text:
# Measures without Canvas Units
# -----------------------------

# Rather than introducing a new type to represent measures that
# have no canvas unit dimension, we just parameterize Measure
# over a special type that promotes appropriately.
immutable MeasureNil
end

const measure_nil = MeasureNil()

# All measures in Compose are specified as the sum
immutable Measure{S, T}
    abs::Float64 # absolute measurement in millimeters
    cx::S        # canvas x-units
    cy::T        # canvas y-units
    cw::Float64  # proportion of canvas width
    ch::Float64  # proportion of canvas height

    function Measure(abs::Number, cx::S, cy::T, cw::Number, ch::Number)
        new(float64(abs), cx, cy, float64(cw), float64(ch))
    end

    function Measure(; abs=0.0, cx::S=zero(S), cy::T=zero(T), cw=0.0, ch=0.0)
        new(float64(abs), cx, cy, float64(cw), float64(ch))
    end
end

typealias MeasureOrNumber Union(Measure, Number)

# MeasureNil semantics
zero(::Type{MeasureNil}) = measure_nil
zero(::MeasureNil) = measure_nil

iszero{T}(a::T) = a == zero(T)

# ambiguity warning
max(::Function, b::MeasureNil) = measure_nil
min(::Function, b::MeasureNil) = measure_nil

max(a::MeasureNil, b::MeasureNil) = measure_nil
max(a::MeasureNil, b)             = b
max(a, b::MeasureNil)             = a

min(a::MeasureNil, b::MeasureNil) = measure_nil
min(a::MeasureNil, b)             = measure_nil
min(a, b::MeasureNil)             = measure_nil

isless(a::MeasureNil, b::MeasureNil) = false

function -{S,T}(a::Measure{S, T})
    return Measure{S, T}(-a.abs, -a.cx, -a.cy, -a.cw, -a.ch)
end

function zero(::Type{Measure})
    return Measure()
end

function zero(::Measure)
    return Measure()
end

function Measure(abs, cx=measure_nil, cy=measure_nil, cw=0.0, ch=0.0)
    Measure{typeof(cx), typeof(cy)}(abs, cx, cy, cw, ch)
end

function Measure(; abs=0.0, cx=measure_nil, cy=measure_nil, cw=0.0, ch=0.0)
    Measure{typeof(cx), typeof(cy)}(abs, cx, cy, cw, ch)
end

const zero_measure = Measure()

# copy with substitutions
function Measure{S, T}(u::Measure{S, T};
                       abs=nothing, cx=nothing, cy=nothing,
                       cw=nothing, ch=nothing)
    return Measure(abs === nothing ? u.abs : abs,
                   cx  === nothing ? u.cx  : cx,
                   cy  === nothing ? u.cy  : cy,
                   cw  === nothing ? u.cw  : cw,
                   ch  === nothing ? u.ch  : ch)
end

function zero{S, T}(::Type{Measure{S, T}})
    Measure{S, T}()
end

function isless{T, S}(a::Measure{T, S}, b::Measure{T, S})
    return (a.abs < b.abs ||
            a.cx  < b.cx ||
            a.cy  < b.cy ||
            a.cw  < b.cw ||
            a.ch  < b.ch) &&
           a.abs <= b.abs &&
           a.cx  <= b.cx &&
           a.cy  <= b.cy &&
           a.cw  <= b.cw &&
           a.ch  <= b.ch
end

function isabsolute{S, T}(u::Measure{S, T})
    iszero(u.cx) && iszero(u.cy) && u.cw == 0.0 && u.ch == 0.0
end

function copy{S, T}(a::Measure{S, T})
    Measure{S, T}(abs=a.abs, cx=a.cx, cy=a.cy, cw=a.cw, ch=a.ch)
end

function show{S, T}(io::IO, a::Measure{S, T})
    first = true
    xz = zero(S)
    yz = zero(T)

    if a.abs != 0.0
        print(io, a.abs, "mm")
        first = false
    end

    if a.cx != xz
        if !first
            print(io, " + ")
        end
        print(io, a.cx, "cx")
        first = false
    end

    if a.cy != yz
        if !first
            print(io, " + ")
        end
        print(io, a.cy, "cy")
        first = false
    end

    if a.cw != 0.0
        if !first
            print(io, " + ")
        end
        print(io, a.cw, "w")
        first = false
    end

    if a.ch != 0.0
        if !first
            print(io, " + ")
        end
        print(io, a.ch, "h")
        first = false
    end

    if first
        print(io, "Measure()")
    end
end

# Measure Arithmatic
# ------------------

# Avoid ambiguity errors
add_measure_part(a::MeasureNil, b::MeasureNil) = measure_nil
add_measure_part(a::MeasureNil, b)             = b
add_measure_part(a, b::MeasureNil)             = a
add_measure_part(a, b)                         = a + b

sub_measure_part(a::MeasureNil, b::MeasureNil) = measure_nil
sub_measure_part(a::MeasureNil, b)             = b
sub_measure_part(a, b::MeasureNil)             = a
sub_measure_part(a, b)                         = a - b

*(a::MeasureNil, b::MeasureNil) = error("Two measure_nil objects multiplied")
*(a::MeasureNil, b)             = measure_nil
*(a, b::MeasureNil)             = measure_nil

/(a::MeasureNil, b::MeasureNil) = error("Division by a measure_nil")
/(a, b::MeasureNil)             = error("Division by a measure_nil")
/(a::MeasureNil, b)             = measure_nil

function +(a::Measure, b::Measure)
    Measure(a.abs + b.abs,
            add_measure_part(a.cx, b.cx),
            add_measure_part(a.cy, b.cy),
            a.cw  + b.cw,
            a.ch  + b.ch)
end

function -(a::Measure, b::Measure)
    Measure(a.abs - b.abs,
            sub_measure_part(a.cx, b.cx),
            sub_measure_part(a.cy, b.cy),
            a.cw  - b.cw,
            a.ch  - b.ch)
end

function *(a::Measure, b::Measure)
    error("A Measure can not be multiplied by another Measure.")
end

function /{T, S}(a::Measure{T}, b::Measure{S})
    factor = nothing

    for unit in (:abs, :cx, :cy, :cw, :ch)
        vala = getfield(a, unit)
        valb = getfield(b, unit)

        if valb == zero(typeof(valb))
            continue
        end

        if factor === nothing
            factor = vala / valb
        else
            if vala / valb != factor
                error("Measure {a} is not divisible by measure {b}")
            end
        end
    end

    if factor === nothing
        error("An empty measure can not be divided by another empty measure.")
    else
        factor
    end
end

# Return a measure that is at least as large as anything else
function max(measures::Measure...)
    # current maximums
    abs = 0.0
    cx = measure_nil
    cy = measure_nil
    cw = 0.0
    ch = 0.0

    for measure in measures
        abs = max(abs, measure.abs)
        cx  = max(cx, measure.cx)
        cy  = max(cy, measure.cy)
        cw  = max(cw, measure.cw)
        ch  = max(ch, measure.ch)
    end

    Measure(abs, cx, cy, cw, ch)
end

