text:
# LSTM model - input * weight, concatenated weights
function lstm(weight, bias, input, hidden, cell)
    gates   = weight * vcat(hidden,input) .+ bias
    hsize   = size(hidden,1)
    forget  = sigm(gates[1:hsize,:])
    ingate  = sigm(gates[1+hsize:2hsize,:])
    outgate = sigm(gates[1+2hsize:3hsize,:])
    change  = tanh(gates[1+3hsize:end,:])
    cell    = cell .* forget + ingate .* change
    hidden  = outgate .* tanh(cell)
    return (hidden,cell)
end

#w1 -> (2H, X+H) #b1   -> (2H,1)
#w2 -> (2H, X+H) #b2   -> (2H,1)
#reference: https://goo.gl/6uDnrk
function gru(w1,w2,b1,b2,input,hidden)
    gates  = w1 * vcat(hidden,input) .+ b1
    hsize  = size(hidden,1)
    update = sigm(gates[1:hsize,:])
    reset  = sigm(gates[1+hsize:end,:])
    h      = w2 * vcat(hidden .* reset,input) .+ b2
    hidden = (1 .- update) + (update .* hidden)
    return hidden
end

function feedforward(w,b,x)
    return relu(w * x .+ b)
end

function propagate(w,b,x,h::Void,c::Void)
    feedforward(w,b,x), nothing, nothing
end

function propagate(w,b,x,h,c)
    h,c = lstm(w,b,x,h,c)
    return h,h,c
end

function predict(w,b,x)
    return w * x .+ b
end

function logprob(output, ypred, mask=nothing)
    nrows,ncols = size(ypred)
    index = output + nrows*(0:(length(output)-1))
    # FIXME: this is so dirty
    if mask != nothing && length(mask) != 1
        index = index[[mask...]]
    elseif mask != nothing && length(mask) == 1 && !mask[1]
        return 0
    end
    o1 = logp(ypred,1)
    # @show index
    o2 = o1[index]
    o3 = sum(o2)
    return o3
end

# loss function for supervised learning
# x: controller input, y: controller output (action+symbol)
# m: masks for loss, h/c: controller states
function sloss(w,x,y,m,h,c; values=[])
    batchsize = size(x[1][1],2)
    atype = typeof(AutoGrad.getval(w[:wcont]))

    lossval1 = lossval2 = 0
    for (i,(xi,yi,mi)) in enumerate(zip(x,y,m))
        # concat previous action and symbol from input tape
        input = convert(atype,xi) # TODO: CPU/GPU comparison

        # use the controller
        cout,h,c = propagate(w[:wcont],w[:bcont],input,h,c)

        # make predictions
        sympred = predict(w[:wsymb],w[:bsymb],cout)
        actpred = predict(w[:wact],w[:bact],cout)

        # log probabilities
        symgold, actgold = yi[1], yi[2]
        lossval1 += logprob(symgold,sympred,mi)
        lossval2 += logprob(actgold,actpred)
    end

    # combined loss
    lossval = -0.5*(lossval1+lossval2)
    push!(values, AutoGrad.getval(lossval))
    push!(values, batchsize*length(x))

    # return -lossval/(batchsize*length(x))
    return lossval
end

slgrad = grad(sloss)

function initweights(
    atype,units,nsymbols,nactions,
    controller="feedforward",dist="randn", winit=0.01)
    unit_dict = Dict("feed"=>1,"lstm"=>4)
    w = Dict()
    winit = (dist=="xavier") ? 1.0 : winit
    _dist = eval(Symbol(dist))

    params = units * get(unit_dict,controller,1)
    input = nsymbols+nactions+(controller!="feedforward")*units
    w[:wcont] = _dist(Float32, params, input)
    w[:bcont] = zeros(Float32, params, 1)
    w[:wsymb] = _dist(Float32, nsymbols, units)
    w[:bsymb] = zeros(Float32, nsymbols, 1)
    w[:wact]  = _dist(Float32, nactions, units)
    w[:bact]  = zeros(Float32, nactions, 1)

    for (k,v) in w
        w[k] = convert(atype, v*winit)
    end

    return w
end

function initstates(atype, hidden, batchsize, controller="lstm")
    if controller == "lstm"
        convert(atype, zeros(hidden, batchsize)),
        convert(atype, zeros(hidden, batchsize))
    elseif controller == "feedforward"
        nothing, nothing
    end
end

function initopts(w,optim)
    opts = Dict()
    for k in keys(w)
        opts[k] = eval(parse(optim))
    end
    return opts
end

# Reinforcement Learning stuff
# xs => controller inputs (concat prev_action and read_symbol)
# ys => controller symbol outputs written to output tape
# as => actions taken by following behaviour policy
# ts => temporal difference learning targets
function rloss(w, ts, xs, ys, as, ms, h, c; values=[])
    # propagate controller, same with previous
    cout, h, c = propagate(w[:wcont], w[:bcont], xs, h, c)

    # symbol prediction, same
    sympred = predict(w[:wsymb], w[:bsymb], cout)

    # compute Q estimate
    qsa = predict(w[:wact], w[:bact], cout)
    nrows, ncols = size(qsa)
    index = as + nrows*(0:(length(as)-1))
    qs = qsa[index]  # divide by nsteps remaining
    estimate = reshape(qs, 1, length(qs))
    ts = reshape(ts, 1, length(ts))

    # hybrid loss calculation, supervised (symbols), q-learning (actions)
    val = 0
    val -= 0.5 * logprob(ys, sympred, ms)
    val += 0.5 * sumabs2(ts-estimate)

    push!(values, val, size(ts,2))
    return val
end

rlgrad = grad(rloss)

# FIXME: this is so dirty and inefficient
function make_batches(w,histories,s2i,a2i,discount,nsteps,batchsize; o=Dict())
    atype = get(o, :atype, typeof(w[:wcont]))

    samples = []
    for history in histories
        for k = 1:length(history)-1
            this = history[k]

            # input formation
            x = (this.input_symbol,this.prev_action)
            y = this.output_symbol
            a = this.action
            m = y != NO_SYMBOL && !this.is_done
            ph = this.h
            pc = this.c
            vs = this.nsteps

            # target formation
            T = min(k+nsteps, length(history))
            rs = reduce(+, [0, map(hi->hi.reward, history[k+1:T])...])
            yT = history[T].output_symbol
            target = rs
            if yT != NO_SYMBOL && !history[T].is_done
                # compute target
                xT = (history[T].input_symbol, history[T].prev_action)
                input = zeros(Cuchar, length(s2i)+length(a2i), 1)
                input[s2i[xT[1]]] = 1
                input[length(s2i)+a2i[xT[2]]] = 1
                input = convert(atype, input)

                vT = history[T].nsteps
                phT,pcT = history[T].h, history[T].c
                cout, hT, cT = propagate(w[:wcont],w[:bcont],input,phT,pcT)
                qsa = predict(w[:wact], w[:bact], cout)
                qs = maximum(qsa)
                target += vT * maximum(qs)
            end

            # normalize target
            target = target/vs

            sample = (target,x,y,a,m,ph,pc)
            push!(samples, sample)
        end

        # episode ending
        length(history) >= 1 || continue
        target = history[end].reward / history[end].nsteps
        x = (history[end].input_symbol, history[end].prev_action)
        y = history[end].output_symbol
        a = history[end].action
        ph = history[end].h
        pc = history[end].c
        m = y != NO_SYMBOL && !history[end].is_done
        sample = (target,x,y,a,m,ph,pc)
        push!(samples,sample)
    end

    batches = []
    for k = 1:batchsize:length(samples)
        from = k; to = min(from+k-1,length(samples))
        bsamples = samples[from:to]

        # make target batch
        ts = mapreduce(s->s[1], vcat, bsamples)

        # make input batch
        xs = falses(length(s2i)+length(a2i), to-from+1)
        for j = 1:to-from+1
            xs[s2i[bsamples[j][2][1]],j] = 1
            xs[length(s2i)+a2i[bsamples[j][2][2]]] = 1
        end

        # make output batch
        ys = map(si->s2i[si[3]], bsamples)

        # make action batch
        as = map(si->a2i[si[4]], bsamples)

        # make mask batch
        ms = map(si->si[5], bsamples)

        # make h,c batches
        hs = cs = nothing
        if bsamples[1][end-1] != nothing
            hs = mapreduce(bi->bi[end-1], hcat, bsamples)
            cs = mapreduce(bi->bi[end], hcat, bsamples)
        end

        batch = (ts,xs,ys,as,ms,hs,cs)
        push!(batches, batch)
    end

    return batches
end

