text:
using EscapeAnalysis, InteractiveUtils, Test
import EscapeAnalysis:
    EscapeInformation
for t in subtypes(EscapeInformation)
    canonicalname = Symbol(parentmodule(t), '.', nameof(t))
    canonicalpath = Symbol.(split(string(canonicalname), '.'))

    modpath = Expr(:., canonicalpath[1:end-1]...)
    symname = Expr(:., last(canonicalpath))
    ex = Expr(:import, Expr(:(:), modpath, symname))
    Core.eval(@__MODULE__, ex)
end

@testset "EscapeAnalysis" begin

let # simplest
    src, escapes = analyze_escapes((Any,)) do a # return to caller
        return nothing
    end
    @test escapes.arguments[2] isa ReturnEscape
end

let # global assignement
    src, escapes = analyze_escapes((Any,)) do a
        global aa = a
        return nothing
    end
    @test escapes.arguments[2] isa Escape
end

let # return
    src, escapes = analyze_escapes((Any,)) do a
        return a
    end
    @test escapes.arguments[2] isa ReturnEscape
end

@testset "control flows" begin
    let # branching
        src, escapes = analyze_escapes((Any,Bool,)) do a, c
            if c
                return nothing # a doesn't escape in this branch
            else
                return a # a escapes to a caller
            end
        end
        @test escapes.arguments[2] isa ReturnEscape
    end

    let # π node
        src, escapes = analyze_escapes((Any,)) do a
            if isa(a, Regex)
                identity(a) # compiler will introduce π node here
                return a    # escape !
            else
                return nothing
            end
        end
        @test escapes.arguments[2] isa ReturnEscape
    end

    let # loop
        src, escapes = analyze_escapes((Int, Regex,)) do n, r
            rs = Regex[]
            while n > 0
                push!(rs, r)
                n -= 1
            end
            return rs
        end
        @test escapes.arguments[3] isa Escape
    end

    let # exception
        src, escapes = analyze_escapes((Any,)) do a
            try
                nothing
            catch err
                return a # return escape
            end
        end
        @test escapes.arguments[2] isa ReturnEscape
    end
end

mutable struct MyMutable
    cond::Bool
end

let # more complex
    src, escapes = analyze_escapes((Bool,)) do c
        x = Vector{MyMutable}() # escape
        y = MyMutable(c) # escape
        if c
            push!(x, y) # escape
            return nothing
        else
            return x # return escape
        end
    end

    i = findfirst(==(Vector{MyMutable}), src.stmts.type)
    @assert !isnothing(i)
    @test escapes.ssavalues[i] isa Escape
    i = findfirst(==(MyMutable), src.stmts.type)
    @assert !isnothing(i)
    @test escapes.ssavalues[i] isa Escape
end

let # simple allocation
    src, escapes = analyze_escapes((Bool,)) do c
        mm = MyMutable(c) # just allocated, never escapes
        return mm.cond ? nothing : 1
    end

    i = findfirst(==(MyMutable), src.stmts.type) # allocation statement
    @assert !isnothing(i)
    @test escapes.ssavalues[i] isa NoEscape
end

@testset "inter-procedural" begin
    m = Module()

    @eval m @noinline f_noescape(x) = (broadcast(identity, x); nothing)
    let
        src, escapes = @eval m $analyze_escapes() do
            f_noescape(Ref("Hi"))
        end
        i = findfirst(==(Base.RefValue{String}), src.stmts.type) # find allocation statement
        @assert !isnothing(i)
        @test escapes.ssavalues[i] isa ReturnEscape
    end

    @eval m @noinline f_returnescape(x) = broadcast(identity, x)
    let
        src, escapes = @eval m $analyze_escapes() do
            f_returnescape(Ref("Hi"))
        end
        i = findfirst(==(Base.RefValue{String}), src.stmts.type) # find allocation statement
        @assert !isnothing(i)
        @test escapes.ssavalues[i] isa ReturnEscape
    end

    @eval m @noinline f_escape(x) = (global xx = x) # obvious escape
    let
        src, escapes = @eval m $analyze_escapes() do
            f_escape(Ref("Hi"))
        end
        i = findfirst(==(Base.RefValue{String}), src.stmts.type) # find allocation statement
        @assert !isnothing(i)
        @test escapes.ssavalues[i] isa Escape
    end

    # if we can't determine the matching method statically, we should be conservative
    let
        src, escapes = @eval m $analyze_escapes((Some{Any},)) do a
            may_exist(a)
        end
        @test escapes.arguments[2] isa Escape
    end
    let
        src, escapes = @eval m $analyze_escapes((Some{Any},)) do a
            Base.@invokelatest f_noescape(a)
        end
        @test escapes.arguments[2] isa Escape
    end

    # handling of simple union-split (just exploit the inliner's effort)
    @eval m begin
        @noinline unionsplit(_)      = string(nothing)
        @noinline unionsplit(a::Int) = a + 10
    end
    let
        src, escapes = @eval m $analyze_escapes((Union{Int,Regex},)) do a
            return unionsplit(a)
        end
        @test escapes.arguments[2] isa ReturnEscape
    end
end

@testset "builtins" begin

    let # sizeof
        src, escapes = analyze_escapes((Vector{Int}, )) do itr
            sizeof(itr)
        end
        @test escapes.arguments[2] isa ReturnEscape
    end

end

end # @testset "EscapeAnalysis" begin


text:
#
# We need this constructor to route around the FixedSizeArray `call` and
# so Simplex(Pt, Pt...) etc works. Hopefully these ambiguities will be fixed in
# forthcoming Julia versions.
@compat (::Type{S}){S <: Simplex}(s::S) = s
@compat function (::Type{T}){T<:Simplex,F<:FixedVector}(f::F...)
    Simplex{length(f),F}(f)
end
@compat (::Type{S}){S <: Simplex}(fs::FlexibleSimplex) = convert(S, fs)

# FSA doesn't handle symbols for length 1 well.
@compat function (::Type{T}){T<:Simplex}(f::Symbol)
    Simplex{1,Symbol}((f,))
end

