text:
"""
set_pvals!(model::CS.Optimizer)

Set the possible values for each constraint.
"""
function set_pvals!(model::CS.Optimizer)
    com = model.inner
    for constraint in com.constraints
        set_pvals!(com, constraint)
    end
end

"""
    set_var_in_all_different!(model::CS.Optimizer)

Set the vector `in_all_different` for each variable
"""
function set_var_in_all_different!(model::CS.Optimizer)
    com = model.inner
    n_all_different = com.info.n_constraint_types.alldifferent
    for var in com.search_space
        var.in_all_different = zeros(Bool, n_all_different)
    end
    ci = 1
    for constraint in com.constraints
        if constraint isa AllDifferentConstraint
            for vidx in constraint.indices
                com.search_space[vidx].in_all_different[ci] = true
            end
            ci += 1
        end
    end
end

"""
init_constraints!(com::CS.CoM; constraints=com.constraints)

Initializes all `constraints` which implement the `init_constraint!` method.
It also activates all constraints which implement the `activate_constraint!` method.
Return if feasible after initalization
"""
function init_constraints!(com::CS.CoM; constraints = com.constraints)
    feasible = true
    for constraint in constraints
        constraint.is_deactivated && continue
        feasible = init_constraint!(com, constraint, constraint.fct, constraint.set)
        !feasible && break
        constraint.is_initialized = true

        feasible = activate_constraint!(com, constraint, constraint.fct, constraint.set)
        !feasible && break
        constraint.is_activated = true
    end
    return feasible
end

"""
init_constraints!(com::CS.CoM; constraints=com.constraints)

Initializes all constraints of the model as new `constraints` were added.
Return if feasible after the update of the initalization
"""
function update_init_constraints!(com::CS.CoM; constraints = com.constraints)
    feasible = true
    for constraint in com.constraints
        feasible = update_init_constraint!(
            com,
            constraint,
            constraint.fct,
            constraint.set,
            constraints,
        )
        !feasible && break
    end
    return feasible
end

"""
call_finished_pruning!(com)

Call `finished_pruning_constraint!` for every constraint which implements that function as saved in `constraint.impl.finished_pruning`
"""
function call_finished_pruning!(com)
    for constraint in com.constraints
        finished_pruning_constraint!(com, constraint, constraint.fct, constraint.set)
    end
end

"""
call_restore_pruning!(com, prune_steps)

Call `call_restore_pruning!` for every constraint which implements that function as saved in `constraint.impl.restore_pruning`
"""
function call_restore_pruning!(com, prune_steps)
    for constraint in com.constraints
        restore_pruning_constraint!(
            com,
            constraint,
            constraint.fct,
            constraint.set,
            prune_steps,
        )
    end
end

"""
    count_unfixed(com, constraint::Constraint)

Count number of unfixed variables in the given Constraint
"""
function count_unfixed(com::CS.CoM, constraint::Constraint)
    count(!isfixed, com.search_space[i] for i in constraint.indices)
end

"""
    get_two_unfixed(com, constraint::Constraint)

Get two unfixed indices and local indices of a constraint. One should use
[`count_unfixed`](@ref) to make sure that there are exactly two unfixed indices.
"""
function get_two_unfixed(com::CS.CoM, constraint::Constraint)
    local_vidx_1 = 0
    vidx_1 = 0
    local_vidx_2 = 0
    vidx_2 = 0
    for local_i in 1:length(constraint.indices)
        var = com.search_space[constraint.indices[local_i]]
        if !isfixed(var)
            if local_vidx_1 == 0
                local_vidx_1 = local_i
                vidx_1 = var.idx
            else
                local_vidx_2 = local_i
                vidx_2 = var.idx
                break
            end
        end
    end
    return local_vidx_1, vidx_1, local_vidx_2, vidx_2
end

"""
    init_constraint!(
        com::CS.CoM,
        constraint::Constraint,
        fct,
        set
    )

Fallback for `init_constraint!`.
This function needs to be implemented if the constraint needs to be initialized for example to check
certain things only ones or initialize some data structures.
[`activate_constraint!`](@ref) needs to be used when variables should be pruned on initialization as `init_constraint!`
even gets called when the constraint itself isn't active i.e inside an `or` constraint.

Return whether the constraint is feasible or not.
"""
function init_constraint!(
    com::CS.CoM,
    constraint::Constraint,
    fct,
    set
)
    return true
end

"""
    implements_activate(::Type{<:ConstraintType}, ::Type{<:FctType}, ::Type{<:SetType})

Fallback for `implements_activate`.

Return whether [`activate_constraint!`](@ref) is implemented
"""
implements_activate(::Type{<:Constraint}, ::Type{<:Any}, ::Type{<:Any}) = false

"""
    activate_constraint!(::CS.CoM, ::Constraint, fct, set)

Fallback for `activate_constraint!`.
If this gets implemented please also implement [`implements_activate`](@ref).

This function will get called if the constraint gets activated by an indicator or reifed constraint as an example.
Can be used to prune variables that aren't possible without fixing anything further simply by being active.

Return whether the constraint is feasible.
"""
function activate_constraint!(::CS.CoM, ::Constraint, fct, set)
    return true
end

"""
    finished_pruning_constraint!(::CS.CoM, ::Constraint, fct, set)

Fallback for `finished_pruning_constraint!`.
This function will get called after all pruning steps in one node.
Can be used to change some data structure but no further pruning should be done here.

Return `nothing`
"""
function finished_pruning_constraint!(::CS.CoM, ::Constraint, fct, set)
    nothing
end

"""
    reverse_pruning_constraint!(::CS.CoM, ::Constraint, fct, set, backtrack_id)

Fallback for `reverse_pruning_constraint!`.
This function will get called when a specific pruning step with id `backtrack_id` needs to get reversed.
Should only be implemented when the data structure of the constraint needs to be updated.
All variables are updated automatically anyway.
See also [`single_reverse_pruning_constraint!`](@ref) to change the data structure based on a single variable.

Return `nothing`
"""
function reverse_pruning_constraint!(
    com::CoM,
    constraint::Constraint,
    fct,
    set,
    backtrack_id,
)
    nothing
end

"""
    single_reverse_pruning_constraint!(::CS.CoM, ::Constraint, fct, set, variable, backtrack_id)

Fallback for `single_reverse_pruning_constraint!`.
This function will get called when a specific pruning step with id `backtrack_id` needs to get reversed.
In contrast to [`reverse_pruning_constraint!`](@ref) however this function will be called for each variable individually and is called
before [`reverse_pruning_constraint!`](@ref).
Should only be implemented when the data structure of the constraint needs to be updated.
All variables are updated automatically anyway.

Return `nothing`
"""
function single_reverse_pruning_constraint!(
    ::CoM,
    ::Constraint,
    fct,
    set,
    variable,
    backtrack_idx,
)
    nothing
end

"""
    restore_pruning_constraint!(::CS.CoM, ::Constraint, fct, set, prune_steps)

Fallback for `restore_pruning_constraint!`.
This function will get called when pruning steps will be restored. `prune_steps` is a vector.
If the data structure of the constraint needs to be updated to reflect the data it had at the last `prune_step` this function needs
to be implemented.

Return `nothing`
"""
function restore_pruning_constraint!(
    ::CoM,
    ::Constraint,
    fct,
    set,
    prune_steps,
)
    nothing
end

"""
    update_best_bound_constraint!(::CS.CoM, ::Constraint, fct, set, vidx, lb, ub)

Fallback for `update_best_bound_constraint!`.
This function will get called when a new objective bound gets computed.
If the constraint needs to change variables inside the underlying LP this function should be used to update those variables.

Return `nothing`
"""
function update_best_bound_constraint!(
    com::CS.CoM,
    constraint::Constraint,
    fct,
    set,
    vidx,
    lb,
    ub,
)
    nothing
end

"""
update_init_constraint!(::CS.CoM, ::Constraint, fct, set, constraints)

Fallback for `update_init_constraint!`.
This function is called when new constraints are added due to presolve processes.
It gets called with all new constraints.
Normally it shouldn't be necessary to implement as constraints should be independent of each other.
Sometimes however this seems to make sense :D

Return whether the constraint is feasible.
"""
function update_init_constraint!(
    com::CS.CoM,
    constraint::Constraint,
    fct,
    set,
    constraints,
)
    return true
end


text:
# ---
# title: 1625. Lexicographically Smallest String After Applying Operations
# id: problem1625
# author: Tian Jun
# date: 2020-10-31
# difficulty: Medium
# categories: Depth-first Search, Breadth-first Search
# link: <https://leetcode.com/problems/lexicographically-smallest-string-after-applying-operations/description/>
# hidden: true
# ---
#
# You are given a string `s` of **even length** consisting of digits from `0` to
# `9`, and two integers `a` and `b`.
#
# You can apply either of the following two operations any number of times and
# in any order on `s`:
#
#   * Add `a` to all odd indices of `s` **(0-indexed)**. Digits post `9` are cycled back to `0`. For example, if `s = "3456"` and `a = 5`, `s` becomes `"3951"`.
#   * Rotate `s` to the right by `b` positions. For example, if `s = "3456"` and `b = 1`, `s` becomes `"6345"`.
#
# Return _the **lexicographically smallest** string you can obtain by applying
# the above operations any number of times on_ `s`.
#
# A string `a` is lexicographically smaller than a string `b` (of the same
# length) if in the first position where `a` and `b` differ, string `a` has a
# letter that appears earlier in the alphabet than the corresponding letter in
# `b`. For example, `"0158"` is lexicographically smaller than `"0190"` because
# the first position they differ is at the third letter, and `'5'` comes before
# `'9'`.
#
#
#
# **Example 1:**
#
#
#
#     Input: s = "5525", a = 9, b = 2
#     Output: "2050"
#     Explanation: We can apply the following operations:
#     Start:  "5525"
#     Rotate: "2555"
#     Add:    "2454"
#     Add:    "2353"
#     Rotate: "5323"
#     Add:    "5222"
#     Add:    "5121"
#     Rotate: "2151"
#     Add:    "2050"
#     There is no way to obtain a string that is lexicographically smaller then "2050".
#
#
# **Example 2:**
#
#
#
#     Input: s = "74", a = 5, b = 1
#     Output: "24"
#     Explanation: We can apply the following operations:
#     Start:  "74"
#     Rotate: "47"
#     Add:    "42"
#     Rotate: "24"
#     There is no way to obtain a string that is lexicographically smaller then "24".
#
#
# **Example 3:**
#
#
#
#     Input: s = "0011", a = 4, b = 2
#     Output: "0011"
#     Explanation: There are no sequence of operations that will give us a lexicographically smaller string than "0011".
#
#
# **Example 4:**
#
#
#
#     Input: s = "43987654", a = 7, b = 3
#     Output: "00553311"
#
#
#
#
# **Constraints:**
#
#   * `2 <= s.length <= 100`
#   * `s.length` is even.
#   * `s` consists of digits from `0` to `9` only.
#   * `1 <= a <= 9`
#   * `1 <= b <= s.length - 1`
#
#
## @lc code=start
using LeetCode

## add your code here:
## @lc code=end

ext: jl


text:
module KhepriRhino
using KhepriBase
using Sockets

# functions that need specialization
include(khepribase_interface_file())

include("Rhino.jl")

function __init__()
  add_current_backend(rhino)
end
end


text:
using Callsite

# Variant of https://github.com/MikeInnes/Flow.jl, that works with arbitrary generic functions

function var(xs)
  mean = sum(xs)/length(xs)
  meansqr = sumabs2(xs)/length(xs)
  return meansqr - mean^2
end

@callsite typed function flow(body, args)
    graph = make_flow_graph(body) # makes a flow graph
    optimized_graph = optimize_graph(graph) # e.g. removes temporaries
    compile(optimized_graph, :Julia) # compile to julia code, or spark ??!
end

_call(flow, var, rand(10))


text:
using Test, LinearAlgebra, SparseArrays, Random
using QDLDL

