text:
for i in 2:2:8
    print(i, ", ")
end
println("whom do we appreciate?")

ext: jl

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
##=========common head===============
using HMRowUnification
using Sequent
using MLStyle

@nospecialize
ImD = Base.ImmutableDict
struct Store{K, O}
    unbox :: ImD{K, O}
end

# given σ ∈ Store{K, O} where K, O
# 'σ[k => v]' add a scoped pair k=>v and returns a new store
# where the old one is not affected.
function Store{K, O}() where {K, O}
    Store(ImD{K, O}())
end
Base.getindex(s::Store{K, O}, x::Pair{K, A}...) where {K, O, A<:O} =
    let im = s.unbox
        for each in x
            im = ImD(im, each)
        end
        Store(im)
    end
Base.getindex(s::Store{K, O}, x::K) where {K, O} = s.unbox[x]
##===========auxiliaries==================
@active T(x) begin
    @match x begin
        App(Nom(:Type), x) => Some(x)
        _ => nothing
    end
end

(::Type{T})(x::HMT) = App(Nom(:Type), x)
(f::HMT)(arg::HMT) = App(f, arg)
(a::HMT) ↦ (r::HMT) = Arrow(a, r)

σ₀ = Store{Symbol, HMT}()[
    :int => T(Nom(:int)),
    :str => T(Nom(:str))
]

@data List{A} begin
    Nil{A} :: () => List{A}
    Cons{A} :: (A, List{A}) => List{A}
end

# from vector to List
function fromVec(x::AbstractVector{A}) where A
    a = Nil{A}()
    for i in eachindex(x)
        i = reverseind(x, i)
        e = x[i]
        a = Cons(e, a)
    end
    a
end

# from List to Expr(:block, ...)
function toBlock(x::List)
    r = Expr(:block)
    while true
        @switch x begin
        @case Nil()
            return r
        @case Cons(h, x)
            push!(r.args, h)
            continue
        end
    end
end
# Define a pattern to handle unzip
#
# @match [(1, :a), (2, :b)]
#    Unzip{Int, Symbol}(ints, syms) => (ints, syms)
#
# => Int[1, 2], Symbol[:a, :b]
@active Unzip{A, B}(x) begin
    fsts = A[]
    snds = B[]
    for field in x
        @switch field begin
            @case (a, b)
            push!(fsts, a)
            push!(snds, b)
            continue

            @case _
            return nothing
        end
    end
    return (fsts, snds)
end

##================semantics===============

# ⊢ₑ does expression judgement, returns (expr, type)
er_sym = @sequent ESYM begin
    (TC, σ) ⊢ₑ e::Symbol =>
        let t = σ[e]
            :($e :: $t), t
        end
end

er_app = @sequent EAPP begin
    (TC, σ) ⊢ₑ f => (ef, tf)
    # 'a = b' performs pattern matching
    # 'a' is the pattern
    tf′ = TC.instantiate(TC.prune(tf))
    # 'Ctx ⊢ ManyOut .=> ManyOut' apply the rule to a sequence of inputs
    (TC, σ) ⊢ₑ args .=> Unzip{Any, HMT}(aexps, ats)
    tret =
        let ats = [TC.instantiate(TC.prune(a)) for a in ats]
            ats = length(ats) == 1 ? ats[1] : Tup(Tuple(ats))
            targ = TC.new_tvar()
            tret = TC.new_tvar()
            TC.unify(targ ↦ tret, tf′)
            TC.unify(targ, ats)
            tret
        end
    (TC, σ) ⊢ₑ Expr(:call, f, args...) =>
        (:($ef($(aexps...)) :: $tret), tret)
end

er_fun = @sequent ELAM begin
    true = all(args) do e; e isa Symbol end
    bindings = [p => TC.new_tvar() for p in args]
    (TC, σ[bindings...]) ⊢ₛ  body => (lst, t)
    (TC, σ) ⊢ₑ Expr(:function, arg && Expr(:tuple, args...), body) =>
        begin
            argtypes = [it.second for it in bindings]
            if length(argtypes) == 1
                argtype = argtypes[1]
            else
                argtype = Tup(Tuple(argtypes))
            end

            Expr(:function, arg, toBlock(lst)), (argtype ↦ t)
        end

end

const Lit = Union{AbstractString, Number}

er_lit = @sequent ELIT begin
    (TC, σ) ⊢ₑ e::Lit =>
        let t =
            if e isa AbstractString
                Nom(:str)
            elseif e isa Integer
                Nom(:int)
            elseif e isa AbstractFloat
                Nom(:float)
            else
                error("unknown")
            end
            :($e :: $t), t
        end
end

sr_let = @sequent SLET begin
    E = Tup(Tuple(TC.tctx))
    (TC, σ) ⊢ₑ exp => (exp′, texp)
    FV = collect(setdiff(ftv(TC.prune(texp)), ftv(TC.prune(E))))
    tbind =
        isempty(FV) ?
        texp :
        let vs = map(FV) do i
                v = Symbol("'a", i)
                TC.unify(Var(Refvar(i)), Fresh(v))
                v
            end
            Forall(Tuple(vs), texp)
        end

    (TC, σ[e => tbind]) ⊢ₛ tl => (tl′, ttl)
    (TC, σ) ⊢ₛ Cons(:($(e::Symbol) = $exp), tl) =>
        (Cons(:($e :: $tbind = $exp′), tl′), ttl)
end

sr_ret = @sequent SReturn begin
    (TC, σ) ⊢ₑ hd => (hd′, thd)
    (TC, σ) ⊢ₛ Cons(hd, Nil()) =>
        (Cons(hd′, Nil{Any}()), thd)
end

sr_b1 = @sequent SB1 begin
    (TC, σ) ⊢ₛ fromVec(stmts) => res
    (TC, σ) ⊢ₛ Expr(:block, stmts...) => res
end

sr_b2 = @sequent SB2 begin
    (TC, σ) ⊢ₛ tl => (res, res_t)
    (TC, σ) ⊢ₛ Cons(ln::LineNumberNode, tl) => (Cons(ln, res), res_t)
end

sr_act = @sequent SAction begin
    (TC, σ) ⊢ₑ hd => (hd′, _)
    (TC, σ) ⊢ₛ tl => (tl′, ttl)
    (TC, σ) ⊢ₛ Cons(hd, tl) =>
        (Cons(hd′, tl′), ttl)
end

@semantics [
    er_sym,
    er_app,
    er_fun,
    er_lit,
    sr_b1,
    sr_b2,
    sr_ret,
    sr_let,
    sr_act
]

##===========execution============
ts = HMT[]
TC = mk_tcstate(ts)
ex, t = ((TC, σ₀) ⊢ₛ quote
    x = function (x, y)
        x
    end
    x(1, (function(x) x end)(1))
end)

@info :inferred_type TC.prune(t)
println("generate implicitly typed code:")

prune_ex!(ex) =
    @switch ex begin
    @case Expr(:(::), a, b)
        prune_ex!(a)
        ex.args[2] = TC.prune(b)
        nothing
    @case Expr(_, exprs...)
        foreach(prune_ex!, exprs)
    @case _
        nothing
    end

ex = toBlock(ex)
prune_ex!(ex)
ex |> println
#=
┌ Info: inferred_type
└   TC.prune(t) = int
generate implicitly typed code:
begin
    #= /home/tainez/github/SequentExamples/HM.jl:221 =#
    x::forall ##a2#7610 ##a1#7611.{##a1#7611, ##a2#7610}->##a1#7611 = function (x, y)
            #= /home/tainez/github/SequentExamples/HM.jl:221 =#
            #= /home/tainez/github/SequentExamples/HM.jl:222 =#
            x::##a1#7611
        end
    #= /home/tainez/github/SequentExamples/HM.jl:224 =#
    (x::forall ##a2#7610 ##a1#7611.{##a1#7611, ##a2#7610}->##a1#7611)(1::int, (function (x,)
                    #= /home/tainez/github/SequentExamples/HM.jl:224 =#
                    #= /home/tainez/github/SequentExamples/HM.jl:224 =#
                    x::int
                end)(1::int)::int)::int
end
=#


text:
@testset "Mesh" begin
    # Need some Nodes
    node1 = Node{2}(1,   Vec{2}((2.3, 4.5)), [1,7,9], invalid_processor_id)
    node3 = Node{2}(3,   Vec{2}((2.3, 4.5)), [1,7,9], invalid_processor_id)
    node13 = Node{2}(13, Vec{2}((2.3, 4.5)), [1,7,9], invalid_processor_id)
    node18 = Node{2}(18, Vec{2}((2.3, 4.5)), [1,7,9], invalid_processor_id)
    node21 = Node{2}(21,   Vec{2}((2.3, 4.5)), [1,7,9], invalid_processor_id)
    node23 = Node{2}(23,   Vec{2}((2.3, 4.5)), [1,7,9], invalid_processor_id)

    # Test Full Construction
    element = Element(11, [node1, node3, node13, node18], [12,17,81], invalid_processor_id)
    element2 = Element(12, [node1, node3, node21, node23], [212,217,281], invalid_processor_id)

    # Create a Mesh
    mesh = Mesh((Node)[node1, node3, node13, node18, node21, node23], [element, element2])

    initialize!(mesh)

    @test mesh.nodes[2].id == 3
    @test mesh.elements[2].id == 12

    @test mesh.node_to_elem_map[3] == [element, element2]
end


text:
# TODO: update
# TODO: averaging

"""
`@knet function par(; dims, init, opts...)` creates a parameter array
of size `dims` which should be a tuple of Ints.  Some entries in dims
can be left as 0, in which case they will be inferred from the input.
`init` can be an Array, CudaArray, or a subtype of Rgen (please see
the Rgen doc).  Other `opts` include:

    * lr
    * l1reg
    * l2reg
    * adagrad
    * momentum
    * nesterov
    * average
"""
type Par <: Op; dims; init; initialized; out; dif; lr; l1reg; l2reg; adagrad; ada; momentum; mom; nesterov; nes; average; avg;
    Par(;o...)=setopt!(new(); initialized=false, o...)
end

Kenv.kdef(:par,Par)

function setopt!(p::Par; o...)
    for (n,v) in o
        if in(n, fieldnames(p))
            p.(n)=v
        else
            # This happens regularly when binit gets passed to wdot etc.
            # Base.warn_once("setopt!: ignoring unrecognized option $n")
        end
    end
    p
end

function infersize(p::Par,ysize)
    psize = (isdefined(p,:init) && isa(p.init, BaseArray) ? size(p.init) :
             isdefined(p,:dims) ? p.dims : nothing)
    psize == nothing && return tuple(ysize)
    ysize == nothing && return tuple(psize)
    length(psize) == length(ysize) || throw(DimensionMismatch())
    dims = map(psize, ysize) do pi,yi
        pi==yi ? pi :
        pi==0  ? yi :
        yi==0  ? pi :
        throw(DimensionMismatch())
    end
    tuple(dims)
end

ninputs(::Par)=0
canoverwrite(::Par)=false
back_reads_x(::Par)=false
back_reads_y(::Par)=false

function back(p::Par, dy; y=nothing, o...)
    p.dif == nothing && (p.dif = dy)
    dy === p.dif || Base.warn_once("dy=$dy p.dif=$(p.dif)")
    y == nothing || y === p.out || Base.warn_once("y=$y p.out=$(p.out)")
end

function forw(p::Par, y; o...)
    if !p.initialized
        if !isdefined(p, :init)
            rgen!(Gaussian(0,0.01), y)
        elseif isa(p.init, BaseArray)
            copysync!(y, p.init)
        else
            rgen!(p.init, y)
        end
        p.out = y
        p.dims = size(y)
        p.dif = nothing
        p.initialized = true
    end
    @assert p.out === y "p.out=$(p.out) y=$y"
    return p.out
end

function Base.isequal(a::Par,b::Par)
    for n in fieldnames(a)
        if isdefined(a,n) && isdefined(b,n)
            isequal(a.(n), b.(n)) || return false
        elseif isdefined(a,n) || isdefined(b,n)
            return false
        end
    end
    return true
end

### DEAD CODE

# BASIC ARRAY OPS:

# for fname in (:eltype, :length, :ndims, :size, :strides, :pointer, :isempty, :vecnorm)
#     @eval (Base.$fname)(a::Par)=$fname(a.arr)
# end

# for fname in (:size, :stride)
#     @eval (Base.$fname)(a::Par,n)=$fname(a.arr,n)
# end

# # atype{A}(::Par{A})=A
# diff(a::Par)=a.diff
# difnorm(a::Par)=(isdefined(a,:diff) ? vecnorm(a.diff) : 0)

# DEPRECATED:
# update!(::Nothing;o...)=nothing
# setopt!(::Nothing;o...)=nothing
# initdiff(w::Par; fill=nothing, o...)=(similar!(w, :diff, w.arr); fillsync!=nothing && fillsync!(w.diff,fill); w)

# We need to fix cpu/gpu copy so the type changes appropriately:

# copy(x::Par)=deepcopy(x)

# function cpucopy_internal{A<:CudaArray,T,N}(x::Par{A,T,N},d::ObjectIdDict)
#     haskey(d,x) && return d[x]
#     y = Par{Array,T,N}()
#     for n in fieldnames(x)
#         isdefined(x,n) || continue
#         y.(n) = cpucopy_internal(x.(n),d)
#     end
#     d[x] = y
# end

