text:
# core mechanism of extending Taine Zhao's @thautwarm 's MatchCore pattern matching.

using MatchCore
using ..Patterns

## compile (quote) left and right hands of a rule
# escape symbols to create MLStyle compatible patterns

# compile left hand of rule
# if it's the first time seeing p, add it to the "seen symbols" Set
# insert a :& expression only if p has been seen before
function compile_lhs(p::PatVar, seen)
	if p.name ∉ seen
		push!(seen, p.name)
		return dollar(p.name)
	else
		return dollar(amp(p.name))
	end
end

function compile_lhs(p::PatLiteral{T}, seen) where T
	p.val
end
compile_lhs(p::PatTypeAssertion, seen) =
	dollar(Expr(:(::), p.var.name, p.type))
compile_lhs(p::PatSplatVar, seen) =
	dollar(Expr(:(...), p.var.name))

function compile_lhs(p::PatTerm, seen)
	cargs = map(x -> compile_lhs(x, seen), p.args)
	Expr(p.head, cargs...)
end

compile_rhs(p::PatVar) = dollar(p.name)
function compile_rhs(p::PatLiteral{T}) where T
    p.val
end
compile_rhs(p::PatTypeAssertion) =
	dollar(Expr(:(::), p.var.name, p.type))
compile_rhs(p::PatSplatVar) =
	dollar(Expr(:(...), p.var.name))

function compile_rhs(p::PatTerm)
	cargs =  map(x -> compile_rhs(x), p.args)
	Expr(p.head, cargs...)
end

# Compile rules from Metatheory format to MatchCore format
function compile_rule(rule::EqualityRule)
	error("equational rules not yet supported by classic rewriting backend." *
			"Knuth-Bendix completion algorithm has not yet been implemented.")
end

function compile_rule(rule::UnequalRule)
	error("inequality anti-rules are only available for the egraphs backend.")
end

function compile_rule(rule::RewriteRule)
	seen = Symbol[]
	lhs = Meta.quot(compile_lhs(rule.left, seen))
	rhs = Meta.quot(compile_rhs(rule.right))
	return :($lhs => $rhs)
end

function compile_rule(rule::DynamicRule)
	seen = Symbol[]
	lhs = Meta.quot(compile_lhs(rule.left, seen))
	rhs = quote
		# FIXME
		# _lhs_expr = $(Meta.quot(lhs));
		$(rule.right)
	end

	return :($lhs => $rhs)
end

# catch-all for reductions
const identity_axiom = :($(quot(dollar(:i))) => i)

# TODO analyse theory before compiling. Identify associativity and commutativity
# and other loop-creating problems. Generate a pattern matching block with the
# correct rule order and expansions for associativity and distributivity
# import Iterators: flatten. Knuth-Bendix completion??

function theory_block(t::Vector{<:AbstractRule})
	tn = Vector{Expr}()

	for r ∈ t
		push!(tn, compile_rule(r))
	end

	block(tn..., identity_axiom)
end

"""
Compile a theory to a closure that does the pattern matching job
Returns a RuntimeGeneratedFunction, which does not use eval and
is as fast as a regular Julia anonymous function 🔥
"""
function compile_theory(theory::Vector{<:AbstractRule}, mod::Module; __source__=LineNumberNode(0))
    # generate an unique parameter name
    parameter = Meta.gensym(:reducing_expression)
    block = theory_block(theory)

	# println(block)
	# dump(block; maxdepth=12)
    matching = MatchCore.gen_match(parameter, block, __source__, mod)
    matching = MatchCore.AbstractPatterns.init_cfg(matching)

    ex = :(($parameter) -> $matching)
    closure_generator(mod, ex)
end

"""
Compile a theory at runtime to a closure that does the pattern matching job
"""
macro compile_theory(theory)
    gettheory(theory, __module__)
end

const MATCHCORE_FUNCTION_CACHE = IdDict{Vector{<:AbstractRule}, Function}()
const MATCHCORE_FUNCTION_CACHE_LOCK = ReentrantLock()

function gettheoryfun(t::Vector{<:AbstractRule}, m::Module)
    lock(MATCHCORE_FUNCTION_CACHE_LOCK) do
        if !haskey(MATCHCORE_FUNCTION_CACHE, t)
            z = compile_theory(t, m)
            MATCHCORE_FUNCTION_CACHE[t] = z
        end
        return MATCHCORE_FUNCTION_CACHE[t]
    end
end

# Retrieve a theory from a module at compile time. Not exported
function gettheory(var, mod; compile=true)
	t = nothing
    if Meta.isexpr(var, :block) # @matcher begine rules... end
		t = rmlines(macroexpand(mod, var)).args .|> Rule
	else
		t = mod.eval(var)
	end

	if compile && !(t isa Function)
		t = gettheoryfun(t, mod)
	end

	return t
end


text: run(`sudo ./build.sh`)

ext: jl


text:
using HetaSimulator, Plots

model = load_jlmodel("../../dist/julia/model.jl")

res = sim(model; tspan = (0,1700))

@info "Creating plots..."

plotd = plot(res; vars = [:IR_apo], yscale=:log10)
savefig(plotd, "./diagnostics/julia/default-hetasimulator-IR_apo.png")

plotd = plot(res; vars = [:COV_num_sputum_ml], yscale=:log10, ylims=(1e1,1e8))
savefig(plotd, "./diagnostics/julia/default-hetasimulator-COV_num_sputum_ml.png")

@info "OK."


text:
haversine(lat1, lon1, lat2, lon2) =
    2 * 6372.8 * asin(sqrt(sind((lat2 - lat1) / 2) ^ 2 +
    cosd(lat1) * cosd(lat2) * sind((lon2 - lon1) / 2) ^ 2))

@show haversine(36.12, -86.67, 33.94, -118.4)

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
"""
```jldoctest
julia> parse(Rational{Int}, "1/4")
1//4
julia> parse(Rational, "1//4")
1//4
```
"""
function Base.parse(::Type{Rational{T}}, x::AbstractString) where {T <: Integer}
    ms, ns = split(x, '/', keepempty = false)
    m = parse(T, ms)
    n = parse(T, ns)
    return m // n
end

Base.parse(::Type{Rational}, x::AbstractString) = parse(Rational{Int32}, x)

"""
    get_ratio(x::AbstractString)

Parse x as either a Float64 or a Rational and return a Float64 ratio.

```jldoctest
julia> get_ratio("1/4")
0.25
julia> get_ratio("0.5")
0.5
```
"""
function get_ratio(x::AbstractString)
    r = tryparse(Float64, x)
    return r === nothing ? convert(Float64, parse(Rational, x)) : r
end

"""
    get_ratio(x::Float64)

For Float64, simply returns x.

```jldoctest
julia> get_ratio(0.8)
0.8
```
"""
get_ratio(x::Float64) = x


text:
module Mux

export mux, stack, branch

using Base64: stringmime

# This might be the smallest core ever.

mux(f) = f
mux(m, f) = x -> m(f, x)
mux(ms...) = foldr(mux, ms)

stack(m) = m
stack(m, n) = (f, x) -> m(mux(n, f), x)
stack(ms...) = foldl(stack, ms)

branch(p, t) = (f, x) -> (p(x) ? t : f)(x)
branch(p, t...) = branch(p, mux(t...))

# May as well provide a few conveniences, though.

using Hiccup

include("lazy.jl")
include("server.jl")
include("basics.jl")
include("routing.jl")

include("websockets_integration.jl")

include("examples/mimetypes.jl")
include("examples/basic.jl")
include("examples/files.jl")

defaults = stack(todict, basiccatch, splitquery, toresponse, assetserver, pkgfiles)
wdefaults = stack(todict, wcatch, splitquery)
prod_defaults = stack(todict, stderrcatch, splitquery, toresponse, assetserver, pkgfiles)

end


text:
module M

import Base: show, +, getindex, convert, length, ==
export @m_str, MString

const INLINE_SIZE=8

type MString <: AbstractString
    kind::DataType

    # Depedenent
    backing::MString
    offset::Int
    length::Int

    # Fixed
    data::Vector{UInt8}

    # Rope
    left::MString
    right::MString

    # Extensible
    pointer::Int

    # Inline
    inline::NTuple{INLINE_SIZE, UInt8}

    function MString{N}(s::NTuple{N, UInt8})
        N > INLINE_SIZE && error("Tuple too big ($N vs $INLINE_SIZE)")
        m = new()
        m.kind = InlineString
        m.length = N
        d = zeros(UInt8, INLINE_SIZE)
        d[1:N] = [s...]
        m.inline = (d...)
        m
    end

    function MString(s::ByteString)
        if length(s) ≤ INLINE_SIZE
            return MString((s.data...))
        end
        get(ATOMS, hash(s.data)) do
            m = new()
            m.kind = FixedString
            m.data = s.data
            m
        end
    end

    MString() = new()
end

MString(s::AbstractString) = MString(utf8(s))

const ATOMS = Dict{UInt64, MString}()

macro m_str(s)
    get!(ATOMS, hash(s.data)) do
        m = MString(s)
        if m.kind == InlineString
            m.kind = InlineAtomString
        else
            m.kind = AtomString
        end
        m
    end
end

