text:
"""
    windnr(p, poly::Matrix)

Determines the winding number of a point and a polygon, i.e. how many
times a polygon winds around the point.

It follows Dan Sunday: http://geomalgorithms.com/a03-_inclusion.html.
"""
function windnr(p, poly)
    @assert length(p) == 2
    @assert poly[:, 1] == poly[:, end]
    # Loop over edges
    px = p[1]
    py = p[2]
    wn = 0 # winding number, inside if >0
    len = length(poly)-2
    @inbounds for k = 1:2:len #size(poly,2)-1 # @fastmath makes it worse
        # ex1,ey1,ex2,ey2 = poly[k:k+3] # is slow...
        ex1, ey1, ex2, ey2 = poly[k], poly[k+1], poly[k+2], poly[k+3]
        # Reject edge if p totally above or below p:
        if (ey1>py && ey2>py) || (ey1<py && ey2<py)
            continue
        end
        # Check edges intersecting a horizontal ray:
        orient = leftorright(px,py,ex1,ey1,ex2,ey2)
        if up(ey1, ey2)
            if orient == -1; wn -= 1 end # p strictly left of e
        elseif down(ey1, ey2)
            if orient==1;  wn += 1 end # p strictly right of e
        end
    end
    return wn
end

up(ey1,ey2)   = ey1 < ey2
down(ey1,ey2) = ey1 > ey2

function leftorright(px,py,ex1,ey1,ex2,ey2)
    # returns:
    # -1 if on left of line
    #  0 if on line
    #  1 if on right of line
    vx,vy = ex2-ex1, ey2-ey1
    px,py =  px-ex1,  py-ey1
    sign(px * vy - py * vx)
end

"""
    inpoly(p, poly::Matrix)

Determines if a point is inside a polygon.

- p -- point (x,y) or [x,y]
- poly -- polygon vertices [x1 x2 ... xn x1
                            y1 y2 ... yn y1]

Returns true if point has an odd winding number.  This should label
points as exterior which are inside outcrops.  See test for a test.

Author: Github "Mauro3" / "Mauro"
"""
function inpoly(p, poly)
  return isodd(windnr(p, poly))
end
# inpoly(p, poly::Matrix) = isodd(windnr(p,poly))

"""
    X, Y = ndgrid(XV, YV)

This function creates a 2-D mesh-grid in a format consistent with Matlab's function ndgrid(). XV and YV are vectors.
"""
ndgrid(v::AbstractVector) = copy(v)

function ndgrid(v1::AbstractVector{T}, v2::AbstractVector{T}) where T
    m, n = length(v1), length(v2)
    v1 = reshape(v1, m, 1)
    v2 = reshape(v2, 1, n)
    (repeat(v1, 1, n), repeat(v2, m, 1))
end

function ndgrid(vs::AbstractVector{T}...) where T
    n = length(vs)
    sz = map(length, vs)
    out = ntuple(i->Array{T}(sz), n)
    s = 1
    for i=1:n
        a = out[i]::Array
        v = vs[i]
        snext = s*size(a,i)
        ndgrid_fill(a, v, s, snext)
        s = snext
    end
    out
end

meshgrid(v::AbstractVector) = meshgrid(v, v)

"""
    X, Y = meshgrid{T}(vx::AbstractVector{T}, vy::AbstractVector{T})

This function creates a 2-D mesh-grid in a format consistent with Matlab's function meshgrid(). XV and YV are vectors.
"""
function meshgrid(vx::AbstractVector{T}, vy::AbstractVector{T}) where T
    m, n = length(vy), length(vx)
    vx = reshape(vx, 1, n)
    vy = reshape(vy, m, 1)
    (repeat(vx, m, 1), repeat(vy, 1, n))
end

function meshgrid(vx::AbstractVector{T}, vy::AbstractVector{T},
    vz::AbstractVector{T}) where T
    m, n, o = length(vy), length(vx), length(vz)
    vx = reshape(vx, 1, n, 1)
    vy = reshape(vy, m, 1, 1)
    vz = reshape(vz, 1, 1, o)
    om = ones(Int, m)
    on = ones(Int, n)
    oo = ones(Int, o)
    (vx[om, :, oo], vy[:, on, oo], vz[om, on, :])
end

"""
    inpolygrid(lon, lat, poly::AbstractArray{N,2} where N)

Used to test a grid of points. Returns a mask of ones and NaNs of the same size as lon and lat.

"""
function inpolygrid(lon::AbstractArray{N, 2} where N, lat::AbstractArray{N,2} where N, poly::AbstractArray{N,2} where N)

    OUT = fill(NaN, size(lon)) # grid mask

    # Find number of polygons (separated by NaN values)
    polyidx = Base.findall(isnan, poly[1,:])
    npoly = length(polyidx) # number of polygons

    for p = 1:npoly # loop over each polygon
        # Build poly n
        if p != npoly
            polyn = poly[:, polyidx[p] + 1:polyidx[p + 1] - 1]
        elseif p == npoly
            polyn = poly[:, polyidx[p] + 1:end]
        end

        # get_limits of polyn
        minlon = minimum(polyn[1, :])
        maxlon = maximum(polyn[1, :])
        minlat = minimum(polyn[2, :])
        maxlat = maximum(polyn[2, :])

        begin
            I = Base.findall((lon .<= maxlon) .& (lon .>= minlon) .& (lat .>= minlat) .& (lat .<= maxlat))
            idx, idy = (getindex.(I, 1), getindex.(I, 2))
        end

        for (ix, iy) in zip(idx, idy)
            # @show lon[ix, iy], lat[ix, iy]
            if OUT[ix, iy] != 1.0 && inpoly([lon[ix, iy], lat[ix, iy]], polyn)
                OUT[ix, iy] = 1.0
            end
        end

    end
    return OUT

end

# TODO define interpolation for 4D grid

"""
    C = regrid(A::ClimGrid, B::ClimGrid; min=[], max=[])

Interpolate `ClimGrid` A onto the lon-lat grid of `ClimGrid` B,
where A and B are `ClimGrid`.

Min and max optional keyword are used to constraint the results of the interpolation. For example, interpolating bounded fields can lead to unrealilstic values, such as negative precipitation. In that case, one would use min=0.0 to convert negative precipitation to 0.0.

"""
function regrid(A::ClimGrid, B::ClimGrid; min=[], max=[])

    # ---------------------------------------
    # Get lat-lon information from ClimGrid B
    londest, latdest = ClimateTools.getgrids(B)

    # Get lat-lon information from ClimGrid A
    lonorig, latorig = ClimateTools.getgrids(A)

    # -----------------------------------------
    # Get initial data and time from ClimGrid A
    dataorig = A[1].data
    timeorig = get_timevec(A)#[1][Axis{:time}][:] # the function will need to loop over time

    # ---------------------
    # Allocate output Array
    OUT = zeros(Float64, (size(B.data, 1), size(B.data, 2), length(timeorig)))

    # ------------------------
    # Interpolation
    interp!(OUT, timeorig, dataorig, lonorig, latorig, londest, latdest, A.variable)

    if !isempty(min)
        OUT[OUT .<= min] .= min
    end

    if !isempty(max)
        OUT[OUT .>= max] .= max
    end

    # -----------------------
    # Construct AxisArrays and ClimGrid struct from array OUT
    latsymbol = Symbol(B.dimension_dict["lat"])
    lonsymbol = Symbol(B.dimension_dict["lon"])
    dataOut = AxisArray(OUT, Axis{lonsymbol}(B[1][Axis{lonsymbol}][:]), Axis{latsymbol}(B[1][Axis{latsymbol}][:]), Axis{:time}(timeorig))

    C = ClimateTools.ClimGrid(dataOut, longrid=B.longrid, latgrid=B.latgrid, msk=B.msk, grid_mapping=B.grid_mapping, dimension_dict=B.dimension_dict, timeattrib=A.timeattrib, model=A.model, frequency=A.frequency, experiment=A.experiment, run=A.run, project=A.project, institute=A.institute, filename=A.filename, dataunits=A.dataunits, latunits=B.latunits, lonunits=B.lonunits, variable=A.variable, typeofvar=A.typeofvar, typeofcal=A.typeofcal, varattribs=A.varattribs, globalattribs=A.globalattribs)

end

"""
    C = regrid(A::ClimGrid, londest::AbstractArray{N, 1} where N, latdest::AbstractArray{N, 1} where N)A

Interpolate `ClimGrid` A onto lat-lon grid defined by londest and latdest vector or array. If an array is provided, it is assumed that the grid is curvilinear (not a regular lon-lat grid) and the user needs to provide the dimension vector ("x" and "y") for such a grid.

"""
function regrid(A::ClimGrid, lon::AbstractArray{N, T} where N where T, lat::AbstractArray{N, T} where N where T; dimx=[], dimy=[], min=[], max=[])

    # Get lat-lon information from ClimGrid A
    lonorig, latorig = getgrids(A)

    # -----------------------------------------
    # Get initial data and time from ClimGrid A
    dataorig = A[1].data
    timeorig = A[1][Axis{:time}][:] # the function will need to loop over time

    if ndims(lon) == 1
        londest, latdest = ndgrid(lon, lat)
        dimx = lon
        dimy = lat
    elseif ndims(lon) == 2
        londest = lon
        latdest = lat
        @assert !isempty(dimx)
        @assert !isempty(dimy)
    else
        throw(error("Grid should be a vector or a grid"))
    end

    # ---------------------
    # Allocate output Array
    if ndims(lon) == 1
        OUT = zeros(Float64, (length(lon), length(lat), length(timeorig)))
    elseif ndims(lon) == 2
        OUT = zeros(Float64, (size(lon, 1), size(lon, 2), length(timeorig)))
    end

    # ------------------------
    # Interpolation
    interp!(OUT, timeorig, dataorig, lonorig, latorig, londest, latdest, A.variable)

    if !isempty(min)
        OUT[OUT .<= min] .= min
    end

    if !isempty(max)
        OUT[OUT .>= max] .= max
    end

    # -----------------------
    # Construct AxisArrays and ClimGrid struct from array OUT
    dataOut = AxisArray(OUT, Axis{:x}(dimx), Axis{:y}(dimy), Axis{:time}(timeorig))
    msk = Array{Float64}(ones((size(OUT, 1), size(OUT, 2))))

    if ndims(lon) == 1
        grid_mapping = Dict(["grid_mapping_name" => "Regular_longitude_latitude"])
        dimension_dict = Dict(["lon" => "lon", "lat" => "lat"])
    elseif ndims(lon) == 2
        grid_mapping = Dict(["grid_mapping_name" => "Curvilinear_grid"])
        dimension_dict = Dict(["lon" => "x", "lat" => "y"])
    end

    C = ClimateTools.ClimGrid(dataOut, longrid=londest, latgrid=latdest, msk=msk, grid_mapping=grid_mapping, dimension_dict=dimension_dict, timeattrib=A.timeattrib, model=A.model, frequency=A.frequency, experiment=A.experiment, run=A.run, project=A.project, institute=A.institute, filename=A.filename, dataunits=A.dataunits, latunits="degrees_north", lonunits="degrees_east", variable=A.variable, typeofvar=A.typeofvar, typeofcal=A.typeofcal, varattribs=A.varattribs, globalattribs=A.globalattribs)

end

"""
    interp!(OUT, timeorig, dataorig, lonorig, latorig, londest, latdest, vari)

Interpolation of `dataorig` onto longitude grid `londest` and latitude grid `latdest`. Used internally by `regrid`.
"""
function interp!(OUT, timeorig, dataorig, lonorig, latorig, londest, latdest, vari)

    # Ensure we have same coords type
    if typeof(lonorig[1]) != typeof(londest[1]) # means we're going towards Float32
        if typeof(dataorig[1]) != Float32
            dataorig = Float32.(dataorig)
        end
        if typeof(lonorig[1]) == Float64
            lonorig = Float32.(lonorig)
        end
        if typeof(londest[1]) == Float64
            londest = Float32.(londest)
        end
        if typeof(latorig[1]) == Float64
            latorig = Float32.(latorig)
        end
        if typeof(lonorig[1]) == Float64
            lonorig = Float32.(lonorig)
        end
    end

    # Variable
    target = Symbol(vari)

    # Destination grid
    SG = StructuredGrid(londest, latdest)

    # Solver
    n = Int(round(0.10*length(lonorig[:])))
    solver = InvDistWeight(target => (neighbors=n,))
    # solver = Kriging()#target => (maxneighbors=500,))

    # Threads.@threads for t = 1:length(timeorig)
    p = Progress(length(timeorig), 5, "Regridding: ")
    for t = 1:length(timeorig)

        SD = StructuredGridData(Dict(target => dataorig[:, :, t]), lonorig, latorig)

        problem = EstimationProblem(SD, SG, target)
        solution = solve(problem, solver)
        OUT[:, :, t] = reshape(solution.mean[target], size(londest))

        next!(p)
    end
end

"""
    getgrids(C::ClimGrid)

Returns longitude and latitude grids of ClimGrid C.
"""
function getgrids(C::ClimGrid)
    longrid = C.longrid
    latgrid = C.latgrid
    return longrid, latgrid
end

"""
    getdims(C::ClimGrid)

Returns dimensions vectors of C
"""
function getdims(C::ClimGrid)
    latsymbol, lonsymbol = ClimateTools.getsymbols(C)
    x = C[1][Axis{lonsymbol}][:]
    y = C[1][Axis{latsymbol}][:]
    timevec = get_timevec(C)

    return x, y, timevec
end

"""
    get_timevec(C::ClimGrid)

Returns time vector of ClimGrid C.
"""
get_timevec(C::ClimGrid) = C[1][Axis{:time}][:]

"""
    applymask(A::AbstractArray{N, n}, mask::AbstractArray{N, n})

Applies a mask on the array A. Return an AbstractArray{N, n}.

"""
function applymask(A::AbstractArray{N,4} where N, mask::AbstractArray{N, 2} where N)

    T = typeof(A[.!ismissing.(A)][1])
    modA = Array{T}(undef, size(A))

    for t = 1:size(A, 4) # time axis
        for lev = 1:size(A, 3) #level axis
            tmp = A[:, :, lev, t]
            tmp .*= mask # TODO use multiple dispatch of applymask
            modA[:, :, lev, t] = tmp
        end
    end

    return modA
