text:
using DataStructures
using GRIB

"""
    FileIndex

A mutable store for indecies of a GRIB file

# Constructors
```julia
FileIndex(grib_path::String, index_keys::Array{String, 1})
```

# Fields
 - `allowed_protocol_version::VersionNumber` : Version number used when saving/hashing index files
 - `grib_path::String` : Path to the file the index belongs to
 - `index_path::String` : Path to the index cache file
 - `index_keys::Array{String, 1}` :
 - `offsets::Array` :
 - `header_values::OrderedDict{String, Array}` :
 - `filter_by_keys::Dict` :
"""
mutable struct FileIndex
    allowed_protocol_version::VersionNumber

    grib_path::String
    index_path::String

    index_keys::Array{String, 1}
    offsets::Array  # TODO: Specify offset type better
    message_lengths::Array{Int, 1}
    header_values::OrderedDict{String, Array}

    filter_by_keys::Dict

    FileIndex() = new(v"0.0.0")
end

function FileIndex(grib_path::String, index_keys::Array{String, 1})
    fileindex = FileIndex()
    fileindex.grib_path = grib_path
    fileindex.index_keys = index_keys

    if isfile(index_path(fileindex))
        from_indexfile!(fileindex)
    else
        from_gribfile!(fileindex)
        get_header_values!(fileindex)
    end

    return fileindex
end

Base.getindex(obj::FileIndex, key) = obj.header_values[key]

function index_path(index::FileIndex)
    index_keys_hash = hash(
        join([index.index_keys..., index.allowed_protocol_version])
    )
    index_keys_hash = string(index_keys_hash, base=16)

    return ".$(index.grib_path).$index_keys_hash.idx"
end

index_path!(index::FileIndex) = setfield!(index, :index_path, index_path(index))

function save_indexfile(index::FileIndex)
    throw("unimplemented")
end

function from_indexfile!(index::FileIndex)
    throw("unimplemented")
end

function from_gribfile!(index::FileIndex)
    offsets = OrderedDict()
    count_offsets = Dict{Int, Int}()

    index_keys = index.index_keys
    index_key_count = length(index_keys)
    index_key_symbols = Tuple(Symbol.(index_keys))
    HeaderTuple = NamedTuple{index_key_symbols}

    #  TODO: Time function to see if it is worth optimising
    #  based on gribfile.nmessages w/ known-length arrays
    #  more, or if I/O overhead too large
    GribFile(index.grib_path) do f
        message_lengths = Array{Int, 1}(undef, f.nmessages)
        for (nmessage, message) in enumerate(f)
            header_values = Array{Any}(undef, index_key_count)
            for (i, key) in enumerate(index_keys)
                value = haskey(message, key) ? message[key] : missing
                value = value isa Array ? Tuple(value) : value
                #  TODO: use dispatch to do this via GRIB
                value = key == "time" ? from_grib_date_time(message) : value

                header_values[i] = value
            end

            offset = Int(message["offset"])
            if offset in keys(count_offsets)
                count_offsets[offset] += 1
                offset_field = (offset, count_offsets[offset])
            else
                count_offsets[offset] = 0
                offset_field = offset
            end

            message_lengths[nmessage] = Int(message["totalLength"])
            offsets[HeaderTuple(header_values)] = offset_field
        end
        index.message_lengths = message_lengths
    end

    index.offsets = collect(pairs(offsets))
end

function get_header_values!(index::FileIndex)
    header_values = OrderedDict{String, Array}()
    for key in index.index_keys
        header_values[key] = unique([
            offset[1][Symbol(key)]
            for offset
            in index.offsets
        ])
    end

    index.header_values = header_values
end

function getone(index::FileIndex, item)
    values = index[item]

    if length(values) != 1
        throw("Expected 1 value for $(item), found $(length(values)) instead")
    end

    return values[1]
end

function first(index::FileIndex)
    GribFile(index.grib_path) do file
        first_offset = index.offsets[1][2][1]
        #  There is a discrepancy between how offsets are defined and used
        #  in cfgrib with the GRIB file seek method and in the Julia GRIB
        #  package, in Julia seek seeks through the messages themselves not
        #  the acutal offset values. Here we use the cumulative sum of the
        #  message lengths to work out which message an offset value is in.
        #
        #  TODO: This is probably due to me making a mistake, don't know
        #  enough about GRIB spec to figure out how this should be done, get
        #  ECMWF help with this
        message_length_cumsum = cumsum(index.message_lengths)
        offset_message_index = findfirst(message_length_cumsum .> first_offset) - 1
        seek(file, offset_message_index)
        return Message(file)
    end
end

function filter_offsets(index::FileIndex; query...)
    filtered_offsets = Array{Pair{Any,Any},1}()

    for (header_values, offset_values) in index.offsets
        for (k, v) in query
            if header_values[k] != v
                break
            else
                append!(filtered_offsets, [Pair(header_values, offset_values)])
                break
            end
        end
    end

    return filtered_offsets
end

function filter(index::FileIndex; query...)
    filtered_offsets = filter_offsets(index; query...)

    filtered_index = deepcopy(index)
    filtered_index.offsets = filtered_offsets
    filtered_index.filter_by_keys = query

    get_header_values!(filtered_index)

    return filtered_index
end

function filter!(index::FileIndex; query...)
    filtered_offsets = filter_offsets(index; query...)

    index.offsets = filtered_offsets
    index.filter_by_keys = query

    get_header_values!(index)
end


text:
"""
    struct ReinforceLearner{Tp<:AbstractPolicy}  <: AbstractModelFreeLearner
        π::Tp
        α::Float64
        γ::Float64
    end

See more details at Section (13.3) on Page 326 of the book *Sutton, Richard S., and Andrew G. Barto. Reinforcement learning: An introduction. MIT press, 2018.*
"""
struct ReinforceLearner{Tp<:AbstractPolicy}  <: AbstractModelFreeLearner
    π::Tp
    α::Float64
    γ::Float64
end

(learner::ReinforceLearner)(s) = learner.π(s)
(learner::ReinforceLearner)(s, ::Val{:dist}) = learner.π(s, Val(:dist))

function update!(learner::ReinforceLearner{<:LinearPolicy}, buffer::EpisodeSARDBuffer)
    π, α, γ = learner.π, learner.α, learner.γ
    if isfull(buffer)
        # need to allocate first, because `Reduction` do not support `Iterators.Reverse`
        reversed_G = collect(reverse_discounted_rewards(buffer.reward, γ))
        γᵗ = 1.
        for (G, Sₜ, Aₜ) in zip(Iterators.reverse(reversed_G), @view(buffer.state[1:end-1]), @view(buffer.action[1:end-1]))
            @views error = α * γᵗ * G * (π.features[Sₜ, Aₜ, :] .- sum(b -> π(Sₜ, b) * π.features[Sₜ, b, :],axes(π.features, 2)))
            update!(π, error)
            γᵗ *= γ
        end
    end
end

"""
    mutable struct ReinforceBaselineLearner{Tapp<:AbstractApproximator, Tp<:AbstractPolicy}  <: AbstractModelFreeLearner
        approximator::Tapp
        π::Tp
        αʷ::Float64
        αᶿ::Float64
        γ::Float64
    end

See more details at Section (13.4) on Page 330 of the book *Sutton, Richard S., and Andrew G. Barto. Reinforcement learning: An introduction. MIT press, 2018.*
"""
mutable struct ReinforceBaselineLearner{Tapp<:AbstractApproximator, Tp<:AbstractPolicy}  <: AbstractModelFreeLearner
    approximator::Tapp
    π::Tp
    αʷ::Float64
    αᶿ::Float64
    γ::Float64
end

(learner::ReinforceBaselineLearner)(s) = learner.π(s)
(learner::ReinforceBaselineLearner)(s, ::Val{:dist}) = learner.π(s, Val(:dist))

function update!(learner::ReinforceBaselineLearner{<:AbstractVApproximator, <:LinearPolicy}, buffer::EpisodeSARDBuffer)
    V, π, αᶿ, αʷ, γ = learner.approximator, learner.π, learner.αᶿ, learner.αʷ, learner.γ
    if isfull(buffer)
        # need to allocate first, because `Reduction` do not support `Iterators.Reverse`
        reversed_G = collect(reverse_discounted_rewards(buffer.reward, γ))
        γᵗ = 1.
        for (G, Sₜ, Aₜ) in zip(Iterators.reverse(reversed_G), @view(buffer.state[1:end-1]), @view(buffer.action[1:end-1]))
            δ = G - V(Sₜ)
            update!(V, Sₜ, αʷ * δ)
            @views error = αᶿ * γᵗ * δ * (π.features[Sₜ, Aₜ, :] .- sum(b -> π(Sₜ, b) * π.features[Sₜ, b, :],axes(π.features, 2)))
            update!(π, error)
            γᵗ *= γ
        end
    end
end

ext: jl


