text:
module ComposeDiff

using Patchwork
using Measures
using Compose
using Reactive
using Compat
using Colors

export Patchable

import Compose:
    Backend,
    draw,
    isrepeatable,
    isscalar,
    svg_fmt_color,
    default_stroke_color,
    default_line_width,
    default_fill_color,
    default_font_size,
    default_graphic_width,
    default_graphic_height,
    default_graphic_format,
    default_jsmode,
    push_property_frame,
    pop_property_frame,
    print_svg_path,
    svg_fmt_float,
    svg_print_path_op,
    svg_fmt_linecap,
    svg_fmt_linejoin,
    size_measure,
    ComposeNode,
    Form,
    Property,
    BitmapPrimitive,
    CirclePrimitive,
    ClipPrimitive,
    ComplexPolygonPrimitive,
    CurvePrimitive,
    EllipsePrimitive,
    FillOpacityPrimitive,
    FillPrimitive,
    FontPrimitive,
    FontSizePrimitive,
    JSCallPrimitive,
    JSIncludePrimitive,
    LinePrimitive,
    LineWidthPrimitive,
    PathPrimitive,
    PolygonPrimitive,
    PropertyPrimitive,
    RectanglePrimitive,
    StrokeDashPrimitive,
    StrokeLineCapPrimitive,
    StrokeLineJoinPrimitive,
    StrokeOpacityPrimitive,
    StrokePrimitive,
    SVGAttributePrimitive,
    SVGClassPrimitive,
    SVGIDPrimitive,
    TextPrimitive,
    Transform,
    VisiblePrimitive

# The Patchable backend

import Patchwork.Elem

type Patchable <: Backend
    width::Length{:mm}
    height::Length{:mm}

    jsheader::Vector{AbstractString}
    jsmodules::Vector{(@compat Tuple{AbstractString, AbstractString})}
    clip_paths::Dict{ClipPrimitive, AbstractString}
    parent_stack::Vector
    property_stack::Vector
    function Patchable(width, height)
        width = size_measure(width)
        height = size_measure(height)
        new(
            width,
            height,
            AbstractString[],
            (@compat Tuple{AbstractString, AbstractString})[],
            Dict{ClipPrimitive, AbstractString}(),
            Elem[Elem(:svg, :svg)],
            Any[])
    end
end
# Redraw everytime
Compose.isfinished(backend::Patchable) = false

vector_properties(img::Patchable) = if !isempty(img.property_stack)
    img.property_stack[end].vector_properties
end

immutable PatchablePropertyFrame
    has_scalar_properties::Bool
    vector_properties::Dict
end

function Compose.push_property_frame(img::Patchable, properties)
    applied_properties = Set{Type}() # Don't double apply the same property
    scalar_properties = Array(Property, 0)
    vector_props = Dict()
    for property in properties
        if !isrepeatable(property) && (typeof(property) in applied_properties)
            continue
        elseif isscalar(property)
            push!(scalar_properties, property)
            push!(applied_properties, typeof(property))
        else
            vector_props[typeof(property)] = property
        end
    end
    push!(img.property_stack, PatchablePropertyFrame(!isempty(scalar_properties), vector_props))
    if isempty(scalar_properties)
        return
    end
    # TODO: current_id???

    props = Dict()
    for p in scalar_properties
        draw!(img, p.primitives[1], props)
    end
    push!(img.parent_stack, Elem(:svg, :g) & props)
end

function pop_property_frame(img::Patchable)
    frame = pop!(img.property_stack)
    if frame.has_scalar_properties
        last = pop!(img.parent_stack)
        img.parent_stack[end] <<= last
    end
end

Compose.iswithjs(::Patchable) = false
Compose.iswithousjs(::Patchable) = true

clip_path_id(img, path) =
   if (haskey(img.clip_paths, path))
       return img.clip_paths[path]
   else
       id = string("clippath-", length(img.clip_paths) + 1)
       img.clip_paths[path] = id
       return id
   end

# Specialize absolute form drawing method for Patchwork backend
function draw(backend::Patchable, box::AbsoluteBox, units::UnitBox, t::Transform,
              form::Form)
    absform = Form([resolve(box, units, t, primitive)
                  for primitive in form.primitives])
    backend.parent_stack[end] <<= draw(backend, absform)
end

function Compose.finish(img::Patchable)
    root = img.parent_stack[end]
    @assert isa(root, Elem{:svg, :svg})
    root &= @compat Dict(
        :width=>string(img.width),
        :height=>string(img.height),
        :viewBox=>string("0 0 ", img.width.value, ' ', img.height.value),
        :stroke=>svg_fmt_color(default_stroke_color),
        :fill=>svg_fmt_color(default_fill_color)
    )

    root &= @compat Dict("stroke-width" => svg_fmt_float(default_line_width.value),
                 "font-size" => svg_fmt_float(default_font_size.value))
    if !isempty(img.clip_paths)
        defs = Elem(:svg, :defs)
        for (path, id) in img.clip_paths
            defs <<= Elem(:svg, :clipPath,
                          Elem(:svg, :path, d=svg_fmt_path(path.points)),
                          id=id)
        end
        root = root << defs
    end
    img.parent_stack[end] = Elem(:svg, :svg)
    root
end

Compose.root_box(img::Patchable) =
    BoundingBox(0.0mm, 0.0mm, img.width, img.height)

init_context(::Patchable, ::Context) = Elem(:svg, :g)

typealias SVGPart @compat(Union{Elem, Dict, (@compat Void)})

function properties_at_index(img, prop_vecs, i)
    props = Dict()
    for (proptype, property) in prop_vecs
        if i > length(property.primitives)
            error("Vector of properties and vector of forms have different length")
        end
        draw!(img, property.primitives[i], props)
    end
    props
end

# Form Drawing
# ------------

function draw(img::Patchable, form::Form)
    acc = Array(Any, length(form.primitives))
    properties = vector_properties(img)

    for i in 1:length(form.primitives)
        elem = draw(img, form.primitives[i])
        if properties !== nothing && !isempty(properties)
            props = properties_at_index(img, properties, i)
            elem &= props
        end
        acc[i] = elem
    end
    img.parent_stack[end] <<= filter(x -> x != nothing, acc)
    acc
end

function draw(img::Patchable, prim::BitmapPrimitive)
    warn("Patchable backend does not yet support bitmap primitives")
    nothing
end

draw(img::Patchable, prim::CirclePrimitive) =
    Elem(:svg, :circle,
         cx=prim.center[1].value,
         cy=prim.center[2].value,
         r=prim.radius.value)

draw(img::Patchable, prim::CurvePrimitive) =
    Elem(:svg, :path,
         fill="none",
         path=string("M"
                     , prim.anchor0[1].value, ','
                     , prim.anchor0[2].value, "C"
                     , prim.ctrl0[1].value, ','
                     , prim.ctrl0[2].value, ' '
                     , prim.ctrl1[1].value, ','
                     , prim.ctrl1[2].value, ' '
                     , prim.anchor1[1].value, ','
                     , prim.anchor1[2].value))

function draw(img::Patchable, prim::EllipsePrimitive)
    cx = prim.center[1].value
    cy = prim.center[2].value
    rx = sqrt((prim.x_point[1].value - cx)^2 +
              (prim.x_point[2].value - cy)^2)
    ry = sqrt((prim.y_point[1].value - cx)^2 +
              (prim.y_point[2].value - cy)^2)
    theta = rad2deg(atan2(prim.x_point[2].value - cy,
                          prim.x_point[1].value - cx))

    if !all(isfinite([cx, cy, rx, ry, theta]))
        return nothing
    end
    el = Elem(:svg, :ellipse,
              cx=cx, cy=cy, rx=rx, ry=ry)
    if abs(theta) > 1e-4
        el = el & @compat Dict(:transform => string("rotate(",
                                        svg_fmt_float(theta), ' ',
                                        svg_fmt_float(cx), ' ',
                                        svg_fmt_float(cy), ')'))
    end
    el
end

function svg_fmt_path(points::Vector, bridge_gaps::Bool=false)
    io=IOBuffer()
    print_svg_path(io, points, bridge_gaps)
    takebuf_string(io)
end

function draw(img::Patchable, prim::LinePrimitive)
    n = length(prim.points)
    if n <= 1; return; end

    Elem(:svg, :path, fill="none", d=svg_fmt_path(prim.points, true))
end

function svg_fmt_path_ops(ops)
    io = IOBuffer()
    for op in ops
        svg_print_path_op(io, op)
    end
    takebuf_string(io)
end

draw(img::Patchable, prim::PathPrimitive) =
    Elem(:svg, :path, d=svg_fmt_path_ops(prim.ops))

function draw(img::Patchable, prim::PolygonPrimitive)
     n = length(prim.points)
     if n <= 1; return; end

     Elem(:svg, :path, d=svg_fmt_path(prim.points, true) * " z")
end

function draw(img::Patchable, prim::ComplexPolygonPrimitive)
    Elem(:svg, :path, d=join(map(r -> svg_fmt_path(r, true), prim.rings), "") * " z")
end

function draw(img::Patchable, prim::RectanglePrimitive)
    width = max(prim.width.value, 0.01)
    height = max(prim.height.value, 0.01)

    Elem(:svg, :rect,
         x=prim.corner[1].value,
         y=prim.corner[2].value,
         width=width,
         height=height)
end

function draw(img::Patchable, prim::TextPrimitive)
    el = pango_to_elems(prim.value) & @compat Dict(
            :x=>prim.position[1].value,
            :y=>prim.position[2].value)
    if is(prim.halign, hcenter)
        el &= @compat Dict("text-anchor" => "middle")
    elseif is(prim.halign, hright)
        el &= @compat Dict("text-anchor" => "end")
    end
    if is(prim.valign, vcenter)
        el &= @compat Dict(:dy=>"0.35em")
    elseif is(prim.halign, vtop)
        el &= @compat Dict(:dy=>"0.6mm")
    end

    if abs(prim.rot.theta) > 1e-4
        el &= @compat Dict(:transform => string("rotate(",
                                     rad2deg(prim.rot.theta), ' ',
                                     svg_fmt_float(prim.rot.offset[1].value), ' ',
                                     svg_fmt_float(prim.rot.offset[2].value), ')'))
     end
     el

end

# Property Primitives
# -------------------
function draw(img::Patchable, prop::Property)
    dict = Dict()
    for prim in prop.primitives
        draw!(img, prim, dict)
    end
    dict
end

function draw!(img::Patchable, prim::PropertyPrimitive, dict)
    item = draw(img, prim)
    if !is(item, nothing)
        k, v = item

        dict[k] = v
    end
end

function draw(img::Patchable, prim::ClipPrimitive)
    id = clip_path_id(img, prim)
    "clip-path", "url(#$id)"
end

draw(img::Patchable, prim::FillOpacityPrimitive) =
    :opacity, prim.value

function draw!(img::Patchable, prim::FillPrimitive, props)
    if isa(prim.color, TransparentColor)
        props[:fill] = svg_fmt_color(color(prim.color))
        props["fill-opacity"] = prim.color.alpha
    elseif isa(prim.color, Color)
        props[:fill] = svg_fmt_color(prim.color)
    else
        props[:fill] = "none"
    end
end

draw(img::Patchable, prim::FontPrimitive) =
    "font-family", escape_string(prim.family)

draw(img::Patchable, prim::FontSizePrimitive) =
    "font-size", prim.value.value

function draw(img::Patchable, prim::JSCallPrimitive)
    nothing
end

function draw(img::Patchable, prim::JSIncludePrimitive)
    push!(img.jsheader, prim.value)
    if prim.jsmodule != nothing
        push!(img.jsmodules, prim.jsmodule)
    end
    nothing
end

draw(img::Patchable, prim::LineWidthPrimitive) =
    "stroke-width", prim.value.value

draw(img::Patchable, prim::SVGAttributePrimitive) = nothing
    #prim.attribute, escape_string(prim.value)

draw(img::Patchable, prim::SVGClassPrimitive) =
    :class, escape_string(prim.value)

draw(img::Patchable, prim::SVGIDPrimitive) =
    :id, escape_string(prim.value)

function draw(img::Patchable, prim::StrokeDashPrimitive)
    if isempty(prim.value)
        "stroke-dasharray", :none
    else
        "stroke-dasharray", join([v.value for v in prim.value], ',')
    end
end

draw(img::Patchable, prim::StrokeLineCapPrimitive) =
    "stroke-linecap", svg_fmt_linecap(prim.value)

draw(img::Patchable, prim::StrokeLineJoinPrimitive) =
    "stroke-linejoin", svg_fmt_linejoin(prim.value)

