text:
#
# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher
# Licensed under the MIT license. See LICENSE file in the project root for details.
#

################################## INSTALLATION ###############################################
# (1) Enter Package Manager via     ]
# (2) Install FMI via               add FMI     or    add "https://github.com/ThummeTo/FMI.jl"
################################ END INSTALLATION #############################################

using FMI

# this FMU runs under Windows and Linux
pathToFMU = joinpath(dirname(@__FILE__), "../model/OpenModelica/v1.17.0/SpringFrictionPendulum1D.fmu")

# this FMU runs only under Windows
if Sys.iswindows()
    pathToFMU = joinpath(dirname(@__FILE__), "../model/Dymola/2020x/SpringFrictionPendulum1D.fmu")
end

# this is how you can quickly simulate a FMU
myFMU = fmiLoad(pathToFMU)
fmiInstantiate!(myFMU)
simData = fmiSimulate(myFMU, 0.0, 10.0; recordValues=["mass.s"])
fmiPlot(simData)
fmiUnload(myFMU)

# this is how you can simulate a FMU with more possibilities
myFMU = fmiLoad(pathToFMU)
fmuComp = fmiInstantiate!(myFMU)
fmiSetupExperiment(fmuComp, 0.0, 10.0)
fmiEnterInitializationMode(fmuComp)
fmiExitInitializationMode(fmuComp)
dt = 0.1
ts = 0.0:dt:10.0
for t in ts
    fmiDoStep(fmuComp, t, dt)
end
fmiTerminate(fmuComp)
fmiFreeInstance!(fmuComp)
fmiUnload(myFMU)


text:
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Description
# ==============================================================================
#
#   Tests related to the components used to compute CIO in IAU-2006 theory.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# References
# ==============================================================================
#
#   [1] Vallado, D. A (2013). Fundamentals of Astrodynamics and Applications.
#       Microcosm Press, Hawthorn, CA, USA.
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

# File: ./src/transformations/cio.jl
# ==================================

# Function cio_iau2006
# --------------------

################################################################################
#                                 Test Results
################################################################################
#
# Scenario 01
# ===========
#
# Example 3-14: Performing an IAU-2000 reduction [1, p. 220]
#
# According to this example, using JD_TT = 2453101.828154745, one gets:
#
#   X = 80.531880"
#   Y =  7.273921"
#   s = -0.003027"
#
################################################################################

@testset "Function cio_iau2006" begin
    JD_TT = 2453101.828_154_745

    X,Y,s = cio_iau2006(JD_TT)

    @test X*180/pi*3600 ≈ 80.531880 atol = 5e-5
    @test Y*180/pi*3600 ≈  7.273921 atol = 5e-5
    @test s*180/pi*3600 ≈ -0.003027 atol = 1e-6
end

ext: jl


text:
using DrWatson
@quickactivate "AccuracyAtTop_DeepTopPush"

include(srcdir("utilities.jl"))

# ------------------------------------------------------------------------------------------
# Metrics
# ------------------------------------------------------------------------------------------
collect_benchmark()

# ------------------------------------------------------------------------------------------
# Metrics
# ------------------------------------------------------------------------------------------
df = collect_metrics(; key = :test, epochs = 200)

table_1 = @linq df |>
    where(:batchsize .== 32)

CSV.write(datadir("results", "metrics_mean.csv"), table_1)

# ------------------------------------------------------------------------------------------
# Curves
# ------------------------------------------------------------------------------------------
Dataset_Settings = Dict(
    :dataset => CIFAR100,
    :posclass => 1,
)

Train_Settings = Dict(
    :batchsize => 32,
    :epochs => 200,
    :optimiser => Descent,
    :steplength => 0.0001,
    :seed => 1,
)

Model_Settings = Dict(
    :type => [BaseLine, DeepTopPush, PatMatNP, APPerf, TFCO],
    :arg => [missing, missing, 0.01, 0.01, 0.01],
    :surrogate => [missing, quadratic, quadratic, missing, missing],
    :reg => 1e-3,
    :buffer => [missing, true, missing, missing, missing],
)

collect_curves(
    Dataset_Settings,
    Train_Settings,
    Model_Settings;
    key = :test,
    xlims = (1e-3, 1),
)


text:
module EverestCrystalShatterTrigger

using ..Ahorn, Maple

const placements = Ahorn.PlacementDict(
    "Crystal Shatter (Everest)" => Ahorn.EntityPlacement(
        Maple.EverestCrystalShatterTrigger,
        "rectangle"
    )
)

function Ahorn.editingOptions(trigger::Maple.EverestCrystalShatterTrigger)
    return Dict{String, Any}(
        "mode" => Maple.everest_crystal_shatter_trigger_modes
    )
end

end


text:
"""
    OneHotTensor{N, T}(classes) <: Block

A block representing a one-hot encoded, N-dimensional array
categorical variable. For example, a single categorical label
is a `OneHotTensor{0, T}` (aliased to `OneHotTensor{T}`).

Use the [`OneHot`](#) encoding to one-hot encode [`Label`](#)s
or [`LabelMulti`](#)s.
"""
struct OneHotTensor{N, T} <: Block
    classes::AbstractVector{T}
end

const OneHotLabel{T} = OneHotTensor{0, T}

Base.summary(io::IO, ::OneHotLabel{T}) where T = print(io, "OneHotLabel{$T}")

function checkblock(block::OneHotTensor{N}, a::AbstractArray{T, M}) where {M, N, T}
    return N + 1 == M && last(size(a)) == length(block.classes)
end

mockblock(block::OneHotTensor{0}) = encode(
    OneHot(), Validation(), Label(block.classes), rand(block.classes))

function mockblock(block::OneHotTensor{N}) where N
    maskblock = Mask{N}(block.classes)
    return encode(OneHot(), Validation(), maskblock, mockblock(maskblock))
end

struct OneHotTensorMulti{N, T} <: Block
    classes::AbstractVector{T}
end

function checkblock(block::OneHotTensorMulti{N}, a::AbstractArray{T, M}) where {M, N, T}
    return N + 1 == M && last(size(a)) == length(block.classes)
end

function mockblock(block::OneHotTensorMulti{0}) where N
    labelblock = LabelMulti(block.classes)
    return encode(OneHot(), Validation(), labelblock, mockblock(labelblock))
end

"""
    OneHot()
    OneHot(T, threshold)

`Encoding` that turns categorical labels into one-hot encoded arrays of type `T`.

Encodes
```
      `Mask{N, U}` -> `OneHotTensor{N, T}`
`LabelMulti{N, U}` -> `OneHotTensorMulti{N, T}`
        `Label{U}` -> `OneHotTensor{N, T}`
```
"""
struct OneHot{TT<:Type} <: Encoding
    T::TT
    threshold::Float32
end

OneHot() = OneHot(Float32, 0.5f0)

# ### `Label` implementation
encodedblock(::OneHot, block::Label{T}) where T = OneHotTensor{0, T}(block.classes)
decodedblock(::OneHot, block::OneHotLabel) = Label(block.classes)

function encode(enc::OneHot, context, block::Label, obs)
    idx = findfirst(isequal(obs), block.classes)
    isnothing(idx) && error("$obs could not be found in `block.classes`: $(block.classes).")
    return DataAugmentation.onehot(enc.T, idx, length(block.classes))
end

function decode(::OneHot, context, block::OneHotLabel, obs)
    return block.classes[argmax(obs)]
end

# ### `LabelMulti` implementation

encodedblock(::OneHot, block::LabelMulti{T}) where T = OneHotTensorMulti{0, T}(block.classes)
decodedblock(::OneHot, block::OneHotTensorMulti{0}) = LabelMulti(block.classes)

function encode(enc::OneHot, _, block::LabelMulti, obs)
    return collect(enc.T, (c in obs for c in block.classes))
end

function decode(enc::OneHot, _, block::OneHotTensorMulti{0}, obs)
    return block.classes[softmax(obs) .> enc.threshold]
end

function blocklossfn(outblock::OneHotTensor{0}, yblock::OneHotTensor{0})
    outblock.classes == yblock.classes || error("Classes of $outblock and $yblock differ!")
    return Flux.Losses.logitcrossentropy
end

function blocklossfn(outblock::OneHotTensorMulti{0}, yblock::OneHotTensorMulti{0})
    outblock.classes == yblock.classes || error("Classes of $outblock and $yblock differ!")
    return Flux.Losses.logitbinarycrossentropy
end

# ## Tests

@testset "OneHot [encoding]" begin
    enc = OneHot()
    testencoding(enc, Label(1:10), 1)
    testencoding(enc, LabelMulti(1:10), [1])
    testencoding(enc, Mask{2}(1:10), rand(1:10, 50, 50))
end


text:
const EPS=nextfloat(0.0)

"""
    LinkType(from,to,dir=2)

Create a LinkType structure that describes the properties of a type of link in the network.

Think of a LinkType as a set of criteria that describe a certain sort of link. The first two arguments
specify the states of the nodes at the start and end of the link respectively. The third argument specified if the LinkType
can either be 1 or 2, where *dir=1* signifies that the link type should be interpreted as directed (unidirectional)
and *dir=2* signifies that it should be interpreted as undirected (bidirectional).

The state of the node at the start and end of this type of link can be specified in different ways.
A value of 0 or \\* for *from* or *to* means that the respective node can be in any state. An integer value corresponding
to a node state means that the node must be in the respective state. An Array or Tuple of Ints means that the
node must be in one of the states listed.

# Examples
```jldoctest
julia> using Fastnet

julia> LinkType(3,4)
Links of the form:  (3) --- (4)

julia> LinkType(3,4,1)
Links of the form:  (3) --> (4)

julia> LinkType(3,4,2)
Links of the form:  (3) --- (4)

julia> LinkType("*",4)
Links of the form:  (any) --- (4)

julia> LinkType(4,0)
Links of the form:  (4) --- (any)

julia> LinkType((1,2),3)
Links of the form:  (1/2) --- (3)

julia> LinkType(4,[1,2],1)
Links of the form:  (4) --> (1/2)
```

"""
struct LinkType
    from
    to
    dir::Int
    LinkType(from,to,dir) = begin
        (f,t,d)=verify_linktype!(from,to,dir)
        new(f,t,d)
    end
end

function LinkType(from,to)
    LinkType(from,to,2)
end

"""
    FastNet(n,k,c,tlist;<keyword arguments>)

Create a FastNet object that represents a network structe.

Memory will be allocated for up to *n* nodes, up to *k* links. Nodes can be in one of *c* different states.

The argument tlist is an array or tuple of LinkType. This list tells the networks which types of links are
important for you. For example in an epidemic simulation the we are particularly interested in links between
infected and susceptible nodes. FastNet will do the necessary bookkeeping, to enable very fast counting, selection, etc.
of the links that are in a state listed in tlist.

Note that the order of elements of tlist is not arbitrary. FastNet will think of links that match the first element
of tlist as being in link state 1. The links that match the sceond type in link state 2, and so on.

WARNING: Each link in the network can only be in any one state at any time passing a tlist that contains overlapping
link types (e.g. [LinkType([1,2],3),LinkType(3,1)] )  will result in an ArgumentError being thrown.

FastNet supports a number of optional keyword arguments:
- nodealias : a vector of strings that will be used as names of node states in outputs
- linkalias : a vector of strings that will be used as names of link states in outputs
- rng : specifies a custom random number generator

The network will initially be empty (i.e. a null graph)

# Examples
```jldoctest
julia> using Fastnet

julia> FastNet(10,9,1,[])
Network of 0 nodes and 0 links

julia> FastNet(100,1000,3,[LinkType(1,2),LinkType(3,"*",1)])
Network of 0 nodes and 0 links

julia> using Random

julia> mt = MersenneTwister(1234);

julia> const S=1;

julia> const I=2;

julia> SI_link=LinkType(S,I)
Links of the form:  (1) --- (2)

julia> net=FastNet(10000,60000,2,[SI_link],nodealias=["S","I"],linkalias=["S-I"],rng=mt)
Network of 0 nodes and 0 links
```
"""
mutable struct FastNet
    rng::AbstractRNG
    N::Int
    K::Int
    C::Int
    L::Int
    nid::Vector
    npos::Vector
    nin::Vector
    nout::Vector
    nstate::Vector
    ncstart::Vector
    nclen::Vector
    kid::Vector
    kpos::Vector
    knexts::Vector
    knextd::Vector
    kstate::Vector
    ksrc::Vector
    kdst::Vector
    kcstart::Vector
    kclen::Vector
    ttable::Array
    nodealias::Vector
    linkalias::Vector