# compute TD targets for objective
function compute_targets(samples, w, discount, nsteps, s2i, a2i)
    # reward calculations
    if discount < 0
        discount = 1
    end
    discounts = map(i->discount^i, 0:nsteps)
    targets = zeros(1, length(samples))
    for k = 1:length(samples)
        sample = samples[k]
        vs, vsp = samples[k][1].nsteps, samples[k][end].nsteps
        reward = mapreduce(
            i->(sample[i].reward)*discounts[i]/vs, +, 1:length(sample))
        targets[k] = reward
    end

    # (1) dynamic discount calculation for max Q(s,a)
    get_steps(s) = (s[1].nsteps, s[end].nsteps)
    gamma = discounts[end]
    discounts = map(i->get_steps(samples[i]), 1:length(samples))
    discounts = map(d->gamma*(d[2]/d[1]), discounts)

    # (2) predict Q(s,a) over all possible actions

    # (2.1) batch controller states
    h = c = nothing
    if samples[1][1].h != nothing
        h = mapreduce(s->s[end].h, hcat, samples)
    end
    if samples[1][1].c != nothing
        c = mapreduce(s->s[end].c, hcat, samples)
    end

    # (2.2) batch environment states - aka controller inputs
    sa = map(s->(s[end].input_symbol, s[end].prev_action), samples)
    inputs = zeros(length(s2i)+length(a2i), length(samples))
    for k = 1:length(sa) # symbol-action pairs
        inputs[s2i[sa[k][1]],k] = 1
        inputs[length(s2i)+a2i[sa[k][2]]] = 1
    end

    # (2.3) convert and propagate
    # FIXME: propagate is redundant
    atype = typeof(w[:wcont])
    targets = convert(atype, targets)
    inputs = convert(atype, inputs)
    h = h == nothing ? h : convert(atype,h)
    c = c == nothing ? c : convert(atype,c)
    discounts = reshape(discounts, 1, length(discounts))
    discounts = convert(atype, discounts)
    cout, h, c = propagate(w[:wcont], w[:bcont], inputs, h, c)

    # (2.4) main part - compute Q(s,a') over all possible actions
    # then, find which action maximizes it and select its value
    qsa0 = predict(w[:wact],w[:bact],cout)
    qsa1 = maximum(qsa0,1)
    qsa2 = sum(qsa0 .* (qsa1.==qsa0), 1)
    qsa3 = reshape(qsa2, 1, length(qsa2))

    targets += discounts .* qsa3
    return targets
end

# function make_batch(
#     obj::ReplayMemory, w, discount, nsteps, s2i, a2i, batchsize)
#     samples = sample(obj, batchsize, nsteps)
#     targets = compute_targets(samples, w, discount, nsteps, s2i, a2i)
#     atype = typeof(targets)

#     # xs <-> inputs (read symbol+previous action) - onehots
#     xs = zeros(length(s2i)+length(a2i),length(samples))
#     for (i,sample) in enumerate(samples)
#         xs[s2i[sample[1].input_symbol],i] = 1
#         xs[length(s2i)+a2i[sample[1].input_action],i] = 1
#     end
#     xs = convert(atype, xs)

#     # ys <-> output symbols
#     # as <-> actions
#     ys = map(s->s[1].output_symbol, samples); ys = map(yi->s2i[yi],ys)
#     as = map(s->s[1].output_action, samples); as = map(ai->a2i[ai],as)

#     h = c = nothing
#     if samples[1][1].h != nothing
#         h = mapreduce(s->s[1].h, hcat, samples)
#         h = convert(atype, h)
#     end
#     if samples[1][1].c != nothing
#         c = mapreduce(s->s[1].c, hcat, samples)
#         c = convert(atype, c)
#     end
#     vs = map(si->si[1].nsteps, samples)
#     vs = reshape(vs, 1, length(vs))
#     vs = convert(atype, vs)

#     return targets, xs, ys, as, h, c, vs
# end

max_stars_repo_name: ereday/algorithm-learning

max_issues_repo_name: ereday/algorithm-learning

max_forks_repo_name: ereday/algorithm-learning


text:
module TestExamples

using Test

examplesbase = joinpath(dirname(dirname(dirname(@__DIR__))), "examples")
examples = []
for (root, _, files) in walkdir(examplesbase)
    for name in files
        endswith(name, ".jl") || continue
        relname = joinpath(relpath(root, examplesbase), name)
        push!(examples, relname => joinpath(root, name))
    end
end

const modules = Dict()

function test(relname, fullpath)
    modules[relname] = m = Module()
    @eval m using LiterateTest.AssertAsTest: @assert
    Base.include(m, fullpath)
end

function test()
    @testset "$relname" for (relname, fullpath) in examples
        test(relname, fullpath)
    end
end

end  # module

ext: jl


text: @node typeof(+) Deterministic  [ out, in1, in2 ]


text:
"""
Library of custom function for HorizonSideRoots by Droideka501 \n
link to repository https://github.com/Droideka501/mirea-progs
"""

using Revise
using HorizonSideRobots
import HorizonSideRobots: move!, isborder, ismarker, putmarker!, temperature, HorizonSide

#------------------------------------------------------------#
"""
Structs

BackPath:
|               back!(::AbstractRobot, ::BackPath)
|               numSteps(::BackPath)

Robot
|
|--AbstactRobot:
|               move!(::AbstractRobot, ::HorizonSide)
|               isborder(::AbstractCoordRobot, ::HorizonSide)
|               putmarker!(::AbstractCoordRobot)
|               ismarker(::AbstractCoordRobot)
|               temperature(::AbstractCoordRobot)
|
|

"""
#------------------------------------------------------------#

"""
moves the robot to `(side, side)` corner and create the array of direction\n
default sides = (Sud, Ost)
"""
struct BackPath
    sides::NTuple{2, HorizonSide}
    path::Vector{Int}

    function BackPath(robot, sides::NTuple{2,HorizonSide}=(Sud, Ost))
        local path=[]
        while !isborder(robot, sides[1]) || !isborder(robot, sides[2])
            for s in sides
                push!(path, movesAndCounting!(robot, s))
            end
        end
        new(reverse(map(side -> reversSide(side), sides)), reverse(path))
    end
end

"""
returns the number of steps taken by the robot
"""
numSteps(back_path::BackPath)::Integer = sum(back_path.path)

"""
moves the robot to initial place
"""
function back!(robot, backpath::BackPath)
    i=1
    for n in backpath.path
        moves!(robot, backpath.sides[i], n)
        i = i%2 + 1
    end
end

"""

"""
function get_xy(back_path::BackPath)
    num_x, num_y = (0, 0)
    for i in 1:length(back_path.path)
        if iseven(i)
            num_y += back_path.path[i]
        else
            num_x += back_path.path[i]
        end
    end
    return (num_x, num_y)
end

#------------------------------------------------------------#

"""
coordinate structure\n
includes a function for changing coordinates and getting a tuple of coordinates
"""
mutable struct Coords
    x::Integer
    y::Integer
    Coords() = new(0, 0)
    Coords(x::Integer, y::Integer) = new(x, y)
end

"""
returns tuple of coordinates
"""
get_xy(coord::Coords) = (coord.x, coord.y)

"""
changes coordinates depending of `side`
"""
function move!(coord::Coords, side::HorizonSide)
    if side==Nord
        coord.y -= 1
    elseif side==Sud
        coord.y += 1
    elseif side==Ost
        coord.x += 1
    else
        coord.x -= 1
    end
end

#------------------------------------------------------------#

"""
an abstract type of robot that is a wrapper for the type ::Robot
"""
abstract type AbstractRobot end

"""
returs the link to the robot\n
typeof(get_robot(::AbstactRobot)) -> ::Robot
"""
get_robot(robot::AbstractRobot) = robot.robot

"""
returs the field coordinates of the robot\n
if robot
typeof(get_coords(::AbstactRobot)) -> ::Coords
"""
function get_coords(robot::AbstractRobot)
    if :coords in fieldnames(typeof(robot))
        return robot.coords
    else
        return error("This robot has not field coords")
    end
end

"""
returs the field flag of the robot\n
typeof(get_coords(::AbstactRobot)) -> ::Boll
"""
function get_flag(robot::AbstractRobot)
    if :flag in fieldnames(typeof(robot))
        return robot.flag
    else
        return error("This robot has not field flag")
    end
end

"""
returs the field flag of the robot\n
typeof(get_coords(::AbstactRobot)) -> ::Boll
"""
function get_number(robot::AbstractRobot)
    if :number in fieldnames(typeof(robot))
        return number.flag
    else
        return error("This robot has not field number")
    end
end

"""
applies the function `move!` to the field `robot`
"""
move!(robot::AbstractRobot, side::HorizonSide) = HorizonSideRobots.move!(get_robot(robot), side)

"""
applies the function `isborder` to the field `robot`
"""
isborder(robot::AbstractRobot,  side::HorizonSide) = HorizonSideRobots.isborder(get_robot(robot), side)

"""
applies the function `putmarker!` to the field `robot`

"""
putmarker!(robot::AbstractRobot) = HorizonSideRobots.putmarker!(get_robot(robot))

"""
applies the function `ismarker` to the field `robot`

"""
ismarker(robot::AbstractRobot) = HorizonSideRobots.ismarker(get_robot(robot))

"""
applies the function `temperature` to the field `robot`

"""
temperature(robot::AbstractRobot) = HorizonSideRobots.temperature(get_robot(robot))

#------------------------------------------------------------#

"""
robot with coordinates
"""
mutable struct CoordsRobot <: AbstractRobot
    robot::Robot
    coords::Coords
    CoordsRobot(robot) = new(robot, Coords())
end

"""
moves the robot and coordinates to a `side` direction
"""
function move!(robot::CoordsRobot, side::HorizonSide)
    move!(get_robot(robot), side)
    move!(get_coords(robot), side)
end

#------------------------------------------------------------#

"""

"""
mutable struct ChessRobot <: AbstractRobot
    robot::Robot
    flag::Bool
end

function move!(robot::ChessRobot, side::HorizonSide)
    move!(get_robot(robot), side)
    robot.flag = !get_flag(robot)
end

function putmarker!(robot::ChessRobot)
    if get_flag(robot)
        putmarker!(get_robot(robot))
    end
end

#------------------------------------------------------------#

"""

"""
abstract type AbstractCoordsRobot <: AbstractRobot end

function move!(robot::AbstractCoordsRobot, side::HorizonSide)
    move!(get_robot(robot), side)
    move!(get_coords(robot), side)
end

#------------------------------------------------------------#

"""

"""
mutable struct NChessRobot <: AbstractCoordsRobot
    robot::Robot
    coords::Coords
    number::Integer
