text:
import Base: >>>

export bubble,
       stopbubbling,
       intent,
       constant,
       pairwith,
       sampler,
       output,
       trigger!,
       collector,
       watch!,
       subscribe

### Behavior ###

"""
A Behavior is a tile that can result in a stream of values.

The stream of values can be given intents, put into signals, used to trigger updates from other behaviors.

See `subscribe`, `intent`, `sampler` and `capture`
"""
abstract Behavior <: Tile

### Intent ###

"""
An intent is a transformation applied to the stream of values coming from a behavior

The purpose of an intent is to turn widget messages into types in the business logic of the application

For example, a simple intent is the pair with intent, if you have a list of buttons and would like to know which button was clicked as well as the mouse button that was pressed, you can attach the `pairwith` intent to the buttons:

    clicks = Signal(Tuple, (0, leftbutton))
    vbox([pairwith(idx, btn) >>> clicks for (idx, btn) in enumerate(buttons)])

Here the `clicks` signal will update to a tuple containing the index of the button clicked and the mouse button clicked whenever any of the buttons is clicked by the user.
"""
abstract Intent

@api intent => WithIntent <: Behavior begin
    arg(intent::Intent, doc="The intent")
    curry(tile::Behavior, doc="The behavior to apply the intent to")
end

render(i::WithIntent, state) = render(i.tile, state)

"""
Attach an intent to a behavior. A widget or a behavior has a default intent defined by the `default_intent` generic function. When another intent is attached to a behavior, it gets chained to the default intent.

Attaching an intent to a behavior results in a new behavior.
"""
intent(i::Intent, tile::Behavior) =
    WithIntent(Chained(i, default_intent(tile)), tile)
intent(i::Intent) = t -> intent(i, t)

"""
The default intent of a behavior. For example, a clickable behavior will convert JSON messages to the appropriate constants, `leftbutton`, `rightbutton`, `scrollbutton`.
"""
default_intent(::Behavior) = identity
default_intent(t::WithIntent) = t.intent

"""
takes an intent and the value and applies the intent to the value
"""
function interpret
end

"""
Identity intent. Does not change the input behavior.
"""
immutable Id <: Intent end
const identity = Id()

interpret(::Id, x) = x

"""
Apply two intents
"""
immutable Chained <: Intent
    intent1::Intent
    intent2::Intent
end

Chained(::Id, ::Id) = identity
Chained(a::Intent, ::Id) = a
Chained(::Id, a::Intent) = a
chain(x::Intent,y::Intent) = Chained(x, y)

interpret(i::Chained, x) =
    interpret(i.intent1, interpret(i.intent2, x))

"""
An intent to convert a value to type T.
"""
immutable ToType{T} <: Intent end

interpret{T}(::ToType{T}, x) = convert(T, x)
interpret{T<:Real}(::ToType{T}, x::AbstractString) = parse(T, x)
interpret{T<:Real}(::ToType{T}, x::Void) = zero(T)
interpret(::ToType{AbstractString}, x::Void) = ""

"""
Ignore the value from the behavior and replace it with a constant
"""
immutable Const{T} <: Intent
    value::T
end

constant(x) = Const(x)
interpret(x::Const, _) = x.value

"""
Intent to pair with a constant
"""
immutable PairWith{T} <: Intent
    value::T
end

pairwith(x) = PairWith(x)
interpret(x::PairWith, _) = x.value => _

"""
A function intent
"""
immutable ApplyIntent <: Intent
    f::Union{Function, Type}
end

intent(f::Union{Function, Type}, tile::Tile) = intent(ApplyIntent(f), tile)

interpret(i::ApplyIntent, x) = i.f(x)

@api bubble => (Bubble <: Behavior) begin
    doc(md""" Give a name to a behavior and allow outer tiles to listen to updates""")
    arg(name::Symbol, doc="The name to associate with the bubbled event")
    arg(tile::Behavior, doc="Behavior to bubble")
    kwarg(bubbles::Bool=true, doc="Enable/disable bubbling")
    kwarg(index::Int=0, doc="Index in an aggregate")
end

default_intent(b::Bubble) = default_intent(b.tile)

render(tile::Bubble, state) = begin
    withlastchild(render(tile.tile, state)) do elem
        elem & @d(:attributes => @d(
            :bubbles => boolattr(tile.bubbles),
            :name=>tile.name,
            :index=>tile.index,
            :id=>"signal-"*string(tile.name)),
        )
    end
end

@api stopbubbling => (StopBubbling <: Behavior) begin
    doc(md"""Stop bubbling of named events to parents.
             This can be used to stop bubbling set up via `bubble`."""
    )
    arg(tile::Tile, doc="Tile to contain the updates inside.")
    arg(names::Vector, doc="Names of the widget/behavior to stop.")
end

render(tile::StopBubbling, state) =
    render(tile.tile, state) <<
        Elem("stop-bubbling", names=tile.names)

### Collective Intents ###

@api sampler => (Sampler <: Intent) begin
    doc(md"""A means to make forms. Use `watch!` and `trigger!` to specify which
         widgets/behavior to watch and which widgets/behavior trigger the form.
         """)
    typedarg(triggers::Dict=Dict(), doc="Internal store for trigger elements.")
    arg(watches::Dict=Dict(), doc="Internal store for watches elements.")
end

interpret(s::Sampler, msg) = begin
    d = Dict()
    d[:_trigger] = symbol(msg["_trigger"])

    for (name, interp) in s.triggers
      if(haskey( msg, string(name)))
        d[name] = interpret(interp, msg[string(name)])
      end
    end

    for (name, interp) in s.watches
        @show name, interp
       d[name] = interpret(interp, msg[string(name)])
    end

    return d
end

watch!(sampler::Sampler, name::Symbol, tile) = begin
    sampler.watches[name] = default_intent(tile)
    bubble(name, wrapbehavior(tile))
end

watch!(sampler::Sampler, tile::Bubble) = begin
    sampler.watches[tile.name] = default_intent(tile)
    tile
end

watch!(sampler::Sampler, name) = t -> watch!(sampler, name, t)

@apidoc watch! => (Tile) begin
    doc("""Make a sampler watch a widget/behavior. Returns the input
         widget/behavior.""")
    arg(sampler::Sampler, doc="The sampler to add the watch on.")
    arg(name::Symbol, doc="A name used for bubbling updates")
    curry(tile::Behavior, doc="The widget/behavior.")
end

trigger!(sampler::Sampler, name::Symbol, tile) = begin
    sampler.triggers[name] = default_intent(tile)
    bubble(name, wrapbehavior(tile))
end

trigger!(sampler::Sampler, tile::Bubble) = begin
    sampler.triggers[tile.name] = default_intent(tile)
    tile
end

trigger!(sampler::Sampler, name::Symbol) = t -> trigger!(sampler, name, t)

@apidoc trigger! => (Tile) begin
    doc("""Make a sampler trigger on a change to a widget/behavior. Returns the
         input widget/behavior.""")
    arg(sampler::Sampler, doc="The sampler to add the trigger on.")
    arg(name::Symbol, doc="A name used for bubbling updates")
    curry(tile::Tile, doc="The widget/behavior.")
end

@api collector => (Collector <: Intent) begin
    doc(md"""Collect stream of values from many behaviors into one steam.
    The `aggregator` returns an intent which can then be applied to a tile that encapsulates
    all the aggregated behaviors
    """)
    typedarg(name::Symbol=:_collector, doc="A name for the collector. Events bubbling from collected tiles are matched to a collector using this name.")
    arg(intents::Vector=Intent[], doc="Internal storage of Intents of collected behaviors")
end

watch!(agg::Collector, tile) = begin
    push!(agg.intents, default_intent(tile))
    bubble(agg.name, tile, index=length(agg.intents))
end

immutable OuterListener{T <: Union{Sampler, Collector}} <: Behavior
    spec::T
    tile::Tile
end

intent(c::Union{Sampler, Collector}, tile::Tile) =
    WithIntent(c, OuterListener(c, tile))

render(c::OuterListener{Sampler}, state) = begin
    render(c.tile, state) <<
        Elem("signal-sampler", signals=collect(keys(c.spec.watches)), triggers=collect(keys(c.spec.triggers)))
end

render(c::OuterListener{Collector}, state) = begin
    render(c.tile, state) <<
        Elem("signal-collector", collectorName=c.spec.name)
end

immutable Collect <: Behavior
    collector::Collector
    index::Int
    tile::Behavior
end
default_intent(c::Collect) = default_intent(c.tile)

render(c::Collect, state) = begin
    withlastchild(render(c.tile, state)) do child
        child << Elem("signal-collect", collectorName=c.collector.name, index=c.index)
    end
end

# Interpret a message from a collectee
interpret(a::Collector, x) = begin
    interpret(a.intents[x["index"]], x["value"])
end

### Subscription ###

# """
# Subscribe to the stream of values from a behavior
# """
@api subscribe => (Subscription <: Tile) begin
    arg(receiver::Signal)
    arg(intent::Intent)
    arg(tile::Tile)
end

subscribe(s::Signal, t::Behavior) =
    subscribe(s, default_intent(t), t)

subscribe(s::Signal, t::WithIntent) =
    subscribe(s, t.intent, t.tile)

subscribe(s::Signal, t::OuterListener) =
    subscribe(s, t.spec, t)

subscribe(c::Collector, tile::Behavior) = begin
    push!(c.intents, default_intent(tile))
    Collect(c, length(c.intents), tile)
end

@apidoc subscribe => (Subscription <: Behavior) begin
    doc(md"""Subscribe to updates from a widget/behavior. `>>>` is an infix
             alias to subscribe"""
    )
    arg(
        input::Signal,
        doc=md"""The input signal to update. See
            [Reactive.jl documentation](http://julialang.org/Reactive.jl/#a-tutorial-introduction)
            for more on input signals."""
    )
    arg(tile::Tile, doc="The widget/behavior.")
    kwarg(
        absorb::Bool=true,
        doc="If set to true, the update event will not bubble out from the widget."
    )
end

render(sig::Subscription, state) =
    withlastchild(render(sig.tile, state)) do child
        # NOTE: This implementation assumes that
        # The behavior will have rendered an element "inside" the behavior-creator element
        # So this puts a constraint on the way behaviors should be implemented

        child << Elem("signal-transport", signalId=makeid((sig.receiver, sig.intent)))
    end

(>>>)(t::Tile, s::Union{Signal, Collector}) = subscribe(s, t)

import Base.Random: UUID, uuid4

const object_to_id = Dict()
const id_to_object = Dict()

"""
Create a unique ID for a (Signal, Intent) pair
"""
makeid(object) = begin
    if haskey(object_to_id, object)
        # TODO ensure connection & reject / collect
        return object_to_id[object]
    else
        id = haskey(object_to_id, object) ?
            object_to_id[object] : string(rand(UInt128))
        object_to_id[object] = id
        id_to_object[id] = object
        return id
    end
end

"""
Given the unique ID created by makeid, return the object associated with it.
"""
fromid(id) = id_to_object[id]


text:
function TrapezoidIntegrator()
    return TrapezoidIntegrator(())
end

function TrapezoidIntegrator(arg0::jdouble, arg1::jdouble, arg2::jint, arg3::jint)
    return TrapezoidIntegrator((jdouble, jdouble, jint, jint), arg0, arg1, arg2, arg3)
end

function TrapezoidIntegrator(arg0::jint, arg1::jint)
    return TrapezoidIntegrator((jint, jint), arg0, arg1)
end

ext: jl