@testset "regularization" begin

  a = 1e-20
  A = sparse([a 0;0 a])

  signs = [1,1]
  f = qdldl(A,Dsigns = signs)
  @test f.workspace.D == [1e-7,1e-7]
  @test regularized_entries(f) == 2

  signs = [1,-1]
  f = qdldl(A,Dsigns = signs)
  @test f.workspace.D == [1e-7,-1e-7]
  @test regularized_entries(f) == 2

  δ = 1e-8
  f = qdldl(A,Dsigns = signs,regularize_delta = δ)
  @test f.workspace.D == [δ,-δ]
  @test regularized_entries(f) == 2

  ϵ = 1e-30
  f = qdldl(A,Dsigns = signs,regularize_eps = ϵ, regularize_delta = δ)
  @test f.workspace.D == [a,-δ]
  @test regularized_entries(f) == 1

  #just setting A[1,1] = 0 should still allow
  #regularization, since A[1,1] will be structurally
  #entry on the diagonal still
  A[1,1] = 0.
  f = qdldl(A,Dsigns = signs)
  @test f.workspace.D == [1e-7,-1e-7]

  #but the same matrix should fail on non regularized
  #factorization since its D[1,1] entry will be exactly zero
  @test_throws ErrorException qdldl(A)

  #regularization should also fail when there is
  #no structural entry on the diagonal, regardless
  #of whether regularization is enabled
  A = sparse([0. 0;0 a])
  @test_throws ErrorException qdldl(A)
  @test_throws ErrorException qdldl(A,Dsigns = signs)

  #make sure that signs are being properly permuted
  A = sparse(I(3).*a)
  signs = [1,1,-1]
  perm  = [2,3,1]
  f = qdldl(A;perm=perm,Dsigns = signs)
  @test f.workspace.D == [1e-7,-1e-7,1e-7]
  @test regularized_entries(f) == 3

  #try a biggish problem
  rng = Random.MersenneTwister(2401)
  m = 20
  n = 30
  A = random_psd(n) + Diagonal(rand(n))
  B = sprandn(m,n,0.2)
  C = -Diagonal(rand(m))
  M = [A B' ; B C]
  b = randn(m+n)
  s = [ones(Int64,n);-ones(Int64,m)]
  F = qdldl(M,perm=randperm(m+n),Dsigns = s)
  #basic solve
  @test norm(F\b -  M\b, Inf) <= 1e-10

end

nothing


text:
#Abstract type definitions
abstract DerivativeOrder
abstract AbstractSample{O<:DerivativeOrder}

#Concrete derivated order types
type ZeroOrder <: DerivativeOrder end
type FirstOrder <: DerivativeOrder end
type SecondOrder <: DerivativeOrder end
type ThirdOrder <: DerivativeOrder end
typealias GradientOrder Union{FirstOrder,SecondOrder,ThirdOrder}
typealias TensorOrder Union{SecondOrder,ThirdOrder}
typealias DTensorOrder ThirdOrder

#Factory functions for all different types of samples
#Currently implemented as symbols are: :base, :gradient, :tensor, :tangent
samples{N<:Number,T<:AbstractFloat}(s::Symbol,nparams::Integer,nsamples::Integer,::Type{N},::Type{T},args...) = _samples(Val{s},nparams,nsamples,N,T,args...)

### Functionality
numparas(s::AbstractSample) = size(s.values,1)
numsamples(s::AbstractSample) = size(s.values,2)
sampletype(s::AbstractSample) = eltype(s.values)
calculationtype(s::AbstractSample) = eltype(s.loglikelihood)
similar(s::AbstractSample,nsamples::Integer =numsamples(s),tosamplename::Symbol =sampletypename(s)) = _samples(Val{tosamplename},numparas(s),nsamples,sampletype(s),calculationtype(s))

function _copy!(dest::AbstractSample,src::AbstractSample)
    for f in fieldnames(dest)
        copy!(getfield(dest,f),getfield(src,f))
    end
    dest
end

function _copy!(dest::AbstractSample,destindex::Integer,src::AbstractSample,srcindex::Integer)
    ndestsamples = numsamples(dest)
    for f in fieldnames(dest)
        destvals = getfield(dest,f)
        copylength = div(length(destvals),ndestsamples)
        copy!(destvals,(destindex-1)*copylength+1,getfield(src,f),(srcindex-1)*copylength+1,copylength)
    end
    dest
end

function _copy!(dest::AbstractSample,destindex::AbstractVector,src::AbstractSample,srcindex::AbstractVector)
    ndestsamples = numsamples(dest)
    ncopysamples = length(destindex)
    for f in fieldnames(dest)
        destvals = getfield(dest,f)
        copylength = ncopysamples>0?div(length(destvals),ndestsamples):0
        for i=1:ncopysamples
            copy!(destvals,(destindex[i]-1)*copylength+1,getfield(src,f),(srcindex[i]-1)*copylength+1,copylength)
        end
    end
    dest
end

function copy!(dest::AbstractSample,src::AbstractSample)
    @assert numparas(dest) == numparas(src) && numsamples(dest) == numsamples(src)
    _copy!(dest,src)
end

function copy!(dest::AbstractSample,destindex::Integer,src::AbstractSample,srcindex::Integer)
    @assert numparas(dest) == numparas(src) && destindex <= numsamples(dest) && srcindex <= numsamples(src)
    _copy!(dest,destindex,src,srcindex)
end

function copy!(dest::AbstractSample,destindex::AbstractVector,src::AbstractSample,srcindex::AbstractVector)
    @assert numparas(dest) == numparas(src) && maximum(destindex) <= numsamples(dest) && maximum(srcindex) <= numsamples(src)
    _copy!(dest,destindex,src,srcindex)
end

function copy!(dest::AbstractSample,src::AbstractSample,srcindex::AbstractVector)
    @assert numparas(dest) == numparas(src) && numsamples(dest) == length(srcindex) && maximum(srcindex) <= numsamples(src)
    _copy!(dest,1:length(srcindex),src,srcindex)
end

copy(src::AbstractSample) = _copy!(similar(src),src)
copy(src::AbstractSample,i::Integer) = _copy!(similar(src,1),1,src,i)
copy(src::AbstractSample,srcindex::AbstractVector) = _copy!(similar(src,length(srcindex)),1:length(srcindex),src,srcindex)
copy(src::AbstractSample,srcindex::AbstractVector,to::Symbol) = _copy!(similar(src,length(srcindex),to),1:length(srcindex),src,srcindex)

function offset!(s::AbstractSample,v::Vector)
    nparas = numparas(s)
    for j=1:numsamples(s)
        @simd for i=1:nparas
            @inbounds s.values[i,j] += v[i]
        end
    end
    s
end

function =={S<:AbstractSample}(s1::S,s2::S)
    for f in fieldnames(s1)
        isequal(getfield(s1,f),getfield(s2,f))?continue:return false
    end
    return true
end

function show{S<:AbstractSample}(io::IO,s::S,n::AbstractString ="")
    nump = numparas(s)
    nums = numsamples(s)
    println(io,n,typeof(s).name.name," with ",nump," parameter",nump>1?"s":""," and ",nums," sample",nums>1?"s":"")
    for f in fieldnames(s)
        print(io," ",f,": ",typeof(getfield(s,f)))
        println(io)
    end
    nothing
end

function show{S<:AbstractSample}(io::IO,v::AbstractVector{S})
    e = isa(eltype(v),Union)?"AbstractSample":eltype(v).name.name
    println(io)
    println(io,"Array{$e} with")
    for i=1:length(v)
        show(io,v[i],"[$i] ")
    end
end

display{S<:AbstractSample}(io::IO,v::AbstractVector{S}) = Base.show{S}(io,v)

######################################################
@inline _valuestuple(s1::Integer,s2::Integer) = s2==1?(s1,):(s1,s2) #if s2 == 1, then values should be one-dimensional
@inline _tensortuple(s1::Integer,s2::Integer,s3::Integer) = s3==1?(s1,s2):(s1,s2,s3) #if s3 == 1, then tensor should be two-dimensional


text:
using PortAudio

PortAudio.versioninfo()

devs = PortAudio.devices();
for d in devs
    println("$(d.idx): $(d.name) ($(d.hostapi)) $(d.maxinchans) in(s) / $(d.maxoutchans) out(s) at $(d.defaultsamplerate) Hz");
end

println(PortAudio.devnames())


text:
import Base
export IndividualStage, copy, describe, valid

"""
Used to contain the data for a stage of development for a given individual.

TODO:
- Explain more about individual stages.
"""
type IndividualStage{T}
  valid::Bool
  value::T

  """
  Constructs a new empty stage of development.
  """
  IndividualStage() = new(false)

  """
  Constructs a non-empty stage of development.
  """
  IndividualStage(v::T) = new(true, v)
end

"""
Produces a copy of a given stage of development.
"""
copy(s::IndividualStage) = if s.valid
  IndividualStage(s.value)
else
  IndividualStage()
end

"""
Returns a string description of a given stage of development.
"""
describe(s::IndividualStage) = if s.valid
  describe(s.value)
else
  "INVALID"
end

"""
Returns true if a given stage of development is valid.
"""
valid(s::IndividualStage) = s.valid

"""
Returns the value of a given stage of development.
"""
get{T}(s::IndividualStage{T}) = s.value

"""
Sets the value of a given stage of development, and marks it as valid.
"""
set{T}(s::IndividualStage{T}, v::T) = begin
  s.valid = true
  s.value = v
end


text:
mutable struct PlaneWaveMW{T,P}
  direction::P
  polarisation::P
  wavenumber::T
  amplitude::T
end

function PlaneWaveMW(d,p,k,a = 1)
    T = promote_type(eltype(d), eltype(p), typeof(k), typeof(a))
    P = similar_type(typeof(d), T)
    PlaneWaveMW{T,P}(d,p,k,a)
end

"""
    planewavemw3d(;direction, polarization, wavenumber[, amplitude=1])

Create a plane wave solution to Maxwell's equations.
"""
planewavemw3d(;
    direction    = error("missing arguement `direction`"),
    polarization = error("missing arguement `polarization`"),
    wavenumber   = error("missing arguement `wavenumber`"),
    amplitude    = 1,
    ) = PlaneWaveMW(direction, polarization, wavenumber, amplitude)

function (e::PlaneWaveMW)(x)
  k = e.wavenumber
  d = e.direction
  u = e.polarisation
  a = e.amplitude
  a * exp(-im * k * dot(d, x)) * u
end

function curl(field::PlaneWaveMW)
  k = field.wavenumber
  d = field.direction
  u = field.polarisation
  a = field.amplitude
  v = d × u
  b = -a * im * k
  PlaneWaveMW(d, v, k, b)
end

*(a::Number, e::PlaneWaveMW) = PlaneWaveMW(e.direction, e.polarisation, e.wavenumber, a*e.amplitude)

abstract type Dipole end

mutable struct DipoleMW{T,P} <: Dipole
    location::P
    orientation::P
    wavenumber::T
end

function DipoleMW(l,o,k)
    T = promote_type(eltype(l), eltype(o), typeof(k))
    P = similar_type(typeof(l), T)
    DipoleMW{T,P}(l,o,k)
end

mutable struct curlDipoleMW{T,P} <: Dipole
    location::P
    orientation::P
    wavenumber::T
end

function curlDipoleMW(l,o,k)
    T = promote_type(eltype(l), eltype(o), typeof(k))
    P = similar_type(typeof(l), T)
    curlDipoleMW{T,P}(l,o,k)
end

"""
    dipolemw3d(;location, orientation, wavenumber)

Create an electric dipole solution to Maxwell's equations representing the electric
field part. Implementation is based on (9.18) of Jackson's “Classical electrodynamics”,
with the notable difference that the ``\exp(ikr)`` is used.
"""
dipolemw3d(;
    location    = error("missing arguement `location`"),
    orientation = error("missing arguement `orientation`"),
    wavenumber   = error("missing arguement `wavenumber`"),
    ) = DipoleMW(location, orientation, wavenumber)

function (d::DipoleMW)(x; isfarfield=false)
    k = d.wavenumber
    x_0 = d.location
    p = d.orientation
    r = norm(x-x_0)
    n = (x - x_0)/r
    if isfarfield
      # postfactor (4*π*im)/k to be consistent with BEAST far field computation
      # and, of course, omitted exp(-im*k*r)/r factor in (9.19)
      # of Jackson's Classical Electrodynamics
      return k^2/(4*π)*cross(cross(n,p),n)*(4*π*im)/k
    else
      return 1/(4*π)*exp(-im*k*r)*(k^2/r*cross(cross(n,p),n) +
              (1/r^3 + im*k/r^2)*(3*n*dot(n,p) - p))
    end
end

function (d::curlDipoleMW)(x; isfarfield=false)
    k = d.wavenumber
    x_0 = d.location
    p = d.orientation
    r = norm(x-x_0)
    n =  (x - x_0)/r
    if isfarfield
      # postfactor (4*π*im)/k to be consistent with BEAST far field computation
      return (-im*k)*k^2/(4*π)*cross(n,p)*(4*π*im)/k
    else
      return -im*(k^3)/(4*π)*cross(n,p)*exp(-im*k*r)/r*(1 + 1/(im*k*r))
    end
end

function curl(d::DipoleMW)
    return curlDipoleMW(d.location, d.orientation, d.wavenumber)
end

*(a::Number, d::DipoleMW) = DipoleMW(d.location, a .* d.orientation, d.wavenumber)
*(a::Number, d::curlDipoleMW) = curlDipoleMW(d.location, a .* d.orientation, d.wavenumber)

mutable struct CrossTraceMW{F} <: Functional
  field::F
end

mutable struct TangTraceMW{F} <: Functional
  field::F
end

cross(::NormalVector, p::Function) = CrossTraceMW(p)
cross(::NormalVector, p::PlaneWaveMW) = CrossTraceMW(p)
cross(::NormalVector, p::Dipole) = CrossTraceMW(p)
cross(t::CrossTraceMW, ::NormalVector) = TangTraceMW(t.field)

function (ϕ::CrossTraceMW)(p)
  F = ϕ.field
  x = cartesian(p)
  n = normal(p)
  return n × F(x)
end

function (ϕ::TangTraceMW)(p)
  F = ϕ.field
  x = cartesian(p)
  n = normal(p)
  return (n × F(x)) × n
end

integrand(::TangTraceMW, gx, ϕx) = gx[1] ⋅ ϕx
integrand(::CrossTraceMW, test_vals, field_val) = test_vals[1] ⋅ field_val

struct NDotTrace{F} <: Functional
  field::F
end

(ϕ::NDotTrace)(p) = dot(normal(p), ϕ.field(cartesian(p)))
integrand(::NDotTrace, g, ϕ) = dot(g.value, ϕ)
LinearAlgebra.dot(::NormalVector, f) = NDotTrace(f)

mutable struct CurlGreen{T,U,V}
  wavenumber::T
  source::U
  position::V
end

function (f::CurlGreen)(x)
  γ = im * f.wavenumber
  r = x-f.position
  R = norm(r)
  g = exp(-γ*R)/(4π*R)
  j = f.source
  return -γ/R * (1 + 1/(γ*R)) * g * (r × j)
end

mutable struct CurlCurlGreen{T,U,V}
  wavenumber::T
  source::U
  position::V
end

cross(::NormalVector, p::CurlGreen) = CrossTraceMW(p)
cross(::NormalVector, p::CurlCurlGreen) = CrossTraceMW(p)

function (f::CurlCurlGreen)(x)
  γ = im * f.wavenumber
  r = x - f.position
  R = norm(r)
  g = exp(-γ*R)/(4π*R)
  j = f.source
  return (-γ^2/R^2 * (r × j) × r + (1/R^2 + γ/R)/R^2 * (3r * dot(r,j) - R^2 * j)) * g
end

curl(f::CurlGreen) = CurlCurlGreen(f.wavenumber, f.source, f.position)
function curl(f::CurlCurlGreen)
  κ = f.wavenumber
  j = κ^2 * f.source
  x = f.position
  return CurlGreen(κ, j, x)
end

Base.:*(a::Number, f::CurlGreen) = CurlGreen(f.wavenumber, a*f.source, f.position)
Base.:*(a::Number, f::CurlCurlGreen) = CurlCurlGreen(f.wavenumber, a*f.source, f.position)


text:
#jl # EFTfitter.jl - Tutorial

#jl #~This tutorial introduces the basic functionalities of EFTfitter.jl using a generic example.
#jl #~More functionalities of EFTfitter.jl, like handling nuisance correlations
#jl #~or ranking measurements and uncertainties, are shown in the
#jl #~[advanced tutorial](https://tudo-physik-e4.github.io/EFTfitter.jl/dev/advanced_tutorial/).

#md  # !!! note
#md  #     An executable version of this tutorial can be found [here](https://github.com/tudo-physik-e4/EFTfitter.jl/tree/main/examples/tutorial).
#md  #     A template to help starting your own analysis is available [here](https://github.com/tudo-physik-e4/EFTfitter.jl/tree/master/examples/empty_template).
#!jl # ---
#!jl # It is recommended to store the inputs (i.e. parameters, observables, measurements and correlations)
#!jl # and the actual analysis in two separate files. This allows to simply load different configurations
#!jl # of the model. We will therefore also consider two files: `tutorial_inputs.jl` and `runTutorial.jl`.

#!jl # ## File "tutorial_inputs.jl"
#~We start by defining all neccesary inputs to create an
#~[`EFTfitterModel`](https://tudo-physik-e4.github.io/EFTfitter.jl/dev/api/#EFTfitter.EFTfitterModel).

#!jl # ### Parameters
#jl #~============= Parameters =============================================#
#~We specify the parameters our model depends on and choose a prior for each of the parameters.
#~The prior has to be specified in form of a [BAT.jl prior](https://bat.github.io/BAT.jl/dev/tutorial/#Prior-Definition).

#~For our example, we consider two parameters with the names `C1` and `C2`.
#~For `C1` we choose a uniform (flat) prior in the range (-3, 3).
#~For `C2` we choose a gaussian prior with μ=0 and σ=0.5.
parameters = BAT.NamedTupleDist(
    C1 = -3..3, # short for: Uniform(-3, 3)
    C2 = Normal(0, 0.5) # Normal distribution
)

#~A parameter can be fixed (and therefore excluded from the fit) by setting its
#~prior to a certain value, e.g.: `C2 = 0`.
#~Also see [here](https://bat.github.io/BAT.jl/dev/tutorial/#Prior-Definition)
#~for more information on priors in the BAT.jl documentation.

#!jl # ### Observables
#jl #~============= Observables =============================================#
#~We now proceed to implement `Functions` that specify how the predicted values
#~of the observables depend on the model parameters.
#~For each observable, we need to provide a `Function` that returns the predicted
#~value of the observable for certain values of the model parameters. In our example,
#~we consider two observables (e.g. cross sections) by defining the two functions `xsec1` and `xsec2`.

#~Note: The functions for the observables may only have the model parameters as
#~their only argument. You can, however define a function that only depends on
#~the parameters and that internally calls a more complex function and passes the
#~corresponding arguments. In this example, the function `xsec2` calls the
#~function `myfunc` and passes further arguments (`coeffs`).

function xsec1(params)
    c = [20.12, 5.56, 325.556]
    return c[1] * params.C1 + c[2] * params.C1 * params.C2+ c[3] * params.C2
end

function xsec2(params)
    coeffs = [2.12, 4.3, 12.6]
    return myfunc(params, coeffs)
end

function myfunc(params, c)
    return c[1] * params.C1 + c[2] * params.C1 * params.C2+ c[3] * params.C2
end

#~If your observable is a distribution, you can define a vector of functions
#~with one function for each bin of the distribution.
#~(You could also treat each bin as a separate observable as shown above.)

function diff_xsec_bin1(params)
    coeffs = [2.2, 5.5, 6.6]
    return myfunc(params, coeffs)
end

function diff_xsec_bin2(params)
    coeffs = [3.3, 4.8, 7.6]
    return myfunc(params, coeffs)
end

function diff_xsec_bin3(params)
    coeffs = [4.9, 5.6, 8.9]
    return myfunc(params, coeffs)
end

diff_xsec = [diff_xsec_bin1, diff_xsec_bin2, diff_xsec_bin3]

#~Note: Another way to define a vector of functions for the bins of distributions
#~is shown [here](https://tudo-physik-e4.github.io/EFTfitter.jl/dev/advanced_tutorial/#Creating-a-vector-of-functions-for-distributions-1)
#~in the [advanced tutorial](https://tudo-physik-e4.github.io/EFTfitter.jl/dev/advanced_tutorial/).
#~This can be particularly useful when the predictions for the individual bins
#~have a similar functional relation and only differ in terms of some coefficients,
#~as it is the case here in this example.

#!jl # ### Measurements
#jl #~============= Measurements =============================================#
#~We can now enter measurements of the observables.
#~This is done by defining a [`NamedTuple`](https://docs.julialang.org/en/v1/manual/types/#Named-Tuple-Types)
#~consisting of [`Measurement`](https://tudo-physik-e4.github.io/EFTfitter.jl/dev/api/#EFTfitter.Measurement)
#~and [`MeasurementDistribution`](https://tudo-physik-e4.github.io/EFTfitter.jl/dev/api/#EFTfitter.MeasurementDistribution) objects.

#~A `Measurement` consists of the observable, the measured numerical value and
#~numerical values for the (multiple types of) uncertainties.
#~The observable can be passed to the `Measurement` either as an [`Observable`](https://tudo-physik-e4.github.io/EFTfitter.jl/dev/api/#EFTfitter.Observable)
#~object or as a `Function`. When using the latter, the observable is assumed to be unconstrained.
#~The uncertainties are passed as a [`NamedTuple`](https://docs.julialang.org/en/v1/manual/types/#Named-Tuple-Types).
#~Each measurement has to provide uncertainty values for all of the (active) uncertainty
#~types (see next section on `Correlations`). For a `MeasurementDistribution`,
#~the corresponding inputs have to be passed as `Vectors`, where each element
#~represents one bin of the distribution.

#~A `Measurement` can be excluded from the model by setting the switch `active=false`.
#~For a `MeasurementDistribution`, the keyword `active` accepts `true` or `false`
#~to (de)activate the whole distribution or a vector of booleans for (de)activating only certain bins.

measurements = (
    Meas1 = Measurement(xsec1, 21.6, uncertainties = (stat=0.8, syst=1.8, another_unc=2.3),
            active=true), # `active = false`: exclude measurement from fit (default: active = true)

    Meas2 = Measurement(Observable(xsec2, min=0), 1.9,
            uncertainties = (stat=0.6, syst=0.9, another_unc=1.1), active=true),

    MeasDist = MeasurementDistribution(diff_xsec, [1.9, 2.93, 4.4],
               uncertainties = (stat = [0.7, 1.1, 1.2], syst= [0.7, 0.8, 1.3], another_unc = [1.0, 1.2, 1.9]),
               active=[true, false, true]), # `active = false`: exclude all bins from fit, `active = [true, true, false]`: exclude only third bin from fit
)

#~Further information on the constructors see the API documentation of [`Measurement`](https://tudo-physik-e4.github.io/EFTfitter.jl/dev/api/#EFTfitter.Measurement)
#~and [`MeasurementDistribution`](https://tudo-physik-e4.github.io/EFTfitter.jl/dev/api/#EFTfitter.MeasurementDistribution).

#md  # !!! note
#md  #     When using only one measurement or only one type of uncertainties, make sure to insert a comma, like: `uncertainties = (stat = 0.5,)` so that Julia can parse the [`NamedTuple`](https://docs.julialang.org/en/v1/manual/types/#Named-Tuple-Types) correctly!
#!md # Note: When using only one measurement or only one type of uncertainties,
#!md #~make sure to insert a comma, like: `uncertainties = (stat = 0.5,)` so that
#!md #~Julia can parse the [`NamedTuple`](https://docs.julialang.org/en/v1/manual/types/#Named-Tuple-Types) correctly!

#!jl # ### Correlations
#jl #~============= Correlations =============================================#
#~The correlations between the uncertainties of the measurements need to be provided
#~for each of the uncertainty types. We can pass them by defining a `NamedTuple`
#~of [`Correlation`](https://tudo-physik-e4.github.io/EFTfitter.jl/dev/api/#EFTfitter.Correlation)
#~objects that contain the corresponding correlation matrices.
#~The correlation matrix for each type of uncertainty needs to have a size
#~of ``N \times N``, where ``N`` is the number of measurements, counting each bin of a distribution.
#~When a certain type of uncertainty should not be considered, it can be deactivated
#~by setting `active = false`. This means that the uncertainty values given in the
#~corresponding `Measurement` and `MeasurementDistribution` objects will not be used.

#~When assuming the uncertainties of all measurements are uncorrelated, you can
#~use the `NoCorrelation` object for easily passing an identity matrix of the correct size.

#~When using a large number of measurements, entering the correlation matrix becomes
#~quite impractical, especially if you want to add further measurements later.
#~With the function `to_correlation_matrix`, it is possible to enter a correlation
#~matrix by simply specifying the names of the measurements that should be correlated
#~and the value of the corresponding correlation coefficient.
#~When using a `MeasurementDistribution`, the inter-bin correlations can also be
#~entered by passing a matrix. By appending `_binX` to the name of a `MeasurementDistribution`,
#~the Xth bin of the distribution can be accessed.
#~Note: This function is evaluated from top to bottom, so if you overwrite a
#~specific correlation value, the last value entered will be used.

dist_corr = [1.0 0.5 0.0;
             0.5 1.0 0.0;
             0.0 0.0 1.0]

another_corr_matrix = to_correlation_matrix(measurements,
    (:Meas1, :Meas2, 0.4), # correlate measurements :Meas1 and :Meas2 with a correlation coefficient of 0.4
    (:Meas1, :MeasDist, 0.1), # correlate all bins of :MeasDist with :Meas1 with 0.1
    (:MeasDist, :MeasDist, dist_corr), # correlate the bins of :MeasDist according to the matrix dist_corr
    (:MeasDist_bin2, :MeasDist_bin3, 0.3), # correlate bin2 of :MeasDist with bin3 with 0.3 (overwrites the corresponding element set in the previous line, but ignored in fit since MeasDist_bin2 is inactive)
)

#-

correlations = (
    stat = NoCorrelation(active=true), # will use the identity matrix of the correct size

    syst = Correlation([1.0 0.5 0.3 0.2 0.2;
                        0.5 1.0 0.2 0.2 0.2;
                        0.3 0.2 1.0 0.2 0.2;
                        0.2 0.2 0.2 1.0 0.2;
                        0.2 0.2 0.2 0.2 1.0], active=false), # `active = false`: ignore all uncertainty values and correlations for this type of uncertainty

    another_unc = Correlation(another_corr_matrix, active=true)
)


text:
using Dates
using TimeZones
using CBinding

packagedir = joinpath(dirname(pathof(DWDataReader)), "..")
includedir = joinpath(packagedir, "src", "include")

# CBinding.jl: Set up compiler context
c`-std=c99 -Wall -I$(includedir) -lDWDataReaderLib64 -L$(packagedir)`

const c"int64_t" = Int64

# CBinding.jl: Create Julia types and bindings for DLL functions from header
c"""
  #include <DWDataReaderLib.h>
"""j;

struct FileInfo
    sample_rate::Float64
    start_store_time::ZonedDateTime
    duration::Float64
end

function Base.show(io::IO, fi::FileInfo)
    println(io, "$(fi.start_store_time) $(fi.sample_rate) Hz $(fi.duration) s")
end

"""
    DWDataReader.File(source; kwargs...) => DWDataReader.File

Read DEWESoft input data files (.d7d extension) and return a `DWDataReader.File` object.

"""
struct File
    name::String
    info::FileInfo
    nchannels::Int64
    channels::Cptr{DWChannel}
    closed::Bool
    delete::Bool
    readerid::Int8
    lookup::Dict{Symbol,DWChannel}
end

getname(f::File) = getfield(f, :name)
getnchannels(f::File) = getfield(f, :nchannels)

function Base.show(io::IO, f::File)
    println(io, "DWDataReader.File(\"$(getname(f))\"): $(getnchannels(f)) channels")
end

# Enables f[:channel] via internal lookup Dict
function Base.getproperty(f::File, ch::Symbol)
    lookup = getfield(f, :lookup)
    return haskey(lookup, ch) ? lookup[ch] : getfield(f, ch)
end

function Base.getindex(f::File, ch::Symbol)
    lookup = getfield(f, :lookup)
    return haskey(lookup, ch) ? lookup[ch] : getfield(f, ch)
end

# New File objects register via the global readers counter as per DLL requirements
global readers = 0
setreaders(r) = (global readers += r)

"""Deprecated in favor of direct DWChannel.name via `getproperty` mechanism"""
function getname(c::DWChannel)
    replace(String(c.name), r"\0+$" => s"")
end

# Property access for wrapped DWChannel with null-terminated string truncation
function Base.getproperty(c::DWChannel, v::Symbol)
    x = invoke(getproperty, Tuple{supertype(DWChannel),Symbol}, c, v)
    return v == :name ? replace(String(x), r"\0+$" => s"") : x
end

function File(
    source;
    # options
    debug::Bool = false,
    kw...,
)
    isempty(source) && throw(ArgumentError("unable to read DW data from empty source"))
    name = source
    closed = true
    delete = false

    DWInit()

    # file Reader management
    readerid = DWDataReader.readers # DWInit creates the first readerid 0
    if readerid > 0 # Add reader only if this is not the first
        status = DWAddReader()
        status != 0 && throw(status)
    end

    DWDataReader.setreaders(1)

    # Check for matching number of readers
    num_readers = Ref{Cint}(0)
    status = DWGetNumReaders(num_readers)
    status != 0 && throw(status)
    num_readers[] != readers && throw("DWGetNumReaders=$(num_readers[]) != $(readers)")

    # Opening the file
    dwfileinfo = Ref(DWFileInfo())
    status = DWOpenDataFile(source, dwfileinfo)
    status != 0 && throw(status)
    closed = false
    fileinfo = FileInfo(
        dwfileinfo[].sample_rate,
        startstoretime(dwfileinfo[].start_store_time),
        dwfileinfo[].duration,
    )

    # How to make this the File AbstractVector{DWChannel} type?
    nchannels = DWGetChannelListCount()
    channels = Libc.malloc(DWChannel(), nchannels)
    DWGetChannelList(channels)

    lookup = Dict(Symbol(getname(channels[i])) => channels[i] for i = 1:nchannels)

    File(name, fileinfo, nchannels, channels, closed, delete, readerid, lookup)
end

"""Set this DWFile instance as the active reader"""
function activate(f::File, verifyopen::Bool = true)
    verifyopen && f.closed && error("I/O operation on closed file")
    status = DWSetActiveReader(f.readerid)
    status != 0 && throw(status)
end

function numberofsamples(ch::DWChannel)
    count = DWGetScaledSamplesCount(ch.index)
    count < 0 &&
        throw("DWGetScaledSamplesCount($(ch.index))=$(count) should be non-negative")
    count
end

"""Load and return full speed data as vector"""
function scaled(ch::DWChannel, arrayindex = 0)
    !(0 <= arrayindex < ch.array_size) && throw("arrayIndex is out of range")
    count = numberofsamples(ch)
    data = zeros(count * ch.array_size)
    time = zeros(count)
    status = DWGetScaledSamples(ch.index, Cint(0), count, data, time)
    status != 0 && throw(status)
    return [time data]
end

function startstoretime(time::Float64)
    epoch = DateTime(1899, 12, 30)
    epochutc = ZonedDateTime(epoch, tz"UTC")
    microseconds = time * 24 * 60 * 60 * 1000 * 1000
    epochutc + Dates.Microsecond(round(microseconds))
end


text:
using LinearAlgebra

include("util.jl")

const Torus32 = Int32

struct LweKey
    n :: Int
    tlwe :: Array{Bool, 1}

    LweKey(rng::AbstractRNG, n::Int) = new(n, rand(rng, Bool, n))
end

mutable struct EncriptedText
    a :: Array{Torus32, 1}
    b :: Torus32

    EncriptedText(a::Array{Torus32, 1}, b::Torus32) =
        new(a, b)
end

function lwe_encrypt_bool(rng::AbstractRNG, message::Bool, key::LweKey, α::Float64, μ::Int)
    a = rand_uniform_Torus32(rng, key.n)
    s = key.tlwe
    m = Int32(μ*(2*message - 1))
    e = modular_gaussian(rng, α)
    b = a ⋅ s + m + e
    EncriptedText(a, b)
end

function lwe_decrypt_bool(ciphertext::EncriptedText, key::LweKey)
    (ciphertext.b - ciphertext.a ⋅ key.tlwe) > 0
end

Base.:+(x::EncriptedText, y::EncriptedText) =
    EncriptedText(x.a + y.a, x.b + y.b)

Base.:-(x::EncriptedText, y::EncriptedText) =
    EncriptedText(x.a - y.a, x.b - y.b)

function Base.:*(x::Integer, y::EncriptedText)
    tx = Torus32(x)
    EncriptedText(tx * y.a, tx * y.b)
end

Base.:*(x::EncriptedText, y::Integer) = y * x

max_stars_repo_name: bbtatt/BBTTFHE

max_issues_repo_name: bbtatt/BBTTFHE

max_forks_repo_name: bbtatt/BBTTFHE


text:
module NatureGas
include("heatvalue.jl")
include("aga8.jl")

end # module

max_stars_repo_name: hzgzh/NG

max_issues_repo_name: hzgzh/NG

max_forks_repo_name: hzgzh/NG


text:
using StaticArrays, Distributions, ProgressMeter

"""
    Haplotype(mutations, n, t_birth, parent)

Type used by the `neutral_growth` simulation. Fields are `mutations` an ordered list of mutations defining the haplotype,
`n` the number of cells of that type, `t_birth` the time of birth of the first cell of this type and `parent` the rowindex of the parental haplotype
within the tumor Array.
"""
mutable struct Haplotype
    mutations :: SVector{L, Int} where L
    n :: Int
    t_birth :: Float64
    parent :: Int
end

"""
    neutral_growth!(tumor, obs, endsize, T=Inf; b, d, μ, t=0., Nthresh=endsize, Tthresh = Inf )

Neutral (exponential) growth simulation of `Haplotypes`. Receives a Vector of `Haplotypes`, an according `obs` Matrix, an `endsize` and final time `T` value.
`obs` records the following observables (**currently disabled for performance**):

* obs[m,1] records the parents haplotype n at birth of mutation m

* obs[m,2] records the sum of n of all haplotypes containing the parents last mutation while not
         containing m

         this includes estranged parents while avoiding offspring of m

* obs[m,3] records tumor size at birth of m

Kwargs are `b` birth-rate, `d` death-rate, `μ` mutation-rate, `t` current time, `Nthresh` and `Tthresh` size and time after which `μ` is set to zero.

Output is a named Tuple `(:tumor, :obs, :N, :t)` containing the final `Haplotype` Vector, observables, endsize and final time.
"""
function neutral_growth!(tumor, obs, endsize, T=Inf; b, d, μ, t=0., Nthresh=endsize, Tthresh = Inf )

    mutID = length(tumor)-1
    obsarr = Vector{Vector{Int}}()
    obstemp = Vector{Int}(undef, 3)
    F = cumsum(getfield.(tumor,:n))
    N = last(F)

    prog = ProgressUnknown("Progress: N ")
    while 0 < N < endsize && t < T
        μp = N < Nthresh && t < Tthresh ? μ : 0.

        p = rand()*(b+d)
        m = rand(1:N)
        row = findfirst(i-> i >= m, F)
        parent = tumor[row]

        t += rand(Exponential(1.))/((b+d)*N)
        if p > d

            if rand() < μp

                mutID += 1
                push!(tumor, Haplotype(push(parent.mutations, mutID), 1, t, row) )
                push!(F, N+1)

#                 obstemp[1] = parent.n
#                 obstemp[2] = isone(row) ? N : sum( getfield.(filter(h-> row-1 in h.mutations, tumor[row : mutID]),:n) )
#                 obstemp[3] = N
#                 push!(obsarr, copy(obstemp) )
            else
                parent.n += 1
                F[row:end] .+= 1
            end
            N += 1

        else
            parent.n -= 1
            F[row:end] .-= 1
            N -= 1
        end

        ProgressMeter.update!(prog, N)
    end
    obsnew = Matrix{Int}(undef, length(obsarr), 3)
#     for i=1:3
#         obsnew[:, i] = getindex.(obsarr, i)
#     end
    return (tumor=tumor, obs=vcat(obs, obsnew), N=N, t=t)
end

"""
    neutral_growth(endsize, T; args... )

Neutral (exponential) growth simulation of `Haplotypes`. Receives `endsize` and final time `T`. See documentation of `neutral_growth!`
for kwargs.

Output is a named Tuple `(:tumor, :obs, :N, :t)` containing the final `Haplotype` Vector, observables, endsize and final time.
"""
function neutral_growth(endsize, T=Inf; args... )
    mutID = 0
    tumor = [Haplotype(SVector{0, Int}(), 1, 0., 0 )]
    obs = Matrix{Int}(undef, 0, 3)

    out =  neutral_growth!(tumor, obs, endsize, T;  args...)
    return iszero(out[:N]) ? neutral_growth(endsize, T; args... ) : out
end

"""
    q(d; b, μ )
Function returning the extinction probability for given `d` death-rate, `b` birth-rate and `μ` mutation-rate.

**Branchingprocess `v1`**: only mutation of single randomly picked offspring possible at division. `μ` is the probability of mutation per cell division.

"""
q(d; b, μ ) = d / (b*(1-μ))

;

max_stars_repo_name: aangaji/Turnover

max_issues_repo_name: aangaji/Turnover

max_forks_repo_name: aangaji/Turnover


text:
__precompile__(true)

module Zomato

# External Imports
using HTTP
using JSON
import Base: show, @info

# Module Exports
export authenticate, get
export Auth, APIError

# see https://developers.zomato.com/documentation
export CategoriesAPI, CitiesAPI, CollectionsAPI, CuisinesAPI, EstablishmentsAPI, GeocodeAPI
export LocationDetailsAPI, LocationsAPI
export DailymenuAPI, RestaurantAPI, ReviewsAPI, SearchAPI

# ZomatoAPI
abstract type ZomatoAPI end

# Subtypes for ZomatoAPI
struct CategoriesAPI      <: ZomatoAPI end
struct CitiesAPI          <: ZomatoAPI end
struct CollectionsAPI     <: ZomatoAPI end
struct CuisinesAPI        <: ZomatoAPI end
struct EstablishmentsAPI  <: ZomatoAPI end
struct GeocodeAPI         <: ZomatoAPI end
struct LocationDetailsAPI <: ZomatoAPI end
struct LocationsAPI       <: ZomatoAPI end
struct DailymenuAPI       <: ZomatoAPI end
struct RestaurantAPI      <: ZomatoAPI end
struct ReviewsAPI         <: ZomatoAPI end
struct SearchAPI          <: ZomatoAPI end

# Routes for specific Subtypes
route(::Type{CategoriesAPI})      = "categories"
route(::Type{CitiesAPI})          = "cities"
route(::Type{CollectionsAPI})     = "collections"
route(::Type{CuisinesAPI})        = "cuisines"
route(::Type{EstablishmentsAPI})  = "establishments"
route(::Type{GeocodeAPI})         = "geocode"
route(::Type{LocationDetailsAPI}) = "location_details"
route(::Type{LocationsAPI})       = "locations"
route(::Type{DailymenuAPI})       = "dailymenu"
route(::Type{RestaurantAPI})      = "restaurant"
route(::Type{ReviewsAPI})         = "reviews"
route(::Type{SearchAPI})          = "search"

"""
Zomato Auth
"""
struct Auth
	base_url::String
	header::Dict{String, String}
end

Base.show(io::IO, z::Auth) = print(io, "Zomato(", z.base_url, ')')

"""
Authenticate
-----------
Takes a valid Zomato API Key
"""
function authenticate(api_key::String)
	Auth("https://developers.zomato.com/api/v2.1/", Dict("Accept" => "application/json", "user-key"=> api_key))
end

"""
Zomato API Error
"""
struct APIError <: Exception
	code::Int16
	response::HTTP.Response
end

"""
Get list of categories
---------------------
List of all restaurants categorized under a particular restaurant type can be obtained using /Search API with Category ID as inputs

	See https://developers.zomato.com/documentation#!/common/categories

"""
function get(z::Auth, ::Type{CategoriesAPI})
	@info "fetching categories..."
	helper(z, route(CategoriesAPI), Dict())
end

"""
Get city details
----------------
Find the Zomato ID and other details for a city . You can obtain the Zomato City ID in one of the following ways:

- City Name in the Search Query - Returns list of cities matching the query
- Using coordinates - Identifies the city details based on the coordinates of any location inside a city

If you already know the Zomato City ID, this API can be used to get other details of the city.

	See https://developers.zomato.com/documentation#!/common/cities

Arguments
---------

| Parameter | Description                      | Parameter Type | Data Type |
|:----------|:---------------------------------|:---------------|:----------|
| q         | query by city name               | query          | String    |
| lat       | latitude                         | query          | Float     |
| lon       | longitude                        | query          | Float     |
| city_ids  | comma separated city_id values   | query          | String    |
| count     | number of max results to display | query          | Int       |
"""
function get(z::Auth, ::Type{CitiesAPI}; kwargs...)
	@info "fetching city details..."
	helper(z, route(CitiesAPI), Dict(kwargs))
end

"""
Get zomato collections in a city
--------------------------------
Returns Zomato Restaurant Collections in a City. The location/City input can be provided in the following ways -

- Using Zomato City ID
- Using coordinates of any location within a city

List of all restaurants listed in any particular Zomato Collection can be obtained using the '/search' API with Collection ID and Zomato City ID as the input

	See https://developers.zomato.com/documentation#!/common/collections

Arguments
---------

| Parameter | Description                                     | Parameter Type | Data Type |
|:----------|:------------------------------------------------|:---------------|:----------|
| city_id   | id of the city for which collections are needed | query          | Int       |
| lat       | latitude                                        | query          | Float     |
| lon       | longitude                                       | query          | Float     |
| count     | number of max results to display                | query          | Int       |
"""
function get(z::Auth, ::Type{CollectionsAPI}; kwargs...)
	@info "fetching collections..."
	helper(z, route(CollectionsAPI), Dict(kwargs))
end

"""
Get list of all cuisines in a city
----------------------------------
The location/city input can be provided in the following ways -

- Using Zomato City ID
- Using coordinates of any location within a city

List of all restaurants serving a particular cuisine can be obtained using '/search' API with cuisine ID and location details

	See https://developers.zomato.com/documentation#!/common/cuisines

Arguments
---------

| Parameter | Description                                     | Parameter Type | Data Type |
|:----------|:------------------------------------------------|:---------------|:----------|
| city_id   | id of the city for which cuisines are needed    | query          | Int       |
| lat       | latitude                                        | query          | Float     |
| lon       | longitude                                       | query          | Float     |
"""
function get(z::Auth, ::Type{CuisinesAPI};kwargs...)
	@info "fetching cuisines... "
	helper(z, route(CuisinesAPI), Dict(kwargs))
end

"""
Get list of restaurant types in a city
---------------------------------------

The location/City input can be provided in the following ways -

- Using Zomato City ID
- Using coordinates of any location within a city

List of all restaurants categorized under a particular restaurant type can obtained using /Search API with Establishment ID and location details as inputs

	See https://developers.zomato.com/documentation#!/common/establishments

Arguments
---------

| Parameter | Description                                     | Parameter Type | Data Type |
|:----------|:------------------------------------------------|:---------------|:----------|
| city_id   | id of the city 															    | query          | Int       |
| lat       | latitude                                        | query          | Float     |
| lon       | longitude                                       | query          | Float     |
"""
function get(z::Auth, ::Type{EstablishmentsAPI}; kwargs...)
	@info "fetching establishments..."
	helper(z, route(EstablishmentsAPI), Dict(kwargs))
end

"""
Get location details based on coordinates
-----------------------------------------
Get Foodie and Nightlife Index, list of popular cuisines and nearby restaurants around the given coordinates

	See https://developers.zomato.com/documentation#!/common/geocode

Arguments
---------

| Parameter | Description                                     | Required | Parameter Type | Data Type |
|:----------|:------------------------------------------------|:---------|:---------------|:----------|
| lat       | latitude                                        | yes      | query          | Float     |
| lon       | longitude                                       | yes      | query          | Float     |

"""
function get(z::Auth, ::Type{GeocodeAPI}; kwargs...)
	@info "fetching geocode..."
	helper(z, route(GeocodeAPI), Dict(kwargs))
end

"""
Get zomato location details
---------------------------
Get Foodie Index, Nightlife Index, Top Cuisines and Best rated restaurants in a given location

	See https://developers.zomato.com/documentation#!/location/location_details

Arguments
---------

| Parameter   | Description                                     | Required | Parameter Type | Data Type |
|:------------|:------------------------------------------------|:---------|:---------------|:----------|
| entity_id   | location id obtained from locations api         | yes      | query          | Int       |
| entity_type | location type obtained from locations api       | yes      | query          | String    |
"""
function get(z::Auth, ::Type{LocationDetailsAPI}; kwargs...)
	@info "fetching location details..."
	helper(z, route(LocationDetailsAPI), Dict(kwargs))
end

"""
Search for locations
--------------------
Search for Zomato locations by keyword. Provide coordinates to get better search results

	See https://developers.zomato.com/documentation#!/location/locations

Arguments
---------

| Parameter   | Description                               | Required | Parameter Type | Data Type |
|:------------|:------------------------------------------|:---------|:---------------|:----------|
| query       | suggestion for location name              |          | query          | String    |
| lat         | latitude                                  | yes      | query          | Float     |
| lon         | longitude                                 | yes      | query          | Float     |
| count       | number of max results to display          |          | query          | Int       |
"""
function get(z::Auth, ::Type{LocationsAPI}; kwargs...)
	@info "fetching locations..."
	helper(z, route(LocationsAPI), Dict(kwargs))
end

"""
Get daily menu of a restaurant
------------------------------
Get daily menu using Zomato restaurant ID.

	See https://developers.zomato.com/documentation#!/restaurant/restaurant

Arguments
---------

| Parameter   | Description                                  | Required | Parameter Type | Data Type |
|:------------|:---------------------------------------------|:---------|:---------------|:----------|
| res_id      | id of restaurant whose details are requested | yes      | query          | Int       |
"""
function get(z::Auth, ::Type{DailymenuAPI}; kwargs...)
	@info "fetching dailymenu..."
	helper(z, route(DailymenuAPI), Dict(kwargs))
end

"""
Get restaurant details
----------------------
Get detailed restaurant information using Zomato restaurant ID. Partner Access is required to access photos and reviews.

	See https://developers.zomato.com/documentation#!/restaurant/restaurant_0

Arguments
---------

| Parameter   | Description                                  | Required | Parameter Type | Data Type |
|:------------|:---------------------------------------------|:---------|:---------------|:----------|
| res_id      | id of restaurant whose details are requested | yes      | query          | Int       |
"""
function get(z::Auth, ::Type{RestaurantAPI}; kwargs...)
	@info "fetching restaurant details..."
	helper(z, route(RestaurantAPI), Dict(kwargs))
end

"""
Get restaurant reviews
----------------------
Get restaurant reviews using the Zomato restaurant ID. Only 5 latest reviews are available under the Basic API plan.

	See https://developers.zomato.com/documentation#!/restaurant/reviews

Arguments
---------

| Parameter   | Description                                  | Required | Parameter Type | Data Type |
|:------------|:---------------------------------------------|:---------|:---------------|:----------|
| res_id      | id of restaurant whose details are requested | yes      | query          | Int       |
| start       | fetch results after this offset              | yes      | query          | Int       |
| count       | number of max results to display             |          | query          | Int       |
"""
function get(z::Auth, ::Type{ReviewsAPI}; kwargs...)
	@info "fetching restaurant reviews..."
	helper(z, route(ReviewsAPI), Dict(kwargs))
end

"""
Search Zomato Restaurants
-------------------------
The location input can be specified using Zomato location ID or coordinates. Cuisine / Establishment / Collection IDs can be obtained from respective api calls. Get up to 100 restaurants by changing the 'start' and 'count' parameters with the maximum value of count being 20. Partner Access is required to access photos and reviews.
Examples:

- To search for 'Italian' restaurants in 'Manhattan, New York City', set cuisines = 55, entity_id = 94741 and entity_type = zone
- To search for 'cafes' in 'Manhattan, New York City', set establishment_type = 1, entity_type = zone and entity_id = 94741
- Get list of all restaurants in 'Trending this Week' collection in 'New York City' by using entity_id = 280, entity_type = city and collection_id = 1

	See https://developers.zomato.com/documentation#!/restaurant/search

"""
function get(z::Auth, ::Type{SearchAPI}; kwargs...)
	@info "searching restaurants..."
	helper(z, route(SearchAPI), Dict(kwargs))
end

"""
HTTP Helper
"""
function helper(z::Auth, path::String, d::Dict)
	try
		query = query_builder(d)
		response = HTTP.get(z.base_url * "$path?" * query, z.header)
		return JSON.parse(String(response.body))
	catch error_response
		throw(APIError(error_response.status, error_response.response))
	end
end

"""
Query Builder
"""
function query_builder(kwargs::Dict)
	query = ""
	for item in kwargs
		query *= "&$(item[1])=" * string(item[2])
	end
	return query
end

end # module


text:
"""
    abstract type Block includes basic network struct like:
    1. Dense, MLP
    2. RNN irnn IndRNN rin lstm IndLSTM
    3. RNNs IRNN IndRNNs RIN LSTM IndLSTMs
    4. PlainConv1d

"""
abstract type Block end
export Block
export bytesof
export gradsof
export paramsof
export xparamsof
export nparamsof
export weightsof
export unbiasedof

include("./1-chain.jl")
include("./2-residual.jl")
include("./3-dropout.jl")
include("./4-macro.jl")

include("./conv/0-conv.jl")
include(  "./fc/0-fc.jl")
include( "./rnn/0-rnns.jl")

max_stars_repo_name: sonosole/Delta

max_issues_repo_name: sonosole/Delta

max_forks_repo_name: sonosole/Delta


text:
module Macros
using MacroTools: prewalk, postwalk, @capture
import Markdown: Markdown, MD, @md_str
import TOML
greet() = print("Hello World!")

struct HelpStr
    str::String
end

# export @help_str
macro help_str(str)
end

# export @info_str
macro info_str(str)
end

function get_args_and_order(default_config)

    arg_order = String[]
    args = Expr[]
    postwalk(default_config) do ex
        chk = @capture(ex, k_ => v_)
        # @show k
        if chk
            push!(arg_order, k)
            push!(args, :($k=>$v))
        end
        ex
    end
    args, arg_order

end

function get_help_str(default_config, __module__)
    start_str = "# Automatically generated docs for $(__module__) config."
    help_str_strg = HelpStr[
        HelpStr(start_str)
    ]
    postwalk(default_config) do expr
        expr_str = string(expr)
        if length(expr_str) > 5 && (expr_str[1:5] == "help\"" || expr_str[1:5] == "info\"")
            push!(help_str_strg, HelpStr(string(expr)[6:end-1]))
        end
        expr
    end
    md_strs = [Markdown.parse(hs.str) for hs in help_str_strg]
    join(md_strs, "\n")
end

macro generate_config_funcs(default_config)
    # println(default_config)

    func_name = :default_config
    help_func_name = :help
    create_toml_func_name = :create_toml_template
    mdstrings = String[]
    src_file = relpath(String(__source__.file))

    docs = get_help_str(default_config, __module__)
    args, arg_order = get_args_and_order(default_config)
    # @show args

    create_toml_docs = """
        create_toml_template(save_file=nothing; database=false)

    Used to create toml template. If save_file is nothing just return toml string.
    If database is true, then generate using mysql backend otherwise generate using file backend.
    """
    quote
        @doc $(docs)
        function $(esc(func_name))()
            Dict{String, Any}(
                $(args...)
            )

        end

        function $(esc(help_func_name))()
            local docs = Markdown.parse($(docs))
            # InteractiveUtils.less(docs)
            display(docs)
        end

        function $(esc(create_toml_func_name))(save_file=nothing; database=false)
            local ao = filter((str)->str!="save_dir", $arg_order)
            cnfg = $(esc(func_name))()
            cnfg_filt = filter((p)->p.first != "save_dir", cnfg)

            mod = $__module__

            save_info = if database
                """
                save_backend="mysql" # mysql only database backend supported
                database="DATABASE_NAME" # Database name
                save_dir="Path/To/Save" # Directory name for exceptions, settings, and more!"""
            else
                """
                save_backend="file" # file saving mode
                file_type = "jld2" # using JLD2 as save type
                save_dir="Path/To/Save" # save location"""
            end

            toml_str = """

            info=\"\"\"
            Config generated automatically from default_config. When you have finished
            making changes to this config, replace this info with useful information.
            \"\"\"

            [config]
            $(save_info)
            exp_file = "$($src_file)"
            exp_module_name = "$(mod)"
            exp_func_name = "main_experiment"
            arg_iter_type = "iter"

            [static_args]
            """
            buf = IOBuffer()

            TOML.print(buf,
                cnfg_filt, sorted=true, by=(str)->findfirst((strinner)->str==strinner, ao)
                       )
            toml_str *= String(take!(buf))

            toml_str *= """\n[sweep_args]
            # Put args to sweep over here.
            """

            if save_file === nothing
                toml_str
            else
                open(save_file, "w") do io
                    write(io, toml_str)
                end
            end

        end
    end
end

end # module


text:
#  Copyright 2017, Iain Dunning, Joey Huchette, Miles Lubin, and contributors
#  This Source Code Form is subject to the terms of the Mozilla Public
#  License, v. 2.0. If a copy of the MPL was not distributed with this
#  file, You can obtain one at https://mozilla.org/MPL/2.0/.

# This file extends JuMP to indicator constraints. It is a good example of how
# JuMP can be extended.

function _build_indicator_constraint(
    _error::Function,
    variable::AbstractVariableRef,
    constraint::ScalarConstraint,
    ::Type{MOI.IndicatorSet{A}},
) where {A}
    set = MOI.IndicatorSet{A}(moi_set(constraint))
    return VectorConstraint([variable, jump_function(constraint)], set)
end
function _indicator_variable_set(::Function, variable::Symbol)
    return variable, MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}
