text:
"""

```
wrap_to_cell_fraction(x,unit_cell_matrix)
```

Obtaint the coordinates of `x` as a fraction of unit cell vectors, first
positive cell. `x` is a vector of dimension `N` and `cell` a matrix of
dimension `NxN`

### Example

```
julia> unit_cell_matrix = [ 10 0
                            0 10 ];

julia> x = [ 15, 13 ];

julia> wrap_to_cell_fraction(x,unit_cell_matrix)
2-element Vector{Float64}:
 0.5
 0.3
```

"""
@inline function wrap_cell_fraction(x,unit_cell_matrix)
  p = mod.(unit_cell_matrix\x,1)
  p = @. ifelse(p < 0, p + 1, p)
  return p
end

"""

```
wrap_to_first(x,unit_cell_matrix)
```

Wraps the coordinates of point `x` such that the returning coordinates are in the
first unit cell with all-positive coordinates.

### Example

```
julia> unit_cell_matrix = [ 10 0
                            0 10 ];

julia> x = [ 15, 13 ];

julia> wrap_to_first(x,unit_cell_matrix)
2-element Vector{Float64}:
 5.0
 3.0000000000000004
 ```

"""
@inline function wrap_to_first(x,unit_cell_matrix)
  p = wrap_cell_fraction(x,unit_cell_matrix)
  return unit_cell_matrix*p
end

"""

```
wrap_to_first(x,box::Box)
```

Wraps the coordinates of point `x` such that the returning coordinates are in the
first unit cell with all-positive coordinates, given the `Box` structure.

"""
@inline wrap_to_first(x,box::Box) = wrap_to_first(x,box.unit_cell.matrix)

"""

```
wrap_to_first(x,box::Box{OrthorhombicCell,N,T}) where {N,T}
```

Wraps the coordinates of point `x` such that the returning coordinates are in the
first unit cell with all-positive coordinates, given an Orthorhombic cell.
This is slightly cheaper than for general cells.

"""
@inline function wrap_to_first(x,box::Box{OrthorhombicCell,N,T}) where {N,T}
  sides = SVector{N,T}(ntuple(i->box.unit_cell.matrix[i,i],N))
  x = mod.(x,sides)
  x = @. ifelse(x < 0, x + sides, x)
  return x
end

"""

```
wrap_relative_to(x, xref, unit_cell_matrix::SMatrix{N,N,T}) where {N,T}
```

Wraps the coordinates of point `x` such that it is the minimum image relative to `xref`.

"""
@inline function wrap_relative_to(x, xref, unit_cell_matrix::SMatrix{N,N,T}) where {N,T}
  x_f = wrap_cell_fraction(x,unit_cell_matrix)
  xref_f = wrap_cell_fraction(xref,unit_cell_matrix)
  xw = wrap_relative_to(x_f,xref_f,SVector{N,T}(ntuple(i->1,N)))
  return unit_cell_matrix * (xw - xref_f) + xref
end

"""

```
wrap_relative_to(x,xref,box::Box{UnitCellType,N,T}) where {UnitCellType,N,T}
```

Wraps the coordinates of point `x` such that it is the minimum image relative to `xref`,
given a general `Box` structure.

"""
@inline wrap_relative_to(x,xref,box::Box{UnitCellType,N,T}) where {UnitCellType,N,T} =
  wrap_relative_to(x,xref,box.unit_cell.matrix)

"""

```
wrap_relative_to(x,xref,box::Box{OrthorhombicCell,N,T}) where {N,T}
```

Wraps the coordinates of point `x` such that it is the minimum image relative to `xref`,
given an Orthorhombic cell. This is slightly cheaper than for general cells.

"""
@inline function wrap_relative_to(x,xref,box::Box{OrthorhombicCell,N,T}) where {N,T}
  sides = SVector{N,T}(ntuple(i->box.unit_cell.matrix[i,i],N))
  return wrap_relative_to(x,xref,sides)
end

"""

```
wrap_relative_to(x,xref,sides::AbstractVector)
```

Wraps the coordinates of point `x` such that it is the minimum image relative to `xref`,
for an Orthorhombic cell of which only the side lengths are provided.

"""
@inline function wrap_relative_to(x,xref,sides::AbstractVector)
  xw = mod.(x-xref,sides)
  xw = _wrap_single_coordinate.(xw,sides)
  return xw + xref
end

#
# Wrap a single coordinate
#
@inline function _wrap_single_coordinate(x,s)
  if x >= s/2
    x = x - s
  elseif x < -s/2
    x = x + s
  end
  return x
end

"""

```
translation_image(x::SVector{N,T},unit_cell_matrix,indices) where {N,T}
```

Translate vector `x` according to the `unit_cell_matrix` lattice vectors and the `indices`
provided.

"""
@inline translation_image(x::SVector{N,T},unit_cell_matrix,indices) where {N,T} =
  x + unit_cell_matrix*SVector{N,T}(ntuple(i -> indices[i],N))

"""

```
neighbour_cells(box::Box{UnitCellType,N}) where UnitCellType
```

Function that returns the iterator of the cartesian indices of the cells that must be
evaluated (forward, i. e. to avoid repeated interactions)
if the cells have sides of length `box.cell_size`. `N` can be
`2` or `3`, for two- or three-dimensional systems.

"""
function neighbour_cells(box::Box{UnitCellType,3}) where UnitCellType
  @unpack lcell = box
  nb = Iterators.flatten((
    CartesianIndices((1:lcell,-lcell:lcell,-lcell:lcell)),
    CartesianIndices((0:0,1:lcell,-lcell:lcell)),
    CartesianIndices((0:0,0:0,1:lcell))
  ))
  return nb
end

function neighbour_cells(box::Box{UnitCellType,2}) where UnitCellType
  @unpack lcell = box
  nb = Iterators.flatten((
    CartesianIndices((1:lcell,-lcell:lcell)),
    CartesianIndices((0:0,1:lcell))
  ))
  return nb
end

"""

```
neighbour_cells_all(box::Box{UnitCellType,N}) where N
```

Function that returns the iterator of the cartesian indices of all neighbouring
cells of a cell if the cells have sides of `box.cell_size`. `N` can be
`2` or `3`, for two- or three-dimensional systems.

"""
function neighbour_cells_all(box::Box{UnitCellType,3}) where UnitCellType
  @unpack lcell = box
  return CartesianIndices((-lcell:lcell,-lcell:lcell,-lcell:lcell))
end

function neighbour_cells_all(box::Box{UnitCellType,2}) where UnitCellType
  @unpack lcell = box
  return CartesianIndices((-lcell:lcell,-lcell:lcell))
end

"""

```
particle_cell(x::SVector{N,T}, box::Box) where {N,T}
```

Returns the coordinates of the *computing cell* to which a particle belongs, given its coordinates
and the `cell_size` vector. The computing box is always Orthorhombic, and the first
computing box with positive coordinates has indexes `Box.lcell + 1`.

"""
@inline particle_cell(x::SVector{N}, box::Box) where N =
  CartesianIndex(ntuple(i -> floor(Int,x[i]/box.cell_size[i]) + box.lcell + 1, N))

"""

```
cell_center(c::CartesianIndex{N},box::Box{UnitCellType,N,T}) where {UnitCellType,N,T}
```

Computes the geometric center of a computing cell, to be used in the projection
of points. Returns a `SVector{N,T}`

"""
@inline cell_center(c::CartesianIndex{N},box::Box{UnitCellType,N,T}) where {UnitCellType,N,T} =
  SVector{N,T}(ntuple(i -> box.cell_size[i]*(c[i] - 0.5 - box.lcell), N))

"""

```
cell_cartesian_indices(nc::SVector{N,Int}, i1D) where {N}
```

Given the linear index of the cell in the cell list, returns the cartesian indices
of the cell (for arbitrary dimension N).

"""
@inline cell_cartesian_indices(nc::SVector{N,Int}, i1D) where N =
  CartesianIndices(ntuple(i -> nc[i],N))[i1D]

"""

```
cell_linear_index(nc::SVector{N,Int}, indices) where N
```

Returns the index of the cell, in the 1D representation, from its cartesian coordinates.

"""
@inline cell_linear_index(nc::SVector{N,Int}, indices) where N =
  LinearIndices(ntuple(i -> nc[i],N))[ntuple(i->indices[i],N)...]

"""

```
out_of_bounding_box(x::SVector{N},box::Box) where N
```

Function that evaluates if a particle is outside the computing bounding box,
defined by the maximum and minimum unit cell coordinates.

"""
function out_of_bounding_box(x::SVector{N},box::Box) where N
  @unpack cutoff, unit_cell_max = box
  for i in 1:N
    (x[i] < -cutoff) && return true
    (x[i] >= unit_cell_max[i]+cutoff) && return true
  end
  return false
end
out_of_bounding_box(p::ParticleWithIndex,box::Box) =
  out_of_bounding_box(p.coordinates,box)

"""

```
replicate_particle!(ip,p::SVector{N},box,cl) where N
```

Replicates the particle as many times as necessary to fill the computing box.

"""
function replicate_particle!(ip,p::SVector{N},box,cl) where N
  itr = Iterators.product(ntuple(i->box.ranges[i],N)...)
  for indexes in itr
    (count(isequal(0),indexes) == N) && continue
    x = translation_image(p,box.unit_cell.matrix,indexes)
    if ! out_of_bounding_box(x,box)
      cl = add_particle_to_celllist!(ip,x,box,cl;real_particle=false)
    end
  end
  return cl
end

"""

```
check_unit_cell(box::Box)
```

Checks if the unit cell satisfies the conditions for using the minimum-image
convention, with the same criteria used gy Gromacs.

"""
check_unit_cell(box::Box) = check_unit_cell(box.unit_cell.matrix,box.cutoff)

function check_unit_cell(unit_cell_matrix::SMatrix{3},cutoff;printerr=true)
  a = @view(unit_cell_matrix[:,1])
  b = @view(unit_cell_matrix[:,2])
  c = @view(unit_cell_matrix[:,3])
  check = true

  if size(unit_cell_matrix) != (3,3)
    printerr && println("UNIT CELL CHECK FAILED: unit cell matrix must have dimenions (3,3).")
    check = false
  end

  if count(el -> el < 0, unit_cell_matrix) != 0
    printerr && println("UNIT CELL CHECK FAILED: unit cell matrix components be strictly positive.")
    check = false
  end

  bc = cross(b,c)
  bc = bc / norm(bc)
  aproj = dot(a,bc)

  ab = cross(a,b)
  ab = ab / norm(ab)
  cproj = dot(c,ab)

  ca = cross(c,a)
  ca = ca / norm(ca)
  bproj = dot(b,ca)

  if (aproj < 2*cutoff) || (bproj < 2*cutoff) || (cproj < 2*cutoff)
    printerr && println("UNIT CELL CHECK FAILED: distance between cell planes too small relative to cutoff.")
    check = false
  end

  return check
end

function check_unit_cell(unit_cell_matrix::SMatrix{2},cutoff;printerr=true)
  a = @view(unit_cell_matrix[:,1])
  b = @view(unit_cell_matrix[:,2])
  check = true

  if size(unit_cell_matrix) != (2,2)
    printerr && println("UNIT CELL CHECK FAILED: unit cell matrix must have dimenions (2,2).")
    check = false
  end

  if count(el -> el < 0, unit_cell_matrix) != 0
    printerr && println("UNIT CELL CHECK FAILED: unit cell matrix components must be strictly positive.")
    check = false
  end

  i = a / norm(a)
  bproj = sqrt(norm_sqr(b) - dot(b,i)^2)

  j = b / norm(b)
  aproj = sqrt(norm_sqr(a) - dot(a,j)^2)

  if (aproj < 2*cutoff) || (bproj < 2*cutoff)
    printerr && println("UNIT CELL CHECK FAILED: distance between cell planes too small relative to cutoff.")
    check = false
  end

  return check
end

#
# The following functions are not being used anymore in CellListMap, but may
# be useful if this is split in into a sepparate package for playing with
# periodic systems.
#
"""

```
ranges_of_replicas(cell_size, lcell, nc, unit_cell_matrix::SMatrix{3,3,T}) where T
```

Function that sets which is the range of periodic images necessary to fill
the computing box, in 3D.

"""
function ranges_of_replicas(cell_size, lcell, nc, unit_cell_matrix::SMatrix{3,3,T}) where T
  V = SVector{3,T}
  cmin = -lcell*cell_size
  cmax = (nc .- lcell) .* cell_size
  cell_vertices = SVector{8,V}(
    V(   cmin[1],   cmin[2],   cmin[3] ),
    V(   cmin[1],   cmin[2],   cmax[3] ),
    V(   cmin[1],   cmax[2],   cmin[3] ),
    V(   cmin[1],   cmax[2],   cmax[3] ),
    V(   cmax[1],   cmin[2],   cmin[3] ),
    V(   cmax[1],   cmin[2],   cmax[3] ),
    V(   cmax[1],   cmax[2],   cmin[3] ),
    V(   cmax[1],   cmax[2],   cmax[3] )
  )
  r_min, r_max = _ranges_of_replicas(
    SVector{3,Int}(10^6,10^6,10^6), #min
    SVector{3,Int}(-1,-1,-1),       #max
    unit_cell_matrix,
    cell_vertices
  )
  ranges = SVector{3,UnitRange{Int}}(
    r_min[1]:r_max[1],
    r_min[2]:r_max[2],
    r_min[3]:r_max[3]
  )
  return ranges
end

"""

```
ranges_of_replicas(cell_size, lcell, nc, unit_cell_matrix::SMatrix{3,3,T}) where T
```

Function that sets which is the range of periodic images necessary to fill
the computing box, in 2D.

"""
function ranges_of_replicas(cell_size, lcell, nc,unit_cell_matrix::SMatrix{2,2,T}) where T
  V = SVector{2,T}
  cmin = -lcell*cell_size
  cmax = (nc .- lcell) .* cell_size
  cell_vertices = SVector{4,V}(
    V(   cmin[1],   cmin[2] ),
    V(   cmin[1],   cmax[2] ),
    V(   cmax[1],   cmin[2] ),
    V(   cmax[1],   cmax[2] ),
  )
  r_min, r_max = _ranges_of_replicas(
    SVector{2,Int}(10^6,10^6), #min
    SVector{2,Int}(-1,-1),     #max
    unit_cell_matrix,
    cell_vertices
  )
  ranges = SVector{2,UnitRange{Int}}(
    r_min[1]:r_max[1],
    r_min[2]:r_max[2]
  )
  return ranges
end

function _ranges_of_replicas(r_min,r_max,unit_cell,cell_vertices)
  for vert in cell_vertices
    r = unit_cell \ vert
    ri = @. ceil(Int,abs(r))
    for (i,el) in pairs(r)
      if el < 0
        @set! ri[i] = -ri[i]
      end
    end
    r_min = min.(ri,r_min)
    r_max = max.(ri,r_max)
  end
  return r_min, r_max
end


text:
module DevilSpawn

import Base.Threads

