text:
module CowSay

### Entrance to Farm ###
export CREATURES
export bubble
export creature_combine_bubble
export message_wrap
export cowsay

const CREATURES = Dict(
    "beavis" => raw"""
          \
            \
             \
                   _------~~-,
                ,'            ,
                /               \\
               /                :
              |                  '
              |                  |
              |                  |
               |   _--           |
               _| =-.     .-.   ||
               o|/o/       _.   |
               /  ~          \\ |
             (____\@)  ___~    |
                |_===~~~.`    |
             _______.--~     |
             \\________       |
                      \\      |
                    __/-___-- -__
                   /            _ \\
    """,
    "daemon" => raw"""
      \         ,        ,
        \       /(        )`
         \      \ \___   / |
                /- _  `-/  '
               (/\/ \ \   /\
               / /   | `    \
               O O   ) /    |
               `-^--'`<     '
              (_.)  _  )   /
               `.___/`    /
                 `-----' /
    <----.     __ / __   \
    <----|====O)))==) \) /====
    <----'    `--' `.__,' \
                 |        |
                  \       /
            ______( (_  / \______
          ,'  ,-----'   |        \
          `--{__________)        \/
    """,
    "cow" => raw"""
        \
          \
           ^__^
           (oo)\_______
           (__)\       )\/\
               ||----w |
               ||     ||
    """,
    "dragon" => raw"""
     \
       \
        \
         \
                              / \\  //\\
               |\\___/|      /   \\//  \\\\
               /0  0  \\__  /    //  | \\ \\
              /     /  \\/_/    //   |  \\  \\
              \@_^_\@'/   \\/_   //    |   \\   \\
              //_^_/     \\/_ //     |    \\    \\
           ( //) |        \\///      |     \\     \\
         ( / /) _|_ /   )  //       |      \\     _\\
       ( // /) '/,_ _ _/  ( ; -.    |    _ _\\.-~        .-~~~^-.
     (( / / )) ,-{        _      `-.|.-~-.           .~         `.
    (( // / ))  '/\\      /                 ~-. _ .-~      .-~^-.  \\
    (( /// ))      `.   {            }                   /      \\  \\
     (( / ))     .----~-.\\        \\-'                 .~         \\  `. \\^-.
                ///.----..>        \\             _ -~             `.  ^-`  ^-_
                  ///-._ _ _ _ _ _ _}^ - - - - ~                     ~-- ,.-~
                                                                     /.-~
    """,
    "ghostbusters" => raw"""       \
             \
              \
                          __---__
                       _-       /--______
                  __--( /     \ )XXXXXXXXXXX\v.
                .-XXX(   O   O  )XXXXXXXXXXXXXXX-
               /XXX(       U     )        XXXXXXX\
             /XXXXX(              )--_  XXXXXXXXXXX\
            /XXXXX/ (      O     )   XXXXXX   \XXXXX\
            XXXXX/   /            XXXXXX   \__ \XXXXX
            XXXXXX__/          XXXXXX         \__---->
    ---___  XXX__/          XXXXXX      \__         /
      \-  --__/   ___/\  XXXXXX            /  ___--/=
       \-\    ___/    XXXXXX              '--- XXXXXX
          \-\/XXX\ XXXXXX                      /XXXXX
            \XXXXXXXXX   \                    /XXXXX/
             \XXXXXX      >                 _/XXXXX/
               \XXXXX--__/              __-- XXXX/
                -XXXXXXXX---------------  XXXXXX-
                   \XXXXXXXXXXXXXXXXXXXXXXXXXX/
                      VXXXXXXXXXXXXXXXXXXV
    """,
    "kitty" => raw"""
     \
       \

        ("`-'  '-/") .___..--' ' "`-._
            ` *_ *  )    `-.   (      ) .`-.__. `)
            (_Y_.) ' ._   )   `._` ;  `` -. .-'
         _.. `--'_..-_/   /--' _ .' ,4
      ( i l ),-''  ( l i),'  ( ( ! .-'
    """,
    "meow" => raw"""
     \
       \ ,   _ ___.--'''`--''//-,-_--_.
          \`"' ` || \\ \ \\/ / // / ,-\\`,_
         /'`  \ \ || Y  | \|/ / // / - |__ `-,
        /@"\  ` \ `\ |  | ||/ // | \/  \  `-._`-,_.,
       /  _.-. `.-\,___/\ _/|_/_\_\/|_/ |     `-._._)
       `-'``/  /  |  // \__/\__  /  \__/ \
            `-'  /-\/  | -|   \__ \   |-' |
              __/\ / _/ \/ __,-'   ) ,' _|'
             (((__/(((_.' ((___..-'((__,'
    """,
    "milk" => raw"""
      \
        \
           ____________
           |__________|
          /           /\
         /           /  \
        /___________/___/|
        |          |     |
        |  ==\ /== |     |
        |   O   O  | \ \ |
        |     <    |  \ \|
       /|          |   \ \
      / |  \_____/ |   / /
     / /|          |  / /|
    /||\|          | /||\/
        -------------|
            | |    | |
           <__/    \__>
    """,
    "pig" => raw"""
      \
        \
                 ,.
                (_|,.
                ,' /, )_______   _
            __j o``-'        `.'-)'
            (")                 \'
            `-j                |
                `-._(           /
                    |_\  |--^.  /
                /_]'|_| /_)_/
                    /_]'  /_]'
    """,
    "stegosaurus" => raw"""
             \
               \
                                         / `.   .' "
                                 .---.  <    > <    >  .---.
                                 |    \  \ - ~ ~ - /  /    |
             _____          ..-~             ~-..-~
            |     |   \~~~\.'                    `./~~~/
           ---------   \__/                        \__/
          .'  O    \     /               /       \  "
         (_____,    `._.'               |         }  \/~~~/
          `----.          /       }     |        /    \__/
                `-.      |       /      |       /      `. ,~~|
                    ~-.__|      /_ - ~ ^|      /- _      `..-'
                         |     /        |     /     ~-.     `-. _  _  _
                         |_____|        |_____|         ~ - . _ _ _ _ _>
    """,
    "stimpy" => raw"""
      \
        \
            .    _  .
           |\_|/__/|
           / / \/ \  \
          /__|O||O|__ \
         |/_ \_/\_/ _\ |
         | | (____) | ||
         \/\___/\__/  //
         (_/         ||
          |          ||
          |          ||\
           \        //_/
            \______//
           __ || __||
          (____(____)
    """,
    "trex" => raw"""
            \
              \
                 .-=-==--==--.
           ..-=="  ,'o`)      `.
         ,'         `"'         \
        :  (                     `.__...._
        |                  )    /         `-=-.
        :       ,vv.-._   /    /               `---==-._
         \/\/\/VV ^ d88`;'    /                         `.
             ``  ^/d88P!'    /             ,              `._
                ^/    !'   ,.      ,      /                  "-,,__,,--'\"\"\"\"-.
               ^/    !'  ,'  \ . .(      (         _           )  ) ) ) ))_,-.\
              ^(__ ,!',"'   ;:+.:%:a.     \:.. . ,'          )  )  ) ) ,\"'    '
              ',,,'','     /o:::":%:%a.    \:.:.:         .    )  ) _,'
               \"\"\"'       ;':::'' `+%%%a._  \%:%|         ;.). _,-\"\"
                      ,-='_.-'      ``:%::)  )%:|        /:._,"
                     (/(/"           ," ,'_,'%%%:       (_,'
                                    (  (//(`.___;        \
                                     \     \    `         `
                                      `.    `.   `.        :
                                        \. . .\    : . . . :
                                         \. . .:    `.. . .:
                                          `..:.:\     \:...\
                                           ;:.:.;      ::...:
                                           ):%::       :::::;
                                       __,::%:(        :::::
                                    ,;:%%%%%%%:        ;:%::
                                      ;,--\"\"-.`\  ,=--':%:%:\
                                     /\"       \"| /-".:%%%%%%%\
                                                     ;,-\"'`)%%)
                                                    /\"      \"|
    """,
    "turkey" => raw"""
             \
               \
                                                 ,+*^^*+___+++_
                                           ,*^^^^              )
                                        _+*                     ^**+_
                                      +^       _ _++*+_+++_,         )
                  _+^^*+_    (     ,+*^ ^          \\+_        )
                 {       )  (    ,(    ,_+--+--,      ^)      ^\\
                { (\@)    } f   ,(  ,+-^ __*_*_  ^^\\_   ^\\       )
               {:;-/    (_+*-+^^^^^+*+*<_ _++_)_    )    )      /
              ( /  (    (        ,___    ^*+_+* )   <    <      \\
               U _/     )    *--<  ) ^\\-----++__)   )    )       )
                (      )  _(^)^^))  )  )\\^^^^^))^*+/    /       /
              (      /  (_))_^)) )  )  ))^^^^^))^^^)__/     +^^
             (     ,/    (^))^))  )  ) ))^^^^^^^))^^)       _)
              *+__+*       (_))^)  ) ) ))^^^^^^))^^^^^)____*^
              \\             \\_)^)_)) ))^^^^^^^^^^))^^^^)
               (_             ^\\__^^^^^^^^^^^^))^^^^^^^)
                 ^\\___            ^\\__^^^^^^))^^^^^^^^)\\\\
                      ^^^^^\\uuu/^^\\uuu/^^^^\\^\\^\\^\\^\\^\\^\\^\\
                         ___) >____) >___   ^\\_\\_\\_\\_\\_\\_\\)
                        ^^^//\\\\_^^//\\\\_^       ^(\\_\\_\\_\\)
                         ^^^ ^^ ^^^ ^
    """,
    "turtle" => raw"""
             \
               \
                                                   ___-------___
                                               _-~~             ~~-_
                                            _-~                    /~-_
                 /^\__/^\         /~  \                   /    \
               /|  O|| O|        /      \_______________/        \
              | |___||__|      /       /                \          \
              |          \    /      /                    \          \
              |   (_______) /______/                        \_________ \
              |         / /         \                      /            \
               \         \^\\         \                  /               \     /
                 \         ||           \______________/      _-_       //\__//
                   \       ||------_-~~-_ ------------- \ --/~   ~\    || __/
                     ~-----||====/~     |==================|       |/~~~~~
                      (_(__/  ./     /                    \_\      \.
                             (_(___/                         \_____)_)
    """,
    "tux" => raw"""
         \
           \
            .--.
           |o_o |
           |:_/ |
          //   \ \
         (|     | )
        /'\_   _/`\
        \___)=(___/
    """
)

"""
    bubble(msg_v::Vector)

Creates a message bubble.
"""
function bubble(msg_v::Vector)
    result = []
    longest_string = maximum(msg_v .|> length)
    if length(msg_v) == 1
        result = " $(strip(msg_v[1])) "
        dashes = length(result) - 4 ≤ 0 ? "\b---" : "-"^(length(result) - 2)
        return "  $dashes\n<$result>\n  $dashes\n"
    else
        for i in 1:length(msg_v)
            if i == 1
                spaces = " "^(longest_string - length(msg_v[i]) + 1)
                a = string("/ ", strip(msg_v[i]), spaces, "\\\n")
                push!(result, a)
            elseif i == length(msg_v)
                spaces = " "^(longest_string - length(msg_v[i]) + 1)
                a = string("\\ ", strip(msg_v[i]), spaces, "/")
                push!(result, a)
            else
                spaces = " "^(longest_string - length(msg_v[i]) + 1)
                a = string("| ", strip(msg_v[i]), spaces, "|\n")
                push!(result, a)
            end
        end

        dashes = "-"^(longest_string + 2)
        return " $dashes\n$(join(result))\n $dashes\n"
    end
end

"""
    creature_combine_bubble(bubble::String, creature::String)

Combine message bubble and ascii art of creature.
"""
function creature_combine_bubble(bubble::String, creature::String)
    creature ∉ keys(CREATURES) && return throw(ArgumentError("Creature does not exist"))
    creature_figure = CREATURES[creature]
    return "$bubble $creature_figure"
end

"""
    message_wrap(msg::String)

Wraps the message into a compact format for each line so it can be used for function `bubble`.
"""
function message_wrap(msg::String)
    tmp = split(msg)
    full_message = []
    msg_v = []
    while !isempty(tmp)
        if length(join(msg_v, " ")) <= 35
            push!(msg_v, popfirst!(tmp))
        else
            push!(full_message, join(msg_v, " "))
            if length(join(tmp, " ")) <= 35
                push!(full_message, join(tmp, " "))
                break
            end
            msg_v = []
        end

    end
    return full_message
end

"""
    cowsay(s::String, creature="cow")

The infamous cowsay will be printed using this function
"""
function cowsay(s::String, creature = "cow")
    println(creature_combine_bubble(bubble(message_wrap(s)), creature))
end
end


