text:
"""
    _concatenate(
        highlights::Vector{String},
        comments::Vector{String},
        pages::Vector{Int32},
    ) -> Tuple{Vector{String}, Vector{String}, Vector{Int32}}

Concatenate highlights based on comments; merge pages.

# Arguments
- `highlights::Vector{String}`: $(HIGHLIGHTS_ARGUMENT)
- `comments::Vector{String}`: $(COMMENTS_ARGUMENT)
- `pages::Vector{Int32}`: $(PAGES_ARGUMENT)

# Returns
- `Tuple{Vector{String}, Vector{String}, Vector{Int32}}`: the concatenated arguments

# Example
```jldoctest; output = false
using PDFHighlights

PDFHighlights.Internal.PDF._concatenate(
    String["Highlight 1", "High-", "light 2"],
    String["Comment 1", ".c1 Comment 2", ".c2"],
    Int32[1, 2, 3],
) ==
(
    String["Highlight 1", "Highlight 2"],
    String["Comment 1", "Comment 2"],
    Int32[1, 2],
)

# output

true
```
"""
function _concatenate(
    highlights::Vector{String},
    comments::Vector{String},
    pages::Vector{Int32},
)::Tuple{Vector{String}, Vector{String}, Vector{Int32}}

    # Label for the comments which will be deleted
    comments_remove_label = "__REMOVE_AFTER_CONCATENATION__"

    # The initial concatenation identifier
    id = 1

    # Combine highlights if there are concatenation identifiers
    for (index, comment) in enumerate(comments)

        # Start a new chain of highlights
        if startswith(comment, ".c1")

            comments[index] = lstrip(chop(comment; head = 3, tail = 0))
            id = 2

        # Continue the current chain of highlights
        elseif startswith(comment, ".c$(id)")

            # Get the current highlight
            current_highlight = highlights[index]

            # Get the chain's first highlight
            first_highlight = highlights[index - id + 1]

            # Take the last word from the chain's first highlight
            half_word = split(first_highlight, ' ')[end]

            # If the last word ends with `-`, concatenate the halves
            if length(half_word) > 1 && endswith(half_word, '-')
                highlights[index - id + 1] =
                chop(first_highlight; tail = 1) * current_highlight
            else
                highlights[index - id + 1] *= ' ' * current_highlight
            end

            # Delete metadata
            highlights[index] = ""
            pages[index] = 0

            # Append the current comment to the first comment in the chain
            comment = replace(comment, Regex("(^.c$id) |(?1)") => "")
            if !isempty(comment)
                comments[index - id + 1] *= ' ' * comment
            end

            comments[index] = comments_remove_label

            id += 1

        # Drop the current chain of highlights
        else

            comments[index] = replace(comment, r"(^.c([2-9]|[1-9][0-9])+) |(?1)" => "")
            id = 1

        end

    end

    return filter(!isempty, highlights),
           filter(comment -> comment != comments_remove_label, comments),
           filter(element -> element != 0, pages)

end


text:
module PersistenceBarcodes

using StaticArrays
using RecipesBase

include("barcode.jl")
include("plotting.jl")

export
    PersistencePair, birth, death, data,
    PersistenceBarcode, dim, barcodes,
    persistencediagram, persistencediagram!

end

ext: jl


text:
"""
Basic continuous multivariate parameter state type

# Constructors

## BasicContMuvParameterState{N<:Real}(value::Vector{N}, <optional arguments>)

Construct a basic continuous multivariate parameter state with some ``value``.

###  Optional arguments:

* ``monitor::Vector{Bool}=fill(false, 9)``: 9-element Boolean vector indicating which of the target-related fields are
stored by the state.
* ``diagnostickeys::Vector{Symbol}=Symbol[]``: the diagnostic keys of the state.
* ``diagnosticvalues::Vector=Array(Any, length(diagnostickeys))``: the diagnostic values of the state.

## BasicContMuvParameterState{N<:Real}(value::Vector{N}, monitor::Vector{Symbol}, <optional arguments>)

Construct a basic continuous multivariate parameter state with some ``value`` and tracked target-related fields specified by
``monitor``.

###  Optional arguments:

* ``diagnostickeys::Vector{Symbol}=Symbol[]``: the diagnostic keys of the state.
* ``diagnosticvalues::Vector=Array(Any, length(diagnostickeys))``: the diagnostic values of the state.

## BasicContMuvParameterState{N<:Real}(size::Integer, <optional arguments>)

Construct a basic continuous multivariate parameter state with a ``value`` of specified ``size``.

###  Optional arguments:

* ``monitor::Vector{Bool}=fill(false, 9)``: 9-element Boolean vector indicating which of the target-related fields are
stored by the state.
* ``diagnostickeys::Vector{Symbol}=Symbol[]``: the diagnostic keys of the state.
* ``::Type{N}=Float64``: the element type of the state value.
* ``diagnosticvalues::Vector=Array(Any, length(diagnostickeys))``: the diagnostic values of the state.

## BasicContMuvParameterState{N<:Real}(size::Integer, monitor::Vector{Symbol}, <optional arguments>)

Construct a basic continuous multivariate parameter state with a ``value`` of specified ``size`` and tracked target-related
fields specified by ``monitor``.

###  Optional arguments:

* ``diagnostickeys::Vector{Symbol}=Symbol[]``: the diagnostic keys of the state.
* ``::Type{N}=Float64``: the element type of the state value.
* ``diagnosticvalues::Vector=Array(Any, length(diagnostickeys))``: the diagnostic values of the state.

# Examples

```julia
julia> state = BasicContMuvParameterState(zeros(Float64, 2), [:logtarget])
Klara.BasicContMuvParameterState{Float64}([0.0,0.0],NaN,NaN,NaN,Float64[],Float64[],Float64[],0x0 Array{Float64,2},0x0 Array{Float64,2},0x0 Array{Float64,2},0x0x0 Array{Float64,3},0x0x0 Array{Float64,3},0x0x0 Array{Float64,3},Any[],2,Symbol[])

julia> state.value
2-element Array{Float64,1}:
 0.0
 0.0
```
"""
type BasicContMuvParameterState{N<:Real} <: ParameterState{Continuous, Multivariate}
  "Vector value of basic continuous multivariate parameter state"
  value::Vector{N}
  "Value of log-likelihood at the state's value"
  loglikelihood::N
  "Value of log-prior at the state's value"
  logprior::N
  "Value of log-target at the state's value"
  logtarget::N
  "Value of gradient of log-likelihood at the state's value"
  gradloglikelihood::Vector{N}
  "Value of gradient of log-prior at the state's value"
  gradlogprior::Vector{N}
  "Value of gradient of log-target at the state's value"
  gradlogtarget::Vector{N}
  "Value of metric tensor of log-likelihood at the state's value"
  tensorloglikelihood::Matrix{N}
  "Value of metric tensor of log-prior at the state's value"
  tensorlogprior::Matrix{N}
  "Value of metric tensor of log-target at the state's value"
  tensorlogtarget::Matrix{N}
  "Value of derivatives of metric tensor of log-likelihood at the state's value"
  dtensorloglikelihood::Array{N, 3}
  "Value of derivatives of metric tensor of log-prior at the state's value"
  dtensorlogprior::Array{N, 3}
  "Value of derivatives of metric tensor of log-target at the state's value"
  dtensorlogtarget::Array{N, 3}
  "Diagnostic values associated with the sampling of the state"
  diagnosticvalues::Vector
  "Integer representing the length of vector value of basic continuous multivariate parameter state"
  size::Integer
  "Diagnostic keys associated with the sampling of the state"
  diagnostickeys::Vector{Symbol}
end

function BasicContMuvParameterState{N<:Real}(
  value::Vector{N},
  monitor::Vector{Bool}=fill(false, 9),
  diagnostickeys::Vector{Symbol}=Symbol[],
  diagnosticvalues::Vector=Array(Any, length(diagnostickeys))
)
  v = convert(N, NaN)

  s = length(value)

  l = Array(Integer, 9)
  for i in 1:9
    l[i] = (monitor[i] == false ? zero(Integer) : s)
  end

  BasicContMuvParameterState{N}(
    value,
    v,
    v,
    v,
    Array(N, l[1]),
    Array(N, l[2]),
    Array(N, l[3]),
    Array(N, l[4], l[4]),
    Array(N, l[5], l[5]),
    Array(N, l[6], l[6]),
    Array(N, l[7], l[7], l[7]),
    Array(N, l[8], l[8], l[8]),
    Array(N, l[9], l[9], l[9]),
    diagnosticvalues,
    s,
    diagnostickeys
  )
end

function BasicContMuvParameterState{N<:Real}(
  value::Vector{N},
  monitor::Vector{Symbol},
  diagnostickeys::Vector{Symbol}=Symbol[],
  diagnosticvalues::Vector=Array(Any, length(diagnostickeys))
)
  fnames = fieldnames(BasicContMuvParameterState)
  BasicContMuvParameterState(value, [fnames[i] in monitor ? true : false for i in 5:13], diagnostickeys, diagnosticvalues)
end

BasicContMuvParameterState{N<:Real}(
  size::Integer,
  monitor::Vector{Bool}=fill(false, 9),
  diagnostickeys::Vector{Symbol}=Symbol[],
  ::Type{N}=Float64,
  diagnosticvalues::Vector=Array(Any, length(diagnostickeys))
) =
  BasicContMuvParameterState(Array(N, size), monitor, diagnostickeys, diagnosticvalues)

BasicContMuvParameterState{N<:Real}(
  size::Integer,
  monitor::Vector{Symbol},
  diagnostickeys::Vector{Symbol}=Symbol[],
  ::Type{N}=Float64,
  diagnosticvalues::Vector=Array(Any, length(diagnostickeys))
) =
  BasicContMuvParameterState(Array(N, size), monitor, diagnostickeys, diagnosticvalues)

value_support{N<:Real}(::Type{BasicContMuvParameterState{N}}) = Continuous
value_support(::BasicContMuvParameterState) = Continuous

variate_form{N<:Real}(::Type{BasicContMuvParameterState{N}}) = Multivariate
variate_form(::BasicContMuvParameterState) = Multivariate

Base.eltype{N<:Real}(::Type{BasicContMuvParameterState{N}}) = N
Base.eltype{N<:Real}(::BasicContMuvParameterState{N}) = N

generate_empty(
  state::BasicContMuvParameterState,
  monitor::Vector{Bool}=[isempty(getfield(state, fieldnames(BasicContMuvParameterState)[i])) ? false : true for i in 5:13]
) =
  BasicContMuvParameterState(state.size, monitor, state.diagnostickeys, eltype(state))


text:
module Scenes

export HitRecord, Scene, TriangleMesh, Triangle, Light, bvh, Bounds

using LinearAlgebra
using StaticArrays

using ..GfxBase
using ..WWUMeshes
using ..Materials

struct Triangle
    positions::SVector{3, Vec3}
    normals::Union{Nothing, SVector{3, Vec3}}
    uvs::Union{Nothing, SVector{3, Vec2}}
    material::Int
end

struct Bounds
    min::Vec3
    max::Vec3
    leaf::Bool
    a::Int
    b::Int
end

struct Light
    color::Vec3
    point::Vec3
    radius::Float32
end

"""Generic scene data type."""
struct Scene
    background::Vec3
    materials::Array{Material, 1}
    triangles::Array{Triangle, 1}
    lights::Array{Light, 1}
    bounds::Array{Bounds, 1}
end

function bounding_box(structures)
    bb_min = [Inf, Inf, Inf]
    bb_max = [-Inf, -Inf, -Inf]

    for s in structures
        smin, smax = bounding_box(s)

        for i in 1:3
            bb_min[i] = min(bb_min[i], smin[i])
            bb_max[i] = max(bb_max[i], smax[i])
        end
    end

    Vec3(bb_min[1], bb_min[2], bb_min[3]), Vec3(bb_max[1], bb_max[2], bb_max[3])
end

