text:
module Quadrature

using Requires, Reexport,  MonteCarloIntegration, QuadGK, HCubature
@reexport using DiffEqBase

struct QuadGKJL <: DiffEqBase.AbstractQuadratureAlgorithm end
struct HCubatureJL <: DiffEqBase.AbstractQuadratureAlgorithm end
struct VEGAS <: DiffEqBase.AbstractQuadratureAlgorithm
    nbins::Int
    ncalls::Int
end

VEGAS(;nbins = 100,ncalls = 1000) = VEGAS(nbins,ncalls)

abstract type AbstractCubaAlgorithm <: DiffEqBase.AbstractQuadratureAlgorithm end
struct CubaVegas <:AbstractCubaAlgorithm end
struct CubaSUAVE <: AbstractCubaAlgorithm end
struct CubaDivonne <: AbstractCubaAlgorithm end
struct CubaCuhre <: AbstractCubaAlgorithm end

abstract type AbstractCubatureJLAlgorithm <: DiffEqBase.AbstractQuadratureAlgorithm end
struct CubatureJLh <: AbstractCubatureJLAlgorithm end
struct CubatureJLp <: AbstractCubatureJLAlgorithm end

function scale_x!(_x,ub,lb,x)
    _x .= (ub .- lb) .* x .+ lb
    _x
end

function DiffEqBase.solve(prob::QuadratureProblem,::Nothing,args...;
                          reltol = 1e-8, abstol = 1e-8, kwargs...)
    if prob.lb isa Number
        solve(prob,QuadGKJL();reltol=reltol,abstol=abstol,kwargs...)
    elseif length(prob.lb) > 8 && reltol < 1e-4 || abstol < 1e-4
        solve(prob,VEGAS();reltol=reltol,abstol=abstol,kwargs...)
    else
        solve(prob,HCubatureJL();reltol=reltol,abstol=abstol,kwargs...)
    end
end

function DiffEqBase.solve(prob::QuadratureProblem,::QuadGKJL,args...;
                          reltol = 1e-8, abstol = 1e-8,
                          maxiters = typemax(Int),
                          kwargs...)
    if isinplace(prob) || prob.lb isa AbstractArray || prob.ub isa AbstractArray
        error("QuadGKJL only accepts one-dimensional quadrature problems.")
    end
    @assert prob.batch == 0
    @assert prob.nout == 1
    p = prob.p
    f = x -> prob.f(x,p)
    val,err = quadgk(f, prob.lb, prob.ub,
                     rtol=reltol, atol=abstol,
                     kwargs...)
    DiffEqBase.build_solution(prob,QuadGKJL(),val,err,retcode = :Success)
end

function DiffEqBase.solve(prob::QuadratureProblem,::HCubatureJL,args...;
                          reltol = 1e-8, abstol = 1e-8,
                          maxiters = typemax(Int),
                          kwargs...)
    p = prob.p
    if isinplace(prob)
        dx = zeros(1)
        f = (x) -> (prob.f(dx,x,p); dx[1])
    else
        f = (x) -> prob.f(x,p)
    end
    @assert prob.batch == 0
    @assert prob.nout == 1
    if prob.lb isa Number
        val,err = hquadrature(f, prob.lb, prob.ub;
                            rtol=reltol, atol=abstol,
                            maxevals=maxiters, initdiv=1)
    else
        val,err = hcubature(f, prob.lb, prob.ub;
                            rtol=reltol, atol=abstol,
                            maxevals=maxiters, initdiv=1)
    end
    DiffEqBase.build_solution(prob,HCubatureJL(),val,err,retcode = :Success)
end