end

function applymask(A::AbstractArray{N,3} where N, mask::AbstractArray{N, 2} where N)

    T = typeof(A[.!ismissing.(A)][1])
    modA = Array{T}(undef, size(A))

    for t = 1:size(A, 3) # time axis
        tmp = A[:, :, t]
        tmp .*= mask # TODO use multiple dispatch of applymask
        modA[:, :, t] = tmp
    end

    return modA
end

function applymask(A::AbstractArray{N,2} where N, mask::AbstractArray{N, 2} where N)

    T = typeof(A[.!ismissing.(A)][1])
    modA = Array{T}(undef, size(A))

    @assert ndims(A) == ndims(mask)
    modA = A .* mask

    return modA
end

function applymask(A::AbstractArray{N,1} where N, mask::AbstractArray{N, 1} where N)

    T = typeof(A[.!ismissing.(A)][1])
    modA = Array{T}(undef, size(A))

    modA = A .* mask

    return modA
end

macro isdefined(var)
    quote
        try
            local _ = $(esc(var))
            true
        catch err
            isa(err, UndefVarError) ? false : rethrow(err)
        end
    end
end

function permute_west_east(data::AbstractArray{N,T} where N where T, longrid)#iwest, ieast)

    dataout = similar(data)
    ieast = longrid .>= 0.0
    iwest = longrid .< 0.0

    if ndims(data) == 2

        datatmp = data[:, :]
        # datawest = reshape(datatmp[iwest], :, size(datatmp, 2))
        # dataeast = reshape(datatmp[ieast], :, size(datatmp, 2))
        dataout[:, :] = permute_west_east2D(datatmp, iwest, ieast)

    elseif ndims(data) == 3

        for t = 1:size(data, 3)
            datatmp = data[:, :, t]
            # datawest = reshape(datatmp[iwest], :, size(datatmp, 2))
            # dataeast = reshape(datatmp[ieast], :, size(datatmp, 2))
            dataout[:, :, t] = permute_west_east2D(datatmp, iwest, ieast) #vcat(datawest, dataeast)
        end

    elseif ndims(data) == 4

        for t = 1:size(data, 4)
            for l = 1:size(data, 3)
                datatmp = data[:, :, l, t]
                # datawest = reshape(datatmp[iwest], :, size(datatmp, 2))
                # dataeast = reshape(datatmp[ieast], :, size(datatmp, 2))
                dataout[:, :, l, t] = permute_west_east2D(datatmp, iwest, ieast) #vcat(datawest, dataeast)
            end
        end

    end

    return dataout

end

function permute_west_east2D(data::AbstractArray{N,2} where N, iwest, ieast)

    datawest = reshape(data[iwest], :, size(data, 2))
    dataeast = reshape(data[ieast], :, size(data, 2))
    return vcat(datawest, dataeast)

end

function permute_east_west2D(data::AbstractArray{N,2} where N, iwest, ieast)

    datawest = reshape(data[iwest], :, size(data, 2))
    dataeast = reshape(data[ieast], :, size(data, 2))
    return vcat(dataeast, datawest)

end

"""
    ensemble_mean(C::ClimGrid...)

Returns the Ensemble mean of ClimGrids C..
"""
function ensemble_mean(C; skipnan=true)

    # Create list of AxisArrays contained inside the ClimGrids
    # Climref = C[1]
    axisarrays = Array{Any}(undef, length(C))
    # unitsClims = Array{Any}(undef, length(C))

    for k = 1:length(C)
        # datatmp[.!isnan.(datatmp)
        axisarrays[k] = periodmean(C[k])[1]#[1][.!isnan.(C[k][1])], dims=3)
        # unitsClims[k] = unit(C[k][1][1])
    end

    # if length(unique(unitsClims)) != 1
    #     throw(error("ClimGrids needs to have the same physical units."))
    # end

    # ENSEMBLE MEAN
    n = length(axisarrays) # number of members
    dataout = sum(axisarrays) / n # ensemble mean

    # # reapply unit
    # dataout = [dataout][1]unitsClims[1]

    # Build AxisArray
    data_axis = ClimateTools.buildarrayinterface(dataout, C[1])

    # Ensemble metadata
    globalattribs = Dict()
    globalattribs["history"] = "Ensemble mean"
    globalattribs["models"] = ""
    for k = 1:length(C)
        globalattribs["models"] = string(globalattribs["models"], ", ", C[k].model)
    end

    # Return ClimGrid
    return ClimGrid(data_axis, longrid=C[1].longrid, latgrid=C[1].latgrid, msk=C[1].msk, grid_mapping=C[1].grid_mapping, dimension_dict=C[1].dimension_dict, timeattrib=C[1].timeattrib, model=globalattribs["models"], frequency="Climatology ensemble mean", experiment="Multi-models ensemble", run="Multi-models ensemble", project="Multi-models ensemble", institute="Multi-models ensemble", filename="muliple_files", dataunits=C[1].dataunits, latunits=C[1].latunits, lonunits=C[1].lonunits, variable=C[1].variable, typeofvar=C[1].typeofvar, typeofcal="Climatology", varattribs=C[1].varattribs, globalattribs=globalattribs)

end

"""
    ensemble_std(C::ClimGrid...)

Returns the Ensemble standard deviation of climatological means of ClimGrids C..
"""
function ensemble_std(C; skipnan=true)

    # Create list of AxisArrays contained inside the ClimGrids
    # Climref = C[1]
    axisarrays = Array{Any}(undef, length(C))
    # unitsClims = Array{Any}(undef, length(C))

    for k = 1:length(C)
        # datatmp[.!isnan.(datatmp)
        axisarrays[k] = periodmean(C[k])[1]#[1][.!isnan.(C[k][1])], dims=3)
        # unitsClims[k] = unit(C[k][1][1])
    end

    # if typeof(unitsClims[1]) != Unitful.FreeUnits{(),NoDims,nothing}
        # if length(unique(unitsClims)) != 1
        #     throw(error("ClimGrids needs to have the same physical units."))
        # end
    # end

    # ENSEMBLE STD
    dataout = std(axisarrays)

    # # reapply unit
    # dataout = [dataout][1]unitsClims[1]

    # Build AxisArray
    data_axis = ClimateTools.buildarrayinterface(dataout, C[1])

    # Ensemble metadata
    globalattribs = Dict()
    globalattribs["history"] = "Ensemble mean"
    globalattribs["models"] = ""
    for k = 1:length(C)
        globalattribs["models"] = string(globalattribs["models"], ", ", C[k].model)
    end

    # Return ClimGrid
    return ClimGrid(data_axis, longrid=C[1].longrid, latgrid=C[1].latgrid, msk=C[1].msk, grid_mapping=C[1].grid_mapping, dimension_dict=C[1].dimension_dict, timeattrib=C[1].timeattrib, model=globalattribs["models"], frequency="Climatology ensemble standard deviation", experiment="Multi-models ensemble", run="Multi-models ensemble", project="Multi-models ensemble", institute="Multi-models ensemble", filename="muliple_files", dataunits=C[1].dataunits, latunits=C[1].latunits, lonunits=C[1].lonunits, variable=C[1].variable, typeofvar=C[1].typeofvar, typeofcal="Climatology", varattribs=C[1].varattribs, globalattribs=globalattribs)

end

"""
    ensemble_max(C::ClimGrid...)

Returns the Ensemble maximum of climatological means of ClimGrids C..
"""
function ensemble_max(C; skipnan=true)

    # Create list of AxisArrays contained inside the ClimGrids
    # Climref = C[1]
    axisarrays = Array{Any}(undef, length(C))
    # unitsClims = Array{Any}(undef, length(C))

    for k = 1:length(C)
        # datatmp[.!isnan.(datatmp)
        axisarrays[k] = periodmean(C[k])[1]#[1][.!isnan.(C[k][1])], dims=3)
        # unitsClims[k] = unit(C[k][1][1])
    end

    # if typeof(unitsClims[1]) != Unitful.FreeUnits{(),NoDims,nothing}
        # if length(unique(unitsClims)) != 1
        #     throw(error("ClimGrids needs to have the same physical units."))
        # end
    # end

    # ENSEMBLE MAX
    dataout = maximum(axisarrays)

    # # reapply unit
    # dataout = [dataout][1]unitsClims[1]

    # Build AxisArray
    data_axis = ClimateTools.buildarrayinterface(dataout, C[1])

    # Ensemble metadata
    globalattribs = Dict()
    globalattribs["history"] = "Ensemble mean"
    globalattribs["models"] = ""
    for k = 1:length(C)
        globalattribs["models"] = string(globalattribs["models"], ", ", C[k].model)
    end

    # Return ClimGrid
    return ClimGrid(data_axis, longrid=C[1].longrid, latgrid=C[1].latgrid, msk=C[1].msk, grid_mapping=C[1].grid_mapping, dimension_dict=C[1].dimension_dict, timeattrib=C[1].timeattrib, model=globalattribs["models"], frequency="Climatology ensemble maximum", experiment="Multi-models ensemble", run="Multi-models ensemble", project="Multi-models ensemble", institute="Multi-models ensemble", filename="muliple_files", dataunits=C[1].dataunits, latunits=C[1].latunits, lonunits=C[1].lonunits, variable=C[1].variable, typeofvar=C[1].typeofvar, typeofcal="Climatology", varattribs=C[1].varattribs, globalattribs=globalattribs)

end

"""
    ensemble_min(C::ClimGrid...)

Returns the Ensemble minimum of climatological means of ClimGrids C..
"""
function ensemble_min(C; skipnan=true)

    # Create list of AxisArrays contained inside the ClimGrids
    # Climref = C[1]
    axisarrays = Array{Any}(undef, length(C))
    # unitsClims = Array{Any}(undef, length(C))

    for k = 1:length(C)
        # datatmp[.!isnan.(datatmp)
        axisarrays[k] = periodmean(C[k])[1]#[1][.!isnan.(C[k][1])], dims=3)
        # unitsClims[k] = unit(C[k][1][1])
    end

    # if typeof(unitsClims[1]) != Unitful.FreeUnits{(),NoDims,nothing}
        # if length(unique(unitsClims)) != 1
        #     throw(error("ClimGrids needs to have the same physical units."))
        # end
    # end

    # ENSEMBLE MIN
    dataout = minimum(axisarrays)

    # # reapply unit
    # dataout = [dataout][1]unitsClims[1]

    # Build AxisArray
    data_axis = ClimateTools.buildarrayinterface(dataout, C[1])

    # Ensemble metadata
    globalattribs = Dict()
    globalattribs["history"] = "Ensemble mean"
    globalattribs["models"] = ""
    for k = 1:length(C)
        globalattribs["models"] = string(globalattribs["models"], ", ", C[k].model)
    end

    # Return ClimGrid
    return ClimGrid(data_axis, longrid=C[1].longrid, latgrid=C[1].latgrid, msk=C[1].msk, grid_mapping=C[1].grid_mapping, dimension_dict=C[1].dimension_dict, timeattrib=C[1].timeattrib, model=globalattribs["models"], frequency="Climatology ensemble minimum", experiment="Multi-models ensemble", run="Multi-models ensemble", project="Multi-models ensemble", institute="Multi-models ensemble", filename="muliple_files", dataunits=C[1].dataunits, latunits=C[1].latunits, lonunits=C[1].lonunits, variable=C[1].variable, typeofvar=C[1].typeofvar, typeofcal="Climatology", varattribs=C[1].varattribs, globalattribs=globalattribs)

end

function maximum(arrays::Array{Any})

    dataout = Array{Any}(undef, size(arrays[1], 1), size(arrays[1], 2))
    nbsims = length(arrays)

    I = size(arrays[1], 1)
    J = size(arrays[1], 2)

    for j = 1:J
        for i = 1:I
            datatmp = Array{Float64}(undef, nbsims)
            for k = 1:nbsims

                datatmp[k] = arrays[k][i, j]

            end
            dataout[i, j] = maximum(datatmp)
        end

    end
    return dataout

end

function minimum(arrays::Array{Any})

    dataout = Array{Any}(undef, size(arrays[1], 1), size(arrays[1], 2))
    nbsims = length(arrays)

    I = size(arrays[1], 1)
    J = size(arrays[1], 2)

    for j = 1:J
        for i = 1:I
            datatmp = Array{Float64}(undef, nbsims)
            for k = 1:nbsims

                datatmp[k] = arrays[k][i, j]

            end
            dataout[i, j] = minimum(datatmp)
        end

    end
    return dataout

end

"""
    polyfit(C::ClimGrid)

Returns an array of the polynomials functions of each grid points contained in ClimGrid C.
"""
function polyfit(C::ClimGrid)

    x = 1:length(C[1][Axis{:time}][:])
    dataout = Array{Polynomials.Poly{typeof(C[1][1,1,1])}}(undef, size(C[1], 1),size(C[1], 2))

    # Reshaping for multi-threads
    datain_rshp = reshape(C[1].data, size(C[1].data,1)*size(C[1].data,2), size(C[1].data,3))
    dataout_rshp = reshape(dataout, size(dataout,1)*size(dataout,2),size(dataout,3))

    # Threads.@threads for k = 1:size(datain_rshp,1)
    for k = 1:size(datain_rshp,1)
        y = datain_rshp[k,:]
        polynomial = Polynomials.polyfit(x, y, 4)
        polynomial[0] = 0.0
        dataout_rshp[k] = polynomial

    end

    return dataout
end