"""
volume_unnormalized(s::Simplex)

Return volume of s, normalized such that the simplex spanned
by the origin and unit vectors has volume 1.
"""
volume_unnormalized(s::Simplex) = begin es=edgespan(s); √(det(es'*es)); end

"""
volume(s::Simplex)

Return the volume of a geometric object.
"""
volume(s::Simplex) = volume_unnormalized(s) / factorial(nvertices(s)-1)

"""
w = weights(pt, s::Simplex)

If pt is a point inside s, w is such that
sum(w .* vertices(s)) = pt.
This is still true, if pt just lies inside the affine subspace spanned by s.
For general point pt, we only have
sum(w .* vertices(s)) = projection of pt onto affine subspace spanned by s.
"""
function weights(pt, s::Simplex)
    wp = pinvli(edgespan(s)) * (pt - translation(s))
    unshift(wp, 1-sum(wp))
end

translation(s::Simplex) = first(vertices(s))

@generated function edgespan{m, T}(s::Simplex{m,T})
    tup(i) = :(Tuple(vert[$i]-v1))
    tuptup = :(())
    append!(tuptup.args, map(tup, 2:m))
    quote
        vert = vertices(s)
        v1 = vert[1]
        return Mat($tuptup)
    end
end

"""
simplex_face(s::Simplex, i::Int)::Simplex

Return the face opposite to ith vertex of simplex.
"""
simplex_face(s::Simplex, i::Int) = Simplex(deleteat(vertices(s), i))

"""
proj_sqdist{T}(pt::T, s::LineSegment{T}, best_sqd=eltype(T)(Inf))
"""
function proj_sqdist{T}(pt::T, s::LineSegment{T}, best_sqd=eltype(T)(Inf))
    v0, v1 = vertices(s)
    pt = pt - v0
    v = v1 - v0
    θ = clamp(dot(v,pt)/sqnorm(v), zero(eltype(T)), one(eltype(T)))
    pt_proj = θ*v
    best_sqd = min(sqdist(pt, pt_proj), best_sqd)
    return pt_proj + v0, best_sqd
end

"""
pt_proj, sqd = proj_sqdist{nv,T}(pt::T, s::Simplex{nv,T}, best_sqd=eltype(T)(Inf))

# parameters

* pt, s: A point and a simplex, of which we want to know the (minimal) square distance.
* best_sqd: A bound on the distance. If the actual distance is greater then this,
search for the closest point is canceled asap.

# Return

* pt_proj is a point inside s, with minimal distance to pt. If the actual square
distance is greater then best_sqd, the behaviour of pt_proj is not defined.
* sqd is the square of the euclidean distance between pt, s. If the actual square
distance is greater then best_sqd is returned instead.

"""
function proj_sqdist{nv,T}(pt::T, s::Simplex{nv,T}, best_sqd=eltype(T)(Inf))
    w = weights(pt, s)
    best_proj = vertexmat(s) * w
    # at this point best_proj lies in the subspace spanned by s,
    # but not necessarily inside s
    sqd = sqdist(pt, best_proj)
    if sqd >= best_sqd  # pt is far away even from the subspace spanned by s
        return best_proj, best_sqd
    elseif any(w .< 0)  # pt is closest to point inside a face of s
        @inbounds for i in 1:length(w)
            if w[i] < 0
                proj, sqd = proj_sqdist(pt, simplex_face(s,i), best_sqd)
                if sqd < best_sqd
                    best_sqd = sqd
                    best_proj = proj
                end
            end
        end
        return best_proj, best_sqd
    else # proj lies in the interiour of s
        return best_proj, sqd
    end
end

sqdist(pt, s, best=Inf) = proj_sqdist(pt, s, best)[2]

"""
proj_sqdist(p::Vec, q::Vec, best_sqd=eltype(p)(Inf))
"""
@inline function proj_sqdist(p::Vec, q::Vec, best_sqd=eltype(p)(Inf))
    q, min(best_sqd, sqnorm(p-q))
end
"""
proj_sqdist{T}(pt::T, s::Simplex{1, T}, best_sqd=eltype(T)(Inf))
"""
@inline function proj_sqdist{T}(pt::T, s::Simplex{1, T}, best_sqd=eltype(T)(Inf))
    proj_sqdist(pt, translation(s), best_sqd)
end

ext: jl


text:
# XML nodes

abstract type AbstractXMLNode end

#### Types of attributes

const XML_ATTRIBUTE_CDATA = 1
const XML_ATTRIBUTE_ID = 2
const XML_ATTRIBUTE_IDREF = 3
const XML_ATTRIBUTE_IDREFS = 4
const XML_ATTRIBUTE_ENTITY = 5
const XML_ATTRIBUTE_ENTITIES = 6
const XML_ATTRIBUTE_NMTOKEN = 7
const XML_ATTRIBUTE_NMTOKENS = 8
const XML_ATTRIBUTE_ENUMERATION = 9
const XML_ATTRIBUTE_NOTATION = 10

#### Types of nodes

const XML_ELEMENT_NODE = 1
const XML_ATTRIBUTE_NODE = 2
const XML_TEXT_NODE = 3
const XML_CDATA_SECTION_NODE = 4
const XML_ENTITY_REF_NODE = 5
const XML_ENTITY_NODE = 6
const XML_PI_NODE = 7
const XML_COMMENT_NODE = 8
const XML_DOCUMENT_NODE = 9
const XML_DOCUMENT_TYPE_NODE = 10
const XML_DOCUMENT_FRAG_NODE = 11
const XML_NOTATION_NODE = 12
const XML_HTML_DOCUMENT_NODE = 13
const XML_DTD_NODE = 14
const XML_ELEMENT_DECL = 15
const XML_ATTRIBUTE_DECL = 16
const XML_ENTITY_DECL = 17
const XML_NAMESPACE_DECL = 18
const XML_XINCLUDE_START = 19
const XML_XINCLUDE_END = 20
const XML_DOCB_DOCUMENT_NODE = 21

##### Generic methods

is_elementnode(nd::AbstractXMLNode) = (nodetype(nd) == XML_ELEMENT_NODE)
is_textnode(nd::AbstractXMLNode)    = (nodetype(nd) == XML_TEXT_NODE)
is_commentnode(nd::AbstractXMLNode) = (nodetype(nd) == XML_COMMENT_NODE)
is_cdatanode(nd::AbstractXMLNode)   = (nodetype(nd) == XML_CDATA_SECTION_NODE)
is_pinode(nd::AbstractXMLNode)      = (nodetype(nd) == XML_PI_NODE)

#######################################
#
#  XML Attributes
#
#######################################

struct _XMLAttrStruct
    # common part
    _private::Ptr{Cvoid}
    nodetype::Cint
    name::Xstr
    children::Xptr
    last::Xptr
    parent::Xptr
    next::Xptr
    prev::Xptr
    doc::Xptr

    # specific part
    ns::Xptr
    atype::Cint
    psvi::Ptr{Cvoid}
end

mutable struct XMLAttr
    ptr::Xptr
    _struct::_XMLAttrStruct

    function XMLAttr(ptr::Xptr)
        s = unsafe_load(convert(Ptr{_XMLAttrStruct}, ptr))
        @assert s.nodetype == XML_ATTRIBUTE_NODE
        new(ptr, s)
    end
end

name(a::XMLAttr) = unsafe_string(a._struct.name)

function value(a::XMLAttr)
    pct = ccall((:xmlNodeGetContent,libxml2), Xstr, (Xptr,), a._struct.children)
    (pct != C_NULL ? _xcopystr(pct) : "")::AbstractString
end

# iterations

struct XMLAttrIter
    p::Xptr
end

function Base.iterate(it::XMLAttrIter, p::Xptr=it.p)
    p == C_NULL && return nothing
    a = XMLAttr(p)
    (a, a._struct.next)
end

Base.IteratorSize(::Type{XMLAttrIter}) = Base.SizeUnknown()

#######################################
#
#  Base XML Nodes
#
#######################################

struct _XMLNodeStruct
    # common part
    _private::Ptr{Cvoid}
    nodetype::Cint
    name::Ptr{UInt8}
    children::Xptr
    last::Xptr
    parent::Xptr
    next::Xptr
    prev::Xptr
    doc::Xptr

    # specific part
    ns::Xptr
    content::Xstr
    attrs::Xptr
    nsdef::Xptr
    psvi::Ptr{Cvoid}
    line::Cushort
    extra::Cushort
end

mutable struct XMLNode <: AbstractXMLNode
    ptr::Xptr
    _struct::_XMLNodeStruct

    function XMLNode(ptr::Xptr)
        s = unsafe_load(convert(Ptr{_XMLNodeStruct}, ptr))
        new(ptr, s)
    end
end

name(nd::XMLNode) = unsafe_string(nd._struct.name)
nodetype(nd::XMLNode) = nd._struct.nodetype
has_children(nd::XMLNode) = (nd._struct.children != C_NULL)

# whether it is a white-space only text node
is_blanknode(nd::XMLNode) = Bool(ccall((:xmlIsBlankNode,libxml2), Cint, (Xptr,), nd.ptr))

function free(nd::XMLNode)
    ccall((:xmlFreeNode,libxml2), Cvoid, (Xptr,), nd.ptr)
    nd.ptr = C_NULL
end

function unlink(nd::XMLNode)
    ccall((:xmlUnlinkNode,libxml2), Cvoid, (Xptr,), nd.ptr)
end

# iteration over children

struct XMLNodeIter
    p::Xptr
end

function Base.iterate(it::XMLNodeIter, p::Xptr=it.p)
    p == C_NULL && return nothing
    nd = XMLNode(p)
    (nd, nd._struct.next)
end

Base.IteratorSize(::Type{XMLNodeIter}) = Base.SizeUnknown()

child_nodes(nd::XMLNode) = XMLNodeIter(nd._struct.children)

function content(nd::XMLNode)
    pct = ccall((:xmlNodeGetContent,libxml2), Xstr, (Xptr,), nd.ptr)
    (pct != C_NULL ? _xcopystr(pct) : "")::AbstractString
end

# dumping

const DEFAULT_DUMPBUFFER_SIZE = 4096

function Base.string(nd::XMLNode)
    buf = XBuffer(DEFAULT_DUMPBUFFER_SIZE)
    ccall((:xmlNodeDump,libxml2), Cint, (Xptr, Xptr, Xptr, Cint, Cint),
        buf.ptr, nd._struct.doc, nd.ptr, 0, 1)
    r = content(buf)
    free(buf)
    return r
end

Base.show(io::IO, nd::XMLNode) = print(io, string(nd))

#######################################
#
#  XML Elements
#
#######################################

mutable struct XMLElement <: AbstractXMLNode
    node::XMLNode

    function XMLElement(node::XMLNode)
        if !is_elementnode(node)
            throw(ArgumentError("The input node is not an element."))
        end
        new(node)
    end

    XMLElement(ptr::Xptr) = XMLElement(XMLNode(ptr))
end

name(x::XMLElement) = name(x.node)
nodetype(x::XMLElement) = XML_ELEMENT_NODE
has_children(x::XMLElement) = has_children(x.node)
child_nodes(x::XMLElement) = child_nodes(x.node)
content(x::XMLElement) = content(x.node)

Base.string(x::XMLElement) = string(x.node)
Base.show(io::IO, x::XMLElement) = show(io, x.node)

free(x::XMLElement) = free(x.node)
unlink(x::XMLElement) = unlink(x.node)

# attribute access

function attribute(x::XMLElement, name::AbstractString; required::Bool=false)
    pv = ccall((:xmlGetProp,libxml2), Xstr, (Xptr, Cstring), x.node.ptr, name)
    if pv != C_NULL
        return _xcopystr(pv)
    else
        if required
            throw(XMLAttributeNotFound())
        else
            return nothing
        end
    end
end

has_attribute(x::XMLElement, name::AbstractString) =
    ccall((:xmlHasProp,libxml2), Xptr, (Xptr, Cstring), x.node.ptr, name) != C_NULL

has_attributes(x::XMLElement) = (x.node._struct.attrs != C_NULL)
attributes(x::XMLElement) = XMLAttrIter(x.node._struct.attrs)

function attributes_dict(x::XMLElement)
    # make an dictionary based on attributes

    dct = Dict{AbstractString,AbstractString}()
    if has_attributes(x)
        for a in attributes(x)
            dct[name(a)] = value(a)
        end
    end
    return dct
end

# element access

struct XMLElementIter
    parent_ptr::Xptr
end

function Base.iterate(it::XMLElementIter, p::Xptr=ccall((:xmlFirstElementChild, libxml2), Xptr, (Xptr,), it.parent_ptr))
    p == C_NULL && return nothing
    XMLElement(p), ccall((:xmlNextElementSibling, libxml2), Xptr, (Xptr,), p)
end

Base.IteratorSize(::Type{XMLElementIter}) = Base.SizeUnknown()

child_elements(x::XMLElement) = XMLElementIter(x.node.ptr)

# elements by tag name

function find_element(x::XMLElement, n::AbstractString)
    for c in child_elements(x)
        name(c) == n && return c
    end
    return nothing
end

function find_element(x, ns::Vector{<:AbstractString})
    foldl(find_element, ns; init = x)
end

function get_elements_by_tagname(x::XMLElement, n::AbstractString)
    lst = Vector{XMLElement}()
    for c in child_elements(x)
        name(c) == n && push!(lst, c)
    end
    return lst
end
Base.getindex(x::XMLElement, name::AbstractString) = get_elements_by_tagname(x, name)

#######################################
#
#  XML Tree Construction
#
#######################################

function new_element(name::AbstractString)
    p = ccall((:xmlNewNode,libxml2), Xptr, (Xptr, Cstring), C_NULL, name)
    XMLElement(p)
end

function add_child(xparent::XMLElement, xchild::XMLNode)
    p = ccall((:xmlAddChild,libxml2), Xptr, (Xptr, Xptr), xparent.node.ptr, xchild.ptr)
    p != C_NULL || throw(XMLTreeError("Failed to add a child node."))
end

add_child(xparent::XMLElement, xchild::XMLElement) = add_child(xparent, xchild.node)

function new_child(xparent::XMLElement, name::AbstractString)
    xc = new_element(name)
    add_child(xparent, xc)
    return xc
end

function new_textnode(txt::AbstractString)
    p = ccall((:xmlNewText,libxml2), Xptr, (Cstring,), txt)
    XMLNode(p)
end

function new_pinode(name::AbstractString, content::AbstractString)
    p = ccall((:xmlNewPI,libxml2), Xptr, (Cstring, Cstring), name, content)
    XMLNode(p)
end

add_text(x::XMLElement, txt::AbstractString) = add_child(x, new_textnode(txt))
add_pi(x::XMLElement, name::AbstractString, content::AbstractString) = add_child(x, new_pinode(name, content))

function set_attribute(x::XMLElement, name::AbstractString, val::AbstractString)
    a = ccall((:xmlSetProp,libxml2), Xptr, (Xptr, Cstring, Cstring), x.node.ptr, name, val)
    return XMLAttr(a)
end

set_attribute(x::XMLElement, name::AbstractString, val) = set_attribute(x, name, string(val))

const PairTypes = Union{NTuple{2}, Pair}

function set_attributes(x::XMLElement, attrs::AbstractArray{<:PairTypes})
    for (nam, val) in attrs
        set_attribute(x, string(nam), string(val))
    end
end

set_attributes(x::XMLElement, attrs::AbstractDict) = set_attributes(x, collect(attrs))

function set_attributes(x::XMLElement; attrs...)
    for (nam, val) in attrs
        set_attribute(x, string(nam), string(val))
    end
end

function set_content(x::XMLElement, txt::AbstractString)
    ccall((:xmlNodeSetContent, libxml2), Xptr, (Xptr, Cstring,), x.node.ptr, txt)
    x
end


text:
"""
```
generateTimeGrid(
    mpSim::ManpowerSimulation,
    timeRes::Real,
    addCurrentTime::Bool = true )
```
This function generates a time grid for the manpower simulation `mpSim` with time resolution `timeRes`. The resulting grid will span from 0 to the current simulation time or the length of the simulation, whichever is smaller. If the flag `addCurrentTime` is set to `true`, the current simulation time will be added at the end.

This function issues a warning if the entered time resolution is ⩽ 0, and if the simulation hasn't started yet (current sim time == 0).

This function returns a `Vector{Float64}`, the time grid. If the entered time resolution is < 0, this vector will be empty.
"""
function generateTimeGrid( mpSim::MPsim, timeRes::Real,
    addCurrentTime::Bool = true )

    if timeRes <= 0
        @warn "Time resolution must be > 0, not generating time grid."
        return Vector{Float64}()
    end  # if timeRes <= 0

    currentTime = now( mpSim )

    if currentTime == 0
        @warn "Simulation hasn't started yet."
        return [0.0]
    end  # if currentTime == 0

    timeGrid = collect( 0:timeRes:currentTime )

    if addCurrentTime && ( timeGrid[end] < currentTime )
        push!( timeGrid, currentTime )
    end  # if timeGrid[end] < currentTime

    return timeGrid

end  # generateTimeGrid( mpSim, timeRes, addCurrentTime )

function generateTimeFork( startTime::Real, endTime::Real )

    if startTime == endTime
        return string( "timeIndex <= ", startTime )
    end  # if startTime == endTime

    return string( "timeIndex > ", startTime, " AND",
        "\n    timeIndex <= ", endTime )

end  # generateTimeFork( startTime, endTime )


text:
############################################################################################
"""
$(TYPEDEF)
Contains information about parameter distributions, transformations and constraints.

# Fields
$(TYPEDFIELDS)
"""
struct ParameterInfo{C,R<:ReConstructor,T<:TransformConstructor}
    "Constraint distribution/boundaries for all model parameter."
    constraint::C
    "Contains information for flatten/unflatten parameter"
    reconstruct::R
    "Contains information for constraining and unconstraining parameter."
    transform::T
    function ParameterInfo(
        constraint::C, val::B, flattendefault::D
    ) where {C<:NamedTuple,B<:NamedTuple,D<:FlattenDefault}
        ## Create flatten constructor
        constructor = ReConstructor(flattendefault, constraint, val)
        ## Assign transformer constraint NamedTuple
        transformer = TransformConstructor(constraint, val)
        ## Return ParameterInfo
        return new{C,typeof(constructor),typeof(transformer)}(
            constraint, constructor, transformer
        )
    end
end

############################################################################################
#export
export ParameterInfo


text:
module TestArrayCommon
using Test
using Future: copy!
using CategoricalArrays, DataAPI
using CategoricalArrays: DefaultRefType, index

const ≅ = isequal
const ≇ = !isequal

@testset "mergelevels()" begin
    # Test that mergelevels handles mutually compatible orderings
    @test CategoricalArrays.mergelevels(true, [6, 2, 4, 8], [2, 3, 5, 4], [2, 4, 8]) ==
        ([6, 2, 3, 5, 4, 8], true)
    @test CategoricalArrays.mergelevels(true, ["A", "B", "D"], ["C", "D", "E", "F"], ["B", "C", "E"]) ==
        (["A", "B", "C", "D", "E", "F"], true)
    @test CategoricalArrays.mergelevels(true, ["A", "B", "D"], ["C", "D", "E", "F"], ["A", "B", "C", "F"]) ==
        (["A", "B", "C", "D", "E", "F"], true)
    @test CategoricalArrays.mergelevels(true, ["B", "C", "D"], ["A", "B"]) ==
        (["A", "B", "C", "D"], true)
    @test CategoricalArrays.mergelevels(true, ["B", "C", "D"], []) ==
        (["B", "C", "D"], true)
    @test CategoricalArrays.mergelevels(true, [], ["A", "C"]) ==
        (["A", "C"], true)
    @test CategoricalArrays.mergelevels(true, [], []) ==
        ([], true)
    @test CategoricalArrays.mergelevels(true, ["A", "B", "C"], [], ["A", "C", "D"]) ==
        (["A", "B", "C", "D"], true)
    @test CategoricalArrays.mergelevels(true, [], ["A", "B", "C"], ["A", "C", "D"]) ==
        (["A", "B", "C", "D"], true)
    @test CategoricalArrays.mergelevels(true, ["A", "C", "D"], ["A", "B", "C"], []) ==
        (["A", "B", "C", "D"], true)
    @test CategoricalArrays.mergelevels(true, [], ["A", "C", "D"], []) ==
        (["A", "C", "D"], true)
    @test CategoricalArrays.mergelevels(true, ["A", "C", "D"], [], []) ==
        (["A", "C", "D"], true)
    @test CategoricalArrays.mergelevels(true, [], [], ["A", "C", "D"]) ==
        (["A", "C", "D"], true)
    @test CategoricalArrays.mergelevels(true, [], [], []) ==
        ([], true)
    @test CategoricalArrays.mergelevels(true, ["A", "C", "D"], ["A", "B", "C"], ["A", "D", "E"], ["C", "D"]) ==
        (["A", "B", "C", "D", "E"], true)

    # Test that mergelevels handles mutually incompatible orderings
    @test CategoricalArrays.mergelevels(true, [6, 3, 4, 7], [2, 3, 6, 5, 4], [2, 4, 8]) ==
        ([6, 2, 3, 5, 4, 7, 8], false)
    @test CategoricalArrays.mergelevels(true, ["A", "C", "D"], ["D", "C"], []) ==
        (["A", "C", "D"], false)
    @test CategoricalArrays.mergelevels(true, ["A", "D", "C"], ["A", "B", "C"], ["A", "D", "E"], ["C", "D"]) ==
        (["A", "D", "B", "C", "E"], false)

    # Test that mergelevels handles incomplete orderings
    @test CategoricalArrays.mergelevels(true, ["B", "C", "D"], ["A", "C"]) ==
        (["B", "A", "C", "D"], false)
    @test CategoricalArrays.mergelevels(true, ["A", "B", "D"], ["C", "D", "E", "F"]) ==
        (["A", "B", "C", "D", "E", "F"], false)
    @test CategoricalArrays.mergelevels(true, ["A", "B", "E", "G"], ["C", "D", "E", "F"]) ==
        (["A", "B", "C", "D", "E", "G", "F"], false)
    @test CategoricalArrays.mergelevels(true, ["A", "B", "D"], ["C", "D", "E", "F"], ["A", "B", "D", "F"]) ==
        (["A", "B", "C", "D", "E", "F"], false)

    # Test with ordered=false (simpler, almost a subset of code paths tested above)
    @test CategoricalArrays.mergelevels(false, ["A", "B", "E", "G"], ["C", "D", "E", "F"]) ==
        (["A", "B", "C", "D", "E", "G", "F"], false)
end

@testset "Testing $T" for T in (Union{}, Missing)
    @testset "vcat()" begin
        # Test that vcat of compress arrays uses a reftype that doesn't overflow
        a1 = 3:200
        a2 = 300:-1:100
        ca1 = CategoricalArray{Union{T, Int}}(a1)
        ca2 = CategoricalArray{Union{T, Int}}(a2)
        cca1 = compress(ca1)
        cca2 = compress(ca2)
        r = vcat(cca1, cca2)
        @test r == vcat(a1, a2)
        @test isa(cca1, CategoricalArray{Union{T, Int}, 1, UInt8})
        @test isa(cca2, CategoricalArray{Union{T, Int}, 1, UInt8})
        @test isa(r, CategoricalArray{Union{T, Int}, 1, CategoricalArrays.DefaultRefType})
        @test isa(vcat(cca1, ca2), CategoricalArray{Union{T, Int}, 1, CategoricalArrays.DefaultRefType})
        @test isordered(r) == false
        @test levels(r) == collect(3:300)

        # Test vcat of multidimensional arrays
        a1 = Array{Int}(undef, 2, 3, 4, 5)
        a2 = Array{Int}(undef, 3, 3, 4, 5)
        a1[1:end] = (length(a1):-1:1) .+ 2
        a2[1:end] = (1:length(a2)) .+ 10
        ca1 = CategoricalArray{Union{T, Int}}(a1)
        ca2 = CategoricalArray{Union{T, Int}}(a2)
        cca1 = compress(ca1)
        cca2 = compress(ca2)
        r = vcat(cca1, cca2)
        @test r == vcat(a1, a2)
        @test isa(r, CategoricalArray{Union{T, Int}, 4, CategoricalArrays.DefaultRefType})
        @test isordered(r) == false
        @test levels(r) == collect(3:length(a2)+10)

        # Test concatenation of mutually compatible levels
        a1 = ["Young", "Middle"]
        a2 = ["Middle", "Old"]
        ca1 = CategoricalArray{Union{T, String}}(a1, ordered=true)
        ca2 = CategoricalArray{Union{T, String}}(a2, ordered=true)
        @test levels!(ca1, ["Young", "Middle"]) === ca1
        @test levels!(ca2, ["Middle", "Old"]) === ca2
        r = vcat(ca1, ca2)
        @test r == vcat(a1, a2)
        @test levels(r) == ["Young", "Middle", "Old"]
        @test isordered(r) == true

        # Test concatenation of conflicting ordering. This drops the ordering
        a1 = ["Old", "Young", "Young"]
        a2 = ["Old", "Young", "Middle", "Young"]
        ca1 = CategoricalArray{Union{T, String}}(a1, ordered=true)
        ca2 = CategoricalArray{Union{T, String}}(a2, ordered=true)
        levels!(ca1, ["Young", "Middle", "Old"])
        # ca2 has another order
        r = vcat(ca1, ca2)
        @test r == vcat(a1, a2)
        @test levels(r) == ["Young", "Middle", "Old"]
        @test isordered(r) == false
    end

    @testset "undef constructors preserve reftype" begin
        x = CategoricalArray{Union{T, CategoricalValue{Int, UInt8}}}(undef, 3)
        @test x isa CategoricalArray{Union{T, Int}, 1, UInt8}

        x = CategoricalArray{Union{T, CategoricalValue{Int, UInt8}}, 1}(undef, 3)
        @test x isa CategoricalArray{Union{T, Int}, 1, UInt8}
    end

    @testset "similar()" begin
        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        y = similar(x)
        @test typeof(x) === typeof(y)
        @test size(y) == size(x)
        if T === Missing
            @test all(ismissing, y)
        else
            @test !any(isassigned(y, i) for i in 1:length(y))
        end

        y = similar(x, 3)
        @test typeof(x) === typeof(y)
        @test size(y) == (3,)
        if T === Missing
            @test all(ismissing, y)
        else
            @test !any(isassigned(y, i) for i in 1:length(y))
        end

        y = similar(x, Int)
        @test isa(y, Vector{Int})
        @test size(y) == size(x)

        y = similar(x, Int, 3, 2)
        @test isa(y, Matrix{Int})
        @test size(y) == (3, 2)

        x = CategoricalArray{Union{T, String}, 1, UInt8}(["Old", "Young", "Middle", "Young"])
        y = similar(x, Union{T, CategoricalValue{String}})
        @test typeof(x) === typeof(y)
        @test size(y) == size(x)
        T === Missing && @test all(ismissing, y)

        y = similar(x, Union{T, CategoricalValue{String, UInt32}})
        @test isa(y, CategoricalVector{Union{T, String}, UInt32})
        @test size(y) == size(x)
        T === Missing && @test all(ismissing, y)

        y = similar(x, Union{Missing, CategoricalValue{String}}, 3, 2)
        @test isa(y, CategoricalMatrix{Union{String, Missing}, UInt8})
        @test size(y) == (3, 2)
        @test all(ismissing, y)

        y = similar(x, CategoricalValue{String})
        @test isa(y, CategoricalVector{String, UInt8})
        @test size(y) == size(x)
        @test !any(isassigned(y, i) for i in 1:length(y))

        y = similar(x, CategoricalValue{String, UInt32})
        @test isa(y, CategoricalVector{String, UInt32})
        @test size(y) == size(x)
        @test !any(isassigned(y, i) for i in 1:length(y))

        y = similar(x, CategoricalValue{Int, UInt32})
        @test isa(y, CategoricalVector{Int, UInt32})
        @test size(y) == size(x)

        y = similar([], Union{CategoricalValue{Int}, T}, (3,))
        @test isa(y, CategoricalVector{Union{Int, T}, UInt32})
        @test size(y) == (3,)

        y = similar([], Union{CategoricalValue{String}, T}, (3,))
        @test isa(y, CategoricalVector{Union{String, T}, UInt32})
        @test size(y) == (3,)

        y = similar([], Union{CategoricalValue{Int, UInt8}, T}, (3,))
        @test isa(y, CategoricalVector{Union{Int, T}, UInt8})
        @test size(y) == (3,)

        y = similar([], Union{CategoricalValue{String, UInt8}, T}, (3,))
        @test isa(y, CategoricalVector{Union{String, T}, UInt8})
        @test size(y) == (3,)

        y = similar(Vector{Union{CategoricalValue{Int}, T}}, (3,))
        @test isa(y, CategoricalVector{Union{Int, T}, UInt32})
        @test size(y) == (3,)

        y = similar(Vector{Union{CategoricalValue{String}, T}}, (3,))
        @test isa(y, CategoricalVector{Union{String, T}, UInt32})
        @test size(y) == (3,)

        y = similar(Vector{Union{CategoricalValue{Int, UInt8}, T}}, (3,))
        @test isa(y, CategoricalVector{Union{Int, T}, UInt8})
        @test size(y) == (3,)

        y = similar(Vector{Union{CategoricalValue{String, UInt8}, T}}, (3,))
        @test isa(y, CategoricalVector{Union{String, T}, UInt8})
        @test size(y) == (3,)

        y = similar(Vector{T}, (3,))
        @test isa(y, Vector{T})
        @test size(y) == (3,)
    end

    @testset "copy" begin
        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        levels!(x, ["Young", "Middle", "Old"])
        ordered!(x, true)

        y = copy(x)
        @test y == x
        levels!(y, ["Z", "Middle", "Old", "Young"])
        y[1] = "Z"
        @test x == ["Old", "Young", "Middle", "Young"]
        @test levels(x) == ["Young", "Middle", "Old"]

        # Test with missing values
        if T === Missing
            x[3] = missing
            @test copy(x) ≅ x
        end
    end

    @testset "copy! and copyto!" begin
        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        levels!(x, ["Young", "Middle", "Old"])
        ordered!(x, true)
        y = CategoricalArray{Union{T, String}}(["X", "Z", "Y", "X"])

        for copyf! in (copy!, copyto!)
            x2 = copy(x)
            @test copyf!(x2, y) === x2
            @test x2 == y
            @test levels(x2) == ["Young", "Middle", "Old", "X", "Y", "Z"]
            @test !isordered(x2)
        end

        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        levels!(x, ["Young", "Middle", "Old"])
        ordered!(x, true)
        y = CategoricalArray{Union{T, String}}(["X", "Z", "Y", "X"])
        a = (Union{String, Missing})["Z", "Y", "X", "Young"]
        # Test with missing values
        if T === Missing
            x[3] = missing
            y[3] = a[2] = missing
        end
        @test copyto!(x, 1, y, 2) === x
        @test x ≅ a
        @test levels(x) == ["Young", "Middle", "Old", "X", "Y", "Z"]
        @test !isordered(x)

        @testset "0-length copy!/copyto! does nothing (including bounds checks)" begin
            u = x[1:0]
            v = y[1:0]

            @test copyto!(x, 1, y, 3, 0) === x
            @test x ≅ a
            @test copyto!(x, 1, y, 5, 0) === x
            @test x ≅ a

            @test copyto!(u, -5, v, 2, 0) === u
            @test u ≅ v
            @test copyto!(x, -5, v, 2, 0) === x
            @test x ≅ a
            @test copyto!(u, v) === u
            @test u ≅ v
            @test copyto!(x, v) === x
            @test x ≅ a
            @test copy!(u, v) === u
            @test u ≅ v
            @test copy!(x, v) === x
            @test x ≅ a
        end

        @testset "nonzero-length copy!/copyto! into/from empty array throws bounds error" begin
            u = x[1:0]
            v = y[1:0]

            @test_throws BoundsError copy!(u, x)
            @test u ≅ v
            @test_throws BoundsError copyto!(u, x)
            @test u ≅ v
            @test_throws BoundsError copyto!(u, 1, v, 1, 1)
            @test u ≅ v
            @test_throws BoundsError copyto!(x, 1, v, 1, 1)
            @test x ≅ a
        end

        @testset "no corruption happens in case of bounds error" begin
            @test_throws BoundsError copyto!(x, 10, y, 2)
            @test x ≅ a
            @test_throws BoundsError copyto!(x, 1, y, 10)
            @test x ≅ a
            @test_throws BoundsError copyto!(x, 10, y, 20)
            @test x ≅ a
            @test_throws BoundsError copyto!(x, 10, y, 2)
            @test x ≅ a
            @test_throws BoundsError copyto!(x, 1, y, 2, 10)
            @test x ≅ a
            @test_throws BoundsError copyto!(x, 4, y, 1, 2)
            @test x ≅ a
            @test_throws BoundsError copyto!(x, 1, y, 4, 2)
            @test x ≅ a
        end
    end

    @testset "$copyf!" for copyf! in (copy!, copyto!)
        @testset "copy src not supporting missings into dest not supporting missings" begin
            v = ["a", "b", "c"]
            src = levels!(CategoricalVector(v), reverse(v))
            dest = CategoricalVector{String}(undef, 3)
            copyf!(dest, src)
            @test dest == src
            @test levels(dest) == levels(src) == reverse(v)
        end

        @testset "copy src supporting missings into dest not supporting missings" begin
            v = ["a", "b", "c"]
            src = levels!(CategoricalVector{Union{Missing, String}}(v), reverse(v))
            dest = CategoricalVector{String}(undef, 3)
            copyf!(dest, src)
            @test dest == src
            @test levels(dest) == levels(src) == reverse(v)
        end

        @testset "copy src not supporting missings into dest supporting missings" begin
            v = ["a", "b", "c"]
            src = levels!(CategoricalVector(v), reverse(v))
            dest = CategoricalVector{Union{String, Missing}}(undef, 3)
            copyf!(dest, src)
            @test dest == src
            @test levels(dest) == levels(src) == reverse(v)
        end

        @testset "copy src supporting missings into dest supporting missings" begin
            v = ["a", "b", "c"]
            src = levels!(CategoricalVector{Union{String, Missing}}(v), reverse(v))
            dest = CategoricalVector{Union{String, Missing}}(undef, 3)
            copyf!(dest, src)
            @test dest == src
            @test levels(dest) == levels(src) == reverse(v)
        end

        @testset "copy viewed src not supporting missings into dest not supporting missings" begin
            v = ["a", "b", "c"]
            src = levels!(CategoricalVector(v), reverse(v))
            vsrc = view(src, 1:length(src))
            dest = CategoricalVector{String}(undef, 3)
            copyf!(dest, vsrc)
            @test dest == src
            @test levels(dest) == levels(src) == reverse(v)
        end

        @testset "copy viewed src supporting missings into dest not supporting missings" begin
            v = ["a", "b", "c"]
            src = levels!(CategoricalVector{Union{String, Missing}}(v), reverse(v))
            vsrc = view(src, 1:length(src))
            dest = CategoricalVector{String}(undef, 3)
            copyf!(dest, vsrc)
            @test dest == src
            @test levels(dest) == levels(src) == reverse(v)
        end

        @testset "copy viewed src not supporting missings into dest supporting missings" begin
            v = ["a", "b", "c"]
            src = levels!(CategoricalVector(v), reverse(v))
            vsrc = view(src, 1:length(src))
            dest = CategoricalVector{Union{String, Missing}}(undef, 3)
            copyf!(dest, vsrc)
            @test dest == src
            @test levels(dest) == levels(src) == reverse(v)
        end

        @testset "copy viewed src supporting missings into dest supporting missings" begin
            v = ["a", "b", "c"]
            src = levels!(CategoricalVector{Union{String, Missing}}(v), reverse(v))
            vsrc = view(src, 1:length(src))
            dest = CategoricalVector{Union{String, Missing}}(undef, 3)
            copyf!(dest, vsrc)
            @test dest == src
            @test levels(dest) == levels(src) == reverse(v)
        end

        @testset "copy a viewed subset of src into dest" begin
            v = ["a", "b", "c"]
            src = levels!(CategoricalVector(v), reverse(v))
            vsrc = view(src, 1:2)
            dest = CategoricalVector{String}(undef, 3)
            copyf!(dest, vsrc)
            @test dest[1:2] == src[1:2]
            @test levels(dest) == levels(src)

            vsrc = view(src, 1:2)
            dest = CategoricalVector{String}(undef, 2)
            copyf!(dest, vsrc)
            @test dest == src[1:2]
            @test levels(dest) == levels(src)
        end

        @testset "copy a src into viewed dest" begin
            v = ["a", "b"]
            src = levels!(CategoricalVector(v), reverse(v))
            dest = CategoricalVector{String}(["e", "f", "g"])
            vdest = view(dest, 1:2)
            copyf!(vdest, src)
            @test dest[1:2] == src[1:2]
            @test levels(dest) == levels(vdest) == ["e", "f", "g", "b", "a"]

            dest = CategoricalVector{String}(["e", "f"])
            vdest = view(dest, 1:2)
            copyf!(vdest, src)
            @test vdest == src[1:2]
            @test levels(dest) == levels(vdest) == ["e", "f", "b", "a"]
        end

        @testset "copy a src into viewed dest and breaking orderedness" begin
            v = ["a", "b"]
            src = levels!(CategoricalVector(v), reverse(v))
            dest = CategoricalVector{String}(["e", "f", "g"], ordered=true)
            vdest = view(dest, 1:2)
            res = @test_throws ArgumentError copyf!(vdest, src)
            @test res.value.msg == "cannot set ordered=false on dest SubArray as it would affect the parent. " *
                "Found when trying to set levels to $(["e", "f", "g", "b", "a"])."
            @test dest[1:2] ==  ["e", "f"]
            @test levels(dest) == levels(vdest) == ["e", "f", "g"]
            @test isordered(dest) && isordered(vdest)

            dest = CategoricalVector{String}(["e", "f"], ordered=true)
            vdest = view(dest, 1:2)
            res = @test_throws ArgumentError copyf!(vdest, src)
            @test res.value.msg == "cannot set ordered=false on dest SubArray as it would affect the parent. " *
                "Found when trying to set levels to $(["e", "f", "b", "a"])."
            @test dest == ["e", "f"]
            @test levels(dest) == levels(vdest) == ["e", "f"]
            @test isordered(dest) && isordered(vdest)
        end

        @testset "viable mixed src and dest types" begin
            v = ["a", "b", "c"]
            src = CategoricalVector{Union{eltype(v), Missing}}(v)
            levels!(src, reverse(v))
            dest = CategoricalVector{String}(undef, 3)
            copyf!(dest, src)
            @test dest == src
            @test levels(dest) == levels(src) == reverse(v)

            vsrc = view(src, 1:length(src))
            copyf!(dest, vsrc)
            @test dest == vsrc
            @test levels(dest) == levels(vsrc) == reverse(v)

            src = CategoricalVector{AbstractString}(v)
            levels!(src, reverse(v))
            dest = CategoricalVector{String}(undef, 3)
            copyf!(dest, src)
            @test dest == src
            @test levels(dest) == levels(src) == reverse(v)

            src = CategoricalVector{String}(v)
            levels!(src, reverse(v))
            dest = CategoricalVector{AbstractString}(undef, 3)
            copyf!(dest, src)
            @test dest == src
            @test levels(dest) == levels(src) == reverse(v)
        end

        @testset "inviable mixed src and dest types" begin
            v = ["a", "b", missing]
            src = CategoricalVector(v)
            dest = CategoricalVector{String}(undef, 3)
            @test_throws MissingException copyf!(dest, src)

            vsrc = view(src, 1:length(src))
            @test_throws MissingException copyf!(dest, vsrc)

            v = Integer[-1, -2, -3]
            src = CategoricalVector(v)
            dest = CategoricalVector{UInt}(undef, 3)
            @test_throws InexactError copyf!(dest, src)
        end
    end

    @testset "assigning into array with empty levels uses orderedness of source" begin
        # destination is marked as ordered when source is ordered
        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        levels!(x, ["Young", "Middle", "Old"])
        ordered!(x, true)

        for copyf! in (copyto!, copy!)
            y = CategoricalArray{Union{T, String}}(undef, 4)
            copyf!(y, x)
            @test isordered(y)
            @test levels(y) == levels(x)
            if T >: Missing
                y = CategoricalArray{Union{T, String}}(fill(missing, 4))
                copyf!(y, x)
                @test isordered(y)
                @test levels(y) == levels(x)
            end
        end

        y = CategoricalArray{Union{T, String}}(undef, 4)
        y[1] = x[1]
        @test isordered(y)
        @test levels(y) == levels(x)
        if T >: Missing
            y = CategoricalArray{Union{T, String}}(fill(missing, 4))
            y[1] = x[1]
            @test isordered(y)
            @test levels(y) == levels(x)
        end

        # destination is marked as unordered when source is unordered
        ordered!(x, false)

        for copyf! in (copyto!, copy!)
            y = CategoricalArray{Union{T, String}}(undef, 4)
            ordered!(y, true)
            copyf!(y, x)
            @test !isordered(y)
            @test levels(y) == levels(x)
            if T >: Missing
                y = CategoricalArray{Union{T, String}}(fill(missing, 4))
                ordered!(y, true)
                copyf!(y, x)
                @test !isordered(y)
                @test levels(y) == levels(x)
            end
        end

        y = CategoricalArray{Union{T, String}}(undef, 4)
        y[1] = x[1]
        @test !isordered(y)
        @test levels(y) == levels(x)
        if T >: Missing
            y = CategoricalArray{Union{T, String}}(fill(missing, 4))
            y[1] = x[1]
            @test !isordered(y)
            @test levels(y) == levels(x)
        end
    end

    @testset "resize!()" begin
        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        @test resize!(x, 3) === x
        @test x == ["Old", "Young", "Middle"]
        @test resize!(x, 4) === x
        if T === Missing
            @test x ≅ ["Old", "Young", "Middle", missing]
        else
            @test x[1:3] == ["Old", "Young", "Middle"]
            @test !isassigned(x, 4)
        end
    end

    @testset "$copyf! and conflicting orders sstart=$sstart dstart=$dstart n=$n" for
        (sstart, dstart, n) in ((1, 1, 4), (1, 2, 3)),
        copyf! in (copy!, copyto!)
        # Conflicting orders: check that the destination wins and that result is not ordered
        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        levels!(x, ["Young", "Middle", "Old"])
        ordered!(x, true)
        y = CategoricalArray{Union{T, String}}(["Middle", "Middle", "Old", "Young"])
        levels!(y, ["Old", "Middle", "Young"])
        ordered!(x, true)
        @test copyf!(x, y) === x
        @test levels(x) == ["Young", "Middle", "Old"]
        @test !isordered(x)

        # Destination ordered, but not origin: check that destination wins
        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        levels!(x, ["Young", "Middle", "Old"])
        ordered!(x, true)
        y = CategoricalArray{Union{T, String}}(["Middle", "Middle", "Old", "Young"])
        levels!(y, ["Young", "Middle", "Old"])
        @test copyf!(x, y) === x
        @test levels(x) == ["Young", "Middle", "Old"]
        @test isordered(x)

        # Origin ordered, but not destination: check that destination wins
        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        levels!(x, ["Young", "Middle", "Old"])
        y = CategoricalArray{Union{T, String}}(["Middle", "Middle", "Old", "Young"])
        ordered!(y, true)
        levels!(y, ["Young", "Middle", "Old"])
        @test copyf!(x, y) === x
        @test levels(x) == ["Young", "Middle", "Old"]
        @test !isordered(x)

        # Origin ordered, destination ordered with no levels: check that result is ordered
        y = CategoricalArray{Union{T, String}}(["Middle", "Middle", "Old", "Young"])
        ordered!(y, true)
        levels!(y, ["Young", "Middle", "Old"])
        x = similar(x)
        ordered!(x, true)
        @test copyf!(x, y) === x
        @test levels(x) == ["Young", "Middle", "Old"]
        @test isordered(x)

        # Destination ordered, but not origin, and new levels: check that result is unordered
        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        levels!(x, ["Young", "Middle", "Old"])
        ordered!(x, true)
        y = CategoricalArray{Union{T, String}}(["Middle", "Middle", "Old", "Young"])
        levels!(y, ["X", "Young", "Middle", "Old"])
        @test copyf!(x, y) === x
        @test levels(x) == ["X", "Young", "Middle", "Old"]
        @test !isordered(x)
    end

    @testset "fill!()" begin
        x = CategoricalArray{Union{String, T}}(["a", "b", "c"])
        x2 = copy(x)
        @test fill!(x2, "a") === x2
        @test x2 == ["a", "a", "a"]
        @test levels(x2) == ["a", "b", "c"]

        @test fill!(x2, x[2]) == ["b", "b", "b"]
        @test levels(x2) == ["a", "b", "c"]

        x2 = copy(x)
        @test_throws MethodError fill!(x2, 3)
        @test x2 == x

        if T === Missing
            x2 = fill!(copy(x), missing)
            @test all(ismissing, x2)
        else
            @test_throws MethodError fill!(x2, missing)
            @test x2 == x
        end

        fill!(x2, "c")
        @test x2 == ["c", "c", "c"]
        @test levels(x2) == ["a", "b", "c"]

        fill!(x2, "0")
        @test x2 == ["0", "0", "0"]
        @test levels(x2) == ["a", "b", "c", "0"]

        y = categorical(["d", "e"])
        ordered!(y, true)
        levels!(y, ["0", "e", "d"])
        fill!(x2, y[1])
        @test x2 == ["d", "d", "d"]
        @test levels(x2) == ["a", "b", "c", "0", "e", "d"]

        x3 = similar(x2)
        fill!(x3, y[1])
        @test x3 == ["d", "d", "d"]
        @test levels(x3) == ["0", "e", "d"]
        @test isordered(x3)
    end

    @testset "overflow of reftype is detected and doesn't corrupt data and levels" begin
        res = @test_throws LevelsException{Int, UInt8} CategoricalArray{Union{T, Int}, 1, UInt8}(256:-1:1)
        @test res.value.levels == [1]
        @test sprint(showerror, res.value) == "cannot store level(s) 1 since reference type UInt8 can only hold 255 levels. Use the decompress function to make room for more levels."

        x = CategoricalArray{Union{T, Int}, 1, UInt8}(254:-1:1)
        x[1] = 1000
        res = @test_throws LevelsException{Int, UInt8} x[1] = 1001
        @test res.value.levels == [1001]
        @test sprint(showerror, res.value) == "cannot store level(s) 1001 since reference type UInt8 can only hold 255 levels. Use the decompress function to make room for more levels."
        @test x == vcat(1000, 253:-1:1)
        @test levels(x) == vcat(1:254, 1000)

        x = CategoricalArray{Union{T, Int}, 1, UInt8}(1:254)
        res = @test_throws LevelsException{Int, UInt8} x[1:2] = 1000:1001
        @test res.value.levels == [1001]
        @test sprint(showerror, res.value) == "cannot store level(s) 1001 since reference type UInt8 can only hold 255 levels. Use the decompress function to make room for more levels."
        @test x == vcat(1000, 2:254)
        @test levels(x) == vcat(1:254, 1000)

        x = CategoricalArray{Union{T, Int}, 1, UInt8}([1, 3, 256])
        res = @test_throws LevelsException{Int, UInt8} levels!(x, collect(1:256))
        @test res.value.levels == [255]
        @test sprint(showerror, res.value) == "cannot store level(s) 255 since reference type UInt8 can only hold 255 levels. Use the decompress function to make room for more levels."

        x = CategoricalArray{Union{T, Int}}(30:2:131115)
        res = @test_throws LevelsException{Int, UInt16} CategoricalVector{Int, UInt16}(x)
        @test res.value.levels == collect(131100:2:131114)
        @test sprint(showerror, res.value) == "cannot store level(s) 131100, 131102, 131104, 131106, 131108, 131110, 131112 and 131114 since reference type UInt16 can only hold 65535 levels. Use the decompress function to make room for more levels."

        x = CategoricalArray{Union{T, String}, 1, UInt8}(string.(Char.(65:318)))
        res = @test_throws LevelsException{String, UInt8} levels!(x, vcat(levels(x), "az", "bz", "cz"))
        @test res.value.levels == ["bz", "cz"]
        @test sprint(showerror, res.value) == "cannot store level(s) \"bz\" and \"cz\" since reference type UInt8 can only hold 255 levels. Use the decompress function to make room for more levels."
        @test x == string.(Char.(65:318))
        lev = copy(levels(x))
        levels!(x, vcat(lev, "az"))
        @test levels(x) == vcat(lev, "az")
    end

    @testset "compress()/decompress()" begin
        x = compress(CategoricalArray{Union{T, Int}}([1, 3, 736251]))
        ux = decompress(x)
        @test x == ux
        @test isa(x, CategoricalArray{Union{T, Int}, 1, UInt8})
        @test isa(ux, CategoricalArray{Union{T, Int}, 1, CategoricalArrays.DefaultRefType})
    end

    @testset "reshape()" begin
        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        levels!(x, ["Young", "Middle", "Old"])
        ordered!(x, true)

        y = reshape(x, 1, 4)
        @test isa(y, CategoricalArray{Union{T, String}, 2, CategoricalArrays.DefaultRefType})
        @test y == ["Old" "Young" "Middle" "Young"]
        @test levels(x) == levels(y)
        @test isordered(x)

        y = reshape(x, 2, 2)
        @test isa(y, CategoricalArray{Union{T, String}, 2, CategoricalArrays.DefaultRefType})
        @test y == ["Old"  "Middle"; "Young" "Young"]
        @test levels(x) == levels(y)
        @test isordered(x)

        # Test with missing values
        if T === Missing
            x[3] = missing
            y = reshape(x, 1, 4)
            @test isa(y, CategoricalArray{Union{T, String}, 2, CategoricalArrays.DefaultRefType})
            @test y ≅ ["Old" "Young" missing "Young"]
            @test levels(x) == levels(y)
            @test isordered(x)
        end
    end

    @testset "sort" begin
        x = CategoricalArray{Union{T, String}}(["Old", "Young", "Middle", "Young"])
        levels!(x, ["Young", "Middle", "Old"])
        @test sort(x) == ["Young", "Young", "Middle", "Old"]
        ordered!(x, true)
        @test sort(x) == ["Young", "Young", "Middle", "Old"]
        @test sort!(x) === x
        @test x == ["Young", "Young", "Middle", "Old"]

        if T === Missing
            v = rand(["a", "b", "c", "d"], 1000)
        else
            v = rand(["a", "b", "c", "d", missing], 1000)
        end

        for rev in (true, false)
            cv = categorical(v)
            sv = sort(v, rev=rev)

            @test sort(cv, rev=rev) ≅ sv
            @test sort!(cv, rev=rev) === cv ≅ sv

            cv = categorical(v)
            levels!(cv, ["b", "a", "c", "d"])
            @test sort(cv, rev=rev) ≅
                [levels(cv); missing][sort([5; CategoricalArrays.order(cv.pool)][cv.refs .+ 1], rev=rev)]

            cv = categorical(v)
            @test sort(cv, rev=rev, lt=(x, y) -> isless(y, x)) ≅
                sort(cv, rev=!rev) ≅
                sort(cv, order=Base.Sort.ord((x, y) -> isless(y, x), identity, rev))

            # Function changing order
            byf1 = x -> ismissing(x) ? "c" : (x == "a" ? "z" : "b")
            @test sort(cv, rev=rev, by=byf1) ≅ sort(cv, rev=rev, by=byf1)

            # Check that by function is not called on unused levels/missing
            byf2 = x -> (@assert get(x) != "b"; x)
            replace!(cv, missing=>"a", "b"=>"a")
            @test sort(cv, rev=rev, by=byf2) ≅ sort(cv, rev=rev, by=byf2)
        end
    end
end

@testset "constructors and convert() between categorical arrays, ordered_orig=$ordered_orig, ordered=$ordered, R=$R, T=$T, CVM2=$CVM2, N=$N" for ordered_orig in (true, false),
    ordered in (true, false),
    R in (DefaultRefType, UInt8, UInt, Int8, Int),
    T in (String, Union{String, Missing}),
    (CVM2, N) in ((CategoricalVector, 1), (CategoricalMatrix, 2))
    # check that ctors/converters preserve levels and ordering by default even across types,
    # do not modify original array when changing ordering, and make copies
    # only when necessary (though for construcors the pool is always copied because of ordered)
    if CVM2 <: AbstractVector
        x = CategoricalArray{T, N, R}(["A", "B"], ordered=ordered_orig)
    else
        x = CategoricalArray{T, N, R}(["A" "B"], ordered=ordered_orig)
    end

    # Do not use lexicographic order in order to catch bugs about order preservation
    levels!(x, ["B", "A"])

    for y in (CategoricalArray(x),
              CategoricalArray{T}(x),
              CategoricalArray{T, N}(x),
              CategoricalArray{T, N, R}(x),
              CategoricalArray{T, N, DefaultRefType}(x),
              CategoricalArray{T, N, UInt8}(x),
              CVM2(x),
              CVM2{T}(x),
              CVM2{T, R}(x),
              CVM2{T, DefaultRefType}(x),
              CVM2{T, UInt8}(x))
        @test isa(y, CVM2{T})
        @test isordered(y) === isordered(x)
        @test isordered(x) === ordered_orig
        @test y.refs == x.refs
        @test index(y.pool) == index(x.pool)
        @test levels(y) == levels(x)
        @test y.refs !== x.refs
        @test y.pool !== x.pool
    end
    for y in (categorical(x),
              categorical(x, false),
              categorical(x, true))
        @test isa(y, CategoricalArray{T, N})
        @test isordered(y) === isordered(x)
        @test isordered(x) === ordered_orig
        @test y.refs == x.refs
        @test index(y.pool) == index(x.pool)
        @test levels(y) == levels(x)
        @test y.refs !== x.refs
        @test y.pool !== x.pool
    end
    for y in (CategoricalArray(x, ordered=ordered),
              CategoricalArray{T}(x, ordered=ordered),
              CategoricalArray{T, N}(x, ordered=ordered),
              CategoricalArray{T, N, R}(x, ordered=ordered),
              CategoricalArray{T, N, DefaultRefType}(x, ordered=ordered),
              CategoricalArray{T, N, UInt8}(x, ordered=ordered),
              CVM2(x, ordered=ordered),
              CVM2{T}(x, ordered=ordered),
              CVM2{T, R}(x, ordered=ordered),
              CVM2{T, DefaultRefType}(x, ordered=ordered),
              CVM2{T, UInt8}(x, ordered=ordered))
        @test isa(y, CVM2{T})
        @test isordered(y) === ordered
        @test isordered(x) === ordered_orig
        @test y.refs == x.refs
        @test index(y.pool) == index(x.pool)
        @test levels(y) == levels(x)
        @test y.refs !== x.refs
        @test y.pool !== x.pool
    end
    for y in (categorical(x, ordered=ordered),
              categorical(x, false, ordered=ordered),
              categorical(x, true, ordered=ordered))
        @test isa(y, CategoricalArray{T, N})
        @test isordered(y) === ordered
        @test isordered(x) === ordered_orig
        @test y.refs == x.refs
        @test index(y.pool) == index(x.pool)
        @test levels(y) == levels(x)
        @test y.refs !== x.refs
        @test y.pool !== x.pool
    end
    for y in (convert(CategoricalArray, x),
              convert(CategoricalArray{T}, x),
              convert(CategoricalArray{T, N}, x),
              convert(CategoricalArray{T, N, R}, x),
              convert(CategoricalArray{T, N, DefaultRefType}, x),
              convert(CategoricalArray{T, N, UInt8}, x))
        @test isa(y, CVM2{T})
        @test isordered(y) === isordered(x)
        @test isordered(x) === ordered_orig
        @test y.refs == x.refs
        @test index(y.pool) == index(x.pool)
        @test levels(y) == levels(x)
        @test (y.refs === x.refs) == (eltype(x.refs) === eltype(y.refs))
        @test (y.pool === x.pool) == (eltype(x.refs) === eltype(y.refs))
    end
end

@testset "converting from array with missings to array without missings CategoricalArray fails with missings" begin
    x = CategoricalArray{Union{String, Missing}}(undef, 1)
    @test_throws MissingException CategoricalArray{String}(x)
    @test_throws MissingException convert(CategoricalArray{String}, x)
end

@testset "in($T, CategoricalArray{$T})" for T in (Int, Union{Int, Missing})
    ca1 = CategoricalArray{T}([1, 2, 3])
    ca2 = CategoricalArray{T}([4, 3, 2])

    @test (ca1[1] in ca1) === true
    @test (ca2[2] in ca1) === true
    @test (ca2[1] in ca1) === false

    @test (1 in ca1) === true
    @test (5 in ca1) === false
end

@testset "comparison" begin
    a1 = [1, 2, 3]
    a2 = Union{Int, Missing}[1, 2, 3]
    a3 = [1, 2, missing]
    a4 = [4, 3, 2]
    a5 = [1 2; 3 4]
    ca1 = CategoricalArray(a1)
    ca2 = CategoricalArray{Union{Int, Missing}}(a2)
    ca2b = CategoricalArray{Union{Int, Missing}, 1}(ca2.refs, ca2.pool)
    ca3 = CategoricalArray(a3)
    ca3b = CategoricalArray{Union{Int, Missing}, 1}(ca3.refs, ca2.pool)
    ca4 = CategoricalArray(a4)
    ca5 = CategoricalArray(a5)

    @testset "==" begin
        @test ca1 == copy(ca1) == a1
        @test ca2 == copy(ca2) == a2
        @test ismissing(ca3 == copy(ca3)) && ismissing(ca3 == ca3b) && ismissing(ca3 == a3)
        @test ca4 == copy(ca4) == a4
        @test ca5 == copy(ca5) == a5
        @test ca1 == ca2 == a2
        @test ismissing(ca1 != ca3) && ismissing(ca1 != a3)
        @test ca1 != ca4
        @test ca1 != a4
        @test a1 != ca4
        @test ca1 != ca5
        @test ca1 != a5
        @test a1 != ca5
        @test ca3 != ca4
        @test ca3 != a4
        @test a3 != ca4
        @test ismissing(ca2b != ca3b)
    end

    @testset "isequal()" begin
        @test ca1 ≅ copy(ca1) ≅ a1
        @test ca2 ≅ copy(ca2) ≅ a2
        @test ca3 ≅ copy(ca3) ≅ ca3b ≅ a3
        @test ca4 ≅ copy(ca4) ≅ a4
        @test ca5 ≅ copy(ca5) ≅ a5
        @test ca1 ≅ ca2 ≅ a2
        @test ca1 ≇ ca3 && ca1 ≇ a3
        @test ca1 ≇ ca4
        @test ca1 ≇ a4
        @test a1 ≇ ca4
        @test ca1 ≇ ca5
        @test ca1 ≇ a5
        @test a1 ≇ ca5
        @test ca3 ≇ ca4
        @test ca3 ≇ a4
        @test a3 ≇ ca4
        @test ca2b ≇ ca3b
    end
end

@testset "summary()" begin
    @test summary(CategoricalArray([1, 2, 3])) ==
        "3-element $CategoricalArray{$Int,1,UInt32}"
    @test summary(CategoricalArray{Union{Int, Missing}}([1 2 3])) ==
        "1×3 $CategoricalArray{$(Union{Missing, Int}),2,UInt32}"
end

@testset "vcat() takes into account element type even when array is empty" begin
    # or when both arrays have the same levels but of different types
    x = CategoricalVector{String}(undef, 0)
    y = CategoricalVector{Int}(undef, 0)
    z1 = CategoricalVector{Float64}([1.0])
    z2 = CategoricalVector{Int}([1])
    if VERSION > v"1.2.0-DEV"
        @inferred vcat(x, y)
    end
    @test vcat(x, y) isa CategoricalVector{Any}
    if VERSION > v"1.2.0-DEV"
        @inferred vcat(x, z1)
    end
    @test vcat(x, z1) isa CategoricalVector{Any}
    if VERSION > v"1.2.0-DEV"
        @inferred vcat(y, z1)
    end
    @test vcat(y, z1) isa CategoricalVector{Float64}
    if VERSION > v"1.2.0-DEV"
        @inferred vcat(x, x)
    end
    @test vcat(x, x) isa CategoricalVector{String}
    if VERSION > v"1.2.0-DEV"
        @inferred vcat(y, y)
    end
    @test vcat(y, y) isa CategoricalVector{Int}
    if VERSION > v"1.2.0-DEV"
        @inferred vcat(z1, z1)
    end
    @test vcat(z1, z1) isa CategoricalVector{Float64}
    if VERSION > v"1.2.0-DEV"
        @inferred vcat(z1, z2)
    end
    @test vcat(z1, z2) isa CategoricalVector{Float64}
end

@testset "categorical() makes a copy of pool and refs" begin
    xs = Any[Int8[1:10;], [Int8[1:10;]; missing]]
    for x in xs, o1 in [true, false], o2 in [true, false], T in [Int64, Int8]
        y = categorical(x, ordered=o1)
        if x === xs[1]
            z = CategoricalArray{T}(y, ordered=o2)
        else
            z = CategoricalArray{Union{T, Missing}}(y, ordered=o2)
        end
        @test z.refs !== y.refs
        @test z.pool !== y.pool
    end
end

@testset "collect of CategoricalArray produces Array" begin
    x = [1,1,2,2]
    y = categorical(x)
    z = collect(y)
    @test typeof(x) == typeof(z)
    @test z == x

    x = [1,1,2,missing]
    y = categorical(x)
    z = collect(y)
    @test typeof(x) == typeof(z)
    @test z ≅ x
end

@testset "Array(::CategoricalArray{T}) produces Array{T}" begin
    x = [1,1,2,2]
    y = categorical(x)
    z = Array(y)
    @test typeof(x) == typeof(z)
    @test z == x

    x = [1,1,2,missing]
    y = categorical(x)
    z = Array(y)
    @test typeof(x) == typeof(z)
    @test z ≅ x
end

@testset "Array{T} constructors and convert" begin
    x = [1,1,2,2]
    y = categorical(x)
    z = Array{Int}(y)
    @test typeof(x) == typeof(z)
    @test z == x
    z = convert(Array{Int}, y)
    @test typeof(x) == typeof(z)
    @test z == x

    x = [1,1,2,missing]
    y = categorical(x)
    z = Array{Union{Int, Missing}}(y)
    @test typeof(x) == typeof(z)
    @test z ≅ x
    z = convert(Array{Union{Int, Missing}}, y)
    @test typeof(x) == typeof(z)
    @test z ≅ x
end

@testset "convert(AbstractArray{T}, x)" begin
    x = [1,1,2,2]
    y = categorical(x)
    z = convert(AbstractArray{Int}, y)
    @test typeof(x) == typeof(z)
    @test z == x

    x = [1,1,2,missing]
    y = categorical(x)
    z = convert(AbstractArray{Union{Int, Missing}}, y)
    @test typeof(x) == typeof(z)
    @test z ≅ x

    # Check that convert is a no-op when appropriate
    for x in (categorical([1,1,2,2]), categorical([1,1,2,missing]))
        y = convert(AbstractArray, x)
        @test x === y
        y = convert(AbstractVector, x)
        @test x === y
        y = convert(AbstractArray{eltype(x)}, x)
        @test x === y
        y = convert(AbstractArray{eltype(x), 1}, x)
        @test x === y
    end
end

@testset "new levels can't be added through assignment when levels are ordered" begin
    x = categorical([1,2,3])
    ordered!(x, true)
    lev = copy(levels(x))
    res = @test_throws OrderedLevelsException{Int, Float64} x[1] = 4.0
    @test res.value.newlevel == 4
    @test sprint(showerror, res.value) ==
        "cannot add new level 4.0 since ordered pools cannot be extended implicitly. " *
        "Use the levels! function to set new levels, or the ordered! function to mark the pool as unordered."
    @test lev == levels(x)

    # Assignment works after adding the level to the pool
    levels!(x, [3,4,1,2])
    x[1] = 4
    @test x == [4,2,3]
end

@testset "float() and complex()" begin
    x = categorical([1,2,3])
    @test float(x) == x
    @test float(x) isa Vector{Float64}

    x = categorical([1,2,3])
    @test complex(x) == x
    @test complex(x) isa Vector{Complex{Int}}

    @test_throws ErrorException float(categorical(Union{Int,Missing}[1]))
    @test_throws ErrorException complex(categorical(Union{Int,Missing}[1]))
end

@testset "droplevels" for a in (["a", "b", "c"], ["a", "b", missing, "c"])
    x = categorical(a)
    levels!(x, ["b", "c", "a"])
    @test droplevels!(x) === x
    @test levels(x) == ["b", "c", "a"]
    x[2] = "a"
    @test droplevels!(x) === x
    @test levels(x) == ["c", "a"]
end

@testset "show" begin
    x = categorical([2, 1])
    @test sprint((io,a)->show(io, "text/plain", a), x) ==
        """
        2-element $CategoricalArray{$Int,1,UInt32}:
         2
         1"""

    x = categorical([2, 1, missing])
    if VERSION >= v"1.4-DEV"
        @test sprint((io,a)->show(io, "text/plain", a), x) ==
            """
            3-element $CategoricalArray{$(Union{Missing,Int}),1,UInt32}:
             2
             1
             missing"""
    else
        @test sprint((io,a)->show(io, "text/plain", a), x) ==
            """
            3-element $CategoricalArray{$(Union{Missing,Int}),1,UInt32}:
             2
             1
             missing"""
    end
end

@testset "broadcast" for x in (CategoricalArray(1:3),
                               CategoricalArray{Union{Int,Missing}}(1:3),
                               CategoricalArray(["a", "b", "c"]),
                               CategoricalArray(["a", missing, "c"]),
                               CategoricalArray([missing, "b", "c"]))
    y = identity.(x)
    @test x ≅ y
    @test x !== y
    @test y isa CategoricalArray

    y = broadcast(v->v, x)
    @test x ≅ y
    @test x !== y
    @test y isa CategoricalArray

    y = broadcast(v->x[3], x)
    @test x !== y
    @test y isa CategoricalArray

    y = broadcast(v->1, x)
    @test y == [1, 1, 1]
    @test y isa Vector{Int}

    x[1:2] .= x[3]
    @test x == fill(x[3], 3)
end

@testset "append! ordered=$ordered" for ordered in (false, true)
    @testset "append! String" begin
        a = ["a", "b", "c"]
        x = CategoricalVector{String}(a, ordered=ordered)

        append!(x, x)
        @test length(x) == 6
        @test x == ["a", "b", "c", "a", "b", "c"]
        @test isordered(x) === ordered
        @test levels(x) == ["a", "b", "c"]

        b = ["z","y","x"]
        y = CategoricalVector{String}(b)
        append!(x, y)
        @test isordered(x) === ordered
        @test length(x) == 9
        @test x == ["a", "b", "c", "a", "b", "c", "z", "y", "x"]
        @test levels(x) == ["a", "b", "c", "x", "y", "z"]

        z1 = view(CategoricalVector{String}(["ex1", "ex2"]), 1)
        z2 = view(CategoricalVector{String}(["ex3", "ex4"]), 1:1)
        append!(x, z1)
        append!(x, z2)
        @test isordered(x) === ordered
        @test length(x) == 11
        @test x == ["a", "b", "c", "a", "b", "c", "z", "y", "x", "ex1", "ex3"]
        @test levels(x) == ["a", "b", "c", "x", "y", "z", "ex1", "ex2", "ex3", "ex4"]
    end

    @testset "append! Float64" begin
        a = [-1.0, 0.0, 1.0]
        x = CategoricalVector{Float64}(a, ordered=ordered)

        append!(x, x)
        @test length(x) == 6
        @test x == [-1.0, 0.0, 1.0, -1.0, 0.0, 1.0]
        @test isordered(x) === ordered
        @test levels(x) == [-1.0, 0.0, 1.0]

        b = [2.5, 3.0, 3.5]
        y = CategoricalVector{Float64}(b, ordered=ordered)
        append!(x, y)
        @test length(x) == 9
        @test x == [-1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 2.5, 3.0, 3.5]
        @test isordered(x) === ordered
        @test levels(x) == [-1.0, 0.0, 1.0, 2.5, 3.0, 3.5]

        z1 = view(CategoricalVector{Float64}([100.0, 101.0]), 1)
        z2 = view(CategoricalVector{Float64}([102.0, 103.0]), 1:1)
        append!(x, z1)
        append!(x, z2)
        @test length(x) == 11
        @test x == [-1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 2.5, 3.0, 3.5, 100.0, 102.0]
        @test isordered(x) === ordered
        @test levels(x) == [-1.0, 0.0, 1.0, 2.5, 3.0, 3.5, 100.0, 101.0, 102.0, 103.0]
    end
end

@testset "append! ordered=$ordered" for ordered in (false, true)
    cases = (["b", "a", missing], Union{String, Missing}["b", "a", "b"])
    @testset "String, has missing: $(any(ismissing.(a)))" for a in cases
        x = CategoricalVector{Union{String, Missing}}(a, ordered=ordered)

        append!(x, x)
        @test x ≅ [a; a]
        @test levels(x) == ["a", "b"]
        @test isordered(x) === ordered
        @test length(x) == 6

        b = ["x","y",missing]
        y = CategoricalVector{Union{String, Missing}}(b)
        append!(x, y)
        @test length(x) == 9
        @test isordered(x) === ordered
        @test levels(x) == ["a", "b", "x", "y"]
        @test x ≅ [a; a; b]
        z1 = view(CategoricalVector{Union{String, Missing}}([missing, "ex2"]), 1)
        z2 = view(CategoricalVector{Union{String, Missing}}(["ex3", "ex4"]), 1:1)
        append!(x, z1)
        append!(x, z2)
        @test length(x) == 11
        @test isordered(x) === ordered
        @test levels(x) == ["a", "b", "x", "y", "ex2", "ex3", "ex4"]
        @test x ≅ [a; a; b; missing; "ex3"]
    end

    @testset "Float64" begin
        a = 0.0:0.5:1.0
        x = CategoricalVector{Union{Float64, Missing}}(a, ordered=ordered)

        append!(x, x)
        @test length(x) == 6
        @test x == [a; a]
        @test isordered(x) === ordered
        @test levels(x) == [0.0,  0.5,  1.0]

        b = [2.5, 3.0, missing]
        y = CategoricalVector{Union{Float64, Missing}}(b)
        append!(x, y)
        @test length(x) == 9
        @test x ≅ [a; a; b]
        @test isordered(x) === ordered
        @test levels(x) == [0.0, 0.5, 1.0, 2.5, 3.0]
        z1 = view(CategoricalVector{Union{Float64, Missing}}([missing, 101.0]), 1)
        z2 = view(CategoricalVector{Union{Float64, Missing}}([102.0, 103.0]), 1:1)
        append!(x, z1)
        append!(x, z2)
        @test length(x) == 11
        @test x ≅ [a; a; b; missing; 102.0]
        @test isordered(x) === ordered
        @test levels(x) == [0.0, 0.5, 1.0, 2.5, 3.0, 101.0, 102.0, 103.0]
    end
end

@testset "deleteat!" begin
    x = ['a':'z';]
    y = categorical(x)
    deleteat!(x, [1, 3])
    deleteat!(y, [1, 3])
    @test x == y
    @test levels(y) == 'a':'z'
end

@testset "DataAPI" begin
    @test DataAPI.defaultarray(CategoricalValue{String, UInt32}, 1) <: CategoricalArray{String,1,UInt32}
    @test DataAPI.defaultarray(Union{Missing, CategoricalValue{String, UInt32}}, 1) <: CategoricalArray{Union{Missing, String},1,UInt32}
    @test DataAPI.defaultarray(CategoricalValue{Int, UInt32}, 1) <: CategoricalArray{Int,1,UInt32}
    @test DataAPI.defaultarray(Union{Missing, CategoricalValue{Int, UInt32}}, 1) <: CategoricalArray{Union{Missing, Int},1,UInt32}
end

@testset "optimized broadcasting with ismissing" begin
    x = categorical([1, missing, 3, 4, missing])
    @test ismissing.(x) == [false, true, false, false, true]
    @test ismissing.(view(x, 2:4)) == [true, false, false]
    @test (!ismissing).(x) == [true, false, true, true, false]
    @test (!ismissing).(view(x, 2:4)) == [false, true, true]

    x = categorical([1, 0, 3, 4, 0])
    @test ismissing.(x) == [false, false, false, false, false]
    @test ismissing.(view(x, 2:4)) == [false, false, false]
    @test (!ismissing).(x) == [true, true, true, true, true]
    @test (!ismissing).(view(x, 2:4)) == [true, true, true]
end

@testset "optimized broadcasting with levelcode" begin
    x = categorical([3, missing, 1, 4, missing])
    levels!(x, [4, 1, 3])
    @test levelcode.(x) ≅ [3, missing, 2, 1, missing]
    @test levelcode.(x) isa Vector{Union{Missing,Int64}}

    replace!(x, missing=>1)
    @test levelcode.(x) ≅ [3, 2, 2, 1, 2]
    @test levelcode.(x) isa Vector{Int64}

    x = CategoricalVector{Int,UInt8}([3, 0, 1, 4, 0])
    levels!(x, [4, 1, 3, 0])
    @test levelcode.(x) ≅ [3, 4, 2, 1, 4]
    @test levelcode.(x) isa Vector{Int16}

    x = CategoricalVector{Union{Missing,Int},UInt8}([3, missing, 1, 4, missing])
    levels!(x, [4, 1, 3])
    @test levelcode.(x) ≅ [3, missing, 2, 1, missing]
    @test levelcode.(x) isa Vector{Union{Missing,Int16}}
end

end


text:
module Terminals

export
    TextTerminal,
    UnixTerminal,
    cmove,
    cmove_col,
    cmove_down,
    cmove_left,
    cmove_line_down,
    cmove_line_up,
    cmove_right,
    cmove_up,
    disable_bracketed_paste,
    enable_bracketed_paste,
    getX,
    getY,
    hascolor,
    pos,
    writepos

import Base: flush,
    read,
    readuntil,
    size,
    start_reading,
    stop_reading,
    write,
    writemime

immutable Size
    width
    height
end

## TextTerminal ##

abstract TextTerminal <: Base.IO

# INTERFACE
size(::TextTerminal) = error("Unimplemented")
writepos(t::TextTerminal, x, y, s::Array{Uint8,1}) = error("Unimplemented")
cmove(t::TextTerminal, x, y) = error("Unimplemented")
getX(t::TextTerminal) = error("Unimplemented")
getY(t::TextTerminal) = error("Unimplemented")
pos(t::TextTerminal) = (getX(t), getY(t))

# Relative moves (Absolute position fallbacks)
cmove_up(t::TextTerminal, n) = cmove(getX(t), max(1, getY(t)-n))
cmove_up(t) = cmove_up(t, 1)

cmove_down(t::TextTerminal, n) = cmove(getX(t), max(height(t), getY(t)+n))
cmove_down(t) = cmove_down(t, 1)

cmove_left(t::TextTerminal, n) = cmove(max(1, getX(t)-n), getY(t))
cmove_left(t) = cmove_left(t, 1)

cmove_right(t::TextTerminal, n) = cmove(max(width(t), getX(t)+n), getY(t))
cmove_right(t) = cmove_right(t, 1)

cmove_line_up(t::TextTerminal, n) = cmove(1, max(1, getY(t)-n))
cmove_line_up(t) = cmove_line_up(t, 1)

cmove_line_down(t::TextTerminal, n) = cmove(1, max(height(t), getY(t)+n))
cmove_line_down(t) = cmove_line_down(t, 1)

cmove_col(t::TextTerminal, c) = cmove(c, getY(t))

# Defaults
hascolor(::TextTerminal) = false

# Utility Functions
function writepos{T}(t::TextTerminal, x, y, b::Array{T})
    if isbits(T)
        writepos(t, x, y, reinterpret(Uint8, b))
    else
        cmove(t, x, y)
        invoke(write, (IO, Array), s, a)
    end
end
function writepos(t::TextTerminal, x, y, args...)
    cmove(t, x, y)
    write(t, args...)
end
width(t::TextTerminal) = size(t).width
height(t::TextTerminal) = size(t).height

# For terminals with buffers
flush(t::TextTerminal) = nothing

clear(t::TextTerminal) = error("Unimplemented")
clear_line(t::TextTerminal, row) = error("Unimplemented")
clear_line(t::TextTerminal) = error("Unimplemented")

raw!(t::TextTerminal, raw::Bool) = error("Unimplemented")

beep(t::TextTerminal) = nothing
enable_bracketed_paste(t::TextTerminal) = nothing
disable_bracketed_paste(t::TextTerminal) = nothing

## UnixTerminal ##

type UnixTerminal <: TextTerminal
    term_type::ASCIIString
    in_stream::Base.TTY
    out_stream::Base.TTY
    err_stream::Base.TTY
end

const CSI = "\x1b["

cmove_up(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)A")
cmove_down(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)B")
cmove_right(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)C")
cmove_left(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)D")
cmove_line_up(t::UnixTerminal, n) = (cmove_up(t, n); cmove_col(t, 0))
cmove_line_down(t::UnixTerminal, n) = (cmove_down(t, n); cmove_col(t, 0))
cmove_col(t::UnixTerminal, n) = write(t.out_stream, "$(CSI)$(n)G")

raw!(t::UnixTerminal, raw::Bool) = ccall((@windows ? :jl_tty_set_mode : :uv_tty_set_mode),
                                         Int32, (Ptr{Void},Int32),
                                         t.in_stream.handle, raw ? 1 : 0) != -1
enable_bracketed_paste(t::UnixTerminal) = write(t.out_stream, "$(CSI)?2004h")
disable_bracketed_paste(t::UnixTerminal) = write(t.out_stream, "$(CSI)?2004l")

function size(t::UnixTerminal)
    s = Array(Int32, 2)
    Base.uv_error("size (TTY)", ccall((@windows ? :jl_tty_get_winsize : :uv_tty_get_winsize),
                                      Int32, (Ptr{Void}, Ptr{Int32}, Ptr{Int32}),
                                      t.out_stream.handle, pointer(s,1), pointer(s,2)) != 0)
    Size(s[1], s[2])
end

clear(t::UnixTerminal) = write(t.out_stream, "\x1b[H\x1b[2J")
clear_line(t::UnixTerminal) = write(t.out_stream, "\x1b[0G\x1b[0K")
#beep(t::UnixTerminal) = write(t.err_stream,"\x7")

write{T,N}(t::UnixTerminal, a::Array{T,N}) = write(t.out_stream, a)
write(t::UnixTerminal, p::Ptr{Uint8}) = write(t.out_stream, p)
write(t::UnixTerminal, p::Ptr{Uint8}, x::Integer) = write(t.out_stream, p, x)
write(t::UnixTerminal, x::Uint8) = write(t.out_stream, x)
read{T,N}(t::UnixTerminal, x::Array{T,N}) = read(t.in_stream, x)
readuntil(t::UnixTerminal, s::String) = readuntil(t.in_stream, s)
readuntil(t::UnixTerminal, c::Char) = readuntil(t.in_stream, c)
readuntil(t::UnixTerminal, s) = readuntil(t.in_stream, s)
read(t::UnixTerminal, ::Type{Uint8}) = read(t.in_stream, Uint8)
start_reading(t::UnixTerminal) = start_reading(t.in_stream)
stop_reading(t::UnixTerminal) = stop_reading(t.in_stream)

@unix_only hascolor(t::UnixTerminal) = (beginswith(t.term_type, "xterm") || success(`tput setaf 0`))
@windows_only hascolor(t::UnixTerminal) = true

end # module

max_stars_repo_name: alyst/julia

max_issues_repo_name: alyst/julia

max_forks_repo_name: alyst/julia


text:
        # sort!
        p  = Point(T(0))
        p₁ = Point(T(1))
        p₂ = Point(T(2))
        p₃ = Point(T(3))
        points = [p₃, p₁, p₂]
        sort!(p, points)
        @test points[1] == p₁
        @test points[2] == p₂
        @test points[3] == p₃

        # sort
        p  = Point(T(0))
        p₁ = Point(T(1))
        p₂ = Point(T(2))
        p₃ = Point(T(3))
        points = [p₃, p₁, p₂]
        points_sorted = sort(p, points)
        @test points_sorted[1] == p₁
        @test points_sorted[2] == p₂
        @test points_sorted[3] == p₃

        # sort!
        p  = Point2D{T}(0, 0)
        p₁ = Point2D{T}(1, 0)
        p₂ = Point2D{T}(2, 0)
        p₃ = Point2D{T}(3, 0)
        points = [p₃, p₁, p₂]
        sort!(p, points)
        @test points[1] == p₁
        @test points[2] == p₂
        @test points[3] == p₃

        # sort
        p  = Point2D{T}(0, 0)
        p₁ = Point2D{T}(1, 0)
        p₂ = Point2D{T}(2, 0)
        p₃ = Point2D{T}(3, 0)
        points = [p₃, p₁, p₂]
        points_sorted = sort(p, points)
        @test points_sorted[1] == p₁
        @test points_sorted[2] == p₂
        @test points_sorted[3] == p₃

        # sort!
        p  = Point3D{T}(0, 0, 0)
        p₁ = Point3D{T}(1, 0, 0)
        p₂ = Point3D{T}(2, 0, 0)
        p₃ = Point3D{T}(3, 0, 0)
        points = [p₃, p₁, p₂]
        sort!(p, points)
        @test points[1] == p₁
        @test points[2] == p₂
        @test points[3] == p₃

        # sort
        p  = Point3D{T}(0, 0, 0)
        p₁ = Point3D{T}(1, 0, 0)
        p₂ = Point3D{T}(2, 0, 0)
        p₃ = Point3D{T}(3, 0, 0)
        points = [p₃, p₁, p₂]
        points_sorted = sort(p, points)
        @test points_sorted[1] == p₁
        @test points_sorted[2] == p₂
        @test points_sorted[3] == p₃

max_stars_repo_name: khurrumsaleem/MOCNeutronTransport

max_issues_repo_name: khurrumsaleem/MOCNeutronTransport

max_forks_repo_name: khurrumsaleem/MOCNeutronTransport


text:
using Test, YaoBlocks, YaoArrayRegister, YaoBlocks.Optimise
import YaoBlocks: Sum

@testset "construction" begin
    @test X + Y + Z == sum(X, Y, Z)
    @test X + (Y + Z) == sum(X, sum(Y, Z))

    @test X * Y * Z == prod(X, Y, Z)
    @test X * (Y * Z) == prod(X, prod(Y, Z))
    @test im * X == Scale(Val(im), X)

    @test mat(X-Y) ≈ mat(X) - mat(Y)
    @test mat(X/2) ≈ 0.5*mat(X)
end

@testset "block operations" begin
    r = rand_state(1)
    @test copy(r) |> X * Y * Z |> state ≈ mat(X * Y * Z) * state(r)
    @test copy(r) |> X + Y + Z |> state ≈ mat(X + Y + Z) * state(r)
end

@testset "merge pauli prod" begin
    test_merge(a, b) = mat(merge_pauli(a, b)) ≈ (mat(a) * mat(b))

    for a in [X, Y, Z], b in [X, Y, Z]
        @test test_merge(a, b)
    end

    @test mat(simplify(X * Y)) ≈ mat(im * Z)
    @test mat(simplify(im * X * im * Y)) ≈ mat(-im * Z)
    @test mat(simplify(I2 * im * I2)) ≈ mat(im * I2)

    @test mat(simplify(X * Y * Y)) ≈ mat(X) ≈ mat(X) * mat(Y) * mat(Y)
    @test mat(simplify(X * Y * Z)) ≈ mat(im * I2) ≈ mat(X) * mat(Y) * mat(Z)
end

@testset "eliminate nested" begin
    @test simplify(prod(X, prod(H))) == prod(X, H)
    @test simplify(prod(X)) == X

    @test simplify(sum(X, sum(X, X))) == 3X
end

@testset "reduce matrices" begin
    @test mat(prod(X, Y)) ≈ mat(X) * mat(Y)
    @test mat(prod(X, Y)) ≈ mat(simplify(prod(X, Y)))
    @test mat(sum(X, Y)) ≈ mat(X) + mat(Y)
end

@testset "composite strcuture" begin
    g = chain(2, kron(1=>chain(X, Y), 2=>X), control(1, 2=>X))
    @test simplify(g) == prod(control(2, 1, 2=>X), kron(2, 1=>(-im * Z), 2=>X))
end


text:
#
# Autogenerated by Thrift Compiler (0.11.0)
#
# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING

module HS2

using Thrift
import Thrift.process, Thrift.meta, Thrift.distribute

export meta
export TProtocolVersion # enum
export TTypeId # enum
export TStatusCode # enum
export TOperationState # enum
export TOperationType # enum
export TGetInfoType # enum
export TFetchOrientation # enum
export TJobExecutionStatus # enum
export TTypeEntryPtr # typealias for Int32
export TIdentifier # typealias for String
export TPattern # typealias for String
export TPatternOrIdentifier # typealias for String
export TTypeQualifierValue # struct
export TTypeQualifiers # struct
export TPrimitiveTypeEntry # struct
export TArrayTypeEntry # struct
export TMapTypeEntry # struct
export TStructTypeEntry # struct
export TUnionTypeEntry # struct
export TUserDefinedTypeEntry # struct
export TTypeEntry # struct
export TTypeDesc # struct
export TColumnDesc # struct
export TTableSchema # struct
export TBoolValue # struct
export TByteValue # struct
export TI16Value # struct
export TI32Value # struct
export TI64Value # struct
export TDoubleValue # struct
export TStringValue # struct
export TColumnValue # struct
export TRow # struct
export TBoolColumn # struct
export TByteColumn # struct
export TI16Column # struct
export TI32Column # struct
export TI64Column # struct
export TDoubleColumn # struct
export TStringColumn # struct
export TBinaryColumn # struct
export TColumn # struct
export TRowSet # struct
export TStatus # struct
export THandleIdentifier # struct
export TSessionHandle # struct
export TOperationHandle # struct
export TOpenSessionReq # struct
export TOpenSessionResp # struct
export TSetClientInfoReq # struct
export TSetClientInfoResp # struct
export TCloseSessionReq # struct
export TCloseSessionResp # struct
export TGetInfoValue # struct
export TGetInfoReq # struct
export TGetInfoResp # struct
export TExecuteStatementReq # struct
export TExecuteStatementResp # struct
export TGetTypeInfoReq # struct
export TGetTypeInfoResp # struct
export TGetCatalogsReq # struct
export TGetCatalogsResp # struct
export TGetSchemasReq # struct
export TGetSchemasResp # struct
export TGetTablesReq # struct
export TGetTablesResp # struct
export TGetTableTypesReq # struct
export TGetTableTypesResp # struct
export TGetColumnsReq # struct
export TGetColumnsResp # struct
export TGetFunctionsReq # struct
export TGetFunctionsResp # struct
export TGetPrimaryKeysReq # struct
export TGetPrimaryKeysResp # struct
export TGetCrossReferenceReq # struct
export TGetCrossReferenceResp # struct
export TGetOperationStatusReq # struct
export TGetOperationStatusResp # struct
export TCancelOperationReq # struct
export TCancelOperationResp # struct
export TCloseOperationReq # struct
export TCloseOperationResp # struct
export TGetResultSetMetadataReq # struct
export TGetResultSetMetadataResp # struct
export TFetchResultsReq # struct
export TFetchResultsResp # struct
export TGetDelegationTokenReq # struct
export TGetDelegationTokenResp # struct
export TCancelDelegationTokenReq # struct
export TCancelDelegationTokenResp # struct
export TRenewDelegationTokenReq # struct
export TRenewDelegationTokenResp # struct
export TProgressUpdateResp # struct
export TGetQueryIdReq # struct
export TGetQueryIdResp # struct
export PRIMITIVE_TYPES # const
export COMPLEX_TYPES # const
export COLLECTION_TYPES # const
export TYPE_NAMES # const
export CHARACTER_MAXIMUM_LENGTH # const
export PRECISION # const
export SCALE # const
export TCLIServiceProcessor, TCLIServiceClient, TCLIServiceClientBase, OpenSession, CloseSession, GetInfo, ExecuteStatement, GetTypeInfo, GetCatalogs, GetSchemas, GetTables, GetTableTypes, GetColumns, GetFunctions, GetPrimaryKeys, GetCrossReference, GetOperationStatus, CancelOperation, CloseOperation, GetResultSetMetadata, FetchResults, GetDelegationToken, CancelDelegationToken, RenewDelegationToken, GetQueryId, SetClientInfo # service TCLIService

include("HS2_constants.jl")
include("HS2_types.jl")
include("HS2_impl.jl")  # server methods to be hand coded
include("TCLIService.jl")

end # module HS2


text:
# ------------------------------------------------------------------
# Licensed under the MIT License. See LICENSE in the project root.
# ------------------------------------------------------------------

Makie.plottype(::Data) = Viz{<:Tuple{Data}}

function Makie.plot!(plot::Viz{<:Tuple{Data}})
  # retrieve data and variable
  data     = plot[:object][]
  variable = plot[:variable][]

  # retrieve domain and element table
  dom, tab = domain(data), values(data)

  # list of all variables
  variables = Tables.columnnames(tab)

  # select variable to visualize
  var = isnothing(variable) ? first(variables) : variable

  # element color from variable column
  c = Tables.getcolumn(tab, var)

  # handle categorical values
  color = eltype(c) <: CategoricalValue ? levelcode.(c) : c

  # call recipe for underlying domain
  viz!(plot, dom,
    size          = plot[:size],
    color         = color,
    colormap      = plot[:colormap],
    boundarycolor = plot[:boundarycolor],
    facetcolor    = plot[:facetcolor],
    showboundary  = plot[:showboundary],
    showfacets    = plot[:showfacets],
    decimation    = plot[:decimation],
  )
end


text:
# Raytracer.jl
# Raytracing for the generation of photorealistic images in Julia
# Copyright (c) 2021 Samuele Colombo, Paolo Galli

# Unit test file for shapes.jl

@testset "OnOffRenderer" begin
    sphere = Sphere(transformation=translation(Vec(2f0, 0f0, 0f0)) * scaling(Vec(0.2f0, 0.2f0, 0.2f0)))
    image = HdrImage(3, 3)
    camera = OrthogonalCamera()
    tracer = ImageTracer(image, camera)
    world = World([sphere])
    renderer = OnOffRenderer(world)
    fire_all_rays!(tracer, renderer, enable_progress_bar=false)

    @test image[1, 1] |> iszero
    @test image[2, 1] |> iszero
    @test image[3, 1] |> iszero

    @test image[1, 2] |> iszero
    @test image[2, 2] |> isone
    @test image[3, 2] |> iszero

    @test image[1, 3] |> iszero
    @test image[2, 3] |> iszero
    @test image[3, 3] |> iszero
end

@testset "FlatRenderer" begin
    sphere_color = RGB(1.0f0, 2.0f0, 3.0f0)
    sphere = Sphere(transformation=translation(Vec(2f0, 0f0, 0f0)) * scaling(Vec(0.2f0, 0.2f0, 0.2f0)),
                    material=Material(brdf=DiffuseBRDF(pigment=UniformPigment(sphere_color))))
    image = HdrImage(3, 3)
    camera = OrthogonalCamera()
    tracer = ImageTracer(image, camera)
    world = World([sphere])
    renderer = FlatRenderer(world)
    fire_all_rays!(tracer, renderer)

    @test image[1, 1] |> iszero
    @test image[2, 1] |> iszero
    @test image[3, 1] |> iszero

    @test image[1, 2] |> iszero
    @test image[2, 2] ≈ sphere_color
    @test image[3, 2] |> iszero

    @test image[1, 3] |> iszero
    @test image[2, 3] |> iszero
    @test image[3, 3] |> iszero
end

@testset "PathTracer" begin
    pcg = PCG()

    begin
        # Run the furnace test several times using random values for
        # the emitted radiance and reflectance
        for i in 1:5
            emitted_radiance = rand(pcg, Float32)
            reflectance = rand(pcg, Float32) * 0.9f0  # Avoid numbers that are too close to 1

            world = World()

            enclosure_material = Material(
                brdf=DiffuseBRDF(pigment=UniformPigment(WHITE * reflectance)),
                emitted_radiance=UniformPigment(WHITE * emitted_radiance),
            )

            push!(world, Sphere(material=enclosure_material))

            path_tracer = PathTracer(
                world,
                rng=pcg,
                n=1,
                max_depth=100,
                roulette_depth=101,
            )

            ray = Ray(Point(0f0, 0f0, 0f0), Vec(1f0, 0f0, 0f0))
            color = path_tracer(ray)

            expected = emitted_radiance / (1f0 - reflectance)
            atol = 1f-3
            @test isapprox(color.r, expected, atol = atol)
            @test isapprox(color.g, expected, atol = atol)
            @test isapprox(color.b, expected, atol = atol)
        end
    end
end


text:
# Objects in the game and their supporting functions (update!, collide!, ...)

# Abstract positions and dimensions in arbitrary coordinate systems for the
# game. Concrete Pos and Dims must always be used with the same CoordType.
# Can convert between them (possibly in reference to the Camera).
abstract type AbstractPos{CoordType} end
abstract type AbstractDims{CoordType} end

""" WorldCoords are the absolute space of the game, independent of camera. """
struct WorldCoords end

"""
    WorldPos(5.0,-200.0)
x,y float coordinates in the game world (not necessarily the same as pixel
coordinates on the screen).
"""
struct WorldPos <: AbstractPos{WorldCoords}  # 0,0 == middle
    x::Float64
    y::Float64
end
toWorldPos(p::WorldPos, c) = p
"""
    WorldDims(5.0,-200.0)
w,h float dimensions in the game world (not necessarily the same as pixel
coordinates on the screen).
"""
struct WorldDims <: AbstractDims{WorldCoords}  # 0,0 == middle
    w::Float64
    h::Float64
end
toWorldDims(d::WorldDims, c) = d

"""
    Vector2D(-2.5,1.0)
x,y vector representing direction in the game world. Could represent a velocity,
a distance, etc. Subtracting two `WorldPos`itions results in a `Vector2D`.
"""
struct Vector2D   # TODO: consider making this abstract and parameterized on CoordType.
    x::Float64
    y::Float64
end
import Base.*, Base./, Base.-, Base.+
+(a::Vector2D, b::Vector2D) = Vector2D(a.x+b.x, a.y+b.y)
-(a::Vector2D, b::Vector2D) = Vector2D(a.x-b.x, a.y-b.y)
*(a::Vector2D, x::Number) = Vector2D(a.x*x, a.y*x)
*(x::Number, a::Vector2D) = a*x
/(a::Vector2D, x::Number) = Vector2D(a.x/x, a.y/x)
+(a::P, b::Vector2D) where {P<:AbstractPos} = P(a.x+b.x, a.y+b.y)
-(a::P, b::Vector2D) where {P<:AbstractPos} = P(a.x-b.x, a.y-b.y)
+(a::Vector2D, b::P) where {P<:AbstractPos} = P(a.x+b.x, a.y+b.y)
-(a::Vector2D, b::P) where {P<:AbstractPos} = P(a.x-b.x, a.y-b.y)
-(a::AbstractPos, b::AbstractPos) = Vector2D(a.x-b.x, a.y-b.y)
-(x::AbstractPos) = AbstractPos(-x.x, -x.y)
-(x::Vector2D) = Vector2D(-x.x, -x.y)

magSqrd(v::Vector2D) = v.x^2 + v.y^2
magnitude(v::Vector2D) = sqrt(magSqrd(v))
unitVec(v::Vector2D) = v / magnitude(v)


text:
using WebIO, JSExpr

abstract type AbstractCtx end

struct Ctx <: AbstractCtx
    s::Scope
    o::Observable
end

# `play(env, actions)`
# or
# `
# using Blink
# w = Blink()
# play(env, actions, (ctx)=> body!(w, ctx.s))
# `
function play(env, actions=rand(1:2, 1000), cb=nothing)
    reset!(env)
    ctx = Ctx(env)
    if cb == nothing
        display(ctx.s)
    else
        cb(ctx)
    end

    i = 1
    done = false

    while i <= length(actions) && !done
        a, b, done, d = step!(env, actions[i])
        render(env, ctx)
        i += 1
        sleep(0.08) # to see an animation
    end

end


text:
module SatelliteImages
using Dates, ArchGDAL, GeoArrays, DataFrames, Shapefile, GeoInterface, ProgressMeter, SparseArrays, StatsBase, Statistics, RecursiveArrayTools, JLD, CubicSplines
# Write your package code here.

export load_img, load_datacube, save_img, save_datacube,
lat_to_row, row_to_lat, lat_to_row, long_to_column, column_to_long, translate_geometry, Coordinate, CoordinateSystem, image_to_coordinate,
polygon_mask, load_shapefile, mask_area, long_apply, cross_apply, apply_mask, view_img, aggregate, aggregate_timeseries, aggregate_dataframe, bias_correction,  sparse_cube, make_datacube, load_example, radiance_datacube, clouds_datacube, mumbai_map, MUMBAI_COORDINATE_SYSTEM, INDIA_COORDINATE_SYSTEM, coordinate_to_image, aggregate_per_area_dataframe

include("data_io.jl")
include("view_image.jl")
include("coordinate_system.jl")
include("polygons.jl")
include("area.jl")
include("f_apply.jl")
include("sparse_datacube.jl")
include("aggregate.jl")
include("example.jl")
include("masks.jl")
include("luxor_functions.jl")
end


text:
using CUDA
using FastAI
using Flux.Losses: logitcrossentropy
using Flux: DataLoader
using ProgressMeter
using Random
using Zygote
include("../../src/models/mlp.jl")
include("../../src/utils/metrics.jl")
include("./prepare_data.jl")
include("../../src/preprocessing/ohe_cat_features.jl")

function run_benchmark(; kws...)
    Random.seed!(42)

    # Create test and train dataloaders
    tabular_dataloaders = getdata()

    # get categorical cardinalities
    cardinalities = collect(map(col -> length(tabular_dataloaders.cat_dict[col]),
                collect(1:length(tabular_dataloaders.cat_dict))))
    embedding_dims = FastAI.Models.get_emb_sz(cardinalities)

    # get continious variable input dims
    cont_input_dim = size(tabular_dataloaders.train_loader.data[2], 1)

    # load hyperparameters
    args = MLPArgs(; embedding_dims=embedding_dims, cont_input_dim=cont_input_dim, kws...)

    # GPU setup
    if CUDA.functional() && args.use_cuda
        @info "Training on CUDA GPU"
        CUDA.allowscalar(false)
        device = gpu
    else
        @info "Training on CPU"
        device = cpu
    end

    # Construct model
    model = MLP(args) |> device
    ps = Flux.params(model) # model's trainable parameters

    ## Optimizer
    opt = ADAM(args.lr)

    ## Training
    for epoch in 1:args.epochs
        @info "Epoch: $epoch"
        progress = Progress(length(tabular_dataloaders.train_loader))
        for (y, X_cont, X_cat...) in tabular_dataloaders.train_loader
            # send batch  to device
            X_cat = X_cat |> device
            X_cont = X_cont |> device
            y = y |> device

            loss, back = Flux.pullback(() -> logitcrossentropy(model(X_cat, X_cont), y), ps)
            gs = back(one(loss)) # calculate gradient
            Flux.Optimise.update!(opt, ps, gs) # update parameters

            next!(progress; showvalues=[(:loss, loss)])  # show loss
        end

        # get train/test losses
        loss_and_accuracy(tabular_dataloaders.train_loader, model, device; set="train")
        loss_and_accuracy(tabular_dataloaders.test_loader, model, device; set="test")
    end
end

a = run_benchmark(; hidden_dims=(256, 128))


text:
function stringToIntArray(input)
    ret = ArrayInt32(1)
    for c in input
        i = parse(Int32, c)
        push!(ret, i)
    end
    return ret
end

function fileToStringArray(fileName)
    ret = Array{String,1}()
    open(fileName) do file

        for line in eachline(file)
            push!(ret, line)
        end
    end
    return ret
end


text:
# include("interpolate.jl") # not work
include("resample.jl")
include("spatial_array.jl")


text:
using SQLite, Tables, Printf

function storetodos(tododict::Union{Nothing, Dict{String, Vector{Todo}}};
                    filename::String="todo_cache.db")

    if tododict === nothing
        println(stdout, "No todos found.")
        exit()
    end
    # TODO: this writes again the previous todos
    db = SQLite.DB()
    db = DBInterface.connect(SQLite.DB, filename)
    for (fname, todo_vec) in tododict
        fname = replace(fname, "." => "_")
        last_separator = findlast("/", fname)
        temp_fname = chop(fname, head=last_separator[1], tail=0)
        execute_string = @sprintf "CREATE TABLE IF NOT EXISTS %s (
                             id INTEGER,
                             pre TEXT,
                             suf TEXT,
                             line INTEGER,
                             body TEXT)" temp_fname
        # println(execute_string)
        DBInterface.execute(db, execute_string)
        prepare_string = @sprintf "INSERT INTO %s VALUES(?,?,?,?,?)" temp_fname
        q = DBInterface.prepare(db, prepare_string)
        for todo in todo_vec
            SQLite.execute(q, (todo.ID, todo.Prefix, todo.Suffix, todo.Line,
                               todo.Body,))
        end
    end

    DBInterface.close!(db)

end


text:
using StringDistances
srand(2)
x = map(Base.randstring, rand(5:25,500_000))
y = map(Base.randstring, rand(5:25,500_000))
function f(t, x, y)
    [evaluate(t, x[i], y[i]) for i in 1:length(x)]
end

# same speed as StringDist
@time f(Levenshtein(), x, y)
@time f(Jaro(), x, y)
@time f(RatcliffObershelp(), x, y)

# 4x slower compared to StringDist
@time f(Jaccard(2), x, y)
@time f(Cosine(2), x, y)
@time f(QGram(2), x, y)

#

#= Rcode
library(stringdist)
x <- sapply(sample(5:25,5 * 1e5,replace=TRUE), function(n) paste(sample(letters,n,replace=TRUE),collapse=""))
y <- sapply(sample(5:25,5 * 1e5,replace=TRUE), function(n) paste(sample(letters,n,replace=TRUE),collapse=""))
system.time(stringdist(x,y,method='lv', nthread = 1))
system.time(stringdist(x,y,method='jaccard', nthread = 1))
system.time(stringdist(x,y,method='cosine', nthread = 1))
system.time(stringdist(x,y,method='qgram', nthread = 1))

=#


text:
module ViewHelper

using Genie, Helpers, App

export output_flash, chirps_pagination

function output_flash(params::Dict{Symbol,Any}) :: String
  ! isempty( flash(params) ) ? """
$(flash(params))
""" : ""
end

function chirps_pagination(total_chirps::Int, chirps_per_page::Int) :: String
  total_chirps < chirps_per_page && return ""
  mapreduce(*, [Int(i) for i in 0:floor(total_chirps/chirps_per_page)]) do i
    """$(i+1) """
  end
end

end

max_stars_repo_name: essenciary/chirper

max_issues_repo_name: essenciary/chirper

max_forks_repo_name: essenciary/chirper