text:
using LinearAlgebra

import Base: -
import Adapt: adapt_structure, adapt

_batched_doc = """
    batched_transpose(A::AbstractArray{T,3})
    batched_adjoint(A)

Equivalent to applying `transpose` or `adjoint` to each matrix `A[:,:,k]`.

These exist to control how `batched_mul` behaves,
as it operates on such matrix slices of an array with `ndims(A)==3`.

`PermutedDimsArray(A, (2,1,3))` is equivalent to `batched_transpose(A)`,
and is also understood by `batched_mul` (and more widely supported elsewhere).

    BatchedTranspose{T, S} <: AbstractBatchedMatrix{T, 3}
    BatchedAdjoint{T, S}

Lazy wrappers analogous to `Transpose` and `Adjoint`, returned by `batched_transpose` etc.
"""

@doc _batched_doc
struct BatchedTranspose{T, S} <: AbstractArray{T, 3}
    parent::S
    BatchedTranspose{T, S}(X::S) where {T, S} = new{T, S}(X)
end

@doc _batched_doc
batched_transpose(A::AbstractArray{T, 3}) where T = BatchedTranspose(A)
batched_transpose(A::BatchedTranspose) = A.parent

@doc _batched_doc
struct BatchedAdjoint{T, S} <: AbstractArray{T, 3}
    parent::S
    BatchedAdjoint{T, S}(X::S) where {T, S} = new{T, S}(X)
end

@doc _batched_doc
batched_adjoint(A::AbstractArray{T, 3}) where T = BatchedAdjoint(A)
batched_adjoint(A::BatchedAdjoint) = A.parent

batched_adjoint(A::BatchedTranspose{<:Real}) = A.parent
batched_transpose(A::BatchedAdjoint{<:Real}) = A.parent
batched_adjoint(A::PermutedDimsArray{<:Real,3,(2,1,3)}) = A.parent
batched_transpose(A::PermutedDimsArray{<:Number,3,(2,1,3)}) = A.parent
# if you can't unwrap, put BatchedAdjoint outside (for dispatch):
batched_transpose(A::BatchedAdjoint{<:Complex}) = BatchedAdjoint(BatchedTranspose(A.parent))

BatchedAdjoint(A) = BatchedAdjoint{Base.promote_op(adjoint,eltype(A)),typeof(A)}(A)
BatchedTranspose(A) = BatchedTranspose{Base.promote_op(transpose,eltype(A)),typeof(A)}(A)

const BatchedAdjOrTrans{T, S} = Union{BatchedTranspose{T, S}, BatchedAdjoint{T, S}}

LinearAlgebra.wrapperop(A::BatchedAdjoint) = batched_adjoint
LinearAlgebra.wrapperop(B::BatchedTranspose) = batched_transpose

# AbstractArray Interface
Base.length(A::BatchedAdjOrTrans) = length(A.parent)
Base.size(m::BatchedAdjOrTrans) = (size(m.parent, 2), size(m.parent, 1), size(m.parent, 3))
Base.axes(m::BatchedAdjOrTrans) = (axes(m.parent, 2), axes(m.parent, 1), axes(m.parent, 3))

Base.IndexStyle(::Type{<:BatchedAdjOrTrans}) = IndexCartesian()
Base.@propagate_inbounds Base.getindex(m::BatchedTranspose, i::Int, j::Int, k::Int) = getindex(m.parent, j, i, k)
Base.@propagate_inbounds Base.getindex(m::BatchedAdjoint, i::Int, j::Int, k::Int) = adjoint(getindex(m.parent, j, i, k))
Base.@propagate_inbounds Base.setindex!(m::BatchedTranspose, v, i::Int, j::Int, k::Int) = setindex!(m.parent, v, j, i, k)
Base.@propagate_inbounds Base.setindex!(m::BatchedAdjoint, v, i::Int, j::Int, k::Int) = setindex!(m.parent, adjoint(v), j, i, k)

Base.similar(A::BatchedAdjOrTrans, T::Type, dims::Dims) = similar(A.parent, T, dims)
Base.similar(A::BatchedAdjOrTrans, dims::Dims) = similar(A.parent, dims)
Base.similar(A::BatchedAdjOrTrans, T::Type) = similar(A.parent, T, size(A))
Base.similar(A::BatchedAdjOrTrans) = similar(A.parent, size(A))

Base.parent(A::BatchedAdjOrTrans) = A.parent

(-)(A::BatchedAdjoint)   = BatchedAdjoint(  -A.parent)
(-)(A::BatchedTranspose) = BatchedTranspose(-A.parent)

# C interface
function Base.strides(A::Union{BatchedTranspose, BatchedAdjoint{<:Real}})
    sp = strides(A.parent)
    (sp[2], sp[1], sp[3])
end

function Base.stride(A::Union{BatchedTranspose, BatchedAdjoint{<:Real}}, d::Integer)
    d == 1 && return Base.stride(A.parent, 2)
    d == 2 && return Base.stride(A.parent, 1)
    Base.stride(A.parent, d)
end

Base.unsafe_convert(::Type{Ptr{T}}, A::BatchedAdjOrTrans{T}) where {T} =
    Base.unsafe_convert(Ptr{T}, parent(A))

# Gradients
function rrule(::typeof(batched_transpose), A::AbstractArray{<:Any,3})
    b_transpose_back(Δ) = (NO_FIELDS, batched_transpose(Δ))
    batched_transpose(A), b_transpose_back
end
function rrule(::typeof(batched_adjoint), A::AbstractArray{<:Any,3})
    b_adjoint_back(Δ) = (NO_FIELDS, batched_adjoint(Δ))
    batched_adjoint(A), b_adjoint_back
end

adapt_structure(to, x::BatchedAdjoint) = BatchedAdjoint(adapt(to, parent(x)))
adapt_structure(to, x::BatchedTranspose) = BatchedTranspose(adapt(to, parent(x)))


text:
module StructC14N

export canonicalize

import Base.convert

######################################################################
# Private functions
######################################################################

"""
  `convert(NamedTuple, str)`

  Convert a structure into a named tuple.
"""
function convert(::Type{NamedTuple}, str)
    k = fieldnames(typeof(str))
    return NamedTuple{k}(getfield.(Ref(str), k))
end

"""
  `findabbrv(v::Vector{Symbol})`

  Find all unique abbreviations of symbols in `v`.  Return a tuple of
  two `Vector{Symbol}`: the first contains all possible abbreviations;
  the second contains the corresponding un-abbreviated symbols.
"""
function findabbrv(symLong::Vector{Symbol})
    @assert length(symLong) >= 1
    symStr = String.(symLong)

    outAbbrv = Vector{Symbol}()
    outLong  = Vector{Symbol}()

    # Max length of string representation of keywords
    maxLen = maximum(length.(symStr))

    # Identify all abbreviations
    for len in 1:maxLen
        for i in 1:length(symStr)
            s = symStr[i]
            if length(s) >= len
                s = s[1:len]
                push!(outAbbrv, Symbol(s))
                push!(outLong , symLong[i])
            end
        end
    end

    # Identify unique abbreviations
    for sym in outAbbrv
        i = findall(outAbbrv .== sym)
        count = length(i)
        if count > 1
            deleteat!(outAbbrv, i)
            deleteat!(outLong , i)
        end
    end
    @assert length(unique(outLong)) == length(symLong) "Input symbols have ambiguous abbreviations"
    i = sortperm(outAbbrv)
    return (outAbbrv[i], outLong[i])
end

function myconvert(template, vv)
    if isa(template, Type)
        tt = template
    else
        tt = typeof(template)
    end

    if isa(tt, Union)
        if getfield(tt, :a) == Missing
            (ismissing(vv))  &&  (return vv)
            tt = getfield(tt, :b)
        elseif getfield(tt, :b) == Missing
            (ismissing(vv))  &&  (return vv)
            tt = getfield(tt, :a)
        end
    end

    if typeof(vv) <: AbstractString  &&  tt <: Number
        return convert(tt, Meta.parse(vv))
    end
    if typeof(vv) <: Number  &&  tt <: AbstractString
        return string(vv)
    end

    if length(methods(parse, (Type{tt}, typeof(vv)))) > 0
        return parse(tt, vv)
    end

    if length(methods(convert, (Type{tt}, typeof(vv)))) > 0
        return convert(tt, vv)
    end

    return tt(vv)
end

######################################################################
# Public functions
######################################################################

# input::NamedTuple
"""
  `canonicalize(template::NamedTuple, input::NamedTuple)`

  Canonicalize the `input` named tuple according to `template` and
  return the "canonicalized" named tuple.
"""
function canonicalize(template::NamedTuple, input::NamedTuple, dconvert=Dict())
    (abbrv, long) = findabbrv(collect(keys(template)))

    # Default values.  Each element in the output vector is `Missing`
    # if the corresponding element in the tuple is a `Type`, otherwise
    # it is the value itself.
    tmp = collect(values(template))
    outval = Vector{Any}(undef, length(tmp))
    for i in 1:length(tmp)
        if isa(tmp[i], Type)
            outval[i] = missing
        else
            outval[i] = deepcopy(tmp[i])
        end
    end

    for i in 1:length(input)
        key = keys(input)[i]
        j = findall(key .== abbrv)
        if length(j) == 0
            error("Unexpected key: " * String(key))
        end
        @assert length(j) == 1
        j = j[1]
        k = findall(long[j] .== keys(template))
        @assert length(k) == 1
        k = k[1]
        if haskey(dconvert, key)
            outval[k] = dconvert[key](input[i])
        else
            outval[k] = myconvert(template[k], input[i])
        end
    end
    return NamedTuple{keys(template)}(tuple(outval...))
end

"""
  `canonicalize(template::DataType, input::NamedTuple)`

  Canonicalize the `input` named tuple according to `template` and
  return the "canonicalized" structure.
"""
function canonicalize(template::DataType, input::NamedTuple, dconvert=Dict())
    (abbrv, long) = findabbrv(collect(fieldnames(template)))

    #Default values
    outval = Vector{Any}(missing, length(fieldnames(template)))

    for i in 1:length(input)
        key = keys(input)[i]
        j = findall(key .== abbrv)
        if length(j) == 0
            error("Unexpected key: " * String(key))
        end
        @assert length(j) == 1
        j = j[1]
        k = findall(long[j] .== fieldnames(template))
        @assert length(k) == 1
        k = k[1]
        if haskey(dconvert, key)
            outval[k] = dconvert[key](input[i])
        else
            outval[k] = myconvert(fieldtype(template, k), input[i])
        end
    end
    return template(outval...)
end

"""
  `canonicalize(template, input::NamedTuple)`

  Canonicalize the `input` named tuple according to `template` and
  return the "canonicalized" structure.
"""
canonicalize(template, input::NamedTuple, dconvert=Dict()) =
    return canonicalize(typeof(template), merge(convert(NamedTuple, template), input), dconvert)

# input::Tuple
"""
  `canonicalize(template::NamedTuple, input::Tuple)`

  Canonicalize the `input` tuple according to `template`, and
  return the "canonicalized" named tuple.
"""
canonicalize(template::NamedTuple, input::Tuple, dconvert=Dict()) = canonicalize(template, NamedTuple{keys(template)}(input), dconvert)

"""
  `canonicalize(template::DataType, input::Tuple)`

  Canonicalize the `input` tuple according to `template`, and
  return the "canonicalized" structure.
"""
canonicalize(template::DataType, input::Tuple, dconvert=Dict()) = canonicalize(template, NamedTuple{fieldnames(template)}(input), dconvert)

