text:
module ELF2

include("constants.jl")
include("demangle.jl")

const EI_NIDENT = 16

function hex(n)
    return string("0x", string(n, base=16))
end

macro read_field(io, field)
    return :($(esc(field)) = read($(esc(io)), typeof($(esc(field)))))
end

# TODO: Use this macro
macro read_field_from_io(field)
    return :($(esc(field)) = read(io, typeof($(esc(field)))))
end

Elf64_Half = UInt16
Elf64_Word = UInt32
Elf64_SWord = Int32
Elf64_Xword = UInt64
Elf64_SxWord = Int64
Elf64_Addr = UInt64
Elf64_Off = UInt64
Elf64_Section = UInt16
Elf64_Versym = Elf64_Half

mutable struct Ehdr
    e_ident1::UInt8
    e_ident2::UInt8
    e_ident3::UInt8
    e_ident4::UInt8
    e_class::UInt8
    e_data::UInt8
    e_fversion::UInt8
    e_osabi::UInt8
    e_abiversion::UInt8
    e_type::UInt16
    e_machine::UInt16
    e_version::UInt32
    e_entry::UInt64
    e_phoff::UInt64
    e_shoff::UInt64
    e_flags::UInt32
    e_ehsize::UInt16
    e_phentsize::UInt16
    e_phnum::UInt16
    e_shentsize::UInt16
    e_shnum::UInt16
    e_shstrndx::UInt16
    Ehdr() = new(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
end

function ehdr_to_str(e::Ehdr)
    ret = """Ehdr(e_class=$(ELFCLASS[e.e_class]), e_data=$(ELFDATA[e.e_data]), e_fversion=$(ELFVERSION[e.e_fversion]), e_osabi=$(ELFOSABI[e.e_osabi]), e_abiversion=$(hex(e.e_abiversion)), e_type=$(ET_TYPES[e.e_type]), e_machine=$(EM_MACHINES[e.e_machine]), e_version=$(hex(e.e_version)), e_entry=$(hex(e.e_entry)), e_phoff=$(hex(e.e_phoff)), e_shoff=$(hex(e.e_shoff)), e_flags=$(hex(e.e_flags)), e_ehsize=$(hex(e.e_ehsize)), e_phentsize=$(hex(e.e_phentsize)), e_phnum=$(hex(e.e_phnum)), e_shentsize=$(hex(e.e_shentsize)), e_shnum=$(e.e_shnum), e_shstrndx=$(string(e.e_shstrndx)))"""
    return ret
end

mutable struct Dyn
    d_tag::UInt64
    d_val_or_ptr::UInt64
    Dyn() = new(0, 0)
end

function dyn_to_str(dyn::Dyn)
    return "Dyn($(DYNAMIC_TYPE[dyn.d_tag]), d_val_or_ptr=0x$(string(dyn.d_val_or_ptr, base=16)))"
end

mutable struct Phdr
    p_type::UInt32
    p_flags::UInt32
    p_offset::UInt64
    p_vaddr::UInt64
    p_paddr::UInt64
    p_filesz::UInt64
    p_memsz::UInt64
    p_align::UInt64
    Phdr() = new(0, 0, 0, 0, 0, 0, 0, 0)
end

function show_PF(f::UInt32)
    ret::Vector{String} = []
    for (value, name) in PF
        if (f & value) == value
            push!(ret, name)
        end
    end

    @assert size(ret)[1] != 0
    return join(ret, "+")
end

function phdr_to_str(p::Phdr)
    ret = "Phdr(p_type=$(P_TYPE[p.p_type]), p_flags=$(show_PF(p.p_flags)), p_offset=$(hex(p.p_offset)), p_vaddr=$(hex(p.p_vaddr)), p_paddr=$(hex(p.p_paddr)), p_filesz=$(hex(p.p_filesz)), p_memsz=$(p.p_memsz), p_align=$(hex(p.p_align)))"
    return ret
end

mutable struct Shdr
    sh_name::UInt32
    sh_type::UInt32
    sh_flags::UInt64
    sh_addr::UInt64
    sh_offset::UInt64
    sh_size::UInt64
    sh_link::UInt32
    sh_info::UInt32
    sh_addralign::UInt64
    sh_entsize::UInt64
    Shdr() = new(0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
end

function show_SHF_FLAGS(f::UInt64)
    ret::Vector{String} = []
    for (value, name) in SHF_FLAGS
        if (f & value) == value
            push!(ret, name)
        end
    end

    return join(ret, "+")
end

function shdr_to_str(s::Shdr, shstrtab::Vector{UInt8})
    ret = "Shdr(sh_name=$(get_str_from_uint8s(shstrtab, s.sh_name + 1)), sh_type=$(SHT_TYPES[s.sh_type]), sh_flags=$(show_SHF_FLAGS(s.sh_flags)), sh_addr=$(hex(s.sh_addr)), sh_offset=$(hex(s.sh_offset)), sh_size=$(hex(s.sh_size)), sh_link=$(s.sh_link), sh_info=$(hex(s.sh_info)), sh_addralign=$(hex(s.sh_addralign)), sh_entsize=$(hex(s.sh_entsize)))"
    return ret
end

mutable struct Sym
    st_name::UInt32
    st_info::UInt8
    st_other::UInt8
    st_shndx::UInt16
    st_value::UInt64
    st_size::UInt64
    Sym() = new(0, 0, 0, 0, 0, 0)
end

function read_sym(io::IOStream)
    sym = Sym()
    @read_field(io, sym.st_name)
    @read_field(io, sym.st_info)
    @read_field(io, sym.st_other)
    @read_field(io, sym.st_shndx)
    @read_field(io, sym.st_value)
    @read_field(io, sym.st_size)
    return sym
end

function sym_to_str(s::Sym, strtab::Vector{UInt8})
    ret = "Sym(st_name=$(get_str_from_uint8s(strtab, s.st_name+1)), st_info=$(hex(s.st_info)), st_other=$(s.st_other), sh_shndx=$(s.st_shndx), st_value=$(hex(s.st_value)), st_size=$(hex(s.st_size)))"
    return ret
end

mutable struct Rela
    r_offset::UInt64
    r_info::UInt64
    r_addend::Int64
    Rela() = new(0, 0, 0)
end

function read_rela(io::IOStream)
    r = Rela()
    @read_field(io, r.r_offset)
    @read_field(io, r.r_info)
    @read_field(io, r.r_addend)
    return r
end

function rela_to_str(r::Rela)
    ret = "Rela(r_offset=$(hex(r.r_offset)), r_info=$(hex(r.r_info)), r_addend=$(r.r_addend))"
    return ret
end

mutable struct Rel
    r_offset::UInt64
    r_info::UInt64
    Rel() = new(0, 0)
end

function read_rel(io::IOStream)
    r = Rel()
    @read_field(io, r.r_offset)
    @read_field(io, r.r_info)
    return r
end

function rel_to_str(r::Rel)
    ret = "Rel(r_offset=$(hex(r.r_offset)), r_info=$(hex(r.r_info)))"
    return ret
end

mutable struct Verdaux
    vda_name::UInt32
    vda_next::UInt32
    Verdaux() = new(0, 0)
end

function read_verdaux(io::IOStream)
    a = Verdaux()
    @read_field(io, a.vda_name)
    @read_field(io, a.vda_next)
    return a
end

function verdaux_to_str(a::Verdaux, strtab::Vector{UInt8})
    ret = "Verdaux(vda_name=$(get_str_from_uint8s(strtab, a.vda_name + 1)), vda_next=$(a.vda_next))"
    return ret
end

mutable struct Verdef
    vd_version::UInt16
    vd_flags::UInt16
    vd_ndx::UInt16
    vd_cnt::UInt16
    vd_hash::UInt32
    vd_aux::UInt32
    vd_next::UInt32
    verdauxs::Vector{Verdaux}
    Verdef() = new(0, 0, 0, 0, 0, 0, 0, [])
end

function read_verdef(io::IOStream)
    d = Verdef()
    @read_field(io, d.vd_version)
    @read_field(io, d.vd_flags)
    @read_field(io, d.vd_ndx)
    @read_field(io, d.vd_cnt)
    @read_field(io, d.vd_hash)
    @read_field(io, d.vd_aux)
    @read_field(io, d.vd_next)
    return d
end

function verdef_to_str(d::Verdef, strtab::Vector{UInt8})
    auxs_str = "["
    for (i, a) in enumerate(d.verdauxs)
        if i != 1
            auxs_str = auxs_str * ", "
        end
        auxs_str = auxs_str * verdaux_to_str(a, strtab)
    end
    auxs_str = auxs_str * "]"

    ret = "Verdef(vd_version=$(VER_DEF[d.vd_version]), vd_flags=$(VER_FLG[d.vd_flags]), vd_ndx=$(d.vd_ndx), vd_cnt=$(d.vd_cnt), vd_hash=$(d.vd_hash), vd_aux=$(d.vd_aux), vd_next=$(d.vd_next) verdauxs=$(auxs_str))"
    return ret
end

mutable struct Vernaux
    vna_hash::Elf64_Word
    vna_flags::Elf64_Half
    vna_other::Elf64_Half
    vna_name::Elf64_Word
    vna_next::Elf64_Word
    Vernaux() = new(0, 0, 0, 0, 0)
end

function read_vernaux(io::IOStream)
    a = Vernaux()
    @read_field(io, a.vna_hash)
    @read_field(io, a.vna_flags)
    @read_field(io, a.vna_other)
    @read_field(io, a.vna_name)
    @read_field(io, a.vna_next)
    return a
end

function vna_flags_to_str(f::Elf64_Half)
    if f == VER_FLG_WEAK
        return "WEAK"
    elseif f == 0
        return ""
    else
        @assert false "Illegitimate value as vna_flags: $(hex(f))"
    end
end

function vernaux_to_str(a::Vernaux, strtab::Vector{UInt8})
    ret = "Vernaux(vna_hash=$(hex(a.vna_hash)), vna_flags=$(vna_flags_to_str(a.vna_flags)), vna_other=$(a.vna_other), vna_name=$(get_str_from_uint8s(strtab, a.vna_name + 1)), vna_next=$(hex(a.vna_next)))"
    return ret
end

mutable struct Verneed
    vn_version::Elf64_Half
    vn_cnt::Elf64_Half
    vn_file::Elf64_Word
    vn_aux::Elf64_Word
    vn_next::Elf64_Word
    vernauxs::Vector{Vernaux}
    Verneed() = new(0, 0, 0, 0, 0, [])
end

function read_verneed(io::IOStream)
    n = Verneed()
    @read_field(io, n.vn_version)
    @read_field(io, n.vn_cnt)
    @read_field(io, n.vn_file)
    @read_field(io, n.vn_aux)
    @read_field(io, n.vn_next)
    return n
end

function verneed_to_str(n::Verneed, strtab::Vector{UInt8})
    ret = "Verneed(vn_version=$(VER_NEED[n.vn_version]), vn_cnt=$(n.vn_cnt), vn_file=$(hex(n.vn_file)), $(get_str_from_uint8s(strtab, n.vn_file + 1)), vn_aux=$(hex(n.vn_aux)), vn_next=$(hex(n.vn_next))\nvernauxs=[\n"
    for a in n.vernauxs
        ret = ret * vernaux_to_str(a, strtab) * "\n"
    end
    ret = ret * "])"

    return ret
end

mutable struct Note
    n_namesz::UInt32
    n_descsz::UInt32
    n_type::UInt32
    name::Vector{UInt8}
    desc::Vector{UInt8}
    Note() = new(0, 0, 0, [], [])
end

function read_note(io::IOStream)
    n = Note()
    @read_field(io, n.n_namesz)
    @read_field(io, n.n_descsz)
    @read_field(io, n.n_type)
    for i = 1:n.n_namesz
        c = 0x0
        @read_field(io, c)
        push!(n.name, c)
    end
    for i = 1:n.n_descsz
        c = 0x0
        @read_field(io, c)
        push!(n.desc, c)
    end
    return n
end

function read_uint32(bytes::Vector{UInt8}, index::Int)
    @assert (1 <= index && index + 3 <= size(bytes)[1]) "index=$(index), size(bytes)[1]=$(size(bytes)[1])"

    r=UInt32(0)
    for i = index+3:-1:index
        r = r << 8
        r += bytes[i]
    end
    return r
end

function read_uint64(bytes::Vector{UInt8}, index::Int)
    @assert (1 <= index && index + 3 <= size(bytes)[1]) "index=$(index), size(bytes)[1]=$(size(bytes)[1])"

    r=UInt64(0)
    for i = index+7:-1:index
        r = r << 8
        r += bytes[i]
    end
    return r
end

function X86_ISA_to_str(d::UInt32)
    ret = ""

    while d != 0
        bit = d & (-d)
        d = d - bit

        if ret != ""
            ret = ret * ", "
        end
        ret = ret * GNU_PROPERTY_X86_ISA_1_to_str[bit]
    end

    return ret
end

function X86_FEATURE_1_to_str(d::UInt32)
    ret = ""

    for k = keys(GNU_PROPERTY_X86_FEATURE_1)
        if k & d != 0
            if ret != ""
                ret = ret * ", "
            end
            ret = ret * GNU_PROPERTY_X86_FEATURE_1[k]
        end
    end

    return ret
end

function gnu_property_to_str(desc::Vector{UInt8})
    @assert size(desc)[1] >= 8

    type=read_uint32(desc, 1)
    datasz=read_uint32(desc, 5)

    if GNU_PROPERTY_LOPROC <= type && type <= GNU_PROPERTY_HIPROC
        @assert type == GNU_PROPERTY_X86_ISA_1_USED || type == GNU_PROPERTY_X86_ISA_1_NEEDED || type == GNU_PROPERTY_X86_FEATURE_1_AND
        @assert datasz == 4

        if type == GNU_PROPERTY_X86_ISA_1_USED
            isa_used = read_uint32(desc, 9)
            return "x86 ISA used: " * X86_ISA_to_str(isa_used)
        elseif type == GNU_PROPERTY_X86_ISA_1_NEEDED
            isa_needed = read_uint32(desc, 9)
            return "x86 ISA needed: " * X86_ISA_to_str(isa_needed)
        elseif type == GNU_PROPERTY_X86_FEATURE_1_AND
            features = read_uint32(desc, 9)
            return "x86 feature: " * X86_FEATURE_1_to_str(features)
        end
    elseif type == GNU_PROPERTY_STACK_SIZE
        @assert datasz == 8
        stack_size = read_uint32(desc, 9)
        return "stack size: $(stack_size)"
    elseif type == GNU_PROPERTY_NO_COPY_ON_PROTECTED
        @assert datasz == 0
        return "no copy on protected"
    else
        @assert false "type=$(type) is not supported yet"
    end
end

function ABI_TAG_to_str(desc::Vector{UInt8})
    @assert size(desc)[1] == 4 * 4 "size(desc)[1] = $(size(desc)[1])"

    ret = ELF_NOTE_OS[read_uint32(desc, 1)] * " " * string(read_uint32(desc, 5)) * "." * string(read_uint32(desc, 9)) * "." * string(read_uint32(desc, 13))
    return ret
end

function note_to_str(n::Note)
    ret = "Note(n_namesz=$(n.n_namesz), n_descsz=$(n.n_descsz), n_type=$(NOTE_TYPES[n.n_type]) name=$(get_str_from_uint8s(n.name, 1)), desc="

    if n.n_type == NT_GNU_BUILD_ID
        for d in n.desc
            ret = ret * string(d, base=16)
        end
    elseif n.n_type == NT_GNU_PROPERTY_TYPE_0
        ret = ret * gnu_property_to_str(n.desc)
    elseif n.n_type == NT_GNU_ABI_TAG
        ret = ret * ABI_TAG_to_str(n.desc)
    elseif n.n_type == NT_GNU_GOLD_VERSION
        ret = ret * get_str_from_uint8s(n.desc, 1)
    else
        @assert false "n_type=$(n.n_type) is not supported yet"
    end

    ret = ret * ")"
    return ret
end

mutable struct EHFrameHdr
    version::UInt8
    eh_frame_ptr_enc::UInt8
    fde_count_enc::UInt8
    table_enc::UInt8
    EHFrameHdr() = new(0, 0, 0, 0)
    # eh_frame_ptr
    # fde_count
    # binary search table
end

function read_eh_frame_hdr(io::IOStream)
    e = EHFrameHdr()
    @read_field(io, e.version)
    @read_field(io, e.eh_frame_ptr_enc)
    @read_field(io, e.fde_count_enc)
    @read_field(io, e.table_enc)
    return e
end

function eh_frame_hdr_to_str(e::EHFrameHdr)
    ret = "EHFrameHdr(version=$(e.version), eh_frame_ptr_enc=$(e.eh_frame_ptr_enc), fde_count_enc=$(e.fde_count_enc), table_enc=$(e.table_enc))"
    return ret
end

mutable struct ELF
    ehdr::Ehdr
    phdrs::Vector{Phdr}
    shdrs::Vector{Shdr}
    dyns::Vector{Dyn}
    syms::Vector{Sym}
    dynsyms::Vector{Sym}
    rels::Vector{Rel}
    relas::Vector{Rela}
    dynstrtab::Vector{UInt8}
    strtab::Vector{UInt8}
    shstrtab::Vector{UInt8}
    notes::Vector{Note}
    versyms::Vector{UInt16}
    verdefs::Vector{Verdef}
    verneeds::Vector{Verneed}
    eh_frame_hdr::EHFrameHdr
    ELF() = new(Ehdr(), [], [], [], [], [], [], [], [], [], [], [], [], [], [])
end

function get_str_from_uint8s(v::Vector{UInt8}, index)
    @assert index <= size(v)[1] "index = $(index), size(v)[1] = $(size(v)[1])"
    s = Vector{UInt8}([])
    for i = index:size(v)[1]
        if v[i] == 0x0
            break
        end
        push!(s, v[i])
    end

    return String(UInt8.(s))
end

function read_dyn(io::IOStream)
    dyn = Dyn()

    @read_field(io, dyn.d_tag)
    @read_field(io, dyn.d_val_or_ptr)
    return dyn
end

function read_ehdr(io::IOStream)
    ehdr = Ehdr()

    @read_field(io, ehdr.e_ident1)
    @read_field(io, ehdr.e_ident2)
    @read_field(io, ehdr.e_ident3)
    @read_field(io, ehdr.e_ident4)
    @read_field(io, ehdr.e_class)
    @read_field(io, ehdr.e_data)
    @read_field(io, ehdr.e_fversion)
    @read_field(io, ehdr.e_osabi)
    @read_field(io, ehdr.e_abiversion)

    for i = 1:EI_NIDENT-position(io)
        read(io, UInt8)
    end

    @read_field(io, ehdr.e_type)
    @read_field(io, ehdr.e_machine)
    @read_field(io, ehdr.e_version)
    @read_field(io, ehdr.e_entry)
    @read_field(io, ehdr.e_phoff)
    @read_field(io, ehdr.e_shoff)
    @read_field(io, ehdr.e_flags)
    @read_field(io, ehdr.e_ehsize)
    @read_field(io, ehdr.e_phentsize)
    @read_field(io, ehdr.e_phnum)
    @read_field(io, ehdr.e_shentsize)
    @read_field(io, ehdr.e_shnum)
    @read_field(io, ehdr.e_shstrndx)

    @assert ehdr.e_ident1 == ELF2.ELFMAG0
    @assert ehdr.e_ident2 == ELF2.ELFMAG1
    @assert ehdr.e_ident3 == ELF2.ELFMAG2
    @assert ehdr.e_ident4 == ELF2.ELFMAG3
    return ehdr
end

function read_phdr(io::IOStream)
    phdr = Phdr()
    @read_field(io, phdr.p_type)
    @read_field(io, phdr.p_flags)
    @read_field(io, phdr.p_offset)
    @read_field(io, phdr.p_vaddr)
    @read_field(io, phdr.p_paddr)
    @read_field(io, phdr.p_filesz)
    @read_field(io, phdr.p_memsz)
    @read_field(io, phdr.p_align)
    return phdr
end

function read_shdr(io::IOStream)
    shdr = Shdr()
    @read_field(io, shdr.sh_name)
    @read_field(io, shdr.sh_type)
    @read_field(io, shdr.sh_flags)
    @read_field(io, shdr.sh_addr)
    @read_field(io, shdr.sh_offset)
    @read_field(io, shdr.sh_size)
    @read_field(io, shdr.sh_link)
    @read_field(io, shdr.sh_info)
    @read_field(io, shdr.sh_addralign)
    @read_field(io, shdr.sh_entsize)
    return shdr
end

function read_strs(io::IOStream, offset::UInt64, size::UInt64)
    seek(io, offset)

    str = Vector{UInt8}([])
    for i in 1:size
        c = 0x0
        @read_field(io, c)
        push!(str, c)
    end

    return str
end

function read_elf(io::IOStream)
    elf = ELF()

    elf.ehdr = read_ehdr(io)

    if elf.ehdr.e_phoff != 0
        seek(io, elf.ehdr.e_phoff)
        for i = 1:elf.ehdr.e_phnum
            push!(elf.phdrs, read_phdr(io))
        end
    end

    if elf.ehdr.e_shoff != 0
        seek(io, elf.ehdr.e_shoff)
        for i = 1:elf.ehdr.e_shnum
            push!(elf.shdrs, read_shdr(io))
        end
    end

    @assert count(p -> p.p_type == PT_DYNAMIC, elf.phdrs) < 2
    for p in elf.phdrs
        if p.p_type == PT_DYNAMIC
            seek(io, p.p_offset)
            while true
                d = read_dyn(io)
                push!(elf.dyns, d)
                if d.d_tag == DT_NULL
                    break
                end
            end
        end
    end

    if elf.ehdr.e_shstrndx < size(elf.shdrs)[1]
        elf.shstrtab = read_strs(io, elf.shdrs[elf.ehdr.e_shstrndx + 1].sh_offset, elf.shdrs[elf.ehdr.e_shstrndx + 1].sh_size)
    end

    for sh in elf.shdrs
        str = get_str_from_uint8s(elf.shstrtab, sh.sh_name + 1)
        if str == ".strtab"
            elf.strtab = read_strs(io, sh.sh_offset, sh.sh_size)
        elseif str == ".dynstr"
            elf.dynstrtab = read_strs(io, sh.sh_offset, sh.sh_size)
        elseif str == ".symtab"
            seek(io, sh.sh_offset)
            for i = 1:Int64(sh.sh_size/sh.sh_entsize)
                s = read_sym(io)
                push!(elf.syms, s)
            end
        elseif str == ".dynsym"
            seek(io, sh.sh_offset)
            for i = 1:Int64(sh.sh_size/sh.sh_entsize)
                s = read_sym(io)
                push!(elf.dynsyms, s)
            end
        elseif str == ".eh_frame_hdr"
            seek(io, sh.sh_offset)
            elf.eh_frame_hdr = read_eh_frame_hdr(io)
        end

        if sh.sh_type == SHT_RELA
            seek(io, sh.sh_offset)
            for i = 1:Int64(sh.sh_size/sh.sh_entsize)
                r = read_rela(io)
                push!(elf.relas, r)
            end
        end

        if sh.sh_type == SHT_REL
            seek(io, sh.sh_offset)
            for i = 1:Int64(sh.sh_size/sh.sh_entsize)
                r = read_rel(io)
                push!(elf.relas, r)
            end
        end

        if sh.sh_type == SHT_NOTE
            seek(io, sh.sh_offset)
            n = read_note(io)
            push!(elf.notes, n)
        end

        if sh.sh_type == SHT_GNU_versym
            seek(io, sh.sh_offset)
            for i = 1:Int64(sh.sh_size/sh.sh_entsize)
                v = UInt16(0)
                @read_field(io, v)
                push!(elf.versyms, v)
            end
        end

        if sh.sh_type == SHT_GNU_verneed
            off = sh.sh_offset
            while true
                seek(io, off)
                n = read_verneed(io)
                for _ in 1:n.vn_cnt
                    a = read_vernaux(io)
                    push!(n.vernauxs, a)
                end

                push!(elf.verneeds, n)
                println("n.vn_next = ", n.vn_next)
                if n.vn_next == 0
                    break
                end
                off = off + n.vn_next
            end
        end

        if sh.sh_type == SHT_GNU_verdef
            off = sh.sh_offset
            while true
                seek(io, off)
                d = read_verdef(io)
                for _ in 1:d.vd_cnt
                    a = read_verdaux(io)
                    push!(n.verdauxs, a)
                end

                push!(elf.verdefs, d)
                println("n.vn_next = ", d.vd_next)
                if n.vd_next == 0
                    break
                end
                off = off + d.vd_next
            end
        end
    end

    return elf
end

function Base.show(io::IO, elf::ELF)
    println("ELF(")

    println(ehdr_to_str(elf.ehdr))

    println("phdrs=[")
    for p in elf.phdrs
        println(phdr_to_str(p))
    end
    println("]")

    println("shdrs=[")
    for s in elf.shdrs
        println(shdr_to_str(s, elf.shstrtab))
    end
    println("]")

    println("dyns=[")
    for d in elf.dyns
        println(dyn_to_str(d))
    end
    println("]")

    println("syms=[")
    for s in elf.syms
        println(sym_to_str(s, elf.strtab))
    end
    println("]")

    println("dynsyms=[")
    for s in elf.dynsyms
        println(sym_to_str(s, elf.dynstrtab))
    end
    println("]")

    println("relas=[")
    for r in elf.relas
        println(rela_to_str(r))
    end
    println("]")

    println("rels=[")
    for r in elf.rels
        println(rela_to_str(r))
    end
    println("]")

    println("notes=[")
    for n in elf.notes
        println(note_to_str(n))
    end
    println("]")

    print("versyms=[")
    for (i, v) in enumerate(elf.versyms)
        if i != 1
            print(", ")
        end
        if haskey(VER_NDX, v)
            print(VER_NDX[v])
        else
            print(v)
        end
    end
    println("]")

    println("verdefs=[")
    for (i, v) in enumerate(elf.verdefs)
        if i != 1
            print(", ")
        end
        println(verdef_to_str(v, elf.strtab))
    end
    println("]")

    println("verneeds=[")
    for (i, n::Verneed) in enumerate(elf.verneeds)
        print(verneed_to_str(n, elf.dynstrtab))
        if i != size(elf.verneeds)[1]
            println(", ")
        end
    end
    println("]")

    println("eh_frame_hdr=$(eh_frame_hdr_to_str(elf.eh_frame_hdr))")

    println(")")
end

end


text:
export
    # model and common random numbers
    simulate_data, common_random, common_random!,
    # likelihood
    MLE, loglikelihood, indirect_logposterior,
    # modeling API
    IndirectLikelihoodProblem, simulate_problem, loglikelihood, local_jacobian,
    vec_parameters

# structural model and common random numbers

"""
    $SIGNATURES

Simulate data from the `model`

1. using random number generator `rng`,

2. with parameters `θ`,

2. common random numbers `ϵ`.

This method should

1. accept `ϵ` generated by [`common_random`](@ref),

2. return simulated `data` in the format that can be used by [`MLE`](@ref) and
[`loglikelihood`](@ref).

!!! usage

    The user should define a method for this function for each `model` type with
    the signature

    ```julia
    simulate_data(rng::AbstractRNG, model, θ, ϵ)
    ```

    For infeasible/meaningless parameters, return `nothing`.
"""
simulate_data(rng::AbstractRNG, model, θ, ϵ) =
    no_model_method(simulate_data, rng, model, θ, ϵ)

"""
    $SIGNATURES

Simulate data, generating `ϵ` using `rng`.

See [`common_random`](@ref).

!!! usage

    For interactive/exploratory use. Models should define methods for
    [`simulate_data(rng::AbstractRNG, model, θ, ϵ)`](@ref).
"""
simulate_data(rng::AbstractRNG, model, θ) =
    simulate_data(rng, model, θ, common_random(rng, model))

"""
   $SIGNATURES

Simulate data, generating `ϵ` with the default random number generator.

See [`common_random`](@ref).

!!! usage

    For interactive/exploratory use. Models should define methods for
    [`simulate_data(rng::AbstractRNG, model, θ, ϵ)`](@ref).
"""
simulate_data(model, θ) = simulate_data(RNG, model, θ)

"""
    $SIGNATURES

Return common random numbers that can be reused by [`simulate_data`](@ref) with
different parameters.

When the model structure does not allow common random numbers, the convention is
to return `nothing`.

The first argument is the random number generator.

!!! usage

    The user should define a method for this function for each `model` type.

See also [`common_random!`](@ref) for further optimizations.
"""
common_random(rng::AbstractRNG, model) =
    no_model_method(common_random, rng, model)

"""
    $SIGNATURES

Update the common random numbers for the model. The semantics is as follows:

1. it *can*, but does not need to, change the contents of its argument `ϵ`,

2. the “new” common random numbers should be *returned* regardless.

Two common usage patterns are

1. having a mutable `ϵ`, updating that in place, returning `ϵ`,

2. generating new `ϵ`, returning that.

!!! note

    The default method falls back to [`common_random`](@ref), reallocating with
    each call. A method for this function should be defined only when
    allocations can be optimized.
"""
common_random!(rng, model, ϵ) = common_random(rng, model)

# problem interface

struct IndirectLikelihoodProblem{M, P, D, R <: AbstractRNG, E}
    """
    The model, used by [`simulate_data`](@ref), [`common_random`](@ref),
    [`MLE`](@ref), and [`loglikelihood`](@ref).
    """
    model::M
    """
    A callable which accepts the same parameters `θ` as arguments as
    [`simulate_data`](@ref), and returns the **log** of the prior density for
    those parameters (can be `-Inf`, otherwise needs to be finite).
    """
    logprior::P
    """
    The data
    """
    data::D
    """
    Random number generator used by [`simulate_data`](@ref) and
    [`common_random`](@ref).
    """
    rng::R
    """
    Saved values for common random numbers. [`common_random!`] can be used to
    update.
    """
    ϵ::E
end

"""
    $SIGNATURES

A simple wrapper for an indirect likelihood problem, with the given `model`
object, log prior, and data.

The random number generator `rng` is saved, and used to initialize the common
random numbers `ϵ` by default.

The user should implement [`simulate_data`](@ref), [`MLE`](@ref),
[`loglikelihood`](@ref), and [`common_random`](@ref).
"""
IndirectLikelihoodProblem(model, logprior, data;
                          rng::AbstractRNG = RNG, ϵ = common_random(rng, model)) =
    IndirectLikelihoodProblem(model, logprior, data, rng, ϵ)

"""
    $SIGNATURES

Return a new problem with updated common random numbers.
"""
function common_random!(problem::IndirectLikelihoodProblem)
    @unpack model, logprior, data, rng, ϵ = problem
    ϵ′ = common_random!(rng, model, ϵ)
    IndirectLikelihoodProblem(model, logprior, data, rng, ϵ′)
end

"""
    $SIGNATURES

Simulate data with the given parameters `θ`.
"""
function simulate_data(problem::IndirectLikelihoodProblem, θ)
    @unpack rng, model, ϵ = problem
    simulate_data(rng, model, θ, ϵ)
end

"""
    $SIGNATURES

Initialize an [`IndirectLikelihoodProblem`](@ref) with simulated data, using
parameters `θ`.

Useful for debugging and exploration of identification with simulated data.
"""
function simulate_problem(model, logprior, θ;
                          rng = RNG, ϵ = common_random(rng, model))
    data = simulate_data(rng, model, θ, ϵ)
    IndirectLikelihoodProblem(model, logprior, data, rng, ϵ)
end

# likelihood

"""
    $SIGNATURES

Maximum likelihood estimate of the parameters for `data` in `model`.

When `ϕ == MLE(model, data)`, `ϕ` should maximize

```julia
ϕ -> loglikelihood(model, data, ϕ)
```

See [`loglikelihood`](@ref).

Methods should be defined by the user for each `model` type.
"""
MLE(model, data) = no_model_method(MLE, model, data)

"""
    $SIGNATURES

Log likelihood of `data` under `model` with parameters ``ϕ``. See [`MLE`](@ref).
"""
loglikelihood(model, data, ϕ) = no_model_method(loglikelihood, model, data, ϕ)

# problem framework

"""
    $SIGNATURES

Return an estimate of the auxiliary parameters `ϕ` as a function of the
structural parameters `θ`.

This is also known the *mapping* or *binding function* in the indirect inference
literature.
"""
function indirect_estimate(problem::IndirectLikelihoodProblem, θ)
    data = simulate_data(problem, θ)
    data == nothing ? nothing : MLE(problem.model, data)
end

"""
    $SIGNATURES

Evaluate the indirect log posterior of `problem` at parameters `θ`.

Short-circuits for infeasible parameters.
"""
function indirect_logposterior(problem::IndirectLikelihoodProblem, θ)
    @unpack data, logprior, model = problem
    ϕ = indirect_estimate(problem, θ)
    ϕ == nothing ? -Inf : loglikelihood(model, data, ϕ) + logprior(θ)
end

"""
    $SIGNATURES

Return a callable that evaluates `indirect_logposterior(problem, θ)` at the
given `θ`.
"""
indirect_logposterior(problem::IndirectLikelihoodProblem) =
    θ -> indirect_logposterior(problem, θ)

# local analysis

"""
    $SIGNATURES

Return the values of the argument as a vector, potentially (but not necessarily)
restricting to those elements that uniquely determine the argument.

For example, a symmetric matrix would be determined by the diagonal and either
half.
"""
function vec_parameters end

vec_parameters(x::Real) = [x]

vec_parameters(xs::Tuple) = vcat(map(vec_parameters, xs)...)

vec_parameters(A::AbstractArray) = vec(A)

"""
    $SIGNATURES

Flattened elements from the upper triangle. Helper function for
[`vec_parameters`](@ref).
"""
function vec_upper(U::AbstractMatrix{T}) where T
    n = LinAlg.checksquare(U)
    l = n*(n+1) ÷ 2
    v = Vector{T}(l)
    k = 1
    @inbounds for i in 1:n
        for j in 1:i
            v[k] = U[j, i]
            k += 1
        end
    end
    v
end

"""
    $SIGNATURES

Flattened elements from the lower triangle. Helper function for
[`vec_parameters`](@ref).
"""
function vec_lower(L::AbstractMatrix{T}) where T
    n = LinAlg.checksquare(L)
    l = n*(n+1) ÷ 2
    v = Vector{T}(l)
    k = 1
    @inbounds for i in 1:n
        for j in i:n
            v[k] = L[j, i]
            k += 1
        end
    end
    v
end

vec_parameters(A::Union{Symmetric, UpperTriangular}) = vec_upper(A)

vec_parameters(A::LowerTriangular) = vec_lower(A)

"""
    $SIGNATURES

Calculate the local Jacobian of the estimated auxiliary parameters ``ϕ`` at the
structural parameters ``θ=θ₀``.

`ω_to_θ` is a transformation that maps a vector of reals ``ω ∈ ℝⁿ`` to the
parameters `θ` in the format acceptable to [`simulate_data`](@ref). It should
support [`ContinuousTransformations.transform`](@ref) and
[`ContinuousTransformations.inverse`](@ref). See, for example,
[`ContinuousTransformations.TransformationTuple`](@ref).

`vecϕ` is a function that is used to flatten the auxiliary parameters to a
vector. Defaults to [`vec_parameters`](@ref).
"""
function local_jacobian(problem::IndirectLikelihoodProblem, θ₀, ω_to_θ;
                        vecϕ = vec_parameters)
    ω₀ = inverse(ω_to_θ, θ₀)
    jacobian(ω₀) do ω
        θ = transform(ω_to_θ, ω)
        ϕ = indirect_estimate(problem, θ)
        vecϕ(ϕ)
    end
end

ext: jl


text:
using CImGuiExtensions
using Test

@testset "CImGuiExtensions.jl" begin
    # Write your own tests here.
end


text:
using Multirate
import Radio: wgn
using GtkInteract
using Winston

function powerspectrum( x::Vector, window::Function = blackman )
    xLen = length( x )
    x  .*= window( xLen )
    10*log10(fftshift(abs2(fft( x ))))
end

function channelizerplots( signal::Vector, channelizedSignals::Matrix )
    (samplesPerChannel,Nchannels) = size( channelizedSignals )
    # Create plot tables to hold original spectrum plus spectrum and signal traces of each channel
    table              = Table(2,1)
    subTable           = Table(2,Nchannels)

    # Compute the spectrum of the original signal and add it to the table
    signalSpectrum     = powerspectrum( signal )
    p                  = plot( linspace(-0.5,0.5,length(signalSpectrum)), signalSpectrum )
    setattr( p, "title", "Original Spectrum" )
    table[1,1]         = p
    ylim(-10,60)

    freqs = linspace( -0.5, 0.5, samplesPerChannel )
    t     = linspace( 0, Nchannels*samplesPerChannel-1, samplesPerChannel )

    # Plot the spectrum/time-domain traces of each channel and add them to the subtable
    for channel in 1:Nchannels
        thisSignal          = channelizedSignals[:,channel]
        spectrum            = powerspectrum( thisSignal )
        sp                  = plot( freqs, spectrum ); ylim(-10,60)
        setattr( sp, "title", "Channel $channel" )
        tp                  = plot( t, real(thisSignal), "-b", t, imag(thisSignal), "-r" )
        if Nchannels > 3
            setattr( sp.y1, "ticklabels", [])
            setattr( sp.x1, "ticklabels", [])
            setattr( tp.y1, "ticklabels", [])
            setattr( tp.x1, "ticklabels", [])
        end
        subTable[1,channel] = sp
        subTable[2,channel] = tp
    end

    # Position the subtable traces below the main spectrum trace
    table[2,1] = subTable

    return table
end

Tx = Complex128 # Datatype for x
ƒs = 1.0        # Input sample rate

@manipulate for ƒ in -0.5:0.05:0.5, Nchannels in [1:9], samplesPerChannel in [128,256,512,1024]

    # Construct a complex sinusoidal signal at frequency ƒ
    signal             = Tx[ complex(cos(2*pi*ƒ*t),sin(2*pi*ƒ*t)) for t in 0:Nchannels*samplesPerChannel-1 ]
    signal            += wgn( length(signal), power=0.1, returnComplex=true )

    # Instantiate a channelizer with Nchannels
    channelizer        = Channelizer( Nchannels, 32 )
    channelizedSignals = filt( channelizer, signal )

    # Create the table of plots
    table = channelizerplots( signal, channelizedSignals )

    display(table)
end


text:
#############################################################
#
# Spam Reporting Functions
#
#############################################################

function post_users_report_spam(; options=Dict{AbstractString, AbstractString}())

    r = post_oauth("https://api.twitter.com/1.1/users/report_spam.json", options)

    #return to_USERS(r)
    return r.status == 200 ? to_USERS(Requests.json(r)) : r

end


text:
__precompile__(true)
module XLSX

import ZipFile, EzXML, Missings

# https://github.com/fhs/ZipFile.jl/issues/39
if !method_exists(Base.nb_available, Tuple{ZipFile.ReadableFile})
	Base.nb_available(f::ZipFile.ReadableFile) = f.uncompressedsize - f._pos
end

include("structs.jl")
include("cellref.jl")
include("iterator.jl")
include("sst.jl")
include("relationship.jl")
include("read.jl")
include("workbook.jl")
include("worksheet.jl")
include("cell.jl")
include("styles.jl")

end # module XLSX


text:
# using CollisionDetection
# using CompScienceMeshes
# using JLD2

m = meshsphere(1.0, 0.2)
@show numcells(m)

#centroid(ch) = cartesian(meshpoint(ch, [1,1]/3))

#ctrs = [centroid(simplex(cellvertices(m,i))) for i in 1:numcells(m)]
ctrs = cartesian.(center.(chart.(m,cells(m))))
#rads = [maximum(norm(v-ctrs[i]) for v in cellvertices(m,i)) for i in eachindex(ctrs)]
rads = [maximum(norm(v-ctrs[i]) for v in vertices(m,c)) for (i,c) in enumerate(cells(m))];
tree = Octree(ctrs, rads)

fn = joinpath(@__FILE__,"..","center_sizes.jld2")
JLD2.@save fn ctrs rads
# save(fn,
#     "ctrs", ctrs,
#     "rads", rads)


text:
function loglike(x)
    l = 0
    H .= H.^2
    Q .= Q.^2
    for t in 1:n
        v = y[t] - Z*a - d
        F = Z*P*Z' + Diagonal(H)
        a_t = a + P*Z'*F^(-1)*v
        a = T*a_t + c
        P_t = P - P*Z'*F^(-1)*Z*P
        P = T*P_t*T' + R*Diagonal(Q)*R'

        l += -1/2*logabsdet(F) - 1/2 v'*F*v
    end
    return l
end


text:
macro warnpcfail(ex::Expr)
    modl = __module__
    file = __source__.file === nothing ? "?" : String(__source__.file)
    line = __source__.line
    quote
        $(esc(ex)) || @warn """precompile directive
     $($(Expr(:quote, ex)))
 failed. Please report an issue in $($modl) (after checking for duplicates) or remove this directive.""" _file=$file _line=$line
    end
end

function _precompile_()
    ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
    @warnpcfail precompile(Scene, ())
    @warnpcfail precompile(update_limits!, (Scene,))
    @warnpcfail precompile(update_limits!, (Scene, Automatic))
    @warnpcfail precompile(update_limits!, (Scene, FRect3D))

    @warnpcfail precompile(boundingbox, (Scene,))
    Ngonf0 = GeometryBasics.Ngon{2, Float32, 3, Point2f0}
    # @warnpcfail precompile(boundingbox, (Mesh{Tuple{Vector{GeometryBasics.Mesh{2, Float32, Ngonf0, FaceView{Ngonf0}}}}},))  # doesn't seem to work
    @warnpcfail precompile(boundingbox, (Poly{Tuple{Vector{Vector{Point2f0}}}},))
    @warnpcfail precompile(boundingbox, (String, Vector{Point3f0}, Vector{Float32}, Vector{FTFont}, Vec2f0, Vector{Quaternionf0}, SMatrix{4, 4, Float32, 16}, Float64, Float64))

    @warnpcfail precompile(poly_convert, (Vector{Vector{Point2f0}},))
    @warnpcfail precompile(rotatedrect, (FRect2D, Float32))

    @warnpcfail precompile(plot!, (Scene, Type{Poly{Tuple{IRect2D}}}, Attributes, Tuple{Observable{IRect2D}}, Observable{Tuple{Vector{Vector{Point2f0}}}}))
    @warnpcfail precompile(plot!, (Mesh{Tuple{Vector{GeometryBasics.Mesh{2, Float32, Ngonf0, FaceView{Ngonf0}}}}},))
    @warnpcfail precompile(plot!, (Scene, Type{Annotations{Tuple{Vector{Tuple{String, Point2f0}}}}}, Attributes, Tuple{Observable{Vector{Tuple{String, Point2f0}}}}, Observable{Tuple{Vector{Tuple{String, Point2f0}}}}))

    # A big dump from SnoopCompile. These will go stale rapidly, but until work is done on inferrability this is probably the best we can do
    isdefined(Makie, Symbol("#303#305")) && Base.precompile(Tuple{getfield(Makie, Symbol("#303#305")),Int64,FTFont,Tuple{String, Point{2, Float32}},RGBA{Float32},Float32,Vec{2, Float32},Quaternionf0,Float64,Float64})   # time: 0.8072854
    Base.precompile(Tuple{typeof(transformationmatrix),Vec{3, Float32},Vec{3, Float32},Quaternionf0,Observable{Vec{2, Float32}},Tuple{Bool, Bool, Bool},GeometryBasics.HyperRectangle{3, Float32}})   # time: 0.70518523
    Base.precompile(Tuple{typeof(update_cam!),Scene,Camera2D,GeometryBasics.HyperRectangle{3, Float32}})   # time: 0.44654787
    Base.precompile(Tuple{typeof(scatter),Vector{Float64},Vararg{Vector{Float64}, 100}})   # time: 0.32425407
    isdefined(Makie, Symbol("#302#304")) && Base.precompile(Tuple{getfield(Makie, Symbol("#302#304")),SMatrix{4, 4, Float32, 16},Vector{FTFont},Vector{Tuple{String, Point{2, Float32}}},Vector{RGBA{Float32}},Vararg{Any, 100}})   # time: 0.23708302
    Base.precompile(Tuple{typeof(plot!),Scene,Type{Lines{Tuple{GeometryBasics.HyperRectangle{2, Float32}}}},Attributes,Tuple{Observable{GeometryBasics.HyperRectangle{2, Float32}}},Observable{Tuple{Vector{Point{2, Float32}}}}})   # time: 0.23567033
    Base.precompile(Tuple{typeof(default_theme),Scene,Type{Scatter{Tuple{Vector{Point{2, Float32}}}}}})   # time: 0.22432384
    Base.precompile(Tuple{typeof(plot),Type{Scatter{ArgType} where ArgType},Vector{Float64},Vector{Float64}})   # time: 0.19391601
    Base.precompile(Tuple{typeof(default_labels),Vector{Float64},typeof(Makie.Formatters.plain)})   # time: 0.19084986
    Base.precompile(Tuple{typeof(convert_arguments),Type{LineSegments{ArgType} where ArgType},Vector{Point{2, Float32}}})   # time: 0.18835282
    Base.precompile(Tuple{typeof(boundingbox),Scatter{Tuple{Vector{Point{2, Float32}}}}})   # time: 0.15786158
    Base.precompile(Tuple{typeof(same_length_array),Vector{Tuple{String, Point{2, Float32}}},Float64,Key{:rotation}})   # time: 0.15258642
    Base.precompile(Tuple{typeof(plot!),Scene,Type{Scatter{Tuple{Vector{Float64}, Vector{Float64}}}},Attributes,Tuple{Observable{Vector{Float64}}, Observable{Vector{Float64}}},Observable{Tuple{Vector{Point{2, Float32}}}}})   # time: 0.096797995
    Base.precompile(Tuple{typeof(data_limits),Text{Tuple{String}}})   # time: 0.09453959
    Base.precompile(Tuple{typeof(convert_arguments),Type{Annotations{ArgType} where ArgType},Vector{String},Vector{Point{2, Float32}}})   # time: 0.09197935
    isdefined(Makie, Symbol("#719#720")) && Base.precompile(Tuple{getfield(Makie, Symbol("#719#720")),Int64,Quaternionf0,FTFont,Float32})   # time: 0.081979275
    let fbody = try Base.bodyfunction(which(convert_arguments, (Type{Scatter{Tuple{Vector{Float64}, Vector{Float64}}}},Vector{Float64},Vararg{Vector{Float64}, 100},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}},typeof(convert_arguments),Type{Scatter{Tuple{Vector{Float64}, Vector{Float64}}}},Vector{Float64},Vararg{Vector{Float64}, 100},))
        end
    end   # time: 0.07799169
    Base.precompile(Tuple{typeof(icon)})   # time: 0.07657142
    Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:color, :linewidth, :transformation, :model, :visible, :transparency, :overdraw, :ambient, :diffuse, :specular, :shininess, :lightposition, :nan_color, :ssao), Tuple{Observable{Any}, Int64, Automatic, Automatic, Bool, Bool, Bool, Vec{3, Float32}, Vec{3, Float32}, Vec{3, Float32}, Float32, Symbol, RGBA{Float32}, Bool}},Type{Attributes}})   # time: 0.06820207
    Base.precompile(Tuple{typeof(project_widths),SMatrix{4, 4, Float32, 16},Vec{3, Float32}})   # time: 0.06811111
    isdefined(Makie, Symbol("#340#343")) && Base.precompile(Tuple{getfield(Makie, Symbol("#340#343")),Float64,Tuple{Tuple{Float32, Float32}, Tuple{Float32, Float32}},Automatic,Automatic,Function})   # time: 0.055591293
    isdefined(Makie, Symbol("#302#304")) && Base.precompile(Tuple{getfield(Makie, Symbol("#302#304")),Any,Any,Vector{Tuple{String, Point{2, Float32}}},Any,Any,Any,Any,Any,Any})   # time: 0.05321678
    let fbody = try Base.bodyfunction(which(cam2d!, (Scene,))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}},typeof(cam2d!),Scene,))
        end
    end   # time: 0.05295532
    isdefined(Makie, Symbol("#340#343")) && Base.precompile(Tuple{getfield(Makie, Symbol("#340#343")),Any,Tuple{Tuple{Float32, Float32}, Tuple{Float32, Float32}},Any,Any,Any})   # time: 0.043772664
    isdefined(Makie, Symbol("#672#686")) && Base.precompile(Tuple{getfield(Makie, Symbol("#672#686")),Tuple{Vector{Float64}, Float64}})   # time: 0.04195882
    Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:axisnames, :title, :textcolor, :textsize, :rotation, :align, :font), Tuple{Tuple{String, String}, Nothing, Tuple{Symbol, Symbol}, Tuple{Int64, Int64}, Tuple{Float64, Float64}, Tuple{Tuple{Symbol, Symbol}, Tuple{Symbol, Symbol}}, Observable{Tuple{String, String}}}},Type{Attributes}})   # time: 0.036071636
    Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:transparency, :shininess, :overdraw, :specular, :visible, :transformation, :model, :ssao, :color, :ambient, :linewidth, :diffuse, :lightposition, :nan_color, :colormap, :marker, :markersize, :strokecolor, :strokewidth, :glowcolor, :glowwidth, :rotations, :marker_offset, :transform_marker, :uv_offset_width, :distancefield, :markerspace, :fxaa), Tuple{Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Symbol, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Symbol, UnionAll, Int64, Symbol, Float64, RGBA{N0f8}, Float64, Billboard, Automatic, Bool, Vec{4, Float32}, Nothing, UnionAll, Bool}},Type{Attributes}})   # time: 0.030648092
    let fbody = try Base.bodyfunction(which(plot!, (Scene,Type{Scatter{ArgType} where ArgType},Attributes,Vector{Float64},Vararg{Vector{Float64}, 100},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}},typeof(plot!),Scene,Type{Scatter{ArgType} where ArgType},Attributes,Vector{Float64},Vararg{Vector{Float64}, 100},))
        end
    end   # time: 0.029508112
    Base.precompile(Tuple{Type{Text{ArgType} where ArgType},Annotations{Tuple{Vector{Tuple{String, Point{2, Float32}}}}},Attributes,Tuple{Observable{String}},Observable{Tuple{String}}})   # time: 0.028124427
    Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:ranges_labels, :formatter, :gap, :title_gap, :linewidth, :linecolor, :linestyle, :textcolor, :textsize, :rotation, :align, :font), Tuple{Tuple{Automatic, Automatic}, typeof(Makie.Formatters.plain), Int64, Int64, Tuple{Int64, Int64}, Tuple{Tuple{Symbol, Float64}, Tuple{Symbol, Float64}}, Tuple{Nothing, Nothing}, Tuple{Symbol, Symbol}, Tuple{Int64, Int64}, Tuple{Float64, Float64}, Tuple{Tuple{Symbol, Symbol}, Tuple{Symbol, Symbol}}, Observable{Tuple{String, String}}}},Type{Attributes}})   # time: 0.028094089
    Base.precompile(Tuple{Core.kwftype(typeof(text!)),NamedTuple{(:align, :model, :position, :color, :visible, :textsize, :font, :rotation), Tuple{Vec{2, Float32}, SMatrix{4, 4, Float32, 16}, Vector{Point{3, Float32}}, Vector{RGBA{Float32}}, Observable{Any}, Vector{Float32}, Vector{FTFont}, Vector{Quaternionf0}}},typeof(text!),Annotations{Tuple{Vector{Tuple{String, Point{2, Float32}}}}},Vararg{Any, 100}})   # time: 0.027778953
    Base.precompile(Tuple{typeof(selection_rect!),Scene,Camera2D,Observable{Any}})   # time: 0.02611231
    Base.precompile(Tuple{typeof(map_once),Function,Observable{Annotations{Tuple{Vector{Tuple{String, Point{2, Float32}}}}}},Observable{LineSegments{Tuple{Vector{Point{2, Float32}}}}},Vararg{Observable, 100}})   # time: 0.024804583
    let fbody = try Base.bodyfunction(which(map_once, (Function,Observable{Vec{3, Float32}},Observable{Vec{3, Float32}},Vararg{Observable, 100},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (SMatrix{4, 4, Float32, 16},Type,typeof(map_once),Function,Observable{Vec{3, Float32}},Observable{Vec{3, Float32}},Vararg{Observable, 100},))
        end
    end   # time: 0.023796478
    let fbody = try Base.bodyfunction(which(Scene, ())) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Bool,Function,Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}},Type{Scene},))
        end
    end   # time: 0.023688106
    Base.precompile(Tuple{typeof(safe_off),Observable{Any},Function})   # time: 0.022924356
    Base.precompile(Tuple{typeof(lift),Function,Observable{Any},Observable{Tuple{Tuple{Float32, Float32}, Tuple{Float32, Float32}}},Vararg{Any, 100}})   # time: 0.020434486
    Base.precompile(Tuple{typeof(broadcast_foreach),Function,UnitRange{Int64},Vararg{Any, 100}})   # time: 0.019735442
    Base.precompile(Tuple{typeof(map_once),Function,Observable{Vec{3, Float32}},Observable{Vec{3, Float32}},Vararg{Observable, 100}})   # time: 0.019173674
    isdefined(Makie, Symbol("#666#680")) && Base.precompile(Tuple{getfield(Makie, Symbol("#666#680")),Vector{Float32},Float32})   # time: 0.015830928
    isdefined(Makie, Symbol("#669#683")) && Base.precompile(Tuple{getfield(Makie, Symbol("#669#683")),Vector{Float64}})   # time: 0.015553104
    isdefined(Makie, Symbol("#340#343")) && Base.precompile(Tuple{getfield(Makie, Symbol("#340#343")),Float64,Any,Any,Any,Any})   # time: 0.014724698
    Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:transparency, :shininess, :overdraw, :specular, :visible, :transformation, :model, :ssao, :color, :ambient, :linewidth, :diffuse, :lightposition, :nan_color, :font, :strokecolor, :strokewidth, :align, :rotation, :textsize, :position, :justification, :lineheight), Tuple{Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Tuple{Symbol, Float64}, Int64, Tuple{Symbol, Symbol}, Float64, Int64, Point{2, Float32}, Float64, Float64}},Type{Attributes}})   # time: 0.014095342
    Base.precompile(Tuple{typeof(on),Function,Camera,Observable{Scene},Vararg{Observable, 100}})   # time: 0.012858183
    Base.precompile(Tuple{Core.kwftype(typeof(Type)),NamedTuple{(:transparency, :shininess, :overdraw, :specular, :visible, :transformation, :model, :ssao, :color, :ambient, :linewidth, :diffuse, :lightposition, :nan_color, :colormap, :linestyle, :fxaa), Tuple{Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Observable{Any}, Symbol, Observable{Any}, Float64, Observable{Any}, Observable{Any}, Observable{Any}, Symbol, Nothing, Bool}},Type{Attributes}})   # time: 0.012534027
    let fbody = try Base.bodyfunction(which(map_once, (Function,Observable{Annotations{Tuple{Vector{Tuple{String, Point{2, Float32}}}}}},Observable{LineSegments{Tuple{Vector{Point{2, Float32}}}}},Vararg{Observable, 100},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Nothing,Type,typeof(map_once),Function,Observable{Annotations{Tuple{Vector{Tuple{String, Point{2, Float32}}}}}},Observable{LineSegments{Tuple{Vector{Point{2, Float32}}}}},Vararg{Observable, 100},))
        end
    end   # time: 0.012269881
    Base.precompile(Tuple{typeof(lift),Function,Observable{Any},Observable{Union{Nothing, FRect3D, FRect{3}, Rect3D{Float32}}}})   # time: 0.012067013
    isdefined(Makie, Symbol("#89#92")) && Base.precompile(Tuple{getfield(Makie, Symbol("#89#92")),Tuple{Int64, Int64}})   # time: 0.010871829
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Tuple{Vector{Tuple{String, Point{2, Float32}}}}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Vector{Tuple{String, Point{2, Float32}}},Type,Symbol,typeof(lift),Function,Observable{Tuple{Vector{Tuple{String, Point{2, Float32}}}}},))
        end
    end   # time: 0.01042566
    isdefined(Makie, Symbol("#174#176")) && Base.precompile(Tuple{getfield(Makie, Symbol("#174#176")),Vector{RGBA{Float32}}})   # time: 0.010158016
    Base.precompile(Tuple{typeof(color_and_colormap!),Scatter{Tuple{Vector{Point{2, Float32}}}},Observable{Any}})   # time: 0.009793119
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{GeometryBasics.HyperRectangle{2, Int64}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (SMatrix{4, 4, Float32, 16},Type,Symbol,typeof(lift),Function,Observable{GeometryBasics.HyperRectangle{2, Int64}},))
        end
    end   # time: 0.009753768
    Base.precompile(Tuple{typeof(xyz_boundingbox),Function,Vector{Point{2, Float32}}})   # time: 0.009729207
    Base.precompile(Tuple{typeof(setindex!),Attributes,Attributes,Symbol})   # time: 0.009677326
    Base.precompile(Tuple{typeof(lift),Function,Observable{Any}})   # time: 0.009117238
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Tuple{Tuple{Tuple{Float32, Float32}, Tuple{Float32, Float32}}}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Tuple{Tuple{Float32, Float32}, Tuple{Float32, Float32}},Type,Symbol,typeof(lift),Function,Observable{Tuple{Tuple{Tuple{Float32, Float32}, Tuple{Float32, Float32}}}},))
        end
    end   # time: 0.00889073
    Base.precompile(Tuple{typeof(value_convert),Tuple{Tuple{Bool, Bool}, Tuple{Bool, Bool}}})   # time: 0.008890678
    Base.precompile(Tuple{typeof(value_convert),Tuple{Makie.Keyboard.Button, Makie.Mouse.Button}})   # time: 0.008794897
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Tuple{Vector{Point{2, Float32}}}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Vector{Point{2, Float32}},Type,Symbol,typeof(lift),Function,Observable{Tuple{Vector{Point{2, Float32}}}},))
        end
    end   # time: 0.00867902
    Base.precompile(Tuple{typeof(default_theme),Scene,Type{Lines{Tuple{Vector{Point{2, Float32}}}}}})   # time: 0.008428088
    Base.precompile(Tuple{typeof(value_convert),Tuple{Tuple{Symbol, Symbol}, Tuple{Symbol, Symbol}}})   # time: 0.008128306
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{GeometryBasics.HyperRectangle{2, Float32}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Tuple{GeometryBasics.HyperRectangle{2, Float32}},Type,Symbol,typeof(lift),Function,Observable{GeometryBasics.HyperRectangle{2, Float32}},))
        end
    end   # time: 0.007614269
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Tuple{String}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (String,Type,Symbol,typeof(lift),Function,Observable{Tuple{String}},))
        end
    end   # time: 0.007157104
    Base.precompile(Tuple{typeof(lift),Function,Observable{String}})   # time: 0.006988709
    isdefined(Makie, Symbol("#165#170")) && Base.precompile(Tuple{getfield(Makie, Symbol("#165#170")),Int64})   # time: 0.006825633
    Base.precompile(Tuple{typeof(lift),Function,Observable{Vector{Float64}},Observable{Vector{Float64}}})   # time: 0.006378372
    Base.precompile(Tuple{typeof(setindex!),LineSegments{Tuple{Vector{Point{2, Float32}}}},Observable{Vector{RGBA{Float32}}},Symbol})   # time: 0.006341601
    Base.precompile(Tuple{typeof(convert_attribute),Vector{Float32},Key{:textsize}})   # time: 0.006148856
    isdefined(Makie, Symbol("#634#635")) && Base.precompile(Tuple{getfield(Makie, Symbol("#634#635")),Vec{3, Float32},Vec{3, Float32},Quaternionf0,Vec{2, Float32},SMatrix{4, 4, Float32, 16},Tuple{Bool, Bool, Bool}})   # time: 0.006117055
    Base.precompile(Tuple{typeof(value_convert),Tuple{Nothing, Nothing}})   # time: 0.005686621
    Base.precompile(Tuple{typeof(default_labels),Automatic,Tuple{Vector{Float64}, Vector{Float64}},Function})   # time: 0.005572814
    Base.precompile(Tuple{Core.kwftype(typeof(plot!)),NamedTuple{(:align, :model, :position, :color, :visible, :textsize, :font, :rotation), Tuple{Vec{2, Float32}, SMatrix{4, 4, Float32, 16}, Vector{Point{3, Float32}}, Vector{RGBA{Float32}}, Observable{Any}, Vector{Float32}, Vector{FTFont}, Vector{Quaternionf0}}},typeof(plot!),Type{Text{ArgType} where ArgType},Annotations{Tuple{Vector{Tuple{String, Point{2, Float32}}}}},String})   # time: 0.005202268
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{GeometryBasics.HyperRectangle{2, Int64}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Vec{2, Float32},Type,Symbol,typeof(lift),Function,Observable{GeometryBasics.HyperRectangle{2, Int64}},))
        end
    end   # time: 0.004954409
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Any},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Vector{RGBA{Float32}},Type,Symbol,typeof(lift),Function,Observable{Any},))
        end
    end   # time: 0.004715678
    Base.precompile(Tuple{typeof(setindex!),Scatter{Tuple{Vector{Point{2, Float32}}}},Observable{Vec{2, Float32}},Symbol})   # time: 0.004576182
    isdefined(Makie, Symbol("#liftdim2#370")) && Base.precompile(Tuple{getfield(Makie, Symbol("#liftdim2#370")),Observable{Any}})   # time: 0.004413254
    Base.precompile(Tuple{typeof(default_theme),Annotations{Tuple{Vector{Tuple{String, Point{2, Float32}}}}},Type{Text{Tuple{String}}}})   # time: 0.004375755
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Any},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Tuple{Bool, Bool},Type,Symbol,typeof(lift),Function,Observable{Any},))
        end
    end   # time: 0.003239549
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{String},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Tuple{String},Type,Symbol,typeof(lift),Function,Observable{String},))
        end
    end   # time: 0.003196933
    let fbody = try Base.bodyfunction(which(Scene, (Scene,))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Events,Observable{GeometryBasics.HyperRectangle{2, Int64}},Bool,Camera,RefValue{Any},Transformation,Attributes,Vector{AbstractScreen},Base.Iterators.Pairs{Symbol, Bool, Tuple{Symbol}, NamedTuple{(:raw,), Tuple{Bool}}},Type{Scene},Scene,))
        end
    end   # time: 0.003125787
    Base.precompile(Tuple{typeof(safe_off),Observable{Vec{2, Float32}},Function})   # time: 0.002785086
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Vector{Point{2, Float32}}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Tuple{Vector{Point{2, Float32}}},Type,Symbol,typeof(lift),Function,Observable{Vector{Point{2, Float32}}},))
        end
    end   # time: 0.002697386
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Any},Observable{Tuple{Tuple{Float32, Float32}, Tuple{Float32, Float32}}},Vararg{Any, 100},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Tuple{Tuple{Vector{Float64}, Vector{Float64}}, Tuple{Vector{String}, Vector{String}}},Type,Symbol,typeof(lift),Function,Observable{Any},Observable{Tuple{Tuple{Float32, Float32}, Tuple{Float32, Float32}}},Vararg{Any, 100},))
        end
    end   # time: 0.002580008
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Vector{Float64}},Observable{Vector{Float64}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Tuple{Vector{Float64}, Vector{Float64}},Type,Symbol,typeof(lift),Function,Observable{Vector{Float64}},Observable{Vector{Float64}},))
        end
    end   # time: 0.00256485
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Any},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Tuple{String, String},Type,Symbol,typeof(lift),Function,Observable{Any},))
        end
    end   # time: 0.002564525
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Vector{String}},Observable{Vector{Point{2, Float32}}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Tuple{Vector{Tuple{String, Point{2, Float32}}}},Type,Symbol,typeof(lift),Function,Observable{Vector{String}},Observable{Vector{Point{2, Float32}}},))
        end
    end   # time: 0.002538605
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{GeometryBasics.HyperRectangle{3, Float32}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Tuple{Tuple{Tuple{Float32, Float32}, Tuple{Float32, Float32}}},Type,Symbol,typeof(lift),Function,Observable{GeometryBasics.HyperRectangle{3, Float32}},))
        end
    end   # time: 0.002528649
    Base.precompile(Tuple{typeof(setindex!),Attributes,Observable{Tuple{Tuple{Vector{Float64}, Vector{Float64}}, Tuple{Vector{String}, Vector{String}}}},Symbol})   # time: 0.00244883
    Base.precompile(Tuple{typeof(safe_off),Observable{Quaternionf0},Function})   # time: 0.002366797
    Base.precompile(Tuple{typeof(to_ndim),Type{Point{3, Float32}},Vec2{Float64},Int64})   # time: 0.002294592
    let fbody = try Base.bodyfunction(which(current_default_theme, ())) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (Base.Iterators.Pairs{Union{}, Union{}, Tuple{}, NamedTuple{(), Tuple{}}},typeof(current_default_theme),))
        end
    end   # time: 0.002075753
    Base.precompile(Tuple{typeof(safe_off),Observable{Tuple{LineSegments{Tuple{Vector{Point{2, Float32}}}}, LineSegments{Tuple{Vector{Point{2, Float32}}}}}},Function})   # time: 0.001949723
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Any},Observable{Union{Nothing, FRect3D, FRect{3}, Rect3D{Float32}}},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (GeometryBasics.HyperRectangle{3, Float32},Type,Symbol,typeof(lift),Function,Observable{Any},Observable{Union{Nothing, FRect3D, FRect{3}, Rect3D{Float32}}},))
        end
    end   # time: 0.001892332
    Base.precompile(Tuple{typeof(lift),Function,Observable{Vector{Point{2, Float32}}}})   # time: 0.001853503
    Base.precompile(Tuple{typeof(node_any),Any})   # time: 0.001851864
    Base.precompile(Tuple{typeof(safe_off),Observable{Tuple{Bool, Bool, Bool}},Function})   # time: 0.001766532
    Base.precompile(Tuple{typeof(safe_off),Observable{Tuple{Bool, Bool}},Function})   # time: 0.001738557
    Base.precompile(Tuple{typeof(lift),Function,Observable{Vector{String}},Observable{Vector{Point{2, Float32}}}})   # time: 0.001728866
    Base.precompile(Tuple{typeof(data_limits),LineSegments{Tuple{Vector{Point{2, Float32}}}}})   # time: 0.001720389
    Base.precompile(Tuple{typeof(safe_off),Observable{SMatrix{4, 4, Float32, 16}},Function})   # time: 0.0017107
    Base.precompile(Tuple{typeof(color_and_colormap!),Lines{Tuple{Vector{Point{2, Float32}}}},Observable{Any}})   # time: 0.00169273
    let fbody = try Base.bodyfunction(which(lift, (Function,Observable{Any},))) catch missing end
        if !ismissing(fbody)
            precompile(fbody, (GeometryBasics.HyperRectangle{2, Int64},Type,Symbol,typeof(lift),Function,Observable{Any},))
        end
    end   # time: 0.001687491
    Base.precompile(Tuple{typeof(safe_off),Observable{LineSegments{Tuple{Vector{Point{2, Float32}}}}},Function})   # time: 0.001671355
    Base.precompile(Tuple{typeof(color_and_colormap!),LineSegments{Tuple{Vector{Point{2, Float32}}}},Observable{Any}})   # time: 0.001637833
    Base.precompile(Tuple{typeof(safe_off),Observable{Tuple{Tuple{Float32, Float32}, Tuple{Float32, Float32}}},Function})   # time: 0.00162075
    isdefined(Makie, Symbol("#186#188")) && Base.precompile(Tuple{getfield(Makie, Symbol("#186#188"))})   # time: 0.001442432
    Base.precompile(Tuple{typeof(same_length_array),Vector{Tuple{String, Point{2, Float32}}},Tuple{Symbol, Symbol},Key{:align}})   # time: 0.001406379
    Base.precompile(Tuple{typeof(lift),Function,Observable{GeometryBasics.HyperRectangle{3, Float32}}})   # time: 0.001330926
    Base.precompile(Tuple{typeof(to_ndim),Type{Vec{3, Float32}},Vec{2, Float32},Float32})   # time: 0.001274049
    Base.precompile(Tuple{typeof(getindex),Scene,Type{Axis}})   # time: 0.001070641
    Base.precompile(Tuple{Type{Scatter{Tuple{Vector{Point{2, Float32}}}}},Scene,Transformation,Attributes,Tuple{Observable{Vector{Float64}}, Observable{Vector{Float64}}},Tuple{Observable{Vector{Point{2, Float32}}}}})   # time: 0.001059559
    Base.precompile(Tuple{typeof(is2d),GeometryBasics.HyperRectangle{3, Float32}})   # time: 0.001005834
    Base.precompile(Tuple{Type{Lines{Tuple{Vector{Point{2, Float32}}}}},Scene,Transformation,Attributes,Tuple{Observable{GeometryBasics.HyperRectangle{2, Float32}}},Tuple{Observable{Vector{Point{2, Float32}}}}})   # time: 0.001005373

    # DataInspector
    @warnpcfail precompile(on_hover, (DataInspector, ))
    for PT in (
            Scatter{Tuple{Vector{Point2f0}}},
            Scatter{Tuple{Vector{Point3f0}}},
            MeshScatter{Tuple{Vector{Point3f0}}},
            Lines{Tuple{Vector{Point2f0}}},
            Lines{Tuple{Vector{Point3f0}}},
            LineSegments{Tuple{Vector{Point2f0}}},
            LineSegments{Tuple{Vector{Point3f0}}},
            # Mesh,
            Surface{Tuple{IntervalSets.ClosedInterval{Float32}, IntervalSets.ClosedInterval{Float32}, Matrix{Float32}}},
            Surface{Tuple{Vector{Float32}, Vector{Float32}, Matrix{Float32}}},
            Surface{Tuple{Matrix{Float32}, Matrix{Float32}, Matrix{Float32}}},
            Heatmap{Tuple{IntervalSets.ClosedInterval{Float32}, IntervalSets.ClosedInterval{Float32}, Matrix{Float32}}},
            Heatmap{Tuple{Vector{Float32}, Vector{Float32}, Matrix{Float32}}},
            Image{Tuple{IntervalSets.ClosedInterval{Float32}, IntervalSets.ClosedInterval{Float32}, Matrix{Float32}}},
            Image{Tuple{Vector{Float32}, Vector{Float32}, Matrix{Float32}}},
            BarPlot{Tuple{Vector{Point{2, Float32}}}}
        )

        @warnpcfail precompile(show_data_recursion, (DataInspector, PT, UInt64))
        @warnpcfail precompile(show_data, (DataInspector, PT, UInt64))
    end