# function gpucopy_internal{A<:Array,T,N}(x::Par{A,T,N},d::ObjectIdDict)
#     haskey(d,x) && return d[x]
#     y = Par{CudaArray,T,N}()
#     for n in fieldnames(x)
#         isdefined(x,n) || continue
#         y.(n) = gpucopy_internal(x.(n),d)
#     end
#     d[x] = y
# end

# convert{A<:BaseArray}(::Type{A}, a::Par)=convert(A, a.arr)
# convert{A<:BaseArray}(::Type{Par}, a::A)=Par(a)

# TODO: both weights and training parameters are called param; setopt! vs params is confusing
# Probably should rename this back to Param after moving others to DynamicArray.
# How does caffe deal with this problem?

# Par(w; o...)=init(setopt!(Par{atype(w),eltype(w),ndims(w)}(); arr=w, o...))
# Par{A,T}(::Type{A}, ::Type{T}, d::Dims; o...)=Par(A(T,d); o...)
# Par{A,T}(::Type{A}, ::Type{T}, d1::Int, d::Int...; o...)=Par(A,T,tuple(d1,d...); o...)
# Par{T}(::Type{T}, d::Dims; o...)=Par((gpu()?CudaArray:Array),T,d; o...)
# Par{T}(::Type{T}, d::Int...; o...)=Par(T, d; o...)
# Par(d::Int...; o...)=Par(Float64, d; o...)

# TODO: create an rgen type: makes things serializable
# function init(p::Par, T::DataType=eltype(p), d::Dims=size(p.arr))
#     (size(p.arr)==d && eltype(p.arr)==T) || (p.arr = similar(p.arr, T, d))
#     # we want no init if params given in matrix
#     if !isempty(p.arr) && nz(p,:init,nothing)
#         initp = (!isdefined(p,:initp) ? () :
#                  isa(p.initp,Tuple) ? p.initp :
#                  (p.initp,))
#         p.init(p.arr, initp...)
#     end
#     return p
# end

# Base.isequal:
    # typeof(a) == typeof(b) || return false
    # size(a) == size(b) || return false

# DONE: back
# DONE: going back we should not zero the incremental dif!

# Use the dims option instead of:
# par(i::Integer, d::Integer...; o...)=par(; dims=(i,d...), o...)

# Use init=w for array initialization.
# par(w::AbstractArray, y; o...)=par(y; out0=w, dims=size(w), o...)

# """
# Rgen is an abstract type whose subtypes represent random distributions
# for parameter initialization.  Currently implemented subtypes are listed
# below.  They are used to specify initialization during Net construction.

#     * Gaussian(mean, std)
#     * Uniform(min, max)
#     * Constant(val)
#     * Identity(scale)
#     * Xavier()
# """
# abstract Rgen
# type Gaussian <: Rgen; mean; std; end
# type Uniform  <: Rgen; min; max; end
# type Constant <: Rgen; val; end
# type Identity <: Rgen; val; Identity(x=1)=new(x); end
# type Xavier <: Rgen; end

# par(y; o...)=(setopt!(Par(); initialized=false, o...), y)


text:
"""
From Reynolds (2020) (Eq2-4)
Calculates the radius of the inner most stable circular orbit of the a black hole,
with spin a_star, and mass M.
"""
function r_isco(a_star, M)
    a = a_star
    r_g = M
    z1 = 1 + ∛(1 - a^2) * (∛(1 + a) + ∛(1 - a))
    z2 = √(3 * a^2 + z1^2)
    if a >= 0
        r_isco = (3 + z2 - √((3 - z1) * (3 + z1 + 2 * z2))) * r_g
    elseif a < 0
        r_isco = (3 + z2 + √((3 - z1) * (3 + z1 + 2 * z2))) * r_g
    end
end

"""
From Page & Thorne (1974) (Eq15n)
Calculates the function f at radius r, for a black hole of spin a_star, and mass M,
which is used to calculate the flux given by its accretion disk.
"""
function flux(r, a_star, M)
    R_isco = r_isco(a_star, M)
    x = √(r / M)
    x0 = √(R_isco / M)
    x1 = 2 * cos((1 / 3) * (acos(a_star)) - (π / 3))
    x2 = 2 * cos((1 / 3) * (acos(a_star)) + (π / 3))
    x3 = -2 * cos((1 / 3) * (acos(a_star)))

    flux =
        (3 / (2 * M)) *
        (1 / (x^2 * (x^3 - (3 * x) + (2 * a_star)))) *
        (
            x - x0 - ((3 / 2) * a_star * log(x / x0)) -
            (3 * (x1 - a_star)^2) / (x1 * (x1 - x2) * (x1 - x3)) *
            log((x - x1) / (x0 - x1)) -
            (3 * (x2 - a_star)^2) / (x2 * (x2 - x1) * (x2 - x3)) *
            log((x - x2) / (x0 - x2)) -
            (3 * (x3 - a_star)^2) / (x3 * (x3 - x1) * (x3 - x2)) *
            log((x - x3) / (x0 - x3))
        )
end

function mdot(M)
    # need something here to convert M into SI units, as M_☼ is in SI, althought we
    # aren't currently clear about what the units M currently is in
    # would look something like:
    # M_kg = M*c^2
    # L_edd = 3e4*L_☼*(M_kg/M_☼)

    L_edd = 3e4 * L_☼ * (M / M_☼)
    Mdot = -L_edd / (c^2 * η)
    mdot = -0.1 * Mdot
end

function diss(mdot, r, a_star, M)
    diss = ((c^6) / (G^2)) * mdot * flux(r, a_star, M) / (4 * π * r)
end

function temperature(r, a_star, M)
    m_dot = mdot(M)
    temperature = (diss(m_dot, r, a_star, M) / σ_SB)^(1 / 4)
end

"""
From Fanton et al. (1997) (Eq78)
"""
function observed_temperature(r, a_star, M, g)
    T = temperature(r, a_star, M)
    observed_temperature = g * T
end

function mass_scale_fraction(M, η, edd_ratio, r_isco, r_g, r)
    mass_scale_fraction =
        ((M * η)^(-1) * (edd_ratio * (1 - √(r_isco / r))) * (r_g / r)^3)^(1 / 4)
end

# constants
G = 6.67e-11
c = 3e8
L_☼ = 3.8e26
M_☼ = 1.99e30
σ_SB = 5.67e-8
η = 0.1

export observed_temperature, r_isco, temperature, mass_scale_fraction


text:
## reading and writing these files

# copy the workbook into the relevant folder so it's up-to-date
"""
    updatefiles(jwl)

Write the JWL workbook `jwl.wb` to `jwl.folder`, ensuring that the JWL file is up-to-date.
"""
function updatefiles(jwl::JWL)
    for (sname, S) in jwl.wb.sheets
        sheetloc = joinpath(jwl.folder, sname * ".csv")
        t = Tables.table(array(S,formula))
        CSV.write(sheetloc, t; header=false)
    end
end

# write the workbook as a .jwl file somewhere
"""
    write(jwl[, targetfolder, overwrite])

Copies the JWL workbook to `targetfolder` as a `.jwl` file.
By default, `overwrite = true`.
"""
function write(jwl::JWL, targetfolder::String=tempdir(), overwrite=true)
    location = joinpath(targetfolder, jwl.name * ".jwl")
    overwrite || @assert !isfile(location) ("File exists already, and overwrite is set to `false`!")
    w = ZipFile.Writer(location)
    for (sname, S) in jwl.wb.sheets # sheet name, Sheet
        f = ZipFile.addfile(w, sname * ".csv")
        Base.write(f,sprint(show, "text/csv", array(S,formula)))
    end
    for x in ("include.jl", "Project.toml", "Manifest.toml")
        p = joinpath(jwl.folder,x)
        if isfile(p)
            f = ZipFile.addfile(w, x)
            Base.write(f, Base.read(p,String))
        end
    end
    ZipFile.close(w)
end

# read a .jwl file as a JWL
"""
    read(filename[, folder])

Reads a `.jwl` file and returns a JWL.
"""
read(filename::String,folder::String=tempdir()) = readabs(joinpath(folder,filename))
function readabs(filelocation::String)
    name = replace(basename(filelocation),".jwl" => "")
    targetpath = joinpath(tempdir(),name)
    isdir(targetpath) || mkdir(targetpath)

    # turn zipped jwl file into temporary location
    # r = ZipFile.Reader(filelocation)
    iobuffer = IOBuffer(Base.read(filelocation,String)) # workaround to no method matching `seekend` on ZipFile.ReadableFile
    r = ZipFile.Reader(iobuffer)
    for f in r.files
        Base.write(joinpath(targetpath,f.name), Base.read(f)) # this assumes that there are no folders in the folder
    end
    close(r)

    # start the environment
    Pkg.activate(targetpath) # ?
    # include `include.jl`, if any
    pinc = joinpath(targetpath,"include.jl")
    isfile(pinc) && include(pinc)

    # import sheets
    wb = Workbook()
    isCSV(f) = f[end-3:end] == ".csv"
    for f in filter(isCSV,readdir(targetpath))
        filepath = joinpath(targetpath,f)
        sheetname = basename(f)[1:end-4]
        addSheet(wb, sheetname, DelimitedFiles.readdlm(filepath,','))
    end

    JWL(name, targetpath, wb)
end

"""
    addSheet(wb, name, formulas)

Given an array `formulas`, it creates a new sheet named `name` in the workbook `wb`.
(It partially overwrites any existing sheet with the same `name`.)
"""
function addSheet(wb::Workbook, name::String, formulas::Matrix{Any})
    S = wb[name]
    for i in axes(formulas,1), j in axes(formulas,2)
        f = formulas[i,j]
        f == "missing" || (S[i,j] = string(f))
    end
end


text:
## BEFORE REMOVING `write_mccs!`:
## Check whether it's used in annotating auspice json files
# """
#     write_mccs!(trees::Dict, MCCs::Dict, key=:mcc_id)

# Write MCCs id to field `data.dat[key]` of tree nodes. Expect `trees` indexed by single segments, and `MCCs` indexed by pairs of segments.
# """
# function write_mccs!(trees::Dict, MCCs::Dict, key=:mcc_id; overwrite=false)
#     for ((i,j), mccs) in MCCs
#         k = Symbol(key,"_$(i)_$(j)")
#         write_mccs!(trees[i], mccs, k, overwrite=overwrite)
#         write_mccs!(trees[j], mccs, k, overwrite=overwrite)
#     end
# end
# """
#     write_mccs!(t::Tree, MCCs, key=:mcc_id)

# Write MCCs id to field `data.dat[key]` of tree nodes.
# """
# function write_mccs!(t::Tree{TreeTools.MiscData}, MCCs, key=:mcc_id; overwrite=false)
#     for (i,mcc) in enumerate(MCCs)
#         for label in mcc
#             t.lleaves[label].data.dat[key] = i
#         end
#         for n in Iterators.filter(n->!n.isleaf, values(t.lnodes))
#             if is_branch_in_mcc(n, mcc)
#                 if !overwrite && haskey(n.data.dat, key)
#                     error("Node $(n.label) already has an MCC attributed")
#                 end
#                 n.data.dat[key] = i
#             end
#         end
#     end
#     nothing
# end

"""
    is_branch_in_mccs(n::TreeNode, mccs::Array)

Is the branch from `n` to `n.anc` in an element of `mccs`?
"""
function is_branch_in_mccs(n::TreeNode, mccs::Dict)
    for mcc in values(mccs)
        if is_branch_in_mcc(n, mcc)
            return true
        end
    end
    return false
end
function is_branch_in_mccs(n::TreeNode, mccs)
    for mcc in mccs
        if is_branch_in_mcc(n, mcc)
            return true
        end
    end
    return false
end

"""
    is_branch_in_mcc(n::TreeNode, mcc::Array{<:AbstractString})

Is the branch from `n` to `n.anc` in `mcc`?
The clade defined by `n` has to intersect with `mcc`, and this intersection should be strictly smaller `mcc`.
"""
function is_branch_in_mcc(n::TreeNode, mcc::Array{<:AbstractString,1})
    # Simple check
    if n.isleaf
        return length(mcc) > 1 && in(n.label, mcc)
    end

    i = count(c -> c.isleaf && in(c.label, mcc), n)

    return (i > 0 && i < length(mcc))
end
"""
    find_mcc_with_branch(n::TreeNode, mccs::Dict)

Find the mcc to which the branch from `n` to `n.anc` belongs. If `mccs` is an array, return the pair `(index, value)`. If it is a dictionary, return the pair `(key, value)`. If no such mcc exists, return `nothing`.
Based on the same idea that `is_branch_in_mcc`.
"""
function find_mcc_with_branch(n::TreeNode, mccs::Dict)
    cl = [x.label for x in POTleaves(n)]
    for (key,mcc) in mccs
        if !isempty(intersect(cl, mcc)) && !isempty(setdiff(mcc, intersect(cl, mcc)))
            return (key, mcc)
        end
    end
    return nothing
end
function find_mcc_with_branch(n::TreeNode, mccs::Array)
    cl = [x.label for x in POTleaves(n)]
    for (i,mcc) in enumerate(mccs)
        if !isempty(intersect(cl, mcc)) && !isempty(setdiff(mcc, intersect(cl, mcc)))
            return (i,mcc)
        end
    end
    return nothing
end

"""
    is_linked_pair(n1, n2, mccs)
    is_linked_pair(n1::T, n2::T, mccs::Dict{Any,Array{T,1}}) where T
    is_linked_pair(n1::T, n2::T, mccs::Array{Array{T,1},1}) where T

Can I join `n1` and `n2` through common branches only? Equivalent to: is there an `m` in `mccs` such that `in(n1,m) && in(n2,m)`?
"""
function is_linked_pair(n1::T, n2::T, mccs::Dict{Any,Array{T,1}}) where T
    for mcc in values(mccs)
        if in(n1, mcc)
            return in(n2, mcc)
        elseif in(n2, mcc)
            return false
        end
    end
    return false