draw(img::Patchable, prim::StrokeOpacityPrimitive) =
    "stroke-opacity", prim.value

function draw!(img::Patchable, prim::StrokePrimitive, dict)
    if isa(prim.color, TransparentColor)
        dict[:stroke] = svg_fmt_color(color(prim.color))
        dict["stroke-opacity"] = prim.color.alpha
    else
        dict[:stroke] = svg_fmt_color(prim.color)
    end
end

draw(img::Patchable, prim::VisiblePrimitive) =
    :visibility, prim.value ? "visible" : "hidden"

# Pango markup to Patchwork
function pango_to_elems(text::AbstractString)
    pat = r"<(/?)\s*([^>]*)\s*>"
    input = text
    output = Elem[Elem(:svg, :text)] # Stack
    lastpos = 1

    baseline_shift = 0.0
    open_tag = false

    for mat in eachmatch(pat, text)
        txt = input[lastpos:mat.offset-1]
        if length(txt) > 0
            output[end] <<= Patchwork.TextNode(txt)
        end

        closing_tag = mat.captures[1] == "/"

        if open_tag && !closing_tag
            el = pop!(output)
            output[end] <<= el
        end

        if mat.captures[2] == "sup"
            if mat.captures[1] == "/"
                el = pop!(output)
                output[end] <<= el
            else
                el = Elem(:svg, :tspan,
                         style=(@compat Dict("dominant-baseline" => :inherit)),
                         dy="-0.6em") & @compat Dict("font-size" => "83%")
                push!(output, el)
                baseline_shift = -0.6 * 0.83
            end
        elseif mat.captures[2] == "sub"
            if mat.captures[1] == "/"
                el = pop!(output)
                output[end] <<= el
            else
                el = Elem(:svg, :tspan,
                          style=(@compat Dict("dominant-baseline" => :inherit)),
                          dy="0.6em") & @compat Dict("font-size" => "83%")
                push!(output, el)
                baseline_shift = 0.6 * 0.83
            end
        elseif mat.captures[2] == "i"
            if mat.captures[1] == "/"
                el = pop!(output)
                output[end] <<= el
            else
                el = Elem(:svg, :tspan,
                          style = @compat Dict("dominant-baseline" => :inherit)) &
                                    @compat Dict("font-style"=>"italic")
                push!(output, el)
            end
        elseif mat.captures[2] == "b"
            if mat.captures[1] == "/"
                el = pop!(output)
                output[end] <<= el
            else
                el = Elem(:svg, :tspan,
                          style=@compat Dict("dominant-baseline" => :inherit)) &
                                    @compat Dict("font-style"=>"bold")
                push!(output, el)
            end
        end

        if closing_tag && baseline_shift != 0.0
            el = Elem(:svg, :tspan,
                      dy="$(-baseline_shift)em")
            push!(output, el)
            baseline_shift = 0.0
            open_tag = true
        end

        lastpos = mat.offset + length(mat.match)
    end
    txt = input[lastpos:end]
    if length(txt) > 0
        output[end] <<= Patchwork.TextNode(string(txt))
    end
    if open_tag
        el = pop!(output)
        output[end] <<= el
    end
    output[1]
end

# writemime for signals

@compat function Base.show{T <: ComposeNode}(io::IO, m::MIME"text/html", ctx::Signal{T})
    Base.show(io, m, map(c -> draw(
        Patchable(
            Compose.default_graphic_width,
            Compose.default_graphic_height
        ), c), ctx))
end

using Requires

@require IJulia begin
    IJulia.metadata{T <: ComposeNode}(::Signal{T}) = Dict()
end

function __init__()
    for f in Requires.__inits__
        f()
    end
end
end


text:
import Random: randn
import JSON: json

# CIR process with parameters (a, b, σ, X_0) = (1.2, 3.1, 0.5, 2.2)
a = 1.2
b = 3.1
sigma = 0.5
x0 = 2.2

# generate samples
T = 10.0
times = LinRange(0.0, T, 2501)
count = 100
trajectories = zeros(length(times), count)
normals = randn(length(times)-1, count)
for i in 1:count
  trajectories[1,i] = x0
  for k in 2:length(times)
    dt = times[k] - times[k-1]
    dw = normals[k-1, i] * sqrt(dt)
    x = trajectories[k-1,i]
    trajectories[k,i] = x + a * (b - x) * dt + sigma * sqrt(abs(x)) * dw
  end
end

# export to json
write(
  "data.json",
  json(Dict(
    :a => a,
    :b => b,
    :sigma => sigma,
    :samples => map(
      i -> map(
        ((x, t), ) -> Dict(:xt => x, :t => t, :sample => i),
        zip(trajectories[:,i], times)
      ),
      1:count
    )
  ))
)

ext: jl

max_stars_repo_name: mvarble/matthew-varble-site

max_issues_repo_name: mvarble/matthew-varble-site

max_forks_repo_name: mvarble/matthew-varble-site


text:
function warmup!(spins::Config, M::Model, N::Int)
    for _ in 1:N
        metro!(spins, M)
    end
end

function mc(spins::Config, M::Model, Obs::Thermo, Grad::Gradient, N::Int, Sto::StochasticMatrix)
    for _ in 1:N
        for _ in 1:5
            metro!(spins, M)
        end
        update_thermo!(Obs, spins.config, M, N, Grad)
    end
    update_grad!(Grad, Obs, M, N)
    # update_smatrix!(Sto, M, Obs)
    return Obs.E.E, Grad.∇E, Obs.mag, Sto.Sinv*Grad.∇E[:total]
end


