text:
#ENV["CUDA_VISIBLE_DEVICES"] = "0,1,2,3,4,5,6,7"
#using Revise
using ADSeismic
using ADCME
using PyPlot
using MAT
using Optim
using Random
using DelimitedFiles
using Dates
matplotlib.use("Agg")
close("all")

gpu = has_gpu() ? true : false

data_dir = "data/acoustic"
method = "FWI/BP_TV_3"

figure_dir = string("figure/",method)
result_dir = string("result/",method)
loss_file = joinpath(result_dir, "loss_$(Dates.now()).txt")

check_path(dir) = !ispath(dir) ? mkpath(dir) : nothing
check_path(figure_dir)
check_path(result_dir)

################### Inversion using Automatic Differentiation #####################
reset_default_graph()
# model_name = "models/marmousi2-model-smooth.mat"
# model_name = "models/marmousi2-model-smooth-large.mat"
model_name = "models/BP-model-smooth.mat"

## load model setting
params = load_params(model_name, vp_ref=1e3)
src = load_acoustic_source(model_name)
rcv = load_acoustic_receiver(model_name)
vp0 = matread(model_name)["vp"]
vp_ = Variable(vp0)
TV_loss = 1e-3 * (sum(abs(vp_[2:end,:] - vp_[1:end-1,:])) + sum(abs(vp_[:,2:end]-vp_[:,1:end-1])))
if exists(matopen(model_name), "mask")
  mask = matread(model_name)["mask"]
  vp = mask .* vp_ + (1.0.-mask) .* vp0
end

## assemble acoustic propagator model
model = x->AcousticPropagatorSolver(params, x, vp)

## load data
std_noise = 0
Random.seed!(1234);
Rs = Array{Array{Float64,2}}(undef, length(src))
for i = 1:length(src)
    # Rs[i] = readdlm(joinpath(data_dir, "marmousi-r$i.txt"))
    Rs[i] = readdlm(joinpath(data_dir, "BP-r$i.txt"))
    Rs[i] .+= randn(size(Rs[i])) .* std(Rs[i]) .* std_noise
end

## calculate loss
if gpu
  losses, grads = compute_loss_and_grads_GPU(model, src, rcv, Rs, vp_, aux_loss=TV_loss)
  grad = sum(grads)
  loss = sum(losses)
else
  [SimulatedObservation!(model(src[i]), rcv[i]) for i = 1:length(src)]
  loss = sum([sum((rcv[i].rcvv-Rs[i])^2) for i = 1:length(rcv)])
  grad = gradients(loss, vp_)
end

sess = Session(); init(sess)
loss0 = run(sess, loss)
TV_loss0 = run(sess, TV_loss)
@info "Initial loss: ", loss0
@info "Initial TV loss: ", TV_loss0

## run inversion
fp = open(loss_file, "w")
write(fp, "0,$loss0\n")
function callback(_, iter, loss)
  if iter%10==0
    # x = Array(reshape(vs[1:(params.NY+2)*(params.NX+2)], params.NY+2, params.NX+2))
    x = run(sess, vp)'
    clf()
    pcolormesh([0:params.NX+1;]*params.DELTAX/1e3,[0:params.NY+1;]*params.DELTAY/1e3,  x, shading="auto", cmap="jet")
    axis("scaled")
    colorbar(shrink=0.4)
    xlabel("x (km)")
    ylabel("z (km)")
    gca().invert_yaxis()
    title("Iteration = $iter")
    savefig(joinpath(figure_dir, "inv_$(lpad(iter,5,"0")).png"), bbox_inches="tight")
    writedlm(joinpath(result_dir, "inv_$(lpad(iter,5,"0")).txt"), x)
  end
  write(fp, "$iter,$loss\n")
  flush(fp)
end

## BFGS
Optimize!(sess, loss, 5000, vars=[vp_], grads=grad,  callback=callback)

## Adam
# global_step = tf.Variable(0, trainable=false)
# max_iter = 50000
# lr_decayed = tf.train.cosine_decay(1.0, global_step, max_iter)
# opt = AdamOptimizer(lr_decayed).minimize(loss, global_step=global_step, colocate_gradients_with_ops=true)

# time = 0
# for iter = 0:max_iter
#   t = @elapsed  _, ls, lr = run(sess, [opt, loss, lr_decayed])
#   callback(nothing, iter, ls)
#   println("   $iter\t$ls\t$lr\t$t")
# end

close(fp)


text:
version = v"0.4.3"

using BinDeps, Libdl

@BinDeps.setup

function validate(name, handle)
    v_ptr_major = Libdl.dlsym(handle, :blossom5_julia_version_major)
    v_ptr_minor = Libdl.dlsym(handle, :blossom5_julia_version_minor)
    if v_ptr_major == C_NULL || v_ptr_minor == C_NULL
        return false
    end
    major = ccall(v_ptr_major, Cint, ())
    minor = ccall(v_ptr_minor, Cint, ())
    bin_version = VersionNumber(major, minor+1, 0, ("",))
    return version < bin_version
end

blossom5int32 = library_dependency("blossom5int32", validate=validate)
blossom5float64 = library_dependency("blossom5float64", validate=validate)

provides(Sources, URI("https://pub.ist.ac.at/~vnk/software/blossom5-v2.05.src.tar.gz"), blossom5int32, SHA="6bb2fabaa4a5eb957385c81f2cdad139454afebbdb19d6deea61ced5f7c06489")

prefix = usrdir(blossom5int32)
blossom5srcdir = joinpath(srcdir(blossom5int32), "blossom5-v2.05.src")
blossom5int32libfile = joinpath(libdir(blossom5int32), "blossom5int32.so")
blossom5float64libfile = joinpath(libdir(blossom5float64), "blossom5float64.so")

if Sys.isapple()
    blossom5int32libfile = joinpath(libdir(blossom5int32), "blossom5int32.dylib")
    blossom5float64libfile = joinpath(libdir(blossom5float64), "blossom5float64.dylib")
end

provides(BuildProcess,
    (@build_steps begin
        `rm -rf $blossom5int32libfile`
        `rm -rf $blossom5srcdir`
        GetSources(blossom5int32)
        @build_steps begin
            ChangeDirectory(blossom5srcdir)
            FileRule(blossom5int32libfile,
                @build_steps begin
                    CreateDirectory(joinpath(prefix, "lib"))
                    `sh -c "patch < ../../sharedlib.patch"`
                    `sh -c "cp ../../interface/* ./"`
                    MakeTargets(["all"])
                    `cp -f blossom5.so $blossom5int32libfile`
                end)
        end
    end), blossom5int32)

provides(BuildProcess,
    (@build_steps begin
        `rm -rf $blossom5float64libfile`
        `rm -rf $blossom5srcdir`
        GetSources(blossom5int32)
        @build_steps begin
            ChangeDirectory(blossom5srcdir)
            FileRule(blossom5float64libfile,
                @build_steps begin
                    CreateDirectory(joinpath(prefix, "lib"))
                    `sh -c "patch < ../../sharedlib.patch"`
                    `sh -c "cp ../../interface/* ./"`
                    `sh -c "patch < ../../float64.patch"`
                    MakeTargets(["all"])
                    `cp -f blossom5.so $blossom5float64libfile`
                end)
        end
    end), blossom5float64)

@BinDeps.install Dict([(:blossom5int32, :_jl_blossom5int32),
                       (:blossom5float64, :_jl_blossom5float64)])

ext: jl


text:
using LightXML, JSON

###
# Formatter taken from the README of JSON.jl
import JSON.Writer
import JSON.Writer.JSONContext
mutable struct PYONContext <: JSONContext
    underlying::JSONContext
end

for delegate in [:indent,
                 :delimit,
                 :separate,
                 :begin_array,
                 :end_array,
                 :begin_object,
                 :end_object]
    @eval JSON.Writer.$delegate(io::PYONContext) = JSON.Writer.$delegate(io.underlying)
end
Base.write(io::PYONContext, byte::UInt8) = write(io.underlying, byte)

JSON.Writer.show_null(io::PYONContext) = print(io, "None")
pyonprint(io::IO, obj) = let io = PYONContext(JSON.Writer.PrettyContext(io, 4))
    JSON.print(io, obj)
    return
end
###

function generate_dict()
    file = joinpath(@__DIR__, "instructions.xml")
    # Download the list of instructions from https://uops.info/xml.html
    if !isfile(file)
        download("https://uops.info/instructions.xml", file)
    end
    xml = parse_file(file)
    # Get the list of all extensions
    extensions = get_elements_by_tagname(root(xml), "extension")

    # Accumulator for all instructions.  The strategy is the following: we loop
    # over the extensions from the lower ones to the higher ones, if an
    # instruction is already found in a lower extension, then it is not added to
    # the higher one.
    all_instructions = String[]
    dict = Dict{String,Vector{String}}("unknown" => String[], "cpuid" => ["cpuid"])
    for name in (
        "mmx", "sse", "sse2", "sse3", "ssse3", "sse4", "avx", "aes", "pclmulqdq" , # sandybridge (aka AVX)
        "movbe", "avx2", "rdwrfsgs", "fma", "bmi1", "bmi2", "f16c", # haswell (aka AVX2)
        "pku", "rdseed", "adcx", "clflush", "xsavec", "xsaves", "clwb", "avx512evex", "avx512vex", # skylake-avx512 (aka AVX512)
    )
        instructions = String[]
        for idx in findall(x -> name == lowercase(attribute(x, "name")), extensions)
            for instruction in get_elements_by_tagname(extensions[idx], "instruction")
                instruction = lowercase(replace(attribute(instruction, "asm"), r"{[a-z]+} " => ""))
                if instruction ∉ all_instructions
                    unique!(sort!(push!(all_instructions, instruction)))
                    unique!(sort!(push!(instructions, instruction)))
                end
            end
        end
        dict[name] = instructions
    end
    free(xml)
    # We're basically converting an XML to a JSOn, funny isn't it?
    open(joinpath(@__DIR__, "..", "src", "auditor", "instructions.json"), "w") do io
        pyonprint(io, dict)
        # Be nice and add a newline at the end of the file
        println(io)
    end
    return dict
end


text:
@testset "enumtype" begin

@testset "instances" begin
    @test instances(FieldType) == (EE, HH)
    @test instances(BC) == (PERIODIC, CONDUCTING)
end

@testset "numel" begin
    @test numel(FieldType) == 2
    @test numel(BC) == 2
end

@testset "integers" begin
    @test Int.(SVec(instances(FieldType))) == nEH == [nE, nH]
end

@testset "alter" begin
    @test alter(EE) == HH
    @test alter(HH) == EE

    @test alter(nE) == nH
    @test alter(nH) == nE
end

@testset "ft2gt" begin
    @test MaxwellBase.ft2gt(EE,EE) == PRIM
    @test MaxwellBase.ft2gt(HH,EE) == DUAL
    @test MaxwellBase.ft2gt(EE,HH) == DUAL
    @test MaxwellBase.ft2gt(HH,HH) == PRIM
end

end  # @testset "enumtype"


text:
using Documenter, SauterSchwabQuadrature

makedocs(modules=[SauterSchwabQuadrature], doctest=false)

deploydocs(
    deps = Deps.pip("pygments","mkdocs", "python-markdown-math"),
    repo = "github.com/ga96tik/SauterSchwabQuadrature.jl.git",
    julia  = "0.6",
    osname = "linux")


text:
Base.exponent(G::AbstractPermutationGroup) = exponent(conjugacy_classes(G))
Base.exponent(cclasses::AbstractVector) = lcm(order.(first.(cclasses)))
dixon_prime(G::AbstractPermutationGroup) = dixon_prime(order(G), exponent(G))

function dixon_prime(cclasses::AbstractVector)
    ordG = sum(length, cclasses)
    m = exponent(cclasses)
    return dixon_prime(ordG, m)
end

function dixon_prime(ordG::Integer, exponent::Integer)
    p = 2 * floor(Int, sqrt(ordG))
    while true
        p = nextprime(p + 1)
        isone(p % exponent) && break # we need -1 to be in the field
    end
    return p
end

function common_esd(Ns, F::Type{<:FiniteFields.GF})
    @assert !isempty(Ns)
    esd = EigenSpaceDecomposition(F.(first(Ns)))
    for N in Iterators.rest(Ns, 2)
        esd = refine(esd, F.(N))
        @debug N esd.eigspace_ptrs
        isdiag(esd) && return esd
    end
    return esd
end

characters_dixon(G::AbstractPermutationGroup) =
    characters_dixon(conjugacy_classes(G))

function characters_dixon(cclasses::AbstractVector{<:AbstractOrbit})
    p = dixon_prime(cclasses)
    chars_𝔽p = characters_dixon(cclasses, FiniteFields.GF{p})
    return complex_characters(chars_𝔽p)
end

function characters_dixon(
    cclasses::AbstractVector{<:AbstractOrbit},
    F::Type{<:FiniteFields.GF},
)
    Ns = [CMMatrix(cclasses, i) for i = 1:length(cclasses)]
    esd = common_esd(Ns, F)
    @assert isdiag(esd) "Class Matricies failed to diagonalize! $esd"
    inv_ccls = _inv_of(cclasses)
    return [
        normalize!(Character(vec(eigensubspace), inv_ccls, cclasses))
        for eigensubspace in esd
    ]
end

function _multiplicities(
    chars::AbstractVector{<:Character{F}},
    cclasses = conjugacy_classes(first(chars)),
) where {F<:FiniteFields.GF}

    e = Int(exponent(cclasses))
    ie = inv(F(e))
    ω = FiniteFields.rootofunity(F, e)

    multiplicities = zeros(Int, length(chars), length(cclasses), e)
    powermap = PowerMap(cclasses)
    for (i, χ) in enumerate(chars)
        for j = 1:length(cclasses), k = 0:e-1
            multiplicities[i, j, k+1] =
                Int(ie * sum(χ[powermap[j, l]] * ω^-(k * l) for l = 0:e-1))
        end
    end

    return multiplicities
end

function complex_characters(
    chars::AbstractVector{<:Character{F}},
) where {F<:FiniteFields.GF}

    cclasses = conjugacy_classes(first(chars))
    lccl = length(cclasses)
    mult_c = _multiplicities(chars, cclasses)
    e = size(mult_c, 3) # the exponent

    inv_of_cls = first(chars).inv_of

    C = Cyclotomics.Cyclotomic{Int,Cyclotomics.SparseVector{Int,Int}}
    # C = typeof(Cyclotomics.E(5))

    complex_chars = Vector{Character{C,eltype(cclasses)}}(undef, length(chars))

    for i = 1:length(complex_chars)
        complex_chars[i] = Character(
            [
                Cyclotomics.reduced_embedding(sum(
                    mult_c[i, j, k+1] * E(e, k) for k = 0:e-1
                )) for j = 1:lccl
            ],
            inv_of_cls,
            cclasses,
        )
    end

    return complex_chars
