text:
"""
$(SIGNATURES)

Runs JuDoc in the current directory.

Keyword arguments:

* `clear=false`:     whether to remove any existing output directory
* `verb=false`:      whether to display messages
* `port=8000`:       the port to use for the local server (should pick a number between 8000 and 9000)
* `single=false`:    whether to run a single pass or run continuously
* `prerender=false`: whether to pre-render javascript (KaTeX and highlight.js)
* `nomess=false`:    suppresses all messages (internal use).
* `isoptim=false`:   whether we're in an optimisation phase or not (if so, links are fixed in case
                     of a project website, see [`write_page`](@ref).
* `no_fail_prerender=true`: whether, in a prerendering phase, ignore errors and try to produce an output
* `eval_all=false`:  whether to force re-evaluation of all code blocks
* `silent=false`:    switch this on to suppress all output (including eval statements).
"""
function serve(; clear::Bool=true,
                 verb::Bool=false,
                 port::Int=8000,
                 single::Bool=false,
                 prerender::Bool=false,
                 nomess::Bool=false,
                 isoptim::Bool=false,
                 no_fail_prerender::Bool=true,
                 eval_all::Bool=false,
                 silent::Bool=false)::Union{Nothing,Int}
    # set the global path
    FOLDER_PATH[]  = pwd()

    # silent mode?
    silent && (SILENT_MODE[] = true; verb = false)

    # brief check to see if we're in a folder that looks promising, otherwise stop
    # and tell the user to check (#155)
    if !isdir(joinpath(FOLDER_PATH[], "src"))
        throw(ArgumentError("The current directory doesn't have a src/ folder. " *
                            "Please change directory to a valid JuDoc folder."))
    end

    # check if a Project.toml file is available, if so activate the folder
    flag_env = false
    if isfile(joinpath(FOLDER_PATH[], "Project.toml"))
        Pkg.activate(".")
        flag_env = true
    end

    # construct the set of files to watch
    watched_files = jd_setup(clear=clear)

    nomess && (verb = false)

    # do a first full pass
    nomess || println("→ Initial full pass...")
    start = time()
    FORCE_REEVAL[] = eval_all
    sig = jd_fullpass(watched_files; clear=clear, verb=verb, prerender=prerender,
                      isoptim=isoptim, no_fail_prerender=no_fail_prerender)
    FORCE_REEVAL[] = false
    sig < 0 && return sig
    fmsg = rpad("✔ full pass...", 40)
    verb && (println(""); print(fmsg); print_final(fmsg, start); println(""))

    # start the continuous loop
    if !single
        nomess || println("→ Starting the server...")
        coreloopfun = (cntr, fw) -> jd_loop(cntr, fw, watched_files; clear=clear, verb=verb)
        # start the liveserver in the current directory
        LiveServer.setverbose(verb)
        LiveServer.serve(port=port, coreloopfun=coreloopfun)
    end
    flag_env && println("→ Use Pkg.activate() to go back to your main environment.")

    empty!(GLOBAL_LXDEFS)
    empty!(GLOBAL_PAGE_VARS)
    empty!(LOCAL_PAGE_VARS)

    return nothing
end

"""
$(SIGNATURES)

Sets up the collection of watched files by doing an initial scan of the input directory.
It also sets the paths variables and prepares the output directory.

**Keyword argument**

* `clear=false`: whether to remove any existing output directory

See also [`serve`](@ref).
"""
function jd_setup(; clear::Bool=true)::NamedTuple
    # . setting up:
    # -- reading and storing the path variables
    # -- setting up the output directory (see `clear`)
    set_paths!()
    prepare_output_dir(clear)

    # . recovering the list of files in the input dir we care about
    # -- these are stored in dictionaries, the key is the full path and the value is the time of
    # last change (useful for continuous monitoring)
    md_files       = TrackedFiles()
    html_files     = TrackedFiles()
    other_files    = TrackedFiles()
    infra_files    = TrackedFiles()
    literate_files = TrackedFiles()
    # named tuples of all the watched files
    watched_files = (md=md_files, html=html_files, other=other_files,
                     infra=infra_files, literate=literate_files)
    # fill the dictionaries
    scan_input_dir!(watched_files...)
    return watched_files
end

"""
$(SIGNATURES)

A single full pass of judoc looking at all watched files and processing them as appropriate.

**Keyword arguments**

* `clear=false`:     whether to remove any existing output directory
* `verb=false`:      whether to display messages
* `prerender=false`: whether to prerender katex and code blocks
* `isoptim=false`  : whether it's an optimization pass
* `no_fail_prerender=true`: whether to skip if a prerendering goes wrong in which case don't prerender

See also [`jd_loop`](@ref), [`serve`](@ref) and [`publish`](@ref).
"""
function jd_fullpass(watched_files::NamedTuple; clear::Bool=false,
                     verb::Bool=false, prerender::Bool=false, isoptim::Bool=false, no_fail_prerender::Bool=true)::Int
    FULL_PASS[] = true
    # initiate page segments
    head    = read(joinpath(PATHS[:src_html], "head.html"), String)
    pg_foot = read(joinpath(PATHS[:src_html], "page_foot.html"), String)
    foot    = read(joinpath(PATHS[:src_html], "foot.html"), String)

    # reset global page variables and latex definitions
    # NOTE: need to keep track of pre-path if specified, see optimize
    prepath = get(GLOBAL_PAGE_VARS, "prepath", nothing)
    def_GLOBAL_PAGE_VARS!()
    def_GLOBAL_LXDEFS!()
    empty!(RSS_DICT)
    # reinsert prepath if specified
    isnothing(prepath) || (GLOBAL_PAGE_VARS["prepath"] = prepath)

    # process configuration file (see also `process_md_defs`)
    process_config()

    # looking for an index file to process
    indexmd   = PATHS[:src] => "index.md"
    indexhtml = PATHS[:src] => "index.html"

    # rest of the pages
    s = 0
    begin
        if isfile(joinpath(indexmd...))
            a = process_file(:md, indexmd, head, pg_foot, foot; clear=clear,
                             prerender=prerender, isoptim=isoptim)
            if a < 0 && prerender && no_fail_prerender
                process_file(:md, indexmd, head, pg_foot, foot; clear=clear,
                             prerender=false, isoptim=isoptim)
            end
            s += a
        elseif isfile(joinpath(indexhtml...))
            a = process_file(:html, indexhtml, head, pg_foot, foot; clear=clear,
                             prerender=prerender, isoptim=isoptim)
            if a < 0 && prerender && no_fail_prerender
                process_file(:html, indexhtml, head, pg_foot, foot; clear=clear,
                             prerender=false, isoptim=isoptim)
            end
            s += a
        else
            @warn "I didn't find an index.[md|html], there should be one. Ignoring."
        end
        # process rest of the files
        for (case, dict) ∈ pairs(watched_files), (fpair, t) ∈ dict
            occursin("index.", fpair.second) && continue
            a = process_file(case, fpair, head, pg_foot, foot, t; clear=clear,
                             prerender=prerender, isoptim=isoptim)
            if a < 0 && prerender && no_fail_prerender
                process_file(case, fpair, head, pg_foot, foot, t; clear=clear,
                             prerender=false, isoptim=isoptim)
            end
            s += a
        end
    end
    # generate RSS if appropriate
    GLOBAL_PAGE_VARS["generate_rss"].first && rss_generator()
    FULL_PASS[] = false
    # return -1 if any page
    return ifelse(s<0, -1, 0)
end

