text:
# gen/generator.jl
# https://developer.riotgames.com/docs/lol#data-dragon

include(normpath(@__DIR__, "common.jl")) # data_version locales resources

using ProgressMeter
using JSON2
json_read(path) = JSON2.read(Base.read(path, String))

locale = first(locales)
rootdir = normpath(@__DIR__, data_version)
datadir = normpath(rootdir, "data", locale)
path = normpath(datadir, "champion.json")
nt = json_read(path)
jl = normpath(@__DIR__, "locales.jl")
@info relpath(jl, @__DIR__)
f = open(jl, "w")
write(f, "# generated\n")
write(f, "type = ", repr(nt.type), "\n")
write(f, "format = ", repr(nt.format), "\n")
write(f, "version = ", repr(VersionNumber(nt.version)), "\n")
write(f, """
for locale in $(repr(locales))
    gendir = normpath(@__DIR__, $(repr(data_version)), "generated", locale)
    include(normpath(gendir, "module.jl"))
end
""")
close(f)

for locale in locales
    local datadir = normpath(rootdir, "data", locale)
    gendir = normpath(@__DIR__, data_version, "generated", locale)
    !isdir(gendir) && mkpath(gendir)
    local jl = normpath(gendir, "module.jl")
    @info relpath(jl, @__DIR__)
    local f = open(jl, "w")
    write(f, """
    # generated
    module $locale # LOLTools.DataDragon
    """)
    for (k, v) in pairs(resources)
        write(f, """
        include(normpath(@__DIR__, "$k.jl"))
        """)
    end
    write(f, "end # module LOLTools.DataDragon.$locale\n")
    close(f)
    for (k, v) in pairs(resources)
        local path = normpath(datadir, string(k, ".json"))
        local jl = normpath(gendir, string(k, ".jl"))
        local nt = json_read(path)
        @info relpath(jl, @__DIR__)
        local f = open(jl, "w")
        write(f, "# generated\n")
        local desc = string(locale, '/', basename(jl), ' ')
        if k in (:champion, :summoner)
            write(f, "$v = Dict{Int,NamedTuple}(\n")
            @showprogress 1 desc for c in nt.data
                id = parse(Int, c.key)
                write(f, repeat(' ', 4), repr(id => c), ",\n")
            end
            write(f, ")\n")
        elseif k === :item
            write(f, "$v = Dict{Int,NamedTuple}(\n")
            @showprogress 1 desc for (sym, c) in pairs(nt.data)
                maps = Dict(pairs(c.maps)...)
                d = merge(c, (maps=maps,))
                n = parse(Int, String(sym))
                write(f, repeat(' ', 4), repr(n => d), ",\n")
            end
            write(f, ")\n")
        end
        close(f)
    end
end


text:
module Day14

using AdventOfCode2019

struct Reaction
    result::Pair{String,Int}
    recipe::Array{Pair{String,Int},1}
end

function day14(input::String = readInput(joinpath(@__DIR__, "..", "data", "day14.txt")))
    recipes = _parseInput(input)
    ingredients = _empty_ingredient_dict(recipes, 1)
    nORE = _amount_of_ore!(ingredients, recipes)
    nFuel = _max_fuel(1_000_000_000_000, recipes)
    return [nORE, nFuel]
end

function _parseInput(input::String)
    lines = split(strip(input), "\n")
    recipes = Dict{String,Reaction}()

    for line in lines
        comp = findall(r"\d+\s+[A-Z]+", line)
        last = split(line[comp[end]])
        result = Pair(last[2], parse(Int, last[1]))
        recipeRanges = comp[1:end-1]
        recipe = [Pair(elem[2], parse(Int, elem[1])) for elem in [split(line[r]) for r in recipeRanges]]
        reaction = Reaction(result, recipe)
        recipes[reaction.result.first] = reaction
    end
    return recipes
end

function _empty_ingredient_dict(recipes::Dict{String,Reaction}, init_fuel=0)
    d = Dict{String,Int}()
    d["ORE"] = 0
    for (key, _) in recipes
        d[key] = 0
    end
    d["FUEL"] = init_fuel
    return d
end

function _amount_of_ore!(ingredients::Dict{String,Int}, recipes::Dict{String,Reaction})
    ing = Array{Pair{String,Int},1}()
    for (name, amount) in ingredients
        if name == "ORE"
            continue
        end
        if amount > 0
            push!(ing, Pair(name, amount))
            ingredients[name] = 0
        end
    end
    if length(ing) == 0
        return ingredients["ORE"]
    end
    for (name, amount) in ing
        if name == "ORE"
            continue
        end
        recipe = recipes[name]
        factor = 1
        if recipe.result[2] < amount
            factor = ceil(Int, amount/recipe.result[2])
        end
        ingredients[name] += amount - factor * recipe.result[2]
        for (n, a) in recipe.recipe
            ingredients[n] += factor * a
        end
    end
    return _amount_of_ore!(ingredients, recipes)
end

function _max_fuel(availableORE::Int, recipes::Dict{String,Reaction})
    u = 1
    while true
        nORE = _amount_of_ore!(_empty_ingredient_dict(recipes, u), recipes)
        if nORE > availableORE
            break
        end
        u *= 2
    end
    u == 1 && return 0
    le = u ÷ 2
    while u - le > 1
        m = (le + u) ÷ 2
        nORE = _amount_of_ore!(_empty_ingredient_dict(recipes, m), recipes)
        if nORE > availableORE
            u = m
        else
            le = m
        end
    end
    return le
end

end # module

ext: jl


text:
# Collection of functions to convert cartesian coordinate to orbital elements
using LinearAlgebra, NbodyGradient
import NbodyGradient: InitialConditions

## Utils ##

const GNEWT = 39.4845/(365.242 * 365.242) # AU^3 Msol^-1 Day^-2

# h vector
function hvec(x::V,v::V) where V <: Vector{<:Real}
    hx,hy,hz = cross(x,v)
    hz >= 0.0 ? hy *= -1 : hx *= -1
    return [hx,hy,hz]
end

# R dot
Rdotmag(R::T,V::T,x::Vector{T},v::Vector{T},h::T) where T<:AbstractFloat = sign(dot(x,v))*sqrt(V^2 - (h/R)^2)

## Elements ##

# Semi-major axis
calc_a(R::T,V::T,Gm::T) where T<:AbstractFloat = 1.0/((2.0/R) - (V*V)/(Gm))

# Eccentricity
calc_e(h::T,Gm::T,a::T) where T<:AbstractFloat = sqrt(1.0 - (h*h/(Gm*a)))

# Inclination
calc_I(hz::T,h::T) where T<:AbstractFloat = acos(hz/h)

# Long. of Ascending Node
function calc_Ω(h::T,hx::T,hy::T,sI::T) where T<:AbstractFloat
    sΩ = hx/(h*sI)
    cΩ = hy/(h*sI)
    return atan(sΩ,cΩ)
end

# Long. of Pericenter
function calc_ϖ(x::Vector{T},R::T,Ṙ::T,Ω::T,I::T,e::T,h::T,a::T) where T<:AbstractFloat
    X,_,Z = x
    sΩ,cΩ = sincos(Ω)
    sI,cI = sincos(I)

    # ω + f
    swpf = Z/(R*sI)
    cwpf= ((X/R) + sΩ*swpf*cI)/cΩ
    wpf = atan(swpf,cwpf)

    # true anomaly, f
    sf = a*Ṙ*(1.0 - e^2)/(h*e)
    cf = (a*(1.0-e^2)/R - 1.0)/e
    f = atan(sf,cf)

    # ϖ: Ω + ω
    return Ω + (wpf - f - π)
end

# Time of pericenter passage
function calc_t0(R::T,a::T,e::T,Gm::T,t::T) where T<:AbstractFloat
    E = acos((1.0 - (R/a)) / e)
    return t - (E - e*sin(E))/sqrt(Gm/(a*a*a))
end

# Period
calc_P(a::T,Gm::T) where T<:AbstractFloat = (2.0*π)*sqrt(a*a*a/Gm)

# Get relative hierarchy positions
function calc_X(s::State{T},ic::InitialConditions{T}) where T<:AbstractFloat
    X = zeros(3,s.n-1)
    V = zeros(3,s.n-1)
    for i in 1:s.n-1
        for k in 1:s.n
            X[:,i] .+= ic.amat[i,k] .* s.x[:,k]
            V[:,i] .+= ic.amat[i,k] .* s.v[:,k]
        end
    end
    return X,V
end

function gmass(m::Vector{T}) where T<:AbstractFloat
    N = length(m)
    M = zeros(N - 1)
    for i in 1:N-1
        for j in 1:N
            M[i] += abs(ic.ϵ[i,j])*m[j]
        end
    end
    return GNEWT .* M
end

"""

Converts cartesian coordinates to orbital elements. (t0 : time of transit)
"""
function get_orbital_elements(s::State{T},ic::InitialConditions{T}) where T<:AbstractFloat
    X::Matrix{T},Xdot::Matrix{T} = calc_X(s,ic)
    Gm = gmass(s.m)
    R = [norm(X[:,i]) for i in 1:s.n-1]
    V = [norm(Xdot[:,i]) for i in 1:s.n-1]
    h_vec::Matrix{T} = hcat([hvec(X[:,i],Xdot[:,i]) for i in 1:s.n-1]...)
    hx,hy,hz = h_vec[1,:],h_vec[2,:],h_vec[3,:]
    h = norm.([hx[i],hy[i],hz[i]] for i in 1:s.n-1)
    Rdot = [Rdotmag(R[i],V[i],X[:,i],Xdot[:,i],h[i]) for i in 1:s.n-1]

    a = calc_a.(R,V,Gm)
    e = calc_e.(h,Gm,a)
    I = calc_I.(hz,h)
    Ω = calc_Ω.(h,hx,hy,sin.(I))
    ϖ = [calc_ϖ(X[:,i],R[i],Rdot[i],Ω[i],I[i],e[i],h[i],a[i]) for i in 1:s.n-1]
    #t0 = calc_t0.(R,a,e,Gm,s.t) # Our elements use the initial transit time
    t0 = ic.elements[2:end,3]
    P = calc_P.(a,Gm)
    elements = zeros(size(ic.elements))
    elements[1] = ic.elements[1]
    elements[2:end,:] = hcat(s.m[2:end],P,t0,e .* cos.(ϖ),e .* sin.(ϖ),I,Ω)
    return elements
end


text:
module MapApplyTests

using Test
using CellwiseValues
using TensorValues

using ..MapsMocks

a = VectorValue(10,10)
b = VectorValue(15,20)
p1 = VectorValue(1,1)
p2 = VectorValue(2,2)
p3 = VectorValue(3,3)
p = [p1,p2,p3]
m = MockMap(a)

m2 = apply(-,m,broadcast=true)

r = evaluate(m,p)
r2 = -r
test_map(m2,p,r2)

m3 = apply(-,m,m2,broadcast=true)
r3 = r .- r2
test_map(m3,p,r3)

m3 = apply(-,m,p,broadcast=true)
r3 = r .- p
test_map(m3,p,r3)

end # module


text:
type OCCAVector{T<:Number}
    dev::OCCA.Device;
    devmem::OCCA.Memory;
    hostmem::Vector{T};
    devflag::OCCADevFlag;
end

function OCCAVector{T}(dev::OCCA.Device,v::Array{T})
    hostmem=copy(v);
    devmem =OCCA.malloc(dev,hostmem);
    flag   =OCCADevFlag(onhost);
    return OCCAVector(dev,devmem,hostmem,flag);
end


text:
module ECapeExceptions
    export ECapeOutOfBounds,ECapeInvalidArgument,ECapeThrmPropertyNotAvailable,ECapeLimitedImpl,ECapeNoImpl,ECapeUnknown

    type ECapeBoundaries <: Exception end
    type ECapeRoot <: Exception end
    type ECapeUser <: Exception end
    type ECapeUnknown <: Exception end
    type ECapeData <: Exception end
    type ECapeLicenceError <: Exception end
    type ECapeBadCOParameter <: Exception end
    type ECapeBadArgument <: Exception end
    type ECapeInvalidArgument <: Exception end
    type ECapeOutOfBounds <: Exception end
    type ECapeImplementation <: Exception end
    type ECapeNoImpl <: Exception end
    type ECapeLimitedImpl <: Exception end
    type ECapeComputation <: Exception end
    type ECapeOutOfResources <: Exception end
    type ECapeNoMemory <: Exception end
    type ECapeTimeOut <: Exception end
    type ECapeFailedInitialisation <: Exception end
    type ECapeSolvingError <: Exception end
    type ECapeBadInvOrder <: Exception end
    type ECapeInvalidOperation <: Exception end
    type ECapePersistence <: Exception end
    type ECapeIllegalAccess <: Exception end
    type ECapePersistenceNotFound <: Exception end
    type ECapePersistenceSystemError <: Exception end
    type ECapePersistenceOverflow <: Exception end
    type ECapeErrorDummy <: Exception end
    type ECapeThrmPropertyNotAvailable <: Exception end

end


text:
using .Makie: Makie
using LinearAlgebra: norm
using .Makie: lift, cam3d!, Point3f0, Vec3f0, Figure, Auto
using .Makie: DataAspect, Axis, labelslidergrid!, set_close_to!, labelslider!, LScene
using GeometryBasics: GLTriangleFace
using ..TopOptProblems: getcloaddict

################################
# Credit to Simon Danisch for the conversion code below

# https://github.com/JuliaPlots/AbstractPlotting.jl/blob/f16321dee2c77ac9c753fed9b1074a2df7b10db8/src/utilities/utilities.jl#L188
# https://github.com/JuliaPlots/AbstractPlotting.jl/blob/444813136a506eba8b5b03e2125c7a5f24e825cb/src/conversions.jl#L522
function Makie.to_vertices(nodes::Vector{<:Ferrite.Node})
    return Point3f0.([n.x for n in nodes])
end

function Makie.to_triangles(cells::AbstractVector{<:Ferrite.Cell})
    tris = GLTriangleFace[]
    for cell in cells
        to_triangle(tris, cell)
    end
    return tris
end

