text:
## Copyright (c) 2013 Miguel Bazdresch
##
## This file is distributed under the 2-clause BSD License.

function closefigure(x...)
    global gnuplot_state
    global gaston_config

    # parse argument
    if isempty(x)
        # close current figure
        h = gnuplot_state.current
    else
        h = x[1]
        if !(isa(h,Int) && h > 0)
            error("Invalid handle")
        end
    end

    term = gaston_config.terminal
    # create vector of handles
    handles = Any[]
    if gnuplot_state.current != 0
        for i in gnuplot_state.figs
            push!(handles, i.handle)
        end
    end
    if in(h, handles)
        # only care about closing windows if term type is screen
        if is_term_screen(term)
            if gnuplot_state.running
                gnuplot_send("set term $term $h close")
            end
        end
        # delete all data related to this figure
        _figs = Any[]
        for i in gnuplot_state.figs
            if i.handle != h
                push!(_figs, i)
            end
        end
        gnuplot_state.figs = _figs
        # update state
        if isempty(gnuplot_state.figs)
            # we just closed the last figure
            gnuplot_state.current = 0
        else
            # select the most-recently created figure
            gnuplot_state.current = gnuplot_state.figs[end].handle
        end
    else
        h = 0
    end
    return h
end

# close all figures
function closeall()
    global gnuplot_state

	closed = 0
	for i in gnuplot_state.figs
		closefigure()
		closed = closed + 1
	end
	return closed
end

# remove a figure's data without closing it
function clearfigure(h::Int)
    global gnuplot_state

    f = findfigure(h)
    if f != 0
        gnuplot_state.figs[f] = Figure(h)
    end
end

# Select or create a figure. When called with no arguments, create a new
# figure. Figure handles must be natural numbers.
# Returns the current figure handle.
function figure(h::Int,redraw::Bool)
    global gnuplot_state
    global gaston_config

    term = gaston_config.terminal

    # assert h is non-negative
    @assert(h >= 0, "Figure handle must not be negative.")

    # see if we need to set up gnuplot
    if gnuplot_state.running == false
        gnuplot_init();
    end
    # create vector of handles, needed later
    handles = Any[]
    for i in gnuplot_state.figs
        push!(handles, i.handle)
    end
    # determine figure handle
    if gnuplot_state.current == 0
        if h == 0
            h = 1
        end
    else
        if h == 0
            # use lowest numbered handle available
            mh = maximum(handles)
            for i = 1:mh+1
                if !in(i, handles)
                    h = i
                    break
                end
            end
        end
    end
    # if figure with handle h exists, replot it; otherwise create it
    gnuplot_state.current = h
    if !in(h, handles)
        push!(gnuplot_state.figs, Figure(h))
    else
        if redraw
            llplot()
        end
    end
    return h
end
figure() = figure(0,true)
figure(h::Int) = figure(h,true)

# 2-d plots
function plot(args...)
    global gnuplot_state
    # if args[1] is an integer, it's the figure handle.
    if isa(args[1], Int)
        h = args[1]
        args = args[2:end]   # argument parsing starts with 1 (eases debug)
    else
        h = gnuplot_state.current
    end
    h = figure(h,false) # create/select figure
    clearfigure(h)  # remove all figure configuration
    # parse arguments
    state = "SINI"
    la = length(args)
    while(true)
        if state == "SINI"
            i = 1
            cc = CurveConf()
            ac = AxesConf()
            state = "S1"
        elseif state == "S1"
            if i > la
                state = "SERROR"
                continue
            end
            y = args[i]
            i = i+1
            state = "S2"
        elseif state == "S2"
            if i > la
                addcoords(y,cc)
                state = "SEND"
                continue
            end
            if isa(args[i], AbstractString)
                x = 1:length(y)
                state = "S4"
            else
                x = y
                y = args[i]
                i = i+1
                state = "S3"
            end
        elseif state == "S3"
            if i > la
                addcoords(x,y,cc)
                state = "SEND"
                continue
            end
            if isa(args[i], AbstractString)
                state = "S4"
            else
                addcoords(x,y,cc)
                cc = CurveConf()
                y = args[i]
                i = i+1
                state = "S2"
            end
        elseif state == "S4"
            if i+1 > la
                state = "SERROR"
                continue
            end
            ai = args[i]; ai1 = args[i+1]
            if ai == "legend"
                cc.legend = ai1
            elseif ai == "plotstyle"
                cc.plotstyle = ai1
            elseif ai == "color"
                cc.color = ai1
            elseif ai == "marker"
                cc.marker = ai1
            elseif ai == "linewidth"
                cc.linewidth = ai1
            elseif ai == "pointsize"
                cc.pointsize = ai1
            elseif ai == "title"
                ac.title = ai1
            elseif ai == "xlabel"
                ac.xlabel = ai1
            elseif ai == "ylabel"
                ac.ylabel = ai1
			elseif ai == "fillstyle"
				ac.fill = ai1
			elseif ai == "grid"
				ac.grid = ai1
            elseif ai == "box"
                ac.box = ai1
            elseif ai == "axis"
                ac.axis = ai1
            elseif ai == "xrange"
                ac.xrange = ai1
            elseif ai == "yrange"
                ac.yrange = ai1
            else
                error("Invalid property specified")
            end
            i = i+2
            state = "S3"
        elseif state == "SEND"
            addconf(ac)
            llplot()
            break
        elseif state == "SERROR"
            error("Invalid arguments")
        else
            error("Unforseen situation, bailing out")
        end
    end
    return h
end

function histogram(args...)
    global gnuplot_state
    # if args[1] is an integer, it's the figure handle.
    if isa(args[1], Int)
        h = args[1]
        args = args[2:end]   # argument parsing starts with 1 (eases debug)
    else
        h = gnuplot_state.current
    end
    h = figure(h,false) # create/select figure
    clearfigure(h)  # remove all figure configuration
    # parse arguments
    state = "SINI"
    la = length(args)
    while(true)
        if state == "SINI"
            i = 1
            bins = 10
            norm = 0
            cc = CurveConf()
            cc.plotstyle = "boxes"
            ac = AxesConf()
            state = "S1"
        elseif state == "S1"
            if i > la
                state = "SERROR"
                continue
            end
            y = args[i]
            i = i+1
            state = "S2"
        elseif state == "S2"
            if i > la
                # validate bins and norm
                if !isa(bins,Int) || !isa(norm,Real) || bins <= 0 || norm < 0
                    state = "SERROR"
                    continue
                end
                x, y = hist(y,bins)
                x = midpoints(x)
                if norm != 0
                    delta = step(x)
                    y = norm*y/(delta*sum(y))
                end
                addcoords(x,y,cc)
                state = "SEND"
                continue
            end
            state = "S3"
        elseif state == "S3"
            if i+1 > la
                state = "SERROR"
                continue
            end
            ai = args[i]; ai1 = args[i+1]
            if ai == "legend"
                cc.legend = ai1
            elseif ai == "color"
                cc.color = ai1
            elseif ai == "linewidth"
                cc.linewidth = ai1
            elseif ai == "bins"
                bins = ai1
            elseif ai == "norm"
                norm = ai1
            elseif ai == "title"
                ac.title = ai1
            elseif ai == "xlabel"
                ac.xlabel = ai1
            elseif ai == "ylabel"
                ac.ylabel = ai1
			elseif ai == "fillstyle"
				ac.fill = ai1
            elseif ai == "box"
                ac.box = ai1
            elseif ai == "xrange"
                ac.xrange = ai1
            elseif ai == "yrange"
                ac.yrange = ai1
            else
                error("Invalid property specified")
            end
            i = i+2
            state = "S2"
        elseif state == "SEND"
            addconf(ac)
            llplot()
            break
        elseif state == "SERROR"
            error("Invalid arguments")
        else
            error("Unforseen situation, bailing out")
        end
    end
    return h
end

# image plots
function imagesc(args...)
    global gnuplot_state
    # if args[1] is an integer, it's the figure handle.
    if isa(args[1], Int)
        h = args[1]
        args = args[2:end]   # argument parsing starts with 1 (eases debug)
    else
        h = gnuplot_state.current
    end
    h = figure(h,false) # create/select figure
    clearfigure(h)  # remove all figure configuration
    # parse arguments
    state = "SINI"
    la = length(args)
    while(true)
        if state == "SINI"
            i = 1
            cc = CurveConf()
            ac = AxesConf()
            state = "S1"
        elseif state == "S1"
            if i > la
                state = "SERROR"
                continue
            end
            tmp = args[i]
            i = i+1
            state = "S2"
        elseif state == "S2"
            if i > la
                Z = tmp
                if isa(Z,Array) && 2 <= ndims(Z) <= 3
                    y = 1:size(Z)[1]
                    x = 1:size(Z)[2]
                    state = "S3"
                else
                    state = "SERROR"
                end
            else
                if isa(args[i],AbstractString)
                    Z = tmp
                    if isa(Z,Array) && 2 <= ndims(Z) <= 3
                        y = 1:size(Z)[1]
                        x = 1:size(Z)[2]
                        state = "S6"
                    else
                        state = "SERROR"
                    end
                else
                    y = tmp
                    tmp = args[i]
                    i = i+1
                    state = "S4"
                end
            end
        elseif state == "S3"
            if ndims(Z) == 2
                cc.plotstyle = "image"
            elseif ndims(Z) == 3
                cc.plotstyle = "rgbimage"
            end
            addcoords(x,y,Z,cc)
            state = "SEND"
        elseif state == "S4"
            if i > la
                Z = tmp
                x = 1:size(Z)[2]
                state = "S3"
            else
                if isa(args[i],AbstractString)
                    Z = tmp
                    x = 1:size(Z)[2]
                    state = "S6"
                else
                    x = tmp
                    tmp = args[i]
                    i = i+1
                    state = "S5"
                end
            end
        elseif state == "S5"
            Z = tmp
            if i > la
                state = "S3"
            else
                state = "S6"
            end
        elseif state == "S6"
            if i+1 > la
                state = "S3"
            else
                ai = args[i]; ai1 = args[i+1]
                if ai == "xlabel"
                    ac.xlabel = ai1
                elseif ai == "ylabel"
                    ac.ylabel = ai1
                elseif ai == "title"
                    ac.title = ai1
                elseif ai == "clim"
                        cmin = ai1[1]
                        cmax = ai1[2]
                        if !isa(cmin,Real) || !isa(cmax,Real)
                            error("Invalid limits specified")
                        else
                            Z -= cmin
                            Z[Z<0] = 0
                            Z *= 255/(cmax-cmin)
                            Z[Z>255] = 255
                        end
                else
                    error("Invalid property specified")
                end
                i = i+2
            end
        elseif state == "SEND"
            addconf(ac)
            llplot()
            break
        elseif state == "SERROR"
            error("Invalid arguments")
        else
            error("Unforseen situation, bailing out")
        end
    end
    return h
end