"""
    polyval(C::ClimGrid, polynomial::Array{Poly{Float64}})

    Returns a ClimGrid containing the values, as estimated from polynomial function polyn.
"""
function polyval(C::ClimGrid, polynomial::Array{Poly{N},2} where N)
    datain = C[1].data
    dataout = Array{typeof(C[1][1,1,1])}(undef, (size(C[1], 1), size(C[1],2), size(C[1], 3)))

    # Reshape
    datain_rshp = reshape(datain, size(datain,1)*size(datain,2),size(datain,3))
    dataout_rshp = reshape(dataout, size(dataout,1)*size(dataout,2),size(dataout,3))
    polynomial_rshp = reshape(polynomial, size(polynomial,1)*size(polynomial,2))

    # Threads.@threads for k = 1:size(datain_rshp,1)
    for k = 1:size(datain_rshp,1)
        val = polynomial_rshp[k](datain_rshp[k,:])
        dataout_rshp[k,:] = val
    end

    dataout2 = buildarrayinterface(dataout, C)

    return ClimGrid(dataout2; longrid=C.longrid, latgrid=C.latgrid, msk=C.msk, grid_mapping=C.grid_mapping, dimension_dict=C.dimension_dict, timeattrib=C.timeattrib, model=C.model, frequency=C.frequency, experiment=C.experiment, run=C.run, project=C.project, institute=C.institute, filename=C.filename, dataunits=C.dataunits, latunits=C.latunits, lonunits=C.lonunits, variable=C.variable, typeofvar=C.typeofvar, typeofcal=C.typeofcal, varattribs=C.varattribs, globalattribs=C.globalattribs)
end

"""
    extension(url::String)

Returns the file extension of *url*.
"""

function extension(url::String)
    try
        return match(r"\.[A-Za-z0-9]+$", url).match
    catch
        return ""
    end
end

# """
#     get_units(C::ClimGrid)
#
# Returns the adequate units of Unitful of ClimGrid C.
# """
# function get_units(C)
#     return unit(C[1][1,1,1])
# end

# """
#     uconvert(a::Units, C::ClimGrid)
#
# Convert a ClimGrid [`ClimateTools.ClimGrid`](@ref) to different units. The conversion will fail if the target units `a` have a different dimension than the dimension of the quantity `x`.
# """
#
# function uconvert(a::Units, C::ClimGrid)
#
#     dataconv = uconvert.(a, C[1])
#
#     dataaxis = buildarrayinterface(dataconv, C)
#
#     ClimGrid(dataaxis, longrid=C.longrid, latgrid=C.latgrid, msk=C.msk, grid_mapping=C.grid_mapping, dimension_dict=C.dimension_dict, timeattrib=C.timeattrib, model=C.model, frequency=C.frequency, experiment=C.experiment, run=C.run, project=C.project, institute=C.institute, filename=C.filename, dataunits=string(unit(dataconv[1])), latunits=C.latunits, lonunits=C.lonunits, variable=C.variable, typeofvar=C.typeofvar, typeofcal=C.typeofcal, varattribs=C.varattribs, globalattribs=C.globalattribs)
#
# end

"""
    replace_missing!(A::AbstractArray)

Replace missing value in array A with NaNs.
"""
function replace_missing!(A::AbstractArray)

    idx = findall(ismissing, A)
    if !isempty(idx)
        A[idx] .= NaN
    end
    return A
end

"""
    convert!(A::AbstractArray)

Convert the array A to a single type, removing the missing union.
"""
function convert!(A::AbstractArray, T)

    # Convert
    # T = typeof(A[1])
    B = Array{T}(A)
    return B

end

# """
#     getunit(C::ClimGrid)
#
# Returns the physical unit of ClimGrid C
# """
# function getunit(C::ClimGrid)
#     # Get unit
#     units_all = unique(unit.(C[1]))
#     return un = units_all[.!ismissing.(units_all)]
# end
#
# """
#     getunit(A::AbstractArray)
#
# Returns the physical unit of AbstractArray A
# """
# function getunit(A::AbstractArray)
#     # Get unit
#     units_all = unique(unit.(A))
#     return un = units_all[.!ismissing.(units_all)]
# end

# function rot2lonlat(lon, lat, SP_lon, SP_lat; northpole = true)
#
#     # Copyright (c) 2013, Simon Funder
#     # All rights reserved.
#     #
#     # Redistribution and use in source and binary forms, with or without
#     # modification, are permitted provided that the following conditions are
#     # met:
#     #
#     #     * Redistributions of source code must retain the above copyright
#     #       notice, this list of conditions and the following disclaimer.
#     #     * Redistributions in binary form must reproduce the above copyright
#     #       notice, this list of conditions and the following disclaimer in
#     #       the documentation and/or other materials provided with the distribution
#     #
#     # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
#     # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
#     # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
#     # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
#     # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#     # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#     # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
#     # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
#     # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
#     # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
#     # POSSIBILITY OF SUCH DAMAGE.
#
#
#
#     # Convert degrees to radians
#     lon = (lon*π) ./ 180.0
#     lat = (lat*π) ./ 180.0
#
#     if northpole
#         SP_lon = SP_lon - 180.0
#         SP_lat = -SP_lat
#
#         θ = 90.0 + SP_lat # Rotation around y-axis
#         # θ = NP_lat # Rotation around y-axis
#         ϕ = SP_lon # Rotation around z-axis
#     else
#
#         θ = 90.0 + SP_lat # Rotation around y-axis
#         # θ = NP_lat # Rotation around y-axis
#         ϕ = SP_lon # Rotation around z-axis
#     end
#
#     ϕ = (ϕ * π) / 180.0 # Convert degrees to radians
#     θ = (θ * π) / 180.0
#
#     # Convert from spherical to cartesian coords
#     x = cos(lon) * cos(lat)
#     y = sin(lon) * cos(lat)
#     z = sin(lat)
#
#     ϕ = -ϕ
#     θ = -θ
#
#     x_new = cos(θ)*cos(ϕ)*x + sin(ϕ)*y + sin(θ).*cos(ϕ)*z
#     y_new = -cos(θ)*sin(ϕ)*x + cos(ϕ)*y - sin(θ)*sin(ϕ)*z
#     z_new = -sin(θ)*x + cos(θ)*z
#
#     # Convert cartesian back to spherical coordinates
#     lon_new = atan2(y_new, x_new)
#     lat_new = asin(z_new)
#
#     # Convert radians back to degrees
#     lon_new = (lon_new * 180.0) / π
#     lat_new = (lat_new * 180.0) / π
#
#     return lon_new, lat_new
#
#
# end

# # example for rot2lonlat
# SP_lon2 = 18
# SP_lat2 = -39.3
#
# grid_in = [[12; 12; 12] [55; 54; 53]]
# rot2lonlat(grid_in[:, 1], grid_in[:, 2], SP_lon2, SP_lat2, northpole=false)


text:
module Panels

import Term: reshape_text, join_lines, fillin, truncate, ltrim_str

import ..Renderables: AbstractRenderable, RenderablesUnion, Renderable, RenderableText
import ..Layout: pad, vstack, Padding, lvstack
import ..Style: apply_style
import ..Segments: Segment
import ..Measures: Measure
import ..Measures: height as get_height
import ..Measures: width as get_width
import ..Consoles: console_width, console_height
using ..Boxes

export Panel, TextBox

abstract type AbstractPanel <: AbstractRenderable end

# ---------------------------------------------------------------------------- #
#                                     PANEL                                    #
# ---------------------------------------------------------------------------- #
"""
    Panel

`Renderable` with a panel surrounding some content:

```
    ╭──────────╮
    │ my panel │
    ╰──────────╯
```
"""
mutable struct Panel <: AbstractPanel
    segments::Vector
    measure::Measure

    function Panel(x1, x2; kwargs...)
        # this is necessary to handle the special case in which 2 objs are passed
        # but they are not segments/measure
        return if x1 isa Vector
            new(x1, x2)
        else
            Panel(vstack(x1, x2); kwargs...)
        end
    end
end

"""
---

    Panel(;
        fit::Bool = false,
        width::Int = 88,
        height::Int = 2,
        padding::Union{Vector,Padding,NTuple} = Padding(0, 0, 0, 0),
        kwargs...,
    )

Construct a `Panel` with no content.

### Examples
```
julia> Panel(; width=10, height=5)
╭────────╮
│        │
│        │
│        │
╰────────╯

julia> Panel(; width=5, height=3)
╭───╮
│   │
╰───╯
```
"""
function Panel(;
    fit::Bool = false,
    width::Int = 88,
    height::Int = 2,
    padding::Union{Vector,Padding,NTuple} = Padding(0, 0, 0, 0),
    kwargs...,
)
    # get panel measure
    panel_measure = if fit
        # hardcoded size of empty 'fitted' panel
        Measure(3, 2)
    else
        Measure(width, height)
    end

    # get empty content measure
    content = ""
    content_measure = Measure(0, 0)

    # get padding
    padding = padding isa Padding ? padding : Padding(padding...)

    # make panel
    return Panel(
        content;
        panel_measure = panel_measure,
        content_measure = content_measure,
        Δw = padding.left + padding.right + 2,
        Δh = padding.top + padding.bottom,
        height = height,
        width = width,
        padding = padding,
        kwargs...,
    )
end

"""
---
    Panel(
        content::Union{AbstractString,AbstractRenderable};
        fit::Bool = true,
        padding::Union{Padding,NTuple} = Padding(2, 2, 0, 0),
        kwargs...,
    )

Construct a `Panel` around an `AbstractRenderable` or `AbstractString`.

This is the main Panel-creating function, it dispatches to other methods based
on the value of `fit` to either fith the `Panel` to its content or vice versa.

`kwargs` can be used to set various aspects of the `Panel`'s appearance like
the presence and style of titles, box type etc... see [render](@ref) below.
"""
function Panel(
    content::Union{AbstractString,AbstractRenderable};
    fit::Bool = true,
    padding::Union{Padding,NTuple} = Padding(2, 2, 0, 0),
    kwargs...,
)
    padding = padding isa Padding ? padding : Padding(padding...)
    return Panel(content, Val(fit), padding; kwargs...)
end

"""
---

    Panel(
        content::Union{AbstractString,AbstractRenderable},
        ::Val{true},
        padding::Padding;
        width::Union{Nothing,Int} = nothing,
        height::Union{Nothing,Int} = nothing,
        kwargs...,
        )

Construct a `Panel` fitting the content's width.

!!! warning
    If the content is larger than the console terminal's width, it will get trimmed to avoid overflow.
"""
function Panel(
    content::Union{AbstractString,AbstractRenderable},
    ::Val{true},
    padding::Padding;
    width::Union{Nothing,Int} = nothing,
    height::Union{Nothing,Int} = nothing,
    kwargs...,
)
    content = content isa AbstractRenderable ? content : RenderableText(content)

    content_measure = content.measure
    width = isnothing(width) ? 0 : width
    height = isnothing(height) ? 0 : height
    panel_measure = Measure(
        max(width, content_measure.w + padding.left + padding.right + 2),
        max(height, content_measure.h + padding.top + padding.bottom + 2),
    )

    # if panel is larger than console, fit content to panel
    panel_measure.w > console_width() && return Panel(
        content,
        Val(false),
        padding;
        width = min(panel_measure.w, console_width() - 1),
        kwargs...,
    )

    Δw = padding.left + padding.right + 2
    Δh = padding.top + padding.bottom

    return render(
        content;
        panel_measure = panel_measure,
        content_measure = content_measure,
        Δw = Δw,
        Δh = Δh,
        padding = padding,
        kwargs...,
    )
end

"""
---
    Panel(
        content::Union{AbstractString,AbstractRenderable},
        ::Val{false},
        padding::Padding;
        width::Int = 88,
        height::Union{Nothing,Int} = nothing,
        kwargs...,
    )

Construct a `Panel` fitting content to it.

!!! tip
    Content that is **too large** to fit in the given width will be trimmed.
    To avoid trimming, set ```fit=true``` when calling panel.

"""
function Panel(
    content::Union{AbstractString,AbstractRenderable},
    ::Val{false},
    padding::Padding;
    width::Int = 88,
    height::Union{Nothing,Int} = nothing,
    kwargs...,
)
    Δw = padding.left + padding.right + 2
    Δh = padding.top + padding.bottom

    # if the content is too large, resize it to fit the panel's width.
    get_width(content) > width - Δw + 1 && (content = trim_renderable(content, width - Δw))

    # get panel height
    content = content isa AbstractRenderable ? content : RenderableText(fillin(content))
    height = isnothing(height) ? content.measure.h + Δh + 2 : height
    panel_measure = Measure(width, height)

    # if the content is too tall, exclude some lines
    if content.measure.h > height - Δh - 1
        content = if content.measure.h - height - Δh - 2 > 0
            segments = [
                content.segments[1:(height - Δh - 3)]...
                Segment("... content omitted ...", "dim")
            ]
            Renderable(segments, Measure(segments))
        else
            RenderableText("")
        end
    end

    return render(
        content;
        panel_measure = panel_measure,
        content_measure = content.measure,
        Δw = Δw,
        Δh = Δh,
        padding = padding,
        kwargs...,
    )
end

"""
    Panel(renderables; kwargs...)

`Panel` constructor for creating a panel out of multiple renderables at once.
"""
Panel(renderables::Vector{RenderablesUnion}; kwargs...) =
    Panel(vstack(renderables...); kwargs...)

Panel(texts::Vector{AbstractString}; kwargs...) = Panel(join_lines(texts); kwargs...)

Panel(renderables...; kwargs...) = Panel(vstack(renderables...); kwargs...)

# ---------------------------------- render ---------------------------------- #