end
function _indicator_variable_set(_error::Function, expr::Expr)
    if expr.args[1] == :¬ || expr.args[1] == :!
        if length(expr.args) != 2
            _error(
                "Invalid binary variable expression `$(expr)` for indicator constraint.",
            )
        end
        return expr.args[2], MOI.IndicatorSet{MOI.ACTIVATE_ON_ZERO}
    else
        return expr, MOI.IndicatorSet{MOI.ACTIVATE_ON_ONE}
    end
end
function parse_one_operator_constraint(
    _error::Function,
    vectorized::Bool,
    ::Union{Val{:(=>)},Val{:⇒}},
    lhs,
    rhs,
)
    variable, S = _indicator_variable_set(_error, lhs)
    if !isexpr(rhs, :braces) || length(rhs.args) != 1
        _error(
            "Invalid right-hand side `$(rhs)` of indicator constraint. Expected constraint surrounded by `{` and `}`.",
        )
    end
    rhs_con = rhs.args[1]
    rhs_vectorized, rhs_parsecode, rhs_buildcall =
        parse_constraint_expr(_error, rhs_con)
    if vectorized != rhs_vectorized
        _error("Inconsistent use of `.` in symbols to indicate vectorization.")
    end
    if vectorized
        buildcall = :(
            _build_indicator_constraint.(
                $_error,
                $(esc(variable)),
                $rhs_buildcall,
                $S,
            )
        )
    else
        buildcall = :(_build_indicator_constraint(
            $_error,
            $(esc(variable)),
            $rhs_buildcall,
            $S,
        ))
    end
    return rhs_parsecode, buildcall
