text:
using AWS
using Checkpoints
using Compat # for only
using Distributed
using FilePathsBase
using JLSO
using Random
using Test

using AWS: AWSConfig
using AWSS3: S3Path, s3_put, s3_list_buckets, s3_create_bucket
using Tables: Tables

Distributed.addprocs(5)
@everywhere using Checkpoints

@testset "Checkpoints" begin
    @everywhere include("testpkg.jl")

    @testset "enabled" begin
        mktempdir() do path
            @test enabled_checkpoints() == []
            Checkpoints.register(["c1", "c2", "c3"])
            @test enabled_checkpoints() == []

            Checkpoints.config("c1", path)
            @test enabled_checkpoints() == ["c1"]

            Checkpoints.config("c2", path)
            @test enabled_checkpoints() == ["c1", "c2"]
        end
    end

    x = reshape(collect(1:100), 10, 10)
    y = reshape(collect(101:200), 10, 10)
    a = collect(1:10)

    @testset "Local handler" begin
        mktempdir() do path
            Checkpoints.config("TestPkg.foo", path)

            TestPkg.foo(x, y)
            TestPkg.bar(a)

            mod_path = joinpath(path, "TestPkg")
            @test isdir(mod_path)

            foo_path = joinpath(path, "TestPkg", "foo.jlso")
            bar_path = joinpath(path, "TestPkg", "bar.jlso")
            @test isfile(foo_path)
            @test !isfile(bar_path)

            data = JLSO.load(foo_path)
            @test data[:x] == x
            @test data[:y] == y
        end
    end

    @testset "deprecated tags syntax" begin
        mktempdir() do path
            Checkpoints.config("TestPkg.deprecated", path)
            TestPkg.deprecated_checkpoint_syntax()
            @test isfile(joinpath(path, "date=2017-01-01", "TestPkg", "deprecated.jlso"))
        end
    end

    @testset "Context tags" begin
        mktempdir() do path
            @everywhere begin
                path=$path
                Checkpoints.config("TestPkg.bar", path)
            end

            @testset "single context tags" begin
                with_checkpoint_tags(:tag => "a") do
                    TestPkg.bar(a)
                end
                @test isfile(joinpath(path, "tag=a", "date=2017-01-01", "TestPkg", "bar.jlso"))
            end

            @testset "NamedTuple tags" begin
                tags = (tag1="some", tag2="thing")
                with_checkpoint_tags(tags) do
                    TestPkg.bar(a)
                end
                @test isfile(joinpath(path, "tag1=some", "tag2=thing", "date=2017-01-01", "TestPkg", "bar.jlso"))
            end

            @testset "nested tags" begin
                @testset "different tags" begin
                    with_checkpoint_tags(:first => "first") do
                        with_checkpoint_tags(:second => "second") do
                            TestPkg.bar(a) # both first and second
                        end
                        TestPkg.bar(a) # only first
                    end
                    @test isfile(joinpath(path, "first=first", "second=second", "date=2017-01-01", "TestPkg", "bar.jlso"))
                    @test isfile(joinpath(path, "first=first", "date=2017-01-01", "TestPkg", "bar.jlso"))
                end

                @testset "duplicate context tags" begin
                    with_checkpoint_tags(:same => "outer") do
                        with_checkpoint_tags(:same => "inner") do
                            TestPkg.bar(a)
                        end
                        TestPkg.bar(a)
                    end
                    @test isfile(joinpath(path, "same=outer", "same=inner", "date=2017-01-01", "TestPkg", "bar.jlso"))
                    @test isfile(joinpath(path, "same=outer", "date=2017-01-01", "TestPkg", "bar.jlso"))
                end

                @testset "same context and package tags" begin
                    with_checkpoint_tags(:date=>"context") do
                        TestPkg.bar(a)
                    end
                    @test isfile(joinpath(path, "date=context", "date=2017-01-01", "TestPkg", "bar.jlso"))
                end
            end

            @testset "multi-process context tags" begin
                @test Distributed.nworkers() > 1
                pmap(["a", "b", "c", "d", "e", "f"]) do tag
                    with_checkpoint_tags(:context_tag => tag) do
                        sleep(rand()) # to make sure not overwritten in the meantime
                        @test Dict(Checkpoints.CONTEXT_TAGS[]...)[:context_tag] == tag
                        TestPkg.bar(a)
                    end
                end
                @test isfile(joinpath(path, "context_tag=e", "date=2017-01-01", "TestPkg", "bar.jlso"))
            end

            @testset "multithreaded" begin
                if Threads.nthreads() > 1
                    Threads.@threads for t = 1:10
                        with_checkpoint_tags(:thread => t) do
                            sleep(rand())
                            @test Dict(Checkpoints.CONTEXT_TAGS[]...)[:thread] == t
                            TestPkg.bar(a)
                        end
                    end
                    @test isfile(joinpath(path, "thread=8", "date=2017-01-01", "TestPkg", "bar.jlso"))
                else
                    @warn("Skipping multi-threading tests. Start with `julia -t n` for n threads.")
                end
            end
        end
    end

    include("indexing.jl")

    if get(ENV, "LIVE", "false") == "true"
        @testset "S3 handler" begin
            config = global_aws_config()
            prefix = "Checkpoints.jl"
            bucket = get(
                ENV,
                "TestBucketAndPrefix",
                string(aws_account_number(config), "-tests")
            )
            bucket in s3_list_buckets(config) || s3_create_bucket(config, bucket)

            bucket_path = Path("s3://$bucket/$prefix/")
            mkdir(bucket_path; recursive=true, exist_ok=true)

            mktmpdir(bucket_path) do fp
                Checkpoints.config("TestPkg.bar", fp)

                TestPkg.bar(a)
                expected_path = joinpath(fp, "date=2017-01-01", "TestPkg/bar.jlso")
                @test JLSO.load(IOBuffer(read(expected_path)))[:data] == a
            end
        end
    else
        @warn("Skipping AWS S3 tests. Set `ENV[\"LIVE\"] = true` to run.")
    end

    @testset "Sessions" begin
        @testset "No-op" begin
            mktempdir() do path
                d = Dict(zip(map(x -> Symbol(randstring(4)), 1:10), map(x -> rand(10), 1:10)))

                TestPkg.baz(d)

                mod_path = joinpath(path, "TestPkg")
                baz_path = joinpath(path, "TestPkg", "baz.jlso")
                @test !isfile(baz_path)
            end
        end
        @testset "Single" begin
            mktempdir() do path
                d = Dict(zip(
                    map(x -> Symbol(randstring(4)), 1:10),
                    map(x -> rand(10), 1:10)
                ))
                Checkpoints.config("TestPkg.baz", path)

                TestPkg.baz(d)

                mod_path = joinpath(path, "TestPkg")
                @test isdir(mod_path)

                baz_path = joinpath(path, "TestPkg", "baz.jlso")
                @test isfile(baz_path)

                data = JLSO.load(baz_path)
                for (k, v) in data
                    @test v == d[Symbol(k)]
                end
            end
        end
        @testset "Multi" begin
            mktempdir() do path
                a = Dict(zip(
                    map(x -> Symbol(randstring(4)), 1:10),
                    map(x -> rand(10), 1:10)
                ))
                b = rand(10)
                Checkpoints.config("TestPkg.qux" , path)

                TestPkg.qux(a, b)

                mod_path = joinpath(path, "TestPkg")
                @test isdir(mod_path)

                qux_a_path = joinpath(path, "TestPkg", "qux_a.jlso")
                @test isfile(qux_a_path)

                qux_b_path = joinpath(path, "TestPkg", "qux_b.jlso")
                @test isfile(qux_b_path)

                data = JLSO.load(qux_a_path)
                for (k, v) in data
                    @test v == a[Symbol(k)]
                end

                data = JLSO.load(qux_b_path)
                @test data[:data] == b
            end
        end
    end
end


text:
# compute ols coefficients, fitted values, and errors
function lsfit(Y, X)
    beta = X\Y
    fit = X*beta
    errors = Y - fit
    return beta, fit, errors
end

ext: jl

max_stars_repo_name: nilshg/Econometrics

max_issues_repo_name: nilshg/Econometrics

max_forks_repo_name: nilshg/Econometrics


text:
using LoopVectorization, SnoopCompile
pkgdir = dirname(@__DIR__)
tinf = @snoopi tmin=0.01 include(joinpath(pkgdir, "test", "runtests.jl"))
pc = SnoopCompile.parcel(tinf; blacklist=["vmaterialize", "vmaterialize!", "vreduce", "Base.Broadcast.materialize", "_vreduce_dims!", "vmapreduce"])
pcs = pc[:LoopVectorization]
open(joinpath(pkgdir, "src", "precompile.jl"), "w") do io
    println(io, """
    function _precompile_()
        ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
    """)
    for stmt in sort(pcs)
        println(io, "    ", stmt)
    end
    println(io, "end")
end


text:
include("../src/UNSflow.jl")

using UNSflow

function fgfromrhoGauss(rho::Float64)
    f = sqrt(2./pi)*exp(-rho^2/2.)
    g = erf(rho/sqrt(2.)) - rho*f
    return f, g
end

function fgfromrhoLeonard(rho::Float64)
    f = 7.5/(rho^2 + 1.)^3.5
    g = (rho^3*(rho^2 + 2.5))/(rho^2 + 1.)^2.5
    return f, g
end

function mutual_ind(vorts::Vector{ThreeDVort})
      for i = 1:length(vorts)
          for j = i+1:length(vorts)
            rvec = vorts[i].x - vorts[j].x
#              dx = vorts[i].x[1] - vorts[j].x[1]
#              dy = vorts[i].x[2] - vorts[j].x[2]
#              dz = vorts[i].x[3] - vorts[j].x[3]
              #source - tar

            r = norm(rvec)
              rhoi = r/vorts[i].vc
              rhoj = r/vorts[j].vc

            f, g = fgfromrhoLeonard(rhoi)

            vorts[j].v[:] -= -g*cross(rvec,vorts[i].s)/(4.*pi*r^3)

              vorts[j].ds[:] += (-g*cross(vorts[j].s, vorts[i].s)/rhoi^3 +
            ((3*g/rhoi^3 - f)*dot(vorts[j].s, rvec)*cross(rvec,vorts[i].s))/r^2)/(4*pi*vorts[i].vc^3)

            f, g = fgfromrhoLeonard(rhoj)
            vorts[i].v[:] += -g*cross(rvec,vorts[j].s)/(4.*pi*r^3)

            vorts[i].ds[:] += (-g*cross(vorts[i].s, vorts[j].s)/rhoj^3 +
                ((3*g/rhoj^3 - f)*dot(vorts[i].s, rvec)*cross(rvec,vorts[j].s))/r^2)/(4*pi*vorts[j].vc^3)

          end
      end
      return vorts
end

function dovort()
    nvort = 250
vorts = ThreeDVort[]
for i = 1:nvort/5
        for j = 1:5
            x = [0.1*real(j); real(i)*0.05; 0.0]
    s = [0.0; 0.002; 0.0]
    vcore = 0.02
    v = [0.0; 0.0; 0.0]
    ds = [0.0; 0.0; 0.0]
    push!(vorts, ThreeDVort(x, s, vcore, v, ds))
end
    end

ntime = 100
dt = 0.015

@time for i =1:ntime
    for j = 1:nvort
        vorts[j].v[:] = 0
        vorts[j].ds[:] = 0
    end
    mutual_ind(vorts)
    for j = 1:nvort
        vorts[j].x[:] += vorts[j].v[:]*dt
        vorts[j].s[:] += vorts[j].ds[:]*dt
    end
end

end


text:
import Base: show

function print_dimacs_cnf(io::IO, formula::Formula, root_var::Int)
  println(io, "p cnf ", root_var, " ", clause_count(formula))
  for clause in formula.clauses
    for literal in clause.literals
      print(io, literal, " ")
    end
    print(io, "0\n")
  end
end

function print_dimacs_cnf(io::IO, ast2cnf_res::Ast2CnfResult)
  print(io, "c Original variables:")
  for identifier in values(ast2cnf_res.identifier_dict)
    print(io, " ", identifier)
  end
  print(io, "\n")

  println(io, "c Root node variable: ", ast2cnf_res.variable_count)

  print_dimacs_cnf(io, ast2cnf_res.result, ast2cnf_res.variable_count)
end

function show(io::IO, cl::Clause)
  print(io, "(")
  if 0 == length(cl)
    print(io, ")")
    return
  end

  print(io, cl[1])
  @inbounds for i in 2:length(cl)
    print(io, " ∨ ", cl[i])
  end
  print(io, ")")
end

function show(io::IO, fla::Formula)
  print(io, "(")
  if 0 == length(fla)
    print(io, ")")
    return
  end

  print(io, fla[1])
  @inbounds for i in 2:length(fla)
    print(io, " ∧ ", fla[i])
  end
  print(io, ")")
end


text:
using LLVM.Interop
using InteractiveUtils

@testset "interop" begin

@testset "base" begin

@generated function add_one(i)
    Context() do ctx
        T_int = convert(LLVMType, Int; ctx)

        f, ft = create_function(T_int, [T_int])

        Builder(ctx) do builder
            entry = BasicBlock(f, "entry"; ctx)
            position!(builder, entry)

            val = add!(builder, parameters(f)[1], ConstantInt(T_int, 1))

            ret!(builder, val)
        end

        call_function(f, Int, Tuple{Int}, :i)
    end
end

@test add_one(1) == 2

@eval struct GhostType end
@eval struct NonGhostType1
    x::Int
end
@eval mutable struct NonGhostType2 end

@test isghosttype(GhostType)
@test !isghosttype(NonGhostType1)
@test !isghosttype(NonGhostType2)
@test isboxed(NonGhostType2)

Context() do ctx
    @test isghosttype(GhostType; ctx)
    @test !isghosttype(NonGhostType1; ctx)
    @test !isghosttype(NonGhostType2; ctx)
end

end

@testset "asmcall" begin

# only asm

a1() = @asmcall("nop")
@test a1() == nothing

a2() = @asmcall("nop", Nothing)
@test a2() == nothing

a3() = @asmcall("nop", Nothing, Tuple{})
@test a3() == nothing

# asm + constraints

b1() = @asmcall("nop", "")
@test b1() == nothing