end


text:
__precompile__(true)
module NeuroAnalysis

include("Base/Base.jl")
include("Visualization/Visualization.jl")
include("IO/IO.jl")

# export all symbols
for n in names(@__MODULE__, all=true)
    if Base.isidentifier(n) && n ∉ (nameof(@__MODULE__), :eval, :include)
        @eval export $n
    end
end

function __init__()
    f = joinpath(@__DIR__,"Visualization","Colors","colormaps.jld2")
    global ColorMaps = load(f)
    global PyOnewayANOVA = pyimport("statsmodels.stats.oneway")
end

end


text:
struct Advection <: Equation end
@declare_dofs Advection [:rho1, :rho2, :rho3]

struct PlanarWaves <: Scenario end
struct Sibson <: Scenario end

function is_periodic_boundary(equation::Advection, scenario::PlanarWaves)
    true
end

function is_periodic_boundary(equation::Advection, scenario::Sibson)
    false
end

function get_initial_values(eq::Advection, scenario::PlanarWaves, global_position; t=0.0)
    x, y = global_position
    # supports t ≠ 0 if there is an analytical solution
    if is_analytical_solution(eq, scenario)
        [ sin( 2*pi* ( (x + y) -  (2*t) ) ), sin( 2*pi* (y - t) ), 1.0] #For all t , analytical solution
    else
        [ sin(2*pi* (x + y)), sin(2*pi*y), 1.0] #at t=0
    end
end

function get_initial_values(eq::Advection, scenario::Sibson, global_position; t=0.0)
    x, y = global_position
    # supports t ≠ 0 if there is an analytical solution
    if is_analytical_solution(eq, scenario)
        println("No analytical solution yet")
    else
        [ cos( 4*π*sqrt( (x-1.25)^2 + (y-1.25)^2 ) ), 1.0, 1.0]
    end
end

function is_analytical_solution(equation::Advection, scenario::PlanarWaves)
    true
end

function is_analytical_solution(equation::Advection, scenario::Sibson)
    false
end

function evaluate_flux(eq::Advection, celldofs, cellflux)
    s = AdvectionShortcuts()

    # you can use s.rho1 == 1 etc to simplify stuff, these symbols can useful for simplicity
    # size(cellflux)=(2*order*order, ndof)=(2,3)
    # size(celldofs)=(order*order, ndof)=(1,3)

    order_sq, ndof = size(celldofs)
    for j=1:order_sq
        for i=1:ndof
            cellflux[j,i] = celldofs[j,i]
            cellflux[j + order_sq, i] = celldofs[j,i]
        end
    end
    #@info celldofs
    end

function max_eigenval(eq::Advection, celldata, normalidx)
    # Is actually correct!
    1.0
end


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

mutable struct EvaluatedNetworkSecurityGroup <: SwaggerModel
    networkSecurityGroupId::Any # spec type: Union{ Nothing, String } # spec name: networkSecurityGroupId
    appliedTo::Any # spec type: Union{ Nothing, String } # spec name: appliedTo
    matchedRule::Any # spec type: Union{ Nothing, MatchedRule } # spec name: matchedRule
    rulesEvaluationResult::Any # spec type: Union{ Nothing, Vector{NetworkSecurityRulesEvaluationResult} } # spec name: rulesEvaluationResult

    function EvaluatedNetworkSecurityGroup(;networkSecurityGroupId=nothing, appliedTo=nothing, matchedRule=nothing, rulesEvaluationResult=nothing)
        o = new()
        validate_property(EvaluatedNetworkSecurityGroup, Symbol("networkSecurityGroupId"), networkSecurityGroupId)
        setfield!(o, Symbol("networkSecurityGroupId"), networkSecurityGroupId)
        validate_property(EvaluatedNetworkSecurityGroup, Symbol("appliedTo"), appliedTo)
        setfield!(o, Symbol("appliedTo"), appliedTo)
        validate_property(EvaluatedNetworkSecurityGroup, Symbol("matchedRule"), matchedRule)
        setfield!(o, Symbol("matchedRule"), matchedRule)
        validate_property(EvaluatedNetworkSecurityGroup, Symbol("rulesEvaluationResult"), rulesEvaluationResult)
        setfield!(o, Symbol("rulesEvaluationResult"), rulesEvaluationResult)
        o
    end
end # type EvaluatedNetworkSecurityGroup

const _property_map_EvaluatedNetworkSecurityGroup = Dict{Symbol,Symbol}(Symbol("networkSecurityGroupId")=>Symbol("networkSecurityGroupId"), Symbol("appliedTo")=>Symbol("appliedTo"), Symbol("matchedRule")=>Symbol("matchedRule"), Symbol("rulesEvaluationResult")=>Symbol("rulesEvaluationResult"))
const _property_types_EvaluatedNetworkSecurityGroup = Dict{Symbol,String}(Symbol("networkSecurityGroupId")=>"String", Symbol("appliedTo")=>"String", Symbol("matchedRule")=>"MatchedRule", Symbol("rulesEvaluationResult")=>"Vector{NetworkSecurityRulesEvaluationResult}")
Base.propertynames(::Type{ EvaluatedNetworkSecurityGroup }) = collect(keys(_property_map_EvaluatedNetworkSecurityGroup))
Swagger.property_type(::Type{ EvaluatedNetworkSecurityGroup }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_EvaluatedNetworkSecurityGroup[name]))}
Swagger.field_name(::Type{ EvaluatedNetworkSecurityGroup }, property_name::Symbol) =  _property_map_EvaluatedNetworkSecurityGroup[property_name]

function check_required(o::EvaluatedNetworkSecurityGroup)
    true
end

function validate_property(::Type{ EvaluatedNetworkSecurityGroup }, name::Symbol, val)
end


text:
# Given rhoAB^(tensor n), sort the state so all A parts come first

export sortAB

""" `rhoSorted = sortAB(rhoBig, d, n)`

Given a state of the form rhoBig = rhoAB^(tensor n), rearrange, so all A parts are first, followed by all B parts. *d* is the dimension of A, assumed to be the same as for B. *n* is the number of copies.
"""

function sortAB(rhoBig::AbstractMatrix, d::Int, n::Int)

	# Check whether the input is a valid state and the dimensions match
	@assert isQuantumState(rhoBig) "The input is not valid quantum state."

	(d1,d2) = size(rhoBig);
	@assert d1 == (d^2)^n "Input dimensions don't match."

	rhoOut = permutesystems(rhoBig, [collect(0:2:2(n - 1)) + 1; collect(2:2:2n)], fill(d, 2n))

	return rhoOut;
end


text:
using NodeJS
using Test

@testset "NodeJS" begin

@test chomp(read(`$(nodejs_cmd()) -v`, String)) == "v12.13.0"
@test chomp(read(`$(npm_cmd()) -v`, String)) == "6.12.0"

end


text:
function abs(A:Assoc)
    #abs: Absolutee value of an inputted numerical associative array.

    if isa(A.val[1],AbstractString)
        error("Attempt to Abs a string valued Associative Array, only numerical Associative Array is accepted")
    end

    AT = deepcopy(A)
    AT.A = abs(AT.A)
    return AT
end

########################################################
# D4M: Dynamic Distributed Dimensional Data Model
# Architect: Dr. Jeremy Kepner (kepner@ll.mit.edu)
# Software Engineer: Alexander Chen (alexc89@mit.edu)
########################################################


text:
## ---------  Fixed by quality only

mutable struct TuitionByQualSwitches <: AbstractTuitionSwitches
    tuitionByQualV :: Vector{Double}
end

"""
	$(SIGNATURES)

Tuition only depends on college quality. Coefficients are directly taken from data.
Stored in model dollars.
"""
mutable struct TuitionByQual <: AbstractTuitionFunction
    objId :: ObjectId
    switches :: TuitionByQualSwitches
end

ModelParams.has_pvector(tf :: TuitionByQual) = false;

Base.show(io :: IO, switches :: TuitionByQualSwitches) =
    print(io, typeof(switches), " with tuition ",
    round.(switches.tuitionByQualV, digits = 2));

Base.show(io :: IO, t :: TuitionByQual) =
    print(io, t.switches);

StructLH.describe(switches :: TuitionByQualSwitches) = [
    "Tuition"  "fixed by college quality only.";
    "Tuition values by college"  "$(switches.tuitionByQualV)"
]

isfree(tf :: TuitionByQual, iCollege :: Integer) =
    tf.switches.tuitionByQualV[iCollege] == 0.0;

make_free!(switches :: TuitionByQualSwitches, iCollege :: Integer) =
    switches.tuitionByQualV[iCollege] = 0.0;

test_tuition_by_qual_switches(nc) =
    TuitionByQualSwitches(collect(range(1.0, 5.0, length = nc)));

make_test_tuition_by_qual(nc) = TuitionByQual(
    ObjectId(:test), test_tuition_by_qual_switches(nc)
    );

init_tuition_fct(objId :: ObjectId, switches :: TuitionByQualSwitches) =
    TuitionByQual(objId, switches);

function tuition(tf :: TuitionByQual, qual, t :: Integer; modelUnits :: Bool = true)
    tuitionV = tf.switches.tuitionByQualV[qual];
    if !modelUnits
        tuitionV = dollars_model_to_data(tuitionV, :perYear);
    end
    return tuitionV
end

# The `.+ 0.0` is meant to ensure that the sizes of `gpa` and `parental` propagate
tuition(tf :: TuitionByQual, qual, gpa, parental, t :: Integer;
    modelUnits :: Bool = true) =
    tuition(tf, qual, t; modelUnits = modelUnits) .+ 0.0 .* (gpa .+ parental);

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


text:
"""
    AnovaValue <: AnovaEffect

A set of values for an Anova item for which a mean square is not required.

`contrast` - the contrast value

`df` - degrees of freedom

`f` - the F statistic

`p` - the probability of a Type I error (incorrect rejection of null hypothesis)

`r` - the effect size
"""
struct AnovaContrastResult <: AnovaEffect
    contrast::Float64
    df::Float64
    f::Float64
    p::Float64
    r::Float64
end

struct AnovaContrastResults
    results::Vector{AnovaContrastResult}
end

import Base.isapprox
isapprox(x::AnovaContrastResults, y::AnovaContrastResults) = x.results .≈ y.results
isapprox(x::AnovaContrastResult, y::AnovaContrastResult) =
    x.contrast ≈ y.contrast &&
    x.df ≈ y.df &&
    x.f ≈ y.f &&
    x.p ≈ y.p &&
    x.r ≈ y.r

import Base.show
show(io::IO, acr::AnovaContrastResult) = show(io, AnovaContrastResults([acr]))
function show(io::IO, acr::AnovaContrastResults)
    colnames = ["Contrast", "DF", "F", "p", "r"]
    nrows = length(acr.results)

    compactshow(x) = sprint(show, x, context=:compact=>true)

    contrast = [e.contrast |> compactshow for e ∈ acr.results]
    df = [e.df |> Int |> compactshow for e ∈ acr.results]
    f = [e.f |> compactshow for e ∈ acr.results]
    p = [e.p |> compactshow for e ∈ acr.results]
    r = [e.r |> compactshow for e ∈ acr.results]

    ndec = [length.(last.(split.(values, "."))) for values ∈ [contrast, f, p, r]]
    maxndec = maximum.(ndec)
    rpadding = [maxndec[i] .- ndec[i] for i ∈ 1:4]

    ss = [rpad(contrast[i], rpadding[1][i] + length(contrast[i])) for i ∈ 1:nrows]
    f = [rpad(f[i], rpadding[2][i] + length(f[i])) for i ∈ 1:nrows]
    p = [rpad(p[i], rpadding[3][i] + length(p[i])) for i ∈ 1:nrows]
    r = [rpad(r[i], rpadding[4][i] + length(r[i])) for i ∈ 1:nrows]

    colwidths = [length.(values) |> maximum for values ∈ [[colnames[1]; contrast],
                                                          [colnames[2]; df],
                                                          [colnames[3]; f],
                                                          [colnames[4]; p],
                                                          [colnames[5]; r]]]
    colwidths[2:end] .+= 2

    headerrow = join(lpad.(colnames, colwidths))
    separator = repeat("-", sum(colwidths))
    rows = [lpad(contrast[i], colwidths[1]) *
            lpad(df[i], colwidths[2]) *
            lpad(f[i], colwidths[3]) *
            lpad(p[i], colwidths[4]) *
            lpad(r[i], colwidths[5]) for i ∈ 1:nrows]

    println(io)
    println(io, "Analysis of Variance Contrast Results")
    println(io)
    println(io, headerrow)
    println(io, separator)
    foreach(i -> println(io, rows[i]), 1:length(rows))
end


text:
using BinaryBuilder

# Collection of sources required to build CMake
sources = [
    "https://cmake.org/files/v3.12/cmake-3.12.0.tar.gz" =>
    "d0781a90f6cdb9049d104ac16a150f9350b693498b9dea8a0331e799db6b9d69", # v3.12.0
]

# Bash recipe for building across all platforms
script = raw"""
cd $WORKSPACE/srcdir/cmake-*
mkdir build
cd build
if cmake -DCMAKE_INSTALL_PREFIX=$prefix -DCMAKE_TOOLCHAIN_FILE=/opt/$target/$target.toolchain -DCMAKE_USE_SYSTEM_LIBRARIES=Off -DBUILD_CursesDialog=Off ..; then
    make
    make install
else
    echo "============= CMakeFiles/CMakeOutput.log ==============="
    cat CMakeFiles/CMakeOutput.log
    echo "============= CMakeFiles/CMakeError.log ==============="
    cat CMakeFiles/CMakeError.log
    exit 1
fi

"""

# These are the platforms we will build for by default, unless further
# platforms are passed in on the command line
platforms = supported_platforms() # build on all supported platforms

# FreeBSD doesn't work yet: BinaryBuilder.jl#232
platforms = filter!(p -> !(p isa FreeBSD), platforms)

# The products that we will ensure are always built
products(prefix) = [
    ExecutableProduct(prefix, "cmake", :cmake),
]

# Dependencies that must be installed before this package can be built
dependencies = [
]