end

function constraint_string(
    print_mode,
    constraint::VectorConstraint{F,<:MOI.IndicatorSet{A}},
) where {F,A}
    # TODO Implement pretty IJulia printing
    var_str = function_string(print_mode, constraint.func[1])
    if A == MOI.ACTIVATE_ON_ZERO
        var_str = "!" * var_str
    end
    con = ScalarConstraint(constraint.func[2], constraint.set.set)
    con_str = constraint_string(print_mode, con)
    return var_str * " => {" * con_str * "}"
end

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
# This module implements the MMA Algorithm in Julia
# as described in:
# AU  - Svanberg, Krister
# TI  - The method of moving asymptotes—a new method for structural optimization
# JO  - International Journal for Numerical Methods in Engineering
# JA  - Int. J. Numer. Meth. Engng.
module MMA

using Parameters, StructArrays, Setfield, TimerOutputs, Base.Threads
using ..GPUUtils, CuArrays, CUDAnative, KissThreading, ..Utilities
using GPUArrays: GPUVector
using CUDAdrv: CUDAdrv

const dev = CUDAdrv.device()
const ctx = CUDAdrv.CuContext(dev)

using LinearAlgebra

import Optim
import Optim: OnceDifferentiable, Fminbox, GradientDescent, update!,
                MultivariateOptimizationResults, OptimizationTrace, maxdiff,
                LineSearches, ConjugateGradient, LBFGS, AbstractOptimizer