end

function putmarker!(robot::NChessRobot)
    x, y = get_xy(get_coords(robot))
    x = x % (2*robot.number)
    y = y  % (2*robot.number)
    if abs(x) in (0:robot.number-1) && abs(y) in (0:robot.number-1) || abs(x) in (robot.number:2*robot.number-1) && abs(y) in (robot.number:2*robot.number-1)
        putmarker!(get_robot(robot))
    end
end

#------------------------------------------------------------#

"""

"""
mutable struct CrossRobot <: AbstractCoordsRobot
    robot::Robot
    coords::Coords
    flag::Bool
    dx::Integer
    dy::Integer
    function CrossRobot(robot, coords::Coords, flag::Bool, dX::Integer, dY::Integer)
        if dX == 0
            dx = 0
        else
            dx = div(dX, gcd(dX, dY))
        end
        if dY == 0
            dy = 0
        else
            dy = div(dY, gcd(dX, dY))
        end
        return new(robot, coords, flag, dx, dy)
    end
end

function move!(robot::CrossRobot, side::HorizonSide)
    robot.flag = false
    move!(get_robot(robot), side)
    move!(get_coords(robot), side)
    x, y = get_xy(get_coords(robot))
    if robot.dx == 0 || robot.dy == 0
        if x == 0 || y == 0
            robot.flag = true
        end
    elseif y//1 == robot.dx//robot.dy * x || x//1 == -(robot.dx//robot.dy) * y
        robot.flag = true
    end
end

function putmarker!(robot::CrossRobot)
    if get_flag(robot)
        putmarker!(get_robot(robot))
    end
end

#------------------------------------------------------------#
"""
Functions
"""
#------------------------------------------------------------#

"""
moves the robot in a `side` direction to the partition
"""
function moves!(r, side::HorizonSide)::Nothing
    while !isborder(r, side)
        move!(r, side)
    end
end

"""
moves the robot in a `side` direction `number` of times
"""
function moves!(r, side::HorizonSide, number::Integer)
    counter = 0
    for _ in 1:number
        if !isborder(r, side)
            move!(r, side)
            counter += 1
        else
            return number - counter
        end
    end
    return 0
end

"""
moves the robot to `side_to_move` direction along partition in a `side_of_partition` direction
"""
function movesAlong!(r, side_to_move::HorizonSide, side_of_partition::HorizonSide)::Nothing
    while isborder(r, side_of_partition)
        move!(r, side_to_move)
    end
end

"""
moves the robot in a `side` direction to the partition and checks if there is a partition in the `side_for_check` direction\n
returns `true` if there is a partition in the `side_for_check`, else `false`
"""
function movesAndCheck!(r, side::HorizonSide, side_for_check::HorizonSide)::Bool
    while !isborder(r, side)
        if isborder(r, side_for_check)
            return true
        end
        move!(r, side)
    end
    return false
end

"""
moves the robot in a `side` direction `number` of times and checks if there is a partition in the `side_for_check` direction\n
returns `true` if there is a partition in the `side_for_check`, else `false`
"""
function movesAndCheck!(r, side::HorizonSide, side_for_check::HorizonSide, number::Integer)::Bool
    for _ in 1:number
        if isborder(r, side_for_check)
            return true
        end
        move!(r, side)
    end
    return false
end

"""
moves the robot in a `side` direction to the partition and counting steps
"""
function movesAndCounting!(r, side::HorizonSide)::Integer
    count = 0
    while !isborder(r, side)
        move!(r, side)
        count+=1
    end
    return count
end

"""
moves the robot and put markers in a `side` direction to the partition
"""
function marksLine!(r, side::HorizonSide)::Nothing
    putmarker!(r)
    while tryToMove!(r, side)
        putmarker!(r)
    end
end

"""
moves the robot and put markers in a `side` direction `number` of times include start point\n
returns the number of successful steps
"""
function marksLine!(r, side::HorizonSide, number::Integer)::Integer
    putmarker!(r)
    for i in 1:(number-1)
        tryToMove!(r, side)
        putmarker!(r)
    end
    return number
end

"""
moves the robot if possible in a `side` direction one of times
"""
function oneStep!(r, side::HorizonSide)::Nothing
    if !isborder(r, side)
        move!(r, side)
    end
end

"""
moves the robot to a `direction_by_y`-`direction_by_x` angle\n
default directions `(Ost, Sud)`\n
returns stack of directions
"""
function moveAndReturnDirections!(r, direction_by_x::HorizonSide = Ost, direction_by_y::HorizonSide = Sud)::Vector{HorizonSide}
    arr_of_direction::Vector{HorizonSide} = []

    while !all(isborder(r, side) for side in (direction_by_x, direction_by_y))

        while !isborder(r, direction_by_x)
            move!(r, direction_by_x)
            push!(arr_of_direction, direction_by_x)
        end

        while !isborder(r, direction_by_y)
            move!(r, direction_by_y)
            push!(arr_of_direction, direction_by_y)
        end
    end
    return arr_of_direction
end

"""
moves the robot to a `direction_by_y`-`direction_by_x` angle\n
default directions `(Ost, Sud)`\n
"""
function moveToStartplace!(r, direction_by_x::HorizonSide = Ost, direction_by_y::HorizonSide = Sud)::Nothing
    while !all(isborder(r, side) for side in (direction_by_x, direction_by_y))
        moves!(r, direction_by_x)
        moves!(r, direction_by_y)
    end
end

"""
changes direction to the opposite
"""
function reversSide(side::HorizonSide)::HorizonSide
    return HorizonSide((Int(deepcopy(side))+2)%4)
end

"""
moves the robot to the start of the program
"""
function moveToBeginplace!(r, stack_of_direction::Vector{HorizonSide})::Nothing
    while length(stack_of_direction) > 0
        move!(r, reversSide(pop!(stack_of_direction)))
    end
end

"""
creating an array of sides shifted by `shift` clockwise
returns `Vector{HorizonSide}``
"""
function sidesWithShift(shift::Integer = 0)::Vector{HorizonSide}
    sides = [_ for _ in instances(HorizonSide)]
    for i in 1:shift
        for j in 1:(length(sides))
            temp = sides[1]
            sides[1] = sides[j]
            sides[j] = temp
        end
    end
    return sides
end

"""
puts markers in the entire area up to the partition from the `side`\n
`side_begin` - starting direction\n
`side_end` - the direction where the partition that restricts movement is located\n
`size_of_area` - size of n*n area
"""
function marksArea!(r, side_begin::HorizonSide = West, side_end::HorizonSide = Nord)::Nothing
    checker = false

    while !checker
        for side in (side_begin, reversSide(side_begin))
            putmarker!(r)
            moveAndPut!(r, side)
            if isborder(r, side_end)
                checker = true
                break
            end
            move!(r, side_end)
        end
    end
end

function marksArea!(r, size_of_area::Integer, side_begin::HorizonSide = West, side_end::HorizonSide = Nord)::Nothing
    size = size_of_area
    count = size
    for n in 1:size
        count = moveAndPut!(r, side_begin, count)
        side_begin = reversSide(side_begin)
        if !isborder(r, side_end)
            move!(r, side_end)
        else
            break
        end
    end
end

"""
moves the work on the markers in a `side` direction
"""
function moveWhileMarker!(r, side::HorizonSide)::Nothing
    while ismarker(r)
        if isborder(r, side)
            break
        end
        move!(r, side)
    end
end

"""
searches for an object inside the field, stops near the found face and returns the direction to the partition
"""
function searchObject!(r, side_begin::HorizonSide = West, side_end::HorizonSide = Nord)::HorizonSide
    checker = false
    counter = movesAndCounting!(r, side_end)
    moves!(r, reversSide(side_end))
    c = 0

    while !checker
        for side in instances(HorizonSide)
            for _ in 1:counter
                if isborder(r, nextSideConterclockwise(side))
                    checker = true
                    break
                end
                if isborder(r, side)
                    checker = true
                    side = nextSideClockwise(side)
                    break
                end
                move!(r, side)
            end

            if checker
                return side
            end
            c += 1
            if c == 2
                counter-=1
                c = 0
            end
        end
    end
end

"""
returns the following direction is counterclockwise
"""
function nextSideConterclockwise(side::HorizonSide)::HorizonSide
    return HorizonSide((Int(deepcopy(side))+1)%4)
end

"""
returns the following direction is clockwise
"""
function nextSideClockwise(side::HorizonSide)::HorizonSide
    return HorizonSide((Int(deepcopy(side))+3)%4)
end

"""
returns the coordinates of the robot relative to the start of a program\n
`sides` - array with directions
"""
function countingCoordinate(sides::Vector{HorizonSide})::Tuple{Integer, Integer}
    arr = deepcopy(sides)
    x = 0
    y = 0

    while length(arr)>0
        a = pop!(arr)
        if a == Sud
            y+=1
        elseif a == Nord
            y-=1
        elseif a == Ost
            x+=1
        else
            x-=1
        end
    end
    return (x, y)
end

"""
trying to move to `side_to_try` direction
"""
function tryMove!(r, side_to_try::HorizonSide = Ost)
    side_to_move = nextSideClockwise(side_to_try)
    checker_side = deepcopy(side_to_move)
    partition = true
    counter = 0

    if isborder(r, side_to_move) && isborder(r, side_to_try)
        side_to_move = reversSide(side_to_move)
    end

    while partition
        if isborder(r, side_to_try)
            partition = true
            tryMove!(r, side_to_move)
            counter += 1
        else
            partition = false
            move!(r, side_to_try)
            for _ in 1:counter
                tryMove!(r, reversSide(side_to_move))
            end
        end
    end

end