end

function FastNet(n,k,c,tlist;nodealias=String[],linkalias=String[],rng=Random.GLOBAL_RNG)
    N=0
    K=0
    C=0
    try
        N=convert(Int,n)
    catch e
        throw(ArgumentError("FastNet constructor expects the number of nodes to be of type Int"))
    end
    if N<0
        throw(ArgumentError("FastNet constructor expects the number of nodes to be positive"))
    end
    try
        K=convert(Int,k)
    catch e
        throw(ArgumentError("FastNet constructor expects the number of links to be of type Int"))
    end
    if K<0
        throw(ArgumentError("FastNet constructor expects the number of links to be positive"))
    end
    try
        C=convert(Int,c)+1
    catch e
        throw(ArgumentError("FastNet constructor expects the number of node states to be of type Int"))
    end
    if C<2
        throw(ArgumentError("FastNet constructor expects the number of node states to be at least 1"))
    end
    if isa(tlist,Tuple)
        tlist=[tlist...]
    end
    if isa(nodealias,Tuple)
        nodealias=[nodealias...]
    end
    if isa(linkalias,Tuple)
        linkalias=[linkalias...]
    end
    if isa(tlist,LinkType)
        tlist=[tlist]
    end
    if !isa(tlist,Array)
        msg="FastNet constructor expects the third argument to be an Array{LinkType}"
        throw(ArgumentError(msg))
    end
    if !(isa(tlist,Array{LinkType}) || isempty(tlist))
        msg="FastNet constructor expects the third argument to be an Array{LinkType}"
        throw(ArgumentError(msg))
    end
    if isa(linkalias,String)
        linkalias=[linkalias]
    end
    if isa(nodealias,String)
        nodealias=[nodealias]
    end
    if !isa(linkalias,Array{String})
        msg="FastNet constructor expects linkalias to be an array of strings."
        throw(ArgumentError(msg))
    end
    if !isa(nodealias,Array{String})
        msg="FastNet constructor expects nodealias to be an array of strings."
        throw(ArgumentError(msg))
    end
    l=length(tlist)
    L=l+2
    if length(nodealias)>c
        msg="Nodealias list passed to FastNet contains more elements than there are node types in the network"
        throw(ArgumentError(msg))
    end
    if length(linkalias)>l
        msg="Linkalias list passed to FastNet contains more elements than there link types defined in tlist"
        throw(ArgumentError(msg))
    end
    if !(isa(rng,AbstractRNG))
        msg="FastNet expects rng to be a random number generator (subtype of AbstractRNG)"
        throw(ArgumentError(msg))
    end
    na=Vector{String}(undef,c)
    la=Vector{String}(undef,l)
    len=length(nodealias)
    for i=1:c
        i<=len ? na[i]=string(nodealias[i]) : na[i]="Node state $i"
    end
    len=length(linkalias)
    for i=1:l
        i<=len ? la[i]=string(linkalias[i]) : la[i]="Link state $i"
    end
    nid=[1:N;]
    npos=[1:N;]
    nin=zeros(Int,N)
    nout=zeros(Int,N)
    nstate=fill(C,N)
    ncstart=zeros(Int,C)
    nclen=zeros(Int,C)
    kid=[1:K;]
    kpos=[1:K;]
    knexts=zeros(Int,K)
    knextd=zeros(Int,K)
    kstate=fill(L,K)
    ksrc=zeros(Int,K)
    kdst=zeros(Int,K)
    kcstart=zeros(Int,L)
    kclen=zeros(Int,L)
    ttable=SArray{Tuple{c,c}}(make_linkstate_table(tlist,c,L))  # Lookup table for tracked link states
    nclen[C]=N
    kclen[L]=K
    return FastNet(rng,N,K,C,L,nid,npos,nin,nout,nstate,ncstart,nclen,kid,kpos,knexts,knextd,kstate,ksrc,kdst,kcstart,kclen,ttable,na,la)
end

"""
    FastSim(net,rates!,processes;<keyword arguments>)

Create a FastSim structure, representing a FastNet simulation run.

The first argument *net* is a FastNet structure that is be used in the simulation.

The second argument is the *rates!* function of the simulation. The rates function is a function
that accepts two arguments. The first of these arguments is an MVector{Float64}
(see StaticArrays Documentation for details). The second argument is a the current time in the simulation.

When the *rates!* function is called it should compute the total rates of at which the different processes
occur in the system, given the current state of the network. The rates functions returns these values by
filling the array that was passed as the first argument. The rates! should not have a return value.

Note that when rates are time dependent then the rates! function should use the time value passed to it rather
than obtaining a time form the simulation structure. The simulation code assumes that the rates will remain
constant until the next event. This should be harmless in almost all cases but can cause inaccuracy if your
rates depend explicitely on time, the rates are very senstitive to time and events are rare.

The third argument is a Vector of functions that implements the processes. The processes are functions
without arguments when they are called they should implement effect of the respecive process running once.
Note that elemets of the process function vector should be in the same order as the corresponding rates computed by
the *rates!* vector.

FastSim supports a number of optional keyword arguments:

- saveas : A String specifying the pathname where results should be saved. If unspecified results aren't saved but
  can be optained using the *results* function.

- output : a boolean variable that specifies if results should be printed on the console, by default this is true.
  Alternatively also an IOStream can be provided to which results should be written.

- repfunc : This argument can be used to specify an alternative function to generate outputs and store results.
  See [custimization](customization.md) for details.

# Examples
```jldoctest
julia> using Fastnet

julia> const Bored=1; const Excited=2;

julia> net=FastNet(1000,5000,2,[LinkType(Excited,Bored,1)]);

julia> randomgraph!(net);

julia> function rates!(rates,t)
         rates[1]=countlinks(net,1)*0.1
         rates[2]=countnodes(net,Excited)*0.2
         rates[3]=countnodes(net,Bored)*0.001
         end;

julia> function excitement_spreads()
         link=randomlink(net,1)
         nodestate!(net,linkdst(net,link),Excited)
         end;

julia> function get_bored()
         node=randomnode(net,Excited)
         nodestate!(net,node,Bored)
         end;

julia> function great_idea()
         node=randomnode(net,Bored)
         nodestate!(net,node,Excited)
         end;

julia> sim=FastSim(net,rates!,[excitement_spreads,get_bored,great_idea])
Simulation run, currently at time 0.0
```
"""
mutable struct FastSim
    net::FastNet
    Nproc::Int
    ratefunc::Function
    procfunc::Vector
    repfunc::Function
    Trep::Float64
    Trepcur::Float64
    t::Float64
    Tend::Float64
    nodedigits::Int
    linkdigits::Int
    timedigits::Int
    timedec::Int
    Nout::Int
    results::DataFrame
    filename::String
    printresults::Union{Bool,IOStream}
end

function FastSim(net::FastNet,ratefunc,procfunc;repfunc=showresults,saveas="",output=true)
    if isa(procfunc,Function)                # Check process function array
        procfunc=[procfunc]
    end
    if isa(procfunc,Tuple)
        procfunc=[procfunc...]
    end
    if !isa(procfunc,Array)
        msg="FastSim constructor expects the third argument to be an Array{Function}"
        throw(ArgumentError(msg))
    end
    procfunc=vec(reshape(procfunc,1,:))
    Nproc=length(procfunc)                  # Determin number of processes
    rates=MVector{Nproc}(zeros(Nproc))      # Check rates! function
    if !isa(ratefunc,Function)
        msg="FastSim constructor expects the second argument to be the rates! function,"
        msg*=" but the argument that was passed isn't a function."
        throw(ArgumentError(msg))
    end
    try
        ratefunc(rates,0.0)
    catch e
        msg="FastSim constructor tried calling the rates! function provided as second argument,"
        msg*=" but encountered an error."
        throw(ArgumentError(msg))
    end
    for i=1:Nproc                                       # Check process functions
        if !applicable(procfunc[i])
            msg="FastSim constructor expects the third argument to be an array of functions that require no "
            msg*="arguments, but I was not able to call these function $i in this Array."
            throw(ArgumentError(msg))
        end
    end
    if !isa(saveas,String)
        msg="FastSim constructor expects saveas to be a String"
        throw(ArgumentError(msg))
    end
    if !(isa(output,Bool) || isa(output,IOStream))
        msg="FastSim constructor expects output to be either of type Bool or of type IOStream"
        throw(ArgumentError(msg))
    end
    if isa(output,IOStream) && !iswritable(output)
        msg="The IOStream provided as output in FastSim is not writable."
        throw(ArgumentError(msg))
    end

    Tend=0.0
    nodedigits=Int(ceil(log10(net.N)))
    c=net.C-1
    for i=1:c
        len=length(net.nodealias[i])
        if len>nodedigits
            nodedigits=len
        end
    end
    linkdigits=Int(ceil(log10(net.K)))
    l=net.L-2
    for i=1:l
        len=length(net.linkalias[i])
        if len>linkdigits
            linkdigits=len
        end
    end
    timedigits=5
    timedec=2
    Nout=0
    r=DataFrame()
    r[!,"Time"]=Float64[]
    for n in net.nodealias
       r[!,n]=Int[]
    end
    for l in net.linkalias
        r[!,l]=Int[]
    end
    if length(saveas)!==0
        fl=0
        try
            fl=open(saveas,"w+")
        catch e
            throw(ArgumentError("FastSim Constructor was unable to open file $saveas for writing."))
        end
        close(fl)
    end
    sim=FastSim(net,Nproc,ratefunc,procfunc,repfunc,1.0,0.0,0.0,Tend,nodedigits,linkdigits,timedigits,timedec,Nout,r,saveas,output)
    if !applicable(repfunc,sim,true)
        msg="FastSim constructor expects repfunc to be a Function(FastSim,Bool),"
        msg*=" however the function provided does not accept the right arguments."
        throw(ArgumentError(msg))
    end
    sim
end


text:
import ..update!, ..select_action, ..reset!

using ..Buffers:Experience

using StaticArrays
using Random
using LinearAlgebra:Diagonal, UniformScaling

using Ramnet.Models.AltDiscriminators:RegularizedFunctionalDiscriminator
using Ramnet.Optimizers
import Ramnet.Loss

struct RegularizedContinousPolicyLoss <: Loss.AbstractLoss end

# Policy approximator with only two admissible actions: {-1, 1}.
mutable struct RegularizedContinousPolicy{OS,AS,T <: Real,O <: StaticArray{Tuple{OS},T,1},A <: StaticArray{Tuple{AS},T,1},E <: AbstractEncoder{T}}
    opt::FunctionalOptimizer{RegularizedContinousPolicyLoss}
    f::RegularizedFunctionalDiscriminator{AS,T,E}
    # Covariance diagonal matrix
    start_cov::Float64
    end_cov::Float64
    cov_decay::Int
    update_count::Int
    rng::MersenneTwister
end

function RegularizedContinousPolicy(::Type{O}, ::Type{A}, n::Int, encoder::E; α::Float64=1.0, start_cov::Float64, end_cov::Float64, cov_decay::Int, η::Float64=0.1, epochs::Int=1, partitioner::Symbol=:uniform_random, seed::Union{Nothing,Int}=nothing) where {AS,OS,T <: Real,O <: StaticArray{Tuple{OS},T,1},A <: StaticArray{Tuple{AS},T,1},E <: AbstractEncoder{T}}
    RegularizedContinousPolicy{OS,AS,T,O,A,E}(
        FunctionalOptimizer(RegularizedContinousPolicyLoss(); learning_rate=η, epochs),
        RegularizedFunctionalDiscriminator{AS}(OS, n, α, encoder, partitioner; seed),
        start_cov,
        end_cov,
        cov_decay,
        0,
        isnothing(seed) ? MersenneTwister() : MersenneTwister(seed)
    )
end

function cov(p::RegularizedContinousPolicy{OS,AS,T,O,A,E}) where {OS,AS,T,O,A,E}
    α = p.update_count / p.cov_decay
    UniformScaling((1 - α) * p.start_cov + α * p.end_cov)
end

function Loss.grad(::RegularizedContinousPolicyLoss, p::RegularizedContinousPolicy{OS,AS,T,O,A,E}, observation::O, action::A, G) where {OS,AS,T,O,A,E}
    inv(cov(p)) * (predict(p.f, observation) - action) * G
end