# Build the tarballs, and possibly a `build.jl` as well.
build_tarballs(ARGS, "CMake", v"3.12.0", sources, script, platforms, products, dependencies)


text:
module TZData

using Printf
using ...TimeZones: DEPS_DIR
using ...TimeZones: @artifact_str

import Pkg
using Pkg.Artifacts: artifact_hash

# Note: The tz database is made up of two parts: code and data. TimeZones.jl only requires
# the "tzdata" archive or more specifically the "tz source" files within the archive
# (africa, australasia, ...)

const ARCHIVE_DIR = joinpath(DEPS_DIR, "tzarchive")
const TZ_SOURCE_DIR = joinpath(DEPS_DIR, "tzsource")
const COMPILED_DIR = joinpath(DEPS_DIR, "compiled", string(VERSION))

const ARTIFACT_TOML = joinpath(@__DIR__, "..", "..", "Artifacts.toml")

export ARCHIVE_DIR, TZ_SOURCE_DIR, COMPILED_DIR, REGIONS, LEGACY_REGIONS

if Sys.iswindows()
    if isdefined(Base, :LIBEXECDIR)
        const exe7z = joinpath(Sys.BINDIR, Base.LIBEXECDIR, "7z.exe")
    else
        const exe7z = joinpath(Sys.BINDIR, "7z.exe")
    end
end

include("timeoffset.jl")
include("archive.jl")
include("version.jl")
include("download.jl")
include("compile.jl")
include("build.jl")
include("deprecated.jl")

end


text:
"""-----------------------------------------------------------------------------
    contracts a tensor represented with indices + values in a symmetric COO
  format. Rows of the indices correspond to sorted indices of a symmetric
  hyper-edge. Values correspond to the edge weights, and v is vector being
  contracted with the
  -----------------------------------------------------------------------------"""
function tensor_vector_contraction(A::ThirdOrderSymTensor, x::Array{Float64,1})
    @assert length(x) == A.n

    y = zeros(Float64,A.n)

	j =1
    @inbounds for (i_1,i_2,i_3) in eachcol(A.indices)

        y[i_1] += 2 * x[i_2]*x[i_3]*A.values[j]
        y[i_2] += 2 * x[i_1]*x[i_3]*A.values[j]
        y[i_3] += 2 * x[i_1]*x[i_2]*A.values[j]

		j +=1
    end

    return y
end

function tensor_vector_contraction(A::UnweightedThirdOrderSymTensor, x::Array{Float64,1})
    @assert length(x) == A.n

    y = zeros(Float64,A.n)

    @inbounds for (i_1,i_2,i_3) in eachcol(A.indices)

        y[i_1] += 2 * x[i_2]*x[i_3]
        y[i_2] += 2 * x[i_1]*x[i_3]
        y[i_3] += 2 * x[i_1]*x[i_2]

    end

    return y
end

"""-----------------------------------------------------------------------------
    contracts a tensor represented with indices + values in a symmetric COO
  format with a vector to return a sparse matrix.
-----------------------------------------------------------------------------"""
function tri_sub_tensor(A::ThirdOrderSymTensor,x::Array{Float64,1})

	index = 0
	nnzs = size(A.indices,2)
	I = zeros(Int64,6*nnzs)
	J = zeros(Int64,6*nnzs)
	V = zeros(Float64,6*nnzs)

    @inbounds for nnz_index = 1:nnzs
		index += 6
		i,j,k = A.indices[:,nnz_index]
		val = A.values[nnz_index]

		I[index-5] = i
		J[index-5] = j
		I[index-4] = j
		J[index-4] = i
		V[index-5] = val*x[k]
		V[index-4] = val*x[k]

		I[index-3] = i
		J[index-3] = k
		I[index-2] = k
		J[index-2] = i
		V[index-3] = val*x[j]
		V[index-2] = val*x[j]

		I[index-1] = j
		J[index-1] = k
		I[index] = k
		J[index] = j
		V[index-1] = val*x[i]
		V[index] = val*x[i]

	end
	return sparse(I,J,V,A.n,A.n)
end

"""-----------------------------------------------------------------------------
    contracts a tensor represented with indices + values in a symmetric COO
  format with a vector to return a sparse matrix.
-----------------------------------------------------------------------------"""
function tri_sub_tensor(A::ThirdOrderSymTensor,x::Array{Float64,1},
    					I::Array{Int64,1},J::Array{Int64,1},V::Array{Float64,1})

	index = 0
	nnzs = size(A.indices,2)
    for nnz_index = 1:nnzs
		index += 6
		i,j,k = A.indices[:,nnz_index]
		val = A.values[nnz_index]

		I[index-5] = i
		J[index-5] = j
		I[index-4] = j
		J[index-4] = i
		V[index-5] = val*x[k]
		V[index-4] = val*x[k]

		I[index-3] = i
		J[index-3] = k
		I[index-2] = k
		J[index-2] = i
		V[index-3] = val*x[j]
		V[index-2] = val*x[j]

		I[index-1] = j
		J[index-1] = k
		I[index] = k
		J[index] = j
		V[index-1] = val*x[i]
		V[index] = val*x[i]

	end
	return sparse(I,J,V,A.n,A.n)
end

"""-----------------------------------------------------------------------------
    contracts a tensor represented with indices + values in a symmetric COO
  format with a vector to return a sparse matrix.
-----------------------------------------------------------------------------"""
function tri_sub_tensor(A::UnweightedThirdOrderSymTensor,x::Array{Float64,1})

	index = 0
	nnzs = 2*sum([length(x) for x in A_U_ten.indices])
	I = zeros(Int64,2*nnzs)
	J = zeros(Int64,2*nnzs)
	V = zeros(Float64,2*nnzs)

	for i in 1:A.n
		for (j,k) in A.indices[i]
			index += 2

			I[index-1] = j
			J[index-1] = k
			I[index] = k
			J[index] = j
			V[index-1] = x[i]
			V[index] = x[i]
		end
	end
	return sparse(I[1:index],J[1:index],V[1:index],A.n,A.n)
end

function kron_contract(A::ThirdOrderSymTensor,B::ThirdOrderSymTensor,
                       X::SparseMatrixCSC{Float64,Int64},rank::Int=minimum(size(X)))

	(U,S,VT),_ = svds(X,nsv = rank)
	println("input rank: ",rank)
	println("output rank:",length(S))

	#singular_indexes = [i for i in 1:length(S) if S[i] > S[1]*eps(Float64)*minimum(size(X))]

	#println("rank in kron contract is",length(singular_indexes))

    kron_contract(A,B,U,VT*diagm(S))
end

function kron_contract(A::ThirdOrderSymTensor,B::ThirdOrderSymTensor,
                       U::Array{Float64,2},V::Array{Float64,2})
    n,d1 = size(U)
    m,d2 = size(V)
    @assert d1 == d2
    @assert A.n == n
    @assert B.n == m

	#preallocate memory used for building sparse matrices
	A_nnzs = size(A.indices,2)
	A_I = zeros(Int64,6*A_nnzs)
	A_J = zeros(Int64,6*A_nnzs)
	A_V = zeros(Float64,6*A_nnzs)

	B_nnzs = size(B.indices,1)
	B_I = zeros(Int64,6*B_nnzs)
	B_J = zeros(Int64,6*B_nnzs)
	B_V = zeros(Float64,6*B_nnzs)

    result = zeros(A.n * B.n)

    @inbounds for i in 1:d1

	#	sub_A_i = tri_sub_tensor(A,U[:,i])
	#	sub_B_i = tri_sub_tensor(B,V[:,i])
        sub_A_i = tri_sub_tensor(A,U[:,i],A_I,A_J,A_V)
        sub_B_i = tri_sub_tensor(B,V[:,i],B_I,B_J,B_V)
        for j in 1:i

            A_update = (sub_A_i*U[:,j])
            B_update = (sub_B_i*V[:,j])

            if i == j
               result += kron(B_update,A_update)
            else
                result += kron(2*B_update,A_update)
            end
        end
    end

    return reshape(result, A.n,B.n)
end

function get_kron_contract_comps(A::Union{ThirdOrderSymTensor,UnweightedThirdOrderSymTensor},
    							 B::Union{ThirdOrderSymTensor,UnweightedThirdOrderSymTensor},
              			         U::Array{Float64,2},V::Array{Float64,2})

    n,d1 = size(U)
    m,d2 = size(V)
    @assert d1 == d2
    @assert A.n == n
    @assert B.n == m

#    result = zeros(A.n * B.n)

    ileave = (i,j) -> i + A.n*(j-1)

    max_rank = Int((d1+1)*d1/2)

	A_comps = zeros(n,max_rank)
	B_comps = zeros(m,max_rank)
	index = 1

	A_nnzs = size(A.indices,2)
	A_I = zeros(Int64,6*A_nnzs)
	A_J = zeros(Int64,6*A_nnzs)
	A_V = zeros(Float64,6*A_nnzs)

	B_nnzs = size(B.indices,2)
	B_I = zeros(Int64,6*B_nnzs)
	B_J = zeros(Int64,6*B_nnzs)
	B_V = zeros(Float64,6*B_nnzs)

    @inbounds for i in 1:d1

        sub_A_i = tri_sub_tensor(A,U[:,i],A_I,A_J,A_V)
        sub_B_i = tri_sub_tensor(B,V[:,i],B_I,B_J,B_V)

        for j in 1:i

			if i == j
				A_comps[:,index] = (sub_A_i*U[:,j])
				B_comps[:,index] = (sub_B_i*V[:,j])
			else

				A_comps[:,index] = sqrt(2)*(sub_A_i*U[:,j])
				B_comps[:,index] = sqrt(2)*(sub_B_i*V[:,j])
			end
			index += 1
        end
    end

    return A_comps, B_comps
end

function get_kron_contract_comps(A::Union{SymTensor{M,T},SymTensorUnweighted{M}},
						B::Union{SymTensor{M,T},SymTensorUnweighted{M}},
						U::Matrix{T},V::Matrix{T}) where {M <: Motif,T}
	# adapted from contract_all_unique_permutations routine in DistributedTensorConstruction.jl
	#=assuming that
		A.order == B.order,
		size(U,2) == size(V,2),
		size(U,1) = A.n, and
		size(V,1) = B.n
	=#
    m,d = size(U)

    A_contraction_components = Array{T,2}(undef,A.n,binomial(d + A.order-2, A.order-1))
	B_contraction_components = Array{T,2}(undef,B.n,binomial(d + B.order-2, B.order-1))
                                                # n choose k w/ replacement
    get_kron_contract_comps!(A,B,U,V,A_contraction_components,B_contraction_components,0,size(U,2),Array{Int}(undef,0))

    return A_contraction_components, B_contraction_components
end

function get_kron_contract_comps!(A::Union{SymTensor{M,T},SymTensorUnweighted{M}},
						 B::Union{SymTensor{M,T},SymTensorUnweighted{M}},
						 U::Matrix{T},V::Matrix{T},
						 A_contraction_components::Matrix{T},
						 B_contraction_components::Matrix{T},
						 offset::Int,end_idx::Int,
						 prefix_indices::Vector{Int},) where {M <: Motif,T}

    d = size(U,2)
    if A.order == 3
        indices = Array{Int}(undef,length(prefix_indices)+2)
        indices[1:end-2] = prefix_indices

        for i = 1:end_idx
            indices[end-1] = i
            sub_A_mat = contract_to_mat(A, U[:,i])
			sub_B_mat = contract_to_mat(B, V[:,i])
            #for j = i:size(U,2)
            for j = 1:i
                indices[end] = j

                factor = DistributedTensorConstruction.compute_multinomial(indices)
                #println("edge:$indices  factor:$factor  ")

                idx = offset + i*(i-1)÷2 + j

                A_contraction_components[:,idx] = factor*(sub_A_mat*U[:,j])
				B_contraction_components[:,idx] = (sub_B_mat*V[:,j])
            end
        end
    else

        running_offset = copy(offset)
        for i = 1:end_idx
            sub_A = single_mode_ttv(A,U[:,i])
			sub_B = single_mode_ttv(B,V[:,i])
            prefix = copy(prefix_indices)
            push!(prefix,i)

            get_kron_contract_comps!(sub_A,sub_B, U,V,
							A_contraction_components,B_contraction_components,
							running_offset,i,prefix)

            running_offset += binomial(i + A.order-3, A.order-2)
        end

    end

end

function get_kron_contract_comps_with_accumulation_param(A::Union{SymTensor{M,T},SymTensorUnweighted{M}},
						B::Union{SymTensor{M,T},SymTensorUnweighted{M}},
						U::Matrix{T},V::Matrix{T}) where {M <: Motif,T}
	# adapted from contract_all_unique_permutations routine in DistributedTensorConstruction.jl
	#=assuming that
		A.order == B.order,
		size(U,2) == size(V,2),
		size(U,1) = A.n, and
		size(V,1) = B.n
	=#
    X = zeros(T,A.n,B.n)
                                                # n choose k w/ replacement
    get_kron_contract_comps!(A,B,U,V,X,size(U,2),Array{Int}(undef,0))

    return X
end

function get_kron_contract_comps!(A::Union{SymTensor{M,T},SymTensorUnweighted{M}},
								B::Union{SymTensor{M,T},SymTensorUnweighted{M}},
								U::Matrix{T},V::Matrix{T},
								X::Matrix{T},end_idx::Int,
								prefix_indices::Vector{Int}) where {M <: Motif,T}

    d = size(U,2)
    if A.order == 3
        indices = Array{Int}(undef,length(prefix_indices)+2)
        indices[1:end-2] = prefix_indices

        for i = 1:end_idx
            indices[end-1] = i
            sub_A_mat = contract_to_mat(A, U[:,i])
			sub_B_mat = contract_to_mat(B, V[:,i])
            #for j = i:size(U,2)
            for j = 1:i
                indices[end] = j
                factor = DistributedTensorConstruction.compute_multinomial(indices)

				u = factor*sub_A_mat*U[:,j]
				v = sub_B_mat*V[:,j]

				for col in 1:B.n
					for row in 1:A.n
						X[row,col] += u[row]*v[col]
					end
				end
            end
        end
    else

        #running_offset = copy(offset)
        for i = 1:end_idx
            sub_A = single_mode_ttv(A,U[:,i])
			sub_B = single_mode_ttv(B,V[:,i])
            prefix = copy(prefix_indices)
            push!(prefix,i)

            get_kron_contract_comps!(sub_A, sub_B, U, V, X, i, prefix)

        end

    end

end

