text:
const MOIDT = MOI.DeprecatedTest

@testset "Linear tests" begin
    MOIDT.contlineartest(DiffOpt.diff_optimizer(GLPK.Optimizer), MOIDT.Config(basis = true), [
        "partial_start",  # see below
        "linear12",       # see below
    ])
    model = DiffOpt.diff_optimizer(Ipopt.Optimizer)
    MOI.set(model, MOI.Silent(), true)
    MOIDT.partial_start_test(
        model,
        MOIDT.Config(basis = true, optimal_status=MOI.LOCALLY_SOLVED, atol=ATOL, rtol=RTOL)
    )

    # This requires an infeasiblity certificate for a variable bound.
    MOIDT.linear12test(
        DiffOpt.diff_optimizer(GLPK.Optimizer),
        MOIDT.Config(infeas_certificates=false)
    )
end

@testset "Convex Quadratic tests" begin
    model = DiffOpt.diff_optimizer(OSQP.Optimizer)
    MOI.set(model, MOI.Silent(), true)
    MOIDT.qp1test(model, MOIDT.Config(atol=1e-2, rtol=1e-2))
    model = DiffOpt.diff_optimizer(OSQP.Optimizer)
    MOI.set(model, MOI.Silent(), true)
    MOIDT.qp2test(model, MOIDT.Config(atol=1e-2, rtol=1e-2))
    model = DiffOpt.diff_optimizer(Ipopt.Optimizer)
    MOI.set(model, MOI.Silent(), true)
    MOIDT.qp3test(
        model,
        MOIDT.Config(optimal_status=MOI.LOCALLY_SOLVED, atol=1e-3),
    )
end

@testset "FEASIBILITY_SENSE zeros objective" begin
    model = DiffOpt.diff_optimizer(GLPK.Optimizer)
    MOI.set(model, MOI.Silent(), true)
    x = MOI.add_variable(model)
    MOI.add_constraint(model, x, MOI.GreaterThan(1.0))
    MOI.set(model, MOI.ObjectiveSense(), MOI.MIN_SENSE)
    MOI.set(model, MOI.ObjectiveFunction{MOI.VariableIndex}(), x)

    MOI.optimize!(model)
    @test MOI.get(model, MOI.ObjectiveValue()) ≈ 1.0 atol=ATOL rtol=RTOL

    MOI.set(model, MOI.ObjectiveSense(), MOI.FEASIBILITY_SENSE)
    MOI.optimize!(model)
    @test MOI.get(model, MOI.ObjectiveValue()) == 0.0
end

@testset "ModelLike" begin
    for opt in [GLPK.Optimizer]
        MODEL = DiffOpt.diff_optimizer(opt)
        @testset "default_objective_test" begin
            MOIDT.default_objective_test(MODEL)
        end
        @testset "default_status_test" begin
            MOIDT.default_status_test(MODEL)
        end
        @testset "nametest" begin
            MOIDT.nametest(MODEL)
        end
        @testset "validtest" begin
            MOIDT.validtest(MODEL)
        end
        @testset "emptytest" begin
            MOIDT.emptytest(MODEL)
        end
        @testset "orderedindicestest" begin
            MOIDT.orderedindicestest(MODEL)
        end
        @testset "copytest" begin
            # Requires VectorOfVariables
            # MOIDT.copytest(MODEL, MOIU.CachingOptimizer(
            #     DiffOpt.diff_optimizer(GLPK.Optimizer),
            #     GLPK.Optimizer()
            # ))
        end
    end
end

@testset "Unit" begin
    MOIDT.unittest(DiffOpt.diff_optimizer(GLPK.Optimizer), MOIDT.Config(), [
        "number_threads", # might not work on all solvers

        # not testing integer constraints
        "solve_zero_one_with_bounds_1",
        "solve_zero_one_with_bounds_2",
        "solve_zero_one_with_bounds_3",
        "solve_integer_edge_cases",

        "delete_soc_variables",
        "solve_qcp_edge_cases",  # currently only affine or conic constraints
        "solve_objbound_edge_cases",
        "solve_qp_edge_cases",  # No quadratics
        "solve_qp_zero_offdiag",
        "update_dimension_nonnegative_variables", # TODO: fix this

        # see below
        "solve_duplicate_terms_vector_affine",
        # SOC not supportedot supported
        "solve_start_soc",
    ])
    model = DiffOpt.diff_optimizer(SCS.Optimizer)
    MOI.set(model, MOI.Silent(), true)
    MOIDT.solve_duplicate_terms_obj(model, MOIDT.Config())
end

@testset "basic_constraint_tests" begin
    # it contains SOCP constraints
    model = DiffOpt.diff_optimizer(SCS.Optimizer)
    MOI.set(model, MOI.Silent(), true)
    MOIDT.basic_constraint_tests(model, MOIDT.Config())
end

# TODO: re-organiza conic tests
@testset "contconic.jl tests" begin
    model = DiffOpt.diff_optimizer(SCS.Optimizer)
    MOI.set(model, MOI.Silent(), true)
    # linear tests
    for (name, test) in MOIDT.lintests
        test(model, MOIDT.Config())
    end

    CONFIG_LOW_TOL = MOIDT.Config(atol = 1e-3, rtol = 1e-2, duals = false, infeas_certificates = false)
    # SOCP tests
    for (name, test) in MOIDT.soctests
        test(model, CONFIG_LOW_TOL)
    end
end


text:
import Base: show, isempty, time, >>, length, unshift!, promote_rule, convert,
  hash, ==, isless, pop!, info, next, start, done, next, getindex
import DataStructures: front, back, top
using MacroTools

export iskeydown, iskeyup, iskeypressed, isfocused, isunfocused, keycode,
  endofpause, @key_str, time, response_time, keycode, listkeys,
  ExtendedExperiment, extension, next, top, modifiedby

################################################################################
# event types

abstract type ExpEvent end

const concrete_events = []

"""
    @Weber.event type [name] <: [ExpEvent or ExpEvent child]
      [fields...]
    end

Marks a concrete type as being an experiment event.

This tag is necessary to ensure that all watcher moments are properly
precompiled. This macro adds the event to a list of concrete events
for which each watcher method must have a precompiled method.
"""
macro event(type_form)
  if !isexpr(type_form,:type)
    error("@event expects a type or struct")
  end
  decl = type_form.args[2]
  if !isexpr(decl,:<:)
    error("@event type must inhert from ExpEvent or a child of ExpEvent.")
  end
  name = decl.args[1] = esc(decl.args[1])

  quote
    $type_form
    push!(concrete_events,$name)
  end
end

@event struct QuitEvent <: ExpEvent
end

@event struct KeyUpEvent <: ExpEvent
  code::UInt32
  mod::UInt16
  time::Float64
end

@event struct KeyDownEvent <: ExpEvent
  code::UInt32
  mod::UInt16
  time::Float64
end

@event struct WindowFocused <: ExpEvent
  time::Float64
end

@event struct WindowUnfocused <: ExpEvent
  time::Float64
end

"""
    time(e::ExpEvent)

Get the time an event occured relative to the start of the experiment.
Resolution is limited by an experiment's input_resolution (which can be
specified upon initialization), and the response rate of the device. For
instance, keyboards usually have a latency on the order of 20-30ms.
"""
time(event::ExpEvent) = NaN
time(event::KeyUpEvent) = event.time
time(event::KeyDownEvent) = event.time
time(event::WindowFocused) = event.time
time(event::WindowUnfocused) = event.time

abstract type Key end
==(x::Key,y::Key) = false

struct KeyboardKey <: Key
  code::Int32
end
hash(x::KeyboardKey,h::UInt) = hash(KeyboardKey,hash(x.code,h))
==(x::KeyboardKey,y::KeyboardKey) = x.code == y.code
isless(x::KeyboardKey,y::KeyboardKey) = isless(x.code,y.code)
isless(x::Key,y::Key) = hash(typeof(x)) < hash(typeof(y))

macro os(kwds...)
  @assert kwds[1].args[1] == :apple
  @assert kwds[2].args[1] == :windows
  @assert kwds[3].args[1] == :linux

  if is_apple()
    kwds[1].args[2]
  elseif is_windows()
    kwds[2].args[2]
  elseif is_linux()
    kwds[3].args[2]
  else
    error("Unsupported operating system")
  end
end