text:
julia> [RpcApi.SimpleOrganism(0x000000000002ed1b,:(function (o::Creature.Organism,)
        local var_323::Int16 = -30014
        function func_286(var_284::Int16=2081,var_285::Int64=9145930075523767031)
            return var_284
        end
        local var_280::Int64 = -2141542542016055773
        function func_273(var_272::Int8=-40)
            Creature.stepDown(o)
            var_272 = var_319 / var_319
            Creature.eatRight(o,Int(var_319))
            Creature.stepUp(o)
            Creature.stepDown(o)
            Creature.eatDown(o,Int(var_319))
            for i::Int8 = 1:div(var_319,_LOOP_STEPS_DIVIDER)
                Creature.stepUp(o)
                Creature.stepUp(o)
            end
            var_319 = var_319 / var_319
            return var_272
        end
        local var_243::Bool = false
        function func_232(var_230::Bool=false,var_231::Int16=-29748)
            local var_336::Int8 = 24
            for i::Int8 = 1:div(var_336,_LOOP_STEPS_DIVIDER)
            end
            Creature.stepLeft(o)
            Creature.stepUp(o)
            var_231 = var_231 * var_231
            return var_230
        end
        function func_189(var_188::Int16=2883)
            Creature.stepLeft(o)
            Creature.stepLeft(o)
            Creature.stepDown(o)
            Creature.stepUp(o)
            return var_188
        end
        function func_142(var_141::Int64=7558744495470982559)
            local var_335::Int16 = 29558
            var_335 = if haskey(o.mem,var_335)
                    o.mem[var_335]
                else
                    var_335
                end
            var_141 = var_141 + var_141
            return var_141
        end
        local var_124::Int64 = -1961703428302216313
        local var_123::Bool = true
        local var_120::Int16 = -4015
        local var_117::Int8 = 61
        local var_156::Int16 = 19308
        Creature.eatDown(o,Int(var_117))
        var_120 = var_120 - var_120
        Creature.eatRight(o,Int(var_117))
        var_280 = func_142(var_124)
        Creature.eatRight(o,Int(var_117))
        var_120 = var_323 * var_156
        var_124 = var_124 - var_124
        Creature.stepRight(o)
        var_117 = var_117 + var_117
        var_123 = var_123 | var_243
        Creature.eatUp(o,Int(var_117))
        Creature.eatDown(o,Int(var_117))
        var_280 = var_124 - var_124
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        Creature.eatLeft(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        var_243 = Bool(abs(var_123 - var_123))
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
            Creature.stepUp(o)
        end
        Creature.eatRight(o,Int(var_117))
        Creature.stepUp(o)
        var_120 = var_120 - var_156
        Creature.stepRight(o)
        Creature.eatRight(o,Int(var_117))
        Creature.stepRight(o)
        Creature.stepUp(o)
        Creature.eatRight(o,Int(var_117))
        var_120 = func_189(var_120)
        Creature.stepUp(o)
        var_156 = var_120 / var_323
        var_280 = var_280 / var_124
        var_156 = var_156 / var_120
        Creature.stepUp(o)
        var_156 = func_286(var_156)
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
            Creature.stepDown(o)
            Creature.stepDown(o)
        end
        Creature.eatUp(o,Int(var_117))
        var_120 = var_156 + var_120
        Creature.stepLeft(o)
        var_156 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_156
            end
        var_120 = if haskey(o.mem,var_156)
                o.mem[var_156]
            else
                var_120
            end
        o.mem[var_323] = var_156
        Creature.stepLeft(o)
        Creature.eatUp(o,Int(var_117))
        Creature.stepLeft(o)
        Creature.eatDown(o,Int(var_117))
        Creature.stepLeft(o)
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        Creature.stepDown(o)
        Creature.eatDown(o,Int(var_117))
        return true
    end),[110,300,95,0,1,1,1],2,3999,78,28678,0x00000111,Dict(0=>0,10070=>10070,-26920=>-26920,-4015=>19308,-29748=>-29748,23323=>23323,19308=>19308,-1631=>-1631,1=>1),[1920,19],86),RpcApi.SimpleOrganism(0x0000000000030dba,:(function (o:
:Creature.Organism,)
        function func_428(var_426::Int64=-527537012255454253,var_427::Int8=15)
            Creature.eatUp(o,Int(var_427))
            for i::Int8 = 1:div(var_427,_LOOP_STEPS_DIVIDER)
            end
            var_426 = var_426 + var_426
            if var_427 != var_427
                Creature.stepUp(o)
            end
            if var_427 >= var_427
            end
            return var_426
        end
        local var_421::Int8 = -26
        function func_356(var_354::Int16=15113,var_355::Int16=-12053)
            local var_437::Int8 = -123
            o.mem[var_354] = var_354
            return var_354
        end
        local var_280::Int64 = -2141542542016055773
        function func_273(var_272::Int8=-40)
            Creature.eatDown(o,Int(var_272))
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepRight(o)
            end
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                local var_436::ASCIIString = "1UtjzI3C"
            end
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
            end
            return var_272
        end
        function func_264(var_263::Int8=-125)
            Creature.stepUp(o)
            for i::Int8 = 1:div(var_263,_LOOP_STEPS_DIVIDER)
            end
            Creature.eatLeft(o,Int(var_263))
            for i::Int8 = 1:div(var_263,_LOOP_STEPS_DIVIDER)
                Creature.stepDown(o)
                Creature.stepUp(o)
                Creature.stepRight(o)
            end
            var_263 = var_263 / var_263
            Creature.stepLeft(o)
            Creature.eatLeft(o,Int(var_263))
            Creature.stepDown(o)
            Creature.stepUp(o)
            Creature.stepUp(o)
            return var_263
        end
        function func_189(var_188::Int16=2883)
            Creature.stepRight(o)
            return var_188
        end
        local var_124::Int64 = -1961703428302216313
        local var_117::Int8 = 61
        Creature.eatLeft(o,Int(var_117))
        if var_117 >= var_117
            Creature.stepUp(o)
        end
        Creature.eatUp(o,Int(var_117))
        var_124 = var_280 - var_124
        Creature.eatLeft(o,Int(var_117))
        Creature.eatDown(o,Int(var_117))
        Creature.eatDown(o,Int(var_117))
        Creature.eatRight(o,Int(var_117))
        Creature.eatUp(o,Int(var_117))
        Creature.eatDown(o,Int(var_117))
        var_117 = var_117 + var_117
        var_124 = var_124 + var_124
        Creature.eatRight(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        var_120 = var_120 / var_120
        Creature.stepLeft(o)
        Creature.eatUp(o,Int(var_117))
        o.mem[var_120] = var_120
        Creature.stepRight(o)
        Creature.eatDown(o,Int(var_117))
        if var_120 === var_120
            Creature.stepDown(o)
        end
        Creature.stepRight(o)
        var_117 = var_117 * var_117
        var_120 = func_189(var_120)
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        if var_120 < var_120
            local var_434::Int8 = 28
            Creature.stepDown(o)
        end
        var_124 = var_124 - var_124
        Creature.stepRight(o)
        Creature.eatRight(o,Int(var_117))
        if var_120 != var_156
            Creature.stepLeft(o)
        end
        Creature.eatLeft(o,Int(var_117))
        var_124 = var_280 * var_124
        Creature.stepDown(o)
        var_280 = var_124 / var_124
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        var_124 = var_124 + var_124
        var_123 = var_123 & var_123
        Creature.stepLeft(o)
        Creature.stepLeft(o)
        Creature.eatRight(o,Int(var_117))
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
            local var_431::ASCIIString = "QIjvzEFK"
            Creature.stepUp(o)
            Creature.stepLeft(o)
        end
        o.mem[var_120] = var_120
        var_124 = var_280 * var_124
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        Creature.stepUp(o)
        Creature.stepLeft(o)
        Creature.eatLeft(o,Int(var_117))
        var_117 = var_117 * var_117
        return true
    end),[110,300,95,0,1,1,1],49,2229,32,19235,0x00000327,Dict(0=>0,10070=>10070,-26920=>-26920,-4015=>-4015,23323=>23323,19308=>19308,-1631=>-1631,1=>1),[400,1],94),RpcApi.SimpleOrganism(0x00000000000301db,:(function (o::Creature.Organi
sm,)
        function func_345(var_343::Int64=8598073464645878164,var_344::Int64=-2115587437940986231)
            Creature.stepRight(o)
            return var_343
        end
        local var_323::Int16 = -30014
        local var_280::Int64 = -2141542542016055773
        function func_273(var_272::Int8=-40)
            local var_352::Int8 = -34
            local var_342::Int64 = 297932496378167337
            Creature.eatUp(o,Int(var_272))
            Creature.eatLeft(o,Int(var_272))
            var_352 = var_272 - var_272
            var_272 = var_272 + var_272
            Creature.eatDown(o,Int(var_272))
            var_272 = var_272 / var_272
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepUp(o)
            end
            Creature.stepLeft(o)
            Creature.stepRight(o)
            if var_342 != var_342
                Creature.stepDown(o)
            end
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepLeft(o)
            end
            Creature.stepDown(o)
            Creature.stepDown(o)
            Creature.stepLeft(o)
            Creature.eatRight(o,Int(var_272))
            Creature.stepRight(o)
            if var_272 != var_272
                local var_348::ASCIIString = "3rwwRKwy"
            end
            return var_272
        end
        local var_243::Bool = false
        function func_232(var_230::Bool=false,var_231::Int16=-29748)
            local var_349::Bool = true
            Creature.stepDown(o)
            Creature.stepDown(o)
            Creature.stepDown(o)
            var_349 = var_349 & var_349
            var_231 = var_231 / var_231
            Creature.stepLeft(o)
            var_231 = var_231 + var_231
            Creature.stepDown(o)
            return var_230
        end
        function func_142(var_141::Int64=7558744495470982559)
            return var_141
        end
        local var_124::Int64 = -1961703428302216313
        local var_123::Bool = true
        local var_120::Int16 = -4015
        local var_117::Int8 = 61
        local var_156::Int16 = 19308
        if var_124 > var_124
        end
        var_120 = var_120 - var_120
        Creature.eatRight(o,Int(var_117))
        var_280 = func_142(var_124)
        var_323 = if haskey(o.mem,var_323)
                o.mem[var_323]
            else
                var_323
            end
        Creature.eatDown(o,Int(var_117))
        var_117 = func_273(var_117)
        var_117 = var_117 + var_117
        Creature.eatDown(o,Int(var_117))
        var_124 = var_124 + var_124
        var_280 = var_124 - var_124
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        Creature.eatLeft(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        var_123 = func_232(var_243,var_156)
        var_280 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        if var_117 != var_117
        end
        var_117 = var_117 * var_117
        Creature.stepUp(o)
        var_280 = Int(Creature.getEnergy(o,Int(var_156),Int(var_120)))
        o.mem[var_120] = var_323
        Creature.stepRight(o)
        if var_123 !== var_243
            Creature.stepDown(o)
        end
        var_337 = var_337[1:if length(var_337) > length(var_337)
                        0
                    else
                        length(var_337) - length(var_337)
                    end]
        var_123 = var_123 | var_243
        Creature.stepUp(o)
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        Creature.eatLeft(o,Int(var_117))
        Creature.stepUp(o)
        var_156 = func_286(var_156)
        o.mem[var_156] = var_120
        var_120 = var_156 + var_120
        var_120 = if haskey(o.mem,var_156)
                o.mem[var_156]
            else
                var_120
            end
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
        end
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
        end
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_156)))
        var_117 = var_117 / var_117
        var_117 = var_117 / var_117
        Creature.stepUp(o)
        var_117 = var_117 / var_117
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        var_280 = var_124 * var_124
        var_123 = var_243 | var_123
        Creature.eatDown(o,Int(var_117))
        return true
    end),[110,300,95,0,1,1,1],78,4775,18,18093,0x00000222,Dict(0=>-30014,10070=>10070,-26920=>-26920,-4015=>19308,-29748=>-29748,23323=>23323,19308=>19308,-1631=>-1631,1=>1),[1919,959],91),RpcApi.SimpleOrganism(0x0000000000030cdb,:(funct
ion (o::Creature.Organism,)
        function func_345(var_343::Int64=8598073464645878164,var_344::Int64=-2115587437940986231)
            if var_344 >= var_343
                Creature.stepUp(o)
                Creature.stepDown(o)
            end
            var_344 = var_343 / var_343
            return var_343
        end
        local var_337::ASCIIString = "7A9IyD4t"
        function func_286(var_284::Int16=2081,var_285::Int64=9145930075523767031)
            var_285 = var_285 - var_285
            if var_284 != var_284
            end
            var_284 = if haskey(o.mem,var_284)
                    o.mem[var_284]
                else
                    var_284
                end
            o.mem[var_284] = var_284
            var_285 = Int(Creature.getEnergy(o,Int(var_284),Int(var_284)))
            return var_284
        end
        local var_280::Int64 = -2141542542016055773
        function func_273(var_272::Int8=-40)
            Creature.stepRight(o)
            Creature.eatLeft(o,Int(var_272))
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepUp(o)
            end
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepRight(o)
            end
            Creature.stepDown(o)
            Creature.eatDown(o,Int(var_272))
            Creature.stepDown(o)
            var_342 = var_342 * var_342
            var_272 = var_272 / var_272
            Creature.stepRight(o)
            var_272 = var_319 + var_272
            return var_272
        end
        local var_243::Bool = false
        function func_232(var_230::Bool=false,var_231::Int16=-29748)
            local var_354::Int16 = -27684
            local var_338::Int8 = 56
            local var_349::Int16 = -10254
            var_231 = if haskey(o.mem,var_231)
                    o.mem[var_231]
                else
                    var_231
                end
            Creature.eatLeft(o,Int(var_338))
            Creature.stepLeft(o)
            var_230 = var_230 | var_230
            var_338 = var_338 / var_338
            var_231 = if haskey(o.mem,var_231)
                    o.mem[var_231]
                else
                    var_231
                end
            for i::Int8 = 1:div(var_338,_LOOP_STEPS_DIVIDER)
            end
            for i::Int8 = 1:div(var_338,_LOOP_STEPS_DIVIDER)
            end
            Creature.stepLeft(o)
            return var_230
        end
        function func_189(var_188::Int16=2883)
            local var_352::Int8 = 12
            for i::Int8 = 1:div(var_352,_LOOP_STEPS_DIVIDER)
            end
            o.mem[var_188] = var_188
            if var_352 == var_352
            end
            var_188 = var_188 - var_188
            return var_188
        end
        function func_142(var_141::Int64=7558744495470982559)
            var_141 = var_141 / var_141
            Creature.stepLeft(o)
            return var_141
        end
        local var_124::Int64 = -1961703428302216313
        local var_123::Bool = true
        local var_120::Int16 = -4015
        local var_117::Int8 = 61
        local var_156::Int16 = 19308
        function func_348(var_347::Bool=false)
            local var_353::Int64 = 7518043858132478339
            Creature.stepRight(o)
            return var_347
        end
        var_120 = var_120 - var_120
        Creature.eatRight(o,Int(var_117))
        var_280 = func_142(var_124)
        Creature.eatRight(o,Int(var_117))
        Creature.eatDown(o,Int(var_117))
        var_117 = var_117 + var_117
        var_123 = var_123 | var_243
        Creature.eatUp(o,Int(var_117))
        var_124 = var_124 + var_124
        var_280 = var_124 - var_124
        Creature.eatLeft(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        var_243 = var_123 | var_123
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
            Creature.stepLeft(o)
            Creature.stepUp(o)
        end
        Creature.eatRight(o,Int(var_117))
        Creature.stepUp(o)
        var_120 = var_120 - var_156
        Creature.eatDown(o,Int(var_117))
        Creature.stepUp(o)
        Creature.eatRight(o,Int(var_117))
        var_120 = func_189(var_120)
        Creature.stepUp(o)
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        var_280 = var_280 / var_124
        Creature.stepUp(o)
        var_156 = func_286(var_156)
        Creature.eatUp(o,Int(var_117))
        var_120 = var_156 + var_120
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
            local var_351::ASCIIString = "FMCNFGI7"
        end
        var_243 = func_232(var_123)
        Creature.eatDown(o,Int(var_117))
        var_120 = if haskey(o.mem,var_156)
                o.mem[var_156]
            else
                var_120
            end
        o.mem[var_323] = var_156
        Creature.stepLeft(o)
        Creature.stepRight(o)
        Creature.eatUp(o,Int(var_117))
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
        end
        var_117 = var_117 / var_117
        o.mem[var_120] = var_120
        Creature.stepLeft(o)
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        var_123 = var_243 | var_123
        Creature.eatDown(o,Int(var_117))
        return true
    end),[110,300,95,0,1,1,1],26,2442,57,17279,0x000001c3,Dict(0=>0,10070=>10070,-26920=>-26920,-4015=>19308,-29748=>-29748,23323=>23323,19308=>19308,-1631=>-1631,1=>1),[1465,960],104),RpcApi.SimpleOrganism(0x000000000002f393,:(function
(o::Creature.Organism,)
        function func_345(var_343::Int64=8598073464645878164,var_344::Int64=-2115587437940986231)
            if var_344 >= var_343
                Creature.stepUp(o)
                Creature.stepDown(o)
            end
            var_344 = var_343 / var_343
            return var_343
        end
        local var_337::ASCIIString = "7A9IyD4t"
        function func_286(var_284::Int16=2081,var_285::Int64=9145930075523767031)
            var_285 = var_285 - var_285
            if var_284 != var_284
            end
            var_284 = if haskey(o.mem,var_284)
                    o.mem[var_284]
                else
                    var_284
                end
            o.mem[var_284] = var_284
            var_285 = Int(Creature.getEnergy(o,Int(var_284),Int(var_284)))
            return var_284
        end
        local var_280::Int64 = -2141542542016055773
        function func_273(var_272::Int8=-40)
            Creature.stepRight(o)
            Creature.eatLeft(o,Int(var_272))
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepUp(o)
            end
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepRight(o)
            end
            Creature.stepDown(o)
            Creature.eatDown(o,Int(var_272))
            Creature.stepDown(o)
            var_342 = var_342 * var_342
            var_272 = var_272 / var_272
            Creature.stepUp(o)
            Creature.stepRight(o)
            var_272 = var_319 + var_272
            return var_272
        end
        local var_243::Bool = false
        function func_232(var_230::Bool=false,var_231::Int16=-29748)
            local var_338::Int8 = 56
            local var_349::Int16 = -10254
            var_231 = if haskey(o.mem,var_231)
                    o.mem[var_231]
                else
                    var_231
                end
            Creature.eatLeft(o,Int(var_338))
            Creature.stepLeft(o)
            var_230 = var_230 | var_230
            var_338 = var_338 / var_338
            var_231 = if haskey(o.mem,var_231)
                    o.mem[var_231]
                else
                    var_231
                end
            for i::Int8 = 1:div(var_338,_LOOP_STEPS_DIVIDER)
            end
            for i::Int8 = 1:div(var_338,_LOOP_STEPS_DIVIDER)
            end
            var_338 = var_338 * var_338
            return var_230
        end
        function func_189(var_188::Int16=2883)
            local var_352::Int8 = 12
            var_188 = var_188 * var_188
            for i::Int8 = 1:div(var_352,_LOOP_STEPS_DIVIDER)
            end
            o.mem[var_188] = var_188
            if var_352 == var_352
            end
            var_188 = var_188 - var_188
            return var_188
        end
        function func_142(var_141::Int64=7558744495470982559)
            Creature.stepDown(o)
            var_141 = var_141 / var_141
            return var_141
        end
        local var_124::Int64 = -1961703428302216313
        local var_123::Bool = true
        local var_120::Int16 = -4015
        local var_117::Int8 = 61
        local var_156::Int16 = 19308
        function func_348(var_347::Bool=false)
            Creature.stepRight(o)
            return var_347
        end
        var_120 = var_120 - var_120
        Creature.eatRight(o,Int(var_117))
        var_280 = func_142(var_124)
        Creature.eatRight(o,Int(var_117))
        Creature.eatDown(o,Int(var_117))
        var_117 = var_117 + var_117
        var_123 = var_123 | var_243
        Creature.eatUp(o,Int(var_117))
        var_124 = var_124 + var_124
        var_280 = var_124 - var_124
        Creature.eatLeft(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        var_243 = var_123 | var_123
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
            Creature.stepLeft(o)
            Creature.stepUp(o)
        end
        Creature.eatRight(o,Int(var_117))
        Creature.stepUp(o)
        var_120 = var_120 - var_156
        Creature.eatDown(o,Int(var_117))
        Creature.stepUp(o)
        Creature.eatRight(o,Int(var_117))
        var_120 = func_189(var_120)
        Creature.stepUp(o)
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        var_280 = var_280 / var_124
        Creature.stepUp(o)
        var_156 = func_286(var_156)
        Creature.eatUp(o,Int(var_117))
        var_120 = var_156 + var_120
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
            local var_351::ASCIIString = "FMCNFGI7"
        end
        var_243 = func_232(var_123)
        Creature.eatDown(o,Int(var_117))
        var_120 = if haskey(o.mem,var_156)
                o.mem[var_156]
            else
                var_120
            end
        o.mem[var_323] = var_156
        Creature.stepLeft(o)
        Creature.stepRight(o)
        Creature.eatUp(o,Int(var_117))
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
        end
        var_117 = var_117 / var_117
        o.mem[var_120] = var_120
        Creature.stepLeft(o)
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        var_123 = var_243 | var_123
        Creature.eatDown(o,Int(var_117))
        return true
    end),[110,300,95,0,1,1,1],26,2442,57,17120,0x000001bc,Dict(0=>0,10070=>10070,-26920=>-26920,-4015=>19308,-29748=>-29748,23323=>23323,19308=>19308,-1631=>-1631,1=>1),[1920,960],104),RpcApi.SimpleOrganism(0x0000000000030c89,:(function
(o::Creature.Organism,)
        function func_345(var_343::Int64=8598073464645878164,var_344::Int64=-2115587437940986231)
            Creature.stepRight(o)
            return var_343
        end
        local var_323::Int16 = -30014
        local var_280::Int64 = -2141542542016055773
        function func_273(var_272::Int8=-40)
            local var_352::Int8 = -34
            local var_342::Int64 = 297932496378167337
            Creature.eatUp(o,Int(var_272))
            Creature.eatUp(o,Int(var_272))
            var_352 = var_272 - var_272
            var_272 = var_272 + var_272
            Creature.eatDown(o,Int(var_272))
            var_272 = var_272 / var_272
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepUp(o)
            end
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepRight(o)
            end
            Creature.stepLeft(o)
            Creature.stepRight(o)
            if var_342 != var_342
                Creature.stepDown(o)
            end
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepLeft(o)
            end
            Creature.stepDown(o)
            Creature.stepDown(o)
            Creature.stepLeft(o)
            if var_272 >= var_352
            end
            Creature.stepRight(o)
            if var_272 != var_272
                local var_348::ASCIIString = "3rwwRKwy"
            end
            return var_272
        end
        local var_243::Bool = false
        function func_232(var_230::Bool=false,var_231::Int16=-29748)
            local var_349::Bool = true
            Creature.stepDown(o)
            var_349 = var_349 & var_349
            var_231 = var_231 / var_231
            Creature.stepLeft(o)
            Creature.stepUp(o)
            Creature.stepLeft(o)
            Creature.stepDown(o)
            return var_230
        end
        function func_142(var_141::Int64=7558744495470982559)
            return var_141
        end
        local var_124::Int64 = -1961703428302216313
        local var_123::Bool = true
        local var_120::Int16 = -4015
        local var_117::Int8 = 61
        local var_156::Int16 = 19308
        if var_124 > var_124
        end
        var_120 = var_120 - var_120
        Creature.eatRight(o,Int(var_117))
        var_280 = func_142(var_124)
        var_323 = if haskey(o.mem,var_323)
                o.mem[var_323]
            else
                var_323
            end
        Creature.eatDown(o,Int(var_117))
        var_117 = func_273(var_117)
        var_117 = var_117 + var_117
        Creature.eatDown(o,Int(var_117))
        var_124 = var_124 + var_124
        var_280 = var_124 - var_124
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        Creature.eatLeft(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        var_123 = func_232(var_243,var_156)
        var_280 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        if var_117 != var_117
        end
        var_117 = var_117 * var_117
        Creature.stepUp(o)
        var_280 = Int(Creature.getEnergy(o,Int(var_156),Int(var_120)))
        o.mem[var_120] = var_323
        Creature.stepRight(o)
        if var_123 !== var_243
            Creature.stepDown(o)
        end
        var_337 = var_337[1:if length(var_337) > length(var_337)
                        0
                    else
                        length(var_337) - length(var_337)
                    end]
        var_123 = var_123 | var_243
        Creature.stepUp(o)
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        Creature.eatLeft(o,Int(var_117))
        Creature.stepUp(o)
        var_156 = func_286(var_156)
        o.mem[var_156] = var_120
        var_120 = var_156 + var_120
        var_120 = if haskey(o.mem,var_156)
                o.mem[var_156]
            else
                var_120
            end
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
        end
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
        end
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_156)))
        var_117 = var_117 / var_117
        var_117 = var_117 / var_117
        Creature.stepUp(o)
        var_117 = var_117 / var_117
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        var_280 = var_124 * var_124
        var_123 = var_243 | var_123
        return true
    end),[110,300,95,0,1,1,1],2,4775,18,15210,0x00000231,Dict(0=>-30014,10070=>10070,-26920=>-26920,-4015=>19308,-29748=>-29748,23323=>23323,19308=>19308,-1631=>-1631,1=>1),[1920,287],91),RpcApi.SimpleOrganism(0x0000000000030dc6,:(functi
on (o::Creature.Organism,)
        function func_356(var_354::Int16=15113,var_355::Int16=-12053)
            Creature.stepLeft(o)
            return var_354
        end
        function func_286(var_284::Int16=2081,var_285::Int64=9145930075523767031)
            var_285 = Int(Creature.getEnergy(o,Int(var_284),Int(var_284)))
            var_284 = if haskey(o.mem,var_284)
                    o.mem[var_284]
                else
                    var_284
                end
            var_284 = if haskey(o.mem,var_284)
                    o.mem[var_284]
                else
                    var_284
                end
            var_284 = var_284 / var_284
            return var_284
        end
        local var_280::Int64 = -2141542542016055773
        function func_273(var_272::Int8=-40)
            local var_339::ASCIIString = "cWRckMTc"
            Creature.eatLeft(o,Int(var_272))
            if var_272 > var_272
            end
            var_272 = var_272 - var_272
            var_339 = var_339 * var_339
            var_339 = var_339 * var_339
            Creature.eatRight(o,Int(var_272))
            return var_272
        end
        function func_264(var_263::Int8=-125)
            local var_404::Int64 = 9136790744435576863
            Creature.eatUp(o,Int(var_263))
            Creature.stepUp(o)
            for i::Int8 = 1:div(var_263,_LOOP_STEPS_DIVIDER)
            end
            Creature.eatRight(o,Int(var_263))
            Creature.stepDown(o)
            Creature.stepRight(o)
            for i::Int8 = 1:div(var_263,_LOOP_STEPS_DIVIDER)
            end
            return var_263
        end
        function func_232(var_230::Bool=false,var_231::Int16=-29748)
            local var_405::Int8 = 4
            Creature.eatRight(o,Int(var_405))
            return var_230
        end
        function func_189(var_188::Int16=2883)
            return var_188
        end
        function func_142(var_141::Int64=7558744495470982559)
            var_141 = var_141 / var_141
            return var_141
        end
        local var_124::Int64 = -1961703428302216313
        local var_120::Int16 = -4015
        local var_117::Int8 = 61
        local var_156::Int16 = 19308
        Creature.eatLeft(o,Int(var_117))
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        Creature.eatUp(o,Int(var_117))
        Creature.eatRight(o,Int(var_117))
        var_124 = var_124 - var_124
        Creature.eatDown(o,Int(var_117))
        Creature.eatRight(o,Int(var_117))
        var_124 = var_124 - var_124
        Creature.eatUp(o,Int(var_117))
        var_117 = var_117 + var_117
        var_124 = Int(Creature.getEnergy(o,Int(var_156),Int(var_156)))
        Creature.stepLeft(o)
        Creature.eatLeft(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        Creature.eatUp(o,Int(var_117))
        var_243 = var_123 | var_123
        if var_123 != var_123
            Creature.stepUp(o)
        end
        Creature.eatUp(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        var_124 = Int(Creature.getEnergy(o,Int(var_156),Int(var_120)))
        Creature.eatDown(o,Int(var_117))
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        Creature.stepRight(o)
        Creature.stepDown(o)
        if var_120 < var_120
            Creature.stepUp(o)
        end
        Creature.stepRight(o)
        Creature.eatRight(o,Int(var_117))
        Creature.eatRight(o,Int(var_117))
        Creature.eatDown(o,Int(var_117))
        if var_123 > var_123
            Creature.stepRight(o)
        end
        var_123 = Bool(abs(var_123 - var_123))
        Creature.eatUp(o,Int(var_117))
        var_124 = var_280 / var_124
        Creature.eatLeft(o,Int(var_117))
        Creature.stepLeft(o)
        Creature.eatUp(o,Int(var_117))
        var_123 = var_123 & var_123
        Creature.stepLeft(o)
        Creature.eatRight(o,Int(var_117))
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        Creature.eatDown(o,Int(var_117))
        var_124 = var_280 * var_124
        var_124 = var_124 + var_124
        Creature.stepUp(o)
        Creature.stepDown(o)
        Creature.stepDown(o)
        Creature.stepLeft(o)
        Creature.eatUp(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        return true
    end),[110,300,95,0,1,1,1],53,1026,6,13787,0x000000cf,Dict(0=>0,10070=>10070,-26920=>-26920,-4015=>-4015,23323=>23323,19308=>19308,-1631=>-1631,1=>1),[1,854],87),RpcApi.SimpleOrganism(0x0000000000030d7c,:(function (o::Creature.Organis
m,)
        function func_428(var_426::Int64=-527537012255454253,var_427::Int8=15)
            Creature.stepRight(o)
            var_427 = var_427 + var_427
            Creature.stepUp(o)
            var_427 = var_427 / var_427
            Creature.stepDown(o)
            Creature.eatRight(o,Int(var_427))
            for i::Int8 = 1:div(var_427,_LOOP_STEPS_DIVIDER)
            end
            return var_426
        end
        local var_421::Int8 = -26
        function func_356(var_354::Int16=15113,var_355::Int16=-12053)
            var_355 = var_354 * var_355
            Creature.stepLeft(o)
            Creature.stepUp(o)
            return var_354
        end
        local var_280::Int64 = -2141542542016055773
        function func_273(var_272::Int8=-40)
            return var_272
        end
        function func_189(var_188::Int16=2883)
            Creature.stepLeft(o)
            o.mem[var_188] = var_188
            return var_188
        end
        local var_124::Int64 = -1961703428302216313
        local var_117::Int8 = 61
        Creature.eatLeft(o,Int(var_117))
        if var_117 >= var_117
            Creature.stepRight(o)
        end
        Creature.eatUp(o,Int(var_117))
        var_124 = var_280 - var_124
        Creature.eatLeft(o,Int(var_117))
        Creature.eatDown(o,Int(var_117))
        Creature.eatDown(o,Int(var_117))
        Creature.eatRight(o,Int(var_117))
        Creature.eatUp(o,Int(var_117))
        var_117 = var_421 * var_117
        Creature.eatDown(o,Int(var_117))
        var_117 = var_117 + var_117
        var_124 = var_124 + var_124
        Creature.eatRight(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        var_120 = var_120 / var_120
        Creature.stepLeft(o)
        Creature.eatUp(o,Int(var_117))
        o.mem[var_120] = var_120
        Creature.stepRight(o)
        Creature.eatDown(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        if var_123 < var_123
        end
        Creature.stepRight(o)
        var_117 = var_117 * var_117
        var_120 = func_189(var_120)
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        if var_120 < var_120
            Creature.stepLeft(o)
            Creature.stepUp(o)
            Creature.stepDown(o)
        end
        var_124 = var_124 - var_124
        Creature.stepRight(o)
        Creature.eatRight(o,Int(var_117))
        Creature.stepDown(o)
        if var_120 != var_156
            Creature.stepRight(o)
        end
        Creature.eatLeft(o,Int(var_117))
        var_124 = var_280 * var_124
        Creature.eatUp(o,Int(var_117))
        o.mem[var_120] = var_120
        var_280 = var_124 / var_124
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        var_120 = var_120 / var_120
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        var_124 = var_124 + var_124
        var_123 = var_123 & var_123
        Creature.stepLeft(o)
        Creature.stepLeft(o)
        Creature.eatRight(o,Int(var_117))
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
            local var_439::ASCIIString = "XXwnn22Z"
            Creature.stepUp(o)
            Creature.stepUp(o)
        end
        o.mem[var_120] = var_120
        var_124 = var_280 * var_124
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        var_124 = func_428(var_124,var_117)
        Creature.stepLeft(o)
        Creature.eatLeft(o,Int(var_117))
        var_117 = var_117 * var_117
        return true
    end),[110,300,95,0,1,1,1],92,2229,32,13521,0x00000351,Dict(0=>0,10070=>10070,-26920=>-26920,-4015=>-4015,23323=>23323,19308=>19308,-1631=>-1631,1=>1),[890,3],82),RpcApi.SimpleOrganism(0x0000000000030d6e,:(function (o::Creature.Organi
sm,)
        function func_364(var_362::Int8=-25,var_363::Bool=false)
            local var_372::ASCIIString = "SkWrEHQg"
            local var_371::Int8 = 105
            return var_362
        end
        local var_349::Int8 = -22
        function func_345(var_343::Int64=8598073464645878164,var_344::Int64=-2115587437940986231)
            return var_343
        end
        local var_337::ASCIIString = "7A9IyD4t"
        local var_323::Int16 = -30014
        function func_286(var_284::Int16=2081,var_285::Int64=9145930075523767031)
            return var_284
        end
        local var_280::Int64 = -2141542542016055773
        function func_273(var_272::Int8=-40)
            Creature.stepRight(o)
            for i::Int8 = 1:div(var_352,_LOOP_STEPS_DIVIDER)
                Creature.stepLeft(o)
                Creature.stepDown(o)
            end
            var_352 = var_272 + var_272
            Creature.eatDown(o,Int(var_272))
            Creature.stepDown(o)
            Creature.stepDown(o)
            Creature.stepUp(o)
            Creature.eatRight(o,Int(var_352))
            return var_272
        end
        local var_243::Bool = false
        function func_232(var_230::Bool=false,var_231::Int16=-29748)
            o.mem[var_231] = var_231
            Creature.stepDown(o)
            Creature.stepRight(o)
            return var_230
        end
        function func_142(var_141::Int64=7558744495470982559)
            local var_375::Int8 = 43
            return var_141
        end
        local var_124::Int64 = -1961703428302216313
        local var_120::Int16 = -4015
        local var_117::Int8 = 61
        local var_156::Int16 = 19308
        Creature.eatRight(o,Int(var_117))
        var_124 = Int(Creature.getEnergy(o,Int(var_156),Int(var_156)))
        Creature.eatDown(o,Int(var_117))
        var_117 = var_117 + var_117
        Creature.eatRight(o,Int(var_117))
        Creature.eatUp(o,Int(var_117))
        var_124 = var_124 - var_124
        var_337 = var_337[1:if length(var_337) > length(var_337)
                        0
                    else
                        length(var_337) - length(var_337)
                    end]
        var_280 = var_124 - var_124
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        Creature.eatLeft(o,Int(var_117))
        if var_337 < var_337
            Creature.stepDown(o)
        end
        Creature.stepUp(o)
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
            Creature.stepDown(o)
            Creature.stepUp(o)
            Creature.stepRight(o)
        end
        var_120 = var_156 * var_156
        Creature.stepUp(o)
        Creature.stepRight(o)
        for i::Int8 = 1:div(var_349,_LOOP_STEPS_DIVIDER)
        end
        var_156 = var_120 / var_323
        var_120 = func_189(var_120)
        Creature.stepUp(o)
        var_156 = var_156 + var_120
        Creature.stepDown(o)
        var_280 = var_280 / var_124
        for i::Int8 = 1:div(var_349,_LOOP_STEPS_DIVIDER)
            Creature.stepUp(o)
        end
        Creature.stepUp(o)
        var_156 = func_286(var_156)
        Creature.stepDown(o)
        Creature.eatLeft(o,Int(var_117))
        var_120 = var_156 + var_120
        Creature.stepLeft(o)
        Creature.stepLeft(o)
        Creature.eatDown(o,Int(var_117))
        var_156 = if haskey(o.mem,var_323)
                o.mem[var_323]
            else
                var_156
            end
        Creature.stepLeft(o)
        var_337 = var_337[1:if length(var_337) > length(var_337) > 0
                        0
                    else
                        div(length(var_337),length(var_337))
                    end]
        var_120 = if haskey(o.mem,var_156)
                o.mem[var_156]
            else
                var_120
            end
        Creature.stepLeft(o)
        var_337 = var_337[1:if length(var_337) > length(var_337)
                        0
                    else
                        length(var_337) - length(var_337)
                    end]
        var_123 = var_243 | var_123
        return true
    end),[110,300,95,0,1,1,1],83,1089,33,13432,0x00000368,Dict(0=>0,10070=>10070,-26920=>-26920,-4015=>19308,-29748=>-29748,23323=>23323,19308=>19308,-1631=>-1631,1=>1),[270,1],76),RpcApi.SimpleOrganism(0x0000000000030deb,:(function (o::
Creature.Organism,)
        function func_345(var_343::Int64=8598073464645878164,var_344::Int64=-2115587437940986231)
            Creature.stepRight(o)
            return var_343
        end
        local var_323::Int16 = -30014
        local var_280::Int64 = -2141542542016055773
        function func_273(var_272::Int8=-40)
            local var_352::Int8 = -34
            local var_342::Int64 = 297932496378167337
            Creature.eatUp(o,Int(var_272))
            Creature.eatUp(o,Int(var_272))
            var_352 = var_272 - var_272
            var_272 = var_272 + var_272
            Creature.eatDown(o,Int(var_272))
            var_272 = var_272 / var_272
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepUp(o)
            end
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepRight(o)
            end
            Creature.stepLeft(o)
            Creature.stepRight(o)
            if var_342 != var_342
                Creature.stepDown(o)
            end
            for i::Int8 = 1:div(var_272,_LOOP_STEPS_DIVIDER)
                Creature.stepLeft(o)
            end
            Creature.stepDown(o)
            Creature.stepDown(o)
            Creature.stepLeft(o)
            if var_272 >= var_352
            end
            Creature.stepRight(o)
            if var_272 != var_272
                local var_348::ASCIIString = "3rwwRKwy"
            end
            return var_272
        end
        local var_243::Bool = false
        function func_232(var_230::Bool=false,var_231::Int16=-29748)
            local var_349::Bool = true
            Creature.stepDown(o)
            var_349 = var_349 & var_349
            var_231 = var_231 / var_231
            Creature.stepLeft(o)
            Creature.stepUp(o)
            Creature.stepLeft(o)
            Creature.stepDown(o)
            return var_230
        end
        function func_142(var_141::Int64=7558744495470982559)
            return var_141
        end
        local var_124::Int64 = -1961703428302216313
        local var_123::Bool = true
        local var_120::Int16 = -4015
        local var_117::Int8 = 61
        local var_156::Int16 = 19308
        if var_124 > var_124
        end
        var_120 = var_120 - var_120
        Creature.eatRight(o,Int(var_117))
        var_280 = func_142(var_124)
        var_323 = if haskey(o.mem,var_323)
                o.mem[var_323]
            else
                var_323
            end
        Creature.eatDown(o,Int(var_117))
        var_117 = func_273(var_117)
        var_117 = var_117 + var_117
        Creature.eatDown(o,Int(var_117))
        var_124 = var_124 + var_124
        var_280 = var_124 - var_124
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        Creature.eatLeft(o,Int(var_117))
        Creature.eatLeft(o,Int(var_117))
        var_123 = func_232(var_243,var_156)
        var_280 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        if var_117 != var_117
        end
        var_117 = var_117 * var_117
        Creature.stepUp(o)
        var_280 = Int(Creature.getEnergy(o,Int(var_156),Int(var_120)))
        o.mem[var_120] = var_323
        Creature.stepRight(o)
        if var_123 !== var_243
            Creature.stepDown(o)
        end
        var_337 = var_337[1:if length(var_337) > length(var_337)
                        0
                    else
                        length(var_337) - length(var_337)
                    end]
        var_123 = var_123 | var_243
        Creature.stepUp(o)
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        Creature.eatLeft(o,Int(var_117))
        Creature.stepUp(o)
        var_156 = func_286(var_156)
        o.mem[var_156] = var_120
        var_120 = var_156 + var_120
        var_120 = if haskey(o.mem,var_156)
                o.mem[var_156]
            else
                var_120
            end
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
        end
        var_120 = if haskey(o.mem,var_120)
                o.mem[var_120]
            else
                var_120
            end
        for i::Int8 = 1:div(var_117,_LOOP_STEPS_DIVIDER)
        end
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_156)))
        var_117 = var_117 / var_117
        var_117 = var_117 / var_117
        Creature.stepUp(o)
        var_117 = var_117 / var_117
        var_124 = Int(Creature.getEnergy(o,Int(var_120),Int(var_120)))
        var_280 = var_124 * var_124
        var_123 = var_243 | var_123
        return true
    end),[110,300,95,0,1,1,1],2,4775,18,12648,0x00000231,Dict(0=>-30014,10070=>10070,-26920=>-26920,-4015=>19308,-29748=>-29748,23323=>23323,19308=>19308,-1631=>-1631,1=>1),[1920,288],91)]

max_stars_repo_name: tmptrash/jevo

max_issues_repo_name: tmptrash/jevo

max_forks_repo_name: tmptrash/jevo


text:
module VTK

using Printf: @printf

function vtk_write(filename::String, x::AbstractArray, y::AbstractArray,
                   field::AbstractArray, nx::Int64, ny::Int64)
        numpts = nx * ny
        @assert numpts == size(x, 1)
        @assert numpts == size(y, 1)
        @assert numpts == size(field, 1)

        fh = open(filename, "w")

        # Header
        @printf(fh, "# vtk DataFile Version 4.2\n")
        @printf(fh, "vtk output\n")
        @printf(fh, "ASCII\n")
        @printf(fh, "DATASET STRUCTURED_GRID\n")
        @printf(fh, "DIMENSIONS %d %d %d\n", nx, ny, 1)
        @printf(fh, "POINTS %d float\n", numpts)

        # Coordinates
        for j in 1:ny
                for i in 1:nx
                        @printf(fh, "%f %f %f\n",
                                x[j + (i - 1) * ny],
                                y[j + (i - 1) * ny],
                                0.0)
                end
        end

        # Field
        @printf(fh, "POINT_DATA %d \n", numpts)
        @printf(fh, "FIELD scalar 1\n")
        @printf(fh, "data 1 %d float\n", numpts)

        for j in 1:ny
                for i in 1:nx
                        @printf(fh, "%f \n", field[j + (i - 1) * ny])
                end
        end

        close(fh)
end

function vtk_read(filename)

        fh = open(filename, "r")

        # Header
        line = readline(fh)
        @assert line == "# vtk DataFile Version 4.2"
        line = readline(fh)
        @assert line == "vtk output"
        line = readline(fh)
        @assert line == "ASCII"
        line = readline(fh)
        @assert line == "DATASET STRUCTURED_GRID"
        line = readline(fh)
        fields = split(line)

        # Grid dimensions
        @assert fields[1] == "DIMENSIONS"
        nx = parse(Int64, fields[2])
        ny = parse(Int64, fields[3])

        # Number of points
        line = readline(fh)
        fields = split(line)
        @assert fields[1] == "POINTS"
        numpts = parse(Int64, fields[2])
        @assert fields[3] == "float"

        # Data section
        x = zeros(numpts)
        y = zeros(numpts)
        field = zeros(numpts)

        for j in 1:ny
                for i in 1:nx
                        line = readline(fh)
                        fields = split(line)
                        idx = j + (i - 1) * ny
                        @inbounds x[idx] = parse(Float64, fields[1])
                        @inbounds y[idx] = parse(Float64, fields[2])
                end
        end

        # Field
        line = readline(fh)
        fields = split(line)
        @assert fields[1] == "POINT_DATA"
        @assert parse(Int64, fields[2]) == numpts
        line = readline(fh)
        @assert line == "FIELD scalar 1"
        line = readline(fh)
        fields = split(line)
        @assert fields[1] == "data"
        @assert fields[2] == "1"
        @assert parse(Int64, fields[3]) == numpts
        @assert fields[4] == "float"

        for j in 1:ny
                for i in 1:nx
                        line = readline(fh)
                        idx = j + (i - 1) * ny
                        @inbounds field[idx] = parse(Float64, line)
                end
        end

        close(fh)
        return x, y, field

end

end

max_stars_repo_name: ooreilly/sbpjl

max_issues_repo_name: ooreilly/sbpjl

max_forks_repo_name: ooreilly/sbpjl


text:
using Plots
using RayTracing
using Gridap

# load geometry
jsonfile = joinpath(@__DIR__,"pincell.json")
model = DiscreteModelFromFile(jsonfile)

# number of azimuthal angles
nφ = 8

# azimuthal spacing
δ = 0.02

# boundary conditions
bcs = BoundaryConditions(top=Reflective, bottom=Reflective, left=Reflective, right=Reflective)

# initialize track generator
tg = TrackGenerator(model, nφ, δ, bcs=bcs)

# perform ray tracing
trace!(tg)

# plot tracks
# plot(tg, dpi=300, size=(250,250), linecolor=:turquoise, background_color=:transparent)
plot(tg, dpi=300, size=(250,250), palette=:Paired_4, background_color=:transparent)

# savefig("pincell.svg")
# savefig("pincell.pdf")
# savefig("pincell.png")

# proceed to segmentation
segmentize!(tg)

# plot mesh
plot(tg.mesh)

# plot segments
plot(tg.tracks_by_uid)

# savefig("segments.svg")


text:
# test bearing

using RoME
using Test

@testset "Triangulation test in 2D, 3 beacons" begin

# noise models
lmp_noise = Matrix(Diagonal([0.01;0.01].^2))

# new factor graph
fg = initfg()

# landmarks
addVariable!(fg, :l1, Point2)
addVariable!(fg, :l2, Point2)
addVariable!(fg, :l3, Point2)

addFactor!(fg, [:l1], PriorPoint2(MvNormal([10.0;1.0],lmp_noise)), autoinit=false)
addFactor!(fg, [:l2], PriorPoint2(MvNormal([10.0+sqrt(3)/2;-0.5],lmp_noise)), autoinit=false)
addFactor!(fg, [:l3], PriorPoint2(MvNormal([10.0-sqrt(3)/2;-0.5],lmp_noise)), autoinit=false)

# pose
addVariable!(fg, :x1, Pose2)
addFactor!(fg, [:x1;:l1], Pose2Point2Bearing(Normal(pi/2,0.05)), autoinit=false)
addFactor!(fg, [:x1;:l2], Pose2Point2Bearing(Normal(-pi/6,0.05)), autoinit=false)
addFactor!(fg, [:x1;:l3], Pose2Point2Bearing(Normal(-pi+pi/6,0.05)), autoinit=false)

# manualinit!(fg, :x1, [30.0*randn(2,100);randn(1,100)])

# drawGraph(fg)

tree,smt,hist = solveTree!(fg)

pts = getPoints(getKDE(fg, :x1))
pts[1,:] .-= 10.0

N = size(pts,2)

@test 0.8*N < sum(sqrt.(sum(pts[1:2,:].^2,dims=1)) .< 0.3)

@test 0.8*N < sum(abs.(pts[3,:]) .< 0.1)

#
# using RoMEPlotting
# Gadfly.set_default_plot_size(35cm,25cm)
# drawPosesLandms(fg, spscale=0.2) # |> PNG("/home/dehann/Downloads/triangulation.png",20cm,15cm)
# plotPose(fg, :x1, scale=0.1) # |> PNG("/home/dehann/Downloads/triangulationPose.png",20cm,15cm)
#
# plotLocalProduct(fg, :x1)
#
# plotFactor(fg,  lsf(fg, Pose2Point2Bearing)[1])

end

@testset "Triangulation test in 2D (opposite), 3 beacons" begin

# noise models
lmp_noise = Matrix(Diagonal([0.01;0.01].^2))

# new factor graph
fg = initfg()

# landmarks
addVariable!(fg, :l1, Point2)
addVariable!(fg, :l2, Point2)
addVariable!(fg, :l3, Point2)

addFactor!(fg, [:l1], PriorPoint2(MvNormal([-10.0;1.0-10.0],lmp_noise)), autoinit=false)
addFactor!(fg, [:l2], PriorPoint2(MvNormal([-10.0+sqrt(3)/2;-0.5-10.0],lmp_noise)), autoinit=false)
addFactor!(fg, [:l3], PriorPoint2(MvNormal([-10.0-sqrt(3)/2;-0.5-10.0],lmp_noise)), autoinit=false)

# pose
addVariable!(fg, :x1, Pose2)
addFactor!(fg, [:x1;:l1], Pose2Point2Bearing(Normal(pi/2,0.05)), autoinit=false)
addFactor!(fg, [:x1;:l2], Pose2Point2Bearing(Normal(-pi/6,0.05)), autoinit=false)
addFactor!(fg, [:x1;:l3], Pose2Point2Bearing(Normal(-pi+pi/6,0.05)), autoinit=false)

manualinit!(fg, :x1, [0.01*randn(2,100);-randn(1,100)])
# manualinit!(fg, :x1, [30.0*randn(2,100);randn(1,100)])

# drawGraph(fg)

tree,smt,hist = solveTree!(fg)

pts = getPoints(getKDE(fg, :x1))
pts[1,:] .+= 10.0
pts[2,:] .+= 10.0

N = size(pts,2)

@test 0.8*N < sum(sqrt.(sum(pts[1:2,:].^2,dims=1)) .< 0.3)

@test 0.8*N < sum(abs.(pts[3,:]) .< 0.1)

#
# using RoMEPlotting
# Gadfly.set_default_plot_size(35cm,25cm)
# drawPosesLandms(fg, spscale=0.2) # |> PNG("/home/dehann/Downloads/triangulation.png",20cm,15cm)
# plotPose(fg, :x1, scale=0.1) # |> PNG("/home/dehann/Downloads/triangulationPose.png",20cm,15cm)
#
# plotLocalProduct(fg, :x1)
#
# plotFactor(fg,  lsf(fg, Pose2Point2Bearing)[1])

end

#


text:
using Documenter, GeneralizedMetropolisHastings

makedocs(
    modules = [GeneralizedMetropolisHastings],
    format = :html,
    clean = false,
    sitename = "GeneralizedMetropolisHastings.jl",
    authors = "Kris De Meyer",
    pages = Any[
        "Home" => "index.md",
        "Manual" => Any[
            "Guide" => "man/guide.md",
            "man/folderstructure.md",
            "man/data.md",
            "man/noise.md",
            "man/models.md",
            ],
        "Library" => Any[
            "Public" => "lib/public.md",
            "Internal" => "lib/internal.md",
            ],
        ]
)

deploydocs(
    repo = "github.com/QuantifyingUncertainty/GeneralizedMetropolisHastings.jl.git",
    target = "build",
    osname = "linux",
    julia  = "0.5",
    deps = nothing,
    make = nothing,
)


text:
using Random

abstract type AbstractSearchProblem{S,A} end

Random.seed!(sp::AbstractSearchProblem, seed) = Random.seed!(sp.rng, seed)

obs(sp::AbstractSearchProblem) = []

info(sp::AbstractSearchProblem) = Dict{String,Any}()  # Some nice printatble information about the search-problem instance e.g., number of cities in a Travelling-Salesman-Problem instance, or densitiy of obstacles in a grid-navigation-puzzle instance.

reset!(sp::AbstractSearchProblem) = nothing

function start_state(sp::AbstractSearchProblem{S,A})::S where {S,A}
    error("not implemented")
end

function successors(sp::AbstractSearchProblem{S,A}, state::S) where {S,A}
    error("Not Implemented. Should return a list (or any iterable collection) of Tuple{S, A}. Each tuple is a pair of: next-state and the action that leads to that next-state from the given state.")
end

function cost(sp::AbstractSearchProblem{S}, state::S, action::A, next_state::S)::Float64 where {S,A}
    error("not implemented")
end

function goal_test(sp::AbstractSearchProblem{S,A}, state::S)::Bool where {S,A}
    error("not implemented")
end

function heuristic(sp::AbstractSearchProblem{S,A}, state::S)::Float64 where {S,A}
    0
end


text: testglobal = 42


text:
push!(LOAD_PATH, "../src")
using Documenter, PolyAAnalysis

makedocs(
    modules = [PolyAAnalysis],
    format = :html,
    clean = false,
    sitename = "PolyAAnalysis.jl",
    authors = "GA, KM, GM, and contributors.",
    pages = ["Methods" => "index.md",
             "Manual" => Any["man/guide.md",
                             "man/AnnotatePolyA.md",
                             "man/TrimmPolyA.md"
                             ]
             ]
)

max_stars_repo_name: laurabiggins/polyAterminus

max_issues_repo_name: laurabiggins/polyAterminus

max_forks_repo_name: laurabiggins/polyAterminus


text:
using D3Trees
using Colors

"""
Return text to display below the node corresponding to state or action s
"""
node_tag(s) = string(s)

"""
Return text to display in the tooltip for the node corresponding to state or action s
"""
tooltip_tag(s) = node_tag(s)

function D3Trees.D3Tree(policy::BOMCPPlanner, root_state; kwargs...)
    # check to see if visualization was enabled
    if !policy.solver.enable_tree_vis
        error("""
              Tree visualization was not enabled for this policy.

              Construct the solver with $(typeof(policy.solver))(enable_tree_vis=true, ...) to enable.
              """)
    end
    return D3Tree(policy.tree, root_state; kwargs...)
end

function D3Trees.D3Tree(policy::BOMCPPlanner; kwargs...)
    @warn("""
         D3Tree(planner::BOMCPPlanner) is deprecated and may be removed in the future. Instead, please use

             a, info = action_info(planner, state)
             D3Tree(info[:tree])

         Make sure that the tree_in_info solver option is set to true. You can also get this info from a POMDPToolbox History

             info = first(ainfo_hist(hist))
             D3Tree(info[:tree])
         """)
    return D3Tree(policy.tree; kwargs...)
end

function D3Trees.D3Tree(tree::BOMCPTree, root_state; title="BOMCP tree", kwargs...)
    if tree._vis_stats == nothing
        error("""
              Visualization was not enabled for this tree.

              Construct the BOMCP solver with 'enable_tree_vis=true' to enable.
              """)
    end

    vs = tree._vis_stats

    nsas = length(vs)
    nsa = length(tree.n_a)
    nodes = Vector{Dict{String, Any}}(undef, 1 + nsas + nsa)

    # root node
    if haskey(tree.state_map, root_state)
        root_id = tree.state_map[root_state]
    else
        error("Could not find state $root_state in tree for visualization.")
    end
    nodes[1] = Dict("type"=>:state,
                    "child_d3ids"=>[1+nsas+c for c in tree.child_ids[root_id]],
                    "tag"=>node_tag(root_state),
                    "tt_tag"=>tooltip_tag(root_state),
                    "n"=>tree.n_b[root_id],
                    "n_b"=>tree.n_b[root_id],
                    "parent_n"=>tree.n_b[root_id]
                   )

    # state-action nodes
    for i in 1:nsa
        a = tree.a_labels[i]
        nodes[1+nsas+i] = Dict("type"=>:action,
                               "child_d3ids"=>Int[],
                               "tag"=>node_tag(a),
                               "tt_tag"=>tooltip_tag(a),
                               "n"=>tree.n_a[i],
                               "q"=>tree.q[i],
                              )
    end

    # state-action-state nodes
    for (i,((said,sid),n)) in enumerate(vs)
        s = tree.b_labels[sid]
        nodes[1+i] = Dict("type"=>:state,
                          "child_d3ids"=>[1+nsas+c for c in tree.child_ids[sid]],
                          "tag"=>node_tag(s),
                          "tt_tag"=>tooltip_tag(s),
                          "n"=>n,
                          "n_b"=>tree.n_b[sid],
                          "parent_n"=>tree.n_a[said]
                         )
        # add as a child to corresponding sa node
        push!(nodes[1+nsas+said]["child_d3ids"], 1+i)

        n = n_b(StateNode(tree, sid))
        # add parent_n to all children
        for csan in children(StateNode(tree, sid))
            csaid = csan.id
            nodes[1+nsas+csaid]["parent_n"] = n
        end
    end

    for csan in children(StateNode(tree, root_id))
        csaid = csan.id
        nodes[1+nsas+csaid]["parent_n"] = n_b(StateNode(tree, root_id))
    end

    return D3Tree(nodes; title=title, kwargs...)
end

function D3Trees.D3Tree(nodes::Vector{Dict{String, Any}}; title="Julia D3Tree", kwargs...)
    len = length(nodes)
    children = Vector{Vector{Int}}(undef, len)
    text = Vector{String}(undef, len)
    tooltip = Vector{String}(undef, len)
    style = fill("", len)
    link_style = fill("", len)
    max_q = maximum(get(n, "q", 0.0) for n in nodes)
    min_q = minimum(get(n, "q", 0.0) for n in nodes)
    for i in 1:len
        n = nodes[i]
        children[i] = n["child_d3ids"]
        if n["type"] == :state
            text[i] = @sprintf("""
                               %25s
                               N: %6d
                               """,
                               n["tag"], n["n_b"])
            tooltip[i] = """
                         $(n["tt_tag"])
                         N: $(n["n_b"])
                         """
            w = 20.0*sqrt(n["n"]/n["parent_n"])
            link_style[i] = "stroke-width:$(w)px"
        elseif n["type"] == :action
            text[i] = @sprintf("""
                               %25s
                               Q: %6.2f
                               N: %6d
                               """,
                               n["tag"], n["q"], n["n"])
            tooltip[i] = """
                         $(n["tt_tag"])
                         Q: $(n["q"])
                         N: $(n["n"])
                         """

            rel_q = (n["q"]-min_q)/(max_q-min_q)
            color = weighted_color_mean(rel_q, colorant"green", colorant"red")
            style[i] = "stroke:#$(hex(color))"
            w = 20.0*sqrt(n["n"]/n["parent_n"])
            link_style[i] = "stroke-width:$(w)px"
        else
            @warn("Unrecognized node type when constructing D3Tree.")
        end
    end
    return D3Tree(children;
                  text=text,
                  tooltip=tooltip,
                  style=style,
                  link_style=link_style,
                  title=title,
                  kwargs...
                 )
end

function D3Trees.D3Tree(tree::BOMCPTree; title="BOMCP Tree", kwargs...)
    lens = length(tree.n_b)
    lensa = length(tree.n_a)
    len = lens + lensa
    children = Vector{Vector{Int}}(undef, len)
    text = Vector{String}(undef, len)
    tt = fill("", len)
    style = fill("", len)
    link_style = fill("", len)
    max_q = maximum(tree.q)
    min_q = minimum(tree.q)

    for s in 1:lens
        children[s] = tree.b_children[s] .+ lens
        text[s] =  @sprintf("""
                            %25s
                            N: %6d
                            """,
                            node_tag(tree.b_labels[s]),
                            tree.n_b[s]
                           )
        tt[s] = """
                $(tooltip_tag(tree.b_labels[s]))
                N: $(tree.n_b[s])
                """
        for sa in tree.b_children[s]
            w = 20.0*sqrt(tree.n_a[sa]/tree.n_b[s])
            link_style[sa+lens] = "stroke-width:$(w)px"
        end
    end
    for sa in 1:lensa
        children[sa+lens] = collect(first(t) for t in tree.a_children[sa])
        text[sa+lens] = @sprintf("""
                                 %25s
                                 Q: %6.2f
                                 N: %6d
                                 """,
                                 node_tag(tree.a_labels[sa]),
                                 tree.q[sa],
                                 tree.n_a[sa]
                                )
        tt[sa+lens] = """
                      $(tooltip_tag(tree.a_labels[sa]))
                      Q: $(tree.q[sa])
                      N: $(tree.n_a[sa])
                      """

        rel_q = (tree.q[sa]-min_q)/(max_q-min_q)
        if isnan(rel_q)
            color = colorant"gray"
        else
            color = weighted_color_mean(rel_q, colorant"green", colorant"red")
        end
        style[sa+lens] = "stroke:#$(hex(color))"
    end
    return D3Tree(children;
                  text=text,
                  tooltip=tt,
                  style=style,
                  link_style=link_style,
                  title=title,
                  kwargs...
                 )
end


text:
function create(c::Client, ::Type{DiscordChannel}, g::AbstractGuild; kwargs...)
    return create_guild_channel(c, g.id; kwargs...)
end
function create(c::Client, ::Type{DiscordChannel}, u::User; kwargs...)
    return create_dm(c; kwargs..., recipient_id=u.id)
end

retrieve(c::Client, ::Type{DiscordChannel}, channel::Integer) = get_channel(c, channel)
retrieve(c::Client, ::Type{DiscordChannel}, g::AbstractGuild) = get_guild_channels(c, g.id)

update(c::Client, ch::DiscordChannel; kwargs...) = modify_channel(c, ch.id; kwargs...)

delete(c::Client, ch::DiscordChannel) = delete_channel(c, ch.id)


text:
T = Float32
adj = T[0 1 0 1;
       1 0 1 0;
       0 1 0 1;
       1 0 1 0]
nf = rand(T, 3, 4)

@testset "cuda" begin
    fg = FeaturedGraph(cu(adj))
    @test has_graph(fg)
    @test !has_node_feature(fg)
    @test !has_edge_feature(fg)
    @test !has_global_feature(fg)
    @test typeof(graph(fg)) == CuMatrix{T}
    @test typeof(node_feature(fg)) == Fill{T,2,Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}}
    @test typeof(edge_feature(fg)) == Fill{T,2,Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}}
    @test typeof(global_feature(fg)) == Fill{T,1,Tuple{Base.OneTo{Int64}}}

    fg = FeaturedGraph(adj, nf=cu(nf))
    @test has_graph(fg)
    @test has_node_feature(fg)
    @test !has_edge_feature(fg)
    @test !has_global_feature(fg)
    @test typeof(graph(fg)) == CuMatrix{T}
    @test typeof(node_feature(fg)) == CuMatrix{T}
    @test typeof(edge_feature(fg)) == Fill{T,2,Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}}
    @test typeof(global_feature(fg)) == Fill{T,1,Tuple{Base.OneTo{Int64}}}
