text:
abstract type AbstractOrdering end
struct CartesianOrdering <: AbstractOrdering end
struct HilbertOrdering <: AbstractOrdering end

function brickgrid(referencecell::LobattoCell, coordinates::Tuple;
                   ordering::AbstractOrdering=CartesianOrdering(),
                   periodic=nothing)
    return brickgrid(identity, referencecell, coordinates;
                   ordering=ordering, periodic=periodic)
end

function brickgrid(warp::Function, referencecell::LobattoCell,
                   coordinates::Tuple;
                   ordering::AbstractOrdering=CartesianOrdering(),
                   periodic=nothing)

    M = ndims(referencecell)
    if M != length(coordinates)
        throw(ArgumentError("The number of dimensions of the reference cell and number of coordinates must match."))
    end

    dims = length.(coordinates) .- 1
    if !all(dims .>= 1)
        throw(ArgumentError("Each coordinate needs to be of atleast length 2."))
    end

    A = arraytype(referencecell)
    coordinates = adapt.(A, collect.(coordinates))
    coordinates = ntuple(M) do i
        coorddims = ntuple(j->ifelse(i==j, length(coordinates[i]), 1), M)
        return reshape(coordinates[i], coorddims)
    end
    vertices = SVector.(coordinates...)

    linear = adapt(A, collect(LinearIndices(dims.+1)))
    connectivity = similar(vertices, NTuple{2^M, Int}, dims)

    if M == 1
        @tullio connectivity[i] = (linear[i], linear[i + 1])
    elseif M == 2
        @tullio connectivity[i, j] = (
                                      linear[i,     j    ],
                                      linear[i + 1, j    ],
                                      linear[i,     j + 1],
                                      linear[i + 1, j + 1],
                                     )
    elseif M == 3
        @tullio connectivity[i, j, k] = (
                                         linear[i,     j,     k    ],
                                         linear[i + 1, j,     k    ],
                                         linear[i,     j + 1, k    ],
                                         linear[i + 1, j + 1, k    ],
                                         linear[i,     j,     k + 1],
                                         linear[i + 1, j,     k + 1],
                                         linear[i,     j + 1, k + 1],
                                         linear[i + 1, j + 1, k + 1],
                                        )
    else
        throw(ArgumentError("Reference cells with number of dimensions greater than 3 not implemented."))
    end

    if isnothing(periodic)
        periodic = ntuple(i->false, M)
    end

    boundaryfaces = fill!(A{Int, M+1}(undef, 2*M, size(connectivity)...), 0)
    if M == 1
        if !periodic[1]
            boundaryfaces[1,     1:1] .= 1
            boundaryfaces[2, end:end] .= 2
        end
    elseif M == 2
        if !periodic[1]
            boundaryfaces[1,   1,   :] .= 1
            boundaryfaces[2, end,   :] .= 2
        end
        if !periodic[2]
            boundaryfaces[3,   :,   1] .= 3
            boundaryfaces[4,   :, end] .= 4
        end
    elseif M == 3
        if !periodic[1]
            boundaryfaces[1,   1,   :,   :] .= 1
            boundaryfaces[2, end,   :,   :] .= 2
        end
        if !periodic[2]
            boundaryfaces[3,   :,   1,   :] .= 3
            boundaryfaces[4,   :, end,   :] .= 4
        end
        if !periodic[3]
            boundaryfaces[5,   :,   :,   1] .= 5
            boundaryfaces[6,   :,   :, end] .= 6
        end
    else
        throw(ArgumentError("Reference cells with number of dimensions greater than 3 not implemented."))
    end
    boundaryfaces = reshape(boundaryfaces, 2*M, length(connectivity))

    if M == 1
        corners = A{Int, M+1}(undef, 2, size(connectivity)...)
        corners[:] .= 1:length(corners)

        corners[2, 1:end-1] .= corners[1, 2:end]
        if periodic[1]
          corners[2, end:end] .= corners[1, 1:1]
        end

        facenumbers = (corners,)
    elseif M == 2
        corners = A{Int, M+1}(undef, 4, size(connectivity)...)
        corners[:] .= 1:length(corners)

        corners[[2,4], 1:end-1, :] .= corners[[1,3], 2:end, :]
        if periodic[1]
          corners[[2,4], end, :] .= corners[[1,3], 1, :]
        end

        corners[[3,4], :, 1:end-1] .= corners[[1,2], :, 2:end]
        if periodic[2]
          corners[[3,4], :, end] .= corners[[1,2], :, 1]
        end

        edges = A{Int, M+1}(undef, 4, size(connectivity)...)
        edges[:] .= 1:length(edges)

        edges[2, 1:end-1, :] .= edges[1, 2:end, :]
        if periodic[1]
          edges[2, end, :] .= edges[1, 1, :]
        end

        edges[4, :, 1:end-1] .= edges[3, :, 2:end]
        if periodic[2]
          edges[4, :, end] .= edges[3, :, 1]
        end

        facenumbers = (edges, corners)
    elseif M == 3
        corners = A{Int, M+1}(undef, 8, size(connectivity)...)
        corners[:] .= 1:length(corners)

        corners[[2,4,6,8], 1:end-1, :, :] .= corners[[1,3,5,7], 2:end, :, :]
        if periodic[1]
            corners[[2,4,6,8], end, :, :] .= corners[[1,3,5,7], 1, :, :]
        end

        corners[[3,4,7,8], :, 1:end-1, :] .= corners[[1,2,5,6], :, 2:end, :]
        if periodic[2]
            corners[[3,4,7,8], :, end, :] .= corners[[1,2,5,6], :, 1, :]
        end

        corners[[5,6,7,8], :, :, 1:end-1] .= corners[[1,2,3,4], :, :, 2:end]
        if periodic[3]
            corners[[5,6,7,8], :, :, end] .= corners[[1,2,3,4], :, :, 1]
        end

        edges = A{Int, M+1}(undef, 12, size(connectivity)...)
        edges[:] .= 1:length(edges)

        edges[[2,4], :, 1:end-1, :] .= edges[[1,3], :, 2:end, :]
        if periodic[2]
          edges[[2,4], :, end, :] .= edges[[1,3], :, 1, :]
        end
        edges[[3,4], :, :, 1:end-1] .= edges[[1,2], :, :, 2:end]
        if periodic[3]
          edges[[3,4], :, :, end] .= edges[[1,2], :, :, 1]
        end

        edges[[6,8], 1:end-1, :, :] .= edges[[5,7], 2:end, :, :]
        if periodic[1]
          edges[[6,8], end, :, :] .= edges[[5,7], 1, :, :]
        end
        edges[[7,8], :, :, 1:end-1] .= edges[[5,6], :, :, 2:end]
        if periodic[3]
          edges[[7,8], :, :, end] .= edges[[5,6], :, :, 1]
        end

        edges[[10,12], 1:end-1, :, :] .= edges[[9,11], 2:end, :, :]
        if periodic[1]
          edges[[10,12], end, :, :] .= edges[[9,11], 1, :, :]
        end
        edges[[11,12], :, 1:end-1, :] .= edges[[9,10], :, 2:end, :]
        if periodic[2]
          edges[[11,12], :, end, :] .= edges[[9,10], :, 1, :]
        end

        faces = A{Int, M+1}(undef, 6, size(connectivity)...)
        faces[:] .= 1:length(faces)

        faces[2, 1:end-1, :, :] .= faces[1, 2:end, :, :]
        if periodic[1]
          faces[2, end, :, :] .= faces[1, 1, :, :]
        end

        faces[4, :, 1:end-1, :] .= faces[3, :, 2:end, :]
        if periodic[2]
          faces[4, :, end, :] .= faces[3, :, 1, :]
        end

        faces[6, :, :, 1:end-1] .= faces[5, :, :, 2:end]
        if periodic[3]
          faces[6, :, :, end] .= faces[5, :, :, 1]
        end

        facenumbers = (faces, edges, corners,)
    else
        throw(ArgumentError("Reference cells with number of dimensions greater than 3 not implemented."))
    end
    facenumbers = ntuple(length(facenumbers)) do i
        return reshape(facenumbers[i], size(facenumbers[i], 1), :)
    end

    if ordering isa CartesianOrdering
    elseif ordering isa HilbertOrdering
        perm = hilbertperm(dims)
        connectivity = connectivity[perm]
        boundaryfaces = boundaryfaces[:, perm]
        facenumbers = ntuple(i->facenumbers[i][:, perm], length(facenumbers))
    else
        throw(ArgumentError("Unsuported ordering $ordering."))
    end

    faces = ntuple(length(facenumbers)) do i
        globalfacenumbers = vec(adapt(Array, facenumbers[i]))
        globalfacenumbers = numbercontiguous(globalfacenumbers)
        localfacenumbers = 1:length(globalfacenumbers)
        P = M == 3 ? 4 : M
        facepermutations = zeros(Permutation{P}, length(globalfacenumbers))

        S = sparse(localfacenumbers, globalfacenumbers, facepermutations)
        if A <: CuArray
            S = adapt(A, GeneralSparseMatrixCSC(S))
        end
        return S
    end

    return NodalGrid(warp, referencecell, vertices, connectivity;
                     faces=faces, boundaryfaces=boundaryfaces)
end

function cubespherewarp(point)
    # Put the points in reverse magnitude order
    p = sortperm(abs.(point))
    point = point[p]

    # Convert to angles
    ξ = π * point[2] / 4point[3]
    η = π * point[1] / 4point[3]

    # Compute the ratios
    y_x = tan(ξ)
    z_x = tan(η)

    # Compute the new points
    x = point[3] / hypot(1, y_x, z_x)
    y = x * y_x
    z = x * z_x

    # Compute the new points and unpermute
    point = SVector(z, y, x)[sortperm(p)]

    return point
end

function cubedshellconnectivity(referencecell::LobattoCell,
                                R::Real,
                                ncells::Integer;
                                ordering::AbstractOrdering=CartesianOrdering())

    if ndims(referencecell) != 2
        throw(ArgumentError("cubed sphere shell requires 2-D reference cell"))
    end

    # Get the array and float type from the reference cell
    A = arraytype(referencecell)
    T = floattype(referencecell)

    # Create the 1-D grid along an edge of the cube
    coord1d = adapt(A, collect(range(-T(R), length = ncells + 1, stop = R)))

    # Create the vertices and cell connectivity on each cube face
    vertices = similar(coord1d, SVector{3, T}, (ncells+1, ncells+1, 6))

    # face 1: ξ1 = -1
    @tullio vertices[i, j, 1] = SVector(-R, coord1d[i], coord1d[j])

    # face 2: ξ1 =  1
    @tullio vertices[i, j, 2] = SVector( R, -coord1d[i], coord1d[j])

    # face 3: ξ2 = -1
    @tullio vertices[i, j, 3] = SVector(-coord1d[i], -R, coord1d[j])

    # face 4: ξ2 =  1
    @tullio vertices[i, j, 4] = SVector(coord1d[i],  R, coord1d[j])

    # face 5: ξ3 = -1
    @tullio vertices[i, j, 5] = SVector(coord1d[i], coord1d[j], -R)

    # face 6: ξ3 =  1
    @tullio vertices[i, j, 6] = SVector(coord1d[i], -coord1d[j],  R)

    # Create a connectivity map for each element
    linear = adapt(A, collect(LinearIndices((ncells + 1, ncells + 1, 6))))
    conn = similar(vertices, Int, (2, 2, ncells, ncells, 6))
    @tullio conn[a, b, i, j, f] = linear[i + a - 1, j + b - 1, f]

    # Remove the vertex references that are actually for duplicate points

    # face 3/4, edge 1 -> face 2/1, edge 2
    conn[1, :,   1, :, [3, 4]] .= conn[2, :, end, :, [2, 1]]
    # face 3/4, edge 2 -> face 1/2, edge 2
    conn[2, :, end, :, [3, 4]] .= conn[1, :,   1, :, [1, 2]]

    # face 5, edge 1 -> face 1, edge 3
    conn[1, :,   1, :, 5] .= conn[:,      1, :,        1, 1]
    # face 5, edge 2 -> face 2, edge -3
    conn[2, :, end, :, 5] .= conn[2:-1:1, 1, end:-1:1, 1, 2]
    # face 5, edge 3 -> face 3, edge -3
    conn[:, 1, :,   1, 5] .= conn[2:-1:1, 1, end:-1:1, 1, 3]
    # face 5, edge 4 -> face 3, edge 3
    conn[:, 2, :, end, 5] .= conn[:,      1, :,        1, 4]

    # face 6, edge 1 -> face 1, edge 4
    conn[1, :,   1, :, 6] .= conn[2:-1:1, 2, end:-1:1, end, 1]
    # face 6, edge 2 -> face 2, edge -4
    conn[2, :, end, :, 6] .= conn[:,      2, :,        end, 2]
    # face 6, edge 3 -> face 3, edge 4
    conn[:, 1, :,   1, 6] .= conn[:,      2, :,        end, 4]
    # face 6, edge 4 -> face 3, edge -4
    conn[:, 2, :, end, 6] .= conn[2:-1:1, 2, end:-1:1, end, 3]

    connectivity = similar(vertices, NTuple{4, Int}, (ncells, ncells, 6))

    @tullio connectivity[i, j, f] = (
                                     conn[1, 1, i, j, f],
                                     conn[2, 1, i, j, f],
                                     conn[1, 2, i, j, f],
                                     conn[2, 2, i, j, f],
                                    )

    if ordering isa CartesianOrdering
    else
        throw(ArgumentError("Unsuported ordering $ordering."))
    end

    return (vertices = vertices, connectivity = connectivity)
end