end


text:
# Reference value from CSPICE
rvm = [4.250906022073639e7,2.3501057648129586e7,8.158467467032234e6,-34.160008371029825,37.844059275357594,23.756128199757867]
mrvm = [rvm';rvm']

de430segments = [
    "SOLAR SYSTEM BARYCENTER (0) => MERCURY BARYCENTER (1)",
    "SOLAR SYSTEM BARYCENTER (0) => VENUS BARYCENTER (2)",
    "SOLAR SYSTEM BARYCENTER (0) => EARTH-MOON BARYCENTER (3)",
    "SOLAR SYSTEM BARYCENTER (0) => MARS BARYCENTER (4)",
    "SOLAR SYSTEM BARYCENTER (0) => JUPITER BARYCENTER (5)",
    "SOLAR SYSTEM BARYCENTER (0) => SATURN BARYCENTER (6)",
    "SOLAR SYSTEM BARYCENTER (0) => URANUS BARYCENTER (7)",
    "SOLAR SYSTEM BARYCENTER (0) => NEPTUNE BARYCENTER (8)",
    "SOLAR SYSTEM BARYCENTER (0) => PLUTO BARYCENTER (9)",
    "SOLAR SYSTEM BARYCENTER (0) => SUN (10)",
    "MERCURY BARYCENTER (1) => MERCURY (199)",
    "VENUS BARYCENTER (2) => VENUS (299)",
    "EARTH-MOON BARYCENTER (3) => MOON (301)",
    "EARTH-MOON BARYCENTER (3) => EARTH (399)",
]
jd = Dates.datetime2julian(DateTime(2016,1,1,0,0,0))
spk = SPK("$path/de430.bsp")