function implicit_contraction(A::ThirdOrderSymTensor,B::ThirdOrderSymTensor,x::Array{Float64,1})

	error("Code is Broken, must be fixed")
    @assert length(x) == A.n*B.n
    m = A.n
    n = B.n
	X = reshape(x,A.n,B.n)
    Y = similar(X)

    #ileave = (i,j) -> i + m*(j-1)
	i = 1
	j = 1
    @inbounds for (i_1,i_2,i_3) in eachcol(A.indices)

		A_val = A.values[i]
		i += 1
		j = 1
#        for (i_1,i_2,i_3) in permutations(A.indices[i,:])
		for (j_1,j_2,j_3) in eachcol(B.indices)

			#i_1,i_2,i_3
			@inbounds Y[i_1,j_1] += 2*A_val*B.values[j]*X[i_2,j_2]*X[i_3,j_3]
			@inbounds Y[i_2,j_2] += 2*A_val*B.values[j]*X[i_1,j_1]*X[i_3,j_3]
			@inbounds Y[i_3,j_3] += 2*A_val*B.values[j]*X[i_1,j_1]*X[i_2,j_2]

			#i_1,i_3,i_2
			@inbounds Y[i_1,j_1] += 2*A_val*B.values[j]*X[i_3,j_2]*X[i_2,j_3]
			@inbounds Y[i_3,j_2] += 2*A_val*B.values[j]*X[i_1,j_1]*X[i_2,j_3]
			@inbounds Y[i_2,j_3] += 2*A_val*B.values[j]*X[i_1,j_1]*X[i_3,j_2]

			#i_2,i_1,i_3
			@inbounds Y[i_2,j_1] += 2*A_val*B.values[j]*X[i_1,j_2]*X[i_3,j_3]
			@inbounds Y[i_1,j_2] += 2*A_val*B.values[j]*X[i_2,j_1]*X[i_3,j_3]
			@inbounds Y[i_3,j_3] += 2*A_val*B.values[j]*X[i_2,j_1]*X[i_1,j_2]

			#i_2,i_3,i_1
			@inbounds Y[i_2,j_1] += 2*A_val*B.values[j]*X[i_3,j_2]*X[i_1,j_3]
			@inbounds Y[i_3,j_2] += 2*A_val*B.values[j]*X[i_2,j_1]*X[i_1,j_3]
			@inbounds Y[i_1,j_3] += 2*A_val*B.values[j]*X[i_2,j_1]*X[i_3,j_2]

			#i_3,i_2,i_1
			@inbounds Y[i_3,j_1] += 2*A_val*B.values[j]*X[i_2,j_2]*X[i_1,j_3]
			@inbounds Y[i_2,j_2] += 2*A_val*B.values[j]*X[i_3,j_1]*X[i_1,j_3]
			@inbounds Y[i_1,j_3] += 2*A_val*B.values[j]*X[i_3,j_1]*X[i_2,j_2]

			#i_3,i_1,i_2
			@inbounds Y[i_3,j_1] += 2*A_val*B.values[j]*X[i_1,j_2]*X[i_2,j_3]
			@inbounds Y[i_1,j_2] += 2*A_val*B.values[j]*X[i_3,j_1]*X[i_2,j_3]
			@inbounds Y[i_2,j_3] += 2*A_val*B.values[j]*X[i_3,j_1]*X[i_1,j_2]

		end
		j += 1
  #      end
    end

    return Y[:]
end

function impTTVnodesym(A::UnweightedThirdOrderSymTensor,
                       B::UnweightedThirdOrderSymTensor,x::Vector{Float64})

	X = reshape(x,A.n,B.n)
	Y = similar(X)
	Y .= 0
	@inbounds for a = 1:A.n
		for b = 1:B.n
			newval = 0.0
			for (jp,kp) in A.indices[a]
				@simd for pair in B.indices[b]
					j,k = pair
					@inbounds newval += X[jp,j]*X[kp,k]+X[kp,j]*X[jp,k]
				end
			end
			Y[a,b] = 2*newval
		end
	end
	y = Y[:]
	return y

end

function impTTVnodesym(nG::Int,nH::Int,x::Vector{Float64},Gti, Hti)

	X = reshape(x,nG,nH)
	#Xt = copy(X')
	Y = similar(X)
	Y .= 0
	@inbounds for g = 1:nG
		for h = 1:nH
			newval = 0.0
			for (jp,kp) in Gti[g]
				@simd for pair in Hti[h]
					j,k = pair
					@inbounds newval += X[jp,j]*X[kp,k]+X[kp,j]*X[jp,k]
				end
			end
			Y[g,h] = 2*newval
		end
	end
	y = Y[:]
	return y
end

function impTTVnodesym(m::Int,n::Int,order::Int,X::Matrix{T},A_Mi,B_Mi) where T

    Y = zeros(T,size(X)...)

	factor = factorial(order-1)

	permutation_template = collect(permutations(1:(order-1)))

	@inbounds for a = 1:m
		for b = 1:n
			newval = 0.0
			for sub_edge_A in A_Mi[a]
				for sub_edge_B in B_Mi[b]

					#_tame_edge_contract!(sub_edge_A, sub_edge_B,newval)
					#for (sub_edge_A_p,sub_edge_B_p) in zip(permutations(sub_edge_A),permutations(sub_edge_B))
					for p in permutation_template

						x_prod = X[sub_edge_A[p[1]],sub_edge_B[1]]
						for i = 2:(order-1)
							x_prod *= X[sub_edge_A[p[i]],sub_edge_B[i]]
						end
						newval += x_prod

					end
				end
			end
			Y[a,b] = factor*newval
		end
	end

    return Y
end

"""-----------------------------------------------------------------------------
                         Iterative method primatives
-----------------------------------------------------------------------------"""
function SSHOPM_sample_return_all(A::Union{ThirdOrderSymTensor,SymTensorUnweighted}, samples::Int, β::Float64, max_iter::Int, tol::Float64)

	#X = rand(A.n,samples)
	X = rand(Uniform(-1,1),A.n,samples)

	V = Array{Float64,2}(undef,A.n,samples)
	Λ = Array{Float64,1}(undef,samples)

	for i=1:samples
		vec, val = SSHOPM(A,β,max_iter,tol,X[:,i])
		V[:,i] .= vec
		Λ[i] = val
	end

	V,Λ

end

function SSHOPM_sample(A::ThirdOrderSymTensor, samples::Int, β::Float64, max_iter::Int, tol::Float64,kwargs...)

	#X = rand(A.n,samples)
	#X = rand(Uniform(-1,1),A.n,ssample)

	argmax_vec = Array{Float64,1}(undef,A.n)
	argmax_val::Float64 = 0.0
	#Vecs = Array{Float64,3}(undef,A.n,B.n,samples)
	Λ = Array{Float64,1}(undef,samples)

	for i=1:samples
		#U,V, val
		vec, val =  SSHOPM(A,β,max_iter,tol,rand(Uniform(-1,1),A.n))

		if abs(val) > abs(argmax_val)
			argmax_vec = vec
			argmax_val = val
		end

		Λ[i] = val
	end

	argmax_vec,argmax_val,Λ

end

#TODO: move to appropriate file
function SSHOPM(A::ThirdOrderSymTensor,β::Float64, max_iter::Int, tol::Float64,
	            x_0::Array{Float64,1}=ones(A.n);update_user::Int=-1)

	#normalize init vector
	x_k = copy(x_0)
	x_k ./=norm(x_0)

    lambda_k = Inf
    i = 1

    while true

		x_k_1 = tensor_vector_contraction(A,x_k)
		lambda_k_1 = x_k_1'*x_k

		if β != 0.0
			x_k_1 .+= β*x_k
        end

		x_k_1 ./= norm(x_k_1)

		res = abs(lambda_k_1 - lambda_k)
		if update_user != -1 && i % update_user == 0
			println("iteration $(i)    λ: $(lambda_k_1)   |λ_k_1 - λ_k| = $res")
		end

        if res < tol || i >= max_iter
            return x_k_1, lambda_k_1
        else
			lambda_k = copy(lambda_k_1)
			x_k = copy(x_k_1)
            i += 1
        end

    end

end

function SSHOPM(A::SymTensorUnweighted,β::Float64, max_iter::Int, tol::Float64,
	x_0::Array{Float64,1}=ones(A.n);update_user::Int=-1)

	#normalize init vector
	buf = zeros(Float64,A.n)
	x_k_1 = Array{Float64,1}(undef,A.n)
	x_k = copy(x_0)
	x_k ./=norm(x_0)

	lambda_k = Inf
	i = 1

	while true

		DistributedTensorConstruction.contraction!(A,x_k,buf)
		x_k_1 .= buf
		lambda_k_1 = x_k_1'*x_k

		if β != 0.0
			x_k_1 .+= β*x_k
		end

		x_k_1 ./= norm(x_k_1)

		res = abs(lambda_k_1 - lambda_k)
		if update_user != -1 && i % update_user == 0
			println("iteration $(i)    λ: $(lambda_k_1)   |λ_k_1 - λ_k| = $res")
		end

		if res < tol || i >= max_iter
			return x_k_1, lambda_k_1
		else
			lambda_k = copy(lambda_k_1)
			x_k = copy(x_k_1)
			i += 1
			buf .= 0.0
		end

	end

end

function SSHOPM_sample_return_all(A::ThirdOrderSymTensor,B::ThirdOrderSymTensor, samples::Int, β::Float64, max_iter::Int, tol::Float64,kwargs...)

	#X = rand(A.n,samples)
	X = rand(Uniform(-1,1),A.n,B.n,samples)

	Vecs = Array{Float64,3}(undef,A.n,B.n,samples)
	Λ = Array{Float64,1}(undef,samples)

	for i=1:samples
		#U,V, val
		U,V, val = SSHOPM(A,B,X[:,:,i],β,max_iter,tol;kwargs...)
		Vecs[:,:,i] = U*V'
		Λ[i] = val
	end

	Vecs,Λ

end

function SSHOPM_sample(A::ThirdOrderSymTensor,B::ThirdOrderSymTensor, samples::Int, β::Float64, max_iter::Int, tol::Float64,kwargs...)

	#X = rand(A.n,samples)
	#X = rand(Uniform(-1,1),A.n,B.n,samples)

	argmax_vec = Array{Float64,1}(undef,A.n*B.n)
	argmax_val::Float64 = 0.0
	#Vecs = Array{Float64,3}(undef,A.n,B.n,samples)
	Λ = Array{Float64,1}(undef,samples)

	for i=1:samples
		#U,V, val
		vec, val = SSHOPM(A,B,rand(Uniform(-1,1),A.n,B.n),β,max_iter,tol;kwargs...)

		if abs(val) > abs(argmax_val)
			argmax_vec = vec
			argmax_val = val
		end

		Λ[i] = val
	end

	reshape(argmax_vec,A.n,B.n),argmax_val,Λ

end

#=
function SSHOPM(A::ThirdOrderSymTensor, B::ThirdOrderSymTensor,W::Array{F,2},
				β::F, max_iter::Int,tol::F;
				max_rank::Int = minimum((A.n,B.n)),kwargs...) where {F <:AbstractFloat}

	dimension = minimum((A.n,B.n))

	U_k,S,VT =svd(W)
	singular_indexes = [i for i in 1:minimum((max_rank,length(S))) if S[i] > S[1]*eps(Float64)*dimension]

	U = U_k[:,singular_indexes]
	V = VT[:,singular_indexes]*diagm(S[singular_indexes])

	return SSHOPM(A,B,U,V,β,max_iter,tol;kwargs...)
end
=#

#uses implicit contraction
function SSHOPM(A::ThirdOrderSymTensor, B::ThirdOrderSymTensor,W::Array{F,2},
				β::F, max_iter::Int,tol::F;update_user::Int=-1) where {F <:AbstractFloat}

	dimension = minimum((A.n,B.n))

	A_Ti, B_Ti = setup_tame_data(A,B)

    x0 = reshape(W,A.n*B.n)
	x0 ./=norm(x0)
    x_k = copy(x0)

    i = 1
    lambda = Inf

    while true

	    x_k_1 = impTTVnodesym(A.n, B.n, x_k, A_Ti, B_Ti)
		#x_k_1 = implicit_contraction(A,B,x_k)

		#println("norm diff is:",norm(x_k_1_test - x_k_1)/norm(x_k_1_test))
        new_lambda = dot(x_k_1,x_k)

        if β != 0.0
            x_k_1 .+= β * x_k
        end

		x_k_1 ./= norm(x_k_1)

		if update_user != -1 && i % update_user == 0
			println("λ: $(new_lambda)")
		end

        if abs(new_lambda - lambda) < tol || i >= max_iter
  			return x_k_1, new_lambda
        else
            x_k = copy(x_k_1)
            lambda = new_lambda
            i += 1
        end

    end

end

function SSHOPM(A::ThirdOrderSymTensor, B::ThirdOrderSymTensor,
				U_0::Array{F,2},V_0::Array{F,2}, β::F, max_iter::Int,tol::F;
				max_rank::Int = minimum((A.n,B.n)),update_user::Int=-1) where {F <:AbstractFloat}

	@assert size(U_0,2) == size(V_0,2)

	dimension = minimum((A.n,B.n))

	normalization_factor = sqrt(tr((V_0'*V_0)*(U_0'*U_0)))
	U_0 ./= sqrt(normalization_factor)
	V_0 ./= sqrt(normalization_factor)

	U_k = copy(U_0)
	V_k = copy(V_0)

	best_U::Array{F,2} = copy(U_k)
	best_V::Array{F,2} = copy(U_k)

	λ_k = Inf

	for i in 1:max_iter

		A_comps, B_comps = get_kron_contract_comps(A,B,U_k,V_k)

		λ_k_1 = tr((U_k'*A_comps)*(B_comps'*V_k))

		if β != 0.0
			U_temp = hcat(A_comps, sqrt(β) * U_k)
			V_temp = hcat(B_comps, sqrt(β) * V_k)
		else
			U_temp = A_comps
			V_temp = B_comps
		end

		A_Q,A_R = qr(U_temp)
		B_Q,B_R = qr(V_temp)

		core = A_R*B_R'
		C_U,C_S,C_Vt = svd(core)
		singular_indexes= [i for i in 1:1:minimum((max_rank,length(C_S))) if C_S[i] > C_S[1]*eps(Float64)*dimension]

		U_k_1 = A_Q*C_U[:,singular_indexes]
		V_k_1 = B_Q*(C_Vt[:,singular_indexes]*diagm(C_S[singular_indexes]))

		normalization_factor = sqrt(tr((V_k_1'*V_k_1)*(U_k_1'*U_k_1)))

		U_k_1 ./= sqrt(normalization_factor)
		V_k_1 ./= sqrt(normalization_factor)

		#Y, Z = get_kron_contract_comps(A,B,U_k_1,V_k_1)

		if update_user != -1 && i % update_user == 0
			println("λ_$i: $(λ_k_1) -- rank:$(length(singular_indexes))")
		end

		if abs(λ_k_1 - λ_k) < tol || i == max_iter
			return U_k_1, V_k_1, λ_k_1
		end

		#get the low rank factorization for the next one
		U_k = copy(U_k_1)
		V_k = copy(V_k_1)

		λ_k = λ_k_1

	end