# Return a measure that at least as small as everything else
function min(measures::Measure...)
    # current maximums
    abs = Inf
    cx = Inf
    cy = Inf
    cw = Inf
    ch = Inf

    for measure in measures
        abs = min(abs, measure.abs)
        cx  = min(cx, measure.cx)
        cy  = min(cy, measure.cy)
        cw  = min(cw, measure.cw)
        ch  = min(ch, measure.ch)
    end

    Measure(abs, cx, cy, cw, ch)
end

# Versus plain numbers

function *(a::Measure, b::Number)
    Measure(a.abs*b, a.cx*b, a.cy*b, a.cw*b, a.ch*b)
end

function *(a::Number, b::Measure)
    b * a
end

function /{T}(a::Measure{T}, b::Number)
    Measure(a.abs/b, a.cx/b, a.cy/b, a.cw/b, a.ch/b)
end

# Measure Constants
# -----------------

# Measure instances are usually constructed by multiplying by one of these
# constants. E.g. "10mm"

const mm   = Measure(abs=1.0)
const cm   = Measure(abs=10.0)
const inch = Measure(abs=25.4)
const pt   = inch/72.0
const w    = Measure(cw=1.0)
const h    = Measure(ch=1.0)
const cx   = Measure(cx=1.0)
const cy   = Measure(cy=1.0)

# Pixels are not typically used in Compose in preference of absolute
# measurements or measurements relative to parent canvases. So for the
# 'px' constant, we just punt and give something do something vagually
# reasonable.

const assumed_ppmm = 3.78 # equivalent to 96 DPI
const px = Measure(abs=1.0/assumed_ppmm)

# Interpretation of bare numbers
# ------------------------------

function x_measure(a::Measure)
    a
end

function x_measure(a)
    Measure(0.0, a)
end

function y_measure(a::Measure)
    a
end

function y_measure(a)
    Measure(0.0, measure_nil, a)
end

function size_measure(a::Measure)
    a
end

function size_measure(a)
    Measure(a)
end

# Higher-order measures
# ---------------------

immutable Point
    x::Measure
    y::Measure

    function Point()
        new(Measure(), Measure())
    end

    function Point(x, y)
        new(x_measure(x), y_measure(y))
    end

    function Point(point::Point)
        new(point.x, point.y)
    end

    function Point(xy::NTuple{2})
        Point(x_measure(xy[1]), y_measure(xy[2]))
    end
end

function copy(point::Point)
    Point(point)
end

function isabsolute(point::Point)
    isabsolute(point.x) && isabsolute(point.y)
end

typealias XYTupleOrPoint Union(NTuple{2}, Point)

function convert(::Type{Point}, xy::NTuple{2})
    Point(xy[1], xy[2])
end

# Bounding Boxes
# --------------

# Measure based bounding box used to specify the extent and positioning
# of canvases.
immutable BoundingBox
    x0::Measure
    y0::Measure
    width::Measure
    height::Measure

    function BoundingBox(x0, y0, width, height)
        new(x_measure(x0), y_measure(y0),
            x_measure(width), y_measure(height))
    end

    function BoundingBox(box::BoundingBox)
        new(box.x0, box.y0, box.width, box.height)
    end

    function BoundingBox(box::BoundingBox;
                         x0=nothing,
                         y0=nothing,
                         width=nothing,
                         height=nothing)
        BoundingBox(x0     === nothing ? box.x0     : x0,
                    y0     === nothing ? box.y0     : y0,
                    width  === nothing ? box.width  : width,
                    height === nothing ? box.height : height)
    end

    function BoundingBox()
        new(0cx, 0cy, 1cx, 1cy)
    end
end

function copy(box::BoundingBox)
    BoundingBox(box)
end

# Compute the union of two bounding boxes.
#
# In other words, given two bounding boxes, return a new bounding box that
# contains both.
#
# Unfortunately this is in general uncomputable without knowing the absolute
# size of the parent canvas which may be passed in via the last two parameters.
# If not passed, this throws an error if they would have been required.
#
function union(a::BoundingBox, b::BoundingBox, units=nothing, parent_abs_width=nothing, parent_abs_height=nothing)
    (a.width == Measure() || a.height == Measure()) && return b
    (b.width == Measure() || b.height == Measure()) && return a
    x0 = min(a.x0, b.x0)
    y0 = min(a.y0, b.y0)
    x1 = max(a.x0 + a.width, b.x0 + b.width)
    y1 = max(a.y0 + a.height, b.y0 + b.height)
    # Check whether we had any problematic computations
    for m in (x0,y0,x1,y1)
        # Pure absolute or pure relative points are fine. When they are mixed,
        # there are problems
        if !isabsolute(m) && m.abs != 0.0
            if units == nothing || parent_abs_width == nothing || parent_abs_height == nothing
                error("""Bounding boxes are uncomputable without knowledge of the
                         absolute dimensions of the top canvase due to mixing of relative
                         and absolute coordinates. Either pass the dimension as a parameter
                         or restrict the context to one kind of coordinates.""")
            end
            parent_box = AbsoluteBoundingBox(0.0,0.0,parent_abs_width,parent_abs_height)
            abb = union(absolute_units(a,IdentityTransform(),units,parent_box),
                        absolute_units(b,IdentityTransform(),units,parent_box))
            return BoundingBox(Measure(;abs = abb.x0), Measure(;abs = abb.x0),
                               Measure(;abs = abb.width), Measure(;abs = abb.height))
        end
    end
    return BoundingBox(x0, y0, x1 - x0, y1 - y0)
end

# Absolute measure bounding box. This is used to keep track of
# coordinates when traversing canvas trees to perform drawing.
immutable AbsoluteBoundingBox
    x0::Float64
    y0::Float64
    width::Float64
    height::Float64

    function AbsoluteBoundingBox(x0::Number, y0::Number, width::Number, height::Number)
        return new(x0, y0, width, height)
    end

    function AbsoluteBoundingBox()
        return new(0.0, 0.0, 1.0, 1.0)
    end
end

function union(a::AbsoluteBoundingBox, b::AbsoluteBoundingBox)
    (a.width == 0.0 || a.height == 0.0) && return b
    (b.width == 0.0 || b.height == 0.0) && return a
    x0 = min(a.x0, b.x0)
    y0 = min(a.y0, b.y0)
    x1 = max(a.x0 + a.width, b.x0 + b.width)
    y1 = max(a.y0 + a.height, b.y0 + b.height)
    return AbsoluteBoundingBox(x0, y0, x1 - x0, y1 - y0)
end

# The same type-signature is used for a box used to assign
# a custom coordinate system to a canvas.
# TODO: There should not be one fixed type for every parameter
immutable UnitBox{S, T, U, V}
    x0::S
    y0::T
    width::U
    height::V

    leftpad::Measure
    rightpad::Measure
    toppad::Measure
    bottompad::Measure

    function UnitBox(x0::S, y0::T, width::U, height::V;
                     leftpad::Measure=Measure(),
                     rightpad::Measure=Measure(),
                     toppad::Measure=Measure(),
                     bottompad::Measure=Measure())
        return new(x0, y0, width, height, leftpad, rightpad, toppad, bottompad)
    end
end