"""
    @spawn_background expr

Like `@spawn`, but ensures that the spawned task isn't scheduled on the main thread, except
if `nthreads() == 1`, in which case this is equivalent to `@async`.

If all background threads are currently blocked, we retry until one becomes available using
a small exponential backoff. A `yield()` call or automatically placed yield point will free
up the thread and allow another task to be scheduled.

If all background threads are currently busy, this Task will block, retrying until one
becomes available using a small exponential backoff. A `yield()` call in one of the other
threads or an automatically placed yield point will eventually free up a thread, and allow
this task to be scheduled.
"""
macro spawn_background(exprs...)
    esc(quote
        $Threads.@spawn $spawn_background(()->$(exprs...))
    end)
end

function spawn_background(f, attempt_num=0)
    if Threads.threadid() == 1 && Threads.nthreads() > 1
        # Out of concern that we might build up a bunch of tasks, all clamoring to schedule
        # on main while we wait for an availabl thread, we use a very small exponential
        # backoff between scheduling attempts. We keep this very fast, so that it shouldn't
        # contribute noticable latency, but will help to prevent many enqueued tasks from
        # burning CPU while they wait.
        sleep(1E-9 * (1 << min(32, attempt_num)))
        # Maintain demand on the new Task, so that errors will propagate.
        return fetch(Threads.@spawn spawn_background(f, attempt_num+1))
    else
        f()
    end
end

export @spawn_background

end # module

ext: jl


text:
import Revise
import GLRenderer as GL
import ThreeDP3 as T
import Images as I
import MiniGSG as S
import Rotations as R
import PoseComposition: Pose
using Gen
import Serialization
import MeshCatViz

import MeshCatViz
MeshCatViz.setup_visualizer()

YCB_DIR = "/home/nishadg/mcs/ThreeDVision.jl/data/ycbv2"
world_scaling_factor = 100.0
id_to_cloud, id_to_shift, id_to_box  = T.load_ycbv_models_adjusted(YCB_DIR, world_scaling_factor);
all_ids = sort(collect(keys(id_to_cloud)));

# +
IDX =6
# IDX =301
IDX =2100
IDX =100

@show T.get_ycb_scene_frame_id_from_idx(YCB_DIR,IDX)

# +
gt_poses, ids, gt_rgb_image, gt_depth_image, cam_pose, camera = T.load_ycbv_scene_adjusted(
    YCB_DIR, IDX, world_scaling_factor, id_to_shift
);
dense_poses, dense_ids = T.load_ycbv_dense_fusion_predictions_adjusted(YCB_DIR, IDX, world_scaling_factor, id_to_shift);
dense_poses_reordered = [dense_poses[findfirst(dense_ids .== id)]   for id in ids];
inf_poses = Serialization.deserialize("../assets/results/$(lpad(IDX,4,"0")).poses").poses_after
inf_poses = T.adjust_poses(inf_poses, ids, world_scaling_factor, id_to_shift)

img = I.colorview(I.Gray, gt_depth_image ./ maximum(gt_depth_image))
I.colorview(I.RGB, permutedims(Float64.(gt_rgb_image)./255.0, (3,1,2)))
# -

I.colorview(I.RGB, permutedims(Float64.(gt_rgb_image)./255.0, (3,1,2)))

# +
resolution = 0.5

renderer = GL.setup_renderer(camera, GL.RGBMode())
for id in all_ids
    cloud = id_to_cloud[id]
    v,n,f = GL.mesh_from_voxelized_cloud(GL.voxelize(cloud, resolution), resolution)
    GL.load_object!(renderer, v, n, f)
end

colors = [
    I.colorant"yellow", I.colorant"cyan", I.colorant"lightgreen",
    I.colorant"red", I.colorant"purple", I.colorant"orange"
]
# -

ids

new_poses = copy(gt_poses)
new_poses = [T.get_c_relative_to_a(cam_pose,p) for p in new_poses]
old_pose = new_poses[1]
new_poses[1] = Pose(old_pose.pos .- [0,0,2.0],old_pose.orientation)

renderer.gl_instance.lightpos = cam_pose.pos

rgb_image_dense, depth_image = GL.gl_render(
    renderer, ids, new_poses, colors, cam_pose)
rgb_image_dense= I.colorview(I.RGBA, permutedims(rgb_image_dense,(3,1,2)))

import Plots

import Pkg;Pkg.add("Measures")

using Measures

low, high = 56.0, 130.0
d = clamp.(depth_image, low, high)
@show minimum(d), maximum(d)
p = Plots.heatmap(d; c=:thermal,
    clim=(53.0, 130.0),
    ylim=(0, 480),
    xlim=(0, 640),
    aspect_ratio=:equal, yflip=true,  legend = :none, yticks=false, xticks=false, xaxis=false, yaxis=false, margin = 0mm)
Plots.savefig(p, "regen.pdf")
p

d = clamp.(gt_depth_image,low, high)
@show minimum(d), maximum(d)
p = Plots.heatmap(d; c=:thermal,
    clim=(53.0, 130.0),
    ylim=(0, 480),
    xlim=(0, 640),
    aspect_ratio=:equal, yflip=true,  legend = :none, yticks=false, xticks=false, xaxis=false, yaxis=false, margin = 0mm)
Plots.savefig(p, "real.pdf")
p

# +
focus_idx = 3
alpha = 0.4

rgb_image_dense, depth_image = GL.gl_render(
    renderer_color, [ids[focus_idx]], [dense_poses_reordered[focus_idx]], [I.colorant"cyan"], T.IDENTITY_POSE)
rgb_image_dense= I.colorview(I.RGBA, permutedims(rgb_image_dense,(3,1,2)))

new_gt_rgb_image = cat(Float64.(gt_rgb_image) ./ 255.0, ones(size(gt_rgb_image)[1:2]),dims=3)
new_gt_rgb_image = I.colorview(I.RGBA, permutedims(new_gt_rgb_image,(3,1,2)))
@show size(new_gt_rgb_image)
mask = (rgb_image_dense .!= I.RGBA(1.0, 1.0, 1.0, 1.0))
new_gt_rgb_image[mask] .= alpha.*new_gt_rgb_image[mask] +(1-alpha).*rgb_image_dense[mask]
new_gt_rgb_image
# +

rgb_image_3dp3, depth_image = GL.gl_render(
    renderer_color, [ids[focus_idx]], [inf_poses[focus_idx]], [I.colorant"limegreen"], T.IDENTITY_POSE)
rgb_image_3dp3= I.colorview(I.RGBA, permutedims(rgb_image_3dp3,(3,1,2)))

new_gt_rgb_image = cat(Float64.(gt_rgb_image) ./ 255.0, ones(size(gt_rgb_image)[1:2]),dims=3)
new_gt_rgb_image = I.colorview(I.RGBA, permutedims(new_gt_rgb_image,(3,1,2)))
@show size(new_gt_rgb_image)
@show size(rgb_image_3dp3)
mask = (rgb_image_3dp3 .!= I.RGBA(1.0, 1.0, 1.0, 1.0))
new_gt_rgb_image[mask] .= alpha.*new_gt_rgb_image[mask] +(1-alpha).*rgb_image_3dp3[mask]
new_gt_rgb_image
# -


text:
struct StaticEnvironmentalLayer end

function MetacommunityDynamics.generate(
    ::Type{StaticEnvironmentalLayer},
    grid::Array{T,2},
    dist::Distribution;
    mask = nothing,
) where {T<:Number}

    n, m = size(grid)

    for i = 1:n
        for j = 1:m
            if isnothing(mask) || !isnothing(mask) && .!mask[i, j]
                grid[i, j] = rand(dist)
            end
        end
    end

    return grid
end


text:
# include("../utilities.jl")

module linalg

using LinearAlgebra # for triu/l
# using ..util

# =========================================================================== #
# Level 1 Vector Vector
# =========================================================================== #

# scalar + vector
# scalar * vector
# elementwise vector vector
# vector + scalar * vector
# norm2
# dot prod

function blas_update_add!(a, x)
    # x <- a + x
    @inbounds @simd for ii = eachindex(x)
        @fastmath x[ii] += a
    end

    return x
end

function blas_add!(y, a, x)
    # x <- a + x
    @inbounds @simd for ii = eachindex(x)
        @fastmath y[ii] = x[ii] + a
    end

    return x
end

function blas_update_scale!(a, x)
    # x <- a * x
    @inbounds @simd for ii = eachindex(x)
        @fastmath x[ii] *= a
    end

    return x
end

function blas_scale!(y, a, x)
    # y <- a * x
    @inbounds @simd for ii = eachindex(x)
        @fastmath y[ii] = x[ii] * a
    end

    return y
end

function blas_elementwise_scale!(y, x)
    # y <- yi * xi
    @inbounds @simd for ii = eachindex(y)
        @fastmath y[ii] *= x[ii]
    end
end

function blas_update_scale_add!(y, a, x)
    # y <- y + a * x
    @inbounds @simd for ii = eachindex(y) #
    # Threads.@threads for ii = eachindex(y)
        @fastmath y[ii] += x[ii] * a # @fastmath
    end

    return x
end

function blas_norm2(x)
    s = zero(Float64);

    @inbounds @simd for ii = eachindex(x)
        @fastmath s += x[ii] * x[ii]
    end

    return sqrt(s)
end

function blas_dot_prod(x, y)
    d = zero(Float64)
    @inbounds @simd for ii = eachindex(x)
        @fastmath d += x[ii] * y[ii]
    end
    return d
end

# =========================================================================== #
# Level 2 - Matrix Vector
# =========================================================================== #

# matrix vector prod
# M + a * v * v' rank one update
# M + a * u * v' rank two update

function blas_matrixview_update_scale_add!(y, a, mat, col)
    # y <- y + a * mat[:, col]
    @inbounds @simd for ii = 1:size(mat,1)
        @fastmath y[ii] += mat[ii, col] * a
    end

    return y
end

function blas_matrix_vector_prod(mat, x)
    # y <- A * x

    (n_row, n_col) = size(mat);

    y = zeros(n_row)
    @inbounds for cc = 1:n_col
		y = blas_matrixview_update_scale_add!(y, x[cc], mat, cc)
    end

	return y;

end

# =========================================================================== #
# Level 3 - Matrix Matrix
# =========================================================================== #

# matrix matrix prod

function blas_matrix_matrix_prod(A, B)
    # C <- A * B

    (n_row, n_inner) = size(A);
    n_col = size(B,2);

    C = zeros(n_row, n_col)
    @inbounds for cc = 1:n_col
        # y = zeros(n_row)
        @inbounds for icc = 1:n_inner
            # C[:, cc] = blas_matrixview_update_scale_add!(C[:, cc], B[icc, cc], A, icc)
            # y = blas_matrixview_update_scale_add!(y, B[icc, cc], A, icc)
            blas_matrixview_update_scale_add!( @view(C[:, cc]) , B[icc, cc], A, icc)
        end
        # C[:,cc] = y
    end

	return C;

end

#=
function saxpy_matrixview(scalar, mat, col, y)
    # y <- y + scalar * mat[:, col]
	# unsafe, dimensions are not checked
	@inbounds @simd for ii = 1:size(y, 1) #
		@fastmath y[ii] += scalar * mat[ii, col];
        # y[ii] += scalar * mat[ii, col];
    end
    return y
end

function matrix_vector_prod(mat, vec)

	n_row = size(mat, 1);
	n_col = size(mat, 2);

    #=
	res = Vector{eltype(vec)}(undef, n_row);
	@inbounds @simd for rr = 1:n_row
		@fastmath res[rr] = mat[rr, 1] * vec[1];
    end

	# @inbounds Threads.@threads for cc = 1:n_col
    @inbounds for cc = 2:n_col
		res = saxpy_matrixview(vec[cc], mat, cc, res);
    end

    =#

    res = zeros(n_row)
    @inbounds for cc = 1:n_col
		res = saxpy_matrixview(vec[cc], mat, cc, res);
    end

	return res;
end
=#

end # linalg

module ltest

using ..linalg
using LinearAlgebra
using BenchmarkTools

function test_blas_update_scale_add!()
    n = 10
    y = zeros(n)
    x = collect(1:n)
    a = 10

    n = 100_000_000 # 1_000_000_000 -> doesnt fit into the memory!!!
    y = rand(n)
    x = rand(n)
    a = rand()

    # y_theo = x .* a .+ y

    @time linalg.blas_update_scale_add!(y, a, x)

    # println( all( (y_theo - y) .<= 1e-16 ) )

end

function benchmark_blas_update_scale_add!(y, a, x)

    b_ = @benchmark linalg.blas_update_scale_add!($y, $a, $x)

    println("=== blas_update_scale_add! ===")
    show(
            stdout,
            MIME("text/plain"),
            b_ )
    println("\n\n")
end

function benchmark_blas_update_scale_add_default(y, a, x)
    # b_ = @benchmark $y = $y .+ $a .* $x;
    b_ = @benchmark $y .+= $a .* $x;

    println("=== blas_update_scale_add_default ===")
    show(
            stdout,
            MIME("text/plain"),
            b_ )
    println("\n\n")
end

function benchmark_blas_update_scale_add_all()
    n = 1_000_000 # for 10_000_000 ~10ms
    y = rand(n)
    x = rand(n)
    a = rand()

    benchmark_blas_update_scale_add!(y, a, x)
    benchmark_blas_update_scale_add_default(y, a, x)
end

function test_matrix_vector_prod()

    mat = reshape( collect(0:14), (5,3) )
    vec = collect(1:3)

    x_theo = mat * vec

    x_mine = linalg.blas_matrix_vector_prod(mat, vec)

    println("norm dx: $(norm(x_theo - x_mine))" )

end

function benchmark_matrix_vector_prod()

    n_row = 1000 # 100000;
	n_col = 100000 # 1000;

    mat = rand(n_row, n_col)
    vec = rand(n_col)

    b_ = @benchmark linalg.blas_matrix_vector_prod($mat, $vec);

    println("=== matrix_vector_prod ===")
    show(
            stdout,
            MIME("text/plain"),
            b_ )
    println("\n\n")

    b_ = @benchmark $mat * $vec;

    println("=== matrix_vector_prod_default ===")
    show(
            stdout,
            MIME("text/plain"),
            b_ )
    println("\n\n")
end

function test_blas_matrix_matrix_prod()

    n_row = 100
    n_inner = 150000
    n_col = 500
    A = rand(n_row, n_inner)
    B = rand(n_inner, n_col)

    @time C = linalg.blas_matrix_matrix_prod(A, B)

    @time C_theo = A * B;

    dC = C_theo - C

    println( all( dC .<= 1e-10 )  )

end

function benchmark_blas_matrix_matrix_prod()

    linalg.blas_matrix_matrix_prod(A, B)

end

#=

function benchmark_linsolve_all()
    N = 6_00
    A = rand(N, N)
    A = diagm( diag(A) ) .+ A
    A = A .+ A'
    b = rand(N)

    benchmark_linsolve_lu(A, b)
    benchmark_linsolve_ldl(A, b)
    benchmark_linsolve_default(A, b)

end

function benchmark_linsolve_default(A, b)
    b_ = @benchmark $A \ $b

    println("=== benchmark_linsolve_default ===")
    show(
            stdout,
            MIME("text/plain"),
            b_ )
    println("\n\n")
