text:
#=
JuMP helpers for constructing formulations for WSOS constraints
=#

# generate random polynomials nonegative on domain (may fail if domain not bounded)
function make_nonneg_polys(num::Int, Ps::Vector{Matrix{Float64}})
    # build JuMP model for finding minima (primal polymin)
    U = size(Ps[1], 1)
    K = Hypatia.WSOSInterpNonnegativeCone{Float64, Float64}(U, Ps)
    model = JuMP.Model(sep_hypatia)
    JuMP.@variable(model, a)
    JuMP.@objective(model, Max, a)
    con = JuMP.@constraint(model, ones(U) .- a in K)

    # generate polys
    return [make_nonneg_poly(U, model, con) for _ in 1:num]
end

function make_nonneg_poly(U::Int, model::JuMP.Model, con::JuMP.ConstraintRef)
    vals = Float64.(rand(0:9, U))
    MOI.modify(JuMP.backend(model), JuMP.index(con), MOI.VectorConstantChange(vals))

    JuMP.optimize!(model)
    stat = JuMP.termination_status(model)

    if stat in (MOI.OPTIMAL, MOI.ALMOST_OPTIMAL)
        # make poly nonnegative if minimum is negative
        min_val = JuMP.dual_objective_value(model)
        if min_val < 1e-5
            vals .+= abs(min_val)
        end
        return vals
    else
        # try again
        @warn("try again")
        return make_nonneg_poly(U, model, con)
    end
end

# find minimum value of a polynomial - solve primal polymin
function find_poly_min(vals::Vector{Float64}, Ps::Vector{Matrix{Float64}})
    U = size(Ps[1], 1)
    K = Hypatia.WSOSInterpNonnegativeCone{Float64, Float64}(U, Ps)
    model = JuMP.Model(sep_hypatia)
    JuMP.@variable(model, a)
    JuMP.@objective(model, Max, a)
    JuMP.@constraint(model, vals .- a in K)

    JuMP.optimize!(model)
    @assert JuMP.termination_status(model) in (MOI.OPTIMAL, MOI.ALMOST_OPTIMAL)
    return JuMP.dual_objective_value(model)
end

# check whether polynomial is nonnegative (actually SOS) - solve separation problem
function check_nonneg(vals::Vector{Float64}, Ps::Vector{Matrix{Float64}})
    U = size(Ps[1], 1)
    K = Hypatia.WSOSInterpNonnegativeCone{Float64, Float64}(U, Ps)
    model = JuMP.Model(sep_hypatia)
    JuMP.@constraint(model, vals in K)

    JuMP.optimize!(model)
    return (JuMP.termination_status(model) in (MOI.OPTIMAL, MOI.ALMOST_OPTIMAL))
end

# add a WSOS constraint
function add_wsos(
    use_nat::Bool,
    Ps::Vector{Matrix{Float64}},
    aff::AbstractVector{<:JuMPScalar},
    model::JuMP.Model,
)
    return (use_nat ? add_wsos_nat : add_wsos_ext)(Ps, aff, model)
end

# WSOS cone formulation
function add_wsos_nat(
    Ps::Vector{Matrix{Float64}},
    aff::AbstractVector{<:JuMPScalar},
    model::JuMP.Model,
)
    U = size(Ps[1], 1)
    @assert length(aff) == U
    K = Hypatia.WSOSInterpNonnegativeCone{Float64, Float64}(U, Ps)
    JuMP.@constraint(model, aff in K)
    return
end

# PSD extended formulation
function add_wsos_ext(
    Ps::Vector{Matrix{Float64}},
    aff::AbstractVector{<:JuMPScalar},
    model::JuMP.Model,
)
    U = size(Ps[1], 1)
    @assert length(aff) == U

    psd_vars = []
    for Pr in Ps
        Lr = size(Pr, 2)
        psd_r = JuMP.@variable(model, [1:Lr, 1:Lr], Symmetric)
        if Lr == 1
            JuMP.@constraint(model, psd_r[1, 1] >= 0)
        else
            JuMP.@constraint(model, psd_r in JuMP.PSDCone())
        end
        push!(psd_vars, psd_r)
    end

    coeffs_lhs = JuMP.@expression(
        model,
        [u in 1:U],
        sum(
            sum(
                Pr[u, k] * Pr[u, l] * psd_r[k, l] * (k == l ? 1 : 2) for
                k in 1:size(Pr, 2) for l in 1:k
            ) for (Pr, psd_r) in zip(Ps, psd_vars)
        )
    )
    JuMP.@constraint(model, coeffs_lhs .== aff)
    return
end


text:
using Documenter, RxNav

makedocs(sitename = "RxNav Module Documentation", format = Documenter.HTML(prettyurls = false))

ext: jl


text:
module HoltsLinearTrendTests

using Test

using TSeriesForecast: HLT, loss, fit, forecast

ϵ = 0.1

### Data

observations = [17.5534, 21.8601, 23.8866, 26.9293, 26.8885, 28.8314, 30.0751, 30.9535, 30.1857, 31.5797, 32.577569, 33.477398,
39.021581, 41.386432, 41.596552, 44.657324, 46.951775, 48.728837, 51.488427,50.026967, 60.640913, 63.3603103378,
66.355274, 68.197955, 68.1232376693, 69.7793454797, 72.597700806]

### Parameters

α = 0.830216559778346
β = 0.000100014855685128
l₀ = 15.5715222051655
b₀ = 2.10171710376136
h = 5

### Expected values

y_expected = [74.6013036045367, 76.7030432818444, 78.8047829591522, 80.90652263646, 83.0082623137678]

### Tests

@testset "Holts Linear Trend" begin
    @testset "HLT struct" begin

        @testset "HLT default constructor" begin
            model = HLT()
            @test model.α ≈ 0
            @test model.β ≈ 0
            @test model.l₀ ≈ 0
            @test model.b₀ ≈ 0
        end

        @testset "HLT parametric constructor" begin
            α = 0.5
            β = 0.2
            l₀ = 130.9
            b₀ = 20.3
            model = HLT(α, β, l₀, b₀)
            @test model.α ≈ α
            @test model.β ≈ β
            @test model.l₀ ≈ l₀
            @test model.b₀ ≈ b₀
        end

        @testset "HLT parametric constructor takes any Number type" begin
            α = Float32(0.2341)
            β = BigFloat(0.1112)
            l₀ = 345
            b₀ = 54.
            model = HLT(α, β, l₀, b₀)
            @test model.α ≈ α
            @test model.β ≈ β
            @test model.l₀ ≈ l₀
            @test model.b₀ ≈ b₀
        end
    end

    @testset "loss" begin
        # taken from R
        expected_mse = 4.76261989118118
        model = HLT(α, β, l₀, b₀)
        @test isapprox(loss(model, observations)/length(observations), expected_mse; atol=ϵ)
    end

    @testset "fit" begin
        y = observations

        starting_point = HLT()
        optimal_model = fit(starting_point, y)

        @test isapprox(optimal_model.α, α; atol=0.1)
        @test isapprox(optimal_model.β, β; atol=1)
        @test isapprox(optimal_model.l₀, l₀; atol=1)
        @test isapprox(optimal_model.b₀, b₀; atol=0.1)
    end

    @testset "forecast" begin
        model = HLT(α, β, l₀, b₀)
        @testset "The forecast is correct" begin
            @test isapprox(forecast(model, observations, h), y_expected; atol=ϵ)
        end

        @testset "forecast returns an array of length `h`" begin
            @test length(forecast(model, observations, 5)) == 5
        end
    end
end

end


text:
using Observers

# Series for π/4
f(k) = (-1)^(k+1)/(2k-1)

function my_iterative_function(niter; observer!, observe_step)
  π_approx = 0.0
  for n in 1:niter
    π_approx += f(n)
    if iszero(n % observe_step)
      update!(observer!; π_approx = 4π_approx, iteration = n)
    end
  end
  return 4π_approx
end

# Measure the relative error from π at each iteration
err_from_π(; π_approx, kwargs...) = abs(π - π_approx) / π

# Record which iteration we are at
iteration(; iteration, kwargs...) = iteration
obs = Observer(["Error" => err_from_π, "Iteration" => iteration])

niter = 10000
π_approx = my_iterative_function(niter; observer! = obs, observe_step = 1000)

@show π_approx
@show obs
@show results(obs, "Iteration")
@show results(obs, "Error")


text:
module ImageCoreTests

include("colorchannels.jl")
include("views.jl")
include("convert_reinterpret.jl")
include("traits.jl")
include("deprecated.jl")

# run these last
@test isempty(detect_ambiguities(ImageCore,Base,Core))
if Base.JLOptions().can_inline == 1
    include("benchmarks.jl")  # these fail if inlining is off
end

end


text:
using ArrayMeta
using Test

import ArrayMeta: indicesinvolved
@testset "utilities" begin
    @test indicesinvolved(:(A[i,j,k])) == [:A=>Any[:i,:j,:k]]
    @test indicesinvolved(:(A[i,j,k]+B[x,y,z])) == [:A=>Any[:i,:j,:k], :B=>[:x,:y,:z]]
    @test indicesinvolved(:(A[i,j,k] |> f)) == [:A=>Any[:i,:j,:k]]
end

import ArrayMeta: Indexing,Map,IndexSym,IndexConst, arraytype, ConstArg
@testset "Indexing" begin
    itr = Indexing([1], (IndexSym{:i}(),))
    @test eltype(typeof(itr)) == Int64
    @test arraytype(typeof(itr)) == Array{Int64,1}
end

@testset "Map" begin
    itr1 = Indexing([1], (IndexSym{:i}()))
    itr2 = Indexing([1.], (IndexSym{:j}()))
    map1 = Map(*, (itr1, itr2))
    map2 = Map(/, (ConstArg(1), itr1))
    @test eltype(typeof(map1)) == Float64
    @test eltype(typeof(map2)) == Float64
    @test arraytype(typeof(map1)) <: Array
end

import ArrayMeta: @lower, Assign

@testset "Lower" begin
    A = rand(2,2); B = rand(2,2); C = rand(2,2);
    i, j, k = [IndexSym{x}() for x in [:i,:j,:k]]
    # map
    @test @lower(A[i,j] = B[i,j]) == Assign(Indexing(A, (i, j)), Indexing(B, (i, j)))

    # transpose
    @test @lower(A[i,j] = B[j,i]) == Assign(Indexing(A, (i, j)), Indexing(B, (j, i)))

    # reduced over i:
    @test @lower(A[j] = B[j,i])   == Assign(Indexing(A, (j,)), Indexing(B, (j, i)))

    # reduced over i, output is reducedim
    @test @lower(A[1,j] = B[i,j]) == Assign(Indexing(A, (IndexConst{Int}(1), j)), Indexing(B, (i, j)))

    # reduce both dimensions, use * to reduce i and + to reduce j
    @test @lower(A[1,1] = B[i,j], *) == Assign(Indexing(A, (IndexConst{Int}(1), IndexConst{Int}(1))), Indexing(B, (i, j)), *, nothing)
end

import ArrayMeta: index_spaces
@testset "indexspaces" begin
    i,j,k=IndexSym{:i}(), IndexSym{:j}(), IndexSym{:k}()
    itr = Indexing(rand(10,10), (i,j))
    @test (index_spaces(:X, typeof(itr))|>string ==
        Dict{Any,Any}(:i=>Any[(Array{Float64, 2}, 1, :(X.array))],
                      :j=>Any[(Array{Float64, 2}, 2, :(X.array))]) |> string)

    a = Indexing(rand(10,10), (i,k))
    b = Indexing(rand(10,10), (k,j))

   #equality problems
   #@test index_spaces(:X, typeof(Map(*, (a, b)))) ==
   #    Dict{Any, Any}(:i => Any[(Array{Float64,2}, 1, :(X.Xs[1]))],
   #                   :k => Any[(Array{Float64,2}, 2, :(X.Xs[1])),
   #                             (Array{Float64,2}, 1, :(X.arrays[2]))],
   #                   :j => Any[(Array{Float64,2}, 2, :(X.arrays[2]))],
   #    )
end

import MacroTools: striplines
import ArrayMeta: kernel_expr