function UnitBox{S,T}(width::S, height::T;
                      leftpad::Measure=Measure(),
                      rightpad::Measure=Measure(),
                      toppad::Measure=Measure(),
                      bottompad::Measure=Measure())
    x0 = zero(S)
    y0 = zero(T)

    return UnitBox{S, T, S, T}(x0, y0, width, height,
                               leftpad=leftpad, rightpad=rightpad,
                               toppad=toppad, bottompad=bottompad)
end

function UnitBox(x0, y0, width, height;
                 leftpad::Measure=Measure(),
                 rightpad::Measure=Measure(),
                 toppad::Measure=Measure(),
                 bottompad::Measure=Measure())
    x0, width  = promote(x0, width)
    y0, height = promote(y0, height)
    return UnitBox{typeof(x0), typeof(y0), typeof(width), typeof(height)}(
                   x0, y0, width, height,
                   leftpad=leftpad, rightpad=rightpad,
                   toppad=toppad, bottompad=bottompad)
end

function UnitBox()
    return UnitBox{Float64, Float64, Float64, Float64}(0.0, 0.0, 1.0, 1.0)
end

# copy with substitution
function UnitBox(units::UnitBox;
                 x0=nothing, y0=nothing, width=nothing, height=nothing,
                 leftpad=nothing, rightpad=nothing, toppad=nothing,
                 bottompad=nothing)
    return UnitBox(x0 === nothing ? units.x0 : x0,
                   y0 === nothing ? units.y0 : y0,
                   width === nothing ? units.width : width,
                   height === nothing ? units.height : height,
                   leftpad   = leftpad   === nothing ? units.leftpad : leftpad,
                   rightpad  = rightpad  === nothing ? units.rightpad : rightpad,
                   toppad    = toppad    === nothing ? units.toppad : toppad,
                   bottompad = bottompad === nothing ? units.bottompad : bottompad)
end

function NilUnitBox()
    return UnitBox{Nothing, Nothing, Nothing, Nothing}(
                nothing, nothing, nothing, nothing)
end

const nil_unit_box = NilUnitBox()

function isabsolute(units::UnitBox)
    return units.leftpad == zero_measure && units.rightpad == zero_measure &&
           units.toppad == zero_measure && units.bottompad == zero_measure
end

# Canvas Transforms
# -----------------

# Transform matrix in absolute coordinates

abstract Transform

immutable IdentityTransform <: Transform
end

immutable MatrixTransform <: Transform
    M::Matrix{Float64}

    function Transform()
        new([1.0 0.0 0.0
             0.0 1.0 0.0
             0.0 0.0 1.0])
    end

    function MatrixTransform(M::Matrix{Float64})
        new(M)
    end
end

function combine(a::IdentityTransform, b::IdentityTransform)
    return a
end

function combine(a::IdentityTransform, b::MatrixTransform)
    return b
end

function combine(a::MatrixTransform, b::IdentityTransform)
    return a
end

function combine(a::MatrixTransform, b::MatrixTransform)
    MatrixTransform(a.M * b.M)
end

# Rotation about a point.
type Rotation
    theta::Float64
    offset::Point

    function Rotation()
        new(0.0, Point(0.5w, 0.5h))
    end

    function Rotation(theta::Number)
        Rotation(theta, 0.5w, 0.5h)
    end

    function Rotation(theta::Number, offset::XYTupleOrPoint)
        new(convert(Float64, theta), convert(Point, offset))
    end

    function Rotation(theta::Number, offset_x, offset_y)
        new(convert(Float64, theta), Point(offset_x, offset_y))
    end

    # copy constructor
    function Rotation(rot::Rotation)
        new(copy(rot.theta),
            copy(rot.offset))
    end
end

copy(rot::Rotation) = Rotation(rot)

function convert(::Type{Transform}, rot::Rotation)
    if rot.theta == 0.0
        return IdentityTransform()
    else
        ct = cos(rot.theta)
        st = sin(rot.theta)
        x0 = rot.offset.x - (ct * rot.offset.x - st * rot.offset.y)
        y0 = rot.offset.y - (st * rot.offset.x + ct * rot.offset.y)
        return MatrixTransform([ct  -st  x0.abs
                                st   ct  y0.abs
                                0.0 0.0  1.0])
    end
end

# Conversion to absolute units
# ----------------------------

# Covert a Measure to a Float64
function absolute_units(u::Measure,
                        t::Transform,
                        unit_box::UnitBox,
                        parent_box::AbsoluteBoundingBox)
    add_measure_part(u.abs,
      add_measure_part(
        add_measure_part((u.cx / unit_box.width) * parent_box.width,
                         (u.cy / unit_box.height) * parent_box.height),
        u.cw * parent_box.width +
        u.ch * parent_box.height))
end

function absolute_units(units::UnitBox, t::Transform, parent_units::UnitBox,
                        box::AbsoluteBoundingBox)
    if isabsolute(units)
        return units
    else
        leftpad   = absolute_units(units.leftpad, t, parent_units, box)
        rightpad  = absolute_units(units.rightpad, t, parent_units, box)
        toppad    = absolute_units(units.toppad, t, parent_units, box)
        bottompad = absolute_units(units.bottompad, t, parent_units, box)

        # just give up trying to pad the units if it's impossible
        if leftpad + rightpad >= box.width ||
           toppad + bottompad >= box.height
            return UnitBox(units.x0, units.y0, units.width, units.height)
       end

        width = units.width * (box.width / (box.width - leftpad - rightpad))
        height = units.height * (box.height / (box.height - toppad - bottompad))
        x0 = units.x0 - width * (leftpad / box.width)
        y0 = units.y0 - height * (toppad / box.height)

        return UnitBox(x0, y0, width, height)
    end
end

# Convert a Rotation to a Transform
function absolute_units(rot::Rotation,
                        t::MatrixTransform,
                        unit_box::UnitBox,
                        parent_box::AbsoluteBoundingBox)

    absrot = Rotation(rot.theta,
                      absolute_units(rot.offset, t, unit_box, parent_box))

    rott = convert(Transform, absrot)
    t = combine(rott, t)
    theta = atan2(t.M[2,1], t.M[1,1])
    return Rotation(theta, absrot.offset)
end

function absolute_units(rot::Rotation,
                        t::IdentityTransform,
                        unit_box::UnitBox,
                        parent_box::AbsoluteBoundingBox)

    return Rotation(rot.theta, absolute_units(rot.offset, t, unit_box, parent_box))
end

function absolute_position_cx(::MeasureNil, unit_box::UnitBox,
                              parent_box::AbsoluteBoundingBox)
    0.0
end

function absolute_position_cx(cx, unit_box::UnitBox,
                              parent_box::AbsoluteBoundingBox)
    float64(((cx - unit_box.x0) / unit_box.width)) * parent_box.width
end

function absolute_position_cy(::MeasureNil, unit_box::UnitBox,
                              parent_box::AbsoluteBoundingBox)
    0.0
end

function absolute_position_cy(cy, unit_box::UnitBox,
                              parent_box::AbsoluteBoundingBox)
    float64(((cy - unit_box.y0) / unit_box.height)) * parent_box.height
end