text:
using ApproxFun

M = 50
d₋, d₊ = -M .. 0, 0 ..M
D = Derivative()

V₋ = Fun(x -> sech(x), d₋)
V₊ = Fun(x -> sech(x), d₊)

# ψ'' + (V(x) + k^2) ψ = 0

k = 0.0001

ψ = [ivp(); D^2  + (V₋ + k^2)] \ [exp(im*k*(-M)), im*k*(exp(im*k*(-M))), 0.0]

max_stars_repo_path: examples/Third order.jl

max_issues_repo_path: examples/Third order.jl

max_forks_repo_path: examples/Third order.jl


text:
Base.@kwdef mutable struct PlotlinesDisplayProperties{T₁ <: Function, T₂ <: NTuple} <: AbstractDisplayProperties
    id::String
    caption::T₁
    col::ImVec4 = ImVec4(0, 0, 0, 1)
    createwindow::Bool = true
    layout::RectangularLayout
    yaxis::Axis = Axis()
    xaxis::Axis = Axis()
    xtick::Tickmark = Tickmark()
    ytick::Tickmark = Tickmark()
    padding::T₂ = (0, 0, 0 ,0)
end

function get_id(p::PlotlinesDisplayProperties)
    p.id
end

function get_captioner(p::PlotlinesDisplayProperties)
    p.caption
end

function get_col(p::PlotlinesDisplayProperties)
    p.col
end

function is_new_window(p::PlotlinesDisplayProperties)
    p.createwindow
end

function get_layout(p::PlotlinesDisplayProperties)
    p.layout
end

function get_xaxis(p::PlotlinesDisplayProperties)
    p.xaxis
end

function get_yaxis(p::PlotlinesDisplayProperties)
    p.yaxis
end

function get_xtick(p::PlotlinesDisplayProperties)
    p.xtick
end

function get_ytick(p::PlotlinesDisplayProperties)
    p.ytick
end

function get_padding(p::PlotlinesDisplayProperties)
    p.padding
end

function set_id!(p::PlotlinesDisplayProperties, id::String)
    p.id = id
end

#TODO change captioner to caption
function set_captioner!(p::PlotlinesDisplayProperties, caption::Function)
    p.caption = caption
end

function set_col!(p::PlotlinesDisplayProperties, col::ImVec4)
    p.col = col
end

function set_layout!(p::PlotlinesDisplayProperties, layout::RectangularLayout)
    p.layout = layout
end

function set_xtick!(p::PlotlinesDisplayProperties, xtick::Tickmark)
    p.xtick = xtick
end

function set_ytick!(p::PlotlinesDisplayProperties, ytick::Tickmark)
    p.ytick = ytick
end

function set_paddding!(p::PlotlinesDisplayProperties, padding::NTuple)
    p.padding = padding
end


text:
function greedy_construction(tuning_run::Run,
                             target::String;
                             cutoff::Integer = 10_000)
    initial_cost = tuning_run.starting_cost
    x            = deepcopy(tuning_run.starting_point)
    x_proposal   = deepcopy(tuning_run.starting_point)
    name         = "Greedy Construction"
    cost_calls   = 0
    iteration    = 1
    while iteration <= cutoff
        iteration += 1
        neighbor!(x_proposal, target)
        proposal    = @fetch (tuning_run.measurement_method(tuning_run, x_proposal))
        cost_calls += tuning_run.cost_evaluations
        if proposal <= initial_cost
            update!(x, x_proposal.parameters)
            initial_cost = proposal
            return Result(name, tuning_run.starting_point, x, initial_cost, iteration,
                          iteration, cost_calls, false)
        end
    end
    Result(name, tuning_run.starting_point, x, initial_cost, iteration,
           iteration, cost_calls, false)
end


text:
module Instance

export Monitoring

include("monitoring.jl")
using Instance.Monitoring

end # module

max_stars_repo_name: Gollor/JuliaAutomation

max_issues_repo_name: Gollor/JuliaAutomation

max_forks_repo_name: Gollor/JuliaAutomation


text:
# https://adventofcode.com/2020/day/2
abstract type Day2 <: AocDay end
day2 = Day2

struct InputDay2
    min::Int64
    max::Int64
    sym::Char
    pwd::String
end

function readinput(::Type{Day2})
    input = readlines("input/day2.txt")
    r = r"^([0-9]*)-([0-9]*) (.*): (.*)$"
    captures = Array{InputDay2,1}(undef, length(input))
    for (idx, line) in enumerate(input)
        m = match(r, line)
        c = m.captures
        min = parse(Int, m.captures[1])
        max = parse(Int, m.captures[2])
        sym = only(m.captures[3])
        pwd = m.captures[4]
        t = InputDay2(min, max, sym, pwd)
        captures[idx] = t
    end
    captures
end

function valid(input::InputDay2)
    occurances = sum((c == input.sym for c in input.pwd))
    (occurances >= input.min) && (occurances <= input.max)
end

function valid_part2(input::InputDay2)
    pos1, pos2, c = input.min, input.max, input.sym
    xor(input.pwd[pos1] == c, input.pwd[pos2] == c)
end

function solve(day::Type{Day2})
    input = readinput(day)
    sum(valid.(input))
end

function part2(day::Type{Day2})
    input = readinput(day)
    sum(valid_part2.(input))
end


text:
# Julia wrapper for header: Network.h
# Automatically generated using Clang.jl

# Julia wrapper for header: Export.h
# Automatically generated using Clang.jl

# Julia wrapper for header: Ftp.h
# Automatically generated using Clang.jl

function sfFtpListingResponse_destroy(ftpListingResponse)
    ccall((:sfFtpListingResponse_destroy, libcsfml_network), Cvoid, (Ptr{sfFtpListingResponse},), ftpListingResponse)
end

function sfFtpListingResponse_isOk(ftpListingResponse)
    ccall((:sfFtpListingResponse_isOk, libcsfml_network), sfBool, (Ptr{sfFtpListingResponse},), ftpListingResponse)
end

function sfFtpListingResponse_getStatus(ftpListingResponse)
    ccall((:sfFtpListingResponse_getStatus, libcsfml_network), sfFtpStatus, (Ptr{sfFtpListingResponse},), ftpListingResponse)
end

function sfFtpListingResponse_getMessage(ftpListingResponse)
    ccall((:sfFtpListingResponse_getMessage, libcsfml_network), Cstring, (Ptr{sfFtpListingResponse},), ftpListingResponse)
end

function sfFtpListingResponse_getCount(ftpListingResponse)
    ccall((:sfFtpListingResponse_getCount, libcsfml_network), Csize_t, (Ptr{sfFtpListingResponse},), ftpListingResponse)
end

function sfFtpListingResponse_getName(ftpListingResponse, index)
    ccall((:sfFtpListingResponse_getName, libcsfml_network), Cstring, (Ptr{sfFtpListingResponse}, Csize_t), ftpListingResponse, index)
end

function sfFtpDirectoryResponse_destroy(ftpDirectoryResponse)
    ccall((:sfFtpDirectoryResponse_destroy, libcsfml_network), Cvoid, (Ptr{sfFtpDirectoryResponse},), ftpDirectoryResponse)
end

function sfFtpDirectoryResponse_isOk(ftpDirectoryResponse)
    ccall((:sfFtpDirectoryResponse_isOk, libcsfml_network), sfBool, (Ptr{sfFtpDirectoryResponse},), ftpDirectoryResponse)
end

function sfFtpDirectoryResponse_getStatus(ftpDirectoryResponse)
    ccall((:sfFtpDirectoryResponse_getStatus, libcsfml_network), sfFtpStatus, (Ptr{sfFtpDirectoryResponse},), ftpDirectoryResponse)
end

function sfFtpDirectoryResponse_getMessage(ftpDirectoryResponse)
    ccall((:sfFtpDirectoryResponse_getMessage, libcsfml_network), Cstring, (Ptr{sfFtpDirectoryResponse},), ftpDirectoryResponse)
end

function sfFtpDirectoryResponse_getDirectory(ftpDirectoryResponse)
    ccall((:sfFtpDirectoryResponse_getDirectory, libcsfml_network), Cstring, (Ptr{sfFtpDirectoryResponse},), ftpDirectoryResponse)
end

function sfFtpResponse_destroy(ftpResponse)
    ccall((:sfFtpResponse_destroy, libcsfml_network), Cvoid, (Ptr{sfFtpResponse},), ftpResponse)
end

function sfFtpResponse_isOk(ftpResponse)
    ccall((:sfFtpResponse_isOk, libcsfml_network), sfBool, (Ptr{sfFtpResponse},), ftpResponse)
end

function sfFtpResponse_getStatus(ftpResponse)
    ccall((:sfFtpResponse_getStatus, libcsfml_network), sfFtpStatus, (Ptr{sfFtpResponse},), ftpResponse)
end

function sfFtpResponse_getMessage(ftpResponse)
    ccall((:sfFtpResponse_getMessage, libcsfml_network), Cstring, (Ptr{sfFtpResponse},), ftpResponse)
end

function sfFtp_create()
    ccall((:sfFtp_create, libcsfml_network), Ptr{sfFtp}, ())
end

function sfFtp_destroy(ftp)
    ccall((:sfFtp_destroy, libcsfml_network), Cvoid, (Ptr{sfFtp},), ftp)
end

function sfFtp_connect(ftp, server, port, timeout)
    ccall((:sfFtp_connect, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp}, sfIpAddress, UInt16, sfTime), ftp, server, port, timeout)
end

function sfFtp_loginAnonymous(ftp)
    ccall((:sfFtp_loginAnonymous, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp},), ftp)
end

function sfFtp_login(ftp, name, password)
    ccall((:sfFtp_login, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp}, Cstring, Cstring), ftp, name, password)
end

function sfFtp_disconnect(ftp)
    ccall((:sfFtp_disconnect, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp},), ftp)
end

function sfFtp_keepAlive(ftp)
    ccall((:sfFtp_keepAlive, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp},), ftp)
end

function sfFtp_getWorkingDirectory(ftp)
    ccall((:sfFtp_getWorkingDirectory, libcsfml_network), Ptr{sfFtpDirectoryResponse}, (Ptr{sfFtp},), ftp)
end

function sfFtp_getDirectoryListing(ftp, directory)
    ccall((:sfFtp_getDirectoryListing, libcsfml_network), Ptr{sfFtpListingResponse}, (Ptr{sfFtp}, Cstring), ftp, directory)
end

function sfFtp_changeDirectory(ftp, directory)
    ccall((:sfFtp_changeDirectory, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp}, Cstring), ftp, directory)
end

function sfFtp_parentDirectory(ftp)
    ccall((:sfFtp_parentDirectory, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp},), ftp)
end

function sfFtp_createDirectory(ftp, name)
    ccall((:sfFtp_createDirectory, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp}, Cstring), ftp, name)
end

function sfFtp_deleteDirectory(ftp, name)
    ccall((:sfFtp_deleteDirectory, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp}, Cstring), ftp, name)
end

function sfFtp_renameFile(ftp, file, newName)
    ccall((:sfFtp_renameFile, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp}, Cstring, Cstring), ftp, file, newName)
end

function sfFtp_deleteFile(ftp, name)
    ccall((:sfFtp_deleteFile, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp}, Cstring), ftp, name)
end

function sfFtp_download(ftp, remoteFile, localPath, mode)
    ccall((:sfFtp_download, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp}, Cstring, Cstring, sfFtpTransferMode), ftp, remoteFile, localPath, mode)
end

