text:
using Base.Test
using LibGit2

import Base: AnyDict

include("util.jl")

testnames = ["oid",
             "blob",
             "config",
             "signature",
             "index",
             "object",
             "tree",
             "walker",
             "tag",
             "branch",
             "patch",
             "repository",
             "repository_pack",
             "reference",
             #"odb",
             "diff",
             "note",
             "merge",
             "remote"
             ]

tests = isempty(ARGS) || ARGS == ["all"] ? testnames : ARGS

function runtests(name)
    println(" \033[1m*\033[0m \033[31m$(name)\033[0m")
    # support shell tab expansion
    endswith(name, ".jl") ? Core.include("$name") : Core.include("$name.jl")
    nothing
end

function propagate_errors(a, b)
    if isa(a,Exception)
        rethrow(a)
    end
    if isa(b,Exception)
        rethrow(b)
    end
    nothing
end

reduce(propagate_errors, nothing, map(runtests, tests))

println(" \033[32;1mSUCCESS\033[0m")


text:
function integral(x::CellVar, grid::TreeGrid; filter::Function = active)
    int = zero(eltype(x.data))
    for cell ∈ cells(grid, filter = filter)
        @inbounds int += volume(cell) * x[cell]
    end
    return int
end

function inner_product(x::CellVar, y::CellVar, grid::TreeGrid; filter::Function = active)
    int = zero(eltype(x.data))
    for cell ∈ cells(grid, filter = filter)
        @inbounds int += volume(cell) * x[cell] * y[cell]
    end
    return int
end

@inline norm(x::CellVar, grid::TreeGrid; filter::Function = active) = sqrt(inner_product(x, x, grid, filter))

ext: jl


text:
type PigPlayer
    name::String
    score::Int
    strat::Function
end

function PigPlayer(a::String)
    PigPlayer(a, 0, pig_manual)
end

function scoreboard(pps::Array{PigPlayer,1})
    join(map(x->@sprintf("%s has %d", x.name, x.score), pps), " | ")
end

function pig_manual(pps::Array{PigPlayer,1}, pdex::Integer, pot::Integer)
    pname = pps[pdex].name
    print(pname, " there is ", @sprintf("%3d", pot), " in the pot.  ")
    print("<ret> to continue rolling? ")
    return chomp(readline()) == ""
end

function pig_round(pps::Array{PigPlayer,1}, pdex::Integer)
    pot = 0
    rcnt = 0
    while pps[pdex].strat(pps, pdex, pot)
        rcnt += 1
        roll = rand(1:6)
        if roll == 1
            return (0, rcnt, false)
        else
            pot += roll
        end
    end
    return (pot, rcnt, true)
end

function pig_game(pps::Array{PigPlayer,1}, winscore::Integer=100)
    pnum = length(pps)
    pdex = pnum
    println("Playing a game of Pig the Dice.")
    while(pps[pdex].score < winscore)
        pdex = rem1(pdex+1, pnum)
        println(scoreboard(pps))
        println(pps[pdex].name, " is now playing.")
        (pot, rcnt, ispotwon) = pig_round(pps, pdex)
        print(pps[pdex].name, " played ", rcnt, " rolls ")
        if ispotwon
            println("and scored ", pot, " points.")
            pps[pdex].score += pot
        else
            println("and butsted.")
        end
    end
    println(pps[pdex].name, " won, scoring ", pps[pdex].score, " points.")
end

pig_game([PigPlayer("Alice"), PigPlayer("Bob")])

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
# Note that this script can accept some limited command-line arguments, run
# `julia build_tarballs.jl --help` to see a usage message.
using BinaryBuilder, Pkg

name = "samtools"
version = v"1.14"

# Collection of sources required to complete build
sources = [
    GitSource("https://github.com/samtools/samtools.git", "c29621d3ae075573fce83e229a5e02348d4e8147"),
]

# Bash recipe for building across all platforms
script = raw"""
cd $WORKSPACE/srcdir/samtools/
autoheader
autoconf -Wno-syntax
export CPPFLAGS="-I${includedir}"
if [[ "${target}" != *-darwin* ]]; then
    # Need to pass `-lcurl` because it's needed by libhts
    export LIBS="-lcurl"
fi
./configure --prefix=${prefix} --build=${MACHTYPE} --host=${target}
make -j${nproc}
make install
"""

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms = supported_platforms(; experimental=true, exclude=Sys.iswindows)

# The products that we will ensure are always built
products = [
    ExecutableProduct("samtools", :samtools)
]

# Dependencies that must be installed before this package can be built
dependencies = [
    Dependency(PackageSpec(name="Ncurses_jll", uuid="68e3532b-a499-55ff-9963-d1c0c0748b3a"))
    Dependency(PackageSpec(name="htslib_jll", uuid="f06fe41e-9474-5571-8c61-5634d2b2700c"))
    # `MbedTLS_jll` is an indirect dependency through `htslib_jll` (-> `LibCURL_jll` ->
    # `MbedTLS_jll`).  For some reasons that aren't clear to me at the moment, we are
    # getting a version of `MbedTLS_jll` which doesn't match the one `LibCURL_jll` was
    # compiled with.
    BuildDependency(PackageSpec(; name="MbedTLS_jll", version="2.24"))
]

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

max_stars_repo_name: sharanry/Yggdrasil

max_issues_repo_name: sharanry/Yggdrasil

max_forks_repo_name: sharanry/Yggdrasil


text:
@testset "Simple Node" begin
    @testset "Handshake" begin
        node = Node("btc.brane.cc", true)
        msg = Channel(2)
        @test Bitcoin.handshake(node, msg)
        Bitcoin.close!(node)
    end
    # @testset "GetHeaders" begin
    #     node = Node("btc.brane.cc", false)
    #     @test typeof(Bitcoin.getheaders(node, 1)) == Array{Bitcoin.BlockHeader,1}
    #     Bitcoin.close!(node)
    # end
    @testset "Using Bloom Filter" begin
        node = Node("btc.brane.cc", 18333, true, false)
        bf = BloomFilter(30, 5, 90210)
        adr = "mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv"
        h160 = Base58.base58checkdecode(UInt8.(collect(adr)))[2:end]
        Bitcoin.add!(bf, h160)

        msg = Channel(2048)
        Bitcoin.handshake(node, msg)

        @async Bitcoin.read(node.sock)
        @async Bitcoin.read_messages(node, messages)

        last_block_hex = "00000000000538d5c2246336644f9a4956551afb44ba47278759ec55ea912e19"
        start_block = hex2bytes(last_block_hex)
        send2node(node, Bitcoin.FilterLoadMessage(bf))
        send2node(node, Bitcoin.GetHeadersMessage(start_block))

        println(Bitcoin.get_tx_of_interest(node, messages, adr))
    end
end


text:
addprocs(7)

using PTools
using Base.Test

# remove all workers
w = workers()

ws1 = WorkerSet(w[1:3], WS_MODE_RR)

@test 2 == remotecall_fetch(ws1, myid)
@test 3 == remotecall_fetch(ws1, myid)
@test 4 == remotecall_fetch(ws1, myid)
@test 2 == remotecall_fetch(ws1, myid)

println("Mode RR PASSED")

function test_ff(id, ws, stime)
    resp = remotecall_fetch(ws,
    () -> begin
        println("In $(myid())")
        sleep(stime);
        println("Exiting $(myid())")
        myid()
    end)
    @test id == resp

end

ws2 = WorkerSet(w[4:7], WS_MODE_FF)
@sync begin
    @async test_ff(5, ws2, 2.0)
    @async test_ff(6, ws2, 2.1)
    @async test_ff(7, ws2, 2.2)
    @async test_ff(8, ws2, 2.3)

    # These should get queued and work in the same manner
    @async test_ff(5, ws2, 2.0)
    @async test_ff(6, ws2, 2.1)
    @async test_ff(7, ws2, 2.2)
    @async test_ff(8, ws2, 2.3)
end

println("Mode FF PASSED")

# test regular pmap and @parallel with all processes.
pmap_resp = pmap(x -> myid(), 1:nprocs())
defprocs = procs()
for i in pmap_resp
    @test contains(defprocs, i)
end


text:
using ..TopOpt.TopOptProblems:
    StiffnessTopOptProblem, Metadata, RectilinearGrid, left, right, middley, middlez

get_fixities_node_set_name(i) = "fixed_u$(i)"

@params struct TrussProblem{xdim,T,N,M} <: StiffnessTopOptProblem{xdim,T}
    truss_grid::TrussGrid{xdim,T,N,M} # ground truss mesh
    materials::Vector{TrussFEAMaterial{T}}
    ch::ConstraintHandler{<:DofHandler{xdim,<:Ferrite.Cell{xdim,N,M},T},T}
    force::Dict{Int,SVector{xdim,T}}
    black::AbstractVector
    white::AbstractVector
    varind::AbstractVector{Int} # variable dof => free dof, based on black & white
    metadata::Metadata
end
# - `force_dof`: dof number at which the force is applied

gettrussgrid(sp::TrussProblem) = sp.truss_grid
getFerritegrid(sp::TrussProblem) = sp.truss_grid.grid

TopOpt.TopOptProblems.getE(sp::TrussProblem) = [m.E for m in sp.materials]
TopOpt.TopOptProblems.getν(sp::TrussProblem) = [m.ν for m in sp.materials]
getA(sp::TrussProblem) = [cs.A for cs in sp.truss_grid.crosssecs]
Ferrite.getnnodes(problem::StiffnessTopOptProblem) = Ferrite.getnnodes(getdh(problem).grid)

function TrussProblem(
    ::Type{Val{CellType}},
    node_points::Dict{iT,SVector{xdim,T}},
    elements::Dict{iT,Tuple{iT,iT}},
    loads::Dict{iT,SVector{xdim,T}},
    supports::Dict{iT,SVector{xdim,fT}},
    mats=TrussFEAMaterial{T}(1.0, 0.3),
    crosssecs=TrussFEACrossSec{T}(1.0),
) where {xdim,T,iT,fT,CellType}
    # unify number type
    # _T = promote_type(eltype(sizes), typeof(mats), typeof(ν), typeof(force))
    # if _T <: Integer
    #     T = Float64
    # else
    #     T = _T
    # end
    if CellType === :Linear
        truss_grid = TrussGrid(node_points, elements; crosssecs)
        geom_order = 1
    else
        @assert false "Other cell type not implemented"
    end
    # reference domain dimension for a line element
    ξdim = 1
    ncells = getncells(truss_grid)

    if mats isa Vector
        @assert length(mats) == ncells
        mats = convert(Vector{TrussFEAMaterial{T}}, mats)
    elseif mats isa TrussFEAMaterial
        mats = [convert(TrussFEAMaterial{T}, mats) for i in 1:ncells]
    else
        error("Invalid mats: $(mats)")
    end

    # * load nodeset
    # the grid node ordering coincides with the input node_points
    if haskey(truss_grid.grid.nodesets, "load")
        pop!(truss_grid.grid.nodesets, "load")
    end
    load_nodesets = Set{Int}()
    for (k, _) in loads
        push!(load_nodesets, k)
    end
    addnodeset!(truss_grid.grid, "load", load_nodesets)

    # * support nodeset
    for i in 1:xdim
        if haskey(truss_grid.grid.nodesets, get_fixities_node_set_name(i))
            pop!(truss_grid.grid.nodesets, get_fixities_node_set_name(i))
        end
        support_nodesets = Set{Int}()
        for (nodeidx, condition) in supports
            if condition[i]
                push!(support_nodesets, nodeidx)
            end
        end
        addnodeset!(truss_grid.grid, get_fixities_node_set_name(i), support_nodesets)
    end

    # Create displacement field u
    dh = DofHandler(truss_grid.grid)
    if CellType === :Linear
        # truss linear
        # interpolation_space
        ip = Lagrange{ξdim,RefCube,geom_order}()
        push!(dh, :u, xdim, ip)
    else
        # TODO truss 2-order
        @assert false "not implemented"
        # ip = Lagrange{2, RefCube, 2}()
        # push!(dh, :u, xdim, ip)
    end
    close!(dh)

    ch = ConstraintHandler(dh)
    for i in 1:xdim
        dbc = Dirichlet(
            :u,
            getnodeset(truss_grid.grid, get_fixities_node_set_name(i)),
            (x, t) -> zeros(T, 1),
            [i],
        )
        add!(ch, dbc)
    end
    close!(ch)

    # update the DBC to current time
    t = T(0)
    update!(ch, t)

    metadata = Metadata(dh)

    # fnode = Tuple(getnodeset(truss_grid.grid, "load"))[1]
    # node_dofs = metadata.node_dofs
    # force_dof = node_dofs[2, fnode]

    black, white = find_black_and_white(dh)
    varind = find_varind(black, white)

    return TrussProblem(truss_grid, mats, ch, loads, black, white, varind, metadata)