function absolute_x_position(u::Measure,
                             t::Transform,
                             unit_box::UnitBox,
                             parent_box::AbsoluteBoundingBox)
    parent_box.x0 +
      u.abs +
      absolute_position_cx(u.cx, unit_box, parent_box) +
      absolute_position_cy(u.cy, unit_box, parent_box) +
      u.cw * parent_box.width +
      u.ch * parent_box.height
end

function absolute_y_position(u::Measure,
                             t::Transform,
                             unit_box::UnitBox,
                             parent_box::AbsoluteBoundingBox)
    parent_box.y0 +
      u.abs +
      absolute_position_cx(u.cx, unit_box, parent_box) +
      absolute_position_cy(u.cy, unit_box, parent_box) +
      u.cw * parent_box.width +
      u.ch * parent_box.height
end

# Convert a BoundingBox to a AbsoluteBoundingBox
function absolute_units(box::BoundingBox,
                        t::Transform,
                        unit_box::UnitBox,
                        parent_box::AbsoluteBoundingBox)
    AbsoluteBoundingBox(
        absolute_x_position(box.x0, t, unit_box, parent_box),
        absolute_y_position(box.y0, t, unit_box, parent_box),
        absolute_units(box.width, t, unit_box, parent_box),
        absolute_units(box.height, t, unit_box, parent_box))
end

# Convert a Point to a Point in absolute units
function absolute_units(point::Point,
                        t::MatrixTransform,
                        unit_box::UnitBox,
                        parent_box::AbsoluteBoundingBox)
    x = absolute_x_position(point.x, t, unit_box, parent_box)
    y = absolute_y_position(point.y, t, unit_box, parent_box)
    xyt = t.M * [x, y, 1.0]
    return Point(Measure(xyt[1]), Measure(xyt[2]))
end

function absolute_units(point::Point,
                        t::IdentityTransform,
                        unit_box::UnitBox,
                        parent_box::AbsoluteBoundingBox)
    x = absolute_x_position(point.x, t, unit_box, parent_box)
    y = absolute_y_position(point.y, t, unit_box, parent_box)
    return Point(Measure(x), Measure(y))
end


text:
@info "Caesar.jl is loading (but not exporting) tools requiring Colors.jl; e.g. Caesar._PCL"

module _PCL

using ..Colors

using Dates
using DocStringExtensions
using Requires
using StaticArrays
using Manifolds
import Rotations as _Rot

# Going to add dispatches on these functions
import Base: getindex, setindex!, resize!, cat, convert, sizeof, hasproperty, getproperty

# gets overloaded
import Manifolds: apply

## hold off on exports, users can in the mean-time use/import via e.g. _PCL.PointXYZ
# export PointT, PointXYZ, PointXYZRGB, PointXYZRGBA
# export PCLHeader, PointCloud

# bring in the types
include("entities/PCLTypes.jl")
# bring in further source code
include("services/PointCloud.jl")

function __init__()
  @require RobotOS="22415677-39a4-5241-a37a-00beabbbdae8" include("services/ROSConversions.jl")
end

end

ext: jl


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

mutable struct StorageAccountUpdateParameters <: SwaggerModel
    sku::Any # spec type: Union{ Nothing, Sku } # spec name: sku
    tags::Any # spec type: Union{ Nothing, Dict{String, String} } # spec name: tags
    identity::Any # spec type: Union{ Nothing, Identity } # spec name: identity
    properties::Any # spec type: Union{ Nothing, StorageAccountPropertiesUpdateParameters } # spec name: properties

    function StorageAccountUpdateParameters(;sku=nothing, tags=nothing, identity=nothing, properties=nothing)
        o = new()
        validate_property(StorageAccountUpdateParameters, Symbol("sku"), sku)
        setfield!(o, Symbol("sku"), sku)
        validate_property(StorageAccountUpdateParameters, Symbol("tags"), tags)
        setfield!(o, Symbol("tags"), tags)
        validate_property(StorageAccountUpdateParameters, Symbol("identity"), identity)
        setfield!(o, Symbol("identity"), identity)
        validate_property(StorageAccountUpdateParameters, Symbol("properties"), properties)
        setfield!(o, Symbol("properties"), properties)
        o
    end
end # type StorageAccountUpdateParameters

const _property_map_StorageAccountUpdateParameters = Dict{Symbol,Symbol}(Symbol("sku")=>Symbol("sku"), Symbol("tags")=>Symbol("tags"), Symbol("identity")=>Symbol("identity"), Symbol("properties")=>Symbol("properties"))
const _property_types_StorageAccountUpdateParameters = Dict{Symbol,String}(Symbol("sku")=>"Sku", Symbol("tags")=>"Dict{String, String}", Symbol("identity")=>"Identity", Symbol("properties")=>"StorageAccountPropertiesUpdateParameters")
Base.propertynames(::Type{ StorageAccountUpdateParameters }) = collect(keys(_property_map_StorageAccountUpdateParameters))
Swagger.property_type(::Type{ StorageAccountUpdateParameters }, name::Symbol) = Union{Nothing,eval(Meta.parse(_property_types_StorageAccountUpdateParameters[name]))}
Swagger.field_name(::Type{ StorageAccountUpdateParameters }, property_name::Symbol) =  _property_map_StorageAccountUpdateParameters[property_name]

function check_required(o::StorageAccountUpdateParameters)
    true
end

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


text:
# This file is part of Kpax3. License is MIT.

function test_write_results()
  ifile = "data/read_proper_aa.fasta"
  ofile = "../build/test"
  partition = "data/output_fasta_proper_aa_partition.csv"

  settings = Kpax3.KSettings(ifile, ofile, gamma=[0.4; 0.35; 0.25])

  x = Kpax3.AminoAcidData(settings)

  R = Kpax3.normalizepartition(partition, x.id)
  k = maximum(R)

  priorR = Kpax3.EwensPitman(settings.α, settings.θ)
  priorC = Kpax3.AminoAcidPriorCol(x.data, settings.γ, settings.r)

  state = Kpax3.AminoAcidState(x.data, R, priorR, priorC, settings)

  Kpax3.writeresults(x, state, "../build/test_results", what=4)

  y1 = read("../build/test_results_partition.csv", String)
  y2 = parse(Float64, strip(read("../build/test_results_logposterior_value.txt", String)))
  y3 = read("../build/test_results_attributes.csv", String)
  y4 = read("../build/test_results_characteristic.csv", String)
  y5 = read("../build/test_results_dataset.txt", String)

  @test y1 == read(partition, String)
  @test isapprox(y2, state.logpp, rtol=ε)
  @test y3 == read("data/output_fasta_proper_aa_attributes.csv", String)
  @test y4 == read("data/output_fasta_proper_aa_characteristic.csv", String)
  @test y5 == read("data/output_fasta_proper_aa_dataset.txt", String)

  nothing
end

test_write_results()


text:
module ShaleDrillingLikelihood_DynamicDrillModel_Simulation

DOBTIME = false
DOPROFILE = false

using ShaleDrillingLikelihood
using Test
using SparseArrays
using BenchmarkTools
using Calculus
using Random
using InteractiveUtils
using Distributions
using Dates
using StatsBase
using Optim
using CountPlus
using LinearAlgebra
using Profile
# using PProf
using Juno
# if DOPROFILE
#     using ProfileView
# end