function sfFtp_upload(ftp, localFile, remotePath, mode, append)
    ccall((:sfFtp_upload, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp}, Cstring, Cstring, sfFtpTransferMode, sfBool), ftp, localFile, remotePath, mode, append)
end

function sfFtp_sendCommand(ftp, command, parameter)
    ccall((:sfFtp_sendCommand, libcsfml_network), Ptr{sfFtpResponse}, (Ptr{sfFtp}, Cstring, Cstring), ftp, command, parameter)
end
# Julia wrapper for header: Http.h
# Automatically generated using Clang.jl

function sfHttpRequest_create()
    ccall((:sfHttpRequest_create, libcsfml_network), Ptr{sfHttpRequest}, ())
end

function sfHttpRequest_destroy(httpRequest)
    ccall((:sfHttpRequest_destroy, libcsfml_network), Cvoid, (Ptr{sfHttpRequest},), httpRequest)
end

function sfHttpRequest_setField(httpRequest, field, value)
    ccall((:sfHttpRequest_setField, libcsfml_network), Cvoid, (Ptr{sfHttpRequest}, Cstring, Cstring), httpRequest, field, value)
end

function sfHttpRequest_setMethod(httpRequest, method)
    ccall((:sfHttpRequest_setMethod, libcsfml_network), Cvoid, (Ptr{sfHttpRequest}, sfHttpMethod), httpRequest, method)
end

function sfHttpRequest_setUri(httpRequest, uri)
    ccall((:sfHttpRequest_setUri, libcsfml_network), Cvoid, (Ptr{sfHttpRequest}, Cstring), httpRequest, uri)
end

function sfHttpRequest_setHttpVersion(httpRequest, major, minor)
    ccall((:sfHttpRequest_setHttpVersion, libcsfml_network), Cvoid, (Ptr{sfHttpRequest}, UInt32, UInt32), httpRequest, major, minor)
end

function sfHttpRequest_setBody(httpRequest, body)
    ccall((:sfHttpRequest_setBody, libcsfml_network), Cvoid, (Ptr{sfHttpRequest}, Cstring), httpRequest, body)
end

function sfHttpResponse_destroy(httpResponse)
    ccall((:sfHttpResponse_destroy, libcsfml_network), Cvoid, (Ptr{sfHttpResponse},), httpResponse)
end

function sfHttpResponse_getField(httpResponse, field)
    ccall((:sfHttpResponse_getField, libcsfml_network), Cstring, (Ptr{sfHttpResponse}, Cstring), httpResponse, field)
end

function sfHttpResponse_getStatus(httpResponse)
    ccall((:sfHttpResponse_getStatus, libcsfml_network), sfHttpStatus, (Ptr{sfHttpResponse},), httpResponse)
end

function sfHttpResponse_getMajorVersion(httpResponse)
    ccall((:sfHttpResponse_getMajorVersion, libcsfml_network), UInt32, (Ptr{sfHttpResponse},), httpResponse)
end

function sfHttpResponse_getMinorVersion(httpResponse)
    ccall((:sfHttpResponse_getMinorVersion, libcsfml_network), UInt32, (Ptr{sfHttpResponse},), httpResponse)
end

function sfHttpResponse_getBody(httpResponse)
    ccall((:sfHttpResponse_getBody, libcsfml_network), Cstring, (Ptr{sfHttpResponse},), httpResponse)
end

function sfHttp_create()
    ccall((:sfHttp_create, libcsfml_network), Ptr{sfHttp}, ())
end

function sfHttp_destroy(http)
    ccall((:sfHttp_destroy, libcsfml_network), Cvoid, (Ptr{sfHttp},), http)
end

function sfHttp_setHost(http, host, port)
    ccall((:sfHttp_setHost, libcsfml_network), Cvoid, (Ptr{sfHttp}, Cstring, UInt16), http, host, port)
end

function sfHttp_sendRequest(http, request, timeout)
    ccall((:sfHttp_sendRequest, libcsfml_network), Ptr{sfHttpResponse}, (Ptr{sfHttp}, Ptr{sfHttpRequest}, sfTime), http, request, timeout)
end
# Julia wrapper for header: IpAddress.h
# Automatically generated using Clang.jl

function sfIpAddress_fromString(address)
    ccall((:sfIpAddress_fromString, libcsfml_network), sfIpAddress, (Cstring,), address)
end

function sfIpAddress_fromBytes(byte0, byte1, byte2, byte3)
    ccall((:sfIpAddress_fromBytes, libcsfml_network), sfIpAddress, (sfUint8, sfUint8, sfUint8, sfUint8), byte0, byte1, byte2, byte3)
end

function sfIpAddress_fromInteger(address)
    ccall((:sfIpAddress_fromInteger, libcsfml_network), sfIpAddress, (sfUint32,), address)
end

function sfIpAddress_toString(address, string)
    ccall((:sfIpAddress_toString, libcsfml_network), Cvoid, (sfIpAddress, Cstring), address, string)
end

function sfIpAddress_toInteger(address)
    ccall((:sfIpAddress_toInteger, libcsfml_network), sfUint32, (sfIpAddress,), address)
end

function sfIpAddress_getLocalAddress()
    ccall((:sfIpAddress_getLocalAddress, libcsfml_network), sfIpAddress, ())
end

function sfIpAddress_getPublicAddress(timeout)
    ccall((:sfIpAddress_getPublicAddress, libcsfml_network), sfIpAddress, (sfTime,), timeout)
end
# Julia wrapper for header: Packet.h
# Automatically generated using Clang.jl

function sfPacket_create()
    ccall((:sfPacket_create, libcsfml_network), Ptr{sfPacket}, ())
end

function sfPacket_copy(packet)
    ccall((:sfPacket_copy, libcsfml_network), Ptr{sfPacket}, (Ptr{sfPacket},), packet)
end

function sfPacket_destroy(packet)
    ccall((:sfPacket_destroy, libcsfml_network), Cvoid, (Ptr{sfPacket},), packet)
end

function sfPacket_append(packet, data, sizeInBytes)
    ccall((:sfPacket_append, libcsfml_network), Cvoid, (Ptr{sfPacket}, Ptr{Cvoid}, Csize_t), packet, data, sizeInBytes)
end

function sfPacket_clear(packet)
    ccall((:sfPacket_clear, libcsfml_network), Cvoid, (Ptr{sfPacket},), packet)
end

function sfPacket_getData(packet)
    ccall((:sfPacket_getData, libcsfml_network), Ptr{Cvoid}, (Ptr{sfPacket},), packet)
end

function sfPacket_getDataSize(packet)
    ccall((:sfPacket_getDataSize, libcsfml_network), Csize_t, (Ptr{sfPacket},), packet)
end

function sfPacket_endOfPacket(packet)
    ccall((:sfPacket_endOfPacket, libcsfml_network), sfBool, (Ptr{sfPacket},), packet)
end

function sfPacket_canRead(packet)
    ccall((:sfPacket_canRead, libcsfml_network), sfBool, (Ptr{sfPacket},), packet)
end

function sfPacket_readBool(packet)
    ccall((:sfPacket_readBool, libcsfml_network), sfBool, (Ptr{sfPacket},), packet)
end

function sfPacket_readInt8(packet)
    ccall((:sfPacket_readInt8, libcsfml_network), sfInt8, (Ptr{sfPacket},), packet)
end

function sfPacket_readUint8(packet)
    ccall((:sfPacket_readUint8, libcsfml_network), sfUint8, (Ptr{sfPacket},), packet)
end

function sfPacket_readInt16(packet)
    ccall((:sfPacket_readInt16, libcsfml_network), sfInt16, (Ptr{sfPacket},), packet)
end

function sfPacket_readUint16(packet)
    ccall((:sfPacket_readUint16, libcsfml_network), sfUint16, (Ptr{sfPacket},), packet)
end

function sfPacket_readInt32(packet)
    ccall((:sfPacket_readInt32, libcsfml_network), sfInt32, (Ptr{sfPacket},), packet)
end

function sfPacket_readUint32(packet)
    ccall((:sfPacket_readUint32, libcsfml_network), sfUint32, (Ptr{sfPacket},), packet)
end

function sfPacket_readFloat(packet)
    ccall((:sfPacket_readFloat, libcsfml_network), Cfloat, (Ptr{sfPacket},), packet)
end

function sfPacket_readDouble(packet)
    ccall((:sfPacket_readDouble, libcsfml_network), Cdouble, (Ptr{sfPacket},), packet)
end

function sfPacket_readString(packet, string)
    ccall((:sfPacket_readString, libcsfml_network), Cvoid, (Ptr{sfPacket}, Cstring), packet, string)
end

function sfPacket_readWideString(packet, string)
    ccall((:sfPacket_readWideString, libcsfml_network), Cvoid, (Ptr{sfPacket}, Ptr{Cwchar_t}), packet, string)
end

function sfPacket_writeBool(packet, arg1)
    ccall((:sfPacket_writeBool, libcsfml_network), Cvoid, (Ptr{sfPacket}, sfBool), packet, arg1)
end

function sfPacket_writeInt8(packet, arg1)
    ccall((:sfPacket_writeInt8, libcsfml_network), Cvoid, (Ptr{sfPacket}, sfInt8), packet, arg1)
end

function sfPacket_writeUint8(packet, arg1)
    ccall((:sfPacket_writeUint8, libcsfml_network), Cvoid, (Ptr{sfPacket}, sfUint8), packet, arg1)
end

function sfPacket_writeInt16(packet, arg1)
    ccall((:sfPacket_writeInt16, libcsfml_network), Cvoid, (Ptr{sfPacket}, sfInt16), packet, arg1)
end

function sfPacket_writeUint16(packet, arg1)
    ccall((:sfPacket_writeUint16, libcsfml_network), Cvoid, (Ptr{sfPacket}, sfUint16), packet, arg1)
end

function sfPacket_writeInt32(packet, arg1)
    ccall((:sfPacket_writeInt32, libcsfml_network), Cvoid, (Ptr{sfPacket}, sfInt32), packet, arg1)
end

function sfPacket_writeUint32(packet, arg1)
    ccall((:sfPacket_writeUint32, libcsfml_network), Cvoid, (Ptr{sfPacket}, sfUint32), packet, arg1)
end

function sfPacket_writeFloat(packet, arg1)
    ccall((:sfPacket_writeFloat, libcsfml_network), Cvoid, (Ptr{sfPacket}, Cfloat), packet, arg1)
end

function sfPacket_writeDouble(packet, arg1)
    ccall((:sfPacket_writeDouble, libcsfml_network), Cvoid, (Ptr{sfPacket}, Cdouble), packet, arg1)
end

function sfPacket_writeString(packet, string)
    ccall((:sfPacket_writeString, libcsfml_network), Cvoid, (Ptr{sfPacket}, Cstring), packet, string)
end

function sfPacket_writeWideString(packet, string)
    ccall((:sfPacket_writeWideString, libcsfml_network), Cvoid, (Ptr{sfPacket}, Ptr{Cwchar_t}), packet, string)
end
# Julia wrapper for header: SocketSelector.h
# Automatically generated using Clang.jl

function sfSocketSelector_create()
    ccall((:sfSocketSelector_create, libcsfml_network), Ptr{sfSocketSelector}, ())
end

function sfSocketSelector_copy(selector)
    ccall((:sfSocketSelector_copy, libcsfml_network), Ptr{sfSocketSelector}, (Ptr{sfSocketSelector},), selector)
end