b2() = @asmcall("nop", "", Nothing)
@test b2() == nothing

b3() = @asmcall("nop", "", Nothing, Tuple{})
@test b3() == nothing

# asm + constraints + side-effects

c1() = @asmcall("nop", "", false)
@test c1() == nothing

c2() = @asmcall("nop", "", false, Nothing)
@test c2() == nothing

c3() = @asmcall("nop", "", false, Nothing, Tuple{})
@test c3() == nothing

if Sys.ARCH == :x86 || Sys.ARCH == :x86_64

# arguments

d1(a) = @asmcall("bswap \$0", "=r,r", Int32, Tuple{Int32}, a)
@test d1(Int32(1)) == Int32(16777216)

# multiple output registers

e1() = @asmcall("mov \$\$1, \$0; mov \$\$2, \$1;", "=r,=r", Tuple{Int16,Int32})
@test e1() == (Int16(1), Int32(2))

# TODO: alternative test snippets for other platforms

end

end

@testset "passes" begin

Context() do ctx
LLVM.Module("SomeModule"; ctx) do mod
ModulePassManager() do pm

demote_float16!(pm)
julia_licm!(pm)
alloc_opt!(pm)
barrier_noop!(pm)
gc_invariant_verifier!(pm)
gc_invariant_verifier!(pm, true)
lower_exc_handlers!(pm)
combine_mul_add!(pm)
multi_versioning!(pm)
propagate_julia_addrsp!(pm)
lower_ptls!(pm)
lower_ptls!(pm, true)
lower_simdloop!(pm)
remove_ni!(pm)
late_lower_gc_frame!(pm)
final_lower_gc!(pm)

end
end
end

end

@testset "intrinsics" begin
    @test assume(true) === nothing
    @test assume() do
        true
    end === nothing
    @test assume(rand()) do x
        0 <= x <= 1
    end isa Float64
end

using Core: LLVMPtr

@testset "pointer operations" begin
    a = LLVMPtr{Int,0}(0)
    b = LLVMPtr{Int,0}(1)
    c = LLVMPtr{UInt,0}(0)
    d = LLVMPtr{UInt,0}(1)
    e = LLVMPtr{Int,1}(0)
    f = LLVMPtr{Int,1}(1)

    @test UInt(a) == 0
    @test UInt(f) == 1

    @test isequal(a,a)
    @test !isequal(a,b)
    @test !isequal(a,c)
    @test !isequal(a,d)
    @test !isequal(a,e)
    @test !isequal(a,f)

    @test a == a
    @test a != b
    @test a == c
    @test a != d
    @test a != e
    @test a != f

    @test a < b
    @test a < d
    @test_throws MethodError a < f

    @test b - a == 1
    @test d - a == 1
    @test_throws MethodError  f - a

    @test a + 1 == b
    @test c + 1 == d
    @test e + 1 == f

    @test b - 1 == a
    @test d - 1 == c
    @test f - 1 == e
end

@testset "unsafe_load" begin
    a = Int64[1]
    ptr = reinterpret(Core.LLVMPtr{Int64,0}, pointer(a))
    @test unsafe_load(ptr) == 1
    unsafe_store!(ptr, 2)
    @test unsafe_load(ptr) == 2

    ir = sprint(io->code_llvm(io, unsafe_load, Tuple{typeof(ptr)}))
    if Sys.iswindows() && Sys.WORD_SIZE == 32
        # FIXME: Win32 nightly emits a i64*, even though bitstype_to_llvm uses T_int8
        @test_broken contains(ir, r"@julia_unsafe_load_\d+\(i8\*")
    else
        @test contains(ir, r"@julia_unsafe_load_\d+\(i8\*")
    end
    @test contains(ir, r"load i64, i64\* %\d+, align 1")

    ir = sprint(io->code_llvm(io, unsafe_load, Tuple{typeof(ptr), Int, Val{4}}))
    @test contains(ir, r"load i64, i64\* %\d+, align 4")
end

@testset "reinterpret(Nothing, nothing)" begin
    ptr = reinterpret(Core.LLVMPtr{Nothing,0}, C_NULL)
    @test unsafe_load(ptr) === nothing
end

@testset "TBAA" begin
    load(ptr) = unsafe_load(ptr)
    store(ptr) = unsafe_store!(ptr, 0)

    for f in (load, store)
        ir = sprint(io->code_llvm(io, f,
                                  Tuple{Core.LLVMPtr{Float32,1}};
                                  dump_module=true, raw=true))
        @test occursin("custom_tbaa_addrspace(1)", ir)

        # no TBAA on generic pointers
        ir = sprint(io->code_llvm(io, f,
                                  Tuple{Core.LLVMPtr{Float32,0}};
                                  dump_module=true, raw=true))
        @test !occursin("custom_tbaa", ir)
    end
end

@testset "ghost values" begin
    @eval struct Singleton end

    ir = sprint(io->code_llvm(io, unsafe_load,
                              Tuple{Core.LLVMPtr{Singleton,0}}))
    @test occursin("ret void", ir)
    @test unsafe_load(reinterpret(Core.LLVMPtr{Singleton,0}, C_NULL)) === Singleton()

    ir = sprint(io->code_llvm(io, unsafe_store!,
                              Tuple{Core.LLVMPtr{Singleton,0},
                              Singleton}))
    @test !occursin("\bstore\b", ir)
end

@testset "type-preserving ccall" begin
    # NOTE: the auto-upgrader will remangle these intrinsics, but only if they were
    #       specified in the first place (`if Name.startswith("ptr.annotation.")`)
    bad(ptr::Ptr{T}) where {T} = ccall("llvm.ptr.annotation.p0i64", llvmcall, Ptr{T}, (Ptr{T}, Ptr{Int8}, Ptr{Int8}, Int32), ptr, C_NULL, C_NULL, 0)
    good(ptr::Ptr{T}) where {T} = @typed_ccall("llvm.ptr.annotation.p0i64", llvmcall, Ptr{T}, (Ptr{T}, Ptr{Int8}, Ptr{Int8}, Int32), ptr, C_NULL, C_NULL, 0)

    ir = sprint(io->code_llvm(io, bad, Tuple{Ptr{Float64}}))
    @test occursin("i64 @llvm.ptr.annotation.p0i64(i64", ir)

    ir = sprint(io->code_llvm(io, good, Tuple{Ptr{Float64}}))
    @test occursin("double* @llvm.ptr.annotation.p0f64(double*", ir)

    bad(ptr::LLVMPtr{T}) where {T} = ccall("llvm.ptr.annotation.p0i64", llvmcall, LLVMPtr{T,1}, (LLVMPtr{T,1}, Ptr{Int8}, Ptr{Int8}, Int32), ptr, C_NULL, C_NULL, 0)
    good(ptr::LLVMPtr{T}) where {T} = @typed_ccall("llvm.ptr.annotation.p0i64", llvmcall, LLVMPtr{T,1}, (LLVMPtr{T,1}, Ptr{Int8}, Ptr{Int8}, Int32), ptr, C_NULL, C_NULL, 0)

    ir = sprint(io->code_llvm(io, bad, Tuple{LLVMPtr{Float64,1}}))
    # XXX: why isn't this remangled to p1i8? and why doesn't it currently assert somewhere?
    @test occursin("i8 addrspace(1)* @llvm.ptr.annotation.p0i64(i8 addrspace(1)*", ir)

    ir = sprint(io->code_llvm(io, good, Tuple{LLVMPtr{Float64,1}}))
    @test occursin("double addrspace(1)* @llvm.ptr.annotation.p1f64(double addrspace(1)*", ir)

    # test return nothing
    LLVM.Interop.@typed_ccall("llvm.donothing", llvmcall, Cvoid, ())
end

end


text:
####################  Translation Search ##########################

function tfmshift(params, img::AbstractArray{T,N}) where {T,N}
    length(params) == N || throw(DimensionMismatch("expected $N parameters, got $(length(params))"))
    return Translation(params...)
end

#slow because it warps for every shift instead of using fourier method
function translate_mm_slow(params, fixed, moving, thresh; initial_tfm=IdentityTransformation())
    tfm = initial_tfm ∘ tfmshift(params, moving)
    moving, fixed = warp_and_intersect(moving, fixed, tfm)
    mm = mismatch0(fixed, moving; normalization=:intensity)
    return ratio(mm, thresh, Inf)
end

function qd_translate_fine(fixed, moving;
                           initial_tfm=IdentityTransformation(),
                           minwidth=fill(0.01, ndims(fixed)),
                           thresh=0.1*sum(abs2.(fixed[.!(isnan.(fixed))])),
                           kwargs...)
    f(x) = translate_mm_slow(x, fixed, moving, thresh; initial_tfm=initial_tfm)
    upper = fill(1.0, ndims(fixed))
    lower = -upper
    root, x0 = _analyze(f, lower, upper; minwidth=minwidth, print_interval=100, kwargs...)
    box = minimum(root)
    tfmfine = initial_tfm ∘ tfmshift(position(box, x0), moving)
    return tfmfine, value(box)
end

"""
`tform, mm = qd_translate(fixed, moving, mxshift; presmoothed=false, thresh=thresh, kwargs...)`
optimizes a simple shift (translation) to minimize the mismatch between `fixed` and
`moving` using the QuadDIRECT algorithm with the constraint that no shifts larger than
``mxshift` (after an optional `initial_tfm`) will be considered.

Both `mxshift` and the returned translation are specified in terms of pixel units, so the
algorithm need not be aware of anisotropic sampling.

The algorithm involves two steps: the first step uses a fourier method to speed up
the search for the best whole-pixel shift.  The second step refines the search for sub-pixel accuracy.
The default precision of this step is 1% of one pixel (0.01) for each dimension of the image.
You can override the default with the `minwidth` argument.  `kwargs...` can also include
any other keyword argument that can be passed to `QuadDIRECT.analyze`.
It's recommended that you pass your own stopping criteria when possible (i.e. `rtol`, `atol`, and/or `fvalue`).

Use `presmoothed=true` if you have called [`qsmooth`](@ref) on `fixed` before calling `qd_affine`.
Do not smooth `moving`.

If you have a good initial guess at the solution, pass it with the `initial_tfm` kwarg to jump-start the search.
`thresh` enforces a certain amount of sum-of-squared-intensity overlap between the two images;
with non-zero `thresh`, it is not permissible to "align" the images by shifting one entirely out of the way of the other.

If the `crop` keyword arg is `true` then `fixed` is cropped by `mxshift` (after the optional `initial_tfm`) on all sides
so that there will be complete overlap between `fixed` and `moving` for any evaluated shift. This avoids edge effects
that can occur due to normalization when the transformed `moving` doesn't fully overlap with `fixed`.
"""
function qd_translate(fixed, moving, mxshift;
                      presmoothed=false,
                      thresh=0.1*sum(abs2.(fixed[.!(isnan.(fixed))])),
                      initial_tfm=IdentityTransformation(),
                      minwidth=fill(0.01, ndims(fixed)), print_interval=100, crop=false, kwargs...)
    fixed, moving = float(fixed), float(moving)
    if presmoothed
        moving = qinterp(eltype(fixed), moving)
    end
    print_interval < typemax(Int) && print("Running coarse step\n")
    if crop
        #we enforce that moving is always bigger than fixed by amount 2*(maxshift+1) (the +1 is for the fine step)
        sz = size(fixed) .- (2 .* mxshift)
        if any(size(moving) .< (2 .* (mxshift.+1)))
            error("Moving image size must be at least 2 * (mxshift+1) when crop_edges is set to true")
        end
        cropped_inds_f = crop_rng.(axes(fixed), mxshift)
        cropped_inds_m = crop_rng.(axes(moving), mxshift)
        moving_inner = view(moving, cropped_inds_m...)
        fixed_inner = view(fixed, cropped_inds_f...)
        moving_fine = OffsetArray(moving, (-1 .* mxshift)...)
    else
        fixed_inner = fixed
        moving_inner = moving_fine = moving
    end
    best_shft, mm = best_shift(fixed_inner, moving_inner, mxshift, thresh; normalization=:intensity, initial_tfm=initial_tfm)
    tfm_coarse = initial_tfm ∘ Translation(best_shft)
    print_interval < typemax(Int) && print("Running fine step\n")
    return qd_translate_fine(fixed_inner, moving_fine; initial_tfm=tfm_coarse, thresh=thresh, minwidth=minwidth, print_interval=print_interval, kwargs...)
end

crop_rng(rng::AbstractUnitRange{Int}, amt::Int) = (first(rng)+amt):(last(rng)-amt)


text:
#=

# 311: Heat Equation with boundary diffusion
([source code](SOURCE_URL))

=#

module Example311_HeatEquation_BoundaryDiffusion
using Printf
using VoronoiFVM
using ExtendableGrids

"""
  We solve the following system

      ∂_tu - εΔu = 0            in [0,T] × Ω
           ε∇u⋅ν = k(u-v)       on [0,T] × Γ_1
           ε∇u⋅ν = 0            on [0,T] × (∂Ω ∖ Γ_1)
  ∂_tv -ε_ΓΔ_Γ v = f(x) +k(u-v) on [0,T] × Γ_1
          u(0)   = 0.5          in   {0} × Ω
          v(0)   = 0.5          on   {0} × Γ_1
"""