# https://github.com/JuliaPlots/AbstractPlotting.jl/blob/444813136a506eba8b5b03e2125c7a5f24e825cb/src/conversions.jl#L505
function to_triangle(tris, cell::Union{Ferrite.Hexahedron,QuadraticHexahedron})
    nodes = cell.nodes
    push!(tris, GLTriangleFace(nodes[1], nodes[2], nodes[5]))
    push!(tris, GLTriangleFace(nodes[5], nodes[2], nodes[6]))

    push!(tris, GLTriangleFace(nodes[6], nodes[2], nodes[3]))
    push!(tris, GLTriangleFace(nodes[3], nodes[6], nodes[7]))

    push!(tris, GLTriangleFace(nodes[7], nodes[8], nodes[3]))
    push!(tris, GLTriangleFace(nodes[3], nodes[8], nodes[4]))

    push!(tris, GLTriangleFace(nodes[4], nodes[8], nodes[5]))
    push!(tris, GLTriangleFace(nodes[5], nodes[4], nodes[1]))

    push!(tris, GLTriangleFace(nodes[1], nodes[2], nodes[3]))
    return push!(tris, GLTriangleFace(nodes[3], nodes[1], nodes[4]))
end

function to_triangle(tris, cell::Union{Ferrite.Tetrahedron,Ferrite.QuadraticTetrahedron})
    nodes = cell.nodes
    push!(tris, GLTriangleFace(nodes[1], nodes[3], nodes[2]))
    push!(tris, GLTriangleFace(nodes[3], nodes[4], nodes[2]))
    push!(tris, GLTriangleFace(nodes[4], nodes[3], nodes[1]))
    return push!(tris, GLTriangleFace(nodes[4], nodes[1], nodes[2]))
end

function to_triangle(
    tris, cell::Union{Ferrite.Quadrilateral,Ferrite.QuadraticQuadrilateral}
)
    nodes = cell.nodes
    push!(tris, GLTriangleFace(nodes[1], nodes[2], nodes[3]))
    return push!(tris, GLTriangleFace(nodes[3], nodes[4], nodes[1]))
end

function to_triangle(tris, cell::Union{Ferrite.Triangle,Ferrite.QuadraticTriangle})
    nodes = cell.nodes
    return push!(tris, GLTriangleFace(nodes[1], nodes[2], nodes[3]))
end

function Makie.convert_arguments(P, x::AbstractVector{<:Ferrite.Node{N,T}}) where {N,T}
    return convert_arguments(P, reinterpret(Point{N,T}, x))
end

################################

function visualize(
    mesh::Ferrite.Grid{dim,<:Ferrite.AbstractCell,TT},
    u;
    topology=undef,
    cloaddict=undef,
    undeformed_mesh_color=(:gray, 0.4),
    deformed_mesh_color=(:cyan, 0.4),
    vector_arrowsize=1.0,
    vector_linewidth=1.0,
    default_support_scale=1.0,
    default_load_scale=1.0,
    scale_range=1.0,
    default_exagg_scale=1.0,
    exagg_range=1.0,
) where {dim,TT}
    T = eltype(u)
    nnodes = length(mesh.nodes)
    if topology !== undef
        mesh_cells = mesh.cells[Bool.(round.(Int, topology))]
        # TODO display opacity accroding to topology values
        # undeformed_mesh_color = [(:gray,t) for t in topology]
    else
        mesh_cells = mesh.cells
    end

    # * initialize the makie scene
    fig = Figure(; resolution=(1200, 800))

    #TODO make this work without creating a Node
    if dim == 2
        nodes = Vector{Ferrite.Node}(undef, nnodes)
        for (i, node) in enumerate(mesh.nodes)
            nodes[i] = Ferrite.Node((node.x[1], node.x[2], zero(T)))
        end
        u = [u; zeros(T, 1, nnodes)]

        ax1 = Axis(fig[1, 1])
        # tightlimits!(ax1)
        # ax1.aspect = AxisAspect(1)
        ax1.aspect = DataAspect()
    else
        nodes = mesh.nodes

        # https://jkrumbiegel.github.io/MakieLayout.jl/v0.3/layoutables/#LScene-1
        # https://makie.juliaplots.org/stable/cameras.html#D-Camera
        # ax1 = layout[1, 1] = LScene(scene, camera = cam3d!, raw = false)
        ax1 = LScene(fig[1, 1]; scenekw=(camera=cam3d!, raw=false), height=750)
    end
    # TODO show the ground mesh in another Axis https://makie.juliaplots.org/stable/makielayout/grids.html
    # ax1.title = "TopOpt result"

    # * support / load appearance / deformatione exaggeration control
    lsgrid = labelslidergrid!(
        fig,
        ["deformation exaggeration", "support scale", "load scale"],
        [
            LinRange(0.0:0.01:exagg_range),
            LinRange(0.0:0.01:scale_range),
            LinRange(0.0:0.01:scale_range),
        ];
        width=Auto(),
        # tellwidth = true,
        # horizontal = false,
    )
    set_close_to!(lsgrid.sliders[1], default_exagg_scale)
    set_close_to!(lsgrid.sliders[2], default_support_scale)
    set_close_to!(lsgrid.sliders[3], default_load_scale)
    fig[2, 1] = lsgrid.layout

    # * undeformed mesh
    Makie.mesh!(ax1, nodes, mesh_cells; color=undeformed_mesh_color, shading=true)

    # * deformed mesh
    if norm(u) > eps()
        exagg_deformed_nodes = lift(
            s -> [
                Ferrite.Node(Tuple([node.x[j] + s * u[j, i] for j in 1:3])) for
                (i, node) in enumerate(nodes)
            ],
            lsgrid.sliders[1].value,
        )
        new_nodes = Vector{Ferrite.Node}(undef, length(nodes))
        Makie.mesh!(ax1, exagg_deformed_nodes, mesh_cells; color=deformed_mesh_color)
    end

    # * dot points for deformation nodes
    # Makie.scatter!(ax1, Point3f0.(getfield.(new_nodes, :x)), markersize = 0.1);
    # points = Point3f0.(getfield.(nodes, :x))
    # * deformation vectors
    # GeometryTypes.Vec{3, Float64}
    # displacevec = reinterpret(Vec3f0, u, (size(u, 2),))
    # displacevec = Vec3f0.([u[:,i] for i=1:size(u,2)])
    # displace = norm.(displacevec)
    # Makie.arrows!(points, displacevec, linecolor = (:black, 0.3))

    # TODO pressure loads?
    # * load vectors
    if cloaddict !== undef
        if length(cloaddict) > 0
            loaded_nodes = Point3f0.(nodes[node_ind].x for (node_ind, _) in cloaddict)
            Makie.arrows!(
                ax1,
                loaded_nodes,
                lift(
                    s -> Vec3f0.(s .* load_vec for (_, load_vec) in cloaddict),
                    lsgrid.sliders[3].value,
                );
                linecolor=:purple,
                arrowcolor=:purple,
                arrowsize=vector_arrowsize,
                linewidth=vector_linewidth,
            )
            Makie.scatter!(ax1, loaded_nodes) #, markersize = lift(s -> s * 3, lsgrid.sliders[2].value))
        end
    end

    # * support vectors
    for (nodeset_name, node_ids) in mesh.nodesets
        vectors = []
        if occursin("fixed_u1", nodeset_name)
            push!(vectors, [1.0, 0.0, 0.0])
        elseif occursin("fixed_u2", nodeset_name)
            push!(vectors, [0.0, 1.0, 0.0])
        elseif occursin("fixed_u3", nodeset_name)
            push!(vectors, [0.0, 0.0, 1.0])
        elseif occursin("fixed_all", nodeset_name)
            push!(vectors, [1.0, 0.0, 0.0])
            push!(vectors, [0.0, 1.0, 0.0])
            push!(vectors, [0.0, 0.0, 1.0])
        else
            continue
        end
        fixed_nodes = Point3f0.(nodes[node_ind].x for node_ind in node_ids)
        for v in vectors
            Makie.arrows!(
                ax1,
                fixed_nodes,
                lift(s -> [Vec3f0(s .* v) for nid in node_ids], lsgrid.sliders[2].value);
                linecolor=:orange,
                arrowcolor=:orange,
                arrowsize=vector_arrowsize,
                linewidth=vector_linewidth,
            )
        end
        Makie.scatter!(ax1, fixed_nodes) #, markersize = lift(s -> s * 3, lsgrid.sliders[1].value))
    end

    return fig
end

"""
draw problem's initial grid with a given displacement vector `u`
"""
function visualize(
    problem::StiffnessTopOptProblem{dim,T}, u::AbstractVector; kwargs...
) where {dim,T}
    mesh = problem.ch.dh.grid
    node_dofs = problem.metadata.node_dofs
    nnodes = Ferrite.getnnodes(mesh)
    if u === undef
        node_displacements = zeros(T, dim, nnodes)
    else
        node_displacements = reshape(u[node_dofs], dim, nnodes)
    end
    cloaddict = getcloaddict(problem)
    return visualize(
        mesh, node_displacements; topology=undef, cloaddict=cloaddict, kwargs...
    )
end

function visualize(problem::StiffnessTopOptProblem{dim,T}; kwargs...) where {dim,T}
    mesh = problem.ch.dh.grid
    nnodes = Ferrite.getnnodes(mesh)
    node_displacements = zeros(T, dim, nnodes)
    cloaddict = getcloaddict(problem)
    return visualize(mesh, node_displacements; cloaddict=cloaddict, kwargs...)
end


text:
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################
@doc """
"""
function firstComponentFactor(data)

    num_obs = size(data)[1]
    centering = I - 1 / (num_obs) * ones(num_obs, num_obs) # centering matrix
    data = centering * data # center the data
    cov_mat = data' * data
    cov_mat_eigen = eigen(cov_mat)
    components = cov_mat_eigen.vectors
    firstComponent = components[:, end] # eigenvalues ordered from smallest to largest
    firstComponent = sqrt(num_obs) * firstComponent
    factor = data * firstComponent / num_obs

    return factor, firstComponent
end;
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################


text:
module TagBot

using Base64: base64decode, base64encode
using Dates: Day, Minute, UTC, now
using Random: randstring
using SHA: sha1

using GitHub: GitHub
using JSON: JSON

const GH = GitHub

const AUTH = Ref{GH.OAuth2}()
const TAGBOT_USER = Ref{String}()
const ISSUE_TITLE = "TagBot trigger issue"
const ISSUE_BODY = """
This issue is used to trigger TagBot; feel free to unsubscribe.

If you haven't already, you should update your `TagBot.yml` to include issue comment triggers.
Please see [this post on Discourse](https://discourse.julialang.org/t/ann-required-updates-to-tagbot-yml/49249) for instructions and more details.

If you'd like for me to do this for you, comment `TagBot fix` on this issue.
I'll open a PR within a few hours, please be patient!
"""
const CRON_ADDENDUM = """

This extra notification is being sent because I expected a tag to exist by now, but it doesn't.
You may want to check your TagBot configuration to ensure that it's running, and if it is, check the logs to make sure that there are no errors.
"""

include("cron.jl")
include("pull_request.jl")
include("fixup.jl")

function main()
    AUTH[] = GH.authenticate(ENV["GITHUB_TOKEN"])
    TAGBOT_USER[] = GH.whoami(; auth=AUTH[]).login
    event = JSON.parse(read(ENV["GITHUB_EVENT_PATH"], String))
    if is_merged_pull_request(event)
        handle_merged_pull_request(event)
    elseif is_cron(event)
        handle_cron(event)
    end
end

function repo_and_version_of_pull_request_body(body)
    if occursin("JLL package", body)
        @info "Skipping JLL package registration"
        return nothing, nothing
    end
    m = match(r"Repository: .*github\.com[:/](.*)", body)
    repo = m === nothing ? nothing : strip(m[1])
    repo !== nothing && endswith(repo, ".git") && (repo = repo[1:(end - 4)])
    m = match(r"Version: (.*)", body)
    version = m === nothing ? nothing : strip(m[1])
    return repo, version
end

function tagbot_file(repo; issue_comments=false)
    files, pages = try
        GH.directory(repo, ".github/workflows"; auth=AUTH[])
    catch e
        occursin("404", e.msg) && return nothing
        rethrow()
    end
    for f in files
        f.typ == "file" || continue
        file = GH.file(repo, f.path; auth=AUTH[])
        contents = String(base64decode(file.content))
        if occursin("JuliaRegistries/TagBot", contents)
            issue_comments && !occursin("issue_comment", contents) && continue
            return f.path, contents
        end
    end
    return nothing
end

function get_repo_notification_issue(repo)
    issues, _ = GH.issues(
        repo; auth=AUTH[], params=(; creator=TAGBOT_USER[], state="closed")
    )
    filter!(x -> x.pull_request === nothing, issues)
    return if isempty(issues)
        @info "Creating new notification issue"
        issue = try
            GH.create_issue(repo; auth=AUTH[], params=(; title=ISSUE_TITLE, body=ISSUE_BODY))
        catch e
            occursin("Issues are disabled", e.msg) || rethrow()
            @info "Issues are disabled on $repo"
            return nothing
        end
        GH.edit_issue(repo, issue; auth=AUTH[], params=(; state="closed"))
        issue
    else
        @info "Found existing notification issue"
        issues[1]
    end
end

function notification_body(event; cron=false)
    url = get(get(event, "pull_request", Dict()), "html_url", "")
    body = "Triggering TagBot for merged registry pull request"
    isempty(url) || (body = "$body: $url")
    cron && (body *= CRON_ADDENDUM)
    return body
end

function notify(repo, issue, body)
    return GH.create_comment(repo, issue, :issue; auth=AUTH[], params=(; body=body))
end

function tag_exists(repo, version)
    return try
        GH.tag(repo, version; auth=AUTH[])
        true
    catch e
        if !occursin("404", e.msg)
            @warn "Unknown error when checking for existing tag" ex = (e, catch_backtrace())
        end
        false
    end
end