"""
    render(
        content;
        box::Symbol = :ROUNDED,
        style::String = "default",
        title::Union{String,Nothing} = nothing,
        title_style::Union{Nothing,String} = nothing,
        title_justify::Symbol = :left,
        subtitle::Union{String,Nothing} = nothing,
        subtitle_style::Union{Nothing,String} = nothing,
        subtitle_justify::Symbol = :left,
        justify::Symbol = :left,
        panel_measure::Measure,
        content_measure::Measure,
        Δw::Int,
        Δh::Int,
        padding::Padding,
    )::Panel

Construct a `Panel`'s content.
"""
function render(
    content;
    box::Symbol = :ROUNDED,
    style::String = "default",
    title::Union{String,Nothing} = nothing,
    title_style::Union{Nothing,String} = nothing,
    title_justify::Symbol = :left,
    subtitle::Union{String,Nothing} = nothing,
    subtitle_style::Union{Nothing,String} = nothing,
    subtitle_justify::Symbol = :left,
    justify::Symbol = :left,
    panel_measure::Measure,
    content_measure::Measure,
    Δw::Int,
    Δh::Int,
    padding::Padding,
    background = nothing,
    kwargs...,
)::Panel

    # create top/bottom rows with titles
    box = eval(box)  # get box object from symbol
    top = get_title_row(
        :top,
        box,
        title;
        width = panel_measure.w,
        style = style,
        title_style = title_style,
        justify = title_justify,
    )

    bottom = get_title_row(
        :bottom,
        box,
        subtitle;
        width = panel_measure.w,
        style = style,
        title_style = subtitle_style,
        justify = subtitle_justify,
    )

    # get left/right vertical lines
    σ(s) = apply_style("\e[0m{" * style * "}" * s * "{/" * style * "}")
    left, right = σ(box.mid.left), σ(box.mid.right)

    # get an empty padding line
    empty = [Segment(left * " "^(panel_measure.w - 2) * right)]

    # add lines with content fn
    function makecontent_line(cline)::Segment
        line = pad(apply_style(cline), panel_measure.w - Δw, justify; bg = background)
        line = pad(line, padding.left, padding.right; bg = background)

        # make line
        return Segment(left * line * right)
    end

    # check if we need extra lines at the bottom to reach target height
    n_extra = if content_measure.h < panel_measure.h - Δh - 2
        panel_measure.h - content_measure.h - Δh - 2
    else
        0
    end

    # create segments
    initial_segments::Vector{Segment} = [
        top,                                        # top border
        repeat(empty, padding.top)...,              # top padding
    ]

    # content
    content_sgs::Vector{Segment} =
        content.measure.w > 0 ? map(s -> makecontent_line(s.text), content.segments) : []

    final_segments::Vector{Segment} = [
        repeat(empty, n_extra)...,                  # lines to reach target height
        repeat(empty, padding.bottom)...,           # bottom padding
        bottom * "\e[0m",                                     # bottom border
    ]

    segments = vcat(initial_segments, content_sgs, final_segments)

    return Panel(segments, panel_measure)
end

# ---------------------------------------------------------------------------- #
#                                    TextBox                                   #
# ---------------------------------------------------------------------------- #

TextBox(args...; kwargs...) = Panel(args...; box = get(kwargs, :box, :NONE), kwargs...)

# ---------------------------------------------------------------------------- #
#                                     MISC.                                    #
# ---------------------------------------------------------------------------- #

"""
    trim_renderable(ren::Union{String, AbstractRenderable}, width::Int)

Trim a string or renderable to a max width.
"""
function trim_renderable(ren::Union{AbstractString,AbstractRenderable}, width::Int)
    return if ren isa AbstractString || ren isa RenderableText
        ren = ren isa RenderableText ? join(getfield.(ren.segments, :text), "\n") : ren
        reshape_text(ren, width)
    else
        texts = rstrip.(getfield.(ren.segments, :text))
        segs = map(
            s -> get_width(s) > width ? pad(truncate(s, width), width, :left) : s,
            texts,
        )
        lvstack(segs)
    end
end

end

ext: jl


text:
using OrdinaryDiffEq, Test

function LotkaVolterraTest_not_inplace(u,a,t)
    b,c,d = 1.0,3.0,1.0
    x,y = u[1],u[2]
    du = zeros(eltype(u),2)
    du[1] = a*x - b*x*y
    du[2] = -c*y + d*x*y
    du
end

# forward
u0 = [1.0;1.0]
tspan = (0.0,10.0)
prob = ODEProblem(LotkaVolterraTest_not_inplace,u0,tspan,1.5)

sol = solve(prob,Tsit5())
t = collect(range(0, stop=10, length=200))
using RecursiveArrayTools # for VectorOfArray
randomized = VectorOfArray([(sol(t[i]) + .01randn(2)) for i in 1:length(t)])
data = convert(Array,randomized)

# inverse
soll = solve(prob,Tsit5())

cost_function = build_loss_objective(prob,Tsit5(),L2Loss(t,data),
                                     maxiters=10000,verbose=false)
import Optim
result = Optim.optimize(cost_function, 0.0, 10.0)

# two-stage OOP regression test

function ff(du, u, p, t)
    du .= p .* u
end
function ff(u, p, t)
    p .* u
end
rc=62
ps = repeat([-0.001], rc)
tspan = (7.0, 84.0)
u0 = 3.4 .+ ones(rc)
t = collect(range(minimum(tspan), stop=maximum(tspan), length=157))
prob = ODEProblem(ff, u0, tspan, ps)
prob_oop = ODEProblem{false}(ff, u0, tspan, ps)
data = Array(solve(prob, Tsit5(), saveat = t))
ptest = ones(rc)

obj_ts = two_stage_method(prob, t, data; kernel=:Sigmoid)
@test obj_ts(ptest) ≈ 418.3400017500223
obj_ts = two_stage_method(prob_oop, t, data; kernel=:Sigmoid)
@test obj_ts(ptest) ≈ 418.3400017500223


text:
# Julia wrapper for header: /Users/jgoldfar/Documents/misc/julia/Silo/gen/../deps/usr/include/silo.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function DBShowErrors(arg1,arg2::DBErrFunc_t)
    ccall((:DBShowErrors,libsilo),Nothing,(Cint,DBErrFunc_t),arg1,arg2)
end

function DBErrString()
    ccall((:DBErrString,libsilo),Cstring,())
end

function DBErrFuncname()
    ccall((:DBErrFuncname,libsilo),Cstring,())
end

function DBErrfunc()
    ccall((:DBErrfunc,libsilo),DBErrFunc_t,())
end

function DBErrno()
    ccall((:DBErrno,libsilo),Cint,())
end

function DBErrlvl()
    ccall((:DBErrlvl,libsilo),Cint,())
end

function DBSetDataReadMask2(arg1::Culonglong)
    ccall((:DBSetDataReadMask2,libsilo),Culonglong,(Culonglong,),arg1)
end

function DBGetDataReadMask2()
    ccall((:DBGetDataReadMask2,libsilo),Culonglong,())
end

function DBGetDatatypeString(datatype)
    ccall((:DBGetDatatypeString,libsilo),Cstring,(Cint,),datatype)
end

function DBSetAllowOverwrites(allow)
    ccall((:DBSetAllowOverwrites,libsilo),Cint,(Cint,),allow)
end

function DBGetAllowOverwrites()
    ccall((:DBGetAllowOverwrites,libsilo),Cint,())
end

function DBSetAllowEmptyObjects(allow)
    ccall((:DBSetAllowEmptyObjects,libsilo),Cint,(Cint,),allow)
end

function DBGetAllowEmptyObjects()
    ccall((:DBGetAllowEmptyObjects,libsilo),Cint,())
end

function DBSetEnableChecksums(enable)
    ccall((:DBSetEnableChecksums,libsilo),Cint,(Cint,),enable)
end

function DBGetEnableChecksums()
    ccall((:DBGetEnableChecksums,libsilo),Cint,())
end

function DBSetCompression(arg1)
    ccall((:DBSetCompression,libsilo),Nothing,(Cstring,),arg1)
end

function DBGetCompression()
    ccall((:DBGetCompression,libsilo),Cstring,())
end

function DBSetFriendlyHDF5Names(enable)
    ccall((:DBSetFriendlyHDF5Names,libsilo),Cint,(Cint,),enable)
end

function DBGetFriendlyHDF5Names()
    ccall((:DBGetFriendlyHDF5Names,libsilo),Cint,())
end

function DBSetDeprecateWarnings(max)
    ccall((:DBSetDeprecateWarnings,libsilo),Cint,(Cint,),max)
end

function DBGetDeprecateWarnings()
    ccall((:DBGetDeprecateWarnings,libsilo),Cint,())
end

function DBSetUnknownDriverPriorities(arg1)
    ccall((:DBSetUnknownDriverPriorities,libsilo),Ptr{Cint},(Ptr{Cint},),arg1)
end

function DBGetUnknownDriverPriorities()
    ccall((:DBGetUnknownDriverPriorities,libsilo),Ptr{Cint},())
end

function DBRegisterFileOptionsSet(opts)
    ccall((:DBRegisterFileOptionsSet,libsilo),Cint,(Ptr{DBoptlist},),opts)
end

function DBUnregisterFileOptionsSet(opts_set_id)
    ccall((:DBUnregisterFileOptionsSet,libsilo),Cint,(Cint,),opts_set_id)
end

function DBUnregisterAllFileOptionsSets()
    ccall((:DBUnregisterAllFileOptionsSets,libsilo),Nothing,())
end

function DBVersion()
    ccall((:DBVersion,libsilo),Cstring,())
end

function DBVersionDigits(Maj,Min,Pat,Pre)
    ccall((:DBVersionDigits,libsilo),Cint,(Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint}),Maj,Min,Pat,Pre)
end

function DBVersionGE(Maj,Min,Pat)
    ccall((:DBVersionGE,libsilo),Cint,(Cint,Cint,Cint),Maj,Min,Pat)
end

function DBVariableNameValid(s)
    ccall((:DBVariableNameValid,libsilo),Cint,(Cstring,),s)
end

function DBForceSingle(arg1)
    ccall((:DBForceSingle,libsilo),Cint,(Cint,),arg1)
end

function DBOpenReal(name,dbtype,mode)
    ccall((:DBOpenReal,libsilo),Ptr{DBfile},(Cstring,Cint,Cint),name,dbtype,mode)
end

function DBCreateReal(name,mode,targ,info,dbtype)
    ccall((:DBCreateReal,libsilo),Ptr{DBfile},(Cstring,Cint,Cint,Cstring,Cint),name,mode,targ,info,dbtype)
end

function DBInqFileReal(name)
    ccall((:DBInqFileReal,libsilo),Cint,(Cstring,),name)
end

function DBClose(arg1)
    ccall((:DBClose,libsilo),Cint,(Ptr{DBfile},),arg1)
end

function DBGetToc(arg1)
    ccall((:DBGetToc,libsilo),Ptr{DBtoc},(Ptr{DBfile},),arg1)
end

function DBNewToc(arg1)
    ccall((:DBNewToc,libsilo),Cint,(Ptr{DBfile},),arg1)
end

function DBGrabDriver(arg1)
    ccall((:DBGrabDriver,libsilo),Ptr{Nothing},(Ptr{DBfile},),arg1)
end

function DBUngrabDriver(arg1,arg2)
    ccall((:DBUngrabDriver,libsilo),Cint,(Ptr{DBfile},Ptr{Nothing}),arg1,arg2)
end

function DBGetDriverType(arg1)
    ccall((:DBGetDriverType,libsilo),Cint,(Ptr{DBfile},),arg1)
end

function DBGetDriverTypeFromPath(arg1)
    ccall((:DBGetDriverTypeFromPath,libsilo),Cint,(Cstring,),arg1)
end

function DBVersionGEFileVersion(dbfile)
    ccall((:DBVersionGEFileVersion,libsilo),Cint,(Ptr{DBfile},),dbfile)
end

function DBFileVersion(dbfile)
    ccall((:DBFileVersion,libsilo),Cstring,(Ptr{DBfile},),dbfile)
end

function DBFileVersionDigits(dbfile,Maj,Min,Pat,Pre)
    ccall((:DBFileVersionDigits,libsilo),Cint,(Ptr{DBfile},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint}),dbfile,Maj,Min,Pat,Pre)
end

function DBFileVersionGE(dbfile,Maj,Min,Pat)
    ccall((:DBFileVersionGE,libsilo),Cint,(Ptr{DBfile},Cint,Cint,Cint),dbfile,Maj,Min,Pat)
end