"""
trying to move to `side_to_try` direction\n
bypasses the the partitions conterclockwise\n
retuns `true` and move to `side_to_try` if can that\n
else returns `false` and stay initial position
"""
function tryToMoveConterclockwise!(r, side_to_try::HorizonSide)::Bool
    side_to_move = nextSideClockwise(side_to_try)
    counter = 0
    partition = true

    if !isborder(r, side_to_try)
        move!(r, side_to_try)
        return true
    end

    while partition

        if isborder(r, side_to_move) && isborder(r, side_to_try)
            moves!(r, reversSide(side_to_move), counter)
            return false
        end
        if isborder(r, side_to_try)
            partition = true
            move!(r, side_to_move)
            counter += 1
        else
            partition = false
            move!(r, side_to_try)
            movesAlong!(r, side_to_try, reversSide(side_to_move))
            moves!(r, reversSide(side_to_move), counter)
            return true
        end
    end
end

"""
trying to move to `side_to_try` direction\n
bypasses the the partitions clockwise\n
retuns `true` and move to `side_to_try` if can that\n
else returns `false` and stay initial position
"""
function tryToMoveClockwise!(r, side_to_try::HorizonSide)::Bool
    side_to_move = nextSideConterclockwise(side_to_try)
    counter = 0
    partition = true

    if !isborder(r, side_to_try)
        move!(r, side_to_try)
        return true
    end

    while partition

        if isborder(r, side_to_move) && isborder(r, side_to_try)
            moves!(r, reversSide(side_to_move), counter)
            return false
        end
        if isborder(r, side_to_try)
            partition = true
            move!(r, side_to_move)
            counter += 1
        else
            partition = false
            move!(r, side_to_try)
            movesAlong!(r, side_to_try, reversSide(side_to_move))
            moves!(r, reversSide(side_to_move), counter)
            return true
        end
    end
end

"""
trying to trying to move to `side_to_try` direction\n
if the partition cannot be bypassed returns false
"""
function tryToMove!(r, side_to_try::HorizonSide)
    checker = false
    if tryToMoveClockwise!(r, side_to_try)
        checker = true
    elseif tryToMoveConterclockwise!(r, side_to_try)
        checker = true
    end
    return checker
end

"""
marks the field in the specified order depending on the type of `robot`
"""
function marks!(r, sides::NTuple{2, HorizonSide} = (Nord, West))::Nothing
    side_to_move = sides[1]
    side_to_marks = sides[2]

    marksLine!(r, side_to_marks)
    while !isborder(r, side_to_move)
        tryToMove!(r, side_to_move)
        side_to_marks = reversSide(side_to_marks)
        marksLine!(r, side_to_marks)
    end
end

"""

"""
function tryToMoveModify!(r, side_to_try::HorizonSide)::Bool
    side_to_move = nextSideConterclockwise(side_to_try)
    steps = 1

    while isborder(r, side_to_try)
        side_to_move = reversSide(side_to_move)
        if moves!(r, side_to_move, steps) != 0
            moves!(r, reversSide(side_to_move), div(steps, 2))
            return false
        end
        steps += 1
    end

    move!(r, side_to_try)

    while isborder(r, reversSide(side_to_move))
        move!(r, side_to_try)
    end

    moves!(r, reversSide(side_to_move), div(steps, 2))
    return true
end

"""

"""
function movements!(r, side::HorizonSide)
    while tryToMoveModify!(r, side) end
end

"""

"""
function movements!(r, side::HorizonSide, number::Integer)
    for _ in 1:number
        tryToMoveModify!(r, side)
    end
end

"""

"""
function spiralBypass!(condition::Function, r::AbstractCoordsRobot)
    counter = 1
    side = HorizonSide(0)
    while !condition(r)
        moves!(r, side, counter)
        if Int(side) == 1 || Int(side) == 3
            counter+=1
        end
        side = nextSideConterclockwise(side)
    end
end

"""

"""
function counterPartition!(r::Robot, side_to_move::HorizonSide = Ost)
    counter = 0
    while !isborder(r, nextSideConterclockwise(side_to_move))
        while tryToMove!(r, side_to_move)
            if isborder(r, nextSideConterclockwise(side_to_move))
                movesAlong!(r, side_to_move, nextSideConterclockwise(side_to_move))
                counter+=1
            end
        end
        while tryToMove!(r, reversSide(side_to_move)) end
        move!(r, nextSideConterclockwise(side_to_move))
    end
    return counter
end


text:
module TreeFitStoppingCriterion

export max_depth_stopping_criterion, max_leaves_stopping_criterion

using ..JLBoostTrees: AbstractJLBoostTree, treedepth, get_leaf_nodes

function max_depth_stopping_criterion(depth)
    function (jlt::AbstractJLBoostTree)
        treedepth(jlt) >= depth
    end
end

function max_leaves_stopping_criterion(leaves)
    function (jlt::AbstractJLBoostTree)
        length(get_leaf_nodes(jlt)) >= leaves
    end
end

end


text:
# internal helper stuff for handling pattern matching

SimplePattern = Union{Regex,AbstractString,Function}
Pattern = Union{SimplePattern, AbstractArray}

matchany(p::Regex, s::AbstractString) = match(p,s)!=nothing
matchany(p::AbstractString, s::AbstractString) = match(Regex(p),s)!=nothing
matchany(p::Function, s::AbstractString) = p(s)

matchany(p::AbstractArray, s::AbstractString) = any(x->match(x,s)!=nothing,p)

matchany(p::Pattern, s::AbstractArray) = map!(x->matchany(p,x),falses(size(s)),s)


text:
using Makie
function img(m, n)
	a = zeros(Int, m, n)
	for (i, z) in enumerate(GoldenCartesianSequence((m, n)))
		a[z] = i
		i > m*n && break
	end
	!any(a .== 0) && @warn("Not spacefilling")
	a
end

m, n = 359, 451
m, n = @. denominator(rationalize(GoldenSequences.phis[2]^(-[1, 2]), tol=0.0000001))
@assert gcd(m, n) == 1
a = img(m, n)

pl = heatmap( -a[1:200, 1:200] )
save("cartesian1.png", pl)

pt(c) = Point2f0(c[1], c[2])

pl = scatter(pt.(take(GoldenCartesianSequence((m, n)), 20*20)), color=:red, markersize=20.0)
scatter!(pl, pt.(take(GoldenCartesianSequence((m, n)), m*n ÷ 525)), markersize=7.0)
#scatter!(pt.(take(GoldenCartesianSequence((m, n)), m*n ÷ 2)), grid=false, markersize=1.0)

save("cartesian2.png", pl)


text:
using Random
using Test

@testset "ExaTronKernels" begin
    using CUDA
    using AMDGPU
    using oneAPI
    @testset "CUDA.jl" begin
        if CUDA.has_cuda_gpu()
            include("CUDA.jl")
        end
    end
    @testset "AMDGPU.jl" begin
        if AMDGPU.has_rocm_gpu()
            include("AMDGPU.jl")
        end
    end
    @testset "oneAPI.jl" begin
        if oneAPI.functional()
            include("oneAPI.jl")
        end
    end
    @testset "KA.jl" begin
        if CUDA.has_cuda_gpu() || AMDGPU.has_rocm_gpu()
            include("KA.jl")
        end
    end
end


text:
#!/usr/bin/env julia

NUM_TRIALS = 10000
PRIOR_LOWER_MAX = 100

# Runs a single trial where an envelope is chosen.  If the chosen envelope has
# a value < cutoff, the function will switch envelopes, otherwise it will keep
# the envelope it has chosen. Returns the value of the envelope it ultimately
# selects.
function single_trial(cutoff)
  lower_value = rand() * PRIOR_LOWER_MAX
  higher_value = 2 * lower_value
  if rand(0:1) == 0
    return lower_value >= cutoff ? lower_value : higher_value
  else
    return higher_value >= cutoff ? higher_value : lower_value
  end
end

# Runs many trials at a given cutoff to approximate the expected value.
function multi_trial(cutoff)
  total_result = 0
  for _ = 1:NUM_TRIALS
    total_result = total_result + single_trial(cutoff)
  end
  return total_result / NUM_TRIALS
end

for cutoff = 1:2*PRIOR_LOWER_MAX
  println("cutoff=", cutoff, " expected_value=", multi_trial(cutoff))
end

max_stars_repo_name: dfings/two-envelopes-problem

max_issues_repo_name: dfings/two-envelopes-problem

max_forks_repo_name: dfings/two-envelopes-problem


text:
# The actual relative path of the package as specified in the `Registry.toml` file.
function get_package_relpath_in_registry(; package_name::String, registry_path::String)
    registry_toml_file_name = joinpath(registry_path, "Registry.toml")
    registry_toml_parsed = TOML.parsefile(registry_toml_file_name)
    all_packages = registry_toml_parsed["packages"]
    all_package_names_and_paths = map(x -> (x["name"], x["path"]), values(all_packages))
    matching_package_indices = findall(
        getindex.(all_package_names_and_paths, 1) .== package_name
    )
    num_indices = length(matching_package_indices)
    (num_indices == 0) &&
        throw(ErrorException("no package found with the name $(package_name)"))
    (num_indices != 1) && throw(
        ErrorException(
            "multiple ($(num_indices)) packages found with the name $(package_name)"
        ),
    )
    single_matching_index = only(matching_package_indices)
    single_matching_package = all_package_names_and_paths[single_matching_index]
    _pkgname, _pkgrelpath = single_matching_package
    always_assert(_pkgname == package_name)
    _pkgrelpath::String
    return _pkgrelpath
end