abstract BaseString
abstract LinearString <:BaseString
abstract RopeString <: BaseString
abstract DependentString <: LinearString
abstract FlatString <: LinearString
abstract FixedString <: FlatString
abstract ExtensibleString <: FlatString
abstract AtomString <: FixedString
abstract InlineString <: FixedString
abstract InlineAtomString <: InlineString
typealias IsAtom Union{InlineAtomString, AtomString}

show(io::IO, m::MString) = show(io, m, m.kind)

show{T<:FlatString}(io, m, ::Type{T}) = show(io, utf8(m))

function show(io, m, ::Type{DependentString})
    print(io, "Dependent ($(m.offset), $(m.length)) of ")
    show(io, m.backing)
end

convert(::Type{UTF8String}, m::MString) = convert(UTF8String, m, m.kind)

function convert{T<:BaseString}(::Type{UTF8String}, m, ::Type{T})
    ensureflat(m)
    convert(UTF8String, m)
end

convert{T<:FixedString}(::Type{UTF8String}, m, ::Type{T}) = utf8(asarray(m, T))

ensureflat(m::MString) = ensureflat(m, m.kind)

ensureflat{T<:FlatString}(m, ::Type{T}) = m

function ensureflat(m, ::Type{DependentString})
    backing, offset, length = m.backing, m.offset, m.length
    while backing.kind == DependentString
        if length > backing.length
            error("Too long")
        end
        offset += backing.offset
        backing = backing.backing
    end
    ensureflat(backing)
    m.data = backing.data[(offset+1):(offset+length)]
    m.kind = FixedString
    m
end

function buffersize(n)
    exp = floor(Int, log2(n)) + 1
    2^exp
end

length(m::MString) = length(m, m.kind)::Int

length(m::MString, ::Type{RopeString}) = length(m.left) + length(m.right)
length{T<:FixedString}(m::MString, ::Type{T}) = length(m.data)
length(m::MString, ::Type{ExtensibleString}) = m.pointer
length(m::MString, ::Type{DependentString}) = m.length
length{T<:InlineString}(m::MString, ::Type{T}) = m.length
length(m::MString, ::Type{RopeString}) = m.length + length(m.right)

function ensureflat(m, ::Type{RopeString})
    ensureflat(m.left)
    ensureflat(m.right)
    ll = length(m.left)
    lr = length(m.right)
    outlength = ll + lr
    if m.left.kind == ExtensibleString && length(m.left.data) > outlength
        m.data = m.left.data
        unsafe_copy!(m.data, ll+1, m.right.data, 1, lr)
        m.pointer = outlength
    else
        m.data = Vector{UInt8}(buffersize(outlength))
        info("Resized to $(length(m.data))")
        unsafe_copy!(m.data, 1, m.left.data, 1, ll)
        unsafe_copy!(m.data, ll+1, m.right.data, 1, lr)
        m.pointer = outlength
    end
    m.kind = ExtensibleString
    m
end

function +(left::MString, right::MString)
    m = MString()
    m.kind = RopeString
    m.left, m.right = left, right
    m.length = length(m.left)
    m
end

+(left::MString, right) = left + MString(right)
+(left, right::MString) = MString(left) + right

function show(io, m, ::Type{RopeString})
    print(io, "Rope(")
    show(io, m.left)
    print(io, ", ")
    show(io, m.right)
    print(io, ")")
end

function getindex(backing::MString, r::UnitRange{Int})
    offset = r.start-1
    length = r.stop - r.start + 1
    m = MString()
    m.kind = DependentString
    m.backing, m.offset, m.length = backing, offset, length
    m
end

getindex(m::MString, idx::Int) = getindex(m, m.kind, idx)::Char
getindex{T<:FlatString}(m, ::Type{T}, idx) = Char(m.data[idx])
getindex{T<:InlineString}(m, ::Type{T}, idx) = Char(m.inline[idx])
function getindex{T<:RopeString}(m, ::Type{T}, idx)
    if idx ≤ m.length
        m.left[idx]
    else
        m.right[idx - m.length]
    end
end
function getindex{T<:DependentString}(m, ::Type{T}, idx)
    m.backing[idx + m.offset]
end

asarray{T<:FixedString}(m, ::Type{T}) = m.data
asarray(m, ::Type{ExtensibleString}) = slice(m.data, 1:m.pointer)
asarray{T<:InlineString}(m, ::Type{T}) = [m.inline[1:m.length]...]

==(left::MString, right::MString) = ==(left, right, left.kind, right.kind)
==(left::MString, right::AbstractString) = left==MString(right)
==(left::AbstractString, right::MString) = MString(left)==right

=={T<:IsAtom, G<:IsAtom}(left, right, ::Type{T}, ::Type{G}) = left===right
=={T<:InlineString, G<:InlineString}(left, right, ::Type{T}, ::Type{G}) = left.inline == right.inline && left.length == right.length

function =={T<:FlatString, G<:InlineString}(left, right, ::Type{G}, ::Type{T})
    N = length(left, InlineString)
    N == length(right, T) || return false
    for i=1:N
        left.inline[i] == right.data[i] || return false
    end
    true
end

=={T<:FlatString, G<:InlineString}(left, right, ::Type{T}, ::Type{G}) = right==left

function =={T<:FlatString, G<:FlatString}(left, right, ::Type{T}, ::Type{G})
    asarray(left, T) == asarray(right, G)
end

function Base.match(r::Regex, m::MString, offset=0)
    match(r, utf8(m), offset)
end

end


text:
#

# Use module instead of baremodule to support document
module Status
"Found end of archive"
const EOF = Cint(1)
"Operation was successful"
const OK = Cint(0)
"Retry might succeed"
const RETRY = Cint(-10)
"Partial success"
const WARN = Cint(-20)
"Current operation cannot complete"
const FAILED = Cint(-25)
"No more operations are possible"
const FATAL = Cint(-30)
end

module FilterType
const NONE = Cint(0)
const GZIP = Cint(1)
const BZIP2 = Cint(2)
const COMPRESS = Cint(3)
const PROGRAM = Cint(4)
const LZMA = Cint(5)
const XZ = Cint(6)
const UU = Cint(7)
const RPM = Cint(8)
const LZIP = Cint(9)
const LRZIP = Cint(10)
const LZOP = Cint(11)
const GRZIP = Cint(12)
const LZ4 = Cint(14)
const ZSTD = Cint(15)
end

# Codes returned by archive_format.
#
# Top 16 bits identifies the format family (e.g., "tar"); lower
# 16 bits indicate the variant.  This is updated by read_next_header.
# Note that the lower 16 bits will often vary from entry to entry.
# In some cases, this variation occurs as libarchive learns more about
# the archive (for example, later entries might utilize extensions that
# weren't necessary earlier in the archive; in this case, libarchive
# will change the format code to indicate the extended format that
# was used).  In other cases, it's because different tools have
# modified the archive and so different parts of the archive
# actually have slightly different formats.  (Both tar and cpio store
# format codes in each entry, so it is quite possible for each
# entry to be in a different format.)
module Format
const BASE_MASK = Cint(0xff0000)
const CPIO = Cint(0x10000)
const CPIO_POSIX = Cint(CPIO | 1)
const CPIO_BIN_LE = Cint(CPIO | 2)
const CPIO_BIN_BE = Cint(CPIO | 3)
const CPIO_SVR4_NOCRC = Cint(CPIO | 4)
const CPIO_SVR4_CRC = Cint(CPIO | 5)
const CPIO_AFIO_LARGE = Cint(CPIO | 6)
const SHAR = Cint(0x20000)
const SHAR_BASE = Cint(SHAR | 1)
const SHAR_DUMP = Cint(SHAR | 2)
const TAR = Cint(0x30000)
const TAR_USTAR = Cint(TAR | 1)
const TAR_PAX_INTERCHANGE = Cint(TAR | 2)
const TAR_PAX_RESTRICTED = Cint(TAR | 3)
const TAR_GNUTAR = Cint(TAR | 4)
const ISO9660 = Cint(0x40000)
const ISO9660_ROCKRIDGE = Cint(ISO9660 | 1)
const ZIP = Cint(0x50000)
const EMPTY = Cint(0x60000)
const AR = Cint(0x70000)
const AR_GNU = Cint(AR | 1)
const AR_BSD = Cint(AR | 2)
const MTREE = Cint(0x80000)
const RAW = Cint(0x90000)
const XAR = Cint(0xA0000)
const LHA = Cint(0xB0000)
const CAB = Cint(0xC0000)
const RAR = Cint(0xD0000)
const _7ZIP = Cint(0xE0000)
const WARC = Cint(0xF0000)
const RAR_V5 = Cint(0x100000)
end

# Codes returned by format_capabilities(::Reader).
#
# This list can be extended with values between 0 and 0xffff.
# The original purpose of this list was to let different archive
# format readers expose their general capabilities in terms of
# encryption.
module ReadFormatCaps
"no special capabilities"
const NONE = Cint(0)
"reader can detect encrypted data"
const ENCRYPT_DATA = Cint(1 << 0)
"reader can detect encryptable metadata (pathname, mtime, etc.)"
const ENCRYPT_METADATA = Cint(1 << 1)
end