# surface plots
function surf(args...)
    global gnuplot_state
    # if args[1] is an integer, it's the figure handle.
    if isa(args[1], Int)
        h = args[1]
        args = args[2:end]   # argument parsing starts with 1 (eases debug)
    else
        h = gnuplot_state.current
    end
    h = figure(h,false) # create/select figure
    clearfigure(h)  # remove all figure configuration
    # parse arguments
    state = "SINI"
    la = length(args)
    while(true)
        if state == "SINI"
            i = 1
            cc = CurveConf()
            ac = AxesConf()
            state = "S1"
        elseif state == "S1"
            if i > la
                state = "SERROR"
                continue
            end
            tmp = args[i]
            i = i+1
            state = "S2"
        elseif state == "S2"
            if i > la
                Z = tmp
                if isa(Z,Array) && ndims(Z) == 2
                    y = 1:size(Z)[1]
                    x = 1:size(Z)[2]
                    state = "S3"
                else
                    state = "SERROR"
                end
            else
                if isa(args[i],AbstractString)
                    Z = tmp
                    if isa(Z,Array) && ndims(Z) == 2
                        y = 1:size(Z)[1]
                        x = 1:size(Z)[2]
                        state = "S6"
                    else
                        state = "SERROR"
                    end
                else
                    y = tmp
                    tmp = args[i]
                    i = i+1
                    state = "S4"
                end
            end
        elseif state == "S3"
            if isa(Z,Function)
                Z = meshgrid(x,y,Z)
            end
            addcoords(x,y,Z,cc)
            state = "SEND"
        elseif state == "S4"
            if i > la
                Z = tmp
                if isa(Z,Array) && ndims(Z) == 2
                    x = 1:size(Z)[2]
                    state = "S3"
                else
                    state = "SERROR"
                end
            else
                if isa(args[i],AbstractString)
                    Z = tmp
                    if isa(Z,Array) && ndims(Z) == 2
                        x = 1:size(Z)[2]
                        state = "S6"
                    else
                        state = "SERROR"
                    end
                else
                    x = tmp
                    tmp = args[i]
                    i = i+1
                    state = "S5"
                end
            end
        elseif state == "S5"
            Z = tmp
            if i > la
                state = "S3"
            else
                state = "S6"
            end
        elseif state == "S6"
            if i+1 > la
                state = "S3"
            else
                ai = args[i]; ai1 = args[i+1]
                if ai == "xlabel"
                    ac.xlabel = ai1
                elseif ai == "ylabel"
                    ac.ylabel = ai1
                elseif ai == "zlabel"
                    ac.zlabel = ai1
                elseif ai == "title"
                    ac.title = ai1
                elseif ai == "legend"
                    cc.legend = ai1
                elseif ai == "plotstyle"
                    cc.plotstyle = ai1
                elseif ai == "color"
                    cc.color = ai1
                elseif ai == "marker"
                    cc.marker = ai1
                elseif ai == "linewidth"
                    cc.linewidth = ai1
                elseif ai == "pointsize"
                    cc.pointsize = ai1
                elseif ai == "box"
                    ac.box = ai1
                elseif ai == "xrange"
                    ac.xrange = ai1
                elseif ai == "yrange"
                    ac.yrange = ai1
                elseif ai == "zrange"
                    ac.zrange = ai1
                else
                    error("Invalid property specified")
                end
                i = i+2
            end
        elseif state == "SEND"
            addconf(ac)
            llplot()
            break
        elseif state == "SERROR"
            error("Invalid arguments")
        else
            error("Unforseen situation, bailing out")
        end
    end
    return h
end

# print a figure to a file
function printfigure(args...)
    global gnuplot_state
    global gaston_config

    # if args is empty, print current figure in pdf
    if isempty(args)
        term = "pdf"
        h = gnuplot_state.current
    elseif length(args) == 1
        a = args[1]
        if isa(a, Int)
            # if a is an integer, it's the figure handle.
            h = a
        elseif isa(a, AbstractString)
            # if a is a string, it's the term type
            h = gnuplot_state.current
            term = a
        else
            error("Wrong arguments.")
        end
    elseif length(args) == 2
        a = args[1]
        if isa(a, Int)
            h = a
        else
            error("Wrong arguments.")
        end
        term = args[2]
        if !is_term_file(term)
            error("Wrong arguments.")
        end
    end

    # make sure requested figure exists
    if findfigure(h) == 0
        error("Requested figure does not exist.")
    end

    # save terminal
    saveterm = gaston_config.terminal
    # set temporary terminal and replot
    set_terminal(term)
    figure(h)
    set_terminal(saveterm)
    # gnuplot is weird: this command is needed to close the output file
    gnuplot_send("set output")

    return h
end


text:
using BinaryBuilder

# Collection of sources required to build ZMQ
sources = [
    ArchiveSource("http://fftw.org/~stevenj/fftw-3.3.9.tar.gz",
                  "33554751aae030b8adac2ae29384f5f4a103e02d71955aa45d613b3695eff042"),
]

name = "FFTW"
version = v"3.3.9"

# Bash recipe for building across all platforms
script = raw"""
cd $WORKSPACE/srcdir/fftw-*

# Base configure flags
FLAGS=(
    --prefix="$prefix"
    --host="${target}"
    --enable-shared
    --disable-static
    --disable-fortran
    --disable-mpi
    --disable-doc
    --enable-threads
    --with-combined-threads
)

# On intel processors, enable SSE2 and AVX2
if [[ "${target}" == x86_64-*  ]] || [[ "${target}" == i686-* ]]; then
    FLAGS+=( --enable-sse2 --enable-avx2 )
fi

# On x86_64, enable AVX512, once this is no longer marked "experimental" in the FFTW release notes.
# if [[ "${target}" == x86_64-* ]]; then
#    FLAGS+=( --enable-avx512 );
# fi

# Enable NEON on Aarch64
if [[ "${target}" == aarch64-* ]]; then FLAGS+=( --enable-neon ); fi

# On windows, we use our own malloc
if [[ "${target}" == *-w64-* ]]; then FLAGS+=( --with-our-malloc ); fi
if [[ "${target}" == i686-w64-* ]]; then FLAGS+=( --with-incoming-stack-boundary=2 ); fi

# On ppc64le, enable VSX
if [[ "${target}" == powerpc64le-*  ]]; then FLAGS+=( --enable-vsx ); fi

# We need to do this a couple times, so functionalize it
build_fftw()
{
    mkdir "${WORKSPACE}/srcdir/build_${1}"
    cd "${WORKSPACE}/srcdir/build_${1}"

    ${WORKSPACE}/srcdir/fftw-*/configure "${FLAGS[@]}" $2
    perl -pi -e "s/tools m4/m4/" Makefile # work around FFTW/fftw3#146
    make -j${nproc}
    make install
}

# Build the double-precision version, then the single-precision version
build_fftw double

build_fftw single --enable-single

# Install both COPYING and COPYRIGHT in the license directory
cd ${WORKSPACE}/srcdir/fftw-*
install_license COPYING COPYRIGHT
"""

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms = supported_platforms() # build on all supported platforms

# The products that we will ensure are always built
products = [
    LibraryProduct("libfftw3", :libfftw3),
    LibraryProduct("libfftw3f", :libfftw3f),
]

# Dependencies that must be installed before this package can be built
dependencies = [
]

# Build the tarballs, and possibly a `build.jl` as well.
build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies; preferred_gcc_version=v"8")

ext: jl


text:
export evaluate, random_evaluate, fitness_evaluate

"""
    evaluate(e::AbstractEvolution)

Default evaluate function. Sets each element of the fitness array of each
individual to -Inf.
"""
function evaluate(e::AbstractEvolution)
    for i in eachindex(e.population)
        for d in 1:e.config.d_fitness
            e.population[i].fitness[d] = -Inf
        end
    end
end

"sets the fitness value of each individual to rand()"
function random_evaluate(e::AbstractEvolution)
    for i in eachindex(e.population)
        for d in 1:e.config.d_fitness
            e.population[i].fitness[d] = rand()
        end
    end
end

function null_evaluate(i::Individual)
    i.fitness[:] .= -Inf
end

"""
    function fitness_evaluate(e::AbstractEvolution; fitness::Function=null_evaluate)

sets the fitness of each individual to the Array of values returned by fitness
"""
function fitness_evaluate(e::AbstractEvolution, fitness::Function=null_evaluate)
    for i in eachindex(e.population)
        e.population[i].fitness[:] = fitness(e.population[i])[:]
    end
end

# TODO: dependencies, test distributed
# function distributed_evaluate!(e::AbstractEvolution; fitness::Function=null_evaluate)
#     fits = SharedArrays.SharedArray{Float64}(e.config["d_fitness"],
#                                              length(e.population))
#     @sync @distributed for i in eachindex(e.population)
#         fits[:, i] = fitness(e.population[i])
#     end
#     for i in eachindex(e.population)
#         e.population[i].fitness .= fits[:, i]
#     end
# end


text:
const ∞ = 20070128.0

const Missable{T} = Union{Missing, T}
const Nullable{T} = Union{Nothing, T}
_parse(val, ::Type{Nullable{T}}; kwargs...) where T = _parse(val, T; kwargs...)
_parse(val, ::Type{Missable{T}}; kwargs...) where T = _parse(val, T; kwargs...)

"""
A simple singleton struct to represent something existing/true.
"""
struct Yes end
_parse(::Any, ::Type{Yes}; kwargs...) = Yes()
_serialize_convert(::Yes) = true

±(center, half) = center - half : center + half

function _make_nullable(expr, T, default)
    @assert expr.head ≡ :struct
    fields = expr.args[3].args
    for i in 1:length(fields)
        field = fields[i]
        field isa Expr || continue
        if field.head ≡ :(::)
            field.args[2] = :($T{$(field.args[2])})
            fields[i] = :($field = $default)
        elseif field.head ≡ :(=)
            arg1 = field.args[1]
            if arg1 isa Expr && arg1.head ≡ :(::)
                arg1.args[2] = arg1.args[2]
            end
            field.args[2] = field.args[2]
        end
    end
    esc(quote
        Base.@kwdef $expr
    end)
end

"""
    @missable mutable struct SomeStruct
        fields...
    end

Make all fields that do not have a default value missable/optional.
"""
macro missable(expr)
    _make_nullable(expr, Missable, missing)
end

macro nullable(expr)
    _make_nullable(expr, Nullable, nothing)
end

abstract type SimpleTypeWrapper{T} end
macro type_wrapper(name, T, default = :nothing, base_type = :SimpleTypeWrapper)
    struct_name = name
    name = esc(name)
    T = esc(T)
    default_constructor = if default ≢ :nothing
        :($name() = $name($default))
    end
    if base_type ≢ :SimpleTypeWrapper
        base_type = esc(base_type)
    end
    quote
        struct $struct_name <: $base_type{$T}
            value::$T
        end
        $default_constructor
        Base.convert(::Type{$name}, x::$name) = x
        Base.convert(::Type{$name}, x) = $name(convert($T, x))
        Base.convert(::Type{$T}, x::$name) = x.value
        Base.print(io::IO, x::$name) = print(io, x.value)
        Base.show(io::IO, x::$name) = show(io, x.value)
        Base.getindex(x::$name) = x.value
        Base.:(==)(x::$name, y::$name) = x.value == y.value
        Base.:(==)(x::$name, y::$T) = x.value == y
        Base.:(==)(x::$T, y::$name) = x == y.value
        Base.isless(x::$name, y::$name) = isless(x.value, y.value)
        @forward $name.value Base.getindex, Base.setindex!
    end
end
_parse(val, ::Type{TS}; kwargs...) where {T, TS <: SimpleTypeWrapper{T}} =
    TS(_parse(val, T; kwargs...))
_serialize_convert(x::SimpleTypeWrapper) = x.value


text:
@testset "traverse!" begin
    mtg = read_mtg("files/simple_plant.mtg", Dict);
    # Add a new attributes, x based on node field, y based on x and z using a function:
    traverse!(mtg, x -> x[:x] = length(x.name))
    @test mtg[:x] ==  6

    traverse!(mtg) do x
        x[:y] = x[:x] + 2
    end
    @test mtg[:y] ==  mtg[:x] + 2
end

@testset "traverse" begin
    mtg = read_mtg("files/simple_plant.mtg", Dict);
    # Add a new attributes, x based on node field, y based on x and z using a function:
    name_length = traverse(mtg, x -> length(x.name))
    @test name_length == repeat([6], length(mtg))

    name_length_do = traverse(mtg) do x
        length(x.name) + 2
    end

    @test name_length_do == repeat([8], length(mtg))
end


text:
using TidalFluxQuantities, TidalSedimentFluxes, TidalFluxCalibrations, Base.Dates
using Base.Test

obs1 = OBS3("T8271",[0.0741962;0.0456691;1.40e-6],250,[-0.1695174;0.1828727;2.30e-5],1000)

ts = collect(now():Minute(10):(999*Minute(10)+now()))

N = length(ts)

r = rand(1:1250,N)
a1 = AnalogLow(ts,4*r)
a2 = AnalogHigh(ts,r)

T1 = Turbidity(a1,obs1)
T2 = Turbidity(a2,obs1)

tsc = ts[1:10:N]
qc = quantity(T2)[1:10:N]
M = length(tsc)

tss1 = TSS(tsc,2*qc+1+randn(M))

c = Calibration(tss1,T2)
m = fit(PolynomialCalibrationModel,c,1)
tss2 = TSS(T1,m)


text:
using ArgParse
s = ArgParseSettings()
@add_arg_table s begin
    "--part2"
    help = "Do part 2"
    action = :store_true
    "--test"
    help = "Run test data"
    action = :store_true