@testset "kernel_expr" begin
    @testset "Indexing" begin
        X = rand(2,2);
        testtype(x) = typeof(x.rhs)
        @test kernel_expr(:X, Array{Float64, 2}, testtype(@lower(X[i,j,k] = X[i,j,k])))|>string == :(X.array[i,j,k])|>string
        @test kernel_expr(:X, Array{Float64, 2}, testtype(@lower(X[i,j,1] = X[i,j,1])))|>string == :(X.array[i,j,X.idx[3].val])|>string
    end
    @testset "Map" begin
        X = rand(2,2);
        Y = rand(2,2);
        testtype(x) = typeof(x.rhs)
        @test kernel_expr(:X,Array{Float64,2}, testtype(@lower(X[i,j,k] = -Y[i,j,k])))|>string == :(X.f(X.arrays[1].array[i,j,k]))|>string
        @test kernel_expr(:X,Array{Float64,2}, testtype(@lower(X[i,j,k] = X[i,k,j]-Y[i,j,k])))|>string == :(X.f(X.arrays[1].array[i,k,j], X.arrays[2].array[i,j,k]))|>string
    end
end

using Dagger
import ArrayMeta: @arrayop

@testset "@arrayop" begin
    X = convert(Array, reshape(1:12, 4,3))

    Y = ones(3,4)

    # copy
    @test @arrayop(_[i,j] := X[i,j]) == X

    # transpose
    @test @arrayop(_[i,j] := X[j,i]) == X'

    # elementwise 1-arg
    @test @arrayop(_[i,j] := -X[i,j]) == -X

    # elementwise 2-args
    @test @arrayop(_[i,j] := X[i,j] + Y[j,i]) == X + Y'

    # elementwise with const
    #@test @arrayop(_[] := 2 * X[i,j])[] == sum(2.*X)

    # reduce default (+)
    @test @arrayop(_[] := X[i,j])[] == sum(X)

    # reduce with function
    @test @arrayop(_[] := X[i,j], *)[] == prod(X)

    # reducedim default (+)
    @test @arrayop(_[1, j] := X[i,j]) == sum(X, dims=1)
    @test @arrayop(_[i, 1] := X[i,j]) == sum(X, dims=2)

    # reducedim with function
    @test @arrayop(_[1, j] := X[i,j], *) == prod(X, dims=1)

    # broadcast
    y = [1, 2, 3, 4]
    @test @arrayop(_[i, j] := X[i, j] + y[i]) == X .+ y
    y = [1 2 3]
    @test @arrayop(_[i, j] := X[i, j] + y[1, j]) == X .+ y

    # matmul
    @test @arrayop(_[i, j] := X[i,k] * Y[k,j]) == X*Y
end

#=
Base.:(==)(a::ArrayMeta.DArray, b::Array) = collect(a) == b