"""
  `canonicalize(template, input::Tuple)`

  Canonicalize the `input` tuple according to the `template` structure, and
  return the "canonicalized" structure.
"""
canonicalize(template, input::Tuple, dconvert=Dict()) = canonicalize(template, NamedTuple{fieldnames(typeof(template))}(input), dconvert)

"""
  `canonicalize(template, kwargs...)`

  Canonicalize the key/value pairs given as keywords according to the
  `template` structure or named tuple.
"""
function canonicalize(template, dconvert=Dict(); kwargs...)
    a = collect(kwargs)
    k = getindex.(a, 1)
    v = getindex.(a, 2)
    nt = NamedTuple{tuple(k...)}(tuple(v...))
    return canonicalize(template, nt, dconvert)
end

end # module

ext: jl


text:
module ROOTHistograms

using ROOT, Histograms

import ROOT.to_root
function to_root{T, E}(h::ErrorHistogram{T, 2, E}, name="hist")
    nbins_x = nbins(h, 1)
    nbins_y = nbins(h, 2)

    conts, errs = contents(h), errors(h)

    #remove overflow bins
    e1 = convert(Vector{Float64}, h.edges[1][2:end-1])
    e2 = convert(Vector{Float64}, h.edges[2][2:end-1])

    hi = TH2D(name, name, Int32(nbins_x - 3), pointer(e1), Int32(nbins_y - 3), pointer(e2))
    for i=0:nbins_x-2
        for j=0:nbins_y-2
            SetBinContent(hi, Int32(i), Int32(j), conts[i + 1, j + 1])
            SetBinError(hi, Int32(i), Int32(j), errs[i + 1, j + 1])
        end
    end
    SetEntries(hi, sum(entries(h)))
    return hi
end

function to_root{T, E}(h::ErrorHistogram{T, 1, E}, name="hist")

    #remove underflow low and overflow high
    _edges = collect(edges(h)[1])[2:end-1]
    hi = TH1D(name, name, Int32(nbins(h)[1] - 2), pointer(_edges))
    for i=0:GetNbinsX(hi)+1
        SetBinContent(hi, Int32(i), contents(h)[i + 1])
        SetBinError(hi, Int32(i), errors(h)[i + 1])
    end
    SetEntries(hi, sum(entries(h)))

    # # println(h)
    # # Print(hi, "ALL")
    # conts, errs, ents, _edges2 = get_hist_bins(hi)
    #
    # if !all(conts .==  contents(h))
    #     warn("mismatch in contents: \n", hcat(conts, contents(h))|>string, "\n")
    # end
    # if !all(errs .==  errors(h))
    #     warn("mismatch in errors: \n", hcat(errs, errors(h))|>string, "\n")
    # end
    # # if !all(ents .==  entries(h))
    # #     warn("mismatch in entries: \n", hcat(ents, entries(h))|>string, "\n")
    # # end
    # if !all(_edges2 .==  _edges)
    #     warn("mismatch in edges: \n", hcat(_edges, edges(h)[1])|>string, "\n")
    # end
    return hi
end

function get_hist_bins(h::Union{TH1D, TH1A, TH1}; error_type=:contents)
    assert(h.p != C_NULL)
    nb = Int64(GetNbinsX(h))
    nb>0 || error("nbins = $nb")

    #+3 = underflow, overflow, superfluous extra bin
    conts = zeros(Float64, nb+2)
    errs = zeros(Float64, nb+2)
    ents = zeros(Float64, nb+2)

    #underflow low, overflow low, overflow high
    edges = zeros(Float64, nb+3)
    for n=0:nb+1
        #println("$n ", GetBinLowEdge(h, Int32(n)), " ", GetBinContent(h, Int32(n)), " ", GetBinError(h, Int32(n)))
        conts[n+1] = GetBinContent(h, Int32(n))
        errs[n+1] = GetBinError(h, Int32(n))
        #entries[n+1] = GetEntries(h) * conts[n+1]
        edges[n+1] = GetBinLowEdge(h, Int32(n))
    end

    #this works for histograms for which the bin errors have been manually set
    #to non-Poisson, GetEntries is meaningless
    if error_type == :errors
        ents = (conts ./ errs).^2
        ents[isnan(ents)] = 0
        ents[ents .== Inf] = 1
        #println(hcat(conts, errs, ents, conts./sqrt(ents)))
    end

    #this works for Poisson bin errors
    if error_type == :contents
        ents = conts ./ sum(conts) .* GetEntries(h)
        ents[isnan(ents)] = 0
    end
    #ents = int(round(ents))

    edges[1] = -Inf
    edges[nb+2] = edges[nb+1] + GetBinWidth(h, Int32(nb))
    edges[nb+3] = Inf

    if error_type != :errors
        if GetEntries(h)>0
            @assert abs(sum(ents) - GetEntries(h))/sum(ents)<0.0001 string("entries unequal ", sum(ents), "!=", GetEntries(h))
        end
    end
    if Integral(h)>0
        @assert abs(sum(conts) - Integral(h, Int32(0), Int32(nb+1)))/sum(conts)<0.0001 string("contents unequal ", sum(conts), "!=", Integral(h, Int32(0), Int32(nb+1)))
    end
    # if (abs(sum(conts) - Integral(h)) > 100000 * eps(Float64))
    #     warn(
    #         GetName(h)|>bytestring,
    #         " integral mismatch: $(sum(conts)) != $(Integral(h))"
    #     )
    # end
    return conts, errs, ents, edges
end

function load_with_errors(f::TDirectoryA, k::ASCIIString; kwargs...)
    th = root_cast(TH1, Get(f, k))
    #println(th)
    conts, errs, ents, edgs = get_hist_bins(th; kwargs...)
    h = Histogram(ents, conts, edgs)
    return h
end

function from_root(o::TH1A)
    assert(o.p != C_NULL)
    conts, errs, ents, edgs = get_hist_bins(o)
    h = ErrorHistogram{Float64, 1, Tuple{Vector{Float64}}}(
        (edgs, ), conts, errs.^2, :left
    )
    # for i=1:nbins(h)
    #     @assert abs(errors(h)[i] - errs[i])<0.0001 string("errors unequal $(hcat(errors(h), errs))")
    # end
    return h
end

function from_root(o::TH2A)
    assert(o.p != C_NULL)
    nx, ny = size(o)
    #println("nx=$nx ny=$ny")
    conts = zeros(nx+2, ny+2)
    errs = zeros(nx+2, ny+2)
    edgs = (zeros(Float64, nx+3), zeros(Float64, ny+3))
    for x=0:nx+1
        edgs[1][x+1] = GetBinLowEdgeX(o, Int32(x))
    end
    for y=0:ny+1
        edgs[2][y+1] = GetBinLowEdgeY(o, Int32(y))
    end
    edgs[1][1] = -Inf
    edgs[1][end] = Inf
    edgs[2][1] = -Inf
    edgs[2][end] = Inf
    for x=0:nx+1
        for y=0:ny+1
            conts[x+1, y+1] =
                GetBinContent(root_cast(TH1, o), Int32(x), Int32(y))
            errs[x+1, y+1] =
                GetBinError(root_cast(TH1, o), Int32(x), Int32(y))
        end
    end

    return ErrorHistogram{Float64, 2, Tuple{Vector{Float64}, Vector{Float64}}}(
        edgs, conts, errs.^2, :left
    )
end

import Base.size
Base.size(o::TH2D) = (GetNbinsX(root_cast(TH1, o)), GetNbinsY(root_cast(TH1, o)))

function load_hists_from_file(fn, hfilter=(name->true))
    tf = TFile(fn)
    @assert tf.p != C_NULL

    kl = GetListOfKeys(tf)
    @assert kl.p != C_NULL

    key_iterator = TListIter(kl.p)
    #kl = GetListOfKeys(tf)
    #objs = GetList(tf)

    ret = Dict()

    tic()
    for i=1:length(kl)
        #(i % 10000 == 0) && (println("$(i)/$(length(kl)) ", toq());tic())
        _k = Next(key_iterator)
        @assert _k != C_NULL
        const k = TKey(_k)
        const n = GetName(k) |> bytestring
        hfilter(n) || continue
        const o = ReadObj(k) |> to_root
        ret[n] = from_root(o)
    end

    Close(tf)
    return ret
end

# function recurse_write(tf, hd::Associative, pref="")
#     if pref != ""
#         println("making $pref")
#         d = ROOT.mkdir(tf, pref)
#         @show d
#         if ROOT.root_pointer(d) == C_NULL
#             d2 =  root_cast(TDirectory, Get(tf, pref))
#             @show d2
#         end
#         d = root_cast(TDirectory, d)
#         assert(d.p != C_NULL)
#     else
#         d = tf
#     end
#     Cd(tf, pref)
#     for (k, v) in hd
#         s = length(pref)>0 ? "$pref/$k" : string(k)
#         recurse_write(d, v, s)
#     end
#     pref!= "" && Cd(tf, "..")
# end

# function recurse_write(tf::TDirectoryA, v::ErrorHistogram, pref="")
#     th = to_root(v)
#     @show tf
#     SetDirectory(th, ROOT.root_pointer(tf))
#     Write(th)
# end

function write_hists_to_file(fn, hd::Associative; verbose=false)
    tf = TFile(convert(ASCIIString, fn), "RECREATE")
    Cd(tf, "")
    for (objpath, obj) in hd
        spl = rsearch(objpath, "/")
        dirname = objpath[1:spl.start-1]
        objname = objpath[spl.start+1:end]
        if length(dirname) > 0
            verbose && println("dir=$dirname obj=$objname")
            d = Get(tf, dirname)
            if d.p == C_NULL
                verbose && println("making $dirname")
                d = ROOT.mkdir(tf, dirname)
            end
            d = root_cast(TDirectory, Get(tf, dirname))
            assert(d.p != C_NULL)
        else
            d = tf
        end
        verbose && println("TDirectory=$d")
        robj = to_root(obj, objname)
        SetDirectory(robj, convert(Ptr{TDirectory}, d.p))
    end
    nb = Write(tf)
    verbose && println("Wrote $nb bytes")
    Close(tf)
end

include("pyplot.jl")

export to_root, get_hist_bins, load_hists_from_file, from_root, write_hists_to_file
export load_with_errors

end


text:
@testset "get burgers data" begin
    xs, ys = Burgers.get_data(n=1000)

    @test size(xs) == (2, 1024, 1000)
    @test size(ys) == (1024, 1000)
end


text:
# Precondition
# ============

primitive type Value 8 end

const NONE  = reinterpret(Value, 0x00)
const TRUE  = reinterpret(Value, 0x01)
const FALSE = reinterpret(Value, 0x02)
const BOTH  = reinterpret(Value, 0x03)

function Base.convert(::Type{UInt8}, v::Value)
    return reinterpret(UInt8, v)
end

function Base.convert(::Type{Value}, b::UInt8)
    return reinterpret(Value, b)
end

function Base.:|(v1::Value, v2::Value)
    return convert(Value, convert(UInt8, v1) | convert(UInt8, v2))
end

function Base.:&(v1::Value, v2::Value)
    return convert(Value, convert(UInt8, v1) & convert(UInt8, v2))
end

struct Precondition
    names::Vector{Symbol}
    values::Vector{Value}
end

function Precondition()
    return Precondition(Symbol[], Value[])
end

function Base.getindex(precond::Precondition, name::Symbol)
    i = findfirst(n -> n == name, precond.names)
    if i == 0
        return BOTH
    else
        return precond.values[i]
    end
end

function Base.push!(precond::Precondition, kv::Pair{Symbol,Value})
    name, value = kv
    i = findfirst(n -> n == name, precond.names)
    if i == nothing
        push!(precond.names, name)
        push!(precond.values, value)
    else
        precond.values[i] |= value
    end
    return precond