end


text:
using Flux, Test
using Flux: maxpool, meanpool

@testset "Pooling" begin
  x = randn(Float32, 10, 10, 3, 2)
  mp = MaxPool((2, 2))
  @test mp(x) == maxpool(x, (2,2))
  mp = MeanPool((2, 2))
  @test mp(x) == meanpool(x, (2,2))
end

@testset "CNN" begin
  r = zeros(Float32, 28, 28, 1, 5)
  m = Chain(
    Conv((2, 2), 1=>16, relu),
    MaxPool((2,2)),
    Conv((2, 2), 16=>8, relu),
    MaxPool((2,2)),
    x -> reshape(x, :, size(x, 4)),
    Dense(288, 10), softmax)

  @test size(m(r)) == (10, 5)
end

@testset "Depthwise Conv" begin
  r = zeros(Float32, 28, 28, 3, 5)

  m1 = DepthwiseConv((2, 2), 3=>5)

  @test size(m1(r), 3) == 15

  m2 = DepthwiseConv((2, 2), 3)

  @test size(m2(r), 3) == 3

  x = zeros(Float64, 28, 28, 3, 5)

  m3 = DepthwiseConv((2, 2), 3 => 5)

  @test size(m3(r), 3) == 15

  m4 = DepthwiseConv((2, 2), 3)

  @test size(m4(r), 3) == 3