function cubedspheregrid(referencecell::LobattoCell,
                         vert_coordinate::AbstractArray,
                         ncells_h_panel::Integer;
                         horz_ordering::AbstractOrdering=CartesianOrdering())

    if ndims(referencecell) != 3
        throw(ArgumentError("cubed sphere shell requires 3-D reference cell"))
    end

    if length(vert_coordinate) < 2
        throw(ArgumentError("Vertical coordinate needs to be of atleast length 2."))
    end

    Nq = size(referencecell)
    if Nq[1] != Nq[2]
        throw(ArgumentError("`referencecell` should have first two dims the same"))
    end

    h_refcell = similar(referencecell, Nq[1], Nq[2])

    # Get the array and float type from the reference cell
    A = arraytype(referencecell)
    T = floattype(referencecell)

    # Create a unit shell
    (h_vert, h_conn) = cubedshellconnectivity(h_refcell,
                                              1,
                                              ncells_h_panel;
                                              ordering = horz_ordering)

    # Blow out to a stacked cubed shell
    vert_coordinate = adapt(A, collect(vert_coordinate))
    vertices = similar(
                       h_vert,
                       size(h_vert)...,
                       length(vert_coordinate),
                       )
    @tullio vertices[x, y, f, z] = h_vert[x, y, f] * vert_coordinate[z]

    # Add the vertical connectivity
    connectivity = similar(
                           h_conn,
                           NTuple{8, Int},
                           length(vert_coordinate) - 1,
                           size(h_conn)...,
                          )
    offset = prod(size(h_vert))
    @tullio connectivity[z, x, y, f] = begin
        c = h_conn[x, y, f]
        l = (z - 1) * offset .+ c
        u = z * offset .+ c
        (l..., u...)
    end

    return NodalGrid(cubespherewarp, referencecell, vertices, connectivity)
end


text:
function S2Point(arg0::Vector3D)
    return S2Point((Vector3D,), arg0)
end

function S2Point(arg0::jdouble, arg1::jdouble)
    return S2Point((jdouble, jdouble), arg0, arg1)
end

function distance(::Type{S2Point}, arg0::S2Point, arg1::S2Point)
    return jcall(S2Point, "distance", jdouble, (S2Point, S2Point), arg0, arg1)
end

function distance(obj::S2Point, arg0::Point)
    return jcall(obj, "distance", jdouble, (Point,), arg0)
end

function equals(obj::S2Point, arg0::Object)
    return jcall(obj, "equals", jboolean, (Object,), arg0)
end

function get_phi(obj::S2Point)
    return jcall(obj, "getPhi", jdouble, ())
end

function get_space(obj::S2Point)
    return jcall(obj, "getSpace", Space, ())
end

function get_theta(obj::S2Point)
    return jcall(obj, "getTheta", jdouble, ())
end

function get_vector(obj::S2Point)
    return jcall(obj, "getVector", Vector3D, ())
end

function hash_code(obj::S2Point)
    return jcall(obj, "hashCode", jint, ())
end

function is_na_n(obj::S2Point)
    return jcall(obj, "isNaN", jboolean, ())
end

function negate(obj::S2Point)
    return jcall(obj, "negate", S2Point, ())
end

function to_string(obj::S2Point)
    return jcall(obj, "toString", JString, ())
end

ext: jl


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

mutable struct ContainerServiceLinuxProfile <: SwaggerModel
    adminUsername::Any # spec type: Union{ Nothing, String } # spec name: adminUsername
    ssh::Any # spec type: Union{ Nothing, ContainerServiceSshConfiguration } # spec name: ssh

    function ContainerServiceLinuxProfile(;adminUsername=nothing, ssh=nothing)
        o = new()
        validate_property(ContainerServiceLinuxProfile, Symbol("adminUsername"), adminUsername)
        setfield!(o, Symbol("adminUsername"), adminUsername)
        validate_property(ContainerServiceLinuxProfile, Symbol("ssh"), ssh)
        setfield!(o, Symbol("ssh"), ssh)
        o
    end
end # type ContainerServiceLinuxProfile

const _property_map_ContainerServiceLinuxProfile = Dict{Symbol,Symbol}(Symbol("adminUsername")=>Symbol("adminUsername"), Symbol("ssh")=>Symbol("ssh"))
const _property_types_ContainerServiceLinuxProfile = Dict{Symbol,String}(Symbol("adminUsername")=>"String", Symbol("ssh")=>"ContainerServiceSshConfiguration")
Base.propertynames(::Type{ ContainerServiceLinuxProfile }) = collect(keys(_property_map_ContainerServiceLinuxProfile))
Swagger.property_type(::Type{ ContainerServiceLinuxProfile }, name::Symbol) = Union{Nothing,eval(Meta.parse(_property_types_ContainerServiceLinuxProfile[name]))}
Swagger.field_name(::Type{ ContainerServiceLinuxProfile }, property_name::Symbol) =  _property_map_ContainerServiceLinuxProfile[property_name]

function check_required(o::ContainerServiceLinuxProfile)
    (getproperty(o, Symbol("adminUsername")) === nothing) && (return false)
    (getproperty(o, Symbol("ssh")) === nothing) && (return false)
    true
end

function validate_property(::Type{ ContainerServiceLinuxProfile }, name::Symbol, val)
    if name === Symbol("adminUsername")
    end
end


text:
is_ch_type(::Val{:Array})  = true
can_be_nullable(::Val{:Array}) = false
result_type(::Val{:Array}, nested::TypeAst) = Vector{result_type(nested)}

"""
    Nested arrays written in flatten form after information about their
    sizes (offsets really).
    One element of array of arrays can be represented as tree:
    (0 depth)          [[3, 4], [5, 6]]
                      |               |
    (1 depth)      [3, 4]           [5, 6]
                   |    |           |    |
    (leaf)        3     4          5     6

    Offsets (sizes) written in breadth-first search order. In example above
    following sequence of offset will be written: 4 -> 2 -> 4
    1) size of whole array: 4
    2) size of array 1 in depth=1: 2
    3) size of array 2 plus size of all array before in depth=1: 2 + 2 = 4

    After sizes info comes flatten data: 3 -> 4 -> 5 -> 6
"""

read_state_prefix(sock::ClickHouseSock, ::Val{:Array}, nested::TypeAst) =
                    read_state_prefix(sock, nested)

write_state_prefix(sock::ClickHouseSock, ::Val{:Array}, nested::TypeAst) =
                write_state_prefix(sock, nested)

function read_offsets!(dest::Vector{Vector{UInt64}}, sock, nest::TypeAst)
    prev_level = dest[end]
    new_level = Vector{UInt64}()
    last_offset = 0
    for offset in prev_level
        for i in 1:(offset - last_offset)
            push!(new_level, chread(sock, UInt64))
        end
        last_offset = offset
    end
    push!(dest, new_level)

    return nest.name == :Array ?
        read_offsets!(dest, sock, nest.args[1]) :
        nest

end

function split_vector(data::T, offsets) where {T <: AbstractVector}
    result = Vector{T}(undef, length(offsets))
    last_offset = 1
    for (i,offset) in enumerate(offsets)
        result[i] = data[last_offset:offset]
        last_offset = offset + 1
    end
    return result
end

function read_col_data(sock::ClickHouseSock, num_rows::VarUInt,
                                            ::Val{:Array}, nest::TypeAst)

    (UInt64(num_rows) == 0) && return
    prev_offset = 0
    cur_deph = 0

    size = UInt64(num_rows)

    offsets = [UInt64[size]]

    data_type = read_offsets!(offsets, sock, nest)

    data_size = offsets[end][end]

    data = read_col_data(sock, VarUInt(data_size), data_type)

    result = data
    #top offset is the size of column, so we don't take it into account
    for off in Iterators.reverse(offsets[2:end])
        result = split_vector(result, off)
    end
    return result
end

const PossibleVectors{T} =
     Union{<:AbstractVector{T}, <:AbstractCategoricalVector{T}}
function get_base_type(
    ::Type{<:AbstractVector{T}},
    nest ::TypeAst,
) where {T}
    nest.name == :Array && return get_base_type(T, nest.args[1])
    return (T, nest)
end
function flatten_array!(offsets, itr, nest)
    new_level = UInt64[]
    last_offset = 0
    for part in itr
        push!(new_level, last_offset + length(part))
        last_offset = new_level[end]
    end
    push!(offsets, new_level)
    (nest.name != :Array) && return (Iterators.flatten(itr), nest)
    return flatten_array!(offsets, Iterators.flatten(itr), nest.args[1])

end
function write_col_data(sock::ClickHouseSock,
                                data::AbstractVector{T},
                                ::Val{:Array}, nest::TypeAst) where {T}

    offsets = [[UInt64(length(data))]]
    flatten_itr, base_ast = flatten_array!(offsets, data, nest)
    for i in 2:length(offsets)
        chwrite(sock, offsets[i])
    end
    write_col_data(sock, collect(flatten_itr), base_ast)
end


text:
@enum PairedReadOrientation::UInt64 FwRv=1 RvFw=2

struct PairedReads{A<:DNAAlphabet} <: ShortReads{A}
    filename::String         # Filename datastore was opened from.
    name::Symbol             # Name of the datastore. Useful for other applications.
    defaultname::Symbol      # Default name, useful for other applications.
    max_read_len::UInt64     # Maximum size of any read in this datastore.
    chunksize::UInt64        # Number of chunks (UInt64) of sequence data per read.
    fragsize::UInt64         # Fragment size of library.
    readpos_offset::UInt64
    size::UInt64
    orientation::PairedReadOrientation
    stream::IOStream
end

"Get the orientation of the read pairs"
@inline orientation(prds::PairedReads) = prds.orientation
# TODO: Phase out.
#@inline BioSequences.bits_per_symbol(prds::PairedReads{A}) where {A<:DNAAlphabet} = BioSequences.bits_per_symbol(A())

###
### PairedReads Header format on disk.
###

# | Field             | Value  | Type        |
# |:-----------------:|:------:|:-----------:|
# | Magic number      | 0x05D5 | UInt16      | 2 0
# | Datastore type    | 0x0001 | UInt16      | 2 2
# | Version number    | 0x0001 | UInt16      | 2 4
# | Bits Per Nuc      | N/A    | UInt64      | 8 6
# | Default name      | N/A    | String      | 7
# | Maximum read size | N/A    | UInt64      | 8
# | Chunk size        | N/A    | UInt64      | 8
# | Fragment size     | N/A    | UInt64      | 8
# | Orientation       | N/A    | Orientation | 8
# | Number of Reads   | N/A    | UInt64      | 8

const PairedDS_Version = 0x0003

__ds_type_code(::Type{<:PairedReads}) = PairedDS
__ds_version_code(::Type{<:PairedReads}) = PairedDS_Version

"""
    PairedReads{A}(rdrx::FASTQ.Reader, rdry::FASTQ.Reader, outfile::String, name::Union{String,Symbol}, minsize::Integer, maxsize::Integer, fragsize::Integer, orientation::PairedReadOrientation) where {A<:DNAAlphabet}

Construct a Paired Read Datastore from a pair of FASTQ file readers.

Paired-end sequencing reads typically come in the form of two FASTQ files, often
named according to a convention `*_R1.fastq` and `*_R2.fastq`.
One file contains all the "left" sequences of each pair, and the other contains
all the "right" sequences of each pair. The first read pair is made of the first
record in each file.

# Arguments
- `rdrx::FASTQ.Reader`: The reader of the `*_R1.fastq` file.
- `rdxy::FASTQ.Reader`: The reader of the `*_R2.fastq` file.
- `outfile::String`: A prefix for the datastore's filename, the full filename
  will include a ".prseq" extension, which will be added automatically.
- `name::String`: A string denoting a default name for your datastore.
  Naming datastores is useful for downstream applications.
- `minsize::Integer`: A minimum read length (in base pairs). When building
  the datastore, if any pair of reads has one or both reads shorter than this
  cutoff, then the pair will be discarded.
- `maxsize::Integer`: A maximum read length (in base pairs). When building
  the datastore, if any read has a greater length, it will be resized to this
  maximum length and added to the datastore.
- `fragsize::Integer`: The average fragment length of the paired end library
  that was sequenced. This value is entirely optional, but may be important for
  downstream applications.
- `orientation::PairedReadOrientation`: The orientation of the reads. Set it to
  `FwRv` for building a datastore from a sequenced paired end library, and set
  it to `RvFw` if you are building the datastore from reads sequenced from a
  long mate pair library.

# Examples
```jldoctest
julia> using FASTX, ReadDatastores

julia> fwq = open(FASTQ.Reader, "test/ecoli_tester_R1.fastq")
FASTX.FASTQ.Reader{TranscodingStreams.TranscodingStream{TranscodingStreams.Noop,IOStream}}(BioGenerics.Automa.State{TranscodingStreams.TranscodingStream{TranscodingStreams.Noop,IOStream}}(TranscodingStreams.TranscodingStream{TranscodingStreams.Noop,IOStream}(<mode=idle>), 1, 1, false), nothing)

julia> rvq = open(FASTQ.Reader, "test/ecoli_tester_R2.fastq")
FASTX.FASTQ.Reader{TranscodingStreams.TranscodingStream{TranscodingStreams.Noop,IOStream}}(BioGenerics.Automa.State{TranscodingStreams.TranscodingStream{TranscodingStreams.Noop,IOStream}}(TranscodingStreams.TranscodingStream{TranscodingStreams.Noop,IOStream}(<mode=idle>), 1, 1, false), nothing)

julia> ds = PairedReads{DNAAlphabet{2}}(fwq, rvq, "ecoli-test-paired", "my-ecoli-test", 250, 300, 0, FwRv)
[ Info: Building paired read datastore from FASTQ files
[ Info: Writing paired reads to datastore
[ Info: Done writing paired read sequences to datastore
[ Info: 0 read pairs were discarded due to a too short sequence
[ Info: 14 reads were truncated to 300 base pairs
[ Info: Created paired sequence datastore with 10 sequence pairs
Paired Read Datastore 'my-ecoli-test': 20 reads (10 pairs)

```
"""
function PairedReads{A}(rdrx::FASTQ.Reader, rdry::FASTQ.Reader, outfile::String, name::Union{String,Symbol},
                     minsize::Integer, maxsize::Integer, fragsize::Integer, orientation::PairedReadOrientation) where {A<:DNAAlphabet}
    return PairedReads{A}(rdrx, rdry, outfile, name, convert(UInt64, minsize),
                       convert(UInt64, maxsize), convert(UInt64, fragsize), orientation)