text:
RpcApi.SimpleOrganism[RpcApi.SimpleOrganism(0x000000000001d2d0,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,68,99,31,13,1,97,22],51.0772,0,53.778,198059,0x00000064,Dict{Int16,Int16}(),[362,288],31210,50,5),RpcApi.SimpleOrganism(0x000000000001d170,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_2::String = "7EtVWHst"
        local var_1::Int8 = 110
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[96,88,31,44,64,0,7,0,75,22],11.6968,0,70.8924,192192,0x00000064,Dict{Int16,Int16}(),[1301,498],34860,50,7),RpcApi.SimpleOrganism(0x000000000001d3da,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        if var_1 == var_1
        end
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,68,99,31,13,1,97,22],73.8115,0,90.7483,180757,0x00000064,Dict{Int16,Int16}(),[360,287],28459,4,6),RpcApi.SimpleOrganism(0x000000000001c985,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.stepRight(o)
        Creature.eatRight(c,o,Int(var_1))
        Creature.stepRight(o)
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        return true
    end),[77,17,83,14,46,14,47,8,3,52],14.2438,0,95.6447,177594,0x0000006b,Dict{Int16,Int16}(),[1886,248],55889,50,6),RpcApi.SimpleOrganism(0x000000000001da56,:(function (c::Config.ConfigData,o::Creature.Organism)
        function func_6(var_3::Bool=false,var_4::Bool=true,var_5::Bool=true)
            return var_3
        end
        local var_1::Int8 = 110
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        var_1 = if 127 >= abs(-2578)
                Int8(-2578)
            else
                127
            end
        Creature.eatLeft(c,o,Int(var_1))
        var_2 = string(2127027164213426971)
        var_1 = (Int8)(var_1) & (Int8)(var_1)
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[34,9,19,50,2,6,13,1,93,22],47.4722,0,30.8516,161016,0x00000064,Dict{Int16,Int16}(),[475,545],11217,5,13),RpcApi.SimpleOrganism(0x000000000001dc52,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.stepRight(o)
        if var_1 == var_1
        end
        var_1 = if 127 >= abs(1656)
                Int8(1656)
            else
                127
            end
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[57,56,8,9,93,9,55,17,0,60],1.26433,0,57.0324,137412,0x0000006b,Dict{Int16,Int16}(),[1278,339],5909,50,7),RpcApi.SimpleOrganism(0x000000000001d740,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,68,99,31,13,1,97,22],18.4044,0,1.71987,137008,0x00000064,Dict{Int16,Int16}(),[363,287],19371,50,5),RpcApi.SimpleOrganism(0x000000000001d0c6,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        if var_1 == var_1
        end
        Creature.stepRight(o)
        var_1 = if 127 >= abs(1656)
                Int8(1656)
            else
                127
            end
        Creature.eatDown(c,o,Int(var_1))
        return true
    end),[49,54,79,5,62,2,85,31,7,75],68.1664,0,76.3901,134826,0x0000006b,Dict{Int16,Int16}(),[272,239],36652,50,8),RpcApi.SimpleOrganism(0x000000000001d1a4,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        if var_1 == var_1
        end
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,68,99,31,13,1,97,22],39.8877,0,79.62,133571,0x00000064,Dict{Int16,Int16}(),[367,286],34288,50,6),RpcApi.SimpleOrganism(0x000000000001dc5a,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.stepRight(o)
        if var_1 == var_1
        end
        Creature.eatLeft(c,o,Int(var_1))
        var_1 = var_1 + var_1
        return true
    end),[30,40,98,34,63,0,22,2,95,93],26.7835,0,12.3085,129753,0x0000006b,Dict{Int16,Int16}(),[1334,158],5830,50,8),RpcApi.SimpleOrganism(0x000000000001ce07,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        var_1 = if 127 >= abs(8341)
                Int8(8341)
            else
                127
            end
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,32,42,31,13,1,53,22],60.2455,0,23.3344,125548,0x00000064,Dict{Int16,Int16}(),[770,299],43883,50,6),RpcApi.SimpleOrganism(0x000000000001d807,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_2::String = "7EtVWHst"
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[33,88,59,57,52,12,7,50,71,9],28.8939,0,92.29,121682,0x00000064,Dict{Int16,Int16}(),[1304,487],17339,12,8),RpcApi.SimpleOrganism(0x000000000001d9b9,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        Creature.stepRight(o)
        Creature.stepLeft(o)
        var_1 = var_1 * var_1
        Creature.stepLeft(o)
        return true
    end),[77,17,9,62,46,14,47,8,40,52],99.1215,0,63.181,121021,0x0000006b,Dict{Int16,Int16}(),[875,250],12847,3,7),RpcApi.SimpleOrganism(0x000000000001d4ab,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_2::String = "7EtVWHst"
        local var_1::Int8 = 110
        Creature.eatDown(c,o,Int(var_1))
        var_1 = if 127 >= abs(-20933)
                Int8(-20933)
            else
                127
            end
        Creature.eatLeft(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[58,0,6,6,47,11,63,4,0,74],11.7862,0,28.8966,115739,0x00000064,Dict{Int16,Int16}(),[526,119],26297,50,9),RpcApi.SimpleOrganism(0x000000000001da9d,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_3::Bool = true
        local var_1::Int8 = 110
        Creature.eatDown(c,o,Int(var_1))
        var_3 = var_3 & var_3
        for i::Int8 = 1:div(var_1,16)
            local var_4::String = "kZOFNBlk"
            var_4 = string(var_4)
        end
        var_3 = 0.53739 > (Float64)(0)
        Creature.eatUp(c,o,Int(var_1))
        for i::Int8 = 1:div(var_1,16)
        end
        var_3 = Creature.stepDown(o)
        var_3 = Creature.stepDown(o)
        var_3 = 0.202637 > (Float64)(0)
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        return true
    end),[50,50,8,77,18,4,13,1,34,22],36.8979,1000,4.53023,113540,0x00000064,Dict{Int16,Int16}(),[696,545],10489,50,18),RpcApi.SimpleOrganism(0x000000000001ddd4,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatDown(c,o,Int(var_1))
        if var_1 == var_1
        end
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,29,99,31,13,1,97,22],58.1774,826,49.6924,113455,0x00000064,Dict{Int16,Int16}(),[367,284],1893,18,6),RpcApi.SimpleOrganism(0x000000000001d931,:(function (c::Config.ConfigData,o::Creature.Organism)
        function func_6(var_3::Bool=false,var_4::Bool=true,var_5::Bool=true)
            return var_3
        end
        local var_1::Int8 = 110
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        var_1 = if 127 >= abs(-2578)
                Int8(-2578)
            else
                127
            end
        Creature.eatLeft(c,o,Int(var_1))
        var_2 = string(2127027164213426971)
        var_1 = (Int8)(var_1) & (Int8)(var_1)
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[34,9,19,50,2,6,13,1,93,22],47.4722,0,30.8516,111462,0x00000064,Dict{Int16,Int16}(),[474,544],14268,63,13),RpcApi.SimpleOrganism(0x000000000001d927,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        if var_1 == var_1
        end
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,68,51,31,13,1,97,22],17.0854,0,30.2627,109201,0x00000064,Dict{Int16,Int16}(),[357,295],14388,50,6),RpcApi.SimpleOrganism(0x000000000001db6c,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        if var_1 == var_1
        end
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,29,99,31,13,1,97,22],19.8493,0,79.62,102604,0x00000064,Dict{Int16,Int16}(),[364,285],8359,50,6),RpcApi.SimpleOrganism(0x000000000001dd81,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        var_1 = (Int8)(var_1) & (Int8)(var_1)
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        for i::Int8 = 1:div(var_1,16)
        end
        for i::Int8 = 1:div(var_1,16)
        end
        Creature.stepRight(o)
        Creature.eatRight(c,o,Int(var_1))
        return true
    end),[57,50,27,73,35,4,13,1,19,88],51.8079,496,18.5475,96952,0x00000068,Dict{Int16,Int16}(),[1644,259],2730,50,11),RpcApi.SimpleOrganism(0x000000000001dd29,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_2::String = "7EtVWHst"
        local var_1::Int8 = 110
        Creature.eatDown(c,o,Int(var_1))
        var_1 = if 127 >= abs(-20933)
                Int8(-20933)
            else
                127
            end
        Creature.eatLeft(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[58,0,6,6,47,11,63,4,0,74],11.7862,0,28.8966,95933,0x00000064,Dict{Int16,Int16}(),[527,120],3680,50,9),RpcApi.SimpleOrganism(0x000000000001d637,:(function (c::Config.ConfigData,o::Creature.Organism)
        var_1 = if 127 >= abs(8341)
                Int8(8341)
            else
                127
            end
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,32,42,31,13,1,53,22],74.2868,0,23.3344,94827,0x00000064,Dict{Int16,Int16}(),[771,298],22189,50,5),RpcApi.SimpleOrganism(0x000000000001c8c3,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_7::Int16 = 24852
        local var_6::String = "tSZopcEp"
        function func_5(var_3::Int8=28,var_4::String="EhGjwuQE")
            return var_3
        end
        local var_1::Int8 = 110
        Creature.eatDown(c,o,Int(var_1))
        var_7 = Int16(o.pos.x)
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        var_2 = string(2127027164213426971)
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[30,55,61,75,57,99,13,0,77,99],1.95542,0,95.2151,94110,0x00000064,Dict{Int16,Int16}(),[451,528],57929,50,11),RpcApi.SimpleOrganism(0x000000000001c82c,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        for i::Int8 = 1:div(var_1,16)
        end
        var_2 = string(2127027164213426971)
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[34,9,8,50,2,6,13,1,93,22],47.4722,0,33.9213,93380,0x00000064,Dict{Int16,Int16}(),[470,552],59541,12,10),RpcApi.SimpleOrganism(0x000000000001d00c,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_2::String = "7EtVWHst"
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[33,88,59,57,52,12,7,67,71,9],28.7747,0,92.29,92723,0x00000064,Dict{Int16,Int16}(),[1302,485],38580,18,8),RpcApi.SimpleOrganism(0x000000000001cf8f,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_2::Int64 = -3564079828176992738
        local var_1::Int8 = 110
        Creature.stepRight(o)
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.stepRight(o)
        if var_1 == var_1
        end
        Creature.eatRight(c,o,Int(var_1))
        return true
    end),[85,91,97,47,20,89,34,70,4,2],11.4278,0,69.5899,91651,0x0000006b,Dict{Int16,Int16}(),[1360,213],39899,50,8),RpcApi.SimpleOrganism(0x000000000001cda5,:(function (c::Config.ConfigData,o::Creature.Organism)
        var_1 = if 127 >= abs(8341)
                Int8(8341)
            else
                127
            end
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,75,32,42,31,13,1,53,22],12.512,0,23.3344,91351,0x00000064,Dict{Int16,Int16}(),[756,291],44920,50,5),RpcApi.SimpleOrganism(0x000000000001d323,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_2::String = "7EtVWHst"
        local var_1::Int8 = 110
        Creature.eatLeft(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        return true
    end),[96,88,2,44,64,0,7,12,75,22],47.0338,0,70.8924,90708,0x00000064,Dict{Int16,Int16}(),[1310,495],30370,6,8),RpcApi.SimpleOrganism(0x000000000001d32c,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        var_1 = var_1 + var_1
        var_1 = var_1 % if var_1 === (Int8)(0)
                    (Int8)(1)
                else
                    var_1
                end
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,8,68,42,6,13,1,33,22],95.5164,0,51.0791,88444,0x00000064,Dict{Int16,Int16}(),[619,316],30278,50,6),RpcApi.SimpleOrganism(0x000000000001d714,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        if var_1 == var_1
            Creature.stepDown(o)
        end
        Creature.stepDown(o)
        Creature.stepDown(o)
        Creature.eatDown(c,o,Int(var_1))
        return true
    end),[96,80,29,39,48,3,28,32,5,61],24.8539,0,89.6098,88207,0x0000006b,Dict{Int16,Int16}(),[552,475],19839,50,9),RpcApi.SimpleOrganism(0x000000000001db73,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        var_1 = if 127 >= abs(8341)
                Int8(8341)
            else
                127
            end
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,32,42,31,13,1,53,22],12.5482,0,23.3344,87775,0x00000064,Dict{Int16,Int16}(),[770,300],8277,50,6),RpcApi.SimpleOrganism(0x000000000001ddb2,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        var_1 = if 127 >= abs(8341)
                Int8(8341)
            else
                127
            end
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,32,42,31,13,1,53,22],9.68563,0,54.5651,87379,0x00000064,Dict{Int16,Int16}(),[763,295],2232,26,6),RpcApi.SimpleOrganism(0x000000000001dd8f,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_2::String = "7EtVWHst"
        local var_1::Int8 = 110
        Creature.eatLeft(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        return true
    end),[96,88,2,70,64,0,7,12,75,22],10.446,0,70.8924,87172,0x00000064,Dict{Int16,Int16}(),[1306,498],2590,46,8),RpcApi.SimpleOrganism(0x000000000001d956,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_2::String = "7EtVWHst"
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[33,88,59,57,52,12,7,67,71,9],28.7747,0,92.29,87154,0x00000064,Dict{Int16,Int16}(),[1301,486],13878,8,8),RpcApi.SimpleOrganism(0x000000000001de11,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.stepRight(o)
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        if var_1 == var_1
        end
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        return true
    end),[12,73,81,1,99,1,64,14,12,17],49.0811,0,16.1015,86691,0x0000006b,Dict{Int16,Int16}(),[424,204],1249,50,7),RpcApi.SimpleOrganism(0x000000000001d29c,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        if var_1 == var_1
        end
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,68,99,31,13,1,97,22],32.0212,0,99.5572,86146,0x00000064,Dict{Int16,Int16}(),[371,287],31757,3,6),RpcApi.SimpleOrganism(0x000000000001dd72,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_3::Bool = true
        local var_1::Int8 = 110
        Creature.eatDown(c,o,Int(var_1))
        var_3 = (Bool)(var_3) & (Bool)(var_3)
        var_3 = var_3 & var_3
        for i::Int8 = 1:div(var_1,16)
            local var_4::String = "kZOFNBlk"
        end
        var_3 = 0.53739 > (Float64)(0)
        Creature.eatUp(c,o,Int(var_1))
        for i::Int8 = 1:div(var_1,16)
            local var_5::Int8 = 111
        end
        var_3 = Creature.stepDown(o)
        var_3 = Creature.stepDown(o)
        var_3 = 0.202637 > (Float64)(0)
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatLeft(c,o,Int(var_1))
        return true
    end),[50,50,8,77,18,4,13,1,34,22],81.4134,756,16.3256,85912,0x00000064,Dict{Int16,Int16}(),[699,559],2891,27,19),RpcApi.SimpleOrganism(0x000000000001dd30,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_2::String = "7EtVWHst"
        local var_1::Int8 = 110
        var_1 = (Int8)(var_1) & (Int8)(var_1)
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        var_1 = var_1 * var_1
        var_1 = if 127 >= abs(var_1)
                Int8(var_1)
            else
                127
            end
        var_1 = if 127 >= abs(var_1)
                Int8(var_1)
            else
                127
            end
        for i::Int8 = 1:div(var_1,16)
            Creature.stepRight(o)
        end
        var_2 = var_2 * var_2
        Creature.eatLeft(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.stepLeft(o)
        Creature.eatUp(c,o,Int(var_1))
        Creature.stepLeft(o)
        return true
    end),[42,67,8,68,18,31,13,1,53,49],46.1729,515,91.2255,83349,0x00000065,Dict{Int16,Int16}(),[1835,683],3610,93,16),RpcApi.SimpleOrganism(0x000000000001dcd5,:(function (c::Config.ConfigData,o::Creature.Organism)
        function func_3(var_2::Int64=-968603455197263991)
            return var_2
        end
        local var_1::Int8 = 110
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.stepRight(o)
        if var_1 == var_1
            Creature.stepLeft(o)
        end
        Creature.eatLeft(c,o,Int(var_1))
        var_1 = if 127 >= abs(1656)
                Int8(1656)
            else
                127
            end
        Creature.stepDown(o)
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        Creature.eatRight(c,o,Int(var_1))
        return true
    end),[21,58,12,76,49,2,36,33,82,4],93.635,0,86.1215,83266,0x0000006b,Dict{Int16,Int16}(),[1139,545],4550,15,13),RpcApi.SimpleOrganism(0x000000000001d8a3,:(function (c::Config.ConfigData,o::Creature.Organism)
        local var_1::Int8 = 110
        Creature.eatUp(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatDown(c,o,Int(var_1))
        Creature.eatUp(c,o,Int(var_1))
        return true
    end),[4,67,46,68,42,31,13,1,53,22],5.3974,0,81.7843,82664,0x00000064,Dict{Int16,Int16}(),[754,292],15719,27,5)]

max_stars_repo_name: tmptrash/jevo

max_issues_repo_name: tmptrash/jevo

max_forks_repo_name: tmptrash/jevo


text:
"""
```
average_update(new::AbstractArray{S}, old::AbstractArray{S}, learning_rate::S) where {S <: Real}
```

updates `old` with `new` by taking a weighted average according to `learning_rate`.
"""
@inline function average_update(new::AbstractArray{S}, old::AbstractArray{S}, learning_rate::S) where {S <: Real}
    return learning_rate .* new + (1 - learning_rate) .* old
end

"""
```
function calculate_func_error(new_funcvar::OrderedDict, old_funcvar::OrderedDict, error_method::Symbol;
    vars::Vector{Symbol} = collect(keys(old_funcvar)))

function calculate_func_error(new_funcvar::AbstractArray{S}, old_funcvar::AbstractArray{S}, error_method::Symbol) where {S <: Real}
```

calculates the error between the proposal and the current guesses
for the functional variables. The keyword `vars` for the first method indicates which variables
we want to use to calculate the error (as sometimes, we want to ignore certain ones).
"""
@inline function calculate_func_error(new_funcvar::OrderedDict, old_funcvar::OrderedDict, error_method::Symbol;
                                      vars::Vector{Symbol} = collect(keys(old_funcvar)))

    if length(vars) == length(old_funcvar)
        new_vals = values(new_funcvar)
        old_vals = values(old_funcvar)
    else
        new_vals = map(x -> new_funcvar[x], vars)
        old_vals = map(x -> old_funcvar[x], vars)
    end

    func_error = if error_method == :total_error
        sum([sum(abs.(v1 - v2)) for (v1, v2)
             in zip(new_vals, old_vals)])
    elseif error_method in [:L∞, :Linf, :max_abs_error, :maximum_absolute_error]
        maximum([maximum(abs.(v1 - v2)) for (v1, v2)
                 in zip(new_vals, old_vals)])
    elseif error_method in [:L², :L2, :squared_error]
        sum([sum((v1 - v2) .^ 2) for (v1, v2)
             in zip(new_vals, old_vals)])
    end

    return func_error
end

@inline function calculate_func_error(new_funcvar::AbstractArray{S}, old_funcvar::AbstractArray{S}, error_method::Symbol) where {S <: Real}

    func_error = if error_method == :total_error
        sum(abs.(new_funcvar - old_funcvar))
    elseif error_method in [:L∞, :Linf, :max_abs_error, :maximum_absolute_error]
        maximum(abs.(new_funcvar - old_funcvar))
    elseif error_method in [:L², :L2, :squared_error]
        sum((new_funcvar - old_funcvar) .^ 2)
    end

    return func_error