const str_to_code = Dict{String,Key}(
  "a" => KeyboardKey(reinterpret(UInt32,'a')),
  "b" => KeyboardKey(reinterpret(UInt32,'b')),
  "c" => KeyboardKey(reinterpret(UInt32,'c')),
  "d" => KeyboardKey(reinterpret(UInt32,'d')),
  "e" => KeyboardKey(reinterpret(UInt32,'e')),
  "f" => KeyboardKey(reinterpret(UInt32,'f')),
  "g" => KeyboardKey(reinterpret(UInt32,'g')),
  "h" => KeyboardKey(reinterpret(UInt32,'h')),
  "i" => KeyboardKey(reinterpret(UInt32,'i')),
  "j" => KeyboardKey(reinterpret(UInt32,'j')),
  "k" => KeyboardKey(reinterpret(UInt32,'k')),
  "l" => KeyboardKey(reinterpret(UInt32,'l')),
  "m" => KeyboardKey(reinterpret(UInt32,'m')),
  "n" => KeyboardKey(reinterpret(UInt32,'n')),
  "o" => KeyboardKey(reinterpret(UInt32,'o')),
  "p" => KeyboardKey(reinterpret(UInt32,'p')),
  "q" => KeyboardKey(reinterpret(UInt32,'q')),
  "r" => KeyboardKey(reinterpret(UInt32,'r')),
  "s" => KeyboardKey(reinterpret(UInt32,'s')),
  "t" => KeyboardKey(reinterpret(UInt32,'t')),
  "u" => KeyboardKey(reinterpret(UInt32,'u')),
  "v" => KeyboardKey(reinterpret(UInt32,'v')),
  "w" => KeyboardKey(reinterpret(UInt32,'w')),
  "x" => KeyboardKey(reinterpret(UInt32,'x')),
  "y" => KeyboardKey(reinterpret(UInt32,'y')),
  "z" => KeyboardKey(reinterpret(UInt32,'z')),
  "0" => KeyboardKey(reinterpret(UInt32,'0')),
  "1" => KeyboardKey(reinterpret(UInt32,'1')),
  "2" => KeyboardKey(reinterpret(UInt32,'2')),
  "3" => KeyboardKey(reinterpret(UInt32,'3')),
  "4" => KeyboardKey(reinterpret(UInt32,'4')),
  "5" => KeyboardKey(reinterpret(UInt32,'5')),
  "6" => KeyboardKey(reinterpret(UInt32,'6')),
  "7" => KeyboardKey(reinterpret(UInt32,'7')),
  "8" => KeyboardKey(reinterpret(UInt32,'8')),
  "9" => KeyboardKey(reinterpret(UInt32,'9')),
  "-" => KeyboardKey(reinterpret(UInt32,'-')),
  "=" => KeyboardKey(reinterpret(UInt32,'=')),
  "_" => KeyboardKey(reinterpret(UInt32,'-')),
  "+" => KeyboardKey(reinterpret(UInt32,'=')),
  "[" => KeyboardKey(reinterpret(UInt32,'[')),
  "]" => KeyboardKey(reinterpret(UInt32,']')),
  "\\" => KeyboardKey(reinterpret(UInt32,'\\')),
  ":backslash:" => KeyboardKey(reinterpret(UInt32,'\\')),
  ";" => KeyboardKey(reinterpret(UInt32,';')),
  "'" => KeyboardKey(reinterpret(UInt32,''')),
  "," => KeyboardKey(reinterpret(UInt32,',')),
  "." => KeyboardKey(reinterpret(UInt32,'.')),
  "/" => KeyboardKey(reinterpret(UInt32,'/')),
  "`" => KeyboardKey(reinterpret(UInt32,'`')),
  ":tab:" => KeyboardKey(reinterpret(UInt32,'\t')),
  ":space:" => KeyboardKey(reinterpret(UInt32,' ')),
  " " => KeyboardKey(reinterpret(UInt32,' ')),
  ":up:" => KeyboardKey(0x40000052),
  ":down:" => KeyboardKey(0x40000051),
  ":left:" => KeyboardKey(0x40000050),
  ":right:" => KeyboardKey(0x4000004f),
  ":delete:" => KeyboardKey(0x0000007f),
  ":backspace:" => KeyboardKey(0x00000008),
  ":enter:" => KeyboardKey(0x0000000d),
  ":return:" => KeyboardKey(0x0000000d),

  ":lshift:" => KeyboardKey(0x400000e1),
  ":rshift:" => KeyboardKey(0x400000e5),
  ":left-shift:" => KeyboardKey(0x400000e1),
  ":right-shift:" => KeyboardKey(0x400000e5),

  ":lctrl:" => KeyboardKey(0x400000e0),
  ":rctrl:" => KeyboardKey(0x400000e4),
  ":left-ctrl:" => KeyboardKey(0x400000e0),
  ":right-ctrl:" => KeyboardKey(0x400000e4),

  ":lalt:" => KeyboardKey(0x400000e2),
  ":ralt:" => KeyboardKey(0x400000e6),
  ":left-alt:" => KeyboardKey(0x400000e2),
  ":right-alt:" => KeyboardKey(0x400000e6),

  @os(apple=":apple:",windows=":windows:",linux=":application:") =>
    KeyboardKey(0x40000065),

  ":caps-lock:" => KeyboardKey(0x40000039),
  ":escape:" => KeyboardKey(0x0000001b),
  ":esc:" => KeyboardKey(0x0000001b),

  ":f1:" => KeyboardKey(0x4000003a),
  ":f2:" => KeyboardKey(0x4000003b),
  ":f3:" => KeyboardKey(0x4000003c),
  ":f4:" => KeyboardKey(0x4000003d),
  ":f5:" => KeyboardKey(0x4000003e),
  ":f6:" => KeyboardKey(0x4000003f),
  ":f7:" => KeyboardKey(0x40000040),
  ":f8:" => KeyboardKey(0x40000041),
  ":f9:" => KeyboardKey(0x40000042),
  ":f10:" => KeyboardKey(0x40000043),
  ":f11:" => KeyboardKey(0x40000044),
  ":f12:" => KeyboardKey(0x40000045),

  ":pause:" => KeyboardKey(0x40000048),
  ":insert:" => KeyboardKey(0x40000049),
  ":home:" => KeyboardKey(0x4000004a),
  ":pageup:" => KeyboardKey(0x4000004b),
  ":end:" => KeyboardKey(0x4000004d),
  ":pagedown:" => KeyboardKey(0x4000004e),

  ":numlock:" => KeyboardKey(0x40000053),
  ":num /:" => KeyboardKey(0x40000054),
  ":num *:" => KeyboardKey(0x40000055),
  ":num -:" => KeyboardKey(0x40000056),
  ":num +:" => KeyboardKey(0x40000057),
  ":num =:" => KeyboardKey(0x40000067),
  ":num enter:" => KeyboardKey(0x40000058),
  ":num tab:" => KeyboardKey(0x400000ba),
  ":num ." => KeyboardKey(0x40000063),
  ":num 1:" => KeyboardKey(0x40000059),
  ":num 2:" => KeyboardKey(0x4000005a),
  ":num 3:" => KeyboardKey(0x4000005b),
  ":num 4:" => KeyboardKey(0x4000005c),
  ":num 5:" => KeyboardKey(0x4000005d),
  ":num 6:" => KeyboardKey(0x4000005e),
  ":num 7:" => KeyboardKey(0x4000005f),
  ":num 8:" => KeyboardKey(0x40000060),
  ":num 9:" => KeyboardKey(0x40000061),
  ":num 0:" => KeyboardKey(0x40000062)
)

function show(io::IO,key::KeyboardKey)
  found = filter((_,akey) -> (akey isa KeyboardKey) && akey.code == key.code,
                 str_to_code)
  if !isempty(found)
    found = collect(found)
    _,j = findmax(map(x -> length(x[1]),found))
    name = found[j][1]
    write(io,"key\"$name\"")
  else
    write(io,"Weber.KeyboardKey($(key.code))")
  end
end

"""
    listkeys()

Lists all available key codes in order.

Also see `@key_str`.
"""
listkeys() = foreach(println,values(str_to_code) |> unique |> collect |> sort)

"""
    key"keyname"

Generate a key code, using a single character (e.g. key"q" or key"]"), or
some special key name surrounded by colons (e.g. :escape:).

Note that keys are orderd and you can list all implemented keys in order, using
`listkeys`. If you want to quickly see the name for a given button you can use
`run_keycode_helper()`.

!!! note "Creating Custom Keycodes"

    Extensions to Weber can define their own keycodes. Such codes must
    but of some new type inheriting from `Weber.Key`, and can be added
    to the list of codes this macro can generate by updating the
    private constant `Weber.str_to_code`. See the section in the user guide
    on extensions for more details.
"""

macro key_str(key)
  try
    str_to_code[key]
  catch
    error("Unknown key \"$key\".")
  end
end

"""
    keycode(e::ExpEvent)

Report the key code for this event, if there is one.
"""
keycode(e::ExpEvent) = nothing
keycode(e::KeyDownEvent) = KeyboardKey(e.code)
keycode(e::KeyUpEvent) = KeyboardKey(e.code)

"""
    iskeydown(event,[key])

Evalutes to true if the event indicates that the given key (or any key)
was pressed down. (See `@key_str`)

    iskeydown(key)

Returns a function which tests if an event indicates the given key was pressed
down.
"""
iskeydown(event::ExpEvent) = false
iskeydown(event::KeyDownEvent) = true
iskeydown(key::KeyboardKey) = e -> iskeydown(e,key::KeyboardKey)
iskeydown(event::ExpEvent,keycode::Key) = false
iskeydown(event::KeyDownEvent,key::KeyboardKey) = event.code == key.code

"""
    modifiedby([event],[modifier = :shift,:ctrl,:alt or :gui])

Returns true if the given event represents a keydown event modified by a given
modifier key.

Without the first argument, returns a function that tests if the given event
is a keydown event modified by a given modifier key.
"""
modifiedby(modifier::Symbol) = e -> modifiedby(e,modifier)
modifiedby(event::ExpEvent,modifier::Symbol) = false
const shift_bit = 0x0003  # SDL2: KMOD_SHIFT
const ctrl_bit = 0x0c0 # SDL2: KMOD_CTRL
const alt_bit = 0x0300 # SDL2: KMOD_ALT
const gui_bit = 0x0c00 # SDL2: KMOD_GUI
function modifiedby(event::KeyDownEvent,modifier::Symbol)
  if modifier == :shift
    event.mod & shift_bit > 0
  elseif modifier in [:ctrl,:control]
    event.mod & ctrl_bit > 0
  elseif modifier == :alt
    event.mod & alt_bit > 0
  elseif modifier in [:gui,:windows,:apple]
    event.mod & gui_bit > 0
  else
    error("Undefined modifier key $modifier")
  end
end

"""
    iskeyup(event,[key])

Evalutes to true if the event indicates that the given keyboard key (or any key)
was released.  (See `@key_str`)

    iskeyup(key)

Returns a function which tests if an event indicates the given key was released.
"""
iskeyup(event::ExpEvent) = false
iskeyup(event::KeyUpEvent) = true
iskeyup(key::KeyboardKey) = e -> iskeydown(e,key)
iskeyup(event::ExpEvent,keycode::Key) = false
iskeyup(event::KeyUpEvent,key::KeyboardKey) = event.code == key.code

isfocused(event::ExpEvent) = false
isfocused(event::WindowFocused) = true

isunfocused(event::ExpEvent) = false
isunfocused(event::WindowUnfocused) = true

@event struct EndPauseEvent <: ExpEvent
  time::Float64
end

"""
    endofpause(event)

Evaluates to true if the event indicates the end of a pause requested by
the user.
"""
endofpause(event::ExpEvent) = false
endofpause(event::EndPauseEvent) = true
time(event::EndPauseEvent) = event.time

################################################################################
# trial types

abstract type AbstractMoment end
abstract type SimpleMoment <: AbstractMoment end

"""
    delta_t(m::AbstractMoment)

Returns the time, since the start of the previous moment, at which this
moment should begin. The default implementation returns zero.

!!! note

    This method is part of the private interface for moments. It
    should not be called directly, but implemented as part of an extension.
"""
delta_t(m::AbstractMoment) = 0.0
required_delta_t(m::AbstractMoment) = delta_t(m)
can_continue_sequence(m::AbstractMoment) = false
sequenceable(m::AbstractMoment) = false
warn_delta_t(m::AbstractMoment) = 0.0 < required_delta_t(m) < Inf

"""
    moment_trace(m)

Returns the stacktrace indicating where this moment was defined.

!!! note

    This method is part of the private interface for moments. It should not be
    called directly, but implemented as part of an extension.  You can get a
    stacktrace inside the function you define that constructs your custom moment
    using `stacktrace()[2:end]`.
"""
moment_trace(m::AbstractMoment) = Vector{StackFrame}()

struct ResponseMoment <: SimpleMoment
  respond::Function
  timeout::Function
  timeout_delta_t::Float64
  minimum_delta_t::Float64
  trace::StackTrace
end
function delta_t(moment::ResponseMoment)
  (moment.timeout_delta_t > 0.0 ? moment.timeout_delta_t : Inf)
end
required_delta_t(m::ResponseMoment) = Inf
can_continue_sequence(m::ResponseMoment) = false
moment_trace(m::ResponseMoment) = m.trace

struct ResponseMomentMin <: SimpleMoment
  delta_t::Float64
  trace::StackTrace
end
delta_t(m::ResponseMomentMin) = m.delta_t
required_delta_t(m::ResponseMomentMin) = Inf
can_continue_sequence(m::ResponseMomentMin) = false
moment_trace(m::ResponseMomentMin) = m.trace

abstract type AbstractTimedMoment <: SimpleMoment end
sequenceable(m::AbstractTimedMoment) = true
can_continue_sequence(m::AbstractTimedMoment) = delta_t(m) == 0.0

struct TimedMoment <: AbstractTimedMoment
  delta_t::Float64
  run::Function
  trace::StackTrace
end
delta_t(moment::TimedMoment) = moment.delta_t
sequenceable(m::TimedMoment) = true
moment_trace(m::TimedMoment) = m.trace

struct OffsetStartMoment <: AbstractTimedMoment
  run::Function
  count_trials::Bool
  expanding::Bool
  trace::StackTrace
end
delta_t(moment::OffsetStartMoment) = 0.0
can_continue_sequence(m::OffsetStartMoment) = false
sequenceable(m::OffsetStartMoment) = false
moment_trace(m::OffsetStartMoment) = m.trace

mutable struct PlayMoment <: AbstractTimedMoment
  delta_t::Float64
  sound::TimedSound.Sound
  channel::Int
  trace::StackTrace
  prepared::Bool
end
PlayMoment(d,f,c,t) = PlayMoment(d,f,c,t,false)
delta_t(m::PlayMoment) = m.delta_t
sequenceable(m::PlayMoment) = true
moment_trace(m::PlayMoment) = m.trace
warn_delta_t(m::PlayMoment) = false

mutable struct PlayFunctionMoment <: AbstractTimedMoment
  delta_t::Float64
  fn::Function
  channel::Int
  trace::StackTrace
  prepared::Nullable{TimedSound.Sound}
end
PlayFunctionMoment(d,f,c,t) = PlayFunctionMoment(d,f,c,t,Nullable())
delta_t(m::PlayFunctionMoment) = m.delta_t
sequenceable(m::PlayFunctionMoment) = true
moment_trace(m::PlayFunctionMoment) = m.trace
warn_delta_t(m::PlayFunctionMoment) = false

struct StreamMoment <: AbstractTimedMoment
  delta_t::Float64
  itr
  channel::Int
  trace::StackTrace
end
delta_t(m::StreamMoment) = delta_t
required_delta_t(m::StreamMoment) = Inf
can_continue_sequence(m::StreamMoment) = false
sequenceable(m::StreamMoment) = false
moment_trace(m::StreamMoment) = m.trace

struct DisplayMoment <: AbstractTimedMoment
  delta_t::Float64
  visual::SDLRendered
  trace::StackTrace
end
delta_t(m::DisplayMoment) = m.delta_t
sequenceable(m::DisplayMoment) = true
moment_trace(m::DisplayMoment) = m.trace

struct DisplayFunctionMoment <: AbstractTimedMoment
  delta_t::Float64
  fn::Function
  keys::Vector
  trace::StackTrace
  visual::Nullable{SDLRendered}
end
DisplayFunctionMoment(d,f,k,t) = DisplayFunctionMoment(d,f,k,t,Nullable())
delta_t(m::DisplayFunctionMoment) = m.delta_t
sequenceable(m::DisplayFunctionMoment) = true
moment_trace(m::DisplayFunctionMoment) = m.trace

struct CompoundMoment <: AbstractMoment
  data::Array{AbstractMoment}
end
delta_t(m::CompoundMoment) = 0.0
can_continue_sequence(m::CompoundMoment) = false
>>(a::SimpleMoment,b::SimpleMoment) = CompoundMoment([a,b])
>>(a::CompoundMoment,b::CompoundMoment) = CompoundMoment(vcat(a.data,b.data))
>>(a::AbstractMoment,b::AbstractMoment) = >>(promote(a,b)...)
>>(a::AbstractMoment,b::AbstractMoment,c::AbstractMoment,d::AbstractMoment...) = moment(a,b,c,d...)
promote_rule{T <: SimpleMoment}(::Type{CompoundMoment},::Type{T}) = CompoundMoment
convert(::Type{CompoundMoment},x::SimpleMoment) = CompoundMoment([x])

# optimize a seequence of moments that can occur, immediately, one after
# the other
struct MomentSequence <: AbstractTimedMoment
  data::Vector{AbstractMoment}
end
delta_t(m::MomentSequence) = delta_t(m.data[1])
required_delta_t(m::MomentSequence) = required_delta_t(m.data[1])
warn_delta_t(m::MomentSequence) = warn_delta_t(m.data[1])
push!(m::MomentSequence,x) = push!(m.data,x)
sequence(m1::AbstractMoment,m2::AbstractMoment) = MomentSequence([m1,m2])
sequence(ms::MomentSequence,m::AbstractMoment) = (push!(ms.data,m); ms)

mutable struct ExpandingMoment <: AbstractMoment
  condition::Function
  data::Stack{AbstractMoment}
  repeat::Bool
  update_offset::Bool
end
delta_t(m::ExpandingMoment) = 0.0
required_delta_t(m::ExpandingMoment) = Inf
can_continue_sequence(m::ExpandingMoment) = false

struct ExpandingMomentStub <: AbstractMoment
end
const expanding_stub = ExpandingMomentStub()
delta_t(m::ExpandingMomentStub) = 0.0
required_delta_t(m::ExpandingMomentStub) = Inf
can_continue_sequence(m::ExpandingMomentStub) = false

struct EmptyMoment <: AbstractMoment end
empty_moment = EmptyMoment()

mutable struct MomentQueue
  data::Vector{AbstractMoment}
  last::Float64
  start_index::Int
  end_index::Int
  very_first::Bool
end
show(io::IO,q::MomentQueue) = write(io,"MomentQueue[$(join(q,","))]")
start(m::MomentQueue) = 1
done(m::MomentQueue,i::Int) = i > length(m)
next(m::MomentQueue,i::Int) = m[i], i+1
@inline function getindex(m::MomentQueue,i)
  @boundscheck 0 < i <= length(m)
  real_index = i + m.start_index - 1
  if real_index > length(m.data)
    real_index = real_index - length(m.data)
  end
  @inbounds return m.data[real_index]
end

function MomentQueue(xs,last::Float64)
  size = 2^ceil(Int,log(length(xs))/log(2))
  data = repeat(AbstractMoment[empty_moment],inner=[size])
  data[1:length(xs)] = xs
  MomentQueue(data,last,1,length(xs),true)
end

MomentQueue(size=256) =
  MomentQueue(repeat(AbstractMoment[empty_moment],inner=[size]),0.0,1,1,true)
isempty(m::MomentQueue) = m.data[m.start_index] == empty_moment
function length(m::MomentQueue)
  if m.start_index < m.end_index
    m.end_index - m.start_index + 1
  elseif m.start_index > m.end_index
    length(m.data) - m.start_index + m.end_index + 1
  else
    Int(m.data[m.start_index] != empty_moment)
  end
end

function resize!(mq::MomentQueue,n)
  new_data = repeat(AbstractMoment[empty_moment],inner=[n])
  @inbounds for (i,m) in enumerate(mq)
    new_data[i] = m
  end
  mq.data = new_data
  end_index = length(mq)
  mq.start_index = 1
  mq.end_index = end_index

  mq
end

function enqueue!(mq::MomentQueue,x)
  if isempty(mq)
    mq.data[mq.start_index] = x
  elseif length(mq) < length(mq.data)
    mq.end_index == length(mq.data) ? mq.end_index = 1 : mq.end_index += 1
    mq.data[mq.end_index] = x
  else enqueue!(resize!(mq,2*length(mq.data)),x) end
  mq
end

function dequeue!(m::MomentQueue)
  @assert !isempty(m)
  result = m.data[m.start_index]

  if length(m) > 1
    m.data[m.start_index] = empty_moment
    if m.start_index < length(m.data)
      m.start_index += 1
    else
      m.start_index = 1
    end
  else
    m.data[m.start_index] = empty_moment
  end

  m.very_first = false
  result
end

function unshift!(m::MomentQueue,x)
  if isempty(m)
    m.data[m.start_index] = x
  elseif length(m) < length(m.data)
    m.start_index > 1 ? m.start_index -= 1 : m.start_index = length(m.data)
    m.data[m.start_index] = x
  else unshift!(resize!(m,2*length(m.data)),x) end
  m
end

function pop!(m::MomentQueue)
  @assert !isempty(m)
  result = m.data[m.end_index]

  if length(m) > 1
    m.data[m.end_index] = empty_moment
    if m.end_index == 1
      m.end_index = length(m.data)
    else
      m.end_index -= 1
    end
  else
    m.data[m.end_index] = empty_moment
  end

  result
end

front(m::MomentQueue) = m.data[m.start_index]
back(m::MomentQueue) = m.data[m.end_index]
very_first(m::MomentQueue) = m.very_first
function next_moment_time(m::MomentQueue)
  (isempty(m) ? Inf : m.last + delta_t(front(m)))
end

################################################################################
# experiment types

# information that remains true throughout an experiment
struct ExperimentInfo
  values::Array
  meta::Dict{Symbol,Any}
  input_resolution::Float64
  moment_resolution::Float64
  start::DateTime
  header::Array{Symbol}
  file::Nullable{String}
  hide_output::Bool
  warn_on_trials_only::Bool
end

# ongoing state about an experiment that changes moment to moment
mutable struct ExperimentData
  offset::Int
  trial::Int
  skip_offsets::Int
  last_time::Float64
  next_moment::Float64
  trial_watcher::Function
  pause_mode::Int
  moments::Array{MomentQueue,1}
  streamers::Dict{Int,TimedSound.Streamer}
  last_good_delta::Float64
  last_bad_delta::Float64
end

# flags to track experiment state
mutable struct ExperimentFlags
  running::Bool
  processing::Bool
end

abstract type Extension end
abstract type Experiment{W} end

struct UnextendedExperiment{W} <: Experiment{W}
  info::ExperimentInfo
  data::ExperimentData
  flags::ExperimentFlags
  win::W
end
info(e::UnextendedExperiment) = e.info
data(e::UnextendedExperiment) = e.data
flags(e::UnextendedExperiment) = e.flags
win(e::UnextendedExperiment) = e.win

"""
    top(experiment::Experiment)

Get the the top-most extended verison for this experiment, if any.
"""
top(e::Experiment) = e

struct ExtendedExperiment{E <: Extension,ES <: Tuple,N,W} <: Experiment{W}
  exp::UnextendedExperiment{W}
  extensions::ES
end
info(e::ExtendedExperiment) = e.exp.info
data(e::ExtendedExperiment) = e.exp.data
flags(e::ExtendedExperiment) = e.exp.flags
win(e::ExtendedExperiment) = e.exp.win

"""
    extension(experiment::ExtendedExperiment)

Get the extension object for this extended expeirment
"""
extension{E,ES,N,W}(e::ExtendedExperiment{E,ES,N,W}) = e.extensions[N]

function top{E,ES <: Tuple,N,W}(e::ExtendedExperiment{E,ES,N,W})
  E1 = ES.parameters[end]
  N1 = length(e.extensions)
  ExtendedExperiment{E1,ES,N1,W}(e.exp,e.extensions)
end

"""
     next(experiment::ExtendedExperiment)

Get the next extended version of this experiment.
"""
function next{E,ES,N,W}(e::ExtendedExperiment{E,ES,N,W})
  E1 = ES.parameters[N-1]
  ExtendedExperiment{E1,ES,N-1,W}(e.exp,e.extensions)
end
function next{E,ES,W}(e::ExtendedExperiment{E,ES,1,W})
  BaseExtendedExperiment{W,typeof(top(e))}(top(e))
end

struct BaseExtendedExperiment{W,E <: ExtendedExperiment} <: Experiment{W}
  top::E
end
info(e::BaseExtendedExperiment) = e.top.exp.info
data(e::BaseExtendedExperiment) = e.top.exp.data
flags(e::BaseExtendedExperiment) = e.top.exp.flags
win(e::BaseExtendedExperiment) = e.top.exp.win
top(e::BaseExtendedExperiment) = e.top

const BaseExperiment{W} = Union{UnextendedExperiment{W},BaseExtendedExperiment{W}}

function extend{W}(exp::UnextendedExperiment{W},exts)
  if isempty(exts)
    exp
  else
    exts = filter(x -> !(x isa Void),exts)
    exts = reverse(exts) # first extension takes precedence over subsequent ones
    exts_tup = tuple(exts...)
    E = typeof(exts[end])
    ES = typeof(exts_tup)
    N = length(exts)
    ExtendedExperiment{E,ES,N,W}(exp,exts_tup)
  end
end

ext: jl


text:
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md

using JuliaFEM, LinearAlgebra, Test

# compare simple 3d heat problem to code aster solution

fn = @__DIR__() * "/testdata/rod_short.med"
mesh = aster_read_mesh(fn, "Hex8")
element_sets = join(keys(mesh.element_sets), ", ")
@debug("element sets: $element_sets")

problem = Problem(Heat, "rod", 1)
volume = create_elements(mesh, "ROD")
face2 = create_elements(mesh, "FACE2")
face3 = create_elements(mesh, "FACE3")
face4 = create_elements(mesh, "FACE4")
face5 = create_elements(mesh, "FACE5")
face6 = create_elements(mesh, "FACE6")
update!(volume, "thermal conductivity", 50.0)
update!(face2, "external temperature", 20.0)
update!(face2, "heat transfer coefficient", 60.0)
update!(face3, "external temperature", 30.0)
update!(face3, "heat transfer coefficient", 50.0)
update!(face4, "external temperature", 40.0)
update!(face4, "heat transfer coefficient", 40.0)
update!(face5, "external temperature", 50.0)
update!(face5, "heat transfer coefficient", 30.0)
update!(face6, "external temperature", 60.0)
update!(face6, "heat transfer coefficient", 20.0)
add_elements!(problem, volume, face2, face3, face4, face5, face6)

bc = Problem(Dirichlet, "left support T=100", 1, "temperature")
bc_elements = create_elements(mesh, "FACE1")
update!(bc_elements, "temperature 1", 100.0)
add_elements!(bc, bc_elements)

analysis = Analysis(Linear)
add_problems!(analysis, problem, bc)
run!(analysis)

# fields extracted from Code Aster .resu file

temp_ca = Dict(
    1 => 1.00000000000000E+02,
    2 => 1.00000000000000E+02,
    3 => 1.00000000000000E+02,
    4 => 1.00000000000000E+02,
    5 => 3.01613322896279E+01,
    6 => 3.01263406641066E+01,
    7 => 3.02559777927923E+01,
    8 => 3.02209215997131E+01)

FLUX_ELGA = Dict(
    1 => [1.74565160615448E+04, -9.99903237329079E+01, -3.69874201221677E+01],
    2 => [1.74565160615448E+04, -3.73168968436642E+02, -1.38038931136833E+02],
    3 => [1.74428571293096E+04, -9.99903237329079E+01, -3.70268090662933E+01],
    4 => [1.74428571293096E+04, -3.73168968436642E+02, -1.38185932677561E+02],
    5 => [1.74615686370955E+04, -9.99509347888079E+01, -3.69874201221677E+01],
    6 => [1.74615686370955E+04, -3.73021966895897E+02, -1.38038931136833E+02],
    7 => [1.74479150854902E+04, -9.99509347888065E+01, -3.70268090662933E+01],
    8 => [1.74479150854901E+04, -3.73021966895874E+02, -1.38185932677561E+02])

FLUX_NOEU = Dict(
    1 => [1.74596669275930E+04,  7.55555618070503E-11,  3.68594044175552E-12],
    2 => [1.74684148339734E+04,  1.10418341137120E-11,  3.48876483258209E-12],
    3 => [1.74360055518019E+04,  7.91828824731056E-11,  1.95399252334028E-13],
    4 => [1.74447696000717E+04, -3.49587025993969E-12,  3.55271367880050E-13],
    5 => [1.74596669275931E+04, -4.73227515822099E+02, -1.74958127606525E+02],
    6 => [1.74684148339733E+04, -4.72904678032251E+02, -1.74958127606524E+02],
    7 => [1.74360055518019E+04, -4.73227515822118E+02, -1.75280965396335E+02],
    8 => [1.74447696000717E+04, -4.72904678032179E+02, -1.75280965396335E+02])

time = 0.0
temp_jf = problem("temperature", time)
@debug("Temperature comparison between JuliaFEM and Code Aster for 3D model",
       temp_ca, temp_jf)

T1 = [temp_ca[i] for i in 1:8]
T2 = [temp_jf[i] for i in 1:8]
@test isapprox(T1, T2; rtol=1.0e-9)


text:
# Unit test functions
function unit_test_compress()
    for i in 0:4
        @test compress(i, 1) == 1
    end

    for i in 0:5
        @test compress(i, 2) == i % 2 + 1
    end

    for i in 0:30
        @test compress(i, 10) == i % 10 + 1
    end

    return nothing
end

function unit_test_hash_number()
    m = SCHash{Int, Float64}()
    for i in -40:40
        @test hash(m, i) == Int(ceil(abs(i))) % m.tablesize + 1
    end

    m = SCHash{Float64, Float64}()
    for i in -40:40
        @test hash(m, Float64(i)) == Int(ceil(abs(i))) % m.tablesize + 1
    end

    m = SCHash{Complex{Float64}, Float64}()
    for i in -40:40
        a = Float64(i) + Float64(i)*im
        @test hash(m, a) == Int(ceil(abs(a))) % m.tablesize + 1
    end

    return nothing
end

function unit_test_hash_string()
    m = SCHash{String, Float64}()
    for i in ["abc", "com", "truss", "buss", "mycele", "new"]
        h = 0
        for c in i
            h  = 37h + UInt8(c)
        end
        @test hash(m, i) == h % m.tablesize + 1
    end

    return nothing
end

function unit_test_schash_empty()
    m = SCHash{Int, Float64}()
    @test m.nkeys == 0
    @test m.tablesize == 10

    return nothing
end

function unit_test_schash_put()
    m = SCHash{Int, Float64}()
    put!(m, 1, 1.0)
    @test m.table[hash(m, 1)][1] == Pair(1, 1.0)
    put!(m, 2, 2.0)
    @test m.table[hash(m, 2)][1] == Pair(2, 2.0)
    put!(m, 3, 3.0)
    @test m.table[hash(m, 3)][1] == Pair(3, 3.0)
    put!(m, 11, 4.0)
    @test m.table[hash(m, 11)][2] == Pair(11, 4.0)
    put!(m, 21, 5.0)
    @test m.table[hash(m, 11)][3] == Pair(21, 5.0)

    return nothing
end

function unit_test_linearsearch_string()
    # known example list
    a = "A search has no name."
    @test linearsearch(a, "A") == 1
    @test linearsearch(a, " ") == 2
    @test linearsearch(a, "n") == 14

    return nothing
end

function unit_test_binarysearch_empty()
    a = Vector{Float64}(undef, 0)
    @test binarysearch(a, 0.0) == 0
    @test binarysearch(a, 2.0) == 0
    @test binarysearch(a, NaN) == 0
    @test binarysearch(a, Inf) == 0

    return nothing
end

function unit_test_binarysearch_one()
    a = [10.0]
    @test binarysearch(a, 0.0) == 0
    @test binarysearch(a, 10.0) == 1
    @test binarysearch(a, NaN) == 0
    @test binarysearch(a, Inf) == 0

    a = [10]
    @test binarysearch(a, 0) == 0
    @test binarysearch(a, 10) == 1

    return nothing
end

function unit_test_binarysearch_many()
    # known example list
    a = [1.0, 3.0, 5.0, 6.0, 10.0, 10.0]
    @test binarysearch(a, 10.0) == 5
    @test binarysearch(a, 1.0) == 1
    @test binarysearch(a, 3.0) == 2
    @test binarysearch(a, 5.0) == 3
    @test binarysearch(a, 6.0) == 4
    @test binarysearch(a, NaN) == 0
    @test binarysearch(a, Inf) == 0

    return nothing
end

# Run the unit tests
@testset "Hash and compress           " begin
    unit_test_compress()
    unit_test_hash_number()
    unit_test_hash_string()
end

@testset "Separate chaining hash table" begin
    unit_test_schash_empty()
    unit_test_schash_put()
    #unit_test_schash_get()
    #unit_test_schash_delete()
    #unit_test_schash_resize()
end

@testset "Open addressing hash table  " begin
    #unit_test_binarysearch_empty()
    #unit_test_binarysearch_one()
    #unit_test_binarysearch_many()
    #unit_test_binarysearch_string()
end


text:
# Fuzzy.jl
#

"""
Module for Fuzzy Sets and Logic
"""
module Fuzzy

doc"""
Defines the Abstract Type for Fuzzy Sets
"""
abstract AbstractFuzzySet
export AbstractFuzzySet

const global tnorm = min
const global tconorm = max

######################
# Type 1
include("./Type1/Type1.jl")
include("./Type1/MFOperations.jl")

######################
# Type 2
include("./Type2/Type2.jl")
include("./Type2/IT2Operations.jl")

end # module


text:
module SpecialVectors
using Test

function constants(n=5)
    return ones(n)
end

@test constants() == ones(5)
@test constants(6) == ones(6)

function linear(n=5)
    return [1:n...]
end

@test linear() == [1:5...]
@test linear(6) == [1:6...]

function squares(n=5)
    return [1:n...].^2
end

@test squares() == [1:5...].^2
@test squares(6) == [1:6...].^2

function checkDim(k::Int, n::Int)
    if (k > n)
        throw(DimensionMismatch("k must be less than n!"))
    end
    return true
end

@test_throws DimensionMismatch checkDim(6, 1)
@test checkDim(1, 5)

function deltaAtK(k=1, n=5)
    checkDim(k, n)
    return [zeros(k - 1)..., 1, zeros(n - k)...]
end

@test_throws DimensionMismatch deltaAtK(6)
@test deltaAtK() == [1, 0, 0, 0, 0]
@test deltaAtK(3, 6) == [0, 0, 1, 0, 0, 0]

function stepAtK(k=1, n=5)
    checkDim(k, n)
    return [zeros(k - 1)..., 1, ones(n - k)...]
end

@test_throws DimensionMismatch stepAtK(6)
@test stepAtK() == [1, 1, 1, 1, 1]
@test stepAtK(3) == [0, 0, 1, 1, 1]

function rampAtK(k=1, n=5)
    checkDim(k, n)
    return [zeros(k - 1)..., 0:(n - k)...]
end

@test_throws DimensionMismatch rampAtK(6)
@test rampAtK() == [0, 1, 2, 3, 4]
@test rampAtK(2) == [0, 0, 1, 2, 3]
@test rampAtK(3) == [0, 0, 0, 1, 2]

function sines(t, n=5)
    return sin.([1:n...] .* t)
end

@test round.(sines(π / 2), digits=2) == [1, 0, -1, 0, 1]
@test round.(sines(π / 4), digits=2) == [.71, 1.0, .71, 0, -.71]

function cosines(t, n=5)
    return cos.([1:n...] .* t)
end

@test round.(cosines(π / 2), digits=2) == [0, -1, 0, 1, 0]
@test round.(cosines(π / 4), digits=2) == [.71, 0.0, -.71, -1.0, -.71]

function exponentials(t, n=5)
    return exp.([1:n...] .* (im * t))
end

@test exponentials(0) == repeat([1.0 + 0.0im], 5)
@test exponentials(1) == [
  0.5403023058681398 + 0.8414709848078965im
 -0.4161468365471424 + 0.9092974268256817im
 -0.9899924966004454 + 0.1411200080598672im
 -0.6536436208636119 - 0.7568024953079282im
 0.28366218546322625 - 0.9589242746631385im
]

export constants, linear, squares, deltaAtK, stepAtK, rampAtK, sines, cosines, exponentials

end


text:
@doc raw"""
    SineSquared

The Sine-Squared base function is given by:

```math
f(\mathbf{x}, \mathbf{y}) = \sine^2 \left(x_i - y_i\right)
```
"""
struct SineSquared <: PreMetric end
@inline base_aggregate(::SineSquared, s::T, x::T, y::T) where {T} = s + sin(x-y)^2
@inline isstationary(::SineSquared) = true


text:
module Gamepad

import ..CImGui.GLFWBackend.GLFW: JOYSTICK_1, GetJoystickAxes, GetJoystickButtons
export GamepadState

struct Axes
    x::Float32
    y::Float32
    trigger::Float32
    function Axes(axis_vec::Vector{Float32})
        offset::Float32 = axis_vec[3] + 1.0
        new(axis_vec[1], axis_vec[2], offset)
    end
end

struct Dpad
    up::Bool
    right::Bool
    down::Bool
    left::Bool
    function Dpad(dpad_vec::Vector{UInt8})
        new(dpad_vec...)
    end
end

struct Buttons
    A::Bool
    B::Bool
    X::Bool
    Y::Bool
    LB::Bool
    RB::Bool
    BACK::Bool
    START::Bool
    LOGI::Bool
    LHAT::Bool
    RHAT::Bool
    function Buttons(bvec::Vector{UInt8})
        new(bvec...)
    end
end

struct GamepadState
    button::Buttons
    DPAD::Dpad
    L::Axes
    R::Axes
    function GamepadState(axis_vals::Vector{Float32}, button_vals::Vector{UInt8})
        buttons = Buttons(button_vals[1:11])
        dpad = Dpad(button_vals[12:15])
        L = Axes(axis_vals[1:3])
        R = Axes(axis_vals[4:6])
        new(buttons, dpad, L, R)
    end
end

function poll(id = JOYSTICK_1)
    return GamepadState(GetJoystickAxes(id), GetJoystickButtons(id))
end

end


text:
# For testing Composite
struct Foo
    x
    y::Float64
end

# For testing Primal + Composite performance
struct Bar
    x::Float64
end

# For testing Composite: it is an invarient of the type that x2 = 2x
# so simple addition can not be defined
struct StructWithInvariant
    x
    x2

    StructWithInvariant(x) = new(x, 2x)
end

@testset "Composite" begin
    @testset "empty types" begin
        @test typeof(Composite{Tuple{}}()) == Composite{Tuple{}, Tuple{}}
    end
    @testset "convert" begin
        @test convert(NamedTuple, Composite{Foo}(x=2.5)) == (; x=2.5)
        @test convert(Tuple, Composite{Tuple{Float64,}}(2.0)) == (2.0,)
        @test convert(Dict, Composite{Dict}(Dict(4 => 3))) == Dict(4 => 3)
    end

    @testset "==" begin
        @test Composite{Foo}(x=0.1, y=2.5) == Composite{Foo}(x=0.1, y=2.5)
        @test Composite{Foo}(x=0.1, y=2.5) == Composite{Foo}(y=2.5, x=0.1)
        @test Composite{Foo}(y=2.5, x=Zero()) == Composite{Foo}(y=2.5)

        @test Composite{Tuple{Float64,}}(2.0) == Composite{Tuple{Float64,}}(2.0)
        @test Composite{Dict}(Dict(4 => 3)) == Composite{Dict}(Dict(4 => 3))

        tup = (1.0, 2.0)
        @test Composite{typeof(tup)}(1.0, 2.0) == Composite{typeof(tup)}(1.0, @thunk(2*1.0))
        @test Composite{typeof(tup)}(1.0, 2.0) == Composite{typeof(tup)}(1.0, 2)

        @test Composite{Foo}(;y=2.0,) == Composite{Foo}(;x=Zero(), y=Float32(2.0),)
    end

    @testset "hash" begin
        @test hash(Composite{Foo}(x=0.1, y=2.5)) == hash(Composite{Foo}(y=2.5, x=0.1))
        @test hash(Composite{Foo}(y=2.5, x=Zero())) == hash(Composite{Foo}(y=2.5))
    end

    @testset "indexing, iterating, and properties" begin
        @test keys(Composite{Foo}(x=2.5)) == (:x,)
        @test propertynames(Composite{Foo}(x=2.5)) == (:x,)
        @test haskey(Composite{Foo}(x=2.5), :x) == true
        if isdefined(Base, :hasproperty)
            @test hasproperty(Composite{Foo}(x=2.5), :y) == false
        end
        @test Composite{Foo}(x=2.5).x == 2.5

        @test keys(Composite{Tuple{Float64,}}(2.0)) == Base.OneTo(1)
        @test propertynames(Composite{Tuple{Float64,}}(2.0)) == (1,)
        @test getproperty(Composite{Tuple{Float64,}}(2.0), 1) == 2.0
        @test getproperty(Composite{Tuple{Float64,}}(@thunk 2.0^2), 1) == 4.0
        @test getproperty(Composite{Tuple{Float64,}}(a=(@thunk 2.0^2),), :a) == 4.0

        # TODO: uncomment this once https://github.com/JuliaLang/julia/issues/35516
        @test_broken haskey(Composite{Tuple{Float64}}(2.0), 1) == true
        @test_broken hasproperty(Composite{Tuple{Float64}}(2.0), 2) == false

        @test length(Composite{Foo}(x=2.5)) == 1
        @test length(Composite{Tuple{Float64,}}(2.0)) == 1

        @test eltype(Composite{Foo}(x=2.5)) == Float64
        @test eltype(Composite{Tuple{Float64,}}(2.0)) == Float64

        # Testing iterate via collect
        @test collect(Composite{Foo}(x=2.5)) == [2.5]
        @test collect(Composite{Tuple{Float64,}}(2.0)) == [2.0]

        # Test indexed_iterate
        ctup = Composite{Tuple{Float64,Int64}}(2.0, 3)
        _unpack2tuple = function(comp)
            a, b = comp
            return (a, b)
        end
        @inferred _unpack2tuple(ctup)
        @test _unpack2tuple(ctup) === (2.0, 3)

        # Test getproperty is inferrable
        _unpacknamedtuple = comp -> (comp.x, comp.y)
        if VERSION ≥ v"1.2"
            @inferred _unpacknamedtuple(Composite{Foo}(x=2, y=3.0))
            @inferred _unpacknamedtuple(Composite{Foo}(y=3.0))
        end
    end

    @testset "reverse" begin
        c = Composite{Tuple{Int, Int, String}}(1, 2, "something")
        cr = Composite{Tuple{String, Int, Int}}("something", 2, 1)
        @test reverse(c) === cr

        # can't reverse a named tuple or a dict
        @test_throws MethodError reverse(Composite{Foo}(;x=1.0, y=2.0))

        d = Dict(:x => 1, :y => 2.0)
        cdict = Composite{Foo, typeof(d)}(d)
        @test_throws MethodError reverse(Composite{Foo}())
    end

    @testset "unset properties" begin
        @test Composite{Foo}(; x=1.4).y === Zero()
    end

    @testset "conj" begin
        @test conj(Composite{Foo}(x=2.0+3.0im)) == Composite{Foo}(x=2.0-3.0im)
        @test ==(
            conj(Composite{Tuple{Float64,}}(2.0+3.0im)),
            Composite{Tuple{Float64,}}(2.0-3.0im)
        )
        @test ==(
            conj(Composite{Dict}(Dict(4 => 2.0 + 3.0im))),
            Composite{Dict}(Dict(4 => 2.0 + -3.0im)),
        )
    end

    @testset "extern" begin
        @test extern(Composite{Foo}(x=2.0)) == (;x=2.0)
        @test extern(Composite{Tuple{Float64,}}(2.0)) == (2.0,)
        @test extern(Composite{Dict}(Dict(4 => 3))) == Dict(4 => 3)

        # with differentials on the inside
        @test extern(Composite{Foo}(x=@thunk(0+2.0))) == (;x=2.0)
        @test extern(Composite{Tuple{Float64,}}(@thunk(0+2.0))) == (2.0,)
        @test extern(Composite{Dict}(Dict(4 => @thunk(3)))) == Dict(4 => 3)
    end

    @testset "canonicalize" begin
        # Testing iterate via collect
        @test ==(
            canonicalize(Composite{Tuple{Float64,}}(2.0)),
            Composite{Tuple{Float64,}}(2.0)
        )

        @test ==(
            canonicalize(Composite{Dict}(Dict(4 => 3))),
            Composite{Dict}(Dict(4 => 3)),
        )

        # For structure it needs to match order and Zero() fill to match primal
        CFoo = Composite{Foo}
        @test canonicalize(CFoo(x=2.5, y=10)) == CFoo(x=2.5, y=10)
        @test canonicalize(CFoo(y=10, x=2.5)) == CFoo(x=2.5, y=10)
        @test canonicalize(CFoo(y=10)) == CFoo(x=Zero(), y=10)

        @test_throws ArgumentError canonicalize(CFoo(q=99.0, x=2.5))
    end

    @testset "+ with other composites" begin
        @testset "Structs" begin
            CFoo = Composite{Foo}
            @test  CFoo(x=1.5) + CFoo(x=2.5) == CFoo(x=4.0)
            @test CFoo(y=1.5) + CFoo(x=2.5) == CFoo(y=1.5, x=2.5)
            @test CFoo(y=1.5, x=1.5) + CFoo(x=2.5) == CFoo(y=1.5, x=4.0)
        end

        @testset "Tuples" begin
            @test ==(
                typeof(Composite{Tuple{}}() + Composite{Tuple{}}()),
                Composite{Tuple{}, Tuple{}}
            )
            @test (
                Composite{Tuple{Float64, Float64}}(1.0, 2.0) +
                Composite{Tuple{Float64, Float64}}(1.0, 1.0)
            ) == Composite{Tuple{Float64, Float64}}(2.0, 3.0)
        end

        @testset "NamedTuples" begin
            nt1 = (;a=1.5, b=0.0)
            nt2 = (;a=0.0, b=2.5)
            nt_sum = (a=1.5, b=2.5)
            @test (
                Composite{typeof(nt1)}(; nt1...) +
                Composite{typeof(nt2)}(; nt2...)
            ) == Composite{typeof(nt_sum)}(; nt_sum...)
        end

        @testset "Dicts" begin
            d1 = Composite{Dict}(Dict(4 => 3.0, 3 => 2.0))
            d2 = Composite{Dict}(Dict(4 => 3.0, 2 => 2.0))
            d_sum = Composite{Dict}(Dict(4 => 3.0 + 3.0, 3 => 2.0, 2 => 2.0))
            @test d1 + d2 == d_sum
        end
    end

    @testset "+ with Primals" begin
        @testset "Structs" begin
            @test Foo(3.5, 1.5) + Composite{Foo}(x=2.5) == Foo(6.0, 1.5)
            @test Composite{Foo}(x=2.5) + Foo(3.5, 1.5) == Foo(6.0, 1.5)
            @test (@ballocated Bar(0.5) + Composite{Bar}(; x=0.5)) == 0
        end

        @testset "Tuples" begin
            @test Composite{Tuple{}}() + () == ()
            @test ((1.0, 2.0) + Composite{Tuple{Float64, Float64}}(1.0, 1.0)) == (2.0, 3.0)
            @test (Composite{Tuple{Float64, Float64}}(1.0, 1.0)) + (1.0, 2.0) == (2.0, 3.0)
        end

        @testset "NamedTuple" begin
            ntx = (; a=1.5)
            @test Composite{typeof(ntx)}(; ntx...) + ntx == (; a=3.0)

            nty = (; a=1.5, b=0.5)
            @test Composite{typeof(nty)}(; nty...) + nty == (; a=3.0, b=1.0)
        end

        @testset "Dicts" begin
            d_primal = Dict(4 => 3.0, 3 => 2.0)
            d_tangent = Composite{typeof(d_primal)}(Dict(4 =>5.0))
            @test d_primal + d_tangent == Dict(4 => 3.0 + 5.0, 3 => 2.0)
        end
    end

    @testset "+ with Primals, with inner constructor" begin
        value = StructWithInvariant(10.0)
        diff = Composite{StructWithInvariant}(x=2.0, x2=6.0)

        @testset "with and without debug mode" begin
            @assert ChainRulesCore.debug_mode() == false
            @test_throws MethodError (value + diff)
            @test_throws MethodError (diff + value)

            ChainRulesCore.debug_mode() = true  # enable debug mode
            @test_throws ChainRulesCore.PrimalAdditionFailedException (value + diff)
            @test_throws ChainRulesCore.PrimalAdditionFailedException (diff + value)
            ChainRulesCore.debug_mode() = false  # disable it again
        end

        # Now we define constuction for ChainRulesCore.jl's purposes:
        # It is going to determine the root quanity of the invarient
        function ChainRulesCore.construct(::Type{StructWithInvariant}, nt::NamedTuple)
            x = (nt.x + nt.x2/2)/2
            return StructWithInvariant(x)
        end
        @test value + diff == StructWithInvariant(12.5)
        @test diff + value == StructWithInvariant(12.5)
    end

    @testset "differential arithmetic" begin
        c = Composite{Foo}(y=1.5, x=2.5)

        @test DoesNotExist() * c == DoesNotExist()
        @test c * DoesNotExist() == DoesNotExist()
        @test dot(DoesNotExist(), c) == DoesNotExist()
        @test dot(c, DoesNotExist()) == DoesNotExist()

        @test Zero() * c == Zero()
        @test c * Zero() == Zero()
        @test dot(Zero(), c) == Zero()
        @test dot(c, Zero()) == Zero()

        @test One() * c === c
        @test c * One() === c

        t = @thunk 2
        @test t * c == 2 * c
        @test c * t == c * 2
    end

    @testset "scaling" begin
        @test (
            2 *  Composite{Foo}(y=1.5, x=2.5)
            == Composite{Foo}(y=3.0, x=5.0)
            == Composite{Foo}(y=1.5, x=2.5) * 2
        )
        @test (
            2 * Composite{Tuple{Float64, Float64}}(2.0, 4.0)
            == Composite{Tuple{Float64, Float64}}(4.0, 8.0)
            == Composite{Tuple{Float64, Float64}}(2.0, 4.0) * 2
        )
        d = Composite{Dict}(Dict(4 => 3.0))
        two_d = Composite{Dict}(Dict(4 => 2 * 3.0))
        @test 2 * d == two_d == d * 2
    end

    @testset "show" begin
        @test repr(Composite{Foo}(x=1,)) == "Composite{Foo}(x = 1,)"
        # check for exact regex match not occurence( `^...$`)
        # and allowing optional whitespace (`\s?`)
        @test occursin(
            r"^Composite{Tuple{Int64,\s?Int64}}\(1,\s?2\)$",
            repr(Composite{Tuple{Int64,Int64}}(1, 2)),
        )
    end

    @testset "internals" begin
        @testset "Can't do backing on primative type" begin
            @test_throws Exception ChainRulesCore.backing(1.4)
        end

        @testset "Internals don't allocate a ton" begin
            bk = (; x=1.0, y=2.0)
            VERSION >= v"1.5" && @test (@ballocated(ChainRulesCore.construct($Foo, $bk))) <= 32

            # weaker version of the above (which should pass on all versions)
            @test (@ballocated(ChainRulesCore.construct($Foo, $bk))) <= 48
            @test (@ballocated ChainRulesCore.elementwise_add($bk, $bk)) <= 48
        end
    end

    @testset "non-same-typed differential arithmetic" begin
        nt = (; a=1, b=2.0)
        c = Composite{typeof(nt)}(; a=DoesNotExist(), b=0.1)
        @test nt + c == (; a=1, b=2.1);
    end

    @testset "NO_FIELDS" begin
        @test NO_FIELDS === Zero()
    end
end


text:
module DependencyWalker

using ObjectFile, Crayons
import Libdl

export Library

struct Library{OH<:Union{ObjectHandle,Missing,Nothing}}
    path::String
    handle_type::Type{OH}
    level::Int
    deps::Vector{Library}
end

function Library(path::String, level::Int = 0)
    if !isfile(path)
        # TODO: should check also if it can be opened?
        return Library(path, Missing, level, Library[])
    end
    io = open(path, "r")
    oh = try
        readmeta(io)
    catch
        close(io)
        nothing
    end
    oh_new, deps = dependency_tree(oh, level)
    lib = Library(path, typeof(oh_new), level, deps)
    isopen(io) && close(io)
    return lib
end

Library(path::String, oht::Type{T}, level::Int) where {T<:Union{Missing,Nothing}} =
    Library{T}(path, oht, level, Library[])

Library(path::AbstractString, oht, level) =
    Library(String(path), oht, level)

# Check if `lib` matches `open_lib`, one of the libraries currently loaded in
# the system.  The condition to ignore the case is not quite accurate as this is
# a file-system property rather than an OS one, but in most cases this is
# correct.
@static if Sys.iswindows() || Sys.isapple()
    is_library_open(lib, open_lib) = occursin(lowercase(lib), lowercase(open_lib))
else
    is_library_open(lib, open_lib) = occursin(lib, open_lib)
end

function dependency_tree(oh::ObjectHandle, level::Int; dlext::String = Libdl.dlext)
    # Initialise list of dependencies
    deps = Library[]
    # Get the list of needed libraries
    deps_names = try
        keys(find_libraries(oh))
    catch
        # We've got an error while looking for the libraries.
        return nothing, deps
    end
    # Get list of already dlopen'ed libraries
    open_dls = Libdl.dllist()
    for dep in deps_names
        if Sys.iswindows() && occursin(r"^api-ms-win-.*\.dll"i, dep)
            # Skipp all "api-ms-win-*" libraries on Windows
            continue
        end
        split_dep = split(dep, '.')
        # Get rid of the soversion.  TODO: this is only for GNU/Linux and
        # FreeBSD, no idea what we have to do for the other operating systems.
        idx = findlast(isequal(dlext), split_dep)
        if !isnothing(idx)
            dep = join(split_dep[1:idx], '.')
        end
        # Get the first dlopen'ed library matching the needed library, if any
        idx = findfirst(d -> is_library_open(dep, d), open_dls)
        if isnothing(idx)
            # Push a missing library to the list
            push!(deps, Library(dep, Missing, level + 1))
        else
            # Push the found library to the list
            push!(deps, Library(open_dls[idx], level + 1))
        end
    end
    return oh, deps
end

dependency_tree(oh::Union{Nothing,Missing}, level) = (oh, Library[])

reduce_hash(x::UInt64) = Base.hash_64_32(x)
reduce_hash(x::UInt32) = x

function Base.show(io::IO, lib::Library{T}) where {T}
    if T === Missing
        symbol = "✗"
        extra_info = " (NOT FOUND)"
    elseif T === Nothing
        symbol = "❓"
        extra_info = " (COULD NOT READ METADATA)"
    else
        symbol = "◼"
        extra_info = ""
    end
    print(io, repeat("  ", lib.level), Crayon(foreground = reduce_hash(hash(lib.path))), symbol,
          Crayon(reset=true), " ", lib.path, Crayon(foreground = :yellow), "$(extra_info)")
    for dep in lib.deps
        println(io)
        show(io, dep)
    end
end

end # module


text:
using MergeSorted
using Base.Test

function test1()
    a = sort!(rand(1000))
    b = sort!(rand(1000))
    @test sort!(vcat(a,b)) == mergesorted(a,b)

    a = sort!(rand(1000), order=Base.Reverse)
    b = sort!(rand(1000), order=Base.Reverse)
    @test sort!(vcat(a,b), order=Base.Reverse) == mergesorted(a,b, order=Base.Reverse)
end

test1()


text:
# General
const Bits64 = Union{Int64, UInt64, Float64}
abstract type StaticRNG end
@inline Base.pointer(x::StaticRNG) = Ptr{UInt64}(Base.pointer_from_objref(x))

# SplitMix64
"""
```julia
SplitMix64([seed::Bits64])
```
Initialize the internal state of a StaticCompiler-safe (non-allocating) `SplitMix64`
deterministic pseudorandom number generator, optionally specifying a 64-bit `seed`
(which may be a `Float64`, `Int64`, or `UInt64`).

If a seed is not specified, `StaticTools.time()` will be used, which returns
the current Unix epoch time in seconds.

### See also:
`splitmix64`, `rand`

## Examples
```julia
julia> seed = StaticTools.time() # Pick a seed
1649890154

julia> rng = SplitMix64(seed) # Initialize the generator
SplitMix64{Int64}((1649890154,))

julia> splitmix64(rng) # Draw a pseudorandom `UInt64` from the generator
0xca764ac7b7ea31e8

julia> rand(rng) # Draw a `Float64` between 0 and 1
0.8704883051360292
```
"""
mutable struct SplitMix64{T<:Bits64} <: StaticRNG
    state::NTuple{1,T}
end
@inline SplitMix64(seed::Bits64=StaticTools.time()) = SplitMix64((seed,))
@inline Base.rand(rng::SplitMix64) = splitmix64(rng)/typemax(UInt64)
"""
```julia
splitmix64([rng::SplitMix64])
```
A StaticCompiler-safe (non-allocating) implementation of the SplitMix64
deterministic pseudorandom number generator.

### See also:
`SplitMix64`, `rand`

## Examples
```julia
julia> seed = StaticTools.time() # Pick a seed
1649890154

julia> rng = SplitMix64(seed) # Initialize the generator
SplitMix64{Int64}((1649890154,))

julia> splitmix64(rng) # Draw a pseudorandom `UInt64` from the generator
0xca764ac7b7ea31e8

julia> rand(rng) # Draw a `Float64` between 0 and 1
0.8704883051360292
```
"""
@inline splitmix64(rng::SplitMix64=SplitMix64()) = GC.@preserve rng splitmix64(pointer(rng))
@inline function splitmix64(state::Ptr{UInt64})
    s = unsafe_load(state)
    s += 0x9e3779b97f4a7c15
    unsafe_store!(state, s)
    z = s
    z = (z ⊻ (z >> 30)) * 0xbf58476d1ce4e5b9
    z = (z ⊻ (z >> 27)) * 0x94d049bb133111eb
    return z ⊻ (z >> 31)
end

# Xoshiro256✴✴
"""
```julia
Xoshiro256✴✴(seed::NTuple{4,Bits64})
```
Initialize the internal state of a StaticCompiler-safe (non-allocating)
`Xoshiro256✴✴` deterministic pseudorandom number generator, specifying a 256-bit
`seed`, which should be specified as an `NTuple` of four 64-bit numbers (all
either `Float64`, `Int64`, or `UInt64`).

### See also:
`xoshiro256✴✴`, `static_rng`, `rand`

## Examples
```julia
julia> seed = (0x9b134eccd2e63538, 0xd74ab64b2c3ecc9b, 0x70ba9c07628c27bf, 0x270a2eb658e6130b)
(0x9b134eccd2e63538, 0xd74ab64b2c3ecc9b, 0x70ba9c07628c27bf, 0x270a2eb658e6130b)

julia> rng = Xoshiro256✴✴(seed) # Initialize the generator
Xoshiro256✴✴{UInt64}((0x9b134eccd2e63538, 0xd74ab64b2c3ecc9b, 0x70ba9c07628c27bf, 0x270a2eb658e6130b))

julia> xoshiro256✴✴(rng) # Draw a pseudorandom `UInt64` from the generator
0x11059b6384fba06a

julia> rand(rng) # Draw a `Float64` between 0 and 1
0.9856766307398369
```
"""
mutable struct Xoshiro256✴✴{T<:Bits64} <: StaticRNG
    state::NTuple{4,T}
end
@inline function Xoshiro256✴✴(seed::Bits64=time())
    rng = SplitMix64(seed)
    Xoshiro256✴✴((splitmix64(rng),splitmix64(rng),splitmix64(rng),splitmix64(rng)))
end
@inline Base.rand(rng::Xoshiro256✴✴) = xoshiro256✴✴(rng)/typemax(UInt64)
# Xoshiro256✴✴ PRNG implemented in LLVM IR
"""
```julia
xoshiro256✴✴(rng::Xoshiro256✴✴)
```
A StaticCompiler-safe (non-allocating) implementation of the Xoshiro256✴✴
deterministic pseudorandom number generator, written in LLVM IR and
invoked via `llvmcall`.

### See also:
`Xoshiro256✴✴`, `static_rng`, `rand`

## Examples
```julia
julia> seed = (0x9b134eccd2e63538, 0xd74ab64b2c3ecc9b, 0x70ba9c07628c27bf, 0x270a2eb658e6130b);

julia> rng = Xoshiro256✴✴(seed) # Initialize the generator
Xoshiro256✴✴{UInt64}((0x9b134eccd2e63538, 0xd74ab64b2c3ecc9b, 0x70ba9c07628c27bf, 0x270a2eb658e6130b))

julia> xoshiro256✴✴(rng) # Draw a pseudorandom `UInt64` from the generator
0x11059b6384fba06a

julia> rand(rng) # Draw a `Float64` between 0 and 1
0.9856766307398369
```
"""
@inline xoshiro256✴✴(rng::Xoshiro256✴✴) = GC.@preserve rng xoshiro256✴✴(pointer(rng))
@inline function xoshiro256✴✴(state::Ptr{UInt64})
    Base.llvmcall(("""
    ; Function Attrs: noinline nounwind ssp uwtable
    define i64 @next(i64) #0 {
      %ptr = inttoptr i64 %0 to i64*
      %2 = alloca i64*, align 8
      %3 = alloca i64, align 8
      %4 = alloca i64, align 8
      store i64* %ptr, i64** %2, align 8
      %5 = load i64*, i64** %2, align 8
      %6 = getelementptr inbounds i64, i64* %5, i64 1
      %7 = load i64, i64* %6, align 8
      %8 = mul i64 %7, 5
      %9 = call i64 @rotl(i64 %8, i32 7)
      %10 = mul i64 %9, 9
      store i64 %10, i64* %3, align 8
      %11 = load i64*, i64** %2, align 8
      %12 = getelementptr inbounds i64, i64* %11, i64 1
      %13 = load i64, i64* %12, align 8
      %14 = shl i64 %13, 17
      store i64 %14, i64* %4, align 8
      %15 = load i64*, i64** %2, align 8
      %16 = getelementptr inbounds i64, i64* %15, i64 0
      %17 = load i64, i64* %16, align 8
      %18 = load i64*, i64** %2, align 8
      %19 = getelementptr inbounds i64, i64* %18, i64 2
      %20 = load i64, i64* %19, align 8
      %21 = xor i64 %20, %17
      store i64 %21, i64* %19, align 8
      %22 = load i64*, i64** %2, align 8
      %23 = getelementptr inbounds i64, i64* %22, i64 1
      %24 = load i64, i64* %23, align 8
      %25 = load i64*, i64** %2, align 8
      %26 = getelementptr inbounds i64, i64* %25, i64 3
      %27 = load i64, i64* %26, align 8
      %28 = xor i64 %27, %24
      store i64 %28, i64* %26, align 8
      %29 = load i64*, i64** %2, align 8
      %30 = getelementptr inbounds i64, i64* %29, i64 2
      %31 = load i64, i64* %30, align 8
      %32 = load i64*, i64** %2, align 8
      %33 = getelementptr inbounds i64, i64* %32, i64 1
      %34 = load i64, i64* %33, align 8
      %35 = xor i64 %34, %31
      store i64 %35, i64* %33, align 8
      %36 = load i64*, i64** %2, align 8
      %37 = getelementptr inbounds i64, i64* %36, i64 3
      %38 = load i64, i64* %37, align 8
      %39 = load i64*, i64** %2, align 8
      %40 = getelementptr inbounds i64, i64* %39, i64 0
      %41 = load i64, i64* %40, align 8
      %42 = xor i64 %41, %38
      store i64 %42, i64* %40, align 8
      %43 = load i64, i64* %4, align 8
      %44 = load i64*, i64** %2, align 8
      %45 = getelementptr inbounds i64, i64* %44, i64 2
      %46 = load i64, i64* %45, align 8
      %47 = xor i64 %46, %43
      store i64 %47, i64* %45, align 8
      %48 = load i64*, i64** %2, align 8
      %49 = getelementptr inbounds i64, i64* %48, i64 3
      %50 = load i64, i64* %49, align 8
      %51 = call i64 @rotl(i64 %50, i32 45)
      %52 = load i64*, i64** %2, align 8
      %53 = getelementptr inbounds i64, i64* %52, i64 3
      store i64 %51, i64* %53, align 8
      %54 = load i64, i64* %3, align 8
      ret i64 %54
    }

    ; Function Attrs: noinline nounwind ssp uwtable
    define internal i64 @rotl(i64, i32) #0 {
      %3 = alloca i64, align 8
      %4 = alloca i32, align 4
      store i64 %0, i64* %3, align 8
      store i32 %1, i32* %4, align 4
      %5 = load i64, i64* %3, align 8
      %6 = load i32, i32* %4, align 4
      %7 = zext i32 %6 to i64
      %8 = shl i64 %5, %7
      %9 = load i64, i64* %3, align 8
      %10 = load i32, i32* %4, align 4
      %11 = sub nsw i32 64, %10
      %12 = zext i32 %11 to i64
      %13 = lshr i64 %9, %12
      %14 = or i64 %8, %13
      ret i64 %14
    }

    attributes #0 = { noinline nounwind ssp uwtable }
    """, "next"), UInt64, Tuple{Ptr{UInt64}}, state)
end

"""
```julia
static_rng([seed::Bits64])
```
Initialize a StaticCompiler-safe (non-allocating) deterministic pseudorandom
number generator, optionally specifying a 64-bit `seed` (which may be any 64-bit
primitive numeric type -- that is, `Float64`, `Int64`, or `UInt64`).

In particular, `static_rng` uses the specified `seed` value (or if not specified,
the current result of `StaticTools.time()`) to initialize a simple `SplitMix64`
generator, which is then in turn used to bootstrap the larger seed required for a
`Xoshiro256✴✴` generator.

## Examples
```julia
julia> rng = static_rng()
Xoshiro256✴✴{UInt64}((0x2d4c7aa97cc1a621, 0x63460fc58ff25249, 0x81498572d44bd2ec, 0x2d4e96d3a7e9fdd2))

julia> rand(rng) # Draw a `Float64` between 0 and 1
0.6577585429879329

julia> rand(rng)
0.4711097758403277
```
"""
@inline static_rng(seed=StaticTools.time()) = Xoshiro256✴✴(seed)


text: @unix_only run(`make`)


text:
## Grouping machinery

fast_hashed(v::AbstractVector) = isbitstype(eltype(v)) ? PooledArray(v) : v

function permutation_ranges(cols)
    isempty(cols) && return nothing, [:]
    grouping_sa = StructArray(map(fast_hashed, cols))
    gp = GroupPerm(grouping_sa)
    return sortperm(gp), collect(gp)
end

shape(pl::ProcessedLayer) = Broadcast.combine_axes(pl.primary..., pl.positional..., pl.named...)

function shape(l::Layer)
    containers = (l.positional, l.named)
    wrappedvars = (v isa AbstractArray ? v : fill(v) for vs in containers for v in vs)
    return Broadcast.combine_axes(wrappedvars...)
end

function assert_equal(a, b)
    if !isequal(a, b)
        msg = "$a and $b must be equal"
        throw(ArgumentError(msg))
    end
    return a
end

getuniquevalue(v) = reduce(assert_equal, v)

function getnewindex(u, c)
    v = Broadcast.broadcastable(u)
    return v[Broadcast.newindex(v, c)]
end

function subgroups(vs, perm, rgs, axs)
    return map(Iterators.product(rgs, CartesianIndices(axs))) do (rg, c)
        v = getnewindex(vs, c)
        return ndims(v) == 0 || rg === (:) ? v : view(v, perm[rg])
    end
end

function shiftdims(v)
    w = Broadcast.broadcastable(v)
    return ndims(w) == 0 ? w[] : reshape(w, 1, axes(w)...)
end

function group(processedlayer::ProcessedLayer)
    grouping = Tuple(only(v) for v in values(processedlayer.primary) if ndims(v) == 0)
    perm, rgs = permutation_ranges(grouping)
    axs = shape(processedlayer)

    primary = map(vs -> subgroups(vs, perm, rgs, axs), processedlayer.primary)
    positional = map(vs -> subgroups(vs, perm, rgs, axs), processedlayer.positional)
    named = map(vs -> subgroups(vs, perm, rgs, axs), processedlayer.named)

    labels = map(shiftdims, processedlayer.labels)
    return ProcessedLayer(processedlayer; primary, positional, named, labels)
end

function getlabeledarray(layer::Layer, s)
    data, axs = layer.data, shape(layer)
    isdims = s isa DimsSelector || s isa Pair && first(s) isa DimsSelector
    if isdims
        vs, (f, label) = select(data, s)
        d = only(vs) # multiple dims selectors in the same mapping are disallowed
        sz = ntuple(length(axs)) do n
            return n in d.dims ? length(axs[n]) : 1
        end
        arr = map(fill∘f, CartesianIndices(sz))
    elseif isnothing(data)
        vs, (f, label) = select(data, s)
        isprim = any(iscategoricalcontainer, vs)
        arr = isprim ? map(fill∘f, vs...) : map(x -> map(f, x...), zip(vs...))
    else
        selector = s isa AbstractArray ? s : fill(s)
        labeled_arr = map(selector) do s
            local vs, (f, label) = select(data, s)
            return label, map(f, vs...)
        end
        label, arr = map(first, labeled_arr), map(last, labeled_arr)
    end
    return label, arr
end

function extract_values!(pairs, labels)
    merge!(labels, Dictionary(map(first, pairs)))
    return map(last, pairs)
end

function process_mappings(layer::Layer)
    labels = MixedArguments()
    positional = extract_values!(map(v -> getlabeledarray(layer, v), layer.positional), labels)
    named = extract_values!(map(v -> getlabeledarray(layer, v), layer.named), labels)
    primary, named = separate(iscategoricalcontainer, named)
    return ProcessedLayer(; primary, positional, named, labels)
end


text:
"""
    sample objective
"""
struct SampleObjective <: Objective
    Q
    R
end

sample_objective(Q, R) = SampleObjective(Q, R)

function objective(τ_nom, τ_sample, obj::SampleObjective,
        model_nom, model_sample,
        idx_τ_nom, idx_τ_sample, T)

    J = 0.0

    for t = 1:T
        ȳ = state_output(model_nom, view(τ_nom, idx_τ_nom.x[t]))
        y = state_output(model_sample, view(τ_sample, idx_τ_sample.x[t]))

        J += (y - ȳ)' * obj.Q[t] * (y - ȳ)

        t == T && continue

        v̄ = control_output(model_nom, view(τ_nom, idx_τ_nom.u[t]))
        v = control_output(model_sample, view(τ_sample, idx_τ_sample.u[t]))
        J += (v - v̄)' * obj.R[t] * (v - v̄)
    end

    return J
end

function objective_gradient!(∇J, τ_nom, τ_sample, obj::SampleObjective,
        model_nom, model_sample,
        idx_τ_nom, idx_τ_sample,
        idx_z_nom, idx_z_sample, T)

    for t = 1:T
        ȳ = state_output(model_nom, view(τ_nom, idx_τ_nom.x[t]))
        y = state_output(model_sample, view(τ_sample, idx_τ_sample.x[t]))

        ∇J[state_output_idx(model_nom, idx_z_nom[idx_τ_nom.x[t]])] -= 2.0 * obj.Q[t] * (y - ȳ)
        ∇J[state_output_idx(model_sample, idx_z_sample[idx_τ_sample.x[t]])] += 2.0 * obj.Q[t] * (y - ȳ)

        t == T && continue

        v̄ = control_output(model_nom, view(τ_nom, idx_τ_nom.u[t]))
        v = control_output(model_sample, view(τ_sample, idx_τ_sample.u[t]))

        ∇J[control_output(model_nom, idx_z_nom[idx_τ_nom.u[t]])] -= 2.0 * obj.R[t] * (v - v̄)
        ∇J[control_output(model_sample, idx_z_sample[idx_τ_sample.u[t]])] += 2.0 * obj.R[t] * (v - v̄)
    end

    return nothing
end

function objective(Z, obj::SampleObjective,
		prob::DPOProblems, idx::DPOIndices, N, D)

	J = 0.0

	τ_nom = view(Z, idx.nom)

	# samples
	for i = 1:N
		τ_sample = view(Z, idx.sample[i])
		J += objective(τ_nom, τ_sample, obj,
			prob.nom.model, prob.sample[i].model,
		    prob.nom.idx, prob.sample[i].idx, prob.nom.T)
	end

	return J
end

function objective_gradient!(∇J, Z, obj::SampleObjective,
		prob::DPOProblems, idx::DPOIndices, N, D)

	τ_nom = view(Z, idx.nom)

	for i = 1:N
		τ_sample = view(Z, idx.sample[i])
		objective_gradient!(∇J, τ_nom, τ_sample, obj,
		 	prob.nom.model, prob.sample[i].model,
		    prob.nom.idx, prob.sample[i].idx,
			idx.nom, idx.sample[i],
			prob.nom.T)
	end

	nothing
end

max_stars_repo_name: zacmanchester/DirectMotionPlanning

max_issues_repo_name: zacmanchester/DirectMotionPlanning

max_forks_repo_name: zacmanchester/DirectMotionPlanning


text:
module EventHandler

include("RunTime.jl")

function handleEvent(method, params)

  result = Dict()
  event = ""
  event_method = ""

  if method == "initialize"
    event = Dict()
    event_method = "initialized"

  elseif method == "launch"
    EventHandler.init(params["program"])
    put!(RunTime.kRunTimeIn, "launch")
    @async EventHandler.RunTime.run()
    if !haskey(params, "stopOnEntry")
      put!(RunTime.kRunTimeIn, "continue")
      finish_sig = take!(RunTime.kRunTimeOut)
      event, event_method = EventHandler.getStatus("breakpoint")
    else
      event_method = "stopped"
      event = Dict("reason" => "entry",
                   "description" => "stop on entry",
                   "text" => " ")
    end

  elseif method == "setBreakPoints"
    filePath = params["path"]
    lineno = params["lines"]
    result = EventHandler.setBreakPoints(filePath, lineno)

  elseif method == "configurationDone"
    result = Dict()

  elseif method == "continue"
    put!(RunTime.kRunTimeIn, "go on")
    put!(RunTime.kRunTimeIn, "continue")
    finish_sig = take!(RunTime.kRunTimeOut)
    event, event_method = EventHandler.getStatus("breakpoint")
    result = Dict("allThreadsContinued" => true)

  elseif method == "next"
    put!(RunTime.kRunTimeIn, "go on")
    put!(RunTime.kRunTimeIn, "stepOver")
    finish_sig = take!(RunTime.kRunTimeOut)
    event, event_method = EventHandler.getStatus("step")

  elseif method == "stackTrace"
    result = EventHandler.getStackTrace()

  elseif method == "scopes"
    frame_id = params["frameId"]
    result = EventHandler.getScopes(frame_id)

  elseif method == "variables"
    var_ref = params["variablesReference"]
    result = EventHandler.getVariables(var_ref)

  else
    # throw(MsgHandler.UnKnownMethod("$(method) can't be called"))
    result = "$method can't be called"
  end
  return result, event, event_method
end

function init(file)
  RunTime.setEntryFile(file)
end

function setBreakPoints(filepath, lineno)
  res = RunTime.setBreakPoints(filepath, lineno)
  result = []
  id = 1
  for idx in collect(1:1:length(lineno))
    if res[idx]
      push!(result, Dict("verified" => true,
                         "line" => lineno[idx],
                         "id" => id))
      id += 1
    else
      push!(result, Dict("verified" => false))
    end
  end
  return result
end

# get stack trace for the current collection
function getStackTrace()
  #return RunTime.DebugInfo.getStackInfo()
  info = RunTime.DebugInfo.getStackInfo()
  results = []
  path = ""
  line = 1
  if length(RunTime.RunBlockStatus) != 0
    path = collect(keys(RunTime.RunBlockStatus[end]))[1]
    line = RunTime.RunBlockStatus[end][path]
    # clear status since it will be set next break time
    RunTime.clearBlockStatus()
  elseif length(RunTime.RunFileStack) != 0
    path = RunTime.RunFileStack[end]
    line = RunTime.FileLine[path]
  else
    return info
  end
  push!(results, Dict("frameId" => 0,
                      "name" => "top",
                      "path" => path,
                      "line" => line))
  for frame in info
    push!(results, frame)
  end
  return results
end

function getScopes(frame_id)
  return Dict("name" => "main",
              "variablesReference" => 1000 + frame_id)
end

function getVariables(ref)
  if ref >= 1000
    ref = 1
  end
  return RunTime.DebugInfo.getVarInfo(ref)
end

function getStatus(reason)
  # detect if program is at end
  if length(RunTime.RunFileStack) == 0
    reason == "exited"
    return Dict("exitCode" => 0), "exited"
  end

  path = ""
  line = 1
  if length(RunTime.RunBlockStatus) != 0
    path = collect(keys(RunTime.RunBlockStatus[end]))[1]
    line = RunTime.RunBlockStatus[end][path]
  elseif length(RunTime.RunFileStack) != 0
    path = RunTime.RunFileStack[end]
    line = RunTime.FileLine[path]
  end

  description = ""
  if reason == "step"
    description = "step over (ignore breakpoints)"
  elseif reason == "breakpoint"
    description = "hit breakpoint: $(path): $(line)"
  end
  result = Dict("reason" => reason,
                "description" => description,
                "text" => " ")
  return result, "stopped"
end

end # module EventHandler

max_stars_repo_name: judy-vscode/judy

max_issues_repo_name: judy-vscode/judy

max_forks_repo_name: judy-vscode/judy


text:
using TKTDsimulations
using Test
using DifferentialEquations

@testset "Linear interpolation" begin
    # TEST INTERNAL FUNCTIONS: need specified TKTDsimulations because not Export
    # 1. linear interpolation
    @test TKTDsimulations.interpLinear([0,1,2,3], [0,0,2,2], 1.5) == 1.0
    @test TKTDsimulations.interpLinear([0,1,2,3], [0,0,2,2], 5.0) == 0
end

@testset "TK solver" begin
    # 2. odeTK
    @test_nowarn begin
        probTK = ODEProblem(TKTDsimulations.odeTK, [0.0], (0.0,3.0), [[0,1,2,3], [0,0,2,2], 0.5])
        _saveatTK = [0,1,2,3] === nothing ? Float64[] : [0,1,2,3]
        solve(probTK ; saveat = _saveatTK)
    end

    # tps = [0,1,2,3]
    # conc = [0,0,2,2]
    # kd = 0.5
    @test_nowarn runTK([0,1,2,3], [0,0,2,2], 0.5)
    # kd = [0.5, 0.6]
    @test_nowarn runTK_MCMC([0,1,2,3], [0,0,2,2], [0.5, 0.6])
end

@testset "SD solver" begin
    # 2.2 odeSD
    @test_nowarn begin
        probSD = ODEProblem(TKTDsimulations.odeSD, [0.0, 0.0], (0.0,3.0), [[0,1,2,3], [0,0,2,2], 0.5, 0.2, 0.3, 0.4])
        _saveatSD = [0,1,2,3] === nothing ? Float64[] : [0,1,2,3]
        solve(probSD ; saveat = _saveatSD)
    end

    tps = [0,1,2,3]
    conc = [5,5,5,5]
    kd = 0.5
    hb = 0.5
    z = 0.5
    kk = 0.5
    # TEST EXPORT FUNCTION: no need of TKTDsimulations specification because Export
    @test_nowarn runSD(tps, conc, kd, hb, z, kk)

    kd = [0.5, 2.0]
    hb = [0.5, 2.0]
    z = [0.5, 2.0]
    kk = [0.5, 2.0]
    @test_nowarn runSD_MCMC(tps, conc, kd, hb, z, kk)

end

@testset "IT solver" begin

    tps = [0,1,2,3]
    conc = [0,0,2,2]
    kd = 0.5
    hb = 0.5
    alpha = 0.5
    beta = 0.5
    @test_nowarn runIT(tps, conc, kd, hb, alpha, beta)

    kd = [0.5, 2.0]
    hb = [0.5, 2.0]
    alpha = [0.5, 2.0]
    beta = [0.5, 2.0]
    @test_nowarn runIT_MCMC(tps, conc, kd, hb, alpha, beta)

end


text:
#######################################
#
# BSA file
#
#######################################

"""
Read Besa's BSA (.bsa) file

#### Input
* `fname`: Name or path for the BSA file

#### Output
* `bsa`: Dipole object
"""
function read_bsa(fname::AbstractString)
    @info("Reading BSA file = $fname")

    # Open file
    file = open(fname, "r")

    # Read version
    first_line = readline(file)
    separator = something(findfirst(isequal('|'), first_line), 0)
    version = first_line[1:separator-1]
    coordinate_system = first_line[separator+1:end-1]

    # Read title line
    regexp =
        r"(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)"
    m = match(regexp, readline(file))

    # Read useless line
    readline(file)

    # Read dipoles
    dips = Neuroimaging.Dipole[]
    while !eof(file)
        dm = match(regexp, readline(file))

        dip = Dipole(
            coordinate_system,
            1u"m" * parse(Float64, dm.captures[2]) / 1000,
            1u"m" * parse(Float64, dm.captures[3]) / 1000,
            1u"m" * parse(Float64, dm.captures[4]) / 1000,
            parse(Float64, dm.captures[5]),
            parse(Float64, dm.captures[6]),
            parse(Float64, dm.captures[7]),
            parse(Float64, dm.captures[8]),
            parse(Float64, dm.captures[9]),
            parse(Float64, dm.captures[10]),
        )

        push!(dips, dip)
    end

    # Close file
    close(file)

    @debug("Version = $version")
    @debug("Coordinate System  = $coordinate_system")
    @debug("Dipoles = $(length(dips))")

    return dips
end


text:
module PatternStructure

include("Trees.jl")
include("Checks.jl")
include("SlurpTypes.jl")
include("Special.jl")
include("Printing.jl")

end


text:
using JuMP, EAGO

                     m = Model()

                     EAGO.register_eago_operators!(m)

                     @variable(m, -1 <= x[i=1:4] <= 1)

                     @variable(m, -12.503038214935698 <= q <= 11.138318577023822)

                     add_NL_constraint(m, :(sigmoid(-0.2825986234777189 + -0.06477303738755547*sigmoid(0.91111659897616 + 0.32194568310871174*$(x[1]) + -0.04079743189253193*$(x[2]) + -0.7834407613653229*$(x[3]) + -0.5105294854228863*$(x[4])) + 0.23435836886254213*sigmoid(-0.27698098400696525 + 0.765733032903245*$(x[1]) + 0.6374561618281618*$(x[2]) + -0.006430667300674209*$(x[3]) + -0.6595935184751247*$(x[4])) + 0.7516401137686608*sigmoid(0.7789283911146407 + -0.8853253179157212*$(x[1]) + -0.6613182381252614*$(x[2]) + 0.5007525575333553*$(x[3]) + 0.7960733427996214*$(x[4]))) + sigmoid(0.12692347233027856 + 0.060984281016326136*sigmoid(0.91111659897616 + 0.32194568310871174*$(x[1]) + -0.04079743189253193*$(x[2]) + -0.7834407613653229*$(x[3]) + -0.5105294854228863*$(x[4])) + 0.4767325000240725*sigmoid(-0.27698098400696525 + 0.765733032903245*$(x[1]) + 0.6374561618281618*$(x[2]) + -0.006430667300674209*$(x[3]) + -0.6595935184751247*$(x[4])) + -0.9515049437955176*sigmoid(0.7789283911146407 + -0.8853253179157212*$(x[1]) + -0.6613182381252614*$(x[2]) + 0.5007525575333553*$(x[3]) + 0.7960733427996214*$(x[4]))) + sigmoid(-0.022625917828582143 + -0.9740734403326825*sigmoid(0.91111659897616 + 0.32194568310871174*$(x[1]) + -0.04079743189253193*$(x[2]) + -0.7834407613653229*$(x[3]) + -0.5105294854228863*$(x[4])) + -0.9306328050206538*sigmoid(-0.27698098400696525 + 0.765733032903245*$(x[1]) + 0.6374561618281618*$(x[2]) + -0.006430667300674209*$(x[3]) + -0.6595935184751247*$(x[4])) + 0.61848968844355*sigmoid(0.7789283911146407 + -0.8853253179157212*$(x[1]) + -0.6613182381252614*$(x[2]) + 0.5007525575333553*$(x[3]) + 0.7960733427996214*$(x[4]))) - $q <= 0.0))

                     @objective(m, Min, q)

                     return m

max_stars_repo_name: PSORLab/RSActivationFunctions

max_issues_repo_name: PSORLab/RSActivationFunctions

max_forks_repo_name: PSORLab/RSActivationFunctions


text:
using CUDAnative

function kernel_vloop(a, b, c, i)
    c[i] = 0
    for j in 1:i
        c[i] += a[j] + b[j]
    end
    return nothing
end

Base.code_llvm(stdout, kernel_vloop, Tuple{CuDeviceArray{Float32,1,AS.Global},
                                           CuDeviceArray{Float32,1,AS.Global},
                                           CuDeviceArray{Float32,1,AS.Global},
                                           Int})

using TinyCassette
struct Ctx end

Base.code_llvm(stdout, TinyCassette.execute,
               Tuple{Ctx, typeof(kernel_vloop),
                     CuDeviceArray{Float32,1,AS.Global},
                     CuDeviceArray{Float32,1,AS.Global},
                     CuDeviceArray{Float32,1,AS.Global},
                     Int})


text:
function commandBind(ed::Editor, args::String)
    arg_arr = strip.(split(args, ' ', limit=2))

    if length(arg_arr) != 2
        setStatusMessage(ed, "bind: command requires two arguments")
        return
    elseif !( length(arg_arr[1]) == 1 && isletter(arg_arr[1][1]) )
        setStatusMessage(ed, "bind: first arg must be a letter")
        return
    end

    key = lowercase(arg_arr[1][1])
    command = join(arg_arr[2])

    # If command is '~', unbind the key
    if command == "~"
        rmKeyBinding(key)
    else
        setKeyBinding(key, join(arg_arr[2]))
    end

end

addCommand(:bind, commandBind,
            help="bind <C> <CMD>: bind ctrl-<C> to command <CMD>. <CMD> = ~, unbind")


text:
__precompile__(true)

"""
**Highlights.jl** is a Julia package for source code highlighting. It provides a regular
expression based mechanism for creating lexers in a similar way to Pygments.

The following names are exported from the root module, `Highlights`, and are available for
external use. Note that unexported names are considered unstable and subject to change.

$(EXPORTS)
"""
module Highlights

using DocStringExtensions
using InteractiveUtils

takebuf_str(b) = String(take!(b))

"""
$(TYPEDEF)

Represents a source code lexer used to tokenise text.
"""
abstract type AbstractLexer end

"""
$(TYPEDEF)

Represents a colour scheme used to highlight tokenised source code.
"""
abstract type AbstractTheme end

# Submodules.

include("Tokens.jl")
include("Compiler.jl")
include("Themes.jl")
include("Lexers.jl")
include("Format.jl")

# Public interface.

export Lexers, Themes, Tokens, Format, highlight, stylesheet, lexer

"""
$(SIGNATURES)

Return the `AbstractLexer` associated with the lexer named `name`. `name` must be a string.
Internally this checks the `:aliases` field in each lexer definition to see whether it is a
match.

!!! warning

    This method is *not* type stable.

When no lexer matches the given `name` an `ArgumentError` is thrown.
"""
function lexer(name::AbstractString)
    for each in subtypes(AbstractLexer)
        def = Compiler.metadata(each)
        name in def.aliases && return each
    end
    throw(ArgumentError("no lexer found with name '$name'."))
end

"""
Highlight source code using a specific lexer, mimetype and theme.

$(SIGNATURES)

`src` is tokenised using the provided `lexer`, then colourised using `theme`, and finally
output to `io` in the given format `mime`. `theme` defaults to `Themes.DefaultTheme` theme.

`mime` can be either `MIME("text/html")` or `MIME("text/latex")`.

# Examples

```jldoctest
julia> using Highlights

julia> highlight(stdout, MIME("text/html"), "2x", Lexers.JuliaLexer)
<pre class='hljl'>
<span class='hljl-ni'>2</span><span class='hljl-n'>x</span>
</pre>

julia> highlight(stdout, MIME("text/latex"), "'x'", Lexers.JuliaLexer, Themes.VimTheme)
\\begin{lstlisting}
(*@\\HLJLsc{{\\textquotesingle}x{\\textquotesingle}}@*)
\\end{lstlisting}

```
"""
function highlight(
        io::IO, mime::MIME, src::AbstractString,
        lexer::Type{L}, theme::Type{T} = Themes.DefaultTheme,
    ) where {
        L <: AbstractLexer,
  T <: AbstractTheme,
}
    Format.render(io, mime, Compiler.lex(src, L), Themes.theme(T))
end

"""
Generate a "stylesheet" for the given theme.

$(SIGNATURES)

Prints out the style information needed to colourise source code in the given
`theme`. Note that `theme` defaults to `Themes.DefaultTheme`. Output is printed
to `io` in the format `mime`. `mine` can be one of

  * `MIME("text/html")`
  * `MIME("text/css")`
  * `MIME("text/latex")`

# Examples

```jldoctest
julia> using Highlights

julia> buf = IOBuffer();

julia> stylesheet(buf, MIME("text/css"), Themes.EmacsTheme)

```
"""
stylesheet(io::IO, mime::MIME, theme::Type{T} = Themes.DefaultTheme) where {T <: AbstractTheme} =
    Format.render(io, mime, Themes.theme(T))

end # module


text:
# Autogenerated wrapper script for SuiteSparse_jll for i686-linux-gnu
export libamd, libbtf, libcamd, libccolamd, libcholmod, libcolamd, libklu, libldl, librbio, libspqr, libsuitesparseconfig, libumfpack

using libblastrampoline_jll
JLLWrappers.@generate_wrapper_header("SuiteSparse")
JLLWrappers.@declare_library_product(libamd, "libamd.so.2")
JLLWrappers.@declare_library_product(libbtf, "libbtf.so.1")
JLLWrappers.@declare_library_product(libcamd, "libcamd.so.2")
JLLWrappers.@declare_library_product(libccolamd, "libccolamd.so.2")
JLLWrappers.@declare_library_product(libcholmod, "libcholmod.so.3")
JLLWrappers.@declare_library_product(libcolamd, "libcolamd.so.2")
JLLWrappers.@declare_library_product(libklu, "libklu.so.1")
JLLWrappers.@declare_library_product(libldl, "libldl.so.2")
JLLWrappers.@declare_library_product(librbio, "librbio.so.2")
JLLWrappers.@declare_library_product(libspqr, "libspqr.so.2")
JLLWrappers.@declare_library_product(libsuitesparseconfig, "libsuitesparseconfig.so.5")
JLLWrappers.@declare_library_product(libumfpack, "libumfpack.so.5")
function __init__()
    JLLWrappers.@generate_init_header(libblastrampoline_jll)
    JLLWrappers.@init_library_product(
        libamd,
        "lib/libamd.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libbtf,
        "lib/libbtf.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libcamd,
        "lib/libcamd.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libccolamd,
        "lib/libccolamd.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libcholmod,
        "lib/libcholmod.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libcolamd,
        "lib/libcolamd.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libklu,
        "lib/libklu.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libldl,
        "lib/libldl.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        librbio,
        "lib/librbio.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libspqr,
        "lib/libspqr.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libsuitesparseconfig,
        "lib/libsuitesparseconfig.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libumfpack,
        "lib/libumfpack.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
# This file is part of RLinearAlgebra.jl

module ProceduralTestLSVRUnidSampler

using Test, RLinearAlgebra, Random

Random.seed!(1010)

@testset "LSVR Uniform Discrete Sampling -- Procedural" begin

    # Verify appropriate super type
    @test supertype(LinSysVecRowUnidSampler) == LinSysVecRowSampler

    # Test construction
    @test let
        A = rand(10,3)
        b = rand(10)
        x = rand(3)

        samp = LinSysVecRowUnidSampler()

        α, β = RLinearAlgebra.sample(samp, A, b, x, 1)

        true
    end

end

end


text:
#-------------------------------------------------------------------
#* EMSO Model Library (EML) Copyright (C) 2004 - 2007 ALSOC.
#*
#* This LIBRARY is free software; you can distribute it and/or modify
#* it under the therms of the ALSOC FREE LICENSE as available at
#* http://www.enq.ufrgs.br/alsoc.
#*
#* EMSO Copyright (C) 2004 - 2007 ALSOC, original code
#* from http://www.rps.eng.br Copyright (C) 2002-2004.
#* All rights reserved.
#*
#* EMSO is distributed under the therms of the ALSOC LICENSE as
#* available at http://www.enq.ufrgs.br/alsoc.
#*
#*----------------------------------------------------------------------
#* Author: Paula B. Staudt
#* $Id$
#*--------------------------------------------------------------------
type reboilerSteady
	reboilerSteady()=begin
		PP=outers.PP
		NComp=outers.NComp
		new(
			DanaPlugin(Dict{Symbol,Any}(
				:Brief=>"External Physical Properties",
				:Type=>"PP"
			)),
			DanaInteger(Dict{Symbol,Any}(
				:Brief=>"Number of Components"
			)),
			DanaSwitcher(Dict{Symbol,Any}(
				:Brief=>"Flash Calculation",
				:Valid=>["Flash_PH","Fake_Conditions"],
				:Default=>"Fake_Conditions"
			)),
			press_delta(Dict{Symbol,Any}(
				:Brief=>"Pressure Drop in the reboiler",
				:Symbol=>"\\Delta P"
			)),
			DanaReal(Dict{Symbol,Any}(
				:Brief=>"Flow Constant"
			)),
			temperature(Dict{Symbol,Any}(
				:Brief=>"Fake temperature",
				:Symbol=>"T_{fake}"
			)),
			fraction(Dict{Symbol,Any}(
				:Brief=>"Fake vapour fraction",
				:Symbol=>"v_{fake}"
			)),
			DanaReal(Dict{Symbol,Any}(
				:Brief=>"Flow Constant",
				:Hidden=>true,
				:Unit=>"mol^3/(kg*m^2)"
			)),
			stream(Dict{Symbol,Any}(
				:Brief=>"Liquid inlet stream",
				:PosX=>0.345,
				:PosY=>1,
				:Symbol=>"_{inL}",
				:Protected=>true
			)),
			stream(Dict{Symbol,Any}(
				:Brief=>"Vapour outlet stream",
				:PosX=>0.17,
				:PosY=>0,
				:Symbol=>"_{outV}",
				:Protected=>true
			)),
			power(Dict{Symbol,Any}(
				:Brief=>"Heat supplied",
				:PosX=>1,
				:PosY=>0.08,
				:Symbol=>"Q_{in}",
				:Protected=>true
			)),
			fill(fraction(Dict{Symbol,Any}(
				:Brief=>"Liquid Molar Fraction",
				:Hidden=>true
			)),(NComp)),
			fill(fraction(Dict{Symbol,Any}(
				:Brief=>"Vapour Molar Fraction",
				:Hidden=>true
			)),(NComp)),
			control_signal(Dict{Symbol,Any}(
				:Brief=>"Temperature  Indicator of Reboiler",
				:Protected=>true,
				:PosX=>0.44,
				:PosY=>0
			)),
			control_signal(Dict{Symbol,Any}(
				:Brief=>"Pressure Indicator of Reboiler",
				:Protected=>true,
				:PosX=>0.35,
				:PosY=>0
			)),
			[
				:(InletLiquid.F = OutletVapour.F),
				:(InletLiquid.z = OutletVapour.z),
				:(InletLiquid.F*InletLiquid.h + InletQ = OutletVapour.F*OutletVapour.h),
				:(OutletVapour.P = InletLiquid.P - Pdrop),
				:(TI * "K" = OutletVapour.T),
				:(PI * "atm" = OutletVapour.P),
				:(OutletVapour.F^3 = FlowConstant*k*InletQ),
				:(OutletVapour.v = Fake_Vfrac),
				:(OutletVapour.T = Fake_Temperature),
				:(x = 1),
				:(y = 1),
				:(OutletVapour.v = Fake_Vfrac),
				:(OutletVapour.T = Fake_Temperature),
				:(x = 1),
				:(y = 1),
			],
			[
				"Molar Flow Balance","Molar Composition Balance","Energy Balance","Pressure Drop","Temperature indicator","Pressure indicator","Flow through the reboiler","Fake Vapourisation Fraction","Fake output temperature","Fake Liquid Molar Fraction","Fake Vapour Molar Fraction","Fake Vapourisation Fraction","Fake output temperature","Fake Liquid Molar Fraction","Fake Vapour Molar Fraction",
			],
			[:PP,:NComp,:Flash_Calculation,:Pdrop,:FlowConstant,:Fake_Temperature,:Fake_Vfrac,:k,],
			[:InletLiquid,:OutletVapour,:InletQ,:x,:y,:TI,:PI,]
		)
	end
	PP::DanaPlugin
	NComp::DanaInteger
	Flash_Calculation::DanaSwitcher
	Pdrop::press_delta
	FlowConstant::DanaReal
	Fake_Temperature::temperature
	Fake_Vfrac::fraction
	k::DanaReal
	InletLiquid::stream
	OutletVapour::stream
	InletQ::power
	x::Array{fraction}
	y::Array{fraction}
	TI::control_signal
	PI::control_signal
	equations::Array{Expr,1}
	equationNames::Array{String,1}
	parameters::Array{Symbol,1}
	variables::Array{Symbol,1}
	attributes::Dict{Symbol,Any}
end
export reboilerSteady
function set(in::reboilerSteady)
	k = 1*"mol^3/(kg*m^2)"

end
function setEquationFlow(in::reboilerSteady)
	addEquation(1)
	addEquation(2)
	addEquation(3)
	addEquation(4)
	addEquation(5)
	addEquation(6)
	addEquation(7)
	let switch=Flash_Calculation
		if switch=="Flash_PH"
			#"Flash Calculation"
#	[OutletVapour.v, x, y] = PP.FlashPH(OutletVapour.P, OutletVapour.h, OutletVapour.z);
#
#"Enthalpy"
#	OutletVapour.h = (1-OutletVapour.v)*PP.LiquidEnthalpy(OutletVapour.T, OutletVapour.P, x) +
#	OutletVapour.v*PP.VapourEnthalpy(OutletVapour.T, OutletVapour.P, y);
#
addEquation(8)
			addEquation(9)
			addEquation(10)
			addEquation(11)
		elseif switch=="Fake_Conditions"
			addEquation(12)
			addEquation(13)
			addEquation(14)
			addEquation(15)
		end
	end
end
function atributes(in::reboilerSteady,_::Dict{Symbol,Any})
	fields::Dict{Symbol,Any}=Dict{Symbol,Any}()
	fields[:Pallete]=true
	fields[:Icon]="icon/ReboilerSteady"
	fields[:Brief]="Model of a  Steady State reboiler with no thermodynamics equilibrium - thermosyphon."
	fields[:Info]="Model of a  Steady State reboiler with two approaches:
**Fake Conditions: fake calculation of vaporisation fraction and output temperature, but with a real
calculation of the output stream enthalpy.

**Flash PH: in the outlet stream a PH Flash is performed to obtain the outlet conditions.

== ASSUMPTIONS ==
* perfect mixing of both phases;
* no thermodynamics equilibrium;

== SET ==
* the option Flash_Calculation
* the fake Outlet temperature;
* the fake outlet vapour fraction;
* the pressure drop in the reboiler;
* the FlowConstant that relates the Flow through the reboiler and the heat duty
**	Flow^3 = FlowConstant*InletQ

== SPECIFY ==
* the InletLiquid stream;
* the InletQ (the model requires an energy stream, also you can use a controller for setting the heat duty using the heat_flow model)
OR the outlet temperature (OutletVapour.T);

== OPTIONAL ==
* the reboiler model has two control ports
** TI OutletVapour Temperature Indicator;
** PI OutletVapour Pressure Indicator;
"
	drive!(fields,_)
	return fields
end
reboilerSteady(_::Dict{Symbol,Any})=begin
	newModel=reboilerSteady()
	newModel.attributes=atributes(newModel,_)
	newModel
end


text:
"""
        greedy_d1_coloring

Find a coloring of a given input graph such that
no two vertices connected by an edge have the same
color using greedy approach. The number of colors
used may be equal or greater than the chromatic
number χ(G) of the graph.
"""
function color_graph(g::VSafeGraph, alg::GreedyD1Color)
    v = nv(g)
    result = zeros(Int, v)
    result[1] = 1
    available = BitArray(undef, v)
    for i = 2:v
        for j in inneighbors(g, i)
            if result[j] != 0
                available[result[j]] = true
            end
        end
        for cr = 1:v
            if available[cr] == false
                result[i] = cr
                break
            end
        end
        fill!(available, false)
    end
    return result
end


text:
mutable struct ScoredSchedulerEntry
    match_limit::Int
    ban_length::Int
    times_banned::Int
    banned_until::Int
    weight::Int
end

"""
A Rewrite Scheduler that implements exponential rule backoff.
For each rewrite, there exists a configurable initial match limit.
If a rewrite search yield more than this limit, then we ban this rule
for number of iterations, double its limit, and double the time it
will be banned next time.

This seems effective at preventing explosive rules like
associativity from taking an unfair amount of resources.
"""
mutable struct ScoredScheduler <: AbstractScheduler
    data::IdDict{AbstractRule, ScoredSchedulerEntry}
    G::EGraph
    theory::Vector{<:AbstractRule}
    curr_iter::Int
end

cansearch(s::ScoredScheduler, r::AbstractRule)::Bool = s.curr_iter > s.data[r].banned_until

exprsize(a) = 1

function exprsize(e::PatTerm)
    c = 1 + length(e.args)
    for a ∈ e.args
        c += exprsize(a)
    end
    return c
end

function exprsize(e::Expr)
    start = Meta.isexpr(e, :call) ? 2 : 1

    c = 1 + length(e.args[start:end])
    for a ∈ e.args[start:end]
        c += exprsize(a)
    end

    return c
end

function ScoredScheduler(g::EGraph, theory::Vector{<:AbstractRule})
    # BackoffScheduler(g, theory, 128, 4)
    ScoredScheduler(g, theory, 1000, 5, exprsize)
end

function ScoredScheduler(G::EGraph, theory::Vector{<:AbstractRule}, match_limit::Int, ban_length::Int, complexity::Function)
    gsize = length(G.uf)
    data = IdDict{AbstractRule, ScoredSchedulerEntry}()

    for rule ∈ theory
        if rule isa DynamicRule
            w = 2
            data[rule] = ScoredSchedulerEntry(match_limit, ban_length, 0, 0, w)
            continue
        end
        (l, r) = rule.left, rule.right

        cl = complexity(l)
        cr = complexity(r)
        # println("$rule HAS SCORE $((cl, cr))")
        if cl > cr
            w = 1   # reduces complexity
        elseif cr > cl
            w = 3   # augments complexity
        else
            w = 2   # complexity is equal
        end
        # println(w)
        data[rule] = ScoredSchedulerEntry(match_limit, ban_length, 0, 0, w)
    end

    return ScoredScheduler(data, G, theory, 1)
end

# can saturate if there's no banned rule
cansaturate(s::ScoredScheduler)::Bool = all(kv -> s.curr_iter > last(kv).banned_until, s.data)

function inform!(s::ScoredScheduler, rule::AbstractRule, matches)
    # println(s.data[rule])

    rd = s.data[rule]
    treshold = rd.match_limit * (rd.weight^rd.times_banned)
    if length(matches) > treshold
        ban_length = rd.ban_length * (rd.weight^rd.times_banned)
        rd.times_banned += 1
        rd.banned_until = s.curr_iter + ban_length
        # @info "banning rule $rule until $(rd.banned_until)!"
        return false
    end
    return true
end

function setiter!(s::ScoredScheduler, curr_iter)
    s.curr_iter = curr_iter
end