import Base: min, max, show
import ..GPUUtils: whichdevice

export Model, box!, ineq_constraint!, optimize, ConvergenceState, Workspace

struct MMA87 <: AbstractOptimizer end
struct MMA02 <: AbstractOptimizer end
abstract type TopOptAlgorithm end

include("utils.jl")
include("model.jl")
include("dual.jl")
include("primal.jl")
include("lift.jl")
include("trace.jl")
include("workspace.jl")

const μ = 0.1
const ρmin = 1e-5

default_dual_caps(::Type{T}) where T = (eps(T), one(T))

function optimize(  model::Model,
                    x0,
                    optimizer = MMA02(),
                    suboptimizer = Optim.ConjugateGradient();
                    options = Options()
                )
    check_error(model, x0)
    workspace = Workspace(model, x0, optimizer, suboptimizer; options = options)
    return optimize!(workspace)
end

@params mutable struct MMAResult{T}
    optimizer
    initial_x::AbstractVector{T}
    minimizer::AbstractVector{T}
    minimum::T
    iter::Int
    maxiter_reached::Bool
    tol::Tolerances
    convstate
    f_calls::Integer
    g_calls::Integer
    h_calls::Integer
end

abstract type ConvergenceCriteria end
struct DefaultCriteria <: ConvergenceCriteria end
struct KKTCriteria <: ConvergenceCriteria end

