text:
# MIT license
# Copyright (c) Microsoft Corporation. All rights reserved.
# See LICENSE in the project root for full license information.

export cooketriplet, doubleconvexlensonly

# Create a geometric hemisphere
function hemisphere()::CSGTree
    sph = Sphere(10.0)
    pln = Plane(0.0, 0.0, -1.0, 0.0, 0.0, 0.0)
    csgintersection(sph, pln)() #csg operations create a csggenerator which instantiates the csg tree after applying a rigid body transformation. This allows you to make as many instances of the object as you want with different transformations. We just want the CSGTree object rather than a generator.
end

# Create an optical hemisphere that has optical material properties so it will reflect and refract light. In the previous example the hemisphere object had optical properties of OpticSim.GlassCat.Air, which is the default optical interface, so it won't refract or reflect light.
function opticalhemisphere()::CSGOpticalSystem
    sph = Sphere(10.0, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air))
    pln = Plane(0.0, 0.0, -1.0, 0.0, 0.0, 0.0, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air))
    assy = LensAssembly{Float64}(csgintersection(sph, pln)())
    return CSGOpticalSystem(assy, Rectangle(1.0, 1.0, SVector{3,Float64}(0.0, 0.0, 1.0), SVector{3,Float64}(0.0, 0.0, -11.0)))
end

#! format: off

cooketriplet(::Type{T} = Float64, detpix::Int = 1000) where {T<:Real} = AxisymmetricOpticalSystem{T}(
    DataFrame(Surface = [:Object, 1, 2, 3, :Stop, 5, 6, :Image],
              Radius = [Inf, 26.777, 66.604, -35.571, 35.571, 35.571, -26.777, Inf],
              OptimizeRadius = [false,true,true,true,true,true,true,false],
              Thickness = [Inf, 4.0, 2.0, 4.0, 2.0, 4.0, 44.748, missing],
              OptimizeThickness = [false,true,true,true,true,true,true,false],
              Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SF2, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, missing],
              SemiDiameter = [Inf, 8.580, 7.513, 7.054, 6.033, 7.003, 7.506, 15.0]), detpix, detpix)

cooketripletfirstelement(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem(
    DataFrame(Surface = [:Object, 1, 2, :Image],
              Radius = [Inf, -35.571, 35.571, Inf],
              Thickness = [Inf, 4.0, 44.748, missing],
              Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_SK16, OpticSim.GlassCat.Air, missing],
              SemiDiameter = [Inf, 7.054, 6.033, 15.0]))

convexplano(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}(
    DataFrame(Surface = [:Object, 1, 2, :Image],
              Radius = [Inf, 60.0, Inf, Inf],
              Thickness = [Inf, 10.0, 57.8, missing],
              Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing],
              SemiDiameter = [Inf, 9.0, 9.0, 15.0]))

doubleconvex(frontradius::T,rearradius::T) where{T<:Real} =
AxisymmetricOpticalSystem{T}(
    DataFrame(Surface = [:Object, 1, 2, :Image],
              Radius = [T(Inf64), frontradius, rearradius, T(Inf64)],
              OptimizeRadius = [false,true,true,false],
              Thickness = [T(Inf64), T(10.0), T(57.8), missing],
              OptimizeThickness = [false,false,false,false],
              Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing],
              SemiDiameter = [T(Inf64), T(9.0), T(9.0), T(15.0)]))

doubleconvexconic(::Type{T} = Float64) where {T<:Real} =
              AxisymmetricOpticalSystem{T}(
                  DataFrame(Surface = [:Object, 1, 2, :Image],
                            Radius = [Inf64, 60, -60, Inf64],
                            OptimizeRadius = [false,true,true,false],
                            Thickness = [Inf64, 10.0, 57.8, missing],
                            OptimizeThickness = [false,false,false,false],
                            Conic = [missing, 0.01, 0.01, missing],
                            OptimizeConic = [false, true, true, false],
                            Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing],
                            SemiDiameter = [Inf64, 9.0, 9.0, 15.0]))

doubleconvexlensonly(frontradius::T,rearradius::T) where{T<:Real} =
AxisymmetricLens{T}(
    DataFrame(Surface = [:Object, 1, 2, :Image],
              Radius = [T(Inf64), frontradius, rearradius, T(Inf64)],
              OptimizeRadius = [false,true,true,false],
              Thickness = [T(Inf64), T(10.0), T(57.8), missing],
              OptimizeThickness = [false,false,false,false],
              Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing],
              SemiDiameter = [T(Inf64), T(9.0), T(9.0), T(15.0)]))

doubleconvexprescription() = DataFrame(
    Surface = [:Object, 1, 2, :Image],
    Radius = [Inf64, 60, -60, Inf64],
    OptimizeRadius = [false,true,true,false],
    Thickness = [Inf64, 10.0, 57.8, missing],
    OptimizeThickness = [false,true,true,false],
    Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing],
    SemiDiameter = [Inf64, 9.0, 9.0, 15.0])

doubleconvex(::Type{T} = Float64; temperature::Unitful.Temperature = OpticSim.GlassCat.TEMP_REF_UNITFUL, pressure::T = T(OpticSim.GlassCat.PRESSURE_REF)) where {T<:Real} = AxisymmetricOpticalSystem{T}(doubleconvexprescription(),temperature = temperature, pressure = pressure)

doubleconcave(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}(
    DataFrame(Surface = [:Object, 1, 2, :Image],
              Radius = [Inf64, -41.0, 41.0, Inf64],
              Thickness = [Inf64, 10.0, 57.8, missing],
              Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing],
              SemiDiameter = [Inf64, 9.0, 9.0, 15.0]))

planoconcaverefl(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}(
    DataFrame(Surface = [:Object, 1, 2, :Image],
              Radius = [Inf64, Inf64, -41.0, Inf64],
              Thickness = [Inf64, 10.0, -57.8, missing],
              Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing],
              SemiDiameter = [Inf64, 9.0, 9.0, 25.0],
              Reflectance = [missing, missing, 1.0, missing]))

concaveplano(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}(
    DataFrame(Surface = [:Object, 1, 2, :Image],
              Radius = [Inf64, -41.0, Inf64, Inf64],
              Thickness = [Inf64, 10.0, 57.8, missing],
              Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing],
              SemiDiameter = [Inf64, 9.0, 9.0, 15.0]))

planoplano(::Type{T} = Float64) where {T<:Real} = AxisymmetricOpticalSystem{T}(
    DataFrame(Surface = [:Object, 1, 2, :Image],
              Radius = [Inf64, Inf64, Inf64, Inf64],
              Thickness = [Inf64, 10.0, 57.8, missing],
              Material = [OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, missing],
              SemiDiameter = [Inf64, 9.0, 9.0, 15.0]))

#! format: on

function autodrawrays(lens::AxisymmetricOpticalSystem = cooketriplet(), angle = 10; kwargs...)
    f1 = HexapolarField(lens, collimated = true, wavelength = 0.45, sourcenum = 1)
    Vis.drawtracerays(lens, raygenerator = f1, test = true, trackallrays = true, colorbysourcenum = true; kwargs...)
    f2 = HexapolarField(lens, collimated = true, wavelength = 0.45, sourceangle = angle / 180 * π, sourcenum = 2)
    Vis.drawtracerays!(lens, raygenerator = f2, test = true, trackallrays = true, colorbysourcenum = true; kwargs...)
end

function autospotdiag(lens::AxisymmetricOpticalSystem = cooketriplet(); kwargs...)
    f1 = HexapolarField(lens, collimated = true, wavelength = 0.45, sourcenum = 1)
    f2 = HexapolarField(lens, collimated = true, wavelength = 0.45, sourceangle = 5 / 180 * π, sourcenum = 2)
    f3 = HexapolarField(lens, collimated = true, wavelength = 0.45, sourceangle = 10 / 180 * π, sourcenum = 3)
    Vis.spotdiaggrid(lens, [f1, f2, f3]; kwargs...)
end

# Display the spot diagram of a simple cooketriplet lens
function hexapolarspotdiagramexample(lens = cooketriplet(), numrings::Int = 5, angle = 0.0)
    Vis.spotdiag(lens, samples = numrings, sourceangle = angle)
end

function cartesiangridspotdiagramexample(lens = cooketriplet(), numsamples::Int = 5, angle = 0.0)
    Vis.spotdiag(lens, hexapolar = false, samples = numsamples, sourceangle = angle)
end

function prism_refraction()
    # build the triangular prism
    int = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_SF14, OpticSim.GlassCat.Air)
    s = 2.0
    prism = csgintersection(leaf(Plane(SVector(0.0, -1.0, 0.0), SVector(0.0, -s, 0.0), interface = int, vishalfsizeu = 2 * s, vishalfsizev = 2 * s)), csgintersection(Plane(SVector(0.0, sind(30), cosd(30)), SVector(0.0, s * sind(30), s * cosd(30)), interface = int, vishalfsizeu = 2 * s, vishalfsizev = 2 * s), Plane(SVector(0.0, sind(30), -cosd(30)), SVector(0.0, s * sind(30), -s * cosd(30)), interface = int, vishalfsizeu = 2 * s, vishalfsizev = 2 * s)))
    sys = CSGOpticalSystem(LensAssembly(prism()), Rectangle(15.0, 15.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, -20.0), interface = opaqueinterface()))
    # create some 'white' light
    rays = Vector{OpticalRay{Float64,3}}(undef, 0)
    for i in 0:7
        λ = ((i / 7) * 200 + 450) / 1000
        r = OpticalRay(SVector(0.0, -3.0, 10.0), SVector(0.0, 0.5, -1.0), 1.0, λ)
        push!(rays, r)
    end
    raygen = RayListSource(rays)
    # draw the result
    Vis.drawtracerays(sys, raygenerator = raygen, test = true, trackallrays = true)
end

function fresnel(convex = true; kwargs...)
    lens = FresnelLens(OpticSim.GlassCat.SCHOTT.N_BK7, 0.0, convex ? 15.0 : -15.0, 1.0, 8.0, 0.8, conic = 0.1)
    sys = CSGOpticalSystem(LensAssembly(lens()), Rectangle(15.0, 15.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, -25.0), interface = opaqueinterface()))
    Vis.drawtracerays(sys; test = true, trackallrays = true, numdivisions = 30, kwargs...)
end

function grating(; period = 1.0, θ = 0.0, λ = 0.55, kwargs...)
    int = ThinGratingInterface(SVector(0.0, 1.0, 0.0), period, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, minorder = -2, maxorder = 2, reflectance = [0.0, 0.0, 0.1, 0.0, 0.0], transmission = [0.05, 0.1, 0.4, 0.1, 0.05])
    grating = ThinGratingSurface(Rectangle(5.0, 5.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 0.0)), int)
    back = Rectangle(30.0, 30.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 25.0))
    sys = CSGOpticalSystem(LensAssembly(grating, back), Rectangle(30.0, 30.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, -25.0), interface = opaqueinterface()))
    Vis.drawtracerays(sys; raygenerator = UniformOpticalSource(CollimatedSource(OriginPoint{Float64}(100, position = SVector(0.0, 0.0, 10.0), direction = SVector(0.0, sind(θ), -cosd(θ)))), λ), trackallrays = true, rayfilter = nothing, kwargs...)
end

function reflgrating(; period = 1.0, θ = 0.0, λ = 0.55, kwargs...)
    int = ThinGratingInterface(SVector(0.0, 1.0, 0.0), period, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, minorder = -2, maxorder = 2, transmission = [0.0, 0.0, 0.1, 0.0, 0.0], reflectance = [0.05, 0.1, 0.4, 0.1, 0.05])
    grating = ThinGratingSurface(Rectangle(5.0, 5.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 0.0)), int)
    back = Rectangle(30.0, 30.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, -25.0))
    sys = CSGOpticalSystem(LensAssembly(grating, back), Rectangle(30.0, 30.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 25.0), interface = opaqueinterface()))
    Vis.drawtracerays(sys; raygenerator = UniformOpticalSource(CollimatedSource(OriginPoint{Float64}(100, position = SVector(0.0, 0.0, 10.0), direction = SVector(0.0, sind(θ), -cosd(θ)))), λ), trackallrays = true, rayfilter = nothing, kwargs...)
end

function HOE(refl = false, firstorderonly = false; kwargs...)
    rect = Rectangle(5.0, 5.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 0.0))
    if refl
        int = HologramInterface(SVector(0.0, -10.0, 20.0), ConvergingBeam, SVector(0.0, 0.0, -200), ConvergingBeam, 0.55, 9.0, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, 0.05, !firstorderonly)
    else
        int = HologramInterface(SVector(0.0, -10.0, -20.0), ConvergingBeam, SVector(0.0, 0.0, -200), ConvergingBeam, 0.55, 5.0, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, 0.05, !firstorderonly)
    end
    obj = HologramSurface(rect, int)
    back = Rectangle(50.0, 50.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, 25.0))
    sys = CSGOpticalSystem(LensAssembly(obj, back), Rectangle(50.0, 50.0, SVector(0.0, 0.0, 1.0), SVector(0.0, 0.0, -25.0), interface = opaqueinterface()))
    Vis.drawtracerays(sys; raygenerator = UniformOpticalSource(GridSource(OriginPoint{Float64}(10, position = SVector(0.0, 0.0, 10.0), direction = SVector(0.0, 0.0, -1.0)), 1, 15, 0.0, π / 6), 0.55), trackallrays = true, rayfilter = nothing, kwargs...)
end