end

function PairedReads{A}(rdrx::FASTQ.Reader, rdry::FASTQ.Reader,
                     outfile::String, name::Union{Symbol,String},
                     minsize::UInt64, maxsize::UInt64,
                     fragsize::UInt64, orientation::PairedReadOrientation) where {A<:DNAAlphabet}

    # Create and allocate the sequence and record objects.
    lread = FASTQ.Record()
    rread = FASTQ.Record()
    lseq = LongSequence{A}(maxsize)
    rseq = LongSequence{A}(maxsize)

    #chunksize::UInt64 = BioSequences.seq_data_len(DNAAlphabet{4}, maxsize)
    chunksize::UInt64 = length(BioSequences.encoded_data(lseq))
    bps = UInt64(BioSequences.bits_per_symbol(A()))

    fd = open(outfile * ".prseq", "w")

    # Write magic no, datastore type, version number.
    sizepos = write(fd, ReadDatastoreMAGIC, PairedDS, PairedDS_Version, bps) +
    # Write the default name of the datastore.
    writestring(fd, String(name)) +
    # Write the read size, and chunk size.
    write(fd, maxsize, chunksize, fragsize, orientation)
    # Write space for size variable (or number of read pairs).
    readpos = write(fd, UInt64(0)) + sizepos

    pairs = discarded = truncated = 0
    p = 1

    @info "Building paired read datastore from FASTQ files"
    @info "Writing paired reads to datastore"

    while !eof(rdrx) && !eof(rdry)
        # Read in the two records.
        try # TODO: Get to the bottom of why this is nessecery to fix Windows issues.
            read!(rdrx, lread)
            read!(rdry, rread)
        catch ex
            if isa(ex, EOFError)
                break
            end
            rethrow()
        end

        llen = UInt64(FASTQ.seqlen(lread))
        rlen = UInt64(FASTQ.seqlen(rread))
        # If either read is too short, discard them both.
        if llen < minsize || rlen < minsize
            discarded += 1
            continue
        end

        if llen > maxsize
            truncated += 1
            ln = maxsize
        else
            ln = llen
        end

        if rlen > maxsize
            truncated += 1
            rn = maxsize
        else
            rn = rlen
        end

        pairs += 1

        # Copy FASTQ records to sequence variables, thus encoding
        # them in 2 bit format.
        copyto!(lseq, 1, lread, 1, ln)
        copyto!(rseq, 1, rread, 1, rn)

        # Write the two sizes reads one after the other:
        # For each sequence, write the size, and then the datachunk.

        write(fd, ln)
        write(fd, lseq.data)

        write(fd, rn)
        write(fd, rseq.data)
    end

    nreads::UInt64 = pairs * 2

    seek(fd, sizepos)
    write(fd, nreads)
    flush(fd)
    close(fd)

    @info "Done writing paired read sequences to datastore"
    @info string(discarded, " read pairs were discarded due to a too short sequence")
    @info string(truncated, " reads were truncated to ", maxsize, " base pairs")
    @info string("Created paired sequence datastore with ", pairs, " sequence pairs")

    stream = open(outfile * ".prseq", "r+")
    return PairedReads{A}(outfile * ".prseq", Symbol(name), Symbol(name), maxsize, chunksize, fragsize,
                       readpos, nreads, orientation, stream)
end

function Base.open(::Type{PairedReads{A}}, filename::String, name::Union{String,Symbol,Nothing} = nothing) where {A<:DNAAlphabet}
    fd = open(filename, "r")

    __validate_datastore_header(fd, PairedReads{A})

    default_name = Symbol(readuntil(fd, '\0'))

    max_read_len = read(fd, UInt64)
    chunksize = read(fd, UInt64)
    fragsize = read(fd, UInt64)
    orientation = reinterpret(PairedReadOrientation, read(fd, UInt64))
    nreads = read(fd, UInt64)
    readpos_offset = position(fd)

    return PairedReads{A}(filename, name === nothing ? default_name : Symbol(name), default_name,
                       max_read_len, chunksize, fragsize,
                       readpos_offset, nreads, orientation, fd)
end

@inline Base.length(prds::PairedReads) = prds.size

Base.summary(io::IO, prds::PairedReads) = print(io, "Paired Read Datastore '", prds.name, "': ", length(prds), " reads (", div(length(prds), 2), " pairs)")

@inline _read_data_begin(prds::PairedReads) = prds.readpos_offset
@inline _bytes_per_read(prds::PairedReads) = (prds.chunksize + 1) * sizeof(UInt64)
@inline max_read_length(prds::PairedReads) = prds.max_read_len


text:
module ZmqCaesar
    using Requires
    using ZMQ
    using JSON
    using Distributions, IncrementalInference, DistributedFactorGraphs, Caesar
    using Unmarshal
    using Dates
    using DocStringExtensions

    # import ZMQ: ls

    include("models/distributions.jl")
    include("models/factors.jl")
    include("models/config.jl")
    include("models/session.jl")
    include("models/plotting.jl")
    include("models/additional.jl")
    include("models/ZmqServer.jl")
    include("services/factors/distributionSerialization.jl")
    include("services/factors/factorSerialization.jl")
    include("services/config.jl")
    include("services/session.jl")
    include("services/additional.jl")
    include("services/ZmqServer.jl")

    # conditional loading for RoMPlotting
    function __init__()
        @require RoMEPlotting="238d586b-a4bf-555c-9891-eda6fc5e55a2" include("services/plotting.jl")
    end
end


text:
using LightGraphs
using SimpleValueGraphs
using Test

using Base.Iterators: product

include("testutils.jl")

tests = [
         "interface/constructors.jl",
         "interface/edges.jl",
         "interface/edgeval_accessors.jl",
         "interface/iterators.jl",
         "interface/valuegraph.jl",
        ]

@testset "ValueGraphs" begin
    for (i, test) in enumerate(tests)
        println("$i / $(length(tests)) $test")
        @time include(test)
    end
end # testset


text:
using PyCall

function generate_SBML_file(sys2userDict::Dict, rnx_set::Set, rnx::Array)
  sbml = pyimport("libsbml")
  sbmlns = sbml.SBMLNamespaces(3,2)
  #  create the document
  document = sbml.SBMLDocument(sbmlns)
  #  create the Model
  model= document.createModel()

  # -----helper functions start------
  #  create the Compartment
  function create_compartment(m, ID)
    compartment = m.createCompartment()
    compartment.setId(ID)
    # compartment.setConstant(true)
    # compartment.setSize(1)
  end
  # create the Species
  function create_species(m, ID, cpt)
    species = m.createSpecies()
    species.setId(ID)
    species.setCompartment(cpt)
    # species.setBoundaryCondition(false)
    # species.setConstant(false)
  end
  # create reactant
  function create_reactant(rn, ID, coe)
    reactant = rn.createReactant()
    reactant.setSpecies(ID)
    reactant.setStoichiometry(coe)
  end
  # create product
  function create_product(rn, ID, coe)
    product = rn.createProduct()
    product.setSpecies(ID)
    product.setStoichiometry(coe)
  end
  # create reactions
  function create_reaction(m, rxn)
    reaction = m.createReaction()
    Id = replace(replace(rxn.rnxName, r"[0-9]|\.|\*" => ""), r"<|:>|>|:" => "__")
    reaction.setId(Id)
    reaction.setReversible(false)
    for rt in rxn.reactants
      create_reactant(reaction, rt.oriBioName, rt.coeff)
    end
    for pt in rxn.products
      create_product(reaction, pt.oriBioName, pt.coeff)
    end
  end
  # -----helper functions end------

  # compartments
  if haskey(sys2userDict, "_exc")
    create_compartment(model, sys2userDict["_exc"])
  end
  if haskey(sys2userDict, "_c")
    create_compartment(model, sys2userDict["_c"])
  end
  # species
  for sps in rnx_set
    create_species(model, sps, "_" * split(sps, "_")[end])
  end
  # reactions
  for rxn in rnx
    create_reaction(model, rxn)
  end

  return sbml.writeSBMLToString(document)
end

max_stars_repo_name: varnerlab/SEML

max_issues_repo_name: varnerlab/SEML

max_forks_repo_name: varnerlab/SEML


text:
import SDELab2
#
T=1 # time step, final time
x0=1. # initial data
alp=-1 # parameter
bet=0
sig=0.5
quad0=SDELab2.delta_measure(x0)
###########################################
function drift_fff(u,alp,bet)
  x=u[1]; mf=u[2]
  return alp*x+bet*mf
end
##########################################
function diff_ggg(u,sig)
  x=u[1]
  return sig*x
end
#########################################
function mf_r(x)
  return [x]
end
#########################################
fcnq=SDELab2.set_fcn_mf(u->drift_fff(u,alp,bet),
          u->diff_ggg(u,sig),
          x->mf_r(x))

# test function
phi=x->[x;x.^2]
######################################
exact_mean=x0*exp((alp+bet));
exact_var=(sig^2)/(2*alp)*exp(2*alp)-sig^2/(2*alp);
exact_mom2=exact_var+exact_mean^2;
#exact_mom2=(exp(2*alp)*x0^2
#            +x0^2*exp(2*alp)*(exp(2*bet)-1)
#            +sig^2/(2*alp)*(exp(2*alp)-1))
exact=[exact_mean,exact_mom2];
println("ode soln ",exact)
##############################################
# MLMC implementation in MATLAB
mlmc_cpus= 1e3*[0.000142083385202,  0.000453974977685,   0.012572159661283, 0.051641483155560,   1.913720991516199,   8.940239873090615]
mlmc_errs=[ 0.008701679831122,   0.003964115036436,   0.000721699175333, 0.000323972021408,   0.000089514867964,   0.000056234777698]
#
dt=1e-3
solver="MFEM0"
params=SDELab2.set_opt(dt,solver)
params["eta"]=1 # determines timesteps
params["cutoff"]=10 # for diameter reduction
params["const"]=1e3 # for no_Gauss_points
params["length_scale"]=1 # for no_Gauss_points
params["skiphalf"]=true
params["periodic"]=false
params["no_partition"]=1
dtpts=[0.2,0.1,0.05,0.025,0.01,0.005,0.0025,0.001,0.0005]
errors=zeros(length(dtpts),2)
errors_no=deepcopy(errors)
errors_nd=deepcopy(errors)
cpu_times=zeros(length(dtpts))
cpu_times_no=deepcopy(cpu_times)
cpu_times_nd=deepcopy(cpu_times)

params["Solver"]="MFEM0"
for i=1:(length(dtpts))
    params["MaxStepSize"]=dtpts[i]/4
    qoi,cpu_time,stats,q=get_soln(fcn,quad0,params,phi,false)
    errors_no[i,:],cpu_times_no[i]=helper(qoi, exact, cpu_time, "normal")
end
########################
params["Solver"]="MFEM0"
for i=1:(length(dtpts))
    params["MaxStepSize"]=dtpts[i]
    qoi,cpu_time,stats,q=get_soln(fcn,quad0,params,phi,true)
    errors[i,:],cpu_times[i]=helper(qoi, exact, cpu_time, "normal")
end
################
params["Solver"]="MFEM2"
for i=1:(length(dtpts))
    params["MaxStepSize"]=dtpts[i]
    qoi,cpu_time,stats,q=get_soln(fcn,quad0,params,phi,false)
    errors_nd[i,:],cpu_times_nd[i]=helper(qoi, exact, cpu_time, "normal")
end
#########################################
str1="--" # extrap
str2="k-." # 2nd-order
figure(1);
# first functional
i=1
time_step_err(dtpts,errors[:,i],
  dtpts,errors_no[:,i],
  dtpts,errors_nd[:,i],[1e0,1e0],utf8("mom1.pdf"))
err_cpu(errors[:,i],cpu_times[:],
  errors_no[:,i],cpu_times_no[:],
  errors_nd[:,i],cpu_times_nd[:],[1e0,1e0], utf8("mom1_.pdf"))
# second functional
i=2
time_step_err(dtpts,errors[:,i],
      dtpts,errors_no[:,i],
      dtpts,errors_nd[:,i],[1e0,1],utf8("mom2.pdf"))
err_cpu(errors[:,i], cpu_times[:],
      errors_no[:,i],cpu_times_no[:],
      errors_nd[:,i],cpu_times_nd[:],[1e0,1], utf8("mom2_.pdf"))
#########################################
println("finished preparing plots")
#


text:
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md

using JuliaFEM
using JuliaFEM.Testing

#= TODO: Fix test
function test_interpolate()
    el = get_element()
    @test isapprox(el("geometry", [0.0, 0.0]), [0.5, 0.5])
    @test isapprox(el("geometry", [0.0, 0.0], 0.0), [0.5, 0.5])
    @test isapprox(el([0.0, 0.0]), [0.25 0.25 0.25 0.25])
    @test isapprox(el([0.0, 0.0], Val{:grad}), [-0.5 0.5 0.5 -0.5; -0.5 -0.5 0.5 0.5])
    gradT = el("temperature", [0.0, 0.0], 1.0, Val{:grad})
    info("gradT = $gradT")
    X = [0.5, 0.5]
    gradT_expected = [1-2*X[2] 3-2*X[1]]
    info("gradT(expected) = $gradT_expected")
    @test isapprox(gradT, gradT_expected)

#   @test isapprox(el("temperature", [0.0, 0.0], 0.5), 1/2*gradT_expected)

#   gradT = el("temperature", [0.0, 0.0], 0.5, Val{:grad})
#   info("gradT = $gradT")
#   @test isapprox(gradT, 1/2*gradT_expected)
end
=#