@testset "@arrayop - Dagger" begin
    X = convert(Array, reshape(1:16, 4,4))
    dX = compute(Distribute(Blocks(2,2), X))

    Y = ones(4,4)
    dY = compute(compute(Distribute(Blocks(2,2), Y))')

    # copy
    @test @arrayop(_[i,j] := dX[i,j]) == X

    # transpose
    @test @arrayop(_[i,j] := dX[j,i]) == X'

    # elementwise 1-arg
    @test @arrayop(_[i,j] := -dX[i,j]) == -X

    # elementwise 2-args
    @test @arrayop(_[i,j] := dX[i,j] + dY[j,i]) == X + Y'

    # elementwise with const
    @test @arrayop(_[] := 2 * X[i,j])[] == sum(2.*X)

    # reduce default (+)
    @test collect(@arrayop(_[1,1] := dX[i,j])) |> first == sum(X)

    # reduce with function
    @test collect(@arrayop(_[1,1] := dX[i,j], *)) |> first == prod(X)

    # reducedim default (+)
    @test @arrayop(_[1, j] := dX[i,j]) == sum(X, dims=1)
    @test @arrayop(_[i, 1] := dX[i,j]) == sum(X, dims=2)

    # reducedim with function
    @test @arrayop(_[1, j] := dX[i,j], *) == prod(X, dims=1)

    # broadcast
    y = [1, 2, 3, 4]
    dy = compute(Distribute(Blocks(2), y))
    @test @arrayop(_[i, j] := dX[i, j] + dy[i]) == X .+ y
    y = [1 2 3 4]
    dy = compute(Distribute(Blocks(1,2), y))
    @test @arrayop(_[i, j] := dX[i, j] + dy[1, j], (+), 0.0) == X .+ y

    # matmul
    @test @arrayop(_[i, j] := dX[i,k] * dY[k,j], (+), 0.0) == X*Y
end
=#


text:
"""
psdplot(signal; fs = 1, maxf::Real = -1, method = "welch", order = 20)

Conviniently plots the power spectral density using one of two methods currently implemented in DSP.jl or a custom method using an AR model.
Futher plot parameters can be passed as keyword arguments.

# Args:

* 'signal::Vector': Data Vector containing te signal
* 'fs': Sample rate in Hz
* 'maxf': maximum frequency that shal be displayed
* 'method': Method for esitmation, either 'welch', 'ar' or 'fft'

"""
psdplot

@userplot PSDPlot
# psdplot(signal, fs; maxf = nothing, estimator = welch_pgram, kwargs...)
@recipe function f(p::PSDPlot; fs = 1, maxf::Real = -1, method = "welch", order = 20)
    y = (p.args[1]) .- mean(p.args[1]) # detrend/ remove dc component
    # Methods for estimation
    if method == "ar"
        psd = pyulear(vec(y), order, fs = fs)
    elseif method == "fft"
        psd = periodogram(vec(y), fs = fs)
        # psd.power[1] = psd.power[2]
    elseif method == "welch"
        psd = welch_pgram(vec(y), fs = fs)
    else
        throw(ArgumentError("Invalid method choosen. Supported are 'welch', 'fft' and 'yule'."))
    end

    # plot porps
    yaxis := :log
    title := "PSD"
    # legend := false
    xaxis := "f [Hz]"
    if maxf > 0
        xlims := (0, maxf)
    else
        xlims := (minimum(psd.freq), maximum(psd.freq))
    end
    @series begin
        psd.freq, psd.power
    end
end

# Get PSD from AR process with variance σ² (Burg 1967)
function S(f::Number, σ::Number, φ::Vector{<:Number})
    indices = 1:length(φ)
    sumXes = sum(φ .* exp.(-2im * pi * f * indices))
    return 2σ^2 / abs2(1 + (sumXes))
end

"""
pyulear(x::Vector{<:Number}, order::Int)

Matlab Äquivalent von pyulear. Bestimme das Spektrum parametrisch mittels Yule-Walker-Gleichungen

# Args
* 'x::Vector{<:Number}': Zeitreihe aus der das Spektrum bestimmt werden soll
* 'order::Int': Ordnung des zugrundeliegenden AR Modells

# Keyword Args
* 'fs::Real = 1' Sampling frequency to get the power at the respective frequencies
"""
function pyulear(x::Vector{<:Real}, order::Int; fs::Real = 1, Δf = 0.001)
    f = 0:Δf:0.5
    fReal = range(0, stop = fs/2, length = length(f))
    # fit ar model
    (a,g) = lpc(x, order)
    # estimate spectrum
    Sar(x) = S(x, sqrt(g), a)
    power = Sar.(f)
    return DSP.Periodograms.Periodogram(power, fReal)
end

"""
getSpectralComponent(signal::Vector{<:Real}, f_range::Tuple{<:Real, <:Real}; method::String = "ar", Δf::Real = 0.001, order::Int = 10)

Get the spectral power of a certain frequency range, in natural frequencies, using different methods ['ar', 'fft', 'welch'].

# Args:

* 'signal::Vector{<:Real}': The signal that is to be decomposed.
* 'f_range::Tuple{<:Real, <:Real}': The frequency range of interest in natural frequencies [0, 0.5].

# Kwargs

* 'method::String = "ar"': Method used for psd  estimation. Choose from 'ar', 'fft' and 'welch'.
* 'Δf::Real = 0.001': Only relevant for method ar, definfes distance of the grid of the underlying integration
* 'order::Int = 10': Only relevant for method ar, defines the order of the ar model

# Examples

```julia
julia> getSpectralComponent(signal, (0.1, 0.4))
```
"""
function getSpectralComponent(signal::Vector{<:Real}, f_range::Tuple{<:Real, <:Real}; method::String = "ar", Δf::Real = 0.001, order::Int = 10)
    0.0 <= f_range[1] < f_range[2] <= 0.5 || throw(DomainError("Start of range ($(f_range[1])) has to be smaller than end ($(f_range[2])) And in range of 0:0.5."))
    if method == "ar"
        psd = pyulear(signal, order, Δf = Δf)
    elseif method == "fft"
        psd = periodogram(signal)
        Δf = psd.freq[2] - psd.freq[1]
    elseif method == "welch"
        psd = welch_pgram(signal)
        Δf = psd.freq[2] - psd.freq[1]
    else
        throw(DomainError("Valid methods are: 'ar', 'fft' & 'welch'."))
    end
    pow = sum(Δf .* psd.power[findall(x -> f_range[1] <= x <= f_range[2], psd.freq)])
    return pow
end

"""
getSpectralComponentAR(ar::Union{ControlSystems.TransferFunction, AbstractVector}, f_range::Tuple{<:Real, <:Real}; σ::Real = 1,  Δf::Real = 0.001)

Get the spectral power of a certain frequency range, in natural frequencies, using different methods ['ar', 'fft', 'welch'].

# Args:

* 'ar::Union{ControlSystems.TransferFunction, AbstractVector}': Fitted AR model that schal be decomposed .
* 'f_range::Tuple{<:Real, <:Real}': The frequency range of interest in natural frequencies [0, 0.5].

# Kwargs

* 'Δf::Real = 0.001': Only relevant for method ar, definfes distance of the grid of the underlying integration
* 'σ::Real = 1': sqrt(innovation variance / prediction error)

# Examples

```julia
julia> getSpectralComponent(ar(iddata(signal), 10), (0.1, 0.4))
```
"""
function getSpectralComponentAR(ar::Union{ControlSystems.TransferFunction, AbstractVector}, f_range::Tuple{<:Real, <:Real}; σ::Real = 1,  Δf::Real = 0.001)
    0.0 <= f_range[1] < f_range[2] <= 0.5 || throw(DomainError("Start of range ($(f_range[1])) has to be smaller than end ($(f_range[2])) And in range of 0:0.5."))
    if typeof(ar) <: ControlSystems.TransferFunction
        arcoef = denvec(ar)[1]
        arcoef = arcoef[2:end]
    elseif typeof(ar) <: AbstractVector
        arcoef = ar
    end
    f = 0:Δf:0.5
    Sar(x) = S(x, σ, arcoef)
    power = Sar.(f)
    pow = sum(Δf .* power[findall(x -> f_range[1] <= x <= f_range[2], f)])
    return pow
end


text:
using StochasticPointProcess
using Test

@testset "StochasticPointProcess.jl" begin
    # Write your tests here.
end

max_stars_repo_name: yukki-jpn/JuliaTSA

max_issues_repo_name: yukki-jpn/JuliaTSA

max_forks_repo_name: yukki-jpn/JuliaTSA


text:
const _default_input_file_name = "OMOP-CDM-sql-server-ddl.txt"
const _default_input_file_path = joinpath(dirname(dirname(dirname(@__FILE__))), "assets", _default_input_file_name)

"""
Generate the code for OMOPCommonDataModel from the DDL.
"""
@inline function generate(; input_file = _default_input_file_path,
                            output_file = "autogenerated.jl",
                            string_casing::F = pascalcase,
                            export_structs::Bool = true,
                            make_all_fields_optional::Bool = false,
                            struct_keyword = "struct") where F
    input_file_abspath = abspath(input_file)
    output_file_abspath = abspath(output_file)
    @info("Reading from input file \"$(input_file_abspath)\"")
    input_file_contents = read(input_file_abspath, String)
    mkpath(dirname(output_file_abspath))
    contents = _generate(input_file_contents;
                         export_structs = export_structs,
                         make_all_fields_optional = make_all_fields_optional,
                         string_casing = string_casing,
                         struct_keyword = struct_keyword)
    mkpath(dirname(output_file_abspath))
    rm(output_file_abspath; force = true, recursive = true)
    open(output_file_abspath, "w") do io
        println(io, contents)
    end
    @info("Wrote to output file \"$(output_file_abspath)\"")
    return output_file_abspath
end

@inline function _generate(input_file_contents::AbstractString;
                           string_casing::F,
                           export_structs::Bool,
                           make_all_fields_optional,
                           struct_keyword)::String where F
    pattern = r"CREATE TABLE ([\w_]*?)[ ]?[\n]?\(([\s\S]*?\n)\s?\s?\s?\s?\s?\s?\)\n;"
    all_match_positions = findall(pattern, input_file_contents)
    all_match_strings = String[input_file_contents[position] for position in all_match_positions]
    all_type_lines = String[
        _generate_single_type(pattern,
                              str;
                              export_structs = export_structs,
                              make_all_fields_optional = make_all_fields_optional,
                              string_casing = string_casing,
                              struct_keyword = struct_keyword) for str in all_match_strings
    ]
    num_generated_types = length(all_type_lines)
    output_lines = vcat(
        String["import Dates"],
        String["import DocStringExtensions"],
        all_type_lines,
    )
    output = join(output_lines, "\n\n\n")
    @info("Generated $(num_generated_types) types")
    return output
end

@inline function _generate_export_statement(structname::AbstractString,
                                            export_structs::Bool)::String
    if export_structs
        return "export $(structname)"
    else
        return ""
    end
end

@inline function _generate_single_type(pattern,
                                       str;
                                       string_casing::F,
                                       export_structs::Bool,
                                       make_all_fields_optional::Bool,
                                       struct_keyword)::String where F
    m = match(pattern, str)
    cdmname = m[1]
    _cdmname = strip(cdmname)
    _cdmname_lowercase = lowercase(_cdmname)
    _cdmname_uppercase = uppercase(_cdmname)
    @debug("Attempting to create a Julia type for the OMOP CDM table \"$(cdmname)\"")
    structname = string_casing(_cdmname)
    fields = String[]
    fieldcontentsraw = m[2]
    lines = strip.(split(strip(fieldcontentsraw), "\n"))
    for line in lines
        _line = strip(line)
        if length(_line) > 0
            field = _generate_single_field(_line;
                                           make_all_fields_optional = make_all_fields_optional)
            push!(fields, field)
        end
    end
    export_statement = _generate_export_statement(structname, export_structs)

    output_lines = vcat(
        String[export_statement],
        String[""],
        String["\"\"\""],
        String["CDM table name: $(_cdmname_uppercase)"],
        String[""],
        String["Julia struct name: $(structname)"],
        String[""],
        String["\$(DocStringExtensions.TYPEDEF)"],
        String["\$(DocStringExtensions.TYPEDFIELDS)"],
        String["\"\"\""],
        String["Base.@kwdef $(struct_keyword) $(structname) <: CDMType"],
        fields,
        String["end"],
    )
    output = join(output_lines, "\n")
    @debug("The OMOP CDM table \"$(cdmname)\" will become the Julia struct `$(structname)`")
    return output
end

@inline function _generate_single_field(line;
                                        make_all_fields_optional::Bool)::String
    _line = strip(line)
    pattern = r"^([\"\w]*)\s[\s]*([\w\d\(\)]*)\s[\s]*([\w ]*),?$"
    m = match(pattern, _line)
    field_name = m[1]
    _field_name = strip(strip(strip(field_name), Char['\"']))
    field_cdm_type = m[2]
    field_null_or_notnull = m[3]
    field_partialtype = _cdm_type_to_julia_partialtype(field_cdm_type)
    field_fulltype = _generate_full_fieldtype(field_partialtype,
                                              field_null_or_notnull;
                                              make_all_fields_optional = make_all_fields_optional)
    result = "    $(strip(_field_name))::$(strip(field_fulltype))"
    return result
end

@inline function _cdm_type_to_julia_partialtype(cdm_type)::String
    varchar_pattern = r"^varchar\([\d]*?\)$"i
    _cdm_type = lowercase(strip(cdm_type))
    if _cdm_type == "integer"
        return "Int"
    elseif _cdm_type == "date"
        return "Dates.DateTime"
    elseif _cdm_type == "datetime2"
        return "Dates.DateTime"
    elseif _cdm_type == "float"
        return "Float64"
    elseif _cdm_type == "varchar(max)"
        return "String"
    elseif occursin(varchar_pattern, _cdm_type)
        return "String"
    end
    throw(ArgumentError("Invalid value for cdm_type: $(cdm_type)"))
end

@inline function _generate_full_fieldtype(partial_fieldtype,
                                          null_or_notnull;
                                          make_all_fields_optional::Bool)::String
    _null_or_notnull = strip(null_or_notnull)
    if _null_or_notnull == "NULL"
        return "Union{$(partial_fieldtype), Missing} = missing # optional"
    elseif _null_or_notnull == "NOT NULL"
        if make_all_fields_optional
            return "Union{$(partial_fieldtype), Missing} = missing # required"
        else
            return "$(partial_fieldtype) # required"
        end
    end
    throw(ArgumentError("Invalid value for `null_or_notnull`: $(null_or_notnull)"))
end


text:
function clisatsubregion(
    productID::AbstractString, date::TimeType;
    path::AbstractString="",
    region::AbstractString="GLB",
    overwrite::Bool=false
)

    if path == ""; dataroot = clisatroot(productID);
    else;          dataroot = clisatroot(productID,path);
    end
    rinfo = gregioninfoload(); isgeoregion(region,rinfo);

    info = Dict{Any,Any}("root"=>dataroot); clisatinfo!(info,productID);

    parent = gregionparent(region); isgeoregion(parent,rinfo);

    @info "$(Dates.now()) - Extracting $(info["source"]) $(info["product"]) data for the entire $(gregionfullname(region)) region ..."

    if !isdir(clisatregfol(info,parent))
        error("$(Dates.now()) - No data has been downloaded from $(info["source"]) $(info["product"]) in the parent region: $(gregionfullname(parent))")
    end

    folp = clisatrawfol(info,date,parent);
    fncp = joinpath(folp,clisatrawname(info,date,parent));
    if !isdir(folp)
        error("$(Dates.now()) - There is no data for $(info["source"]) $(info["product"]) for $(yrmo2dir(dateii)) in the parent region: $(gregionfullname(parent))")
    end

    pds  = Dataset(fncp,"r");
    plon = pds["longitude"].var[:]; plat = pds["latitude"].var[:];
    time = pds["time"].var[:];

    rlon,rlat,rinfo = gregiongridvec(region,plon,plat); iWE,iNS = rinfo["IDvec"];
    nlon = length(rlon); nlat = length(rlat); nt = length(time);
    nvar = length(info["variable"]);

    var_var = Vector{AbstractString}(undef,nvar)
    att_var = map(x->Dict(),1:nvar)

    for ii = 1 : nvar
        var_var[ii]                  = info["varID"][ii];
        att_var[ii]["units"]         = info["units"][ii];
        att_var[ii]["standard_name"] = info["standard"][ii];
        att_var[ii]["long_name"]     = info["variable"][ii];
        att_var[ii]["scale_factor"]  = info["scale"][ii];
        att_var[ii]["add_offset"]    = info["offset"][ii];
        att_var[ii]["missing_value"] = -32768;
    end

    att_lon = pds["longitude"].attrib;
    att_lat = pds["latitude"].attrib;
    att_t   = pds["time"].attrib;

    folr = clisatrawfol(info,date,region);
    fncr = joinpath(folr,clisatrawname(info,date,region));

    if isfile(fncr)
        @info "$(Dates.now()) - Stale NetCDF file $(fncr) detected.  Overwriting ..."
        rm(fncr);
    end

    ## Write data here

    @debug "$(Dates.now()) - Creating $(info["source"]) $(info["product"]) netCDF file $(fncr) ..."

    ds = Dataset(fncr,"c");
    ds.dim["longitude"] = nlon; ds.dim["latitude"] = nlat; ds.dim["time"] = nt;

    @debug "$(Dates.now()) - Saving $(info["source"]) $(info["product"]) data to netCDF file $(fncr) ..."

    if nvar != 1
        for ii = 1 : nvar
            v = defVar(ds,var_var[ii],Int16,("longitude","latitude","time"),
                       attrib=att_var[ii]);
            v.var[:] = pds[var_var[ii]].var[iWE,iNS,:];
        end
    else;
        v = defVar(ds,var_var[1],Int16,("longitude","latitude","time"),attrib=att_var[1]);
        v.var[:] = pds[var_var[1]].var[iWE,iNS,:];
    end

    defVar(ds,"longitude",rlon,("longitude",),attrib=att_lon)
    defVar(ds,"latitude",rlat,("latitude",),attrib=att_lat)
    defVar(ds,"time",time,("time",),attrib=att_t)

    close(ds); close(pds);

    ## Write data end

    @info "$(Dates.now()) - $(info["source"]) $(info["product"]) data for the $(gregionfullname(region)) region has been saved into file $(fncr) and moved to the data directory $(folr)."

end


text:
using DrWatson
@quickactivate "ScoreDrivenExponentialRandomGraphs"
DrWatson.greet()

using Test
using ScoreDrivenERGM
import ScoreDrivenERGM:StaticNets,DynNets, Utilities
using LinearAlgebra
using SharedArrays
using PyPlot
using Statistics
using StatsBase
using DataStructures
using JLD2
using RCall

using PyCall

model = DynNets.SdErgmPml(staticModel = StaticNets.NetModeErgmPml("edges +  gwesp(decay = 0.25,fixed = TRUE)", true), indTvPar = [false, true], scoreScalingType="FISH_D")

JLD2.@load( datadir("US_congr_covoting", "estimates") * "\\SS_est_MCMC.jld2",estParSS_T)#, obsMat_T, changeStats_T, stats_T)

JLD2.@load( datadir("US_congr_covoting", "estimates")*"\\SD_est_$(DynNets.name(model))", res_conf, res_est, estParStatic)

#%% Adapt plot to fit paper format
begin
fig = figure(figsize=(18,7))
names = ["Number of Links" "GWESP"]
labSize = 26
tickSize = 20
legSize = 20
SDFiltPar_T = res_est.fVecT_filt
confBands1 = res_conf.confBandsFiltPar
T = size(SDFiltPar_T)[2]
Nterms = DynNets.number_ergm_par(model)
for parInd = 1:Nterms
    x = collect(1:T).+40
    subplot(1,Nterms,parInd)
    plot(x, SDFiltPar_T[parInd,:],"r")
    plot(x, estParSS_T[parInd,:],".b")
    plot(x, ones(T).*estParStatic[parInd],"--b")

    b= 1
    nBands=1
    fill_between(x, confBands1[parInd, :, b,1], y2 =confBands1[parInd,:,b, 2],color =(0.9, 0.2 , 0.2, 0.1), alpha = 0.2*b/nBands  )#, color='b', alpha=.1)

    title(names[parInd],fontsize = labSize+4)
    ylabel("\$ \\theta_$(parInd) \$",fontsize = labSize)
    xlabel("Congress Number",fontsize = labSize)
    xticks(fontsize = tickSize)
    yticks(fontsize = tickSize)
    legTex = [ "SD-ERGM "; "Cross Sect. ERGM"; "Constant ERGM" ]
    legend(legTex,fontsize = legSize,framealpha = 0.95)
end

tight_layout()

end
##

max_stars_repo_name: domenicodigangi/SDERGM

max_issues_repo_name: domenicodigangi/SDERGM

max_forks_repo_name: domenicodigangi/SDERGM


text:
module TraitPerf
# some performance comparisons
using Traits
using Base.Test

# helpers:
println("""\n\nRunning performance tests.  There will be some warnings here, ignore them:\n""")

# from julia/test/perf/perfutil.jl
ntrials = 50
macro timeit(ex)
    quote
        out, time, mem, _ = 0.0, 0.0, 1, 0.0
        t = zeros(Float64, ntrials)
        m = zeros(Int, ntrials)
        for i=0:ntrials
            gc()
            out, time, mem, _ = @timed $(esc(ex))
            if i > 0
                # warm up on first iteration
                t[i] = time
                m[i] = mem
            end
        end
        mean(t), mean(m)
    end
end

function compare_code_native(f1, f2, types, fraction_range=[-Inf,Inf])
    # A very crude way to compare whether two functions produce the
    # same machine code: compare their lengths.  Returns the relative
    # difference of the length of code_native of two functions.
    #
    # If fraction_range is specified, print warning if outside that range.
    #
    # Note, when running with --code-coverage the traits-functions
    # will be much longer than the duck-typed ones.

    function prune_native(st)
        sts = split(st, "\n")
        out = ""
        for s in sts[3:end]     # the first two lines have some file names, etc
            if startswith(s, "Source line:")
                continue
            end
            out *= s
        end
        out
    end

    df1 = prune_native(Base._dump_function(f1, types, true, false, true, false))
    df2 = prune_native(Base._dump_function(f2, types, true, false, true, false))
    rel_diff = abs(length(df1)-length(df2))/length(df2)
    if !(fraction_range[1]<=rel_diff<=fraction_range[2])
        println("""Warning: length of code native of $(f1.env.name) and $(f2.env.name) differ by $rel_diff,
                which is outside the specified range: $fraction_range.""")
    end
    return rel_diff
end

include("traits_vs_ducks.jl")

# load all examples from
dispatch_bug1 = true # needs to be synchronized with ../runtests.jl:dispatch_bug1
include("../traitdispatch.jl")

println("""\n\nAny warnings following this line can indicate code-generation problems:""")
# the bounds used below are from my Linux i7, Julia commit 01a3216*,
# Traits commit 6d9cc07e9

# checks the generated code is within some % of each other
# @code_native ft1(4,5)
# @code_native ff1(4,5)
compare_code_native(ff1, ft1, (Int,Int), [0.0,0.0])
compare_code_native(ff1, ft1, (BigFloat,BigInt), [0.0, 0.0])

# @code_llvm ft2(7.3,5.)
# @code_llvm ff2(7.3,5.)
compare_code_native(ff2, ft2, (Int,Int), [ 0.0, 0.0])
compare_code_native(ff2, ft2, (BigFloat,BigInt), [0.0, 0.0])

# @code_llvm ft3([1:10],5)
# @show "---------------------------------------------------"
# @code_llvm ff3([1:10],5)
compare_code_native(ff3, ft3, (Array{Int,1},Int), [0.025, 0.03])
compare_code_native(ff3, ft3, (Array{BigFloat,1},BigInt), [0.18, 0.19])

end


text:
export NeuralNetLayer, InvertibleNetwork, ReverseLayer, ReverseNetwork

# Base Layer and network types with property getters

abstract type NeuralNetLayer end

abstract type InvertibleNetwork end

function Base.getproperty(obj::Union{InvertibleNetwork,NeuralNetLayer}, sym::Symbol)
    if sym == :forward
        return (args...; kwargs...) -> forward(args..., obj; kwargs...)
    elseif sym == :inverse
        return (args...; kwargs...) -> inverse(args..., obj; kwargs...)
    elseif sym == :backward
        return (args...; kwargs...) -> backward(args..., obj; kwargs...)
    elseif sym == :inverse_Y
        return (args...; kwargs...) -> inverse_Y(args..., obj; kwargs...)
    elseif sym == :forward_Y
        return (args...; kwargs...) -> forward_Y(args..., obj; kwargs...)
    else
         # fallback to getfield
        return getfield(obj, sym)
    end
end

abstract type ReverseLayer end

function Base.getproperty(obj::ReverseLayer, sym::Symbol)
    if sym == :forward
        return (args...; kwargs...) -> inverse(args..., obj.layer; kwargs...)
    elseif sym == :inverse
        return (args...; kwargs...) -> forward(args..., obj.layer; kwargs...)
    elseif sym == :backward
        return (args...; kwargs...) -> backward_inv(args..., obj.layer; kwargs...)
    elseif sym == :inverse_Y
        return (args...; kwargs...) -> forward_Y(args..., obj.layer; kwargs...)
    elseif sym == :forward_Y
        return (args...; kwargs...) -> inverse_Y(args..., obj.layer; kwargs...)
    elseif sym == :layer
        return getfield(obj, sym)
    else
         # fallback to getfield
        return getfield(obj.layer, sym)
    end
end

struct Reverse <: ReverseLayer
    layer::NeuralNetLayer
end

function reverse(L::NeuralNetLayer)
    L_rev = deepcopy(L)
    tag_as_reversed!(L_rev, true)
    return Reverse(L_rev)
end

function reverse(RL::ReverseLayer)
    R = deepcopy(RL)
    tag_as_reversed!(R.layer, false)
    return R.layer
end

abstract type ReverseNetwork end

function Base.getproperty(obj::ReverseNetwork, sym::Symbol)
    if sym == :forward
        return (args...; kwargs...) -> inverse(args..., obj.network; kwargs...)
    elseif sym == :inverse
        return (args...; kwargs...) -> forward(args..., obj.network; kwargs...)
    elseif sym == :backward
        return (args...; kwargs...) -> backward_inv(args..., obj.network; kwargs...)
    elseif sym == :inverse_Y
        return (args...; kwargs...) -> forward_Y(args..., obj.network; kwargs...)
    elseif sym == :forward_Y
        return (args...; kwargs...) -> inverse_Y(args..., obj.network; kwargs...)
    elseif sym == :network
        return getfield(obj, sym)
    else
         # fallback to getfield
        return getfield(obj.network, sym)
    end
end

struct ReverseNet <: ReverseNetwork
    network::InvertibleNetwork
end

function reverse(N::InvertibleNetwork)
    N_rev = deepcopy(N)
    tag_as_reversed!(N_rev, true)
    return ReverseNet(N_rev)
end

function reverse(RN::ReverseNetwork)
    R = deepcopy(RN)
    tag_as_reversed!(R.network, false)
    return R.network
end

# Clear grad functionality for reversed layers/networks

function clear_grad!(RL::ReverseLayer)
    clear_grad!(RL.layer)
end

function clear_grad!(RN::ReverseNetwork)
    clear_grad!(RN.network)
end

# Get params for reversed layers/networks

function get_params(RL::ReverseLayer)
    return get_params(RL.layer)
end

function get_params(RN::ReverseNetwork)
    return get_params(RN.network)
end


text:
function _run(cmd::Cmd; ignorestatus = true, verbose = true)
    cmd = Cmd(cmd; ignorestatus)
    out = read(cmd, String)
    verbose && _printcmd(out)
    return out
end

function _run(cmd::String; ignorestatus = true, verbose = true)
    cmd = Cmd(`bash -c $(cmd)`)
    _run(cmd; ignorestatus, verbose)
end

# For logging
function _printcmd(str::String; len = 60)
    isempty(str) && return
    str = strip(str)
    if length(str) > len
        @info(string("\n", str, "\n", " "))
    else
        @info(str)
    end
end


text:
# Serialization functions for Flux models that depend on BSON

# @info "IncrementalInference is adding Flux/BSON serialization functionality."

export PackedFluxModelsDistribution

using Base64

import Base: convert

mutable struct PackedFluxModelsDistribution <: IIF.PackedSamplableBelief
  # shape of the input data
  inputDim::Vector{Int}
  # shape of the output data
  outputDim::Vector{Int}
  # actual Flux models (Base64 encoded binary)
  mimeTypeModel::String
  models::Vector{String}
  # the data used for prediction, must be <: AbstractArray
  mimeTypeData::String
  data::String
  # shuffle model predictions relative to particle index at each sampling
  shuffle::Bool
  # false for default serialization with model info, set true for separate storage of models
  serializeHollow::Bool
    # TODO remove requirement and standardize sampler API
    # specialSampler::Symbol
  # field name usage to direct the IIF serialization towards JSON method
  PackedSamplableTypeJSON::String
end

function _serializeFluxModelBase64(model::Flux.Chain)
  io = IOBuffer()
  iob64 = Base64EncodePipe(io)
  BSON.@save iob64 model
  close(iob64)
  return String(take!(io))
end

function _deserializeFluxModelBase64(smodel::AbstractString)
  iob64 = PipeBuffer(base64decode(smodel))
  BSON.@load iob64 model
  close(iob64)
  return model
end

function _serializeFluxDataBase64(data::AbstractArray)
  io = IOBuffer()
  iob64 = Base64EncodePipe(io)
  BSON.@save iob64 data
  close(iob64)
  return String(take!(io))
end

function _deserializeFluxDataBase64(sdata::AbstractString)
  iob64 = PipeBuffer(base64decode(sdata))
  BSON.@load iob64 data
  close(iob64)
  return data
end

function convert( ::Union{Type{<:PackedSamplableBelief},Type{<:PackedFluxModelsDistribution}},
                  obj::FluxModelsDistribution)
  #

    # and the specialSampler function -- likely to be deprecated
    # specialSampler = Symbol(obj.specialSampler)
  # fields to persist
  inputDim = collect(obj.inputDim)
  outputDim = collect(obj.outputDim)
  models = Vector{String}()
  # store all models as Base64 Strings (using BSON)
  if !obj.serializeHollow[]
    resize!(models, length(obj.models))
    # serialize the Vector of Flux models (each one individually)
    models .= _serializeFluxModelBase64.(obj.models)
    # also store data as Base64 String, using BSON
    sdata = _serializeFluxDataBase64(obj.data)
    mimeTypeData = "application/bson/octet-stream/base64"
  else
    # store one just model to preserve the type (allows resizing on immutable Ref after deserialize)
    push!(models,_serializeFluxModelBase64(obj.models[1]))
    # at least capture the type of how the data looks for future deserialization
    sdata = string(typeof(obj.data))
    mimeTypeData = "application/text"
  end
  mimeTypeModel = "application/bson/octet-stream/base64"

  # and build the JSON-able object
  packed = PackedFluxModelsDistribution(inputDim,
                                        outputDim,
                                        mimeTypeModel,
                                        models,
                                        mimeTypeData,
                                        sdata,
                                        obj.shuffle[],
                                        obj.serializeHollow[],
                                        # specialSampler,
                                        "IncrementalInference.PackedFluxModelsDistribution" )
  #
  return JSON2.write(packed)
end

function convert( ::Union{Type{<:SamplableBelief},Type{FluxModelsDistribution}},
                  obj::PackedFluxModelsDistribution)
  #

  obj.serializeHollow && @warn("Deserialization of FluxModelsDistribution.serializationHollow=true is not yet well developed, please open issues at IncrementalInference.jl accordingly.")

  # specialSampler likely to be deprecated
  # specialSampler = getfield(Main, obj.specialSampler)

  # deserialize
  # @assert obj.mimeTypeModel == "application/bson/octet-stream/base64"
  models = _deserializeFluxModelBase64.(obj.models)

  # @assert obj.mimeTypeData == "application/bson/octet-stream/base64"
  data = !obj.serializeHollow ? _deserializeFluxDataBase64.(obj.data) : zeros(0)

  return FluxModelsDistribution(models,
                                (obj.inputDim...,),
                                data,
                                (obj.outputDim...,),
                                shuffle=obj.shuffle,
                                serializeHollow=obj.serializeHollow  )
end

#


text:
module Seahawk

using Base.Docs: modules, DocStr, MultiDoc, parsedoc
using CodeTracking
using DocSeeker
using REPL: doc, meta, stripmd
using ReplMaker
using Markdown: Markdown, MD

const DESCRIPTION_LIMIT = 80

"""
    search(string)

Search for `string` in all docstrings for all loaded packages and print the results
such that the best match is at the bottom.
If the matches should be returned instead of printed one can use `;silent = true`
"""
search(string; silent=false) = search(stdout, string; silent=silent)

function search(io::IO, needle; silent=false)
    search_results = searchdocs(needle)
    if silent
        return search_results
    end
    print_results(search_results)
end

flatten(md::MD) = MD(flat_content(md))

# Faster version

function flat_content!(xs, out = [])
  for x in xs
    if isa(x, MD)
      flat_content!(x.content, out)
    else
      push!(out, x)
    end
  end
  return out
end

flat_content(md::MD) = flat_content!(md.content)

function strlimit(str::AbstractString, limit::Integer = 30, ellipsis::AbstractString = "…")
    will_append = length(str) > limit

    io = IOBuffer()
    i = 1
    for c in str
      will_append && i > limit - length(ellipsis) && break
      isvalid(c) || continue

      print(io, c)
      i += 1
    end
    will_append && print(io, ellipsis)

    return String(take!(io))
end

description(docs) = ""
description(docs::MD) = begin
  md = flatten(docs).content
  for part in md
    if part isa Markdown.Paragraph
      desc = Markdown.plain(part)
      occursin("No documentation found.", desc) && return ""
      return strip(strlimit(desc, DESCRIPTION_LIMIT))
    end
  end
  return ""
end

function print_results(search_results)
    for search_result in reverse(search_results)
        print_result(search_result[2])
    end
end

function print_result(res::DocSeeker.DocObj)
    path = CodeTracking.maybe_fix_path(res.path)
    summary = description(res.html)
    printstyled(res.name; color=:green)
    print(" in ")
    printstyled(res.mod; color=:green)
    print(" at ")
    printstyled("$path:$(res.line)"; color=:blue)
    println()
    println(summary)
end

function __init__()
    initrepl(search,
            prompt_text="Seahawk> ",
            prompt_color = :white,
            start_key='/',
            mode_name="Search mode")
end

end


text:
# syntax: proto3
const NullValue = (;[
    Symbol("NULL_VALUE") => Int32(0),
]...)

mutable struct Struct_FieldsEntry <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function Struct_FieldsEntry(; kwargs...)
        obj = new(meta(Struct_FieldsEntry), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct Struct_FieldsEntry (mapentry) (has cyclic type dependency)
const __meta_Struct_FieldsEntry = Ref{ProtoMeta}()
function meta(::Type{Struct_FieldsEntry})
    ProtoBuf.metalock() do
        if !isassigned(__meta_Struct_FieldsEntry)
            __meta_Struct_FieldsEntry[] = target = ProtoMeta(Struct_FieldsEntry)
            allflds = Pair{Symbol,Union{Type,String}}[:key => AbstractString, :value => "Value"]
            meta(target, Struct_FieldsEntry, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_Struct_FieldsEntry[]
    end
end
function Base.getproperty(obj::Struct_FieldsEntry, name::Symbol)
    if name === :key
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :value
        return (obj.__protobuf_jl_internal_values[name])::Any
    else
        getfield(obj, name)
    end
end

mutable struct Struct <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function Struct(; kwargs...)
        obj = new(meta(Struct), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct Struct (has cyclic type dependency)
const __meta_Struct = Ref{ProtoMeta}()
function meta(::Type{Struct})
    ProtoBuf.metalock() do
        if !isassigned(__meta_Struct)
            __meta_Struct[] = target = ProtoMeta(Struct)
            allflds = Pair{Symbol,Union{Type,String}}[:fields => "Base.Dict{AbstractString,Value}"]
            meta(target, Struct, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_Struct[]
    end
end
function Base.getproperty(obj::Struct, name::Symbol)
    if name === :fields
        return (obj.__protobuf_jl_internal_values[name])::Any
    else
        getfield(obj, name)
    end
end

mutable struct Value <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function Value(; kwargs...)
        obj = new(meta(Value), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct Value (has cyclic type dependency)
const __meta_Value = Ref{ProtoMeta}()
function meta(::Type{Value})
    ProtoBuf.metalock() do
        if !isassigned(__meta_Value)
            __meta_Value[] = target = ProtoMeta(Value)
            allflds = Pair{Symbol,Union{Type,String}}[:null_value => Int32, :number_value => Float64, :string_value => AbstractString, :bool_value => Bool, :struct_value => Struct, :list_value => "ListValue"]
            oneofs = Int[1,1,1,1,1,1]
            oneof_names = Symbol[Symbol("kind")]
            meta(target, Value, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, oneofs, oneof_names)
        end
        __meta_Value[]
    end
end
function Base.getproperty(obj::Value, name::Symbol)
    if name === :null_value
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :number_value
        return (obj.__protobuf_jl_internal_values[name])::Float64
    elseif name === :string_value
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :bool_value
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :struct_value
        return (obj.__protobuf_jl_internal_values[name])::Struct
    elseif name === :list_value
        return (obj.__protobuf_jl_internal_values[name])::Any
    else
        getfield(obj, name)
    end
end

mutable struct ListValue <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function ListValue(; kwargs...)
        obj = new(meta(ListValue), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct ListValue (has cyclic type dependency)
const __meta_ListValue = Ref{ProtoMeta}()
function meta(::Type{ListValue})
    ProtoBuf.metalock() do
        if !isassigned(__meta_ListValue)
            __meta_ListValue[] = target = ProtoMeta(ListValue)
            allflds = Pair{Symbol,Union{Type,String}}[:values => Base.Vector{Value}]
            meta(target, ListValue, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_ListValue[]
    end
end
function Base.getproperty(obj::ListValue, name::Symbol)
    if name === :values
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{Value}
    else
        getfield(obj, name)
    end
end

export NullValue, Struct_FieldsEntry, Struct, Value, ListValue, Struct_FieldsEntry, Struct, Value, ListValue
# mapentries: "Struct_FieldsEntry" => ("AbstractString", "Value")


text:
module MadNLPPardiso

include(joinpath("..","deps","deps.jl"))

const INPUT_MATRIX_TYPE = :csc

import Libdl: dlopen, RTLD_DEEPBIND
import MadNLP:
    MadNLP, @kwdef, Logger, @debug, @warn, @error,
    SubVector, StrideOneVector, SparseMatrixCSC,
    SymbolicException,FactorizationException,SolveException,InertiaException,
    AbstractOptions, AbstractLinearSolver, set_options!,
    introduce, factorize!, solve!, improve!, is_inertia, inertia
import MKL_jll: libmkl_rt

@isdefined(libpardiso) && include("pardiso.jl")
include("pardisomkl.jl")

function __init__()
    check_deps()
    @isdefined(libpardiso) && dlopen(libpardiso,RTLD_DEEPBIND)
end

export MadNLPPardisoMKL

end # module


text:
module Units

export second, minute, hour, meter, kilometer,
       seconds, minutes, hours, meters, kilometers,
       KiB, MiB, GiB, TiB

const second = 1
const seconds = second
const minute = 60seconds
const minutes = minute
const hour = 60minutes
const hours = hour

const meter = 1.0
const meters = meter
const kilometer = 1000meters
const kilometers = kilometer

const KiB = 1024.0
const MiB = 1024KiB
const GiB = 1024MiB
const TiB = 1024GiB

end


text:
#InspectDR: Secondary annotation (Cairo layer)
#-------------------------------------------------------------------------------

#==Constants
===============================================================================#
const ALIGN_MAP = Dict{Symbol, CAlignment}(
	:tl => ALIGN_TOP | ALIGN_LEFT,
	:tc => ALIGN_TOP | ALIGN_HCENTER,
	:tr => ALIGN_TOP | ALIGN_RIGHT,

	:cl => ALIGN_VCENTER | ALIGN_LEFT,
	:cc => ALIGN_VCENTER | ALIGN_HCENTER,
	:cr => ALIGN_VCENTER | ALIGN_RIGHT,

	:bl => ALIGN_BOTTOM | ALIGN_LEFT,
	:bc => ALIGN_BOTTOM | ALIGN_HCENTER,
	:br => ALIGN_BOTTOM | ALIGN_RIGHT,
)

#==Rendering text annotation
===============================================================================#
function render(canvas::PCanvas2D, a::TextAnnotation, axes::Axes)
	const ctx = canvas.ctx
	const graphbb = canvas.graphbb
	align = get(ALIGN_MAP, a.align, ALIGN_BOTTOM | ALIGN_LEFT)
	angle = deg2rad(a.angle)

	Cairo.set_source(ctx, a.color)
	pt = _rescale(a.pt, axes)
	pt = ptmap(canvas.xf, pt)
	x = pt.x; y = pt.y
	if isnan(x); x = graphbb.xmin; end
	if isnan(y); y = graphbb.ymax; end
	x += a.xoffset * width(graphbb)
	y -= a.yoffset * height(graphbb)
	render(ctx, a.text, Point2D(x,y), a.font, angle=angle, align=align)
	return
end

render(canvas::PCanvas2D, alist::Vector{TextAnnotation}, axes::Axes) =
	map((a)->render(canvas, a, axes::Axes), alist)

#==Rendering markers
===============================================================================#

function render(canvas::PCanvas2D, mkr::HVMarker, axes::Axes)
	const ctx = canvas.ctx
	const graphbb = canvas.graphbb
	if :none == mkr.line.style
		return
	end

	Cairo.set_source(ctx, mkr.line.color)
	setlinestyle(ctx, mkr.line.style, Float64(mkr.line.width))
	pt = _rescale(Point2D(mkr.pos, mkr.pos), axes)
	pt = ptmap(canvas.xf, pt)

	if mkr.vmarker
		drawline(ctx, Point2D(pt.x, graphbb.ymin), Point2D(pt.x, graphbb.ymax))
	else #hmarker
		drawline(ctx, Point2D(graphbb.xmin, pt.y), Point2D(graphbb.xmax, pt.y))
	end

	return
end

render(canvas::PCanvas2D, mkrlist::Vector{HVMarker}, axes::Axes) =
	map((mkr)->render(canvas, mkr, axes::Axes), mkrlist)

#Last line


text:
using PooksoftOptionsKit
using PyPlot

# call -
result_buyer = compute_call_option_profit_loss_at_expiration(:buy, 20.0, 1.20, 0.0, 40.0)
result_seller = compute_call_option_profit_loss_at_expiration(:sell, 20.0, 1.20, 0.0, 40.0)

profit_loss_buyer = result_buyer.value
profit_loss_seller = result_seller.value

# plot -
plot(profit_loss_buyer[:,1], profit_loss_buyer[:,3], "b")       # buyer - payoff
#plot(profit_loss_buyer[:,1], profit_loss_buyer[:,2], "b--")     # buyer - P/L
#plot(profit_loss_seller[:,1], profit_loss_seller[:,2], "r")       # buyer - payoff
#plot(profit_loss_seller[:,1], profit_loss_seller[:,2], "r--")     # buyer - P/L


text:
using LazyPseudoinverse, LinearAlgebra
using Test

@testset "LazyPseudoInverse.jl" begin
    A = [1 2 3; 4 5 6; 7. 8 10; 11 13 19]            # a few handy matrices/vectors for testing
    At = collect(A') # the unadulterated adjoint
    B = [1 2 3; 8 9 1; 5. 3 4; 5 9 8]
    b = [5, 8, 10, 11.]
    c = [1.,2.,3.]
    @test typeof(A'A) <: MatrixInnerProd
    @test collect(A'A) == At*A                       # collecting materializes the actual matrix
    @test A'A*collect(B') == At*A*B'                 # right-multiply should just complete
    @test adjointmul(A',A) == At*A                   # same thing, except using adjointmul
    @test A'B == At*B                                # non-inner product
    @test inv(A'A)*B' == cholesky(At*A)\B'           # lazy inverse works with adjoint B'
    @test inv(A'A)c  == cholesky(At*A)\c             # lazy inverse works with vector
    @test inv(A'A)*collect(B') == cholesky(At*A)\B'  # works with regular right-multiplied matrix
    @test B*inv(A'A) ≈ B*inv(cholesky(At*A))         # left-multiplied matrix with lazy PD inverse
    @test inv(A'A)A'b == A\b                         # acts like \ with vector b, using QR
    @test inv(A'A)A'B == A\B                         # acts like \ with matrix B
    @test inv(A'A)A'B == qr(A,Val(true))\B           # ...which should use QR

# Also manually check that show works:  should say MatrixInnerProd
# and show the materialized output.
#  show(stdout, MIME("text/plain"), A'A)           -> MatrixInnerProd
#  show(stdout, MIME("text/plain"), inv(A'A))      -> InvMatrixInnerProd
#  show(stdout, MIME("text/plain"), inv(A'A)A')    -> LazyLeftPseudoinverse
end


text:
module KoreanJosa

export josa

# https://github.com/myevan/pyjosa/blob/master/pyjosa.py
# https://github.com/trilliwon/JNaturalKorean/blob/master/Sources/JNaturalKorean/JNaturalKorean.swift

# unicode codepoints
const BASECODE = 0xac00 # '가' 이후 한글 코드
const JUNGSUNG = 28
const ALL_JOSA= r".?\((이|가|과|와|을|를|은|는|으로|로|아|야|이여|여|이라|라)\)"

abstract type JOSAMarker end
function JOSAMarker(marker)
    if marker == "(이)" || marker == "(가)"
        JOSA_이_가
    elseif marker == "(과)" || marker == "(와)"
        JOSA_과_와
    elseif marker == "(을)" || marker == "(를)"
        JOSA_을_를
    elseif marker == "(은)" || marker == "(는)"
        JOSA_은_는
    elseif marker == "(으로)" || marker == "(로)"
        JOSA_으로_로
    elseif marker == "(아)" || marker == "(야)"
        JOSA_아_야
    elseif marker == "(이여)" || marker == "(여)"
        JOSA_이여_여
    elseif marker == "(이라)" || marker == "(라)"
        JOSA_이라_라
    else
        throw(ArgumentError("\"$(marker)\" is not defined for JOSA"))
    end
end
struct JOSA_이_가 <: JOSAMarker
end
struct JOSA_과_와 <: JOSAMarker
end
struct JOSA_을_를 <: JOSAMarker
end
struct JOSA_은_는 <: JOSAMarker
end
struct JOSA_으로_로 <: JOSAMarker
end
struct JOSA_아_야 <: JOSAMarker
end
struct JOSA_이여_여 <: JOSAMarker
end
struct JOSA_이라_라 <: JOSAMarker
end
function Base.getindex(::Type{JOSA_이_가}, i)
    i == 1 ? "이" : i == 2 ? "가" : throw(ArgumentError("Josa can have only 2 types"))
end
function Base.getindex(::Type{JOSA_과_와}, i)
    i == 1 ? "과" : i == 2 ? "와" : throw(ArgumentError("Josa can have only 2 types"))
end
function Base.getindex(::Type{JOSA_을_를}, i)
    i == 1 ? "을" : i == 2 ? "를" : throw(ArgumentError("Josa can have only 2 types"))
end
function Base.getindex(::Type{JOSA_은_는}, i)
    i == 1 ? "은" : i == 2 ? "는" : throw(ArgumentError("Josa can have only 2 types"))
end
function Base.getindex(::Type{JOSA_으로_로}, i)
    i == 1 ? "으로" : i == 2 ? "로" : throw(ArgumentError("Josa can have only 2 types"))
end
function Base.getindex(::Type{JOSA_아_야}, i)
    i == 1 ? "아" : i == 2 ? "야" : throw(ArgumentError("Josa can have only 2 types"))
end
function Base.getindex(::Type{JOSA_이여_여}, i)
    i == 1 ? "이여" : i == 2 ? "여" : throw(ArgumentError("Josa can have only 2 types"))
end
function Base.getindex(::Type{JOSA_이라_라}, i)
    i == 1 ? "이라" : i == 2 ? "라" : throw(ArgumentError("Josa can have only 2 types"))
end

function josa(s::AbstractString)
    if !occursin(ALL_JOSA, s)
        return s
    end
    for el in eachmatch(ALL_JOSA, s)
        x = select_josa(el.match)
        s = replace(s, el.match => x)
    end
    return s
end

"""
    select_josa(word::AbstractString)

"""
function select_josa(word::AbstractString)
    letter = word[1]
    T = JOSAMarker(word[nextind(word, 1):end])
    return letter * select_josa(T, letter)
end
function select_josa(::Type{T}, letter::Char) where T <: JOSAMarker
    char = only(letter)
    char_code = codepoint(char)

    kor_code = char_code - BASECODE
    jong_code = kor_code % JUNGSUNG

    # 종성이 없는 경우
    if jong_code == 0
        return T[2]
    end
    # 종성이 있는 경우
    if T == JOSA_으로_로
        if jong_code == 8 # ㄹ 종성인 경우
            return T[2]
        end
    end

    return T[1]
end

end # module


text:
# A perfect number is a number for which the sum of its proper divisors is
# exactly equal to the number. For example, the sum of the proper divisors of
# 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.
#
# A number n is called deficient if the sum of its proper divisors is less than
# n and it is called abundant if this sum exceeds n.
#
# As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest
# number that can be written as the sum of two abundant numbers is 24. By
# mathematical analysis, it can be shown that all integers greater than 28123
# can be written as the sum of two abundant numbers. However, this upper limit
# cannot be reduced any further by analysis even though it is known that the
# greatest number that cannot be expressed as the sum of two abundant numbers
# is less than this limit.
#
# Find the sum of all the positive integers which cannot be written as the sum
# of two abundant numbers.

using ProjectEulerSolutions

# Uses the same approach as in 021.jl to build up array of factor sums, testing
# for abundant numbers and storing them.  Then filters out sums of abundant
# numbers.
function p023solution(n::Integer=10)::Integer
    abundant_numbers = Array{Integer, 1}()

    # Store abundant_numbers
    factor_sums = ones(Integer, n)
    for i = 2:n
        factor_sums[2*i:i:n] .+= i
        if i < factor_sums[i]
            push!(abundant_numbers, i)
        end
    end

    # Check for sums of abundant_numbers
    sum_of_abundant_numbers = falses(n)
    for i in 1:length(abundant_numbers)
        for j in i:length(abundant_numbers)
            h = abundant_numbers[i] + abundant_numbers[j]
            if h > n
                break
            else
                sum_of_abundant_numbers[h] = true
            end
        end
    end

    # Invert the bitarray to get values that are not sums of abundant numbers
    return sum(findall(.!sum_of_abundant_numbers))
end

p023 = Problems.Problem(p023solution)

Problems.benchmark(p023, 28_123)

max_stars_repo_name: gnujosh/julia-euler-project

max_issues_repo_name: gnujosh/julia-euler-project

max_forks_repo_name: gnujosh/julia-euler-project


text:
################################################################################
#
#  Conversion to Nemo/Hecke for storage
#
################################################################################

function to_hecke(f::IOStream, a::Dict{T, S}; name::String="R") where {T, S}
  print(f, name, " = Dict{$T,$S}(\n")
  k = collect(keys(a))
  for i=1:length(k)-1
    print(f, k[i], " => ", a[k[i]], ", \n")
  end
  print(f, k[end], " => ", a[k[end]], ");\n")
end

function to_hecke(s::String, a::Dict; name::String="R", mode::String ="w")
  f = open(s, mode)
  to_hecke(f, a, name = name)
  close(f)
end

function to_hecke(f::IOStream, a::Vector{T}; name::String="R") where T
  print(f, name, " = [\n")
  for i=1:(length(a)-1)
    print(f, a[i], ",\n")
  end
  print(f, a[end], "];\n")
end

function to_hecke(s::String, a::Vector{T}; name::String="R", mode::String ="w") where T
  f = open(s, mode)
  to_hecke(f, a, name = name)
  close(f)
end

################################################################################
# fmpz_mat -> nemo file
# use as include(...)
################################################################################
function to_hecke(io::IOStream, A::fmpz_mat; name = "A")
  println(io, name, " = matrix(FlintZZ, ", nrows(A), ", ", ncols(A), "fmpz[")
  for i = 1:nrows(A)
    for j = 1:ncols(A)
      print(io, A[i,j])
      if j < ncols(A)
        print(io, ", ")
      end
    end
    if i<nrows(A)
      println(io, ", ")
    end
  end
  println(io, "]);")
  println(io, "println(\"Loaded ", name, "\")")
end

function to_hecke(s::String, A::fmpz_mat)
  f = open(s, "w")
  to_hecke(f, A)
  close(f)
end


text:
function solve()
    n, k = [parse(Int, x) for x in split(readline())]
    a = [parse(Int, x) for x in split(readline())]

    current = 1
    path = [1]
    visited = Set{Int}(1)

    while a[current] ∉ visited
        current = a[current]
        append!(path, current)
        push!(visited, current)
    end
    append!(path, a[current])

    if k < length(path)
        path[k+1]
    else
        cycle_start = findfirst(x->(x==path[end]), path)
        k = k - cycle_start
        path = path[cycle_start+1:end]
        k = k % length(path) + 1
        path[k]
    end
end

println(solve())

max_stars_repo_name: aishikawa/atcoder-julia

max_issues_repo_name: aishikawa/atcoder-julia

max_forks_repo_name: aishikawa/atcoder-julia


text:
module TestShapes

using Test, Random

using Gloria.Shapes
using Gloria.Shapes: edges, inside, intersects, projection, rotate, trace, translate, vertices

@testset "Intersection" begin
    p0 = Vertex(0., 0.)
    p1 = Vertex(1.05, 0.)
    p2 = Vertex(1.5, 0.25)
    p3 = Vertex(-0.5, 1.25)
    l1 = Polyline(Vertex(-1., 0.), Vertex(1., 0.))
    l2 = Polyline(Vertex(0.5, 0.), Vertex(1.5, 0.))
    l3 = Polyline(Vertex(0.85, -0.5), Vertex(1.85, 0.5))
    l4 = Polyline(Vertex(-0.5, 1.), Vertex(-0.5, 2.))
    l5 = Polyline(Vertex(-0.25, -0.75), Vertex(0.75, 0.25))
    pol1 = Polygon(Vertex(-1., -0.5), Vertex(0., 0.5), Vertex(1., -0.5), Vertex(0., -1.5))
    pol2 = Polygon(Vertex(-0.5, -0.5), Vertex(-0.5, 0.5), Vertex(0.5, 0.5), Vertex(0.5, -0.5))
    pol3 = Polygon(reverse((Vertex(-0.5, -0.5), Vertex(-0.5, 0.5), Vertex(0.5, 0.5), Vertex(0.5, -0.5))))
    c1 = circle(Vertex(0., 0.), 1., samples=4)
    c2 = circle(Vertex(0., 3.), 1., samples=4)

    @test trace(p0, l1) == (0.5,)
    @test trace(p0, l2) == ()
    @test trace(p0, l3) == ()
    @test trace(p0, l4) == ()
    @test trace(p0, l5) == ()

    @test trace(p1, l1) == ()
    @test trace(p1, l2) == (0.55,)
    @test trace(p2, l1) == trace(p2, l2) == ()
    @test trace(p2, l3) == () # Floating point errors means this will never hit

    @test trace(l1, l2) == (0., 0.5)
    @test trace(l2, l1) == (0.75, 1.0)
    @test trace(l3, l1) == ()
    @test trace(l3, l2) == (0.85,)
    @test trace(l3, l1) == trace(l1, l3) == ()

    @test collect(Float64, trace(pol1, l1)) == [0.25, 0.75]
    @test collect(Float64, trace(pol1, l4)) == Float64[]
    # @test collect(Float64, trace(pol1, (l1, l2))) == [0.25, 0.75, 0.]
    @test collect(Float64, trace(pol1, l3)) ≈ [0.075]
    # @test collect(Float64, trace(pol1, (l1, l2, l3, l4))) ≈ [0.25, 0.75, 0., 0.075]

    @test intersects(pol1, l1)
    @test intersects(l1, pol1)
    @test intersects(pol1, l3)
    @test intersects(l3, pol1)
    @test !intersects(pol1, l4)
    @test !intersects(l4, pol1)

    for θ in 0:10:360
        @eval @test inside($pol1, $p0, $θ)
        @eval @test !inside($pol1, $p1, $θ)
        @eval @test !inside($pol1, $p2, $θ)
        @eval @test !inside($pol2, $p3, $θ)
        @eval @test !inside($pol3, $p3, $θ)
    end
    for θ in 0:10:360, v in vertices(c2)
        @eval @test !inside($c1, $v, $θ)
    end
end

@testset "Transformations" begin
    p = Vertex(0., 0.)
    l = Polyline(p, p |> translate(1, 0))

    @test p |> translate(2, 0) == Vertex(2., 0.)
    @test p |> translate(1, 0) |> rotate(90) == Vertex(0., 1.)
    @test p |> translate(1, 0) |> rotate(90) == p |> rotate(90) |> translate(0, 1.) == Vertex(0., 1.)

    @test l == Polyline(Vertex(0., 0.), Vertex(1., 0.))
    @test l |> translate(1, 0) |> rotate(90) == l |> rotate(90) |> translate(0, 1.) == Polyline(Vertex(0., 1.), Vertex(0., 2.))
end

@testset "Projections" begin
    p1 = Vertex(0., 0.)
    p2 = Vertex(1., 0.8)
    l = Polyline(Vertex(-1.0, -0.5), Vertex(1.0, -0.5))
    shape = Polygon(Vertex(-1.0, -0.5), Vertex(1.0, -0.5), Vertex(2.0, 0.5), Vertex(0.0, 0.5))
    @test projection(p1, l) == Vertex(0., -0.5)
    @test projection(p2, l) == Vertex(1.0, -0.5)
end

end #module


text:
module TestCore
using Test
using Accessors
using Accessors: test_getset_laws, test_modify_law
using Accessors: compose, get_update_op
using ConstructionBase: ConstructionBase
using StaticNumbers: StaticNumbers, static

struct T
    a
    b
end

struct TT{A,B}
    a::A
    b::B
end

@testset "get_update_op" begin
    @test get_update_op(:(&=)) === :(&)
    @test get_update_op(:(^=)) === :(^)
    @test get_update_op(:(-=)) === :(-)
    @test get_update_op(:(%=)) === :(%)
    @test_throws ArgumentError get_update_op(:(++))
    @test_throws ArgumentError get_update_op(:(<=))
end

@testset "@reset" begin
    a = 1
    @set a = 2
    @test a === 1
    @reset a = 2
    @test a === 2

    t = T(1, T(2,3))
    @set t.b.a = 20
    @test t === T(1, T(2,3))

    @reset t.b.a = 20
    @test t === T(1,T(20,3))

    a = 1
    @reset a += 10
    @test a === 11
    nt = (a=1,)
    @reset nt.a = 5
    @test nt === (a=5,)
end

@testset "@set" begin

    t = T(1, T(2, T(T(4,4),3)))
    s = @set t.b.b.a.a = 5
    @test t === T(1, T(2, T(T(4,4),3)))
    @test s === T(1, T(2, T(T(5, 4), 3)))
    @test_throws ArgumentError @set t.b.b.a.a.a = 3

    t = T(1,2)
    @test T(1, T(1,2)) === @set t.b = T(1,2)
    @test_throws ArgumentError @set t.c = 3

    t = T(T(2,2), 1)
    s = @set t.a.a = 3
    @test s === T(T(3, 2), 1)

    t = T(1, T(2, T(T(4,4),3)))
    s = @set t.b.b = 4
    @test s === T(1, T(2, 4))

    t = T(1,2)
    s = @set t.a += 1
    @test s === T(2,2)

    t = T(1,2)
    s = @set t.b -= 2
    @test s === T(1,0)

    t = T(10, 20)
    s = @set t.a *= 10
    @test s === T(100, 20)

    t = T(2,1)
    s = @set t.a /= 2
    @test s === T(1.0,1)

    t = T(1, 2)
    s = @set t.a <<= 2
    @test s === T(4, 2)

    t = T(8, 2)
    s = @set t.a >>= 2
    @test s === T(2, 2)

    t = T(1, 2)
    s = @set t.a &= 0
    @test s === T(0, 2)

    t = T(1, 2)
    s = @set t.a |= 2
    @test s === T(3, 2)

    t = T((1,2),(3,4))
    @set t.a[1] = 10
    s1 = @set t.a[1] = 10
    @test s1 === T((10,2),(3,4))
    i = 1
    si = @set t.a[i] = 10
    @test s1 === si
    se = @set t.a[end] = 20
    @test se === T((1,20),(3,4))
    se1 = @set t.a[end-1] = 10
    @test s1 === se1

    s1 = @set t.a[static(1)] = 10
    @test s1 === T((10,2),(3,4))
    i = 1
    si = @set t.a[static(i)] = 10
    @test s1 === si

    t = @set T(1,2).a = 2
    @test t === T(2,2)

    t = (1, 2, 3, 4)
    @test (@set t[length(t)] = 40) === (1, 2, 3, 40)
    @test (@set t[length(t) ÷ 2] = 20) === (1, 20, 3, 4)

    t = (1, 2)
    @test (@set t |> first = 10) === (10, 2)
end

struct UserDefinedLens end

struct LensIfTextPlain end
Base.show(io::IO, ::MIME"text/plain", ::LensIfTextPlain) =
    print(io, "I define text/plain.")

@testset "lens laws" begin
    obj = T(2, T(T(3,(4,4)), 2))
    i = 2
    for lens ∈ [
            @optic _.a
            @optic _.b
            @optic _.b.a
            @optic _.b.a.b[2]
            @optic _.b.a.b[i]
            @optic _.b.a.b[static(2)]
            @optic _.b.a.b[static(i)]
            @optic _.b.a.b[end]
            @optic _.b.a.b[identity(end) - 1]
            @optic _
        ]
        val1, val2 = randn(2)
        f(x) = (x,x)
        test_getset_laws(lens, obj, val1, val2)
        test_modify_law(f, lens, obj)
    end
end

@testset "type stability" begin
    o1 = 2
    o22 = 2
    o212 = (4,4)
    o211 = 3
    o21 = TT(o211, o212)
    o2 = TT(o21, o22)
    obj = TT(o1, o2)
    @assert obj === TT(2, TT(TT(3,(4,4)), 2))
    i = 1
    for (lens, val) ∈ [
          ((@optic _.a           ),   o1 ),
          ((@optic _.b           ),   o2 ),
          ((@optic _.b.a         ),   o21),
          ((@optic _.b.a.b[2]    ),   4  ),
          ((@optic _.b.a.b[i+1]  ),   4  ),
          ((@optic _.b.a.b[static(2)]   ),   4  ),
          ((@optic _.b.a.b[static((i+1))]),  4  ),
          ((@optic _.b.a.b[static(2)]   ),   4.0),
          ((@optic _.b.a.b[static((i+1))]),  4.0),
          ((@optic _.b.a.b[end]),     4.0),
          ((@optic _.b.a.b[end÷2+1]), 4.0),
          ((@optic _             ),   obj),
          ((@optic _             ),   :xy),
        ]
        @inferred lens(obj)
        @inferred set(obj, lens, val)
        @inferred modify(identity, obj, lens)
    end
end

@testset "IndexLens" begin
    l = @optic _[]
    @test l isa Accessors.IndexLens
    x = randn()
    obj = Ref(x)
    @test l(obj) == x

    l = @optic _[][]
    @test l.outer isa Accessors.IndexLens
    @test l.inner isa Accessors.IndexLens
    inner = Ref(x)
    obj = Base.RefValue{typeof(inner)}(inner)
    @test l(obj) == x

    obj = (1,2,3)
    l = @optic _[1]
    @test l isa Accessors.IndexLens
    @test l(obj) == 1
    @test set(obj, l, 6) == (6,2,3)

    l = @optic _[1:3]
    @test l isa Accessors.IndexLens
    @test l([4,5,6,7]) == [4,5,6]
end

@testset "DynamicIndexLens" begin
    l = @optic _[end]
    @test l isa Accessors.DynamicIndexLens
    obj = (1,2,3)
    @test l(obj) == 3
    @test set(obj, l, true) == (1,2,true)

    l = @optic _[end÷2]
    @test l isa Accessors.DynamicIndexLens
    obj = (1,2,3)
    @test l(obj) == 1
    @test set(obj, l, true) == (true,2,3)

    two = 2
    plusone(x) = x + 1
    l = @optic _.a[plusone(end) - two].b
    obj = (a=(1, (a=10, b=20), 3), b=4)
    @test l(obj) == 20
    @test set(obj, l, true) == (a=(1, (a=10, b=true), 3), b=4)
    if VERSION ≥ v"1.5.0-DEV.666"
        # parser is confused by x[begin] on older julia versions
        l = eval(Meta.parse("@optic _[begin]"))
        @test l isa Accessors.DynamicIndexLens
        obj = (1,2,3)
        @test l(obj) == 1
        @test set(obj, l, true) == (true,2,3)

        l = eval(Meta.parse("@optic _[2*begin]"))
        @test l isa Accessors.DynamicIndexLens
        obj = (1,2,3)
        @test l(obj) == 2
        @test set(obj, l, true) == (1,true,3)

        l = eval(Meta.parse(
        """
        let
            one = 1
            plustwo(x) = x + 2
            @optic _.a[plustwo(begin) - one].b
        end
        """))
        obj = (a=(1, (a=10, b=20), 3), b=4)
        @test l(obj) == 20
        @test set(obj, l, true) == (a=(1, (a=10, b=true), 3), b=4)
    end
end

@testset "StaticNumbers" begin
    obj = (1, 2.0, '3')
    l = @optic _[static(1)]
    @test (@inferred l(obj)) === 1
    @test (@inferred set(obj, l, 6.0)) === (6.0, 2.0, '3')
    l = @optic _[static(1 + 1)]
    @test (@inferred l(obj)) === 2.0
    @test (@inferred set(obj, l, 6)) === (1, 6, '3')
    n = 1
    l = @optic _[static(3n)]
    @test (@inferred l(obj)) === '3'
    @test (@inferred set(obj, l, 6)) === (1, 2.0, 6)

    l = @optic _[static(1):static(3)]
    @test l([4,5,6,7]) == [4,5,6]

    @testset "complex example (sweeper)" begin
        sweeper_with_const = (
            model = (1, 2.0, 3im),
            axis = (@optic _[static(2)]),
        )

        sweeper_with_noconst = @set sweeper_with_const.axis = @optic _[2]

        function f(s)
            a = sum(set(s.model, s.axis, 0))
            for i in 1:10
                a += sum(set(s.model, s.axis, i))
            end
            return a
        end

        @test (@inferred f(sweeper_with_const)) == 66 + 33im
        @test_broken (@inferred f(sweeper_with_noconst)) == 66 + 33im
    end
end

mutable struct M
    a
    b
end

@testset "IdentityLens" begin
    @test identity === @optic(_)
end

struct ABC{A,B,C}
    a::A
    b::B
    c::C
end

@testset "type change during @set (default constructorof)" begin
    obj = TT(2,3)
    obj2 = @set obj.b = :three
    @test obj2 === TT(2, :three)
end

# https://github.com/tkf/Reconstructables.jl#how-to-use-type-parameters
struct B{T, X, Y}
    x::X
    y::Y
    B{T}(x::X, y::Y = 2) where {T, X, Y} = new{T, X, Y}(x, y)
end
ConstructionBase.constructorof(::Type{<: B{T}}) where T = B{T}

@testset "type change during @set (custom constructorof)" begin
    obj = B{1}(2,3)
    obj2 = @set obj.y = :three
    @test obj2 === B{1}(2, :three)
end

@testset "Named Tuples" begin
    t = (x=1, y=2)
    @test (@set t.x =2) === (x=2, y=2)
    @test (@set t.x += 2) === (x=3, y=2)
    @test (@set t.x =:hello) === (x=:hello, y=2)
    l = @optic _.x
    @test l(t) === 1

    # do we want this to throw an error?
    @test_throws ArgumentError (@set t.z = 3)
end

struct CustomProperties
    _a
    _b
end

function ConstructionBase.setproperties(o::CustomProperties, patch::NamedTuple)
    CustomProperties(get(patch, :a, getfield(o, :_a)),
                     get(patch, :b, getfield(o, :_b)))

end

ConstructionBase.constructorof(::Type{CustomProperties}) = error()

@testset "setproperties overloading" begin
    o = CustomProperties("A", "B")
    o2 = @set o.a = :A
    @test o2 == CustomProperties(:A, "B")
    o3 = @set o.b = :B
    @test o3 == CustomProperties("A", :B)
end

@testset "issue #83" begin
    @test_throws ArgumentError Accessors.opticmacro(identity, :(_.[:a]))
end

@testset "|>" begin
    lbc = @optic _.b.c
    @test @optic(_ |> lbc) === lbc
    @test @optic(_.a |> lbc) === opcompose(@optic(_.a), lbc)
    @test @optic((_.a |> lbc).d) === opcompose(@optic(_.a), lbc , @optic(_.d))
    @test @optic(_.a |> lbc |> (@optic _[1]) |> lbc) ===
        opcompose(@optic(_.a), lbc, @optic(_[1]), lbc)

    @test @optic(_ |> _) === identity
    @test (@optic _ |> _[1])            === (@optic _[1])
    @test (@optic _ |> _.a)             === (@optic _.a)
    @test (@optic _ |> _.a.b)           === (@optic _.a.b)
    @test (@optic _ |> _.a[2])          === (@optic _.a[2])
    @test (@optic _ |> first |> _[1])   === (@optic first(_)[1])
    @test (@optic _ |> identity(first)) === first
    twice = lens -> lens ∘ lens
    @test (@optic _ |> twice(first)) === first ∘ first
    @test (@optic _ |> first |> _.a |> (first ∘ last) |> _[2]) ===
        (@optic (first ∘ last)(first(_).a)[2])
    @test (@optic _ |> _[1] |> _[2] |> _[3]) === @optic _[1][2][3]
end

if !Accessors.BASE_COMPOSED_FUNCTION_HAS_SHOW
    @info "Skipping show tests, on old VERSION = $VERSION"
else
    @testset "text/plain show" begin
        @testset for lens in [
            LensIfTextPlain()
        ]
            @test occursin("I define text/plain.", sprint(show, "text/plain", lens))
        end
        @testset for lens in [
            @optic _.a |> LensIfTextPlain()
            @optic _ |> LensIfTextPlain() |> _.b
            @optic _.a |> LensIfTextPlain() |> @optic _.b
        ]
            @test_broken occursin("I define text/plain.", sprint(show, "text/plain", lens))
        end

        @testset for lens in [
            UserDefinedLens()
            @optic _.a |> UserDefinedLens()
            @optic _ |> UserDefinedLens() |> _.b
            @optic _.a |> UserDefinedLens() |> _.b
        ]
            @test sprint(show, lens) == sprint(show, "text/plain", lens)
        end
    end

    @testset "show it like you build it " begin
        @testset for item in [
                @optic _.a
                @optic _[1]
                @optic _[:a]
                @optic _["a"]
                @optic _[static(1)]
                @optic _[static(1), static(1 + 1)]
                @optic _.a.b[:c]["d"][2][static(3)]
                @optic _
                @optic first(_)
                @optic last(first(_))
                @optic last(first(_.a))[1]
                UserDefinedLens()
                @optic _ |> UserDefinedLens()
                @optic UserDefinedLens()(_)
                @optic _ |> ((x -> x)(first))
                @optic _.a |> UserDefinedLens()
                @optic _ |> UserDefinedLens() |> _.b
                (@optic _.a) ∘ UserDefinedLens()   ∘ (@optic _.b)
                (@optic _.a) ∘ LensIfTextPlain() ∘ (@optic _.b)
            ]
            buf = IOBuffer()
            show(buf, item)
            item2 = eval(Meta.parse(String(take!(buf))))
            @test item === item2
        end
    end
end

@testset "@modify" begin
    obj = (field=4,)
    ret = @modify(obj.field) do x
        x + 1
    end
    expected = (field=5,)
    @test ret === expected
    @test obj === (field = 4,)

    @test expected === @modify(x -> x+1, obj.field)
    f = x -> x+1
    @test expected === @modify(f, obj.field)
    @test expected === @modify f obj.field
end

@testset "equality & hashing" begin
    # singletons (identity and property optic) are egal
    for (l1, l2) ∈ [
        @optic(_) => @optic(_),
        @optic(_.a) => @optic(_.a)
    ]
        @test l1 === l2
        @test l1 == l2
        @test hash(l1) == hash(l2)
    end

    # composite and index optices are structurally equal
    for (l1, l2) ∈ [
        @optic(_[1]) => @optic(_[1])
        @optic(_.a[2]) => @optic(_.a[2])
        @optic(_.a.b[3]) => @optic(_.a.b[3])
    ]
        @test l1 == l2
        @test hash(l1) == hash(l2)
    end

    # inequality
    for (l1, l2) ∈ [
        @optic(_[1]) => @optic(_[2])
        @optic(_.a[1]) => @optic(_.a[2])
        @optic(_.a[1]) => @optic(_.b[1])
    ]
        @test l1 != l2
    end

    # Hash property: equality implies equal hashes, or in other terms:
    # optices either have equal hashes or are unequal
    # Because collisions can occur theoretically (though unlikely), this is a property test,
    # not a unit test.
    random_optices = (@optic(_.a[rand(Int)]) for _ in 1:1000)
    @test all((hash(l2) == hash(l1)) || (l1 != l2)
              for (l1, l2) in zip(random_optices, random_optices))

    # Lenses should hash differently from the underlying tuples, to avoid confusion.
    # To account for potential collisions, we check that the property holds with high
    # probability.
    @test count(hash(@optic(_[i])) != hash((i,)) for i = 1:1000) > 900

    # Same for tuples of tuples (√(1000) ≈ 32).
    @test count(hash(@optic(_[i][j])) != hash(((i,), (j,))) for i = 1:32, j = 1:32) > 900
end

end


text:
@testset "Order tests" begin
    @testset "gtmax" begin
        @test @inferred(gtmax(1:10, 1:11)) == false
        @test @inferred(gtmax(1:11, 1:10)) == true
    end

    @testset "ltmax" begin
        @test @inferred(ltmax(1:10, 1:11)) == true
        @test @inferred(ltmax(1:11, 1:10)) == false
    end

    @testset "eqmax" begin
        @test @inferred(eqmax(1:10, 3:10)) == true
        @test @inferred(eqmax(1:11, 1:10)) == false
    end

    @testset "gtmin" begin
        @test @inferred(gtmin(1:10, 3:11)) == false
        @test @inferred(gtmin(3:11, 1:10)) == true
    end

    @testset "ltmin" begin
        @test @inferred(ltmin(1:10, 3:11)) == true
        @test @inferred(ltmin(3:11, 1:10)) == false
    end

    @testset "eqmin" begin
        @test @inferred(eqmin(3:10, 3:11)) == true
        @test @inferred(eqmin(3:11, 2:10)) == false
    end

    @testset "cmpmin" begin
        @test @inferred(cmpmin(0:10, 3.0:-1.0:1.0)) == -1
    end

    @testset "cmpmax" begin
        @test @inferred(cmpmax(1:10, 3.0:-1.0:1.0)) == 1
    end

    @testset "group_max" begin
        @test @inferred(group_max(1:10, [1,4, 20], 3.0:-1.0:1.0)) == 20
    end

    @testset "group_min" begin
        @test @inferred(group_min(1:10, [1,4, 20], 3.0:-1.0:1.0)) == 1
    end

    @testset "min_of_group_max" begin
        @test @inferred(min_of_group_max(1:10, 3.0:-1.0:1.0)) == min(maximum(1:10), maximum(3.0:-1.0:1.0))
    end

    @testset "max_of_group_min" begin
        @test @inferred(max_of_group_min(1:10, 3.0:-1.0:1.0)) == max(minimum(1:10), minimum(3.0:-1.0:1.0))
    end

    x = 1:10
    y = 10:-2:1
    z = [1.5, 1.7, 3.3]
    a = [1, 3, 2]

    @testset "order" begin
        @test @inferred(order(x)) == Forward
        @test order(y) == Reverse
        @test order(z) == Forward
        @test order(a) == Unordered
    end

    @testset "is_before" begin
        @test @inferred(is_before(2, 3, x)) == true
        @test @inferred(is_before(3, 2, x)) == false
        @test @inferred(is_before(1:2, 3:4)) == true
        @test @inferred(is_before(3:4, 1:2)) == false
        @test @inferred(is_before(2:-1:1, 4:-1:3)) == true
        @test @inferred(is_before(4:-1:3, 2:-1:1)) == false
    end

    @testset "is_after" begin
        @test @inferred(is_after(2, 3, x)) == false
        @test @inferred(is_after(3, 2, x)) == true
        @test @inferred(is_after(1:2, 3:4)) == false
        @test @inferred(is_after(3:4, 1:2)) == true
        @test @inferred(is_after(2:-1:1, 4:-1:3)) == false
        @test @inferred(is_after(4:-1:3, 2:-1:1)) == true
    end

    @testset "is_forward" begin
        @test @inferred(is_forward(x)) == true
        @test @inferred(is_forward(y)) == false
        @test @inferred(is_forward(z)) == true
        @test @inferred(is_forward(a)) == false
    end

    @testset "is_reverse" begin
        @test @inferred(is_reverse(x)) == false
        @test @inferred(is_reverse(y)) == true
        @test @inferred(is_reverse(z)) == false
        @test @inferred(is_reverse(a)) == false
    end

    @testset "is_ordered" begin
        @test @inferred(is_ordered(x)) == true
        @test @inferred(is_ordered(typeof(x))) == true
        @test @inferred(is_ordered(y)) == true
        @test @inferred(is_ordered(z)) == true
        @test @inferred(is_ordered(a)) == false
        @test @inferred(is_ordered(typeof(a))) == false
    end

    @testset "is_within" begin
        for (xo,yo,x,y) in ((Forward, Forward, 2:3, 1:10),
                            (Reverse, Reverse, 3:-1:2, 10:-1:1),
                            (Forward, Reverse, 2:3, 10:-1:1),
                            (Reverse, Forward, 3:-1:2, 1:10))
            @test @inferred(is_within(x, y)) == true
            @test @inferred(is_within(x, xo, y, yo)) == true
            @test @inferred(is_within(y, yo, x, xo)) == false
        end
    end

    @testset "find_max" begin
        @test find_max(x) == findmax(x)
        @test find_max(y) == findmax(y)
        @test find_max(z) == findmax(z)
        @test find_max(a) == findmax(a)
    end

    @testset "find_min" begin
        @test find_min(x) == findmin(x)
        @test find_min(y) == findmin(y)
        @test find_min(z) == findmin(z)
        @test find_min(a) == findmin(a)
    end

    @testset "is_contiguous" begin
        @test @inferred(is_contiguous(1:3, 3:4)) == true
        @test @inferred(is_contiguous(3:-1:1, 3:4)) == true
        @test @inferred(is_contiguous(3:-1:1, 4:-1:3)) == true
        @test @inferred(is_contiguous(1:3, 4:-1:3)) == true
        @test @inferred(is_contiguous(1:3, 2:4)) == false
    end

    @testset "next_type" begin
        @test next_type("a") == "b"
        @test next_type(:a) == :b
        @test next_type('a') == 'b'
        @test next_type(1) == 2
        @test next_type(1.0) == nextfloat(1.0)
        @test next_type("") == ""
    end

    @testset "prev_type" begin
        @test prev_type("b") == "a"
        @test prev_type(:b) == :a
        @test prev_type('b') == 'a'
        @test prev_type(1) == 0
        @test prev_type(nextfloat(1.0)) == prevfloat(nextfloat(1.0))
        @test prev_type("") == ""
    end

    @testset "is_forward" begin
        @test @inferred(is_forward([1, 2, 3])) == true
        @test @inferred(is_forward(Forward)) == true
        @test @inferred(is_forward(Reverse)) == false
        @test @inferred(is_forward(UnitSRange(1, 10))) == true
    end
    @testset "is_reverse" begin
        @test @inferred(is_reverse([1, 2, 3])) == false
        @test @inferred(is_reverse(Forward)) == false
        @test @inferred(is_reverse(Reverse)) == true
        @test @inferred(is_reverse(UnitSRange(1, 10))) == false
    end
end

#=
@testset "grow" begin
    sv_int = sorted([1,2,3])
    sv_float = sorted([1., 2., 3.])
    @test @inferred(grow_last!(sv_int, 2)) == [1, 2, 3, 4, 5]
    @test @inferred(grow_last!(sv_float, 1)) == [1., 2., 3., nextfloat(3.)]

    sr_int = sorted(mrange(1, 10))
    sr_float = sorted(mrange(1., 10.))
    @test @inferred(grow_last!(sr_int, 2)) == sorted(mrange(1, 12))
    @test @inferred(grow_last!(sr_float, 1)) == sorted(mrange(1., 11.))

    @test @inferred(grow_first!(sv_int, 2)) == [-1, 0, 1, 2, 3, 4, 5]
    @test @inferred(grow_first!(sv_float, 1)) == [prevfloat(1.), 1., 2., 3., nextfloat(3.)]

    @test @inferred(grow_first!(sr_int, 2)) == sorted(mrange(-1, 12))
    @test @inferred(grow_first!(sr_float, 1)) == sorted(mrange(0., 11.))
end

@testset "shrink" begin
    sv = SortedVector([1,2,3])
    @test shrink_last!(sv, 1) == [1,2]
    @test shrink_first!(sv, 1) == [2]
end
=#