# TODO: Validate action (must be ether -1 or +1)
function update!(p::RegularizedContinousPolicy{OS,AS,T,O,A,E}, observation::O, action::A, G) where {OS,AS,T,O,A,E}
    gradient = Optimizers.grad(p.opt, p, observation, action, G)

    train!(p.f, observation, learning_rate(p.opt) * gradient)
    p.update_count = p.update_count == p.cov_decay ? p.cov_decay : p.update_count + 1

    return nothing
end

function update!(p::RegularizedContinousPolicy{OS,AS,T,O,A,E}, experiences::AbstractVector{Experience{O,A}}, critic) where {OS,AS,T,O,A,E}
    gradients = Matrix{Float64}(undef, AS, length(experiences))
    observations = Matrix{T}(undef, OS, length(experiences))

    for i in eachindex(experiences)

        observation = experiences[i].observation
        action = experiences[i].action
        value = experiences[i].value
        advantage = value - critic(observation)
        gradients[:, i] = Optimizers.grad(p.opt, p, observation, action, advantage)
        observations[:, i] = observation
    end

    train!(p.f, observations, SizedMatrix{AS,length(experiences)}(learning_rate(p.opt) * gradients))
    p.update_count = p.update_count == p.cov_decay ? p.cov_decay : p.update_count + 1

    nothing
end

function select_action(p::RegularizedContinousPolicy{OS,AS,T,O,A,E}, observation::O) where {OS,AS,T,O,A,E}
    return SizedVector{AS}(cov(p) * randn(p.rng, AS) + predict(p.f, observation))
end

function reset!(p::RegularizedContinousPolicy)
    Ramnet.reset!(p.f)

    return nothing
end


text:
## ------------------------------------------------------------------
function _new_document!(callinfo::LineNumberNode, label)

    # book
    book = _check_currbook()

    # TODO: Update book but just if necessary

    # checks
    _check_call_inbook(callinfo, book)

    # new doc
    doc = RBDoc(label)
    set_book!(doc, book)
    srcfile!(doc, srcfile(callinfo))
    srcline!(doc, srcline(callinfo))

    # add to book
    add_doc!(book, doc)

    currdoc!(doc)
end

## ------------------------------------------------------------------
macro new_document!(ex...)
    label = _insert_label!("new_document!", ex, __source__)
    _new_document!(__source__, label)
end


text:
if !(haskey(ENV, "JULIA_SCS_LIBRARY_PATH") || VERSION < v"1.3")
    @info("Installing default SCS binaries")
    exit(0)
end

using BinaryProvider, Libdl # requires BinaryProvider 0.3.0 or later

## NOTE: This is not a typical build.jl file; it has extra stuff toward the bottom.
## Don't just replace this file with the output of a BinaryBuilder repository!

# Parse some basic command-line arguments
const verbose = "--verbose" in ARGS
const prefix = Prefix(get([a for a in ARGS if a != "--verbose"], 1, joinpath(@__DIR__, "usr")))
products = [
    LibraryProduct(prefix, ["libscsindir"], :indirect),
    LibraryProduct(prefix, ["libscsdir"], :direct),
]

# Download binaries from hosted location
function url(triplet)
    return "https://github.com/JuliaBinaryWrappers/SCS_jll.jl/releases/download/SCS-v2.1.4+0/SCS.v2.1.4.$(triplet).tar.gz"
end

# If you need to recompute the hashes for theses files, use:
# using SHA
# for (key, arg) in download_info
#     print(key)
#     open(io -> println(bytes2hex(sha2_256(io))), download(arg[1]))
# end

# Listing of files generated by BinaryBuilder:
download_info = Dict(
    Linux(:aarch64, libc=:glibc) => (url("aarch64-linux-gnu"), "9db5a4a164da965855eee78106649713076f049649d5ecfaeab77c6644db843b"),
    Linux(:aarch64, libc=:musl) => (url("aarch64-linux-musl"), "bc7824a631efb8aad17b2de2dadecdecfec52d122ed4e452a55af088bd596708"),
    Linux(:armv7l, libc=:glibc, call_abi=:eabihf) => (url("armv7l-linux-gnueabihf"), "1414a8e20f30ca3a26c54abec65465040e7080e5bc9343b1d8330e00f53e7643"),
    Linux(:armv7l, libc=:musl, call_abi=:eabihf) => (url("armv7l-linux-musleabihf"), "3ee878ae6a8b531705002d28c3ccc5b8441cab690255a3d9cf248ea0323e1697"),
    Linux(:i686, libc=:glibc) => (url("i686-linux-gnu"), "3431cbe6205f7ba45d0553948e3d8219416ce3015427fcfc4385b529e5d796e9"),
    Linux(:i686, libc=:musl) => (url("i686-linux-musl"), "2feecc5ee273035e4438ef1625efdde14ca5f5e0ad07cc10d0b9bef7ad94ed61"),
    Windows(:i686) => (url("i686-w64-mingw32"), "e600cccdb13a89624c968279e4bdb669111b0affa747ebfd891718cc499ee312"),
    Linux(:powerpc64le, libc=:glibc) => (url("powerpc64le-linux-gnu"), "98d6bb7bbab35b2d2a469648a637b13e3a74e0e518158aec5d3e8228b88cf776"),
    MacOS(:x86_64) => (url("x86_64-apple-darwin"), "a93bd2b54d660e86c67424880799a5bba08242c74f0c5ff8fc65e0ee4fc05523"),
    Linux(:x86_64, libc=:glibc) => (url("x86_64-linux-gnu"), "9546e6f1cda137b2e7a7d9128fc2e137ddd646cc31896fe080b8c8046ad599c7"),
    Linux(:x86_64, libc=:musl) => (url("x86_64-linux-musl"), "1802c7759575c296f276ef39ef729e36c2751459a52783f26ee84f9afa972a52"),
    FreeBSD(:x86_64) => (url("x86_64-unknown-freebsd"), "a2b28c174401978078927d6d534ab4d90004dcf546f86bc3952291449579272e"),
    Windows(:x86_64) => (url("x86_64-w64-mingw32"), "f55d5ddb60fcdae7c2502febb2770e7854e4c9aea6fb8cd67b77caad6b26eb29"),
)

this_platform = platform_key_abi()

custom_library = false
if haskey(ENV,"JULIA_SCS_LIBRARY_PATH")

    names_symbols = Dict("libscsdir"=>:direct, "libscsindir"=>:indirect, "libscsgpuindir"=>:gpuindirect)

    scs_prefix = ENV["JULIA_SCS_LIBRARY_PATH"]
    @assert isdir(scs_prefix)

    custom_products = Product[]
    @info "looking for scs libs in $scs_prefix"
    for fn in readdir(scs_prefix)
        if endswith(fn, Libdl.dlext) && haskey(names_symbols,first(split(fn, '.')))
            lib = first(split(fn, '.'))
            @info "found scs library: $lib"
            push!(custom_products,
                LibraryProduct(scs_prefix, [lib], names_symbols[lib]))
        end
    end

    if all(satisfied(p; verbose=verbose) for p in custom_products)
        products = custom_products
        custom_library = true
    else
        error("Could not install custom libraries from $(ENV["JULIA_SCS_LIBRARY_PATH"]).\nTo fall back to BinaryProvider call delete!(ENV,\"JULIA_SCS_LIBRARY_PATH\") and run build again.")
    end
end

if !custom_library
    # Install unsatisfied or updated dependencies:
    unsatisfied = any(!satisfied(p; verbose=verbose) for p in products)

    dl_info = choose_download(download_info, this_platform)
    if dl_info === nothing && unsatisfied
        # If we don't have a compatible .tar.gz to download, complain.
        # Alternatively, you could attempt to install from a separate provider,
        # build from source or something even more ambitious here.
        error("Your platform (\"$(Sys.MACHINE)\", parsed as \"$(triplet(platform_key_abi()))\") is not supported by this package!")
    end

    # If we have a download, and we are unsatisfied (or the version we're
    # trying to install is not itself installed) then load it up!
    if unsatisfied || !isinstalled(dl_info...; prefix=prefix)
        # Download and install binaries
        install(dl_info...; prefix=prefix, force=true, verbose=verbose)
    end
end

# Write out a deps.jl file that will contain mappings for our products
write_deps_file(joinpath(@__DIR__, "deps.jl"), products, verbose=verbose)


text:
using ValidatedNumerics
using .DynamicDefinition, .PwDynamicDefinition
using .Contractors

using .DynamicDefinition: derivative

"""
Reimplementation of Mod1Dynamic as a PwMap instance.
We assume that f is monotonic and differentiable, for now (this is not restrictive, for our purposes)
"""
function mod1_dynamic(f::Function, X = (0.,1.), ε = 0.0)
    br = Branch(f, X)

    # check monotonicity
    fprime = x -> derivative(f, x)
    @assert minimise(x -> fprime(x) * (br.increasing ? 1 : -1), hull(Interval.(X)...))[1] > 0

    Yhull = hull(Interval.(br.Y)...)
    possible_integer_parts = floor(Int, Yhull.lo):ceil(Int, Yhull.hi)

    x, integer_parts = preimages(possible_integer_parts, br, possible_integer_parts)

    ep = [x; X[end]]
    Ts = [x->f(x)-k for k in integer_parts]

    n = length(x)
    if br.increasing
        y_endpoints::Matrix{Interval{Float64}} = hcat(fill(0., n), fill(1., n))
    else
        y_endpoints = hcat(fill(1., n), fill(0., n))
    end
    y_endpoints[1, 1] = br.Y[begin] - integer_parts[begin]
    if y_endpoints[1, 1] == 0.
        y_endpoints[1, 1] = 0. # hack to get rid of -0..0 intervals
    end
    y_endpoints[end, end] = br.Y[end] - integer_parts[end]
    if y_endpoints[end, end] == 0.
        y_endpoints[end, end] = 0. # hack to get rid of -0..0 intervals
    end

    # if !isthin(floor(T0))
    #     @error "T(I.lo) does not have a unique integer part; we did not implement this more complicated case"
    # end

    # first_branch_integer_part = floor(T0).lo
    # if isinteger(T0) && orientation < 0
    #     first_branch_integer_part -= 1
    # end

    # last_branch_integer_part = floor(T1).hi
    # if isinteger(T1) && orientation > 0
    #     last_branch_integer_part -= 1
    # end

    # if orientation > 0
    #     Ts = [x->T(x)-k for k in first_branch_integer_part:last_branch_integer_part]
    #     endpoints = [Interval(domain.lo); [preimage(k, T, domain, ε) for k in first_branch_integer_part+1:last_branch_integer_part]; Interval(domain.hi)]
    #     if length(Ts) == 1
    #         y_endpoints = [(isinteger(T0) ? 0 : T0-floor(T0), isinteger(T1) ? 1 : T1-floor(T1))]
    #     else
    #         y_endpoints = [(isinteger(T0) ? 0 : T0-floor(T0)) , 1; fill((0,1), length(Ts)-2); (0, isinteger(T1) ? 1 : T1-floor(T1))]
    #     end
    # else
    #     Ts = [x->T(x)-k for k in first_branch_integer_part:-1:last_branch_integer_part]
    #     endpoints = [Interval(domain.lo); [preimage(k, T, domain, ε) for k in first_branch_integer_part:-1:last_branch_integer_part+1]; Interval(domain.hi)]
    #     if length(Ts) == 1
    #         y_endpoints = [(isinteger(T0) ? 1 : T0-floor(T0), isinteger(T1) ? 0 : T1-floor(T1))]
    #     else
    #         y_endpoints = [(isinteger(T0) ? 1 : T0-floor(T0), 0); fill((1,0), length(Ts)-2); (1, isinteger(T1) ? 0 : T1-floor(T1))]
    #     end
    # end
    return PwMap(Ts, ep, y_endpoints, fill(br.increasing, length(Ts)))
end


text:
#
# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher
# Licensed under the MIT license. See LICENSE file in the project root for details.
#

# What is included in this file:
# - fmi2xxx-structs and -functions from the FMI2-specification
# - helper-structs that are not part of the FMI2-specification, but help to parse the model description nicely (e.g. `fmi2ModelDescriptionDefaultExperiment`, ...)

"""
Source: FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions

FMI2 Data Types
To simplify porting, no C types are used in the function interfaces, but the alias types are defined in this section.
All definitions in this section are provided in the header file “fmi2TypesPlatform.h”.
"""
const fmi2Char = Cuchar
const fmi2String = Ptr{fmi2Char}
const fmi2Boolean = Cint
const fmi2Real = Creal      # defined in FMICore.jl
const fmi2Integer = Cint
const fmi2Byte = Char
const fmi2ValueReference = Cuint
const fmi2FMUstate = Ptr{Cvoid}
const fmi2Component = Ptr{Cvoid}
const fmi2ComponentEnvironment = Ptr{Cvoid}
const fmi2Enum = Array{Array{String}} # TODO: correct it