function DBGetDir(arg1,arg2)
    ccall((:DBGetDir,libsilo),Cint,(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBSetDir(arg1,arg2)
    ccall((:DBSetDir,libsilo),Cint,(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBMkDir(arg1,arg2)
    ccall((:DBMkDir,libsilo),Cint,(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBCpDir(dbfile,srcDir,dstFile,dstDir)
    ccall((:DBCpDir,libsilo),Cint,(Ptr{DBfile},Cstring,Ptr{DBfile},Cstring),dbfile,srcDir,dstFile,dstDir)
end

function DBGuessHasFriendlyHDF5Names(f)
    ccall((:DBGuessHasFriendlyHDF5Names,libsilo),Cint,(Ptr{DBfile},),f)
end

function DBInqVarExists(arg1,arg2)
    ccall((:DBInqVarExists,libsilo),Cint,(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBUninstall(arg1)
    ccall((:DBUninstall,libsilo),Cint,(Ptr{DBfile},),arg1)
end

function DBFreeCompressionResources(dbfile,meshname)
    ccall((:DBFreeCompressionResources,libsilo),Cint,(Ptr{DBfile},Cstring),dbfile,meshname)
end

function DBSortObjectsByOffset(arg1,nobjs,obj_names,ranks)
    ccall((:DBSortObjectsByOffset,libsilo),Cint,(Ptr{DBfile},Cint,Ptr{Cstring},Ptr{Cint}),arg1,nobjs,obj_names,ranks)
end

#TODO: Re-enable or wrap using native Julia type
# function DBFilters(arg1,arg2)
#     ccall((:DBFilters,libsilo),Cint,(Ptr{DBfile},Ptr{FILE}),arg1,arg2)
# end

function DBFilterRegistration(arg1,init,open)
    ccall((:DBFilterRegistration,libsilo),Cint,(Cstring,Ptr{Nothing},Ptr{Nothing}),arg1,init,open)
end

function DBInqFileHasObjects(arg1)
    ccall((:DBInqFileHasObjects,libsilo),Cint,(Ptr{DBfile},),arg1)
end

function DBAllocCompoundarray()
    ccall((:DBAllocCompoundarray,libsilo),Ptr{DBcompoundarray},())
end

function DBAllocCurve()
    ccall((:DBAllocCurve,libsilo),Ptr{DBcurve},())
end

function DBAllocDefvars(arg1)
    ccall((:DBAllocDefvars,libsilo),Ptr{DBdefvars},(Cint,),arg1)
end

function DBAllocMultimesh(arg1)
    ccall((:DBAllocMultimesh,libsilo),Ptr{DBmultimesh},(Cint,),arg1)
end

function DBAllocMultimeshadj(arg1)
    ccall((:DBAllocMultimeshadj,libsilo),Ptr{DBmultimeshadj},(Cint,),arg1)
end

function DBAllocMultivar(arg1)
    ccall((:DBAllocMultivar,libsilo),Ptr{DBmultivar},(Cint,),arg1)
end

function DBAllocMultimat(arg1)
    ccall((:DBAllocMultimat,libsilo),Ptr{DBmultimat},(Cint,),arg1)
end

function DBAllocMultimatspecies(arg1)
    ccall((:DBAllocMultimatspecies,libsilo),Ptr{DBmultimatspecies},(Cint,),arg1)
end

function DBAllocCsgmesh()
    ccall((:DBAllocCsgmesh,libsilo),Ptr{DBcsgmesh},())
end

function DBAllocQuadmesh()
    ccall((:DBAllocQuadmesh,libsilo),Ptr{DBquadmesh},())
end

function DBAllocPointmesh()
    ccall((:DBAllocPointmesh,libsilo),Ptr{DBpointmesh},())
end

function DBAllocMeshvar()
    ccall((:DBAllocMeshvar,libsilo),Ptr{DBmeshvar},())
end

function DBAllocUcdmesh()
    ccall((:DBAllocUcdmesh,libsilo),Ptr{DBucdmesh},())
end

function DBAllocCsgvar()
    ccall((:DBAllocCsgvar,libsilo),Ptr{DBcsgvar},())
end

function DBAllocQuadvar()
    ccall((:DBAllocQuadvar,libsilo),Ptr{DBquadvar},())
end

function DBAllocUcdvar()
    ccall((:DBAllocUcdvar,libsilo),Ptr{DBucdvar},())
end

function DBAllocZonelist()
    ccall((:DBAllocZonelist,libsilo),Ptr{DBzonelist},())
end

function DBAllocPHZonelist()
    ccall((:DBAllocPHZonelist,libsilo),Ptr{DBphzonelist},())
end

function DBAllocCSGZonelist()
    ccall((:DBAllocCSGZonelist,libsilo),Ptr{DBcsgzonelist},())
end

function DBAllocEdgelist()
    ccall((:DBAllocEdgelist,libsilo),Ptr{DBedgelist},())
end

function DBAllocFacelist()
    ccall((:DBAllocFacelist,libsilo),Ptr{DBfacelist},())
end

function DBAllocMaterial()
    ccall((:DBAllocMaterial,libsilo),Ptr{DBmaterial},())
end

function DBAllocMatspecies()
    ccall((:DBAllocMatspecies,libsilo),Ptr{DBmatspecies},())
end

function DBAllocNamescheme()
    ccall((:DBAllocNamescheme,libsilo),Ptr{DBnamescheme},())
end

function DBAllocGroupelmap(arg1,arg2::DBdatatype)
    ccall((:DBAllocGroupelmap,libsilo),Ptr{DBgroupelmap},(Cint,DBdatatype),arg1,arg2)
end

function DBFreeMatspecies(arg1)
    ccall((:DBFreeMatspecies,libsilo),Nothing,(Ptr{DBmatspecies},),arg1)
end

function DBFreeMaterial(arg1)
    ccall((:DBFreeMaterial,libsilo),Nothing,(Ptr{DBmaterial},),arg1)
end

function DBFreeFacelist(arg1)
    ccall((:DBFreeFacelist,libsilo),Nothing,(Ptr{DBfacelist},),arg1)
end

function DBFreeEdgelist(arg1)
    ccall((:DBFreeEdgelist,libsilo),Nothing,(Ptr{DBedgelist},),arg1)
end

function DBFreeZonelist(arg1)
    ccall((:DBFreeZonelist,libsilo),Nothing,(Ptr{DBzonelist},),arg1)
end

function DBFreePHZonelist(arg1)
    ccall((:DBFreePHZonelist,libsilo),Nothing,(Ptr{DBphzonelist},),arg1)
end

function DBFreeCSGZonelist(arg1)
    ccall((:DBFreeCSGZonelist,libsilo),Nothing,(Ptr{DBcsgzonelist},),arg1)
end

function DBResetUcdvar(arg1)
    ccall((:DBResetUcdvar,libsilo),Nothing,(Ptr{DBucdvar},),arg1)
end

function DBFreeUcdvar(arg1)
    ccall((:DBFreeUcdvar,libsilo),Nothing,(Ptr{DBucdvar},),arg1)
end

function DBResetQuadvar(arg1)
    ccall((:DBResetQuadvar,libsilo),Nothing,(Ptr{DBquadvar},),arg1)
end

function DBFreeCsgvar(arg1)
    ccall((:DBFreeCsgvar,libsilo),Nothing,(Ptr{DBcsgvar},),arg1)
end

function DBFreeQuadvar(arg1)
    ccall((:DBFreeQuadvar,libsilo),Nothing,(Ptr{DBquadvar},),arg1)
end

function DBFreeUcdmesh(arg1)
    ccall((:DBFreeUcdmesh,libsilo),Nothing,(Ptr{DBucdmesh},),arg1)
end

function DBFreeMeshvar(arg1)
    ccall((:DBFreeMeshvar,libsilo),Nothing,(Ptr{DBmeshvar},),arg1)
end

function DBFreePointvar(arg1)
    ccall((:DBFreePointvar,libsilo),Nothing,(Ptr{DBpointvar},),arg1)
end

function DBFreePointmesh(arg1)
    ccall((:DBFreePointmesh,libsilo),Nothing,(Ptr{DBpointmesh},),arg1)
end

function DBFreeQuadmesh(arg1)
    ccall((:DBFreeQuadmesh,libsilo),Nothing,(Ptr{DBquadmesh},),arg1)
end

function DBFreeCsgmesh(arg1)
    ccall((:DBFreeCsgmesh,libsilo),Nothing,(Ptr{DBcsgmesh},),arg1)
end

function DBFreeDefvars(arg1)
    ccall((:DBFreeDefvars,libsilo),Nothing,(Ptr{DBdefvars},),arg1)
end

function DBFreeMultimesh(arg1)
    ccall((:DBFreeMultimesh,libsilo),Nothing,(Ptr{DBmultimesh},),arg1)
end

function DBFreeMultimeshadj(arg1)
    ccall((:DBFreeMultimeshadj,libsilo),Nothing,(Ptr{DBmultimeshadj},),arg1)
end

function DBFreeMultivar(arg1)
    ccall((:DBFreeMultivar,libsilo),Nothing,(Ptr{DBmultivar},),arg1)
end

function DBFreeMultimat(arg1)
    ccall((:DBFreeMultimat,libsilo),Nothing,(Ptr{DBmultimat},),arg1)
end

function DBFreeMultimatspecies(arg1)
    ccall((:DBFreeMultimatspecies,libsilo),Nothing,(Ptr{DBmultimatspecies},),arg1)
end

function DBFreeCompoundarray(arg1)
    ccall((:DBFreeCompoundarray,libsilo),Nothing,(Ptr{DBcompoundarray},),arg1)
end

function DBFreeCurve(arg1)
    ccall((:DBFreeCurve,libsilo),Nothing,(Ptr{DBcurve},),arg1)
end

function DBFreeNamescheme(arg1)
    ccall((:DBFreeNamescheme,libsilo),Nothing,(Ptr{DBnamescheme},),arg1)
end

function DBFreeMrgvar(mrgv)
    ccall((:DBFreeMrgvar,libsilo),Nothing,(Ptr{DBmrgvar},),mrgv)
end

function DBFreeMrgtree(tree)
    ccall((:DBFreeMrgtree,libsilo),Nothing,(Ptr{DBmrgtree},),tree)
end

function DBFreeGroupelmap(map)
    ccall((:DBFreeGroupelmap,libsilo),Nothing,(Ptr{DBgroupelmap},),map)
end

function DBIsEmptyCurve(curve)
    ccall((:DBIsEmptyCurve,libsilo),Cint,(Ptr{DBcurve},),curve)
end

function DBIsEmptyPointmesh(msh)
    ccall((:DBIsEmptyPointmesh,libsilo),Cint,(Ptr{DBpointmesh},),msh)
end

function DBIsEmptyPointvar(var)
    ccall((:DBIsEmptyPointvar,libsilo),Cint,(Ptr{DBpointvar},),var)
end

function DBIsEmptyMeshvar(var)
    ccall((:DBIsEmptyMeshvar,libsilo),Cint,(Ptr{DBmeshvar},),var)
end

function DBIsEmptyQuadmesh(msh)
    ccall((:DBIsEmptyQuadmesh,libsilo),Cint,(Ptr{DBquadmesh},),msh)
end

function DBIsEmptyQuadvar(var)
    ccall((:DBIsEmptyQuadvar,libsilo),Cint,(Ptr{DBquadvar},),var)
end

function DBIsEmptyUcdmesh(msh)
    ccall((:DBIsEmptyUcdmesh,libsilo),Cint,(Ptr{DBucdmesh},),msh)
end

function DBIsEmptyFacelist(fl)
    ccall((:DBIsEmptyFacelist,libsilo),Cint,(Ptr{DBfacelist},),fl)
end

function DBIsEmptyZonelist(zl)
    ccall((:DBIsEmptyZonelist,libsilo),Cint,(Ptr{DBzonelist},),zl)
end

function DBIsEmptyPHZonelist(zl)
    ccall((:DBIsEmptyPHZonelist,libsilo),Cint,(Ptr{DBphzonelist},),zl)
end

function DBIsEmptyUcdvar(var)
    ccall((:DBIsEmptyUcdvar,libsilo),Cint,(Ptr{DBucdvar},),var)
end

function DBIsEmptyCsgmesh(msh)
    ccall((:DBIsEmptyCsgmesh,libsilo),Cint,(Ptr{DBcsgmesh},),msh)
end

function DBIsEmptyCSGZonelist(zl)
    ccall((:DBIsEmptyCSGZonelist,libsilo),Cint,(Ptr{DBcsgzonelist},),zl)
end

function DBIsEmptyCsgvar(var)
    ccall((:DBIsEmptyCsgvar,libsilo),Cint,(Ptr{DBcsgvar},),var)
end

function DBIsEmptyMaterial(mat)
    ccall((:DBIsEmptyMaterial,libsilo),Cint,(Ptr{DBmaterial},),mat)
end

function DBIsEmptyMatspecies(spec)
    ccall((:DBIsEmptyMatspecies,libsilo),Cint,(Ptr{DBmatspecies},),spec)
end

function DBGetObjtypeTag(arg1)
    ccall((:DBGetObjtypeTag,libsilo),Cint,(Cstring,),arg1)
end

function DBMakeObject(arg1,arg2,arg3)
    ccall((:DBMakeObject,libsilo),Ptr{DBobject},(Cstring,Cint,Cint),arg1,arg2,arg3)
end

function DBFreeObject(arg1)
    ccall((:DBFreeObject,libsilo),Cint,(Ptr{DBobject},),arg1)
end

function DBClearObject(arg1)
    ccall((:DBClearObject,libsilo),Cint,(Ptr{DBobject},),arg1)
end

function DBAddVarComponent(arg1,arg2,arg3)
    ccall((:DBAddVarComponent,libsilo),Cint,(Ptr{DBobject},Cstring,Cstring),arg1,arg2,arg3)
end

function DBAddIntComponent(arg1,arg2,arg3)
    ccall((:DBAddIntComponent,libsilo),Cint,(Ptr{DBobject},Cstring,Cint),arg1,arg2,arg3)
end

function DBAddFltComponent(arg1,arg2,arg3::Cdouble)
    ccall((:DBAddFltComponent,libsilo),Cint,(Ptr{DBobject},Cstring,Cdouble),arg1,arg2,arg3)
end

function DBAddDblComponent(arg1,arg2,arg3::Cdouble)
    ccall((:DBAddDblComponent,libsilo),Cint,(Ptr{DBobject},Cstring,Cdouble),arg1,arg2,arg3)
end

function DBAddStrComponent(arg1,arg2,arg3)
    ccall((:DBAddStrComponent,libsilo),Cint,(Ptr{DBobject},Cstring,Cstring),arg1,arg2,arg3)
end

function DBGetComponentNames(arg1,arg2,arg3,arg4)
    ccall((:DBGetComponentNames,libsilo),Cint,(Ptr{DBfile},Cstring,Ptr{Ptr{Cstring}},Ptr{Ptr{Cstring}}),arg1,arg2,arg3,arg4)
end

function DBGetObject(arg1,arg2)
    ccall((:DBGetObject,libsilo),Ptr{DBobject},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBChangeObject(arg1,arg2)
    ccall((:DBChangeObject,libsilo),Cint,(Ptr{DBfile},Ptr{DBobject}),arg1,arg2)
end

function DBWriteObject(arg1,arg2,arg3)
    ccall((:DBWriteObject,libsilo),Cint,(Ptr{DBfile},Ptr{DBobject},Cint),arg1,arg2,arg3)
end

function DBGetComponent(arg1,arg2,arg3)
    ccall((:DBGetComponent,libsilo),Ptr{Nothing},(Ptr{DBfile},Cstring,Cstring),arg1,arg2,arg3)
end

function DBGetComponentType(arg1,arg2,arg3)
    ccall((:DBGetComponentType,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring),arg1,arg2,arg3)
end

function DBWriteComponent(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)
    ccall((:DBWriteComponent,libsilo),Cint,(Ptr{DBfile},Ptr{DBobject},Cstring,Cstring,Cstring,Ptr{Nothing},Cint,Ptr{Clong}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)
end

function DBWrite(arg1,arg2,arg3,arg4,arg5,arg6)
    ccall((:DBWrite,libsilo),Cint,(Ptr{DBfile},Cstring,Ptr{Nothing},Ptr{Cint},Cint,Cint),arg1,arg2,arg3,arg4,arg5,arg6)
end

function DBWriteSlice(dbfile,array_name,data,datatype,offsets,lengths,strides,dims,ndims)
    ccall((:DBWriteSlice,libsilo),Cint,(Ptr{DBfile},Cstring,Ptr{Nothing},Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Cint),dbfile,array_name,data,datatype,offsets,lengths,strides,dims,ndims)
end

function DBRead(arg1,arg2,arg3)
    ccall((:DBRead,libsilo),Cint,(Ptr{DBfile},Cstring,Ptr{Nothing}),arg1,arg2,arg3)
end

function DBReadVar(arg1,arg2,arg3)
    ccall((:DBReadVar,libsilo),Cint,(Ptr{DBfile},Cstring,Ptr{Nothing}),arg1,arg2,arg3)
end

function DBReadVarSlice(arg1,arg2,arg3,arg4,arg5,arg6,arg7)
    ccall((:DBReadVarSlice,libsilo),Cint,(Ptr{DBfile},Cstring,Ptr{Cint},Ptr{Cint},Ptr{Cint},Cint,Ptr{Nothing}),arg1,arg2,arg3,arg4,arg5,arg6,arg7)
end

function DBGetCompoundarray(arg1,arg2)
    ccall((:DBGetCompoundarray,libsilo),Ptr{DBcompoundarray},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBInqCompoundarray(arg1,arg2,arg3,arg4,arg5,arg6,arg7)
    ccall((:DBInqCompoundarray,libsilo),Cint,(Ptr{DBfile},Cstring,Ptr{Ptr{Cstring}},Ptr{Ptr{Cint}},Ptr{Cint},Ptr{Cint},Ptr{Cint}),arg1,arg2,arg3,arg4,arg5,arg6,arg7)
end

function DBGetVar(arg1,arg2)
    ccall((:DBGetVar,libsilo),Ptr{Nothing},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetVarByteLength(arg1,arg2)
    ccall((:DBGetVarByteLength,libsilo),Cint,(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetVarLength(arg1,arg2)
    ccall((:DBGetVarLength,libsilo),Cint,(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetVarDims(arg1,arg2,arg3,arg4)
    ccall((:DBGetVarDims,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Ptr{Cint}),arg1,arg2,arg3,arg4)
end

function DBGetVarType(arg1,arg2)
    ccall((:DBGetVarType,libsilo),Cint,(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBInqVarType(arg1,arg2)
    ccall((:DBInqVarType,libsilo),DBObjectType,(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetCurve(arg1,arg2)
    ccall((:DBGetCurve,libsilo),Ptr{DBcurve},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetDefvars(arg1,arg2)
    ccall((:DBGetDefvars,libsilo),Ptr{DBdefvars},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetMaterial(arg1,arg2)
    ccall((:DBGetMaterial,libsilo),Ptr{DBmaterial},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetMatspecies(arg1,arg2)
    ccall((:DBGetMatspecies,libsilo),Ptr{DBmatspecies},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetPointmesh(arg1,arg2)
    ccall((:DBGetPointmesh,libsilo),Ptr{DBpointmesh},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetPointvar(arg1,arg2)
    ccall((:DBGetPointvar,libsilo),Ptr{DBmeshvar},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetQuadmesh(arg1,arg2)
    ccall((:DBGetQuadmesh,libsilo),Ptr{DBquadmesh},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetQuadvar(arg1,arg2)
    ccall((:DBGetQuadvar,libsilo),Ptr{DBquadvar},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetUcdmesh(arg1,arg2)
    ccall((:DBGetUcdmesh,libsilo),Ptr{DBucdmesh},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetUcdvar(arg1,arg2)
    ccall((:DBGetUcdvar,libsilo),Ptr{DBucdvar},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetCsgmesh(arg1,arg2)
    ccall((:DBGetCsgmesh,libsilo),Ptr{DBcsgmesh},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetCsgvar(arg1,arg2)
    ccall((:DBGetCsgvar,libsilo),Ptr{DBcsgvar},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetCSGZonelist(arg1,arg2)
    ccall((:DBGetCSGZonelist,libsilo),Ptr{DBcsgzonelist},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetFacelist(arg1,arg2)
    ccall((:DBGetFacelist,libsilo),Ptr{DBfacelist},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetZonelist(arg1,arg2)
    ccall((:DBGetZonelist,libsilo),Ptr{DBzonelist},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetPHZonelist(arg1,arg2)
    ccall((:DBGetPHZonelist,libsilo),Ptr{DBphzonelist},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBInqMeshname(arg1,arg2,arg3)
    ccall((:DBInqMeshname,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring),arg1,arg2,arg3)
end

function DBInqMeshtype(arg1,arg2)
    ccall((:DBInqMeshtype,libsilo),Cint,(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBPutCompoundarray(dbfile,name,elemnames,elemlens,nelems,values,nvalues,datatype,arg1)
    ccall((:DBPutCompoundarray,libsilo),Cint,(Ptr{DBfile},Cstring,Ptr{Cstring},Ptr{Cint},Cint,Ptr{Nothing},Cint,Cint,Ptr{DBoptlist}),dbfile,name,elemnames,elemlens,nelems,values,nvalues,datatype,arg1)
end

function DBPutCurve(dbfile,name,xvals,yvals,datatype,npts,opts)
    ccall((:DBPutCurve,libsilo),Cint,(Ptr{DBfile},Cstring,Ptr{Nothing},Ptr{Nothing},Cint,Cint,Ptr{DBoptlist}),dbfile,name,xvals,yvals,datatype,npts,opts)
end

function DBPutDefvars(dbfile,name,arg1,names,types,defns,opts)
    ccall((:DBPutDefvars,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Ptr{Cstring},Ptr{Cint},Ptr{Cstring},Ptr{Ptr{DBoptlist}}),dbfile,name,arg1,names,types,defns,opts)
end

function DBPutFacelist(dbfile,arg1,nfaces,ndims,nodelist,lnodelist,origin,zoneno,shapesize,shapecnt,nshapes,types,typelist,ntypes)
    ccall((:DBPutFacelist,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Cint,Ptr{Cint},Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Cint,Ptr{Cint},Ptr{Cint},Cint),dbfile,arg1,nfaces,ndims,nodelist,lnodelist,origin,zoneno,shapesize,shapecnt,nshapes,types,typelist,ntypes)
end

#TODO: Re-wrap functions below
# function DBPutMaterial(dbfile,name,meshname,nmat,matnos,matlist,dims,ndims,mix_next,mix_mat,mix_zone,mix_vf::DBVCP1_t,mixlen,datatype,opts)
#     ccall((:DBPutMaterial,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},DBVCP1_t,Cint,Cint,Ptr{DBoptlist}),dbfile,name,meshname,nmat,matnos,matlist,dims,ndims,mix_next,mix_mat,mix_zone,mix_vf,mixlen,datatype,opts)
# end

# function DBPutMatspecies(dbfile,name,matnam,nmat,nmatspec,speclist,dims,ndims,nspecies_mf,species_mf::DBVCP1_t,mix_speclist,mixlen,datatype,optlist)
#     ccall((:DBPutMatspecies,libsilo),Cint,(Ptr{Nothing},Cstring,Cstring,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Cint,Cint,DBVCP1_t,Ptr{Cint},Cint,Cint,Ptr{DBoptlist}),dbfile,name,matnam,nmat,nmatspec,speclist,dims,ndims,nspecies_mf,species_mf,mix_speclist,mixlen,datatype,optlist)
# end

# function DBPutPointmesh(arg1,arg2,arg3,arg4::DBVCP2_t,arg5,arg6,arg7)
#     ccall((:DBPutPointmesh,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,DBVCP2_t,Cint,Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7)
# end

# function DBPutPointvar(arg1,arg2,arg3,arg4,arg5::DBVCP2_t,arg6,arg7,arg8)
#     ccall((:DBPutPointvar,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring,Cint,DBVCP2_t,Cint,Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)
# end

# function DBPutPointvar1(arg1,arg2,arg3,arg4::DBVCP1_t,arg5,arg6,arg7)
#     ccall((:DBPutPointvar1,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring,DBVCP1_t,Cint,Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7)
# end

# function DBPutQuadmesh(arg1,arg2,arg3,arg4::DBVCP2_t,arg5,arg6,arg7,arg8,arg9)
#     ccall((:DBPutQuadmesh,libsilo),Cint,(Ptr{DBfile},Cstring,Ptr{Cstring},DBVCP2_t,Ptr{Cint},Cint,Cint,Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9)
# end

# function DBPutQuadvar(arg1,arg2,arg3,arg4,arg5,arg6::DBVCP2_t,arg7,arg8,arg9::DBVCP2_t,arg10,arg11,arg12,arg13)
#     ccall((:DBPutQuadvar,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring,Cint,Ptr{Cstring},DBVCP2_t,Ptr{Cint},Cint,DBVCP2_t,Cint,Cint,Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13)
# end

# function DBPutQuadvar1(arg1,arg2,arg3,arg4::DBVCP1_t,arg5,arg6,arg7::DBVCP1_t,arg8,arg9,arg10,arg11)
#     ccall((:DBPutQuadvar1,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring,DBVCP1_t,Ptr{Cint},Cint,DBVCP1_t,Cint,Cint,Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)
# end

# function DBPutUcdmesh(arg1,arg2,arg3,arg4,arg5::DBVCP2_t,arg6,arg7,arg8,arg9,arg10,arg11)
#     ccall((:DBPutUcdmesh,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Ptr{Cstring},DBVCP2_t,Cint,Cint,Cstring,Cstring,Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)
# end

function DBPutUcdsubmesh(arg1,arg2,arg3,arg4,arg5,arg6,arg7)
    ccall((:DBPutUcdsubmesh,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring,Cint,Cstring,Cstring,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7)
end

# function DBPutUcdvar(arg1,arg2,arg3,arg4,arg5,arg6::DBVCP2_t,arg7,arg8::DBVCP2_t,arg9,arg10,arg11,arg12)
#     ccall((:DBPutUcdvar,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring,Cint,Ptr{Cstring},DBVCP2_t,Cint,DBVCP2_t,Cint,Cint,Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
# end

# function DBPutUcdvar1(arg1,arg2,arg3,arg4::DBVCP1_t,arg5,arg6::DBVCP1_t,arg7,arg8,arg9,arg10)
#     ccall((:DBPutUcdvar1,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring,DBVCP1_t,Cint,DBVCP1_t,Cint,Cint,Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)
# end

function DBPutZonelist(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)
    ccall((:DBPutZonelist,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Cint,Ptr{Cint},Cint,Cint,Ptr{Cint},Ptr{Cint},Cint),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)
end

function DBPutZonelist2(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14)
    ccall((:DBPutZonelist2,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Cint,Ptr{Cint},Cint,Cint,Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14)
end

function DBPutPHZonelist(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15)
    ccall((:DBPutPHZonelist,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Ptr{Cint},Cint,Ptr{Cint},Cstring,Cint,Ptr{Cint},Cint,Ptr{Cint},Cint,Cint,Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12,arg13,arg14,arg15)
end

function DBPutCsgmesh(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
    ccall((:DBPutCsgmesh,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Nothing},Cint,Cint,Ptr{Cdouble},Cstring,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
end

function DBPutCSGZonelist(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
    ccall((:DBPutCSGZonelist,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Nothing},Cint,Cint,Cint,Ptr{Cint},Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,arg12)
end

# function DBPutCsgvar(arg1,arg2,arg3,arg4,arg5,arg6::DBVCP2_t,arg7,arg8,arg9,arg10)
#     ccall((:DBPutCsgvar,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring,Cint,Ptr{Cstring},DBVCP2_t,Cint,Cint,Cint,Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10)
# end

function DBPrintMrgtree(tnode,walk_order,data)
    ccall((:DBPrintMrgtree,libsilo),Nothing,(Ptr{DBmrgtnode},Cint,Ptr{Nothing}),tnode,walk_order,data)
end

function DBLinearizeMrgtree(tnode,walk_order,data)
    ccall((:DBLinearizeMrgtree,libsilo),Nothing,(Ptr{DBmrgtnode},Cint,Ptr{Nothing}),tnode,walk_order,data)
end

function DBWalkMrgtree(tree,cb::DBmrgwalkcb,wdata,traversal_order)
    ccall((:DBWalkMrgtree,libsilo),Nothing,(Ptr{DBmrgtree},DBmrgwalkcb,Ptr{Nothing},Cint),tree,cb,wdata,traversal_order)
end

function DBMakeMrgtree(source_mesh_type,mrgtree_info,max_root_descendents,opts)
    ccall((:DBMakeMrgtree,libsilo),Ptr{DBmrgtree},(Cint,Cint,Cint,Ptr{DBoptlist}),source_mesh_type,mrgtree_info,max_root_descendents,opts)
end

function DBAddRegion(tree,region_name,type_info_bits,max_descendents,maps_name,nsegs,seg_ids,seg_sizes,seg_types,opts)
    ccall((:DBAddRegion,libsilo),Cint,(Ptr{DBmrgtree},Cstring,Cint,Cint,Cstring,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{DBoptlist}),tree,region_name,type_info_bits,max_descendents,maps_name,nsegs,seg_ids,seg_sizes,seg_types,opts)
end

function DBAddRegionArray(tree,nregn,regn_names,type_info_bits,maps_name,nsegs,seg_ids,seg_sizes,seg_types,opts)
    ccall((:DBAddRegionArray,libsilo),Cint,(Ptr{DBmrgtree},Cint,Ptr{Cstring},Cint,Cstring,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{DBoptlist}),tree,nregn,regn_names,type_info_bits,maps_name,nsegs,seg_ids,seg_sizes,seg_types,opts)
end

function DBSetCwr(tree,path)
    ccall((:DBSetCwr,libsilo),Cint,(Ptr{DBmrgtree},Cstring),tree,path)
end

function DBGetCwr(tree)
    ccall((:DBGetCwr,libsilo),Cstring,(Ptr{DBmrgtree},),tree)
end

function DBPutMrgtree(dbfile,mrg_tree_name,mesh_name,tree,opts)
    ccall((:DBPutMrgtree,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring,Ptr{DBmrgtree},Ptr{DBoptlist}),dbfile,mrg_tree_name,mesh_name,tree,opts)
end

# function DBPutMrgvar(dbfile,name,mrgt_name,ncomps,compnames,nregns,reg_pnames,datatype,data::DBVCP2_t,opts)
#     ccall((:DBPutMrgvar,libsilo),Cint,(Ptr{DBfile},Cstring,Cstring,Cint,Ptr{Cstring},Cint,Ptr{Cstring},Cint,DBVCP2_t,Ptr{DBoptlist}),dbfile,name,mrgt_name,ncomps,compnames,nregns,reg_pnames,datatype,data,opts)
# end

# function DBPutGroupelmap(dbfile,map_name,num_segments,groupel_types,segment_lengths,segment_ids,segment_data,segment_fracs::DBVCP2_t,fracs_data_type,opts)
#     ccall((:DBPutGroupelmap,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Ptr{Cint}},DBVCP2_t,Cint,Ptr{DBoptlist}),dbfile,map_name,num_segments,groupel_types,segment_lengths,segment_ids,segment_data,segment_fracs,fracs_data_type,opts)
# end

function DBGetMrgtree(dbfile,mrg_tree_name)
    ccall((:DBGetMrgtree,libsilo),Ptr{DBmrgtree},(Ptr{DBfile},Cstring),dbfile,mrg_tree_name)
end

function DBGetGroupelmap(dbfile,name)
    ccall((:DBGetGroupelmap,libsilo),Ptr{DBgroupelmap},(Ptr{DBfile},Cstring),dbfile,name)
end

function DBGetMrgvar(dbfile,name)
    ccall((:DBGetMrgvar,libsilo),Ptr{DBmrgvar},(Ptr{DBfile},Cstring),dbfile,name)
end

function DBGetName(ns,natnum)
    ccall((:DBGetName,libsilo),Cstring,(Ptr{DBnamescheme},Cint),ns,natnum)
end

function DBGetMultimesh(arg1,arg2)
    ccall((:DBGetMultimesh,libsilo),Ptr{DBmultimesh},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetMultimeshadj(arg1,arg2,arg3,arg4)
    ccall((:DBGetMultimeshadj,libsilo),Ptr{DBmultimeshadj},(Ptr{DBfile},Cstring,Cint,Ptr{Cint}),arg1,arg2,arg3,arg4)
end

function DBGetMultivar(arg1,arg2)
    ccall((:DBGetMultivar,libsilo),Ptr{DBmultivar},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetMultimat(arg1,arg2)
    ccall((:DBGetMultimat,libsilo),Ptr{DBmultimat},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBGetMultimatspecies(arg1,arg2)
    ccall((:DBGetMultimatspecies,libsilo),Ptr{DBmultimatspecies},(Ptr{DBfile},Cstring),arg1,arg2)
end

function DBPutMultimesh(arg1,arg2,arg3,arg4,arg5,arg6)
    ccall((:DBPutMultimesh,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Ptr{Cstring},Ptr{Cint},Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6)
end

function DBPutMultimeshadj(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,optlist)
    ccall((:DBPutMultimeshadj,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Ptr{Cint}},Ptr{Cint},Ptr{Ptr{Cint}},Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11,optlist)
end

function DBPutMultivar(arg1,arg2,arg3,arg4,arg5,arg6)
    ccall((:DBPutMultivar,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Ptr{Cstring},Ptr{Cint},Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5,arg6)
end

function DBPutMultimat(arg1,arg2,arg3,arg4,arg5)
    ccall((:DBPutMultimat,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Ptr{Cstring},Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5)
end

function DBPutMultimatspecies(arg1,arg2,arg3,arg4,arg5)
    ccall((:DBPutMultimatspecies,libsilo),Cint,(Ptr{DBfile},Cstring,Cint,Ptr{Cstring},Ptr{DBoptlist}),arg1,arg2,arg3,arg4,arg5)
end

function DBMakeOptlist(arg1::Int)
    ccall((:DBMakeOptlist,libsilo),Ptr{DBoptlist},(Cint,),arg1)
end

function DBClearOptlist(arg1)
    ccall((:DBClearOptlist,libsilo),Cint,(Ptr{DBoptlist},),arg1)
end

function DBFreeOptlist(arg1)
    ccall((:DBFreeOptlist,libsilo),Cint,(Ptr{DBoptlist},),arg1)
end

function DBAddOption(arg1,arg2,arg3)
    ccall((:DBAddOption,libsilo),Cint,(Ptr{DBoptlist},Cint,Ptr{Nothing}),arg1,arg2,arg3)
end

function DBGetOption(arg1,arg2)
    ccall((:DBGetOption,libsilo),Ptr{Nothing},(Ptr{DBoptlist},Cint),arg1,arg2)
end

function DBClearOption(arg1,arg2)
    ccall((:DBClearOption,libsilo),Cint,(Ptr{DBoptlist},Cint),arg1,arg2)
end

function DBAnnotateUcdmesh(arg1)
    ccall((:DBAnnotateUcdmesh,libsilo),Cint,(Ptr{DBucdmesh},),arg1)
end

function DBCalcExternalFacelist(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)
    ccall((:DBCalcExternalFacelist,libsilo),Ptr{DBfacelist},(Ptr{Cint},Cint,Cint,Ptr{Cint},Ptr{Cint},Cint,Ptr{Cint},Cint),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8)
end

function DBCalcExternalFacelist2(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)
    ccall((:DBCalcExternalFacelist2,libsilo),Ptr{DBfacelist},(Ptr{Cint},Cint,Cint,Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Cint,Ptr{Cint},Cint),arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)
end

function DBJoinPath(arg1,arg2)
    ccall((:DBJoinPath,libsilo),Cstring,(Cstring,Cstring),arg1,arg2)
end

function DBStringArrayToStringList(strArray,n,strList,m)
    ccall((:DBStringArrayToStringList,libsilo),Nothing,(Ptr{Cstring},Cint,Ptr{Cstring},Ptr{Cint}),strArray,n,strList,m)
end

function DBStringListToStringArray(strList,n,skipSemicolonAtIndexZero)
    ccall((:DBStringListToStringArray,libsilo),Ptr{Cstring},(Cstring,Ptr{Cint},Cint),strList,n,skipSemicolonAtIndexZero)
end

function DBIsDifferentDouble(a::Cdouble,b::Cdouble,abstol::Cdouble,reltol::Cdouble,reltol_eps::Cdouble)
    ccall((:DBIsDifferentDouble,libsilo),Cint,(Cdouble,Cdouble,Cdouble,Cdouble,Cdouble),a,b,abstol,reltol,reltol_eps)
end

function DBIsDifferentLongLong(a::Clonglong,b::Clonglong,abstol::Cdouble,reltol::Cdouble,reltol_eps::Cdouble)
    ccall((:DBIsDifferentLongLong,libsilo),Cint,(Clonglong,Clonglong,Cdouble,Cdouble,Cdouble),a,b,abstol,reltol,reltol_eps)
end

function DBFortranAccessPointer(value)
    ccall((:DBFortranAccessPointer,libsilo),Ptr{Nothing},(Cint,),value)
end

function DBFortranAllocPointer(pointer)
    ccall((:DBFortranAllocPointer,libsilo),Cint,(Ptr{Nothing},),pointer)
end

function DBFortranRemovePointer(value)
    ccall((:DBFortranRemovePointer,libsilo),Nothing,(Cint,),value)
end

function _db_safe_strdup(arg1)
    ccall((:_db_safe_strdup,libsilo),Cstring,(Cstring,),arg1)
end


text:
# Based on https://github.com/fchollet/keras/raw/master/keras/datasets/imdb.py
# Also see https://github.com/fchollet/keras/raw/master/examples/imdb_lstm.py
# Also see https://github.com/ilkarman/DeepLearningFrameworks/raw/master/common/utils.py

using Pkg; for p in ("PyCall","JSON","JLD2"); haskey(Pkg.installed(),p) || Pkg.add(p); end
using PyCall,JSON,JLD2,Random
np = pyimport("numpy")

"""

    imdb()

Load the IMDB Movie reviews sentiment classification dataset from
https://keras.io/datasets and return (xtrn,ytrn,xtst,ytst,dict) tuple.

# Keyword Arguments:
- url=https://s3.amazonaws.com/text-datasets: where to download the data (imdb.npz) from.
- dir=Pkg.dir("Knet/data"): where to cache the data.
- maxval=nothing: max number of token values to include. Words are ranked by how often they occur (in the training set) and only the most frequent words are kept. nothing means keep all, equivalent to maxval = vocabSize + pad + stoken.
- maxlen=nothing: truncate sequences after this length. nothing means do not truncate.
- seed=0: random seed for sample shuffling. Use system seed if 0.
- pad=true: whether to pad short sequences (padding is done at the beginning of sequences). pad_token = maxval.
- stoken=true: whether to add a start token to the beginning of each sequence. start_token = maxval - pad.
- oov=true: whether to replace words >= oov_token with oov_token (the alternative is to skip them). oov_token = maxval - pad - stoken.

"""
function imdb(;
              url = "https://s3.amazonaws.com/text-datasets",
              dir = joinpath(@__DIR__, "imdb"),
              data="imdb.npz",
              dict="imdb_word_index.json",
              jld2="imdb.jld2",
              maxval=nothing,
              maxlen=nothing,
              seed=0, oov=true, stoken=true, pad=true
              )
    global _imdb_xtrn,_imdb_ytrn,_imdb_xtst,_imdb_ytst,_imdb_dict
    if !(@isdefined _imdb_xtrn)
        isdir(dir) || mkpath(dir)
        jld2path = joinpath(dir,jld2)
        if !isfile(jld2path)
            @info("Downloading IMDB...")
            datapath = joinpath(dir,data)
            dictpath = joinpath(dir,dict)
            isfile(datapath) || download("$url/$data",datapath)
            isfile(dictpath) || download("$url/$dict",dictpath)
            d = np.load(datapath, allow_pickle=true)
            _imdb_xtrn = map(a->np.asarray(a,dtype=np.int32), get(d, "x_train"))
            _imdb_ytrn = Array{Int8}(get(d, "y_train") .+ 1)
            _imdb_xtst = map(a->np.asarray(a,dtype=np.int32), get(d, "x_test"))
            _imdb_ytst = Array{Int8}(get(d, "y_test") .+ 1)
            _imdb_dict = Dict{String,Int32}(JSON.parsefile(dictpath))
            JLD2.@save jld2path _imdb_xtrn _imdb_ytrn _imdb_xtst _imdb_ytst _imdb_dict
            #rm(datapath)
            #rm(dictpath)
        end
        @info("Loading IMDB...")
        JLD2.@load jld2path _imdb_xtrn _imdb_ytrn _imdb_xtst _imdb_ytst _imdb_dict
    end
    if seed != 0; Random.seed!(seed); end
    xs = [_imdb_xtrn;_imdb_xtst]
    if maxlen == nothing; maxlen = maximum(map(length,xs)); end
    if maxval == nothing; maxval = maximum(map(maximum,xs)) + pad + stoken; end
    if pad; pad_token = maxval; maxval -= 1; end
    if stoken; start_token = maxval; maxval -= 1; end
    if oov; oov_token = maxval; end
    function _imdb_helper(x,y)
        rp = randperm(length(x))
        newy = y[rp]
        newx = similar(x)
        for i in 1:length(x)
            xi = x[rp[i]]
            if oov
                xi = map(w->(w<=oov_token ? w : oov_token), xi)
            else
                xi = filter(w->(w<=oov_token), xi)
            end
            if stoken
                xi = [ start_token; xi ]
            end
            if length(xi) > maxlen
                xi = xi[end-maxlen+1:end]
            end
            if pad && length(xi) < maxlen
                xi = append!(repeat([pad_token], maxlen-length(xi)), xi)
            end
            newx[i] = xi
        end
        newx,newy
    end
    xtrn,ytrn = _imdb_helper(_imdb_xtrn,_imdb_ytrn)
    xtst,ytst = _imdb_helper(_imdb_xtst,_imdb_ytst)
    return xtrn,ytrn,xtst,ytst,_imdb_dict
end


text:
using SQLite

loc = dirname(@__FILE__)

if isfile(joinpath(loc, "julia_packages.db"))
    rm(joinpath(loc, "julia_packages.db"))
end

db = SQLite.DB(joinpath(loc, "julia_packages.db"))

SQLite.execute!(db, """
    create table if not exists [Packages] (
        [Name] varchar(50) not null,
        [URL] varchar(200) not null,
        [Owner] varchar(100) default null
    );
""")

SQLite.execute!(db, """
    create table if not exists [Versions] (
        [Package] varchar(50) not null,
        [Version] varchar(15) not null,
        [SHA1] varchar(50) not null,
        [Dependency] varchar(50) default null,
        [LowerBound] varchar(15) default null,
        [UpperBound] varchar(15) default null,
        [Platform] varchar(7) default null
    );
""")

pkg_insert = SQLite.Stmt(db, "insert into Packages values (?1, ?2, ?3);")
vers_insert = SQLite.Stmt(db, "insert into Versions values (?1, ?2, ?3, ?4, ?5, ?6, ?7);")

if isdir(joinpath(loc, "METADATA.jl"))
    rm(joinpath(loc, "METADATA.jl"), recursive=true)
end

cd(loc) do
    run(`git clone -q --depth 1 -b metadata-v2 https://github.com/JuliaLang/METADATA.jl.git`)
end

const GHURL = r"^(?:git@|git://|https://(?:[\w\.\+\-]+@)?)github.com[:/](([^/].+)/(.+?))(?:\.git)?$"i

for pkg in readdir(joinpath(loc, "METADATA.jl"))
    pkgdir = joinpath(loc, "METADATA.jl", pkg)

    (!isdir(pkgdir) || pkg == ".git" || pkg == ".test") && continue

    if isfile(joinpath(pkgdir, "url"))
        url = readchomp(joinpath(pkgdir, "url"))
    else
        warn("$pkg will be omitted from the database: does not have a URL")
        continue
    end

    if !isdir(joinpath(pkgdir, "versions"))
        warn("$pkg will be omitted from the database: no available versions")
        continue
    end

    SQLite.bind!(pkg_insert, 1, pkg)
    SQLite.bind!(pkg_insert, 2, url)
    SQLite.bind!(pkg_insert, 3, ismatch(GHURL, url) ? match(GHURL, url).captures[2] : SQLite.NULL)
    SQLite.execute!(pkg_insert)

    for ver in readdir(joinpath(pkgdir, "versions"))
        verdir = joinpath(pkgdir, "versions", ver)

        if isfile(joinpath(verdir, "sha1"))
            sha = readchomp(joinpath(verdir, "sha1"))
        else
            warn("$pkg version $ver will be omitted: no corresponding SHA-1")
            continue
        end

        for (i, val) in zip(1:3, (pkg, ver, sha))
            SQLite.bind!(vers_insert, i, val)
        end

        if isfile(joinpath(verdir, "requires"))
            lines = map(chomp, readlines(joinpath(verdir, "requires")))
            filter!(s -> !isempty(s) && !all(isspace, s), lines)

            for req in lines
                m = match(r"^(@\w+\s+)?(\w+)(\s+[\d.-]+)?(\s+[\d.-]+)?", req)
                m === nothing && continue

                plt, dep, lb, ub = m.captures

                SQLite.bind!(vers_insert, 4, dep)
                SQLite.bind!(vers_insert, 5, lb === nothing ? SQLite.NULL : lstrip(lb))
                SQLite.bind!(vers_insert, 6, ub === nothing ? SQLite.NULL : lstrip(ub))
                SQLite.bind!(vers_insert, 7, plt === nothing ? SQLite.NULL : rstrip(plt)[2:end])

                SQLite.execute!(vers_insert)
            end
        else
            for i = 4:6
                SQLite.bind!(vers_insert, i, SQLite.NULL)
            end

            SQLite.execute!(vers_insert)
        end
    end
end

for tbl in (:Packages, :Versions)
    @assert size(SQLite.query(db, "select * from $tbl limit 1;"), 1) > 0
end

rm(joinpath(loc, "METADATA.jl"), recursive=true)

max_stars_repo_name: ararslan/JuliaPkgDb

max_issues_repo_name: ararslan/JuliaPkgDb

max_forks_repo_name: ararslan/JuliaPkgDb


text:
""" mathies.jl -- helpful geometry constants and aliases
    author: Daniel H. Morgan
    version: 0.1.1
    date: April 22, 2019
"""
# Shortcuts and Aliases

#1 km = (1/1.609344) mi = 0.62137119 mi
const KM_PER_MILE_RATIO = 1.609344
const MILE_PER_KM_RATIO = 0.62137119

## Math Constants
#### square roots of integers 2, 3, 5, 6, 8, and 10
    const SQRT2 = sqrt(2)
    const SQRT3 = sqrt(3)
    const SQRT5 = sqrt(5)
    const SQRT6 = sqrt(6)
    const SQRT8 = sqrt(8)
    const SQRT10 = sqrt(10)
### variations of phi
    const φ = (sqrt(5) - 1) / 2        # \varphi, inverse golden ratio 0.618...
    ϕ = const Φ = (sqrt(5) + 1) / 2    # \phi or \Phi, golden ratio 1.618...
    const ΦSQ =  1 + ((sqrt(5) + 1) / 2)  # \PhiSQ, phi squared, 2.618...
    const HALFφ= φ/2.0
    const HALFΦ = Φ/2.0
    const HALFΦSQ = ΦSQ/2.0
    const SQRTφ = sqrt(φ)
    const SQRTΦ = sqrt(Φ)
    const SQRTΦSQ = sqrt(ΦSQ)
### fractions of pi
    const πOVER2 = pi / 2
    const πOVER3 = pi / 3
    const πOVER4 = pi / 4
    const πOVER5 = pi / 5
    const πOVER6 = pi / 6
    const πOVER10 = pi / 10
## Cartesian Geometric Points
### 3D-Graphics orientation where:
    # a cube of edge-length 2, as seen from straight-on has its
    #   right face (+X) centered at [1, 0, 0], its
    #     top face (+Y) at [0, 1, 0], and its
    #     front face (+Z) centererd at [0, 0, 1];
    #     the left face is -X, bottom is -Y, and rear is -Z;
    #   +T, +U, +V, +W are vertices at right-top-front, right-bottom-rear,
    #     left-top-rear, and left-bottom-front, respectively;
    #   N, O, P, Q, R, S are the midpoints of the edges where:
    #     +N is the midpoint of top edge of front face, +O on bottom of front,
    #     +P on right edge of front face, +Q is right edge of right face,
    #     +R is top edge of right face, +S is top edge of left face
const CTR = [0, 0, 0]
##### center points X Y Z, vertices T U V W, and edge midpoints N O P Q R S
const X = [ 1,  0,  0]
const Y = [ 0,  1,  0]
const Z = [ 0,  0,  1]
const T = [ 1,  1,  1]
const U = [ 1, -1, -1]
const V = [-1,  1, -1]
const W = [-1, -1,  1]
const N = [ 0,  1,  1]
const O = [ 0, -1,  1]
const P = [ 1,  0,  1]
const Q = [ 1,  0, -1]
const R = [ 1,  1,  0]
const S = [-1,  1,  0]

""" GEOGRAPHIC CARTESIAN: North is Z+, 180 East is Y+, 90 East is X+
const X = [ 1,  0,  0]
const Y = [ 0,  1,  0]
const Z = [ 0,  0,  1]
const T = [ 1,  1,  1]
const U = [ 1, -1, -1]
const V = [-1,  1, -1]
const W = [-1, -1,  1]

const N = [ 0,  1,  1]
const O = [ 0, -1,  1]
const P = [ 1,  0,  1]
const Q = [ 1,  0, -1]
const R = [ 1,  1,  0]
const S = [-1,  1,  0]
"""

#### each vector transformed by magnitudes phi and 1/phi
const ΦX  = Φ * X, const φX = φ * X
const ΦY  = Φ * Y, const φY = φ * Y
const ΦZ  = Φ * Z, const φZ = φ * Z
const ΦT  = Φ * T, const φT = φ * T
const ΦU = Φ * U, const φU = φ * U
const ΦV = Φ * V, const φV = φ * V
const ΦW = Φ * W, const φW = φ * W
const ΦN = Φ * N, const φN = φ * N
const ΦO = Φ * O, const φO = φ * O
const ΦP = Φ * P, const φP = φ * P
const ΦQ = Φ * Q, const φQ = φ * Q
const ΦR = Φ * R, const φR = φ * R
const ΦS = Φ * S, const φS = φ * S
#### variations on N through S for use as dodecahedral vertices
const Nφ = [ 0,  φ,  Φ ]
const Oφ = [ 0, -φ,  Φ ]
const Pφ = [ Φ,  0,  φ ]
const Qφ = [ Φ,  0, -φ ]
const Rφ = [ Φ,  φ,  0 ]
const Sφ = [-φ,  Φ,  0 ]
#### variations on N through S for use as icosohedral vertices
const NΦ = [ 0,  Φ,  1 ]
const OΦ = [ 0, -Φ,  1 ]
const PΦ = [ 1,  0,  Φ ]
const QΦ = [ 1,  0, -Φ ]
const RΦ = [ Φ,  1,  0 ]
const SΦ = [-Φ,  1,  0 ]
# Polyhedra
const TETRA_VERTS = [T, U, V, W]
const OCTA_VERTS = [X, Y, Z, -X, -Y, -Z]
const CUBE_VERTS = [T, U, V, W, -T, -U, -V, -W]
const DODECA_VERTS = [T, U, V, W, -T, -U, -V, -W,
                      Nφ, Oφ, Pφ, Qφ, Rφ, Sφ,
                      -Nφ, -Oφ, -Pφ, -Qφ, -Rφ, -Sφ]
const ICOSO_VERTS = [NΦ, OΦ, PΦ, QΦ, RΦ, SΦ,
                     -NΦ, -OΦ, -PΦ, -QΦ, -RΦ, -SΦ]
const TRIACONTA_VERTS = vcat(DODECA_VERTS, ICOSO_VERTS)
const RHOMBIC_DODECA_VERTS = vcat(CUBE_VERTS, 1.5*OCTA_VERTS)

# GEOSPATIAL -- Z+ takes value Y+ and Y+ takes Z- from graphics-orientation
# icosohedral vertices
# TODO: composite transformation indicated in comment above; apply to [TODO: Typed ] arrays
#    of constants organized similar to above non-arrayed, non-typed constants
const GNΦ = [ 0, -1,  Φ ]
const GOΦ = [ 0,  1,  Φ ]
const GPΦ = [ 1, -Φ,  0 ]
const GQΦ = [-1, -Φ,  0 ]
const GRΦ = [ Φ,  0,  1 ]
const GSΦ = [-Φ,  0,  1 ]

GEO_ICOSO_VERTS = [-GNΦ, -GOΦ, -GPΦ, -GQΦ, -GRΦ, -GSΦ, GNΦ, GOΦ, GPΦ, GQΦ, GRΦ, GSΦ]

earth_radius = 6378137 # 6,378,137 meters, roughly 6,378 Km

## Aliases
### math constants
#### square roots of integers 2, 3, 5, 6, 8, and 10
    sq2 = SQRT2
    sq3 = SQRT3
    sq5 = SQRT5
    sq6 = SQRT6
    sq8 = SQRT8
    sq10 = SQRT10
#### 1/phi, phi, and phi^2, with their halves and square roots
    fe = φ
    fi = Φ
    fu = ΦSQ
    hafe = HALFφ
    hafi = HALFΦ
    hafu = HALFΦSQ
    sqfe = SQRTΦ
    sqfi = SQRTΦ
    sqfu = SQRTΦSQ
#### N through S variations
    nfi, ofi, pfi, qfi, rfi, sfi = NΦ, OΦ, PΦ, QΦ, RΦ, SΦ
    nfe, ofe, pfe, qfe, rfe, sfe = Nφ, Oφ, Pφ, Qφ, Rφ, Sφ
#### fractions of pi
    pio2 = πOVER2
    pio3 = πOVER3
    pio4 = πOVER4
    pio5 = πOVER5
    pio6 = πOVER6
    pio10 = πOVER10
included_message = "mathies.jl inclusion concluded"

max_stars_repo_name: sespaces/modjin

max_issues_repo_name: sespaces/modjin

max_forks_repo_name: sespaces/modjin


text:
module RulesMvNormalMeanPrecisionPrecisionTest

using Test
using ReactiveMP
using Random

import ReactiveMP: @test_rules

@testset "rules:MvNormalMeanPrecision:precision" begin

    @testset "Variational: (q_out::PointMass, q_μ::MultivariateNormalDistributionsFamily)" begin

        @test_rules [ with_float_conversions = true, float32_atol = 1e-5 ] MvNormalMeanPrecision(:Λ, Marginalisation) [
            (input = (q_out = PointMass([ 1.0, 2.0 ]), q_μ = MvNormalMeanPrecision([ 3.0, 5.0 ], [ 3.0 2.0; 2.0 4.0 ])), output = Wishart(4.0, [ 75/73 -46/73; -46/73 36/73 ])),
            (input = (q_out = MvNormalMeanPrecision([1.0; 2.0], [3.0 2.0; 2.0 4.0]), q_μ = PointMass([3.0; 5.0])), output = Wishart(4.0, [ 75/73 -46/73; -46/73 36/73 ])),
            (input = (q_out = MvNormalMeanPrecision([1.0; 2.0], [3.0 2.0; 2.0 4.0]), q_μ = MvNormalMeanPrecision([3.0; 5.0], [3.0 2.0; 2.0 4.0])), output = Wishart(4.0, [ 39/74 -11/37; -11/37 10/37 ])),
            (input = (q_out = MvNormalMeanPrecision([1.0; 2.0; 3.0], [3.0 0.0 0.0; 0.0 2.0 0.0; 0.0 0.0 4.0]), q_μ = MvNormalMeanPrecision([3.0; 5.0; -2.0], [3.0 0.0 0.0; 0.0 2.0 0.0; 0.0 0.0 4.0])), output = Wishart(5.0, [ 15/11 -3/22 5/11; -3/22 19/22 5/11; 5/11 5/11 16/33 ]))
        ]
        @test_rules [ with_float_conversions = true, float32_atol = 1e-5 ] MvNormalMeanPrecision(:Λ, Marginalisation) [
            (input = (q_out = PointMass([ 1.0, 2.0 ]), q_μ = MvNormalMeanCovariance([ 3.0, 5.0 ], [ 3.0 2.0; 2.0 4.0 ])), output = Wishart(4.0, [ 13/27 -8/27; -8/27 7/27 ])),
            (input = (q_out = MvNormalMeanCovariance([1.0; 2.0], [3.0 2.0; 2.0 4.0]), q_μ = PointMass([3.0; 5.0])), output = Wishart(4.0, [ 13/27 -8/27; -8/27 7/27 ])),
            (input = (q_out = MvNormalMeanCovariance([1.0; 2.0], [3.0 2.0; 2.0 4.0]), q_μ = MvNormalMeanCovariance([3.0; 5.0], [3.0 2.0; 2.0 4.0])), output = Wishart(4.0, [ 17/70 -1/7; -1/7 1/7 ])),
            (input = (q_out = MvNormalMeanCovariance([1.0; 2.0; 3.0], [3.0 0.0 0.0; 0.0 2.0 0.0; 0.0 0.0 4.0]), q_μ = MvNormalMeanCovariance([3.0; 5.0; -2.0], [3.0 0.0 0.0; 0.0 2.0 0.0; 0.0 0.0 4.0])), output = Wishart(5.0, [ 51/338 -6/169 5/169; -6/169 115/676 45/676; 5/169 45/676 47/676 ]))
        ]
        @test_rules [ with_float_conversions = true, float32_atol = 1e-5 ] MvNormalMeanPrecision(:Λ, Marginalisation) [
            (input = (q_out = PointMass([ 1.0, 2.0 ]), q_μ = MvNormalWeightedMeanPrecision([ 3.0, 5.0 ], [ 3.0 2.0; 2.0 4.0 ])), output = Wishart(4.0, [ 73/67 -26/67; -26/67 68/67 ])),
            (input = (q_out = MvNormalWeightedMeanPrecision([1.0; 2.0], [3.0 2.0; 2.0 4.0]), q_μ = PointMass([3.0; 5.0])), output = Wishart(4.0, [ 165/163 -106/163; -106/163 76/163 ])),
            (input = (q_out = MvNormalWeightedMeanPrecision([1.0; 2.0], [3.0 2.0; 2.0 4.0]), q_μ = MvNormalWeightedMeanPrecision([3.0; 5.0], [3.0 2.0; 2.0 4.0])), output = Wishart(4.0, [ 73/70 11/35; 11/35 34/35 ])),
            (input = (q_out = MvNormalWeightedMeanPrecision([1.0; 2.0; 3.0], [3.0 0.0 0.0; 0.0 2.0 0.0; 0.0 0.0 4.0]), q_μ = MvNormalWeightedMeanPrecision([3.0; 5.0; -2.0], [3.0 0.0 0.0; 0.0 2.0 0.0; 0.0 0.0 4.0])), output = Wishart(5.0, [ 459/338 -36/169 60/169; -36/169 115/169 90/169; 60/169 90/169 188/169 ]))
        ]

    end

end

end