end


text:
using Scientific_Programming_in_Julia
using EcosystemCore
using Test

include("ReverseDiff.jl")
include("Ecosystem.jl")


text:
# relay execution of certain functions on type  T  to one of its fields  f  .
# kind of a workaround for missing inheritance
#TODO rethink this... might fuck up interface e.g. in conjuction with observer
macro relay(T′, f′)
	T,f = eval(T′), eval(f′)	# use esc instead?
	@assert f in fieldnames(T)
	U = fieldtype(T, f)

	return quote
		Base.setindex!(x::$T, v...) 	= setindex!(x.$f, v...)
		Base.getindex(x::$T, v...) 		= getindex(x.$f, v...)
		Base.start(x::$T) 				= start(x.$f)
		Base.next(x::$T, state) 		= next(x.$f, state)
		Base.done(x::$T, state) 		= done(x.$f, state)
		Base.convert(::Type{$U}, x::$T)	= x.$f
		Base.push!(x::$T, items...)		= push!(x.$f, items...)
		Base.pop!(x::$T, items...)		= pop!(x.$f, items...)
		Base.unshift!(x::$T, items...)	= unshift!(x.$f, items...)
		Base.shift!(x::$T, items...)	= shift!(x.$f, items...)
		Base.length(x::$T)				= length(x.$f)
		Base.endof(x::$T)				= endof(x.$f)
		return Void
	end