end
function is_linked_pair(n1, n2, mccs)
    for mcc in values(mccs)
        if in(n1, mcc)
            return in(n2, mcc)
        elseif in(n2, mcc)
            return false
        end
    end
    return false
end
function is_linked_pair(n1::T, n2::T, mccs::Array{Array{T,1},1}) where T
    for mcc in mccs
        if in(n1, mcc)
            return in(n2, mcc)
        elseif in(n2, mcc)
            return false
        end
    end
    return false
end

"""
    find_mcc_with_node(n::String, mccs::Array{Array{<:AbstractString,1},1})

Find MCC to which `n` belongs.
"""
function find_mcc_with_node(n::String, mccs)
    for m in mccs
        if in(n, m)
            return m
        end
    end
    return nothing
end
find_mcc_with_node(n::TreeNode, mccs) = find_mcc_with_node(n.label, mccs)
find_mcc_with_node(n, mccs) = find_mcc_with_node(n.label, mccs)

max_stars_repo_name: PierreBarrat/RecombTools

max_issues_repo_name: PierreBarrat/RecombTools

max_forks_repo_name: PierreBarrat/RecombTools


text:
### Parsing utilities

include("lib/result.jl")

macro chk1(expr,label=:error)
    quote
        x = $(esc(expr))
        if isnull(x[1])
            @goto $label
        else
           x[1].value, x[2]
        end
    end
end

macro chk2(expr,label=:error)
    @assert expr.head == :(=)
    lhs, rhs = expr.args

    @assert lhs.head == :tuple
    res, state = lhs.args
    quote
        x = $(esc(rhs))
        $(esc(state)) = x[2] # bubble error location
        if isnull(x[1])
            @goto $label
        else
            $(esc(res)) = x[1].value
        end
    end
end

@inline function tryparsenext_base10_digit(T,str,i, len)
    R = Nullable{T}
    i > len && @goto error
    @inbounds c,ii = next(str,i)
    '0' <= c <= '9' || @goto error
    return R(c-'0'), ii

    @label error
    return R(), i
end

@inline function tryparsenext_base10(T, str,i,len)
    R = Nullable{T}
    @chk2 r, i = tryparsenext_base10_digit(T,str,i, len)
    ten = T(10)
    while true
        @chk2 d, i = tryparsenext_base10_digit(T,str,i,len) done
        r = r*ten + d
    end
    @label done
    return R(r), i

    @label error
    return R(), i
end

@inline function tryparsenext_sign(str, i, len)
    R = Nullable{Int}
    i > len && return R(), i
    c, ii = next(str, i)
    if c == '-'
        return R(-1), ii
    elseif c == '+'
        return R(1), ii
    else
        return (R(1), i)
    end
end

@inline function isspace(c::Char)
    c == ' '
end

@inline function isnewline(c::Char)
    c == '\n' || c == '\r'
end

@inline function eatwhitespaces(str, i=1, l=endof(str))
    while i <= l
        c, ii = next(str, i)
        if isspace(c)
            i=ii
        else
            break
        end
    end
    return i
end

function eatnewlines(str, i=1, l=endof(str))
    count = 0
    while i<=l
        c, ii = next(str, i)
        if c == '\r'
            i=ii
            if i <= l
                @inbounds c, ii = next(str, i)
                if c == '\n'
                    i=ii
                end
            end
            count += 1
        elseif c == '\n'
            i=ii
            if i <= l
                @inbounds c, ii = next(str, i)
                if c == '\r'
                    i=ii
                end
            end
            count += 1
        else
            break
        end
    end

    return i, count
end

function stripquotes(x)
    x[1] in ('\'', '"') && x[1] == x[end] ?
        strip(x, x[1]) : x
end

function getlineend(str, i=1, l=endof(str))
    while i<=l
        c, ii = next(str, i)
        isnewline(c) && break
        i = ii
    end

    return i-1
end

### Testing helpers

unwrap(xs) = (get(xs[1]), xs[2:end]...)
failedat(xs) = (@assert isnull(xs[1]); xs[2])

# String speedup hacks

# StrRange
# This type is the beginning of a hack to avoid allocating 3 objects
# instead of just 1 when using the `tryparsenext` framework.
# The expression (Nullable{String}("xyz"), 4) asks the GC to track
# the string, the nullable and the tuple. Instead we return
# (Nullable{StrRange}(StrRange(0,3)), 4) which makes 0 allocations.
# later when assigning the column inside `tryparsesetindex` we
# create the string. See `setcell!`
immutable StrRange
    offset::Int
    length::Int
end

# PooledArrays for string data
using PooledArrays

_pointer(x::String, n) = pointer(x, n)

@inline function nonallocating_setindex!{T}(pa::PooledArray{T}, i, rng::StrRange, str::AbstractString)
    # wstr = WeakRefString(_pointer(str, 1+rng.offset), rng.length)
    wstr = str[(1:rng.length) + rng.offset] # so now it is allocating
    pool_idx = searchsortedfirst(pa.pool, wstr)
    if pool_idx > length(pa.pool) || pa.pool[pool_idx] != wstr
        # allocate only here.
        val = convert(T,alloc_string(str, rng))
        pool_idx = PooledArrays.unsafe_pool_push!(pa, val)
    end

    pa.refs[i] = pool_idx
end

function getlineat(str, i)
    ii = prevind(str, i)
    line_start = i
    l = endof(str)
    while ii > 0 && !isnewline(str[ii])
        line_start = ii
        ii = prevind(str, line_start)
    end

    c, ii = next(str, line_start)
    line_end = line_start
    while !isnewline(c) && ii <= l
        line_end = ii
        c, ii = next(str, ii)
    end

    line_start:line_end
end

_widen(::Type{UInt8}) = UInt16 # fix for bad Base behavior
_widen(::Type{Int8}) = Int16
_widen(T) = widen(T)


text:
# TODO: follow RMarkdown convention more
const _DEFAULT_PARAMS = Dict{Symbol,Any}(
    :echo => true,
    :results => "markup",
    :hold => false,
    :fig => true,
    :eval => true,
    :error => true,
    :tangle => true,
    :cache => false,
    :fig_cap => nothing,
    # NOTE: size in inches
    :fig_width => 6,
    :fig_height => 4,
    :fig_path => DEFAULT_FIG_PATH,
    :dpi => 96,
    :term => false,
    :prompt => "julia>",
    :label => nothing,
    :wrap => true,
    :line_width => 75,
    :fig_ext => nothing,
    :fig_pos => nothing,
    :fig_env => nothing,
    :out_width => nothing,
    :out_height => nothing,
    :print => false,
)
const DEFAULT_PARAMS = deepcopy(_DEFAULT_PARAMS) # might be changed at runtime

"""
    set_chunk_defaults!(k, v)
    set_chunk_defaults!(kv::Pair...)
    set_chunk_defaults!(opts::AbstractDict)

Set default options for code chunks, use [`get_chunk_defaults`](@ref) to see the current values.

E.g.: all the three examples below will set default `dpi` to `200` and `fig_width` to `8`:
- `set_chunk_defaults!(:dpi, 200); set_chunk_defaults!(:fig_width, 8)`
- `set_chunk_defaults!(:dpi => 200, :fig_width => 8)`
- `set_chunk_defaults!(Dict(:dpi => 200, :fig_width => 8))`
"""
set_chunk_defaults!(k, v) = DEFAULT_PARAMS[k]= v
set_chunk_defaults!(kv::Pair...) = for (k,v) in kv; set_chunk_defaults!(k, v); end
set_chunk_defaults!(opts::AbstractDict) = merge!(DEFAULT_PARAMS, opts)

"""
    get_chunk_defaults()

Get default options used for code chunks.
"""
get_chunk_defaults() = DEFAULT_PARAMS

"""
    restore_chunk_defaults!()

Restore Weave.jl default chunk options.
"""
restore_chunk_defaults!() = for (k,v) in _DEFAULT_PARAMS; DEFAULT_PARAMS[k] = v; end


text:
# ---
# title: 502. IPO
# id: problem502
# author: Tian Jun
# date: 2020-10-31
# difficulty: Hard
# categories: Heap, Greedy
# link: <https://leetcode.com/problems/ipo/description/>
# hidden: true
# ---
#
# Suppose LeetCode will start its IPO soon. In order to sell a good price of its
# shares to Venture Capital, LeetCode would like to work on some projects to
# increase its capital before the IPO. Since it has limited resources, it can
# only finish at most **k** distinct projects before the IPO. Help LeetCode
# design the best way to maximize its total capital after finishing at most
# **k** distinct projects.
#
# You are given several projects. For each project **i** , it has a pure profit
# **P i** and a minimum capital of **C i** is needed to start the corresponding
# project. Initially, you have **W** capital. When you finish a project, you
# will obtain its pure profit and the profit will be added to your total
# capital.
#
# To sum up, pick a list of at most **k** distinct projects from given projects
# to maximize your final capital, and output your final maximized capital.
#
# **Example 1:**
#
#
#
#     Input: k=2, W=0, Profits=[1,2,3], Capital=[0,1,1].
#
#     Output: 4
#
#     Explanation: Since your initial capital is 0, you can only start the project indexed 0.
#                  After finishing it you will obtain profit 1 and your capital becomes 1.
#                  With capital 1, you can either start the project indexed 1 or the project indexed 2.
#                  Since you can choose at most 2 projects, you need to finish the project indexed 2 to get the maximum capital.
#                  Therefore, output the final maximized capital, which is 0 + 1 + 3 = 4.
#
#
# **Note:**
#
#   1. You may assume all numbers in the input are non-negative integers.
#   2. The length of Profits array and Capital array will not exceed 50,000.
#   3. The answer is guaranteed to fit in a 32-bit signed integer.
#
#
## @lc code=start
using LeetCode

## add your code here:
## @lc code=end


text:
## 04.jl
# 元素記号

str = "Hi He Lied Because Boron Could Not Oxidize Fluorine.
 New Nations Might Also Sign Peace Security Clause. Arthur King Can."
dic = Dict()
single = [1, 5, 6, 7, 8, 9, 15, 16, 19]
for (i,word) in enumerate(split(str," "))
  if i in single; dic[word[1]] = i
  else; dic[word[1:2]] = i ; end
end
println(dic)


text:
## Direct calls

function adjoint_sensitivities_u0(sol,args...;
                                  sensealg=InterpolatingAdjoint(),
                                  kwargs...)
  _adjoint_sensitivities_u0(sol,sensealg,args...;kwargs...)
end

function _adjoint_sensitivities_u0(sol,sensealg,alg,g,t=nothing,dg=nothing;
                                   checkpoints=sol.t,kwargs...)
  adj_prob = ODEAdjointProblem(sol,sensealg,g,t,dg,checkpoints=checkpoints)
  adj_sol = solve(adj_prob,alg;kwargs...,
                  save_everystep=false,save_start=false,saveat=eltype(sol[1])[])

  -adj_sol[end][1:length(sol.prob.u0)],
    adj_sol[end][(1:length(sol.prob.p)) .+ length(sol.prob.u0)]'
end

function adjoint_sensitivities(sol,args...;
                               sensealg=InterpolatingAdjoint(),
                               kwargs...)
  _adjoint_sensitivities(sol,sensealg,args...;kwargs...)
end

function _adjoint_sensitivities(sol,sensealg,alg,g,t=nothing,dg=nothing;
                               abstol=1e-6,reltol=1e-3,
                               iabstol=abstol, ireltol=reltol,
                               checkpoints=sol.t,
                               kwargs...)
  adj_prob = ODEAdjointProblem(sol,sensealg,g,t,dg,checkpoints=checkpoints)
  adj_sol = solve(adj_prob,alg;abstol=abstol,reltol=reltol,
                               save_everystep=false,save_start=false,kwargs...)
  adj_sol[end][(1:length(sol.prob.p)) .+ length(sol.prob.u0)]'
end

### Common utils

function generate_callbacks(sensefun, g, λ, t, callback, init_cb)
  if sensefun.discrete
    @unpack sensealg, y, sol = sensefun
    prob = sol.prob
    cur_time = Ref(length(t))
    function time_choice(integrator)
      cur_time[] > 0 ? t[cur_time[]] : nothing
    end
    affect! = let isq = (sensealg isa QuadratureAdjoint), λ=λ, t=t, y=y, cur_time=cur_time, idx=length(prob.u0)
      function (integrator)
        p, u = integrator.p, integrator.u
        λ  = isq ? λ : @view(λ[1:idx])
        g(λ,y,p,t[cur_time[]],cur_time[])
        if isq
          u .+= λ
        else
          u = @view u[1:idx]
          u .= λ .+ @view integrator.u[1:idx]
        end
        u_modified!(integrator,true)
        cur_time[] -= 1
      end
    end
    cb = IterativeCallback(time_choice,affect!,eltype(prob.tspan);initial_affect=init_cb)

    _cb = CallbackSet(cb,callback)
  else
    _cb = callback
  end
  return _cb
end


text:
export AbstractData, Data, evaluate, FourierMetaData

abstract type AbstractData end
struct Data{𝒯, 𝒟} <: AbstractData
    data::𝒯
end

function Base.show(io::IO, d::Data)
    printstyled(io, d.data, color = 199)
end