text:
abstract type Shape end
abstract type Tria <: Shape end
abstract type Rect <: Shape end
abstract type Hexa <: Shape end

ext: jl


text:
module TopCheck

# package code goes here

include("small_intestine.jl")

end # module


text:
module ImageViews

using Genie, Stipple, StippleUI, StippleUI.API
import Genie.Renderer.Html: HTMLString, normal_element, register_normal_element

export imageview

register_normal_element("q__img", context = @__MODULE__)

function imageview(args...; kwargs...)
  q__img(args...; kw(kwargs)...)
end

end


text:
"""
   $(TYPEDEF)

Abstract type for geometry items (node,bnode,edge, bedge)
"""
abstract type AbstractGeometryItem{Tv<:Number, Ti <:Integer} end

"""
   $(TYPEDEF)

Abstract type for nodes.

`node[idim]` gives the the corresponding coordinate.
"""
abstract type AbstractNode{Tv<:Number, Ti <:Integer}  <: AbstractGeometryItem{Tv, Ti} end
Base.size(node::AbstractNode)=(size(node.coord)[1],)
Base.getindex(node::AbstractNode, idim)=@inbounds  node.coord[idim,node.index]

"""
    $(TYPEDEF)

Abstract type for data on nodes.
`u[ispec]` accesses value of species at this node.
"""
abstract type AbstractNodeData{T<: Number} <: AbstractVector{T} end
Base.size(u::AbstractNodeData)=size(u.val)
Base.getindex(u::AbstractNodeData,i)=@inbounds u.val[i]
Base.setindex!(f::AbstractNodeData,v,i)=@inbounds f.val[i]=v

"""
   $(TYPEDEF)

Abstract type for edges

`edge[idim,inode]` gives coordinate of node.
"""
abstract type AbstractEdge{Tv<:Number, Ti <:Integer}  <: AbstractGeometryItem{Tv, Ti} end
Base.size(edge::AbstractEdge)=(size(edge.coord)[1],2)
Base.getindex(edge::AbstractEdge, idim,inode)=@inbounds  edge.coord[idim,edge.node[inode]]

"""
    $(TYPEDEF)

Abstract type for data on edges.
`u[ispec,inode]` accesses value of species at corresponding node.
"""
abstract type AbstractEdgeData{T<: Number} <: AbstractMatrix{T} end
Base.size(u::AbstractEdgeData)=(u.n1,2)
Base.getindex(u::AbstractEdgeData,i,j)=@inbounds u.val[(j-1)*u.n1+i]

##################################################################
"""
$(TYPEDEF)

Structure holding local node information.

$(TYPEDFIELDS)
"""
mutable struct Node{Tv,Ti} <: AbstractNode{Tv, Ti}

    """
    Index in grid

    """
    index::Ti
    """
    Inner region number
    """
    region::Ti

    """
    Number of species defined in node
    """
    nspec::Ti

    """
    Number of discretization cell the node is invoked from
    """
    icell::Ti

    """
    Grid coordinates
    """
    coord::Matrix{Tv}

    """
    Grid cell nodes
    """
    cellnodes::Array{Ti,2}

    """
    Grid cell regions
    """
    cellregions::Vector{Ti}

    Node{Tv,Ti}(sys::AbstractSystem{Tv,Ti}) where {Tv,Ti}  =new(zero(Ti),0,
                                                                num_species(sys),0,
                                                                coordinates(sys.grid),
                                                                sys.grid[CellNodes],
                                                                sys.grid[CellRegions]
                                                                )
end

@inline function _fill!(node::Node,inode,icell)
    node.region=node.cellregions[icell]
    node.index=node.cellnodes[inode,icell]
    node.icell=icell
    nothing
end

"""
    $(TYPEDEF)

Unknown data on node.
"""
struct NodeUnknowns{T} <:AbstractNodeData{T}
    val::Vector{T}
    geom::Node
end

@inline unknowns(node::Node,u::Vector{T}) where T = NodeUnknowns{T}(u,node)

"""
    $(TYPEDEF)

RHS data on node.
"""
struct NodeRHS{T} <:AbstractNodeData{T}
    val::Vector{T}
    geom::Node
end

@inline rhs(node::Node, f::Vector{T}) where T = NodeRHS{T}(f,node)

##################################################################
"""
$(TYPEDEF)

Structure holding local boundary  node information.

$(TYPEDFIELDS)
"""
mutable struct BNode{Tv, Ti} <: AbstractNode{Tv, Ti}

    """
    Index in grid
    """
    index::Ti

    """
    BFace number it is called from
    """
    ibface::Ti

    """
    local node number
    """
    ibnode::Ti

    """
    Boundary region number
    """
    region::Ti

    cellregions::Vector{Ti}

    """
    Number of species defined in node
    """
    nspec::Ti

    """
    Grid coordinates
    """
    coord::Matrix{Tv}

    bfacenodes::Array{Ti,2}

    bfaceregions::Vector{Ti}

    allcellregions::Vector{Ti}

    bfacecells::ExtendableGrids.Adjacency{Ti}

    BNode{Tv,Ti}(sys::AbstractSystem{Tv,Ti}) where {Tv,Ti}  =new(0,0,0,0,zeros(Ti,2),
                                                                 num_species(sys),
                                                                 coordinates(sys.grid),
                                                                 sys.grid[BFaceNodes],
                                                                 sys.grid[BFaceRegions],
                                                                 sys.grid[CellRegions],
                                                                 sys.grid[BFaceCells],
                                                                 )
end

@inline function _fill0!(node::BNode,ibnode,ibface)
    node.ibface=ibface
    node.ibnode=ibnode
    node.region=node.bfaceregions[ibface]
    node.index=node.bfacenodes[ibnode,ibface]
    nothing
end

@inline function _fill!(node::BNode,ibnode,ibface)
    _fill0!(node,ibnode,ibface)
    node.cellregions[1]=0
    node.cellregions[2]=0
    for i=1:num_targets(node.bfacecells,ibface)
        icell=node.bfacecells[i,ibface]
        node.cellregions[i]=node.allcellregions[icell]
    end
end

struct BNodeUnknowns{T} <:AbstractNodeData{T}
    val::Vector{T}
    geom::BNode
end

@inline unknowns(bnode::BNode,u::Vector{T}) where T = BNodeUnknowns{T}(u,bnode)

struct BNodeRHS{T} <:AbstractNodeData{T}
    val::Vector{T}
    geom::BNode
end

@inline rhs(bnode::BNode, f::Vector{T}) where T = BNodeRHS{T}(f,bnode)

##################################################################
"""
$(TYPEDEF)

Structure holding local edge information.

$(TYPEDFIELDS)
"""
mutable struct Edge{Tv,Ti}  <: AbstractEdge{Tv, Ti}

    """
    Index in grid
    """
    index::Ti

    """
    Index
    """
    node::Vector{Ti}

    """
    Inner region number corresponding to edge
    """
    region::Ti

    """
    Number of species defined in edge
    """
    nspec::Ti

    """
    Number of discretization cell the edge is invoked from
    """
    icell::Ti

    """
    Grid coordinates
    """
    coord::Matrix{Tv}

    cellx::Array{Ti,2}
    edgenodes::Array{Ti,2}
    cellregions::Vector{Ti}
    has_celledges::Bool

    Edge{Tv,Ti}(::Nothing) where {Tv,Ti}  =new()
end

function  Edge{Tv,Ti}(sys::AbstractSystem{Tv,Ti}) where {Tv,Ti}
    edge=Edge{Tv,Ti}(nothing)

    edge.index=0
    edge.node=[0,0]
    edge.region=0
    edge.nspec=num_species(sys)
    edge.icell=0
    edge.coord=coordinates(sys.grid)
    geom=sys.grid[CellGeometries][1]
    if haskey(sys.grid,CellEdges)
        edge.cellx=sys.grid[CellEdges]
        edge.edgenodes=sys.grid[EdgeNodes]
        edge.has_celledges=true
    else
        edge.cellx=sys.grid[CellNodes]
        edge.edgenodes=local_celledgenodes(geom)
        edge.has_celledges=false
    end
    edge.cellregions=sys.grid[CellRegions]
    edge
end

@inline function _fill!(edge::Edge,iedge,icell)
    if edge.has_celledges #  cellx==celledges, edgenodes==global_edgenodes
        # If we work with projections of fluxes onto edges,
        # we need to ensure that the edges are accessed with the
        # same orientation without regard of the orientation induced
        # by local cell numbering
        edge.index=edge.cellx[iedge,icell]
        edge.node[1]=edge.edgenodes[1,edge.index]
        edge.node[2]=edge.edgenodes[2,edge.index]
    else # cx==cellnodes, edgenodes== local_edgenodes
        edge.index=0
        edge.node[1]=edge.cellx[edge.edgenodes[1,iedge],icell]
        edge.node[2]=edge.cellx[edge.edgenodes[2,iedge],icell]
    end
    edge.region=edge.cellregions[icell]
    edge.icell=icell
    nothing
end

struct EdgeUnknowns{T} <:AbstractEdgeData{T}
    val::Vector{T}
    n1::Int64
    geom::AbstractEdge
end

@inline unknowns(edge::Edge,u::Vector{T}) where T = EdgeUnknowns{T}(u,edge.nspec,edge)

struct EdgeRHS{T} <:AbstractNodeData{T}
    val::Vector{T}
    geom::AbstractEdge
end

@inline rhs(edge::Edge, f::Vector{T}) where T = EdgeRHS{T}(f,edge)

##################################################################
"""
$(TYPEDEF)

Structure holding local edge information.

$(TYPEDFIELDS)
"""
mutable struct BEdge{Tv,Ti}  <: AbstractEdge{Tv, Ti}

    """
    Index in grid
    """
    index::Ti

    """
    Index
    """
    node::Vector{Ti}

    """
    Inner region number corresponding to edge
    """
    region::Ti

    """
    Number of species defined in edge
    """
    nspec::Ti

    """
    Number of discretization cell the edge is invoked from
    """
    icell::Ti

    """
    Grid coordinates
    """
    coord::Matrix{Tv}

    bedgenodes::Array{Ti,2}
    bfaceedges::Array{Ti,2}
    bfaceregions::Vector{Ti}

    BEdge{Tv,Ti}(::Nothing) where {Tv,Ti}  =new()
end

function  BEdge{Tv,Ti}(sys::AbstractSystem{Tv,Ti}) where {Tv,Ti}
    bedge=BEdge{Tv,Ti}(nothing)

    bedge.index=0
    bedge.node=[0,0]
    bedge.region=0
    bedge.nspec=num_species(sys)
    bedge.icell=0
    bedge.coord=coordinates(sys.grid)

    bedge.bedgenodes=sys.grid[BEdgeNodes]
    bedge.bfaceedges=sys.grid[BFaceEdges]
    bedge.bfaceregions=sys.grid[BFaceRegions]
    bedge
end

@inline function _fill!(bedge::BEdge,ibedge,ibface)

    bedge.index   = bedge.bfaceedges[ibedge, ibface]
    bedge.node[1] = bedge.bedgenodes[1, bedge.index]
    bedge.node[2] = bedge.bedgenodes[2, bedge.index]

    bedge.region = bedge.bfaceregions[ibface]
    bedge.icell  = ibface

    nothing
end

struct BEdgeUnknowns{T} <:AbstractEdgeData{T}
    val::Vector{T}
    n1::Int64
    geom::AbstractEdge
end

@inline unknowns(edge::BEdge,u::Vector{T}) where T = EdgeUnknowns{T}(u,edge.nspec,edge)

struct BEdgeRHS{T} <:AbstractNodeData{T}
    val::Vector{T}
    geom::AbstractEdge
end

@inline rhs(edge::BEdge, f::Vector{T}) where T = EdgeRHS{T}(f,edge)

##################################################################
"""
$(TYPEDSIGNATURES)

Return number of species for edge
"""
@inline num_species(edge::AbstractEdge)=edge.nspec

##################################################################
"""
$(TYPEDSIGNATURES)

Calculate the length of an edge.
"""
function meas(edge::AbstractEdge)
    l=0.0
    for i=1:size(edge.coord)[1]
        d=edge.coord[i,edge.node[1]]-edge.coord[i,edge.node[2]]
        l=l+d*d
    end
    return sqrt(l)
end

edgelength(edge::AbstractEdge)=meas(edge)

function project(edge::Edge,vec)
    vh=0.0
    for i=1:size(edge.coord)[1]
        vh+=(edge.coord[i,edge.node[2]]-edge.coord[i,edge.node[1]])*vec[i]
    end
    return vh
end

###############################################################
# Deprecation warnings here ?
"""
$(TYPEDEF)

Wrapper struct for viewing unknowns passed to callback functions

$(TYPEDFIELDS)
"""
struct VectorUnknowns{T} <:AbstractVector{T}
    val::Vector{T}
    n::Int64
    offset::Int64