function bounding_box(triangle::Triangle)
    t_min = [Inf, Inf, Inf]
    t_max = [-Inf, -Inf, -Inf]

    for n in 1:3
        p = triangle.positions[n]
        for i in 1:3
            t_min[i] = min(t_min[i], p[i])
            t_max[i] = max(t_max[i], p[i])
        end
    end

    Vec3(t_min[1], t_min[2], t_min[3]), Vec3(t_max[1], t_max[2], t_max[3])
end

function bounding_box(bounds::Bounds)
    bounds.min, bounds.max
end

function center_of(structure)
    min, max = bounding_box(structure)
    min .+ (max .- min) ./ 2
end

function bound_triangles(triangles, a::Int, b::Int)
    min, max = bounding_box([triangles[a], triangles[b]])
    Bounds(min, max, true, a, b)
end

function bound_bounds(bounds, a::Int, b::Int)
    min, max = bounding_box([bounds[a], bounds[b]])
    Bounds(min, max, false, a, b)
end

function bvh(triangles)
    bounds::Array{Bounds, 1} = []
    bvh(triangles, bounds, [i for i in 1:length(triangles)])
    bounds
end

function bvh(triangles, bounds::Array{Bounds, 1}, indices::Array{Int, 1})
    if length(indices) == 1
        push!(bounds, bound_triangles(triangles, indices[1], indices[1]))
        length(bounds)
    elseif length(indices) == 2
        push!(bounds, bound_triangles(triangles, indices[1], indices[2]))
        length(bounds)
    else
        i, j = farthest_pair(triangles, indices)

        is::Array{Int, 1} = []
        js::Array{Int, 1} = []

        for index in indices
            center = center_of(triangles[index])
            if distance(center_of(triangles[indices[i]]), center) < distance(center_of(triangles[indices[j]]), center)
                push!(is, index)
            else
                push!(js, index)
            end
        end

        ibounds = bvh(triangles, bounds, is)
        jbounds = bvh(triangles, bounds, js)
        push!(bounds, bound_bounds(bounds, ibounds, jbounds))
        length(bounds)
    end
end

function farthest_pair(triangles, indices::Array{Int, 1})
    max_dist = 0
    farthest_pair = nothing
    for i in 1:length(indices) - 1
        for j in i + 1:length(indices)
            dist = distance(center_of(triangles[indices[i]]), center_of(triangles[indices[j]]))
            if dist > max_dist
                max_dist = dist
                farthest_pair = i, j
            end
        end
    end

    farthest_pair
end

end

max_stars_repo_name: aedans/raytracer

max_issues_repo_name: aedans/raytracer

max_forks_repo_name: aedans/raytracer


text:
using Qecsim
using Qecsim.GenericModels: DepolarizingErrorModel, NaiveDecoder
using TensorNetworkCodes
using TensorNetworkCodes.QecsimAdaptors
using Test

@testset "_tnpauli_to_bsf" begin
    # single operator
    str_pauli = "IXIYIZ"
    int_pauli = pauli_rep_change.(collect(str_pauli))
    bsf_pauli = QecsimAdaptors._tnpauli_to_bsf(int_pauli)
    @test bsf_pauli == Qecsim.to_bsf(str_pauli)
    # multiple operators
    str_paulis = ["XZZXI", "IXZZX", "XIXZZ", "ZXIXZ"]
    int_paulis = [pauli_rep_change.(collect(p)) for p in str_paulis]
    bsf_paulis = QecsimAdaptors._tnpauli_to_bsf(int_paulis)
    @test bsf_paulis == Qecsim.to_bsf(str_paulis)
end

@testset "_bsf_to_tnpauli" begin
    # single operator
    str_pauli = "IXIYIZ"
    bsf_pauli = Qecsim.to_bsf(str_pauli)
    int_pauli = QecsimAdaptors._bsf_to_tnpauli(bsf_pauli)
    @test int_pauli == pauli_rep_change.(collect(str_pauli))
    # multiple operators
    str_paulis = ["XZZXI", "IXZZX", "XIXZZ", "ZXIXZ"]
    bsf_paulis = Qecsim.to_bsf(str_paulis)
    int_paulis = QecsimAdaptors._bsf_to_tnpauli(bsf_paulis)
    @test int_paulis == [pauli_rep_change.(collect(p)) for p in str_paulis]
end

@testset "QecsimTNCode" begin
    # default distance, label
    tn_code = TensorNetworkCode(five_qubit_code())
    qs_code = QecsimTNCode(tn_code)
    @test validate(qs_code) === nothing  # no error
    @test isequal(nkd(qs_code), (5, 1, missing))
    @test label(qs_code) == "QecsimTNCode: [5,1,missing]"
    # kwargs distance, label
    tn_code = TensorNetworkCode(steane_code())
    qs_code = QecsimTNCode(tn_code; distance=3, label="Steane")
    @test validate(qs_code) === nothing  # no error
    @test isequal(nkd(qs_code), (7, 1, 3))
    @test label(qs_code) == "Steane"
end

@testset "QecsimTNDecoder" begin
    # field test
    @test label(QecsimTNDecoder()) == "QecsimTNDecoder"
    @test label(QecsimTNDecoder(1)) == "QecsimTNDecoder (chi=1)"
    # invalid parameters
    @test_throws ArgumentError QecsimTNDecoder(-1)
    # models
    tn_code = rotated_surface_code(3)
    qs_code = QecsimTNCode(tn_code; distance=3, label="Rotated Surface 3")
    qs_error_model = DepolarizingErrorModel()
    qs_decoder = QecsimTNDecoder()
    p = 0.1
    # direct test of decoder (exact contraction)
    qs_error = generate(qs_error_model, qs_code, p)
    qs_syndrome = bsp(stabilizers(qs_code), qs_error)
    qs_result = decode(qs_decoder, qs_code, qs_syndrome; p=p)
    @test bsp(stabilizers(qs_code), qs_result.recovery) == qs_syndrome
    @test !any(bsp(stabilizers(qs_code), xor.(qs_error, qs_result.recovery)))
    @test 0 <= qs_result.custom_values[1][1] <= 1 # success probability
    # direct test of decoder (approx. contraction)
    qs_result = decode(QecsimTNDecoder(1), qs_code, qs_syndrome; p=p)
    @test bsp(stabilizers(qs_code), qs_result.recovery) == qs_syndrome
    @test !any(bsp(stabilizers(qs_code), xor.(qs_error, qs_result.recovery)))
    @test 0 <= qs_result.custom_values[1][1] <= 1 # success probability
    # test via run_once
    qec_run_once(qs_code, qs_error_model, qs_decoder, p)  # no error
end


text:
# Events for timing

import Base: unsafe_convert

export CuEvent, record, synchronize, elapsed

typealias CuEvent_t Ptr{Void}

immutable CuEvent
    handle::CuEvent_t

    function CuEvent()
        handle_ref = Ref{CuEvent_t}()
        @apicall(:cuEventCreate, (Ptr{CuEvent_t}, Cuint), handle_ref, 0)
        return new(handle_ref[])
    end
end

unsafe_convert(::Type{CuEvent_t}, e::CuEvent) = e.handle

record(e::CuEvent, stream=default_stream()) =
    @apicall(:cuEventRecord, (CuEvent_t, CuStream_t), e, stream)

synchronize(e::CuEvent) = @apicall(:cuEventSynchronize, (CuEvent_t,), e)

function elapsed(start::CuEvent, stop::CuEvent)
    time_ref = Ref{Cfloat}()
    @apicall(:cuEventElapsedTime, (Ptr{Cfloat}, CuEvent_t, CuEvent_t),
                                  time_ref, start, stop)
    return time_ref[]
end

destroy(e::CuEvent) = @apicall(:cuEventDestroy, (CuEvent_t,), e)


text:
import accrue.cryptoerase.runtime.Condition;

class C {
    int{L} x = 7;
    void m() {
	final Condition c = new Condition();
	int y = ({L /c H}) 42;
	int z = 0;
	if (y > 0) {
	    c.set();
	    z = 4; // level of z should be H, since the PC should have been raised since c has been set.
	}
	this.x = z; // We should reject this assignment since c may have been set
    }

    public static void main(String[] args) {
	new C().m();
    }
}

max_stars_repo_name: HarvardPL/cryptoerase

max_issues_repo_name: HarvardPL/cryptoerase

max_forks_repo_name: HarvardPL/cryptoerase


text:
struct DatasetContainer{T}
    duals::Dict{ConstraintKey, T}
    aux_variables::Dict{AuxVarKey, T}
    variables::Dict{VariableKey, T}
    parameters::Dict{ParameterKey, T}
    expressions::Dict{ExpressionKey, T}
end

function DatasetContainer{T}() where {T <: AbstractDataset}
    return DatasetContainer(
        Dict{ConstraintKey, T}(),
        Dict{AuxVarKey, T}(),
        Dict{VariableKey, T}(),
        Dict{ParameterKey, T}(),
        Dict{ExpressionKey, T}(),
    )
end

function Base.empty!(container::DatasetContainer)
    for field in fieldnames(DatasetContainer)
        field_dict = getfield(container, field)
        for val in values(field_dict)
            empty!(val)
        end
    end
    @debug "Emptied the store" _group = LOG_GROUP_SIMULATION_STORE
    return
end

function get_duals_values(container::DatasetContainer{DataFrameDataset})
    return container.duals
end

function get_aux_variables_values(container::DatasetContainer{DataFrameDataset})
    return container.aux_variables
end

function get_variables_values(container::DatasetContainer{DataFrameDataset})
    return container.variables
end

function get_parameters_values(container::DatasetContainer{DataFrameDataset})
    return container.parameters
end

function get_expression_values(container::DatasetContainer{DataFrameDataset})
    return container.expressions
end

function get_duals_values(::DatasetContainer{HDF5Dataset})
    error("Operation not allowed on a HDF5Dataset.")
end

function get_aux_variables_values(::DatasetContainer{HDF5Dataset})
    error("Operation not allowed on a HDF5Dataset.")
end

function get_variables_values(::DatasetContainer{HDF5Dataset})
    error("Operation not allowed on a HDF5Dataset.")
end

function get_parameters_values(::DatasetContainer{HDF5Dataset})
    error("Operation not allowed on a HDF5Dataset.")
end

function get_expression_values(::DatasetContainer{HDF5Dataset})
    error("Operation not allowed on a HDF5Dataset.")
end

function get_dataset_keys(container::DatasetContainer)
    return Iterators.flatten(
        keys(getfield(container, f)) for f in fieldnames(DatasetContainer)
    )
end

function get_dataset(container::DatasetContainer, key::OptimizationContainerKey)
    datasets = getfield(container, get_store_container_type(key))
    return datasets[key]
end

function set_dataset!(
    container::DatasetContainer{T},
    key::OptimizationContainerKey,
    val::T,
) where {T <: AbstractDataset}
    datasets = getfield(container, get_store_container_type(key))
    datasets[key] = val
    return
end

function has_dataset(container::DatasetContainer, key::OptimizationContainerKey)
    datasets = getfield(container, get_store_container_type(key))
    return haskey(datasets, key)
end

function get_dataset(
    container::DatasetContainer,
    ::T,
    ::Type{U},
) where {T <: ConstraintType, U <: Union{PSY.Component, PSY.System}}
    return get_dataset(container, ConstraintKey(T, U))
end

function get_dataset(
    container::DatasetContainer,
    ::T,
    ::Type{U},
) where {T <: VariableType, U <: Union{PSY.Component, PSY.System}}
    return get_dataset(container, VariableKey(T, U))
end

function get_dataset(
    container::DatasetContainer,
    ::T,
    ::Type{U},
) where {T <: AuxVariableType, U <: Union{PSY.Component, PSY.System}}
    return get_dataset(container, AuxVarKey(T, U))
end

function get_dataset(
    container::DatasetContainer,
    ::T,
    ::Type{U},
) where {T <: ParameterType, U <: Union{PSY.Component, PSY.System}}
    return get_dataset(container, ParameterKey(T, U))
end