end

"""
```
nojump_ode_init(m::AbstractNLCTFPModel)
```

sets up (by default) the initial condition for the no-jump solution via an ODE solver.
The inference may not always work.
"""
function nojump_ode_init(m::AbstractNLCTFPModel)
    @warn "Guessing the initial values for the no-jump ODE. It is recommended to overload the function `nojump_ode_init` " *
        "to make sure the correct initial values are used."
    bcs = get_setting(m, :boundary_conditions)
    out = map(x -> x[1], values(bcs))
    if length(out) == 1
        return out[1]
    else
        return out
    end
end

"""
```
function nonuniform_grid_spacing(stategrid::StateGrid, bc::AbstractVector{Tuple{S, S}} =
    Vector{Tuple{Float64, Float64}}(undef, 0)) where {S <: Real}
```

constructs the spacing vector for a non-uniform grid using a ghost-node approach.

If `bc` is empty, then we assume the spacing between the boundary and the boundary-adjacent grid points
are the same as the second most interior grid point. For a 1D grid `x`, this assumption means that
the spacing between the boundary and left/right endpoints are `diff(x)[1]` and `diff[x][end]`, respectively.

If the boundary values are known, then they can be passed to `bc` as a vector of the endpoints of
each dimension in a Cartesian product, e.g.
with a grid with boundaries `[a, b] × [c, d]`, the user would set `bc = [(a, b), (c, d)]`.
"""
function nonuniform_grid_spacing(stategrid::StateGrid, bc::AbstractVector{Tuple{S, S}} =
                                 Vector{Tuple{Float64, Float64}}(undef, 0)) where {S <: Real}
    @assert isempty(bc) || ndims(stategrid) == length(bc) "The dimensions of `stategrid` must match `bc`"
    if ndims(stategrid) == 1
        x = values(stategrid.x)[1]
        dx1 = isempty(bc) ? x[2] - x[1] : x[1] - bc[1][1]
        dxN = isempty(bc) ? x[end] - x[end - 1] : bc[1][2] - x[end]
        return vcat(dx1, diff(x), dxN)
    else
        error("Not yet implemented")
    end
end

# Constructs the diagonals of a 2nd derivative 2nd order centered difference matrix with reflecting
# boundary condition and the optional input of a coefficients vector.
function _centered_difference_reflecting_bc_weights(order::Int, x::AbstractVector{S},
                                                    coefs::AbstractVector{S} = Vector{S}(undef, 0)) where {S <: Real}

    # Set up
    N  = length(x)
    D0 = Vector{S}(undef, N)
    DU = Vector{S}(undef, N - 1)
    DD = Vector{S}(undef, N - 1)

    # Handle boundaries
    # a0 * f0 + a2 * f2 = 0 ⇒ f0 = -(a2 / a0) f2
    # If the ghost node is uniformly spaced, then a2 = -a0, hence f0 = f2.
    # ⇒ ∂²f/∂x² ≈ b0 * f2 + b1 * f1 + b2 * f2 = b1 * f1 + (b0 + b2) * f2
    b0, b1, b2 = DiffEqOperators.calculate_weights(order, x[1], [x[1] - (x[2] - x[1]), x[1], x[2]])
    D0[1] = b1
    DU[1] = (b0 + b2)
    b0, b1, b2 = DiffEqOperators.calculate_weights(order, x[end], [x[end - 1], x[end], x[end] + (x[end] - x[end - 1])])
    D0[end] = b1
    DD[end] = (b0 + b2)

    # Handle rest of diagonals
    for i in 2:(N - 1)
        DD[i - 1], D0[i], DU[i] = DiffEqOperators.calculate_weights(order, x[i], x[(i - 1):(i + 1)])
    end

    # Update with coefficients
    if !isempty(coefs)
        DD .*= coefs[2:N]
        D0 .*= coefs
        DU .*= coefs[1:(N - 1)]
    end

    return DD, D0, DU
end


text:
using ADCME
using PyCall
using LinearAlgebra
using PyPlot
using Random
Random.seed!(233)

relu(x) = max(x, 0)
function extended_nn(x,config,theta,activation)
    extended_nn_ = load_op_and_grad("./build/libExtendedNn","extended_nn", multiple=true)
    x,config_,theta = convert_to_tensor([x,config,theta], [Float64,Int64,Float64])
    u, du = extended_nn_(x,config_,theta,activation)
    n = length(x)÷config[1]
    reshape(u, (n, config[end])), du
end

# TODO: specify your input parameters
x = rand(20)
config = [2,20,50,8]
activation = "tanh"

W1 = rand(2,20); b1 = rand(20)
W2  = rand(20,50); b2 = rand(50);
W3 = rand(50,8); b3 = rand(8)
X = reshape(x, 2, 10)'|>Array