# Codes returned by archive_read_has_encrypted_entries().
#
# In case the archive does not support encryption detection at all
# ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. If the reader
# for some other reason (e.g. not enough bytes read) cannot say if
# there are encrypted entries, ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW
# is returned.
module ReadFormatEncryption
const UNSUPPORTED = Cint(-2)
const DONT_KNOW = Cint(-1)
end

module ExtractFlag
"Default: Do not try to set owner/group."
const OWNER = Cint(0x0001)
"Default: Do obey umask, do not restore SUID/SGID/SVTX bits."
const PERM = Cint(0x0002)
"Default: Do not restore mtime/atime."
const TIME = Cint(0x0004)
"Default: Replace existing files."
const NO_OVERWRITE = Cint(0x0008)
"Default: Try create first, unlink only if create fails with EEXIST."
const UNLINK = Cint(0x0010)
"Default: Do not restore ACLs."
const ACL = Cint(0x0020)
"Default: Do not restore fflags."
const FFLAGS = Cint(0x0040)
"Default: Do not restore xattrs."
const XATTR = Cint(0x0080)
"""
Default: Do not try to guard against extracts redirected by symlinks.
Note: With UNLINK, will remove any intermediate symlink.
"""
const SECURE_SYMLINKS = Cint(0x0100)
"Default: Do not reject entries with '..' as path elements."
const SECURE_NODOTDOT = Cint(0x0200)
"Default: Create parent directories as needed."
const NO_AUTODIR = Cint(0x0400)
"Default: Overwrite files, even if one on disk is newer."
const NO_OVERWRITE_NEWER = Cint(0x0800)
"Detect blocks of 0 and write holes instead."
const SPARSE = Cint(0x1000)
"""
Default: Do not restore Mac extended metadata.
This has no effect except on Mac OS.
"""
const MAC_METADATA = Cint(0x2000)
"""
Default: Use HFS+ compression if it was compressed.
This has no effect except on Mac OS v10.6 or later.
"""
const NO_HFS_COMPRESSION = Cint(0x4000)
"""
Default: Do not use HFS+ compression if it was not compressed.
This has no effect except on Mac OS v10.6 or later.
"""
const HFS_COMPRESSION_FORCED = Cint(0x8000)
"Default: Do not reject entries with absolute paths"
const SECURE_NOABSOLUTEPATHS = Cint(0x10000)
"Default: Do not clear no-change flags when unlinking object"
const CLEAR_NOCHANGE_FFLAGS = Cint(0x20000)
"Default: Do not extract atomically (using rename)"
const SAFE_WRITES = Cint(0x40000)
end

module ReadDiskFlag
"""
Request that the access time of the entry visited by travesal be restored.
This is the same as archive_read_disk_set_atime_restored.
"""
const RESTORE_ATIME = Cint(0x0001)
"Default: Do not skip an entry which has nodump flags."
const HONOR_NODUMP = Cint(0x0002)
"""
Default: Skip a mac resource fork file whose prefix is "._" because of
using copyfile.
"""
const MAC_COPYFILE = Cint(0x0004)
"Default: Do not traverse mount points."
const NO_TRAVERSE_MOUNTS = Cint(0x0008)
"Default: Xattrs are read from disk."
const NO_XATTR = Cint(0x0010)
"Default: ACLs are read from disk."
const NO_ACL = Cint(0x0020)
"Default: File flags are read from disk."
const NO_FFLAGS = Cint(0x0040)
end

"""
Flags to tell a matching type of time stamps. These are used for
following functinos.
"""
module MatchFlag
"Time flag: mtime to be tested"
const MTIME = Cint(0x0100)
"Time flag: ctime to be tested"
const CTIME = Cint(0x0200)
"Comparison flag: Match the time if it is newer than"
const NEWER = Cint(0x0001)
"Comparison flag: Match the time if it is older than"
const OLDER = Cint(0x0002)
"Comparison flag: Match the time if it is equal to"
const EQUAL = Cint(0x0010)
end

module FileType
const MT = Cint(0o170000)
const REG = Cint(0o100000)
const LNK = Cint(0o120000)
const SOCK = Cint(0o140000)
const CHR = Cint(0o020000)
const BLK = Cint(0o060000)
const DIR = Cint(0o040000)
const IFO = Cint(0o010000)
const FIFO = IFO
end

module SymlinkType
const UNDEFINED = Cint(0)
const FILE = Cint(1)
const DIRECTORY = Cint(2)
end

module ACL
# Permission bits.

const EXECUTE = Cint(0x00000001)
const WRITE = Cint(0x00000002)
const READ = Cint(0x00000004)
const READ_DATA = Cint(0x00000008)
const LIST_DIRECTORY = Cint(0x00000008)
const WRITE_DATA = Cint(0x00000010)
const ADD_FILE = Cint(0x00000010)
const APPEND_DATA = Cint(0x00000020)
const ADD_SUBDIRECTORY = Cint(0x00000020)
const READ_NAMED_ATTRS = Cint(0x00000040)
const WRITE_NAMED_ATTRS = Cint(0x00000080)
const DELETE_CHILD = Cint(0x00000100)
const READ_ATTRIBUTES = Cint(0x00000200)
const WRITE_ATTRIBUTES = Cint(0x00000400)
const DELETE = Cint(0x00000800)
const READ_ACL = Cint(0x00001000)
const WRITE_ACL = Cint(0x00002000)
const WRITE_OWNER = Cint(0x00004000)
const SYNCHRONIZE = Cint(0x00008000)

const PERMS_POSIX1E = EXECUTE | WRITE | READ
const PERMS_NFS4 = (EXECUTE | READ_DATA | LIST_DIRECTORY | WRITE_DATA |
                    ADD_FILE | APPEND_DATA | ADD_SUBDIRECTORY |
                    READ_NAMED_ATTRS | WRITE_NAMED_ATTRS | DELETE_CHILD |
                    READ_ATTRIBUTES | WRITE_ATTRIBUTES | DELETE | READ_ACL |
                    WRITE_ACL | WRITE_OWNER | SYNCHRONIZE)

# Inheritance values (NFS4 ACLs only); included in permset.
const INHERITED = Cint(0x01000000)
const FILE_INHERIT = Cint(0x02000000)
const DIRECTORY_INHERIT = Cint(0x04000000)
const NO_PROPAGATE_INHERIT = Cint(0x08000000)
const INHERIT_ONLY = Cint(0x10000000)
const SUCCESSFUL_ACCESS = Cint(0x20000000)
const FAILED_ACCESS = Cint(0x40000000)

const INHERITANCE_NFS4 = (INHERITED | FILE_INHERIT | DIRECTORY_INHERIT |
                          NO_PROPAGATE_INHERIT | INHERIT_ONLY |
                          SUCCESSFUL_ACCESS | FAILED_ACCESS)

module Type
# We need to be able to specify combinations of these.
const ACCESS = Cint(0x00000100)  # POSIX.1e only
const DEFAULT = Cint(0x00000200) # POSIX.1e only
const ALLOW = Cint(0x00000400) # NFS4 only
const DENY = Cint(0x00000800) # NFS4 only
const AUDIT = Cint(0x00001000) # NFS4 only
const ALARM = Cint(0x00002000) # NFS4 only
const POSIX1E = (ACCESS | DEFAULT)
const NFS4 = (ALLOW | DENY | AUDIT | ALARM)
end

# Tag values mimic POSIX.1e
"Specified user."
const USER = Cint(10001)
"User who owns the file."
const USER_OBJ = Cint(10002)
"Specified group."
const GROUP = Cint(10003)
"Group who owns the file."
const GROUP_OBJ = Cint(10004)
"Modify group access (POSIX.1e only)"
const MASK = Cint(10005)
"Public (POSIX.1e only)"
const OTHER = Cint(10006)
"Everyone (NFS4 only)"
const EVERYONE = Cint(10107)

module Style
const EXTRA_ID = Cint(0x00000001)
const MARK_DEFAULT = Cint(0x00000002)
const SOLARIS = Cint(0x00000004)
const SEPARATOR_COMMA = Cint(0x00000008)
const COMPACT = Cint(0x00000010)
end
end


text:
module XXZNumerics

using LinearAlgebra
using SparseArrays
import Optim, LineSearches

# Write your package code here.

include("geometry.jl")
include("interaction.jl")
include("spin_half.jl")
include("entropy.jl")
include("hamiltonian.jl")
include("thermalization.jl")

end


text:
using Knet

Pkg.test("Knet")
load_only = true

for (p,f,o1,o2,o3) =
    (
     (:LinReg, "linreg.jl", "--gcheck 2", "--fast", "--fast"),
     (:Housing, "housing.jl", "--gcheck 2 --atype Array{Float64}", "--fast", "--fast"),
     (:MNIST, "mnist.jl", "--gcheck 2", "--fast", "--fast"),
     (:LeNet, "lenet.jl", "--gcheck 2", "--fast", "--fast"),
     (:CharLM, "charlm.jl", "--gcheck 2 --winit 0.01", "--fast", "--fast"),
    )
    gpu() < 0 && p == :LeNet && continue
    include(f)
    m = eval(:($p.main))
    m(o1); m(o2); m(o3)
    gc(); gpu() >= 0 && Knet.knetgc()
end


text:
using Test
using MinimalRLCore
using Random

mutable struct TestEnv <: MinimalRLCore.AbstractEnvironment
    name::String
    size::Int
    state::Float64
    rew::Float64
    TestEnv(name, size) = new(name, size, 0.0, 0.0)