function main(n=1)

    breg = 5 # boundary region number for surface diffusion

    println("Surface diffusion example")

    hmin   = 0.01 * 2.0^(-n+1)
    hmax   = 0.1  * 2.0^(-n+1)
    XLeft  = geomspace(0.0, 0.5, hmax, hmin)
    XRight = geomspace(0.5, 1.0, hmin, hmax)
    X      = glue(XLeft, XRight)

    Z      = geomspace(0.0, 1.0, hmin, 2*hmax)

    grid   = VoronoiFVM.Grid(X, X, Z)

    # parameters
    eps      = 1.0e0  # bulk heat conduction coefficient
    eps_surf = 1.0e-2 # surface diffusion coefficient
    k        = 1.0    # transmission coefficient
    physics  = VoronoiFVM.Physics(
        flux        = function(f,u,edge)
                            f[1] = eps*(u[1,1]-u[1,2])
                      end,

        bflux       = function(f, u, edge)
                        if edge.region == breg
                          f[2]     = eps_surf*(u[2,1]-u[2,2])
                        else
                          f[2] = 0.0
                        end

                      end,
        breaction   = function(f,u,node)
                        if node.region == breg
                          f[1] = k*(u[1]-u[2])
                          f[2] = k*(u[2]-u[1])
                        else
                          f[1] = 0.0
                          f[2] = 0.0
                        end
                      end,
        bsource      = function(f, bnode)
                        x1   = bnode[1]-0.5
                        x2   = bnode[2]-0.5
                        x3   = bnode[3]-0.5
                        f[2] = 1.0e4*exp(-20.0*(x1^2+x2^2+x3^2))
                      end,

        bstorage    = function(f,u,node)
                        if node.region == breg
                          f[2] = u[2]
                        end
                      end,

        storage     = function(f,u,node)
                        f[1] = u[1]
                      end
    )

    sys=VoronoiFVM.System(grid,physics,unknown_storage=:sparse)
    enable_species!(sys,1,[1])
    enable_boundary_species!(sys,2,[breg])

    function tran32!(a,b)
        a[1]=b[2]
    end

    bgrid2=subgrid(grid,[breg],boundary=true,transform=tran32!)

    inival  = unknowns(sys)
    U       = unknowns(sys)
    inival .= 0.5

    control             = VoronoiFVM.NewtonControl()
    control.verbose     = true
    control.tol_linear  = 1.0e-5
    control.max_lureuse = 10

    tstep = 0.1
    time  = 0.0
    step  = 0
    T     = 1.0
    while time < T
        time=time+tstep
        solve!(U, inival, sys, control=control, tstep=tstep)
        inival.=U
        U_surf=view(U[2,:],bgrid2)

        if true
            @printf("time=%g\n",time)
        end

        tstep*=1.0

        step += 1
    end

    nothing
end

function test()
    main()
    true
end

end


text:
#=
Functionality regarding spatial coordinates of an array, i.e. Longitude and Lattitude
as well as equal area grid handling and anything else related to space.
=#
using Statistics, StatsBase, StaticArrays
export SVector # for equal area grid
#########################################################################
# Spatial indexing
#########################################################################
export spatialidxs

"""
    spatialidxs(A::ClimArray) → idxs
Return an iterable that can be used to access all spatial points of `A` with the syntax
```julia
idxs = spatialidxs(A)
for i in idxs
    slice_at_give_space_point = A[i...]
end
```
Works for standard grid as well as equal area (`...` necessary because `i` is a `Tuple`).
"""
spatialidxs(A::AbDimArray) = spatialidxs(spacestructure(A), A)
function spatialidxs(::Grid, A)
    lons = (Lon(i) for i in 1:size(A, Lon))
    lats = (Lat(i) for i in 1:size(A, Lat))
    return Iterators.product(lons, lats)
end

function spatialidxs(::EqArea, A)
    return ((Coord(i),) for i in 1:size(A, Coord))
end

#########################################################################
# Periodicity of longitude
#########################################################################
export lon_distance, wrap_lon
"""
    wrap_lon(x)
Wrap given longitude to -180 to 180 degrees.
"""
wrap_lon(x) = @. -180 + (360 + ((x+180) % 360)) % 360

"""
    lon_distance(λ1, λ2, Δλ = 360) → δ
Calculate distance `δ` (also in degrees) between longitudes `λ1, λ2`, but taking into
account the periodic nature of longitude, which has period 360ᵒ.
"""
function lon_distance(x, y, p = eltype(x)(360))
    moddis = mod(abs(x - y), p)
    min(moddis, p - moddis)
end

#########################################################################
# averaging functions over space or time
#########################################################################
using StatsBase

export latmean, spacemean, zonalmean, spaceagg, uniquelats

# TODO: Document what it means to be Coord space.
# We expect that the coordinates are sorted by latitude

"""
    zonalmean(A::ClimArray)
Return the zonal mean of `A`.
Optionally do the mean for the data in range `r` of the longitude
(`r` is fed into the dimension so it can be A range or an arbitrary selector).

Works for both grid and equal area space.
"""
zonalmean(A::AbDimArray, args...) = zonalmean(spacestructure(A), A, args...)
zonalmean(::Grid, A::AbDimArray) = dropagg(mean, A, Lon)

function zonalmean(::EqArea, A::AbDimArray) where {T}
    idxs, lats = uniquelats(A)
    other = otherdims(A, Coord())
    n = A.name == "" ? "" : A.name*", zonally averaged"
    r = zeros(eltype(A), (length(lats), size.(Ref(A), other)...), other)
    R = ClimArray(r, (Lat(lats), other...), n)
    for (i, r) in enumerate(idxs)
        for j in otheridxs(A, Coord())
            R[Lat(i), j...] = mean(view(A, Coord(r), j...))
        end
    end
    return R
end
function zonalmean(::EqArea, A::AbDimArray{T, 1}) where {T}
    idxs, lats = uniquelats(A)
    res = zeros(T, length(lats))
    for (i, r) in enumerate(idxs)
        res[i] = mean(view(A.data, r))
    end
    return ClimArray(res, (Lat(lats),))
end

"""
    uniquelats(A::AbDimArray) → idxs, lats
    uniquelats(c::Vector{<:AbstractVector}) → idxs, lats
Find the unique latitudes of `A`. Return the indices (vector of ranges) that each latitude
in `lats` covers, as well as the latitudes themselves.
"""
uniquelats(A::AbDimArray) = uniquelats(dims(A, Coord))
function uniquelats(c)
    @assert issorted(c, by = x -> x[2])
    idxs = Vector{UnitRange{Int}}()
    lats = eltype(eltype(c))[]
    sizehint!(lats, round(Int, sqrt(length(c))))
    iprev = 1
    for i in 2:length(c)
        if c[i][2] != c[i-1][2]
            push!(lats, c[i-1][2])
            push!(idxs, iprev:(i-1))
            iprev = i
        end
    end
    push!(lats, c[end][2])
    push!(idxs, iprev:length(c))
    sizehint!(lats, length(lats))
    return idxs, lats
end

"""
    latmean(A::ClimArray [, r])
Return the latitude-mean `A` (mean across dimension `Lat`).
Optionally do the mean for the data in range `r` of that dimension.

This function properly weights the mean by the cosine of the latitude.
"""
function latmean(A::AbDimArray, r = 1:size(A, Lat))
    A = A[Lat(r)]
    lw = _latweights(A)
    if ndims(A) > 1
        return dropagg(sum, dimwise(*, A, lw), Lat)
    else
        return sum(A .* lw)
    end
end
# Warning!!! `_latweights` divides by the weight sum, because it is intended to be
# used only with the `sum` function (for A)
_latweights(A::AbDimArray) = _latweights(dims(A, Lat))
function _latweights(A::Lat)
    we = cosd.(A.val)
    we ./= sum(we)
    return ClimArray(we, (A,))
end

using StatsBase

"""
    spacemean(A::ClimArray [, w]) = spaceagg(mean, A, w)
Average given `A` over its spatial coordinates.
Optionally provide statistical weights in `w`.
"""
spacemean(A, exw=nothing) = spaceagg(mean, A, exw)