function maybe_notify(event, repo, version; cron=false)
    @info "Processing version $version of $repo"
    if tagbot_file(repo) === nothing
        @info "TagBot is not enabled on $repo"
        return nothing
    end
    if cron && tag_exists(repo, version)
        @info "Tag $version already exists for $repo"
        return nothing
    end
    issue = get_repo_notification_issue(repo)
    if issue === nothing
        @info "Couldn't get notification issue for $repo"
        return nothing
    end
    if cron && should_fixup(repo, issue)
        @info "Opening fixup PR for $repo"
        open_fixup_pr(repo)
    end
    body = notification_body(event; cron=cron)
    return notify(repo, issue, body)
end

end


text:
import NNlib: conv_direct, conv_im2col

@testset "Conv Inference" begin

    for T in (Float32, Float64)
        impl = [conv, conv_direct, conv_im2col]
        if NNlib.is_nnpack_available() && T == Float32
            push!(impl, NNlib.conv_nnpack)
        end

        x = rand(T, 10, 10, 3, 2)
        w = rand(T, 3, 3, 3, 1)

        for f in impl
            @test @inferred(f(x, w, DenseConvDims(x, w))) isa Array{T,4}
        end
    end
end


text:
## Horseshoe methods
#==========================================================================================#

quarter_point(p1, p2) = weighted_vector(p1, p2, SVector(1/4, 0, 1/4))

three_quarter_point(p1, p2) = weighted_vector(p1, p2, SVector(3/4, 0, 3/4))

collocation_point(p1, p2, p3, p4) = ( three_quarter_point(p1, p2) + three_quarter_point(p4, p3) ) / 2
bound_leg(p1, p2, p3, p4) = SVector(quarter_point(p1, p2), quarter_point(p4, p3))

"""
    bound_leg(panel :: Panel3D)

Compute the bound leg for a `Panel3D`, for horseshoes/vortex rings.
"""
bound_leg(panel :: Panel3D) = bound_leg(panel.p1, panel.p2, panel.p3, panel.p4)

"""
    collocation_point(panel :: Panel3D)

Compute the collocation point of a `Panel3D` for horseshoes/vortex rings, which is the 3-quarter point on each side in the ``x``-``z`` plane.
"""
collocation_point(panel :: Panel3D) = collocation_point(panel.p1, panel.p2, panel.p3, panel.p4)

bound_leg_velocity(a, b, Γ)    = Γ/4π * (1/norm(a) + 1/norm(b)) * a × b / (norm(a) * norm(b) + dot(a, b))
trailing_leg_velocity(r, Γ, u) = Γ/4π * normalize(r) × normalize(u) / (norm(r) - dot(r, u))

trailing_legs_velocities(a, b, Γ, u) = trailing_leg_velocity(a, Γ, u) - trailing_leg_velocity(b, Γ, u)
total_horseshoe_velocity(a, b, Γ, u) = bound_leg_velocity(a, b, Γ) + trailing_legs_velocities(a, b, Γ, u)

# Finite-core model
function bound_leg_velocity(a, b, Γ, ε)
    na, nb, σ = norm(a), norm(b), dot(a, b)
    term_1    = (na^2 - σ) / √(na^2 + ε^2) + (nb^2 - σ) / √(nb^2 + ε^2)
    term_2    = a × b / (na^2 * nb^2 - σ^2 + ε^2 * (na^2 + nb^2 - 2 * na * nb))

    Γ/4π * term_1 * term_2
end

trailing_leg_velocity(r, Γ, u, ε) = Γ/4π * normalize(r) × u / (norm(r) - dot(r, u) + ε^2 / (norm(r) + dot(r, u)))
trailing_legs_velocities(a, b, Γ, u, ε) = trailing_leg_velocity(a, Γ, u, ε) - trailing_leg_velocity(b, Γ, u, ε)
total_horseshoe_velocity(a, b, Γ, u, ε) = bound_leg_velocity(a, b, Γ, ε) + trailing_legs_velocities(a, b, Γ, u, ε)

## Arrays of vortex lines
#==========================================================================================#

abstract type AbstractVortex end

"""
    Horseshoe(r1, r2, collocation_point, normal, chord)

Define a horseshoe vortex with a start and endpoints ``r₁, r₂`` for the bound leg, a collocation point ``r``, a normal vector ``̂n``, and a finite core size.

The finite core setup is not implemented for now.
"""
struct Horseshoe{T <: Real} <: AbstractVortex
    r1                :: SVector{3,T}
    r2                :: SVector{3,T}
    collocation_point :: SVector{3,T}
    normal            :: SVector{3,T}
    core              :: T
end

Base.length(::Horseshoe) = 1

r1(horseshoe :: Horseshoe) = horseshoe.r1
r2(horseshoe :: Horseshoe) = horseshoe.r2

function Horseshoe(r1, r2, r_c, n, c)
    T = promote_type(eltype(r1), eltype(r2), eltype(r_c), eltype(n), eltype(c))
    Horseshoe{T}(r1, r2, r_c, n, c)
end

"""
    bound_leg(horseshoe :: Horseshoe)

Getter for bound leg field of a `Horseshoe`.
"""
bound_leg(horseshoe :: Horseshoe)        = horseshoe.bound_leg
collocation_point(horseshoe :: Horseshoe)  = horseshoe.collocation_point
horseshoe_normal(horseshoe :: Horseshoe) = horseshoe.normal

r1(r, horseshoe :: Horseshoe) = r - horseshoe.r1
r2(r, horseshoe :: Horseshoe) = r - horseshoe.r2

"""
    Horseshoe(panel :: Panel3D, normal, drift = zeros(3))

Generate a `Horseshoe` corresponding to a `Panel3D`, an associated normal vector, and a "drift velocity".
"""
function Horseshoe(panel :: Panel3D, normal, drift = SVector(0., 0., 0.))
    r1, r2 = bound_leg(panel)
    r_c = collocation_point(panel) + drift
    ε   = 0. # (norm ∘ average_chord)(panel))
    Horseshoe(r1, r2, r_c, normal, ε)
end

"""
    transform(horseshoe :: Horseshoe, T :: LinearMap)

Generate a new `Horseshoe` with the points and normal vectors transformed by the linear map ``T``.
"""
transform(horseshoe :: Horseshoe, T :: LinearMap) =
    setproperties(
              horseshoe,
              r1                = T(horseshoe.r1),
              r2                = T(horseshoe.r2),
              collocation_point = T(horseshoe.collocation_point),
              normal            = T(horseshoe.normal),
             )

transform(horseshoe :: Horseshoe; rotation = I(3), translation = zeros(3)) = transform(horseshoe, Translation(translation) ∘ LinearMap(rotation))

"""
    bound_leg_center(horseshoe :: Horseshoe)

Compute the midpoint of the bound leg of a `Horseshoe`.
"""
bound_leg_center(horseshoe :: Horseshoe) = (horseshoe.r1 + horseshoe.r2) / 2

"""
    bound_leg_vector(horseshoe :: Horseshoe)

Compute the direction vector of the bound leg of a `Horseshoe`.
"""
bound_leg_vector(horseshoe :: Horseshoe) = horseshoe.r2 - horseshoe.r1

"""
    velocity(r, horseshoe, Γ, u_hat = [1.,0.,0.])

Compute the induced velocity at a point ``r`` of a given `Horseshoe` with a bound leg of constant strength ``Γ`` and semi-infinite trailing legs pointing in a given direction ``û``, by default `û = x̂`.
"""
velocity(r, horseshoe :: Horseshoe, Γ :: Real, V_hat = SVector(1.,0.,0.)) = total_horseshoe_velocity(r1(r, horseshoe), r2(r, horseshoe), Γ, V_hat, horseshoe.core)

"""
    bound_velocity(r, horseshoe, Γ, u_hat)

Compute the induced velocity at a point ``r`` from the bound leg with constant strength ``Γ`` of a given `Horseshoe`.
"""
bound_velocity(r, horseshoe :: Horseshoe, Γ) = bound_leg_velocity(r1(r, horseshoe), r2(r, horseshoe), Γ, horseshoe.core)

"""
    trailing_velocity(r, horseshoe, Γ, u_hat)

Compute the induced velocity at a point ``r`` from the semi-infinite trailing legs with constant strength ``Γ`` of a given `Horseshoe`.
"""
trailing_velocity(r, horseshoe :: Horseshoe, Γ, V) = trailing_legs_velocities(r1(r, horseshoe), r2(r, horseshoe), Γ, V, horseshoe.core)


text:
pospath = "./data/positions/Positions.h5"

@testset "Testing Positions submodule" begin
  shp = [3,3,3]
  fov = [3.0,3.0,3.0]Unitful.mm
  ctr = [0.0,0.0,0.0]Unitful.mm
  caG = RegularGridPositions(shp,fov,ctr)
  @test shape(caG) == shp
  @test fieldOfView(caG) == fov
  @test fieldOfViewCenter(caG) == ctr
  @test_throws BoundsError caG[0]
  @test_throws BoundsError caG[28]
  @test caG[1] == [-1,-1,-1]Unitful.mm
  @test caG[2] == [0,-1,-1]Unitful.mm
  @test caG[3] == [1,-1,-1]Unitful.mm
  @test caG[4] == [-1,0,-1]Unitful.mm
  @test caG[27] == [1,1,1]Unitful.mm
  h5open(pospath, "w") do file
    write(file, caG)
  end
  h5open(pospath, "r") do file
    caG1 = Positions(file)
    @test typeof(caG1) <: RegularGridPositions
    @test shape(caG1) == shp
    @test fieldOfView(caG1) == fov
    @test fieldOfViewCenter(caG1) == ctr
  end
  for (i,pos) in enumerate(caG)
    @test posToLinIdx(caG,pos) == i
  end

  chG = ChebyshevGridPositions(shp,fov,ctr)
  @test shape(chG) == shp
  @test fieldOfView(chG) == fov
  @test fieldOfViewCenter(chG) == ctr
  @test_throws BoundsError chG[0]
  @test_throws BoundsError chG[28]
  @test chG[1] ≈ cos(π/6)*3/2*caG[1]
  @test chG[2] ≈ cos(π/6)*3/2*caG[2]
  @test chG[3] ≈ cos(π/6)*3/2*caG[3]
  @test chG[4] ≈ cos(π/6)*3/2*caG[4]
  @test chG[27] ≈ cos(π/6)*3/2*caG[27]
  h5open(pospath, "w") do file
    write(file, chG)
  end
  h5open(pospath, "r") do file
    chG1 = Positions(file)
    @test typeof(chG1) <: ChebyshevGridPositions
    @test shape(chG1) == shp
    @test fieldOfView(chG1) == fov
    @test fieldOfViewCenter(chG1) == ctr
  end

  for grid in [caG,chG]
    mG = MeanderingGridPositions(grid)
    @test length(mG) == prod(shp)
    @test shape(mG) == shp
    @test fieldOfView(mG) == fov
    @test fieldOfViewCenter(mG) == ctr
    @test mG[1] == grid[1]
    @test mG[2] == grid[2]
    @test mG[3] == grid[3]
    @test mG[4] == grid[6]
    @test mG[7] == grid[7]
    @test mG[9] == grid[9]
    @test mG[10] == grid[18]
    @test mG[18] == grid[10]
    @test mG[19] == grid[19]
    @test mG[27] == grid[27]
    @test getPermutation(mG) == [1, 2, 3, 6, 5, 4, 7, 8, 9, 18, 17, 16, 13, 14, 15, 12, 11, 10, 19, 20, 21, 24, 23, 22, 25, 26, 27]
    h5open(pospath, "w") do file
      write(file, mG)
    end
    h5open(pospath, "r") do file
      mG1 = Positions(file)
      @test mG1[1] ≈ grid[1]
      @test shape(mG1) == shp
      @test fieldOfView(mG1) == fov
      @test fieldOfViewCenter(mG1) == ctr
    end
  end
#BG Test
    bgInd = collect(1:4:37)
    bgPos = [10.0,10.0,10.0]Unitful.mm
  for grid in [caG,chG]
    bG = BreakpointGridPositions(grid,bgInd,bgPos)
    @test length(bG) == prod(shp)+length(bgInd)
    @test shape(bG) == shp
    @test fieldOfView(bG) == fov
    @test fieldOfViewCenter(bG) == ctr
    @test bG[1] == bgPos
    @test bG[2] == grid[1]
    @test bG[3] == grid[2]
    @test bG[4] == grid[3]
    @test bG[5] == bgPos
    @test bG[6] == grid[4]
    @test bG[7] == grid[5]
    @test bG[8] == grid[6]
    @test bG[9] == bgPos
    @test bG[10] == grid[7]
    @test bG[11] == grid[8]
    @test bG[12] == grid[9]
    @test bG[13] == bgPos
    @test bG[14] == grid[10]
    @test bG[15] == grid[11]
    @test bG[16] == grid[12]
    @test bG[17] == bgPos
    @test bG[18] == grid[13]
    @test bG[19] == grid[14]
    @test bG[20] == grid[15]
    @test bG[21] == bgPos
    @test bG[22] == grid[16]
    @test bG[23] == grid[17]
    @test bG[24] == grid[18]
    @test bG[25] == bgPos
    @test bG[26] == grid[19]
    @test bG[27] == grid[20]
    @test bG[28] == grid[21]
    @test bG[29] == bgPos
    @test bG[30] == grid[22]
    @test bG[31] == grid[23]
    @test bG[32] == grid[24]
    @test bG[33] == bgPos
    @test bG[34] == grid[25]
    @test bG[35] == grid[26]
    @test bG[36] == grid[27]
    @test bG[37] == bgPos

    h5open(pospath, "w") do file
      write(file, bG)
    end
    h5open(pospath, "r") do file
      bG1 = Positions(file)
      @test bG1[1] ≈ grid[1]
      @test shape(bG1) == shp
      @test fieldOfView(bG1) == fov
      @test fieldOfViewCenter(bG1) == ctr
    end
  end