end

"""
$(TYPEDSIGNATURES)

Construct vector unknowns on edge.
"""
unknowns(edge::AbstractEdge, u::Vector{T},i) where T = VectorUnknowns{T}(u,edge.nspec,(i-1)*(edge.nspec))
Base.getindex(u::VectorUnknowns,i)=@inbounds u.val[u.offset+i]
Base.size(u::VectorUnknowns)=(u.n,)

# For backward compatibility
unknowns(edge,u::AbstractEdgeData)=u
# For backward compatibility
unknowns(edge::Edge, u::AbstractEdgeData{T},i) where T = VectorUnknowns{T}(u.val,edge.nspec,(i-1)*(edge.nspec))

"""
$(TYPEDSIGNATURES)

Solution view on first edge node
"""
viewK(edge::AbstractEdge,u)=unknowns(edge,u,1)

"""
$(TYPEDSIGNATURES)

Solution view on second edge node
"""
viewL(edge::AbstractEdge,u)=unknowns(edge,u,2)


text:
import Distributions.Categorical

immutable HiddenMarkovModel
    initial_state_prior::Array{Float64,1}
    transition_model::Array{Float64,2}
    observation_model::Array{Float64,2}
    log_initial_state_prior::Array{Float64,1}
    log_transition_model::Array{Float64,2}
    log_observation_model::Array{Float64,2}
    num_states::Int
    num_obs::Int

    function HiddenMarkovModel(initial_state_prior::Array{Float64,1},
                               transition_model::Array{Float64,2},
                               observation_model::Array{Float64,2})
        if !isapprox(sum(initial_state_prior), 1.)
            error("initial_state_prior is not normalized: $(initial_state_prior)")
        end
        num_states = size(initial_state_prior)[1]
        if size(transition_model) != (num_states, num_states)
            error("transition_model has wrong dimension: got $(size(transition_model)) expected $((num_states, num_states))")
        end
        if !isapprox(sum(transition_model, 2), ones(num_states, 1))
            error("transition_model rows are not all normalized: got $(sum(transition_model, 2))")
        end
        if size(observation_model)[1] != num_states
            error("observation_model has wrong number of rows: got $(size(observation_model)[1]) expected $num_states")
        end
        num_obs = size(observation_model)[2]
        if !isapprox(sum(observation_model, 2), ones(num_states, 1))
            error("observation_model rows are not all normalized: got $(sum(observation_model, 2))")
        end
        log_initial_state_prior = log.(initial_state_prior)
        log_transition_model = log.(transition_model)
        log_observation_model = log.(observation_model)
        new(initial_state_prior, transition_model, observation_model,
            log_initial_state_prior, log_transition_model, log_observation_model,
            num_states, num_obs)
    end
end

num_states(hmm::HiddenMarkovModel) = hmm.num_states
num_observations(hmm::HiddenMarkovModel) = hmm.num_obs

function hmm_simulate(hmm::HiddenMarkovModel, num_steps::Int)
    states = Array{Int, 1}(num_steps)
    observations = Array{Int, 1}(num_steps)
    states[1] = rand(Categorical(hmm.initial_state_prior))
    for i=2:num_steps
        prev = states[i-1]
        states[i] = rand(Categorical(hmm.transition_model[prev,:]))
    end
    for i=1:num_steps
        observations[i] = rand(Categorical(hmm.observation_model[states[i],:]))
    end
    (states, observations)
end

function hmm_forward_pass(hmm::HiddenMarkovModel, observations::Array{Int, 1})
    # compute the forward probabilities
    # p(x_t, y_{1:t-1}) for t=1,...,T
    # NOTE: we are assuming an observation for each time point
    num_steps = length(observations)
    num_states = hmm.num_states
    fprobs = Array{Float64,2}(num_steps, num_states)
    fprobs[1,:] = hmm.initial_state_prior
    for t=2:num_steps
        obs = observations[t-1]
        message = fprobs[t-1,:] .* hmm.observation_model[:,obs]
        # rows are x_{t-1}, cols are x_t
        product = message .* hmm.transition_model
        fprobs[t,:] = vec(sum(product, 1)) # sum over rows
    end
    return fprobs
end

function hmm_log_forward_pass(hmm::HiddenMarkovModel,
                              observations::Array{Int, 1})
    # compute the log forward probabilities
    # log p(x_t, y_{1:t-1}) for t=1,...,T
    # NOTE: we are assuming an observation for each time point
    num_steps = length(observations)
    num_states = hmm.num_states
    lfprobs = Array{Float64,2}(num_steps, num_states)
    lfprobs[1,:] = hmm.log_initial_state_prior
    for t=2:num_steps
        obs = observations[t-1]
        lmessage = lfprobs[t-1,:] .+ hmm.log_observation_model[:,obs]
        # rows are x_{t-1}, cols are x_t; sum over rows
        lproduct = lmessage .+ hmm.log_transition_model
        lfprobs[t,:] = logsumexp(lproduct, 1)
    end
    return lfprobs
end

function hmm_marginal_likelihood(hmm::HiddenMarkovModel,
                                 observations::Array{Int, 1})
    # use the forward probability p(x_T, y_{1:T-1})
    fprobs = hmm_forward_pass(hmm, observations)
    # p(y_{1:T}) = sum_{x_T} p(x_T, y_{1:T-1}) p(y_T | x_T)
    sum(fprobs[end,:] .* hmm.observation_model[:,observations[end]])
end

function hmm_log_marginal_likelihood(hmm::HiddenMarkovModel,
                                 observations::Array{Int, 1})
    lfprobs = hmm_log_forward_pass(hmm, observations)
    logsumexp(lfprobs[end,:] .+ hmm.log_observation_model[:,observations[end]])
end

function hmm_posterior_sample(hmm::HiddenMarkovModel,
                              observations::Array{Int, 1})
    num_steps = length(observations)
    lfprobs = hmm_log_forward_pass(hmm, observations)
    ldist = lfprobs[end,:] .+ hmm.log_observation_model[:,observations[end]]
    particle = Array{Int,1}(num_steps)
    particle[end] = rand(Categorical(exp.(ldist - logsumexp(ldist))))
    for t = num_steps-1:-1:1
        ldist = lfprobs[t,:]
        ldist = ldist .+ hmm.log_observation_model[:,observations[t]]
        ldist = ldist .+ hmm.log_transition_model[:,particle[t+1]]
        dist = exp.(ldist - logsumexp(ldist))
        particle[t] = rand(Categorical(dist))
    end
    particle
end

function hmm_log_joint_probability(hmm::HiddenMarkovModel,
                                   x::Array{Int,1},
                                   observations::Array{Int,1})
    if length(x) != length(observations)
        error("length(x) != length(observations)")
    end
    lj = hmm.log_initial_state_prior[x[1]]
    for t=2:length(x)
        lj += hmm.log_transition_model[x[t-1], x[t]]
    end
    for t=1:length(x)
        lj += hmm.log_observation_model[x[t], observations[t]]
    end
    lj
end

# -- Helper functions for SMC in HMM using prior proposals

immutable HMMPriorInitializer
    hmm::HiddenMarkovModel
    observation::Int # should be the first observation
end

function forward(init::HMMPriorInitializer)
    particle = Array{Int,1}([rand(Categorical(init.hmm.initial_state_prior))])
    log_weight = init.hmm.log_observation_model[particle[1], init.observation]
    (particle, log_weight)
end

function backward(init::HMMPriorInitializer, particle::Array{Int,1})
    @assert length(particle) == 1
    init.hmm.log_observation_model[particle[1], init.observation]
end

immutable HMMPriorIncrementer
    hmm::HiddenMarkovModel
    observation::Int
end

function forward(incr::HMMPriorIncrementer, particle::Array{Int,1})
    prev = particle[end]
    cur = rand(Categorical(incr.hmm.transition_model[prev,:]))
    log_weight = incr.hmm.log_observation_model[cur, incr.observation]
    new_particle = vcat(particle, [cur])
    (new_particle, log_weight)
end

function backward(incr::HMMPriorIncrementer, new_particle::Array{Int,1})
    cur = new_particle[end]
    log_weight = incr.hmm.log_observation_model[cur, incr.observation]
    particle = new_particle[1:end-1]
    (particle, log_weight)
end

function HMMPriorSMCScheme(hmm::HiddenMarkovModel,
                           observations::Array{Int,1},
                           num_particles::Int)
    initializer = HMMPriorInitializer(hmm, observations[1])
    incrementers = Array{Any,1}(length(observations) - 1)
    for i = 2:length(observations)
        incrementers[i-1] = HMMPriorIncrementer(hmm, observations[i])
    end
    SMCScheme(initializer, incrementers, num_particles)
end

# -- Helper functions for SMC in HMM using conditonal (optimal) proposals

immutable HMMConditionalInitializer
    hmm::HiddenMarkovModel
    observation::Int
    dist::Categorical
    log_weight::Float64
    function HMMConditionalInitializer(hmm::HiddenMarkovModel, observation::Int)
        lprior = hmm.log_initial_state_prior
        llikelihood = hmm.log_observation_model[:,observation]
        ldist = lprior .+ llikelihood
        log_weight = logsumexp(ldist)
        # log normalized distribution
        ldist = ldist - log_weight
        dist = Categorical(exp.(ldist))
        new(hmm, observation, dist, log_weight)
    end
end

function forward(init::HMMConditionalInitializer)
    # p(x_1 | y_1)
    particle = Array{Int,1}([rand(init.dist)])
    (particle, init.log_weight)
end

function backward(init::HMMConditionalInitializer, particle::Array{Int,1})
    @assert length(particle) == 1
    # p(y_1) = sum_{x_1} p(x_1) p(y_1 | x_1)
    init.log_weight
end

immutable HMMConditionalIncrementer
    hmm::HiddenMarkovModel
    observation::Int
    llikelihood::Array{Float64,1}
    function HMMConditionalIncrementer(hmm::HiddenMarkovModel, observation::Int)
        llikelihood = hmm.log_observation_model[:,observation]

        new(hmm, observation, llikelihood)
    end
end

function forward(incr::HMMConditionalIncrementer, particle::Array{Int,1})
    cur = particle[end]
    lprior = incr.hmm.log_transition_model[cur,:]
    ldist = lprior .+ incr.llikelihood
    # p(x_t | x_{t-1}, y_t)
    log_weight = logsumexp(ldist)
    new_component = rand(Categorical(exp.(ldist - log_weight)))
    new_particle = vcat(particle, [new_component])
    (new_particle, log_weight)
end

function backward(incr::HMMConditionalIncrementer, new_particle::Array{Int,1})
    cur = new_particle[end]
    lprior = incr.hmm.log_transition_model[cur,:]
    ldist = lprior .+ incr.llikelihood
    # p(y_t | x_{t-1}) = sum_{x_t} p(x_t | x_{t-1}) p(y_t | x_t)
    log_weight = logsumexp(ldist)
    particle = new_particle[1:end-1]
    (particle, log_weight)
end

function HMMConditionalSMCScheme(hmm::HiddenMarkovModel,
                                 observations::Array{Int,1},
                                 num_particles::Int)
    initializer = HMMConditionalInitializer(hmm, observations[1])
    incrementers = Array{Any,1}(length(observations) - 1)
    for i = 2:length(observations)
        incrementers[i-1] = HMMConditionalIncrementer(hmm, observations[i])
    end
    SMCScheme(initializer, incrementers, num_particles)
end


text:
const functions = Dict{String,Function}(
    "foo" => x -> 42 + x,
    "bar" => x -> 42 * x)

@show functions["foo"](3)
@show functions["bar"](3)

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
#jl #! format: off
# # Parsing Tabular Data

# **Originally Contributed by**: Clayton Barrows

# ## Introduction

# An example of how to parse tabular files (CSV) files similar to the format established in
# the [RTS-GMLC](github.com/gridmod/rts-gmlc/RTS_Data/SourceData) and create a `System` using
# [PowerSystems.jl](github.com/NREL-SIIP/PowerSystems.jl)

# ### Dependencies
using PowerSystems
using TimeSeries
using Dates

# ### Fetch Data
# PowerSystems.jl links to some test data that is suitable for this example.
# Let's download the test data
PowerSystems.download(PowerSystems.TestData; branch = "master") # *note* add `force=true` to get a fresh copy
base_dir = pkgdir(PowerSystems);

# ### The tabular data format relies on a folder containing `*.csv` files and a `user_descriptors.yaml` file
# First, we'll read the tabular data
RTS_GMLC_DIR = joinpath(base_dir, "data", "RTS_GMLC");
rawsys = PowerSystems.PowerSystemTableData(
    RTS_GMLC_DIR,
    100.0,
    joinpath(RTS_GMLC_DIR, "user_descriptors.yaml"),
    timeseries_metadata_file = joinpath(RTS_GMLC_DIR, "timeseries_pointers.json"),
    generator_mapping_file = joinpath(RTS_GMLC_DIR, "generator_mapping_multi_start.yaml"),
)