"""
Source: FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions

Status returned by functions. The status has the following meaning:
fmi2OK – all well
fmi2Warning – things are not quite right, but the computation can continue. Function “logger” was called in the model (see below), and it is expected that this function has shown the prepared information message to the user.
fmi2Discard – this return status is only possible if explicitly defined for the corresponding function
(ModelExchange: fmi2SetReal, fmi2SetInteger, fmi2SetBoolean, fmi2SetString, fmi2SetContinuousStates, fmi2GetReal, fmi2GetDerivatives, fmi2GetContinuousStates, fmi2GetEventIndicators;
CoSimulation: fmi2SetReal, fmi2SetInteger, fmi2SetBoolean, fmi2SetString, fmi2DoStep, fmiGetXXXStatus):
For “model exchange”: It is recommended to perform a smaller step size and evaluate the model equations again, for example because an iterative solver in the model did not converge or because a function is outside of its domain (for example sqrt(<negative number>)). If this is not possible, the simulation has to be terminated.
For “co-simulation”: fmi2Discard is returned also if the slave is not able to return the required status information. The master has to decide if the simulation run can be continued. In both cases, function “logger” was called in the FMU (see below) and it is expected that this function has shown the prepared information message to the user if the FMU was called in debug mode (loggingOn = fmi2True). Otherwise, “logger” should not show a message.
fmi2Error – the FMU encountered an error. The simulation cannot be continued with this FMU instance. If one of the functions returns fmi2Error, it can be tried to restart the simulation from a formerly stored FMU state by calling fmi2SetFMUstate.
This can be done if the capability flag canGetAndSetFMUstate is true and fmi2GetFMUstate was called before in non-erroneous state. If not, the simulation cannot be continued and fmi2FreeInstance or fmi2Reset must be called afterwards.4 Further processing is possible after this call; especially other FMU instances are not affected. Function “logger” was called in the FMU (see below), and it is expected that this function has shown the prepared information message to the user.
fmi2Fatal – the model computations are irreparably corrupted for all FMU instances. [For example, due to a run-time exception such as access violation or integer division by zero during the execution of an fmi function]. Function “logger” was called in the FMU (see below), and it is expected that this function has shown the prepared information message to the user. It is not possible to call any other function for any of the FMU instances.
fmi2Pending – this status is returned only from the co-simulation interface, if the slave executes the function in an asynchronous way. That means the slave starts to compute but returns immediately. The master has to call fmi2GetStatus(..., fmi2DoStepStatus) to determine if the slave has finished the computation. Can be returned only by fmi2DoStep and by fmi2GetStatus (see section 4.2.3).
"""
const fmi2Status = Cuint
const fmi2StatusOK      = Cuint(0)
const fmi2StatusWarning = Cuint(1)
const fmi2StatusDiscard = Cuint(2)
const fmi2StatusError   = Cuint(3)
const fmi2StatusFatal   = Cuint(4)
const fmi2StatusPending = Cuint(5)

"""
Source: FMISpec2.0.2[p.19-22]: 2.1.5 Creation, Destruction and Logging of FMU Instances

The struct contains pointers to functions provided by the environment to be used by the FMU. It is not allowed to change these functions between fmi2Instantiate(..) and fmi2Terminate(..) calls. Additionally, a pointer to the environment is provided (componentEnvironment) that needs to be passed to the “logger” function, in order that the logger function can utilize data from the environment, such as mapping a valueReference to a string. In the unlikely case that fmi2Component is also needed in the logger, it has to be passed via argument componentEnvironment. Argument componentEnvironment may be a null pointer. The componentEnvironment pointer is also passed to the stepFinished(..) function in order that the environment can provide an efficient way to identify the slave that called stepFinished(..).
"""
mutable struct fmi2CallbackFunctions
    logger::Ptr{Cvoid}
    allocateMemory::Ptr{Cvoid}
    freeMemory::Ptr{Cvoid}
    stepFinished::Ptr{Cvoid}
    componentEnvironment::Ptr{Cvoid}
end

"""
A not further specified annotation struct.
"""
mutable struct fmi2Annotation
    # No implementation
end

"""
Source: FMISpec2.0.2[p.48]: 2.2.7 Definition of Model Variables (ModelVariables)

Enumeration that defines the causality of the variable. Allowed values of this enumeration:

"parameter": Independent parameter (a data value that is constant during the simulation and is provided by the environment and cannot be used in connections). variability must be "fixed" or "tunable". initial must be exact or not present (meaning exact).
"calculatedParameter": A data value that is constant during the simulation and is computed during initialization or when tunable parameters change. variability must be "fixed" or "tunable". initial must be "approx", "calculated" or not present (meaning calculated).
"input": The variable value can be provided from another model or slave. It is not allowed to define initial.
"output": The variable value can be used by another model or slave. The algebraic relationship to the inputs is defined via the dependencies attribute of <fmiModelDescription><ModelStructure><Outputs><Unknown>.
"local": Local variable that is calculated from other variables or is a continuous-time state (see section 2.2.8). It is not allowed to use the variable value in another model or slave.
"independent": The independent variable (usually “time”). All variables are a function of this independent variable. variability must be "continuous". At most one ScalarVariable of an FMU can be defined as "independent". If no variable is defined as "independent", it is implicitly present with name = "time" and unit = "s". If one variable is defined as "independent", it must be defined as "Real" without a "start" attribute. It is not allowed to call function fmi2SetReal on an "independent" variable. Instead, its value is initialized with fmi2SetupExperiment and after initialization set by fmi2SetTime for ModelExchange and by arguments currentCommunicationPoint and communicationStepSize of fmi2DoStep for CoSimulation. [The actual value can be inquired with fmi2GetReal.]
The default of causality is “local”. A continuous-time state must have causality = "local" or "output", see also section 2.2.8.
[causality = "calculatedParameter" and causality = "local" with variability = "fixed" or "tunable" are similar. The difference is that a calculatedParameter can be used in another model or slave, whereas a local variable cannot. For example, when importing an FMU in a Modelica environment, a "calculatedParameter" should be imported in a public section as final parameter, whereas a "local" variable should be imported in a protected section of the model.]
Added prefix "fmi2" to help with redefinition of constans in enums.
"""
const fmi2Causality = Cuint
const fmi2CausalityParameter              = Cuint(0)
const fmi2CausalityCalculatedParameter    = Cuint(1)
const fmi2CausalityInput                  = Cuint(2)
const fmi2CausalityOutput                 = Cuint(3)
const fmi2CausalityLocal                  = Cuint(4)
const fmi2CausalityIndependent            = Cuint(5)

"""
Source: FMISpec2.0.2[p.49]: 2.2.7 Definition of Model Variables (ModelVariables)

Enumeration that defines the time dependency of the variable, in other words, it defines the time instants when a variable can change its value.

"constant": The value of the variable never changes.
"fixed": The value of the variable is fixed after initialization, in other words, after fmi2ExitInitializationMode was called the variable value does not change anymore.
"tunable": The value of the variable is constant between external events (ModelExchange) and between Communication Points (Co-Simulation) due to changing variables with causality = "parameter" or "input" and variability = "tunable". Whenever a parameter or input signal with variability = "tunable" changes, an event is triggered externally (ModelExchange), or the change is performed at the next Communication Point (Co-Simulation) and the variables with variability = "tunable" and causality = "calculatedParameter" or "output" must be newly computed.
"discrete": ModelExchange: The value of the variable is constant between external and internal events (= time, state, step events defined implicitly in the FMU). Co-Simulation: By convention, the variable is from a “real” sampled data system and its value is only changed at Communication Points (also inside the slave).
"continuous": Only a variable of type = “Real” can be “continuous”. ModelExchange: No restrictions on value changes. Co-Simulation: By convention, the variable is from a differential
The default is “continuous”.
Added prefix "fmi2" to help with redefinition of constans in enums.
"""
const fmi2Variability = Cuint
const fmi2VariabilityConstant   = Cuint(0)
const fmi2VariabilityFixed      = Cuint(1)
const fmi2VariabilityTunable    = Cuint(2)
const fmi2VariabilityDiscrete   = Cuint(3)
const fmi2VariabilityContinuous = Cuint(4)

"""
Source: FMISpec2.0.2[p.48]: 2.2.7 Definition of Model Variables (ModelVariables)

Enumeration that defines how the variable is initialized. It is not allowed to provide a value for initial if causality = "input" or "independent":

"exact": The variable is initialized with the start value (provided under Real, Integer, Boolean, String or Enumeration).
"approx": The variable is an iteration variable of an algebraic loop and the iteration at initialization starts with the start value.
"calculated": The variable is calculated from other variables during initialization. It is not allowed to provide a “start” value.
If initial is not present, it is defined by the table below based on causality and variability. If initial = exact or approx, or causality = ″input″, a start value must be provided. If initial = calculated, or causality = ″independent″, it is not allowed to provide a start value.
If fmiSetXXX is not called on a variable with causality = ″input″, then the FMU must use the start value as value of this input.
Added prefix "fmi2" to help with redefinition of constans in enums.
"""
const fmi2Initial = Cuint
const fmi2InitialExact      = Cuint(0)
const fmi2InitialApprox     = Cuint(1)
const fmi2InitialCalculated = Cuint(2)

"""
Source: FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions

To simplify porting, no C types are used in the function interfaces, but the alias types are defined in this section.
All definitions in this section are provided in the header file “fmi2TypesPlatform.h”.
"""
const fmi2True = fmi2Boolean(true)
const fmi2False = fmi2Boolean(false)

"""
Source: FMISpec2.0.2[p.19]: 2.1.5 Creation, Destruction and Logging of FMU Instances

Argument fmuType defines the type of the FMU:
- fmi2ModelExchange: FMU with initialization and events; between events simulation of continuous systems is performed with external integrators from the environment.
- fmi2CoSimulation: Black box interface for co-simulation.
"""
const fmi2Type = Cuint
const fmi2TypeModelExchange = Cuint(0)
const fmi2TypeCoSimulation  = Cuint(1)

# Custom helper, not part of the FMI-Spec.
mutable struct fmi2ModelDescriptionReal
    # mandatory
    # (nothing)

    # optional
    declaredType::Union{String, Nothing}
    quantity::Union{String, Nothing}
    unit::Union{String, Nothing}
    displayUnit::Union{String, Nothing}
    relativeQuantity::Union{Bool, Nothing}
    min::Union{Real, Nothing}
    max::Union{Real, Nothing}
    nominal::Union{Real, Nothing}
    unbounded::Union{Bool, Nothing}
    start::Union{Real, Nothing}
    derivative::Union{UInt, Nothing}

    # constructor
    function fmi2ModelDescriptionReal()
        inst = new()

        inst.start = nothing
        inst.derivative = nothing
        inst.quantity = nothing
        inst.unit = nothing
        inst.displayUnit = nothing
        inst.relativeQuantity = nothing
        inst.min = nothing
        inst.max = nothing
        inst.nominal = nothing
        inst.unbounded = nothing
        inst.start = nothing
        inst.derivative = nothing

        return inst
    end
end

# Custom helper, not part of the FMI-Spec.
mutable struct fmi2ModelDescriptionInteger
    # optional
    start::Union{fmi2Integer, Nothing}
    declaredType::Union{String, Nothing}
    # ToDo: remaining attributes

    # constructor
    function fmi2ModelDescriptionInteger()
        inst = new()
        inst.start = nothing
        return inst
    end
end

# Custom helper, not part of the FMI-Spec.
mutable struct fmi2ModelDescriptionBoolean
    # optional
    start::Union{fmi2Boolean, Nothing}
    declaredType::Union{String, Nothing}
    # ToDo: remaining attributes

    # constructor
    function fmi2ModelDescriptionBoolean()
        inst = new()
        inst.start = nothing
        return inst
    end
end

# Custom helper, not part of the FMI-Spec.
mutable struct fmi2ModelDescriptionString
    # optional
    start::Union{String, Nothing}
    declaredType::Union{String, Nothing}
    # ToDo: remaining attributes

    # constructor
    function fmi2ModelDescriptionString()
        inst = new()
        inst.start = nothing
        return inst
    end
end

# Custom helper, not part of the FMI-Spec.
mutable struct fmi2ModelDescriptionEnumeration
    # mandatory
    declaredType::Union{String, Nothing}

    # optional
    start::Union{fmi2Enum, Nothing}
    # ToDo: remaining attributes

    # constructor
    function fmi2ModelDescriptionEnumeration()
        inst = new()
        inst.start = nothing
        return inst
    end