end
parsed_args = parse_args(ARGS, s)

test_suffix = parsed_args["test"] ? "_test" : ""

input = readlines("input/day_14$test_suffix.txt")
template = input[1]

function addcount!(d, k, n)
    c = get(d, k, 0)
    d[k] = c + n
end

paircounts = Dict{String,UInt128}()
for place = 1:length(template)-1
    pair = template[place:place+1]
    addcount!(paircounts, pair, 1)
end

rules = Dict{String,Tuple{String,String}}()
for l in input[3:end]
    r = split(l, " -> ")
    rules[r[1]] = (String([r[1][1], r[2][1]]), String([r[2][1], r[1][2]]))
end

function process(counts)
    newcounts = Dict{String,UInt128}()
    for (k, v) in counts
        product = rules[k]
        addcount!(newcounts, product[1], v)
        addcount!(newcounts, product[2], v)
    end
    newcounts
end

function doit(n)
    counts = paircounts
    for _ = 1:n
        counts = process(counts)
    end
    lettercounts = Dict{Char,UInt128}([template[end] => 1,])
    for (k, v) in counts
        addcount!(lettercounts, k[1], v)
    end

    mn = typemax(UInt128)
    mx = 0
    for v in values(lettercounts)
        mn = min(mn, v)
        mx = max(mx, v)
    end
    return mx - mn
end

function part1()
    doit(10)
end

function part2()
    doit(40)
end

p = parsed_args["part2"] ? part2 : part1
answer = p()
println("The answer is: $answer")


text:
module TwodWrapper

using JavaCall

const AbstractRegion = @jimport org.hipparchus.geometry.partitioning.AbstractRegion
const AbstractSubHyperplane = @jimport org.hipparchus.geometry.partitioning.AbstractSubHyperplane
const Arc = @jimport org.hipparchus.geometry.spherical.oned.Arc
const BSPTree = @jimport org.hipparchus.geometry.partitioning.BSPTree
const BSPTreeVisitor_Order = @jimport org.hipparchus.geometry.partitioning.BSPTreeVisitor$Order
const BoundaryProjection = @jimport org.hipparchus.geometry.partitioning.BoundaryProjection
const Circle = @jimport org.hipparchus.geometry.spherical.twod.Circle
const Class = @jimport java.lang.Class
const Collection = @jimport java.util.Collection
const Edge = @jimport org.hipparchus.geometry.spherical.twod.Edge
const EdgeWithNodeInfo = @jimport org.hipparchus.geometry.spherical.twod.EdgeWithNodeInfo
const EdgesWithNodeInfoBuilder = @jimport org.hipparchus.geometry.spherical.twod.EdgesWithNodeInfoBuilder
const EnclosingBall = @jimport org.hipparchus.geometry.enclosing.EnclosingBall
const Hyperplane = @jimport org.hipparchus.geometry.partitioning.Hyperplane
const JString = @jimport java.lang.String
const JVector = @jimport org.hipparchus.geometry.Vector
const List = @jimport java.util.List
const Object = @jimport java.lang.Object
const Point = @jimport org.hipparchus.geometry.Point
const PropertiesComputer = @jimport org.hipparchus.geometry.spherical.twod.PropertiesComputer
const Region = @jimport org.hipparchus.geometry.partitioning.Region
const Region_Location = @jimport org.hipparchus.geometry.partitioning.Region$Location
const Rotation = @jimport org.hipparchus.geometry.euclidean.threed.Rotation
const S1Point = @jimport org.hipparchus.geometry.spherical.oned.S1Point
const S2Point = @jimport org.hipparchus.geometry.spherical.twod.S2Point
const Space = @jimport org.hipparchus.geometry.Space
const Sphere1D = @jimport org.hipparchus.geometry.spherical.oned.Sphere1D
const Sphere2D = @jimport org.hipparchus.geometry.spherical.twod.Sphere2D
const SphericalPolygonsSet = @jimport org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet
const SubCircle = @jimport org.hipparchus.geometry.spherical.twod.SubCircle
const SubHyperplane = @jimport org.hipparchus.geometry.partitioning.SubHyperplane
const SubHyperplane_SplitSubHyperplane = @jimport org.hipparchus.geometry.partitioning.SubHyperplane$SplitSubHyperplane
const Transform = @jimport org.hipparchus.geometry.partitioning.Transform
const Vector3D = @jimport org.hipparchus.geometry.euclidean.threed.Vector3D
const Vertex = @jimport org.hipparchus.geometry.spherical.twod.Vertex

export Circle
export Edge
export EdgeWithNodeInfo
export EdgesWithNodeInfoBuilder
export PropertiesComputer
export S2Point
export Sphere2D
export SphericalPolygonsSet
export SubCircle
export Vertex
export apply_transform
export are_natural_followers
export build_new
export check_point
export check_tolerance
export contains
export copy_self
export distance
export empty_hyperplane
export equals
export get_arc
export get_area
export get_barycenter
export get_boundary_loops
export get_boundary_size
export get_circle
export get_class
export get_convex_cells_inside_points
export get_dimension
export get_edges
export get_enclosing_cap
export get_end
export get_hyperplane
export get_incoming
export get_inside_arc
export get_instance
export get_length
export get_location
export get_offset
export get_outgoing
export get_phase
export get_phi
export get_point_at
export get_pole
export get_remaining_region
export get_reverse
export get_size
export get_space
export get_start
export get_sub_space
export get_theta
export get_tolerance
export get_transform
export get_tree
export get_vector
export get_x_axis
export get_y_axis
export hash_code
export intersection
export is_empty
export is_full
export is_na_n
export is_processed
export negate
export notify
export notify_all
export project
export project_to_boundary
export reset
export result_from_a_split
export reunite
export revert_self
export same_orientation_as
export set_processed
export split
export to_space
export to_string
export to_sub_space
export visit_internal_node
export visit_leaf_node
export visit_order
export wait
export whole_hyperplane
export whole_space

include("circle.jl")
include("edge.jl")
include("edge_with_node_info.jl")
include("edges_with_node_info_builder.jl")
include("properties_computer.jl")
include("s2_point.jl")
include("sphere2_d.jl")
include("spherical_polygons_set.jl")
include("sub_circle.jl")
include("vertex.jl")

end


text:
import MLBase
import ROCAnalysis
import StatsBase

function _aurocc_trapz(
        ytrue::AbstractVector{<:Integer},
        yscore::AbstractVector{<:Real},
        )
    allfpr, alltpr, allthresholds = roccurve(
        ytrue,
        yscore,
        )
    #
    permutation = sortperm(allthresholds; rev=true)
    allfpr = allfpr[permutation]
    alltpr = alltpr[permutation]
    allthresholds = allthresholds[permutation]
    #
    x = allfpr
    y = alltpr
    aurocc_trapz_result = trapz(x, y)
    return aurocc_trapz_result
end

function _aurocc_verify(
        ytrue::AbstractVector{<:Integer},
        yscore::AbstractVector{<:Real},
        )
    targetlevel = 1
    nontargetlevel = 0
    targetscores = yscore[ytrue .== targetlevel]
    nontargetscores = yscore[ytrue .== nontargetlevel]
    r = ROCAnalysis.roc(targetscores, nontargetscores)
    complement_of_aurocc = ROCAnalysis.auc(r)
    aurocc_verify_result = 1 - complement_of_aurocc
    return aurocc_verify_result
end

"""
"""
function aurocc(
        ytrue::AbstractVector{<:Integer},
        yscore::AbstractVector{<:Real},
        )
    aurocc_trapz_value = _aurocc_trapz(
        ytrue,
        yscore,
        )
    aurocc_verify_value = _aurocc_verify(
        ytrue,
        yscore,
        )
    if !( isapprox(aurocc_trapz_value, aurocc_verify_value; atol=0.00000001) )
        error("Was not able to accurately compute the AUROCC.")
    end
    return aurocc_trapz_value
end


text:
module Day11
export power_level, part_1, part_2

function power_level(x::Int, y::Int, serial::Int)
    rack_id = x + 10
    power = rack_id * (rack_id * y + serial)
    power = div(power, 100) % 10
    return power - 5
end

function part_1(serial::Int)::Tuple{Int, Int, Int}
    power_grid = [power_level(x, y, serial) for x in 1:300, y in 1:300]

    max_power = 0
    best_x = -1
    best_y = -1
    for x in 1:298
        for y in 1:298
            power = 0
            for dx in 0:2
                for dy in 0:2
                    power += power_grid[x + dx, y + dy]
                end
            end
            if power > max_power
                best_x = x
                best_y = y
                max_power = power
            end
        end
    end

    return best_x, best_y, max_power
end

function part_2(serial::Int)::Tuple{Int, Int, Int, Int}
    power_grid = [power_level(x, y, serial) for x in 1:300, y in 1:300]

    max_power = 0
    best_x = -1
    best_y = -1
    best_n = -1
    for n in 1:300
        for x in 1:(300 - n - 1)
            for y in 1:(300 - n - 1)
                power = 0
                for dx in 0:(n - 1)
                    for dy in 0:(n - 1)
                        power += power_grid[x + dx, y + dy]
                    end
                end
                if power > max_power
                    best_x = x
                    best_y = y
                    best_n = n
                    max_power = power
                end
            end
        end
    end

    return best_x, best_y, best_n, max_power
end

end


text:
using ReachabilityAnalysis, SparseArrays

LazySets.set_ztol(Float64, 1e-14)

x  = 1  # x position (negative!)
y  = 2  # y position (negative!)
vx = 3  # x velocity
vy = 4  # y velocity
t  = 5  # time

# number of variables
n = 4 + 1;