@testset "API" begin
    @testset for (a, b) in zip(JPLEphemeris.list_segments(spk), de430segments)
        @test a == b
    end
    @testset for (func, range) in zip((position, velocity, state), (1:3, 4:6, 1:6))
        res = func(spk, "mercury barycenter", jd)
        @test res ≈ rvm[range]
        res = func(spk, 1, jd)
        @test res ≈ rvm[range]
        res = func(spk, "ssb", "mercury barycenter", jd)
        @test res ≈ rvm[range]
        res = func(spk, 0, "mercury barycenter", jd)
        @test res ≈ rvm[range]
        res = func(spk, "ssb", 1, jd)
        @test res ≈ rvm[range]
        res = func(spk, 0, 1, jd)
        @test res ≈ rvm[range]
        res = func(spk, 0, 1, [jd; jd])
        @test res ≈ mrvm[:,range]
        res = func(spk, "mercury barycenter", jd, 0.0)
        @test res ≈ rvm[range]
        res = func(spk, 1, jd, 0.0)
        @test res ≈ rvm[range]
        res = func(spk, "ssb", "mercury barycenter", jd, 0.0)
        @test res ≈ rvm[range]
        res = func(spk, 0, "mercury barycenter", jd, 0.0)
        @test res ≈ rvm[range]
        res = func(spk, "ssb", 1, jd, 0.0)
        @test res ≈ rvm[range]
        res = func(spk, 0, 1, jd, 0.0)
        @test res ≈ rvm[range]
        res = func(spk, 0, 1, [jd; jd], [0.0, 0.0])
        @test res ≈ mrvm[:,range]
    end