end

function precondition_names(precond::Precondition)
    return copy(precond.names)
end

function conflicts(precond1::Precondition, precond2::Precondition)
    for (n1, v1) in precond1
        if (v1 & precond2[n1]) == NONE
            return true
        end
    end
    return false
end

function Base.iterate(precond::Precondition, i=1)
    if i > length(precond.names)
        return nothing
    end
    return (precond.names[i], precond.values[i]), i + 1
end

function isconditioned(precond::Precondition)
    for v in precond.values
        if v != BOTH
            return true
        end
    end
    return false
end


text:
include("factorial.jl")

"""
    krishnamurthy(number)

Check if a number is a Krishnamurthy number or not

# Details

It is also known as Peterson Number.

A Krishnamurthy Number is a number whose sum of the
factorial of the digits equals to the original
number itself.

For example: 145 = 1! + 4! + 5!
    So, 145 is a Krishnamurthy Number

# Example

```julia
krishnamurthy(145) # returns true
krishnamurthy(240) # returns false
krishnamurthy(1)   # returns true
```

Contributed By:- [Ashwani Rathee](https://github.com/ashwani-rathee)
"""
function krishnamurthy(number)
    if number != trunc(number) || number < 0
        throw(
            error("krishnamurthy() only accepts non-negative integral values"),
        )
    end
    total = 0
    temp = number
    while temp > 0
        temp, digit = divrem(temp, 10)
        total += factorial_iterative(digit)
    end
    return total == number
end

max_issues_repo_name: AugustoCL/Julia

max_forks_repo_name: AugustoCL/Julia


text:
module IACA
export iaca_start, iaca_end, analyze

using LLVM
using LLVM.Interop

const optlevel = Ref{Int}()

function __init__()
    @assert LLVM.InitializeNativeTarget() == false
    optlevel[] = Base.JLOptions().opt_level
end

"""
    analyze(func, tt, march = :SKL)

Analyze a given function `func` with the type signature `tt`.
The specific method needs to be annotated with the `IACA` markers.
Supported `march` are :HSW, :BDW, :SKL, and :SKX.

# Example

```julia
function mysum(A)
    acc = zero(eltype(A))
    for a in A
        iaca_start()
        acc += a
    end
    iaca_end()
    return acc
end

analyze(mysum, Tuple{Vector{Float64}})
```

# Advanced usage
## Switching opt-level
```julia
IACA.optlevel[] = 3
analyze(mysum, Tuple{Vector{Float64}}, :SKL)
````

## Changing the optimization pipeline

```julia
myoptimize!(tm, mod) = ...
analyze(mysum. Tuple{Vector{Float64}}, :SKL, myoptimize!)
````
"""
function analyze(@nospecialize(func), @nospecialize(tt), march=:SKL, optimize!::Core.Function = jloptimize!)
    iaca_path = "iaca"
    if haskey(ENV, "IACA_PATH")
        iaca_path = ENV["IACA_PATH"]
    end
    @assert !isempty(iaca_path)

    cpus = Dict(
        :HSW => "haswell",
        :BDW => "broadwell",
        :SKL => "skylake",
        :SKX => "skx",
    )
    @assert haskey(cpus, march) "Arch: $march not supported"

    mktempdir() do dir
        objfile = joinpath(dir, "a.out")
        mod, _ = irgen(func, tt)
        target_machine(cpus[march]) do tm
            optimize!(tm, mod)
            LLVM.emit(tm, mod, LLVM.API.LLVMObjectFile, objfile)
        end
        Base.run(`$iaca_path -arch $march $objfile`)
    end
end

nameof(f::Core.Function) = String(typeof(f).name.mt.name)

function target_machine(lambda, cpu, features = "")
    triple = LLVM.triple()
    target = LLVM.Target(triple)
    LLVM.TargetMachine(lambda, target, triple, cpu, features)
end

globalUnique = 0

