text:
module Markdown2Tests
using Test
import Markdown
import Documenter.Utilities: Markdown2

@testset "Markdown2" begin
    let md = Markdown.parse(""),
        md2 = convert(Markdown2.MD, md)
        @test isa(md2, Markdown2.MD)
        @test length(md2) === 0
    end

    let md = Markdown.parse("""
        # Text Paragraphs

        Foo *bar **baz** qux*!

        Foo Bar \\
        Baz
        """),
        md2 = convert(Markdown2.MD, md)

        @test isa(md2, Markdown2.MD)
        @test length(md2) === 3

        let h = md2.nodes[1]
            @test isa(h, Markdown2.Heading)
            @test length(h.nodes) === 1
            @test isa(h.nodes[1], Markdown2.Text)
            @test h.nodes[1].text == "Text Paragraphs"
        end

        let p = md2.nodes[2]
            @test isa(p, Markdown2.Paragraph)
            @test length(p.nodes) === 3

            @test isa(p.nodes[1], Markdown2.Text)
            @test p.nodes[1].text == "Foo "
            @test isa(p.nodes[2], Markdown2.Emphasis)
            @test isa(p.nodes[3], Markdown2.Text)
            @test p.nodes[3].text == "!"

            @test length(p.nodes[2].nodes) === 3
            @test isa(p.nodes[2].nodes[1], Markdown2.Text)
            @test p.nodes[2].nodes[1].text == "bar "
            @test isa(p.nodes[2].nodes[2], Markdown2.Strong)
            @test length(p.nodes[2].nodes[2].nodes) === 1
            @test isa(p.nodes[2].nodes[2].nodes[1], Markdown2.Text)
            @test p.nodes[2].nodes[2].nodes[1].text == "baz"
            @test isa(p.nodes[2].nodes[3], Markdown2.Text)
            @test p.nodes[2].nodes[3].text == " qux"
        end

        @test isa(md2.nodes[3], Markdown2.Paragraph)
    end

    let md = Markdown.parse("""
        # Images

        ![Alt Text](https://example.com/image.png)
        ![](https://example.com/image-noalt.png)
        """),
        md2 = convert(Markdown2.MD, md)

        @test isa(md2, Markdown2.MD)
        @test length(md2) === 2

        @test isa(md2.nodes[1], Markdown2.Heading)
        @test md2.nodes[1].level === 1

        @test isa(md2.nodes[2], Markdown2.Paragraph)
        images = md2.nodes[2].nodes
        @test length(md2.nodes[2].nodes) === 3 # there are Text() nodes between Image() nodes

        @test isa(images[1], Markdown2.Image)
        @test images[1].destination == "https://example.com/image.png"
        @test images[1].description == "Alt Text"

        @test isa(images[3], Markdown2.Image)
        @test images[3].destination == "https://example.com/image-noalt.png"
        @test images[3].description == ""
    end

    let md = Markdown.parse("""
        Blocks
        ------

        ```language
        Hello
        > World!
        ```

        ---

        > Block
        > ``z+1``
        > Quote!
        >
        > ```math
        > x^2 + y^2 = z^2
        > ```

        --- ---
        """),
        md2 = convert(Markdown2.MD, md)

        @test isa(md2, Markdown2.MD)
        @test length(md2) === 5

        @test isa(md2.nodes[1], Markdown2.Heading)
        @test md2.nodes[1].level === 2

        @test isa(md2.nodes[2], Markdown2.CodeBlock)
        @test md2.nodes[2].language == "language"

        @test isa(md2.nodes[3], Markdown2.ThematicBreak)
        @test isa(md2.nodes[4], Markdown2.BlockQuote)
        @test isa(md2.nodes[5], Markdown2.ThematicBreak)
    end

    let md = Markdown.parse("""
        ### Lists

        - a `code span`
        - b
        - c
        """),
        md2 = convert(Markdown2.MD, md)

        @test isa(md2, Markdown2.MD)
        @test length(md2) === 2

        @test isa(md2.nodes[1], Markdown2.Heading)
        @test md2.nodes[1].level === 3

        let list = md2.nodes[2]
            @test isa(list, Markdown2.List)
            @test list.tight === true
            @test list.orderedstart === nothing
            @test length(list.items) === 3

            @test length(list.items[1]) === 1
            @test isa(list.items[1][1], Markdown2.Paragraph)
            @test length(list.items[1][1].nodes) === 2
            @test isa(list.items[1][1].nodes[1], Markdown2.Text)
            @test isa(list.items[1][1].nodes[2], Markdown2.CodeSpan)
            @test list.items[1][1].nodes[2].code == "code span"
        end
    end

    let md = Markdown.parse("""
        !!! warn "FOOBAR"
            Hello World

            ``math
            x+1
            ``
        """),
        md2 = convert(Markdown2.MD, md)

        @test isa(md2, Markdown2.MD)
        @test length(md2) === 1

        @test isa(md2.nodes[1], Markdown2.Admonition)
    end

    let md = Markdown.parse("""
        | Column One | Column Two | Column Three |
        |:---------- | ---------- |:------------:|
        | Row `1`    | Column `2` | > asd        |
        | *Row* 2    | **Row** 2  | Column ``3`` |
        """),
        md2 = convert(Markdown2.MD, md)

        @test isa(md2, Markdown2.MD)
        @test length(md2) === 1

        @test isa(md2.nodes[1], Markdown2.Table)
    end
end

end # module


text:
# code for FastTransforms.jl until that package is compatible with Polynomials v2.0.0

## Use FastTransform for conversion, as  possible
## FastTransforms.kind2string.(0:15)
# Legendre<--Chebyshev
function _convert(::Type{Q}, p::P) where {
    T <: AbstractFloat,
    Q <: Union{Legendre, OrthonormalLegendre},
    P <: Union{Chebyshev{T}, OrthonormalChebyshev{T}}}
    ps = coeffs(p)
    Q(cheb2leg(ps, normcheb=isorthonormal(P), normleg=isorthonormal(Q)))
end

# Chebyshev<--Legendre
function _convert(::Type{Q}, p::P) where {
    T <: AbstractFloat,
    Q <: Union{Chebyshev, OrthonormalChebyshev},
    P <: Union{Legendre{T}, OrthonormalLegendre{T}}
}
    ps =  coeffs(p)
    Q(leg2cheb(ps, normleg=isorthonormal(P), normcheb=isorthonormal(Q)) )
end

# ultraspherical<--ultraspherical
function _convert(::Type{Q}, p::P) where {
    β, α,  T <: AbstractFloat,
    Q <: Union{Gegenbauer{β}, OrthonormalGegenbauer{β}},
    P <: Union{Gegenbauer{α, T}, OrthonormalGegenbauer{α, T}}
}

    ps =  coeffs(p)
    Q( ultra2ultra(ps, α, β, norm1=isorthonormal(P), norm2=isorthonormal(Q)) )

end

# Jacobi<--Jacobi
function _convert(::Type{Q}, p::P) where {
    γ, δ, α, β,  T <: AbstractFloat,
    Q <: Union{Jacobi{γ, δ}, OrthonormalJacobi{γ, δ}},
    P <: Union{Jacobi{α, β, T}, OrthonormalJacobi{α, β, T}}
}

    ps =  coeffs(p)
    Q( jac2jac(ps, α, β, γ, δ,  norm1=isorthonormal(P), norm2=isorthonormal(Q)) )

end

# Laguerre<--Laguerre
function _convert(::Type{Q}, p::P) where {
    α, β,  T <: AbstractFloat,
    Q <: Union{Laguerre{β}, OrthonormalLaguerre{β}},
    P <: Union{Laguerre{α, T}, OrthonormalLaguerre{α, T}}
}

    ps =  coeffs(p)
    Q( lag2lag(ps, α, β,  norm1=isorthonormal(P), norm2=isorthonormal(Q)) )

end

# Jacobi<--ultraspherical
function _convert(::Type{Q}, p::P) where {
    γ, δ, α,  T <: AbstractFloat,
    Q <: Union{Jacobi{γ, δ}, OrthonormalJacobi{γ, δ}},
    P <: Union{Gegenbauer{α, T}, OrthonormalGegenbauer{α, T}}
}

    ps =  coeffs(p)
    Q( ultra2jac(ps, α, γ, δ,  normultra=isorthonormal(P), normjac=isorthonormal(Q)) )

end

# ultraspherical<--Jacobi
function _convert(::Type{Q}, p::P) where {
    α, γ, δ,  T <: AbstractFloat,
    Q <: Union{Gegenbauer{α, T}, OrthonormalGegenbauer{α, T}},
    P <: Union{Jacobi{γ, δ}, OrthonormalJacobi{γ, δ}}
}

    ps =  coeffs(p)
    Q( jac2ultra(ps,γ, δ, α, normjac=isorthonormal(P), normultra=isorthonormal(Q)) )

end

# Jacobi<--Chebyshev
function _convert(::Type{Q}, p::P) where {
    γ, δ,  T <: AbstractFloat,
    Q <: Union{Jacobi{γ, δ}, OrthonormalJacobi{γ, δ}},
    P <: Union{Chebyshev{T}, OrthonormalChebyshev{T}}
}

    ps =  coeffs(p)
    Q( cheb2jac(ps,γ, δ, normcheb=isorthonormal(P), normjac=isorthonormal(Q)) )

end

# Chebyshev<--Jacobi
function _convert(::Type{Q}, p::P) where {
    γ, δ,  T <: AbstractFloat,
    Q <: Union{Chebyshev, OrthonormalChebyshev},
    P <: Union{Jacobi{γ, δ,T}, OrthonormalJacobi{γ, δ,T}}
}

    ps =  coeffs(p)
    Q( jac2cheb(ps,γ, δ, normjac = isorthonormal(P), normcheb=isorthonormal(Q)) )

end

# ultraspherical<--Chebyshev
function _convert(::Type{Q}, p::P) where {
    α,  T <: AbstractFloat,
    Q <: Union{Gegenbauer{α}, OrthonormalGegenbauer{α}},
    P <: Union{Chebyshev{T}, OrthonormalChebyshev{T}}
}

    ps =  coeffs(p)
    Q( cheb2ultra(ps,α, normcheb=isorthonormal(P), normultra=isorthonormal(Q)) )

end

# Chebyshev<--ultraspherical
function _convert(::Type{Q}, p::P) where {
    α,  T <: AbstractFloat,
    Q <: Union{Chebyshev, OrthonormalChebyshev},
    P <: Union{Gegenbauer{α,T}, OrthonormalGegenbauer{α,T}}
}
    ps =  coeffs(p)
    Q( ultra2cheb(ps,α, normultra=isorthonormal(P), normcheb=isorthonormal(Q)) )

end

ext: jl


text:
using CuArrays
using CUDAapi
import NNlib: conv2d, conv2d_grad_w, conv2d_grad_x, pool, pool_grad

const Cptr = Ptr{Void}
macro gs(); if false; esc(:(ccall(("cudaDeviceSynchronize","libcudart"),UInt32,()))); end; end

include("init.jl")
include("const.jl")
include("descriptors.jl")
include("utils.jl")
include("conv.jl")
include("pool.jl")
include("batchnorm.jl")
# include("dropout.jl")
include("softmax.jl")


text:
#  Generic driver routine for 1D Clawpack 5.0, using claw1ez
#  Allocation has been moved int claw2ez; this file essentially
#  does nothing, but is being retained because it gives the
#  codebase more flexibility.

include("claw1ez.jl")

function driver()

    claw1ez()

end # program driver

driver()


text:
# MIT License
#
# Copyright (c) 2018 Martin Biel
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

abstract type AbstractRegularization end
abstract type AbstractRegularizer end
# Regularization API #
# ------------------------------------------------------------
initialize_regularization!(lshaped::AbstractLShaped) = initialize_regularization!(lshaped, lshaped.regularization)
restore_regularized_master!(lshaped::AbstractLShaped) = restore_regularized_master!(lshaped, lshaped.regularization)
filter_variables!(lshaped::AbstractLShaped, list) = filter_variables!(lshaped.regularization, list)
filter_constraints!(lshaped::AbstractLShaped, list) = filter_constraints!(lshaped.regularization, list)
log_regularization!(lshaped::AbstractLShaped) = log_regularization!(lshaped, lshaped.regularization)
log_regularization!(lshaped::AbstractLShaped, t::Integer) = log_regularization!(lshaped, t, lshaped.regularization)
take_step!(lshaped::AbstractLShaped) = take_step!(lshaped, lshaped.regularization)
decision(lshaped::AbstractLShaped) = decision(lshaped, lshaped.regularization)
objective_value(lshaped::AbstractLShaped) = objective_value(lshaped, lshaped.regularization)
gap(lshaped::AbstractLShaped) = gap(lshaped, lshaped.regularization)
process_cut!(lshaped::AbstractLShaped, cut::AbstractHyperPlane) = process_cut!(lshaped, cut, lshaped.regularization)
# ------------------------------------------------------------
# Attributes #
# ------------------------------------------------------------
"""
    RawRegularizationParameter

An optimizer attribute used for raw parameters of the regularizer. Defers to `RawParameter`.
"""
struct RawRegularizationParameter <: RegularizationParameter
    name::Any