end


text:
import Base.Iterators: Cycle

shader_symbol(::Type{<:ComponentData}) = :none

@component struct DioEntity end

#TODO get rid of this in favor of a correct iterator
function shared_entities(c::SharedComponent{T}, dat::T) where {T}
    ids = Int[]
    id = findfirst(x -> x == dat, c.shared)
    return findall(x -> x == id, data(c))
end

# DEFAULT COMPONENTS
abstract type Vao <: ComponentData end

macro vao(name)
    return esc(quote
                   @component @with_kw mutable struct $name <: Vao
                       vertexarray::VertexArray
                   end
               end)
end

macro instanced_vao(name)
    return esc(quote
                   @grouped_component @with_kw mutable struct $name <: Vao
                       vertexarray::VertexArray
                   end
               end)
end

Base.length(vao::Vao) = length(vao.vertexarray)
GLA.bind(vao::Vao) = GLA.bind(vao.vertexarray)

GLA.draw(vao::Vao) = GLA.draw(vao.vertexarray)

GLA.upload!(vao::Vao; kwargs...) = GLA.upload!(vao.vertexarray; kwargs...)

@component @with_kw struct Visible
    visible::Bool = true
end

# NON rendering Components
@component struct Dynamic end
@component @with_kw struct Spatial
    position::Point3f0 = zero(Point3f0)
    velocity::Vec3f0   = zero(Vec3f0)