# What the relative path of the package *should* be, in theory.
# This function should ONLY be used in the
# "PR only changes a subset of the allowed files" check.
# For all other uses, you shoud use the `get_package_relpath_in_registry`
# function instead.
function _get_package_relpath_per_name_scheme(; package_name::String)
    return RegistryTools.package_relpath(package_name)
end


text:
import SparseArrays:
    SparseMatrixCSC, AbstractSparseMatrix, nnz, nonzeros, nzvalview,
    dropzeros!, dropzeros

# For adding a method
import SparseArrays: spzeros, sparse

export
    SparseMatrixCOO

"""
    SparseMatrixCOO{Tv,Ti<:Integer} <: AbstractSparseMatrix{Tv,Ti}

Matrix type for storing sparse matrices in the
Coordinate list form (COO) format.
"""
struct SparseMatrixCOO{Tv, Ti<:Integer} <: SparseArrays.AbstractSparseMatrix{Tv, Ti}
    m::Int
    n::Int
    Ir::Vector{Ti}
    Ic::Vector{Ti}
    nzval::Vector{Tv}
    function SparseMatrixCOO(m, n, Ir::Vector{Ti}, Ic::Vector{Ti}, nzval::Vector{Tv}) where {Ti <: Integer, Tv}
        length(Ir) == length(Ic) == length(nzval) || throw(DimensionMismatch("Ir, Ic, and nzval must have the same length."))
        (!isempty(Ir) && m < maximum(Ir)) &&
            throw(DimensionMismatch("Maximum row index $(maximum(Ir)) greater than row dimension $m."))
        (!isempty(Ic) && n < maximum(Ic)) && throw(DimensionMismatch("Maximum column index greater than column dimension."))
        new{Tv, Ti}(m, n, Ir, Ic, nzval)
    end
end

# Yes, we need this. It would have prevented a bug.
_splat_fields(S::SparseMatrixCOO) = (S.m, S.n, S.Ir, S.Ic, S.nzval)

#Base.length(coo::SparseMatrixCOO) = prod(size(coo))
Base.size(coo::SparseMatrixCOO) = (coo.m, coo.n)
#Base.eltype(coo::SparseMatrixCOO{Tv, Ti}) where {Tv, Ti} = Tv
Base.getindex(S::SparseMatrixCOO, i::Integer, j::Integer) = IJV.getindex(S.Ir, S.Ic, S.nzval, i, j)
Base.setindex!(S::SparseMatrixCOO, val, i::Integer, j::Integer) = IJV.setindex!(S.Ir, S.Ic, S.nzval, val, i, j)
SparseArrays.dropstored!(S::SparseMatrixCOO, i::Integer, j::Integer) = (IJV.dropstored!(S.Ir, S.Ic, S.nzval, i, j); S)

"""
    sparse(I, J, V, m, n; sparsetype=SparseMatrixCOO)

Create a sparse matrix of type SparseMatrixCOO.
"""
sparse(I, J, V, m, n; sparsetype=SparseMatrixCOO) = SparseMatrixCOO(m, n, I, J, V)

"""
    issorted(S::SparseMatrixCOO)

Return `true` if the data structures in `S` storing non-zero indices
are canonically sorted. If the data structures are not sorted,
then functions taking an `SparseMatrixCOO`
argument will, in general, give incorrect results.
"""
Base.issorted(S::SparseMatrixCOO) = IJV.issorted(S.Ir, S.Ic)

"""
    spzeros([type,] m,n; sparsetype=SparseMatrixCOO)

Create a sparse matrix of size `mxn`. If `sparsetype` is ommited,
a matrix of type `SparseMatrixCSC` will be created.
"""
spzeros(args...; sparsetype=Type{SparseMatrixCOO}) = SparseMatrixCOO(IJV.spzeros(args...)...)
"""
    nnz(A::SparseMatrixCOO)

Return the number of stored (filled) elements in `A`.
"""
nnz(coo::SparseMatrixCOO) = length(coo.Ir)
nonzeros(coo::SparseMatrixCOO) = coo.nzval
ncols(coo::SparseMatrixCOO) = coo.n
nrows(coo::SparseMatrixCOO) = coo.m

# The @inline decorations and the hardcoding of functions in reduction increase
# speed dramatically. But, this may depend on Julia version.

@inline nzvalview(S::SparseMatrixCOO) = view(S.nzval, 1:nnz(S))
@inline Base.count(pred, S::SparseMatrixCOO) = NZVal.count(pred, S.m, S.n, nzvalview(S), length(S.nzval))

## FIXME: this is probably never called because SparseMatrixCOO is not a AbstractArray
Base._mapreduce(f, op, ::Base.IndexCartesian, S::SparseMatrixCOO) =
    NZVal._mapreduce(f, op, Base.IndexCartesian(), S.m, S.n, nzvalview(S), nnz(S))

@inline Base._mapreduce(f, op, S::SparseMatrixCOO) =
    NZVal._mapreduce(f, op, S.m, S.n, nzvalview(S), nnz(S))

for (fname, op) in ((:sum, :add_sum), (:maximum, :max), (:minimum, :min), (:prod, :mul_prod))
    @eval @inline (Base.$fname)(f::Callable, S::SparseMatrixCOO) = Base._mapreduce(f, Base.$op, S)
    @eval @inline (Base.$fname)(S::SparseMatrixCOO) = Base._mapreduce(identity, Base.$op, S)
end

@inline Base._mapreduce(f, op::Union{typeof(*), typeof(Base.mul_prod)}, S::SparseMatrixCOO{T}) where T =
    NZVal._mapreduce(f, op, S.m, S.n, nzvalview(S), nnz(S))

@inline Base.mapreduce(f, op, S::SparseMatrixCOO) = # Base._mapreduce(f, op, Base.IndexCartesian(), S)
    Base._mapreduce(f, op, S)

Base.copy(S::SparseMatrixCOO) =
    SparseMatrixCOO(S.m, S.n, Base.copy(S.Ir), Base.copy(S.Ic), Base.copy(S.nzval))

for fname in (:dropzeros, :dropzeros!)
    @eval ($fname)(S::SparseMatrixCOO) = (IJV.$fname)(S.Ir, S.Ic, S.nzval)
end

Base.:(==)(S::SparseMatrixCOO, V::SparseMatrixCOO) =
    S.m == V.m &&  S.n == V.n && S.Ir == V.Ir && S.nzval == V.nzval

# The following is somewhat inefficient. Iterating over nzvalview(coo) directly is better.
# But, defining `iterate` allows methods to be called with no more work.
Base.iterate(coo::SparseMatrixCOO, args...) = Base.iterate(SparseArrays.nzvalview(coo), args...)

### Conversion

"""
    SparseMatrixCOO(S::SparseMatrixCSC)

Convert `S` to type `SparseMatrixCOO`.
"""
SparseMatrixCOO(spcsc::SparseMatrixCSC) =
    SparseMatrixCOO(nrows(spcsc), ncols(spcsc), SparseArrays.findnz(spcsc)...)
"""
    SparseMatrixCSC(S::SparseMatrixCOO)

Convert `S` to type `SparseMatrixCSC`.
"""
SparseMatrixCSC(coo::SparseMatrixCOO) = SparseArrays.sparse(coo.Ir, coo.Ic, coo.nzval, coo.m, coo.n)
"""
    Array(S::SparseMatrixCOO)

Convert `S` to a dense matrix.
"""
Base.Array(S::SparseMatrixCOO) = IJV.Array(_splat_fields(S)...)

"""
    prunecols(S::SparseMatrixCOO, min_entries; renumber=true)

Remove all columns from `S` that have fewer than `min_entries` non-zero
entries. If `renumber` is `true`, renumber the remaining columns
consecutively starting from `1`.
"""
prunecols(S::SparseMatrixCOO, min_entries; renumber=true) =
    SparseMatrixCOO(IJV.prunecols(_splat_fields(S)..., min_entries; renumber=renumber)...)

"""
    prunerows(S::SparseMatrixCOO, min_entries; renumber=true)

Remove all rows from `S` that have fewer than `min_entries` non-zero
entries. If `renumber` is `true`, renumber the remaining rows
consecutively starting from `1`.
"""
prunerows(S::SparseMatrixCOO, min_entries; renumber=true) =
    SparseMatrixCOO(IJV.prunerows(_splat_fields(S)..., min_entries; renumber=renumber)...)

for f in (:rotr90, :rotl90, :rot180)
    ijvf = Symbol(f, "!")
    @eval (Base.$f)(S::SparseMatrixCOO) = SparseMatrixCOO((IJV.$ijvf)(S.m, S.n, copy(S.Ir), copy(S.Ic), copy(S.nzval))...)
end

@doc """
    rotr90(S::SparseMatrixCOO)
rotate `S` clockwise 90 degrees.
""" rotr90

@doc """
    rotl90(S::SparseMatrixCOO)
rotate `S` counter-clockwise 90 degrees.
""" rotl90

@doc """
    rot180(S::SparseMatrixCOO)
rotate `S` 180 degrees.
""" rot180

"""
    permutedims!(S::SparseMatrixCOO)

Permute dimensions `1` and `2` of `S` in place.
"""
Base.permutedims!(S::SparseMatrixCOO) = SparseMatrixCOO(IJV.permutedims!(_splat_fields(S)...)...)
#Base.permutedims!(S::SparseMatrixCOO) = SparseMatrixCOO(IJV.permutedims!(S.m, S.n, S.Ir, S.Ic, S.nzval)...)