#BG+Meander Test
    bgInd = collect(1:4:37)
    bgPos = [10.0,10.0,10.0]Unitful.mm
  for grid in [caG,chG]
    mG = MeanderingGridPositions(grid)
    bG = BreakpointGridPositions(mG,bgInd,bgPos)
    @test length(bG) == prod(shp)+length(bgInd)
    @test shape(bG) == shp
    @test fieldOfView(bG) == fov
    @test fieldOfViewCenter(bG) == ctr
    @test bG[1] == bgPos
    @test bG[2] == grid[1]
    @test bG[3] == grid[2]
    @test bG[4] == grid[3]
    @test bG[5] == bgPos
    @test bG[6] == grid[6]
    @test bG[7] == grid[5]
    @test bG[8] == grid[4]
    @test bG[9] == bgPos
    @test bG[10] == grid[7]
    @test bG[11] == grid[8]
    @test bG[12] == grid[9]
    @test bG[13] == bgPos
    @test bG[14] == grid[18]
    @test bG[15] == grid[17]
    @test bG[16] == grid[16]
    @test bG[17] == bgPos
    @test bG[18] == grid[13]
    @test bG[19] == grid[14]
    @test bG[20] == grid[15]
    @test bG[21] == bgPos
    @test bG[22] == grid[12]
    @test bG[23] == grid[11]
    @test bG[24] == grid[10]
    @test bG[25] == bgPos
    @test bG[26] == grid[19]
    @test bG[27] == grid[20]
    @test bG[28] == grid[21]
    @test bG[29] == bgPos
    @test bG[30] == grid[24]
    @test bG[31] == grid[23]
    @test bG[32] == grid[22]
    @test bG[33] == bgPos
    @test bG[34] == grid[25]
    @test bG[35] == grid[26]
    @test bG[36] == grid[27]
    @test bG[37] == bgPos

    h5open(pospath, "w") do file
      write(file, bG)
    end
    h5open(pospath, "r") do file
      bG1 = Positions(file)
      @test bG1[1] ≈ grid[1]
      @test shape(bG1) == shp
      @test fieldOfView(bG1) == fov
      @test fieldOfViewCenter(bG1) == ctr
    end
  end

  positions = [1 2 3 4; 0 1 2 3;-4 -3 -2 -1]Unitful.mm
  aG1 = ArbitraryPositions(positions)
  @test aG1[1] == [1,0,-4]*Unitful.mm
  @test aG1[2] == [2,1,-3]Unitful.mm
  @test aG1[3] == [3,2,-2]Unitful.mm
  @test aG1[4] == [4,3,-1]Unitful.mm
  aG2 = ArbitraryPositions(caG)
  @test aG2[1] == caG[1]
  @test aG2[2] == caG[2]
  @test aG2[27] == caG[27]
  h5open(pospath, "w") do file
    write(file, aG2)
  end
  h5open(pospath, "r") do file
    aG3 = Positions(file)
    @test typeof(aG3) <: ArbitraryPositions
    @test aG3.positions == aG2.positions
  end

  # the same seed yields the same sequence of points
  seed = UInt32(42)
  N = UInt(3)
  domain = AxisAlignedBox(fov,ctr)
  @test domain.fov == fov
  @test domain.center == ctr
  rP1 = UniformRandomPositions(N,seed,domain)
  @test rP1[1] == [0.09954904813158394,-0.13791259323857274,-1.446939519855107]Unitful.mm
  @test rP1[2] == [-0.9812009131891462,1.3767776289892044,1.4206979394110573]Unitful.mm
  @test rP1[3] == [-0.5883911667396526,-0.9692742011014337,1.3707474722677764]Unitful.mm
  @test_throws BoundsError rP1[0]
  @test_throws BoundsError rP1[4]
  h5open(pospath, "w") do file
    write(file, rP1)
  end
  h5open(pospath, "r") do file
    rP2 = Positions(file)
    @test typeof(rP2) <: UniformRandomPositions{AxisAlignedBox}
    @test rP2.N == N
    @test rP2.seed == seed
    @test rP2.domain.fov == fov
    @test rP2.domain.center == ctr
  end
  radius = 10Unitful.mm
  domain = Ball(radius,ctr)
  @test domain.radius == radius
  @test domain.center == ctr
  rP3 = UniformRandomPositions(N,seed,domain)
  @test rP3[1] == [-6.715713750009747,0.4103832286623821,-4.525933276650638]Unitful.mm
  @test_throws BoundsError rP3[0]
  @test_throws BoundsError rP3[4]
  h5open(pospath, "w") do file
    write(file, rP3)
  end
  h5open(pospath, "r") do file
    rP4 = Positions(file)
    @test typeof(rP4) <: UniformRandomPositions{Ball}
    @test rP4.N == N
    @test rP4.seed == seed
    @test rP4.domain.radius == radius
    @test rP4.domain.center == ctr
  end
  #TODO conversion methods dont work. Why?
  #rG = UniformRandomPositions(15,fov,ctr)

  # the following 2 tests fail but should work
  @test_throws DomainError loadTDesign(8,1)
  @test_throws DomainError loadTDesign(10,1)
  t = 1
  N = 2
  radius = 5Unitful.mm
  tDesign = loadTDesign(t,N, radius)
  @test length(tDesign) == N
  @test tDesign.T == t
  @test tDesign.radius == radius
  @test any(tDesign.positions .== [1 -1; 0 0; 0 0])
  @test tDesign[1] == [5,0,0]Unitful.mm
  @test tDesign[2] == [-5,0,0]Unitful.mm
  h5open(pospath, "w") do file
    write(file, tDesign)
  end
  h5open(pospath, "r") do file
    tDesign1 = Positions(file)
    @test typeof(tDesign1) <: SphericalTDesign
    @test tDesign1.radius == tDesign.radius
    @test tDesign1.center == tDesign.center
    @test tDesign1.positions == tDesign.positions
  end

  @test length(caG) == prod(shp)
  @test length(chG) == prod(shp)
  @test length(aG1) == size(positions,2)
  @test length(aG2) == prod(shp)

  for (i,p) in enumerate(caG)
    @test p == caG[i]
  end
end


text:
for i ∈ 0:959
    @test chess960fen(i) == fen(fromfen(chess960fen(i)))
end


text:
using MDBM
using PyPlot
pygui(true)

#Solution of an uncertain implicit equation

function foo(x,y)
    x^2.0+y^2.0-2.0^2.0+randn()
end

for k = 1:5
mymdbm=MDBM_Problem(foo,[-3.0:3.0,-3.0:3.0])
solve!(mymdbm,5)

x_sol,y_sol=getinterpolatedsolution(mymdbm)
fig = figure(1)#;clf()
scatter(x_sol,y_sol,s=4);

fig = figure(2)#;clf()
hist(x_sol,100)
end


text:
using Documenter, DECAES

makedocs(;
    modules = [DECAES],
    format = Documenter.HTML(
        prettyurls = get(ENV, "CI", nothing) == "true",
    ),
    sitename = "DECAES.jl",
    authors = "Jonathan Doucette",
    pages = [
        "Home" => "index.md",
        "cli.md",
        "ref.md",
    ],
)

deploydocs(;
    repo = "github.com/jondeuce/DECAES.jl.git",
    push_preview = true,
    deploy_config = Documenter.GitHubActions(),
)


text:
export SectoralPrism

const SectoralPrism = Prism{Sector}

# Below, if we called SectoralPrism(c, ...) in the function body, it would call the inner
# constructor Prism{Sector{Nothing}}(c, ...) because SectoralPrism = Prism{Sector{Nothing}},
# which is not what we want.
# To call the outer constructor of Prism, we should call Prism(c, ...) instead of SectoralPrism(c, ...).
SectoralPrism(c::SVector{3,<:Real},
              r::Real,
              ϕ::Real,
              ∆ϕ::Real,
              h::Real=Inf,
              a::SVector{3,<:Real}=SVector(0.0,0.0,1.0)
              ) where {K} =
    (â = normalize(a); Prism(c, Sector(SVector(0.0,0.0),r,ϕ,∆ϕ), h, [orthoaxes(â)... â]))

SectoralPrism(c::AbstractVector{<:Real},  # center of prism
              r::Real,  # radius of sectoral base
              ϕ::Real,  # start angle of sectoral base: 0 ≤ ϕₛ < 2π  (2π excluded)
              ∆ϕ::Real,  # end angle sectoral base: 0 ≤ ϕₑ-ϕₛ ≤ 2π
              h::Real=Inf,  # height of prism
              a::AbstractVector{<:Real}=[0.0,0.0,1.0]) =  # axis direction of prism
    SectoralPrism(SVector{3}(c), r, ϕ, ∆ϕ, h, SVector{3}(a))

function bounds_ctrcut(s::SectoralPrism)
    ax = inv(s.p)  # prism axes: columns are not only unit vectors, but also orthogonal
    if ax ≈ I  # prism axes are aligned with Cartesian directions (this covers most usage)
        l, u = bounds(s.b)  # (SVector{2}, SVector{2})
        a₁₂ = ax[:,SVector(1,2)]  # SMatrix{3,2}

        return a₁₂*l, a₁₂*u
    else  # prism axes are not aligned with Cartesian directions
        b = s.b
        r = b.r

        el = Ellipsoid(SVector(0.0,0.0,0.0), SVector(r,r,0.0), ax)  # center is set at origin to return bounds with respect to prism center
        bp = boundpts(el)  # SMatrix{3,3}: boundary points; all three columns of b are free of NaN because no column of ax is aligned with Cartesian directions
        bp′ = s.p * bp  # SMatrix{3,3}: bp in prism coordinates
        bp2′ = bp′[SVector(1,2),:]  # SMatrix{2,3}: in each column of bp′, third entry is in axis dimension, so must be zero mathematically

        ϕ = atan.(bp2′[2,:], bp2′[1,:])  # SVector{3}: angles of boundary points in base plane
        ϕsym = [ϕ; ϕ.+π]  # SVector{6}: include symmetric points with respect to base center
        ϕall = [ϕsym; SVector(b.ϕ₀-b.∆ϕ2, b.ϕ₀+b.∆ϕ2)]  # SVector{8}: angles of all boundary point candidates, except base center

        bpall′ = r .* [cos.(ϕall) sin.(ϕall) @SVector(zeros(8))]'  # SMatrix{3,8}: each column is boundary point candidate in prism coordinates
        bpall = ax * bpall′  # SMatrix{3,8}: each column is boundary point candidate in external coordinates
        bpallc = [bpall SVector(0.0,0.0,0.0)]  # SMatrix{3,9}: include base center
        ind = abs.(distangle.(ϕsym, b.ϕ₀)) .≤ b.∆ϕ2  # SVector{6}: indices of angles contained in base arc
        indallc = [ind; SVector(true,true,true)]  # SVector{9}: include arc ends and base center

        xs = bpallc[1,:]
        ys = bpallc[2,:]
        zs = bpallc[3,:]

        # It might be possible to implement the following more efficiently using reduce().
        xmin = ymin = zmin = Inf
        xmax = ymax = zmax = -Inf
        for i = 1:9
            if indallc[i]
                xmin = min(xmin, xs[i])
                ymin = min(ymin, ys[i])
                zmin = min(zmin, zs[i])

                xmax = max(xmax, xs[i])
                ymax = max(ymax, ys[i])
                zmax = max(zmax, zs[i])
            end
        end

        return (SVector(xmin,ymin,zmin), SVector(xmax,ymax,zmax))
    end
end


text:
using OffsetArrays
using ProgressMeter
using PyPlot
using LsqFit
using ReadCoverageDistributions,Test

@testset "simulate_readcoverage" begin
n=10
genome_length=10^2
read_length=5
no_reads=1
hist1=ReadCoverageDistributions.simulate_readcoverage(n,genome_length,read_length,no_reads)
@test size(hist1)==(3,)
sum=0
for j in 0:2
    for i in 1:length(hist1[j])
        sum+=i*hist1[j][i]
    end
end
#@test (genome_length*sum-genome_length)<10
end

@testset "simulate_oceansislands" begin
n=100
genome_length=10^7
read_length=100
no_reads=10^5
hist1=ReadCoverageDistributions.simulate_oceansislands(n,genome_length,read_length,no_reads)
sum=0
for j in 0:1
    for i in 1:length(hist1[j])
        sum+=i*hist1[j][i]
    end
end
@test (genome_length-sum)<5000
@test size(hist1)==(2,)
end

@testset "Histogram Helpers" begin
	# increment!
	h = zeros(Int64, 10)
	@test all(h .== 0)

	increment!(h, 1)
	@test h[1] == 1

	@test length(h) < 20
	increment!(h, 20)
	@test h[20] == 1
	@test length(h) >= 20
	@test h[19] == 0

	# hist_add!
	h1 = [0, 0, 1]
	h2 = [1, 1, 0, 1, 1]
	h = hist_add!(h1, h2)
	@test length(h) == max(length(h1), length(h2))
	@test all(h .== 1)

	h1 = [0, 0, 1]
	h2 = [1, 1, 0, 1, 1]
	h = hist_add!(h2, h1)
	@test length(h) == max(length(h1), length(h2))
	@test all(h .== 1)

    #vec_hist_add!
    @test vec_hist_add!([[1.0,3.0]],[[2.0,4.0]])==[[3.0, 7.0]]
    @test vec_hist_add!([[1.0,3.0]],[[2.0,4.0,5.0]])==[[3.0, 7.0, 5.0]]
end

@testset "IslandIterator discrete version" begin
    starts = [3, 5, 9, 40]
    length_read = 2
    @test collect(IslandIterator(starts, length_read)) == [(2, 4), (1, 2), (1, 2)]

    length_read = 3
    @test collect(IslandIterator(starts, length_read)) == [(2, 5), (1, 3), (1, 3)]

    length_read = 5
    @test collect(IslandIterator(starts, length_read)) == [(3, 11), (1, 5)]

    starts = [3, 5, 9, 40, 40]
    length_read = 2
    @test collect(IslandIterator(starts, length_read)) == [(2, 4), (1, 2), (2, 2)]

    starts = [3, 5, 9, 40, 41]
    length_read = 2
    @test collect(IslandIterator(starts, length_read)) == [(2, 4), (1, 2), (2, 3)]
end