end

function Base.:(+)(s1::Spatial, s2::Spatial)
    return Spatial(s1.position + s2.position, s1.velocity + s2.velocity)
end
function Base.:(-)(s1::Spatial, s2::Spatial)
    return Spatial(s1.position - s2.position, s1.velocity - s2.velocity)
end

@component struct Rotation
    q::Quaternions.Quaternion{Float32}
end
Rotation(axis::Vec, angle::Number) = Rotation(Quaternions.qrotation(axis, angle))
Rotation(axis1::Vec, axis2::Vec) = Rotation(rotation(axis1, axis2))

Base.:(*)(r1::Rotation, r2::Rotation) = Rotation(r1.q * r2.q)

Quaternions.angleaxis(r::Rotation) = Quaternions.angleaxis(r.q)
Quaternions.axis(r::Rotation)      = Quaternions.axis(r.q)
Quaternions.angle(r::Rotation)     = Quaternions.angle(r.q)

GeometryBasics.direction(r::Rotation) = r.q * Z_AXIS

@component @with_kw struct Shape
    scale::Vec3f0 = Vec3f0(1.0f0)
end
Shape(f::Real) = Shape(Vec3f0(f))
Base.length(::Type{Shape}) = 3
Base.eltype(::Type{Shape}) = Float32