using Optim: minimizer, minimum, maximize, maximizer, maximum

using Base.Iterators: product, OneTo

using ShaleDrillingLikelihood: ObservationDrill,
    SimulationDraw,
    idx_ρ,
    actionspace,
    ichars_sample,
    j1chars,
    tptr,
    _x, _y,
    zchars,
    ztrange,
    InitialDrilling,
    _i,
    j1_sample,
    j1_range,
    jtstart,
    exploratory_terminal,
    ssprime,
    total_leases,
    zero_out_small_probs,
    lrvar,
    lrstd,
    lrmean,
    simulate,
    theta_royalty_ρ,
    revenue,
    cost,
    extend,
    theta_ρ,
    vw_revenue,
    vw_cost,
    vw_extend,
    DataDynamicDrill,
    max_states,
    _D,
    simloglik!,
    simloglik_drill_data!,
    SimulationDraws,
    DCDPTmpVars,
    _model,
    theta_drill_ρ,
    update!,
    value_function,
    EV, dEV,
    _x, _y,
    end_ex0, end_ex1, end_lrn, end_inf,
    state_idx,
    j2ptr, tptr,
    idx_produce_ψ, idx_drill_ψ,
    idx_produce_g, idx_drill_g,
    merge_thetas,
    split_thetas,
    theta_produce

println("print to keep from blowing up")

@testset "Simulate Dynamic Drilling Model" begin

    Random.seed!(1234)
    f = DrillReward(DrillingRevenue(Constrained(),NoTrend(),NoTaxes()), DrillingCost_constant(), ExtensionCost_Constant())
    num_parms = _nparm(f)

    # dimensions of state space
    nψ, _dmax, nz =  13, 3, 21

    # number of obs
    num_zt = 100
    num_i = 5

    # psi
    ψs = range(-4.5; stop=4.5, length=nψ)

    # price process
    # ----------------------------------

    # define price process
    zrho = 0.8 # AR1 parameter
    zprocess = AR1process(0.8, 1.33*(1-zrho), 0.265^2*(1-zrho^2))

    # simulate price process
    zvec = simulate(zprocess, num_zt)
    ztrng = range(Date(2003,10); step=Dates.Quarter(1), length=num_zt)
    _zchars = ExogTimeVars(tuple.(zvec), ztrng)

    # grid for price process
    zmin = min(minimum(zvec), lrmean(zprocess)-3*lrstd(zprocess))
    zmax = max(maximum(zvec), lrmean(zprocess)+3*lrstd(zprocess))
    zrng = range(zmin, zmax; length=nz)
    zs = ( zrng, )
    @test prod(length.(zs)) == nz

    # transition for price process
    ztrans = sparse(zero_out_small_probs(tauchen_1d(zprocess, zrng), 1e-4))
    # ztrans = spdiagm(-1 => fill(1.0/3, nz-1), 0 => fill(1.0/3, nz), 1 => fill(1.0/3, nz-1) )
    # ztrans[1,1] = ztrans[1,2] = ztrans[end,end-1] = ztrans[end,end] = 0.5

    # wp = LeasedProblemContsDrill(dmx,4,5,3,2)
    wp = LeasedProblem(_dmax,4,5,3,2)

    # ichars
    ichar = (4.0, 0.25,)

    # ddm object
    ddm_no_t1ev   = DynamicDrillModel(f, 0.9, wp, zs, ztrans, ψs, false)
    ddm_with_t1ev = DynamicDrillModel(f, 0.9, wp, zs, ztrans, ψs, true)
    tmpv = DCDPTmpVars(ddm_no_t1ev)

    theta = [-4.0, -1.0, -3.0, 0.7]
    @test length(theta) == num_parms

    u,v = randn(num_i), randn(num_i)

    for ddm in (ddm_with_t1ev, ddm_no_t1ev,)
        _ichars = ichars_sample(ddm, num_i)
        datanew = ShaleDrillingLikelihood.DataDynamicDrill(
            u, v, _zchars, _ichars, ddm, theta;
            minmaxleases=2:5,
            nper_initial=10:15,
            tstart=1:10
        )
    end

end