end
=#

end # ltest

max_stars_repo_name: HomoModelicus/julia

max_issues_repo_name: HomoModelicus/julia

max_forks_repo_name: HomoModelicus/julia


text:
function spelled_out_ru(number::Number)

end


text:
using Test

function _timed_include(file)
    println("Testing ", file)
    start = time()
    include(file)
    run_time = round(time() - start, digits=1)
    println("    Took $(run_time) seconds")
end

@testset "$(file)" for file in ["bridge_optimizer.jl", "lazy_bridge_optimizer.jl"]
    _timed_include(file)
end
@testset "Variable bridges" begin
    variable_dir = joinpath(@__DIR__, "Variable")
    @testset "$(file)" for file in readdir(variable_dir)
        _timed_include(joinpath(variable_dir, file))
    end
end
@testset "Constraint bridges" begin
    constraint_dir = joinpath(@__DIR__, "Constraint")
    @testset "$(file)" for file in readdir(constraint_dir)
        _timed_include(joinpath(constraint_dir, file))
    end
end
@testset "Objective bridges" begin
    objective_dir = joinpath(@__DIR__, "Objective")
    @testset "$(file)" for file in readdir(objective_dir)
        _timed_include(joinpath(objective_dir, file))
    end
end


text:
# coding: utf-8

# In[1]:

#bloom filter is a space-efficient probabilistic data structure
#it is commonly used for query in large dataset
#the query can possibly return false positive matches but never false negative matches
#the workflow is very straight forward
#for each string in the database, it has to go through k number of hash functions
#k hash value would be allocated to the hashtable accordingly
#to make any query,the query string has to go through k number of hash functions as well
#if every underlying cell has been occupied in the hashtable
#the query returns positive matches

#fowler–noll–vo hash function
#pseudo code can be found in the link below
# https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1_hash
function fnv1(text,
              offset_basis=0xcbf29ce484222325,
              prime=0x100000001b3)

        hash_value=offset_basis
        for letter in text
            hash_value*=prime

            #for some unknown reasons,large int xor in julia is different from python
            hash_value=hash_value ⊻ codepoint(letter)

        end

        return hash_value

end

# In[2]:

#jenkins one at a time hash function
#pseudo code can be found in the link below
# https://en.wikipedia.org/wiki/Jenkins_hash_function#one_at_a_time
#actual code can be found in the link below
# https://stackoverflow.com/a/51730837
function one_at_a_time(text)

    hash_value=0

    for letter in text
        hash_value+=codepoint(letter)
        hash_value=hash_value & 0xFFFFFFFF
        hash_value+=hash_value<<10
        hash_value=hash_value & 0xFFFFFFFF
        hash_value=hash_value ⊻ hash_value>>6
        hash_value=hash_value & 0xFFFFFFFF
    end

    hash_value+=hash_value<<3
    hash_value=hash_value & 0xFFFFFFFF
    hash_value=hash_value ⊻ hash_value>>11
    hash_value=hash_value & 0xFFFFFFFF
    hash_value+=hash_value<<15
    hash_value=hash_value & 0xFFFFFFFF

    return hash_value

end

# In[3]:

#compute hash value from two different functions
#update the underlying cells in hashtable
function update_hashtable(text,hashtable,verbose=true)

    #use extra computation to shrink hashtable size
    fnv_hash=Int64(round(fnv1(text)^0.0625))
    jenkins_hash=Int64(round(one_at_a_time(text)^0.25))

    #prevent overflow
    if max(fnv_hash,jenkins_hash)<=hashtable_size

        #update hashtable
        hashtable[fnv_hash]=1
        hashtable[jenkins_hash]=1
        if verbose
            println("Hashtable updated.")
        end

    else
        if verbose
            println("Hash value exceeds hashtable size!")
        end
    end

    return hashtable

end

# In[4]:

#compute hash value from two different functions
#check the underlying cells in hashtable
function search_hashtable(text,hashtable)

    #use extra computation to shrink hashtable size
    fnv_hash=Int64(round(fnv1(text)^0.0625))
    jenkins_hash=Int64(round(one_at_a_time(text)^0.25))

    #check hashtable
    if hashtable[fnv_hash]==1 && hashtable[jenkins_hash]==1
        return true
    else
        return false
    end

end

# In[5]:

#initialize
hashtable_size=500
hashtable=[0 for _ in 1:hashtable_size];
update_list=["raison d'être","porte-voix","prêt-à-gouverner",
             "proxénétisme","hydroxychloroquine"];

# In[6]:

#update hashtable
for text in update_list
    hashtable=update_hashtable(text,hashtable)
end

# In[7]:

#true negative
println(search_hashtable("raison d’être",hashtable))
println(search_hashtable("raison d être",hashtable))
println(search_hashtable("raison d\"être",hashtable))

#true positive
println(search_hashtable("raison d'être",hashtable))

#false positive
println(search_hashtable("rajson d'être",hashtable))

max_stars_repo_path: bloom filter.jl

max_stars_repo_name: je-suis-tm/search-and-sort

max_issues_repo_path: bloom filter.jl

max_issues_repo_name: tattooday/search-and-sort

max_forks_repo_path: bloom filter.jl

max_forks_repo_name: tattooday/search-and-sort


text:
# Derived from http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types

using Compat

const MIMETYPES = Dict{Compat.UTF8String, Compat.UTF8String}()