@testset "IslandIterator continious version" begin
    starts = [3.0, 5.0, 9.0, 40.0]
    length_read = 3.0
    @test collect(IslandIterator(starts, length_read)) == [(2, 5.0), (1, 3.0), (1, 3.0)]

    length_read = 2.0
    @test collect(IslandIterator(starts, length_read)) == [(2, 4.0), (1, 2.0), (1, 2.0)]

    starts = [3.0, 5.0, 9.0, 40.0] .+ 0.5
    length_read = 3.0
    @test collect(IslandIterator(starts, length_read)) == [(2, 5.0), (1, 3.0), (1, 3.0)]

    starts = [3.0, 5.0 + 0.000001, 9.0, 40.0]
    length_read = 2.0
    @test collect(IslandIterator(starts, length_read)) ==
        [(1, 2.0), (1, 2.0), (1, 2.0), (1, 2.0)]
end

@testset "Merge_sort" begin
    s = 1:0.000001:10000000
    L = 100000
    x = sort(rand(s, L))
    y = sort(rand(s, L))
    @test length(merge_sorted_arrays(x,y)) == length(x) + length(y)
    @test merge_sorted_arrays(x,y)  == sort(vcat(x,y))

    s = 1:10
    L = 10
    x = sort(rand(s, L))
    y = sort(rand(s, 2*L))
    @test length(merge_sorted_arrays(x,y)) == length(x) + length(y)
    @test merge_sorted_arrays(x,y)  == sort(vcat(x,y))
end

@testset "count_islands_and_append_to_array" begin
    read_locations=[0.7938454015695862, 1.2664405566742531, 1.984966354304496, 4.445497047524059, 5.3558595394406705, 5.723246025280289, 6.961645696749663, 7.5597158849959945, 9.110791441702704, 9.184417263215249]
    res=count_islands_and_append_to_array!(10,read_locations,max_no_of_reads=100,read_length=1);
    sum=0
    for i in res
    	sum+=i[5]
    end
    @test sum==7.140565940250017
end


text:
using Convex
Random.seed!(2)

m = 40;  n = 50
A = randn(m, n); b = randn(m, 1)
x = Variable(n)
problem = minimize(sumsquares(A * x - b), [x >= 0])

ϵ = 1e-8
@static if VERSION >= v"1.5.0"
    # New random numbers in julia 1.5
    opt = 10.945929126466417
    #opt = 10.945829112949474
else
    opt = 12.38418747141913 # Before julia 1.5
end
dr = DR(eps=ϵ, verbose=1)

solve!(problem, dr)

@test problem.status == :Optimal
@test problem.optval ≈ opt
@test abs(minimum(x.value)) < 10*ϵ

xsave = copy(x.value)

# Test indirect
problem = minimize(sumsquares(A * x - b), [x >= 0])
solve!(problem, GAPA(eps=1e-4, verbose=0))

@test problem.status == :Optimal
@test abs((problem.optval - opt)/opt) < 2e-3
@test maximum(abs.(x.value-xsave)) < 1e-3

#Test direct
problem = minimize(sumsquares(A * x - b), [x >= 0])
solve!(problem, GAPA(direct=true, eps=1e-4, verbose=0))

@test problem.status == :Optimal
@test abs((problem.optval - opt)/opt) < 2e-3
@test maximum(abs.(x.value-xsave)) < 1e-3

# Test β in GAPA
problem = minimize(sumsquares(A * x - b), [x >= 0])
solve!(problem, GAPA(0.5, 0.9, eps=1e-9, verbose=0))

@test problem.status == :Optimal
@test abs((problem.optval - opt)/opt) < 1e-8
@test maximum(abs.(x.value-xsave)) < 1e-7


text:
using RAFF
using Printf
using ArgParse
using Random

function mainf()

    s = ArgParseSettings()

    @add_arg_table s begin

        "np"
        help = "Number of points"
        arg_type = Int
        required = true

        "p"
        help = "Number of trusted points"
        arg_type = Int
        required = true

        "--model"
        help = "Model function: linear, cubic, expon, logistic"
        arg_type = String
        default = "linear"

        "--fname"
        help = "File name"
        arg_type = String
        default = "output"

        "--sol"
        help = "Solution"
        nargs = '*'
        arg_type = Float64

        "--cint"
        help = "Cluster interval"
        nargs = 2
        arg_type = Float64

        "--i"
        help = "Generate i-th run."
        arg_type = Int
        default = 0

        "--std"
        help = "Standard deviation of the error."
        arg_type = Float64
        default = 200.0

    end

    # Main program

    parsed_args = parse_args(ARGS, s)

    n, model, modelStr = RAFF.model_list[parsed_args["model"]]

    x_interval = (- 0.0, 30.0)

    θSol = Vector{Float64}(undef, n)

    if length(parsed_args["sol"]) == 0

        randn!(θSol)

    elseif length(parsed_args["sol"]) == n

        θSol .= parsed_args["sol"]

    else

        error("Incorrect number of elements in solution")

    end

    fname = parsed_args["fname"]

    try

        ffname = "/tmp/" * fname * ".txt"
        fsname = "/tmp/" * fname * "_sol.txt"

        if parsed_args["i"] != 0

            Random.seed!(179424673 + parsed_args["i"])

        end

        if length(parsed_args["cint"]) == 2

            generate_test_problems(ffname, fsname, model, modelStr, n,
                parsed_args["np"], parsed_args["p"], x_interval,
                Tuple(parsed_args["cint"]); θSol=θSol, std=parsed_args["std"])

        else

            generate_test_problems(ffname, fsname, model, modelStr, n,
                parsed_args["np"], parsed_args["p"];
                x_interval=x_interval, θSol=θSol, std=parsed_args["std"])

        end

        @printf("Created problem and solution files.\n")

    catch e

        @printf("Problems when creating test problem.\n")
        println(e)

    end

end

mainf()


text:
module Blind

using Random

using ArgParse
using ProgressMeter

using FileIO, CSVFiles

export blind

DEFAULT_NUMERIC = 4
DEFAULT_SETS = 3

function parse_commandline()
    s = ArgParseSettings()

    @add_arg_table! s begin
        "--sets", "-s"
            help = "Number of numeric sets."
            arg_type = Int
            default = DEFAULT_SETS
        "--numeric", "-n"
            help = "Number of numeric characters."
            arg_type = Int
            default = DEFAULT_NUMERIC
        "input"
            help = "Input directory."
            required = true
        "output"
            help = "Output directory."
            required = false
        "key"
            help = "Key file (.csv)."
            required = false
    end

    return parse_args(s)
end

function generate_names(n::Int, num_sets::Int, num_numeric::Int)
    strs = Vector{String}()

    @info "Generating $n strings with $num_sets sets of $num_numeric numerics."
    while length(strs) < n

        sets = [String(rand('0':'9', num_numeric)) for i in 1:num_sets]

        str = join(sets, "-")

        if !in(str, strs)
            push!(strs, str)
        end
    end

    return strs
end

function _nt(path_original::AbstractString, path_blind::AbstractString)
    return NamedTuple{(:original, :blind),Tuple{String,String}}((path_original, path_blind))
end

function blind(dir_input::AbstractString, dir_output::AbstractString, path_key::AbstractString; num_sets::Int = DEFAULT_SETS, num_numeric::Int = DEFAULT_NUMERIC)

    isdir(dir_input) || error("Input $dir_input is not a directory.")

    mkpath(dir_output)

    @info "Reading input $dir_input."
    files_original = readdir(dir_input)

    strs = generate_names(length(files_original), num_sets, num_numeric)
    exts = files_original .|> (str) ->(splitext(str)[2])

    files_blind = string.(strs, exts)

    paths_original = joinpath.(dir_input, files_original)
    paths_blind = joinpath.(dir_output, files_blind)

    @info "Copying to output $dir_output"
    @showprogress 1 for (path_original, path_blind) in zip(paths_original, paths_blind)
        cp(path_original, path_blind)
    end

    @info "Saving key to $path_key"
    nts = _nt.(paths_original, paths_blind)

    nts |> save(path_key)
end

function blind(dict::Dict)

    if dict["key"] === nothing
        dict["key"] = joinpath(dict["input"], "key.csv")
    end

    if dict["output"] === nothing
        dict["output"] = string(dict["input"], "-blind")
    end

    return blind(dict["input"], dict["output"], dict["key"], num_sets = dict["sets"], num_numeric = dict["numeric"])
end

end # module


text:
using Documenter, GaussLaw1D

makedocs(;
    modules=[GaussLaw1D],
    format=Documenter.HTML(),
    pages=[
        "Home" => "index.md",
    ],
    repo="https://github.com/jw3126/GaussLaw1D.jl/blob/{commit}{path}#L{line}",
    sitename="GaussLaw1D.jl",
    authors="Jan Weidner",
    assets=String[],
)


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

using Markdown
using InteractiveUtils

# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
    quote
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing
        el
    end
end

# ╔═╡ 747d446a-dfeb-11ea-3533-c9404fd41688
begin
	using IndividualDisplacements, Plots, NetCDF, OrdinaryDiffEq, DataFrames
	using Statistics, StatsPlots, PlutoUI

	p=dirname(pathof(IndividualDisplacements))
    include(joinpath(p,"../examples/example123.jl"))
    include(joinpath(p,"../examples/helper_functions.jl"))
    include(joinpath(p,"../examples/recipes_plots.jl"))
	𝑃,Γ=OCCA_setup()
	tmp=(Γ = Γ, m = "OCCA")
    𝑃=merge(𝑃,tmp)
	✓ = "😃"
	"$✓ Set up packages, gridded domain, etc"
end

# ╔═╡ bf19d29c-e70e-11ea-0153-d3a49981d56c
md"""longitude,latitude of South West corner =
$(@bind lon0 NumberField(-180.0:10:180.0; default=0.0))
,
$(@bind lat0 NumberField(-90.0:5:90.0; default=-50.0))
"""

# ╔═╡ 4935fd46-e70f-11ea-386c-f9c444a20644
md"""depth level (integer), set size (nb of particles) =
$(@bind klev NumberField(1:10; default=5))
,
$(@bind npar NumberField(50:50:1000; default=100))
"""

# ╔═╡ 9c80e722-e70f-11ea-22a6-0be2e85f3b8b
md"""time step (for plotting)=
$(@bind tt Slider(2:75; default=50, show_value=true))
"""

# ╔═╡ e25eee9e-dfee-11ea-2a4c-3946ccb63876
begin
	lo0=lon0; lo1=lo0+5
	la0=lat0; la1=la0+5
	z_init=klev
	n_part=npar
	(particles=n_part,longitudes=(lo0,lo1),latitudes=(la0,la1),level=z_init,plot_time=tt)
end

# ╔═╡ f75fae30-dfee-11ea-18ef-259321acfa2f
begin
	day=86400.0
	mon=365/12*day
	solv(prob) = solve(prob,Euler(),dt=2*day)

	lon=lo0 .+(lo1-lo0).*rand(n_part)
	lat=la0 .+(la1-la0).*rand(n_part)
	(xy,du)=initialize_lonlat(Γ,lon,lat)
	xy[3,:] .= z_init
	id=collect(1:size(xy,2))

	function solv(prob)
	  sol=solve(prob,Euler(),dt=10*86400.0)
	  nx,ny=𝑃.ioSize[1:2]
	  sol[1,:,:]=mod.(sol[1,:,:],nx)
	  sol[2,:,:]=mod.(sol[2,:,:],ny)
	  return sol
	end

	tr = DataFrame(ID=Int[], fid=Int[], x=Float64[], y=Float64[],
	               z=Float64[], t=Float64[], lon=Float64[], lat=Float64[])

	function postproc(sol,𝑃::NamedTuple;id=missing,𝑇=missing)
	  df=postprocess_lonlat(sol,𝑃,id=id,𝑇=𝑇)
	  #add third coordinate
	  z=sol[3,:,:]
	  df.z=z[:]
	  #to plot e.g. Pacific Ocean transports, shift longitude convention?
	  #df.lon[findall(df.lon .< 0.0 )] = df.lon[findall(df.lon .< 0.0 )] .+360.0
	  return df
	end

	"$✓ Set up Individuals"
end

# ╔═╡ 9ffe84c0-dff0-11ea-2726-8924892df73a
begin
	𝐼 = Individuals{Float64}(📌=deepcopy(xy), 🔴=deepcopy(tr), 🆔=id,
		                     🚄 = dxyz_dt, ∫ = solv, 🔧 = postproc, 𝑃=𝑃)

	𝑇=(0.0,𝐼.𝑃.𝑇[2])
	∫!(𝐼,𝑇)

	🔴_by_ID = groupby(𝐼.🔴, :ID)
	🔴_by_t = groupby(𝐼.🔴, :t)

	ff(x) = x[1]
	tmp1=combine(🔴_by_ID,:lon => ff => :lo,:lat => ff => :la)
	𝐼.🔴.dlon=𝐼.🔴.lon - tmp1.lo[𝐼.🔴.ID]
	𝐼.🔴.dlat=𝐼.🔴.lat - tmp1.la[𝐼.🔴.ID]

	nt=length(unique(𝐼.🔴.t))

	"$✓ ∫!(𝐼,𝑇) etc"
end

# ╔═╡ f65ddffa-e63a-11ea-34a6-2fa9284e98fa
begin
	mx=50.0

	#f(x)=x[tt]-x[1]
	#f(x)=last(x).-first(x)
	#cdf = combine(🔴_by_ID,nrow,:lat => f => :dlat,:lon => f => :dlon)

	g(x)=x[tt]
	cdf = combine(🔴_by_ID,:dlat => g => :dlat,:dlon => g => :dlon)

	plt_hist=histogram2d(cdf.dlon,cdf.dlat,nbins = (10, 10),
		xlims=(-mx,mx),ylims=(-mx,mx), colorbar=false)
	#scatter(cdf.dlon,cdf.dlat,xlims=(-mx,mx),ylims=(-mx,mx))
	"$✓ dlon, dlat histogram2d"
end

# ╔═╡ 7d52252e-e006-11ea-2632-df2af831b52f
begin
	x=vec(𝐼.𝑃.Γ["XC"][1][:,1])
	y=vec(𝐼.𝑃.Γ["YC"][1][1,:])
	z=transpose(log10.(𝐼.𝑃.Γ["Depth"][1]))
	𝐵=(x = x, y = y, z = z)

	𝐶(g::ColorGradient) = RGB[g[z] for z=LinRange(0,1,length(🔴_by_t))]
	𝐶(t::Int) = 𝐶(cgrad(:inferno))[t]
	"$✓ Set up plotting"