# ### Create a `System`
# Next, we'll create a `System` from the `rawsys` data. Since a `System` is predicated on a
# time series resolution and the `rawsys` data includes both 5-minute and 1-hour resolution
# time series, we also need to specify which time series we want to include in the `System`.
# The `time_series_resolution` kwarg filters to only include time series with a matching resolution.

sys = System(rawsys; time_series_resolution = Dates.Hour(1));
horizon = 24;
interval = Dates.Hour(24);
transform_single_time_series!(sys, horizon, interval);
sys

max_stars_repo_name: NREL-SIIP/Examples

max_issues_repo_name: NREL-SIIP/Examples

max_forks_repo_name: NREL-SIIP/Examples


text:
using Random
using SHTOOLS
using Test

include("test_legendre.jl")
include("test_transforms.jl")
include("test_storage.jl")
include("test_misc.jl")


text:
using Flux
using Tracker

struct Embedding
    table
end

Embedding(voc_size, feature_size) = Embedding(Flux.glorot_normal(voc_size, feature_size))

(e::Embedding)(x) = e.table[x, :]

function (e::Embedding)(x::AbstractArray{T, 2}) where {T}
    out = e.table[x, :]
    return(permutedims(out, (1, 3, 2)))
end

@Flux.treelike Embedding

model = Embedding(100, 16) # feature-size=16
input = rand(1:100, (10,32)) # input-size=10, batch-size=32

out = model(input) # input-size x feature-size x batch-size
println("$out")

#loss(x) = sum(model(x)) # not actually meaningful, just as a test
#loss(input)

#Tracker.gradient(params(model)) do
#    loss(input)
#end


text:
module SnoopCompileCore

using Core: MethodInstance, CodeInfo

# @snoopi and @snoopc are exported from their files of definition

include("snoopc.jl")

if VERSION >= v"1.2.0-DEV.573"
    include("snoopi.jl")
end

if VERSION >= v"1.6.0-DEV.1190"  # https://github.com/JuliaLang/julia/pull/37749
    include("snoopi_deep.jl")
end

if VERSION >= v"1.6.0-DEV.154"
    include("snoopr.jl")
end

if VERSION >= v"1.6.0-DEV.1192"  # https://github.com/JuliaLang/julia/pull/37136
    include("snoopl.jl")
end

end


text:
mutable struct Model
    config
    worddict
    nn
end

function Model(config)
    traindata, testdata, worddict = readdata(config)
    nn = NN_LSTM(Float32, length(worddict))
    m = Model(config, worddict, nn)
    train!(m, traindata, testdata)
    m
end

function train!(model, traindata, testdata)
    config = model.config
    device = config["device"]
    nn = todevice(model.nn, device)
    traindata = DataLoader(traindata, device=device, batchsize=config["seqlength"])
    testdata = DataLoader(testdata, device=device, batchsize=1)

    for epoch = 1:config["nepochs"]
        println("Epoch:\t$epoch")
        opt.rate = config["learning_rate"]
        println("Learning rate: $(opt.rate)")

        loss = fit!(traindata, nn)
        loss /= length(traindata.data.data)
        println("Loss:\t$loss")
        #perplexity = 2^loss
        #println("Perplexity:\t$perplexity")

        println()
    end
end


text:
function RKn(   ::Type{T},
                ::Type{Tprog},
                N::Int,
                X::AbstractVector,
                α::Real,
                F::Real,
                s::Real,
                Δt::Real,
                output::Bool;
                RKo::Int=4) where {T<:AbstractFloat,Tprog<:AbstractFloat}

    # number of variables
    n = length(X)

    # preallocate for storing results - store without scaling
    if output
        Xout = Array{Tprog,2}(undef,n,N+1)
        Xout[:,1] = Tprog.(X)
    end

    if RKo == 4     # Runge Kutta 4th order coefficients including time step
        RKα = [1/6.,1/3.,1/3.,1/6.]*Δt
        RKβ = [1/2.,1/2.,1.]*Δt
    elseif RKo == 3
        RKα = [1/4.,0.,3/4.]*Δt
        RKβ = [1/3.,2/3.]*Δt
    elseif RKo == 2
        RKα = [1/2.,1/2.]*Δt
        RKβ = [1.]*Δt
    else
        throw(error("RKo = $RKo not implemented."))
    end

    # convert everything to the desired number system determined by T and scale
    X = Tprog.(X*s)
    α = convert(T,α)
    F = convert(T,F*s)
    s_inv = convert(T,inv(s))
    RKα = Tprog.(RKα)
    RKβ = Tprog.(RKβ)

    # preallocate memory for intermediate results
    X0 = deepcopy(X)
    X1 = deepcopy(X)                # prognostic variables of type Tprog
    X1rhs = zeros(T,size(X1))       # prognostic variables when converted to type T
    dXrhs = zeros(T,size(X))        # tendencies of type T
    dX = zeros(Tprog,size(X))       # tendencies when converted to type Tprog

    for i = 1:N
        copyto!(X1,X)

        for rki = 1:RKo
            X1rhs = convert(X1rhs,X1)
            rhs!(dXrhs,X1rhs,α,F,s_inv)
            dX = convert(dX,dXrhs)          # change from T to Tprog

            if rki < RKo
                @inbounds for j in eachindex(X)
                    X1[j] = X[j] + dX[j] * RKβ[rki]
                end
            end

            # sum the RK steps on the go
            @inbounds for j in eachindex(X0)
                X0[j] += dX[j] * RKα[rki]
            end
        end

        copyto!(X,X0)

        if output
            Xout[:,i+1] = X*s_inv
        end
    end

    if output
        return Xout
    else
        return X
    end
end

"""Convert function for two 1-dim arrays, X1, X2, in case their eltypes differ. Convert every element from X1 and store it in X2."""
function Base.convert(X2::Array{T2,1},X1::Array{T1,1}) where {T1<:AbstractFloat,T2<:AbstractFloat}
    m = length(X2)
    @boundscheck m == length(X1) || throw(BoundsError())

    @inbounds for i in 1:m
            X2[i] = convert(T2,X1[i])
    end

    return X2
end

"""Convert function for two 1-dim arrays, X1, X2, in case their eltypes are identical.
Just pass X1, such that X2 is pointed to the same place in memory."""
function Base.convert(X2::Array{T,1},X1::Array{T,1}) where {T<:AbstractFloat}
    m = length(X2)
    @boundscheck m == length(X1) || throw(BoundsError())
    return X1
end


text:
mutable struct SymbolicCone
    V::Array{Int64,2}
    q::Array{Float64,1}
    o::Array{Bool,1}
    sign::Int
    fp:: Array{Array{Int64},1}
    ratfun:: Any
    SymbolicCone(V::Array{Int64,2}, q::Array{Float64,1}, o::Array{Bool,1}, fp::Array{Array{Int64},1}, ratfun::Any, sign::Int=1) =
        new(V, q, o, sign, fp, ratfun)
    SymbolicCone(V::Array{Int64,2}, q::Array{Float64,1}, o::Array{Bool,1}, sign::Int=1) =
        new(V, q, o, sign)
end

function Base.println(C::SymbolicCone)
    println("Symbolic Cone: \t", C.V, "\t", C.q, "\t", C.o, "\t", C.sign, "\n")
end

function Base.isequal()
    return true;
end

max_stars_repo_name: kevseryolcu/PolyhedralOmega

max_issues_repo_name: kevseryolcu/PolyhedralOmega

max_forks_repo_name: kevseryolcu/PolyhedralOmega


text:
export consistenceCheck, generateHeaderDictOnline
import Base: ndims
import MPIFiles: calibSize, calibFov, filterFrequencies
if VERSION >= v"1.0.0"
  export squeeze
else
  import Base: squeeze
end
squeeze(A) = dropdims(A, dims=tuple(findall(([size(A)...].==1))...))

function generateHeaderDict(bSF::MPIFile, b::MPIFile)
  #header["spatialorder"] TODO
  header = loadMetadata(b)
  header["datatype"] = "MPI"
  header["dim"] = ndims(b)
  header["size"] = calibSize(bSF)
  return header
end

const onlineParams = [:version, :uuid, :time, :dfStrength, :acqGradient,
  :scannerFacility, :scannerOperator, :scannerManufacturer, :scannerName,
  :scannerTopology, :acqFramePeriod, :acqNumPeriodsPerFrame, :acqNumAverages,
  :acqStartTime, :acqOffsetField, :acqOffsetFieldShift,
  :dfNumChannels, :dfPhase, :dfBaseFrequency, :dfDivider,
  :dfCycle, :dfWaveform, :rxNumChannels, :rxBandwidth,
  :rxNumSamplingPoints, :rxTransferFunction] # needs to be extended
  # :tracerName, :tracerBatch, :tracerVendor, :tracerVolume, :tracerConcentration,
  # :tracerSolute, :tracerInjectionTime,
function generateHeaderDictOnline(bSF::MPIFile, b::MPIFile)
   header = loadMetadata(b, onlineParams)
   header["datatype"] = "MPI"
   header["dim"] = ndims(b)
   header["size"] = calibSize(bSF)
  return header
end

# multi patch fallback
generateHeaderDict(bSF::MPIFile, b::Vector) = generateHeaderDict(bSF,b[1])

function consistenceCheck(bSF::MPIFile, bMeas::MPIFile)
  gSF = acqGradient(bSF)[:,:,1,1]
  gMeas = acqGradient(bMeas)[:,:,1,1]
  if gSF != gMeas
    @warn("The gradient strength of the system matrix ($gSF T/m) does not fit to the measurements ($gMeas T/m)!")
  end

  dfSF = dfStrength(bSF)
  dfMeas = dfStrength(bMeas)
  if dfSF[:,1] != dfMeas[:,1]
    @warn("The drive-field strength of the system matrix ($dfSF mT) does not fit to the measurements ($dfMeas mT)!")
  end

end

function consistenceCheck(bSFs::Vector{T}, bMeas::MPIFile) where {T<:MPIFile}
  for bSF in bSFs
    consistenceCheck(bSF,bMeas)
  end
end

function consistenceCheck(bSF::MPIFile, bMeass::Vector{T}) where {T<:MPIFile}
  for bMeas in bMeass
    consistenceCheck(bSF,bMeas)
  end
end
function consistenceCheck(bSFs::Vector{T}, bMeass::Vector{T}) where {T<:MPIFile}
  for i = 1:length(bMeass)
    bMeas=bMeass[i]
    bSF=bSFs[i]
    consistenceCheck(bSF,bMeas)
  end
end

### deprecated function names
acqDate(b) = acqStartTime(b)
subjectName(b) = experimentSubject(b)
scanName(b) = experimentName(b)
expno(b) = experimentNumber(b)
numAverages(b) = acqNumAverages(b)
frequencies(b) = rxFrequencies(b)
operator(b) = scannerOperator(b)
numReceivers(b) = rxNumChannels(b)
bandwidth(b) = rxBandwidth(b)
tracer(b) = tracerName(b)
description(b) = experimentDescription(b)
getSNRAllFrequencies(b) = calibSNR(b)[:,:,1]
measPath(b::BrukerFile) = b.path
measPath(b::MDFFile) = b.filename
gridSize(b::MPIFile) = squeeze(calibSize(b))
gridSizeCommon(bs::MPIFile) = gridSize(bs)
fov(b::MPIFile) = calibFov(b)
sfGradient(b::MPIFile) = diag(acqGradient(b)[:,:,1,1])
sfGradient(b::MPIFile,dim) = sfGradient(b)[dim]
numFreq(b::MPIFile) = rxNumFrequencies(b)
ffPos(b::MPIFile; kargs...) = squeeze(acqOffsetFieldShift(b))
function ffPos(b::Vector{T}; alpha=[0,0,0]) where {T<:BrukerFile} # this seems to be wrong
  fovCenter = zeros(3,length(b))
  for l=1:length(b)
    fovCenter[:,l] = ffPos(b[l], alpha=alpha)
  end
  return fovCenter
end
numScans(b) = acqNumFrames(b)
dfcycle(b::MPIFile) = dfCycle(b)
ndims(b::MPIFile) = sum( (dfStrength(b) .> 0.00001) )
numPatches(b) = acqNumPeriodsPerFrame(b)
voxelSize(b::MPIFile) = fov(b) ./ gridSize(b)
voxelVolume(b::MPIFile) = prod( voxelSize(b) ) * 1000 #in Liter
dfFov(b) = squeeze(acqFov(b))
numTimePoints(b::MPIFile) = rxNumSamplingPoints(b)