function get_dataset(
    container::DatasetContainer,
    ::T,
    ::Type{U},
) where {T <: ExpressionType, U <: Union{PSY.Component, PSY.System}}
    return get_dataset(container, ExpressionKey(T, U))
end

# Get dataset values is currently type unstable since the values field could be a DF
function get_dataset_values(container::DatasetContainer, key::OptimizationContainerKey)
    return get_dataset(container, key).values
end

function get_dataset_values(
    container::DatasetContainer,
    ::T,
    ::Type{U},
) where {T <: ConstraintType, U <: Union{PSY.Component, PSY.System}}
    return get_dataset_values(container, ConstraintKey(T, U))
end

function get_dataset_values(
    container::DatasetContainer,
    ::T,
    ::Type{U},
) where {T <: VariableType, U <: Union{PSY.Component, PSY.System}}
    return get_dataset_values(container, VariableKey(T, U))
end

function get_dataset_values(
    container::DatasetContainer,
    ::T,
    ::Type{U},
) where {T <: AuxVariableType, U <: Union{PSY.Component, PSY.System}}
    return get_dataset_values(container, AuxVarKey(T, U))
end

function get_dataset_values(
    container::DatasetContainer,
    ::T,
    ::Type{U},
) where {T <: ExpressionType, U <: Union{PSY.Component, PSY.System}}
    return get_dataset_values(container, ExpressionKey(T, U))
end

function get_dataset_values(
    container::DatasetContainer,
    key::OptimizationContainerKey,
    date::Dates.DateTime,
)
    return get_dataset_value(get_dataset(container, key), date)
end

function get_last_recorded_row(container::DatasetContainer, key::OptimizationContainerKey)
    return get_last_recorded_row(get_dataset(container, key))
end

"""
Return the timestamp from the data used in the last update
"""
function get_update_timestamp(container::DatasetContainer, key::OptimizationContainerKey)
    return get_update_timestamp(get_dataset(container, key))
end

"""
Return the timestamp from most recent data row updated in the dataset. This value may not be the same as the result from `get_update_timestamp`
"""
function get_last_updated_timestamp(
    container::DatasetContainer,
    key::OptimizationContainerKey,
)
    return get_last_updated_timestamp(get_dataset(container, key))
end

function get_last_update_value(container::DatasetContainer, key::OptimizationContainerKey)
    return get_last_recorded_value(get_dataset(container, key))
end

function set_dataset_values!(
    container::DatasetContainer,
    key::OptimizationContainerKey,
    index::Int,
    vals,
)
    set_value!(get_dataset(container, key), vals, index)
    return
end


text:
module XKPasswd

"""
`XKPasswd` generates memorable passwords for you in the style of diceware and
[xkcd #936](https://xkcd.com/936/).

This module does not export symbols but the main functions of interest are:

- `XKPasswd.generate`: gives an array of generated passwords
- `XKPasswd.pwentropy`: gives the bits of entropy in the password, with
  knowledge of the wordlist used and formatting
- `XKPasswd.pw100yattrate`: estimates the guess attempt rate needed to brute
  force the password within 100 years, with knowledge of the wordlist used and
  formatting
- `XKPasswd.spin_the_wheel`: cycles through random passwords until you stop it
  (should be used from REPL or a terminal)

!!! warning

    Diceware fairly explicitly tells you to use dice for randomness and *not* a
    PRNG, so keep that in mind. (Do you know where your entropy comes from?)
"""
XKPasswd

using Base.prettyprint_getunits

const superunits = ["", " k", " M", " G", " T", " P", " E", " Z", " Y"]
const secper100y = 3.154e9

datapath = joinpath(dirname(@__FILE__), "..", "data")
google10kpath = joinpath(datapath, "google-10000-english")

pwentropy(n, total, digit) = n*log2(total) + (digit ? log2(10) : 0)
pw100yattrate(s) = BigFloat(2)^s / secper100y

function pw100yattrate_pretty(s::Real)::AbstractString
    rate = pw100yattrate(s)
    if rate < 1
        @sprintf("%.1E", s)
    else
        (atts, unit) = prettyprint_getunits(rate, length(superunits), 1000)
        string(round(BigInt, atts), superunits[unit])
    end
end

"""
    @enum WordList

An enum type used to indicate which of the builtin wordlists to use.

The elements are:
+ `XKPasswd.simple`, a list of 2248 simple words
+ `XKPasswd.jargon`, a list of 9460 more complicated words
+ `XKPasswd.immemorable`, the list of all 94 non-whitespace printable ASCII
  characters (probably want to use `delimstr=""` and lots of "words")
+ `XKPasswd.google_20k`, a list of 20k words with *UK spelling*
+ `XKPasswd.google_10k`, a list of 10k words with *UK spelling*
+ `XKPasswd.google_10k_clean`, (86 "bad" words removed) with *UK spelling*
+ `XKPasswd.google_10k_usa` the 10k list with *USA spelling*
+ `XKPasswd.google_10k_usa_clean` (98 "bad words removed)
+ `XKPasswd.google_10k_usa_clean_short` 2186 words with length < 5
+ `XKPasswd.google_10k_usa_clean_medium` 5471 words with length in [5,8]
+ `XKPasswd.google_10k_usa_clean_long` 2246 words with length > 8
"""
@enum WordList simple jargon immemorable chinese google_20k google_10k google_10k_clean google_10k_usa google_10k_usa_clean google_10k_usa_clean_short google_10k_usa_clean_medium google_10k_usa_clean_long

wordlistfiles = Dict(simple => joinpath(datapath, "simple.txt"),
                     jargon => joinpath(datapath, "jargon.txt"),
                     immemorable => joinpath(datapath, "immemorable.txt"),
                     chinese => joinpath(datapath, "chinese.txt"),
                     google_20k => joinpath(google10kpath, "20k.txt"),
                     google_10k => joinpath(google10kpath,
                                            "google-10000-english.txt"),
                     google_10k_clean => joinpath(google10kpath,
                         "google-10000-english-no-swears.txt"),
                     google_10k_usa => joinpath(google10kpath,
                         "google-10000-english-usa.txt"),
                     google_10k_usa_clean => joinpath(google10kpath,
                         "google-10000-english-usa-no-swears.txt"),
                     google_10k_usa_clean_short => joinpath(google10kpath,
                         "google-10000-english-usa-no-swears-short.txt"),
                     google_10k_usa_clean_medium => joinpath(google10kpath,
                         "google-10000-english-usa-no-swears-medium.txt"),
                     google_10k_usa_clean_long => joinpath(google10kpath,
                         "google-10000-english-usa-no-swears-long.txt"))

function stats(n, l, d)::AbstractString
    s = pwentropy(n, l, d)
    string("Entropy: ~", round(Int, s), " bits; 100y BF attempt rate: ",
           pw100yattrate_pretty(s), " att/s.")
end

"""
    XKPasswd.generate(n[, wordlist=XKPasswd.simple]; <keyword arguments>)

Generate an array of memorable passwords of a given specification.

# Arguments
* `n::Integer`: the number of random words per password
* `wordlist::WordList=XKPasswd.simple`: selection from the bundled word list options OR
* `wordlist::AbstractString`: the path to a newline delimited word list file
* `npws::integer=1`: the number of passwords to generate
* `captialize::Bool=false`: whether to capitalize the first letter of each word
* `delimstr::AbstractString=" "`: what to insert between each word
* `append_digit::Bool=false`: whether to tack on a single digit at the end
* `quiet::Bool=false`: whether to print entropy information to STDERR

# Examples

```julia
julia> XKPasswd.generate(4) # output here is just a joke
Entropy: ~45 bits; 100y BF attempt rate: 9 k att/s.
1-element Array{String,1}:
 "correct horse battery staple"
```
"""
function generate(n::Integer, wordlist::AbstractString; npws::Integer=1,
                  capitalize::Bool=false, delimstr::AbstractString=" ",
                  append_digit::Bool=false, quiet::Bool=false)
    @assert n > 0 "Must use at least 1 random word"
    @assert npws > 0 "Must generate at least 1 password"
    open(wordlist) do f
#        lines = readlines(f, chomp=true)
        lines = readlines(f);

        if (!quiet)
            println(STDERR, stats(n, length(lines), append_digit))
        end

        [(
#            words = rand(lines, n);
            words = map(chomp, rand(lines, n));
            cased_words = capitalize ?  map(ucfirst, words) : words;
            string(join(cased_words, delimstr),
                   append_digit ? "$(delimstr)$(rand(0:9))" : "")
         ) for k in 1:npws]
    end
end

function generate(n::Integer, wordlist::WordList=simple; npws::Integer=1,
                  capitalize::Bool=false, delimstr::AbstractString=" ",
                  append_digit::Bool=false, quiet::Bool=false)
    generate(n, wordlistfiles[wordlist], npws=npws, capitalize=capitalize,
             delimstr=delimstr, append_digit=append_digit, quiet=quiet)
end

"""
    XKPasswd.spin_the_wheel(n::Integer=4[, wordlist=XKPasswd.simple]; <keyword arguments>)

Starts cycling through randomly generated passwords, selecting the last one once
you hit [Enter] on your keyboard. Arguments are the same as in
[`XKPasswd.generate`](@ref), though without `npws` and `quiet`.

!!! note

    This function puts VT100 commands to `STDOUT` and reads from file descriptor
    `0`, so it might not be applicable in all situations.
"""
function spin_the_wheel(n::Integer, wordlist::AbstractString;
                        capitalize::Bool=false, delimstr::AbstractString=" ",
                        append_digit::Bool=false)
    open(wordlist) do f
        lines = readlines(f);
        println(STDERR, stats(n, length(lines), append_digit))
    end
    println("Spinning... Press [enter] to end\n\n")
    while true
        ev = poll_fd(RawFD(0), 0, readable=true)
        p = rand(XKPasswd.generate(n, wordlist, npws=20, quiet=true,
                                   capitalize=capitalize, delimstr=delimstr,
                                   append_digit=append_digit))
        print("\u1b[1A\u1b[K\u1b[1K")
        println(p)
        if ev.readable
            print("\u1b[1A\u1b[K\u1b[1K")
            break
        end
    end
end

function spin_the_wheel(n::Integer=4, wordlist::WordList=simple;
                        capitalize::Bool=false, delimstr::AbstractString=" ",
                        append_digit::Bool=false)
    spin_the_wheel(n, wordlistfiles[wordlist], capitalize=capitalize,
                   delimstr=delimstr, append_digit=append_digit)
end

end # module


text:
const rebug_prompt_string = "rebug> "
const rebug_prompt_ref = Ref{Union{LineEdit.Prompt,Nothing}}(nothing)       # set by __init__
const interpret_prompt_ref = Ref{Union{LineEdit.Prompt,Nothing}}(nothing)   # set by __init__

# For debugging
function logaction(msg)
    open("/tmp/rebugger.log", "a") do io
        println(io, "* ", msg)
        flush(io)
    end
    nothing
end

dummy() = nothing
const dummymethod = first(methods(dummy))
const dummyuuid   = UUID(UInt128(0))

uuidextractor(str) = match(r"getstored\(\"([a-z0-9\-]+)\"\)", str)

mutable struct RebugHeader <: AbstractHeader
    warnmsg::String
    errmsg::String
    uuid::UUID
    current_method::Method
    nlines::Int   # size of the printed header
end
RebugHeader() = RebugHeader("", "", dummyuuid, dummymethod, 0)

mutable struct InterpretHeader <: AbstractHeader
    frame::Union{Nothing,Frame}
    leveloffset::Int
    val
    bt
    warnmsg::String
    errmsg::String
    nlines::Int   # size of the printed header
end
InterpretHeader() = InterpretHeader(nothing, 0, nothing, nothing, "", "", 0)

struct DummyAST end  # fictive input for the put!/take! evaluation by the InterpretREPL backend

header(s::LineEdit.MIState) = header(mode(s).repl)
header(repl::HeaderREPL) = repl.header
header(::LineEditREPL) = header(rebug_prompt_ref[].repl)  # default to the Rebug header