function get_kkt_residual(∇f_x, g, ∇g_x, c, x, lb, ub)
    r = mapreduce(max, 1:length(x), init = zero(eltype(x))) do j
        if lb[j] == x[j]
            return abs(min(0, ∇f_x[j] + dot(@view(∇g_x[j,:]), c)))
        elseif x[j] == ub[j]
            return abs(min(0, -∇f_x[j] - dot(@view(∇g_x[j,:]), c)))
        elseif  lb[j] < x[j] < ub[j]
            return zero(eltype(x))
        else
            throw("x is out of range.")
        end
    end
    r = mapreduce(max, 1:length(g), init = r) do i
        return max(abs(g[i] * c[i]), g[i], 0)
    end
    return r
end

function update_values!(w, _x = nothing)
    @unpack model, primal_data, f_calls, g_calls = w
    @unpack x1, x2, ∇f_x, f_x, f_x_previous, g, ∇g = primal_data
    n_i = length(constraints(model))
    n_j = dim(model)

    if _x === nothing
        x = primal_data.x
        f_x = eval_objective(model, x, ∇f_x)
    else
        x = _x
        x2 .= x1
        x1 .= primal_data.x
        primal_data.x .= x
        f_x_previous, f_x = f_x, eval_objective(model, x, ∇f_x)
    end
    T = eltype(x)
    f_calls, g_calls = f_calls + 1, g_calls + 1

    # Correct for functions whose gradients go to infinity at some points, e.g. √x
    while mapreduce(or, ∇f_x, init = false) do x
            isinf(x) || isnan(x)
        end

        map!(x, x1, x) do x1, x
            T(0.01)*x1 + T(0.99)*x
        end
        f_x = eval_objective(model, x, ∇f_x)
        f_calls, g_calls = f_calls + 1, g_calls + 1
    end

    # Evaluate the constraints and their Jacobian
    map!(g, 1:n_i) do i
        @views eval_constraint(model, i, x, ∇g[:,i])
    end

    @pack! w = f_calls, g_calls
    @pack! primal_data = f_x, f_x_previous

    return w
end

function optimize!(workspace::Workspace{T, TV, TM}) where {T, TV, TM}
    @unpack model, optimizer, suboptimizer, options = workspace
    @unpack primal_data, dual_data = workspace
    @unpack asymptotes_updater, variable_bounds_updater = workspace
    @unpack cvx_grad_updater, lift_updater, lift_resetter, x_updater = workspace
    @unpack dual_obj, dual_obj_grad, tracing, tr = workspace
    @unpack outer_iter, iter = workspace

    @unpack subopt_options, dual_caps = options
    @unpack x0, x, x1, x2, ∇f_x, g, ∇g = primal_data
    @unpack ng_approx = lift_updater
    @unpack λ, l, u = dual_data

    n_i = length(constraints(model))
    n_j = dim(model)
    maxiter = options.maxiter
    outer_maxiter = options.outer_maxiter

    while !(workspace.convstate.converged) && iter < maxiter &&
        outer_iter < outer_maxiter

        outer_iter += 1
        asymptotes_updater(Iteration(outer_iter))

        # Track trial points two steps back
        tmap!(identity, x2, x1)
        tmap!(identity, x1, x)

        # Update convex approximation
        ## Update bounds on primal variables
        variable_bounds_updater()

        ## Computes values and updates gradients of convex approximations of objective and constraints
        cvx_grad_updater()

        if optimizer isa MMA02
            lift_resetter(Iteration(outer_iter))
        end
        lift = true
        while !workspace.convstate.converged && lift && iter < options.maxiter
            iter += 1

            # Solve dual
            λ.cpu .= min.(dual_caps[2], max.(λ.cpu, dual_caps[1]))

            d = OnceDifferentiable(dual_obj, dual_obj_grad, λ.cpu)
            minimizer = Optim.optimize(d, l, u, λ.cpu, Optim.Fminbox(suboptimizer), subopt_options).minimizer

            copyto!(λ.cpu, minimizer)
            dual_obj_grad(ng_approx, λ.cpu)

            update_values!(workspace)
            workspace.convstate = assess_convergence(workspace)
            lift = (optimizer isa MMA87) ? false : lift_updater()
        end

        # Print some trace if flag is on
        @mmatrace()
    end
    h_calls = 0
    @unpack f_calls, g_calls = workspace
    @unpack f_x, f_x_previous = primal_data
    @pack! workspace = outer_iter, iter, tr, tracing

    results = MMAResult(    optimizer,
                            x0,
                            x,
                            f_x,
                            iter,
                            iter == options.maxiter,
                            options.tol,
                            deepcopy(workspace.convstate),
                            f_calls,
                            g_calls,
                            h_calls
                        )
    return results
end

end # module


text:
function dataframe_xy_test()
	@testset "DataFrameXY" begin
		ds = test_data_settings();
		rf = CollegeStratData.raw_entry_gpa_parental(ds);
		fPath = data_file(rf);
		df = CollegeStratData.read_by_xy(fPath);
		@test size(df) == (5,6)

		colHeaderV = CollegeStratData.col_headers(df);
		@test colHeaderV[1] == CollegeStratData.col_header(:gpa, 1)
		rowHeaderV = CollegeStratData.row_headers(df);
		@test rowHeaderV[2] == CollegeStratData.row_header(2)

		m = CollegeStratData.data_matrix(df);
		@test isa(m, Matrix{Float64})
		@test size(m) == (length(rowHeaderV), length(colHeaderV))

		total = CollegeStratData.total(df);
		@test isa(total, Float64)
		@test total > 0.0

		colTotalV = CollegeStratData.col_totals(df);
		@test isa(colTotalV, Vector{Float64})
		@test all(colTotalV .> 0.0)
		@test all(isfinite.(colTotalV))
		rowTotalV = CollegeStratData.row_totals(df);
		@test isa(rowTotalV, Vector{Float64})
		@test all(rowTotalV .> 0.0)
		@test all(isfinite.(rowTotalV))
	end
