text:
function enlargesubset(initialsubset, data::DataFrame, dataMatrix::Matrix, h::Int)
    n, p = size(dataMatrix)
    indices = collect(1:n)
    basicsubset = copy(initialsubset)
    while length(basicsubset) < h
        meanvector = applyColumns(mean, data[basicsubset,:])
        covmatrix = cov(dataMatrix[basicsubset, :])
        md2mat = mahalanobisSquaredMatrix(data, meanvector=meanvector, covmatrix=covmatrix)
        md2 = diag(md2mat)
        md2sortedindex = sortperm(md2)
        basicsubset = md2sortedindex[1:(length(basicsubset) + 1)]
    end
    return basicsubset
end

function robcov(data::DataFrame; alpha=0.01, estimator=:mve)
    dataMatrix = convert(Matrix, data)
    n, p = size(dataMatrix)
    chisquared = Chisq(p)
    chisqcrit = quantile(chisquared, 1.0 - alpha)
    c = sqrt(chisqcrit)
    h = Int(floor((n + p + 1.0) / 2.0))
    indices = collect(1:n)
    k = p + 1
    mingoal = Inf
    bestinitialsubset = []
    besthsubset = []
    maxiter = minimum([p * 500, 3000])
    initialsubset = []
    hsubset = []
    for iter in 1:maxiter
        goal = Inf
        try
            initialsubset = sample(indices, k, replace=false)
            hsubset = enlargesubset(initialsubset, data, dataMatrix, h)
            covmatrix = cov(dataMatrix[hsubset, :])
            if estimator == :mve
                meanvector = applyColumns(mean, data[hsubset, :])
                md2mat = mahalanobisSquaredMatrix(data, meanvector=meanvector, covmatrix=covmatrix)
                DJ = sqrt(sort(diag(md2mat))[h])
                goal =  (DJ / c)^p * det(covmatrix)
            else
                goal = det(covmatrix)
            end
        catch e
            # Possibly singularity
        end
        if goal < mingoal
            mingoal = goal
            bestinitialsubset = initialsubset
            besthsubset = hsubset
        end
    end
    meanvector = applyColumns(mean, data[besthsubset, :])
    covariancematrix = cov(dataMatrix[besthsubset, :])
    md2 = diag(mahalanobisSquaredMatrix(data, meanvector=meanvector, covmatrix=covariancematrix))
    outlierset = filter(x -> md2[x] > chisqcrit, 1:n)
    result = Dict()
    result["goal"] = mingoal
    result["best.subset"] = sort(besthsubset)
    result["robust.location"] = meanvector
    result["robust.covariance"] = covariancematrix
    result["squared.mahalanobis"] = md2
    result["chisq.crit"] = chisqcrit
    result["alpha"] = alpha
    result["outliers"] = outlierset
    return result
end

"""
    mve(data; alpha = 0.01)

Performs the Minimum Volume Ellipsoid algorithm for a robust covariance matrix.

# Arguments
- `data::DataFrame`: Multivariate data.
- `alpha::Float64`: Probability for quantiles of Chi-Squared statistic.

# References
Van Aelst, Stefan, and Peter Rousseeuw. "Minimum volume ellipsoid." Wiley
Interdisciplinary Reviews: Computational Statistics 1.1 (2009): 71-82.
"""
function mve(data::DataFrame; alpha=0.01)
    robcov(data, alpha=alpha, estimator=:mve)
end

function mve(data::Array{Float64,2}; alpha=0.01)
    return mve(DataFrame(data), alpha=alpha)
end

"""
    mcd(data; alpha = 0.01)

Performs the Minimum Covariance Determinant algorithm for a robust covariance matrix.

# Arguments
- `data::DataFrame`: Multivariate data.
- `alpha::Float64`: Probability for quantiles of Chi-Squared statistic.

# Notes
Algorithm is implemented using concentration steps as described in the reference paper.
However, details about number of iterations are slightly different.

# References
Rousseeuw, Peter J., and Katrien Van Driessen. "A fast algorithm for the minimum covariance
determinant estimator." Technometrics 41.3 (1999): 212-223.
"""
function mcd(data::DataFrame; alpha=0.01)
    robcov(data, alpha=alpha, estimator=:mcd)
end

function mcd(data::Array{Float64,2}; alpha=0.01)
    return mcd(DataFrame(data), alpha=alpha)
end

max_stars_repo_name: akadal/LinRegOutliers

max_issues_repo_name: akadal/LinRegOutliers

max_forks_repo_name: akadal/LinRegOutliers


text:
"""
    fire(inplanes, squeeze_planes, expand1x1_planes, expand3x3_planes)

Create a fire module
([reference](https://arxiv.org/abs/1602.07360v4)).

# Arguments
- `inplanes`: number of input feature maps
- `squeeze_planes`: number of intermediate feature maps
- `expand1x1_planes`: number of output feature maps for the 1x1 expansion convolution
- `expand3x3_planes`: number of output feature maps for the 3x3 expansion convolution
"""
function fire(inplanes, squeeze_planes, expand1x1_planes, expand3x3_planes)
  branch_1 = Conv((1, 1), inplanes => squeeze_planes, relu)
  branch_2 = Conv((1, 1), squeeze_planes => expand1x1_planes, relu)
  branch_3 = Conv((3, 3), squeeze_planes => expand3x3_planes, pad = 1, relu)

  return Chain(branch_1,
               Parallel(cat_channels,
                        branch_2,
                        branch_3))
end

"""
    squeezenet()

Create a SqueezeNet
([reference](https://arxiv.org/abs/1602.07360v4)).
"""
function squeezenet()
  layers = Chain(Chain(Conv((3, 3), 3 => 64, relu, stride = 2),
                       MaxPool((3, 3), stride = 2),
                       fire(64, 16, 64, 64),
                       fire(128, 16, 64, 64),
                       MaxPool((3, 3), stride = 2),
                       fire(128, 32, 128, 128),
                       fire(256, 32, 128, 128),
                       MaxPool((3, 3), stride = 2),
                       fire(256, 48, 192, 192),
                       fire(384, 48, 192, 192),
                       fire(384, 64, 256, 256),
                       fire(512, 64, 256, 256),
                       Dropout(0.5),
                       Conv((1, 1), 512 => 1000, relu)),
                 AdaptiveMeanPool((1, 1)),
                 MLUtils.flatten)

  return layers
end

"""
    SqueezeNet(; pretrain = false)

Create a SqueezeNet
([reference](https://arxiv.org/abs/1602.07360v4)).
Set `pretrain=true` to load the model with pre-trained weights for ImageNet.

!!! warning
    `SqueezeNet` does not currently support pretrained weights.

See also [`squeezenet`](#).
"""
struct SqueezeNet
  layers
end

function SqueezeNet(; pretrain = false)
  layers = squeezenet()
  pretrain && loadpretrain!(layers, "SqueezeNet")

  SqueezeNet(layers)
end

@functor SqueezeNet

(m::SqueezeNet)(x) = m.layers(x)

backbone(m::SqueezeNet) = m.layers[1]
classifier(m::SqueezeNet) = m.layers[2:end]

ext: jl