function sfSocketSelector_destroy(selector)
    ccall((:sfSocketSelector_destroy, libcsfml_network), Cvoid, (Ptr{sfSocketSelector},), selector)
end

function sfSocketSelector_addTcpListener(selector, socket)
    ccall((:sfSocketSelector_addTcpListener, libcsfml_network), Cvoid, (Ptr{sfSocketSelector}, Ptr{sfTcpListener}), selector, socket)
end

function sfSocketSelector_addTcpSocket(selector, socket)
    ccall((:sfSocketSelector_addTcpSocket, libcsfml_network), Cvoid, (Ptr{sfSocketSelector}, Ptr{sfTcpSocket}), selector, socket)
end

function sfSocketSelector_addUdpSocket(selector, socket)
    ccall((:sfSocketSelector_addUdpSocket, libcsfml_network), Cvoid, (Ptr{sfSocketSelector}, Ptr{sfUdpSocket}), selector, socket)
end

function sfSocketSelector_removeTcpListener(selector, socket)
    ccall((:sfSocketSelector_removeTcpListener, libcsfml_network), Cvoid, (Ptr{sfSocketSelector}, Ptr{sfTcpListener}), selector, socket)
end

function sfSocketSelector_removeTcpSocket(selector, socket)
    ccall((:sfSocketSelector_removeTcpSocket, libcsfml_network), Cvoid, (Ptr{sfSocketSelector}, Ptr{sfTcpSocket}), selector, socket)
end

function sfSocketSelector_removeUdpSocket(selector, socket)
    ccall((:sfSocketSelector_removeUdpSocket, libcsfml_network), Cvoid, (Ptr{sfSocketSelector}, Ptr{sfUdpSocket}), selector, socket)
end

function sfSocketSelector_clear(selector)
    ccall((:sfSocketSelector_clear, libcsfml_network), Cvoid, (Ptr{sfSocketSelector},), selector)
end

function sfSocketSelector_wait(selector, timeout)
    ccall((:sfSocketSelector_wait, libcsfml_network), sfBool, (Ptr{sfSocketSelector}, sfTime), selector, timeout)
end

function sfSocketSelector_isTcpListenerReady(selector, socket)
    ccall((:sfSocketSelector_isTcpListenerReady, libcsfml_network), sfBool, (Ptr{sfSocketSelector}, Ptr{sfTcpListener}), selector, socket)
end

function sfSocketSelector_isTcpSocketReady(selector, socket)
    ccall((:sfSocketSelector_isTcpSocketReady, libcsfml_network), sfBool, (Ptr{sfSocketSelector}, Ptr{sfTcpSocket}), selector, socket)
end

function sfSocketSelector_isUdpSocketReady(selector, socket)
    ccall((:sfSocketSelector_isUdpSocketReady, libcsfml_network), sfBool, (Ptr{sfSocketSelector}, Ptr{sfUdpSocket}), selector, socket)
end
# Julia wrapper for header: SocketStatus.h
# Automatically generated using Clang.jl

# Julia wrapper for header: TcpListener.h
# Automatically generated using Clang.jl

function sfTcpListener_create()
    ccall((:sfTcpListener_create, libcsfml_network), Ptr{sfTcpListener}, ())
end

function sfTcpListener_destroy(listener)
    ccall((:sfTcpListener_destroy, libcsfml_network), Cvoid, (Ptr{sfTcpListener},), listener)
end

function sfTcpListener_setBlocking(listener, blocking)
    ccall((:sfTcpListener_setBlocking, libcsfml_network), Cvoid, (Ptr{sfTcpListener}, sfBool), listener, blocking)
end

function sfTcpListener_isBlocking(listener)
    ccall((:sfTcpListener_isBlocking, libcsfml_network), sfBool, (Ptr{sfTcpListener},), listener)
end

function sfTcpListener_getLocalPort(listener)
    ccall((:sfTcpListener_getLocalPort, libcsfml_network), UInt16, (Ptr{sfTcpListener},), listener)
end

function sfTcpListener_listen(listener, port, address)
    ccall((:sfTcpListener_listen, libcsfml_network), sfSocketStatus, (Ptr{sfTcpListener}, UInt16, sfIpAddress), listener, port, address)
end

function sfTcpListener_accept(listener, connected)
    ccall((:sfTcpListener_accept, libcsfml_network), sfSocketStatus, (Ptr{sfTcpListener}, Ptr{Ptr{sfTcpSocket}}), listener, connected)
end
# Julia wrapper for header: TcpSocket.h
# Automatically generated using Clang.jl

function sfTcpSocket_create()
    ccall((:sfTcpSocket_create, libcsfml_network), Ptr{sfTcpSocket}, ())
end

function sfTcpSocket_destroy(socket)
    ccall((:sfTcpSocket_destroy, libcsfml_network), Cvoid, (Ptr{sfTcpSocket},), socket)
end

function sfTcpSocket_setBlocking(socket, blocking)
    ccall((:sfTcpSocket_setBlocking, libcsfml_network), Cvoid, (Ptr{sfTcpSocket}, sfBool), socket, blocking)
end

function sfTcpSocket_isBlocking(socket)
    ccall((:sfTcpSocket_isBlocking, libcsfml_network), sfBool, (Ptr{sfTcpSocket},), socket)
end

function sfTcpSocket_getLocalPort(socket)
    ccall((:sfTcpSocket_getLocalPort, libcsfml_network), UInt16, (Ptr{sfTcpSocket},), socket)
end

function sfTcpSocket_getRemoteAddress(socket)
    ccall((:sfTcpSocket_getRemoteAddress, libcsfml_network), sfIpAddress, (Ptr{sfTcpSocket},), socket)
end

function sfTcpSocket_getRemotePort(socket)
    ccall((:sfTcpSocket_getRemotePort, libcsfml_network), UInt16, (Ptr{sfTcpSocket},), socket)
end

function sfTcpSocket_connect(socket, remoteAddress, remotePort, timeout)
    ccall((:sfTcpSocket_connect, libcsfml_network), sfSocketStatus, (Ptr{sfTcpSocket}, sfIpAddress, UInt16, sfTime), socket, remoteAddress, remotePort, timeout)
end

function sfTcpSocket_disconnect(socket)
    ccall((:sfTcpSocket_disconnect, libcsfml_network), Cvoid, (Ptr{sfTcpSocket},), socket)
end

function sfTcpSocket_send(socket, data, size)
    ccall((:sfTcpSocket_send, libcsfml_network), sfSocketStatus, (Ptr{sfTcpSocket}, Ptr{Cvoid}, Csize_t), socket, data, size)
end

function sfTcpSocket_sendPartial(socket, data, size, sent)
    ccall((:sfTcpSocket_sendPartial, libcsfml_network), sfSocketStatus, (Ptr{sfTcpSocket}, Ptr{Cvoid}, Csize_t, Ptr{Csize_t}), socket, data, size, sent)
end

function sfTcpSocket_receive(socket, data, size, received)
    ccall((:sfTcpSocket_receive, libcsfml_network), sfSocketStatus, (Ptr{sfTcpSocket}, Ptr{Cvoid}, Csize_t, Ptr{Csize_t}), socket, data, size, received)
end

function sfTcpSocket_sendPacket(socket, packet)
    ccall((:sfTcpSocket_sendPacket, libcsfml_network), sfSocketStatus, (Ptr{sfTcpSocket}, Ptr{sfPacket}), socket, packet)
end

function sfTcpSocket_receivePacket(socket, packet)
    ccall((:sfTcpSocket_receivePacket, libcsfml_network), sfSocketStatus, (Ptr{sfTcpSocket}, Ptr{sfPacket}), socket, packet)
end
# Julia wrapper for header: Types.h
# Automatically generated using Clang.jl

# Julia wrapper for header: UdpSocket.h
# Automatically generated using Clang.jl

function sfUdpSocket_create()
    ccall((:sfUdpSocket_create, libcsfml_network), Ptr{sfUdpSocket}, ())
end

function sfUdpSocket_destroy(socket)
    ccall((:sfUdpSocket_destroy, libcsfml_network), Cvoid, (Ptr{sfUdpSocket},), socket)
end

function sfUdpSocket_setBlocking(socket, blocking)
    ccall((:sfUdpSocket_setBlocking, libcsfml_network), Cvoid, (Ptr{sfUdpSocket}, sfBool), socket, blocking)
end

function sfUdpSocket_isBlocking(socket)
    ccall((:sfUdpSocket_isBlocking, libcsfml_network), sfBool, (Ptr{sfUdpSocket},), socket)
end

function sfUdpSocket_getLocalPort(socket)
    ccall((:sfUdpSocket_getLocalPort, libcsfml_network), UInt16, (Ptr{sfUdpSocket},), socket)
end

function sfUdpSocket_bind(socket, port, address)
    ccall((:sfUdpSocket_bind, libcsfml_network), sfSocketStatus, (Ptr{sfUdpSocket}, UInt16, sfIpAddress), socket, port, address)
end

function sfUdpSocket_unbind(socket)
    ccall((:sfUdpSocket_unbind, libcsfml_network), Cvoid, (Ptr{sfUdpSocket},), socket)
end

function sfUdpSocket_send(socket, data, size, remoteAddress, remotePort)
    ccall((:sfUdpSocket_send, libcsfml_network), sfSocketStatus, (Ptr{sfUdpSocket}, Ptr{Cvoid}, Csize_t, sfIpAddress, UInt16), socket, data, size, remoteAddress, remotePort)
end

function sfUdpSocket_receive(socket, data, size, received, remoteAddress, remotePort)
    ccall((:sfUdpSocket_receive, libcsfml_network), sfSocketStatus, (Ptr{sfUdpSocket}, Ptr{Cvoid}, Csize_t, Ptr{Csize_t}, Ptr{sfIpAddress}, Ptr{UInt16}), socket, data, size, received, remoteAddress, remotePort)
end

function sfUdpSocket_sendPacket(socket, packet, remoteAddress, remotePort)
    ccall((:sfUdpSocket_sendPacket, libcsfml_network), sfSocketStatus, (Ptr{sfUdpSocket}, Ptr{sfPacket}, sfIpAddress, UInt16), socket, packet, remoteAddress, remotePort)
end

function sfUdpSocket_receivePacket(socket, packet, remoteAddress, remotePort)
    ccall((:sfUdpSocket_receivePacket, libcsfml_network), sfSocketStatus, (Ptr{sfUdpSocket}, Ptr{sfPacket}, Ptr{sfIpAddress}, Ptr{UInt16}), socket, packet, remoteAddress, remotePort)
end

function sfUdpSocket_maxDatagramSize()
    ccall((:sfUdpSocket_maxDatagramSize, libcsfml_network), UInt32, ())
end


text:
module Camera

using ..CImGui.OpenGLBackend.ModernGL
using PVCAM
export ImagePipeline

struct ImagePipeline
    histogram::Vector{Int32}
    cdf::Vector{Int32}
    out::Array{<:Union{UInt8,UInt16}}
    bitdepth::Integer
    target_bitdepth::Integer
    function ImagePipeline(x::Array{<:Union{UInt8,UInt16}}; bitdepth = 2^12, target_bitdepth = 2^16)
        histogram = zeros(Int32, bitdepth)
        cdf = zeros(Int32, bitdepth)
        out = similar(x)
        new(histogram, cdf, out, bitdepth, target_bitdepth)
    end
end

function gen_textures(num::Integer)
    result = UInt32[0 for i in 1:num]
    glGenTextures(num, result)
    any(i -> i <= 0, result) && error("glGenTextures returned an invalid id. OpenGL context active/current?")
    return result