end

function dataframe_x_test()
	@testset "DataFrame by X" begin
		ds = test_data_settings();
		rf = CollegeStratData.raw_afqt_pct_qual(ds);
		fPath = data_file(rf);
		@test isfile(fPath)
		d = CollegeStratData.read_by_x(fPath);
		@test isa(d, CollegeStratData.DataFrameX)
		@test length(d) > 3
		v = CollegeStratData.data_vector(d);
		@test length(v) == length(CollegeStratData.row_indices(d))
		@test all(isfinite.(v))
		@test all(v .> 0.0)
		v2 = CollegeStratData.read_vector_by_x(fPath);
		@test v ≈ v2
	end
end

@testset "DataFrameXY" begin
	dataframe_xy_test()
	dataframe_x_test()
end

# -----------


text:
type EvoAnalyserLogger <: Logger

end

function write_meta_to_log_file(l::EvoAnalyserLogger)

end

function log!()

end

"""
Converts a provided collection of individuals into a CSV string, where each
individual is represented by a record within the string.

**Parameters:**

* ``ic::IndividualCollection``, the collection of individuals.
* ``fs::FitnessScheme``, the fitness scheme used by the individuals belonging
  to the collection.
* ``prefix::UTF8String``, the prefix that should be added to each CSV
  record. Used to provide generation and deme numbers. If any information
  is provided in the prefix, it MUST be suffixed by a semi-colon.

**Returns:**

A CSV string, in the form of a UTF-8 string.
"""

function individuals_to_csv(
  ic::IndividualCollection,
  fs::FitnessScheme,
  prefix::UTF8String
)::UTF8String
  # Initialise the CSV row for each individual.
  num = length(ic)
  serialised = UTF8String["$(prefix) $(i)" for i in 1:num]

  # Record the developmental stage for each individual.
  for rep in keys(ic.stages)
    for (i, stage) in enumerate(ic.stages[rep])
      serialised[i] = serialised[i] * "; $(to_s(stage))"
    end
  end

  # Add the fintess values for each individual to the JSON objects,
  # along with their evaluated flag.
  for (i, csv) in enumerate(serialised)
    csv = csv * "; true; " * to_s(fs, ic.fitnesses[i])
  end

  # Glue together the individual CSV entries.
  return join(serialised, "\n")
end

"""
Converts a provided collection of individuals into a list of JSON descriptions.

**Parameters:**

* ``ic::IndividualCollection``, the collection of individuals.
* ``fs::FitnessScheme``, the fitness scheme used by the individuals belonging
  to the collection.
* ``prefix::UTF8String``, the prefix that should be added to each JSON
  description. Used to provide generation and deme numbers. If any information
  is provided in the prefix, it MUST be suffixed by a comma.

**Returns:**

A list of JSON descriptions, implemented as a vector of UTF-8 strings.
"""

# Idea: Could supply a JSON prefix? (generations, deme number, etc).
function individuals_to_json(
  ic::IndividualCollection,
  fs::FitnessScheme,
  prefix::UTF8String
)
  # Find the number of individuals in the provided collection.
  num = length(ic)

  # Create an array to hold the JSON objects for each of the individuals within
  # the provided collection, initialised with the supplied prefix and the
  # individual's position.
  serialised = UTF8String["$(prefix) \"position\": $(i)" for i in 1:num]

  # Add each of the representations used by the individual to the log entries.
  for rep in keys(ic.stages)
    for (i, stage) in enumerate(ic.stages[rep])
      serialised[i] = serialised[i] * ", \"$(rep)\": $(to_json_s(stage))"
    end
  end

  # Add the fitness values for each individual to the JSON objects, along with
  # their evaluated flag.
  for (i, json) in enumerate(serialised)
    json = json * ", \"evaluated\": true, " * to_json(fs, ic.fitnesses[i])
  end

  # Add the opening and closing tags to each JSON object.
  map!(json -> "{" * json * "}", serialised)

  # Return the vector of JSON descriptions.
  return serialised
end


text:
export matuscsirmaztetraproj, matuscsirmaztetra!

function matuscsirmaztetraproj(i, j, k, l)
    alpha = -4ingleton(i, j)
    beta1 = submodular(4, k, l, i)
    beta2 = submodular(4, k, l, j)
    beta  = beta1 + beta2
    gamma = 2submodular(4, i, j, k) + 2submodular(4, i, j, l)
    delta = submodular(4, j, l, k) + submodular(4, i, l, k) + submodular(4, j, k, l) + submodular(4, i, k, l)
    [alpha  beta  gamma  delta]'
end