MIMETYPES["application/andrew-inset"]="ez"
MIMETYPES["application/applixware"]="aw"
MIMETYPES["application/atom+xml"]="atom"
MIMETYPES["application/atomcat+xml"]="atomcat"
MIMETYPES["application/atomsvc+xml"]="atomsvc"
MIMETYPES["application/ccxml+xml"]="ccxml"
MIMETYPES["application/cdmi-capability"]="cdmia"
MIMETYPES["application/cdmi-container"]="cdmic"
MIMETYPES["application/cdmi-domain"]="cdmid"
MIMETYPES["application/cdmi-object"]="cdmio"
MIMETYPES["application/cdmi-queue"]="cdmiq"
MIMETYPES["application/cu-seeme"]="cu"
MIMETYPES["application/davmount+xml"]="davmount"
MIMETYPES["application/docbook+xml"]="dbk"
MIMETYPES["application/dssc+der"]="dssc"
MIMETYPES["application/dssc+xml"]="xdssc"
MIMETYPES["application/ecmascript"]="ecma"
MIMETYPES["application/emma+xml"]="emma"
MIMETYPES["application/epub+zip"]="epub"
MIMETYPES["application/exi"]="exi"
MIMETYPES["application/font-tdpfr"]="pfr"
MIMETYPES["application/gml+xml"]="gml"
MIMETYPES["application/gpx+xml"]="gpx"
MIMETYPES["application/gxf"]="gxf"
MIMETYPES["application/hyperstudio"]="stk"
MIMETYPES["application/inkml+xml"]="ink"
MIMETYPES["application/ipfix"]="ipfix"
MIMETYPES["application/java-archive"]="jar"
MIMETYPES["application/java-serialized-object"]="ser"
MIMETYPES["application/java-vm"]="class"
MIMETYPES["application/javascript"]="js"
MIMETYPES["application/json"]="json"
MIMETYPES["application/jsonml+json"]="jsonml"
MIMETYPES["application/lost+xml"]="lostxml"
MIMETYPES["application/mac-binhex40"]="hqx"
MIMETYPES["application/mac-compactpro"]="cpt"
MIMETYPES["application/mads+xml"]="mads"
MIMETYPES["application/marc"]="mrc"
MIMETYPES["application/marcxml+xml"]="mrcx"
MIMETYPES["application/mathematica"]="ma"
MIMETYPES["application/mathml+xml"]="mathml"
MIMETYPES["application/mbox"]="mbox"
MIMETYPES["application/mediaservercontrol+xml"]="mscml"
MIMETYPES["application/metalink+xml"]="metalink"
MIMETYPES["application/metalink4+xml"]="meta4"
MIMETYPES["application/mets+xml"]="mets"
MIMETYPES["application/mods+xml"]="mods"
MIMETYPES["application/mp21"]="m21"
MIMETYPES["application/mp4"]="mp4s"
MIMETYPES["application/msword"]="doc"
MIMETYPES["application/mxf"]="mxf"
MIMETYPES["application/octet-stream"]="bin"
MIMETYPES["application/oda"]="oda"
MIMETYPES["application/oebps-package+xml"]="opf"
MIMETYPES["application/ogg"]="ogx"
MIMETYPES["application/omdoc+xml"]="omdoc"
MIMETYPES["application/onenote"]="onetoc"
MIMETYPES["application/oxps"]="oxps"
MIMETYPES["application/patch-ops-error+xml"]="xer"
MIMETYPES["application/pdf"]="pdf"
MIMETYPES["application/pgp-encrypted"]="pgp"
MIMETYPES["application/pgp-signature"]="asc"
MIMETYPES["application/pics-rules"]="prf"
MIMETYPES["application/pkcs10"]="p10"
MIMETYPES["application/pkcs7-mime"]="p7m"
MIMETYPES["application/pkcs7-signature"]="p7s"
MIMETYPES["application/pkcs8"]="p8"
MIMETYPES["application/pkix-attr-cert"]="ac"
MIMETYPES["application/pkix-cert"]="cer"
MIMETYPES["application/pkix-crl"]="crl"
MIMETYPES["application/pkix-pkipath"]="pkipath"
MIMETYPES["application/pkixcmp"]="pki"
MIMETYPES["application/pls+xml"]="pls"
MIMETYPES["application/postscript"]="ai"
MIMETYPES["application/prs.cww"]="cww"
MIMETYPES["application/pskc+xml"]="pskcxml"
MIMETYPES["application/rdf+xml"]="rdf"
MIMETYPES["application/reginfo+xml"]="rif"
MIMETYPES["application/relax-ng-compact-syntax"]="rnc"
MIMETYPES["application/resource-lists+xml"]="rl"
MIMETYPES["application/resource-lists-diff+xml"]="rld"
MIMETYPES["application/rls-services+xml"]="rs"
MIMETYPES["application/rpki-ghostbusters"]="gbr"
MIMETYPES["application/rpki-manifest"]="mft"
MIMETYPES["application/rpki-roa"]="roa"
MIMETYPES["application/rsd+xml"]="rsd"
MIMETYPES["application/rss+xml"]="rss"
MIMETYPES["application/rtf"]="rtf"
MIMETYPES["application/sbml+xml"]="sbml"
MIMETYPES["application/scvp-cv-request"]="scq"
MIMETYPES["application/scvp-cv-response"]="scs"
MIMETYPES["application/scvp-vp-request"]="spq"
MIMETYPES["application/scvp-vp-response"]="spp"
MIMETYPES["application/sdp"]="sdp"
MIMETYPES["application/set-payment-initiation"]="setpay"
MIMETYPES["application/set-registration-initiation"]="setreg"
MIMETYPES["application/shf+xml"]="shf"
MIMETYPES["application/smil+xml"]="smi"
MIMETYPES["application/sparql-query"]="rq"
MIMETYPES["application/sparql-results+xml"]="srx"
MIMETYPES["application/srgs"]="gram"
MIMETYPES["application/srgs+xml"]="grxml"
MIMETYPES["application/sru+xml"]="sru"
MIMETYPES["application/ssdl+xml"]="ssdl"
MIMETYPES["application/ssml+xml"]="ssml"
MIMETYPES["application/tei+xml"]="tei"
MIMETYPES["application/thraud+xml"]="tfi"
MIMETYPES["application/timestamped-data"]="tsd"
MIMETYPES["application/vnd.3gpp.pic-bw-large"]="plb"
MIMETYPES["application/vnd.3gpp.pic-bw-small"]="psb"
MIMETYPES["application/vnd.3gpp.pic-bw-var"]="pvb"
MIMETYPES["application/vnd.3gpp2.tcap"]="tcap"
MIMETYPES["application/vnd.3m.post-it-notes"]="pwn"
MIMETYPES["application/vnd.accpac.simply.aso"]="aso"
MIMETYPES["application/vnd.accpac.simply.imp"]="imp"
MIMETYPES["application/vnd.acucobol"]="acu"
MIMETYPES["application/vnd.acucorp"]="atc"
MIMETYPES["application/vnd.adobe.air-application-installer-package+zip"]="air"
MIMETYPES["application/vnd.adobe.formscentral.fcdt"]="fcdt"
MIMETYPES["application/vnd.adobe.fxp"]="fxp"
MIMETYPES["application/vnd.adobe.xdp+xml"]="xdp"
MIMETYPES["application/vnd.adobe.xfdf"]="xfdf"
MIMETYPES["application/vnd.ahead.space"]="ahead"
MIMETYPES["application/vnd.airzip.filesecure.azf"]="azf"
MIMETYPES["application/vnd.airzip.filesecure.azs"]="azs"
MIMETYPES["application/vnd.amazon.ebook"]="azw"
MIMETYPES["application/vnd.americandynamics.acc"]="acc"
MIMETYPES["application/vnd.amiga.ami"]="ami"
MIMETYPES["application/vnd.android.package-archive"]="apk"
MIMETYPES["application/vnd.anser-web-certificate-issue-initiation"]="cii"
MIMETYPES["application/vnd.anser-web-funds-transfer-initiation"]="fti"
MIMETYPES["application/vnd.antix.game-component"]="atx"
MIMETYPES["application/vnd.apple.installer+xml"]="mpkg"
MIMETYPES["application/vnd.apple.mpegurl"]="m3u8"
MIMETYPES["application/vnd.aristanetworks.swi"]="swi"
MIMETYPES["application/vnd.astraea-software.iota"]="iota"
MIMETYPES["application/vnd.audiograph"]="aep"
MIMETYPES["application/vnd.blueice.multipass"]="mpm"
MIMETYPES["application/vnd.bmi"]="bmi"
MIMETYPES["application/vnd.businessobjects"]="rep"
MIMETYPES["application/vnd.chemdraw+xml"]="cdxml"
MIMETYPES["application/vnd.chipnuts.karaoke-mmd"]="mmd"
MIMETYPES["application/vnd.cinderella"]="cdy"
MIMETYPES["application/vnd.claymore"]="cla"
MIMETYPES["application/vnd.cloanto.rp9"]="rp9"
MIMETYPES["application/vnd.clonk.c4group"]="c4g"
MIMETYPES["application/vnd.cluetrust.cartomobile-config"]="c11amc"
MIMETYPES["application/vnd.cluetrust.cartomobile-config-pkg"]="c11amz"
MIMETYPES["application/vnd.commonspace"]="csp"
MIMETYPES["application/vnd.contact.cmsg"]="cdbcmsg"
MIMETYPES["application/vnd.cosmocaller"]="cmc"
MIMETYPES["application/vnd.crick.clicker"]="clkx"
MIMETYPES["application/vnd.crick.clicker.keyboard"]="clkk"
MIMETYPES["application/vnd.crick.clicker.palette"]="clkp"
MIMETYPES["application/vnd.crick.clicker.template"]="clkt"
MIMETYPES["application/vnd.crick.clicker.wordbank"]="clkw"
MIMETYPES["application/vnd.criticaltools.wbs+xml"]="wbs"
MIMETYPES["application/vnd.ctc-posml"]="pml"
MIMETYPES["application/vnd.cups-ppd"]="ppd"
MIMETYPES["application/vnd.curl.car"]="car"
MIMETYPES["application/vnd.curl.pcurl"]="pcurl"
MIMETYPES["application/vnd.dart"]="dart"
MIMETYPES["application/vnd.data-vision.rdz"]="rdz"
MIMETYPES["application/vnd.dece.data"]="uvf"
MIMETYPES["application/vnd.dece.ttml+xml"]="uvt"
MIMETYPES["application/vnd.dece.unspecified"]="uvx"
MIMETYPES["application/vnd.dece.zip"]="uvz"
MIMETYPES["application/vnd.denovo.fcselayout-link"]="fe_launch"
MIMETYPES["application/vnd.dna"]="dna"
MIMETYPES["application/vnd.dolby.mlp"]="mlp"
MIMETYPES["application/vnd.dpgraph"]="dpg"
MIMETYPES["application/vnd.dreamfactory"]="dfac"
MIMETYPES["application/vnd.ds-keypoint"]="kpxx"
MIMETYPES["application/vnd.dvb.ait"]="ait"
MIMETYPES["application/vnd.dvb.service"]="svc"
MIMETYPES["application/vnd.dynageo"]="geo"
MIMETYPES["application/vnd.ecowin.chart"]="mag"
MIMETYPES["application/vnd.enliven"]="nml"
MIMETYPES["application/vnd.epson.esf"]="esf"
MIMETYPES["application/vnd.epson.msf"]="msf"
MIMETYPES["application/vnd.epson.quickanime"]="qam"
MIMETYPES["application/vnd.epson.salt"]="slt"
MIMETYPES["application/vnd.epson.ssf"]="ssf"
MIMETYPES["application/vnd.eszigno3+xml"]="es3"
MIMETYPES["application/vnd.ezpix-album"]="ez2"
MIMETYPES["application/vnd.ezpix-package"]="ez3"
MIMETYPES["application/vnd.fdf"]="fdf"
MIMETYPES["application/vnd.fdsn.mseed"]="mseed"
MIMETYPES["application/vnd.fdsn.seed"]="seed"
MIMETYPES["application/vnd.flographit"]="gph"
MIMETYPES["application/vnd.fluxtime.clip"]="ftc"
MIMETYPES["application/vnd.framemaker"]="fm"
MIMETYPES["application/vnd.frogans.fnc"]="fnc"
MIMETYPES["application/vnd.frogans.ltf"]="ltf"
MIMETYPES["application/vnd.fsc.weblaunch"]="fsc"
MIMETYPES["application/vnd.fujitsu.oasys"]="oas"
MIMETYPES["application/vnd.fujitsu.oasys2"]="oa2"
MIMETYPES["application/vnd.fujitsu.oasys3"]="oa3"
MIMETYPES["application/vnd.fujitsu.oasysgp"]="fg5"
MIMETYPES["application/vnd.fujitsu.oasysprs"]="bh2"
MIMETYPES["application/vnd.fujixerox.ddd"]="ddd"
MIMETYPES["application/vnd.fujixerox.docuworks"]="xdw"
MIMETYPES["application/vnd.fujixerox.docuworks.binder"]="xbd"
MIMETYPES["application/vnd.fuzzysheet"]="fzs"
MIMETYPES["application/vnd.genomatix.tuxedo"]="txd"
MIMETYPES["application/vnd.geogebra.file"]="ggb"
MIMETYPES["application/vnd.geogebra.tool"]="ggt"
MIMETYPES["application/vnd.geometry-explorer"]="gex"
MIMETYPES["application/vnd.geonext"]="gxt"
MIMETYPES["application/vnd.geoplan"]="g2w"
MIMETYPES["application/vnd.geospace"]="g3w"
MIMETYPES["application/vnd.gmx"]="gmx"
MIMETYPES["application/vnd.google-earth.kml+xml"]="kml"
MIMETYPES["application/vnd.google-earth.kmz"]="kmz"
MIMETYPES["application/vnd.grafeq"]="gqf"
MIMETYPES["application/vnd.groove-account"]="gac"
MIMETYPES["application/vnd.groove-help"]="ghf"
MIMETYPES["application/vnd.groove-identity-message"]="gim"
MIMETYPES["application/vnd.groove-injector"]="grv"
MIMETYPES["application/vnd.groove-tool-message"]="gtm"
MIMETYPES["application/vnd.groove-tool-template"]="tpl"
MIMETYPES["application/vnd.groove-vcard"]="vcg"
MIMETYPES["application/vnd.hal+xml"]="hal"
MIMETYPES["application/vnd.handheld-entertainment+xml"]="zmm"
MIMETYPES["application/vnd.hbci"]="hbci"
MIMETYPES["application/vnd.hhe.lesson-player"]="les"
MIMETYPES["application/vnd.hp-hpgl"]="hpgl"
MIMETYPES["application/vnd.hp-hpid"]="hpid"
MIMETYPES["application/vnd.hp-hps"]="hps"
MIMETYPES["application/vnd.hp-jlyt"]="jlt"
MIMETYPES["application/vnd.hp-pcl"]="pcl"
MIMETYPES["application/vnd.hp-pclxl"]="pclxl"
MIMETYPES["application/vnd.hydrostatix.sof-data"]="sfd-hdstx"
MIMETYPES["application/vnd.ibm.minipay"]="mpy"
MIMETYPES["application/vnd.ibm.modcap"]="afp"
MIMETYPES["application/vnd.ibm.rights-management"]="irm"
MIMETYPES["application/vnd.ibm.secure-container"]="sc"
MIMETYPES["application/vnd.iccprofile"]="icc"
MIMETYPES["application/vnd.igloader"]="igl"
MIMETYPES["application/vnd.immervision-ivp"]="ivp"
MIMETYPES["application/vnd.immervision-ivu"]="ivu"
MIMETYPES["application/vnd.insors.igm"]="igm"
MIMETYPES["application/vnd.intercon.formnet"]="xpw"
MIMETYPES["application/vnd.intergeo"]="i2g"
MIMETYPES["application/vnd.intu.qbo"]="qbo"
MIMETYPES["application/vnd.intu.qfx"]="qfx"
MIMETYPES["application/vnd.ipunplugged.rcprofile"]="rcprofile"
MIMETYPES["application/vnd.irepository.package+xml"]="irp"
MIMETYPES["application/vnd.is-xpr"]="xpr"
MIMETYPES["application/vnd.isac.fcs"]="fcs"
MIMETYPES["application/vnd.jam"]="jam"
MIMETYPES["application/vnd.jcp.javame.midlet-rms"]="rms"
MIMETYPES["application/vnd.jisp"]="jisp"
MIMETYPES["application/vnd.joost.joda-archive"]="joda"
MIMETYPES["application/vnd.kahootz"]="ktz"
MIMETYPES["application/vnd.kde.karbon"]="karbon"
MIMETYPES["application/vnd.kde.kchart"]="chrt"
MIMETYPES["application/vnd.kde.kformula"]="kfo"
MIMETYPES["application/vnd.kde.kivio"]="flw"
MIMETYPES["application/vnd.kde.kontour"]="kon"
MIMETYPES["application/vnd.kde.kpresenter"]="kpr"
MIMETYPES["application/vnd.kde.kspread"]="ksp"
MIMETYPES["application/vnd.kde.kword"]="kwd"
MIMETYPES["application/vnd.kenameaapp"]="htke"
MIMETYPES["application/vnd.kidspiration"]="kia"
MIMETYPES["application/vnd.kinar"]="kne"
MIMETYPES["application/vnd.koan"]="skp"
MIMETYPES["application/vnd.kodak-descriptor"]="sse"
MIMETYPES["application/vnd.las.las+xml"]="lasxml"
MIMETYPES["application/vnd.llamagraphics.life-balance.desktop"]="lbd"
MIMETYPES["application/vnd.llamagraphics.life-balance.exchange+xml"]="lbe"
MIMETYPES["application/vnd.lotus-1-2-3"]="123"
MIMETYPES["application/vnd.lotus-approach"]="apr"
MIMETYPES["application/vnd.lotus-freelance"]="pre"
MIMETYPES["application/vnd.lotus-notes"]="nsf"
MIMETYPES["application/vnd.lotus-organizer"]="org"
MIMETYPES["application/vnd.lotus-screencam"]="scm"
MIMETYPES["application/vnd.lotus-wordpro"]="lwp"
MIMETYPES["application/vnd.macports.portpkg"]="portpkg"
MIMETYPES["application/vnd.mcd"]="mcd"
MIMETYPES["application/vnd.medcalcdata"]="mc1"
MIMETYPES["application/vnd.mediastation.cdkey"]="cdkey"
MIMETYPES["application/vnd.mfer"]="mwf"
MIMETYPES["application/vnd.mfmp"]="mfm"
MIMETYPES["application/vnd.micrografx.flo"]="flo"
MIMETYPES["application/vnd.micrografx.igx"]="igx"
MIMETYPES["application/vnd.mif"]="mif"
MIMETYPES["application/vnd.mobius.daf"]="daf"
MIMETYPES["application/vnd.mobius.dis"]="dis"
MIMETYPES["application/vnd.mobius.mbk"]="mbk"
MIMETYPES["application/vnd.mobius.mqy"]="mqy"
MIMETYPES["application/vnd.mobius.msl"]="msl"
MIMETYPES["application/vnd.mobius.plc"]="plc"
MIMETYPES["application/vnd.mobius.txf"]="txf"
MIMETYPES["application/vnd.mophun.application"]="mpn"
MIMETYPES["application/vnd.mophun.certificate"]="mpc"
MIMETYPES["application/vnd.mozilla.xul+xml"]="xul"
MIMETYPES["application/vnd.ms-artgalry"]="cil"
MIMETYPES["application/vnd.ms-cab-compressed"]="cab"
MIMETYPES["application/vnd.ms-excel"]="xls"
MIMETYPES["application/vnd.ms-excel.addin.macroenabled.12"]="xlam"
MIMETYPES["application/vnd.ms-excel.sheet.binary.macroenabled.12"]="xlsb"
MIMETYPES["application/vnd.ms-excel.sheet.macroenabled.12"]="xlsm"
MIMETYPES["application/vnd.ms-excel.template.macroenabled.12"]="xltm"
MIMETYPES["application/vnd.ms-fontobject"]="eot"
MIMETYPES["application/vnd.ms-htmlhelp"]="chm"
MIMETYPES["application/vnd.ms-ims"]="ims"
MIMETYPES["application/vnd.ms-lrm"]="lrm"
MIMETYPES["application/vnd.ms-officetheme"]="thmx"
MIMETYPES["application/vnd.ms-pki.seccat"]="cat"
MIMETYPES["application/vnd.ms-pki.stl"]="stl"
MIMETYPES["application/vnd.ms-powerpoint"]="ppt"
MIMETYPES["application/vnd.ms-powerpoint.addin.macroenabled.12"]="ppam"
MIMETYPES["application/vnd.ms-powerpoint.presentation.macroenabled.12"]="pptm"
MIMETYPES["application/vnd.ms-powerpoint.slide.macroenabled.12"]="sldm"
MIMETYPES["application/vnd.ms-powerpoint.slideshow.macroenabled.12"]="ppsm"
MIMETYPES["application/vnd.ms-powerpoint.template.macroenabled.12"]="potm"
MIMETYPES["application/vnd.ms-project"]="mpp"
MIMETYPES["application/vnd.ms-word.document.macroenabled.12"]="docm"
MIMETYPES["application/vnd.ms-word.template.macroenabled.12"]="dotm"
MIMETYPES["application/vnd.ms-works"]="wps"
MIMETYPES["application/vnd.ms-wpl"]="wpl"
MIMETYPES["application/vnd.ms-xpsdocument"]="xps"
MIMETYPES["application/vnd.mseq"]="mseq"
MIMETYPES["application/vnd.musician"]="mus"
MIMETYPES["application/vnd.muvee.style"]="msty"
MIMETYPES["application/vnd.mynfc"]="taglet"
MIMETYPES["application/vnd.neurolanguage.nlu"]="nlu"
MIMETYPES["application/vnd.nitf"]="ntf"
MIMETYPES["application/vnd.noblenet-directory"]="nnd"
MIMETYPES["application/vnd.noblenet-sealer"]="nns"
MIMETYPES["application/vnd.noblenet-web"]="nnw"
MIMETYPES["application/vnd.nokia.n-gage.data"]="ngdat"
MIMETYPES["application/vnd.nokia.n-gage.symbian.install"]="n-gage"
MIMETYPES["application/vnd.nokia.radio-preset"]="rpst"
MIMETYPES["application/vnd.nokia.radio-presets"]="rpss"
MIMETYPES["application/vnd.novadigm.edm"]="edm"
MIMETYPES["application/vnd.novadigm.edx"]="edx"
MIMETYPES["application/vnd.novadigm.ext"]="ext"
MIMETYPES["application/vnd.oasis.opendocument.chart"]="odc"
MIMETYPES["application/vnd.oasis.opendocument.chart-template"]="otc"
MIMETYPES["application/vnd.oasis.opendocument.database"]="odb"
MIMETYPES["application/vnd.oasis.opendocument.formula"]="odf"
MIMETYPES["application/vnd.oasis.opendocument.formula-template"]="odft"
MIMETYPES["application/vnd.oasis.opendocument.graphics"]="odg"
MIMETYPES["application/vnd.oasis.opendocument.graphics-template"]="otg"
MIMETYPES["application/vnd.oasis.opendocument.image"]="odi"
MIMETYPES["application/vnd.oasis.opendocument.image-template"]="oti"
MIMETYPES["application/vnd.oasis.opendocument.presentation"]="odp"
MIMETYPES["application/vnd.oasis.opendocument.presentation-template"]="otp"
MIMETYPES["application/vnd.oasis.opendocument.spreadsheet"]="ods"
MIMETYPES["application/vnd.oasis.opendocument.spreadsheet-template"]="ots"
MIMETYPES["application/vnd.oasis.opendocument.text"]="odt"
MIMETYPES["application/vnd.oasis.opendocument.text-master"]="odm"
MIMETYPES["application/vnd.oasis.opendocument.text-template"]="ott"
MIMETYPES["application/vnd.oasis.opendocument.text-web"]="oth"
MIMETYPES["application/vnd.olpc-sugar"]="xo"
MIMETYPES["application/vnd.oma.dd2+xml"]="dd2"
MIMETYPES["application/vnd.openofficeorg.extension"]="oxt"
MIMETYPES["application/vnd.openxmlformats-officedocument.presentationml.presentation"]="pptx"
MIMETYPES["application/vnd.openxmlformats-officedocument.presentationml.slide"]="sldx"
MIMETYPES["application/vnd.openxmlformats-officedocument.presentationml.slideshow"]="ppsx"
MIMETYPES["application/vnd.openxmlformats-officedocument.presentationml.template"]="potx"
MIMETYPES["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"]="xlsx"
MIMETYPES["application/vnd.openxmlformats-officedocument.spreadsheetml.template"]="xltx"
MIMETYPES["application/vnd.openxmlformats-officedocument.wordprocessingml.document"]="docx"
MIMETYPES["application/vnd.openxmlformats-officedocument.wordprocessingml.template"]="dotx"
MIMETYPES["application/vnd.osgeo.mapguide.package"]="mgp"
MIMETYPES["application/vnd.osgi.dp"]="dp"
MIMETYPES["application/vnd.osgi.subsystem"]="esa"
MIMETYPES["application/vnd.palm"]="pdb"
MIMETYPES["application/vnd.pawaafile"]="paw"
MIMETYPES["application/vnd.pg.format"]="str"
MIMETYPES["application/vnd.pg.osasli"]="ei6"
MIMETYPES["application/vnd.picsel"]="efif"
MIMETYPES["application/vnd.pmi.widget"]="wg"
MIMETYPES["application/vnd.pocketlearn"]="plf"
MIMETYPES["application/vnd.powerbuilder6"]="pbd"
MIMETYPES["application/vnd.previewsystems.box"]="box"
MIMETYPES["application/vnd.proteus.magazine"]="mgz"
MIMETYPES["application/vnd.publishare-delta-tree"]="qps"
MIMETYPES["application/vnd.pvi.ptid1"]="ptid"
MIMETYPES["application/vnd.quark.quarkxpress"]="qxd"
MIMETYPES["application/vnd.realvnc.bed"]="bed"
MIMETYPES["application/vnd.recordare.musicxml"]="mxl"
MIMETYPES["application/vnd.recordare.musicxml+xml"]="musicxml"
MIMETYPES["application/vnd.rig.cryptonote"]="cryptonote"
MIMETYPES["application/vnd.rim.cod"]="cod"
MIMETYPES["application/vnd.rn-realmedia"]="rm"
MIMETYPES["application/vnd.rn-realmedia-vbr"]="rmvb"
MIMETYPES["application/vnd.route66.link66+xml"]="link66"
MIMETYPES["application/vnd.sailingtracker.track"]="st"
MIMETYPES["application/vnd.seemail"]="see"
MIMETYPES["application/vnd.sema"]="sema"
MIMETYPES["application/vnd.semd"]="semd"
MIMETYPES["application/vnd.semf"]="semf"
MIMETYPES["application/vnd.shana.informed.formdata"]="ifm"
MIMETYPES["application/vnd.shana.informed.formtemplate"]="itp"
MIMETYPES["application/vnd.shana.informed.interchange"]="iif"
MIMETYPES["application/vnd.shana.informed.package"]="ipk"
MIMETYPES["application/vnd.simtech-mindmapper"]="twd"
MIMETYPES["application/vnd.smaf"]="mmf"
MIMETYPES["application/vnd.smart.teacher"]="teacher"
MIMETYPES["application/vnd.solent.sdkm+xml"]="sdkm"
MIMETYPES["application/vnd.spotfire.dxp"]="dxp"
MIMETYPES["application/vnd.spotfire.sfs"]="sfs"
MIMETYPES["application/vnd.stardivision.calc"]="sdc"
MIMETYPES["application/vnd.stardivision.draw"]="sda"
MIMETYPES["application/vnd.stardivision.impress"]="sdd"
MIMETYPES["application/vnd.stardivision.math"]="smf"
MIMETYPES["application/vnd.stardivision.writer"]="sdw"
MIMETYPES["application/vnd.stardivision.writer-global"]="sgl"
MIMETYPES["application/vnd.stepmania.package"]="smzip"
MIMETYPES["application/vnd.stepmania.stepchart"]="sm"
MIMETYPES["application/vnd.sun.xml.calc"]="sxc"
MIMETYPES["application/vnd.sun.xml.calc.template"]="stc"
MIMETYPES["application/vnd.sun.xml.draw"]="sxd"
MIMETYPES["application/vnd.sun.xml.draw.template"]="std"
MIMETYPES["application/vnd.sun.xml.impress"]="sxi"
MIMETYPES["application/vnd.sun.xml.impress.template"]="sti"
MIMETYPES["application/vnd.sun.xml.math"]="sxm"
MIMETYPES["application/vnd.sun.xml.writer"]="sxw"
MIMETYPES["application/vnd.sun.xml.writer.global"]="sxg"
MIMETYPES["application/vnd.sun.xml.writer.template"]="stw"
MIMETYPES["application/vnd.sus-calendar"]="sus"
MIMETYPES["application/vnd.svd"]="svd"
MIMETYPES["application/vnd.symbian.install"]="sis"
MIMETYPES["application/vnd.syncml+xml"]="xsm"
MIMETYPES["application/vnd.syncml.dm+wbxml"]="bdm"
MIMETYPES["application/vnd.syncml.dm+xml"]="xdm"
MIMETYPES["application/vnd.tao.intent-module-archive"]="tao"
MIMETYPES["application/vnd.tcpdump.pcap"]="pcap"
MIMETYPES["application/vnd.tmobile-livetv"]="tmo"
MIMETYPES["application/vnd.trid.tpt"]="tpt"
MIMETYPES["application/vnd.triscape.mxs"]="mxs"
MIMETYPES["application/vnd.trueapp"]="tra"
MIMETYPES["application/vnd.ufdl"]="ufd"
MIMETYPES["application/vnd.uiq.theme"]="utz"
MIMETYPES["application/vnd.umajin"]="umj"
MIMETYPES["application/vnd.unity"]="unityweb"
MIMETYPES["application/vnd.uoml+xml"]="uoml"
MIMETYPES["application/vnd.vcx"]="vcx"
MIMETYPES["application/vnd.visio"]="vsd"
MIMETYPES["application/vnd.visionary"]="vis"
MIMETYPES["application/vnd.vsf"]="vsf"
MIMETYPES["application/vnd.wap.wbxml"]="wbxml"
MIMETYPES["application/vnd.wap.wmlc"]="wmlc"
MIMETYPES["application/vnd.wap.wmlscriptc"]="wmlsc"
MIMETYPES["application/vnd.webturbo"]="wtb"
MIMETYPES["application/vnd.wolfram.player"]="nbp"
MIMETYPES["application/vnd.wordperfect"]="wpd"
MIMETYPES["application/vnd.wqd"]="wqd"
MIMETYPES["application/vnd.wt.stf"]="stf"
MIMETYPES["application/vnd.xara"]="xar"
MIMETYPES["application/vnd.xfdl"]="xfdl"
MIMETYPES["application/vnd.yamaha.hv-dic"]="hvd"
MIMETYPES["application/vnd.yamaha.hv-script"]="hvs"
MIMETYPES["application/vnd.yamaha.hv-voice"]="hvp"
MIMETYPES["application/vnd.yamaha.openscoreformat"]="osf"
MIMETYPES["application/vnd.yamaha.openscoreformat.osfpvg+xml"]="osfpvg"
MIMETYPES["application/vnd.yamaha.smaf-audio"]="saf"
MIMETYPES["application/vnd.yamaha.smaf-phrase"]="spf"
MIMETYPES["application/vnd.yellowriver-custom-menu"]="cmp"
MIMETYPES["application/vnd.zul"]="zir"
MIMETYPES["application/vnd.zzazz.deck+xml"]="zaz"
MIMETYPES["application/voicexml+xml"]="vxml"
MIMETYPES["application/widget"]="wgt"
MIMETYPES["application/winhlp"]="hlp"
MIMETYPES["application/wsdl+xml"]="wsdl"
MIMETYPES["application/wspolicy+xml"]="wspolicy"
MIMETYPES["application/x-7z-compressed"]="7z"
MIMETYPES["application/x-abiword"]="abw"
MIMETYPES["application/x-ace-compressed"]="ace"
MIMETYPES["application/x-apple-diskimage"]="dmg"
MIMETYPES["application/x-authorware-bin"]="aab"
MIMETYPES["application/x-authorware-map"]="aam"
MIMETYPES["application/x-authorware-seg"]="aas"
MIMETYPES["application/x-bcpio"]="bcpio"
MIMETYPES["application/x-bittorrent"]="torrent"
MIMETYPES["application/x-blorb"]="blb"
MIMETYPES["application/x-bzip"]="bz"
MIMETYPES["application/x-bzip2"]="bz2"
MIMETYPES["application/x-cbr"]="cbr"
MIMETYPES["application/x-cdlink"]="vcd"
MIMETYPES["application/x-cfs-compressed"]="cfs"
MIMETYPES["application/x-chat"]="chat"
MIMETYPES["application/x-chess-pgn"]="pgn"
MIMETYPES["application/x-conference"]="nsc"
MIMETYPES["application/x-cpio"]="cpio"
MIMETYPES["application/x-csh"]="csh"
MIMETYPES["application/x-debian-package"]="deb"
MIMETYPES["application/x-dgc-compressed"]="dgc"
MIMETYPES["application/x-director"]="dir"
MIMETYPES["application/x-doom"]="wad"
MIMETYPES["application/x-dtbncx+xml"]="ncx"
MIMETYPES["application/x-dtbook+xml"]="dtb"
MIMETYPES["application/x-dtbresource+xml"]="res"
MIMETYPES["application/x-dvi"]="dvi"
MIMETYPES["application/x-envoy"]="evy"
MIMETYPES["application/x-eva"]="eva"
MIMETYPES["application/x-font-bdf"]="bdf"
MIMETYPES["application/x-font-ghostscript"]="gsf"
MIMETYPES["application/x-font-linux-psf"]="psf"
MIMETYPES["application/x-font-otf"]="otf"
MIMETYPES["application/x-font-pcf"]="pcf"
MIMETYPES["application/x-font-snf"]="snf"
MIMETYPES["application/x-font-ttf"]="ttf"
MIMETYPES["application/x-font-type1"]="pfa"
MIMETYPES["application/font-woff"]="woff"
MIMETYPES["application/x-freearc"]="arc"
MIMETYPES["application/x-futuresplash"]="spl"
MIMETYPES["application/x-gca-compressed"]="gca"
MIMETYPES["application/x-glulx"]="ulx"
MIMETYPES["application/x-gnumeric"]="gnumeric"
MIMETYPES["application/x-gramps-xml"]="gramps"
MIMETYPES["application/x-gtar"]="gtar"
MIMETYPES["application/x-hdf"]="hdf"
MIMETYPES["application/x-install-instructions"]="install"
MIMETYPES["application/x-iso9660-image"]="iso"
MIMETYPES["application/x-java-jnlp-file"]="jnlp"
MIMETYPES["application/x-latex"]="latex"
MIMETYPES["application/x-lzh-compressed"]="lzh"
MIMETYPES["application/x-mie"]="mie"
MIMETYPES["application/x-mobipocket-ebook"]="prc"
MIMETYPES["application/x-ms-application"]="application"
MIMETYPES["application/x-ms-shortcut"]="lnk"
MIMETYPES["application/x-ms-wmd"]="wmd"
MIMETYPES["application/x-ms-wmz"]="wmz"
MIMETYPES["application/x-ms-xbap"]="xbap"
MIMETYPES["application/x-msaccess"]="mdb"
MIMETYPES["application/x-msbinder"]="obd"
MIMETYPES["application/x-mscardfile"]="crd"
MIMETYPES["application/x-msclip"]="clp"
MIMETYPES["application/x-msdownload"]="exe"
MIMETYPES["application/x-msmediaview"]="mvb"
MIMETYPES["application/x-msmetafile"]="wmf"
MIMETYPES["application/x-msmoney"]="mny"
MIMETYPES["application/x-mspublisher"]="pub"
MIMETYPES["application/x-msschedule"]="scd"
MIMETYPES["application/x-msterminal"]="trm"
MIMETYPES["application/x-mswrite"]="wri"
MIMETYPES["application/x-netcdf"]="nc"
MIMETYPES["application/x-nzb"]="nzb"
MIMETYPES["application/x-pkcs12"]="p12"
MIMETYPES["application/x-pkcs7-certificates"]="p7b"
MIMETYPES["application/x-pkcs7-certreqresp"]="p7r"
MIMETYPES["application/x-rar-compressed"]="rar"
MIMETYPES["application/x-research-info-systems"]="ris"
MIMETYPES["application/x-sh"]="sh"
MIMETYPES["application/x-shar"]="shar"
MIMETYPES["application/x-shockwave-flash"]="swf"
MIMETYPES["application/x-silverlight-app"]="xap"
MIMETYPES["application/x-sql"]="sql"
MIMETYPES["application/x-stuffit"]="sit"
MIMETYPES["application/x-stuffitx"]="sitx"
MIMETYPES["application/x-subrip"]="srt"
MIMETYPES["application/x-sv4cpio"]="sv4cpio"
MIMETYPES["application/x-sv4crc"]="sv4crc"
MIMETYPES["application/x-t3vm-image"]="t3"
MIMETYPES["application/x-tads"]="gam"
MIMETYPES["application/x-tar"]="tar"
MIMETYPES["application/x-tcl"]="tcl"
MIMETYPES["application/x-tex"]="tex"
MIMETYPES["application/x-tex-tfm"]="tfm"
MIMETYPES["application/x-texinfo"]="texinfo"
MIMETYPES["application/x-tgif"]="obj"
MIMETYPES["application/x-ustar"]="ustar"
MIMETYPES["application/x-wais-source"]="src"
MIMETYPES["application/x-x509-ca-cert"]="der"
MIMETYPES["application/x-xfig"]="fig"
MIMETYPES["application/x-xliff+xml"]="xlf"
MIMETYPES["application/x-xpinstall"]="xpi"
MIMETYPES["application/x-xz"]="xz"
MIMETYPES["application/x-zmachine"]="z1"
MIMETYPES["application/xaml+xml"]="xaml"
MIMETYPES["application/xcap-diff+xml"]="xdf"
MIMETYPES["application/xenc+xml"]="xenc"
MIMETYPES["application/xhtml+xml"]="xhtml"
MIMETYPES["application/xml"]="xml"
MIMETYPES["application/xml-dtd"]="dtd"
MIMETYPES["application/xop+xml"]="xop"
MIMETYPES["application/xproc+xml"]="xpl"
MIMETYPES["application/xslt+xml"]="xslt"
MIMETYPES["application/xspf+xml"]="xspf"
MIMETYPES["application/xv+xml"]="mxml"
MIMETYPES["application/yang"]="yang"
MIMETYPES["application/yin+xml"]="yin"
MIMETYPES["application/zip"]="zip"
MIMETYPES["audio/adpcm"]="adp"
MIMETYPES["audio/basic"]="au"
MIMETYPES["audio/midi"]="mid"
MIMETYPES["audio/mp4"]="mp4a"
MIMETYPES["audio/mpeg"]="mpga"
MIMETYPES["audio/ogg"]="oga"
MIMETYPES["audio/s3m"]="s3m"
MIMETYPES["audio/silk"]="sil"
MIMETYPES["audio/vnd.dece.audio"]="uva"
MIMETYPES["audio/vnd.digital-winds"]="eol"
MIMETYPES["audio/vnd.dra"]="dra"
MIMETYPES["audio/vnd.dts"]="dts"
MIMETYPES["audio/vnd.dts.hd"]="dtshd"
MIMETYPES["audio/vnd.lucent.voice"]="lvp"
MIMETYPES["audio/vnd.ms-playready.media.pya"]="pya"
MIMETYPES["audio/vnd.nuera.ecelp4800"]="ecelp4800"
MIMETYPES["audio/vnd.nuera.ecelp7470"]="ecelp7470"
MIMETYPES["audio/vnd.nuera.ecelp9600"]="ecelp9600"
MIMETYPES["audio/vnd.rip"]="rip"
MIMETYPES["audio/webm"]="weba"
MIMETYPES["audio/x-aac"]="aac"
MIMETYPES["audio/x-aiff"]="aif"
MIMETYPES["audio/x-caf"]="caf"
MIMETYPES["audio/x-flac"]="flac"
MIMETYPES["audio/x-matroska"]="mka"
MIMETYPES["audio/x-mpegurl"]="m3u"
MIMETYPES["audio/x-ms-wax"]="wax"
MIMETYPES["audio/x-ms-wma"]="wma"
MIMETYPES["audio/x-pn-realaudio"]="ram"
MIMETYPES["audio/x-pn-realaudio-plugin"]="rmp"
MIMETYPES["audio/x-wav"]="wav"
MIMETYPES["audio/xm"]="xm"
MIMETYPES["chemical/x-cdx"]="cdx"
MIMETYPES["chemical/x-cif"]="cif"
MIMETYPES["chemical/x-cmdf"]="cmdf"
MIMETYPES["chemical/x-cml"]="cml"
MIMETYPES["chemical/x-csml"]="csml"
MIMETYPES["chemical/x-xyz"]="xyz"
MIMETYPES["image/bmp"]="bmp"
MIMETYPES["image/cgm"]="cgm"
MIMETYPES["image/g3fax"]="g3"
MIMETYPES["image/gif"]="gif"
MIMETYPES["image/ief"]="ief"
MIMETYPES["image/jpeg"]="jpeg"
MIMETYPES["image/ktx"]="ktx"
MIMETYPES["image/png"]="png"
MIMETYPES["image/prs.btif"]="btif"
MIMETYPES["image/sgi"]="sgi"
MIMETYPES["image/svg+xml"]="svg"
MIMETYPES["image/tiff"]="tiff"
MIMETYPES["image/vnd.adobe.photoshop"]="psd"
MIMETYPES["image/vnd.dece.graphic"]="uvi"
MIMETYPES["image/vnd.dvb.subtitle"]="sub"
MIMETYPES["image/vnd.djvu"]="djvu"
MIMETYPES["image/vnd.dwg"]="dwg"
MIMETYPES["image/vnd.dxf"]="dxf"
MIMETYPES["image/vnd.fastbidsheet"]="fbs"
MIMETYPES["image/vnd.fpx"]="fpx"
MIMETYPES["image/vnd.fst"]="fst"
MIMETYPES["image/vnd.fujixerox.edmics-mmr"]="mmr"
MIMETYPES["image/vnd.fujixerox.edmics-rlc"]="rlc"
MIMETYPES["image/vnd.ms-modi"]="mdi"
MIMETYPES["image/vnd.ms-photo"]="wdp"
MIMETYPES["image/vnd.net-fpx"]="npx"
MIMETYPES["image/vnd.wap.wbmp"]="wbmp"
MIMETYPES["image/vnd.xiff"]="xif"
MIMETYPES["image/webp"]="webp"
MIMETYPES["image/x-3ds"]="3ds"
MIMETYPES["image/x-cmu-raster"]="ras"
MIMETYPES["image/x-cmx"]="cmx"
MIMETYPES["image/x-freehand"]="fh"
MIMETYPES["image/x-icon"]="ico"
MIMETYPES["image/x-mrsid-image"]="sid"
MIMETYPES["image/x-pcx"]="pcx"
MIMETYPES["image/x-pict"]="pic"
MIMETYPES["image/x-portable-anymap"]="pnm"
MIMETYPES["image/x-portable-bitmap"]="pbm"
MIMETYPES["image/x-portable-graymap"]="pgm"
MIMETYPES["image/x-portable-pixmap"]="ppm"
MIMETYPES["image/x-rgb"]="rgb"
MIMETYPES["image/x-tga"]="tga"
MIMETYPES["image/x-xbitmap"]="xbm"
MIMETYPES["image/x-xpixmap"]="xpm"
MIMETYPES["image/x-xwindowdump"]="xwd"
MIMETYPES["message/rfc822"]="eml"
MIMETYPES["model/iges"]="igs"
MIMETYPES["model/mesh"]="msh"
MIMETYPES["model/vnd.collada+xml"]="dae"
MIMETYPES["model/vnd.dwf"]="dwf"
MIMETYPES["model/vnd.gdl"]="gdl"
MIMETYPES["model/vnd.gtw"]="gtw"
MIMETYPES["model/vnd.mts"]="mts"
MIMETYPES["model/vnd.vtu"]="vtu"
MIMETYPES["model/vrml"]="wrl"
MIMETYPES["model/x3d+binary"]="x3db"
MIMETYPES["model/x3d+vrml"]="x3dv"
MIMETYPES["model/x3d+xml"]="x3d"
MIMETYPES["text/cache-manifest"]="appcache"
MIMETYPES["text/calendar"]="ics"
MIMETYPES["text/css"]="css"
MIMETYPES["text/csv"]="csv"
MIMETYPES["text/html"]="html"
MIMETYPES["text/n3"]="n3"
MIMETYPES["text/plain"]="txt"
MIMETYPES["text/prs.lines.tag"]="dsc"
MIMETYPES["text/richtext"]="rtx"
MIMETYPES["text/sgml"]="sgml"
MIMETYPES["text/tab-separated-values"]="tsv"
MIMETYPES["text/troff"]="t"
MIMETYPES["text/turtle"]="ttl"
MIMETYPES["text/uri-list"]="uri"
MIMETYPES["text/vcard"]="vcard"
MIMETYPES["text/vnd.curl"]="curl"
MIMETYPES["text/vnd.curl.dcurl"]="dcurl"
MIMETYPES["text/vnd.curl.scurl"]="scurl"
MIMETYPES["text/vnd.curl.mcurl"]="mcurl"
MIMETYPES["text/vnd.dvb.subtitle"]="sub"
MIMETYPES["text/vnd.fly"]="fly"
MIMETYPES["text/vnd.fmi.flexstor"]="flx"
MIMETYPES["text/vnd.graphviz"]="gv"
MIMETYPES["text/vnd.in3d.3dml"]="3dml"
MIMETYPES["text/vnd.in3d.spot"]="spot"
MIMETYPES["text/vnd.sun.j2me.app-descriptor"]="jad"
MIMETYPES["text/vnd.wap.wml"]="wml"
MIMETYPES["text/vnd.wap.wmlscript"]="wmls"
MIMETYPES["text/x-asm"]="s"
MIMETYPES["text/x-c"]="c"
MIMETYPES["text/x-fortran"]="f"
MIMETYPES["text/x-java-source"]="java"
MIMETYPES["text/x-opml"]="opml"
MIMETYPES["text/x-pascal"]="p"
MIMETYPES["text/x-nfo"]="nfo"
MIMETYPES["text/x-setext"]="etx"
MIMETYPES["text/x-sfv"]="sfv"
MIMETYPES["text/x-uuencode"]="uu"
MIMETYPES["text/x-vcalendar"]="vcs"
MIMETYPES["text/x-vcard"]="vcf"
MIMETYPES["video/3gpp"]="3gp"
MIMETYPES["video/3gpp2"]="3g2"
MIMETYPES["video/h261"]="h261"
MIMETYPES["video/h263"]="h263"
MIMETYPES["video/h264"]="h264"
MIMETYPES["video/jpeg"]="jpgv"
MIMETYPES["video/jpm"]="jpm"
MIMETYPES["video/mj2"]="mj2"
MIMETYPES["video/mp4"]="mp4"
MIMETYPES["video/mpeg"]="mpeg"
MIMETYPES["video/ogg"]="ogv"
MIMETYPES["video/quicktime"]="qt"
MIMETYPES["video/vnd.dece.hd"]="uvh"
MIMETYPES["video/vnd.dece.mobile"]="uvm"
MIMETYPES["video/vnd.dece.pd"]="uvp"
MIMETYPES["video/vnd.dece.sd"]="uvs"
MIMETYPES["video/vnd.dece.video"]="uvv"
MIMETYPES["video/vnd.dvb.file"]="dvb"
MIMETYPES["video/vnd.fvt"]="fvt"
MIMETYPES["video/vnd.mpegurl"]="mxu"
MIMETYPES["video/vnd.ms-playready.media.pyv"]="pyv"
MIMETYPES["video/vnd.uvvu.mp4"]="uvu"
MIMETYPES["video/vnd.vivo"]="viv"
MIMETYPES["video/webm"]="webm"
MIMETYPES["video/x-f4v"]="f4v"
MIMETYPES["video/x-fli"]="fli"
MIMETYPES["video/x-flv"]="flv"
MIMETYPES["video/x-m4v"]="m4v"
MIMETYPES["video/x-matroska"]="mkv"
MIMETYPES["video/x-mng"]="mng"
MIMETYPES["video/x-ms-asf"]="asf"
MIMETYPES["video/x-ms-vob"]="vob"
MIMETYPES["video/x-ms-wm"]="wm"
MIMETYPES["video/x-ms-wmv"]="wmv"
MIMETYPES["video/x-ms-wmx"]="wmx"
MIMETYPES["video/x-ms-wvx"]="wvx"
MIMETYPES["video/x-msvideo"]="avi"
MIMETYPES["video/x-sgi-movie"]="movie"
MIMETYPES["video/x-smv"]="smv"
MIMETYPES["x-conference/x-cooltalk"]="ice"