#= TODO: Fix test
function test_calculate_normal_tangential_coordinates()
    el = Tri3([1, 2, 3])
    el["geometry"] = Vector{Float64}[
        [0.0, 0.0, 0.0],
        [1.0, 0.0, 0.0],
        [0.0, 1.0, 0.0]]
    calculate_normal_tangential_coordinates!(el, 0.0)
    n = [0.0 0.0 1.0]'
    t1 = [1.0 0.0 0.0]'
    t2 = [0.0 1.0 0.0]'
    R = [n t1 t2]
    @test isapprox(el("normal-tangential coordinates", [0.0, 0.0], 0.0), R)
end
=#

#= TODO: Fix test
function test_manifold_determinant()
    el = Quad4([1, 2, 3, 4])
    #el["geometry"] = Vector{Float64}[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]
    el["geometry"] = Vector{Float64}[[0.0, 0.0, 1.0], [1.0, 0.0, 1.0], [1.0, 1.0, 1.0], [0.0, 1.0, 1.0]]
    # mother element area = 2*2 = 4, this element is 1, determinant should be 1/4 everywhere
    d = det(el, [0.1, 0.2], 0.0)
    d_expected = 0.25
    @test d == d_expected
end
=#

#= TODO: Fix test
@testset "add new discrete constant time-variant field and interpolate it" begin
    element = Element(Quad4, [1, 2, 3, 4])
    element["my field"] = (0.0 => 0.0, 1.0 => 1.0)
    @test isapprox(element("my field", [0.0, 0.0], 0.5), 0.5)
    update!(element, "my field 2", 0.0 => 0.0, 1.0 => 1.0)
    @test isapprox(element("my field 2", [0.0, 0.0], 0.5), 0.5)
end
=#

@testset "add time dependent field to element" begin
    el = Element(Seg2, [1, 2])
    u1 = Vector{Float64}[[0.0, 0.0], [0.0, 0.0]]
    u2 = Vector{Float64}[[1.0, 1.0], [1.0, 1.0]]
    update!(el, "displacement", 0.0 => u1)
    update!(el, "displacement", 1.0 => u2)
    @test length(el["displacement"]) == 2
    @test isapprox(el("displacement", [0.0], 0.0), [0.0, 0.0])
    @test isapprox(el("displacement", [0.0], 0.5), [0.5, 0.5])
    @test isapprox(el("displacement", [0.0], 1.0), [1.0, 1.0])
    el2 = Element(Poi1, [1])
    update!(el2, "force 1", 0.0 => 1.0)
end

@testset "add CVTV field to element" begin
    el = Element(Seg2, [1, 2])
    f(xi, time) = xi[1]*time
    update!(el, "my field", f)
    v = el("my field", [1.0], 2.0)
    @test isapprox(v, 2.0)
end

@testset "add DCTI to element" begin
    el = Element(Quad4, [1, 2, 3, 4])
    update!(el, "displacement load", DCTI([4.0, 8.0]))
    @test isa(el["displacement load"], DCTI)
    @test !isa(el["displacement load"].data, DCTI)
    update!(el, "displacement load 2", [4.0, 8.0])
    @test isa(el["displacement load 2"], DCTI)
    update!(el, "temperature", [1.0, 2.0, 3.0, 4.0])
    @test isa(el["temperature"], DVTI)
    @test isapprox(el("displacement load", [0.0, 0.0], 0.0), [4.0, 8.0])
end

@testset "interpolate DCTI from element" begin
    el = Element(Seg2, [1, 2])
    update!(el, "foobar", 1.0)
    fb = el("foobar", [0.0], 0.0)
    @test isa(fb, Float64)
    @test isapprox(fb, 1.0)
end

#= unnecessary feature
@testset "add two time dependent fields to element at once" begin
    el = Element(Seg2, [1, 2])
    update!(el, "foo1", 1.0 => 1.0)
    update!(el, "foo1", 2.0 => 2.0)
    update!(el, "foo2", 1.0 => 1.0, 2.0 => 2.0)
    @test isapprox(el("foo1", 1.5), el("foo2", 1.5))
end
=#

@testset "add elements to elements" begin
    el1 = Element(Seg2, [1, 2])
    el2 = Element(Seg2, [3, 4])
    update!(el1, "master elements", [el2])
    lst = el1("master elements", 0.0)
    @test isa(lst, Vector)
end


text:
"""
# to visualize the current obstacle in the field
obstaclePlot(n,c)

# to run it after a single optimization
pp = obstaclePlot(n,c,1)

# to create a new plot
pp = obstaclePlot(n,c,idx)

# to add to an exsting position plot
pp = obstaclePlot(n,c,idx,pp;(:append=>true))

# posterPlot
pp = obstaclePlot(n,c,ii,pp;(:append=>true),(:posterPlot=>true)) # add obstacles
--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 3/11/2017, Last Modified: 7/5/2017 \n
--------------------------------------------------------------------------------------\n
"""
function obstaclePlot(n,c,idx,args...;kwargs...)
  r = n.r
  kw = Dict(kwargs)

  # check to see if is a basic plot
  if !haskey(kw,:basic); basic=false;
  else; basic=get(kw,:basic,0);
  end

  # check to see if is a poster plot
  if !haskey(kw,:posterPlot);posterPlot=false;
  else; posterPlot=get(kw,:posterPlot,0);
  end

  # check to see if user wants to reduce the size of the markers TODO get ride of this eventually
  if !haskey(kw,:smallMarkers);smallMarkers=false;
  else;smallMarkers=get(kw,:smallMarkers,0);
  end

  # check to see if user wants to crash
  if !haskey(kw,:obstacleMiss);obstacleMiss=false;
  else;obstacleMiss=get(kw,:obstacleMiss,0);
  end

  if basic
    pp = plot(0,leg=:false)

    # if typeof(c["goal"]["x"])==Float64  # TODO remove redundant code
    #   if isnan(c["goal"]["tol"]); rg = 1; else rg = c["goal"]["tol"]; end
    #   if !posterPlot || idx == r.ocp.evalNum
    #     pts = Plots.partialcircle(0,2π,100,rg)
    #     x, y = Plots.unzip(pts)
    #     x += c["goal"]["x"];  y += c["goal"]["yVal"]
    #     pts = collect(zip(x, y))
    #     if !smallMarkers  #TODO get ride of this-> will not be a legend for this case
    #       scatter!((c["goal"]["x"],c["goal"]["yVal"]),marker=_pretty_defaults[:goal_marker][1],label="Goal Area")
    #     end
    #     plot!(pts,line=_pretty_defaults[:goal_line],fill=_pretty_defaults[:goal_fill][1],leg=true,label="")
    #
    #     if isnan(c["tolerances"]["fx"]); rg = 1; else rg = c["tolerances"]["fx"]; end
    #     pts = Plots.partialcircle(0,2π,100,rg)
    #     x, y = Plots.unzip(pts)
    #     x += c["goal"]["x"];  y += c["goal"]["yVal"]
    #     pts = collect(zip(x, y))
    #     if !smallMarkers  #TODO get ride of this-> will not be a legend for this case
    #       scatter!((c["goal"]["x"] + c["goal"]["vx"]*r.ip.dfsplant[idx][:t][end],c["goal"]["yVal"] + c["goal"]["vy"]*r.ip.dfsplant[idx][:t][end]),marker=_pretty_defaults[:goal_marker][2],label="Goal")
    #     end
    #     plot!(pts,line=_pretty_defaults[:goal_line],fill=_pretty_defaults[:goal_fill][2],leg=true,label="")
    #   end
    # end

    if !isempty(c["obstacle"]["radius"])
      for i in 1:length(c["obstacle"]["radius"])
          # create an ellipse
          pts = Plots.partialcircle(0,2π,100,c["obstacle"]["radius"][i])
          x, y = Plots.unzip(pts)
          tc = 0
          x += c["obstacle"]["x0"][i] + c["obstacle"]["vx"][i]*tc
          y = c["obstacle"]["radius"][i]/c["obstacle"]["radius"][i]*y + c["obstacle"]["y0"][i] + c["obstacle"]["vy"][i]*tc
          pts = collect(zip(x, y))
          if i==1
            scatter!((c["obstacle"]["x0"][i],c["obstacle"]["y0"][i]),marker=_pretty_defaults[:obstacle_marker],label="Obstacles")
          end
          plot!(pts,line=_pretty_defaults[:obstacle_line],fill=_pretty_defaults[:obstacle_fill],leg=true,label="") #line=(3.0,0.0,:solid,:red)
        #  plot!(pts,line=(4.0,0.0,:solid,:red),fill=(0, 1, :red),leg=true,label="")
      end
    end
  else
    # check to see if user would like to add to an existing plot
    if !haskey(kw,:append); kw_ = Dict(:append => false); append = get(kw_,:append,0);
    else; append = get(kw,:append,0);
    end
    if !append; pp=plot(0,leg=:false); else pp=args[1]; end

    # plot the goal; assuming same in x and y
    if typeof(c["goal"]["x"])==Float64 # TODO remove redundant code
      if isnan(c["goal"]["tol"]); rg = 1; else rg = c["goal"]["tol"]; end
      if !posterPlot || idx ==r.ocp.evalNum
        # pts = Plots.partialcircle(0,2π,100,rg)
        # x, y = Plots.unzip(pts)
        # x += c["goal"]["x"];  y += c["goal"]["yVal"]
        # pts = collect(zip(x, y))
        # if !smallMarkers  #TODO get ride of this-> will not be a legend for this case
        #   scatter!((c["goal"]["x"],c["goal"]["yVal"]),marker=_pretty_defaults[:goal_marker][1],label="Goal Area")
        # end
        # plot!(pts,line=_pretty_defaults[:goal_line],fill=_pretty_defaults[:goal_fill][1],leg=true,label="")

        if isnan(c["tolerances"]["fx"]); rg=1; else rg = c["tolerances"]["fx"]; end
        pts = Plots.partialcircle(0,2π,100,rg)
        x, y = Plots.unzip(pts)
        if length(r.ip.dfsplant) < idx
          goalIdx = idx - 1
          warn("no time data for current frame using previos data")
        else
          goalIdx = idx
        end
        x += c["goal"]["x"] + c["goal"]["vx"]*r.ip.dfsplant[goalIdx][:t][end]
        y += c["goal"]["yVal"] + c["goal"]["vy"]*r.ip.dfsplant[goalIdx][:t][end]
        pts = collect(zip(x, y))
        if !smallMarkers  #TODO get ride of this-> will not be a legend for this case
          scatter!((c["goal"]["x"] + c["goal"]["vx"]*r.ip.dfsplant[goalIdx][:t][end],c["goal"]["yVal"] + c["goal"]["vy"]*r.ip.dfsplant[goalIdx][:t][end]),marker=_pretty_defaults[:goal_marker][2],label="Goal")
        end
        plot!(pts,line=_pretty_defaults[:goal_line],fill=_pretty_defaults[:goal_fill][2],leg=true,label="")
      end
    end

    if typeof(c["obstacle"]["radius"][1])==Float64
      for i in 1:length(c["obstacle"]["radius"])
        # create an ellipse
        pts = Plots.partialcircle(0,2π,100,c["obstacle"]["radius"][i])
        x, y = Plots.unzip(pts)
        if _pretty_defaults[:plant]
          x += c["obstacle"]["x0"][i] + c["obstacle"]["vx"][i]*r.ip.dfsplant[idx][:t][end];
          y = c["obstacle"]["radius"][i]/c["obstacle"]["radius"][i]*y + c["obstacle"]["y0"][i] + c["obstacle"]["vy"][i]*r.ip.dfsplant[idx][:t][end];
        else
          if r.ocp.dfs[idx]!=nothing
            tc = r.ocp.dfs[idx][:t][end]
          else
            tc = 0
            if idx!=1; warn("\n Obstacles set to inital condition for current frame. \n") end
          end
          x += c["obstacle"]["x0"][i] + c["obstacle"]["vx"][i]*tc;
          y = c["obstacle"]["radius"][i]/c["obstacle"]["radius"][i]*y + c["obstacle"]["y0"][i] + c["obstacle"]["vy"][i]*tc;
        end
        pts = collect(zip(x, y))
        X = c["obstacle"]["x0"][i] + c["obstacle"]["vx"][i]*r.ip.dfsplant[idx][:t][end]
        Y = c["obstacle"]["y0"][i] + c["obstacle"]["vy"][i]*r.ip.dfsplant[idx][:t][end]
        if posterPlot
          shade=idx/r.ocp.evalNum;
          if idx==r.ocp.evalNum && i==1
            scatter!((X,Y),marker=_pretty_defaults[:obstacle_marker],label="Obstacles")
          end
          plot!(pts,line=_pretty_defaults[:obstacle_line],fill=(0,shade,:red),leg=true,label="")
          annotate!(X,Y,text(string(idx*c["misc"]["tex"],"s"),10,:black,:center))
        else
          if i==1 && !smallMarkers
            scatter!((X,Y),marker=_pretty_defaults[:obstacle_marker],label="Obstacles")
          end
          plot!(pts,line=_pretty_defaults[:obstacle_line],fill=_pretty_defaults[:obstacle_fill],leg=true,label="") #line=(3.0,0.0,:solid,:red)
          if obstacleMiss && i>8
            annotate!(X,Y+5,text("obstacle not seen!"),14,:red,:center)
          end
        end
      end
    end

    xaxis!(n.ocp.state.description[1])
    yaxis!(n.ocp.state.description[2])
    if !_pretty_defaults[:simulate] savefig(string(r.resultsDir,"/",n.ocp.state.name[1],"_vs_",n.ocp.state.name[2],".",_pretty_defaults[:format])); end
  end
  return pp
end

obstaclePlot(n,c)=obstaclePlot(n,c,1;(:basic=>true))