"""
    spaceagg(f, A::ClimArray, w = nothing)
Aggregate `A` using function `f` (e.g. `mean`) over all available space (i.e.
longitude and latitude) of `A`, weighting every part of `A` by its spatial area.
The function works for grid as well as equal area space.

`w` can be extra weights, to weight each spatial point with. `w` can either be
just an `AbDimArray` with same space as `A`, or of exactly same shape as `A`.
"""
spaceagg(f, A::AbDimArray, exw=nothing) = spaceagg(spacestructure(A), f, A, exw)
function spaceagg(::Grid, f, A::AbDimArray, w=nothing)
    wtype = spaceweightassert(A, w)
    cosweights = repeat(cosd.(dims(A, Lat).val)', size(A, Lon))
    # TODO: Extends so that this assertion is not necessary:
    @assert dimindex(A, Lon) < dimindex(A, Lat) "longitude must precede latitude"
    other = otherdims(A, (Lon, Lat))
    # pre-calculate weights if possible
    if wtype == :no
        W = weights(cosweights)
    elseif wtype == :d2
        W = weights(cosweights .* Array(w))
    end
    # if A is only 2-dimensional, operation is trivial and single number
    if ndims(A) == 2
        return f(A, W)
    end
    # do the weighted average
    oidxs = otheridxs(A, (Lon(), Lat()))
    if wtype != :dany
        r = map(i -> f(view(A, i), W), oidxs)
    else
        # TODO: This multiplication .* here assumes that the lon-lat grid is the
        # first dimension.
        r = map(i -> f(view(A, i), weights(view(w, i) .* cosweights)), oidxs)
    end
    n = A.name == "" ? "" : A.name*", spatially aggregated with $(string(f))"
    return ClimArray(r, other, n)
end

function spaceweightassert(A, w)
    if !isnothing(w)
        wdims = dims(w)
        if length(wdims) == 2
            @assert wdims == dims(A, (Lon, Lat))
            wtype = :d2
        else
            @assert wdims == dims(A)
            wtype = :dany
        end
    else
        wtype = :no
    end
    return wtype
end

spaceagg(::EqArea, f, A, ::Nothing) = dropagg(f, A, Coord)
# I think the best scenario is to modify `dropagg` to take in weights.
function spaceagg(::EqArea, f, A, exw)
    error("TODO")
    w = pweights(Array(exw))
    dropagg(f, A, Coord)
end

#########################################################################
# Hemispheric sum/difference
#########################################################################
export hemispheric_means, hemispheric_functions

"""
    hemispheric_functions(A::ClimArray) → north, south
Return two arrays `north, south`, by splitting `A` to its northern and southern hemispheres,
appropriately translating the latitudes of `south` so that both arrays have the same
latitudinal dimension (and thus can be compared and do opperations between them).
"""
hemispheric_functions(A) = hemispheric_functions(spacestructure(A), A)
function hemispheric_functions(::Grid, A)
    nh = A[Lat(Between(0,  90))]
    sh = A[Lat(Between(-90, 0))]
    # TODO: this can be a function "reverse dim"
    di = dimindex(sh, Lat)
    newdims = [dims(sh)...]
    newdims[di] = dims(nh, Lat)
    data = reverse(Array(sh); dims = di)
    sh = ClimArray(data, (newdims...,))
    return nh, sh
end

function hemispheric_functions(::EqArea, A)
    c = dims(A, Coord)
    @assert issorted(c, by = x -> x[2])
    shi, nhi = hemisphere_indices(c)
    nh = A[Coord(nhi)]
    sh = A[Coord(shi)]
    oldc = dims(sh, Coord).val
    si = sortperm(oldc, by = x -> x[2], rev = true)
    newc = [SVector(x[1], abs(x[2])) for x in oldc[si]]
    di = dimindex(sh, Coord)
    newdims = Any[dims(sh)...]
    newdims[di] = Coord(newc)
    data = reverse(Array(sh); dims = di)
    sh = ClimArray(data, (newdims...,))
    return nh, sh
end

"""
    hemispheric_means(A) → nh, sh
Return the (proper) averages of `A` over the northern and southern hemispheres.
Notice that this function explicitly does both zonal as well as meridional averaging.
Use [`hemispheric_functions`](@ref) to just split `A` into two hemispheres.
"""
hemispheric_means(A) = hemispheric_means(spacestructure(A), A)
function hemispheric_means(::Grid, A::AbDimArray)
    @assert hasdim(A, Lat)
    if hasdim(A, Lon)
        B = zonalmean(A)
    else
        B = A
    end
    nh = latmean(B[Lat(Between(0,  90))])
    sh = latmean(B[Lat(Between(-90, 0))])
    return nh, sh
end

function hemispheric_means(::EqArea, A::AbDimArray)
    shi, nhi = hemisphere_indices(c)
    nh = dropagg(mean, A[Coord(nhi)], Coord)
    sh = dropagg(mean, A[Coord(shi)], Coord)
    return nh, sh
end

latitudes(A) = latitudes(spacestructure(A), A)
latitudes(::Grid, A) = dims(A, Lat).val
latitudes(::EqArea, A) = unique!([x[2] for x in dims(A, Coord)])


text:
# Julia wrapper for header: /Users/jgoldfar/Documents/misc/julia/Libui/src/../deps/src/ui.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function uiInit(options)
	ccall((:uiInit, libui), Cstring, (Ptr{uiInitOptions},), options)
end

function uiUninit()
	ccall((:uiUninit, libui), Nothing, ())
end

function uiFreeInitError(err)
	ccall((:uiFreeInitError, libui), Nothing, (Cstring,), err)
end

function uiMain()
	ccall((:uiMain, libui), Nothing, ())
end

function uiMainSteps()
	ccall((:uiMainSteps, libui), Nothing, ())
end

function uiMainStep(wait::Integer)
	ccall((:uiMainStep, libui), Cint, (Cint,), wait)
end

function uiQuit()
	ccall((:uiQuit, libui), Nothing, ())
end

function uiQueueMain(f, data)
	ccall((:uiQueueMain, libui), Nothing, (Ptr{Nothing}, Ptr{Nothing}), f, data)
end

function uiTimer(milliseconds::Integer, f, data)
	ccall((:uiTimer, libui), Nothing, (Cint, Ptr{Nothing}, Ptr{Nothing}), milliseconds, f, data)
end

function uiOnShouldQuit(f, data)
	ccall((:uiOnShouldQuit, libui), Nothing, (Ptr{Nothing}, Ptr{Nothing}), f, data)
end

function uiFreeText(text)
	ccall((:uiFreeText, libui), Nothing, (Cstring,), text)
end

function uiControlDestroy(arg1)
	ccall((:uiControlDestroy, libui), Nothing, (Ptr{uiControl},), arg1)
end

function uiControlHandle(arg1)
	ccall((:uiControlHandle, libui), Csize_t, (Ptr{uiControl},), arg1)
end

function uiControlParent(arg1)
	ccall((:uiControlParent, libui), Ptr{uiControl}, (Ptr{uiControl},), arg1)
end

function uiControlSetParent(arg1, arg2)
	ccall((:uiControlSetParent, libui), Nothing, (Ptr{uiControl}, Ptr{uiControl}), arg1, arg2)
end

function uiControlToplevel(arg1)
	ccall((:uiControlToplevel, libui), Cint, (Ptr{uiControl},), arg1)
end

function uiControlVisible(arg1)
	ccall((:uiControlVisible, libui), Cint, (Ptr{uiControl},), arg1)
end

function uiControlShow(arg1)
	ccall((:uiControlShow, libui), Nothing, (Ptr{uiControl},), arg1)
end

function uiControlHide(arg1)
	ccall((:uiControlHide, libui), Nothing, (Ptr{uiControl},), arg1)
end

function uiControlEnabled(arg1)
	ccall((:uiControlEnabled, libui), Cint, (Ptr{uiControl},), arg1)
end

function uiControlEnable(arg1)
	ccall((:uiControlEnable, libui), Nothing, (Ptr{uiControl},), arg1)
end

function uiControlDisable(arg1)
	ccall((:uiControlDisable, libui), Nothing, (Ptr{uiControl},), arg1)
end

function uiAllocControl(n::Csize_t, OSsig::UInt32, typesig::UInt32, typenamestr)
	ccall((:uiAllocControl, libui), Ptr{uiControl}, (Csize_t, UInt32, UInt32, Cstring), n, OSsig, typesig, typenamestr)
end

function uiFreeControl(arg1)
	ccall((:uiFreeControl, libui), Nothing, (Ptr{uiControl},), arg1)
end

function uiControlVerifySetParent(arg1, arg2)
	ccall((:uiControlVerifySetParent, libui), Nothing, (Ptr{uiControl}, Ptr{uiControl}), arg1, arg2)
end

function uiControlEnabledToUser(arg1)
	ccall((:uiControlEnabledToUser, libui), Cint, (Ptr{uiControl},), arg1)
end

function uiUserBugCannotSetParentOnToplevel(_type)
	ccall((:uiUserBugCannotSetParentOnToplevel, libui), Nothing, (Cstring,), _type)
end

function uiWindowTitle(w)
	ccall((:uiWindowTitle, libui), Cstring, (Ptr{uiWindow},), w)
end

function uiWindowSetTitle(w, title)
	ccall((:uiWindowSetTitle, libui), Nothing, (Ptr{uiWindow}, Cstring), w, title)
end

function uiWindowContentSize(w, width, height)
	ccall((:uiWindowContentSize, libui), Nothing, (Ptr{uiWindow}, Ptr{Cint}, Ptr{Cint}), w, width, height)
end

function uiWindowSetContentSize(w, width::Integer, height::Integer)
	ccall((:uiWindowSetContentSize, libui), Nothing, (Ptr{uiWindow}, Cint, Cint), w, width, height)
end

function uiWindowFullscreen(w)
	ccall((:uiWindowFullscreen, libui), Cint, (Ptr{uiWindow},), w)
end

function uiWindowSetFullscreen(w, fullscreen::Integer)
	ccall((:uiWindowSetFullscreen, libui), Nothing, (Ptr{uiWindow}, Cint), w, fullscreen)
end

function uiWindowOnContentSizeChanged(w, f, data)
	ccall((:uiWindowOnContentSizeChanged, libui), Nothing, (Ptr{uiWindow}, Ptr{Nothing}, Ptr{Nothing}), w, f, data)
end

function uiWindowOnClosing(w, f, data)
	ccall((:uiWindowOnClosing, libui), Nothing, (Ptr{uiWindow}, Ptr{Nothing}, Ptr{Nothing}), w, f, data)
end

function uiWindowBorderless(w)
	ccall((:uiWindowBorderless, libui), Cint, (Ptr{uiWindow},), w)
end

function uiWindowSetBorderless(w, borderless::Integer)
	ccall((:uiWindowSetBorderless, libui), Nothing, (Ptr{uiWindow}, Cint), w, borderless)
end

function uiWindowSetChild(w, child)
	ccall((:uiWindowSetChild, libui), Nothing, (Ptr{uiWindow}, Ptr{uiControl}), w, child)
end

function uiWindowMargined(w)
	ccall((:uiWindowMargined, libui), Cint, (Ptr{uiWindow},), w)
end

function uiWindowSetMargined(w, margined::Integer)
	ccall((:uiWindowSetMargined, libui), Nothing, (Ptr{uiWindow}, Cint), w, margined)
end

function uiNewWindow(title, width::Integer, height::Integer, hasMenubar::Integer)
	ccall((:uiNewWindow, libui), Ptr{uiWindow}, (Cstring, Cint, Cint, Cint), title, width, height, hasMenubar)
end

function uiButtonText(b)
	ccall((:uiButtonText, libui), Cstring, (Ptr{uiButton},), b)
end

function uiButtonSetText(b, text)
	ccall((:uiButtonSetText, libui), Nothing, (Ptr{uiButton}, Cstring), b, text)
end

function uiButtonOnClicked(b, f, data)
	ccall((:uiButtonOnClicked, libui), Nothing, (Ptr{uiButton}, Ptr{Nothing}, Ptr{Nothing}), b, f, data)
end

function uiNewButton(text)
	ccall((:uiNewButton, libui), Ptr{uiButton}, (Cstring,), text)
end

function uiBoxAppend(b, child, stretchy::Integer)
	ccall((:uiBoxAppend, libui), Nothing, (Ptr{uiBox}, Ptr{uiControl}, Cint), b, child, stretchy)
end

function uiBoxDelete(b, index::Integer)
	ccall((:uiBoxDelete, libui), Nothing, (Ptr{uiBox}, Cint), b, index)
end

function uiBoxPadded(b)
	ccall((:uiBoxPadded, libui), Cint, (Ptr{uiBox},), b)
end

function uiBoxSetPadded(b, padded::Integer)
	ccall((:uiBoxSetPadded, libui), Nothing, (Ptr{uiBox}, Cint), b, padded)
end

function uiNewHorizontalBox()
	ccall((:uiNewHorizontalBox, libui), Ptr{uiBox}, ())
end

function uiNewVerticalBox()
	ccall((:uiNewVerticalBox, libui), Ptr{uiBox}, ())
end

function uiCheckboxText(c)
	ccall((:uiCheckboxText, libui), Cstring, (Ptr{uiCheckbox},), c)
end

function uiCheckboxSetText(c, text)
	ccall((:uiCheckboxSetText, libui), Nothing, (Ptr{uiCheckbox}, Cstring), c, text)
end

function uiCheckboxOnToggled(c, f, data)
	ccall((:uiCheckboxOnToggled, libui), Nothing, (Ptr{uiCheckbox}, Ptr{Nothing}, Ptr{Nothing}), c, f, data)
end

function uiCheckboxChecked(c)
	ccall((:uiCheckboxChecked, libui), Cint, (Ptr{uiCheckbox},), c)
end

function uiCheckboxSetChecked(c, checked::Integer)
	ccall((:uiCheckboxSetChecked, libui), Nothing, (Ptr{uiCheckbox}, Cint), c, checked)
end

function uiNewCheckbox(text)
	ccall((:uiNewCheckbox, libui), Ptr{uiCheckbox}, (Cstring,), text)
end

function uiEntryText(e)
	ccall((:uiEntryText, libui), Cstring, (Ptr{uiEntry},), e)
end

function uiEntrySetText(e, text)
	ccall((:uiEntrySetText, libui), Nothing, (Ptr{uiEntry}, Cstring), e, text)
end

function uiEntryOnChanged(e, f, data)
	ccall((:uiEntryOnChanged, libui), Nothing, (Ptr{uiEntry}, Ptr{Nothing}, Ptr{Nothing}), e, f, data)
end

function uiEntryReadOnly(e)
	ccall((:uiEntryReadOnly, libui), Cint, (Ptr{uiEntry},), e)
end

function uiEntrySetReadOnly(e, readonly::Integer)
	ccall((:uiEntrySetReadOnly, libui), Nothing, (Ptr{uiEntry}, Cint), e, readonly)
end

function uiNewEntry()
	ccall((:uiNewEntry, libui), Ptr{uiEntry}, ())
end

function uiNewPasswordEntry()
	ccall((:uiNewPasswordEntry, libui), Ptr{uiEntry}, ())
end

function uiNewSearchEntry()
	ccall((:uiNewSearchEntry, libui), Ptr{uiEntry}, ())
end

function uiLabelText(l)
	ccall((:uiLabelText, libui), Cstring, (Ptr{uiLabel},), l)
end

function uiLabelSetText(l, text)
	ccall((:uiLabelSetText, libui), Nothing, (Ptr{uiLabel}, Cstring), l, text)
end

function uiNewLabel(text)
	ccall((:uiNewLabel, libui), Ptr{uiLabel}, (Cstring,), text)
end

function uiTabAppend(t, name, c)
	ccall((:uiTabAppend, libui), Nothing, (Ptr{uiTab}, Cstring, Ptr{uiControl}), t, name, c)
end

function uiTabInsertAt(t, name, before::Integer, c)
	ccall((:uiTabInsertAt, libui), Nothing, (Ptr{uiTab}, Cstring, Cint, Ptr{uiControl}), t, name, before, c)
end

function uiTabDelete(t, index::Integer)
	ccall((:uiTabDelete, libui), Nothing, (Ptr{uiTab}, Cint), t, index)
end

function uiTabNumPages(t)
	ccall((:uiTabNumPages, libui), Cint, (Ptr{uiTab},), t)
end

function uiTabMargined(t, page::Integer)
	ccall((:uiTabMargined, libui), Cint, (Ptr{uiTab}, Cint), t, page)
end

function uiTabSetMargined(t, page::Integer, margined::Integer)
	ccall((:uiTabSetMargined, libui), Nothing, (Ptr{uiTab}, Cint, Cint), t, page, margined)
end

function uiNewTab()
	ccall((:uiNewTab, libui), Ptr{uiTab}, ())
end

function uiGroupTitle(g)
	ccall((:uiGroupTitle, libui), Cstring, (Ptr{uiGroup},), g)
end

function uiGroupSetTitle(g, title)
	ccall((:uiGroupSetTitle, libui), Nothing, (Ptr{uiGroup}, Cstring), g, title)
end

function uiGroupSetChild(g, c)
	ccall((:uiGroupSetChild, libui), Nothing, (Ptr{uiGroup}, Ptr{uiControl}), g, c)
end

function uiGroupMargined(g)
	ccall((:uiGroupMargined, libui), Cint, (Ptr{uiGroup},), g)
end

function uiGroupSetMargined(g, margined::Integer)
	ccall((:uiGroupSetMargined, libui), Nothing, (Ptr{uiGroup}, Cint), g, margined)
end

function uiNewGroup(title)
	ccall((:uiNewGroup, libui), Ptr{uiGroup}, (Cstring,), title)
end

function uiSpinboxValue(s)
	ccall((:uiSpinboxValue, libui), Cint, (Ptr{uiSpinbox},), s)
end

function uiSpinboxSetValue(s, value::Integer)
	ccall((:uiSpinboxSetValue, libui), Nothing, (Ptr{uiSpinbox}, Cint), s, value)
end

function uiSpinboxOnChanged(s, f, data)
	ccall((:uiSpinboxOnChanged, libui), Nothing, (Ptr{uiSpinbox}, Ptr{Nothing}, Ptr{Nothing}), s, f, data)
end

function uiNewSpinbox(min::Integer, max::Integer)
	ccall((:uiNewSpinbox, libui), Ptr{uiSpinbox}, (Cint, Cint), min, max)
end

function uiSliderValue(s)
	ccall((:uiSliderValue, libui), Cint, (Ptr{uiSlider},), s)
end

function uiSliderSetValue(s, value::Integer)
	ccall((:uiSliderSetValue, libui), Nothing, (Ptr{uiSlider}, Cint), s, value)
end

function uiSliderOnChanged(s, f, data)
	ccall((:uiSliderOnChanged, libui), Nothing, (Ptr{uiSlider}, Ptr{Nothing}, Ptr{Nothing}), s, f, data)
end

function uiNewSlider(min::Integer, max::Integer)
	ccall((:uiNewSlider, libui), Ptr{uiSlider}, (Cint, Cint), min, max)
end

function uiProgressBarValue(p)
	ccall((:uiProgressBarValue, libui), Cint, (Ptr{uiProgressBar},), p)
end

function uiProgressBarSetValue(p, n::Integer)
	ccall((:uiProgressBarSetValue, libui), Nothing, (Ptr{uiProgressBar}, Cint), p, n)
end

function uiNewProgressBar()
	ccall((:uiNewProgressBar, libui), Ptr{uiProgressBar}, ())
end

function uiNewHorizontalSeparator()
	ccall((:uiNewHorizontalSeparator, libui), Ptr{uiSeparator}, ())
end

function uiNewVerticalSeparator()
	ccall((:uiNewVerticalSeparator, libui), Ptr{uiSeparator}, ())
end

function uiComboboxAppend(c, text)
	ccall((:uiComboboxAppend, libui), Nothing, (Ptr{uiCombobox}, Cstring), c, text)
end

function uiComboboxSelected(c)
	ccall((:uiComboboxSelected, libui), Cint, (Ptr{uiCombobox},), c)
end

function uiComboboxSetSelected(c, n::Integer)
	ccall((:uiComboboxSetSelected, libui), Nothing, (Ptr{uiCombobox}, Cint), c, n)
end

function uiComboboxOnSelected(c, f, data)
	ccall((:uiComboboxOnSelected, libui), Nothing, (Ptr{uiCombobox}, Ptr{Nothing}, Ptr{Nothing}), c, f, data)
end

function uiNewCombobox()
	ccall((:uiNewCombobox, libui), Ptr{uiCombobox}, ())
end

function uiEditableComboboxAppend(c, text)
	ccall((:uiEditableComboboxAppend, libui), Nothing, (Ptr{uiEditableCombobox}, Cstring), c, text)
end

function uiEditableComboboxText(c)
	ccall((:uiEditableComboboxText, libui), Cstring, (Ptr{uiEditableCombobox},), c)
end

function uiEditableComboboxSetText(c, text)
	ccall((:uiEditableComboboxSetText, libui), Nothing, (Ptr{uiEditableCombobox}, Cstring), c, text)
end

function uiEditableComboboxOnChanged(c, f, data)
	ccall((:uiEditableComboboxOnChanged, libui), Nothing, (Ptr{uiEditableCombobox}, Ptr{Nothing}, Ptr{Nothing}), c, f, data)
end

function uiNewEditableCombobox()
	ccall((:uiNewEditableCombobox, libui), Ptr{uiEditableCombobox}, ())
end

function uiRadioButtonsAppend(r, text)
	ccall((:uiRadioButtonsAppend, libui), Nothing, (Ptr{uiRadioButtons}, Cstring), r, text)
end

function uiRadioButtonsSelected(r)
	ccall((:uiRadioButtonsSelected, libui), Cint, (Ptr{uiRadioButtons},), r)
end

function uiRadioButtonsSetSelected(r, n::Integer)
	ccall((:uiRadioButtonsSetSelected, libui), Nothing, (Ptr{uiRadioButtons}, Cint), r, n)
end

function uiRadioButtonsOnSelected(r, f, data)
	ccall((:uiRadioButtonsOnSelected, libui), Nothing, (Ptr{uiRadioButtons}, Ptr{Nothing}, Ptr{Nothing}), r, f, data)
end

function uiNewRadioButtons()
	ccall((:uiNewRadioButtons, libui), Ptr{uiRadioButtons}, ())
end

function uiDateTimePickerTime(d, time)
	ccall((:uiDateTimePickerTime, libui), Nothing, (Ptr{uiDateTimePicker}, Ptr{Nothing}), d, time)
end

function uiDateTimePickerSetTime(d, time)
	ccall((:uiDateTimePickerSetTime, libui), Nothing, (Ptr{uiDateTimePicker}, Ptr{Nothing}), d, time)
end

function uiDateTimePickerOnChanged(d, f, data)
	ccall((:uiDateTimePickerOnChanged, libui), Nothing, (Ptr{uiDateTimePicker}, Ptr{Nothing}, Ptr{Nothing}), d, f, data)
end

function uiNewDateTimePicker()
	ccall((:uiNewDateTimePicker, libui), Ptr{uiDateTimePicker}, ())
end

function uiNewDatePicker()
	ccall((:uiNewDatePicker, libui), Ptr{uiDateTimePicker}, ())
end

function uiNewTimePicker()
	ccall((:uiNewTimePicker, libui), Ptr{uiDateTimePicker}, ())
end

function uiMultilineEntryText(e)
	ccall((:uiMultilineEntryText, libui), Cstring, (Ptr{uiMultilineEntry},), e)
end

function uiMultilineEntrySetText(e, text)
	ccall((:uiMultilineEntrySetText, libui), Nothing, (Ptr{uiMultilineEntry}, Cstring), e, text)
end

function uiMultilineEntryAppend(e, text)
	ccall((:uiMultilineEntryAppend, libui), Nothing, (Ptr{uiMultilineEntry}, Cstring), e, text)
end

function uiMultilineEntryOnChanged(e, f, data)
	ccall((:uiMultilineEntryOnChanged, libui), Nothing, (Ptr{uiMultilineEntry}, Ptr{Nothing}, Ptr{Nothing}), e, f, data)
end

function uiMultilineEntryReadOnly(e)
	ccall((:uiMultilineEntryReadOnly, libui), Cint, (Ptr{uiMultilineEntry},), e)
end

function uiMultilineEntrySetReadOnly(e, readonly::Integer)
	ccall((:uiMultilineEntrySetReadOnly, libui), Nothing, (Ptr{uiMultilineEntry}, Cint), e, readonly)
end

function uiNewMultilineEntry()
	ccall((:uiNewMultilineEntry, libui), Ptr{uiMultilineEntry}, ())
end

function uiNewNonWrappingMultilineEntry()
	ccall((:uiNewNonWrappingMultilineEntry, libui), Ptr{uiMultilineEntry}, ())
end

function uiMenuItemEnable(m)
	ccall((:uiMenuItemEnable, libui), Nothing, (Ptr{uiMenuItem},), m)
end

function uiMenuItemDisable(m)
	ccall((:uiMenuItemDisable, libui), Nothing, (Ptr{uiMenuItem},), m)
end

function uiMenuItemOnClicked(m, f, data)
	ccall((:uiMenuItemOnClicked, libui), Nothing, (Ptr{uiMenuItem}, Ptr{Nothing}, Ptr{Nothing}), m, f, data)
end

function uiMenuItemChecked(m)
	ccall((:uiMenuItemChecked, libui), Cint, (Ptr{uiMenuItem},), m)
end

function uiMenuItemSetChecked(m, checked::Integer)
	ccall((:uiMenuItemSetChecked, libui), Nothing, (Ptr{uiMenuItem}, Cint), m, checked)
end

function uiMenuAppendItem(m, name)
	ccall((:uiMenuAppendItem, libui), Ptr{uiMenuItem}, (Ptr{uiMenu}, Cstring), m, name)
end

function uiMenuAppendCheckItem(m, name)
	ccall((:uiMenuAppendCheckItem, libui), Ptr{uiMenuItem}, (Ptr{uiMenu}, Cstring), m, name)
end

function uiMenuAppendQuitItem(m)
	ccall((:uiMenuAppendQuitItem, libui), Ptr{uiMenuItem}, (Ptr{uiMenu},), m)
end

function uiMenuAppendPreferencesItem(m)
	ccall((:uiMenuAppendPreferencesItem, libui), Ptr{uiMenuItem}, (Ptr{uiMenu},), m)
end

function uiMenuAppendAboutItem(m)
	ccall((:uiMenuAppendAboutItem, libui), Ptr{uiMenuItem}, (Ptr{uiMenu},), m)
end

function uiMenuAppendSeparator(m)
	ccall((:uiMenuAppendSeparator, libui), Nothing, (Ptr{uiMenu},), m)
end

function uiNewMenu(name)
	ccall((:uiNewMenu, libui), Ptr{uiMenu}, (Cstring,), name)
end

function uiOpenFile(parent)
	ccall((:uiOpenFile, libui), Cstring, (Ptr{uiWindow},), parent)
end

function uiSaveFile(parent)
	ccall((:uiSaveFile, libui), Cstring, (Ptr{uiWindow},), parent)
end

function uiMsgBox(parent, title, description)
	ccall((:uiMsgBox, libui), Nothing, (Ptr{uiWindow}, Cstring, Cstring), parent, title, description)
end

function uiMsgBoxError(parent, title, description)
	ccall((:uiMsgBoxError, libui), Nothing, (Ptr{uiWindow}, Cstring, Cstring), parent, title, description)
end

function uiAreaSetSize(a, width::Integer, height::Integer)
	ccall((:uiAreaSetSize, libui), Nothing, (Ptr{uiArea}, Cint, Cint), a, width, height)
end

function uiAreaQueueRedrawAll(a)
	ccall((:uiAreaQueueRedrawAll, libui), Nothing, (Ptr{uiArea},), a)
end

function uiAreaScrollTo(a, x::Cdouble, y::Cdouble, width::Cdouble, height::Cdouble)
	ccall((:uiAreaScrollTo, libui), Nothing, (Ptr{uiArea}, Cdouble, Cdouble, Cdouble, Cdouble), a, x, y, width, height)
end

function uiAreaBeginUserWindowMove(a)
	ccall((:uiAreaBeginUserWindowMove, libui), Nothing, (Ptr{uiArea},), a)
end

function uiAreaBeginUserWindowResize(a, edge::uiWindowResizeEdge)
	ccall((:uiAreaBeginUserWindowResize, libui), Nothing, (Ptr{uiArea}, uiWindowResizeEdge), a, edge)
end

function uiNewArea(ah)
	ccall((:uiNewArea, libui), Ptr{uiArea}, (Ptr{uiAreaHandler},), ah)
end

function uiNewScrollingArea(ah, width::Integer, height::Integer)
	ccall((:uiNewScrollingArea, libui), Ptr{uiArea}, (Ptr{uiAreaHandler}, Cint, Cint), ah, width, height)
end

function uiDrawNewPath(fillMode::uiDrawFillMode)
	ccall((:uiDrawNewPath, libui), Ptr{uiDrawPath}, (uiDrawFillMode,), fillMode)
end

function uiDrawFreePath(p)
	ccall((:uiDrawFreePath, libui), Nothing, (Ptr{uiDrawPath},), p)
end

function uiDrawPathNewFigure(p, x::Cdouble, y::Cdouble)
	ccall((:uiDrawPathNewFigure, libui), Nothing, (Ptr{uiDrawPath}, Cdouble, Cdouble), p, x, y)
end

function uiDrawPathNewFigureWithArc(p, xCenter::Cdouble, yCenter::Cdouble, radius::Cdouble, startAngle::Cdouble, sweep::Cdouble, negative::Integer)
	ccall((:uiDrawPathNewFigureWithArc, libui), Nothing, (Ptr{uiDrawPath}, Cdouble, Cdouble, Cdouble, Cdouble, Cdouble, Cint), p, xCenter, yCenter, radius, startAngle, sweep, negative)
end

function uiDrawPathLineTo(p, x::Cdouble, y::Cdouble)
	ccall((:uiDrawPathLineTo, libui), Nothing, (Ptr{uiDrawPath}, Cdouble, Cdouble), p, x, y)
end

function uiDrawPathArcTo(p, xCenter::Cdouble, yCenter::Cdouble, radius::Cdouble, startAngle::Cdouble, sweep::Cdouble, negative::Integer)
	ccall((:uiDrawPathArcTo, libui), Nothing, (Ptr{uiDrawPath}, Cdouble, Cdouble, Cdouble, Cdouble, Cdouble, Cint), p, xCenter, yCenter, radius, startAngle, sweep, negative)
end

function uiDrawPathBezierTo(p, c1x::Cdouble, c1y::Cdouble, c2x::Cdouble, c2y::Cdouble, endX::Cdouble, endY::Cdouble)
	ccall((:uiDrawPathBezierTo, libui), Nothing, (Ptr{uiDrawPath}, Cdouble, Cdouble, Cdouble, Cdouble, Cdouble, Cdouble), p, c1x, c1y, c2x, c2y, endX, endY)
end

function uiDrawPathCloseFigure(p)
	ccall((:uiDrawPathCloseFigure, libui), Nothing, (Ptr{uiDrawPath},), p)
end

function uiDrawPathAddRectangle(p, x::Cdouble, y::Cdouble, width::Cdouble, height::Cdouble)
	ccall((:uiDrawPathAddRectangle, libui), Nothing, (Ptr{uiDrawPath}, Cdouble, Cdouble, Cdouble, Cdouble), p, x, y, width, height)
end

function uiDrawPathEnd(p)
	ccall((:uiDrawPathEnd, libui), Nothing, (Ptr{uiDrawPath},), p)
end

function uiDrawStroke(c, path, b, p)
	ccall((:uiDrawStroke, libui), Nothing, (Ptr{uiDrawContext}, Ptr{uiDrawPath}, Ptr{uiDrawBrush}, Ptr{uiDrawStrokeParams}), c, path, b, p)
end

function uiDrawFill(c, path, b)
	ccall((:uiDrawFill, libui), Nothing, (Ptr{uiDrawContext}, Ptr{uiDrawPath}, Ptr{uiDrawBrush}), c, path, b)
end

function uiDrawMatrixSetIdentity(m)
	ccall((:uiDrawMatrixSetIdentity, libui), Nothing, (Ptr{uiDrawMatrix},), m)
end

function uiDrawMatrixTranslate(m, x::Cdouble, y::Cdouble)
	ccall((:uiDrawMatrixTranslate, libui), Nothing, (Ptr{uiDrawMatrix}, Cdouble, Cdouble), m, x, y)
end

function uiDrawMatrixScale(m, xCenter::Cdouble, yCenter::Cdouble, x::Cdouble, y::Cdouble)
	ccall((:uiDrawMatrixScale, libui), Nothing, (Ptr{uiDrawMatrix}, Cdouble, Cdouble, Cdouble, Cdouble), m, xCenter, yCenter, x, y)
end

function uiDrawMatrixRotate(m, x::Cdouble, y::Cdouble, amount::Cdouble)
	ccall((:uiDrawMatrixRotate, libui), Nothing, (Ptr{uiDrawMatrix}, Cdouble, Cdouble, Cdouble), m, x, y, amount)
end

function uiDrawMatrixSkew(m, x::Cdouble, y::Cdouble, xamount::Cdouble, yamount::Cdouble)
	ccall((:uiDrawMatrixSkew, libui), Nothing, (Ptr{uiDrawMatrix}, Cdouble, Cdouble, Cdouble, Cdouble), m, x, y, xamount, yamount)
end

function uiDrawMatrixMultiply(dest, src)
	ccall((:uiDrawMatrixMultiply, libui), Nothing, (Ptr{uiDrawMatrix}, Ptr{uiDrawMatrix}), dest, src)
end

function uiDrawMatrixInvertible(m)
	ccall((:uiDrawMatrixInvertible, libui), Cint, (Ptr{uiDrawMatrix},), m)
end

function uiDrawMatrixInvert(m)
	ccall((:uiDrawMatrixInvert, libui), Cint, (Ptr{uiDrawMatrix},), m)
end

function uiDrawMatrixTransformPoint(m, x, y)
	ccall((:uiDrawMatrixTransformPoint, libui), Nothing, (Ptr{uiDrawMatrix}, Ptr{Cdouble}, Ptr{Cdouble}), m, x, y)
end

function uiDrawMatrixTransformSize(m, x, y)
	ccall((:uiDrawMatrixTransformSize, libui), Nothing, (Ptr{uiDrawMatrix}, Ptr{Cdouble}, Ptr{Cdouble}), m, x, y)
end

function uiDrawTransform(c, m)
	ccall((:uiDrawTransform, libui), Nothing, (Ptr{uiDrawContext}, Ptr{uiDrawMatrix}), c, m)
end

function uiDrawClip(c, path)
	ccall((:uiDrawClip, libui), Nothing, (Ptr{uiDrawContext}, Ptr{uiDrawPath}), c, path)
end

function uiDrawSave(c)
	ccall((:uiDrawSave, libui), Nothing, (Ptr{uiDrawContext},), c)
end

function uiDrawRestore(c)
	ccall((:uiDrawRestore, libui), Nothing, (Ptr{uiDrawContext},), c)
end

function uiFreeAttribute(a)
	ccall((:uiFreeAttribute, libui), Nothing, (Ptr{uiAttribute},), a)
end

function uiAttributeGetType(a)
	ccall((:uiAttributeGetType, libui), uiAttributeType, (Ptr{uiAttribute},), a)
end

function uiNewFamilyAttribute(family)
	ccall((:uiNewFamilyAttribute, libui), Ptr{uiAttribute}, (Cstring,), family)
end

function uiAttributeFamily(a)
	ccall((:uiAttributeFamily, libui), Cstring, (Ptr{uiAttribute},), a)
end

function uiNewSizeAttribute(size::Cdouble)
	ccall((:uiNewSizeAttribute, libui), Ptr{uiAttribute}, (Cdouble,), size)
end

function uiAttributeSize(a)
	ccall((:uiAttributeSize, libui), Cdouble, (Ptr{uiAttribute},), a)
end

function uiNewWeightAttribute(weight::uiTextWeight)
	ccall((:uiNewWeightAttribute, libui), Ptr{uiAttribute}, (uiTextWeight,), weight)
end

function uiAttributeWeight(a)
	ccall((:uiAttributeWeight, libui), uiTextWeight, (Ptr{uiAttribute},), a)
end

function uiNewItalicAttribute(italic::uiTextItalic)
	ccall((:uiNewItalicAttribute, libui), Ptr{uiAttribute}, (uiTextItalic,), italic)
end

function uiAttributeItalic(a)
	ccall((:uiAttributeItalic, libui), uiTextItalic, (Ptr{uiAttribute},), a)
end

function uiNewStretchAttribute(stretch::uiTextStretch)
	ccall((:uiNewStretchAttribute, libui), Ptr{uiAttribute}, (uiTextStretch,), stretch)
end

function uiAttributeStretch(a)
	ccall((:uiAttributeStretch, libui), uiTextStretch, (Ptr{uiAttribute},), a)
end

function uiNewColorAttribute(r::Cdouble, g::Cdouble, b::Cdouble, a::Cdouble)
	ccall((:uiNewColorAttribute, libui), Ptr{uiAttribute}, (Cdouble, Cdouble, Cdouble, Cdouble), r, g, b, a)
end

function uiAttributeColor(a, r, g, b, alpha)
	ccall((:uiAttributeColor, libui), Nothing, (Ptr{uiAttribute}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), a, r, g, b, alpha)
end

function uiNewBackgroundAttribute(r::Cdouble, g::Cdouble, b::Cdouble, a::Cdouble)
	ccall((:uiNewBackgroundAttribute, libui), Ptr{uiAttribute}, (Cdouble, Cdouble, Cdouble, Cdouble), r, g, b, a)
end

function uiNewUnderlineAttribute(u::uiUnderline)
	ccall((:uiNewUnderlineAttribute, libui), Ptr{uiAttribute}, (uiUnderline,), u)
end

function uiAttributeUnderline(a)
	ccall((:uiAttributeUnderline, libui), uiUnderline, (Ptr{uiAttribute},), a)
end

function uiNewUnderlineColorAttribute(u::uiUnderlineColor, r::Cdouble, g::Cdouble, b::Cdouble, a::Cdouble)
	ccall((:uiNewUnderlineColorAttribute, libui), Ptr{uiAttribute}, (uiUnderlineColor, Cdouble, Cdouble, Cdouble, Cdouble), u, r, g, b, a)
end

function uiAttributeUnderlineColor(a, u, r, g, b, alpha)
	ccall((:uiAttributeUnderlineColor, libui), Nothing, (Ptr{uiAttribute}, Ptr{uiUnderlineColor}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), a, u, r, g, b, alpha)
end

function uiNewOpenTypeFeatures()
	ccall((:uiNewOpenTypeFeatures, libui), Ptr{uiOpenTypeFeatures}, ())
end

function uiFreeOpenTypeFeatures(otf)
	ccall((:uiFreeOpenTypeFeatures, libui), Nothing, (Ptr{uiOpenTypeFeatures},), otf)
end

function uiOpenTypeFeaturesClone(otf)
	ccall((:uiOpenTypeFeaturesClone, libui), Ptr{uiOpenTypeFeatures}, (Ptr{uiOpenTypeFeatures},), otf)
end

function uiOpenTypeFeaturesAdd(otf, a::UInt8, b::UInt8, c::UInt8, d::UInt8, value::UInt32)
	ccall((:uiOpenTypeFeaturesAdd, libui), Nothing, (Ptr{uiOpenTypeFeatures}, UInt8, UInt8, UInt8, UInt8, UInt32), otf, a, b, c, d, value)
end

function uiOpenTypeFeaturesRemove(otf, a::UInt8, b::UInt8, c::UInt8, d::UInt8)
	ccall((:uiOpenTypeFeaturesRemove, libui), Nothing, (Ptr{uiOpenTypeFeatures}, UInt8, UInt8, UInt8, UInt8), otf, a, b, c, d)
end

function uiOpenTypeFeaturesGet(otf, a::UInt8, b::UInt8, c::UInt8, d::UInt8, value)
	ccall((:uiOpenTypeFeaturesGet, libui), Cint, (Ptr{uiOpenTypeFeatures}, UInt8, UInt8, UInt8, UInt8, Ptr{UInt32}), otf, a, b, c, d, value)
end

function uiOpenTypeFeaturesForEach(otf, f::uiOpenTypeFeaturesForEachFunc, data)
	ccall((:uiOpenTypeFeaturesForEach, libui), Nothing, (Ptr{uiOpenTypeFeatures}, uiOpenTypeFeaturesForEachFunc, Ptr{Nothing}), otf, f, data)
end

function uiNewFeaturesAttribute(otf)
	ccall((:uiNewFeaturesAttribute, libui), Ptr{uiAttribute}, (Ptr{uiOpenTypeFeatures},), otf)
end

function uiAttributeFeatures(a)
	ccall((:uiAttributeFeatures, libui), Ptr{uiOpenTypeFeatures}, (Ptr{uiAttribute},), a)
end

function uiNewAttributedString(initialString)
	ccall((:uiNewAttributedString, libui), Ptr{uiAttributedString}, (Cstring,), initialString)
end

function uiFreeAttributedString(s)
	ccall((:uiFreeAttributedString, libui), Nothing, (Ptr{uiAttributedString},), s)
end

function uiAttributedStringString(s)
	ccall((:uiAttributedStringString, libui), Cstring, (Ptr{uiAttributedString},), s)
end

function uiAttributedStringLen(s)
	ccall((:uiAttributedStringLen, libui), Csize_t, (Ptr{uiAttributedString},), s)
end

function uiAttributedStringAppendUnattributed(s, str)
	ccall((:uiAttributedStringAppendUnattributed, libui), Nothing, (Ptr{uiAttributedString}, Cstring), s, str)
end

function uiAttributedStringInsertAtUnattributed(s, str, at::Csize_t)
	ccall((:uiAttributedStringInsertAtUnattributed, libui), Nothing, (Ptr{uiAttributedString}, Cstring, Csize_t), s, str, at)
end

function uiAttributedStringDelete(s, start::Csize_t, _end::Csize_t)
	ccall((:uiAttributedStringDelete, libui), Nothing, (Ptr{uiAttributedString}, Csize_t, Csize_t), s, start, _end)
end

function uiAttributedStringSetAttribute(s, a, start::Csize_t, _end::Csize_t)
	ccall((:uiAttributedStringSetAttribute, libui), Nothing, (Ptr{uiAttributedString}, Ptr{uiAttribute}, Csize_t, Csize_t), s, a, start, _end)
end

function uiAttributedStringForEachAttribute(s, f::uiAttributedStringForEachAttributeFunc, data)
	ccall((:uiAttributedStringForEachAttribute, libui), Nothing, (Ptr{uiAttributedString}, uiAttributedStringForEachAttributeFunc, Ptr{Nothing}), s, f, data)
end

function uiAttributedStringNumGraphemes(s)
	ccall((:uiAttributedStringNumGraphemes, libui), Csize_t, (Ptr{uiAttributedString},), s)
end

function uiAttributedStringByteIndexToGrapheme(s, pos::Csize_t)
	ccall((:uiAttributedStringByteIndexToGrapheme, libui), Csize_t, (Ptr{uiAttributedString}, Csize_t), s, pos)
end

function uiAttributedStringGraphemeToByteIndex(s, pos::Csize_t)
	ccall((:uiAttributedStringGraphemeToByteIndex, libui), Csize_t, (Ptr{uiAttributedString}, Csize_t), s, pos)
end

function uiDrawNewTextLayout(params)
	ccall((:uiDrawNewTextLayout, libui), Ptr{uiDrawTextLayout}, (Ptr{uiDrawTextLayoutParams},), params)
end

function uiDrawFreeTextLayout(tl)
	ccall((:uiDrawFreeTextLayout, libui), Nothing, (Ptr{uiDrawTextLayout},), tl)
end

function uiDrawText(c, tl, x::Cdouble, y::Cdouble)
	ccall((:uiDrawText, libui), Nothing, (Ptr{uiDrawContext}, Ptr{uiDrawTextLayout}, Cdouble, Cdouble), c, tl, x, y)
end

function uiDrawTextLayoutExtents(tl, width, height)
	ccall((:uiDrawTextLayoutExtents, libui), Nothing, (Ptr{uiDrawTextLayout}, Ptr{Cdouble}, Ptr{Cdouble}), tl, width, height)
end

function uiFontButtonFont(b, desc)
	ccall((:uiFontButtonFont, libui), Nothing, (Ptr{uiFontButton}, Ptr{uiFontDescriptor}), b, desc)
end

function uiFontButtonOnChanged(b, f, data)
	ccall((:uiFontButtonOnChanged, libui), Nothing, (Ptr{uiFontButton}, Ptr{Nothing}, Ptr{Nothing}), b, f, data)
end

function uiNewFontButton()
	ccall((:uiNewFontButton, libui), Ptr{uiFontButton}, ())
end

function uiFreeFontButtonFont(desc)
	ccall((:uiFreeFontButtonFont, libui), Nothing, (Ptr{uiFontDescriptor},), desc)
end

function uiColorButtonColor(b, r, g, bl, a)
	ccall((:uiColorButtonColor, libui), Nothing, (Ptr{uiColorButton}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), b, r, g, bl, a)
end

function uiColorButtonSetColor(b, r::Cdouble, g::Cdouble, bl::Cdouble, a::Cdouble)
	ccall((:uiColorButtonSetColor, libui), Nothing, (Ptr{uiColorButton}, Cdouble, Cdouble, Cdouble, Cdouble), b, r, g, bl, a)
end

function uiColorButtonOnChanged(b, f, data)
	ccall((:uiColorButtonOnChanged, libui), Nothing, (Ptr{uiColorButton}, Ptr{Nothing}, Ptr{Nothing}), b, f, data)
end

function uiNewColorButton()
	ccall((:uiNewColorButton, libui), Ptr{uiColorButton}, ())
end

function uiFormAppend(f, label, c, stretchy::Integer)
	ccall((:uiFormAppend, libui), Nothing, (Ptr{uiForm}, Cstring, Ptr{uiControl}, Cint), f, label, c, stretchy)
end

function uiFormDelete(f, index::Integer)
	ccall((:uiFormDelete, libui), Nothing, (Ptr{uiForm}, Cint), f, index)
end

function uiFormPadded(f)
	ccall((:uiFormPadded, libui), Cint, (Ptr{uiForm},), f)
end

function uiFormSetPadded(f, padded::Integer)
	ccall((:uiFormSetPadded, libui), Nothing, (Ptr{uiForm}, Cint), f, padded)
end

function uiNewForm()
	ccall((:uiNewForm, libui), Ptr{uiForm}, ())
end

function uiGridAppend(g, c, left::Integer, top::Integer, xspan::Integer, yspan::Integer, hexpand::Integer, halign::uiAlign, vexpand::Integer, valign::uiAlign)
	ccall((:uiGridAppend, libui), Nothing, (Ptr{uiGrid}, Ptr{uiControl}, Cint, Cint, Cint, Cint, Cint, uiAlign, Cint, uiAlign), g, c, left, top, xspan, yspan, hexpand, halign, vexpand, valign)
end

function uiGridInsertAt(g, c, existing, at::uiAt, xspan::Integer, yspan::Integer, hexpand::Integer, halign::uiAlign, vexpand::Integer, valign::uiAlign)
	ccall((:uiGridInsertAt, libui), Nothing, (Ptr{uiGrid}, Ptr{uiControl}, Ptr{uiControl}, uiAt, Cint, Cint, Cint, uiAlign, Cint, uiAlign), g, c, existing, at, xspan, yspan, hexpand, halign, vexpand, valign)
end

function uiGridPadded(g)
	ccall((:uiGridPadded, libui), Cint, (Ptr{uiGrid},), g)
end

function uiGridSetPadded(g, padded::Integer)
	ccall((:uiGridSetPadded, libui), Nothing, (Ptr{uiGrid}, Cint), g, padded)
end

function uiNewGrid()
	ccall((:uiNewGrid, libui), Ptr{uiGrid}, ())
end

function uiNewImage(width::Cdouble, height::Cdouble)
	ccall((:uiNewImage, libui), Ptr{uiImage}, (Cdouble, Cdouble), width, height)
end

function uiFreeImage(i)
	ccall((:uiFreeImage, libui), Nothing, (Ptr{uiImage},), i)
end

function uiImageAppend(i, pixels, pixelWidth::Integer, pixelHeight::Integer, byteStride::Integer)
	ccall((:uiImageAppend, libui), Nothing, (Ptr{uiImage}, Ptr{Nothing}, Cint, Cint, Cint), i, pixels, pixelWidth, pixelHeight, byteStride)
end

function uiFreeTableValue(v)
	ccall((:uiFreeTableValue, libui), Nothing, (Ptr{uiTableValue},), v)
end

function uiTableValueGetType(v)
	ccall((:uiTableValueGetType, libui), uiTableValueType, (Ptr{uiTableValue},), v)
end

function uiNewTableValueString(str)
	ccall((:uiNewTableValueString, libui), Ptr{uiTableValue}, (Cstring,), str)
end

function uiTableValueString(v)
	ccall((:uiTableValueString, libui), Cstring, (Ptr{uiTableValue},), v)
end

function uiNewTableValueImage(img)
	ccall((:uiNewTableValueImage, libui), Ptr{uiTableValue}, (Ptr{uiImage},), img)
end

function uiTableValueImage(v)
	ccall((:uiTableValueImage, libui), Ptr{uiImage}, (Ptr{uiTableValue},), v)
end

function uiNewTableValueInt(i::Integer)
	ccall((:uiNewTableValueInt, libui), Ptr{uiTableValue}, (Cint,), i)
end

function uiTableValueInt(v)
	ccall((:uiTableValueInt, libui), Cint, (Ptr{uiTableValue},), v)
end

function uiNewTableValueColor(r::Cdouble, g::Cdouble, b::Cdouble, a::Cdouble)
	ccall((:uiNewTableValueColor, libui), Ptr{uiTableValue}, (Cdouble, Cdouble, Cdouble, Cdouble), r, g, b, a)
end

function uiTableValueColor(v, r, g, b, a)
	ccall((:uiTableValueColor, libui), Nothing, (Ptr{uiTableValue}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), v, r, g, b, a)
end

function uiNewTableModel(mh)
	ccall((:uiNewTableModel, libui), Ptr{uiTableModel}, (Ptr{uiTableModelHandler},), mh)
end

function uiFreeTableModel(m)
	ccall((:uiFreeTableModel, libui), Nothing, (Ptr{uiTableModel},), m)
end

function uiTableModelRowInserted(m, newIndex::Integer)
	ccall((:uiTableModelRowInserted, libui), Nothing, (Ptr{uiTableModel}, Cint), m, newIndex)
end

function uiTableModelRowChanged(m, index::Integer)
	ccall((:uiTableModelRowChanged, libui), Nothing, (Ptr{uiTableModel}, Cint), m, index)
end

function uiTableModelRowDeleted(m, oldIndex::Integer)
	ccall((:uiTableModelRowDeleted, libui), Nothing, (Ptr{uiTableModel}, Cint), m, oldIndex)
end

function uiTableAppendTextColumn(t, name, textModelColumn::Integer, textEditableModelColumn::Integer, textParams)
	ccall((:uiTableAppendTextColumn, libui), Nothing, (Ptr{uiTable}, Cstring, Cint, Cint, Ptr{uiTableTextColumnOptionalParams}), t, name, textModelColumn, textEditableModelColumn, textParams)
end

function uiTableAppendImageColumn(t, name, imageModelColumn::Integer)
	ccall((:uiTableAppendImageColumn, libui), Nothing, (Ptr{uiTable}, Cstring, Cint), t, name, imageModelColumn)
end

function uiTableAppendImageTextColumn(t, name, imageModelColumn::Integer, textModelColumn::Integer, textEditableModelColumn::Integer, textParams)
	ccall((:uiTableAppendImageTextColumn, libui), Nothing, (Ptr{uiTable}, Cstring, Cint, Cint, Cint, Ptr{uiTableTextColumnOptionalParams}), t, name, imageModelColumn, textModelColumn, textEditableModelColumn, textParams)
end

function uiTableAppendCheckboxColumn(t, name, checkboxModelColumn::Integer, checkboxEditableModelColumn::Integer)
	ccall((:uiTableAppendCheckboxColumn, libui), Nothing, (Ptr{uiTable}, Cstring, Cint, Cint), t, name, checkboxModelColumn, checkboxEditableModelColumn)
end

function uiTableAppendCheckboxTextColumn(t, name, checkboxModelColumn::Integer, checkboxEditableModelColumn::Integer, textModelColumn::Integer, textEditableModelColumn::Integer, textParams)
	ccall((:uiTableAppendCheckboxTextColumn, libui), Nothing, (Ptr{uiTable}, Cstring, Cint, Cint, Cint, Cint, Ptr{uiTableTextColumnOptionalParams}), t, name, checkboxModelColumn, checkboxEditableModelColumn, textModelColumn, textEditableModelColumn, textParams)
end

function uiTableAppendProgressBarColumn(t, name, progressModelColumn::Integer)
	ccall((:uiTableAppendProgressBarColumn, libui), Nothing, (Ptr{uiTable}, Cstring, Cint), t, name, progressModelColumn)
end

function uiTableAppendButtonColumn(t, name, buttonModelColumn::Integer, buttonClickableModelColumn::Integer)
	ccall((:uiTableAppendButtonColumn, libui), Nothing, (Ptr{uiTable}, Cstring, Cint, Cint), t, name, buttonModelColumn, buttonClickableModelColumn)
end

function uiNewTable(params)
	ccall((:uiNewTable, libui), Ptr{uiTable}, (Ptr{uiTableParams},), params)
end


text:
using BinDeps

vers = "1.12.1"

# Set to true to build locally with internal compressors:
build_locally_w_internal_compressors = true
#build_locally_w_internal_compressors = false

tagfile = "installed_vers"
target = "libblosc.$(Libdl.dlext)"
if !isfile(tagfile) || readchomp(tagfile) != vers
    if !build_locally_w_internal_compressors && is_windows()
        run(download_cmd("http://ab-initio.mit.edu/blosc/libblosc$(Sys.WORD_SIZE)-$vers.dll", target))
    elseif !build_locally_w_internal_compressors && is_apple()
        run(download_cmd("http://ab-initio.mit.edu/blosc/libblosc$(Sys.WORD_SIZE)-$vers.dylib", target))
    else
        tarball = "c-blosc-$vers.tar.gz"
        maindir = "c-blosc-$vers"
        srcdir = "c-blosc-$vers/blosc"
        if !isfile(tarball)
            run(download_cmd("https://github.com/Blosc/c-blosc/archive/v$vers.tar.gz", tarball))
        end
        run(unpack_cmd(tarball, ".", ".gz", ".tar"))
        if !build_locally_w_internal_compressors
            cd(srcdir) do
                println("Compiling libblosc...")
                for f in ("blosc.c", "blosclz.c", "shuffle.c")
                    println("   CC $f")
                    run(`gcc -fPIC -O3 -msse2 -I. -c $f`)
                end
                println("   LINK libblosc")
                run(`gcc -shared -o ../../$target blosc.o blosclz.o shuffle.o`)
            end
        else
            cd(maindir) do
                println("Compiling libblosc with internal compressor libs...")
                run(`mkdir build`)
                cd("build") do
                    run(`cmake -DPREFER_EXTERNAL_COMPLIBS=OFF ..`)
                    run(`make`)
                    run(`cp blosc/$target ../..`)
                    run(`make clean`)
                end
            end
            run(`rm -rf $maindir $tarball`)
            println("Compiled libblosc with internal compressor libs...")
        end
    end
    open(tagfile, "w") do f
        println(f, "$vers $(Sys.WORD_SIZE)")
    end
end


text:
export simulate_iterations

"""

Sample the total latency of a worker.
"""
function sample_worker_latency(d_comm, d_comp)
    !isnothing(d_comm) || !isnothing(d_comp) || error("either d_comm or d_comp must be provided")
    rv = 0.0
    if !isnothing(d_comm)
        rv += rand(d_comm)
    end
    if !isnothing(d_comp)
        rv += rand(d_comp)
    end
    rv
end

"""

Simulate `niterations` iterations of the computation.
"""
function simulate_iterations(;nwait, niterations=100, ds_comm, ds_comp, update_latency=0.5e-3)
    length(ds_comm) == length(ds_comp) || throw(DimensionMismatch("ds_comm has dimension $(length(ds_comm)), but ds_comp has dimension $(length(ds_comp))"))
    nworkers = length(ds_comm)
    0 < nwait <= nworkers || throw(DomainError(nwait, "nwait must be in [1, nworkers]"))
    sepochs = zeros(Int, nworkers) # epoch at which an iterate was last sent to each worker
    repochs = zeros(Int, nworkers) # epoch that each received gradient corresponds to
    stimes = zeros(nworkers) # time at which each worker was most recently assigned a task
    rtimes = zeros(nworkers) # time at which each worker most recently completed a task
    pq = PriorityQueue{Int,Float64}() # queue for event-driven simulation
    time = 0.0 # simulation time
    times = zeros(niterations) # time at which each iteration finished
    nfreshs = zeros(Int, niterations)
    nstales = zeros(Int, niterations)
    latencies = zeros(niterations)
    idle_times = zeros(niterations)
    fresh_times = zeros(niterations)
    stale_times = zeros(niterations)
    participation_prob = zeros(nworkers) # fraction of iterations the worker partitipates in
    for k in 1:niterations
        nfresh, nstale = 0, 0
        idle_time = 0.0 # total time workers spend being idle
        fresh_time = 0.0 # total time workers spend working on fresh gradients
        stale_time = 0.0 # total time workers spend working on stale gradients

        # enqueue all idle workers
        # (workers we received a fresh result from in the previous iteration are idle)
        t0 = time + update_latency # start time of this iteration
        for i in 1:nworkers
            if repochs[i] == k-1
                enqueue!(pq, i, t0 + sample_worker_latency(ds_comm[i], ds_comp[i]))
                sepochs[i] = k
                stimes[i] = t0
            end
        end

        # wait for nwait fresh workers
        while nfresh < nwait
            i, time = dequeue_pair!(pq)
            repochs[i] = sepochs[i]
            rtimes[i] = time
            if k > 1 && time < t0
                idle_time += t0 - time
                time = t0
            end
            if repochs[i] == k
                nfresh += 1
                participation_prob[i] += 1
                fresh_time += rtimes[i] - stimes[i]
            else
                # put stale workers back in the queue
                nstale += 1
                stale_time += rtimes[i] - stimes[i]
                enqueue!(pq, i, time + sample_worker_latency(ds_comm[i], ds_comp[i]))
                sepochs[i] = k
                stimes[i] = time
            end
        end

        # tally up for how long each worker has been idle
        # (only workers we received a fresh result from are idle)
        for i in 1:nworkers
            if repochs[i] == k
                idle_time += time - rtimes[i] + update_latency
            end
        end

        # record
        nfreshs[k] = nfresh
        nstales[k] = nstale
        times[k] = time + update_latency
        latencies[k] = time - t0
        idle_times[k] = idle_time
        fresh_times[k] = fresh_time
        stale_times[k] = stale_time
    end
    participation_prob ./= niterations

    rv = DataFrame()
    rv.time = times
    rv[!, :update_latency] .= update_latency
    rv.latency = latencies
    rv.iteration = 1:niterations
    rv.idle_time = idle_times
    rv.fresh_time = fresh_times
    rv.stale_time = stale_times
    rv[!, :nworkers] .= nworkers
    rv[!, :nwait] .= nwait
    rv, participation_prob
end


text:
# This file is a part of Julia. License is MIT: https://julialang.org/license

# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from src/cholmod.jl, to deprecate
@eval SuiteSparse.CHOLMOD begin
    Base.Ac_ldiv_B(A::RealHermSymComplexHermF64SSL, B::StridedVecOrMat) = \(adjoint(A), B)
    Base.Ac_ldiv_B(L::Factor, B::Dense) = \(adjoint(L), B)
    Base.Ac_ldiv_B(L::Factor, B::VecOrMat) = \(adjoint(L), B)
    Base.Ac_ldiv_B(L::Factor, B::Sparse) = \(adjoint(L), B)
    Base.Ac_ldiv_B(L::Factor, B::SparseVecOrMat) = \(adjoint(L), B)
    Base.Ac_ldiv_B(L::FactorComponent, B) = \(adjoint(L), B)
    Base.Ac_ldiv_B(L::FactorComponent, B::RowVector) = \(adjoint(L), B)
    Base.Ac_mul_B(A::Sparse, B::Dense) = *(adjoint(A), B)
    Base.Ac_mul_B(A::Sparse, B::VecOrMat) =  *(adjoint(A), B)
    Base.Ac_mul_B(A::Sparse, B::Sparse) = *(adjoint(A), B)
    Base.A_mul_Bc(A::Sparse{Tv}, B::Sparse{Tv}) where {Tv<:VRealTypes} = *(A, adjoint(B))
end

# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from src/umfpack.jl, to deprecate
@eval SuiteSparse.UMFPACK begin
    using LinearAlgebra: Adjoint, Transpose
    LinearAlgebra.A_ldiv_B!(X::StridedVecOrMat{T}, lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} =
        LinearAlgebra.ldiv!(X, lu, B)
    LinearAlgebra.At_ldiv_B!(X::StridedVecOrMat{T}, lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} =
        LinearAlgebra.ldiv!(X, transpose(lu), B)
    LinearAlgebra.Ac_ldiv_B!(X::StridedVecOrMat{T}, lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} =
        LinearAlgebra.ldiv!(X, adjoint(lu), B)
    LinearAlgebra.A_ldiv_B!(X::StridedVecOrMat{Tb}, lu::UmfpackLU{Float64}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} =
        LinearAlgebra.ldiv!(X, lu, B)
    LinearAlgebra.At_ldiv_B!(X::StridedVecOrMat{Tb}, lu::UmfpackLU{Float64}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} =
        LinearAlgebra.ldiv!(X, transpose(lu), B)
    LinearAlgebra.Ac_ldiv_B!(X::StridedVecOrMat{Tb}, lu::UmfpackLU{Float64}, B::StridedVecOrMat{Tb}) where {Tb<:Complex} =
        LinearAlgebra.ldiv!(X, adjoint(lu), B)
    LinearAlgebra.A_ldiv_B!(lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = LinearAlgebra.ldiv!(B, lu, copy(B))
    LinearAlgebra.At_ldiv_B!(lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = LinearAlgebra.ldiv!(B, transpose(lu), copy(B))
    LinearAlgebra.Ac_ldiv_B!(lu::UmfpackLU{T}, B::StridedVecOrMat{T}) where {T<:UMFVTypes} = LinearAlgebra.ldiv!(B, adjoint(lu), copy(B))
    LinearAlgebra.A_ldiv_B!(lu::UmfpackLU{Float64}, B::StridedVecOrMat{<:Complex}) = LinearAlgebra.ldiv!(B, lu, copy(B))
    LinearAlgebra.At_ldiv_B!(lu::UmfpackLU{Float64}, B::StridedVecOrMat{<:Complex}) = LinearAlgebra.ldiv!(B, transpose(lu), copy(B))
    LinearAlgebra.Ac_ldiv_B!(lu::UmfpackLU{Float64}, B::StridedVecOrMat{<:Complex}) = LinearAlgebra.ldiv!(B, adjoint(lu), copy(B))
end

# A[ct]_(mul|ldiv|rdiv)_B[ct][!] methods from src/spqr.jl, to deprecate
@eval SuiteSparse.SPQR begin
    using LinearAlgebra: Adjoint, Transpose
    LinearAlgebra.A_mul_Bc!(A::StridedMatrix, Q::QRSparseQ) = LinearAlgebra.mul!(A, adjoint(Q))
    LinearAlgebra.Ac_mul_B!(Q::QRSparseQ, A::StridedVecOrMat) = LinearAlgebra.mul!(adjoint(Q), A)
    LinearAlgebra.A_mul_B!(A::StridedMatrix, Q::QRSparseQ) = LinearAlgebra.mul!(A, Q)
    LinearAlgebra.A_mul_B!(Q::QRSparseQ, A::StridedVecOrMat) = LinearAlgebra.mul!(Q, A)
end

max_stars_repo_name: djsegal/julia-fork

max_issues_repo_name: djsegal/julia-fork

max_forks_repo_name: djsegal/julia-fork


text:
# # Double Inverted Pendulum
#
#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/models/Double-Pendulum.ipynb)
#
# This example consists of a double-link pendulum with equal point masses $m$
# at the end of connected mass-less links of length $L$. Both links are
# actuated with torques $T_1$ and $T_2$ and we assume viscous friction
# exists with a coefficient of $c$.

module DoublePendulum  #jl

using ClosedLoopReachability
using ClosedLoopReachability: Specification

# The following option determines whether the falsification settings should be
# used or not. The falsification settings are sufficient to show that the safety
# property is violated. Concretely, we start from an initial point and use a
# smaller time step.
const falsification = true;

# ## Model
#
# ```math
# \begin{aligned}
# 2\ddot \theta_1 + \ddot \theta_2 cos(\theta_2 - \theta_1) - \ddot \theta^2_2 sin(\theta_2 - \theta_1) - 2 \frac{g}{L}sin\theta_1 + \frac{c}{mL^2}\dot\theta_1 &= \frac{1}{mL^2}T_1 \\
# \ddot \theta_1 cos(\theta_2 - \theta_1) + \ddot \theta_2 + \ddot \theta^2_1 sin(\theta_2 - \theta_1) - \frac{g}{L}sin\theta_2 + \frac{c}{mL^2}\dot\theta_2 &= \frac{1}{mL^2}T_2
# \end{aligned}
# ```
# where $θ_1$ and $θ_2$ are the angles that links make with the
# upward vertical axis. The state is:
# ```math
# \begin{aligned}
# [\theta_1, \theta_2, \dot \theta_1, \dot \theta_2]
# \end{aligned}
# ```
# The angular velocity and acceleration of the links are denoted with $θ_1'$,
# $θ_2'$, $θ_1''$ and $θ_2''$ and $g$ is the gravitational acceleration.

const m = 0.5
const L = 0.5
const c = 0.0
const g = 1.0
const gL = g/L
const mL = m*L^2;

@taylorize function double_pendulum!(dx, x, p, t)
    x₁, x₂, x₃, x₄, T₁, T₂ = x

    ## auxiliary terms
    Δ12 = x₁ - x₂
    ★ = cos(Δ12)
    x3sin12 = x₃^2 * sin(Δ12)
    x4sin12 = x₄^2 * sin(Δ12) / 2
    gLsin1 = gL * sin(x₁)
    gLsin2 = gL * sin(x₂)
    T1_frac = (T₁ - c * x₃) / (2 * mL)
    T2_frac = (T₂ - c * x₄) / mL
    bignum = x3sin12 - ★ * (gLsin1 - x4sin12 + T1_frac) + gLsin2 + T2_frac
    denom = ★^2 / 2 - 1

    dx[1] = x₃
    dx[2] = x₄
    dx[3] = ★ * bignum / (2 * denom) - x4sin12 + gLsin1 + T1_frac
    dx[4] = - bignum / denom
end;

# ## Specification

function DoublePendulum_model(use_less_robust_controller::Bool)
    net_lr = @modelpath("Double-Pendulum", "controller_double_pendulum_less_robust.nnet")
    net_mr = @modelpath("Double-Pendulum", "controller_double_pendulum_more_robust.nnet")
    controller = read_nnet(use_less_robust_controller ? net_lr : net_mr)

    X₀ = BallInf(fill(1.15, 4), 0.15)
    if falsification
        ## choose a single point in the initial states (here: the top-most one)
        if use_less_robust_controller
            X₀ = Singleton(high(X₀))
        else
            X₀ = Singleton(low(X₀))
        end
    end
    U₀ = ZeroSet(2)
    vars_idx = Dict(:state_vars=>1:4, :control_vars=>5:6)
    ivp = @ivp(x' = double_pendulum!(x), dim: 6, x(0) ∈ X₀ × U₀)

    period = use_less_robust_controller ? 0.05 : 0.02  # control period

    prob = ControlledPlant(ivp, controller, vars_idx, period)

    ## Safety specification: x[1], x[2], x[3], x[4] ∈ [lb, ub] for all t
    if falsification
        if use_less_robust_controller
            k = 5
        else
            k = 7
        end
    else
        k = 20
    end
    T = k * period  # time horizon

    lb = use_less_robust_controller ? -1.0 : -0.5
    ub = use_less_robust_controller ? 1.7 : 1.5
    safe_states = cartesian_product(Hyperrectangle(low=fill(lb, 4), high=fill(ub, 4)),
                                    Universe(2))
    ## sufficient property for guaranteed violation
    predicate = X -> isdisjoint(overapproximate(X, Hyperrectangle), safe_states)
    predicate_sol = sol -> any(predicate(R) for F in sol for R in F)

    spec = Specification(T, predicate_sol, safe_states)

    return prob, spec
end;

# ## Results

import DifferentialEquations

function run(use_less_robust_controller::Bool)
    prob, spec = DoublePendulum_model(use_less_robust_controller)

    alg = TMJets20(abstol=1e-9, orderT=8, orderQ=1)
    alg_nn = DeepZ()

    function benchmark(; silent::Bool=false)
        ## We solve the controlled system:
        silent || println("flowpipe construction")
        res_sol = @timed solve(prob, T=spec.T, alg_nn=alg_nn, alg=alg)
        sol = res_sol.value
        silent || print_timed(res_sol)

        ## Next we check the property for an overapproximated flowpipe:
        solz = overapproximate(sol, Zonotope)
        if spec.predicate(solz)
            silent || println("The property is violated.")
        else
            silent || println("The property may be satisfied.")
        end

        ## We also compute some simulations:
        silent || println("simulation")
        trajectories = falsification ? 1 : 10
        res_sim = @timed simulate(prob, T=spec.T, trajectories=trajectories,
                                  include_vertices=!falsification)
        sim = res_sim.value
        silent || print_timed(res_sim)

        return solz, sim
    end;

    benchmark(silent=true)  # warm-up
    if use_less_robust_controller
        println("Running analysis with less robust controller")
    else
        println("Running analysis with more robust controller")
    end
    res = @timed benchmark()  # benchmark
    sol, sim = res.value
    println("total analysis time")
    print_timed(res)

    return sol, sim, prob, spec
end;

## pass flag to choose the controller
## `true`: use a less robust controller
## `false`: use a more robust controller
## the choice also influences settings like the period and the specification
res_true = run(true)
res_false = run(false);

# Finally we plot the results:

using Plots
import DisplayAs

function plot_helper(fig, vars, sol, sim, prob, spec)
    safe_states = spec.ext
    if vars[1] == 0
        safe_states_projected = project(safe_states, [vars[2]])
        time = Interval(0, T)
        safe_states_projected = cartesian_product(time, safe_states_projected)
    else
        safe_states_projected = project(safe_states, vars)
    end
    plot!(fig, safe_states_projected, color=:lightgreen, lab="safe states")
    if !falsification && 0 ∉ vars
        plot!(fig, project(initial_state(prob), vars), lab="X₀")
    end
    plot!(fig, sol, vars=vars, color=:yellow, lab="")
    lab_sim = falsification ? "simulation" : ""
    plot_simulation!(fig, sim; vars=vars, color=:black, lab=lab_sim)
    fig = DisplayAs.Text(DisplayAs.PNG(fig))
end

vars=(1, 2)
fig = plot(xlab="θ₁", ylab="θ₂")
sol, sim, prob, spec = res_true
if falsification
    plot!(leg=:topleft)
end
xlims!(-0.5, 2.0)
fig = plot_helper(fig, vars, sol, sim, prob, spec)
## savefig("Double-Pendulum-less-robust-x$(vars[1])-x$(vars[2]).png")
fig

#-

vars=(3, 4)
fig = plot(xlab="θ₁'", ylab="θ₂'")
sol, sim, prob, spec = res_true
if falsification
    plot!(leg=:topleft)
end
xlims!(-0.7, 1.7)
ylims!(-1.6, 1.5)
fig = plot_helper(fig, vars, sol, sim, prob, spec)
## savefig("Double-Pendulum-less-robust-x$(vars[1])-x$(vars[2]).png")
fig

#-

vars=(1, 2)
fig = plot(xlab="θ₁", ylab="θ₂")
sol, sim, prob, spec = res_false
if falsification
    plot!(leg=:topleft)
end
fig = plot_helper(fig, vars, sol, sim, prob, spec)
## savefig("Double-Pendulum-more-robust-x$(vars[1])-x$(vars[2]).png")
fig

#-

vars=(3, 4)
fig = plot(xlab="θ₁'", ylab="θ₂'")
sol, sim, prob, spec = res_false
if falsification
    plot!(leg=:topleft)
    ylims!(-1.0, 1.5)
else
    xlims!(-1.8, 1.5)
    ylims!(-1.6, 1.5)
end
fig = plot_helper(fig, vars, sol, sim, prob, spec)
## savefig("Double-Pendulum-more-robust-x$(vars[1])-x$(vars[2]).png")
fig

#-

end  #jl
nothing  #jl


text:
module Aperture

using DataFrames: DataFrame

export mask,
       cutout,
       aperture_photometry

"""
The abstract super-type for Apertures
"""
abstract type AbstractAperture end

"""
    mask(::AbstractAperture; method=:exact)

Return an array of the weighting of the aperture in the minimum bounding box. For an explanation of the different methods, see [`aperture_photometry`](@ref).
"""
mask(::AbstractAperture)

"""
    bbox(::AbstractAperture)

Return the (`xlow`, `xhigh`, `ylow`, `yhigh`) bounds for a given Aperture.
"""
bbox(::AbstractAperture)

"""
    size(::AbstractAperture)

Return (`ny`, `nx`) of the aperture.
"""
function Base.size(a::AbstractAperture)
    box = bbox(a)
    return (box[4] - box[3] + 1, box[2] - box[1] + 1)
end

function overlap_slices(c::AbstractAperture, shape::Tuple)
    xmin, xmax, ymin, ymax = bbox(c)

    # No overlap
    if xmin ≥ shape[2] || ymin ≥ shape[1] || xmax ≤ 1 || ymax ≤ 1
        return nothing, nothing
    end

    # slices for indexing the larger array
    slices_large = (max(ymin, 1):min(ymax, shape[1]),
                    max(xmin, 1):min(xmax, shape[2]))

    # slices for indexing the smaller array
    slices_small = (max(2 - ymin, 1):min(ymax - ymin, shape[1] - ymin) + 1,
                    max(2 - xmin, 1):min(xmax - xmin, shape[2] - xmin) + 1)

    return slices_large, slices_small
end

"""
    cutout(::AbstractAperture, data)

Get the cutout of the aperture from the `data`. This will handle partial overlap by padding the data with zeros.
"""
function cutout(c::AbstractAperture, data::AbstractMatrix{T}) where {T}
    box = bbox(c)
    maxy, maxx = size(data)
    ny, nx = size(c)

    # Check if x or y are less than our minimum index
    partial_overlap = box[1] < 1 || box[3] < 1 || box[2] > maxx || box[4] > maxy

    if !partial_overlap
        cutout = data[box[3]:box[4], box[1]:box[2]]
    end

    if partial_overlap || size(cutout) != size(c)
        slices_large, slices_small = overlap_slices(c, size(data))
        # no overlap
        slices_small === nothing && return nothing

        cutout = zeros(T, ny, nx)
        cutout[slices_small...] .= data[slices_large...]
    end
    return cutout
end

function apply(a::AbstractAperture, data::AbstractMatrix; method = :exact)
    cut = cutout(a, data)
    cut === nothing && return similar(data, 0, 0)
    return cut .* mask(a, method = method)
end

"""
    aperture_photometry(::AbstractAperture, data::AbstractMatrix, [error]; method=:exact)
    aperture_photometry(::AbstractVector{<:AbstractAperture}, data::AbstractMatrix, [error]; method=:exact)

Perform aperture photometry on `data` given aperture(s). If `error` (the pixel-wise standard deviation) is provided, will calculate sum error. If a list of apertures is provided the output will be a `DataFrame`, otherwise a `NamedTuple`.

# Methods
* `:exact` - Will calculate the exact geometric overlap
* `:center` - Will only consider full-pixel overlap (equivalent to subpixel method with 1 subpixel)
* `(:subpixel, n)` - Use `n^2` subpixels to calculate overlap

"""
function aperture_photometry(a::AbstractAperture, data::AbstractMatrix, error = zeros(size(data)); method = :exact)
    data_weighted = apply(a, data, method = method)
    aperture_sum = sum(data_weighted)
    variance_weighted = apply(a, error.^2, method = method)
    aperture_sum_err = sqrt(sum(variance_weighted))

    return (xcenter = a.x, ycenter = a.y, aperture_sum = aperture_sum, aperture_sum_err = aperture_sum_err)
end

aperture_photometry(a::AbstractVector{<:AbstractAperture}, data::AbstractMatrix, error = zeros(size(data)); method = :exact) = DataFrame(aperture_photometry.(a, Ref(data), Ref(error); method = method))

include("circular.jl")
include("overlap.jl")

end