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

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

"""
Creates a tag in the subscription.
The tag name can have a maximum of 512 characters and is case insensitive. Tag names created by Azure have prefixes of microsoft, azure, or windows. You cannot create tags with one of these prefixes.
Param: tagName::String (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: TagDetails
"""
function tagsCreateOrUpdate(_api::TagsApi, tagName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "PUT", TagDetails, "/subscriptions/{subscriptionId}/tagNames/{tagName}", ["azure_auth"])
    Swagger.set_param(_ctx.path, "tagName", tagName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    Swagger.exec(_ctx)
end

"""

Creates a tag value. The name of the tag must already exist.
Param: tagName::String (required)
Param: tagValue::String (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: TagValue
"""
function tagsCreateOrUpdateValue(_api::TagsApi, tagName::String, tagValue::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "PUT", TagValue, "/subscriptions/{subscriptionId}/tagNames/{tagName}/tagValues/{tagValue}", ["azure_auth"])
    Swagger.set_param(_ctx.path, "tagName", tagName)  # type String
    Swagger.set_param(_ctx.path, "tagValue", tagValue)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    Swagger.exec(_ctx)
end

"""
Deletes a tag from the subscription.
You must remove all values from a resource tag before you can delete it.
Param: tagName::String (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: Nothing
"""
function tagsDelete(_api::TagsApi, tagName::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "DELETE", Nothing, "/subscriptions/{subscriptionId}/tagNames/{tagName}", ["azure_auth"])
    Swagger.set_param(_ctx.path, "tagName", tagName)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    Swagger.exec(_ctx)
end

"""

Deletes a tag value.
Param: tagName::String (required)
Param: tagValue::String (required)
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: Nothing
"""
function tagsDeleteValue(_api::TagsApi, tagName::String, tagValue::String, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "DELETE", Nothing, "/subscriptions/{subscriptionId}/tagNames/{tagName}/tagValues/{tagValue}", ["azure_auth"])
    Swagger.set_param(_ctx.path, "tagName", tagName)  # type String
    Swagger.set_param(_ctx.path, "tagValue", tagValue)  # type String
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    Swagger.exec(_ctx)
end

"""

Gets the names and values of all resource tags that are defined in a subscription.
Param: api_version::String (required)
Param: subscriptionId::String (required)
Return: TagsListResult
"""
function tagsList(_api::TagsApi, api_version::String, subscriptionId::String; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "GET", TagsListResult, "/subscriptions/{subscriptionId}/tagNames", ["azure_auth"])
    Swagger.set_param(_ctx.path, "subscriptionId", subscriptionId)  # type String
    Swagger.set_param(_ctx.query, "api-version", api_version)  # type String
    Swagger.set_header_accept(_ctx, ["application/json"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json"] : [_mediaType])
    Swagger.exec(_ctx)
end

export tagsCreateOrUpdate, tagsCreateOrUpdateValue, tagsDelete, tagsDeleteValue, tagsList


text:
module SQLDataFrameTools

using DataFrameTools
using SHA
using DBInterface
using Dates
using DataFrames
using Distributed

export QueryCache, df_cached, select_fn, expired, fetch_and_combine, Dfetch_and_combine

"""
    QueryCache(sql, select, dir, format;  subformat=nothing, dictencode=true)

is the Data Structure used in this module.

# Arguments

- `sql` is the SQL Query
- `select` is the function used to retrieve the dataset (which can be created with [`select_fn`](@ref))
- `dir` is the directory in which to store the cache file
- `format` is one of the file formats supported. See DataFrameTools.df_formats() for the list.
- `subformat` and `dictencode` are optional parameters for DataFrameTools.df_write

# Examples

	query = QueryCache("SELECT 1",  select_fn(MySQL.Connection, SERVER, USER, PASSWORD), ".", :jdf)

"""
struct QueryCache
	sql
	select
	cachepath
	subformat::Union{Nothing,Symbol}
	dictencode::Bool
	QueryCache(sql, select, dir, format;  subformat=nothing, dictencode=true) = new(sql, select, cachepath(dir, bytes2hex(sha256(sql)), format), subformat, dictencode)
end

cachepath(dir, hash, sformat) = joinpath(dir, hash * '.' * string(sformat))

"""
    expired(q::QueryCache, expires::Dates.DateTime)
    expired(q::QueryCache, ttl::Dates.Period)

Has the cache file expired?

If the file doesn't exist always return true, otherwise check the mtime against the given time.

# Arguments

- `q` a QueryCache struct
- `expires` a DateTime to check against the current time.
- `ttl` a time period to compare the current time to the mtime of the cache + ttl

# Examples

	expired(query, Dates.Day(3)) # returns a bool of whether the cache is more than 3 days old
	expired(query, Dates.Minute(30)) # returns a bool of whether the cache is more than 30 minutes old
	expired(query, Dates.DateTime(2021, 1, 1, 1, 2, 3)) # returns a bool compared to the given time

"""
expired(q::QueryCache, expires::DateTime) = expires <= now() || stat(q.cachepath).device == 0
expired(q::QueryCache, ttl::Period) = expired(q, unix2datetime(mtime(q.cachepath)) + ttl)

"""
    df_cached(q::QueryCache, ttl_e::Union{Dates.Period, Dates.DateTime}; noisy::Bool=false)

# Arguments
- `q` a QueryCache
- `ttl_e` is either a DataTime or Period specifying how long the cache should be live.

If the cached version of the DataFrame is still live, return it from disk.

If it has expired, call the Query's sql_function with the sql, write the DataFrame to disk
in the specified formats and return the DataFrame.

The noisy flag indicates whether to print to stderr where the data is coming from.

# Examples

Always retreive the SQL from the server

	df = df_cached(query, now())

Get the cached version, if it exists, or is less than 7 days old

Print "From Server" or "From Cache" on stderr, depending where it came from, with the filename / sql snippet

	df = df_cached(query, Dates.Day(7), noisy=true)

"""
function df_cached(q::QueryCache, ttl_e; noisy=false, attempts=0)
	if expired(q, ttl_e)
		if isa(noisy, Bool) && noisy
			println(stderr, "($(Threads.threadid())) From Server - ", q.sql)# [1:(length(q.sql) < 40 ? end : 40)])
		end
		df = q.select(q.sql)
		df_write(q.cachepath, df, subformat=q.subformat, dictencode=q.dictencode)
		return df
	else
		if noisy
			println(stderr, "($(Threads.threadid())) From Cache - ", splitpath(q.cachepath)[end])
		end
		try
			df_read(q.cachepath)
		catch e
			if attempts > 1
				throw("df_cached failed $attempts times")
				return nothing # probably not needed
			end

			if isa(e, SystemError)
				return df_cached(q, now(), noisy=noisy, attempts=attempts+1)
			end
		end
	end
end

"""
    select_fn(connection, args...; kw...)

Return a function which will `execute` the Query's sql on the supplied connection

# Arguments
- `connection` the appropriate Connection data structure from some other module
- `args` splatted arguments to use in DBInterface.connect
- `kw` splatted kwarguments to use in DBInterface.connect

# Examples

	sql_fn = select_fn(MySQL.Connection, SERVER, USER, PASSWORD)

"""
select_fn(connection, args...; kw...) = sql->DBInterface.execute(DBInterface.connect(connection, args...; kw...), sql) |> DataFrame

"""
	fetch_and_combine(queries; ttl:Union{Dates.Period, Dates.DateTime}, noisy::Bool)

Given an iterable collection of queries, fetch them and combine them into a single DataFrame using as many threads as available.

# Arguments

- `queries` iterable collection of QueryCache
- `ttl` Time To Live, a Period or DateTime (default 7 days)
- `noisy` if so, report on stderr where the data is coming from (default false)

# Example

If we have a long_view that times out on a single connection then split it into 3 and re-combine them.

This is my actual use case for this Module. I'm querying from MySQL on AWS and only get 300 seconds.

If the network is busy, my queries risk being terminated, so I break them into chunks.

	df = fetch_and_combine([
		QueryCache("SELECT long_view WHERE created BETWEEN '2019-01-01' AND '2019-12-13'", sql_fn, ".", :arrow),
		QueryCache("SELECT long_view WHERE created BETWEEN '2020-01-01' AND '2020-12-13'", sql_fn, ".", :arrow),
		QueryCache("SELECT long_view WHERE created BETWEEN '2021-01-01' AND '2021-12-13'", sql_fn, ".", :arrow),
		])
"""
function fetch_and_combine(queries; ttl=Day(7), noisy=false)
	dfs = Vector{DataFrame}(undef, length(queries))
	Threads.@threads for i in 1:length(queries)
		dfs[i] = df_cached(queries[i], ttl, noisy=noisy)
	end
	reduce((adf, df)->append!(adf, df), dfs[2:end], init=dfs[1])
end
#fetch_and_combine(queries; ttl=Day(7), noisy=false) = reduce((adf, query)->append!(adf, df_cached(query, ttl, noisy=noisy)), queries, init=DataFrame())

"""
	Dfetch_and_combine(queries; ttl:Union{Dates.Period, Dates.DateTime}, noisy::Bool)

The same as [fetch\\_and\\_combine][@ref] but use a different process for each Query, spawning at :any.
"""
Dfetch_and_combine(queries; ttl=Day(7), noisy=false) = reduce((adf, future)->append!(adf, fetch(future)), [@spawnat :any df_cached(query, ttl, noisy=noisy) for query in queries], init=DataFrame())
###
end

ext: jl


text:
##############
##ABC-Rejection code
##############

"
`abcRejection` has various methods.
Possible arguments are as follows:

* `in`
An `ABCInput` variable.

* `nsims`
How many simulations to perform.

* `k`
How many simulations to accept (an integer).

* `h`
Acceptance threshold (floating point).

* `store_init`.
Whether to return simulations used to initialise the distance function.

The methods are:

* `(in, nsims, k; store_init)`
Performs ABC accepting k simulations.

* `(in, nsims, h; store_init)`
Performs ABC accepting simulations with distance below the threshold h.

* `(in, nsims; store_init)`
Performs ABC accepting everything.

The output is a `ABCRejOutput` object.
"
function abcRejection(in::ABCInput, nsims::Integer; store_init=false)
    nparameters = length(in.prior)
    parameters = Array{Float64}(nparameters, nsims)
    sumstats = zeros(Float64, (in.nsumstats, nsims))
    successes = Array{Bool}(nsims)
    prog = Progress(nsims, 1) ##Progress meter
    for i in 1:nsims
        pars = rand(in.prior)
        parameters[:,i] = pars
        (success, stats) = in.sample_sumstats(pars)
        successes[i] = success
        if (success)
            sumstats[:,i] = stats
        end
        next!(prog)
    end
    nsuccesses = sum(successes)
    parameters = parameters[:, successes]
    sumstats = sumstats[:, successes]
    newdist = init(in.abcdist, sumstats, parameters)
    distances = Float64[evaldist(newdist, sumstats[:,i]) for i=1:nsuccesses]
    if (store_init)
        init_sims = sumstats
        init_pars = parameters
    else
        init_sims = Array{Float64}(0,0)
        init_pars = Array{Float64}(0,0)
    end
    out = ABCRejOutput(nparameters, in.nsumstats, nsims, nsuccesses, parameters, sumstats, distances, ones(nsims), newdist, init_sims, init_pars)
    sortABCOutput!(out)
    out
end

##Do abcRejection, accepting k closest matches
function abcRejection(in::ABCInput, nsims::Integer, k::Integer; store_init=false)
    out = abcRejection(in, nsims, store_init=store_init)
    out.parameters = out.parameters[:,1:k]
    out.sumstats = out.sumstats[:,1:k]
    out.distances = out.distances[1:k]
    out.weights = out.weights[1:k]
    out
end

##Do abcRejection, accepting distances <= h
function abcRejection(in::ABCInput, nsims::Integer, h::AbstractFloat; store_init=false)
    out = abcRejection(in, nsims, store_init=store_init)
    if (out.distances[nsims] <= h)
        k = out.nsuccesses
    else
        k = findfirst((x)->x>h, out.distances) - 1
    end
    ##nb the following works sensibly even if k==0
    out.parameters = out.parameters[:,1:k]
    out.sumstats = out.sumstats[:,1:k]
    out.distances = out.distances[1:k]
    out.weights = out.weights[1:k]
    out
end


text:
struct Claim
    id::UInt32
    x_inches::UInt32
    y_inches::UInt32
    x_size::UInt32
    y_size::UInt32
end

struct IterPoints
    claim::Claim
    px::UInt32
    py::UInt32
end

file = open("../input/input.txt")
input = read(file, String)

first_part(input)
second_part(input)

close(file)

max_stars_repo_name: GrayJack/Advent-Of-Code

max_issues_repo_name: GrayJack/Advent-Of-Code

max_forks_repo_name: GrayJack/Advent-Of-Code


text:
using Distributions
using StaticArrays
using POMDPs

@testset "PMDP.jl" begin

    # struct ConstUserBudget <: PMDPs.AbstractUserBudget
    #     β::Distribution
    # end

    pp = simple_pp()
    mg = PMDPs.PMDPg(pp)
    me = PMDPs.PMDPe(pp)

    for m in [mg, me]
        @test PMDPs.pp(m) == pp
        @test PMDPs.selling_period_end(m) == pp.T
        @test PMDPs.budgets(m) == pp.B
        @test PMDPs.demand(m) == pp.D
        @test POMDPs.actions(m) == mg.pp.A
        @test PMDPs.objective(m) == :revenue
        @test PMDPs.n_resources(m) == 2

        @test typeof(m) <: PMDPs.PMDP
    end

    action = 5.
    @testset "StatePMDPMethods" begin
       s = PMDPs.State(mg, SA[2,3], 5, SA[true, true])
       @test PMDPs.sale_impossible(mg, s, action) == false
       @test PMDPs.isterminal(mg, s) == false

       # timestep over selling_period_end
       s_afterspe = PMDPs.State(mg, SA[2,3], 7, SA[true, true])
       @test PMDPs.sale_impossible(mg, s_afterspe, action) == true
       @test PMDPs.isterminal(mg, s_afterspe) == false

       # timestep over T
       s_t = PMDPs.State(mg, SA[2,3], 8, SA[true, true])
       @test PMDPs.sale_impossible(mg, s_t, action) == true
       @test PMDPs.isterminal(mg, s_t) == true

       # some 0 capacity
       s_0c = PMDPs.State(mg, SA[0,3], 3, SA[true, true])
       @test PMDPs.sale_impossible(mg, s_0c, action) == true
       @test PMDPs.isterminal(mg, s_0c) == false

       # 0 capacity
       s_0allc = PMDPs.State(mg, SA[0,0], 3, SA[true, true])
       @test PMDPs.sale_impossible(mg, s_0allc, action) == true
       @test PMDPs.isterminal(mg, s_0allc) == true

       # 0 product
       s_0p = PMDPs.State(mg, SA[2,3], 3, SA[false, false])
       @test PMDPs.sale_impossible(mg, s_0p, action) == true
       @test PMDPs.isterminal(mg, s_0p) == false
    end

end


text:
struct StrictlyGreaterToStrictlyLessBridge{
    T,
    F<:MOI.AbstractScalarFunction,
    G<:MOI.AbstractScalarFunction,
} <: MOIBC.FlipSignBridge{T,CPE.Strictly{MOI.GreaterThan{T},T},CPE.Strictly{MOI.LessThan{T}, T},F,G}
    constraint::CI{F,CPE.Strictly{MOI.LessThan{T}, T}}
end
function MOIBC.map_set(::Type{<:StrictlyGreaterToStrictlyLessBridge}, set::CPE.Strictly{MOI.GreaterThan{T}, T}) where T
    return CPE.Strictly(MOI.LessThan(-set.set.lower))
end
function MOIBC.inverse_map_set(::Type{<:StrictlyGreaterToStrictlyLessBridge}, set::CPE.Strictly{MOI.LessThan{T}, T}) where T
    return CPE.Strictly(MOI.GreaterThan(-set.set.upper))
end
function MOIBC.concrete_bridge_type(
    ::Type{<:StrictlyGreaterToStrictlyLessBridge{T}},
    G::Type{<:MOI.AbstractScalarFunction},
    ::Type{CPE.Strictly{MOI.GreaterThan{T}, T}},
) where {T}
    F = MOIU.promote_operation(-, T, G)
    return StrictlyGreaterToStrictlyLessBridge{T,F,G}
end


text:
using InteractionNetworkModels, BenchmarkTools, Distances

d_lcs = LCS()

x,y = (rand(1:3,10), rand(1:3, 10))

@btime d(x,y)

d_fast = FastLCS(100)
@btime d_fast(x,y)

d = MatchingDist(LCS())
d_fast = FastMatchingDist(LCS(), 50)
x,y = (

    [rand(1:3, rand(4:6)) for i in 1:rand(4:5)],
    [rand(1:3, rand(4:6)) for i in 1:rand(4:5)]
)
C = zeros(100,100)
@btime d(x,y)
@btime d_fast(x,y)
@btime matching_dist_with_memory!(x,y,d_lcs,C)

@btime pairwise_inbounds(d_lcs, x,y)
@btime Distances.pairwise(d_lcs, x,y)

d = MatchingDist(LCS())
d_norm = Normalised(d)

d_norm([[1,2,1]], [[1,2,3,4,5,4],[1]])

typeof(Normalised(d)) <: InteractionSetDistance

supertype(typeof(Normalised(d)))
supertype(typeof(Euclidean()))


text:
## Taylor coeffcients of different functions
taylor_coeff(::typeof(exp), i, x) = exp(x) / factorial(i)

function taylor_coeff(::typeof(sin), i, x)
    j = i % 4

    (j == 0) && (return sin(x) / factorial(i))
    (j == 1) && (return cos(x) / factorial(i))
    (j == 2) && (return -sin(x) / factorial(i))
    (j == 3) && (return -cos(x) / factorial(i))
end

taylor_coeff(::typeof(inv), i, x) = (-1)^i / (x^(i+1))

taylor_coeffs(f, n, x0) = taylor_coeff.(f, 0:n, x0)

doc"""
Make a Taylor1Model for a given function over a given domain.
"""
function Taylor1Model(f, n, x0, I)

    a = taylor_coeffs(f, n, x0)
    p = Taylor1(a)

    Γ = taylor_coeff(f, n+1, I)

    if sup(Γ) ≤ 0 || inf(Γ) ≥ 0

        lo = Interval(inf(I))
        hi = Interval(sup(I))

        Δlo = f(lo) - bound(p, x0, lo)
        Δhi = f(hi) - bound(p, x0, hi)
        Δx0 = f(x0) - bound(p, x0, x0)
        Δ = Interval(min(inf(Δlo), inf(Δx0), inf(Δhi)), max(sup(Δlo), sup(Δx0), sup(Δhi)))

    else
        V = (I - x0)^(n+1)
        Δ = V * Γ
    end

    return Taylor1Model(n, x0, I, p, Δ)
end

doc"""
Evaluate a polynomial of a polynomial-like object (Taylor1Model, Taylor1) `f`.
`a` are the coefficients of the polynomial, expressed as a `Taylor1`.
"""
function evaluate_polynomial(a::Taylor1, f)

    M = zero(f)

    # Horner method:
    for i in degree(f):-1:0
        M = (M * f) + a[i]
    end

    return M
end

doc"""
Calculate the Taylor1Model of `(g∘f)` given a function `g` and a Taylor1Model `f`.
"""
function TMcomposition(g, f::Taylor1Model)
    n = f.n

    # centre ("x0") for g is f(x0), which is first coefficient of expansion of f:
    f_of_x0 = f[0]  # constant_term(f.p)

    # calculate interval for g: image of f
    Bf = bound(f)  # Bf + Δf in Joldes thesis; basically f(I)

    Mg = Taylor1Model(g, n, f_of_x0, Bf)

    b, Δg = Mg.p, Mg.Δ

    f_non_constant_part = [0; f.p[1:end]]  # f - f(x0)

    M1 = Taylor1Model(f, f_non_constant_part, f.Δ)

    M = evaluate_polynomial(b, M1)

    return Taylor1Model(M, M.Δ + Δg)   # same polynomial, different interval
end

# allow exp(t) etc. for a Taylor1Model t:
for g in (:exp, :sin, :inv)
    @eval $g(f::Taylor1Model) = TMcomposition($g, f)
end

function /(f::Taylor1Model, g::Taylor1Model)
    @assert data(f) == data(g)

    M = f * inv(g)
end


text:
using EntropyStableEuler
using Test
using StaticArrays

@testset "Logmean tests" begin
    uL,uR = 1,2
    @test logmean(uL,uR) == logmean(uL,uR,log(uL),log(uR))
    @test logmean(uL,uR) == logmean(uR,uL)
    @test logmean(uL,uL) ≈ uL
end

function init_prim(d)
    if d==1
        rho,u,p = 1,.1,2
        Q = (rho,u,p)
    elseif d==2
        rho,u,v,p = 1,.1,.2,2
        Q = (rho,u,v,p)
    elseif d==3
        rho,u,v,w,p = 1,.1,.2,.3,2
        Q = (rho,u,v,w,p)
    end
    return Q
end

@testset "Tests for d = $d" for d in (1:3)

    @testset "Entropy variable tests" begin

        U = prim_to_cons(Euler{d}(),init_prim(d))
        V = v_ufun(Euler{d}(),U)

        h = 1e-7
        central_diff(f,x) = (f(x+h) - f(x-h))/(2*h)
        swapentry(x,y,i) = (x[begin:i-1]...,y,x[i+1:end]...)
        for j = 1:d+2
            @test abs(V[j] - central_diff(x->Sfun(Euler{d}(),swapentry(U,x,j)),U[j])) < h
        end

        UV = u_vfun(Euler{d}(),V)
        @test all(UV .≈ U)
    end

    @testset "Symmetry" begin
        # test symmetry
        UL = prim_to_cons(Euler{d}(),init_prim(d))
        UR = prim_to_cons(Euler{d}(),init_prim(d).*1.1)
        FLR = fS(Euler{d}(),UL,UR)
        FRL = fS(Euler{d}(),UR,UL)
        @test all(FLR .≈ FRL)
    end

    @testset "Consistency" begin
        Q = init_prim(d)
        U = prim_to_cons(Euler{d}(),Q)
        F = fS(Euler{d}(),U,U)

        p = pfun(Euler{d}(),U)
        if d==1
            rho,rhou,E = U
            u = rhou./rho
            Fexact = SVector{3}(rho*u, rho*u^2 + p, u*(E+p))
        elseif d==2
            rho,rhou,rhov,E = U
            u,v = rhou./rho, rhov./rho
            Fx = SVector{4}(rho*u, rho*u^2 + p, rho*u*v,     u*(E+p))
            Fy = SVector{4}(rho*v, rho*u*v,     rho*v^2 + p, v*(E+p))
            Fexact = (Fx,Fy)
        elseif d==3
            rho,rhou,rhov,rhow,E = U
            u,v,w = rhou./rho, rhov./rho, rhow./rho
            Fx = SVector{5}(rho*u, rho*u^2 + p, rho*u*v,     rho*u*w,     u*(E+p))
            Fy = SVector{5}(rho*v, rho*u*v,     rho*v^2 + p, rho*v*w,     v*(E+p))
            Fz = SVector{5}(rho*w, rho*u*w,     rho*v*w,     rho*w^2 + p, w*(E+p))
            Fexact = (Fx,Fy,Fz)
        end

        @test all(F .≈ Fexact)
    end

    @testset "Entropy conservation property" begin
        γ = Euler{d}().γ

        UL = prim_to_cons(Euler{d}(),init_prim(d))
        UR = prim_to_cons(Euler{d}(),init_prim(d).*1.1)
        VL = v_ufun(Euler{d}(),UL)
        VR = v_ufun(Euler{d}(),UR)

        ψ(U) = (γ-1).*U[2:d+1]
        F = fS(Euler{d}(),UL,UR)
        vTF(VL,VR,F) = sum((VL .- VR).*F)
        for j = 1:d
            if d==1
                @test vTF(VL,VR,F) ≈ ψ(UL)[j]-ψ(UR)[j]
            else
                @test vTF(VL,VR,F[j]) ≈ ψ(UL)[j]-ψ(UR)[j]
            end
        end
    end

    @testset "Type stability tests" begin
        Q = init_prim(d)
        U = prim_to_cons(Euler{d}(),Q)
        V = v_ufun(Euler{d}(),U)

        @inferred prim_to_cons(Euler{d}(),Q)
        @inferred cons_to_prim_beta(Euler{d}(),U)
        @inferred v_ufun(Euler{d}(),U)
        @inferred u_vfun(Euler{d}(),V)
        @inferred fS(Euler{d}(),U,U)
    end
end


text:
abstract type ContinuationKind end
abstract type OneParamCont <: ContinuationKind end
abstract type TwoParamCont <: ContinuationKind end

# Codim1
struct FixedPointCont <: OneParamCont end

# Codim2
struct SaddleNodeCont <: TwoParamCont end
struct HopfCont <: TwoParamCont end

# Codim1LimitCycle
struct LimitCycleCont <: OneParamCont end

# Codim2LimitCycle
struct FoldLimitCycleCont <: TwoParamCont end

#=
contkind(::T) where T = ContinuationKind(T)
=#

function contkind(cache::AbstractContinuationCache)  # TODO: trait
    prob = as(cache, ContinuationCache).prob_cache.prob  # TODO: interface
    return contkind(prob)
end

contkind(solver::AbstractContinuationSolver) = contkind(solver.prob)


text:
# SimHistory
# maintained by @zsunberg

abstract type AbstractSimHistory{NT} <: AbstractVector{NT} end

nt_type(::Type{H}) where H<:AbstractSimHistory{NT} where NT = NT
nt_type(h::AbstractSimHistory) = nt_type(typeof(h))

"""
    SimHistory

An (PO)MDP simulation history returned by `simulate(::HistoryRecorder, ::Union{MDP,POMDP},...)`.

This is an `AbstractVector` of [`NamedTuples`](https://docs.julialang.org/en/v1/manual/types/index.html#Named-Tuple-Types-1) containing the states, actions, etc.

# Examples
```
hist[1][:s] # returns the first state in the history
```
```
hist[:a] # returns all of the actions in the history
```
"""
struct SimHistory{NT} <: AbstractSimHistory{NT}
    hist::Vector{NT}

    discount::Float64

    # if an exception is captured, it will be stored here
    exception::Union{Nothing, Exception}
    backtrace::Union{Nothing, Any}
end

# accessors: use these to access the members - in case the implementation changes
n_steps(h::SimHistory) = length(h.hist)
hist(h::SimHistory) = h.hist

state_hist(h::AbstractSimHistory) = push!([step.s for step in hist(h)], last(hist(h)).sp)
action_hist(h::AbstractSimHistory) = h[:a]
observation_hist(h::AbstractSimHistory) = h[:o]
belief_hist(h::AbstractSimHistory) = push!([step.b for step in hist(h)], last(hist(h)).bp)
reward_hist(h::AbstractSimHistory) = h[:r]
info_hist(h::AbstractSimHistory) = h[:i]
ainfo_hist(h::AbstractSimHistory) = h[:action_info]
uinfo_hist(h::AbstractSimHistory) = h[:update_info]

exception(h::SimHistory) = h.exception
Base.backtrace(h::SimHistory) = h.backtrace
POMDPs.discount(h::SimHistory) = h.discount

undiscounted_reward(h::AbstractSimHistory) = sum(reward_hist(h))
function discounted_reward(h::AbstractSimHistory)
    disc = 1.0
    r_total = 0.0
    for r in h[:r]
        r_total += disc*r
        disc *= discount(h)
    end
    return r_total
end

# AbstractArray interface
Base.size(h::AbstractSimHistory) = (n_steps(h),)

Base.getindex(h::AbstractSimHistory, i::Int) = hist(h)[i]
Base.getindex(h::AbstractSimHistory, s::Symbol) = (step[s] for step in hist(h))

# SubHistory
const Inds = Union{AbstractRange,Colon,Real}
Base.view(h::AbstractSimHistory, inds::Inds) = SubHistory(h, inds)

struct SubHistory{NT, H<:AbstractSimHistory{NT}, I<:Inds} <: AbstractSimHistory{NT}
    parent::H
    inds::I
end

n_steps(h::SubHistory) = length(h.inds)
hist(h::SubHistory) = view(hist(h.parent), h.inds)

exception(h::SubHistory) = exception(h.parent)
Base.backtrace(h::SubHistory) = backtrace(h.parent)
POMDPs.discount(h::SubHistory) = discount(h.parent)

# iterators
struct HistoryIterator{H<:AbstractSimHistory, SPEC}
    history::H
end

hist(it::HistoryIterator) = it.history
spec(it::HistoryIterator) = typeof(it).parameters[2]

HistoryIterator(h::AbstractSimHistory, spec) = HistoryIterator{typeof(h), convert_spec(spec, POMDP)}(h)

"""
    for t in eachstep(hist, [spec])
        ...
    end

Iterate through the steps in `SimHistory` `hist`. `spec` is a tuple of symbols or string that controls what is returned for each step.

For example,
```julia
for (s, a, r, sp) in eachstep(h, "(s, a, r, sp)")
    println("reward \$r received when state \$sp was reached after action \$a was taken in state \$s")
end
```
returns the start state, action, reward and destination state for each step of the simulation.

Alternatively, instead of expanding the steps implicitly, the elements of the step can be accessed as fields (since each step is a `NamedTuple`):
```julia
for step in eachstep(h, "(s, a, r, sp)")
    println("reward \$(step.r) received when state \$(step.sp) was reached after action \$(step.a) was taken in state \$(step.s)")
end
```

The possible valid elements in the iteration specification are
- Any node in the (PO)MDP Dynamic Decision network (by default `:s`, `:a`, `:sp`, `:o`, `:r`)
- `b` - the initial belief in the step (for POMDPs only)
- `bp` - the belief after being updated based on `o` (for POMDPs only)
- `action_info` - info from the policy decision (from `action_info`)
- `update_info` - info from the belief update (from `update_info`)
- `t` - the timestep index
"""
eachstep(hist::AbstractSimHistory, spec) = HistoryIterator(hist, spec)
eachstep(mh::AbstractSimHistory) = mh

@generated function step_tuple(it::HistoryIterator{<:Any, SPEC}, i::Int) where SPEC
    # the only reason this is generated is to check for :ai and :ui - can get rid of in v0.4
    newspec = Meta.quot(fixdeps(SPEC))
    quote
        if isa($newspec, Tuple)
            return NamedTupleTools.select(hist(it)[i], $newspec)
        else
            @assert isa(spec(it), Symbol) "Output specification $(spec(it)) was not a Tuple or Symbol"
            return hist(it)[i][spec(it)]
        end
    end
end

Base.length(it::HistoryIterator) = n_steps(it.history)
Base.getindex(it::HistoryIterator, i) = step_tuple(it, i)
function Base.iterate(it::HistoryIterator, i::Int = 1)
    if i > length(it)
        return nothing
    else
        return (step_tuple(it, i), i+1)
    end
end


text:
export add_special_form, codegen!

SF = Dict{Symbol, Tuple{Int, Function}}() # Int is the number that desires. if arg num is less than that, continuation will be passed as the last argument

catch_continuation(::Token) = false
catch_continuation(x::S_Expr) = if SF[x.head][1] > length(x.args) + 1
    throw(ParseError("Too few arguments for $(x.head) expression"))
else
    SF[x.head][1] == length(x.args) + 1
end

macro gen(x)
    :(codegen!($x, scope))
end

function extend(f, scope, sym)
    unshift!(scope, sym)
    try
        f()
    finally
        shift!(scope)
    end
end

codegen!(x::Atom, scope) = all(x->x=='.', x.name) ? scope[length(x.name)] : Symbol(x.name)
codegen!(x::JuliaExpr, scope) = x.expr
codegen!(x::Affixed, scope) = error("unexpected " * string(x))
codegen!(x::Chained, scope) = Expr(:., @gen(x.base), QuoteNode(Symbol(x.suffix)))
codegen!(x::Curly, scope) = Expr(:curly, x.head, map(x->@gen(x), x.tail)...)
codegen!(x::S_Expr, scope) = SF[x.head][2](x.args, scope)
codegen!(x::S_Expr, scope, continuation) = begin
    push!(x.args, S_Expr("begin", continuation))
    @gen(x)
end

function sf_call(x, scope)
    isempty(x) && error("cannot do empty function call; if you need empty tuple, use `'()`")
    exp = Expr(:call)
    kw  = Expr(:parameters)

    i = 2
    while i <= length(x)
        if isa(x[i], Affixed)
            if x[i].affix == 0x00
                push!(exp.args, Expr(:..., @gen(x[i].token)))
            elseif x[i].affix == 0x01
                push!(kw.args, Expr(:..., @gen(x[i].token)))
            elseif x[i].affix == 0x02
                i+1 > length(x) && throw(ParseError("need argument after " * string(x[i])))
                push!(kw.args, Expr(:kw, @gen(x[i].token), @gen(x[i+1])))
                i += 1
            else
                error("BUG")
            end
        else
            push!(exp.args, @gen(x[i]))
        end
        i += 1
    end

    !isempty(kw.args) && unshift!(exp.args, kw)
    unshift!(exp.args, @gen(x[1]))
    exp
end

function sf_function(x, scope)
    exp = Expr(:function, Expr(:call))
    args = exp.args[1].args

    push!(args, @gen(shift!(x)))

    arg, kw, i = [], [], 1
    tokens = shift!(x).args
    while i <= length(tokens)
        a = tokens[i]
        if isa(a, Affixed)
            if a.affix == 0x00
                push!(arg, Expr(:..., gen_arg!(a.token, scope)))
            elseif a.affix == 0x01
                push!(kw, Expr(:..., gen_arg!(a.token, scope)))
            elseif a.affix == 0x02
                i+1 > length(tokens) && throw(ParseError("need argument after " * string(a)))
                b = tokens[i+1]
                unshift!(b.args, a.token)
                push!(kw, gen_arg!(b, scope))
                i += 1
            else
                error("BUG")
            end
        else
            push!(arg, gen_arg!(a, scope))
        end
        i += 1
    end

    if !isempty(kw)
        push!(args, Expr(:parameters, kw...))
    end

    append!(args, arg)

    push!(exp.args, sf_begin(x, scope))

    exp
end

function sf_begin(x, scope)
    exp = Expr(:block)
    while !isempty(x)
        i = shift!(x)
        if catch_continuation(i)
            push!(exp.args, codegen!(i, scope, x))
            break
        else
            push!(exp.args, codegen!(i, scope))
        end
    end
    exp
end

function sf_assign(x, scope)
    Expr(:(=), @gen(x[1]), @gen(x[2]))
end

function sf_tuple(x, scope)
    Expr(:tuple, map(x->@gen(x), x)...)
end

function sf_let(x, scope)
    Expr(:let, @gen(x[3]), sf_assign(x, scope))
end

function sf_if(x, scope)
    Expr(:if, map(x->@gen(x), x)...)
end

function sf_lambda(x, scope)
    if length(x) == 1
        this = gensym()
        extend(scope, this) do
            Expr(:->, Expr(:tuple, this), @gen(x[1]))
        end
    else
        args = []
        for i in x[1].args
            if isa(i, Affixed)
                if i.affix == 0x00
                    push!(arg, Expr(:..., gen_arg!(i.token, scope)))
                elseif i.affix == 0x01 || i.affix == 0x02
                    throw(ParseError("lambda expressions cannot accept keyword arguments"))
                else
                    error("BUG")
                end
            else
                push!(args, gen_arg!(i, scope))
            end
        end
        Expr(:->, Expr(:tuple, args...), @gen(x[2]))
    end
end

function sf_pipe(x, scope)
    this = gensym()
    exp  = Expr(:block, Expr(:(=), this, @gen(shift!(x))))
    extend(scope, this) do
        for i in x
            push!(exp.args, dispatch_pipe!(i, scope, this))
        end
    end
    exp
end

function sf_for(x, scope)
    if isa(x[2], Atom) && x[2].name in ("in", "∈")
        Expr(:for, sf_assign(x[[1,3]], scope), sf_begin(x[4:end], scope))
    else
        throw(ParseError("malformed for expression"))
    end
end

function sf_each(x, scope)
    this = gensym()
    body = extend(scope, this) do
        map(x->dispatch_pipe!(x, scope, this), x[2:end])
    end
    Expr(:for, Expr(:(=), this, @gen(x[1])), Expr(:block, body...))
end

function sf_while(x, scope)
    Expr(:while, @gen(x[1]), sf_begin(x[2:end], scope))
end

function sf_loop(x, scope)
    unshift!(x, JuliaExpr(true))
    sf_while(x, scope)
end

function sf_try(x, scope)
    e = gensym()
    extend(scope, e) do
        caught = @gen(x[2])
    end
    exp = Expr(:try, @gen(x[1]), e, caught)
    if length(x) == 3
        push!(exp.args, @gen(x[3]))
    end
    exp
end

function sf_cond(x, scope)
    cons(i) = if i+1 > length(x) # default
        @gen(x[i])
    elseif i+1 == length(x) # last
        Expr(:if, @gen(x[i]), @gen(x[i+1]))
    else
        Expr(:if, @gen(x[i]), @gen(x[i+1]), cons(i+2))
    end
    cons(1)
end

function sf_switch(x, scope)
    this = gensym()
    exp  = Expr(:block, Expr(:(=), this, @gen(x[1])))
    unshift!(scope, this)
    comp(x) = if isa(x, Affixed) && x.affix == 0x00
        sf_call(Token[Atom("=="), Atom("."), x.token], scope)
    else
        @gen(x)
    end
    cons(i) = if i+1 > length(x) # default
        @gen(x[i])
    elseif i+1 == length(x) # last
        Expr(:if, comp(x[i]), @gen(x[i+1]))
    else
        Expr(:if, comp(x[i]), @gen(x[i+1]), cons(i+2))
    end
    push!(exp.args, cons(2))
    shift!(scope)
    exp
end

function sf_return_star(x, scope)
    this = gensym()
    Expr(:block, Expr(:(=), this, @gen(x[1])), @gen(x[2]).args..., this)
end

function sf_macrodef(x, scope)
    Expr(:macro, Expr(:call, @gen(x[1]), map(x->@gen(x), x[2].args)...),
                 sf_begin(x[3:end], scope))
end

function sf_macrocall(x, scope)
    Expr(:macrocall, Symbol('@', x[1].name), map(x->@gen(x), x[2:end])...)
end

function sf_and(x, scope)
    cons(i) = if i == length(x)
        @gen(x[i])
    else
        Expr(:&&, @gen(x[i]), cons(i+1))
    end
    cons(1)
end

function sf_or(x, scope)
    cons(i) = if i == length(x)
        @gen(x[i])
    else
        Expr(:||, @gen(x[i]), cons(i+1))
    end
    cons(1)
end

function sf_break(x, scope)
    Expr(:break)
end

function sf_continue(x, scope)
    Expr(:continue)
end

function sf_return(x, scope)
    Expr(:return, length(x) == 0 ? nothing : @gen(x[1]))
end

function sf_type(x, scope)
    gen_type!(x, scope, true)
end

function sf_immutable(x, scope)
    gen_type!(x, scope, false)
end

function sf_abstract(x, scope)
    Expr(:abstract, @gen(x[1]))
end

function sf_range(x, scope)
    Expr(:(:), @gen(x[1]), @gen(x[2]))
end

function sf_local(x, scope)
    Expr(:local, map(x->@gen(x), x)...)
end

function sf_global(x, scope)
    Expr(:global, map(x->@gen(x), x)...)
end

function sf_const(x, scope)
    Expr(:const, sf_assign(x, scope))
end

function sf_module(x, scope)
    Expr(:module, true, @gen(x[1]), @gen(x[2]))
end

function sf_baremodule(x, scope)
    Expr(:module, false, @gen(x[1]), @gen(x[2]))
end

function sf_import(x, scope)
    toplevel(x, scope, :import)
end

function sf_importall(x, scope)
    toplevel(x, scope, :importall)
end

function sf_using(x, scope)
    toplevel(x, scope, :using)
end

function sf_ref(x, scope)
    Expr(:ref, map(x->@gen(x), x)...)
end

function sf_quote(x, scope)
    Expr(:quote, sf_begin(x, scope))
end

add_special_form(t, f, cps=0) = SF[t] = cps, f

add_special_form(Symbol("")        , sf_call)
add_special_form(:function         , sf_function)
add_special_form(:f                , sf_function)
add_special_form(:begin            , sf_begin)
add_special_form(:>                , sf_begin)
add_special_form(:assign           , sf_assign)
add_special_form(:(=)              , sf_assign)
add_special_form(:tuple            , sf_tuple)
add_special_form(Symbol("'")       , sf_tuple)
add_special_form(:let              , sf_let, 3)
add_special_form(:l                , sf_let, 3)
add_special_form(:if               , sf_if)
add_special_form(:?                , sf_if)
add_special_form(:lambda           , sf_lambda)
add_special_form(:λ                , sf_lambda)
add_special_form(:pipe             , sf_pipe)
add_special_form(:.                , sf_pipe)
add_special_form(:for              , sf_for,   4)
add_special_form(Symbol("∀")       , sf_for,   4)
add_special_form(:each             , sf_each)
add_special_form(:while            , sf_while, 2)
add_special_form(:loop             , sf_loop,  1)
add_special_form(:try              , sf_try)
add_special_form(:cond             , sf_cond)
add_special_form(:switch           , sf_switch)
add_special_form(Symbol("return*") , sf_return_star, 2)
add_special_form(:macrodef         , sf_macrodef)
add_special_form(:macro            , sf_macrodef)
add_special_form(:macrocall        , sf_macrocall)
add_special_form(Symbol("@")       , sf_macrocall)
add_special_form(:and              , sf_and)
add_special_form(:&                , sf_and)
add_special_form(:or               , sf_or)
add_special_form(:|                , sf_or)
add_special_form(:break            , sf_break)
add_special_form(:continue         , sf_continue)
add_special_form(:return           , sf_return)
add_special_form(:type             , sf_type)
add_special_form(:immutable        , sf_immutable)
add_special_form(:abstract         , sf_abstract)
add_special_form(:range            , sf_range)
add_special_form(:(:)              , sf_range)
add_special_form(:local            , sf_local)
add_special_form(:global           , sf_global)
add_special_form(:const            , sf_const)
add_special_form(:def              , sf_const)
add_special_form(:module           , sf_module,     2)
add_special_form(:baremodule       , sf_baremodule, 2)
add_special_form(:import           , sf_import)
add_special_form(:importall        , sf_importall)
add_special_form(:using            , sf_using)
add_special_form(:ref              , sf_ref)
add_special_form(:quote            , sf_quote)
add_special_form(Symbol("`")       , sf_quote)


text:
# AUTO GENERATED FILE - DO NOT EDIT

export ''_fefferysyntaxhighlighter

"""
    ''_fefferysyntaxhighlighter(;kwargs...)

A FefferySyntaxHighlighter component.

Keyword arguments:
- `id` (String; optional)
- `codeString` (String; required)
- `codeStyle` (String; optional)
- `language` (String; required)
- `loading_state` (optional): . loading_state has the following type: lists containing elements 'is_loading', 'prop_name', 'component_name'.
Those elements have the following types:
  - `is_loading` (Bool; optional): Determines if the component is loading or not
  - `prop_name` (String; optional): Holds which property is loading
  - `component_name` (String; optional): Holds the name of the component that is loading
- `showInlineLineNumbers` (Bool; optional)
- `showLineNumbers` (Bool; optional)
"""
function ''_fefferysyntaxhighlighter(; kwargs...)
        available_props = Symbol[:id, :codeString, :codeStyle, :language, :loading_state, :showInlineLineNumbers, :showLineNumbers]
        wild_props = Symbol[]
        return Component("''_fefferysyntaxhighlighter", "FefferySyntaxHighlighter", "feffery_utils_components", available_props, wild_props; kwargs...)
end

max_stars_repo_name: CNFeffery/feffery-utils-components

max_issues_repo_name: CNFeffery/feffery-utils-components

max_forks_repo_name: CNFeffery/feffery-utils-components


text:
using FEMfunctions

using LinearAlgebra
using SparseArrays

include("twodStokes.jl")

@test twodStokes(25)<1e-10


text:
import KnetLayers: IndexedDict

#####
##### Helper Functions for Base
#####

### TO-DO: Localization for all languages
"""
    TRtoLower(x::Char)
    TRtoLower(s::AbstractString)

    lowercase function for Turkish locale
"""
TRtoLower(x::Char) = x=='I' ? 'ı' : lowercase(x);
TRtoLower(s::AbstractString) = map(TRtoLower,s)

#####
##### IO and Vocabulary
#####

"""
    const specialTokens = (unk="❓", mask="⭕", eow="🏁", bow="🎬")
    unk: unknown inputs
    mask: mask token
    eow: end of word/sentence
    bow: beginning of word/sentence
"""
const specialTokens = (unk="❓", mask="⭕", eow="🏁", bow="🎬")

"""
    Vocabulary
    Vocabulary(sets::Array)

    General Vocabulary structure for models presented in Morse.

    Vocabulary can be created from sets of ParsedIO arrays.
"""
struct Vocabulary
    chars::IndexedDict{Char}
    tags::IndexedDict{String}
    comptags::IndexedDict{String}
    words::IndexedDict{String}
    specialTokens::NamedTuple
    specialIndices::NamedTuple
end

"""
    Analysis

    Analysis is structure that keeps morphological anlysis of a word
"""
struct Analysis
    lemma::Vector{Char}
    tags::Vector{String}
    isValid::Bool
end

"""
    EncodedAnalysis

    Encoded Analysis is structure that keeps morphological anlysis
    of a word with encoded fields.
"""
struct EncodedAnalysis
    lemma::Vector{Int}
    tags::Vector{Int}
    compositeTag::Int
    isValid::Bool
end

EncodedAnalysis(mask::Int, len::Int) = EncodedAnalysis(fill(mask,len), fill(mask,len), mask, true)
EncodedAnalysis(a::Analysis; v::Vocabulary) =
EncodedAnalysis(map(x->get(v.tags, string(x), v.specialIndices.unk)::Int, a.lemma),
                map(x->get(v.tags, x, v.specialIndices.unk)::Int, a.tags),
                get(v.comptags, join(a.tags,'+'), v.specialIndices.unk),
                a.isValid)

"""
    ParsedIO
    parseDataLine(line::AbstractString, p::Parser{MyDataSet}; wLemma=true, parseAll=false)

    ParsedIO keeps input and output of a single dataset line
    Input are `chars` of the word.
    Outputs are all possible `Analysis`s of tht word

    ParsedIO can be created from a dataset line, with `parseDataLine`
"""
struct ParsedIO
    chars::Vector{Char}
    analyses::Vector{Analysis}
    isAmbigous::Bool
end

"""
    EncodedIO
    EncodedIO(a::ParsedIO; v::Vocabulary)

    EncodedIO keeps input and output of a single dataset line
    Input are one hot encodings of the `chars` of the word.
    Outputs are all possible `EncodedAnalysis`s of that word

    `EncodedIO` can be created from a `ParsedIO` via a `Vocabulary`
"""
struct EncodedIO
    chars::Vector{Int}
    analyses::Vector{EncodedAnalysis}
    completeWord::Int
    isAmbigous::Bool
end

#Empty Outputs
EncodedIO(chars::Vector{Char}; v::Vocabulary, mask=1,len=20) =
    EncodedIO(map(x->get(v.chars, x, v.specialIndices.unk)::Int, chars),
              [EncodedAnalysis(v.specialIndices.unk,len)],
              get(v.words, join(chars), v.specialIndices.unk),
              false)

EncodedIO(a::ParsedIO; v::Vocabulary) =
    EncodedIO(map(x->get(v.chars, x, v.specialIndices.unk)::Int, a.chars),
              map(x->EncodedAnalysis(x;v=v), a.analyses),
              get(v.words, join(a.chars), v.specialIndices.unk),
              a.isAmbigous)

encode(data::Vector; v::Vocabulary) = encode.(data,v=v)
encode(s::Vector{ParsedIO}; v::Vocabulary) = EncodedIO.(s,v=v)

const StrDict  = Dict{String,Int}
const CharDict = Dict{Char,Int}

function Vocabulary(sets::Vector)
    char2ix, tag2ix, word2ix, ctag2ix=CharDict(), StrDict(), StrDict(), StrDict()

    for (i,T) in enumerate(specialTokens)
        get!(tag2ix,T,i); get!(word2ix,T,i); get!(ctag2ix,T,i)
        get!(char2ix,T[1],i);
    end
    specialIndicies = (unk=1, mask=2, eow=3, bow=4)

    for data in sets, sentence in data, par::ParsedIO in sentence
        for c::Char in par.chars
            get!(char2ix, c, length(char2ix)+1)
        end
        for a::Analysis in par.analyses
            for c::Char in a.lemma
                get!(tag2ix, string(c), length(tag2ix)+1)
            end
            get!(ctag2ix,join(a.tags,'+'),length(ctag2ix)+1)
        end
        get!(word2ix,join(par.chars),length(word2ix)+1)
    end

    for data in sets, sentence in data, par::ParsedIO in sentence
        for a::Analysis in par.analyses
            for t::String in a.tags
                get!(tag2ix,t,length(tag2ix)+1)
            end
        end
    end

    Vocabulary(IndexedDict(char2ix), IndexedDict(tag2ix),
               IndexedDict(ctag2ix), IndexedDict(word2ix),
               specialTokens, specialIndicies)
end

#####
##### DataSet and Parser
#####

"""
    DataSet

    Abstract type for datasets used in Morse
"""
abstract type DataSet; end
"""
    UDDataSet

    Universal Dependencies Dataset
"""
abstract type UDDataSet <: DataSet; end

"""
    TRDataSet

    TrMor dataset
"""
abstract type TRDataSet <: DataSet; end

const NString  = Union{Nothing,String}

"""
    Parser{T<:DataSet}

    Parser structure for datasets.
"""
struct Parser{MyDataSet}
    sentenceStart::String
    sentenceEnd::String
    partsSeperator::Char
    tagsSeperator::Char
    skipLines::Vector{String}
    unkToken::String
    dbToken::NString # derivational boundry
    tagValueSeperator::NString
end

Parser{UDDataSet}(v) =
    Parser{UDDataSet}("# text", " ", '\t', '|', ["#"],"_", nothing, "=")

Parser{TRDataSet}(v::Val{2018}) =
    Parser{TRDataSet}("<S", "</S", '\t', '+', ["<"], "?", "^DB", nothing) # "*UNKNOWN*" => "?"

Parser{TRDataSet}(v::Val{2016}) =
    Parser{TRDataSet}("<S", "</S", '\t', '+', ["<"], "*UNKNOWN*", "^DB", nothing)  # ' ' => '\t'

Parser{TRDataSet}(v::Val{2006}) = Parser{TRDataSet}(Val(2016))

"""
     parseDataLine(line::AbstractString, p::Parser{<:MyDataSet}; wLemma=true, parseAll)

     It parses a line from given dataset. Returns a ParsedIO object.

Keywords
========
     * wLemma = decision for adding lemma to the outputs.
     * parseAll = decision for adding all posible anlyses or the correct one
"""
function parseDataLine(line::AbstractString, p::Parser{TRDataSet}; wLemma=true, parseAll=false)
    tokens = split(line, p.partsSeperator)
    ParsedIO(collect(TRtoLower(tokens[1])),
             map(t->Analysis(t, p; wLemma=wLemma), tokens[2:(parseAll ? end : 2)]),
             length(tokens)>2);
end

function Analysis(analysis::AbstractString, p::Parser{TRDataSet}; wLemma=true)
    if occursin(p.unkToken,analysis) #unknown case
        lemma   = ""
        isValid = false
        tags    = String[specialTokens.unk]
    elseif occursin(p.tagsSeperator^2,analysis) # ++ case
        lemma   = string(p.tagsSeperator)
        isValid = true
        tags = String[split(analysis,p.tagsSeperator^2)[2]]
    else
        tokens  = split(analysis,p.tagsSeperator)
        lemma   = popfirst!(tokens)
        isValid	= true
        tags    = String[]
        for tag in tokens
            tag == "Prop" && continue # don't consider proper name tags
            if endswith(tag, p.dbToken)
                push!(tags, tag[1:end-length(p.dbToken)], p.dbToken)
            else
                push!(tags, tag)
            end
        end
    end
    lemmaOut = wLemma ? collect(TRtoLower(lemma)) : Char[]
    return Analysis(lemmaOut, tags, isValid)
end

function parseDataLine(line::AbstractString, p::Parser{UDDataSet}; wLemma=true, parseAll=false)
    tokens = split(line,p.partsSeperator)
    feats = tokens[6]
    occursin("-",first(tokens)) && return nothing
    if feats != p.unkToken
        tags = pushfirst!(split(feats,p.tagsSeperator),"Upos="*tokens[4])
    else
        tags = String["Upos="*tokens[4]]
    end
    lemmaOut = wLemma ? collect(lowercase(tokens[3])) : Char[]
    return ParsedIO(collect(lowercase(tokens[2])), [Analysis(lemmaOut , tags, true)], false)
end

"""
     parseFile(file::AbstractString; p::Parser, withLemma=true, parseAll)

It parses a file from given dataset. Returns a ParsedIO array.

Keywords
========
     * withLemma = decision for adding lemma to the outputs.
     * parseAll = decision for adding all posible anlyses or the correct one
"""
function parseFile(file::AbstractString; p::Parser, withLemma=true, parseAll=false)
    data = []
    sentence = ParsedIO[]
    for line in eachline(file)
        if startswith(line,p.sentenceStart)
            sentence = ParsedIO[]
        elseif isempty(line) || startswith(line,p.sentenceEnd)
           isempty(sentence) && continue # push!(data,sentence) #continue
           if any(a->a.analyses[1].isValid,sentence)
               push!(data,sentence)
           end
        elseif !any(startswith.(line,p.skipLines))
            parsedLine = parseDataLine(line, p; wLemma=withLemma, parseAll=parseAll)
            parsedLine !== nothing && push!(sentence,parsedLine)
        end
    end
    return data
end


text:
using BenchmarkTools
using CHull2D
using FixedSizeArrays
using PlotlyJS
using Polygons

# Create random points we want
function gen_random_points(N::Int, seed::Int=42)
    srand(seed)

    # Generate points
    x = randn(N, 2)

    # Create FixedSizeArrays.Point array
    x_pts = Point{2, Float64}[Point(x[i, 1], x[i, 2]) for i=1:N]

    return x, x_pts
end

N = 50_000
x, x_pts = gen_random_points(N, 5);

# Compute convex hull from Polygons
@time out = Polygons.grahamScan(x)
p_x = Polygon( pts = x )
@time out2 = Polygons.chull(p_x)

npts_polygons = size(out.pts, 1)
ep_polygons = out.pts
println("Polygons produced a convex hull with $npts_polygons points")

# Compute convex hull from CHull2D
ch = CHull2D.convexhull(x_pts)

npts_chull2d = length(ch.extremepoints)
ep_chull2d = Array(Float64, npts_chull2d, 2);
println("CHull2D produced a convex hull with $npts_chull2d points")

for i=1:npts_chull2d
    curr_pt = ch.extremepoints[i]
    ep_chull2d[i, 1] = curr_pt[1]
    ep_chull2d[i, 2] = curr_pt[2]
end

# Order them the same way
ep_polygons_s = sortrows(ep_polygons)
ep_chull2d_s = sortrows(ep_chull2d)

if npts_polygons == npts_chull2d
    maxdiff = maxabs(ep_chull2d_s - ep_polygons_s)
    println("The max difference in points is $maxdiff")
else
    println("Produced different number of points")
end

t1 = scatter(;x=ep_polygons[:, 1], y=ep_polygons[:, 2], mode="lines+markers")
t2 = scatter(;x=ep_chull2d[:, 1], y=ep_chull2d[:, 2], mode="lines+markers")

plot([t1, t2])

bPolygons = @benchmark Polygons.grahamScan(x)
bHybrid = @benchmark Polygons.chull(p_x)
bCHull2D = @benchmark CHull2D.convexhull(x_pts)

println("\n\nBenchmarking with Polygons")
println(bPolygons)
println("\n\nBenchmarking with Hybrid conversion")
println(bHybrid)
println("\n\nBenchmarking with CHull2D")
println(bCHull2D)


text:
function testfunc()
x = rand(10000, 1000)
y = std(x, 1)
return y
end

max_stars_repo_path: Module 2/Chapter02/testf.jl

max_issues_repo_path: Module 2/Chapter02/testf.jl

max_forks_repo_path: Module 2/Chapter02/testf.jl


text:
asdataframe(df::DataFrames.AbstractDataFrame) = df
asdataframe(table) = DataFrame(table)

const VegaLiteEltype = Union{AbstractString,Missing,Nothing,Number,Symbol}

function refineeltype(xs)
    if eltype(xs) <: VegaLiteEltype
        return xs
    else
        return identity.(xs)
    end
end

function Orihime.cleanup(table)
    df = asdataframe(table)
    size(df, 1) == 0 && return df

    # To use `eltype` below, refine `eltype` of all columns first:
    cols = map(refineeltype, eachcol(df))
    cnames = propertynames(df)

    idx = findall(c -> eltype(c) <: VegaLiteEltype , cols)
    df = DataFrame(cols[idx], cnames[idx])
    return df
end


text:
# This file is a part of Julia. License is MIT: https://julialang.org/license

module OperationsTest

import Random: randstring
import LibGit2
using Test
using UUIDs

using Pkg
using Pkg.Types

import Random: randstring
import LibGit2

include("utils.jl")

const TEST_PKG = (name = "Example", uuid = UUID("7876af07-990d-54b4-ab0e-23690620f79a"))

import Pkg.Types: semver_spec, VersionSpec
@testset "semver notation" begin
    @test semver_spec("^1.2.3") == VersionSpec("1.2.3-1")
    @test semver_spec("^1.2")   == VersionSpec("1.2.0-1")
    @test semver_spec("^1")     == VersionSpec("1.0.0-1")
    @test semver_spec("^0.2.3") == VersionSpec("0.2.3-0.2")
    @test semver_spec("^0.0.3") == VersionSpec("0.0.3-0.0.3")
    @test semver_spec("^0.0")   == VersionSpec("0.0.0-0.0")
    @test semver_spec("^0")     == VersionSpec("0.0.0-0")
    @test semver_spec("~1.2.3") == VersionSpec("1.2.3-1.2")
    @test semver_spec("~1.2")   == VersionSpec("1.2.0-1.2")
    @test semver_spec("~1")     == VersionSpec("1.0.0-1")
    @test semver_spec("1.2.3")  == semver_spec("^1.2.3")
    @test semver_spec("1.2")    == semver_spec("^1.2")
    @test semver_spec("1")      == semver_spec("^1")
    @test semver_spec("0.0.3")  == semver_spec("^0.0.3")
    @test semver_spec("0")      == semver_spec("^0")

    @test semver_spec("0.0.3, 1.2") == VersionSpec(["0.0.3-0.0.3", "1.2.0-1"])
    @test semver_spec("~1.2.3, ~v1") == VersionSpec(["1.2.3-1.2", "1.0.0-1"])

    @test   v"1.5.2"  in semver_spec("1.2.3")
    @test   v"1.2.3"  in semver_spec("1.2.3")
    @test !(v"2.0.0"  in semver_spec("1.2.3"))
    @test !(v"1.2.2"  in semver_spec("1.2.3"))
    @test   v"1.2.99" in semver_spec("~1.2.3")
    @test   v"1.2.3"  in semver_spec("~1.2.3")
    @test !(v"1.3"    in semver_spec("~1.2.3"))
    @test  v"1.2.0"   in semver_spec("1.2")
    @test  v"1.9.9"   in semver_spec("1.2")
    @test !(v"2.0.0"  in semver_spec("1.2"))
    @test !(v"1.1.9"  in semver_spec("1.2"))
    @test   v"0.2.3"  in semver_spec("0.2.3")
    @test !(v"0.3.0"  in semver_spec("0.2.3"))
    @test !(v"0.2.2"  in semver_spec("0.2.3"))
    @test   v"0.0.0"  in semver_spec("0")
    @test  v"0.99.0"  in semver_spec("0")
    @test !(v"1.0.0"  in semver_spec("0"))
    @test  v"0.0.0"   in semver_spec("0.0")
    @test  v"0.0.99"  in semver_spec("0.0")
    @test !(v"0.1.0"  in semver_spec("0.0"))

    @test semver_spec("<1.2.3") == VersionSpec("0.0.0 - 1.2.2")
    @test semver_spec("<1.2") == VersionSpec("0.0.0 - 1.1")
    @test semver_spec("<1") == VersionSpec("0.0.0 - 0")
    @test semver_spec("<2") == VersionSpec("0.0.0 - 1")
    @test semver_spec("<0.2.3") == VersionSpec("0.0.0 - 0.2.2")
    @test semver_spec("<2.0.3") == VersionSpec("0.0.0 - 2.0.2")
    @test   v"0.2.3" in semver_spec("<0.2.4")
    @test !(v"0.2.4" in semver_spec("<0.2.4"))

    @test semver_spec("=1.2.3") == VersionSpec("1.2.3")
    @test semver_spec("=1.2") == VersionSpec("1.2.0")
    @test semver_spec("  =1") == VersionSpec("1.0.0")
    @test   v"1.2.3" in semver_spec("=1.2.3")
    @test !(v"1.2.4" in semver_spec("=1.2.3"))
    @test !(v"1.2.2" in semver_spec("=1.2.3"))

    @test semver_spec("≥1.3.0") == semver_spec(">=1.3.0")

    @test semver_spec(">=   1.2.3") == VersionSpec("1.2.3-*")
    @test semver_spec(">=1.2  ") == VersionSpec("1.2.0-*")
    @test semver_spec("  >=  1") == VersionSpec("1.0.0-*")
    @test   v"1.0.0" in semver_spec(">=1")
    @test   v"0.0.1" in semver_spec(">=0")
    @test   v"1.2.3" in semver_spec(">=1.2.3")
    @test !(v"1.2.2" in semver_spec(">=1.2.3"))

    @test_throws ErrorException semver_spec("^^0.2.3")
    @test_throws ErrorException semver_spec("^^0.2.3.4")
    @test_throws ErrorException semver_spec("0.0.0")

    @test Pkg.Types.isjoinable(Pkg.Types.VersionBound((1,5)), Pkg.Types.VersionBound((1,6)))
    @test !(Pkg.Types.isjoinable(Pkg.Types.VersionBound((1,5)), Pkg.Types.VersionBound((1,6,0))))
end

# TODO: Should rewrite these tests not to rely on internals like field names
@testset "union, isjoinable" begin
    @test sprint(print, VersionRange("0-0.3.2")) == "0-0.3.2"
    # test missing paths on union! and isjoinable
    # there's no == for VersionBound or VersionRange
    unified_vr = union!([VersionRange("1.5-2.8"), VersionRange("2.5-3")])[1]
    @test unified_vr.lower.t == (UInt32(1), UInt32(5), UInt32(0))
    @test unified_vr.upper.t == (UInt32(3), UInt32(0), UInt32(0))
    unified_vr = union!([VersionRange("2.5-3"), VersionRange("1.5-2.8")])[1]
    @test unified_vr.lower.t == (UInt32(1), UInt32(5), UInt32(0))
    @test unified_vr.upper.t == (UInt32(3), UInt32(0), UInt32(0))
    unified_vr = union!([VersionRange("1.5-2.2"), VersionRange("2.5-3")])[1]
    @test unified_vr.lower.t == (UInt32(1), UInt32(5), UInt32(0))
    @test unified_vr.upper.t == (UInt32(2), UInt32(2), UInt32(0))
    unified_vr = union!([VersionRange("1.5-2.2"), VersionRange("2.5-3")])[2]
    @test unified_vr.lower.t == (UInt32(2), UInt32(5), UInt32(0))
    @test unified_vr.upper.t == (UInt32(3), UInt32(0), UInt32(0))
    unified_vb = Types.VersionBound(union!([v"1.5", v"1.6"])[1])
    @test unified_vb.t == (UInt32(1), UInt32(5), UInt32(0))
    unified_vb = Types.VersionBound(union!([v"1.5", v"1.6"])[2])
    @test unified_vb.t == (UInt32(1), UInt32(6), UInt32(0))
    unified_vb = Types.VersionBound(union!([v"1.5", v"1.5"])[1])
    @test unified_vb.t == (UInt32(1), UInt32(5), UInt32(0))
end

temp_pkg_dir() do project_path
    @testset "simple add and remove with preview" begin
        Pkg.activate(project_path)
        Pkg.add(TEST_PKG.name; preview = true)
        @test !isinstalled(TEST_PKG)
        Pkg.add(TEST_PKG.name)
        @test isinstalled(TEST_PKG)
        @eval import $(Symbol(TEST_PKG.name))
        @test_throws SystemError open(pathof(eval(Symbol(TEST_PKG.name))), "w") do io end  # check read-only
        Pkg.rm(TEST_PKG.name; preview = true)
        @test isinstalled(TEST_PKG)
        Pkg.rm(TEST_PKG.name)
        @test !isinstalled(TEST_PKG)
        # https://github.com/JuliaLang/Pkg.jl/issues/601
        pkgdir = joinpath(Pkg.depots1(), "packages")
        touch(joinpath(pkgdir, ".DS_Store"))
        Pkg.gc()
        rm(joinpath(pkgdir, ".DS_Store"))
        @test isempty(readdir(pkgdir))
    end

    @testset "package with wrong UUID" begin
        @test_throws ResolverError Pkg.add(PackageSpec(TEST_PKG.name, UUID(UInt128(1))))
    end

    @testset "adding and upgrading different versions" begin
        # VersionNumber
        Pkg.add(PackageSpec(TEST_PKG.name, v"0.3"))
        @test Pkg.API.__installed()[TEST_PKG.name] == v"0.3"
        Pkg.add(PackageSpec(TEST_PKG.name, v"0.3.1"))
        @test Pkg.API.__installed()[TEST_PKG.name] == v"0.3.1"
        Pkg.rm(TEST_PKG.name)

        # VersionRange
        Pkg.add(PackageSpec(TEST_PKG.name, VersionSpec(VersionRange("0.3.0-0.3.2"))))
        @test Pkg.API.__installed()[TEST_PKG.name] == v"0.3.2"
        # Check that adding another packages doesn't upgrade other packages
        Pkg.add("Test")
        @test Pkg.API.__installed()[TEST_PKG.name] == v"0.3.2"
        Pkg.update(; level = UPLEVEL_PATCH)
        @test Pkg.API.__installed()[TEST_PKG.name] == v"0.3.3"
        Pkg.update(; level = UPLEVEL_MINOR)
        @test Pkg.API.__installed()[TEST_PKG.name].minor != 3
        Pkg.rm(TEST_PKG.name)
    end

    @testset "testing" begin
        # TODO: Check that preview = true doesn't actually execute the test
        Pkg.add(TEST_PKG.name)
        Pkg.test(TEST_PKG.name; coverage=true)
        pkgdir = Base.locate_package(Base.PkgId(TEST_PKG.uuid, TEST_PKG.name))
        # No coverage files being generated?
        @test_broken TEST_PKG.name * ".cov" in readdir(pkgdir)
        Pkg.rm(TEST_PKG.name)
    end

    @testset "pinning / freeing" begin
        Pkg.add(TEST_PKG.name)
        old_v = Pkg.API.__installed()[TEST_PKG.name]
        Pkg.pin(PackageSpec(TEST_PKG.name, v"0.2"))
        @test Pkg.API.__installed()[TEST_PKG.name].minor == 2
        Pkg.update(TEST_PKG.name)
        @test Pkg.API.__installed()[TEST_PKG.name].minor == 2
        Pkg.free(TEST_PKG.name)
        Pkg.update()
        @test Pkg.API.__installed()[TEST_PKG.name] == old_v
        Pkg.rm(TEST_PKG.name)
    end

    @testset "develop / freeing" begin
        Pkg.add(TEST_PKG.name)
        old_v = Pkg.API.__installed()[TEST_PKG.name]
        Pkg.rm(TEST_PKG.name)
        mktempdir() do devdir
            withenv("JULIA_PKG_DEVDIR" => devdir) do
                @test_throws PkgError Pkg.develop(PackageSpec(url="bleh", rev="blurg"))
                Pkg.develop(TEST_PKG.name)
                @test isinstalled(TEST_PKG)
                @test Pkg.API.__installed()[TEST_PKG.name] > old_v
                test_pkg_main_file = joinpath(devdir, TEST_PKG.name, "src", TEST_PKG.name * ".jl")
                @test isfile(test_pkg_main_file)
                # Pkg #152
                write(test_pkg_main_file,
                    """
                    module Example
                        export hello, domath
                        const example2path = joinpath(@__DIR__, "..", "deps", "deps.jl")
                        if !isfile(example2path)
                            error("Example is not installed correctly")
                        end
                        hello(who::String) = "Hello, \$who"
                        domath(x::Number) = x + 5
                    end
                    """)
                mkpath(joinpath(devdir, TEST_PKG.name, "deps"))
                write(joinpath(devdir, TEST_PKG.name, "deps", "build.jl"),
                    """
                    touch("deps.jl")
                    """
                )
                Pkg.build(TEST_PKG.name)
                @test isfile(joinpath(devdir, TEST_PKG.name, "deps", "deps.jl"))
                Pkg.test(TEST_PKG.name)
                Pkg.free(TEST_PKG.name)
                @test Pkg.API.__installed()[TEST_PKG.name] == old_v
            end
        end
    end

    @testset "invalid pkg name" begin
        @test_throws PkgError Pkg.add(",sa..,--")
    end

    @testset "stdlibs as direct dependency" begin
        uuid_pkg = (name = "CRC32c", uuid = UUID("8bf52ea8-c179-5cab-976a-9e18b702a9bc"))
        Pkg.add("CRC32c")
        @test haskey(Pkg.API.__installed(), uuid_pkg.name)
        Pkg.update()
        # Disable until fixed in Base
        # Pkg.test("CRC32c")
        Pkg.rm("CRC32c")
    end

    @testset "package name in resolver errors" begin
        try
            Pkg.add(PackageSpec(;name = TEST_PKG.name, version = v"55"))
        catch e
            @test occursin(TEST_PKG.name, sprint(showerror, e))
        end
    end

    @testset "protocols" begin
        mktempdir() do devdir
            withenv("JULIA_PKG_DEVDIR" => devdir) do
                try
                    Pkg.setprotocol!("notarealprotocol")
                    @test_throws PkgError Pkg.develop("Example")
                    Pkg.setprotocol!("https")
                    Pkg.develop("Example")
                    @test isinstalled(TEST_PKG)
                finally
                    Pkg.setprotocol!()
                end
            end
        end
        mktempdir() do devdir
            withenv("JULIA_PKG_DEVDIR" => devdir) do
                try
                    https_url = "https://github.com/JuliaLang/Example.jl.git"
                    ssh_url = "ssh://git@github.com/JuliaLang/Example.jl.git"
                    @test Pkg.GitTools.normalize_url(https_url) == https_url
                    Pkg.setprotocol!("ssh")
                    @test Pkg.GitTools.normalize_url(https_url) == ssh_url
                    # TODO: figure out how to test this without
                    #       having to deploy a ssh key on github
                    #Pkg.develop("Example")
                    #@test isinstalled(TEST_PKG)
                finally
                    Pkg.setprotocol!()
                end
            end
        end
    end

    @testset "check logging" begin
        usage = Pkg.TOML.parse(String(read(joinpath(Pkg.logdir(), "manifest_usage.toml"))))
        manifest = Types.safe_realpath(joinpath(project_path, "Manifest.toml"))
        @test any(x -> startswith(x, manifest), keys(usage))
    end

    @testset "adding nonexisting packages" begin
        nonexisting_pkg = randstring(14)
        @test_throws PkgError Pkg.add(nonexisting_pkg)
        @test_throws PkgError Pkg.update(nonexisting_pkg)
    end

    Pkg.rm(TEST_PKG.name)

    @testset "legacy CI script" begin
        mktempdir() do dir
            LibGit2.with(LibGit2.clone("https://github.com/JuliaLang/Example.jl", joinpath(dir, "Example.jl"))) do r
                cd(joinpath(dir, "Example.jl")) do
                    let Pkg = Pkg
                        Pkg.clone(pwd())
                        Pkg.build("Example")
                        Pkg.test("Example"; coverage=true)
                        @test isfile(Pkg.dir("Example", "src", "Example.jl"))
                    end
                end
            end
        end
    end

    @testset "add julia" begin
        @test_throws PkgError Pkg.add("julia")
    end
end

temp_pkg_dir() do project_path
    @testset "libgit2 downloads" begin
        Pkg.add(TEST_PKG.name; use_libgit2_for_all_downloads=true)
        @test haskey(Pkg.installed(), TEST_PKG.name)
        @eval import $(Symbol(TEST_PKG.name))
        @test_throws SystemError open(pathof(eval(Symbol(TEST_PKG.name))), "w") do io end  # check read-only
        Pkg.rm(TEST_PKG.name)
    end

    @testset "up in Project without manifest" begin
        mktempdir() do dir
            cp(joinpath(@__DIR__, "test_packages", "UnregisteredWithProject"), joinpath(dir, "UnregisteredWithProject"))
            cd(joinpath(dir, "UnregisteredWithProject")) do
                with_current_env() do
                    Pkg.update()
                    @test haskey(Pkg.API.__installed(), "Example")
                end
            end
        end
    end
end

temp_pkg_dir() do project_path
    @testset "libgit2 downloads" begin
        Pkg.add(TEST_PKG.name; use_libgit2_for_all_downloads=true)
        @test haskey(Pkg.API.__installed(), TEST_PKG.name)
        Pkg.rm(TEST_PKG.name)
    end
    @testset "tarball downloads" begin
        Pkg.add("JSON"; use_only_tarballs_for_downloads=true)
        @test haskey(Pkg.API.__installed(), "JSON")
        Pkg.rm("JSON")
    end
end

@testset "parse package url win" begin
    @test typeof(Pkg.REPLMode.parse_package("https://github.com/abc/ABC.jl"; add_or_develop=true)) == PackageSpec
end

@testset "preview generate" begin
    mktempdir() do tmp
        cd(tmp) do
            Pkg.generate("Foo"; preview=true)
            @test !isdir(joinpath(tmp, "Foo"))
        end
    end
end

temp_pkg_dir() do project_path
    @testset "test should instantiate" begin
        mktempdir() do dir
            cp(joinpath(@__DIR__, "test_packages", "UnregisteredWithProject"), joinpath(dir, "UnregisteredWithProject"))
            cd(joinpath(dir, "UnregisteredWithProject")) do
                with_current_env() do
                    Pkg.add("Test") # test https://github.com/JuliaLang/Pkg.jl/issues/324
                    Pkg.test()
                end
            end
        end
    end
end

temp_pkg_dir() do project_path
    @testset "valid project file names" begin
        extract_uuid(toml_path) = begin
            uuid = ""
            for line in eachline(toml_path)
                m = match(r"uuid = \"(.+)\"", line)
                if m !== nothing
                    uuid = m.captures[1]
                    break
                end
            end
            return uuid
        end

        cd(project_path) do
            target_dir = mktempdir()
            uuid = nothing
            mktempdir() do tmp; cd(tmp) do
                pkg_name = "FooBar"
                # create a project and grab its uuid
                Pkg.generate(pkg_name)
                uuid = extract_uuid(joinpath(pkg_name, "Project.toml"))
                # activate project env
                Pkg.activate(abspath(pkg_name))
                # add an example project to populate manifest file
                Pkg.add("Example")
                # change away from default names
                ## note: this is written awkwardly because a `mv` here causes failures on AppVeyor
                cp(joinpath(pkg_name, "src"), joinpath(target_dir, "src"))
                cp(joinpath(pkg_name, "Project.toml"), joinpath(target_dir, "JuliaProject.toml"))
                cp(joinpath(pkg_name, "Manifest.toml"), joinpath(target_dir, "JuliaManifest.toml"))
            end end
            Pkg.activate()
            # make sure things still work
            Pkg.REPLMode.pkgstr("dev $target_dir")
            @test isinstalled((name="FooBar", uuid=UUID(uuid)))
            Pkg.rm("FooBar")
            @test !isinstalled((name="FooBar", uuid=UUID(uuid)))
        end # cd project_path
    end # @testset
end

temp_pkg_dir() do project_path
    @testset "invalid repo url" begin
        cd(project_path) do
            @test_throws PkgError Pkg.add("https://github.com")
            Pkg.generate("FooBar")
            @test_throws PkgError Pkg.add("./Foobar")
        end
    end
end

temp_pkg_dir() do project_path
    # pkg assumes `Example.jl` is still a git repo, it will try to fetch on `update`
    # `fetch` should warn that it is no longer a git repo
    with_temp_env() do
        @testset "inconsistent repo state" begin
            package_path = joinpath(project_path, "Example")
            LibGit2.with(LibGit2.clone("https://github.com/JuliaLang/Example.jl", package_path)) do repo
                Pkg.add(PackageSpec(path=package_path))
            end
            rm(joinpath(package_path, ".git"); force=true, recursive=true)
            @test_throws PkgError Pkg.update()
        end
    end
end

temp_pkg_dir() do project_path; cd(project_path) do
    tmp = mktempdir()
    depo1 = mktempdir()
    depo2 = mktempdir()
    cd(tmp) do; @testset "instantiating updated repo" begin
        empty!(DEPOT_PATH)
        pushfirst!(DEPOT_PATH, depo1)
        LibGit2.close(LibGit2.clone("https://github.com/JuliaLang/Example.jl", "Example.jl"))
        mkdir("machine1")
        cd("machine1")
        Pkg.activate(".")
        Pkg.add(PackageSpec(path="../Example.jl"))
        cd("..")
        cp("machine1", "machine2")
        empty!(DEPOT_PATH)
        pushfirst!(DEPOT_PATH, depo2)
        cd("machine2")
        Pkg.activate(".")
        Pkg.instantiate()
        cd("..")
        cd("Example.jl")
        open("README.md", "a") do io
            print(io, "Hello")
        end
        LibGit2.with(LibGit2.GitRepo(".")) do repo
            LibGit2.add!(repo, "*")
            LibGit2.commit(repo, "changes"; author=TEST_SIG, committer=TEST_SIG)
        end
        cd("../machine1")
        empty!(DEPOT_PATH)
        pushfirst!(DEPOT_PATH, depo1)
        Pkg.activate(".")
        Pkg.update()
        cd("..")
        cp("machine1/Manifest.toml", "machine2/Manifest.toml"; force=true)
        cd("machine2")
        empty!(DEPOT_PATH)
        pushfirst!(DEPOT_PATH, depo2)
        Pkg.activate(".")
        Pkg.instantiate()
    end end
    Base.rm.([tmp, depo1, depo2]; force = true, recursive = true)
end end

temp_pkg_dir() do project_path
    cd(project_path) do
        project = """
        [deps]
        UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

        [extras]
        Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
        Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

        [targets]
        test = ["Markdown", "Test"]
        """
        write("Project.toml", project)
        Pkg.activate(".")
        @testset "resolve ignores extras" begin
            Pkg.resolve()
            @test !(occursin("[[Test]]", read("Manifest.toml", String)))
        end
    end
end

@testset "dependency of test dependency (#567)" begin
    temp_pkg_dir() do project_path; cd_tempdir(;rm=false) do tmpdir; with_temp_env(;rm=false) do
        for x in ["x1", "x2", "x3"]
            cp(joinpath(@__DIR__, "test_packages/$x"), joinpath(tmpdir, "$x"))
            Pkg.develop(Pkg.PackageSpec(url = joinpath(tmpdir, x)))
        end
        Pkg.test("x3")
    end end end
end

@testset "printing of stdlib paths, issue #605" begin
    path = Pkg.Types.stdlib_path("Test")
    @test Pkg.Types.pathrepr(path) == "`@stdlib/Test`"
end

@testset "Set download concurrency" begin
    withenv("JULIA_PKG_CONCURRENCY" => 1) do
        ctx = Pkg.Types.Context()
        @test ctx.num_concurrent_downloads == 1
    end
end

temp_pkg_dir() do project_path
    @testset "Pkg.add should not mutate" begin
        package_names = ["JSON"]
        packages = PackageSpec.(package_names)
        Pkg.add(packages)
        @test [p.name for p in packages] == package_names
    end
end

@testset "manifest read/write unit tests" begin
    manifestdir = joinpath(@__DIR__, "manifest", "good")
    temp = joinpath(mktempdir(), "x.toml")
    for testfile in joinpath.(manifestdir, readdir(manifestdir))
        a = Types.read_manifest(testfile)
        Types.write_manifest(a, temp)
        b = Types.read_manifest(temp)
        for (uuid, x) in a
            y = b[uuid]
            for property in propertynames(x)
                @test getproperty(x, property) == getproperty(y, property)
            end
        end
    end
    rm(dirname(temp); recursive = true, force = true)
    @test_throws PkgError Types.read_manifest(
        joinpath(@__DIR__, "manifest", "bad", "parse_error.toml"))
end

@testset "project read/write unit tests" begin
    projectdir = joinpath(@__DIR__, "project", "good")
    temp = joinpath(mktempdir(), "x.toml")
    for testfile in joinpath.(projectdir, readdir(projectdir))
        a = Types.read_project(testfile)
        Types.write_project(a, temp)
        b = Types.read_project(temp)
        for property in propertynames(a)
            @test getproperty(a, property) == getproperty(b, property)
        end
    end
    rm(dirname(temp); recursive = true, force = true)
    @test_throws PkgError Types.read_project(
        joinpath(@__DIR__, "project", "bad", "parse_error.toml"))
end

@testset "stdlib_resolve!" begin
    a = Pkg.Types.PackageSpec(name="Markdown")
    b = Pkg.Types.PackageSpec(uuid=UUID("9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"))
    Pkg.Types.stdlib_resolve!(Types.Context(), [a, b])
    @test a.uuid == UUID("d6f4376e-aef5-505a-96c1-9c027394607a")
    @test b.name == "Profile"

    x = Pkg.Types.PackageSpec(name="Markdown", uuid=UUID("d6f4376e-aef5-505a-96c1-9c027394607a"))
    Pkg.Types.stdlib_resolve!(Types.Context(), [x])
    @test x.name == "Markdown"
    @test x.uuid == UUID("d6f4376e-aef5-505a-96c1-9c027394607a")
end

@testset "issue #913" begin
    temp_pkg_dir() do project_path
        Pkg.activate(project_path)
        Pkg.add(PackageSpec(name="Example", rev = "master"))
        @test isinstalled(TEST_PKG)
        rm.(joinpath.(project_path, ["Project.toml","Manifest.toml"]))
        Pkg.add(PackageSpec(name="Example", rev = "master")) # should not fail
        @test isinstalled(TEST_PKG)
    end
end

include("repl.jl")
include("api.jl")
include("registry.jl")

end # module


text:
# common array methods
for op in [:sum, :prod, :mean, :var, :std, :maximum, :minimum]
    @eval begin
        function ($op)(A::Array{Timestamp})
            # TODO add error catching if all timestamps are not either Date or DateTime
            # TODO add error catching if all values are not float or integer
            stamps = [as.timestamp for as in A]
            vals   = float([as.value for as in A])
            tdays  = maximum(stamps) - minimum(stamps)
            val    = ($op)(vals)
            Timestamp(tdays, val)
        end # function
    end # eval
end # loop


text:
# this will be overloaded in ./broadcast.jl
function broadcast_to end

mutable struct Sum <: DiffableFunction
    grad_field::GradField
    dims
    keepdims
    x_shape
    Sum(dims, keepdims) = new(GradField(), dims, keepdims, nothing)
end

function set_same_dim(x::R, n_dim) where R <: Real
    (ndims(x) > n_dim) && (throw(DimensionMismatch("ndims(x) = $(ndims(x)), but n_dim = $(n_dim). ndims(x) must be less than n_dim")))
    return reshape([x], (ones(Int, n_dim)...))
end

function set_same_dim(x::T, n_dim) where T <: AbstractArray
    (ndims(x) > n_dim) && (throw(DimensionMismatch("ndims(x) = $(ndims(x)), but n_dim = $(n_dim). ndims(x) must be less than n_dim")))
    return reshape(x, (size(x)..., ones(Int, n_dim - ndims(x))...))
end

# wrapper of Base.sum: this function enabales `Base.sum` to use dims, keepdims
function _sum(x; dims=nothing, keepdims=false)
    if dims isa Nothing
        result = Base.sum(x)
        if keepdims
            result = set_same_dim(result, ndims(x))
        end
    else
        result = Base.sum(x, dims=dims)
    end
    return result
end

function forward(f::Sum, x)
    f.x_shape = size(x)
    return _sum(x, dims=f.dims, keepdims=f.keepdims)
end

function backward(f::Sum, gy)
    return broadcast_to(gy, f.x_shape)
end

"""
    sum(x::Variable; dims=nothing, keepdims=false)

# Arguments
- keepdims
When true, the number of dimensions in the input and output arrays is guaranteed to match.

# Examples
```julia-repl
julia> x = Variable([1, 2, 3])
name: nothing
values: [1, 2, 3]
creator: User-Defined(nothing)

julia> y = sum(x)
name: nothing
values: 6
creator: JITrench.Sum

julia> x = Variable(rand(2, 2, 2))
name: nothing
values: [0.8036752887616154 0.918293421092931; 0.9092024610524445 0.8788506330169976]

[0.7726260228472543 0.6884237844746439; 0.38214845033860456 0.660455509851009]
creator: User-Defined(nothing)

julia> y = sum(x, keepdims=true)
name: nothing
values: [6.013675571435501]
creator: JITrench.Sum

julia> y.values
1×1×1 Array{Float64, 3}:
[:, :, 1] =
 6.013675571435501
```
"""
Base.sum(x::Variable; dims=nothing, keepdims=false) = Sum(dims, keepdims)(x)
is_support(::typeof(Base.sum)) = true


text:
using MLJBase
using OutlierDetection
using Statistics
using Test

import OutlierDetectionInterface
const OD = OutlierDetectionInterface

struct MinimalUnsupervised <: OD.UnsupervisedDetector end
struct MinimalSupervised <: OD.SupervisedDetector end
struct MinimalModel <: OD.DetectorModel end

score(X) = dropdims(mean(X, dims=1), dims=1)
OD.fit(_::MinimalUnsupervised, X::OD.Data)::OD.Fit = MinimalModel(), score(X)
OD.fit(_::MinimalSupervised, X::OD.Data, y::OD.Labels)::OD.Fit = MinimalModel(), score(X)
OD.transform(_::Union{MinimalSupervised, MinimalUnsupervised}, model::MinimalModel, X::OD.Data)::OD.Scores = score(X)

include("tests.jl")


text:
function plotfeatures(df::DataFrame, feature_name::String)
    sort!(df, feature_name)
    groupdf = groupby(df, :instance_name)
    plots = []
    for g in groupdf
        p = plot(g[!, feature_name], g[!, "solver.solving_time"], title=g[!, "instance_name"][1])
        push!(plots, p)
    end
    plot(plots...,
         layout=length(plots),
         size = (700, 700),
         xtickfontsize=5,
         ytickfontsize=5,
         titlefontsize=5,
         legend=false)
end

function plotfeatures_all(df::DataFrame)
    colnames = filter(col -> typeof(df[!,col]) == Vector{Float64},  names(df))
    plots = []
    for feature in colnames
        sort!(df, feature)
        p = plot(df[!, feature], df[!, "solver.solving_time"], title=feature)
        push!(plots, p)
    end
    plot(plots...,
         layout=length(plots),
         size = (700, 700),
         xtickfontsize=5,
         ytickfontsize=5,
         titlefontsize=5,
         legend=false)
end

function interact(df::DataFrame)
    w = Window()
    body!(w, dataviewer(df))
end

max_stars_repo_name: charlyalizadeh/OPFdecgen

max_issues_repo_name: charlyalizadeh/OPFdecgen

max_forks_repo_name: charlyalizadeh/OPFdecgen


text:
"""
All events subtyped from this need to be recorded under :simulation_status.
"""
abstract type AbstractSimulationStatusEvent <: IS.AbstractRecorderEvent end

struct SimulationStepEvent <: AbstractSimulationStatusEvent
    common::IS.RecorderEventCommon
    simulation_time::Dates.DateTime
    step::Int
    status::String
end

function SimulationStepEvent(
    simulation_time::Dates.DateTime,
    step::Int,
    status::AbstractString,
)
    return SimulationStepEvent(
        IS.RecorderEventCommon("SimulationStepEvent"),
        simulation_time,
        step,
        status,
    )
end

struct ProblemExecutionEvent <: AbstractSimulationStatusEvent
    common::IS.RecorderEventCommon
    simulation_time::Dates.DateTime
    step::Int
    model_name::Symbol
    status::String
end

function ProblemExecutionEvent(
    simulation_time::Dates.DateTime,
    step::Int,
    model_name::Symbol,
    status::AbstractString,
)
    return ProblemExecutionEvent(
        IS.RecorderEventCommon("ProblemExecutionEvent"),
        simulation_time,
        step,
        model_name,
        status,
    )
end

struct InitialConditionUpdateEvent <: IS.AbstractRecorderEvent
    common::IS.RecorderEventCommon
    simulation_time::Dates.DateTime
    initial_condition_type::String
    component_type::String
    device_name::String
    new_value::Float64
    previous_value::Float64
    model_name::String
end

function InitialConditionUpdateEvent(
    simulation_time,
    ic::InitialCondition,
    previous_value::Float64,
    model_name,
)
    return InitialConditionUpdateEvent(
        IS.RecorderEventCommon("InitialConditionUpdateEvent"),
        simulation_time,
        string(get_ic_type(ic)),
        string(get_component_type(ic)),
        get_component_name(ic),
        get_condition(ic),
        previous_value,
        string(model_name),
    )
end

struct ParameterUpdateEvent <: IS.AbstractRecorderEvent
    common::IS.RecorderEventCommon
    simulation_time::Dates.DateTime
    parameter_type::String
    component_type::String
    tag::String
    model_name::String
end

function ParameterUpdateEvent(
    parameter_type::Type{<:ParameterType},
    component_type::DataType,
    tag::String,
    simulation_time::Dates.DateTime,
    model_name::Symbol,
)
    return ParameterUpdateEvent(
        IS.RecorderEventCommon("ParameterUpdateEvent"),
        simulation_time,
        string(parameter_type),
        string(component_type),
        tag,
        string(model_name),
    )
end

function ParameterUpdateEvent(
    parameter_type::Type{<:ParameterType},
    component_type::DataType,
    attributes::TimeSeriesAttributes,
    simulation_time::Dates.DateTime,
    model_name::Symbol,
)
    return ParameterUpdateEvent(
        parameter_type,
        component_type,
        attributes.name,
        simulation_time,
        model_name,
    )
end

function ParameterUpdateEvent(
    parameter_type::Type{<:ParameterType},
    component_type::DataType,
    attributes::VariableValueAttributes,
    simulation_time::Dates.DateTime,
    model_name::Symbol,
)
    return ParameterUpdateEvent(
        parameter_type,
        component_type,
        # TODO: Store as string in the attributes to avoid interpolations
        encode_key_as_string(get_attribute_key(attributes)),
        simulation_time,
        model_name,
    )
end

function ParameterUpdateEvent(
    parameter_type::Type{<:ParameterType},
    component_type::DataType,
    attributes::CostFunctionAttributes,
    simulation_time::Dates.DateTime,
    model_name::Symbol,
)
    return ParameterUpdateEvent(
        parameter_type,
        component_type,
        # TODO: Store as string in the attributes to avoid interpolations
        string(get_variable_type(attributes)),
        simulation_time,
        model_name,
    )
end

struct StateUpdateEvent <: IS.AbstractRecorderEvent
    common::IS.RecorderEventCommon
    simulation_time::Dates.DateTime
    model_name::String
    state_type::String
end

function StateUpdateEvent(simulation_time::Dates.DateTime, model_name, state_type::String)
    return StateUpdateEvent(
        IS.RecorderEventCommon("StateUpdateEvent"),
        simulation_time,
        string(model_name),
        state_type,
    )
end

function get_simulation_step_range(filename::AbstractString, step::Int)
    events = IS.list_recorder_events(SimulationStepEvent, filename, x -> x.step == step)
    if length(events) != 2
        throw(
            ArgumentError(
                "$filename does not have two SimulationStepEvents for step = $step",
            ),
        )
    end

    if events[1].status != "start" || events[2].status != "done"
        throw(
            ArgumentError(
                "$filename does not contain start and done events for step = $step",
            ),
        )
    end

    return (start=events[1].simulation_time, done=events[2].simulation_time)
end

function get_simulation_model_range(filename::AbstractString, step::Int, model::String)
    events = IS.list_recorder_events(
        ProblemExecutionEvent,
        filename,
        x -> x.step == step && x.model_name == Symbol(model),
    )
    if length(events) != 2
        throw(
            ArgumentError(
                "$filename does not have two ProblemExecutionEvent for step = $step model = $model",
            ),
        )
    end

    if events[1].status != "start" || events[2].status != "done"
        throw(
            ArgumentError(
                "$filename does not contain start and done events for step = $step model = $model",
            ),
        )
    end

    return (start=events[1].simulation_time, done=events[2].simulation_time)
end

function _filter_by_type_range!(events::Vector{<:IS.AbstractRecorderEvent}, time_range)
    return filter!(
        x -> x.simulation_time >= time_range.start && x.simulation_time <= time_range.done,
        events,
    )
end

function _get_recorder_filename(output_dir, recorder_name)
    return joinpath(output_dir, "recorder", recorder_name * ".log")
end

function _get_simulation_status_recorder_filename(output_dir)
    return _get_recorder_filename(output_dir, "simulation_status")
end

function _get_simulation_recorder_filename(output_dir)
    return _get_recorder_filename(output_dir, "execution")
end

"""
    list_simulation_events(
        ::Type{T},
        output_dir::AbstractString,
        filter_func::Union{Nothing, Function} = nothing;
        step = nothing,
        model = nothing,
    ) where {T <: IS.AbstractRecorderEvent}

List simulation events of type T in a simulation output directory.

# Arguments

  - `output_dir::AbstractString`: Simulation output directory
  - `filter_func::Union{Nothing, Function} = nothing`: Refer to [`show_simulation_events`](@ref).
  - `step::Int = nothing`: Filter events by step. Required if model is passed.
  - `model::Int = nothing`: Filter events by model.
"""
function list_simulation_events(
    ::Type{T},
    output_dir::AbstractString,
    filter_func::Union{Nothing, Function}=nothing;
    step=nothing,
    model_name::Union{String, Nothing}=nothing,
) where {T <: IS.AbstractRecorderEvent}
    if model_name !== nothing && step === nothing
        throw(ArgumentError("step is required if model_name is passed"))
    end

    recorder_file = _get_simulation_recorder_filename(output_dir)
    events = IS.list_recorder_events(T, recorder_file, filter_func)

    if step !== nothing
        recorder_file = _get_simulation_status_recorder_filename(output_dir)
        step_range = get_simulation_step_range(recorder_file, step)
        _filter_by_type_range!(events, step_range)
    end

    if model_name !== nothing
        recorder_file = _get_simulation_status_recorder_filename(output_dir)
        model_range = get_simulation_model_range(recorder_file, step, model_name)
        _filter_by_type_range!(events, model_range)
    end

    return events
end

function list_simulation_events(
    ::Type{T},
    output_dir::AbstractString,
    filter_func::Union{Nothing, Function}=nothing;
    kwargs...,
) where {T <: AbstractSimulationStatusEvent}
    recorder_file = _get_simulation_status_recorder_filename(output_dir)
    return IS.list_recorder_events(T, recorder_file, filter_func)
end

"""
    show_simulation_events(
        ::Type{T},
        output_dir::AbstractString,
        filter_func::Union{Nothing,Function} = nothing;
        step = nothing,
        model = nothing,
        wall_time = false,
        kwargs...,
    ) where { T <: IS.AbstractRecorderEvent}

Show all simulation events of type T in a simulation output directory.

# Arguments

  - `::Type{T}`: Recorder event type
  - `output_dir::AbstractString`: Simulation output directory
  - `filter_func::Union{Nothing, Function} = nothing`: Refer to [`show_recorder_events`](@ref).
  - `step::Int = nothing`: Filter events by step. Required if model is passed.
  - `model::Int = nothing`: Filter events by model.
  - `wall_time = false`: If true, show the wall_time timestamp.
"""
function show_simulation_events(
    ::Type{T},
    output_dir::AbstractString,
    filter_func::Union{Nothing, Function}=nothing;
    step=nothing,
    model=nothing,
    wall_time=false,
    kwargs...,
) where {T <: IS.AbstractRecorderEvent}
    show_simulation_events(
        stdout,
        T,
        output_dir,
        filter_func;
        step=step,
        model=model,
        wall_time=wall_time,
        kwargs...,
    )
end

function show_simulation_events(
    ::Type{T},
    output_dir::AbstractString,
    filter_func::Union{Nothing, Function}=nothing;
    wall_time=false,
    kwargs...,
) where {T <: AbstractSimulationStatusEvent}
    show_simulation_events(
        stdout,
        T,
        output_dir,
        filter_func;
        wall_time=wall_time,
        kwargs...,
    )
end

function show_simulation_events(
    io::IO,
    ::Type{T},
    output_dir::AbstractString,
    filter_func::Union{Nothing, Function}=nothing;
    wall_time=false,
    kwargs...,
) where {T <: AbstractSimulationStatusEvent}
    events = list_simulation_events(T, output_dir, filter_func)
    show_recorder_events(io, events, filter_func; wall_time=wall_time, kwargs...)
end

function show_simulation_events(
    io::IO,
    ::Type{T},
    output_dir::AbstractString,
    filter_func::Union{Nothing, Function}=nothing;
    step=nothing,
    model_name::Union{String, Nothing}=nothing,
    wall_time=false,
    kwargs...,
) where {T <: IS.AbstractRecorderEvent}
    events =
        list_simulation_events(T, output_dir, filter_func; step=step, model_name=model_name)
    show_recorder_events(io, events, filter_func; wall_time=wall_time, kwargs...)
end

"""
    show_recorder_events(
        ::Type{T},
        filename::AbstractString,
        filter_func::Union{Nothing, Function} = nothing;
        wall_time = false,
        kwargs...,
    ) where {T <: IS.AbstractRecorderEvent}

Show the events of type T in a recorder file.

# Arguments

  - `::Type{T}`: Recorder event type
  - `filename::AbstractString`: recorder filename
  - `filter_func::Union{Nothing, Function} = nothing`: Optional function that accepts an event
    of type T and returns a Bool. Apply this function to each event and only return events
    where the result is true.
  - `wall_time = false`: If true, show the wall_time timestamp.
"""
function show_recorder_events(
    ::Type{T},
    filename::AbstractString,
    filter_func::Union{Nothing, Function}=nothing;
    wall_time=false,
    kwargs...,
) where {T <: IS.AbstractRecorderEvent}
    show_recorder_events(stdout, T, filename, filter_func; wall_time=wall_time, kwargs...)
end

function show_recorder_events(
    io::IO,
    ::Type{T},
    filename::AbstractString,
    filter_func::Union{Nothing, Function}=nothing;
    wall_time=false,
    kwargs...,
) where {T <: IS.AbstractRecorderEvent}
    if wall_time
        IS.show_recorder_events(io, T, filename, filter_func)
    else
        # This will not display the first column, 'timestamp'.
        f_c(data, i) = i > 1
        IS.show_recorder_events(io, T, filename, filter_func; filters_col=(f_c,), kwargs...)
    end
end

function show_recorder_events(
    io::IO,
    events::Vector{T},
    filter_func::Union{Nothing, Function}=nothing;
    wall_time=false,
    kwargs...,
) where {T <: IS.AbstractRecorderEvent}
    if wall_time
        IS.show_recorder_events(io, events; kwargs...)
    else
        # This will not display the first column, 'timestamp'.
        f_c(data, i) = i > 1
        IS.show_recorder_events(io, events; filters_col=(f_c,), kwargs...)
    end
end


text:
@testset "TestZTest" begin

    # OneSampleZTest tests
    # Loop over n, d, p, s, two_sided values
    # TODO: Test one-sided vs two-sided
    params = (
        (33.36712895331925, 0.5, 0.80, 0.05, false),
        (43.995480906737704, 0.5, 0.90, 0.05, false),
        (53.940614296961286, 0.5, 0.95, 0.05, false),
        (16, 0.7494656445134399, 0.8, 0.05, false),
        (32, 0.5112738234562735, 0.8, 0.05, false),
        (64, 0.35565012796825096, 0.8, 0.05, false),
        (16, 0.5, 0.46487, 0.05, false),
        (32, 0.5, 0.782276, 0.05, false),
        (64, 0.5, 0.9760556, 0.05, false),
    )

    for (n, d, p, s, one_sided) in params
        p_z = power(OneSampleZTest, n, d, 1.0, s, one_sided)
        p_t = power(OneSampleTTest, n, d, 1.0, s, one_sided)
        n_z = sample_size(OneSampleZTest, d, 1.0, p, s, one_sided)
        n_t = sample_size(OneSampleTTest, d, 1.0, p, s, one_sided)
        d_z = effect_size(OneSampleZTest, n, p, s, one_sided)
        d_t = effect_size(OneSampleTTest, n, p, s, one_sided)
        # TODO: Get non-stupid bounds here on gap between z-test and t-test
        @test 0.9 * p_z < p_t < p_z
        @test 0.8 * n_t < n_z < n_t
        @test 0.9 * d_t < d_z < d_t
    end

    # EqualVarianceZTest tests
    # Loop over n, d, p, s, two_sided values
    # TODO: Test one-sided vs two-sided
    params = (
        (63.76561019093564, 0.5, 0.80, 0.05, false),
        (85.03128413735288, 0.5, 0.90, 0.05, false),
        (104.92794298436287, 0.5, 0.95, 0.05, false),
        (16, 1.0236637440012688, 0.8, 0.05, false),
        (32, 0.7114799360863416, 0.8, 0.05, false),
        (64, 0.4990691779657755, 0.8, 0.05, false),
        (16, 0.5, 0.2777445, 0.05, false),
        (32, 0.5, 0.5036382, 0.05, false),
        (64, 0.5, 0.8014596, 0.05, false),
    )

    for (n, d, p, s, one_sided) in params
        p_z = power(EqualVarianceZTest, n, d, 1.0, s, one_sided)
        p_t = power(EqualVarianceTTest, n, d, 1.0, s, one_sided)
        n_z = sample_size(EqualVarianceZTest, d, 1.0, p, s, one_sided)
        n_t = sample_size(EqualVarianceTTest, d, 1.0, p, s, one_sided)
        d_z = effect_size(EqualVarianceZTest, n, p, s, one_sided)
        d_t = effect_size(EqualVarianceTTest, n, p, s, one_sided)
        # TODO: Get non-stupid bounds here on gap between z-test and t-test
        @test 0.9 * p_z < p_t < p_z
        @test 0.8 * n_t < n_z < n_t
        @test 0.9 * d_t < d_z < d_t
    end
end


text:
# This file was generated, do not modify it. # hide
using Gnuplot
x = -2π:0.001:2π
@gp(x, sin.(x), "w l t 'sin' lw 2 lc '#56B4E9'", "set grid",
    "set auto fix",
    "set offsets graph .05, graph .05, graph .05, graph .05",
    ylabel="Y label", xlabel="X label", title = "Title",
    "set key bottom left font ',12' title 'Legend' box 2",)
@gp(:-, x, cos.(x), "w l t 'cos' lw 1.5 dashtype 2 lc '#E69F00'")
save(term="pngcairo font 'Consolas, 12' size 600,400", output="plt2_ex5.png") # hide


text:
#=
# start of assignment 6 code
"""
count_records(path)

Given a path to a `fasta` file,
counts and returns the number of records it contains.

Example
≡≡≡≡≡≡≡≡≡
julia> count_records("data/cov2_genomes.fasta")
10
"""
function count_records(path)
## need a count
count = 0
for line in eachline(path)
    if startswith(line, '>')
        count = count + 1
    end
end

return count

end

"""
 fasta_header(header)

Divides a fasta header into its component parts,
removing any leading or trailing spaces.

Example
≡≡≡≡≡≡≡≡≡
 julia> fasta_header(">M0002 |China|Homo sapiens")
 ("M0002", "China", "Homo sapiens")

 julia> fasta_header("AAATTC")
 Error: Invalid header (headers must start with '>')

 julia> fasta_header(">Another sequence")
 ("Another sequence",)

 julia> fasta_header(">headers| can | have| any number | of | info blocks")
 ("headers", "can", "have", "any number", "of", "info blocks")
"""
function fasta_header(header)
 startswith(header, '>') || error("Invalid header (headers must start with '>')")

 ## Your code here
 splitVect = split(header[2:end], "|")
 returnTuple = ()
 for component in splitVect
     returnTuple = (returnTuple..., strip(component))
 end

 return returnTuple
end

"""
 function parse_fasta(path)

Reads a fasta-formated file and returns 2 vectors,
one containing parsed headers,
the other containing the entire sequence as a `String`.

Note: function does not validate DNA sequences for correctness.

Example
≡≡≡≡≡≡≡≡≡
 julia> ex1 = parse_fasta("data/ex1.fasta");

 julia> ex1 isa Tuple
 true

 julia> ex1[1]
 2-element Array{Tuple{String,String},1}:
   ("ex1.1", "easy")
   ("ex1.2", "multiline")

 julia> ex1[2]
 2-element Array{String,1}:
 "AATTATAGC"
 "CGCCCCCCAGTCGGATT"

 julia> ex2 = parse_fasta("data/ex2.fasta");

 julia> ex2[1]
 4-element Array{Tuple{String,String},1}:
   ("ex2.1", "oneper")
   ("ex2.2", "wrong")
   ("ex2.3", "wronger")
   ("ex2.4", "wrongest")

 julia> ex2[2]
 4-element Array{String,1}:
   "ATCCGT"
   "ATCGTGGaact"
   "ATCGTGGaact"
   "this isn't a dna string,but parse it anyway"
"""
function parse_fasta(path)
 ## Think through the components you need
 ## Does it make sense to define any containers at the beginning?
 ## How will you loop through the file?
 ## What do you need to get from each line?

 headersVect = Vector()
 seqVect = Vector()
 toBeCombined = Vector()

 for line in eachline(path)
     #@info "line is " line
     #@info "to be combined is" toBeCombined
     if startswith(line, '>')
         push!(headersVect, fasta_header(line))
         if size(toBeCombined,1) > 0
             push!(seqVect, join(toBeCombined))
             toBeCombined = Vector()
         end
     elseif line != ""
         push!(toBeCombined, line)

     end
     #@info "to be combined is" toBeCombined
 end
 push!(seqVect, join(toBeCombined))

 return (headersVect, seqVect)
end
# end of assignment 6
=#