for unary_operator in unary_operators
    b_symbol = Meta.parse.(unary_operator[2]) #broadcast
    @eval $b_symbol(field1::AbstractData) where {𝒯} = Data(broadcast($b_symbol, field1.data))
end

for binary_operator in [binary_operators..., ["Negative", "-"]]
    b_symbol = Meta.parse.(binary_operator[2]) #broadcast
    @eval $b_symbol(field1::AbstractData, field2::AbstractData) = Data(broadcast($b_symbol, field1.data, field2.data))
    @eval $b_symbol(field1::AbstractData, field2::𝒮) where {𝒮} =  Data(broadcast($b_symbol,field1.data, field2))
    @eval $b_symbol(field1::𝒯, field2::AbstractData) where {𝒯} =  Data(broadcast($b_symbol, field1, field2.data))
    # otherwise there is a method error, data wrapper makes it a closed system
    #@eval $b_symbol(field1::AbstractData, field2::𝒮) where {𝒮 <: Number} = Data(broadcast($b_symbol,field1.data, field2))
    #@eval $b_symbol(field1::𝒯, field2::AbstractData) where {𝒯 <: Number} = Data(broadcast($b_symbol, field1, field2.data))
end

# Define evaluation functions
compute(d::AbstractData) = d
evaluate(a::AbstractExpression) = compute(a).data

max_stars_repo_name: upiterbarg/QuasiGeostrophy

max_issues_repo_name: upiterbarg/QuasiGeostrophy

max_forks_repo_name: upiterbarg/QuasiGeostrophy


text:
println("==============flag! BnBTree.jl======================================")

include("table_log.jl")
include("bb_inits_and_defaults.jl")
include("bb_strategies.jl")
include("bb_user_limits.jl")
include("bb_type_correct.jl")
include("bb_integral_or_branch.jl")
include("bb_gains.jl")

"""
    get_branching_disc_idx!(m, step_obj, opts, disc2var_idx, gains, counter::Int64=1)

Get the index of a variable to branch on.
"""
function get_branching_disc_idx!(m, step_obj, opts, disc2var_idx, gains, counter::Int64=1)
    start = time()
    node = step_obj.node
    idx = 0
    strong_restarts = 0
    branch_strat = opts.branch_strategy
    status = :Normal
    if branch_strat == :MostInfeasible
        idx = branch_mostinfeasible(m, node, disc2var_idx)
        step_obj.branch_strategy = :MostInfeasible
    elseif branch_strat == :PseudoCost || branch_strat == :StrongPseudoCost
        if counter == 1 && branch_strat == :PseudoCost
            idx = branch_mostinfeasible(m, node, disc2var_idx)
            step_obj.branch_strategy = :MostInfeasible
        elseif counter <= opts.strong_branching_nsteps && branch_strat == :StrongPseudoCost
            status, idx, strong_restarts = branch_strong!(m, opts, disc2var_idx, step_obj, counter)
            step_obj.branch_strategy = :Strong
        else
            idx = branch_pseudo(m, node, disc2var_idx, gains, opts.gain_mu, opts.atol)
            step_obj.branch_strategy = :Pseudo
        end
    elseif branch_strat == :Reliability
        status, idx, strong_restarts = branch_reliable!(m,opts,step_obj,disc2var_idx,gains,counter)
        step_obj.branch_strategy = :Reliability
    end
    step_obj.state = status
    step_obj.var_idx = idx
    step_obj.nrestarts = strong_restarts
    step_obj.idx_time = time()-start
    return
end

"""
    process_node!(m, step_obj, cnode, disc2var_idx, temp)

Solve a child node `cnode` by relaxation.
Set the state and best_bound property.
Push integrals and new branch nodes to the step object
Return state
"""
function process_node!(m, step_obj, cnode, disc2var_idx, temp; restarts=0)
     # set bounds
    for i=1:m.num_var
        JuMP.set_lower_bound(m.x[i], cnode.l_var[i])
        JuMP.set_upper_bound(m.x[i], cnode.u_var[i])
    end
    if restarts > 0
        println("Doing one restart")
        restart_values = generate_random_restart(m)
        JuMP.set_start_value.(m.x[1:m.num_var], restart_values)
    else
        JuMP.set_start_value.(m.x[1:m.num_var], step_obj.node.solution)
    end

    old_mu_init = set_subsolver_option!(m, m.model, "nl", "Ipopt", "mu_init", 0.1 => 1e-5)

    status, backend = optimize_get_status_backend(m.model)

    # reset mu_init
    reset_subsolver_option!(m, "nl", "Ipopt", "mu_init", old_mu_init)

    objval = NaN
    cnode.solution = fill(NaN, m.num_var)
    if state_is_optimal(status; allow_almost=m.options.allow_almost_solved)
        objval = JuMP.objective_value(m.model)
        cnode.solution = JuMP.value.(m.x)
    end

    cnode.relaxation_state = status
    if !state_is_optimal(status; allow_almost=m.options.allow_almost_solved) && !state_is_infeasible(status)
        cnode.state = :Error
    elseif state_is_optimal(status; allow_almost=m.options.allow_almost_solved)
        cnode.best_bound = objval
        set_cnode_state!(cnode, m, step_obj, disc2var_idx)
        if only_almost_solved(status) && (!(cnode.state == :Integral) || m.options.allow_almost_solved_integral)
            @warn "Only almost solved"
        end

        # if almost_solved_integral is not allowed but it is integral => restart and hope for the best
        if cnode.state == :Integral && only_almost_solved(status) && !m.options.allow_almost_solved_integral
            if restarts >= 1
                cnode.state = :Almost_Solved
                Base.finalize(backend)
                return cnode.state
            else
                return process_node!(m, step_obj, cnode, disc2var_idx, temp; restarts=restarts+1)
            end
        end
        if !temp
            push_integral_or_branch!(step_obj, cnode)
        end
    else
        cnode.state = :Infeasible
    end
    Base.finalize(backend)
    return cnode.state
end

"""
    branch!(m, opts, step_obj, counter, disc2var_idx; temp=false)

Branch a node by using x[idx] <= floor(x[idx]) and x[idx] >= ceil(x[idx])
Solve both nodes and set current node state to done.
"""
function branch!(m, opts, step_obj, counter, disc2var_idx; temp=false)
    ps = opts.log_levels
    node = step_obj.node
    vidx = step_obj.var_idx

    start = time()
    # it might be already branched on
    if !temp && node.state != :Branch
        for cnode in [step_obj.l_nd,step_obj.r_nd]
            if cnode.state == :Branch || cnode.state == :Integral
                push_integral_or_branch!(step_obj, cnode)
            end
        end
        return step_obj.l_nd,step_obj.r_nd
    end

    l_nd_u_var = copy(node.u_var)
    r_nd_l_var = copy(node.l_var)
    l_nd_u_var[vidx] = floor(node.solution[vidx])
    r_nd_l_var[vidx] = ceil(node.solution[vidx])

    if opts.debug
        path_l = copy(node.path)
        path_r = copy(node.path)
        push!(path_l,node.hash)
        push!(path_r,node.hash)
    else
        path_l = []
        path_r = []
    end
    l_nd = new_left_node(node, l_nd_u_var; path=path_l)
    r_nd = new_right_node(node, r_nd_l_var; path=path_r)

    # save that this node branches on this particular variable
    node.var_idx = vidx

    check_print(ps,[:All,:FuncCall]) && println("branch")

    if !temp
        step_obj.l_nd = l_nd
        step_obj.r_nd = r_nd
        node.state = :Done
    end

    start_process = time()
    l_state = process_node!(m, step_obj, l_nd, disc2var_idx, temp)
    r_state = process_node!(m, step_obj, r_nd, disc2var_idx, temp)
    node_time = time() - start_process

    if !temp
        step_obj.node_branch_time += node_time
    end

    branch_strat = opts.branch_strategy

    if check_print(ps,[:All])
        println("State of left node: ", l_state)
        println("State of right node: ", r_state)
        println("l sol: ", l_nd.solution)
        println("r sol: ", r_nd.solution)
    end

    if !temp
        step_obj.branch_time += time()-start
    end

    return l_nd,r_nd
end

"""
    update_incumbent!(tree::BnBTreeObj, node::BnBNode)

Gets called if new integral solution was found.
Check whether it's a new incumbent and update if necessary
"""
function update_incumbent!(tree::BnBTreeObj, node::BnBNode)
    ps = tree.options.log_levels
    check_print(ps,[:All,:FuncCall]) && println("update_incumbent")

    factor = tree.obj_fac
    if !isdefined(tree,:incumbent) || factor*node.best_bound > factor*tree.incumbent.objval
        objval = node.best_bound
        solution = copy(node.solution)
        status = node.relaxation_state
        @assert(state_is_optimal(status; allow_almost=false) || (only_almost_solved(status) && tree.options.allow_almost_solved_integral))
        tree.incumbent = Incumbent(objval, solution, only_almost_solved(status))
        if !tree.options.all_solutions
            bound!(tree)
        end
        return true
    end

    return false
end

"""
    bound!(tree::BnBTreeObj)
"""
function bound!(tree::BnBTreeObj)
    function isbetter(n)
        return f*n.best_bound > f*incumbent_val
    end
    incumbent_val = tree.incumbent.objval
    f = tree.obj_fac
    filter!(isbetter, tree.branch_nodes)
end

"""
    add_incumbent_constr(m, incumbent)

Add a constraint >=/<= incumbent
"""
function add_incumbent_constr(m, incumbent)
    add_obj_constraint(m, incumbent.objval)
end

"""
    add_obj_epsilon_constr(tree)

Add a constraint obj ≦ (1+ϵ)*LB or obj ≧ (1-ϵ)*UB
"""
function add_obj_epsilon_constr(tree)
    # add constr for objval
    if tree.options.obj_epsilon > 0
        ϵ = tree.options.obj_epsilon
        if tree.m.obj_sense == :Min
            rhs = (1+ϵ)*tree.m.relaxation_objval
        else
            rhs = (1-ϵ)*tree.m.relaxation_objval
        end
        add_obj_constraint(tree.m, rhs)
        tree.m.ncuts += 1
    end
end

"""
    get_next_branch_node!(tree)

Get the next branch node (sorted by best bound)
Return true,step_obj if there is a branch node and
false, nothing otherwise
"""
function get_next_branch_node!(tree)
    if length(tree.branch_nodes) == 0
        return false, false, nothing
    end
    bvalue, nidx = findmax([tree.obj_fac*n.best_bound for n in tree.branch_nodes])

    trav_strat = tree.options.traverse_strategy
    if trav_strat == :BFS
        # use the one with highest depth
        _value, nidx = findmax([if isapprox(tree.obj_fac*n.best_bound, bvalue) n.level else -Inf end for n in tree.branch_nodes])
    end

    if trav_strat == :DFS || (trav_strat == :DBFS && !isdefined(tree,:incumbent))
        _value, nidx = findmax([n.level for n in tree.branch_nodes])
    end

    tree.best_bound = tree.obj_fac*bvalue
    bbreak = isbreak_mip_gap(tree)
    if bbreak
        return false, true, nothing
    end

    node = tree.branch_nodes[nidx]
    deleteat!(tree.branch_nodes, nidx)

    return true, false, new_default_step_obj(tree.m,node)
end

"""
    one_branch_step!(m1, incumbent, opts, step_obj, disc2var_idx, gains, counter)

Get a branch variable using the specified strategy and branch on the node in step_obj
using that variable. Return the new updated step_obj
"""
function one_branch_step!(m1, incumbent, opts, step_obj, disc2var_idx, gains, counter)
    if m1 === nothing
        global m
        global is_newincumbent
        if opts.incumbent_constr && incumbent !== nothing && is_newincumbent
            is_newincumbent = false
            add_incumbent_constr(m, incumbent)
        end
    else
        m = m1
    end

    node = step_obj.node
    step_obj.counter = counter

# get branch variable
    node_idx_start = time()
    get_branching_disc_idx!(m, step_obj, opts, disc2var_idx, gains, counter)
    step_obj.node_idx_time = time()-node_idx_start
    # if no variable got selected might be true that all variables are already type correct
    # node.solution can be updated if one child is infeasible and the other optimal (can result in discrete)
    if step_obj.var_idx == 0 && are_type_correct(step_obj.node.solution, m.var_type, disc2var_idx, opts.atol)
        push!(step_obj.integral, node)
    else
        if step_obj.state != :Infeasible && step_obj.state != :PartlyInfeasible
            @assert step_obj.var_idx != 0
            branch!(m, opts, step_obj, counter, disc2var_idx)
        end
    end
    return step_obj
end

"""
    upd_time_obj!(time_obj, step_obj)

Add step_obj times to time_obj
"""
function upd_time_obj!(time_obj, step_obj)
    time_obj.solve_leaves_get_idx += step_obj.node_idx_time
    time_obj.solve_leaves_branch += step_obj.node_branch_time
    time_obj.branch += step_obj.branch_time
    time_obj.get_idx += step_obj.idx_time
    time_obj.upd_gains += step_obj.upd_gains_time
end

"""
    upd_tree_obj!(tree, step_obj, time_obj)

Update the tree obj like new incumbent or new branch nodes using the step_obj
Return true if it's the end of the algorithm (checking different break rules)
"""
function upd_tree_obj!(tree, step_obj, time_obj)
    node = step_obj.node
    still_running = true

    if step_obj.node.level+1 > tree.m.nlevels
        tree.m.nlevels = step_obj.node.level+1
    end

    if step_obj.state == :Infeasible
        # if there is no incumbent yet
        if !isdefined(tree,:incumbent)
            # this can be locally infeasible or globally infeasible depending on the solver
            tree.limit = :Infeasible
        end # it will terminate and use the current solution as optimal (might want to rerun as an option)
        still_running = false
    end

    if still_running
        upd_gains_step!(tree, step_obj)
    end

    bbreak = upd_integral_branch!(tree, step_obj)
    if bbreak
        still_running = false
    end

    upd_time_obj!(time_obj, step_obj)
    return !still_running