@component @with_kw struct ModelMat
    modelmat::Mat4f0 = Eye4f0()
end
Base.length(::Type{ModelMat}) = 16
Base.eltype(::Type{ModelMat}) = Float32
shader_symbol(::Type{ModelMat}) = :modelmat
Base.size(::Type{ModelMat}) = size(Mat4f0)

@component @with_kw struct Material
    specpow::Float32 = 0.8f0
    specint::Float32 = 0.8f0
end
Base.eltype(::Type{Material}) = Float32
Base.length(::Type{Material}) = 2
shader_symbol(::Type{Material}) = :material

@component @with_kw struct PointLight
    diffuse::Float32  = 0.5f0
    specular::Float32 = 0.5f0
    ambient::Float32  = 0.5f0
end
Base.length(::Type{PointLight}) = 3
Base.eltype(::Type{PointLight}) = Float32

@component struct DirectionLight
    direction :: Vec3f0
    diffuse   :: Float32
    specular  :: Float32
    ambient   :: Float32
end

# Meshing and the like
@grouped_component struct Mesh
    mesh::Any
end

@component struct Alpha
    α::Float32
end
Base.length(::Type{Alpha}) = 1
Base.eltype(::Type{Alpha}) = Float32
shader_symbol(::Type{Alpha}) = :alpha

abstract type Color <: ComponentData end

# one color, will be put as a uniform in the shader
@component @with_kw struct UniformColor <: Color
    color::RGBf0 = DEFAULT_COLOR
end
UniformColor(x, y, z) = UniformColor(RGBf0(x, y, z))
Base.length(::Type{UniformColor}) = 3
Base.eltype(::Type{UniformColor}) = Float32
shader_symbol(::Type{UniformColor}) = :color

# vector of colors, either supplied manually or filled in by mesher
@component struct BufferColor <: Color
    color::Vector{RGBf0}
end

# color function, mesher uses it to throw in points and get out colors
#TODO super slow
@component struct FunctionColor <: Color
    color::Function
end

@component struct DensityColor <: Color
    color::Array{RGBf0,3}
end

# Cycle, mesher uses it to iterate over together with points
@component struct CycledColor <: Color
    color::Cycle{Union{RGBAf0,Vector{RGBAf0}}}
end

@shared_component struct Grid
    points::Array{Point3f0,3}
end

abstract type Geometry <: ComponentData end

@component struct PolygonGeometry <: Geometry #spheres and the like
    geometry::Any
end

@component struct FileGeometry <: Geometry #.obj files
    geometry::String
end

@component struct FunctionGeometry <: Geometry
    geometry :: Function
    iso      :: Float32
end

@component struct DensityGeometry <: Geometry
    geometry :: Array{Float32,3}
    iso      :: Float32
end

@component struct VectorGeometry <: Geometry
    geometry::Vector{Point3f0}
end

@component struct LineGeometry <: Geometry
    points::Vector{Point3f0}
    function LineGeometry(points::Vector{Point3f0})
        if length(points) < 4
            insert!(points, 1, points[2] + 1.001 * (points[1] - points[2]))
        end
        if length(points) < 4
            push!(points, points[end-1] + 1.001 * (points[end] - points[end-1]))
        end
        return new(points)
    end
end

@component @with_kw struct LineOptions
    thickness::Float32 = 2.0f0
    miter::Float32     = 0.6f0
end

@component @with_kw struct Text
    str::String = "test"
    font_size::Float64 = 20
    font = default_font()
    align::Tuple{Symbol,Symbol} = (:bottom, :right)
    offset::Vec3f0 = zero(Vec3f0)
end


text:
using Documenter, RandomizedLinAlg

makedocs(
    modules = [RandomizedLinAlg],
    format = Documenter.HTML(),
    doctest = false,
    clean = true,
    sitename = "RandomizedLinAlg.jl",
    pages = [
        "Home" => "index.md",
    ]
)

deploydocs(
    repo = "github.com/haampie/RandomizedLinAlg.jl.git",
    target = "build"
)


text:
import Flux

"""
    Dense(in::Integer, out::Integer; omega_0 = 30, is_first = false)

Create a `Dense` layer with SIREN initialization, parameters `W` and `b`, and scaling factor omega_0.

    y = sin.(omega_0 *(W * x .+ b))

The input `x` must be a vector of length `in`, or a batch of vectors represented
as an `in × N` matrix. The out `y` will be a vector or batch of length `out`.

# Examples
```jldoctest; setup = :(using Random; Random.seed!(0))
julia> d = SIREN.Dense(5, 2)
SIREN.Dense(5, 2, omega_0=30)

julia> d(rand(5))
2-element Array{Float64,1}:
 -0.9926777049551361
 -0.9019978122219484```
"""
struct Dense{F,S,T}
    omega_0::F
    W::S
    b::T
end

function Dense(in::Integer, out::Integer;
               omega_0=30, is_first::Bool = false)
  return Dense(omega_0, SIREN_init(omega_0, is_first, out, in), zeros(out))
end

Flux.@functor Dense

function (a::Dense)(x::AbstractArray)
  W, b, omega_0 = a.W, a.b, a.omega_0
  sin.(omega_0 * (W*x .+ b))
end

function Base.show(io::IO, l::Dense)
  print(io, "SIREN.Dense(", size(l.W, 2), ", ", size(l.W, 1))
  print(io, ", omega_0=", l.omega_0)
  print(io, ")")
end

## FIGURE OUT WHAT THIS MEANS
# Try to avoid hitting generic matmul in some simple cases
# Base's matmul is so slow that it's worth the extra conversion to hit BLAS
(a::Dense{<:Any,W})(x::AbstractArray{T}) where {T <: Union{Float32,Float64}, W <: AbstractArray{T}} =
  invoke(a, Tuple{AbstractArray}, x)

(a::Dense{<:Any,W})(x::AbstractArray{<:AbstractFloat}) where {T <: Union{Float32,Float64}, W <: AbstractArray{T}} =
  a(T.(x))
##
"""
    outdims(l::Dense, isize)

Calculate the output dimensions given the input dimensions, `isize`.

```julia
m = Dense(10, 5)
outdims(m, (5, 2)) == (5,)
outdims(m, (10,)) == (5,)
```
"""
outdims(l::Dense, isize) = (size(l.W)[1],)

max_issues_repo_name: MacKenzieHnC/SIREN

max_forks_repo_name: MacKenzieHnC/SIREN


text:
"""
    FDSNRequest

An abstract type representing requests conforming to the FDSN Web Services specification.

Current subtypes of `FDSNRequest`:
- `FDSNDataSelect`
- `FDSNEvent`
- `FDSNStation`
"""
abstract type FDSNRequest <: SeisRequest end

protocol_string(::FDSNRequest) = "fdsnws"