# Custom methods
set_method!(header::RebugHeader, method::Method) = header.current_method = method

function set_uuid!(header::RebugHeader, uuid::UUID)
    if haskey(stored, uuid)
        header.uuid = uuid
        header.current_method = stored[uuid].method
    else
        header.uuid = dummyuuid
        header.current_method = dummymethod
    end
    uuid
end

function set_uuid!(header::RebugHeader, str::AbstractString)
    m = uuidextractor(str)
    uuid = if m isa RegexMatch && length(m.captures) == 1
        UUID(m.captures[1])
    else
        dummyuuid
    end
    set_uuid!(header, uuid)
end

struct FakePrompt{Buf<:IO}
    input_buffer::Buf
end
LineEdit.mode(p::FakePrompt) = rebug_prompt_ref[]

"""
    stepin(s)

Given a buffer `s` representing a string and "point" (the seek position) set at a call expression,
replace the contents of the buffer with a `let` expression that wraps the *body* of the callee.

For example, if `s` has contents

    <some code>
    if x > 0.5
        ^fcomplex(x)
        <more code>

where in the above `^` indicates `position(s)` ("point"), and if the definition of `fcomplex` is

    function fcomplex(x::A, y=1, z=""; kw1=3.2) where A<:AbstractArray{T} where T
        <body>
    end

rewrite `s` so that its contents are

    @eval ModuleOf_fcomplex let (x, y, z, kw1, A, T) = Main.Rebugger.getstored(id)
        <body>
    end

where `Rebugger.getstored` returns has been pre-loaded with the values that would have been
set when you called `fcomplex(x)` in `s` above.
This line can be edited and `eval`ed at the REPL to analyze or improve `fcomplex`,
or can be used for further `stepin` calls.
"""
function stepin(s::LineEdit.MIState)
    # Add the command we're tracing to the history. That way we can go "up the call stack".
    pos = position(s)
    cmd = String(take!(copy(LineEdit.buffer(s))))
    add_history(s, cmd)
    # Analyze the command string and step in
    local uuid, letcmd
    try
        uuid, letcmd = stepin(LineEdit.buffer(s))
    catch err
        repl = rebug_prompt_ref[].repl
        handled = false
        if err isa StashingFailed
            repl.header.warnmsg = "Execution did not reach point"
            handled = true
        elseif err isa Meta.ParseError || err isa StepException
            repl.header.warnmsg = "Expression at point is not a call expression"
            handled = true
        elseif err isa EvalException
            io = IOBuffer()
            showerror(io, err.exception)
            errstr = String(take!(io))
            repl.header.errmsg = "$errstr while evaluating $(err.exprstring)"
            handled = true
        elseif err isa DefMissing
            repl.header.errmsg = "The expression for method $(err.method) was unavailable. Perhaps it was untracked or generated by code."
            handled = true
        end
        if handled
            buf = LineEdit.buffer(s)
            LineEdit.edit_clear(buf)
            write(buf, cmd)
            seek(buf, pos)
            return nothing
        end
        rethrow(err)
    end
    set_uuid!(header(s), uuid)
    LineEdit.edit_clear(s)
    LineEdit.edit_insert(s, letcmd)
    return nothing
end

function capture_stacktrace(s)
    if mode(s) isa LineEdit.PrefixHistoryPrompt
        # history search, re-enter with the corresponding mode
        LineEdit.accept_result(s, mode(s))
        return capture_stacktrace(s)
    end
    cmdstring = LineEdit.content(s)
    add_history(s, cmdstring)
    print(REPL.terminal(s), '\n')
    expr = Meta.parse(cmdstring)
    local uuids
    try
        uuids = capture_stacktrace(expr)
    catch err
        print(stderr, err)
        return nothing
    end
    io = IOBuffer()
    buf = FakePrompt(io)
    hp = mode(s).hist
    for uuid in uuids
        println(io, generate_let_command(uuid))
        REPL.add_history(hp, buf)
        take!(io)
    end
    hp.cur_idx = length(hp.history) + 1
    if !isempty(uuids)
        set_uuid!(header(s), uuids[end])
        print(REPL.terminal(s), '\n')
        LineEdit.edit_clear(s)
        LineEdit.enter_prefix_search(s, find_prompt(s, LineEdit.PrefixHistoryPrompt), true)
    end
    return nothing
end

function add_history(s, str::AbstractString)
    io = IOBuffer()
    buf = FakePrompt(io)
    hp = mode(s).hist
    println(io, str)
    REPL.add_history(hp, buf)
end

function interpret(s)
    hdr = header(s)
    hdr.bt = nothing
    term = REPL.terminal(s)
    cmdstring = LineEdit.content(s)
    isempty(cmdstring) && return :done
    add_history(s, cmdstring)
    assigns, expr, display_result = simplecall(cmdstring)
    tupleexpr = JuliaInterpreter.extract_args(Main, expr)
    callargs = Core.eval(Main, tupleexpr)   # get the elements of the call
    callexpr = Expr(:call, callargs...)
    frame = JuliaInterpreter.enter_call_expr(callexpr)
    if frame === nothing
        local val
        try
            hdr.val = Core.eval(Main, callexpr)
        catch err
            hdr.val = err
            hdr.bt = catch_backtrace()
        end
    else
        # frame = JuliaInterpreter.maybe_step_through_wrapper!(frame)
        hdr.frame = frame
        deflines = expression_lines(frame)

        print(term, '\n') # to advance beyond the user's input line
        nlines = 0
        try
            while true
                HeaderREPLs.clear_nlines(term, nlines)
                print_header(term, hdr)
                if hdr.leveloffset == 0
                    nlines = show_code(term, frame, deflines, nlines)
                else
                    f, Δ = frameoffset(frame, hdr.leveloffset)
                    hdr.leveloffset -= Δ
                    nlines = show_code(term, f, expression_lines(f), nlines)
                end
                cmd = read(term, Char)
                if cmd == '?'
                    hdr.warnmsg = """
                    Commands:
                      space: next line
                      enter: continue to next breakpoint or completion
                          →: step in to next call
                          ←: finish frame and return to caller
                          ↑: display the caller frame
                          ↓: display the callee frame
                          b: insert breakpoint at current line
                          c: insert conditional breakpoint at current line
                          r: remove breakpoint at current line
                          d: disable breakpoint at current line
                          e: enable breakpoint at current line
                          o: open current position in editor
                          q: abort (returns nothing)"""
                elseif cmd == ' '
                    hdr.leveloffset = 0
                    ret = debug_command(frame, :n)
                    if ret === nothing
                        hdr.val = JuliaInterpreter.get_return(root(frame))
                        break
                    end
                    frame, deflines = refresh(frame, ret, deflines)
                elseif cmd == '\n' || cmd == '\r'
                    hdr.leveloffset = 0
                    ret = debug_command(frame, :c)
                    if ret === nothing
                        hdr.val = JuliaInterpreter.get_return(root(frame))
                        break
                    end
                    frame, deflines = refresh(frame, ret, deflines)
                elseif cmd == 'q'
                    hdr.val = nothing
                    break
                elseif cmd == 'o'
                    f, Δ = frameoffset(frame, hdr.leveloffset)
                    file, line = whereis(f)
                    edit(file, line)
                elseif cmd == '\e'   # escape codes
                    nxtcmd = read(term, Char)
                    nxtcmd == "O" && (nxtcmd = '[')  # normalize escape code
                    cmd *= nxtcmd
                    while nxtcmd == '['
                        nxtcmd = read(term, Char)
                        cmd *= nxtcmd
                    end
                    if cmd == "\e[C"  # right arrow
                        hdr.leveloffset = 0
                        ret = debug_command(frame, :s)
                        if ret === nothing
                            # Trying to "step in" at program exit
                            hdr.val = JuliaInterpreter.get_return(frame)
                            break
                        end
                        frame, deflines = refresh(frame, ret, deflines)
                    elseif cmd == "\e[D"  # left arrow
                        hdr.leveloffset = 0
                        ret = debug_command(frame, :finish)
                        if ret === nothing
                            hdr.val = JuliaInterpreter.get_return(root(frame))
                            break
                        end
                        frame, deflines = refresh(frame, ret, deflines)
                    elseif cmd == "\e[A"  # up arrow
                        hdr.leveloffset += 1
                    elseif cmd == "\e[B"  # down arrow
                        hdr.leveloffset = max(0, hdr.leveloffset - 1)
                    end
                elseif cmd == 'b' || cmd == 'c'
                    if cmd == 'b'
                        cond = nothing
                    else
                        print(term, "enter condition: ")
                        condstr = ""
                        c = read(term, Char)
                        while c != '\n' && c != '\r'
                            print(term, c)
                            condstr *= c
                            c = read(term, Char)
                        end
                        condex = Base.parse_input_line(condstr; filename="condition")
                        cond = (JuliaInterpreter.moduleof(frame), condex)
                    end
                    ret = JuliaInterpreter.whereis(frame)
                    if ret === nothing
                        @warn "Failed to find location info at current statement"
                    else
                        file, line = ret
                        JuliaInterpreter.breakpoint(file, line, cond)
                    end
                elseif cmd == 'r'
                    breakpoint_action(remove, frame)
                elseif cmd == 'd'
                    breakpoint_action(disable, frame)
                elseif cmd == 'e'
                    breakpoint_action(enable, frame)
                else
                    push!(msgs, cmd)
                end
                hdr.frame = frame
            end
        catch err
            hdr.val = err
            hdr.bt = catch_backtrace()
        end
    end
    # Store the result
    repl = mode(s).repl
    if isdefined(repl, :backendref)
        response = (display_result ? hdr.val : nothing, VERSION >= v"1.2.0-DEV.249" ? hdr.bt !== nothing : hdr.bt)
        put!(repl.backendref.response_channel, response)
    end
    hdr.frame = nothing
    # Do this last in case of errors
    if assigns !== nothing && hdr.bt === nothing
        Core.eval(Main, Expr(:(=), assigns, hdr.val))
    end
    return :done
end

function refresh(frame, ret, deflines)
    @assert ret !== nothing
    cframe, _ = ret
    if cframe === frame
        return frame, deflines
    end
    return cframe, expression_lines(cframe)
end

# Find the range of statement indexes that preceed a line
# `thisline` should be in "compiled" numbering
function coderange(src::CodeInfo, thisline)
    codeloc = searchsortedfirst(src.linetable, LineNumberNode(thisline, ""); by=x->x.line)
    if codeloc == 1
        return 1:1
    end
    idxline = searchsortedfirst(src.codelocs, codeloc)
    idxprev = searchsortedfirst(src.codelocs, codeloc-1) + 1
    return idxprev:idxline
end
coderange(framecode::FrameCode, thisline) = coderange(framecode.src, thisline)

function breakpoint_action(f, frame)
    ret = CodeTracking.whereis(frame)
    if ret === nothing
        @warn "Failed to find location info at current statement"
    else
        file, line = ret
        for bp in JuliaInterpreter.breakpoints()
            if bp isa JuliaInterpreter.BreakpointFileLocation && bp.path == file && bp.line == line
                f(bp)
            end
        end
    end
    return nothing
end

function simplecall(cmdstring)
    cmdstring = chomp(cmdstring)
    display_result = !endswith(cmdstring, ';')
    if !display_result
        cmdstring = cmdstring[1:end-1]
    end
    expr = Meta.parse(cmdstring)
    if expr.head == :(=)
        assigns = expr.args[1]
        expr = expr.args[2]
    else
        assigns = nothing
    end
    return assigns, expr, display_result
end

### REPL modes

function HeaderREPLs.setup_prompt(repl::HeaderREPL{RebugHeader}, hascolor::Bool)
    julia_prompt = find_prompt(repl.interface, "julia")

    prompt = REPL.LineEdit.Prompt(
        rebug_prompt_string;
        prompt_prefix = hascolor ? repl.prompt_color : "",
        prompt_suffix = hascolor ?
            (repl.envcolors ? Base.input_color : repl.input_color) : "",
        complete = julia_prompt.complete,
        on_enter = REPL.return_callback)

    prompt.on_done = HeaderREPLs.respond(repl, julia_prompt) do str
        Base.parse_input_line(str; filename="REBUG")
    end
    # hist will be handled automatically if repl.history_file is true
    # keymap_dict is separate
    return prompt, :rebug