end

# ╔═╡ 0b12cf52-e6e3-11ea-1a01-dd0c49c9e641
begin
	plt_dlat = @df 🔴_by_t[1] density(:dlat, leg = :none, colour = 𝐶(1), ylims=(0,0.5))
	[@df 🔴_by_t[tt] density!(plt_dlat,:dlat, leg = :none, colour = 𝐶(tt)) for tt in 2:length(🔴_by_t)];
	density!(plt_dlat,🔴_by_t[nt].dlat, leg = :none, colour = :cyan, linewidth=4)
	"$✓ dlat density"
end

# ╔═╡ 6f70033a-e6cc-11ea-373e-6dcbaaa53d15
begin
	#clims=extrema(:t)
	#@df 𝐼.🔴 density(:lon, group = (:t), leg = :none, palette = cgrad(:ice))
	plt_dlon = @df 🔴_by_t[1] density(:dlon, leg = :none, colour = 𝐶(1), ylims=(0,0.5))
	[@df 🔴_by_t[tt] density!(plt_dlon,:dlon, leg = :none, colour = 𝐶(tt)) for tt in 2:length(🔴_by_t)];
	density!(plt_dlon,🔴_by_t[tt].dlon, leg = :none, colour = :cyan, linewidth=4)
	"$✓ dlon density"
end

# ╔═╡ a13d6ea6-dff1-11ea-0713-cb235e28cf79
begin
	plt_map=contourf(x,y,z,clims=(-.5,4.),c = :ice,
		colorbar=false, xlims=(-180.0,180.0),ylims=(-90.0,90.0))
	scatter!(plt_map,🔴_by_t[1].lon,🔴_by_t[1].lat,c=:gold,leg=:none,
		markersize=2.0, marker = (:dot, stroke(0)) )
	scatter!(plt_map,🔴_by_t[tt].lon,🔴_by_t[tt].lat,c=:red,leg=:none,
		markersize=2.0, marker = (:dot, stroke(0)) )

	plot(plt_map,plt_hist,plt_dlon,plt_dlat)
end

# ╔═╡ Cell order:
# ╟─bf19d29c-e70e-11ea-0153-d3a49981d56c
# ╟─4935fd46-e70f-11ea-386c-f9c444a20644
# ╟─9c80e722-e70f-11ea-22a6-0be2e85f3b8b
# ╟─e25eee9e-dfee-11ea-2a4c-3946ccb63876
# ╟─a13d6ea6-dff1-11ea-0713-cb235e28cf79
# ╟─f65ddffa-e63a-11ea-34a6-2fa9284e98fa
# ╟─0b12cf52-e6e3-11ea-1a01-dd0c49c9e641
# ╟─6f70033a-e6cc-11ea-373e-6dcbaaa53d15
# ╟─9ffe84c0-dff0-11ea-2726-8924892df73a
# ╟─7d52252e-e006-11ea-2632-df2af831b52f
# ╟─f75fae30-dfee-11ea-18ef-259321acfa2f
# ╟─747d446a-dfeb-11ea-3533-c9404fd41688


text:
using PowerModelsSecurityConstrained
using PowerModels

using Memento

using Test

using Ipopt
using Cbc

Memento.setlevel!(Memento.getlogger(PowerModels.InfrastructureModels), "error")
Memento.setlevel!(Memento.getlogger(PowerModels), "error")
Memento.setlevel!(Memento.getlogger(PowerModelsSecurityConstrained), "error")

nlp_solver = optimizer_with_attributes(Ipopt.Optimizer, "tol"=>1e-6, "print_level"=>0)
#nlp_solver = optimizer_with_attributes(Ipopt.Optimizer, "tol"=>1e-6)
lp_solver = optimizer_with_attributes(Cbc.Optimizer, "logLevel"=>0)
#lp_solver = optimizer_with_attributes(Cbc.Optimizer)

ini_file = "../test/data/inputfiles.ini"
scenarios = ["scenario_01", "scenario_02"]
cases = [parse_goc_files(ini_file, scenario_id=sid) for sid in scenarios]

networks = [build_pm_model(case) for case in cases]
solutions = [read_solution1(networks[i], output_dir=dirname(case.files["raw"])) for (i,case) in enumerate(cases)]

case_infeasible = parse_goc_files(ini_file, scenario_id="scenario_03")
network_infeasible = build_pm_model(case_infeasible)

@testset "PowerModelsSecurityConstrained" begin

    include("common.jl")

    include("opf.jl")

    include("contingency.jl")

    include("contingency-stage.jl")

    include("scopf.jl")

end


text:
using Turing, BenchmarkTools, BenchmarkHelper

## Dummny benchmarks

BenchmarkSuite["dummy"] = BenchmarkGroup(["dummy"])

data = [0, 1, 0, 1, 1, 1, 1, 1, 1, 1]

@model constrained_test(obs) = begin
    p ~ Beta(2,2)
    for i = 1:length(obs)
        obs[i] ~ Bernoulli(p)
    end
    p
end

BenchmarkSuite["dummy"]["dummy"] = @benchmarkable sample(constrained_test($data), HMC(0.01, 2), 2000)

## gdemo

BenchmarkSuite["gdemo"] = BenchmarkGroup(["gdemo"])

@model gdemo(x, y) = begin
    s² ~ InverseGamma(2, 3)
    m ~ Normal(0, sqrt(s²))
    x ~ Normal(m, sqrt(s²))
    y ~ Normal(m, sqrt(s²))
    return s², m
end

BenchmarkSuite["gdemo"]["hmc"] = @benchmarkable sample(gdemo(1.5, 2.0), HMC(0.01, 2), 2000)

##
## MvNormal
##

BenchmarkSuite["mnormal"] = BenchmarkGroup(["mnormal"])

# Define the target distribution and its gradient
const D = 10

@model target(dim) = begin
   Θ = Vector{Real}(undef, dim)
   θ ~ MvNormal(zeros(D), ones(dim))
end

# Sampling parameter settings
n_samples = 100_000
n_adapts = 2_000

BenchmarkSuite["mnormal"]["hmc"] = @benchmarkable sample(target($D), HMC(0.1, 5), $n_samples)

## MvNormal: ForwardDiff vs BackwardDiff (Tracker)

using LinearAlgebra

@model mdemo(d, N) = begin
    Θ = Vector(undef, N)
   for n=1:N
      Θ[n] ~ d
   end
end

dim2 = 250
A    = rand(Wishart(dim2, Matrix{Float64}(I, dim2, dim2)));
d    = MvNormal(zeros(dim2), A)

# ForwardDiff
Turing.setadbackend(:forwarddiff)
BenchmarkSuite["mnormal"]["forwarddiff"] = @benchmarkable sample(mdemo($d, 1), HMC(0.1, 5), 5000)

# BackwardDiff
Turing.setadbackend(:reversediff)
BenchmarkSuite["mnormal"]["reversediff"] = @benchmarkable sample(mdemo($d, 1), HMC(0.1, 5), 5000)


text:
using Unitful, MagneticResonanceSignals, Test
using MagneticResonanceSignals: FixedString
using AxisArrays

@testset "NMRPipe format IO" begin
    test_header = [
       # Name              Type               Offset            Ground truth
        ("FDFLTFORMAT",    Float32,           1,                4.0086362f9),
        ("FDFLTORDER",     Float32,           2,                Float32(2.3450000286102295)),
        ("FDDIMCOUNT",     Float32,           9,                2),
        ("FDF3SIZE",       Float32,           15,               1.),
        ("FDF2LABEL",      FixedString{8},    16,               "X"),
        ("FDF1LABEL",      FixedString{8},    18,               "Y"),
        ("FDF3LABEL",      FixedString{8},    20,               "Z"),
        ("FDF4LABEL",      FixedString{8},    22,               "A"),
        ("FDDIMORDER1",    Float32,           24,               2.0),
        ("FDDIMORDER2",    Float32,           25,               1.0),
        ("FDDIMORDER3",    Float32,           26,               3.0),
        ("FDDIMORDER4",    Float32,           27,               4.0),
        ("FDF4SIZE",       Float32,           32,               1.),
        ("FDF1QUADFLAG",   Float32,           55,               0.0),
        ("FDF2QUADFLAG",   Float32,           56,               0.0),
        ("FDF2CAR",        Float32,           66,               Float32(1.2)),
        ("FDF1CAR",        Float32,           67,               0),
        ("FDF2CENTER",     Float32,           79,               2.0),
        ("FDF1CENTER",     Float32,           80,               5.0),
        ("FDF3CENTER",     Float32,           81,               1.),
        ("FDF4CENTER",     Float32,           82,               1.),
        ("FDF2APOD",       Float32,           95,               2.0),
        ("FDREALSIZE",     Float32,           97,               8.0),
        ("FDSIZE",         Float32,           99,               8.0),
        ("FDF2SW",         Float32,           100,              1000.0),
        ("FDF2ORIG",       Float32,           101,              Float32(147.7476)),
        ("FDF2OBS",        Float32,           119,              Float32(123.123)),
        ("FDF1OBS",        Float32,           218,              Float32(123.123)),
        ("FDSPECNUM",      Float32,           219,              4.0),
        ("FDF2FTFLAG",     Float32,           220,              0.0),
        ("FDF1FTFLAG",     Float32,           222,              0.0),
        ("FDF1SW",         Float32,           229,              Float32(1250)),
        ("FDF1ORIG",       Float32,           249,              Float32(468.75 * -1)),
        ("FD2DPHASE",      Float32,           256,              0.0),
        ("FDF2TDSIZE",     Float32,           386,              2.0),
        ("FDF1TDSIZE",     Float32,           387,              8.0),
        ("FD2DVIRGIN",     Float32,           399,              1.),
        ("FDF1APOD",       Float32,           428,              8.0),
        ("FDFILECOUNT",    Float32,           442,              1.),
        ("FDF1AQSIGN",     Float32,           475,              16),
    ]
    test_data = rand(8,4)
    test_data_ax = AxisArray(test_data,
                             Axis{:time2}((0.0:1.0:7.0)*u"ms"),
                             Axis{:time1}((0.0:0.8:2.4)*u"ms"))
    # Test write NMR Pipe into buffer
    buf = IOBuffer()
    save_nmrpipe(buf, test_data_ax, (Axis{:time1}, Axis{:time2});
                 frequency=123.123u"MHz", ref_freq_offset=(0.0u"ppm", 1.2u"ppm"))
    # Test read the NMR Pipe from buffer and ensure all values are correct
    # 1. Assert header (512 * 4-byte array)
    for (key,type,offset,ground_truth) in test_header
        seek(buf, offset*4)
        @test read(buf, type) == ground_truth
    end

    # 2. Assert data with test_data
    seek(buf, 512*4)
    # Written data: r r r ... i i i ... r r r ... i i i ... and so on
    #               where r = real and i = imaginary
    for i = size(test_data_ax, Axis{:time1}()):-1:1
        fid = test_data_ax[Axis{:time1}(i), Axis{:time2}(:)]
        for real_time2 in real.(fid)
            value = reinterpret(Float32, read(buf, 4))
            @test value[1] == Float32(real_time2)
        end

        for imag_time2 in imag.(fid)
            value = reinterpret(Float32, read(buf, 4))
            @test value[1] == Float32(imag_time2)
        end
    end
end

max_stars_repo_name: TRIImaging/MagneticResonanceSignals

max_issues_repo_name: TRIImaging/MagneticResonanceSignals

max_forks_repo_name: TRIImaging/MagneticResonanceSignals


text:
using Distributed
using Distributions
# using Pkg
# Pkg.activate(".")
# using Psychometrics

# @everywhere using Pkg
# @everywhere Pkg.activate(".")
@everywhere using Psychometrics

function est()
    I_total = 50
    N = 3000
    test_length = 50
    metric = [0.0, 1.0]

    ### generate true items

    a_dist = LogNormal(0, 0.25) # mu= exp(0.4 + (0.5*0.1^2)), sigma^2= exp(0.4 + 0.1^2)*(exp(0.1^2) - 1)
    a_bounds = [1e-5, 5.0]
    b_dist = Normal(0, 1)
    b_bounds = [-4.0, 4.0]
    items = [
        Item(
            i,
            string("item_", i),
            ["math"],
            Parameters2PL(Product([a_dist, b_dist]), a_bounds, b_bounds),
        ) for i = 1:I_total
    ]

    ## generate true examinees

    latent_dist = Normal(0.0, 1.0)
    latent_bounds = [-4.0, 4.0]
    examinees = Psychometrics.Examinee[]
    for n = 1:N
        push!(
            examinees,
            Examinee(n, string("examinee_", n), Latent1D(latent_dist, latent_bounds)),
        )
    end
    ## generate responses
    responses = vcat(map(e -> answer(e, items), examinees)...)

    #start points and probs
    prob = Distributions.pdf(Normal(metric[1], metric[2]), collect(-6.0:0.3:6.0))
    prob = prob ./ sum(prob)
    dist = Distributions.DiscreteNonParametric(collect(-6.0:0.3:6.0), prob)

    # initialize examinees
    latent_est_prior = dist
    latent_est_bounds = [-4.0, 4.0]
    examinees_est = [
        Examinee(e, string("examinee_", e), Latent1D(latent_est_prior, latent_est_bounds)) for e = 1:N
    ]
    #set starting value taking a random value in the interval -0.5:0.5
    map(e -> begin
        e.latent.val = 0.0
    end, examinees_est)
    println(examinees_est[1].latent.prior)
    #initalize items estimates
    a_est_bounds = [1e-5, 5.0]
    b_est_bounds = [-4.0, 4.0]

    items_est = [
        Item(i, string("item_", i), ["math"], Parameters2PL(a_est_bounds, b_est_bounds)) for i = 1:I_total
    ]
    map(i -> begin
        i.parameters.calibrated = false
    end, items_est)
    # starting values
    map(i -> begin
        i.parameters.a = 1.0
    end, items_est)
    map(i -> begin
        i.parameters.b = 0.0
    end, items_est)

    #start calibration
    joint_estimate!(
        items_est,
        examinees_est,
        responses;
        dist = dist,
        method = "mmle",
        rescale_latent = true,
        metric = metric,
        max_iter = 500,
        max_time = 100,
        x_tol_rel = 0.001,
        super_fast_2pl_1d = true
    )
    println("a RMSE")
    println(
        sqrt(
            mean(
                map(
                    (i, i_est) -> (i.parameters.a - i_est.parameters.a)^2,
                    items,
                    items_est,
                ),
            ),
        ),
    )
    println("b RMSE")
    println(
        sqrt(
            mean(
                map(
                    (i, i_est) -> (i.parameters.b - i_est.parameters.b)^2,
                    items,
                    items_est,
                ),
            ),
        ),
    )
    println("latent RMSE")
    println(
        sqrt(
            mean(
                map(
                    (i, i_est) -> (i.latent.val - i_est.latent.val)^2,
                    examinees,
                    examinees_est,
                ),
            ),
        ),
    )
    return examinees, examinees_est, items, items_est, responses