function spacecraft(; abort_time::Union{Float64, Vector{Float64}}=-1.)
    # variables
    x  = 1  # x position (negative!)
    y  = 2  # y position (negative!)
    vx = 3  # x velocity
    vy = 4  # y velocity
    t  = 5  # time

    # number of variables
    n = 4 + 1

    # flag for activating the "rendezvous abort" scenario
    aborting = true
    if abort_time isa Number
        if abort_time < 0.
            aborting = false
        else
            t_abort_lower = abort_time
            t_abort_upper = abort_time
        end
    else
        @assert length(abort_time) == 2 "abort time must be a point or an interval"
        t_abort_lower = abort_time[1]
        t_abort_upper = abort_time[2]
    end

    # discrete structure (graph)
    automaton = LightAutomaton(aborting ? 3 : 2)

    # common vector of affine dynamics
    b = sparsevec([t], [1.], n)

    # mode 1 ("approaching")
    A = spzeros(n, n)
    A[x, vx] = 1.
    A[y, vy] = 1.
    A[vx, x] = -0.057599765881773
    A[vx, y] = 0.000200959896519766
    A[vx, vx] = -2.89995083970656
    A[vx, vy] = 0.00877200894463775
    A[vy, x] = -0.000174031357370456
    A[vy, y] = -0.0665123984901026
    A[vy, vx] = -0.00875351105536225
    A[vy, vy] = -2.90300269286856
    invariant = HalfSpace(sparsevec([x], [1.], n), -100.)  # x <= -100
    if aborting
        invariant = HPolyhedron([
            invariant,
            HalfSpace(sparsevec([t], [1.], n), t_abort_upper)  # t <= t_abort_upper
           ])
    end
    m_1 = @system(x' = Ax + b, x ∈ invariant)

    # mode 2 ("rendezvous attempt")
    A = spzeros(n, n)
    A[x, vx] = 1.
    A[y, vy] = 1.
    A[vx, x] = -0.575999943070835
    A[vx, y] = 0.000262486079431672
    A[vx, vx] = -19.2299795908647
    A[vx, vy] = 0.00876275931760007
    A[vy, x] = -0.000262486080737868
    A[vy, y] = -0.575999940191886
    A[vy, vx] = -0.00876276068239993
    A[vy, vy] = -19.2299765959399
    invariant = HPolyhedron([
        HalfSpace(sparsevec([x], [-1.], n), 100.),           # x >= -100
        HalfSpace(sparsevec([x], [1.], n), 100.),            # x <= 100
        HalfSpace(sparsevec([y], [-1.], n), 100.),           # y >= -100
        HalfSpace(sparsevec([y], [1.], n), 100.),            # y <= 100
        HalfSpace(sparsevec([x, y], [-1., -1.], n), 141.1),  # x + y >= -141.1
        HalfSpace(sparsevec([x, y], [1., 1.], n), 141.1),    # x + y <= 141.1
        HalfSpace(sparsevec([x, y], [1., -1.], n), 141.1),   # -x + y >= -141.1
        HalfSpace(sparsevec([x, y], [-1., 1.], n), 141.1)    # -x + y <= 141.1
       ])
    if aborting
        addconstraint!(invariant, HalfSpace(sparsevec([t], [1.], n), t_abort_upper))  # t <= t_abort_upper
    end

    m_2 = @system(x' = Ax + b, x ∈ invariant)

    # mode 3 ("aborting")
    A = spzeros(n, n)
    A[x, vx] = 1.
    A[y, vy] = 1.
    A[vx, x] = 0.0000575894721132
    A[vx, vy] = 0.00876276
    A[vy, vx] = -0.00876276
    invariant = Universe(n)

    m_3 = @system(x' = Ax + b, x ∈ invariant)

    # modes
    modes = aborting ? [m_1, m_2, m_3] : [m_1, m_2]

    # transition 1 -> 2
    add_transition!(automaton, 1, 2, 1)
    guard = HPolyhedron([
        HalfSpace(sparsevec([x], [-1.], n), 100.),           # x >= -100
        HalfSpace(sparsevec([x], [1.], n), 100.),            # x <= 100
        HalfSpace(sparsevec([y], [-1.], n), 100.),           # y >= -100
        HalfSpace(sparsevec([y], [1.], n), 100.),            # y <= 100
        HalfSpace(sparsevec([x, y], [-1., -1.], n), 141.1),  # x + y >= -141.1
        HalfSpace(sparsevec([x, y], [1., 1.], n), 141.1),    # x + y <= 141.1
        HalfSpace(sparsevec([x, y], [1., -1.], n), 141.1),   # -x + y >= -141.1
        HalfSpace(sparsevec([x, y], [-1., 1.], n), 141.1)    # -x + y <= 141.1
       ])
    t1 = ConstrainedIdentityMap(n, guard)

    if aborting
        add_transition!(automaton, 1, 3, 2)
        guard = HalfSpace(sparsevec([t], [-1.], n), -t_abort_lower)  # t >= t_abort_lower
        t2 = ConstrainedIdentityMap(n, guard)

        add_transition!(automaton, 2, 3, 3)
        guard = HalfSpace(sparsevec([t], [-1.], n), -t_abort_lower)  # t >= t_abort_lower
        t3 = ConstrainedIdentityMap(n, guard)
    end

    # transition annotations
    resetmaps = aborting ? [t1, t2, t3] : [t1]

    H = HybridSystem(automaton, modes, resetmaps, [AutonomousSwitching()])

    # initial condition in mode 1
    X0 = Hyperrectangle([-900., -400., 0., 0., 0.],
                        [25., 25., 0., 0., 0.])
    initial_condition = [(1, X0)]

    return IVP(H, initial_condition)
end

# safety property in "Mode 2"
const velocity = 0.055 * 60.  # meters per minute
const cx = velocity * cos(π / 8)  # x-coordinate of the octagon's first (ENE) corner
const cy = velocity * sin(π / 8)  # y-coordinate of the octagon's first (ENE) corner
const octagon = [
    HalfSpace(sparsevec([vx], [-1.], n), cx),                # vx >= -cx
    HalfSpace(sparsevec([vx], [1.], n), cx),                 # vx <= cx
    HalfSpace(sparsevec([vy], [-1.], n), cx),                # vy >= -cx
    HalfSpace(sparsevec([vy], [1.], n), cx),                 # vy <= cx
    HalfSpace(sparsevec([vx, vy], [1., 1.], n), cy + cx),    # vx + vy <= cy + cx
    HalfSpace(sparsevec([vx, vy], [1., -1.], n), cy + cx),   # vx - vy <= cy + cx
    HalfSpace(sparsevec([vx, vy], [-1., 1.], n), cy + cx),   # -vx + vy <= cy + cx
    HalfSpace(sparsevec([vx, vy], [-1., -1.], n), cy + cx)   # -vx - vy <= cy + cx
   ]
const tan30 = tan(π/6)
const cone = [
    HalfSpace(sparsevec([x], [-1.], n), 100.),          # x >= -100
    HalfSpace(sparsevec([x, y], [tan30, -1.], n), 0.),  # -x tan(30°) + y >= 0
    HalfSpace(sparsevec([x, y], [tan30, 1.], n), 0.),   # -x tan(30°) - y >= 0
   ];

# safety property in "aborting"
const target = BallInf(zeros(2), 0.2);

function line_of_sight(sol)
    all_idx = findall(x -> x == 2, location.(sol))  # attempt
    for idx in all_idx
        verif = all(set(R) ⊆ HPolyhedron(cone) for R in sol[idx])
        !verif && return false
    end
    return true
end

function velocity_constraint(sol)
    all_idx = findall(x -> x == 2, location.(sol)) # attempt
    for idx in all_idx
        verif = all(set(R) ⊆ HPolyhedron(octagon) for R in sol[idx])
        !verif && return false
    end
    return true
end

function target_avoidance(sol)
   all_idx = findall(x -> x == 3, location.(sol)) # aborting
   for idx in all_idx

       #Lazy:
       # verif = all(is_intersection_empty(set(Projection(R, [x, y])), target) for R in sol[idx])

       #Concrete if R is hyperrectangular
       verif = all(is_intersection_empty(overapproximate(Projection(R, [x, y]), Hyperrectangle), target) for R in sol[idx])
       !verif && return false
   end
   return true
end

function SR02_specification(sol)
    return line_of_sight(sol) && velocity_constraint(sol) && target_avoidance(sol)
end


text:
using Base.BinaryPlatforms
const AnyRedirectable = Union{Base.AbstractCmd, Base.TTY, <:IO}

"""
    SandboxConfig(read_only_maps, read_write_maps, env)

Sandbox executors require a configuration to set up the environment properly.

- `read_only_maps`: Directories that are mapped into the sandbox as read-only mappings.
   - Specified as pairs, e.g. `sandbox_path => host_path`.  All paths must be absolute.
   - Must always include a mapping for root, e.g. `"/" => rootfs_path`.

- `read_write_maps`: Directories that are mapped into the sandbox as read-write mappings.
   - Specified as pairs, e.g. `sandbox_path => host_path`.  All paths must be absolute.
   - Note that some executors may not show perfect live updates; consistency is guaranteed
     only after execution is finished.

- `env`: Dictionary mapping of environment variables that should be set within the sandbox.

- `entrypoint`: Executable that gets passed the actual command being run.
  - This is a path within the sandbox, and must be absolute.
  - Defaults to `nothing`, which causes the command to be executed directly.

- `pwd`: Set the working directory of the command that will be run.
  - This is a path within the sandbox, and must be absolute.

- `persist`: Tell the executor object to persist changes made to the rootfs.
  - This is a boolean value, it is up to interpretation by the executor.
  - Persistence is a property of an individual executor and changes live only as long
    as the executor object itself.
  - You cannot transfer persistent changes from one executor to another.

- `multiarch`: Request multiarch executable support
  - This is an array of `Platform` objects
  - Sandbox will ensure that interpreters (such as `qemu-*-static` binaries) are
    available for each platform.
  - Requesting multiarch support for a platform that we don't support results in
    an `ArgumentError`.

- `uid` and `gid`: Numeric user and group identifiers to spawn the sandboxed process as.
  - By default, these are both `0`, signifying `root` inside the sandbox.

- `stdin`, `stdout`, `stderr`: input/output streams for the sandboxed process.
  - Can be any kind of `IO`, `TTY`, `devnull`, etc...

- `verbose`: Set whether the sandbox construction process should be more or less verbose.
"""
struct SandboxConfig
    read_only_maps::Dict{String,String}
    read_write_maps::Dict{String,String}
    env::Dict{String,String}
    entrypoint::Union{String,Nothing}
    pwd::String
    persist::Bool
    multiarch_formats::Vector{BinFmtRegistration}
    uid::Cint
    gid::Cint
    tmpfs_size::Union{String, Nothing}

    stdin::AnyRedirectable
    stdout::AnyRedirectable
    stderr::AnyRedirectable
    verbose::Bool

    function SandboxConfig(read_only_maps::Dict{String,String},
                           read_write_maps::Dict{String,String} = Dict{String,String}(),
                           env::Dict{String,String} = Dict{String,String}();
                           entrypoint::Union{String,Nothing} = nothing,
                           pwd::String = "/",
                           persist::Bool = false,
                           multiarch::Vector{<:Platform} = Platform[],
                           uid::Integer=0,
                           gid::Integer=0,
                           tmpfs_size::Union{String, Nothing}=nothing,
                           stdin::AnyRedirectable = Base.devnull,
                           stdout::AnyRedirectable = Base.stdout,
                           stderr::AnyRedirectable = Base.stderr,
                           verbose::Bool = false)
        # Lint the maps to ensure that all are absolute paths:
        for path in [keys(read_only_maps)..., values(read_only_maps)...,
                     keys(read_write_maps)..., values(read_write_maps)...,
                     something(entrypoint, "/"), pwd]
            if !startswith(path, "/")
                throw(ArgumentError("Path mapping $(path) is not absolute!"))
            end
        end

        # Don't touch anything that is encrypted; it doesn't play well with user namespaces or docker
        for path in [values(read_only_maps)...; values(read_write_maps)...]
            crypt, mountpoint = is_ecryptfs(path; verbose)
            if crypt
                throw(ArgumentError("Path $(path) is mounted on the ecryptfs filesystem $(mountpoint)!"))
            end
        end

        # Ensure that read_only_maps contains a mapping for the root in the guest:
        if !haskey(read_only_maps, "/")
            throw(ArgumentError("Must provide a read-only root mapping!"))
        end

        # Collect all multiarch platforms, mapping to the known interpreter for that platform.
        multiarch_formats = Set{BinFmtRegistration}()
        interp_platforms = collect(keys(platform_qemu_registrations))
        for platform in multiarch
            # If this platform is natively runnable, skip it
            if natively_runnable(platform)
                continue
            end

            platform_idx = findfirst(p -> platforms_match(platform, p), interp_platforms)
            if platform_idx === nothing
                throw(ArgumentError("Platform $(triplet(platform)) unsupported for multiarch!"))
            end
            push!(multiarch_formats, platform_qemu_registrations[interp_platforms[platform_idx]])
        end

        return new(read_only_maps, read_write_maps, env, entrypoint, pwd, persist, collect(multiarch_formats), Cint(uid), Cint(gid), tmpfs_size, stdin, stdout, stderr, verbose)
    end
end


text:
## Functions that depend on the structure of BandedMatrix

function pad!(A::BandedMatrix,n,m)
    A.data=pad(A.data,size(A.data,1),m)
    A.m=n
    A
end

# linear algebra

## Constructors that involve MultivariateFun

function Fun(f::Function,d::BivariateSpace)
    if f==zero
        zeros(d)
    elseif hasnumargs(f,2)
        Fun(ProductFun(f,d))
    else
        Fun(ProductFun((x,y)->f((x,y)),d))
    end
end
function Fun(f::Function,d::BivariateSpace,n::Integer)
    if hasnumargs(f,2)
        defaultFun(x->f(x...),d,n)
    else
        defaultFun(f,d,n)
    end
end

function Fun(f::Function)
    if hasnumargs(f,1)
        # check for tuple
        try
            f(0)
        catch ex
            if isa(ex,BoundsError)
                # assume its a tuple
                return Fun(f,Interval()^2)
            else
                throw(ex)
            end
        end

        Fun(f,Interval())
    elseif hasnumargs(f,2)
            Fun(f,Interval()^2)
    else
        error("Function not defined on interval or square")
    end
end

## These hacks support PDEs with block matrices

## dot for vector{Number} * Vector{Fun}

function Base.dot{T<:Union{Number,Fun,MultivariateFun},F<:Union{Fun,MultivariateFun}}(c::Vector{T},f::Vector{F})
    @assert length(c)==length(f)
    ret=conj(first(c))*first(f)
    for k=2:length(c)
        ret+=conj(c[k])*f[k]
    end
    ret
end

# for TYP in (:Real,:Number)
#     @eval begin
#         function dotu{T<:$TYP,F<:Union{Fun,MultivariateFun}}(c::Vector{T},f::Vector{F})
#             @assert length(c)==length(f)
#             ret=first(c)*first(f)
#             for k=2:length(c)
#                 ret+=c[k]*f[k]
#             end
#             ret
#         end
#     end
# end

function dotu{T<:Union{Fun,MultivariateFun,Number},F<:Union{Fun,MultivariateFun,Number}}(c::Vector{T},f::Vector{F})
    @assert length(c)==length(f)
    ret=first(c)*first(f)
    for k=2:length(c)
        ret+=c[k]*f[k]
    end
    ret
end


text:
module Clouds

using ..Ahorn, Maple

const placements = Ahorn.PlacementDict(
    "Cloud (Normal)" => Ahorn.EntityPlacement(
        Maple.Cloud,
        "point",
        Dict{String, Any}(
            "fragile" => false,
            "small" => false
        )
    ),
    "Cloud (Fragile)" => Ahorn.EntityPlacement(
        Maple.Cloud,
        "point",
        Dict{String, Any}(
            "fragile" => true,
            "small" => false
        )
    ),
)

normalScale = 1.0
smallScale = 29 / 35

function cloudSprite(entity::Maple.Cloud)
    fragile = get(entity.data, "fragile", false)

    return fragile ? "objects/clouds/fragile00.png" : "objects/clouds/cloud00.png"
end

function cloudScale(entity::Maple.Cloud)
    small = get(entity.data, "small", false)

    return small ? smallScale : normalScale
end

function Ahorn.selection(entity::Maple.Cloud)
    x, y = Ahorn.position(entity)

    sprite = cloudSprite(entity)
    scaleX = cloudScale(entity)

    return Ahorn.getSpriteRectangle(sprite, x, y, sx=scaleX)
end

function Ahorn.render(ctx::Ahorn.Cairo.CairoContext, entity::Maple.Cloud, room::Maple.Room)
    sprite = cloudSprite(entity)
    scaleX = cloudScale(entity)

    Ahorn.drawSprite(ctx, sprite, 0, 0, sx=scaleX)
end

end


text:
@inline function formatinfo(s::Spec, x::Integer)
    if s.type == 'c'
        char = Char(x)
        size = ncodeunits(char)
        isspecified(s.width) || return size, (0, 1)
        return paddingsize(s, 1) + size, (0, 1)
    end

    base = s.type == 'X' || s.type == 'x' ? 16 : s.type == 'o' ? 8 : s.type == 'B' || s.type == 'b' ? 2 : 10

    # sign and prefix width
    l = 0
    l += x < 0 || s.sign == SIGN_PLUS || s.sign == SIGN_SPACE
    l += (s.altform && base != 10) * 2

    # number of digits (including grouping separators)
    m = base == 10 ? ndigits_decimal(x) : ndigits(x; base)
    if isspecified(s.grouping)
        k = base == 10 ? 3 : 4
        if isspecified(s.width) && s.zero
            m += number_of_leading_zeros(m, k, s.width - l)
        end
        m += div(m - 1, k)
    elseif isspecified(s.width) && s.zero
        m = max(s.width - l, m)
    end

    width = l + m
    return width + paddingsize(s, width), (m, width)
end

@inline function formatfield(data::Vector{UInt8}, p::Int, s::Spec, x::Integer, (m, width)::Tuple{Int, Int})
    base = s.type == 'X' || s.type == 'x' ? 16 : s.type == 'o' ? 8 : s.type == 'B' || s.type == 'b' ? 2 : 10
    align = default(s.align, ALIGN_RIGHT)
    pw = paddingwidth(s, width)
    if !s.zero
        p = padleft(data, p, s.fill, align, pw)
    end
    p, _ = sign(data, p, x, s.sign)
    if s.altform && base ≠ 10
        data[p] = Z
        data[p+1] = UInt8(s.type)
        p += 2
    end
    if s.type == 'c'
        p = pad(data, p, Char(x), 1)
    else
        u = magnitude(x)
        if !isspecified(s.grouping)
            p = base ==  2 ? binary(data, p, u, m) :
                base ==  8 ? octal(data, p, u, m) :
                base == 10 ? decimal(data, p, u, m) :
                hexadecimal(data, p, u, m, s.type == 'X')
        else
            p = base ==  2 ? binary_grouping(data, p, u, m) :
                base ==  8 ? octal_grouping(data, p, u, m) :
                base == 10 ? decimal_grouping(data, p, u, m, s.grouping == GROUPING_COMMA ? UInt8(',') : UInt8('_')) :
                hexadecimal_grouping(data, p, u, m, s.type == 'X')
        end
    end
    if !s.zero
        p = padright(data, p, s.fill, align, pw)
    end
    return p
end

magnitude(x::Unsigned) = x
magnitude(x::Union{Int8, Int16, Int32, Int64, Int128}) = unsigned(abs(x))
magnitude(x::Bool) = UInt(x)
magnitude(x::BigInt) = abs(x)

function binary(data::Vector{UInt8}, p::Int, x::Integer, m::Int)
    n = m
    while n > 0
        r = (x & 0x1) % UInt8
        data[p+n-1] = r + Z
        x >>= 1
        n -= 1
    end
    return p + m
end

function binary_grouping(data::Vector{UInt8}, p::Int, x::Integer, m::Int)
    n = m
    while n ≥ 5
        r1 = (x & 0x1) % UInt8; x >>= 1
        r2 = (x & 0x1) % UInt8; x >>= 1
        r3 = (x & 0x1) % UInt8; x >>= 1
        r4 = (x & 0x1) % UInt8; x >>= 1
        data[p+n-1] = r1 + Z
        data[p+n-2] = r2 + Z
        data[p+n-3] = r3 + Z
        data[p+n-4] = r4 + Z
        data[p+n-5] = UInt8('_')
        n -= 5
    end
    binary(data, p, x, n)
    return p + m
end

function octal(data::Vector{UInt8}, p::Int, x::Integer, m::Int)
    n = m
    while n > 0
        r = (x & 0x7) % UInt8
        data[p+n-1] = r + Z
        x >>= 3
        n -= 1
    end
    return p + m
end

function octal_grouping(data::Vector{UInt8}, p::Int, x::Integer, m::Int)
    n = m
    while n ≥ 5
        r1 = (x & 0x7) % UInt8; x >>= 3
        r2 = (x & 0x7) % UInt8; x >>= 3
        r3 = (x & 0x7) % UInt8; x >>= 3
        r4 = (x & 0x7) % UInt8; x >>= 3
        data[p+n-1] = r1 + Z
        data[p+n-2] = r2 + Z
        data[p+n-3] = r3 + Z
        data[p+n-4] = r4 + Z
        data[p+n-5] = UInt8('_')
        n -= 5
    end
    octal(data, p, x, n)
    return p + m
end

const DECIMAL_DIGITS = [let (d, r) = divrem(x, 10); ((d + Z) << 8) % UInt16 + (r + Z) % UInt8; end for x in 0:99]

function decimal(data::Vector{UInt8}, p::Int, x::Integer, m::Int)
    n = m
    @inbounds while n ≥ 2
        x, r = divrem(x, 0x64)  # 0x64 = 100
        dd = DECIMAL_DIGITS[(r % Int) + 1]
        data[p+n-1] =  dd       % UInt8
        data[p+n-2] = (dd >> 8) % UInt8
        n -= 2
    end
    if n > 0
        data[p] = (rem(x, 0xa) % UInt8) + Z
    end
    return p + m
end

function decimal_grouping(data::Vector{UInt8}, p::Int, x::Integer, m::Int, sep::UInt8)
    n = m
    while n ≥ 4
        x, r = divrem(x, 0x64)  # 0x64 = 100
        dd = DECIMAL_DIGITS[(r % Int) + 1]
        data[p+n-1] = dd % UInt8
        data[p+n-2] = (dd >> 8) % UInt8
        x, r = divrem(x, 0xa)
        data[p+n-3] = r % UInt8 + Z
        data[p+n-4] = sep
        n -= 4
    end
    decimal(data, p, x, n)
    return p + m
end

const HEXADECIMAL_DIGITS_UPPERCASE = zeros(UInt16, 256)
const HEXADECIMAL_DIGITS_LOWERCASE = zeros(UInt16, 256)
for x in 0:255
    d, r = divrem(x, 16)
    A = UInt8('A')
    HEXADECIMAL_DIGITS_UPPERCASE[x+1] = ((d < 10 ? d + Z : d - 10 + A) << 8) % UInt16 + (r < 10 ? r + Z : r - 10 + A) % UInt8
    A = UInt8('a')
    HEXADECIMAL_DIGITS_LOWERCASE[x+1] = ((d < 10 ? d + Z : d - 10 + A) << 8) % UInt16 + (r < 10 ? r + Z : r - 10 + A) % UInt8
end

function hexadecimal(data::Vector{UInt8}, p::Int, x::Integer, m::Int, uppercase::Bool)
    n = m
    hexdigits = uppercase ? HEXADECIMAL_DIGITS_UPPERCASE : HEXADECIMAL_DIGITS_LOWERCASE
    while n ≥ 2
        x, r = divrem(x, 0x100)  # 0x100 = 256
        xx = hexdigits[(r % Int) + 1]
        data[p+n-1] =  xx       % UInt8
        data[p+n-2] = (xx >> 8) % UInt8
        n -= 2
    end
    if n > 0
        A = uppercase ? UInt8('A') : UInt8('a')
        r = rem(x, 0x10) % UInt8
        data[p] = r < 0xa ? r + Z : r - 0xa + A
    end
    return p + m
end

function hexadecimal_grouping(data::Vector{UInt8}, p::Int, x::Integer, m::Int, uppercase::Bool)
    n = m
    hexdigits = uppercase ? HEXADECIMAL_DIGITS_UPPERCASE : HEXADECIMAL_DIGITS_LOWERCASE
    while n ≥ 5
        x, r = divrem(x, 0x100)  # 0x100 = 256
        xx = hexdigits[(r % Int) + 1]
        data[p+n-1] = xx % UInt8
        data[p+n-2] = (xx >> 8) % UInt8
        x, r = divrem(x, 0x100)
        xx = hexdigits[(r % Int) + 1]
        data[p+n-3] = xx % UInt8
        data[p+n-4] = (xx >> 8) % UInt8
        data[p+n-5] = UInt8('_')
        n -= 5
    end
    hexadecimal(data, p, x, n, uppercase)
    return p + m
end


text:
export
    DiscreteCPT

"""
    function DiscreteCPT(range::Vector{O}, paramdict::Dict{I, Vector{Float64}}) where {I <: Tuple, O}

Constructs an sfunc that represents a Discrete Conditional Probability table.

`DiscreteCPT`s are implemented as a `Table` with a `Cat`.

The `range` parameter defines all the possible outputs of the `DiscreteCPT`.  The `paramdict`
parameter defines the input(s) and the actual CPT.  For example,

```
    range = [1, 2]
    paramdict = Dict((1,1) => [0.3, 0.7], (1,2) => [0.6, 0.4], (2,1) =>[0.4, 0.6],
    (2,2) => [0.7, 0.3], (3,1) => [0.5, 0.5], (3,2) => [0.8, 0.2])
```

can create a `DiscreteCPT` which has two(2) inputs (the length of the key) and, given each input
as defined by the key, selects either `1` or `2` (the range) with the given probability.  So, if
the input is `(2,1)`, `1` is selected with probability `0.4` and `2` is selected with probability
`0.6`.

See also: [`Table`](@ref), [`Cat`](@ref)
"""
function DiscreteCPT(range::Vector{O}, paramdict::Dict{I, Vector{Float64}}) where {I <: Tuple, O}
    NumInputs = length(collect(keys(paramdict))[1])
    sfmaker(probs) = Cat(range, probs)
    return Table(Tuple{}, O, NumInputs, paramdict, sfmaker)
end

#=
# This form is provided for backward compatibility
# The ranges of the parents and child are all integer ranges from 1 to the number of values
function DiscreteCPT(params :: Array{Vector{Float64}, N}) where N
    rangesizes = size(params)
    parranges = [collect(1:r) for r in rangesizes]
    parcombos = cartesian_product(parranges)
    childrange = collect(1:length(params[1]))
    I = NTuple{N, Int}
    paramdict = Dict{I, Vector{Float64}}()
    for (i, combo) in enumerate(parcombos)
        paramdict[tuple(combo...)] = params[i]
    end
    return DiscreteCPT(childrange, paramdict)
end
=#


text:
struct WheelGraph{T <: Integer} <: LG.AbstractGraph{T}
    nv::T
end

LG.eltype(::WheelGraph{T}) where {T} = T
LG.edgetype(::WheelGraph{T}) where {T} = LG.Edge{T}
LG.is_directed(::Type{<:WheelGraph}) = false
LG.nv(g::WheelGraph) = g.nv
function LG.ne(g::WheelGraph)
    n = Int(nv(g))
    return 2 * (n - 1) - (n == 3) - (n == 2) + 2 * (n == 0)
end
LG.vertices(g::WheelGraph) = 1:LG.nv(g)

function LG.edges(g::WheelGraph)
    edges = Vector{LG.Edge{Int}}()
    # add inner edges
    for j in 1:LG.nv(g)-1
        push!(edges, LG.Edge(1, j+1))
    end
    # add perimeter
    for j in 2:LG.nv(g)-1
        push!(edges, LG.Edge(j, j+1))
    end
    push!(edges, LG.Edge(2, LG.nv(g)))
    return edges
end

function LG.outneighbors(g::WheelGraph, v)
    if v == 1
        return collect(2:LG.nv(g))
    end
    if v == 2
        return [1, 3, LG.nv(g)]
    end
    if v == LG.nv(g)
        return [1, 2, LG.nv(g)-1]
    end
    return [1, v-1, v+1]
end

LG.inneighbors(g::WheelGraph, v) = outneighbors(g, v)

LG.has_vertex(g::WheelGraph, v) = 1 <= v <= LG.nv(g)

function LG.has_edge(g::WheelGraph, v1, v2)
    v1, v2 = minmax(v1, v2)

    if !has_vertex(g, v1) || !has_vertex(g, v2)
        return false
    end
    # rayon
    if v1 == 1 && v2 > 1
        return true
    end
    # perimeter
    if v2 == v1 + 1
        return true
    end
    # boundary conditions
    if v1 == 2 && v2 == LG.nv(g) && v1 != v2
        return true
    end
    return false
end

# =======================================================
#         overrides
# =======================================================

# we use this check so that we have the same convention as in LightGraphs
LG.is_connected(g::WheelGraph) = nv(g) > 0

function LG.connected_components(g::WheelGraph)

    nv(g) == 0 && return typeof(vertices(g))[]
    return [vertices(g)]
end

# has_self_loops is defined in terms of this
LG.num_self_loops(::WheelGraph) = 0

LG.is_bipartite(g::WheelGraph) = nv(g) <= 2

function LG.squash(g::WheelGraph)
    nvg = nv(g)
    for T ∈ (UInt8, UInt16, UInt32, UInt64)
        nv(g) < typemax(T) && return WheelGraph(T(nvg))
    end
end

# ---- degree -----------------------------------

function LG.Δ(g::WheelGraph)
    nvg = nv(g)
    return ifelse(nvg == 0, typemin(Int), Int(nvg) - 1)
end

LG.Δout(g::WheelGraph) = Δ(g)
LG.Δin(g::WheelGraph) = Δ(g)

function LG.δ(g::WheelGraph)
    nvg = nv(g)
    return ifelse(nvg == 0, typemax(Int), ifelse(nvg <= 3, Int(nvg) - 1, 3))
end

LG.δout(g::WheelGraph) = δ(g)
LG.δin(g::WheelGraph) = δ(g)


text:
function partial_operand(n)

  reps = parse(Int64, ENV["LAMP_REPS"])

  A = randn(n,n)
  B = randn(n,n)

  Benchmarker.add_data(csv, "part_op_col_mult_nai", Benchmarker.measure(reps, part_op_col_mult_nai, A, B))
  Benchmarker.add_data(csv, "part_op_col_add_nai", Benchmarker.measure(reps, part_op_col_add_nai, A, B))
  Benchmarker.add_data(csv, "part_op_col_add_rec", Benchmarker.measure(reps, part_op_col_add_rec, A, B))

  Benchmarker.add_data(csv, "part_op_ele_mult_nai", Benchmarker.measure(reps, part_op_ele_mult_nai, A, B))
  Benchmarker.add_data(csv, "part_op_ele_add_nai", Benchmarker.measure(reps, part_op_ele_add_nai, A, B))
  Benchmarker.add_data(csv, "part_op_ele_add_rec", Benchmarker.measure(reps, part_op_ele_add_rec, A, B))

  @test isapprox(implicit_diagonal(A, B)[2], explicit_diagonal(A, B)[2])
end

function part_op_col_mult_nai(A, B)
  result = zeros(size(A,1), 1)
  start::Float64 = 0.0
  finish::Float64 = 0.0
  Benchmarker.cachescrub()
  Benchmarker.gcscrub()
  start = time_ns()

  result = (A*B)[:,2]

  finish = time_ns()
  return ((finish-start)*1e-9, result)
end

function part_op_col_add_nai(A, B)
  result = zeros(size(A,1), 1)
  start::Float64 = 0.0
  finish::Float64 = 0.0
  Benchmarker.cachescrub()
  Benchmarker.gcscrub()
  start = time_ns()

  result = (A+B)[:,2]

  finish = time_ns()
  return ((finish-start)*1e-9, result)
end

function part_op_col_add_rec(A, B)
  result = zeros(size(A,1), 1)
  start::Float64 = 0.0
  finish::Float64 = 0.0
  Benchmarker.cachescrub()
  Benchmarker.gcscrub()
  start = time_ns()

  result = A[:,2] + B[:,2]

  finish = time_ns()
  return ((finish-start)*1e-9, result)
end

function part_op_ele_mult_nai(A, B)
  result = zeros(size(A,1), 1)
  start::Float64 = 0.0
  finish::Float64 = 0.0
  Benchmarker.cachescrub()
  Benchmarker.gcscrub()
  start = time_ns()

  result = (A*B)[2,2]

  finish = time_ns()
  return ((finish-start)*1e-9, result)
end

function part_op_ele_add_nai(A, B)
  result = zeros(size(A,1), 1)
  start::Float64 = 0.0
  finish::Float64 = 0.0
  Benchmarker.cachescrub()
  Benchmarker.gcscrub()
  start = time_ns()

  result = (A+B)[2,2]

  finish = time_ns()
  return ((finish-start)*1e-9, result)
end

function part_op_ele_add_rec(A, B)
  result = zeros(size(A,1), 1)
  start::Float64 = 0.0
  finish::Float64 = 0.0
  Benchmarker.cachescrub()
  Benchmarker.gcscrub()
  start = time_ns()

  result = A[2,2] + B[2,2]

  finish = time_ns()
  return ((finish-start)*1e-9, result)
end


text:
export concat

"""
    concat(dim::Int, xs::Var...)

Concatenate arrays over the given dimension.

```julia
T = Float32
x1 = Var(rand(T,4,3))
x2 = Var(rand(T,4,5))
y = concat(2, x1, x2)
```
"""
function concat(dim::Int, xs::Vararg{Var})
    ydata = cat(map(x -> x.data, xs)..., dims=dim)
    Var(ydata, ∇concat!, (dim,xs...))
end
concat(dim, xs::Vararg{Node}) = Node(concat, (dim,xs...))

function ∇concat!(y::Var, dim::Int, xs::Var...)
    offset = 0
    for x in xs
        s = size(x, dim)
        if !isnothing(x.grad)
            I = ntuple(ndims(y)) do i
                i == dim ? (offset+1:offset+s) : Colon()
            end
            #gy = view(y.grad, I...)
            #if ndims(y) > ndims(x)
            #    gy = dropdims(gy, dims=ndims(y))
            #end
            addto!(x.grad, view(y.grad,I...))
        end
        offset += s
    end
end


text:
"""
Skewlia - mergable priority queues

```
    heap = Skewlia.SkewHeap()

    # Insert one at a time
    for job in some_list_of_jobs
        Skewlia.put!(heap, job)
    end

    # Insert all at once
    Skewlia.put!(heap, some_list_of_jobs...)

    # Retrieve jobs in order (using <=)
    while !Skewlia.is_empty(heap)
        job = Skewlia.get!(heap)
        do_stuff_with(job)
    end

    # Or as an iterator
    for job in heap
        do-stuff_with(job)
    end
```

"""
module Skewlia

import Base.+
import Base.iterate

struct SkewNode
    left::Union{SkewNode, Nothing}
    right::Union{SkewNode, Nothing}
    item

    SkewNode(item, left=nothing, right=nothing) = new(left, right, item)
end

const Node = Union{SkewNode, Nothing}

(+)(a::Nothing,  b::Nothing)  = nothing
(+)(a::SkewNode, b::Nothing)  = a
(+)(a::Nothing,  b::SkewNode) = b

function (+)(a::SkewNode, b::SkewNode)
    if a.item <= b.item
        SkewNode(a.item, b + a.right, a.left)
    else
        b + a
    end
end

"""    SkewHeap() ::SkewHeap

Initialize a new skew heap. Elements inserted into the heap will be ordered
using `<=`.
"""
mutable struct SkewHeap
    size::UInt64
    root::Node

    SkewHeap() = new(0, nothing)
end

"""    iterate(h::SkewHeap)

Returns an iterator that will sequentially retrieve each item from the heap.
Adding new items while iterating over the heap is perfectly acceptable.

```
heap = Skewlia.SkewHeap()

Skewlia.put!("foo", "bar", "baz", "bat")

for abused_string in heap
    println(abused_string)
end
```

"""
function Base.iterate(h::SkewHeap, state=true)
    if is_empty(h)
        return nothing
    else
        return take!(h), true
    end
end

"""    length(h::SkewHeap)

Returns the number of items in the heap.
"""
function length(h::SkewHeap)
    return h.size
end

"""    is_empty(h::SkewHeap)

Returns true if the heap is empty.
"""
function is_empty(h::SkewHeap)
    return length(h) == 0
end

"""    put(h::SkewHeap, items...)

Inserts new items into the heap and returns the heap's new size.
"""
function put!(h::SkewHeap, items...)
    for item in items
        h.root = h.root + SkewNode(item, nothing, nothing)
        h.size += 1
    end

    return h.size
end

"""    take(h::SkewHeap)

Removes and returns the next item from the heap or `nothing` if it is empty.
"""
function take!(h::SkewHeap)
    if h.size > 0
        item = h.root.item
        h.root = h.root.left + h.root.right
        h.size -= 1
        return item
    end

    return nothing
end

"""    peek(h::SkewHeap)
Returns the next item from the heap without removing it, or `nothing` if empty.
"""
function peek(h::SkewHeap)
    if h.size > 0
        return h.root.item
    end

    return nothing
end

"""    explain(h::SkewHeap)

Prints out the structure of the heap for debugging.
"""
function explain(n::SkewNode, indent)
    print(repeat("  ", indent))
    println(" - ", n.item)

    explain(n.left, indent + 1)
    explain(n.right, indent + 1)
end

function explain(n::Nothing, indent)
    print(repeat("  ", indent))
    println(" - Leaf")
end

function explain(h::SkewHeap)
    println("SkewHeap(size=", h.size, ")")
    println("  -Root:")
    explain(h.root, 1)
end

end

max_stars_repo_name: sysread/Skewlia

max_issues_repo_name: sysread/Skewlia

max_forks_repo_name: sysread/Skewlia


text:
struct FeatureSelector
    enable_node_feature::Bool
    enable_edge_feature::Bool
    enable_global_feature::Bool
end

function FeatureSelector(feature::Symbol)
    if feature == :node
        return FeatureSelector(true, false, false)
    elseif feature == :edge
        return FeatureSelector(false, true, false)
    elseif feature == :global
        return FeatureSelector(false, false, true)
    else
        throw(ArgumentError("only accept :node, :edge and :global while got $feature"))
    end
end

function (fs::FeatureSelector)(fg::FeaturedGraph)
    if fs.enable_node_feature && has_node_feature(fg)
        return node_feature(fg)
    elseif fs.enable_edge_feature && has_edge_feature(fg)
        return edge_feature(fg)
    elseif fs.enable_global_feature && has_global_feature(fg)
        return global_feature(fg)
    end
end

(fs::FeatureSelector)(fg::NullGraph) = nothing


text:
using Test
using HTTP

mutable struct URLTest
    name::String
    url::String
    isconnect::Bool
    expecteduri::HTTP.URI
    shouldthrow::Bool
end

struct Offset
    off::UInt16
    len::UInt16
end

function parse_connect_target(target)
    t = parse(HTTP.URI, "dummy://$target")
    if !isempty(t.userinfo) ||
       !isempty(t.path) ||
        isempty(t.host) ||
        isempty(t.port)

        throw(HTTP.URIs.ParseError(""))
    end
    return t.host, t.port
end

function offsetss(uri, offset)
    if offset == Offset(0,0)
        return SubString(uri, 1, 0)
    else
        return SubString(uri, offset.off, offset.off + offset.len-1)
    end
end

function URLTest(nm::String, url::String, isconnect::Bool, shouldthrow::Bool)
    URLTest(nm, url, isconnect, HTTP.URI(""), shouldthrow)
end

function URLTest(nm::String, url::String, isconnect::Bool, offsets::NTuple{7, Offset}, shouldthrow::Bool)
    uri = HTTP.URI(url, (offsetss(url, o) for o in offsets)...)
    URLTest(nm, url, isconnect, uri, shouldthrow)
end

@testset "HTTP.URI" begin
    # constructor
    @test string(HTTP.URI("")) == ""
    @test HTTP.URI(scheme="http", host="google.com") == HTTP.URI("http://google.com")
    @test HTTP.URI(scheme="http", host="google.com", path="/") == HTTP.URI("http://google.com/")
    @test HTTP.URI(scheme="http", host="google.com", userinfo="user") == HTTP.URI("http://user@google.com")
    @test HTTP.URI(scheme="http", host="google.com", path="/user") == HTTP.URI("http://google.com/user")
    @test HTTP.URI(scheme="http", host="google.com", query=Dict("key"=>"value")) == HTTP.URI("http://google.com?key=value")
    @test HTTP.URI(scheme="http", host="google.com", path="/", fragment="user") == HTTP.URI("http://google.com/#user")

    urls = [("hdfs://user:password@hdfshost:9000/root/folder/file.csv#frag", ["root", "folder", "file.csv"]),
            ("https://user:password@httphost:9000/path1/path2;paramstring?q=a&p=r#frag", ["path1", "path2;paramstring"]),
            ("https://user:password@httphost:9000/path1/path2?q=a&p=r#frag", ["path1","path2"]),
            ("https://user:password@httphost:9000/path1/path2;paramstring#frag", ["path1","path2;paramstring"]),
            ("https://user:password@httphost:9000/path1/path2#frag", ["path1","path2"]),
            ("file:///path/to/file/with%3fshould%3dwork%23fine", ["path","to","file","with%3fshould%3dwork%23fine"]),
            ("ftp://ftp.is.co.za/rfc/rfc1808.txt", ["rfc","rfc1808.txt"]),
            ("http://www.ietf.org/rfc/rfc2396.txt", ["rfc","rfc2396.txt"]),
            ("ldap://[2001:db8::7]/c=GB?objectClass?one", ["c=GB"]),
            ("mailto:John.Doe@example.com", ["John.Doe@example.com"]),
            ("news:comp.infosystems.www.servers.unix", ["comp.infosystems.www.servers.unix"]),
            ("tel:+1-816-555-1212", ["+1-816-555-1212"]),
            ("telnet://192.0.2.16:80/", String[]),
            ("urn:oasis:names:specification:docbook:dtd:xml:4.1.2", ["oasis:names:specification:docbook:dtd:xml:4.1.2"])
            ]

    for (url, splpath) in urls
        u = parse(HTTP.URI, url)
        @test string(u) == url
        @test isvalid(u)
        @test HTTP.URIs.splitpath(u.path) == splpath
    end

    @test parse(HTTP.URI, "hdfs://user:password@hdfshost:9000/root/folder/file.csv") == HTTP.URI(host="hdfshost", path="/root/folder/file.csv", scheme="hdfs", port=9000, userinfo="user:password")
    @test parse(HTTP.URI, "http://google.com:80/some/path") == HTTP.URI(scheme="http", host="google.com", path="/some/path")

    @test HTTP.Strings.lower(UInt8('A')) == UInt8('a')
    @test HTTP.escapeuri(Char(1)) == "%01"

    @test HTTP.escapeuri(Dict("key1"=>"value1", "key2"=>["value2", "value3"])) == "key2=value2&key2=value3&key1=value1"

    @test HTTP.escapeuri("abcdef αβ 1234-=~!@#\$()_+{}|[]a;") == "abcdef%20%CE%B1%CE%B2%201234-%3D%7E%21%40%23%24%28%29_%2B%7B%7D%7C%5B%5Da%3B"
    @test HTTP.unescapeuri(HTTP.escapeuri("abcdef 1234-=~!@#\$()_+{}|[]a;")) == "abcdef 1234-=~!@#\$()_+{}|[]a;"
    @test HTTP.unescapeuri(HTTP.escapeuri("👽")) == "👽"

    @test HTTP.escapeuri([("foo", "bar"), (1, 2)]) == "foo=bar&1=2"
    @test HTTP.escapeuri(Dict(["foo" => "bar", 1 => 2])) in ("1=2&foo=bar", "foo=bar&1=2")
    @test HTTP.escapeuri(["foo" => "bar", 1 => 2]) == "foo=bar&1=2"

    @test "user:password" == parse(HTTP.URI, "https://user:password@httphost:9000/path1/path2;paramstring?q=a&p=r#frag").userinfo

    @test HTTP.queryparams(HTTP.URI("https://httphost/path1/path2;paramstring?q=a&p=r#frag")) == Dict("q"=>"a","p"=>"r")
    @test HTTP.queryparams(HTTP.URI("https://foo.net/?q=a&malformed")) == Dict("q"=>"a","malformed"=>"")

    @test false == isvalid(parse(HTTP.URI, "file:///path/to/file/with?should=work#fine"))
    @test true == isvalid( parse(HTTP.URI, "file:///path/to/file/with%3fshould%3dwork%23fine"))

    @test parse(HTTP.URI, "s3://bucket/key") == HTTP.URI(host="bucket", path="/key", scheme="s3")

    @test sprint(show, parse(HTTP.URI, "http://google.com")) == "HTTP.URI(\"http://google.com\")"

    # Error paths
    # Non-ASCII characters
    @test_throws HTTP.URIs.ParseError HTTP.URIs.parse_uri("http://🍕.com", strict=true)
    # Unexpected start of URL
    @test_throws HTTP.URIs.ParseError HTTP.URIs.parse_uri(".google.com", strict=true)
    # Unexpected character after scheme
    @test_throws HTTP.URIs.ParseError HTTP.URIs.parse_uri("ht!tp://google.com", strict=true)

    #  Issue #27
    @test HTTP.escapeuri("t est\n") == "t%20est%0A"

    @testset "HTTP.parse(HTTP.URI, str)" begin

        urltests = URLTest[
        URLTest("proxy request"
         ,"http://hostname/"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(8, 8) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(16, 1) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("proxy request with port"
         ,"http://hostname:444/"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(8, 8) # UF_HOST
             ,Offset(17, 3) # UF_PORT
             ,Offset(20, 1) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("CONNECT request"
         ,"hostname:443"
         ,true
             ,(Offset(0, 0) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(1, 8) # UF_HOST
             ,Offset(10, 3) # UF_PORT
             ,Offset(0, 0) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("proxy ipv6 request"
         ,"http://[1:2::3:4]/"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(9, 8) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(18, 1) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("proxy ipv6 request with port"
         ,"http://[1:2::3:4]:67/"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(9, 8) # UF_HOST
             ,Offset(19, 2) # UF_PORT
             ,Offset(21, 1) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("CONNECT ipv6 address"
         ,"[1:2::3:4]:443"
         ,true
             ,(Offset(0, 0) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(2, 8) # UF_HOST
             ,Offset(12, 3) # UF_PORT
             ,Offset(0, 0) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("ipv4 in ipv6 address"
         ,"http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(9,37) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(47, 1) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("extra ? in query string"
         ,"http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css,fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css,fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(8,10) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(18,12) # UF_PATH
             ,Offset(31,187) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("space URL encoded"
         ,"/toto.html?toto=a%20b"
         ,false
             ,(Offset(0, 0) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(0, 0) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(1,10) # UF_PATH
             ,Offset(12,10) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("URL fragment"
         ,"/toto.html#titi"
         ,false
             ,(Offset(0, 0) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(0, 0) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(1,10) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(12, 4) # UF_FRAGMENT
             )
         ,false
         ), URLTest("complex URL fragment"
         ,"http://www.webmasterworld.com/r.cgi?f=21&d=8405&url=http://www.example.com/index.html?foo=bar&hello=world#midpage"
         ,false
         ,(Offset(  1,  4) # UF_SCHEMA
          ,Offset(  0,  0) # UF_USERINFO
          ,Offset(  8, 22) # UF_HOST
          ,Offset(  0,  0) # UF_PORT
          ,Offset( 30,  6) # UF_PATH
          ,Offset( 37, 69) # UF_QUERY
          ,Offset(107,  7) # UF_FRAGMENT
          )
         ,false
         ), URLTest("complex URL from node js url parser doc"
         ,"http://host.com:8080/p/a/t/h?query=string#hash"
         ,false
         ,(   Offset(1, 4) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(8, 8) # UF_HOST
             ,Offset(17, 4) # UF_PORT
             ,Offset(21, 8) # UF_PATH
             ,Offset(30,12) # UF_QUERY
             ,Offset(43, 4) # UF_FRAGMENT
             )
             ,false
         ), URLTest("complex URL with basic auth from node js url parser doc"
         ,"http://a:b@host.com:8080/p/a/t/h?query=string#hash"
         ,false
         ,(   Offset(1, 4) # UF_SCHEMA
             ,Offset(8, 3) # UF_USERINFO
             ,Offset(12, 8) # UF_HOST
             ,Offset(21, 4) # UF_PORT
             ,Offset(25, 8) # UF_PATH
             ,Offset(34,12) # UF_QUERY
             ,Offset(47, 4) # UF_FRAGMENT
             )
            ,false
         ), URLTest("double @"
         ,"http://a:b@@hostname:443/"
         ,false
         ,true
         ), URLTest("proxy empty host"
         ,"http://:443/"
         ,false
         ,true
         ), URLTest("proxy empty port"
         ,"http://hostname:/"
         ,false
         ,true
         ), URLTest("CONNECT with basic auth"
         ,"a:b@hostname:443"
         ,true
         ,true
         ), URLTest("CONNECT empty host"
         ,":443"
         ,true
         ,true
         ), URLTest("CONNECT empty port"
         ,"hostname:"
         ,true
         ,true
         ), URLTest("CONNECT with extra bits"
         ,"hostname:443/"
         ,true
         ,true
         ), URLTest("space in URL"
         ,"/foo bar/"
         ,false
         ,true # s_dead
         ), URLTest("proxy basic auth with space url encoded"
         ,"http://a%20:b@host.com/"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
              ,Offset(8, 6) # UF_USERINFO
              ,Offset(15, 8) # UF_HOST
              ,Offset(0, 0) # UF_PORT
              ,Offset(23, 1) # UF_PATH
              ,Offset(0, 0) # UF_QUERY
              ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("carriage return in URL"
         ,"/foo\rbar/"
         ,false
         ,true # s_dead
         ), URLTest("proxy double : in URL"
         ,"http://hostname::443/"
         ,false
         ,true # s_dead
         ), URLTest("proxy basic auth with double :"
         ,"http://a::b@host.com/"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
             ,Offset(8, 4) # UF_USERINFO
             ,Offset(13, 8) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(21, 1) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("line feed in URL"
         ,"/foo\nbar/"
         ,false
         ,true # s_dead
         ), URLTest("proxy empty basic auth"
         ,"http://@hostname/fo"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(9, 8) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(17, 3) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("proxy line feed in hostname"
         ,"http://host\name/fo"
         ,false
         ,true # s_dead
         ), URLTest("proxy % in hostname"
         ,"http://host%name/fo"
         ,false
         ,true # s_dead
         ), URLTest("proxy ; in hostname"
         ,"http://host;ame/fo"
         ,false
         ,true # s_dead
         ), URLTest("proxy basic auth with unreservedchars"
         ,"http://a!;-_!=+\$@host.com/"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
             ,Offset(8, 9) # UF_USERINFO
             ,Offset(18, 8) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(26, 1) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("proxy only empty basic auth"
         ,"http://@/fo"
         ,false
         ,true # s_dead
         ), URLTest("proxy only basic auth"
         ,"http://toto@/fo"
         ,false
         ,true # s_dead
         ), URLTest("proxy = in URL"
         ,"http://host=ame/fo"
         ,false
         ,true # s_dead
         ), URLTest("ipv6 address with Zone ID"
         ,"http://[fe80::a%25eth0]/"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(9,14) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(24, 1) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("ipv6 address with Zone ID, but '%' is not percent-encoded"
         ,"http://[fe80::a%eth0]/"
         ,false
             ,(Offset(1, 4) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(9,12) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(22, 1) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("ipv6 address ending with '%'"
         ,"http://[fe80::a%]/"
         ,false
         ,true # s_dead
         ), URLTest("ipv6 address with Zone ID including bad character"
         ,"http://[fe80::a%\$HOME]/"
         ,false
         ,true # s_dead
         ), URLTest("just ipv6 Zone ID"
         ,"http://[%eth0]/"
         ,false
         ,true # s_dead
         ), URLTest("tab in URL"
         ,"/foo\tbar/"
         ,false
             ,(Offset(0, 0) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(0, 0) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(1, 9) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         ), URLTest("form feed in URL"
         ,"/foo\fbar/"
         ,false
             ,(Offset(0, 0) # UF_SCHEMA
             ,Offset(0, 0) # UF_USERINFO
             ,Offset(0, 0) # UF_HOST
             ,Offset(0, 0) # UF_PORT
             ,Offset(1, 9) # UF_PATH
             ,Offset(0, 0) # UF_QUERY
             ,Offset(0, 0) # UF_FRAGMENT
             )
         ,false
         )
        ]

        for u in urltests
            println("TEST - uri.jl: $(u.name)")
            if u.isconnect
                if u.shouldthrow
                    @test_throws HTTP.URIs.ParseError parse_connect_target(u.url)
                else
                    h, p = parse_connect_target(u.url)
                    @test h == u.expecteduri.host
                    @test p == u.expecteduri.port
                end
            elseif u.shouldthrow
                @test_throws HTTP.URIs.ParseError HTTP.URIs.parse_uri_reference(u.url, strict=true)
            else
                url = parse(HTTP.URI, u.url)
                @test u.expecteduri == url
            end
        end
    end

    # Issue 323
    @test string(HTTP.URI(scheme="http", host="example.com")) == "http://example.com"

end; # @testset


text:
export CollectGems

mutable struct CollectGems <: AbstractGridWorld
    world::GridWorldBase{Tuple{Empty,Wall,Gem}}
    agent_pos::CartesianIndex{2}
    agent::Agent
    num_gem_init::Int
    num_gem_current::Int
    gem_reward::Float64
    r::Float64
end

function CollectGems(;n=8, agent_start_pos=CartesianIndex(2,2), agent_start_dir=RIGHT, rng=Random.GLOBAL_RNG)
    objects = (EMPTY, WALL, GEM)
    w = GridWorldBase(objects, n, n)

    w[EMPTY, 2:n-1, 2:n-1] .= true
    w[WALL, [1,n], 1:n] .= true
    w[WALL, 1:n, [1,n]] .= true

    w[GEM, 1:n, 1:n] .= false
    num_gem_init = n - 1
    num_gem_current = num_gem_init

    gem_placed = 0
    while gem_placed < num_gem_init
        gem_pos = CartesianIndex(rand(rng, 2:n-1), rand(rng, 2:n-1))
        if (gem_pos == agent_start_pos) || (w[GEM, gem_pos] == true)
            continue
        else
            w[GEM, gem_pos] = true
            w[EMPTY, gem_pos] = false
            gem_placed = gem_placed + 1
        end
    end

    gem_reward = 1.0
    r = 0.0

    CollectGems(w, agent_start_pos, Agent(dir=agent_start_dir), num_gem_init, num_gem_current, gem_reward, r)
end

function (w::CollectGems)(::MoveForward)
    dir = get_dir(w.agent)
    dest = dir(w.agent_pos)
    w.r = 0.0
    if !w.world[WALL, dest]
        w.agent_pos = dest
        if w.world[GEM, dest]
            w.world[GEM, dest] = false
            w.world[EMPTY, dest] = true
            w.num_gem_current = w.num_gem_current - 1
            w.r = w.gem_reward
        end
    end
    w
end

function (w::CollectGems)(action::Union{TurnRight, TurnLeft})
    w.r = 0.0
    agent = get_agent(w)
    set_dir!(agent, action(get_dir(agent)))
    w
end

function get_terminal(w::CollectGems)
    return w.num_gem_current <= 0
end

get_reward(w::CollectGems) = w.r


text:
# Julia wrapper for header: /usr/include/libavutil/stereo3d.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

export
    av_stereo3d_alloc,
    av_stereo3d_create_side_data,
    av_stereo3d_type_name,
    av_stereo3d_from_name

function av_stereo3d_alloc()
    ccall((:av_stereo3d_alloc, libavutil), Ptr{AVStereo3D}, ())
end

function av_stereo3d_create_side_data(frame)
    ccall((:av_stereo3d_create_side_data, libavutil), Ptr{AVStereo3D}, (Ptr{AVFrame},), frame)
end

function av_stereo3d_type_name(_type::Integer)
    ccall((:av_stereo3d_type_name, libavutil), Cstring, (UInt32,), _type)
end

function av_stereo3d_from_name(name)
    ccall((:av_stereo3d_from_name, libavutil), Cint, (Cstring,), name)
end


text:
function tr3!(r::Robot)#главная функция
    move_corner(r)#перемещаем робота в угол
    put_a_marker(r)#ставим маркер
    show!(r)#показать
end
function put_a_marker(r::Robot)#ставим маркер
    while ismarker(r) == false
        while isborder(r, Sud) == false
            putmarker!(r)
            move!(r, Sud)
        end
        if isborder(r, Ost) == false
            putmarker!(r)
            move!(r, Ost)
        end
        while isborder(r, Nord) == false
            putmarker!(r)
            move!(r, Nord)
        end
        if isborder(r, Ost) == false
            putmarker!(r)
            move!(r, Ost)
        end
    end
end
function move_corner(r::Robot) #перемещаем робота в угол
    while isborder(r, Nord) == false
        move!(r, Nord)
    end
    while isborder(r, West) == false
        move!(r, West)
    end
end


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

	using Base
	using BitOperations

	#= Credit to Gandalf#4004 in the Humans of Julia discord
	   I might use this at some point =#
	# _cvt_int(x) = (bv = BitVector((false,)) ; bv.chunks[1] = UInt64(x) ; bv.len = 64 ; bv)

	_bitindices(I) = range(bsizeof(I)-1, step=(-1), stop=0)

	export bitsof
	@inline bitsof(n::I, b_inds::StepRange) where {I <: Integer} = bget.(n, b_inds)

	@inline bitsof(n::I) where {I <: Integer} = bget.(n, _bitindices(I))

	export appendbitsof!
	appendbitsof!(V::BitVector, n::I) where I <: Integer = append!(V, bitsof(n, _bitindices(I)))

	appendbitsof!(V::BitVector, n::I, bitindices::StepRange) where I <: Integer = append!(V, bitsof(n, bitindices))

	function appendbitsof!(V::BitVector, N::Vector{I}) where I <: Integer
		bitindices = _bitindices(I)
		for n in N
			appendbitsof!(V, n, bitindices)
		end
	end

	export bmat_from_ints
	function bmat_from_ints(V::Vector{I}) where {I <: Integer}
		hcat((V .|> bitsof)...)
	end

	export bvec_from_ints
	function bvec_from_ints(V::Vector{I}) where {I <: Integer}
		vcat((v .|> bitsof)...)
	end

	export bvec_from_int
	@inline bvec_from_int(n::I) where {I <: Integer} = bitsof.(n)

end # module


text:
# K-LINK heuristic by Zhang, W.-H. Lin, M. Huang and X. Hu (2021) doi:10.1016/j.ejor.2019.07.004
function KLINKS(trans::SparseMatrixCSC{Float64, Int64},
                capacity::Array{Int64,1},
                trials::Int64,
                stagnant::Int64,
                strategy::Int64,
                klinkstatus::Int64)
    trans = Matrix(trans)
    if CHECKCAPACITY(trans,capacity) == 1
        ## Calculation of links based on orders
        ov = LINKADJUST(trans::Array{Int64,2})
        L = LINKS(trans::Array{Int64,2},ov::Array{Float64,1})
        ## Set trial = 0
        besttrial = 0
        lw_trial = Array{Float64,1}(undef,trials) .= 0
        cw_trial = Array{Int64,3}(undef,size(trans,2),size(capacity,1),trials) .= 0
        if klinkstatus == 1
            print("\nstarting k-link trials: ")
        end
        for y = 1:trials
            ## Random initialisation of the category distribution
            X = RANDOMALLOCONCE(trans::Array{Int64,2},capacity::Array{Int64,1})
            ## Get the matrix CW trial, Calculate the LW trial
            lw_trial[y] = LW(L::Array{Float64,2},X::Array{Int64,2})
            if klinkstatus == 1
                print(y,"/ ")
            end
            ## Start the heuristic
            stop = 0
            while stop <= stagnant
                # select a random warehouse to test potential improvements
                stop += 1
                m = rand(1:size(X,2))
                # apply either local search strategy 1 or strategy 2
                # -> 1: move SKU to a different warehouse if it improves the objective
                #       and the warehouse has capacity cap_left
                # -> 2: pair-wise exchange between SKUs if it improves the objective
                if strategy == 1
                    X = STRATEGY1(X::Array{Int64,2},
                                  m::Int64,
                                  L::Array{Float64,2},
                                  capacity::Array{Int64,1},
                                  stop::Int64)
                else
                    X = STRATEGY2(X::Array{Int64,2},
                                  m::Int64,
                                  L::Array{Float64,2},
                                  capacity::Array{Int64,1},
                                  stop::Int64)
                end
            end
            # Save the results from the trial
            lw_trial[y] = LW(L::Array{Float64,2},X::Array{Int64,2})
            cw_trial[:,:,y] = X
        end
        # Save the best result from all trails for export
        besttrial     = findmax(lw_trial)[2]
        cw_best       = cw_trial[:,:,besttrial]
        return cw_best
    end
end

max_stars_repo_name: beyondatlas/splitdeliveries

max_issues_repo_name: beyondatlas/splitdeliveries

max_forks_repo_name: beyondatlas/splitdeliveries


text:
using Metalhead, Test
using Flux

@testset "ViT" begin
    @test size(ViT()(rand(Float32, 256, 256, 3, 2))) == (1000, 2)
    @test_skip gradtest(ViT(), rand(Float32, 256, 256, 3, 2))
end


text:
import Winston

function Base.display(report::Report, m::MIME"image/png", data)

    chunk = report.cur_chunk
    full_name, rel_name = get_figname(report, chunk)

    docformat = formats[report.formatdict[:doctype]]

    #Add to results for term chunks and store otherwise
    if chunk[:term]
      chunk[:figure] = [rel_name]

      if report.term_state == :text
        report.cur_result *= "\n" * report.formatdict[:codeend] * "\n"
      end

      report.cur_result *= formatfigures(chunk, docformat)
      report.term_state = :fig
      chunk[:figure] = String[]
    else
      push!(report.figures, rel_name)
    end

    vector_fmts = [".pdf", ".svg"]

    #Don't use dpi for vector formats
    if chunk[:fig_ext] in vector_fmts
        Winston.savefig(data, full_name, width=chunk[:fig_width]*100, height=chunk[:fig_height]*100)
    else
        Winston.savefig(data, full_name, width=chunk[:fig_width]*chunk[:dpi], height=chunk[:fig_height]*chunk[:dpi])
    end

    report.fignum += 1
end