end

function HeaderREPLs.append_keymaps!(keymaps, repl::HeaderREPL{RebugHeader})
    julia_prompt = find_prompt(repl.interface, "julia")
    kms = [
        trigger_search_keymap(repl),
        mode_termination_keymap(repl, julia_prompt),
        trigger_prefix_keymap(repl),
        REPL.LineEdit.history_keymap,
        REPL.LineEdit.default_keymap,
        REPL.LineEdit.escape_defaults,
    ]
    append!(keymaps, kms)
end

# To get it to parse the UUID whenever we move through the history, we have to specialize
# this method
function HeaderREPLs.activate_header(header::RebugHeader, p, s, termbuf, term)
    str = String(take!(copy(LineEdit.buffer(s))))
    set_uuid!(header, str)
end

## Interpret also requires a separate repl

function HeaderREPLs.setup_prompt(repl::HeaderREPL{InterpretHeader}, hascolor::Bool)
    julia_prompt = find_prompt(repl.interface, "julia")

    prompt = REPL.LineEdit.Prompt(
        "interpret> ";   # should never be shown
        prompt_prefix = hascolor ? repl.prompt_color : "",
        prompt_suffix = hascolor ?
            (repl.envcolors ? Base.input_color : repl.input_color) : "",
        complete = julia_prompt.complete,
        on_enter = REPL.return_callback)

    prompt.on_done = HeaderREPLs.respond(repl, julia_prompt) do str
        return DummyAST()
    end
    return prompt, :interpret
end

function HeaderREPLs.append_keymaps!(keymaps, repl::HeaderREPL{InterpretHeader})
    # No keymaps
    return keymaps
end

function HeaderREPLs.activate_header(header::InterpretHeader, p, s, termbuf, term)
end

function Base.put!(c::Channel, input::Tuple{DummyAST,Int})
    return nothing
end

const keybindings = Dict{Symbol,String}(
    :stacktrace => "\es",                        # Alt-s ("[s]tacktrace")
    :stepin => "\ee",                            # Alt-e ("[e]nter")
    :interpret => "\ei",                         # Alt-i ("[i]nterpret")
)

const modeswitches = Dict{Any,Any}(
    :stacktrace => (s, o...) -> capture_stacktrace(s),
    :stepin => (s, o...) -> (stepin(s); enter_rebug(s)),
    :interpret => (s, o...) -> (enter_interpret(s); interpret(s)),
)

function get_rebugger_modeswitch_dict()
    rebugger_modeswitch = Dict()
    for (action, keybinding) in keybindings
        rebugger_modeswitch[keybinding] = modeswitches[action]
    end
    rebugger_modeswitch
end

function add_keybindings(main_repl; override::Bool=false, kwargs...)
    history_prompt = find_prompt(main_repl.interface, LineEdit.PrefixHistoryPrompt)
    julia_prompt = find_prompt(main_repl.interface, "julia")
    rebug_prompt = find_prompt(main_repl.interface, "rebug")
    for (action, keybinding) in kwargs
        if !(action in keys(keybindings))
            error("$action is not a supported action.")
        end
        if !(keybinding isa Union{String,Vector{String}})
            error("Expected the value for $action to be a String or Vector{String}, got $keybinding instead")
        end
        if haskey(keybindings, action)
            keybindings[action] = keybinding
        end
        # PackageCompiler can cause these keys to be added twice (once during compilation and once by __init__),
        # so put these in a try/catch (issue #62)
        if action == :interpret
            try
                LineEdit.add_nested_key!(julia_prompt.keymap_dict, keybinding, modeswitches[action], override=override)
            catch
            end
        else
            # We need Any here because "cannot convert REPL.LineEdit.PrefixHistoryPrompt to an object of type REPL.LineEdit.Prompt"
            prompts = Any[julia_prompt, rebug_prompt]
            if action == :stacktrace push!(prompts, history_prompt) end
            for prompt in prompts
                if keybinding isa Vector
                    for kb in keybinding
                        try
                            LineEdit.add_nested_key!(prompt.keymap_dict, kb, modeswitches[action], override=override)
                        catch
                        end
                    end
                else
                    try
                        LineEdit.add_nested_key!(prompt.keymap_dict, keybinding, modeswitches[action], override=override)
                    catch
                    end
                end
            end
        end
    end
end

# These work only at the `rebug>` prompt
const rebugger_keys = Dict{Any,Any}(
)

## REPL commands TODO?:
## "\em" (meta-m): create REPL line that populates Main with arguments to current method
## "\eS" (meta-S): save version at REPL to file? (a little dangerous, perhaps make it configurable as to whether this is on)
## F1 is "^[OP" (showvalues?), F4 is "^[OS" (showinputs?)

enter_rebug(s) = mode_switch(s, rebug_prompt_ref[])
enter_interpret(s) = mode_switch(s, interpret_prompt_ref[])

function mode_switch(s, other_prompt)
    buf = copy(LineEdit.buffer(s))
    LineEdit.edit_clear(s)
    LineEdit.transition(s, other_prompt) do
        LineEdit.state(s, other_prompt).input_buffer = buf
    end
end

# julia_prompt = find_prompt(main_repl.interface, "julia")
# julia_prompt.keymap_dict['|'] = (s, o...) -> enter_count(s)


text:
# SPDX-License-Identifier: MIT

macro cache(cache_dict::Symbol, expr::Expr)
    @assert expr.head == :(=) "can only cache assignment expression"
    sym = QuoteNode(expr.args[1])
    return quote
        local retval = $(esc(expr))
        $(esc(cache_dict))[$sym] = retval
        retval
    end
end

function logsumexp(x; dims=:)
    xmax = maximum(x, dims=dims)
    xmax + log.(sum(exp.(x .- xmax), dims=dims))
end

function init_gpu()
    device_reset!()

    for device in devices()
        try
            device!(device)
            @goto device_selected
        catch e
            @debug "$device is busy, trying the next one"
        end
    end
    if isnothing(selected_device)
        throw(ErrorException("could not set a working device, all devices appear to be busy"))
    end

    @label device_selected
    @info "using cuda device $(device())"
    return nothing
end

function _reallocate!(obj, allocator, visited = Set())
    for name in fieldnames(typeof(obj))
        prop = getproperty(obj, name)
        T = typeof(prop)
        if T <: EFD.AbstractParameter
            param = EFD.reallocate(prop, allocator)
            setproperty!(obj, name, param)
        elseif T <: BayesianParameter
            push!(visited, prop.prior)
            push!(visited, prop.posterior)
            newprior = _reallocate!(prop.prior, allocator, visited)
            newposterior = _reallocate!(prop.posterior, allocator, visited)
            setproperty!(obj, name, BayesianParameter(newprior, newposterior))
        else prop ∉ visited
            push!(visited, prop)
            _reallocate!(prop, allocator, visited)
        end
    end
    obj
end

gpu!(obj) = _reallocate!(obj, CuArray, Set())
cpu!(obj) = _reallocate!(obj, Array, Set())

function todict(t::NTuple{N,T}) where {N,T}
    d = Dict()
    d[:eltype] = T
    d[:length] = N
    for (i,el) in enumerate(t)
        d[Symbol("el_$(i)")] = todict(el)
    end
    d
end

function fromdict(T::Type{<:NTuple}, d::AbstractDict)
    a = []
    for i in 1:d[:length]
        push!(a, fromdict(d[:eltype], d[Symbol("el_$(i)")]))
    end
    tuple(a...)
end

max_stars_repo_name: BUTSpeechFIT/PPCA

max_issues_repo_name: BUTSpeechFIT/PPCA

max_forks_repo_name: BUTSpeechFIT/PPCA


text:
@testset "Not exported Interface" begin
    @test supertype(ImageInTerminal.TermColor256) <: ImageInTerminal.TermColorDepth
    @test supertype(ImageInTerminal.TermColor24bit) <: ImageInTerminal.TermColorDepth

    # This tests if the mapping from RGB to the
    # 256 ansi color codes is correct
    @testset "256 colors" begin
        # reference functions to compare against
        function _ref_col2ansi(r,g,b)
            r6, g6, b6 = map(c->round(Int, 5c), (r, g, b))
            16 + 36 * r6 + 6 * g6 + b6
        end
        function _ref_col2ansi(gr)
            round(Int, 232 + gr * 23)
        end
        @testset "RGB" begin
            for col in rand(RGB, 10)
                r, g, b = red(col), green(col), blue(col)
                ri, gi, bi = map(c->round(Int, 23c), (r, g, b))
                if ri == gi == bi
                    @test ImageInTerminal._colorant2ansi(col, ImageInTerminal.TermColor256()) === _ref_col2ansi(r)
                else
                    @test ImageInTerminal._colorant2ansi(col, ImageInTerminal.TermColor256()) === _ref_col2ansi(r, g, b)
                end
            end
        end
        @testset "Gray" begin
            for col in rand(Gray, 10)
                r = real(col)
                @test ImageInTerminal._colorant2ansi(col, ImageInTerminal.TermColor256()) === _ref_col2ansi(r)
            end
        end
    end

    # This tests if the mapping from RGB to the 24 bit r g b tuples
    # (which are in the set {0,1,...,255}) is correct.
    @testset "24 bit" begin
        @testset "RGB" begin
            for col in rand(RGB, 10)
                r, g, b = red(col), green(col), blue(col)
                ri, gi, bi = map(c->round(Int,255c), (r,g,b))
                @test ImageInTerminal._colorant2ansi(col, ImageInTerminal.TermColor24bit()) === (ri, gi, bi)
            end
        end
        @testset "Gray" begin
            for col in rand(Gray, 10)
                r = round(Int, 255*real(col))
                @test ImageInTerminal._colorant2ansi(col, ImageInTerminal.TermColor24bit()) === (r, r, r)
            end
        end
    end

    # Internally non RGB Colors should be converted to RGB
    # This tests if the result reflects that assumption
    @testset "Non RGB" begin
        for col_rgb in rand(RGB, 10)
            col_other = convert(HSV, col_rgb)
            @test ImageInTerminal._colorant2ansi(col_rgb, ImageInTerminal.TermColor24bit()) === ImageInTerminal._colorant2ansi(col_other, ImageInTerminal.TermColor24bit())
        end
    end

    # Internally all Alpha Colors should be stripped of their alpha
    # channel. This tests if the result reflects that assumption
    @testset "TransparentColor" begin
        for col in (rand(RGB, 10)..., rand(HSV, 10)...)
            acol = alphacolor(col, rand())
            @test ImageInTerminal._colorant2ansi(col, ImageInTerminal.TermColor24bit()) === ImageInTerminal._colorant2ansi(acol, ImageInTerminal.TermColor24bit())
        end
    end
end

# Tests that we don't pollute the calling namespace with
# exports that they don't need.
# Also compare functionality against the functions tested above
@testset "Exported Interface" begin
    @testset "Validate exported interface boundaries" begin
        @test_throws UndefVarError TermColor256()
        @test_throws UndefVarError TermColor24bit()
        @test_throws MethodError colorant2ansi(RGB(1.,1.,1.), ImageInTerminal.TermColor256())
        @test_throws MethodError colorant2ansi(RGB(1.,1.,1.), ImageInTerminal.TermColor24bit())
    end

    @testset "256 colors" begin
        for col in (rand(RGB, 10)..., rand(Gray, 10)...)
            # compare against non-exported interface,
            # which we already tested above
            @test colorant2ansi(col) === ImageInTerminal._colorant2ansi(col, ImageInTerminal.TermColor256())
        end
    end

    # Check if exported interface propagatres conversions
    @testset "Non RGB" begin
        for col_rgb in rand(RGB, 10)
            col_other = convert(HSV, col_rgb)
            @test colorant2ansi(col_rgb) === colorant2ansi(col_other)
        end
    end

    # Check if exported interface propagatres conversions
    @testset "TransparentColor" begin
        for col in (rand(RGB, 10)..., rand(HSV, 10)...)
            acol = alphacolor(col, rand())
            @test colorant2ansi(col) === colorant2ansi(acol)
        end
    end