end

name(t::TestEnv) = t.name

MinimalRLCore.get_state(env::TestEnv) = env.state
MinimalRLCore.get_reward(env::TestEnv) = env.rew
MinimalRLCore.get_actions(env::TestEnv) = (1, 2)
MinimalRLCore.is_terminal(env::TestEnv) = false

MinimalRLCore.reset!(env::TestEnv, rng::Random.AbstractRNG=Random.GLOBAL_RNG) =
    env.state = rand(rng) * env.size

MinimalRLCore.reset!(env::TestEnv, state::Number) =
    env.state = state

MinimalRLCore.environment_step!(env::TestEnv, action, rng::AbstractRNG=Random.GLOBAL_RNG) =
    env.rew = action*env.state

function test_env()
    Random.seed!(10)
    expected_state = 0.5629122239323647
    @testset "TestEnv Global RNG" begin
        env = TestEnv("Matt", 5)
        @test start!(env) ≈ expected_state
        @test all(step!(env, 1) .≈ (expected_state, 1*expected_state, false))
        @test all(step!(env, 2) .≈ (expected_state, 2*expected_state, false))
        @test all(MinimalRLCore.get_actions(env) .== (1,2))
    end

    rng = MersenneTwister(10)
    @testset "TestEnv Managed RNG" begin
        env = TestEnv("Matt", 5)
        @test start!(env, rng) ≈ expected_state
        @test all(step!(env, 1, rng) .≈ (expected_state, 1*expected_state, false))
        @test all(step!(env, 2, rng) .≈ (expected_state, 2*expected_state, false))
        @test all(MinimalRLCore.get_actions(env) .== (1,2))
    end

    Random.seed!(10)
    expected_state = rand()
    @testset "TestEnv deterministic state restart" begin
        env = TestEnv("Matt", 5)
        @test start!(env, expected_state) ≈ expected_state
        @test all(step!(env, 1, rng) .≈ (expected_state, 1*expected_state, false))
        @test all(step!(env, 2, rng) .≈ (expected_state, 2*expected_state, false))
        @test all(MinimalRLCore.get_actions(env) .== (1,2))
    end
end


text:
module Defaults

export handler_cached,
    mandatory

using Discord
using Discord: logkws, withsem
using Setfield

function mandatory(c::Client, e::Ready)
    @info "Logged in as $(e.user.username)" logkws(c)...

    c.state.v = e.v
    c.state.session_id = e.session_id
    c.state._trace = e._trace
    c.state.user = e.user

    c.use_cache || return

    foreach(ch -> put!(c.state, ch), e.private_channels)
    for  g in e.guilds
        # Don't use put! normally here because these guilds are unavailable.
        if !haskey(c.state.guilds, g.id)
            c.state.guilds[g.id] = g
        end
    end
end
mandatory(c::Client, e::Resumed) = c.state._trace = e._trace

handler(c::Client, e::Union{ChannelCreate, ChannelUpdate}) = put!(c.state, e.channel)
handler(c::Client, e::Union{GuildCreate, GuildUpdate}) = put!(c.state, e.guild)
handler(c::Client, e::GuildEmojisUpdate) = put!(c.state, e.emojis; guild=e.guild_id)
handler(c::Client, e::GuildMemberAdd) = put!(c.state, e.member; guild=e.guild_id)
handler(c::Client, e::GuildMembersChunk) = put!(c.state, e.members; guild=e.guild_id)
handler(c::Client, e::Union{MessageCreate, MessageUpdate}) = put!(c.state, e.message)
handler(c::Client, e::PresenceUpdate) = put!(c.state, e.presence)
handler(c::Client, e::UserUpdate) = put!(c.state, e.user)

function handler(c::Client, e::ChannelPinsUpdate)
    haskey(c.state.channels, e.channel_id) || return

    ch = c.state.channels[e.channel_id]

    if !ismissing(e.last_pin_timestamp)
        c.state.channels[ch.id] = @set ch.last_pin_timestamp = e.last_pin_timestamp
    end
end

function handler(c::Client, e::Union{GuildIntegrationsUpdate, GuildBanRemove})
    touch(c.state.guilds, e.guild_id)
end

function handler(c::Client, e::MessageDelete)
    delete!(c.state.messages, e.id)
    touch(c.state.channels, e.channel_id)
    touch(c.state.guilds, e.guild_id)
end

function handler(c::Client, e::ChannelDelete)
    delete!(c.state.channels, e.channel.id)

    if !ismissing(e.channel.guild_id) && haskey(c.state.guilds, e.channel.guild_id)
        delete!(c.state.guilds[e.channel.guild_id], e.channel.id)
    end
end

function handler(c::Client, e::GuildDelete)
    delete!(c.state.guilds, e.guild.id)
    delete!(c.state.members, e.guild.id)
    delete!(c.state.presences, e.guild.id)

    if e.guild isa Guild && !ismissing(e.guild.channels)
        for channel in map(ch -> ch.id, e.guild.channels)
            delete!(c.state.channels, channel)
        end
    end
end

function handler(c::Client, e::GuildMemberUpdate)
    if haskey(c.state.guilds, e.guild_id)
        g = c.state.guilds[e.guild_id]
        g isa Guild && push!(g.djl_users, e.user.id)
    end

    haskey(c.state.members, e.guild_id) || return
    haskey(c.state.members[e.guild_id], e.user.id) || return

    ms = c.state.members[e.guild_id]
    m = ms[e.user.id]
    m = @set m.nick = e.nick
    m = @set m.roles = e.roles
    ms[e.user.id] = m

    put!(c.state, e.user)
end

function handler(c::Client, e::GuildMemberRemove)
    ismissing(e.user) && return

    if haskey(c.state.members, e.guild_id)
        delete!(c.state.members[e.guild_id], e.user.id)
    end

    if haskey(c.state.guilds, e.guild_id)
        delete!(c.state.guilds[e.guild_id].djl_users, e.user.id)
    end
end

function handler(c::Client, e::Union{GuildRoleCreate, GuildRoleUpdate})
    put!(c.state, e.role; guild=e.guild_id)
end

function handler(c::Client, e::GuildRoleDelete)
    haskey(c.state.guilds, e.guild_id) || return
    c.state.guilds[e.guild_id] isa Guild || return

    rs = c.state.guilds[e.guild_id].roles
    ismissing(rs) && return

    idx = findfirst(r -> r.id == e.role_id, rs)
    idx === nothing || deleteat!(rs, idx)
end

function handler(c::Client, e::MessageDeleteBulk)
    foreach(id -> delete!(c.state.messages, id), e.ids)
    touch(c.state.channels, e.channel_id)
    touch(c.state.channels, e.guild_id)
end

function handler(c::Client, e::MessageReactionAdd)
    put!(c.state, e.emoji; message=e.message_id, user=e.user_id)
    touch(c.state.channels, e.channel_id)
    touch(c.state.guilds, e.guild_id)
    touch(c.state.users, e.user_id)
    haskey(c.state.members, e.guild_id) && touch(c.state.members[e.guild_id], e.user_id)
end

function handler(c::Client, e::MessageReactionRemove)
    withsem(c.state.sem) do
        haskey(c.state.messages, e.message_id) || return
        ismissing(c.state.messages[e.message_id].reactions) && return

        rs = c.state.messages[e.message_id].reactions
        idx = findfirst(r -> r.emoji.name == e.emoji.name, rs)

        if idx !== nothing
            if rs[idx].count == 1
                deleteat!(rs, idx)
            else
                r = rs[idx]
                r = @set r.count -= 1
                r = @set r.me &= ismissing(c.state.user) || c.state.user.id != e.user_id
                rs[idx] = r
            end
        end
    end

    touch(c.state.channels, e.channel_id)
    touch(c.state.guilds, e.guild_id)
    touch(c.state.users, e.user_id)
    haskey(c.state.members, e.guild_id) && touch(c.state.members[e.guild_id], e.user_id)
end

function handler(c::Client, e::MessageReactionRemoveAll)
    haskey(c.state.messages, e.message_id) || return
    ismissing(c.state.messages[e.message_id].reactions) && return

    withsem(c.state.sem) do
        empty!(c.state.messages[e.message_id].reactions)
    end

    touch(c.state.channels, e.channel_id)
    touch(c.state.guilds, e.guild_id)
end

function handler(c::Client, e::GuildBanAdd)
    if haskey(c.state.members, e.guild_id)
        delete!(c.state.members[e.guild_id], e.user.id)
    end

    if haskey(c.state.guilds, e.guild_id)
        delete!(c.state.guilds[e.guild_id].djl_users, e.user.id)
    end
end

# For each handler, define an identical method for handler_cached
# which only runs when the client has its cache enabled.
for T in map(m -> m.sig.types[3], methods(handler))
    @eval handler_cached(c::Client, e::$T) = c.use_cache && handler(c, e)
end

end


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