"""
    permutedims(S::SparseMatrixCOO)

Like `permutedims!`, but return a copy.
"""
Base.permutedims(S::SparseMatrixCOO) = permutedims!(copy(S))
## FIXME. The two below should be recursive
Base.copy(S::LinearAlgebra.Transpose{T, SparseMatrixCOO{T,V}}) where {T,V} = Base.permutedims(S.parent)
Base.copy(S::LinearAlgebra.Adjoint{T, SparseMatrixCOO{T,V}}) where {T,V} = conj(Base.permutedims(S.parent))

# We are now testing SparseMatrixCOO <: AbstractSparseMatrix
# The would require reproducing a lot of code that assumes the sparse matrix is an AbstractArray
#Base.transpose(S::SparseMatrixCOO) = throw(DomainError("Tranpose not implemented because `SparseMatrixCOO` is not an `AbstractArray`"))

"""
    sprand(args...; sparsetype=SparseMatrixCOO)

Create a random matrix of type `sparsetype`. See the other methods of `sprand`
for information on `args`.
"""
function SparseArrays.sprand(args...; sparsetype=Type{SparseMatrixCOO})
    if sparsetype == SparseMatrixCOO
        return SparseMatrixCOO(IJV.sprand(args...)...)
    elseif sparsetype == SparseMatrixCSC
        return SparseArrays.sprand(args...)
    else
        throw(ArgumentError("Unsupported sparse matrix type"))
    end
end


text:
module TableLogger

using Formatting

"""
    struct TableSetup

Stores information about the columns of the table by storing:
ids, names, widths, alignments and precision
"""
struct TableSetup
    ids::Vector{Symbol}
    names::Vector{String}
    widths::Vector{Int}
    alignments::Vector{Symbol}
    precisions::Vector{Int}
end

"""
    DiffX{V,B}

Can be used to specify the absolute difference which makes the given value different enough
from the previous value to print a new line.
As an example if the last value is `DiffX(5, 10)` and the new value is `DiffX(5, 12)` the change is not significant enough.
If the next value however is `DiffX(5, 15)` then the value is different enough from the last printed value `10`.
Therefore a new line is printed.
"""
struct DiffX{V,B}
    by::B
    value::V
end

"""
    DiffX(by)

Create an anonymous function with something like `Diffd1 = DiffX(0.1)` to be able to use `Diffd1(10.0)` instead of `DiffX(0.1, 10.0)`.
"""
function DiffX(by)
    return (val)->DiffX(by, val)
end

const Diff5 = DiffX(5)
const Diff10 = DiffX(10)

"""
    mutable struct Table

Stores the [`TableSetup`](@ref) as well as the current and previous values
"""
mutable struct Table
    setup::TableSetup
    current_values::Vector
    prev_values::Vector
end

include("utils.jl")
include("format.jl")
include("header.jl")
include("line.jl")

"""
    init_log_table(ids::Vector{Symbol}, names::Vector{String}, widths::Vector{Int}, alignments::Vector{Symbol}, precisions::Vector{Int})

Initialize the table structure with a vector of ids, names, widths, alignments and precisions.
"""
function init_log_table(ids::Vector{Symbol}, names::Vector{String}, widths::Vector{Int}, alignments::Vector{Symbol}, precisions::Vector{Int})
    @assert length(ids) == length(names)
    @assert length(ids) == length(widths)
    @assert length(ids) == length(alignments)
    @assert length(ids) == length(precisions)
    current_values = Vector{Any}(undef, length(ids))
    prev_values = Vector{Any}(undef, length(ids))
    return Table(TableSetup(ids, names, widths, alignments, precisions), current_values, prev_values)
end

"""
    init_log_table(columns::NamedTuple...; width=20, alignment=:center, precision=2)

Initialize the table structure by a list of information for each column.

## Example
```
table = init_log_table(
    (id=:open_nodes, name="#Open", width=30),
    (id=:closed_nodes, name="#Closed"),
)
```

Would create a table with two columns named `#Open` and `#Closed` and the width of `#Open` is `30`.
The default width of `20` is used for the closed nodes and both tables use the default alignment `:center`.

```
table = init_log_table(
    (id=:open_nodes, name="#Open", width=30),
    (id=:closed_nodes, name="#Closed");
    alignment = :left
)
```

In this case the default alignment is changed to `:left`.
"""
function init_log_table(columns::NamedTuple...; width=20, alignment=:center, precision=2)
    ids = Vector{Symbol}()
    names = Vector{String}()
    widths = Vector{Int}()
    alignments = Vector{Symbol}()
    precisions = Vector{Int}()
    for column in columns
        push!(ids, column.id)
        push!(names, column.name)
        if haskey(column, :width)
            push!(widths, column.width)
        else
            push!(widths, width)
        end
        if haskey(column, :alignment)
            push!(alignments, column.alignment)
        else
            push!(alignments, alignment)
        end
        if haskey(column, :precision)
            push!(precisions, column.precision)
        else
            push!(precisions, precision)
        end
    end
    return init_log_table(ids, names, widths, alignments, precisions)
end

export init_log_table, print_header, print_line, set_value!
export DiffX, Diff5, Diff10
end


text:
using LightXML

# Modified from the documentation for LightXML.jl. The underlying library requires an encoding string be printed.

# create an empty XML document
xdoc = XMLDocument()

# create & attach a root node
xroot = create_root(xdoc, "root")

# create the first child
xs1 = new_child(xroot, "element")

# add the inner content
add_text(xs1, "some text here")

println(xdoc)

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
"""
Mutates each particle
* `model`: model containing a likelihood function with data and priors
* `de`: differential evolution object
* `group`: a group of particles
"""
function mutation!(model, de, group)
    @unpack σ,bounds = de
    noise = Normal(0.0, σ)
    for pt in group
        # add noise to each parameter
        proposal = pt + noise
        # ensure that bounds are respected
        enforce_bounds!(bounds, proposal)
        # add Loglikelihood of prior to particle weight
        proposal.weight = priorlike(model, proposal) + model.model(proposal.Θ)
        # update whether proposal was accepted and add proposal if accepted
        update_particle!(de, pt, proposal)
    end
    return nothing
end


text:
import PredictMD

abstract type AbstractTestGroup end

struct TestGroupDefault <: AbstractTestGroup end

struct TestGroupAll <: AbstractTestGroup end

struct TestGroupTestPlots <: AbstractTestGroup end

struct TestGroupImportOnly <: AbstractTestGroup end

struct TestGroupTravis1 <: AbstractTestGroup end
struct TestGroupTravis2 <: AbstractTestGroup end
struct TestGroupTravis3 <: AbstractTestGroup end
struct TestGroupTravis4 <: AbstractTestGroup end
struct TestGroupTravis5 <: AbstractTestGroup end
struct TestGroupTravis6 <: AbstractTestGroup end
struct TestGroupTravis7 <: AbstractTestGroup end

struct TestGroupDocker1 <: AbstractTestGroup end
struct TestGroupDocker2 <: AbstractTestGroup end
struct TestGroupDocker3 <: AbstractTestGroup end
struct TestGroupDocker4 <: AbstractTestGroup end

const TEST_GROUP_STRING_TO_INSTANCE = Dict{String, AbstractTestGroup}(
    #
    "default" => TestGroupDefault(),
    #
    "all" => TestGroupAll(),
    #
    "test-plots" => TestGroupTestPlots(),
    #
    "import-only" => TestGroupImportOnly(),
    #
    "travis-1" => TestGroupTravis1(),
    "travis-2" => TestGroupTravis2(),
    "travis-3" => TestGroupTravis3(),
    "travis-4" => TestGroupTravis4(),
    "travis-5" => TestGroupTravis5(),
    "travis-6" => TestGroupTravis6(),
    "travis-7" => TestGroupTravis7(),
    #
    "docker-1" => TestGroupDocker1(),
    "docker-2" => TestGroupDocker2(),
    "docker-3" => TestGroupDocker3(),
    "docker-4" => TestGroupDocker4(),
    )

const TEST_GROUP_INSTANCE_TO_STRING = PredictMD.inverse(
    TEST_GROUP_STRING_TO_INSTANCE
    )


text:
using Glob
import Oceananigans.Fields: set!

using Oceananigans: fields
using Oceananigans.Fields: offset_data
using Oceananigans.TimeSteppers: RungeKutta3TimeStepper, QuasiAdamsBashforth2TimeStepper

mutable struct Checkpointer{T, P} <: AbstractOutputWriter
    schedule :: T
    dir :: String
    prefix :: String
    properties :: P
    overwrite_existing :: Bool
    verbose :: Bool
    cleanup :: Bool
end