end
"""
    RegularizationPenaltyTerm

An optimizer attribute used to set the proximal term in regulariztion procedures (RD/LV). Options are:

- [`Quadratic`](@ref) (default)
- [`Linearized`](@ref)
- [`InfNorm`](@ref)
- [`ManhattanNorm`](@ref)
"""
struct RegularizationPenaltyTerm <: RegularizationParameter end

include("common.jl")
include("no_regularization.jl")
include("rd.jl")
include("tr.jl")
include("lv.jl")


text:
abstract type AbstractIndicator end

function create_cache(typ::Type{IndicatorType}, semi) where {IndicatorType<:AbstractIndicator}
  create_cache(typ, mesh_equations_solver_cache(semi)...)
end

function get_element_variables!(element_variables, indicator::AbstractIndicator, ::VolumeIntegralShockCapturingHG)
  element_variables[:indicator_shock_capturing] = indicator.cache.alpha
  return nothing
end

"""
    IndicatorHennemannGassner

Indicator used for shock-capturing or AMR used by
- Hennemann, Gassner (2020)
  "A provably entropy stable subcell shock capturing approach for high order split form DG"
  [arXiv: 2008.12044](https://arxiv.org/abs/2008.12044)
"""
struct IndicatorHennemannGassner{RealT<:Real, Variable, Cache} <: AbstractIndicator
  alpha_max::RealT
  alpha_min::RealT
  alpha_smooth::Bool
  variable::Variable
  cache::Cache
end

# this method is used when the indicator is constructed as for shock-capturing volume integrals
function IndicatorHennemannGassner(equations::AbstractEquations, basis;
                                   alpha_max=0.5,
                                   alpha_min=0.001,
                                   alpha_smooth=true,
                                   variable)
  alpha_max, alpha_min = promote(alpha_max, alpha_min)
  cache = create_cache(IndicatorHennemannGassner, equations, basis)
  IndicatorHennemannGassner{typeof(alpha_max), typeof(variable), typeof(cache)}(
    alpha_max, alpha_min, alpha_smooth, variable, cache)
end

# this method is used when the indicator is constructed as for AMR
function IndicatorHennemannGassner(semi::AbstractSemidiscretization;
                                   alpha_max=0.5,
                                   alpha_min=0.001,
                                   alpha_smooth=true,
                                   variable)
  alpha_max, alpha_min = promote(alpha_max, alpha_min)
  cache = create_cache(IndicatorHennemannGassner, semi)
  IndicatorHennemannGassner{typeof(alpha_max), typeof(variable), typeof(cache)}(
    alpha_max, alpha_min, alpha_smooth, variable, cache)
end

function Base.show(io::IO, indicator::IndicatorHennemannGassner)
  @nospecialize indicator # reduce precompilation time

  print(io, "IndicatorHennemannGassner(")
  print(io, indicator.variable)
  print(io, ", alpha_max=", indicator.alpha_max)
  print(io, ", alpha_min=", indicator.alpha_min)
  print(io, ", alpha_smooth=", indicator.alpha_smooth)
  print(io, ")")
end

function Base.show(io::IO, ::MIME"text/plain", indicator::IndicatorHennemannGassner)
  @nospecialize indicator # reduce precompilation time

  if get(io, :compact, false)
    show(io, indicator)
  else
    setup = [
             "indicator variable" => indicator.variable,
             "max. α" => indicator.alpha_max,
             "min. α" => indicator.alpha_min,
             "smooth α" => (indicator.alpha_smooth ? "yes" : "no"),
            ]
    summary_box(io, "IndicatorHennemannGassner", setup)
  end
end

"""
    IndicatorLöhner (equivalent to IndicatorLoehner)

AMR indicator adapted from a FEM indicator by Löhner (1987), also used in the
FLASH code as standard AMR indicator.
The indicator estimates a weighted second derivative of a specified variable locally.
- Löhner (1987)
  "An adaptive finite element scheme for transient problems in CFD"
  [doi: 10.1016/0045-7825(87)90098-3](https://doi.org/10.1016/0045-7825(87)90098-3)
- http://flash.uchicago.edu/site/flashcode/user_support/flash4_ug_4p62/node59.html#SECTION05163100000000000000
"""
struct IndicatorLöhner{RealT<:Real, Variable, Cache} <: AbstractIndicator
  f_wave::RealT # TODO: Taal documentation
  variable::Variable
  cache::Cache
end

# this method is used when the indicator is constructed as for shock-capturing volume integrals
function IndicatorLöhner(equations::AbstractEquations, basis;
                         f_wave=0.2, variable)
  cache = create_cache(IndicatorLöhner, equations, basis)
  IndicatorLöhner{typeof(f_wave), typeof(variable), typeof(cache)}(f_wave, variable, cache)
end

# this method is used when the indicator is constructed as for AMR
function IndicatorLöhner(semi::AbstractSemidiscretization;
                         f_wave=0.2, variable)
  cache = create_cache(IndicatorLöhner, semi)
  IndicatorLöhner{typeof(f_wave), typeof(variable), typeof(cache)}(f_wave, variable, cache)
end

function Base.show(io::IO, indicator::IndicatorLöhner)
  @nospecialize indicator # reduce precompilation time

  print(io, "IndicatorLöhner(")
  print(io, "f_wave=", indicator.f_wave, ", variable=", indicator.variable, ")")
end

function Base.show(io::IO, ::MIME"text/plain", indicator::IndicatorLöhner)
  @nospecialize indicator # reduce precompilation time

  if get(io, :compact, false)
    show(io, indicator)
  else
    setup = [
             "indicator variable" => indicator.variable,
             "f_wave" => indicator.f_wave,
            ]
    summary_box(io, "IndicatorLöhner", setup)
  end
end

const IndicatorLoehner = IndicatorLöhner

# dirty Löhner estimate, direction by direction, assuming constant nodes
@inline function local_löhner_estimate(um::Real, u0::Real, up::Real, löhner::IndicatorLöhner)
  num = abs(up - 2 * u0 + um)
  den = abs(up - u0) + abs(u0-um) + löhner.f_wave * (abs(up) + 2 * abs(u0) + abs(um))
  return num / den
end

struct IndicatorMax{Variable, Cache<:NamedTuple} <: AbstractIndicator
  variable::Variable
  cache::Cache
end

# this method is used when the indicator is constructed as for shock-capturing volume integrals
function IndicatorMax(equations::AbstractEquations, basis;
                      variable)
  cache = create_cache(IndicatorMax, equations, basis)
  IndicatorMax{typeof(variable), typeof(cache)}(variable, cache)
end

# this method is used when the indicator is constructed as for AMR
function IndicatorMax(semi::AbstractSemidiscretization;
                      variable)
  cache = create_cache(IndicatorMax, semi)
  return IndicatorMax{typeof(variable), typeof(cache)}(variable, cache)
end

function Base.show(io::IO, indicator::IndicatorMax)
  @nospecialize indicator # reduce precompilation time

  print(io, "IndicatorMax(")
  print(io, "variable=", indicator.variable, ")")
end

function Base.show(io::IO, ::MIME"text/plain", indicator::IndicatorMax)
  @nospecialize indicator # reduce precompilation time

  if get(io, :compact, false)
    show(io, indicator)
  else
    setup = [
             "indicator variable" => indicator.variable,
            ]
    summary_box(io, "IndicatorMax", setup)
  end
end


text:
export start_berl, print_metrics

using UUIDs

function start_berl(algo_name::String, env_name::String; env_params...)
    cfg_path = "./src/algorithms/$algo_name/$env_name.yaml"

    if algo_name in ["NEAT", "HyperNEAT", "CPPN"]
        cfg = NeuroEvolution.get_config(cfg_path)
    else
        cfg = CartesianGeneticProgramming.get_config(cfg_path)
    end

    for (k, v) in pairs(env_params)
        cfg[string(k)] = v
    end

    # Create and setup the environment
    env::BERLenv = environments[env_name](cfg)
    id = string(UUIDs.uuid1())
    println(id)
    cfg["id"] = "$(algo_name)_$(env.name)_$id)"
    println(cfg["id"])
    # Fitness function
    fit::Function = i::Cambrian.Individual -> fitness(i, env)

    # Create evolution
    e::Cambrian.Evolution = algorithms[algo_name](cfg, fit)
    # e.logger = CambrianLogger(string("logs/", e.id, ".log"))

    val, t, bytes, gctime, memallocs = @timed BERL.run!(e, env)
    best = sort(e.population)[end]

    metrics = Dict()
    metrics["id"]=cfg["id"]
    metrics["Algorithm"]=algo_name
    metrics["Environment"]= get(cfg, "gym_env", get(cfg, "atari_game", env_name))
    metrics["Best fitness"]=best.fitness[1]
    metrics["Best indiv"]=best
    metrics["Run time"]=t
    metrics["Memory allocated"]=bytes

    metrics
end

function print_metrics(m)
    println("> ", m["Algorithm"], " | ", m["Environment"])
    println(" - Final fitness: ", m["Best fitness"])
    println(" - Run time: ", m["Run time"], "s")
    println(" - Memory allocated: ", m["Memory allocated"], " bytes")
end


text:
import Term: remove_markup, remove_ansi, truncate, reshape_text, textlen, fillin
import Term.style: apply_style

@testset "\e[34mTU - remove" begin
    # ------------------------------- remove markup ------------------------------ #
    @test remove_markup("[red]text[/red]") == "text"
    @test remove_markup("[red]sffsdf[green on_blue italic]") == "sffsdf"
    @test remove_markup("[red]aa[green on_blue italic]bb[/green on_blue italic]cc[/]") ==
        "aabbcc"
    @test remove_markup("[(255, 1, 3)]aa[#ff0022 italic]bb[/ff0022]") == "aabb"

    # test that parentheses are ignored
    strings = [
        "1111",
        "[222a",
        "333asd[adsada",
        "a444asdas]asda]asda",
        "[a5555adsad[[sada",
        "a6666[[asdasd]]",
    ]
    for str in strings
        @test remove_markup(str) == str
    end

    # -------------------------------- remove ansi ------------------------------- #
    strings = [
        ("[red]asdasdad[/red]", "asdasdad"),
        ("aaa[bold on_green]bb[/]", "aaabb"),
        ("[red]aa[bold]bb[#ffffff]cc[/#ffffff]dd", "aabbccdd"),
        ("[bold italic underline]aa[/bold italic underline]", "aa"),
    ]
    for (str, clean) in strings
        @test remove_ansi(apply_style(str)) == clean
        @test remove_markup(str) == clean
    end
end

@testset "\e[34mTU - reshape text" begin
    # --------------------------------- truncate --------------------------------- #
    strings = [("a"^20, 6), ("asd"^33, 12), ("c"^3, 22)]
    for (str, w) in strings
        @test length(truncate(str, w)) <= w
    end

    # ---------------------------------- fillin ---------------------------------- #
    a = """asdasd
asdasdsaasdasdasdasdsadsadasd
asdasdasda"""
    filled = fillin(a)

    @test nlines(filled) == 3
    @test lw(filled) == 29

    widths = [textlen(ln) for ln in split(filled, "\n")]
    @test length(unique(widths)) == 1

    # ---------------------------------- reshape --------------------------------- #
    s1 = "."^500

    sizes = [(50, 10), (25, 20), (5, 100), (100, 5)]

    for (w, h) in sizes
        rs = reshape_text(s1, w)
        @test lw(rs) == w
        @test nlines(rs) == h
    end

    s1 = "[red]aa[green]bb[/green]c[/red]"^100

    sizes = [(50, 10), (25, 20), (5, 100), (100, 5)]

    for (w, h) in sizes
        rs = remove_markup(reshape_text(s1, w))
        @test lw(rs) == w
        @test nlines(rs) == h
    end

    for L in (25, 50, 125)
        lorem = "Lorem ipsum dolor sit amet, [red]consectetur adipiscing elit, sed do[blue] eiusmod tempor[/blue] incididunt ut labore et [/red]dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
        r1 = reshape_text(lorem, L)
        for line in split(r1, "\n")
            @test textlen(line) == L
        end
    end
end


text:
# Segment frames independently for explanation purposes only.

function segment_blobs_(mask, fun!)
    f = Int32.(mask)
    _, clusterid = doclustering!(@view f[:,:,1])
    for frame in 2:size(f, 3)
        println(frame)
        _, clusterid = doclustering!(view(f, :,:,frame)) #, clusterid)
        fun!((@view f[:,:,frame]), @view f[:,:,frame-1])
    end
    f
end
function segment_blobs0(mask)
    segment_blobs_(mask, (_,_) -> nothing)
end


text:
#!/usr/bin/env julia

using GZip

exomf = ARGS[1] # Exome file e.g: Exome_region.bed
vcf  = ARGS[2] # Variant Calling file e.g: chr3.vcf.gz

