text:
############################################################
## joSAdistribute/gather - overloaded Base functions

# eltype(jo)
eltype(A::joAbstractSAparallelToggleOperator{DDT,RDT}) where {DDT,RDT} = promote_type(DDT,RDT)

# deltype(jo)
deltype(A::joAbstractSAparallelToggleOperator{DDT,RDT}) where {DDT,RDT} = DDT

# reltype(jo)
reltype(A::joAbstractSAparallelToggleOperator{DDT,RDT}) where {DDT,RDT} = RDT

# show(jo)
function show(A::joAbstractSAparallelToggleOperator)
    println("Type: $(typeof(A).name)")
    println("Name: $(A.name)")
    println("Size: $(size(A))")
    println(" NVC: $(A.nvc)")
    println(" DDT: $(deltype(A))")
    println(" RDT: $(reltype(A))")
    return nothing
end

# display(jo)
display(A::joAbstractSAparallelToggleOperator) = println((typeof(A),((A.m,A.n),A.nvc),A.name))

# size(jo)
size(A::joAbstractSAparallelToggleOperator) = A.m,A.n

# size(jo,1/2)
function size(A::joAbstractSAparallelToggleOperator,ind::Integer)
    if ind==1
		return A.m
	elseif ind==2
		return A.n
	else
		throw(joAbstractSAparallelToggleOperatorException("invalid index"))
	end
end

# length(jo)
length(A::joAbstractSAparallelToggleOperator) = A.m*A.n

# jo_full(jo)

# norm(jo)

# real(jo)

# imag(jo)

# conj(jo)
conj(A::joAbstractSAparallelToggleOperator) = A

# transpose(jo)
transpose(A::joSAdistribute{DDT,RDT,N}) where {DDT,RDT,N} =
    joSAgather{RDT,DDT,N}("regather($(A.name))",A.n,A.m,A.nvc,
        A.fop_T, A.fop, A.fop_C, A.fop_A,
        A.iop_T, A.iop, A.iop_C, A.iop_A,
        A.PAs_out, A.gclean)
transpose(A::joSAgather{DDT,RDT,N}) where {DDT,RDT,N} =
    joSAdistribute{RDT,DDT,N}("redistribute($(A.name))",A.n,A.m,A.nvc,
        A.fop_T, A.fop, A.fop_C, A.fop_A,
        A.iop_T, A.iop, A.iop_C, A.iop_A,
        A.PAs_in, A.gclean)

# adjoint(jo)
adjoint(A::joAbstractSAparallelToggleOperator) = transpose(A)

# isreal(jo)

# issymmetric(jo)

# ishermitian(jo)

# getindex(jo,...)

############################################################
## overloaded Base *(...jo...)

# *(jo,jo)

# *(jo,mvec)
function *(A::joSAdistribute{ADDT,ARDT,2},mv::LocalMatrix{mvDT}) where {ADDT,ARDT,mvDT<:Number}
    A.n == size(mv,1) || throw(joAbstractSAparallelToggleOperatorException("joSAdistributeMV: shape mismatch A$(size(A))*v$(size(mv))"))
    A.PAs_out.dims==size(mv) || throw(joAbstractSAparallelToggleOperatorException("joSAdistributeMV: shape mismatch dst$(A.PAs_out.dims)*v$(size(mv))"))
    jo_check_type_match(ADDT,mvDT,join(["DDT for *(jo,mvec):",A.name,typeof(A),mvDT]," / "))
    MV = A.fop(mv)
    jo_check_type_match(ARDT,eltype(MV),join(["RDT from *(jo,mvec):",A.name,typeof(A),eltype(MV)]," / "))
    return MV
end
function *(A::joSAgather{ADDT,ARDT,2},mv::SharedArray{mvDT,2}) where {ADDT,ARDT,mvDT<:Number}
    A.n == size(mv,1) || throw(joAbstractSAparallelToggleOperatorException("joSAgatherMV: shape mismatch A$(size(A))*v$(size(mv))"))
    A.PAs_in.dims==size(mv) || throw(joAbstractSAparallelToggleOperatorException("joSAgatherMV: shape mismatch dst$(A.PAs_in.dims)*v$(size(mv))"))
    jo_check_type_match(ADDT,mvDT,join(["DDT for *(jo,mvec):",A.name,typeof(A),mvDT]," / "))
    isequiv(A.PAs_in,mv) || throw(joAbstractSAparallelToggleOperatorException("*($(A.name),mv::Darray): input distributor mismatch"))
    MV = A.fop(mv)
    jo_check_type_match(ARDT,eltype(MV),join(["RDT from *(jo,mvec):",A.name,typeof(A),eltype(MV)]," / "))
    return MV
end
# in joAbstractSAparallelLinearOperator/base_functions.jl
#function *(A::joSAdistribute{CDT,ARDT,2},B::joAbstractLinearOperator{BDDT,CDT}) where {ARDT,BDDT,CDT}
#function *(A::joAbstractLinearOperator{CDT,ARDT},B::joSAgather{BDDT,CDT,2}) where {ARDT,BDDT,CDT}

# *(mvec,jo)

# *(jo,vec)
function *(A::joSAdistribute{ADDT,ARDT,1},v::LocalVector{vDT}) where {ADDT,ARDT,vDT<:Number}
    A.n == size(v,1) || throw(joAbstractSAparallelToggleOperatorException("joSAdistributeV: shape mismatch A$(size(A))*v$(size(v))"))
    A.PAs_out.dims==size(v) || throw(joAbstractSAparallelToggleOperatorException("joSAdistributeV: shape mismatch dst$(A.PAs_out.dims)*v$(size(v))"))
    jo_check_type_match(ADDT,vDT,join(["DDT for *(jo,vec):",A.name,typeof(A),vDT]," / "))
    V=A.fop(v)
    jo_check_type_match(ARDT,eltype(V),join(["RDT from *(jo,vec):",A.name,typeof(A),eltype(V)]," / "))
    return V
end
function *(A::joSAgather{ADDT,ARDT,1},v::SharedArray{vDT,1}) where {ADDT,ARDT,vDT<:Number}
    A.n == size(v,1) || throw(joAbstractSAparallelToggleOperatorException("joSAgatherV: shape mismatch A$(size(A))*v$(size(v))"))
    A.PAs_in.dims==size(v) || throw(joAbstractSAparallelToggleOperatorException("joSAgatherV: shape mismatch dst$(A.PAs_in.dims)*v$(size(v))"))
    jo_check_type_match(ADDT,vDT,join(["DDT for *(jo,vec):",A.name,typeof(A),vDT]," / "))
    V=A.fop(v)
    jo_check_type_match(ARDT,eltype(V),join(["RDT from *(jo,vec):",A.name,typeof(A),eltype(V)]," / "))
    return V
end

# *(vec,jo)

# *(num,jo)

# *(jo,num)


text:
@testset "HSA Status Error" begin
    errorcode = AMDGPU.HSAError(HSA.STATUS_SUCCESS)
    @test AMDGPU.description(errorcode) == "HSA_STATUS_SUCCESS: The function has been executed successfully."
end

ext: jl


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

using Test
using Mortar2D: calculate_segments

# calculate segmentation
elements = Dict(
    1 => [1, 2],
    2 => [3, 4])
element_types = Dict(
    1 => :Seg2,
    2 => :Seg2)
coords = Dict(
    1 => [1.0, 2.0],
    2 => [3.0, 2.0],
    3 => [0.0, 2.0],
    4 => [2.0, 2.0])
normals = Dict(
    1 => [0.0, -1.0],
    2 => [0.0, -1.0])
slave_ids = [1]
master_ids = [2]
segments = calculate_segments(
    slave_ids,
    master_ids,
    elements,
    element_types,
    coords,
    normals)
@test length(segments) == 1
@test length(segments[1]) == 1
elid, xi = first(segments[1])
@test elid == 2
@test isapprox(xi, [-1.0, 0.0])


text:
### A Pluto.jl notebook ###
# v0.14.3

using Markdown
using InteractiveUtils

# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
    quote
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing
        el
    end
end

# ╔═╡ 55593255-a4ca-49df-9f6e-12411e9fe9d2
using PlutoUI

# ╔═╡ f46bcfa1-445d-4928-abd0-a551cef1e36f
using Plots

# ╔═╡ 361b5f40-6c24-46b2-a389-f819e3481f71
md"# Interactivity:

Try changing `x` to a different number."

# ╔═╡ dd18192a-a85c-11eb-202d-914944b9ef89
x = 4

# ╔═╡ d88098cf-aa9a-424b-8682-77aad6901795
y = 2

# ╔═╡ 71eac437-61c2-42b4-86a1-4a8b73b67f85
x + y

# ╔═╡ 798d0410-8615-4164-935b-1419e1ee61b9
md"# Rendering as HTML"

# ╔═╡ c77a4e1e-a8be-41c8-aaff-9b066184c24c
md"""
### This is an h3 tag written via Markdown

- I'm a bullet
- Me too!
  - I'm a nested bullet

| I'm  | a  | table |
|------|----|-------|
| this | is | neat  |
"""

# ╔═╡ 13b03cc2-f2cf-40d6-8b08-bedc7a0acc95
md"# Using `@bind`"

# ╔═╡ e762440f-bfc4-411e-a63b-d61fc9ffc4ae
@bind my_input html"<input></input>"

# ╔═╡ 94e52639-6072-4649-a7b9-33efa2791918
my_input

# ╔═╡ ccac4170-071a-4dd8-b87c-c2cb23f61819
md"# Using PlutoUI"

# ╔═╡ 55518562-76b8-4969-bc03-efe3bd138e68
@bind thing Slider(1:10)

# ╔═╡ 6d676090-70e7-4ef8-b888-ea0b7a3c0491
thing

# ╔═╡ b7aa9aa5-49d6-4baa-962b-f65dc748b9f2
md"# Custom Display Methods"