# Multi-Patch setting
function filterFrequencies(bSFs::MultiMPIFile; kargs...)
  return union([filterFrequencies(bSF; kargs...) for bSF in bSFs]...)
end

function rowEnergy(A::AbstractMatrix{Complex{T}}) where T
  M = size(A,1)
  energy = zeros(T, M)
  for m=1:M
    energy[m] = sqrt(rownorm²(A,m))
  end

  return energy
end

function rowEnergy(A::AbstractMatrix{T}) where {T<:Real}
  M = size(A,1)
  energy = zeros(T, M)
  for m=1:M
    energy[m] = sqrt(rownorm²(A,m))
  end

  return energy
end

function normalizeRows!(A::AbstractMatrix, u)
  energy = rowEnergy(A)
  for m=1:length(energy)
    if energy[m] > 0
      A[:,m] /= energy[m]
      u[m,:] /= energy[m]
    end
  end

  return energy
end

function calculateNoise(x; sizeRegion = 5)
  xHat = fft(x)

  multIdx = UnitRange{Int64}[]
  for d=1:ndims(x)
    sr = floor(Int, min(size(xHat,d)/2-1, sizeRegion) )
    push!(multIdx, floor(Int,size(xHat,d)/2-sr):floor(Int,size(xHat,d)/2+sr))
  end

  xHatSub = (xHat[multIdx...])[:]

  noise = norm(xHatSub, 2) / sqrt(length(xHatSub)*length(xHat) )

  # sigma = weight*sqrt(1/(N-1))*norm(S,2); from Alex code

  return noise
end

function calculateSNR(x)
  signal = norm(x[:],Inf)
  noise = calculateNoise(x)

  if noise == 0 || signal == 0
    SNR = 0
  else
    SNR = signal/noise
  end
  return SNR
end

function calculateTraceOfNormalMatrix(A::AbstractMatrix, weights::Vector)
  energy = rowEnergy(A)

  trace = norm(weights[1:size(A)[1]] .* energy)^2
  return trace
end

function calculateTraceOfNormalMatrix(A::AbstractMatrix, weights::Nothing)
  energy = rowEnergy(A)
  return  norm(energy)^2
end

function constraint!(x, enforcePositive, enforceReal)
  enforceReal ? enfReal!(x) : nothing
  enforcePositive ? enfPos!(x) : nothing
end

softThreshold(x,sigma) = (abs(x) > sigma)*sign(x)*(abs(x)-sigma)


text:
module CliOptions

Combiner = Union{Function,Nothing}

"""
    CliOptionError(msg::String)

An error occurred inside `CliOptions` module. Message describing the error is available in
the `msg` field.
"""
struct CliOptionError <: Exception
    msg::String
end

Base.showerror(io::IO, e::CliOptionError) = print(io, e.msg)

"""
    CliOptions.AbstractOption

Abstract supertype representing a command line option. Concrete subtypes are:

- [`Option`](@ref) ... an option which takes a following argument as its value
- [`FlagOption`](@ref) ... an option of which existence becomes its boolean value
- [`CounterOption`](@ref) ... an option of which number of usage becomes its integer value
- [`Positional`](@ref) ... an argument which is not an option

Note that a group of options represented with `AbstractOptionGroup` is also an
`AbstractOption` so it can be used to construct `CliOptionSpec`.
"""
abstract type AbstractOption end

function Base.show(io::IO, x::AbstractOption)
    print(io, typeof(x), "(", join([":" * encode(name) for name in x.names], ','), ")")
end
Base.show(x::AbstractOption) = show(stdout, x)

"""
    CliOptions.AbstractOptionGroup

Abstract type representing a group of command line options. Concrete subtypes are:

- [`OptionGroup`](@ref)
- [`MutexGroup`](@ref)
"""
abstract type AbstractOptionGroup <: AbstractOption end

function Base.show(io::IO, x::AbstractOptionGroup)
    print(io, typeof(x), "(", join([repr(o) for o in x], ','), ")")
end
Base.show(x::AbstractOptionGroup) = show(stdout, x)

Base.length(o::AbstractOptionGroup) = length(o.options)

function Base.iterate(o::AbstractOptionGroup)
    1 ≤ length(o.options) ? (o.options[1], 2) : nothing
end

function Base.iterate(o::AbstractOptionGroup, state)
    state ≤ length(o.options) ? (o.options[state], state + 1) : nothing
end

"""
    CliOptions.ParseResult()

Dict-like object holding parsing result of command line options. The values can be accessed
using either:

1. dot notation (e.g.: `result.num_workers`)
2. bracket notation (e.g.: `result["num_workers"]`)

This is the type [`parse_args`](@ref) function returns. If the function detected errors,
it stores error messages into `_errors` field of this type. This may be useful if you let
the program continue running on errors (see `onerror` parameter of `CliOptionSpec`).
"""
mutable struct ParseResult
    _defaults
    _argvals
    _resolved
    _errors

    function ParseResult(argvals = Dict{String,Any}(),
                         defaults = Dict{String,Tuple{Any,Combiner}}(),
                         errors = String[])
        # Generate merged dictionary
        resolved = Dict{String,Any}()
        for (k, (v, _)) in defaults
            resolved[k] = v
        end
        for (k, v) in argvals
            if haskey(defaults, k)
                _, combiner = defaults[k]
                if combiner !== nothing
                    resolved[k] = combiner(resolved[k], v)  # combine the old with the new
                else
                    resolved[k] = v  # overwrite the old with the new
                end
            else
                resolved[k] = v  # add new entry for the new default value
            end
        end

        new(defaults, argvals, resolved, errors)
    end
end

function Base.show(io::IO, x::ParseResult)
    print(io, typeof(x), "(", join([":$k" for k in sort(propertynames(x))], ','), ")")
end

Base.show(x::ParseResult) = show(stdout, x)

function Base.getindex(result::ParseResult, key)
    k = key isa Symbol ? String(key) : key
    getindex(result._resolved, k)
end

function Base.propertynames(result::ParseResult; private = false)
    props = [Symbol(k) for (k, v) in getfield(result, :_resolved)]
    if private
        push!(props, :_argvals, :_defaults, :_errors, :_resolved)
    end
    sort!(props)
end

function Base.getproperty(result::ParseResult, name::Symbol)
    if name in (:_argvals, :_defaults, :_errors, :_resolved)
        return getfield(result, name)
    else
        return getfield(result, :_resolved)[String(name)]
    end
end

"""
    Option([type=String,] primary_name::String, secondary_name::String = "";
           default = missing, until = nothing, requirement = nothing, help = "")

Type representing a command line option whose value is a following argument. Two forms of
option notations are supported:

1. Short form (e.g.: `-n 42`)
   - Starting with a dash, one character follows it
   - A following command line argument will be the option's value
2. Long form (e.g.: `--foo-bar`)
   - Starting with two dash, dash-separated words follow them
   - Value can be specified as one of the two forms below:
     1. `--foo-bar value`; a following command line argument becomes the option's value
     2. `--foo-bar=value`; characters after an equal sign following the option name becomes
        the option's value

An Option can have two names. `primary_name` is typically a short form notation and is also
used to express the option in a usage message or error messages. `secondary_name` is
typically a long form notation and is also used to generate a value name in a usage message.
For example, if names of an option are `-n` and `--foo-bar`, it will appear in a usage
message as `-n FOO_BAR`. If you want to define an option which have only a long form
notation, specify it as `primary_name` and omit `secondary_name`.

If `type` parameter is set, option values will be converted to the type inside `parse_args`
and will be stored in returned `ParseResult`.

`default` parameter is used when `parse_args` does not see the option in the given command
line arguments. If a value other than `missing` was specified, it will be the option's
value. If it's `missing`, absense of the option is considered as an error; in other word,
the option becomes a *required* option. The default value of `default` parameter is
`missing`.

If `until` parameter is specified, following arguments will be collected into a vector to be
the option's value until an argument which is or one of the `until` parameter appears. In
this case, type of the option's value will be `Vector{T}` where `T` is the type specified
with `type` parameter. `until` parameter can be a string, a vector or tuple of strings, or
`nothing`. Default value is `nothing`; no collection will be done.

`requirement` determines how to validate the option's value. If the option's value does not
meet the requirement, it's considered an error. `requirement` can be one of:

1. `nothing`
   - Any value will be accepted
2. A list of acceptable values
   - Arguments which matches one of the values will be accepted
   - Any iterable can be used to specify acceptable values
   - Arguments will be converted to the specified type and then compared to each element of
     the list using function `==`
3. A `Regex`
   - Arguments which matches the regular expression will be accepted
   - Pattern matching will be done for unprocessed input string, not type converted one
4. A custom validator function
   - It validates command line arguments one by one
   - It can return a `Bool` which indicates whether a given argument is acceptable or not
   - It also can return a `String` describing why a given command line argument is NOT
     acceptable, or an empty `String` if it is acceptable

If you want an option which does not take a command line argument as its value, see
[`FlagOption`](@ref) and [`CounterOption`](@ref)
"""
struct Option <: AbstractOption
    names::Union{Tuple{String},Tuple{String,String}}
    T::Type
    default::Any
    until::Union{Nothing,String,Vector{String},Tuple{Vararg{String}}}
    requirement::Any
    help::String

    function Option(T::Type, primary_name::String, secondary_name::String = "";
                    default::Any = missing, until = nothing,
                    requirement::Any = nothing, help::String = "")
        names = secondary_name == "" ? (primary_name,) : (primary_name, secondary_name)
        _validate_option_names(Option, names)
        new(names, T, default, until, requirement, help)
    end
end

function Option(primary_name::String, secondary_name::String = "";
                default::Any = missing, until = nothing, requirement::Any = nothing,
                help::String = "")
    Option(String, primary_name, secondary_name;
           default = default, until = until, requirement = requirement, help = help)
end

function set_default!(d::Dict{String,Tuple{Any,Combiner}}, o::Option)
    for name in o.names
        d[encode(name)] = (o.default, nothing)
    end
end

function consume!(d::Dict{String,Any}, o::Option, args, ctx)
    @assert 1 ≤ length(args)
    @assert "" ∉ o.names
    @assert all(o isa AbstractOption for o in ctx.all_options)

    if args[1] ∉ o.names
        return 0
    end
    if o.until === nothing
        # Ensure at least one argument is available
        if length(args) < 2
            throw(CliOptionError("A value is needed for option \"$(args[1])\""))
        end

        # Update counter
        ctx.usage_count[o] = get(ctx.usage_count, o, 0) + 1

        # Parse the argument as value
        value = _parse(o.T, args[2], o.requirement; optname = args[1])
        for name in o.names
            d[encode(name)] = value
        end
        return 2
    else
        _match(term, arg) = begin
            if term isa String
                arg == term
            else
                arg in term
            end
        end

        # Scan for the last argument
        term_index = 2
        while !_match(o.until, args[term_index])
            if length(args) == term_index
                msg = "\"$(o.names[1])\" needs \"$(o.until)\" as an end-mark"
                throw(CliOptionError(msg))
            end
            term_index += 1
        end

        # Update counter
        ctx.usage_count[o] = get(ctx.usage_count, o, 0) + 1

        # Parse the arguments as value
        values = o.T[]
        for j = 2:term_index-1
            value = _parse(o.T, args[j], o.requirement; optname = args[1])
            push!(values, value)
        end
        for name in o.names
            d[encode(name)] = values
        end
        return term_index
    end
end

function check_usage_count(o::Option, ctx)
    # Throw if it's required but was omitted
    if ismissing(o.default) && get(ctx.usage_count, o, 0) ≤ 0
        msg = "Option \"$(o.names[1])\" must be specified"
        throw(CliOptionError(msg))
    end
end

function to_usage_tokens(o::Option)
    tokens = [o.names[1] * " " * _to_placeholder(o.names)]
    if !ismissing(o.default)
        tokens[1] = "[" * tokens[1]
        tokens[end] = tokens[end] * "]"
    end
    tokens
end
function print_description(io::IO, o::Option)
    print_description(io, o.names, _to_placeholder(o.names), o.help)
end

"""
    HelpOption(names = ("-h", "--help"); [help::String])

Options for printing help (usage) message.

The default value of `names` are `-h` and `--help`. If you do not like to have `-h` for
printing help message, just give `--help` for `names` parameter (i.e.:
`HelpOption("--help"; ...)`).

The default behavior for a help option is printing help message and exiting. If you do not
like this behavior, use `onhelp` parameter on constructing [`CliOptionSpec`](@ref).
"""
struct HelpOption <: AbstractOption
    names
    help::String

    function HelpOption(names::String...; help::String = "Show usage message and exit")
        if length(names) == 0
            names = ("-h", "--help")
        end
        _validate_option_names(HelpOption, names)
        new(names, help)
    end