text:
include("util.jl")
include("preprocess.jl")
include("stitch.jl")
include("stitchedseries.jl")
include("write.jl")


text:
##Tests used in paper for the Small-Data KP
using Distributions, Random, DelimitedFiles, LinearAlgebra
include("KPNormal.jl")
using .KP

#Default experiments fix a single theta, cs, vs across all simulation
mutable struct DefaultExp
	cs
	thetas
	vs
end

function sim!(o, muhat)
	muhat[:] = randn!(muhat) ./ sqrt.(o.vs) .+ o.thetas
end

#simulates random normal stuff, but via a dataset
#dat is assumed n, S
function sim!(o, muhat, dat)
	S = size(dat, 2)
	n = size(dat, 1)
	for i = 1:S
		dat[:, i] .= randn(n) ./ sqrt.(o.vs/S)  .+ o.thetas #notice scaling by S
	end
	muhat[:] = mean(dat, dims=2)
end
######################
####
#For increasing n, many simulations compare
#		#SAA
#		#FullInfo
#		#EB MM
#		#EB MLE
#		#SURE MSE
#		#OR MSE
#		#Diract Stein
#		#Box Stein
#		#tauOR
#Compare on metrics
#		#Value wrt theta
#		#Time to compute
#		#optimal value of tau0
function test_harness(f, numRuns, o, n_grid; Gamma_min=1., Gamma_max=20., Gamma_step=.01)
	n_max = maximum(n_grid)
	S = 10
	muhat = zeros(Float64, n_max)
	xs  = zeros(Float64, n_max)
	dat = zeros(Float64, n_max, S)
	lam_t = 0.

	#write a header
	writedlm(f,  ["Run" "n" "Method" "thetaVal" "time" "tau0"], ',')

	for iRun = 1:numRuns
		#generate the entire path up to n_max
		#sim!(o, muhat)
		sim!(o, muhat, dat)

		for n in n_grid
			#Take Views on Everything to speed up garbage collection
			x_t = view(xs, 1:n)
			vs  = view(o.vs, 1:n)
			cs  = view(o.cs, 1:n)
			thetas = view(o.thetas, 1:n)
			muhat_t = view(muhat, 1:n)
			dat_t = view(dat, 1:n, 1:S)

			#Compute performance of each method

			#SAA
			t = @elapsed x_t[:] = x(cs, muhat_t)
			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "SAA" thetaval t 0.], ',')

			#fullInfo val
			t = @elapsed x_t[:] = x(cs, thetas)
			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "FullInfo" thetaval t 0.], ',')

			# #The "Bayes" value.. only possible bc we if we we are in bayesian
			# if :tau0 in fieldnames(o)
			# 	tic()
			# 	xs = x(cs, shrink(muhat_t, vs, o.tau0))
			# 	t = toc()
			# 	thetaval = dot(thetas, xs)/n
			# 	writedlm(f,  [iRun n "Bayes" thetaval t o.tau0], ',')
			# end

			#Tau MLE
			t =
			  @elapsed tauMLE, x_t[:] = x_MLE(cs, muhat_t, vs)

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "EB_MLE" thetaval t tauMLE], ',')

			#Tau MM
			t =
			  @elapsed tauMM, x_t[:] = x_MM(cs, muhat_t, vs)
			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "EB_MM" thetaval t tauMM], ',')

			#Oracle MSE
			t =
			  @elapsed x_t[:], tau_CV = x_OR_MSE(cs, muhat_t, thetas, vs)

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "OR_MSE" thetaval t tau_CV], ',')

			#Sure MSE
			t =
			  @elapsed x_t[:], tau_CV = x_sure_MSE(cs, muhat_t, vs)

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "SURE_MSE" thetaval t tau_CV], ',')

			#Dirac Stein
			t =
			  @elapsed x_t[:], vals, objs = x_stein_exact(cs, muhat_t, vs, thetas)

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "DiracStein" thetaval t vals[argmax(objs)]], ',')

			#Box with the optimized rate, i.e. h_n = n^-1/6 and scaling, altKernel
			h = n^-.16666
			t =
			  @elapsed x_t[:], vals, objs = x_stein_box(cs, muhat_t, vs, h, tau_step = .05)

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "BoxStein" thetaval t vals[argmax(objs)]], ',')

			#Oracle Value
			t =
			  @elapsed x_t[:], vals, objs = best_x_tau(cs, muhat_t, vs, thetas)

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "OR" thetaval t vals[argmax(objs)]], ',')

			#Hold-Out validation
			t =
			  @elapsed x_t[:], tau_grid, objs = KP.x_kFoldCV(cs, vs/S, dat_t, 2; tau_grid=collect(0.:.05:5))

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "HO_EB" thetaval t tau_grid[argmax(objs)]], ',')

			#5-Fold validation
			t =
			  @elapsed x_t[:], tau_grid, objs = KP.x_kFoldCV(cs, vs/S, dat_t, 5; tau_grid=collect(0.:.05:5))

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "K5_EB" thetaval t tau_grid[argmax(objs)]], ',')

			#LOO validation
			t =
			  @elapsed x_t[:], tau_grid, objs = KP.x_kFoldCV(cs, vs/S, dat_t, S; tau_grid=collect(0.:.05:5))

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "LOO_EB" thetaval t tau_grid[argmax(objs)]], ',')

			###Regularization Methods
			#Oracle Regularization
			t =
			  @elapsed x_t[:], Gamma_grid, objs = KP.x_l2reg_CV(cs, muhat_t, vs, thetas,
														Gamma_min=Gamma_min, Gamma_max=Gamma_max, Gamma_step=Gamma_step)

			Gammahat = Gamma_grid[argmax(objs)]
			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "OracleReg" thetaval t Gammahat], ',')

			# #From the same values, extract oracles for Other pairs
			# #For Gamma_min = 5
			ind_min = findfirst(Gamma_grid .>= 5.0)
			Gammahat = Gamma_grid[ind_min:end][argmax(objs[ind_min:end])]
			lam_t = KP.x_l2reg2!(cs, muhat_t, vs, Gammahat, x_t)
			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "OracleReg_5" thetaval t Gammahat], ',')

			# #Our Stein Approach to Regularization
			t =
			  @elapsed x_t[:], Gamma_grid, objs = KP.x_stein_reg(cs, muhat_t, vs,
										Gamma_min=Gamma_min, Gamma_max=Gamma_max, Gamma_step=Gamma_step)

			Gammahat = Gamma_grid[argmax(objs)]
			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "SteinReg" thetaval t Gammahat], ',')

			# #Again, from same values, extract values for gamma_min
			ind_min = findfirst(Gamma_grid .>= 5.0)
			Gammahat = Gamma_grid[ind_min:end][argmax(objs[ind_min:end])]
			lam_t = KP.x_l2reg2!(cs, muhat_t, vs, Gammahat, x_t)
			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "SteinReg_5" thetaval t Gammahat], ',')

			# #NEW RO method with new threshold
			thresh = sqrt(2*log(1/.1))
			t =
			  @elapsed x_t[:] = KP.x_robFW(cs, muhat_t, vs, thresh, TOL=1e-4)

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "FWRO_Eps_.1" thetaval t thresh], ',')

			thresh = sqrt(2*log(1/.05))
			t =
			  @elapsed x_t[:] = KP.x_robFW(cs, muhat_t, vs, thresh, TOL=1e-4)

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "FWRO_Eps_.05" thetaval t thresh], ',')

			thresh = sqrt(2*log(1/.01))
			t =
			  @elapsed x_t[:] = KP.x_robFW(cs, muhat_t, vs, thresh, TOL=1e-4)

			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "FWRO_Eps_.01" thetaval t thresh], ',')

			# ####
			# #This section was used for the intial paper submission Feb2017
			# # The thresholds have been updated.  If want to rerun, consider using the FW implementation too.
			# #RO heuristic for Gamma
			# #eps = .05
			# tic()
			# xs, lam = KP.x_rob(cs, muhat_t, vs, 1.6448536269514717)
			# t = toc()
			# thetaval = dot(thetas, xs)/n
			# writedlm(f,  [iRun n "RO_Eps_.05" thetaval t 1.6448536269514717], ',')

			# #eps = .01
			# tic()
			# xs, lam = KP.x_rob(cs, muhat_t, vs, 2.326347874040845)
			# t = toc()
			# thetaval = dot(thetas, xs)/n
			# writedlm(f,  [iRun n "RO_Eps_.01" thetaval t 2.326347874040845], ',')

			#VG Replaced with proper KFold
			#Leave one out validation (LOO)
			# tic()
			# x_t[:], Gamma_grid, objs = KP.x_LOO_reg(cs, muhat_t + noise_t, muhat_t - noise_t, vs,
			# 									Gamma_min=Gamma_min, Gamma_max=Gamma_max, Gamma_step=Gamma_step)
			# t = toc()
			# thetaval = dot(thetas, x_t)/n
			# GammaLOO = Gamma_grid[argmax(objs)]
			# writedlm(f,  [iRun n "LOO" thetaval t GammaLOO], ',')

			# #Use same values to extract for other gamma_min
			# ind_min = findfirst(Gamma_grid .>= 5.0)
			# GammaLOO = Gamma_grid[ind_min:end][argmax(objs[ind_min:end])]
			# lam_t = KP.x_l2reg2!(cs, muhat_t, vs, GammaLOO, x_t)
			# thetaval = dot(thetas, x_t)/n
			# writedlm(f,  [iRun n "LOO_5" thetaval t GammaLOO], ',')
			#######
			#########
			#######

			#Hold Out Validation choice
			t =
			  @elapsed x_t[:], Gamma_grid, objs = KP.x_l2reg_kFoldCV(cs, vs/S, dat_t, 2;
                    Gamma_step=Gamma_step, Gamma_min=Gamma_min, Gamma_max=Gamma_max)

			Gammahat = Gamma_grid[argmax(objs)]
			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "HO_Reg" thetaval t Gammahat], ',')

			# #5-Fold Validation
			t =
			  @elapsed x_t[:], Gamma_grid, objs = KP.x_l2reg_kFoldCV(cs, vs/S, dat_t, 5;
                    Gamma_step=Gamma_step, Gamma_min=Gamma_min, Gamma_max=Gamma_max)

			Gammahat = Gamma_grid[argmax(objs)]
			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "K5_Reg" thetaval t Gammahat], ',')

			#LOO Validation
			t =
			  @elapsed x_t[:], Gamma_grid, objs = KP.x_l2reg_kFoldCV(cs, vs/S, dat_t, S;
	                Gamma_step=Gamma_step, Gamma_min=Gamma_min, Gamma_max=Gamma_max)
			Gammahat = Gamma_grid[argmax(objs)]
			thetaval = dot(thetas, x_t)/n
			writedlm(f,  [iRun n "LOO_Reg" thetaval t Gammahat], ',')
		end
		flush(f)
	end