"""
    Checkpointer(model; schedule,
                 dir = ".",
                 prefix = "checkpoint",
                 overwrite_existing = false,
                 cleanup = false,
                 additional_kwargs...)

Construct a `Checkpointer` that checkpoints the model to a JLD2 file on `schedule.`
The `model.clock.iteration` is included in the filename to distinguish between multiple checkpoint files.

To restart or "pickup" a model from a checkpoint, specify `pickup=true` when calling `run!`, ensuring
that the checkpoint file is the current working directory. See

```julia
help> run!
```
for more details.

Note that extra model `properties` can be safely specified, but removing crucial properties
such as `:velocities` will make restoring from the checkpoint impossible.

The checkpointer attempts to serialize as much of the model to disk as possible,
but functions or objects containing functions cannot be serialized at this time.

Keyword arguments
=================
- `schedule` (required): Schedule that determines when to checkpoint.

- `dir`: Directory to save output to. Default: "." (current working directory).

- `prefix`: Descriptive filename prefixed to all output files. Default: "checkpoint".

- `overwrite_existing`: Remove existing files if their filenames conflict. Default: `false`.

- `verbose`: Log what the output writer is doing with statistics on compute/write times
             and file sizes. Default: `false`.

- `cleanup`: Previous checkpoint files will be deleted once a new checkpoint file is written.
             Default: `false`.

- `properties`: List of model properties to checkpoint. This list must contain
                `[:grid, :architecture, :timestepper, :particles]`.
                Default: [:architecture, :grid, :clock, :coriolis, :buoyancy, :closure,
                          :velocities, :tracers, :timestepper, :particles]
"""
function Checkpointer(model; schedule,
                      dir = ".",
                      prefix = "checkpoint",
                      overwrite_existing = false,
                      verbose = false,
                      cleanup = false,
                      properties = [:architecture, :grid, :clock, :coriolis,
                                    :buoyancy, :closure, :timestepper, :particles])

    # Certain properties are required for `restore_from_checkpoint` to work.
    required_properties = (:grid, :architecture, :timestepper, :particles)

    for rp in required_properties
        if rp ∉ properties
            @warn "$rp is required for checkpointing. It will be added to checkpointed properties"
            push!(properties, rp)
        end
    end

    for p in properties
        p isa Symbol || error("Property $p to be checkpointed must be a Symbol.")
        p ∉ propertynames(model) && error("Cannot checkpoint $p, it is not a model property!")

        if (p ∉ required_properties) && has_reference(Function, getproperty(model, p))
            @warn "model.$p contains a function somewhere in its hierarchy and will not be checkpointed."
            filter!(e -> e != p, properties)
        end
    end

    mkpath(dir)

    return Checkpointer(schedule, dir, prefix, properties, overwrite_existing, verbose, cleanup)
end

#####
##### Checkpointer utils
#####

""" Returns the full prefix (the `superprefix`) associated with `checkpointer`. """
checkpoint_superprefix(prefix) = prefix * "_iteration"

"""
    checkpoint_path(iteration::Int, c::Checkpointer)

Returns the path to the `c`heckpointer file associated with model `iteration`.
"""
checkpoint_path(iteration::Int, c::Checkpointer) =
    joinpath(c.dir, string(checkpoint_superprefix(c.prefix), iteration, ".jld2"))

# This is the default name used in the simulation.output_writers ordered dict.
defaultname(::Checkpointer, nelems) = :checkpointer

""" Returns `filepath`. Shortcut for `run!(simulation, pickup=filepath)`. """
checkpoint_path(filepath::AbstractString, output_writers) = filepath

function checkpoint_path(pickup, output_writers)
    checkpointers = filter(writer -> writer isa Checkpointer, collect(values(output_writers)))
    length(checkpointers) == 0 && error("No checkpointers found: cannot pickup simulation!")
    length(checkpointers) > 1 && error("Multiple checkpointers found: not sure which one to pickup simulation from!")
    return checkpoint_path(pickup, first(checkpointers))
end

"""
    checkpoint_path(pickup::Bool, checkpointer)

For `pickup=true`, parse the filenames in `checkpointer.dir` associated with
`checkpointer.prefix` and return the path to the file whose name contains
the largest iteration.
"""
function checkpoint_path(pickup::Bool, checkpointer::Checkpointer)
    filepaths = glob(checkpoint_superprefix(checkpointer.prefix) * "*.jld2", checkpointer.dir)

    if length(filepaths) == 0 # no checkpoint files found
        # https://github.com/CliMA/Oceananigans.jl/issues/1159
        @warn "pickup=true but no checkpoints were found. Simulation will run without picking up."
        return nothing
    else
        return latest_checkpoint(checkpointer, filepaths)
    end
end

function latest_checkpoint(checkpointer, filepaths)
    filenames = basename.(filepaths)
    leading = length(checkpoint_superprefix(checkpointer.prefix))
    trailing = length(".jld2") # 5
    iterations = map(name -> parse(Int, name[leading+1:end-trailing]), filenames)
    latest_iteration, idx = findmax(iterations)
    return filepaths[idx]
end

#####
##### Writing checkpoints
#####

function write_output!(c::Checkpointer, model)
    filepath = checkpoint_path(model.clock.iteration, c)
    c.verbose && @info "Checkpointing to file $filepath..."

    t1 = time_ns()
    jldopen(filepath, "w") do file
        file["checkpointed_properties"] = c.properties
        serializeproperties!(file, model, c.properties)

        model_fields = fields(model)
        field_names = keys(model_fields)
        for name in field_names
            serializeproperty!(file, string(name), model_fields[name])
        end
    end

    t2, sz = time_ns(), filesize(filepath)
    c.verbose && @info "Checkpointing done: time=$(prettytime((t2-t1)/1e9)), size=$(pretty_filesize(sz))"

    c.cleanup && cleanup_checkpoints(c)

    return nothing
end

function cleanup_checkpoints(checkpointer)
    filepaths = glob(checkpoint_superprefix(checkpointer.prefix) * "*.jld2", checkpointer.dir)
    latest_checkpoint_filepath = latest_checkpoint(checkpointer, filepaths)
    [rm(filepath) for filepath in filepaths if filepath != latest_checkpoint_filepath]
    return nothing
end

#####
##### set! for checkpointer filepaths
#####

set!(model, ::Nothing) = nothing

"""
    set!(model, filepath::AbstractString)

Set data in `model.velocities`, `model.tracers`, `model.timestepper.Gⁿ`, and
`model.timestepper.G⁻` to checkpointed data stored at `filepath`.
"""
function set!(model, filepath::AbstractString)

    jldopen(filepath, "r") do file

        # Validate the grid
        checkpointed_grid = file["grid"]

        model.grid == checkpointed_grid ||
             error("The grid associated with $filepath and model.grid are not the same!")

        model_fields = fields(model)

        for name in propertynames(model_fields)
            try
                parent_data = file["$name/data"]
                model_field = model_fields[name]
                copyto!(model_field.data.parent, parent_data)
            catch
                @warn "Could not retore $name from checkpoint."
            end
        end

        set_time_stepper!(model.timestepper, file, model_fields)

        if !isnothing(model.particles)
            copyto!(model.particles.properties, file["particles"])
        end

        checkpointed_clock = file["clock"]

        # Update model clock
        model.clock.iteration = checkpointed_clock.iteration
        model.clock.time = checkpointed_clock.time
    end

    return nothing
end

function set_time_stepper_tendencies!(timestepper, file, model_fields)
    for name in propertynames(model_fields)
        # Tendency "n"
        parent_data = file["timestepper/Gⁿ/$name/data"]

        tendencyⁿ_field = timestepper.Gⁿ[name]
        copyto!(tendencyⁿ_field.data.parent, parent_data)

        # Tendency "n-1"
        parent_data = file["timestepper/G⁻/$name/data"]

        tendency⁻_field = timestepper.G⁻[name]
        copyto!(tendency⁻_field.data.parent, parent_data)
    end

    return nothing
end

set_time_stepper!(timestepper::RungeKutta3TimeStepper, file, model_fields) =
    set_time_stepper_tendencies!(timestepper, file, model_fields)

function set_time_stepper!(timestepper::QuasiAdamsBashforth2TimeStepper, file, model_fields)
    set_time_stepper_tendencies!(timestepper, file, model_fields)
    timestepper.previous_Δt = file["timestepper/previous_Δt"]
    return nothing
end


text:
#!/usr/bin/env julia

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

using CSV
using Tables

function read_data_file(filename::String)
    CSV.File(filename; header=false, skipto=6) |> Tables.matrix
end

function parse_width_and_thickness(filename::String)
    l::String = ""
    for (i, line) in enumerate(eachline(filename))
        l = line
        if i == 3
          break
        end
   end
   first_split_string = split(l, ",")
   width = parse(Float64, strip(split(first_split_string[3], "=")[2], '"'))
   thickness = parse(Float64, split(split(first_split_string[4], "=")[2], '"')[1])
   (width, thickness)
end

function convert_to_true_stress_and_strain(filename::String)

end

function compute_toughness(filename::String)

end

end


text:
module ImageInspector

using Colors
using Requires

export image, imagegrid

const ImArray{T<:Real} = Union{AbstractArray{T,3}, AbstractArray{T,4}}

"""
    image(x::AbstractMatrix{T}; flip = true)

Converts a matrix of real numbers to the matrix of `Gray` points. If the keyword argument
`flip` is true, the resulting matrix is transposed.

# Example

```julia-repl
julia> x = [0.1 0.25; 0.4 0.6]
2×2 Array{Float64,2}:
 0.1  0.25
 0.4  0.6

julia> image(x)
2×2 Array{Gray{Float64},2} with eltype Gray{Float64}:
 Gray{Float64}(0.1)   Gray{Float64}(0.4)
 Gray{Float64}(0.25)  Gray{Float64}(0.6)

julia> image(x; flip = false)
2×2 Array{Gray{Float64},2} with eltype Gray{Float64}:
 Gray{Float64}(0.1)  Gray{Float64}(0.25)
 Gray{Float64}(0.4)  Gray{Float64}(0.6)
```
"""
function image(x::AbstractMatrix{T}; flip = true) where {T <: Real}
    xx = flip ? PermutedDimsArray(x, (2, 1)) : x
    return Gray.(xx)
end

function image(x::AbstractArray{T,3}; flip = true) where {T <: Real}
    s = size(x, 3)
    if s == 1
        return image(dropdims(x; dims = 3); flip)
    elseif s == 3
        xx = flip ? PermutedDimsArray(x, (2, 1, 3)) : x
        return RGB.(eachslice(xx; dims= 3)...)
    else
        throw(ArgumentError("unsupported size of the third dimension $(s) ∉ [1,3]."))
    end
end

function image(x::ImArray, inds; flip = true)
    return [image(selectdim(x, ndims(x), i); flip) for i in inds]