function read(file)
    if ismatch(r".gz$", file)   # Gzipped .gz files
		f = GZip.open(file)
		lines = readlines(f)
		close(f)
    else
		f = open(file)
		lines = readlines(f)
		close(f)
	end
	return lines
end

function expand(locci)
    list = []
    pos = split(locci, ':')
        chr = pos[1]
        region = split(pos[2], '-')
        n = parse(Int64, region[1])
        while n <= parse(Int64, region[end])
            #out = "$chr" * ":" * "$n"
            push!(list, n)
            n +=  1
        end
    return list
end

function getchr(records=read(vcf))
    chr = split(records[5], '\t')[1]
	return chr
end

function readBED(bed_file, chr::AbstractString=getchr())
    pos = []
    bed = read(bed_file)
    for line in bed
        bed = split(line, '\t')
        chrm = replace(bed[1], "chr", "")
        if chrm == chr
            start, last = bed[2], bed[3]
            chroms = "$chrm" * ":" * "$start" * "-" * "$last"
            region = expand(chroms)
            append!(pos, region)
        end
    end
    pos = unique(pos)
    return pos
end

function checkExome(vcf_line, exomf=exomf)
    exompos = readBED(exomf)
    snp = split(vcf_line, '\t')[2]
    out = in(snp, exompos)
    return out
end

function filterExonic(vcf_path)
	lines = read(vcf_path)
	println(chomp(lines[1]))
	for line = lines[2:end]
		exomic = checkExome(line)
		if exomic == true
            continue
        else
			print(line)
		end
	end
end

filterExonic(vcf)


text:
#!/usr/bin/env julia
# vim:set ft=julia ts=4 sw=4 sts=4 autoindent:

# Performance testing for the CoNLL-X format module.
#
# Author:   Pontus Stenetorp    <pontus stenetorp se>
# Version:  2014-05-09

include("../hdr.jl")

require("conllx.jl")

import Base.source_path
using Base.Test

using CoNLLX

open(talpath, "r") do data_f
    sentcnt = 0
    before = time()
    for _ in conllxparse(data_f)
        sentcnt += 1
    end
    duration = time() - before
    throughput = sentcnt / duration
    @printf("Data reader throughput: %.1f sentence(s) per second\n",
        throughput)
end

max_stars_repo_name: ninjin/allen

max_issues_repo_name: ninjin/allen

max_forks_repo_name: ninjin/allen


text:
using Minerva, Flux

"""
    Softmax()
"""
struct Softmax end

(a::Softmax)(x::AbstractArray) = softmax(x)

Base.show(io::IO, l::Softmax) = print(io, "Softmax()")

batch_size = 1
discount_rate = 1.00

model = Chain(
    Dense(4, 1024, relu),
    Dense(1024, 512, relu),
    Dense(512, 2),
    Softmax()
)
opt = Descent(1e-3)
agent = VanillaPG(model, opt, batch_size, discount_rate)
env = CartPole()
recorder = train!(agent, env, max_episodes = 10000)
evaluate(agent, env, 1, rendered = true)


text:
@testset "orders" begin
  api_key = "some-api-key"
  api_secret = "some-api-secret"
  r = new_order(
    true,
    api_key,
    api_secret,
    "buy",
    "btcusd",
    "1",
    "49000.00",
    "exchange limit",
    ["fill-or-kill"]
  )
  println(r)
  if ==(r.status, 200)
    if ==(r.response["is_cancelled"], false)
      order_id = parse(Int64, r.response["order_id"])
      r = cancel_order(
        true,
        api_key,
        api_secret,
        order_id
      )
      println(r)
      if !=(r.status, 200)
        @test false
      end
    end
  else
    @test false
  end
end

max_stars_repo_name: rory-linehan/Gemini

max_issues_repo_name: rory-linehan/Gemini

max_forks_repo_name: rory-linehan/Gemini


text:
using Test

@testset "Maps.jl" begin
    include("Maps.jl")
end


text:
@docref () -> REF_ENTRY_TYPE
type Entry{category} # category::Symbol
    docs::Markdown.Block
    meta::Dict{Symbol, Any}

    function Entry(source, meta::Dict)
        push!(meta, :source, source)
        docs = haskey(meta, :file) ?
            Markdown.parse_file(joinpath(dirname(source[2]), meta[:file])) :
            Markdown.parse("")
        new(docs, meta)
    end

    function Entry(source, text::String, meta::Dict = Dict{Symbol, Any}())
        push!(meta, :source, source)
        new(Markdown.parse(text), meta)
    end

    Entry(args...) = error("@doc: incorrect arguments given to docstring macro:\n$(args)")
end

@docref () -> REF_DOCUMENTATION_TYPE
type Documentation
    modname::Module
    entries::Dict{Any, Entry}
    Documentation(m::Module) = new(m, Dict{Any, Entry}())
end

function push!(docs::Documentation, object, ent::Entry)
    haskey(docs.entries, object) && warn("@doc: overwriting object $(object)")
    docs.entries[object] = ent
end


text:
__precompile__()
module KerrQNMShifts

using KerrQuasinormalModes
using PyCall
using CSV
using DataFrames
using Plots
using Cubature
using ContourIntegrals
# Write your package code here.

include("KerrQuasinormalModeAdditions.jl")
include("ImportExpressionsFromFile.jl")
include("OperatorShiftType.jl")
include("OperatorSandwichType.jl")

export qnm, qnmfunctionnew, importqnm
export OperatorShift, OperatorSandwich

end

max_stars_repo_name: Potatoasad/KerrQNMShifts

max_issues_repo_name: Potatoasad/KerrQNMShifts

max_forks_repo_name: Potatoasad/KerrQNMShifts


text:
function accumulator(i)
	f(n) = i += n
	return f
end

x = accumulator(1)
@show x(5)

accumulator(3)
@show x(2.3)

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
# Autogenerated wrapper script for pigpiod_if2_jll for i686-linux-musl
export libpigpiod_if2