@testset "simulate all data" begin

    Random.seed!(7)

    discount = ((0x1.006b55c832502p+0)^12 / 1.125) ^ (1/4)  # real discount rate

    # set up coefs
    θρ =  0.0
    αψ = 0.33
    αg = 0.56

    # set up coefs
    #            θρ  ψ        g    x_r     κ₁   κ₂
    θ_royalty = [θρ, 1.0,    0.1, -0.3,  -0.6, 0.6]
    #                αψ, αg, γx   σ2η, σ2u   # η is iwt, u is iw
    θ_produce = vcat(αψ, αg, 0.2, 0.3, 0.4)
    #            drill  ext    α0  αg  αψ  θρ
    θ_drill_u = [-5.5, -2.0, -2.8, αg, αψ, θρ]
    # θ_drill_u = [-5.8,       -2.8, αg, αψ, θρ]
    θ_drill_c = vcat(θ_drill_u[1:3], θρ)

    # model
    rwrd_c = DrillReward(DrillingRevenue(Constrained(;log_ogip=αg, α_ψ=αψ),NoTrend(),NoTaxes()), DrillingCost_constant(), ExtensionCost_Constant())
    rwrd_u = UnconstrainedProblem(rwrd_c)
    rwrd = rwrd_u
    @test _nparm(rwrd) == length(θ_drill_u)

    # parms
    num_i = 15

    # grid sizes
    nψ =  13
    nz = 15

    # simulations
    M = 250

    # observations
    num_zt = 150          # drilling
    obs_per_well = 10:20  # pdxn

    # roylaty
    royalty_rates = [1/8, 3/16, 1/4,]
    num_royalty_rates = length(royalty_rates)
    nk_royalty = length(θ_royalty) - (length(royalty_rates)-1)-2

    # geology
    ogip_dist = Normal(4.68,0.31)

    # price parameters
    zrho = 0.8                # rho
    zmean = 1.33*(1-zrho)     # mu
    zvar = 0.265^2*(1-zrho^2) # sigsq

    # state space, psi-space
    # wp = LeasedProblem(_dmax,4,5,3,2)
    # wp = LeasedProblem(8, 8, 30, 20, 8)
    wp = LeasedProblem(8, 8, 12, 12, 8)
    ψs = range(-4.5; stop=4.5, length=nψ)

    # simulate price process
    zprocess = AR1process(zmean, zrho, zvar)
    zvec = simulate(zprocess, num_zt)
    ztrng = range(Date(2003,10); step=Dates.Quarter(1), length=num_zt)
    _zchars = ExogTimeVars(tuple.(zvec), ztrng)

    # price grid2
    zmin = min(minimum(zvec), lrmean(zprocess)-3*lrstd(zprocess))
    zmax = max(maximum(zvec), lrmean(zprocess)+3*lrstd(zprocess))
    zrng = range(zmin, zmax; length=nz)
    zs = tuple(zrng)
    @test prod(length.(zs)) == nz
    ztrans = sparse(zero_out_small_probs(tauchen_1d(zprocess, zrng), 1e-4))
    @test all(isfinite.(ztrans))

    # random vars
    log_ogip = rand(ogip_dist, num_i)
    Xroyalty = vcat(log_ogip', randn(nk_royalty-1, num_i))
    u,v = randn(num_i), randn(num_i)

    # model
    ddm_no_t1ev     = DynamicDrillModel(rwrd_u, discount, wp, zs, ztrans, ψs, false)
    ddm_with_t1ev   = DynamicDrillModel(rwrd_u, discount, wp, zs, ztrans, ψs, true)
    ddm_c_no_t1ev   = DynamicDrillModel(rwrd_c, discount, wp, zs, ztrans, ψs, false)
    ddm_c_with_t1ev = DynamicDrillModel(rwrd_c, discount, wp, zs, ztrans, ψs, true)

    # construct royalty data
    data_roy = DataRoyalty(u, v, Xroyalty, θ_royalty, num_royalty_rates)
    royrates_endog = royalty_rates[_y(data_roy)]
    royrates_exog = sample(royalty_rates, num_i)

    # construct ichars for drilling
    _ichars = [gr for gr in zip(log_ogip, royrates_exog)]

    # construct drilling data
    # ddm_opts = (minmaxleases=1:1, nper_initial=40:40, tstart=1:50)
    # data_drill_w = DataDynamicDrill(u, v, _zchars, _ichars, ddm_with_t1ev, θ_drill_u; ddm_opts...)
    # data_drill_n = DataDynamicDrill(u, v, _zchars, _ichars, ddm_no_t1ev,   θ_drill_u; ddm_opts...)
    ddm_opts = (minmaxleases=0:0, nper_initial=0:0, nper_development=60:60, tstart=1:75, xdomain=0:0)
    data_drill_w = DataDrill(u, v, _zchars, _ichars, ddm_with_t1ev, θ_drill_u; ddm_opts...)
    data_drill_n = DataDrill(u, v, _zchars, _ichars, ddm_no_t1ev,   θ_drill_u; ddm_opts...)

    # constrained versions of above
    data_drill_w_con = DataDrill(data_drill_w, ddm_c_with_t1ev)
    data_drill_n_con = DataDrill(data_drill_n, ddm_c_no_t1ev  )

    # number of wells drilled
    nwells_w = map(s -> _D(wp,s), max_states(data_drill_w))
    nwells_n = map(s -> _D(wp,s), max_states(data_drill_n))

    # @show sort(countmap(nwells_w))
    # @show sort(countmap(nwells_n))

    data_produce_w = DataProduce(u, nwells_w, obs_per_well, θ_produce, log_ogip)
    data_produce_n = DataProduce(u, nwells_n, obs_per_well, θ_produce, log_ogip)

    @test sum(nwells_w .> 0) == length(Set(view(_x(data_produce_w), 1, :)))
    @test sum(nwells_n .> 0) == length(Set(view(_x(data_produce_n), 1, :)))

    @testset "Big Joint model" begin

        data_d_sm = data_drill_w_con
        data_d_lg = data_drill_w
        data_p    = data_produce_w
        data_r    = data_roy
        empty = EmptyDataSet()

        coef_links = [(idx_produce_ψ, idx_drill_ψ,), (idx_produce_g, idx_drill_g)]

        data_dril = DataSetofSets(data_d_sm, empty, empty)
        data_full = DataSetofSets(data_d_lg, data_r, data_p, coef_links)
        data_royp = DataSetofSets(empty, data_r, data_p)

        theta_dril = θ_drill_c
        theta_tuple = (θ_drill_u, θ_royalty, θ_produce)
        theta_full = merge_thetas(theta_tuple, data_full)
        theta_royp = vcat(θ_royalty, θ_produce)

        @test theta_produce(data_produce_w, θ_produce)[idx_produce_g(data_produce_w)] == αg
        @test theta_produce(data_produce_n, θ_produce)[idx_produce_g(data_produce_n)] == αg

        @test data_full isa DataFull

        function dochecks(thet, data; M=50)
            sim = SimulationDraws(data, M)
            k = length(thet)
            n = ShaleDrillingLikelihood.num_i(data)
            grad = zeros(k)
            hess = zeros(k,k)
            tmpg = zeros(k,n)

            theta_vw = split_thetas(data, thet)
            @test length.(theta_vw) == _nparm.(data)
            @test last(size(sim)) == n

            simloglik!(grad, hess, tmpg, data, thet, sim, false)
            @test all(grad .== 0)
            simloglik!(grad, hess, tmpg, data, thet, sim, true)
            angrad = copy(grad)

            f(xx) = simloglik!(grad, hess, tmpg, data, xx, sim, false)
            fd = Calculus.gradient(f, thet, :central)
            @test fd ≈ angrad
        end

        dochecks(theta_dril, data_dril)
        dochecks(theta_royp, data_royp)
        dochecks(theta_full, data_full)

        if DOPROFILE
            @testset "timing for biglik" begin
                data = data_full
                thet = theta_full
                M = 500
                sim = SimulationDraws(data,M)
                k = length(thet)
                n = ShaleDrillingLikelihood.num_i(data)
                grad = zeros(k)
                hess = zeros(k,k)
                tmpg = zeros(k,n)
                Profile.clear()
                @profile simloglik!(grad, hess, tmpg, data, thet, sim, true)
                Juno.profiletree()
                Juno.profiler()
            end
        end

    end

    if false
    @testset "Test dynamic Drilling model gradients" begin
        data = data_drill_n_con
        theta = θ_drill_c
        ddm = _model(data)
        vf = value_function(ddm)

        @test data isa DataDrill
        sim = SimulationDraws(M, data)
        nparm = _nparm(data)
        @test nparm == length(theta)
        grad = zeros(nparm)
        hess = zeros(nparm, nparm)
        tmpgrads = zeros(nparm, num_i)

        println("simloglik, no grad")
        simloglik_drill_data!(grad, hess, data, theta, sim, false)
        @test all(grad .== 0)
        println("simloglik, with grad")
        simloglik_drill_data!(grad, hess, data, theta, sim, true)
        @test all(isfinite.(EV(vf)))
        @test all(isfinite.(dEV(vf)))
        @test all(isfinite.(grad))

        # println("simloglik finite diff")
        # fd = Calculus.gradient(xx -> simloglik_drill_data!(grad, hess, data, xx, sim, false), theta, :central)
        #
        # fill!(grad,0)
        # fill!(hess,0)
        # println("simloglik gradient")
        # simloglik_drill_data!(grad, hess, data, theta, sim, true, true)
        # @test !all(grad.==0)
        # @test all(isfinite.(grad))
        # @test all(isfinite.(hess))
        # @test isapprox(fd, grad; rtol=2e-5)
        # println("done")

        if DOBTIME
            print("")
            @show @benchmark simloglik_drill_data!($grad, $hess, $data, $theta, $sim, false)
            @show @benchmark simloglik_drill_data!($grad, $hess, $data, $theta, $sim, true)
            print("")
        end

        # if DOPROFILE
        #     Profile.clear()
        #     @profile simloglik_drill_data!(grad, hess, data, theta, sim, true, true)
        #     Juno.profiletree()
        #     Juno.profiler()
        #     # Profile.print()
        #     # ProfileView.view()
        #     # pprof()
        #
        # end

    end

    @testset "Dynamic Drilling Model optimize" begin
        data = data_drill_w_con
        # theta = [-0x1.70fd6ff5b951p+2, -0x1.58566f20326a4p-1, -0x1.4fe0e4a9cd48bp+1, 0x1.26c2c754b506ap+2, ]
        theta = θ_drill_c
        sim = SimulationDraws(M, data)

        nparm = _nparm(data)
        grad = zeros(nparm)
        hess = zeros(nparm, nparm)

        simloglik_drill_data!(grad, hess, data, theta, sim, false)

        function f(x)
            LL = simloglik_drill_data!(grad, hess, data, x, sim, false, false)
            countplus!(LL,x)
            return -LL
        end

        function fg!(grad, x)
            fill!(grad,0)
            LL = simloglik_drill_data!(grad, hess, data, x, sim, true, false)
            countplus!(LL,x)
            grad .*= -1
            return -LL
        end

        function h!(hess, x)
            fill!(grad,0)
            fill!(hess,0)
            LL = simloglik_drill_data!(grad, hess, data, x, sim, true, true)
            countplus!(LL,x)
            grad .*= -1
            return -LL
        end

        function invH0(x::AbstractVector)
            h!(hess, x)
            return inv(hess)
        end

        println("getting ready to optmize")
        odfg  = OnceDifferentiable(f, fg!, fg!, theta)
        tdfgh = TwiceDifferentiable(f, fg!, fg!, h!, theta)
        startcount!([100, 200, 500, 100000,], [1, 5, 5, 5,])
        resetcount!()
        max_time_sec = 30*60
        opts = Optim.Options(allow_f_increases=true, show_trace=true, time_limit=max_time_sec)
        res = optimize(tdfgh, theta, BFGS(;initial_invH = invH0), opts)
        # res = optimize(tdfgh, theta*0.9, BFGS(), opts)
        @show res
        @show minimizer(res), theta

        vcovinv = invH0(minimizer(res))
        se = sqrt.(diag(vcovinv))
        tstats = minimizer(res) ./ se
        pvals = cdf.(Normal(), -2*abs.(tstats))
        coef_and_se = hcat(theta, minimizer(res), se, tstats, pvals)

        # θ_drill_u = [-6.5, -0.85, -2.8, αg, αψ, θρ]
        # θ_drill_u = [-5.0, -0.85, -2.7, 0.56, 0.33, 0.5]
        # θ_drill_c = [-5.0, -0.85, -2.7, 0.5]

        err = theta .- minimizer(res)
        waldtest = err'*vcovinv*err
        @show ccdf(Chisq(length(theta)), waldtest) > 0.05
        @show coef_and_se
        # Base.showarray(stdout, coef_and_se)
    end
    end

end

end # module


text:
module NAG
export
    nag_licence_query, nag_license_query,
    nag_complex_polygamma,
    nag_opt_read!,
    nag_opt_nlp!,
    nag_1d_quad_inf_1,
    nag_zero_cont_func_brent,
    nag_opt_lp!,
    last_nag_error

nag_licence_query() = ccall((:a00acc, :libnagc_nag), Cint, ()) == 1
const nag_license_query = nag_licence_query # US vs UK spelling
nag_license_query() || warn("Cannot acquire a NAG license.")

const NagInt = Int32
const NagComplex = Complex128

type NagError <: Exception
    code::Int
    name::ASCIIString
    message::UTF8String
end

Base.showerror(io::IO, e::NagError) =
    print(io, "NAG function \"$(e.name)\" [$(e.code)] – $(e.message)")

const NAG_ERROR = zeros(Uint8,544)
const nag_errors = Array(NagError)
nag_errors[] = NagError(0, "", "NO_ERROR")

cstr_to_array(p::Ptr{Uint8}, own::Bool = false) =
    pointer_to_array(p, int(ccall(:strlen, Csize_t, (Ptr{Uint8},), p)), own)

function error_handler(msg::Ptr{Uint8}, code::Cint, name::Ptr{Uint8})
    code == 0 && return
    msg = UTF8String(copy(cstr_to_array(msg)))
    name = ASCIIString(copy(cstr_to_array(name)))
    nag_errors[] = NagError(int(code), name, msg)
    throw(nag_errors[])
end
const ptr_error_handler = cfunction(error_handler, Void, (Ptr{Uint8}, Cint, Ptr{Uint8}))

function reset_nag_error()
    fill!(NAG_ERROR, 0)
    unsafe_store!(
        convert(Ptr{Ptr{Void}}, pointer(NAG_ERROR)) + 2*sizeof(Cint) + 512,
        ptr_error_handler
    )
end
reset_nag_error()

last_nag_error() = nag_errors[]

const objfunref = Array(Function)
const confunref = Array(Function)

function objfun_wrapper(
    n::NagInt, x::Ptr{Float64}, objf::Ptr{Float64}, g::Ptr{Float64}, comm::Ptr{NagInt}
)
    x = pointer_to_array(x,int(n),false)
    g = pointer_to_array(g,int(n),false)
    f = unsafe_load(comm)
    unsafe_store!(objf,objfunref[1](x,g,f))
    return nothing
end
const c_objfun = cfunction(objfun_wrapper, Void,
    (NagInt, Ptr{Float64}, Ptr{Float64}, Ptr{Float64}, Ptr{NagInt}))

function confun_wrapper(
    n::NagInt, ncnlin::NagInt, needc::Ptr{NagInt}, x::Ptr{Float64},
    conf::Ptr{Float64}, conjac::Ptr{Float64}, comm::Ptr{NagInt}
)
    needc  = pointer_to_array(needc,int(ncnlin),false)
    x      = pointer_to_array(x,int(n),false)
    conf   = pointer_to_array(conf,int(ncnlin),false)
    conjac = pointer_to_array(conjac,(int(n),int(ncnlin)),false)
    flag   = unsafe_load(comm)
    confunref[1](needc,x,conf,conjac,flag)
    return nothing
end
const c_confun = cfunction(confun_wrapper, Void,
    (NagInt, NagInt, Ptr{NagInt}, Ptr{Float64}, Ptr{Float64}, Ptr{Float64}, Ptr{NagInt}))

function nag_complex_polygamma(z::Number, k::Integer)
    ccall((:s14afc, :libnagc_nag), NagComplex,
          (NagComplex, NagInt, Ptr{Void}),
          z, k, NAG_ERROR)
end

# if Base.polygamma doesn't support complex args, use NAG
if !applicable(Base.polygamma, 1, 1+2im)
    Base.polygamma(k::Int, z::Complex) = nag_complex_polygamma(z, k)
    Base.digamma(z::Complex) = polygamma(0, z)
    Base.trigamma(z::Complex) = polygamma(1, z)
end

function nag_opt_read!(name::ByteString, optfile::ByteString, print::Bool = false)
    options = zeros(Uint8,1440)
    ccall((:e04xxc, :libnagc_nag), Void, (Ptr{Void},), options)
    ccall((:e04xyc, :libnagc_nag), Void,
          (Ptr{Uint8}, Ptr{Uint8}, Ptr{Void}, Cint, Ptr{Uint8}, Ptr{Void}),
          name, optfile, options, print, "stdout", NAG_ERROR)
    return options
end

function nag_opt_lp!(
    A         :: Matrix{Float64},
    bl        :: Vector{Float64},
    bu        :: Vector{Float64},
    c         :: Vector{Float64},
    x         :: Vector{Float64};
    optfile   :: ByteString = "",
    transpose :: Bool = true,
)
    # since NAG is row-major
    #   when transpose == true the rows are linear constraints
    #   when transpose == false the columns are linear constraints
    transpose && (A = A')

    n = length(c)
    tda, nclin = size(A)

    nclin > 0 && tda >= n   ||
        error("bad linear constraint dimensions (tda ≱ n): $tda ≱ $n")
    length(bl) == n + nclin ||
        error("wrong number of lower bounds: $(length(bl)) ≠ $(n + nclin)")
    length(bu) == n + nclin ||
        error("wrong number of upper bounds: $(length(bu)) ≠ $(n + nclin)")
    length(c) == n          ||
        error("wrong number of coefficients: $(length(c)) ≠ $n")
    length(x) == n          ||
        error("wrong data vector size: $(length(x)) ≠ $n")

    objf = zeros()
    options = isempty(optfile) ? C_NULL :
        convert(Ptr{Void}, nag_opt_read!("e04mfc", optfile))

    reset_nag_error()
    ccall((:e04mfc,:libnagc_nag), Void,
           (NagInt, NagInt, Ptr{Float64}, NagInt, Ptr{Float64}, Ptr{Float64},
            Ptr{Float64}, Ptr{Float64}, Ptr{Float64}, Ptr{Void}, Ptr{Void}, Ptr{Void}),
           n, nclin, A, tda, bl, bu, c, x, objf, options, C_NULL, NAG_ERROR)

    return x, objf[]
end

function nag_opt_nlp!(
    A  :: Matrix{Float64},
    bl :: Vector{Float64},
    bu :: Vector{Float64},
    x  :: Vector{Float64},
    objfun! :: Function,
    confun! :: Function,
    optfile :: ByteString = "",
    transpose :: Bool = true,
)
    # since NAG is row-major
    #   when transpose == true the rows are linear constraints
    #   when transpose == false the columns are linear constraints
    transpose && (A = A')

    # extract various dimensions
    n = length(x)
    tda, nclin = size(A)
    ncnlin = length(bl) - n - nclin

    # check for usage problems
    length(bl) == length(bu) ||
        error("bounds vectors must have matching length")
    lexcmp(bl,bu) <= 0       ||
        error("lower bounds cannot be greater than upper bounds")
    0 <= ncnlin              ||
        error("as many bounds as variables and linear constraints must be given")
    nclin == 0 || n <= tda   ||
        error("second dimension of linear coefficients too small")

    # allocate output variables
    objf = zeros()
    g = zeros(n)

    # save callbacks in globals
    objfunref[1] = objfun!
    confunref[1] = confun!

    options = isempty(optfile) ? C_NULL :
        convert(Ptr{Void}, nag_opt_read!("e04ucc", optfile))

    reset_nag_error()
    ccall((:e04ucc, :libnagc_nag), Void,
          (NagInt, NagInt, NagInt, Ptr{Float64},
           NagInt, Ptr{Float64}, Ptr{Float64},
           Ptr{Void}, Ptr{Void},
           Ptr{Float64}, Ptr{Float64}, Ptr{Float64},
           Ptr{Void}, Ptr{Void}, Ptr{Void}),
          n, nclin, ncnlin, A,
          tda, bl, bu,
          c_objfun, c_confun,
          x, objf, g,
          options, C_NULL, NAG_ERROR)

    return x, objf[], g
end

const quadfunref = Array(Function)
quad_fun_wrapper(x::Float64, comm::Ptr{NagInt}) = quadfunref[1](x)::Float64
const c_quadfun = cfunction(quad_fun_wrapper, Float64, (Float64, Ptr{NagInt}))

function nag_1d_quad_inf_1(
    f :: Function,
    boundinf :: Symbol = :Infinite,
    bound :: Float64 = 0.0;
    epsabs :: Float64 = 0.0,
    epsrel :: Float64 = sqrt(eps(Float64)),
    max_num_subint :: NagInt = int32(1e7),
)
    max_num_subint > 0 || error("max num subint must be > 0")
    boundinf_val =
        boundinf == :UpperSemiInfinite ? int32(1076 + 0) :
        boundinf == :LowerSemiInfinite ? int32(1076 + 1) :
        boundinf == :Infinite          ? int32(1076 + 2) :
        error("""
        invalid boundinf symbol: $boundinf
        must be one of: UpperSemiInfinite, LowerSemiInfinite, Infinite
        """)

    # allocate output variables
    result = zeros()
    abserr = zeros()
    qp = zeros(Uint8, 48)
    comm = zeros(Uint8, 8)

    quadfunref[] = f

    reset_nag_error()
    ccall((:d01smc, :libnagc_nag), Void,
        (Ptr{Void}, NagInt, Float64, Float64,
         Float64, NagInt, Ptr{Float64}, Ptr{Float64},
         Ptr{Void}, Ptr{Void}, Ptr{Void}),
        c_quadfun, boundinf_val, bound, epsabs,
        epsrel, max_num_subint, result, abserr,
        qp, comm, NAG_ERROR)

    return result[], abserr[]
end

const quadfunref_brent = Array(Function)
quad_fun_wrapper_brent(x::Float64, comm::Ptr{NagInt}) = quadfunref_brent[1](x)::Float64
const c_quadfun_brent = cfunction(quad_fun_wrapper_brent, Float64, (Float64, Ptr{NagInt}))

function nag_zero_cont_func_brent(
    a :: Float64,
    b :: Float64,
    f :: Function;
    eps :: Float64 = 1e-5,
    eta :: Float64 = 0.0,
)
    f(a)*f(b) <= 0 || error("f(a)*f(b) must be <= 0")
    quadfunref_brent[1] = f

    x = zeros()
    comm = zeros(Uint8, 8)

    reset_nag_error()
    ccall((:c05ayc, :libnagc_nag), Void,
        (Float64, Float64, Float64, Float64,
         Ptr{Void}, Ptr{Float64}, Ptr{Void}, Ptr{Void}),
        a, b, eps, eta, NAG.c_quadfun_brent, x, comm, NAG_ERROR)

    return x[]
end

end # module


text:
using DataDeps

register(DataDep(
  "car-evaluation",
  "http://archive.ics.uci.edu/ml/datasets/Car+Evaluation",
  "http://archive.ics.uci.edu/ml/machine-learning-databases/car/car.data",
  "b703a9ac69f11e64ce8c223c0a40de4d2e9d769f7fb20be5f8f2e8a619893d83",
  post_fetch_method=(path -> begin
    UCIData.process_dataset(path,
        target_index=7,
        feature_indices=1:6,
        categoric_indices=1:6,
    )
  end),
))

max_stars_repo_name: JackDunnNZ/uci-data

max_issues_repo_name: JackDunnNZ/uci-data

max_forks_repo_name: JackDunnNZ/uci-data