end


text:
export SizeConstrainedFileCache, add!, delete!, hit!, rebuild!, filepath,
       TargetSizeConstant, TargetSizeKeepFree, DiscardLRU, DiscardLFU

struct CacheEntry
    size::UInt64
    last_accessed::Float64
    num_accessed::UInt64
end

abstract type FileCache end

"""
    SizeConstrainedFileCache <: FileCache

Represents a size-constrained file cache.  Configurable with different policies for when
to discard elements from the cache and how to choose which elements to discard.

    SizeConstrainedFileCache(root, target_func, discard_func; predicate=x->true)

Construct a new file cache. Arguments:
 - `root`: the root directory of the cache.
 - `target_func`: function that return the (maximum) number of bytes that files
   in the cache may occupy, see e.g. `TargetSizeKeepFree` and `TargetSizeConstant`.
 - `discard_func`: function that return the eviction order, see e.g. `DiscardLRU`
   and `DiscardLFU`.
 - `predicate`: function that determines whether a file should be tracked/included
   in the cache. Currently only used for existing files when setting up the file cache.
   The default is to track every existing file.

!!! warn
    This is a potentially destructive operation since the file cache may delete
    files in the `root` directory to fit the given constraints.

Example usage:

    # Create cache that keeps 10GB free and releases LRU objects
    scfc = SizeConstrainedFileCache(root, TargetSizeKeepFree(10*1024^3), DiscardLRU())

    # Add a new file:
    path = add!(scfc, key, filesize)
    open(path, "w") do io
        write(path, filedata)
    end

    # Check to see if that file is there (and also increment its usage counters)
    hit!(scfc, key)

    # Delete that file
    delete!(scfc, key)
"""
mutable struct SizeConstrainedFileCache <: FileCache
    # storage root
    root::String

    # Storage leaves
    entries::Dict{String,CacheEntry}
    total_size::UInt64

    # Function that returns the target size of the cache.
    # For simple usage, this can simply return a constant:
    #   (scfc) -> 4*1024*1024*1024
    # For more complex usage, this may return a size that always leaves
    # a certain amount of space free for the rest of the system.
    target_size::Function

    # Function that sorts the cache entries, returning the values that we should
    # drop in order to free up more space.  An example of this is a function that
    # simply sorts by time last accessed:
    #   (entries) -> sort(entries, by = k -> entries[k].last_accessed)
    # For more complex usage, users may wish to sort objects by some combination
    # of how often they are accessed, how recently they were accessed, and the size
    # of the object that may be freed.  Or perhaps ensure that some keys are never
    # discarded, etc...
    discard_ordering::Function

    function SizeConstrainedFileCache(root::AbstractString, target_size::Function, discard_ordering::Function;
                                      predicate::Function=x->true)
        scfc = new(
            string(root),
            Dict{String,CacheEntry}(),
            UInt64(0),
            target_size,
            discard_ordering,
        )

        # Always rebuild the scfc so that it represents the correct data on-disk
        rebuild!(scfc; predicate=predicate)

        # After rebuilding, immediately run a shrink check:
        target_size = scfc.target_size(scfc)
        if scfc.total_size > target_size
            shrink!(scfc, scfc.total_size - target_size)
        end

        # Finally, give the scfc back
        return scfc
    end