end

function load_texture(tex_id::UInt32, img::Vector{UInt16}, height::Integer, width::Integer)
    glBindTexture(GL_TEXTURE_2D, tex_id)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED)
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)
    glTexImage2D(GL_TEXTURE_2D, GLint(0), GL_RGB, Cint(width), Cint(height), GLint(0), GL_RED, GL_UNSIGNED_SHORT, img)
end

function reload_texture(tex_id, img::Vector{UInt16}, height, width)
    glBindTexture(GL_TEXTURE_2D, tex_id)
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Cint(width), Cint(height), GL_RED, GL_UNSIGNED_SHORT, img)
end

function make_histogram!(x, hist_out)
    fill!(hist_out, zero(Int32))
    @simd for i in x
        hist_out[i+1] += 1
    end
end

function equalize!(img, out, cdf, histogram, bitdepth)
    pixels = length(img)
    cdf .= round.(Int, cumsum(histogram) ./ pixels .* (bitdepth - 1))
    for i in 1:length(img)
        out[i] = cdf[img[i]+1]
    end
end

function (pipe::ImagePipeline)(img::Array)
    make_histogram!(img, pipe.histogram)
    equalize!(img, pipe.out, pipe.cdf, pipe.histogram, pipe.target_bitdepth)
end

end