@doc raw"""DaemonSet represents the configuration of a daemon set.

    IoK8sApiAppsV1DaemonSet(;
        apiVersion=nothing,
        kind=nothing,
        metadata=nothing,
        spec=nothing,
        status=nothing,
    )

    - apiVersion::String : APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
    - kind::String : Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
    - metadata::IoK8sApimachineryPkgApisMetaV1ObjectMeta : Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
    - spec::IoK8sApiAppsV1DaemonSetSpec : The desired behavior of this daemon set. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
    - status::IoK8sApiAppsV1DaemonSetStatus : The current status of this daemon set. This data may be out of date by some window of time. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
"""
mutable struct IoK8sApiAppsV1DaemonSet <: SwaggerModel
    apiVersion::Any # spec type: Union{ Nothing, String } # spec name: apiVersion
    kind::Any # spec type: Union{ Nothing, String } # spec name: kind
    metadata::Any # spec type: Union{ Nothing, IoK8sApimachineryPkgApisMetaV1ObjectMeta } # spec name: metadata
    spec::Any # spec type: Union{ Nothing, IoK8sApiAppsV1DaemonSetSpec } # spec name: spec
    status::Any # spec type: Union{ Nothing, IoK8sApiAppsV1DaemonSetStatus } # spec name: status

    function IoK8sApiAppsV1DaemonSet(;apiVersion=nothing, kind=nothing, metadata=nothing, spec=nothing, status=nothing)
        o = new()
        validate_property(IoK8sApiAppsV1DaemonSet, Symbol("apiVersion"), apiVersion)
        setfield!(o, Symbol("apiVersion"), apiVersion)
        validate_property(IoK8sApiAppsV1DaemonSet, Symbol("kind"), kind)
        setfield!(o, Symbol("kind"), kind)
        validate_property(IoK8sApiAppsV1DaemonSet, Symbol("metadata"), metadata)
        setfield!(o, Symbol("metadata"), metadata)
        validate_property(IoK8sApiAppsV1DaemonSet, Symbol("spec"), spec)
        setfield!(o, Symbol("spec"), spec)
        validate_property(IoK8sApiAppsV1DaemonSet, Symbol("status"), status)
        setfield!(o, Symbol("status"), status)
        o
    end
end # type IoK8sApiAppsV1DaemonSet

const _property_map_IoK8sApiAppsV1DaemonSet = Dict{Symbol,Symbol}(Symbol("apiVersion")=>Symbol("apiVersion"), Symbol("kind")=>Symbol("kind"), Symbol("metadata")=>Symbol("metadata"), Symbol("spec")=>Symbol("spec"), Symbol("status")=>Symbol("status"))
const _property_types_IoK8sApiAppsV1DaemonSet = Dict{Symbol,String}(Symbol("apiVersion")=>"String", Symbol("kind")=>"String", Symbol("metadata")=>"IoK8sApimachineryPkgApisMetaV1ObjectMeta", Symbol("spec")=>"IoK8sApiAppsV1DaemonSetSpec", Symbol("status")=>"IoK8sApiAppsV1DaemonSetStatus")
Base.propertynames(::Type{ IoK8sApiAppsV1DaemonSet }) = collect(keys(_property_map_IoK8sApiAppsV1DaemonSet))
Swagger.property_type(::Type{ IoK8sApiAppsV1DaemonSet }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_IoK8sApiAppsV1DaemonSet[name]))}
Swagger.field_name(::Type{ IoK8sApiAppsV1DaemonSet }, property_name::Symbol) =  _property_map_IoK8sApiAppsV1DaemonSet[property_name]

function check_required(o::IoK8sApiAppsV1DaemonSet)
    true
end

function validate_property(::Type{ IoK8sApiAppsV1DaemonSet }, name::Symbol, val)
end


text:
abstract type TotalField end
struct Evanescent  <: TotalField end
struct Propagative <: TotalField end

include("heat_transfer_plane_geometry.jl")


text:
module SymSemiseparableMatrices
using LinearAlgebra

abstract type SymSemiseparableMatrix end
abstract type SymSemiseparableCholesky  <: SymSemiseparableMatrix end

# Must be imported here, as it is relevant before "syntax.jl"
import LinearAlgebra: inv!, tr, mul!
import Base: inv, size, eltype

export SymSemiseparableMatrix,
       SymSemiseparableCholesky

# Properties
include("adjointoperator.jl")

# Matrices
include("matrices/symsep.jl")
include("matrices/symsepchol.jl")
include("matrices/diasymsep.jl")
include("matrices/diasymsepchol.jl")

include("syntax.jl")

# More constructors
SymSemiseparableChol(K::SymSemiseparable) = SymSemiseparableChol(K.n, K.p, K.U, ss_create_w(K.U, K.V))
SymSemiseparable(L::SymSemiseparableChol) = SymSemiseparable(L.n, L.p, L.U, ss_create_v(L.U, L.W))
DiaSymSemiseparable(L::SymSemiseparable, d::AbstractArray) = DiaSymSemiseparable(L.n, L.p, L.U, L.V, d)
function DiaSymSemiseparableChol(L::DiaSymSemiseparable)
      W, dbar = dss_create_wdbar(L.U, L.V, L.d)
      return DiaSymSemiseparableChol(L.n, L.p, L.U, W, dbar)
end
function DiaSymSemiseparable(L::DiaSymSemiseparableChol)
      V, d = dss_create_vd(L.U, L.W, L.ds);
      return DiaSymSemiseparable(L.n, L.p, L.U, V, d)
end

function DiaSymSemiseparableChol(U::AbstractArray, V::AbstractArray, σn, σf)
      n, p = size(U)
      W, dbar = dss_create_wdbar(σf*U, σf*V, ones(n)*σn^2)
      DiaSymSemiseparableChol(n, p, σf*U, W, dbar)
end

# # 2D tensor algorithms
# include("algorithms/tensor_kernel.jl")
# include("operators/tensorkernel.jl")
# include("operators/tensoreigenkernel.jl")

end # module


text:
## test_plot.jl : test plotting commands

## 1D ##
m = Matern(0.75,1,p=1.)
cov = CovarianceFunction(1,m)
pts = 0:0.01:1
grf1 = GaussianRandomField(cov,KarhunenLoeve(500),pts)
plot(grf1,n=10); close()

## 2D ##
e = Exponential(0.01)
cov = CovarianceFunction(2,e)
pts = 0:0.05:1
grf2 = GaussianRandomField(cov,KarhunenLoeve(10),pts,pts)
plot(grf2)
surf(grf2)
contourf(grf2)
contour(grf2)

## 3D ##
m = Exponential(0.5)
cov = CovarianceFunction(3,m)
pts = 0:0.1:1
grf3 = GaussianRandomField(cov,KarhunenLoeve(10),pts,pts,pts)
plot(grf3); close()
plot(grf3,ix=1); close()

## Separable ##
e1 = Exponential(0.1,p=1)
e2 = Exponential(0.01,p=1)
e3 = Exponential(0.001,p=1)
sp1 = SeparableCovarianceFunction(e1)
sp2 = SeparableCovarianceFunction(e1,e2)
sp3 = SeparableCovarianceFunction(e1,e2,e3)
pts = 0:0.01:1
sg1 = GaussianRandomField(sp1,KarhunenLoeve(10),pts)
sg2 = GaussianRandomField(sp2,KarhunenLoeve(10),pts,pts)
sg3 = GaussianRandomField(sp3,KarhunenLoeve(10),pts,pts,pts)

## Eigenvalues/functions ##
plot_eigenvalues(grf1); close()
plot_eigenvalues(grf2); close()
plot_eigenvalues(sg2); close()
plot_eigenfunction(grf1,1); close()
plot_eigenfunction(grf2,1); close()
plot_eigenfunction(grf3,1); close()
plot_eigenfunction(sg1,1); close()
plot_eigenfunction(sg2,1); close()
plot_eigenfunction(sg3,1); close()


text:
using EFIT

function efit(g::GEQDSKFile, cc::Union{Int,COCOS})
    M = efit(cocos(cc), g.r, g.z, g.psi, g.psirz, g.fpol, g.pres,
             g.qpsi, g.fpol*0, (g.rmaxis,g.zmaxis),
             Int(sign(g.bcentr)*sign(g.current)));
    return M
end

function efit(g::GEQDSKFile; clockwise_phi::Bool)
    cc = cocos(g,clockwise_phi=clockwise_phi)
    M = efit(g, cc)
    return M
end

function Wall(g::GEQDSKFile)
    return Wall(collect(zip(g.rlim,g.zlim)))
end

function read_geqdsk(gfile; kwargs...)
    g = readg(gfile)
    return efit(g; kwargs...), Wall(g)
end


text:
using JSON, HTTP

const FIRESTORE_URL = "https://firestore.googleapis.com/v1"

function get_singlepage(documentpath; pagesize = 300, pagetoken::String = "")
    @show "Firestore.get_singlepage", documentpath, pagesize, pagetoken
    base_url = FIRESTORE_URL
    headers = Dict(auth_header())
    project_id = projectid()
    firestore_path = "/projects/$project_id/databases/(default)/documents"
    url = "$base_url$firestore_path/$documentpath"
    query = Dict{String,Any}("pageSize" => pagesize)
    if !isempty(pagetoken)
        query["pageToken"] = pagetoken
    end
    http_response = HTTP.get(url, headers; query = query)
    response_string = String(http_response.body)
    JSON.parse(response_string)
end