end

"""
    filepath(fc::FileCache, key::AbstractString)

Given a `key`, returns the path on disk for that key.
"""
function filepath(scfc::FileCache, key::AbstractString)
    return joinpath(scfc.root, key)
end

"""
    add!(scfc::SizeConstrainedFileCache, key::AbstractString, new_size)

Reserves space for a new file within the file cache of the specified size.  If the
addition would result in a new total size that is greater than the target specified by
the `target_size` function passed to the SCFC constructor, `shrink!()` the file cache
until this new object can fit nicely within the cache without overstepping any file size
bounds.  If the new object cannot fit wihtin the cache at all, throws an `ArgumentError`.

`add!()`'ing an entry that already exists within the file cache overwrites it and clears
all access counters, treating it as a semantically different object than the object that
was replaced.
"""
function add!(scfc::SizeConstrainedFileCache, key::AbstractString, new_size)
    # Remove this key from the cache if it already exists.
    delete!(scfc, key)

    target_size = UInt64(scfc.target_size(scfc))
    new_total_size = UInt64(scfc.total_size + new_size)
    if new_total_size > target_size
        # If the new value is just preposterously large, complain
        if new_size > target_size
            throw(ArgumentError(
                "Requested size $(new_size) is larger than entire cache $(target_size)"
            ))
        end

        # Call `shrink!()``.  We have no behavior for `shrink!()` failing; we assume it
        # can always hit the shrinking target we give it.
        shrink!(scfc, UInt64(new_total_size - target_size))
    end

    scfc.entries[key] = CacheEntry(new_size, time(), 1)
    scfc.total_size += new_size

    # Return the filepath so that users can use this in `open()` or whatever
    path = filepath(scfc, key)
    mkpath(dirname(path))
    return path
