text:
function try_move!(robot, side)::Bool
    if isborder(robot, side)
        false
    else
        move!(robot, side)
        true
    end
end

left(side::HorizonSide) = HorizonSide(mod(Int(side::HorizonSide)+1, 4))
function movements2(robot,side)
    while try_move!(robot,side)
        putmarker!(robot)
        move!(robot,side)
    end
end

function main(robot,side::HorizonSide)
    west_sud(robot)
    side=Ost
    for _ in 1:3
        movements2(robot,side)
        side=left(side::HorizonSide)
    end
end
function west_sud(robot)
    while try_move(r,West) || try_move(r,Sud)
        if try_move(r,West)
            move!(robot,West)
        else
            move!(r,Sud)
        end
    end
end

function mark_frame_perimetr!(r::Robot)
    num_vert = moves!(r, Sud)
    num_hor = moves!(r, West)
    #УТВ: Робот - в Юго-Западном углу

    for side in (Nord, Ost, Sud, West)
        putmarkers!(r, side)
    end
    #УТВ: По всему периметру стоят маркеры

    moves!(r, Nord, num_vert)
    moves!(r, Ost, num_hor)
    #УТВ: Робот - в исходном положении
end

function moves!(r::Robot,side::HorizonSide)
    num_steps=0
    while isborder(r,side)==false
        move!(r,side)
        num_steps+=1
    end
    return num_steps
end

function moves!(r::Robot,side::HorizonSide,num_steps::Int)
    for _ in 1:num_steps # символ "_" заменяет фактически не используемую переменную
        move!(r,side)
    end
end

function putmarkers!(r::Robot, side::HorizonSide)
    while isborder(r,side)==false
        move!(r,side)
        putmarker!(r)
    end
end

max_stars_repo_name: NikitaDestroyer/Basics

max_issues_repo_name: NikitaDestroyer/Basics

max_forks_repo_name: NikitaDestroyer/Basics


text:
using Potree
using Test

# WARNING : change with your path, just click on the folder and copy-paste path
# path to "../potre/so_on
# I'm just using the same potree version with different output Format
# if u want to change the potree files check if the version is supported

potreeBIN = "C:/Users/Alessio/.julia/dev/Potree/potree/stairsBIN(v1.7)"
potreeLAS = "C:/Users/Alessio/.julia/dev/Potree/potree/stairsLAS(v1.7)"
potreeLAZ = "C:/Users/Alessio/.julia/dev/Potree/potree/stairsLAZ(v1.7)"

oneNodeBIN = "C:/Users/Alessio/.julia/dev/Potree/potree/stairsBIN(v1.7)/data/r/r0.bin"
oneNodeLAS = "C:/Users/Alessio/.julia/dev/Potree/potree/stairsLAS(v1.7)/data/r/r0.las"
oneNodeLAZ = "C:/Users/Alessio/.julia/dev/Potree/potree/stairsLAZ(v1.7)/data/r/r0.laz"

# Hardcoded potree infos
# If u change the testing potree u must change these values

totalNodes = 71 # aka number of files
maxDepth = 3    # depth of the tree
totalPoints = (3, 357003) # using that to check coordinates and rgbs ( 3 (xyz/rgb), 357003 (total points))
boundingbox = (1.4770147800445557, -0.7153962850570679, -1.4153246879577637, 5.361339569091797, 3.1689285039901735, 2.4690001010894777)

#las.jl testing

@testset "las2pointcloud" begin
    @test size(Potree.las2pointcloud((Potree.get_all_values(Potree.potree2trie(potreeLAS)))...).coordinates) == totalPoints
    @test size(Potree.las2pointcloud((Potree.get_all_values(Potree.potree2trie(potreeLAZ)))...).coordinates) == totalPoints

    @test size(Potree.las2pointcloud((Potree.get_all_values(Potree.potree2trie(potreeLAS)))...).rgbs) == totalPoints
    @test size(Potree.las2pointcloud((Potree.get_all_values(Potree.potree2trie(potreeLAZ)))...).rgbs) == totalPoints
end

@testset "las2larpoints" begin
    @test (Potree.las2larpoints(oneNodeLAS)) == (Potree.las2larpoints(oneNodeLAZ))
    #@test (Potree.las2larpoints(oneNodeBIN)) == (Potree.las2larpoints(oneNodeLAZ))
    #@test (Potree.las2larpoints(oneNodeBIN)) == (Potree.las2larpoints(oneNodeLAS))
end

#hierarchy.jl testing

@testset "max_depth" begin
    @test Potree.max_depth(Potree.potree2trie(potreeBIN)) == maxDepth
    @test Potree.max_depth(Potree.potree2trie(potreeLAS)) == maxDepth
    @test Potree.max_depth(Potree.potree2trie(potreeLAZ)) == maxDepth
end

# check if get_all_values reads all files and types

@testset "get_all_values" begin

    # size gives a tuple (totalNodes, ) so use [1] to check the first element

    @test size(Potree.get_all_values(Potree.potree2trie(potreeBIN)))[1] == totalNodes
    @test size(Potree.get_all_values(Potree.potree2trie(potreeLAS)))[1] == totalNodes
    @test size(Potree.get_all_values(Potree.potree2trie(potreeLAZ)))[1] == totalNodes
end

@testset "sub_trie" begin

end

@testset "get_files_in_potree_folder + get_files" begin

# size gives a tuple (totalNodes, ) so use [1] to check the first element

    # LOD = 0, just one node (radix node)
    @test size(Potree.get_files_in_potree_folder(potreeBIN, 0))[1] == 1
    @test size(Potree.get_files_in_potree_folder(potreeLAS, 0))[1] == 1
    @test size(Potree.get_files_in_potree_folder(potreeLAZ, 0))[1] == 1

    # LOD = 1, radix + 7 child
    @test size(Potree.get_files_in_potree_folder(potreeBIN, 1))[1] == 8
    @test size(Potree.get_files_in_potree_folder(potreeLAS, 1))[1] == 8
    @test size(Potree.get_files_in_potree_folder(potreeLAZ, 1))[1] == 8

    # LOD = 2, radix + 7 child + 26 child of child
    @test size(Potree.get_files_in_potree_folder(potreeBIN, 2))[1] == 36
    @test size(Potree.get_files_in_potree_folder(potreeLAS, 2))[1] == 36
    @test size(Potree.get_files_in_potree_folder(potreeLAZ, 2))[1] == 36

    # LOD = 3, radix + 7 child + 26 child of child + 35 child = totalNodes (71)
    @test size(Potree.get_files_in_potree_folder(potreeBIN, 3))[1] == totalNodes
    @test size(Potree.get_files_in_potree_folder(potreeLAS, 3))[1] == totalNodes
    @test size(Potree.get_files_in_potree_folder(potreeLAZ, 3))[1] == totalNodes
end

# bin.jl testing

@testset "bin2pointcloud" begin

    # !!! once you change bin2pointcloud you MUST change this test
    # !!! not testing wheter the bin PC is the same as the LAS PC
    # !!! not testing if the rgbs are good

    @test (size(Potree.bin2pointcloud(potreeBIN)) == totalPoints)
    @test (size(Potree.bin2pointcloudNoMultithreading(potreeBIN)) == totalPoints)
end

ext: jl


text:
export simulate

"""
    sample_locus(locus::Dict, n::Int, ploidy::Signed)
Internal function used by `simulate` to take a `Dict` of alleles => frequencies of a locus and return
`n` number of genotypes (n_alleles = `ploidy`) by using weighted sampling of the
allele-frequency pairs.

**Example**
```julia
d = Dict(
  133 => 0.125,
  135 => 0.5625,
  143 => 0.25,
  137 => 0.0625
  )

julia> sample_locus(d, 3, 2)
5-element Array{Tuple{Int16,Int16},1}:
 (133, 135)
 (135, 135)
 (143, 137)

julia> sample_locus(d, 3, 3)
5-element Array{Tuple{Int16,Int16,Int16},1}:
 (135, 135, 133)
 (143, 135, 133)
 (137, 135, 135)
```
"""
function sample_locus(locus::Dict, n::Int, ploidy::Signed)
    isempty(locus) && return fill(missing, n)
    k,v = collect(keys(locus)), collect(values(locus))
    alleles = [sample(k, Weights(v), n) for i in 1:ploidy]
    Tuple.(sort.(eachrow(hcat(alleles...))))
end

"""
    simulate(data::PopData; n::Int = 100)
Simulate `n` number of individuals per population (default: `100`) using per-population
allele frequencies derived from a `PopData` object. Returns a new `PopData` object.

**Example**
```julia
cats = nancycats();

julia> sims = simulate(cats , n = 100)
PopData Object
  Markers: Microsatellite
  Ploidy: 2
  Samples: 1700
  Loci: 9
  Populations: 17
  Coordinates: absent
  julia> sims.meta

1700×5 DataFrame
│ Row  │ name     │ population │ ploidy │ longitude │ latitude │
│      │ String   │ String     │ Int64  │ Missing   │ Missing  │
├──────┼──────────┼────────────┼────────┼───────────┼──────────┤
│ 1    │ sim_1    │ 1          │ 2      │ missing   │ missing  │
│ 2    │ sim_2    │ 1          │ 2      │ missing   │ missing  │
│ 3    │ sim_3    │ 1          │ 2      │ missing   │ missing  │
│ 4    │ sim_4    │ 1          │ 2      │ missing   │ missing  │
⋮
│ 1696 │ sim_1696 │ 17         │ 2      │ missing   │ missing  │
│ 1697 │ sim_1697 │ 17         │ 2      │ missing   │ missing  │
│ 1698 │ sim_1698 │ 17         │ 2      │ missing   │ missing  │
│ 1699 │ sim_1699 │ 17         │ 2      │ missing   │ missing  │
│ 1700 │ sim_1700 │ 17         │ 2      │ missing   │ missing  │
julia> sims.loci
15300×4 DataFrame
│ Row   │ name     │ population │ locus  │ genotype   │
│       │ String   │ String     │ String │ Tuple…?    │
├───────┼──────────┼────────────┼────────┼────────────┤
│ 1     │ sim_1    │ 1          │ fca8   │ (135, 135) │
│ 2     │ sim_1    │ 1          │ fca23  │ (132, 140) │
│ 3     │ sim_1    │ 1          │ fca43  │ (139, 139) │
│ 4     │ sim_1    │ 1          │ fca45  │ (126, 126) │
⋮
│ 15297 │ sim_1700 │ 17         │ fca78  │ (142, 142) │
│ 15298 │ sim_1700 │ 17         │ fca90  │ (199, 199) │
│ 15299 │ sim_1700 │ 17         │ fca96  │ (113, 113) │
│ 15300 │ sim_1700 │ 17         │ fca37  │ (208, 208) │
```
"""
function simulate(data::PopData; n::Int = 100)
    length(unique(data.meta.ploidy)) != 1 && error("Simulations do not work on mixed-ploidy data (yet)")
    ploidy = first(unique(data.meta.ploidy))
    pops = unique(data.meta.population)
    npops = length(pops)
    nloci = length(data.loci.locus.pool)

    # instantiate output df
    simnames = reduce(vcat, fill.(["sim_" * "$i" for i in 1:(n*npops)], nloci))
    popnames = reduce(vcat, fill.(pops, (nloci * n)))
    locinames = reduce(vcat, fill.(Ref(unique(data.loci.locus)), (n * npops)))
    geno_out = DataFrame(:name => simnames, :population => popnames, :locus => locinames, :genotype => similar(data.loci.genotype, length(locinames)))

    # generate allele freqs per population
    gdf = groupby(data.loci, [:population, :locus])
    freqs = DataFrames.combine(
        gdf,
        :genotype => allele_freq => :frq
    )
    # create new genotypes
    transform!(freqs, :frq => (i -> sample_locus.(i,n,ploidy)) => :frq)

    # populate out df
    out_gdf = groupby(geno_out, :population)
    geno_gdf = groupby(freqs, :population)
    for pop in pops
        out_gdf[(population = pop,)].genotype .= reduce(hcat, geno_gdf[(population = pop,)].frq) |> permutedims |> vec
    end

    # regenerate meta info
    meta_df = DataFrames.combine(
        groupby(geno_out, :name),
        :name => first => :name,
        :population => first => :population
    )
    meta_df[!, :ploidy] .= 2
    meta_df[!, :longitude] .= missing
    meta_df[!, :latitude] .= missing

    PopData(meta_df, geno_out)
end


text:
# Note that this script can accept some limited command-line arguments, run
# `julia build_tarballs.jl --help` to see a usage message.
using BinaryBuilder, Pkg

name = "assimp"
version = v"5.0.1"

# Collection of sources required to complete build
sources = [
    "https://github.com/assimp/assimp.git" =>
    "8f0c6b04b2257a520aaab38421b2e090204b69df",
]