end


text:
using Printf
using PyPlot
using DelimitedFiles

# specify workspace directory
ws_dir = pwd() * "/";

ref_file = ws_dir * "data/impresponse_a.dat";				# impulse response from Julia
dut_file = ws_dir * "Emulation-SW/x86simulator_output/output.dat";	# impulse response from AI engine simulation

# read the files into variables
ref = readdlm(ref_file);
dut = readdlm(dut_file);

err = ref - dut;	# calculate the difference

# plot the difference
plot(err);
grid("on");
title("Impulse Response Error");
xlabel("Sampling Index");
ylabel("Error");

@printf("eps(Float32) = %e\n", eps(Float32));
@printf("maximum(abs.(err) = %e\n", maximum(abs.(err)));

max_stars_repo_name: jlamperez/Vitis-Tutorials

max_issues_repo_name: jlamperez/Vitis-Tutorials

max_forks_repo_name: jlamperez/Vitis-Tutorials


text:
module BenchHashIndices

using BenchmarkTools
using Dictionaries
using OrderedCollections
# include("../contrib/OldHashDictionaries.jl")
# using .OldHashDictionaries

const suite = BenchmarkGroup()

sizes = [10, 100, 1000, 10_000]
cutoff = 101

function build_vector_by_insertion(n)
    out = Vector{Int}()
    for i in 1:n
        push!(out, i)
    end
    return out
end

function build_set_by_insertion(n)
    out = Set{Int}()
    for i in 1:n
        push!(out, i)
    end
    return out
end

function build_ordered_set_by_insertion(n)
    out = OrderedSet{Int}()
    for i in 1:n
        push!(out, i)
    end
    return out
end

function build_indices_by_insertion(n)
    out = ArrayIndices{Int}()
    for i in 1:n
        insert!(out, i)
    end
    return out
end

function build_hashindices_by_insertion(n)
    out = Indices{Int}()
    for i in 1:n
        insert!(out, i)
    end
    return out
end

# function build_old_hashindices_by_insertion(n)
#     out = HashIndices{Int}()
#     for i in 1:n
#         insert!(out, i)
#     end
#     return out
# end

function empty_by_deletion(set::Vector, n)
    for i in 1:n
        pop!(set)
    end
    return set
end

function empty_by_deletion(set::Set, n)
    for i in 1:n
        delete!(set, i)
    end
    return set
end

function empty_by_deletion(set::OrderedSet, n)
    for i in 1:n
        delete!(set, i)
    end
    return set
end

function empty_by_deletion(indices::AbstractIndices, n)
    for i in 1:n
        delete!(indices, i)
    end
    return indices
end

function foreachsum(set)
    count = Ref(0)
    foreach(x -> count[] += 1, set)
    return count[]
end

function all_in(set, n)
    out = true
    for i in 1:n
        out &= i in set
    end
    return out
end

function not_in(set, n)
    out = true
    for i in n+1:2n
        out &= i in set
    end
    return out
end

function basic_set_test(N)
    h = Set{Int}()
    out = true
    for i in 1:N
        push!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:2:N
        delete!(h, i)
    end
    for i in 1:N
        out &= (i in h) == iseven(i)
    end
    for i in 1:2:N
        push!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:N
        delete!(h, i)
    end
    out &= isempty(h)
    push!(h, 7)
    out &= 7 in h
    for i in 1:N
        push!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:2:N
        delete!(h, i)
    end
    for i in 1:N
        out &= (i in h) == iseven(i)
    end
    for i in N+1:2N
        push!(h, i)
    end
    for i in 1:2N
        out &= (i in h) == (i > N || iseven(i))
    end
    return out
end

function basic_ordered_set_test(N)
    h = OrderedSet{Int}()
    out = true
    for i in 1:N
        push!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:2:N
        delete!(h, i)
    end
    for i in 1:N
        out &= (i in h) == iseven(i)
    end
    for i in 1:2:N
        push!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:N
        delete!(h, i)
    end
    out &= isempty(h)
    push!(h, 7)
    out &= 7 in h
    for i in 1:N
        push!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:2:N
        delete!(h, i)
    end
    for i in 1:N
        out &= (i in h) == iseven(i)
    end
    for i in N+1:2N
        push!(h, i)
    end
    for i in 1:2N
        out &= (i in h) == (i > N || iseven(i))
    end
    return out
end

function basic_indices_test(N)
    h = ArrayIndices{Int}()
    out = true
    for i in 1:N
        insert!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:2:N
        delete!(h, i)
    end
    for i in 1:N
        out &= (i in h) == iseven(i)
    end
    for i in 1:2:N
        insert!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:N
        delete!(h, i)
    end
    out &= isempty(h)
    insert!(h, 7)
    out &= 7 in h
    for i in 1:N
        set!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:2:N
        delete!(h, i)
    end
    for i in 1:N
        out &= (i in h) == iseven(i)
    end
    for i in N+1:2N
        insert!(h, i)
    end
    for i in 1:2N
        out &= (i in h) == (i > N || iseven(i))
    end
    return out
end

function basic_hash_indices_test(N)
    h = Indices{Int}()
    out = true
    for i in 1:N
        insert!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:2:N
        delete!(h, i)
    end
    for i in 1:N
        out &= (i in h) == iseven(i)
    end
    for i in 1:2:N
        insert!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:N
        delete!(h, i)
    end
    out &= isempty(h)
    insert!(h, 7)
    out &= 7 in h
    for i in 1:N
        set!(h, i)
    end
    for i in 1:N
        out &= i in h
    end
    for i in 1:2:N
        delete!(h, i)
    end
    for i in 1:N
        out &= (i in h) == iseven(i)
    end
    for i in N+1:2N
        insert!(h, i)
    end
    for i in 1:2N
        out &= (i in h) == (i > N || iseven(i))
    end
    return out
end

# function basic_old_hash_indices_test(N)
#     h = HashIndices{Int}()
#     out = true
#     for i in 1:N
#         insert!(h, i)
#     end
#     for i in 1:N
#         out &= i in h
#     end
#     for i in 1:2:N
#         delete!(h, i)
#     end
#     for i in 1:N
#         out &= (i in h) == iseven(i)
#     end
#     for i in 1:2:N
#         insert!(h, i)
#     end
#     for i in 1:N
#         out &= i in h
#     end
#     for i in 1:N
#         delete!(h, i)
#     end
#     out &= isempty(h)
#     insert!(h, 7)
#     out &= 7 in h
#     for i in 1:N
#         set!(h, i)
#     end
#     for i in 1:N
#         out &= i in h
#     end
#     for i in 1:2:N
#         delete!(h, i)
#     end
#     for i in 1:N
#         out &= (i in h) == iseven(i)
#     end
#     for i in N+1:2N
#         insert!(h, i)
#     end
#     for i in 1:2N
#         out &= (i in h) == (i > N || iseven(i))
#     end
#     return out
# end