function irgen(@nospecialize(func), @nospecialize(tt))
    isa(func, Core.Builtin) && error("function is not a generic function")
    world = typemax(UInt)
    meth = which(func, tt)
    sig = Base.signature_type(func, tt)::Type

    (ti, env) = ccall(:jl_type_intersection_with_env, Any,
                      (Any, Any), sig, meth.sig)::Core.SimpleVector
    meth = Base.func_for_method_checked(meth, ti)
    linfo = ccall(:jl_specializations_get_linfo, Ref{Core.MethodInstance},
                  (Any, Any, Any, UInt), meth, ti, env, world)

    dependencies = Vector{LLVM.Module}()
    function hook_module_activation(ref::Ptr{Cvoid})
        ref = convert(LLVM.API.LLVMModuleRef, ref)
        push!(dependencies, LLVM.Module(ref))
    end

    params = Base.CodegenParams(cached=false,
                                module_activation  = hook_module_activation,
                                )

    # get the code
    mod = let
        ref = ccall(:jl_get_llvmf_defn, LLVM.API.LLVMValueRef,
                    (Any, UInt, Bool, Bool, Base.CodegenParams),
                    linfo, world, #=wrapper=#false, #=optimize=#false, params)
        if ref == C_NULL
            throw(CompilerError(ctx, "the Julia compiler could not generate LLVM IR"))
        end

        llvmf = LLVM.Function(ref)
        LLVM.parent(llvmf)
    end

    # the main module should contain a single jfptr_ function definition,
    # e.g. jfptr_kernel_vadd_62977
    definitions = LLVM.Function[]
    for llvmf in functions(mod)
        if !isdeclaration(llvmf)
            push!(definitions, llvmf)
        end
    end

    wrapper = nothing
    for llvmf in definitions
        if startswith(LLVM.name(llvmf), "jfptr_")
            @assert wrapper == nothing
            wrapper = llvmf
        end
    end
    @assert wrapper != nothing

    # the jfptr wrapper function should point us to the actual entry-point,
    # e.g. julia_kernel_vadd_62984
    # FIXME: Julia's globalUnique starting with `-` is probably a bug.
    entry_tag = let
        m = match(r"^jfptr_(.+)_[-\d]+$", LLVM.name(wrapper))
        if m == nothing
            error(LLVM.name(wrapper))
        end
        m.captures[1]
    end
    unsafe_delete!(mod, wrapper)
    entry = let
        re = Regex("^julia_$(entry_tag)_[-\\d]+\$")
        entrypoints = LLVM.Function[]
        for llvmf in definitions
            if llvmf != wrapper
                llvmfn = LLVM.name(llvmf)
                if occursin(re, llvmfn)
                    push!(entrypoints, llvmf)
                end
            end
        end
        if length(entrypoints) != 1
            @warn ":cry:" functions=Tuple(LLVM.name.(definitions)) tag=entry_tag entrypoints=Tuple(LLVM.name.(entrypoints))
        end
        entrypoints[1]
    end

    # link in dependent modules
    for dep in dependencies
        link!(mod, dep)
    end

    # rename the entry point
    llvmfn = replace(LLVM.name(entry), r"_\d+$"=>"")

    ## append a global unique counter
    global globalUnique
    globalUnique += 1
    llvmfn *= "_$globalUnique"
    LLVM.name!(entry, llvmfn)

    return mod, entry
end

"""
    jloptimize!(tm, mod)

Runs the Julia optimizer pipeline.
"""
function jloptimize!(tm::LLVM.TargetMachine, mod::LLVM.Module)
    ModulePassManager() do pm
        add_library_info!(pm, triple(mod))
        add_transform_info!(pm, tm)
        ccall(:jl_add_optimization_passes, Nothing,
              (LLVM.API.LLVMPassManagerRef, Cint),
               LLVM.ref(pm), optlevel[])
        run!(pm, mod)
    end
end

"""
    iaca_start()

Insertes IACA start marker at this position.
"""
function iaca_start()
    @asmcall("""
    movl \$\$111, %ebx
    .byte 0x64, 0x67, 0x90
    """, "~{memory},~{ebx}", true)
end

"""
    iaca_end()

Insertes IACA end marker at this position.
"""
function iaca_end()
    @asmcall("""
    movl \$\$222, %ebx
    .byte 0x64, 0x67, 0x90
    """, "~{memory},~{ebx}", true)
end

include("reflection.jl")
end # module


text:
using SafeTestsets: @safetestset

@time @safetestset "cmd" begin include("cmd.jl") end


text:
# ---
# title: 658. Find K Closest Elements
# id: problem658
# author: Indigo
# date: 2021-06-28
# difficulty: Medium
# categories: Binary Search
# link: <https://leetcode.com/problems/find-k-closest-elements/description/>
# hidden: true
# ---
#
# Given a **sorted** integer array `arr`, two integers `k` and `x`, return the
# `k` closest integers to `x` in the array. The result should also be sorted in
# ascending order.
#
# An integer `a` is closer to `x` than an integer `b` if:
#
#   * `|a - x| < |b - x|`, or
#   * `|a - x| == |b - x|` and `a < b`
#
#
#
# **Example 1:**
#
#
#
#     Input: arr = [1,2,3,4,5], k = 4, x = 3
#     Output: [1,2,3,4]
#
#
# **Example 2:**
#
#
#
#     Input: arr = [1,2,3,4,5], k = 4, x = -1
#     Output: [1,2,3,4]
#
#
#
#
# **Constraints:**
#
#   * `1 <= k <= arr.length`
#   * `1 <= arr.length <= 104`
#   * Absolute value of elements in the array and `x` will not exceed `104`
#
#
## @lc code=start
using LeetCode

function find_closest_elements(arr::Vector{Int}, k::Int, x::Int)
    res = Int[]
    j = searchsortedfirst(arr, x)
    i = j - 1
    for _ in 1:k
        if i == 0 || (j <= length(arr) && arr[j] - x < x - arr[i])
            push!(res, arr[j])
            j += 1
        else
            pushfirst!(res, arr[i])
            i -= 1
        end
    end
    return res
end
## @lc code=end


text:
# This file is auto-generated by AWSMetadata.jl
using AWS
using AWS.AWSServices: backup_gateway
using AWS.Compat
using AWS.UUIDs

"""
    associate_gateway_to_server(gateway_arn, server_arn)
    associate_gateway_to_server(gateway_arn, server_arn, params::Dict{String,<:Any})

Associates a backup gateway with your server. After you complete the association process,
you can back up and restore your VMs through the gateway.

# Arguments
- `gateway_arn`: The Amazon Resource Name (ARN) of the gateway. Use the ListGateways
  operation to return a list of gateways for your account and Amazon Web Services Region.
- `server_arn`: The Amazon Resource Name (ARN) of the server that hosts your virtual
  machines.

"""
function associate_gateway_to_server(
    GatewayArn, ServerArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return backup_gateway(
        "AssociateGatewayToServer",
        Dict{String,Any}("GatewayArn" => GatewayArn, "ServerArn" => ServerArn);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function associate_gateway_to_server(
    GatewayArn,
    ServerArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "AssociateGatewayToServer",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("GatewayArn" => GatewayArn, "ServerArn" => ServerArn),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_gateway(activation_key, gateway_display_name, gateway_type)
    create_gateway(activation_key, gateway_display_name, gateway_type, params::Dict{String,<:Any})

Creates a backup gateway. After you create a gateway, you can associate it with a server
using the AssociateGatewayToServer operation.

# Arguments
- `activation_key`: The activation key of the created gateway.
- `gateway_display_name`: The display name of the created gateway.
- `gateway_type`: The type of created gateway.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Tags"`: A list of up to 50 tags to assign to the gateway. Each tag is a key-value pair.
"""
function create_gateway(
    ActivationKey,
    GatewayDisplayName,
    GatewayType;
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "CreateGateway",
        Dict{String,Any}(
            "ActivationKey" => ActivationKey,
            "GatewayDisplayName" => GatewayDisplayName,
            "GatewayType" => GatewayType,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_gateway(
    ActivationKey,
    GatewayDisplayName,
    GatewayType,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "CreateGateway",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "ActivationKey" => ActivationKey,
                    "GatewayDisplayName" => GatewayDisplayName,
                    "GatewayType" => GatewayType,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_gateway(gateway_arn)
    delete_gateway(gateway_arn, params::Dict{String,<:Any})

Deletes a backup gateway.

# Arguments
- `gateway_arn`: The Amazon Resource Name (ARN) of the gateway to delete.

"""
function delete_gateway(GatewayArn; aws_config::AbstractAWSConfig=global_aws_config())
    return backup_gateway(
        "DeleteGateway",
        Dict{String,Any}("GatewayArn" => GatewayArn);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_gateway(
    GatewayArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "DeleteGateway",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("GatewayArn" => GatewayArn), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_hypervisor(hypervisor_arn)
    delete_hypervisor(hypervisor_arn, params::Dict{String,<:Any})

Deletes a hypervisor.

# Arguments
- `hypervisor_arn`: The Amazon Resource Name (ARN) of the hypervisor to delete.

"""
function delete_hypervisor(HypervisorArn; aws_config::AbstractAWSConfig=global_aws_config())
    return backup_gateway(
        "DeleteHypervisor",
        Dict{String,Any}("HypervisorArn" => HypervisorArn);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_hypervisor(
    HypervisorArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "DeleteHypervisor",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("HypervisorArn" => HypervisorArn), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    disassociate_gateway_from_server(gateway_arn)
    disassociate_gateway_from_server(gateway_arn, params::Dict{String,<:Any})

Disassociates a backup gateway from the specified server. After the disassociation process
finishes, the gateway can no longer access the virtual machines on the server.

# Arguments
- `gateway_arn`: The Amazon Resource Name (ARN) of the gateway to disassociate.

"""
function disassociate_gateway_from_server(
    GatewayArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return backup_gateway(
        "DisassociateGatewayFromServer",
        Dict{String,Any}("GatewayArn" => GatewayArn);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function disassociate_gateway_from_server(
    GatewayArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "DisassociateGatewayFromServer",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("GatewayArn" => GatewayArn), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    import_hypervisor_configuration(host, name)
    import_hypervisor_configuration(host, name, params::Dict{String,<:Any})

Connect to a hypervisor by importing its configuration.

# Arguments
- `host`: The server host of the hypervisor. This can be either an IP address or a
  fully-qualified domain name (FQDN).
- `name`: The name of the hypervisor.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"KmsKeyArn"`: The Key Management Service for the hypervisor.
- `"Password"`: The password for the hypervisor.
- `"Tags"`: The tags of the hypervisor configuration to import.
- `"Username"`: The username for the hypervisor.
"""
function import_hypervisor_configuration(
    Host, Name; aws_config::AbstractAWSConfig=global_aws_config()
)
    return backup_gateway(
        "ImportHypervisorConfiguration",
        Dict{String,Any}("Host" => Host, "Name" => Name);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function import_hypervisor_configuration(
    Host,
    Name,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "ImportHypervisorConfiguration",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("Host" => Host, "Name" => Name), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_gateways()
    list_gateways(params::Dict{String,<:Any})

Lists backup gateways owned by an Amazon Web Services account in an Amazon Web Services
Region. The returned list is ordered by gateway Amazon Resource Name (ARN).

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of gateways to list.
- `"NextToken"`: The next item following a partial list of returned resources. For example,
  if a request is made to return MaxResults number of resources, NextToken allows you to
  return more items in your list starting at the location pointed to by the next token.
"""
function list_gateways(; aws_config::AbstractAWSConfig=global_aws_config())
    return backup_gateway(
        "ListGateways"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_gateways(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return backup_gateway(
        "ListGateways", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

"""
    list_hypervisors()
    list_hypervisors(params::Dict{String,<:Any})

Lists your hypervisors.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of hypervisors to list.
- `"NextToken"`: The next item following a partial list of returned resources. For example,
  if a request is made to return maxResults number of resources, NextToken allows you to
  return more items in your list starting at the location pointed to by the next token.
"""
function list_hypervisors(; aws_config::AbstractAWSConfig=global_aws_config())
    return backup_gateway(
        "ListHypervisors"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_hypervisors(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return backup_gateway(
        "ListHypervisors", params; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end

"""
    list_tags_for_resource(resource_arn)
    list_tags_for_resource(resource_arn, params::Dict{String,<:Any})

Lists the tags applied to the resource identified by its Amazon Resource Name (ARN).

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the resource's tags to list.

"""
function list_tags_for_resource(
    ResourceArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return backup_gateway(
        "ListTagsForResource",
        Dict{String,Any}("ResourceArn" => ResourceArn);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_tags_for_resource(
    ResourceArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "ListTagsForResource",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("ResourceArn" => ResourceArn), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_virtual_machines()
    list_virtual_machines(params::Dict{String,<:Any})

Lists your virtual machines.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of virtual machines to list.
- `"NextToken"`: The next item following a partial list of returned resources. For example,
  if a request is made to return maxResults number of resources, NextToken allows you to
  return more items in your list starting at the location pointed to by the next token.
"""
function list_virtual_machines(; aws_config::AbstractAWSConfig=global_aws_config())
    return backup_gateway(
        "ListVirtualMachines"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_virtual_machines(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return backup_gateway(
        "ListVirtualMachines",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    put_maintenance_start_time(gateway_arn, hour_of_day, minute_of_hour)
    put_maintenance_start_time(gateway_arn, hour_of_day, minute_of_hour, params::Dict{String,<:Any})

Set the maintenance start time for a gateway.

# Arguments
- `gateway_arn`: The Amazon Resource Name (ARN) for the gateway, used to specify its
  maintenance start time.
- `hour_of_day`: The hour of the day to start maintenance on a gateway.
- `minute_of_hour`: The minute of the hour to start maintenance on a gateway.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DayOfMonth"`: The day of the month start maintenance on a gateway. Valid values range
  from Sunday to Saturday.
- `"DayOfWeek"`: The day of the week to start maintenance on a gateway.
"""
function put_maintenance_start_time(
    GatewayArn, HourOfDay, MinuteOfHour; aws_config::AbstractAWSConfig=global_aws_config()
)
    return backup_gateway(
        "PutMaintenanceStartTime",
        Dict{String,Any}(
            "GatewayArn" => GatewayArn,
            "HourOfDay" => HourOfDay,
            "MinuteOfHour" => MinuteOfHour,
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function put_maintenance_start_time(
    GatewayArn,
    HourOfDay,
    MinuteOfHour,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "PutMaintenanceStartTime",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "GatewayArn" => GatewayArn,
                    "HourOfDay" => HourOfDay,
                    "MinuteOfHour" => MinuteOfHour,
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    tag_resource(resource_arn, tags)
    tag_resource(resource_arn, tags, params::Dict{String,<:Any})

Tag the resource.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the resource to tag.
- `tags`: A list of tags to assign to the resource.

"""
function tag_resource(ResourceARN, Tags; aws_config::AbstractAWSConfig=global_aws_config())
    return backup_gateway(
        "TagResource",
        Dict{String,Any}("ResourceARN" => ResourceARN, "Tags" => Tags);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function tag_resource(
    ResourceARN,
    Tags,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "TagResource",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("ResourceARN" => ResourceARN, "Tags" => Tags),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    test_hypervisor_configuration(gateway_arn, host)
    test_hypervisor_configuration(gateway_arn, host, params::Dict{String,<:Any})

Tests your hypervisor configuration to validate that backup gateway can connect with the
hypervisor and its resources.

# Arguments
- `gateway_arn`: The Amazon Resource Name (ARN) of the gateway to the hypervisor to test.
- `host`: The server host of the hypervisor. This can be either an IP address or a
  fully-qualified domain name (FQDN).

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Password"`: The password for the hypervisor.
- `"Username"`: The username for the hypervisor.
"""
function test_hypervisor_configuration(
    GatewayArn, Host; aws_config::AbstractAWSConfig=global_aws_config()
)
    return backup_gateway(
        "TestHypervisorConfiguration",
        Dict{String,Any}("GatewayArn" => GatewayArn, "Host" => Host);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function test_hypervisor_configuration(
    GatewayArn,
    Host,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "TestHypervisorConfiguration",
        Dict{String,Any}(
            mergewith(
                _merge, Dict{String,Any}("GatewayArn" => GatewayArn, "Host" => Host), params
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    untag_resource(resource_arn, tag_keys)
    untag_resource(resource_arn, tag_keys, params::Dict{String,<:Any})

Removes tags from the resource.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the resource from which to remove tags.
- `tag_keys`: The list of tag keys specifying which tags to remove.

"""
function untag_resource(
    ResourceARN, TagKeys; aws_config::AbstractAWSConfig=global_aws_config()
)
    return backup_gateway(
        "UntagResource",
        Dict{String,Any}("ResourceARN" => ResourceARN, "TagKeys" => TagKeys);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function untag_resource(
    ResourceARN,
    TagKeys,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "UntagResource",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("ResourceARN" => ResourceARN, "TagKeys" => TagKeys),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    update_gateway_information(gateway_arn)
    update_gateway_information(gateway_arn, params::Dict{String,<:Any})

Updates a gateway's name. Specify which gateway to update using the Amazon Resource Name
(ARN) of the gateway in your request.

# Arguments
- `gateway_arn`: The Amazon Resource Name (ARN) of the gateway to update.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"GatewayDisplayName"`: The updated display name of the gateway.
"""
function update_gateway_information(
    GatewayArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return backup_gateway(
        "UpdateGatewayInformation",
        Dict{String,Any}("GatewayArn" => GatewayArn);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_gateway_information(
    GatewayArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "UpdateGatewayInformation",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("GatewayArn" => GatewayArn), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    update_hypervisor(hypervisor_arn)
    update_hypervisor(hypervisor_arn, params::Dict{String,<:Any})

Updates a hypervisor metadata, including its host, username, and password. Specify which
hypervisor to update using the Amazon Resource Name (ARN) of the hypervisor in your request.

# Arguments
- `hypervisor_arn`: The Amazon Resource Name (ARN) of the hypervisor to update.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Host"`: The updated host of the hypervisor. This can be either an IP address or a
  fully-qualified domain name (FQDN).
- `"Password"`: The updated password for the hypervisor.
- `"Username"`: The updated username for the hypervisor.
"""
function update_hypervisor(HypervisorArn; aws_config::AbstractAWSConfig=global_aws_config())
    return backup_gateway(
        "UpdateHypervisor",
        Dict{String,Any}("HypervisorArn" => HypervisorArn);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_hypervisor(
    HypervisorArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return backup_gateway(
        "UpdateHypervisor",
        Dict{String,Any}(
            mergewith(_merge, Dict{String,Any}("HypervisorArn" => HypervisorArn), params)
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end


text:
function (steady_state_callback::SteadyStateCallback)(du, u, mesh::AbstractMesh{3},
                                                      equations, dg::DG, cache)
  @unpack abstol, reltol = steady_state_callback

  terminate = true
  for element in eachelement(dg, cache)
    for k in eachnode(dg), j in eachnode(dg), i in eachnode(dg)
      u_local  = get_node_vars(u,  equations, dg, i, j, k, element)
      du_local = get_node_vars(du, equations, dg, i, j, k, element)
      threshold = abstol + reltol * residual_steady_state(u_local, equations)
      terminate = terminate && residual_steady_state(du_local, equations) <= threshold
    end
  end

  return terminate
end


text:
"""
    LandCoverChangeMode

Methods for randomly selecting a new land-use category.
"""
abstract type SuitabilityScore end

"""
    MaxProbability <: LandCoverChangeMode

Select from the highest probability land-use change or
the current state.
"""
struct MaxProbability <: SuitabilityScore end

# Return the category number (1..N)
score(::MaxProbability, suitabilities) = findmax(values(suitabilities))

"""
    ChangeProbabilities <: LandCoverChangeRandimisation

Choose the new land-use from the probabilities of shifting to all
possible land uses.
"""
struct ChangeProbabilities <: SuitabilityScore end

function score(::ChangeProbabilities, suitabilities::NamedTuple{K}, lc) where K
    probabilities = map(s -> s / sum(suitabilities), suitabilities)
    cumulative_probabilities = reduce(Base.tail(probabilities); init=(first(probabilities),)) do acc, x
       (acc..., x + last(acc))
    end
    return NamedVector{K}(cumulative_probabilities)
end

"""
    RawSuitabilities <: LandCoverChangeRandimisation

Choose the new land-use from the probabilities of shifting to all
possible land uses.
"""
struct RawSuitabilities <: SuitabilityScore end

score(::RawSuitabilities, suitabilities) = suitabilities

"""
    LandCoverCount{R,W} <: NeighborhoodRule
    LandCoverCount{R,W}(neighborhood, categories)

Simple rule that counts category values in the neighborhood.

- `R` must be a single `Symbol` representing the grid that holds
    `Int` land-use values
- `W` must be a single `Symbol` representing the grid to write counts to,
    with the `eltype` of `NameTuple` matching the `categories` `NameTuple`.
"""
struct LandCoverCount{R,W,N,C} <: NeighborhoodRule{R,W}
    neighborhood::N
    categories::C
end
LandCoverCount(; neighborhood=Moore(1), categories) = LandCoverCount(neighborhood, categories)
categories(rule::LandCoverCount) = rule.categories

function DynamicGrids.applyrule(data, rule::LandCoverCount, lc, I)
    _count_categories(neighborhood(rule), categories(rule))
end

function _count_categories(itr, categories)
    # The simplest method is fastest for low numbers of categories
    map(categories) do e
        count(x -> x === e, itr)
    end
end

struct LandCoverSuitability{R,W,F,P,M} <: CellRule{R,W}
    functions::F
    params::P
end
function LandCoverSuitability{R,W}(; functions, params=nothing, mode=RawSuitabilities()) where {R<:Tuple{},W}
    LandCoverSuitability{R,W}(functions, params, mode)
end

DynamicGrids.applyrule(data, rule::LandCoverSuitability, _, I) = _suitability(data, rule, I)

function _suitability(data, rule, I)
    cellparams = map(rule.params) do p
        get(data, p, I)
    end
    map(f -> f(cellparams), rule.functions)
end

"""
    LandCoverPotential{R,W} <: NeighborhoodRule
    LandCoverPotential{R,W}(suitabilities, categories,

Calculate land-use potential from the land-use categories
of the surrounding neighborhoods, and suitability parameters.
"""
struct LandCoverPotential{R<:Tuple{<:Any,<:Any},W,N,NM,SP,SF,C,I,RM} <: NeighborhoodRule{R,W}
    categories::C
    neighborhood::N
    suitability_parameters::SP
    suitability_functions::SF
    neighbor_mode::NM
    result_mode::RM
end
function LandCoverPotential(;
    categories,
    neighborhood=Moore(1),
    suitability_paremeters=nothing,
    suitability_functions=nothing,
    neighbor_mode=NeighborCount(),
    result_mode=ChangeProbabilities(),
)
    LandCoverPotential(
        categories, neighborhood, suitability_paremeters,
        suitability_functions, neighbor_mode, result_mode,
    )
end

function DynamicGrids.applyrule(data, rule::LandCoverPotential, lc, I)
    # Get auxiliary suitability data
    cell_suitabilities = _suitability(data, rule, I)
    # Count all the categories
    potential = _category_potential(rule.neigbor_mode, )
    # Compine the neighborhood-based potential
    # with the land-use suitability and pressure
    cell_potential = map(*, suitabilities, potential)

    return score(rule.mode, cell_potential)
end

abstract type NeighborhoodInfluence end
struct NeighborCount <: NeighborhoodInfluence end
struct NeighborDistance{F} <: NeighborhoodInfluence
    f::F
end
NeighborDistance() = NeighborDistance()

# Utils
function _category_potential(nd::NeighborDistance, rule)
    # This should compile away - `distances` are known at compile time
    dist_weights = map(nd.f, distances(rule))

    return map(categories) do c
        nsum = reduce(zip(neighbors(rule), dist_weights); init=zero(first(dist_weights))) do acc, (n, d)
            n === c ? acc + d : acc
        end
        nsum / length(sum(distances(rule)))
    end
end

function _category_potential(::NeighborCount, rule)
    map(_countcategories(neighborhood(rule), categories(rule))) do x
        x / length(neighborhood(rule))
    end
end

struct LandCoverChange{R<:Tuple{<:Any,<:Any},W,S,P,X} <: NeighborhoodRule{R,W}
    suitability::S
    pressure::P
    weights::X
end

function DynamicGrids.modifyrule(data, rule::LandCoverChange{<:Tuple{S,P}}) where {S,P}
    _get_thresholds(data[P], rule)
end
function _get_thresholds(A, rule::LandCoverChange{R}) where R
    # steps = map(x -> ?, rule.suitability)
    thresholds = map(x -> false, rule.suitability)
    nbelow = map(x -> 0, rule.suitability)
    while true
        counts = mapreduce((acc, xs) -> map(+, acc, xs), A) do val, cat
            val > thresholds[icategory] ? setindex(nbelow, 1, cat) : nbelow
        end
        all(map(counts, targets) do c, t
            abs(c - t) > rule.tol
        end) && break
        thresholds = map(counts, targets, thresholds, steps) do th, s
            c > t ? th + abs(s) : th - abs(s)
        end
    end

    rule = @set rule.thresholds = thresholds
    return rule
end

function DynamicGrids.applyrule(
    data, rule::LandCoverChange{R}, (state, (potential, category)), I
) where R
    # TODO add noise
    potential > rule.thresholds[category] ? category : state
end

# influences = (
#     forest = (
#         forest = 1.0,
#         cleared = 0.1,
#         urban = 0.01,
#     ),
#     cleared = (
#         forest = 0.1,
#         cleared = 1.0,
#         urban = 0.2
#     ),
#     urban = (
#         forest =
#         cleared =
#         urban = 1.0
#     ),
# )

# LandCoverSuitability(
#     params=(slope=Aux{:slope}(), river=Aux{:river}()),
#     suitability = (
#         forest=(_ -> 1.0)
#         cleared=(p ->
#         urban=(p ->
#     ),
# )

# function checkMacroDemand(thisYearsMacroDemand):
#     tot = 0
#     for luNr in thisYearsMacroDemand.keys()
#         tot += thisYearsMacroDemand[luNr]
#     end
#     return tot
# end

#function applyMacroDemand(macroDemand, year, luNrsDyn, luNrsStat, potArrs, arrLU)
#function applyMacroDemand(macroDemand, year, neighborhood, luNrsDyn, luNrsStat, potArrs, arrLU)
#    """ Make the new land use map by changing the required cells for current time step,
#    for the dynamic land uses.
#    """

#    n = 8 # neighborhood size

#    thisYearsMacroDemand = macroDemand[year]
#    #lastYearsMacroDemand = macroDemand[year-1]

#    # Make a new arr for the new land use array, where all dynamic LU are replaced by number 1.
#    newArrLU = Utils.findAndReplace(arrLU.copy(), find=luNrsDyn, replaceWith=1, within=[(n,n),(-n,-n)])

#    # Cut away the surrounding "frame" of neighborhood cells which are not supposed to be calculated.
#    for nr in potArrs.keys()
#        potArrs[nr] = potArrs[nr][n:-n, n:-n]
#        # print "max", potArrs[nr].max()
#    end
#    # This raster keeps track of which land use has been changed already so that it wont change again.
#    arrLUChange = numpy.zeros(arrLU.shape, dtype=numpy.integer) # I would like int0/unit0 here instead

#    # Iterate
#    while checkMacroDemand(thisYearsMacroDemand) > 0
#        mx = 0 # int Note! Maybe this should be initialized as None?
#        luNr = None # int
#        tempMax = None # int
#        # Get max value of all potential arrays and find out which array (LuNr) holds it
#        for tLu in potArrs.keys()
#            # If the land use demand is satisfied for one land use,
#            # then don't try to find the potential for this LU. When
#            # all LU are satisfied, the loop with stop automatically (see while-statement)
#            if thisYearsMacroDemand[tLu]<=0:
#                continue
#            tempMax = potArrs[tLu].max()
#            if tempMax > mx
#                mx = tempMax # save current max val
#                luNr = tLu # save lu (which has the highest potential)
#            end
#        if luNr == None
#            # print "Breaking when macroDemandStatus is: %i" %(checkMacroDemand(thisYearsMacroDemand))
#            break
#        end

#        # Find out the xy-location of the max value
#        #print "lu", lu, "tempMax", tempMax, "mx", mx, "luNr", luNr
#        potArr = potArrs[luNr] # get potArr for this land use
#        sortedArr = potArr.argsort() # sort it according to potential

#        rowIndex = 0
#        maxValList = []
#        for column in sortedArr # (column is an entire column (1D-array) )
#            # Get the column index which has the max value, for row nr = rowIndex
#            mxColIndex = column[-1]

#            # get the max value, of the argsorted array, for comparison with max
#            val = potArr[rowIndex, mxColIndex]

#            if val == mx: # if there is more than one max-value... choose randomly
#                maxValList.append((rowIndex, mxColIndex))
#            end
#            rowIndex+=1
#        end

#        # One (or more) locations of the max potential value found,
#        # inserted into the list maxValList. In case many values - pick a random.
#        random.shuffle(maxValList)
#        row, col = maxValList[0]
#        luRow, luCol = row+n, col+n # Add the neighborhood size to the row and col.

#        #print "maxVal=", potArr[row, col]

#        potArr[row, col] = -999 # make sure it's not again selected for land use change.

#        # Don't allow LU change if LU has already been assigned once.
#        if arrLUChange[luRow, luCol] == 1
#            continue
#        end

#        nrExistingLU = arrLU[luRow, luCol]
#        if nrExistingLU not in luNrsStat
#            # Allow land use change
#            newArrLU[luRow, luCol] = luNr
#            arrLUChange[luRow, luCol] = 1 # register as "changed"

#            # If replacing dynamic land use (which is not its own), increment the replaced LU demand by one.
#            if nrExistingLU in luNrsDyn and nrExistingLU!=luNr:
#                thisYearsMacroDemand[nrExistingLU] += 1

#            # Always decrease decrement the value when satisfying LU demand.
#            thisYearsMacroDemand[luNr] -= 1

#            # ...and decrease loop counters value by 1.
#            # If all demand satisfied for this land use (empty) - take away lu potential arr
#            # This means, it won't look for LU change potential in this array anymore.
#            #if thisYearsMacroDemand[luNr] <= 0:
#                #print "del potArrs[%i]" % luNr
#                #del potArrs[luNr]
#        else
#            # Continue, without subtracting from the demand counter - since the location of
#            # existing land use was not allowed to change
#            continue
#        end
#        #print macroDemandStatus
#    # Areas not assigned any dynamic land use gets value nr 1 - i.e. same as vacant lu.
#    return newArrLU
#end

#function makeMacroDemandDict(macroDemandNodes):
#    """ output should look like this:
#        dict = {1998 : {3 : 187, 4 : 459}, 1999 : {3 : 193, 4 : 498}}"""
#    pass
#endVery interesting.


text:
@testset "554.brick-wall.jl" begin
    @test least_bricks([
        [1, 2, 2, 1], [3, 1, 2], [1, 3, 2], [2, 4], [3, 1, 2], [1, 3, 1, 1]
    ]) == 2
    @test least_bricks([[1], [1], [1]]) == 3
end


text:
"""
LinearSystem + SingleIntegrator
"""
function LinearSystem_SingleIntegrator(args_linearsystem)
    linearsystem = LinearSystem(args_linearsystem...)
    integ = SingleIntegrator()
    linearsystem, integ
end

"""
# Notes
- `r` denotes integrand of `integ`.
"""
function State(linearsystem::LinearSystem, integ::SingleIntegrator)
    return function (x0_linearsystem, x0_integrator=[0.0])
        x_linearsystem = State(linearsystem)(x0_linearsystem)
        x_integrator = State(integ)(x0_integrator)
        ComponentArray(x=x_linearsystem, ∫r=x_integrator)
    end
end

"""
# Notes
running_cost: integrand; function of (x, u)
"""
function Dynamics!(linearsystem::LinearSystem, integ::SingleIntegrator, running_cost::Function)
    @Loggable function dynamics!(dX, X, p, t; u)
        @unpack x = X
        @nested_log :linearsystem Dynamics!(linearsystem)(dX.x, X.x, nothing, t; u=u)
        r = running_cost(x, u)
        @nested_log :integ Dynamics!(integ)(dX.∫r, X.∫r, nothing, t; u=r)
    end
end


text:
CLUST_FOR_OPT=ENV["CLUST_FOR_OPT"]
push!(LOAD_PATH, normpath(joinpath(CLUST_FOR_OPT,"src"))) #adds the location of ClustForOpt to the LOAD_PATH
using ClustForOpt
using TimeWarp # has to be before ClustForOpt
using PyPlot
 plt = PyPlot
plt.close()
# example not working, somehow input is not in correct format
# x = [1,2,2,3,3,4]
# y = [1,3,4]
# z = [1,2,2,4]
# avg,result = dba([x,y,z],ClassicDTW(),iterations=15)  # make sure to put in ClassicDTW()
# println(avg)

 ######## DATA INPUT ##########

 # region
region = "GER"

# read in original data
data_orig_daily = load_pricedata(region)
seq = data_orig_daily[:,1:365]  # do not load as sequence

println("data loaded")

## Manual data input
n_seq=365
n_clust = 3
n_init=50

##########################
# normalized clustering hourly

# optional warping window
rad_sc = 5 # sakoe chiba band radius
rmin,rmax = sakoe_chiba_band(rad_sc,24)
#rmin=[];rmax=[]

seq_norm, hourly_mean, hourly_sdv = z_normalize(data_orig_daily[:,1:n_seq],hourly=true)
tic()
results = dbaclust(seq_norm[:,1:n_seq],n_clust,n_init,ClassicDTW();iterations=100,inner_iterations=15,rtol=1e-5,show_progress=false,store_trace=false,i2min=rmin,i2max=rmax)
toc()
centers_norm = results.centers
clustids = results.clustids

centers = undo_z_normalize(seq_to_array(centers_norm),hourly_mean,hourly_sdv)

col = plt.get_cmap("Dark2")

figure()
for i=1:n_clust
  plt.plot(seq[:,clustids.==i],color=col((i-1)/(n_clust-1)),alpha=0.15)
end
for i=1:n_clust
  plt.plot(centers[:,i],label=string("clust:",i),color=col((i-1)/(n_clust-1)),linewidth=2.0)
end
#plt.plot(mean_euc,label="euclidean",color="blue")
plt.title("normalized")
plt.legend()

show()


text:
using MCMCBenchmarks,Test,Random
Random.seed!(4504)
tests = [
    "generative_model_tests",
    "Gaussian_Tests",
    "SDT_Tests",
    "Poisson_Test",
    "Regression_Tests",
    "Plot_Tests",
    #"LBA_Tests"
]

res = map(tests) do t
    @eval module $(Symbol("Test_", t))
        include($t * ".jl")
    end
end


text:
using Typeclass

@class MolecularContainer T begin
    clone(::T, new_props::Dict=Dict())::T
    obtain(::T, ::Symbol)
    features(::T)::Dict
    ==(::T, ::T)::Bool
end


text:
################################################################################
#
#  Integer functions
#
################################################################################

function next_prime(x::UInt, proof::Bool)
  z = ccall((:n_nextprime, :libflint), UInt, (UInt, Cint), x, Cint(proof))
  return z
end

function next_prime(x::Int, proof::Bool)
  z = next_prime(UInt(x), proof)
  z > typemax(Int) && error("Next prime of input is not an Int")
  return Int(z)
end

function next_prime(x::Int)
  z = next_prime(x, false)
  return z
end

function next_prime{T <: Integer}(z::T)
  z < 0 && error("Argument must be positive")

  Tone = one(z)
  Tzero = zero(z)
  Ttwo = one(z) + one(z)

  if z == Tone || z == Tzero
    return Ttwo
  end

  if iseven(z)
    z += Tone
  else z += Ttwo
  end

  while !isprime(z)
    z += Ttwo
  end

  return z
end

function next_prime(z::fmpz)
  z < 0 && error("Argument must be positive")

  Tone = one(z)
  Tzero = zero(z)
  Ttwo = one(z) + one(z)

  if z == Tone || z == Tzero
    return Ttwo
  end

  if iseven(z)
    z += Tone
  else z += Ttwo
  end

  while !isprime(z)
    Nemo.addeq!(z, Ttwo)
  end

  return z
end

# should be Bernstein'ed: this is slow for large valuations
# returns the maximal v s.th. z mod p^v == 0 and z div p^v
#   also useful if p is not prime....

function valuation{T <: Integer}(z::T, p::T)
  z == 0 && error("Not yet implemented")
  const v = 0
  while mod(z, p) == 0
    z = div(z, p)
    v += 1
  end
  return (v, z)
end

function valuation{T <: Integer}(z::Rational{T}, p::T)
  z == 0 && error("Not yet implemented")
  v, d = valuation(den(z), p)
  w, n = valuation(num(z), p)
  return w-v, n//d
end

function valuation(z::fmpz, p::fmpz)
  z == 0 && error("Not yet implemented")
  v = 0
  while mod(z, p) == 0
    z = div(z, p)
    v += 1
  end
  return v, z
end

function valuation(z::fmpq, p::fmpz)
  z == 0 && error("Not yet implemented")
  v, d = valuation(den(z), p)
  w, n = valuation(num(z), p)
  return w-v, n//d
end

valuation(z::fmpz, p::Int) = valuation(z, fmpz(p))

function *(a::fmpz, b::BigFloat)
  return BigInt(a)*b
end

function Float64(a::fmpz)
  return ccall((:fmpz_get_d, :libflint), Float64, (Ptr{fmpz},), &a)
end

function BigFloat(a::fmpq)
  r = BigFloat(0)
  ccall((:fmpq_get_mpfr, :libflint), Void, (Ptr{BigFloat}, Ptr{fmpq}, Int32), &r, &a, __get_rounding_mode())
  return r
end

function isless(a::Float64, b::fmpq) return a<b*1.0; end
function isless(a::fmpq, b::Float64) return a*1.0<b; end

function isless(a::Float64, b::fmpz) return a<b*1.0; end
function isless(a::fmpz, b::Float64) return a*1.0<b; end

function Base.call(a::FlintIntegerRing, b::fmpq)
  !isone(den(b)) && error("Denominator not 1")
  return deepcopy(num(b))
end

function //(a::fmpq, b::fmpz)
  return a//fmpq(b)
end

function //(a::fmpz, b::fmpq)
  return fmpq(a)//b
end

function *(a::fmpz, b::Float64)
  return BigInt(a)*b
end

function *(b::Float64, a::fmpz)
  return BigInt(a)*b
end

function *(a::fmpq, b::Float64)
  return Rational(a)*b
end

function *(b::Float64, a::fmpq)
  return Rational(a)*b
end

function Float64(a::fmpq)
  b = a*fmpz(2)^53
  Float64(div(num(b), den(b)))/(Float64(2)^53) #CF 2^53 is bad in 32bit
end

function convert(R::Type{Rational{Base.GMP.BigInt}}, a::Nemo.fmpz)
  return R(BigInt(a))
end

log(a::fmpz) = log(BigInt(a))
log(a::fmpq) = log(num(a)) - log(den(a))

function round(a::fmpq)
  n = num(a)
  d = den(a)
  q = div(n, d)
  r = mod(n, d)
  if r >= d//2
    return q+1
  else
    return q
  end
end

function zero(::Type{Nemo.fmpz})
  return fmpz(0)
end

function one(::Type{Nemo.fmpz})
  return fmpz(1)
end

@doc """
  modord(a::fmpz, m::fmpz) -> Int
  modord(a::Integer, m::Integer)

  The multiplicative order of a modulo m, no good algorithm.
""" ->
function modord(a::fmpz, m::fmpz)
  gcd(a,m)!=1 && throw("1st agrument not a unit")
  i = 1
  b = a % m
  while b != 1
    i += 1
    b = b*a % m
  end
  return i
end

function modord(a::Integer, m::Integer)
  gcd(a,m)!=1 && throw("1st agrument not a unit")
  i = 1
  b = a % m
  while b != 1
    i += 1
    b = b*a % m
  end
  return i
end

function isodd(a::fmpz)
  ccall((:fmpz_is_odd, :libflint), Int, (Ptr{fmpz},), &a) == 1
end

function iseven(a::fmpz)
  ccall((:fmpz_is_even, :libflint), Int, (Ptr{fmpz},), &a) == 1
end
##
## to support rand(fmpz:fmpz)....
##
# note, we cannot get a UnitRange as this is only legal for subtypes of Real

function colon(a::Int, b::fmpz)
  return fmpz(a):b
end

function one(::fmpz)
  return fmpz(1)
end

function zero(::fmpz)
  return fmpz(0)
end

#the build-in show fails due to Integer(a::fmpz) not defined
# I don't think it would efficient to provide this for printing
#display() seems to NOT call my show function, why, I don't know
function Integer(a::fmpz)
  return BigInt(a)
end

function show(io::IO, a::StepRange{fmpz, fmpz})
  println(io, "2-element ", typeof(a), ":\n ", a.start, ",", a.stop)
end

# need to be mapped onto proper Flint primitives
# flints needs a proper interface to randomness - I think
# currently one simply cannot use it at all
#
# should be tied(?) to the Julia rng stuff?
# similarly, all the derived rand functions should probably also do this
#
# inspired by/ copied from the Base/random.jl
#
function rand(rng::AbstractRNG, a::StepRange{fmpz, fmpz})
  m = Base.last(a) - Base.first(a)
  m < 0 && throw("range empty")
  nd = ndigits(m, 2)
  nl, high = divrem(nd, 8*sizeof(Base.GMP.Limb))
  if high>0
    mask = m>>(nl*8*sizeof(Base.GMP.Limb))
  end
  s = fmpz(0)
  while true
    s = fmpz(0)
    for i=1:nl
      s = s << (8*sizeof(Base.GMP.Limb))
      s += rand(Base.GMP.Limb)
    end
    if high >0
      s = s << high
      s += rand(0:Base.GMP.Limb(mask))
    end
    if s <= m break; end
  end
  return s + first(a)
end

function length(a::StepRange{fmpz, fmpz})
  return a.stop - a.start +1
end

immutable RangeGeneratorfmpz <: Base.Random.RangeGenerator
  a::StepRange{fmpz, fmpz}
end

function Base.Random.RangeGenerator(r::StepRange{fmpz,fmpz})
    m = last(r) - first(r)
    m < 0 && throw(ArgumentError("range must be non-empty"))
    return RangeGeneratorfmpz(r)
end

function rand(rng::AbstractRNG, g::RangeGeneratorfmpz)
  return rand(rng, g.a)
end

function Base.getindex(a::StepRange{fmpz,fmpz}, i::fmpz)
  a.start+(i-1)*Base.step(a)
end

function ^(x::fmpq, y::fmpz)
  if typemax(Int) > y
    return x^Int(y)
  else
    error("Not implemented (yet)")
  end
end

############################################################
# more unsafe function that Bill does not want to have....
############################################################

function divexact!(z::fmpz, x::fmpz, y::fmpz)
    y == 0 && throw(DivideError())
    ccall((:fmpz_divexact, :libflint), Void,
          (Ptr{fmpz}, Ptr{fmpz}, Ptr{fmpz}), &z, &x, &y)
    z
end

function lcm!(z::fmpz, x::fmpz, y::fmpz)
   ccall((:fmpz_lcm, :libflint), Void,
         (Ptr{fmpz}, Ptr{fmpz}, Ptr{fmpz}), &z, &x, &y)
end

function gcd!(z::fmpz, x::fmpz, y::fmpz)
   ccall((:fmpz_gcd, :libflint), Void,
         (Ptr{fmpz}, Ptr{fmpz}, Ptr{fmpz}), &z, &x, &y)
end

function inv!(a::perm)
  R = parent(a)
  ccall((:_perm_inv, :libflint), Void, (Ref{Int}, Ref{Int}, Int), a.d, a.d, R.n)
  nothing
end

################################################################################
#
#  Chinese remaindering modulo UInts to fmpz
#
################################################################################

type fmpz_comb
  primes::Ptr{UInt}
  num_primes::Int
  n::Int
  comb::Ptr{Ptr{fmpz}}
  res::Ptr{Ptr{fmpz}}
  mod_n::UInt
  mod_ninv::UInt
  mod_norm::UInt

  function fmpz_comb(primes::Array{UInt, 1})
    z = new()
    ccall((:fmpz_comb_init, :libflint), Void, (Ptr{fmpz_comb}, Ptr{UInt}, Int),
            &z, primes, length(primes))
    finalizer(z, _fmpz_comb_clear_fn)
    return z
  end
end

function _fmpz_comb_clear_fn(z::fmpz_comb)
  ccall((:fmpz_comb_clear, :libflint), Void, (Ptr{fmpz_comb}, ), &z)
end

type fmpz_comb_temp
  n::Int
  comb_temp::Ptr{Ptr{fmpz}}
  temp::Ptr{fmpz}
  temp2::Ptr{fmpz}

  function fmpz_comb_temp(comb::fmpz_comb)
    z = new()
    ccall((:fmpz_comb_temp_init, :libflint), Void,
            (Ptr{fmpz_comb_temp}, Ptr{fmpz_comb}), &z, &comb)
    finalizer(z, _fmpz_comb_temp_clear_fn)
    return z
  end
end

function _fmpz_comb_temp_clear_fn(z::fmpz_comb_temp)
  ccall((:fmpz_comb_temp_clear, :libflint), Void, (Ptr{fmpz_comb_temp}, ), &z)
end

function fmpz_multi_crt_ui!(z::fmpz, a::Array{UInt, 1}, b::fmpz_comb, c::fmpz_comb_temp)
  ccall((:fmpz_multi_CRT_ui, :libflint), Void,
          (Ptr{fmpz}, Ptr{UInt}, Ptr{fmpz_comb}, Ptr{fmpz_comb_temp}, Cint),
          &z, a, &b, &c, 1)
  return z
end

function _fmpz_preinvn_struct_clear_fn(z::fmpz_preinvn_struct)
  ccall((:fmpz_preinvn_clear, :libflint), Void, (Ptr{fmpz_preinvn_struct}, ), &z)
end

function fdiv_qr_with_preinvn!(q::fmpz, r::fmpz, g::fmpz, h::fmpz, hinv::fmpz_preinvn_struct)
  ccall((:fmpz_fdiv_qr_preinvn, :libflint), Void, (Ptr{fmpz}, Ptr{fmpz}, Ptr{fmpz}, Ptr{fmpz}, Ptr{fmpz_preinvn_struct}), &q, &r, &g, &h, &hinv)
end

function submul!(z::fmpz, x::fmpz, y::fmpz)
  ccall((:fmpz_submul, :libflint), Void, (Ptr{fmpz}, Ptr{fmpz}, Ptr{fmpz}), &z, &x, &y)
end


text:
@recipe function f(results::ABCSMCmodelresults)
    Probability = results.modelprob
    Model = map(x -> "$x", 1:length(results.modelprob))

    seriestype --> :bar
    title --> "Model Probabilities"
    yaxis --> "Probability"
    linecolor --> :white
    fillcolor --> :darkslategrey
    markerstrokecolor --> :white
    legend --> false
    grid --> false

    Model, Probability
end

@recipe function f(results::ABCrejectionmodelresults)
    Probability = results.modelfreq
    Model = map(x -> "$x", 1:length(results.modelfreq))

    seriestype --> :bar
    title --> "Model Probabilities"
    yaxis --> "Probability"
    linecolor --> :white
    fillcolor --> :darkslategrey
    markerstrokecolor --> :white
    legend --> false
    grid --> false

    Model, Probability
end

@recipe function f(results::ABCrejectionmodelresults, model = 1)
    nparams = size(results.parameters[model])[2]
    x = Array(results.parameters[model])
    seriestype --> :histogram
    nbins --> 20
    layout --> nparams
    title --> hcat(map(x -> "Parameter $x", 1:nparams)...)
    linecolor --> :white
    fillcolor --> :darkred
    markerstrokecolor --> :white
    legend --> false
    x
end

@recipe function f(results::ABCrejectionresults)
    nparams = size(results.parameters)[2]
    x = Array(results.parameters)
    seriestype --> :histogram
    nbins --> 20
    layout --> nparams
    title --> hcat(map(x -> "Parameter $x", 1:nparams)...)
    linecolor --> :white
    fillcolor --> :darkred
    markerstrokecolor --> :white
    legend --> false
    x
end

@recipe function f(results::ABCSMCmodelresults, model = 1)
    nparams = size(results.parameters[model])[2]
    x = Array(results.parameters[model])
    seriestype --> :histogram
    nbins --> 20
    layout --> nparams
    title --> hcat(map(x -> "Parameter $x", 1:nparams)...)
    linecolor --> :white
    fillcolor --> :darkred
    markerstrokecolor --> :white
    legend --> false
    weights --> results.weights[model]
    x
end

@recipe function f(results::ABCSMCresults)
    nparams = size(results.parameters)[2]
    x = Array(results.parameters)
    seriestype --> :histogram
    nbins --> 20
    layout --> nparams
    title --> hcat(map(x -> "Parameter $x", 1:nparams)...)
    linecolor --> :white
    fillcolor --> :darkred
    markerstrokecolor --> :white
    legend --> false
    weights --> results.weights
    x
end


text:
using BEAST
using CompScienceMeshes

Γ = readmesh(Pkg.dir("BEAST", "test", "assets","flatplate.in"))
RT = raviartthomas(Γ)

X = RT
Y = RT

κ = 1.0
t = Maxwell3D.singlelayer(gamma=im*κ)

BEAST.quadrule(op::BEAST.MaxwellOperator3D, g::BEAST.RTRefSpace, f::BEAST.RTRefSpace, i, τ, j, σ, qd) = BEAST.qrib(op, g, f, i, τ, j, σ, qd)
Zbogaert = assemble(t,X,Y)

BEAST.quadrule(op::BEAST.MaxwellOperator3D, g::BEAST.RTRefSpace, f::BEAST.RTRefSpace, i, τ, j, σ, qd) = BEAST.q(op, g, f, i, τ, j, σ, qd)
Zss = assemble(t,X,Y)

println(abs(Zbogaert)./abs(Zss))


text:
# Practical Machine learning
# Bayesian learning - Naive Bayes example
# Chapter 9

using Distributions

include("datastats.jl")

# Base type for Naive Bayes models.
# Inherited classes should have at least following fields:
#  c_counts::Dict{C, Int64} - count of ocurrences of each class
#  n_obs::Int64             - total number of observations
abstract NBModel{C}

#####################################
#####  Multinomial Naive Bayes  #####
#####################################

type MultinomialNB{C} <: NBModel
    c_counts::Dict{C, Int64}           # count of ocurrences of each class
    x_counts::Dict{C, Vector{Number}}  # count/sum of occurrences of each var
    x_totals::Vector{Number}           # total occurrences of each var
    n_obs::Int64                       # total number of seen observations
end

# Multinomial Naive Bayes classifier
#
# classes : array of objects
#     Class names
# n_vars : Int64
#     Number of variables in observations
# alpha : Number (optional, default 1)
#     Smoothing parameter. E.g. if alpha equals 1, each variable in each class
#     is believed to have 1 observation by default
function MultinomialNB{C}(classes::Vector{C}, n_vars::Int64; alpha=1)
    c_counts = Dict(classes, ones(Int64, length(classes)) * alpha)
    x_counts = Dict{C, Vector{Int64}}()
    for c in classes
        x_counts[c] = ones(Int64, n_vars) * alpha
    end
    x_totals = ones(Float64, n_vars) * alpha * length(c_counts)
    MultinomialNB{C}(c_counts, x_counts, x_totals, sum(x_totals))
end

function Base.show(io::IO, m::MultinomialNB)
    print(io, "MultinomialNB($(m.c_counts))")
end

#####################################
######  Gaussian Naive Bayes  #######
#####################################

type GaussianNB{C} <: NBModel
    c_counts::Dict{C, Int64}           # count of ocurrences of each class
    c_stats::Dict{C, DataStats}        # aggregative data statistics
    gaussians::Dict{C, MvNormal}        # precomputed distribution
    # x_counts::Dict{C, Vector{Number}}  # ?? count/sum of occurrences of each var
    # x_totals::Vector{Number}           # ?? total occurrences of each var
    n_obs::Int64                       # total number of seen observations
end

function GaussianNB{C}(classes::Vector{C}, n_vars::Int64)
    c_counts = Dict(classes, zeros(Int64, length(classes)))
    c_stats = Dict(classes, [DataStats(n_vars, 2) for i=1:length(classes)])
    gaussians = Dict{C, MvNormal}()
    GaussianNB{C}(c_counts, c_stats, gaussians, 0)
end

function Base.show(io::IO, m::GaussianNB)
    print(io, "GaussianNB($(m.c_counts))")
end


text:
function set_initQbase(xmax,ymax,nodes,restart_file,init_T,out_file_front,out_ext,out_dir,restart_num)
    Qbase=[]
    cellxmax = xmax - 1
    cellymax = ymax - 1

    restart_check=0
    try Qbase=setup_restart_value(cellxmax,cellymax,out_dir,restart_file)
        println("Restart "*restart_file)
        restart_check=2
    catch
        restart_check=1
    end

    if restart_check == 1
        Qbase=setup_init_value(cellxmax,cellymax,init_T)
        println("Start Initial condition")
        restart_num=0
        output_result(0,nodes,Qbase,cellxmax,cellymax,out_file_front,out_ext,out_dir)
    elseif restart_check == 0
        println("restart error")
        println("Please check restart file")
        throw(UndefVarError(:x))
    end

    return Qbase,cellxmax,cellymax,restart_num
end

function setup_init_value(cellxmax,cellymax,init_T)
    Qbase=zeros(cellxmax, cellymax)
    for i in 1:cellxmax
        for j in 1:cellymax
            Qbase[i,j]=init_T
        end
    end
    return Qbase
end

function setup_restart_value(cellxmax,cellymax,out_dir,restart_file)
    Qbase=zeros(cellxmax,cellymax)

    skipnum=1
    fff=[]
    open("result/"*restart_file, "r") do f
        fff=read(f,String)
    end
    fff=split(fff,"\n",keepempty=false)

    for i in 1+skipnum:length(fff)
        fff[i]=replace(fff[i]," \r" => "")
    end

    for i in 2:cellxmax-1
        for j in 2:cellymax-1
            temp = split(fff[i+skipnum]," ")
            Qbase[i,j] = parse(Float64,temp[1])
        end
    end
    return Qbase
end


text:
s = """
@generated function f(a,b)
    if a == 1
        :(b)
    elseif b == Int
        :(a)
    else
        :(0)
    end
end
"""

msgs = lintstr(s)
@test msgs[1].code == :W542
@test contains(msgs[1].message, "incompatible types (#1)")

# if it is not a staged function, it would have no lint message
s = """
@generated function f(x)
    :(x+y)
end
"""
msgs = lintstr(s)
@test_broken msgs[1].code == :I371
@test_broken contains(msgs[1].message, "use of undeclared symbol")

s = """
@generated function f(args::Int...)
    @lintpragma("Info type args")
    x = args[1]
    @lintpragma("Info type x")
    :(show(x, args...))
end
"""
msgs = lintstr(s)
@test msgs[1].code == :I271
@test contains(msgs[1].message, "typeof(args) == Tuple{Vararg{Type")
@test msgs[2].code == :I271
@test contains(msgs[2].message, "typeof(x) == ")


text:
@testset "dotproduct" begin
    A = rand(10, 5)
    B = rand(20, 5)
    d = KernelFunctions.DotProduct()
    @test diag(pairwise(d, A; dims=2)) == [dot(A[:, i], A[:, i]) for i in 1:size(A, 2)]
    @test_throws DimensionMismatch d(rand(3), rand(4))
    @test d(3.0, 2.0) == 6.0
end


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

using Markdown
using InteractiveUtils

# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
    quote
        local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
        el
    end
end

# ╔═╡ fbd777b9-1cb3-4d78-93c5-eae75c01b5dd
import HypertextLiteral

# ╔═╡ 80ffb0fa-1a23-4af6-968d-c02b641f5e6d
import Test

# ╔═╡ f00356a7-cadd-4363-8769-a2b0e3373ebc
import PlutoUI: Slider

# ╔═╡ db2e67d8-7172-484e-ac91-85fd611326e6
md"---"

# ╔═╡ 33eaf9ec-3da2-11ec-3db2-3ff3f1ba309a
module PlutoTestWrapper include("../src/PlutoTest.jl") end

# ╔═╡ db6dce9e-3cc0-4fce-8cb9-d0fb2d07cb62
import .PlutoTestWrapper.PlutoTest: PlutoTest, @test

# ╔═╡ f9bdd61c-475c-4f17-8ccb-e7f85e7471a2
md"---"

# ╔═╡ 6220f755-4082-4362-b3fa-1107beee2739
module ModuleName
	function FunctionName()
		true
	end
end

# ╔═╡ 8f64cdc1-77c2-401b-8d05-7b7cbc388f81
@test ModuleName.FunctionName()

# ╔═╡ 72244046-9b53-4953-8cc7-906279c7b4c8
x = [1,3]

# ╔═╡ d162b047-4c3a-4d91-9b97-210e51842996
@test x == [1,2+2]

# ╔═╡ 90b0b055-2dd1-4b28-a869-ec3a9b853b83
@test missing == 2

# ╔═╡ 7660f123-1064-4869-9cfd-997ec4a12974
@test call(10, 20)

# ╔═╡ 0114b7be-36ac-4bbe-b52c-9d54742c7c91
@test 2+2 == 2+2

# ╔═╡ 5743b872-da02-4922-ae01-2e328a8cd3aa
@test rand(50) == [rand(50),2]

# ╔═╡ 20639058-4c4c-4380-a22c-dc15c4259542
macro test_that_throws(expr)
	# esc(..) used like this (around the whole expression)
	# is not something you'll usually see... but it's something @test needs now
	esc(quote
		result = @test $(expr)
		if result isa PlutoTest.Fail
			throw(result)
		end
		result
	end)
end

# ╔═╡ 182669e9-7dd0-44f7-957a-e7f461be2d8c
function increment(counter)
	counter[] = counter[] + 1
	nothing
end

# ╔═╡ 48bed8b7-374b-445e-a13b-ef291a7d0887
result = begin
	counter = Ref(0)
	@test begin
		@test_that_throws counter[] ^ 2 == 0
		increment(counter)
		@test_that_throws counter[] ^ 2 == 3
		increment(counter)
		@test_that_throws counter[] ^ 2 == 9
	end
end

# ╔═╡ d25f42f1-08eb-4852-8162-fe4f28497f4a
let x = 1
	@test :($(x) + 1) == :(1 + 1)
end

# ╔═╡ 9209719e-532f-4206-b2f8-eacd58a84d21
@bind howmuch Slider(0:100)

# ╔═╡ 6f619fbf-80a6-42b0-ab4f-9da28bc77970
@test isless(2+2,1)

# ╔═╡ b5d95cce-a4fa-4c86-8547-9ea25a9837c0
@test isless(1,2+2)

# ╔═╡ 9366cb04-476b-4bac-85fe-db64ccc4047a
@bind n Slider(1:10)

# ╔═╡ 4e8e065e-474d-45b3-9310-13a36521acd7
@test iseven(n^2)

# ╔═╡ e3993b93-dc70-4337-a98e-6fab7132a3b8
@bind k Slider(0:15)

# ╔═╡ ab1737e2-ee22-41d1-b63c-70da6c94facf
@test 4+4 ∈ [1:k...]

# ╔═╡ f03c135b-07f0-4783-97f9-d1a08e86a892
@test isempty((1:k) .^ 2)

# ╔═╡ 1fb3abd8-e49e-40da-848c-b81b1ff0dac3
@test isempty([1,sqrt(2)])

# ╔═╡ ed8170b3-3ef4-469f-aa5c-9ed240ed0e0b
begin
	i = 8
	@test sqrt(i) < 3
end

# ╔═╡ 4d8207ab-363d-4cb3-bf96-fe9c95482047
@test 1 ∈ [sqrt(20), 5:9...]

# ╔═╡ 1d4fd6d3-77d3-438c-8809-4388f23cd94e
@test 1 ∈ rand(60)

# ╔═╡ a16f12ea-0205-4a2b-94d9-0aa680358e4b
@test rand(60) ∋ 1

# ╔═╡ 3ea68a01-6022-437c-b9bf-0b4e34b80c2d
# Fons wtf
always_false(args...; kwargs...) = true

# ╔═╡ a82718bb-effa-4c93-9ef2-3985417e8820
@test always_false(rand(howmuch), rand(howmuch),123)

# ╔═╡ f7631f63-5942-4462-bac7-836119058a23
@test always_false(rand(2), rand(2),123)

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
HypertextLiteral = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[compat]
HypertextLiteral = "~0.9.2"
PlutoUI = "~0.7.18"
"""

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

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

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

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

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

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

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

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

[[HypertextLiteral]]
git-tree-sha1 = "5efcf53d798efede8fee5b2c8b09284be359bf24"
uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
version = "0.9.2"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

# ╔═╡ Cell order:
# ╠═fbd777b9-1cb3-4d78-93c5-eae75c01b5dd
# ╠═80ffb0fa-1a23-4af6-968d-c02b641f5e6d
# ╠═f00356a7-cadd-4363-8769-a2b0e3373ebc
# ╟─db2e67d8-7172-484e-ac91-85fd611326e6
# ╠═33eaf9ec-3da2-11ec-3db2-3ff3f1ba309a
# ╠═db6dce9e-3cc0-4fce-8cb9-d0fb2d07cb62
# ╟─f9bdd61c-475c-4f17-8ccb-e7f85e7471a2
# ╠═6220f755-4082-4362-b3fa-1107beee2739
# ╠═8f64cdc1-77c2-401b-8d05-7b7cbc388f81
# ╠═72244046-9b53-4953-8cc7-906279c7b4c8
# ╠═d162b047-4c3a-4d91-9b97-210e51842996
# ╠═90b0b055-2dd1-4b28-a869-ec3a9b853b83
# ╠═7660f123-1064-4869-9cfd-997ec4a12974
# ╠═0114b7be-36ac-4bbe-b52c-9d54742c7c91
# ╠═5743b872-da02-4922-ae01-2e328a8cd3aa
# ╠═a82718bb-effa-4c93-9ef2-3985417e8820
# ╠═20639058-4c4c-4380-a22c-dc15c4259542
# ╠═182669e9-7dd0-44f7-957a-e7f461be2d8c
# ╠═48bed8b7-374b-445e-a13b-ef291a7d0887
# ╠═d25f42f1-08eb-4852-8162-fe4f28497f4a
# ╠═9209719e-532f-4206-b2f8-eacd58a84d21
# ╠═f7631f63-5942-4462-bac7-836119058a23
# ╠═6f619fbf-80a6-42b0-ab4f-9da28bc77970
# ╠═b5d95cce-a4fa-4c86-8547-9ea25a9837c0
# ╠═9366cb04-476b-4bac-85fe-db64ccc4047a
# ╠═4e8e065e-474d-45b3-9310-13a36521acd7
# ╠═e3993b93-dc70-4337-a98e-6fab7132a3b8
# ╠═ab1737e2-ee22-41d1-b63c-70da6c94facf
# ╠═f03c135b-07f0-4783-97f9-d1a08e86a892
# ╠═1fb3abd8-e49e-40da-848c-b81b1ff0dac3
# ╠═ed8170b3-3ef4-469f-aa5c-9ed240ed0e0b
# ╠═4d8207ab-363d-4cb3-bf96-fe9c95482047
# ╠═1d4fd6d3-77d3-438c-8809-4388f23cd94e
# ╠═a16f12ea-0205-4a2b-94d9-0aa680358e4b
# ╠═3ea68a01-6022-437c-b9bf-0b4e34b80c2d
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
using TerminalUserInterfaces
const TUI = TerminalUserInterfaces
using Random

function main()
    TUI.initialize()
    y, x = 1, 1

    count = 1
    t = TUI.Terminal()

    TUI.clear_screen()
    TUI.hide_cursor()

    while true

        w, h = TUI.terminal_size()

        p = TUI.Grid(
            block = TUI.Block(title = "Grid"),
            data = [
                    1 2 3
                    4 5 6
                    7 8 9
                   ],
            cell_height = 6,
            cell_width = 6,
        )

        r = TUI.Rect(x, y, w, h)

        TUI.draw(t, p, r)

        TUI.flush(t)

        c = TUI.get_event(t)

        if c == 'j'
            count += 1
        elseif c == 'k'
            count -= 1
        elseif c == 'q'
            break
        end

        if count < 1
            count = 1
        end

    end

    TUI.cleanup()

end

main()