end

#######################

### Bayesian set-up with a non-zero mean
### costs and vs are random, but fixed over runs
function test_Gaussian(file_out, numRuns, n_grid, seed, tau0, mu0, avg_tau,
						frac_fit = .1)
	#build the sim object
	n_max = maximum(n_grid)
	Random.seed!(seed)
	cs = rand(n_max) .* 2 ./ frac_fit
	vs = 2. * avg_tau .* rand(n_max)
	thetas = randn(n_max) / sqrt(tau0) + mu0
	o = DefaultExp(cs, thetas, vs)

	#run the testharness
	#output files
	file_name = "$(file_out)_Gaussian_$(tau0)_$(mu0)_$(avg_tau)_$(seed).csv"
	f = open(file_name, "w")
	test_harness(f, numRuns, o, n_grid)
	close(f)
	return file_name
end

### The odd even set-up.
function test_OddEven(file_out, numRuns, n_grid, seed, even_v;
						even_theta=1., frac_fit=.1)
	#build the sim object
	Random.seed!(seed)
	n_max = maximum(n_grid)
	cs = 1/frac_fit .* ones(n_max)
	thetas = zeros(n_max)
	thetas[2:2:n_max] = even_theta
	vs = ones(n_max)
	vs[2:2:n_max] = even_v
	o = DefaultExp(cs, thetas, vs)

	#run the testharness
	#output files
	file_name = "$(file_out)_OddEven_$(even_theta)_$(even_v)_$(seed).csv"
	f = open(file_name, "w")
	test_harness(f, numRuns, o, n_grid)
	close(f)
	return file_name