y1 = tanh.(X*W1 .+ b1')
y2 = tanh.(y1*W2 .+ b2')
y3 = y2*W3 .+ b3'

# x = rand(10)
# config = [1,2]
# activation = "tanh"

# W1 = ones(1,2); b1 = ones(2)
# X = reshape(x, 1, 10)'|>Array

# y1 = X*W1 .+ b1'

θ = [W1'[:];b1[:];W2'[:];b2[:];W3'[:];b3[:]]
# θ = [W1'[:];b1[:]]
tfx = constant(x)
u = extended_nn(x,config,θ,activation)
sess = Session(); init(sess)
@show run(sess, u)[1]-y3

# S = gradients(u[1][:,1], tfx)
# run(sess, S)

# uncomment it for testing gradients
# error()

# TODO: change your test parameter to `m`
#       in the case of `multiple=true`, you also need to specify which component you are testings
# gradient check -- v
function scalar_function(m)
    return sum(extended_nn(m,config,θ,activation)[1]^2)
end

# TODO: change `m_` and `v_` to appropriate values
m_ = constant(rand(length(θ)))
v_ = rand(length(θ))
m_ = constant(rand(length(x)))
v_ = rand(length(x))
y_ = scalar_function(m_)
dy_ = gradients(y_, m_)
ms_ = Array{Any}(undef, 5)
ys_ = Array{Any}(undef, 5)
s_ = Array{Any}(undef, 5)
w_ = Array{Any}(undef, 5)
gs_ =  @. 1 / 10^(1:5)

for i = 1:5
    g_ = gs_[i]
    ms_[i] = m_ + g_*v_
    ys_[i] = scalar_function(ms_[i])
    s_[i] = ys_[i] - y_
    w_[i] = s_[i] - g_*sum(v_.*dy_)
end

sess = Session(); init(sess)
sval_ = run(sess, s_)
wval_ = run(sess, w_)
close("all")
loglog(gs_, abs.(sval_), "*-", label="finite difference")
loglog(gs_, abs.(wval_), "+-", label="automatic differentiation")
loglog(gs_, gs_.^2 * 0.5*abs(wval_[1])/gs_[1]^2, "--",label="\$\\mathcal{O}(\\gamma^2)\$")
loglog(gs_, gs_ * 0.5*abs(sval_[1])/gs_[1], "--",label="\$\\mathcal{O}(\\gamma)\$")

plt.gca().invert_xaxis()
legend()
xlabel("\$\\gamma\$")
ylabel("Error")


text:
# promote start and stop, leaving step alone
#(:)(start::A, step, stop::C) where {A<:Real,C<:Real} =
#    (:)(convert(promote_type(A,C),start), step, convert(promote_type(A,C),stop))

for (ST,BT) in S2B
    for B in (ST,BT)
    for E in (ST,BT)
        B == BT && E == BT && continue
        if BT <: AbstractFloat
            eval(:((:)(a::$B, b::$E) = (:)(a, $(one(ST)), b)))
        elseif BT <: Integer
            if B == ST && E == ST
                eval(:((:)(a::$B, b::$E) = UnitSRange{$BT}(a, b)))
            else
                eval(:((:)(a::$B, b::$E) = UnitMRange{$BT}(a, b)))
            end
        else
            @eval begin
                (:)(start::$B, stop::$E) = (:)(start, ofeltype(stop-start, SOne), stop)
                (:)(a::$B, b::AbstractFloat, c::$E) = (:)(promote(a, b, c)...)
                (:)(a::$B, b::Real, c::$E) = (:)(promote(a, b, c)...)
            end
        end
    end
    end
end

# FIXME
for (ST,BT) in SI2BI
    for B in (ST,BT)
    for S in (ST,BT)
    for E in (ST,BT)
        B == BT && S == BT && E == BT && continue
        @eval begin
            (:)(a::$B, b::$S, c::$E) = _scolon(Base.OrderStyle($BT), Base.ArithmeticStyle($BT), a, b, c)
        end
    end
    end
    end
end
#(:)(start::A, step, stop::C) where {A<:Real,C<:Real} =
#    (:)(convert(promote_type(A,C),start), step, convert(promote_type(A,C),stop))

#(:)(start::SVal, stop::SVal) = (:)(start, oftype(stop-start, SOne), stop)

#=
# promote start and stop, leaving step alone
function (:)(start::SReal, step, stop::BaseReal)
    T = eltype(start)
    if T == eltype(stop)
        _scolon(start, step, stop)
    else
        (:)(ofeltype(promote_eltype(start, stop), start), step, ofeltype(promote_eltype(start, stop), stop))
    end
end
function (:)(start::BaseReal, step::Integer, stop::SReal)
    T = eltype(start)
    if T == eltype(stop)
        _scolon(start, step, stop)
    else
        (:)(ofeltype(promote_eltype(start, stop), start), step, ofeltype(promote_eltype(start, stop), stop))
    end
end
function (:)(start::SReal, step::Integer, stop::SReal)
    T = eltype(start)
    if T == eltype(stop)
        _scolon(start, step, stop)
    else
        (:)(ofeltype(promote_eltype(start, stop), start), step, ofeltype(promote_eltype(start, stop), stop))
    end
end
=#
# AbstractFloat specializations
(:)(start::SFloat, stop::SFloat) = (:)(promote_toeltype(start, stop)...)
(:)(start::SFloat, stop::BaseFloat) = (:)(promote_toeltype(start, stop)...)
(:)(start::BaseFloat, stop::SFloat) = (:)(promote_toeltype(start, stop)...)

#(:)(start::T, step::T, stop::T) where {T<:AbstractFloat} =
#    _colon(OrderStyle(T), ArithmeticStyle(T), start, step, stop)

#=
for B in (SVal,BaseAny)
for S in (SVal,BaseAny)
for E in (SVal,BaseAny)
    B == BaseAny && S == BaseAny && E == BaseAny && continue
    eval(:((:)(start::$B, step::$S, stop::$E) = _scolon(start, step, stop)))
end
end
end
=#
for (ST,BT) in S2B
    for B in (ST,BT)
    for S in (SVal,BaseAny)
    for E in (ST,BT)
        if B == ST && S == SVal && E == ST
            @eval begin
                function _scolon(start::$B, step::$S, stop::$E)
                    T′ = typeof(start+zero(step))
                    StepSRange(ofeltype(T′,start), step, ofeltype(T′,stop))
                end
            end
        else
            @eval begin
                function _scolon(start::$B, step::$S, stop::$E)
                    T′ = typeof(start+zero(step))
                    StepMRange(ofeltype(T′,start), step, ofeltype(T′,stop))
                end
            end
            #=
           =#
        end
        B == BT && S == BaseAny && E == BT && continue
        @eval begin
            (:)(a::$B, b::$S, c::$E) = (:)(promote(a,b,c)...)
        end
    end
    end
    end
end

function _scolon(start::T, step::SVal, stop::T) where T
    T′ = typeof(start+zero(step))
    StepSRange(ofeltype(T′,start), step, ofeltype(T′,stop))
end
#=
for (ST,BT) in S2B
    for B in (ST,BT)
    for S in (SReal,BaseReal)
    for E in (ST,BT)  (Colon())(SFloat(1.0), SFloat(0.2), SFloat(2.0))
        B == BT && S == BaseReal && E == BT && continue
        @eval begin
            @eval begin
            end
        end
    end
    end
    end
end

start = SVal(1.)
s = SVal(.2)
stop = SVal(2.)
isbetween(a, x, b) = (a <= x <= b || b <= x <= a)
=#
const STwo = SInt(2)
for (ST,BT) in SF2BF
    for B in (ST, BT)
    for S in (ST, BT)
    for E in (ST, BT)
        B == BT && S == BT && E == BT && continue
        @eval begin
            function (:)(start::$B, s::$S, stop::$E)
                s == 0 && throw(ArgumentError("range step cannot be zero"))
                # see if the inputs have exact rational approximations (and if so,
                # perform all computations in terms of the rationals)
                step_n, step_d = Base.rat(s)
                if step_d != 0 && $BT(step_n/step_d) == s
                    start_n, start_d = Base.rat(start)
                    stop_n, stop_d = Base.rat(stop)
                    if start_d != 0 && stop_d != 0 &&
                            (start_n/start_d) == start && (stop_n/stop_d) == stop
                        den = lcm(start_d, step_d) # use same denominator for start and step
                        m = maxintfloat($ST, Int)
                        if den != 0 && abs(start*den) <= m && abs(s*den) <= m &&  # will round succeed?
                                rem(den, start_d) == 0 && rem(den, step_d) == 0      # check lcm overflow
                            start_n = round(Int, start*den)
                            step_n = round(Int, s*den)
                            len = max(SZero, div(den*stop_n - stop_d*start_n + step_n*stop_d, step_n*stop_d))
                            # Integer ops could overflow, so check that this makes sense
                            if isbetween(start, start + (len-SOne)*s, stop + s/STwo) && !isbetween(start, start + len*s, stop)
                                # Return a 2x precision range
                                return sfloatrange($BT, start_n, step_n, len, den)
                            end
                        end
                    end
                end
                # Fallback, taking start and step literally
                lf = (stop-start)/s
                if lf < 0
                    len = SZero
                elseif lf == 0
                    len = SOne
                else
                    len = round(Int, lf) + SOne
                    stop′ = start + (len-SOne)*s
                    if len isa SInteger
                        len -= SInt(start < stop < stop′) + SInt(start > stop > stop′)
                    else
                        len -= (start < stop < stop′) + (start > stop > stop′)
                    end
                end
                srangehp($BT, start, s, SOne, len, SOne)
            end
        end
    end
    end
    end
end


text:
using MPIReco

@testset "system matrix center estimation" begin
  #dirs = ["8.mdf", "9.mdf", "10.mdf", "11.mdf"]   8.mdf is wrong. BG is subtracted twice
  dirs = ["9.mdf", "10.mdf", "11.mdf"]
  SFs = joinpath.(datadir, "calibrations", dirs)
  #center = [[9.0,23.0,1.0],[9.0,10.0,1.0],[22.0,23.0,1.0],[22.0,10.0,1.0]]
  center = [[9.0,10.0,1.0],[22.0,23.0,1.0],[22.0,10.0,1.0]]

  for (l,SF) in enumerate(SFs)
    bSF = MPIFile(SF)
    a = findCenterOfDfFov(bSF)
    @test a == center[l]
    S = getSF(bSF,2,0,0,2)
    exportImage(joinpath(imgdir, "Center1.png"), abs.(S)[:,:,1])
    #p = imagesc(abs.(S)[:,:,1])
    #add(p, Points([a[2]-1],[a[1]-1],color="yellow",lw=5))
    #savefig(p, "$imgdir/Center1.png")
  end

  for (l,SF) in enumerate(SFs)
    bSF = MPIFile(SF)
    a = findCenterOfDfFov(bSF)
    @test a == center[l]
    S = getSF(bSF,5,6,0,1)
    exportImage(joinpath(imgdir, "Center2.png"), abs.(S)[:,:,1])
    #p = imagesc(abs.(S)[:,:,1])
    #add(p, Points([a[2]-1],[a[1]-1],color="yellow",lw=5))
    #savefig(p, "$imgdir/Center2.png")
  end
end


text:
using Cairo
using Colors
using Vec
using Reel

Reel.set_output_type("gif")

const MONOKAI_LITE = colorant"0xCFBFADFF"
const MONOKAI_DARK = colorant"0x272822FF"
const MONOKAI_BLUE   = colorant"0x52E3F6FF"
const MONOKAI_GREEN  = colorant"0xA7EC21FF"
const MONOKAI_RED    = colorant"0xFF007FFF"
const MONOKAI_ORANGE = colorant"0xF9971FFF"
const MONOKAI_COBALT = colorant"0x79ABFFFF"

char2ind(c::Char) = uppercase(c) - 'A' + 1
ind2char(i::Int) = i + 'A' - 1

function Cairo.set_source_rgba(ctx::CairoContext, color::RGB)

    # g = convert(Float64, gray(grayscale_transform(color)))
    # r = g = b = g

    r = convert(Float64, red(color))
    g = convert(Float64, green(color))
    b = convert(Float64, blue(color))

    set_source_rgba(ctx, r, g, b, 1.0)
end
function Cairo.set_source_rgba(ctx::CairoContext, color::TransparentColor)

    # grayscale = grayscale_transform(color)
    # g = convert(Float64, gray(grayscale))
    # r = g = b = g
    # a = convert(Float64, alpha(grayscale))

    r = convert(Float64, red(color))
    g = convert(Float64, green(color))
    b = convert(Float64, blue(color))
    a = convert(Float64, alpha(color))

    set_source_rgba(ctx, r, g, b, a)
end
function Cairo.set_source_rgba(ctx::CairoContext, color₀::Colorant, color₁::Colorant, t::Real)

    r₀ = convert(Float64, red(color₀))
    g₀ = convert(Float64, green(color₀))
    b₀ = convert(Float64, blue(color₀))
    a₀ = convert(Float64, alpha(color₀))

    r₁ = convert(Float64, red(color₁))
    g₁ = convert(Float64, green(color₁))
    b₁ = convert(Float64, blue(color₁))
    a₁ = convert(Float64, alpha(color₁))

    r = r₀ + (r₁ - r₀)*t
    g = g₀ + (g₁ - g₀)*t
    b = b₀ + (b₁ - b₀)*t
    a = a₀ + (a₁ - a₀)*t
    set_source_rgba(ctx, r, g, b, a)
end

function render_text(ctx::CairoContext, text::String, x::Real, y::Real;
    font_size::Real=10.0,
    color::Colorant = colorant"black",
    font_face::String="sans-serif",
    )

    Cairo.save(ctx)
    select_font_face(ctx, font_face, Cairo.FONT_SLANT_NORMAL, Cairo.FONT_WEIGHT_NORMAL)
    set_font_size(ctx, font_size)

    set_source_rgba(ctx, color)
    move_to(ctx, x, y)
    show_text(ctx, text)
    restore(ctx)
end
function render_text_centered(ctx::CairoContext, text::String, x::Real, y::Real;
    font_size::Real=10.0,
    color::Colorant = colorant"black",
    font_face::String="sans-serif",
    )

    Cairo.save(ctx)
    select_font_face(ctx, font_face, Cairo.FONT_SLANT_NORMAL, Cairo.FONT_WEIGHT_NORMAL)
    set_font_size(ctx, font_size)
    extents = text_extents(ctx, text)

    set_source_rgba(ctx, color)
    move_to(ctx, x - extents[3]/2, y + extents[4]/2)
    show_text(ctx, text)
    restore(ctx)
end

function get_surface_and_context(canvas_width::Int, canvas_height::Int)
    s = CairoRGBSurface(canvas_width, canvas_height)
    ctx = creategc(s)
    (s, ctx)
end
function get_surface_and_context(;
    canvas_width::Int = 590,
    canvas_height::Int = 400,
    background_color::Colorant = colorant"white",
    )

    s, ctx = get_surface_and_context(canvas_width, canvas_height)

    # fill with background color
    set_source_rgba(ctx, background_color)
    paint(ctx)

    (s, ctx)
end

bezier(A::VecE2, B::VecE2, t::Float64) = lerp(A, B, t)
bezier(A::VecE2, B::VecE2, C::VecE2, t::Float64) = (1-t)^2*A + 2*(1-t)*t*B + t*t*C
bezier(A::VecE2, B::VecE2, C::VecE2, D::VecE2, t::Float64) = (1-t)^3*A + 3*(1-t)^2*t*B + 3*(1-t)*t*t*C + t*t*t*D

type RotorRenderParams
    margin_left::Float64
    margin_top::Float64
    sep_vert::Float64
    sep_horz::Float64

    vertex_radius::Float64
    line_width::Float64

    function RotorRenderParams()
        new(150.0, 30.0, 80.0, 200.0, 8.0, 4.0)
    end
    function RotorRenderParams(margin_left::Real, margin_top::Real, sep_vert::Real, sep_horz::Real, vertex_radius::Real, line_width::Real)
        new(
            convert(Float64, margin_left),
            convert(Float64, margin_top),
            convert(Float64, sep_vert),
            convert(Float64, sep_horz),
            convert(Float64, vertex_radius),
            convert(Float64, line_width),
        )
    end
end
get_vertex_x(rp::RotorRenderParams, i::Int) = rp.margin_left + rp.sep_horz*(i-1)
get_vertex_y(rp::RotorRenderParams, j::Int) = rp.margin_top + rp.sep_vert*(j-1)
get_vertex_pos(rp::RotorRenderParams, i::Int, j::Int) = VecE2(get_vertex_x(rp, i), get_vertex_y(rp, j))

type Rotor
    enshift::Vector{Int} # amount each input gets shifted
    deshift::Vector{Int} # amount reversed inputs get shifted
    knock_points::Vector{Int}
    rotor_position::Int
    function Rotor(perm::Vector{Int}, knock_points::Vector{Int}=Int[], rotor_position::Int=0)

        n = length(perm)
        enshift = Array(Int, n)
        deshift = Array(Int, n)
        for (i,p) in enumerate(perm)
            enshift[i] = p - i
            deshift[p] = i - p
        end

        rotor_position = mod(rotor_position, n)

        new(enshift, deshift, knock_points, rotor_position)
    end
end
Base.length(rotor::Rotor) = length(rotor.enshift)
function tick!(rotor::Rotor)
    rotor.rotor_position = mod(rotor.rotor_position + 1, length(rotor))
    rotor
end
function encode(rotor::Rotor, a::Int)
    n = length(rotor.enshift) # number of letters
    a₂ = a + rotor.rotor_position
    a₂ = mod(a₂-1, n)+1
    b = a + rotor.enshift[a₂]
    mod(b-1, n)+1
end
function decode(rotor::Rotor, a::Int)
    n = length(rotor.deshift) # number of letters
    a₂ = a + rotor.rotor_position
    a₂ = mod(a₂-1, n)+1
    b = a + rotor.deshift[a₂]
    mod(b-1, n)+1
end

function render_bezier_edge!(ctx::CairoContext, A::VecE2, D::VecE2, color::Colorant=MONOKAI_DARK;
    line_width::Real = 5.0,
    bezier_strength::Real = 100.0,
    reflect::Bool=false,
    )

    B = A + VecE2(bezier_strength, 0.0)
    C = D + (reflect ? 1 : -1) * VecE2(bezier_strength, 0.0)

    save(ctx)
    set_source_rgba(ctx, color)
    set_line_width(ctx, line_width)
    move_to(ctx, A.x, A.y)
    curve_to(ctx, B.x, B.y, C.x, C.y, D.x, D.y)
    stroke(ctx)
    restore(ctx)

    ctx
end
function render_vertex!(ctx::CairoContext, P::VecE2, color::Colorant=MONOKAI_DARK;
    radius::Real=10.0,
    )

    save(ctx)
    set_source_rgba(ctx, color)
    translate(ctx, P.x, P.y)
    arc(ctx, 0.0, 0.0, radius, 0, 2pi)
    fill(ctx)
    restore(ctx)

    ctx
end
function render_text_and_ciphertext!(
    ctx::CairoContext,
    rotor::Rotor,
    text::String,
    cipher_text::String;
    render_params::RotorRenderParams = RotorRenderParams(),
    font_size::Real=20.0,
    only_input::Bool=false,
    font_face::String="monospace",
    )

    x = get_vertex_x(render_params, 1)
    y = get_vertex_y(render_params, length(rotor))

    render_text(ctx, text, x, y + 50, font_size=font_size, font_face=font_face, color=MONOKAI_DARK)
    if !only_input
        render_text(ctx, cipher_text, x, y + 100, font_size=font_size, font_face=font_face, color=MONOKAI_COBALT)
    end
    ctx
end
function render_text_and_ciphertext!(
    s::CairoSurface,
    rotor::Rotor,
    text::String,
    cipher_text::String;
    render_params::RotorRenderParams = RotorRenderParams(),
    font_size::Real=20.0,
    only_input::Bool=false,
    )

    ctx = creategc(s)
    render_text_and_ciphertext!(ctx, rotor, text, cipher_text, render_params=render_params, font_size=font_size, only_input=only_input)
    s
end
function render_alphabet!(
    ctx::CairoContext,
    rotor::Rotor,
    alphabet::Vector{Char};
    render_params::RotorRenderParams = RotorRenderParams(),
    font_size::Real=20.0,
    )

    for (i, c) in enumerate(alphabet)
        P = get_vertex_pos(render_params, 1, i)
        Q = get_vertex_pos(render_params, 2, i)

        render_text_centered(ctx, string(c), P.x - 50.0, P.y, font_size=font_size, color=MONOKAI_DARK)
        render_text_centered(ctx, string(c), Q.x + 50.0, Q.y, font_size=font_size, color=MONOKAI_DARK)
    end
    ctx
end
function render!(ctx::CairoContext,
    rotor::Rotor,
    active_inputs::Vector{Int},
    render_params::RotorRenderParams = RotorRenderParams(),
    )

    n = length(rotor)
    for a in 1 : n
        if !in(a, active_inputs)
            P = get_vertex_pos(render_params, 1, a)

            b = encode(rotor, a)
            Q = get_vertex_pos(render_params, 2, b)

            render_vertex!(ctx, P, MONOKAI_DARK, radius=render_params.vertex_radius)
            render_vertex!(ctx, Q, MONOKAI_DARK, radius=render_params.vertex_radius)
            render_bezier_edge!(ctx, P, Q, MONOKAI_DARK, line_width=render_params.line_width)
        end
    end
    for a in active_inputs
        P = get_vertex_pos(render_params, 1, a)

        b = encode(rotor, a)
        Q = get_vertex_pos(render_params, 2, b)

        render_vertex!(ctx, P, MONOKAI_COBALT, radius=render_params.vertex_radius)
        render_vertex!(ctx, Q, MONOKAI_COBALT, radius=render_params.vertex_radius)
        render_bezier_edge!(ctx, P, Q, MONOKAI_COBALT, line_width=render_params.line_width)
    end

    ctx
end
function render(rotor::Rotor;
    active_inputs::Vector{Int}=Int[],
    render_params::RotorRenderParams = RotorRenderParams(),
    )

    s, ctx = get_surface_and_context()
    render!(ctx, rotor, active_inputs, render_params)
    s
end

let
    rotor = Rotor([1, 2, 3, 4])
    for i in 1 : 4
        @assert encode(rotor, i) == i
        @assert decode(rotor, i) == i
    end

    tick!(rotor)
    for i in 1 : 4
        @assert encode(rotor, i) == i
        @assert decode(rotor, i) == i
    end

    rotor = Rotor([2, 1, 4, 3]) #+1  -1  +1  -1#
    @assert encode(rotor, 1) == 2 # +1
    @assert encode(rotor, 2) == 1 # -1
    @assert encode(rotor, 3) == 4 # +1
    @assert encode(rotor, 4) == 3 # -1

    @assert decode(rotor, 1) == 2
    @assert decode(rotor, 2) == 1
    @assert decode(rotor, 3) == 4
    @assert decode(rotor, 4) == 3

    tick!(rotor)
    @assert encode(rotor, 1) == 4 # (1+1 → 2) -1
    @assert encode(rotor, 2) == 3 # (2+1 → 3) +1
    @assert encode(rotor, 3) == 2 # (3+1 → 4) -1
    @assert encode(rotor, 4) == 1 # (4+1 → 1) +1

    @assert decode(rotor, 1) == 4
    @assert decode(rotor, 2) == 3
    @assert decode(rotor, 3) == 2
    @assert decode(rotor, 4) == 1

    rotor = Rotor([4, 2, 1, 3])
    @assert encode(rotor, 1) == 4
    @assert encode(rotor, 2) == 2
    @assert encode(rotor, 3) == 1
    @assert encode(rotor, 4) == 3

    @assert decode(rotor, 1) == 3
    @assert decode(rotor, 2) == 2
    @assert decode(rotor, 3) == 4
    @assert decode(rotor, 4) == 1
end

function encode(rotors::Vector{Rotor}, a::Int)
    for rotor in rotors
        a = encode(rotor, a)
    end
    a
end
function decode(rotors::Vector{Rotor}, a::Int)
    for rotor in reverse(rotors)
        a = decode(rotor, a)
    end
    a
end
function tick!(rotors::Vector{Rotor}, rotor_index::Int=1)

    # rotate the way you would expect.
    # Thus "double stepping" does not occur, as it does with the real Enigma

    rotor = rotors[rotor_index]
    if mod(rotor.rotor_position,length(rotor))+1 in rotor.knock_points && rotor_index < length(rotors)
        # rotate the next rotor as well
        tick!(rotors, rotor_index+1)
    end
    tick!(rotor) # rotate this rotor
    rotors
end
function render_alphabet!(
    ctx::CairoContext,
    rotors::Vector{Rotor},
    alphabet::Vector{Char};
    render_params::RotorRenderParams = RotorRenderParams(),
    font_size::Real=20.0,
    )

    n = length(rotors)+1
    for (i, c) in enumerate(alphabet)
        P = get_vertex_pos(render_params, 1, i)
        Q = get_vertex_pos(render_params, n, i)

        render_text_centered(ctx, string(c), P.x - 50.0, P.y, font_size=font_size, color=MONOKAI_DARK)
        render_text_centered(ctx, string(c), Q.x + 50.0, Q.y, font_size=font_size, color=MONOKAI_DARK)
    end
    ctx
end
function render_rotor_tick!(
    ctx::CairoContext,
    rotor::Rotor,
    t::Float64, # ∈ [0,1]
    color::Colorant,
    render_params::RotorRenderParams = RotorRenderParams(),
    bezier_strength::Real=125.0,
    )

    n = length(rotor)
    for a1 in 1 : n

        a2 = mod(a1-2, n)+1
        P1 = get_vertex_pos(render_params, 1, a1)
        P2 = get_vertex_pos(render_params, 1, a2)

        if a2 != n
            P = bezier(P1, P2, t)
        else # use a special bezier
            C = P1 - VecE2(0, bezier_strength)
            D = P2 + VecE2(0, bezier_strength)
            P = bezier(P1, C, D, P2, t)
        end

        b1 = encode(rotor, a1)
        b2 = mod(b1-2,n)+1
        Q1 = get_vertex_pos(render_params, 2, b1)
        Q2 = get_vertex_pos(render_params, 2, b2)

        if b2 != n
            Q = bezier(Q1, Q2, t)
        else
            C = Q1 -VecE2(0, bezier_strength)
            D = Q2 + VecE2(0, bezier_strength)
            Q = bezier(Q1, C, D, Q2, t)
        end

        render_vertex!(ctx, P, color, radius=render_params.vertex_radius)
        render_vertex!(ctx, Q, color, radius=render_params.vertex_radius)
        render_bezier_edge!(ctx, P, Q, color, line_width=render_params.line_width)
    end

    ctx
end
function render_rotor_tick!(
    ctx::CairoContext,
    rotors::Vector{Rotor},
    t::Float64, # ∈ [0,1]
    color::Colorant,
    render_params::RotorRenderParams = RotorRenderParams(),
    )

    n = length(rotors[1])
    n_rotors = length(rotors)

    left_offset = 0

    rotor_index = 1
    done = false
    while !done
        rotor = rotors[rotor_index]

        rp2 = deepcopy(render_params)
        rp2.margin_left = render_params.margin_left + render_params.sep_horz*(rotor_index-1)

        render_rotor_tick!(ctx, rotor, t, color, rp2)
        done = rotor_index == n_rotors || !in(mod(rotor.rotor_position,n)+1, rotor.knock_points)
        rotor_index += 1
    end

    while rotor_index ≤ n_rotors

        rp2 = deepcopy(render_params)
        rp2.margin_left = render_params.margin_left + render_params.sep_horz*(rotor_index-1)

        render!(ctx, rotors[rotor_index], Int[], rp2)
        rotor_index += 1
    end

    ctx
end
function render_trace!(
    ctx::CairoContext,
    rotors::Vector{Rotor},
    a::Int,
    color::Colorant,
    render_params::RotorRenderParams,
    )

    P = get_vertex_pos(render_params, 1, a)
    render_vertex!(ctx, P, color, radius=render_params.vertex_radius)

    for rotor in rotors
        b = encode(rotor, a)
        Q = VecE2(P.x + render_params.sep_horz, get_vertex_y(render_params, b))
        render_bezier_edge!(ctx, P, Q, color, line_width=render_params.line_width)
        render_vertex!(ctx, Q, color, radius=render_params.vertex_radius)
        a, P = b, Q
    end

    ctx
end
function render!(
    ctx::CairoContext,
    rotors::Vector{Rotor},
    input::Int,
    render_params::RotorRenderParams,
    )

    for a in 1 : length(rotors[1])
        color = a == input ? MONOKAI_BLUE : MONOKAI_DARK
        render_trace!(ctx, rotors, a, color, render_params)
    end

    ctx
end
function render(rotors::Vector{Rotor};
    render_params::RotorRenderParams = RotorRenderParams(),
    )

    s, ctx = get_surface_and_context()

    rp2 = deepcopy(render_params)
    for (i,rotor) in enumerate(rotors)
        rp2.margin_left = get_vertex_x(render_params, i)
        render!(ctx, rotor, Int[], rp2)
    end

    s
end

let
    rotor = Rotor([4, 2, 1, 3])
    rotors = [rotor, rotor, rotor]
    @assert encode(rotors, 1) == 1
    @assert encode(rotors, 2) == 2
    @assert encode(rotors, 3) == 3
    @assert encode(rotors, 4) == 4
    @assert decode(rotors, 1) == 1
    @assert decode(rotors, 2) == 2
    @assert decode(rotors, 3) == 3
    @assert decode(rotors, 4) == 4
end

type Reflector
    perm::Vector{Int} # pairwise combinations, so perm[a] = b and perm[b] = a, a ≠ b
    function Reflector(perm::Vector{Int})
        for (i,p) in enumerate(perm)
            @assert perm[p] == i && i != p
        end
        new(perm)
    end
end
Base.length(ref::Reflector) = length(ref.perm)
encode(ref::Reflector, a::Int) = ref.perm[a]
decode(ref::Reflector, b::Int) = ref.perm[b]

let
    ref = Reflector([2,1,4,3])
    @assert encode(ref, 1) == 2
    @assert encode(ref, 2) == 1
    @assert encode(ref, 3) == 4
    @assert encode(ref, 4) == 3

    @assert decode(ref, 1) == 2
    @assert decode(ref, 2) == 1
    @assert decode(ref, 3) == 4
    @assert decode(ref, 4) == 3
end

type Plugboard
    perm::Vector{Int} # optional pairwise perms
end
Base.length(plugboard::Plugboard) = length(plugboard.perm)
encode(plugboard::Plugboard, a::Int) = plugboard.perm[a]
decode(plugboard::Plugboard, b::Int) = plugboard.perm[b]

type Enigma
    plugboard::Plugboard
    rotors::Vector{Rotor}
    ref::Reflector
    alphabet::Vector{Char}
    emulate_double_stepping::Bool # the original enigmas had a weird double-stepping effect that can also be emulated

    function Enigma(
        plugboard::Plugboard,
        rotors::Vector{Rotor},
        ref::Reflector,
        alphabet::Vector{Char},
        emulate_double_stepping::Bool=false,
        )
        new(plugboard, rotors, ref, alphabet, emulate_double_stepping)
    end
end
Base.length(enigma::Enigma) = length(enigma.ref)
function encode(enigma::Enigma, a::Int)
    b = encode(enigma.plugboard, a)
    c = encode(enigma.rotors, b)
    d = encode(enigma.ref, c)
    e = decode(enigma.rotors, d)
    decode(enigma.plugboard, e)
end
decode(enigma::Enigma, b::Int) = encode(enigma, b)

tick_with_mathematical_purity!(enigma::Enigma) = tick!(enigma.rotors)
function tick_with_double_stepping!(enigma::Enigma)

    # rotor 1 is always moved
    # if a rotor is in its notch position, it also moves the rotor to its right

    # 1 - identify rotors that are to be moved
    # 2 - move them

    n_rotors = length(enigma.rotors)
    move = falses(n_rotors)
    move[1] = true # always move the first rotor

    for (i,rotor) in enumerate(enigma.rotors)
        if i != n_rotors && mod(rotor.rotor_position,length(rotor))+1 in rotor.knock_points
            move[i] = true # rotate this guy
            move[i+1] = true # rotate next guy
        end
    end

    for (i,it_moves) in enumerate(move)
        if it_moves
            tick!(enigma.rotors[i])
        end
    end

    enigma
end
function tick!(enigma::Enigma)
    if enigma.emulate_double_stepping
        tick_with_double_stepping!(enigma)
    else
        tick_with_mathematical_purity!(enigma)
    end
    enigma
end

function encode!(enigma::Enigma, a::Int)
    #=
    Enigma Process
         1. Rotate wheels
         2. Encode
    =#

    tick!(enigma)
    b = encode(enigma, a)

    b
end

function render_trace!(
    ctx::CairoContext,
    enigma::Enigma,
    a::Int,
    color::Colorant,
    render_params::RotorRenderParams,
    render_plugboard::Bool,
    )

    P = get_vertex_pos(render_params, 1, a)
    render_vertex!(ctx, P, color, radius=render_params.vertex_radius)

    if render_plugboard
        b = encode(enigma.plugboard, a)
        Q = VecE2(P.x + render_params.sep_horz, get_vertex_y(render_params, b))
        render_bezier_edge!(ctx, P, Q, color, line_width=render_params.line_width)
        render_vertex!(ctx, Q, color, radius=render_params.vertex_radius)
        a, P = b, Q
    end

    for rotor in enigma.rotors
        b = encode(rotor, a)
        Q = VecE2(P.x + render_params.sep_horz, get_vertex_y(render_params, b))
        render_bezier_edge!(ctx, P, Q, color, line_width=render_params.line_width)
        render_vertex!(ctx, Q, color, radius=render_params.vertex_radius)
        a, P = b, Q
    end

    b = encode(enigma.ref, a)
    Q = VecE2(P.x, get_vertex_y(render_params, b))
    render_bezier_edge!(ctx, Q, P, color, reflect=true, line_width=render_params.line_width)
    render_vertex!(ctx, Q, color, radius=render_params.vertex_radius)
    a, P = b, Q

    for rotor in reverse(enigma.rotors)
        b = decode(rotor, a)
        Q = VecE2(P.x - render_params.sep_horz, get_vertex_y(render_params, b))
        render_bezier_edge!(ctx, Q, P, color, line_width=render_params.line_width)
        render_vertex!(ctx, Q, color, radius=render_params.vertex_radius)
        a, P = b, Q
    end

    if render_plugboard
        b = decode(enigma.plugboard, a)
        Q = VecE2(P.x - render_params.sep_horz, get_vertex_y(render_params, b))
        render_bezier_edge!(ctx, Q, P, color, line_width=render_params.line_width)
        render_vertex!(ctx, Q, color, radius=render_params.vertex_radius)
        a, P = b, Q
    end

    ctx
end
function render!(
    ctx::CairoContext,
    enigma::Enigma,
    input::Int,
    render_params::RotorRenderParams,
    render_plugboard::Bool,
    )

    rendered = Set{Int}()
    for a in 1 : length(enigma)
        # if !in(a, rendered)
            b = encode(enigma, a)
            # push!(rendered, b)
            color = (a == input || b == input) ? MONOKAI_BLUE : MONOKAI_DARK
            render_trace!(ctx, enigma, a, color, render_params, render_plugboard)
        # end
    end

    ctx
end

function render_engima_tick!(
    ctx::CairoContext,
    enigma::Enigma,
    t::Float64, # ∈ [0,1]
    color::Colorant,
    render_params::RotorRenderParams = RotorRenderParams(),
    render_plugboard::Bool = true,
    )

    n = length(enigma)

    left_offset = 0

    if render_plugboard
        plugboard = enigma.plugboard
        for a in 1 : n
            b = encode(plugboard, a)
            A = get_vertex_pos(render_params, 1, a)
            B = get_vertex_pos(render_params, 2, b)
            render_bezier_edge!(ctx, A, B, color, line_width=render_params.line_width)
            render_vertex!(ctx, A, color, radius=render_params.vertex_radius)
            render_vertex!(ctx, B, color, radius=render_params.vertex_radius)
        end

        render_params.margin_left += render_params.sep_horz
    end

    n_rotors = length(enigma.rotors)
    rotor_index = 1
    done = false
    while !done
        rotor = enigma.rotors[rotor_index]

        rp2 = deepcopy(render_params)
        rp2.margin_left = render_params.margin_left + render_params.sep_horz*(rotor_index-1)

        render_rotor_tick!(ctx, rotor, t, color, rp2)
        done = rotor_index == n_rotors || !in(mod(rotor.rotor_position,n)+1, rotor.knock_points)
        rotor_index += 1
    end

    while rotor_index ≤ n_rotors

        rp2 = deepcopy(render_params)
        rp2.margin_left = render_params.margin_left + render_params.sep_horz*(rotor_index-1)

        render!(ctx, enigma.rotors[rotor_index], Int[], rp2)
        rotor_index += 1
    end

    # render the reflector
    rendered = Set{Int}()
    ref_x = get_vertex_x(render_params, n_rotors+1)
    for a in 1 : n
        if !in(a, rendered)
            b = encode(enigma.ref, a)
            push!(rendered, b)

            A = VecE2(ref_x, get_vertex_y(render_params, a))
            B = VecE2(ref_x, get_vertex_y(render_params, b))
            render_bezier_edge!(ctx, A, B, color, reflect=true, line_width=render_params.line_width)
            render_vertex!(ctx, A, color, radius=render_params.vertex_radius)
            render_vertex!(ctx, B, color, radius=render_params.vertex_radius)
        end
    end

    if render_plugboard
        render_params.margin_left -= render_params.sep_horz
    end

    ctx
end
function render_enigma_labels!(
    ctx::CairoContext,
    enigma::Enigma,
    render_params::RotorRenderParams = RotorRenderParams(),
    render_plugboard::Bool = true,
    font_size::Real=20.0,
    )

    P = VecE2(render_params.margin_left + render_params.sep_horz*0.5, get_vertex_y(render_params, 1) - 1.5*font_size)

    if render_plugboard
        render_text_centered(ctx, "Plugboard", P.x, P.y, font_size=font_size)
        P = P + VecE2(render_params.sep_horz, 0)
    end

    for i in 1 : length(enigma.rotors)
        text = @sprintf("Rotor %d", i)
        render_text_centered(ctx, text, P.x, P.y, font_size=font_size)
        P = P + VecE2(render_params.sep_horz, 0)
    end

    render_text_centered(ctx, "Reflector", P.x, P.y, font_size=font_size)

    ctx
end
function render_enigma_io!(
    ctx::CairoContext,
    enigma::Enigma,
    a::Int;
    render_params::RotorRenderParams = RotorRenderParams(),
    font_size::Real=20.0,
    only_input::Bool=false,
    )

    if 1 ≤ a ≤ length(enigma.alphabet)
        b = encode(enigma, a)

        x = get_vertex_x(render_params, 1) - 50.0
        P = VecE2(x, get_vertex_y(render_params, a))
        Q = VecE2(x, get_vertex_y(render_params, b))

        render_text_centered(ctx, string(enigma.alphabet[a]), P.x, P.y, font_size=font_size, color=MONOKAI_DARK)
        if !only_input
            render_text_centered(ctx, string(enigma.alphabet[b]), Q.x, Q.y, font_size=font_size, color=MONOKAI_COBALT)
        end
    end

    ctx
end
function render_text_and_ciphertext!(
    ctx::CairoContext,
    enigma::Enigma,
    text::String,
    cipher_text::String;
    render_params::RotorRenderParams = RotorRenderParams(),
    font_size::Real=20.0,
    only_input::Bool=false,
    font_face::String="monospace",
    )

    x = get_vertex_x(render_params, 1)
    y = get_vertex_y(render_params, length(enigma))

    render_text(ctx, text, x, y + 50, font_size=font_size, font_face=font_face, color=MONOKAI_DARK)
    if !only_input
        render_text(ctx, cipher_text, x, y + 100, font_size=font_size, font_face=font_face, color=MONOKAI_COBALT)
    end
    ctx
end
function render_text_and_ciphertext!(
    s::CairoSurface,
    enigma::Enigma,
    text::String,
    cipher_text::String;
    render_params::RotorRenderParams = RotorRenderParams(),
    font_size::Real=20.0,
    only_input::Bool=false,
    )

    ctx = creategc(s)
    render_text_and_ciphertext!(ctx, enigma, text, cipher_text, render_params=render_params, font_size=font_size, only_input=only_input)
    s
end

function render(enigma::Enigma, input::Int=-1;
    render_params::RotorRenderParams = RotorRenderParams(),
    render_plugboard::Bool=true,
    render_labels::Bool=true,
    render_input::Bool=true,
    do_not_render_trace::Bool=false,
    only_input::Bool=false,
    )

    s, ctx = get_surface_and_context()
    render!(ctx, enigma, do_not_render_trace ? -1 : input, render_params, render_plugboard)
    if render_labels
        render_enigma_labels!(ctx, enigma, render_params, render_plugboard)
    end
    if render_input
        render_enigma_io!(ctx, enigma, input, render_params=render_params, only_input=only_input)
    end
    s
end

function play_animation(rotor::Rotor, input::String, alphabet::Vector{Char};
    render_params::RotorRenderParams = RotorRenderParams(),
    font_size::Real=20.0,
    fps::Int=12,
    fp_render_nothing=6,
    fp_show_input_first=4,
    fp_show_trace=8,
    )

    input_text = ""
    cipher_text = ""

    frames = Frames(MIME("image/png"), fps=fps)

    # render empty machine first
    s, ctx = get_surface_and_context()
    render!(ctx, rotor, Int[], render_params)
    render_alphabet!(ctx, rotor, alphabet, render_params=render_params, font_size=font_size)
    render_text_and_ciphertext!(s, rotor, input_text, cipher_text, render_params=render_params, font_size=1.5*font_size, only_input=false)
    for i in 1 : fp_render_nothing
        push!(frames, s)
    end

    input_index = 1
    while input_index ≤ length(input)

        while input_index ≤ length(input) && input[input_index] == ' '
            input_text = input_text * " "
            cipher_text = cipher_text * " "
            input_index += 1
        end
        if input_index > length(input)
            break
        end

        A = input[input_index]
        a = findfirst(alphabet, A)

        # show input first
        s, ctx = get_surface_and_context()
        render!(ctx, rotor, Int[], render_params)
        render_alphabet!(ctx, rotor, alphabet, render_params=render_params, font_size=font_size)
        render_text_and_ciphertext!(s, rotor, input_text, cipher_text, render_params=render_params, font_size=1.5*font_size, only_input=false)
        for i in 1 : fp_show_input_first
            push!(frames, s)
        end

        # show trace
        b = encode(rotor, a)
        B = alphabet[b]
        input_text = input_text * string(A)
        cipher_text = cipher_text * string(B)
        s, ctx = get_surface_and_context()
        render!(ctx, rotor, [a], render_params)
        render_alphabet!(ctx, rotor, alphabet, render_params=render_params, font_size=font_size)
        render_text_and_ciphertext!(s, rotor, input_text, cipher_text, render_params=render_params, font_size=1.5*font_size, only_input=false)
        for i in 1 : fp_show_trace
            push!(frames, s)
        end

        input_index += 1
    end

    frames
end
function play_animation(rotors::Vector{Rotor}, input::String, alphabet::Vector{Char};
    render_params::RotorRenderParams = RotorRenderParams(),
    font_size::Real=20.0,
    fps::Int=12,
    fp_render_nothing=6,
    fp_show_input_first=2,
    fp_rot::Int=24,
    fp_show_trace=4,
    )

    input_text = ""
    cipher_text = ""

    frames = Frames(MIME("image/png"), fps=fps)

    # render empty machine first
    s = render(rotors, render_params=render_params)
    ctx = creategc(s)
    render_text_and_ciphertext!(ctx, rotors[1], input_text, cipher_text, render_params=render_params, font_size=1.5*font_size)
    render_alphabet!(ctx, rotors, alphabet, render_params=render_params, font_size=font_size)
    for i in 1 : fp_render_nothing
        push!(frames, s)
    end

    input_index = 1
    while input_index ≤ length(input)

        while input_index ≤ length(input) && input[input_index] == ' '
            input_text = input_text * " "
            cipher_text = cipher_text * " "
            input_index += 1
        end
        if input_index > length(input)
            break
        end

        A = input[input_index]
        a = findfirst(alphabet, A)

        # rotate the machine
        for i in 1 : fp_rot
            t = i/fp_rot
            s, ctx = get_surface_and_context()
            render_rotor_tick!(ctx, rotors, t, MONOKAI_DARK, render_params)
            render_text_and_ciphertext!(ctx, rotors[1], input_text, cipher_text, render_params=render_params, font_size=1.5*font_size)
            render_alphabet!(ctx, rotors, alphabet, render_params=render_params, font_size=font_size)
            push!(frames, s)
        end

        # show trace
        tick!(rotors)
        b = encode(rotors, a)
        B = alphabet[b]
        input_text = input_text * string(A)
        cipher_text = cipher_text * string(B)
        s, ctx = get_surface_and_context()
        render!(ctx, rotors, a, render_params)
        render_text_and_ciphertext!(ctx, rotors[1], input_text, cipher_text, render_params=render_params, font_size=1.5*font_size)
        render_alphabet!(ctx, rotors, alphabet, render_params=render_params, font_size=font_size)
        for i in 1 : fp_show_trace
            push!(frames, s)
        end

        input_index += 1
    end

    frames
end
function play_animation(enigma::Enigma, input::String;
    render_params::RotorRenderParams = RotorRenderParams(),
    render_plugboard::Bool=true,
    font_size::Real=20.0,
    fps::Int=12,
    fp_render_nothing=6,
    fp_show_input_first=2,
    fp_rot::Int=24,
    fp_show_trace=4,
    )

    input_text = ""
    cipher_text = ""

    frames = Frames(MIME("image/png"), fps=fps)

    # render empty machine first
    s = render(enigma, render_params=render_params, render_plugboard=render_plugboard)
    s = render_text_and_ciphertext!(s, enigma, input_text, cipher_text, render_params=render_params, font_size=1.5*font_size, only_input=false)
    for i in 1 : fp_render_nothing
        push!(frames, s)
    end

    input_index = 1
    while input_index ≤ length(input)

        while input_index ≤ length(input) && input[input_index] == ' '
            input_text = input_text * " "
            cipher_text = cipher_text * " "
            input_index += 1
        end
        if input_index > length(input)
            break
        end

        A = input[input_index]
        a = findfirst(enigma.alphabet, A)

        # show input first
        s = render(enigma, a, render_params=render_params, render_plugboard=render_plugboard, do_not_render_trace=true, only_input=true)
        s = render_text_and_ciphertext!(s, enigma, input_text, cipher_text, render_params=render_params, font_size=1.5*font_size, only_input=false)
        for i in 1 : fp_show_input_first
            push!(frames, s)
        end

        # rotate the machine
        for i in 1 : fp_rot
            t = i/fp_rot
            s, ctx = get_surface_and_context()
            render_engima_tick!(ctx, enigma, t, MONOKAI_DARK, render_params, render_plugboard)
            render_enigma_labels!(ctx, enigma, render_params, render_plugboard)
            render_enigma_io!(ctx, enigma, a, render_params=render_params, font_size=font_size, only_input=true)
            render_text_and_ciphertext!(ctx, enigma, input_text, cipher_text, render_params=render_params, font_size=1.5*font_size, only_input=false)
            push!(frames, s)
        end

        # show trace
        tick!(enigma)
        b = encode(enigma, a)
        B = enigma.alphabet[b]
        input_text = input_text * string(A)
        cipher_text = cipher_text * string(B)
        s = render(enigma, a, render_params=render_params, render_plugboard=render_plugboard, do_not_render_trace=false, only_input=false)
        s = render_text_and_ciphertext!(s, enigma, input_text, cipher_text, render_params=render_params, font_size=1.5*font_size, only_input=false)
        for i in 1 : fp_show_trace
            push!(frames, s)
        end

        input_index += 1
    end

    frames
end

include("fullsize.jl")

max_stars_repo_name: MageekDM/Enigma

max_issues_repo_name: MageekDM/Enigma

max_forks_repo_name: MageekDM/Enigma


text:
using Documenter, NormalHermiteSplines

makedocs(
    sitename = "NormalHermiteSplines.jl",
	format = Documenter.HTML(prettyurls = get(ENV, "CI", nothing) == "true"),
	authors = "Igor Kohanovsky",
    pages = [
				"Home" => "index.md",
				"Public API" => "Public-API.md",
				"Example Usage" => "Usage.md",
				"Normal Splines Method" => "Normal-Splines-Method.md",
			]
)

deploydocs(
    repo = "github.com/IgorKohan/NormalHermiteSplines.jl.git",
	devurl = "v0.6.0",
    versions = ["stable" => "v^", "v#.#.#"],
)


text:
using MultiNest

##### loglikelihood routine #####

# sample an egg box likelihood
#
# arguments
# cube
#     on entry has the ndim parameters in unit-hypercube
#     on exit, the ndim physical parameters plus (npar-ndim) derived parameters
#     you want to store with the free parameters
#
# returns
# log-likelihood

function loglike(cube::Vector{Cdouble})
    chi = 1.0
    for i in 1:length(cube)
        x = cube[i]*10pi
        chi *= cos(0.5x)
        cube[i] = x
    end
    (chi + 2)^5
end

#####

##### dumper routine #####

# The dumper routine will be called every updInt*10 iterations
# MultiNest does not need to the user to do anything. User can use the arguments
# in whichever way he/she wants
#
# arguments:
#
# physlive[nlive, npar + 1]
#     2D array containing the last set of live points (physical parameters plus
#     derived parameters) along with their log-likelihood values
# posterior[nsamples, npar + 2]
#     posterior distribution containing nSamples points. Each sample has npar
#     parameters (physical + derived) along with the their loglike value &
#     posterior probability
# paramConstr[npar, 4]
#     for each parameter, an array of [ mean, stddev, ML, MAP ] values
# maxloglike
#     maximum log-likelihood value
# logz
#     log evidence value from the default (non-INS) mode
# inslogz
#     log evidence value from the INS mode
# logzerr
#     error on log evidence value
function dumper(
    physlive::Array{Cdouble, 2},
    posterior::Array{Cdouble, 2},
    paramconstr::Array{Cdouble, 2},
    maxloglike::Cdouble,
    logz::Cdouble,
    inslogz::Cdouble,
    logzerr::Cdouble
)
    println("dumper called after ", size(posterior, 1), " samples")
end

#####

##### main program #####

# create MultiNest configuration
# arguments are log-likelihood function, number of dimensions, output root
# other MultiNest parameters are given as keywords and can be omitted
nest = nested(loglike, 2, "chains/eggbox_jl-",
    ins = true,
    mmodal = false,
    ceff = false,
    nlive = 1000,
    efr = 1.0,
    tol = 0.1,
    npar = 2,
    nclspar = 2,
    updint = 1000,
    ztol = -1E90,
    maxmodes = 100,
    wrap = false,
    seed = -1,
    fb = true,
    resume = false,
    outfile = true,
    initmpi = true,
    logzero = nextfloat(-Inf),
    maxiter = 0,
    dumper = dumper
)

# run MultiNest
@time run(nest)

#####


text:
function autocorrelation(M, v, a, ns)
    correlations = Float64[];
    # we can take vector n values as input
    for n in ns
        # Sum over M-n terms (v[i+n,a]-v̂[a])(v[i,a]-v̂[a]), divide by (M-n),
        #   is the same as taking the mean of those terms for i in [1:M-n].
        push!(correlations, mean(
            ( v[(n+1):M,a] - mean(v[:,a]) ) .* ( v[1:(M-n),a] - mean(v[:,a]) )
        ));
    end
    return correlations;
end

# find autocorrelation time for datasets v, M samples, cutoff ncut
function τ(M, v, ncut);
    ns = [0:ncut];

    # Find autocorrelation times
    tau = Float64[];
    ndims(v) == 1 ? ndatasets = 1 : ndatasets = size(v)[2];
    for a in [1:ndatasets]
        # Just sum over the normalized autocorrelations
        corra = autocorrelation(M, v, a, ns);
        corra /= corra[1];                 # Normalize
        push!(tau,sum(corra) - 0.5);       # Get autocorrelation time
    end
    return tau;
end


text:
"""
    NestedSamplers.Bounds

This module contains the different algorithms for bounding the prior volume.

The available implementations are
* [`Bounds.NoBounds`](@ref) - no bounds on the prior volume (equivalent to a unit cube)
* [`Bounds.Ellipsoid`](@ref) - bound using a single ellipsoid
* [`Bounds.MultiEllipsoid`](@ref) - bound using multiple ellipsoids in an optimal cluster
"""
module Bounds

using LinearAlgebra
using Random: GLOBAL_RNG, AbstractRNG

using StatsBase: mean_and_cov
using Clustering
using Distributions: Categorical, Uniform

export AbstractBoundingSpace, rand_live, randoffset

"""
    Bounds.AbstractBoundingSpace{T<:Number}

Abstract type for describing the bounding algorithms. For information about the interface, see the extended help (`??Bounds.AbstractBoundingSpace`)

# Extended Help

## Interface

The following functionality defines the interface for `AbstractBoundingSpace` for an example type `::MyBounds`

| Function | Required | Description |
|---------:|:--------:|:------------|
| `Base.rand(::AbstractRNG, ::MyBounds)` | x | Sample a single point from the prior volume |
| `Bounds.randoffset(::AbstractRNG, ::MyBounds)` |  | Get a random offset from the center of the bounds. Required for random walk schemes, although a fallback is provided. |
| `Base.in(point, ::MyBounds)` | x | Checks if the point is contained by the bounding space |
| `Bounds.scale!(::MyBounds, factor)` | x | Scale the volume by the linear `factor`|
| `Bounds.volume(::MyBounds)` | | Retrieve the current prior volume occupied by the bounds. |
| `Bounds.fit(::Type{<:MyBounds}, points, pointvol=0)` | x | update the bounds given the new `points` each with minimum volume `pointvol`|
| `Bounds.axes(::MyBounds)` | | Used for transforming points from the unit cube to the encompassing bound. Worth storing as a property.
"""
abstract type AbstractBoundingSpace{T <: Number} end

Base.eltype(::AbstractBoundingSpace{T}) where {T} = T

# convenience
Base.rand(B::AbstractBoundingSpace) = rand(GLOBAL_RNG, B)
Base.rand(B::AbstractBoundingSpace, N::Integer) = rand(GLOBAL_RNG, B, N)
randoffset(B::AbstractBoundingSpace) = randoffset(GLOBAL_RNG, B)

# fallback method
Base.rand(rng::AbstractRNG, B::AbstractBoundingSpace, N::Integer) = reduce(hcat, rand(rng, B) for _ in 1:N)

"""
    rand_live([rng], ::AbstractBoundingSpace, us) -> (u, bound)

Returns a random live point and the bounds associated with it.
"""
function rand_live(rng::AbstractRNG, B::AbstractBoundingSpace, us)
    idx = rand(rng, Base.axes(us, 2))
    return us[:, idx], B
end
rand_live(B::AbstractBoundingSpace, us) = rand_live(GLOBAL_RNG, B, us)

function Base.show(io::IO, bound::B) where {T,B <: AbstractBoundingSpace{T}}
    base = nameof(B) |> string
    print(io, "$base{$T}(ndims=$(ndims(bound)))")

    return nothing
end

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

"""
    Bounds.NoBounds([T=Float64], N)

Unbounded prior volume; equivalent to the unit cube in `N` dimensions.
"""
struct NoBounds{T} <: AbstractBoundingSpace{T}
    ndims::Int
end
NoBounds(D::Integer) = NoBounds{Float64}(D)
NoBounds(T::Type, D::Integer) = NoBounds{T}(D)

Base.ndims(B::NoBounds) = B.ndims

randoffset(rng::AbstractRNG, b::NoBounds{T}) where {T} = rand(rng, Uniform(0, 1), ndims(b)) .- 0.5 .|> T
Base.rand(rng::AbstractRNG, b::NoBounds{T}) where {T} = rand(rng, Uniform(0, 1), ndims(b)) .|> T
Base.rand(rng::AbstractRNG, b::NoBounds{T}, N::Integer) where {T} = rand(rng, Uniform(0, 1), ndims(b), N) .|> T
Base.in(pt, ::NoBounds) = all(p -> 0 < p < 1, pt)
fit(::Type{<:NoBounds}, points::AbstractMatrix{T}; kwargs...) where T =
    NoBounds(T, size(points, 1))
scale!(b::NoBounds, factor) = b
volume(::NoBounds{T}) where {T} = one(T)
axes(b::NoBounds{T}) where {T} = Diagonal(ones(T, b.ndims))

include("ellipsoid.jl")
include("multiellipsoid.jl")

end # module Bounds


text:
function larget_prime(n::Int)
    i = 2
    while(i<n)
        if n%i == 0
            n = n/i;
        else
            i = i+1;
        end
    end
    if(i == 2)
        return n
    end
    return i
end

larget_prime(600851475143)