end

"""
Source: FMISpec2.0.2[p.46]: 2.2.7 Definition of Model Variables (ModelVariables)

The fmi2ScalarVariable specifies the type and argument of every exposed variable in the fmu
"""
mutable struct fmi2ScalarVariable
    # attributes (mandatory)
    name::String
    valueReference::fmi2ValueReference

    # attributes (optional)
    description::Union{String, Nothing}
    causality::Union{fmi2Causality, Nothing}
    variability::Union{fmi2Variability, Nothing}
    initial::Union{fmi2Initial, Nothing}
    canHandleMultipleSetPerTimeInstant::Union{fmi2Boolean, Nothing}
    annotations::Union{fmi2Annotation, Nothing}

    _Real::Union{fmi2ModelDescriptionReal, Nothing}
    _Integer::Union{fmi2ModelDescriptionInteger, Nothing}
    _Boolean::Union{fmi2ModelDescriptionBoolean, Nothing}
    _String::Union{fmi2ModelDescriptionString, Nothing}
    _Enumeration::Union{fmi2ModelDescriptionEnumeration, Nothing}

    # Constructor for not further specified ScalarVariables
    function fmi2ScalarVariable(name::String, valueReference::fmi2ValueReference)
        inst = new()
        inst.name = name
        inst.valueReference = valueReference
        inst.description = nothing  # ""
        inst.causality = nothing    # fmi2CausalityLocal
        inst.variability = nothing  # fmi2VariabilityContinuous
        inst.initial = nothing      # fmi2InitialCalculated
        inst.canHandleMultipleSetPerTimeInstant = nothing
        inst.annotations = nothing

        inst._Real = nothing
        inst._Integer = nothing
        inst._Boolean = nothing
        inst._String = nothing
        inst._Enumeration = nothing

        return inst
    end
end

"""
Overload the Base.show() function for custom printing of the fmi2ScalarVariable.
"""
Base.show(io::IO, var::fmi2ScalarVariable) = print(io,
"Name: '$(var.name)' (reference: $(var.valueReference))")

"""
Source: FMISpec2.0.2[p.106]: 4.2.3 Retrieving Status Information from the Slave

CoSimulation specific Enum representing state of fmu after fmi2DoStep returned fmi2Pending.
"""
const fmi2StatusKind = Cuint
const fmi2StatusKindDoStepStatus        = Cuint(0)
const fmi2StatusKindPendingStatus       = Cuint(1)
const fmi2StatusKindLastSuccessfulTime  = Cuint(2)
const fmi2StatusKindTerminated          = Cuint(3)

"""
Source: FMISpec2.0.2[p.84]: 3.2.2 Evaluation of Model Equations

If return argument fmi2eventInfo->newDiscreteStatesNeeded = fmi2True, the FMU should stay in Event Mode, and the FMU requires to set new inputs to the FMU (fmi2SetXXX on inputs) to compute and get the outputs (fmi2GetXXX on outputs) and to call fmi2NewDiscreteStates again. Depending on the connection with other FMUs, the environment shall
- call fmi2Terminate, if terminateSimulation = fmi2True is returned by at least one FMU.
- call fmi2EnterContinuousTimeMode if all FMUs return newDiscreteStatesNeeded = fmi2False.
- stay in Event Mode otherwise.
When the FMU is terminated, it is assumed that an appropriate message is printed by the logger function (see section 2.1.5) to explain the reason for the termination.
If nominalsOfContinuousStatesChanged = fmi2True, then the nominal values of the states have changed due to the function call and can be inquired with fmi2GetNominalsOfContinuousStates.
If valuesOfContinuousStatesChanged = fmi2True. then at least one element of the continuous state vector has changed its value due to the function call. The new values of the states can be retrieved with fmi2GetContinuousStates or individually for each state for which reinit = "true" by calling getReal. If no element of the continuous state vector has changed its value, valuesOfContinuousStatesChanged must return fmi2False. [If fmi2True would be returned in this case, an infinite event loop may occur.]
If nextEventTimeDefined = fmi2True, then the simulation shall integrate at most until time = nextEventTime, and shall call fmi2EnterEventMode at this time instant. If integration is stopped before nextEventTime, for example, due to a state event, the definition of nextEventTime becomes obsolete.
"""
mutable struct fmi2EventInfo
    newDiscreteStatesNeeded::fmi2Boolean
    terminateSimulation::fmi2Boolean
    nominalsOfContinuousStatesChanged::fmi2Boolean
    valuesOfContinuousStatesChanged::fmi2Boolean
    nextEventTimeDefined::fmi2Boolean
    nextEventTime::fmi2Real

    # constructor
    function fmi2EventInfo()
        inst = new()
        inst.newDiscreteStatesNeeded = fmi2False
        inst.terminateSimulation = fmi2False
        inst.nominalsOfContinuousStatesChanged = fmi2False
        inst.valuesOfContinuousStatesChanged = fmi2False
        inst.nextEventTimeDefined = fmi2False
        inst.nextEventTime = 0.0
        return inst
    end
end

"""
ToDo
"""
mutable struct fmi2Unit
    # ToDo
end

"""
ToDo
"""
mutable struct fmi2SimpleType
    # ToDo
end

# Custom helper, not part of the FMI-Spec.
const fmi2DependencyKind            = Cuint
const fmi2DependencyKindDependent   = Cuint(0)
const fmi2DependencyKindConstant    = Cuint(1)
const fmi2DependencyKindFixed       = Cuint(2)
const fmi2DependencyKindTunable     = Cuint(3)
const fmi2DependencyKindDiscrete    = Cuint(4)

# Custom helper, not part of the FMI-Spec.
const fmi2VariableNamingConvention              = Cuint
const fmi2VariableNamingConventionFlat          = Cuint(0)
const fmi2VariableNamingConventionStructured    = Cuint(1)

"""
ToDo
"""
mutable struct fmi2VariableDependency
    # mandatory
    index::UInt

    # optional
    dependencies::Union{Array{UInt, 1}, Nothing}
    dependenciesKind::Union{Array{fmi2DependencyKind, 1}, Nothing}

    # Constructor
    function fmi2VariableDependency(index)
        inst = new()
        inst.index = index
        inst.dependencies = nothing
        inst.dependenciesKind = nothing
        return inst
    end
end

# Custom helper, not part of the FMI-Spec.
mutable struct fmi2ModelDescriptionDefaultExperiment
    startTime::Union{Real,Nothing}
    stopTime::Union{Real,Nothing}
    tolerance::Union{Real,Nothing}
    stepSize::Union{Real,Nothing}

    # Constructor
    function fmi2ModelDescriptionDefaultExperiment()
        inst = new()
        inst.startTime = nothing
        inst.stopTime = nothing
        inst.tolerance = nothing
        inst.stepSize = nothing
        return inst
    end
end

# Custom helper, not part of the FMI-Spec.
fmi2Unknown = fmi2VariableDependency

# Custom helper, not part of the FMI-Spec.
mutable struct fmi2ModelDescriptionModelStructure
    outputs::Union{Array{fmi2VariableDependency, 1}, Nothing}
    derivatives::Union{Array{fmi2VariableDependency, 1}, Nothing}
    initialUnknowns::Union{Array{fmi2Unknown, 1}, Nothing}

    # Constructor
    function fmi2ModelDescriptionModelStructure()
        inst = new()
        inst.outputs = nothing
        inst.derivatives = nothing
        inst.initialUnknowns = nothing
        return inst
    end
end

# Custom helper, not part of the FMI-Spec.
mutable struct fmi2ModelDescriptionModelExchange
    # mandatory
    modelIdentifier::String

    # optional
    canGetAndSetFMUstate::Union{Bool, Nothing}
    canSerializeFMUstate::Union{Bool, Nothing}
    providesDirectionalDerivative::Union{Bool, Nothing}

    # ToDo: Further attributes 3.3.1

    # constructor
    function fmi2ModelDescriptionModelExchange()
        inst = new()
        return inst
    end

    function fmi2ModelDescriptionModelExchange(modelIdentifier::String)
        inst = fmi2ModelDescriptionModelExchange()
        inst.modelIdentifier = modelIdentifier
        return inst
    end
end

# Custom helper, not part of the FMI-Spec.
mutable struct fmi2ModelDescriptionCoSimulation
    # mandatory
    modelIdentifier::String

    # optional
    canHandleVariableCommunicationStepSize::Union{Bool, Nothing}
    canInterpolateInputs::Union{Bool, Nothing}
    maxOutputDerivativeOrder::Union{UInt, Nothing}
    canGetAndSetFMUstate::Union{Bool, Nothing}
    canSerializeFMUstate::Union{Bool, Nothing}
    providesDirectionalDerivative::Union{Bool, Nothing}

    # ToDo: Further attributes 4.3.1

    # constructor
    function fmi2ModelDescriptionCoSimulation()
        inst = new()
        return inst
    end

    function fmi2ModelDescriptionCoSimulation(modelIdentifier::String)
        inst = fmi2ModelDescriptionCoSimulation()
        inst.modelIdentifier = modelIdentifier
        return inst
    end
end

"""
Source: FMISpec2.0.2[p.34]: 2.2.1 Definition of an FMU (fmiModelDescription)

The “ModelVariables” element of fmiModelDescription is the central part of the model description. It provides the static information of all exposed variables.
"""
mutable struct fmi2ModelDescription
    # attributes (mandatory)
    fmiVersion::String
    modelName::String
    guid # String gor Base.UUID

    # attributes (optional)
    description::Union{String, Nothing}
    author::Union{String, Nothing}
    version::Union{String, Nothing}
    copyright::Union{String, Nothing}
    license::Union{String, Nothing}
    generationTool::Union{String, Nothing}
    generationDateAndTime # DateTime
    variableNamingConvention::Union{fmi2VariableNamingConvention, Nothing}
    numberOfEventIndicators::Union{UInt, Nothing}

    unitDefinitions::Array{fmi2Unit, 1}
    typeDefinitions::Array{fmi2SimpleType, 1}
    logCategories::Array # ToDo: Array type

    defaultExperiment::Union{fmi2ModelDescriptionDefaultExperiment, Nothing}

    vendorAnnotations::Array # ToDo: Array type
    modelVariables::Array{fmi2ScalarVariable, 1}
    modelStructure::fmi2ModelDescriptionModelStructure

    modelExchange::Union{fmi2ModelDescriptionModelExchange, Nothing}
    coSimulation::Union{fmi2ModelDescriptionCoSimulation, Nothing}

    # additionals
    valueReferences::Array{fmi2ValueReference}
    inputValueReferences::Array{fmi2ValueReference}
    outputValueReferences::Array{fmi2ValueReference}
    stateValueReferences::Array{fmi2ValueReference}
    derivativeValueReferences::Array{fmi2ValueReference}
    parameterValueReferences::Array{fmi2ValueReference}

    stringValueReferences::Dict{String, fmi2ValueReference}     # String-ValueReference pairs of MD

    # ToDo: from here on refactoring is needed

    enumerations::fmi2Enum

    # additional fields (non-FMI-specific)
    valueReferenceIndicies::Dict{UInt, UInt}

    # Constructor for uninitialized struct
    function fmi2ModelDescription()
        inst = new()
        inst.fmiVersion = ""
        inst.modelName = ""
        inst.guid = ""

        inst.modelExchange = nothing
        inst.coSimulation = nothing
        inst.defaultExperiment = nothing

        inst.modelVariables = Array{fmi2ScalarVariable, 1}()
        inst.modelStructure = fmi2ModelDescriptionModelStructure()
        inst.numberOfEventIndicators = nothing
        inst.enumerations = []

        inst.valueReferences = []
        inst.inputValueReferences = []
        inst.outputValueReferences = []
        inst.stateValueReferences = []
        inst.derivativeValueReferences = []
        inst.parameterValueReferences = []

        return inst
    end
end

"""
Overload the Base.show() function for custom printing of the fmi2ModelDescription.
"""
Base.show(io::IO, desc::fmi2ModelDescription) = print(io,
"Model name:      $(desc.modelName)
FMI version:     $(desc.fmiVersion)
GUID:            $(desc.guid)
Description:     $(desc.description)
Model variables: [$(length(desc.modelVariables))]"
)

### FUNCTIONS ###