# ╔═╡ 39af1a40-21e9-4e02-8193-b33ffd77ec98
begin
	struct Thing end

	function Base.show(io::IO, ::MIME"text/html", o::Thing)
		print(io, "
")
		print(io, "
")
	end
end

# ╔═╡ 353b54bf-2cd7-4ece-840c-01d9b121dbbd
Thing()

# ╔═╡ f268819d-e75b-4818-8779-b719625b5b4c
md"# Putting this all Together"

# ╔═╡ 5b5e3de9-8413-4ab9-854d-69832e677c1d
begin
	data = randn(100)
	nobs_ui = @bind nobs Slider(10:10:100)
	series_ui = @bind series Select(["scatter", "line", "bar"])

	md"""
	This is a small UI for editing the elements of a plot.

	- It's neat!

	$nobs_ui  $series_ui
	"""
end

# ╔═╡ 784f192c-0830-44fa-bf09-bcc0752961c0
plot(data[1:nobs], seriestype=Symbol(series), title="Nobs: $nobs")

# ╔═╡ Cell order:
# ╟─361b5f40-6c24-46b2-a389-f819e3481f71
# ╠═dd18192a-a85c-11eb-202d-914944b9ef89
# ╠═d88098cf-aa9a-424b-8682-77aad6901795
# ╠═71eac437-61c2-42b4-86a1-4a8b73b67f85
# ╟─798d0410-8615-4164-935b-1419e1ee61b9
# ╟─c77a4e1e-a8be-41c8-aaff-9b066184c24c
# ╟─13b03cc2-f2cf-40d6-8b08-bedc7a0acc95
# ╠═e762440f-bfc4-411e-a63b-d61fc9ffc4ae
# ╠═94e52639-6072-4649-a7b9-33efa2791918
# ╟─ccac4170-071a-4dd8-b87c-c2cb23f61819
# ╠═55593255-a4ca-49df-9f6e-12411e9fe9d2
# ╠═55518562-76b8-4969-bc03-efe3bd138e68
# ╠═6d676090-70e7-4ef8-b888-ea0b7a3c0491
# ╟─b7aa9aa5-49d6-4baa-962b-f65dc748b9f2
# ╠═39af1a40-21e9-4e02-8193-b33ffd77ec98
# ╠═353b54bf-2cd7-4ece-840c-01d9b121dbbd
# ╟─f268819d-e75b-4818-8779-b719625b5b4c
# ╠═f46bcfa1-445d-4928-abd0-a551cef1e36f
# ╠═5b5e3de9-8413-4ab9-854d-69832e677c1d
# ╠═784f192c-0830-44fa-bf09-bcc0752961c0


text:
# Implementation note
# There are two important design features of GroupedDataFrame
# 1. idx, starts, ends and keymap are by default left uninitialized;
#    they get populated only on demand; this means that every GroupedDataFrame
#    has lazy_lock field which is used to make sure that two threads concurrently
#    do not try to create them. The lock should be used in every function that
#    does a direct access to these fields via getfield.
# 2. Except for point 1 above currently fields of GroupedDataFrame are never
#    mutated after it is created. This means that internally when copying
#    a GroupedDataFrame they are not copied for efficiency. If in the future
#    operations that mutate GroupedDataFrame are introduced all non-copying
#    passing of the internal fields to a new GroupedDataFrame should be
#    updated. Currently this applies to `getindex` and `combine_helper` functions

"""
    GroupedDataFrame

The result of a [`groupby`](@ref) operation on an `AbstractDataFrame`; a
view into the `AbstractDataFrame` grouped by rows.

Not meant to be constructed directly, see `groupby`.
"""
mutable struct GroupedDataFrame{T<:AbstractDataFrame}
    parent::T
    cols::Vector{Symbol}                 # column names used for grouping
    groups::Vector{Int}                  # group indices for each row in 0:ngroups, 0 skipped
    idx::Union{Vector{Int},Nothing}      # indexing vector sorting rows into groups
    starts::Union{Vector{Int},Nothing}   # starts of groups after permutation by idx
    ends::Union{Vector{Int},Nothing}     # ends of groups after permutation by idx
    ngroups::Int                         # number of groups
    keymap::Union{Dict{Any,Int},Nothing} # mapping of key tuples to group indices
    lazy_lock::Threads.ReentrantLock     # lock is needed to make lazy operations
                                         # thread safe
end

function genkeymap(gd, cols)
    # currently we use Dict{Any,Int} because then field :keymap in GroupedDataFrame
    # has a concrete type which makes the access to it faster as we do not have a dynamic
    # dispatch when indexing into it. In the future an optimization of this approach
    # can be investigated (also taking compilation time into account).
    d = Dict{Any,Int}()
    gdidx = gd.idx
    sizehint!(d, length(gd.starts))
    for (i, s) in enumerate(gd.starts)
        d[getindex.(cols, gdidx[s])] = i
    end
    d
end

function Base.getproperty(gd::GroupedDataFrame, f::Symbol)
    if f in (:idx, :starts, :ends)
        # Group indices are computed lazily the first time they are accessed
        # Do not lock when field is already initialized
        if getfield(gd, f) === nothing
            Threads.lock(gd.lazy_lock) do
                if getfield(gd, f) === nothing # Do not lock when field is already initialized
                    gd.idx, gd.starts, gd.ends = compute_indices(gd.groups, gd.ngroups)
                end
            end
        end
        return getfield(gd, f)::Vector{Int}
    elseif f === :keymap
        # Keymap is computed lazily the first time it is accessed
        if getfield(gd, f) === nothing # Do not lock when field is already initialized
            Threads.lock(gd.lazy_lock) do
                if getfield(gd, f) === nothing
                    gd.keymap = genkeymap(gd, ntuple(i -> parent(gd)[!, gd.cols[i]], length(gd.cols)))
                end
            end
        end
        return getfield(gd, f)::Dict{Any,Int}
    else
        return getfield(gd, f)
    end
end

Base.broadcastable(::GroupedDataFrame) =
    throw(ArgumentError("broadcasting over `GroupedDataFrame`s is reserved"))

"""
    parent(gd::GroupedDataFrame)

Return the parent data frame of `gd`.
"""
Base.parent(gd::GroupedDataFrame) = getfield(gd, :parent)

function Base.:(==)(gd1::GroupedDataFrame, gd2::GroupedDataFrame)
    gd1.cols == gd2.cols &&
        length(gd1) == length(gd2) &&
        all(x -> ==(x...), zip(gd1, gd2))
end

function Base.isequal(gd1::GroupedDataFrame, gd2::GroupedDataFrame)
    isequal(gd1.cols, gd2.cols) &&
        isequal(length(gd1), length(gd2)) &&
        all(x -> isequal(x...), zip(gd1, gd2))
end

Base.names(gd::GroupedDataFrame) = names(gd.parent)
Base.names(gd::GroupedDataFrame, cols) = names(gd.parent, cols)
_names(gd::GroupedDataFrame) = _names(gd.parent)

function DataFrame(gd::GroupedDataFrame; copycols::Bool=true, keepkeys::Bool=true)
    if !copycols
        throw(ArgumentError("It is not possible to construct a `DataFrame`" *
                            "from GroupedDataFrame with `copycols=false`"))
    end
    length(gd) == 0 && return similar(parent(gd), 0)
    gdidx = gd.idx
    idx = similar(gdidx)
    doff = 1
    for (s,e) in zip(gd.starts, gd.ends)
        n = e - s + 1
        copyto!(idx, doff, gdidx, s, n)
        doff += n
    end
    resize!(idx, doff - 1)
    if keepkeys
        return parent(gd)[idx, :]
    else
        return parent(gd)[idx, Not(gd.cols)]
    end
end

#
# Accessing group indices, columns, and values
#

"""
    groupindices(gd::GroupedDataFrame)

Return a vector of group indices for each row of `parent(gd)`.

Rows appearing in group `gd[i]` are attributed index `i`. Rows not present in
any group are attributed `missing` (this can happen if `skipmissing=true` was
passed when creating `gd`, or if `gd` is a subset from
a larger [`GroupedDataFrame`](@ref)).
"""
groupindices(gd::GroupedDataFrame) = replace(gd.groups, 0=>missing)

"""
    groupcols(gd::GroupedDataFrame)

Return a vector of `Symbol` column names in `parent(gd)` used for grouping.
"""
function groupcols(gd::GroupedDataFrame)
    issubset(gd.cols, _names(parent(gd))) ||
        throw(ErrorException("grouping column names not found in data frame column names"))
    return copy(gd.cols)
end

"""
    valuecols(gd::GroupedDataFrame)

Return a vector of `Symbol` column names in `parent(gd)` not used for grouping.
"""
function valuecols(gd::GroupedDataFrame)
    issubset(gd.cols, _names(parent(gd))) || throw(ErrorException("grouping column " *
        "names not found in data frame column names"))
    return setdiff(_names(gd), gd.cols)
end

# Get grouping variable index by its name
function _groupvar_idx(gd::GroupedDataFrame, name::Symbol, strict::Bool)
    i = findfirst(==(name), gd.cols)
    i === nothing && strict && throw(ArgumentError("$name is not a grouping column"))
    return i
end

# Get values of grouping columns for single group
_groupvalues(gd::GroupedDataFrame, i::Integer) =
    gd.parent[gd.idx[gd.starts[i]], gd.cols]

# Get values of single grouping column for single group
_groupvalues(gd::GroupedDataFrame, i::Integer, col::Integer) =
    gd.parent[gd.idx[gd.starts[i]], gd.cols[col]]
_groupvalues(gd::GroupedDataFrame, i::Integer, col::Symbol) =
    _groupvalues(gd, i, _groupvar_idx(gd, col, true))

#
# Vector interface and integer indexing
#

Base.length(gd::GroupedDataFrame) = gd.ngroups

function Base.iterate(gd::GroupedDataFrame, i=1)
    if i > length(gd)
        nothing
    else
        (view(gd.parent, gd.idx[gd.starts[i]:gd.ends[i]], :), i+1)
    end
end

Compat.lastindex(gd::GroupedDataFrame) = gd.ngroups
Base.first(gd::GroupedDataFrame) = gd[1]
Base.last(gd::GroupedDataFrame) = gd[end]

# These have to be defined for some to_indices() logic to work, as long
# as GroupedDataFrame is not <: AbstractArray
Base.IndexStyle(::Type{<:GroupedDataFrame}) = IndexLinear()
Base.IndexStyle(::GroupedDataFrame) = IndexLinear()
Base.keys(::IndexLinear, gd::GroupedDataFrame) = Base.OneTo(length(gd))

# Single integer indexing
Base.getindex(gd::GroupedDataFrame, idx::Integer) =
    view(gd.parent, gd.idx[gd.starts[idx]:gd.ends[idx]], :)

# Index with array of integers OR bools
function Base.getindex(gd::GroupedDataFrame, idxs::AbstractVector{<:Integer})
    new_starts = gd.starts[idxs]
    new_ends = gd.ends[idxs]
    if !allunique(new_starts)
        throw(ArgumentError("duplicates in idxs argument are not allowed"))
    end
    new_groups = zeros(Int, length(gd.groups))
    idx = gd.idx
    for i in eachindex(new_starts)
        @inbounds for j in new_starts[i]:new_ends[i]
            new_groups[idx[j]] = i
        end
    end
    GroupedDataFrame(gd.parent, copy(gd.cols), new_groups, gd.idx,
                     new_starts, new_ends, length(new_starts), nothing,
                     Threads.ReentrantLock())
end

# Index with colon (creates copy)
Base.getindex(gd::GroupedDataFrame, idxs::Colon) =
    Threads.lock(gd.lazy_lock) do
        return GroupedDataFrame(gd.parent, copy(gd.cols), gd.groups, getfield(gd, :idx),
                                getfield(gd, :starts), getfield(gd, :ends), gd.ngroups,
                                getfield(gd, :keymap), Threads.ReentrantLock())
    end

#
# GroupKey and GroupKeys
#

"""
    GroupKey{T<:GroupedDataFrame}

Key for one of the groups of a [`GroupedDataFrame`](@ref). Contains the values
of the corresponding grouping columns and behaves similarly to a `NamedTuple`,
but using it to index its `GroupedDataFrame` is more efficient than using the
equivalent `Tuple` and `NamedTuple`, and much more efficient than using
the equivalent `AbstractDict`.

Instances of this type are returned by `keys(::GroupedDataFrame)` and are not
meant to be constructed directly.

Indexing fields of `GroupKey` is allowed using an integer, a `Symbol`, or a string.
It is also possible to access the data in a `GroupKey` using the `getproperty`
function. A `GroupKey` can be converted to a `Tuple`, `NamedTuple`, a `Vector`, or
a `Dict`. When converted to a `Dict`, the keys of the `Dict` are `Symbol`s.

See [`keys(::GroupedDataFrame)`](@ref) for more information.
"""
struct GroupKey{T<:GroupedDataFrame}
    parent::T
    idx::Int
end

function Base.show(io::IO, k::GroupKey)
    print(io, "GroupKey: ")
    show(io, NamedTuple(k))
end

Base.parent(key::GroupKey) = getfield(key, :parent)
Base.length(key::GroupKey) = length(parent(key).cols)
Base.names(key::GroupKey) = string.(parent(key).cols)
# Private fields are never exposed since they can conflict with column names
Base.propertynames(key::GroupKey, private::Bool=false) = copy(parent(key).cols)
Base.keys(key::GroupKey) = propertynames(key)
Base.haskey(key::GroupKey, idx::Symbol) = idx in parent(key).cols
Base.haskey(key::GroupKey, idx::AbstractString) = haskey(key, Symbol(idx))
Base.haskey(key::GroupKey, idx::Union{Signed,Unsigned}) = 1 <= idx <= length(key)
Base.values(key::GroupKey) = Tuple(_groupvalues(parent(key), getfield(key, :idx)))
Base.IteratorEltype(::Type{<:GroupKey}) = Base.EltypeUnknown()
Base.iterate(key::GroupKey, i::Integer=1) =
    i <= length(key) ? (key[i], i + 1) : nothing
Base.getindex(key::GroupKey, i::Integer) =
    _groupvalues(parent(key), getfield(key, :idx), i)

function Base.getindex(key::GroupKey, n::Symbol)
    try
        return _groupvalues(parent(key), getfield(key, :idx), n)
    catch e
        throw(KeyError(n))
    end
end

Base.getindex(key::GroupKey, n::AbstractString) = key[Symbol(n)]

function Base.getproperty(key::GroupKey, p::Symbol)
    try
        return key[p]
    catch e
        throw(ArgumentError("$(typeof(key)) has no property $p"))
    end
end

Base.getproperty(key::GroupKey, p::AbstractString) = getproperty(key, Symbol(p))

function Base.NamedTuple(key::GroupKey)
    N = NamedTuple{Tuple(parent(key).cols)}
    N(_groupvalues(parent(key), getfield(key, :idx)))
end

"""
    copy(key::GroupKey)

Construct a `NamedTuple` with the same contents as the [`GroupKey`](@ref).
"""
Base.copy(key::GroupKey) = NamedTuple(key)

Base.convert(::Type{NamedTuple}, key::GroupKey) = NamedTuple(key)
Base.convert(::Type{Tuple}, key::GroupKey) = Tuple(key)

Base.convert(::Type{Vector}, key::GroupKey) = [v for v in key]
Base.convert(::Type{Vector{T}}, key::GroupKey) where T = T[v for v in key]
Base.Vector(key::GroupKey) = convert(Vector, key)
Base.Vector{T}(key::GroupKey) where T = convert(Vector{T}, key)

Base.convert(::Type{Array}, key::GroupKey) = Vector(key)
Base.convert(::Type{Array{T}}, key::GroupKey) where {T} = Vector{T}(key)
Base.Array(key::GroupKey) = Vector(key)
Base.Array{T}(key::GroupKey) where {T} = Vector{T}(key)

Base.Dict(key::GroupKey) = Dict(pairs(key)...)

Base.broadcastable(::GroupKey) =
    throw(ArgumentError("broadcasting over `GroupKey`s is reserved"))

"""
    GroupKeys{T<:GroupedDataFrame} <: AbstractVector{GroupKey{T}}

A vector containing all [`GroupKey`](@ref) objects for a given
[`GroupedDataFrame`](@ref).

See [`keys(::GroupedDataFrame)`](@ref) for more information.
"""
struct GroupKeys{T<:GroupedDataFrame} <: AbstractVector{GroupKey{T}}
    parent::T
end

Base.parent(gk::GroupKeys) = gk.parent

Base.size(gk::GroupKeys) = (length(parent(gk)),)
Base.IndexStyle(::Type{<:GroupKeys}) = IndexLinear()
@Base.propagate_inbounds function Base.getindex(gk::GroupKeys, i::Integer)
    @boundscheck checkbounds(gk, i)
    return GroupKey(parent(gk), i)
end

#
# Non-standard indexing
#

# Non-standard indexing relies on converting to integer indices first
# The full version (to_indices) is required rather than to_index even though
# GroupedDataFrame behaves as a 1D array due to the behavior of Colon and Not.
# Note that this behavior would be the default if it was <:AbstractArray
function Base.getindex(gd::GroupedDataFrame, idx...)
    length(idx) == 1 || throw(ArgumentError("GroupedDataFrame requires a single index"))
    return getindex(gd, Base.to_indices(gd, idx)...)
end

# The allowed key types for dictionary-like indexing
const GroupKeyTypes = Union{GroupKey, Tuple, NamedTuple, AbstractDict{Symbol}, AbstractDict{<:AbstractString}}
# All allowed scalar index types
const GroupIndexTypes = Union{Integer, GroupKeyTypes}

# Find integer index for dictionary keys
function Base.to_index(gd::GroupedDataFrame, key::GroupKey)
    gd === parent(key) && return getfield(key, :idx)
    throw(ErrorException("Cannot use a GroupKey to index a GroupedDataFrame " *
                         "other than the one it was derived from."))
end

Base.to_index(gd::GroupedDataFrame, key::Tuple) = gd.keymap[key]

function Base.to_index(gd::GroupedDataFrame, key::NamedTuple{N}) where {N}
    if length(key) != length(gd.cols) || any(n != c for (n, c) in zip(N, gd.cols))
        throw(KeyError(key))
    end
    return Base.to_index(gd, Tuple(key))
end

function _dict_to_tuple(key::AbstractDict{<:AbstractString}, gd::GroupedDataFrame)
    if length(key) != length(gd.cols)
        throw(KeyError(key))
    end

    return ntuple(i -> key[String(gd.cols[i])], length(gd.cols))
end

function _dict_to_tuple(key::AbstractDict{Symbol}, gd::GroupedDataFrame)
    if length(key) != length(gd.cols)
        throw(KeyError(key))
    end

    return ntuple(i -> key[gd.cols[i]], length(gd.cols))
end

Base.to_index(gd::GroupedDataFrame, key::Union{AbstractDict{Symbol},AbstractDict{<:AbstractString}}) =
    Base.to_index(gd, _dict_to_tuple(key, gd))

# Array of (possibly non-standard) indices
function Base.to_index(gd::GroupedDataFrame, idxs::AbstractVector{T}) where {T}
    # A concrete eltype which is <: GroupKeyTypes, don't need to check
    if isconcretetype(T) && T <: GroupKeyTypes
        return [Base.to_index(gd, i) for i in idxs]
    end

    # Edge case - array is empty
    isempty(idxs) && return Int[]

    # Infer eltype based on type of first index, expect rest to match
    idx1 = idxs[1]
    E1 = typeof(idx1)

    E = if E1 <: Integer && E1 !== Bool
        Integer
    elseif E1 <: GroupKey
        GroupKey
    elseif E1 <: Tuple
        Tuple
    elseif E1 <: NamedTuple
        NamedTuple
    elseif E1 <: AbstractDict{Symbol}
        AbstractDict{Symbol}
    elseif E1 <: AbstractDict{<:AbstractString}
        AbstractDict{<:AbstractString}
    else
        throw(ArgumentError("Invalid index: $idx1 of type $E1"))
    end

    # Convert each index to integer format
    ints = Vector{Int}(undef, length(idxs))
    for (i, idx) in enumerate(idxs)
        if !(idx isa GroupIndexTypes) || idx isa Bool
            throw(ArgumentError("Invalid index: $idx of type $(typeof(idx))"))
        end
        idx isa E || throw(ArgumentError("Mixed index types in array not allowed"))
        ints[i] = Base.to_index(gd, idx)
    end

    return ints
end

#
# Indexing with Not/InvertedIndex
#

# InvertedIndex wrapping any other valid index type
# to_indices() is needed here rather than to_index() in order to override the
# to_indices(::Any, ::Tuple{Not}) methods defined in InvertedIndices.jl
function Base.to_indices(gd::GroupedDataFrame, (idx,)::Tuple{<:Not})
    (skip_idx,) = Base.to_indices(gd, (idx.skip,))
    idxs = Base.OneTo(length(gd))[Not(skip_idx)]
    return (idxs,)
end

# InvertedIndex wrapping a boolean array
# The definition above works but we need to define specialized methods to avoid
# ambiguity in dispatch
function Base.to_indices(gd::GroupedDataFrame,
                         (idx,)::Tuple{Not{<:Union{BitArray{1}, Vector{Bool}}}})
    (findall(!, idx.skip),)
end
function Base.to_indices(gd::GroupedDataFrame,
                         (idx,)::Tuple{Not{<:AbstractVector{Bool}}})
    (findall(!, idx.skip),)
end

#
# Dictionary interface
#

"""
    keys(gd::GroupedDataFrame)

Get the set of keys for each group of the `GroupedDataFrame` `gd` as a
[`GroupKeys`](@ref) object. Each key is a [`GroupKey`](@ref), which behaves like
a `NamedTuple` holding the values of the grouping columns for a given group.
Unlike the equivalent `Tuple`, `NamedTuple`, and `AbstractDict`, these keys can be used to index
into `gd` efficiently. The ordering of the keys is identical to the ordering of
the groups of `gd` under iteration and integer indexing.

# Examples

```jldoctest groupkeys
julia> df = DataFrame(a = repeat([:foo, :bar, :baz], outer=[4]),
                      b = repeat([2, 1], outer=[6]),
                      c = 1:12);

julia> gd = groupby(df, [:a, :b])
GroupedDataFrame with 6 groups based on keys: a, b
First Group (2 rows): a = :foo, b = 2
│ Row │ a      │ b     │ c     │
│     │ Symbol │ Int64 │ Int64 │
├─────┼────────┼───────┼───────┤
│ 1   │ foo    │ 2     │ 1     │
│ 2   │ foo    │ 2     │ 7     │
⋮
Last Group (2 rows): a = :baz, b = 1
│ Row │ a      │ b     │ c     │
│     │ Symbol │ Int64 │ Int64 │
├─────┼────────┼───────┼───────┤
│ 1   │ baz    │ 1     │ 6     │
│ 2   │ baz    │ 1     │ 12    │

julia> keys(gd)
6-element DataFrames.GroupKeys{GroupedDataFrame{DataFrame}}:
 GroupKey: (a = :foo, b = 2)
 GroupKey: (a = :bar, b = 1)
 GroupKey: (a = :baz, b = 2)
 GroupKey: (a = :foo, b = 1)
 GroupKey: (a = :bar, b = 2)
 GroupKey: (a = :baz, b = 1)
```

`GroupKey` objects behave similarly to `NamedTuple`s:

```jldoctest groupkeys
julia> k = keys(gd)[1]
GroupKey: (a = :foo, b = 2)

julia> keys(k)
(:a, :b)

julia> values(k)  # Same as Tuple(k)
(:foo, 2)

julia> NamedTuple(k)
(a = :foo, b = 2)

julia> k.a
:foo

julia> k[:a]
:foo

julia> k[1]
:foo
```

Keys can be used as indices to retrieve the corresponding group from their
`GroupedDataFrame`:

```jldoctest groupkeys
julia> gd[k]
2×3 SubDataFrame
│ Row │ a      │ b     │ c     │
│     │ Symbol │ Int64 │ Int64 │
├─────┼────────┼───────┼───────┤
│ 1   │ foo    │ 2     │ 1     │
│ 2   │ foo    │ 2     │ 7     │

julia> gd[keys(gd)[1]] == gd[1]
true
```
"""
Base.keys(gd::GroupedDataFrame) = GroupKeys(gd)

Base.in(key::Union{GroupKeyTypes, Signed, Unsigned}, gk::GroupKeys) =
    haskey(parent(gk), key)

function Base.haskey(gd::GroupedDataFrame, key::GroupKey)
    if gd === parent(key)
        if 1 <= getfield(key, :idx) <= length(gd)
            return true
        else
            throw(BoundsError(gd, getfield(key, :idx)))
        end
    else
        msg = "The parent of key does not match the passed GroupedDataFrame"
        throw(ArgumentError(msg))
    end
end

function Base.haskey(gd::GroupedDataFrame, key::Tuple)
    if length(key) != length(gd.cols)
        return throw(ArgumentError("The length of key does not match the " *
                                   "number of grouping columns"))
    end
    return haskey(gd.keymap, key)
end

function Base.haskey(gd::GroupedDataFrame, key::NamedTuple{N}) where {N}
    if length(key) != length(gd.cols) || any(((n, c),) -> n != c, zip(N, gd.cols))
        return throw(ArgumentError("The column names of key do not match " *
                                   "the names of grouping columns"))
    end
    return haskey(gd, Tuple(key))
end

Base.haskey(gd::GroupedDataFrame, key::AbstractDict{<:Union{Symbol, <:AbstractString}}) =
    haskey(gd, _dict_to_tuple(key, gd))

Base.haskey(gd::GroupedDataFrame, key::Union{Signed,Unsigned}) =
    1 <= key <= length(gd)

"""
    get(gd::GroupedDataFrame, key, default)

Get a group based on the values of the grouping columns.

`key` may be a `GroupKey`, `NamedTuple` or `Tuple` of grouping column values (in the same
order as the `cols` argument to `groupby`). It may also be an `AbstractDict`, in which case the
order of the arguments does not matter.

# Examples

```jldoctest
julia> df = DataFrame(a = repeat([:foo, :bar, :baz], outer=[2]),
                      b = repeat([2, 1], outer=[3]),
                      c = 1:6);

julia> gd = groupby(df, :a)
GroupedDataFrame with 3 groups based on key: a
First Group (2 rows): a = :foo
│ Row │ a      │ b     │ c     │
│     │ Symbol │ Int64 │ Int64 │
├─────┼────────┼───────┼───────┤
│ 1   │ foo    │ 2     │ 1     │
│ 2   │ foo    │ 1     │ 4     │
⋮
Last Group (2 rows): a = :baz
│ Row │ a      │ b     │ c     │
│     │ Symbol │ Int64 │ Int64 │
├─────┼────────┼───────┼───────┤
│ 1   │ baz    │ 2     │ 3     │
│ 2   │ baz    │ 1     │ 6     │

julia> get(gd, (a=:bar,), nothing)
2×3 SubDataFrame
│ Row │ a      │ b     │ c     │
│     │ Symbol │ Int64 │ Int64 │
├─────┼────────┼───────┼───────┤
│ 1   │ bar    │ 1     │ 2     │
│ 2   │ bar    │ 2     │ 5     │

julia> get(gd, (:baz,), nothing)
2×3 SubDataFrame
│ Row │ a      │ b     │ c     │
│     │ Symbol │ Int64 │ Int64 │
├─────┼────────┼───────┼───────┤
│ 1   │ baz    │ 2     │ 3     │
│ 2   │ baz    │ 1     │ 6     │

julia> get(gd, (:qux,), nothing)
```
"""
function Base.get(gd::GroupedDataFrame, key::GroupKeyTypes, default)
    try
        return gd[key]
    catch KeyError
        return default
    end
end

"""
    filter(fun, gdf::GroupedDataFrame)
    filter(cols => fun, gdf::GroupedDataFrame)

Return a new `GroupedDataFrame` containing only groups for which `fun`
returns `true`.

If `cols` is not specified then the predicate `fun` is called with a
`SubDataFrame` for each group.

If `cols` is specified then the predicate `fun` is called for each group with
views of the corresponding columns as separate positional arguments, unless
`cols` is an `AsTable` selector, in which case a `NamedTuple` of these arguments
is passed. `cols` can be any column selector ($COLUMNINDEX_STR;
$MULTICOLUMNINDEX_STR), and column duplicates are allowed if a vector of
`Symbol`s, strings, or integers is passed.

# Examples
```
julia> df = DataFrame(g=[1, 2], x=['a', 'b']);

julia> gd = groupby(df, :g)
GroupedDataFrame with 2 groups based on key: g
First Group (1 row): g = 1
│ Row │ g     │ x    │
│     │ Int64 │ Char │
├─────┼───────┼──────┤
│ 1   │ 1     │ 'a'  │
⋮
Last Group (1 row): g = 2
│ Row │ g     │ x    │
│     │ Int64 │ Char │
├─────┼───────┼──────┤
│ 1   │ 2     │ 'b'  │

julia> filter(x -> x.x[1] == 'a', gd)
GroupedDataFrame with 1 group based on key: g
First Group (1 row): g = 1
│ Row │ g     │ x    │
│     │ Int64 │ Char │
├─────┼───────┼──────┤
│ 1   │ 1     │ 'a'  │

julia> filter(:x => x -> x[1] == 'a', gd)
GroupedDataFrame with 1 group based on key: g
First Group (1 row): g = 1
│ Row │ g     │ x    │
│     │ Int64 │ Char │
├─────┼───────┼──────┤
│ 1   │ 1     │ 'a'  │

```
"""
Base.filter(f, gdf::GroupedDataFrame) =
    gdf[[f(sdf)::Bool for sdf in gdf]]
Base.filter((col, f)::Pair{<:ColumnIndex}, gdf::GroupedDataFrame) =
    _filter_helper(gdf, f, gdf.idx, gdf.starts, gdf.ends, parent(gdf)[!, col])
Base.filter((cols, f)::Pair{<:AbstractVector{Symbol}}, gdf::GroupedDataFrame) =
    filter([index(parent(gdf))[col] for col in cols] => f, gdf)
Base.filter((cols, f)::Pair{<:AbstractVector{<:AbstractString}}, gdf::GroupedDataFrame) =
    filter([index(parent(gdf))[col] for col in cols] => f, gdf)
Base.filter((cols, f)::Pair, gdf::GroupedDataFrame) =
    filter(index(parent(gdf))[cols] => f, gdf)
Base.filter((cols, f)::Pair{<:AbstractVector{Int}}, gdf::GroupedDataFrame) =
    _filter_helper(gdf, f, gdf.idx, gdf.starts, gdf.ends, (parent(gdf)[!, i] for i in cols)...)

function _filter_helper(gdf::GroupedDataFrame, f, idx::Vector{Int},
                        starts::Vector{Int}, ends::Vector{Int}, cols...)
    function mapper(i::Integer)
        idxs = idx[starts[i]:ends[i]]
        return map(x -> view(x, idxs), cols)
    end

    if length(cols) == 0
        throw(ArgumentError("At least one column must be passed to filter on"))
    end
    sel = [f(mapper(i)...)::Bool for i in 1:length(gdf)]
    return gdf[sel]
end

function Base.filter((cols, f)::Pair{<:AsTable}, gdf::GroupedDataFrame)
    df_tmp = select(parent(gdf), cols.cols, copycols=false)
    if ncol(df_tmp) == 0
        throw(ArgumentError("At least one column must be passed to filter on"))
    end
    return _filter_helper_astable(gdf, Tables.columntable(df_tmp), f,
                                      gdf.idx, gdf.starts, gdf.ends)
end

function _filter_helper_astable(gdf::GroupedDataFrame, nt::NamedTuple, f,
                                idx::Vector{Int}, starts::Vector{Int}, ends::Vector{Int})
    function mapper(i::Integer)
        idxs = idx[starts[i]:ends[i]]
        return map(x -> view(x, idxs), nt)
    end

    return gdf[[f(mapper(i))::Bool for i in 1:length(gdf)]]
end


text:
"""
Helper function for quadratic_interval that computes roots of a
real quadratic using interval arithmetic to bound rounding errors.
"""
function quadratic_helper!(a::Interval{T}, b::Interval{T}, c::Interval{T}, L::Array{Interval{T}}) where {T}

    Δ = b^2 - 4*a*c

    Δ.hi < 0 && return

    Δ = sqrt(Δ)

    if (b.lo >= 0)
        x0 = -0.5 * (b + Δ)

    else
        x0 = -0.5 * (b - Δ)
    end

    if (0 ∈ x0)
        push!(L, x0)

    else
        x1 = c / x0
        x0 = x0 / a
        push!(L, x0, x1)
    end

end

"""
Function to solve a quadratic equation where the coefficients are intervals.
Returns an array of intervals of the roots.
Arguments `a`, `b` and `c` are interval coefficients of `x²`, `x` and `1` respectively.
The interval case differs from the non-interval case in that
there might be three disjoint interval roots. In the third
case, one interval root extends to −∞ and another extends to +∞.
This algorithm finds the set of points where `F.lo(x) ≥ 0` and the set
of points where `F.hi(x) ≤ 0` and takes the intersection of these two sets.
Eldon Hansen and G. William Walster : Global Optimization Using Interval Analysis - Chapter 8
"""
function quadratic_roots(a::Interval{T}, b::Interval{T}, c::Interval{T}) where {T}

    L = Interval{T}[]
    R = Interval{T}[]

    quadratic_helper!(Interval(a.lo), Interval(b.lo), Interval(c.lo), L)
    quadratic_helper!(Interval(a.hi), Interval(b.hi), Interval(c.hi), L)
    quadratic_helper!(Interval(a.lo), Interval(b.hi), Interval(c.lo), L)
    quadratic_helper!(Interval(a.hi), Interval(b.lo), Interval(c.hi), L)

    if (length(L) == 8)
        resize!(L, 4)
    end

    if (a.lo < 0 || (a.lo == 0 && b.hi == 0) || (a.lo == 0 && b.hi == 0 && c.lo ≤ 0))
        push!(L, Interval(-∞))
    end

    if (a.lo < 0 || (a.lo == 0 && b.lo == 0) || (a.lo == 0 && b.lo == 0 && c.lo ≤ 0))
        push!(L, Interval(∞))
    end

    sort!(L, by = x -> x.lo)

    for i in 1:2:length(L)
        push!(R, Interval(L[i].lo, L[i+1].hi))
    end

    R
end


text:
#-------------------------------------------------------------------
#* EMSO Model Library (EML) Copyright (C) 2004 - 2007 ALSOC.
#*
#* This LIBRARY is free software; you can distribute it and/or modify
#* it under the therms of the ALSOC FREE LICENSE as available at
#* http://www.enq.ufrgs.br/alsoc.
#*
#* EMSO Copyright (C) 2004 - 2007 ALSOC, original code
#* from http://www.rps.eng.br Copyright (C) 2002-2004.
#* All rights reserved.
#*
#* EMSO is distributed under the therms of the ALSOC LICENSE as
#* available at http://www.enq.ufrgs.br/alsoc.
#*
#*--------------------------------------------------------------------
#* Models to simulate a power plant.
#*--------------------------------------------------------------------
#* Author: Argimiro R. Secchi
#* $Id: power_plant.mso 195 2007-03-07 20:30:12Z arge $
#*-------------------------------------------------------------------
# Declaracao de tipos
type Fonte2
	Fonte2()=begin
		PP2=outers.PP2
		new(
			DanaPlugin(Dict{Symbol,Any}(
				:Brief=>"Steam tables"
			)),
			Corrente(Dict{Symbol,Any}(
				:Symbol=>"_{out}",
				:PosX=>1,
				:PosY=>0.5
			)),
			[
				:([Fout.S,Fout.H] = PP2.propPTl(Fout.P,Fout.T)),
			],
			[
				"",
			],
			[:PP2,],
			[:Fout,]
		)
	end
	PP2::DanaPlugin
	Fout::Corrente
	equations::Array{Expr,1}
	equationNames::Array{String,1}
	parameters::Array{Symbol,1}
	variables::Array{Symbol,1}
	attributes::Dict{Symbol,Any}
end
export Fonte2
function setEquationFlow(in::Fonte2)
	addEquation(1)
end
function atributes(in::Fonte2,_::Dict{Symbol,Any})
	fields::Dict{Symbol,Any}=Dict{Symbol,Any}()
	fields[:Pallete]=true
	fields[:Icon]="icon/fonte2"
	fields[:Brief]="Corrente de sa죡da"
	fields[:Info]=" "
	drive!(fields,_)
	return fields
end
Fonte2(_::Dict{Symbol,Any})=begin
	newModel=Fonte2()
	newModel.attributes=atributes(newModel,_)
	newModel
end


text:
# script to parse CUDA headers and generate Julia wrappers

#
# Parsing
#

using Clang

function wrap(name, headers...; wrapped_headers=headers, library="lib$name", defines=[], include_dirs=[])
    clang_args = String[]
    append!(clang_args, map(dir->"-I$dir", include_dirs))
    for define in defines
        if isa(define, Pair)
            append!(clang_args, ["-D", "$(first(define))=$(last(define))"])
        else
            append!(clang_args, ["-D", "$define"])
        end
    end

    output_file = "lib$(name).jl"
    common_file = "lib$(name)_common.jl"

    # only wrap headers that are wanted, and make sure we only process each header once
    included_from = Dict()
    function wrap_header(root, current)
        return any(header->endswith(current, header), wrapped_headers) &&
               get!(included_from, current, root) == root
    end

    context = init(;
                    headers = [headers...],
                    output_file = output_file,
                    common_file = common_file,
                    clang_includes = [include_dirs..., CLANG_INCLUDE],
                    clang_args = clang_args,
                    header_wrapped = wrap_header,
                    header_library = x->library,
                    clang_diagnostics = true,
                  )
    run(context)

    return output_file, common_file
end

#
# Fixing-up
#

using CSTParser, Tokenize

## pass infrastructure

struct Edit{T}
    loc::T
    text::String
end

function pass(x, state, f = (x, state)->nothing)
    f(x, state)
    if length(x) > 0
        for a in x
            pass(a, state, f)
        end
    else
        state.offset += x.fullspan
    end
    state
end

function apply(text, edit::Edit{Int})
    string(text[1:edit.loc], edit.text, text[nextind(text, edit.loc):end])
end
function apply(text, edit::Edit{UnitRange{Int}})
    # println("Rewriting '$(text[edit.loc])' to '$(edit.text)'")
    string(text[1:prevind(text, first(edit.loc))], edit.text, text[nextind(text, last(edit.loc)):end])
end

## rewrite passes

mutable struct State
    offset::Int
    edits::Vector{Edit}
end

# insert `@checked` before each function with a `ccall` returning a checked type`
checked_types = [
    "CUresult",
    "CUptiResult",
    "NVPA_Status",
    "nvmlReturn_t",
    "cublasStatus_t",
    "cudnnStatus_t",
    "cufftResult",
    "curandStatus_t",
    "cusolverStatus_t",
    "cusparseStatus_t",
    "cutensorStatus_t",
]
function insert_check_pass(x, state)
    if x isa CSTParser.EXPR && x.head == :function
        _, def, body, _ = x
        @assert body isa CSTParser.EXPR && body.head == :block
        @assert length(body) == 1

        # Clang.jl-generated ccalls should be directly part of a function definition
        call = body.args[1]
        @assert call isa CSTParser.EXPR && call.head == :call && call[1].val == "ccall"

        # get the ccall return type
        rv = call[5]

        if rv.val in checked_types
            push!(state.edits, Edit(state.offset, "@checked "))
        end
    end
end

# insert `initialize_api()` before each function with a `ccall` calling non-whitelisted fns
preinit_apicalls = Set{String}([
    # CUDAdrv
    ## error handling
    "cuGetErrorString",
    "cuGetErrorName",
    ## initialization
    "cuInit",
    ## version management
    "cuDriverGetVersion",
    ## device management
    "cuDeviceGet",
    "cuDeviceGetAttribute",
    "cuDeviceGetCount",
    "cuDeviceGetLuid",
    "cuDeviceGetName",
    "cuDeviceGetUuid",
    "cuDeviceTotalMem",
    "cuDeviceGetProperties",     # deprecated
    "cuDeviceComputeCapability", # deprecated
    ## context management
    "cuCtxCreate",
    "cuCtxDestroy",
    "cuCtxSetCurrent",
    "cuCtxGetCurrent",
    "cuCtxPushCurrent",
    "cuCtxPopCurrent",
    "cuCtxGetDevice", # this actually does require a context, but we use it unsafely
    ## primary context management
    "cuDevicePrimaryCtxGetState",
    "cuDevicePrimaryCtxRelease",
    "cuDevicePrimaryCtxReset",
    "cuDevicePrimaryCtxRetain",
    "cuDevicePrimaryCtxSetFlags",
    # CUPTI
    "cuptiGetVersion",
    "cuptiGetResultString",
    # NVML
    "nvmlInit",
    "nvmlInitWithFlags",
    "nvmlShutdown",
    "nvmlErrorString",
    # CUBLAS
    "cublasGetVersion",
    "cublasGetProperty",
    "cublasGetCudartVersion",
    # CURAND
    "curandGetVersion",
    "curandGetProperty",
    # CUFFT
    "cufftGetVersion",
    "cufftGetProperty",
    # CUSPARSE
    "cusparseGetVersion",
    "cusparseGetProperty",
    "cusparseGetErrorName",
    "cusparseGetErrorString",
    # CUSOLVER
    "cusolverGetVersion",
    "cusolverGetProperty",
    # CUDNN
    "cudnnGetVersion",
    "cudnnGetProperty",
    "cudnnGetCudartVersion",
    "cudnnGetErrorString",
    # CUTENSOR
    "cutensorGetVersion",
    "cutensorGetCudartVersion",
    "cutensorGetErrorString",
])
function insert_init_pass(x, state)
    if x isa CSTParser.EXPR && x.head == :call && x.args[1].val == "ccall"
        fun = x[3][2][2].val
        actual_fun = first(split(fun, '_'))    # strip tags

        # call the API initializer
        if !in(actual_fun, preinit_apicalls)
            push!(state.edits, Edit(state.offset, "initialize_api()\n    "))
        end
    end
end

# replace handles from the CUDA runtime library with CUDA driver API equivalents
function rewrite_runtime_pass(x, state)
    if x isa CSTParser.EXPR && x.head == :IDENTIFIER && x.val == "cudaStream_t"
        offset = state.offset
        push!(state.edits, Edit(offset+1:offset+x.span, "CUstream"))
    end
end

# remove aliases that are used to version functions
#
# when NVIDIA changes the behavior of an API, they version the function (`cuFunction_v2`).
# To maintain backwards compatibility, they ship aliases with their headers such that
# compiled binaries will keep using the old version, and newly-compiled ones will use the
# developer's CUDA version. remove those, since we target multiple CUDA versions.
#
# remove this if we ever decide to support a single supported version of CUDA.
cuda_version_alias(lhs, rhs) = occursin(Regex("$(lhs)_v\\d"), rhs)
nvtx_string_alias(lhs, rhs) = occursin(Regex("$(lhs)(A|W|Ex)"), rhs)
function remove_aliases_pass(x, state)
    if x isa CSTParser.EXPR && x.head == :const
        @assert x[2] isa CSTParser.EXPR
        lhs, op, rhs = x[2]
        @assert CSTParser.isoperator(op) && op.val == "="
        if lhs.head == :IDENTIFIER && rhs.head == :IDENTIFIER &&
            (cuda_version_alias(lhs.val, rhs.val) || nvtx_string_alias(lhs.val, rhs.val))
            offset = state.offset
            push!(state.edits, Edit(offset+1:offset+x.span, ""))
        end
    end
end

# collect function definitions in a wrapped file
#
# when updating CUDA, deprecated functions are removed from the headers (but not from the
# binaries). we detect that by looking at the wrapped functions in the generated files.
function collect_function_definitions(file)
    text = read(file, String)

    state = State(0, Edit[])
    ast = CSTParser.parse(text, true)

    definitions = Dict()
    for x in ast
        fn = nothing
        if x isa CSTParser.EXPR && x.head == :function
            _, def, body, _ = x
            fn = def[1].val
        elseif x isa CSTParser.EXPR && x.head === :macrocall
            m, _, y = x
            if y isa CSTParser.EXPR && y.head === :function
                _, def, body, _ = y
                fn = def[1].val
            end
        elseif x isa CSTParser.EXPR && CSTParser.isliteral(x) && x.args === nothing
            # ignore
        else
            error("Unsupported global expression: $x")
        end

        # if we found a function definition, save its range
        if fn !== nothing
            definitions[fn] = (offset=state.offset, span=x.span, fullspan=x.fullspan)
        end

        state.offset += x.fullspan
    end

    return definitions
end

#
# Main application
#

using CUDA_full_jll, CUDNN_jll, CUTENSOR_jll

function process(name, headers...; libname=name, kwargs...)
    new_output_file, new_common_file = wrap(libname, headers...; kwargs...)

    for file in (new_output_file, new_common_file)
        text = read(file, String)

        ## rewriting passes

        state = State(0, Edit[])
        ast = CSTParser.parse(text, true)

        state.offset = 0
        pass(ast, state, insert_check_pass)

        state.offset = 0
        pass(ast, state, insert_init_pass)

        state.offset = 0
        pass(ast, state, rewrite_runtime_pass)

        state.offset = 0
        pass(ast, state, remove_aliases_pass)

        # apply
        state.offset = 0
        sort!(state.edits, lt = (a,b) -> first(a.loc) < first(b.loc), rev = true)
        for i = 1:length(state.edits)
            text = apply(text, state.edits[i])
        end

        ## header

        squeezed = replace(text, "\n\n\n"=>"\n\n")
        while length(text) != length(squeezed)
            text = squeezed
            squeezed = replace(text, "\n\n\n"=>"\n\n")
        end
        text = squeezed

        write(file, text)
    end

    ## manual patches

    patchdir = joinpath(@__DIR__, "patches", name)
    if isdir(patchdir)
        for entry in readdir(patchdir)
            if endswith(entry, ".patch")
                path = joinpath(patchdir, entry)
                run(`patch -p1 -i $path`)
            end
        end
    end

    ## merge with existing wrappers

    new_output_text = read(new_output_file, String)

    existing_output_file = joinpath(dirname(dirname(@__DIR__)) , "lib", name, basename(new_output_file))
    @assert isfile(existing_output_file)
    existing_output_text = read(existing_output_file, String)

    new_defs = collect_function_definitions(new_output_file)
    existing_defs = collect_function_definitions(existing_output_file)

    # move removed methods to the 'deprecated' file and remove them from header
    removed = setdiff(keys(existing_defs), keys(new_defs))
    if !isempty(removed)
        deprecated_output_file = joinpath(dirname(dirname(@__DIR__)) , "lib", name, "lib$(libname)_deprecated.jl")
        open(deprecated_output_file, "a") do io
            state = State(0, Edit[])
            for fn in removed
                pos = existing_defs[fn]
                text = existing_output_text[pos.offset+1:pos.offset+pos.span]
                println(io)
                println(io, text)
                push!(state.edits, Edit(pos.offset+1:pos.offset+pos.fullspan, ""))
                @warn "Deprecating definition of $fn"
            end

            # apply removals
            sort!(state.edits, lt = (a,b) -> first(a.loc) < first(b.loc), rev = true)
            for i = 1:length(state.edits)
                existing_output_text = apply(existing_output_text, state.edits[i])
            end

            write(existing_output_file, existing_output_text)
        end
    end

    # append new additions and prompt the user to review
    added = setdiff(keys(new_defs), keys(existing_defs))
    if !isempty(added)
        open(existing_output_file, "a") do io
            for fn in added
                pos = new_defs[fn]
                text = new_output_text[pos.offset+1:pos.offset+pos.span]
                println(io)
                println(io, text)
                @warn "Adding definition of $fn, please review!"
            end
        end
    end

    # apply the common file
    cp(new_common_file, joinpath(dirname(dirname(@__DIR__)) , "lib", name, basename(new_common_file)); force=true)

    return
end

function main()
    cuda = joinpath(CUDA_full_jll.artifact_dir, "cuda", "include")
    cupti = joinpath(CUDA_full_jll.artifact_dir, "cuda", "extras", "CUPTI", "include")
    cudnn = joinpath(CUDNN_jll.artifact_dir, "include")
    cutensor = joinpath(CUTENSOR_jll.artifact_dir, "include")

    process("cudadrv", "$cuda/cuda.h","$cuda/cudaGL.h", "$cuda/cudaProfiler.h";
            include_dirs=[cuda], libname="cuda")

    process("nvtx", "$cuda/nvtx3/nvToolsExt.h", "$cuda/nvtx3/nvToolsExtCuda.h";
            include_dirs=[cuda])

    process("nvml", "$cuda/nvml.h"; include_dirs=[cuda])

    process("cupti", "$cupti/cupti.h", "$cupti/cupti_profiler_target.h";
            include_dirs=[cuda, cupti],
            wrapped_headers=["cupti_result.h", "cupti_version.h", "cupti_activity.h",
                             "cupti_callbacks.h", "cupti_events.h",
                             "cupti_profiler_target.h",
                             "cupti_metrics.h"], # deprecated, but still required
            defines=["__packed__"=>"", "aligned"=>""])
    # NOTE: libclang (the C API) doesn't support/expose the __packed__/aligned attributes,
    #       so disable them (Julia doesn't support packed structs anyway)

    process("cublas", "$cuda/cublas_v2.h", "$cuda/cublasXt.h";
            wrapped_headers=["cublas_v2.h", "cublas_api.h", "cublasXt.h"],
            include_dirs=[cuda])

    process("cufft", "$cuda/cufft.h"; include_dirs=[cuda])

    process("curand", "$cuda/curand.h"; include_dirs=[cuda])

    process("cusparse", "$cuda/cusparse.h"; include_dirs=[cuda])

    process("cusolver", "$cuda/cusolverDn.h", "$cuda/cusolverSp.h", "$cuda/cusolverMg.h";
            wrapped_headers=["cusolver_common.h", "cusolverDn.h", "cusolverSp.h", "cusolverMg.h"],
            include_dirs=[cuda])

    process("cudnn", "$cudnn/cudnn_version.h", "$cudnn/cudnn_ops_infer.h",
                     "$cudnn/cudnn_ops_train.h", "$cudnn/cudnn_adv_infer.h",
                     "$cudnn/cudnn_adv_train.h", "$cudnn/cudnn_cnn_infer.h",
                     "$cudnn/cudnn_cnn_train.h"; include_dirs=[cuda, cudnn])

    process("cutensor", "$cutensor/cutensor.h";
            wrapped_headers=["cutensor.h", "cutensor/types.h"],
            include_dirs=[cuda, cutensor])
end

if abspath(PROGRAM_FILE) == @__FILE__
    main()
end


text:
@testset "4.6.1.3 (d cos)^n (a+b csc)^m" begin
    (a, b, x, ) = @variables a b x

    #= ::Package:: =#

    #= ::Title::Closed:: =#
    #=Integrands*of*the*form*(e*cos(c+d*x))^m*(a+a*csc(c+d*x))^n=#

    #= ::Section::Closed:: =#
    #=Integrands*of*the*form*(e*cos(c+d*x))^m*(a+a*csc(c+d*x))^n=#

    #= ::Subsection::Closed:: =#
    #=Integrands*of*the*form*cos(c+d*x)^m*(a+a*csc(c+d*x))^n=#

    @test_int [cos(x)^4/(a + a*csc(x)), x, 7, -(x/(8*a)) - cos(x)^3/(3*a) - (cos(x)*sin(x))/(8*a) + (cos(x)^3*sin(x))/(4*a)]
    @test_int [cos(x)^3/(a + a*csc(x)), x, 6, sin(x)^2/(2*a) - sin(x)^3/(3*a)]
    @test_int [cos(x)^2/(a + a*csc(x)), x, 5, -(x/(2*a)) - cos(x)/a + (cos(x)*sin(x))/(2*a)]
    @test_int [cos(x)^1/(a + a*csc(x)), x, 5, -(log(1 + sin(x))/a) + sin(x)/a]
    @test_int [sec(x)^1/(a + a*csc(x)), x, 6, atanh(sin(x))/(2*a) + sec(x)^2/(2*a) - (sec(x)*tan(x))/(2*a)]
    @test_int [sec(x)^2/(a + a*csc(x)), x, 6, sec(x)^3/(3*a) - tan(x)^3/(3*a)]
    @test_int [sec(x)^3/(a + a*csc(x)), x, 7, atanh(sin(x))/(8*a) + sec(x)^4/(4*a) + (sec(x)*tan(x))/(8*a) - (sec(x)^3*tan(x))/(4*a)]
    @test_int [sec(x)^4/(a + a*csc(x)), x, 7, sec(x)^5/(5*a) - tan(x)^3/(3*a) - tan(x)^5/(5*a)]

    #= ::Subsection:: =#
    #=Integrands*of*the*form*cos(c+d*x)^m*(a+a*csc(c+d*x))^(n/2)=#

    #= ::Title::Closed:: =#
    #=Integrands*of*the*form*(e*cos(c+d*x))^m*(a+b*csc(c+d*x))^n=#

    #= ::Section::Closed:: =#
    #=Integrands*of*the*form*(e*cos(c+d*x))^m*(a+b*csc(c+d*x))^n=#

    #= ::Subsection::Closed:: =#
    #=Integrands*of*the*form*cos(c+d*x)^m*(a+b*csc(c+d*x))^n=#

    @test_int [cos(x)^4/(a + b*csc(x)), x, 7, ((3*a^4 - 12*a^2*b^2 + 8*b^4)*x)/(8*a^5) + (2*b*(a^2 - b^2)^(3/2)*atanh((a + b*tan(x/2))/sqrt(a^2 - b^2)))/a^5 - (cos(x)^3*(4*b - 3*a*sin(x)))/(12*a^2) - (cos(x)*(8*b*(a^2 - b^2) - a*(3*a^2 - 4*b^2)*sin(x)))/(8*a^4)]
    @test_int [cos(x)^3/(a + b*csc(x)), x, 5, -((b*(a^2 - b^2)*log(b + a*sin(x)))/a^4) + ((a^2 - b^2)*sin(x))/a^3 + (b*sin(x)^2)/(2*a^2) - sin(x)^3/(3*a)]
    @test_int [cos(x)^2/(a + b*csc(x)), x, 6, ((a^2 - 2*b^2)*x)/(2*a^3) + (2*b*sqrt(a^2 - b^2)*atanh((a + b*tan(x/2))/sqrt(a^2 - b^2)))/a^3 - (cos(x)*(2*b - a*sin(x)))/(2*a^2)]
    @test_int [cos(x)^1/(a + b*csc(x)), x, 5, -((b*log(b + a*sin(x)))/a^2) + sin(x)/a]
    @test_int [sec(x)^1/(a + b*csc(x)), x, 4, -(log(1 - sin(x))/(2*(a + b))) + log(1 + sin(x))/(2*(a - b)) - (b*log(b + a*sin(x)))/(a^2 - b^2)]
    @test_int [sec(x)^2/(a + b*csc(x)), x, 6, (2*a*b*atanh((a + b*tan(x/2))/sqrt(a^2 - b^2)))/(a^2 - b^2)^(3/2) - (sec(x)*(b - a*sin(x)))/(a^2 - b^2)]
    @test_int [sec(x)^3/(a + b*csc(x)), x, 6, -((a*log(1 - sin(x)))/(4*(a + b)^2)) + (a*log(1 + sin(x)))/(4*(a - b)^2) - (a^2*b*log(b + a*sin(x)))/(a^2 - b^2)^2 - (sec(x)^2*(b - a*sin(x)))/(2*(a^2 - b^2))]
    @test_int [sec(x)^4/(a + b*csc(x)), x, 7, (2*a^3*b*atanh((a + b*tan(x/2))/sqrt(a^2 - b^2)))/(a^2 - b^2)^(5/2) - (sec(x)^3*(b - a*sin(x)))/(3*(a^2 - b^2)) - (sec(x)*(3*a^2*b - a*(2*a^2 + b^2)*sin(x)))/(3*(a^2 - b^2)^2)]

    #= ::Subsection:: =#
    #=Integrands*of*the*form*cos(c+d*x)^m*(a+b*csc(c+d*x))^(n/2)=#
    end

max_stars_repo_path: test/4 Trig functions/4.6 Cosecant/4.6.1.3 (d cos)^n (a+b csc)^m.jl


text:
function copper_plate(
    optimization_container::OptimizationContainer,
    expression::Symbol,
    bus_count::Int,
)
    time_steps = model_time_steps(optimization_container)
    expressions = get_expression(optimization_container, expression)
    remove_undef!(optimization_container.expressions[expression])

    constraint_val = JuMPConstraintArray(undef, time_steps)
    assign_constraint!(optimization_container, "CopperPlateBalance", constraint_val)

    for t in time_steps
        constraint_val[t] = JuMP.@constraint(
            optimization_container.JuMPmodel,
            sum(expressions.data[i, t] for i in 1:bus_count) == 0
        )
    end

    return
end


text:
# Example: Compartmental models in epidemiology
#=
- https://github.com/epirecipes/sir-julia/blob/master/markdown/function_map/function_map.md
- https://en.wikipedia.org/wiki/Compartmental_models_in_epidemiology#Deterministic_versus_stochastic_epidemic_models
=#
using ModelingToolkit, Test

@inline function rate_to_proportion(r, t)
    1 - exp(-r * t)
end;

# Independent and dependent variables and parameters
@parameters t c nsteps δt β γ
D = Difference(t; dt = 0.1)
@variables S(t) I(t) R(t)

infection = rate_to_proportion(β * c * I / (S + I + R), δt) * S
recovery = rate_to_proportion(γ, δt) * I

# Equations
eqs = [D(S) ~ S - infection,
    D(I) ~ I + infection - recovery,
    D(R) ~ R + recovery]

# System
@named sys = DiscreteSystem(eqs, t, [S, I, R], [c, nsteps, δt, β, γ]; controls = [β, γ])
syss = structural_simplify(sys)
@test syss == syss

# Problem
u0 = [S => 990.0, I => 10.0, R => 0.0]
p = [β => 0.05, c => 10.0, γ => 0.25, δt => 0.1, nsteps => 400]
tspan = (0.0, ModelingToolkit.value(substitute(nsteps, p))) # value function (from Symbolics) is used to convert a Num to Float64
prob_map = DiscreteProblem(sys, u0, tspan, p)

# Solution
using OrdinaryDiffEq
sol_map = solve(prob_map, FunctionMap());
@test sol_map[S] isa Vector

# Using defaults constructor
@parameters t c=10.0 nsteps=400 δt=0.1 β=0.05 γ=0.25
Diff = Difference(t; dt = 0.1)
@variables S(t)=990.0 I(t)=10.0 R(t)=0.0

infection2 = rate_to_proportion(β * c * I / (S + I + R), δt) * S
recovery2 = rate_to_proportion(γ, δt) * I

eqs2 = [D(S) ~ S - infection2,
    D(I) ~ I + infection2 - recovery2,
    D(R) ~ R + recovery2]

@named sys = DiscreteSystem(eqs2; controls = [β, γ])
@test ModelingToolkit.defaults(sys) != Dict()

prob_map2 = DiscreteProblem(sys, [], tspan)
sol_map2 = solve(prob_map, FunctionMap());

@test sol_map.u == sol_map2.u
@test sol_map.prob.p == sol_map2.prob.p

# Direct Implementation

function sir_map!(u_diff, u, p, t)
    (S, I, R) = u
    (β, c, γ, δt) = p
    N = S + I + R
    infection = rate_to_proportion(β * c * I / N, δt) * S
    recovery = rate_to_proportion(γ, δt) * I
    @inbounds begin
        u_diff[1] = S - infection
        u_diff[2] = I + infection - recovery
        u_diff[3] = R + recovery
    end
    nothing
end;
u0 = [990.0, 10.0, 0.0];
p = [0.05, 10.0, 0.25, 0.1];
prob_map = DiscreteProblem(sir_map!, u0, tspan, p);
sol_map2 = solve(prob_map, FunctionMap());

@test Array(sol_map) ≈ Array(sol_map2)

# Delayed difference equation
@parameters t
@variables x(..) y(..) z(t)
D1 = Difference(t; dt = 1.5)
D2 = Difference(t; dt = 2)

@test ModelingToolkit.is_delay_var(Symbolics.value(t), Symbolics.value(x(t - 2)))
@test ModelingToolkit.is_delay_var(Symbolics.value(t), Symbolics.value(y(t - 1)))
@test !ModelingToolkit.is_delay_var(Symbolics.value(t), Symbolics.value(z))
@test_throws ErrorException ModelingToolkit.get_delay_val(Symbolics.value(t),
                                                          Symbolics.arguments(Symbolics.value(x(t +
                                                                                2)))[1])
@test_throws ErrorException z(t)

# Equations
eqs = [
    D1(x(t)) ~ 0.4x(t) + 0.3x(t - 1.5) + 0.1x(t - 3),
    D2(y(t)) ~ 0.3y(t) + 0.7y(t - 2) + 0.1z,
]

# System
@named sys = DiscreteSystem(eqs, t, [x(t), x(t - 1.5), x(t - 3), y(t), y(t - 2), z], [])

eqs2, max_delay = ModelingToolkit.linearize_eqs(sys; return_max_delay = true)

@test max_delay[Symbolics.operation(Symbolics.value(x(t)))] ≈ 3
@test max_delay[Symbolics.operation(Symbolics.value(y(t)))] ≈ 2

linearized_eqs = [eqs
                  x(t - 3.0) ~ x(t - 1.5)
                  x(t - 1.5) ~ x(t)
                  y(t - 2.0) ~ y(t)]
@test all(eqs2 .== linearized_eqs)

# observed variable handling
@variables t x(t) RHS(t)
@parameters τ
@named fol = DiscreteSystem([D(x) ~ (1 - x) / τ]; observed = [RHS ~ (1 - x) / τ])
@test isequal(RHS, @nonamespace fol.RHS)
RHS2 = RHS
@unpack RHS = fol
@test isequal(RHS, RHS2)

@testset "Preface tests" begin
    @parameters t
    using OrdinaryDiffEq
    using Symbolics
    using DiffEqBase: isinplace
    using ModelingToolkit
    using SymbolicUtils.Code
    using SymbolicUtils: Sym

    c = [0]
    f = function f(c, d::Vector{Float64}, u::Vector{Float64}, p, t::Float64, dt::Float64)
        c .= [c[1] + 1]
        d .= randn(length(u))
        nothing
    end

    dummy_identity(x, _) = x
    @register_symbolic dummy_identity(x, y)

    u0 = ones(5)
    p0 = Float64[]
    syms = [Symbol(:a, i) for i in 1:5]
    syms_p = Symbol[]
    dt = 0.1
    @assert isinplace(f, 6)
    wf = let c = c, buffer = similar(u0), u = similar(u0), p = similar(p0), dt = dt
        t -> (f(c, buffer, u, p, t, dt); buffer)
    end

    num = hash(f) ⊻ length(u0) ⊻ length(p0)
    buffername = Symbol(:fmi_buffer_, num)

    Δ = DiscreteUpdate(t; dt = dt)
    us = map(s -> (@variables $s(t))[1], syms)
    ps = map(s -> (@variables $s(t))[1], syms_p)
    buffer, = @variables $buffername[1:length(u0)]
    dummy_var = Sym{Any}(:_) # this is safe because _ cannot be a rvalue in Julia

    ss = Iterators.flatten((us, ps))
    vv = Iterators.flatten((u0, p0))
    defs = Dict{Any, Any}(s => v for (s, v) in zip(ss, vv))

    preface = [Assignment(dummy_var, SetArray(true, term(getfield, wf, Meta.quot(:u)), us))
               Assignment(dummy_var, SetArray(true, term(getfield, wf, Meta.quot(:p)), ps))
               Assignment(buffer, term(wf, t))]
    eqs = map(1:length(us)) do i
        Δ(us[i]) ~ dummy_identity(buffer[i], us[i])
    end

    @named sys = DiscreteSystem(eqs, t, us, ps; defaults = defs, preface = preface)
    prob = DiscreteProblem(sys, [], (0.0, 1.0))
    sol = solve(prob, FunctionMap(); dt = dt)
    @test c[1] + 1 == length(sol)
end


text:
# This file was generated, do not modify it. # hide
using Soss

N = 10000

m = @model x, λ begin
    σ ~ Exponential(λ)
    β ~ Normal(0,1)
    y ~ For(1:N) do j
        Normal(x[j] * β, σ)
    end
    return y
end

max_stars_repo_name: cscherrer/InformativePrior

max_issues_repo_name: cscherrer/InformativePrior

max_forks_repo_name: cscherrer/InformativePrior


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

struct RoutesApi <: SwaggerApi
    client::Swagger.Client
end

"""

Creates or updates a route in the specified route table.
Param: resourceGroupName::String (required)
Param: routeTableName::String (required)
Param: routeName::String (required)
Param: routeParameters::Route (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: Route
"""
function _swaggerinternal_routesCreateOrUpdate(_api::RoutesApi, resourceGroupName::String, routeTableName::String, routeName::String, routeParameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "PUT", Route, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/routeTables/{routeTableName}/routes/{routeName}", ["azure_auth"], routeParameters)
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "routeTableName", routeTableName)  # type String
    Swagger.set_param(_ctx.path, "routeName", routeName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function routesCreateOrUpdate(_api::RoutesApi, resourceGroupName::String, routeTableName::String, routeName::String, routeParameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_routesCreateOrUpdate(_api, resourceGroupName, routeTableName, routeName, routeParameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function routesCreateOrUpdate(_api::RoutesApi, response_stream::Channel, resourceGroupName::String, routeTableName::String, routeName::String, routeParameters, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_routesCreateOrUpdate(_api, resourceGroupName, routeTableName, routeName, routeParameters, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Deletes the specified route from a route table.
Param: resourceGroupName::String (required)
Param: routeTableName::String (required)
Param: routeName::String (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: Nothing
"""
function _swaggerinternal_routesDelete(_api::RoutesApi, resourceGroupName::String, routeTableName::String, routeName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "DELETE", Nothing, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/routeTables/{routeTableName}/routes/{routeName}", ["azure_auth"])
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "routeTableName", routeTableName)  # type String
    Swagger.set_param(_ctx.path, "routeName", routeName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function routesDelete(_api::RoutesApi, resourceGroupName::String, routeTableName::String, routeName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_routesDelete(_api, resourceGroupName, routeTableName, routeName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function routesDelete(_api::RoutesApi, response_stream::Channel, resourceGroupName::String, routeTableName::String, routeName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_routesDelete(_api, resourceGroupName, routeTableName, routeName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Gets the specified route from a route table.
Param: resourceGroupName::String (required)
Param: routeTableName::String (required)
Param: routeName::String (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: Route
"""
function _swaggerinternal_routesGet(_api::RoutesApi, resourceGroupName::String, routeTableName::String, routeName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "GET", Route, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/routeTables/{routeTableName}/routes/{routeName}", ["azure_auth"])
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "routeTableName", routeTableName)  # type String
    Swagger.set_param(_ctx.path, "routeName", routeName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function routesGet(_api::RoutesApi, resourceGroupName::String, routeTableName::String, routeName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_routesGet(_api, resourceGroupName, routeTableName, routeName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function routesGet(_api::RoutesApi, response_stream::Channel, resourceGroupName::String, routeTableName::String, routeName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_routesGet(_api, resourceGroupName, routeTableName, routeName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

"""

Gets all routes in a route table.
Param: resourceGroupName::String (required)
Param: routeTableName::String (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: RouteListResult
"""
function _swaggerinternal_routesList(_api::RoutesApi, resourceGroupName::String, routeTableName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "GET", RouteListResult, "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/routeTables/{routeTableName}/routes", ["azure_auth"])
    Swagger.set_param(_ctx.path, "resourceGroupName", resourceGroupName)  # type String
    Swagger.set_param(_ctx.path, "routeTableName", routeTableName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    return _ctx
end

function routesList(_api::RoutesApi, resourceGroupName::String, routeTableName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_routesList(_api, resourceGroupName, routeTableName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx)
end

function routesList(_api::RoutesApi, response_stream::Channel, resourceGroupName::String, routeTableName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = _swaggerinternal_routesList(_api, resourceGroupName, routeTableName, api_version, subscriptionId; _mediaType=_mediaType)
    Swagger.exec(_ctx, response_stream)
end

export routesCreateOrUpdate, routesDelete, routesGet, routesList


text:
using Test
using WavePropBase
using WavePropBase.Geometry
using WavePropBase.Interpolation
using WavePropBase.Mesh
using StaticArrays

@testset "One dimension" begin
    l = HyperRectangle(0.0,1.0)
    E = typeof(l) # type of mesh element
    h = 0.1 # grid spacing
    mesh = UniformCartesianMesh(l,(10,))
    @test keys(mesh) == (E,)
    iter = ElementIterator(mesh,E)
    @test eltype(iter) == E
    @test iter[1] ≈ HyperRectangle(0,0.1)
    @test iter[3] ≈ HyperRectangle(0.2,0.3)
    for (n,el) in enumerate(iter)
        @test el ≈ HyperRectangle((n-1)*0.1,n*0.1)
    end
    iter = NodeIterator(mesh)
    @test eltype(iter) == SVector{1,Float64}
    @test size(iter) == (11,)
    for (n,x) in enumerate(iter)
        @test x ≈ SVector((n-1)*h)
    end
end

@testset "Two dimensions" begin
    l    = HyperRectangle((0.0,0.0),(1.0,1.0))
    E    = typeof(l) # type of mesh element
    mesh = UniformCartesianMesh(l,(10,20))
    iter = ElementIterator(mesh,E)
    @test iter[1,1] ≈ HyperRectangle((0,0),(0.1,0.05))
    @test length(iter) == 200
    @test size(iter) == (10,20)
    iter = NodeIterator(mesh)
    @test eltype(iter) == SVector{2,Float64}
    @test length(iter) == 11*21
    @test size(iter) == (11,21)
end

max_stars_repo_name: WaveProp/WavePropBase

max_issues_repo_name: WaveProp/WavePropBase

max_forks_repo_name: WaveProp/WavePropBase


text:
function get_tippetop(;
    timestep=0.01,
    gravity=[0.0; 0.0; -9.81],
    friction_coefficient=0.4,
    contact=true,
    contact_type=:nonlinear,
    T=Float64)

    origin = Origin{T}(name=:origin)
    radius = 0.5
    mass = 1.0
    α = 0.2
    bodies = [
        Sphere(radius, mass, name=:sphere1, color=gray_light),
        Sphere(radius*α, mass*α^3, name=:sphere2, color=gray_light)]

    joints = [
        JointConstraint(Floating(origin, bodies[1]),
                name=:floating_joint),
        JointConstraint(Fixed(bodies[1], bodies[2],
                parent_vertex=[0,0,radius],
                child_vertex=zeros(3)),
                name = :fixed_joint)]
    mechanism = Mechanism(origin, bodies, joints,
        timestep=timestep,
        gravity=gravity)

    # modify inertias
    mechanism.bodies[1].inertia = Diagonal([1.9, 2.1, 2.0])

    if contact
        contact_point = [0.0, 0.0, 0.0]
        normal = [0.0, 0.0, 1.0]
        contacts = [
            contact_constraint(get_body(mechanism, :sphere1), normal,
                friction_coefficient=friction_coefficient,
                contact_point=contact_point, offset=[0.0, 0.0, radius],
                contact_type=contact_type),
            contact_constraint(get_body(mechanism, :sphere2), normal,
                friction_coefficient=friction_coefficient,
                contact_point=contact_point,
                offset=[0.0, 0.0, radius * α],
                contact_type=contact_type)
            ]
        set_minimal_coordinates!(mechanism, get_joint(mechanism, :floating_joint), [0.0; 0.0; radius; zeros(3)])
        mechanism = Mechanism(origin, bodies, joints, contacts,
            gravity=gravity,
            timestep=timestep)
    end

    return mechanism
end

function initialize_tippetop!(mechanism::Mechanism{T};
    body_position=zeros(3),
    body_orientation=zeros(3),
    body_linear_velocity=zeros(3),
    body_angular_velocity=zeros(3)) where T

    floating_joint = get_joint(mechanism, :floating_joint)
    fixed_joint = get_joint(mechanism, :fixed_joint)
    radius = fixed_joint.translational.vertices[1][3]

    zero_velocity!(mechanism)
    set_minimal_coordinates_velocities!(mechanism, floating_joint,
        xmin=[body_position; body_orientation; body_linear_velocity; body_angular_velocity])
    set_minimal_coordinates_velocities!(mechanism, fixed_joint)
    return nothing
end


text:
export dominant_set

function _remove_equivalent(Lambda)
    #= Removes all but one of equivalent constraints =#

    Lambda_new = Set{Constraint}()
    for lambda_i in Lambda
        push!(Lambda_new, lambda_i)
        for lambda_j in Lambda
            if (lambda_i != lambda_j
                    && lambda_j in Lambda_new
                    && is_equivalent(lambda_i, lambda_j))

                delete!(Lambda_new, lambda_i)
                break
            end # if
        end # for
    end # for

    return Lambda_new
end # function

"""
    dominant_set(Lambda::Set{Constraint})

Calculates the dominant constraint set given a set of weakly-hard constraints, `Lambda`.

# Examples
```julia-repl
julia> Lambda_star = dominant_set(Set([RowMissConstraint(1),
                                       AnyMissConstraint(3, 5),
                                       AnyMissConstraint(1, 7)]))
Set([AnyMissConstraint(1, 7)])
```
"""
function dominant_set(Lambda::Set{Constraint})::Set{Constraint}

    Lambda = _remove_equivalent(Lambda)

    # Return full set if there is only one constraint
    if length(Lambda) == 1
        return Lambda
    end

    # Add Constraints to a connectivity-graph
    dominance_graph = Dict(lambda => Set{Constraint}() for lambda in Lambda)
    for lambda_i in Lambda
        for lambda_j in Lambda
            if lambda_i != lambda_j
                # Add edge if lambda_i <= lambda_j
                if is_dominant(lambda_i, lambda_j)
                    push!(dominance_graph[lambda_i], lambda_j)
                # Else, if
                #   lambda_i </= lambda_j and lambda_j </= lambda_i,
                # add undirected edge
                elseif !is_dominant(lambda_j, lambda_i)
                    push!(dominance_graph[lambda_i], lambda_j)
                    push!(dominance_graph[lambda_j], lambda_i)
                end # if
            end # if
        end # for
    end # for

    # For all constraints
    for (lambda_i, doms) in dominance_graph
        # For all dominations of the constraint
        for lambda_j in doms
            # If lambda_j is in the dominance graph but it does not dominate
            # lambda_i, remove it (since lambda_i <= lambda_j).
            # NOTE: We do not have to remove it if it is not already in the graph.
            if lambda_j in keys(dominance_graph) && !(lambda_i in dominance_graph[lambda_j])
                delete!(dominance_graph, lambda_j)
            end # if
        end # for
    end # for

    # Return the dominant constraints
    return Set(keys(dominance_graph))
end # function


text:
module Recorders

using Sockets
using DemeNet: Certificate, Intent, Contract, Consensus, Envelope, Notary, Deme, Signer, ID, DemeID, AbstractID, datadir, verify, serialize, deserialize
using PeaceVote: AbstractVote, AbstractChain, AbstractProposal

import PeaceVote: record
using ..Analysis: voters!, members, addvoters!
using ..Braiders: Braider
using ..Types: Proposal, Vote, Braid
using ..Ledgers: Ledger, load

include("../debug.jl")

struct Registrator{T}
    server
    daemon
    messages::Channel{Certificate{T}}
end

function Registrator{T}(port,verify::Function,validate::Function) where T<:Any
    server = listen(port)
    messages = Channel{Certificate{T}}()

    daemon = @async while true
        socket = accept(server)
        @async begin
            envelope = deserialize(socket,Certificate{T})
            signerid = verify(envelope)
            #memberid, signerid = unwrap(envelope)

            if validate(signerid)
                put!(messages,envelope)
            end
        end
    end

    Registrator(server,daemon,messages)
end

struct RecorderConfig{T}
    membersca::Union{Vector{Union{DemeID,ID}},Vector{ID}} ### One needs to explicitly add the certifier server id here. That's because
    serverid::ID
    registratorport::T ### The port to which the certificate of membership is delivered
    votingport::T
    proposalport::T
end

struct Recorder # RecorderConfig
    registrator::Registrator{ID}
    voterecorder::Registrator{Vote}
    proposalreceiver::Registrator{Proposal}
    braider::Braider
    members::Set{ID}
    daemon
end

const listmembers = members

extverify(x::Certificate{T},notary::Notary) where T <: AbstractID = verify(x,notary)
extverify(x::Envelope{Certificate{T}},notary::Notary) where T <: AbstractID = verify(x)

### Recorder or BraidChainRecorder
function Recorder(config::RecorderConfig,deme::Deme,ledger::Ledger,braider::Braider,signer::Signer)
    notary = deme.notary

    @show messages = load(ledger) ### Maybe a different name must be used here

    members = listmembers(messages,config.membersca)
    voters!(braider.voters,messages) ### I could update the braider here

    allvoters = Set{ID}()
    voters!(allvoters,messages)

    registrator = Registrator{ID}(config.registratorport,x->extverify(x,notary),x -> x in config.membersca)
    voterecorder = Registrator{Vote}(config.votingport,x->verify(x,notary),x -> x in allvoters)
    proposalreceiver = Registrator{Proposal}(config.proposalport,x->verify(x,notary),x -> x in members)

    daemon = @async @sync begin
        @async while true
            cert = take!(registrator.messages)

            id = cert.document

            push!(members,id)
            push!(braider.voters,id)
            push!(allvoters,id)

            serialize(ledger,cert)
        end

        @async while true
            braid = take!(braider)
            consbraid = Consensus(braid,notary)

            ### We have different types here. I could move everything to references in future.
            input = unique(consbraid.references)
            output = unique(consbraid.document.ids)
            @assert length(input)==length(output)

            voters!(braider.voters,input,output)
            addvoters!(allvoters,input,output)

            serialize(ledger,braid)
        end

        @async while true
            vote = take!(voterecorder.messages)
            serialize(ledger,vote)
        end

        @async while true
            proposal = take!(proposalreceiver.messages)
            serialize(ledger,proposal)
        end
    end

    Recorder(registrator,voterecorder,proposalreceiver,braider,members,daemon)
end

function record(config::RecorderConfig,cert::Certificate{ID})
    socket = connect(config.registratorport)
    serialize(socket,cert)
    close(socket)
end

function record(config::RecorderConfig,cert::Certificate{T}) where T <: AbstractVote
    socket = connect(config.votingport)
    serialize(socket,cert)
    close(socket)
end

function record(config::RecorderConfig,cert::Certificate{T}) where T <: AbstractProposal
    socket = connect(config.proposalport)
    serialize(socket,cert)
    close(socket)
end

export BraidChain, RecorderConfig, Recorder, record

end


text:
### A Pluto.jl notebook ###
# v0.12.16

using Markdown
using InteractiveUtils

# ╔═╡ aea710be-3347-11eb-0fc4-3f8605d39ec6
md" ## Acknowledgements
1. [Reference from Calculus with Julia] (https://juliahub.com/docs/CalculusWithJulia/AZHbv/0.0.5/limits/limits.html)
2. https://observablehq.com/@petulla/explorable-linear-algebra-cheatsheet

"

# ╔═╡ Cell order:
# ╠═aea710be-3347-11eb-0fc4-3f8605d39ec6


text:
# This file includes code originally from Julia.
# License is MIT: https://github.com/JuliaString/Strs.jl/LICENSE.md

const RegexStrings = (ASCIIStr, BinaryStr, Text1Str, LatinStr, Strs._LatinStr, UTF8Str)

@static if V6_COMPAT
    collect_eachmatch(re, str; overlap=false) =
        [m.match for m in collect(eachmatch(re, str, overlap))]
else
    collect_eachmatch(re, str; overlap=false) =
        [m.match for m in collect(eachmatch(re, str, overlap = overlap))]
end

@testset "UTF8Str Regex" begin
    # Proper unicode handling
    @test match(r"∀∀", UTF8Str("∀x∀∀∀")).match == "∀∀"
    @test collect_eachmatch(r".\s", UTF8Str("x \u2200 x \u2203 y")) == ["x ", "∀ ", "x ", "∃ "]
end

@testset "Regex" begin
    for T in RegexStrings
        @test collect_eachmatch(r"a?b?", T("asbd")) == ["a","","b","",""] ==
            collect_eachmatch(r"""a?b?""", T("asbd"))
        @test collect_eachmatch(r"a?b?", T("asbd"), overlap=true) == ["a","","b","",""]
        @test collect_eachmatch(r"\w+", T("hello"), overlap=true) ==
            ["hello","ello","llo","lo","o"]
        @test collect_eachmatch(r"(\w+)(\s*)", T("The dark side of the moon")) ==
            ["The ", "dark ", "side ", "of ", "the ", "moon"]
        @test collect_eachmatch(r"", T("")) == [""]
        @test collect_eachmatch(r"", T(""), overlap=true) == [""]
        @test collect_eachmatch(r"aa", T("aaaa")) == ["aa", "aa"]
        @test collect_eachmatch(r"aa", T("aaaa"), overlap=true) == ["aa", "aa", "aa"]
        @test collect_eachmatch(r"", T("aaa")) == ["", "", "", ""]
        @test collect_eachmatch(r"", T("aaa"), overlap=true) == ["", "", "", ""]
        @test collect_eachmatch(r"GCG", T("GCGCG")) == ["GCG"]
        @test collect_eachmatch(r"GCG", T("GCGCG"),overlap=true) == ["GCG","GCG"]

# Issue 8278
target = """71.163.72.113 - - [30/Jul/2014:16:40:55 -0700] "GET emptymind.org/thevacantwall/wp-content/uploads/2013/02/DSC_006421.jpg HTTP/1.1" 200 492513 "http://images.search.yahoo.com/images/view;_ylt=AwrB8py9gdlTGEwADcSjzbkF;_ylu=X3oDMTI2cGZrZTA5BHNlYwNmcC1leHAEc2xrA2V4cARvaWQDNTA3NTRiMzYzY2E5OTEwNjBiMjc2YWJhMjkxMTEzY2MEZ3BvcwM0BGl0A2Jpbmc-?back=http%3A%2F%2Fus.yhs4.search.yahoo.com%2Fyhs%2Fsearch%3Fei%3DUTF-8%26p%3Dapartheid%2Bwall%2Bin%2Bpalestine%26type%3Dgrvydef%26param1%3D1%26param2%3Dsid%253Db01676f9c26355f014f8a9db87545d61%2526b%253DChrome%2526ip%253D71.163.72.113%2526p%253Dgroovorio%2526x%253DAC811262A746D3CD%2526dt%253DS940%2526f%253D7%2526a%253Dgrv_tuto1_14_30%26hsimp%3Dyhs-fullyhosted_003%26hspart%3Dironsource&w=588&h=387&imgurl=occupiedpalestine.files.wordpress.com%2F2012%2F08%2F5-peeking-through-the-wall.jpg%3Fw%3D588%26h%3D387&rurl=http%3A%2F%2Fwww.stopdebezetting.com%2Fwereldpers%2Fcompare-the-berlin-wall-vs-israel-s-apartheid-wall-in-palestine.html&size=49.0KB&name=...+%3Cb%3EApartheid+wall+in+Palestine%3C%2Fb%3E...+%7C+Or+you+go+peeking+through+the+%3Cb%3Ewall%3C%2Fb%3E&p=apartheid+wall+in+palestine&oid=50754b363ca991060b276aba291113cc&fr2=&fr=&tt=...+%3Cb%3EApartheid+wall+in+Palestine%3C%2Fb%3E...+%7C+Or+you+go+peeking+through+the+%3Cb%3Ewall%3C%2Fb%3E&b=0&ni=21&no=4&ts=&tab=organic&sigr=13evdtqdq&sigb=19k7nsjvb&sigi=12o2la1db&sigt=12lia2m0j&sign=12lia2m0j&.crumb=.yUtKgFI6DE&hsimp=yhs-fullyhosted_003&hspart=ironsource" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36"""

        pat = r"""([\d\.]+) ([\w.-]+) ([\w.-]+) (\[.+\]) "([^"\r\n]*|[^"\r\n\[]*\[.+\][^"]+|[^"\r\n]+.[^"]+)" (\d{3}) (\d+|-) ("(?:[^"]|\")+)"? ("(?:[^"]|\")+)"?"""

        match(pat, T(target))

        # Issue 9545 (32 bit)
        buf = PipeBuffer()
        show(buf, r"")
        @static if V6_COMPAT
            @test readstring(buf) == "r\"\""
        else
            @test read(buf, String) == "r\"\""
        end

        # see #10994, #11447: PCRE2 allows NUL chars in the pattern
        @test occurs_in(Regex(T("^a\0b\$")), T("a\0b"))

        # regex match / search string must be a String
        @test_throws ArgumentError match(r"test", GenericString("this is a test"))
        @test_throws ArgumentError fnd(First, r"test", GenericString("this is a test"))

        # Named subpatterns
        let m = match(r"(?<a>.)(.)(?<b>.)", T("xyz"))
            @test (m[:a], m[2], m["b"]) == ("x", "y", "z")
            @test sprint(show, m) == "RegexMatchStr(\"xyz\", a=\"x\", 2=\"y\", b=\"z\")"
        end
        # Backcapture reference in substitution string
        @static if !V6_COMPAT
            @test_broken replace(T("abcde"), r"(..)(?P<byname>d)" => s"\g<byname>xy\\\1") ==
                "adxy\\bce"
            @test_throws ErrorException replace("a", r"(?P<x>)" => s"\g<y>")
        end
    end
end


text:
# Compile speed tests
# Tests time to get from nothing to certain tasks
using JuMP  # Ensure compiled before running the tests

# Test 1
# Size 100, aff_str into model_str
test1_time = @elapsed begin
    run(`$(ENV["_"]) -e """
    using JuMP
    m = Model()
    N = 100
    @variable(m, x[1:N])
    @constraint(m, sum(i*x[i] for i=1:N) >= N)
    @time JuMP.aff_str(JuMP.REPLMode, m.linconstr[end].terms)
    @time JuMP.model_str(JuMP.REPLMode, m)"""
    `)
end

# Test 2
# Size 100, model_str
test2_time = @elapsed begin
    run(`$(ENV["_"]) -e """
    using JuMP
    m = Model()
    N = 100
    @variable(m, x[1:N])
    @constraint(m, sum(i*x[i] for i=1:N) >= N)
    @time JuMP.model_str(JuMP.REPLMode, m)"""
    `)
end

# Test 3
# Size 10,000, print model
test3_time = @elapsed begin
    run(`$(ENV["_"]) -e """
    using JuMP
    m = Model()
    N = 10000
    @variable(m, x[1:N])
    @constraint(m, sum(i*x[i] for i=1:N) >= N)
    @time sprint(print, m)"""
    `)
end

# Test 4
# Size 10, 4 variables, print model
test4_time = @elapsed begin
    run(`$(ENV["_"]) -e """
    using JuMP
    m = Model()
    N = 10
    @variable(m, x1[1:N])
    @variable(m, x2[1:N,f=1:N])
    @variable(m, x3[1:N,f=1:2:N])
    @variable(m, x4[[:a,:b,:c]])
    @variable(m, x5[[:a,:b,:c],[:d,"e",4]])
    @constraint(m,
        sum(i*x1[i] for i=1:N) +
        sum(i*f*x2[i,f] for i=1:N,f=1:N) +
        sum(i*f*x3[i,f] for i=1:N,f=1:2:N) +
        sum(x4) >= N)
    @time sprint(print, m)"""
    `)
end

println("Julia ", VERSION)
println(
    "Current branch: $(chomp(read(`git rev-parse --abbrev-ref HEAD`, String)))",
)
println("Current commit: $(chomp(read(`git rev-parse HEAD`, String)))")
@printf("Test 1: %7.2f s\n", test1_time)
@printf("Test 2: %7.2f s\n", test2_time)
@printf("Test 3: %7.2f s\n", test3_time)
@printf("Test 4: %7.2f s\n", test4_time)

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
##  Copyright 2022 Myrl Marmarelis
##
##  Licensed under the Apache License, Version 2.0 (the "License");
##  you may not use this file except in compliance with the License.
##  You may obtain a copy of the License at
##
##    http://www.apache.org/licenses/LICENSE-2.0
##
##  Unless required by applicable law or agreed to in writing, software
##  distributed under the License is distributed on an "AS IS" BASIS,
##  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
##  See the License for the specific language governing permissions and
##  limitations under the License.

using Flux, Zygote

make_glorot_normal(T) = (a...) -> convert.(T, Flux.glorot_normal(a...))

# is there any value in specializing the type with one final parameter
# that indicates whatever complicated structure that `model` takes on?
struct NeuralPredictor{ In, Out, T } <: Predictor{In, Out, T}
  model
end

function NeuralPredictor(n_inputs::Int, n_outputs::Int; n_layers::Int,
    n_inner_dims::Int, dropout::T) where T
  @assert n_layers >= 1
  model = Chain(
    # can the same model be used for treating all inputs,
    # or should different ones be trained for each case?
    # at least in the case of a latent space...
    Dense(n_inputs, n_inner_dims, swish, init=make_glorot_normal(T)),
    Dropout(dropout),
    ( SkipConnection( Chain(
        Dense(n_inner_dims, n_inner_dims, swish, init=make_glorot_normal(T)),
        Dropout(dropout) ), +) # make subsequent decoder layers ResNet-like
      for _ in 2:n_layers )...,
    Dense(n_inner_dims, n_outputs, init=make_glorot_normal(T)) )
  NeuralPredictor{n_inputs, n_outputs, T}(model)
end

predict(predictor::NeuralPredictor{In,Out,T},
    data::AbstractVector) where {In,Out,T} = predictor.model(data)

get_params(predictor::NeuralPredictor) = Flux.params(predictor.model)

max_stars_repo_name: marmarelis/TreatmentCurves

max_issues_repo_name: marmarelis/TreatmentCurves

max_forks_repo_name: marmarelis/TreatmentCurves