function get_collection(documentpath; pagesize = 300)
    @show "Firestore.get_collection", documentpath, pagesize
    docs = []
    pagetoken = ""
    while true
        response = get_singlepage(
            documentpath,
            pagesize = pagesize,
            pagetoken = pagetoken,
        )
        isempty(response) && return docs
        push!(docs, response["documents"]...)
        !haskey(response, "nextPageToken") && break
        pagetoken = response["nextPageToken"]
    end
    docs
end

get_document(documentpath) = get_singlepage(documentpath)


text:
function test_install()
    install(TEST_CONFIG, v"0.4.0"; labels=["julia-bin", "julia-stable-bin"])
    install(TEST_CONFIG, v"0.5.0-"; labels=["julia-nightly-bin"])
end

function test_dirinstall()
    dirinstall(
        TEST_CONFIG,
        joinpath(TEST_CONFIG.dir.bin, "julia-nightly-bin");
        labels=["julia-nightly-dir"]
    )
    dirinstall(
        TEST_CONFIG,
        joinpath(TEST_CONFIG.dir.bin, "julia-stable-bin");
        labels=["julia-stable-dir"]
    )
end

test_install()
test_dirinstall()


text:
module PotentialInference

importall BrmlFunctions

# Type definitions:

export Potential, DiscretePotential, ArrayPotential
abstract Potential
abstract DiscretePotential <: Potential
abstract ArrayPotential <: DiscretePotential

# Type Unions:
export DictOrArray
DictOrArray=Union{Dict,Array}

# Variable Types:
export Variable
abstract Variable

export DiscreteVariable
type DiscreteVariable <: Variable
    name
    state
    function DiscreteVariable(varname,varstates)
        new(varname,varstates)
    end
end

# Potential Types

export PotArray
type PotArray <: ArrayPotential
    variables
    content
    function PotArray(variables, content)
        content=standardise(content)
        if length(variables)!= length(mysize(content))
            error("number of variables does not match the size of the potential")
        end
        new(vec(variables),content)
    end
end

export Const
type Const <: Potential
    variables
    content
    function Const(content)
        if !isa(content,Number)
            error("Content must be a numerical scalar")
        end
        new([],content)
    end
end

export PotLogArray
type PotLogArray <: ArrayPotential
    variables
    content
    function PotLogArray(variables, content)
        content=standardise(content)
        if length(variables)!= length(mysize(content))
            error("number of variables does not match the size of the potential")
        end
        new(vec(variables),content)
    end
end

try
    current_path = joinpath((pwd()), "src", "PotentialInference")
    PotentialsPath = joinpath(current_path, "Potentials")
    AlgorithmsPath = joinpath(current_path, "Algorithms")
    include(joinpath(PotentialsPath, "ArrayPotential.jl"))
    include(joinpath(PotentialsPath, "Potential.jl"))
    include(joinpath(PotentialsPath, "PotArray.jl"))
    include(joinpath(PotentialsPath, "PotConst.jl"))
    include(joinpath(PotentialsPath, "PotLogArray.jl"))
    include(joinpath(AlgorithmsPath, "FactorGraph.jl"))
end

end # module


text:
mutable struct FRMJumpAggregation{T,S,F1,F2,RNG} <: AbstractSSAJumpAggregator
  next_jump::Int
  next_jump_time::T
  end_time::T
  cur_rates::Vector{T}
  sum_rate::T
  ma_jumps::S
  rates::F1
  affects!::F2
  save_positions::Tuple{Bool,Bool}
  rng::RNG
end
FRMJumpAggregation(nj, njt, et, crs, sr, maj, rs, affs!, sps, rng; kwargs...) = FRMJumpAggregation(nj, njt, et, crs, sr, maj, rs, affs!, sps, rng)

########### The following routines should be templates for all SSAs ###########

# condition for jump to occur
@inline function (p::FRMJumpAggregation)(u, t, integrator)
  p.next_jump_time == t
end

# executing jump at the next jump time
function (p::FRMJumpAggregation)(integrator)
  execute_jumps!(p, integrator, integrator.u, integrator.p, integrator.t)
  generate_jumps!(p, integrator, integrator.u, integrator.p, integrator.t)
  register_next_jump_time!(integrator, p, integrator.t)
  nothing
end

# setting up a new simulation
function (p::FRMJumpAggregation)(dj, u, t, integrator) # initialize
  initialize!(p, integrator, u, integrator.p, t)
  register_next_jump_time!(integrator, p, t)
  nothing
end

############################# Required Functions #############################

# creating the JumpAggregation structure (tuple-based constant jumps)
function aggregate(aggregator::FRM, u, p, t, end_time, constant_jumps,
                    ma_jumps, save_positions, rng; kwargs...)

  # handle constant jumps using tuples
  rates, affects! = get_jump_info_tuples(constant_jumps)

  build_jump_aggregation(FRMJumpAggregation, u, p, t, end_time, ma_jumps, rates, affects!,
                          save_positions, rng; kwargs...)
end

# creating the JumpAggregation structure (function wrapper-based constant jumps)
function aggregate(aggregator::FRMFW, u, p, t, end_time, constant_jumps,
                    ma_jumps, save_positions, rng; kwargs...)

  # handle constant jumps using function wrappers
  rates, affects! = get_jump_info_fwrappers(u, p, t, constant_jumps)

  build_jump_aggregation(FRMJumpAggregation, u, p, t, end_time, ma_jumps, rates, affects!,
                          save_positions, rng; kwargs...)
end

# set up a new simulation and calculate the first jump / jump time
function initialize!(p::FRMJumpAggregation, integrator, u, params, t)
  generate_jumps!(p, integrator, u, params, t)
  nothing
end

# execute one jump, changing the system state
@inline function execute_jumps!(p::FRMJumpAggregation, integrator, u, params, t)
  num_ma_rates = length(p.ma_jumps.scaled_rates)
  if p.next_jump <= num_ma_rates
      @inbounds executerx!(u, p.ma_jumps.net_stoch[p.next_jump])
  else
      idx = p.next_jump - num_ma_rates
      @inbounds p.affects![idx](integrator)
  end
  nothing
end

# calculate the next jump / jump time
function generate_jumps!(p::FRMJumpAggregation, integrator, u, params, t)
  nextmaj, ttnmaj = next_ma_jump(p, u, params, t)
  nextcrj, ttncrj = next_constant_rate_jump(p, u, params, t)

  # execute reaction with minimal time
  if ttnmaj < ttncrj
    p.next_jump      = nextmaj
    p.next_jump_time = t + ttnmaj
  else
    p.next_jump      = nextcrj
    p.next_jump_time = t + ttncrj
  end
  nothing
end

######################## SSA specific helper routines ########################

# mass action jumps
@fastmath function next_ma_jump(p::FRMJumpAggregation, u, params, t)
    ttnj      = typemax(typeof(t))
    nextrx    = zero(Int)
    majumps   = p.ma_jumps
    @inbounds for i in eachindex(majumps.scaled_rates)
        p.cur_rates[i] = evalrxrate(u, majumps.scaled_rates[i], majumps.reactant_stoch[i])
        dt = randexp(p.rng) / p.cur_rates[i]
        if dt < ttnj
            ttnj   = dt
            nextrx = i
        end
    end
    nextrx, ttnj
end

# tuple-based constant jumps
@fastmath function next_constant_rate_jump(p::FRMJumpAggregation{T,S,F1,F2,RNG}, u, params, t) where {T,S,F1 <: Tuple, F2 <: Tuple, RNG}
    ttnj   = typemax(typeof(t))
    nextrx = zero(Int)
    if !isempty(p.rates)
        idx = length(p.ma_jumps.scaled_rates) + 1
        fill_cur_rates(u, params, t, p.cur_rates, idx, p.rates...)
        @inbounds for i in idx:length(p.cur_rates)
            dt = randexp(p.rng) / p.cur_rates[i]
            if dt < ttnj
                ttnj   = dt
                nextrx = i
            end
        end
    end
    nextrx, ttnj
end

# function wrapper-based constant jumps
@fastmath function next_constant_rate_jump(p::FRMJumpAggregation{T,S,F1,F2,RNG}, u, params, t) where {T,S,F1 <: AbstractArray,F2 <: AbstractArray, RNG}
    ttnj   = typemax(typeof(t))
    nextrx = zero(Int)
    if !isempty(p.rates)
        idx = length(p.ma_jumps.scaled_rates) + 1
        @inbounds for i in 1:length(p.rates)
            p.cur_rates[idx] = p.rates[i](u, params, t)
            dt = randexp(p.rng) / p.cur_rates[idx]
            if dt < ttnj
                ttnj   = dt
                nextrx = idx
            end
            idx += 1
        end
    end
    nextrx, ttnj
end

max_stars_repo_name: isaacsas/DiffEqJumpExtensions

max_issues_repo_name: isaacsas/DiffEqJumpExtensions

max_forks_repo_name: isaacsas/DiffEqJumpExtensions


text:
# # *******************

# Douglass.@use(df)
# Douglass.@use df

# d" drop :SepalWidth :SepalLength"
# d" drop  :SepalWidth "
# d" drop  :SepalWidth :"

# d"drop [:SepalLength, :SepalWidth]"

# d"drop [:SepalLength, :SepalWidth]"

# d"drop if :PetalLength .< 3.0"

# d"keep"

# d"keep if :PetalLength .< 3.0"

# d"sort [:SepalLength, :SepalWidth]"