"""
Source: FMISpec2.0.2[p.19]: 2.1.5 Creation, Destruction and Logging of FMU Instances

The function returns a new instance of an FMU.
"""
function fmi2Instantiate(cfunc::Ptr{Nothing},
                         instanceName::fmi2String,
                         fmuType::fmi2Type,
                         fmuGUID::fmi2String,
                         fmuResourceLocation::fmi2String,
                         functions::Ptr{fmi2CallbackFunctions},
                         visible::fmi2Boolean,
                         loggingOn::fmi2Boolean)

    ccall(cfunc,
          Ptr{Cvoid},
          (fmi2String, fmi2Type, fmi2String, fmi2String, Ptr{Cvoid}, fmi2Boolean, fmi2Boolean),
          instanceName, fmuType, fmuGUID, fmuResourceLocation, functions, visible, loggingOn)
end

"""
Source: FMISpec2.0.2[p.22]: 2.1.5 Creation, Destruction and Logging of FMU Instances

Disposes the given instance, unloads the loaded model, and frees all the allocated memory and other resources that have been allocated by the functions of the FMU interface.
If a null pointer is provided for “c”, the function call is ignored (does not have an effect).

Removes the component from the FMUs component list.
"""
function fmi2FreeInstance!(cfunc::Ptr{Nothing}, c::fmi2Component)

    ccall(cfunc, Cvoid, (fmi2Component,), c)

    nothing
end

"""
Source: FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files

Returns the string to uniquely identify the “fmi2TypesPlatform.h” header file used for compilation of the functions of the FMU.
The standard header file, as documented in this specification, has fmi2TypesPlatform set to “default” (so this function usually returns “default”).
"""
function fmi2GetTypesPlatform(cfunc::Ptr{Nothing})
    ccall(cfunc, fmi2String, ())
end

"""
Source: FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files

Returns the version of the “fmi2Functions.h” header file which was used to compile the functions of the FMU. The function returns “fmiVersion” which is defined in this header file. The standard header file as documented in this specification has version “2.0”
"""
function fmi2GetVersion(cfunc::Ptr{Nothing})
    ccall(cfunc, fmi2String, ())
end

"""
Source: FMISpec2.0.2[p.22]: 2.1.5 Creation, Destruction and Logging of FMU Instances

The function controls debug logging that is output via the logger function callback. If loggingOn = fmi2True, debug logging is enabled, otherwise it is switched off.
"""
function fmi2SetDebugLogging(cfunc::Ptr{Nothing}, c::fmi2Component, logginOn::fmi2Boolean, nCategories::Csize_t, categories::Union{Ptr{fmi2String}, AbstractArray{fmi2String}})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2Component, Csize_t, Ptr{fmi2String}),
          c, logginOn, nCategories, categories)
end

"""
Source: FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU

Informs the FMU to setup the experiment. This function must be called after fmi2Instantiate and before fmi2EnterInitializationMode is called.The function controls debug logging that is output via the logger function callback. If loggingOn = fmi2True, debug logging is enabled, otherwise it is switched off.
"""
function fmi2SetupExperiment(cfunc::Ptr{Nothing},
                             c::fmi2Component,
                             toleranceDefined::fmi2Boolean,
                             tolerance::fmi2Real,
                             startTime::fmi2Real,
                             stopTimeDefined::fmi2Boolean,
                             stopTime::fmi2Real)

    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2Boolean, fmi2Real, fmi2Real, fmi2Boolean, fmi2Real),
          c, toleranceDefined, tolerance, startTime, stopTimeDefined, stopTime)
end

"""
Source: FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU

Informs the FMU to enter Initialization Mode. Before calling this function, all variables with attribute <ScalarVariable initial = "exact" or "approx"> can be set with the “fmi2SetXXX” functions (the ScalarVariable attributes are defined in the Model Description File, see section 2.2.7). Setting other variables is not allowed. Furthermore, fmi2SetupExperiment must be called at least once before calling fmi2EnterInitializationMode, in order that startTime is defined.
"""
function fmi2EnterInitializationMode(cfunc::Ptr{Nothing}, c::fmi2Component)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component,),
          c)
end

"""
Source: FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU

Informs the FMU to exit Initialization Mode.
"""
function fmi2ExitInitializationMode(cfunc::Ptr{Nothing}, c::fmi2Component)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component,),
          c)
end

"""
Source: FMISpec2.0.2[p.24]: 2.1.6 Initialization, Termination, and Resetting an FMU

Informs the FMU that the simulation run is terminated.
"""
function fmi2Terminate(cfunc::Ptr{Nothing}, c::fmi2Component)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component,),
          c)
end

"""
Source: FMISpec2.0.2[p.24]: 2.1.6 Initialization, Termination, and Resetting an FMU

Is called by the environment to reset the FMU after a simulation run. The FMU goes into the same state as if fmi2Instantiate would have been called.
"""
function fmi2Reset(cfunc::Ptr{Nothing}, c::fmi2Component)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component,),
          c)
end

"""
Source: FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values

Functions to get and set values of variables idetified by their valueReference
"""
function fmi2GetReal!(cfunc::Ptr{Nothing}, c::fmi2Component, vr::Union{AbstractArray{fmi2ValueReference}, Ptr{fmi2ValueReference}}, nvr::Csize_t, value::Union{AbstractArray{fmi2Real}, Ptr{fmi2Real}})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2Real}),
          c, vr, nvr, value)
end

"""
Source: FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values

Functions to get and set values of variables idetified by their valueReference
"""
function fmi2SetReal(cfunc::Ptr{Nothing}, c::fmi2Component, vr::Union{AbstractArray{fmi2ValueReference}, Ptr{fmi2ValueReference}}, nvr::Csize_t, value::Union{AbstractArray{fmi2Real}, Ptr{fmi2Real}})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2Real}),
          c, vr, nvr, value)
end

"""
Source: FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values

Functions to get and set values of variables idetified by their valueReference
"""
function fmi2GetInteger!(cfunc::Ptr{Nothing}, c::fmi2Component, vr::Union{AbstractArray{fmi2ValueReference}, Ptr{fmi2ValueReference}}, nvr::Csize_t, value::Union{AbstractArray{fmi2Integer}, Ptr{fmi2Integer}})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2Integer}),
          c, vr, nvr, value)
end

"""
Source: FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values

Functions to get and set values of variables idetified by their valueReference
"""
function fmi2SetInteger(cfunc::Ptr{Nothing}, c::fmi2Component, vr::Union{AbstractArray{fmi2ValueReference}, Ptr{fmi2ValueReference}}, nvr::Csize_t, value::Union{AbstractArray{fmi2Integer}, Ptr{fmi2Integer}})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2Integer}),
          c, vr, nvr, value)
end

"""
Source: FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values

Functions to get and set values of variables idetified by their valueReference
"""
function fmi2GetBoolean!(cfunc::Ptr{Nothing}, c::fmi2Component, vr::Union{AbstractArray{fmi2ValueReference}, Ptr{fmi2ValueReference}}, nvr::Csize_t, value::Union{AbstractArray{fmi2Boolean}, Ptr{fmi2Boolean}})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2Boolean}),
          c, vr, nvr, value)
end

"""
Source: FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values

Functions to get and set values of variables idetified by their valueReference
"""
function fmi2SetBoolean(cfunc::Ptr{Nothing}, c::fmi2Component, vr::Union{AbstractArray{fmi2ValueReference}, Ptr{fmi2ValueReference}}, nvr::Csize_t, value::Union{AbstractArray{fmi2Boolean}, Ptr{fmi2Boolean}})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2Boolean}),
          c, vr, nvr, value)
end

"""
Source: FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values

Functions to get and set values of variables idetified by their valueReference
"""
function fmi2GetString!(cfunc::Ptr{Nothing}, c::fmi2Component, vr::Union{AbstractArray{fmi2ValueReference}, Ptr{fmi2ValueReference}}, nvr::Csize_t, value::Union{AbstractArray{fmi2String}, Ptr{fmi2String}})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2String}),
          c, vr, nvr, value)
end

"""
Source: FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values

Functions to get and set values of variables idetified by their valueReference
"""
function fmi2SetString(cfunc::Ptr{Nothing}, c::fmi2Component, vr::Union{AbstractArray{fmi2ValueReference}, Ptr{fmi2ValueReference}}, nvr::Csize_t, value::Union{AbstractArray{fmi2String}, Ptr{fmi2String}})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2String}),
          c, vr, nvr, value)
end

"""
Source: FMISpec2.0.2[p.26]: 2.1.8 Getting and Setting the Complete FMU State

fmi2GetFMUstate makes a copy of the internal FMU state and returns a pointer to this copy
"""
function fmi2GetFMUstate!(cfunc::Ptr{Nothing}, c::fmi2Component, FMUstate::Ref{fmi2FMUstate})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2FMUstate}),
          c, FMUstate)
end

"""
Source: FMISpec2.0.2[p.26]: 2.1.8 Getting and Setting the Complete FMU State

fmi2SetFMUstate copies the content of the previously copied FMUstate back and uses it as actual new FMU state.
"""
function fmi2SetFMUstate(cfunc::Ptr{Nothing}, c::fmi2Component, FMUstate::fmi2FMUstate)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2FMUstate),
          c, FMUstate)
end

"""
Source: FMISpec2.0.2[p.26]: 2.1.8 Getting and Setting the Complete FMU State

fmi2FreeFMUstate frees all memory and other resources allocated with the fmi2GetFMUstate call for this FMUstate.
"""
function fmi2FreeFMUstate!(cfunc::Ptr{Nothing}, c::fmi2Component, FMUstate::Ref{fmi2FMUstate})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2FMUstate}),
          c, FMUstate)
end

"""
Source: FMISpec2.0.2[p.26]: 2.1.8 Getting and Setting the Complete FMU State

fmi2SerializedFMUstateSize returns the size of the byte vector, in order that FMUstate can be stored in it.
"""
function fmi2SerializedFMUstateSize!(cfunc::Ptr{Nothing}, c::fmi2Component, FMUstate::fmi2FMUstate, size::Ref{Csize_t})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2FMUstate, Ptr{Csize_t}),
          c, FMUstate, size)
end

"""
Source: FMISpec2.0.2[p.26]: 2.1.8 Getting and Setting the Complete FMU State

fmi2SerializeFMUstate serializes the data which is referenced by pointer FMUstate and copies this data in to the byte vector serializedState of length size
"""
function fmi2SerializeFMUstate!(cfunc::Ptr{Nothing}, c::fmi2Component, FMUstate::fmi2FMUstate, serialzedState::AbstractArray{fmi2Byte}, size::Csize_t)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2FMUstate, Ptr{fmi2Byte}, Csize_t),
          c, FMUstate, serialzedState, size)
end

"""
Source: FMISpec2.0.2[p.26]: 2.1.8 Getting and Setting the Complete FMU State

fmi2DeSerializeFMUstate deserializes the byte vector serializedState of length size, constructs a copy of the FMU state and returns FMUstate, the pointer to this copy.
"""
function fmi2DeSerializeFMUstate!(cfunc::Ptr{Nothing}, c::fmi2Component, serializedState::AbstractArray{fmi2Byte}, size::Csize_t, FMUstate::Ref{fmi2FMUstate})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2Byte}, Csize_t, Ptr{fmi2FMUstate}),
          c, serializedState, size, FMUstate)
end

"""
Source: FMISpec2.0.2[p.26]: 2.1.9 Getting Partial Derivatives

This function computes the directional derivatives of an FMU.

    ΔvUnknown = ∂h / ∂vKnown ⋅ ΔvKnown
"""
function fmi2GetDirectionalDerivative!(cfunc::Ptr{Nothing},
                                       c::fmi2Component,
                                       vUnknown_ref::AbstractArray{fmi2ValueReference},
                                       nUnknown::Csize_t,
                                       vKnown_ref::AbstractArray{fmi2ValueReference},
                                       nKnown::Csize_t,
                                       ΔvKnown::AbstractArray{fmi2Real},
                                       ΔvUnknown::AbstractArray{fmi2Real})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2Real}, Ptr{fmi2Real}),
          c, vUnknown_ref, nUnknown, vKnown_ref, nKnown, ΔvKnown, ΔvUnknown)
end

# Functions specificly for isCoSimulation

"""
Source: FMISpec2.0.2[p.104]: 4.2.1 Transfer of Input / Output Values and Parameters

Sets the n-th time derivative of real input variables.
vr defines the value references of the variables
the array order specifies the corresponding order of derivation of the variables
"""
function fmi2SetRealInputDerivatives(cfunc::Ptr{Nothing}, c::fmi2Component, vr::AbstractArray{fmi2ValueReference}, nvr::Csize_t, order::AbstractArray{fmi2Integer}, value::AbstractArray{fmi2Real})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2Integer}, Ptr{fmi2Real}),
          c, vr, nvr, order, value)