#=
using Plots
import Images
#ENV["PYTHONPATH"]="/home/febbo/.julia/v0.5/Conda/deps/usr/bin/python"
img=Images.load(Pkg.dir("PrettyPlots/src/humvee.png"));
plot(img)
=#
"""
pp=vehiclePlot(n,c,idx);
pp=vehiclePlot(n,c,idx,pp;(:append=>true));
--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 3/11/2017, Last Modified: 4/4/2017 \n
--------------------------------------------------------------------------------------\n
"""
function vehiclePlot(n,c,idx,args...;kwargs...)
  r = n.r

  kw = Dict(kwargs)

  # check to see if user wants to zoom
  if !haskey(kw,:zoom); zoom = false;
  else; zoom=get(kw,:zoom,0);
  end

  # check to see if user would like to add to an existing plot
  if !haskey(kw,:append); append = false
  else; append = get(kw,:append,0);
  end
  if !append; pp=plot(0,leg=:false); else pp=args[1]; end

  # check to see if is a poster plot
  if !haskey(kw,:posterPlot); posterPlot=false;
  else; posterPlot=get(kw,:posterPlot,0);
  end

  # check to see if we want to set the limits to the position constraints
  if !haskey(kw,:setLims);setLims=false;
  else;setLims=get(kw,:setLims,0);
  end

  # check to see if user wants to reduce the size of the markers TODO get ride of this eventually
  if !haskey(kw,:smallMarkers);smallMarkers=false;
  else;smallMarkers=get(kw,:smallMarkers,0);
  end

  w = _pretty_defaults[:vehicle_width]; h=_pretty_defaults[:vehicle_length]
  XQ = [-w/2 w/2 w/2 -w/2 -w/2]
  YQ = [h/2 h/2 -h/2 -h/2 h/2]

  # plot the vehicle
  if _pretty_defaults[:plant]
    X_v = r.ip.dfsplant[idx][:x][end]  # using the end of the simulated data from the vehicle model
    Y_v = r.ip.dfsplant[idx][:y][end]
    PSI_v = r.ip.dfsplant[idx][:psi][end]-pi/2
  else
   #TODO condider eliminating option to plot mpc only
    X_v = r.ocp.dfs[idx][:x][1] # start at begining
    Y_v = r.ocp.dfs[idx][:y][1]
    PSI_v = r.ocp.dfs[idx][:psi][1]-pi/2
  end

  P = [XQ;YQ]
  ct = cos(PSI_v)
  st = sin(PSI_v)
  R = [ct -st;st ct]
  P2 = R*P
  if !posterPlot || idx==r.ocp.evalNum
    if !smallMarkers # for legend
      scatter!((X_v,Y_v),marker=_pretty_defaults[:vehicle_marker], grid=true,label="Vehicle")
    end
  end
  scatter!((P2[1,:]+X_v,P2[2,:]+Y_v),marker=(:circle,:black,0.,0.),fill=_pretty_defaults[:vehicle_fill],leg=true,grid=true,label="")

  if !zoom && !setLims
    if _pretty_defaults[:plant]  # TODO push this to a higher level
      xL = minDF(r.ip.dfsplant,:x);xU=maxDF(r.ip.dfsplant,:x);
      yL = minDF(r.ip.dfsplant,:y);yU=maxDF(r.ip.dfsplant,:y);
    else
      xL = minDF(r.ocp.dfs,:x);xU=maxDF(r.ocp.dfs,:x);
      yL = minDF(r.ocp.dfs,:y);yU=maxDF(r.ocp.dfs,:y);
    end
      dx = xU - xL;dy = yU - yL; # axis equal
      if dx>dy; yU=yL+dx; else xU=xL+dy; end
      xlims!(xL,xU)
      ylims!(yL,yU)
  else
    xlims!(X_v-20.,X_v+80.)
    ylims!(Y_v-50.,Y_v+50.)
  end

  if posterPlot
    t = idx*c["misc"]["tex"]
    annotate!(X_v,Y_v-4,text(string("t=",t," s"),10,:black,:center))
  end

  if setLims || posterPlot
    xlims!(c["misc"]["Xlims"][1],c["misc"]["Xlims"][2])
    ylims!(c["misc"]["Ylims"][1],c["misc"]["Ylims"][2])
  end

  if !_pretty_defaults[:simulate]; savefig(string(r.resultsDir,"x_vs_y",".",_pretty_defaults[:format])); end
  return pp
end
"""
vt = vtPlot(n,idx)
-------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 3/11/2017, Last Modified: 3/11/2017 \n
--------------------------------------------------------------------------------------\n
"""
function vtPlot(n,idx::Int64)
  r = n.r
  pa = n.ocp.params[1]
  c = n.ocp.params[5]

	@unpack_Vpara pa

  # check length of n.r.ocp.dfs to see if there is data for the provided idx
  if length(n.r.ocp.dfs) >= idx
    ocpPlot = true
  else
    ocpPlot = false
  end

#  if idx > length(n.r.ocp.dfs)
#    warn("Cannot plot idx = ", idx, " because length(n.r.ocp.dfs) = ", length(n.r.ocp.dfs), ". \n
#          Skipping idx in vtPlot().")
#    vt = plot(0,leg=:false)
#    return vt
#  end

  if ocpPlot
    t_vec=linspace(0.0,max(5,ceil(r.ocp.dfs[end][:t][end]/1)*1),_pretty_defaults[:L]);
  else
    t_vec=linspace(0.0,max(5,ceil(r.ip.dfsplant[end][:t][end]/1)*1),_pretty_defaults[:L]);
  end

	vt=plot(t_vec,c["vehicle"][:Fz_off]*ones(_pretty_defaults[:L],1),line=_pretty_defaults[:limit_lines][2],label="min")

  if !_pretty_defaults[:plantOnly] && ocpPlot

    if  isequal(c["misc"]["model"],:ThreeDOFv2)
      V=r.ocp.dfs[idx][:v];R=r.ocp.dfs[idx][:r];SA=r.ocp.dfs[idx][:sa];
      Ax=r.ocp.dfs[idx][:ax]; U=r.ocp.dfs[idx][:ux];
    elseif isequal(c["misc"]["model"],:ThreeDOFv1) # constain speed (the model is not optimizing speed)
      V=r.ocp.dfs[idx][:v];R=r.ocp.dfs[idx][:r];SA=r.ocp.dfs[idx][:sa];
      U=c["misc"]["ux"]*ones(length(V)); Ax=zeros(length(V));
    elseif isequal(c["misc"]["model"],:KinematicBicycle2)
      Vtotal = r.ocp.dfs[idx][:ux]
      Atotal = r.ocp.dfs[idx][:ax]
      SA = r.ocp.dfs[idx][:sa]
      Beta = atan.(la/(la+lb)*tan.(SA))
      V = Vtotal.*sin.(Beta)
      U = Vtotal.*cos.(Beta)
      Ax = Atotal.*cos.(Beta)
      Rturn = (la + lb)./SA  # turning radius, Ackerman angle (small angle assumption)
      R = V./Rturn
    end
    plot!(r.ocp.dfs[idx][:t],@FZ_RL(),line=_pretty_defaults[:mpc_lines][1],label="RL-mpc");
    plot!(r.ocp.dfs[idx][:t],@FZ_RR(),line=_pretty_defaults[:mpc_lines][2],label="RR-mpc");
    plot!(r.ocp.dfs[idx][:t],@FZ_FL(),line=_pretty_defaults[:mpc_lines][7],label="FL-mpc");
    plot!(r.ocp.dfs[idx][:t],@FZ_FR(),line=_pretty_defaults[:mpc_lines][4],label="FR-mpc");
  end
  if _pretty_defaults[:plant]

    if isequal(c["misc"]["model"],:ThreeDOFv2)
      temp = [r.ip.dfsplant[jj][:v] for jj in 1:idx] # V
      V = [idx for tempM in temp for idx=tempM]
      temp = [r.ip.dfsplant[jj][:ux] for jj in 1:idx]; # ux
      U=[idx for tempM in temp for idx=tempM];

      temp = [r.ip.dfsplant[jj][:ax] for jj in 1:idx]; # ax
      Ax=[idx for tempM in temp for idx=tempM];

      temp = [r.ip.dfsplant[jj][:r] for jj in 1:idx]; # r
      R=[idx for tempM in temp for idx=tempM];

      temp = [r.ip.dfsplant[jj][:sa] for jj in 1:idx]; # sa
      SA=[idx for tempM in temp for idx=tempM];
    elseif  isequal(c["misc"]["model"],:ThreeDOFv1) # constain speed ( the model is not optimizing speed)
      temp = [r.ip.dfsplant[jj][:v] for jj in 1:idx] # V
      V = [idx for tempM in temp for idx=tempM]
      U=c["misc"]["ux"]*ones(length(V)); Ax=zeros(length(V));

      temp = [r.ip.dfsplant[jj][:r] for jj in 1:idx]; # r
      R=[idx for tempM in temp for idx=tempM];

      temp = [r.ip.dfsplant[jj][:sa] for jj in 1:idx]; # sa
      SA=[idx for tempM in temp for idx=tempM];
    elseif isequal(c["misc"]["model"],:KinematicBicycle2)
      temp = [r.ip.dfsplant[jj][:ux] for jj in 1:idx]; # u
      Vtotal=[idx for tempM in temp for idx=tempM];

      temp = [r.ip.dfsplant[jj][:ax] for jj in 1:idx]; # a
      Atotal=[idx for tempM in temp for idx=tempM];

      temp = [r.ip.dfsplant[jj][:sa] for jj in 1:idx]; # sa
      SA = [idx for tempM in temp for idx=tempM];

      Beta = atan.(la/(la+lb)*tan.(SA))
      V = Vtotal.*sin.(Beta)
      U = Vtotal.*cos.(Beta)
      Ax = Atotal.*cos.(Beta)
      Rturn = (la + lb)./SA  # turning radius, Ackerman angle (small angle assumption)
      R = V./Rturn
    end

    # time
    temp = [r.ip.dfsplant[jj][:t] for jj in 1:idx]
    time = [idx for tempM in temp for idx=tempM]

    plot!(time,@FZ_RL(),line=_pretty_defaults[:plant_lines][1],label="RL-plant")
    plot!(time,@FZ_RR(),line=_pretty_defaults[:plant_lines][2],label="RR-plant")
    plot!(time,@FZ_FL(),line=_pretty_defaults[:plant_lines][3],label="FL-plant")
    plot!(time,@FZ_FR(),line=_pretty_defaults[:plant_lines][4],label="FR-plant")
  end
  plot!(size=_pretty_defaults[:size])
	adjust_axis(xlims(),ylims())
  xlims!(t_vec[1],t_vec[end])
  ylims!(_pretty_defaults[:tire_force_lims])
	title!("Vertical Tire Forces"); yaxis!("Force (N)"); xaxis!("time (s)")
	if !_pretty_defaults[:simulate] savefig(string(r.resultsDir,"vt.",_pretty_defaults[:format])) end
  return vt
end

"""
axp=axLimsPlot(n,pa,idx)
axp=axLimsPlot(n,pa,idx,axp;(:append=>true))
# this plot adds the nonlinear limits on acceleration to the plot
--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 3/11/2017, Last Modified: 3/11/2017 \n
--------------------------------------------------------------------------------------\n
"""
function axLimsPlot(n,pa,idx::Int64,args...;kwargs...)
  r = n.r

  kw = Dict(kwargs)
  if !haskey(kw,:append); kw_ = Dict(:append => false); append = get(kw_,:append,0);
  else; append = get(kw,:append,0);
  end
  if !append; axp=plot(0,leg=:false); else axp=args[1]; end

  # check length of n.r.ocp.dfs to see if there is data for the provided idx
  if length(n.r.ocp.dfs) >= idx
    ocpPlot = true
  else
    ocpPlot = false
  end

  @unpack_Vpara pa

  if !_pretty_defaults[:plant] &&  !_pretty_defaults[:plantOnly] && ocpPlot
    t_vec = linspace(0.0,max(5,ceil(r.ocp.dfs[end][:t][end]/1)*1),_pretty_defaults[:L])
  else
    t_vec = linspace(0,max(5,ceil(r.ip.dfsplant[end][:t][end]/1)*1),_pretty_defaults[:L])
  end

  if !_pretty_defaults[:plantOnly] && ocpPlot
    U = r.ocp.dfs[idx][:ux]
    plot!(r.ocp.dfs[idx][:t],@Ax_max(),line=_pretty_defaults[:limit_lines][2],label="max-mpc")
    plot!(r.ocp.dfs[idx][:t],@Ax_min(),line=_pretty_defaults[:limit_lines][1],label="min-mpc")
  end
  if _pretty_defaults[:plant]
    temp = [r.ip.dfsplant[jj][:ux] for jj in 1:idx] # ux
    U = [idx for tempM in temp for idx=tempM]

    # time
    temp = [r.ip.dfsplant[jj][:t] for jj in 1:idx]
    time = [idx for tempM in temp for idx=tempM]

    plot!(time,@Ax_max(),line=_pretty_defaults[:limit_lines][4],label="max-plant")
    plot!(time,@Ax_min(),line=_pretty_defaults[:limit_lines][3],label="min-plant")
  end
  ylims!(_pretty_defaults[:ax_lims])
  plot!(size=_pretty_defaults[:size])
  if !_pretty_defaults[:simulate] savefig(string(r.resultsDir,"axp.",_pretty_defaults[:format])) end
  return axp
end