end
image(x::ImArray, ind::Int; flip = true) = image(x, [ind]; flip)[1]

function gridsize(n::Int; nrows::Int = -1, ncols::Int = - 1)
    if nrows < 1
        if ncols < 1
            nrows = round(Int, sqrt(n))
            ncols = ceil(Int, n / nrows)
        else
            nrows = ceil(Int, n / ncols)
        end
    else
        ncols = ceil(Int, n / nrows)
    end
    return nrows, ncols
end

imagegrid(x, ind::Int; flip = true, kwargs...) = image(x, ind; flip)

function imagegrid(x, inds; flip = true, sep = 1, kwargs...)
    imgs = image(x, inds; flip)
    n = length(imgs)
    nrows, ncols = gridsize(n; kwargs...)

    h, w = size(imgs[1])
    A = fill(
        eltype(imgs[1])(1), # white color in proper color type
        nrows*h + (nrows + 1)*sep, # height of the reculting image
        ncols*w + (ncols + 1)*sep, # width of the reculting image
    )

    for i in 1:nrows, j in 1:ncols
        k = j + (i - 1) * ncols
        k > n && break

        rows = (1:h) .+ (i - 1)*h .+ i*sep
        cols = (1:w) .+ (j - 1)*w .+ j*sep
        A[rows, cols] = imgs[k]
    end
    return A
end

function __init__()
    @require Plots="91a5bcdd-55d7-5caf-9e0b-520d859cae80" include("imageplot.jl")
end

end


text:
using OrdinaryDiffEq, DiffEqMonteCarlo, Distributions, Test

include("koopman.jl")

function f(du,u,p,t)
  du[1] = dx = p[1]*u[1] - u[1]*u[2]
  du[2] = dy = -3*u[2] + u[1]*u[2]
end

u0 = [1.0;1.0]
tspan = (0.0,10.0)
p = [1.5]
prob = ODEProblem(f,u0,tspan,p)
sol = solve(remake(prob,u0=u0),Tsit5())
cost(sol) = sum(max(x[1]-12,0) for x in sol.u)
u0s = [Uniform(0.25,5.5),Uniform(0.25,5.5)]
ps  = [Uniform(0.5,2.0)]
@time c1, _ = koopman_cost(u0s, ps, cost, prob, Tsit5();saveat=0.1, use_vegas = true)
@time c2 = montecarlo_cost(u0s, ps, cost, prob, Tsit5(); num_monte = 100000, saveat = 0.1)
@show c1, c2

#=function f2(du,u,p,t)
  du[1] = dx = p[1]*u[1] - p[2]*u[1]*u[2]
  du[2] = dy = -p[3]*u[2] + p[4]*u[1]*u[2]
end

u0 = [1.0;1.0]
tspan = (0.0,10.0)
p = [1.5,1.0,3.0,1.0]
prob = ODEProblem(f2,u0,tspan,p)
cost(sol) = sum(max(x[1]-6,0) for x in sol.u)
u0s = [Uniform(0.25,5.5),Uniform(0.25,5.5)]
ps  = [Uniform(0.5,2.0), Uniform(0.5, 1.5), Uniform(2.5, 3.5), Uniform(0.5, 1.5)]
@time c1, _ = koopman_cost(u0s, ps, cost, prob, Tsit5();saveat=0.1, use_vegas = true)
@time c2 = montecarlo_cost(u0s, ps, cost, prob, Tsit5(); num_monte = 100000, saveat = 0.1)
@show c1, c2
=#


text:
# ---
# title: Legend tweaking
# cover: assets/legend_tweaking.png
# description: Setting legend attributes
# ---

using AlgebraOfGraphics, CairoMakie
set_aog_theme!() #src

# To tweak the position and appearance of the legend, simply use the `legend` keyword when plotting. For example

labels = ["a looooooong label", "an even loooooonger label", "and one more long label"]
df = (x=rand(100), y=rand(100), group=rand(labels, 100))
layers = linear() + mapping(color=:group)
plt = data(df) * layers * mapping(:x, :y)
draw(plt)

#

fg = draw(plt, legend=(position=:top, titleposition=:left, framevisible=true, padding=5))

# To adjust the title and order of labels in a legend you can use the pair syntax.

layers = linear() +  mapping(color=:group => sorter(labels) => "Labels")
plt = data(df) * layers * mapping(:x, :y)
draw(plt)

# save cover image #src
mkpath("assets") #src
save("assets/legend_tweaking.png", fg) #src


text:
attach!(uri::String) = attach!(DB, uri)

toattrname(name::String) =
    Symbol(endswith(name, "_id") ? rstrip(name[1:end-2], '_') : name)

function attach!(db::Database, uri::String)
    id2tab = Dict{UInt,SQLTable}()
    conn = connect(uri)
    pg = introspect(conn)
    set = pg.set
    catalog = pg.obj
    disconnect(conn)
    schema_id = catalog.name2schema["public"]
    schema = set.schemas[schema_id]
    for table_id in values(schema.name2table)
        table = set.tables[table_id]
        sname = "public"
        name = table.name
        nattrs = 0
        attrnames = String[]
        attrtypes = Type[]
        attrisnulls = Bool[]
        attruniques = Bool[]
        for column_id in table.columns
            column = set.columns[column_id]
            type_ = set.types[column.type_]
            attrtype =
                if type_.name == "bool"
                    Bool
                elseif type_.name == "int4"
                    Int32
                elseif type_.name == "int8"
                    Int64
                else
                    String
                end
            attrunique = false
            for ukey_id in column.ukeys
                ukey = set.ukeys[ukey_id]
                if length(ukey.columns) == 1
                    attrunique = true
                end
            end
            nattrs += 1
            push!(attrnames, column.name)
            push!(attrtypes, attrtype)
            push!(attrisnulls, column.isnull)
            push!(attruniques, attrunique)
        end
        sortattrs = Int[]
        if !isnull(table.pkey)
            pkey_id = get(table.pkey)
            pkey = set.ukeys[pkey_id]
            for column_id in pkey.columns
                sortattr = findfirst(table.columns, column_id)
                push!(sortattrs, sortattr)
            end
        end
        id2tab[table_id] = SQLTable(sname, name, nattrs, attrnames, attrtypes, attrisnulls, attruniques, sortattrs)
    end
    for table_id in values(schema.name2table)
        table = set.tables[table_id]
        tab = id2tab[table_id]
        tfmt = Symbol[]
        for attrname in tab.attrnames
            push!(tfmt, toattrname(attrname))
        end
        tab_name = Symbol(tab.name)
        attach!(
            db,
            tab_name,
            SQLCollectionQuery(uri, tab, [Decoration(:tag, tab_name), Decoration(:fmt, tfmt)]))
        for attr in 1:tab.nattrs
            column_id = table.columns[attr]
            column = set.columns[column_id]
            attrname = toattrname(tab.attrnames[attr])
            if any(length(set.fkeys[fkey_id].columns) == 1 for fkey_id in column.fkeys)
                for fkey_id in column.fkeys
                    fkey = set.fkeys[fkey_id]
                    if length(fkey.columns) != 1
                        continue
                    end
                    rtable = set.tables[fkey.rtable]
                    rtab = id2tab[fkey.rtable]
                    rattr = findfirst(rtable.columns, fkey.rcolumns[1])
                    fmt = nothing
                    if !isnull(rtable.pkey)
                        rpkey = set.ukeys[get(rtable.pkey)]
                        fmt = Symbol[toattrname(rtab.attrnames[findfirst(rtable.columns, rcol)]) for rcol in rpkey.columns]
                    end
                    attach!(
                        db,
                        attrname,
                        SQLLinkQuery(uri, tab, attr, rtab, rattr, [Decoration(:tag, attrname), Decoration(:fmt, fmt)]))
                    rattrname = Symbol(table.name)
                    card = (count(rfk -> set.fkeys[rfk].table == table_id, rtable.rfkeys) +
                            count(c -> toattrname(set.columns[c].name) == rattrname, rtable.columns))
                    if card > 1
                        rattrname = Symbol(table.name, "_via_", attrname)
                    end
                    attach!(
                        db,
                        rattrname,
                        SQLLinkQuery(uri, rtab, rattr, tab, attr, [Decoration(:tag, rattrname), Decoration(:fmt, tfmt)]))
                    break
                end
            else
                attach!(
                    db,
                    Symbol(attrname),
                    SQLFieldQuery(uri, tab, attr, [Decoration(:tag, attrname)]))
            end
        end
    end
end

max_stars_repo_name: rbt-lang/rbt-proto

max_issues_repo_name: rbt-lang/rbt-proto

max_forks_repo_name: rbt-lang/rbt-proto


text:
# julia -i -q --project=. revise.jl example

using Revise, Jive
using Example

trigger = function (path)
    printstyled("changed ", color=:cyan)
    println(path)
    revise()
    runtests(@__DIR__, skip=["revise.jl"])
end

watch(trigger, @__DIR__, sources=[pathof(Example)])
trigger("")

Base.JLOptions().isinteractive==0 && wait()


text:
using LoopVectorization

""" Trapezoidal rule for numerical quadrature"""
function quad_trap(f,a,b,N)
    h = (b-a)/N
    int = h * ( f(a) + f(b) ) / 2
    @turbo for k=1:N-1
        xk = (b-a) * k/N + a
        int = int + h*f(xk)
    end
    return int
end

g(p) = quad_trap( x -> exp(p*x) - 10, -1, 1, 10000)
g(1)
@time g(1)

max_stars_repo_name: mdmaas/julia-numba

max_issues_repo_name: mdmaas/julia-numba

max_forks_repo_name: mdmaas/julia-numba