# Bash recipe for building across all platforms
script = raw"""
cd $WORKSPACE/srcdir
cd assimp/
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=$prefix -DCMAKE_TOOLCHAIN_FILE="${CMAKE_TARGET_TOOLCHAIN}" \
    -DCMAKE_BUILD_TYPE=Release \
    -DASSIMP_BUILD_ASSIMP_TOOLS=false \
    -DASSIMP_BUILD_TESTS=false \
    -DASSIMP_INSTALL_PDB=false \
    -DASSIMP_DOUBLE_PRECISION=false \

make -j${nproc}
make install
"""

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms = [p for p in supported_platforms() if p != Platform("i686", "linux"; libc="musl") &&
                                                 p != Platform("armv7l", "linux"; libc="musl")
            ]
platforms = expand_cxxstring_abis(platforms)

# The products that we will ensure are always built
products = [
    LibraryProduct("libassimp", :libassimp)
]

# Dependencies that must be installed before this package can be built
dependencies = [
    Dependency("Zlib_jll")
]

# Build the tarballs, and possibly a `build.jl` as well.
build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies, preferred_gcc_version=v"7")

max_stars_repo_name: blenessy/Yggdrasil

max_issues_repo_name: blenessy/Yggdrasil

max_forks_repo_name: blenessy/Yggdrasil


text:
export Derivative,Integral,Laplacian,Volterra

abstract CalculusOperator{S,OT,T}<:Operator{T}

## Note that all functions called in calculus_operator must be exported

macro calculus_operator(Op)
    ConcOp=parse("Concrete"*string(Op))
    WrappOp=parse(string(Op)*"Wrapper")
    return esc(quote
        # The SSS, TTT are to work around #9312
        abstract $Op{SSS,OT,TTT} <: CalculusOperator{SSS,OT,TTT}

        immutable $ConcOp{S<:Space,OT,T} <: $Op{S,OT,T}
            space::S        # the domain space
            order::OT
        end
        immutable $WrappOp{BT<:Operator,S<:Space,OT,T} <: $Op{S,OT,T}
            op::BT
            order::OT
        end

        @wrapper $WrappOp

        ## Constructors
        $ConcOp(sp::Space,k)=$ConcOp{typeof(sp),typeof(k),op_eltype(sp)}(sp,k)

        $Op(sp::UnsetSpace,k)=$ConcOp(sp,k)
        $Op(sp::UnsetSpace,k::Real)=$ConcOp(sp,k)
        $Op(sp::UnsetSpace,k::Integer)=$ConcOp(sp,k)

        function $Op(sp,k)
            csp=canonicalspace(sp)
            if conversion_type(csp,sp)==csp   # Conversion(sp,csp) is not banded, or sp==csp
               error("Implement $(string($Op))($(string(sp)),$k)")
            end
            $WrappOp(TimesOperator([$Op(csp,k),Conversion(sp,csp)]),k)
        end

        $Op(sp)=$Op(sp,1)
        $Op()=$Op(UnsetSpace())
        $Op(k::Number)=$Op(UnsetSpace(),k)

        $Op(d::Domain,n)=$Op(Space(d),n)
        $Op(d::Domain)=$Op(d,1)
        $Op(d::Vector)=$Op(Space(d),1)
        $Op(d::Vector,n)=$Op(Space(d),n)
        $ConcOp(S::Space)=$ConcOp(S,1)

        function Base.convert{T}(::Type{Operator{T}},D::$ConcOp)
            if T==eltype(D)
                D
            else
                $ConcOp{typeof(D.space),typeof(D.order),T}(D.space,D.order)
            end
        end

        $WrappOp(op::Operator,order) =
            $WrappOp{typeof(op),typeof(domainspace(op)),typeof(order),eltype(op)}(op,order)
        $WrappOp(op::Operator) = $WrappOp(op,1)

        function Base.convert{T}(::Type{Operator{T}},D::$WrappOp)
            if T==eltype(D)
                D
            else
                # work around typeinfernece bug
                op=convert(Operator{T},D.op)
                $WrappOp{typeof(op),typeof(domainspace(op)),typeof(D.order),T}(op,D.order)
            end
        end

        ## Routines
        domain(D::$ConcOp) = domain(D.space)
        domainspace(D::$ConcOp) = D.space

        getindex{OT,T}(::$ConcOp{UnsetSpace,OT,T},k::Integer,j::Integer) =
            error("Spaces cannot be inferred for operator")
        rangespace{T}(D::$ConcOp{UnsetSpace,T}) = UnsetSpace()

        #promoting domain space is allowed to change range space
        # for integration, we fall back on existing conversion for now
        promotedomainspace(D::$Op,sp::UnsetSpace) = D

        function promotedomainspace(D::$Op,sp::Space)
            if isambiguous(domain(sp))
                $Op(typeof(sp)(domain(D)),D.order)
            else
                $Op(sp,D.order)
            end
        end
    end)
#     for func in (:rangespace,:domainspace,:bandinds)
#         # We assume the operator wrapped has the correct spaces
#         @eval $func(D::$WrappOp)=$func(D.op)
#     end
end

choosedomainspace(M::CalculusOperator{UnsetSpace},sp::Space) =
    iswrapper(M)?choosedomainspace(M.op,sp):sp  # we assume the space itself will work

@calculus_operator(Derivative)
@calculus_operator(Integral)
@calculus_operator(Volterra)

for TYP in (:Derivative,:Integral)
    @eval begin
        function *(D1::$TYP,D2::$TYP)
            @assert domain(D1) == domain(D2)

            $TYP(domainspace(D2),D1.order+D2.order)
        end
    end
end

## Overrideable

## Convenience routines

integrate(d::Domain)=Integral(d,1)

# Default is to use ops
differentiate(f::Fun)=Derivative(space(f))*f
function integrate(f::Fun)
    d=domain(f)
    cd=canonicaldomain(d)
    if typeof(d)==typeof(cd)  || isa(d,PeriodicDomain)
        Integral(space(f))*f
    else
        # map to canonical domain
        setdomain(integrate(setdomain(f,cd)*fromcanonicalD(f)),d)
    end
end

function Base.sum(f::Fun)
    d=domain(f)
    cd=canonicaldomain(d)
    if typeof(cd)==typeof(d)  || isa(d,PeriodicDomain)
        g=integrate(f)
        last(g)-first(g)
    else
        # map first
        sum(setdomain(f,cd)*fromcanonicalD(f))
    end
end

function linesum(f::Fun)
    cd=canonicaldomain(f)
    d=domain(f)
    if typeof(cd)==typeof(d)  || isa(d,PeriodicDomain)
        error("override linesum for $(f.space)")
    else
        # map first
        linesum(setdomain(f,cd)*abs(fromcanonicalD(f)))
    end
end

# Multivariate

@calculus_operator(Laplacian)

## Map to canonical
function defaultDerivative(sp::Space,order::Integer)
    if typeof(canonicaldomain(sp)).name==typeof(domain(sp)).name
        # this is the normal default constructor
        csp=canonicalspace(sp)
        if conversion_type(csp,sp)==csp   # Conversion(sp,csp) is not banded, or sp==csp
           error("Implement Derivative($(string(sp)),$order)")
        end
        DerivativeWrapper(TimesOperator([Derivative(csp,order),Conversion(sp,csp)]),order)
    else
        D1=invfromcanonicalD(sp)*Derivative(setdomain(sp,canonicaldomain(sp)))
        D=DerivativeWrapper(SpaceOperator(D1,sp,setdomain(rangespace(D1),domain(sp))),1)
        if order==1
            D
        else
            DerivativeWrapper(TimesOperator(Derivative(rangespace(D),order-1),D),order)
        end
    end
end

Derivative(sp::Space,order)=defaultDerivative(sp,order)

function Integral(sp::Space,k::Integer)
    if typeof(canonicaldomain(sp)).name==typeof(domain(sp)).name
        # this is the normal default constructor
        csp=canonicalspace(sp)
        if conversion_type(csp,sp)==csp   # Conversion(sp,csp) is not banded, or sp==csp
            # we require that Integral is overridden
            error("Implement Integral($(string(sp)),$order)")
        end
        IntegralWrapper(TimesOperator([Integral(csp,order),Conversion(sp,csp)]),order)
    elseif k > 1
        Q=Integral(sp,1)
        IntegralWrapper(TimesOperator(Integral(rangespace(Q),k-1),Q),k)
    else # k==1
        csp=setdomain(sp,canonicaldomain(sp))

        x=Fun(identity,domain(csp))
        M=Multiplication(fromcanonicalD(sp,x),csp)
        Q=Integral(rangespace(M))*M
        IntegralWrapper(SpaceOperator(Q,sp,setdomain(rangespace(Q),domain(sp))),1)
    end
end


text:
struct SVD{T} <: SurpriseModel{T}
    object::PyObject
    features::Int
    n_epochs::Int
    lrate::Float64
    lambda::Float64
    preference::Persa.Preference{T}
    users::Int
    items::Int
end

function SVD(
    dataset::Persa.Dataset,
    biased::Bool;
    features = 100,
    n_epochs = 20,
    lrate = 0.005,
    lambda = 0.02,
)
    return SVD(
        surprise.SVD(
            biased = biased,
            n_factors = features,
            n_epochs = n_epochs,
            lr_all = lrate,
            reg_all = lambda,
        ),
        features,
        n_epochs,
        lrate,
        lambda,
        dataset.preference,
        Persa.users(dataset),
        Persa.items(dataset)
    )
end

"""
    IRSVD(dataset::Persa.Dataset; features = 100, n_epochs = 20, lrate = 0.005, lambda = 0.02)
Improved Regulared SVD. Extension of RSVD algorithm adding the user and item
bias.
# Arguments
- `features::Int = 100`: Number of factors.
- `n_epochs::Int = 20`: The number of iteration of the SGD algorithm.
- `lrate::Float = 0.005`: Learning rate parameter.
- `lambda::Int = 0.02`: Regularization parameter.
"""
function IRSVD(
    dataset::Persa.Dataset;
    features = 100,
    n_epochs = 20,
    lrate = 0.005,
    lambda = 0.02,
)
    return SVD(
        dataset,
        true;
        features = features,
        n_epochs = n_epochs,
        lrate = lrate,
        lambda = lambda,
    )
end

"""
    RSVD(dataset::Persa.Dataset; features = 100, n_epochs = 20, lrate = 0.005, lambda = 0.02)
Regulared SVD. The algorithm is also known as SVD by Funk.
# Arguments
- `features::Int = 100`: Number of factors.
- `n_epochs::Int = 20`: The number of iteration of the SGD algorithm.
- `lrate::Float = 0.005`: Learning rate parameter.
- `lambda::Int = 0.02`: Regularization parameter.
"""
function RSVD(
    dataset::Persa.Dataset;
    features = 100,
    n_epochs = 20,
    lrate = 0.005,
    lambda = 0.02,
)
    return SVD(
        dataset,
        false;
        features = features,
        n_epochs = n_epochs,
        lrate = lrate,
        lambda = lambda,
    )
end

struct NMF{T} <: SurpriseModel{T}
    object::PyObject
    features::Int
    n_epochs::Int
    biased::Bool
    preference::Persa.Preference{T}
    users::Int
    items::Int
end

"""
    NMF(dataset::Persa.Dataset; features = 100, n_epochs = 20, lrate = 0.005, lambda = 0.02)
Collaborative Filtering based on Non-negative Matrix Factorization.
# Arguments
- `features::Int = 15`: Number of factors.
- `n_epochs::Int = 50`: The number of iteration of the SGD algorithm.
- `biased::Bool = false`: If the method use biases.
"""
function NMF(
    dataset::Persa.Dataset;
    features::Int = 15,
    n_epochs::Int = 50,
    biased::Bool = false,
)
    return NMF(
        surprise.NMF(n_factors = features, n_epochs = n_epochs, biased = biased),
        features,
        n_epochs,
        biased,
        dataset.preference,
        Persa.users(dataset),
        Persa.items(dataset)
    )
end


text:
module CutCell

using LinearAlgebra
using SparseArrays
using NearestNeighbors
using CartesianMesh
using PolynomialBasis
using ImplicitDomainQuadrature
import ImplicitDomainQuadrature: extend

include("cell_map.jl")
include("elasticity.jl")
include("mesh_routines.jl")
include("dg_mesh.jl")
include("weak_form.jl")
include("assembly.jl")
include("dirichlet_bc.jl")
include("cut_mesh.jl")
include("cell_quadratures.jl")
include("face_quadratures.jl")
include("interface_quadratures.jl")
include("cell_merging.jl")
include("cut_mesh_bilinear_forms.jl")
include("transformation_strain.jl")
include("interface_conditions.jl")
include("penalty_displacement_bc.jl")
include("stress.jl")
include("cut_mesh_assembly.jl")
include("postprocess.jl")
include("levelset_reinitialize.jl")
include("levelset_propagate.jl")
include("utilities.jl")