"""
# to visualize the current track in the field
trackPlot(c)

pp=trackPlot(c,pp;(:append=>true));
--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 3/28/2017, Last Modified: 5/1/2017 \n
--------------------------------------------------------------------------------------\n
"""
function trackPlot(c,args...;kwargs...)
  kw = Dict(kwargs);
  # s=Settings(); NOTE commented out

  # check to see if user would like to add to an existing plot
  if !haskey(kw,:append); append=false;
  else; append = get(kw,:append,0);
  end

  # check to see if user wants to reduce the size of the markers TODO get ride of this eventually
  if !haskey(kw,:smallMarkers);smallMarkers=false;
  else;smallMarkers=get(kw,:smallMarkers,0);
  end

  if !append; pp=plot(0,leg=:false); else pp=args[1]; end

  if c["track"]["func"]==:poly
    f(y)=c["track"]["a"][1] + c["track"]["a"][2]*y + c["track"]["a"][3]*y^2 + c["track"]["a"][4]*y^3 + c["track"]["a"][5]*y^4;
    Y=c["track"]["Y"];
    X=f.(Y);
  elseif c["track"]["func"]==:fourier
    ff(x)=c["track"]["a"][1]*sin(c["track"]["b"][1]*x+c["track"]["c"][1]) + c["track"]["a"][2]*sin(c["track"]["b"][2]*x+c["track"]["c"][2]) + c["track"]["a"][3]*sin(c["track"]["b"][3]*x+c["track"]["c"][3]) + c["track"]["a"][4]*sin(c["track"]["b"][4]*x+c["track"]["c"][4]) + c["track"]["a"][5]*sin(c["track"]["b"][5]*x+c["track"]["c"][5]) + c["track"]["a"][6]*sin(c["track"]["b"][6]*x+c["track"]["c"][6]) + c["track"]["a"][7]*sin(c["track"]["b"][7]*x+c["track"]["c"][7]) + c["track"]["a"][8]*sin(c["track"]["b"][8]*x+c["track"]["c"][8])+c["track"]["y0"];
    X=c["track"]["X"];
    Y=ff.(X);
  end

  if !smallMarkers; L=40; else L=4; end

  plot!(X,Y,label="Road",line=(L,0.3,:solid,:black))
  return pp
end