end

max_stars_repo_name: chuckcol/LambdaTAME

max_issues_repo_name: chuckcol/LambdaTAME

max_forks_repo_name: chuckcol/LambdaTAME


text:
#`ffmpeg -i volume.webm -codec:v libvpx -quality good -cpu-used 0 -b:v 500k -qmin 10 -qmax 42 -maxrate 500k -bufsize 1000k -threads 4 -vf scale=-1:480 -codec:a libvorbis -b:a 128k volume2.webm`
# ffmpeg version
# ffmpeg -r 24 -pattern_type glob -i '*.png' -vcodec libx264 -crf 25  -pix_fmt yuv420p test.mp4

immutable VideoStream
    io
    buffer
    window
end

"""
returns a stream and a buffer that you can use to not allocate for new frames.
Use `add_frame!(stream, window, buffer)` to add new video frames to the stream.
"""
function create_video_stream(path, window)
    #codec = `-codec:v libvpx -quality good -cpu-used 0 -b:v 500k -qmin 10 -qmax 42 -maxrate 500k -bufsize 1000k -threads 8`
    tex = GLWindow.framebuffer(window).color
    res = size(tex)
    io, process = open(`ffmpeg -f rawvideo -pixel_format rgb24 -s:v $(res[1])x$(res[2]) -i pipe:0 -vf vflip -y $path`, "w")
    VideoStream(io, Matrix{RGB{N0f8}}(res), window) # tmp buffer
end

"""
Adds a video frame to a stream created with `create_video_stream`
"""
function add_frame!(io)
    #codec = `-codec:v libvpx -quality good -cpu-used 0 -b:v 500k -qmin 10 -qmax 42 -maxrate 500k -bufsize 1000k -threads 8`
    tex = GLWindow.framebuffer(io.window).color
    write(io.io, map(RGB{N0f8}, gpu_data(tex)))
end

"""
Converts a folder full of videos into a folder full of webm videos
"""
function webm_batchconvert(oldpath, newpath, scale = 0.5)
    for file in readdir(oldpath)
        isfile(file) || continue
        f = joinpath(oldpath, file)
        name, ext = splitext(file)
        ext != ".mkv" && continue
        out = joinpath(newpath, name * ".webm")
        run(`ffmpeg -i $f -c:v libvpx-vp9 -threads 16 -b:v 2000k -c:a libvorbis -threads 16 -vf scale=iw$("*")$scale:ih$("*")$scale -y $out`)
    end
end


text:
"""
	AccelSteeringAngle
Allows driving the car in a circle based on the steering angle
If steering angle less than threshold 0.01 radian, just drives straight

# Fields
- `a::Float64` longitudinal acceleration [m/s^2]
- `δ::Float64` Steering angle [rad]
"""
struct AccelSteeringAngle
    a::Float64 # accel [m/s²]
    δ::Float64 # steering angle [rad]
end
Base.show(io::IO, a::AccelSteeringAngle) = @printf(io, "AccelSteeringAngle(%6.3f,%6.3f)", a.a, a.δ)
Base.length(::Type{AccelSteeringAngle}) = 2

"""
Take a vector containing acceleration and desired steering angle and
convert to AccelSteeringAngle
"""
Base.convert(::Type{AccelSteeringAngle}, v::Vector{Float64}) = AccelSteeringAngle(v[1], v[2])

"""
Extract acceleration and steering angle components from AccelSteeringAngle
and return them into a vector
"""
function Base.copyto!(v::Vector{Float64}, a::AccelSteeringAngle)
    v[1] = a.a
    v[2] = a.δ
    v
end

"""
propagate vehicle forward in time given a desired acceleration and
steering angle. If steering angle higher than 0.1 radian, the vehicle
drives in a circle
"""
function propagate(veh::Entity{VehicleState, BicycleModel, Int}, action::AccelSteeringAngle, roadway::Roadway, Δt::Float64)

    L = veh.def.a + veh.def.b
    l = -veh.def.b

    a = action.a # accel [m/s²]
    δ = action.δ # steering wheel angle [rad]

    x, y, θ = posg(veh.state)
    v = vel(veh.state)

    s = v*Δt + a*Δt*Δt/2 # distance covered
    v′ = v + a*Δt

    if abs(δ) < 0.01 # just drive straight
        posG = posg(veh.state) + polar(s, θ)
    else # drive in circle

        R = L/tan(δ) # turn radius

        β = s/R
        xc = x - R*sin(θ) + l*cos(θ)
        yc = y + R*cos(θ) + l*sin(θ)

        θ′ = mod(θ+β, 2π)
        x′ = xc + R*sin(θ+β) - l*cos(θ′)
        y′ = yc - R*cos(θ+β) - l*sin(θ′)

        posG = VecSE2(x′, y′, θ′)
    end

    VehicleState(posG, roadway, v′)
end


text:
using Blosc2
@testset "dev" begin
end


text:
using Test, Random, LSHFunctions

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

#==================
Tests
==================#
@testset "SimHash tests" begin
    Random.seed!(RANDOM_SEED)

    @testset "Construct SimHash" begin
        # Create 128 SimHash hash functions
        hashfn = LSHFunctions.SimHash(128)

        @test n_hashes(hashfn) == 128
        @test hashtype(hashfn) == Bool
        @test similarity(hashfn) == cossim

        # By default, SimHash should start off unable to hash inputs of any
        # size, and should not resize in powers of 2.
        @test LSHFunctions.current_max_input_size(hashfn) == 0
        @test hashfn.resize_pow2 == false
    end

    @testset "Hash simple inputs" begin
        hashfn = SimHash(128)

        ## Test 1: a single input that is just the zero vector
        x = zeros(10)
        @test all(hashfn(x) .== true)

        ## Test 2: many inputs, all of which are zero vectors
        x = zeros(10, 32)
        @test all(hashfn(x) .== true)

        ## Test 3: many identical inputs
        u = randn(10)
        x = similar(u, 10, 32)
        x .= u
        hashes = hashfn(x)
        @test all(hashes[:,1] .== hashes)

        # For any input, the probability that all of its hashes are the
        # same should be extremely low, 2^(-n_hashes+1). Thus, there
        # should be at least one true bit and one false bit among
        # the hashes for an input.
        @test any(hashes[:,1]) && !all(hashes[:,1])
    end

    @testset "Hashing returns the correct data types" begin
        hashfn = SimHash(2)

        ## Test 1: Vector{Float64} -> BitArray{1}
        hashes = hashfn(randn(5))
        @test isa(hashes, BitArray{1})

        ## Test 2: Matrix{Float64} -> BitArray{2}
        hashes = hashfn(randn(5, 10))
        @test isa(hashes, BitArray{2})
    end

    @testset "SimHash collision probabilities match expectations" begin
        # Draw a massive number of hash functions, since we're going to be testing
        # the probability of collision for many different pairs of random inputs.
        # As the number of pairs increases, the probability that one pair has an
        # above- or below-average number of collisions increases.
        hashfn = LSHFunctions.SimHash(1024)

        # Run test_collision_probability lots of times to ensure that the
        # collision probability is close to what's advertised.
        # Dry run: just try once
        @test test_collision_probability(hashfn, 0.05)

        # Full test: test many more times
        @test all(test_collision_probability(hashfn, 0.05) for ii = 1:128)
    end

    @testset "SimHash current_max_input_size scales with input size" begin
        inputs = [rand(4), rand(7), rand(127), rand(4)]

        ### First round of tests: run with resize_pow2 == false
        hashfn = LSHFunctions.SimHash(1; resize_pow2 = false)

        for (ii,x) in enumerate(inputs)
            max_size_seen = inputs[1:ii] .|> length |> maximum
            hashfn(x)
            @test LSHFunctions.current_max_input_size(hashfn) == max_size_seen
        end

        # Second round of tests: run with resize_pow2 == true
        hashfn = LSHFunctions.SimHash(1; resize_pow2 = true)
        for (ii,x) in enumerate(inputs)
            max_size_seen = inputs[1:ii] .|> length |> maximum
            next_pow_2 = nextpow(2, max_size_seen)
            hashfn(x)
            @test LSHFunctions.current_max_input_size(hashfn) == next_pow_2
        end
    end
end


text:
export awk

@with_kw struct AwkOptions
    field_separator = " "
    source = nothing
end

function parse_options(::Type{AwkOptions}, options)
    AwkOptions(
        source = get_option(options, :e, :source).second,
    )
end

"""
    awk(options..., prog, files...)

Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options:          GNU long options: (standard)
        -f progfile             --file=progfile
        -F fs                   --field-separator=fs
        -v var=val              --assign=var=val
Short options:          GNU long options: (extensions)
        -b                      --characters-as-bytes
        -c                      --traditional
        -C                      --copyright
        -d[file]                --dump-variables[=file]
        -D[file]                --debug[=file]
        -e 'program-text'       --source='program-text'
        -E file                 --exec=file
        -g                      --gen-pot
        -h                      --help
        -i includefile          --include=includefile
        -l library              --load=library
        -L[fatal|invalid]       --lint[=fatal|invalid]
        -M                      --bignum
        -N                      --use-lc-numeric
        -n                      --non-decimal-data
        -o[file]                --pretty-print[=file]
        -O                      --optimize
        -p[file]                --profile[=file]
        -P                      --posix
        -r                      --re-interval
        -S                      --sandbox
        -t                      --lint-old
        -V                      --version

To report bugs, see node 'Bugs' in 'gawk.info', which is
section 'Reporting Problems and Bugs' in the printed version.

gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.

# Examples

    gawk '{ sum += \$1 }; END { print sum }' file
    gawk -F: '{ print \$1 }' /etc/passwd

"""
function awk(args...)
    options_seq, pos_args = parse_args(args)
    do_print_usage(options_seq, @doc awk) && return
    options = parse_options(AwkOptions, options_seq)
    _awk(options, pos_args)
end

function _awk(options, args)
    # TODO: Select program based on file or source options as well as first
    #       positional argument.
    program = options.source
    program === nothing && return
    # Each element of program is either a function or a pair.
    # Functions are run every time on each line.
    # Pairs are a predicate plus action. The first term is a predicate, so that
    # the action only runs if the predicate returns true. The action is the same
    # as a stand alone function.
    # The function has signature f(vars, fields) and can return any value.
    # Return nothing to not append anything to result.

    function read_fields(fn)
        if options.field_separator == " "
            return readdlm(fn, String, quotes=false)
        else
            return readdlm(fn, '=', String, quotes=false)
        end
    end

    ret = []
    vars = []
    for fn in args
        fields = read_fields(fn)
        # Swap dims so we index by column major order.
        fields = permutedims(fields)
        for i in axes(fields, 2)
            for rule in program
                if rule isa Pair
                    if rule.first(vars, fields[:, i])
                        result = rule.second(vars, fields[:, i])
                    else
                        result = nothing
                    end
                else
                    result = rule(vars, fields[:, i])
                end
                result !== nothing && push!(ret, result)
            end
        end
    end
    ret
end