end

### The three parts experimental set-up
function test_threePart(file_out, numRuns, n_grid, seed,
						theta_l, v_l, c_l, theta_m, v_m, c_m, theta_h, v_h, c_h,
						Gamma_min, Gamma_max)
	Random.seed!(seed)
	n_max = maximum(n_grid)
	cs = ones(n_max)
	thetas = ones(n_max)
	vs = ones(n_max)

	thetas[1:3:n_max] = theta_l
	vs[1:3:n_max] = v_l
	cs[1:3:n_max] = c_l

	thetas[2:3:n_max] = theta_m
	vs[2:3:n_max] = v_m
	cs[2:3:n_max] = c_m

	thetas[3:3:n_max] = theta_h
	vs[3:3:n_max] = v_h
	cs[3:3:n_max] = c_h

	o = DefaultExp(cs, thetas, vs)
	file_name = "$(file_out)_3part_$(theta_l)_$(v_l)_$(c_l)_$(theta_m)_$(v_m)_$(c_m)_$(theta_h)_$(v_h)_$(c_h)_$(seed).csv"
	f = open(file_name, "w")
	test_harness(f, numRuns, o, n_grid; Gamma_min=Gamma_min, Gamma_max=Gamma_max)
	close(f)
	return file_name
end

###  Reads in a theta/cs/vs specification
function test_ReadData(file_out, numRuns, n_grid, seed, param_path;
						Gamma_min = 1., Gamma_max = 20, Gamma_step=.01)
	Random.seed!(seed)
	n_max = maximum(n_grid)
	dat, header = readdlm(param_path, ',', header=true)

	#confirm that n_max works
	@assert n_max <= size(dat, 1) "Param file too short for n_max"
	cs = dat[1:n_max, 3]
	thetas = dat[1:n_max, 1]
	vs = dat[1:n_max, 2]

	o = DefaultExp(cs, thetas, vs)
	file_name = "$(file_out)_$(seed).csv"
	f = open(file_name, "w")
	test_harness(f, numRuns, o, n_grid; Gamma_min=Gamma_min, Gamma_max=Gamma_max, Gamma_step=Gamma_step)
	close(f)
	return file_name
end

#uses the three-part set-up to create density plots
function create_density_plot(file_name; n=2^17, seed=8675309)
	Random.seed!(seed)
	f = open(file_name, "w")

	cs = ones(n)
	thetas = ones(n)
	vs = ones(n)

	thetas[1:3:n] = theta_l
	vs[1:3:n] = v_l
	cs[1:3:n] = c_l

	thetas[2:3:n] = theta_m
	vs[2:3:n] = v_m
	cs[2:3:n] = c_m

	thetas[3:3:n] = theta_h
	vs[3:3:n] = v_h
	cs[3:3:n] = c_h
end

function tauDependence3PartPlot(file_name, n, seed)
	Random.seed!(seed)
	f = open("$(file_name)_$(n)_$(seed).csv", "w")
	#present the true value and relative to full-info
	writedlm(f,  ["n" "tauVal" "thetaVal" "RelFullInfo"], ',')

	#sim some data
	theta_l, v_l, c_l = 0.0, 0.1, 20.001
	theta_m, v_m, c_m = 1.0, 1.0, 20.001
	theta_h, v_h, c_h = 0.3, 4.0, 20.001

	cs = ones(n)
	thetas = ones(n)
	vs = ones(n)

	thetas[1:3:n] = theta_l
	vs[1:3:n] = v_l
	cs[1:3:n] = c_l

	thetas[2:3:n] = theta_m
	vs[2:3:n] = v_m
	cs[2:3:n] = c_m

	thetas[3:3:n] = theta_h
	vs[3:3:n] = v_h
	cs[3:3:n] = c_h

	muhat = randn(n) ./ sqrt.(vs) + thetas

	#compute full-info for scaling
	xstar, lamstar = KP.x_dual(cs, thetas)
	zstar = dot(xstar, thetas)/n

	for tau in linspace(0, 5, 500)
		rs = shrink(muhat, vs, tau)
		xs, lam = KP.x_dual(cs, rs)
		thetaVal = dot(xs, thetas)/n
		writedlm(f,  [n tau thetaVal thetaVal/zstar ], ',')
	end
	close(f)
end

########################################################
#########
#Small run to precompiles stuff
#test_ReadData("./temp/temp_PortExp", 5, [100, 150], 8675309, "./Results/param_portExp_mtn2.csv")

max_stars_repo_path: Normal Model/testHarness_Paper.jl

max_issues_repo_path: Normal Model/testHarness_Paper.jl

max_forks_repo_path: Normal Model/testHarness_Paper.jl


text:
let
	# read a sample .XDSL BN file
	# NOTE: these are generated by Genie / Smile
	#       See Smile.jl
	# Success -> Forecast

	bn = readxdsl(Pkg.dir("BayesNets", "test", "sample_bn.xdsl"))

	@test sort!(names(bn)) == [:Forecast, :Success]
	@test isempty(parents(bn, :Success))
	@test sort!(parents(bn, :Forecast)) == [:Success]

	@test isapprox(pdf(bn, :Success=>1, :Forecast=>1), 0.2*0.4)
	@test isapprox(pdf(bn, :Success=>1, :Forecast=>2), 0.2*0.4)
	@test isapprox(pdf(bn, :Success=>1, :Forecast=>3), 0.2*0.2)
	@test isapprox(pdf(bn, :Success=>2, :Forecast=>1), 0.8*0.1)
	@test isapprox(pdf(bn, :Success=>2, :Forecast=>2), 0.8*0.3)
	@test isapprox(pdf(bn, :Success=>2, :Forecast=>3), 0.8*0.6)

    # test output to text
    push!(bn, DiscreteCPD(:Test, [:Forecast], [3], [Categorical([1.0, 0.0]),
                                                    Categorical([0.0, 1.0]),
                                                    Categorical([0.1234569, 1-0.1234569])]))

    filename = tempname()
    open(filename, "w") do io
        write(io, MIME"text/plain"(), bn)
    end

    lines = readlines(filename)
    @test strip(lines[1]) == "Success Forecast Test"
    @test strip(lines[2]) == "010"
    @test strip(lines[3]) == "001"
    @test strip(lines[4]) == "000"
    @test strip(lines[5]) == "2 3 2"
    @test strip(lines[6]) == "0.2 0.4 0.4 0.1 0.3 1 0 0.1234569"
    @test length(lines) == 6

    bn2 = open(filename, "r") do io
        read(io, MIME"text/plain"(), DiscreteBayesNet)
    end
    rm(filename)

    @test isapprox(pdf(bn2, :Success=>1, :Forecast=>1, :Test=>1), 0.2*0.4*1.0)
    @test isapprox(pdf(bn2, :Success=>1, :Forecast=>1, :Test=>2), 0.2*0.4*0.0)
    @test isapprox(pdf(bn2, :Success=>1, :Forecast=>2, :Test=>1), 0.2*0.4*0.0)
    @test isapprox(pdf(bn2, :Success=>1, :Forecast=>2, :Test=>2), 0.2*0.4*1.0)
    @test isapprox(pdf(bn2, :Success=>1, :Forecast=>3, :Test=>1), 0.2*0.2*0.1234569)
    @test isapprox(pdf(bn2, :Success=>1, :Forecast=>3, :Test=>2), 0.2*0.2*(1-0.1234569))
    @test isapprox(pdf(bn2, :Success=>2, :Forecast=>1, :Test=>1), 0.8*0.1*1.0)
    @test isapprox(pdf(bn2, :Success=>2, :Forecast=>1, :Test=>2), 0.8*0.1*0.0)
    @test isapprox(pdf(bn2, :Success=>2, :Forecast=>2, :Test=>1), 0.8*0.3*0.0)
    @test isapprox(pdf(bn2, :Success=>2, :Forecast=>2, :Test=>2), 0.8*0.3*1.0)
    @test isapprox(pdf(bn2, :Success=>2, :Forecast=>3, :Test=>1), 0.8*0.6*0.1234569)
    @test isapprox(pdf(bn2, :Success=>2, :Forecast=>3, :Test=>2), 0.8*0.6*(1-0.1234569))
end


text:
using Test
using MPI

MPI.Init()

function allgatherv_array(A, counts::Vector{Cint})
    comm = MPI.COMM_WORLD
    B = MPI.Allgatherv(A, counts, comm)