function matuscsirmaztetra!(h::EntropyCone{15}, i, j, k, l, tetravertices::Matrix=[1 1 1;1 -1 -1; -1 1 -1; -1 -1 1]')
    tight!(h)
    intersect!(h, -ingleton(i, j))
    # er = getextremerays(h)
    # name = ["r_1", "br_ij", "r_1^jl", "r_1^j", "r_1^jk", "r_2^k", "r_2^l", "r_3", "r_1^i", "r_1^il", "r_1^ik"]
    # println(length(er))
    # for i in 1:length(er)
    #   println(name[i])
    #   println(er[i])
    # end
    # alpha = -4ingleton(i, j)
    # beta1 = submodular(4, k, l, i)
    # beta2 = submodular(4, k, l, j)
    # beta  = beta1 + beta2
    # gamma = 2submodular(4, i, j, k) + 2submodular(4, i, j, l)
    # delta = submodular(4, j, l, k) + submodular(4, i, l, k) + submodular(4, j, k, l) + submodular(4, i, k, l)
    removeredundantinequalities!(h.poly)
    #poly = [alpha  beta  gamma  delta]' * h.poly
    matuscsirmaztetra!(h.poly, i, j, k, l, tetravertices)
end

function matuscsirmaztetra!(poly::Polyhedron{15}, i, j, k, l, tetravertices::Matrix=[1 1 1;1 -1 -1; -1 1 -1; -1 -1 1]')
    poly = transformgenerators(poly, matuscsirmaztetraproj(i,j,k,l))
    poly = radialprojectoncut(poly, [1, 1, 1, 1], 1)
    removeredundantgenerators!(poly)
    #poly = tetravertices * poly
    poly = transformgenerators(poly, tetravertices)
    removeredundantgenerators!(poly)
    poly
end


text:
module MyInterpolations

export MyLinInterp

immutable MyLinInterp
    grid::Array
    vals::Array
end

function (f::MyLinInterp)(x)
    i = searchsortedlast(f.grid,x)
    k = searchsortedfirst(f.grid,x)
    if i == 0 || (i == length(f.grid) && k == length(f.grid) + 1)
        return 0
    end

    if i == length(f.grid) && k != length(f.grid) + 1
        return (f.vals[i])
    end

    interpolated_value = (x - f.grid[i])*(f.vals[i+1]-f.vals[i])/(f.grid[i+1]-f.grid[i])+f.vals[i]
    return interpolated_value
end

end


text:
module reporting

export summarise_linkage_run, compare_linkage_runs

using CSV
using DataFrames
using Dates
using Logging

"Summarise the results of a linkage run."
function summarise_linkage_run(directory1, outfile)
    @info "$(now()) Starting summary of linkage run."
    directory2 = replace("x$(rand())", "." => "")  # Dummy directory. Random so that it likely doesn't exist.
    for i = 1:1_000_000
        !isdir(directory2) && break  # Directory doesn't exist...break
        directory2 = replace("x$(rand())", "." => "")
    end
    report_on_linkage_runs(directory1, directory2, outfile, 1)
    dlm    = get_delimiter(outfile)
    report = DataFrame(CSV.File(outfile; delim=dlm))
    rename!(report, :status1 => :status)
    CSV.write(outfile, report; delim=dlm, append=false)
    @info "$(now()) Finished summary of linkage run."
end

"Summarise a row-by-row comparison of linkage runs."
function compare_linkage_runs(directory1, directory2, outfile)
    @info "$(now()) Starting comparison of linkage runs."
    report_on_linkage_runs(directory1, directory2, outfile, 2)
    @info "$(now()) Finished comparison of linkage runs."
end

"""
Report on 1 or 2 linkage runs.

If `n_linkage_runs` is 1, then the function reports on the linkage run that was written to directory 1.
If `n_linkage_runs` is 2, then the function compares the linkage runs in directory 1 and directory 2.
In both cases the resulting report is written to the specified output file.

When comparing 2 runs:

- Typically the linkage run in directory 1 predates that in directory 2.
- Results are compared table-wise. For example, directory1/output/table_A.tsv is compared to directory2/output/table_A.tsv.
- The output is a table with columns:
  - tablename: A table in either linkage run (directory1/output/ or directory2/output/).
  - status1:   The status of a record in the table in the 1st linkage run.
  - status2:   The status of a record in the table in the 2nd linkage run.
  - nrecords:  The number of records with status1 in the 1st linkage run and status2 in the 2nd linkage run.

The statuses are:

- nonexistent: The record doesn't exist in the linkage run.
- unlinked:    The record (in the table) exists and is not linked to the spine.
- linked with criteria ID X: The record exists and is linked to the spine by CriteriaId X.
- existent:    The spine record exists in 1 linkage run but not the other.

When reporting on just 1 linkage run the `status2` column is omitted from the result.
"""
function report_on_linkage_runs(directory1::String, directory2::String, outfile::String, n_linkage_runs::Int)
    run_checks(directory1, directory2, outfile, n_linkage_runs)
    dlm = get_delimiter(outfile)
    init_result(Dict(("LINKAGE RUNS", directory1, directory2) => missing), outfile, dlm, n_linkage_runs)
    outdir1   = joinpath(directory1, "output")
    outdir2   = joinpath(directory2, "output")
    filelist1 = [x for x in readdir(outdir1) if isfile(joinpath(outdir1, x))]
    filelist2 = n_linkage_runs == 2 ? [x for x in readdir(outdir2) if isfile(joinpath(outdir2, x))] : String[]
    filelist  = Set(vcat(filelist1, filelist1))
    filelist  = sort!([x for x in filelist])
    for filename in filelist
        filename == "criteria.tsv" && continue
        filename == "links.tsv"    && continue
        tablename = filename == "spine.tsv" ? "spine" : filename[1:(findfirst("_primarykey_and_eventid.tsv", filename)[1] - 1)]
        @info "$(now()) Reporting results for table $(tablename)"
        fullpath1 = joinpath(outdir1, filename)
        fullpath2 = joinpath(outdir2, filename)
        d         = Dict{Tuple{String, String, String}, Int}()  # (tablename, status1, status2) => nrecords
        if tablename == "spine"
            isfile(fullpath1)  && isfile(fullpath2)  && compare_spines!(d, fullpath1, fullpath2)
            isfile(fullpath1)  && !isfile(fullpath2) && report_solitary_spine!(d, fullpath1, 1)
            !isfile(fullpath1) && isfile(fullpath2)  && report_solitary_spine!(d, fullpath2, 2)
        else
            isfile(fullpath1)  && isfile(fullpath2)  && compare_event_tables!(d, fullpath1, fullpath2, tablename)
            isfile(fullpath1)  && !isfile(fullpath2) && report_solitary_event_table!(d, fullpath1, 1, tablename)
            !isfile(fullpath1) && isfile(fullpath2)  && report_solitary_event_table!(d, fullpath2, 2, tablename)
        end
        append_to_result(d, outfile, dlm, n_linkage_runs)
    end
end

################################################################################
# Compare 2 existing tables.

function compare_spines!(result::Dict, spinepath1::String, spinepath2::String)
    entityids1 = get_set_of_values(spinepath1, :EntityId)
    entityids2 = get_set_of_values(spinepath2, :EntityId)
    s = intersect(entityids1, entityids2)
    k = ("spine", "existent", "existent")
    increment_value!(result, k, length(s))
    s = setdiff(entityids1, entityids2)
    k = ("spine", "existent", "nonexistent")
    increment_value!(result, k, length(s))
    s = setdiff(entityids2, entityids1)
    k = ("spine", "nonexistent", "existent")
    increment_value!(result, k, length(s))
end

function compare_event_tables!(result::Dict, fullpath1::String, fullpath2::String, tablename::String)
    eventids1 = get_set_of_values(fullpath1, :EventId)
    eventids2 = get_set_of_values(fullpath2, :EventId)
    eventid2criteraid1 = construct_eventid2criteriaid(joinpath(dirname(fullpath1), "links.tsv"), tablename) # eventid => criteriaid for events in tablename
    eventid2criteraid2 = construct_eventid2criteriaid(joinpath(dirname(fullpath2), "links.tsv"), tablename)
    for eventid in eventids1
        status1 = haskey(eventid2criteraid1, eventid) ? linkage_status(eventid2criteraid1[eventid]) : "unlinked"
        status2 = linkage_status(eventid, eventids2, eventid2criteraid2)
        k       = (tablename, status1, status2)
        increment_value!(result, k, 1)
    end
    for eventid in eventids2
        in(eventid, eventids1) && continue  # Already processed this eventid
        status1 = linkage_status(eventid, eventids1, eventid2criteraid1)
        status2 = haskey(eventid2criteraid2, eventid) ? linkage_status(eventid2criteraid2[eventid]) : "unlinked"
        k       = (tablename, status1, status2)
        increment_value!(result, k, 1)
    end
end

################################################################################
# Report on a table that exists in only 1 linkage run.

function report_solitary_spine!(result::Dict{Tuple{String, String, String}, Int}, spinepath::String, status_number)
    entityids = get_set_of_values(spinepath, :EntityId)
    n = length(entityids)
    k = status_number == 1 ? ("spine", "existent", "nonexistent") : ("spine", "nonexistent", "existent")
    increment_value!(result, k, n)
end

"""
Modified: result.

Reports on outdir/filename.
The tablenamne is derived from filename.
The specified status column (:statusX, where x == status_number) and the nrecords column are filled appropriately.
The other status column is filled with "nonexistent".
"""
function report_solitary_event_table!(result::Dict{Tuple{String, String, String}, Int}, fullpath::String, status_number::Int, tablename::String)
    eventids   = get_set_of_values(fullpath, :EventId)
    nevents    = length(eventids)
    nlinks     = 0
    links_path = joinpath(dirname(fullpath), "links.tsv")
    for row in CSV.Rows(links_path; reusebuffer=true)
        tname = getproperty(row, :TableName)
        tname != tablename && continue
        nlinks       += 1
        CriteriaId    = getproperty(row, :CriteriaId)
        active_status = linkage_status(CriteriaId)
        k = status_number == 1 ? (tablename, active_status, "nonexistent") : (tablename, "nonexistent", active_status)
        increment_value!(result, k, 1)
    end
    n_unlinked = nevents - nlinks
    k = status_number == 1 ? (tablename, "unlinked", "nonexistent") : (tablename, "unlinked", active_status)
    increment_value!(result, k, n_unlinked)
end

################################################################################
# Utils

linkage_status(criteriaid) = "linked with criteria ID $(criteriaid)"

function linkage_status(eventid, eventids, eventid2criteraid)
    haskey(eventid2criteraid, eventid) && return linkage_status(eventid2criteraid[eventid])  # Linked (exists in links)
    in(eventid, eventids) && return "unlinked"  # Unlinked (exists in events but not in links)
    "nonexistent"                               # Non-existent (does not exist in events)
end

function run_checks(directory1::String, directory2::String, outfile::String, n_linkage_runs::Int)
    msgs = String[]
    !isdir(directory1) && push!(msgs, "This directory does not exist: $(directory1)")
    isdir(outfile)     && push!(msgs, "The output file is a directory. Please specify a file.")
    if !isdir(dirname(outfile))
        msg = "The directory containing the output file does not exist. Please create it or specify a different output file."
        push!(msgs, msg)
    end
    if n_linkage_runs == 1      # Report on a single linkage run
    elseif n_linkage_runs == 2  # Compare 2 linkage runs
        !isdir(directory2) && push!(msgs, "This directory does not exist: $(directory2)")
    else
        push!(msgs, "n_linkage_runs must be 1 or 2 (currently $(n_linkage_runs))")
    end
    !isempty(msgs) && earlyexit(msgs)
end

function get_delimiter(filename::String)
    ext = lowercase(splitext(filename)[2])
    ext = occursin(".", ext) ? replace(ext, "." => "") : "csv"
    ext == "tsv" ? '\t' : ','
end

"Returns: Set(values...) where values are in column colname of the table located at fullpath."
function get_set_of_values(fullpath::String, colname::Symbol)
    result = Set{String}()
    for row in CSV.Rows(fullpath; reusebuffer=true)
        push!(result, getproperty(row, colname))
    end
    result
end

"""
Modified: d.

Increments d[k] by n if it exists, else initialises d[k] to n.
"""
function increment_value!(d, k, n)
    n == 0 && return
    if haskey(d, k)
        d[k] += n
    else
        d[k] = n
    end
end

function construct_eventid2criteriaid(links_path::String, tablename::String)
    result = Dict{String, String}()
    for row in CSV.Rows(links_path; reusebuffer=true)
        getproperty(row, :TableName) != tablename && continue
        eventid = getproperty(row, :EventId)
        result[eventid] = getproperty(row, :CriteriaId)
    end
    result
end

function earlyexit(msgs::Vector{String})
    isempty(msgs) && return
    for msg in msgs
        @error msg
    end
    @warn "Exiting early."
    exit(1)
end

earlyexit(msg::String) = earlyexit([msg])

################################################################################
# Write result to disk

function init_result(d::Dict, outfile::String, dlm::Char, n_linkage_runs::Int)
    if n_linkage_runs == 1
        write_to_linkage_report(d, outfile, dlm, false)
    elseif n_linkage_runs == 2
        write_to_linkage_comparison(d, outfile, dlm, false)
    else
        error("n_linkage_runs should be not 1 or 2 (currently $(n_linkage_runs))")
    end
end

function append_to_result(d::Dict, outfile::String, dlm::Char, n_linkage_runs::Int)
    if n_linkage_runs == 1
        write_to_linkage_report(d, outfile, dlm, true)
    elseif n_linkage_runs == 2
        write_to_linkage_comparison(d, outfile, dlm, true)
    else
        error("n_linkage_runs should be not 1 or 2 (currently $(n_linkage_runs))")
    end
end

function write_to_linkage_comparison(d::Dict, outfile::String, dlm::Char, apnd::Bool)
    result = DataFrame(tablename=String[], status1=String[], status2=String[], nrecords=Union{Int, Missing}[])
    for (k, v) in d
        push!(result, (tablename=k[1], status1=k[2], status2=k[3], nrecords=v))
    end
    sort!(result, [:tablename, :status1, :status2])
    CSV.write(outfile, result; delim=dlm, append=apnd)
end

function write_to_linkage_report(d::Dict, outfile::String, dlm::Char, apnd::Bool)
    result = DataFrame(tablename=String[], status1=String[], nrecords=Union{Int, Missing}[])
    for (k, v) in d
        push!(result, (tablename=k[1], status1=k[2], nrecords=v))
    end
    sort!(result, [:tablename, :status1])
    CSV.write(outfile, result; delim=dlm, append=apnd)
end

end


text:
"""
    XLSXFile(filepath)

Creates an empty instance of XLSXFile.
"""
XLSXFile(filepath::AbstractString) = XLSXFile(filepath, Dict{String, EzXML.Document}(), EmptyWorkbook(), Vector{Relationship}())

"""
    read(filepath) :: XLSXFile

Main function for reading an Excel file.
"""
function read(filepath::AbstractString) :: XLSXFile
    @assert isfile(filepath) "File $filepath not found."
    xf = XLSXFile(filepath)

    xlfile = ZipFile.Reader(filepath)
    try
        for f in xlfile.files

            # parse only XML files
            if !ismatch(r".xml", f.name) && !ismatch(r".rels", f.name)
                #warn("Ignoring non-XML file $(f.name).") # debug
                continue
            end

            doc = EzXML.readxml(f)
            xf.data[f.name] = doc
        end

        # Check for minimum package requirements
        check_minimum_requirements(xf)

        parse_relationships!(xf)
        parse_workbook!(xf)

    finally
        close(xlfile)
    end

    return xf
end

get_default_namespace(d::EzXML.Document) = get_default_namespace(EzXML.root(d))

function get_default_namespace(r::EzXML.Node) :: String
    for (prefix, ns) in EzXML.namespaces(r)
        if prefix == ""
            return ns
        end
    end

    error("No default namespace found.")
end

# See section 12.2 - Package Structure
function check_minimum_requirements(xf::XLSXFile)
    mandatory_files = ["_rels/.rels",
                       "xl/workbook.xml",
                       "[Content_Types].xml",
                       "xl/_rels/workbook.xml.rels"
                       ]

    for f in mandatory_files
        @assert in(f, filenames(xf)) "Malformed XLSX File. Couldn't find file $f in the package."
    end

    nothing
end

"""
Parses package level relationships defined in `_rels/.rels`.
Prases workbook level relationships defined in `xl/_rels/workbook.xml.rels`.
"""
function parse_relationships!(xf::XLSXFile)
    xroot = xmlroot(xf, "_rels/.rels")
    @assert EzXML.nodename(xroot) == "Relationships" "Malformed XLSX file $(xf.filepath). _rels/.rels root node name should be `Relationships`. Found $(EzXML.nodename(xroot))."
    @assert EzXML.namespaces(xroot) == Pair{String,String}[""=>"http://schemas.openxmlformats.org/package/2006/relationships"]

    for el in EzXML.eachelement(xroot)
        push!(xf.relationships, Relationship(el))
    end
    @assert !isempty(xf.relationships) "Relationships not found in _rels/.rels!"

    xroot = xmlroot(xf, "xl/_rels/workbook.xml.rels")
    @assert EzXML.nodename(xroot) == "Relationships" "Malformed XLSX file $(xf.filepath). xl/_rels/workbook.xml.rels root node name should be `Relationships`. Found $(EzXML.nodename(xroot))."
    @assert EzXML.namespaces(xroot) == Pair{String,String}[""=>"http://schemas.openxmlformats.org/package/2006/relationships"]

    for el in EzXML.eachelement(xroot)
        push!(xf.workbook.relationships, Relationship(el))
    end
    @assert !isempty(xf.workbook.relationships) "Relationships not found in xl/_rels/workbook.xml.rels"

    nothing
end

function parse_shared_strings!(xf::XLSXFile)
    workbook = xf.workbook

    relationship_type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
    if has_relationship_by_type(workbook, relationship_type)
        sst_root = xmlroot(xf, "xl/" * get_relationship_target_by_type(workbook, relationship_type))
        workbook.sst = SharedStrings(sst_root)
    end

    nothing
end

"""
  parse_workbook!(xf::XLSXFile)

Updates xf.workbook from xf.data[\"xl/workbook.xml\"]
"""
function parse_workbook!(xf::XLSXFile)
    xroot = xmlroot(xf, "xl/workbook.xml")
    @assert EzXML.nodename(xroot) == "workbook" "Malformed xl/workbook.xml. Root node name should be 'workbook'. Got '$(EzXML.nodename(xroot))'."

    # workbook to be parsed
    workbook = xf.workbook

    # workbookPr
    local foundworkbookPr::Bool = false
    for node in EzXML.eachelement(xroot)

        if EzXML.nodename(node) == "workbookPr"
            foundworkbookPr = true

            # read date1904 attribute
            if haskey(node, "date1904")
                attribute_value_date1904 = node["date1904"]

                if attribute_value_date1904 == "1" || attribute_value_date1904 == "true"
                    workbook.date1904 = true
                elseif attribute_value_date1904 == "0" || attribute_value_date1904 == "false"
                    workbook.date1904 = false
                else
                    error("Could not parse xl/workbook -> workbookPr -> date1904 = $(attribute_value_date1904).")
                end
            else
                # does not have attribute => is not date1904
                workbook.date1904 = false
            end

            break
        end
    end
    @assert foundworkbookPr "Malformed: couldn't find workbookPr node element in 'xl/workbook.xml'."

    # shared string table
    parse_shared_strings!(xf)

    # sheets
    sheets = Vector{Worksheet}()
    for node in EzXML.eachelement(xroot)
        if EzXML.nodename(node) == "sheets"

            for sheet_node in EzXML.eachelement(node)
                @assert EzXML.nodename(sheet_node) == "sheet" "Unsupported node $(EzXML.nodename(sheet_node)) in 'xl/workbook.xml'."
                worksheet = Worksheet(xf, sheet_node)
                push!(sheets, worksheet)
            end

            break
        end
    end
    workbook.sheets = sheets

    # styles
    STYLES_RELATIONSHIP_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
    if has_relationship_by_type(workbook, STYLES_RELATIONSHIP_TYPE)
        styles_target = get_relationship_target_by_type(workbook, STYLES_RELATIONSHIP_TYPE)
        workbook.styles = xmldocument(xf, "xl/" * styles_target)

        # check root node name for styles.xml
        styles_root = EzXML.root(workbook.styles)
        @assert get_default_namespace(styles_root) == STYLES_NAMESPACE_XPATH_ARG[1][2] "Unsupported styles XML namespace $(get_default_namespace(styles_root))."
        @assert EzXML.nodename(styles_root) == "styleSheet" "Malformed package. Expected root node named `styleSheet` in `styles.xml`."
    end

    nothing
end