text:
# Auto-generated by gen_constants.jl on 6/9/2015
const MBEDTLS_ASN1_PRINTABLE_STRING=19
const MBEDTLS_X509_BADCERT_CN_MISMATCH=4
const MBEDTLS_ERR_NET_INVALID_CONTEXT=-69
const MBEDTLS_ERR_PK_SIG_LEN_MISMATCH=-14592
const MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT=86400
const MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE=-5120
const MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED=-30336
const MBEDTLS_ERR_MD_FILE_IO_ERROR=-20992
const MBEDTLS_CIPHER_VARIABLE_KEY_LEN=2
const MBEDTLS_TLS_EXT_SIG_ALG=13
const MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256=49304
const MBEDTLS_PADLOCK_ACE=192
const MBEDTLS_ASN1_GENERALIZED_TIME=24
const MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256=184
const MBEDTLS_HMAC_DRBG_RESEED_INTERVAL=10000
const MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL=-20224
const MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME=0
const MBEDTLS_SSL_TRUNC_HMAC_ENABLED=1
const MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL=120
const MBEDTLS_ERR_PK_ALLOC_FAILED=-16256
const MBEDTLS_ERR_X509_BUFFER_TOO_SMALL=-10624
const MBEDTLS_SSL_TRUNCATED_HMAC_LEN=10
const MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA=49205
const MBEDTLS_CTR_DRBG_RESEED_INTERVAL=10000
const MBEDTLS_SSL_MINOR_VERSION_0=0
const MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED=-12928
const MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE=-20608
const MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA=49167
const MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED=-64
const MBEDTLS_SSL_ANTI_REPLAY_DISABLED=0
const MBEDTLS_ERR_CCM_BAD_INPUT=-13
const MBEDTLS_PSK_MAX_LEN=32
const MBEDTLS_SSL_VERIFY_OPTIONAL=1
const MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384=49208
const MBEDTLS_BLOWFISH_ENCRYPT=1
const MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX=60000
const MBEDTLS_SSL_VERIFY_DATA_MAX_LEN=12
const MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384=49307
const MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC=22
const MBEDTLS_ERR_DHM_CALC_SECRET_FAILED=-13056
const MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH=-2
const MBEDTLS_ERR_SSL_CONN_EOF=-29312
const MBEDTLS_ERR_BASE64_INVALID_CHARACTER=-44
const MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256=49189
const MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE=-2
const MBEDTLS_ERR_PEM_PASSWORD_REQUIRED=-4864
const MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384=181
const MBEDTLS_CTR_DRBG_KEYSIZE=32
const MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256=49197
const MBEDTLS_ERR_RSA_RNG_FAILED=-17536
const MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES=10
const MBEDTLS_ERR_RSA_INVALID_PADDING=-16640
const MBEDTLS_ERR_SSL_COMPRESSION_FAILED=-28416
const MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256=49274
const MBEDTLS_ERR_NET_RECV_FAILED=-76
const MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE=-29952
const MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA=49171
const MBEDTLS_ERR_NET_SOCKET_FAILED=-66
const MBEDTLS_ERR_SSL_TIMEOUT=-26624
const MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256=49272
const MBEDTLS_ERR_SSL_INVALID_RECORD=-29184
const MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR=-58
const MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED=-30208
const MBEDTLS_X509_BADCERT_MISSING=64
const MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384=49291
const MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR=80
const MBEDTLS_CIPHERSUITE_WEAK=1
const MBEDTLS_SSL_VERIFY_REQUIRED=2
const MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384=179
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8=49327
const MBEDTLS_PKCS12_DERIVE_KEY=1
const MBEDTLS_SSL_HASH_SHA512=6
const MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256=49201
const MBEDTLS_CTR_DRBG_MAX_REQUEST=1024
const MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION=0
const MBEDTLS_ERR_PK_PASSWORD_REQUIRED=-15360
const MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA=139
const MBEDTLS_ECP_DP_MAX=12
const MBEDTLS_CAMELLIA_DECRYPT=0
const MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE=-26
const MBEDTLS_SSL_COMPRESS_DEFLATE=1
const MBEDTLS_X509_BADCRL_EXPIRED=32
const MBEDTLS_HMAC_DRBG_PR_ON=1
const MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384=49295
const MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA=46
const MBEDTLS_ERR_SSL_INTERNAL_ERROR=-27648
const MBEDTLS_VERSION_PATCH=0
const MBEDTLS_CTR_DRBG_ENTROPY_LEN=32
const MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA=65
const MBEDTLS_ERR_X509_INVALID_SIGNATURE=-9344
const MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK=86
const MBEDTLS_X509_BADCERT_EXPIRED=1
const MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR=51
const MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE=-29824
const MBEDTLS_SSL_SESSION_TICKETS_ENABLED=1
const MBEDTLS_X509_BADCERT_FUTURE=512
const MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384=169
const MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA=149
const MBEDTLS_SSL_RETRANS_FINISHED=3
const MBEDTLS_SSL_RENEGOTIATION_PENDING=3
const MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE=-30464
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA=49159
const MBEDTLS_SSL_HS_CERTIFICATE=11
const MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8=49314
const MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED=0
const MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA=48
const MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256=49268
const MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL=-42
const MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE=-17408
const MBEDTLS_ERR_ECP_RANDOM_FAILED=-19712
const MBEDTLS_DES_DECRYPT=0
const MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY=0
const MBEDTLS_GCM_ENCRYPT=1
const MBEDTLS_ERR_ASN1_UNEXPECTED_TAG=-98
const MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA=49172
const MBEDTLS_SSL_HASH_SHA224=3
const MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO=255
const MBEDTLS_SSL_EXTENDED_MS_DISABLED=0
const MBEDTLS_SSL_VERIFY_UNSET=3
const MBEDTLS_PADLOCK_RNG=12
const MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256=158
const MBEDTLS_ERR_ECP_BAD_INPUT_DATA=-20352
const MBEDTLS_MEMORY_ALIGN_MULTIPLE=4
const MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET=23
const MBEDTLS_ERR_ASN1_ALLOC_FAILED=-106
const MBEDTLS_ERR_ASN1_OUT_OF_DATA=-96
const MBEDTLS_ASN1_BOOLEAN=1
const MBEDTLS_ERR_SSL_INVALID_MAC=-29056
const MBEDTLS_TLS_RSA_WITH_AES_128_CCM=49308
const MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA=146
const MBEDTLS_ERR_PK_FILE_IO_ERROR=-15872
const MBEDTLS_ERR_DHM_INVALID_FORMAT=-13184
const MBEDTLS_ERR_SSL_ALLOC_FAILED=-32512
const MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS=11
const MBEDTLS_SSL_RENEGOTIATION_NOT_ENFORCED=-1
const MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM=49310
const MBEDTLS_PKCS12_DERIVE_MAC_KEY=3
const MBEDTLS_ECP_FIXED_POINT_OPTIM=1
const MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT=-10112
const MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256=49300
const MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC=20
const MBEDTLS_ERR_X509_INVALID_ALG=-8960
const MBEDTLS_ECP_PF_UNCOMPRESSED=0
const MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN=32
const MBEDTLS_ERR_OID_BUF_TOO_SMALL=-11
const MBEDTLS_ERR_DHM_READ_PARAMS_FAILED=-12544
const MBEDTLS_ERR_PK_KEY_INVALID_FORMAT=-15616
const MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA=49209
const MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256=49270
const MBEDTLS_X509_RFC5280_UTC_TIME_LEN=15
const MBEDTLS_BLOWFISH_MIN_KEY_BITS=32
const MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256=49306
const MBEDTLS_ERR_ENTROPY_MAX_SOURCES=-62
const MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384=171
const MBEDTLS_ASN1_UTC_TIME=23
const MBEDTLS_ECP_MAX_BITS=521
const MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH=-27904
const MBEDTLS_SSL_PRESET_SUITEB=2
const MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256=49294
const MBEDTLS_SSL_PRESET_DEFAULT=0
const MBEDTLS_ERR_X509_INVALID_VERSION=-8704
const MBEDTLS_SSL_COOKIE_TIMEOUT=60
const MBEDTLS_NET_PROTO_TCP=0
const MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA=49163
const MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT=110
const MBEDTLS_NET_LISTEN_BACKLOG=10
const _CRT_SECURE_NO_DEPRECATE=1
const MBEDTLS_PKCS5_ENCRYPT=1
const MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED=-30720
const MBEDTLS_ERR_NET_SEND_FAILED=-78
const MBEDTLS_SSL_SECURE_RENEGOTIATION=1
const MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384=49289
const MBEDTLS_SSL_MAJOR_VERSION_3=3
const MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256=49290
const MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE=-28800
const MBEDTLS_X509_CRT_VERSION_1=0
const MBEDTLS_ERR_THREADING_BAD_INPUT_DATA=-28
const MBEDTLS_ERR_PK_BAD_INPUT_DATA=-16000
const MBEDTLS_SSL_HS_CERTIFICATE_VERIFY=15
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384=49188
const MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION=100
const MBEDTLS_SSL_SIG_RSA=1
const MBEDTLS_DES_KEY_SIZE=8
const MBEDTLS_TLS_RSA_WITH_RC4_128_SHA=5
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256=49187
const MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION=1
const MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT=384
const MBEDTLS_SSL_RETRANS_PREPARING=0
const MBEDTLS_SSL_COMPRESS_NULL=0
const MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE=-7936
const MBEDTLS_TLS_EXT_TRUNCATED_HMAC=4
const MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL=-8
const MBEDTLS_SSL_IS_NOT_FALLBACK=0
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA=49158
const MBEDTLS_SSL_ALERT_MSG_NO_CERT=41
const MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH=-19456
const MBEDTLS_SSL_MINOR_VERSION_2=2
const MBEDTLS_SSL_ALERT_LEVEL_FATAL=2
const MBEDTLS_ERR_RSA_VERIFY_FAILED=-17280
const MBEDTLS_X509_BADCERT_BAD_MD=16384
const MBEDTLS_ASN1_SET=17
const MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA=142
const MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384=173
const MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH=-24
const MBEDTLS_ASN1_UTF8_STRING=12
const MBEDTLS_SSL_SIG_ANON=0
const MBEDTLS_ERR_CIPHER_AUTH_FAILED=-25344
const MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE=10
const MBEDTLS_ERR_ENTROPY_SOURCE_FAILED=-60
const MBEDTLS_CIPHERSUITE_NODTLS=4
const MBEDTLS_SSL_ALERT_MSG_DECOMPRESSION_FAILURE=30
const MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA=49164
const MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256=156
const MBEDTLS_X509_MAX_DN_NAME_SIZE=256
const MBEDTLS_ERR_MPI_NOT_ACCEPTABLE=-14
const MBEDTLS_SSL_MAX_FRAG_LEN_INVALID=5
const MBEDTLS_SSL_HS_FINISHED=20
const MBEDTLS_MPI_MAX_SIZE=1024
const MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8=49313
const MBEDTLS_SSL_RENEGO_MAX_RECORDS_DEFAULT=16
const MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED=-12800
const MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED=-28032
const MBEDTLS_ENTROPY_MIN_HARDWARE=32
const MBEDTLS_X509_BADCERT_KEY_USAGE=2048
const MBEDTLS_ASN1_INTEGER=2
const MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE=16
const MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH=-28544
const MBEDTLS_PKCS12_PBE_ENCRYPT=1
const MBEDTLS_ENTROPY_SOURCE_STRONG=1
const MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=49191
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA=49162
const MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA=45
const MBEDTLS_SSL_ALERT_MSG_INSUFFICIENT_SECURITY=71
const MBEDTLS_ERR_NET_ACCEPT_FAILED=-74
const MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY=-32128
const MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA=49204
const MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256=170
const MBEDTLS_SSL_HS_SERVER_HELLO=2
const MBEDTLS_RSA_PRIVATE=1
const MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG=-54
const MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH=-38
const MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256=49292
const MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA=136
const MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA=148
const MBEDTLS_SSL_ARC4_DISABLED=1
const MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE=-31616
const MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384=157
const MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN=-29568
const MBEDTLS_ENTROPY_MAX_GATHER=128
const MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA=21
const MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA=49203
const MBEDTLS_SSL_HS_NEW_SESSION_TICKET=4
const MBEDTLS_SSL_ALERT_MSG_DECRYPTION_FAILED=21
const MBEDTLS_CAMELLIA_ENCRYPT=1
const MBEDTLS_TLS_RSA_WITH_NULL_MD5=1
const MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384=49305
const MBEDTLS_X509_BADCRL_FUTURE=1024
const MBEDTLS_ERR_X509_INVALID_FORMAT=-8576
const MBEDTLS_ERR_ASN1_INVALID_LENGTH=-100
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384=49267
const MBEDTLS_HMAC_DRBG_MAX_INPUT=256
const MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED=1
const MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET=-28160
const MBEDTLS_VERSION_MAJOR=2
const MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384=49277
const MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE=-14848
const MBEDTLS_ERR_MPI_BAD_INPUT_DATA=-4
const MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA=49168
const MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL=-27136
const MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER=47
const MBEDTLS_X509_BADCERT_REVOKED=2
const MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT=-7808
const MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8=49322
const MBEDTLS_SSL_CHANNEL_OUTBOUND=0
const MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG=-5
const MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA=144
const MBEDTLS_SSL_CERT_TYPE_RSA_SIGN=1
const MBEDTLS_RSA_CRYPT=2
const MBEDTLS_AES_ENCRYPT=1
const MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE=-31744
const MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8=49315
const MBEDTLS_ERR_MPI_NEGATIVE_VALUE=-10
const MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA=132
const MBEDTLS_AESNI_AES=33554432
const MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384=183
const MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA=49206
const MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256=49288
const MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION=-28288
const MBEDTLS_SSL_IS_CLIENT=0
const MBEDTLS_ERR_X509_CERT_VERIFY_FAILED=-9984
const MBEDTLS_ERR_PEM_INVALID_ENC_IV=-4608
const MBEDTLS_MEMORY_VERIFY_NONE=0
const MBEDTLS_ERR_NET_LISTEN_FAILED=-72
const MBEDTLS_SSL_COMPRESSION_ADD=0
const MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE=2
const MBEDTLS_SSL_RETRANS_WAITING=2
const MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME=112
const MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256=49302
const MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED=-48
const MBEDTLS_CIPHERSUITE_SHORT_TAG=2
const MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA=49156
const MBEDTLS_ERR_RSA_KEY_GEN_FAILED=-16768
const MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH=-22
const MBEDTLS_ERR_NET_CONN_RESET=-80
const MBEDTLS_ERR_PK_INVALID_PUBKEY=-15104
const MBEDTLS_SSL_ETM_ENABLED=1
const MBEDTLS_ASN1_OCTET_STRING=4
const MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE=40
const MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA=140
const MBEDTLS_ERR_SSL_WANT_READ=-26880
const MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE=-20096
const MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT=43
const MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384=49202
const MBEDTLS_ASN1_CONSTRUCTED=32
const MBEDTLS_CTR_DRBG_BLOCKSIZE=16
const MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR=-63
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256=49195
const MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384=49200
const MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED=-27264
const MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE=-31488
const MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA=22
const MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256=49296
const MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST=-31360
const MBEDTLS_MPI_MAX_LIMBS=10000
const MBEDTLS_SSL_TRUNC_HMAC_DISABLED=0
const MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256=182
const MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE=12
const MBEDTLS_PKCS12_PBE_DECRYPT=0
const MBEDTLS_PKCS5_DECRYPT=0
const MBEDTLS_TLS_PSK_WITH_RC4_128_SHA=138
const MBEDTLS_TLS_PSK_WITH_AES_128_CCM=49316
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384=49287
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256=49266
const MBEDTLS_X509_MAX_INTERMEDIATE_CA=8
const MBEDTLS_ERR_DHM_FILE_IO_ERROR=-13440
const MBEDTLS_ERR_OID_NOT_FOUND=-46
const MBEDTLS_ENTROPY_MAX_SOURCES=20
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256=49286
const MBEDTLS_SSL_ETM_DISABLED=0
const MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256=49207
const MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST=3
const MBEDTLS_ENTROPY_MIN_HARDCLOCK=4
const MBEDTLS_ERR_MPI_FILE_IO_ERROR=-2
const MBEDTLS_MAX_BLOCK_LENGTH=16
const MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256=168
const MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC=20
const MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384=49301
const MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256=49199
const MBEDTLS_BLOWFISH_DECRYPT=0
const MBEDTLS_SSL_SIG_ECDSA=3
const MBEDTLS_ERR_SSL_BAD_INPUT_DATA=-28928
const MBEDTLS_SSL_ALERT_MSG_USER_CANCELED=90
const MBEDTLS_X509_BADCRL_BAD_PK=262144
const MBEDTLS_ERR_X509_UNKNOWN_OID=-8448
const MBEDTLS_SSL_FALLBACK_SCSV_VALUE=22016
const MBEDTLS_ERR_SSL_NO_RNG=-29696
const MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME=86400
const MBEDTLS_SSL_ARC4_ENABLED=0
const MBEDTLS_SSL_HASH_SHA1=2
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA=49161
const MBEDTLS_NET_PROTO_UDP=1
const MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8=49321
const MBEDTLS_BLOWFISH_MAX_KEY_BITS=448
const MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED=45
const MBEDTLS_ERR_NET_BUFFER_TOO_SMALL=-67
const MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384=185
const MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384=49303
const MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256=180
const MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384=49297
const MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG=-9728
const MBEDTLS_SSL_IS_FALLBACK=1
const MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256=49276
const MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED=49
const MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256=172
const MBEDTLS_ENTROPY_MIN_PLATFORM=32
const MBEDTLS_ERR_RSA_PUBLIC_FAILED=-17024
const MBEDTLS_ERR_GCM_BAD_INPUT=-20
const MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM=49319
const MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH=-7680
const MBEDTLS_X509_BADCRL_BAD_MD=131072
const MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED=-52
const MBEDTLS_ERR_MD_ALLOC_FAILED=-20864
const MBEDTLS_X509_BADCERT_EXT_KEY_USAGE=4096
const MBEDTLS_ERR_MD_BAD_INPUT_DATA=-20736
const MBEDTLS_ASN1_BMP_STRING=30
const MBEDTLS_BLOWFISH_BLOCKSIZE=8
const MBEDTLS_SSL_HASH_SHA256=4
const MBEDTLS_ERR_DHM_BAD_INPUT_DATA=-12416
const MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384=49198
const MBEDTLS_ENTROPY_SOURCE_WEAK=0
const MBEDTLS_SSL_MAX_FRAG_LEN_4096=4
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8=49326
const MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED=-25216
const MBEDTLS_ERR_ECP_VERIFY_FAILED=-19968
const MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA=47
const MBEDTLS_SSL_HS_CLIENT_HELLO=1
const MBEDTLS_ERR_NET_UNKNOWN_HOST=-82
const MBEDTLS_SSL_HS_CERTIFICATE_REQUEST=13
const MBEDTLS_SSL_HS_HELLO_REQUEST=0
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM=49325
const MBEDTLS_RSA_SIGN=1
const MBEDTLS_SSL_MINOR_VERSION_3=3
const MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS=-32000
const MBEDTLS_TLS_PSK_WITH_NULL_SHA384=177
const MBEDTLS_ENTROPY_MAX_SEED_SIZE=1024
const MBEDTLS_ERR_PEM_INVALID_DATA=-4352
const MBEDTLS_MAX_IV_LENGTH=16
const MBEDTLS_ERR_CIPHER_ALLOC_FAILED=-24960
const MBEDTLS_X509_BADCERT_OTHER=256
const MBEDTLS_ERR_X509_INVALID_DATE=-9216
const MBEDTLS_SSL_MAX_FRAG_LEN_2048=3
const MBEDTLS_ERR_NET_BIND_FAILED=-70
const MBEDTLS_SSL_ALERT_MSG_RECORD_OVERFLOW=22
const MBEDTLS_CTR_DRBG_PR_OFF=0
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384=49196
const MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS=1
const MBEDTLS_SSL_HASH_MD5=1
const MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8=49323
const MBEDTLS_ERR_AES_INVALID_KEY_LENGTH=-32
const MBEDTLS_ASN1_SEQUENCE=16
const MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA=-2
const MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA=145
const MBEDTLS_X509_BADCERT_NS_CERT_TYPE=8192
const MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED=-12672
const MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA=49157
const MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG=-56
const MBEDTLS_ERR_CCM_AUTH_FAILED=-15
const MBEDTLS_SSL_TRANSPORT_DATAGRAM=1
const MBEDTLS_ASN1_NULL=5
const MBEDTLS_SSL_EXTENDED_MS_ENABLED=1
const MBEDTLS_TLS_EXT_ALPN=16
const MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA=69
const MBEDTLS_ERR_RSA_PRIVATE_FAILED=-17152
const MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA=49170
const MBEDTLS_ERR_ASN1_LENGTH_MISMATCH=-102
const MBEDTLS_ERR_SSL_BAD_HS_FINISHED=-32384
const MBEDTLS_ERR_PK_TYPE_MISMATCH=-16128
const MBEDTLS_TLS_RSA_WITH_NULL_SHA256=59
const MBEDTLS_PKCS12_DERIVE_IV=2
const MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256=174
const MBEDTLS_ASN1_T61_STRING=20
const MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA=49169
const MBEDTLS_ERR_ECP_INVALID_KEY=-19584
const MBEDTLS_ERR_X509_UNKNOWN_VERSION=-9600
const MBEDTLS_ERR_PKCS5_INVALID_FORMAT=-2
const MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256=192
const MBEDTLS_X509_FORMAT_PEM=2
const MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH=1
const MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA=49155
const MBEDTLS_ASN1_BIT_STRING=3
const MBEDTLS_SSL_RETRANS_SENDING=1
const MBEDTLS_TLS_RSA_WITH_NULL_SHA=2
const MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256=196
const MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA=9
const MBEDTLS_X509_BADCRL_BAD_KEY=524288
const MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE=-24704
const MBEDTLS_TLS_PSK_WITH_AES_256_CCM=49317
const MBEDTLS_XTEA_ENCRYPT=1
const MBEDTLS_X509_BADCRL_NOT_TRUSTED=16
const MBEDTLS_ERR_PK_INVALID_ALG=-14976
const MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256=49210
const MBEDTLS_SSL_SESSION_TICKETS_DISABLED=0
const MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM=49318
const MBEDTLS_SSL_ALERT_LEVEL_WARNING=1
const MBEDTLS_SSL_PADDING_ADD=0
const MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA=57
const MBEDTLS_TLS_PSK_WITH_NULL_SHA256=176
const MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384=159
const MBEDTLS_ERR_MPI_DIVISION_BY_ZERO=-12
const MBEDTLS_SSL_MSG_APPLICATION_DATA=23
const MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO=-31104
const MBEDTLS_TLS_EXT_SERVERNAME=0
const MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE=-31232
const MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT=-4224
const MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384=49190
const MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256=103
const MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY=115
const MBEDTLS_SSL_LEGACY_RENEGOTIATION=0
const MBEDTLS_ERR_ASN1_INVALID_DATA=-104
const MBEDTLS_ERR_NET_CONNECT_FAILED=-68
const MBEDTLS_X509_BADCERT_SKIP_VERIFY=128
const MBEDTLS_ERR_SSL_HW_ACCEL_FAILED=-32640
const MBEDTLS_ERR_X509_INVALID_EXTENSIONS=-9472
const MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH=-40
const MBEDTLS_TLS_RSA_WITH_RC4_128_MD5=4
const MBEDTLS_ERR_PEM_PASSWORD_MISMATCH=-4992
const MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA=49154
const MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED=44
const MBEDTLS_ERR_THREADING_MUTEX_ERROR=-30
const MBEDTLS_ERR_ASN1_BUF_TOO_SMALL=-108
const MBEDTLS_GCM_DECRYPT=0
const MBEDTLS_CTR_DRBG_MAX_INPUT=256
const MBEDTLS_RSA_PKCS_V15=0
const MBEDTLS_SSL_ANTI_REPLAY_ENABLED=1
const MBEDTLS_MD_MAX_SIZE=32
const MBEDTLS_HAVEGE_COLLECT_SIZE=1024
const MBEDTLS_ERR_GCM_AUTH_FAILED=-18
const MBEDTLS_AESNI_CLMUL=2
const MBEDTLS_CTR_DRBG_PR_ON=1
const MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256=186
const MBEDTLS_ECP_TLS_NAMED_CURVE=3
const MBEDTLS_ERR_RSA_BAD_INPUT_DATA=-16512
const MBEDTLS_CIPHER_VARIABLE_IV_LEN=1
const MBEDTLS_PADLOCK_PMM=12288
const MBEDTLS_X509_BADCERT_BAD_PK=32768
const MBEDTLS_ERR_PK_KEY_INVALID_VERSION=-15744
const MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED=-9
const MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256=61
const MBEDTLS_ENTROPY_BLOCK_SIZE=32
const MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA=141
const MBEDTLS_X509_BADCERT_BAD_KEY=65536
const MBEDTLS_HMAC_DRBG_MAX_REQUEST=1024
const MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR=-7
const MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384=49271
const MBEDTLS_TLS_EXT_RENEGOTIATION_INFO=65281
const MBEDTLS_MPI_WINDOW_SIZE=6
const MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR=50
const MBEDTLS_DES_ENCRYPT=1
const MBEDTLS_PADLOCK_PHE=3072
const MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256=49193
const MBEDTLS_ERR_PEM_ALLOC_FAILED=-4480
const MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE=-30592
const MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA=53
const MBEDTLS_TLS_PSK_WITH_NULL_SHA=44
const MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384=49211
const MBEDTLS_ECP_WINDOW_SIZE=6
const MBEDTLS_BLOWFISH_ROUNDS=16
const MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384=175
const MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384=49275
const MBEDTLS_TLS_RSA_WITH_AES_256_CCM=49309
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM=49324
const MBEDTLS_ERR_SSL_WANT_WRITE=-26752
const MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH=-50
const MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO=-27392
const MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA=51
const MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH=-34
const MBEDTLS_ERR_SSL_UNKNOWN_CIPHER=-29440
const MBEDTLS_ERR_X509_INVALID_SERIAL=-8832
const MBEDTLS_SSL_MAX_FRAG_LEN_1024=2
const MBEDTLS_X509_BADCERT_NOT_TRUSTED=8
const MBEDTLS_ERR_RSA_KEY_CHECK_FAILED=-16896
const MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY=-30848
const MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES=50
const MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC=-32256
const MBEDTLS_XTEA_DECRYPT=0
const MBEDTLS_ERR_PK_PASSWORD_MISMATCH=-15232
const MBEDTLS_ERR_X509_FILE_IO_ERROR=-10496
const MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384=49293
const MBEDTLS_RSA_SALT_LEN_ANY=-1
const MBEDTLS_ERR_PK_UNKNOWN_PK_ALG=-15488
const MBEDTLS_X509_FORMAT_DER=1
const MBEDTLS_SSL_ALERT_MSG_BAD_CERT=42
const MBEDTLS_SSL_HASH_NONE=0
const MBEDTLS_X509_CRT_VERSION_2=1
const MBEDTLS_ERR_X509_BAD_INPUT_DATA=-10240
const MBEDTLS_SSL_MAC_ADD=16
const MBEDTLS_ASN1_IA5_STRING=22
const MBEDTLS_SSL_ALERT_MSG_EXPORT_RESTRICTION=60
const MBEDTLS_VERSION_MINOR=1
const MBEDTLS_ERR_ECP_ALLOC_FAILED=-19840
const MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM=49311
const MBEDTLS_ERR_X509_SIG_MISMATCH=-9856
const MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384=49192
const MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY=-27776
const MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP=-31872
const MBEDTLS_ENTROPY_MIN_HAVEGE=32
const MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO=-30976
const MBEDTLS_SSL_HASH_SHA384=5
const MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384=49273
const MBEDTLS_ERR_MPI_ALLOC_FAILED=-16
const MBEDTLS_ASN1_PRIMITIVE=0
const MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE=-8320
const MBEDTLS_HMAC_DRBG_PR_OFF=0
const MBEDTLS_ERR_X509_INVALID_NAME=-9088
const MBEDTLS_SSL_MINOR_VERSION_1=1
const MBEDTLS_SSL_MAX_FRAG_LEN_512=1
const MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED=-30080
const MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA=10
const MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA=49165
const MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA=143
const MBEDTLS_X509_CRT_VERSION_3=2
const MBEDTLS_SSL_HS_SERVER_HELLO_DONE=14
const MBEDTLS_ASN1_OID=6
const MBEDTLS_ASN1_UNIVERSAL_STRING=28
const MBEDTLS_RSA_PKCS_V21=1
const MBEDTLS_TLS_EXT_SESSION_TICKET=35
const MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN=1000
const MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION=70
const MBEDTLS_AES_DECRYPT=0
const MBEDTLS_ERR_PEM_BAD_INPUT_DATA=-5248
const MBEDTLS_SSL_TRANSPORT_STREAM=0
const MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA=-24832
const MBEDTLS_ERR_CIPHER_INVALID_PADDING=-25088
const MBEDTLS_ECP_PF_COMPRESSED=1
const MBEDTLS_SSL_CHANNEL_INBOUND=1
const MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN=64
const MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256=107
const MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256=60
const MBEDTLS_SSL_MAX_FRAG_LEN_NONE=0
const MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384=49269
const MBEDTLS_VERSION_NUMBER=33619968
const MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE=-61
const MBEDTLS_ERR_DHM_ALLOC_FAILED=-13312
const MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA=49153
const MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE=-14720
const MBEDTLS_SSL_INITIAL_HANDSHAKE=0
const MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA=-8064
const MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA=49160
const MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA=49166
const MBEDTLS_SSL_RENEGOTIATION_DONE=2
const MBEDTLS_SSL_RENEGOTIATION_DISABLED=0
const MBEDTLS_SSL_MSG_ALERT=21
const MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH=-36
const MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256=49298
const MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE=-27008
const MBEDTLS_ERR_X509_ALLOC_FAILED=-10368
const MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256=190
const MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8=49312
const MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG=-3
const MBEDTLS_ERR_SSL_COUNTER_WRAPPING=-27520
const MBEDTLS_SSL_IS_SERVER=1
const MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384=49194
const MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256=178
const MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN=46
const MBEDTLS_SSL_MAX_CONTENT_LEN=16384
const MBEDTLS_SSL_VERIFY_NONE=0
const MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8=49320
const MBEDTLS_RSA_PUBLIC=0
const MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384=49299
const MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA=147
const MBEDTLS_SSL_RENEGOTIATION_ENABLED=1
const MBEDTLS_LN_2_DIV_LN_10_SCALE100=332
const MBEDTLS_ASN1_CONTEXT_SPECIFIC=128
const MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG=-4736
const MBEDTLS_SSL_MSG_HANDSHAKE=22
const MBEDTLS_PK_DEBUG_MAX_ITEMS=3
const MBEDTLS_ERR_MPI_INVALID_CHARACTER=-6
const MBEDTLS_CTR_DRBG_MAX_SEED_INPUT=384