end

"""
    solve_sequential(tree,
        last_table_arr,
        time_bnb_solve_start,
        fields,
        field_chars,
        time_obj)

Run branch and bound on a single processor
"""
function solve_sequential(tree,
    last_table_arr,
    time_bnb_solve_start,
    fields,
    field_chars,
    time_obj)

    m = tree.m
    opts = tree.options
    disc2var_idx = tree.disc2var_idx
    counter = 0
    ps = tree.options.log_levels

    dictTree = Dict{Any,Any}()
    while true
        # the _ is only needed for parallel
        exists, _, step_obj = get_next_branch_node!(tree)
        !exists && break
        isbreak_after_step!(tree) && break
        counter += 1
        if isdefined(tree,:incumbent)
            step_obj = one_branch_step!(m, tree.incumbent, opts, step_obj, disc2var_idx, tree.obj_gain, counter)
        else
            step_obj = one_branch_step!(m, nothing, opts, step_obj, disc2var_idx, tree.obj_gain, counter)
        end
        m.nnodes += 2 # two nodes explored per branch
        node = step_obj.node

        bbreak = upd_tree_obj!(tree,step_obj,time_obj)
        tree.options.debug && (dictTree = push_step2treeDict!(dictTree,step_obj))

        if check_print(ps,[:Table])
            last_table_arr = print_table(1,tree,node,step_obj,time_bnb_solve_start,fields,field_chars;last_arr=last_table_arr)
        end

        if bbreak
            break
        end
    end

    tree.options.debug && (tree.m.debugDict[:tree] = dictTree)
    return counter
end

function sendto(p::Int; args...)
    for (nm, val) in args
        remotecall_fetch(Core.eval, p, Juniper, Expr(:(=), nm, val))
    end
end

function dummysolve()
    global m
    optimize!(m.model)
end

"""
    pmap(f, tree, last_table_arr, time_bnb_solve_start,
        fields, field_chars, time_obj)

Run the solving steps on several processors
"""
function pmap(f, tree, last_table_arr, time_bnb_solve_start,
    fields, field_chars, time_obj)
    np = nprocs()  # determine the number of processes available
    if tree.options.processors+1 < np
        np = tree.options.processors+1
    end

    # function to produce the next work item from the queue.
    # in this case it's just an index.
    ps = tree.options.log_levels
    still_running = true
    run_counter = 0
    counter = 0

    for p=2:np
        seed = Random.seed!
        remotecall_fetch(seed, p, 1)
    end
    @sync begin
        for p=2:np
            @async begin
                sendto(p, m=tree.m)
                sendto(p, is_newincumbent=false)
            end
        end
    end

    for p=3:np
        remotecall(dummysolve, p)
    end

    proc_counter = zeros(np)

    dictTree = Dict{Any,Any}()

    branch_strat = tree.options.branch_strategy
    opts = tree.options
    @sync begin
        for p=1:np
            if p != myid() || np == 1
                @async begin
                    while true
                        exists, bbreak, step_obj = get_next_branch_node!(tree)
                        if bbreak
                            still_running = false
                            break
                        end

                        while !exists && still_running
                            sleep(0.1)
                            exists, bbreak, step_obj = get_next_branch_node!(tree)
                            exists && break
                            if bbreak
                                still_running = false
                                break
                            end
                        end
                        !still_running && break

                        if isbreak_after_step!(tree)
                            still_running = false
                            break
                        end

                        run_counter += 1
                        counter += 1
                        if isdefined(tree,:incumbent)
                            step_obj = remotecall_fetch(f, p, nothing, tree.incumbent, tree.options, step_obj,
                                                        tree.disc2var_idx, tree.obj_gain, counter)
                        else
                            step_obj = remotecall_fetch(f, p, nothing, nothing, tree.options, step_obj,
                            tree.disc2var_idx, tree.obj_gain, counter)
                        end
                        tree.m.nnodes += 2 # two nodes explored per branch
                        run_counter -= 1

                        !still_running && break

                        bbreak = upd_tree_obj!(tree,step_obj,time_obj)
                        tree.options.debug && (dictTree = push_step2treeDict!(dictTree,step_obj))

                        if run_counter == 0 && length(tree.branch_nodes) == 0
                            still_running = false
                        end

                        bbreak && (still_running = false)

                        if check_print(ps,[:Table])
                            if length(tree.branch_nodes) > 0
                                bvalue, nidx = findmax([tree.obj_fac*n.best_bound for n in tree.branch_nodes])
                                tree.best_bound = tree.obj_fac*bvalue
                            end
                            last_table_arr = print_table(p,tree,step_obj.node,step_obj,time_bnb_solve_start,fields,field_chars;last_arr=last_table_arr)
                        end

                        !still_running && break
                    end
                end
            end
        end
    end
    tree.options.debug && (tree.m.debugDict[:tree] = dictTree)
    return counter
end

"""
    solvemip(tree::BnBTreeObj)

Solve the MIP part of a problem given by BnBTreeObj using branch and bound.
 - Identify the node to branch on
 - Get variable to branch on
 - Solve subproblems
"""
function solvemip(tree::BnBTreeObj)
    time_obj = init_time_obj()
    time_bnb_solve_start = time()

    ps = tree.options.log_levels

    # check if already integral
    if are_type_correct(tree.m.relaxation_solution,tree.m.var_type,tree.disc2var_idx, tree.options.atol)
        tree.nsolutions = 1
        objval = JuMP.objective_value(tree.m.model)
        sol = JuMP.value.(tree.m.x)
        bbound = try
            JuMP.objective_bound(tree.m.model)
        catch
            JuMP.objective_value(tree.m.model)
        end
        tree.incumbent = Incumbent(objval,sol,only_almost_solved(tree.m.status))
        return tree.incumbent
    end

    # check if incumbent and if mip gap already fulfilled (i.e found by fp)
    if isbreak_mip_gap(tree)
        return tree.incumbent
    end

    last_table_arr = []
    fields = []
    field_chars = []
    # Print table init
    if check_print(ps,[:Table])
        fields, field_chars = get_table_config(tree.options)
        print_table_header(fields,field_chars)
    end

    check_print(ps,[:All,:FuncCall]) && println("Solve Tree")

    branch_strat = tree.options.branch_strategy

    add_obj_epsilon_constr(tree)

    # use pmap if more then one processor
    if tree.options.processors > 1 || tree.options.force_parallel
        counter = pmap(Juniper.one_branch_step!,tree,
            last_table_arr,
            time_bnb_solve_start,
            fields,
            field_chars,
            time_obj)
    else
        counter = solve_sequential(tree,
            last_table_arr,
            time_bnb_solve_start,
            fields,
            field_chars,
            time_obj)
    end

    if !isdefined(tree,:incumbent) && tree.limit == :None
        # infeasible
        tree.limit = :Infeasible
    end

    if tree.options.obj_epsilon != 0 && tree.limit == :Infeasible
        @warn "Maybe only infeasible because of obj_epsilon."
    end

    if !isnan(tree.options.best_obj_stop) && isdefined(tree, :incumbent)
        inc_val = tree.incumbent.objval
        bos = tree.options.best_obj_stop
        sense = tree.m.obj_sense
        if (sense == :Min && inc_val > bos) || (sense == :Max && inc_val < bos)
            @warn "best_obj_gap couldn't be reached."
        end
    end

    if length(tree.branch_nodes) > 0
        bvalue, nidx = findmax([tree.obj_fac*n.best_bound for n in tree.branch_nodes])
        tree.best_bound = tree.obj_fac*bvalue
    else
        if isdefined(tree, :incumbent) && !isnan(tree.incumbent.objval)
            tree.best_bound = tree.incumbent.objval
        end
    end

    tree.m.nbranches = counter

    time_bnb_solve = time()-time_bnb_solve_start
    check_print(ps,[:Table]) && println("")
    check_print(ps,[:All,:Info]) && println("#branches: ", counter)

    tree.options.debug && debug_set_tree_obj_gain!(tree)
    check_print(ps,[:All,:Timing]) && print_final_timing(time_bnb_solve, time_obj)
end


text:
# read the output flags
export psp_readflags

const READ_FLAGS = [0x46, 0x0d]

"""
    psp_readflags(io)

Read the flags.

Returns the tuple (isrelayon, isoverheat, isknobfine, isknobunlock, isremote, islock)
"""
function psp_readflags(io_psp::IO)
  write(io_psp, READ_FLAGS)
  flagsstring = bytestring(read(io_psp,UInt8, 10))
  if  flagsstring[1] != 'F' ||
      flagsstring[8:10] != "\r\r\n"
        error("PSP Invalid Response: ",flagsstring)
  end
  isrelayon = flagsstring[2] == '1'
  isoverheat = flagsstring[3] == '1'
  isknobfine = flagsstring[4] =='1'
  isknobunlock = flagsstring[5] == '1'
  isremote = flagsstring[6] == '1'
  islock = flagsstring[7] == '1'
  return(isrelayon,isoverheat,isknobfine,isknobunlock,isremote,islock)
end


text:
using
  Documenter,
  Literate,
  Plots,   # to not capture precompilation output
  GeophysicalFlows

# Gotta set this environment variable when using the GR run-time on CI machines.
# This happens as examples will use Plots.jl to make plots and movies.
# See: https://github.com/jheinen/GR.jl/issues/278
ENV["GKSwstype"] = "100"

#####
##### Generate literated examples
#####

const EXAMPLES_DIR = joinpath(@__DIR__, "..", "examples")
const OUTPUT_DIR   = joinpath(@__DIR__, "src/literated")

examples = [
  "twodnavierstokes_decaying.jl",
  "twodnavierstokes_stochasticforcing.jl",
  "twodnavierstokes_stochasticforcing_budgets.jl",
  "singlelayerqg_betadecay.jl",
  "singlelayerqg_betaforced.jl",
  "singlelayerqg_decaying_topography.jl",
  "singlelayerqg_decaying_barotropic_equivalentbarotropic.jl",
  "barotropicqgql_betaforced.jl",
  "multilayerqg_2layer.jl",
  "surfaceqg_decaying.jl",
]

for example in examples
  withenv("GITHUB_REPOSITORY" => "FourierFlows/GeophysicalFlowsDocumentation") do
    example_filepath = joinpath(EXAMPLES_DIR, example)
    Literate.markdown(example_filepath, OUTPUT_DIR; flavor = Literate.DocumenterFlavor())
    Literate.notebook(example_filepath, OUTPUT_DIR)
    Literate.script(example_filepath, OUTPUT_DIR)
  end
end

#####
##### Build and deploy docs
#####

# Set up a timer to print a space ' ' every 240 seconds. This is to avoid CI machines
# timing out when building demanding Literate.jl examples.
Timer(t -> println(" "), 0, interval=240)

format = Documenter.HTML(
  collapselevel = 2,
     prettyurls = get(ENV, "CI", nothing) == "true",
      canonical = "https://fourierflows.github.io/GeophysicalFlowsDocumentation/stable/"
)

makedocs(
 modules = [GeophysicalFlows],
 doctest = false,
   clean = true,
checkdocs = :all,
  format = format,
 authors = "Navid C. Constantinou and Gregory L. Wagner",
sitename = "GeophysicalFlows.jl",
   pages = Any[
            "Home"    => "index.md",
            "Installation instructions" => "installation_instructions.md",
            "Aliasing" => "aliasing.md",
            "GPU" => "gpu.md",
            "Examples" => [
              "TwoDNavierStokes" => Any[
                "literated/twodnavierstokes_decaying.md",
                "literated/twodnavierstokes_stochasticforcing.md",
                "literated/twodnavierstokes_stochasticforcing_budgets.md",
                ],
              "SingleLayerQG" => Any[
                "literated/singlelayerqg_betadecay.md",
                "literated/singlelayerqg_betaforced.md",
                "literated/singlelayerqg_decaying_topography.md",
                "literated/singlelayerqg_decaying_barotropic_equivalentbarotropic.md"
                ],
              "BarotropicQGQL" => Any[
                "literated/barotropicqgql_betaforced.md",
                ],
              "MultiLayerQG" => Any[
                "literated/multilayerqg_2layer.md"
                ],
              "SurfaceQG" => Any[
                "literated/surfaceqg_decaying.md"
                ]
            ],
            "Modules" => Any[
              "modules/twodnavierstokes.md",
              "modules/singlelayerqg.md",
              "modules/barotropicqgql.md",
              "modules/multilayerqg.md",
              "modules/surfaceqg.md"
            ],
            "Stochastic Forcing" => "stochastic_forcing.md",
            "Contributor's guide" => "contributing.md",
            "Library" => Any[
              "lib/types.md",
              "lib/functions.md"
            ]
           ]
)

withenv("GITHUB_REPOSITORY" => "FourierFlows/GeophysicalFlowsDocumentation") do
  deploydocs(       repo = "github.com/FourierFlows/GeophysicalFlowsDocumentation.git",
                versions = ["stable" => "v^", "v#.#.#", "dev" => "dev"],
            push_preview = false,
               devbranch = "main"
            )
end


text:
module EstimHill

include("Model.jl")
include("Opt.jl")
include("Sens.jl")
include("Utils.jl")