end

comm = MPI.COMM_WORLD
size = MPI.Comm_size(comm)
rank = MPI.Comm_rank(comm)

# Defining this to make ones work for Char
Base.one(::Type{Char}) = '\01'

for typ in Base.uniontypes(MPI.MPIDatatype)

    A = ones(typ, mod(rank,2) + 1)
    counts = Cint[mod(i,2) + 1 for i in 0:(size-1)]
    B = allgatherv_array(A, counts)
    @test B == ones(typ, 3 * div(size,2) + mod(size,2))
end

MPI.Finalize()


text:
export DirectPowerGroup, DirectPowerGroupElem
export MultiplicativeGroup, MltGrp, MltGrpElem
export AdditiveGroup, AddGrp, AddGrpElem

###############################################################################
#
#   MltGrp/MltGrpElem & AddGrp/AddGrpElem
#   (a thin wrapper for multiplicative/additive group of a Ring)
#
###############################################################################

for (Gr, Elem) in [(:MltGrp, :MltGrpElem), (:AddGrp, :AddGrpElem)]
   @eval begin
      struct $Gr{T<:AbstractAlgebra.Ring} <: AbstractAlgebra.Group
         obj::T
      end

      struct $Elem{T<:AbstractAlgebra.RingElem} <: AbstractAlgebra.GroupElem
         elt::T
      end

      ==(g::$Elem, h::$Elem) = g.elt == h.elt
      ==(G::$Gr, H::$Gr) = G.obj == H.obj

      elem_type(::Type{$Gr{T}}) where T = $Elem{elem_type(T)}
      eltype(::Type{$Gr{T}}) where T = $Elem{elem_type(T)}
      parent_type(::Type{$Elem{T}}) where T = $Gr{parent_type(T)}
      parent(g::$Elem) = $Gr(parent(g.elt))
      length(G::$Gr{<:AbstractAlgebra.Ring}) = order(G.obj)
   end
end

MultiplicativeGroup = MltGrp
AdditiveGroup = AddGrp

(G::MltGrp)(g::MltGrpElem) = MltGrpElem(G.obj(g.elt))

function (G::MltGrp)(g)
   r = (G.obj)(g)
   isunit(r) || throw(DomainError(
      "Cannot coerce to multplicative group: $r is not invertible!"))
   return MltGrpElem(r)
end

(G::AddGrp)(g) = AddGrpElem((G.obj)(g))

(G::MltGrp)() = MltGrpElem(G.obj(1))
(G::AddGrp)() = AddGrpElem(G.obj())

inv(g::MltGrpElem) = MltGrpElem(inv(g.elt))
inv(g::AddGrpElem) = AddGrpElem(-g.elt)

for (Elem, op) in ([:MltGrpElem, :*], [:AddGrpElem, :+])
   @eval begin

      ^(g::$Elem, n::Integer) = $Elem(op(g.elt, n))

      function *(g::$Elem, h::$Elem)
         parent(g) == parent(h) || throw(DomainError(
            "Cannot multiply elements of different parents"))
         return $Elem($op(g.elt,h.elt))
      end
   end
end

show(io::IO, G::MltGrp) = print(io, "The multiplicative group of $(G.obj)")
show(io::IO, G::AddGrp) = print(io, "The additive group of $(G.obj)")

show(io::IO, g::Union{MltGrpElem, AddGrpElem}) = show(io, g.elt)

gens(F::AbstractAlgebra.Field) = elem_type(F)[gen(F)]

order(G::AddGrp{<:AbstractAlgebra.GFField}) = order(G.obj)

order(G::MltGrp{<:AbstractAlgebra.GFField}) = order(G.obj) - 1

function iterate(G::AddGrp, s=0)
   if s >= order(G)
      return nothing
   else
      g, s = iterate(G.obj,s)
      return G(g), s
   end
end

function iterate(G::MltGrp, s=0)
   if s > order(G)
      return nothing
   else
      g, s = iterate(G.obj, s)
      if g == G.obj()
         g, s = iterate(G.obj, s)
      end
      return G(g), s
   end
end

###############################################################################
#
#   DirectPowerGroup / DirectPowerGroupElem Constructors
#
###############################################################################

@doc doc"""
    DirectPowerGroup(G::Group, n::Int) <: Group
Implements `n`-fold direct product of `G`. The group operation is
`*` distributed component-wise, with component-wise identity as neutral element.
"""
struct DirectPowerGroup{N, T<:Group} <: Group
   group::T
end

DirectPowerGroup(G::Gr, N::Int) where Gr<:Group = DirectPowerGroup{N,Gr}(G)

function DirectPower(G::Group, H::Group)
   G == H || throw(DomainError(
      "Direct Powers are defined only for the same groups"))
   return DirectPowerGroup(G,2)
end

DirectPower(H::Group, G::DirectPowerGroup) = DirectPower(G,H)

function DirectPower(G::DirectPowerGroup{N}, H::Group) where N
   G.group == H || throw(DomainError(
      "Direct Powers are defined only for the same groups"))
   return DirectPowerGroup(G.group, N+1)
end

function DirectPower(R::AbstractAlgebra.Ring, n::Int)
   @warn "Creating DirectPower of the multilplicative group!"
   return DirectPowerGroup(MultiplicativeGroup(R), n)
end

struct DirectPowerGroupElem{N, T<:GroupElem} <: GroupElem
   elts::NTuple{N,T}
end

function DirectPowerGroupElem(v::Vector{GrEl}) where GrEl<:GroupElem
   return DirectPowerGroupElem(tuple(v...))
end

###############################################################################
#
#   Type and parent object methods
#
###############################################################################

elem_type(::Type{DirectPowerGroup{N,T}}) where {N,T} =
   DirectPowerGroupElem{N, elem_type(T)}

parent_type(::Type{DirectPowerGroupElem{N,T}}) where {N,T} =
   DirectPowerGroup{N, parent_type(T)}

parent(g::DirectPowerGroupElem{N, T}) where {N,T} =
   DirectPowerGroup(parent(first(g.elts)), N)

###############################################################################
#
#   AbstractVector interface
#
###############################################################################

size(g::DirectPowerGroupElem{N}) where N = (N,)
Base.IndexStyle(::Type{DirectPowerGroupElem}) = Base.LinearFast()
Base.getindex(g::DirectPowerGroupElem, i::Int) = g.elts[i]

###############################################################################
#
#   Parent object call overloads
#
###############################################################################

@doc doc"""
    (G::DirectPowerGroup)(a::Vector, check::Bool=true)
> Constructs element of the $n$-fold direct product group `G` by coercing each
> element of vector `a` to `G.group`. If `check` flag is set to `false` neither
> check on the correctness nor coercion is performed.
"""
function (G::DirectPowerGroup{N})(a::Vector, check::Bool=true) where N
   if check
      N == length(a) || throw(DomainError(
         "Can not coerce to DirectPowerGroup: lengths differ"))
      a = (G.group).(a)
   end
   return DirectPowerGroupElem(a)
end

function (G::DirectPowerGroup{N})(a::NTuple{N, GrEl}) where {N, GrEl}
   return DirectPowerGroupElem(G.group.(a))
end

(G::DirectPowerGroup{N})(a::Vararg{GrEl, N}) where {N, GrEl} = DirectPowerGroupElem(G.group.(a))

function (G::DirectPowerGroup{N})() where N
   return DirectPowerGroupElem(ntuple(i->G.group(),N))
end

(G::DirectPowerGroup)(g::DirectPowerGroupElem) = G(g.elts)

###############################################################################
#
#   Basic manipulation
#
###############################################################################

function hash(G::DirectPowerGroup{N}, h::UInt) where N
   return hash(G.group, hash(N, hash(DirectPowerGroup,h)))
end

function hash(g::DirectPowerGroupElem, h::UInt)
   return hash(g.elts, hash(DirectPowerGroupElem, h))
end

###############################################################################
#
#   String I/O
#
###############################################################################

function show(io::IO, G::DirectPowerGroup{N}) where N
   print(io, "$(N)-fold direct product of $(G.group)")
end

function show(io::IO, g::DirectPowerGroupElem)
   print(io, "[$(join(g.elts,","))]")
end

###############################################################################
#
#   Comparison
#
###############################################################################

@doc doc"""
    ==(g::DirectPowerGroup, h::DirectPowerGroup)
> Checks if two direct product groups are the same.
"""
function (==)(G::DirectPowerGroup{N}, H::DirectPowerGroup{M}) where {N,M}
   N == M || return false
   G.group == H.group || return false
   return true
end

@doc doc"""
    ==(g::DirectPowerGroupElem, h::DirectPowerGroupElem)
> Checks if two direct product group elements are the same.
"""
(==)(g::DirectPowerGroupElem, h::DirectPowerGroupElem) = g.elts == h.elts

###############################################################################
#
#   Group operations
#
###############################################################################

@doc doc"""
    *(g::DirectPowerGroupElem, h::DirectPowerGroupElem)
> Return the direct-product group operation of elements, i.e. component-wise
> operation as defined by `operations` field of the parent object.
"""
function *(g::DirectPowerGroupElem{N}, h::DirectPowerGroupElem{N}, check::Bool=true) where N
   if check
      parent(g) == parent(h) || throw(DomainError(
         "Can not multiply elements of different groups!"))
   end
   return DirectPowerGroupElem(ntuple(i-> g.elts[i]*h.elts[i], N))
end

^(g::DirectPowerGroupElem, n::Integer) = Base.power_by_squaring(g, n)

@doc doc"""
    inv(g::DirectPowerGroupElem)
> Return the inverse of the given element in the direct product group.
"""
function inv(g::DirectPowerGroupElem{N}) where {N}
   return DirectPowerGroupElem(ntuple(i-> inv(g.elts[i]), N))
end

###############################################################################
#
#   Misc
#
###############################################################################

order(G::DirectPowerGroup{N}) where N = order(G.group)^N
length(G::DirectPowerGroup) = order(G)

function iterate(G::DirectPowerGroup{N}) where N
   elts = collect(G.group)

   indices = CartesianIndices(ntuple(i -> order(G.group), N))
   idx, s = iterate(indices)
   g = DirectPowerGroupElem(ntuple(i -> elts[idx[i]], N))
   return g, (elts, indices, s)
end

function iterate(G::DirectPowerGroup{N}, state) where N
   elts, indices, s = state
   res = iterate(indices, s)
   if res == nothing
      return nothing
   else
      idx, s = res
   end
   g = DirectPowerGroupElem(ntuple(i -> elts[idx[i]], N))
   return g, (elts, indices, s)
end

eltype(::Type{DirectPowerGroup{N, G}}) where {N, G} = DirectPowerGroupElem{N, elem_type(G)}


text:
import Base: +, -

"""
    +(fa::GP, fb::GP)

Produces a GP `f` satisfying `f(x) = fa(x) + fb(x)`.
"""
+(fa::GP, fb::GP) = GP(+, fa, fb)

"""
    +(fa::Union{GP, BlockGP}, fb::Union{GP, BlockGP})

Same as above, but for a collection of GPs.
"""
+(fa::BlockGP, fb::BlockGP) = BlockGP(fa.fs .+ fb.fs)
+(fa::BlockGP, fb::GP) = BlockGP(fa.fs .+ Ref(fb))
+(fa::GP, fb::BlockGP) = BlockGP(Ref(fa) .+ fb.fs)

μ_p′(::typeof(+), fa, fb) = mean(fa) + mean(fb)
function k_p′(::typeof(+), fa, fb)
    k_out = kernel(fa) + kernel(fb) + kernel(fa, fb) + kernel(fb, fa)
    if k_out isa CompositeCrossKernel
        return CompositeKernel(+, k_out.x...)
    else
        return k_out
    end
end
k_pp′(fp::GP, ::typeof(+), fa, fb) = kernel(fp, fa) + kernel(fp, fb)
k_p′p(::typeof(+), fa, fb, fp::GP) = kernel(fa, fp) + kernel(fb, fp)

"""
    +(c, f::GP)
    +(f::GP, c)

Adding a deterministic quantity to a GP just shifts the mean.
"""
+(c, f::GP) = GP(c, zero(kernel(f)), f.gpc) + f
+(f::GP, c) = f + GP(c, zero(kernel(f)), f.gpc)

# Define negation in terms of other operations.
-(f::GP) = -1 * f
-(f::GP, c) = f + (-c)
-(c, f::GP) = c + (-f)
-(f::GP, g::GP) = f + (-g)


text:
"""
Creates a type which incorporates the mesh attributes alongside the necessary values
to solve finite element problems. It works by taking in a FEniCS mesh, working out
the necessary values, and then creating an ordering of the internal/boundary nodes
and applying the DirichletBC (via a function) to the respective nodes.
"""
mutable struct feMesh
    n_nodes::Int
    n_elements::Int
    nodes::Array{Float64, 2}
    internal_nodes::Vector
    boundary_nodes::Vector
    elements::Array{Int, 2}
    n_internal_nodes::Int
    n_boundary_nodes::Int
    node_vals::Vector

    function feMesh(mesh::Mesh,boundaryCondition::Base.Function)
        n_nodes = num_vertices(mesh)
        n_elements = num_cells(mesh)
        nodes = coordinates(mesh)
        bmesh = BoundaryMesh(mesh,"exterior")
        external_nodes = coordinates(bmesh)
        n_bc_nodes = size(external_nodes)[1]
        n_internal_nodes = n_nodes - n_bc_nodes
        node_vals = zeros(n_nodes)
        #this applied the boundary values to node_vals, and also calculates the numbering for internal nodes
        boundary_nodes, internal_nodes = find_node_number(n_nodes, n_bc_nodes, external_nodes, nodes,boundaryCondition,node_vals)
        elements_temp = cells(mesh)
        #the following commands convert the element numbering to Int64 and handle the 0/1 difference between FEniCS(Python) and Julia
        elements_temp2 = convert.(Int,elements_temp)
        elements = elements_temp2 .+1
        new(n_nodes, n_elements, nodes, internal_nodes, boundary_nodes, elements, n_internal_nodes, n_bc_nodes, node_vals)
    end
end

export feMesh

"finds node numbering for a specific FeMesh. Not currently exported as it is only
used to create the FeMesh type."
function find_node_number(n_nodes, n_bc_nodes, external_nodes, nodes, boundaryCondition::Core.Function, node_vals)
    j=1
    k=1
    count_int=0
    boundary_nodes = zeros(Int64, n_nodes)
    internal_nodes = zeros(Int64, n_nodes)

    node_ext = [external_nodes[1,:]]
    ##maybe it's more efficient to create and then pass values instead of push?
    for i=2:n_bc_nodes
        push!(node_ext,external_nodes[i,:])
    end
    node_overall = [nodes[1,:]]
    for i =2:n_nodes
        push!(node_overall,nodes[i,:])
    end

    node_number = findall((in)(node_ext),node_overall)
    for i = 1:n_nodes
        if i in node_number
            @inbounds node_vals[i] = boundaryCondition(nodes[i,1],nodes[i,2])
        else
            count_int+=1
            @inbounds internal_nodes[i]=count_int
        end
        i+=1
    end
    return boundary_nodes, internal_nodes
end