end

"""
Source: FMISpec2.0.2[p.104]: 4.2.1 Transfer of Input / Output Values and Parameters

Retrieves the n-th derivative of output values.
vr defines the value references of the variables
the array order specifies the corresponding order of derivation of the variables
"""
function fmi2GetRealOutputDerivatives!(cfunc::Ptr{Nothing}, c::fmi2Component,  vr::AbstractArray{fmi2ValueReference}, nvr::Csize_t, order::AbstractArray{fmi2Integer}, value::AbstractArray{fmi2Real})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2ValueReference}, Csize_t, Ptr{fmi2Integer}, Ptr{fmi2Real}),
          c, vr, nvr, order, value)
end

"""
Source: FMISpec2.0.2[p.104]: 4.2.2 Computation

The computation of a time step is started.
"""
function fmi2DoStep(cfunc::Ptr{Nothing}, c::fmi2Component, currentCommunicationPoint::fmi2Real, communicationStepSize::fmi2Real, noSetFMUStatePriorToCurrentPoint::fmi2Boolean)
    ccall(cfunc, fmi2Status,
          (fmi2Component, fmi2Real, fmi2Real, fmi2Boolean),
          c, currentCommunicationPoint, communicationStepSize, noSetFMUStatePriorToCurrentPoint)
end

"""
Source: FMISpec2.0.2[p.105]: 4.2.2 Computation

Can be called if fmi2DoStep returned fmi2Pending in order to stop the current asynchronous execution.
"""
function fmi2CancelStep(cfunc::Ptr{Nothing}, c::fmi2Component)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component,),
          c)
end

"""
Source: FMISpec2.0.2[p.106]: 4.2.3 Retrieving Status Information from the Slave

Informs the master about the actual status of the simulation run. Which status information is to be returned is specified by the argument fmi2StatusKind.
"""
function fmi2GetStatus!(cfunc::Ptr{Nothing}, c::fmi2Component, s::fmi2StatusKind, value::Ptr{fmi2Status})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2StatusKind, Ptr{fmi2Status}),
          c, s, value)
end

"""
Source: FMISpec2.0.2[p.106]: 4.2.3 Retrieving Status Information from the Slave

Informs the master about the actual status of the simulation run. Which status information is to be returned is specified by the argument fmi2StatusKind.
"""
function fmi2GetRealStatus!(cfunc::Ptr{Nothing}, c::fmi2Component, s::fmi2StatusKind, value::Ptr{fmi2Real})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2StatusKind, Ptr{fmi2Real}),
          c, s, value)
end

"""
Source: FMISpec2.0.2[p.106]: 4.2.3 Retrieving Status Information from the Slave

Informs the master about the actual status of the simulation run. Which status information is to be returned is specified by the argument fmi2StatusKind.
"""
function fmi2GetIntegerStatus!(cfunc::Ptr{Nothing}, c::fmi2Component, s::fmi2StatusKind, value::Ptr{fmi2Integer})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2StatusKind, Ptr{fmi2Integer}),
          c, s, value)
end

"""
Source: FMISpec2.0.2[p.106]: 4.2.3 Retrieving Status Information from the Slave

Informs the master about the actual status of the simulation run. Which status information is to be returned is specified by the argument fmi2StatusKind.
"""
function fmi2GetBooleanStatus!(cfunc::Ptr{Nothing}, c::fmi2Component, s::fmi2StatusKind, value::Ptr{fmi2Boolean})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2StatusKind, Ptr{fmi2Boolean}),
          c, s, value)
end

"""
Source: FMISpec2.0.2[p.106]: 4.2.3 Retrieving Status Information from the Slave

Informs the master about the actual status of the simulation run. Which status information is to be returned is specified by the argument fmi2StatusKind.
"""
function fmi2GetStringStatus!(cfunc::Ptr{Nothing}, c::fmi2Component, s::fmi2StatusKind, value::Ptr{fmi2String})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2StatusKind, Ptr{fmi2String}),
          c, s, value)
end

# Model Exchange specific Functions

"""
Source: FMISpec2.0.2[p.83]: 3.2.1 Providing Independent Variables and Re-initialization of Caching

Set a new time instant and re-initialize caching of variables that depend on time, provided the newly provided time value is different to the previously set time value (variables that depend solely on constants or parameters need not to be newly computed in the sequel, but the previously computed values can be reused).
"""
function fmi2SetTime(cfunc::Ptr{Nothing}, c::fmi2Component, time::fmi2Real)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2Real),
          c, time)
end

"""
Source: FMISpec2.0.2[p.83]: 3.2.1 Providing Independent Variables and Re-initialization of Caching

Set a new (continuous) state vector and re-initialize caching of variables that depend on the states. Argument nx is the length of vector x and is provided for checking purposes
"""
function fmi2SetContinuousStates(cfunc::Ptr{Nothing}, c::fmi2Component, x::Union{AbstractArray{fmi2Real}, Ptr{fmi2Real}}, nx::Csize_t)
    ccall(cfunc,
         fmi2Status,
         (fmi2Component, Ptr{fmi2Real}, Csize_t),
         c, x, nx)
end

"""
Source: FMISpec2.0.2[p.84]: 3.2.2 Evaluation of Model Equations

The model enters Event Mode from the Continuous-Time Mode and discrete-time equations may become active (and relations are not “frozen”).
"""
function fmi2EnterEventMode(cfunc::Ptr{Nothing}, c::fmi2Component)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component,),
          c)
end

"""
Source: FMISpec2.0.2[p.84]: 3.2.2 Evaluation of Model Equations

The FMU is in Event Mode and the super dense time is incremented by this call.
"""
function fmi2NewDiscreteStates!(cfunc::Ptr{Nothing}, c::fmi2Component, eventInfo::Ptr{fmi2EventInfo})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2EventInfo}),
          c, eventInfo)
end

"""
Source: FMISpec2.0.2[p.85]: 3.2.2 Evaluation of Model Equations

The model enters Continuous-Time Mode and all discrete-time equations become inactive and all relations are “frozen”.
This function has to be called when changing from Event Mode (after the global event iteration in Event Mode over all involved FMUs and other models has converged) into Continuous-Time Mode.
"""
function fmi2EnterContinuousTimeMode(cfunc::Ptr{Nothing}, c::fmi2Component)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component,),
          c)
end

"""
Source: FMISpec2.0.2[p.85]: 3.2.2 Evaluation of Model Equations

This function must be called by the environment after every completed step of the integrator provided the capability flag completedIntegratorStepNotNeeded = false.
If enterEventMode == fmi2True, the event mode must be entered
If terminateSimulation == fmi2True, the simulation shall be terminated
"""
function fmi2CompletedIntegratorStep!(cfunc::Ptr{Nothing},
                                      c::fmi2Component,
                                      noSetFMUStatePriorToCurrentPoint::fmi2Boolean,
                                      enterEventMode::Ptr{fmi2Boolean},
                                      terminateSimulation::Ptr{fmi2Boolean})
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, fmi2Boolean, Ptr{fmi2Boolean}, Ptr{fmi2Boolean}),
          c, noSetFMUStatePriorToCurrentPoint, enterEventMode, terminateSimulation)
end

"""
Source: FMISpec2.0.2[p.86]: 3.2.2 Evaluation of Model Equations

Compute state derivatives at the current time instant and for the current states.
"""
function fmi2GetDerivatives!(cfunc::Ptr{Nothing},
                            c::fmi2Component,
                            derivatives::Union{AbstractArray{fmi2Real}, Ptr{fmi2Real}},
                            nx::Csize_t)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2Real}, Csize_t),
          c, derivatives, nx)
end

"""
Source: FMISpec2.0.2[p.86]: 3.2.2 Evaluation of Model Equations

Compute event indicators at the current time instant and for the current states.
"""
function fmi2GetEventIndicators!(cfunc::Ptr{Nothing}, c::fmi2Component, eventIndicators::Union{AbstractArray{fmi2Real}, Ptr{fmi2Real}}, ni::Csize_t)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2Real}, Csize_t),
          c, eventIndicators, ni)
end

"""
Source: FMISpec2.0.2[p.86]: 3.2.2 Evaluation of Model Equations

Return the new (continuous) state vector x.
"""
function fmi2GetContinuousStates!(cfunc::Ptr{Nothing}, c::fmi2Component,
                                 x::Union{AbstractArray{fmi2Real}, Ptr{fmi2Real}},
                                 nx::Csize_t)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2Real}, Csize_t),
          c, x, nx)
end

"""
Source: FMISpec2.0.2[p.86]: 3.2.2 Evaluation of Model Equations

Return the nominal values of the continuous states.
"""
function fmi2GetNominalsOfContinuousStates!(cfunc::Ptr{Nothing}, c::fmi2Component, x_nominal::Union{AbstractArray{fmi2Real}, Ptr{fmi2Real}}, nx::Csize_t)
    ccall(cfunc,
          fmi2Status,
          (fmi2Component, Ptr{fmi2Real}, Csize_t),
          c, x_nominal, nx)
end


text:
#=
compute the capacity of a classical-quantum channel
adapted from https://github.com/hfawzi/cvxquad/blob/master/examples/cq_channel_capacity.m
and listing 1 in "Efficient optimization of the quantum relative entropy" by H. Fawzi and O. Fawzi
=#

struct ClassicalQuantum{T <: Real} <: ExampleInstanceJuMP{T}
    d::Int
    complex::Bool
    use_EF::Bool
end