end # module


text:
"""
# Module OraNumbers

The main type for this module is `OraNumber`, which mirrors
the internal representation of `NUMBER` values in Oracle Databases.

# References

* https://docs.oracle.com/cd/B10500_01/appdev.920/a96584/oci03typ.htm
* http://www.ixora.com.au/notes/number_representation.htm
* https://docs.oracle.com/en/database/oracle/oracle-database/18/lnoci/oci-NUMBER-functions.html#GUID-B20FC9D4-B984-4668-999B-1E22387596AF
"""
module OraNumbers

export OraNumber

include("types.jl")
include("encoding.jl")
include("io.jl")
include("base.jl")
include("arithmetic.jl")

end # module


text:
function finaltypes(T::Type)
    s = InteractiveUtils.subtypes(T)
    if isempty(s)
        return [T, ]
    else
        return reduce(vcat, [finaltypes(S) for S in s])
    end
end

"""
    flat_values(t::NamedTuple)

View a nested named tuple `t` as a tree and return, as a tuple, the values
at the leaves, in the order they appear in the original tuple.

```julia-repl
julia> t = (X = (x = 1, y = 2), Y = 3)
julia> flat_values(t)
(1, 2, 3)
```

"""
function flat_values(params::NamedTuple)
    values = []
    for k in keys(params)
        value = getproperty(params, k)
        if value isa NamedTuple
            append!(values, flat_values(value))
        else
            push!(values, value)
        end
    end
    return Tuple(values)
end

## RECURSIVE VERSIONS OF getproperty and setproperty!

# applying the following to `:(a.b.c)` returns `(:(a.b), :c)`
function reduce_nested_field(ex)
    ex.head == :. || throw(ArgumentError)
    tail = ex.args[2]
    tail isa QuoteNode || throw(ArgumentError)
    field = tail.value
    field isa Symbol || throw(ArgumentError)
    subex = ex.args[1]
    return (subex, field)
end

"""
    MLJBase.prepend(::Symbol, ::Union{Symbol,Expr,Nothing})

For prepending symbols in expressions like `:(y.w)` and `:(x1.x2.x3)`.

julia> prepend(:x, :y)
:(x.y)

julia> prepend(:x, :(y.z))
:(x.y.z)

julia> prepend(:w, ans)
:(w.x.y.z)

If the second argument is `nothing`, then `nothing` is returned.

"""
prepend(s::Symbol, ::Nothing) = nothing
prepend(s::Symbol, t::Symbol) = Expr(:(.), s, QuoteNode(t))
prepend(s::Symbol, ex::Expr) = Expr(:(.), prepend(s, ex.args[1]), ex.args[2])

"""
    recursive_getproperty(object, nested_name::Expr)

Call getproperty recursively on `object` to extract the value of some
nested property, as in the following example:

    julia> object = (X = (x = 1, y = 2), Y = 3)
    julia> recursive_getproperty(object, :(X.y))
    2

"""
recursive_getproperty(obj, property::Symbol) = getproperty(obj, property)
function recursive_getproperty(obj, ex::Expr)
    subex, field = reduce_nested_field(ex)
    return recursive_getproperty(recursive_getproperty(obj, subex), field)
end

recursive_getpropertytype(obj, property::Symbol) = typeof(getproperty(obj, property))
recursive_getpropertytype(obj::T, property::Symbol) where T <: Model = begin
    model_type = typeof(obj)
    property_names = fieldnames(model_type)
    property_types = model_type.types
    for (t, n) in zip(property_types, property_names)
        n == property && return t
    end
    error("Property $property not found")
end
function recursive_getpropertytype(obj, ex::Expr)
    subex, field = reduce_nested_field(ex)
    return recursive_getpropertytype(recursive_getproperty(obj, subex), field)
end

"""
    recursively_setproperty!(object, nested_name::Expr, value)

Set a nested property of an `object` to `value`, as in the following example:

```
julia> mutable struct Foo
           X
           Y
       end

julia> mutable struct Bar
           x
           y
       end

julia> object = Foo(Bar(1, 2), 3)
Foo(Bar(1, 2), 3)

julia> recursively_setproperty!(object, :(X.y), 42)
42

julia> object
Foo(Bar(1, 42), 3)
```

"""
recursive_setproperty!(obj, property::Symbol, value) =
    setproperty!(obj, property, value)
function recursive_setproperty!(obj, ex::Expr, value)
    subex, field = reduce_nested_field(ex)
    last_obj = recursive_getproperty(obj, subex)
    return recursive_setproperty!(last_obj, field, value)
end

"""
    check_dimensions(X, Y)

Internal function to check two arrays have the same shape.

"""
@inline function check_dimensions(X, Y)
    size(X)  == size(Y) ||
        throw(DimensionMismatch(
            "Encountered two objects with sizes $(size(X)) and "*
            "$(size(Y)) which needed to match but don't. "))
    return nothing
end

"""
    check_same_nrows(X, Y)

Internal function to check two objects, each a vector or a matrix,
have the same number of rows.

"""
@inline function check_same_nrows(X, Y)
    size(X, 1) == size(Y, 1) ||
        throw(DimensionMismatch("The two objects don't have the same " *
                                "number of rows."))
    return nothing
end

"""
_permute_rows(obj, perm)

Internal function to return a vector or matrix with permuted rows given
the permutation `perm`.
"""
function _permute_rows(obj::AbstractVecOrMat, perm::Vector{Int})
    check_same_nrows(obj, perm)
    obj isa AbstractVector && return obj[perm]
    obj[perm, :]
end

"""
    shuffle_rows(X::AbstractVecOrMat,
                 Y::AbstractVecOrMat;
                 rng::AbstractRNG=Random.GLOBAL_RNG)

Return row-shuffled vectors or matrices using a random permutation of `X`
and `Y`. An optional random number generator can be specified using
the `rng` argument.

"""
function shuffle_rows(
    X::AbstractVecOrMat, Y::AbstractVecOrMat;
    rng::AbstractRNG=Random.GLOBAL_RNG
)
    check_same_nrows(X, Y)
    perm_length = size(X, 1)
    perm = randperm(rng, perm_length)
    return _permute_rows(X, perm), _permute_rows(Y, perm)
end

"""
init_rng(rng)

Create an `AbstractRNG` from `rng`. If `rng` is a non-negative `Integer`, it returns a
`MersenneTwister` random number generator seeded with `rng`; If `rng` is
an `AbstractRNG` object it returns `rng`, otherwise it throws an error.
"""
function init_rng(rng)
    if (rng isa Integer && rng > 0)
        return Random.MersenneTwister(rng)
    elseif !(rng isa AbstractRNG)
        throw(
            ArgumentError(
                "`rng` must either be a non-negative `Integer`, "*
                "or an `AbstractRNG` object."
            )
        )
    end
    return rng
end

## FOR PRETTY PRINTING

# of coloumns:
function pretty(io::IO, X; showtypes=true, alignment=:l, kwargs...)
    names = schema(X).names |> collect
    if showtypes
        types = schema(X).types |> collect
        scitypes = schema(X).scitypes |> collect
        header = (names, types, scitypes)
    else
        header  = (names, )
    end
    show_color = MLJBase.SHOW_COLOR[]
    color_off()
    try
        PrettyTables.pretty_table(io, MLJBase.matrix(X),
                                  header=header;
                                  alignment=alignment,
                                  kwargs...)
    catch
        println("Trouble displaying table.")
    end
    show_color ? color_on() : color_off()
    return nothing
end

pretty(X; kwargs...) = pretty(stdout, X; kwargs...)

# of long vectors (returns a compact string version of a vector):
function short_string(v::Vector)
    L = length(v)
    if L <= 3
        middle = join(v, ", ")
    else
        middle = string(round3(v[1]), ", ", round3(v[2]),
                        ", ..., ", round3(v[end]))
    end
    return "[$middle]"
end

"""
    sequence_string(itr, n=3)

Return a "sequence" string from the first `n` elements generated
by `itr`.

    julia> MLJBase.sequence_string(1:10, 4)
    "1, 2, 3, 4, ..."

**Private method.**

"""
function sequence_string(itr::Itr, n=3) where Itr
    n > 1 || throw(ArgumentError("Cutoff must be at least 2. "))
    I = Base.IteratorSize(Itr)
    I isa Base.HasLength ||
        I isa Base.HasShape ||
        I isa IsInfinite ||
        throw(Argumenterror("Unsupported iterator. "))
    vals = String[]
    i = 0
    earlystop = false
    for x in itr
        i += 1
        if i === n + 1
            earlystop = true
            break
        else
            push!(vals, string(x))
        end
    end
    ret = join(vals, ", ")
    earlystop && (ret *= ", ...")
    return ret
end

## UNWINDING ITERATORS

"""
    unwind(iterators...)

Represent all possible combinations of values generated by `iterators`
as rows of a matrix `A`. In more detail, `A` has one column for each
iterator in `iterators` and one row for each distinct possible
combination of values taken on by the iterators. Elements in the first
column cycle fastest, those in the last clolumn slowest.

### Example

```julia
julia> iterators = ([1, 2], ["a","b"], ["x", "y", "z"]);
julia> MLJTuning.unwind(iterators...)
12×3 Array{Any,2}:
 1  "a"  "x"
 2  "a"  "x"
 1  "b"  "x"
 2  "b"  "x"
 1  "a"  "y"
 2  "a"  "y"
 1  "b"  "y"
 2  "b"  "y"
 1  "a"  "z"
 2  "a"  "z"
 1  "b"  "z"
 2  "b"  "z"
```

"""
function unwind(iterators...)
    n_iterators = length(iterators)
    iterator_lengths = map(length, iterators)

    # product of iterator lengths:
    L = reduce(*, iterator_lengths)
    L != 0 || error("Parameter iterator of length zero encountered.")

    A = Array{Any}(undef, L, n_iterators)  ## TODO: this can be done better
    n_iterators != 0 || return A

    inner = 1
    outer = L
    for j in 1:n_iterators
        outer = outer ÷ iterator_lengths[j]
        A[:,j] = repeat(iterators[j], inner=inner, outer=outer)
        inner *= iterator_lengths[j]
    end
    return A
end

"""
    chunks(range, n)

Split an `AbstractRange`  into `n` subranges of approximately equal length.

### Example
```julia
julia> collect(chunks(1:5, 2))
2-element Array{UnitRange{Int64},1}:
 1:3
 4:5

**Private method**

```
"""
function chunks(c::AbstractRange, n::Integer)
    n < 1 && throw(ArgumentError("cannot split range into $n subranges"))
    return Chunks(c, divrem(length(c), Int(n))...)
end

struct Chunks{T <: AbstractRange}
    range::T
    div::Int
    rem::Int
end

Base.eltype(::Type{Chunks{T}}) where {T <: AbstractRange} = T

function Base.length(itr::Chunks{<:AbstractRange})
   l = length(itr.range)
   return itr.div == 0 ? l : div(l - itr.rem, itr.div)
end

function Base.iterate(itr::Chunks{<:AbstractRange}, state=(1,itr.rem))
    first(state) > length(itr.range) && return nothing
    rem = last(state)
    r = min(first(state) + itr.div - (rem > 0 ? 0 : 1),
                length(itr.range))
   return @inbounds itr.range[first(state):r], (r + 1, rem-1)
end

"""
    available_name(modl::Module, name::Symbol)

Function to replace, if necessary, a given `name` with a modified one
that ensures it is not the name of any existing object in the global
scope of `modl`. Modifications are created with numerical suffixes.

"""
function available_name(modl, name)
    new_name = name
    i = 1
    while isdefined(modl, Symbol(new_name))
        i += 1
        new_name = string(name, i) |> Symbol
    end
    return new_name
end

"""
    generate_name!(M, existing_names; only=Union{Function,Type}, substitute=:f)

Given a type `M` (e.g., `MyEvenInteger{N}`) return a symbolic,
snake-case, representation of the type name (such as
`my_even_integer`). The symbol is pushed to `existing_names`, which
must be an `AbstractVector` to which a `Symbol` can be pushed.

If the snake-case representation already exists in `existing_names` a
suitable integer is appended to the name.

If `only` is specified, then the operation is restricted to those `M`
for which `M isa only`. In all other cases the symbolic name is
generated using `substitute` as the base symbol.

```
existing_names = []
julia> generate_name!(Vector{Int}, existing_names)
:vector

julia> generate_name!(Vector{Int}, existing_names)
:vector2

julia> generate_name!(AbstractFloat, existing_names)
:abstract_float

julia> generate_name!(Int, existing_names, only=Array, substitute=:not_array)
:not_array

julia> generate_name!(Int, existing_names, only=Array, substitute=:not_array)
:not_array2
```

"""
function generate_name!(M::DataType,
                        existing_names;
                        only=Any,
                        substitute=:f)
    if M <: only
        str = split(string(M), '{') |> first
        candidate = split(str, '.') |> last |> snakecase |> Symbol
    else
        candidate = substitute
    end

    candidate in existing_names ||
        (push!(existing_names, candidate); return candidate)
    n = 2
    new_candidate = candidate
    while true
        new_candidate = string(candidate, n) |> Symbol
        new_candidate in existing_names || break
        n += 1
    end
    push!(existing_names, new_candidate)
    return new_candidate
end

generate_name!(model, existing_names; kwargs...) =
    generate_name!(typeof(model), existing_names; kwargs...)


text:
using Documenter, LearnBase, LossFunctions

istravis = "TRAVIS" ∈ keys(ENV)