end

function Base.show(io::Base.IO, mime::MIME"text/plain", sp::TrussProblem)
    println(io, "TrussProblem:")
    print(io, "    ")
    Base.show(io, mime, sp.truss_grid)
    println(io, "    point loads: $(length(sp.force))")
    return println(io, "    active vars: $(sum(sp.varind .!= 0))")
end

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

TopOpt.TopOptProblems.nnodespercell(p::TrussProblem) = nnodespercell(p.truss_grid)

"""
    getcloaddict(TrussProblem{xdim,T})

Get a dict (node_idx => force vector) for concentrated loads
"""
function TopOpt.TopOptProblems.getcloaddict(p::TrussProblem{xdim,T}) where {xdim,T}
    return p.force
end

function default_quad_order(::TrussProblem)
    return 1
end

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

"""
    PointLoadCantileverTruss(nels::NTuple{dim,Int}, sizes::NTuple{dim}, E = 1.0, ν = 0.3, force = 1.0; k_connect=1) where {dim, CellType}

# Inputs

- `nels`: number of elements in each direction, a 2-tuple for 2D problems and a 3-tuple for 3D problems
- `sizes`: the size of each element in each direction, a 2-tuple for 2D problems and a 3-tuple for 3D problems
- `E`: Young's modulus
- `ν`: Poisson's ration
- `force`: force at the center right of the cantilever beam (positive is downward)
- `k_connect`: k-ring of a node to connect to form the ground mesh. Defaults to 1. For example, for a 2D domain, a node will be connected to `8` neighboring nodes if `k_connect=1`, and `8+16=24` neighboring nodes if `k_connect=2`.

# Returns
- `TrussProblem`

# Example
```
nels = (60,20);
sizes = (1.0,1.0);
E = 1.0;
ν = 0.3;
force = 1.0;
problem = PointLoadCantileverTruss(nels, sizes, E, ν, force, k_connect=2)
```
"""
function PointLoadCantileverTruss(
    nels::NTuple{dim,Int}, sizes::NTuple{dim}, E=1.0, ν=0.3, force=1.0; k_connect=1
) where {dim,CellType}
    iseven(nels[2]) && (length(nels) < 3 || iseven(nels[3])) ||
        throw("Grid does not have an even number of elements along the y and/or z axes.")
    _T = promote_type(eltype(sizes), typeof(E), typeof(ν), typeof(force))
    if _T <: Integer
        T = Float64
    else
        T = _T
    end

    # only for the convience of getting all the node points
    rect_grid = RectilinearGrid(Val{:Linear}, nels, T.(sizes))
    node_mat = hcat(map(x -> Vector(x.x), rect_grid.grid.nodes)...)
    kdtree = KDTree(node_mat)
    if dim == 2
        # 4+1*4 -> 4+3*4 -> 4+5*4
        k_ = 4 * k_connect + 4 * sum(1:2:(2 * k_connect - 1))
    else
        k_ = 8 * k_connect + 6 * sum(1:9:(9 * k_connect - 1))
    end
    idxs, _ = knn(kdtree, node_mat, k_ + 1, true)
    connect_mat = zeros(Int, 2, k_ * length(idxs))
    for (i, v) in enumerate(idxs)
        connect_mat[1, ((i - 1) * k_ + 1):(i * k_)] = ones(Int, k_) * i
        connect_mat[2, ((i - 1) * k_ + 1):(i * k_)] = v[2:end] # skip the point itself
    end
    truss_grid = TrussGrid(node_mat, connect_mat)

    # reference domain dimension for a line element
    ξdim = 1
    ncells = getncells(truss_grid)
    mats = [TrussFEAMaterial{T}(E, ν) for i in 1:ncells]

    # * support nodeset
    for i in 1:dim
        addnodeset!(truss_grid.grid, get_fixities_node_set_name(i), x -> left(rect_grid, x))
    end

    # * load nodeset
    if dim == 2
        addnodeset!(
            truss_grid.grid, "force", x -> right(rect_grid, x) && middley(rect_grid, x)
        )
    else
        addnodeset!(
            truss_grid.grid,
            "force",
            x -> right(rect_grid, x) && middley(rect_grid, x) && middlez(rect_grid, x),
        )
    end

    # * Create displacement field u
    geom_order = 1
    dh = DofHandler(truss_grid.grid)
    ip = Lagrange{ξdim,RefCube,geom_order}()
    push!(dh, :u, dim, ip)
    close!(dh)

    ch = ConstraintHandler(dh)
    for i in 1:dim
        dbc = Dirichlet(
            :u,
            getnodeset(truss_grid.grid, get_fixities_node_set_name(i)),
            (x, t) -> zeros(T, 1),
            [i],
        )
        add!(ch, dbc)
    end
    close!(ch)
    # update the DBC to current time
    t = T(0)
    update!(ch, t)

    metadata = Metadata(dh)

    loadset = getnodeset(truss_grid.grid, "force")
    ploads = Dict{Int,SVector{dim,T}}()
    for node_id in loadset
        ploads[node_id] = SVector{dim,T}(dim == 2 ? [0.0, force] : [0.0, 0.0, force])
    end

    black, white = find_black_and_white(dh)
    varind = find_varind(black, white)

    return TrussProblem(truss_grid, mats, ch, ploads, black, white, varind, metadata)
end


text:
module FluxTest

using Flux
using Flux:cu

function test()
  model = Chain(
    Conv((3,3), 3=>16, relu),
    Conv((3,3), 16=>16, relu),
    BatchNorm(3),
    MaxPool((4,4)),
    Conv((3,3), 16=>64, relu),
    Conv((3,3), 64=>64, relu),
    BatchNorm(3),
    MaxPool((4,4)),
    Conv((3,3), 64=>256, relu),
    Conv((3,3), 256=>256, relu),
    BatchNorm(3),
    MaxPool((4,4)),
    x -> reshape(x, :, size(x, 4)),
    Dense(1024, 64, relu),
    Dense(64, 10, relu),
  ) |> gpu

  data = randn(Float32,224,224,3,16)

  model(cu(data))

  @time for i in 1:1000
    X = cu(data)
    model(X)
  end
end

test()

end


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

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

Accepts an invitation for the member account to contribute data to a behavior graph. This
operation can only be called by an invited member account.  The request provides the ARN of
behavior graph. The member account status in the graph must be INVITED.

# Arguments
- `graph_arn`: The ARN of the behavior graph that the member account is accepting the
  invitation for. The member account status in the behavior graph must be INVITED.

"""
accept_invitation(GraphArn; aws_config::AbstractAWSConfig=global_aws_config()) = detective("PUT", "/invitation", Dict{String, Any}("GraphArn"=>GraphArn); aws_config=aws_config)
accept_invitation(GraphArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("PUT", "/invitation", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("GraphArn"=>GraphArn), params)); aws_config=aws_config)

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

Creates a new behavior graph for the calling account, and sets that account as the
administrator account. This operation is called by the account that is enabling Detective.
Before you try to enable Detective, make sure that your account has been enrolled in Amazon
GuardDuty for at least 48 hours. If you do not meet this requirement, you cannot enable
Detective. If you do meet the GuardDuty prerequisite, then when you make the request to
enable Detective, it checks whether your data volume is within the Detective quota. If it
exceeds the quota, then you cannot enable Detective.  The operation also enables Detective
for the calling account in the currently selected Region. It returns the ARN of the new
behavior graph.  CreateGraph triggers a process to create the corresponding data tables for
the new behavior graph. An account can only be the administrator account for one behavior
graph within a Region. If the same account calls CreateGraph with the same administrator
account, it always returns the same behavior graph ARN. It does not create a new behavior
graph.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Tags"`: The tags to assign to the new behavior graph. For each tag, you provide the tag
  key and the tag value.
"""
create_graph(; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph"; aws_config=aws_config)
create_graph(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph", params; aws_config=aws_config)

"""
    create_members(accounts, graph_arn)
    create_members(accounts, graph_arn, params::Dict{String,<:Any})

Sends a request to invite the specified AWS accounts to be member accounts in the behavior
graph. This operation can only be called by the administrator account for a behavior graph.
  CreateMembers verifies the accounts and then invites the verified accounts. The
administrator can optionally specify to not send invitation emails to the member accounts.
This would be used when the administrator manages their member accounts centrally. The
request provides the behavior graph ARN and the list of accounts to invite. The response
separates the requested accounts into two lists:   The accounts that CreateMembers was able
to start the verification for. This list includes member accounts that are being verified,
that have passed verification and are to be invited, and that have failed verification.
The accounts that CreateMembers was unable to process. This list includes accounts that
were already invited to be member accounts in the behavior graph.

# Arguments
- `accounts`: The list of AWS accounts to invite to become member accounts in the behavior
  graph. For each invited account, the account list contains the account identifier and the
  AWS account root user email address.
- `graph_arn`: The ARN of the behavior graph to invite the member accounts to contribute
  their data to.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"DisableEmailNotification"`: if set to true, then the member accounts do not receive
  email notifications. By default, this is set to false, and the member accounts receive
  email notifications.
- `"Message"`: Customized message text to include in the invitation email message to the
  invited member accounts.
"""
create_members(Accounts, GraphArn; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/members", Dict{String, Any}("Accounts"=>Accounts, "GraphArn"=>GraphArn); aws_config=aws_config)
create_members(Accounts, GraphArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/members", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Accounts"=>Accounts, "GraphArn"=>GraphArn), params)); aws_config=aws_config)

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

Disables the specified behavior graph and queues it to be deleted. This operation removes
the graph from each member account's list of behavior graphs.  DeleteGraph can only be
called by the administrator account for a behavior graph.

# Arguments
- `graph_arn`: The ARN of the behavior graph to disable.

"""
delete_graph(GraphArn; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/removal", Dict{String, Any}("GraphArn"=>GraphArn); aws_config=aws_config)
delete_graph(GraphArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/removal", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("GraphArn"=>GraphArn), params)); aws_config=aws_config)

"""
    delete_members(account_ids, graph_arn)
    delete_members(account_ids, graph_arn, params::Dict{String,<:Any})

Deletes one or more member accounts from the administrator account's behavior graph. This
operation can only be called by a Detective administrator account. That account cannot use
DeleteMembers to delete their own account from the behavior graph. To disable a behavior
graph, the administrator account uses the DeleteGraph API method.

# Arguments
- `account_ids`: The list of AWS account identifiers for the member accounts to delete from
  the behavior graph.
- `graph_arn`: The ARN of the behavior graph to delete members from.