export plane_strain_voigt_hooke_matrix

end # module


text:
# Autogenerated wrapper script for CUDA_compat_jll for x86_64-linux-gnu
export libcuda, libnvidia_ptxjitcompiler

JLLWrappers.@generate_wrapper_header("CUDA_compat")
JLLWrappers.@declare_library_product(libcuda, "libcuda.so.1")
JLLWrappers.@declare_library_product(libnvidia_ptxjitcompiler, "libnvidia-ptxjitcompiler.so.1")
function __init__()
    JLLWrappers.@generate_init_header()
    JLLWrappers.@init_library_product(
        libcuda,
        "lib/libcuda.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_library_product(
        libnvidia_ptxjitcompiler,
        "lib/libnvidia-ptxjitcompiler.so.1",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
using QCMaterial
using PyCall
using LinearAlgebra

import Random
import PyCall: pyimport

"tau plus"
nsite = 4
n_qubit　= 2*nsite
U = 1.0
V = 1.0
μ = 1.0
ε = 1.0
d_theta = 1e-5

# Output debug messages only on the master node
verbose = QCMaterial.MPI_rank == 0

#Hamiltonian
ham_op = generate_impurity_ham_with_1imp_multibath(U, V, μ, ε, nsite)

n_electron_gs = 4
@assert mod(n_electron_gs, 2) == 0
sparse_mat = get_number_preserving_sparse_operator(ham_op, n_qubit, n_electron_gs);
enes_ed = eigvals(sparse_mat.toarray());

#debug
println("Ground energy_ED=",minimum(enes_ed))

#ansatz
state0 = create_hf_state(n_qubit, n_electron_gs)
vc = uccgsd(n_qubit, orbital_rot=true)
theta_init = rand(num_theta(vc))

#Perform VQE
cost_history, thetas_opt =
QCMaterial.solve_gs(jordan_wigner(ham_op), vc, state0, theta_init=theta_init, verbose=true,
    comm=QCMaterial.MPI_COMM_WORLD
)

#debug
println("Ground energy_VQE=",cost_history[end])

#c^{dag},c
up1 = up_index(1)
down1 = down_index(1)
up2 = up_index(2)
down2 = down_index(2)
right_op = FermionOperator("$(up1)^ ", 1.0)
right_op = jordan_wigner(right_op)
left_op = FermionOperator("$(up1) ", 1.0)
left_op = jordan_wigner(left_op)

##Ansatz -> apply_qubit_op & imag_time_evolve
vc_ex = uccgsd(n_qubit, orbital_rot=true)

#state_gs = QulacsQuantumState(n_qubit,0b0000)
state_gs = create_hf_state(n_qubit, n_electron_gs)
update_circuit_param!(vc, thetas_opt)
update_quantum_state!(vc, state_gs)

n_electron_ex = 5
state0_ex = create_hf_state(n_qubit, n_electron_ex)

taus = collect(range(0.0, 0.2, length=8))
half_beta = taus[end]

Gfunc_ij_list = compute_gtau(jordan_wigner(ham_op), left_op, right_op, vc_ex,  state_gs, state0_ex, taus, d_theta, verbose=verbose)
println("Gfunc_ij_list=", Gfunc_ij_list)

function write_to_txt(file_name, x, y)
    open(file_name,"w") do fp
        for i in 1:length(x)
            println(fp, x[i], " ", real(y[i]))
        end
    end
end

write_to_txt("gf_upup_4site_plus_points_8.txt", taus, Gfunc_ij_list)

max_stars_repo_name: Sakurairihito/QCMaterialNew

max_issues_repo_name: sakurairihito/QCMaterialNew

max_forks_repo_name: sakurairihito/QCMaterialNew


text:
# # Example 10
# This example is from The models of bilevel programming with lower level second-order cone programs ([url](https://journalofinequalitiesandapplications.springeropen.com/articles/10.1186/1029-242X-2014-168) or [url](https://core.ac.uk/download/pdf/81261904.pdf))
# SOCBLP stands for bilevel programming problem with lower level second-order cone program
# Bold point(s): Using second-order cone in the lower level problem

# Model of the problem
# First level
# ```math
# \min x + 3(y_1-y_2),\\
# \notag s.t.\\
# 2 \leq x \leq 6,\\
# ```
# Second level
# ```math
# \min - y_1 + y_2,\\
# \notag s.t.\\
# y_1 - y_2 \leq  8,\\
# 4y_1 - 4y_2 \geq  8,\\
# 2y_1 - 2y_2 \leq  12,\\
# y_1 \geq 0,\\
# y_2 \geq 0,\\
# y \in K^2\\
# ```

# Here, ``K^2`` is second order cone and it represents:
# ```math
# y \in \{y=(y_1,y_2)\in \mathbb{R}\times \mathbb{R}:y_1 \geq ||y_2||_2\}\\
# ```

using BilevelJuMP
using Ipopt
using JuMP
using Test

model = BilevelModel(() -> MOI.Bridges.Constraint.SOCtoNonConvexQuad{Float64}(Ipopt.Optimizer()), mode = BilevelJuMP.ProductMode(1e-9))

# First we need to create all of the variables in the upper and lower problems:

# Upper level variables
@variable(Upper(model), x)

#Lower level variables
@variable(Lower(model), y[i=1:2])

# Then we can add the objective and constraints of the upper problem:

# Upper level objecive function
@objective(Upper(model), Min, x + 3(y[1] -y[2]))

# Upper level constraints
@constraint(Upper(model), x >= 2)
@constraint(Upper(model), x <= 6)

# Followed by the objective and constraints of the lower problem:

# Lower objective function
@objective(Lower(model), Min, - (y[1] - y[2]))

# Lower constraints
@constraint(Lower(model), lb_y_1, y[1] >= 0)
@constraint(Lower(model), lb_y_2, y[2] >= 0)
@constraint(Lower(model), con1, x +  (y[1] - y[2]) <=  8)
@constraint(Lower(model), con2, x + 4(y[1] - y[2]) >=  8)
@constraint(Lower(model), con3, x + 2(y[1] - y[2]) <= 12)
@constraint(Lower(model), soc_lw, y in SecondOrderCone())

# Defining bounds
BilevelJuMP.set_dual_upper_bound(soc_lw, +[5., 5.])
BilevelJuMP.set_dual_lower_bound(soc_lw, -[5., 5.])
# require lower bounds
for con in [con1, con3]
    BilevelJuMP.set_dual_lower_bound(con, -15)
end
# require upper bounds
for con in [lb_y_1, lb_y_2, con2]
    BilevelJuMP.set_dual_upper_bound(con, +15)
end
# bounds defined in the upper level are not dualized
for i in 1:2
    @constraint(Upper(model), y[i] in MOI.LessThan(+5.0))
    @constraint(Upper(model), y[i] in MOI.GreaterThan(-5.0))
end

# Now we can solve the problem and verify the solution again that reported by

optimize!(model)
primal_status(model)
termination_status(model)

value.(y)

@test objective_value(model) ≈ 12  atol=1e-1
@test value(x) ≈ 6 atol=1e-3
@test value(y[2]) >= 0 - 1e-3
@test value(y[1]) - value(y[2]) ≈ 2 atol=1e-3


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

"""
    CreateApp()

Creates an application. An application consists of one or more server groups. Each server group contain one or more servers.

# Optional Parameters
- `clientToken`: A unique, case-sensitive identifier that you provide to ensure the idempotency of application creation.
- `description`: The description of the new application
- `name`: The name of the new application.
- `roleName`: The name of the service role in the customer's account to be used by AWS SMS.
- `serverGroups`: The server groups to include in the application.
- `tags`: The tags to be associated with the application.
"""
create_app(; aws_config::AWSConfig=global_aws_config()) = sms("CreateApp"; aws_config=aws_config)
create_app(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("CreateApp", args; aws_config=aws_config)

"""
    CreateReplicationJob()

Creates a replication job. The replication job schedules periodic replication runs to replicate your server to AWS. Each replication run creates an Amazon Machine Image (AMI).

# Required Parameters
- `seedReplicationTime`: The seed replication time.
- `serverId`: The ID of the server.

# Optional Parameters
- `description`: The description of the replication job.
- `encrypted`: Indicates whether the replication job produces encrypted AMIs.
- `frequency`: The time between consecutive replication runs, in hours.
- `kmsKeyId`: The ID of the KMS key for replication jobs that produce encrypted AMIs. This value can be any of the following:   KMS key ID   KMS key alias   ARN referring to the KMS key ID   ARN referring to the KMS key alias    If encrypted is true but a KMS key ID is not specified, the customer's default KMS key for Amazon EBS is used.
- `licenseType`: The license type to be used for the AMI created by a successful replication run.
- `numberOfRecentAmisToKeep`: The maximum number of SMS-created AMIs to retain. The oldest is deleted after the maximum number is reached and a new AMI is created.
- `roleName`: The name of the IAM role to be used by the AWS SMS.
- `runOnce`: Indicates whether to run the replication job one time.
"""
create_replication_job(seedReplicationTime, serverId; aws_config::AWSConfig=global_aws_config()) = sms("CreateReplicationJob", Dict{String, Any}("seedReplicationTime"=>seedReplicationTime, "serverId"=>serverId); aws_config=aws_config)
create_replication_job(seedReplicationTime, serverId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("CreateReplicationJob", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("seedReplicationTime"=>seedReplicationTime, "serverId"=>serverId), args)); aws_config=aws_config)

"""
    DeleteApp()

Deletes the specified application. Optionally deletes the launched stack associated with the application and all AWS SMS replication jobs for servers in the application.

# Optional Parameters
- `appId`: The ID of the application.
- `forceStopAppReplication`: Indicates whether to stop all replication jobs corresponding to the servers in the application while deleting the application.
- `forceTerminateApp`: Indicates whether to terminate the stack corresponding to the application while deleting the application.
"""
delete_app(; aws_config::AWSConfig=global_aws_config()) = sms("DeleteApp"; aws_config=aws_config)
delete_app(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("DeleteApp", args; aws_config=aws_config)

"""
    DeleteAppLaunchConfiguration()

Deletes the launch configuration for the specified application.

# Optional Parameters
- `appId`: The ID of the application.
"""
delete_app_launch_configuration(; aws_config::AWSConfig=global_aws_config()) = sms("DeleteAppLaunchConfiguration"; aws_config=aws_config)
delete_app_launch_configuration(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("DeleteAppLaunchConfiguration", args; aws_config=aws_config)

"""
    DeleteAppReplicationConfiguration()

Deletes the replication configuration for the specified application.

# Optional Parameters
- `appId`: The ID of the application.
"""
delete_app_replication_configuration(; aws_config::AWSConfig=global_aws_config()) = sms("DeleteAppReplicationConfiguration"; aws_config=aws_config)
delete_app_replication_configuration(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("DeleteAppReplicationConfiguration", args; aws_config=aws_config)

"""
    DeleteAppValidationConfiguration()

Deletes the validation configuration for the specified application.

# Required Parameters
- `appId`: The ID of the application.

"""
delete_app_validation_configuration(appId; aws_config::AWSConfig=global_aws_config()) = sms("DeleteAppValidationConfiguration", Dict{String, Any}("appId"=>appId); aws_config=aws_config)
delete_app_validation_configuration(appId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("DeleteAppValidationConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("appId"=>appId), args)); aws_config=aws_config)

"""
    DeleteReplicationJob()

Deletes the specified replication job. After you delete a replication job, there are no further replication runs. AWS deletes the contents of the Amazon S3 bucket used to store AWS SMS artifacts. The AMIs created by the replication runs are not deleted.

# Required Parameters
- `replicationJobId`: The ID of the replication job.

"""
delete_replication_job(replicationJobId; aws_config::AWSConfig=global_aws_config()) = sms("DeleteReplicationJob", Dict{String, Any}("replicationJobId"=>replicationJobId); aws_config=aws_config)
delete_replication_job(replicationJobId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("DeleteReplicationJob", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("replicationJobId"=>replicationJobId), args)); aws_config=aws_config)

"""
    DeleteServerCatalog()

Deletes all servers from your server catalog.

"""
delete_server_catalog(; aws_config::AWSConfig=global_aws_config()) = sms("DeleteServerCatalog"; aws_config=aws_config)
delete_server_catalog(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("DeleteServerCatalog", args; aws_config=aws_config)

"""
    DisassociateConnector()

Disassociates the specified connector from AWS SMS. After you disassociate a connector, it is no longer available to support replication jobs.

# Required Parameters
- `connectorId`: The ID of the connector.

"""
disassociate_connector(connectorId; aws_config::AWSConfig=global_aws_config()) = sms("DisassociateConnector", Dict{String, Any}("connectorId"=>connectorId); aws_config=aws_config)
disassociate_connector(connectorId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("DisassociateConnector", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("connectorId"=>connectorId), args)); aws_config=aws_config)

"""
    GenerateChangeSet()

Generates a target change set for a currently launched stack and writes it to an Amazon S3 object in the customer’s Amazon S3 bucket.

# Optional Parameters
- `appId`: The ID of the application associated with the change set.
- `changesetFormat`: The format for the change set.
"""
generate_change_set(; aws_config::AWSConfig=global_aws_config()) = sms("GenerateChangeSet"; aws_config=aws_config)
generate_change_set(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("GenerateChangeSet", args; aws_config=aws_config)

"""
    GenerateTemplate()

Generates an AWS CloudFormation template based on the current launch configuration and writes it to an Amazon S3 object in the customer’s Amazon S3 bucket.

# Optional Parameters
- `appId`: The ID of the application associated with the AWS CloudFormation template.
- `templateFormat`: The format for generating the AWS CloudFormation template.
"""
generate_template(; aws_config::AWSConfig=global_aws_config()) = sms("GenerateTemplate"; aws_config=aws_config)
generate_template(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("GenerateTemplate", args; aws_config=aws_config)

"""
    GetApp()

Retrieve information about the specified application.

# Optional Parameters
- `appId`: The ID of the application.
"""
get_app(; aws_config::AWSConfig=global_aws_config()) = sms("GetApp"; aws_config=aws_config)
get_app(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("GetApp", args; aws_config=aws_config)

"""
    GetAppLaunchConfiguration()

Retrieves the application launch configuration associated with the specified application.

# Optional Parameters
- `appId`: The ID of the application.
"""
get_app_launch_configuration(; aws_config::AWSConfig=global_aws_config()) = sms("GetAppLaunchConfiguration"; aws_config=aws_config)
get_app_launch_configuration(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("GetAppLaunchConfiguration", args; aws_config=aws_config)

"""
    GetAppReplicationConfiguration()

Retrieves the application replication configuration associated with the specified application.

# Optional Parameters
- `appId`: The ID of the application.
"""
get_app_replication_configuration(; aws_config::AWSConfig=global_aws_config()) = sms("GetAppReplicationConfiguration"; aws_config=aws_config)
get_app_replication_configuration(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("GetAppReplicationConfiguration", args; aws_config=aws_config)

"""
    GetAppValidationConfiguration()

Retrieves information about a configuration for validating an application.

# Required Parameters
- `appId`: The ID of the application.

"""
get_app_validation_configuration(appId; aws_config::AWSConfig=global_aws_config()) = sms("GetAppValidationConfiguration", Dict{String, Any}("appId"=>appId); aws_config=aws_config)
get_app_validation_configuration(appId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("GetAppValidationConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("appId"=>appId), args)); aws_config=aws_config)

"""
    GetAppValidationOutput()

Retrieves output from validating an application.

# Required Parameters
- `appId`: The ID of the application.

"""
get_app_validation_output(appId; aws_config::AWSConfig=global_aws_config()) = sms("GetAppValidationOutput", Dict{String, Any}("appId"=>appId); aws_config=aws_config)
get_app_validation_output(appId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("GetAppValidationOutput", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("appId"=>appId), args)); aws_config=aws_config)

"""
    GetConnectors()

Describes the connectors registered with the AWS SMS.

# Optional Parameters
- `maxResults`: The maximum number of results to return in a single call. The default value is 50. To retrieve the remaining results, make another call with the returned NextToken value.
- `nextToken`: The token for the next set of results.
"""
get_connectors(; aws_config::AWSConfig=global_aws_config()) = sms("GetConnectors"; aws_config=aws_config)
get_connectors(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("GetConnectors", args; aws_config=aws_config)

"""
    GetReplicationJobs()

Describes the specified replication job or all of your replication jobs.

# Optional Parameters
- `maxResults`: The maximum number of results to return in a single call. The default value is 50. To retrieve the remaining results, make another call with the returned NextToken value.
- `nextToken`: The token for the next set of results.
- `replicationJobId`: The ID of the replication job.
"""
get_replication_jobs(; aws_config::AWSConfig=global_aws_config()) = sms("GetReplicationJobs"; aws_config=aws_config)
get_replication_jobs(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("GetReplicationJobs", args; aws_config=aws_config)

"""
    GetReplicationRuns()

Describes the replication runs for the specified replication job.

# Required Parameters
- `replicationJobId`: The ID of the replication job.

# Optional Parameters
- `maxResults`: The maximum number of results to return in a single call. The default value is 50. To retrieve the remaining results, make another call with the returned NextToken value.
- `nextToken`: The token for the next set of results.
"""
get_replication_runs(replicationJobId; aws_config::AWSConfig=global_aws_config()) = sms("GetReplicationRuns", Dict{String, Any}("replicationJobId"=>replicationJobId); aws_config=aws_config)
get_replication_runs(replicationJobId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("GetReplicationRuns", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("replicationJobId"=>replicationJobId), args)); aws_config=aws_config)

"""
    GetServers()

Describes the servers in your server catalog. Before you can describe your servers, you must import them using ImportServerCatalog.

# Optional Parameters
- `maxResults`: The maximum number of results to return in a single call. The default value is 50. To retrieve the remaining results, make another call with the returned NextToken value.
- `nextToken`: The token for the next set of results.
- `vmServerAddressList`: The server addresses.
"""
get_servers(; aws_config::AWSConfig=global_aws_config()) = sms("GetServers"; aws_config=aws_config)
get_servers(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("GetServers", args; aws_config=aws_config)

"""
    ImportAppCatalog()

Allows application import from AWS Migration Hub.

# Optional Parameters
- `roleName`: The name of the service role. If you omit this parameter, we create a service-linked role for AWS Migration Hub in your account. Otherwise, the role that you provide must have the policy and trust policy described in the AWS Migration Hub User Guide.
"""
import_app_catalog(; aws_config::AWSConfig=global_aws_config()) = sms("ImportAppCatalog"; aws_config=aws_config)
import_app_catalog(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("ImportAppCatalog", args; aws_config=aws_config)

"""
    ImportServerCatalog()

Gathers a complete list of on-premises servers. Connectors must be installed and monitoring all servers to import. This call returns immediately, but might take additional time to retrieve all the servers.

"""
import_server_catalog(; aws_config::AWSConfig=global_aws_config()) = sms("ImportServerCatalog"; aws_config=aws_config)
import_server_catalog(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("ImportServerCatalog", args; aws_config=aws_config)

"""
    LaunchApp()

Launches the specified application as a stack in AWS CloudFormation.

# Optional Parameters
- `appId`: The ID of the application.
"""
launch_app(; aws_config::AWSConfig=global_aws_config()) = sms("LaunchApp"; aws_config=aws_config)
launch_app(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("LaunchApp", args; aws_config=aws_config)

"""
    ListApps()

Retrieves summaries for all applications.

# Optional Parameters
- `appIds`: The unique application IDs.
- `maxResults`: The maximum number of results to return in a single call. The default value is 100. To retrieve the remaining results, make another call with the returned NextToken value.
- `nextToken`: The token for the next set of results.
"""
list_apps(; aws_config::AWSConfig=global_aws_config()) = sms("ListApps"; aws_config=aws_config)
list_apps(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("ListApps", args; aws_config=aws_config)

"""
    NotifyAppValidationOutput()

Provides information to AWS SMS about whether application validation is successful.

# Required Parameters
- `appId`: The ID of the application.

# Optional Parameters
- `notificationContext`: The notification information.
"""
notify_app_validation_output(appId; aws_config::AWSConfig=global_aws_config()) = sms("NotifyAppValidationOutput", Dict{String, Any}("appId"=>appId); aws_config=aws_config)
notify_app_validation_output(appId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("NotifyAppValidationOutput", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("appId"=>appId), args)); aws_config=aws_config)

"""
    PutAppLaunchConfiguration()

Creates or updates the launch configuration for the specified application.

# Optional Parameters
- `appId`: The ID of the application.
- `autoLaunch`: Indicates whether the application is configured to launch automatically after replication is complete.
- `roleName`: The name of service role in the customer's account that AWS CloudFormation uses to launch the application.
- `serverGroupLaunchConfigurations`: Information about the launch configurations for server groups in the application.
"""
put_app_launch_configuration(; aws_config::AWSConfig=global_aws_config()) = sms("PutAppLaunchConfiguration"; aws_config=aws_config)
put_app_launch_configuration(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("PutAppLaunchConfiguration", args; aws_config=aws_config)

"""
    PutAppReplicationConfiguration()

Creates or updates the replication configuration for the specified application.

# Optional Parameters
- `appId`: The ID of the application.
- `serverGroupReplicationConfigurations`: Information about the replication configurations for server groups in the application.
"""
put_app_replication_configuration(; aws_config::AWSConfig=global_aws_config()) = sms("PutAppReplicationConfiguration"; aws_config=aws_config)
put_app_replication_configuration(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("PutAppReplicationConfiguration", args; aws_config=aws_config)

"""
    PutAppValidationConfiguration()

Creates or updates a validation configuration for the specified application.

# Required Parameters
- `appId`: The ID of the application.

# Optional Parameters
- `appValidationConfigurations`: The configuration for application validation.
- `serverGroupValidationConfigurations`: The configuration for instance validation.
"""
put_app_validation_configuration(appId; aws_config::AWSConfig=global_aws_config()) = sms("PutAppValidationConfiguration", Dict{String, Any}("appId"=>appId); aws_config=aws_config)
put_app_validation_configuration(appId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("PutAppValidationConfiguration", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("appId"=>appId), args)); aws_config=aws_config)

"""
    StartAppReplication()

Starts replicating the specified application by creating replication jobs for each server in the application.

# Optional Parameters
- `appId`: The ID of the application.
"""
start_app_replication(; aws_config::AWSConfig=global_aws_config()) = sms("StartAppReplication"; aws_config=aws_config)
start_app_replication(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("StartAppReplication", args; aws_config=aws_config)

"""
    StartOnDemandAppReplication()

Starts an on-demand replication run for the specified application.

# Required Parameters
- `appId`: The ID of the application.

# Optional Parameters
- `description`: The description of the replication run.
"""
start_on_demand_app_replication(appId; aws_config::AWSConfig=global_aws_config()) = sms("StartOnDemandAppReplication", Dict{String, Any}("appId"=>appId); aws_config=aws_config)
start_on_demand_app_replication(appId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("StartOnDemandAppReplication", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("appId"=>appId), args)); aws_config=aws_config)

"""
    StartOnDemandReplicationRun()

Starts an on-demand replication run for the specified replication job. This replication run starts immediately. This replication run is in addition to the ones already scheduled. There is a limit on the number of on-demand replications runs that you can request in a 24-hour period.

# Required Parameters
- `replicationJobId`: The ID of the replication job.

# Optional Parameters
- `description`: The description of the replication run.
"""
start_on_demand_replication_run(replicationJobId; aws_config::AWSConfig=global_aws_config()) = sms("StartOnDemandReplicationRun", Dict{String, Any}("replicationJobId"=>replicationJobId); aws_config=aws_config)
start_on_demand_replication_run(replicationJobId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("StartOnDemandReplicationRun", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("replicationJobId"=>replicationJobId), args)); aws_config=aws_config)

"""
    StopAppReplication()

Stops replicating the specified application by deleting the replication job for each server in the application.

# Optional Parameters
- `appId`: The ID of the application.
"""
stop_app_replication(; aws_config::AWSConfig=global_aws_config()) = sms("StopAppReplication"; aws_config=aws_config)
stop_app_replication(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("StopAppReplication", args; aws_config=aws_config)

"""
    TerminateApp()

Terminates the stack for the specified application.

# Optional Parameters
- `appId`: The ID of the application.
"""
terminate_app(; aws_config::AWSConfig=global_aws_config()) = sms("TerminateApp"; aws_config=aws_config)
terminate_app(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("TerminateApp", args; aws_config=aws_config)

"""
    UpdateApp()

Updates the specified application.

# Optional Parameters
- `appId`: The ID of the application.
- `description`: The new description of the application.
- `name`: The new name of the application.
- `roleName`: The name of the service role in the customer's account used by AWS SMS.
- `serverGroups`: The server groups in the application to update.
- `tags`: The tags to associate with the application.
"""
update_app(; aws_config::AWSConfig=global_aws_config()) = sms("UpdateApp"; aws_config=aws_config)
update_app(args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("UpdateApp", args; aws_config=aws_config)

"""
    UpdateReplicationJob()

Updates the specified settings for the specified replication job.

# Required Parameters
- `replicationJobId`: The ID of the replication job.

# Optional Parameters
- `description`: The description of the replication job.
- `encrypted`: When true, the replication job produces encrypted AMIs. For more information, KmsKeyId.
- `frequency`: The time between consecutive replication runs, in hours.
- `kmsKeyId`: The ID of the KMS key for replication jobs that produce encrypted AMIs. This value can be any of the following:   KMS key ID   KMS key alias   ARN referring to the KMS key ID   ARN referring to the KMS key alias   If encrypted is enabled but a KMS key ID is not specified, the customer's default KMS key for Amazon EBS is used.
- `licenseType`: The license type to be used for the AMI created by a successful replication run.
- `nextReplicationRunStartTime`: The start time of the next replication run.
- `numberOfRecentAmisToKeep`: The maximum number of SMS-created AMIs to retain. The oldest is deleted after the maximum number is reached and a new AMI is created.
- `roleName`: The name of the IAM role to be used by AWS SMS.
"""
update_replication_job(replicationJobId; aws_config::AWSConfig=global_aws_config()) = sms("UpdateReplicationJob", Dict{String, Any}("replicationJobId"=>replicationJobId); aws_config=aws_config)
update_replication_job(replicationJobId, args::AbstractDict{String, <:Any}; aws_config::AWSConfig=global_aws_config()) = sms("UpdateReplicationJob", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("replicationJobId"=>replicationJobId), args)); aws_config=aws_config)


text:
module Cbc

if haskey(ENV, "JULIA_CBC_LIBRARY_PATH") || VERSION < v"1.3"
    deps_file = joinpath(dirname(@__DIR__), "deps", "deps.jl")
    if isfile(deps_file)
        using Libdl
        include(deps_file)
    else
        error(
            "Cbc not properly installed. Please run `import Pkg; " *
            "Pkg.build(\"Cbc\")` for more information.",
        )
    end
else
    import Cbc_jll: libcbcsolver
end

using CEnum

include("gen/ctypes.jl")
include("gen/libcbc_common.jl")
include("gen/libcbc_api.jl")

const _CBC_VERSION_STRING = unsafe_string(Cbc_getVersion())

const _CBC_VERSION = if _CBC_VERSION_STRING == "devel"
    # Support un-released versions of Cbc. These may differ in C API
    # compatibility! Use at your own peril.
    v"2.10.5"
else
    VersionNumber(_CBC_VERSION_STRING)
end

if !(v"2.10.0" <= _CBC_VERSION <= v"2.10.5")
    error("""
You have installed version $_CBC_VERSION of Cbc, which is not supported by
Cbc.jl We require Cbc version 2.10. After installing Cbc 2.10, run:

    import Pkg
    Pkg.rm("Cbc")
    Pkg.add("Cbc")

If you have a newer version of Cbc installed, changes may need to be made
to the Julia code. Please open an issue at
https://github.com/jump-dev/Cbc.jl.
""")
end

include("MOI_wrapper/MOI_wrapper.jl")

# Cbc exports all `Cbc_xxx` symbols. If you don't want all of these symbols in
# your environment, then use `import Cbc` instead of `using Cbc`.

for sym in filter(s -> startswith("$s", "Cbc_"), names(@__MODULE__, all = true))
    @eval export $sym
end

# TODO(odow): remove at Cbc.jl v1.0.0.
function CbcSolver(args...; kwargs...)
    return error(
        """
  `CbcSolver` is no longer supported. If you are using JuMP, upgrade to the
  latest version and use `Cbc.Optimizer` instead. If you are using
  MathProgBase (e.g., via `lingprog`), you will need to upgrade to
  MathOptInterface (https://github.com/jump-dev/MathOptInterface.jl).
  """,
    )
end
export CbcSolver

end


text:
function test13()
  filename = "test13.asc"
  # exectuablepath = null string will not run LTspice.exe.  Test parsing only.
  sim = LTspiceSimulation(filename,executablepath="")
  @test LTspice.does_circuitfilearray_file_match(sim)
  show(IOBuffer(),sim)

  npnsteps = [50.0, 75.0, 100.0]
  v2steps = [10.0, 15.0, 20.0, 25.0, 30.0]
  v1steps = [1.0, 2.0]
  teststepnames = ("2N2222(VAF)","V2","V1")
  testmeasurementnames = ("aaaaaa", "b43")

  @test stepvalues(sim) == (npnsteps,v2steps,v1steps)
  @test measurementnames(sim) == testmeasurementnames
  @test stepnames(sim) == teststepnames
  @test length(measurementvalues(sim)) == length(testmeasurementnames)*length(npnsteps)*length(v2steps)*length(v1steps)
  show(IOBuffer(),sim)
end
test13()


text:
# FASTQ
# =====
#
# Reader and writer of the FASTQ file format.
#
# This file is a part of BioJulia.
# License is MIT: https://github.com/BioJulia/Bio.jl/blob/master/LICENSE.md

immutable FASTQ <: FileFormat end

"""
Metadata for FASTQ sequence records containing a `description` field,
and a `quality` string corresponding to the sequence.

Quality scores are stored as integer Phred scores.
"""
type FASTQMetadata
    description::StringField
    quality::Vector{Int8}
end

function FASTQMetadata()
    return FASTQMetadata(StringField(), Int8[])
end

@compat function Base.:(==)(a::FASTQMetadata, b::FASTQMetadata)
    return a.description == b.description && a.quality == b.quality
end

function Base.copy(metadata::FASTQMetadata)
    return FASTQMetadata(copy(metadata.description), copy(metadata.quality))
end

"""
    FASTQSeqRecord(name, seq, quality[, description=""])

Create a sequence record for the FASTQ file format.
"""
typealias FASTQSeqRecord{S} SeqRecord{S,FASTQMetadata}

@compat function (::Type{FASTQSeqRecord})(name::AbstractString,
                                          seq::Sequence,
                                          quality::Vector{Int8},
                                          description::AbstractString="")
    if length(seq) != length(quality)
        throw(ArgumentError("sequence and base quality must be the same length"))
    end
    return SeqRecord(name, seq, FASTQMetadata(description, quality))
end

function Base.open(
        filepath::AbstractString,
        mode::AbstractString,
        ::Type{FASTQ};
        # parser options
        quality_encoding::QualityEncoding=EMPTY_QUAL_ENCODING,
        # writer options
        quality_header::Bool=false,
        ascii_offset::Integer=typemin(Int))
    io = open(filepath, mode)
    if mode[1] == 'r'
        return open(BufferedInputStream(io), FASTQ, quality_encoding)
    elseif mode[1] ∈ ('w', 'a')
        return FASTQWriter(io, quality_header, ascii_offset)
    end
    error("invalid open mode")
end

function Base.open{S}(input::BufferedInputStream, ::Type{FASTQ},
                      quality_encoding::QualityEncoding,
                      ::Type{S}=DNASequence;
                      # TODO: remove this option after v0.2
                      qualenc=quality_encoding)
    return FASTQParser{S}(input, quality_encoding)
end

# Parser
# ------

"A type encapsulating the current state of a FASTQ parser"
type FASTQParser{S<:Sequence} <: AbstractParser
    state::Ragel.State
    seqbuf::BufferedOutputStream{BufferedStreams.EmptyStream}
    qualbuf::BufferedOutputStream{BufferedStreams.EmptyStream}
    name2buf::StringField
    desc2buf::StringField
    qualcount::Int
    quality_encodings::QualityEncoding

    function FASTQParser(input::BufferedInputStream,
                         quality_encodings::QualityEncoding)
        if quality_encodings == EMPTY_QUAL_ENCODING
            error("The `quality_encodings` argument is required when parsing FASTQ.")
        elseif count_ones(convert(UInt16, quality_encodings)) > 1
            error("The `quality_encodings` argument must specify exactly one encoding.")
        elseif count_ones(convert(UInt16, quality_encodings & ALL_QUAL_ENCODINGS)) != 1
            error("Unknown quality encoding.")
        end
        return new(Ragel.State(fastqparser_start, input),
                   BufferedOutputStream(), BufferedOutputStream(),
                   StringField(), StringField(), 0, quality_encodings)
    end
end

Base.eltype{S}(::Type{FASTQParser{S}}) = FASTQSeqRecord{S}

function Base.eof(parser::FASTQParser)
    return eof(parser.state.stream)
end

function Base.close(parser::FASTQParser)
    close(parser.state.stream)
end

include("fastq-parser.jl")

# Writer
# ------

type FASTQWriter{T<:IO} <: AbstractWriter
    output::T

    # write sequence name and description header at the third line
    quality_header::Bool

    # encoding offset of base qualities (ASCII code = Phred quality + offset)
    ascii_offset::Int
end

function Base.flush(writer::FASTQWriter)
    # TODO: This can be removed on Julia v0.5
    # (because flush will be defined for IOBuffer).
    if applicable(flush, writer.output)
        flush(writer.output)
    end
end
Base.close(writer::FASTQWriter) = close(writer.output)

function Base.write(writer::FASTQWriter, seqrec::FASTQSeqRecord)
    if writer.ascii_offset == typemin(Int)
        # infer quality encoding based on data
        if !isempty(seqrec.metadata.quality) && minimum(seqrec.metadata.quality) < 0
            writer.ascii_offset = 64  # solexa
        else
            writer.ascii_offset = 33  # others
        end
    end

    output = writer.output
    n = 0

    # header
    n += write(output, '@', seqrec.name)
    if !isempty(seqrec.metadata.description)
        n += write(output, ' ', seqrec.metadata.description)
    end
    n += write(output, '\n')

    # sequence
    for x in seqrec.seq
        n += write(output, Char(x))
    end
    n += write(output, '\n')

    # (optional) identifier and description
    n += write(output, '+')
    if writer.quality_header
        n += write(output, seqrec.name)
        if !isempty(seqrec.metadata.description)
            n += write(output, ' ', seqrec.metadata.description)
        end
    end
    n += write(output, '\n')

    for q in seqrec.metadata.quality
        n += write(output, Char(q + writer.ascii_offset))
    end
    n += write(output, '\n')

    return n
end

function Base.show(io::IO, seqrec::FASTQSeqRecord)
    write(io, "@", seqrec.name, " ", seqrec.metadata.description, "\n")
    for c in seqrec.seq
        print(io, c)
    end
    write(io, '\n')
    # print quality scores as a unicode bar chart
    for q in seqrec.metadata.quality
        if q <= 0
            write(io, '▁')
        elseif q <= 6
            write(io, '▂')
        elseif q <= 12
            write(io, '▃')
        elseif q <= 18
            write(io, '▄')
        elseif q <= 24
            write(io, '▅')
        elseif q <= 30
            write(io, '▆')
        elseif q <= 36
            write(io, '▇')
        else
            write(io, '█')
        end
    end
    write(io, '\n')
end

function Base.write(io::IO, seqrec::FASTQSeqRecord;
                    offset::Integer=-1, qualheader::Bool=false)

    # choose offset automatically
    if offset < 0
        if !isempty(seqrec.metadata.quality) && minimum(seqrec.metadata.quality) < 0
            offset = 64 # solexa quality offset
        else
            offset = 33  # sanger
        end
    end

    write(io, "@", seqrec.name)
    if !isempty(seqrec.metadata.description)
        write(io, " ", seqrec.metadata.description)
    end
    write(io, "\n")

    for c in seqrec.seq
        print(io, c)
    end
    write(io, "\n")

    write(io, "+")
    if qualheader
        write(io, seqrec.name)
        if !isempty(seqrec.metadata.description)
            write(io, " ", seqrec.metadata.description)
        end
    end
    write(io, "\n")

    for q in seqrec.metadata.quality
        write(io, Char(q + offset))
    end
    write(io, "\n")
end


text:
module TestBenchmarks

using Schedulers.Internal: Debug
using SchedulersBenchmarks: clear, setup
using Test

function test_smoke_test_benchmarks()
    try
        local suite
        #=
        @test (suite = setup_smoke()) isa Any
        =#
        @test (suite = setup()) isa Any
        Debug.get_logger() === nothing || return
        @test run(suite) isa Any
    finally
        clear()
    end
end

end  # module


text:
using Test, InteractiveErrors

@testset "InteractiveErrors" begin
    IE = InteractiveErrors

    @test IE.rootmodule(Main) === Main
    @test IE.rootmodule(Base) === Base
    @test IE.rootmodule(Core) === Core
    @test IE.rootmodule(InteractiveErrors) === InteractiveErrors
    @test IE.rootmodule(Base.Math) === Base

    @test IE.is_from_stdlib(Test)
    @test !IE.is_from_base(Test)
    @test IE.is_from_base(Base)
    @test !IE.is_from_package(Base)
    @test IE.is_from_package(InteractiveErrors)
    @test !IE.is_from_core(InteractiveErrors)
    @test IE.is_from_core(Core)

    build = joinpath(normpath(Sys.BUILD_STDLIB_PATH), "Test", "src", "Test.jl")
    stdlib = joinpath(normpath(Sys.STDLIB), "Test", "src", "Test.jl")
    package = @__FILE__
    @test isfile(InteractiveErrors.find_source(build))
    @test isfile(InteractiveErrors.find_source(stdlib))
    @test isfile(InteractiveErrors.find_source(package))
    @test startswith(InteractiveErrors.rewrite_path(build), "@stdlib")
    @test startswith(InteractiveErrors.rewrite_path(stdlib), "@stdlib")

    @test isa(IE.wrap_errors(:(1 + 1)), Expr)
    @test isa(IE.wrap_errors(:(toggle())), Expr)
    toggle()
    @test isa(IE.wrap_errors(:(1 + 1)), Expr)
    @test isa(IE.wrap_errors(:(toggle())), Expr)
    toggle()

    @test IE.style("func", :function_name) == "\e[0m\e[1mfunc\e[22m"
    @test isa(IE.adjust_theme!(function_name = (color = :yellow, bold = false)), NamedTuple)
    @test IE.style("func", :function_name) == "\e[33mfunc\e[39m"
    @test isa(IE.current_theme(), NamedTuple)

    @test IE.maybe_retry((; retry = true), :(true))
    @test IE.maybe_retry((; retry = false), :(true)) == (; retry = false)

    try
        div(1, 0)
    catch err
        ce = IE.CapturedError(err, catch_backtrace())
        io = IOBuffer()
        nt = IE.explore(io, ce; interactive = false)
        str = String(take!(io))
        @test !isempty(str)
        @test contains(str, "DivideError:")
        @test isa(nt, NamedTuple)
        @test collect(keys(nt)) == [:stacktrace, :exception, :backtrace]
        @test isa(nt.exception, DivideError)
        @test !isempty(nt.stacktrace)
        @test !isempty(nt.backtrace)
    end

    @test !IE.has_cthulhu()
    @test !IE.has_debugger()
    @test !IE.has_jet()
    @test !IE.has_ohmyrepl()
    @test !IE.has_juliaformatter()

    using Cthulhu, Debugger, JET, OhMyREPL, JuliaFormatter

    @test IE.has_cthulhu()
    @test IE.has_debugger()
    @test IE.has_jet()
    @test IE.has_ohmyrepl()
    @test IE.has_juliaformatter()

    try
        sqrt(-1)
    catch err
        ce = IE.CapturedError(err, catch_backtrace())
        io = IOBuffer()
        nt = IE.explore(io, ce; interactive = false)
        str = String(take!(io))
        @test !isempty(str)
        @test contains(str, "DomainError")
        @test isa(nt, NamedTuple)
        @test collect(keys(nt)) == [:stacktrace, :exception, :backtrace]
        @test isa(nt.exception, DomainError)
        @test !isempty(nt.stacktrace)
        @test !isempty(nt.backtrace)
    end
end


text:
export OSProc, Context

abstract type Processor end

"""
OS process - contains pid returned by `addprocs`
"""
struct OSProc <: Processor
    pid::Int
end

"""
A context represents a set of processors to use
for a papply operation.
"""
mutable struct Context
    procs::Array{OSProc}
    log_sink::Any
    profile::Bool
end

function Context(xs)
    Context(xs, NoOpLog(), false) # By default don't log events
end
Context(xs::Array{Int}) = Context(map(OSProc, xs))
Context() = Context(workers())
procs(c::Context) = c.procs

"""
Write a log event
"""
function write_event(ctx::Context, event::Event)
    write_event(ctx.log_sink, event)
end


text:
## SCALE TRANSFORMATIONS

#     Scale = SCALE()

# Object for dispatching on scales and functions when generating
# parameter ranges. We require different behaviour for scales and
# functions:

#      transform(Scale, scale(:log10), 100) = 2
#      inverse_transform(Scale, scale(:log10), 2) = 100

# but
#     transform(Scale, scale(log10), 100) = 100       # identity
#     inverse_transform(Scale, scale(log10), 100) = 2

struct SCALE end
Scale = SCALE()

scale(s::Symbol)   = Val(s)
scale(f::Function) = f

transform(::SCALE, ::Val{:linear}, x) = x
inverse_transform(::SCALE, ::Val{:linear}, x) = x

transform(::SCALE, ::Val{:log}, x) = log(x)
inverse_transform(::SCALE, ::Val{:log}, x) = exp(x)

transform(::SCALE, ::Val{:logminus}, x) = log(-x)
inverse_transform(::SCALE, ::Val{:logminus}, x) = -exp(x)

transform(::SCALE, ::Val{:log10minus}, x) = log10(-x)
inverse_transform(::SCALE, ::Val{:log10minus}, x) = -10^x

transform(::SCALE, ::Val{:log10}, x) = log10(x)
inverse_transform(::SCALE, ::Val{:log10}, x) = 10^x

transform(::SCALE, ::Val{:log2}, x) = log2(x)
inverse_transform(::SCALE, ::Val{:log2}, x) = 2^x

transform(::SCALE, f::Function, x) = x            # not a typo!
inverse_transform(::SCALE, f::Function, x) = f(x) # not a typo!

## SCALE INSPECTION (FOR EG PLOTTING)

"""
    scale(r::ParamRange)

Return the scale associated with a `ParamRange` object `r`. The possible
return values are: `:none` (for a `NominalRange`), `:linear`, `:log`, `:log10`,
`:log2`, or `:custom` (if `r.scale` is a callable object).
"""
scale(r::NominalRange) = :none
scale(r::NumericRange) = :custom
scale(r::NumericRange{T,B,Symbol}) where {B<:Boundedness,T} = r.scale

## ITERATOR METHOD (FOR GENERATING A 1D GRID)

"""
    iterator([rng, ], r::NominalRange, [,n])
    iterator([rng, ], r::NumericRange, n)

Return an iterator (currently a vector) for a `ParamRange` object `r`.
In the first case iteration is over all `values` stored in the range
(or just the first `n`, if `n` is specified). In the second case, the
iteration is over approximately `n` ordered values, generated as
follows:

(i) First, exactly `n` values are generated between `U` and `L`, with a
spacing determined by `r.scale` (uniform if `scale=:linear`) where `U`
and `L` are given by the following table:

| `r.lower`   | `r.upper`  | `L`                 | `U`                 |
|-------------|------------|---------------------|---------------------|
| finite      | finite     | `r.lower`           | `r.upper`           |
| `-Inf`      | finite     | `r.upper - 2r.unit` | `r.upper`           |
| finite      | `Inf`      | `r.lower`           | `r.lower + 2r.unit` |
| `-Inf`      | `Inf`      | `r.origin - r.unit` | `r.origin + r.unit` |

(ii) If a callable `f` is provided as `scale`, then a uniform spacing
is always applied in (i) but `f` is broadcast over the results. (Unlike
ordinary scales, this alters the effective range of values generated,
instead of just altering the spacing.)

(iii) If `r` is a discrete numeric range (`r isa NumericRange{<:Integer}`)
then the values are additionally rounded, with any duplicate values
removed. Otherwise all the values are used (and there are exacltly `n`
of them).

(iv) Finally, if a random number generator `rng` is specified, then the values are
returned in random order (sampling without replacement), and otherwise
they are returned in numeric order, or in the order provided to the
range constructor, in the case of a `NominalRange`.

"""
iterator(rng::AbstractRNG, r::ParamRange, args...) =
    Random.shuffle(rng, iterator(r, args...))

iterator(r::NominalRange, ::Nothing) = iterator(r)
iterator(r::NominalRange, n::Integer) =
    collect(r.values[1:min(n, length(r.values))])
iterator(r::NominalRange) = collect(r.values)

# numeric range, top level dispatch

function iterator(r::NumericRange{T,<:Bounded},
                  n::Int) where {T<:Real}
    L = r.lower
    U = r.upper
    return iterator(T, L, U, r.scale, n)
end

function iterator(r::NumericRange{T,<:LeftUnbounded},
                  n::Int) where {T<:Real}
    L = r.upper - 2r.unit
    U = r.upper
    return iterator(T, L, U, r.scale, n)
end

function iterator(r::NumericRange{T,<:RightUnbounded},
                  n::Int) where {T<:Real}
    L = r.lower
    U = r.lower + 2r.unit
    return iterator(T, L, U, r.scale, n)
end

function iterator(r::NumericRange{T,<:DoublyUnbounded},
                  n::Int) where {T<:Real}
    L = r.origin - r.unit
    U = r.origin + r.unit
    return iterator(T, L, U, r.scale, n)
end

# middle level

iterator(::Type{<:Real}, L, U, s, n) =
    iterator(L, U, s, n)

function iterator(I::Type{<:Integer}, L, U, s, n)
    raw = iterator(L, U, s, n)
    rounded = map(x -> round(I, x), raw)
    return unique(rounded)
end

# ground level

# if scale `s` is a callable (the fallback):
function iterator(L, U, s, n)
    return s.(range(L, stop=U, length=n))
end

# if scale is a symbol:
function iterator(L, U, s::Symbol, n)
    transformed = range(transform(Scale, scale(s), L),
                stop=transform(Scale, scale(s), U),
                        length=n)
    inverse_transformed = map(transformed) do value
        inverse_transform(Scale, scale(s), value)
    end
    return inverse_transformed
end

## FITTING DISTRIBUTIONS TO A RANGE

### Helper

function _truncated(d::Dist.Distribution, r::NumericRange)
    if minimum(d) >= r.lower && maximum(d) <= r.upper
        return d
    else
        return Dist.truncated(d, r.lower, r.upper)
    end
end

### Fallback and docstring

"""
    Distributions.fit(D, r::MLJBase.NumericRange)

Fit and return a distribution `d` of type `D` to the one-dimensional
range `r`.

Only types `D` in the table below are supported.

The distribution `d` is constructed in two stages. First, a
distributon `d0`, characterized by the conditions in the second column
of the table, is fit to `r`. Then `d0` is truncated between `r.lower`
and `r.upper` to obtain `d`.

Distribution type `D`  | Characterization of `d0`
:----------------------|:-------------------------
`Arcsine`, `Uniform`, `Biweight`, `Cosine`, `Epanechnikov`, `SymTriangularDist`, `Triweight` |   `minimum(d) = r.lower`, `maximum(d) = r.upper`
`Normal`, `Gamma`, `InverseGaussian`, `Logistic`, `LogNormal` | `mean(d) = r.origin`, `std(d) = r.unit`
`Cauchy`, `Gumbel`, `Laplace`, (`Normal`) | `Dist.location(d) = r.origin`, `Dist.scale(d)  = r.unit`
`Poisson` | `Dist.mean(d) = r.unit`

Here `Dist = Distributions`.

"""
Dist.fit(::Type{D}, r::NumericRange) where D<:Distributions.Distribution =
    throw(ArgumentError("Fitting distributions of type `$D` to "*
          "`NumericRange` objects is unsupported. "*
          "Try passing an explicit instance, or a supported type. "))

### Continuous support

##### bounded

for D in [:Arcsine, :Uniform]
    @eval Dist.fit(::Type{<:Dist.$D}, r::NumericRange) =
        Dist.$D(r.lower, r.upper)
end
for D in [:Biweight, :Cosine, :Epanechnikov, :SymTriangularDist, :Triweight]
    @eval Dist.fit(::Type{<:Dist.$D}, r::NumericRange) =
        Dist.$D(r.origin, r.unit)
end

##### doubly-unbounded

# corresponding to values of `Dist.location` and `Dist.scale`:
for D in [:Cauchy, :Gumbel, :Normal, :Laplace]
    @eval Dist.fit(::Type{<:Dist.$D}, r::NumericRange) =
        _truncated(Dist.$D(r.origin, r.unit), r)
end

# Logistic:
function Dist.fit(::Type{<:Dist.Logistic}, r::NumericRange)
    μ = r.origin
    θ = sqrt(3)*r.unit/pi
    return _truncated(Dist.Logistic(μ, θ), r)
end

#### right-unbounded

# Gamma:
function Dist.fit(::Type{<:Dist.Gamma}, r::NumericRange)
    α = (r.origin/r.unit)^2
    θ = r.origin/α
    _truncated(Dist.Gamma(α, θ), r)
end

# InverseGaussian:
function Dist.fit(::Type{<:Dist.InverseGaussian}, r::NumericRange)
    mu = r.origin
    lambda = mu^3/r.unit^2
    return _truncated(Dist.InverseGaussian(mu, lambda), r)
end

# LogNormal:
function Dist.fit(::Type{<:Dist.LogNormal}, r::NumericRange)
    sig2 = log((r.unit/r.origin)^2 + 1)
    sig = sqrt(sig2)
    mu = log(r.origin) - sig2/2
    return _truncated(Dist.LogNormal(mu, sig), r)
end

### Discrete support

# Poisson:
function Dist.fit(::Type{<:Dist.Poisson}, r::NumericRange)
    _truncated(Dist.Poisson(r.unit), r)
end

## SAMPLER (FOR RANDOM SAMPLING A 1D RANGE)

### Numeric case

struct NumericSampler{T,D<:Distributions.Sampleable,S}
    distribution::D
    scale::S
    NumericSampler(::Type{T}, d::D, s::S) where {T,D,S} = new{T,D,S}(d,s)
end

function Base.show(stream::IO,
                   s::NumericSampler{T,D}) where {T,D}
    repr = "NumericSampler{$T,$D}}"
    s.scale isa Symbol || (repr = "transformed "*repr)
    print(stream, repr)
    return nothing
end

# constructor for distribution *instances*:
"""
    sampler(r::NominalRange, probs::AbstractVector{<:Real})
    sampler(r::NominalRange)
    sampler(r::NumericRange{T}, d)

Construct an object `s` which can be used to generate random samples
from a `ParamRange` object `r` (a one-dimensional range) using one of
the following calls:

    rand(s)             # for one sample
    rand(s, n)          # for n samples
    rand(rng, s [, n])  # to specify an RNG

The argument `probs` can be any probability vector with the same
length as `r.values`. The second `sampler` method above calls the
first with a uniform `probs` vector.

The argument `d` can be either an arbitrary instance of
`UnivariateDistribution` from the Distributions.jl package, or one of
a Distributions.jl *types* for which `fit(d, ::NumericRange)` is
defined. These include: `Arcsine`, `Uniform`, `Biweight`, `Cosine`,
`Epanechnikov`, `SymTriangularDist`, `Triweight`, `Normal`, `Gamma`,
`InverseGaussian`, `Logistic`, `LogNormal`, `Cauchy`, `Gumbel`,
`Laplace`, and `Poisson`; but see the doc-string for
[`Distributions.fit`](@ref) for an up-to-date list.

If `d` is an *instance*, then sampling is from a truncated form of the
supplied distribution `d`, the truncation bounds being `r.lower` and
`r.upper` (the attributes `r.origin` and `r.unit` attributes are
ignored). For discrete numeric ranges (`T <: Integer`) the samples are
rounded.

If `d` is a *type* then a suitably truncated distribution is
automatically generated using `Distributions.fit(d, r)`.

*Important.* Values are generated with no regard to `r.scale`, except
in the special case `r.scale` is a callable object `f`. In that case,
`f` is applied to all values generated by `rand` as described above
(prior to rounding, in the case of discrete numeric ranges).

### Examples

    r = range(Char, :letter, values=collect("abc"))
    s = sampler(r, [0.1, 0.2, 0.7])
    samples =  rand(s, 1000);
    StatsBase.countmap(samples)
    Dict{Char,Int64} with 3 entries:
      'a' => 107
      'b' => 205
      'c' => 688

    r = range(Int, :k, lower=2, upper=6) # numeric but discrete
    s = sampler(r, Normal)
    samples = rand(s, 1000);
    UnicodePlots.histogram(samples)
               ┌                                        ┐
    [2.0, 2.5) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 119
    [2.5, 3.0) ┤ 0
    [3.0, 3.5) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 296
    [3.5, 4.0) ┤ 0
    [4.0, 4.5) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 275
    [4.5, 5.0) ┤ 0
    [5.0, 5.5) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 221
    [5.5, 6.0) ┤ 0
    [6.0, 6.5) ┤▇▇▇▇▇▇▇▇▇▇▇ 89
               └                                        ┘

"""
Distributions.sampler(r::NumericRange{T},
                      d::Distributions.UnivariateDistribution) where T =
                          NumericSampler(T, _truncated(d, r), r.scale)

# constructor for distribution *types*:
Distributions.sampler(r::NumericRange,
                      D::Type{<:Dist.UnivariateDistribution}) =
                          sampler(r, Dist.fit(D, r))

# rand fallbacks (non-integer ranges):
Base.rand(s::NumericSampler, dims::Integer...) =
    s.scale.(rand(s.distribution, dims...))
Base.rand(rng::AbstractRNG, s::NumericSampler, dims::Integer...) =
    s.scale.(rand(rng, s.distribution, dims...))
Base.rand(s::NumericSampler{<:Any,<:Dist.Sampleable,Symbol},
          dims::Integer...) = rand(s.distribution, dims...)
Base.rand(rng::AbstractRNG,
          s::NumericSampler{<:Any,<:Dist.Sampleable,Symbol},
          dims::Integer...) =
              rand(rng, s.distribution, dims...)

# rand for integer ranges:
Base.rand(s::NumericSampler{I}, dims::Integer...) where I<:Integer =
    map(x -> round(I, s.scale(x)), rand(s.distribution, dims...))
Base.rand(rng::AbstractRNG,
          s::NumericSampler{I},
          dims::Integer...) where I<:Integer =
    map(x -> round(I, s.scale(x)), rand(rng, s.distribution, dims...))
Base.rand(s::NumericSampler{I,<:Dist.Sampleable,Symbol},
          dims::Integer...) where I<:Integer  =
              map(x -> round(I, x), rand(s.distribution, dims...))
Base.rand(rng::AbstractRNG,
          s::NumericSampler{I,<:Dist.Sampleable,Symbol},
          dims::Integer...) where I<:Integer =
              map(x -> round(I, x), rand(rng, s.distribution, dims...))

## Nominal case:

struct NominalSampler{T,N,D<:Distributions.Sampleable} <: MLJType
    distribution::D
    values::NTuple{N,T}
    NominalSampler(::Type{T}, d::D, values::NTuple{N,T}) where {T,N,D} =
        new{T,N,D}(d, values)
end

function Base.show(stream::IO,
                   s::NominalSampler{T,N,D}) where {T,N,D}
    samples = round3.(s.values)
    seqstr = sequence_string(s.values)
    repr = "NominalSampler($seqstr)"
    print(stream, repr)
    return nothing
end

# constructor for probability vectors:
function Distributions.sampler(r::NominalRange{T},
                 probs::AbstractVector{<:Real}) where T
    length(probs) == length(r.values) ||
        error("Length of probability vector must match number "*
              "of range values. ")
    return NominalSampler(T, Distributions.Categorical(probs), r.values)
end

# constructor for uniform sampling:
function Distributions.sampler(r::NominalRange{T,N}) where {T, N}
    return sampler(r, fill(1/N, N))
end

Base.rand(s::NominalSampler, dims::Integer...) where I<:Integer =
    broadcast(idx -> s.values[idx], rand(s.distribution, dims...))
Base.rand(rng::AbstractRNG,
          s::NominalSampler,
          dims::Integer...) where I<:Integer =
    broadcast(idx -> s.values[idx], rand(rng, s.distribution, dims...))

## SCALE METHOD FOR SAMPLERS

# these mimick the definitions for 1D ranges above:
scale(::Any) = :none
scale(::NumericSampler) = :custom
scale(s::NumericSampler{<:Any,<:Distributions.Sampleable,Symbol}) = s.scale


text:
using Unitful

using HTTP

include("urlparser.jl")

const tunit = u"ms"
const tmul = Int(1u"s"/1tunit)
delta_t(a, b) = round((b - a) * tmul, 0)tunit

function go(count::Int)

    urls = split(String(read("urls")), '\n')

                                                                t_start = time()
    @time for rep in 1:count
        for url in urls
            uri = http_parser_parse_url(url)
        end
    end
                                                                 t_done = time()
    t1 = delta_t(t_start, t_done)

    if count > 10
        println("http_parser_parse_url parsed $(length(urls)) urls $count times in $t1")
    end
                                                                t_start = time()
    @time for rep in 1:count
        for url in urls
            uri = HTTP.URIs.parse_uri_reference(url)
        end
    end
                                                                 t_done = time()
    t2 = delta_t(t_start, t_done)

    if count > 10
        println("regex_parse parsed $(length(urls)) urls $count times in $t2 ($(round(100*t2/t1, 1))%)")
    end
end

for r in [10, 10000]
    go(r)
    println("")
end


text:
module ExcelFiles

using ExcelReaders, XLSX, IteratorInterfaceExtensions, TableTraits, DataValues
using TableTraitsUtils, FileIO, TableShowUtils, Dates, Printf
import IterableTables

export load, save, File, @format_str

struct ExcelFile
    filename::String
    range::String
    keywords
end

function Base.show(io::IO, source::ExcelFile)
    TableShowUtils.printtable(io, getiterator(source), "Excel file")
end

function Base.show(io::IO, ::MIME"text/html", source::ExcelFile)
    TableShowUtils.printHTMLtable(io, getiterator(source))
end

Base.Multimedia.showable(::MIME"text/html", source::ExcelFile) = true

function Base.show(io::IO, ::MIME"application/vnd.dataresource+json", source::ExcelFile)
    TableShowUtils.printdataresource(io, getiterator(source))
end

Base.Multimedia.showable(::MIME"application/vnd.dataresource+json", source::ExcelFile) = true

function fileio_load(f::FileIO.File{FileIO.format"Excel"}, range; keywords...)
    return ExcelFile(f.filename, range, keywords)
end

function fileio_save(f::FileIO.File{FileIO.format"Excel"}, data; sheetname::AbstractString="")
    cols, colnames = TableTraitsUtils.create_columns_from_iterabletable(data, na_representation=:missing)
    return XLSX.writetable(f.filename, cols, colnames; sheetname=sheetname)
end

IteratorInterfaceExtensions.isiterable(x::ExcelFile) = true
TableTraits.isiterabletable(x::ExcelFile) = true

function gennames(n::Integer)
    res = Vector{Symbol}(undef, n)
    for i in 1:n
        res[i] = Symbol(@sprintf "x%d" i)
    end
    return res
end

function _readxl(file::ExcelReaders.ExcelFile, sheetname::AbstractString, startrow::Integer, startcol::Integer, endrow::Integer, endcol::Integer; header::Bool=true, colnames::Vector{Symbol}=Symbol[])
    data = ExcelReaders.readxl_internal(file, sheetname, startrow, startcol, endrow, endcol)

    nrow, ncol = size(data)

    if length(colnames) == 0
        if header
            headervec = data[1, :]
            NAcol = map(i -> isa(i, DataValues.DataValue) && DataValues.isna(i), headervec)
            headervec[NAcol] = gennames(count(!iszero, NAcol))

            # This somewhat complicated conditional makes sure that column names
            # that are integer numbers end up without an extra ".0" as their name
            colnames = [isa(i, AbstractFloat) ? ( modf(i)[1] == 0.0 ? Symbol(Int(i)) : Symbol(string(i)) ) : Symbol(i) for i in vec(headervec)]
        else
            colnames = gennames(ncol)
        end
    elseif length(colnames) != ncol
        error("Length of colnames must equal number of columns in selected range")
    end

    columns = Array{Any}(undef, ncol)

    for i = 1:ncol
        if header
            vals = data[2:end,i]
        else
            vals = data[:,i]
        end

        # Check whether all non-NA values in this column
        # are of the same type
        type_of_el = length(vals) > 0 ? typeof(vals[1]) : Any
        for val = vals
            type_of_el = promote_type(type_of_el, typeof(val))
        end

        if type_of_el <: DataValue
            columns[i] = convert(DataValueArray{eltype(type_of_el)}, vals)

            # TODO Check wether this hack is correct
            for (j, v) in enumerate(columns[i])
                if v isa DataValue && !DataValues.isna(v) && v[] isa DataValue
                    columns[i][j] = v[]
                end
            end
        else
            columns[i] = convert(Array{type_of_el}, vals)
        end
    end

    return columns, colnames
end

function IteratorInterfaceExtensions.getiterator(file::ExcelFile)
    column_data, col_names = if occursin("!", file.range)
        excelfile = openxl(file.filename)

        sheetname, startrow, startcol, endrow, endcol = ExcelReaders.convert_ref_to_sheet_row_col(file.range)

        _readxl(excelfile, sheetname, startrow, startcol, endrow, endcol; file.keywords...)
    else
        excelfile = openxl(file.filename)
        sheet = excelfile.workbook.sheet_by_name(file.range)

        keywords = filter(i -> !(i[1] in (:header, :colnames)), file.keywords)
        startrow, startcol, endrow, endcol = ExcelReaders.convert_args_to_row_col(sheet; keywords...)

        keywords2 = copy(file.keywords)
        keywords2 = filter(i -> !(i[1] in (:skipstartrows, :skipstartcols, :nrows, :ncols)), file.keywords)

        _readxl(excelfile, file.range, startrow, startcol, endrow, endcol; keywords2...)
    end

    return create_tableiterator(column_data, col_names)
end

function Base.collect(file::ExcelFile)
    return collect(getiterator(file))
end

end # module


text:
using Dates

tomlpath = joinpath(@__DIR__, "sbm_config.toml")
config = Wflow.Config(tomlpath)

model = Wflow.initialize_sbm_model(config)
@unpack network = model

model = Wflow.update(model)

# test if the first timestep was written to the CSV file
flush(model.writer.csv_io)  # ensure the buffer is written fully to disk
@testset "CSV output" begin
    row = csv_first_row(model.writer.csv_path)

    @test row.time == DateTime("2000-01-01T00:00:00")
    @test row.Q ≈ 7.815587720999557f0
    @test row.volume ≈ 2.7783643457819197f7
    @test row.temp_bycoord ≈ 2.3279826641082764f0
    @test row.temp_byindex ≈ 2.3279826641082764f0
    @test row.Q_6336050 ≈ 0.02388490515704142f0
    @test row.Q_6336510 ≈ 0.012411069754330572f0
    @test row.Q_6836100 ≈ 0.004848609260578462f0
    @test row.Q_6336500 ≈ 0.011474801875419624f0
    @test row.Q_6836190 ≈ 0.0005262529349807199f0
    @test row.Q_6336800 ≈ 0.013467698526109831f0
    @test row.Q_6336900 ≈ 0.003408280699908697f0
    @test row.Q_6336930 ≈ 0.09773275295006544f0
    @test row.Q_6336910 ≈ 0.002147610203630289f0
    @test row.Q_6336920 ≈ 0.002649393436607859f0
    @test row.Q_6136100 ≈ 0.0008708128761381345f0
    @test row.Q_6136500 ≈ 0.000729148906480041f0
    @test row.Q_6136520 ≈ 0.002155395279410574f0
    @test row.Q_6136150 ≈ 0.0022298329229975987f0
    @test row.Q_6136151 ≈ 0.0031045027476524524f0
    @test row.Q_6136160 ≈ 3.3423894540713786f0
    @test row.Q_6136200 ≈ 1.358270076420503f0
    @test row.Q_6136201 ≈ 5.942330218662147f0
    @test row.Q_6136202 ≈ 1.680997341533662f0
    @test row.recharge_1 ≈ -0.027398093386017383f0
end

@testset "NetCDF scalar output" begin
    ds = model.writer.dataset_scalar
    @test ds["time"][1] == DateTime("2000-01-01T00:00:00")
    @test ds["Q"][:] ≈ [
        1.6809974f0,
        5.9423304f0,
        1.35827f0,
        3.3423896f0,
        0.0031045028f0,
        0.0022298328f0,
        0.0021553952f0,
        0.0007291489f0,
        0.00087081286f0,
        0.0026493934f0,
        0.0021476103f0,
        0.09773275f0,
        0.0034082807f0,
        0.013467698f0,
        0.00052625296f0,
        0.011474802f0,
        0.004848609f0,
        0.01241107f0,
        0.023884906f0,
    ]
    @test ds["Q_gauges"].attrib["cf_role"] == "timeseries_id"
    @test ds["temp_index"][:] ≈ [2.3279827f0]
    @test ds["temp_coord"][:] ≈ [2.3279827f0]
    @test keys(ds.dim) == ["time", "Q_gauges", "temp_bycoord", "temp_byindex"]
end

@testset "first timestep" begin
    sbm = model.vertical

    @test sbm.tt[50069] ≈ 1.2999999523162842f0

    @test model.clock.iteration == 2

    @test sbm.θₛ[50069] ≈ 0.48343977332115173f0
    @test sbm.runoff[50069] == 0.0
    @test sbm.soilevap[50069] == 0.0
    @test sbm.snow[50069] ≈ 0.6029989752244306f0
end

# run the second timestep
model = Wflow.update(model)

@testset "second timestep" begin
    sbm = model.vertical
    @test sbm.θₛ[50069] ≈ 0.48343977332115173f0
    @test sbm.runoff[50069] == 0.0
    @test sbm.soilevap[50069] ≈ 0.005865651540305367f0
    @test sbm.snow[50069] ≈ 0.009696763863612956f0
end

@testset "subsurface flow" begin
    ssf = model.lateral.subsurface.ssf
    @test sum(ssf) ≈ 6.368140761295825f16
    @test ssf[network.land.order[1]] ≈ 5.324295565183691f11
    @test ssf[network.land.order[end-100]] ≈ 7.855716879739626f11
    @test ssf[network.land.order[end]] ≈ 2.161246841709492f11
end

@testset "overland flow" begin
    q = model.lateral.land.q_av
    @test sum(q) ≈ 319.69538082148307f0
    @test q[26625] ≈ 0.0
    @test q[39308] ≈ 0.0
    @test q[network.land.order[end]] ≈ 1.0978547520221912f-5
end

@testset "river flow" begin
    q = model.lateral.river.q_av
    @test sum(q) ≈ 2807.884971209105f0
    @test q[1622] ≈ 0.0016288040314320486f0
    @test q[43] ≈ 7.338169165884175f0
    @test q[network.river.order[end]] ≈ 0.00610520650626283f0
end

@testset "reservoir simple" begin
    res = model.lateral.river.reservoir
    @test res.outflow[1] ≈ 0.2174998592483153f0
    @test res.inflow[1] ≈ 50.170880189190626f0
    @test res.volume[1] ≈ 2.776162917050312f7
    @test res.precipitation[1] ≈ 0.1765228509902954f0
    @test res.evaporation[1] ≈ 0.5372688174247742f0
end

# set these variables for comparison in "changed dynamic parameters"
precip = copy(model.vertical.precipitation)
evap = copy(model.vertical.potential_evaporation)
lai = copy(model.vertical.leaf_area_index)
res_evap = copy(model.lateral.river.reservoir.evaporation)

benchmark = @benchmark Wflow.update(model)
trialmin = BenchmarkTools.minimum(benchmark)

println("SBM Model update")
print_benchmark(trialmin)
# @profview Wflow.update(model)
Wflow.close_files(model, delete_output = false)

# test for setting a pit
tomlpath = joinpath(@__DIR__, "sbm_config.toml")
config = Wflow.Config(tomlpath)
config["model"]["pits"] = true
config["input"]["pits"] = "wflow_pits"
config.endtime = DateTime(2000, 1, 9)

model = Wflow.run(config)

@testset "timing" begin
    # clock has been reset
    calendar = get(config, "calendar", "standard")::String
    @test model.clock.time == Wflow.cftime(config.starttime, calendar)
    @test model.clock.iteration == 1
end

# pit is at river index 1765, CartesianIndex(141, 86)
# downstream from pit is at river index 1739, CartesianIndex(142, 85)
@testset "river flow at and downstream of pit" begin
    q = model.lateral.river.q_av
    @test q[3908] ≈ 8.133435566601927f0
    @test q[3920] ≈ 0.008996045895155833f0
end

# test changing forcing and cyclic LAI parameter
tomlpath = joinpath(@__DIR__, "sbm_config.toml")
config = Wflow.Config(tomlpath)

config.input.vertical.precipitation =
    Dict("scale" => 2.0, "netcdf" => Dict("variable" => Dict("name" => "P")))
config.input.vertical.potential_evaporation = Dict(
    "scale" => 3.0,
    "offset" => 1.50,
    "netcdf" => Dict("variable" => Dict("name" => "PET")),
)
config.input.vertical.leaf_area_index =
    Dict("scale" => 1.6, "netcdf" => Dict("variable" => Dict("name" => "LAI")))

model = Wflow.initialize_sbm_model(config)
model = Wflow.update(model)
model = Wflow.update(model)

@testset "changed dynamic parameters" begin
    res = model.lateral.river.reservoir
    vertical = model.vertical
    @test vertical.precipitation[2] / precip[2] ≈ 2.0f0
    @test (vertical.potential_evaporation[100] - 1.50) / evap[100] ≈ 3.0f0
    @test vertical.leaf_area_index[100] / lai[100] ≈ 1.6f0
    @test (res.evaporation[2] - 1.50) / res_evap[2] ≈ 3.0000012203408635f0
end
Wflow.close_files(model, delete_output = false)


text:
module Formats

using Dates:Date
import Base:show
export formats

mutable struct FmtVer
  v::Union{Number, String}
  d::Union{Date, String}
  s::Union{Bool, Nothing}

  FmtVer() = new(0, Date("1970-01-01"), nothing)

  FmtVer(v::Union{Number, String},
         d::Union{Date, String},
         s::Union{Bool, Nothing}) = new(v,d,s)
end

const HistVec = Array{FmtVer,1}
const FmtStatus = Dict{UInt8, String}(
  0x00 => "unknown",
  0x01 => "in use; maintained",
  0x20 => "legacy; maintained but no longer in use",
  0xfd => "ostensibly maintained, but they don't answer our emails",
  0xfe => "suspected abandoned, can't find contact info",
  0xff => "abandoned"
)

mutable struct FormatDesc
  name::String
  str::String
  origin::String
  source::String
  contact::String
  ver::HistVec
  desc::Array{String,1}
  used::Array{String,1}
  docs::Array{String,1}
  status::UInt8

  function FormatDesc()
    return new( "",
                "",
                "",
                "",
                "",
                HistVec(undef, 0),
                String[],
                String[],
                String[],
                0x00,
              )
  end

  function FormatDesc(  name::String,
                        str::String,
                        origin::String,
                        source::String,
                        contact::String,
                        ver::HistVec,
                        desc::Array{String,1},
                        used::Array{String,1},
                        docs::Array{String,1},
                        status::UInt8
                      )

    return new(name, str, origin, source, contact, ver, desc, used, docs, status)
  end
end

@doc """
    formats[fmt]

Show resources for working with data format `fmt`. Returned are:
* name: Data format name
* read_data: String(s) to pass to `read_data` for this format, separated by commas
* origin: Where the data format was created
* source: Where to download external source code for working with data in this format
* contact: Whom to contact with questions
* description: Description of the data format's purpose and any notable issues
* used by: Where the data format is typically encountered
* status: Whether the data format is still in use
* versions: Notable versions or revisions to the standard
* documentation: Any useful documentation related to understanding a format

    formats["list"]

List formats with entries.

### How to read "status:"
* "in use" means that a data format is currently used to read, transmit, or archive new data from modern geophysical instruments.
* "legacy" means that a data format is maintained by an official authority but no longer being actively developed or used by new equipment.
* "abandoned" means that a data format is no longer maintained.

### Notes
* `:used` lists locations, programs, and research areas where the format is (or was) used.
* `:ver` format is `number`, `date`, `read/write`. In the third field, "r" means read support, "rw" means read or write support, "-" means no support.

""" formats
const formats = Dict{String, Union{Array{String,1}, FormatDesc}}()

function show(io::IO, F::FormatDesc)
  p = 17
  println("")
  printstyled(lpad("name:", p), color=:cyan, bold=true)
  printstyled(" "*getfield(F, :name)*"\n", bold=true)
  printstyled(lpad("string:", p), color=:cyan)
  printstyled(" "*getfield(F, :str)*"\n")
  for i in (:origin, :source, :contact)
    printstyled(lpad(string(i)*":", p), color=:cyan)
    println(" ", getfield(F, i))
  end
  printstyled(lpad("description:\n", p+1), color=:cyan)
  for i in F.desc
    println(" "^(p+1), i)
  end
  printstyled(lpad("used by:\n", p+1), color=:cyan)
  for i in F.used
    println(" "^(p+1), i)
  end
  printstyled(lpad("status:\n", p+1), color=:cyan)
  println(" "^(p+1), FmtStatus[F.status])
  printstyled(lpad("versions:\n", p+1), color=:cyan)
  for i in F.ver
    println(" "^(p+1), i.v, ", ", i.d, ", ", i.s == nothing ? "-" : i.s == true ? "rw" : "r")
  end
  printstyled(lpad("documentation:", p), color=214, bold=true)
  println("")
  for i in F.docs
    println(" "^(p+1), i)
  end
end
show(F::FormatDesc) = show(stdout, F)

include("FormatGuide/formats_list.jl")

end


text:
@testset "varargs" begin
    @noinline f(a, b, c...) = a + b + sum(c)

    @noinline function foobar()
        f(3, 4, 5, 6, 7)
    end

    @test TinyCassette.execute(nothing, foobar) == 25
end


text:
function to_symbol_arg_dict(str_dict)
    sym_dict = Dict{Symbol, Any}()
    for (str_k, dat) in str_dict
        str_k = replace(str_k, "-" => "_")
        sym_dict[Symbol(str_k)] = dat
    end
    return sym_dict
end

ishomedir(path) = isdir(path) && (abspath(path) == abspath(homedir()))
isrootdir(path) = isdir(path) && (abspath(path) == abspath(dirname(path)))