"""
    FDSNEvent(kwargs...)

Create a FDSN web services event query which can be sent to a datacentre which implements
the FDSN Web Services specification.

## Available options:

|Parameter|Description|
|:--------|:----------|
|`starttime`|Limit to events on or after the specified start time.|
|`endtime`|Limit to events on or before the specified end time.|
|`minlatitude`|Limit to events with a latitude larger than or equal to the specified minimum.|
|`maxlatitude`|Limit to events with a latitude smaller than or equal to the specified maximum.|
|`minlongitude`|Limit to events with a longitude larger than or equal to the specified minimum.|
|`maxlongitude`|Limit to events with a longitude smaller than or equal to the specified maximum.|
|`latitude`|Specify the latitude to be used for a radius search.|
|`longitude`|Specify the longitude to the used for a radius search.|
|`minradius`|Limit to events within the specified minimum number of degrees from the geographi point defined by the latitude and longitude parameters.|
|`maxradius`|Limit to events within the specified maximum number of degrees from the geographic point defined by the latitude and longitude parameters.|
|`mindepth`|Limit to events with depth more than the specified minimum.|
|`maxdepth`|Limit to events with depth less than the specified maximum.|
|`minmagnitude`|Limit to events with a magnitude larger than the specified minimum.|
|`maxmagnitude`|Limit to events with a magnitude smaller than the specified maximum.|
|`magnitudetype`|Specify a magnitude type to use for testing the minimum and maximum limits.|
|`includeallorigins`|Specify if all origins for the event should be included, default is data center dependent but is suggested to be the preferred origin only.|
|`includeallmagnitudes`|Specify if all magnitudes for the event should be included, default is data center dependent but is suggested to be the preferred magnitude only.|
|`includearrivals`|Specify if phase arrivals should be included.|
|`eventid`|Select a specific event by ID; event identifiers are data center specific.|
|`limit`|Limit the results to the specified number of events.|
|`offset`|Return results starting at the event count specified, starting at 1.|
|`orderby`|Order the result by time or magnitude with the following possibilities: `"time"`: order by origin descending time; `"time-asc"`: order by origin ascending time; `"magnitude"`: order by descending magnitude; `"magnitude-asc"`: order by ascending magnitude|
|`catalog`|Limit to events from a specified catalog|
|`contributor`|Limit to events contributed by a specified contributor.|
|`updatedafter`|Limit to events updated after the specified time.|
|`format`|Specify format of result, either `"xml"` (default) or `"text"`. If this parameter is not specified the service must return QuakeML.|
|`nodata`|Select status code for “no data”, either `204` (default) or `404`.|"""
@with_kw struct FDSNEvent <: FDSNRequest
    starttime::MDateTime = missing
    endtime::MDateTime = missing
    minlatitude::MFloat = missing
    maxlatitude::MFloat = missing
    minlongitude::MFloat = missing
    maxlongitude::MFloat = missing
    latitude::MFloat = missing
    longitude::MFloat = missing
    minradius::MFloat = missing
    maxradius::MFloat = missing
    mindepth::MFloat = missing
    maxdepth::MFloat = missing
    minmagnitude::MFloat = missing
    maxmagnitude::MFloat = missing
    magnitudetype::MString = missing
    includeallorigins::MBool = missing
    includeallmagnitudes::MBool = missing
    includearrivals::MBool = missing
    eventid::MString = missing
    limit::MInt = missing
    offset::MInt = missing
    orderby::MString = missing
    catalog::MString = missing
    contributor::MString = missing
    updatedafter::MDateTime = missing
    format::MString = missing
    nodata::Int = 204
    function FDSNEvent(st, et, minlat, maxlat, minlon, maxlon, lat, lon, minr, maxr, mind, maxd,
                       minmag, maxmag, magtype, allorigins, allmags, arrs, id, limit, offset,
                       orderby, catalog, contributor, updatedafter, format, nodata)
        !ismissing(st) && !ismissing(et) && st > et &&
           throw(ArgumentError("`starttime` must be before endtime"))
        (!ismissing(minr) || !ismissing(maxr)) && (ismissing(lat) || ismissing(lon)) &&
            throw(ArgumentError("Both `latitude` and `longitude` must be present if " *
                                "specifying `minradius` or `maxradius`"))
        coalesce(limit, 1) > 0 || throw(ArgumentError("`limit` cannot be less than 1"))
        coalesce(offset, 1) > 0 || throw(ArgumentError("`offset` cannot be less than 1"))
        !ismissing(orderby) && orderby ∉ ("time", "time-asc", "magnitude", "magnitude-asc")
        -90 ≤ coalesce(minlat, -90) ≤ 90 || throw(ArgumentError("`minlatitude` must be in range -90 to 90"))
        -90 ≤ coalesce(maxlat, 90) ≤ 90 || throw(ArgumentError("`maxlatitude` must be in range -90 to 90"))
        -180 ≤ coalesce(minlon, -180) ≤ 180 || throw(ArgumentError("`minlongitude` must be in range -180 to 180"))
        -180 ≤ coalesce(maxlon, 180) ≤ 180 || throw(ArgumentError("`maxlongitude` must be in range -180 to 180"))
        -90 ≤ coalesce(lat, 0) ≤ 90 || throw(ArgumentError("`latitude` must be in range -90 to 90"))
        -180 ≤ coalesce(lon, 0) ≤ 180 || throw(ArgumentError("`longitude` must be in range -180 to 180"))
        0 ≤ coalesce(minr, 0) ≤ 180 || throw(ArgumentError("`minradius` must be in range 0 to 180"))
        0 ≤ coalesce(maxr, 180) ≤ 180 || throw(ArgumentError("`maxradius` must be in range 0 to 180"))
        coalesce(format, "xml") ∈ ("xml", "miniseed", "text") ||
            throw(ArgumentError("`format` must be one of \"xml\" or \"text\""))
        nodata ∈ (204, 404) || throw(ArgumentError("`nodata` must be 204 or 404"))
        new(st, et, minlat, maxlat, minlon, maxlon, lat, lon, minr, maxr, mind, maxd,
            minmag, maxmag, magtype, allorigins, allmags, arrs, id, limit, offset,
            orderby, catalog, contributor, updatedafter, format, nodata)
        end
end

"""
    FDSNDataSelect(kwargs...)

Create a FDSN web services data selection query which can be sent to a datacentre which
implements the FDSN Web Services specification.

Set options with keyword arguments, e.g.:

```
julia> FDSNDataSelect(station="ANMO", starttime=)
```

## Available options:

|Parameter|Description|
|:--------|:----------|
|`starttime`|Limit results to time series samples on or after the specified start time.|
|`endtime`|Limit results to time series samples on or before the specified end time.|
|`network`|Select one or more network codes.  Can be SEED network codes or data center defined codes.  Multiple codes are comma-separated.|
|`station`|Select one or more SEED station codes.  Multiple codes are comma-separated.|
|`location`|Select one or more SEED location identifiers.  Multiple identifiers are comma-separated.  As a special case “--“ (two dashes) will be translated to a string of two space characters to match blank location IDs.|
|`channel`|Select one or more SEED channel codes.  Multiple codes are comma-separated.|
|`quality`|Select a specific SEED quality indicator, handling is data center dependent.|
|`minimumlength`|Limit results to continuous data segments of a minimum length specified in seconds.|
|`longestonly`|Limit results to the longest continuous segment per channel.|
|`format`|Specify format of result, the default value is `"miniseed"`.|
|`nodata`|Select status code for “no data”, either ‘204’ (default) or ‘404’.|
"""
@with_kw struct FDSNDataSelect <: FDSNRequest
    starttime::MDateTime = missing
    endtime::MDateTime = missing
    network::MString = missing
    station::MString = missing
    location::MString = missing
    channel::MString = missing
    quality::MString = missing
    minimumlength::MFloat = missing
    longestonly::MBool = missing
    format::MString = missing
    nodata::Int = 204
    function FDSNDataSelect(st, et, net, sta, loc, cha, q, minlength, longestonly, format, nodata)
        !ismissing(st) && !ismissing(et) && st > et &&
            throw(ArgumentError("`starttime` must be before endtime"))
        !ismissing(net) && !isascii(net) && throw(ArgumentError("`network` must be ASCII"))
        !ismissing(sta) && !isascii(sta) && throw(ArgumentError("`station` must be ASCII"))
        if !ismissing(loc)
            !isascii(loc) && throw(ArgumentError("`location` must be ASCII"))
            loc == "  " && (loc = "--")
        end
        !ismissing(cha) && !isascii(cha) && throw(ArgumentError("`channel` must be ASCII"))
        coalesce(q, "B") ∈ ("D", "R", "Q", "M", "B") ||
            throw(ArgumentError("`quality` must be one of \"D\", \"R\", \"Q\", \"M\" or \"B\""))
        coalesce(minlength, 0) >= 0 || throw(ArgumentError("`minimumlength` must be 0 or more"))
        nodata ∈ (204, 404) || throw(ArgumentError("`nodata` must be 204 or 404"))
        new(st, et, net, sta, loc, cha, q, minlength, longestonly, format, nodata)
    end
end

"""
    FDSNStation(kwargs...)

Create a FDSN web services station query which can be sent to a datacentre which implements
the FDSN Web Services specification.

## Available options

|Parameter|Description|
|:--------|:----------|
|`starttime`|Limit to metadata epochs starting on or after the specified start time.|
|`endtime`|Limit to metadata epochs ending on or before the specified end time.|
|`startbefore`|Limit to metadata epochs starting before specified time.|
|`startafter`|Limit to metadata epochs starting after specified time.|
|`endbefore`|Limit to metadata epochs ending before specified time.|
|`endafter`|Limit to metadata epochs ending after specified time.|
|`network`|Select one or more network codes.  Can be SEED network codes or data center defined codes.  Multiple codes are comma-separated.|
|`station`|Select one or more SEED station codes.  Multiple codes are comma-separated.|
|`location`|Select one or more SEED location identifiers.  Multiple identifiers are comma-separated.  As a special case “--“ (two dashes) will be translated to a string of two space characters to match blank location IDs.|
|`channel`|Select one or more SEED channel codes.  Multiple codes are comma-separated.|
|`minlatitude`|Limit to stations with a latitude larger than or equal to the specified minimum.|
|`maxlatitude`|Limit to stations with a latitude smaller than or equal to the specified maximum.|
|`minlongitude`|Limit to stations with a longitude larger than or equal to the specified minimum.|
|`maxlongitude`|Limit to stations with a longitude smaller than or equal to the specified maximum.|
|`latitude`|Specify the latitude to be used for a radius search.|
|`longitude`|Specify the longitude to the used for a radius search.|
|`minradius`|Limit results to stations within the specified minimum number of degrees from the geographic point defined by the latitude and longitude parameters.|
|`maxradius`|Limit results to stations within the specified maximum number of degrees from the geographic point defined by the latitude and longitude parameters.|
|`level`|Specify the level of detail for the results.|
|`includerestricted`|Specify if results should include information for restricted stations.|
|`includeavailability`|Specify if results should include information about time series data availability.|
|`updatedafter`|Limit to metadata updated after specified time; updates are data center specific.|
|`matchtimeseries`|Limit to metadata where selection criteria matches time series data availability.|
|`format`|Specify format of result, either `"xml"` (default) or `"text"`.|
|`nodata`|Select status code for “no data”, either `204` (default) or `404`.|
"""
@with_kw struct FDSNStation <: FDSNRequest
    starttime::MDateTime = missing
    endtime::MDateTime = missing
    startbefore::MDateTime = missing
    startafter::MDateTime = missing
    endbefore::MDateTime = missing
    endafter::MDateTime = missing
    network::MString = missing
    station::MString = missing
    location::MString = missing
    channel::MString = missing
    minlatitude::MFloat = missing
    maxlatitude::MFloat = missing
    minlongitude::MFloat = missing
    maxlongitude::MFloat = missing
    latitude::MFloat = missing
    longitude::MFloat = missing
    minradius::MFloat = missing
    maxradius::MFloat = missing
    level::MString = missing
    includerestricted::MBool = missing
    includeavailability::MBool = missing
    updatedafter::MDateTime = missing
    matchtimeseries::MBool = missing
    format::MString = missing
    nodata::Int = 204
    function FDSNStation(st, et, sb, sa, eb, ea, net, sta, loc, cha, minlat, maxlat,
                         minlon, maxlon, lat, lon, minr, maxr, level, restricted,
                         availability, updatedafter, matchtimeseries, format, nodata)
        !ismissing(st) && !ismissing(et) && st > et &&
            throw(ArgumentError("`starttime` must be before endtime"))
        !ismissing(sb) && !ismissing(sa) && sb > sa &&
            throw(ArgumentError("`startbefore` must be before startafter"))
        !ismissing(eb) && !ismissing(ea) && eb > ea &&
            throw(ArgumentError("`endbefore` must be before endafter"))
        !ismissing(net) && !isascii(net) && throw(ArgumentError("`network` must be ASCII"))
        !ismissing(sta) && !isascii(sta) && throw(ArgumentError("`station` must be ASCII"))
        if !ismissing(loc)
            !isascii(loc) && throw(ArgumentError("`channel` must be ASCII"))
            loc == "  " && (loc = "--")
        end
        !ismissing(cha) && !isascii(cha) && throw(ArgumentError("`channel` must be ASCII"))
        (!ismissing(minr) || !ismissing(maxr)) && (ismissing(lat) || ismissing(lon)) &&
            throw(ArgumentError("Both `latitude` and `longitude` must be present if " *
                                "specifying `minradius` or `maxradius`"))
        -90 ≤ coalesce(minlat, -90) ≤ 90 || throw(ArgumentError("`minlatitude` must be in range -90 to 90"))
        -90 ≤ coalesce(maxlat, 90) ≤ 90 || throw(ArgumentError("`maxlatitude` must be in range -90 to 90"))
        -180 ≤ coalesce(minlon, -180) ≤ 180 || throw(ArgumentError("`minlongitude` must be in range -180 to 180"))
        -180 ≤ coalesce(maxlon, 180) ≤ 180 || throw(ArgumentError("`maxlongitude` must be in range -180 to 180"))
        -90 ≤ coalesce(lat, 0) ≤ 90 || throw(ArgumentError("`latitude` must be in range -90 to 90"))
        -180 ≤ coalesce(lon, 0) ≤ 180 || throw(ArgumentError("`longitude` must be in range -180 to 180"))
        0 ≤ coalesce(minr, 0) ≤ 180 || throw(ArgumentError("`minradius` must be in range 0 to 180"))
        0 ≤ coalesce(maxr, 180) ≤ 180 || throw(ArgumentError("`maxradius` must be in range 0 to 180"))
        if !ismissing(level)
            !isascii(level) && throw(ArgumentError("`level` must be ASCII"))
            level ∉ ("network", "station", "channel", "response") &&
                throw(ArgumentError("`level` must be one of \"network\", \"station\", \"channel\" or \"response\""))
        end
        nodata ∈ (204, 404) || throw(ArgumentError("`nodata` must be 204 or 404"))
        new(st, et, sb, sa, eb, ea, net, sta, loc, cha, minlat, maxlat,
            minlon, maxlon, lat, lon, minr, maxr, level, restricted,
            availability, updatedafter, matchtimeseries, format, nodata)
    end