function eyetrackHOE(nrays = 5000, det = false, showhead = true, zeroorder = false; kwargs...)
    # TODO update for new specs from Chris
    hoehalfwidth = 50.0 #25.0
    hoehalfheight = 50.0 #22.5
    hoecenter = SVector(-8.0 - 25.0, 0.0, -10.0 - 25.0)
    rect = Rectangle(hoehalfheight, hoehalfwidth, SVector(0.0, 1.0, 0.0), hoecenter)
    er = 15.0
    cornea_rad = 7.85
    corneavertex = SVector(0.0, er, 0.0)
    sourceloc = SVector(-33.0, er, 0.0)
    camloc = SVector(20.0, 3.0, -11.0)
    camdir = corneavertex - camloc
    camdir_norm = normalize(camdir)

    interfaces = []

    # offset = SVector(-5.0, 10.0, -10.0)
    # for θ in 0:(π / 6):(2π)
    #     ledloc = SVector(20 * cos(θ) + offset[1], 0 + offset[2], 15 * sin(θ) + offset[3])
    #     int = HologramInterface(ledloc, ConvergingBeam, sourceloc, DivergingBeam, 0.78, 100.0, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, 0.05, zeroorder)
    #     push!(interfaces, int)
    # end

    dirs = [SVector(0.7713, 0.6350, -0.0437), SVector(0.5667, 0.8111, -0.1445), SVector(0.3400, 0.9349, -0.1017), SVector(0.1492, 0.9878, 0.0445), SVector(0.0249, 0.9686, 0.2474), SVector(-0.0184, 0.8855, 0.4643), SVector(0.0254, 0.7537, 0.6567), SVector(0.1548, 0.5964, 0.7876), SVector(0.3570, 0.4462, 0.8207), SVector(0.5959, 0.3470, 0.7242), SVector(0.7976, 0.3449, 0.4948), SVector(0.8680, 0.4555, 0.1978)]

    for d in dirs
        int = HologramInterface(normalize(d), CollimatedBeam, sourceloc, DivergingBeam, 0.78, 100.0, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, 0.05, zeroorder)
        # int = HologramInterface(corneavertex - 10 * d, ConvergingBeam, sourceloc, DivergingBeam, 0.78, 100.0, OpticSim.GlassCat.Air, OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, OpticSim.GlassCat.Air, 0.05, zeroorder)
        push!(interfaces, int)
    end

    mint = MultiHologramInterface(interfaces...)
    obj = MultiHologramSurface(rect, mint)
    cornea = leaf(Sphere(cornea_rad, interface = FresnelInterface{Float64}(OpticSim.GlassCat.EYE.CORNEA, OpticSim.GlassCat.Air, reflectance = 1.0, transmission = 0.0)), translation(0.0, er + cornea_rad, 0.0))()

    # cam settings
    fnum = 2.0
    fov = 80
    sensorrad = 1.0
    barrellength = sensorrad / tand(fov / 2)
    aprad = barrellength / fnum / 2
    camrad = max(sensorrad, aprad)

    camap = Annulus(aprad, camrad, camdir_norm, camloc)
    distfromcamtoeye = norm(camdir)
    focallength = 1 / (1 / distfromcamtoeye + 1 / barrellength)
    camlens = ParaxialLensEllipse(focallength, aprad, aprad, -camdir_norm, camloc)
    barrelloc = camloc - barrellength / 2 * camdir_norm
    barreltop = Plane(camdir_norm, camloc)
    barrelbot = Plane(-camdir_norm, camloc - 3 * barrellength * camdir_norm)
    barrelrot = OpticSim.rotmatbetween(SVector(0.0, 0.0, 1.0), camdir_norm)
    cambarrel = csgintersection(barrelbot, csgintersection(barreltop, leaf(Cylinder(camrad, barrellength, interface = opaqueinterface(Float64)), Transform(barrelrot, barrelloc))))()
    camdet = Circle(sensorrad, camdir_norm, camloc - barrellength * camdir_norm, interface = opaqueinterface(Float64))

    # sourceleft = hoecenter[1] + hoehalfwidth - sourceloc[1]
    # sourceright = hoecenter[1] - hoehalfwidth - sourceloc[1]
    # sourceleftθ = atan(sourceleft, sourceloc[2])
    # sourcerightθ = atan(sourceright, sourceloc[2])
    # midθ = (sourceleftθ + sourcerightθ) / 2
    # sourcedir = normalize(SVector(er * tan(midθ), -er, 0.0))
    # sourceextentθ = abs(midθ - sourcerightθ)
    # source = CosineOpticalSource(RandomSource(OriginPoint{Float64}(1, position = sourceloc, direction = sourcedir), nrays, sourceextentθ), 1.0, 0.78)

    rays = Vector{OpticalRay{Float64,3}}(undef, nrays)
    @simd for i in 1:nrays
        p = point(rect, rand() * 2 - 1, rand() * 2 - 1)
        rays[i] = OpticalRay(sourceloc, p - sourceloc, 1.0, 0.78)
    end
    source = RayListSource(rays)

    sys = CSGOpticalSystem(LensAssembly(obj, cornea, camlens, cambarrel, camap), camdet, 800, 800)
    if det
        Vis.show(OpticSim.traceMT(sys, source))
    else
        Vis.drawtracerays(sys; raygenerator = source, trackallrays = true, kwargs...)
        # for θ in 0:(π / 6):(2π)
        #     ledloc = SVector(20 * cos(θ) + offset[1], 0 + offset[2], 15 * sin(θ) + offset[3])
        #     Vis.draw!(leaf(Sphere(1.0), translation(ledloc...)), color = :red)
        # end
        for d in dirs
            # Vis.draw!(leaf(Sphere(1.0), translation((corneavertex - 10 * d)...)), color = :red)
            Vis.draw!((corneavertex - 50 * d, corneavertex), color = :red)
        end
        if showhead
            Vis.draw!(joinpath(@__DIR__, "../../OBJ/glasses.obj"), scale = 100.0, transform = Transform(OpticSim.rotmatd(90, 0, 0), [27.0, 45.0, -8.0]), color = :black)
            Vis.draw!(joinpath(@__DIR__, "../../OBJ/femalehead.obj"), scale = 13.0, transform = Transform(OpticSim.rotmatd(0, 0, 180), [27.0, 105.0, -148.0]), color = :white)
        end
        Vis.display()
    end
end


text:
using Test
# using Revise
using JDF

@testset "JDFFile" begin
    df = DataFrame([collect(1:100) for i =1:3])
    df[!, :x1] = categorical(df[!, :x1])
    df[!, :x2] = categorical(string.(df[!, :x2]))
    savejdf("a3dfsyntax.jdf", df)

    jdffile = JDFFile("a3dfsyntax.jdf")
    jdffile[!, :x1]
    jdffile[!, [:x1, :x2]]

    jdffile[:, :x1]
    jdffile[:, [:x1, :x2]]

    jdffile[[1, 100], :x1]
    jdffile[1:100, :x1]

    jdffile[rand(Bool, 100), :x1]

    rm("a3dfsyntax.jdf", force=true, recursive=true)
end

ext: jl


text:
struct Dkplsr
    X::Array{Float64}
    fm
    K::Array{Float64}
    kern
    dots
end

"""
    dkplsr(X, Y, weights = ones(size(X, 1)); nlv , kern = "krbf", kwargs...)
Direct kernel partial least squares regression (DKPLSR) (Bennett & Embrechts 2003).

* `X` : X-data.
* `Y` : Y-data.
* `weights` : Weights of the observations.
* `nlv` : Nb. latent variables (LVs) to consider.
* 'kern' : Type of kernel used to compute the Gram matrices.
    Possible values are "krbf" of "kpol" (see respective functions `krbf` and `kpol`).
* `kwargs` : Named arguments to pass in the kernel function.

The method builds kernel Gram matrices and then runs a usual PLSR algorithm on them. This is faster
(but not equivalent) to the "true" NIPALS KPLSR algorithm described in Rosipal & Trejo (2001).

## References

Bennett, K.P., Embrechts, M.J., 2003. An optimization perspective on kernel partial least squares regression,
in: Advances in Learning Theory: Methods, Models and Applications,
NATO Science Series III: Computer & Systems Sciences. IOS Press Amsterdam, pp. 227-250.

Rosipal, R., Trejo, L.J., 2001. Kernel Partial Least Squares Regression in Reproducing Kernel Hilbert Space.
Journal of Machine Learning Research 2, 97-123.

"""
function dkplsr(X, Y, weights = ones(size(X, 1)); nlv, kern = "krbf", kwargs...)
    dkplsr!(copy(X), copy(Y), weights; nlv = nlv, kern = kern, kwargs...)
end

function dkplsr!(X, Y, weights = ones(size(X, 1));
        nlv, kern = "krbf", kwargs...)
    fkern = eval(Meta.parse(kern))
    K = fkern(X, X; kwargs...)     # In the future: fkern!(K, X, X; kwargs...)
    fm = plskern!(K, Y; nlv = nlv)
    Dkplsr(X, fm, K, kern, kwargs)
end

"""
    transform(object::Dkplsr, X; nlv = nothing)
Compute LVs (score matrix "T") from a fitted model and X-data.
* `object` : The maximal fitted model.
* `X` : X-data for which LVs are computed.
* `nlv` : Nb. LVs to consider. If nothing, it is the maximum nb. LVs.
"""
function transform(object::Dkplsr, X; nlv = nothing)
    fkern = eval(Meta.parse(object.kern))
    K = fkern(X, object.X; object.dots...)
    transform(object.fm, K; nlv = nlv)
end

"""
    coef(object::Dkplsr; nlv = nothing)
Compute the b-coefficients of a fitted model.
* `object` : The fitted model.
* `nlv` : Nb. LVs, or collection of nb. LVs, to consider.
    If nothing, it is the maximum nb. LVs.
"""
function coef(object::Dkplsr; nlv = nothing)
    coef(object.fm; nlv = nlv)
end

"""
    predict(object::Dkplsr, X; nlv = nothing)
Compute Y-predictions from a fitted model and X-data.
* `object` : The maximal fitted model.
* `X` : X-data for which predictions are computed.
* `nlv` : Nb. LVs, or collection of nb. LVs, to consider.
    If nothing, it is the maximum nb. LVs.
"""
function predict(object::Dkplsr, X; nlv = nothing)
    fkern = eval(Meta.parse(object.kern))
    K = fkern(X, object.X; object.dots...)
    pred = predict(object.fm, K; nlv = nlv).pred
    (pred = pred,)
end


text:
module BallTest

using Projections, Test

@testset "ball" begin
y = [-2.5, -1.5, -0.5, 0.0, 0.5, 1.5, 2.5]
n = length(y)
@show sqrt(sum(abs2, y))
@test isapprox(project(Ball(n), y), [-0.597614, -0.358569, -0.119523, 0.0,
    0.119523, 0.358569, 0.597614], rtol=1e-4)
@test all(project(Ball(n, 5.), y) .== y)
end

end


text:
ENV["MPLBACKEND"]="agg"

using Test, ExtendableGrids, GridVisualize
import PyPlot