end

function set_default!(d::Dict{String,Tuple{Any,Combiner}}, o::HelpOption)
    for name in o.names
        d[encode(name)] = (false, nothing)
    end
end

function consume!(d::Dict{String,Any}, o::HelpOption, args, ctx)
    @assert 1 ≤ length(args)
    @assert "" ∉ o.names
    @assert all(o isa AbstractOption for o in ctx.all_options)

    arg = args[1]
    if startswith(arg, "--")
        if arg in o.names
            value = true
        else
            return 0
        end
    elseif startswith(arg, "-")
        @assert length(arg) == 2  # Splitting -abc to -a, -b, -c is done by parse_args()
        if arg in o.names
            value = true
        else
            return 0
        end
    else
        return 0
    end

    # Update counter
    count::Int = get!(ctx.usage_count, o, 0)
    ctx.usage_count[o] = count + 1

    # Construct parsed values
    for name in o.names
        d[encode(name)] = value
    end
    return 1
end

function to_usage_tokens(o::HelpOption)
    ["[" * o.names[1] * "]"]
end

function print_description(io::IO, o::HelpOption)
    print_description(io, o.names, "", o.help)
end

"""
    FlagOption(primary_name::String, secondary_name::String = "";
               negators::Union{String,Vector{String}} = String[],
               help = "",
               negator_help = "")

`FlagOption` represents a so-called "flag" command line option. An option of this type takes
no value and whether it was specified becomes a boolean value.
"""
struct FlagOption <: AbstractOption
    names::Union{Tuple{String},Tuple{String,String}}
    negators::Vector{String}
    help::String
    negator_help::String

    function FlagOption(primary_name::String, secondary_name::String = "";
                        negators::Union{String,Vector{String}} = String[],
                        help = "", negator_help = "")
        names = secondary_name == "" ? [primary_name] : [primary_name, secondary_name]
        if negators isa String
            negators = [negators]
        end
        _validate_option_names(FlagOption, names, negators)
        if negator_help == ""
            negator_help = "Negate usage of " * names[1] * " option"
        end
        new(Tuple(names), [n for n in negators], help, negator_help)
    end
end

function set_default!(d::Dict{String,Tuple{Any,Combiner}}, o::FlagOption)
    for name in o.names
        d[encode(name)] = (false, nothing)
    end
    for name in o.negators
        d[encode(name)] = (true, nothing)
    end
end

function consume!(d::Dict{String,Any}, o::FlagOption, args, ctx)
    @assert 1 ≤ length(args)
    @assert "" ∉ o.names
    @assert all(o isa AbstractOption for o in ctx.all_options)

    arg = args[1]
    if startswith(arg, "--")
        if arg in o.names
            value = true
        elseif arg in o.negators
            value = false
        else
            return 0
        end
    elseif startswith(arg, "-")
        @assert length(arg) == 2  # Splitting -abc to -a, -b, -c is done by parse_args()
        if arg in o.names
            value = true
        elseif arg in o.negators
            value = false
        else
            return 0
        end
    else
        return 0
    end

    # Update counter
    count::Int = get!(ctx.usage_count, o, 0)
    ctx.usage_count[o] = count + 1

    # Construct parsed values
    for name in o.names
        d[encode(name)] = value
    end
    for name in o.negators
        d[encode(name)] = !value
    end
    return 1
end

check_usage_count(o::Union{FlagOption,HelpOption}, ctx) = nothing

function to_usage_tokens(o::FlagOption)
    latter_part = 1 ≤ length(o.negators) ? " | " * o.negators[1] : ""
    ["[" * o.names[1] * latter_part * "]"]
end

function print_description(io::IO, o::FlagOption)
    print_description(io, o.names, "", o.help)
    if 1 ≤ length(o.negators)
        print_description(io, o.negators, "", o.negator_help)
    end
end

"""
    CounterOption([type=Int,] primary_name::String, secondary_name::String = "";
                  decrementers::Union{String,Vector{String}} = String[],
                  default::Signed = 0,
                  help::String = "",
                  decrementer_help = "")

A type represents a flag-like command line option. Total number of times a `CounterOption`
was specified becomes the option's value.
"""
struct CounterOption <: AbstractOption
    names::Union{Tuple{String},Tuple{String,String}}
    decrementers::Vector{String}
    default::Signed
    T::Type
    help::String
    decrementer_help::String

    function CounterOption(T::Type, primary_name::String, secondary_name::String = "";
                           decrementers::Union{String,Vector{String}} = String[],
                           default::Signed = 0,
                           help::String = "",
                           decrementer_help::String = "")
        names = secondary_name == "" ? [primary_name] : [primary_name, secondary_name]
        if decrementers isa String
            decrementers = [decrementers]
        end
        _validate_option_names(CounterOption, names, decrementers)
        if !(T <: Signed)
            throw(ArgumentError("Type of a CounterOption must be a subtype of Signed:" *
                                " \"$T\""))
        end
        if decrementer_help == ""
            decrementer_help = "Opposite of " * names[1] * " option"
        end
        new(Tuple(names), [n for n in decrementers], T(default), T, help, decrementer_help)
    end
end

function CounterOption(primary_name::String, secondary_name::String = "";
                       decrementers::Union{String,Vector{String}} = String[],
                       default::Signed = 0,
                       help::String = "",
                       decrementer_help::String = "")
    CounterOption(Int, primary_name, secondary_name;
                  decrementers = decrementers, default = default, help = help,
                  decrementer_help = decrementer_help)
end

function set_default!(d::Dict{String,Tuple{Any,Combiner}}, o::CounterOption)
    for name in o.names
        d[encode(name)] = (o.T(o.default), +)  # Intentionally allowing overflow/underflow
    end
end

function consume!(d::Dict{String,Any}, o::CounterOption, args, ctx)
    @assert 1 ≤ length(args)
    @assert "" ∉ o.names
    @assert all(o isa AbstractOption for o in ctx.all_options)

    arg = args[1]
    diff = 0
    if startswith(arg, "--")
        if arg in o.names
            diff = +1
        elseif arg in o.decrementers
            diff = -1
        end
    elseif startswith(arg, "-")
        @assert length(arg) == 2  # Splitting -abc to -a, -b, -c is done by parse_args()
        if arg in o.names
            diff = +1
        elseif arg in o.decrementers
            diff = -1
        end
    end
    if diff == 0
        return 0
    end
    value = get(d, encode(o.names[1]), 0) + diff
    if !(typemin(o.T) ≤ value ≤ typemax(o.T))
        throw(CliOptionError("Too many \"$(arg)\""))
    end

    # Update counter
    ctx.usage_count[o] = get(ctx.usage_count, o, 0) + 1

    # Construct parsed values
    for name in o.names
        d[encode(name)] = o.T(value)
    end
    return 1
end

check_usage_count(o::CounterOption, ctx) = nothing

function to_usage_tokens(o::CounterOption)
    latter_part = 1 ≤ length(o.decrementers) ? " | " * o.decrementers[1] : ""
    ["[" * o.names[1] * latter_part * "]"]
end

function print_description(io::IO, o::CounterOption)
    print_description(io, o.names, "", o.help)
    if 1 ≤ length(o.decrementers)
        print_description(io, o.decrementers, "", o.decrementer_help)
    end
end

"""
    Positional([type=String,] singular_name, plural_name = "";
               multiple = false, requirement = nothing,
               default = missing, help = "")

`Positional` represents a command line argument which are not an option name nor an option
value.

`requirement` determines how to validate positional arguments. See explanation of
[Option](@ref) for more detail.
"""
struct Positional <: AbstractOption
    names::Union{Tuple{String},Tuple{String,String}}
    T::Type
    multiple::Bool
    requirement::Any
    default::Any
    help::String

    function Positional(T::Type,
                        singular_name::String,
                        plural_name::String = "";
                        multiple::Bool = false,
                        requirement::Any = nothing,
                        default::Any = missing,
                        help::String = "")
        if singular_name == ""
            throw(ArgumentError("Name of a Positional must not be empty"))
        elseif startswith(singular_name, '-')
            throw(ArgumentError("Name of a Positional must not start with a dash: " *
                                singular_name))
        elseif startswith(plural_name, '-')
            throw(ArgumentError("Name of a Positional must not start with a dash: " *
                                plural_name))
        elseif singular_name == plural_name
            throw(ArgumentError("Duplicate names for a Positional found: " *
                                singular_name))
        end

        if plural_name == ""
            return new((singular_name,), T, multiple, requirement, default, help)
        else
            return new((singular_name, plural_name),
                       T, multiple, requirement, default, help)
        end
    end
end

function Positional(singular_name::String,
                    plural_name::String = "";
                    multiple::Bool = false,
                    requirement::Any = nothing,
                    default::Any = missing,
                    help::String = "")
    Positional(String, singular_name, plural_name;
               multiple = multiple, requirement = requirement, default = default,
               help = help)
end

function set_default!(d::Dict{String,Tuple{Any,Combiner}}, o::Positional)
    for name in o.names
        d[encode(name)] = (o.default, nothing)
    end
end

function consume!(d::Dict{String,Any}, o::Positional, args, ctx)
    @assert 1 ≤ length(args)
    @assert "" ∉ o.names
    @assert all(o isa AbstractOption for o in ctx.all_options)

    # Skip if this node is already processed
    count::Int = get(ctx.usage_count, o, 0)
    max_nvalues = o.multiple ? Inf : 1
    if max_nvalues ≤ count
        return 0
    end
    ctx.usage_count[o] = count + 1

    # Scan values to consume
    values = Vector{o.T}()
    nconsumed = 0
    for arg in args[1:(o.multiple ? length(args) : 1)]
        token_type = _check_option_name(arg)
        if token_type == :double_dash
            # Raise flag if it's first double-dash otherwise consume it
            if ctx.double_dash_found == false
                ctx.double_dash_found = true
                nconsumed += 1
                continue
            end
        elseif ctx.double_dash_found != true && token_type == :valid
            break  # Do not consume an argument which looks like an option
        elseif ctx.double_dash_found != true && token_type == :negative
            if any(name == arg for opt in ctx.all_options for name in opt.names)
                break  # Do not consume an option which looks like a negative number
            end
        end
        push!(values, _parse(o.T, arg, o.requirement))
        nconsumed += 1
    end
    if length(values) == 0
        return 0  # No arguments consumable
    end

    # Store parse result
    for name in o.names
        d[encode(name)] = o.multiple ? values : values[1]
    end

    return nconsumed
end

function check_usage_count(o::Positional, ctx)
    # Throw if it's required but was omitted
    if ismissing(o.default) && get(ctx.usage_count, o, 0) ≤ 0
        msg = "\"$(o.names[1])\" must be specified"
        throw(CliOptionError(msg))
    end
end

function to_usage_tokens(o::Positional)
    name = _to_placeholder(o.names[1])
    if o.multiple
        if ismissing(o.default)
            [name * " [$name...]"]
        else
            ["[$name...]"]
        end
    elseif ismissing(o.default)
        [name]
    else
        ["[$name]"]
    end
end

function print_description(io::IO, o::Positional)
    print_description(io, (_to_placeholder(o.names[1]),), "", o.help)
end

function Base.show(io::IO, x::Positional)
    print(io, typeof(x), "(", join([":$name" for name in x.names], ','), ")")
end
Base.show(x::Positional) = show(stdout, x)

"""
    OptionGroup(options::AbstractOption...; name::String = "")

`OptionGroup` contains one or more `AbstractOption`s and accepts command line arguments if
one of the options is accepted. In other word, this is an OR operator for `AbstractOption`s.
"""
struct OptionGroup <: AbstractOptionGroup
    names::Tuple{String}
    options

    OptionGroup(options::AbstractOption...; name::String = "") = new((name,), options)
end

function set_default!(d::Dict{String,Tuple{Any,Combiner}}, o::OptionGroup)
    for option in o.options
        set_default!(d, option)
    end
end

function consume!(d::Dict{String,Any}, o::OptionGroup, args, ctx)
    for option in o.options
        num_consumed = consume!(d, option, args, ctx)
        if 0 < num_consumed
            return num_consumed
        end
    end
    return 0
end

function check_usage_count(o::OptionGroup, ctx)
    for option in o.options
        check_usage_count(option, ctx)
    end
end

function to_usage_tokens(o::OptionGroup)
    tokens = Vector{String}()
    for option in o.options
        append!(tokens, to_usage_tokens(option))
    end
    tokens
end

function print_description(io::IO, o::OptionGroup)
    if o.names[1] != ""
        println(io, "  " * o.names[1] * ":")
    end
    for option in o.options
        print_description(io, option)
    end
end