"""
$(SIGNATURES)

This is the function that is continuously run, checks if files have been modified and if so,
processes them. Every 30 cycles, it checks whether any file was added or deleted and consequently
updates the `watched_files`.

**Keyword arguments**

* `clear=false`: whether to remove any existing output directory
* `verb=false`:  whether to display messages
"""
function jd_loop(cycle_counter::Int, ::LiveServer.FileWatcher, watched_files::NamedTuple;
                 clear::Bool=false, verb::Bool=false)::Nothing
    # every 30 cycles (3 seconds), scan directory to check for new or deleted files and
    # update dicts accordingly
    if mod(cycle_counter, 30) == 0
        # 1) check if some files have been deleted; note that we don't do anything,
        # we just remove the file reference from the corresponding dictionary.
        for d ∈ watched_files, (fpair, _) ∈ d
            isfile(joinpath(fpair...)) || delete!(d, fpair)
        end
        # 2) scan the input folder, if new files have been added then this will update
        # the dictionaries
        scan_input_dir!(watched_files..., verb)
    else
        # do a pass over the files, check if one has changed and if so trigger
        # the appropriate file processing mechanism
        for (case, dict) ∈ pairs(watched_files), (fpair, t) ∈ dict
            # check if there was a modification to the file
            fpath = joinpath(fpair...)
            cur_t = mtime(fpath)
            cur_t <= t && continue
            # if there was then the file has been modified and should be re-processed + copied
            fmsg = rpad("→ file $(fpath[length(FOLDER_PATH[])+1:end]) was modified ", 30)
            verb && print(fmsg)
            dict[fpair] = cur_t
            # if it's an infra_file
            if haskey(watched_files[:infra], fpair)
                verb && println("→ full pass...")
                start = time()
                jd_fullpass(watched_files; clear=false, verb=false, prerender=false)
                verb && (print_final(rpad("✔ full pass...", 15), start); println(""))
            # if it's a literate file
            elseif haskey(watched_files[:literate], fpair)
                fmsg = fmsg * rpad("→ updating... ", 15)
                verb && print("\r" * fmsg)
                start = time()
                #
                literate_path = splitext(unixify(joinpath(fpair...)))[1]
                #
                head    = read(joinpath(PATHS[:src_html], "head.html"), String)
                pg_foot = read(joinpath(PATHS[:src_html], "page_foot.html"), String)
                foot    = read(joinpath(PATHS[:src_html], "foot.html"), String)
                # process all md files that have `\literate` with something that matches

                for mdfpair in keys(watched_files.md)
                    mdfpath = joinpath(mdfpair...)
                    # read the content and look for `{...}` that may refer
                    # to that script.
                    content = read(mdfpath, String)
                    for m in eachmatch(r"\{(.*?)(\.jl)?\}", content)
                        if endswith(literate_path, m.captures[1])
                            process_file(:md, mdfpair, head, pg_foot, foot, cur_t;
                                         clear=false, prerender=false)
                            break
                        end
                    end
                end
                verb && print_final(fmsg, start)
            else
                fmsg = fmsg * rpad("→ updating... ", 15)
                verb && print("\r" * fmsg)
                start = time()
                #
                head    = read(joinpath(PATHS[:src_html], "head.html"), String)
                pg_foot = read(joinpath(PATHS[:src_html], "page_foot.html"), String)
                foot    = read(joinpath(PATHS[:src_html], "foot.html"), String)
                # if it's the first time we modify this file then all blocks need
                # to be evaluated so that everything is in scope
                process_file(case, fpair, head, pg_foot, foot, cur_t;
                             clear=false, prerender=false)
                verb && print_final(fmsg, start)
            end
        end
    end
    return nothing
end


text:
"""
    The colormap from EigTool. This provides clearly
    distinguishable colors for a line-contour plot.
"""
function etcgrad()
    cm = [
        0   1.00000000000000   0.10000000000000
        0   0.92500000000000   0.17500000000000
        0   0.85000000000000   0.25000000000000
        0   0.77500000000000   0.32500000000000
        0   0.70000000000000   0.40000000000000
        0   0.62500000000000   0.47500000000000
        0   0.55000000000000   0.55000000000000
        0   0.47500000000000   0.62500000000000
        0   0.40000000000000   0.70000000000000
        0   0.32500000000000   0.77500000000000
        0   0.25000000000000   0.85000000000000
        0   0.17500000000000   0.92500000000000
        0   0.10000000000000   1.00000000000000
        0.06153846153846   0.09230769230769   1.00000000000000
        0.12307692307692   0.08461538461538   1.00000000000000
        0.18461538461538   0.07692307692308   1.00000000000000
        0.24615384615385   0.06923076923077   1.00000000000000
        0.30769230769231   0.06153846153846   1.00000000000000
        0.36923076923077   0.05384615384615   1.00000000000000
        0.43076923076923   0.04615384615385   1.00000000000000
        0.49230769230769   0.03846153846154   1.00000000000000
        0.55384615384615   0.03076923076923   1.00000000000000
        0.61538461538462   0.02307692307692   1.00000000000000
        0.67692307692308   0.01538461538462   1.00000000000000
        0.73846153846154   0.00769230769231   1.00000000000000
        0.80000000000000                  0   1.00000000000000
        0.80769230769231                  0   0.92307692307692
        0.81538461538462                  0   0.84615384615385
        0.82307692307692                  0   0.76923076923077
        0.83076923076923                  0   0.69230769230769
        0.83846153846154                  0   0.61538461538462
        0.84615384615385                  0   0.53846153846154
        0.85384615384615                  0   0.46153846153846
        0.86153846153846                  0   0.38461538461538
        0.86923076923077                  0   0.30769230769231
        0.87692307692308                  0   0.23076923076923
        0.88461538461538                  0   0.15384615384615
        0.89230769230769                  0   0.07692307692308
        0.90000000000000                  0                  0
        0.86923076923077                  0                  0
        0.83846153846154                  0                  0
        0.80769230769231                  0                  0
        0.77692307692308                  0                  0
        0.74615384615385                  0                  0
        0.71538461538462                  0                  0
        0.68461538461538                  0                  0
        0.65384615384615                  0                  0
        0.62307692307692                  0                  0
        0.59230769230769                  0                  0
        0.56153846153846                  0                  0
        0.53076923076923                  0                  0
        0.50000000000000                  0                  0
        0.54166666666667   0.05000000000000                  0
        0.58333333333333   0.10000000000000                  0
        0.62500000000000   0.15000000000000                  0
        0.66666666666667   0.20000000000000                  0
        0.70833333333333   0.25000000000000                  0
        0.75000000000000   0.30000000000000                  0
        0.79166666666667   0.35000000000000                  0
        0.83333333333333   0.40000000000000                  0
        0.87500000000000   0.45000000000000                  0
        0.91666666666667   0.50000000000000                  0
        0.95833333333333   0.55000000000000                  0
        1.00000000000000   0.60000000000000                  0
    ]
    nc = size(cm,1)
    cc = Vector{RGBA{Float64}}()
    vv = zeros(nc)
    for i in 1:nc
        col = RGBA(RGB(cm[i,:]...))
        push!(cc,col)
        vv[i]=(i-1)/(nc-1)
    end
    if :ContinuousColorGradient in names(Plots.PlotUtils, all=true)
        return PlotUtils.ContinuousColorGradient(cc,vv)
    else
        return PlotUtils.ColorGradient(cc,vv)
    end
end

const eigtool_cgrad = etcgrad()

ext: jl


text:
__precompile__(true)
module Oracle

include("compat.jl")

const DEPS_FILE = joinpath(@__DIR__, "..", "deps", "deps.jl")
if !isfile(DEPS_FILE)
    error("Oracle.jl is not installed properly, run Pkg.build(\"Oracle\") and restart Julia.")
end
include(DEPS_FILE)

include("oranumbers/oranumbers.jl")
import .OraNumbers.OraNumber

include("macros.jl")
include("constants.jl")
include("enums.jl")
include("types.jl")
include("odpi.jl")
include("timestamps.jl")
include("ora_timestamp.jl")
include("context.jl")
include("connection.jl")
include("oracle_value.jl")
include("stmt.jl")
include("bind.jl")
include("lob.jl")
include("cursor.jl")
include("pool.jl")
include("variable.jl")
include("deprecated.jl")

function __init__()
    # this function is defined in DEPS_FILE
    check_deps()

    # check size of structs affected by C unions
    @assert sizeof(OraDataBuffer) == sizeof_dpiDataBuffer()
    @assert sizeof(OraData) == sizeof_dpiData()
    @assert sizeof(OraPoolCreateParams) == sizeof_dpiPoolCreateParams()
    @assert sizeof(OraConnCreateParams) == sizeof_dpiConnCreateParams()
    @assert sizeof(OraQueryInfo) == sizeof_dpiQueryInfo()
    @assert sizeof(OraNumber) == sizeof_dpiNumber()
end

@inline function error_check(ctx::Context, result::OraResult)
    if result == ORA_FAILURE
        error_info_ref = Ref{OraErrorInfo}()
        dpiContext_getError(ctx.handle, error_info_ref)
        error_info = error_info_ref[]
        throw(error_info)
    end
    @assert result == ORA_SUCCESS

    nothing
end

end # module Oracle


text:
# Common functions

# KNITRO special types
const KNLONG = Clonglong
const KNBOOL = Cint

"A macro to make calling KNITRO's KN_* C API a little cleaner"
macro kn_ccall(func, args...)
    f = Base.Meta.quot(Symbol("KN_$(func)"))
    args = [esc(a) for a in args]
    quote
        ccall(($f, libknitro), $(args...))
    end
end

macro define_getters(function_name)
    fname = Symbol("KN_" * string(function_name))
    quote
        function $(esc(fname))(kc::Model, index::Vector{Cint})
            result = zeros(Cdouble, length(index))
            ret = @kn_ccall($function_name, Cint,
                            (Ptr{Cvoid}, Cint, Ptr{Cint}, Ptr{Cdouble}),
                            kc.env, length(index), index, result)
            _checkraise(ret)
            return result
        end
    end
end

"Check if return value is valid."
function _checkraise(ret::Cint)
    if ret != 0
        error("Fail to use specified function: $ret")
    end
end

"Format output returned by KNITRO as proper Julia string."
function format_output(output::AbstractString)
    # remove trailing whitespace
    res = strip(output)
    # remove special characters
    res = strip(res, '\0')
end

"Return the current KNITRO version."
function get_release()
    len = 15
    out = zeros(Cchar,len)

    @kn_ccall(get_release, Cvoid, (Cint, Ptr{Cchar}), len, out)
    return String(strip(String(convert(Vector{UInt8},out)), '\0'))