text:
"""
	$(SIGNATURES)

Grouped bar plot of a matrix by (x,y).
The `y` categories become groups.

Bug in `Plots.jl` (v1.6.0): Some `groupLabels` such as `fill("x", n)` give size errors.

# Arguments
- `groupLabels`: labels for each group of bars
- `xLabels`: used for legend, unless `legendPos == :none`
- `xLabel`: x axis label.
- `yLabel`: y axis label.
- `yErrorM`: optional matrix with std deviations for error bars. Same format as `dataM`.
"""
function grouped_bar_xy(dataM :: AbstractMatrix{F1},
    groupLabels :: AbstractVector{String};
    xLabel :: AbstractString = "", yLabel :: AbstractString = "",
    legendV = nothing, legendPos = :best,
    yErrorM = nothing) where F1 <: AbstractFloat

    nx, ny = size(dataM);
    @assert length(groupLabels) == ny  "Size mismatch: $ny vs $groupLabels"

    if isnothing(legendV)
        legendPos = :none;
    end
    if isnothing(yErrorM)
        yErrM = nothing;
    else
        @assert size(yErrorM) == size(dataM)  "Size mismatch"
        yErrM = yErrorM';
    end

    # markerstrokewidth for error bars
    # linewidth does not affect error bars
    p = groupedbar(groupLabels, dataM', bar_position = :dodge,
        leg = legendPos, labels = make_legend(legendV),
        xlabel = xLabel, ylabel = yLabel,
        yerr = yErrM, markerstrokewidth = 2, markerstrokecolor = :black,
        linecolor = :black, lw = 0);
    # end
    return p