end
examinees, examinees_est, items, items_est, responses = est();


text:
mutable struct LTeX <: MakieLayout.LObject
    parent::Scene
    layoutobservables::MakieLayout.LayoutObservables
    plot::TeXImg
    attributes::Attributes
end

function default_attributes(::Type{LTeX}, scene)
    Attributes(
        tex = raw"\int \mathbf E \cdot d\mathbf a = \frac{Q_{encl}}{4\pi\epsilon_0}",
        visible = true,
        padding = (0f0, 0f0, 0f0, 0f0),
        height = Auto(),
        width = Auto(),
        alignmode = Inside(),
        valign = :center,
        halign = :left,
    )
end

function LTeX(parent::Scene, tex; kwargs...)
    LTeX(parent; tex = tex, kwargs...)
end

function LTeX(parent::Scene; bbox = nothing, kwargs...)
    attrs = merge!(Attributes(kwargs), default_attributes(LTeX, parent))

    @extract attrs (tex, visible, padding, halign, valign)

    layoutobservables = LayoutObservables(LTeX, attrs.width, attrs.height, halign, valign, attrs.alignmode; suggestedbbox = bbox)

    textpos = Node(Point2f0(0, 0))

    cached_tex = @lift CachedTeX($tex)

    wh = @lift ($cached_tex.raw_dims.width, $cached_tex.raw_dims.height)

    t = teximg!(parent, textpos, cached_tex; visible = visible, raw = true, align = @lift ($halign, $valign))[end]

    onany(cached_tex, padding, ) do cached_tex, padding
        autowidth = cached_tex.raw_dims.width + padding[1] + padding[2]
        autoheight = cached_tex.raw_dims.height + padding[3] + padding[4]
        layoutobservables.autosize[] = (autowidth, autoheight)
    end

    onany(layoutobservables.computedbbox, padding, halign, valign) do bbox, padding, halign, valign

        tw = cached_tex[].raw_dims.width
        th = cached_tex[].raw_dims.height

        box = bbox.origin[1]
        boy = bbox.origin[2]

        # this is also part of the hack to improve left alignment until
        # boundingboxes are perfect
        tx = box + padding[1]
        ty = boy + padding[3]

        textpos[] = Point2f0(tx, ty)
    end

    # trigger first update, otherwise bounds are wrong somehow
    tex[] = tex[]
    # trigger bbox
    layoutobservables.suggestedbbox[] = layoutobservables.suggestedbbox[]

    lt = LTeX(parent, layoutobservables, t, attrs)

    lt
end

defaultlayout(lt::LTeX) = ProtrusionLayout(lt)

function align_to_bbox!(lt::LTeX, bbox)
    lt.layoutobservables.suggestedbbox[] = bbox
end

computedsizenode(lt::LTeX) = lt.layoutobservables.computedsize
protrusionnode(lt::LTeX) = lt.layoutobservables.protrusions

function Base.getproperty(lt::LTeX, s::Symbol)
    if s in fieldnames(LTeX)
        getfield(lt, s)
    else
        lt.attributes[s]
    end
end

function Base.setproperty!(lt::LTeX, s::Symbol, value)
    if s in fieldnames(LTeX)
        setfield!(lt, s, value)
    else
        lt.attributes[s][] = value
    end
end

function Base.propertynames(lt::LTeX)
    [fieldnames(LTeX)..., keys(lt.attributes)...]
end

function Base.delete!(lt::LTeX)

    disconnect_layoutnodes!(lt.layoutobservables.gridcontent)
    GridLayoutBase.remove_from_gridlayout!(lt.layoutobservables.gridcontent)
    empty!(lt.layoutobservables.suggestedbbox.listeners)
    empty!(lt.layoutobservables.computedbbox.listeners)
    empty!(lt.layoutobservables.computedsize.listeners)
    empty!(lt.layoutobservables.autosize.listeners)
    empty!(lt.layoutobservables.protrusions.listeners)

    # remove the plot object from the scene
    delete!(lt.parent, lt.plot)
end

# LLegend integration
# function MakieLayout.layoutable_textlike(scene, label::LaTeXString, textsize, font, color, halign, valign)
#     return LTeX(scene,
#         tex = label,
#         halign = halign,
#         valign = valign
#     )
# end
#
# function MakieLayout.layoutable_textlike(scene, label::TeXDocument, textsize, font, color, halign, valign)
#     return LTeX(scene,
#         tex = label,
#         halign = halign,
#         valign = valign
#     )
# end


text:
mutable struct NthNewton <: NearlyNewtonMethod
   counter::Int
   Nth::Int
end
NthNewton(Nth) = NthNewton(Nth-1, Nth)
function update!(scheme::NthNewton, B::DirectApprox, ∇²f, x)
   scheme.counter += 1
   if scheme.count % scheme.Nth == 0
      B.A = ∇²f
      scheme.counter = 0
   end
   B.A
end


text:
latextabular(args...; kwargs...) = latexify(args...; kwargs..., env=:tabular)

function _latextabular(arr::AbstractMatrix; latex::Bool=true, booktabs::Bool=false, head=[], side=[], adjustment::Symbol=:c, transpose=false, kwargs...)
    transpose && (arr = permutedims(arr, [2,1]))

    if !isempty(head)
        arr = vcat(safereduce(hcat, head), arr)
        @assert length(head) == size(arr, 2) "The length of the head does not match the shape of the input matrix."
    end
    if !isempty(side)
        length(side) == size(arr, 1) - 1 && (side = [""; side])
        @assert length(side) == size(arr, 1) "The length of the side does not match the shape of the input matrix."
        arr = hcat(side, arr)
    end

    (rows, columns) = size(arr)
    str = "\\begin{tabular}{" * "$(adjustment)"^columns * "}\n"

    if booktabs
        str *= "\\toprule\n"
    end

    if latex
        arr = latexinline.(arr; kwargs...)
    elseif haskey(kwargs, :fmt)
        formatter = kwargs[:fmt] isa String ? PrintfNumberFormatter(kwargs[:fmt]) : kwargs[:fmt]
        arr = map(x -> x isa Number ? formatter(x) : x, arr)
    end

    # print first row
    str *= join(arr[1,:], " & ")
    str *= "\\\\\n"

    if booktabs && !isempty(head)
        str *= "\\midrule\n"
    end

    for i in 2:size(arr, 1)
        str *= join(arr[i,:], " & ")
        str *= "\\\\\n"
    end

    if booktabs
        str *= "\\bottomrule\n"
    end

    str *= "\\end{tabular}\n"
    latexstr = LaTeXString(str)
    COPY_TO_CLIPBOARD && clipboard(latexstr)
    return latexstr
end

_latextabular(vec::AbstractVector; kwargs...) = latextabular(safereduce(hcat, vec); kwargs...)
_latextabular(vectors::AbstractVector...; kwargs...) = latextabular(safereduce(hcat, vectors); kwargs...)
_latextabular(dict::AbstractDict; kwargs...) = latextabular(hcat(collect(keys(dict)), collect(values(dict))); kwargs...)


text:
using DataValues
using Random
using Test

@testset "DataValueArray: Reduce" begin

    Random.seed!(1)
    f(x) = 5 * x
    f(x::DataValue{T}) where {T <: Number} = ifelse(isna(x), DataValue{typeof(5 * x.value)}(),
                                                    DataValue(5 * x.value))

    for N in (10, 2050)
        A = rand(N)
        M = rand(Bool, N)
        i = rand(1:N)
        M[i] = true
        j = rand(1:N)
        while j == i
            j = rand(1:N)
        end
        M[j] = false
        X = DataValueArray(A)
        Y = DataValueArray(A, M)
        B = A[findall(x -> !x, M)]

        @test isequal(mapreduce(f, +, X), DataValue(mapreduce(f, +, X.values)))
        @test isequal(mapreduce(f, +, Y), DataValue{Float64}())
        v = mapreduce(f, +, Y, skipna=true)
        @test v.value ≈ mapreduce(f, +, B)
        @test !isna(v)

        @test isequal(reduce(+, X), DataValue(reduce(+, X.values)))
        @test isequal(reduce(+, Y), DataValue{Float64}())
        v = reduce(+, Y, skipna=true)
        @test v.value ≈ reduce(+, B)
        @test !isna(v)

        for method in (sum,
        prod,
        minimum,
        maximum,)
            @test method(X) == DataValue(method(A))
            @test method(f, X) == DataValue(method(f, A))
            @test method(Y) == DataValue{Float64}()
            v = method(Y, skipna=true)
            @test v.value ≈ method(B)
            @test !isna(v)
            @test method(f, Y) == DataValue{Float64}()
            v = method(f, Y, skipna=true)
            @test v.value ≈ method(f, B)
            @test !isna(v)
        end

        @test isequal(extrema(X), (DataValue(minimum(A)), DataValue(maximum(A))))
        @test isequal(extrema(Y), (DataValue{Float64}(), DataValue{Float64}()))
        v1 = extrema(Y, skipna=true)
        v2 = extrema(B)
        @test v1[1].value == v2[1]
        @test !isna(v1[1])
        @test v1[2].value == v2[2]
        @test !isna(v1[2])

        H = rand(Bool, N)
        G = H[findall(x -> !x, M)]
        U = DataValueArray(H)
        V = DataValueArray(H, M)

        for op in (&,
        |,)
            @test isequal(reduce(op, U),
                        DataValue(reduce(op, H)))
            @test isequal(reduce(op, U, skipna=true),
                        DataValue(reduce(op, H)))
            @test isequal(reduce(op, V, skipna=true),
                        DataValue(reduce(op, G)))
        end
    end

end


text:
# Arrays
glorot_uniform(dims...) = (rand(Float32, dims...) .- 0.5f0) .* sqrt(24.0f0/sum(dims))
glorot_normal(dims...) = randn(Float32, dims...) .* sqrt(2.0f0/sum(dims))

ones(T::Type, dims...) = Base.ones(T, dims...)
zeros(T::Type, dims...) = Base.zeros(T, dims...)

ones(dims...) = Base.ones(Float32, dims...)
zeros(dims...) = Base.zeros(Float32, dims...)

unsqueeze(xs, dim) = reshape(xs, (size(xs)[1:dim-1]..., 1, size(xs)[dim:end]...))

stack(xs, dim) = cat(unsqueeze.(xs, dim)..., dims=dim)
unstack(xs, dim) = [copy(selectdim(xs, dim, i)) for i in 1:size(xs, dim)]

"""
    chunk(xs, n)

Split `xs` into `n` parts.

```julia
julia> chunk(1:10, 3)
3-element Array{Array{Int64,1},1}:
 [1, 2, 3, 4]
 [5, 6, 7, 8]
 [9, 10]
```
"""
chunk(xs, n) = collect(Iterators.partition(xs, ceil(Int, length(xs)/n)))

batchindex(xs, i) = (reverse(Base.tail(reverse(axes(xs))))..., i)

"""
    frequencies(xs)

Count the number of times that each element of `xs` appears.

```julia
julia> frequencies(['a','b','b'])
Dict{Char,Int64} with 2 entries:
  'b' => 2
  'a' => 1
```
"""
function frequencies(xs)
  fs = Dict{eltype(xs),Int}()
  for x in xs
    fs[x] = get(fs, x, 0) + 1
  end
  return fs
end

head(x::Tuple) = reverse(Base.tail(reverse(x)))

squeezebatch(x) = reshape(x, head(size(x)))

"""
  batch(xs)

Batch the arrays in `xs` into a single array.

```julia
julia> batch([[1,2,3],[4,5,6]])
3×2 Array{Int64,2}:
 1  4
 2  5
 3  6
```
"""
function batch(xs)
  data = first(xs) isa AbstractArray ?
    similar(first(xs), size(first(xs))..., length(xs)) :
    Vector{eltype(xs)}(undef, length(xs))
  for (i, x) in enumerate(xs)
    data[batchindex(data, i)...] = x
  end
  return data
end

Base.rpad(v::AbstractVector, n::Integer, p) = [v; fill(p, max(n - length(v), 0))]

"""
    batchseq(seqs, pad)

Take a list of `N` sequences, and turn them into a single sequence where each
item is a batch of `N`. Short sequences will be padded by `pad`.

```julia
julia> batchseq([[1, 2, 3], [4, 5]], 0)
3-element Array{Array{Int64,1},1}:
 [1, 4]
 [2, 5]
 [3, 0]
```
"""
function batchseq(xs, pad = nothing, n = maximum(length(x) for x in xs))
  xs_ = [rpad(x, n, pad) for x in xs]
  [batch([xs_[j][i] for j = 1:length(xs_)]) for i = 1:n]
end

# Other

"""
Returns a function that when invoked, will only be triggered at most once
during `timeout` seconds. Normally, the throttled function will run
as much as it can, without ever going more than once per `wait` duration;
but if you'd like to disable the execution on the leading edge, pass
`leading=false`. To enable execution on the trailing edge, ditto.
"""
function throttle(f, timeout; leading=true, trailing=false)
  cooldown = true
  later = nothing
  result = nothing

  function throttled(args...; kwargs...)
    yield()

    if cooldown
      if leading
        result = f(args...; kwargs...)
      else
        later = () -> f(args...; kwargs...)
      end

      cooldown = false
      @async try
        while (sleep(timeout); later != nothing)
          later()
          later = nothing
        end
      finally
        cooldown = true
      end
    elseif trailing
      later = () -> (result = f(args...; kwargs...))
    end

    return result
  end