function build(inst::ClassicalQuantum{T}) where {T <: Float64}
    d = inst.d
    ext = (inst.use_EF ? MatNegEntropyEigOrd() : MatNegEntropy())
    rt2 = sqrt(T(2))
    R = (inst.complex ? Complex{T} : T)

    function hermtr1()
        P = randn(R, d, d)
        P = Hermitian(P * P', :U)
        P.data ./= tr(P)
        return Hermitian(P)
    end
    Ps = [hermtr1() for _ in 1:d]
    Hs = [dot(P, log(P)) for P in Ps]

    model = JuMP.Model()
    JuMP.@variable(model, ρ[1:d] >= 0)
    JuMP.@constraint(model, sum(ρ) == 1)
    JuMP.@variable(model, epi)
    JuMP.@objective(model, Max, -epi + dot(ρ, Hs))

    vec_dim = Cones.svec_length(R, d)
    entr = JuMP.AffExpr.(zeros(vec_dim))
    P_vec = zeros(T, vec_dim)
    for (Pi, ρi) in zip(Ps, ρ)
        Cones.smat_to_svec!(P_vec, Pi, rt2)
        JuMP.add_to_expression!.(entr, ρi, P_vec)
    end
    add_homog_spectral(ext, d, vcat(epi, entr), model)

    # save for use in tests
    model.ext[:epi] = epi
    model.ext[:entr] = entr

    return model
end

function test_extra(inst::ClassicalQuantum{T}, model::JuMP.Model) where T
    stat = JuMP.termination_status(model)
    @test stat == MOI.OPTIMAL
    (stat == MOI.OPTIMAL) || return

    # check constraint
    tol = eps(T)^0.2
    epi_opt = JuMP.value(model.ext[:epi])
    Entr_opt = zeros(inst.complex ? Complex{T} : T, inst.d, inst.d)
    Cones.svec_to_smat!(Entr_opt, JuMP.value.(model.ext[:entr]), sqrt(T(2)))
    λ = eigvals(Hermitian(Entr_opt, :U))
    @test minimum(λ) >= -tol
    qe_result = get_val(pos_only(λ), MatNegEntropy())
    @test epi_opt ≈ qe_result atol=tol rtol=tol
    return
end


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

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

"""

get information of a group
Return: IoK8sApimachineryPkgApisMetaV1APIGroup
"""
function getPolicyAPIGroup(_api::PolicyApi; _mediaType=nothing)
    _ctx = Swagger.Ctx(_api.client, "GET", IoK8sApimachineryPkgApisMetaV1APIGroup, "/apis/policy/", ["BearerToken"])
    Swagger.set_header_accept(_ctx, ["application/json", "application/yaml", "application/vnd.kubernetes.protobuf"])
    Swagger.set_header_content_type(_ctx, (_mediaType === nothing) ? ["application/json", "application/yaml", "application/vnd.kubernetes.protobuf"] : [_mediaType])
    Swagger.exec(_ctx)
end

export getPolicyAPIGroup


text:
module TestPackage2

using TestPackage
greet() = print("Hello World!!")
greet_child() = TestPackage.greet()

answer_to_life_universe() = 42

end # module


text:
# Resolving Partial XYH constraints

using TransformUtils
using CoordinateTransformations
using DrakeVisualizer
import DrakeVisualizer: Triad

import Base: convert
using Base: Test

import Rotations as _Rot

# random testing and converstion to be moved out

function convert{T <: CoordinateTransformations.AffineMap}(::Type{T}, x::SE3)
  q = convert(TransformUtils.Quaternion, x.R)
  Translation(x.t...) ∘ LinearMap( _Rot.QuatRotation(q.s, q.v...) )
end
function convert{T <: CoordinateTransformations.AffineMap{_Rot.QuatRotation{Float64}}}(::Type{SE3}, x::T)
  SE3(x.v[1:3], TransformUtils.Quaternion(x.m.w, [x.m.x,x.m.y,x.m.z]) )
end

tq = SE3(zeros(3),Quaternion(0.0,[1.0, 0,0]));
q1 = convert(AffineMap, tq);
q2 = convert(AffineMap, tq);

q12 = q1 ∘ q2

tq12 = convert(SE3, q12)

@test compare(SE3(0), tq12)

# testing complete, continue with XYH example

# Launch the viewer application if it isn't running already:
DrakeVisualizer.any_open_windows() || DrakeVisualizer.new_window();
vis = Visualizer();

# okay, do the numbers
dist = 10.0

wTx1 = SE3(zeros(3), TransformUtils.AngleAxis(-pi/2,[1.0,0,0]))
wTx2 = SE3([0,-dist,0], TransformUtils.AngleAxis(-pi/2,[1.0,0,0]))

# x1
setgeometry!(vis[:evalXYH][:x1], Triad());
settransform!(vis[:evalXYH][:x1], convert(AffineMap,wTx1 ) );
# x2
setgeometry!(vis[:evalXYH][:x2], Triad());
settransform!(vis[:evalXYH][:x2], convert(AffineMap,wTx2 ) );

## Look at XYH constraint numbers
# iSAM is doing
# predicted = p2.ominus(p1);
# Eigen::Vector3d predicted3(predicted.x(), predicted.y(), standardRad(predicted.yaw()));
# Eigen::Vector3d err = predicted3 - _measure;
# Pose3d ominus(const Pose3d& b) const {
#     return Pose3d(b.oTw() * wTo());
#   }

x1Tx2 = wTx1\wTx2
predicted = [x1Tx2.t[1:2]..., convert(Euler, x1Tx2.R).Y]

@show predicted

@test norm(predicted - dist) < 1e-10

#


text:
using Compat
using ProtoBuf
import ProtoBuf.meta
import Base: hash, isequal, ==

type __enum_RpcKindProto <: ProtoEnum
    RPC_BUILTIN::Int32
    RPC_WRITABLE::Int32
    RPC_PROTOCOL_BUFFER::Int32
    __enum_RpcKindProto() = new(0,1,2)
end #type __enum_RpcKindProto
const RpcKindProto = __enum_RpcKindProto()

type RPCTraceInfoProto
    traceId::Int64
    parentId::Int64
    RPCTraceInfoProto() = (o=new(); fillunset(o); o)
end #type RPCTraceInfoProto
hash(v::RPCTraceInfoProto) = ProtoBuf.protohash(v)
isequal(v1::RPCTraceInfoProto, v2::RPCTraceInfoProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::RPCTraceInfoProto, v2::RPCTraceInfoProto) = ProtoBuf.protoeq(v1, v2)

type __enum_RpcRequestHeaderProto_OperationProto <: ProtoEnum
    RPC_FINAL_PACKET::Int32
    RPC_CONTINUATION_PACKET::Int32
    RPC_CLOSE_CONNECTION::Int32
    __enum_RpcRequestHeaderProto_OperationProto() = new(0,1,2)
end #type __enum_RpcRequestHeaderProto_OperationProto
const RpcRequestHeaderProto_OperationProto = __enum_RpcRequestHeaderProto_OperationProto()

type RpcRequestHeaderProto
    rpcKind::Int32
    rpcOp::Int32
    callId::Int32
    clientId::Array{UInt8,1}
    retryCount::Int32
    traceInfo::RPCTraceInfoProto
    RpcRequestHeaderProto() = (o=new(); fillunset(o); o)
end #type RpcRequestHeaderProto
const __req_RpcRequestHeaderProto = Symbol[:callId,:clientId]
const __val_RpcRequestHeaderProto = @compat Dict(:retryCount => -1)
const __wtype_RpcRequestHeaderProto = @compat Dict(:callId => :sint32, :retryCount => :sint32)
meta(t::Type{RpcRequestHeaderProto}) = meta(t, __req_RpcRequestHeaderProto, ProtoBuf.DEF_FNUM, __val_RpcRequestHeaderProto, true, ProtoBuf.DEF_PACK, __wtype_RpcRequestHeaderProto)
hash(v::RpcRequestHeaderProto) = ProtoBuf.protohash(v)
isequal(v1::RpcRequestHeaderProto, v2::RpcRequestHeaderProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::RpcRequestHeaderProto, v2::RpcRequestHeaderProto) = ProtoBuf.protoeq(v1, v2)

type __enum_RpcResponseHeaderProto_RpcStatusProto <: ProtoEnum
    SUCCESS::Int32
    ERROR::Int32
    FATAL::Int32
    __enum_RpcResponseHeaderProto_RpcStatusProto() = new(0,1,2)
end #type __enum_RpcResponseHeaderProto_RpcStatusProto
const RpcResponseHeaderProto_RpcStatusProto = __enum_RpcResponseHeaderProto_RpcStatusProto()

type __enum_RpcResponseHeaderProto_RpcErrorCodeProto <: ProtoEnum
    ERROR_APPLICATION::Int32
    ERROR_NO_SUCH_METHOD::Int32
    ERROR_NO_SUCH_PROTOCOL::Int32
    ERROR_RPC_SERVER::Int32
    ERROR_SERIALIZING_RESPONSE::Int32
    ERROR_RPC_VERSION_MISMATCH::Int32
    FATAL_UNKNOWN::Int32
    FATAL_UNSUPPORTED_SERIALIZATION::Int32
    FATAL_INVALID_RPC_HEADER::Int32
    FATAL_DESERIALIZING_REQUEST::Int32
    FATAL_VERSION_MISMATCH::Int32
    FATAL_UNAUTHORIZED::Int32
    __enum_RpcResponseHeaderProto_RpcErrorCodeProto() = new(1,2,3,4,5,6,10,11,12,13,14,15)
end #type __enum_RpcResponseHeaderProto_RpcErrorCodeProto
const RpcResponseHeaderProto_RpcErrorCodeProto = __enum_RpcResponseHeaderProto_RpcErrorCodeProto()

type RpcResponseHeaderProto
    callId::UInt32
    status::Int32
    serverIpcVersionNum::UInt32
    exceptionClassName::AbstractString
    errorMsg::AbstractString
    errorDetail::Int32
    clientId::Array{UInt8,1}
    retryCount::Int32
    RpcResponseHeaderProto() = (o=new(); fillunset(o); o)
end #type RpcResponseHeaderProto
const __req_RpcResponseHeaderProto = Symbol[:callId,:status]
const __val_RpcResponseHeaderProto = @compat Dict(:retryCount => -1)
const __wtype_RpcResponseHeaderProto = @compat Dict(:retryCount => :sint32)
meta(t::Type{RpcResponseHeaderProto}) = meta(t, __req_RpcResponseHeaderProto, ProtoBuf.DEF_FNUM, __val_RpcResponseHeaderProto, true, ProtoBuf.DEF_PACK, __wtype_RpcResponseHeaderProto)
hash(v::RpcResponseHeaderProto) = ProtoBuf.protohash(v)
isequal(v1::RpcResponseHeaderProto, v2::RpcResponseHeaderProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::RpcResponseHeaderProto, v2::RpcResponseHeaderProto) = ProtoBuf.protoeq(v1, v2)

type __enum_RpcSaslProto_SaslState <: ProtoEnum
    SUCCESS::Int32
    NEGOTIATE::Int32
    INITIATE::Int32
    CHALLENGE::Int32
    RESPONSE::Int32
    WRAP::Int32
    __enum_RpcSaslProto_SaslState() = new(0,1,2,3,4,5)
end #type __enum_RpcSaslProto_SaslState
const RpcSaslProto_SaslState = __enum_RpcSaslProto_SaslState()

type RpcSaslProto_SaslAuth
    method::AbstractString
    mechanism::AbstractString
    protocol::AbstractString
    serverId::AbstractString
    challenge::Array{UInt8,1}
    RpcSaslProto_SaslAuth() = (o=new(); fillunset(o); o)
end #type RpcSaslProto_SaslAuth
const __req_RpcSaslProto_SaslAuth = Symbol[:method,:mechanism]
meta(t::Type{RpcSaslProto_SaslAuth}) = meta(t, __req_RpcSaslProto_SaslAuth, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, true, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES)
hash(v::RpcSaslProto_SaslAuth) = ProtoBuf.protohash(v)
isequal(v1::RpcSaslProto_SaslAuth, v2::RpcSaslProto_SaslAuth) = ProtoBuf.protoisequal(v1, v2)
==(v1::RpcSaslProto_SaslAuth, v2::RpcSaslProto_SaslAuth) = ProtoBuf.protoeq(v1, v2)

type RpcSaslProto
    version::UInt32
    state::Int32
    token::Array{UInt8,1}
    auths::Array{RpcSaslProto_SaslAuth,1}
    RpcSaslProto() = (o=new(); fillunset(o); o)
end #type RpcSaslProto
const __req_RpcSaslProto = Symbol[:state]
meta(t::Type{RpcSaslProto}) = meta(t, __req_RpcSaslProto, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, true, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES)
hash(v::RpcSaslProto) = ProtoBuf.protohash(v)
isequal(v1::RpcSaslProto, v2::RpcSaslProto) = ProtoBuf.protoisequal(v1, v2)
==(v1::RpcSaslProto, v2::RpcSaslProto) = ProtoBuf.protoeq(v1, v2)

export RpcKindProto, RPCTraceInfoProto, RpcRequestHeaderProto_OperationProto, RpcRequestHeaderProto, RpcResponseHeaderProto_RpcStatusProto, RpcResponseHeaderProto_RpcErrorCodeProto, RpcResponseHeaderProto, RpcSaslProto_SaslState, RpcSaslProto_SaslAuth, RpcSaslProto


text:
# parameters
mass_bin_name = "1540_1560" #ARGS[1]#
tslice = "t1"
path_to_working_folder = "/afs/cern.ch/user/m/mimikhas/work/private/pwa_data"#"data"
path_wavelist = "src"

######################################################
@show ARGS
push!(LOAD_PATH,"src")
using amplitudes_compass
using PWAHelper

# set names
for app in ["rd", "mc", "fu"]
    pwf = path_to_working_folder
    @eval $(Symbol("kinvar_"*app))    = joinpath($pwf,"variables_$(mass_bin_name)_$(tslice)_"*$app*".txt")
    @eval $(Symbol("basisfunc_"*app)) = joinpath($pwf,"functions_$(mass_bin_name)_$(tslice)_"*$app*".bin")
end

# read wavelist throw waves below threshold
wavelist = get_wavelist(joinpath(path_wavelist,"wavelist_formated.txt");
     path_to_thresholds=joinpath(path_wavelist,"thresholds_formated.txt"),
     M3pi=Meta.parse(mass_bin_name[1:4])/1000)

# extract names and wavefunctions from the wavelist
wavenames = get_wavenames(wavelist)
wavebasis = get_wavebasis(wavelist)

# do precalculations
@time precalculate_compass_basis(wavebasis, kinvar_rd, basisfunc_rd)
@time precalculate_compass_basis(wavebasis, kinvar_mc, basisfunc_mc)
@time precalculate_compass_basis(wavebasis, kinvar_fu, basisfunc_fu)


text:
using OffsetBuffers
using Test
# using Random
# using Serialization

@test [] == detect_ambiguities(Base, Core, OffsetBuffers)

tests = [
         "rolling_buffer",
         "sliding_buffer",
        ]

if length(ARGS) > 0
    tests = ARGS
end

@testset "OffsetBuffers" begin

for t in tests
    fp = joinpath(dirname(@__FILE__), "test_$t.jl")
    println("$fp ...")
    include(fp)
end

end # @testset