makedocs(
    format = Documenter.HTML(assets=["assets/style.css","assets/favicon.ico"], prettyurls=istravis),
    sitename = "LossFunctions.jl",
    authors = "Christof Stocker, Tom Breloff, Alex Williams",
    pages = [
        hide("Home" => "index.md"),
        "Introduction" => [
            "introduction/gettingstarted.md",
            "introduction/motivation.md",
        ],
        "User's Guide" => [
            "user/interface.md",
            "user/aggregate.md",
        ],
        "Available Losses" => [
            "losses/distance.md",
            "losses/margin.md",
            "losses/other.md",
        ],
        "Advances Topics" => [
            "advanced/extend.md",
            "advanced/developer.md",
        ],
        hide("Indices" => "indices.md"),
        "acknowledgements.md",
        "LICENSE.md",
    ],
)

deploydocs(repo="github.com/JuliaML/LossFunctions.jl.git")


text:
using PDBenchmark
using Test

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

max_stars_repo_name: ravinderbhattoo/PDBenchmark

max_issues_repo_name: ravinderbhattoo/PDBenchmark

max_forks_repo_name: ravinderbhattoo/PDBenchmark


text:
# Use baremodule to shave off a few KB from the serialized `.ji` file
baremodule libportaudio_jll
using Base
using Base: UUID
import JLLWrappers

JLLWrappers.@generate_main_file_header("libportaudio")
JLLWrappers.@generate_main_file("libportaudio", UUID("2d7b7beb-0762-5160-978e-1ab83a1e8a31"))
end  # module libportaudio_jll


text:
function to_real_field_univariate_matrix_function(obj::FieldUnivariateMatrixFunction, arg0::Field)
    return jcall(obj, "toRealFieldUnivariateMatrixFunction", RealFieldUnivariateMatrixFunction, (Field,), arg0)
end

function value(obj::FieldUnivariateMatrixFunction, arg0::RealFieldElement)
    return jcall(obj, "value", Vector{Vector{RealFieldElement}}, (RealFieldElement,), arg0)
end


text:
@testset "Rule making" begin
    @test (@rule a + a => 2a) isa Rule
    r = Rule(:(a + a => 2a))
    rm = @rule a + a => 2a
    @test r.left == rm.left
    @test r.right == rm.right
    @test r.expr == rm.expr
end

@testset "MatchCore Theory Compilation" begin
    theory = :(
        begin
            :($a + $(&a)) => :(2 * $a)
            :($b + $(&b) + $(&b)) => :(3 * $b)
            :($i) => i
        end
    ) |> rmlines
    theory_macro = @theory begin
        a + a => 2a
        b + b + b => 3b
    end
    @test (Metatheory.theory_block(theory_macro) == theory)
end


text:
"""
This script is to be used with the example ´05c-multifunc_external-server.vi´ to start
the corresponding Julia script on remote server:

- Install ´LabVIEW0´ on that computer
- Adapt the path below to point to the example script ´05-multiple_functions.jl´
- In the Terminal window, type ´Julia [path to this script]´
- Run ´05c-multifunc_external-server.vi´ on the LabVIEW computer
"""

using LabVIEW0

try
   # change the path!
   include(get_script_path(raw"C:\_MyOwnDocs\SoftwareDevelopment\LabVIEW0.jl\src\LabVIEW\LV2Julia_examples\jl-scripts\05-multiple_functions.jl"))
   LabVIEW0.setglobals(isOK=true)
catch excep
  LabVIEW0.setglobals(isOK=false, excpn=(;excep, stack_trace=backtrace()))
end

server_0mq4lv(fns)


text:
export sfw!

# construction of a regular grid with given bounds and number of points
function makegrid(lowerbounds, upperbounds, gridsize::Int64)
    ndims = length(lowerbounds)
    grid = collect(Iterators.product(
        [[lowerbounds[n] + (upperbounds[n] - lowerbounds[n]) * (i-1) / (gridsize-1)
          for i=1:gridsize] for n=1:ndims]...))
end

# finds the maximum of a function on a grid
function gridsearch(η, lowerbounds, upperbounds, gridsize)
    grid = makegrid(lowerbounds, upperbounds, gridsize)
    argmax_temp = grid[1]

    for x in grid
        if abs(η(x)) > abs(η(argmax_temp))
            argmax_temp = x
        end
    end

    collect(argmax_temp)  # tuple to array conversion
end

# attempts to find the maximum of a function using Newton algorithm, initialized
# with the output of a grid search (no guarantee to reach a global optimum)
function findargmax(η, lowerbounds, upperbounds, gridsize)
    x0 = gridsearch(η, lowerbounds, upperbounds, gridsize)
    obj(x) = -abs(η(x))

    # TODO: check autodiff vs analytic
    Optim.minimizer(optimize(obj, x0, Newton(); autodiff=:forward))
end

# adds a spike with 0 amplitude at a given location
function addspike(μ, new_x)
    new_atom = WeightedDiracMeasure(new_x, 0.0)
    AtomicMeasure(μ.variables, append!(μ.atoms, [new_atom]))
end

# finds optimal amplitudes with fixed locations by solving a LASSO problem
function updateamplitudes(μ, y, φ, λ)
    natoms = length(μ.atoms)
    nmoments = length(y)

    x = [atom.center for atom in μ.atoms]
    Φx = [φ(x[i], n) for n=1:nmoments, i=1:natoms]

    # constraints = hcat([[0 Inf]' for i=1:natoms]...)  # positive spikes
    # lasso = glmnet(Φx, y, lambda=[λ], constraints=constraints)
    lasso = glmnet(vcat(real(Φx), imag(Φx)), vcat(real(y), imag(y)), lambda=[λ])
    new_a = lasso.betas[:]

    new_atoms = [WeightedDiracMeasure(μ.atoms[i].center, new_a[i]) for i=1:natoms]
    AtomicMeasure(μ.variables, new_atoms)
end

# attempts to find optimal amplitudes and locations by solving a non convex
# problem with BFGS algorithm (no guarantee to reach a global optimum)
function performsliding(μ, y, φ, λ)
    natoms = length(μ.atoms)
    ndims = length(μ.variables)
    nmoments = length(y)

    function obj(arg)
        # amplitudes and locations are parsed from the arg vector
        a = arg[1:natoms]
        # x = reshape(arg[natoms+1:length(arg)], (ndims, natoms))'
        x = [[arg[natoms + (i-1) * ndims + j] for j=1:ndims] for i=1:natoms]

        nspikes = length(μ.atoms)
        Φx = [sum(a[i] * φ(x[i], n) for i=1:natoms)
              for n=1:nmoments]

        sum(abs(Φx[n] - y[n])^2 for n=1:nmoments) / 2 + λ * sum(abs(a[i]) for i=1:nspikes)
    end

    # amplitudes and locations are concatenated in a single vector to cope
    # with Optim.jl API
    cat_centers = vcat([atom.center for atom in μ.atoms]...)
    x0 = vcat([atom.weight for atom in μ.atoms]..., cat_centers)

    # TODO: check autodiff vs analytic
    res = Optim.minimizer(optimize(obj, x0, BFGS(); autodiff=:forward))

    new_a = res[1:natoms]
    new_x = [[res[natoms + (i-1) * ndims + j] for j=1:ndims] for i=1:natoms]
    new_atoms = [WeightedDiracMeasure(new_x[i], new_a[i]) for i=1:natoms]

    AtomicMeasure(μ.variables, new_atoms)
end

# Sliding Frank-Wolfe algorithm
function sfw!(blasso::BLASSO{T, FT, DT},
              niter::Integer,
              gridsize::Integer) where {T, FT<:Function, BT, DT<:Array{BT, 2}}

    lowerbounds = blasso.domain[:, 1]
    upperbounds = blasso.domain[:, 2]

    φ = blasso.φ
    y = blasso.y

    ndims = length(lowerbounds)
    nmoments = length(y)

    @polyvar var[1:ndims]

    for k=1:niter
        if k == 1
            Φμ = zeros(nmoments)  # workaround to simulate a null atomic measure
        else
            Φμ = [expectation(μ, x -> φ(x, n)) for n=1:nmoments]
        end

        η(x) = sum((y[n] - Φμ[n]) * φ(x, n) for n=1:length(y)) / blasso.λ
        new_x = findargmax(η, lowerbounds, upperbounds, gridsize)

        if k == 1
            global μ
            μ = AtomicMeasure(var, [WeightedDiracMeasure(new_x, 0.0)])
        else
            μ = addspike(μ, new_x)
        end

        if abs(η(new_x)) <= 1  # check convergence
            @goto convergence_label
        end

        μ = updateamplitudes(μ, y, φ, blasso.λ)
        μ = performsliding(μ, y, φ, blasso.λ)
    end

    @label convergence_label
    blasso.μ = μ
end


text:
using LinearAlgebra

"""
    get_std_normal(shape=1; seed=nothing)

Generate a `shape` element array of random variables from a standard Normal(0, 1) distribution. Optionally you can set a specific seed.

# Examples

```julia-repl
julia> get_std_normal()
1-element Vector{Float64}:
 0.6315076033452351

julia> get_std_normal(5, seed=43)
5-element Vector{Float64}:
  1.2311463458421277
  1.7786409025309897
 -0.4178415161339713
  0.3518755172644067
 -0.16742990320047046

julia> get_std_normal((2,2))
2×2 Matrix{Float64}:
 -0.900365   -0.432759
 -0.0350299   1.55754

```
"""
function get_std_normal(shape::Int=1; seed::Union{Int, Nothing}=nothing)
    seed_setter(seed)
    a = sqrt.(-2 .* log.(get_std_uniform(shape)))
    b = 2 * π .* get_std_uniform(shape)
    A = a .* sin.(b)
    B = a .* cos.(b)
    X = collect(Iterators.flatten(zip(A, B)))[1:shape]
    return X
end

function get_std_normal(shape::Tuple{Vararg{Int}}; seed::Union{Int, Nothing}=nothing)
    X = get_std_normal(reduce(*, shape), seed=seed)
    return reshape(X, shape)
end

"""
    normal_rng(μ, σ², shape=1; seed=nothing)

Generate a `shape` element array of random variables from a Normal(`μ`, `σ²`) distribution. Optionally you can set a specific seed.

# Notes

The Normal distribution is given by:

``f(x, μ, σ²) = \\frac{1}{σ\\sqrt{2π}} e^{ - \\frac{1}{2} (\\frac{x-μ}{σ})^2}``

# Examples

```julia-repl
julia> normal_rng()
1-element Vector{Float64}:
 0.03130435813519526

julia> normal_rng(3, 9, 2)
2-element Vector{Float64}:
  7.362935421449054
 -1.0173543995738399

julia> normal_rng(0,1,(2,2))
2×2 Matrix{Float64}:
 -0.640505   0.30303
 -0.0556832  0.714122

```

# References

Walk, C. Handbook on statistical distributions for experimentalists. 2007.
"""
function normal_rng(μ::Real=0, σ²::Real=1, shape::Union{Int, Tuple{Vararg{Int}}}=1; seed::Union{Int, Nothing}=nothing)
    σ = sqrt(σ²)
    X = get_std_normal(shape, seed=seed) .* σ .+ μ
    return X
end

# NOT DOCUMENTED, NOT EXPORTED!
function lognormal_rng(μ::Real=0, σ²::Real=1, shape::Union{Int, Tuple{Vararg{Int}}}=1; seed::Union{Int, Nothing}=nothing)
    Y = normal_rng(μ, σ², shape, seed=seed)
    X = exp.(Y)
    return X
end

"""
    get_mv_std_normal(μ, Σ; seed=nothing)

Generate an array of random variables from a Multivariate Normal(`μ`, `Σ`) distribution. Optionally you can set a specific seed.

# Notes

The Normal distribution is given by:

``f(\\textbf{x, μ}, Σ) = \\frac{1}{2π^{k/2} |Σ|^{1/2}} exp \\{ - \\frac{(\\textbf{x} - \\textbf{μ})^T Σ^{-1} (\\textbf{x} - \\textbf{μ})}{2} \\} \\quad \\textbf{x} \\in \\mathbb{R}^k``

with mean vector ``\\textbf{μ} = (μ_1, μ_2, …, μ_k)`` and covariance matrix ``Σ``.

# Examples

```julia-repl
julia> A
2×2 Matrix{Float64}:
 1.0  0.9
 0.9  1.0

julia> get_mv_std_normal([2,2], A)
1×2 transpose(::Vector{Float64}) with eltype Float64:
 2.60139  1.76837

julia> B
3×3 Matrix{Float64}:
 1.0  0.8  0.3
 0.8  1.0  0.6
 0.3  0.6  1.0

julia> get_mv_std_normal([0,1,2], B)
1×3 transpose(::Vector{Float64}) with eltype Float64:
 -1.24861  0.110397  0.609328

```

# References

Law, A. Simulation modeling and analysis, 5th Ed. McGraw Hill Education, Tuscon, 2013.
"""
function get_mv_std_normal(μ, Σ; seed=nothing)
    Z = get_std_normal(length(μ), seed=seed)
    C = cholesky(Σ)
    X = transpose(μ) + transpose(Z) * C.U
    return X
end