end

service_string(::FDSNEvent) = "event"
service_string(::FDSNDataSelect) = "dataselect"
service_string(::FDSNStation) = "station"


text:
"""
The simplest bed file only has three columns (chr, start, end), like:
```
chr1    11846100    11846483
chr1    11846810    11850969
chr1    11851220    11851402
chr1    11852290    11852468
chr1    11853920    11854179
```
"""

# read all records in a bed file
function bed_read_intervals(filename)
    records = Array{Interval}{1}()
    stream = opengene_open(filename, "r")
    # TODO: work around for readall missing in master
    if isdefined(Base, :readstring)
        text = readstring(stream)
    else
        text = readall(stream)
    end
    lines = split(text, "\n")
    for line in lines
        # remove Windows/Mac line breaks
        if startswith(line, "track")
            continue
        end
        str = strip(line, '\r')
        items = split(str, r"[\s\t]+")
        if length(items) < 3
            continue
        end
        chrom = items[1]
        chromstart = parse(Int, items[2])
        chromend = parse(Int, items[3])
        push!(records, Interval(chrom, chromstart, chromend))
    end
    return records
end

# write all records into a bed file
function bed_write_intervals(filename, records)
    stream = opengene_open(filename, "w")
    for r in records
        write(stream, r.chrom, "\t", string(r.chromstart), "\t", string(r.chromend), "\n")
    end
    close(stream)
end


text:
using DashBootstrapComponents

button_group = dbc_buttongroup([
    dbc_button("Left", outline = true, color = "primary"),
    dbc_button("Middle", outline = true, color = "primary"),
    dbc_button("Right", outline = true, color = "primary"),
])

max_stars_repo_name: glsdown/dash-bootstrap-components

max_issues_repo_name: glsdown/dash-bootstrap-components

max_forks_repo_name: glsdown/dash-bootstrap-components


text:
abstract AbstractPlanOutOp

assertIndexishValue(value::Associative) = value
assertIndexishValue(value::AbstractArray) = value

getArgs(op::AbstractPlanOutOp) = op.args
hasArg(op::AbstractPlanOutOp, name) = haskey(op.args, name)
getArg(op::AbstractPlanOutOp, name::AbstractString) = getindex(op.args, name)
setArg!(op::AbstractPlanOutOp, value, name::AbstractString) = setindex!(op.args, value, name)
getArgMixed(op::AbstractPlanOutOp, name::AbstractString) = getArg(op, name)
getArgInt(op::AbstractPlanOutOp, name::AbstractString) = getArgMixed(op, name)::Int
getArgString(op::AbstractPlanOutOp, name::AbstractString) = getArgMixed(op, name)::AbstractString
getArgNumeric(op::AbstractPlanOutOp, name::AbstractString) = getArgMixed(op, name)::Number
getArgList(op::AbstractPlanOutOp, name::AbstractString) = getArgMixed(op, name)::AbstractArray
getArgMap(op::AbstractPlanOutOp, name::AbstractString) = getArgMixed(op, name)::Associative
getArgIndexish(op::AbstractPlanOutOp, name::AbstractString) = assertIndexishValue(getArgMixed(op, name))

abstract AbstractPlanOutOpSimple <: AbstractPlanOutOp

function execute(op::AbstractPlanOutOpSimple, i::AbstractPlanOutMapper)
  args = getArgs(op)
  for (k, v) in args
    setArg!(op, evaluate(i, v), k)
  end
  simpleExecute(op, i)
end

abstract AbstractPlanOutOpBinary <: AbstractPlanOutOpSimple
simpleExecute(op::AbstractPlanOutOpBinary, i::AbstractPlanOutMapper) = execute(op, i, getArgMixed(op, "left"), getArgMixed(op, "right"))

abstract AbstractPlanOutOpUnary <: AbstractPlanOutOpSimple
simpleExecute(op::AbstractPlanOutOpUnary, i::AbstractPlanOutMapper) = execute(op, i, getArgMixed(op, "value"))

abstract AbstractPlanOutOpCommutative <: AbstractPlanOutOpSimple
simpleExecute(op::AbstractPlanOutOpCommutative, i::AbstractPlanOutMapper) = execute(op, i, getArgList(op, "values"))

abstract AbstractPlanOutOpRandom <: AbstractPlanOutOpSimple
simpleExecute(op::AbstractPlanOutOpRandom, i::AbstractPlanOutMapper) = randExecute(op, i)
getValue(a::Assignment, value, name) = value
function getValue(a::Assignment, value::AbstractPlanOutOpRandom, name)
  if !hasArg(value, "salt")
    setArg!(value, name, "salt")
  end
  execute(value, a)
end

type StopPlanOutException <: Exception
  in_experiment::Bool
end


text:
using StructuresKit

#Example 1 from

#Plaut and Moen (2019).  "Flexural-torsional deformations of imperfect thin-walled columns with continous bracing."  Proceedings of the Annual Stability Conference, Structural Stability Research Council, St. Louis, MO.
#https://www.aisc.org/globalassets/continuing-education/ssrc-proceedings/2019/plaut_and_moen_ssrc_2019.pdf

#A Ix Iy J Cw xc yc xs ys
A = 272.0
Ix = 363370.0
Iy = 64100.0
xc = 0.0
yc = 0.0
xs = -32.59
ys = 0.0
J = 188.0
Cw = 122720891.0
section_properties = [(A, Ix, Iy, J, Cw, xc, yc, xs, ys)]

#E  ν
material_properties = [(200,0.30)]

#kx ky kϕ hx hy
springs = [0.0, 0.0, 0.0, 0.0, 0.0]

#member information
#L dL SectionProperties MaterialProperties Springs
member_definitions = [(2438.0, 2438.0/10,1,1,1)]

num_nodes = Int(member_definitions[1][1]/member_definitions[1][2]) + 1

#P
loads = 5.0 * ones(num_nodes)

#end boundary conditions
#type=1 u''=v''=ϕ''=0 (simply supported), type=2 u'=v'=ϕ'=0  (fixed), type=3 u''=v''=ϕ''=u'''=v'''=ϕ'''=0 (free end, e.g., a cantilever)
end_boundary_conditions = [1 1]

#supports
#location where u=v=ϕ=0
supports = [0.0 2438.0]

#imperfections
L = member_definitions[1][1]
dL = member_definitions[1][2]
z = 0: dL :L
uo = L / 1000 * sin.(π*z/L)
vo = L / 1000 * sin.(π*z/L)
ϕo = 0.00766 * sin.(π*z/L)

imperfections = [uo, vo, ϕo]

#Figure 4
#for P=5 kN
#(kϕ, ϕ+ϕo) from Mathematica
#kϕ is in kN-mm/rad/mm
data_SSRC = [(0,0.0201),(0.01,0.0185),(0.03,0.0163),(0.04,0.0158),(0.05,0.01486),(0.06,0.0143),(0.09,0.01305),(0.12,0.0122),(0.15,0.0116),(0.2,0.01085),(0.3,0.00999),(0.4,0.00949),(0.5,0.00917),(0.7,0.00876),(1,0.00846),(2,0.00808),(5,0.00783)]

num_points = length(data_SSRC)

ϕ_predicted_max = zeros(Float64, num_points)
kϕ = zeros(Float64, num_points)

ϕo_max = maximum(ϕo)

ϕ_total_SSRC = zeros(Float64, num_points)

for i = 1:num_points

    #kx ky kϕ hx hy
    kϕ[i] = data_SSRC[i][1]

    springs = [0.0, 0.0, kϕ[i], 0.0, 0.0]

    u, v, ϕ, properties = Column.solve(member_definitions, section_properties, material_properties, loads, springs, end_boundary_conditions, supports, imperfections)

    ϕ_predicted_max[i] = maximum(ϕ)
    ϕ_total_SSRC[i] = data_SSRC[i][2]

end

ϕ_total_predicted = ϕ_predicted_max .+ ϕo_max

#calculate percent error at every load compared to Mathematica solution
ϕ_difference= abs.((ϕ_total_predicted .- ϕ_total_SSRC[:]))./ ϕ_total_SSRC[:]

MaxError=maximum(ϕ_difference[2:end])

#accept 2% error from numerical solution
#there looks to be a small bug in the Mathematica data for one point, otherwise 0.01 would work here
@test MaxError <= 0.02

# using Plots
# plot(kϕ, ϕ_predicted_max .+ ϕo_max, markershape = :o)
# plot!(kϕ, ϕ_total_SSRC, markershape = :hexagon)

#*********************************************************

#Figure 5
#for P=5 kN
#(kϕ, v+vo) from Mathematica
#kϕ is in kN-mm/rad/mm
data_SSRC = [(0,2.5716),(0.01,2.5694),(0.02,2.5677),(0.04,2.5652),(0.06,2.5635),(0.08,2.5623),(0.1,2.5613),(0.12,2.5606),(0.15,2.5600),(0.2,2.5587),(0.3,2.5575),(0.4,2.55675),(0.5,2.5563),(0.6,2.556),(0.7,2.5558)]

num_points = length(data_SSRC)

v_predicted_max = zeros(Float64, num_points)
kϕ = zeros(Float64, num_points)

vo_max = maximum(vo)

v_total_SSRC = zeros(Float64, num_points)

for i = 1:num_points

    #kx ky kϕ hx hy
    kϕ[i] = data_SSRC[i][1]

    springs = [0.0, 0.0, kϕ[i], 0.0, 0.0]

    u, v, ϕ, properties = Column.solve(member_definitions, section_properties, material_properties, loads, springs, end_boundary_conditions, supports, imperfections)

    v_predicted_max[i] = maximum(v)
    v_total_SSRC[i] = data_SSRC[i][2]

end

v_total_predicted = v_predicted_max .+ vo_max

#calculate percent error at every load compared to Mathematica solution
v_difference= abs.((v_total_predicted .- v_total_SSRC[:]))./ v_total_SSRC[:]

MaxError=maximum(v_difference[2:end])
#accept 1% error from numerical solution
@test MaxError <= 0.01

# using Plots
# plot(kϕ, v_predicted_max .+ vo_max, markershape = :o)
# plot!(kϕ, v_total_SSRC, markershape = :hexagon)


text:
using DataDeps

register(DataDep(
  "lung-cancer",
  "http://archive.ics.uci.edu/ml/datasets/Lung+Cancer",
  "http://archive.ics.uci.edu/ml/machine-learning-databases/lung-cancer/lung-cancer.data",
  "5fe074a5e4b44816e958b3f37503b1357a1543daa7eee77485040b0e3aef18f1",
  post_fetch_method=(path -> begin
    UCIData.process_dataset(path,
        target_index=1,
        feature_indices=2:57,
        categoric_indices=2:57,
        footerskip=1,
    )
  end),
))

max_stars_repo_name: JackDunnNZ/uci-data

max_issues_repo_name: JackDunnNZ/uci-data

max_forks_repo_name: JackDunnNZ/uci-data


text:
using quantumoptics

N = 200
xmin = -10.
xmax = 10.
omega = 2.

x0 = 1.
p0 = 0.
sigma0 = 1.

T = [0.:0.2:2.;]

basis_position = quantumoptics.particle.PositionBasis(xmin, xmax, N)
basis_position2d = compose(basis_position, basis_position)
basis_momentum = quantumoptics.particle.MomentumBasis(basis_position)
basis_momentum2d = compose(basis_momentum, basis_momentum)

xsamplepoints = quantumoptics.particle.samplepoints(basis_position)
psamplepoints = quantumoptics.particle.samplepoints(basis_momentum)

# Tpx = quantumoptics.particle.FFTOperator(basis_momentum, basis_position)
# Txp = quantumoptics.particle.FFTOperator(basis_position, basis_momentum)

# Position Basis
@time p = SparseOperator(quantumoptics.particle.momentumoperator(basis_position))
@time x = SparseOperator(quantumoptics.particle.positionoperator(basis_position))
@time V = SparseOperator(basis_position, diagm(complex(omega)^2*xsamplepoints.^2))
@time I = sparse_identity(basis_position)

@time p2 = p^2/2
@time Hkin2d = (tensor(p2, I) + tensor(I, p2))
@time V2d = tensor(V, I) + tensor(I, V)
@time H2d = Hkin2d + V2d

@time psi0 = quantumoptics.particle.gaussianstate(basis_position, x0, p0, sigma0)
@time psi0_2d = tensor(psi0, psi0)
@time tout, psi_t = timeevolution.schroedinger(T, psi0_2d, H2d)
@time tout, psi_t = timeevolution.schroedinger(T, psi0_2d, H2d)

# for i=1:length(T)
#     println(expect(p_mom, psi_mom_t[i]), ", ", expect(p_pos, psi_pos_t[i]))
#     println(expect(x_mom, psi_mom_t[i]), ", ", expect(x_pos, psi_pos_t[i]))
#     println(norm(Txp*psi_mom_t[i] - psi_pos_t[i]))
#     println(norm(psi_mix_t[i] - psi_pos_t[i]))
#     println("================================================")
# end