end


text:
struct QubitSiteMap
	siteForQubit::Vector{Int}
	qubitAtSite::Vector{Int}
	QubitSiteMap(N::Int) = new([1:N;],[1:N;])
	QubitSiteMap(siteForQubit::Vector{Int}, qubitAtSite::Vector{Int}) = new(siteForQubit,qubitAtSite)
end #struct
copy(map::QubitSiteMap) = QubitSiteMap(copy(map.siteForQubit), copy(map.qubitAtSite))

siteForQubit(map::QubitSiteMap, i::Int) = map.siteForQubit[i]
sitesForQubits(map::QubitSiteMap, inds::Vector{Int}) = [siteForQubit(map,i) for i ∈ inds]
qubitAtSite(map::QubitSiteMap, i::Int) = map.qubitAtSite[i]
qubitsAtSites(map::QubitSiteMap, inds::Vector{Int}) = [qubitAtSite(map,i) for i ∈ inds]

function updateMap!(map::QubitSiteMap; kwargs...)
	q = get(kwargs, :q, -1)
	s = get(kwargs, :s, -1)
	map.siteForQubit[q] = s
	map.qubitAtSite[s] = q
end


text:
using Test, Random, LinearAlgebra, LuxurySparse

using Yao
using Yao.YaoArrayRegister: invorder
using YaoExtensions
using FFTW

@testset "QFT" begin
    num_bit = 5
    fftblock = qft_circuit(num_bit)
    ifftblock = fftblock'
    reg = rand_state(num_bit)
    rv = copy(statevec(reg))

    @test Matrix(mat(chain(3, qft_circuit(3) |> adjoint, qft_circuit(3)))) ≈ IMatrix(1<<3)

    # test ifft
    reg1 = apply!(copy(reg), ifftblock)

    # permute lines (Manually)
    kv = fft(statevec(reg))/sqrt(length(rv))
    @test statevec(reg1) ≈ invorder(kv)

    # test fft
    reg2 = apply!(invorder!(copy(reg)), fftblock)
    kv = ifft(rv) * sqrt(length(rv))
    @test statevec(reg2) ≈ kv
end