# df = dataset("datasets", "iris")
# d"by mygroup1 mygroup2: egen :var = mean(:othervar) if thirdvar .== 5, missing"
# d"egen"

# a = :(:x = :SepalWidth + :PetalLength)

# Douglass.@with(df, :SepalWidth[1] + :PetalLength[1] )

# dump(:(Mymodule.@mymacro) )

# # string interpolation
# include("src/Douglass.jl")
# df = dataset("datasets", "iris")
# Douglass.set_active_df(:df)

# name = "myone"
# d"gen :$$name = 1.0"
# d"gen :$$(name) = 1.0"

# m"gen :x = $(one)"

# name = :x
# d"gen $name = :SepalLength"

# ex = quote
#     :x::Float64 = :y .+ :z
#     drop :x
# end
# dump(ex)

# # ***************
# # egen with by and if
# include("src/Douglass.jl")
# df = dataset("datasets", "iris")
# Douglass.set_active_df(:df)
# using Statistics

# d"gen :row = _n"
# d"bysort :Species (:SepalLength) : egen :x = mean(:PetalWidth) if :SepalWidth .< 3.4"
# sort!(df, :row)

# d"drop :x"
# d"bysort :Species (:SepalLength) : egen :x = :SepalLength if :SepalWidth .< 3.4"

# d"bysort :Species (:SepalLength) : egen :x = 1.0 if :SepalWidth .< 3.4"

# e = :(:SepalLength .+ :SepalWidth )
# dump(e)

# d"bysort :Species (:SepalLength) : egen :x = :SepalLength .+ mean(:PetalLength) if :PetalWidth .> 2.0"

# # egen with by but not if
# include("src/Douglass.jl")
# df = dataset("datasets", "iris")
# Douglass.set_active_df(:df)
# using Statistics

# d"bysort :Species (:SepalLength) : egen :x = mean(:PetalWidth)"
# d"bysort :Species (:SepalLength) : erep :x = mean(:SepalLength)"

# # speed test

# vecr1 = rand(Float64, 1_000_000)
# vecr2 = rand(Float64, 1_000_000)
# vecr3 = Int64.(floor.(100.0 .*rand(Float64, 1_000_000)))

# df = DataFrame(x = vecr1, y = vecr2, g = vecr3)
# categorical!(df,:g)
# Douglass.set_active_df(:df)
# d"bysort :g (:x) : egen :z::Float64 = mean(:y) if :x .< 1000.0"
# d"drop :z"

# # parsing

# include("src/Douglass.jl")
# df = dataset("datasets", "iris")
# Douglass.set_active_df(:df)

# d"bysort :Species (:SepalLength) : gen :z = 1.0 if :SepalLength .< 1000.0, option1 option2(false) option3(:x .+ :y)"

# # replace without by
# include("src/Douglass.jl")
# df = dataset("datasets", "iris")
# Douglass.set_active_df(:df)

# d"gen :x = _n"
# d"replace :x = _n + 1"
# d"replace :x = _n + 10 if _n<3 "

# include("src/Douglass.jl")
# df = dataset("datasets", "iris")
# Douglass.set_active_df(:df)

# d"rename :SepalLength :SomethingBetter"

# # cheatsheet
# macroexpand(Main, :(@d_str("rename :SepalLength :SomethingBetter")))
# macroexpand(Main, :(@d_str("bysort :Species (:SepalLength) : gen :z = 1.0 if :SepalLength .< 1000.0")))

# # merge

# # 1:1
# include("src/Douglass.jl")
# people = DataFrame(ID = [20, 40], Name = ["John Doe", "Jane Doe"])
# jobs = DataFrame(ID = [20, 40], Job = ["Lawyer", "Doctor"])
# Douglass.set_active_df(:people)
# d"merge_11 :ID using jobs"

# people = DataFrame(ID = [20, 40], Name = ["John Doe", "Jane Doe"])
# jobs = DataFrame(ID = [20, 60], Job = ["Lawyer", "Astronaut"])
# Douglass.set_active_df(:people)
# d"merge_11 :ID using jobs"

# # multiple keys
# people = DataFrame(ID = [20, 40], Birthday = ["1980-01-01", "1970-01-01"], Name = ["John Doe", "Jane Doe"])
# jobs = DataFrame(ID = [20, 40], Birthday = ["1980-01-01", "1970-01-01"], Job = ["Lawyer", "Doctor"])
# Douglass.set_active_df(:people)
# d"merge_11 :ID :Birthday using jobs"

# # 1:m
# people = DataFrame(ID = [20, 40], Name = ["John Doe", "Jane Doe"])
# jobs = DataFrame(ID = [20, 20, 60], Job = ["Lawyer", "Economist", "Astronaut"])
# Douglass.set_active_df(:people)
# d"merge_1m :ID using jobs"

# # m:1
# people = DataFrame(ID = [20, 40, 40], Name = ["John Doe", "Jane Doe", "The CEO"])
# jobs = DataFrame(ID = [20, 40, 60], Job = ["Lawyer", "Doctor", "Astronaut"])
# Douglass.set_active_df(:people)
# d"merge_m1 :ID using jobs"

# # reshape

# # with one variable
# include("src/Douglass.jl")
# df = dataset("datasets", "iris")
# Douglass.set_active_df(:df)
# df.id = collect(1:(size(df,1)))
# select!(df,Not([:PetalLength,:PetalWidth]))
# d"reshape_long :Sepal , i(:id) j(:Var)"
# @test :Var ∈ propertynames(df)
# @test :Sepal ∈ propertynames(df)
# @test size(df,1) == 300
# d"reshape_wide :Sepal , i(:id) j(:Var)"
# @test :SepalLength ∈ propertynames(df)
# @test :SepalWidth ∈ propertynames(df)
# @test size(df,1) == 150
# df2 = dataset("datasets", "iris")
# for v in [:SepalLength, :SepalWidth]
#     @test all(df[!,v] .== df2[!,v])
# end

# # with two variables
# include("src/Douglass.jl")
# df = dataset("datasets", "iris")
# Douglass.set_active_df(:df)
# df.id = collect(1:(size(df,1)))

# d"reshape_long :Sepal :Petal, i(:id) j(:Var)"
# @test :Var ∈ propertynames(df)
# @test :Sepal ∈ propertynames(df)
# @test :Petal ∈ propertynames(df)
# @test size(df,1) == 300
# d"reshape_wide :Sepal :Petal, i(:id) j(:Var)"
# @test :SepalLength ∈ propertynames(df)
# @test :SepalWidth ∈ propertynames(df)
# @test :PetalLength ∈ propertynames(df)
# @test :PetalWidth ∈ propertynames(df)
# @test size(df,1) == 150
# df2 = dataset("datasets", "iris")
# for v in [:SepalLength, :SepalWidth, :PetalLength, :PetalWidth]
#     @test all(df[!,v] .== df2[!,v])
# end

# # reshape

# include("src/Douglass.jl")
# df = dataset("datasets", "iris")
# Douglass.set_active_df(:df)

# df.id = collect(1:(size(df,1)))
# #df = stack(df, [:SepalLength, :SepalWidth], :Species)
# df = stack(df, Not([:Species, :id]))

# d"reshape_wide :value , i(:id) j(:variable)"

# macroexpand(Main, :(@d_str("reshape_wide :value , i(:id) j(:variable)")))

# df.value2 = df.value .+ 2.0
# df
# d"reshape_wide :value :value2 , i(:id) j(:variable)"

# # wide to long:
# include("src/Douglass.jl")
# df = dataset("datasets", "iris")
# Douglass.set_active_df(:df)
# df.id = collect(1:(size(df,1)))
# df
# #               all that are Stub*        i               j                given by `Stub`
# stack(df, [:SepalLength, :SepalWidth], [:id], variable_name=:VarIndex, value_name=:Sepal)

# d"reshape_long :Sepal, i(:id) j(:Var)"

# d"reshape_long :Sepal :Petal, i(:id) j(:Var)"

# # Examples from the Readme.md

# using Douglass, RDatasets
# df = dataset("datasets", "iris")
# # set the active DataFrame
# Douglass.set_active_df(:df)

# # create a variable `z` that is the sum of `SepalLength` and `SepalWidth`, for each row
# d"gen :z = :SepalLength + :SepalWidth"
# # replace `z` by the row index for the first 10 observations
# d"replace :z = _n if _n <= 10"
# # drop a variable
# d"drop :z"
# # construct the within-group mean for a subset of the observations
# d"bysort :Species : egen :z = mean(:SepalLength) if :SepalWidth .> 3.0"

# include("src/Douglass.jl")
# df = dataset("datasets", "iris")
# Douglass.set_active_df(:df)
# df.id = collect(1:(size(df,1)))

# d"reshape_long :Sepal :Petal, i(:id) j(:Var)"
# d"reshape_wide :Sepal :Petal, i(:id) j(:Var)"

# ------ BENCHMARK ---------

# using DataFrames, Random, BenchmarkTools
# using Douglass

# rng = MersenneTwister(12345)

# # This is Mathieu Gomez's setup for benchmarking FixedEffectModels
# N = 1_000_000
# K = 100
# id1 = rand(rng,1:div(N, K), N)
# id2 = rand(rng, 1:K, N)
# x1 = 5 * cos.(id1) + 5 * sin.(id2) + randn(N)
# x2 =  cos.(id1) +  sin.(id2) + randn(N)
# y= 3 .* x1 .+ 5 .* x2 .+ cos.(id1) .+ cos.(id2).^2 .+ randn(N)