for n in sizes
    r = 1:n
    y = n ÷ 2
    pred1(x) = x != y
    pred2(x) = x == y
    mostly_unique = rand(1:n, n)
    sorted_mostly_unique = sort(mostly_unique)
    rarely_unique = rand(1:floor(Int, sqrt(n)), n)
    sorted_rarely_unique = sort(rarely_unique)

    if n < cutoff
        vec = collect(r)
        even_vec = collect(2:2:n)
        odd_vec = collect(1:2:n)

        indices = ArrayIndices(collect(r))
        even_indices = ArrayIndices(collect(2:2:n))
        odd_indices = ArrayIndices(collect(1:2:n))
    end

    set = Set(r)
    even_set = Set(2:2:n)
    odd_set = Set(1:2:n)

    ordered_set = OrderedSet(r)
    even_ordered_set = OrderedSet(2:2:n)
    odd_ordered_set = OrderedSet(1:2:n)

    hash_indices = Indices(r)
    even_hash_indices = Indices(2:2:n)
    odd_hash_indices = Indices(1:2:n)

    # old_hash_indices = HashIndices(r)
    # even_old_hash_indices = HashIndices(2:2:n)
    # odd_old_hash_indices = HashIndices(1:2:n)

    suite_n = suite["$n"] = BenchmarkGroup()

    s = suite_n["constructor ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable Vector($r))
    s["Set"] = @benchmarkable Set($r)
    s["OrderedSet"] = @benchmarkable OrderedSet($r)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable ArrayIndices($r))
    s["Indices"] = @benchmarkable Indices($r)
    #s["HashIndices"] = @benchmarkable Indices($r)

    s = suite_n["build by insertion ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector (push!)"] = @benchmarkable build_set_by_insertion($n))
    s["Set"] = @benchmarkable build_set_by_insertion($n)
    s["OrderedSet"] = @benchmarkable build_ordered_set_by_insertion($n)
    n < cutoff && (s["Set"] = @benchmarkable build_indices_by_insertion($n))
    s["Indices"] = @benchmarkable build_hashindices_by_insertion($n)
    #s["HashIndices"] = @benchmarkable build_old_hashindices_by_insertion($n)

    s = suite_n["copy ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector (pop!)"] = @benchmarkable copy($vec))
    s["Set"] = @benchmarkable copy($set)
    s["OrderedSet"] = @benchmarkable copy($ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable copy($indices))
    s["Indices"] = @benchmarkable copy($hash_indices)
    #s["HashIndices"] = @benchmarkable copy($old_hash_indices)

    s = suite_n["copy and empty by deletion ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector (pop!)"] = @benchmarkable empty_by_deletion(copy($vec), $n))
    s["Set"] = @benchmarkable empty_by_deletion(copy($set), $n)
    s["OrderedSet"] = @benchmarkable empty_by_deletion(copy($ordered_set), $n)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable empty_by_deletion(copy($indices), $n))
    s["Indices"] = @benchmarkable empty_by_deletion(copy($hash_indices), $n)
    #s["HashIndices"] = @benchmarkable empty_by_deletion(copy($old_hash_indices), $n)

    s = suite_n["insertion/deletion tests ($n)"] = BenchmarkGroup()
    s["Set"] = @benchmarkable basic_set_test($n)
    s["OrderedSet"] = @benchmarkable basic_ordered_set_test($n)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable basic_indices_test($n))
    s["Indices"] = @benchmarkable basic_hash_indices_test($n)
    #s["HashIndices"] = @benchmarkable basic_old_hash_indices_test($n)

    s = suite_n["insertion/deletion tests ($n)"] = BenchmarkGroup()
    s["Set"] = @benchmarkable basic_set_test($n)
    s["OrderedSet"] = @benchmarkable basic_ordered_set_test($n)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable basic_indices_test($n))
    s["Indices"] = @benchmarkable basic_hash_indices_test($n)
    #s["HashIndices"] = @benchmarkable basic_old_hash_indices_test($n)

    s = suite_n["unique/distinct (high uniqueness, unsorted) ($n)"] = BenchmarkGroup()
    s["Vector (unique)"] = @benchmarkable unique($mostly_unique)
    s["Set"] = @benchmarkable Set($mostly_unique)
    s["OrderedSet"] = @benchmarkable OrderedSet($mostly_unique)
    s["Indices (distinct)"] = @benchmarkable distinct($mostly_unique)

    s = suite_n["unique/distinct (high uniqueness, sorted) ($n)"] = BenchmarkGroup()
    s["Vector (unique)"] = @benchmarkable unique($sorted_mostly_unique)
    s["Set"] = @benchmarkable Set($sorted_mostly_unique)
    s["OrderedSet"] = @benchmarkable OrderedSet($sorted_mostly_unique)
    s["Indices"] = @benchmarkable distinct($sorted_mostly_unique)

    s = suite_n["unique/distinct (low uniqueness, unsorted) ($n)"] = BenchmarkGroup()
    s["Vector (unique)"] = @benchmarkable unique($rarely_unique)
    s["Set"] = @benchmarkable Set($rarely_unique)
    s["OrderedSet"] = @benchmarkable OrderedSet($rarely_unique)
    s["Indices"] = @benchmarkable distinct($rarely_unique)

    s = suite_n["unique/distinct (low uniqueness, sorted) ($n)"] = BenchmarkGroup()
    s["Vector (unique)"] = @benchmarkable unique($sorted_rarely_unique)
    s["Set"] = @benchmarkable Set($sorted_rarely_unique)
    s["OrderedSet"] = @benchmarkable OrderedSet($sorted_rarely_unique)
    s["Indices"] = @benchmarkable distinct($sorted_rarely_unique)

    s = suite_n["in ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable all_in($vec, $n))
    s["Set"] = @benchmarkable all_in($set, $n)
    s["OrderedSet"] = @benchmarkable all_in($ordered_set, $n)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable all_in($indices, $n))
    s["Indices"] = @benchmarkable all_in($hash_indices, $n)
    #s["HashIndices"] = @benchmarkable all_in($old_hash_indices, $n)

    s = suite_n["not in ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable not_in($vec, $n))
    s["Set"] = @benchmarkable not_in($set, $n)
    s["OrderedSet"] = @benchmarkable not_in($ordered_set, $n)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable not_in($indices, $n))
    s["Indices"] = @benchmarkable not_in($hash_indices, $n)
    #s["HashIndices"] = @benchmarkable not_in($old_hash_indices, $n)

    s = suite_n["count ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable count(iseven, $vec))
    s["Set"] = @benchmarkable count(iseven, $set)
    s["OrderedSet"] = @benchmarkable count(iseven, $ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable count(iseven, $indices))
    s["Indices"] = @benchmarkable count(iseven, $hash_indices)
    #s["HashIndices"] = @benchmarkable count(iseven, $old_hash_indices)

    s = suite_n["sum ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable sum($vec))
    s["Set"] = @benchmarkable sum($set)
    s["OrderedSet"] = @benchmarkable sum($ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable sum($indices))
    s["Indices"] = @benchmarkable sum($hash_indices)
    #s["HashIndices"] = @benchmarkable sum($old_hash_indices)

    s = suite_n["foreach ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable foreachsum($vec))
    s["Set"] = @benchmarkable foreachsum($set)
    s["OrderedSet"] = @benchmarkable foreachsum($ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable foreachsum($indices))
    s["Indices"] = @benchmarkable foreachsum($hash_indices)
    #s["HashIndices"] = @benchmarkable foreachsum($old_hash_indices)

    s = suite_n["filter-map-reduce via generator ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable sum($(2x for x in vec if isodd(x))))
    s["Set"] = @benchmarkable sum($(2x for x in set if isodd(x)))
    s["OrderedSet"] = @benchmarkable sum($(2x for x in ordered_set if isodd(x)))
    n < cutoff && (s["ArrayIndices"] = @benchmarkable sum($(2x for x in indices if isodd(x))))
    s["Indices"] = @benchmarkable sum($(2x for x in hash_indices if isodd(x)))
    #s["HashIndices"] = @benchmarkable sum($(2x for x in old_hash_indices if isodd(x)))

    s = suite_n["filter (most) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable filter($pred1, $vec))
    s["Set"] = @benchmarkable filter($pred1, $set)
    s["OrderedSet"] = @benchmarkable filter($pred1, $ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable filter($pred1, $indices))
    s["Indices"] = @benchmarkable filter($pred1, $hash_indices)
    #s["HashIndices"] = @benchmarkable filter($pred1, $old_hash_indices)

    s = suite_n["filter (half) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable filter(iseven, $vec))
    s["Set"] = @benchmarkable filter(iseven, $set)
    s["OrderedSet"] = @benchmarkable filter(iseven, $ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable filter(iseven, $indices))
    s["Indices"] = @benchmarkable filter(iseven, $hash_indices)
    #s["HashIndices"] = @benchmarkable filter(iseven, $old_hash_indices)

    s = suite_n["filter (few) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable filter($pred2, $vec))
    s["Set"] = @benchmarkable filter($pred2, $set)
    s["OrderedSet"] = @benchmarkable filter($pred2, $ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable filter($pred2, $indices))
    s["Indices"] = @benchmarkable filter($pred2, $hash_indices)
    #s["HashIndices"] = @benchmarkable filter($pred2, $old_hash_indices)

    s = suite_n["copy and filter! (most) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable filter!($pred1, copy($vec)))
    s["Set"] = @benchmarkable filter!($pred1, copy($set))
    s["OrderedSet"] = @benchmarkable filter!($pred1, copy($ordered_set))
    n < cutoff && (s["ArrayIndices"] = @benchmarkable filter!($pred1, copy($indices)))
    s["Indices"] = @benchmarkable filter!($pred1, copy($hash_indices))
    #s["HashIndices"] = @benchmarkable filter!($pred1, copy($old_hash_indices))

    s = suite_n["copy and filter! (half) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable filter!(iseven, copy($vec)))
    s["Set"] = @benchmarkable filter!(iseven, copy($set))
    s["OrderedSet"] = @benchmarkable filter!(iseven, copy($ordered_set))
    n < cutoff && (s["ArrayIndices"] = @benchmarkable filter!(iseven, copy($indices)))
    s["Indices"] = @benchmarkable filter!(iseven, copy($hash_indices))
    #s["HashIndices"] = @benchmarkable filter!(iseven, copy($old_hash_indices))

    s = suite_n["copy and filter! (few) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable filter!($pred2, copy($vec)))
    s["Set"] = @benchmarkable filter!($pred2, copy($set))
    s["OrderedSet"] = @benchmarkable filter!($pred2, copy($ordered_set))
    n < cutoff && (s["ArrayIndices"] = @benchmarkable filter!($pred2, copy($indices)))
    s["Indices"] = @benchmarkable filter!($pred2, copy($hash_indices))
    #s["HashIndices"] = @benchmarkable filter!($pred2, copy($old_hash_indices))

    s = suite_n["union ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable union($even_vec, $odd_vec))
    s["Set"] = @benchmarkable union($even_set, $odd_set)
    s["OrderedSet"] = @benchmarkable union($even_ordered_set, $odd_ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable union($even_indices, $even_indices))
    s["Indices"] = @benchmarkable union($even_hash_indices, $odd_hash_indices)
    #s["HashIndices"] = @benchmarkable union($even_old_hash_indices, $odd_old_hash_indices)

    s = suite_n["intersect (empty) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable intersect($even_vec, $odd_vec))
    s["Set"] = @benchmarkable intersect($even_set, $odd_set)
    s["OrderedSet"] = @benchmarkable intersect($even_ordered_set, $odd_ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable intersect($even_indices, $odd_indices))
    s["Indices"] = @benchmarkable intersect($even_hash_indices, $odd_hash_indices)
    #s["HashIndices"] = @benchmarkable intersect($even_old_hash_indices, $odd_old_hash_indices)

    s = suite_n["intersect (half) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable intersect($even_vec, $vec))
    s["Set"] = @benchmarkable intersect($even_set, $set)
    s["OrderedSet"] = @benchmarkable intersect($even_ordered_set, $ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable intersect($even_indices, $indices))
    s["Indices"] = @benchmarkable intersect($even_hash_indices, $hash_indices)
    #s["HashIndices"] = @benchmarkable intersect($even_old_hash_indices, $old_hash_indices)

    s = suite_n["intersect (whole) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable intersect($vec, $vec))
    s["Set"] = @benchmarkable intersect($set, $set)
    s["OrderedSet"] = @benchmarkable intersect($ordered_set, $ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable intersect($indices, $indices))
    s["Indices"] = @benchmarkable intersect($hash_indices, $hash_indices)
    #s["HashIndices"] = @benchmarkable intersect($old_hash_indices, $old_hash_indices)

    s = suite_n["setdiff (whole) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable setdiff($even_vec, $odd_vec))
    s["Set"] = @benchmarkable setdiff($even_set, $odd_set)
    s["OrderedSet"] = @benchmarkable setdiff($even_ordered_set, $odd_ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable setdiff($even_indices, $odd_indices))
    s["Indices"] = @benchmarkable setdiff($even_hash_indices, $odd_hash_indices)
    #s["HashIndices"] = @benchmarkable setdiff($even_old_hash_indices, $odd_old_hash_indices)

    s = suite_n["setdiff (half) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable setdiff($even_vec, $vec))
    s["Set"] = @benchmarkable setdiff($even_set, $set)
    s["OrderedSet"] = @benchmarkable setdiff($even_ordered_set, $ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable setdiff($even_indices, $indices))
    s["Indices"] = @benchmarkable setdiff($even_hash_indices, $hash_indices)
    #s["HashIndices"] = @benchmarkable setdiff($even_old_hash_indices, $old_hash_indices)

    s = suite_n["setdiff (empty) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable setdiff($vec, $vec))
    s["Set"] = @benchmarkable setdiff($set, $set)
    s["OrderedSet"] = @benchmarkable setdiff($ordered_set, $ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable setdiff($indices, $indices))
    s["Indices"] = @benchmarkable setdiff($hash_indices, $hash_indices)
    #s["HashIndices"] = @benchmarkable setdiff($old_hash_indices, $old_hash_indices)

    s = suite_n["symdiff (whole) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable symdiff($even_vec, $odd_vec))
    s["Set"] = @benchmarkable symdiff($even_set, $odd_set)
    s["OrderedSet"] = @benchmarkable symdiff($even_ordered_set, $odd_ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable symdiff($even_indices, $odd_indices))
    s["Indices"] = @benchmarkable symdiff($even_hash_indices, $odd_hash_indices)
    #s["HashIndices"] = @benchmarkable symdiff($even_old_hash_indices, $odd_old_hash_indices)

    s = suite_n["symdiff (left half) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable symdiff($vec, $odd_vec))
    s["Set"] = @benchmarkable symdiff($set, $odd_set)
    s["OrderedSet"] = @benchmarkable symdiff($ordered_set, $odd_ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable symdiff($indices, $odd_indices))
    s["Indices"] = @benchmarkable symdiff($hash_indices, $odd_hash_indices)
    #s["HashIndices"] = @benchmarkable symdiff($old_hash_indices, $odd_old_hash_indices)

    s = suite_n["symdiff (right half) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable symdiff($even_vec, $vec))
    s["Set"] = @benchmarkable symdiff($even_set, $set)
    s["OrderedSet"] = @benchmarkable symdiff($even_ordered_set, $ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable symdiff($even_indices, $indices))
    s["Indices"] = @benchmarkable symdiff($even_hash_indices, $hash_indices)
    #s["HashIndices"] = @benchmarkable symdiff($even_old_hash_indices, $old_hash_indices)

    s = suite_n["symdiff (empty) ($n)"] = BenchmarkGroup()
    n < cutoff && (s["Vector"] = @benchmarkable symdiff($vec, $vec))
    s["Set"] = @benchmarkable symdiff($set, $set)
    s["OrderedSet"] = @benchmarkable symdiff($ordered_set, $ordered_set)
    n < cutoff && (s["ArrayIndices"] = @benchmarkable symdiff($indices, $indices))
    s["Indices"] = @benchmarkable symdiff($hash_indices, $hash_indices)
    #s["HashIndices"] = @benchmarkable symdiff($old_hash_indices, $old_hash_indices)
end

end  # module

BenchHashIndices.suite


text:
function add_dual_equality_constraints(dual_model::MOI.ModelLike, primal_model::MOI.ModelLike,
                                       primal_dual_map::PrimalDualMap,  dual_names::DualNames,
                                       primal_objective::PrimalObjective{T},
                                       con_types::Vector{Tuple{DataType, DataType}},
                                       variable_parameters::Vector{VI}) where T

    sense_change = MOI.get(dual_model, MOI.ObjectiveSense()) == MOI.MAX_SENSE ? one(T) : -one(T)

    all_variables = MOI.get(primal_model, MOI.ListOfVariableIndices())
    restricted_variables = setdiff(all_variables, variable_parameters)

    # Loop at every constraint to get the scalar affine terms
    scalar_affine_terms = get_scalar_affine_terms(primal_model,
        primal_dual_map.primal_con_dual_var,
        all_variables, con_types, T)

    # get RHS from objective coeficients
    scalar_terms = get_scalar_terms(primal_model,
        all_variables, primal_objective)

    # Add terms from objective:
    # Terms from quadratic part
    add_scalar_affine_terms_from_quad_obj(scalar_affine_terms, primal_model,
        primal_dual_map.primal_var_dual_quad_slack, primal_objective)
    # terms from mixing variables and parameters
    add_scalar_affine_terms_from_quad_params(scalar_affine_terms, primal_model,
        primal_dual_map.primal_parameter, primal_objective)

    for primal_vi in restricted_variables
        # Add equality constraint
        dual_ci = MOIU.normalize_and_add_constraint(dual_model,
            MOI.ScalarAffineFunction(scalar_affine_terms[primal_vi], zero(T)),
            MOI.EqualTo(sense_change * get(scalar_terms, primal_vi, zero(T))))
        #Set constraint name with the name of the associated priaml variable
        if !is_empty(dual_names)
            set_dual_constraint_name(dual_model, primal_model, primal_vi, dual_ci,
                                     dual_names.dual_constraint_name_prefix)
        end
        # Add primal variable to dual contraint to the link dictionary
        push!(primal_dual_map.primal_var_dual_con, primal_vi => dual_ci)
    end
    return scalar_affine_terms
end

function add_scalar_affine_terms_from_quad_obj(
    scalar_affine_terms::Dict{VI,Vector{MOI.ScalarAffineTerm{T}}},
    primal_model::MOI.ModelLike,
    primal_var_dual_quad_slack::Dict{VI, VI},
    primal_objective::PrimalObjective{T}) where T
    for term in primal_objective.obj.quadratic_terms
        if term.variable_index_1 == term.variable_index_2
            dual_vi = primal_var_dual_quad_slack[term.variable_index_1]
            push_to_scalar_affine_terms!(
                scalar_affine_terms[term.variable_index_1],
                -MOI.coefficient(term), dual_vi)
        else
            dual_vi_1 = primal_var_dual_quad_slack[term.variable_index_1]
            push_to_scalar_affine_terms!(
                scalar_affine_terms[term.variable_index_2],
                -MOI.coefficient(term), dual_vi_1)
            dual_vi_2 = primal_var_dual_quad_slack[term.variable_index_2]
            push_to_scalar_affine_terms!(
                scalar_affine_terms[term.variable_index_1],
                -MOI.coefficient(term), dual_vi_2)
        end
    end
end

function add_scalar_affine_terms_from_quad_params(
    scalar_affine_terms::Dict{VI,Vector{MOI.ScalarAffineTerm{T}}},
    primal_model::MOI.ModelLike,
    primal_parameter::Dict{VI, VI},
    primal_objective::PrimalObjective{T}) where T
    for (key,val) in primal_objective.quad_cross_parameters
        for term in val
            dual_vi = primal_parameter[term.variable_index]
            push_to_scalar_affine_terms!(scalar_affine_terms[key], -MOI.coefficient(term), dual_vi)
        end
    end
end

function set_dual_constraint_name(dual_model::MOI.ModelLike, primal_model::MOI.ModelLike,
                                  primal_vi::VI, dual_ci::CI, prefix::String)
    MOI.set(dual_model, MOI.ConstraintName(), dual_ci,
            prefix*MOI.get(primal_model, MOI.VariableName(), primal_vi))
    return
end

function get_scalar_terms(primal_model::MOI.ModelLike,
    variables::Vector{VI},
    primal_objective::PrimalObjective{T}) where T

    scalar_terms = Dict{VI,T}()
    for term in get_affine_terms(primal_objective)
        if haskey(scalar_terms, term.variable_index)
            scalar_terms[term.variable_index] += MOI.coefficient(term)
        else
            scalar_terms[term.variable_index] = MOI.coefficient(term)
        end
    end
    return scalar_terms
end

function get_scalar_affine_terms(primal_model::MOI.ModelLike,
                                 primal_con_dual_var::Dict{CI, Vector{VI}},
                                 variables::Vector{VI},
                                 con_types::Vector{Tuple{DataType, DataType}},
                                 T::Type)

    scalar_affine_terms = Dict{VI,Vector{MOI.ScalarAffineTerm{T}}}()
    for vi in variables
        scalar_affine_terms[vi] = MOI.ScalarAffineTerm{T}[]
    end
    for (F, S) in con_types
        primal_cis = MOI.get(primal_model, MOI.ListOfConstraintIndices{F,S}()) # Constraints of type {F, S}
        for ci in primal_cis
            fill_scalar_affine_terms!(scalar_affine_terms, primal_con_dual_var,
                                      primal_model, ci)
        end
    end
    return scalar_affine_terms
end

function push_to_scalar_affine_terms!(scalar_affine_terms::Vector{MOI.ScalarAffineTerm{T}},
                                      affine_term::T, vi::VI) where T

    if !iszero(affine_term) # if term is different than 0 add to the scalar affine terms vector
        push!(scalar_affine_terms, MOI.ScalarAffineTerm(affine_term, vi))
    end
    return
end

function fill_scalar_affine_terms!(scalar_affine_terms::Dict{VI,Vector{MOI.ScalarAffineTerm{T}}},
                                   primal_con_dual_var::Dict{CI, Vector{VI}},
                                   primal_model::MOI.ModelLike, ci::CI{SAF{T}, S},
                                   ) where {T, S <: Union{MOI.GreaterThan{T},
                                                          MOI.LessThan{T},
                                                          MOI.EqualTo{T}}}

    moi_function = get_function(primal_model, ci)
    for term in moi_function.terms
        dual_vi = primal_con_dual_var[ci][1] # In this case we only have one vi
        push_to_scalar_affine_terms!(scalar_affine_terms[term.variable_index],
                                     MOI.coefficient(term), dual_vi)
    end
    return
end

function fill_scalar_affine_terms!(scalar_affine_terms::Dict{VI,Vector{MOI.ScalarAffineTerm{T}}},
                                   primal_con_dual_var::Dict{CI, Vector{VI}},
                                   primal_model::MOI.ModelLike, ci::CI{SVF, S},
                                   ) where {T, S <: Union{MOI.GreaterThan{T},
                                                          MOI.LessThan{T},
                                                          MOI.EqualTo{T}}}

    moi_function = get_function(primal_model, ci)
    dual_vi = primal_con_dual_var[ci][1] # In this case we only have one vi
    push_to_scalar_affine_terms!(scalar_affine_terms[moi_function.variable], one(T), dual_vi)
    return
end

function fill_scalar_affine_terms!(scalar_affine_terms::Dict{VI,Vector{MOI.ScalarAffineTerm{T}}},
                                   primal_con_dual_var::Dict{CI, Vector{VI}},
                                   primal_model::MOI.ModelLike, ci::CI{VAF{T}, S},
                                   ) where {T, S <: MOI.AbstractVectorSet}

    moi_function = get_function(primal_model, ci)
    set = get_set(primal_model, ci)
    for term in moi_function.terms
        dual_vi = primal_con_dual_var[ci][term.output_index]
        # term.output_index is the row of the VAF,
        # it corresponds to the dual variable associated with this constraint
        push_to_scalar_affine_terms!(scalar_affine_terms[term.scalar_term.variable_index],
            set_dot(term.output_index, set, T)*MOI.coefficient(term), dual_vi)
    end
    return
end

function fill_scalar_affine_terms!(scalar_affine_terms::Dict{VI,Vector{MOI.ScalarAffineTerm{T}}},
                                   primal_con_dual_var::Dict{CI, Vector{VI}},
                                   primal_model::MOI.ModelLike, ci::CI{VVF, S},
                                   ) where {T, S <: MOI.AbstractVectorSet}

    moi_function = get_function(primal_model, ci)
    set = get_set(primal_model, ci)
    for (i, variable) in enumerate(moi_function.variables)
        dual_vi = primal_con_dual_var[ci][i]
        push_to_scalar_affine_terms!(scalar_affine_terms[variable],
                                    set_dot(i, set, T)*one(T), dual_vi)
    end
    return
end

function set_dot(i::Int, s::MOI.AbstractVectorSet, T::Type)
    vec = zeros(T, MOI.dimension(s))
    vec[i] = one(T)
    return MOIU.set_dot(vec, vec, s)
end
function set_dot(i::Int, s::MOI.AbstractScalarSet, T::Type)
    return one(T)
end


text:
import Compat: @info, @error, Sys.iswindows, mv, GC
using Compat.Libdl
libale_detected = false
if haskey(ENV, "LIBALE_HOME")
    @info("LIBALE_HOME environment detected: $(ENV["LIBALE_HOME"])")
    @info("Trying to load existing libale_c...")
    lib = Libdl.find_library(["libale_c.so","libale_c.dll"],
        [joinpath(ENV["LIBALE_HOME"], "ale_python_interface")])
    if isempty(lib) == false
        @info("Existing libalec detected at $lib, skip building...")
        libale_detected = true
    else
        @info("Failed to load existing libalec, trying to build from source...")
    end
end

import Compat.LibGit2: clone, checkout!, GitRepo
function getroms(romdir)
    @info("Downloading roms to $romdir")
    tmpdir = mktempdir()
    clone("https://github.com/openai/atari-py", tmpdir)
    repo = GitRepo(tmpdir)
    checkout!(repo, "03676470b32711dfa77186712ff9f74f3afdc512")
    GC.gc()
    mv(joinpath(tmpdir, "atari_py", "atari_roms"), romdir, force = true)
    rm(tmpdir, recursive = true, force = true)
end

using BinDeps
@BinDeps.setup
if libale_detected == false
    if Sys.iswindows()
	info("This package currently does not support Windows.")
        info("You may want to try using the prebuilt libale_c.dll file from")
        info("https://github.com/pkulchenko/alecwrap and setting the")
        info("LIBALE_HOME environment variable to the directory containing")
        info("the file, then issuing Pkg.build(\"ArcadeLearningEnvironment\")")
        error("Automatic building of libale_c.dll on Windows is currently not supported yet.")
    end

    libale_c = library_dependency("libale_c",
        aliases=["libale_c.so", "libale_c.dll"])

    _prefix = joinpath(BinDeps.depsdir(libale_c), "usr")
    _srcdir = joinpath(BinDeps.depsdir(libale_c), "src")
    _aledir = joinpath(_srcdir, "Arcade-Learning-Environment-0.6.0")
    _cmakedir = joinpath(_aledir, "build")
    _libdir = joinpath(_prefix, "lib")
    provides(BuildProcess,
        (@build_steps begin
            CreateDirectory(_srcdir)
            CreateDirectory(_libdir)
            @build_steps begin
                ChangeDirectory(_srcdir)
                `rm -rf Arcade-Learning-Environment-0.5.2`
                `rm -rf v0.5.2.zip`
				`rm -rf Arcade-Learning-Environment-0.6.0`
                `rm -rf v0.6.0.zip`
                `curl -LO https://github.com/mgbellemare/Arcade-Learning-Environment/archive/v0.6.0.zip`
                `unzip v0.6.0.zip`
                FileRule(joinpath(_libdir, "libale_c.so"),
                    @build_steps begin
                        ChangeDirectory("$_aledir")
                        `cmake -DUSE_SDL=OFF -DBUILD_EXAMPLES=OFF -DBUILD_CPP_LIB=OFF -DBUILD_CLI=OFF .`
                        `make -j 4`
                        `cp ale_python_interface/libale_c.so $_libdir`
                    end)
            end
        end), libale_c)
    @BinDeps.install Dict(:libale_c => :libale_c)
    getroms(joinpath(@__DIR__, "roms"))
end