@testset "QFT" begin
    num_bit = 5
    circuit_qft = qft_circuit(num_bit)
    circuit_iqft = circuit_qft'
    block_qft = qft(num_bit)
    block_iqft = qft(num_bit)'
    @test openbox(block_qft) == circuit_qft
    @test openbox(block_iqft) == circuit_iqft
    reg = rand_state(num_bit)

    @test Matrix(chain(3, qft(3)', qft(3))) ≈ IMatrix(1<<3)

    # permute lines (Manually)
    @test apply!(copy(reg), circuit_iqft) ≈ apply!(copy(reg), block_iqft)

    # test fft
    @test apply!(copy(reg), qft) ≈ apply!(copy(reg), block_qft)

    # regression test for nactive
    @test apply!(focus!(copy(reg), 1:3), QFT{3}()) |> isnormalized
end

max_stars_repo_name: QuantumBFS/YaoExtensions

max_issues_repo_name: QuantumBFS/YaoExtensions

max_forks_repo_name: QuantumBFS/YaoExtensions


text:
# this doesn't actually put anything into the type form
# It transforms any number into a bitstype that can hold that number

#function make_number_from_tuple( n::Tuple ; base = 1000 )
#        return foldl( (a,b)-> a*base+b, big(0), n )
#end
function make_number_from_tuple( n::Tuple ; base = 1000 )
        # BigInts to ensure known return type
        fn(a::BigInt,b) = BigInt( a*base+b )
        return foldl( fn, big(0), n )
end

function make_tuple_from_number( n; last_digits = tuple(), base =1000 )
        if -base < n < base
                return ( oftype(base,n),last_digits...)
        end
        next_n, next_digit = fldmod(n,base)
        return make_tuple_from_number( next_n; last_digits = (oftype( base, next_digit ),last_digits...), base = base )
end

# for testing:
function tuple_number_round_trip( n ; base =1000 )
        t = make_tuple_from_number( n; base=base )
        n2 = make_number_from_tuple( t; base=base )
        @assert( n == n2 )
        return n2
end

function to_type_constant( n::Integer )
        if     Int == Int32 && typemin(Int32)  <= n <= typemax(Int32)
                # only for machines where Int is Int32
                return Int32(n)
        elseif typemin(Int64)  <= n <= typemax(Int64)
                return Int64(n)
        elseif typemin(Int128) <= n <= typemax(Int128)
                return Int128(n)
        else
                return make_tuple_from_number(n )
        end
end

function from_type_constant( n::Integer )
        return BigInt(n)
end

function from_type_constant( n::Tuple )
        return make_number_from_tuple( n )
end


text:
# This contains code that deals with data that has to be saved/loaded constantly because it is too large to hold in the RAM all at once
using JLD2

"""
    LargeNODEDataloader(sol, N_batch, N_length, name, base_path=""; dt=nothing, valid_set=nothing)

Impelements an array of NODEDataloader that are too large for the RAM and are thus saved to the hard drive (temporally). They can be loaded by just indexing the
"""
struct LargeNODEDataloader
    name
    path
    N
end

function LargeNODEDataloader(sol, N_batch, N_length, name, base_path=""; dt=nothing, valid_set=nothing)

    t = sol.t[1]:eltype(sol)(dt):sol.t[end]

    N_t = length(t)
    N_t_batch = Int(floor(N_t / N_batch))

    rnd_name = rand(1:100000) # so that multiple instances running in parallel don't interfere

    path = string(base_path,rnd_name,"-",name,"/")
    mkpath(path)

    for i=1:N_batch

        train = NODEDataloader(sol(t[(i-1)*N_t_batch+1:i*N_t_batch]), N_length)

        if !(isnothing(valid_set)) && i==N_batch
            global valid = train
        else
            # to be safe, it is always saved on cpu mem
            train = cpu(train)
            save_name = string(path,name,"-",i,".jld2")
            @save save_name train
        end

    end

    N_batch = !(isnothing(valid_set)) ? N_batch - 1 : N_batch

    if !(isnothing(valid_set))
        return LargeNODEDataloader(name, path, N_batch), valid
    else
        return LargeNODEDataloader(name, path, N_batch)
    end
end

function Base.getindex(iter::LargeNODEDataloader, i::Integer)
    @assert 0 < i <= iter.N

    save_name = string(iter.path, iter.name, "-", i, ".jld2")

    @load save_name train

    # if a gpu is available, it is used, can be switched off by toggling gpuoff()
    return gpu(train)
end

function Base.iterate(iter::LargeNODEDataloader, state=1)
    if state>iter.N
        return nothing
    else
        return (iter[state], state+1)
    end
end

Base.length(iter::LargeNODEDataloader) = iter.N
Base.eltype(iter::LargeNODEDataloader) = eltype(iter.data)

Base.firstindex(iter::LargeNODEDataloader) = 1
Base.lastindex(iter::LargeNODEDataloader) = iter.N
Base.show(io::IO,seq::LargeNODEDataloader) = print(io, "LargeNODEDataloader with files saved at ",seq.path,"/tmp-data")

delete(data::LargeNODEDataloader) = rm(data.path, recursive=true)


text:
import InfrastructureSystems: increment_count

TEST_MSG = "test log message"

@testset "Test LogEventTracker" begin
    levels = (Logging.Info, Logging.Warn, Logging.Error)
    tracker = IS.LogEventTracker(levels)

    events = (
        IS.LogEvent("file", 14, :id, TEST_MSG, Logging.Debug),
        IS.LogEvent("file", 14, :id, TEST_MSG, Logging.Info),
        IS.LogEvent("file", 14, :id, TEST_MSG, Logging.Warn),
        IS.LogEvent("file", 14, :id, TEST_MSG, Logging.Error),
    )

    for i in range(1, length = 2)
        for event in events
            increment_count(tracker, event, false)
        end
    end

    @test length(IS.get_log_events(tracker, Logging.Debug)) == 0
    for level in levels
        test_events = collect(IS.get_log_events(tracker, level))
        @test length(test_events) == 1
        @test test_events[1].count == 2
    end

    text = IS.report_log_summary(tracker)
    @test !occursin("Debug", text)
    @test !occursin("suppressed", text)
    for level in ("Error", "Warn", "Info")
        @test occursin("1 $level event", text)
    end

    # Test again with suppression.
    increment_count(tracker, events[2], true)
    text = IS.report_log_summary(tracker)
    @test occursin("suppressed=1", text)
end

@testset "Test MultiLogger with no event tracking" begin
    logger = IS.MultiLogger([
        ConsoleLogger(devnull, Logging.Info),
        SimpleLogger(devnull, Logging.Debug),
    ])
    with_logger(logger) do
        @info TEST_MSG
    end

    @test_throws ErrorException IS.report_log_summary(logger)
end

@testset "Test MultiLogger with event tracking" begin
    levels = (Logging.Debug, Logging.Info, Logging.Warn, Logging.Error)
    logger = IS.MultiLogger(
        [ConsoleLogger(devnull, Logging.Info), SimpleLogger(devnull, Logging.Debug)],
        IS.LogEventTracker(levels),
    )

    with_logger(logger) do
        for i in range(1, length = 2)
            @debug TEST_MSG
            @info TEST_MSG
            @warn TEST_MSG
            @error TEST_MSG maxlog = 1
        end
    end

    events = collect(IS.get_log_events(logger.tracker, Logging.Error))
    @test length(events) == 1
    events[1].suppressed == 1

    text = IS.report_log_summary(logger)
    for level in levels
        @test occursin("1 $level event", text)
    end
end

@testset "Test configure_logging" begin
    # Verify logging to a file.
    logfile = "testlog.txt"
    logger = IS.configure_logging(;
        file = true,
        filename = logfile,
        file_level = Logging.Info,
        set_global = false,
    )
    with_logger(logger) do
        @info TEST_MSG
    end

    close(logger)

    @test isfile(logfile)
    open(logfile) do io
        lines = readlines(io)
        @test length(lines) == 2  # two lines per message
        @test occursin(TEST_MSG, lines[1])
    end
    rm(logfile)

    # Verify logging with no file.
    logger = IS.configure_logging(;
        console = true,
        file = false,
        console_stream = devnull,
        filename = nothing,
        file_level = Logging.Info,
        set_global = false,
    )
    with_logger(logger) do
        @error TEST_MSG
    end

    events = collect(IS.get_log_events(logger.tracker, Logging.Error))
    @test length(events) == 1
    close(logger)

    @test !isfile(logfile)

    # Verify disabling of tracker.
    logger = IS.configure_logging(;
        console = true,
        file = false,
        console_stream = devnull,
        filename = logfile,
        file_level = Logging.Info,
        set_global = false,
        tracker = nothing,
    )
    with_logger(logger) do
        @error TEST_MSG
        @test isnothing(logger.tracker)
    end

    # Verify setting of global logger
    orig_logger = global_logger()
    logger = IS.configure_logging(;
        console = true,
        file = false,
        console_stream = devnull,
        filename = logfile,
        file_level = Logging.Info,
        set_global = true,
        tracker = nothing,
    )
    @error TEST_MSG
    @test orig_logger != global_logger()
    global_logger(orig_logger)
end

@testset "Test group level" begin
    levels = (Logging.Debug, Logging.Info, Logging.Warn, Logging.Error)
    tracker = IS.LogEventTracker(levels)
    logger = IS.MultiLogger([ConsoleLogger(devnull, Logging.Debug)], tracker)
    IS.set_group_level!(logger, :test_group, Logging.Info)

    @test IS.get_group_level(logger, :test_group) == Logging.Info
    @test IS.get_group_level(logger, :not_stored) === nothing

    with_logger(logger) do
        @debug TEST_MSG _group = :test_group
    end
    @test length(IS.get_log_events(tracker, Logging.Debug)) == 0

    IS.empty_group_levels!(logger)
    with_logger(logger) do
        @debug TEST_MSG _group = :test_group
    end
    @test length(IS.get_log_events(tracker, Logging.Debug)) == 1
end

@testset "Test group levels" begin
    levels = (Logging.Debug, Logging.Info, Logging.Warn, Logging.Error)
    tracker = IS.LogEventTracker(levels)
    logger = IS.MultiLogger([ConsoleLogger(devnull, Logging.Debug)], tracker)
    min_levels = Dict(:test_group => Logging.Warn)
    IS.set_group_levels!(logger, min_levels)
    @test IS.get_group_levels(logger) == min_levels
    with_logger(logger) do
        @info TEST_MSG _group = :test_group
    end
    @test length(IS.get_log_events(tracker, Logging.Info)) == 0

    IS.empty_group_levels!(logger)
    with_logger(logger) do
        @info TEST_MSG _group = :test_group
    end
    @test length(IS.get_log_events(tracker, Logging.Info)) == 1
end

@testset "Test make_logging_config_file" begin
    filename = joinpath(tempdir(), "logging_config.toml")
    try
        redirect_stdout(devnull) do
            IS.make_logging_config_file(filename)
            IS.make_logging_config_file(filename, force = true)
        end
        @test IS.LoggingConfiguration(filename) isa IS.LoggingConfiguration
    finally
        isfile(filename) && rm(filename)
    end
end


text:
# This file is auto-generated by AWSMetadata.jl
using AWS
using AWS.AWSServices: appintegrations
using AWS.Compat
using AWS.UUIDs

"""
    create_data_integration(name)
    create_data_integration(name, params::Dict{String,<:Any})

Creates and persists a DataIntegration resource.  You cannot create a DataIntegration
association for a DataIntegration that has been previously associated. Use a different
DataIntegration, or recreate the DataIntegration using the CreateDataIntegration API.

# Arguments
- `name`: The name of the DataIntegration.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ClientToken"`: A unique, case-sensitive identifier that you provide to ensure the
  idempotency of the request.
- `"Description"`: A description of the DataIntegration.
- `"KmsKey"`: The KMS key for the DataIntegration.
- `"ScheduleConfig"`: The name of the data and how often it should be pulled from the
  source.
- `"SourceURI"`: The URI of the data source.
- `"Tags"`: One or more tags.
"""
function create_data_integration(Name; aws_config::AbstractAWSConfig=global_aws_config())
    return appintegrations(
        "POST",
        "/dataIntegrations",
        Dict{String,Any}("Name" => Name, "ClientToken" => string(uuid4()));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_data_integration(
    Name, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "POST",
        "/dataIntegrations",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}("Name" => Name, "ClientToken" => string(uuid4())),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    create_event_integration(event_bridge_bus, event_filter, name)
    create_event_integration(event_bridge_bus, event_filter, name, params::Dict{String,<:Any})

Creates an EventIntegration, given a specified name, description, and a reference to an
Amazon EventBridge bus in your account and a partner event source that pushes events to
that bus. No objects are created in the your account, only metadata that is persisted on
the EventIntegration control plane.

# Arguments
- `event_bridge_bus`: The EventBridge bus.
- `event_filter`: The event filter.
- `name`: The name of the event integration.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"ClientToken"`: A unique, case-sensitive identifier that you provide to ensure the
  idempotency of the request.
- `"Description"`: The description of the event integration.
- `"Tags"`: One or more tags.
"""
function create_event_integration(
    EventBridgeBus, EventFilter, Name; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "POST",
        "/eventIntegrations",
        Dict{String,Any}(
            "EventBridgeBus" => EventBridgeBus,
            "EventFilter" => EventFilter,
            "Name" => Name,
            "ClientToken" => string(uuid4()),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function create_event_integration(
    EventBridgeBus,
    EventFilter,
    Name,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return appintegrations(
        "POST",
        "/eventIntegrations",
        Dict{String,Any}(
            mergewith(
                _merge,
                Dict{String,Any}(
                    "EventBridgeBus" => EventBridgeBus,
                    "EventFilter" => EventFilter,
                    "Name" => Name,
                    "ClientToken" => string(uuid4()),
                ),
                params,
            ),
        );
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_data_integration(identifier)
    delete_data_integration(identifier, params::Dict{String,<:Any})

Deletes the DataIntegration. Only DataIntegrations that don't have any
DataIntegrationAssociations can be deleted. Deleting a DataIntegration also deletes the
underlying Amazon AppFlow flow and service linked role.   You cannot create a
DataIntegration association for a DataIntegration that has been previously associated. Use
a different DataIntegration, or recreate the DataIntegration using the
CreateDataIntegration API.

# Arguments
- `identifier`: A unique identifier for the DataIntegration.

"""
function delete_data_integration(
    Identifier; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "DELETE",
        "/dataIntegrations/$(Identifier)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_data_integration(
    Identifier,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return appintegrations(
        "DELETE",
        "/dataIntegrations/$(Identifier)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    delete_event_integration(name)
    delete_event_integration(name, params::Dict{String,<:Any})

Deletes the specified existing event integration. If the event integration is associated
with clients, the request is rejected.

# Arguments
- `name`: The name of the event integration.

"""
function delete_event_integration(Name; aws_config::AbstractAWSConfig=global_aws_config())
    return appintegrations(
        "DELETE",
        "/eventIntegrations/$(Name)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_event_integration(
    Name, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "DELETE",
        "/eventIntegrations/$(Name)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_data_integration(identifier)
    get_data_integration(identifier, params::Dict{String,<:Any})

Returns information about the DataIntegration.  You cannot create a DataIntegration
association for a DataIntegration that has been previously associated. Use a different
DataIntegration, or recreate the DataIntegration using the CreateDataIntegration API.

# Arguments
- `identifier`: A unique identifier.

"""
function get_data_integration(Identifier; aws_config::AbstractAWSConfig=global_aws_config())
    return appintegrations(
        "GET",
        "/dataIntegrations/$(Identifier)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_data_integration(
    Identifier,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return appintegrations(
        "GET",
        "/dataIntegrations/$(Identifier)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_event_integration(name)
    get_event_integration(name, params::Dict{String,<:Any})

Returns information about the event integration.

# Arguments
- `name`: The name of the event integration.

"""
function get_event_integration(Name; aws_config::AbstractAWSConfig=global_aws_config())
    return appintegrations(
        "GET",
        "/eventIntegrations/$(Name)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_event_integration(
    Name, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "GET",
        "/eventIntegrations/$(Name)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_data_integration_associations(identifier)
    list_data_integration_associations(identifier, params::Dict{String,<:Any})

Returns a paginated list of DataIntegration associations in the account.  You cannot create
a DataIntegration association for a DataIntegration that has been previously associated.
Use a different DataIntegration, or recreate the DataIntegration using the
CreateDataIntegration API.

# Arguments
- `identifier`: A unique identifier for the DataIntegration.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"nextToken"`: The token for the next set of results. Use the value returned in the
  previous response in the next request to retrieve the next set of results.
"""
function list_data_integration_associations(
    Identifier; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "GET",
        "/dataIntegrations/$(Identifier)/associations";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_data_integration_associations(
    Identifier,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return appintegrations(
        "GET",
        "/dataIntegrations/$(Identifier)/associations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_data_integrations()
    list_data_integrations(params::Dict{String,<:Any})

Returns a paginated list of DataIntegrations in the account.  You cannot create a
DataIntegration association for a DataIntegration that has been previously associated. Use
a different DataIntegration, or recreate the DataIntegration using the
CreateDataIntegration API.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"nextToken"`: The token for the next set of results. Use the value returned in the
  previous response in the next request to retrieve the next set of results.
"""
function list_data_integrations(; aws_config::AbstractAWSConfig=global_aws_config())
    return appintegrations(
        "GET", "/dataIntegrations"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_data_integrations(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "GET",
        "/dataIntegrations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_event_integration_associations(name)
    list_event_integration_associations(name, params::Dict{String,<:Any})

Returns a paginated list of event integration associations in the account.

# Arguments
- `name`: The name of the event integration.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"nextToken"`: The token for the next set of results. Use the value returned in the
  previous response in the next request to retrieve the next set of results.
"""
function list_event_integration_associations(
    Name; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "GET",
        "/eventIntegrations/$(Name)/associations";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_event_integration_associations(
    Name, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "GET",
        "/eventIntegrations/$(Name)/associations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_event_integrations()
    list_event_integrations(params::Dict{String,<:Any})

Returns a paginated list of event integrations in the account.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"maxResults"`: The maximum number of results to return per page.
- `"nextToken"`: The token for the next set of results. Use the value returned in the
  previous response in the next request to retrieve the next set of results.
"""
function list_event_integrations(; aws_config::AbstractAWSConfig=global_aws_config())
    return appintegrations(
        "GET", "/eventIntegrations"; aws_config=aws_config, feature_set=SERVICE_FEATURE_SET
    )
end
function list_event_integrations(
    params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "GET",
        "/eventIntegrations",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    list_tags_for_resource(resource_arn)
    list_tags_for_resource(resource_arn, params::Dict{String,<:Any})

Lists the tags for the specified resource.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the resource.

"""
function list_tags_for_resource(
    resourceArn; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "GET",
        "/tags/$(resourceArn)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function list_tags_for_resource(
    resourceArn,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return appintegrations(
        "GET",
        "/tags/$(resourceArn)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    tag_resource(resource_arn, tags)
    tag_resource(resource_arn, tags, params::Dict{String,<:Any})

Adds the specified tags to the specified resource.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the resource.
- `tags`: One or more tags.

"""
function tag_resource(resourceArn, tags; aws_config::AbstractAWSConfig=global_aws_config())
    return appintegrations(
        "POST",
        "/tags/$(resourceArn)",
        Dict{String,Any}("tags" => tags);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function tag_resource(
    resourceArn,
    tags,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return appintegrations(
        "POST",
        "/tags/$(resourceArn)",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("tags" => tags), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    untag_resource(resource_arn, tag_keys)
    untag_resource(resource_arn, tag_keys, params::Dict{String,<:Any})

Removes the specified tags from the specified resource.

# Arguments
- `resource_arn`: The Amazon Resource Name (ARN) of the resource.
- `tag_keys`: The tag keys.

"""
function untag_resource(
    resourceArn, tagKeys; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "DELETE",
        "/tags/$(resourceArn)",
        Dict{String,Any}("tagKeys" => tagKeys);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function untag_resource(
    resourceArn,
    tagKeys,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return appintegrations(
        "DELETE",
        "/tags/$(resourceArn)",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("tagKeys" => tagKeys), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    update_data_integration(identifier)
    update_data_integration(identifier, params::Dict{String,<:Any})

Updates the description of a DataIntegration.  You cannot create a DataIntegration
association for a DataIntegration that has been previously associated. Use a different
DataIntegration, or recreate the DataIntegration using the CreateDataIntegration API.

# Arguments
- `identifier`: A unique identifier for the DataIntegration.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Description"`: A description of the DataIntegration.
- `"Name"`: The name of the DataIntegration.
"""
function update_data_integration(
    Identifier; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "PATCH",
        "/dataIntegrations/$(Identifier)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_data_integration(
    Identifier,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return appintegrations(
        "PATCH",
        "/dataIntegrations/$(Identifier)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    update_event_integration(name)
    update_event_integration(name, params::Dict{String,<:Any})

Updates the description of an event integration.

# Arguments
- `name`: The name of the event integration.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"Description"`: The description of the event inegration.
"""
function update_event_integration(Name; aws_config::AbstractAWSConfig=global_aws_config())
    return appintegrations(
        "PATCH",
        "/eventIntegrations/$(Name)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function update_event_integration(
    Name, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()
)
    return appintegrations(
        "PATCH",
        "/eventIntegrations/$(Name)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end


text:
# Sampler for drawing random number of a Gamma distribution

# Routines for sampling from Gamma distribution

#  A simple method for generating gamma variables - Marsaglia and Tsang (2000)
#  http://www.cparity.com/projects/AcmClassification/samples/358414.pdf
#  Page 369
#  basic simulation loop for pre-computed d and c

const _v13 = 1.0 / 3.0

# a sampler for Gamma(α)
immutable GammaSampler
    α::Float64
    iα::Float64  # iα = α > 1 ? 1.0 : 1.0 / α
    d::Float64
    c::Float64

    function GammaSampler(α::Float64)
        local iα::Float64, d::Float64
        if α > 1.0
            iα = 1.0
            d = α - _v13
        else
            iα = 1.0 / α
            d = α + 1.0 - _v13
        end
        new(α, iα, d, 1.0 / sqrt(9.0 * d))
    end
end

function rand(s::GammaSampler)
    d::Float64 = s.d
    c::Float64 = s.c

    v = 0.0
    while true
        x = randn()
        v = 1.0 + c * x
        while v <= 0.0
            x = randn()
            v = 1.0 + c * x
        end
        v *= (v * v)
        u = rand()
        x2 = x^2
        if u < 1.0 - 0.331 * x2^2
            break
        end
        if log(u) < 0.5 * x2 + d * (1.0 - v + log(v))
            break
        end
    end
    v *= d

    if s.α <= 1.0
        v *= (rand()^s.iα)
    end
    return v::Float64
end

randg(α::Float64) = rand(GammaSampler(α))
randg(α::Real) = randg(float64(α))


text:
using Pkg.TOML, StaticArrays

@testset "TracerDistributions.jl" begin
	params = TOML.parsefile("TracerDistributions.toml")

	aob = MPISimulations.initialize(MPISimulations.AxisOrientedBox,"AxisOrientedBox",params,Float64)
	sphere = MPISimulations.initialize(MPISimulations.Sphere,"Sphere",params,Float64)
	t = randn()
	r = zeros(SVector{3,Float64})
	@test !MPISimulations.isZero(aob,r)
	@test !MPISimulations.isZero(sphere,r)
	r = SVector{3,Float64}(1e-3,0,0)
	@test !MPISimulations.isZero(aob,r)
	@test !MPISimulations.isZero(sphere,r)
	r = SVector{3,Float64}(1.01e-3,0,0)
	@test MPISimulations.isZero(aob,r)
	@test MPISimulations.isZero(sphere,r)

	r = zeros(SVector{3,Float64})
	@test MPISimulations.tracerConcentration(aob,r,t) == 1.8141555811322022e15
	@test MPISimulations.tracerConcentration(sphere,r,t) == 1.8141555811322022e15
	r = SVector{3,Float64}(1.01e-3,0,0)
	@test MPISimulations.tracerConcentration(aob,r,t) == 0.0
	@test MPISimulations.tracerConcentration(sphere,r,t) == 0.0

	#Misc
	@test MPISimulations.numberOfParticles(1e-3,25e-9) == 1.8141352092994865e15
end


text:
using Primes

@testset "Chineese remainder theorem" begin

    modular_images(a, ms) = map(m -> mod(a, m), ms)

    Ms = [
        [2, 3],
        [3, 7],
        [2^31 - 1, Primes.nextprime(2^31)],
        [Primes.nextprime(BigInt(2)^100), Primes.nextprime(BigInt(2)^101)]
    ]
    for ms in Ms
        P = prod(ms)
        nums = [rand(1:P-1) for _ in 1:10]

        for a in nums
            rs = modular_images(a, ms)

            r1, r2 = BigInt.(rs)
            m1, m2 = BigInt.(ms)
            acrt = Groebner.CRT(r1, m1, r2, m2)
            @test acrt == a
        end

    end

end


text:
# ============================================================
# Initial & Boundary Conditions of Specific Problems
# ============================================================

export config_ib, ib_rh, ib_sod, ib_briowu, ib_cavity

include("cfg_rh.jl")
include("cfg_sod.jl")
include("cfg_briowu.jl")
include("cfg_cavity.jl")

"""
$(SIGNATURES)

Config initial and boundary conditions
"""
function config_ib(args...; case = args[1].case)
    func = begin
        if case in ("shock", :shock)
            eval(Symbol("ib_" * "rh"))
        elseif case in ("brio-wu", Symbol("brio-wu"))
            eval(Symbol("ib_" * "briowu"))
        else
            eval(Symbol("ib_" * string(case)))
        end
    end

    return func(args...)
end


text:
const ArrayOrField = Union{AbstractArray, AbstractField}

#####
##### Diffusivities
#####

κᶠᶜᶜ(i, j, k, grid, clock, κ::Number) = κ
κᶜᶠᶜ(i, j, k, grid, clock, κ::Number) = κ
κᶜᶜᶠ(i, j, k, grid, clock, κ::Number) = κ

κᶠᶜᶜ(i, j, k, grid, clock, κ::Function) = κ(xnode(Face,   i, grid), ynode(Center, j, grid), znode(Center, k, grid), clock.time)
κᶜᶠᶜ(i, j, k, grid, clock, κ::Function) = κ(xnode(Center, i, grid), ynode(Face,   j, grid), znode(Center, k, grid), clock.time)
κᶜᶜᶠ(i, j, k, grid, clock, κ::Function) = κ(xnode(Center, i, grid), ynode(Center, j, grid), znode(Face,   k, grid), clock.time)

# Assumes that `κ` is located at cell centers
κᶠᶜᶜ(i, j, k, grid, clock, κ::ArrayOrField) = ℑxᶠᵃᵃ(i, j, k, grid, κ)
κᶜᶠᶜ(i, j, k, grid, clock, κ::ArrayOrField) = ℑyᵃᶠᵃ(i, j, k, grid, κ)
κᶜᶜᶠ(i, j, k, grid, clock, κ::ArrayOrField) = ℑzᵃᵃᶠ(i, j, k, grid, κ)

#####
##### Diffusive fluxes
#####

@inline diffusive_flux_x(i, j, k, grid, clock, κ, c) = κᶠᶜᶜ(i, j, k, grid, clock, κ) * ∂xᶠᶜᵃ(i, j, k, grid, c)
@inline diffusive_flux_y(i, j, k, grid, clock, κ, c) = κᶜᶠᶜ(i, j, k, grid, clock, κ) * ∂yᶜᶠᵃ(i, j, k, grid, c)
@inline diffusive_flux_z(i, j, k, grid, clock, κ, c) = κᶜᶜᶠ(i, j, k, grid, clock, κ) * ∂zᵃᵃᶠ(i, j, k, grid, c)

#####
##### Diffusive flux divergence
#####

"""
    ∇_κ_∇c(i, j, k, grid, clock, closure::AbstractTurbulenceClosure, c, ::Val{tracer_index}, args...)

Calculates diffusion for a tracer c via

    1/V * [δxᶜᵃᵃ(Ax * diffusive_flux_x) + δyᵃᶜᵃ(Ay * diffusive_flux_y) + δzᵃᵃᶜ(Az * diffusive_flux_z)]

which will end up at the location `ccc`.
"""
@inline function ∇_κ_∇c(i, j, k, grid, clock, closure::AbstractTurbulenceClosure, c, ::Val{tracer_index}, args...) where tracer_index
    return 1/Vᶜᶜᶜ(i, j, k, grid) * (δxᶜᵃᵃ(i, j, k, grid, Ax_uᶠᶜᶜ, diffusive_flux_x, clock, closure, c, Val(tracer_index), args...) +
                                    δyᵃᶜᵃ(i, j, k, grid, Ay_vᶜᶠᶜ, diffusive_flux_y, clock, closure, c, Val(tracer_index), args...) +
                                    δzᵃᵃᶜ(i, j, k, grid, Az_wᶜᶜᵃ, diffusive_flux_z, clock, closure, c, Val(tracer_index), args...))
end


text:
const ProgressToken = Union{Int, String}
struct ProgressParams{T}
    token::ProgressToken
    value::T
end

mutable struct DocumentFilter
    language::Union{String,Missing}
    scheme::Union{String,Missing}
    pattern::Union{String,Missing}
end
const DocumentSelector = Vector{DocumentFilter}
const DocumentUri = String

@dict_readable struct Position
    line::Int
    character::Int
end
Position(line::Integer) = Position(line, 0)

struct Range
    start::Position
    stop::Position
end
# Special case to account for use of 'end' as a fieldname in LSP
Range(d::Dict) = Range(Position(d["start"]), Position(d["end"]))
Range(line::Integer) = Range(Position(line), Position(line))
Range(l0::Integer, c0::Integer, l1::Integer, c1::Integer) = Range(Position(l0, c0), Position(l1, c1))
function JSON.lower(a::Range)
    Dict("start" => a.start, "end" => a.stop)
end

@dict_readable struct Location
    uri::DocumentUri
    range::Range
end
Location(f::String, line::Integer) = Location(f, Range(line))

@dict_readable struct LocationLink <: Outbound
    originalSelectionRange::Union{Range,Missing}
    targetUri::DocumentUri
    targetRange::Range
    targetSelectionRange::Range
end

@dict_readable struct WorkspaceFolder
    uri::String
    name::String
end

##############################################################################
# Diagnostics
const DiagnosticSeverity = Int
const DiagnosticSeverities = (Error = 1,
                              Warning = 2,
                              Information = 3,
                              Hint = 4)

const DiagnosticTag = Int
const DiagnosticTags = (Unnecessary = 1,
                        Deprecated = 2)

struct DiagnosticRelatedInformation
    location::Location
    message::String
end

@dict_readable struct Diagnostic <: Outbound
    range::Range
    severity::Union{DiagnosticSeverity,Missing}
    code::Union{String,Missing}
    source::Union{String,Missing}
    message::String
    tags::Union{Vector{DiagnosticTag},Missing}
    relatedInformation::Union{Vector{DiagnosticRelatedInformation},Missing}
end

##############################################################################

struct Command <: Outbound # Use traits for this?
    title::String
    command::String
    arguments::Union{Vector{Any},Missing}
end

struct TextEdit
    range::Range
    newText::String
end

##############################################################################
# Markup
const MarkupKind = String
const MarkupKinds = (PlainText = "plaintext",
                     Markdown = "markdown")

mutable struct MarkupContent
   kind::MarkupKind
   value::String
end
MarkupContent(value::String) = MarkupContent(MarkupKinds.Markdown, value)

mutable struct MarkedString
    language::String
    value::AbstractString
end

Base.convert(::Type{MarkedString}, x::String) = MarkedString("julia", string(x))
MarkedString(x) = MarkedString("julia", string(x))
Base.hash(x::MarkedString) = hash(x.value) # for unique

##############################################################################
# Window
const MessageType = Int
const MessageTypes = (Error = 1,
                      Warning = 2,
                      Info = 3,
                      Log = 4)

struct ShowMessageParams <: Outbound
    type::MessageType
    message::String
end

struct MessageActionItem <: Outbound
    title::String
end

mutable struct ShowMessageRequestParams <: Outbound
    type::MessageType
    message::String
    actions::Union{Vector{MessageActionItem},Missing}
end

mutable struct LogMessageParams <: Outbound
    type::Integer
    message::String
end

##############################################################################
# Progress
struct WorkDoneProgressCreateParams <: Outbound
    token::ProgressToken
end

@dict_readable struct WorkDoneProgressCancelParams
    token::ProgressToken
end

struct WorkDoneProgressBegin
    kind::String
    title::String
    cancellable::Union{Bool,Missing}
    message::Union{String,Missing}
    percentage::Union{Int,Missing}
    function WorkDoneProgressBegin(title, cancellable, message, percentage)
        new("begin", title, cancellable, message, percentage)
    end
end

struct WorkDoneProgressReport
    kind::String
    cancellable::Union{Bool,Missing}
    message::Union{String,Missing}
    percentage::Union{Int,Missing}
    function WorkDoneProgressReport(cancellable, message, percentage)
        new("report", cancellable, message, percentage)
    end
end

struct WorkDoneProgressEnd
    kind::String
    message::Union{String,Missing}
    function WorkDoneProgressEnd(message)
        new("end", message)
    end
end

struct WorkDoneProgressParams
    workDoneToken::Union{ProgressToken,Missing}
end

struct WorkDoneProgressOptions
    workDoneProgress::Union{Bool,Missing}
end

##############################################################################
# Partial

struct PartialResultParams
    partialResultToken::Union{ProgressToken,Missing}
end


text:
N = 13
	num = string("73167176531330624919225119674426574742355349194934",
			"96983520312774506326239578318016984801869478851843",
			"85861560789112949495459501737958331952853208805511",
			"12540698747158523863050715693290963295227443043557",
			"66896648950445244523161731856403098711121722383113",
			"62229893423380308135336276614282806444486645238749",
			"30358907296290491560440772390713810515859307960866",
			"70172427121883998797908792274921901699720888093776",
			"65727333001053367881220235421809751254540594752243",
			"52584907711670556013604839586446706324415722155397",
			"53697817977846174064955149290862569321978468622482",
			"83972241375657056057490261407972968652414535100474",
			"82166370484403199890008895243450658541227588666881",
			"16427171479924442928230863465674813919123162824586",
			"17866458359124566529476545682848912883142607690042",
			"24219022671055626321111109370544217506941658960408",
			"07198403850962455444362981230987879927244284909188",
			"84580156166097919133875499200524063689912560717606",
			"05886116467109405077541002256983155200055935729725",
			"71636269561882670428252483600823257530420752963450")

	p = 0;

	for i = 1:(endof(num)-N)

		pn = prod([int(string(x)) for x in num[i:i+N-1]])
		if pn>p
			p=pn
		end
	end

	println(p)

max_stars_repo_name: gribeill/ProjectEuler

max_issues_repo_name: gribeill/ProjectEuler

max_forks_repo_name: gribeill/ProjectEuler


text:
"An ordinary differential equation"
immutable ODE
  var::DReal.Ex{Float64}         # independent variable
  rhs::DReal.Ex{Float64}        # f(var)
end

"A system of differential equations"
immutable ODESystem
  name::ASCIIString
  odes::Vector{ODE}
end

ODESystem(odes::Vector{ODE}) = ODESystem(genvar("flow_"), odes)

to_c{T}(exs::Vector{Ex{T}}) = [ex.e for ex in exs]

"Returns constraint that [x_1 ...] is the integral of the system of differential
equations from 0 to time_0 with initial conditions x_0 and p_0"
function integral(
  sys::ODESystem,         # a system of odes
  varst::Vector{Ex{Float64}},     # variables which will be constrained to integral output
  t0::Ex{Float64},        # lower bound of integration
  tend::Ex{Float64},      # upper bound of integration
  vars0::Vector{Ex{Float64}};     # Initial conditions
  ctx::Context=global_context())

  nvars = length(varst)
  @assert nvars == length(vars0)
  @assert nvars == length(sys.odes)
  odevars = [ode.var for ode in sys.odes]
  oderhses = [ode.rhs for ode in sys.odes]
  opensmt_define_ode(ctx.ctx, sys.name, to_c(odevars), to_c(oderhses), Cuint(length(odevars)))
  Ex{Bool}(opensmt_mk_integral(ctx.ctx, to_c(varst), t0.e, tend.e, to_c(vars0), Cuint(nvars), sys.name), no_vars())
end

function integral(
  odes::Vector{ODE},      # a system of odes
  varst::Vector{Ex{Float64}},     # variables which will be constrained to integral output
  t0::Ex{Float64},        # lower bound of integration
  tend::Ex{Float64},      # upper bound of integration
  vars0::Vector{Ex{Float64}};     # Initial conditions
  ctx::Context=global_context())

  sys = ODESystem(odes)
  integral(sys, varst, t0, tend, vars0; ctx=ctx)
end


text:
"""
    hash256(x::Block) -> Vector{UInt8}
    hash256(x::Header) -> Vector{UInt8}
    hash256(x::Tx) -> Vector{UInt8}

Hash a `Block`, `Header`, or `Tx`

```julia
hash256(block)
hash256(header)
hash256(transaction)
```
"""
hash256(x::Tx) = reverse(sha256(sha256(serialize(x))))
hash256(x::Header) = reverse(sha256(sha256(x.data)))
hash256(x::Block) = hash256(x.header)


text:
function transitions(states_t, controls_t, exog_states, mparams, opts)
"""
Calculate state transition for approximation
"""

    # Set up control variables
    cons = controls_t[1]
    cost = controls_t[2]

    # Abatement rate
    mu = (cost./exog_states[:Psi]).^(1 ./ mparams[:a2])

    # Next period's states
    states_next = zeros(length(states_t))

    # Net output
    if opts[:learn_e]
        exog_states[:net_output] = states_t[1]^(mparams[:kappa])*states_t[5]
    else
        exog_states[:net_output] = states_t[1]^(mparams[:kappa])*states_t[3]
    end

    # Capital
    states_next[1] = (states_t[1]*(1 - mparams[:deltak]) .+ (exog_states[:net_output]*(1 - cost[1]) .- cons[1])) * exog_states[:effkgrowth]

    # Cumulative emissions
    states_next[2] = states_t[2] .+ exog_states[:emint].*(1 - mu[1]).*states_t[1].^mparams[:kappa] .+ exog_states[:Bs]

    if opts[:learn_e]

        # Damage quadrature
        dams, total_weight = qnwlogn(mparams[:nqnodes],
            states_t[3]*log.(mparams[:ccr]*states_next[2]),
            states_t[4]*log.(mparams[:ccr]*states_next[2])^2)

        # Fractional net output, quadrature and actual state
        dam_next = 1 ./ (ones(size(dams,1), size(mparams[:coeff],1)) + dams*mparams[:coeff]')
        states_next[5] = 1 ./ (1 + exp(mparams[:coeff_loc])*(mparams[:ccr]*states_next[2])^mparams[:exp_mean])

        # d_2 mean, quadrature and actual state
        exp_next = ((mparams[:coeff_scale])*states_t[3] .+
            states_t[4].*log.(mparams[:ccr]*states_next[2]).*(log.(1 ./ dam_next .- 1) .- mparams[:coeff_loc]))./
            (mparams[:coeff_scale] .+ states_t[4]*log.(mparams[:ccr]*states_next[2])^2)
        states_next[3] = ((mparams[:coeff_scale])*states_t[3] .+
        states_t[4].*log.(mparams[:ccr]*states_next[2]).*(log.(1 ./ states_next[5] .- 1) .- mparams[:coeff_loc]))./
            (mparams[:coeff_scale] .+ states_t[4]*log.(mparams[:ccr]*states_next[2])^2)

        # d_2 variance
        states_next[4] = states_t[4]*(mparams[:coeff_scale])./
            (mparams[:coeff_scale] .+ states_t[4]*log.(mparams[:ccr]*states_next[2])^2)

    else

        # Damage quadrature
        dams, total_weight = qnwlogn(mparams[:nqnodes],
            mparams[:exp_mean]*log.(mparams[:ccr]*states_next[2]),
            mparams[:exp_var]*log.(mparams[:ccr]*states_next[2])^2)

        # Fractional net output, quadrature and actual state
        dam_next = 1 ./ (ones(size(dams,1), size(mparams[:coeff],1)) + dams*mparams[:coeff]')
        states_next[3] = 1 ./ (1 + exp(mparams[:coeff_loc])*(mparams[:ccr]*states_next[2])^mparams[:exp_mean])

        # Placeholder
        exp_next = mparams[:exp_mean].*ones(size(dam_next))

    end

    return states_next, exp_next, dam_next

end

function transitions(states_t, controls_t, exog_states, mparams, opts, exponent_sim, coeff_sim)
"""
Calculate state transition for simulations
"""

    # Set up control variables
    cons = controls_t[1]
    cost = controls_t[2]

    # Abatement rate
    mu = (cost./exog_states[:Psi]).^(1 ./ mparams[:a2])

    # No shocks if 1 run

    if mparams[:num_runs] == 1 | opts[:perfect_info]
        exponent_sim = mparams[:exp_mean]
        coeff_sim = exp(mparams[:coeff_loc])
    end

    # Next period's states
    states_next = zeros(length(states_t))

    # Net output
    if opts[:learn_e]
        exog_states[:net_output] = states_t[1]^(mparams[:kappa])*states_t[5]
    else
        exog_states[:net_output] = states_t[1]^(mparams[:kappa])*states_t[3]
    end

    # Capital
    states_next[1] = (states_t[1]*(1 - mparams[:deltak]) .+ (exog_states[:net_output]*(1 - cost[1]) .- cons[1])) * exog_states[:effkgrowth]

    # Cumulative emissions
    states_next[2] = states_t[2] .+ exog_states[:emint].*(1 - mu[1]).*states_t[1].^mparams[:kappa] .+ exog_states[:Bs]

    if opts[:learn_e]

        # Base fractional net output or misspecified fractional net output
        if mparams[:damages]  == :base
            if opts[:alt_damages]
                states_next[5] = 1 ./ (1 + coeff_sim*mparams[:d1]*(mparams[:ccr]*states_next[2])^mparams[:d2])
            else
                states_next[5] = 1 ./ (1 + coeff_sim*(mparams[:ccr]*states_next[2])^exponent_sim)
            end

        elseif mparams[:damages]  == :weitzman
            states_next[5] = 1 ./ (1 + coeff_sim*((mparams[:ccr]*states_next[2]/mparams[:weitz_c1])^mparams[:weitz_e1] .+
                (mparams[:ccr]*states_next[2]/mparams[:weitz_c2])^mparams[:weitz_e2]))

        elseif mparams[:damages] == :dietz
            states_next[5] = 1 ./ (1 + coeff_sim*(mparams[:dietz_c1].*(mparams[:ccr]*states_next[2])^mparams[:dietz_e1] .+
                mparams[:dietz_c2].*(mparams[:ccr]*states_next[2])^mparams[:dietz_e2]))

        elseif mparams[:damages] == :extreme
            states_next[5] = 1 ./ (1 + coeff_sim*(mparams[:extreme_c1].*(mparams[:ccr]*states_next[2])^mparams[:extreme_e1] .+
                mparams[:extreme_c2].*(mparams[:ccr]*states_next[2])^mparams[:extreme_e2]))
        end

        # Damage quadrature
        dams, total_weight = qnwlogn(mparams[:nqnodes],
            states_t[3]*log.(mparams[:ccr]*states_next[2]),
            states_t[4]*log.(mparams[:ccr]*states_next[2])^2)

        # Fractional net output quadrature
        dam_next = 1 ./ (ones(size(dams,1), size(mparams[:coeff],1)) + dams*mparams[:coeff]')

        # d_2 mean, quadrature and actual state
        exp_next = ((mparams[:coeff_scale])*states_t[3] .+
            states_t[4].*log.(mparams[:ccr]*states_next[2]).*(log.(1 ./ dam_next .- 1) .- mparams[:coeff_loc]))./
            (mparams[:coeff_scale] .+ states_t[4]*log.(mparams[:ccr]*states_next[2]).^2)
        states_next[3] = ((mparams[:coeff_scale])*states_t[3] .+
            states_t[4].*log.(mparams[:ccr]*states_next[2]).*(log.(1 ./ states_next[5] - 1) .- mparams[:coeff_loc]))./
            (mparams[:coeff_scale] .+ states_t[4]*log.(mparams[:ccr]*states_next[2])^2)

        # d_2 variance
        states_next[4] = states_t[4]*(mparams[:coeff_scale])./
            (mparams[:coeff_scale] .+ states_t[4]*log.(mparams[:ccr]*states_next[2])^2)

    else

        # Base fractional net output or misspecified fractional net output
        if mparams[:damages]  == :base
            if opts[:alt_damages]
                states_next[3] = 1 ./ (1 + mparams[:d1]*(mparams[:ccr]*states_next[2])^mparams[:d2])
            else
                states_next[3] = 1 ./ (1 + coeff_sim*(mparams[:ccr]*states_next[2])^exponent_sim)
            end

        elseif mparams[:damages]  == :weitzman
            states_next[3] = 1 ./ (1 + coeff_sim*((mparams[:ccr]*states_next[2]/mparams[:weitz_c1])^mparams[:weitz_e1] .+
                (mparams[:ccr]*states_next[2]/mparams[:weitz_c2])^mparams[:weitz_e2]))

        elseif mparams[:damages] == :dietz
            states_next[3] = 1 ./ (1 + coeff_sim*(mparams[:dietz_c1].*(mparams[:ccr]*states_next[2])^mparams[:dietz_e1] .+
                mparams[:dietz_c2].*(mparams[:ccr]*states_next[2])^mparams[:dietz_e2]))

        elseif mparams[:damages] == :extreme
            states_next[3] = 1 ./ (1 + coeff_sim*(mparams[:extreme_c1].*(mparams[:ccr]*states_next[2])^mparams[:extreme_e1] .+
                mparams[:extreme_c2].*(mparams[:ccr]*states_next[2])^mparams[:extreme_e2]))
        end

        # Damage quadrature
        dams, total_weight = qnwlogn(mparams[:nqnodes],
            mparams[:exp_mean]*log.(mparams[:ccr]*states_next[2]),
            mparams[:exp_var]*log.(mparams[:ccr]*states_next[2])^2)

        # Fractional net output quadrature
        dam_next = 1 ./ (ones(size(dams,1), size(mparams[:coeff],1)) + dams*mparams[:coeff]')

        # Placeholder
        exp_next = mparams[:exp_mean].*ones(size(dam_next))

    end

    return states_next, exp_next, dam_next

end

max_stars_repo_name: irudik/optimal-climate-policy-aej

max_issues_repo_name: irudik/optimal-climate-policy-aej

max_forks_repo_name: irudik/optimal-climate-policy-aej


text:
module TestSumProdPolynomials
using Test

using Poly

p = SumProdPoly{Symbol}([ [[:B]] => [:S], [[:S]] => [:S,:A] ])
q = SumProdPoly{Symbol}([ [[:A]] => [:B] ])
@test p+q == SumProdPoly{Symbol}([
  [[:B]] => [:S], [[:S]] => [:S,:A], [[:A]] => [:B],
])

end


text:
function triangles(del::DataFrame, summ::DataFrame)
    generators = emptygenerators(summ)
    generatorstogenerated!(generators, del)
    indextriangles = buildindextriangles(generators)
    return buildvaluetriangles(indextriangles, summ)
end

function emptygenerators(summ::DataFrame)::Dict{Int64,Array{Int,1}}
    generators = Dict{Int64,Array{Int,1}}()
    for (index, row) in enumerate(eachrow(summ))
        generators[index] = []
    end
    return generators
end

function generatorstogenerated!(generators::Dict{Int64,Array{Int,1}}, del::DataFrame)
    for row in eachrow(del)
        generators[row[5]] = append!(generators[row[5]], row[6])
        generators[row[6]] = append!(generators[row[6]], row[5])
    end
end

function buildindextriangles(generators::Dict{Int64,Array{Int,1}})::Array{Array{Int,1},1}
    triangles = Array{Array{Int,1},1}()
    for k in keys(generators)
        for e in generators[k]
            i = findall(in(generators[e]), generators[k])
            common = generators[k][i]
            for c in common
                tri = sort([c, k, e])
                if !(tri in triangles)
                    push!(triangles, tri)
                end
            end
        end
    end
    return triangles
end

function buildvaluetriangles(
    indextriangles::Array{Array{Int,1},1},
    summ::DataFrame,
)::Array{Array{Point2D,1},1}
   return [
        [
            Point(summ[t[1], 1], summ[t[1], 2]),
            Point(summ[t[2], 1], summ[t[2], 2]),
            Point(summ[t[3], 1], summ[t[3], 2]),
        ] for t in indextriangles
    ]
end

max_stars_repo_name: jstarczewski/julia-num

max_issues_repo_name: jstarczewski/julia-num

max_forks_repo_name: jstarczewski/julia-num


text:
@discord_object struct Reaction
    count::Int
    me::Bool
    emoji::Emoji
end


text:
#######################################
# Implements Richardson Extrapolation #
#######################################

import LinearAlgebra: norm

"""
Implements a single iteration of Richardson extrapolation

i (input) = Row of Richardson Extrapolation
Ai1 (output) = Next row of Richardson Extrapolation to be calculated
Ai (input) = Previous Row of Richardson Extrapolation
k (inputs) = vector of error orders
t = ratio of step sizes between the i and i-1 iteration
"""
function extrapolate_iter(A::Function, i::Integer, Ai::AbstractArray, Ai1::AbstractArray, h::AbstractArray, k::AbstractArray, abstol::Real, reltol::Real, erri::Real)
    Ai1[1] = A(h[i+1])
    t = h[i]/h[i+1]
    for j = 1:i
        tk = t^k[j]
        Ai1[j+1] = (tk*Ai1[j] - Ai[j])/(tk- 1)
    end
    # We estimate the error by comparing the estimated value at the previous and current row
    # This gives a good estimate of the error at the previous iteration,
    # so we extrapolate to estimate the error at the current order
    err = norm(Ai[i] - Ai1[i+1]) * (h[i+1]^k[i+1]) / (h[i]^k[i])

    # Checking for stopping conditions
    if err < abstol + reltol*norm(Ai1[i+1]) || length(Ai1) == i+1
        # If the err is acceptable or we have reached the maximum number of iterations, return the answer and the error
        return Ai1[i+1], err
    elseif err > erri
        # If the estimate error has increased, we are probably running into round-off error and should stop
        # We return the previous answer and error estimate
        return Ai[i], erri
    else
        # Otherwise, we calculate another iteration
        # We swap the order of the work arrays Ai, Ai1
        return extrapolate_iter(A, i+1, Ai1, Ai, h, k, abstol, reltol, err)
    end
end

function extrapolate(A::Function, A1::AbstractArray, A2::AbstractArray, h::AbstractArray, k::AbstractArray, abstol::Real, reltol::Real)
    A1[1] = A(h[1])
    ans, err = extrapolate_iter(A, 1, A1, A2, h, k, abstol, reltol, Inf)
    if err > abstol + reltol*norm(ans)
        @warn @sprintf("Error estimate of derivative larger than requested tolerance.  Err: %g, abstol + reltol*|ans|: %g", err, abstol + reltol*norm(ans))
    end
    return ans
end