@testset "Basic" begin
    function test_geomspace()
        X1=geomspace(2.0,3.0,0.2,0.2)
        X2=collect(2:0.2:3)
        @assert X1 ≈  X2
        X1=geomspace(2.0,3.0,0.1,0.2)
        X2=geomspace(2.0,3.0,0.2,0.1)

        X1=geomspace(2.0,3.0,1.0e-5,0.2)
        X2=geomspace(2.0,3.0,0.2,1.0e-5)
        (X1[2]-X1[1])  ≈ (X2[end]-X2[end-1]) &&
            (X2[2]-X2[1])  ≈ (X1[end]-X1[end-1])
    end
    @test test_geomspace()

    function test_prepare_edges()
        ## Compared with pdelib; have more of these
        nodes=Matrix([
            0.0 1;
            1 0;
            0 1;
            1 1]')

        cells=Matrix([
            1 2 3;
            2 3 4
        ]')
        cellmat=[1,1]
        bfaces=Matrix([ 1 2;
                        1 3;
                        2 4]')
        bfacemat=[1,1]

        grid=simplexgrid(nodes,cells,cellmat,bfaces,bfacemat)

        grid[CellEdges]==[3 5; 2 4; 1 3] &&
        grid[EdgeNodes]==[2 3 3 4 4; 1 1 2 2 3] &&
            grid[EdgeCells]==[1 1 1 2 2; 0 0 2 0 0]

    end
    @test test_prepare_edges()

    @test let
        g=simplexgrid(0:10)
        bfc=g[BFaceCells]
        bfc[1,1]==1 && bfc[1,2]==10
    end

    @test let
        g=simplexgrid(0:10)
        bfn=g[BFaceNormals]
        bfn==[-1.0 1.0]
    end

    @test let
        g=simplexgrid(0:2, 0:2)
        bfn=g[BFaceNormals]
        bfn==[0.0  -1.0;
              -1.0   0.0;
              0.0  -1.0;
              1.0   0.0;
              0.0   1.0;
              -1.0   0.0;
              1.0   0.0;
              0.0   1.0]'
    end

    @test let
        g=simplexgrid(0:2, 0:2)
        bfc=g[BFaceCells]
        tryfix(bfc)==[1  2  3  3  6  6  7  8;]
    end

end

@testset "Read/Write" begin
    function testrw(grid)
        ftmp=tempname()
        write(ftmp,grid,format="sg")
        grid1=simplexgrid(ftmp,format="sg")
        seemingly_equal(grid1,grid)
    end
    X=collect(0:0.05:1)
    @test testrw(simplexgrid(X))
    @test testrw(simplexgrid(X,X))
    @test testrw(simplexgrid(X,X,X))
end

function testgrid(grid,testdata)
    (num_nodes(grid),num_cells(grid), num_bfaces(grid))==testdata
end

examples1d=joinpath(@__DIR__,"..","examples","examples1d.jl")
include(examples1d)
examples2d=joinpath(@__DIR__,"..","examples","examples2d.jl")
include(examples2d)
examples3d=joinpath(@__DIR__,"..","examples","examples3d.jl")
include(examples3d)
plotting=joinpath(@__DIR__,"..","examples","plotting.jl")
include(plotting)

@testset "1D" begin
    @test testgrid(interval_from_vector(),(21,20,2))
    @test testgrid(interval_localref(),   (27,26,2))
    @test testgrid(interval_multiregion(),(21,20,3))
    @test testgrid(interval_subgrid(),(51,50,2))
end

@testset "2D" begin
    @test testgrid(rectangle(),(441,800,80))
    @test testgrid(rectangle_localref(),(729, 1352, 104))
    @test testgrid(rectangle_multiregion(),(441,800,100))
    @test testgrid(rectangle_subgrid(),(360, 600, 120))
end

@testset "3D" begin
    @test testgrid(quadrilateral(),(330,1200,440))
end

if !Sys.isapple()
    @testset "plotting examples" begin
        include("../docs/makeplots.jl")
        picdir=mktempdir()

        @test makeplot("interval_from_vector",picdir)
        @test makeplot("interval_localref",picdir)
        @test makeplot("interval_multiregion",picdir)
        @test makeplot("interval_subgrid",picdir)
        @test makeplot("rectangle",picdir)
        @test makeplot("rectangle_localref",picdir)
        @test makeplot("rectangle_multiregion",picdir)
        @test makeplot("rectangle_subgrid",picdir)
        @test makeplot("quadrilateral",picdir)
    end
end


text:
using Test

using Pinecone

APIKEY = ENV["PINECONE_API_KEY"]
CLOUDENV="us-west1-gcp"

context = Pinecone.init(APIKEY, CLOUDENV)

INDEX = "filter-example"
NAMESPACE = "mynamespace"
index = Pinecone.Index(INDEX);

@testset "Scale Index()" begin
    context = Pinecone.init(APIKEY, CLOUDENV)
    index = Pinecone.Index(INDEX)
    @test_throws ArgumentError Pinecone.scale_index(context, index, -1)
    result = Pinecone.scale_index(context, index, 2)
    @test result !== nothing
    @test result == true
 end


text:
import Base.@deprecate
import Base.depwarn

import Base.varm, Base.stdm
@deprecate varm(v::RealArray, m::Real, wv::WeightVec) varm(v, wv, m)
@deprecate varm(A::RealArray, M::RealArray, wv::WeightVec, dim::Int) varm(v, wv, m, dim)
@deprecate stdm(v::RealArray, m::Real, wv::WeightVec) stdm(v, wv, m)
@deprecate stdm(v::RealArray, m::RealArray, wv::WeightVec, dim::Int) stdm(v, wv, m, dim)

@deprecate _moment2(v::RealArray, m::Real, wv::WeightVec) _moment2(v, wv, m)
@deprecate _moment3(v::RealArray, m::Real, wv::WeightVec) _moment3(v, wv, m)
@deprecate _moment4(v::RealArray, m::Real, wv::WeightVec) _moment4(v, wv, m)
@deprecate _momentk(v::RealArray, k::Int, m::Real, wv::WeightVec) _momentk(v, k, wv, m)
@deprecate moment(v::RealArray, k::Int, m::Real, wv::WeightVec) moment(v, k, wv, m)

@deprecate AIC(obj::StatisticalModel) aic(obj)
@deprecate AICc(obj::StatisticalModel) aicc(obj)
@deprecate BIC(obj::StatisticalModel) bic(obj)

@deprecate R2(obj::StatisticalModel, variant::Symbol) r2(obj, variant)
@deprecate R²(obj::StatisticalModel, variant::Symbol) r²(obj, variant)
@deprecate adjR2(obj::StatisticalModel, variant::Symbol) adjr2(obj, variant)
@deprecate adjR²(obj::StatisticalModel, variant::Symbol) adjr²(obj, variant)

function findat!{T}(r::IntegerArray, a::AbstractArray{T}, b::AbstractArray{T})
    Base.depwarn("findat! is deprecated, use indexin instead", :findat!)
    length(r) == length(b) || raise_dimerror()
    d = indexmap(a)
    @inbounds for i = 1 : length(b)
        r[i] = get(d, b[i], 0)
    end
    return r
end

"""
    findat(a, b)

For each element in `b`, find its first index in `a`. If the value does
not occur in `a`, the corresponding index is 0.
"""
findat(a::AbstractArray, b::AbstractArray) = findat!(Array{Int}(size(b)), a, b)

@deprecate df(obj::StatisticalModel) dof(obj)
@deprecate df_residual(obj::StatisticalModel) dof_residual(obj)


text:
const Region2_pt = ( no = [-0.969_276_865_002_17E1,
    0.100_866_559_680_18E2,
    -0.560_879_112_830_20E-2,
    0.714_527_380_814_55E-1,
    -0.407_104_982_239_28,
    0.142_408_191_714_44E1,
    -0.438_395_113_194_50E1,
    -0.284_086_324_607_72,
    0.212_684_637_533_07E-1],

    Jo = [0,
    1,
    -5,
    -4,
    -3,
    -2,
    -1,
    2,
    3],

    nr = [-0.177_317_424_732_13E-2,
    -0.178_348_622_923_58E-1,
    -0.459_960_136_963_65E-1,
    -0.575_812_590_834_32E-1,
    -0.503_252_787_279_30E-1,
    -0.330_326_416_702_03E-4,
    -0.189_489_875_163_15E-3,
    -0.393_927_772_433_55E-2,
    -0.437_972_956_505_73E-1,
    -0.266_745_479_140_87E-4,
    0.204_817_376_923_09E-7,
    0.438_706_672_844_35E-6,
    -0.322_776_772_385_70E-4,
    -0.150_339_245_421_48E-2,
    -0.406_682_535_626_49E-1,
    -0.788_473_095_593_67E-9,
    0.127_907_178_522_85E-7,
    0.482_253_727_185_07E-6,
    0.229_220_763_376_61E-5,
    -0.167_147_664_510_61E-10,
    -0.211_714_723_213_55E-2,
    -0.238_957_419_341_04E2,
    -0.590_595_643_242_70E-17,
    -0.126_218_088_991_01E-5,
    -0.389_468_424_357_39E-1,
    0.112_562_113_604_59E-10,
    -0.823_113_408_979_98E1,
    0.198_097_128_020_88E-7,
    0.104_069_652_101_74E-18,
    -0.102_347_470_959_29E-12,
    -0.100_181_793_795_11E-8,
    -0.808_829_086_469_85E-10,
    0.106_930_318_794_09,
    -0.336_622_505_741_71,
    0.891_858_453_554_21E-24,
    0.306_293_168_762_32E-12,
    -0.420_024_676_982_08E-5,
    -0.590_560_296_856_39E-25,
    0.378_269_476_134_57E-5,
    -0.127_686_089_346_81E-14,
    0.730_876_105_950_61E-28,
    0.554_147_153_507_78E-16,
    -0.943_697_072_412_10E-6],

    Ir = [1,
    1,
    1,
    1,
    1,
    2,
    2,
    2,
    2,
    2,
    3,
    3,
    3,
    3,
    3,
    4,
    4,
    4,
    5,
    6,
    6,
    6,
    7,
    7,
    7,
    8,
    8,
    9,
    10,
    10,
    10,
    16,
    16,
    18,
    20,
    20,
    20,
    21,
    22,
    23,
    24,
    24,
    24],

    Jr = [0,
    1,
    2,
    3,
    6,
    1,
    2,
    4,
    7,
    36,
    0,
    1,
    3,
    6,
    35,
    1,
    2,
    3,
    7,
    3,
    16,
    35,
    0,
    11,
    25,
    8,
    36,
    13,
    4,
    10,
    14,
    29,
    50,
    57,
    20,
    35,
    48,
    21,
    53,
    39,
    26,
    40,
    58])

"""
    IF97Region2

    Returns all the property values in region 2.
    273.15K ≤ T ≤ 623.15K  0 ≤ P ≤ Psat(T)
    623.15K <  T ≤ 863.15K  0 <  P ≤ P(T) from B23-model
    863.15K <  T ≤ 1073.15K 0 <  P ≤ 100MPa
    Accuracy in the metastable region is reasonable above 10MPa, only
"""
const IF97Region2 = IF97Region{:r2}

function Region2(Output::Symbol, P, T)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2_pt.no
    Jo = Region2_pt.Jo
    nr = Region2_pt.nr
    Ir = Region2_pt.Ir
    Jr = Region2_pt.Jr

    π = P / Pstar
    τ = Tstar / T

    γo    = log(π) + sum(no[i]*τ^Jo[i] for i=1:9)
    γo_π  = 1/π
    γo_ππ = -1/(π^2)
    γo_τ  = sum(no[i]*Jo[i]*τ^(Jo[i]-1) for i=1:9)
    γo_ττ = sum(no[i]*Jo[i]*(Jo[i]-1)*τ^(Jo[i]-2) for i=1:9)
    γo_πτ = 0

    γr    = sum(nr[i]*π^Ir[i]*(τ-0.5)^Jr[i] for i = 1:43)
    γr_π  = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*(τ-0.5)^Jr[i] for i=1:43)
    γr_ππ = sum(nr[i]*Ir[i]*(Ir[i]-1)*π^(Ir[i]-2)*(τ-0.5)^Jr[i] for i=1:43)
    γr_τ  = sum(nr[i]*π^Ir[i]*Jr[i]*(τ-0.5)^(Jr[i]-1) for i=1:43)
    γr_ττ = sum(nr[i]*π^Ir[i]*Jr[i]*(Jr[i]-1)*(τ-0.5)^(Jr[i]-2) for i=1:43)
    γr_πτ = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*Jr[i]*(τ-0.5)^(Jr[i]-1) for i = 1:43)

    if Output == :SpecificG            #kJ/kg
        return IF97_R*T*(γo + γr)
    elseif Output == :SpecificF        #kJ/kg
        return IF97_R*T*(γo + γr - π*(γo_π + γr_π)/1000)
    elseif Output == :SpecificV        #m3/kg
        return IF97_R*T*π*(γo_π + γr_π)/P/1000
    elseif Output == :SpecificU        #kJ/kg
        return IF97_R*T*(τ*(γo_τ + γr_τ) - π*(γo_π + γr_π))
    elseif Output == :SpecificS        #kJ/kgK
        return IF97_R*(τ*(γo_τ + γr_τ) - (γo + γr))
    elseif Output == :SpecificH        #kJ/kg
        return IF97_R*T*τ*(γo_τ + γr_τ)
    elseif Output == :SpecificCP       #kJ/kgK
        return -IF97_R*τ^2*(γo_ττ + γr_ττ)
    elseif Output == :SpecificCV       #kJ/kgK
        return IF97_R*(-τ^2*(γo_ττ+γr_ττ) - (1+π*γr_π-τ*π*γr_πτ)^2/(1-π^2*γr_ππ))
    elseif Output == :SpeedOfSound     #m/s
        return sqrt((1000*IF97_R*T)*(1+2*π*γr_π+π^2*γr_π^2)/((1-π^2*γr_ππ)+(1+π*γr_π-τ*π*γr_πτ)^2/τ^2/(γo_ττ + γr_ττ)))
    else
        throw(DomainError(Output, "Unknown value requested."))
    end
end

function mass_gibbs_impl(mt::SinglePT,model::IF97Region{:r2},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2_pt.no
    Jo = Region2_pt.Jo
    nr = Region2_pt.nr
    Ir = Region2_pt.Ir
    Jr = Region2_pt.Jr

    π = P / Pstar
    τ = Tstar / T
    γo = log(π) + sum(no[i]*τ^Jo[i] for i=1:9)
    γr = sum(nr[i]*π^Ir[i]*(τ-0.5)^Jr[i] for i = 1:43)
    res = IF97_R*T*(γo + γr)
    return convert_unit(u"kJ/kg",u"J/kg",res)
end

function mass_helmholtz_impl(mt::SinglePT,model::IF97Region{:r2},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2_pt.no
    Jo = Region2_pt.Jo
    nr = Region2_pt.nr
    Ir = Region2_pt.Ir
    Jr = Region2_pt.Jr
    π = P / Pstar
    τ = Tstar / T
    γo    = log(π) + sum(no[i]*τ^Jo[i] for i=1:9)
    γr    = sum(nr[i]*π^Ir[i]*(τ-0.5)^Jr[i] for i = 1:43)
    γo_π  = 1/π
    γr_π  = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*(τ-0.5)^Jr[i] for i=1:43)
    res =  IF97_R*T*(γo + γr - π*(γo_π + γr_π)/1000)
    return convert_unit(u"kJ/kg",u"J/kg",res)
end

function mass_volume_impl(mt::SinglePT,model::IF97Region{:r2},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2_pt.no
    Jo = Region2_pt.Jo
    nr = Region2_pt.nr
    Ir = Region2_pt.Ir
    Jr = Region2_pt.Jr

    π = P / Pstar
    τ = Tstar / T

    γo_π  = 1/π
    γr_π  = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*(τ-0.5)^Jr[i] for i=1:43)

    res = IF97_R*T*π*(γo_π + γr_π)/P/1000
    return res
end

function mass_internal_energy_impl(mt::SinglePT,model::IF97Region{:r2},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2_pt.no
    Jo = Region2_pt.Jo
    nr = Region2_pt.nr
    Ir = Region2_pt.Ir
    Jr = Region2_pt.Jr

    π = P / Pstar
    τ = Tstar / T
    γo_τ  = sum(no[i]*Jo[i]*τ^(Jo[i]-1) for i=1:9)
    γr_τ  = sum(nr[i]*π^Ir[i]*Jr[i]*(τ-0.5)^(Jr[i]-1) for i=1:43)
    γo_π  = 1/π
    γr_π  = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*(τ-0.5)^Jr[i] for i=1:43)

    res = IF97_R*T*(τ*(γo_τ + γr_τ) - π*(γo_π + γr_π))

    return convert_unit(u"kJ/kg",u"J/kg",res)
end

function mass_entropy_impl(mt::SinglePT,model::IF97Region{:r2},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2_pt.no
    Jo = Region2_pt.Jo
    nr = Region2_pt.nr
    Ir = Region2_pt.Ir
    Jr = Region2_pt.Jr

    π = P / Pstar
    τ = Tstar / T
    γo_τ  = sum(no[i]*Jo[i]*τ^(Jo[i]-1) for i=1:9)
    γr_τ  = sum(nr[i]*π^Ir[i]*Jr[i]*(τ-0.5)^(Jr[i]-1) for i=1:43)

    γo    = log(π) + sum(no[i]*τ^Jo[i] for i=1:9)
    γr    = sum(nr[i]*π^Ir[i]*(τ-0.5)^Jr[i] for i = 1:43)

    res = IF97_R*(τ*(γo_τ + γr_τ) - (γo + γr))

    return convert_unit(u"kJ/(kg*K)",u"J/(kg*K)",res)
end

function mass_enthalpy_impl(mt::SinglePT,model::IF97Region{:r2},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2_pt.no
    Jo = Region2_pt.Jo
    nr = Region2_pt.nr
    Ir = Region2_pt.Ir
    Jr = Region2_pt.Jr

    π = P / Pstar
    τ = Tstar / T
    γo_τ  = sum(no[i]*Jo[i]*τ^(Jo[i]-1) for i=1:9)
    γr_τ  = sum(nr[i]*π^Ir[i]*Jr[i]*(τ-0.5)^(Jr[i]-1) for i=1:43)

    res = IF97_R*T*τ*(γo_τ + γr_τ)
    return convert_unit(u"kJ/kg",u"J/kg",res)
end

function mass_cp_impl(mt::SinglePT,model::IF97Region{:r2},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
       Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2_pt.no
    Jo = Region2_pt.Jo
    nr = Region2_pt.nr
    Ir = Region2_pt.Ir
    Jr = Region2_pt.Jr

    π = P / Pstar
    τ = Tstar / T
    γo_ττ = sum(no[i]*Jo[i]*(Jo[i]-1)*τ^(Jo[i]-2) for i=1:9)
    γr_ττ = sum(nr[i]*π^Ir[i]*Jr[i]*(Jr[i]-1)*(τ-0.5)^(Jr[i]-2) for i=1:43)

    res = -IF97_R*τ^2*(γo_ττ + γr_ττ)

    return convert_unit(u"kJ/(kg*K)",u"J/(kg*K)",res)

end

function mass_cv_impl(mt::SinglePT,model::IF97Region{:r2},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2_pt.no
    Jo = Region2_pt.Jo
    nr = Region2_pt.nr
    Ir = Region2_pt.Ir
    Jr = Region2_pt.Jr

    π = P / Pstar
    τ = Tstar / T

    γo_ττ = sum(no[i]*Jo[i]*(Jo[i]-1)*τ^(Jo[i]-2) for i=1:9)
    γr_ττ = sum(nr[i]*π^Ir[i]*Jr[i]*(Jr[i]-1)*(τ-0.5)^(Jr[i]-2) for i=1:43)
    γr_π  = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*(τ-0.5)^Jr[i] for i=1:43)
    γr_πτ = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*Jr[i]*(τ-0.5)^(Jr[i]-1) for i = 1:43)
    γr_ππ = sum(nr[i]*Ir[i]*(Ir[i]-1)*π^(Ir[i]-2)*(τ-0.5)^Jr[i] for i=1:43)

    res = IF97_R*(-τ^2*(γo_ττ+γr_ττ) - (1+π*γr_π-τ*π*γr_πτ)^2/(1-π^2*γr_ππ))

    return convert_unit(u"kJ/(kg*K)",u"J/(kg*K)",res)
end

function sound_speed_impl(mt::SinglePT,model::IF97Region{:r2},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2_pt.no
    Jo = Region2_pt.Jo
    nr = Region2_pt.nr
    Ir = Region2_pt.Ir
    Jr = Region2_pt.Jr

    π = P / Pstar
    τ = Tstar / T

    γr_π  = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*(τ-0.5)^Jr[i] for i=1:43)
    γr_ππ = sum(nr[i]*Ir[i]*(Ir[i]-1)*π^(Ir[i]-2)*(τ-0.5)^Jr[i] for i=1:43)
    γr_πτ = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*Jr[i]*(τ-0.5)^(Jr[i]-1) for i = 1:43)
    γo_ττ = sum(no[i]*Jo[i]*(Jo[i]-1)*τ^(Jo[i]-2) for i=1:9)
    γr_ττ = sum(nr[i]*π^Ir[i]*Jr[i]*(Jr[i]-1)*(τ-0.5)^(Jr[i]-2) for i=1:43)

    res =  sqrt((1000*IF97_R*T)*(1+2*π*γr_π+π^2*γr_π^2)/
    ((1-π^2*γr_ππ)+(1+π*γr_π-τ*π*γr_πτ)^2/τ^2/(γo_ττ + γr_ττ)))
    return res
end

const Region2m_pt = (
    no = [-0.969_372_683_930_49E1, #Updated from Region_2
           0.100_872_759_700_06E2, #Updated from Region_2
          -0.560_879_112_830_20E-2,
           0.714_527_380_814_55E-1,
          -0.407_104_982_239_28,
           0.142_408_191_714_44E1,
          -0.438_395_113_194_50E1,
          -0.284_086_324_607_72,
           0.212_684_637_533_07E-1],

    Jo = [ 0,
           1,
          -5,
          -4,
          -3,
          -2,
          -1,
           2,
           3],

    nr = [-0.733_622_601_865_06E-2,
          -0.882_238_319_431_46E-1,
          -0.723_345_552_132_45E-1,
          -0.408_131_785_344_55E-2,
           0.200_978_033_802_07E-2,
          -0.530_459_218_986_42E-1,
          -0.761_904_090_869_70E-2,
          -0.634_980_376_573_13E-2,
          -0.860_430_930_285_88E-1,
           0.753_215_815_227_70E-2,
          -0.792_383_754_461_39E-2,
          -0.228_881_607_784_47E-3,
          -0.264_565_014_828_10E-2],

    Ir = [1,
          1,
          1,
          1,
          2,
          2,
          2,
          3,
          3,
          4,
          4,
          5,
          5],

    Jr = [0,
          2,
          5,
          11,
          1,
          7,
          16,
          4,
          16,
          7,
          10,
          9,
          10]

)

function mass_gibbs_impl(mt::SinglePT,model::IF97Region{:r2m},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2m_pt.no
    Jo = Region2m_pt.Jo
    nr = Region2m_pt.nr
    Ir = Region2m_pt.Ir
    Jr = Region2m_pt.Jr

    π = P / Pstar
    τ = Tstar / T
    γo = log(π) + sum(no[i]*τ^Jo[i] for i=1:9)
    γr = sum(nr[i]*π^Ir[i]*(τ-0.5)^Jr[i] for i = 1:13)
    res = IF97_R*T*(γo + γr)
    return convert_unit(u"kJ/kg",u"J/kg",res)
end

function mass_helmholtz_impl(mt::SinglePT,model::IF97Region{:r2m},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2_pt.no
    Jo = Region2_pt.Jo
    nr = Region2_pt.nr
    Ir = Region2_pt.Ir
    Jr = Region2_pt.Jr
    π = P / Pstar
    τ = Tstar / T
    γo    = log(π) + sum(no[i]*τ^Jo[i] for i=1:9)
    γr    = sum(nr[i]*π^Ir[i]*(τ-0.5)^Jr[i] for i = 1:13)
    γo_π  = 1/π
    γr_π  = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*(τ-0.5)^Jr[i] for i=1:13)
    res =  IF97_R*T*(γo + γr - π*(γo_π + γr_π)/1000)
    return convert_unit(u"kJ/kg",u"J/kg",res)
end

function mass_volume_impl(mt::SinglePT,model::IF97Region{:r2m},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2m_pt.no
    Jo = Region2m_pt.Jo
    nr = Region2m_pt.nr
    Ir = Region2m_pt.Ir
    Jr = Region2m_pt.Jr

    π = P / Pstar
    τ = Tstar / T

    γo_π  = 1/π
    γr_π  = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*(τ-0.5)^Jr[i] for i=1:13)

    res = IF97_R*T*π*(γo_π + γr_π)/P/1000
    return res
end

function mass_internal_energy_impl(mt::SinglePT,model::IF97Region{:r2m},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2m_pt.no
    Jo = Region2m_pt.Jo
    nr = Region2m_pt.nr
    Ir = Region2m_pt.Ir
    Jr = Region2m_pt.Jr

    π = P / Pstar
    τ = Tstar / T
    γo_τ  = sum(no[i]*Jo[i]*τ^(Jo[i]-1) for i=1:9)
    γr_τ  = sum(nr[i]*π^Ir[i]*Jr[i]*(τ-0.5)^(Jr[i]-1) for i=1:13)
    γo_π  = 1/π
    γr_π  = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*(τ-0.5)^Jr[i] for i=1:13)

    res = IF97_R*T*(τ*(γo_τ + γr_τ) - π*(γo_π + γr_π))

    return convert_unit(u"kJ/kg",u"J/kg",res)
end

function mass_entropy_impl(mt::SinglePT,model::IF97Region{:r2m},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2m_pt.no
    Jo = Region2m_pt.Jo
    nr = Region2m_pt.nr
    Ir = Region2m_pt.Ir
    Jr = Region2m_pt.Jr

    π = P / Pstar
    τ = Tstar / T
    γo_τ  = sum(no[i]*Jo[i]*τ^(Jo[i]-1) for i=1:9)
    γr_τ  = sum(nr[i]*π^Ir[i]*Jr[i]*(τ-0.5)^(Jr[i]-1) for i=1:13)

    γo    = log(π) + sum(no[i]*τ^Jo[i] for i=1:9)
    γr    = sum(nr[i]*π^Ir[i]*(τ-0.5)^Jr[i] for i = 1:13)

    res = IF97_R*(τ*(γo_τ + γr_τ) - (γo + γr))

    return convert_unit(u"kJ/(kg*K)",u"J/(kg*K)",res)
end

function mass_enthalpy_impl(mt::SinglePT,model::IF97Region{:r2m},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2m_pt.no
    Jo = Region2m_pt.Jo
    nr = Region2m_pt.nr
    Ir = Region2m_pt.Ir
    Jr = Region2m_pt.Jr

    π = P / Pstar
    τ = Tstar / T
    γo_τ  = sum(no[i]*Jo[i]*τ^(Jo[i]-1) for i=1:9)
    γr_τ  = sum(nr[i]*π^Ir[i]*Jr[i]*(τ-0.5)^(Jr[i]-1) for i=1:13)

    res = IF97_R*T*τ*(γo_τ + γr_τ)
    return convert_unit(u"kJ/kg",u"J/kg",res)
end

function mass_cp_impl(mt::SinglePT,model::IF97Region{:r2m},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
       Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2m_pt.no
    Jo = Region2m_pt.Jo
    nr = Region2m_pt.nr
    Ir = Region2m_pt.Ir
    Jr = Region2m_pt.Jr

    π = P / Pstar
    τ = Tstar / T
    γo_ττ = sum(no[i]*Jo[i]*(Jo[i]-1)*τ^(Jo[i]-2) for i=1:9)
    γr_ττ = sum(nr[i]*π^Ir[i]*Jr[i]*(Jr[i]-1)*(τ-0.5)^(Jr[i]-2) for i=1:13)

    res = -IF97_R*τ^2*(γo_ττ + γr_ττ)

    return convert_unit(u"kJ/(kg*K)",u"J/(kg*K)",res)

end

function mass_cv_impl(mt::SinglePT,model::IF97Region{:r2m},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2m_pt.no
    Jo = Region2m_pt.Jo
    nr = Region2m_pt.nr
    Ir = Region2m_pt.Ir
    Jr = Region2m_pt.Jr

    π = P / Pstar
    τ = Tstar / T

    γo_ττ = sum(no[i]*Jo[i]*(Jo[i]-1)*τ^(Jo[i]-2) for i=1:9)
    γr_ττ = sum(nr[i]*π^Ir[i]*Jr[i]*(Jr[i]-1)*(τ-0.5)^(Jr[i]-2) for i=1:13)
    γr_π  = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*(τ-0.5)^Jr[i] for i=1:13)
    γr_πτ = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*Jr[i]*(τ-0.5)^(Jr[i]-1) for i = 1:13)
    γr_ππ = sum(nr[i]*Ir[i]*(Ir[i]-1)*π^(Ir[i]-2)*(τ-0.5)^Jr[i] for i=1:13)

    res = IF97_R*(-τ^2*(γo_ττ+γr_ττ) - (1+π*γr_π-τ*π*γr_πτ)^2/(1-π^2*γr_ππ))

    return convert_unit(u"kJ/(kg*K)",u"J/(kg*K)",res)
end

function sound_speed_impl(mt::SinglePT,model::IF97Region{:r2m},p,t)
    P = convert_unit(u"Pa",u"MPa",p)
    T = normalize_units(t)
    Pstar = 1.0    #MPa
    Tstar = 540.0  #K
    no = Region2m_pt.no
    Jo = Region2m_pt.Jo
    nr = Region2m_pt.nr
    Ir = Region2m_pt.Ir
    Jr = Region2m_pt.Jr

    π = P / Pstar
    τ = Tstar / T

    γr_π  = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*(τ-0.5)^Jr[i] for i=1:13)
    γr_ππ = sum(nr[i]*Ir[i]*(Ir[i]-1)*π^(Ir[i]-2)*(τ-0.5)^Jr[i] for i=1:13)
    γr_πτ = sum(nr[i]*Ir[i]*π^(Ir[i]-1)*Jr[i]*(τ-0.5)^(Jr[i]-1) for i = 1:13)
    γo_ττ = sum(no[i]*Jo[i]*(Jo[i]-1)*τ^(Jo[i]-2) for i=1:9)
    γr_ττ = sum(nr[i]*π^Ir[i]*Jr[i]*(Jr[i]-1)*(τ-0.5)^(Jr[i]-2) for i=1:13)

    res =  sqrt((1000*IF97_R*T)*(1+2*π*γr_π+π^2*γr_π^2)/
    ((1-π^2*γr_ππ)+(1+π*γr_π-τ*π*γr_πτ)^2/τ^2/(γo_ττ + γr_ττ)))
    return res
end

const Region2a_t_ph = (

    n = [0.108_989_523_182_88E4,
         0.849_516_544_955_35E3,
        -0.107_817_480_918_26E3,
         0.331_536_548_012_63E2,
        -0.742_320_167_902_48E1,
         0.117_650_487_243_56E2,
         0.184_457_493_557_90E1,
        -0.417_927_005_496_24E1,
         0.624_781_969_358_12E1,
        -0.173_445_631_081_14E2,
        -0.200_581_768_620_96E3,
         0.271_960_654_737_96E3,
        -0.455_113_182_858_18E3,
         0.309_196_886_047_55E4,
         0.252_266_403_578_72E6,
        -0.617_074_228_683_39E-2,
        -0.310_780_466_295_83,
         0.116_708_730_771_07E2,
         0.128_127_984_040_46E9,
        -0.985_549_096_232_76E9,
         0.282_245_469_730_02E10,
        -0.359_489_714_107_03E10,
         0.172_273_499_131_97E10,
        -0.135_513_342_407_75E5,
         0.128_487_346_646_50E8,
         0.138_657_242_832_26E1,
         0.235_988_325_565_14E6,
        -0.131_052_365_450_54E8,
         0.739_998_354_747_66E4,
        -0.551_966_970_300_60E6,
         0.371_540_859_962_33E7,
         0.191_277_292_396_60E5,
        -0.415_351_648_356_34E6,
        -0.624_598_551_925_07E2],

    I = [0,
         0,
         0,
         0,
         0,
         0,
         1,
         1,
         1,
         1,
         1,
         1,
         1,
         1,
         1,
         2,
         2,
         2,
         2,
         2,
         2,
         2,
         2,
         3,
         3,
         4,
         4,
         4,
         5,
         5,
         5,
         6,
         6,
         7],

    J = [0,
         1,
         2,
         3,
         7,
         20,
         0,
         1,
         2,
         3,
         7,
         9,
         11,
         18,
         44,
         0,
         2,
         7,
         36,
         38,
         40,
         42,
         44,
         24,
         44,
         12,
         32,
         44,
         32,
         36,
         42,
         34,
         44,
         28],
)

function temperature_impl(mt::SinglePH,model::IF97Region{:r2a},p,_h)
    P = convert_unit(u"Pa",u"MPa",p)
    h = convert_unit(u"J/kg",u"kJ/kg",_h)
    hstar = 2000.0
    Pstar = 1.0
    n = Region2a_t_ph.n
    I = Region2a_t_ph.I
    J = Region2a_t_ph.J
    π = P / Pstar
    ηη = h / hstar - 2.1

    return sum(n[i]*π^I[i]*ηη^J[i] for i=1:34)
end

const Region2b_t_ph = (
    n = [0.148_950_410_795_16E4,
    0.743_077_983_140_34E3,
    -0.977_083_187_978_37E2,
    0.247_424_647_056_74E1,
    -0.632_813_200_160_26,
    0.113_859_521_296_58E1,
    -0.478_118_636_486_25,
    0.852_081_234_315_44E-2,
    0.937_471_473_779_32,
    0.335_931_186_049_16E1,
    0.338_093_556_014_54E1,
    0.168_445_396_719_04,
    0.738_757_452_366_95,
    -0.471_287_374_361_86,
    0.150_202_731_397_07,
    -0.217_641_142_197_50E-2,
    -0.218_107_553_247_61E-1,
    -0.108_297_844_036_77,
    -0.463_333_246_358_12E-1,
    0.712_803_519_595_51E-4,
    0.110_328_317_899_99E-3,
    0.189_552_483_879_02E-3,
    0.308_915_411_605_37E-2,
    0.135_555_045_549_49E-2,
    0.286_402_374_774_56E-6,
    -0.107_798_573_575_12E-4,
    -0.764_627_124_548_14E-4,
    0.140_523_928_183_16E-4,
    -0.310_838_143_314_34E-4,
    -0.103_027_382_121_03E-5,
    0.282_172_816_350_40E-6,
    0.127_049_022_719_45E-5,
    0.738_033_534_682_92E-7,
    -0.110_301_392_389_09E-7,
    -0.814_563_652_078_33E-13,
    -0.251_805_456_829_62E-10,
    -0.175_652_339_694_07E-17,
    0.869_341_563_441_63E-14],

    I = [0,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    1,
    2,
    2,
    2,
    2,
    3,
    3,
    3,
    3,
    4,
    4,
    4,
    4,
    4,
    4,
    5,
    5,
    5,
    6,
    7,
    7,
    9,
    9],

    J = [0,
    1,
    2,
    12,
    18,
    24,
    28,
    40,
    0,
    2,
    6,
    12,
    18,
    24,
    28,
    40,
    2,
    8,
    18,
    40,
    1,
    2,
    12,
    24,
    2,
    12,
    18,
    24,
    28,
    40,
    18,
    24,
    40,
    28,
    2,
    28,
    1,
    40]
)

function temperature_impl(mt::SinglePH,model::IF97Region{:r2b},p,_h)
    P = convert_unit(u"Pa",u"MPa",p)
    h = convert_unit(u"J/kg",u"kJ/kg",_h)
    hstar = 2000.0
    Pstar = 1.0
    n = Region2b_t_ph.n
    I = Region2b_t_ph.I
    J = Region2b_t_ph.J
    π = P / Pstar
    ηη = h / hstar - 2.1

    return sum(n[i]*π^I[i]*ηη^J[i] for i=1:38)
end

const Region2c_t_ph=(n = [-0.323_683_985_552_42E13,
    0.732_633_509_021_81E13,
    0.358_250_899_454_47E12,
    -0.583_401_318_515_90E12,
    -0.107_830_682_174_70E11,
    0.208_255_445_631_71E11,
    0.610_747_835_645_16E6,
    0.859_777_225_355_80E6,
    -0.257_457_236_041_70E5,
    0.310_810_884_227_14E5,
    0.120_823_158_659_36E4,
    0.482_197_551_092_55E3,
    0.379_660_012_724_86E1,
    -0.108_429_848_800_77E2,
    -0.453_641_726_766_60E-1,
    0.145_591_156_586_98E-12,
    0.112_615_974_072_30E-11,
    -0.178_049_822_406_86E-10,
    0.123_245_796_908_32E-6,
    -0.116_069_211_309_84E-5,
    0.278_463_670_885_54E-4,
    -0.592_700_384_741_76E-3,
    0.129_185_829_918_78E-2],

    I = [-7,
        -7,
        -6,
        -6,
        -5,
        -5,
        -2,
        -2,
        -1,
        -1,
        0,
        0,
        1,
        1,
        2,
        6,
        6,
        6,
        6,
        6,
        6,
        6,
        6],

    J = [0,
        4,
        0,
        2,
        0,
        2,
        0,
        1,
        0,
        2,
        0,
        1,
        4,
        8,
        4,
        0,
        1,
        4,
        10,
        12,
        16,
        20,
        22]
)

function temperature_impl(mt::SinglePH,model::IF97Region{:r2c},p,_h)
    P = convert_unit(u"Pa",u"MPa",p)
    h = convert_unit(u"J/kg",u"kJ/kg",_h)
    hstar = 2000.0
    Pstar = 1.0
    n = Region2c_t_ph.n
    I = Region2c_t_ph.I
    J = Region2c_t_ph.J
    ππ = P / Pstar + 25
    ηη = h / hstar - 1.8

    return sum(n[i]*ππ^I[i]*ηη^J[i] for i=1:23)
end

const Region2a_t_ps = (n = [-0.392_359_838_619_84E6,
    0.515_265_738_272_70E6,
    0.404_824_431_610_48E5,
    -0.321_937_909_239_02E3,
    0.969_614_242_186_94E2,
    -0.228_678_463_717_73E2,
    -0.449_429_141_243_57E6,
    -0.501_183_360_201_66E4,
    0.356_844_635_600_15,
    0.442_353_358_481_90E5,
    -0.136_733_888_117_08E5,
    0.421_632_602_078_64E6,
    0.225_169_258_374_75E5,
    0.474_421_448_656_46E3,
    -0.149_311_307_976_47E3,
    -0.197_811_263_204_52E6,
    -0.235_543_994_707_60E5,
    -0.190_706_163_020_76E5,
    0.553_756_698_831_64E5,
    0.382_936_914_373_63E4,
    -0.603_918_605_805_67E3,
    0.193_631_026_203_31E4,
    0.426_606_436_986_10E4,
    -0.597_806_388_727_18E4,
    -0.704_014_639_268_62E3,
    0.338_367_841_075_53E3,
    0.208_627_866_351_87E2,
    0.338_341_726_561_96E-1,
    -0.431_244_284_148_93E-4,
    0.166_537_913_564_12E3,
    -0.139_862_920_558_98E3,
    -0.788_495_479_998_72,
    0.721_324_117_538_72E-1,
    -0.597_548_393_982_83E-2,
    -0.121_413_589_539_04E-4,
    0.232_270_967_338_71E-6,
    -0.105_384_635_661_94E2,
    0.207_189_254_965_02E1,
    -0.721_931_552_604_27E-1,
    0.207_498_870_811_20E-6,
    -0.183_406_579_113_79E-1,
    0.290_362_723_486_96E-6,
    0.210_375_278_936_19,
    0.256_812_397_299_99E-3,
    -0.127_990_029_337_81E-1,
    -0.821_981_026_520_18E-5],

    I = [-1.5,
    -1.5,
    -1.5,
    -1.5,
    -1.5,
    -1.5,
    -1.25,
    -1.25,
    -1.25,
    -1.0,
    -1.0,
    -1.0,
    -1.0,
    -1.0,
    -1.0,
    -0.75,
    -0.75,
    -0.5,
    -0.5,
    -0.5,
    -0.5,
    -0.25,
    -0.25,
    -0.25,
    -0.25,
    0.25,
    0.25,
    0.25,
    0.25,
    0.5,
    0.5,
    0.5,
    0.5,
    0.5,
    0.5,
    0.5,
    0.75,
    0.75,
    0.75,
    0.75,
    1.0,
    1.0,
    1.25,
    1.25,
    1.5,
    1.5],

    J = [-24,
    -23,
    -19,
    -13,
    -11,
    -10,
    -19,
    -15,
    -6,
    -26,
    -21,
    -17,
    -16,
    -9,
    -8,
    -15,
    -14,
    -26,
    -13,
    -9,
    -7,
    -27,
    -25,
    -11,
    -6,
    1,
    4,
    8,
    11,
    0,
    1,
    5,
    6,
    10,
    14,
    16,
    0,
    4,
    9,
    17,
    7,
    18,
    3,
    15,
    5,
    18]
)

function temperature_impl(mt::SinglePS,model::IF97Region{:r2a},p,_s)
    P = convert_unit(u"Pa",u"MPa",p)
    s = convert_unit(u"J/(kg*K)",u"kJ/(kg*K)",_s)
    hstar = 2000.0
    Pstar = 1.0
    n = Region2a_t_ps.n
    I = Region2a_t_ps.I
    J = Region2a_t_ps.J
    π = P / Pstar
    σσ = s / sstar - 2.0

    return sum([n[i]*π^I[i]*σσ^J[i] for i=1:46])
end

const Region2b_t_ps = ( n = [0.316_876_650_834_97E6,
    0.208_641_758_818_58E2,
    -0.398_593_998_035_99E6,
    -0.218_160_585_188_77E2,
    0.223_697_851_942_42E6,
    -0.278_417_034_458_17E4,
    0.992_074_360_714_80E1,
    -0.751_975_122_991_57E5,
    0.297_086_059_511_58E4,
    -0.344_068_785_485_26E1,
    0.388_155_642_491_15,
    0.175_112_950_857_50E5,
    -0.142_371_128_544_49E4,
    0.109_438_033_641_67E1,
    0.899_716_193_084_95,
    -0.337_597_400_989_58E4,
    0.471_628_858_183_55E3,
    -0.191_882_419_936_79E1,
    0.410_785_804_921_96,
    -0.334_653_781_720_97,
    0.138_700_347_775_05E4,
    -0.406_633_261_958_38E3,
    0.417_273_471_596_10E2,
    0.219_325_494_345_32E1,
    -0.103_200_500_090_77E1,
    0.358_829_435_167_03,
    0.525_114_537_260_66E-2,
    0.128_389_164_507_05E2,
    -0.286_424_372_193_81E1,
    0.569_126_836_648_55,
    -0.999_629_545_849_31E-1,
    -0.326_320_377_784_59E-2,
    0.233_209_225_767_23E-3,
    -0.153_348_098_574_50,
    0.290_722_882_399_02E-1,
    0.375_347_027_411_67E-3,
    0.172_966_917_024_11E-2,
    -0.385_560_508_445_04E-3,
    -0.350_177_122_926_08E-4,
    -0.145_663_936_314_92E-4,
    0.564_208_572_672_69E-5,
    0.412_861_500_746_05E-7,
    -0.206_846_711_188_24E-7,
    0.164_093_936_747_25E-8],

    I = [-6,
    -6,
    -5,
    -5,
    -4,
    -4,
    -4,
    -3,
    -3,
    -3,
    -3,
    -2,
    -2,
    -2,
    -2,
    -1,
    -1,
    -1,
    -1,
    -1,
    0,
    0,
    0,
    0,
    0,
    0,
    0,
    1,
    1,
    1,
    1,
    1,
    1,
    2,
    2,
    2,
    3,
    3,
    3,
    4,
    4,
    5,
    5,
    5],

    J = [0,
    11,
    0,
    11,
    0,
    1,
    11,
    0,
    1,
    11,
    12,
    0,
    1,
    6,
    10,
    0,
    1,
    5,
    8,
    9,
    0,
    1,
    2,
    4,
    5,
    6,
    9,
    0,
    1,
    2,
    3,
    7,
    8,
    0,
    1,
    5,
    0,
    1,
    3,
    0,
    1,
    0,
    1,
    2]
)

function temperature_impl(mt::SinglePS,model::IF97Region{:r2b},p,_s)
    P = convert_unit(u"Pa",u"MPa",p)
    s = convert_unit(u"J/(kg*K)",u"kJ/(kg*K)",_s)
    sstar = 0.7853
    Pstar = 1.0
    n = Region2b_t_ps.n
    I = Region2b_t_ps.I
    J = Region2b_t_ps.J
    π = P / Pstar
    σσ = 10.0 - s / sstar
    return sum([n[i]*π^I[i]*σσ^J[i] for i=1:44])
end

const Region2c_t_ps = (n = [0.909_685_010_053_65E3,
    0.240_456_670_884_20E4,
    -0.591_623_263_871_30E3,
    0.541_454_041_280_74E3,
    -0.270_983_084_111_92E3,
    0.979_765_250_979_26E3,
    -0.469_667_729_594_35E3,
    0.143_992_746_047_23E2,
    -0.191_042_042_304_29E2,
    0.532_991_671_119_71E1,
    -0.212_529_753_759_34E2,
    -0.311_473_344_137_60,
    0.603_348_408_946_23,
    -0.427_648_397_025_09E-1,
    0.581_855_972_552_59E-2,
    -0.145_970_082_847_53E-1,
    0.566_311_756_310_27E-2,
    -0.761_558_645_845_77E-4,
    0.224_403_429_193_32E-3,
    -0.125_610_950_134_13E-4,
    0.633_231_326_609_34E-6,
    -0.205_419_896_753_75E-5,
    0.364_053_703_900_82E-7,
    -0.297_598_977_892_15E-8,
    0.101_366_185_297_63E-7,
    0.599_257_196_923_51E-11,
    -0.206_778_701_051_64E-10,
    -0.208_742_781_818_86E-10,
    0.101_621_668_250_89E-9,
    -0.164_298_282_813_47E-9],

    I = [-2,
    -2,
    -1,
    0,
    0,
    0,
    0,
    1,
    1,
    1,
    1,
    2,
    2,
    2,
    3,
    3,
    3,
    4,
    4,
    4,
    5,
    5,
    5,
    6,
    6,
    7,
    7,
    7,
    7,
    7],

    J = [0,
    1,
    0,
    0,
    1,
    2,
    3,
    0,
    1,
    3,
    4,
    0,
    1,
    2,
    0,
    1,
    5,
    0,
    1,
    4,
    0,
    1,
    2,
    0,
    1,
    0,
    1,
    3,
    4,
    5]
)

function temperature_impl(mt::SinglePS,model::IF97Region{:r2c},p,_s)
    P = convert_unit(u"Pa",u"MPa",p)
    s = convert_unit(u"J/(kg*K)",u"kJ/(kg*K)",_s)
    sstar = 2.9251
    Pstar = 1.0
    n = Region2c_t_ps.n
    I = Region2c_t_ps.I
    J = Region2c_t_ps.J
        π = P / Pstar
    σσ = 2.0 - s / sstar
    return sum(n[i]*π^I[i]*σσ^J[i] for i=1:30)
end


text:
# generated from SQSTypeDict via AWS/src/codegen.jl
# do not edit, edit specification file and regenerate instead

type GetQueueUrlResult <: AbstractAWSType
    queueUrl::Union{Void,String}
    function GetQueueUrlResult(;queueUrl=nothing)
        new(queueUrl)
    end
    GetQueueUrlResult(pd) = parse_from_xml(GetQueueUrlResult, SQSTypeDict, pd)
end # GetQueueUrlResult
export GetQueueUrlResult

type GetQueueUrlRequest <: AbstractAWSType
    queueName::Union{Void,String}
    queueOwnerAWSAccountId::Union{Void,String}
    function GetQueueUrlRequest(;queueName=nothing, queueOwnerAWSAccountId=nothing)
        new(queueName, queueOwnerAWSAccountId)
    end
    GetQueueUrlRequest(pd) = parse_from_xml(GetQueueUrlRequest, SQSTypeDict, pd)
end # GetQueueUrlRequest
export GetQueueUrlRequest

function GetQueueUrl(env::AWSEnv, msg::GetQueueUrlRequest)
    resp::SQSResponse = sqs_execute(env, "GetQueueUrl", msg)
    if (resp.pd !== nothing) && (resp.obj === nothing)
        resp.obj = GetQueueUrlResult(resp.pd)
    end
    resp
end
GetQueueUrl(env::AWSEnv; kwargs...) = GetQueueUrl(env, GetQueueUrlRequest(; kwargs...))
export GetQueueUrl

type GetQueueAttributesResult <: AbstractAWSType
    attribute::Union{Void,Dict{String,String}}
    function GetQueueAttributesResult(;attribute=nothing)
        new(attribute)
    end
    GetQueueAttributesResult(pd) = parse_from_xml(GetQueueAttributesResult, SQSTypeDict, pd)
end # GetQueueAttributesResult
export GetQueueAttributesResult

type GetQueueAttributesRequest <: AbstractAWSType
    attributeName::Union{Void,Array{String,1}}
    queueUrl::Union{Void,String}
    function GetQueueAttributesRequest(;attributeName=nothing, queueUrl=nothing)
        new(attributeName, queueUrl)
    end
    GetQueueAttributesRequest(pd) = parse_from_xml(GetQueueAttributesRequest, SQSTypeDict, pd)
end # GetQueueAttributesRequest
export GetQueueAttributesRequest

function GetQueueAttributes(env::AWSEnv, msg::GetQueueAttributesRequest)
    resp::SQSResponse = sqs_execute(env, "GetQueueAttributes", msg)
    if (resp.pd !== nothing) && (resp.obj === nothing)
        resp.obj = GetQueueAttributesResult(resp.pd)
    end
    resp
end
GetQueueAttributes(env::AWSEnv; kwargs...) = GetQueueAttributes(env, GetQueueAttributesRequest(; kwargs...))
export GetQueueAttributes

type DeleteMessageRequest <: AbstractAWSType
    queueUrl::Union{Void,String}
    receiptHandle::Union{Void,String}
    function DeleteMessageRequest(;queueUrl=nothing, receiptHandle=nothing)
        new(queueUrl, receiptHandle)
    end
    DeleteMessageRequest(pd) = parse_from_xml(DeleteMessageRequest, SQSTypeDict, pd)
end # DeleteMessageRequest
export DeleteMessageRequest

function DeleteMessage(env::AWSEnv, msg::DeleteMessageRequest)
    resp::SQSResponse = sqs_execute(env, "DeleteMessage", msg)
    resp
end
DeleteMessage(env::AWSEnv; kwargs...) = DeleteMessage(env, DeleteMessageRequest(; kwargs...))
export DeleteMessage

type SetQueueAttributesRequest <: AbstractAWSType
    attribute::Union{Void,Dict{String,String}}
    queueUrl::Union{Void,String}
    function SetQueueAttributesRequest(;attribute=nothing, queueUrl=nothing)
        new(attribute, queueUrl)
    end
    SetQueueAttributesRequest(pd) = parse_from_xml(SetQueueAttributesRequest, SQSTypeDict, pd)
end # SetQueueAttributesRequest
export SetQueueAttributesRequest

function SetQueueAttributes(env::AWSEnv, msg::SetQueueAttributesRequest)
    resp::SQSResponse = sqs_execute(env, "SetQueueAttributes", msg)
    resp
end
SetQueueAttributes(env::AWSEnv; kwargs...) = SetQueueAttributes(env, SetQueueAttributesRequest(; kwargs...))
export SetQueueAttributes

type ChangeMessageVisibilityBatchResult <: AbstractAWSType
    batchResultErrorEntry::Union{Void,Array{BatchResultErrorEntry,1}}
    changeMessageVisibilityBatchResultEntry::Union{Void,Array{ChangeMessageVisibilityBatchResultEntry,1}}
    function ChangeMessageVisibilityBatchResult(;batchResultErrorEntry=nothing, changeMessageVisibilityBatchResultEntry=nothing)
        new(batchResultErrorEntry, changeMessageVisibilityBatchResultEntry)
    end
    ChangeMessageVisibilityBatchResult(pd) = parse_from_xml(ChangeMessageVisibilityBatchResult, SQSTypeDict, pd)
end # ChangeMessageVisibilityBatchResult
export ChangeMessageVisibilityBatchResult

type ChangeMessageVisibilityBatchRequest <: AbstractAWSType
    changeMessageVisibilityBatchRequestEntry::Union{Void,Array{ChangeMessageVisibilityBatchRequestEntry,1}}
    queueUrl::Union{Void,String}
    function ChangeMessageVisibilityBatchRequest(;changeMessageVisibilityBatchRequestEntry=nothing, queueUrl=nothing)
        new(changeMessageVisibilityBatchRequestEntry, queueUrl)
    end
    ChangeMessageVisibilityBatchRequest(pd) = parse_from_xml(ChangeMessageVisibilityBatchRequest, SQSTypeDict, pd)
end # ChangeMessageVisibilityBatchRequest
export ChangeMessageVisibilityBatchRequest

function ChangeMessageVisibilityBatch(env::AWSEnv, msg::ChangeMessageVisibilityBatchRequest)
    resp::SQSResponse = sqs_execute(env, "ChangeMessageVisibilityBatch", msg)
    if (resp.pd !== nothing) && (resp.obj === nothing)
        resp.obj = ChangeMessageVisibilityBatchResult(resp.pd)
    end
    resp
end
ChangeMessageVisibilityBatch(env::AWSEnv; kwargs...) = ChangeMessageVisibilityBatch(env, ChangeMessageVisibilityBatchRequest(; kwargs...))
export ChangeMessageVisibilityBatch

type ReceiveMessageResult <: AbstractAWSType
    message::Union{Void,Array{Message,1}}
    function ReceiveMessageResult(;message=nothing)
        new(message)
    end
    ReceiveMessageResult(pd) = parse_from_xml(ReceiveMessageResult, SQSTypeDict, pd)
end # ReceiveMessageResult
export ReceiveMessageResult

type ReceiveMessageRequest <: AbstractAWSType
    attributeName::Union{Void,Array{String,1}}
    maxNumberOfMessages::Union{Void,Int64}
    messageAttributeName::Union{Void,Array{String,1}}
    queueUrl::Union{Void,String}
    receiveRequestAttemptId::Union{Void,String}
    visibilityTimeout::Union{Void,Int64}
    waitTimeSeconds::Union{Void,Int64}
    function ReceiveMessageRequest(;attributeName=nothing, maxNumberOfMessages=nothing, messageAttributeName=nothing, queueUrl=nothing, receiveRequestAttemptId=nothing, visibilityTimeout=nothing, waitTimeSeconds=nothing)
        new(attributeName, maxNumberOfMessages, messageAttributeName, queueUrl, receiveRequestAttemptId, visibilityTimeout, waitTimeSeconds)
    end
    ReceiveMessageRequest(pd) = parse_from_xml(ReceiveMessageRequest, SQSTypeDict, pd)
end # ReceiveMessageRequest
export ReceiveMessageRequest

function ReceiveMessage(env::AWSEnv, msg::ReceiveMessageRequest)
    resp::SQSResponse = sqs_execute(env, "ReceiveMessage", msg)
    if (resp.pd !== nothing) && (resp.obj === nothing)
        resp.obj = ReceiveMessageResult(resp.pd)
    end
    resp
end
ReceiveMessage(env::AWSEnv; kwargs...) = ReceiveMessage(env, ReceiveMessageRequest(; kwargs...))
export ReceiveMessage

type ChangeMessageVisibilityRequest <: AbstractAWSType
    queueUrl::Union{Void,String}
    receiptHandle::Union{Void,String}
    visibilityTimeout::Union{Void,Int}
    function ChangeMessageVisibilityRequest(;queueUrl=nothing, receiptHandle=nothing, visibilityTimeout=nothing)
        new(queueUrl, receiptHandle, visibilityTimeout)
    end
    ChangeMessageVisibilityRequest(pd) = parse_from_xml(ChangeMessageVisibilityRequest, SQSTypeDict, pd)
end # ChangeMessageVisibilityRequest
export ChangeMessageVisibilityRequest

function ChangeMessageVisibility(env::AWSEnv, msg::ChangeMessageVisibilityRequest)
    resp::SQSResponse = sqs_execute(env, "ChangeMessageVisibility", msg)
    resp
end
ChangeMessageVisibility(env::AWSEnv; kwargs...) = ChangeMessageVisibility(env, ChangeMessageVisibilityRequest(; kwargs...))
export ChangeMessageVisibility

type DeleteQueueRequest <: AbstractAWSType
    queueUrl::Union{Void,String}
    function DeleteQueueRequest(;queueUrl=nothing)
        new(queueUrl)
    end
    DeleteQueueRequest(pd) = parse_from_xml(DeleteQueueRequest, SQSTypeDict, pd)
end # DeleteQueueRequest
export DeleteQueueRequest

function DeleteQueue(env::AWSEnv, msg::DeleteQueueRequest)
    resp::SQSResponse = sqs_execute(env, "DeleteQueue", msg)
    resp
end
DeleteQueue(env::AWSEnv; kwargs...) = DeleteQueue(env, DeleteQueueRequest(; kwargs...))
export DeleteQueue

type RemovePermissionRequest <: AbstractAWSType
    label::Union{Void,String}
    queueUrl::Union{Void,String}
    function RemovePermissionRequest(;label=nothing, queueUrl=nothing)
        new(label, queueUrl)
    end
    RemovePermissionRequest(pd) = parse_from_xml(RemovePermissionRequest, SQSTypeDict, pd)
end # RemovePermissionRequest
export RemovePermissionRequest

function RemovePermission(env::AWSEnv, msg::RemovePermissionRequest)
    resp::SQSResponse = sqs_execute(env, "RemovePermission", msg)
    resp
end
RemovePermission(env::AWSEnv; kwargs...) = RemovePermission(env, RemovePermissionRequest(; kwargs...))
export RemovePermission

type AddPermissionRequest <: AbstractAWSType
    actionName::Union{Void,Array{String,1}}
    aWSAccountId::Union{Void,Array{String,1}}
    label::Union{Void,String}
    queueUrl::Union{Void,String}
    function AddPermissionRequest(;actionName=nothing, aWSAccountId=nothing, label=nothing, queueUrl=nothing)
        new(actionName, aWSAccountId, label, queueUrl)
    end
    AddPermissionRequest(pd) = parse_from_xml(AddPermissionRequest, SQSTypeDict, pd)
end # AddPermissionRequest
export AddPermissionRequest

function AddPermission(env::AWSEnv, msg::AddPermissionRequest)
    resp::SQSResponse = sqs_execute(env, "AddPermission", msg)
    resp
end
AddPermission(env::AWSEnv; kwargs...) = AddPermission(env, AddPermissionRequest(; kwargs...))
export AddPermission

type ListQueuesResult <: AbstractAWSType
    queueUrl::Union{Void,Array{String,1}}
    function ListQueuesResult(;queueUrl=nothing)
        new(queueUrl)
    end
    ListQueuesResult(pd) = parse_from_xml(ListQueuesResult, SQSTypeDict, pd)
end # ListQueuesResult
export ListQueuesResult

type ListQueuesRequest <: AbstractAWSType
    queueNamePrefix::Union{Void,String}
    function ListQueuesRequest(;queueNamePrefix=nothing)
        new(queueNamePrefix)
    end
    ListQueuesRequest(pd) = parse_from_xml(ListQueuesRequest, SQSTypeDict, pd)
end # ListQueuesRequest
export ListQueuesRequest

function ListQueues(env::AWSEnv, msg::ListQueuesRequest)
    resp::SQSResponse = sqs_execute(env, "ListQueues", msg)
    if (resp.pd !== nothing) && (resp.obj === nothing)
        resp.obj = ListQueuesResult(resp.pd)
    end
    resp
end
ListQueues(env::AWSEnv; kwargs...) = ListQueues(env, ListQueuesRequest(; kwargs...))
export ListQueues

type CreateQueueResult <: AbstractAWSType
    queueUrl::Union{Void,String}
    function CreateQueueResult(;queueUrl=nothing)
        new(queueUrl)
    end
    CreateQueueResult(pd) = parse_from_xml(CreateQueueResult, SQSTypeDict, pd)
end # CreateQueueResult
export CreateQueueResult

type CreateQueueRequest <: AbstractAWSType
    attribute::Union{Void,Dict{String,String}}
    queueName::Union{Void,String}
    function CreateQueueRequest(;attribute=nothing, queueName=nothing)
        new(attribute, queueName)
    end
    CreateQueueRequest(pd) = parse_from_xml(CreateQueueRequest, SQSTypeDict, pd)
end # CreateQueueRequest
export CreateQueueRequest

function CreateQueue(env::AWSEnv, msg::CreateQueueRequest)
    resp::SQSResponse = sqs_execute(env, "CreateQueue", msg)
    if (resp.pd !== nothing) && (resp.obj === nothing)
        resp.obj = CreateQueueResult(resp.pd)
    end
    resp
end
CreateQueue(env::AWSEnv; kwargs...) = CreateQueue(env, CreateQueueRequest(; kwargs...))
export CreateQueue

type SendMessageBatchResult <: AbstractAWSType
    batchResultErrorEntry::Union{Void,Array{BatchResultErrorEntry,1}}
    sendMessageBatchResultEntry::Union{Void,Array{SendMessageBatchResultEntry,1}}
    function SendMessageBatchResult(;batchResultErrorEntry=nothing, sendMessageBatchResultEntry=nothing)
        new(batchResultErrorEntry, sendMessageBatchResultEntry)
    end
    SendMessageBatchResult(pd) = parse_from_xml(SendMessageBatchResult, SQSTypeDict, pd)
end # SendMessageBatchResult
export SendMessageBatchResult

type SendMessageBatchRequest <: AbstractAWSType
    queueUrl::Union{Void,String}
    sendMessageBatchRequestEntry::Union{Void,Array{SendMessageBatchRequestEntry,1}}
    function SendMessageBatchRequest(;queueUrl=nothing, sendMessageBatchRequestEntry=nothing)
        new(queueUrl, sendMessageBatchRequestEntry)
    end
    SendMessageBatchRequest(pd) = parse_from_xml(SendMessageBatchRequest, SQSTypeDict, pd)
end # SendMessageBatchRequest
export SendMessageBatchRequest

function SendMessageBatch(env::AWSEnv, msg::SendMessageBatchRequest)
    resp::SQSResponse = sqs_execute(env, "SendMessageBatch", msg)
    if (resp.pd !== nothing) && (resp.obj === nothing)
        resp.obj = SendMessageBatchResult(resp.pd)
    end
    resp
end
SendMessageBatch(env::AWSEnv; kwargs...) = SendMessageBatch(env, SendMessageBatchRequest(; kwargs...))
export SendMessageBatch

type SendMessageResult <: AbstractAWSType
    mD5OfMessageAttributes::Union{Void,String}
    mD5OfMessageBody::Union{Void,String}
    messageId::Union{Void,String}
    sequenceNumber::Union{Void,String}
    function SendMessageResult(;mD5OfMessageAttributes=nothing, mD5OfMessageBody=nothing, messageId=nothing, sequenceNumber=nothing)
        new(mD5OfMessageAttributes, mD5OfMessageBody, messageId, sequenceNumber)
    end
    SendMessageResult(pd) = parse_from_xml(SendMessageResult, SQSTypeDict, pd)
end # SendMessageResult
export SendMessageResult

type SendMessageRequest <: AbstractAWSType
    delaySeconds::Union{Void,Int}
    messageAttribute::Union{Void,Dict{String,MessageAttributeValue}}
    messageBody::Union{Void,String}
    messageDeduplicationId::Union{Void,String}
    messageGroupId::Union{Void,String}
    queueUrl::Union{Void,String}
    function SendMessageRequest(;delaySeconds=nothing, messageAttribute=nothing, messageBody=nothing, messageDeduplicationId=nothing, messageGroupId=nothing, queueUrl=nothing)
        new(delaySeconds, messageAttribute, messageBody, messageDeduplicationId, messageGroupId, queueUrl)
    end
    SendMessageRequest(pd) = parse_from_xml(SendMessageRequest, SQSTypeDict, pd)
end # SendMessageRequest
export SendMessageRequest

function SendMessage(env::AWSEnv, msg::SendMessageRequest)
    resp::SQSResponse = sqs_execute(env, "SendMessage", msg)
    if (resp.pd !== nothing) && (resp.obj === nothing)
        resp.obj = SendMessageResult(resp.pd)
    end
    resp
end
SendMessage(env::AWSEnv; kwargs...) = SendMessage(env, SendMessageRequest(; kwargs...))
export SendMessage

type DeleteMessageBatchResult <: AbstractAWSType
    batchResultErrorEntry::Union{Void,Array{BatchResultErrorEntry,1}}
    deleteMessageBatchResultEntry::Union{Void,Array{DeleteMessageBatchResultEntry,1}}
    function DeleteMessageBatchResult(;batchResultErrorEntry=nothing, deleteMessageBatchResultEntry=nothing)
        new(batchResultErrorEntry, deleteMessageBatchResultEntry)
    end
    DeleteMessageBatchResult(pd) = parse_from_xml(DeleteMessageBatchResult, SQSTypeDict, pd)
end # DeleteMessageBatchResult
export DeleteMessageBatchResult

type DeleteMessageBatchRequest <: AbstractAWSType
    deleteMessageBatchRequestEntry::Union{Void,Array{DeleteMessageBatchRequestEntry,1}}
    queueUrl::Union{Void,String}
    function DeleteMessageBatchRequest(;deleteMessageBatchRequestEntry=nothing, queueUrl=nothing)
        new(deleteMessageBatchRequestEntry, queueUrl)
    end
    DeleteMessageBatchRequest(pd) = parse_from_xml(DeleteMessageBatchRequest, SQSTypeDict, pd)
end # DeleteMessageBatchRequest
export DeleteMessageBatchRequest

function DeleteMessageBatch(env::AWSEnv, msg::DeleteMessageBatchRequest)
    resp::SQSResponse = sqs_execute(env, "DeleteMessageBatch", msg)
    if (resp.pd !== nothing) && (resp.obj === nothing)
        resp.obj = DeleteMessageBatchResult(resp.pd)
    end
    resp
end
DeleteMessageBatch(env::AWSEnv; kwargs...) = DeleteMessageBatch(env, DeleteMessageBatchRequest(; kwargs...))
export DeleteMessageBatch

type PurgeQueueRequest <: AbstractAWSType
    queueUrl::Union{Void,String}
    function PurgeQueueRequest(;queueUrl=nothing)
        new(queueUrl)
    end
    PurgeQueueRequest(pd) = parse_from_xml(PurgeQueueRequest, SQSTypeDict, pd)
end # PurgeQueueRequest
export PurgeQueueRequest

function PurgeQueue(env::AWSEnv, msg::PurgeQueueRequest)
    resp::SQSResponse = sqs_execute(env, "PurgeQueue", msg)
    resp
end
PurgeQueue(env::AWSEnv; kwargs...) = PurgeQueue(env, PurgeQueueRequest(; kwargs...))
export PurgeQueue

type ListDeadLetterSourceQueuesResult <: AbstractAWSType
    queueUrl::Union{Void,Array{String,1}}
    function ListDeadLetterSourceQueuesResult(;queueUrl=nothing)
        new(queueUrl)
    end
    ListDeadLetterSourceQueuesResult(pd) = parse_from_xml(ListDeadLetterSourceQueuesResult, SQSTypeDict, pd)
end # ListDeadLetterSourceQueuesResult
export ListDeadLetterSourceQueuesResult

type ListDeadLetterSourceQueuesRequest <: AbstractAWSType
    queueUrl::Union{Void,String}
    function ListDeadLetterSourceQueuesRequest(;queueUrl=nothing)
        new(queueUrl)
    end
    ListDeadLetterSourceQueuesRequest(pd) = parse_from_xml(ListDeadLetterSourceQueuesRequest, SQSTypeDict, pd)
end # ListDeadLetterSourceQueuesRequest
export ListDeadLetterSourceQueuesRequest

function ListDeadLetterSourceQueues(env::AWSEnv, msg::ListDeadLetterSourceQueuesRequest)
    resp::SQSResponse = sqs_execute(env, "ListDeadLetterSourceQueues", msg)
    if (resp.pd !== nothing) && (resp.obj === nothing)
        resp.obj = ListDeadLetterSourceQueuesResult(resp.pd)
    end
    resp
end
ListDeadLetterSourceQueues(env::AWSEnv; kwargs...) = ListDeadLetterSourceQueues(env, ListDeadLetterSourceQueuesRequest(; kwargs...))
export ListDeadLetterSourceQueues


text:
for N in [Float64, Rational{Int}, Float32]
    # random half-space
    rand(HalfSpace)

    # normal constructor
    hs = HalfSpace(ones(N, 3), N(5))

    # corner case: zero normal vector
    @test_throws AssertionError HalfSpace(N[0, 0], N(1))

    # dimension
    @test dim(hs) == 3

    # support function
    hs2 = HalfSpace(N[1, 0], N(1))
    @test ρ(N[2, 0], hs2) == N(2)
    @test ρ(N[-2, 0], hs2) == N(Inf)
    @test ρ(N[1, 1], hs2) == N(Inf)

    # support vector and membership function
    function test_svec(hs, d)
        @test σ(d, hs) ∈ hs
        @test σ(N(2) * d, hs) ∈ hs
        d2 = N[1, 0, 0]
        @test_throws ErrorException σ(d2, hs)
        d2 = zeros(N, 3)
        @test σ(d2, hs) ∈ hs
    end
    # tests 1
    normal = ones(N, 3)
    d = ones(N, 3)
    test_svec(HalfSpace(normal, N(5)), d)
    # tests 2
    normal = zeros(N, 3); normal[3] = N(1)
    d = zeros(N, 3); d[3] = 1
    test_svec(HalfSpace(normal, N(5)), d)

    # support vector in other directions throws an error (but see #750)
    # opposite direction
    @test_throws ErrorException σ(N[-1], HalfSpace(N[1], N(1)))
    # any other direction
    @test_throws ErrorException σ(N[1, 1], HalfSpace(N[1, 0], N(1)))

    # boundedness
    @test !isbounded(hs)

    # universality
    @test !isuniversal(hs)
    res, w = isuniversal(hs, true)
    @test !res && w ∉ hs

    # isempty
    @test !isempty(hs)

    # an_element function and membership function
    @test an_element(hs) ∈ hs

    # constraints list
    @test constraints_list(hs) == [hs]

    # constraints list from matrix-vector representation
    A = N[2 0; 1 3]
    b = N[-1, 1]
    @test constraints_list(A, b) ==
          [HalfSpace(N[2, 0], N(-1)), HalfSpace(N[1, 3], N(1))]

    # constrained dimensions
    @test constrained_dimensions(HalfSpace(N[1, 0, 1], N(1))) == [1, 3]
    @test constrained_dimensions(HalfSpace(N[0, 1, 0], N(1))) == [2]
    # sparse vector
    @test constrained_dimensions(HalfSpace(sparsevec([2], N[1], 3), N(1))) == [2]

    # halfspace_left & halfspace_right
    @test N[1, 2] ∈ halfspace_left(N[1, 1], N[2, 2])
    @test N[2, 1] ∈ halfspace_right(N[1, 1], N[2, 2])

    # translation
    @test translate(hs, N[1, 2, 3]) == HalfSpace(ones(N, 3), N(11))

    # intersection emptiness
    b = BallInf(N[3, 3, 3], N(1))
    empty_intersection, v = is_intersection_empty(b, hs, true)
    @test is_intersection_empty(b, hs) && empty_intersection
    b = BallInf(N[1, 1, 1], N(1))
    empty_intersection, v = is_intersection_empty(b, hs, true)
    @test !is_intersection_empty(b, hs) && !empty_intersection && v ∈ hs
    hs1 = HalfSpace(N[1, 0], N(1)) # x <= 1
    hs2 = HalfSpace(N[-1, 0], N(-2)) # x >= 2
    empty_intersection, v = is_intersection_empty(hs1, hs2, true)
    @test is_intersection_empty(hs1, hs2) && empty_intersection && v == N[]
    hs3 = HalfSpace(N[-1, 0], N(-1)) # x >= 1
    empty_intersection, v = is_intersection_empty(hs1, hs3, true)
    @test !is_intersection_empty(hs1, hs3) && !empty_intersection && v == N[1, 0]
    hs4 = HalfSpace(N[-1, 0], N(0)) # x >= 0
    empty_intersection, v = is_intersection_empty(hs1, hs4, true)
    @test !is_intersection_empty(hs1, hs4) && !empty_intersection && v ∈ hs1 && v ∈ hs4

    # check for tighter constraint
    c1 = HalfSpace([1., 0.], 1.)
    c2 = HalfSpace([2., 0.], 2.)
    c3 = HalfSpace([2., 0.], 1.)
    @test LazySets.is_tighter_same_dir_2D(c1, c2) &&
          LazySets.is_tighter_same_dir_2D(c3, c2)
    @test !LazySets.is_tighter_same_dir_2D(c1, c2, strict=true) &&
          LazySets.is_tighter_same_dir_2D(c3, c2, strict=true)

    # test concrete linear map of a half-space
    H = HalfSpace(N[1, -1], N(0)) # x <= y
    M = N[1 0; 0 0] # non-invertible matrix
    @test_throws ArgumentError linear_map(M, H, algorithm="vrep")
    M = N[2 2; 0 1] # invertible matrix
    @test linear_map(M, H) == HalfSpace(N[0.5, -2.0], N(0.0))

    if test_suite_polyhedra
        if N == Float64 || N == Float32
            @test linear_map(N[1 1], H) == Universe{N}(1)
        end
    end

    # conversion of the normal vector
    hs_sev = HalfSpace(SingleEntryVector(2, 3, N(1)), N(1))
    hs_vec = convert(HalfSpace{N, Vector{N}}, hs_sev)
    @test hs_vec.a == N[0, 1, 0] && hs_vec.b == N(1)
end


text:
function __init__tudataset()
    DEPNAME = "TUDataset"
    LINK = "https://www.chrsmrrs.com/graphkerneldatasets"
    DOCS = "https://chrsmrrs.github.io/datasets/docs/home/"
    DATA = "PROTEINS.zip"

    register(DataDep(
        DEPNAME,
        """
        Dataset: The $DEPNAME dataset.
        Website: $LINK)
        """,
        "$LINK/$DATA",
        "2da8de15284b88edabca2888ce5444d62f364ed41159260977088c4e53d4d848",  # if checksum omitted, will be generated by DataDeps
        post_fetch_method = unpack
    ))
end

"""
    TUDataset(name; dir=nothing)

A variety of graph benchmark datasets, *.e.g.* "QM9", "IMDB-BINARY",
"REDDIT-BINARY" or "PROTEINS", collected from the [TU Dortmund University](https://chrsmrrs.github.io/datasets/).
Retrieve from TUDataset collection the dataset `name`, where `name`
is any of the datasets available [here](https://chrsmrrs.github.io/datasets/docs/datasets/).

A `TUDataset` object can be indexed to retrieve a specific graph or a subset of graphs.

See [here](https://chrsmrrs.github.io/datasets/docs/format/) for an in-depth
description of the format.

# Usage Example

```julia
using MLDatasets: TUDataset
using LightGraphs: SimpleGraph, add_edge!

data = TUDataset("PROTEINS")

# Access first graph
d1 = data[1]

# Create a LightGraphs' graph
g = SimpleGraph(d1.num_nodes)
for (s, t) in zip(d1.source, d1.target)
    add_edge!(g, s, t)
end

# Node features
X = d1.node_attributes # (nfeatures x nnodes) matrix
```
"""
struct TUDataset <: AbstractDataset
    name::String
    metadata::Dict{String, Any}
    graphs::Vector{Graph}
    graph_data::Union{Nothing,NamedTuple}
    num_nodes::Int
    num_edges::Int
    num_graphs::Int
end

function TUDataset(name; dir=nothing)
    d = tudataset_datadir(name, dir)
    # See here for the file format: https://chrsmrrs.github.io/datasets/docs/format/

    st = readdlm(joinpath(d, "$(name)_A.txt"), ',', Int)
    # Check that the first node is labeled 1.
    # TODO this will fail if the first node is isolated
    @assert minimum(st) == 1
    source, target = st[:,1], st[:,2]

    graph_indicator = readdlm(joinpath(d, "$(name)_graph_indicator.txt"), Int) |> vec
    @assert all(sort(unique(graph_indicator)) .== 1:length(unique(graph_indicator)))

    num_nodes = length(graph_indicator)
    num_edges = length(source)
    num_graphs = length(unique(graph_indicator))

    # LOAD OPTIONAL FILES IF EXIST

    node_labels = isfile(joinpath(d, "$(name)_node_labels.txt")) ?
                    readdlm(joinpath(d, "$(name)_node_labels.txt"), Int) |> vec :
                    nothing
    edge_labels = isfile(joinpath(d, "$(name)_edge_labels.txt")) ?
                    readdlm(joinpath(d, "$(name)_edge_labels.txt"), Int) |> vec :
                    nothing
    graph_labels = isfile(joinpath(d, "$(name)_graph_labels.txt")) ?
                    readdlm(joinpath(d, "$(name)_graph_labels.txt"), Int) |> vec :
                    nothing

    node_attributes = isfile(joinpath(d, "$(name)_node_attributes.txt")) ?
                        readdlm(joinpath(d, "$(name)_node_attributes.txt"), ',', Float32)' |> collect :
                        nothing
    edge_attributes = isfile(joinpath(d, "$(name)_edge_attributes.txt")) ?
                        readdlm(joinpath(d, "$(name)_edge_attributes.txt"), ',', Float32)' |> collect :
                        nothing
    graph_attributes = isfile(joinpath(d, "$(name)_graph_attributes.txt")) ?
                        readdlm(joinpath(d, "$(name)_graph_attributes.txt"), ',', Float32)' |> collect :
                        nothing

    # We need this two vectors sorted for efficiency in tudataset_getgraph(full_dataset, i)
    @assert issorted(graph_indicator)
    if !issorted(source)
        p = sortperm(source)
        source, target[p] = source[p], target[p]
        if edge_labels !== nothing
            edge_labels = edge_labels[p]
        end
        if edge_attributes !== nothing
            edge_attributes = edge_attributes[:,p]
        end
    end

    full_dataset = (; num_nodes, num_edges, num_graphs,
                        source, target,
                        graph_indicator,
                        node_labels,
                        edge_labels,
                        graph_labels,
                        node_attributes,
                        edge_attributes,
                        graph_attributes)

    graphs = [tudataset_getgraph(full_dataset, i) for i in 1:num_graphs]
    graph_data = (; features = graph_attributes, targets = graph_labels) |> clean_nt
    metadata = Dict{String, Any}("name" => name)
    return TUDataset(name, metadata, graphs, graph_data, num_nodes, num_edges, num_graphs)
end

function tudataset_datadir(name, dir = nothing)
    dir = isnothing(dir) ? datadep"TUDataset" : dir
    LINK = "https://www.chrsmrrs.com/graphkerneldatasets/$name.zip"
    d  = joinpath(dir, name)
    if !isdir(d)
        DataDeps.fetch_default(LINK, dir)
        currdir = pwd()
        cd(dir) # Needed since `unpack` extracts in working dir
        DataDeps.unpack(joinpath(dir, "$name.zip"))
        cd(currdir)
    end
    @assert isdir(d)
    return d
end

function tudataset_getgraph(data::NamedTuple, i::Int)
    vmin = searchsortedfirst(data.graph_indicator, i)
    vmax = searchsortedlast(data.graph_indicator, i)
    nodes = vmin:vmax
    node_labels = isnothing(data.node_labels) ? nothing : getobs(data.node_labels, nodes)
    node_attributes = isnothing(data.node_attributes) ? nothing : getobs(data.node_attributes, nodes)

    emin = searchsortedfirst(data.source, vmin)
    emax = searchsortedlast(data.source, vmax)
    edges = emin:emax
    source = data.source[edges] .- vmin .+ 1
    target = data.target[edges] .- vmin .+ 1
    edge_labels = isnothing(data.edge_labels) ? nothing : getobs(data.edge_labels, edges)
    edge_attributes = isnothing(data.edge_attributes) ? nothing : getobs(data.edge_attributes, edges)

    num_nodes = length(nodes)
    num_edges = length(source)
    node_data = (features = node_attributes, targets = node_labels)
    edge_data = (features = edge_attributes, targets = edge_labels)

    return Graph(; num_nodes, num_edges,
                edge_index = (source, target),
                node_data = node_data |> clean_nt,
                edge_data = edge_data |> clean_nt,
                )
end

Base.length(data::TUDataset) = length(data.graphs)

function Base.getindex(data::TUDataset)
    if data.graph_data === nothing
        return getobs(data.graphs)
    else
        return getobs((; data.graphs, data.graph_data...))
    end
end

function Base.getindex(data::TUDataset, i)
    if data.graph_data === nothing
        return getobs(data.graphs, i)
    else
        return getobs((; data.graphs, data.graph_data...), i)
    end
end


text:
using CSV, DataFrames, JSON3
using Dash, DashHtmlComponents, DashCoreComponents

df5 = DataFrame(
    x = [1, 2, 1, 2],
    y = [1, 2, 3, 4],
    customdata = [1, 2, 3, 4],
    fruit = ["apple", "apple", "orange", "orange"],
)

app = dash()

app.layout = html_div() do
    dcc_graph(id = "basic-interactions", figure = (
        data = [
            (
                x = [1,2,3,4],
                y = [4,1,3,5],
                text = ["a", "b", "c", "d"],
                customdata = ["c.a", "c.b", "c.c", "c.d"],
                name = "Trace 1",
                mode = "markers",
                marker = (size = 12,)
            ),
            (
                x = [1,2,3,4],
                y = [9,4,1,4],
                text = ["w", "x", "y", "z"],
                customdata = ["c.w", "c.x", "c.y", "c.z"],
                name = "Trace 2",
                mode = "markers",
                marker = (size = 12,)
            )
        ],
        layout = (clickmode = "event+select",)
    )),
    html_div(
        children = [
            html_div(
                children = [
                    dcc_markdown("
                    **Hover Data**

                    Mouse over values in the graph.
                    "),
                    html_pre(id = "hover-data"),
                ],
            ),
            html_div(
                children = [
                    dcc_markdown("
                    **Click Data**

                    Click on points in the graph.
                    "),
                    html_pre(id = "click-data"),
                ],
            ),
            html_div(
                children = [
                    dcc_markdown("
                    **Selection Data**

                    Choose the lasso or rectangle tool in the graph's menu
                    bar and then select points in the graph.

                    Note that if `layout.clickmode = 'event+select'`, selection data also
                    accumulates (or un-accumulates) selected data if you hold down the shift
                    button while clicking.
                    "),
                    html_pre(id = "selected-data"),
                ],
            ),
            html_div(
                children = [
                    dcc_markdown("
                    **Zoom and Relayout Data**

                    Click and drag on the graph to zoom or click on the zoom
                    buttons in the graph's menu bar.
                    Clicking on legend items will also fire
                    this event.
                    "),
                    html_pre(id = "relayout-data"),
                ],
            ),
        ],
    )

end

callback!(
    app,
    Output("hover-data", "children"),
    Input("basic-interactions", "hoverData"),
) do hover_data

    return JSON3.write(hover_data)
end

callback!(
    app,
    Output("click-data", "children"),
    Input("basic-interactions", "clickData"),
) do click_data

    return JSON3.write(click_data)
end

callback!(
    app,
    Output("selected-data", "children"),
    Input("basic-interactions", "selectedData"),
) do selected_data

    return string(selected_data)
end

callback!(
    app,
    Output("relayout-data", "children"),
    Input("basic-interactions", "relayoutData"),
) do relayout_data

    return string(relayout_data)
end

run_server(app, "0.0.0.0", debug=true)

max_stars_repo_name: joelostblom/dash-docs

max_issues_repo_name: joelostblom/dash-docs

max_forks_repo_name: joelostblom/dash-docs


text:
###### Operations for JuMPExpressionMatrix ######

function _remove_undef!(expression_array::T) where T<:JuMPExpressionMatrix

    for j in 1:size(expression_array)[2]

        for i in 1:size(expression_array)[1]

            if !isassigned(expression_array, i, j)
                 expression_array[i,j] = zero(eltype(expression_array))
            else
                continue
            end

        end

    end

    return

end

###### Operations for JuMPDenseAxisExpressionMatrix ######

function _remove_undef!(axis_expression_array::JuMP.Containers.DenseAxisArray)
    _remove_undef!(axis_expression_array.data)
end

function _add_to_expression!(expression_array::T,
                             ix::Int64,
                             jx::Int64,
                             var::JV,
                             multiplier::Float64) where {T, JV<:JuMP.AbstractVariableRef}

    if isassigned(expression_array, ix, jx)
        JuMP.add_to_expression!(expression_array[ix,jx], multiplier, var)
    else
        expression_array[ix,jx] = multiplier*var
    end

    return

end

function _add_to_expression!(expression_array::T,
                             ix::Int64,
                             jx::Int64,
                             var::JV,
                             multiplier::Float64,
                             constant::Float64) where {T, JV<:JuMP.AbstractVariableRef}

    if isassigned(expression_array, ix, jx)
        JuMP.add_to_expression!(expression_array[ix,jx], multiplier, var)
        JuMP.add_to_expression!(expression_array[ix,jx], constant)
    else
        expression_array[ix,jx] = multiplier*var + constant
    end

    return

end

function _add_to_expression!(expression_array::T,
                             ix::Int64,
                             jx::Int64,
                             value::Float64) where T

    if isassigned(expression_array, ix, jx)
        expression_array[ix,jx].constant +=  value
    else
        expression_array[ix,jx] = zero(eltype(expression_array)) + value
    end

    return

end

function _add_to_expression!(expression_array::T,
                            ix::Int64,
                            jx::Int64,
                            parameter::PJ.ParameterRef) where T

    if isassigned(expression_array, ix, jx)
        JuMP.add_to_expression!(expression_array[ix,jx], 1.0, parameter);
    else
        expression_array[ix,jx] = zero(eltype(expression_array)) + parameter;
    end

    return

end


text:
include("MeshStruct.jl")

function createnodes(points)
    nodes = []
    for i in 1:length(points)
        node = Node()
        node.index = i
        node.centroid = points[i]
        node.ifaces = []
        node.icells = []
        push!(nodes, node)
    end
    return nodes
end

function createfaces(faces, owner, neighbour)
    faces_ = []
    for i in 1:length(faces)
        face = Face()
        face.index = i
        face.centroid = []
        face.inodes = faces[i]
        face.iowner = owner[i]
        if i <= length(neighbour)
            face.ineighbour = neighbour[i]
        else
            face.ineighbour = -1
        end
        face.area = 0
        face.sf = []
        face.cn = []
        face.geodiff = 0
        face.T = []
        face.gf = 0
        face.walldist = 0
        face.iownerneighbourcoeff = 1
        face.ineighbourownercoeff = 1
        push!(faces_, face)
    end
    return faces_
end

function createboundaries(boundary)
    boundaries = []
    for i in 1:length(boundary)
        boundarydict = Boundary()
        boundarydict.name = boundary[i]["name"]
        boundarydict.index = i
        boundarydict.type = boundary[i]["type"]
        boundarydict.nfaces = boundary[i]["nFaces"]
        boundarydict.startface = boundary[i]["startFace"]
        push!(boundaries, boundarydict)
    end
    return boundaries
end

function createcells(owner)
    cells = []
    current_owner = 0
    for i in 1:length(owner)
        if owner[i] == current_owner + 1
            current_owner = owner[i]
            cell = Cell()
            cell.index = current_owner
            cell.ineighbours = []
            cell.ifaces = []
            cell.inodes = []
            cell.volume = 0
            cell.facesign = []
            cell.nneighbours = 0
            cell.centroid = []
            push!(cells, cell)
        end
    end
    return cells
end


text:
module NetworkOptions

include("ca_roots.jl")
include("verify_host.jl")

end # module


text:
@register Base.getindex(x,i::Integer)
@register Base.getindex(x,i)
@register Base.binomial(n,k)

@register Base.signbit(x)
ModelingToolkit.derivative(::typeof(signbit), args::NTuple{1,Any}, ::Val{1}) = 0

ModelingToolkit.derivative(::typeof(abs), args::NTuple{1,Any}, ::Val{1}) = IfElse.ifelse(signbit(args[1]),-one(args[1]),one(args[1]))

@register IfElse.ifelse(x,y,z::Any)
ModelingToolkit.derivative(::typeof(IfElse.ifelse), args::NTuple{3,Any}, ::Val{1}) = 0
ModelingToolkit.derivative(::typeof(IfElse.ifelse), args::NTuple{3,Any}, ::Val{2}) = IfElse.ifelse(args[1],1,0)
ModelingToolkit.derivative(::typeof(IfElse.ifelse), args::NTuple{3,Any}, ::Val{3}) = IfElse.ifelse(args[1],0,1)


text:
#=
display:
- Julia version: 1.1.0
- Author: bramb
- Date: 2019-03-12
=#

using MetaGraphs

import Base.display

function Base.display(mime::MIME"image/svg+xml", mg::MetaDiGraph)
    _display_svg(mg)
end

function Base.display(mime::MIME"image/png", mg::MetaDiGraph)
    _display_png(mg)
end

function _display_svg(x)
    file = "tmp.dot"
    write(file,to_dot(x))
    display("image/svg+xml", read(`dot -Tsvg $file`,String))
    rm(file)
end

function _display_png(x)
    file = "tmp.dot"
    write(file,to_dot(x))
    display("image/png", read(`dot -Tpng -Gfontname=Sans $file`))
    rm(file)
end

show_svg(mg::MetaDiGraph) = display("image/svg+xml",mg)

show_png(mg::MetaDiGraph) = display("image/png",mg)


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

mutable struct TagsPatchResource <: SwaggerModel
    operation::Any # spec type: Union{ Nothing, String } # spec name: operation
    properties::Any # spec type: Union{ Nothing, Tags } # spec name: properties

    function TagsPatchResource(;operation=nothing, properties=nothing)
        o = new()
        validate_property(TagsPatchResource, Symbol("operation"), operation)
        setfield!(o, Symbol("operation"), operation)
        validate_property(TagsPatchResource, Symbol("properties"), properties)
        setfield!(o, Symbol("properties"), properties)
        o
    end
end # type TagsPatchResource

const _property_map_TagsPatchResource = Dict{Symbol,Symbol}(Symbol("operation")=>Symbol("operation"), Symbol("properties")=>Symbol("properties"))
const _property_types_TagsPatchResource = Dict{Symbol,String}(Symbol("operation")=>"String", Symbol("properties")=>"Tags")
Base.propertynames(::Type{ TagsPatchResource }) = collect(keys(_property_map_TagsPatchResource))
Swagger.property_type(::Type{ TagsPatchResource }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_TagsPatchResource[name]))}
Swagger.field_name(::Type{ TagsPatchResource }, property_name::Symbol) =  _property_map_TagsPatchResource[property_name]

const _allowed_TagsPatchResource_operation = ["Replace", "Merge", "Delete"]

function check_required(o::TagsPatchResource)
    true
end

function validate_property(::Type{ TagsPatchResource }, name::Symbol, val)
    if name === Symbol("operation")
        Swagger.validate_param(name, "TagsPatchResource", :enum, val, _allowed_TagsPatchResource_operation)
    end
end