function DiffEqBase.solve(prob::QuadratureProblem,alg::VEGAS,args...;
                          reltol = 1e-8, abstol = 1e-8,
                          maxiters = typemax(Int),
                          kwargs...)
    p = prob.p
    @assert prob.nout == 1
    if prob.batch == 0
        if isinplace(prob)
          dx = zeros(1)
          f = (x) -> (prob.f(dx,x,p); dx[1])
        else
          f = (x) -> prob.f(x,p)
        end
    else
        if isinplace(prob)
          dx = zeros(prob.batch)
          f = (x) -> (prob.f(dx,x',p); dx)
        else
          f = (x) -> prob.f(x',p)
        end
    end
    val,err,chi = vegas(f, prob.lb, prob.ub, rtol=reltol, atol=abstol,
                        maxiter = maxiters, nbins = alg.nbins,
                        ncalls = alg.ncalls, batch=prob.batch != 0, kwargs...)
    DiffEqBase.build_solution(prob,alg,val,err,chi=chi,retcode = :Success)
end

function __init__()
    @require Cubature="667455a9-e2ce-5579-9412-b964f529a492" begin
        function DiffEqBase.solve(prob::QuadratureProblem,
                                  alg::AbstractCubatureJLAlgorithm, args...;
                                  reltol = 1e-8, abstol = 1e-8,
                                  maxiters = typemax(Int),
                                  kwargs...)
            nout = prob.nout
            if nout == 1
                if prob.batch == 0
                    if isinplace(prob)
                        dx = zeros(1)
                        f = (x) -> (prob.f(dx,x,prob.p); dx[1])
                    else
                        f = (x) -> prob.f(x,prob.p)
                    end
                    if prob.lb isa Number
                        if alg isa CubatureJLh
                            val,err = Cubature.hquadrature(f, prob.lb, prob.ub;
                                                           reltol=reltol, abstol=abstol,
                                                           maxevals=maxiters)
                        else
                            val,err = Cubature.pquadrature(f, prob.lb, prob.ub;
                                                           reltol=reltol, abstol=abstol,
                                                           maxevals=maxiters)
                        end
                    else
                        if alg isa CubatureJLh
                            val,err = Cubature.hcubature(f, prob.lb, prob.ub;
                                                         reltol=reltol, abstol=abstol,
                                                         maxevals=maxiters)
                        else
                            val,err = Cubature.pcubature(f, prob.lb, prob.ub;
                                                         reltol=reltol, abstol=abstol,
                                                         maxevals=maxiters)
                        end
                     end
                else
                    if isinplace(prob)
                        f = (x,dx) -> prob.f(dx,x,prob.p)
                    else
                        f = (x,dx) -> (dx .= prob.f(x,prob.p))
                    end
                    if prob.lb isa Number
                        if alg isa CubatureJLh
                            val,err = Cubature.hquadrature_v(f, prob.lb, prob.ub;
                                                             reltol=reltol, abstol=abstol,
                                                             maxevals=maxiters)
                        else
                            val,err = Cubature.pquadrature_v(f, prob.lb, prob.ub;
                                                             reltol=reltol, abstol=abstol,
                                                             maxevals=maxiters)
                        end
                    else
                        if alg isa CubatureJLh
                            val,err = Cubature.hcubature_v(f, prob.lb, prob.ub;
                                                           reltol=reltol, abstol=abstol,
                                                           maxevals=maxiters)
                        else
                            val,err = Cubature.pcubature_v(f, prob.lb, prob.ub;
                                                           reltol=reltol, abstol=abstol,
                                                           maxevals=maxiters)
                        end
                     end
                 end
             else
                 if prob.batch == 0
                     if isinplace(prob)
                         dx = similar(a)
                         f = (x,dx) -> (prob.f(dx,x,p); dx)
                     else
                         f = (x,dx) -> (dx .= prob.f(x,p))
                     end
                     if prob.lb isa Number
                         if alg isa CubatureJLh
                             val,err = Cubature.hquadrature(nout, f, prob.lb, prob.ub;
                                                            reltol=reltol, abstol=abstol,
                                                            maxevals=maxiters)
                         else
                             val,err = Cubature.pquadrature(nout, f, prob.lb, prob.ub;
                                                            reltol=reltol, abstol=abstol,
                                                            maxevals=maxiters)
                         end
                     else
                         if alg isa CubatureJLh
                             val,err = Cubature.hcubature(nout, f, prob.lb, prob.ub;
                                                          reltol=reltol, abstol=abstol,
                                                          maxevals=maxiters)
                         else
                             val,err = Cubature.pcubature(nout, f, prob.lb, prob.ub;
                                                          reltol=reltol, abstol=abstol,
                                                          maxevals=maxiters)
                         end
                      end
                 else
                     if isinplace(prob)
                         f = (x,dx) -> prob.f(dx,x,p)
                     else
                         f = (x,dx) -> (dx .= prob.f(x,p))
                     end
                     if prob.lb isa Number
                         if alg isa CubatureJLh
                             val,err = Cubature.hquadrature_v(nout, f, prob.lb, prob.ub;
                                                              reltol=reltol, abstol=abstol,
                                                              maxevals=maxiters)
                         else
                             val,err = Cubature.pquadrature_v(nout, f, prob.lb, prob.ub;
                                                              reltol=reltol, abstol=abstol,
                                                              maxevals=maxiters)
                         end
                     else
                         if alg isa CubatureJLh
                             val,err = Cubature.hcubature_v(nout, f, prob.lb, prob.ub;
                                                            reltol=reltol, abstol=abstol,
                                                            maxevals=maxiters)
                         else
                             val,err = Cubature.pcubature_v(nout, f, prob.lb, prob.ub;
                                                            reltol=reltol, abstol=abstol,
                                                            maxevals=maxiters)
                         end
                      end
                  end
              end
              DiffEqBase.build_solution(prob,alg,val,err,retcode = :Success)
        end
    end

    @require Cuba="8a292aeb-7a57-582c-b821-06e4c11590b1" begin
        function DiffEqBase.solve(prob::QuadratureProblem,alg::AbstractCubaAlgorithm,
                                  args...;
                                  reltol = 1e-8, abstol = 1e-8,
                                  maxiters = typemax(Int),
                                  kwargs...)
          p = prob.p
          if prob.lb isa Number && prob.batch == 0
              _x = Float64[prob.lb]
          elseif prob.lb isa Number
              _x = zeros(prob.batch)
          elseif prob.batch == 0
              _x = zeros(length(prob.lb))
          else
              _x = zeros(length(prob.lb),prob.batch)
          end
          ub = prob.ub
          lb = prob.lb

          if prob.batch == 0
              if isinplace(prob)
                  f = function (x,dx)
                      prob.f(dx,scale_x!(_x,ub,lb,x),p)
                      dx .*= prod((y)->y[1]-y[2],zip(ub,lb))
                  end
              else
                  f = function (x,dx)
                      dx .= prob.f(scale_x!(_x,ub,lb,x),p) .* prod((y)->y[1]-y[2],zip(ub,lb))
                  end
              end
          else
              if prob.lb isa Number
                  if isinplace(prob)
                      f = function (x,dx)
                          prob.f(dx',scale_x!(view(_x,1:length(x)),ub,lb,x),p)
                          dx .*= prod((y)->y[1]-y[2],zip(ub,lb))
                      end
                  else
                      f = function (x,dx)
                          dx .= prob.f(scale_x!(view(_x,1:length(x))',ub,lb,x),p)' .* prod((y)->y[1]-y[2],zip(ub,lb))
                      end
                  end
              else
                  if isinplace(prob)
                      f = function (x,dx)
                          prob.f(dx',scale_x!(view(_x,1:size(x,1),1:size(x,2)),ub,lb,x),p)
                          dx .*= prod((y)->y[1]-y[2],zip(ub,lb))
                      end
                  else
                      f = function (x,dx)
                          dx .= prob.f(scale_x!(view(_x,1:size(x,1),1:size(x,2)),ub,lb,x),p)' .* prod((y)->y[1]-y[2],zip(ub,lb))
                      end
                  end
              end
          end

          ndim = length(prob.lb)

          nvec = prob.batch == 0 ? 1 : prob.batch

          if alg isa CubaVegas
              out = Cuba.vegas(f, ndim, prob.nout; rtol = reltol,
                               atol = abstol, nvec = nvec,
                               maxevals = maxiters, kwargs...)
          elseif alg isa CubaSUAVE
              out = Cuba.suave(f, ndim, prob.nout; rtol = reltol,
                               atol = abstol, nvec = nvec,
                               maxevals = maxiters, kwargs...)
          elseif alg isa CubaDivonne
              out = Cuba.divonne(f, ndim, prob.nout; rtol = reltol,
                                 atol = abstol, nvec = nvec,
                                 maxevals = maxiters, kwargs...)
          elseif alg isa CubaCuhre
              out = Cuba.cuhre(f, ndim, prob.nout; rtol = reltol,
                               atol = abstol, nvec = nvec,
                               maxevals = maxiters, kwargs...)
          end

          if prob.nout == 1
              val = out.integral[1]
          else
              val = out.integral
          end

          DiffEqBase.build_solution(prob,alg,val,out.error,
                         chi=out.probability,retcode = :Success)
        end
    end
end

export QuadGKJL, HCubatureJL, VEGAS
export CubatureJLh, CubatureJLp
export CubaVegas, CubaSUAVE, CubaDivonne, CubaCuhre
end # module


text:
# module MySQL_Octo.SQL

function connect(; kw...)::MySQLAdapter # throws(MySQLInternalError)
    adapter = MySQLAdapter(nothing)
    options = Dict(kw)
    opts = Dict(MYSQL_OPT_RECONNECT => Int(get(options, :reconnect, true)))
    args = Vector()
    for key in (:host, :user, :pass, :db)
        haskey(options, key) && push!(args, options[key])
    end
    adapter.handle = mysql_connect(args..., opts=opts)
    adapter
end

function disconnect(adapter::QueryBuilders.AbstractAdapter)
    mysql_disconnect(adapter.handle)
end

ext: jl


text:
# Tools for analyzing domains
include("utils.jl")
include("static.jl")


text:
# All numerical values should be here. No hard-coded values
# elsewhere in the Sesi module

# The design_ functions create the parameter dictionary. This contains
# design parameters that do not change in time.

function design_base!()
    p = Dict()
    p[:utc_offset] = -7
    # These will be toggled on as they are added to the model
    p[:cbp] = false
    p[:carbon] = false
    p[:peak] = false
    p[:sw] = false
    p[:cap_thstorage] = false
    p[:cap_machines] = false
    p[:ev] = false
    p[:umLoadsL2] = true # set this to false to use L1 norm instead for unmet loads

    return p
end

function design_water!(p::Dict)
    # chilled water storage capacity
    p[:coldTankMax] = 90.e3 # ton-hr # 90
    p[:coldTankSafety] = 0.05 # safety zone (%)
    p[:cwTankInit] = 0.1*p[:coldTankMax] # ton-hr
    p[:S_c_dot_max] = 18.e3 # ton

    # hot water storage capacity
    p[:hotTankMax] = 600. # mmbtu
    p[:hotTankSafety] = 0.05 # safety zone (%)
    p[:hwTankInit] = 0.1*p[:hotTankMax] # mmbtu
    p[:S_h_dot_max] = 120. # mmbtu/hr

    # machines
    # there are 3 HRCs, 4 chillers and 3 heaters. For now we assume one of each and scale accordingly
    # When data does not vary, we use a scalar instead of a vector
    p[:HRCCAP] = 2500.*3# data[:HRC1CAP]*3 # tons
    p[:chillerCAP] = 3000.*4 # data[:C6CAP]*4 # tons
    p[:heaterCAP] = 60.55*3 # data[:H1CAP]*3 # mmbtu
    p[:HRCPE] = 1.32703695050335 #data[:HRC1PE] # kWh/ton-hr
    p[:heaterPE] = 0.85 # data[:H1PE] # %HHV
    p[:heaterEPE] = 2.0 # data[:H1ePE] # kWh/mmbtu
    p[:chillerPE] = 0.45566 # kW/ton - mean value in 2016 - will be used if efficiency is not supplied in the timeseries data
    p[:HRCHotToColdRatio] = 41. / 2500. # mmbtu/ton-hr - my assumption based on CEPOM

    p[:swPenalty] = 1e-8 # $/kW

    # capital costs
    # 7.4e6 for the three tanks - assume equal split -> 2.46e6 per tank
    # Assume a lifetime of 20 years
    p[:capCostCold] = 2.46666666e6 / p[:coldTankMax] / (20*365*24) # $/ton/hr
    p[:capCostHot] = 2 * 2.46666666e6 / p[:hotTankMax] / (20*365*24) # $/mmbtu/hr

    # unmet load cost
    p[:umCold] = 1.32 * 10 # kWh/ton-hr * $/kWh
    p[:umHot] = 1.32 * 10 * 2500. / 41. # kWh/ton-hr * $/kWh * ton-hr/mmbtu

    return p
end

function design_storage!(p::Dict)
    # battery
    p[:capitalCostBattery] = 400 # $/kWh # 400
    p[:elecStorageMax] = 10.e3 # kWh
    p[:elecTransferMax] = p[:elecStorageMax]/2
    p[:elecTransferEta] = 1-0.064500
    p[:elecStorageInit] = p[:elecStorageMax] # kWh
    p[:lifetimeBattery] = 3000 #[number of cycles]
    # this is intentionnally left very small and is needed numerically to avoid overusing the battery
    p[:usageCostBattery] = p[:capitalCostBattery] / p[:lifetimeBattery] # $/kWh
    return p
end

function design_prices!(p::Dict)
    p[:gasPrice] = 5.40 # $/mmbtu
    #p[:demandCharge] = 4.56# $/kW

    # data from SESI Performance Review (recieved 2017-09-15)
    prices = [3.38,3.38,3.76,3.76,3.76,3.76,3.76,3.76,3.55,3.55,3.55,3.55,2.63,
	      2.63,3.18,3.18,3.18,3.18,3.18,3.18,3.18,3.18,2.98,2.98,2.71,2.71,
	      3.03,3.03,3.03,3.03,3.03,3.03,3.03,3.03,3.03,3.03,3.25,3.25,3.67,
	      3.67,3.67,3.67,3.67,3.67,3.67,3.67,3.67,3.67,3.44,3.44,4.28,4.28,
	      4.28,3.97,3.97,3.97,3.97,3.97,3.97,3.97,4.22,4.22,4.79,4.79,4.79,
	      4.79,4.79,4.79,4.79,4.79,4.79,4.79,4.06,4.06,4.06,4.06,4.06,4.06,
	      4.06,4.06,4.06,4.06,4.06,4.06,4.05,4.05,4.05,4.05,4.75,4.75,4.75,
	      4.75,4.75,4.64,4.64,4.64,4.61,4.61,4.61,4.61,4.77,4.77,4.77,4.77,
	      4.77,4.66,4.66,4.66,4.64,4.64,6.08,6.08,6.08,6.08,6.08,6.08,5.37,
	      5.37,5.37,5.37,5.95,5.95,7.4,7.4,7.4,7.4,7.4,7.39,7.39,6.59,6.59,
	      6.59,6.54,6.54,8.31,8.31,8.31,8.31,8.31,8.31,8.31, 8.31, 8.31, 8.31,
          8.32, 8.32, 8.79, 8.79, 8.79, 8.79, 8.79, 8.79, 8.79, 8.31, 8.31, 8.31,
          8.31]
    dates = [Dates.DateTime("2006-01-01") + Dates.Month(ii) for ii in 0:157]
    p[:demandCharge] = Dict(zip(dates, prices))
    return p
end

function design_carbon!(p::Dict)
    # kg/MW -> ton/kW
    p[:carbon_units] = 1e-6
    # ton/mmbtu
    p[:carbonIntensityGas] = 14.46*44/12*1e-3;
    # carbon intenstiy gas - according to this
    # https://www.epa.gov/energy/greenhouse-gases-equivalencies-calculator-calculations-and-references

     # $/ton
    p[:carbonPrice] = 100;
end

max_stars_repo_name: jdechalendar/sesi

max_issues_repo_name: jdechalendar/sesi

max_forks_repo_name: jdechalendar/sesi


text:
using Toxcore
using GLVisualize
using GLWindow
using Reactive
using GeometryTypes
using GLAbstraction
using ColorTypes
using FileIO
using ImageIO
using MeshIO
using WavefrontObj
using Meshes
using NPZ
using GLFW
using ModernGL

include("helper.jl")
function xy_data(x,y,i, N)
    x = ((x/N)-0.5f0)*i
    y = ((y/N)-0.5f0)*i
    r = sqrt(x*x + y*y)
    Float32(sin(r)/r)
end
generate(i, N) = Float32[xy_data(Float32(x),Float32(y),Float32(i), N) for x=1:N, y=1:N]

immutable Message
    leftaligned::Bool # kinda silly place, but it works for now
    color::RGBA{Float32}
    text::UTF8String
end
global const MESSAGES = Input(Message(false, RGBA(1f0,0.2f0,0.5f0,0.7f0), "msg"))

function message_area(yoffset, y_scroll, m_area, screen_width, screen_height, left_aligned)
    yposition    = yoffset+(round(Int, y_scroll)*50) # for scrolling and positioning
    xposition    = left_aligned ? 50 : (m_area.w - 50 - screen_width)
    Rectangle(xposition, yposition, screen_width, screen_height)
end
const edit_value_names = (
    :color,
    :grid_min,
    :grid_max,
    :algorithm,
    :style,
    :technique,
    :scale,
    :norm,
    :absorption,
    :light_position,
    :isovalue
)

is_screen_active(v0, ek, esc) = (esc && return false; ek && return true; v0)

function create_edit_screen(parent, robj, namefilter=edit_value_names)
    frame       = 20
    key_string  = ""
    yoffset     = 10
    vizzes      = RenderObject[]
    max_screenwidth = 0
    screenheigth    = 0
    for (key, value) in filter((k,v)->in(k, namefilter), robj.uniforms)
        if applicable(vizzedit, value, parent.inputs)

            signal, editvizz = vizzedit(value, parent.inputs)
            robj[key]        = signal
            keylabel         = visualize(string(key)*": ")

            boundingbox      = keylabel.boundingbox.value
            bbsize           = boundingbox.maximum - boundingbox.minimum
            key_width        = round(Int, bbsize[1])
            key_height       = round(Int, bbsize[2])
            move             = -boundingbox.minimum+Float32(frame/2f0)+Vec3f0(0, yoffset, 0)
            keylabel[:model] = translationmatrix(Vec3f0(move[1], move[2], 0f0))
            keylabel[:preferred_camera] = :fixed_pixel

            boundingbox      = editvizz.boundingbox.value
            bbsize           = boundingbox.maximum - boundingbox.minimum
            edit_width       = round(Int, bbsize[1])
            edit_height      = round(Int, bbsize[2])
            move             = -boundingbox.minimum+Float32(frame/2f0)+Vec3f0(key_width, yoffset, 0)
            editvizz[:model] = translationmatrix(Vec3f0(move[1], move[2], 0f0))
            editvizz[:preferred_camera] = :fixed_pixel
            push!(vizzes, editvizz, keylabel)

            yoffset         += max(edit_height, key_height)+50
            max_screenwidth = max(max_screenwidth, key_width+edit_width)
        end
    end

    buttonspressed  = parent.inputs[:buttonspressed]

    edit_key            = lift(==, buttonspressed, [GLFW.KEY_LEFT_CONTROL, GLFW.KEY_E])
    escape_key          = lift(==, buttonspressed, [GLFW.KEY_ESCAPE])
    edit_key_active     = keepwhen(edit_key, false, edit_key)

    mouse_at_edit_time  = sampleon(edit_key_active, parent.inputs[:mouseposition])
    is_active           = foldl(is_screen_active, false, edit_key, escape_key)
    area                = lift(mouse_at_edit_time, is_active) do mousepos, active
        !active && return Rectangle(0,0,0,0)
        Rectangle(round(Int, mousepos[1]), round(Int, mousepos[2]), max_screenwidth+frame, yoffset)
    end
    edit_screen         = Screen(parent, area=area)
    view(
        visualize(lift(zeroposition, area), color=RGBA(0f0,0f0,0f0,1f0)),
        edit_screen, method=:fixed_pixel
    )
    view(vizzes, edit_screen)
end

function create_screens(yoffset, robjs_alignment, scroll_window, main_screen)
    frame = 40
    robjs, alignement, color = robjs_alignment
    for robj in robjs
        yoffset -= 30
        camera_position = Vec3f0(2)
        camera_lookat   = Vec3f0(0)
        boundingbox     = robj.boundingbox.value
        bbsize          = boundingbox.maximum - boundingbox.minimum
        if endswith(string(robj[:preferred_camera]), "_pixel") # terrible way of working around the lack of a unit system
            screen_height           = round(Int, bbsize[2])+frame
            screen_width            = round(Int, bbsize[1])+frame
            move                    = -boundingbox.minimum+Float32(frame/2f0)
            robj[:model]            = translationmatrix(Vec3f0(move[1], move[2], 0f0))
            robj[:preferred_camera] = :fixed_pixel #better fixate this
        else
            screen_height     = 700 # for now, all 3D windows will have a fixed size
            screen_width      = lift(x->round(Int, x.w*0.9), main_screen.area)
            camera_position   = boundingbox.minimum+(bbsize*1.5f0)
            camera_lookat     = boundingbox.minimum+(bbsize*0.5f0)
        end
        yoffset     -= screen_height
        area        = lift(message_area, yoffset, scroll_window, main_screen.area, screen_width, screen_height, alignement)
        new_screen  = Screen(main_screen, area=area, position=camera_position, lookat=camera_lookat)
        #view(
        #    visualize(lift(zeroposition, area), color=color),
        #    new_screen, method=:fixed_pixel
        #)
        view(robj, new_screen)
        #create_edit_screen(new_screen, robj)
    end
    yoffset
end

function handle_drop(files::Vector{UTF8String})
    files = map(File, files)
    (RenderObject[visualize(f) for f in files], false, RGBA(1f0,1f0,1f0,0.7f0))
end

function visualize_source(source)
    value = save_eval(source)
    if isa(value, RenderObject)
        return value
    else
        try
            return visualize(value)
        catch e # ultra terrible way of trying to find out if there is a default visulization
            return visualize("error: $e", preferred_camera=:fixed_pixel)
        end
    end
end

function GLVisualize.visualize(julia_source::File{:jl})
    source = readall(abspath(julia_source))
    visualize_source(source)
end
function GLVisualize.visualize(npzfile::File{:npz}, style::Symbol=:default; kw_args...)
    volume = npzread(abspath(npzfile))["data"]
    volume = volume./256f0
    visualize(volume, Style{style}(), visualize_default(volume, style, kw_args))
end

function visualize_message(msg::Message)
    text = msg.text
    vizz = "error"
    if startswith(text, "jl\"") && endswith(text, "\"") # its julia code
        vizz = visualize_source(text[4:end-1])
    else # its just text
        vizz = visualize(text, preferred_camera=:fixed_pixel)
    end
    return ([vizz], msg.leftaligned, msg.color) # this is what the insertinto screen function wants!
end

function main()
    RS, renderloop = Screen()
    # Try to load the tox settings
    my_tox = 0

    try
        savefile = open(Pkg.dir("Toxcore", "test", "bot_savedata.binary"), "r")
        savedata = readbytes(savefile)
        close(savefile)

        default_options = tox_options_default()

        options = Tox_Options(default_options.ipv6_enabled,
                            default_options.udp_enabled,
                            default_options.proxy_type,
                            default_options.proxy_host,
                            default_options.proxy_port,
                            default_options.start_port,
                            default_options.end_port,
                            default_options.tcp_port,
                            TOX_SAVEDATA_TYPE_TOX_SAVE,
                            pointer(savedata),
                            length(savedata))

        my_tox = tox_new(options)

        info("Previous bot instance found. Reusing it!")
    catch e
        println(e)
        #Create a default Tox
        my_tox = tox_new()
        info("Created new bot instance")
    end

    # register the callbacks
    tox_callback_friend_request(my_tox, OnToxFriendRequest, C_NULL)
    tox_callback_friend_message(my_tox, OnToxFriendMessage, C_NULL)

    # print own address
    info("Here is my address")
    println(convert(ASCIIString, tox_self_get_address(my_tox)))

    # define user details
	tox_self_set_name(my_tox, "SamD")
    tox_self_set_status_message(my_tox, "Whatup yo!")
    Toxcore.CInterface.tox_self_set_status(my_tox, Toxcore.CInterface.TOX_USER_STATUS_NONE)
    # bootstrap from the node defined above
    if !tox_bootstrap(my_tox)
        println("Failed to bootstrap.")
        exit()
    end

    # get the friend list
    friendlist = tox_self_get_friend_list(my_tox)
    info("I have $(length(friendlist)) friend(s)")
    currentfriend = Cuint(0)
    for friend in friendlist
        fname = tox_friend_get_name(my_tox, friend)
        println(fname)
        fname == "SimonD" && (currentfriend = Cuint(friend))
    end
    println(currentfriend)
    println(tox_friend_get_name(my_tox, currentfriend))

    write_area, main_area   = y_partition(RS.area, 20.0)
    write_screen            = Screen(RS, area=write_area)
    main_screen             = Screen(RS, area=main_area)

    text = visualize("write something \n", model=translationmatrix(Vec3f0(0, write_area.value.h-40,0)))
    background, cursor_robj, text_sig = vizzedit(text[:glyphs], text, write_screen.inputs)
    buttonspressed  = write_screen.inputs[:buttonspressed]
    enter_pressed   = lift(==, buttonspressed, [GLFW.KEY_ENTER])
    system_message  = Input(utf8("jl\"file\"osmosisheader.png\"\""))
    message         = sampleon(keepwhen(enter_pressed, true, enter_pressed), text_sig)
    message         = merge(system_message, message)

    mymessages      = lift(message) do msg
        tox_friend_send_message(my_tox, currentfriend, msg)
        Message(false, RGBA(1f0,1f0,1f0,0.7f0), msg)
    end

    view(visualize(lift(x->Rectangle(0,0,x.w, x.h), write_screen.area), color=RGBA(0f0,0f0,0f0,0.7f0)), write_screen, method=:fixed_pixel)

    view(background,    write_screen)
    view(text,          write_screen)
    view(cursor_robj,   write_screen)

    scroll_window   = foldl(+, 0.0, keepwhen(main_screen.inputs[:mouseinside], 0.0, main_screen.inputs[:scroll_y]))

    drop_robjs      = lift(handle_drop, RS.inputs[:droppedfiles])

    all_msgs        = merge(mymessages, MESSAGES)

    msg_robj        = lift(visualize_message, all_msgs)
    all_robjs       = merge(msg_robj, drop_robjs)

    foldl(
        create_screens,
        main_area.value.h,
        all_robjs,
        Input(scroll_window), Input(main_screen)
    )
    push!(system_message, utf8("jl\"file\"osmosisheader.png\"\""))

    glClearColor(1,1,1,1)
    renderloop(()-> tox_iterate(my_tox))

    savedata = tox_get_savedata(my_tox)
    tox_kill(my_tox)

    savefile = open(Pkg.dir("Toxcore", "test", "bot_savedata.binary"), "w")
    write(savefile, savedata)
    close(savefile)

    info("Bot instance saved")

end

main()


text:
## ----------  Retired

# RetiredSolution() = RetiredSolution(nothing, nothing);

# function init_test_retired_solution()
#     kPrimeFct(x) = 0.5 * x;
#     cFct(x) = 0.3 * x;
#     return RetiredSolution(kPrimeFct, cFct)
# end

# kprime_fct(sol :: RetiredSolution; eIdx = 0) = sol.kPrimeFct;
# cons_fct(sol :: RetiredSolution; eIdx = 0) = sol.cFct;
# kprime(sol :: RetiredSolution, k) = kprime_fct(sol)(k);
# consumption(sol :: RetiredSolution, k) = cons_fct(sol)(k);

## ------------  Worker

init_worker_solution(n :: Integer) =
    WorkerSolution(Vector{Any}(undef, n), Vector{Any}(undef, n));
# WorkerSolution() = WorkerSolution(nothing, nothing);

# n is the number of efficiency states
# n = 1 in retirement
function init_test_worker_solution(n :: Integer = 4)
    kPrimeFctV = [x -> (0.25 + 0.05 * j) * x  for j = 1 : n];
    cFctV = [x -> (0.3 + 0.1 * j) * x  for j = 1 : n];
    return WorkerSolution(kPrimeFctV, cFctV)
end

kprime_fct(sol :: WorkerSolution, eIdx) = sol.kPrimeFctV[eIdx];
cons_fct(sol :: WorkerSolution, eIdx) = sol.cFctV[eIdx];
kprime(sol :: WorkerSolution, k, eIdx) = kprime_fct(sol, eIdx)(k);
consumption(sol :: WorkerSolution, k, eIdx) = cons_fct(sol, eIdx)(k);
set_kprime_fct!(sol :: WorkerSolution, eIdx, kpFct) = sol.kPrimeFctV[eIdx] = kpFct;
set_cons_fct!(sol :: WorkerSolution, eIdx, kpFct) = sol.consFctV[eIdx] = kpFct;

## ------------  Complete

function init_solution(Twork :: Integer, T :: Integer, n :: Integer)
    workV = [init_worker_solution(n)  for t = 1 : T];
    retireV = [init_worker_solution(1) for t = (Twork+1) : T];
    return Solution(Twork, vcat(workV, retireV))
end

function init_test_solution(Twork :: Integer, T :: Integer)
    workV = [init_test_worker_solution(4)  for t = 1 : Twork];
    retireV = [init_test_worker_solution(1) for t = (Twork+1) : T];
    return Solution(Twork, vcat(workV, retireV))
end

## -----------  Helpers

workspan(sol :: Solution) = sol.workSpan;
isretired(sol :: Solution, t :: Integer) = (t > workspan(sol));
# retire_idx(sol :: Solution, t :: Integer) = t - workspan(sol);

function get_solution(sol :: Solution, t :: Integer)
    solOut = sol.solV[t];
end

kprime(sol :: Solution, t :: Integer, k, eIdx) =
    kprime_fct(sol, t, eIdx)(k);
consumption(sol :: Solution, t :: Integer, k, eIdx) =
    cons_fct(sol, t, eIdx)(k);

kprime_fct(sol :: Solution, t :: Integer, eIdx) =
    kprime_fct(get_solution(sol, t), eIdx);
cons_fct(sol :: Solution, t :: Integer, eIdx) =
    cons_fct(get_solution(sol, t), eIdx);

function set_solution!(sol :: Solution, t :: Integer, wkSol :: WorkerSolution)
    sol.solV[t] = wkSol;
end

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


text:
function predictorstep!(Aforward::Vector{Float64},Qforward::Vector{Float64},
    Abackward::Vector{Float64},Qbackward::Vector{Float64},A::Vector{Float64},
    Q::Vector{Float64},h::Float64,k::Float64,Fp::Vector{Float64},colsint::Vector{Int8},
    acolspre::Vector{Int8},qcolspre::Vector{Int8},diff::Float64,μ::Float64,rho::Float64)
    Aforward .= (0.5.*(A[colsint.+1] .+ A[colsint]) .-
        0.5.*h./k.*(Fp[acolspre.+1] .- Fp[acolspre]));
    Qforward .= (0.5.*(Q[colsint.+1] .+ Q[colsint]) .- 0.5.*h./k.*(Fp[qcolspre.+1] .- Fp[qcolspre]) .-
        0.5.*h.*diff.*π.*μ./rho.*(0.5.*(Q[colsint.+1]./A[colsint.+1] .+ Q[colsint]./A[colsint])));
    Abackward .= (0.5.*(A[colsint] .+ A[colsint.-1]) .-
        0.5.*h./k.*(Fp[acolspre] .- Fp[acolspre.-1]));
    Qbackward .= (0.5.*(Q[colsint] .+ Q[colsint.-1]) .- 0.5.*h./k.*(Fp[qcolspre] .- Fp[qcolspre.-1]) .-
        0.5.*h.*diff.*π.*μ./rho.*(0.5.*(Q[colsint]./A[colsint] .+ Q[colsint.-1]./A[colsint.-1])));
end

max_stars_repo_name: dcanuto/CardioModeling

max_issues_repo_name: dcanuto/CardioModeling

max_forks_repo_name: dcanuto/CardioModeling


text:
module aoc_02
    using Test
    export read_input, part1, part2
    export test_part1, test_part2, test
    export input, demo

    const input_r = r"(\d+)-(\d+) ([a-z]): ([a-z]+)"

    function read_input(filename = "input.txt")
        lines = readlines(filename)
        # for line in eachline(filename)
        # for line in lines
        #end
        [parse_line(line) for line in eachline(filename)]
        # lines
    end

    function parse_line(line)
        m = match( input_r, line )
        # policy = Regex("$(m.captures[3]){$(m.captures[1]),$(m.captures[2])}")
        policy = parse(Int,m.captures[1]):parse(Int,m.captures[2])
        (policy, m.captures[3], m.captures[4])
    end

    input = read_input("input.txt")
    demo = read_input("demo.txt")

#= Each line gives the password policy and then the password. The password policy indicates the lowest and highest number of times a given letter must appear for the password to be valid. For example, 1-3 a means that the password must contain a at least 1 time and at most 3 times.

In the above example, 2 passwords are valid. The middle password, cdefg, is not; it contains no instances of b, but needs at least 1. The first and third passwords are valid: they contain one a or nine c, both within the limits of their respective policies.

How many passwords are valid according to their policies? =#

    function part1(input = input)
        sum( [sum(Vector{Char}(l[3]) .== l[2][1]) ∈ l[1] for l in input] )
    end

    function test_part1()
        @test part1( demo ) == 2
        @test part1() == 439
    end

    function part2(input = input)
        total = 0
        for line in input
            r = line[1]
            total += xor(line[3][r.start] == line[2][1], line[3][r.stop] == line[2][1])
        end
        total
    end

    function test_part2()
        @test part2( demo ) == 1
        @test part2() == 584
    end
end


text:
###
# DDUS tests relying on QP funcitonality
####
# Merge these into main test suite when default solver in JuMPeR supports QPs

using DDUS
using FactCheck
using JuMPeR

include("test_helpers.jl")  #loads up generic functionality

facts("portTest2  UCS bounds") do
	srand(8675309); data = randn(500, 2)
	w = UCSOracle(data, .1, .1, .1)
	portTest(w, -2.4604223389522866, [0.530985977658841, 0.46901402234115896], TOL=1e-6,
			unc_lower=[-1e6, -1e6], unc_upper=[1e6, 1e6])
end


text:
"""
Mapping from libclang types to Julia types
"""
const CLANG_JULIA_TYPEMAP = Dict(
    CXType_Void             => :Cvoid,
    CXType_Bool             => :Bool,
    CXType_Char_U           => :UInt8,
    CXType_UChar            => :Cuchar,
    CXType_Char16           => :UInt16,
    CXType_Char32           => :UInt32,
    CXType_UShort           => :UInt16,
    CXType_UInt             => :UInt32,
    CXType_ULong            => :Culong,
    CXType_ULongLong        => :Culonglong,
    CXType_UInt128          => :UInt128,
    CXType_Char_S           => :UInt8,
    CXType_SChar            => :UInt8,
    CXType_WChar            => :Char,
    CXType_Short            => :Int16,
    CXType_Int              => :Cint,
    CXType_Long             => :Clong,
    CXType_LongLong         => :Clonglong,
    CXType_Int128           => :Int128,
    CXType_Float            => :Cfloat,
    CXType_Double           => :Cdouble,
    CXType_LongDouble       => :Float64,
    CXType_NullPtr          => :C_NULL,
    # CXType_Float128         => ?
    # CXType_Half             => ?
    # CXType_Float16          => :Float16
    CXType_Complex          => :Complex,
    CXType_Pointer          => :Cvoid,
    CXType_BlockPointer     => :Cvoid,
    CXType_Elaborated       => :Cvoid,
    CXType_Invalid          => :Cvoid,
    :size_t                 => :Csize_t,
    :ptrdiff_t              => :Cptrdiff_t,
    :uint64_t               => :UInt64,
    :uint32_t               => :UInt32,
    :uint16_t               => :UInt16,
    :uint8_t                => :UInt8,
    :int64_t                => :Int64,
    :int32_t                => :Int32,
    :int16_t                => :Int16,
    :int8_t                 => :Int8,
    :uintptr_t              => :Csize_t,
    :tm                     => :Ctm,
    :time_t                 => :Ctime_t,
    :clock_t                => :Cclock_t,
    :wchar_t                => :Cwchar_t,
    )

const INT_CONVERSION = Dict(
    :Cint   => Int32,
    :Cuint  => UInt32,
    :UInt64 => UInt64,
    :UInt32 => UInt32,
    :UInt16 => UInt16,
    :UInt8  => UInt8,
    :Int64  => Int64,
    :Int32  => Int32,
    :Int16  => Int16,
    :Int8   => Int8,
    )

target_type(s::Symbol) = s
function target_type(e::Expr)
    if e.head == :curly && e.args[1] == :Ptr
        return target_type(e.args[2])
    elseif  e.head == :curly && e.args[1] == :NTuple
        return target_type(e.args[3])
    else
        error("target_type: don't know how to handle $e")
    end
end
target_type(q) = error("target_type: don't know how to handle $q")

"""
    typesize(t::CLType) -> Int
    typesize(c::CLCursor) -> Int
Return field declaration size.
"""
typesize(t::CLType) = clang_Type_getSizeOf(t)
typesize(t::CLTypedef) = typesize(typedecl(t))
typesize(t::CLElaborated) = typesize(get_named_type(t))
typesize(t::CLConstantArray) = element_num(t)
typesize(t::CLInvalid) = (@warn("  incorrect typesize for CXType_Invalid field"); 0)
typesize(c::CLTypedefDecl) = typesize(underlying_type(c))

"""
    clang2julia(t::CLType) -> Symbol/Expr
Convert libclang cursor/type to Julia.
"""
function clang2julia(t::CLType)
    type_kind = kind(t)
    !haskey(CLANG_JULIA_TYPEMAP, type_kind) && error("No CXType translation available for: $type_kind")
    return CLANG_JULIA_TYPEMAP[type_kind]
end

# get the original named type if the type is CXType_Elaborated
clang2julia(t::CLElaborated) = clang2julia(get_named_type(t))

# CXType_Enum types are mapped into Cenums, so we only need to extract enum's names.
clang2julia(t::CLEnum) = spelling(t) |> split |> last |> Symbol

function clang2julia(t::Union{CLRecord,CLTypedef})
    cursor_name = spelling(typedecl(t))
    type_name = isempty(cursor_name) ? spelling(t) : cursor_name  # handle anonymous typedef records
    type_sym = Symbol(type_name)
    return get(CLANG_JULIA_TYPEMAP, type_sym, type_sym)
end

"""
    clang2julia(t::CLPointer)
Pointers are translated to `Ptr`s.
"""
function clang2julia(t::CLPointer)
    ptree = pointee_type(t)
    ptree_kind = kind(ptree)
    (ptree_kind == CXType_Char_U || ptree_kind == CXType_Char_S) && return :Cstring
    ptree_kind == CXType_WChar && return :Cwstring
    Expr(:curly, :Ptr, clang2julia(ptree))
end

"""
    clang2julia(t::CLUnexposed)
Unexposed Clang types are translated to the symbol of its cursor name(if exist).
"""
function clang2julia(t::CLUnexposed)
    cursor_name = spelling(typedecl(t))
    isempty(cursor_name) ? :Cvoid : Symbol(cursor_name)
end

"""
    clang2julia(t::CLConstantArray)
`ConstantArray`s are translated to `NTuple`s.
"""
function clang2julia(t::CLConstantArray)
    arrsize = element_num(t)
    eltype = clang2julia(element_type(t))
    return :(NTuple{$arrsize, $eltype})
end

"""
    clang2julia(t::CLIncompleteArray)
`IncompleteArray`s are translated to pointers, so one need to deal with the byte offsets directly.
"""
clang2julia(t::CLIncompleteArray) = Expr(:curly, :Ptr, clang2julia(element_type(t)))

"""
    clang2julia(c::CLCursor) -> Symbol/Expr
Convert libclang cursor/type to Julia.
"""
clang2julia(c::CLCursor) = clang2julia(type(c))
clang2julia(c::CLUnionDecl) = type(c) |> largestfield |> clang2julia
clang2julia(c::CLEnumDecl) = integer_type(c) |> clang2julia

function clang2julia(c::CLTypeRef)
    reftype = getref(c)
    refdef = getdef(reftype)
    refdefKind = kind(refdef)
    if isnull(refdef) || refdefKind == CXCursor_InvalidFile || refdefKind == CXCursor_FirstInvalid
        return :Cvoid
    else
        return Symbol(spelling(reftype))
    end
end


text:
@testset "SparseMatrixCSC" begin
    maxnz=5
    maxrows=5
    maxcols=5

    for T in (Int32,Int64,Float32,Float64)
        I = Vector{Int}()
        J = Vector{Int}()
        V = Vector{T}()
        for (ik, jk, vk) in zip(rand(1:maxrows, maxnz), rand(1:maxcols, maxnz), rand(1:T(maxnz), maxnz))
            push_coo!(I,J,V,ik,jk,vk)
        end
        finalize_coo!(I,J,V,maxcols,maxrows)
        CSC = sparse(I, J, V, maxcols,maxrows)

        @test convert(SparseMatrixCSC, CSC) === CSC

        @test hasrowmajororder(CSC)  == false
        @test hascolmajororder(CSC) == true
        @test getptr(CSC)           == CSC.colptr
        @test getindices(CSC)       == rowvals(CSC)

        for col = 1:maxcols
            for j in nzrange(CSC, col)
                @test nonzeros(CSC)[j] == CSC[rowvals(CSC)[j], col]
            end
        end

        @test size(CSC) == (maxrows,maxcols)

        @test nnz(CSC) == count(!iszero, CSC) <= maxnz

    end

end


text:
using HMCExamples

HMCExamples.main_rbc_1_joint(ARGS)

max_stars_repo_name: HighDimensionalEconLab/HMCExamples

max_issues_repo_name: HighDimensionalEconLab/HMCExamples

max_forks_repo_name: HighDimensionalEconLab/HMCExamples


text:
export BasicDQNLearner

using Random
using Flux

"""
    BasicDQNLearner(;kwargs...)

See paper: [Playing Atari with Deep Reinforcement Learning](https://www.cs.toronto.edu/~vmnih/docs/dqn.pdf)

This is the very basic implementation of DQN. Compared to the traditional Q learning, the only difference is that,
in the updating step it uses a batch of transitions sampled from an experience buffer instead of current transition.
And the `approximator` is usually a [`NeuralNetworkApproximator`](@ref).
You can start from this implementation to understand how everything is organized and how to write your own customized algorithm.
# Keywords
- `approximator`::[`AbstractApproximator`](@ref): used to get Q-values of a state.
- `loss_func`: the loss function to use. TODO: provide a default [`huber_loss`](@ref)?
- `γ::Float32=0.99f0`: discount rate.
- `batch_size::Int=32`
- `min_replay_history::Int=32`: number of transitions that should be experienced before updating the `approximator`.
- `rng=Random.GLOBAL_RNG`
"""
mutable struct BasicDQNLearner{Q,F,R} <: AbstractLearner
    approximator::Q
    loss_func::F
    γ::Float32
    batch_size::Int
    min_replay_history::Int
    rng::R
    loss::Float32
end

Flux.functor(x::BasicDQNLearner) = (Q = x.approximator,), y -> begin
    x = @set x.approximator = y.Q
    x
end

(learner::BasicDQNLearner)(env) =
    env |>
    get_state |>
    x ->
        send_to_device(device(learner.approximator), x) |>
        learner.approximator |>
        send_to_host

function BasicDQNLearner(;
    approximator::Q,
    loss_func::F,
    γ = 0.99f0,
    batch_size = 32,
    min_replay_history = 32,
    rng = Random.GLOBAL_RNG,
) where {Q,F}
    BasicDQNLearner{Q,F,typeof(rng)}(
        approximator,
        loss_func,
        γ,
        batch_size,
        min_replay_history,
        rng,
        0.0,
    )
end

function RLBase.update!(learner::BasicDQNLearner, T::AbstractTrajectory)
    length(T[:terminal]) < learner.min_replay_history && return

    inds = rand(learner.rng, 1:length(T[:terminal]), learner.batch_size)

    batch = (
        state = consecutive_view(T[:state], inds),
        action = consecutive_view(T[:action], inds),
        reward = consecutive_view(T[:reward], inds),
        terminal = consecutive_view(T[:terminal], inds),
        next_state = consecutive_view(T[:next_state], inds),
    )

    update!(learner, batch)
end

function RLBase.update!(learner::BasicDQNLearner, batch::NamedTuple)

    Q = learner.approximator
    D = device(Q)
    γ = learner.γ
    loss_func = learner.loss_func

    batch_size = nframes(batch.terminal)

    s = send_to_device(D, batch.state)
    a = batch.action
    r = send_to_device(D, batch.reward)
    t = send_to_device(D, batch.terminal)
    s′ = send_to_device(D, batch.next_state)

    a = CartesianIndex.(a, 1:batch_size)

    gs = gradient(params(Q)) do
        q = Q(s)[a]
        q′ = vec(maximum(Q(s′); dims = 1))
        G = r .+ γ .* (1 .- t) .* q′
        loss = loss_func(G, q)
        ignore() do
            learner.loss = loss
        end
        loss
    end

    update!(Q, gs)
end


text:
"""
Tucker decomposition of a N-mode tensor.
"""
struct Tucker{T<:Number, N} <: TensorDecomposition{T, N}
    factors::NTuple{N, Matrix{T}}   # factor matrices
    core::Array{T, N}               # core tensor
    props::Dict{Symbol, Any}        # extra properties

    Tucker{T, N}(factors::NTuple{N, Matrix{T}}, core::AbstractArray{T, N}) where {T<:Number, N} =
        new{T, N}(factors, core, Dict{Symbol, Any}())
end

Tucker(factors::NTuple{N, Matrix{T}}, core::AbstractArray{T, N}) where {T<:Number, N} =
    Tucker{T, N}(factors, core)

function Tucker(factors::AbstractArray{<:StridedMatrix{T}}, core::AbstractArray{T, N}) where {T<:Number, N}
    length(factors) == N || throw(ArgumentError("Number of factor matrices do not match the core dimensions"))
    Tucker{T, N}(tuple(factors...), core)
end

"""
Returns the core tensor of Tucker decomposition.
"""
core(decomp::Tucker) = decomp.core

"""
Returns the factor matrices of Tucker decomposition.
"""
factors(decomp::Tucker) = decomp.factors

"""
Composes a full tensor from Tucker decomposition.
"""
compose(decomp::Tucker) = tensorcontractmatrices(core(decomp), factors(decomp), transpose=true)

compose!(dest::Array{T,N}, decomp::Tucker{T,N}) where {T,N} = tensorcontractmatrices!(dest, core(decomp), factors(decomp), transpose=true)

"""
Scale the factors and core of the initial decomposition.
Each decompositon component is scaled proportional to the number of its elements.
After scaling, `|decomp|=s`
"""
function rescale!(decomp::Tucker, s::Number)
    total_length = length(decomp.core) + sum(length, decomp.factors) # total elements in the decomposition
    for F in decomp.factors
        F .*= s^(length(F)/total_length)/norm(F)
    end
    decomp.core .*= s^(length(decomp.core)/total_length)/norm(decomp.core)
    return decomp
end


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

mutable struct ObjectReplicationPolicies <: SwaggerModel
    value::Any # spec type: Union{ Nothing, Vector{ObjectReplicationPolicy} } # spec name: value

    function ObjectReplicationPolicies(;value=nothing)
        o = new()
        validate_property(ObjectReplicationPolicies, Symbol("value"), value)
        setfield!(o, Symbol("value"), value)
        o
    end
end # type ObjectReplicationPolicies

const _property_map_ObjectReplicationPolicies = Dict{Symbol,Symbol}(Symbol("value")=>Symbol("value"))
const _property_types_ObjectReplicationPolicies = Dict{Symbol,String}(Symbol("value")=>"Vector{ObjectReplicationPolicy}")
Base.propertynames(::Type{ ObjectReplicationPolicies }) = collect(keys(_property_map_ObjectReplicationPolicies))
Swagger.property_type(::Type{ ObjectReplicationPolicies }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_ObjectReplicationPolicies[name]))}
Swagger.field_name(::Type{ ObjectReplicationPolicies }, property_name::Symbol) =  _property_map_ObjectReplicationPolicies[property_name]

function check_required(o::ObjectReplicationPolicies)
    true
end

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


text:
# ----------------------------------------------------
# --- Import modules
# ----------------------------------------------------
using DigitalComm
using Test
# ----------------------------------------------------
# --- Tests
# ----------------------------------------------------
println("Tests for binary sequence generation");

@testset "genBitSequence" begin
	# --- Check type and so on
	N		= 1000;
	rSeed	= 12;
	bitSeq	= genBitSequence(N,rSeed);
	# --- Ensure that output is a UInt8 vector
	@test typeof(bitSeq) == Array{UInt8,1};
	# --- Checking 0 and 1 populate the buffer
	# Not elegant, commutative presence ?
	@test unique(bitSeq) == [0x00,0x01] || unique(bitSeq) == [0x01,0x00] ;
	# --- Checking bang method
	bitSeq2	= zeros(UInt8,N);
	genBitSequence!(bitSeq2,rSeed);
	# --- Ensure that output is a UInt8 vector
	@test typeof(bitSeq2) == Array{UInt8,1};
	# --- Checking 0 and 1 populate the buffer
	# Not elegant, commutative presence ?
	@test unique(bitSeq2) == [0x00,0x01] || unique(bitSeq) == [0x01,0x00] ;
	# --- Seed should have generated same vector for both call
	@test (bitSeq == bitSeq2)
	# --- Forcing a random seed and check taht vector is different
	@test (genBitSequence(N) != bitSeq)
end

@testset "genByteSequence" begin
	# --- Check type and so on
	N		= 1000;
	rSeed	= 12;
	byteSeq	= genByteSequence(N,rSeed);
	# --- Ensure that output is a UInt8 vector
	@test typeof(byteSeq) == Array{UInt8,1};
	# --- Checking bang method
	byteSeq2	= zeros(UInt8,N);
	genByteSequence!(byteSeq2,rSeed);
	# --- Ensure that output is a UInt8 vector
	@test typeof(byteSeq2) == Array{UInt8,1};
	# --- Seed should have generated same vector for both call
	@test (byteSeq == byteSeq2)
	# --- Forcing a random seed and check that vector is different
	@test (genByteSequence(N) != byteSeq)
end


text:
module EventsWrapper

using JavaCall

const AbsoluteDate = @jimport org.orekit.time.AbsoluteDate
const AbstractDetector = @jimport org.orekit.propagation.events.AbstractDetector
const Action = @jimport org.hipparchus.ode.events.Action
const AdapterDetector = @jimport org.orekit.propagation.events.AdapterDetector
const AlignmentDetector = @jimport org.orekit.propagation.events.AlignmentDetector
const AltitudeDetector = @jimport org.orekit.propagation.events.AltitudeDetector
const AngularSeparationDetector = @jimport org.orekit.propagation.events.AngularSeparationDetector
const ApsideDetector = @jimport org.orekit.propagation.events.ApsideDetector
const AtmosphericRefractionModel = @jimport org.orekit.models.AtmosphericRefractionModel
const BodyShape = @jimport org.orekit.bodies.BodyShape
const BooleanDetector = @jimport org.orekit.propagation.events.BooleanDetector
const Class = @jimport java.lang.Class
const Collection = @jimport java.util.Collection
const DataContext = @jimport org.orekit.data.DataContext
const DateDetector = @jimport org.orekit.propagation.events.DateDetector
const EclipseDetector = @jimport org.orekit.propagation.events.EclipseDetector
const ElevationDetector = @jimport org.orekit.propagation.events.ElevationDetector
const ElevationExtremumDetector = @jimport org.orekit.propagation.events.ElevationExtremumDetector
const ElevationMask = @jimport org.orekit.utils.ElevationMask
const EnablingPredicate = @jimport org.orekit.propagation.events.EnablingPredicate
const Enum = @jimport java.lang.Enum
const EventDetector = @jimport org.orekit.propagation.events.EventDetector
const EventEnablingPredicateFilter = @jimport org.orekit.propagation.events.EventEnablingPredicateFilter
const EventHandler = @jimport org.orekit.propagation.events.handlers.EventHandler
const EventShifter = @jimport org.orekit.propagation.events.EventShifter
const EventSlopeFilter = @jimport org.orekit.propagation.events.EventSlopeFilter
const EventState = @jimport org.orekit.propagation.events.EventState
const EventState_EventOccurrence = @jimport org.orekit.propagation.events.EventState$EventOccurrence
const EventsLogger = @jimport org.orekit.propagation.events.EventsLogger
const Field = @jimport org.hipparchus.Field
const FieldAbsoluteDate = @jimport org.orekit.time.FieldAbsoluteDate
const FieldAbstractDetector = @jimport org.orekit.propagation.events.FieldAbstractDetector
const FieldAltitudeDetector = @jimport org.orekit.propagation.events.FieldAltitudeDetector
const FieldApsideDetector = @jimport org.orekit.propagation.events.FieldApsideDetector
const FieldDateDetector = @jimport org.orekit.propagation.events.FieldDateDetector
const FieldEclipseDetector = @jimport org.orekit.propagation.events.FieldEclipseDetector
const FieldElevationDetector = @jimport org.orekit.propagation.events.FieldElevationDetector
const FieldEventDetector = @jimport org.orekit.propagation.events.FieldEventDetector
const FieldEventHandler = @jimport org.orekit.propagation.events.handlers.FieldEventHandler
const FieldEventState = @jimport org.orekit.propagation.events.FieldEventState
const FieldEventState_EventOccurrence = @jimport org.orekit.propagation.events.FieldEventState$EventOccurrence
const FieldEventsLogger = @jimport org.orekit.propagation.events.FieldEventsLogger
const FieldFunctionalDetector = @jimport org.orekit.propagation.events.FieldFunctionalDetector
const FieldLatitudeCrossingDetector = @jimport org.orekit.propagation.events.FieldLatitudeCrossingDetector
const FieldNodeDetector = @jimport org.orekit.propagation.events.FieldNodeDetector
const FieldOfView = @jimport org.orekit.geometry.fov.FieldOfView
const FieldOfViewDetector = @jimport org.orekit.propagation.events.FieldOfViewDetector
const FieldOrbit = @jimport org.orekit.orbits.FieldOrbit
const FieldOrekitStepInterpolator = @jimport org.orekit.propagation.sampling.FieldOrekitStepInterpolator
const FieldSpacecraftState = @jimport org.orekit.propagation.FieldSpacecraftState
const FieldTimeStamped = @jimport org.orekit.time.FieldTimeStamped
const FilterType = @jimport org.orekit.propagation.events.FilterType
const FootprintOverlapDetector = @jimport org.orekit.propagation.events.FootprintOverlapDetector
const Frame = @jimport org.orekit.frames.Frame
const Function = @jimport java.util.function.Function
const FunctionalDetector = @jimport org.orekit.propagation.events.FunctionalDetector
const GeoMagneticFieldFactory_FieldModel = @jimport org.orekit.models.earth.GeoMagneticFieldFactory$FieldModel
const GeographicZoneDetector = @jimport org.orekit.propagation.events.GeographicZoneDetector
const GroundAtNightDetector = @jimport org.orekit.propagation.events.GroundAtNightDetector
const GroundFieldOfViewDetector = @jimport org.orekit.propagation.events.GroundFieldOfViewDetector
const HaloXZPlaneCrossingDetector = @jimport org.orekit.propagation.events.HaloXZPlaneCrossingDetector
const InterSatDirectViewDetector = @jimport org.orekit.propagation.events.InterSatDirectViewDetector
const JString = @jimport java.lang.String
const LatitudeCrossingDetector = @jimport org.orekit.propagation.events.LatitudeCrossingDetector
const LatitudeExtremumDetector = @jimport org.orekit.propagation.events.LatitudeExtremumDetector
const List = @jimport java.util.List
const LongitudeCrossingDetector = @jimport org.orekit.propagation.events.LongitudeCrossingDetector
const LongitudeExtremumDetector = @jimport org.orekit.propagation.events.LongitudeExtremumDetector
const MagneticFieldDetector = @jimport org.orekit.propagation.events.MagneticFieldDetector
const NegateDetector = @jimport org.orekit.propagation.events.NegateDetector
const NodeDetector = @jimport org.orekit.propagation.events.NodeDetector
const Object = @jimport java.lang.Object
const OneAxisEllipsoid = @jimport org.orekit.bodies.OneAxisEllipsoid
const Optional = @jimport java.util.Optional
const Orbit = @jimport org.orekit.orbits.Orbit
const OrbitType = @jimport org.orekit.orbits.OrbitType
const OrekitStepInterpolator = @jimport org.orekit.propagation.sampling.OrekitStepInterpolator
const PVCoordinatesProvider = @jimport org.orekit.utils.PVCoordinatesProvider
const PositionAngle = @jimport org.orekit.orbits.PositionAngle
const PositionAngleDetector = @jimport org.orekit.propagation.events.PositionAngleDetector
const RealFieldElement = @jimport org.hipparchus.RealFieldElement
const SpacecraftState = @jimport org.orekit.propagation.SpacecraftState
const SphericalPolygonsSet = @jimport org.hipparchus.geometry.spherical.twod.SphericalPolygonsSet
const TimeStamped = @jimport org.orekit.time.TimeStamped
const ToDoubleFunction = @jimport java.util.function.ToDoubleFunction
const TopocentricFrame = @jimport org.orekit.frames.TopocentricFrame
const Transformer = @jimport org.orekit.propagation.events.Transformer
const VisibilityTrigger = @jimport org.orekit.propagation.events.VisibilityTrigger

export AbstractDetector
export AdapterDetector
export AlignmentDetector
export AltitudeDetector
export AngularSeparationDetector
export ApsideDetector
export BooleanDetector
export DateDetector
export EclipseDetector
export ElevationDetector
export ElevationExtremumDetector
export EnablingPredicate
export EventDetector
export EventEnablingPredicateFilter
export EventShifter
export EventSlopeFilter
export EventState
export EventsLogger
export FieldAbstractDetector
export FieldAltitudeDetector
export FieldApsideDetector
export FieldDateDetector
export FieldEclipseDetector
export FieldElevationDetector
export FieldEventDetector
export FieldEventState
export FieldEventsLogger
export FieldFunctionalDetector
export FieldLatitudeCrossingDetector
export FieldNodeDetector
export FieldOfViewDetector
export FilterType
export FootprintOverlapDetector
export FunctionalDetector
export GeographicZoneDetector
export GroundAtNightDetector
export GroundFieldOfViewDetector
export HaloXZPlaneCrossingDetector
export InterSatDirectViewDetector
export LatitudeCrossingDetector
export LatitudeExtremumDetector
export LongitudeCrossingDetector
export LongitudeExtremumDetector
export MagneticFieldDetector
export NegateDetector
export NodeDetector
export PositionAngleDetector
export Transformer
export VisibilityTrigger
export add_event_date
export and_combine
export clear_logged_events
export compare_to
export describe_constable
export do_event
export equals
export evaluate_step
export event_is_enabled
export event_occurred
export g
export get_align_angle
export get_altitude
export get_angle
export get_beacon
export get_body
export get_body_shape
export get_central_body
export get_class
export get_date
export get_declaring_class
export get_decreasing_time_shift
export get_detector
export get_detectors
export get_elevation
export get_elevation_mask
export get_event_date
export get_event_detector
export get_fov
export get_frame
export get_function
export get_handler
export get_increasing_time_shift
export get_latitude
export get_logged_events
export get_longitude
export get_margin
export get_max_check_interval
export get_max_iteration_count
export get_min_elevation
export get_observer
export get_occulted
export get_occulted_radius
export get_occulting
export get_occulting_radius
export get_orbit_type
export get_original
export get_pending_event
export get_position_angle
export get_proximity_angle
export get_pv_coordinates_provider
export get_pv_target
export get_refraction_model
export get_slave
export get_threshold
export get_topocentric_frame
export get_total_eclipse
export get_zone
export hash_code
export init
export is_forward
export monitor_detector
export name
export not_combine
export notify
export notify_all
export or_combine
export ordinal
export radius_correction
export reinitialize_begin
export reset_state
export to_string
export try_advance
export value_of
export values
export wait
export with_constant_elevation
export with_elevation_mask
export with_function
export with_handler
export with_margin
export with_max_check
export with_max_iter
export with_penumbra
export with_refraction
export with_threshold
export with_umbra

include("HandlersWrapper/HandlersWrapper.jl")
include("abstract_detector.jl")
include("adapter_detector.jl")
include("alignment_detector.jl")
include("altitude_detector.jl")
include("angular_separation_detector.jl")
include("apside_detector.jl")
include("boolean_detector.jl")
include("date_detector.jl")
include("eclipse_detector.jl")
include("elevation_detector.jl")
include("elevation_extremum_detector.jl")
include("enabling_predicate.jl")
include("event_detector.jl")
include("event_enabling_predicate_filter.jl")
include("event_shifter.jl")
include("event_slope_filter.jl")
include("event_state.jl")
include("events_logger.jl")
include("field_abstract_detector.jl")
include("field_altitude_detector.jl")
include("field_apside_detector.jl")
include("field_date_detector.jl")
include("field_eclipse_detector.jl")
include("field_elevation_detector.jl")
include("field_event_detector.jl")
include("field_event_state.jl")
include("field_events_logger.jl")
include("field_functional_detector.jl")
include("field_latitude_crossing_detector.jl")
include("field_node_detector.jl")
include("field_of_view_detector.jl")
include("filter_type.jl")
include("footprint_overlap_detector.jl")
include("functional_detector.jl")
include("geographic_zone_detector.jl")
include("ground_at_night_detector.jl")
include("ground_field_of_view_detector.jl")
include("halo_xz_plane_crossing_detector.jl")
include("inter_sat_direct_view_detector.jl")
include("latitude_crossing_detector.jl")
include("latitude_extremum_detector.jl")
include("longitude_crossing_detector.jl")
include("longitude_extremum_detector.jl")
include("magnetic_field_detector.jl")
include("negate_detector.jl")
include("node_detector.jl")
include("position_angle_detector.jl")
include("transformer.jl")
include("visibility_trigger.jl")

end


text:
function lfig(arg, args...)
    file = dfname(arg, args...)
    FileIO.load(file)
end


text:
using SparseTransforms
using Test

function test_query()
    n = 4
    num_delays = 6
    locs = [4, 6, 10, 15]
    signal = TestSignal(n, locs)

    # this also implicitly does type checks

    println("Testing all the query methods")
    for method_name in all_methods["query"]
        local b = get_b(signal; method=method_name)
        local Ms = get_Ms(n, b; method=method_name)
        @test b < n
        for M in Ms
            @test size(M) == (n, b)
        end
    end

    println("Testing the delays methods")
    for method_name in all_methods["delays"]
        local D = get_D(n; method=method_name, num_delays=num_delays)
        # @ test size(D, 1) > n TODO
        @test size(D, 2) == n
    end
end


text:
using MySQL
using Nettle  # for md5

function connect_db(uri, user, pw, dbname)
    mydb = mysql_connect(uri, user, pw, dbname)

    const command = """CREATE TABLE IF NOT EXISTS users (
                          userid INT PRIMARY KEY AUTO_INCREMENT,
                          username VARCHAR(32) UNIQUE KEY NOT NULL,
                          pass_salt tinyblob NOT NULL,
                              -- a string of 16 random bytes
                          pass_md5 tinyblob NOT NULL
                              -- binary MD5 hash of pass_salt concatenated with the password
                  );"""
    mysql_execute(mydb, command)
    mydb
end

function create_user(dbh, user, pw)
    mysql_stmt_prepare(dbh, "INSERT IGNORE INTO users (username, pass_salt, pass_md5) values (?, ?, ?);")
    salt = join([Char(c) for c in rand(UInt8, 16)], "")
    passmd5 = digest("md5", salt * user)
    mysql_execute(dbh, [MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VARCHAR], [user, salt, passmd5])
end

function addusers(dbh, userdict)
    for user in keys(userdict)
        create_user(dbh, user, userdict[user])
    end
end

"""
    authenticate_user
Note this returns true if password provided authenticates as correct, false otherwise
"""
function authenticate_user(dbh, username, pw)
    mysql_stmt_prepare(dbh, "SELECT pass_salt, pass_md5 FROM users WHERE username = ?;")
    pass_salt, pass_md5 = mysql_execute(dbh, [MYSQL_TYPE_VARCHAR], [username], opformat=MYSQL_TUPLES)[1]
    pass_md5 == digest("md5", pass_salt * username)
end

const users = Dict("Joan" => "joanspw", "John" => "johnspw", "Mary" => "marpw", "Mark" => "markpw")
const mydb = connect_db("192.168.1.1", "julia", "julia", "mydb")

addusers(mydb, users)
println("""John authenticates correctly: $(authenticate_user(mydb, "John", "johnspw")==false)""")
println("""Mary does not authenticate with password of 123: $(authenticate_user(mydb, "Mary", "123")==false)""")
mysql_disconnect(mydb)

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
### Multidimensional iterators
module QuasiIteratorsMD
    import Base: eltype, length, size, first, last, in, getindex,
                 setindex!, IndexStyle, min, max, zero, oneunit, isless, eachindex,
                 ndims, IteratorSize, convert, show, iterate, promote_rule

    import Base: +, -, *, (:)
    import Base: simd_outer_range, simd_inner_length, simd_index
    using Base: IndexLinear, IndexCartesian, AbstractCartesianIndex, fill_to_length, tail
    using Base.Iterators: Reverse
    import QuasiArrays: AbstractQuasiArray, AbstractQuasiVector, domain, AbstractQuasiOrVector

    export QuasiCartesianIndex, QuasiCartesianIndices

    """
        QuasiCartesianIndex(i, j, k...)   -> I
        QuasiCartesianIndex((i, j, k...)) -> I

    Create a multidimensional index `I`, which can be used for
    indexing a multidimensional array `A`.  In particular, `A[I]` is
    equivalent to `A[i,j,k...]`.  One can freely mix integer and
    `QuasiCartesianIndex` indices; for example, `A[Ipre, i, Ipost]` (where
    `Ipre` and `Ipost` are `QuasiCartesianIndex` indices and `i` is an
    `Int`) can be a useful expression when writing algorithms that
    work along a single dimension of an array of arbitrary
    dimensionality.

    A `QuasiCartesianIndex` is sometimes produced by [`eachindex`](@ref), and
    always when iterating with an explicit [`QuasiCartesianIndices`](@ref).

    # Examples
    ```jldoctest
    julia> A = reshape(Vector(1:16), (2, 2, 2, 2))
    2×2×2×2 Array{Int64,4}:
    [:, :, 1, 1] =
     1  3
     2  4

    [:, :, 2, 1] =
     5  7
     6  8

    [:, :, 1, 2] =
      9  11
     10  12

    [:, :, 2, 2] =
     13  15
     14  16

    julia> A[QuasiCartesianIndex((1, 1, 1, 1))]
    1

    julia> A[QuasiCartesianIndex((1, 1, 1, 2))]
    9

    julia> A[QuasiCartesianIndex((1, 1, 2, 1))]
    5
    ```
    """
    struct QuasiCartesianIndex{N,II<:Tuple} <: AbstractCartesianIndex{N}
        I::II
        QuasiCartesianIndex{N,II}(index::II) where {N,II} = new(index)
    end
    QuasiCartesianIndex{N}(index::NTuple{N,Number}) where N = QuasiCartesianIndex{N,typeof(index)}(index)
    QuasiCartesianIndex(index::NTuple{N,Number}) where {N} = QuasiCartesianIndex{N}(index)
    QuasiCartesianIndex(index::Number...) = QuasiCartesianIndex(index)
    QuasiCartesianIndex{N}(index::Vararg{Number,N}) where {N} = QuasiCartesianIndex{N}(index)
    # Allow passing tuples smaller than N
    QuasiCartesianIndex{N}(index::Tuple) where {N} = QuasiCartesianIndex{N}(fill_to_length(index, 1, Val(N)))
    QuasiCartesianIndex{N}(index::Number...) where {N} = QuasiCartesianIndex{N}(index)
    QuasiCartesianIndex{N}() where {N} = QuasiCartesianIndex{N}(())
    # Un-nest passed QuasiCartesianIndexes
    QuasiCartesianIndex(index::Union{Number, QuasiCartesianIndex}...) = QuasiCartesianIndex(flatten(index))
    flatten(I::Tuple{}) = I
    flatten(I::Tuple{Any}) = I
    flatten(I::Tuple{<:QuasiCartesianIndex}) = I[1].I
    @inline flatten(I) = _flatten(I...)
    @inline _flatten() = ()
    @inline _flatten(i, I...)                 = (i, _flatten(I...)...)
    @inline _flatten(i::QuasiCartesianIndex, I...) = (i.I..., _flatten(I...)...)
    QuasiCartesianIndex(index::Tuple{Vararg{Union{Number, QuasiCartesianIndex}}}) = QuasiCartesianIndex(index...)
    show(io::IO, i::QuasiCartesianIndex) = (print(io, "QuasiCartesianIndex"); show(io, i.I))

    # length
    length(::QuasiCartesianIndex{N}) where {N} = N
    length(::Type{QuasiCartesianIndex{N}}) where {N} = N

    # indexing
    getindex(index::QuasiCartesianIndex, i::Integer) = index.I[i]
    Base.get(A::AbstractQuasiArray, I::QuasiCartesianIndex, default) = get(A, I.I, default)
    eltype(::Type{T}) where {T<:QuasiCartesianIndex} = eltype(fieldtype(T, :I))

    # access to index tuple
    Tuple(index::QuasiCartesianIndex) = index.I

    # equality
    Base.:(==)(a::QuasiCartesianIndex{N}, b::QuasiCartesianIndex{N}) where N = a.I == b.I

    # zeros and ones
    zero(::QuasiCartesianIndex{N}) where {N} = zero(QuasiCartesianIndex{N})
    zero(::Type{QuasiCartesianIndex{N}}) where {N} = QuasiCartesianIndex(ntuple(x -> 0, Val(N)))
    oneunit(::QuasiCartesianIndex{N}) where {N} = oneunit(QuasiCartesianIndex{N})
    oneunit(::Type{QuasiCartesianIndex{N}}) where {N} = QuasiCartesianIndex(ntuple(x -> 1, Val(N)))

    # arithmetic, min/max
    @inline (-)(index::QuasiCartesianIndex{N}) where {N} =
        QuasiCartesianIndex{N}(map(-, index.I))
    @inline (+)(index1::QuasiCartesianIndex{N}, index2::QuasiCartesianIndex{N}) where {N} =
        QuasiCartesianIndex{N}(map(+, index1.I, index2.I))
    @inline (-)(index1::QuasiCartesianIndex{N}, index2::QuasiCartesianIndex{N}) where {N} =
        QuasiCartesianIndex{N}(map(-, index1.I, index2.I))
    @inline min(index1::QuasiCartesianIndex{N}, index2::QuasiCartesianIndex{N}) where {N} =
        QuasiCartesianIndex{N}(map(min, index1.I, index2.I))
    @inline max(index1::QuasiCartesianIndex{N}, index2::QuasiCartesianIndex{N}) where {N} =
        QuasiCartesianIndex{N}(map(max, index1.I, index2.I))

    @inline (*)(a::Number, index::QuasiCartesianIndex{N}) where {N} = QuasiCartesianIndex{N}(map(x->a*x, index.I))
    @inline (*)(index::QuasiCartesianIndex, a::Number) = *(a,index)

    # comparison
    @inline isless(I1::QuasiCartesianIndex{N}, I2::QuasiCartesianIndex{N}) where {N} = _isless(0, I1.I, I2.I)
    @inline function _isless(ret, I1::NTuple{N,Int}, I2::NTuple{N,Int}) where N
        newret = ifelse(ret==0, icmp(I1[N], I2[N]), ret)
        _isless(newret, Base.front(I1), Base.front(I2))
    end
    _isless(ret, ::Tuple{}, ::Tuple{}) = ifelse(ret==1, true, false)
    icmp(a, b) = ifelse(isless(a,b), 1, ifelse(a==b, 0, -1))

    # conversions
    convert(::Type{T}, index::QuasiCartesianIndex{1}) where {T<:Number} = convert(T, index[1])
    convert(::Type{T}, index::QuasiCartesianIndex) where {T<:Tuple} = convert(T, index.I)

    # hashing
    const cartindexhash_seed = UInt == UInt64 ? 0xd60ca92f8284b8b0 : 0xf2ea7c2e
    function Base.hash(ci::QuasiCartesianIndex, h::UInt)
        h += cartindexhash_seed
        for i in ci.I
            h = hash(i, h)
        end
        return h
    end

    # nextind and prevind with QuasiCartesianIndex
    function Base.nextind(a::AbstractQuasiArray{<:Any,N}, i::QuasiCartesianIndex{N}) where {N}
        iter = QuasiCartesianIndices(axes(a))
        # might overflow
        I = inc(i.I, first(iter).I, last(iter).I)
        return I
    end
    function Base.prevind(a::AbstractQuasiArray{<:Any,N}, i::QuasiCartesianIndex{N}) where {N}
        iter = QuasiCartesianIndices(axes(a))
        # might underflow
        I = dec(i.I, last(iter).I, first(iter).I)
        return I
    end

    # Iteration over the elements of QuasiCartesianIndex cannot be supported until its length can be inferred,
    # see #23719
    Base.iterate(::QuasiCartesianIndex) =
        error("iteration is deliberately unsupported for QuasiCartesianIndex. Use `I` rather than `I...`, or use `Tuple(I)...`")

    # Iteration
    """
        QuasiCartesianIndices(sz::Dims) -> R
        QuasiCartesianIndices((istart:istop, jstart:jstop, ...)) -> R

    Define a region `R` spanning a multidimensional rectangular range
    of integer indices. These are most commonly encountered in the
    context of iteration, where `for I in R ... end` will return
    [`QuasiCartesianIndex`](@ref) indices `I` equivalent to the nested loops

        for j = jstart:jstop
            for i = istart:istop
                ...
            end
        end

    Consequently these can be useful for writing algorithms that
    work in arbitrary dimensions.

        QuasiCartesianIndices(A::AbstractQuasiArray) -> R

    As a convenience, constructing a `QuasiCartesianIndices` from an array makes a
    range of its indices.

    # Examples
    ```jldoctest
    julia> foreach(println, QuasiCartesianIndices((2, 2, 2)))
    QuasiCartesianIndex(1, 1, 1)
    QuasiCartesianIndex(2, 1, 1)
    QuasiCartesianIndex(1, 2, 1)
    QuasiCartesianIndex(2, 2, 1)
    QuasiCartesianIndex(1, 1, 2)
    QuasiCartesianIndex(2, 1, 2)
    QuasiCartesianIndex(1, 2, 2)
    QuasiCartesianIndex(2, 2, 2)

    julia> QuasiCartesianIndices(fill(1, (2,3)))
    2×3 QuasiCartesianIndices{2,Tuple{Base.OneTo{Int64},Base.OneTo{Int64}}}:
     QuasiCartesianIndex(1, 1)  QuasiCartesianIndex(1, 2)  QuasiCartesianIndex(1, 3)
     QuasiCartesianIndex(2, 1)  QuasiCartesianIndex(2, 2)  QuasiCartesianIndex(2, 3)
    ```

    ## Conversion between linear and QuasiCartesian indices

    Linear index to QuasiCartesian index conversion exploits the fact that a
    `QuasiCartesianIndices` is an `AbstractQuasiArray` and can be indexed linearly:

    ```jldoctest
    julia> QuasiCartesian = QuasiCartesianIndices((1:3, 1:2))
    3×2 QuasiCartesianIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}:
     QuasiCartesianIndex(1, 1)  QuasiCartesianIndex(1, 2)
     QuasiCartesianIndex(2, 1)  QuasiCartesianIndex(2, 2)
     QuasiCartesianIndex(3, 1)  QuasiCartesianIndex(3, 2)

    julia> cartesian[4]
    QuasiCartesianIndex(1, 2)
    ```

    ## Broadcasting

    `QuasiCartesianIndices` support broadcasting arithmetic (+ and -) with a `QuasiCartesianIndex`.

    !!! compat "Julia 1.1"
        Broadcasting of QuasiCartesianIndices requires at least Julia 1.1.

    ```jldoctest
    julia> CIs = QuasiCartesianIndices((2:3, 5:6))
    2×2 QuasiCartesianIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}:
     QuasiCartesianIndex(2, 5)  QuasiCartesianIndex(2, 6)
     QuasiCartesianIndex(3, 5)  QuasiCartesianIndex(3, 6)

    julia> CI = QuasiCartesianIndex(3, 4)
    QuasiCartesianIndex(3, 4)

    julia> CIs .+ CI
    2×2 QuasiCartesianIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}:
     QuasiCartesianIndex(5, 9)  QuasiCartesianIndex(5, 10)
     QuasiCartesianIndex(6, 9)  QuasiCartesianIndex(6, 10)
    ```

    For cartesian to linear index conversion, see [`LinearIndices`](@ref).
    """

    struct QuasiCartesianIndices{N,R<:NTuple{N,AbstractQuasiOrVector{<:Number}},RR<:NTuple{N,Number}} <: AbstractArray{QuasiCartesianIndex{N,RR},N}
        indices::R
    end

    QuasiCartesianIndices(nd::NTuple{N,AbstractQuasiOrVector{<:Number}}) where N =
        QuasiCartesianIndices{N,typeof(nd),Tuple{map(eltype,nd)...}}(nd)

    QuasiCartesianIndices(::Tuple{}) = QuasiCartesianIndices{0,typeof(())}(())

    QuasiCartesianIndices(index::QuasiCartesianIndex) = QuasiCartesianIndices(index.I)
    QuasiCartesianIndices(sz::NTuple{N,<:Number}) where {N} = QuasiCartesianIndices(map(Base.OneTo, sz))

    QuasiCartesianIndices(A::AbstractQuasiArray) = QuasiCartesianIndices(axes(A))

    """
        (:)(I::QuasiCartesianIndex, J::QuasiCartesianIndex)

    Construct [`QuasiCartesianIndices`](@ref) from two `QuasiCartesianIndex`.

    !!! compat "Julia 1.1"
        This method requires at least Julia 1.1.

    # Examples
    ```jldoctest
    julia> I = QuasiCartesianIndex(2,1);

    julia> J = QuasiCartesianIndex(3,3);

    julia> I:J
    2×3 QuasiCartesianIndices{2,Tuple{UnitRange{Int64},UnitRange{Int64}}}:
     QuasiCartesianIndex(2, 1)  QuasiCartesianIndex(2, 2)  QuasiCartesianIndex(2, 3)
     QuasiCartesianIndex(3, 1)  QuasiCartesianIndex(3, 2)  QuasiCartesianIndex(3, 3)
    ```
    """
    (:)(I::QuasiCartesianIndex{N}, J::QuasiCartesianIndex{N}) where N =
        QuasiCartesianIndices(map((i,j) -> i:j, Tuple(I), Tuple(J)))

    promote_rule(::Type{QuasiCartesianIndices{N,R1}}, ::Type{QuasiCartesianIndices{N,R2}}) where {N,R1,R2} =
        QuasiCartesianIndices{N,Base.indices_promote_type(R1,R2)}

    convert(::Type{Tuple{}}, R::QuasiCartesianIndices{0}) = ()
    convert(::Type{NTuple{N,AbstractUnitRange{Int}}}, R::QuasiCartesianIndices{N}) where {N} =
        R.indices
    convert(::Type{NTuple{N,AbstractUnitRange}}, R::QuasiCartesianIndices{N}) where {N} =
        convert(NTuple{N,AbstractUnitRange{Int}}, R)
    convert(::Type{NTuple{N,UnitRange{Int}}}, R::QuasiCartesianIndices{N}) where {N} =
        UnitRange{Int}.(convert(NTuple{N,AbstractUnitRange}, R))
    convert(::Type{NTuple{N,UnitRange}}, R::QuasiCartesianIndices{N}) where {N} =
        UnitRange.(convert(NTuple{N,AbstractUnitRange}, R))
    convert(::Type{Tuple{Vararg{AbstractUnitRange{Int}}}}, R::QuasiCartesianIndices{N}) where {N} =
        convert(NTuple{N,AbstractUnitRange{Int}}, R)
    convert(::Type{Tuple{Vararg{AbstractUnitRange}}}, R::QuasiCartesianIndices) =
        convert(Tuple{Vararg{AbstractUnitRange{Int}}}, R)
    convert(::Type{Tuple{Vararg{UnitRange{Int}}}}, R::QuasiCartesianIndices{N}) where {N} =
        convert(NTuple{N,UnitRange{Int}}, R)
    convert(::Type{Tuple{Vararg{UnitRange}}}, R::QuasiCartesianIndices) =
        convert(Tuple{Vararg{UnitRange{Int}}}, R)

    convert(::Type{QuasiCartesianIndices{N,R}}, inds::QuasiCartesianIndices{N}) where {N,R} =
        QuasiCartesianIndices(convert(R, inds.indices))

    # AbstractQuasiArray implementation
    Base.axes(iter::QuasiCartesianIndices{N,R}) where {N,R} = map(Base.axes1, iter.indices)
    Base.IndexStyle(::Type{QuasiCartesianIndices{N,R}}) where {N,R} = IndexCartesian()
    @inline function Base.getindex(iter::QuasiCartesianIndices{N,R}, I::Vararg{Int, N}) where {N,R}
        @boundscheck checkbounds(iter, I...)
        QuasiCartesianIndex(getindex.(domain.(iter.indices), I))
    end

    ndims(R::QuasiCartesianIndices) = ndims(typeof(R))
    ndims(::Type{QuasiCartesianIndices{N}}) where {N} = N
    ndims(::Type{QuasiCartesianIndices{N,TT}}) where {N,TT} = N

    eachindex(::IndexCartesian, A::AbstractQuasiArray) = QuasiCartesianIndices(axes(A))

    @inline function eachindex(::IndexCartesian, A::AbstractQuasiArray, B::AbstractQuasiArray...)
        axsA = axes(A)
        Base._all_match_first(axes, axsA, B...) || Base.throw_eachindex_mismatch(IndexCartesian(), A, B...)
        QuasiCartesianIndices(axsA)
    end

    eltype(::Type{QuasiCartesianIndices{N}}) where {N} = QuasiCartesianIndex{N}
    eltype(::Type{QuasiCartesianIndices{N,TT}}) where {N,TT} = QuasiCartesianIndex{N}
    eltype(::Type{QuasiCartesianIndices{N,TT,RR}}) where {N,TT,RR} = QuasiCartesianIndex{N,RR}
    IteratorSize(::Type{<:QuasiCartesianIndices{N}}) where {N} = Base.HasShape{N}()

    size(iter::QuasiCartesianIndices) = map(length, iter.indices)
    length(iter::QuasiCartesianIndices) = prod(size(iter))

    first(iter::QuasiCartesianIndices) = QuasiCartesianIndex(map(first, iter.indices))
    last(iter::QuasiCartesianIndices)  = QuasiCartesianIndex(map(last, iter.indices))

    @inline function split(I::QuasiCartesianIndex, V::Val)
        i, j = split(I.I, V)
        QuasiCartesianIndex(i), QuasiCartesianIndex(j)
    end
    function split(R::QuasiCartesianIndices, V::Val)
        i, j = split(R.indices, V)
        QuasiCartesianIndices(i), QuasiCartesianIndices(j)
    end

    Base.LinearIndices(inds::QuasiCartesianIndices{N,R}) where {N,R} = LinearIndices{N,R}(inds.indices)
end  # IteratorsMD

using .QuasiIteratorsMD

## Bounds-checking with QuasiCartesianIndex
# Disallow linear indexing with QuasiCartesianIndex
function checkbounds(::Type{Bool}, A::AbstractQuasiArray, i::Union{QuasiCartesianIndex, AbstractArray{<:QuasiCartesianIndex}})
    @_inline_meta
    checkbounds_indices(Bool, axes(A), (i,))
end

@inline checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple{QuasiCartesianIndex,Vararg{Any}}) =
    checkbounds_indices(Bool, (), (I[1].I..., tail(I)...))
@inline checkbounds_indices(::Type{Bool}, IA::Tuple{Any}, I::Tuple{QuasiCartesianIndex,Vararg{Any}}) =
    checkbounds_indices(Bool, IA, (I[1].I..., tail(I)...))
@inline checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple{QuasiCartesianIndex,Vararg{Any}}) =
    checkbounds_indices(Bool, IA, (I[1].I..., tail(I)...))

# Indexing into Array with mixtures of Numbers and QuasiCartesianIndices is
# extremely performance-sensitive. While the abstract fallbacks support this,
# codegen has extra support for SIMDification that sub2ind doesn't (yet) support
@propagate_inbounds getindex(A::Array, i1::Union{Number, QuasiCartesianIndex}, I::Union{Number, QuasiCartesianIndex}...) =
    A[to_indices(A, (i1, I...))...]
@propagate_inbounds setindex!(A::Array, v, i1::Union{Number, QuasiCartesianIndex}, I::Union{Number, QuasiCartesianIndex}...) =
    (A[to_indices(A, (i1, I...))...] = v; A)

# Support indexing with an array of QuasiCartesianIndex{N}s
# Here we try to consume N of the indices (if there are that many available)
# The first two simply handle ambiguities
@inline function checkbounds_indices(::Type{Bool}, ::Tuple{},
        I::Tuple{AbstractArray{QuasiCartesianIndex{N}},Vararg{Any}}) where N
    checkindex(Bool, (), I[1]) & checkbounds_indices(Bool, (), tail(I))
end
@inline function checkbounds_indices(::Type{Bool}, IA::Tuple{Any},
        I::Tuple{AbstractArray{QuasiCartesianIndex{0}},Vararg{Any}})
    checkbounds_indices(Bool, IA, tail(I))
end
@inline function checkbounds_indices(::Type{Bool}, IA::Tuple{Any},
        I::Tuple{AbstractArray{QuasiCartesianIndex{N}},Vararg{Any}}) where N
    checkindex(Bool, IA, I[1]) & checkbounds_indices(Bool, (), tail(I))
end
@inline function checkbounds_indices(::Type{Bool}, IA::Tuple,
        I::Tuple{AbstractArray{QuasiCartesianIndex{N}},Vararg{Any}}) where N
    IA1, IArest = IteratorsMD.split(IA, Val(N))
    checkindex(Bool, IA1, I[1]) & checkbounds_indices(Bool, IArest, tail(I))
end

function checkindex(::Type{Bool}, inds::Tuple, I::AbstractArray{<:QuasiCartesianIndex})
    b = true
    for i in I
        b &= checkbounds_indices(Bool, inds, (i,))
    end
    b
end

# combined count of all indices, including QuasiCartesianIndex and
# AbstractArray{QuasiCartesianIndex}
# rather than returning N, it returns an NTuple{N,Bool} so the result is inferrable
@inline function index_ndims(i1::QuasiCartesianIndex, I...)
    (map(x->true, i1.I)..., index_ndims(I...)...)
end
@inline function index_ndims(i1::AbstractArray{QuasiCartesianIndex{N}}, I...) where N
    (ntuple(x->true, Val(N))..., index_ndims(I...)...)
end

# In simple cases, we know that we don't need to use axes(A). Optimize those
# until Julia gets smart enough to elide the call on its own:
@inline to_indices(A, I::Tuple{Vararg{Union{Number, QuasiCartesianIndex}}}) = to_indices(A, (), I)
# But some index types require more context spanning multiple indices
# QuasiCartesianIndexes are simple; they just splat out
@inline to_indices(A, inds, I::Tuple{QuasiCartesianIndex, Vararg{Any}}) =
    to_indices(A, inds, (I[1].I..., tail(I)...))
# But for arrays of QuasiCartesianIndex, we just skip the appropriate number of inds
@inline function to_indices(A, inds, I::Tuple{AbstractArray{QuasiCartesianIndex{N}}, Vararg{Any}}) where N
    _, indstail = IteratorsMD.split(inds, Val(N))
    (to_index(A, I[1]), to_indices(A, indstail, tail(I))...)
end

# Colons get converted to slices by `uncolon`
const CI0 = Union{QuasiCartesianIndex{0}, AbstractArray{QuasiCartesianIndex{0}}}

### From abstractarray.jl: Internal multidimensional indexing definitions ###
getindex(x::Number, i::QuasiCartesianIndex{0}) = x
getindex(t::Tuple,  i::QuasiCartesianIndex{1}) = getindex(t, i.I[1])

@inline function _getindex(l::IndexStyle, A::AbstractQuasiArray, I::Union{Number, AbstractArray}...)
    @boundscheck checkbounds(A, I...)
    return _unsafe_getindex(l, _maybe_reshape(l, A, I...), I...)
end

@inline index_dimsum(::AbstractQuasiArray{Bool}, I...) = (true, index_dimsum(I...)...)
@inline function index_dimsum(::AbstractQuasiArray{<:Any,N}, I...) where N
    (ntuple(x->true, Val(N))..., index_dimsum(I...)...)
end

Slice(d::AbstractQuasiVector{<:Number}) = Inclusion(d)

_maybe_reshape(::IndexLinear, A::AbstractQuasiArray, I...) = A
_maybe_reshape(::IndexCartesian, A::AbstractQuasiVector, I...) = A
@inline _maybe_reshape(::IndexCartesian, A::AbstractQuasiArray, I...) = __maybe_reshape(A, index_ndims(I...))
@inline __maybe_reshape(A::AbstractQuasiArray{T,N}, ::NTuple{N,Any}) where {T,N} = A
@inline __maybe_reshape(A::AbstractQuasiArray, ::NTuple{N,Any}) where {N} = reshape(A, Val(N))

_unsafe_getindex(::IndexStyle, A::AbstractQuasiArray, I::Vararg{Union{Number, AbstractArray}, N}) where N =
    lazy_getindex(A, I...)

# Always index with the exactly indices provided.
@generated function _unsafe_getindex!(dest::Union{AbstractArray,AbstractQuasiArray}, src::AbstractQuasiArray, I::Vararg{Union{Number, AbstractArray}, N}) where N
    quote
        @_inline_meta
        D = eachindex(dest)
        Dy = iterate(D)
        @inbounds @nloops $N j d->I[d] begin
            # This condition is never hit, but at the moment
            # the optimizer is not clever enough to split the union without it
            Dy === nothing && return dest
            (idx, state) = Dy
            dest[idx] = @ncall $N getindex src j
            Dy = iterate(D, state)
        end
        return dest
    end
end

function fill!(A::AbstractQuasiArray{T}, x) where T
    xT = convert(T, x)
    for I in eachindex(A)
        @inbounds A[I] = xT
    end
    A
end


text:
import Base: writemime

using JSON

const widgets_js = readall(joinpath(dirname(Base.source_path()), "widgets.js"))

try
    display("text/html", """""")
catch
end

function writemime(io, ::MIME{symbol("text/html")}, w::InputWidget)
    wtype = typeof(w)
    while super(wtype) <: InputWidget
        wtype = super(wtype)
    end

    widgettype = string(typeof(w).name.name)
    inputtype  = string(wtype.parameters[1].name.name)

    id = register_widget(w)
    el_id = "widget-$(id)"

    write(io, "

")
end


text:
module PersistentCollections
    export LMDB, PersistentDict

    module LMDB
        include(joinpath(@__DIR__, "lmdb.jl"))
    end

    struct PersistentDict{K,V} <: AbstractDict{K,V}
        env::LMDB.Environment
        id::String
        PersistentDict{K,V}(env; id="") where {K,V} = new{K,V}(env, id)
    end

    Base.show(io::IO, d::PersistentDict) = print(io, typeof(d), "(", isempty(d.id) ? "" : repr(e.id), ")")

    function rotxn(func::Function, d::PersistentDict)
        isopen(d.env) || error("Environment is closed")
        txn = d.env.rotxn[Threads.threadid()]
        LMDB.mdb_txn_renew(txn)
        try
            dbi = LMDB.mdb_dbi_open(txn, d.id, zero(Cuint))
            return func(txn, dbi)
        finally
            LMDB.mdb_txn_reset(txn)
        end
    end

    function rwtxn(func::Function, d::PersistentDict, sync::Bool)
        isopen(d.env) || error("Environment is closed")
        txn, commit = C_NULL, false
        lock(d.env.wlock) # need this lock otherwise it will deadlock
        try
            txn = LMDB.mdb_txn_begin(d.env.handle, sync ? zero(Cuint) : LMDB.MDB_NOSYNC)
            dbi = LMDB.mdb_dbi_open(txn, d.id, LMDB.MDB_CREATE)
            commit = func(txn, dbi)
            commit == false || LMDB.mdb_txn_commit(txn)
            return commit
        finally
            (commit || txn == C_NULL) || LMDB.mdb_txn_abort(txn)
            unlock(d.env.wlock)
        end
    end

    function cursor(func::Function, dict::PersistentDict)
        isopen(dict.env) || error("Environment is closed")
        txn, cur = LMDB.mdb_txn_begin(dict.env.handle, LMDB.DEFAULT_ROTXN_FLAGS), C_NULL
        try
            dbi = LMDB.mdb_dbi_open(txn, dict.id, zero(Cuint))
            cur = LMDB.mdb_cursor_open(txn, dbi)
            func(cur)
        catch e
            e.code == LMDB.MDB_NOTFOUND || rethrow(e)
            return false
        finally
            cur == C_NULL || LMDB.mdb_cursor_close(cur)
            LMDB.mdb_txn_abort(txn)
        end
    end

    function Base.get(d::PersistentDict{K,V}, key::K, default::D) where {K,V,D}
        mdbkey, mdbval = convert(LMDB.MDBValue, key), LMDB.MDBValue()
        found = rotxn(d) do txn, dbi
            GC.@preserve mdbkey LMDB.mdb_get!(txn, dbi, pointer(mdbkey), pointer(mdbval))
        end
        found || return default
        # try converting if possible
        V == Any || return convert(V, mdbval)
        D == Nothing || return convert(D, mdbval)
        return mdbval # return unconverted
    end

    function Base.getindex(d::PersistentDict{K,V}, key::K) where {K,V}
        val = get(d, key, nothing)
        isnothing(val) || return val
        throw(KeyError(key))
    end

    function Base.setindex!(d::PersistentDict{K,V}, val::V, key::K; sync=true) where {K,V}
        mdbkey, mdbval = convert(LMDB.MDBValue, key), convert(LMDB.MDBValue, val)
        rwtxn(d, sync) do txn, dbi
            GC.@preserve mdbkey mdbval LMDB.mdb_put(txn, dbi, pointer(mdbkey), pointer(mdbval), zero(Cuint))
            true
        end
        return val
    end

    function Base.delete!(d::PersistentDict{K,V}, key::K; sync=true) where {K,V}
        mdbkey = convert(LMDB.MDBValue, key)
        return rwtxn(d, sync) do txn, dbi
            GC.@preserve mdbkey LMDB.mdb_del(txn, dbi, pointer(mdbkey), C_NULL)
        end
    end

    abstract type AbstractMDBCursor end
    mutable struct MDBPairCursor{K,V} <: AbstractMDBCursor
        cur::Threads.Atomic{UInt}
    end
    mutable struct MDBKeyCursor{K,V} <: AbstractMDBCursor
        cur::Threads.Atomic{UInt}
    end
    mutable struct MDBValCursor{K,V} <: AbstractMDBCursor
        cur::Threads.Atomic{UInt}
    end

    function create_atomic_cursor(dict::PersistentDict)
        isopen(dict.env) || error("Environment is closed")
        txn = LMDB.mdb_txn_begin(dict.env.handle, LMDB.DEFAULT_ROTXN_FLAGS)
        cur = C_NULL
        try
            dbi = LMDB.mdb_dbi_open(txn, dict.id, zero(Cuint))
            cur = LMDB.mdb_cursor_open(txn, dbi)
        catch e
            LMDB.mdb_txn_abort(txn)
            # return C_NULL cur if database is empty
            e.code == LMDB.MDB_NOTFOUND || rethrow(e)
        end
        atomic = Threads.Atomic{UInt}(convert(UInt, cur))
        finalizer(close_atomic_cursor, atomic)
        return atomic
    end

    function close_atomic_cursor(atomic_cursor::Threads.Atomic{UInt})
        # Make sure that two threads do not close the same handles
        # by using Atomic exchange operation
        cur = convert(Ptr{Cvoid}, Threads.atomic_xchg!(atomic_cursor, convert(UInt, C_NULL)))
        if cur != C_NULL
            txn = LMDB.mdb_cursor_txn(cur)
            LMDB.mdb_cursor_close(cur)
            LMDB.mdb_txn_abort(txn)
        end
        return nothing
    end

    Base.close(iter::AbstractMDBCursor) = close_atomic_cursor(iter.cur)

    # multi-threading might introduce race-condition where wrong length is reported
    Base.IteratorSize(d::PersistentDict) = Base.SizeUnknown()
    Base.IteratorSize(iter::AbstractMDBCursor) = Base.SizeUnknown()
    Base.eltype(iter::MDBPairCursor{K,V}) where {K,V} = Pair{K,V}
    Base.eltype(iter::MDBKeyCursor{K,V}) where {K,V} = K
    Base.eltype(iter::MDBValCursor{K,V}) where {K,V} = V

    function Base.iterate(iter::MDBPairCursor{K,V}, op=LMDB.MDB_FIRST) where {K,V}
        mdbkey, mdbval = LMDB.MDBValue(), LMDB.MDBValue()
        finished = !LMDB.mdb_cursor_get!(convert(Ptr{Cvoid}, iter.cur[]), pointer(mdbkey), pointer(mdbval), op)
        finished || return (convert(K, mdbkey) => convert(V, mdbval), LMDB.MDB_NEXT)
        close(iter)
        return nothing
    end
    function Base.iterate(iter::MDBKeyCursor{K,V}, op=LMDB.MDB_FIRST) where {K,V}
        mdbkey, mdbval = LMDB.MDBValue(), LMDB.MDBValue()
        finished = !LMDB.mdb_cursor_get!(convert(Ptr{Cvoid}, iter.cur[]), pointer(mdbkey), pointer(mdbval), op)
        finished || return (convert(K, mdbkey), LMDB.MDB_NEXT)
        close(iter)
        return nothing
    end
    function Base.iterate(iter::MDBValCursor{K,V}, op=LMDB.MDB_FIRST) where {K,V}
        mdbkey, mdbval = LMDB.MDBValue(), LMDB.MDBValue()
        finished = !LMDB.mdb_cursor_get!(convert(Ptr{Cvoid}, iter.cur[]), pointer(mdbkey), pointer(mdbval), op)
        finished || return (convert(V, mdbval), LMDB.MDB_NEXT)
        close(iter)
        return nothing
    end

    function Base.iterate(d::PersistentDict{K,V}, iter=nothing) where {K,V}
        op = isnothing(iter) ? LMDB.MDB_FIRST : LMDB.MDB_NEXT
        if isnothing(iter)
            iter = MDBPairCursor{K,V}(create_atomic_cursor(d))
        end
        next = iterate(iter, op)
        return isnothing(next) ? nothing : (next[1], iter)
    end

    Base.keys(d::PersistentDict{K,V}) where {K,V} = MDBKeyCursor{K,V}(create_atomic_cursor(d))
    Base.values(d::PersistentDict{K,V}) where {K,V} = MDBValCursor{K,V}(create_atomic_cursor(d))

    function Base.length(d::PersistentDict)
        return rotxn(d) do txn, dbi
            convert(Int, LMDB.mdb_stat(txn, dbi).ms_entries)
        end
    end

    function Base.first(d::PersistentDict{K,V}) where {K,V}
        mdbkey, mdbval = LMDB.MDBValue(), LMDB.MDBValue()
        found = cursor(d) do cur
            LMDB.mdb_cursor_get!(cur, pointer(mdbkey), pointer(mdbval), LMDB.MDB_FIRST)
        end
        found || throw(BoundsError())
        return convert(K, mdbkey) => convert(V, mdbval)
    end

    function Base.last(d::PersistentDict{K,V}) where {K,V}
        mdbkey, mdbval = LMDB.MDBValue(), LMDB.MDBValue()
        found = cursor(d) do cur
            LMDB.mdb_cursor_get!(cur, pointer(mdbkey), pointer(mdbval), LMDB.MDB_LAST)
        end
        found || throw(BoundsError())
        return convert(K, mdbkey) => convert(V, mdbval)
    end

end # module


text:
const RD = RobotDynamics
using RobotDynamics: KnotPoint, dynamics, dynamics!, jacobian!
using RobotDynamics: StaticReturn, InPlace, ForwardAD, FiniteDifference
using Random
function test_model(model; evals=1, samples=1, tol=1e-6, customjacobian=false)
    println(typeof(model))
    dmodel = RD.DiscretizedDynamics{RD.RK4}(model)
    t,dt = 1.1,0.1
    Random.seed!(1)
    x, u = rand(model)
    n,m = RD.dims(model)
    z = KnotPoint(x, u, t, dt)
    ∇c1  = zeros(n,n+m)
    ∇c2  = zeros(n,n+m)
    xdot = zeros(n)
    allocs = 0
    allocs += @ballocated RobotDynamics.dynamics($model, $x, $u) evals=evals samples=samples
    allocs += @ballocated RobotDynamics.dynamics!($model, $xdot, $x, $u) evals=evals samples=samples
    @test xdot == RobotDynamics.dynamics(model, x, u)
    @test allocs == 0
    RobotDynamics.jacobian!(StaticReturn(), ForwardAD(), model, ∇c1, xdot, z)
    RobotDynamics.jacobian!(StaticReturn(), FiniteDifference(), model, ∇c2, xdot, z)
    @test ∇c1 ≈ ∇c2 atol=tol
    RobotDynamics.jacobian!(InPlace(), ForwardAD(), model, ∇c2, xdot, z)
    @test ∇c1 ≈ ∇c2
    RobotDynamics.jacobian!(InPlace(), FiniteDifference(), model, ∇c1, xdot, z)
    @test ∇c1 ≈ ∇c2 atol=tol
    if customjacobian
        RobotDynamics.jacobian!(InPlace(), RD.UserDefined(), model, ∇c1, xdot, z)
        @test ∇c1 ≈ ∇c2
    end
end

# Acrobot
acrobot = RobotZoo.Acrobot()
@test RD.dims(acrobot) == (4,1,4)
test_model(acrobot)

# Car
car = RobotZoo.DubinsCar()
@test RD.dims(car) == (3,2,3)
test_model(car, customjacobian=true)

# Bicycle Car
bicycle = RobotZoo.BicycleModel()
@test RD.dims(bicycle) == (4,2,4)
test_model(bicycle)

bicycle = RobotZoo.BicycleModel(ref=:rear)
@test RD.dims(bicycle) == (4,2,4)
test_model(bicycle)

# Planar Rocket
rocket = RobotZoo.PlanarRocket()
@test RD.dims(rocket) == (8,2,8)
test_model(rocket)

# Planar Quad
quad = RobotZoo.PlanarQuadrotor()
@test RD.dims(quad) == (6,2,6)
test_model(quad)

# Cartpole
cartpole = RobotZoo.Cartpole()
@test RD.dims(cartpole) == (4,1,4)
test_model(cartpole)

# Double Integrator
dim = 3
di = RobotZoo.DoubleIntegrator(dim)
n,m = RD.dims(di)
@test (n,m) == (6,3)
test_model(di)

# Pendulum
pend = RobotZoo.Pendulum()
RobotZoo.Pendulum{Float64}(1,1,1, 1,1,1)
@test RD.dims(pend) == (2,1,2)
test_model(pend)

# Quadrotor
quad = RobotZoo.Quadrotor()
@test RD.dims(quad) == (13,4,13)
test_model(quad,tol=1e-4)

# Yak Plane
yak = RobotZoo.YakPlane(MRP{Float64})
@test RD.dims(yak) == (12,4,12)
test_model(yak,tol=1e-4)

# Test other functions
dt = 0.1
car = RobotZoo.DubinsCar()
n,m = RD.dims(car)
@test zeros(car) == (zeros(n), zeros(m))
@test zeros(Int,car)[1] isa SVector{n,Int}
@test fill(car,0.1) == (fill(0.1,n), fill(0.1,m))
# @test ones(Float32,car)[2] isa SVector{m,Float32}