JLLWrappers.@generate_wrapper_header("pigpiod_if2")
JLLWrappers.@declare_library_product(libpigpiod_if2, "libpigpiod_if2.so.1")
function __init__()
    JLLWrappers.@generate_init_header()
    JLLWrappers.@init_library_product(
        libpigpiod_if2,
        "lib/libpigpiod_if2.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
import .GeometryPredicates: orient, incircle

struct Triangulation{T}
    vertices::Vector{NTuple{2,T}}
    edges::Dict{NTuple{2,Int},Int}
end

function Triangulation(vertices::Vector{NTuple{2,T}}) where {T}
    return Triangulation(vertices, Dict{NTuple{2,Int},Int}())
end

function Triangulation(T::DataType, n::Int)
    return Triangulation(Vector{NTuple{2,T}}(undef, n), Dict{NTuple{2,Int},Int}())
end

function add_triangle!(triangulation::Triangulation, triangle::NTuple{3,Int})
    u, v, w = triangle
    edges = keys(triangulation.edges)
    if ((u, v) in edges) || ((v, w) in edges) || ((w, u) in edges)
        return triangle
    end
    triangulation.edges[(u, v)] = w
    triangulation.edges[(v, w)] = u
    triangulation.edges[(w, u)] = v
    return triangle
end

function delete_triangle!(triangulation::Triangulation, triangle::NTuple{3,Int})
    u, v, w = triangle
    edges = keys(triangulation.edges)
    if ((u, v) in edges) && ((v, w) in edges) && ((w, u) in edges)
        delete!(triangulation.edges, (u, v))
        delete!(triangulation.edges, (v, w))
        delete!(triangulation.edges, (w, u))
    end
    return
end

function adjacent(triangulation::Triangulation, edge::NTuple{2,Int})
    return get(triangulation.edges, edge, 0)
end

function adjacent_to_vertex(triangulation::Triangulation, u::Int)
    for (key, value) in triangulation.edges
        if value == u
            return key
        end
    end
    return (0, 0)
end

function GeometryPredicates.orient(triangulation::Triangulation, u::Int, v::Int, w::Int)
    return orient(triangulation.vertices[u], triangulation.vertices[v],
                  triangulation.vertices[w])
end

function GeometryPredicates.incircle(triangulation::Triangulation, u::Int, v::Int, w::Int, q::Int)
    return incircle(triangulation.vertices[u], triangulation.vertices[v],
                    triangulation.vertices[w], triangulation.vertices[q])
end

function GeometryPredicates.incircle(triangulation::Triangulation, u::Int, v::Int, w::Int)
    return incircle(triangulation.vertices[u], triangulation.vertices[v],
                    triangulation.vertices[w])
end

max_stars_repo_name: PaulMatlashewski/DelaunayTriangulations

max_issues_repo_name: PaulMatlashewski/DelaunayTriangulations

max_forks_repo_name: PaulMatlashewski/DelaunayTriangulations


text:
###############################################################################
# Machine Learning
###############################################################################

###############################################################################
# Introduction

using MLJ, RDatasets

# Let's load some synthetic dataset

iris = RDatasets.dataset("datasets", "iris")

y, X = unpack(iris, ==(:Species), colname -> true)

# 1/ What is the type of X? What is the type of y? X should respect the Tables.jl interface to work with MLJ models.

# Let's see what models are available to fit this dataset

models(matching(X,y))

# MLJ does not define any model but only an interface.
# This means we need to install and load the different libraries where the models are implemented.
# The following is the MLJ facility to load a model but using `using` or `import` will also work of course.

# Enter the Package manager and run: `add MLJLinearModels NearestNeighborModels MLJFlux MLJDecisionTreeInterface Plots`

RandomForestClassifier= @load RandomForestClassifier pkg=DecisionTree verbosity = 0
NeuralNetworkClassifier = @load NeuralNetworkClassifier pkg=MLJFlux verbosity = 0
LogisticClassifier = @load LogisticClassifier pkg=MLJLinearModels verbosity = 0
KNNClassifier = @load KNNClassifier pkg=NearestNeighborModels verbosity = 0

###############################################################################
# Fitting Models

# Let's look at the API with a simple model fit

# A model is simply a container for hyperparmeters describing the procedure
model = LogisticClassifier()
# The machine wraps a procedure with data
mach = machine(model, X, y)
# The estimation part
fit!(mach)
fp = fitted_params(mach)
fp.coefs
fp.intercept

# Investigate the following result
ypred = predict(mach)

# rand(ypred[end]) to sample from the categorical distribution

# Evaluate our fit
# log_loss(ypred, y) # applied element-wise
mean(log_loss(ypred, y))

# A caveat: X should respect the Tables.jl interface

Xmatrix = MLJ.matrix(X)
# This will raise a warning and subsequenti fit potentially fail
mach = machine(RandomForestClassifier(), Xmatrix, y)

# Now for the Stack
library = (rf=RandomForestClassifier(),
            svr=NeuralNetworkClassifier(),
            lr=LogisticClassifier(),
            lr1=LogisticClassifier(lambda=10),
            knn=KNNClassifier())

stack = Stack(;metalearner=LogisticClassifier(),
                resampling=CV(nfolds=30),
                library...) # dots to tell julia to unpack the various models # if don't want everything printed can add a ;

# TODO: Now fit the stack

super_mach = machine(stack, X, y)
fit!(super_mach)
super_fp = fitted_params(super_mach)
super_fp.metalearner.coefs

super_ypred = predict(super_mach)

###############################################################################
# Model Comparison
# TODO: What does the following code do?
# Use the push!(array, new_element) function to extend the results for each model
# Notice the "!", this isyntax tells you that the first argument will be modified by the function

allmodels = (stack=stack, library...)
results = []
for model in allmodels
    res = evaluate(model, X, y, resampling=Holdout(), measure=log_loss, verbosity=0)
    push!(results,res.measurement[1])
end

results

using Plots
plot([string(x) for x in keys(allmodels)], results,
        seriestype=:bar,
        label=:none,
        title="Log Loss")


text:
module SimplexGridFactory

using Printf
using LinearAlgebra

using ExtendableGrids
using GridVisualize
using DocStringExtensions
using ElasticArrays

include("utils.jl")

include("options.jl")

include("binnedpointlist.jl")
export  BinnedPointList

include("simplexgridbuilder.jl")
export SimplexGridBuilder
export point!,facet!, cellregion!, holepoint!,facetregion!,maxvolume!,regionpoint!,options!
export istriangulate,istetgen
export flags

include("simplexgrid.jl")
export simplexgrid

include("triangle.jl")

include("tetgen.jl")

export SimplexGridBuilder

include("primitives.jl")
export circle!,rect2d!,rect3d!,sphere!,bregions!

include("plot.jl")
export builderplot

end # module


text:
# Maximum likelihood estimation
using EstimateSDE
using Random
using Printf
using Distributions
using Parameters

## Settings
proc = testprocess(:C)
N = 200
Tav = 0.5
Tkld = 0.5
tor = MlEstimator()
rng = MersenneTwister(12202)

data = rand(rng,proc,N,Tav)
problem = ProblemLike(data;p=EstimateSDE.order(proc),engine=ElimQ)

Ts = [0.5,1.0,2.0]*Tkld
init_tors = default_init_tors(rng,Ts)
proc_ml = estimate(tor,problem;init_tors=init_tors,throw_errors=true)

D = kldiv(proc,proc_ml,(0:Tkld:N*Tav))

## Report
printstyled("Actual:\n",color=:blue)
describe_model(proc)
printstyled("Estimate:\n",color=:blue)
describe_model(proc_ml)
@printf "KL divergence: %0.1f\n" D


text:
# ToFeT_io.jl
# Code to read in ToFeT file format .edge and .xyz specifications

import DelimitedFiles
import SparseArrays

function readToFeTedges(f)
    raw=DelimitedFiles.readdlm(f)

    # - .+1 renumber indices from 1 rather than zero
    # - double up (vcat) indices for making explicit A->B && implicit B->A
    As=Int.(vcat(raw[:,1],raw[:,2])) .+ 1
    Bs=Int.(vcat(raw[:,2],raw[:,1])) .+ 1

    Js=vcat(raw[:,3],raw[:,3])

    SparseArrays.sparse(As,Bs,Js)
end

function generateLinearChain(n; J=0.1)
    # bit ugly, surely a nicer way to write this?
    As=[ i for i=1:n-1 ]
    Bs=[ i+1 for i=1:n-1 ]
    Js=[J for i=1:n-1]

    SparseArrays.sparse(vcat(As,Bs),vcat(Bs,As),vcat(Js,Js))
end

function generateNearestNeighbourCube(n; J=0.1)
    N=n^3 # number of sites in cube
    As=Int[]
    Bs=Int[]
    Js=Float64[]

    nn=[+1 -1 +n -n +n^2 -n^2]

    for i in 1:N # iterate over all elements
        for neighbour in nn
            append!(As,i)
            append!(Bs,(i+neighbour-1+N)%N + 1) # modulo arithmatic to enforce PBCs
            append!(Js,J)
        end
    end

    SparseArrays.sparse(As,Bs,Js)
end

function readToFeTxyz(f)
     raw=DelimitedFiles.readdlm(f)
     XYZ=raw[:,1:3]
 end


text:
# __precompile__()
module EconModel

import Base:display,names,length,getindex,setindex!,sort,*,convert,kron,spzeros,find
using SparseGrids
import SparseGrids:ndgrid

include("utils.jl")
include("parse.jl")
include("modelparse.jl")
include("equations.jl")
include("model.jl")
include("aggregation.jl")
include("solve.jl")

export Model,
	   solve,
	   updateX,
	   updateXP,
	   updateSP,
	   updateT,
	   updateT1,
	   updatetd,
	   updatedistribution,
	   updateAggregates,
	   updateA,
	   ∫,
	   ARSim,
	   MarkovSim!,
	   ProblemParse

end # module


text:
##########################################################################
# Copyright 2017 Samuel Ridler.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##########################################################################

# Capture statistics at current time.
# Mutates: sim.stats, sim.time
function captureSimStats!(sim::Simulation, currentTime::Float)
	if sim.complete currentTime = min(currentTime, sim.endTime) end

	if !sim.complete @assert(currentTime == sim.stats.nextCaptureTime) end
	@assert(sim.time <= currentTime)
	@assert(isempty(sim.eventList) || currentTime <= sim.eventList[end].time) # currentTime should be before next event

	sim.time = currentTime

	capture = SimPeriodStats()
	capture.startTime = sim.startTime
	capture.endTime = currentTime
	capture.duration = capture.endTime - capture.startTime
	capture.ambulances = [AmbulanceStats(sim, a) for a in sim.ambulances]
	capture.hospitals = [HospitalStats(h) for h in sim.hospitals]
	capture.stations = [StationStats(sim, s) for s in sim.stations]
	capture.ambulance = sum(capture.ambulances)
	capture.hospital = sum(capture.hospitals)
	capture.station = sum(capture.stations)

	push!(sim.stats.captures, capture)

	# determine next capture time
	nextPeriodDuration = isempty(sim.stats.periodDurationsIter) ? Inf : first(sim.stats.periodDurationsIter)
	@assert(nextPeriodDuration > 0)
	sim.stats.nextCaptureTime += nextPeriodDuration
end

# For statistics that should be calculated at sim end.
# Mutates: sim.stats
function populateSimStats!(sim::Simulation)
	@assert(sim.complete)

	# shorthand
	stats = sim.stats
	captures = stats.captures

	@assert(all(s -> s.startTime == sim.startTime, captures))
	@assert(issorted(captures, by = s -> s.endTime))
	@assert(captures[end].endTime == sim.endTime)

	# timestamps
	stats.simStartTime = sim.startTime
	stats.simEndTime = sim.endTime
	stats.warmUpEndTime = sim.startTime + stats.warmUpDuration
	stats.lastCallArrivalTime = sim.calls[end].arrivalTime

	# populate call statistics
	callsByPriority = Dict([p => filter(c -> c.priority == p, sim.calls) for p in priorities])
	sim.stats.responseDurationHistNumBins = floor(Int, maximum(c -> c.responseDuration, sim.calls) / sim.stats.responseDurationHistBinWidth) + 1
	for i = 1:length(captures)
		period = i == 1 ? captures[i] : captures[i] - captures[i-1]
		period.call = CallStats(sim, sim.calls, period.startTime, period.endTime)
		for priority in priorities
			period.callPriorities[priority] = CallStats(sim, callsByPriority[priority], period.startTime, period.endTime)
		end
		push!(stats.periods, period)

		captures[i].call = i == 1 ? period.call : period.call + captures[i-1].call
		captures[i].callPriorities = i == 1 ? period.callPriorities : period.callPriorities + captures[i-1].callPriorities
	end
end

# Return ambulance stats for given ambulance.
# Accounts for durations and distances of partially completed travelling and processes.
function AmbulanceStats(sim::Simulation, ambulance::Ambulance)::AmbulanceStats
	stats = AmbulanceStats()

	# copy some fields
	stats.ambIndex = ambulance.index
	stats.numCallsTreated = ambulance.numCallsTreated
	stats.numCallsTransported = ambulance.numCallsTransported
	stats.numDispatches = ambulance.numDispatches
	stats.numDispatchesFromStation = ambulance.numDispatchesFromStation
	stats.numDispatchesWhileMobilising = ambulance.numDispatchesWhileMobilising
	stats.numDispatchesOnRoad = ambulance.numDispatchesOnRoad
	stats.numDispatchesOnFree = ambulance.numDispatchesOnFree
	stats.numRedispatches = ambulance.numRedispatches
	stats.numMoveUps = ambulance.numMoveUps
	stats.numMoveUpsFromStation = ambulance.numMoveUpsFromStation
	stats.numMoveUpsOnRoad = ambulance.numMoveUpsOnRoad
	stats.numMoveUpsOnFree = ambulance.numMoveUpsOnFree
	stats.numMoveUpsReturnToPrevStation = ambulance.numMoveUpsReturnToPrevStation
	stats.statusTransitionCounts = deepcopy(ambulance.statusTransitionCounts)

	stats.statusDurations = deepcopy(ambulance.statusDurations)
	addStatusDuration!(stats.statusDurations, ambulance.status, sim.time - ambulance.statusSetTime) # account for time spent in current/final status

	# calculate travel distance, accounting for any partially completed route
	stats.statusDistances = deepcopy(ambulance.statusDistances) # ambulance.statusDistances is for routes completed before or at sim.time
	if sim.time < ambulance.route.endTime # have not finished route
		dist = calcRouteDistance!(sim, ambulance.route, sim.time)
		addStatusDistance!(stats.statusDistances, ambulance.status, dist) # account for distance travelled in current/final status
	end

	if checkMode
		@assert(stats.numDispatches == stats.numDispatchesFromStation + stats.numDispatchesWhileMobilising + stats.numDispatchesOnRoad + stats.numDispatchesOnFree) # numRedispatches already included in numDispatchesOnRoad
		@assert(stats.numMoveUps == stats.numMoveUpsFromStation + stats.numMoveUpsOnRoad + stats.numMoveUpsOnFree)

		ambStatuses = setdiff(instances(AmbStatus), (ambNullStatus,))
		@assert(isapprox(sum(s -> stats.statusDurations[s], ambStatuses), sim.time - sim.startTime))

		# statusTransitionCounts
		travelStatuses = ambStatusSets[ambTravelling]
		@assert(stats.numCallsTreated == sum(stats.statusTransitionCounts[:, Int(ambAtCall)]))
		@assert(stats.numCallsTransported == stats.statusTransitionCounts[Int(ambGoingToHospital), Int(ambAtHospital)])
		@assert(stats.numDispatches == sum(stats.statusTransitionCounts[:, Int(ambMobilising)]) + sum(stats.statusTransitionCounts[:, Int(ambGoingToCall)]) - stats.statusTransitionCounts[Int(ambMobilising), Int(ambGoingToCall)])
		@assert(stats.numDispatchesFromStation == sum(stats.statusTransitionCounts[Int(ambIdleAtStation), [Int(ambMobilising), Int(ambGoingToCall)]]))
		@assert(stats.numDispatchesWhileMobilising == stats.statusTransitionCounts[Int(ambMobilising), Int(ambMobilising)])
		@assert(stats.numDispatchesOnRoad == sum(s -> stats.statusTransitionCounts[Int(s), Int(ambGoingToCall)], travelStatuses))
		@assert(stats.numDispatchesOnFree == stats.statusTransitionCounts[Int(ambFreeAfterCall), Int(ambGoingToCall)])
		@assert(stats.numRedispatches == sum(stats.statusTransitionCounts[[Int(ambMobilising), Int(ambGoingToCall)], [Int(ambMobilising), Int(ambGoingToCall)]]) - stats.statusTransitionCounts[Int(ambMobilising), Int(ambGoingToCall)])
		@assert(stats.numMoveUps == sum(stats.statusTransitionCounts[:, Int(ambMovingUpToStation)]))
		@assert(stats.numMoveUpsFromStation == stats.statusTransitionCounts[Int(ambIdleAtStation), Int(ambMovingUpToStation)])
		@assert(stats.numMoveUpsOnRoad == sum(s -> stats.statusTransitionCounts[Int(s), Int(ambMovingUpToStation)], travelStatuses))
		@assert(stats.numMoveUpsOnFree == stats.statusTransitionCounts[Int(ambFreeAfterCall), Int(ambMovingUpToStation)])
	end

	return stats
end

function createResponseDurationHist(responseDurations::Vector{Float}, numBins::Int, binWidth::Float)::Histogram
	# numBins and binWidth should be the same for all histograms so that the histograms can be easily added and subtracted
	@assert(numBins >= 0)
	@assert(binWidth > 0)
	h = fit(Histogram, responseDurations, (0:numBins)*binWidth)
	@assert(sum(h.weights) == length(responseDurations)) # otherwise there are durations outside of histogram bins that were not included
	return h
end

function CallStats(sim::Simulation, calls::Vector{Call})::CallStats
	if isempty(calls) return CallStats() end
	@assert(all(c -> c.status == callProcessed, calls))
	stats = CallStats()
	stats.numCalls = length(calls)
	if stats.numCalls == 1 stats.callIndex = calls[1].index end

	# counts
	stats.numQueued = count(c -> c.wasQueued, calls)
	stats.numBumped = count(c -> c.numBumps > 0, calls)
	stats.numBumps = sum(c -> c.numBumps, calls)
	stats.numTransports = count(c -> c.transport, calls)
	stats.numResponsesInTime = count(c -> c.responseDuration <= sim.targetResponseDurations[Int(c.priority)], calls)

	# durations
	stats.totalDispatchDelay = sum(c -> c.dispatchDelay, calls)
	stats.totalOnSceneDuration = sum(c -> c.onSceneDuration, calls)
	stats.totalHandoverDuration = sum(c -> c.handoverDuration, calls)
	stats.totalQueuedDuration = sum(c -> c.queuedDuration, calls)
	stats.totalBumpedDuration = sum(c -> c.bumpedDuration, calls)
	stats.totalWaitingForAmbDuration = sum(c -> c.waitingForAmbDuration, calls)
	stats.totalResponseDuration = sum(c -> c.responseDuration, calls)
	stats.totalAmbGoingToCallDuration = sum(c -> c.ambGoingToCallDuration, calls)
	stats.totalTransportDuration = sum(c -> c.transportDuration, calls)
	stats.totalServiceDuration = sum(c -> c.serviceDuration, calls)

	# response duration histogram
	if sim.stats.recordResponseDurationHist
		(numBins, binWidth) = (sim.stats.responseDurationHistNumBins, sim.stats.responseDurationHistBinWidth) # shorthand
		stats.responseDurationHist = createResponseDurationHist([c.responseDuration for c in calls], numBins, binWidth)
	end

	if checkMode
		@assert(all(c -> c.wasQueued || c.queuedDuration == 0, calls))
		@assert(all(c -> c.numBumps > 0 || c.bumpedDuration == 0, calls))
		@assert(all(c -> c.dispatchDelay >= 0, calls))
		@assert(all(c -> c.transport || c.transportDuration == 0, calls)) # calls not taken to hospital should have transportDuration == 0
		@assert(all(c -> c.transport || c.handoverDuration == 0, calls)) # calls not taken to hospital should have handoverDuration == 0
		@assert(isapprox(stats.totalWaitingForAmbDuration, stats.totalAmbGoingToCallDuration + stats.totalBumpedDuration))
		@assert(isapprox(stats.totalResponseDuration, stats.totalDispatchDelay + stats.totalQueuedDuration + stats.totalBumpedDuration + stats.totalAmbGoingToCallDuration))
	end

	return stats
end

function CallStats(sim::Simulation, calls::Vector{Call}, startTime::Float, endTime::Float)::CallStats
	# filter calls by arrivalTime within [startTime, endTime)
	i = findfirst(c -> c.arrivalTime >= startTime, calls)
	if i == nothing return CallStats() end # no calls in time period
	j = something(findnext(c -> c.arrivalTime >= endTime, calls, i), length(calls) + 1) - 1
	return CallStats(sim, calls[i:j])
end

function HospitalStats(hospital::Hospital)::HospitalStats
	stats = HospitalStats()
	stats.hospitalIndex = hospital.index
	stats.numCalls = hospital.numCalls
	return stats
end

function StationStats(sim::Simulation, station::Station)::StationStats
	stats = StationStats()
	stats.stationIndex = station.index

	stats.numIdleAmbsTotalDuration = deepcopy(station.numIdleAmbsTotalDuration)
	@assert(sim.time >= station.currentNumIdleAmbsSetTime)
	stats.numIdleAmbsTotalDuration[station.currentNumIdleAmbs] += sim.time - station.currentNumIdleAmbsSetTime

	if checkMode
		@assert(isapprox(sum(stats.numIdleAmbsTotalDuration), sim.time - sim.startTime))
	end

	return stats
end

# for ambulance statusDurations and statusDistances:
Base.:+(a::Dict{Union{AmbStatus,AmbStatusSet},Float}, b::Dict{Union{AmbStatus,AmbStatusSet},Float}) = merge(+, a, b)
Base.:-(a::Dict{Union{AmbStatus,AmbStatusSet},Float}, b::Dict{Union{AmbStatus,AmbStatusSet},Float}) = merge(-, a, b)

function Base.:+(a::AmbulanceStats, b::AmbulanceStats)::AmbulanceStats
	stats = AmbulanceStats()
	for fname in fieldnames(AmbulanceStats)
		setfield!(stats, fname, getfield(a, fname) + getfield(b, fname))
	end
	stats.ambIndex = a.ambIndex == b.ambIndex ? a.ambIndex : nullIndex
	return stats
end

function Base.:-(a::AmbulanceStats, b::AmbulanceStats)::AmbulanceStats
	stats = AmbulanceStats()
	for fname in fieldnames(AmbulanceStats)
		setfield!(stats, fname, getfield(a, fname) - getfield(b, fname))
	end
	stats.ambIndex = a.ambIndex == b.ambIndex ? a.ambIndex : nullIndex
	return stats
end

function Base.:+(a::CallStats, b::CallStats)::CallStats
	stats = CallStats()
	for fname in fieldnames(CallStats)
		setfield!(stats, fname, getfield(a, fname) + getfield(b, fname))
	end
	stats.callIndex = a.callIndex == b.callIndex ? a.callIndex : nullIndex
	return stats
end

function Base.:-(a::CallStats, b::CallStats)::CallStats
	stats = CallStats()
	for fname in fieldnames(CallStats)
		setfield!(stats, fname, getfield(a, fname) - getfield(b, fname))
	end
	stats.callIndex = a.callIndex == b.callIndex ? a.callIndex : nullIndex
	return stats
end

Base.:+(a::Dict{Priority,CallStats}, b::Dict{Priority,CallStats}) = merge(+, a, b)
Base.:-(a::Dict{Priority,CallStats}, b::Dict{Priority,CallStats}) = merge(-, a, b)

function Base.:+(a::HospitalStats, b::HospitalStats)::HospitalStats
	stats = HospitalStats()
	for fname in fieldnames(HospitalStats)
		setfield!(stats, fname, getfield(a, fname) + getfield(b, fname))
	end
	stats.hospitalIndex = a.hospitalIndex == b.hospitalIndex ? a.hospitalIndex : nullIndex
	return stats
end

function Base.:-(a::HospitalStats, b::HospitalStats)::HospitalStats
	stats = HospitalStats()
	for fname in fieldnames(HospitalStats)
		setfield!(stats, fname, getfield(a, fname) - getfield(b, fname))
	end
	stats.hospitalIndex = a.hospitalIndex == b.hospitalIndex ? a.hospitalIndex : nullIndex
	return stats
end

function Base.:+(a::StationStats, b::StationStats)::StationStats
	stats = StationStats()
	for fname in fieldnames(StationStats)
		setfield!(stats, fname, getfield(a, fname) + getfield(b, fname))
	end
	stats.stationIndex = a.stationIndex == b.stationIndex ? a.stationIndex : nullIndex
	return stats
end

function Base.:-(a::StationStats, b::StationStats)::StationStats
	stats = StationStats()
	for fname in fieldnames(StationStats)
		setfield!(stats, fname, getfield(a, fname) - getfield(b, fname))
	end
	stats.stationIndex = a.stationIndex == b.stationIndex ? a.stationIndex : nullIndex
	return stats
end

function Base.:+(a::SimPeriodStats, b::SimPeriodStats)::SimPeriodStats
	@assert(a.startTime == b.endTime || a.endTime == b.startTime)
	stats = SimPeriodStats()
	for fname in fieldnames(SimPeriodStats)
		setfield!(stats, fname, getfield(a, fname) + getfield(b, fname))
	end
	stats.startTime = min(a.startTime, b.startTime)
	stats.endTime = max(a.endTime, b.endTime)
	return stats
end

function Base.:-(a::SimPeriodStats, b::SimPeriodStats)::SimPeriodStats
	@assert(a.startTime == b.startTime)
	stats = SimPeriodStats()
	for fname in fieldnames(SimPeriodStats)
		setfield!(stats, fname, getfield(a, fname) - getfield(b, fname))
	end
	stats.startTime = b.endTime
	stats.endTime = a.endTime
	return stats
end

function Base.print(mhw::MeanAndHalfWidth)
	print(mhw.mean, " ± ", mhw.halfWidth)
end

function Base.println(mhw::MeanAndHalfWidth)
	println(mhw.mean, " ± ", mhw.halfWidth)
end

function Base.:*(mhw::MeanAndHalfWidth, x::T) where T <: Real
	return MeanAndHalfWidth(mhw.mean * x, mhw.halfWidth * x)
end

function Base.:/(mhw::MeanAndHalfWidth, x::T) where T <: Real
	return MeanAndHalfWidth(mhw.mean / x, mhw.halfWidth / x)
end


text:
using JavaCall
using Iterators
import Base: map, reduce, count, collect, close

JSparkConf = @jimport org.apache.spark.SparkConf
JSparkContext = @jimport org.apache.spark.SparkContext
JJavaSparkContext = @jimport org.apache.spark.api.java.JavaSparkContext
JJavaRDD = @jimport org.apache.spark.api.java.JavaRDD
JJuliaRDD = @jimport org.apache.spark.api.julia.JuliaRDD

include("init.jl")
include("serialization.jl")
include("config.jl")
include("context.jl")
include("rdd.jl")
include("worker.jl")


text:
module IntervalCensoredEventTimes

using LinearAlgebra, SparseArrays
using Distributions, Ipopt, MathProgBase, StatsModels, UnicodePlots
import LinearAlgebra: BlasReal, copytri!, mul!

export fit!, iht!, initialize_uniform!, IcmAlphaMatrix,
IntervalCensoredModel, IntervalCensoredSparseModel,
loglikelihood!, npmle!

"""
IntervalCensoredModel

Interval censored event time model, which contains data, model parameters,
and working arrays.

IntervalCensoredModel(Z, L, R)

# Positional arguments
- `Z`: `n`-by-`p` covariate matrix, excluding intercept.
- `L`: `n` vector of left censoring times.
- `R`: `n` vector of right censoring times.

# Keyword arguments
"""
struct IntervalCensoredModel{T <: BlasReal} <: MathProgBase.AbstractNLPEvaluator
    # Data
    Z          :: Matrix{T} # n-by-p covariate matrix
    L          :: Vector{T} # n vector of left ends of interval
    R          :: Vector{T} # n vector of right ends of interval
    C          :: Vector{Symbol}    # n vector of censoring type
#    A          :: IcmAlphaMatrix{T} # αij=I(Li<sj≤Ri) indicator matrix
    # parameters
    β          :: Vector{T}   # regression coefficients
    Λ₀         :: Vector{T}   # baseline cumulative hazards
    λ₀         :: Vector{T}   # baseline hazards
    S₀         :: Vector{T}   # baseline survival function
    # working arrays
    ts         :: Vector{T}   # finite observed time points in the data
    Lidx       :: Vector{Int} # ts[Lidx] == L
    Ridx       :: Vector{Int} # ts[Ridx] == R
    η          :: Vector{T}   # η = Z * β
    expη       :: Vector{T}   # expη = exp(η)
    # gradient
    ∇λ₀        :: Vector{T}
    ∇β         :: Vector{T}
    βres       :: Vector{T}
    # Hessian
    Hλ₀λ₀      :: Matrix{T}
    Hββ        :: Matrix{T}
    Hλ₀β       :: Matrix{T}
    Vββ        :: Matrix{T}
    glmwt      :: Vector{T}
    # logical
    isfitted   :: Vector{Bool}
    # scrach spaces
    storage_n  :: Vector{T}
    storage_np :: Matrix{T}
end

function IntervalCensoredModel(
    Z :: AbstractMatrix{T},
    L :: Vector{T},
    R :: Vector{T}
    ) where T <: BlasReal
    n, p = size(Z)
    @assert length(L) == n "length(L) ≠ size(Z, 1); check input"
    @assert length(R) == n "length(R) ≠ size(Z, 1); check input"
    @assert all(L .≤ R) "Some L[i] are larger than R[i]; check input"
    @assert all(L .≥ 0) "Some L[i] are negative; check input"
    @assert all(R .≥ 0) "Some R[i] are negative; check input"
    ts   = unique!(sort!([L; R])) # last time can be infinity
    iszero(ts[1])  && popfirst!(ts)
    isinf(ts[end]) && pop!(ts)
    m = length(ts)
    # Lidx[i] = 0 if L[i] = 0
    Lidx = map(x -> isnothing(x) ? 0 : x, indexin(L, ts))
    # Ridx[i] = length(ts) + 1 if R[i] = Inf
    Ridx = map(x -> isnothing(x) ? length(ts) + 1 : x, indexin(R, ts))
    C    = Vector{Symbol}(undef, n)
    for i in 1:n
        if iszero(L[i]) # L[i] == 0
            if isfinite(R[i])
                C[i] = :left_censored
            else
                C[i] = :non_informative
            end
        elseif isfinite(L[i]) # 0 < L[i] < ∞
            if R[i] == L[i]
                C[i] = :exact_time
            elseif isfinite(R[i])
                C[i] = :interval_censored
            else
                C[i] = :right_censored
            end
        else # L[i] = ∞
            C[i] = :non_informative
        end
    end
    η        = Vector{T}(undef, n)
    expη     = Vector{T}(undef, n)
    β        = Vector{T}(undef, p)
    Λ₀       = Vector{T}(undef, m)
    λ₀       = Vector{T}(undef, m)
    S₀       = Vector{T}(undef, m)
    ∇λ₀      = Vector{T}(undef, m)
    ∇β       = Vector{T}(undef, p)
    βres     = Vector{T}(undef, n)
    Hλ₀λ₀    = Matrix{T}(undef, m, m)
    Hββ      = Matrix{T}(undef, p, p)
    Hλ₀β     = Matrix{T}(undef, m, p)
    Vββ      = Matrix{T}(undef, p, p)
    glmwt    = Vector{T}(undef, n)
    isfitted = [false]
    storage_n  = Vector{T}(undef, n)
    storage_np = Matrix{T}(undef, n, p)
    # constructor
    IntervalCensoredModel{T}(
        Z, L, R, C,
        β, Λ₀, λ₀, S₀, ts, Lidx, Ridx, η, expη,
        ∇λ₀, ∇β, βres,
        Hλ₀λ₀, Hββ, Hλ₀β, Vββ, glmwt, isfitted,
        storage_n, storage_np)
end

coefnames(icm::IntervalCensoredModel) = "Z" .* string.(1:size(icm.Z, 2))
coef(icm::IntervalCensoredModel) = icm.β
nobs(icm::IntervalCensoredModel) = length(icm.L)
stderror(icm::IntervalCensoredModel) = [sqrt(icm.Vββ[i, i]) for i in 1:size(icm.Z, 2)]
vcov(icm::IntervalCensoredModel) = icm.Vββ

confint(icm::IntervalCensoredModel, level::Real) = hcat(coef(icm), coef(icm)) +
    stderror(icm) * quantile(Normal(), (1. - level) / 2.) * [1. -1.]
confint(icm::IntervalCensoredModel) = confint(icm, 0.95)

function coeftable(icm::IntervalCensoredModel)
    mstder = stderror(icm)
    mcoefs = coef(icm)
    wald = mcoefs ./ mstder
    pvals = 2 * Distributions.ccdf.(Normal(), abs.(wald))
    StatsModels.CoefTable(hcat(mcoefs, mstder, wald, pvals),
        ["Estimate", "Std. Error", "Z", "Pr(>|Z|)"],
        coefnames(icm), 4, 3)
end

function Base.show(io::IO, icm::IntervalCensoredModel)
    println(io)
    println(io, "Interval Censored Event Time PH Model")
    println(io)
    println(io, "Total observations: $(length(icm.L))")
    println(io, "Left-censored     : $(count(x -> x == :left_censored, icm.C))")
    println(io, "Right-censored    : $(count(x -> x == :right_censored, icm.C))")
    println(io, "Interval-censored : $(count(x -> x == :interval_censored, icm.C))")
    println(io, "Exact time        : $(count(x -> x == :exact_time, icm.C))")
    println(io)
    if icm.isfitted[1]
        println(io, "Log-likelihood: $(loglikelihood!(icm))")
        println(io)
        println(io, "Regression coefficients:")
        show(io, coeftable(icm))
        println(io)
        println(io)
        println(io, "Baseline survival:")
        show(io, lineplot([0; icm.ts], [1; icm.S₀],
            xlabel = "Time", ylabel = "Survival Functions"))
    else
        println("The regression model has not been fit.")
        return nothing
    end
    println(io)
    println(io)
    nothing
end

"""
    ICM_Alpha_Matrix(icm::IntervalCensoredModel)

An indicator matrix constructed from an interval censored model.
- If `C[i]=:left-censored`, the correspondng row is 1{sj≤Ri}.
- If `C[i]=:right-censored`, the correspondng row is 1{sj≤Li}.
- If `C[i]=:interval-censored`, it generates **two rows**: 1{sj≤Li} and 1{Li<sj≤Ri}.
- If `C[i]=:exact_time`, the correspondng row is 1{sj≤Li}.
"""
struct IcmAlphaMatrix{T <: Real} <: AbstractMatrix{T}
    C     :: Vector{Symbol}
    s     :: Vector{T} # examination time points: 0 < s1 < ... < sm < ∞
    Lidx  :: Vector{Int}
    Ridx  :: Vector{Int}
end

function IcmAlphaMatrix(icm::IntervalCensoredModel{T}) where T <: Real
    # constructor
    IcmAlphaMatrix{T}(icm.C, icm.ts, icm.Lidx, icm.Ridx)
end

LinearAlgebra.issymmetric(::IcmAlphaMatrix) = false
Base.size(A::IcmAlphaMatrix) = (
    length(A.C) + count(ct -> ct == :interval_censored, A.C), length(A.ts)
    )

function LinearAlgebra.mul!(
    out :: Vector{T},
    A   :: IcmAlphaMatrix{T},
    v   :: Vector{T}
    ) where T <: Real
    fill!(out, 0)
    row = 1
    @inbounds for i in 1:length(A.C)
        if A.C[i] == :left_censored
            for j in 1:A.Ridx[i]
                out[row] += v[j]
            end
            row += 1
        elseif A.C[i] == :right_censored
            for j in 1:A.Lidx[i]
                out[row] += v[j]
            end
            row += 1
        elseif A.C[i] == :interval_censored
            for j in 1:A.Lidx[i]
                out[row] += v[j]
            end
            row += 1
            for j in (A.Lidx[i]+1):A.Ridx[j]
                out[row] += v[j]
            end
            row += 1
        elseif A.C[i] == :exact_time
            for j in 1:A.Lidx[i]
                out[row] += v[j]
            end
            row += 1
        end
    end
    out
end

function LinearAlgebra.mul!(
    out :: Vector{T},
    At  :: Transpose{T, IcmAlphaMatrix{T}},
    v   :: Vector{T}
    ) where T <: Real
    A = At.parent
    fill!(out, 0)
    row = 0
    for i in 1:A.nrows
        vrow = v[row]
        if A.C[i] == :left_censored
            for j in 1:A.Ridx[i]
                out[j] += vrow
            end
            row += 1
        elseif A.C[i] == :right_censored
            for j in 1:A.Lidx[i]
                out[j] += vrow
            end
            row += 1
        elseif A.C[i] == :interval_censored
            for j in 1:A.Lidx[i]
                out[j] += vrow
            end
            row += 1
            for j in (A.Lidx[i]+1):A.Ridx[j]
                out[j] += vrow
            end
            row += 1
        elseif A.C[i] == :exact_time
            for j in 1:A.Lidx[i]
                out[j] += vrow
            end
            row += 1
        end
    end
    out
end

include("nlp.jl")
include("sparse.jl")

end # module


text:
# Links: https://github.com/JuliaGraphs/GraphPlot.jl#arguments
# https://docs.juliaplots.org/latest/graphrecipes/examples/#Undirected-graph
using GraphRecipes
using LightGraphs
import Plots
Plots.pyplot()

h = watts_strogatz(50, 6, 0.3)

graphplot(h)


text:
using Scratch, CMake_jll

Metal = Base.UUID("dde4c033-4e86-420c-a63e-0dd931031962")

# get a scratch directory
scratch_dir = get_scratch!(Metal, "cmt")
isdir(scratch_dir) && rm(scratch_dir; recursive=true)
source_dir = joinpath(dirname(@__DIR__), "cmt")

mktempdir() do build_dir
    run(`$(cmake()) -DCMAKE_INSTALL_PREFIX=$(scratch_dir) -B$(build_dir) -S$(source_dir) -DCMAKE_BUILD_TYPE=Debug`)
    run(`$(cmake()) --build $(build_dir) --parallel $(Sys.CPU_THREADS)`)
    run(`$(cmake()) --install $(build_dir)`)
end


text:
using Test
using BEAST
using CompScienceMeshes

T = Float64
tol = eps(T) * 10^3

mesh = meshrectangle(1.0, 1.0, 0.5)
@test numvertices(mesh) == 9

idcs = mesh.faces[1]
@test size(idcs) == (3,)

verts = vertices(mesh, idcs)
@test size(verts) == (3,)

faces = skeleton(mesh, 2)
idcs = faces.faces[1]
verts = vertices(mesh, idcs)
p = simplex(verts, Val{2})
@test volume(p) == 1/8

edges = skeleton(mesh,1)
@test numcells(edges) == 16

cps = cellpairs(mesh, edges)
@test size(cps) == (2,16)

# select only inner edges
I = findall(x->(x>0), cps[2,:])
cps = cps[:,I]
@test size(cps) == (2,8)

# build the Raviart-Thomas elements
rt = raviartthomas(mesh, cps)
@test numfunctions(rt) == 8

function neighbortest(X)
    Γ = X.geo
    for (e,f) in enumerate(X.fns)
        i = Γ.faces[f[1].cellid]
        j = Γ.faces[f[2].cellid]
        ij = intersect(i,j)
        @assert length(ij) == 2
        ri = f[1].refid
        rj = f[2].refid
        #@assert !(i[ri] in ij)
        if (j[rj] in ij)
            @show e
            @show f
            @show i, ri
            @show j, rj
            @assert false
        end
    end
end

neighbortest(rt)


text: # Tests construction of various types


text:
@testset "Linear differential equations" begin

    T, t = Nemo.PowerSeriesRing(Nemo.GF(2^31 - 1), 300, "t"; model=:capped_absolute)

    for d = 1:5
        for c = 1:5
            S = Nemo.MatrixSpace(T, d, d)
            A = random_ps_matrix(T, S)
            B = random_ps_matrix(T, S)
            Sconst = Nemo.MatrixSpace(Nemo.GF(2^31 - 1), d, d)
            Y0 = Sconst([rand(Int) % 100 for i = 1:d, j = 1:d])
            @time sol = ps_matrix_linear_de(A, B, Y0)
            to_be_zero = map(ps_diff, sol) - A * sol - B
            @test truncate_matrix(to_be_zero, 299) == truncate_matrix(zero(S), 299)
        end
    end

end


text:
function closure_tke_full_evolution(parameters, U⁰, V⁰, T⁰, t, les; subsample = 1, grid = 1)

     # set parameters
     # parameters = TKEMassFlux.TKEParameters( Cᴰ = Cᴰ )

     # assume constant interval between time steps
     Δt = t[2] - t[1]

     # number of gridpoints
     N = length(T⁰)

     # Build the model with a Backward Euler timestepper
     constants = Constants(Float64; α = les.α , β = les.β, f=les.f⁰, g=les.g)
     model = TKEMassFlux.Model(grid = UniformGrid(N, les.L), stepper=:BackwardEuler, constants = constants, tke_equation = parameters)

     # Get grid if necessary
     if grid != 1
         zp = collect(model.grid.zc)
         @. grid  = zp
     end

     # Set boundary conditions
     model.bcs.U.top    = FluxBoundaryCondition(les.u_top)
     model.bcs.U.bottom = GradientBoundaryCondition(les.u_bottom)
     model.bcs.T.top    = FluxBoundaryCondition(les.θ_top)
     model.bcs.T.bottom = GradientBoundaryCondition(les.θ_bottom) # may need to fix

    # define the closure
    function evolve()

        # set equal to initial condition of parameterization
        model.solution.U[1:N] = copy(U⁰)
        model.solution.V[1:N] = copy(V⁰)
        model.solution.T[1:N] = copy(T⁰)

        # set aside memory
        if subsample != 1
            time_index = subsample
        else
            time_index = 1:length(t)
        end
        Nt = length(t[time_index])

        U_evolution = zeros(N, Nt)
        V_evolution = zeros(N, Nt)
        T_evolution = zeros(N, Nt)

        # loop the model
        ti = collect(time_index)
        for i in 1:Nt
            time = t[ti[i]]
            run_until!(model, Δt, time)
            @. U_evolution[:,i] = model.solution.U[1:N]
            @. V_evolution[:,i] = model.solution.V[1:N]
            @. T_evolution[:,i] = model.solution.T[1:N]
        end
        return (U_evolution, V_evolution, T_evolution)
    end
    return evolve
end


text:
# RainFARM:  Stochastic downscaling following
# - *D'Onofrio et al. 2014, J of Hydrometeorology 15 , 830-843* and
# - *Rebora et. al 2006, JHM 7, 724*
# Includes orographic corrections
# Implementation in Julia language

# Copyright 2016 Jost von Hardenberg
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
# either express or implied.
# See the License for the specific language governing permissions
# and limitations under the License.

__precompile__()
module RainFARM
    export agg, fft3d, initmetagauss, gaussianize, metagauss, smoothconv, smoothspec
    export mergespec_spaceonly, downscale_spaceonly, lon_lat_fine, fitslope
    export read_netcdf2d, write_netcdf2d, rainfarm, interpola, smooth
    export overwrite_netcdf2d, rfweights

    using Interpolations, NetCDF, FFTW
    using Statistics, Printf, SparseArrays

    include("rf/agg.jl")
    include("rf/smoothconv.jl")
    include("rf/smoothspec.jl")
    include("rf/smooth.jl")
    include("rf/fft3d.jl")
    include("rf/initmetagauss.jl")
    include("rf/gaussianize.jl")
    include("rf/metagauss.jl")
    include("rf/mergespec_spaceonly.jl")
    include("rf/downscale_spaceonly.jl")
    include("rf/lon_lat_fine.jl")
    include("rf/fitslope.jl")
    include("rf/read_netcdf2d.jl")
    include("rf/write_netcdf2d.jl")
    include("rf/overwrite_netcdf2d.jl")
    include("rf/interpola.jl")
    include("rf/rainfarm.jl")
    include("rf/rfweights.jl")

end


text:
using Raylib

const screenWidth = 800
const screenHeight = 450

function main()
    Raylib.InitWindow(
        screenWidth, screenHeight,
        "raylib [core] example - 3d camera free"
    )

    # Define the camera to look into our 3d world
    camera = Raylib.RayCamera3D(
        Raylib.rayvector(0, 10, 10),   # Camera position
        Raylib.rayvector(0, 0, 0), # Camera looking at point
        Raylib.rayvector(0, 1, 0), # Camera up vector (rotation towards target)
        45, # Camera field-of-view Y
        Int(Raylib.CAMERA_PERSPECTIVE), # Camera mode type
    )

    cubePosition = Raylib.rayvector(0, 0, 0)

    Raylib.SetCameraMode(camera, Int(Raylib.CAMERA_FREE))   # Set a free camera mode

    Raylib.SetTargetFPS(60)
    while !Raylib.WindowShouldClose()   # Detect window close button or ESC key
        # Update
        camera = Raylib.UpdateCamera(camera)    # Update camera
        Raylib.IsKeyDown(Int('Z')) && (camera = Raylib.RayCamera3D(
            camera.position,
            Raylib.rayvector(0, 0, 0),
            camera.up,
            camera.fovy,
            camera.projection
        ))

        # Draw
        Raylib.BeginDrawing()
        Raylib.ClearBackground(Raylib.RAYWHITE)

        Raylib.BeginMode3D(camera)
        Raylib.DrawCube(cubePosition, 2f0, 2f0, 2f0, Raylib.RED)

        Raylib.DrawCubeWires(cubePosition, 2f0, 2f0, 2f0, Raylib.MAROON)

        Raylib.DrawGrid(10, 1f0)

        Raylib.EndMode3D()

        Raylib.DrawRectangle(10, 10, 320, 133, Raylib.Fade(Raylib.SKYBLUE, 0.5))
        Raylib.DrawRectangleLines(10, 10, 320, 133, Raylib.BLUE)

        Raylib.DrawText("Free camera default controls:", 20, 20, 10, Raylib.BLACK)
        Raylib.DrawText("- Mouse Wheel to Zoom in-out", 40, 40, 10, Raylib.DARKGRAY)
        Raylib.DrawText("- Mouse Wheel Pressed to Pan", 40, 60, 10, Raylib.DARKGRAY)
        Raylib.DrawText("- Alt + Mouse Wheel Pressed to Rotate", 40, 80, 10, Raylib.DARKGRAY)
        Raylib.DrawText("- Alt + Ctrl + Mouse Wheel Pressed for Smooth Zoom", 40, 100, 10, Raylib.DARKGRAY)
        Raylib.DrawText("- Z to zoom to (0, 0, 0)", 40, 120, 10, Raylib.DARKGRAY)

        Raylib.EndDrawing()
    end

    Raylib.CloseWindow()
end


text:
@testset "ObjectId" begin

@testset "construct" begin
    x = BSONObjectId((0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc))
    @test BSONObjectId("0102030405060708090a0b0c") == x
    @test BSONObjectId("0102030405060708090A0B0C") == x
    @test BSONObjectId([UInt8(x) for x in 1:12]) == x
    @test_throws ArgumentError BSONObjectId("0102030405060708090a0b")
    @test_throws ArgumentError BSONObjectId("0102030405060708090a0b0c0d")
    @test_throws ArgumentError BSONObjectId("010203040506070809xxxx")
    @test_throws ArgumentError BSONObjectId([UInt8(x) for x in 1:11])
    @test_throws ArgumentError BSONObjectId([UInt8(x) for x in 1:13])
end

@testset "string" begin
    x = BSONObjectId((0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc))
    @test string(x) == "0102030405060708090a0b0c"
end

@testset "generate" begin
    x1 = BSONObjectId()
    x2 = BSONObjectId()
    x3 = BSONObjectId()
    @test x1 != x2
    @test x2 != x3
    @test now(UTC) - DateTime(x1) < Minute(5)
    @test time() - time(x1) < 5*60
end

@testset "generate range" begin
    x = collect(bson_object_id_range(3))
    @test length(x) == 3
    @test eltype(x) == BSONObjectId
    @test x[1] != x[2]
    @test x[1] != x[3]
    @test x[2] != x[3]
    @test DateTime(x[1]) == DateTime(x[2])
    @test DateTime(x[1]) == DateTime(x[3])
end

end


text:
abstract type Serializer end
Serializer(serializer::NamedTuple) = StatelessSerializer(serializer)

struct StatelessSerializer
    serialize
    deserialize
end

StatelessSerializer(; serialize, deserialize) = StatelessSerializer(serialize, deserialize)

StatelessSerializer(serializer::NamedTuple) = StatelessSerializer(; serializer...)

trygetid(x::AbstractDict) = haskey(x, :id) ? x : get(x, "id", nothing)
trygetid(x::NamedTuple) = get(x, :id, nothing)
trygetid(x) =
    try
        try
            return x.id
        catch
        end
        return x[:id]
    catch
        return nothing
    end

function ignoringclosed(f, io, args...)
    try
        return f(io, args...)
    catch err
        err isa IOError && !isopen(io) && return
        rethrow()
    end
end

# https://en.wikipedia.org/wiki/JSON_streaming

function jsonparseln(io)
    line = readline(io)
    isempty(line) && return nothing
    @debug "jsonparseln" line
    return JSON.parse(line)
end

function jsonprintln(io, x)
    @debug "jsonprintln: Sending" x

    local line, err, backtrace
    try
        line = JSON.json(x)
        true
    catch err
        @error "`jsonprintln` failed to send serialize a message" exception = (
            err,
            catch_backtrace(),
        )
        backtrace = sprint(showerror, err, catch_backtrace())
        false
    end && begin
        ignoringclosed(println, io, line)
        return
    end

    # Failed to serialize. Try to respond as an error:
    id = trygetid(x)
    message = sprint(showerror, err)
    data = (backtrace = backtrace,)
    line = JSON.json(ErrorResponse(id, SerializationError, message, data))
    ignoringclosed(println, io, line)
    return
end

const NDJSON = (serialize = jsonprintln, deserialize = jsonparseln)

# probably doesn't work?
const Concatenated_JSON = (serialize = JSON.print, deserialize = JSON.parse)


text:
function ParseAST(sema::Sema, PrintStats::Bool=false, SkipFunctionBodies::Bool=false)
    @check_ptrs sema
    clang_ParseAST(sema, PrintStats, SkipFunctionBodies)
    return nothing
end

function tryParseAndSkipInvalidOrParsedDecl(p::Parser, cg::CodeGenerator)
    @check_ptrs p cg
    return clang_Parser_tryParseAndSkipInvalidOrParsedDecl(p, cg)
end


text:
using SparseArrays

for N in [Float64, Float32, Rational{Int}]
    p0 = zero(N)
    p1 = one(N)
    v0 = zeros(N, 2)
    v1 = ones(N, 2)

    # ---------------
    # set definitions
    # ---------------

    # bounded basic set types
    b1 = Ball1(v0, p1)
    bi = BallInf(v0, p1)
    hr = Hyperrectangle(v0, v1)
    itv = Interval(p0, p1)
    ls = LineSegment(v0, v1)
    st = Singleton(v1)
    zt = Zonotope(v0, Diagonal(N[1, 1]))
    zs = ZeroSet{N}(2)

    # -------------------------------------------
    # plot polytopes
    # -------------------------------------------
    plot(b1)
    plot(bi)
    plot(hr)
    plot(itv)
    plot(ls)
    plot(st)
    plot(zt)
    plot(zs)

    if N == Rational{Int}
        # rationals do not support epsilon-close approximation
        continue
    end

    # bounded basic set types which are not polytopes
    b2 = Ball2(v0, p1)
    bp = Ballp(N(1.5), v0, p1)
    el = Ellipsoid(v0, Diagonal(N[1, 1]))

    # unary set operations
    spI = SparseMatrixCSC{N}(2I, 2, 2)
    sme = SparseMatrixExp(spI)
    em = ExponentialMap(sme, b2)
    psme = ProjectionSparseMatrixExp(spI, sme, spI)
    epm = ExponentialProjectionMap(psme, b2)

    # binary set operations
    its = Intersection(b1, bi)
    itsa = IntersectionArray([b1, bi])

    # polygon/polytope types
    constraints = [LinearConstraint([p1, p0], p1),
                   LinearConstraint([p0, p1], p1),
                   LinearConstraint([-p1, p0], p0),
                   LinearConstraint([p0, -p1], p0)]
    hpg = HPolygon(constraints)
    hpgo = HPolygonOpt(constraints)
    hpt = HPolytope(constraints)
    vertices = vertices_list(bi)
    vpg = VPolygon(vertices)
    vpt = VPolytope(vertices)

    # empty set
    es = EmptySet{N}()

    # infinite sets
    hs = HalfSpace(v1, p1)
    hp = Hyperplane(v1, p1)
    l = Line(v1, p1)
    uni = Universe{N}(2)

    # unary set operations
    sih = SymmetricIntervalHull(b1)
    lm = LinearMap(N[2 1; 1 2], bi)
    rm = ResetMap(bi, Dict(1 => N(1)))

    # binary set operations
    ch = ConvexHull(b1, bi)
    cha = ConvexHullArray([b1, bi])

    ms = MinkowskiSum(b1, bi)
    msa = MinkowskiSumArray([b1, bi])
    cms = CacheMinkowskiSum([b1, bi])
    cp = CartesianProduct(itv, itv)
    cpa = CartesianProductArray([itv, itv])

    # ------------------------------------------------------------------
    # plot using epsilon-close approximation (default threshold ε value)
    # ------------------------------------------------------------------
    if N == Float64 # Float32 requires promotion see #1304
        plot(its)
    end
    plot(hpg)
    plot(hpgo)
    if test_suite_polyhedra
        plot(hpt)
    end
    plot(vpg)
    plot(vpt)
    plot(es)
    @test_throws AssertionError plot(hs) # TODO see #576
    @test_throws AssertionError plot(hp) # TODO see #576
    @test_throws AssertionError plot(l) # TODO see #576
    @test_throws AssertionError plot(uni) # TODO see #576
    plot(ch)
    plot(cha)
    plot(sih)
    plot(lm)
    plot(rm)
    plot(ms)
    plot(msa)
    plot(cms)
    plot(cp)
    plot(cpa)

    # -----
    # cases that are not implemented
    # -----
    @test_throws ErrorException plot(itsa) # TODO not implemented yet
end


text:
"""
Functionality for handling the default content of the various files (migrations, models, controllers, etc).
"""
module FileTemplates

using SearchLight

"""
    new_database_migration(module_name::String) :: String

Default content for a new SearchLight migration.
"""
function new_table_migration(module_name::String, resource::String) :: String
  """
  module $module_name

  import SearchLight.Migrations: create_table, column, primary_key, add_index, drop_table

  function up()
    create_table(:$resource) do
      [
        primary_key()
        column(:column_name, :column_type)
      ]
    end

    add_index(:$resource, :column_name)
  end

  function down()
    drop_table(:$resource)
  end

  end
  """
end

function newmigration(module_name::String) :: String
  """
  module $module_name

  import SearchLight.Migrations: add_column, add_index

  function up()

  end

  function down()

  end

  end
  """
end

"""
    newmodel(model_name::String, resource_name::String = model_name) :: String

Default content for a new SearchLight model.
"""
function newmodel(model_name::String, resource_name::String = model_name; pluralize::Bool = true) :: String
  """
  module $(SearchLight.Inflector.to_plural(model_name))

  import SearchLight: AbstractModel, DbId
  import Base: @kwdef

  export $model_name

  @kwdef mutable struct $model_name <: AbstractModel
    id::DbId = DbId()
  end

  end
  """
end

"""
    newvalidator(validator_name::String) :: String

Default content for a new SearchLight validator.
"""
function newvalidator(validator_name::String; pluralize::Bool = true) :: String
  """
  module $(SearchLight.Inflector.to_plural(validator_name))Validator

  using SearchLight, SearchLight.Validation

  function not_empty(field::Symbol, m::T, args::Vararg{Any})::ValidationResult where {T<:AbstractModel}
    isempty(getfield(m, field)) && return ValidationResult(invalid, :not_empty, "should not be empty")

    ValidationResult(valid)
  end

  end
  """
end

function adapter_default_config end

function newconfig() :: String
  """
  env: $(SearchLight.config.app_env)

  $(adapter_default_config())
    config:
      log_queries: true
      log_level: :debug
  """
end

"""
    newtest(resource_name::String) :: String

Default content for a new test file.
"""
function newtest(resource_name::String) :: String
  """
  using Test, SearchLight, $resource_name

  @testset "$resource_name unit tests" begin

    ### Your tests here
    @test 1 == 1

  end;
  """
end

end


text:
l_vertex = 2
center = 5
r_vertex = 7

mf = TriangularMF(l_vertex, center, r_vertex)

# Evaluation tests
@assert mf.eval(center) == 1
@assert mf.eval(l_vertex) == mf.eval(r_vertex) == 0
@assert mf.eval((l_vertex + center) / 2) == mf.eval((r_vertex + center) / 2) == 0.5

# Mean finding tests
@assert mf.mean_at(1) == center
@assert mf.mean_at(0) == (l_vertex + r_vertex) / 2


text:
using Test
using Mongoc
using GraffSDK
using UUIDs
using Caesar
using HTTP
using JSON2

function waitForQueueToEmpty()
    waitsLeft = 10
    while getSessionBacklog() > 0 && waitsLeft > 0
        @info "...Session backlog currently has $(getSessionBacklog()) entries, waiting until complete..."
        sleep(3)
        waitsLeft-=1;
    end
    if getSessionBacklog() > 0
        error("Nope, graph was not completely consumed in time - failing!")
    end
    if getSessionDeadQueueLength() > 0
        error("Nope, some messages ended up in dead queue... check it:")
        @info getSessionDeadQueueMessages()
    end
end

@testset "End-To-End Tests" begin

@testset "Configuration" begin
    # 1a. Create a Configuration using default file
    global config = loadGraffConfig();
    # global config = loadGraffConfig("synchronyConfigLocal.json");
    @test getGraffConfig() == config
    global config = getGraffConfig()
    config.userId = "QA"
    config.robotId = "QARobot_"*replace(string(uuid4()), "-" => "")
    config.sessionId = "QASession_"*replace(string(uuid4()), "-" => "")
    @info config
end

@testset "User and User Config" begin
    global config = getGraffConfig()
    @test getUser(config.userId) != nothing
end

@testset "Robot Creation and Configuration" begin
    @test length(getRobots().robots) > 0
    @test isRobotExisting() == false
    newRobot = RobotRequest(config.robotId, "QARobot", "QA Robot", "Active");
    robot = addRobot(newRobot);
    @test getRobot().id == robot.id
    @test isRobotExisting() == true

    robotConfig = getRobotConfig()

    @test robotConfig != nothing
    robotConfig["DepthCameraModel"] = "{\"width\":640,\"height\":480,\"fc\":[387.205,387.205],\"f\":387.205,\"cc\":[322.042,238.544],\"skew\":0.0,\"kc\":[0.0],\"K\":[387.205,0.0,0.0,0.0,387.205,0.0,322.042,238.544,1.0],\"Ki\":[0.0025826112782634525,0.0,0.0,0.0,0.0025826112782634525,0.0,-0.8317093012745187,-0.6160664247620771,1.0]}"
    robotConfig["RGBCameraModel"] = "{\"width\":640,\"height\":480,\"fc\":[387.205,387.205],\"f\":387.205,\"cc\":[322.042,238.544],\"skew\":0.0,\"kc\":[0.0],\"K\":[387.205,0.0,0.0,0.0,387.205,0.0,322.042,238.544,1.0],\"Ki\":[0.0025826112782634525,0.0,0.0,0.0,0.0025826112782634525,0.0,-0.8317093012745187,-0.6160664247620771,1.0]}"
    robotConfig["TestParam"] = "This is a test configuration parameter"
    updateRobotConfig(robotConfig)
    retConfig = getRobotConfig()

    @test retConfig == robotConfig

    #Clear it out and test that works too
    updateRobotConfig(Dict{Any, Any}())
    @test getRobotConfig() == Dict{Any, Any}()
end

@testset "Session Creation" begin
    global config = getGraffConfig()
    @test isSessionExisting() == false
    newSessionRequest = SessionDetailsRequest(config.sessionId, "QA Test dataset.", "Pose2")
    session = addSession(newSessionRequest)
    @test session != nothing
    @test getSession() != nothing
    @test length(GraffSDK.ls().nodes) == 1
    # Update session
end

@testset "Classical Variable and Factor Creation" begin
    deltaMeasurement = [1.0, 1.0, 0.05]
    pOdo = [0.01 0 0; 0 0.005 0; 0 0 0.02]
    pp = Pose2Pose2(MvNormal(deltaMeasurement, pOdo.^2))
    addVariable(:x1, Pose2, String[])
    addFactor([:x0;:x1], pp)
    # Landmark
    addVariable(:l1, Point2, ["LANDMARK"])
    p2br = Pose2Point2BearingRange(Normal(0.1,0.1), Normal(0.1, 0.1))
    addFactor([:x0; :l1], p2br)
    # Waiting for completion
    waitForQueueToEmpty()

    nodes = GraffSDK.ls()
    @test length(nodes.nodes) == 3

    # Put ready
    putReady(true)
end

@testset "Listing and Getting Variables" begin
    nodes = GraffSDK.ls()
    @test length(nodes.nodes) == 3
    @test map(n -> n.label, nodes.nodes) == ["l1", "x0", "x1"]
    @test getNode("l1").label == "l1"
    @test getNode("x0").label == "x0"
    @test getNode("x1").label == "x1"
end

@testset "Odometry and BearingRange Creation" begin
end

@testset "Data Setting/Getting" begin
    @test length(getDataEntries(getNode("x0"))) == 0
    data = "TEST DATA.............................................................."
    dataUpdate = "UPDATED"
    x0 = getNode("x0")
    setData(x0, "testId", data)
    waitForQueueToEmpty()
    @test length(getDataEntries(x0)) == 1
    setData(getNode("x0"), "testId2", data)
    waitForQueueToEmpty()
    @test length(getDataEntries(x0)) == 2
    setData(x0, "testId", dataUpdate)
    waitForQueueToEmpty()
    @test length(getDataEntries(x0)) == 2
    @test GraffSDK.getData(x0, "testId").data == dataUpdate
    @test getRawData(x0, "testId") == dataUpdate
    deleteData(x0, "testId2")
    # This is synchronous
    @test length(getDataEntries(x0)) == 1

    # New method - retrieves all entries for an entire session
    sessionEntries = getDataEntriesForSession()
    @test length(sessionEntries) == 3
    @test haskey(sessionEntries, "x0")
    @test length(sessionEntries["x0"]) == 1
end

@testset "Data Caching" begin
    dataUpdate = "UPDATED"
    x0 = getNode("x0")
    x1 = getNode("x1")
    # Make sure cloud data is set.
    setData(x0, "testId", dataUpdate)
    waitForQueueToEmpty()

    # Set up a local cache
    client = Mongoc.Client("localhost", 27017)
    database = client["GraffLocal"]
    collection = database["GraffLocal"]
    localCache = LocalCache(client, collection)
    setLocalCache(localCache)
    @test getLocalCache() == localCache
    # Force local caching only
    forceOnlyLocalCache(true)

    @test GraffSDK.getData(x0, "testId") == nothing # Not in cache
    @test GraffSDK.getData(x1, "testId") == nothing # Not in cache
    forceOnlyLocalCache(false)
    @test GraffSDK.getData(x0, "testId").data == dataUpdate
    @test_throws HTTP.ExceptionRequest.StatusError GraffSDK.getData(x1, "testId") == nothing
    # Now it should be cached
    forceOnlyLocalCache(true)
    @test GraffSDK.getData(x0, "testId").data == dataUpdate

    # Now try the mirroring
    newData = "Testing Dataaaaaaa...."
    forceOnlyLocalCache(false)
    GraffSDK.setData(x0, "testId2", newData)
    waitForQueueToEmpty()
    # Now should be cached...
    @test GraffSDK.getData(x0, "testId2").data == newData
    @test GraffSDK.getData(x0, "testId2").data == newData
    # Turn off upstream
    forceOnlyLocalCache(true)
    @test GraffSDK.getData(x0, "testId2").data == newData
    # Turn off cache and check that it's upstream
    forceOnlyLocalCache(false)
    setLocalCache(nothing)
    @test GraffSDK.getData(x0, "testId2").data == newData
    # Now delete on both and make sure it's gone
    setLocalCache(localCache)
    GraffSDK.deleteData(x0, "testId")
    GraffSDK.deleteData(x0, "testId2")
    @test_throws HTTP.ExceptionRequest.StatusError GraffSDK.getData(x0, "testId2")
    # And local only too...
    forceOnlyLocalCache(true)
    @test GraffSDK.getData(x0, "testId2") == nothing

    # Now turn caching off again and carry on.
    forceOnlyLocalCache(false)
    setLocalCache(nothing)
end

@testset "Helper Functions" begin
    @test length(getEstimates()) == 3
    @test length(getLandmarks()) == 1
end

@testset "Import/Export" begin
    file = "testFile.jld2"
    if isfile(file)
        rm(file)
    end
    exportSessionJld(file)
    @test isfile(file)
    # New test code!
    fg = loadjld(;file=file)
    @test ls(fg)[1] = ["x0", "x1", "l1"]
    # TODO: Import
end

@testset "Negative Test Cases" begin
end

# New stuff!

@testset "ZMQ Variable and Factor Creation" begin
end

@testset "Graff Editing" begin
end

end


text:
# This file is loaded conditionally for supported versions of Julia

export TreeMenu

mutable struct TreeMenu{N<:Node} <: TerminalMenus._ConfiguredMenu{TerminalMenus.Config}
    root::N
    current::N
    currentidx::Int
    currentdepth::Int
    cursoridx::Int
    chosen::Bool   # when true, indicates that `current` was chosen by user
    # Needed by REPL.TerminalMenus
    pagesize::Int
    dynamic::Bool
    maxsize::Int
    pageoffset::Int
    config::TerminalMenus.Config
end
function TreeMenu(root; pagesize::Int=10, dynamic = false, maxsize = pagesize, kwargs...)
    pagesize = min(pagesize, count_open_leaves(root))
    return TreeMenu(root, root, 1, 1, 1, false, pagesize, dynamic, maxsize, 0, TerminalMenus.Config(kwargs...))
end

"""
    writeoption(buf::IO, data, charsused::Int; width::Int=displaysize(stdout)[2])

Print `data` to `buf` as a menu option. `charsused` is the number of characters already printed on that line.
`width` allows you to specify the display width (in characters), which defaults to the width of the terminal window.

Given a tree built from `Node{Data}`, packages implementing a `TreeMenu` may need to implement
`writeoption(buf, data::Data, charsused)`.

The implementation for `data::AbstractString` is careful to ensure that the option does not wrap to a new
line of the terminal, and to ensure that any color printing is turned off even when the line has to be truncated.
"""
function writeoption(buf::IO, str::AbstractString, charsused::Int; width::Int=(displaysize(stdout)::Tuple{Int,Int})[2])
    function print_escape_code(buf, str, idx)
        idxe = nextind(str, idx)
        c = str[idxe]
        if c == '['
            idxe = nextind(str, idxe)
            while true
                c = str[idxe]
                if '0' <= c <= '9' || c == ';'
                    idxe = nextind(str, idxe)
                elseif c == 'm'
                    # This is the end of a mode-setting code. Render it without counting it against the char count.
                    print(buf, str[idx:idxe])
                    idx = nextind(str, idxe)
                    break
                else
                    error("terminal escape code ", escape_string(str[idx:idxe]), " not supported")
                end
            end
            return idx
        end
        error("terminal escape code ", escape_string(str[idx:idxe]), " not supported")
    end

    nchars = width - charsused
    idx, k = 1, 0
    idxend = lastindex(str)
    while k < nchars && idx <= idxend
        c = str[idx]
        if c == '\n' || c == '\r'
            idx = nextind(str, idx) # don't print `\n` or `\r`, but also don't count against total
            continue
        elseif c == '\e' # ANSI terminal escape code
            idx = print_escape_code(buf, str, idx)
        else
            print(buf, c)
            idx, k = nextind(str, idx), k+1
        end
    end
    if idx <= idxend
        # Print all the remaining escape codes, to set the state correctly for the next commands
        idx = nextind(str, idx)
        while idx <= idxend
            c = str[idx]
            if c == '\e'
                idx = print_escape_code(buf, str, idx)
            else
                idx = nextind(str, idx)
            end
        end
    end
    return nothing
end

function writeoption(buf::IO, data, charsused::Int; kwargs...)
    io = IOBuffer()
    show(io, data)
    writeoption(buf, String(take!(io)), charsused; kwargs...)
end

# AbstractMenu API
function TerminalMenus.pick(menu::TreeMenu, cursor::Int)
    setcurrent!(menu, cursor)
    menu.chosen = true
    return true
end

TerminalMenus.cancel(menu::TreeMenu) = menu.chosen = false

TerminalMenus.numoptions(menu::TreeMenu) = count_open_leaves(menu.root)

function TerminalMenus.writeline(buf::IOBuffer, menu::TreeMenu, idx::Int, cursor::Bool)
    node = setcurrent!(menu, idx)
    if cursor
        menu.cursoridx = idx
    end
    node.foldchildren ? print(buf, "+") : print(buf, " ")
    print(buf, " "^menu.currentdepth)
    writeoption(buf, node.data, menu.currentdepth+4)
end

function TerminalMenus.keypress(menu::TreeMenu, i::UInt32)
    if i == Int(' ')
        node = setcurrent!(menu, menu.cursoridx)
        node.foldchildren = !node.foldchildren
        if menu.dynamic
            menu.pagesize = min(menu.maxsize, count_open_leaves(menu.root))
        end
    end
    return false
end

function TerminalMenus.selected(menu::TreeMenu)
    menu.chosen || return nothing
    return menu.current
end

# Internals

function setcurrent!(menu::TreeMenu, idx::Int)
    node, depth = menu.current, menu.currentdepth
    Δidx = idx - menu.currentidx
    while Δidx > 0
        node, depth = next(node, depth)
        Δidx -= 1
    end
    while Δidx < 0
        node, depth = prev(node, depth)
        Δidx += 1
    end
    menu.current = node
    menu.currentdepth = depth
    menu.currentidx = idx
    return node
end


text:
__precompile__(true)
module SortingLab

# export sort, sort!
# package code goes here

#using InternedStrings, StatsBase, CategoricalArrays

import InternedStrings
import StatsBase: countmap
import CategoricalArrays: CategoricalArray
import SortingAlgorithms: uint_mapping
import Base.Threads: @threads

export fsortperm, radixsort, radixsort!, fsort, fsort!

include("radixsort_string.jl")
include("fsortperm_string.jl")
include("fsortperm_Integer.jl")
include("radixsort.jl")
include("fsort_CategoricalArrays.jl")
# include("../benchmarks/is_parallel_hist_faster_YES.jl")
end # module