text:
using JuMP, EAGO

                     m = Model()

                     EAGO.register_eago_operators!(m)

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

                     @variable(m, -65.76627584345755 <= q <= 59.26265199263469)

                     add_NL_constraint(m, :(softplus(-0.4079491356153899 + -0.18134844314194787*softplus(0.2817697329190594 + 0.989386077401103*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.6068435500303653*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.8530798012021474*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + 0.8376755183348754*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.6594644406874322*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + -0.2976334456396539*softplus(-0.4984715860832294 + -0.6460783499544172*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.0952691245496573*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + -0.5434919689873383*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.2400778955734424*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.904210133814042*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + -0.11940205422195982*softplus(-0.9402956128299329 + 0.19522910845028774*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + -0.5236489579886725*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + -0.09802794343243137*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.5359271533353085*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.5362141752531211*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + -0.6350558501595733*softplus(-0.842982128122256 + 0.6833459994096582*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.15560340828874075*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.5368387122163134*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.6086259049043772*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + -0.5403730914454505*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + 0.4683577877900529*softplus(0.6067063734003204 + 0.8661978259504042*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + -0.06088102390312189*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.9836506901320718*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + 0.7952476421961925*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + -0.6703006410599177*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3])))) + softplus(0.9379679817528435 + -0.4660824895766815*softplus(0.2817697329190594 + 0.989386077401103*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.6068435500303653*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.8530798012021474*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + 0.8376755183348754*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.6594644406874322*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + 0.32761179552569075*softplus(-0.4984715860832294 + -0.6460783499544172*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.0952691245496573*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + -0.5434919689873383*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.2400778955734424*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.904210133814042*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + 0.6880683972685175*softplus(-0.9402956128299329 + 0.19522910845028774*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + -0.5236489579886725*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + -0.09802794343243137*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.5359271533353085*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.5362141752531211*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + 0.5888723964207281*softplus(-0.842982128122256 + 0.6833459994096582*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.15560340828874075*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.5368387122163134*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.6086259049043772*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + -0.5403730914454505*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + -0.05595383404471299*softplus(0.6067063734003204 + 0.8661978259504042*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + -0.06088102390312189*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.9836506901320718*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + 0.7952476421961925*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + -0.6703006410599177*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3])))) + softplus(-0.3048668135843893 + -0.3680078347752045*softplus(0.2817697329190594 + 0.989386077401103*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.6068435500303653*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.8530798012021474*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + 0.8376755183348754*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.6594644406874322*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + -0.09989706667818732*softplus(-0.4984715860832294 + -0.6460783499544172*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.0952691245496573*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + -0.5434919689873383*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.2400778955734424*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.904210133814042*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + -0.6733365176188579*softplus(-0.9402956128299329 + 0.19522910845028774*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + -0.5236489579886725*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + -0.09802794343243137*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.5359271533353085*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.5362141752531211*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + -0.7967060490111804*softplus(-0.842982128122256 + 0.6833459994096582*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.15560340828874075*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.5368387122163134*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.6086259049043772*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + -0.5403730914454505*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + 0.8483184805894783*softplus(0.6067063734003204 + 0.8661978259504042*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + -0.06088102390312189*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.9836506901320718*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + 0.7952476421961925*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + -0.6703006410599177*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3])))) + softplus(-0.8260325513973243 + 0.9282935832138137*softplus(0.2817697329190594 + 0.989386077401103*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.6068435500303653*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.8530798012021474*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + 0.8376755183348754*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.6594644406874322*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + -0.5968467249691596*softplus(-0.4984715860832294 + -0.6460783499544172*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.0952691245496573*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + -0.5434919689873383*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.2400778955734424*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.904210133814042*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + -0.003449906971975558*softplus(-0.9402956128299329 + 0.19522910845028774*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + -0.5236489579886725*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + -0.09802794343243137*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.5359271533353085*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.5362141752531211*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + 0.5427745947324003*softplus(-0.842982128122256 + 0.6833459994096582*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.15560340828874075*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.5368387122163134*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.6086259049043772*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + -0.5403730914454505*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + 0.4794292841893828*softplus(0.6067063734003204 + 0.8661978259504042*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + -0.06088102390312189*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.9836506901320718*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + 0.7952476421961925*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + -0.6703006410599177*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3])))) + softplus(-0.3442450542855955 + 0.3679171232252214*softplus(0.2817697329190594 + 0.989386077401103*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.6068435500303653*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.8530798012021474*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + 0.8376755183348754*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.6594644406874322*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + 0.4969759600474797*softplus(-0.4984715860832294 + -0.6460783499544172*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.0952691245496573*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + -0.5434919689873383*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.2400778955734424*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.904210133814042*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + -0.17345395101703964*softplus(-0.9402956128299329 + 0.19522910845028774*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + -0.5236489579886725*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + -0.09802794343243137*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.5359271533353085*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + 0.5362141752531211*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + -0.24637355767613478*softplus(-0.842982128122256 + 0.6833459994096582*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + 0.15560340828874075*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.5368387122163134*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + -0.6086259049043772*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + -0.5403730914454505*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3]))) + 0.4183638306902213*softplus(0.6067063734003204 + 0.8661978259504042*softplus(-0.7838782818766057 + 0.6083304932652234*$(x[1]) + 0.4982278286707449*$(x[2]) + -0.2123905230276213*$(x[3])) + -0.06088102390312189*softplus(-0.6220948510874038 + -0.22981743777707297*$(x[1]) + 0.33188126395442463*$(x[2]) + -0.8264122617752747*$(x[3])) + 0.9836506901320718*softplus(0.5453301275165048 + -0.2798145416678528*$(x[1]) + -0.9787415760841154*$(x[2]) + 0.5329097417839521*$(x[3])) + 0.7952476421961925*softplus(-0.31934053056836653 + 0.3102265855539219*$(x[1]) + -0.9236015463563882*$(x[2]) + -0.5629164596540628*$(x[3])) + -0.6703006410599177*softplus(0.17795541107351465 + 0.6245951080916892*$(x[1]) + -0.14381738742917527*$(x[2]) + 0.44898943772247746*$(x[3])))) - $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 Plots
using ElectrochemicalKinetics

"""
    plot_models(models::Vector{<:KineticModel}; kwargs...)

Plot predicted rate constants for each model in the provided list.

# Keyword Arguments
* V_min and V_max: bounds of voltage, defaults to +/- 1.0
* plot_title
* kwargs for compute_k function
"""
function plot_models(
    models::Vector{<:KineticModel};
    plot_title = "",
    V_min = -1.0,
    V_max = 1.0,
    kwargs...,
)
    V_range = range(V_min, V_max, length = 200)
    xs = repeat([V_range], length(models))
    ys = map(model -> [compute_k(V, model; kwargs...) for V in V_range], models)
    plot(
        xs,
        ys,
        seriestype = [:line repeat([:line], length(models) - 1)...],
        label = [repr(models[1]) repr.(models[2:end])...],
        xlabel = "V",
        ylabel = "log(k or I)",
        yscale = :log10,
        leg = :bottomright,
        title = plot_title,
    )
end

"""
    plot_exp_and_models(models::Vector{<:KineticModel}; kwargs...)

Plot predicted rate constants for each model in the provided list.

# Keyword Arguments
* V_min and V_max: bounds of voltage, defaults to +/- 1.0
* plot_title
* kwargs for compute_k function
"""
function plot_exp_and_models(
    exp_data::Matrix,
    models::Vector{<:KineticModel};
    plot_title = "",
    kwargs...,
)
    V = exp_data[:, 1]
    V_mag = 1.1 * maximum(abs.(V))
    V_range = range(-V_mag, V_mag, length = 200)
    xs = Vector[V, repeat([V_range], length(models))...]
    ys = Vector[
        exp_data[:, 2],
        map(model -> compute_k(V_range, model; kwargs...), models)...,
    ]

    # scatter plot of experimental data, lines for fits
    plot(
        xs,
        ys,
        seriestype = [:scatter repeat([:line], length(models))...],
        label = ["experiment" repr.(models)...],
        xlabel = "V",
        ylabel = "log(k or I)",
        yscale = :log10,
        leg = :bottomright,
        title = plot_title,
    )
end

# if you want to visualize each term in MHC+DOS integrand separately
function plot_integrand_components(
    dos_file,
    E_min,
    E_max;
    eη = 0,
    kT = 0.026,
    λ = 0.26,
    length = 500,
    plot_title = "",
)
    E_range = range(E_min + 1e-9, E_max - 1e-9, length = length)
    dos = DOSData(dos_file)
    p1 = plot(
        E_range,
        dos.(E_range),
        color = :black,
        ylabel = "electrode states",
        label = "electrons/holes",
        title = plot_title,
    )

    fd_vals_e = fermi_dirac.(E_range; kT = kT)
    fd_vals_h = 1 .- fd_vals_e
    p2 = plot(
        E_range,
        hcat(fd_vals_e, fd_vals_h),
        label = ["electrons" "holes"],
        ylabel = "occupation",
        legend = :right,
    )

    marcus_model = Marcus(λ)
    ox_dos_vals = integrand(marcus_model, eη, true; kT = kT).(E_range)
    red_dos_vals = integrand(marcus_model, eη, false; kT = kT).(E_range)
    p3 = plot(
        E_range,
        hcat(red_dos_vals, ox_dos_vals),
        label = ["reduction" "oxidation"],
        ylabel = "electrolyte states",
    )

    plot(p1, p2, p3, layout = (3, 1))
end


text:
include("runtests_mcp.jl")
include("runtests_mpec.jl")


text:
# test_multinomial.jl -- Part of 'MultinomialSeries',
# a package for The Julia Programming Language
# Copyright (C) 2020-2021 Markus J. Weber
# License: See accompanying file 'LICENSE.md'

#=----    Reference Sinusoid Solver Tests    ----=#

@testset "Standard MultinomialSeries" begin

    @test collect(eachmultinomial(1,0)) == [(0,)]
    @test collect(eachmultinomial(2,2)) == [(2,0), (1,1), (0,2)]
    @test collect(eachmultinomial(2,3)) == [(3,0), (2,1), (1,2), (0,3)]
    @test collect(eachmultinomial(3,3)) == [
                (3, 0, 0), (2, 1, 0), (2, 0, 1), (1, 2, 0), (1, 1, 1),
                (1, 0, 2), (0, 3, 0), (0, 2, 1), (0, 1, 2), (0, 0, 3) ]

end

@testset "Automated consistency checks" begin

    for (m,n) in [ (1,0), (1,1), (1,2),
                   (2,2), (2,3), (2,4), (2,4),
                   (3,0), (3,1), (3,2), (3,3), (3,4), (3,5),
                   (4,0), (4,1), (4,2), (4,3), (4,4), (4,5),
                   (8,0), (8,1), (8,2), (8,3), (8,4), (8,5),
                   (8,6), (8,7), (8,8), (8,9), (8,10), (8,12)
                ]

        it = eachmultinomial(m,n)
        xs = collect(it)
        @test   length(first(xs)) == m          # tuple length correct
        @test   length(xs) == length(it)        # theoretical number reached
        @test   all( sum(x) == n for x in xs )  # all add up to n
        @test   all( all(x .>= 0) for x in xs )  # all non-negative
        @test   unique(xs) == xs                # no duplicates in list

    end

end # testset

@testset "Result types" begin

    for t in (UInt8, Int8, UInt16, Int16, UInt32, Int32, UInt64, Int64, UInt128, Int128)

        @test collect(eachmultinomial(t, 1, 1))[1] isa Tuple{t}
        @test collect(eachmultinomial(t, 2, 2))[2] isa Tuple{t,t}
        @test collect(eachmultinomial(t, 3, 3))[3] isa Tuple{t,t,t}

        @test eltype(collect(eachmultinomial(t, 1, 1))) == Tuple{t}
        @test eltype(eachmultinomial(t, 1, 1)) == Tuple{t}
    end

end

@testset "Wrong function arguments" begin

    @test_skip #=DomainError=# collect(eachmultinomial( 0, 0))
    @test_skip #=DomainError=# collect(eachmultinomial(-1, 0))
    @test_skip #=DomainError=# collect(eachmultinomial( 1,-1))

    @test_skip #=TypeError=# collect(eachmultinomial(String, 1, 1))  # Only integer types
    @test_skip #=TypeError=# collect(eachmultinomial(BigInt, 1, 1))  # Only bits types, sorry.

end

# end of file


text:
# using XFields
# using Test
using LinearAlgebra

#%%
#%% =========================================

Σₒ, Γₒ, Cₒ, rFT, rFTplan, gr, fk_sim = let

    # 1-d vector of length N
    N = 12

    # set up the FFT matrices
    rFT = rFFT(nᵢ=(N,),pᵢ=(1.0,))
    gr  = Grid(rFT)
    𝒲 = [exp(-im * 2π * (k-1)*(n-1) / N) for k=1:N, n=1:N]
    ℱ = (gr.Ωx / sqrt(2π)) .* 𝒲

    #
    M = fill(0.0,N) |> x-> (x[4:end-1].= 1; x) |> Diagonal

    # cov pixel model before masking
    Σpre   = Symmetric([exp(-abs(i-j)) for i=1:N, j=1:N])
    # Σpre  = [exp(-abs(i-j)) for i=1:d, j=1:d]
    # for i = 2:size(Σpre,2)
    # 	Σpre[:,i] .= circshift(Σpre[:,i-1], 1)
    # end
    # Σ = Symmetric((Σpre .+ Σpre') ./ 2) # --> zero C on unique frequencies
    Lpre = cholesky(Σpre).L

    # cov model in pixel space
    Σ = M*Σpre*M

    #
    fx_sim = M * Lpre * randn(N)
    fk_sim = ℱ * fx_sim |> x -> x[1:N÷2+1] # only the complex unique coeffs

    ##
    Γ = ℱ * Σ * adjoint(ℱ)   |> x -> x[1:N÷2+1,1:N÷2+1]
    C = ℱ * Σ * transpose(ℱ) |> x -> x[1:N÷2+1,1:N÷2+1]
    #=
    Izu = 2:N÷2
    Γk[Izu, Izu] .|> abs |> matshow; colorbar()
    Ck[Izu, Izu] .|> abs |> matshow; colorbar()
    =#

    Σ, Γ, C, rFT, plan(rFT), gr, fk_sim

end

#%%
#%% =========================================

rΓ, rC, ΣXX, ΣYY, ΣYX, ΣXY = let

    rFFTimpulses, CI, LI, get_dual_ci = get_rFFTimpulses(rFT)
    EZXᵀ = fill(0.0im, length(fk_sim), length(fk_sim))
    EZYᵀ = fill(0.0im, length(fk_sim), length(fk_sim))
    rFTplanᴴ = adjoint(rFTplan)
    for (li,ci) ∈ zip(LI, CI)
        φ, iφ = rFFTimpulses(ci)
        EZXᵀ[:,li] = rFTplan * (Σₒ * (rFTplanᴴ * φ))
        EZYᵀ[:,li] = rFTplan * (Σₒ * (rFTplanᴴ * iφ))
    end

    ΣXX = real.(EZXᵀ)
    ΣYY = imag.(EZYᵀ)
    ΣYX = imag.(EZXᵀ)
    ΣXY = real.(EZYᵀ)

    rΓ = complex.(ΣXX .+ ΣYY, ΣYX .- ΣXY)
    rC = complex.(ΣXX .- ΣYY, ΣYX .+ ΣXY)

    rΓ, rC, ΣXX, ΣYY, ΣYX, ΣXY

end

#%%
#%% =========================================
let
	function logPk1(z; Σxx,Σxy,Σyx,Σyy)
	    # Σ    = [
	    #     Σxx  Σxy
	    #     Σyx  Σyy
	    # ] |> Symmetric
	    Σ    = hvcat((2,2), Σxx, Σxy, Σyx, Σyy) |> Symmetric
	    xy   = vcat(real.(z), imag.(z))
	    rtn  = - dot(xy, Σ \ xy) / 2
	    rtn -= logabsdet(Σ)[1] / 2
	    rtn -= length(z)*log(2)
	    return rtn
	end

	function logPk2(z; Γ, C)
	    # ΓC = [
	    #     Γ         C
	    #     conj.(C)  conj.(Γ)
	    # ] |> Hermitian
	    ΓC   = hvcat((2,2), Γ, C, conj.(C), conj.(Γ)) |> Hermitian
	    zcz = vcat(z, conj.(z))
	    rtn  = real.(- dot(zcz, ΓC \ zcz) / 2)
	    rtn -= logabsdet(ΓC)[1] / 2
	    return rtn
	end

	subInd = 2:5

	val1 = logPk1(fk_sim[subInd]; Σxx = ΣXX[subInd,subInd],
	                    Σxy = ΣXY[subInd,subInd],
	                    Σyx = ΣYX[subInd,subInd],
	                    Σyy = ΣYY[subInd,subInd]
	)
	val2 = logPk2(fk_sim[subInd];
	    Γ=rΓ[subInd,subInd],
	    C=rC[subInd,subInd]
	)

	@test val1 ≈ val2 atol=1e-10

end

# ## check this has the correct std

# function sim1()
# 	dmlw = ℳ * L * randn(N)
# 	dk   = 𝒲 * dmlw
# 	return logPk1(dk[ksub]; Γ=Γksub, C=Cksub)
# end

# function sim2()
# 	dmlw = ℳ * L * randn(N)
# 	dk   = 𝒲 * dmlw
# 	return logPk2(dk[ksub]; Γ=Γksub, C=Cksub)
# end

# logPk1s = [sim1() for i=1:5000]
# logPk2s = [sim2() for i=1:5000]
# std(logPk1s) # should be about sqrt(2*length(ksub)) / sqrt(2)
# std(logPk2s) # should be about sqrt(2*length(ksub)) / sqrt(2)


text:
using Libui
@static if VERSION >= v"0.7-"
  using Test
else
  using Base.Test
end

@testset "Init and Uninit" begin
  o = Libui.uiInitOptions(0)
  err = uiInit(Ref(o))
  @test err == C_NULL

  uiUninit()
end

@testset "Control Gallery" begin
  include("controlgallery.jl")
end


text:
########################################################################################
# Read size info
########################################################################################
using CpelNano

dataDir = "/Users/jordiabante/Desktop/"
fastq = "$(dataDir)/ex.fastq"
CpelNano. fastq_len_store(fastq,dataDir)
CpelNano. fastq_len_dist(fastq,dataDir)

########################################################################################
# Read size testing
########################################################################################
using Plots
using CpelNano
using Distributions

# Histogram
u = CpelNano.gen_read_len(50000);
plot(u/1000,seriestype=:histogram,bins=100,xlim=(0,205),
    xticks=[18.4,38.9,59.4,79.9,100,121,141,162,182,203],
    xlabel="Read length l (kbp)",ylabel="Counts",label="")
savefig("/Users/jordiabante/Desktop/Read-Size-Histo.png")

# Total Basecalled Bases
reso = 5000
u = Int.(round.(10000.0*rand(Gamma(2,0.5),50000)))
uniq_sizes = unique(sort(u))
weights = map(y->length(findall(x->x==y,u)),uniq_sizes)
delims = collect(1:reso:130000)
bin_id = map(u->findfirst(x->u-x<reso,delims),uniq_sizes)
uniq_bin_id = unique(bin_id)
total_basecalled = map(i->sum(uniq_sizes[bin_id.==i].*weights[bin_id.==i]),uniq_bin_id)
delims_mid = 0.5*(delims[2:end]+delims[1:(end-1)])
plot(delims/1000,total_basecalled,seriestype=:bar,xlim=(0,205),
    xticks=[18.4,38.9,59.4,79.9,100,121,141,162,182,203],
    xlabel="Read length l (kbp)",ylabel="Total Basecalled Bases",label="")

########################################################################################
# MCMC sampling (we tried to see if it's feasible to generate entire chromosome)
########################################################################################
using Plots
using CpelNano

reps = 10
ns = [5,10,25,50,100,500,1000,2500]
total_time = zeros(length(ns))
for i=1:length(ns)
    CpelNano.print_log("n=$(ns[i])")
    for j=1:reps
        total_time[i] += @elapsed CpelNano.metro_hast_inst(ns[i],10000,zeros(ns[i]),zeros(ns[i]-1))
    end
    total_time[i] /= reps
end

plot(ns,total_time,xlabel="N",ylabel="Time (s)",label="")
plot!(ns,ns/250,xlabel="N",ylabel="Time (s)",label="")

########################################################################################
# Augmenting model file
########################################################################################
using CpelNano

## Regular mode
pkg_dir = dirname(dirname(pathof(CpelNano)))

# IO
dataDir = "$(pkg_dir)/examples/full_example/"
nano = "$(dataDir)/nanopolish/full_example_noise2.0_methylation_calls.sorted.tsv"
fasta = "$(dataDir)/reference/hg38_chr17_43023997_43145780.fa"
outdir = "/Users/jordiabante/Desktop/"

# IO
config = CpelNano.CpelNanoConfig();
config.out_prefix = "full_example";
config.out_dir = outdir;
config.verbose = false; # true;

# Analyze nano
CpelNano.analyze_nano(nano,fasta,config)

# Augment file
chr = "hg38_dna"
mod_file = "$(outdir)/$(config.out_prefix)_theta.txt"
CpelNano.aug_mod_file(mod_file,chr,fasta)

########################################################################################
# Sandeep testing
########################################################################################
using CpelNano
using FASTX
using DelimitedFiles

# IO
dataDir = "/Users/sandeepk/Downloads/"
fasta = "$(dataDir)/chr22.fa"
chr22record = CpelNano.get_chr_fa_rec("chr22",fasta)
genome = convert(String,FASTX.FASTA.sequence(chr22record,35723841:35723842));
genome = convert(String,FASTA.sequence(chr22record,40688790:40688791));
model_regs = aug_mod_file("/Users/sandeepk/Downloads/GM12878_CpelNano_Theta.txt", "chr22", fasta, chr22record);

config = CpelNano.CpelNanoConfig();
chr_part = CpelNano.get_chr_part("chr22", config, fasta);
model_regs = read_reg_chr("/Users/sandeepk/Downloads/GM12878_CpelNano_Theta_run4.txt", "chr22", fasta, chr22record);
# Test constructing a methyl vector

# Double check if length of test_methylvec matches number of cpg sites in read
fa_record = chr22record
chrstart = fa_record.sequence[1]
chrend = fa_record.sequence[length(fa_record.sequence)];
read_len = 100000
genom_pos, newRead = gen_read("chr22", fasta, read_len);
startidx = linearsearch_readstart(genom_pos, chr_part);
endidx = linearsearch_readend(genom_pos+read_len-1, startidx, chr_part);
meth_lattice, out_cpg_pos = get_methyl_vector(genom_pos, genom_pos+read_len-1, startidx, endidx, model_regs);
#meth_lattice, out_cpg_pos = CpelNano.get_methyl_vector(40576278, 41576277, 13526, 13859, model_regs);
cpg_pos = map(x->getfield(x,:offset),eachmatch(r"CG",newRead));
length(meth_lattice)
length(cpg_pos)
for i in 1:length(cpg_pos)
    cpg_pos[i] = cpg_pos[i] + genom_pos - 1
end

for i in 1:length(cpg_pos)
    if cpg_pos[i] != out_cpg_pos[i]
        print(i)
        break
    end
end

dataDir = "/Users/sandeepk/Downloads/"
fasta = "$(dataDir)/chr22.fa"
config = CpelNano.CpelNanoConfig();
chr_part = CpelNano.get_chr_part("chr22", config, fasta);
chr_part[13563]
chr22record = CpelNano.get_chr_fa_rec("chr22",fasta)
genome = convert(String,FASTA.sequence(chr22record,40685791:40688791))

##### Create full GM12878 Chr22 parameter file with alpha, beta
dataDir = "/Users/sandeepk/Downloads/"
fasta = "$(dataDir)/chr22.fa"
fa_record = CpelNano.get_chr_fa_rec("chr22",fasta)
config = CpelNano.CpelNanoConfig();
chr_part = CpelNano.get_chr_part("chr22", config, fasta);

model_regs = CpelNano.aug_mod_file("/Users/sandeepk/Downloads/GM12878_CpelNano_Theta.txt", "chr22", fasta, fa_record);

output = Vector{String}()

for i in 1:length(chr_part)
    reg = model_regs[i]
    #if reg.L > 0
        ϕhat_str = string(reg.ϕhat[1], ",", reg.ϕhat[2], ",", reg.ϕhat[3])
        α,β = CpelNano.get_αβ_from_ϕ(reg.ϕhat, reg)
        α_str = join(α, ",")
        β_str = join(β, ",")
        push!(output, string(reg.chr, '\t', reg.chrst, '\t', reg.chrend, '\t', ϕhat_str, '\t', α_str, " ", β_str, "\n"))
    #end
end
output_str = join(output);

open("/Users/sandeepk/Downloads/GM12878_CpelNano_Theta_run4.txt", "w") do io
    write(io, output_str)
end;


text:
"""
    Scores = AbstractArray{Float64, 2}

A type alias for score matrices.
"""
const Scores = AbstractArray{Float64, 2}

"""
    EdgeEvidence(src, dst, evidence)

An edge from src to dst with evidence that it exists.
"""
struct EdgeEvidence
    src::Int
    dst::Int
    evidence::Float64
    EdgeEvidence(src, dst, evidence) = if isnan(evidence)
        throw(DomainError(evidence, "cannot be NaN"))
    else
        new(src, dst, evidence)
    end
end

"""
    Scorer

A supertype for all network inference types.
"""
abstract type Scorer end

function score(scorer::M, series::AbstractArray{Int,4}, args...; self=false, kwargs...) where {M <: Scorer}
    N = size(series, 4)
    scores = Array{Float64}(undef, N, N)
    @views for i in 1:N, j in 1:N
        scores[i,j] = scorer(series[:,:,:,i], series[:,:,:,j], args...; kwargs...)
    end
    !self && foreach(i -> scores[i,i] = zero(scores[i,i]), 1:N)
    scores
end

function score(scorer::M, series::AbstractArray{Int,3}, args...; kwargs...) where {M <: Scorer}
    score(scorer, reshape(series, 1, size(series)...), args...; kwargs...)
end

function score(scorer::M, series::AbstractArray{Int,2}, args...; self=false, kwargs...) where {M <: Scorer}
    N = size(series, 2)
    scores = Array{Float64}(undef, N, N)
    @views for i in 1:N, j in 1:N
        scores[i,j] = scorer(series[:,i], series[:,j], args...; kwargs...)
    end
    !self && foreach(i -> scores[i,i] = zero(scores[i,i]), 1:N)
    scores
end

"""
    SymmetricScorer
"""
abstract type SymmetricScorer <: Scorer end

function score(scorer::M, series::AbstractArray{Int,4}, args...; self=false, kwargs...) where {M <: SymmetricScorer}
    N = size(series, 4)
    scores = Array{Float64}(undef, N, N)
    @views for i in 1:N, j in i+1:N
        scores[i,j] = scores[j,i] = scorer(series[:,:,:,i], series[:,:,:,j], args...; kwargs...)
    end
    !self && foreach(i -> scores[i,i] = zero(scores[i,i]), 1:N)
    scores
end

function score(scorer::M, series::AbstractArray{Int,3}, args...; kwargs...) where {M <: SymmetricScorer}
    score(scorer, reshape(series, 1, size(series)...), args...; kwargs...)
end

function score(scorer::M, series::AbstractMatrix{Int}, args...; self=false, kwargs...) where {M <: SymmetricScorer}
    N = size(series, 2)
    scores = Array{Float64}(undef, N, N)
    @views for i in 1:N, j in i+1:N
        scores[i,j] = scores[j,i] = scorer(series[:,i], series[:,j], args...; kwargs...)
    end
    !self && foreach(i -> scores[i,i] = zero(scores[i,i]), 1:N)
    scores
end

"""
    ChisqScorer

Score based on the χ²-test statistic
"""
struct ChisqScorer <: SymmetricScorer end

function (::ChisqScorer)(xs::AbstractArray{Int}, ys::AbstractArray{Int}, args...; kwargs...)
    @views ChisqTest(xs[:], ys[:], (minimum(xs):maximum(xs), minimum(ys):maximum(ys))).stat
end

"""
    LaggedChisqScorer
"""
struct LaggedChisqScorer <: Scorer
    lag::Int
end
LaggedChisqScorer() = LaggedChisqScorer(1)

function (m::LaggedChisqScorer)(xs::AbstractArray{Int,1}, ys::AbstractArray{Int,1}, args...; kwargs...)
    scorer = ChisqScorer()
    if m.lag < 0
        @views scorer(xs[m.lag+1:end], ys[1:end-m.lag])
    else
        @views scorer(xs[1:end-m.lag], ys[m.lag+1:end])
    end
end

function (m::LaggedChisqScorer)(xs::AbstractArray{Int,2}, ys::AbstractArray{Int,2}, args...; kwargs...)
    scorer = ChisqScorer()
    if m.lag < 0
        @views scorer(xs[:,m.lag+1:end], ys[:,1:end-m.lag])
    else
        @views scorer(xs[:,1:end-m.lag], ys[:,m.lag+1:end])
    end
end

function (m::LaggedChisqScorer)(xs::AbstractArray{Int,3}, ys::AbstractArray{Int,3}, args...; kwargs...)
    scorer = ChisqScorer()
    if m.lag < 0
        @views scorer(xs[:,m.lag+1:end,:], ys[:,1:end-m.lag,:])
    else
        @views scorer(xs[:,1:end-m.lag,:], ys[:,m.lag+1:end,:])
    end
end

"""
    LaggedChisqScorer
"""
struct SymLaggedChisqScorer <: Scorer
    lag::Int
end
SymLaggedChisqScorer() = SymLaggedChisqScorer(1)

function (m::SymLaggedChisqScorer)(xs::AbstractArray{Int}, ys::AbstractArray{Int}, args...; kwargs...)
    scorer = LaggedChisqScorer(m.lag)
    0.5 * (scorer(xs, ys) + scorer(ys, xs))
end

"""
    MIScorer

Infer based on the mutual information between pairs of nodes.
"""
struct MIScorer <: SymmetricScorer end

function (::MIScorer)(xs::AbstractArray{Int}, ys::AbstractArray{Int}, args...; kwargs...)
    mutualinfo(xs, ys, args...; kwargs...)
end

"""
    LaggedMIScorer

Infer based on the lagged mutual information between pairs of nodes.
"""
struct LaggedMIScorer <: Scorer
    lag::Int
end
LaggedMIScorer() = LaggedMIScorer(1)

function (m::LaggedMIScorer)(xs::AbstractArray{Int}, ys::AbstractArray{Int}, args...; kwargs...)
    mutualinfo(xs, ys, args...; lag=m.lag, kwargs...)
end

"""
    SymLaggedMIScorer

Infer based on the mean, lagged mutual information between pairs of nodes.
"""
struct SymLaggedMIScorer <: SymmetricScorer
    lag::Int
end
SymLaggedMIScorer() = SymLaggedMIScorer(1)

function (m::SymLaggedMIScorer)(xs::AbstractArray{Int}, ys::AbstractArray{Int}, args...; kwargs...)
    xy = mutualinfo(xs, ys, args...; lag=m.lag, kwargs...)
    yx = mutualinfo(ys, xs, args...; lag=m.lag, kwargs...)
    0.5 * (xy + yx)
end

"""
    TEScorer

Infer based on the transfer entropy between pairs of nodes.
"""
struct TEScorer <: Scorer
    k::Int
end
TEScorer() = TEScorer(1)

function (m::TEScorer)(xs::AbstractArray{Int}, ys::AbstractArray{Int}, args...; kwargs...)
    transferentropy(xs, ys, args...; k=m.k, kwargs...)
end

"""
    SymTEScorer

Infer based on the mean, transfer entropy between pairs of nodes.
"""
struct SymTEScorer <: SymmetricScorer
    k::Int
end
SymTEScorer() = SymTEScorer(1)

function (m::SymTEScorer)(xs::AbstractArray{Int}, ys::AbstractArray{Int}, args...; kwargs...)
    xy = transferentropy(xs, ys, args...; k=m.k, kwargs...)
    yx = transferentropy(ys, xs, args...; k=m.k, kwargs...)
    0.5 * (xy + yx)
end

struct SignificanceScorer{S<:Significance, T<:Scorer} <: Scorer
    scorer::T
    nperms::Int
    α::Float64
    function SignificanceScorer(::Type{S}, scorer::T, nperms=1000, α=0.05) where {S<:Significance, T<:Scorer}
        if !(zero(α) ≤ α ≤ one(α))
            throw(DomainError(α, "p-value must be in [0.0, 1.0]"))
        end
        new{S,T}(scorer, nperms, α)
    end
end
SignificanceScorer(scorer::Scorer, args...) = SignificanceScorer(AnalyticSig, scorer, args...)

scorer(m::SignificanceScorer) = (args...; kwargs...) -> m.scorer(args...; kwargs...)

function (m::SignificanceScorer{S})(args...; kwargs...) where S
    try
        dist = @sig S scorer(m)(args...; kwargs...) nperm=m.nperms
        dist.p < m.α ? dist.gt : zero(dist.gt)
    catch
        zero(Float64)
    end
end

"""
    Rescorer

A supertype for all rescoring methods.
"""
abstract type Rescorer end

"""
    CLRRescorer

A rescorer based on the mean and variance of all edges into and out of a pair of nodes.
"""
struct CLRRescorer <: Rescorer end

function rescore(::CLRRescorer, scores::Scores)
    N = size(scores, 1)
    rescore = zeros(Float64, N, N)
    for i in 1:N
        for j in i+1:N
            score = scores[i, j]
            iscores = vcat((@view scores[1:i-1, i]), (@view scores[i+1:end, i]))
            jscores = vcat((@view scores[1:j-1, j]), (@view scores[j+1:end, j]))

            ibar = score - mean(iscores)
            jbar = score - mean(jscores)
            iσ2 = var(iscores)
            jσ2 = var(jscores)

            irescored = (iσ2 == zero(iσ2) || ibar < zero(ibar)) ? zero(score) : ibar^2 / iσ2
            jrescored = (jσ2 == zero(jσ2) || jbar < zero(jbar)) ? zero(score) : jbar^2 / jσ2

            rescore[i, j] = rescore[j, i] = sqrt(irescored + jrescored)
        end
    end
    rescore
end

abstract type Aggregator end

struct Sum <: Aggregator end

(::Sum)(args::Number...) = sum(args)

struct HarmonicMean <: Aggregator end

(::HarmonicMean)(args::Number...) = 1.0 / mean(1.0 ./ args)

"""
    GammaRescorer(ϵ=eps(Float64), aggregator=(p,q) -> p + q)

Rescore edges by fitting a Gamma distribution to the incoming and outgoing scores and aggregating
the probability of the score given those distributions.

The scores provided to the Gamma distribution cannot be 0, so all 0-scores are set to ϵ.
"""
struct GammaRescorer{A<:Aggregator} <: Rescorer
    aggregator::A
    ϵ::Float64
    GammaRescorer(aggregator::T; ϵ::Float64=eps(Float64)) where T = new{T}(aggregator, ϵ)
end
GammaRescorer() = GammaRescorer(Sum())

function rescore(gr::GammaRescorer, scores::Scores)
    try
        N = size(scores, 1)
        rescore = zeros(Float64, N, N)
        for i in 1:N
            for j in i+1:N
                score = scores[i, j]
                iscores = vcat((@view scores[1:i-1, i]), (@view scores[i+1:end, i]))
                jscores = vcat((@view scores[1:j-1, j]), (@view scores[j+1:end, j]))

                iscores[iscores .== zero(Float64)] .= gr.ϵ
                jscores[jscores .== zero(Float64)] .= gr.ϵ

                p = cdf(fit(Gamma, iscores), score)
                q = cdf(fit(Gamma, jscores), score)

                rescore[i, j] = rescore[j, i] = gr.aggregator(p, q)
            end
        end
        rescore
    catch
        rescore(CLRRescorer(), scores)
    end
end

"""
    edgelist(scores[; symmetric=false, self=false])

Construct a weighted edge list from a scores matrix.
"""
function evidence(scores::Scores; symmetric=false, self=false)
    N = size(scores, 1)

    evidence = if symmetric
        [EdgeEvidence(i, j, scores[i, j]) for i in 1:N for j in i+1:N]
    else
        [EdgeEvidence(i, j, scores[i, j]) for i in 1:N for j in 1:N]
    end

    !self && filter(e -> e.src != e.dst, evidence)

    evidence
end

function infer(scorer::Scorer, series; kwargs...)
    evidence(score(scorer, series); kwargs...)
end

function infer(scorer::SymmetricScorer, series; kwargs...)
    evidence(score(scorer, series); symmetric=true, kwargs...)
end

function infer(scorer::SignificanceScorer{AnalyticSig,<:SymmetricScorer}, series; kwargs...)
    evidence(score(scorer, series); symmetric=true, kwargs...)
end

function infer(scorer::Scorer, rescorer::Rescorer, series; kwargs...)
    evidence(rescore(rescorer, score(scorer, series)); kwargs...)
end

function infer(scorer::SymmetricScorer, rescorer::Rescorer, series; kwargs...)
    evidence(rescore(rescorer, score(scorer, series)); symmetric=true, kwargs...)
end

function infer(scorer::SignificanceScorer{AnalyticSig,<:SymmetricScorer}, rescorer::Rescorer, series; kwargs...)
    evidence(rescore(rescorer, score(scorer, series)); symmetric=true, kwargs...)
end


text:
# Only need to define heuristic stuff
function focal_state_heuristic_grid2d(env::Grid2DEnvironment, solution::Vector{PlanResult{Grid2DState,Grid2DAction,Int64}},
                                      s::Grid2DState)

    num_conflicts = 0

    for (i, agent_soln) in enumerate(solution)
        if i != env.agent_idx && ~(isempty(agent_soln))
            state2 = get_state(i, solution, s.time)
            if equal_except_time(s, state2)
                num_conflicts += 1
            end
        end
    end

    return num_conflicts
end

function focal_transition_heuristic_grid2d(env::Grid2DEnvironment,  solution::Vector{PlanResult{Grid2DState,Grid2DAction,Int64}},
                                           s1a::Grid2DState, s1b::Grid2DState)

    num_conflicts = 0

    for (i, agent_soln) in enumerate(solution)
        if i != env.agent_idx && ~(isempty(agent_soln))

            s2a = get_state(i, solution, s1a.time)
            s2b = get_state(i, solution, s1b.time)

            if equal_except_time(s1a, s2b) && equal_except_time(s1b, s2a)
                num_conflicts += 1
            end
        end
    end

    return num_conflicts
end

function focal_heuristic(env::Grid2DEnvironment, solution::Vector{PlanResult{Grid2DState,Grid2DAction,Int64}})

    num_conflicts = 0
    max_rel_time = 0

    for sol in solution
        max_rel_time = max(max_rel_time, length(sol.states) - 1)
    end

    for rel_time = 0:max_rel_time-1
        # Drive-drive vertex collisions
        for i = 1:length(solution)-1
            state1 = get_state(i, solution, rel_time)
            for j = i+1:length(solution)
                state2 = get_state(j, solution, rel_time)

                if equal_except_time(state1, state2)
                    num_conflicts += 1
                end
            end
        end

        # Drive-drive edge
        for i = 1:length(solution)-1
            state1a = get_state(i, solution, rel_time)
            state1b = get_state(i, solution, rel_time + 1)

            for j = i+1:length(solution)
                state2a = get_state(j, solution, rel_time)
                state2b = get_state(j, solution, rel_time + 1)

                if equal_except_time(state1a, state2b) &&
                    equal_except_time(state1b, state2a)

                    num_conflicts += 1
                end
            end
        end
    end

    return num_conflicts
end

function low_level_search!(solver::ECBSSolver, agent_idx::Int64, s::Grid2DState,
                           constraints::Grid2DConstraints, solution::Vector{PlanResult{Grid2DState,Grid2DAction,Int64}})

    env = solver.env

    env.curr_goal_idx = 0

    idx = get_env_state_idx!(env, s)

    edge_wt_fn(u, v) = 1

    # Set the heuristics
    admissible_heuristic(s) = admissible_heuristic_grid2d(solver.env, s)
    focal_state_heuristic(s) = focal_state_heuristic_grid2d(solver.env, solution, s)
    focal_transition_heuristic(s1a, s1b) = focal_transition_heuristic_grid2d(solver.env, solution, s1a, s1b)

    # Run the search
    vis = CBSGoalVisitorImplicit(env, constraints)
    a_star_eps_states = a_star_implicit_epsilon_path!(env.state_graph,
                                                          edge_wt_fn, idx,
                                                          vis,
                                                          solver.weight,
                                                          admissible_heuristic,
                                                          focal_state_heuristic,
                                                          focal_transition_heuristic,
                                                          Int64)

    plan_result = get_plan_result_from_astar(env, a_star_eps_states.a_star_states.dists,
                                            a_star_eps_states.a_star_states.parent_indices, idx,
                                            env.curr_goal_idx, a_star_eps_states.best_fvalue)

    if plan_result == nothing
        return PlanResult{Grid2DState,Grid2DAction,Int64}()
    end

    return plan_result
end


text:
__precompile__()

"""
Module to read the binary data files created by the OpenEphys GUI

Provides array interfaces to file contents, without loading the entire file into memory
"""
module OpenEphysLoader
# Module to interact with Open Ephys files
using LightXML, Dates
using Base: @propagate_inbounds

import Base: show,
    showerror,
    size,
    getindex,
    setindex!,
    length
import LightXML: parse_file

export
    # Package wide
    ## Exceptions
    CorruptedException,

    # Original binary format
    ## Types
    OriginalHeader,

    # Continuous data file
    ## Types
    ContinuousFile,
    OEArray,
    OEContArray,
    SampleArray,
    TimeArray,
    RecNoArray,
    JointArray,

    # Metadata for continuous files
    ## Types
    OEExperMeta,
    OESettings,
    OEInfo,
    OERecordingMeta,
    OEProcessor,
    OERhythmProcessor,
    OEChannel,
    XmlNode,

    ## Functions
    metadata

## source files
include("metadata.jl")
include("original.jl")
include("continuous.jl")

end # module OpenEphys


text:
using ConcurrentCollectionsBenchmarks
SUITE = ConcurrentCollectionsBenchmarks.setup()


text:
## ------------------------------------------------------------------
function _macro_call_regex(name::String)
    str = string("(?>",
        "\\@", name, "(?>", "\\([^\\(]*\\)", ")?",
    ")")
    return Regex(str)
end

## ------------------------------------------------------------------
function _replace_line(callinfo::LineNumberNode, old, new)
    file, line = srcfile(callinfo), srcline(callinfo)
    !isfile(file) && return
    lines = readlines(file)
    linestr = lines[line]
    nocalls = count(old, linestr)
    nocalls > 1 && error("More than one match for `$(old)` at the same line $(line): '$(linestr)'.")
    nocalls == 0 && return
    lines[line] = replace(linestr, old => new)
    open(file, "w") do io
        for line in lines
            println(io, line)
        end
    end
    touch(file)
    return nothing
end

# ------------------------------------------
function _make_report(f::Function, file, srcli)

    lines = readlines(file)
    line = lines[srcli]

    # check line
    !contains(line, _macro_call_regex("report")) && error("macro call missing at ", line)

    # capture
    output = _capture_output(f)

    # write
    # TODO: handle or detect multiline expressions
    open(file, "w") do io
        # original
        for (li, line) in enumerate(lines)
            println(io, line)
            (li == srcli) && break
        end

        # output
        for line in split(output, "\n")
            println(io, "# ", line)
        end
    end

end

# ------------------------------------------
macro report(ex)
    file, line = srcfile(__source__), srcline(__source__)
    quote
        _make_report($(file), $(line)) do
            $(esc(ex))
        end
    end
end