end

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


text:
import Base.source_path

using Base.Test

srcpath = source_path()
srcdir  = dirname(srcpath)

# Inject the main source directory into the load path
push!(LOAD_PATH, "$srcdir/")

max_stars_repo_name: ogh/binclusion

max_issues_repo_name: ogh/binclusion

max_forks_repo_name: ogh/binclusion


text:
using Klimakoffer

Klimakoffer.images_to_maps(joinpath(@__DIR__,"reference_data"), joinpath(@__DIR__, "reference_data"), true, 1, 10, 10, 190, 210)

world = Klimakoffer.read_geography(joinpath(@__DIR__, "reference_data", "The_World_from_image10x6_3.dat" ), 10, 6)

ref = Klimakoffer.read_geography(joinpath(@__DIR__,"reference_data", "test_image_result.dat"), 10, 6)

diff = ref-world

res = sum(abs.(diff))

if !isfile(joinpath(@__DIR__, "reference_data", "The_World_from_image128x65_1.dat" ))
    res +=1
end

result = res/(10*6)

rm(joinpath(@__DIR__, "reference_data", "The_World_from_image10x6_3.dat" ))


text:
@doc doc"""
sma{Float64}(x::Vector{Float64}, n::Int64=10)

Simple moving average
""" ->
function sma{Float64}(x::Vector{Float64}, n::Int64=10)
	return runmean(x, n, false)
end

@doc doc"""
trima{Float64}(x::Vector{Float64}, n::Int64=10; ma::Function=sma, args...)

Triangular moving average
""" ->
function trima{Float64}(x::Vector{Float64}, n::Int64=10; ma::Function=sma)
    return ma(ma(x, n), n)
end

@doc doc"""
wma{Float64}(x::Vector{Float64}, n::Int64=10; wts::Vector{Float64}=collect(1:n)/sum(1:n))

Weighted moving average
""" ->
function wma{Float64}(x::Vector{Float64}, n::Int64=10; wts::Vector{Float64}=collect(1:n)/sum(1:n))
    @assert n<size(x,1) && n>0 "Argument n out of bounds"
	out = fill(NaN, size(x,1))
    @inbounds for i = n:size(x,1)
        out[i] = (wts' * x[i-n+1:i])[1]
    end
    return out
end

@doc doc"""
ema{Float64}(x::Vector{Float64}, n::Int64=10; alpha::Float64=2.0/(n+1.0), wilder::Bool=false)

Exponential moving average
""" ->
function ema{Float64}(x::Vector{Float64}, n::Int64=10; alpha::Float64=2.0/(n+1), wilder::Bool=false)
    @assert n<size(x,1) && n>0 "Argument n out of bounds."
    if wilder
        alpha = 1.0/n
    end
    out = zeros(x)
    i = first(find(!isnan(x)))
    out[1:n+i-2] = NaN
    out[n+i-1] = mean(x[i:n+i-1])
    @inbounds for i = n+i:size(x,1)
        out[i] = alpha * (x[i] - out[i-1]) + out[i-1]
    end
    return out
end

@doc doc"""
mma{Float64}(x::Vector{Float64}, n::Int64=10)

Modified moving average
""" ->
function mma{Float64}(x::Vector{Float64}, n::Int64=10)
    return ema(x, n, alpha=1.0/n)
end

@doc doc"""
dema{Float64}(x::Vector{Float64}, n::Int64=10; alpha=2.0/(n+1), wilder::Bool=false)

Double exponential moving average
""" ->
function dema{Float64}(x::Vector{Float64}, n::Int64=10; alpha=2.0/(n+1), wilder::Bool=false)
    return 2.0 * ema(x, n, alpha=alpha, wilder=wilder) -
        ema(ema(x, n, alpha=alpha, wilder=wilder),
            n, alpha=alpha, wilder=wilder)
end

@doc doc"""
tema{Float64}(x::Vector{Float64}, n::Int64=10; alpha=2.0/(n+1), wilder::Bool=false)

Triple exponential moving average
""" ->
function tema{Float64}(x::Vector{Float64}, n::Int64=10; alpha=2.0/(n+1), wilder::Bool=false)
    return 3.0 * ema(x, n, alpha=alpha, wilder=wilder) -
        3.0 * ema(ema(x, n, alpha=alpha, wilder=wilder),
                  n, alpha=alpha, wilder=wilder) +
        ema(ema(ema(x, n, alpha=alpha, wilder=wilder),
                n, alpha=alpha, wilder=wilder),
            n, alpha=alpha, wilder=wilder)
end

@doc doc"""
mama{Float64}(x::Vector{Float64}, fastlimit::Float64=0.5, slowlimit::Float64=0.05)

MESA adaptive moving average (developed by John Ehlers)
""" ->
function mama{Float64}(x::Vector{Float64}, fastlimit::Float64=0.5, slowlimit::Float64=0.05)
    n = size(x,1)
    out = zeros(n,2)
    smooth = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    detrend = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    Q1 = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    I1 = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
    I2 = [0.0, 0.0]
    Q2 = [0.0, 0.0]
    Re = [0.0, 0.0]
    Im = [0.0, 0.0]
    per = [0.0, 0.0]
    sper = [0.0, 0.0]
    phase = [0.0, 0.0]
    jI = 0.0
    jQ = 0.0
    dphase = 0.0
    alpha = 0.0
    a = 0.0962
    b = 0.5769
    @inbounds for i = 13:n
        # Smooth and detrend price movement ====================================
        smooth[7] = (4*x[i] + 3*x[i-1] + 2*x[i-2] + x[i-3]) * 0.1
        detrend[7] = (0.0962*smooth[7]+0.5769*smooth[5]-0.5769*smooth[3]-0.0962*smooth[1]) * (0.075*per[1]+0.54)
        # Compute InPhase and Quandrature components ===========================
        Q1[7] = (0.0962*detrend[7]+0.5769*detrend[5]-0.5769*detrend[3]-0.0962*detrend[1]) * (0.075*per[1]+0.54)
        I1[7] = detrend[4]
        # Advance phase of I1 and Q1 by 90 degrees =============================
        jQ = (0.0962*Q1[7]+0.5769*Q1[5]-0.5769*Q1[3]-0.0962*Q1[1]) * (0.075*per[1]+0.54)
        jI = (0.0962*I1[7]+0.5769*I1[5]-0.5769*I1[3]-0.0962*I1[1]) * (0.075*per[1]+0.54)
        # Phasor addition for 3 bar averaging ==================================
        Q2[2] = Q1[7] + jI
        I2[2] = I1[7] - jQ
        # Smooth I & Q components before applying the discriminator ============
        Q2[2] = 0.2 * Q2[2] + 0.8 * Q2[1]
        I2[2] = 0.2 * I2[2] + 0.8 * I2[1]
        # Homodyne discriminator ===============================================
        Re[2] = I2[2] * I2[1] + Q2[2]*Q2[1]
        Im[2] = I2[2] * Q2[1] - Q2[2]*I2[1]
        Re[2] = 0.2 * Re[2] + 0.8*Re[1]
        Im[2] = 0.2 * Im[2] + 0.8*Im[1]
        if (Im[2] != 0.0) & (Re[2] != 0.0)
            per[2] = 360.0/atan(Im[2]/Re[2])
        end
        if per[2] > 1.5 * per[1]
            per[2] = 1.5*per[1]
        elseif per[2] < 0.67 * per[1]
            per[2] = 0.67 * per[1]
        end
        if per[2] < 6.0
            per[2] = 6.0
        elseif per[2] > 50.0
            per[2] = 50.0
        end
        per[2] = 0.2*per[2] + 0.8*per[1]
        sper[2] = 0.33*per[2] + 0.67*sper[1]
        if I1[7] != 0.0
            phase[2] = atan(Q1[7]/I1[7])
        end
        dphase = phase[1] - phase[2]
        if dphase < 1.0
            dphase = 1.0
        end
        alpha = fastlimit / dphase
        if alpha < slowlimit
            alpha = slowlimit
        end
        out[i,1] = alpha*x[i] + (1.0-alpha)*out[i-1,1]
        out[i,2] = 0.5*alpha*out[i,1] + (1.0-0.5*alpha)*out[i-1,2]
        # Reset/increment array variables
        smooth = [smooth[2:7]; smooth[7]]
        detrend = [detrend[2:7]; detrend[7]]
        Q1 = [Q1[2:7]; Q1[7]]
        I1 = [I1[2:7]; I1[7]]
        I2[1] = I2[2]
        Q2[1] = Q2[2]
        Re[1] = Re[2]
        Im[1] = Im[2]
        per[1] = per[2]
        sper[1] = sper[2]
        phase[1] = phase[2]
    end
    out[1:32,:] = NaN
    return out
end

@doc doc"""
hma{Float64}(x::Vector{Float64}, n::Int64=20)

Hull moving average
""" ->
function hma{Float64}(x::Vector{Float64}, n::Int64=20)
    return wma(2 * wma(x, Int64(round(n/2.0))) - wma(x, n), Int64(trunc(sqrt(n))))
end

@doc doc"""
swma{Float64}(x::Vector{Float64}, n::Int64)

Sine-weighted moving average
""" ->
function swma{Float64}(x::Vector{Float64}, n::Int64=10)
    @assert n<size(x,1) && n>0 "Argument n out of bounds."
    w = sin(collect(1:n) * 180.0/6.0)  # numerator weights
    d = sum(w)  # denominator = sum(numerator weights)
    out = zeros(x)
    out[1:n-1] = NaN
    @inbounds for i = n:size(x,1)
        out[i] = sum(w .* x[i-n+1:i]) / d
    end
    return out
end

@doc doc"""
kama{Float64}(x::Vector{Float64}, n::Int64=10, nfast::Float64=0.6667, nslow::Float64=0.0645)

Kaufman adaptive moving average
""" ->
function kama{Float64}(x::Vector{Float64}, n::Int64=10, nfast::Float64=0.6667, nslow::Float64=0.0645)
    @assert n<size(x,1) && n>0 "Argument n out of bounds."
    @assert nfast>0.0 && nfast<1.0 "Argument nfast out of bounds."
    @assert nslow>0.0 && nslow<1.0 "Argument nslow out of bounds."
    dir = diffn(x, n)  # price direction := net change in price over past n periods
    vol = runsum(abs(diffn(x,1)), n, false)  # volatility/noise
    er = abs(dir) ./ vol  # efficiency ratio
    ssc = er * (nfast-nslow) + nslow  # scaled smoothing constant
    sc = ssc .^ 2  # smoothing constant
    # initiliaze result variable
    out = zeros(x)
    i = first(find(!isnan(x)))
    out[1:n+i-2] = NaN
    out[n+i-1] = mean(x[i:n+i-1])
    @inbounds for i = n+1:size(x,1)
        out[i] = out[i-1] + sc[i]*(x[i]-out[i-1])
    end
    return out
end

@doc doc"""
alma{Float64}(x::Vector{Float64}, n::Int64=9, offset::Float64=0.85, sigma::Float64=6.0)

Arnaud-Legoux moving average
""" ->
function alma{Float64}(x::Vector{Float64}, n::Int64=9, offset::Float64=0.85, sigma::Float64=6.0)
    @assert n<size(x,1) && n>0 "Argument n out of bounds."
    @assert sigma>0.0 "Argument sigma must be greater than 0."
    @assert offset>=0.0 && offset<=1 "Argument offset must be in (0,1)."
    out = zeros(x)
    out[1:n-1] = NaN
    m = floor(offset*(float(n)-1.0))
    s = float(n) / sigma
    w = exp(-(((0.0:-1.0:-float(n)+1.0)-m).^2.0) / (2.0*s*s))
    wsum = sum(w)
    if wsum != 0.0
        w = w ./ wsum
    end
    @inbounds for i = n:length(x)
        out[i] = sum(x[i-n+1] .* w)
    end
    return out
end


text:
using Documenter, NeuralPDE

makedocs(
    sitename="NeuralPDE.jl",
    authors="#",
    clean=true,
    doctest=false,
    modules=[NeuralPDE],

    format=Documenter.HTML(# analytics = "",
                             assets=["assets/favicon.ico"],
                             canonical="#"),
    pages=[
        "NeuralPDE.jl: Scientific Machine Learning (SciML) for Partial Differential Equations" => "index.md",
        "Physics-Informed Neural Network Tutorials" => Any[
            "pinn/poisson.md",
            "pinn/wave.md",
            "pinn/3D.md",
            "pinn/system.md",
            "pinn/3rd.md",
            "pinn/low_level.md",
            "pinn/ks.md",
            "pinn/fp.md",
            "pinn/debugging.md",
        ],
        "Specialized Neural PDE Tutorials" => Any[
            "examples/100_HJB.md",
            "examples/blackscholes.md",
            "examples/kolmogorovbackwards.md",
            "examples/optimal_stopping_american.md",
        ],
        "Specialized Neural ODE Tutorials" => Any[
            "examples/ode.md",
            "examples/nnrode_example.md",
        ],
        "API Documentation" => Any[
            "solvers/pinns.md",
            "solvers/deep_fbsde.md",
            "solvers/kolmogorovbackwards_solver.md",
            "solvers/optimal_stopping.md",#TODO
            "solvers/ode.md",
            "solvers/nnrode.md",#TODO
        ]
    ]
)

deploydocs(
   repo="github.com/SciML/NeuralPDE.jl.git";
   push_preview=true
)