end

"""
    delete!(fc::FileCache, key)

Removes a key from the file cache, clearing all metadata about that key within the cache.
Also removes the backing file on disk if it still exists.  Returns `true` if the key was
actually deleted.
"""
function Base.delete!(scfc::FileCache, key::AbstractString)
    if !haskey(scfc.entries, key)
        return false
    end

    entry = scfc.entries[key]
    rm(filepath(scfc, key); force=true)
    delete!(scfc.entries, key)
    scfc.total_size -= entry.size
    return true
end

"""
    hit!(fc::FileCache, key)

Returns `true` if the key exists within the cache, `false` otherwise.  Increments access
counters for the given key, recording last access time, number of times accessed, etc...
"""
function hit!(scfc::FileCache, key::AbstractString)
    # If this is not in our entries, return `false`
    if !haskey(scfc.entries, key)
        return false
    end

    old_entry = scfc.entries[key]
    scfc.entries[key] = CacheEntry(old_entry.size, time(), old_entry.num_accessed + 1)

    # We `touch()` it here, so that if we have to rebuild the cache from disk,
    # our access times are roughly in-line with what we would expect.
    touch(filepath(scfc, key))
    return true
end

"""
    rebuild!(fc::FileCache; predicate::Function = x -> true)

Rebuilds the file cache datastructures within memory from disk.  This is not a lossless
operation; last access times may be inaccurate and number of times accessed will be set
to 1 for any key that was not previously tracked.  This is done automatically when
creating a new cache; the file cache will scan its root directory and populate itself with the
values gathered using this function.

The `predicate` keyword can be used to pass a predicate function (input: `key`, output: `Bool`)
to filter which files in the root directory that should be tracked/included in the cache.
The default is to include every file.
"""
function rebuild!(scfc::FileCache; predicate::Function = x -> true)
    # Clear the total size to zero, then build it back up again
    scfc.total_size = UInt64(0)

    # We will create a new entries dict:
    new_entries = Dict{String,CacheEntry}()
    old_entries = scfc.entries

    # Ensure that the cache root always exists
    mkpath(scfc.root)
    for (parent, dirs, files) in walkdir(scfc.root)
        for fname in files
            path = joinpath(parent, fname)
            key = relpath(path, scfc.root)

            # Check if this file should be included
            if !(predicate(key)::Bool)
                continue
            end

            # First, collect ground-truth size
            st = stat(path)
            size = filesize(st)

            # Default values
            last_accessed = mtime(st)
            num_accessed = 1

            # Next, let's see if this actually existed in the scfc before.  If they did,
            # use the values from the old metadata rather than the defaults above.
            key = relpath(path, scfc.root)
            if haskey(old_entries, key)
                last_accessed = old_entries[key].last_accessed
                num_accessed = old_entries[key].num_accessed
            end

            # Store this new value into `new_entries` and update `total_size`
            new_entries[key] = CacheEntry(size, last_accessed, num_accessed)
            scfc.total_size += size
        end
    end

    # Finally, update `scfc.entries` and let `old_entries` wither
    scfc.entries = new_entries
    return nothing
end

"""
    shrink!(scfc, size_to_shrink)

Shrinks a file cache by the amount given by discarding files within the file cache,
stopping only when the target has been met or the list of keys to discard is exhausted.
Returns the new total size of the file cache.
"""
function shrink!(scfc::SizeConstrainedFileCache, size_to_shrink::UInt64)
    # Sort the keys by the user criterion
    keys_to_discard = scfc.discard_ordering(scfc)

    # Delete elements until we are under our target size
    target_size = scfc.total_size - size_to_shrink
    while scfc.total_size > target_size && !isempty(keys_to_discard)
        delete!(scfc, popfirst!(keys_to_discard))
    end
    return scfc.total_size
end