# df = DataFrame(id1 = categorical(id1), id2 = categorical(id2), x1 = x1, x2 = x2, y = y)
# allowmissing!(df)

# df.x2[rand(rng, 1:10,N) .> 8] .= missing
# sort!(df, [:id2, :id1])

# set_active_df(:df)
# @time d"gen :z = :x1 + :x2"
# @time d"drop :z"

# @btime begin
#     d"gen :z = :x1 + :x2"
#     d"drop :z"
# end

# @btime begin
#     d"bysort :id2 (:id1): egen :z = mean(:x1)"
#     d"drop :z"
# end

# @time begin
#     d"egen :z = mean(:x1)"
#     d"drop :z"
# end

# @time d"gen :z = 0.0"
# @time d"replace :z = :x1 + :x2"
# @time d"drop :z"

# @time d"gen :z = 0.0"
# @time d"bysort :id2 (:id1): egen :z = mean(:x1)"
# @time d"drop :z"

# @time d"bysort :id2 (:id1): egen :z::Float64 = mean(:x1)"
# @time d"drop :z"

# @time df2 = combine(x -> mean(x) , groupby(df,[:id2], sort=false, skipmissing = false ))

# @time by(df, [:id1], :, :x1 => mean)

# df[:z] .= 0.0

# @time d"drop :z"

# d"bysort :id2 (:id1): egen :z = mean(:x2) if ismissing(:x2)"

# d"drop :z"

# @time transform!(groupby(df, [:id2], sort=false, skipmissing = true ), :x1 => mean => :z)

# function myfun2(args...)
#     return cor(args[1],args[2])
# end

# @time transform!(groupby(df, [:id2], sort=false, skipmissing = true ), [:x1,:x2] => cor => :z)
# @time transform!(groupby(df, [:id2], sort=false, skipmissing = true ), [:x1,:y] => cor => :z)

# @time transform!(groupby(df, [:id2], sort=false, skipmissing = true ), [:x1,:y] => myfun2 => :z)

# using Pipe

# @time @pipe df |> groupby(_, :id2) |> transform!(_, :x2 => mean => :z)
# d"drop :z"

# @time @pipe df |> filter(:y => x -> x>0.0, _) |> groupby(_, :id2) |> transform!(_, :x1 => mean => :z)
# d"drop :z"

# function m_f(x)
#     a = x[.!ismissing.(x)]
#     a = a[a .> 0]
#     return mean(a)
# end

# @time transform!(groupby(df, [:id2], sort=false, skipmissing = true ), [:x1,:y] => myfun2 => :z)

# # @time @pipe df |> groupby(_, :id2) |> transform!(_, :x2 => mean => :z))

# @time transform!(groupby(df, [:id2], sort=false, skipmissing = true ), :x2 => m_f => :z )

# d"drop :z"

# dump( :( a + cor(:x1, :x2)))
# dump( :(args[1]))
# dump( :( args[1][2] ))

# a = [ [1, 2] , [3,4]]
# a[1][2]

# using MacroTools

# ex = :( cor(:x1, :x2, :x1) )
# qn_vec = Vector{QuoteNode}()
# replace_QuoteNodes!(ex, :args, qn_vec)

# ex
# qn_vec

# include("src/Douglass.jl")

# using Revise

# using DataFrames, Random, BenchmarkTools
# using Douglass

# rng = MersenneTwister(12345)

# # This is Mathieu Gomez's setup for benchmarking FixedEffectModels
# N = 1_000_000
# K = 100
# id1 = rand(rng,1:div(N, K), N)
# id2 = rand(rng, 1:K, N)
# x1 = 5 * cos.(id1) + 5 * sin.(id2) + randn(N)
# x2 =  cos.(id1) +  sin.(id2) + randn(N)
# y= 3 .* x1 .+ 5 .* x2 .+ cos.(id1) .+ cos.(id2).^2 .+ randn(N)

# df = DataFrame(id1 = categorical(id1), id2 = categorical(id2), x1 = x1, x2 = x2, y = y)
# allowmissing!(df)

# df.x2[rand(rng, 1:10,N) .> 8] .= missing
# sort!(df, [:id2, :id1])

# set_active_df(:df)
# @time d"gen :z = :x1 + :x2"
# @time d"drop :z"

# include("src/Douglass.jl")

# @time begin
#     d"bysort :id2 (:id1): egen :z = mean(:x2) if .!ismissing.(:x2) "
#     d"drop :z"
# end

# @time begin
#     d"bysort :id2 (:id1): egen :z = mean(:y) "
#     d"drop :z"
# end

# @time begin
#     d"egen :z = mean(:x2) if .!ismissing.(:x2) "
#     d"drop :z"
# end

# @time begin
#     d"egen :z = mean(:y) "
#     d"drop :z"
# end

# using Statistics
# @time begin
#     d"bysort :id2 (:id1): egen2 :z = cor(:x1, :x2) if .!ismissing.(:x2)"
#     d"drop :z"
# end

# @time d"bysort :id2 (:id1): egen :z = mean(:x2) if .!ismissing.(:x2) "

# d"bysort :id2 (:id1): egen2 :z = cor(:x1, :x2) if 0+1"

# @time d"bysort :id2 (:id1): egen :z = mean(:x1) if 1+1"

# @time begin
#     d"bysort :id2 (:id1): egen :z = :x1 .+ :x2 if :x1 .> 0.0 "
#     d"drop :z"
# end

# @time begin
#     d"bysort :id2 (:id1): egen :z = :x1 .+ :x2 if :x1 .> 0.0 "
#     d"drop :z"
# end

# include("src/Douglass.jl")
# @time begin
#     d"bysort :id2 (:id1) : erep :y = mean(:x1) if :x1 .> 0.0"
# end

# @time begin
#     d"bysort :id2 (:id1) : erep :y = mean(:x1) "
# end

# @time begin
#     d"erep :y = mean(:x1) if :x1 .> 0.0"
# end

# @time begin
#     d"erep :y = mean(:x1)"
# end

# a = Vector{QuoteNode}()
# push!(a, QuoteNode(:x1))
# push!(a, QuoteNode(:y))
# Symbol.(a)
# println("$(Symbol.(a))")


text:
type InterpolatingSurface{N, T, F <: Function} <: AbstractScalarField{N}
    weights::Vector{T}
    points::Vector{SVector{N, T}}
    offset::MultiPoly.MPoly{T}
    phi::F
end

function InterpolatingSurface{Dimension, T, Tv}(points::Vector{SVector{Dimension, T}}, values::AbstractVector{Tv},
    phi::Function=XCubed(),
    normalize=false)
    @assert length(points) == length(values)
    @assert Dimension <= 3

    num_points = length(points)
    A = zeros(T, num_points + Dimension + 1, num_points + Dimension + 1)
    b = vcat(values, zeros(Tv, Dimension + 1))

    for i = 1:num_points
        A[i, end-Dimension] = 1.0
        for j = 1:Dimension
            A[i, end-Dimension+j] = points[i][j]
        end
        A[num_points+1, i] = 1.0
        for j = 1:Dimension
            A[end-Dimension+j,i] = points[i][j]
        end
        for j = 1:num_points
            if i != j
                v = points[i] - points[j]
                n = norm(v)
                if n >= 1e-9
                    f = phi(n)
                    A[i,j] = f
                end
            end
        end
    end

    y = A \ b

    weights = y[1:num_points]
    p = y[num_points+1:end]
    if normalize
        # Normalize the surface's SDF values to try to ensure that they
        # represent real distances
        averaging_factor = (1 + (Dimension - 1) / 2) / Dimension
        average_slope = averaging_factor * 3 * sum(weights .* (p -> sum(p .^ 2)).(points))
        weights ./= average_slope
        p ./= average_slope
    end

    terms = OrderedDict(zeros(Int, Dimension) => p[1])
    for i = 1:Dimension
        powers = zeros(Int, Dimension)
        powers[i] = 1
        terms[powers] = p[i+1]
    end
    offset = MultiPoly.MPoly{T}(terms, [:x, :y, :z][1:Dimension])

    InterpolatingSurface(weights, points, offset, phi)
end

Base.norm{T <: Real}(x::SVector{2, T}) = sqrt(x[1]^2 + x[2]^2)
Base.norm{T <: Real}(x::SVector{3, T}) = sqrt(x[1]^2 + x[2]^2 + x[3]^2)
Base.norm{T <: Real}(x::MVector{2, T}) = sqrt(x[1]^2 + x[2]^2)
Base.norm{T <: Real}(x::MVector{3, T}) = sqrt(x[1]^2 + x[2]^2 + x[3]^2)

function (surface::InterpolatingSurface{N, Ts}){N, Ts, Tx}(x::AbstractVector{Tx})::promote_type(Ts, Tx)
    typealias T promote_type(Ts, Tx)
    result::T = zero(T)
    for i = eachindex(surface.points)
        n = norm(x - surface.points[i])
        if n >= 1e-9
            result += surface.weights[i] * surface.phi(n)
        end
    end
    result + evaluate(surface.offset, x)
end