"""
    MutexGroup(options::AbstractOption...; name::String = "")

`MutexGroup` contains one or more `AbstractOption`s and accepts command line arguments only
if exactly one of the options was accepted.
"""
struct MutexGroup <: AbstractOptionGroup
    name::String
    options

    MutexGroup(options::AbstractOption...; name::String = "") = new(name, options)
end

function set_default!(d::Dict{String,Tuple{Any,Combiner}}, o::MutexGroup)  # Same as from OptionGroup
    for option in o.options
        set_default!(d, option)
    end
end

function consume!(d::Dict{String,Any}, o::MutexGroup, args, ctx)  # Same as from OptionGroup
    for option in o.options
        num_consumed = consume!(d, option, args, ctx)
        if 0 < num_consumed
            return num_consumed
        end
    end
    return 0
end

function check_usage_count(o::MutexGroup, ctx)
    exceptions = Exception[]
    for option in o.options
        try
            check_usage_count(option, ctx)
        catch ex
            push!(exceptions, ex)
        end
    end
    if length(o.options) - length(exceptions) != 1
        buf = IOBuffer()
        print(buf, "Exactly one of ")
        print(buf, join([x.names[1] for x in o.options], ", ", " or "))
        print(buf, " must be specified")
        msg = String(take!(buf))
        throw(CliOptionError(msg))
    end
end

function to_usage_tokens(o::MutexGroup)
    tokens = Vector{String}()
    append!(tokens, to_usage_tokens(o.options[1]))
    for option in o.options[2:end]
        push!(tokens, "|")
        append!(tokens, to_usage_tokens(option))
    end
    tokens[1] = "{" * tokens[1]
    tokens[end] = tokens[end] * "}"
    tokens
end

function print_description(io::IO, o::MutexGroup)  # Same as from OptionGroup
    if o.name != ""
        println(io, "  " * o.name * ":")
    end
    for option in o.options
        print_description(io, option)
    end
end

"""
    CliOptionSpec(options::AbstractOption...;
                  program = PROGRAM_FILE,
                  use_double_dash = true,
                  onhelp = 0,
                  onerror = 1)

A type representing a command line option specification.

`program` parameter is used for the program name which appears in help (usage) message. If
omitted, `Base.PROGRAM_FILE` will be used.

If `use_double_dash` parameters is `true`, no argument after double dash (`--`) will be
recognized as an option. In this case, the double dash itself will not parsed as an option
nor a positional argument. Note that only the first double dash is treated specially so
double dashes which appeares after it will be recognized as positional arguments. This is
especially useful for programs which launches another program using command line arguments
given to itself.

`onhelp` parameter controls what to do if a [`HelpOption`](@ref) was used. It can be either:

1. An `Integer`
   - The running program will print help message and exit using it as the status code.
2. `nothing`
   - Nothing happens. In this case, the `HelpOption` is treated just like a
     [`FlagOption`](@ref) so you can examine whether it was used or not by examining
     [`ParseResult`](@ref) using its name.
3. A function which takes no arguments
   - Do whatever you want in the function.

The default value is `0`.

`onerror` parameter controls the action when an error was detected on parsing arguments.
Available choices are:

1. An `Integer`
   - The running program will print an error message along with a help message and exit with
     the status code.
2. `nothing`
   - Ignore errors. Note that error messages are stored in `_errors` field of the returning
     [`ParseResult`](@ref) so you can examine them later.
3. A function which takes an error message
   - Example 1) `onerror = (msg) -> (@warn msg)` ... Warn the error but continue processing
   - Example 2) `onerror = error` ... Throw `ErrorException` using `Base.exit`, instead of
     exiting

The default value is `1`.

#### Example: Using a function for `onhelp` parameter

```jldoctest
using CliOptions

spec = CliOptionSpec(
    HelpOption(),
    onhelp = () -> begin
        print_usage(spec, verbose = false)
        # exit(42)  # Use exit() to let the program exit inside parse_args()
    end,
    program = "onhelptest.jl"
)
options = parse_args(spec, ["-h"])  # The program does not exit here
println(options.help)

# output

Usage: onhelptest.jl [-h]
true
```

#### Example: Using a function for `onerror` parameter

```jldoctest
using CliOptions

spec = CliOptionSpec(
    Option("--required-argument"),
    onerror = (msg) -> println("Warning: \$msg"),
)
options = parse_args(spec, String[])
println(repr(options.required_argument))

# output

Warning: Option \"--required-argument\" must be specified
missing
```
"""
struct CliOptionSpec
    root::OptionGroup
    program::String
    use_double_dash::Bool
    onhelp::Any
    onerror::Any

    function CliOptionSpec(options::AbstractOption...;
                           program = PROGRAM_FILE,
                           use_double_dash = true,
                           onhelp = 0,
                           onerror = 0)
        if program == ""
            program = "PROGRAM"  # may be called inside REPL
        end
        new(OptionGroup(options...), program, use_double_dash, onhelp, onerror)
    end
end

function Base.show(io::IO, x::CliOptionSpec)
    print(io, typeof(x), "(", join([repr(o) for o in x.root], ','), ")")
end
Base.show(x::CliOptionSpec) = show(stdout, x)

"""
    print_usage([io::IO], spec::CliOptionSpec; verbose = true)

Write usage (help) message to `io`. Set `false` to `verbose` if you want to print only the
first line of the usage message. If `io` is omitted, message will be written `stdout`.
"""
function print_usage(io::IO, spec::CliOptionSpec; verbose = true)
    print(io, "Usage: $(spec.program) ")
    println(io, join(Iterators.flatten(to_usage_tokens(o) for o in spec.root), " "))
    if verbose
        println(io)
        println(io, "Options:")
        print_description(io, spec.root)
    end
end

function print_usage(spec::CliOptionSpec; verbose = true)
    print_usage(stdout, spec, verbose = verbose)
end

mutable struct ParseContext
    usage_count
    all_options
    double_dash_found::Union{Nothing,Bool}

    ParseContext(use_double_dash = false) = new(Dict{AbstractOption,Int}(),
                                                Vector{AbstractOption}(),
                                                use_double_dash ? false : nothing)
end

"""
    parse_args(spec::CliOptionSpec, args = ARGS)

Parse `args` according to the `spec`.

`spec` is an instance of [`CliOptionSpec`](@ref) which defines how to parse command line
arguments. It is constructed with one or more concrete subtypes of
[`AbstractOption`](@ref)s. See document of `AbstractOption` for full list of its subtypes.

`args` is the command line arguments to be parsed. If omitted, `Base.ARGS` – the command
line arguments passed to the Julia script – will be parsed.

This function returns a [`ParseResult`](@ref) after parsing. It is basically a Dict-like
object holding the values of options.

```jldoctest
using CliOptions

spec = CliOptionSpec(
    Option(Int, "-n", "--num-workers"),
    FlagOption("-i", "--ignore-case"; negators = "--case-sensitive"),
    Positional("root"),
    Positional("pattern", "patterns"; multiple = true);
    program = "myfind"
)

args = parse_args(spec, split("-n 3 -i /var/log *.log", " "))
println("num_workers: ", args.num_workers)
println("ignore_case: ", args.ignore_case)
println("root: ", args.root)
println("patterns: ", args.patterns)

# output

num_workers: 3
ignore_case: true
root: /var/log
patterns: ["*.log"]
```
"""
function parse_args(spec::CliOptionSpec, args = ARGS)
    ctx = ParseContext(spec.use_double_dash)
    defaults = Dict{String,Tuple{Any,Combiner}}()
    argvals = Dict{String,Any}()
    errors = Vector{String}()

    # Store all options in a vector and pick special options
    help_option = nothing
    foreach_options(spec.root) do o
        push!(ctx.all_options, o)
        if o isa HelpOption
            help_option = o
        end
    end

    # Normalize argument list
    args = _normalize_args(args)

    # Collect default values
    for option in spec.root
        set_default!(defaults, option)
    end

    # Parse arguments
    i = 1
    while i ≤ length(args)
        try
            num_consumed = consume!(argvals, spec.root, args[i:end], ctx)
            if num_consumed ≤ 0
                throw(CliOptionError("Unrecognized argument: \"$(args[i])\""))
            end
            i += num_consumed
        catch ex
            push!(errors, _stringify(ex))
            i += 1
        end
    end

    # Take care of omitted options
    for option in (o for o in spec.root.options if get(ctx.usage_count, o, 0) ≤ 0)
        try
            check_usage_count(option, ctx)
        catch ex
            ex::CliOptionError
            push!(errors, ex.msg)
        end
    end

    # Finally, handle help option and errors
    if 1 ≤ get(ctx.usage_count, help_option, 0)
        if spec.onhelp isa Integer
            print_usage(stdout, spec)
            _exit(spec.onhelp)
        elseif spec.onhelp !== nothing
            spec.onhelp()
        end
    end
    for msg in errors
        if spec.onerror isa Integer
            printstyled(stderr, "ERROR: "; color = Base.error_color())
            println(stderr, msg)
            print_usage(stderr, spec)
            _exit(spec.onerror)
        elseif spec.onerror !== nothing
            spec.onerror(msg)
        end
    end

    ParseResult(argvals, defaults, errors)
end

"""
    update_defaults(result::ParseResult, defaults::Dict{String,Any})::ParseResult

Create a new [`ParseResult`](@ref) of which option values are updated by new default values.

`ParseResult` actually remembers the command line arguments and the default values which
were originally defined by [`CliOptionSpec`](@ref). This function firstly updates (merges)
the default values stored in `result` using `defaults`, secondly resolves final option
values, and finally creates and returns a new `ParseResult`.

This function is useful for a program which uses multiple sources of default values.
For example, if you want to resolve option values in the following order:

1. Option values specified as command line argument
2. Option values read from a config file
3. Hard coded default value

you can use this function as below:

```jldoctest
using CliOptions

# Firstly parse arguments normally
spec = CliOptionSpec(
    Option("--config-file"),
    Option("-x"; default = "foo"),
)
args = split("--config-file /path/to/config/file")
options = parse_args(spec, args)
println(options.x)  # We see hard-coded default value

# Let's pretend we loaded a config file and update defaults with it
config = Dict("x" => "bar")
options = update_defaults(options, config)
println(options.x)  # Now we see the default value in the config file

# If the option was specified in command line arguments, update_defaults has no effect
args = split("--config-file /path/to/config/file -x baz")
options = parse_args(spec, args)
options = update_defaults(options, config)
println(options.x)  # We see the value specified in the command line arguments

# output

foo
bar
baz
```
"""
function update_defaults(result::ParseResult, defaults::AbstractDict)::ParseResult
    new_defaults = copy(result._defaults)
    for k in keys(new_defaults)
        if haskey(defaults, k)
            new_defaults[k] = (defaults[k], new_defaults[k][2])
        end
    end
    ParseResult(result._argvals, new_defaults, result._errors)
end

# Internals
function _stringify(e::Exception)
    buf = IOBuffer()
    showerror(buf, e)
    String(take!(buf))
end

encode(s) = replace(replace(s, r"^(--|-|/)" => ""), r"[^0-9a-zA-Z]" => "_")

_to_placeholder(name::String) = uppercase(encode(name))
_to_placeholder(names::Tuple{String}) = uppercase(encode(names[1]))
_to_placeholder(names::Tuple{String,String}) = begin
    uppercase(encode(2 ≤ length(names) ? names[2] : names[1]))
end

function _get_duplicates(iterables::T...) where T
    duplicates = eltype(T)[]
    elements = collect(Iterators.flatten(iterables))
    for i = 1:length(elements)
        for j = i+1:length(elements)
            if elements[i] == elements[j]
                push!(duplicates, elements[i])
            end
        end
    end
    duplicates
end

function foreach_options(f, option::AbstractOption)
    if option isa AbstractOptionGroup
        for o in option.options
            foreach_options(f, o)
        end
    end
    f(option)
end

_exit = Base.exit

function _mock_exit_function(mock)  # Testing utility
    global _exit
    backup = _exit
    _exit = mock
    return _exit
end

function _mock_exit_function(f, mock)  # Testing utility
    backup = _mock_exit_function(mock)
    try
        f()
    finally
        _mock_exit_function(backup)
    end
end

function _normalize_args(args)
    normalized = String[]
    for i = 1:length(args)
        if !startswith(args[i], '-')
            push!(normalized, args[i])
        elseif startswith(args[i], "--")
            kv = split(args[i], '=')
            if length(kv) == 1
                push!(normalized, args[i])  # --foo-bar
            elseif length(kv) == 2
                push!(normalized, kv[1], kv[2])  # --foo-bar=baz
            else
                throw(CliOptionError("Unrecognizable option string: \"$(args[i])\""))
            end
        elseif startswith(args[i], '-')
            append!(normalized, ["-$c" for c in args[i][2:end]])  # -abc ==> -a -b -c
        end
    end
    return normalized
end