## Policies for determining target size of the cache:
# Keep cache always below `bytes` size
TargetSizeConstant(bytes) = (scfc) -> UInt64(bytes)
# Ensure that `bytes` are always free on the disk the scfc is stored on
TargetSizeKeepFree(bytes) = (scfc) -> begin
    # Be careful of unsigned wraparound
    curr = get_disk_freespace(scfc.root) + scfc.total_size
    if bytes > curr
        return UInt64(0)
    else
        return UInt64(curr - bytes)
    end
end

## Policies for sorting entries for discard.  We define LRU and LFU here as an example.
DiscardLRU() = (scfc) -> begin
    sort(collect(keys(scfc.entries)); by = k -> scfc.entries[k].last_accessed)
end
# Note that for LFU, we break ties by falling back to discarding the least-recently used:
DiscardLFU() = (scfc) -> begin
    sort(collect(keys(scfc.entries)); by = k -> (scfc.entries[k].num_accessed,
                                                 scfc.entries[k].last_accessed))
end


text:
Base.length(x::Value) = length(value(x))
Base.eltype(x::Value) = eltype(value(x))

# NOTE: this is a fallback method, it is slow
Base.iterate(x::Value) = iterate_forward(iterate(value(x)), x)
Base.iterate(x::Value, st) = iterate_forward(iterate(value(x), st), x, st)

iterate_forward(out::Nothing, x::Value) = nothing
iterate_forward(out::Nothing, x::Value, st) = nothing

function iterate_forward(out, x::Value, st)
    node = Node(Base.iterate, (x, st))
    v, st = out
    CachedNode(node, v), st
end

function iterate_forward(out, x::Value)
    node = Node(Base.iterate, (x, ))
    v, st = out
    CachedNode(node, v), st
end

function gradient(::typeof(Base.iterate), grad::Number, output, x::AbstractArray)
    out_grad = zero(x)
    out_grad[1] = grad
    (out_grad, )
end

function gradient(::typeof(Base.iterate), grad, output, x::AbstractArray, st)
    out_grad = zero(x)
    out_grad[st] = grad
    (out_grad, )
end

Base.sum(x::Value{<:AbstractArray}; dims=:) = register(Base.sum, x; dims=dims)

gradient(::typeof(Base.sum), grad, output, x::AbstractArray; dims) =
    grad_sum(grad, x, dims)

grad_sum(grad, x, dims::Colon) = (fill!(similar(x), grad), )


text:
module TestTyndall
using Tyndall
using PyCall
using FactCheck

# facts("Planck function") do
#     @fact abs(planck(500,250)-0.09) < 0.01 => true
#     @fact abs(planck(500,350)-0.225) < 0.01 => true
# end
#
# facts("dry_adiabat creates a dry adiabat temperature profile with a specified surface temperature") do
#     T = dry_adiabat(300)
#     p_s = 1.013e5
#     @fact T(p_s) => 300
#     @fact abs(T(p_s/2)-.82 * 300) < 1 => true
# end

facts("produces fluxes for a given atmospheric condition") do
    context("isothermal") do
        T = isothermal(300)
        println(OLR(T,400e-6))
        println(5.67e-8 * 300^4)
        @fact (abs(OLR(T,400e-6)-5.67e-8 * 300^4) < 1.0) => true
    end

    context("dry adiabat") do
        ps = [1.013e5i for i=0:1/101:1][2:end]
        T = dry_adiabat_with_strat(283.15)
        co2 = 400

        # call the Python (which calls the Fortran...)
        @pyimport climt
        cam3 = climt.make_radiation(
            scheme="cam3", co2=co2,
            p=ps[1:end-1]/100, ps=ps[end]/100, T=[T(p) for p=ps[1:end-1]],
            Ts=T(ps[end]), q=[1.e-10 for i=ps[1:end-1]]
        )

        # call the Julia
        olr = OLR(T,.0004 * (44/29))
        println(olr)
        println(getindex(cam3, "lwuflx")[1])
        @fact (abs(olr - getindex(cam3, "lwuflx")[1]) < 1.0) => true
    end
end
end


text:
code_cache(interp::CustomInterpreter) = CustomGlobalCache(interp, code_cache(interp.native))

struct CustomGlobalCache{NativeCache}
    interp::CustomInterpreter
    native::NativeCache
    CustomGlobalCache(interp::CustomInterpreter, native::NativeCache) where {NativeCache} =
        new{NativeCache}(interp, native)
end
WorldView(tpc::CustomGlobalCache, wr::WorldRange) = CustomGlobalCache(tpc.interp, WorldView(tpc.native, wr))
WorldView(tpc::CustomGlobalCache, args...) = WorldView(tpc, WorldRange(args...))

CC.haskey(tpc::CustomGlobalCache, mi::MethodInstance) = CC.haskey(tpc.native, mi)

# here we can work on global cache retrieval
function CC.get(tpc::CustomGlobalCache, mi::MethodInstance, default)
    ret = CC.get(tpc.native, mi, default)

    # return default # NOTE: return `default` will invalidate inference cache

    return ret
end

CC.getindex(tpc::CustomGlobalCache, mi::MethodInstance) = CC.getindex(tpc.native, mi)

CC.setindex!(tpc::CustomGlobalCache, ci::CodeInstance, mi::MethodInstance) = CC.setindex!(tpc.native, ci, mi)

max_stars_repo_name: aviatesk/AbstractInterpreterPlayground

max_issues_repo_name: aviatesk/AbstractInterpreterPlayground

max_forks_repo_name: aviatesk/AbstractInterpreterPlayground


text:
"""
    GraphVertex

Store the drawing function and properties individual to the node.

# Examples
```julia
function draw(;position, radius)
    circle(position, radius, :stroke)
    return position
end

g_props = [Dict(:weight=>2, :neighbors=>[2])
     Dict(:weight=>4, :neighbors=>[1])]
ga = @Object(1:100, Graph(true, 100, 100), O)

node1 = @Graph(ga, 1:50, GraphVertex(1, [draw_shape(:square, 12), draw_text(:inside, "123"), fill(:image, "./img.png"), custom_border()];
                                     animate_on=:scale, property_style_map=Dict(:weight=>:radius)))

# each of these draw_* functions return functionsn with specified change keywords like radius, border_color etc.
# expose as many of these props as supported by Luxor drawing
node2 = @Graph(ga, 50:100, GraphVertex(2, draw; animate_on=:scale, property_style_map=Dict(:weight=>:radius)))
render(video; pathname="graph_node.gif")
```
"""
struct GraphVertex <: AbstractGraphVertex
    vertex_id
    object::AbstractObject
    animate_on::Symbol
    style_property_map::Dict{Symbol, Any}
    opts::Dict{Symbol, Any}
end

GRAPH_VERTICES = Vector{AbstractGraphVertex}()
CURRENT_GRAPH_VERTEX = Array{AbstractGraphVertex, 1}()

# """
#     GraphVertex(node::Integer, draw::Function; <keyword arguments>)
#     GraphVertex(graph::AbstractObject, node::Integer, draw::Function; <keyword arguments>)
#     GraphVertex(graph::AbstractObject, node::Integer, draw::Vector{Function}; <keyword arguments>)

# Create a graph node, specifying a drawing function or a property style map or both.

# # Arguments
# - `graph::AbstractObject`: The graph created using [`GraphAnimation`](@ref) to which this node should be added to.
# - `node::Integer`: A unique id representing the node being added to the graph.
#     - Currently, only numeric node ids are supported.
# - `draw::Function`: The drawing function used to draw the node.
#     - Implementing the drawing function in a special way to expose the drawing parameters helps in better animation.

# # Keywords
# - `animate_on::Symbol`: Control the animation effect on the nodes using pre-defined drawing parameters. Default is `:opacity`.
#     - For nodes, it can be
#         - `:opacity`
#         - `:scale`
#     - For known graph types, it can additionally be
#         - `:fill_color`
#         - `:border_color`
#         - `:radius`
# - `property_style_map::Dict{Any,Symbol}`: A mapping to of how node attributes map to node drawing styles.
# """

GraphVertex(vertex_id::Integer, frames; kwargs...) =
    GraphVertex(CURRENT_GRAPH[1], vertex_id, frames; kwargs...)

GraphVertex(vertex_id::Integer, object::AbstractObject; kwargs...) =
    GraphVertex(CURRENT_GRAPH[1], vertex_id, object; kwargs...)

function GraphVertex(
    jg::JGraph,
    vertex_id::Integer,
    frames;
    kwargs...
)
    check_frames_within(jg.object.frames, frames, vertex_id)
    object = Object(frames, get_draw(:vertex); kwargs...)
    return GraphVertex(jg, vertex_id, object; kwargs...)
end

function GraphVertex(
    jg::JGraph,
    vertex_id::Integer,
    object::AbstractObject;
    animate_on::Symbol = :opacity,
    start_pos::Point = O,
    style_property_map::Dict{Any,Symbol} = Dict{Any,Symbol}()
)
    if jg.mode == :static
        if has_vertex(jg.graph.adjacency_graph, vertex_id)
            @warn "Vertex $(vertex_id) is already created on canvas. Recreating it will leave orphan vertex objects in the animation. To undo, call `rem_vertex!`"
        end
        object.opts[:_graph_idx] = jg.object.opts[:_graph_idx]
        object.opts[:_vertex_idx] = length(GRAPH_VERTICES) + 1
        if jg.layout == :none
            object.opts[:position] = start_pos
        end
        # ToDo: Create a mapping for vertex ids here
        # vertex id for the graph vertex need not be same as vertex id for adjacency graph
        # vertex_id = object.opts[:_vertex_idx] # this breaks test
        opts = Dict{Symbol, Any}()
        opts[:styles] = OrderedDict{Symbol, Function}()
        object.opts[:_style_opts_cache] = Dict{Symbol, Any}()
        add_vertex!(jg.graph.adjacency_graph)
        set_prop!(jg.graph.adjacency_graph, vertex_id, length(jg.ordering) + 1)
        vertex = GraphVertex(vertex_id, object, animate_on, style_property_map, opts)
        push!(GRAPH_VERTICES, vertex)
        push!(jg.ordering, vertex)
        if isempty(CURRENT_GRAPH_VERTEX)
            push!(CURRENT_GRAPH_VERTEX, vertex)
        else
            CURRENT_GRAPH_VERTEX[1] = vertex
        end
        return vertex
    elseif g.mode == :dynamic
    end
end


text:
using Test
using BenchmarkTools
using LinearAlgebra
using BQCESubroutine
using YaoLocations
using BQCESubroutine: threaded_basic_broutine!

# @broutine X = [0 1; 1 0]

N = 15
st = rand(Float64, 1<<N)
st_mat = rand(Float64, 5, 1<<N)
X = [0 1; 1 0]
locs = Locations(3)

BQCESubroutine.disable_threads()
st0 = broutine!(copy(st), Val(:X), locs)
st1 = broutine!(copy(st), Val(:X_test), locs)
st2 = broutine!(copy(st), X, locs)
@test st1 ≈ st2
@test st1 ≈ st0

BQCESubroutine.disable_threads()
# @benchmark broutine!(st, Val(:X), locs) setup=(st = rand(Float64, 1<<N))
# @benchmark broutine!(st, Val(:X_test), locs) setup=(st = rand(Float64, 1<<N))
# @benchmark broutine!(st, X, locs) setup=(st = rand(Float64, 1<<N))

function benchmark_loc(N)
    BQCESubroutine.enable_threads()
    nthreads = Threads.nthreads()
    for i in 1:N
        print("nthreads=$nthreads, N=$N, loc=$i, (:X)     ")
        @btime st1 = threaded_basic_broutine!(copy(st), Val(:X), Locations($i)) setup=(st = rand(Float64, 1<<$N))
        print("nthreads=$nthreads, N=$N, loc=$i, (:X_test)")
        @btime st1 = broutine!(copy(st), Val(:X_test), Locations($i)) setup=(st = rand(Float64, 1<<$N))
    end
end
benchmark_loc(27)

@benchmark st1 = broutine!(copy(st), Val(:X_test), Locations(9)) setup=(st = rand(Float64, 1<<27))