text:
module TestGradient
    using Base.Test
    import FiniteDiff

    f1(x) = sin(x[1]) + cos(x[2])
    function g1!(out, x)
        out[1] = cos(x[1])
        out[2] = -sin(x[2])
        return
    end

    f2(x) = 2.3 * sin(x[1]) + 3.1 * cos(x[2])
    function g2!(out, x)
        out[1] = 2.3 * cos(x[1])
        out[2] = -3.1 * sin(x[2])
        return
    end

    f3(x) = 0.1 * (x[1] - 1.0)^2 - 0.3 * (x[2] - 0.7)^2
    function g3!(out, x)
        out[1] = 0.1 * 2.0 * (x[1] - 1.0)
        out[2] = -0.3 * 2.0 * (x[2] - 0.7)
        return
    end

    function check_error(y_true, y_approximate, err = 1 // 1_000)
        n = length(y_true)
        @test length(y_approximate) == n
        for i in 1:n
            if y_true[i] > eps(y_true[i])
                @test abs(y_true[i] - y_approximate[i]) / abs(y_true[i]) < err
            end
        end
    end

    function run_tests(n::Integer)
        funcs = (
            (f1, g1!),
            (f2, g2!),
            (f3, g3!),
        )

        x = Array(Float64, 2)
        output = Array(Float64, 2)
        buffer = Array(Float64, 2)
        buffer_complex = Array(Complex{Float64}, 2)
        gr = Array(Float64, 2)

        n_dims = length(x)

        modes = (
            FiniteDiff.ForwardMode(),
            FiniteDiff.BackwardMode(),
            FiniteDiff.CentralMode(),
            FiniteDiff.ComplexMode(),
        )

        for (f, f′!) in funcs
            for itr in 1:n
                for i in 1:n_dims
                    x[i] = itr
                end

                # Evaluate the true gradient and store it into gr.
                f′!(gr, x)

                for mode in modes
                    if mode != FiniteDiff.ComplexMode()
                        FiniteDiff.gradient!(output, f, x, buffer, mode)
                    else
                        FiniteDiff.gradient!(output, f, x, buffer_complex, mode)
                    end
                    check_error(gr, output)

                    output2 = FiniteDiff.gradient(f, x, mode)
                    check_error(gr, output2)

                    tmp! = FiniteDiff.gradient(f, mode, mutates = true)
                    if mode != FiniteDiff.ComplexMode()
                        tmp!(output, x, buffer)
                    else
                        tmp!(output, x, buffer_complex)
                    end
                    check_error(gr, output)

                    tmp = FiniteDiff.gradient(f, mode, mutates = false)
                    output2 = tmp(x)
                    check_error(gr, output2)
                end
            end
        end
    end

    @testset "gradient tests" begin
        run_tests(100)
    end
end


text:
export UnionSetArray,
       array

# ========================================
# n-ary set union
# ========================================

"""
   UnionSetArray{N<:Real, S<:LazySet{N}}

Type that represents the set union of a finite number of convex sets.

### Fields

- `array` -- array of convex sets
"""
struct UnionSetArray{N<:Real, S<:LazySet{N}}
   array::Vector{S}
end

isoperationtype(::Type{<:UnionSetArray}) = true
isconvextype(::Type{<:UnionSetArray}) = false

# EmptySet is the neutral element for UnionSetArray
@neutral(UnionSetArray, EmptySet)

# Universe is the absorbing element for UnionSetArray
@absorbing(UnionSetArray, Universe)

# add functions connecting UnionSet and UnionSetArray
@declare_array_version(UnionSet, UnionSetArray)

"""
   dim(cup::UnionSetArray)

Return the dimension of the set union of a finite number of convex sets.

### Input

- `cup` -- union of a finite number of convex sets

### Output

The ambient dimension of the union of a finite number of convex sets.
"""
function dim(cup::UnionSetArray)
   return dim(cup.array[1])
end

"""
   array(cup::UnionSetArray{N, S}) where {N<:Real, S<:LazySet{N}}

Return the array of a union of a finite number of convex sets.

### Input

- `cup` -- union of a finite number of convex sets

### Output

The array that holds the union of a finite number of convex sets.
"""
function array(cup::UnionSetArray{N, S}) where {N<:Real, S<:LazySet{N}}
   return cup.array
end

"""
   σ(d::AbstractVector{N}, cup::UnionSetArray{N}; [algorithm]="support_vector") where {N<:Real}

Return the support vector of the union of a finite number of convex sets in
a given direction.

### Input

- `d`         -- direction
- `cup`       -- union of a finite number of convex sets
- `algorithm` -- (optional, default: "support_vector"): the algorithm to compute
                the support vector; if "support_vector", use the support
                vector of each argument; if "support_function" use the support
                function of each argument and evaluate the support vector of only
                one of them

### Output

The support vector in the given direction.

### Algorithm

The support vector of the union of a finite number of convex sets ``X₁, X₂, ...``
can be obtained as the vector that maximizes the support function, i.e.
it is sufficient to find the ``\\argmax(ρ(d, X₂), ρ(d, X₂), ...])`` and evaluate
its support vector.

The default implementation, with option `algorithm="support_vector"`, computes
the support vector of all ``X₁, X₂, ...`` and then compares the support function using
a dot product. If it happens that the support function can be more efficiently
computed (without passing through the support vector), consider using the alternative
`algorithm="support_function"` implementation, which evaluates the support function
of each set directly and then calls only the support vector of one of the ``Xᵢ``.
"""
function σ(d::AbstractVector{N}, cup::UnionSetArray{N}; algorithm="support_vector") where {N<:Real}
   A = array(cup)
   if algorithm == "support_vector"
       σarray = map(Xi -> σ(d, Xi), A)
       ρarray = map(vi -> dot(d, vi), σarray)
       m = argmax(ρarray)
       return σarray[m]
   elseif algorithm == "support_function"
       ρarray = map(Xi -> ρ(d, Xi), A)
       m = argmax(ρarray)
       return σ(d, A[m])
   else
       error("algorithm $algorithm for the support vector of a `UnionSetArray` is unknown")
   end
end

"""
   ρ(d::AbstractVector{N}, cup::UnionSetArray{N}) where {N<:Real}

Return the support function of the union of a finite number of convex sets in
a given direction.

### Input

- `d`   -- direction
- `cup` -- union of a finite number of convex sets

### Output

The support function in the given direction.

### Algorithm

The support function of the union of a finite number of convex sets ``X₁, X₂, ...``
can be obtained as the maximum of ``ρ(d, X₂), ρ(d, X₂), ...``.
"""
function ρ(d::AbstractVector{N}, cup::UnionSetArray{N}) where {N<:Real}
   A = array(cup)
   ρarray = map(Xi -> ρ(d, Xi), A)
   return maximum(ρarray)
end

"""
   an_element(cup::UnionSetArray{N}) where {N<:Real}

Return some element of a union of a finite number of convex sets.

### Input

- `cup` -- union of a finite number of convex sets

### Output

An element in the union of a finite number of convex sets.

### Algorithm

We use `an_element` on the first wrapped set.
"""
function an_element(cup::UnionSetArray{N}) where {N<:Real}
   return an_element(array(cup)[1])
end

"""
   ∈(x::AbstractVector{N}, cup::UnionSetArray{N}) where {N<:Real}

Check whether a given point is contained in a union of a finite number of convex
sets.

### Input

- `x`   -- point/vector
- `cup` -- union of a finite number of convex sets

### Output

`true` iff ``x ∈ cup``.
"""
function ∈(x::AbstractVector{N}, cup::UnionSetArray{N}) where {N<:Real}
   return any(X -> x ∈ X, array(cup))
end

"""
   isempty(cup::UnionSetArray)

Check whether a union of a finite number of convex sets is empty.

### Input

- `cup` -- union of a finite number of convex sets

### Output

`true` iff the union is empty.
"""
function isempty(cup::UnionSetArray)
   return all(isempty, array(cup))
end

"""
   isbounded(cup::UnionSetArray)

Determine whether a union of a finite number of convex sets is bounded.

### Input

- `cup` -- union of a finite number of convex sets

### Output

`true` iff the union is bounded.
"""
function isbounded(cup::UnionSetArray)
   return all(isbounded, array(cup))
end


text:
function fname_param(testunit_name,param,ext=".mat")
#"Test_VI=-1[V]_VRADJ=0[V].mat"
pnames = fieldnames(typeof(param))
param_names = ""
for pname in pnames
	aux  = getfield(param,pname)
	name = string(pname)
	val  = string(aux.value)
	unit = string(aux.unit)
	param_names = param_names*"_"*name*"="*val*"["*unit*"]"
end
fname = testunit_name*param_names*ext
end


text:
import DFWannier: Point3, SVector

import DFWannier: WannierFunction

x_range = -1:0.01:1
y_range = -1:0.01:1
z_range = -1:0.01:1

wfc_grid = [Point3(x, y, z) for x in x_range, y in y_range, z in z_range]

px_orb = normalize(WannierFunction(wfc_grid, [SVector(((p[1] + 0im) * ℯ^(-norm(p)^2)),) for p in wfc_grid]))

px_orb2 = px_orb'
LinearAlgebra.adjoint!(px_orb2, px_orb2)

@test values(px_orb2) == values(px_orb)

@test norm(px_orb) ≈ norm(px_orb2) ≈ 1.0

py_orb = normalize(WannierFunction(wfc_grid, [SVector(((p[2] + 0im) * ℯ^(-norm(p)^2)),) for p in wfc_grid]))

pz_orb = normalize(WannierFunction(wfc_grid, [SVector(((p[3] + 0im) * ℯ^(-norm(p)^2)),) for p in wfc_grid]))

@test dot(px_orb, py_orb) <= 1.0e-15
@test dot(px_orb, px_orb) ≈ 1.0

Lx = zeros(ComplexF64, 3, 3)
Ly = zeros(ComplexF64, 3, 3)
Lz = zeros(ComplexF64, 3, 3)
for (i1, p1) in enumerate((px_orb, py_orb, pz_orb)), (i2, p2) in enumerate((px_orb, py_orb, pz_orb))
	Lx[i1, i2], Ly[i1, i2], Lz[i1, i2] = DFW.calc_angmom(p1, p2, zero(Point3))
end

@test norm(sum(Lx .- [0 0 0; 0 0 -im; 0 im 0])) < 1e-4
@test norm(sum(Ly .- [0 0 im; 0 0 0; -im 0 0])) < 1e-4
@test norm(sum(Lz .- [0 -im 0; im 0 0; 0 0 0])) < 1e-4

px_orb_up = normalize(WannierFunction(wfc_grid, [SVector((p[1] + 0im, zero(ComplexF64)) .* ℯ^(-norm(p)^2)) for p in wfc_grid]))
px_orb_dn = normalize(WannierFunction(wfc_grid, [SVector((zero(ComplexF64), p[1] + 0im) .* ℯ^(-norm(p)^2)) for p in wfc_grid]))

@test dot(px_orb_dn, px_orb_up) ≈ 0.0
@test DFW.calc_spin(px_orb_up, px_orb_up) ≈ DFW.Point3(0.0 + 0im, 0.0+0.0im, 0.5 + 0.0im)

@test norm(DFW.calc_dip(px_orb, py_orb)) < 1e-17
@test norm(DFW.calc_dip(px_orb_up, px_orb_dn)) < 1e-17


text:
# JSONFile.jl

using JSON, DataStructures

import Base: ==, getindex
import Base: length, filesize, start, next, done, parse, open, push!, keys, values, map, endof
export JSONFile, save, @json_str

type JSONFile <: AbstractFile
  path::AbstractString
  data::Any
  JSONFile(path) = new(path, nothing)
end

type JSONFileIO
  file::JSONFile
  isdirty::Bool
end

function support(filename::AbstractString, ::Type{Val{symbol(".json")}})
  JSONFile(filename)
end

macro json_str(data::AbstractString)
  JSON.parse(data)
end

function ==(a::JSONFile, b::JSONFile)
  a.path == b.path
end

function parse(file::JSONFile)
  if nothing == file.data
    file.data = JSON.parsefile(file.path, dicttype=DataStructures.OrderedDict)
  end
  file.data
end

function open(fn::Function, file::JSONFile)
  parse(file)
  io = JSONFileIO(file, false)
  fn(io)
  if io.isdirty
    save(file, io.file.data)
  end
end

function save(file::JSONFile, data)
  f = open(file.path, "w")
  write(f, JSON.json(data))
  close(f)
end

function push!(file::JSONFile, data::Any)
  open(file) do io
    push!(io, data)
  end
end

function push!(io::JSONFileIO, data::Any)
  if isa(io.file.data, AbstractArray)
    push!(io.file.data, data)
    io.isdirty = true
  elseif isa(io.file.data, Associative)
    if isa(data, Pair)
      setindex!(io.file.data, data.second, string(data.first))
      io.isdirty = true
    end
  else
    # error
  end
end

map(fn::Function, file::JSONFile) = map(fn, parse(file))

length(file::JSONFile) = length(parse(file))
filesize(file::JSONFile) = filesize(file.path)

# indexing
getindex(file::JSONFile, a::Any) = getindex(parse(file), a)

# iterators
start(f::JSONFile) = start(parse(f))
next(file::JSONFile, i) = next(parse(file), i)
done(file::JSONFile, i) = done(parse(file), i)
endof(file::JSONFile) = endof(parse(file))

# dict
keys(file::JSONFile) = collect(keys(parse(file)))
values(file::JSONFile) = collect(values(parse(file)))


text:
# FF 2015 scrap

module FantasyFootball

  # Exports
  export Season,
         filter,
         score

  # Sources
  include("season.jl")

end

max_stars_repo_name: jnu/FantasyFootball

max_issues_repo_name: jnu/FantasyFootball

max_forks_repo_name: jnu/FantasyFootball


text:
test_str = "F10
N3
F7
R90
F11"

test_list = split(test_str, '\n')

list = readlines("day12_input.txt")

function navigate(list)
    instructions = map(x -> (x[1], parse(Int, x[2:end])), list)
    direction_table = Dict('N' => (0,1), 'S' => (0,-1), 'E' => (1,0), 'W' => (-1,0))
    rotate_right = Dict('N' => 'E', 'E' => 'S', 'S' => 'W', 'W' => 'N')
    rotate_left = Dict('N' => 'W', 'W' => 'S', 'S' => 'E', 'E' => 'N')
    heading = 'E'
    pos = (0,0) # (W-E, S-N) with negative values being W or S and positive, E and N
    for (i,v) in instructions
        if i in "NESW"
            pos = pos .+ (v .* direction_table[i])
        elseif i == 'F'
            pos = pos .+ (v .* direction_table[heading])
        elseif i == 'R'
            for j in 1:div(v, 90)
                heading = rotate_right[heading]
            end
        elseif i == 'L'
            for j in 1:div(v, 90)
                heading = rotate_left[heading]
            end
        end
    end
    return sum(abs.(pos))
end

@show navigate(test_list)
@show navigate(list)
@show navigate(test_list) == 25
@show navigate(list) == 2270

function navigate_waypoint(list)
    instructions = map(x -> (x[1], parse(Int, x[2:end])), list)
    direction_table = Dict('N' => (0,1), 'S' => (0,-1), 'E' => (1,0), 'W' => (-1,0))
    waypoint = (10,1)
    pos = (0,0) # (W-E, S-N) with negative values being W or S and positive, E and N
    for (i,v) in instructions
        if i in "NESW"
            waypoint = waypoint .+ (v .* direction_table[i])
        elseif i == 'F'
            pos = pos .+ (v .* waypoint)
        elseif i == 'R'
            for j in 1:div(v, 90)
                waypoint = (waypoint[2], -waypoint[1])
            end
        elseif i == 'L'
            for j in 1:div(v, 90)
                waypoint = (-waypoint[2], waypoint[1])
            end
        end
    end
    return sum(abs.(pos))
end

@show navigate_waypoint(test_list)
@show navigate_waypoint(list)
@show navigate_waypoint(test_list) == 286
@show navigate_waypoint(list) == 138669

nothing

# Counting ocurrences:
#=
```julia
ulia> count(in("NSEW"), join([i for (i,v) in instructions]))
408

julia> count(==("F"), join([i for (i,v) in instructions]))
0

julia> count(==('F'), join([i for (i,v) in instructions]))
206

julia> count(==('R'), join([i for (i,v) in instructions]))
99
```
 =#
#=
# Timings
```julia
 julia> @btime navigate(test_list)
  1.672 μs (13 allocations: 1.75 KiB)
25

julia> @btime navigate(list)
  126.258 μs (809 allocations: 39.02 KiB)
2270

julia> @btime navigate_waypoint(test_list)
  1.176 μs (5 allocations: 832 bytes)
286

julia> @btime navigate_waypoint(list)
  122.945 μs (801 allocations: 38.08 KiB)
138669
```

# P.S.: I could modify part1 `navigate` to treat `heading` like `waypoint`
# and implement the rotations as done for part1, but I will just leave it
# like that.
=#


text:
@varset Data begin
    x
    y
    z
    xend
    yend
    xmin
    xmax
    ymin
    ymax
    width
    xintercept
    yintercept
    intercept
    slope
    middle
    lower_hinge
    upper_hinge
    lower_fence
    upper_fence
    xgroup
    ygroup
    xtick
    ytick
    xtick_labels
    ytick_labels
    xlim
    ylim
    xviewmin
    xviewmax
    yviewmin
    yviewmax
    size
    shape
    linestyle
    xsize
    ysize
    color
    group
    label
    alpha
    func
    titles, Dict{Symbol, AbstractString}, Dict{Symbol, AbstractString}()
end

# Calculating fieldnames at runtime is expensive
const data_fields = fieldnames(Data)

# Produce a new Data instance chaining the values of one or more others.
#
# The bound values in the returned Data instance are chain iterators which will
# iterate through the values contained in all the given Data instances.
#
# Args:
#  ds: Some Data instances.
#
# Returns:
#   A new Data instance.
#
function chain(ds::Data...)
    chained_data = Data()
    for name in data_fields
        vs = Any[getfield(d, name) for d in ds]
        vs = Any[v for v in filter(issomething, vs)]
        if isempty(vs)
            setfield!(chained_data, name, nothing)
        else
            setfield!(chained_data, name, flatten(vs))
        end
    end

    chained_data
end

function show(io::IO, data::Data)
    maxlen = 0
    print(io, "Data(")
    for name in data_fields
        if getfield(data, name) != nothing
            print(io, "\n  ", string(name), "=")
            show(io, getfield(data, name))
        end
    end
    print(io, "\n)\n")
end


text:
using Test

import PySCF: get_4idx

@testset "Indexing functions" begin
   @test get_4idx(1,2,3,4) == 38
end

include("test_scf.jl")
include("test_mp2.jl")
include("test_ccsd.jl")
include("test_properties.jl")


text:
# this function makes sure that the number of examples in each class are the same
function equalize_inputs(train_X::Array{Float32,2}, train_Y::Array{Int,2}, num_classes)
    train_X_len = size(train_X)[2]
    train_Y_len = size(train_Y)[2]
    @assert train_X_len == train_Y_len
    len = train_X_len

    class_counter = zeros(Int, num_classes)
    for i in 1:len
        class_counter[train_Y[1, i]+1] += 1
    end
    println("Total entries for each class: ", class_counter)
    max_per_class = minimum(class_counter)

    new_train_X = Array{Float32, 2}(undef, size(train_X)[1], min(train_X_len, max_per_class*num_classes))
    new_train_Y = Array{Float32, 2}(undef, size(train_Y)[1], min(train_Y_len, max_per_class*num_classes))

    counters = zeros(Int, num_classes)
    iter = 1
    new_counter = 1
    while (iter < len) && any(counters .< max_per_class) # Exits when all of the counters are more than the max limit
#         println(counters, new_counter)
        if counters[train_Y[1, iter]+1] < max_per_class
            counters[train_Y[1, iter]+1] += 1
            new_train_X[:, new_counter] = train_X[:, iter]
            new_train_Y[:, new_counter] = train_Y[:, iter]
            new_counter += 1
        end
        iter += 1
    end
    println("Counters: ", counters)
    println("Total entries added: ", new_counter)
    println("Total entries checked: ", iter)
    return new_train_X, new_train_Y
end

# Example usage:
# new_train_X, new_train_Y = equalize_inputs(train_X, train_Y, 2)


text:
using FaultTolerantControl
const FTC = FaultTolerantControl
using LinearAlgebra
using Transducers
using Plots

function test()
    multicopter = LeeHexacopterEnv()
    τ = 0.2
    fdi = DelayFDI(τ)
    index = 1
    faults = FaultSet(LoE(5.0, index, 0.5))
    env = FTC.DelayFDI_Plant(multicopter, fdi, faults)
    x0 = State(env)()
    tf = 10.0
    prob, df = sim(x0,
                   apply_inputs(Dynamics!(env); u=zeros(6));
                   savestep=0.01,
                   tf=tf)
    ts = df.time
    _Λs_index = df.FDI |> Map(datum -> diag(datum.Λ)[index]) |> collect
    _Λ̂s_index = df.FDI |> Map(datum -> diag(datum.Λ̂)[index]) |> collect
    # plot
    p = plot()
    plot!(ts, hcat(_Λs_index...)'; label="true")
    plot!(ts, hcat(_Λ̂s_index...)'; label="estimated")
end


text:
# This file is a part of ValueShapes.jl, licensed under the MIT License (MIT).

"""
    varshape(d::Distributions.Distribution)::AbstractValueShape

Get the value shape of the variates of distribution `d`.
"""
varshape(d::Distribution{Univariate}) = ScalarShape{Real}()
@static if isdefined(Distributions, :ArrayLikeVariate)
    varshape(d::Distribution{<:ArrayLikeVariate}) = ArrayShape{Real}(size(d)...)
else
    varshape(d::Distribution{Multivariate}) = ArrayShape{Real}(size(d)...)
    varshape(d::Distribution{Matrixvariate}) = ArrayShape{Real}(size(d)...)
end

@deprecate valshape(d::Distribution) varshape(d)

"""
    vardof(d::Distributions.Distribution)

Get the number of degrees of freedom of the variates of distribution `d`.
Equivalent to `totalndof(varshape(d))`.
"""
vardof(d::Distribution) = totalndof(varshape(d))

"""
    unshaped(d::Distributions.Distribution)

Turns `d` into a `Distributions.Distribution{Multivariate}` based on
`varshape(d)`.
"""
function unshaped(d::UnivariateDistribution)
    # ToDo: Replace with `reshape(d, 1)` when result of `reshape(::UnivariateDistribution, 1)`
    # becomes fully functional in Distributions:
    Distributions.Product(Fill(d, 1))
end

_unshaped_uv_pullback(ΔΩ) = NoTangent(), only(unthunk(ΔΩ).v)
ChainRulesCore.rrule(::typeof(unshaped), d::UnivariateDistribution) = unshaped(d), _unshaped_uv_pullback

unshaped(d::Distribution{Multivariate}) = d

@static if isdefined(Distributions, :ReshapedDistribution)
    unshaped(d::Distribution{<:ArrayLikeVariate}) = reshape(d, length(d))
else
    unshaped(d::MatrixReshaped) = d.d
end

@static if isdefined(Distributions, :ArrayLikeVariate)
    const PlainVariate = ArrayLikeVariate
else
    const PlainVariate = Union{Univariate,Multivariate,Matrixvariate}
end

struct StructVariate{T} <: VariateForm end

const NamedTupleVariate{names} = StructVariate{NamedTuple{names}}  # ToDo: Use StructVariate{<:NamedTuple{names}} instead?

function _rand_flat_impl(rng::AbstractRNG, d::Distribution{NamedTupleVariate{names}}) where names
    shape = varshape(d)
    X = Vector{default_unshaped_eltype(shape)}(undef, totalndof(varshape(d)))
    (shape, rand!(rng, unshaped(d), X))
end

function Random.rand(rng::AbstractRNG, d::Distribution{NamedTupleVariate{names}}) where names
    shape, X = _rand_flat_impl(rng, d)
    shape(X)
end

function Random.rand(rng::AbstractRNG, d::Distribution{NamedTupleVariate{names}}, dims::Tuple{}) where names
    shape, X = _rand_flat_impl(rng, d)
    shape.(Fill(X))
end

function Random.rand(rng::AbstractRNG, d::Distribution{NamedTupleVariate{names}}, dims::Dims) where names
    shape = varshape(d)
    X_flat = Array{default_unshaped_eltype(shape)}(undef, totalndof(varshape(d)), dims...)
    X = ArrayOfSimilarVectors(X_flat)
    rand!(rng, unshaped(d), X)
    shape.(X)
end

function Random.rand!(d::Distribution{NamedTupleVariate{names}}, x::ShapedAsNT{names}) where names
    rand!(Random.default_rng(), d, x)
end

function Random.rand!(rng::AbstractRNG, d::Distribution{NamedTupleVariate{names}}, x::ShapedAsNT{names}) where names
    valshape(x) >= varshape(d) || throw(ArgumentError("Shapes of variate and value are not compatible"))
    rand!(rng, unshaped(d), unshaped(x))
    x
end

function _aov_rand_impl!(rng::AbstractRNG, d::Distribution{Multivariate}, X::ArrayOfSimilarVectors{<:Real})
    rand!(rng, unshaped(d), flatview(X))
end

# Workaround for current limitations of ArraysOfArrays.unshaped for standard arrays of vectors
function _aov_rand_impl!(rng::AbstractRNG, d::Distribution{Multivariate}, X::AbstractArray{<:AbstractVector{<:Real}})
    rand!.(Ref(rng), Ref(unshaped(d)), X)
end

function Random.rand!(rng::AbstractRNG, d::Distribution{<:NamedTupleVariate}, X::ShapedAsNTArray)
    elshape(X) >= varshape(d) || throw(ArgumentError("Shapes of variate and value are not compatible"))
    _aov_rand_impl!(rng, unshaped(d), unshaped.(X))
    X
end

function Distributions.logpdf(d::Distribution{NamedTupleVariate{names}}, x::NamedTuple{names}) where names
    logpdf(unshaped(d), unshaped(x, varshape(d)))
end

function Distributions.logpdf(d::Distribution{NamedTupleVariate{names}}, x::ShapedAsNT{names}) where names
    @argcheck valshape(x) <= varshape(d)
    logpdf(unshaped(d), unshaped(x))
end

function Distributions.logpdf(d::Distribution{NamedTupleVariate{names}}, x::AbstractArray{<:NamedTuple{names},0}) where names
    logpdf(unshaped(d), unshaped(x, varshape(d)))
end

function Distributions.pdf(d::Distribution{NamedTupleVariate{names}}, x::NamedTuple{names}) where names
    pdf(unshaped(d), unshaped(x, varshape(d)))
end

function Distributions.pdf(d::Distribution{NamedTupleVariate{names}}, x::ShapedAsNT{names}) where names
    @argcheck valshape(x) <= varshape(d)
    pdf(unshaped(d), unshaped(x))
end

function Distributions.pdf(d::Distribution{NamedTupleVariate{names}}, x::AbstractArray{<:NamedTuple{names},0}) where names
    pdf(unshaped(d), unshaped(x, varshape(d)))
end

function Distributions.insupport(d::Distribution{NamedTupleVariate{names}}, x::NamedTuple{names}) where names
    insupport(unshaped(d), unshaped(x, varshape(d)))
end

function Distributions.insupport(d::Distribution{NamedTupleVariate{names}}, x::ShapedAsNT{names}) where names
    @argcheck valshape(x) <= varshape(d)
    insupport(unshaped(d), unshaped(x))
end

function Distributions.insupport(d::Distribution{NamedTupleVariate{names}}, x::AbstractArray{<:NamedTuple{names},0}) where names
    insupport(unshaped(d), unshaped(x, varshape(d)))
end

function Distributions.insupport(d::Distribution{NamedTupleVariate{names}}, X::AbstractArray{<:NamedTuple{names},N}) where {N,names}
    Distributions.insupport!(BitArray(undef, size(X)), d, X)
end

function Distributions.insupport!(r::AbstractArray{Bool,N}, d::Distribution{NamedTupleVariate{names}}, X::AbstractArray{<:NamedTuple{names},N}) where {N,names}
    r .= insupport.(Ref(d), X)
end


text:
global dfg,v1,v2,f1

if typeof(dfg) <: CloudGraphsDFG
    @warn "TEST: Removing all data for user '$(dfg.userId)'!"
    clearUser!!(dfg)
    createDfgSessionIfNotExist(dfg)
end

# Building simple graph...
@testset "Building a simple Graph" begin
    global dfg,v1,v2,f1
    # Use IIF to add the variables and factors
    v1 = addVariable!(dfg, :a, ContinuousScalar, tags = [:POSE], solvable=0)
    v2 = addVariable!(dfg, :b, ContinuousScalar, tags = [:LANDMARK], solvable=1)
    f1 = addFactor!(dfg, [:a; :b], LinearRelative(Normal(50.0,2.0)), solvable=0)

    @show dfg
    @show f1
    @show v1
end

println()
println()

#test before anything changes
@testset "Producing Dot Files" begin
    global dfg
    @show todotstr = toDot(dfg)
    #TODO consider using a regex, but for now test all orders
    todota = cmp(todotstr, "graph graphname {\n2 [\"label\"=\"a\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n2 -- 3\n3 [\"label\"=\"abf1\",\"shape\"=\"box\",\"fillcolor\"=\"blue\",\"color\"=\"blue\"]\n1 [\"label\"=\"b\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n1 -- 3\n}\n") |> abs
    todotb = cmp(todotstr, "graph graphname {\n2 [\"label\"=\"b\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n2 -- 3\n3 [\"label\"=\"abf1\",\"shape\"=\"box\",\"fillcolor\"=\"blue\",\"color\"=\"blue\"]\n1 [\"label\"=\"a\",\"shape\"=\"ellipse\",\"fillcolor\"=\"red\",\"color\"=\"red\"]\n1 -- 3\n}\n") |> abs
    todotc = cmp(todotstr, "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box];\na -- abf1\nb -- abf1\n}\n") |> abs
    todotd = cmp(todotstr, "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box];\nb -- abf1\na -- abf1\n}\n") |> abs
    todote = cmp(todotstr, "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\na -- abf1\nb -- abf1\n}\n") |> abs
    todotf = cmp(todotstr, "graph G {\na [color=red, shape=ellipse];\nb [color=red, shape=ellipse];\nabf1 [color=blue, shape=box, fontsize=8, fixedsize=false, height=0.1, width=0.1];\nb -- abf1\na -- abf1\n}\n") |> abs
    @show todota, todotb, todotc, todotd, todote, todotf
    @test (todota < 1 || todotb < 1 || todotc < 1 || todotd < 1 || todote < 1 || todotf < 1)
    @test toDotFile(dfg, "something.dot") === nothing
    Base.rm("something.dot")
end

@testset "Testing CRUD, return and Failures from a LightDFG" begin
    global dfg
    # dfg to copy to
    # creating a whole new graph with the same labels
    T = typeof(dfg)
    if dfg isa CloudGraphsDFG
        #TODO
        dfg2 = CloudGraphsDFG(solverParams=SolverParams(), userId="testUserId")
    else
        dfg2 = T(solverParams=SolverParams(), userId="testUserId")
    end

    # Build a new in-memory IIF graph to transfer into the new graph.
    iiffg = initfg()
    v1 = deepcopy(addVariable!(iiffg, :a, ContinuousScalar))
    v2 = deepcopy(addVariable!(iiffg, :b, ContinuousScalar))
    v3 = deepcopy(addVariable!(iiffg, :c, ContinuousScalar))
    f1 = deepcopy(addFactor!(iiffg, [:a; :b], LinearRelative(Normal(50.0,2.0)) ))
    f2 = deepcopy(addFactor!(iiffg, [:b; :c], LinearRelative(Normal(10.0,1.0)) ))

    # Add it to the new graph.
    @test addVariable!(dfg2, v1) == v1
    @test addVariable!(dfg2, v2) == v2
    @test @test_logs (:warn, r"exist") match_mode=:any updateVariable!(dfg2, v3) == v3
    @test_throws ErrorException addVariable!(dfg2, v3)
    @test addFactor!(dfg2, [v1, v2], f1) == f1
    @test_throws ErrorException addFactor!(dfg2, [v1, v2], f1)
    # @test @test_logs (:warn, r"exist") updateFactor!(dfg2, f2) == f2
    @test updateFactor!(dfg2, f2) == f2
    @test_throws ErrorException addFactor!(dfg2, [:b, :c], f2)

    dv3, dv3facs = deleteVariable!(dfg2, v3)
    #TODO write compare if we want to compare complete one, for now just label
    # @test dv3 == v3
    @test dv3.label == v3.label
    @test_throws ErrorException deleteVariable!(dfg2, v3)

    @test issetequal(ls(dfg2),[:a,:b])
    df2 = dv3facs[1]
    #TODO write compare if we want to compare complete one, for now just label
    # @test df2 == f2
    @test df2.label == f2.label
    @test_throws ErrorException deleteFactor!(dfg2, f2)

    @test lsf(dfg2) == [:abf1]

end

@testset "Listing Nodes" begin
    global dfg,v1,v2,f1
    @test length(ls(dfg)) == 2
    @test length(lsf(dfg)) == 1 # Unless we add the prior!
    @test symdiff([:a, :b], listVariables(dfg)) == []
    @test listFactors(dfg) == [:abf1] # Unless we add the prior!
    # Additional testing for https://github.com/JuliaRobotics/DistributedFactorGraphs.jl/issues/201
    @test symdiff([:a, :b], listVariables(dfg, solvable=0)) == []
    @test listVariables(dfg, solvable=1) == [:b]
    @test map(v->v.label, getVariables(dfg, solvable=1)) == [:b]
    @test listFactors(dfg) == [:abf1]
    @test listFactors(dfg, solvable=1) == []
    @test listFactors(dfg, solvable=0) == [:abf1]
    @test map(f->f.label, getFactors(dfg, solvable=0)) == [:abf1]
    @test map(f->f.label, getFactors(dfg, solvable=1)) == []
    #
    @test lsf(dfg, :a) == [f1.label]
    # Tags
    @test ls(dfg, tags=[:POSE]) == [:a]
    @test symdiff(ls(dfg, tags=[:POSE, :LANDMARK]), ls(dfg, tags=[:VARIABLE])) == []
    # Regexes
    @test ls(dfg, r"a") == [v1.label]
    # TODO: Check that this regular expression works on everything else!
    # it works with the .
    # REF: https://stackoverflow.com/questions/23834692/using-regular-expression-in-neo4j
    @test lsf(dfg, r"abf.*") == [f1.label]

    # Accessors
    @test getAddHistory(dfg) == [:a, :b] #, :abf1
    @test getDescription(dfg) != nothing
    #TODO Deprecate
    # @test_throws ErrorException getLabelDict(dfg)
    # Existence
    @test exists(dfg, :a) == true
    @test exists(dfg, v1) == true
    @test exists(dfg, :nope) == false
    # isFactor and isVariable
    @test isFactor(dfg, f1.label)
    @test !isFactor(dfg, v1.label)
    @test isVariable(dfg, v1.label)
    @test !isVariable(dfg, f1.label)
    @test !isVariable(dfg, :doesntexist)
    @test !isFactor(dfg, :doesntexist)

    @test issetequal([:a,:b], listVariables(dfg))
    @test issetequal([:abf1], listFactors(dfg))

    # @test @test_deprecated getVariableIds(dfg) == listVariables(dfg)
    # @test @test_deprecated getFactorIds(dfg) == listFactors(dfg)

    @test getFactorType(f1.solverData) === f1.solverData.fnc.usrfnc!
    @test getFactorType(f1) === f1.solverData.fnc.usrfnc!
    @test getFactorType(dfg, :abf1) === f1.solverData.fnc.usrfnc!

    @test !isPrior(dfg, :abf1) # f1 is not a prior
    @test lsfPriors(dfg) == []
    #FIXME don't know what it is supposed to do
    @test_broken lsfTypes(dfg)

    @test ls(dfg, LinearRelative) == [:abf1]
    @test lsf(dfg, LinearRelative) == [:abf1]
    @test lsfWho(dfg, :LinearRelative) == [:abf1]

    @test getVariableType(v1) isa ContinuousScalar
    @test getVariableType(dfg,:a) isa ContinuousScalar

    #TODO what is lsTypes supposed to return?
    @test_broken lsTypes(dfg)

    @test issetequal(ls(dfg, ContinuousScalar), [:a, :b])

    @test issetequal(lsWho(dfg, :ContinuousScalar),[:a, :b])

    varNearTs = findVariableNearTimestamp(dfg, now())
    @test_skip varNearTs[1][1]  == [:b]

end

# Gets
@testset "Gets, Sets, and Accessors" begin
    global dfg,v1,v2,f1
    @test getVariable(dfg, v1.label) == v1
    @test getFactor(dfg, f1.label) == f1
    @test_throws Exception getVariable(dfg, :nope)
    @test_throws Exception getVariable(dfg, "nope")
    @test_throws Exception getFactor(dfg, :nope)
    @test_throws Exception getFactor(dfg, "nope")

    # Sets
    v1Prime = deepcopy(v1)
    @test updateVariable!(dfg, v1Prime) == v1 #Maybe move to crud
    @test updateVariable!(dfg, v1Prime) == getVariable(dfg, v1.label)
    f1Prime = deepcopy(f1)
    @test updateFactor!(dfg, f1Prime) == f1 #Maybe move to crud
    @test updateFactor!(dfg, f1Prime) == getFactor(dfg, f1.label)

    # Accessors
    @test getLabel(v1) == v1.label
    @test getTags(v1) == v1.tags
    @test getTimestamp(v1) == v1.timestamp
    @test getVariablePPEDict(v1) == v1.ppeDict
    @test_throws Exception DistributedFactorGraphs.getVariablePPE(v1, :notfound)
    @test getSolverData(v1) === v1.solverDataDict[:default]
    @test getSolverData(v1) === v1.solverDataDict[:default]
    @test getSolverData(v1, :default) === v1.solverDataDict[:default]
    @test getSolverDataDict(v1) == v1.solverDataDict
    # legacy compat test
    @test getVariablePPEDict(v1) == v1.ppeDict # changed to .ppeDict -- delete by DFG v0.7

    @test typeof(getVariableType(v1)) == ContinuousScalar
    @test typeof(getVariableType(v2)) == ContinuousScalar
    @test typeof(getVariableType(v1)) == ContinuousScalar

    @test getLabel(f1) == f1.label
    @test getTags(f1) == f1.tags
    @test getSolverData(f1) == f1.solverData

    @test getSolverParams(dfg) != nothing
    @test setSolverParams!(dfg, getSolverParams(dfg)) == getSolverParams(dfg)

    #solver data is initialized
    @test !isInitialized(dfg, :a)
    @test !isInitialized(v2)

    @test !isInitialized(v2, :second)

    # Session, robot, and user small data tests
    # NOTE: CloudGraphDFG isnt supporting this yet.
    smallUserData = Dict{Symbol, String}(:a => "42", :b => "Hello")
    smallRobotData = Dict{Symbol, String}(:a => "43", :b => "Hello")
    smallSessionData = Dict{Symbol, String}(:a => "44", :b => "Hello")
    setUserData!(dfg, deepcopy(smallUserData))
    setRobotData!(dfg, deepcopy(smallRobotData))
    setSessionData!(dfg, deepcopy(smallSessionData))
    @test getUserData(dfg) == smallUserData
    @test getRobotData(dfg) == smallRobotData
    @test getSessionData(dfg) == smallSessionData

end

@testset "Data Entries" begin
    # NOTE: CloudGraphDFG isnt supporting this yet.
    if !(typeof(dfg) <: CloudGraphsDFG)
        oid = zeros(UInt8,12); oid[12] = 0x01
        de1 = MongodbDataEntry(:key1, uuid4(), NTuple{12,UInt8}(oid), "", now(localzone()))

        oid = zeros(UInt8,12); oid[12] = 0x02
        de2 = MongodbDataEntry(:key2, uuid4(), NTuple{12,UInt8}(oid), "", now(localzone()))

        oid = zeros(UInt8,12); oid[12] = 0x03
        de2_update = MongodbDataEntry(:key2, uuid4(), NTuple{12,UInt8}(oid), "", now(localzone()))

        #add
        v1 = getVariable(dfg, :a)
        @test addDataEntry!(v1, de1) == de1
        @test addDataEntry!(dfg, :a, de2) == de2
        @test_throws ErrorException addDataEntry!(v1, de1)
        @test de2 in getDataEntries(v1)

        #get
        @test deepcopy(de1) == getDataEntry(v1, :key1)
        @test deepcopy(de2) == getDataEntry(dfg, :a, :key2)
        @test_throws ErrorException getDataEntry(v2, :key1)
        @test_throws ErrorException getDataEntry(dfg, :b, :key1)

        #update
        @test updateDataEntry!(dfg, :a, de2_update) == de2_update
        @test deepcopy(de2_update) == getDataEntry(dfg, :a, :key2)
        @test @test_logs (:warn, r"does not exist") match_mode=:any updateDataEntry!(dfg, :b, de2_update) == de2_update

        #list
        entries = getDataEntries(dfg, :a)
        @test length(entries) == 2
        @test issetequal(map(e->e.label, entries), [:key1, :key2])
        @test length(getDataEntries(dfg, :b)) == 1

        @test issetequal(listDataEntries(dfg, :a), [:key1, :key2])
        @test listDataEntries(dfg, :b) == Symbol[:key2]

        #delete
        @test deleteDataEntry!(v1, :key1) == de1
        @test listDataEntries(v1) == Symbol[:key2]
        #delete from ddfg
        @test deleteDataEntry!(dfg, :a, :key2) == de2_update
        @test listDataEntries(v1) == Symbol[]
    end
end

@testset "Updating Nodes and Estimates" begin
    global dfg
    #get the variable
    var1 = getVariable(dfg, :a)
    #make a copy and simulate external changes
    newvar = deepcopy(var1)
    getVariablePPEDict(newvar)[:default] = MeanMaxPPE(:default, [150.0], [100.0], [50.0])
    mergeVariableData!(dfg, newvar)

    #Check if variable is updated
    var1 = getVariable(dfg, :a)
    @test getVariablePPEDict(newvar) == getVariablePPEDict(var1)

    # Add a new estimate.
    getVariablePPEDict(newvar)[:second] = MeanMaxPPE(:second, [15.0], [10.0], [5.0])

    # Confirm they're different
    @test getVariablePPEDict(newvar) != getVariablePPEDict(var1)
    # Persist it.
    mergeVariableData!(dfg, newvar)
    # Get the latest
    var1 = getVariable(dfg, :a)
    @test symdiff(collect(keys(getVariablePPEDict(var1))), [:default, :second]) == Symbol[]

    #Check if variable is updated
    @test getVariablePPEDict(newvar) == getVariablePPEDict(var1)

    # Delete :default and replace to see if new ones can be added
    delete!(getVariablePPEDict(newvar), :default)
    #confirm delete
    @test symdiff(collect(keys(getVariablePPEDict(newvar))), [:second]) == Symbol[]
    # Persist it., and test
    mergeVariableData!(dfg, newvar)  #357 #358

    # Get the latest and confirm they're the same, :second
    var1 = getVariable(dfg, :a)

    # TODO issue #166
    @test getVariablePPEDict(newvar) != getVariablePPEDict(var1)
    @test collect(keys(getVariablePPEDict(var1))) ==  [:default, :second]

    # @test symdiff(collect(keys(getVariablePPE(getVariable(dfg, :a)))), [:default, :second]) == Symbol[]
end

# Connectivity test
@testset "Connectivity Test" begin
    global dfg,v1,v2,f1
    if !(typeof(dfg) <: CloudGraphsDFG)
        @test isConnected(dfg) == true
        # @test @test_deprecated isFullyConnected(dfg) == true
        # @test @test_deprecated hasOrphans(dfg) == false
        addVariable!(dfg, :orphan, ContinuousScalar, tags = [:POSE], solvable=0)
        @test isConnected(dfg) == false
    else
        addVariable!(dfg, :orphan, ContinuousScalar, tags = [:POSE], solvable=0)
        @warn "CloudGraphsDFG is currently failing with the connectivity test."
    end
end

# Adjacency matrices
@testset "Adjacency Matrices" begin
    global dfg,v1,v2,f1

    # Normal
    adjMat = DistributedFactorGraphs.getAdjacencyMatrixSymbols(dfg)
    @test size(adjMat) == (2,4)
    @test symdiff(adjMat[1, :], [nothing, :a, :b, :orphan]) == Symbol[]
    @test symdiff(adjMat[2, :], [:abf1, :abf1, :abf1, nothing]) == Symbol[]

    #sparse
    adjMat, v_ll, f_ll = getBiadjacencyMatrix(dfg)
    @test size(adjMat) == (1,3)

    # Checking the elements of adjacency, its not sorted so need indexing function
    indexOf = (arr, el1) -> findfirst(el2->el2==el1, arr)
    @test adjMat[1, indexOf(v_ll, :orphan)] == 0
    @test adjMat[1, indexOf(v_ll, :a)] == 1
    @test adjMat[1, indexOf(v_ll, :b)] == 1
    @test symdiff(v_ll, [:a, :b, :orphan]) == Symbol[]
    @test symdiff(f_ll, [:abf1, :abf1, :abf1]) == Symbol[]

    # Filtered - REF DFG #201
    adjMat, v_ll, f_ll = getBiadjacencyMatrix(dfg, solvable=1)
    @test size(adjMat) == (0,1)

    # sparse
    adjMat, v_ll, f_ll = getBiadjacencyMatrix(dfg, solvable=1)
    @test size(adjMat) == (0,1)
    @test issetequal(v_ll, [:b])
    @test f_ll == []
end

# Deletions
@testset "Deletions" begin
    deleteFactor!(dfg, :abf1)
    @test listFactors(dfg) == []
    deleteVariable!(dfg, :b)
    @test symdiff([:a, :orphan], listVariables(dfg)) == []
    #delete last also for the LightGraphs implementation coverage
    deleteVariable!(dfg, :orphan)
    @test symdiff([:a], listVariables(dfg)) == []
    deleteVariable!(dfg, :a)
    @test listVariables(dfg) == []
end

# Now make a complex graph for connectivity tests
numNodes = 10
#the deletions in last test should have cleared out the dfg
# dfg = DistributedFactorGraphs._getDuplicatedEmptyDFG(dfg)
# if typeof(dfg) <: CloudGraphsDFG
#     clearSession!!(dfg)
# end

#change solvable and solveInProgress for x7,x8 for improved tests on x7x8f1
verts = map(n -> addVariable!(dfg, Symbol("x$n"), ContinuousScalar, tags = [:POSE]), 1:numNodes)
#TODO fix this to use accessors
setSolvable!(verts[7], 1)
setSolvable!(verts[8], 0)
getSolverData(verts[8]).solveInProgress = 1
#call update to set it on cloud
updateVariable!(dfg, verts[7])
updateVariable!(dfg, verts[8])

facts = map(n ->
    addFactor!(dfg, [verts[n], verts[n+1]], LinearRelative(Normal(50.0,2.0)),solvable=0), 1:(numNodes-1))

@testset "Getting Neighbors" begin
    global dfg,verts
    # Trivial test to validate that intersect([], []) returns order of first parameter
    @test intersect([:x3, :x2, :x1], [:x1, :x2]) == [:x2, :x1]
    # Get neighbors tests
    @test getNeighbors(dfg, verts[1]) == [:x1x2f1]
    neighbors = getNeighbors(dfg, getFactor(dfg, :x1x2f1))
    @test neighbors == [:x1, :x2]
    # Testing aliases
    @test getNeighbors(dfg, getFactor(dfg, :x1x2f1)) == ls(dfg, getFactor(dfg, :x1x2f1))
    @test getNeighbors(dfg, :x1x2f1) == ls(dfg, :x1x2f1)

    # solvable checks
    @test getNeighbors(dfg, :x5, solvable=1) == Symbol[]
    @test symdiff(getNeighbors(dfg, :x5, solvable=0), [:x4x5f1,:x5x6f1]) == []
    @test symdiff(getNeighbors(dfg, :x5),[:x4x5f1,:x5x6f1]) == []
    @test getNeighbors(dfg, :x7x8f1, solvable=0) == [:x7, :x8]
    @test getNeighbors(dfg, :x7x8f1, solvable=1) == [:x7]
    @test getNeighbors(dfg, verts[1], solvable=0) == [:x1x2f1]
    @test getNeighbors(dfg, verts[1], solvable=1) == Symbol[]
    @test getNeighbors(dfg, verts[1]) == [:x1x2f1]

end

#TODO make sure similar testing exists then delete
# @testset "Getting Subgraphs" begin
#     # Subgraphs
#     dfgSubgraph = getSubgraphAroundNode(dfg, verts[1], 2)
#     # Only returns x1 and x2
#     @test symdiff([:x1, :x1x2f1, :x2], [ls(dfgSubgraph)..., lsf(dfgSubgraph)...]) == []
#     # Test include orphan factorsVoid
#     @test_broken begin
#         dfgSubgraph = getSubgraphAroundNode(dfg, verts[1], 1, true)
#         @test symdiff([:x1, :x1x2f1], [ls(dfgSubgraph)..., lsf(dfgSubgraph)...]) == []
#         # Test adding to the dfg
#         dfgSubgraph = getSubgraphAroundNode(dfg, verts[1], 2, true, dfgSubgraph)
#         @test symdiff([:x1, :x1x2f1, :x2], [ls(dfgSubgraph)..., lsf(dfgSubgraph)...]) == []
#     end
#     dfgSubgraph = getSubgraph(dfg,[:x1, :x2, :x1x2f1])
#     # Only returns x1 and x2
#     @test symdiff([:x1, :x1x2f1, :x2], [ls(dfgSubgraph)..., lsf(dfgSubgraph)...]) == []
#
#     @test_broken begin
#         # DFG issue #201 Test include orphan factors with filtering - should only return x7 with solvable=1
#         dfgSubgraph = getSubgraphAroundNode(dfg, getFactor(dfg, :x7x8f1), 1, true, solvable=0)
#         @test symdiff([:x7, :x8, :x7x8f1], [ls(dfgSubgraph)..., lsf(dfgSubgraph)...]) == []
#         # Filter - always returns the node you start at but filters around that.
#         dfgSubgraph = getSubgraphAroundNode(dfg, getFactor(dfg, :x7x8f1), 1, true, solvable=1)
#         @test symdiff([:x7x8f1, :x7], [ls(dfgSubgraph)..., lsf(dfgSubgraph)...]) == []
#     end
#     # DFG issue #95 - confirming that getSubgraphAroundNode retains order
#     # REF: https://github.com/JuliaRobotics/DistributedFactorGraphs.jl/issues/95
#     for fId in listVariables(dfg)
#         # Get a subgraph of this and it's related factors+variables
#         dfgSubgraph = getSubgraphAroundNode(dfg, verts[1], 2)
#         # For each factor check that the order the copied graph == original
#         for fact in getFactors(dfgSubgraph)
#             @test fact._variableOrderSymbols == getFactor(dfg, fact.label)._variableOrderSymbols
#         end
#     end
# end

@testset "Summaries and Summary Graphs" begin
    factorFields = fieldnames(DFGFactorSummary)
    variableFields = fieldnames(DFGVariableSummary)

    summary = getSummary(dfg)
    @test symdiff(collect(keys(summary.variables)), ls(dfg)) == Symbol[]
    @test symdiff(collect(keys(summary.factors)), lsf(dfg)) == Symbol[]

    summaryGraph = getSummaryGraph(dfg)
    @test symdiff(ls(summaryGraph), ls(dfg)) == Symbol[]
    @test symdiff(lsf(summaryGraph), lsf(dfg)) == Symbol[]
    # Check all fields are equal for all variables
    for v in ls(summaryGraph)
        for field in variableFields
            if field != :variableTypeName
                @test getproperty(getVariable(dfg, v), field) == getfield(getVariable(summaryGraph, v), field)
            else
                # Special case to check the symbol variableType is equal to the full variableType.
                @test Symbol(typeof(getVariableType(getVariable(dfg, v)))) == getVariableTypeName(getVariable(summaryGraph, v))
            end
        end
    end
    for f in lsf(summaryGraph)
        for field in factorFields
            @test getproperty(getFactor(dfg, f), field) == getfield(getFactor(summaryGraph, f), field)
        end
    end

end


text:
"""
The following is based on RFC 1951 at:
https://www.ietf.org/rfc/rfc1951.txt

I found the RFC to very confusing until I read:
http://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art001

Even this was confusing, so I'm including more information in this tutorial.
"""

"""
As an example we'll be working with the file gunzip.c.gz

gz stands for gzip, which is a file format that uses the DEFLATE compression algorithm
https://en.wikipedia.org/wiki/Gzip

Some key lingo:
1. GZIP - file format that uses DEFLATE
2. ZIP - different file format that often uses DEFLATE
3. DEFLATE - compression format which we'll be learning about below

When I first got started I was under the impression that the actual data for
GZIP files (.gz extension) always started at byte 11 (1 based). This is not true and for this particular file the actual compressed data starts at byte 20.

** For this file all byte numberings will be 1 based **

Important Numbers:
1. 20 - first byte in the compressed stream
2. 8 - # of bytes at the end of a gzip file
3. 4704 - # of bytes in this file
4. 4696 - last byte in the stream
"""