end

"""
    @jit ...

The `@jit` annotation can be applied to any code, and the code will be compiled
for performance.

    @jit f(x) = @jit(x) + @jit(x)

Note that compilation happens regardless of the `@jit` macro, so it should only
be used for aesthetic purposes, or by recovering Python users.
"""
macro jit(ex)
  esc(ex)
end


text:
module CSTParser
global debug = true

using Tokenize
import Base: length, first, last, getindex, setindex!
import Tokenize.Tokens
import Tokenize.Tokens: RawToken, AbstractToken, iskeyword, isliteral, isoperator, untokenize
import Tokenize.Lexers: Lexer, peekchar, iswhitespace

export ParseState, parse_expression

include("lexer.jl")
include("spec.jl")
include("utils.jl")
include("recovery.jl")
include("components/internals.jl")
include("components/keywords.jl")
include("components/lists.jl")
include("components/operators.jl")
include("components/strings.jl")
include("conversion.jl")
include("display.jl")
include("interface.jl")
include("reparse.jl")

"""
    parse_expression(ps)

Parses an expression until `closer(ps) == true`. Expects to enter the
`ParseState` the token before the the beginning of the expression and ends
on the last token.

Acceptable starting tokens are:
+ A keyword
+ An opening parentheses or brace.
+ An operator.
+ An instance (e.g. identifier, number, etc.)
+ An `@`.

"""
function parse_expression(ps::ParseState)
    if kindof(ps.nt) == Tokens.COMMA
        ps.errored = true
        ret = mErrorToken(mPUNCTUATION(next(ps)), UnexpectedToken)
    elseif kindof(ps.nt) ∈ term_c && !(kindof(ps.nt) === Tokens.END && ps.closer.square)
        if match_closer(ps)
            # trying to parse an expression but we've hit a token that closes a parent expression
            ps.errored = true
            ret = mErrorToken(MissingCloser)
        else
            ps.errored = true
            ret = mErrorToken(INSTANCE(next(ps)), UnexpectedToken)
        end
    else
        next(ps)
        if iskeyword(kindof(ps.t)) && kindof(ps.t) != Tokens.DO
            ret = parse_kw(ps)
        elseif kindof(ps.t) == Tokens.LPAREN
            ret = parse_paren(ps)
        elseif kindof(ps.t) == Tokens.LSQUARE
            ret = @default ps parse_array(ps)
        elseif kindof(ps.t) == Tokens.LBRACE
            ret = @default ps @closebrace ps parse_braces(ps)
        elseif isinstance(ps.t) || isoperator(ps.t)
            if kindof(ps.t) == Tokens.WHERE || kindof(ps.t) == Tokens.IN || kindof(ps.t) == Tokens.ISA
                ret = mIDENTIFIER(ps)
            else
                ret = INSTANCE(ps)
            end
            if is_colon(ret) && kindof(ps.nt) != Tokens.COMMA
                ret = parse_unary(ps, ret)
            elseif typof(ret) === OPERATOR && precedence(ret) == AssignmentOp && kindof(ret) !== Tokens.APPROX
                ret = mErrorToken(ret, UnexpectedAssignmentOp)
            end
        elseif kindof(ps.t) == Tokens.AT_SIGN
            ret = parse_macrocall(ps)
        else
            ps.errored = true
            ret = mErrorToken(INSTANCE(ps), UnexpectedToken)
        end
        while !closer(ps)
            ret = parse_compound(ps, ret)
        end
    end
    return ret
end

function parse_compound(ps::ParseState, ret::EXPR)
    if kindof(ps.nt) == Tokens.FOR
        ret = parse_generator(ps, ret)
    elseif kindof(ps.nt) == Tokens.DO
        ret = @default ps @closer ps block parse_do(ps, ret)
    elseif isajuxtaposition(ps, ret)
        if is_number(ret) && last(valof(ret)) == '.'
            ps.errored = true
            ret = mErrorToken(ret, CannotJuxtapose)
        end
        op = mOPERATOR(0, 0, Tokens.STAR, false)
        ret = parse_operator(ps, ret, op)
    elseif (typof(ret) === x_Str || typof(ret) === x_Cmd) && kindof(ps.nt) == Tokens.IDENTIFIER
        arg = mIDENTIFIER(next(ps))
        push!(ret, mLITERAL(arg.fullspan, arg.span, val(ps.t, ps), Tokens.STRING))
    elseif (isidentifier(ret) || (typof(ret) === BinaryOpCall && is_dot(ret.args[2]))) && (kindof(ps.nt) == Tokens.STRING || kindof(ps.nt) == Tokens.TRIPLE_STRING || kindof(ps.nt) == Tokens.CMD || kindof(ps.nt) == Tokens.TRIPLE_CMD)
        next(ps)
        arg = parse_string_or_cmd(ps, ret)
        head = kindof(arg) == Tokens.CMD || kindof(arg) == Tokens.TRIPLE_CMD ? x_Cmd : x_Str
        ret = EXPR(head, EXPR[ret, arg])
    elseif kindof(ps.nt) == Tokens.LPAREN
        no_ws = !isemptyws(ps.ws)
        err_rng = ps.t.endbyte + 2:ps.nt.startbyte
        ret = @closeparen ps parse_call(ps, ret)
        if no_ws && !(typof(ret) === UnaryOpCall)
            ps.errored = true
            ret = mErrorToken(ret, UnexpectedWhiteSpace)
        end
    elseif kindof(ps.nt) == Tokens.LBRACE
        if isemptyws(ps.ws)
            ret = @default ps @nocloser ps inwhere @closebrace ps parse_curly(ps, ret)
        else
            ps.errored = true
            ret = mErrorToken((@default ps @nocloser ps inwhere @closebrace ps parse_curly(ps, ret)), UnexpectedWhiteSpace)

        end
    elseif kindof(ps.nt) == Tokens.LSQUARE && isemptyws(ps.ws) && !isoperator(ret)
        ret = @default ps @nocloser ps block parse_ref(ps, ret)
    elseif kindof(ps.nt) == Tokens.COMMA
        ret = parse_tuple(ps, ret)
    elseif isunaryop(ret) && kindof(ps.nt) != Tokens.EQ
        ret = parse_unary(ps, ret)
    elseif isoperator(ps.nt)
        op = mOPERATOR(next(ps))
        ret = parse_operator(ps, ret, op)
    elseif typof(ret) === UnaryOpCall && is_prime(ret.args[2])
        # prime operator followed by an identifier has an implicit multiplication
        nextarg = @precedence ps 11 parse_expression(ps)
        ret = mBinaryOpCall(ret, mOPERATOR(0, 0, Tokens.STAR, false), nextarg)
# ###############################################################################
# Everything below here is an error
# ###############################################################################
    elseif kindof(ps.nt) in (Tokens.RPAREN, Tokens.RSQUARE, Tokens.RBRACE)
        ps.errored = true
        ret = EXPR(ErrorToken, EXPR[ret, mErrorToken(mPUNCTUATION(next(ps)), Unknown)])
    else
        nextarg = parse_expression(ps)
        ps.errored = true
        ret = EXPR(ErrorToken, EXPR[ret, nextarg])
    end
    return ret
end

"""
    parse_paren(ps, ret)

Parses an expression starting with a `(`.
"""
@addctx :paren function parse_paren(ps::ParseState)
    args = EXPR[mPUNCTUATION(ps)]
    @closeparen ps @default ps @nocloser ps inwhere parse_comma_sep(ps, args, false, true, true)

    if length(args) == 2 && ((kindof(ps.ws) != SemiColonWS || (length(args) == 2 && typof(args[2]) === Block)) && !(typof(args[2]) === Parameters))
        accept_rparen(ps, args)
        ret = EXPR(InvisBrackets, args)
    else
        accept_rparen(ps, args)
        ret = EXPR(TupleH, args)
    end
    return ret
end

"""
    parse(str, cont = false)

Parses the passed string. If `cont` is true then will continue parsing until the end of the string returning the resulting expressions in a TOPLEVEL block.
"""
function parse(str::String, cont = false)
    ps = ParseState(str)
    x, ps = parse(ps, cont)
    return x
end

function parse_doc(ps::ParseState)
    if (kindof(ps.nt) == Tokens.STRING || kindof(ps.nt) == Tokens.TRIPLE_STRING) && !isemptyws(ps.nws)
        doc = mLITERAL(next(ps))
        if kindof(ps.nt) == Tokens.ENDMARKER || kindof(ps.nt) == Tokens.END || ps.t.endpos[1] + 1 < ps.nt.startpos[1]
            return doc
        elseif isbinaryop(ps.nt) && !closer(ps)
            ret = parse_compound(ps, doc)
            return ret
        end

        ret = parse_expression(ps)
        ret = EXPR(MacroCall, EXPR[GlobalRefDOC(), doc, ret])
    elseif kindof(ps.nt) == Tokens.IDENTIFIER && val(ps.nt, ps) == "doc" && (kindof(ps.nnt) == Tokens.STRING || kindof(ps.nnt) == Tokens.TRIPLE_STRING)
        doc = mIDENTIFIER(next(ps))
        next(ps)
        arg = parse_string_or_cmd(ps, doc)
        doc = EXPR(x_Str, EXPR[doc, arg])
        ret = parse_expression(ps)
        ret = EXPR(MacroCall, EXPR[GlobalRefDOC(), doc, ret])
    else
        ret = parse_expression(ps)
    end
    return ret
end

function parse(ps::ParseState, cont = false)
    if ps.l.io.size == 0
        return (cont ? EXPR(FileH, EXPR[]) : nothing), ps
    end
    last_line = 0
    curr_line = 0

    if cont
        top = EXPR(FileH, EXPR[])
        if kindof(ps.nt) == Tokens.WHITESPACE || kindof(ps.nt) == Tokens.COMMENT
            next(ps)
            push!(top, mLITERAL(ps.nt.startbyte, ps.nt.startbyte, "", Tokens.NOTHING))
        end

        while !ps.done
            curr_line = ps.nt.startpos[1]
            ret = parse_doc(ps)
            if _continue_doc_parse(ret, ps)
                push!(ret, parse_expression(ps))
            end
            # join semicolon sep items
            if curr_line == last_line && typof(last(top.args)) === TopLevel
                push!(last(top.args), ret)
                top.fullspan += ret.fullspan
                top.span = top.fullspan - (ret.fullspan - ret.span)
            elseif kindof(ps.ws) == SemiColonWS
                push!(top, EXPR(TopLevel, EXPR[ret]))
            else
                push!(top, ret)
            end
            last_line = curr_line
        end
    else
        if kindof(ps.nt) == Tokens.WHITESPACE || kindof(ps.nt) == Tokens.COMMENT
            next(ps)
            top = mLITERAL(ps.nt.startbyte, ps.nt.startbyte, "", Tokens.NOTHING)
        else
            curr_line = ps.nt.startpos[1]
            top = parse_doc(ps)
            if _continue_doc_parse(top, ps)
                push!(top, parse_expression(ps))
            end
            last_line = ps.nt.startpos[1]
            if kindof(ps.ws) == SemiColonWS
                top = EXPR(TopLevel, EXPR[top])
                while kindof(ps.ws) == SemiColonWS && ps.nt.startpos[1] == last_line && kindof(ps.nt) != Tokens.ENDMARKER
                    ret = parse_doc(ps)
                    push!(top, ret)
                    last_line = ps.nt.startpos[1]
                end
            end
        end
    end

    return top, ps
end

function _continue_doc_parse(x::EXPR, ps::ParseState)
    typof(x) === MacroCall &&
    typof(x.args[1]) === MacroName &&
    length(x.args[1]) == 2 &&
    valof(x.args[1].args[2]) == "doc" &&
    length(x.args) < 3 &&
    ps.t.endpos[1] + 1 <= ps.nt.startpos[1]
end

function parse_file(path::String)
    x = parse(read(path, String), true)
    File([], [], path, x, [])
end

function parse_directory(path::String, proj = Project(path, []))
    for f in readdir(path)
        if isfile(joinpath(path, f)) && endswith(f, ".jl")
            try
                push!(proj.files, parse_file(joinpath(path, f)))
            catch
                println("$f failed to parse")
            end
        elseif isdir(joinpath(path, f))
            parse_directory(joinpath(path, f), proj)
        end
    end
    proj
end

include("precompile.jl")
_precompile()
end


text:
# This file was generated, do not modify it. # hide
mach = machine(mdl, X, y)
fit!(mach)

max_stars_repo_name: vdayanand/MLJTutorials

max_issues_repo_name: vdayanand/MLJTutorials

max_forks_repo_name: vdayanand/MLJTutorials


text:
using ArgParse
using JSON

function main(args)
    s = ArgParseSettings()
    s.description = "Caption generation script for the model (raw images)"

    @add_arg_table s begin
        ("--input"; help="input file in JSON format")
        ("--outdir"; help="output dir")
    end

    # parse args
    println("Datetime: ", now()); flush(STDOUT)
    isa(args, AbstractString) && (args=split(args))
    o = parse_args(args, s; as_symbols=true); println(o); flush(STDOUT)
    outdir = abspath(o[:outdir])
    inputfile = abspath(o[:input])
    elements = JSON.parsefile(inputfile)["captions"]
    rfs = Array(Any, 5)
    for k = 0:1:4
        rfs[k+1] = open(joinpath(outdir,"reference$k"),"w")
    end
    hf = open(joinpath(outdir,"output"),"w")

    for el in elements
        write(hf, string(el["hypothesis"][1:end-2],"\n"))
        for k = 1:5
            write(rfs[k], string(el["references"][k][1:end-2], "\n"))
        end
    end

    for k = 1:5
        close(rfs[k])
    end
    close(hf)
end

!isinteractive() && !isdefined(Core.Main, :load_only) && main(ARGS)

max_stars_repo_name: ilkerkesen/kusrp

max_issues_repo_name: ilkerkesen/kusrp

max_forks_repo_name: ilkerkesen/kusrp