"""

pp=lidarPlot(r,c,idx);
pp=lidarPlot(r,c,idx,pp;(:append=>true));
--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 4/3/2017, Last Modified: 4/3/2017 \n
--------------------------------------------------------------------------------------\n
"""
function lidarPlot(r,c,idx,args...;kwargs...)
  kw = Dict(kwargs);

  # check to see if user would like to add to an existing plot
  if !haskey(kw,:append); kw_ = Dict(:append => false); append = get(kw_,:append,0);
  else; append = get(kw,:append,0);
  end
  if !append; pp=plot(0,leg=:false); else pp=args[1]; end

  if idx > length(r.ocp.dfs)
    warn("Cannot plot idx = ", idx, " because length(r.ocp.dfs) = ", length(r.ocp.dfs), ". \n
          Skipping idx in lidarPlot().")
    return pp
  end

  # plot the LiDAR
  #if _pretty_defaults[:plant]
  #  X_v = r.ip.dfsplant[idx][:x][1]  # using the begining of the simulated data from the vehicle model
  #  Y_v = r.ip.dfsplant[idx][:y][1]
  #  PSI_v = r.ip.dfsplant[idx][:psi][1]-pi/2
  #else # NOTE plotting w.r.t. the OCP, that is how the constraints are set up
  X_v = r.ocp.dfs[idx][:x][1]
  Y_v = r.ocp.dfs[idx][:y][1]
  PSI_v = r.ocp.dfs[idx][:psi][1]-pi/2
  #end

  pts = Plots.partialcircle(PSI_v-pi,PSI_v+pi,50,c["misc"]["Lr"]);
  x, y = Plots.unzip(pts);
  x += X_v;  y += Y_v;
  pts = collect(zip(x, y));
  plot!(pts,line=_pretty_defaults[:lidar_line],fill=_pretty_defaults[:lidar_fill],leg=true,label="LiDAR Range")
  return pp
end
"""
--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Tesla
Date Create: 7/7/2020, Last Modified: 7/7/2020 \n
--------------------------------------------------------------------------------------\n
"""
function pltCurb(P2,w,h)
    scatter!((P2[1,:]+w,P2[2,:]+h),marker=(:circle,:black,0.,0.),fill=(0,1,:black),leg=true,grid=true,label="")
end

function intersectionPlot()
    pp = plot(0,leg=:false)

    # parameters TODO add to YAML file
    lw = 3
    w = 3
    h = 3
    psi = 0

    XQ = [-w/2 w/2 w/2 -w/2 -w/2]
    YQ = [h/2 h/2 -h/2 -h/2 h/2]
    P = [XQ;YQ]
    ct = cos(psi)
    st = sin(psi)
    R = [ct -st;st ct]
    P2 = R*P

    pltCurb(P2,w+lw/2,h+lw/2)
    pltCurb(P2,w+lw/2,-h-lw/2)
    pltCurb(P2,-w-lw/2,-h-lw/2)
    pltCurb(P2,-w-lw/2,h+lw/2)

    return pp
end

"""
# to plot the second solution
pp = posPlot(n,2)
--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 3/28/2017, Last Modified: 5/1/2017 \n
--------------------------------------------------------------------------------------\n
"""
function posPlot(n,idx;kwargs...)
  r = n.r
  c = n.ocp.params[5]

  kw = Dict(kwargs)

  if !haskey(kw,:intersection);
      intersection=false;
  else;
      intersection=get(kw,:zoom,0);
  end

  if !haskey(kw,:zoom);
      zoom = false
  else
      zoom = get(kw,:zoom,0)
  end

  # check to see if we want to set the limits to the position constraints
  if !haskey(kw,:setLims)
    setLims = false
  else
    setLims = get(kw,:setLims,0)
  end

  # check to see if user wants to reduce the size of the markers TODO get ride of this eventually
  if !haskey(kw,:smallMarkers);smallMarkers=false;
  else;smallMarkers=get(kw,:smallMarkers,0);
  end

  # check to see if user wants to crash
  if !haskey(kw,:obstacleMiss);obstacleMiss=false;
  else;obstacleMiss=get(kw,:obstacleMiss,0);
  end

  if haskey(c,"track");
      pp = trackPlot(c;(:smallMarkers=>smallMarkers));
  else
      if intersection
          pp = intersectionPlot()
      else
          pp = plot(0,leg=:false)
      end
  end  # track

  # TEMP removing lidar plot
  #if haskey(c["misc"],"Lr"); pp=lidarPlot(r,c,idx,pp;(:append=>true)); end  # lidar

  pp = obstaclePlot(n,c,idx,pp;(:append=>true),(:smallMarkers=>smallMarkers),(:obstacleMiss=>obstacleMiss))   # obstacles
  pp = statePlot(n,idx,1,2,pp;(:lims=>false),(:append=>true)) # vehicle trajectory
  pp = vehiclePlot(n,c,idx,pp;(:append=>true),(:zoom=>zoom),(:setLims=>setLims),(:smallMarkers=>smallMarkers))# vehicle

  if !setLims; plot!(aspect_ratio=:equal); end

  if intersection
      lim_size = 6       #  TODO add to YAML file
      if length(r.ocp.dfs) < idx
        ocpIdx = idx - 1
        warn("no time data for current frame using previos data")
      else
        ocpIdx = idx
      end
      xlims!(r.ocp.dfs[ocpIdx][:x][1]-lim_size , lim_size + r.ocp.dfs[ocpIdx][:x][1])
      ylims!(r.ocp.dfs[ocpIdx][:y][1]-lim_size, lim_size + r.ocp.dfs[ocpIdx][:y][1])
  end

  if !_pretty_defaults[:simulate] savefig(string(r.resultsDir,"pp.",_pretty_defaults[:format])) end
  return pp
end

"""
main=mainPlot(n,idx;kwargs...)
--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 3/11/2017, Last Modified: 2/12/2018 \n
--------------------------------------------------------------------------------------\n
"""
function mainPlot(n,idx;kwargs...)
  r = n.r
  pa = n.ocp.params[1]
  c = n.ocp.params[5]

  kw = Dict(kwargs)
  if !haskey(kw,:mode);error("select a mode for the simulation \n")
  else; mode=get(kw,:mode,0);
  end

  if mode==:path1
    sap=statePlot(n,idx,6)
    vp=statePlot(n,idx,3)
    rp=statePlot(n,idx,4)
    vt=vtPlot(n,idx)
    pp=posPlot(n,idx)
    pz=posPlot(n,idx;(:zoom=>true))
    if _pretty_defaults[:plant]; tp=tPlot(n,idx); else; tp=plot(0,leg=:false); end
    l = @layout [a{0.3w} [grid(2,2)
                          b{0.2h}]]
    mainS=plot(pp,sap,vt,pz,rp,tp,layout=l,size=_pretty_defaults[:size]);
  elseif mode==:path2
    sap=statePlot(n,idx,6);plot!(leg=:topleft)
    vp=statePlot(n,idx,3);plot!(leg=:topleft)
    vt=vtPlot(n,idx);plot!(leg=:bottomleft)
    pz=posPlot(n,idx;(:zoom=>true));plot!(leg=:topleft)
    if _pretty_defaults[:plant]; tp=tPlot(n,idx);plot!(leg=:topright) else; tp=plot(0,leg=:false);plot!(leg=:topright) end
    l=@layout([a{0.6w} [b;c]; d{0.17h}])
    mainS=plot(pz,vt,sap,tp,layout=l,size=_pretty_defaults[:size]);
  elseif mode==:path3
    sap=statePlot(n,idx,6);plot!(leg=:topleft)
    vp=statePlot(n,idx,3);plot!(leg=:topleft)
    vt=vtPlot(n,idx);plot!(leg=:bottomleft)
    pp=posPlot(n,idx;(:setLims=>true),(:smallMarkers=>true),(:obstacleMiss=>false));plot!(leg=false);
    pz=posPlot(n,idx;(:zoom=>true),(:obstacleMiss=>false));plot!(leg=:topleft)
    if _pretty_defaults[:plant]; tp=tPlot(n,idx);plot!(leg=:topright) else; tp=plot(0,leg=:false);plot!(leg=:topright) end
    l=@layout([[a;
                b{0.2h}] [c;d;e]])
    mainS=plot(pz,pp,vt,sap,tp,layout=l,size=_pretty_defaults[:size]);
  elseif mode==:zoom1
    if isequal(c["misc"]["model"],:ThreeDOFv2)
    sap = statePlot(n,idx,6);plot!(leg=:topleft)
    longv = statePlot(n,idx,7);plot!(leg=:topleft)
    axp=axLimsPlot(n,pa,idx);# add nonlinear acceleration limits
    axp=statePlot(n,idx,8,axp;(:lims=>false),(:append=>true));plot!(leg=:bottomright);
    vt = vtPlot(n,idx);plot!(leg=:bottomleft)
    pp = posPlot(n,idx;(:setLims=>true),(:smallMarkers=>true),(:obstacleMiss=>false));plot!(leg=false);
    pz = posPlot(n,idx;(:zoom=>true),(:obstacleMiss=>false));plot!(leg=:topleft)
    if _pretty_defaults[:plant]; tp=tPlot(n,idx);plot!(leg=:topright) else; tp=plot(0,leg=:false);plot!(leg=:topright) end
    l = @layout [[a;b{0.2h}] c{0.1w} [d;e;f;g]]
    mainS = plot(pz,tp,pp,vt,sap,longv,axp,layout=l,size=_pretty_defaults[:size])
    else
      error("TODO")
    end
  elseif mode==:intersection
    if isequal(c["misc"]["model"],:ThreeDOFv2)
        psip=statePlot(n,idx,5);plot!(leg=:topleft)

        sap = statePlot(n,idx,6);plot!(leg=:topleft)
        longv = statePlot(n,idx,7);plot!(leg=:topleft)
        axp=axLimsPlot(n,pa,idx);# add nonlinear acceleration limits
        axp=statePlot(n,idx,8,axp;(:lims=>false),(:append=>true));plot!(leg=:bottomright);
        vt = vtPlot(n,idx);plot!(leg=:bottomleft)
        #pp = posPlot(n,idx;(:setLims=>true),(:smallMarkers=>true),(:obstacleMiss=>false));plot!(leg=false);
        pz = posPlot(n,idx;(:intersection=>true),(:zoom=>true),(:obstacleMiss=>false));plot!(leg=:topleft)
        if _pretty_defaults[:plant]; tp=tPlot(n,idx);plot!(leg=:topright) else; tp=plot(0,leg=:false);plot!(leg=:topright) end
        l = @layout [[a;b{0.2h}] [c;d;e;f;g]]
        mainS = plot(pz,tp,vt,psip,sap,longv,axp,layout=l,size=_pretty_defaults[:size])
    else
        error("TODO")
    end
  elseif mode==:open1
    if isequal(c["misc"]["model"],:ThreeDOFv2)
      sap=statePlot(n,idx,6);plot!(leg=:topleft)
      longv=statePlot(n,idx,7);plot!(leg=:topleft)
      axp=axLimsPlot(n,pa,idx);# add nonlinear acceleration limits
      axp=statePlot(n,idx,8,axp;(:lims=>false),(:append=>true));plot!(leg=:bottomright);
      pp=posPlot(n,idx;(:setLims=>false));plot!(leg=:topright);
      if _pretty_defaults[:plant]; tp=tPlot(n,idx); else; tp=plot(0,leg=:false); end
      vt=vtPlot(n,idx)
      l = @layout [a{0.5w} [grid(2,2)
                            b{0.2h}]]
      mainS=plot(pp,sap,vt,longv,axp,tp,layout=l,size=_pretty_defaults[:size]);
    elseif isequal(c["misc"]["model"],:KinematicBicycle2)
      sap=controlPlot(n,idx,1);plot!(leg=:topleft)
      longv=statePlot(n,idx,4);plot!(leg=:topleft)
      axp=controlPlot(n,idx,2);plot!(leg=:bottomright);
      pp=posPlot(n,idx;(:setLims=>true));plot!(leg=:topright);
      if _pretty_defaults[:plant]; tp=tPlot(n,idx); else; tp=plot(0,leg=:false); end
      vt=vtPlot(n,idx)
      l = @layout [a{0.5w} [grid(2,2)
                            b{0.2h}]]
      mainS=plot(pp,sap,vt,longv,axp,tp,layout=l,size=_pretty_defaults[:size]);
    end

  end

  return mainS
end

"""
mainSim(n;(:mode=>:open1))
--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 4/13/2017, Last Modified: 7/6/2017 \n
--------------------------------------------------------------------------------------\n
"""

function mainSim(n;kwargs...)
  r = n.r
  kw = Dict(kwargs)
  if !haskey(kw,:mode);error("select a mode for the simulation \n")
  else; mode=get(kw,:mode,0);
  end

  if n.r.ocp.evalNum>2
    if typeof(n.r.ocp.dfs[end]) == nothing || typeof(n.r.ocp.dfs[end]) == Void
      pop!(n.r.ocp.dfs)
    end # assuming there is only one nothing
    if abs(n.r.ocp.dfs[end][:t][end]-n.r.ocp.dfs[end][:t][1]) < 0.2
      warn("\n The time scale for the final optimization is too small to plot.\n
                Deleting the final element in the results! \n ")
      pop!(n.r.ocp.dfs)
      num = n.r.ocp.evalNum - 1
    else
      num = n.r.ocp.evalNum
    end
      if n.r.ocp.evalNum > length(n.r.ip.dfsplant)
        warn("Reducing the number of frames. n.r.ocp.evalNum > length(n.r.ip.dfsplant) ")
        num = length(n.r.ip.dfsplant)
      end
     anim = @animate for idx in 1:num
       mainPlot(n,idx;(:mode=>mode))
    end
    cd(n.r.resultsDir)
      gif(anim,"mainSim.gif",fps=Int(ceil(1/n.mpc.v.tex)));
      run(`ffmpeg -f gif -i mainSim.gif RESULT.mp4`)
    cd(n.r.mainDir)
  else
    warn("the evaluation number was not greater than 2. Cannot make animation. Plotting a static plot.")
    warn("\n Modifying current plot settings! \n")
    plotSettings(;(:simulate=>false),(:plant=>false));
    mainPlot(n,1;(:mode=>mode))
  end
  return nothing
end

"""

--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 4/13/2017, Last Modified: 5/1/2017 \n
--------------------------------------------------------------------------------------\n
"""

function pSim(n,c)
  r = n.r

  anim = @animate for ii in 1:length(r.ocp.dfs)
    posPlot(n,ii);
  end
  gif(anim, string(r.resultsDir,"posSim.gif"), fps=Int(ceil(1/n.mpc.v.tex)) );
  return nothing
end

"""

--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 4/13/2017, Last Modified: 4/13/2017 \n
--------------------------------------------------------------------------------------\n
"""

function pSimGR(n)

  ENV["GKS_WSTYPE"]="mov"
  gr(show=true)
  for ii in 1:length(n.r.ocp.dfs)
    posPlot(n,ii);
  end
end

"""
default(guidefont = font(17), tickfont = font(15), legendfont = font(12), titlefont = font(20))
s=Settings(;save=true,MPC=true,simulate=false,format=:png,plantOnly=true);
posterP(n,c)
--------------------------------------------------------------------------------------\n
Author: Huckleberry Febbo, Graduate Student, University of Michigan
Date Create: 4/13/2017, Last Modified: 6/22/2017 \n
--------------------------------------------------------------------------------------\n
"""

function posterP(n)
  r = n.r
  pa = n.ocp.params[1]
  c = n.ocp.params[5]

  if n.r.ocp.status==:Infeasible
    warn("\n Current solution is infeasible! Will try to plot, but it may fail... \n")
  end
  warn("\n Modifying current plot settings! \n")
  plotSettings(;(:simulate=>false),(:plant=>true),(:plantOnly=>true));

  # static plots for each frame
  idx = length(n.r.ocp.dfs)
  idxT = length(n.r.ocp.dfsOpt[:tSolve])
  if isequal(c["misc"]["model"],:ThreeDOFv2)
    sap = statePlot(n,idx,6)
    longv = statePlot(n,idx,7)
    axp = axLimsPlot(n,pa,idx); # add nonlinear acceleration limits
    axp = statePlot(n,idx,8,axp;(:lims=>false),(:append=>true))
  elseif isequal(c["misc"]["model"],:KinematicBicycle2)
    sap = controlPlot(n,idx,1);plot!(leg=:topleft)
    longv = statePlot(n,idx,4);plot!(leg=:topleft)
    axp = controlPlot(n,idx,2);plot!(leg=:bottomright)
  end
  pp = statePlot(n,idx,1,2;(:lims=>false))
  if _pretty_defaults[:plant]; tp=tPlot(n,idx); else; tp=plot(0,leg=:false); end
  vt = vtPlot(n,idx)

  # dynamic plots ( maybe only update every 5 frames or so)
  L = length(n.r.ip.dfsplant)
  v = Vector(1:5:L); if v[end]!=L; append!(v,L); end
  for ii in v
    if ii==1
      st1 = 1;st2 = 2;
      # values
  		temp = [r.ip.dfsplant[jj][n.ocp.state.name[st1]] for jj in 1:L]
  		vals1 = [idx for tempM in temp for idx=tempM]

  		# values
  		temp = [r.ip.dfsplant[jj][n.ocp.state.name[st2]] for jj in 1:L]
  		vals2 = [idx for tempM in temp for idx=tempM]

      pp = obstaclePlot(n,c,ii;(:append=>false),(:posterPlot=>true)) # add obstacles
  		plot!(vals1,vals2,line=_pretty_defaults[:plant_lines][1],label="Vehicle Trajectory")
      #pp = plot(vals1,vals2,line=_pretty_defaults[:plant_lines][1],label="Vehicle Trajectory")
      #pp = obstaclePlot(n,c,ii,pp;(:append=>true),(:posterPlot=>true)) # add obstacles
      pp = vehiclePlot(n,c,ii,pp;(:append=>true),(:posterPlot=>true))  # add the vehicle
    else
      pp = obstaclePlot(n,c,ii,pp;(:append=>true),(:posterPlot=>true))  # add obstacles
      pp = vehiclePlot(n,c,ii,pp;(:append=>true),(:posterPlot=>true))  # add the vehicle
    end
  end
  l = @layout [a{0.5w} [grid(2,2)
                        b{0.2h}]]
  poster = plot(pp,sap,vt,longv,axp,tp,layout=l,size=_pretty_defaults[:size])
  savefig(string(r.resultsDir,"poster",".",_pretty_defaults[:format]))
  return nothing
end


text:
#using PyCall
#@pyimport jsonschema
using JSON, Vega, Base.Test, KernelDensity, Distributions, RDatasets
vegaschema = JSON.parse(readall(joinpath(dirname(@__FILE__), "..", "assets/bower_components/vega/vega-schema.json")))

#### Tests ####
#Test that Julia returned VegaVisulization (every public function does)
#jsonschema.validate returns nothing if json validates against schema

#1. Area Plot
println("Test 1")
x = rand(Beta(3.0, 2.0), 10)
k = kde(x)
a = areaplot(x = k.x, y = k.density);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#2. Stacked Area
println("Test 2")
x = [0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9]
y = [28, 43, 81, 19, 52, 24, 87, 17, 68, 49, 55, 91, 53, 87, 48, 49, 66, 27, 16, 15]
g = [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1]
a = areaplot(x = x, y = y, group = g, stacked = true);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#3. Normalized Stacked area
println("Test 3")
x = [0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9]
y = [28, 43, 81, 19, 52, 24, 87, 17, 68, 49, 55, 91, 53, 87, 48, 49, 66, 27, 16, 15]
g = [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1]
a = areaplot(x = x, y = y, group = g, stacked = true, normalize = true);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#4. Aster Plot
println("Test 4")
score = [59, 24, 98, 60 ,74,70,42,77,88,60,65,71,88,83]
id = ["FIS", "MAR","AO","NP","CS","CP","TR","LIV","ECO","ICO","LSP","CW","HAB","SPP"]
weight = [0.5, 0.5, 1,1,1,1,1,0.5,0.5,0.5,0.5,1,0.5,0.5]
a = asterplot(x = id, y = score, weight = weight, holesize = 75);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#5. Bar plot
println("Test 5")
x = [1, 2, 3, 4, 5]
y = [1, 2, 3, 2, 1]
a = barplot(x = x, y = y);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#6. Horizontal Bar Plot
println("Test 6")
x = [1, 2, 3, 4, 5]
y = [1, 2, 3, 2, 1]
a = barplot(x = x, y = y, horizontal = true);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#7. Group Argument
println("Test 7")
x = collect(1:20)
y = rand(20)
group = [round(val/10) for val in x]
a = barplot(x = x, y = y, group = group);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#8. Stacked bar
println("Test 8")
x = [0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9]
y = [28, 43, 81, 19, 52, 24, 87, 17, 68, 49, 55, 91, 53, 87, 48, 49, 66, 27, 16, 15]
g = [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1]
a = barplot(x = x, y = y, group = g, stacked = true);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#9. Horizontal Normalized Bar
println("Test 9")
x = [0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9]
y = [28, 43, 81, 19, 52, 24, 87, 17, 68, 49, 55, 91, 53, 87, 48, 49, 66, 27, 16, 15]
g = [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1]
a = barplot(x = x, y = y, group = g, stacked = true, normalize = true, horizontal = true);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#10. Single boxplot
println("Test 10")
df = dataset("datasets", "mtcars")
a = boxplot(y = df[:MPG])

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#11. Group boxplot
println("Test 11")
df = dataset("datasets", "mtcars")
boxplot(y = df[:MPG], group = df[:Cyl])

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#12. Bubble Chart
println("Test 12")
x = [95, 86.5, 80.8, 80.4, 80.3, 78.4, 74.2, 73.5, 71, 69.2, 68.6, 65.5, 65.4, 63.4, 64]
y = [95, 102.9, 91.5, 102.5, 86.1, 70.1, 68.5, 83.1, 93.2, 57.6, 20, 126.4, 50.8, 51.8, 82.9]
cont = ["EU", "EU", "EU", "EU", "EU", "EU", "EU", "NO", "EU", "EU", "RU", "US", "EU", "EU", "NZ"]
z = [13.8, 14.7, 15.8, 12, 11.8, 16.6, 14.5, 10, 24.7, 10.4, 16, 35.3, 28.5, 15.4, 31.3]
a = bubblechart(x = x, y = y, group = cont, pointSize = z)

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#13. Choropleth Counties
println("Test 13")
df = readtable(joinpath(dirname(@__FILE__), "..", "vega-datasets/unemployment.tsv"))
a = choropleth(x = df[:id], y = df[:rate])

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#14. Choropleth States
println("Test 14")
x = collect(1:60)
y = rand(Float64, 60)
a = choropleth(x = x, y = y, entity = :usstates)

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#15. Grouped Bar
println("Test 15")
category = ["A", "A", "A", "A", "B", "B", "B", "B", "C", "C", "C", "C"]
group = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
value = [0.1, 0.6, 0.9, 0.4, 0.7, 0.2, 1.1, 0.8, 0.6, 0.2, 0.1, 0.7]
a = groupedbar(x = category, y = value, group = group);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#16. Heatmap
println("Test 16")
x = Array(Int, 900)
y = Array(Int, 900)
color = Array(Float64, 900)

t = 0
for i in 1:30
    for j in 1:30
        t += 1
        x[t] = i
        y[t] = j
        color[t] = rand()
    end
end
a = heatmap(x = x, y = y, color = color);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#17. Histogram
println("Test 17")
x = rand(Gamma(3.0, 1.0), 100_000)
a = histogram(x = x);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#18. Histogram
println("Test 18")
x = rand(Gamma(3.0, 1.0), 100_000)
a = histogram(x = x, relativefreq = true);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#19. Joint Plot
println("Test 19")
faithful = dataset("datasets", "faithful")
a = jointplot(x = faithful[:Eruptions], y = faithful[:Waiting]);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#20. Line Plot
println("Test 20")
x = [1:100; 1:100]
y = [collect(1:100) + randn(100); 3.0 + 1.5 * collect(1:100) + randn(100)]
group = [[1 for i in 1:100]; [2 for i in 1:100]]
a = lineplot(x = x, y = y, group = group);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#21. Line Plot with Points
println("Test 21")
x = [1:100; 1:100]
y = [collect(1:100) + randn(100); 3.0 + 1.5 * collect(1:100) + randn(100)]
group = [[1 for i in 1:100]; [2 for i in 1:100]]
a = lineplot(x = x, y = y, group = group, points = true);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#22. Line Plot, Bigger Points
println("Test 22")
x = [1:100; 1:100]
y = [collect(1:100) + randn(100); 3.0 + 1.5 * collect(1:100) + randn(100)]
group = [[1 for i in 1:100]; [2 for i in 1:100]]
a = lineplot(x = x, y = y, group = group, points = true, pointSize = 20);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#23. Pie chart
println("Test 23")
fruit = ["peaches", "plums", "blueberries", "strawberries", "bananas"]
bushels = [100, 32, 180, 46, 21]
a = piechart(x = fruit, y = bushels);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#24. Donut chart
println("Test 24")
fruit = ["peaches", "plums", "blueberries", "strawberries", "bananas"]
bushels = [100, 32, 180, 46, 21]
a = piechart(x = fruit, y = bushels, holesize = 175);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#25. Population Chart
println("Test 25")
df = DataFrame()
for p in JSON.parse(readall(joinpath(dirname(@__FILE__), "..", "vega-datasets/population.json")))
    df = vcat(df, DataFrame(;[symbol(k)=>v for (k,v) in p]...))
end
pop1900 = df[df[:year] .== 1900, :];
x = pop1900[:people]
y = pop1900[:age]
group = pop1900[:sex]
a = popchart(x = x, y = y, group = group);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#26. Rug Plot
println("Test 26")
mtcars = dataset("datasets", "mtcars")
x = mtcars[:Disp]
a = rugplot(x = x);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#27. Scatter Plot
println("Test 27")
d1 = MultivariateNormal([0.0, 0.0], [1.0 0.9; 0.9 1.0])
d2 = MultivariateNormal([10.0, 10.0], [4.0 0.5; 0.5 4.0])
points = vcat(rand(d1, 500)', rand(d2, 500)')
x = points[:, 1]
y = points[:, 2]
group = vcat(ones(Int, 500), ones(Int, 500) + 1)
a = scatterplot(x = x, y = y, group = group);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#28. Stem and Leaf
println("Test 28")
data = [6, 1,3,5, 17, 32, 47, 53, 60, 61, 64, 67, 70, 70, 71, 72, 73, 73, 74, 76, 77,
        79, 81, 82, 83, 83, 83, 83, 84, 85, 86, 87, 87, 88, 89, 90, 91, 91, 92, 94, 94,
        95, 96, 97, 98, 98, 99, 99, 99, 99, 99, 100, 100, 100, 101, 101, 102, 103, 103,
        103, 103, 104, 106, 106, 106, 106, 107, 107, 107, 107, 108, 109, 109, 110, 111,
        111, 111, 112, 112, 113, 114, 114, 114, 115, 116, 117, 117, 119, 120, 120, 120,
        120, 121, 121, 122, 122, 122, 123, 124, 124, 125, 125, 126, 126, 127, 128, 129,
        130, 131, 131, 131, 131, 132, 132, 132, 132, 133, 133, 134, 134, 134, 135, 135,
        135, 136, 136, 136, 137, 138, 139, 140, 140, 142, 143, 144, 145, 145, 145, 145,
        145, 147, 149, 152, 155, 157, 159]
a = stemleaf(y = data);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#29. Stream Plot
println("Test 29")
df = readtable(joinpath(dirname(@__FILE__), "..", "vega-datasets/streamdata.csv"))
a = streamplot(x = df[:date], y = df[:value], group = df[:key]);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#30. Waterfall
println("Test 30")
categories = ["Product Revenue", "Services Revenue", "Fixed Costs", "Variable Costs", "One-Time Costs"]
value = [420000, 210000, -170000, -140000, -75000]
a = waterfall(x = categories, y = value)

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#31. Wordcloud
println("Test 31")
corpus = [
"Julia is a high-level, high-performance dynamic programming language for technical computing, with syntax that is familiar to users of other technical computing environments. It provides a sophisticated compiler, distributed parallel execution, numerical accuracy, and an extensive mathematical function library. Julia’s Base library, largely written in Julia itself, also integrates mature, best-of-breed open source C and Fortran libraries for linear algebra, random number generation, signal processing, and string processing. In addition, the Julia developer community is contributing a number of external packages through Julia’s built-in package manager at a rapid pace. IJulia, a collaboration between the IPython and Julia communities, provides a powerful browser-based graphical notebook interface to Julia.",
"Julia programs are organized around multiple dispatch; by defining functions and overloading them for different combinations of argument types, which can also be user-defined. For a more in-depth discussion of the rationale and advantages of Julia over other systems, see the following highlights or read the introduction in the online manual."
]
a = wordcloud(x = corpus);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#32. Wordcloud
println("Test 32")
corpus = [
"Julia is a high-level, high-performance dynamic programming language for technical computing, with syntax that is familiar to users of other technical computing environments. It provides a sophisticated compiler, distributed parallel execution, numerical accuracy, and an extensive mathematical function library. Julia’s Base library, largely written in Julia itself, also integrates mature, best-of-breed open source C and Fortran libraries for linear algebra, random number generation, signal processing, and string processing. In addition, the Julia developer community is contributing a number of external packages through Julia’s built-in package manager at a rapid pace. IJulia, a collaboration between the IPython and Julia communities, provides a powerful browser-based graphical notebook interface to Julia.",
"Julia programs are organized around multiple dispatch; by defining functions and overloading them for different combinations of argument types, which can also be user-defined. For a more in-depth discussion of the rationale and advantages of Julia over other systems, see the following highlights or read the introduction in the online manual."
]
a = wordcloud(x = corpus, wordAngles = [0, 90]);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#33. Wordcloud
println("Test 33")
corpus = [
"Julia is a high-level, high-performance dynamic programming language for technical computing, with syntax that is familiar to users of other technical computing environments. It provides a sophisticated compiler, distributed parallel execution, numerical accuracy, and an extensive mathematical function library. Julia’s Base library, largely written in Julia itself, also integrates mature, best-of-breed open source C and Fortran libraries for linear algebra, random number generation, signal processing, and string processing. In addition, the Julia developer community is contributing a number of external packages through Julia’s built-in package manager at a rapid pace. IJulia, a collaboration between the IPython and Julia communities, provides a powerful browser-based graphical notebook interface to Julia.",
"Julia programs are organized around multiple dispatch; by defining functions and overloading them for different combinations of argument types, which can also be user-defined. For a more in-depth discussion of the rationale and advantages of Julia over other systems, see the following highlights or read the introduction in the online manual."
]
a = wordcloud(x = corpus, minThreshold = 1);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#34. colorscheme!
println("Test 34")
a = barplot(x = collect(1:20), y = rand(20), group = vcat([1 for i in 1:10], [2 for i in 1:10]));
colorscheme!(a, palette = ("Purples", 3));

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#35. colorscheme!
println("Test 35")
srand(1)
a = barplot(x = collect(1:20), y = rand(20))
colorscheme!(a, palette = "Violet");

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#36. colorscheme!
println("Test 36")
df = DataFrame()
for p in JSON.parse(readall(joinpath(dirname(@__FILE__), "..", "vega-datasets/population.json")))
    df = vcat(df, DataFrame(;[symbol(k)=>v for (k,v) in p]...))
end
pop1900 = df[df[:year] .== 1900, :];
x = pop1900[:people]
y = pop1900[:age]
group = pop1900[:sex]
a = popchart(x = x, y = y, group = group);
colorscheme!(a, palette = ["Green", "Red"]);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#37. hline!
println("Test 37")
x = [0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9]
y = [28, 43, 81, 19, 52, 24, 87, 17, 68, 49, 55, 91, 53, 87, 48, 49, 66, 27, 16, 15]
g = [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1]
a = areaplot(x = x, y = y, group = g, stacked = true);
hline!(a, value = 60.25, strokeDash = 3)

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#38 hover!
println("Test 38")
score = [59, 24, 98, 60 ,74,70,42,77,88,60,65,71,88,83]
id = ["FIS", "MAR","AO","NP","CS","CP","TR","LIV","ECO","ICO","LSP","CW","HAB","SPP"]
weight = [0.5, 0.5, 1,1,1,1,1,0.5,0.5,0.5,0.5,1,0.5,0.5]
a = asterplot(x = id, y = score, weight = weight, holesize = 75);
hover!(a, opacity = 0.5);

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#39 jitter!
println("Test 39")
x = rand(1:10, 500)
y = rand(0:10, 500) + x
a = scatterplot(x = x, y = y);
jitter!(a)

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

jitter!(a, pctXrange = 0.1, pctYrange = 0)

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#40 legend!
println("Test 40")
fruit = ["peaches", "plums", "blueberries", "strawberries", "bananas"]
bushels = [100, 32, 180, 46, 21]
a = piechart(x = fruit, y = bushels);
legend!(a, title = "Fruit")

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#41 stroke!
println("Test 41")
category = ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C']
group = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
value = [0.1, 0.6, 0.9, 0.4, 0.7, 0.2, 1.1, 0.8, 0.6, 0.2, 0.1, 0.7]
a = groupedbar(x = category, y = value, group = group);
stroke!(a, width = 1.5)

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#42 text!
println("Test 42")
x = [95, 86.5, 80.8, 80.4, 80.3, 78.4, 74.2, 73.5, 71, 69.2, 68.6, 65.5, 65.4, 63.4, 64]
y = [95, 102.9, 91.5, 102.5, 86.1, 70.1, 68.5, 83.1, 93.2, 57.6, 20, 126.4, 50.8, 51.8, 82.9]
cont = ["EU", "EU", "EU", "EU", "EU", "EU", "EU", "NO", "EU", "EU", "RU", "US", "EU", "EU", "NZ"]
z = [13.8, 14.7, 15.8, 12, 11.8, 16.6, 14.5, 10, 24.7, 10.4, 16, 35.3, 28.5, 15.4, 31.3]
a = bubblechart(x = x, y = y, group = cont, pointSize = z);

#Annotate graph
text!(a, title = "Safe Sugar Intake 50g/day", x = 525, y = 200)
text!(a, title = "Safe Fat Intake 65g/day", x = 150, y = 10)

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#43 title!
println("Test 43")
df = DataFrame()
for p in JSON.parse(readall(joinpath(dirname(@__FILE__), "..", "vega-datasets/population.json")))
    df = vcat(df, DataFrame(;[symbol(k)=>v for (k,v) in p]...))
end
pop1900 = df[df[:year] .== 1900, :];
x = pop1900[:people]
y = pop1900[:age]
group = pop1900[:sex]
a = popchart(x = x, y = y, group = group);
title!(a, title = "Gender & Age Comparison - 1900")

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#44 xlab!/ylab!
println("Test 44")
x = [1:100; 1:100]
y = [collect(1:100) + randn(100); 3.0 + 1.5 * collect(1:100) + randn(100)]
group = [[1 for i in 1:100]; [2 for i in 1:100]]
a = lineplot(x = x, y = y, group = group);
xlab!(a, title = "Weight (kg)")
ylab!(a, title = "Height (cm)")

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#45 xlim!/ylim!
println("Test 45")
x = [1:100; 1:100]
y = [collect(1:100) + randn(100); 3.0 + 1.5 * collect(1:100) + randn(100)]
group = [[1 for i in 1:100]; [2 for i in 1:100]]
a = lineplot(x = x, y = y, group = group);
xlim!(a, min=0, max=200)
ylim!(a, min=0, max=200)

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#46 background color
println("Test 46")
x = [1:100; 1:100]
y = [collect(1:100) + randn(100); 3.0 + 1.5 * collect(1:100) + randn(100)]
group = [[1 for i in 1:100]; [2 for i in 1:100]]
a = lineplot(x = x, y = y, group = group);
a.background = "green"

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#47 dotplot
println("Test 47")
df = DataFrame()
for p in JSON.parse(readall(joinpath(dirname(@__FILE__), "..", "vega-datasets/movies.json")))
    df = vcat(df, DataFrame(;[symbol(k)=>v for (k,v) in p]...))
end

a = dotplot(x = x = df[:US_Gross], y = df[:Major_Genre])
a.width = 500
ylab!(a, title = " ", grid = true)
xlab!(a, title = "Avg. U.S. Gross Movie Receipts", format = ".3s")

@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#48 dotplot
println("Test 48")
df = DataFrame()
for p in JSON.parse(readall(joinpath(dirname(@__FILE__), "..", "vega-datasets/movies.json")))
    df = vcat(df, DataFrame(;[symbol(k)=>v for (k,v) in p]...))
end

a = dotplot(x = x = df[:US_Gross], y = df[:Major_Genre], sorted = false)
@test typeof(a) == VegaVisualization
#@test jsonschema.validate(tojs(a), vegaschema) == nothing

#49 lineplot with log yaxis
println("Test 49")
x = [1:100; 1:100]
y = [collect(1:100) + randn(100); 3.0 + 1.5 * collect(1:100) + randn(100)]
group = [[1 for i in 1:100]; [2 for i in 1:100]]

a = lineplot(x = x, y = y, group = group)
ylim!(a, _type = "log")
@test typeof(a) == VegaVisualization

#50 lineplot with pow yaxis
println("Test 50")
x = [1:100; 1:100]
y = [collect(1:100) + randn(100); 3.0 + 1.5 * collect(1:100) + randn(100)]
group = [[1 for i in 1:100]; [2 for i in 1:100]]

a = lineplot(x = x, y = y, group = group)
ylim!(a, _type = "pow")
@test typeof(a) == VegaVisualization

#51 lineplot with sqrt yaxis
println("Test 51")
x = [1:100; 1:100]
y = [collect(1:100) + randn(100); 3.0 + 1.5 * collect(1:100) + randn(100)]
group = [[1 for i in 1:100]; [2 for i in 1:100]]

a = lineplot(x = x, y = y, group = group)
ylim!(a, _type = "sqrt")
@test typeof(a) == VegaVisualization

#52 reverse keyword for colorscheme!
println("Test 52")
x = [1:100; 1:100]
y = [collect(1:100) + randn(100); 3.0 + 1.5 * collect(1:100) + randn(100)]
group = [[1 for i in 1:100]; [2 for i in 1:100]]

a = lineplot(x = x, y = y, group = group)
colorscheme!(a, palette = ("wesanderson", "BottleRocket1"), reversePalette = true)
@test typeof(a) == VegaVisualization

#53 color keyword for hover!
println("Test 53")
x = [1, 2, 3, 4, 5]
y = [1, 2, 3, 2, 1]

a = barplot(x = x, y = y)
hover!(a, color = "red")
@test typeof(a) == VegaVisualization

#54. Ribbon plot
println("Test 54")
x = [0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9]
y = [28, 43, 81, 19, 52, 24, 87, 17, 68, 49, 55, 91, 53, 87, 48, 49, 66, 27, 16, 15]
g = [0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1]
a = ribbonplot(x = x, ylow = 0.9y, yhigh=1.1y, group = g);

@test typeof(a) == VegaVisualization

#55. Horizon plot
x = 1:20
y = [28, 55, 43, 91, 81, 53, 19, 87, 52, 48, 24, 49, 87, 66, 17, 27, 68, 16, 49, 15]
a = horizon(x = x, y = y)
colorscheme!(a, palette = "green")

@test typeof(a) == VegaVisualization

max_stars_repo_name: jpthor/vega