"""
    mv_normal_rng(μ, Σ, shape=1; seed=nothing)

Generate a `shape` element array of random variables from a Multivariate Normal(`μ`, `Σ`) distribution. Optionally you can set a specific seed.

# Notes

The Normal distribution is given by:

``f(\\textbf{x, μ}, Σ) = \\frac{1}{2π^{k/2} |Σ|^{1/2}} exp \\{ - \\frac{(\\textbf{x} - \\textbf{μ})^T Σ^{-1} (\\textbf{x} - \\textbf{μ})}{2} \\} \\quad \\textbf{x} \\in \\mathbb{R}^k``

with mean vector ``\\textbf{μ} = (μ_1, μ_2, …, μ_k)`` and covariance matrix ``Σ``.

# Examples

```julia-repl
julia> A
2×2 Matrix{Float64}:
 1.0  0.9
 0.9  1.0

julia> mv_normal_rng([2,2], A)
1×2 Matrix{Float64}:
 0.398043  0.651268

julia> mv_normal_rng([2,2], A, 4)
4×2 Matrix{Float64}:
 2.12004  1.9172
 4.81543  5.02956
 2.97096  2.2597
 3.27012  3.07918

```

# References

Law, A. Simulation modeling and analysis, 5th Ed. McGraw Hill Education, Tuscon, 2013.
"""
function mv_normal_rng(μ::Array, Σ::Matrix, shape::Int=1; seed=nothing)
    X = zeros(shape, length(μ))
    for i in 1:size(X, 1)
        X[i, :] += transpose(get_mv_std_normal(μ, Σ; seed=seed))
    end
    return X
end


text:
using Gtk

"""
Creates game in GUI.
Default game is: Game(dims=(10,10), n_mines=15)
Pass game object for custom game
Start new game: File->New Game
Game setup: File->Setup
Flagging: switch on and off using toggle slider in top left corner
"""
function generate_gui()
    game = Game(dims=(10,10), n_mines=15)
    generate_gui(game)
end

function generate_gui(game)
    win = GtkWindow("Minesweeper")
    generate_gui!(game, win)
    return win
end

function generate_gui!(game, win)
    menu_bar = setup_menu(win, game)
    g = GtkGrid(name="grid")
    base_panel = GtkBox(:v, name="base_panel")
    score_panel = GtkBox(:h, name="score_panel")
    toggle_panel = GtkBox(:h, name="toggle_panel")
    push!(base_panel, menu_bar)
    push!(base_panel, score_panel)
    push!(base_panel, toggle_panel)
    set_gtk_property!(score_panel, :spacing, 20)
    set_gtk_property!(toggle_panel, :spacing, 20)
    label = GtkLabel("Mines flagged ", name="mines_flagged_label")
    push!(score_panel, label)
    flag_label = GtkLabel("0", name="flag_counter")
    push!(score_panel, flag_label)
    push!(base_panel, g)
    toggle = Gtk.GtkSwitch()
    signal_connect(set_toggle, toggle, "activate")
    toggle_label = GtkLabel("Flagging")
    push!(toggle_panel, toggle_label)
    push!(toggle_panel, toggle)
    for r in 1:game.dims[2], c in 1:game.dims[1]
        b = GtkButton("")
        g[r,c] = b
        signal_connect(x->on_button_clicked(x, game, win, game.cells[c,r], toggle), b, "clicked")
    end
    set_gtk_property!(g, :column_spacing, 5)
    set_gtk_property!(g, :row_spacing, 5)
    set_gtk_property!(g, :column_homogeneous, true)
    set_gtk_property!(g, :row_homogeneous, true)
    set_gtk_property!(g, :expand, true)
    set_gtk_property!(score_panel, :pack_type, label, 0)
    push!(win, base_panel)
    showall(win)
end

function on_button_clicked(button, game, gui, cell, toggle)
    game.mine_detonated ? (return nothing) : nothing
    flag_on = get_gtk_property(toggle, :state, Bool)
    if flag_on
        counter = gui[1][2][2]
        if cell.flagged
            set_gtk_property!(button, :label, "")
            game.mines_flagged -= 1
        else
            set_gtk_property!(button, :label, "🚩")
            game.mines_flagged += 1
        end
        update_flag_count!(game, gui)
        cell.flagged = !cell.flagged
        return nothing
    end
    grid = gui[1][4]
    if cell.flagged
    elseif cell.has_mine
        game.mine_detonated = true
        cell.revealed = true
        reveal_button!(grid, cell, "💣")
    elseif cell.mine_count == 0
        cell.revealed = true
        reveal_button!(grid, cell, "∘")
        cells = game.cells
        indices = get_neighbor_indices(game, cell.idx)
        for i in indices
            c = cells[i]
            if !c.has_mine && !c.revealed
                on_button_clicked(button, game, gui, c, toggle)
            end
        end
    else
        cell.revealed = true
        reveal_button!(grid, cell, string(cell.mine_count))
    end
    return nothing
end

function set_toggle(button)
    state = get_gtk_property(button, :state, String)
    set_gtk_property(button, :state, !state)
end

function update_flag_count!(game, gui)
    counter = gui[1][2][2]
    set_gtk_property!(counter, :label, string(game.mines_flagged))
    return nothing
end

function update_reveal!(game, gui::GtkWindowLeaf)
    update_flag_count!(game, gui)
    for c in game.cells
        if c.revealed
            if c.has_mine
                reveal_button!(gui, c, "💣")
            elseif c.mine_count == 0
                reveal_button!(gui, c, "∘")
            else
                reveal_button!(gui, c, string(c.mine_count))
            end
        end
    end
    return nothing
end

reveal_button!(win::GtkWindowLeaf, cell, value) = reveal_button!(win[1][4], reverse(cell.idx.I), value)

reveal_button!(buttons::GtkGridLeaf, cell::Cell, value) = reveal_button!(buttons, reverse(cell.idx.I), value)

function reveal_button!(buttons::GtkGridLeaf, idx, value)
    delete!(buttons, buttons[idx...])
    buttons[idx...] = GtkLabel(value)
    set_gtk_property!(buttons[idx...], :visible, true)
end

function flag_cell!(cell, game, gui)
    cell.flagged = true
    flag_button!(gui, cell)
    game.mines_flagged += 1
    update_flag_count!(game, gui)
    return nothing
end

flag_button!(win::GtkWindowLeaf, cell) = flag_button!(win[1][4], reverse(cell.idx.I))

function flag_button!(buttons, idx)
    set_gtk_property!(buttons[idx...], :label, "🚩")
end

start_new_game!(x, gui, game) = start_new_game!(gui, game)

function start_new_game!(gui, game)
    game.score = (hits=0.0,false_alarms=0.0,misses=0.0,correct_rejections=0.0)
    cells = initilize_cells(game.dims)
    add_mines!(cells, game.n_mines)
    mine_count!(cells)
    game.cells = cells
    game.mines_flagged = 0
    game.mine_detonated = false
    remove_components!(gui)
    generate_gui!(game, gui)
end

function setup_menu(gui, game)
    mb = GtkMenuBar(name="menu_bar")
    file = GtkMenuItem("_File")
    file_menu = GtkMenu(file, name="file_menu")
    new_game = GtkMenuItem("New Game", name="new_game")
    signal_connect(x->start_new_game!(x, gui, game), new_game, :activate)
    push!(file_menu, new_game)
    setup = GtkMenuItem("Setup", name="setup")
    signal_connect(x->setup_game(x, game, gui), setup, :activate)
    push!(file_menu, setup)
    push!(mb, file)
    return mb
end

function remove_components!(gui)
    for g in gui
        delete!(gui, g)
    end
end

function setup_game(x, game, gui)
    popup = GtkWindow("Setup")
    base_panel = GtkBox(:v)
    push!(popup, base_panel)
    grid = GtkGrid()
    col_label = GtkLabel("Number of Columns")
    row_label = GtkLabel("Number of Rows")
    mine_label = GtkLabel("Number of Mines")
    col_entry = GtkEntry(name="col_value")
    row_entry = GtkEntry(name="row_value")
    mine_entry = GtkEntry(name="mine_value")
    grid[1,1] = col_label
    grid[2,1] = col_entry
    grid[1,2] = row_label
    grid[2,2] = row_entry
    grid[1,3] = mine_label
    grid[2,3] = mine_entry
    GAccessor.justify(col_label, Gtk.GConstants.GtkJustification.LEFT)
    GAccessor.justify(row_label, Gtk.GConstants.GtkJustification.LEFT)
    set_gtk_property!(grid, :column_spacing, 5)  # introduce a 15-pixel gap between columns
    set_gtk_property!(grid, :row_spacing, 5)
    set_gtk_property!(grid, :column_homogeneous, true)
    set_gtk_property!(grid, :row_homogeneous, true)
    push!(base_panel, grid)
    ok_button = GtkButton("OK")
    components = (col_entry=col_entry, row_entry=row_entry, mine_entry=mine_entry, popup=popup)
    signal_connect(x-> modify_game(x, components, game, gui), ok_button, "clicked")
    cancel_button = GtkButton("Cancel")
    signal_connect(x->close_window(x, popup), cancel_button, "clicked")
    hbox = GtkButtonBox(:h)
    set_gtk_property!(hbox, :expand, ok_button, true)
    set_gtk_property!(hbox, :spacing, 10)
    push!(base_panel, hbox)
    push!(hbox, cancel_button)
    push!(hbox, ok_button)
    showall(popup)
end

function modify_game(x, c, game, gui)
    str_cols = get_gtk_property(c.col_entry, :text, String)
    n_cols = parse(Int, str_cols)
    str_rows = get_gtk_property(c.row_entry, :text, String)
    n_rows = parse(Int, str_rows)
    str_mines = get_gtk_property(c.mine_entry, :text, String)
    n_mines = parse(Int, str_mines)
    if n_mines > n_rows*n_cols
        error_window = GtkWindow("Error")
        base_panel = GtkBox(:v)
        set_gtk_property!(base_panel, :spacing, 20)
        message = GtkLabel(
            "The number of mines cannot exceed the number of cells"
        )
        ok_button = GtkButton("OK")
        push!(error_window, base_panel)
        push!(base_panel, message)
        push!(base_panel, ok_button)
        signal_connect(x->close_window(x, error_window), ok_button, "clicked")
        showall(error_window)
        return nothing
    end
    game.dims = (n_rows,n_cols)
    game.n_mines = n_mines
    start_new_game!(gui, game)
    close_window(c.popup)
    return nothing
end

close_window(_, component) = close_window(component)

function close_window(component)
    hide(component)
end


text:
"""
# Interpolation Search
Used for sorted array which is uniformly distributed.
Binary Search always goes to the middle element to check. On the other hand, interpolation search may go to different locations according to the value of the key being searched. For example, if the value of the key is closer to the last element, interpolation search is likely to start search toward the end side.
The idea of formula is to return higher value of pos when element to be searched is closer to arr[hi]. And smaller value when closer to arr[lo]
pos = lo + [ (x-arr[lo])*(hi-lo) / (arr[hi]-arr[Lo]) ]
- arr[] ==> Array where elements need to be searched
- x     ==> Element to be searched
- lo    ==> Starting index in arr[]
- hi    ==> Ending index in arr[]
## Derivation =>
Let's assume that the elements of the array are linearly distributed.
General equation of line : y = m*x + c.
y is the value in the array and x is its index.
Now putting value of lo,hi and x in the equation
- arr[hi] = m*hi+c ----(1)
- arr[lo] = m*lo+c ----(2)
- x = m*pos + c     ----(3)
m = (arr[hi] - arr[lo] )/ (hi - lo)
subtracting eqxn (2) from (3)
- x - arr[lo] = m * (pos - lo)
- lo + (x - arr[lo])/m = pos
- pos = lo + (x - arr[lo]) *(hi - lo)/(arr[hi] - arr[lo])
## Algorithm:
Rest of the Interpolation algorithm is the same except the above partition logic.
- Step1: In a loop, calculate the value of “pos” using the probe position formula.
- Step2: If it is a match, return the index of the item, and exit.
- Step3: If the item is less than arr[pos], calculate the probe position of the left sub-array. Otherwise calculate the same in the right sub-array.
- Step4: Repeat until a match is found or the sub-array reduces to zero.

"""

"""
	 interpolation_search(arr::AbstractArray{T,1}, l::T, r::T, x::T) where {T <: Real}

Interpolation Search in 1-D array
Time Complexity: O(log2(log2 n))
"""
function interpolation_search(arr::AbstractArray{T,1}, l::T, r::T, x::T) where {T <: Real}

    if (r >= l && x >= arr[l] && x <= arr[r])

        mid = Int(ceil(l + (((x - arr[l]) * (r - l)) / (arr[r] - arr[l]))))

        if (arr[mid] == x)
            return mid

        elseif (arr[mid] > x)
            interpolation_search(arr, l, mid - 1, x)

        else
            interpolation_search(arr, mid + 1, r, x)

        end

    else
        return -1

    end

end

max_stars_repo_name: gohpeijin/Julia

max_issues_repo_name: gohpeijin/Julia

max_forks_repo_name: gohpeijin/Julia


text:
GKernel(var) = (x) -> Normal(x, sqrt.(var))

function randr(vi::Turing.VarInfo,
               vn::Turing.VarName,
               dist::Distribution,
               spl::Turing.Sampler,
               count::Bool = false)
    if ~haskey(vi, vn)
        r = rand(dist)
        Turing.push!(vi, vn, r, dist, spl)
        return r
    elseif is_flagged(vi, vn, "del")
        unset_flag!(vi, vn, "del")
        r = rand(dist)
        Turing.RandomVariables.setval!(vi, Turing.vectorize(dist, r), vn)
        return r
    else
        if count Turing.checkindex(vn, vi, spl) end
        Turing.updategid!(vi, vn, spl)
        return vi[vn]
    end
end

function insdelim(c, deli=",")
	return reduce((e, res) -> append!(e, [res, deli]), c; init = [])[1:end-1]
end