"""
delete_members(AccountIds, GraphArn; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/members/removal", Dict{String, Any}("AccountIds"=>AccountIds, "GraphArn"=>GraphArn); aws_config=aws_config)
delete_members(AccountIds, GraphArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/members/removal", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("AccountIds"=>AccountIds, "GraphArn"=>GraphArn), params)); aws_config=aws_config)

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

Removes the member account from the specified behavior graph. This operation can only be
called by a member account that has the ENABLED status.

# Arguments
- `graph_arn`: The ARN of the behavior graph to remove the member account from. The member
  account's member status in the behavior graph must be ENABLED.

"""
disassociate_membership(GraphArn; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/membership/removal", Dict{String, Any}("GraphArn"=>GraphArn); aws_config=aws_config)
disassociate_membership(GraphArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/membership/removal", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("GraphArn"=>GraphArn), params)); aws_config=aws_config)

"""
    get_members(account_ids, graph_arn)
    get_members(account_ids, graph_arn, params::Dict{String,<:Any})

Returns the membership details for specified member accounts for a behavior graph.

# Arguments
- `account_ids`: The list of AWS account identifiers for the member account for which to
  return member details. You cannot use GetMembers to retrieve information about member
  accounts that were removed from the behavior graph.
- `graph_arn`: The ARN of the behavior graph for which to request the member details.

"""
get_members(AccountIds, GraphArn; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/members/get", Dict{String, Any}("AccountIds"=>AccountIds, "GraphArn"=>GraphArn); aws_config=aws_config)
get_members(AccountIds, GraphArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/members/get", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("AccountIds"=>AccountIds, "GraphArn"=>GraphArn), params)); aws_config=aws_config)

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

Returns the list of behavior graphs that the calling account is an administrator account
of. This operation can only be called by an administrator account. Because an account can
currently only be the administrator of one behavior graph within a Region, the results
always contain a single behavior graph.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of graphs to return at a time. The total must be less
  than the overall limit on the number of results to return, which is currently 200.
- `"NextToken"`: For requests to get the next page of results, the pagination token that
  was returned with the previous set of results. The initial request does not include a
  pagination token.
"""
list_graphs(; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graphs/list"; aws_config=aws_config)
list_graphs(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graphs/list", params; aws_config=aws_config)

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

Retrieves the list of open and accepted behavior graph invitations for the member account.
This operation can only be called by a member account. Open invitations are invitations
that the member account has not responded to. The results do not include behavior graphs
for which the member account declined the invitation. The results also do not include
behavior graphs that the member account resigned from or was removed from.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of behavior graph invitations to return in the
  response. The total must be less than the overall limit on the number of results to return,
  which is currently 200.
- `"NextToken"`: For requests to retrieve the next page of results, the pagination token
  that was returned with the previous page of results. The initial request does not include a
  pagination token.
"""
list_invitations(; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/invitations/list"; aws_config=aws_config)
list_invitations(params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/invitations/list", params; aws_config=aws_config)

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

Retrieves the list of member accounts for a behavior graph. Does not return member accounts
that were removed from the behavior graph.

# Arguments
- `graph_arn`: The ARN of the behavior graph for which to retrieve the list of member
  accounts.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"MaxResults"`: The maximum number of member accounts to include in the response. The
  total must be less than the overall limit on the number of results to return, which is
  currently 200.
- `"NextToken"`: For requests to retrieve the next page of member account results, the
  pagination token that was returned with the previous page of results. The initial request
  does not include a pagination token.
"""
list_members(GraphArn; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/members/list", Dict{String, Any}("GraphArn"=>GraphArn); aws_config=aws_config)
list_members(GraphArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/members/list", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("GraphArn"=>GraphArn), params)); aws_config=aws_config)

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

Returns the tag values that are assigned to a behavior graph.

# Arguments
- `resource_arn`: The ARN of the behavior graph for which to retrieve the tag values.

"""
list_tags_for_resource(ResourceArn; aws_config::AbstractAWSConfig=global_aws_config()) = detective("GET", "/tags/$(ResourceArn)"; aws_config=aws_config)
list_tags_for_resource(ResourceArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("GET", "/tags/$(ResourceArn)", params; aws_config=aws_config)

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

Rejects an invitation to contribute the account data to a behavior graph. This operation
must be called by a member account that has the INVITED status.

# Arguments
- `graph_arn`: The ARN of the behavior graph to reject the invitation to. The member
  account's current member status in the behavior graph must be INVITED.

"""
reject_invitation(GraphArn; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/invitation/removal", Dict{String, Any}("GraphArn"=>GraphArn); aws_config=aws_config)
reject_invitation(GraphArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/invitation/removal", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("GraphArn"=>GraphArn), params)); aws_config=aws_config)

"""
    start_monitoring_member(account_id, graph_arn)
    start_monitoring_member(account_id, graph_arn, params::Dict{String,<:Any})

Sends a request to enable data ingest for a member account that has a status of
ACCEPTED_BUT_DISABLED. For valid member accounts, the status is updated as follows.   If
Detective enabled the member account, then the new status is ENABLED.   If Detective cannot
enable the member account, the status remains ACCEPTED_BUT_DISABLED.

# Arguments
- `account_id`: The account ID of the member account to try to enable. The account must be
  an invited member account with a status of ACCEPTED_BUT_DISABLED.
- `graph_arn`: The ARN of the behavior graph.

"""
start_monitoring_member(AccountId, GraphArn; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/member/monitoringstate", Dict{String, Any}("AccountId"=>AccountId, "GraphArn"=>GraphArn); aws_config=aws_config)
start_monitoring_member(AccountId, GraphArn, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/graph/member/monitoringstate", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("AccountId"=>AccountId, "GraphArn"=>GraphArn), params)); aws_config=aws_config)

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

Applies tag values to a behavior graph.

# Arguments
- `resource_arn`: The ARN of the behavior graph to assign the tags to.
- `tags`: The tag values to assign to the behavior graph.

"""
tag_resource(ResourceArn, Tags; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/tags/$(ResourceArn)", Dict{String, Any}("Tags"=>Tags); aws_config=aws_config)
tag_resource(ResourceArn, Tags, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("POST", "/tags/$(ResourceArn)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("Tags"=>Tags), params)); aws_config=aws_config)

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

Removes tags from a behavior graph.

# Arguments
- `resource_arn`: The ARN of the behavior graph to remove the tags from.
- `tag_keys`: The tag keys of the tags to remove from the behavior graph.

"""
untag_resource(ResourceArn, tagKeys; aws_config::AbstractAWSConfig=global_aws_config()) = detective("DELETE", "/tags/$(ResourceArn)", Dict{String, Any}("tagKeys"=>tagKeys); aws_config=aws_config)
untag_resource(ResourceArn, tagKeys, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = detective("DELETE", "/tags/$(ResourceArn)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("tagKeys"=>tagKeys), params)); aws_config=aws_config)


text:
using Pkg

Pkg.add("Distances")
Pkg.add("Pathogen")
Pkg.add("Random")
Pkg.add("Plots")
Pkg.add("Revise")
Pkg.add("Genie")
Pkg.add("JSON")
Pkg.add("JuliaDB")

max_issues_repo_name: MLH-Fellowship/CodeVidLive


text:
function get_predicts(sol, dx)
    ds = [infimum(d.domain):dx:supremum(d.domain) for d in sol.domains]

    length_x = Int((length(sol.domains)-1)/2 + 1)
    ds_x = [infimum(d.domain):dx:supremum(d.domain) for d in sol.domains[1:length_x]]

    acum =  [0;accumulate(+, length.(sol.initθ))]
    sep = [acum[i]+1 : acum[i+1] for i in 1:length(acum)-1]
    minimizers_ = [sol.res.minimizer[s] for s in sep]

    vars = sol.vars
    phi = sol.phi
    dict_vars = sol.dict_vars

    # checks if it is Es or Bs
    condition = if sol.plasma isa CollisionlessPlasma
                    dict_vars[vars[end-1]] || dict_vars[vars[end]]
                else
                    dict_vars[vars[end]]
                end

    predicts = Dict()

    i_vars = vcat(vars...)
    for i in eachindex(phi)
        if i_vars[i] ∈ condition
            push!(predicts, i_vars[i] => [first(phi[i](collect(d), minimizers_[i])) for d in Iterators.product(ds_x...)])
        else
            push!(predicts, i_vars[i] => [first(phi[i](collect(d), minimizers_[i])) for d in Iterators.product(ds...)])
        end
    end

    return predicts
end

"""
Plots a plasma given a PlasmaSolution object
"""
function Plasma.plot(sol::PlasmaSolution, dx=0.1)
    predicts = get_predicts(sol, dx)

    d = sol.domains[1]
    ts = infimum(d.domain):dx:supremum(d.domain)

    for (var, predict) in predicts
        plot_with_makie(var, predict, ts)
    end

end

function plot_with_makie(var, predict, ts)
    ts = 1:length(ts)
    GLMakie.activate!()

    # 1 means 1 graph, 1:2 means 2 graphs
    multigraph = length(size(predict)) > 4 ? (1:2) : 1

    i = Observable(1)
    f = Figure()

    if length(size(predict)) == 7
        data_1 = @lift(predict[$i, :, :, :, 1, 1, 1])
        data_2 = @lift(predict[$i, 1, 1, 1, :, :, :])

        GLMakie.volume(f[1, 1], data_1, axis = (;type = Axis3))
        GLMakie.volume(f[1, 2], data_2, axis = (;type = Axis3))

    elseif length(size(predict)) == 5
        data_1 = @lift(predict[$i, :, :, 1, 1])
        data_2 = @lift(predict[$i, 1, 1, :, :])

        heatmap(f[1, 1], data_1)
        heatmap(f[1, 2], data_2)

    elseif length(size(predict)) == 4
        data_1 = @lift(predict[$i, :, :, :])
        GLMakie.volume(f[1, 1], data_1, axis = (;type = Axis3))

    elseif length(size(predict)) == 3
        data_1 = @lift(predict[$i, :, :])
        heatmap(f[1, 1], data_1)

    elseif length(size(predict)) == 2
        heatmap(f[1, 1], predict[:, :])
    else
        error("dimension not yet implemented.")
    end

    ls = labelslider!(f, "t", ts)

    f[2, multigraph] = ls.layout
    connect!(i, ls.slider.value)

    GLMakie.save("$var.png", f)

    GLMakie.record(f, "time_animation.mp4", ts;
        framerate = 10) do t
        i[] = t
    end

    display(f)
end


text:
##################################################################
#
# Pointers to Sundials objects
#
##################################################################

"""
    Base type for dummy placeholders that help to
    providing typed pointers for Sundials objects
    (KINSOL, CVODE, IDA).

    See `Handle`.
"""
abstract AbstractSundialsObject

immutable CVODEMem <: AbstractSundialsObject end
typealias CVODEMemPtr Ptr{CVODEMem}

immutable IDAMem <: AbstractSundialsObject end
typealias IDAMemPtr Ptr{IDAMem}

immutable KINMem <: AbstractSundialsObject end
typealias KINMemPtr Ptr{KINMem}

"""
   Handle for Sundials objects (CVODE, IDA, KIN).

   Wraps the reference to the pointer to the Sundials object.
   Manages automatic destruction of the referenced objects when it is
   no longer in use.
"""
immutable Handle{T <: AbstractSundialsObject}
    ptr_ref::Ref{Ptr{T}} # pointer to a pointer

    @compat function (::Type{Handle}){T}(ptr::Ptr{T})
        h = new{T}(Ref{Ptr{T}}(ptr))
        finalizer(h.ptr_ref, release_handle)
        return h
    end
end

Base.convert{T}(::Type{Ptr{T}}, h::Handle{T}) = h.ptr_ref[]
Base.convert{T}(::Type{Ptr{Ptr{T}}}, h::Handle{T}) = convert(Ptr{Ptr{T}}, h.ptr_ref[])

release_handle{T}(ptr_ref::Ref{Ptr{T}}) = throw(MethodError("Freeing objects of type $T not supported"))
release_handle(ptr_ref::Ref{Ptr{KINMem}}) = KINSOLFree(ptr_ref)
release_handle(ptr_ref::Ref{Ptr{CVODEMem}}) = CVodeFree(ptr_ref)
release_handle(ptr_ref::Ref{Ptr{IDAMem}}) = IDAFree(ptr_ref)

##################################################################
#
# Convenience typealiases for Sundials handles
#
##################################################################

typealias CVODEh Handle{CVODEMem}
typealias KINh Handle{KINMem}
typealias IDAh Handle{IDAMem}


text:
using Test
using Tachyons
using WebIO
using Blink
using Observables

notinstalled = !AtomShell.isinstalled()

notinstalled && AtomShell.install()

@testset "Blink mocks" begin
    w = Window(Dict(:show => false))

    elem = dom"div#test1"("hello, world") |> class"bg-yellow green" |> class"pa5"
    body!(w, dom"div"(tachyons_css, elem))
    sleep(5) # wait for it to render.

    substrings = ["""
hello, world
"""]
    content = Blink.@js(w, document.body.innerHTML)
    @test all(x->occursin(x, content), substrings)
    br = Blink.@js(w, window.getComputedStyle(document.querySelector("#test1"), null).getPropertyValue("background-color"))
    @test br == "rgb(255, 215, 0)"
end

notinstalled && AtomShell.uninstall()


text:
module TestFileMgrBlock
  using Base.Test
  using HelloDB.Blocks

  block1 = Block("foo", 1)
  block2 = Block("bar", 2)

  @test block1 == block1
  @test block1 != block2

  @test hash(block1) != hash(block2)
  @test hash(block1) == hash(block1)

  @test tostring(block1) == "Block[filename: foo, number: 1]"
end


text:
#///////////////////////////////////////
#// File Name: ileqg_test.jl
#// Author: Haruki Nishimura (hnishimura@stanford.edu)
#// Date Created: 2020/11/03
#// Description: Test code for src/ileqg.jl
#///////////////////////////////////////

using LinearAlgebra
using Test

@testset "iLEQG Test" begin
    f(x, u) = x + u;
    c(k, x, u) = k;
    h(x) = 1.0;
    W(k) = Matrix(1.0I, 2, 2);
    N = 10;

    prob = FiniteHorizonRiskSensitiveOptimalControlProblem(f, c, h, W, N)

    u_array = [ones(2) for ii = 1 : prob.N];
    x_array = simulate_dynamics(prob, zeros(2), u_array);

    @test x_array[1] == zeros(2)
    @test all([x_array[ii + 1] == f(x_array[ii], u_array[ii]) for ii = 1 : prob.N - 1])

    L_array = [ones(2, 2) for ii = 1:prob.N];
    x_array_new, u_array_new = simulate_dynamics(prob, x_array, u_array, L_array)
    @test all([u_array_new[ii] == u_array[ii] for ii = 1:prob.N])
    @test all([x_array_new[ii] == x_array[ii] for ii = 1:prob.N])

    # integrate_cost test
    cost = integrate_cost(prob, x_array, u_array)
    @test cost ≈ sum([c(ii - 1, x_array[ii], u_array[ii]) for ii = 1 : prob.N]) + h(x_array[end])

    # initialize test
    solver = ILEQGSolver(prob);
    initialize!(solver, prob, zeros(2), u_array, 0.0);
    @test solver.l_array == u_array
    @test solver.L_array == [zeros(2, 2) for ii = 1 : prob.N]
    @test solver.x_array == x_array
    @test solver.μ == 0.0
    @test solver.Δ == solver.Δ_0
    @test solver.d_current == Inf
    @test solver.iter_current == 0;
    @test solver.ϵ_history == Tuple{Float64, Float64}[]
    dp_result_init = solve_approximate_dp(
                    approximate_model(prob, u_array, x_array),
                    [zeros(2, 2) for ii = 1 : N], θ=0.0, μ=0.0);
    @test solver.value_current ≈ dp_result_init.s_array[1];

    # approximate_model test
    prob.c(k, x, u) = 0.5*x'*x + 1.0*u'*u + x'*u
    prob.h(x) = 0.5*x'*x
    approx_result = approximate_model(prob, u_array, x_array);

    @test all([isapprox(approx_result.q_array[ii], 0.5*(2*(ii - 1)^2) + 1.0*2 + 2*(ii - 1)) for ii = 1 : length(u_array)])
    @test isapprox(approx_result.q_array[end], h(x_array[end]))

    @test all([isapprox(approx_result.q_vec_array[ii], x_array[ii] + ones(2)) for ii = 1:length(u_array)])
    @test isapprox(approx_result.q_vec_array[end], x_array[end])
    @test all([isapprox(approx_result.Q_array[ii], Matrix(1.0I, 2, 2)) for ii = 1:length(x_array)])
    @test all([isapprox(approx_result.r_array[ii], x_array[ii] + 2.0*ones(2)) for ii = 1:length(u_array)])
    @test all([isapprox(approx_result.R_array[ii], 2.0*Matrix(1.0I, 2, 2)) for ii = 1:length(u_array)])
    @test all([isapprox(approx_result.P_array[ii], Matrix(1.0I, 2, 2)) for ii = 1:length(u_array)])
    @test all([approx_result.W_array[ii] == Matrix(1.0I, 2, 2) for ii = 1:length(u_array)])

    prob.c(k, x, u) = 0.5*x'*x + 1.0*u'*u;
    prob.h(x) = 0.5*x'*x
    approx_result = approximate_model(prob, u_array, x_array);
    # solve_approximate_dp test
    dp_result, dl_array_new = solve_approximate_dp!(solver, approx_result, false, θ=0.0);
    @test length(dp_result.s_array) == length(x_array)
    @test length(dp_result.s_vec_array) == length(x_array)
    @test all([length(s_vec) == 2 for s_vec in dp_result.s_vec_array])
    @test length(dp_result.S_array) == length(x_array)
    @test all([size(S) == (2, 2) for S in dp_result.S_array])
    @test all([issymmetric(S) for S in dp_result.S_array])
    @test all([isposdef(S) for S in dp_result.S_array])
    @test length(dp_result.g_array) == length(u_array)
    @test all([length(g) == 2 for g in dp_result.g_array])
    @test length(dp_result.G_array) == length(u_array)
    @test all([size(G) == (2, 2) for G in dp_result.G_array])
    @test length(dp_result.H_array) == length(u_array)
    @test all([size(H) == (2, 2) for H in dp_result.H_array])
    # # gains should match LQR solution.
    begin
        L_array_lqr = Vector{Matrix{Float64}}(undef, N);
        S_array_lqr = Vector{Matrix{Float64}}(undef, N + 1);
        S_array_lqr[N + 1] = approx_result.Q_array[N + 1];
        for ii = Iterators.reverse(1 : N)
            Q = approx_result.Q_array[ii];
            R = approx_result.R_array[ii];
            A = approx_result.A_array[ii];
            B = approx_result.B_array[ii];
            S_array_lqr[ii] = Q + (A')*S_array_lqr[ii + 1]*A -
                              (A')*S_array_lqr[ii + 1]*B/(R + (B')*S_array_lqr[ii + 1]*B)*(B')*S_array_lqr[ii + 1]*A;
        end
        for ii = 1 : N
            R = approx_result.R_array[ii];
            A = approx_result.A_array[ii];
            B = approx_result.B_array[ii];
            L_array_lqr[ii] = -(R + (B')*S_array_lqr[ii + 1]*B)\B*S_array_lqr[ii + 1]*A
        end
        @test all([all(L_array_lqr[ii] .≈ solver.L_array[ii]) for ii = 1 : N])
    end
    # # Nominal control offsets should be 0 (LQR is linear feedback)
    @test all(isapprox.(norm.(u_array .+ dl_array_new .- solver.L_array.*x_array[1:end-1]), 0.0, atol=1e-8))

    dp_result_2, dl_array_new_2 = solve_approximate_dp!(solver, approx_result, false, θ=1e-8);
    @test length(dp_result_2.s_array) == length(x_array)
    @test length(dp_result_2.s_vec_array) == length(x_array)
    @test all([length(s_vec) == 2 for s_vec in dp_result_2.s_vec_array])
    @test length(dp_result_2.S_array) == length(x_array)
    @test all([size(S) == (2, 2) for S in dp_result_2.S_array])
    @test all([issymmetric(S) for S in dp_result_2.S_array])
    @test all([isposdef(S) for S in dp_result_2.S_array])
    @test length(dp_result_2.g_array) == length(u_array)
    @test all([length(g) == 2 for g in dp_result_2.g_array])
    @test length(dp_result_2.G_array) == length(u_array)
    @test all([size(G) == (2, 2) for G in dp_result_2.G_array])
    @test length(dp_result_2.H_array) == length(u_array)
    @test all([size(H) == (2, 2) for H in dp_result_2.H_array])
    @test isapprox(dp_result.s_array[1], dp_result_2.s_array[1], rtol=1e-5)
    @test all([isapprox(dl_array_new[ii], dl_array_new_2[ii]) for ii = 1 : N])

    solve_approximate_dp!(solver, approx_result, false, θ=0.0);

    dp_result_3 = solve_approximate_dp(approx_result, solver.L_array, dl_array_new, θ=0.0, μ=0.0);
    @test dp_result_3.s_array == dp_result.s_array

    # line search test (for linear system)
    line_search!(solver, prob, dl_array_new, 0.0, false)
    @test solver.value_current .≈ dp_result.s_array[1] # line search should find the same optimal solution

    # increase_μ_and_Δ test
    solver = ILEQGSolver(prob);
    initialize!(solver, prob, zeros(2), u_array, 0.0)
    increase_μ_and_Δ!(solver);
    @test solver.Δ == 4.0
    @test solver.μ == 1e-6

    # decrease_μ_and_Δ test
    solver = ILEQGSolver(prob);
    initialize!(solver, prob, zeros(2), u_array, 0.0)
    decrease_μ_and_Δ!(solver);
    @test solver.Δ == 0.5
    @test solver.μ == 0.0

    # Testing with nonlinear model
    f(x, u) = x.^1.3 + u.^1.5;
    c(k, x, u) = sum(x.^2.5 + u.^2.5);
    h(x) = 1.0;
    W(k) = Matrix(0.01I, 2, 2);
    N = 10;
    θ = 0.5;

    u_array = [0.1*ones(2) for ii = 1 : prob.N];

    prob = FiniteHorizonRiskSensitiveOptimalControlProblem(f, c, h, W, N)

    solver = ILEQGSolver(prob);
    initialize!(solver, prob, zeros(2), u_array, θ)
    approx_result = approximate_model(prob, solver.l_array, solver.x_array,
                                      solver.A_array, solver.B_array);
    dp_result, dl_array = solve_approximate_dp!(solver, approx_result, false, θ=θ);
    value_new = line_search!(solver, prob, dl_array, θ, false)
    @test length(solver.ϵ_history) == 1
    @test solver.ϵ_history[1][1] == 1.0;
    @test solver.ϵ_history[1][2] < 0.0

    x_array, l_array, L_array, value, ϵ_history =
    solve!(solver, prob, zeros(2), u_array, θ=0.0, verbose=false);
    @test all([all(isapprox.(x_array[ii], zeros(2), atol=1e-4)) for ii = 1 : N + 1])
end


text:
struct DeadVolume{T} <: AbstractVirtualVolume{T}
    name::String
    geometry::AbstractGeometry{T}
end

function modulate_driftvector(sv::CartesianVector{T}, cp::CartesianPoint{T}, tl::DeadVolume{T})::CartesianVector{T} where {T <: SSDFloat}
    return CartesianVector{T}(0,0,0)
end

function DeadVolume{T}(dict::Dict, inputunit_dict::Dict{String,Unitful.Units}) where T <: SSDFloat
    n = haskey(dict, "name") ? dict["name"] : "external part"
    g = Geometry(T, dict["geometry"], inputunit_dict)
    return DeadVolume{T}(n, g)
end

struct ArbitraryDriftModificationVolume{T} <: AbstractVirtualVolume{T}
    name::String
    id::Int
    geometry::AbstractGeometry{T}
end

function modulate_driftvector(sv::CartesianVector{T}, cp::CartesianPoint{T}, tl::ArbitraryDriftModificationVolume{T})::CartesianVector{T} where {T <: SSDFloat}
    modulate_driftvector(sv, cp, tl, Val{tl.id})
end
function modulate_driftvector(sv::CartesianVector{T}, cp::CartesianPoint{T}, tl::ArbitraryDriftModificationVolume{T}, ::Type{Val{id}})::CartesianVector{T} where {T <: SSDFloat, id}
    error("""
        This function needs to be overwritten by the user. Use `::Type{Val{<id>}}` for the last argument.
        <id> is the corresponding id specified in the json-config file of the detector.
    """)
end

function ArbitraryDriftModificationVolume{T}(dict::Dict, inputunit_dict::Dict{String,Unitful.Units}) where T <: SSDFloat
    n = haskey(dict, "name") ? dict["name"] : "external part"
    g = Geometry(T, dict["geometry"], inputunit_dict)
    id = Int(dict["id"])
    return ArbitraryDriftModificationVolume{T}(n, id, g)
end


text:
include("setupInversionTest.jl");

@everywhere begin
	using jInv.InverseSolve
	using jInv.LinearSolvers
end

using Test

println("Running inversion test");

Dobs, Wd = solveForwardProblem(m ,pForp, omega, nrec, nsrc, nfreq);
mc, Dc, pInv, Iact, mback = solveInverseProblem(pForp, Dobs, Wd, nfreq, nx, nz, Mr);

fullMc = reshape(Iact*pInv.modelfun(mc)[1] + mback,tuple((pInv.MInv.n)...));
println("Model error:");
println(norm(fullMc.-m));
@test norm(fullMc.-m) < 1.4

for k=1:length(Dc)
	wait(Dc[k]);
end
Dinv = Array{Array}(undef, nfreq);
for k=1:length(Dc)
	Dinv[k] = fetch(Dc[k]);
end
println("Data error:");
println(norm(Dobs.-Dinv));
@test norm(Dobs.-Dinv) < 5.4


text:
_error() = error(
    "The WebIO Jupyter extension must be installed using Python or Conda. " *
    "See https://juliagizmos.github.io/WebIO.jl/latest/providers/ijulia/ for more information."
)

find_jupyter_cmd(args...; kwargs...) = _error()
find_condajl_jupyter_cmd(args...; kwargs...) = _error()
install_jupyter_labextension(args...; kwargs...) = _error()
install_jupyter_nbextension(args...; kwargs...) = _error()
install_jupyter_serverextension(args...; kwargs...) = _error()


text:
using DifferentialEquations
using Plots
barrier=4

condition(u,t,integrator)=abs(u[1])>barrier || abs(u[2])>barrier || abs(u[3])>barrier||abs(u[4])>barrier
affect!(integrator) = terminate!(integrator)
cb=DiscreteCallback(condition,affect!)
Energy=0.18;
H=(2*Energy)^2
h=sqrt(H)

PofY_find(YY)=sqrt((h+YY.^2-h*YY.^2 )./(1+h-h*YY.^2))
H1(p,q,t)= ( (q[2]-q[1])^2+(p[2]-p[1])^2 )*( (q[2]+q[1])^2+(p[2]+p[1])^2 )
H2(p,q,t)= (p[2]^4+2*p[2]^2*(q[1]^2-1)+(1+q[1]^2)^2 )*(q[2]^4+2*q[2]^2*(p[1]^2+1)+(p[1]^2-1)^2 )
HAM(p,q,t)=H1(p,q,t)/H2(p,q,t)
PofY_find(YY)=sqrt((h+YY.^2-h*YY.^2 )./(1+h-h*YY.^2))

n_iter=100
Y_start=1e-6
Y_end=1e-2
t_end=1e10

Y=range(Y_start,stop=Y_end,length=n_iter)
P=zeros(n_iter)
T=zeros(n_iter)

for k=1:n_iter
    global
    q0,p0=[zeros(2) for i in 1:2]
    P[k]=PofY_find(Y[k])
    q0[1]=0
    p0[1]=P[k]
    q0[2]=0
    p0[2]=Y[k]
    prob= HamiltonianProblem{true}(HAM, p0, q0, (0., t_end))
    t,A=solve(prob, Vern9(),reltol=1e-13,abstol=1e-20,maxiters=1e15, callback=cb)
    T[k]=t.t[end]
end
println("Max exit time is  ", maximum(T))


text:
using DelimitedFiles, ProgressMeter, PyPlot

include("./util.jl")
include("./parsers.jl")
include("./Algorithms/TEAVAR.jl")
include("./simulation.jl")

function pathSelection(topologies,
                      demand_downscales,
                      paths,
                      num_demands,
                      bars,
                      cutoff;
                      scale=1.0,
                      ksp=[],
                      weibull=true,
                      plot=true,
                      dirname="./data/raw/path_selection")

    env = Gurobi.Env()
    x_vals = bars
    y_vals = []
    labels = []
    scenarios = []
    probs = []

    # COMPUTE SCENARIOS
    for i in 1:length(topologies)
        links, capacity, link_probs, nodes = readTopology(topologies[i])
        if weibull == true
            weibull_probs = weibullProbs(length(link_probs), shape=.8, scale=.0001)
            temp_s, temp_p = subScenarios(weibull_probs, (sum(weibull_probs)/length(weibull_probs))^2, first=true, last=false)
            push!(scenarios, temp_s)
            push!(probs, temp_p)
        else
            scenario, prob = subScenarios(link_probs, cutoff, first=false, last=false)
            push!(scenarios, scenario)
            push!(probs, prob)
        end
    end

    for p in 1:length(paths)
        all_var_vals = [[] for i=1:length(x_vals)]
        algorithmn_vals = []
        progress = ProgressMeter.Progress(length(topologies)*num_demands*length(x_vals), .1, "Computing TEAVAR_$(paths[p])...", 50)
        for i in 1:length(topologies)
            links, capacity, link_probs, nodes = readTopology(topologies[i])
            for d in 1:num_demands
                demand, flows = readDemand("$(topologies[i])/demand", length(nodes), d, scale=scale, downscale=demand_downscales[i])
                T, Tf, k = parsePaths("$(topologies[i])/paths/$(paths[p])", links, flows)
                vals = map(b -> (ProgressMeter.next!(progress, showvalues = [(:topology,topologies[i]), (:demand,"$(d)/$(num_demands)"), (:paths,paths[p])]);
                                 TEAVAR(env, links, capacity, flows, demand, b, k, T, Tf, scenarios[i], probs[i])), x_vals)
                for j in 1:length(vals)
                    push!(all_var_vals[j], vals[j][2])
                end
            end
        end
        for j in 1:length(all_var_vals)
            push!(algorithmn_vals, sum(all_var_vals[j])/length(all_var_vals[j]))
        end
        push!(y_vals, algorithmn_vals)
        push!(labels, "Teavar_$(paths[p])")
    end

    for p in 1:length(ksp)
        all_var_vals = [[] for i=1:length(x_vals)]
        algorithmn_vals = []
        progress = ProgressMeter.Progress(length(topologies)*num_demands*length(x_vals), .1, "Computing TEAVAR_ksp$(ksp[p])...", 50)
        for i in 1:length(topologies)
            links, capacity, link_probs, nodes = readTopology(topologies[i])
            for d in 1:num_demands
                demand, flows = readDemand("$(topologies[i])/demand", length(nodes), d, scale=scale, downscale=demand_downscales[i])
                T, Tf, g = getTunnels(nodes, links, capacity, flows, ksp[p])
                vals = map(b -> (ProgressMeter.next!(progress, showvalues = [(:topology,topologies[i]), (:demand,"$(d)/$(num_demands)"), (:paths,"KSP-$p")]);
                                 TEAVAR(env, links, capacity, flows, demand, b, ksp[p], T, Tf, scenarios[i],probs[i])), x_vals)
                for j in 1:length(vals)
                    push!(all_var_vals[j], vals[j][2])
                end
            end
        end
        for j in 1:length(all_var_vals)
            push!(algorithmn_vals, sum(all_var_vals[j])/length(all_var_vals[j]))
        end
        push!(y_vals, algorithmn_vals)
        push!(labels, "Teavar_ksp$(ksp[p])")
    end

    # LOG OUTPUTS
    dir = nextRun(dirname)
    z = zeros(length(x_vals), length(y_vals) + 1)
    z[:,1] = x_vals
    for i in 1:length(y_vals)
        z[:,i+1] = y_vals[i]
    end
    writedlm("$dir/vals", z)

    # PLOT
    if plot
        PyPlot.clf()
        for i in 1:size(y_vals, 1)
            PyPlot.plot(x_vals, y_vals[i])
        end
        PyPlot.xlabel("Availability", fontweight="bold")
        PyPlot.ylabel("Beta Tail Loss", fontweight="bold")
        PyPlot.legend(labels, loc="upper right")
        PyPlot.savefig("$(dir)/plot.png")
        PyPlot.show()
    end
end

# pathSelection(["./data/B4", "./data/IBM"],
#                      [4000, 4000],
#                      ["SMORE", "FFC"],
#                      6,
#                      [.9, .92, .94, .96, .98, .99],
#                      .0001,
#                      ksp=[4,6],
#                      weibull=true)


text:
# State tests
n=Set(["a","b","c"])
l=Set([("a","b"),("b","c")])
s=State(0.2,0.6,n,l)
@test s.t0==0.2
@test s.t1==0.6
@test s.nodes==n
@test s.links==l
@test isapprox(duration(s),0.4)
@test number_of_nodes(s)==3
@test number_of_links(s)==2

# Transition tests
narr=Set(["d"])
ndep=Set(["a"])
larr=Set([("b","d")])
ldep=Set([("a","b")])
t=Transition(0.2,0.6,2.3,narr,ndep,larr,ldep)
@test t.tprev==0.2
@test t.t==0.6
@test t.tnxt==2.3
@test t.node_arrivals==narr
@test t.node_departures==ndep
#@test t.links_arrivals==larr
@test t.link_departures==ldep
@test Δnodes(t)==0
@test Δlinks(t)==0
apply!(s,t)
@test s.t0==0.6
@test s.t1==2.3
@test s.nodes==Set(["b","c","d"])
@test s.links==Set([("b","c"),("b","d")])
apply!(s,t)
@test s.t0==0.2
@test s.t1==0.6
@test s.nodes==Set(["a","b","c"])
@test s.links==Set([("a","b"),("b","c")])

S0=State(-1.0,0.0,Set(),Set())
T=Dict{Float64,Transition}()
T[0.0]=Transition(-1.0,0.0,1.0,Set(["a","b"]),Set(),Set(),Set())
T[1.0]=Transition(0.0,1.0,2.0,Set(["d"]),Set(),Set([("a","b")]),Set())
T[2.0]=Transition(1.0,2.0,3.0,Set(),Set(),Set([("b","d")]),Set())
T[3.0]=Transition(2.0,3.0,4.0,Set(),Set(["d"]),Set(),Set([("a","b"),("b","d")]))
T[4.0]=Transition(3.0,4.0,4.5,Set(["c"]),Set(["b"]),Set(),Set())
T[4.5]=Transition(4.0,4.5,5.0,Set(),Set(),Set([("a","c")]),Set())
T[5.0]=Transition(4.5,5.0,6.0,Set(["b"]),Set(),Set(),Set())
T[6.0]=Transition(5.0,6.0,7.0,Set(),Set(),Set([("b","c")]),Set())
T[7.0]=Transition(6.0,7.0,7.5,Set(),Set(),Set([("a","b")]),Set())
T[7.5]=Transition(7.0,7.5,8.0,Set(),Set(),Set(),Set([("a","c")]))
T[8.0]=Transition(7.5,8.0,9.0,Set(),Set(),Set(),Set([("a","b")]))
T[9.0]=Transition(8.0,9.0,10.0,Set(),Set(["c"]),Set(),Set([("b","c")]))
T[10.0]=Transition(9.0,10.0,11.0,Set(),Set(["a","b"]),Set(),Set())
tc=TimeCursor(S0,T)
@test number_of_nodes(tc)==0
@test number_of_links(tc)==0
next!(tc)
@test number_of_nodes(tc)==2
@test nodes(tc)==Set(["a","b"])
@test number_of_links(tc)==0
next!(tc)
@test number_of_nodes(tc)==3
@test nodes(tc)==Set(["a","b","d"])
@test number_of_links(tc)==1
@test links(tc)==Set([("a","b")])
next!(tc)
@test number_of_nodes(tc)==3
@test nodes(tc)==Set(["a","b","d"])
@test number_of_links(tc)==2
@test links(tc)==Set([("a","b"),("b","d")])
next!(tc)
@test number_of_nodes(tc)==2
@test nodes(tc)==Set(["a","b"])
@test number_of_links(tc)==0
@test links(tc)==Set()
previous!(tc)
@test number_of_nodes(tc)==3
@test nodes(tc)==Set(["a","b","d"])
@test number_of_links(tc)==2
@test links(tc)==Set([("a","b"),("b","d")])
previous!(tc)
@test number_of_nodes(tc)==3
@test nodes(tc)==Set(["a","b","d"])
@test number_of_links(tc)==1
@test links(tc)==Set([("a","b")])
end!(tc)
@test number_of_nodes(tc)==2
@test nodes(tc)==Set(["a","b"])
@test number_of_links(tc)==0
start!(tc)
@test number_of_nodes(tc)==2
@test nodes(tc)==Set(["a","b"])
@test number_of_links(tc)==0
goto!(tc,4.2)
@test number_of_nodes(tc)==2
@test nodes(tc)==Set(["a","c"])
@test number_of_links(tc)==0
goto!(tc,7.2)
@test number_of_nodes(tc)==3
@test nodes(tc)==Set(["a","c","b"])
@test number_of_links(tc)==3
@test links(tc)==Set([("a","b"),("a","c"),("b","c")])
goto!(tc,2.999999)
@test number_of_nodes(tc)==3
@test nodes(tc)==Set(["a","d","b"])
@test number_of_links(tc)==2
@test links(tc)==Set([("a","b"),("b","d")])
goto!(tc,3.0)
@test number_of_nodes(tc)==2
@test nodes(tc)==Set(["a","b"])
@test number_of_links(tc)==0
@test nodes(tc,6.8)==Set(["a","b","c"])
@test links(tc,6.8)==Set([("a","c"),("b","c")])
@test nodes(tc,4.0)==Set(["a","b","c"])
@test links(tc,4.0)==Set()
@test nodes(tc,0.0)==Set(["a","b"])
@test links(tc,0.0)==Set()
@test nodes(tc,10.0)==Set(["a","b"])
@test links(tc,10.0)==Set()
@test nodes(tc,0.0,10.0)==Set(["a","b","c","d"])
@test links(tc,0.0,10.0)==Set([("a","b"),("a","c"),("b","d"),("b","c")])
@test nodes(tc,0.0,0.0)==Set(["a","b"])
@test links(tc,0.0,0.0)==Set()
@test nodes(tc,1.0,3.0)==Set(["a","b","d"])
@test links(tc,1.0,3.0)==Set([("a","b"),("b","d")])
@test nodes(tc,0.9999,3.000001)==Set(["a","b","d"])
@test links(tc,0.9999,3.000001)==Set([("a","b"),("b","d")])
@test nodes(tc,4.0,4.0)==Set(["a","b","c"])
@test nodes(tc,3.9999,4.0)==Set(["a","b","c"])
@test nodes(tc,4.0,4.0001)==Set(["a","b","c"])
@test nodes(tc,4.00001,4.1)==Set(["a","c"])
@test density(tc)==0.0
@test density(tc,0.0,10.0)==8.0/12.0


text:
# *****************************************************************************
# Written by Ritchie Lee, ritchie.lee@sv.cmu.edu
# *****************************************************************************
# Copyright ã 2015, United States Government, as represented by the
# Administrator of the National Aeronautics and Space Administration. All
# rights reserved.  The Reinforcement Learning Encounter Simulator (RLES)
# platform is licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You
# may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable
# law or agreed to in writing, software distributed under the License is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the specific language
# governing permissions and limitations under the License.
# _____________________________________________________________________________
# Reinforcement Learning Encounter Simulator (RLES) includes the following
# third party software. The SISLES.jl package is licensed under the MIT Expat
# License: Copyright (c) 2014: Youngjun Kim.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
# "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# *****************************************************************************

using RLESUtils, DataFrameSets

type TFDataset{Tx,Ty,N}
    X::Array{Tx,N}
    Y::Vector{Ty}
    num_examples::Int64
    index_in_epoch::Int64
    epochs_completed::Int64
end

type TFDatasets
    train::TFDataset
    validation::TFDataset
    test::TFDataset
end

TFDataset(Dl::DFSetLabeled) = TFDataset(Dl.data, Dl.labels)
function TFDataset(DX, DY)
    X = convert(Array, DX)
    Y = convert(Array, DY)

    sizeX = size(X)
    sizeY = size(Y)
    @assert sizeX[1] == sizeY[1]
    num_examples = sizeY[1]

    index_in_epoch = 0
    epochs_completed = 0
    TFDataset(X, Y, num_examples, index_in_epoch, epochs_completed)
end

getX(ds::TFDataset) = Tensor(ds.X)
getY(ds::TFDataset) = Tensor(ds.Y)
epochs_completed(ds::TFDataset) = ds.epochs_completed
num_examples(ds::TFDataset) = ds.num_examples
index_in_epoch(ds::TFDataset) = ds.index_in_epoch

function next_batch(ds::TFDataset, batch_size::Int64;
    rng::Nullable{AbstractRNG}=Nullable{AbstractRNG}())

    start_index = ds.index_in_epoch + 1
    ds.index_in_epoch += batch_size
    if ds.index_in_epoch > ds.num_examples
        # Finished epoch
        ds.epochs_completed += 1
        # Shuffle the data
        if isnull(rng)
            perm = randperm(ds.num_examples)
        else
            perm = randperm(get(rng), ds.num_examples)
        end
        ds.X = getindex1(ds.X, perm)
        ds.Y = ds.Y[perm]
        start_index = 1
        ds.index_in_epoch = batch_size
        @assert ds.index_in_epoch <= ds.num_examples
    end
    end_index = ds.index_in_epoch
    x = getindex1(ds.X, start_index:end_index)
    y = ds.Y[start_index:end_index] #label is dense (not one-hot)
    return (x, y)
end

"""
getindex where the index for the first dim is given, others are ':'
this function exists to support varying dims in arrays
"""
function getindex1{T,N}(X::Array{T,N}, i1)
    if N == 2
        return X[i1, :]
    elseif N == 3
        return X[i1, :, :]
    elseif N == 1
        return X[i1]
    else
        error("Not implemented")
    end
end


text:
#
#--------------------------------------#
export advect
#--------------------------------------#
"""
 for v,u,T in H¹₀(Ω)

 (v,(u⃗⋅∇)T) = (v,ux*∂xT + uy*∂yT)\n
            = v' *B*(ux*∂xT + uy*∂yT)\n

 implemented as

 R'R * QQ' * B * (ux*∂xT + uy*∂yT)

 (u⃗⋅∇)T = ux*∂xT + uy*∂yT

        = [ux uy] * [Dx] T
                    [Dx]

 ux,uy, ∇T are interpolated to
 a grid with higher polynomial order
 for dealiasing (over-integration)
 so we don't commit any
 "variational crimes"

"""
function advect(T  ::Array
               ,ux ::Array
               ,uy ::Array
               ,msh::Mesh)

    @unpack B = msh

    Tx,Ty = grad(T,msh)

    Cu   = @. ux * Tx + uy * Ty
    Cu .*= B

#   Cu = gatherScatter(Cu,msh)
#   Cu = mask(Cu,M)

    return Cu
end
#--------------------------------------#
function advect(T   ::Array
               ,ux  ::Array
               ,uy  ::Array
               ,mshV::Mesh
               ,mshD::Mesh  # dealias
               ,Jr,Js)

    Tx,Ty = grad(T,mshV)

    JTx = ABu(Js,Jr,Tx)
    JTy = ABu(Js,Jr,Ty)
    Jux = ABu(Js,Jr,ux)
    Juy = ABu(Js,Jr,uy)

    JCu   = @. Jux*JTx + Juy*JTy
    JCu .*= mshD.B
    Cu    = ABu(Js',Jr',JCu)

    return Cu
end
#--------------------------------------#
function advect(T   ::Array
               ,ux  ::Array
               ,uy  ::Array
               ,mshV::Mesh
               ,mshD::Mesh) # dealias

    Jr = interpMat(mshD.zr,mshV.zr)
    Js = interpMat(mshD.zs,mshV.zs)

    Cu = advect(T,ux,uy,mshV,mshD,Jr,Js)

    return Cu
end
#--------------------------------------#


text:
using Clang.Generators
using Sundials_jll
using MLStyle
using Pkg

# 1st arg name to wrapped arg type map
const arg1_name2type = Dict(
    :arkode_mem => :(ARKStepMemPtr),
    :cvode_mem => :(CVODEMemPtr),
    :cv_mem => :(CVODEMemPtr),
    :kinmem => :(KINMemPtr),
    :kinmemm => :(KINMemPtr), # Sundials typo?
    :ida_mem => :(IDAMemPtr),
    :idaa_mem => :(IDAMemPtr), # Sundials typo?
    :idaadj_mem => :(IDAMemPtr), # Sundials typo?
)

const linear_solvers_and_matrices = [
    # Linear Solvers
    "band",
    "dense",
    "klu",
    "lapackend",
    "lapackdense",
    "pcg",
    "spbcgs",
    "spfgmr",
    "spgmr",
    "sptfqmr",
    # Matrices
    "sparse",
    # Non linear solvers
    "fixedpoint",
    "newton"
    ]

# substitute Ptr{Void} with the typed pointer
const ctor_return_type = Dict(
    "ARKCreate" => :(ARKStepMemPtr),
    "ARKStepCreate" => :(ARKStepMemPtr),
    "ERKStepCreate" => :(ERKStepMemPtr),
    "MRIStepCreate" => :(MRIStepMemPtr),
    "CVodeCreate" => :(CVODEMemPtr),
    "IDACreate" => :(IDAMemPtr),
    "KINCreate" => :(KINMemPtr)
)
# signatures for C function pointer types
const FnTypeSignatures = Dict(
    :ARKRhsFn => (:Cint, :((realtype, N_Vector, N_Vector, Ptr{Cvoid}))),
    :CVRhsFn => (:Cint, :((realtype, N_Vector, N_Vector, Ptr{Cvoid}))),
    :CVRootFn => (:Cint, :((realtype, N_Vector, Ptr{realtype}, Ptr{Cvoid}))),
    :IDAResFn => (:Cint, :((realtype, N_Vector, N_Vector, N_Vector, Ptr{Cvoid}))),
    :IDARootFn => (:Cint, :((realtype, N_Vector, N_Vector, Ptr{realtype}, Ptr{Cvoid}))),
    :KINSysFn => (:Cint, :((N_Vector, N_Vector, Ptr{Cvoid}))),
)

function wrap_sundials_api(expr::Expr)
    if expr.head == :function &&
        expr.args[1].head == :call
        func_name = string(expr.args[1].args[1])
        convert_required = false
        if occursin(r"^(ARK|ERK|MRI|CV|KIN|IDA|SUN|N_V)", func_name)
	        # @show func_name
            if occursin(r"Create$", func_name) && !occursin(r"Butcher", func_name)
                # create functions return typed pointers
		        @assert expr.args[2].args[1].args[3] == :(Ptr{Cvoid})
                expr.args[2].args[1].args[3] = ctor_return_type[func_name]
            elseif length(expr.args[1].args) > 1
		        arg1_type = expr.args[2].args[1].args[4].args[1]
                if arg1_type == :(Ptr{Cvoid}) || arg1_type == :(Ptr{Ptr{Cvoid}})
		            arg1_name = expr.args[1].args[2]
                    arg1_newtype = arg1_name2type[arg1_name]
                    # seperate ARKStepMemPtr from ERK* and MRI*
                    if arg1_newtype == :ARKStepMemPtr
                        arg1_newtype = Symbol(func_name[1:3] * "StepMemPtr")
                    end
                    if arg1_type == :(Ptr{Ptr{Cvoid}})
                        # adjust for void** type (for CVodeFree()-like funcs)
                        arg1_newtype = Expr(:curly, :Ref, arg1_newtype)
                    end
		             expr.args[2].args[1].args[4].args[1] = arg1_newtype
                    convert_required = true
                end
            end
            if occursin(r"UserDataB?$", func_name)
                # replace Ptr{Void} with Any to allow passing Julia objects through user data
                for (i, arg_expr) in enumerate(expr.args[2].args[1].args)
         	        if !(typeof(arg_expr) <: Symbol) && arg_expr.args[1] in values(ctor_return_type)
			            if arg_expr.args[2] == :(Ptr{Cvoid})
		                    arg_expr.args[2] = Any
		                elseif arg_expr.args[3] == :(Ptr{Cvoid})
		    	            arg_expr.args[3] = Any
		                end
			        end
                end
            end
            if !(typeof(expr) <: Symbol) && length(expr.args) > 1 && (expr.args[2].args[1].args[2].args[2] == :libsundials_sunlinsol || expr.args[2].args[1].args[2].args[2] == :libsundials_sunmatrix || expr.args[2].args[1].args[2].args[2] == :libsundials_sunnonlinsol)
                if func_name[1:6] == "SUNMAT"
                    expr.args[2].args[1].args[2].args[2] =
                    Symbol(string(expr.args[2].args[1].args[2].args[2]) *
                    lowercase(split(func_name, "_")[end]))
                else
                    name_i = findfirst(lsmn -> occursin(lsmn, lowercase(func_name)), linear_solvers_and_matrices)

                    @assert name_i > 0
                    name = linear_solvers_and_matrices[name_i]
                    expr.args[2].args[1].args[2].args[2] = Symbol(string(expr.args[2].args[1].args[2].args[2]) * name)
                end
            end
            # generate a higher-level wrapper that converts 1st arg to XXXMemPtr
            # and all other args from Julia objects to low-level C wrappers (e.g. NVector to N_Vector)
            # create wrapers for all arguments that need wrapping
            args_wrap_exprs = map(Base.Iterators.drop(expr.args[1].args, 1)) do expr
                # process each argument
                # return a tuple:
                #   1) high-level wrapper arg name expr
                #   2) expr for local var definition, nothing if not required
                #   3) expr for low-level wrapper call
                # if 1)==3), then no wrapping is required
                if typeof(expr) <: Symbol
                    arg_name_expr = expr
                    arg_type_expr = Any
                else
                    arg_name_expr = expr.args[1]
                    arg_type_expr = expr.args[2]
                end
                if arg_type_expr == :N_Vector
                    # first convert argument to NVector() and store in local var,
                    # this guarantees that the wrapper and associated Sundials object (e.g. N_Vector)
                    # is not removed by GC
                    return (arg_name_expr,
                            Expr(:call, :convert, :NVector, arg_name_expr), # convert arg to NVector to store in a local var
                            Expr(:call, :convert, arg_type_expr, Symbol(string("__", arg_name_expr)))) # convert NVector to N_Vector
                elseif arg_type_expr == :Clong || arg_type_expr == :Cint ||
                    occursin(r"MemPtr$", string(arg_type_expr))
                    # convert(XXXMemPtr, mem), no local var required
                    return (arg_name_expr, nothing,
                            Expr(:call, :convert, arg_type_expr, arg_name_expr))
                elseif isa(arg_type_expr, Expr) && arg_type_expr.head == :curly &&
                    arg_type_expr.args[1] == :Ptr && arg_type_expr.args[2] != :FILE
                    # convert julia arrays to pointer, no local var required
                    # FIXME sometimes these arguments are not really arrays, but just a pointer to a var to be assigned
                    # by the function call. Does that make sense to detect such cases and assume that input arg is a reference to Julia var?
                    return (arg_name_expr, nothing,
                            Expr(:call, :pointer, arg_name_expr))
                elseif haskey(FnTypeSignatures, arg_type_expr) # wrap Julia function to C function using a defined signature
                    return (arg_name_expr, nothing,
                            Expr(:call, Symbol(string(arg_type_expr, "_wrapper")), arg_name_expr))
                else # any other case, no argument wrapping
                    return (arg_name_expr, nothing, arg_name_expr)
                end
            end
            # check which arguments are wrapped
            if any(map(arg_exprs -> arg_exprs[1] != arg_exprs[3], args_wrap_exprs))
                # mangle the name of the low-level wrapper to avoid recursion
                lowlevel_func_name = string(func_name)
                expr.args[1].args[1] = Symbol(lowlevel_func_name)

                # higher-level wrapper function
                wrapper_func_expr = Expr(:function,
                    # function declaration with argument types stripped, so it would accept any type
                    Expr(:call, Symbol(func_name), map(arg_exprs -> arg_exprs[1], args_wrap_exprs)...),
                    Expr(:block,
                    # local var defs
                    map(filter(arg_exprs -> arg_exprs[2] !== nothing, args_wrap_exprs)) do arg_exprs
                    Expr(:(=), Symbol("__", arg_exprs[1]), arg_exprs[2])
                end...,
                    # low-level function call with Julia types converted to low-level arguments
                    Expr(:call, Symbol(lowlevel_func_name),
                         map(arg_exprs -> arg_exprs[3], args_wrap_exprs)...)
                    )
                )
                # write down both low-level and higher level wrappers
                return Any[expr, wrapper_func_expr]
            else
                return Any[expr]
            end
        end
    elseif expr.head == :typealias && haskey(FnTypeSignatures, expr.args[1])
        # C functional type, generate the wrapper from Julia to C function
        # dummy wrapper that accepts pointer
        fn_typename = expr.args[1]
        fn_rettype, fn_argtypes = FnTypeSignatures[fn_typename]
        wrapper_name = Symbol(string(string(fn_typename), "_wrapper"))
        c_wrapper_def = Expr(:(=),
                Expr(:call, wrapper_name, Expr(:(::), :fp, fn_typename)), :fp)
        jl_wrapper_def = Expr(:(=),
            Expr(:call, wrapper_name, :f),
            # function declaration with argument types stripped
            Expr(:call, :cfunction, :f, fn_rettype, fn_argtypes))
        return Any[expr, c_wrapper_def, jl_wrapper_def]
    elseif expr.head == :const && expr.args[1].head == :(=) &&
           isa(expr.args[1].args[2], Int)
        # fix integer constants should be Cint
        expr.args[1].args[2] = Expr(:call, :Cint, expr.args[1].args[2])
    end
    return Any[expr]
end

function rewrite(ex)
    ex = @match ex begin
        :(const $name = SUNDIALS_F77_FUNC($arg1, $arg2)) => :(const $name = nothing)
            # Expr(:macro, :($name()), Expr(:macrocall, Symbol("@SUNDIALS_F77_FUNC"), nothing, arg1, arg2))
        :(const $sun_name = $klu_name) &&
                if startswith(string(sun_name), "sun_klu_") && startswith(string(klu_name), "klu_") end =>
            :(const $sun_name = nothing) # skip
        _ => ex
    end
    wrap_sundials_api(ex)
end

cd(@__DIR__)

include_dir = joinpath(Sundials_jll.artifact_dir, "include") |> normpath

artifact_toml = joinpath(dirname(pathof(Sundials_jll.SuiteSparse_jll)), "..", "StdlibArtifacts.toml")
suitespase_dir= Pkg.Artifacts.ensure_artifact_installed("SuiteSparse", artifact_toml)
suitespase_include_sir = joinpath(suitespase_dir, "include")

# wrapper generator options
options = load_options(joinpath(@__DIR__, "generate.toml"))

# add compiler flags, e.g. "-DXXXXXXXXX"
args = get_default_args()
push!(args, "-I$include_dir", "-isystem$suitespase_include_sir")

library_names = Dict(
    raw"sundials[\\/].+" => "libsundials_sundials",
    raw"sunnonlinsol[\\/].+" => "libsundials_sunnonlinsol",
    raw"sunmatrix[\\/].+" => "libsundials_sunmatrix",
    raw"kinsol[\\/].+" => "libsundials_kinsol",
    raw"ida[\\/].+" => "libsundials_ida",
    raw"cvodes[\\/].+" => "libsundials_cvodes",
    raw"sunlinsol[\\/].+$(?<!lapackband\.h)(?<!lapackdense\.h)" => "libsundials_sunlinsol",
    raw"cvode[\\/].+" => "libsundials_cvode",
    raw"idas[\\/].+" => "libsundials_idas",
    raw"arkode[\\/].+" => "libsundials_arkode",
    raw"nvector[\\/].+" => "libsundials_nvecserial",
    raw"lapackband\.h" => "libsundials_sunlinsollapackband",
    raw"lapackdense\.h" => "libsundials_sunlinsollapackdense",
    )
headers = String[]
for lib in readdir(include_dir)
    header_dir = joinpath(include_dir, lib)
    append!(headers, joinpath(header_dir, header) for header in readdir(header_dir) if endswith(header, ".h"))
end
options["general"]["library_names"] = library_names

ctx = create_context(headers, args, options)

# run generator
build!(ctx, BUILDSTAGE_NO_PRINTING)
for n in ctx.dag.nodes
    copy!(n.exprs, reduce(vcat, rewrite.(n.exprs), init=[]))
end
build!(ctx, BUILDSTAGE_PRINTING_ONLY)


text:
# --- Utilities

"""
    _unzip(xs::Tuple)

# Examples
```jldoctest; setup = :(using Transducers: _unzip)
julia> _unzip(((1, 2, 3), (4, 5, 6)))
((1, 4), (2, 5), (3, 6))
```
"""
_unzip(xs::Tuple{Vararg{NTuple{N,Any}}}) where {N} = ntuple(i -> map(x -> x[i], xs), N)

if isdefined(Iterators, :Zip1)  # VERSION < v"1.1-"
    arguments(xs::Iterators.Zip1) = (xs.a,)
    arguments(xs::Iterators.Zip2) = (xs.a, xs.b)
    arguments(xs::Iterators.Zip) = (xs.a, arguments(xs.z)...)
    const _Zip = Iterators.AbstractZipIterator
else
    arguments(xs::Iterators.Zip) = xs.is
    const _Zip = Iterators.Zip
end

if VERSION < v"1.3"
    _Channel(f, ::Type{T}, size; kwargs...) where {T} =
        Channel(f; ctype = T, csize = size, kwargs...)
else
    _Channel(f, ::Type{T}, size; kwargs...) where {T} = Channel{T}(f, size; kwargs...)
end

_typeof(::Type{T}) where {T} = Type{T}
_typeof(::T) where {T} = T

const ValBool = Union{Val{false}, Val{true}}

@generated function default_constructorof(::Type{T}) where T
    getfield(parentmodule(T), nameof(T))
end

function _materializer(xs)
    T = Tables.materializer(xs)
    return T isa Type ? T : _materializer(typeof(xs))
end

function _materializer(::Type{T}) where T
    S = ConstructionBase.constructorof(T)
    return S isa Type ? S : T
end

prefixed_type_name(@nospecialize x) =
    sprint(show, typeof(x), context = :module => Base)
# `:module => Base` to enforce that the type is prefixed even when
# `typeof(x)` is imported in `Main`.  See:
# https://github.com/JuliaLang/julia/pull/29466

const DenseSubVector{T} =
    SubArray{T, 1, Vector{T}, Tuple{UnitRange{Int64}}, true}

# https://github.com/JuliaLang/julia/pull/33533
if VERSION < v"1.4"
    const PartitionableArray = Vector
else
    const PartitionableArray = AbstractArray
end

const _non_executable_transducer_msg = """
Output type of the transducer is inferred to be a `Union{}`.  This
probably means one or more of the composed transducers throw.
"""

@inline _poptail(xs) = _poptail_impl(xs...)
@inline _poptail_impl(a) = (), a
@inline function _poptail_impl(a, xs...)
    head, tail = _poptail_impl(xs...)
    return (a, head...), tail
end

Base.@pure nthtype(::Val{1}, ::Type{T}) where {T <: Tuple} =
    Base.tuple_type_head(T)

Base.@pure nthtype(::Val{n}, ::Type{T}) where {n, T <: Tuple} =
    nthtype(Val(n - 1), Base.tuple_type_tail(T))

_cljapiurl(name) =
    "https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/$name"
_cljref(name) =
    "[`$name` in Clojure]($(_cljapiurl(name)))"
_thx_clj(name) =
    "This API is modeled after $(_cljref(name))."

# https://github.com/JuliaLang/julia/pull/30575
const _true_str = sprint(show, true; context=:typeinfo => Bool)
const _false_str = sprint(show, false; context=:typeinfo => Bool)

# Just like `Function` but for defining some common methods.
abstract type _Function <: Function end

# Avoid `Function` fallbacks:
@nospecialize
Base.show(io::IO, ::MIME"text/plain", f::_Function) = show(io, f)
Base.print(io::IO, f::_Function) = show(io, f)
@specialize

# A macro for "manual Union splitting".  It is sometimes useful to let
# the compiler know that it is beneficial to type-specialize `body`.
# * https://github.com/JuliaFolds/Transducers.jl/pull/188
# * https://github.com/JuliaLang/julia/pull/34293#discussion_r363550608
macro manual_union_split(cond, body)
    quote
        if $cond
            $body
        else
            $body
        end
    end |> esc
end

@inline _firstindex(arr) = firstindex(arr)
@inline _lastindex(arr) = lastindex(arr)

# Define `firstindex` and `lastindex` for `Broadcasted` with linear
# index style:
@inline _firstindex(bc::Broadcasted) = first((axes(bc)::Tuple{Any})[1])
@inline _lastindex(bc::Broadcasted) = last((axes(bc)::Tuple{Any})[1])

# Define `CartesianIndices` for `Broadcasted`
@inline _CartesianIndices(arr) = CartesianIndices(arr)
@inline _CartesianIndices(bc::Broadcasted) = CartesianIndices(axes(bc)::Tuple)

# Define `IndexStyle` for `Broadcasted`
_IndexStyle(arr) = IndexStyle(arr)
_IndexStyle(bc::Broadcasted) = _IndexStyle(typeof(bc))
_IndexStyle(::Type{<:Broadcasted{<:Any,<:Tuple{Any}}}) = IndexLinear()
_IndexStyle(::Type{<:Broadcasted{<:Any}}) = IndexCartesian()

struct Err{T}
    value::T
end

struct Ok{T}
    value::T
end

struct Promise
    value::Base.RefValue{Any}
    isset::Threads.Atomic{Bool}
    notify::Threads.Condition
end

Promise() = Promise(Ref{Any}(), Threads.Atomic{Bool}(false), Threads.Condition())

tryfetch(::Nothing) = nothing
tryfetch(p::Promise) = p.isset[] ? Some(p.value[]) : nothing

function tryput!(p::Promise, value)
    p.isset[] && return Some(p.value[])
    lock(p.notify) do
        p.isset[] && return Some(p.value[])
        p.value[] = value
        p.isset[] = true
        notify(p.notify)
        return nothing
    end
end

function Base.fetch(p::Promise)
    p.isset[] && return p.value[]
    lock(p.notify) do
        while !p.isset[]
            wait(p.notify)
        end
        return p.value[]
    end
end

function async_foreach(f, xs)
    @sync for x in xs
        @async f(x)
    end
end

function sync_spawn_foreach(f, xs)
    for x in xs
        wait(@spawn f(x))
    end
end


text:
# problems found in readTopologyUpdate when trying to plot with John Spaw's functions
# will test here the problems
# Claudia July 2015

include("../src/types.jl")
include("../src/functions.jl")

# estNetworks form baseline and phylonet
n1 = "(((1,2))#H1,(6,(5,((4,3),#H1))));"
n2 = "((5)#H1,(6,((1,2),(3,(4,#H1)))));"
n3 = "((5,((3,4),((2,1))#H1)),(6,#H1));"
n4 = "(6,(5,((1,(2,(3)#H1)),(4,#H1))));"
n5 = "(6,((((3,4))#H1,(2,1)),(5,#H1)));"
n6 = "((((5,(3,4)))#H1,(1,2)),(6,#H1));"
n7 = "(((5)#H1,((2,1),(4,3))),(#H1,6));"
n8 = "(6,((5,((4,3))#H1),((1,2),#H1)));"
n9 = "(6,(((1,2),((3,4))#H1),(5,#H1)));"
n10 = "(6,((((4,3))#H1,(1,2)),(5,#H1)));"
n11 = "(6,(((2,1),((4,3))#H1),(5,#H1)));"
n12 = "(6,((5)#H1,((2,1),((4,3),#H1))));"
n13 = "(6,((((4,3))#H1,(1,2)),(#H1,5)));"
n14 = "(6,((5,((4,3))#H1),(#H1,(2,1))));"
n15 = "(6,(((2,1),((4,3))#H1),(5,#H1)));"
n16 = "(6,(5,(((4,3))#H1,(1,(#H1,2)))));"
n17 = "(6,(((1,2),((4)#H1,3)),(5,#H1)));"
n18 = "((5,((4,3),(1,(2)#H1))),(6,#H1));"
n19 = "((((5,(3,4)))#H1,6),((2,1),#H1));"
n20 = "(6,(((1,2),((4,3))#H1),(5,#H1)));"
n21 = "(6,((5,((3,4))#H1),((1,2),#H1)));"
n22 = "((5)#H1,(6,((2,1),(#H1,(4,3)))));"
n23 = "(6,(((1,2),((4)#H1,3)),(5,#H1)));"
n24 = "(6,((5,((3,4))#H1),((1,2),#H1)));"
n25 = "(6,((5,((4,3))#H1),((2,1),#H1)));"
n26 = "(((1,2))#H1,(6,(5,((3,4),#H1))));"
n27 = "(6,((5)#H1,((2,1),((4,3),#H1))));"
n28 = "(6,(((2,1),((3,4))#H1),(5,#H1)));"
n29 = "(6,((((4,3))#H1,(2,1)),(5,#H1)));"
n30 = "(6,(((1,2),(3,(4)#H1)),(#H1,5)));"

string = [n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15,n16,n17,n18,n19,n20,n21,n22,n23,n24,n25,n26,n27,n28,n29,n30]

for s in string
    net = readTopologyUpdate(s);
    printEdges(net)
    printNodes(net)
    net.node[net.root].number
    net.node[net.root].leaf
    canBeRoot(net.node[net.root]) || error("root wrongly placed in $(s)")

    net2 = readTopologyUpdate(s,true);
    printEdges(net2)
    printNodes(net2)
    net2.node[net2.root].number
    net2.node[net2.root].leaf
    canBeRoot(net2.node[net2.root])  || error("root wrongly placed in $(s)")
end

println("NO ERRORS!")

## # --------------
## n31 = "(6,((5,(((1,(2,(3)#H7:9.380388137723473):1.215558354715711):1.533022718529031,#H7:0.8208307297991476):0.0,(4)#H9:-0.0):10.0):10.0,#H9:0.0):0.02572743545235116);"
## net = readTopologyUpdate(n31)
## printEdges(net)
## printNodes(net)
## net.node[net.root].number
## net.node[net.root].leaf
## canBeRoot(net.node[net.root]) || error("root wrongly placed in $(s)")


text:
using TopoChains

using Test

const tests = [
    "functopo", "topochain",
]

@testset "TopoChains" begin
  for t in tests
    fp = joinpath(dirname(@__FILE__), "test_$t.jl")
    @info "Test $(uppercase(t))"
    include(fp)
  end
end


text:
println("Dh) Test of the PhotoIonizationAutoIon module with ASF from an internally generated initial-, intermediate and final-state multiplets.")
#
wa = Atomic.Computation(Atomic.Computation(), name="xx", grid=JAC.Radial.Grid(true), nuclearModel=Nuclear.Model(26.),
                        initialConfigs=[Configuration("1s^2 2s"), Configuration("1s^2 2p")],
                        intermediateConfigs=[Configuration("1s 2s^2 2p"), Configuration("1s 2s 2p^2") ],
                        finalConfigs  =[Configuration("1s^2 2s^2"), Configuration("1s^2 2s 2p") ],
                        process = PhotoIonAuto(),
                        processSettings=PhotoIonizationAutoion.Settings()  )

wb = perform(wa)


text:
using DelimitedFiles

function solve(input)
    raw = readdlm(input,'\n')
    dependencies = Dict{Char,Set{Char}}()
    reduce(parse,raw,init=dependencies)
    @show dependencies
    dependencies_copy = deepcopy(dependencies)
    #part 1
    assembly_order = []
    while !isempty(dependencies)
        _, next_task = minimum([(length(v),k) for (k,v) in dependencies])
        delete!(dependencies,next_task)
        for (_,v) in dependencies
            delete!(v,next_task)
        end
        push!(assembly_order,next_task)
    end
    @show join(assembly_order)
    #part 2
    dependencies = dependencies_copy
    assemblers = [[nothing,0] for _ in 1:5]
    task_delay = 60
    clock = 0
    for time in Iterators.countfrom(1,1)
        if isempty(dependencies) && all(assembler->(assembler[2]<=0),assemblers)
            break
        end
        for assembler in assemblers
            assembler[2]-=1
            if assembler[2]<=0
                if isempty(dependencies)
                    assembler[1]=nothing
                    assembler[2]=0
                    continue
                end
                if assembler[1] != nothing
                    for (_,v) in dependencies
                        delete!(v,Char(assembler[1]))
                    end
                end
            end
        end
        for assembler in assemblers
            if assembler[2]<=0
                if isempty(dependencies)
                    continue
                end
                tasks = [(length(v),k) for (k,v) in dependencies]
                deps, next_task = minimum(tasks)
                if deps>0
                    assembler[1]=nothing
                    assembler[2]=0
                    continue
                end
                delete!(dependencies,next_task)
                assembler[1] = next_task
                assembler[2] = (next_task-'A')+1+task_delay
            end
        end
        clock+=1
    end
    clock-=1
    @show clock

end

function parse(dependencies,s)
    m = match(r"Step (?<left>[A-Z]) must be finished before step (?<right>[A-Z]) can begin.", s)
    dependency = collect(m[:left])[1]
    task = collect(m[:right])[1]
    if haskey(dependencies,task)
        push!(dependencies[task],dependency)
    else
        dependencies[task]=Set([dependency])
    end
    if !haskey(dependencies,dependency)
        dependencies[dependency]=Set()
    end
    return dependencies
end

solve("input.txt")


text:
using Compose
using Compat

include("misc.jl")
include("immerse.jl")

# Run the examples
const testdir = dirname(@__FILE__)
cd(testdir)

exampledir = joinpath(testdir, "..", "examples")
for ex in readdir(exampledir)
    endswith(ex, ".jl") || continue
    file = joinpath(exampledir, ex)
    expr = quote
        module $(Symbol(replace(ex, ".", "_")))
        using Compose
        using Colors
        using Compat
        srand(1) #Needed so that SVG uuid is reproducible
        include($file)
        end
    end
    expr.head = :toplevel
    eval(expr)
end

if !haskey(ENV, "TRAVIS")
    include("compare_examples.jl")
end


text:
include("lib_for_robot.jl")
function task2(r)
    x,y=tostart(r)
    for s in (Nord,Ost,Sud,West)
        putmarks(r,s)
    end
    for i in 1:x
        move!(r,Ost)
    end
    for i in 1:y
        move!(r,Nord)
    end
end


text:
using GPUCompiler

if !@isdefined(TestRuntime)
    include("../util.jl")
end

# create a native test compiler, and generate reflection methods for it

function wasm_job(@nospecialize(func), @nospecialize(types); kernel::Bool=false, kwargs...)
  source = FunctionSpec(func, Base.to_tuple_type(types), kernel)
  target = WASMCompilerTarget()
  params = TestCompilerParams()
  CompilerJob(target, source, params), kwargs
end

function wasm_code_typed(@nospecialize(func), @nospecialize(types); kwargs...)
  job, kwargs = wasm_job(func, types; kwargs...)
  GPUCompiler.code_typed(job; kwargs...)
end

function wasm_code_warntype(io::IO, @nospecialize(func), @nospecialize(types); kwargs...)
  job, kwargs = wasm_job(func, types; kwargs...)
  GPUCompiler.code_warntype(io, job; kwargs...)
end

function wasm_code_llvm(io::IO, @nospecialize(func), @nospecialize(types); kwargs...)
  job, kwargs = wasm_job(func, types; kwargs...)
  GPUCompiler.code_llvm(io, job; kwargs...)
end

function wasm_code_native(io::IO, @nospecialize(func), @nospecialize(types); kwargs...)
  job, kwargs = wasm_job(func, types; kwargs...)
  GPUCompiler.code_native(io, job; kwargs...)
end

# aliases without ::IO argument
for method in (:code_warntype, :code_llvm, :code_native)
  wasm_method = Symbol("wasm_$(method)")
  @eval begin
      $wasm_method(@nospecialize(func), @nospecialize(types); kwargs...) =
          $wasm_method(stdout, func, types; kwargs...)
  end
end

# simulates codegen for a kernel function: validates by default
function wasm_code_execution(@nospecialize(func), @nospecialize(types); kwargs...)
  job, kwargs = wasm_job(func, types; kernel=true, kwargs...)
  GPUCompiler.compile(:asm, job; kwargs...)
end


text:
using Documenter

if haskey(ENV, "GITHUB_ACTIONS")
    ENV["JULIA_DEBUG"] = "Documenter"
end

Documenter.post_status(;
    type="pending",
    repo="github.com/JuliaGaussianProcesses/AbstractGPs.jl.git"
)

using Literate, AbstractGPs

if ispath(joinpath(@__DIR__, "src/examples"))
    rm(joinpath(@__DIR__, "src/examples"), recursive=true)
end

for filename in readdir(joinpath(@__DIR__, "..", "examples"))
    endswith(filename, ".jl") || continue
	name = splitext(filename)[1]
    Literate.markdown(
        joinpath(@__DIR__, "..", "examples", filename),
        joinpath(@__DIR__, "src/examples");
        name = name,
        documenter=true,
    )
end

generated_examples = joinpath.("examples", filter(
    x -> endswith(x, ".md"),
    readdir(joinpath(@__DIR__, "src", "examples"))
    )
)

DocMeta.setdocmeta!(
    AbstractGPs,
    :DocTestSetup,
    :(using AbstractGPs, LinearAlgebra, Random);
    recursive=true,
)

makedocs(;
    modules=[AbstractGPs],
    format=Documenter.HTML(),
    repo="https://github.com/JuliaGaussianProcesses/AbstractGPs.jl/blob/{commit}{path}#L{line}",
    sitename="AbstractGPs.jl",
    pages = [
        "Home" => "index.md",
        "API" => "api.md",
        "Examples" => [
            generated_examples...
        ]
    ]
)

deploydocs(;
    repo="github.com/JuliaGaussianProcesses/AbstractGPs.jl.git",
    target="build",
    versions = ["dev" => "dev", "v#.#.#"],
)


text:
module SpecTools

using Parameters
using Distributions
using Interpolations
using SHA
using PhysicalConstants
using MetaGraphs
using Tullio
using CSV
using StructArrays

# Write your package code here.

include("constants.jl")
include("types.jl")

export Level, Transition, Levels, Transitions
export e, g, ν, I, quantum_numbers, features
export match_encoding, make_linear_transitions, upper_state_qnos, lower_state_qnos

include("graphs.jl")
include("graph_analysis.jl")

export LevelsGraph, BipartiteSG, ProjectedSG, offset, indices
export link_nodes_by_Δ!

include("lineshapes.jl")

export MultiGaussian, Gaussian, simulate_lineshape

include("signal.jl")
include("partition_function.jl")

export partition_function, read_qpart, InterpPartitionFunction

include("preprocess.jl")

export search_frequency, intersect_frequencies

include("parsers.jl")

export read_pgopher_linelist, read_pgopher_levels

end