function _check_option_name(name)
    if "" == name
        return :empty  # An empty string
    elseif name[1] != '-'
        return :no_dash  # Not starting with a dash
    elseif name == "--"
        return :double_dash  # It's double dash
    elseif match(r"^-[^-]", name) === nothing && match(r"^--[^-]", name) === nothing
        return :invalid  # At least invalid as a name of an option
    end

    if tryparse(Float64, name) !== nothing
        return :negative  # It can be a negative number or a name of an option
    end
    return :valid  # It is a name of an option
end

function _validate_option_names(T, name_lists...)
    article(T) = occursin("$T"[1], "AEIOUaeiou") ? "an" : "a"
    names = collect(Iterators.flatten(name_lists))
    if length(names) == 0
        throw(ArgumentError("At least one name must be supplied for $(article(T)) $T"))
    end
    duplicates = _get_duplicates(names)
    if 1 ≤ length(duplicates)
        throw(ArgumentError("Duplicate names for $(article(T)) $T found: " *
                            join(duplicates, ", ")))
    end
    for name in names
        result = _check_option_name(name)
        if result == :empty
            throw(ArgumentError("Name of $(article(T)) $T must not be empty"))
        elseif result == :no_dash
            throw(ArgumentError("Name of $(article(T)) $T must start with a dash:" *
                                " \"$name\""))
        elseif result in (:double_dash, :invalid)
            throw(ArgumentError("Invalid name for $T: \"$name\""))
        end
    end
end

function _parse(T, optval::AbstractString, requirement::Any; optname = "")
    parsed_value::Union{Nothing,T} = nothing
    try
        # Use `parse` if available, or use constructor of the type
        if applicable(parse, T, optval)
            parsed_value = parse(T, optval)
        else
            parsed_value = T(optval)
        end
    catch ex
        # Generate message expressing the error encountered
        if :msg in fieldnames(typeof(ex))
            reason = ex.msg
        else
            reason = split(_stringify(ex), '\n')[1]
        end

        # Throw exception with formatted message
        buf = IOBuffer()
        print(buf, "Unparsable ")
        print(buf, optname == "" ? "positional argument" : "value for $optname")
        print(buf, " of type $T: ")
        print(buf, "\"$optval\" ($reason)")
        msg = String(take!(buf))
        throw(CliOptionError(msg))
    end

    # Validate the parsed result
    reason = ""
    if requirement isa Function
        rv = requirement(parsed_value)
        if rv == false || (rv isa String && rv != "")
            reason = rv isa Bool ? "validation failed" : rv
        end
    elseif requirement isa Regex
        if match(requirement, optval) === nothing
            reason = "must match for $(requirement)"
        end
    elseif requirement !== nothing
        if !any(x == parsed_value for x in requirement)
            reason = "must be one of " * join([isa(s, Regex) ? "$s" : "\"$s\""
                                               for s in requirement],
                                              ", ", " or ")
        end
    end

    # Throw if validation failed
    if reason != ""
        buf = IOBuffer()
        print(buf, "Invalid ")
        print(buf, "value for $optname")  #TODO: in case of positional argument
        print(buf, T == String ? ": " : " of type $T: ")
        print(buf, "\"$optval\" ($reason)")
        msg = String(take!(buf))
        throw(CliOptionError(msg))
    end

    # Return validated value
    parsed_value
end

const _usage_indent = 27
function print_description(io, names, val, help)
    heading = join(names, ", ") * (val != "" ? " $val" : "")
    print(io, repeat(" ", 4) * heading)
    if _usage_indent ≤ length(heading) + 4
        println(io)
        println(io, repeat(" ", _usage_indent) * help)
    else
        println(io, repeat(" ", _usage_indent - 4 - length(heading)) * help)
    end
    println(io)
end

export CliOptionSpec,
       Option,
       FlagOption,
       CounterOption,
       HelpOption,
       Positional,
       OptionGroup,
       MutexGroup,
       update_defaults,
       parse_args,
       print_usage,
       CliOptionError

end # module


text:
"""
Bernoulli scheme is a generalization of Bernoulli proceses to dimension N where the random
variable may take on values with probability p₁,...,p_N that sum to 1.

In our case, we assume p₁,...,p_{N-1} are probabilities of different types of success,
p_N is the probability

The constructor takes probabilities p_1, ... p_N-1 and calculates p_N = 1-sum_i=1^N-1(pᵢ)
"""
struct BernoulliScheme{N}<:DiscreteCountingProcess
    n::Int64
    p_suc::SVector{N, Float64}

    function BernoulliScheme(n::Int64, p_suc::AbstractArray{<:Float64})
        @assert 0<sum(p_suc)<=1
        new{length(p_suc)}(n, SA[p_suc...])
    end
end

# Distributions.jl interface (https://juliastats.org/Distributions.jl/stable/extends/)
Base.length(bs::BernoulliScheme) = 2

"""
Get step-shift of the next success and the next succes type.
Support for step-shift is 1,2, ....
Support for success type is 1, 2, ..., N  (N is the number of success results)
"""
function Distributions._rand!(rng::AbstractRNG, bs::BernoulliScheme, x::AbstractVector{T}) where T <: Real
    x[2] = Distributions.rand(rng, Categorical(bs.p_suc./sum(bs.p_suc)))
    x[1] = Distributions.rand(rng, Geometric(sum(bs.p_suc)))+1
    return x
end

"""
Get parameters of the process
"""
Distributions.params(bs::BernoulliScheme) = (bs.n, bs.p_suc)

"""
Get outcome distribution for given index.
Support for the outcome distribution is 1...N+1. N+1 means failure.
Index can be in the range 1, ..., n (n is the number of random variables in the scheme).
"""
Base.getindex(bs::BernoulliScheme, i::Integer) = 1<=i<=bs.n ? Categorical([bs.p_suc..., 1-sum(bs.p_suc)]) : throw(BoundsError(bs, i))


text:
module TestConversions
	using Base.Test
	using DataArrays

	@assert isequal(@data([1, 2, NA]),
		            convert(DataArray, @pdata([1, 2, NA])))

	# Test vector() and matrix() conversion tools
	dv = @data ones(5)
	@assert isa(array(dv), Vector{Float64})
	@assert isa(convert(Vector{Float64}, dv), Vector{Float64})
	dv[1] = NA
	# Should raise errors:
	# vector(dv)
	# convert(Vector{Float64}, dv)

	dm = @data ones(3, 3)
	@assert isa(array(dm), Matrix{Float64})
	@assert isa(convert(Matrix{Float64}, dm), Matrix{Float64})
	dm[1, 1] = NA
	# Should raise errors:
	# matrix(dm)
	# convert(Matrix{Float64}, dm)
end


text:
############################################################
# apply L2 constraint
############################################################

function apply_l2_cons!{T <: AbstractFloat}(backend::GPUBackend, blob::CuTensorBlob{T},
                                            coef::AbstractFloat, ninputs::Integer, nunits::Integer)
  # we allocate a bit of temporary memory here
  # we could instead also store this in the cons type
  # but that would double the memory footprint of a network
  # which is prohibitive for large models!
  # --
  # NOTE stokasto:
  # an even better alternative would be to write
  # a dedicated kernel for normalization
  # but since the weight matrices are usually small
  # I am not sure whether that will pay off especially
  # since the constraints only apply rarely
  # I also tested using cublas cublasSnorm2 but that was way slower
  # than computing all norms using gemm
  @assert(ninputs*nunits == length(blob))
  # allocate
  tmpA = make_blob(backend, T, size(blob)...)
  onesv = make_blob(backend, ones(T, ninputs, 1, 1, 1))
  tmp_norm = make_blob(backend, T, (nunits, 1, 1, 1))
  tmp_norm_host = zeros(T, nunits)
  # copy blob so that it stays intact
  copy!(tmpA, blob)

  # we compute the squared norm of all colums of matrix A as:
  #  ||A||^2 = transpose(A .* A) * ones(size(A))
  # square blob inplace
  CuVec.mul!(backend, T, tmpA.ptr.p, tmpA.ptr.p, length(blob))
  # and reduce via gemv to get the sum
  CuBLAS.gemm(backend.cublas_ctx, CuBLAS.OP_T, CuBLAS.OP_N, nunits, 1, ninputs,
              convert(T, 1), tmpA.ptr, ninputs, onesv.ptr, ninputs, convert(T, 0), tmp_norm.ptr, nunits)
  # copy back for doing the norm size check on the cpu
  copy!(tmp_norm_host, tmp_norm)

  for i = 1:nunits
    # calculate offset in blob vector
    offset = sizeof(T) * (i-1) * ninputs
    off_ptr = CuPtr(blob.ptr.p + offset)
    @inbounds norm = sqrt(tmp_norm_host[i])
    if norm > coef
      scale_factor = (1. / norm) * coef
      CuBLAS.scal(backend.cublas_ctx, ninputs, convert(T, scale_factor), off_ptr, 1)
    end
  end
  destroy(tmpA)
  destroy(onesv)
  destroy(tmp_norm)
end


text:
if normpath(@__DIR__) ∉ LOAD_PATH
    pushfirst!(LOAD_PATH, normpath(@__DIR__, ".."))
    pushfirst!(LOAD_PATH, normpath(@__DIR__))
end

using NormalHermiteSplines
using NormalHermiteSplines: ElasticCholesky, ElasticNormalSpline
const nhs = NormalHermiteSplines

using BenchmarkTools
using LinearAlgebra
using Random
using StaticArrays
using UnPack

function random_nodes(::Val{n} = 2, ::Type{T} = Float64; max_size) where {n,T}
    min_bound   = -rand(SVector{n,T})
    max_bound   = rand(SVector{n,T})
    rand_node() = min_bound .+ rand(SVector{n,T}) .* (max_bound .- min_bound)
    rand_dir()  = (x = rand_node(); x/norm(x))

    nodes     = [min_bound, max_bound, (rand_node() for i in 3:max_size)...]
    values    = rand(T, max_size)
    d_nodes   = [rand_node() for _ in 1:n*max_size]
    d_dirs    = [rand_dir() for _ in 1:n*max_size]
    d_values  = rand(T, n*max_size)
    return (; min_bound, max_bound, nodes, values, d_nodes, d_dirs, d_values)
end

function bench_insertion(::Val{n} = Val(2), ::Type{T} = Float64) where {n,T}
    for max_size in [8,16,32]
        @unpack min_bound, max_bound, nodes, values, d_nodes, d_dirs, d_values = random_nodes(Val(n), T; max_size = max_size)
        rk_H0 = RK_H0(T(0.5 + rand()))
        rk_H1 = RK_H1(T(0.5 + rand()))
        espl_H0 = ElasticNormalSpline(min_bound, max_bound, max_size, rk_H0)
        espl_H1_0 = ElasticNormalSpline(min_bound, max_bound, max_size, rk_H1)
        espl_H1_1 = ElasticNormalSpline(min_bound, max_bound, max_size, rk_H1)

        print((dim = n, eltype = T, spline = :elastic, kernel = :RK_H0, nodes = max_size, d_nodes = 0))
        @btime (empty!($espl_H0); insert!($espl_H0, $nodes, $values))

        print((dim = n, eltype = T, spline = :elastic, kernel = :RK_H1, nodes = max_size, d_nodes = 0))
        @btime (empty!($espl_H1_0); insert!($espl_H1_0, $nodes, $values))

        print((dim = n, eltype = T, spline = :elastic, kernel = :RK_H1, nodes = max_size, d_nodes = n * max_size))
        @btime (empty!($espl_H1_1); insert!($espl_H1_1, $nodes, $values, $d_nodes, $d_dirs, $d_values))

        print((dim = n, eltype = T, spline = :normal, kernel = :RK_H0, nodes = max_size, d_nodes = 0))
        @btime for i in 2:$max_size # i=1 errors; requires either 2+ nodes or 1+ node and 1+ derivative node
            interpolate(view($nodes, 1:i), view($values, 1:i), $rk_H0)
        end;

        print((dim = n, eltype = T, spline = :normal, kernel = :RK_H1, nodes = max_size, d_nodes = 0))
        @btime for i in 2:$max_size # i=1 errors; requires either 2+ nodes or 1+ node and 1+ derivative node
            interpolate(view($nodes, 1:i), view($values, 1:i), $rk_H1)
        end;

        print((dim = n, eltype = T, spline = :normal, kernel = :RK_H1, nodes = max_size, d_nodes = n * max_size))
        @btime for i in 1:$max_size
            interpolate(view($nodes, 1:i), view($values, 1:i), view($d_nodes, 1:$n*i), view($d_dirs, 1:$n*i), view($d_values, 1:$n*i), $rk_H1)
        end;

        println("")
    end
end

bench_insertion(Val(1));
bench_insertion(Val(2));
bench_insertion(Val(3));