text:
struct PriceCurve{N,T <: AbstractFloat} <: AbstractVector{T}
    λ::Vector{T}

    function PriceCurve(λ::AbstractVector)
        N = length(λ)
        T = eltype(λ)
        return new{N,T}(λ)
    end
end
Base.iterate(curve::PriceCurve) = iterate(curve.λ)
Base.length(curve::PriceCurve{N}) where N = N
Base.size(curve::PriceCurve) = size(curve.λ)
@inline function Base.getindex(curve::PriceCurve, I...)
    @boundscheck checkbounds(curve.λ, I...)
    @inbounds return curve.λ[I...]
end
function Base.zero(::Type{PriceCurve{N,T}}) where {N, T <: AbstractFloat}
    return PriceCurve(zeros(T,N))
end
function Base.getindex(curve::PriceCurve, horizon::Horizon)
    horizon <= HydroModels.horizon(curve) || throw(BoundsError(curve,horizon))
    return PriceCurve(curve.λ[1:nhours(horizon)])
end
@inline function Base.setindex!(curve::PriceCurve, x, I...)
    @boundscheck checkbounds(curve.λ, I...)
    @inbounds curve.λ[I...] = x
end
Base.axes(curve::PriceCurve) = axes(curve.λ)
Base.IndexStyle(::Type{<:PriceCurve}) = Base.IndexLinear()
horizon(curve::PriceCurve{N}) where N = Horizon(N)
mean_price(curve::PriceCurve) = mean(curve.λ)

function Statistics.mean(price_curves::Vector{PriceCurve{N,T}}) where {N, T <: AbstractFloat}
    λ̄ = [mean([curve[i] for curve in price_curves]) for i in 1:N]
    return PriceCurve(λ̄)
end

struct PriceData{T <: AbstractFloat}
    curves::Dict{Int, PriceCurve{T}}

    function PriceData(curves::Dict{Int, PriceCurve{T}}) where T <: AbstractFloat
        return new{T}(curves)
    end
end

ncurves(pricedata::PriceData) = length(pricedata.curves)
horizon(pricedata::PriceData,i::Integer) = horizon(first(pricedata))
mean_price(pricedata::PriceData) = mean([mean_price(c) for (d,c) in pricedata.curves])
Base.getindex(pricedata::PriceData, i::Integer) = pricedata.curves[i]

function mean_price(resolution::Resolution, ρ::PriceCurve, t::Integer)
    idx = (t - 1) * resolution.hours_in_period + 1
    return mean(ρ[idx:idx+resolution.hours_in_period-1])
end


text:
# This file is originally based netcdf_c.jl from NetCDF.jl
# Copyright (c) 2012-2013: Fabian Gans, Max-Planck-Institut fuer Biogeochemie, Jena, Germany
# MIT

# Several calls are commented out because they are not captured by tests
# TODO: Then why keep the commented code here?

const depfile = joinpath(dirname(@__FILE__), "..", "deps", "deps.jl")
if isfile(depfile)
    include(depfile)
else
    error("libnetcdf not properly installed. Please run: import Pkg; Pkg.build(\"NCDatasets\")")
end

const NC_NAT = 0
const NC_BYTE = 1
const NC_CHAR = 2
const NC_SHORT = 3
const NC_INT = 4
const NC_LONG = NC_INT
const NC_FLOAT = 5
const NC_DOUBLE = 6
const NC_UBYTE = 7
const NC_USHORT = 8
const NC_UINT = 9
const NC_INT64 = 10
const NC_UINT64 = 11
const NC_STRING = 12
const NC_MAX_ATOMIC_TYPE = NC_STRING
const NC_VLEN = 13
const NC_OPAQUE = 14
const NC_ENUM = 15
const NC_COMPOUND = 16
const NC_FIRSTUSERTYPEID = 32

const NC_FILL = 0
const NC_NOFILL = 0x0100
const NC_NOWRITE = 0x0000
const NC_WRITE = 0x0001
const NC_CLOBBER = 0x0000
const NC_NOCLOBBER = 0x0004
const NC_DISKLESS = 0x0008
const NC_MMAP = 0x0010
const NC_64BIT_DATA = 0x0020
const NC_CDF5 = NC_64BIT_DATA
const NC_CLASSIC_MODEL = 0x0100
const NC_64BIT_OFFSET = 0x0200
const NC_LOCK = 0x0400
const NC_SHARE = 0x0800
const NC_NETCDF4 = 0x1000
const NC_MPIIO = 0x2000
const NC_MPIPOSIX = 0x4000
const NC_INMEMORY = 0x8000
const NC_PNETCDF = NC_MPIIO
const NC_FORMAT_CLASSIC = 1
const NC_FORMAT_64BIT_OFFSET = 2
const NC_FORMAT_64BIT = NC_FORMAT_64BIT_OFFSET
const NC_FORMAT_NETCDF4 = 3
const NC_FORMAT_NETCDF4_CLASSIC = 4
const NC_FORMAT_64BIT_DATA = 5
const NC_FORMAT_CDF5 = NC_FORMAT_64BIT_DATA
const NC_FORMATX_NC3 = 1
const NC_FORMATX_NC_HDF5 = 2
const NC_FORMATX_NC4 = NC_FORMATX_NC_HDF5
const NC_FORMATX_NC_HDF4 = 3
const NC_FORMATX_PNETCDF = 4
const NC_FORMATX_DAP2 = 5
const NC_FORMATX_DAP4 = 6
const NC_FORMATX_UNDEFINED = 0
const NC_FORMAT_NC3 = NC_FORMATX_NC3
const NC_FORMAT_NC_HDF5 = NC_FORMATX_NC_HDF5
const NC_FORMAT_NC4 = NC_FORMATX_NC4
const NC_FORMAT_NC_HDF4 = NC_FORMATX_NC_HDF4
const NC_FORMAT_PNETCDF = NC_FORMATX_PNETCDF
const NC_FORMAT_DAP2 = NC_FORMATX_DAP2
const NC_FORMAT_DAP4 = NC_FORMATX_DAP4
const NC_FORMAT_UNDEFINED = NC_FORMATX_UNDEFINED
const NC_SIZEHINT_DEFAULT = 0

const NC_UNLIMITED = Int32(0)
const NC_GLOBAL = -1
const NC_MAX_DIMS = 1024
const NC_MAX_ATTRS = 8192
const NC_MAX_VARS = 8192
const NC_MAX_NAME = 256
const NC_MAX_VAR_DIMS = 1024
const NC_MAX_HDF4_NAME = 64
const NC_ENDIAN_NATIVE = 0
const NC_ENDIAN_LITTLE = 1
const NC_ENDIAN_BIG = 2
const NC_CHUNKED = 0
const NC_CONTIGUOUS = 1
const NC_NOCHECKSUM = 0
const NC_FLETCHER32 = 1
const NC_NOSHUFFLE = 0
const NC_SHUFFLE = 1

const NC_NOERR = 0
const NC2_ERR = -1
const NC_EBADID = -33
const NC_ENFILE = -34
const NC_EEXIST = -35
const NC_EINVAL = -36
const NC_EPERM = -37
const NC_ENOTINDEFINE = -38
const NC_EINDEFINE = -39
const NC_EINVALCOORDS = -40
const NC_EMAXDIMS = -41
const NC_ENAMEINUSE = -42
const NC_ENOTATT = -43
const NC_EMAXATTS = -44
const NC_EBADTYPE = -45
const NC_EBADDIM = -46
const NC_EUNLIMPOS = -47
const NC_EMAXVARS = -48
const NC_ENOTVAR = -49
const NC_EGLOBAL = -50
const NC_ENOTNC = -51
const NC_ESTS = -52
const NC_EMAXNAME = -53
const NC_EUNLIMIT = -54
const NC_ENORECVARS = -55
const NC_ECHAR = -56
const NC_EEDGE = -57
const NC_ESTRIDE = -58
const NC_EBADNAME = -59
const NC_ERANGE = -60
const NC_ENOMEM = -61
const NC_EVARSIZE = -62
const NC_EDIMSIZE = -63
const NC_ETRUNC = -64
const NC_EAXISTYPE = -65
const NC_EDAP = -66
const NC_ECURL = -67
const NC_EIO = -68
const NC_ENODATA = -69
const NC_EDAPSVC = -70
const NC_EDAS = -71
const NC_EDDS = -72
const NC_EDATADDS = -73
const NC_EDAPURL = -74
const NC_EDAPCONSTRAINT = -75
const NC_ETRANSLATION = -76
const NC_EACCESS = -77
const NC_EAUTH = -78
const NC_ENOTFOUND = -90
const NC_ECANTREMOVE = -91
const NC4_FIRST_ERROR = -100
const NC_EHDFERR = -101
const NC_ECANTREAD = -102
const NC_ECANTWRITE = -103
const NC_ECANTCREATE = -104
const NC_EFILEMETA = -105
const NC_EDIMMETA = -106
const NC_EATTMETA = -107
const NC_EVARMETA = -108
const NC_ENOCOMPOUND = -109
const NC_EATTEXISTS = -110
const NC_ENOTNC4 = -111
const NC_ESTRICTNC3 = -112
const NC_ENOTNC3 = -113
const NC_ENOPAR = -114
const NC_EPARINIT = -115
const NC_EBADGRPID = -116
const NC_EBADTYPID = -117
const NC_ETYPDEFINED = -118
const NC_EBADFIELD = -119
const NC_EBADCLASS = -120
const NC_EMAPTYPE = -121
const NC_ELATEFILL = -122
const NC_ELATEDEF = -123
const NC_EDIMSCALE = -124
const NC_ENOGRP = -125
const NC_ESTORAGE = -126
const NC_EBADCHUNK = -127
const NC_ENOTBUILT = -128
const NC_EDISKLESS = -129
const NC_ECANTEXTEND = -130
const NC_EMPI = -131
const NC4_LAST_ERROR = -131
const DIM_WITHOUT_VARIABLE = "This is a netCDF dimension but not a netCDF variable."
const NC_HAVE_NEW_CHUNKING_API = 1
const NC_EURL = NC_EDAPURL
const NC_ECONSTRAINT = NC_EDAPCONSTRAINT

const NC_ENTOOL = NC_EMAXNAME
const NC_EXDR = -32
const NC_SYSERR = -31
const NC_FATAL = 1

# default fill values

const NC_FILL_BYTE   = Int8(-127)
const NC_FILL_CHAR   = '\0'
const NC_FILL_SHORT  = Int16(-32767)
const NC_FILL_INT    = Int32(-2147483647)
const NC_FILL_FLOAT  = 9.9692099683868690f+36
const NC_FILL_DOUBLE = 9.9692099683868690e+36
const NC_FILL_UBYTE  = UInt8(255)
const NC_FILL_USHORT = UInt16(65535)
const NC_FILL_UINT   = UInt32(4294967295)
const NC_FILL_INT64  = Int64(-9223372036854775806)
const NC_FILL_UINT64 = UInt64(18446744073709551614)
const NC_FILL_STRING = ""

# depcrecated by e.g. fillvalue(Int8)
#export NC_FILL_BYTE, NC_FILL_CHAR, NC_FILL_SHORT, NC_FILL_INT, NC_FILL_FLOAT,
#    NC_FILL_DOUBLE, NC_FILL_UBYTE, NC_FILL_USHORT, NC_FILL_UINT, NC_FILL_INT64,
#    NC_FILL_UINT64, NC_FILL_STRING

const nc_type = Cint

# type is immutable to ensure that it has the memory same layout
# as the C struct nc_vlen_t

struct nc_vlen_t{T}
    len::Csize_t
    p::Ptr{T}
end

const nclong = Cint

const NCSymbols = Dict{Cint,Symbol}(
    NC_CONTIGUOUS => :contiguous,
    NC_CHUNKED => :chunked
)
# Inverse mapping
const NCConstants = Dict(value => key for (key, value) in NCSymbols)

const NCChecksumSymbols = Dict{Cint,Symbol}(
    NC_FLETCHER32 => :fletcher32,
    NC_NOCHECKSUM => :nochecksum
)
# Inverse mapping
const NCChecksumConstants = Dict(value => key for (key, value) in NCChecksumSymbols)

function convert(::Type{Array{nc_vlen_t{T},N}},data::Array{Vector{T},N}) where {T,N}
    tmp = Array{nc_vlen_t{T},N}(undef,size(data))

    for i = 1:length(data)
        tmp[i] = nc_vlen_t{T}(length(data[i]), pointer(data[i]))
    end
    return tmp
end

function nc_inq_libvers()
    unsafe_string(ccall((:nc_inq_libvers,libnetcdf),Cstring,()))
end

function nc_strerror(ncerr::Integer)
    unsafe_string(ccall((:nc_strerror,libnetcdf),Cstring,(Cint,),ncerr))
end

# function nc__create(path,cmode::Integer,initialsz::Integer,chunksizehintp,ncidp)
#     check(ccall((:nc__create,libnetcdf),Cint,(Cstring,Cint,Cint,Ptr{Cint},Ptr{Cint}),path,cmode,initialsz,chunksizehintp,ncidp))
# end

function nc_create(path,cmode::Integer)
    ncidp = Vector{Cint}(undef,1)
    check(ccall((:nc_create,libnetcdf),Cint,(Cstring,Cint,Ptr{Cint}),path,cmode,ncidp))
    return ncidp[1]
end

# function nc__open(path,mode::Integer,chunksizehintp,ncidp)
#     check(ccall((:nc__open,libnetcdf),Cint,(Cstring,Cint,Ptr{Cint},Ptr{Cint}),path,mode,chunksizehintp,ncidp))
# end

function nc_open(path,mode::Integer)
    ncidp = Vector{Cint}(undef,1)

    code = ccall((:nc_open,libnetcdf),Cint,(Cstring,Cint,Ptr{Cint}),path,mode,ncidp)

    if code == NC_NOERR
        return ncidp[1]
        # otherwise throw an error message
    else
        # return a more helpful error message (i.e. with the path)
        throw(NetCDFError(code, "Opening path $(path): $(nc_strerror(code))"))
    end
end

function nc_inq_path(ncid::Integer)
    pathlenp = Vector{Csize_t}(undef,1)
    check(ccall((:nc_inq_path,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{UInt8}),ncid,pathlenp,C_NULL))

    path = zeros(UInt8,pathlenp[1]+1)
    check(ccall((:nc_inq_path,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{UInt8}),ncid,pathlenp,path))

    return unsafe_string(pointer(path))
end

# function nc_inq_ncid(ncid::Integer,name,grp_ncid)
#     check(ccall((:nc_inq_ncid,libnetcdf),Cint,(Cint,Cstring,Ptr{Cint}),ncid,name,grp_ncid))
# end

function nc_inq_grps(ncid::Integer)
    numgrpsp = Vector{Cint}(undef,1)
    check(ccall((:nc_inq_grps,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{Cint}),ncid,numgrpsp,C_NULL))
    numgrps = numgrpsp[1]

    ncids = Vector{Cint}(undef,numgrps)

    check(ccall((:nc_inq_grps,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{Cint}),ncid,numgrpsp,ncids))

    return ncids
end

function nc_inq_grpname(ncid::Integer)
    name = zeros(UInt8,NC_MAX_NAME+1)

    check(ccall((:nc_inq_grpname,libnetcdf),Cint,(Cint,Ptr{UInt8}),ncid,name))

    return unsafe_string(pointer(name))
end

# function nc_inq_grpname_full(ncid::Integer,lenp,full_name)
#     check(ccall((:nc_inq_grpname_full,libnetcdf),Cint,(Cint,Ptr{Cint},Cstring),ncid,lenp,full_name))
# end

# function nc_inq_grpname_len(ncid::Integer,lenp)
#     check(ccall((:nc_inq_grpname_len,libnetcdf),Cint,(Cint,Ptr{Cint}),ncid,lenp))
# end

# function nc_inq_grp_parent(ncid::Integer,parent_ncid)
#     check(ccall((:nc_inq_grp_parent,libnetcdf),Cint,(Cint,Ptr{Cint}),ncid,parent_ncid))
# end

function nc_inq_grp_ncid(ncid::Integer,grp_name)
    grp_ncid = Vector{Cint}(undef,1)
    check(ccall((:nc_inq_grp_ncid,libnetcdf),Cint,(Cint,Cstring,Ptr{Cint}),ncid,grp_name,grp_ncid))
    return grp_ncid[1]
end

# function nc_inq_grp_full_ncid(ncid::Integer,full_name,grp_ncid)
#     check(ccall((:nc_inq_grp_full_ncid,libnetcdf),Cint,(Cint,Cstring,Ptr{Cint}),ncid,full_name,grp_ncid))
# end

function nc_inq_varids(ncid::Integer)::Vector{Cint}
    # first get number of variables
    nvarsp = zeros(Int,1)
    check(ccall((:nc_inq_varids,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{Cint}),ncid,nvarsp,C_NULL))
    nvars = nvarsp[1]

    varids = zeros(Cint,nvars)
    check(ccall((:nc_inq_varids,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{Cint}),ncid,nvarsp,varids))
    return varids
end

function nc_inq_dimids(ncid::Integer,include_parents::Bool)
    ndimsp = Vector{Cint}(undef,1)
    ndims = nc_inq_ndims(ncid)
    dimids = Vector{Cint}(undef,ndims)
    check(ccall((:nc_inq_dimids,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{Cint},Cint),ncid,ndimsp,dimids,include_parents))

    return dimids
end

function nc_inq_typeids(ncid::Integer)
    ntypesp = Vector{Cint}(undef,1)
    check(ccall((:nc_inq_typeids,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{Cint}),ncid,ntypesp,C_NULL))

    typeids = Vector{Cint}(undef,ntypesp[1])
    check(ccall((:nc_inq_typeids,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{Cint}),ncid,C_NULL,typeids))

    return typeids
end

# function nc_inq_type_equal(ncid1::Integer,typeid1::Integer,ncid2::Integer,typeid2::Integer,equal)
#     check(ccall((:nc_inq_type_equal,libnetcdf),Cint,(Cint,nc_type,Cint,nc_type,Ptr{Cint}),ncid1,typeid1,ncid2,typeid2,equal))
# end

"""
Create a group with the name `name` returnings its id.
"""
function nc_def_grp(parent_ncid::Integer,name)
    new_ncid = Vector{Cint}(undef,1)
    check(ccall((:nc_def_grp,libnetcdf),Cint,(Cint,Cstring,Ptr{Cint}),parent_ncid,name,new_ncid))

    return new_ncid[1]
end

# function nc_rename_grp(grpid::Integer,name)
#     check(ccall((:nc_rename_grp,libnetcdf),Cint,(Cint,Cstring),grpid,name))
# end

# function nc_def_compound(ncid::Integer,size::Integer,name,typeidp)
#     check(ccall((:nc_def_compound,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{nc_type}),ncid,size,name,typeidp))
# end

# function nc_insert_compound(ncid::Integer,xtype::Integer,name,offset::Integer,field_typeid::Integer)
#     check(ccall((:nc_insert_compound,libnetcdf),Cint,(Cint,nc_type,Cstring,Cint,nc_type),ncid,xtype,name,offset,field_typeid))
# end

# function nc_insert_array_compound(ncid::Integer,xtype::Integer,name,offset::Integer,field_typeid::Integer,ndims::Integer,dim_sizes)
#     check(ccall((:nc_insert_array_compound,libnetcdf),Cint,(Cint,nc_type,Cstring,Cint,nc_type,Cint,Ptr{Cint}),ncid,xtype,name,offset,field_typeid,ndims,dim_sizes))
# end

# function nc_inq_type(ncid::Integer,xtype::Integer,name,size)
#     check(ccall((:nc_inq_type,libnetcdf),Cint,(Cint,nc_type,Cstring,Ptr{Cint}),ncid,xtype,name,size))
# end

# function nc_inq_typeid(ncid::Integer,name,typeidp)
#     check(ccall((:nc_inq_typeid,libnetcdf),Cint,(Cint,Cstring,Ptr{nc_type}),ncid,name,typeidp))
# end

# function nc_inq_compound(ncid::Integer,xtype::Integer,name,sizep,nfieldsp)
#     check(ccall((:nc_inq_compound,libnetcdf),Cint,(Cint,nc_type,Cstring,Ptr{Cint},Ptr{Cint}),ncid,xtype,name,sizep,nfieldsp))
# end

# function nc_inq_compound_name(ncid::Integer,xtype::Integer,name)
#     check(ccall((:nc_inq_compound_name,libnetcdf),Cint,(Cint,nc_type,Cstring),ncid,xtype,name))
# end

# function nc_inq_compound_size(ncid::Integer,xtype::Integer,sizep)
#     check(ccall((:nc_inq_compound_size,libnetcdf),Cint,(Cint,nc_type,Ptr{Cint}),ncid,xtype,sizep))
# end

# function nc_inq_compound_nfields(ncid::Integer,xtype::Integer,nfieldsp)
#     check(ccall((:nc_inq_compound_nfields,libnetcdf),Cint,(Cint,nc_type,Ptr{Cint}),ncid,xtype,nfieldsp))
# end

# function nc_inq_compound_field(ncid::Integer,xtype::Integer,fieldid::Integer,name,offsetp,field_typeidp,ndimsp,dim_sizesp)
#     check(ccall((:nc_inq_compound_field,libnetcdf),Cint,(Cint,nc_type,Cint,Cstring,Ptr{Cint},Ptr{nc_type},Ptr{Cint},Ptr{Cint}),ncid,xtype,fieldid,name,offsetp,field_typeidp,ndimsp,dim_sizesp))
# end

# function nc_inq_compound_fieldname(ncid::Integer,xtype::Integer,fieldid::Integer,name)
#     check(ccall((:nc_inq_compound_fieldname,libnetcdf),Cint,(Cint,nc_type,Cint,Cstring),ncid,xtype,fieldid,name))
# end

# function nc_inq_compound_fieldindex(ncid::Integer,xtype::Integer,name,fieldidp)
#     check(ccall((:nc_inq_compound_fieldindex,libnetcdf),Cint,(Cint,nc_type,Cstring,Ptr{Cint}),ncid,xtype,name,fieldidp))
# end

# function nc_inq_compound_fieldoffset(ncid::Integer,xtype::Integer,fieldid::Integer,offsetp)
#     check(ccall((:nc_inq_compound_fieldoffset,libnetcdf),Cint,(Cint,nc_type,Cint,Ptr{Cint}),ncid,xtype,fieldid,offsetp))
# end

# function nc_inq_compound_fieldtype(ncid::Integer,xtype::Integer,fieldid::Integer,field_typeidp)
#     check(ccall((:nc_inq_compound_fieldtype,libnetcdf),Cint,(Cint,nc_type,Cint,Ptr{nc_type}),ncid,xtype,fieldid,field_typeidp))
# end

# function nc_inq_compound_fieldndims(ncid::Integer,xtype::Integer,fieldid::Integer,ndimsp)
#     check(ccall((:nc_inq_compound_fieldndims,libnetcdf),Cint,(Cint,nc_type,Cint,Ptr{Cint}),ncid,xtype,fieldid,ndimsp))
# end

# function nc_inq_compound_fielddim_sizes(ncid::Integer,xtype::Integer,fieldid::Integer,dim_sizes)
#     check(ccall((:nc_inq_compound_fielddim_sizes,libnetcdf),Cint,(Cint,nc_type,Cint,Ptr{Cint}),ncid,xtype,fieldid,dim_sizes))
# end

function nc_def_vlen(ncid::Integer,name,base_typeid::Integer)
    xtypep = Vector{nc_type}(undef,1)

    check(ccall((:nc_def_vlen,libnetcdf),Cint,(Cint,Cstring,nc_type,Ptr{nc_type}),ncid,name,base_typeid,xtypep))

    return xtypep[1]
end

"""
datum_size is sizeof(nc_vlen_t)
"""
function nc_inq_vlen(ncid::Integer,xtype::Integer)
    datum_sizep = Vector{Csize_t}(undef,1)
    base_nc_typep = Vector{nc_type}(undef,1)
    name = zeros(UInt8,NC_MAX_NAME+1)

    check(ccall((:nc_inq_vlen,libnetcdf),Cint,(Cint,nc_type,Ptr{UInt8},Ptr{Csize_t},Ptr{nc_type}),ncid,xtype,name,datum_sizep,base_nc_typep))

    return unsafe_string(pointer(name)),datum_sizep[1],base_nc_typep[1]
end

function nc_free_vlen(vl)
    check(ccall((:nc_free_vlen,libnetcdf),Cint,(Ptr{nc_vlen_t},),vl))
end

# function nc_free_vlens(len::Integer,vlens)
#     check(ccall((:nc_free_vlens,libnetcdf),Cint,(Cint,Ptr{nc_vlen_t}),len,vlens))
# end

# function nc_put_vlen_element(ncid::Integer,typeid1::Integer,vlen_element,len::Integer,data)
#     check(ccall((:nc_put_vlen_element,libnetcdf),Cint,(Cint,Cint,Ptr{Nothing},Cint,Ptr{Nothing}),ncid,typeid1,vlen_element,len,data))
# end

# function nc_get_vlen_element(ncid::Integer,typeid1::Integer,vlen_element,len,data)
#     check(ccall((:nc_get_vlen_element,libnetcdf),Cint,(Cint,Cint,Ptr{Nothing},Ptr{Cint},Ptr{Nothing}),ncid,typeid1,vlen_element,len,data))
# end

# function nc_free_string(len::Integer,data)
#     check(ccall((:nc_free_string,libnetcdf),Cint,(Cint,Ptr{Ptr{UInt8}}),len,data))
# end

function nc_inq_user_type(ncid::Integer,xtype::Integer)
    name = Vector{UInt8}(undef,NC_MAX_NAME+1)
    sizep = Vector{Csize_t}(undef,1)
    base_nc_typep = Vector{nc_type}(undef,1)
    nfieldsp = Vector{Csize_t}(undef,1)
    classp = Vector{Cint}(undef,1)

    check(ccall((:nc_inq_user_type,libnetcdf),Cint,(Cint,nc_type,Ptr{UInt8},Ptr{Cint},Ptr{nc_type},Ptr{Csize_t},Ptr{Cint}),ncid,xtype,name,sizep,base_nc_typep,nfieldsp,classp))

    return unsafe_string(pointer(name)),sizep[1],base_nc_typep[1],nfieldsp[1],classp[1]
end

function nc_put_att(ncid::Integer,varid::Integer,name::AbstractString,data::AbstractString)
    check(ccall((:nc_put_att_text,libnetcdf),Cint,(Cint,Cint,Cstring,Csize_t,Cstring),
                ncid,varid,name,sizeof(data),data))
end

function nc_put_att(ncid::Integer,varid::Integer,name::AbstractString,data::Vector{Char})
    nc_put_att(ncid,varid,name,join(data))
end

# NetCDF does not necessarily support 64 bit attributes
nc_put_att(ncid::Integer,varid::Integer,name::AbstractString,data::Int64) =
    nc_put_att(ncid,varid,name,Int32(data))

nc_put_att(ncid::Integer,varid::Integer,name::AbstractString,data::Vector{Int64}) =
    nc_put_att(ncid,varid,name,Int32.(data))

function nc_put_att(ncid::Integer,varid::Integer,name::AbstractString,data::Number)
    check(ccall((:nc_put_att,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Csize_t,Ptr{Nothing}),
                ncid,varid,name,ncType[typeof(data)],1,[data]))
end

function nc_put_att(ncid::Integer,varid::Integer,name::AbstractString,data::Char)
    # UInt8('α')
    # ERROR: InexactError: trunc(UInt8, 945)
    check(ccall((:nc_put_att,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Csize_t,Ptr{Nothing}),
                ncid,varid,name,ncType[typeof(data)],1,[UInt8(data)]))
end

function nc_put_att(ncid::Integer,varid::Integer,name::AbstractString,data::Vector{T}) where T <: AbstractString
    check(ccall((:nc_put_att,libnetcdf),Cint,(Cint,Cint,Cstring,
                                              nc_type,Csize_t,Ptr{Nothing}),
                ncid,varid,name,ncType[eltype(data)],length(data),pointer.(data)))
end

function nc_put_att(ncid::Integer,varid::Integer,name::AbstractString,data::Vector{T}) where {T}
    check(ccall((:nc_put_att,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Csize_t,Ptr{Nothing}),
                ncid,varid,name,ncType[eltype(data)],length(data),data))
end

function nc_put_att(ncid::Integer,varid::Integer,name::AbstractString,data)
    error("attributes can only be scalars or vectors")
end

function nc_get_att(ncid::Integer,varid::Integer,name)
    xtype,len = nc_inq_att(ncid,varid,name)

    if xtype == NC_CHAR
        val = Vector{UInt8}(undef,len)
        check(ccall((:nc_get_att,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Nothing}),ncid,varid,name,val))

        if any(val .== 0)
            # consider the null terminating character if present
            # see issue #12
            return unsafe_string(pointer(val))
        else
            return unsafe_string(pointer(val),length(val))
        end
    elseif xtype == NC_STRING
        val = Vector{Ptr{UInt8}}(undef,len)
        check(ccall((:nc_get_att,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Nothing}),ncid,varid,name,val))

        str = unsafe_string.(val)
        if len == 1
            return str[1]
        else
            return str
        end
    else
        val = Vector{jlType[xtype]}(undef,len)
        check(ccall((:nc_get_att,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Nothing}),ncid,varid,name,val))

        if len == 1
            return val[1]
        else
            return val
        end
    end
end

# function nc_def_enum(ncid::Integer,base_typeid::Integer,name,typeidp)
#     check(ccall((:nc_def_enum,libnetcdf),Cint,(Cint,nc_type,Cstring,Ptr{nc_type}),ncid,base_typeid,name,typeidp))
# end

# function nc_insert_enum(ncid::Integer,xtype::Integer,name,value)
#     check(ccall((:nc_insert_enum,libnetcdf),Cint,(Cint,nc_type,Cstring,Ptr{Nothing}),ncid,xtype,name,value))
# end

# function nc_inq_enum(ncid::Integer,xtype::Integer,name,base_nc_typep,base_sizep,num_membersp)
#     check(ccall((:nc_inq_enum,libnetcdf),Cint,(Cint,nc_type,Cstring,Ptr{nc_type},Ptr{Cint},Ptr{Cint}),ncid,xtype,name,base_nc_typep,base_sizep,num_membersp))
# end

# function nc_inq_enum_member(ncid::Integer,xtype::Integer,idx::Integer,name,value)
#     check(ccall((:nc_inq_enum_member,libnetcdf),Cint,(Cint,nc_type,Cint,Cstring,Ptr{Nothing}),ncid,xtype,idx,name,value))
# end

# function nc_inq_enum_ident(ncid::Integer,xtype::Integer,value::Clonglong,identifier)
#     check(ccall((:nc_inq_enum_ident,libnetcdf),Cint,(Cint,nc_type,Clonglong,Cstring),ncid,xtype,value,identifier))
# end

# function nc_def_opaque(ncid::Integer,size::Integer,name,xtypep)
#     check(ccall((:nc_def_opaque,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{nc_type}),ncid,size,name,xtypep))
# end

# function nc_inq_opaque(ncid::Integer,xtype::Integer,name,sizep)
#     check(ccall((:nc_inq_opaque,libnetcdf),Cint,(Cint,nc_type,Cstring,Ptr{Cint}),ncid,xtype,name,sizep))
# end

# can the NetCDF variable varid receive the data?
function _nc_shape_check(ncid,varid,data,start,count,stride)
    @debug ncid,varid,data,start,count,stride
end

function nc_put_var(ncid::Integer,varid::Integer,data::Array{Char,N}) where N
    nc_put_var(ncid,varid,convert(Array{UInt8,N},data))
end

function nc_put_var(ncid::Integer,varid::Integer,data::Array{String,N}) where N
    nc_put_var(ncid,varid,pointer.(data))
end

function nc_put_var(ncid::Integer,varid::Integer,data::Array{Vector{T},N}) where {T,N}
    nc_put_var(ncid,varid,convert(Array{nc_vlen_t{T},N},data))
end

function nc_unsafe_put_var(ncid::Integer,varid::Integer,data)
    check(ccall((:nc_put_var,libnetcdf),Cint,(Cint,Cint,Ptr{Nothing}),ncid,varid,data))
end

function nc_put_var(ncid::Integer,varid::Integer,data)
    dimids = nc_inq_vardimid(ncid,varid)
    ndims = length(dimids)
    ncsize = ntuple(i -> nc_inq_dimlen(ncid,dimids[ndims-i+1]), ndims)

    if isempty(nc_inq_unlimdims(ncid))
        if ncsize != size(data)
            path = nc_inq_path(ncid)
            varname = nc_inq_varname(ncid,varid)
            throw(NetCDFError(-1,"wrong size of variable '$varname' (size $ncsize) in file '$path' for an array of size $(size(data))"))
        end

        nc_unsafe_put_var(ncid,varid,data)
    else
        # honor this good advice:

        # Take care when using this function with record variables (variables
        # that use the ::NC_UNLIMITED dimension). If you try to write all the
        # values of a record variable into a netCDF file that has no record data
        # yet (hence has 0 records), nothing will be written. Similarly, if you
        # try to write all the values of a record variable but there are more
        # records in the file than you assume, more in-memory data will be
        # accessed than you supply, which may result in a segmentation
        # violation. To avoid such problems, it is better to use the nc_put_vara
        # interfaces for variables that use the ::NC_UNLIMITED dimension.

        # https://github.com/Unidata/netcdf-c/blob/48cc56ea3833df455337c37186fa6cd7fac9dc7e/libdispatch/dvarput.c#L895

        startp = zeros(ndims)
        countp = Int[reverse(size(data))...,]
        nc_put_vara(ncid,varid,startp,countp,data)
    end
end

function nc_get_var!(ncid::Integer,varid::Integer,ip::Array{Char,N}) where N
    tmp = Array{UInt8,N}(undef,size(ip))
    nc_get_var!(ncid,varid,tmp)
    for i in eachindex(tmp)
        ip[i] = Char(tmp[i])
    end
end

function nc_get_var!(ncid::Integer,varid::Integer,ip::Array{String,N}) where N
    tmp = Array{Ptr{UInt8},N}(undef,size(ip))
    nc_get_var!(ncid,varid,tmp)
    for i in eachindex(tmp)
        #ip[:] = unsafe_string.(tmp)
        ip[i] = unsafe_string(tmp[i])
    end
end

function nc_get_var!(ncid::Integer,varid::Integer,ip::Array{Vector{T},N}) where {T,N}
    tmp = Array{NCDatasets.nc_vlen_t{T},N}(undef,size(ip))
    nc_get_var!(ncid,varid,tmp)

    for i in eachindex(tmp)
        ip[i] = unsafe_wrap(Vector{T},tmp[i].p,(tmp[i].len,))
    end
end

function nc_get_var!(ncid::Integer,varid::Integer,ip)
    check(ccall((:nc_get_var,libnetcdf),Cint,(Cint,Cint,Ptr{Nothing}),ncid,varid,ip))
end

function nc_put_var1(ncid::Integer,varid::Integer,indexp,op::Vector{T}) where T
    tmp = nc_vlen_t{T}(length(op), pointer(op))
    check(ccall((:nc_put_var1,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Nothing}),ncid,varid,indexp,Ref(tmp)))
end

function nc_put_var1(ncid::Integer,varid::Integer,indexp,op::T) where T
    @debug "nc_put_var1",indexp,op
    check(ccall((:nc_put_var1,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Nothing}),ncid,varid,indexp,T[op]))
end

function nc_put_var1(ncid::Integer,varid::Integer,indexp,op::Char)
   @debug "nc_put_var1 char",indexp,op
   check(ccall((:nc_put_var1,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Nothing}),ncid,varid,indexp,[UInt8(op)]))
end

function nc_get_var1(::Type{Char},ncid::Integer,varid::Integer,indexp)
    @debug "nc_get_var1",indexp
    tmp = Vector{UInt8}(undef,1)
    check(ccall((:nc_get_var1,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Nothing}),ncid,varid,indexp,tmp))
    return Char(tmp[1])
end

function nc_get_var1(::Type{String},ncid::Integer,varid::Integer,indexp)
    tmp = Vector{Ptr{UInt8}}(undef,1)
    check(ccall((:nc_get_var1_string,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Ptr{UInt8}}),ncid,varid,indexp,tmp))
    return unsafe_string(tmp[1])
end

function nc_get_var1(::Type{T},ncid::Integer,varid::Integer,indexp) where T
    @debug "nc_get_var1",indexp
    ip = Vector{T}(undef,1)
    check(ccall((:nc_get_var1,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Nothing}),ncid,varid,indexp,ip))
    return ip[1]
end

function nc_get_var1(::Type{Vector{T}},ncid::Integer,varid::Integer,indexp) where T
    ip = Vector{nc_vlen_t{T}}(undef,1)
    check(ccall((:nc_get_var1,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Nothing}),ncid,varid,indexp,ip))
    #data = unsafe_wrap(Vector{T},ip[1].p,(ip[1].len,))
    data = copy(unsafe_wrap(Vector{T},ip[1].p,(ip[1].len,)))
    nc_free_vlen(ip)
    return data
end

function nc_put_vara(ncid::Integer,varid::Integer,startp,countp,op)
    check(ccall((:nc_put_vara,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Nothing}),ncid,varid,startp,countp,op))
end

function nc_put_vara(ncid::Integer,varid::Integer,startp,countp,op::Array{Char,N}) where N
    tmp = convert(Array{UInt8,N},op)
    nc_put_vara(ncid,varid,startp,countp,tmp)
end

function nc_get_vara!(ncid::Integer,varid::Integer,startp,countp,ip)
     check(ccall((:nc_get_vara,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Nothing}),ncid,varid,startp,countp,ip))
end

# do we need nc_put_vara/nc_get_vara! for Array{String,N} ?
function nc_get_vara!(ncid::Integer,varid::Integer,startp,countp,ip::Array{Char,N}) where N
    tmp = Array{UInt8,N}(undef,size(ip))
    nc_get_vara!(ncid,varid,startp,countp,tmp)
    for i in eachindex(tmp)
        ip[i] = Char(tmp[i])
    end
end

function nc_put_vars(ncid::Integer,varid::Integer,startp,countp,stridep,
                     op::Array{Char,N}) where N
    tmp = Array{UInt8,N}(undef,size(op))
    for i in eachindex(op)
        tmp[i] = UInt8(op[i])
    end

    nc_put_vars(ncid,varid,startp,countp,stridep,tmp)
end

function nc_put_vars(ncid::Integer,varid::Integer,startp,countp,stridep,
                     op::Array{String,N}) where N
    nc_put_vars(ncid,varid,startp,countp,stridep,pointer.(op))
end

function nc_put_vars(ncid::Integer,varid::Integer,startp,countp,stridep,
                     op::Array{Vector{T},N}) where {T,N}

    nc_put_vars(ncid,varid,startp,countp,stridep,
                convert(Array{nc_vlen_t{T},N},op))
end

function _nc_check_size_put_vars(ncid,varid,countp,op)
    # dimension index for NetCDF variable
    i1 = 1
    # dimension index of data op
    i2 = 1

    # not_one(x) = x != 1
    # if filter(not_one,reverse(countp)) != filter(not_one,[size(op)...])
    #     path = nc_inq_path(ncid)
    #     varname = nc_inq_varname(ncid,varid)
    #     throw(DimensionMismatch("size mismatch for variable '$(varname)' in file '$(path)'. Trying to write $(size(op)) elements while $(countp) are expected"))
    # end

    unlimdims = nc_inq_unlimdims(ncid)
    dimids = nc_inq_vardimid(ncid,varid)

    countp = reverse(countp)
    dimids = reverse(dimids)

    while true
        if (i2 > ndims(op)) && (i1 > length(countp))
            break
        end

        count_i1 =
            if i1 <= length(countp)
                countp[i1]
            else
                1
            end

        # ignore dimensions with only one element
        if (count_i1 == 1) && (i1 <= length(countp))
            i1 += 1
            continue
        end
        if size(op,i2) == 1
            i2 += 1
            continue
        end

        # no test for unlimited dimensions
        if (i1 <= length(countp)) && (dimids[i1] in unlimdims)
            # ok
        elseif (size(op,i2) !== count_i1)
            path = nc_inq_path(ncid)
            varname = nc_inq_varname(ncid,varid)

            throw(NetCDFError(NC_EEDGE,"size mismatch for variable '$(varname)' in file '$(path)'. Trying to write $(size(op)) elements while $(countp) are expected"))
        end

        i1 += 1
        i2 += 1
    end
end

function nc_put_vars(ncid::Integer,varid::Integer,startp,countp,stridep,op)
    @debug "nc_put_vars: $startp,$countp,$stridep"
    @debug "shape $(size(op))"
    _nc_check_size_put_vars(ncid,varid,countp,op)

    check(ccall((:nc_put_vars,libnetcdf),Cint,
                (Cint,Cint,Ptr{Cint},Ptr{Cint},
                 Ptr{Cint},Ptr{Nothing}),ncid,varid,startp,countp,stridep,op))
end

function nc_get_vars!(ncid::Integer,varid::Integer,startp,countp,stridep,ip::Array{Char,N}) where N
    tmp = Array{UInt8,N}(undef,size(ip))
    nc_get_vars!(ncid,varid,startp,countp,stridep,tmp)
    for i in eachindex(tmp)
        ip[i] = Char(tmp[i])
    end
end

function nc_get_vars!(ncid::Integer,varid::Integer,startp,countp,stridep,ip::Array{String,N}) where N
    tmp = Array{Ptr{UInt8},N}(undef,size(ip))
    nc_get_vars!(ncid,varid,startp,countp,stridep,tmp)
    for i in eachindex(tmp)
        #ip[:] = unsafe_string.(tmp)
        ip[i] = unsafe_string(tmp[i])
    end
end

function nc_get_vars!(ncid::Integer,varid::Integer,startp,countp,stridep,ip::Array{Vector{T},N}) where {T,N}
    tmp = Array{NCDatasets.nc_vlen_t{T},N}(undef,size(ip))
    nc_get_vars!(ncid,varid,startp,countp,stridep,tmp)

    for i in eachindex(tmp)
        ip[i] = unsafe_wrap(Vector{T},tmp[i].p,(tmp[i].len,))
    end
end

function nc_get_vars!(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
    @debug "nc_get_vars!: $startp,$countp,$stridep"
    check(ccall((:nc_get_vars,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Nothing}),ncid,varid,startp,countp,stridep,ip))
end

# function nc_put_varm(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Nothing}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Nothing}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

function nc_def_var_deflate(ncid::Integer,varid::Integer,shuffle::Bool,deflate::Integer,deflate_level::Integer)
    ishuffle = (shuffle ? 1 : 0)
    check(ccall((:nc_def_var_deflate,libnetcdf),Cint,(Cint,Cint,Cint,Cint,Cint),ncid,varid,shuffle,deflate,deflate_level))
end

function nc_inq_var_deflate(ncid::Integer,varid::Integer)
    shufflep = zeros(Cint,1)
    deflatep = zeros(Cint,1)
    deflate_levelp = zeros(Cint,1)

    check(ccall((:nc_inq_var_deflate,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint}),ncid,varid,shufflep,deflatep,deflate_levelp))

    return shufflep[1] == 1, deflatep[1] == 1, deflate_levelp[1]
end

# function nc_inq_var_szip(ncid::Integer,varid::Integer,options_maskp,pixels_per_blockp)
#     check(ccall((:nc_inq_var_szip,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint}),ncid,varid,options_maskp,pixels_per_blockp))
# end

function nc_def_var_fletcher32(ncid::Integer,varid::Integer,fletcher32)
    check(ccall((:nc_def_var_fletcher32,libnetcdf),Cint,(Cint,Cint,Cint),ncid,varid,NCChecksumConstants[fletcher32]))
end

function nc_inq_var_fletcher32(ncid::Integer,varid::Integer)
    fletcher32p = zeros(Cint,1)
    check(ccall((:nc_inq_var_fletcher32,libnetcdf),Cint,(Cint,Cint,Ptr{Cint}),ncid,varid,fletcher32p))
    return NCChecksumSymbols[fletcher32p[1]]
end

function nc_def_var_chunking(ncid::Integer,varid::Integer,storage,chunksizes)

    check(ccall((:nc_def_var_chunking,libnetcdf),Cint,(Cint,Cint,Cint,Ptr{Csize_t}),ncid,varid,NCConstants[storage],chunksizes))
end

function nc_inq_var_chunking(ncid::Integer,varid::Integer)
    ndims = nc_inq_varndims(ncid,varid)
    storagep = zeros(Cint,1)
    chunksizes = zeros(Csize_t,ndims)

    check(ccall((:nc_inq_var_chunking,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Csize_t}),ncid,varid,storagep,chunksizes))

    return NCSymbols[storagep[1]],Int.(chunksizes)
end

"""
no_fill is a boolean and fill_value the value
"""
function nc_def_var_fill(ncid::Integer,varid::Integer,no_fill::Bool,fill_value)
    check(ccall((:nc_def_var_fill,libnetcdf),Cint,(Cint,Cint,Cint,Ptr{Nothing}),
                ncid,
                varid,
                Cint(no_fill),
                [fill_value]))
end

"""
no_fill,fill_value = nc_inq_var_fill(ncid::Integer,varid::Integer)
no_fill is a boolean and fill_value the fill value (in the appropriate type)
"""
function nc_inq_var_fill(ncid::Integer,varid::Integer)
    T = jlType[nc_inq_vartype(ncid,varid)]
    fill_valuep = Vector{T}(undef,1)
    no_fillp = Vector{Cint}(undef,1)
    check(ccall((:nc_inq_var_fill,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Nothing}),
                ncid,varid,no_fillp,fill_valuep))

    return Bool(no_fillp[1]),fill_valuep[1]
end

# function nc_def_var_endian(ncid::Integer,varid::Integer,endian::Integer)
#     check(ccall((:nc_def_var_endian,libnetcdf),Cint,(Cint,Cint,Cint),ncid,varid,endian))
# end

# function nc_inq_var_endian(ncid::Integer,varid::Integer,endianp)
#     check(ccall((:nc_inq_var_endian,libnetcdf),Cint,(Cint,Cint,Ptr{Cint}),ncid,varid,endianp))
# end

# function nc_set_fill(ncid::Integer,fillmode::Integer,old_modep)
#     check(ccall((:nc_set_fill,libnetcdf),Cint,(Cint,Cint,Ptr{Cint}),ncid,fillmode,old_modep))
# end

# function nc_set_default_format(format::Integer,old_formatp)
#     check(ccall((:nc_set_default_format,libnetcdf),Cint,(Cint,Ptr{Cint}),format,old_formatp))
# end

# function nc_set_chunk_cache(size::Integer,nelems::Integer,preemption::Cfloat)
#     check(ccall((:nc_set_chunk_cache,libnetcdf),Cint,(Cint,Cint,Cfloat),size,nelems,preemption))
# end

# function nc_get_chunk_cache(sizep,nelemsp,preemptionp)
#     check(ccall((:nc_get_chunk_cache,libnetcdf),Cint,(Ptr{Cint},Ptr{Cint},Ptr{Cfloat}),sizep,nelemsp,preemptionp))
# end

# function nc_set_var_chunk_cache(ncid::Integer,varid::Integer,size::Integer,nelems::Integer,preemption::Cfloat)
#     check(ccall((:nc_set_var_chunk_cache,libnetcdf),Cint,(Cint,Cint,Cint,Cint,Cfloat),ncid,varid,size,nelems,preemption))
# end

# function nc_get_var_chunk_cache(ncid::Integer,varid::Integer,sizep,nelemsp,preemptionp)
#     check(ccall((:nc_get_var_chunk_cache,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cfloat}),ncid,varid,sizep,nelemsp,preemptionp))
# end

function nc_redef(ncid::Integer)
    check(ccall((:nc_redef,libnetcdf),Cint,(Cint,),ncid))
end

# function nc__enddef(ncid::Integer,h_minfree::Integer,v_align::Integer,v_minfree::Integer,r_align::Integer)
#     check(ccall((:nc__enddef,libnetcdf),Cint,(Cint,Cint,Cint,Cint,Cint),ncid,h_minfree,v_align,v_minfree,r_align))
# end

function nc_enddef(ncid::Integer)
    check(ccall((:nc_enddef,libnetcdf),Cint,(Cint,),ncid))
end

function nc_sync(ncid::Integer)
    check(ccall((:nc_sync,libnetcdf),Cint,(Cint,),ncid))
end

# function nc_abort(ncid::Integer)
#     check(ccall((:nc_abort,libnetcdf),Cint,(Cint,),ncid))
# end

function nc_close(ncid::Integer)
    check(ccall((:nc_close,libnetcdf),Cint,(Cint,),ncid))
end

# function nc_inq(ncid::Integer,ndimsp,nvarsp,nattsp,unlimdimidp)
#     check(ccall((:nc_inq,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint}),ncid,ndimsp,nvarsp,nattsp,unlimdimidp))
# end

function nc_inq_ndims(ncid::Integer)
    ndimsp = Vector{Cint}(undef,1)
    check(ccall((:nc_inq_ndims,libnetcdf),Cint,(Cint,Ptr{Cint}),ncid,ndimsp))
    return ndimsp[1]
end

# function nc_inq_nvars(ncid::Integer,nvarsp)
#     check(ccall((:nc_inq_nvars,libnetcdf),Cint,(Cint,Ptr{Cint}),ncid,nvarsp))
# end

# function nc_inq_natts(ncid::Integer,nattsp)
#     check(ccall((:nc_inq_natts,libnetcdf),Cint,(Cint,Ptr{Cint}),ncid,nattsp))
# end

# function nc_inq_unlimdim(ncid::Integer,unlimdimidp)
#     check(ccall((:nc_inq_unlimdim,libnetcdf),Cint,(Cint,Ptr{Cint}),ncid,unlimdimidp))
# end

"""
Returns the identifiers of unlimited dimensions
"""
function nc_inq_unlimdims(ncid::Integer)
    nunlimdimsp = Vector{Cint}(undef,1)
    check(ccall((:nc_inq_unlimdims,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{Cint}),ncid,nunlimdimsp,C_NULL))

    unlimdimids = Vector{Cint}(undef,nunlimdimsp[1])
    check(ccall((:nc_inq_unlimdims,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{Cint}),ncid,nunlimdimsp,unlimdimids))
    return unlimdimids
end

# function nc_inq_format(ncid::Integer,formatp)
#     check(ccall((:nc_inq_format,libnetcdf),Cint,(Cint,Ptr{Cint}),ncid,formatp))
# end

# function nc_inq_format_extended(ncid::Integer,formatp,modep)
#     check(ccall((:nc_inq_format_extended,libnetcdf),Cint,(Cint,Ptr{Cint},Ptr{Cint}),ncid,formatp,modep))
# end

"""
Define the dimension with the name NAME and the length LEN in the
dataset NCID.  The id of the dimension is returned
"""
function nc_def_dim(ncid::Integer,name,len::Integer)
    idp = Vector{Cint}(undef,1)

    check(ccall((:nc_def_dim,libnetcdf),Cint,(Cint,Cstring,Cint,Ptr{Cint}),ncid,name,len,idp))
    return idp[1]
end

"""Return the id of a NetCDF dimension."""
function nc_inq_dimid(ncid::Integer,name)
    dimidp = Vector{Cint}(undef,1)
    check(ccall((:nc_inq_dimid,libnetcdf),Cint,(Cint,Cstring,Ptr{Cint}),ncid,name,dimidp))
    return dimidp[1]
end

# function nc_inq_dim(ncid::Integer,dimid::Integer,name,lenp)
#     check(ccall((:nc_inq_dim,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Cint}),ncid,dimid,name,lenp))
# end

function nc_inq_dimname(ncid::Integer,dimid::Integer)
    cname = zeros(UInt8,NC_MAX_NAME+1)

    check(ccall((:nc_inq_dimname,libnetcdf),Cint,(Cint,Cint,Ptr{UInt8}),ncid,dimid,cname))

    return unsafe_string(pointer(cname))
end

function nc_inq_dimlen(ncid::Integer,dimid::Integer)
    lengthp = zeros(Csize_t,1)
    check(ccall((:nc_inq_dimlen,libnetcdf),Cint,(Cint,Cint,Ptr{Csize_t}),ncid,dimid,lengthp))
    return Int(lengthp[1])
end

function nc_rename_dim(ncid::Integer,dimid::Integer,name)
    check(ccall((:nc_rename_dim,libnetcdf),Cint,(Cint,Cint,Cstring),ncid,dimid,name))
end

function nc_inq_att(ncid::Integer,varid::Integer,name)
    xtypep = zeros(nc_type,1)
    lenp = zeros(Csize_t,1)

    check(ccall((:nc_inq_att,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{nc_type},Ptr{Cint}),ncid,varid,name,xtypep,lenp))

    return xtypep[1],lenp[1]
end

# function nc_inq_attid(ncid::Integer,varid::Integer,name,idp)
#     check(ccall((:nc_inq_attid,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Cint}),ncid,varid,name,idp))
# end

# function nc_inq_atttype(ncid::Integer,varid::Integer,name,xtypep)
#     check(ccall((:nc_inq_atttype,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{nc_type}),ncid,varid,name,xtypep))
# end

# function nc_inq_attlen(ncid::Integer,varid::Integer,name,lenp)
#     check(ccall((:nc_inq_attlen,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Cint}),ncid,varid,name,lenp))
# end

function nc_inq_attname(ncid::Integer,varid::Integer,attnum::Integer)
    cname = zeros(UInt8,NC_MAX_NAME+1)

    check(ccall((:nc_inq_attname,libnetcdf),Cint,(Cint,Cint,Cint,Ptr{UInt8}),ncid,varid,attnum,cname))
    # really necessary?
    cname[end]=0

   return unsafe_string(pointer(cname))
end

# function nc_copy_att(ncid_in::Integer,varid_in::Integer,name,ncid_out::Integer,varid_out::Integer)
#     check(ccall((:nc_copy_att,libnetcdf),Cint,(Cint,Cint,Cstring,Cint,Cint),ncid_in,varid_in,name,ncid_out,varid_out))
# end

# function nc_rename_att(ncid::Integer,varid::Integer,name,newname)
#     check(ccall((:nc_rename_att,libnetcdf),Cint,(Cint,Cint,Cstring,Cstring),ncid,varid,name,newname))
# end

# function nc_del_att(ncid::Integer,varid::Integer,name)
#     check(ccall((:nc_del_att,libnetcdf),Cint,(Cint,Cint,Cstring),ncid,varid,name))
# end

# function nc_put_att_text(ncid::Integer,varid::Integer,name,len::Integer,op)
#     check(ccall((:nc_put_att_text,libnetcdf),Cint,(Cint,Cint,Cstring,Cint,Cstring),ncid,varid,name,len,op))
# end

# function nc_get_att_text(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_text,libnetcdf),Cint,(Cint,Cint,Cstring,Cstring),ncid,varid,name,ip))
# end

# function nc_put_att_string(ncid::Integer,varid::Integer,name,len::Integer,op)
#     check(ccall((:nc_put_att_string,libnetcdf),Cint,(Cint,Cint,Cstring,Cint,Ptr{Ptr{UInt8}}),ncid,varid,name,len,op))
# end

# function nc_get_att_string(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_string,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Ptr{UInt8}}),ncid,varid,name,ip))
# end

# function nc_put_att_uchar(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_uchar,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Cint,Ptr{Cuchar}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_uchar(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_uchar,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Cuchar}),ncid,varid,name,ip))
# end

# function nc_put_att_schar(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_schar,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Cint,Ptr{UInt8}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_schar(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_schar,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{UInt8}),ncid,varid,name,ip))
# end

# function nc_put_att_short(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_short,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Cint,Ptr{Int16}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_short(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_short,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Int16}),ncid,varid,name,ip))
# end

# function nc_put_att_int(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_int,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Cint,Ptr{Cint}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_int(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_int,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Cint}),ncid,varid,name,ip))
# end

# function nc_put_att_long(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_long,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Cint,Ptr{Clong}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_long(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_long,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Clong}),ncid,varid,name,ip))
# end

# function nc_put_att_float(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_float,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Cint,Ptr{Cfloat}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_float(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_float,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Cfloat}),ncid,varid,name,ip))
# end

# function nc_put_att_double(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_double,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Cint,Ptr{Cdouble}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_double(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_double,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Cdouble}),ncid,varid,name,ip))
# end

# function nc_put_att_ushort(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_ushort,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Cint,Ptr{UInt16}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_ushort(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_ushort,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{UInt16}),ncid,varid,name,ip))
# end

# function nc_put_att_uint(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_uint,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Cint,Ptr{UInt32}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_uint(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_uint,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{UInt32}),ncid,varid,name,ip))
# end

# function nc_put_att_longlong(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_longlong,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Cint,Ptr{Clonglong}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_longlong(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_longlong,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Clonglong}),ncid,varid,name,ip))
# end

# function nc_put_att_ulonglong(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_ulonglong,libnetcdf),Cint,(Cint,Cint,Cstring,nc_type,Cint,Ptr{Culonglong}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_ulonglong(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_ulonglong,libnetcdf),Cint,(Cint,Cint,Cstring,Ptr{Culonglong}),ncid,varid,name,ip))
# end

function nc_def_var(ncid::Integer,name,xtype::Integer,dimids::Vector{Cint})
    varidp = Vector{Cint}(undef,1)

    check(ccall((:nc_def_var,libnetcdf),Cint,(Cint,Cstring,nc_type,Cint,Ptr{Cint},Ptr{Cint}),ncid,name,xtype,length(dimids),dimids,varidp))

    return varidp[1]
end

function nc_inq_var(ncid::Integer,varid::Integer)
    ndims = nc_inq_varndims(ncid,varid)

    ndimsp = zeros(Int,1)
    cname = zeros(UInt8,NC_MAX_NAME+1)
    dimids = zeros(Cint,ndims)
    nattsp = Vector{Cint}(undef,1)
    xtypep = zeros(nc_type,1)

    check(ccall((:nc_inq_var,libnetcdf),Cint,(Cint,Cint,Ptr{UInt8},Ptr{nc_type},Ptr{Cint},Ptr{Cint},Ptr{Cint}),ncid,varid,cname,xtypep,ndimsp,dimids,nattsp))

    name = unsafe_string(pointer(cname))

    xtype = xtypep[1]
    jltype =
        if xtype >= NCDatasets.NC_FIRSTUSERTYPEID
            name,size,base_nc_type,nfields,class = nc_inq_user_type(ncid,xtype)
            # assume here variable-length type
            @assert(class == NC_VLEN)
            Vector{jlType[base_nc_type]}
        else
            jlType[xtype]
        end

    return name,jltype,dimids,nattsp[1]
end

function nc_inq_varid(ncid::Integer,name)
    varidp = zeros(Cint,1)

    code = ccall((:nc_inq_varid,libnetcdf),Cint,(Cint,Cstring,Ptr{Cint}),ncid,name,varidp);
    if code == NC_NOERR
        return varidp[1]
    else
        # return a more helpful error message (i.e. with the path)
        path =
            try
                nc_inq_path(ncid)
            catch
                "<unknown>"
            end

        throw(NetCDFError(code, "Variable '$name' not found in file $path"))
    end
end

function nc_inq_varname(ncid::Integer,varid::Integer)
    cname = zeros(UInt8,NC_MAX_NAME+1)
    check(ccall((:nc_inq_varname,libnetcdf),Cint,(Cint,Cint,Ptr{UInt8}),ncid,varid,cname))
    return unsafe_string(pointer(cname))
end

function nc_inq_vartype(ncid::Integer,varid::Integer)
    xtypep = zeros(nc_type,1)
    check(ccall((:nc_inq_vartype,libnetcdf),Cint,(Cint,Cint,Ptr{nc_type}),ncid,varid,xtypep))
    return xtypep[1]
end

function nc_inq_varndims(ncid::Integer,varid::Integer)
    ndimsp = zeros(Int,1)
    check(ccall((:nc_inq_varndims,libnetcdf),Cint,(Cint,Cint,Ptr{Cint}),ncid,varid,ndimsp))
    return ndimsp[1]
end

function nc_inq_vardimid(ncid::Integer,varid::Integer)
    ndims = nc_inq_varndims(ncid,varid)
    dimids = zeros(Cint,ndims)
    check(ccall((:nc_inq_vardimid,libnetcdf),Cint,(Cint,Cint,Ptr{Cint}),ncid,varid,dimids))
    return dimids
end

function nc_inq_varnatts(ncid::Integer,varid::Integer)
    nattsp = Vector{Cint}(undef,1)

    check(ccall((:nc_inq_varnatts,libnetcdf),Cint,(Cint,Cint,Ptr{Cint}),ncid,varid,nattsp))

    return nattsp[1]
end

function nc_rename_var(ncid::Integer,varid::Integer,name)
    check(ccall((:nc_rename_var,libnetcdf),Cint,(Cint,Cint,Cstring),ncid,varid,name))
end

# function nc_copy_var(ncid_in::Integer,varid::Integer,ncid_out::Integer)
#     check(ccall((:nc_copy_var,libnetcdf),Cint,(Cint,Cint,Cint),ncid_in,varid,ncid_out))
# end

# function nc_put_var1_text(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_text,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{UInt8}),ncid,varid,indexp,op))
# end

# function nc_get_var1_text(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_text,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{UInt8}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_uchar(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_uchar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cuchar}),ncid,varid,indexp,op))
# end

# function nc_get_var1_uchar(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_uchar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cuchar}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_schar(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_schar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{UInt8}),ncid,varid,indexp,op))
# end

# function nc_get_var1_schar(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_schar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{UInt8}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_short(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_short,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Int16}),ncid,varid,indexp,op))
# end

# function nc_get_var1_short(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_short,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Int16}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_int(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_int,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint}),ncid,varid,indexp,op))
# end

# function nc_get_var1_int(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_int,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_long(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_long,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Clong}),ncid,varid,indexp,op))
# end

# function nc_get_var1_long(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_long,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Clong}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_float(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_float,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cfloat}),ncid,varid,indexp,op))
# end

# function nc_get_var1_float(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_float,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cfloat}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_double(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_double,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cdouble}),ncid,varid,indexp,op))
# end

# function nc_get_var1_double(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_double,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cdouble}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_ushort(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_ushort,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{UInt16}),ncid,varid,indexp,op))
# end

# function nc_get_var1_ushort(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_ushort,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{UInt16}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_uint(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_uint,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{UInt32}),ncid,varid,indexp,op))
# end

# function nc_get_var1_uint(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_uint,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{UInt32}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_longlong(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_longlong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Clonglong}),ncid,varid,indexp,op))
# end

# function nc_get_var1_longlong(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_longlong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Clonglong}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_ulonglong(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_ulonglong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Culonglong}),ncid,varid,indexp,op))
# end

# function nc_get_var1_ulonglong(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_ulonglong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Culonglong}),ncid,varid,indexp,ip))
# end

# function nc_put_var1_string(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_string,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Ptr{UInt8}}),ncid,varid,indexp,op))
# end

# function nc_get_var1_string(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_string,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Ptr{UInt8}}),ncid,varid,indexp,ip))
# end

# function nc_put_vara_text(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_text,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_text(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_text,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_uchar(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_uchar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_uchar(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_uchar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_schar(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_schar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_schar(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_schar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_short(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_short,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Int16}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_short(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_short,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Int16}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_int(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_int,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_int(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_int,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_long(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_long,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Clong}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_long(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_long,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Clong}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_float(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_float,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cfloat}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_float(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_float,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cfloat}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_double(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_double,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cdouble}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_double(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_double,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cdouble}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_ushort(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_ushort,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{UInt16}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_ushort(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_ushort,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{UInt16}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_uint(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_uint,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{UInt32}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_uint(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_uint,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{UInt32}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_longlong(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_longlong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Clonglong}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_longlong(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_longlong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Clonglong}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_ulonglong(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_ulonglong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Culonglong}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_ulonglong(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_ulonglong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Culonglong}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vara_string(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_string,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Ptr{UInt8}}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_string(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_string,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Ptr{UInt8}}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vars_text(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_text,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_text(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_text,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_uchar(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_uchar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_uchar(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_uchar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_schar(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_schar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_schar(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_schar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_short(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_short,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Int16}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_short(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_short,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Int16}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_int(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_int,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_int(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_int,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_long(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_long,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Clong}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_long(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_long,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Clong}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_float(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_float,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cfloat}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_float(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_float,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cfloat}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_double(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_double,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cdouble}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_double(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_double,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cdouble}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_ushort(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_ushort,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt16}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_ushort(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_ushort,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt16}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_uint(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_uint,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt32}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_uint(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_uint,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt32}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_longlong(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_longlong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Clonglong}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_longlong(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_longlong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Clonglong}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_ulonglong(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_ulonglong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Culonglong}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_ulonglong(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_ulonglong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Culonglong}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_vars_string(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_string,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Ptr{UInt8}}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_string(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_string,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Ptr{UInt8}}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_varm_text(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_text,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_text(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_text,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_uchar(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_uchar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_uchar(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_uchar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_schar(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_schar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_schar(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_schar,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt8}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_short(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_short,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Int16}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_short(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_short,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Int16}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_int(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_int,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_int(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_int,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_long(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_long,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Clong}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_long(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_long,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Clong}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_float(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_float,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cfloat}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_float(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_float,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cfloat}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_double(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_double,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cdouble}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_double(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_double,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cdouble}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_ushort(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_ushort,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt16}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_ushort(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_ushort,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt16}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_uint(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_uint,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt32}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_uint(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_uint,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{UInt32}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_longlong(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_longlong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Clonglong}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_longlong(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_longlong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Clonglong}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_ulonglong(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_ulonglong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Culonglong}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_ulonglong(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_ulonglong,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Culonglong}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_varm_string(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_string,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Ptr{UInt8}}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_string(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_string,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Ptr{UInt8}}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_var_text(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_text,libnetcdf),Cint,(Cint,Cint,Ptr{UInt8}),ncid,varid,op))
# end

# function nc_get_var_text(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_text,libnetcdf),Cint,(Cint,Cint,Ptr{UInt8}),ncid,varid,ip))
# end

# function nc_put_var_uchar(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_uchar,libnetcdf),Cint,(Cint,Cint,Ptr{Cuchar}),ncid,varid,op))
# end

# function nc_get_var_uchar(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_uchar,libnetcdf),Cint,(Cint,Cint,Ptr{Cuchar}),ncid,varid,ip))
# end

# function nc_put_var_schar(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_schar,libnetcdf),Cint,(Cint,Cint,Ptr{UInt8}),ncid,varid,op))
# end

# function nc_get_var_schar(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_schar,libnetcdf),Cint,(Cint,Cint,Ptr{UInt8}),ncid,varid,ip))
# end

# function nc_put_var_short(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_short,libnetcdf),Cint,(Cint,Cint,Ptr{Int16}),ncid,varid,op))
# end

# function nc_get_var_short(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_short,libnetcdf),Cint,(Cint,Cint,Ptr{Int16}),ncid,varid,ip))
# end

# function nc_put_var_int(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_int,libnetcdf),Cint,(Cint,Cint,Ptr{Cint}),ncid,varid,op))
# end

# function nc_get_var_int(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_int,libnetcdf),Cint,(Cint,Cint,Ptr{Cint}),ncid,varid,ip))
# end

# function nc_put_var_long(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_long,libnetcdf),Cint,(Cint,Cint,Ptr{Clong}),ncid,varid,op))
# end

# function nc_get_var_long(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_long,libnetcdf),Cint,(Cint,Cint,Ptr{Clong}),ncid,varid,ip))
# end

# function nc_put_var_float(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_float,libnetcdf),Cint,(Cint,Cint,Ptr{Cfloat}),ncid,varid,op))
# end

# function nc_get_var_float(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_float,libnetcdf),Cint,(Cint,Cint,Ptr{Cfloat}),ncid,varid,ip))
# end

# function nc_put_var_double(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_double,libnetcdf),Cint,(Cint,Cint,Ptr{Cdouble}),ncid,varid,op))
# end

# function nc_get_var_double(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_double,libnetcdf),Cint,(Cint,Cint,Ptr{Cdouble}),ncid,varid,ip))
# end

# function nc_put_var_ushort(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_ushort,libnetcdf),Cint,(Cint,Cint,Ptr{UInt16}),ncid,varid,op))
# end

# function nc_get_var_ushort(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_ushort,libnetcdf),Cint,(Cint,Cint,Ptr{UInt16}),ncid,varid,ip))
# end

# function nc_put_var_uint(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_uint,libnetcdf),Cint,(Cint,Cint,Ptr{UInt32}),ncid,varid,op))
# end

# function nc_get_var_uint(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_uint,libnetcdf),Cint,(Cint,Cint,Ptr{UInt32}),ncid,varid,ip))
# end

# function nc_put_var_longlong(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_longlong,libnetcdf),Cint,(Cint,Cint,Ptr{Clonglong}),ncid,varid,op))
# end

# function nc_get_var_longlong(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_longlong,libnetcdf),Cint,(Cint,Cint,Ptr{Clonglong}),ncid,varid,ip))
# end

# function nc_put_var_ulonglong(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_ulonglong,libnetcdf),Cint,(Cint,Cint,Ptr{Culonglong}),ncid,varid,op))
# end

# function nc_get_var_ulonglong(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_ulonglong,libnetcdf),Cint,(Cint,Cint,Ptr{Culonglong}),ncid,varid,ip))
# end

# function nc_put_var_string(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_string,libnetcdf),Cint,(Cint,Cint,Ptr{Ptr{UInt8}}),ncid,varid,op))
# end

# function nc_get_var_string(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_string,libnetcdf),Cint,(Cint,Cint,Ptr{Ptr{UInt8}}),ncid,varid,ip))
# end

# function nc_put_att_ubyte(ncid::Integer,varid::Integer,name,xtype::Integer,len::Integer,op)
#     check(ccall((:nc_put_att_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{UInt8},nc_type,Cint,Ptr{Cuchar}),ncid,varid,name,xtype,len,op))
# end

# function nc_get_att_ubyte(ncid::Integer,varid::Integer,name,ip)
#     check(ccall((:nc_get_att_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{UInt8},Ptr{Cuchar}),ncid,varid,name,ip))
# end

# function nc_put_var1_ubyte(ncid::Integer,varid::Integer,indexp,op)
#     check(ccall((:nc_put_var1_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cuchar}),ncid,varid,indexp,op))
# end

# function nc_get_var1_ubyte(ncid::Integer,varid::Integer,indexp,ip)
#     check(ccall((:nc_get_var1_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cuchar}),ncid,varid,indexp,ip))
# end

# function nc_put_vara_ubyte(ncid::Integer,varid::Integer,startp,countp,op)
#     check(ccall((:nc_put_vara_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,op))
# end

# function nc_get_vara_ubyte(ncid::Integer,varid::Integer,startp,countp,ip)
#     check(ccall((:nc_get_vara_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,ip))
# end

# function nc_put_vars_ubyte(ncid::Integer,varid::Integer,startp,countp,stridep,op)
#     check(ccall((:nc_put_vars_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,stridep,op))
# end

# function nc_get_vars_ubyte(ncid::Integer,varid::Integer,startp,countp,stridep,ip)
#     check(ccall((:nc_get_vars_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,stridep,ip))
# end

# function nc_put_varm_ubyte(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,op)
#     check(ccall((:nc_put_varm_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,stridep,imapp,op))
# end

# function nc_get_varm_ubyte(ncid::Integer,varid::Integer,startp,countp,stridep,imapp,ip)
#     check(ccall((:nc_get_varm_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cint},Ptr{Cuchar}),ncid,varid,startp,countp,stridep,imapp,ip))
# end

# function nc_put_var_ubyte(ncid::Integer,varid::Integer,op)
#     check(ccall((:nc_put_var_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{Cuchar}),ncid,varid,op))
# end

# function nc_get_var_ubyte(ncid::Integer,varid::Integer,ip)
#     check(ccall((:nc_get_var_ubyte,libnetcdf),Cint,(Cint,Cint,Ptr{Cuchar}),ncid,varid,ip))
# end

# function nc_show_metadata(ncid::Integer)
#     check(ccall((:nc_show_metadata,libnetcdf),Cint,(Cint,),ncid))
# end

# function nc__create_mp(path,cmode::Integer,initialsz::Integer,basepe::Integer,chunksizehintp,ncidp)
#     check(ccall((:nc__create_mp,libnetcdf),Cint,(Cstring,Cint,Cint,Cint,Ptr{Cint},Ptr{Cint}),path,cmode,initialsz,basepe,chunksizehintp,ncidp))
# end

# function nc__open_mp(path,mode::Integer,basepe::Integer,chunksizehintp,ncidp)
#     check(ccall((:nc__open_mp,libnetcdf),Cint,(Cstring,Cint,Cint,Ptr{Cint},Ptr{Cint}),path,mode,basepe,chunksizehintp,ncidp))
# end

# function nc_delete(path)
#     check(ccall((:nc_delete,libnetcdf),Cint,(Cstring,),path))
# end

# function nc_delete_mp(path,basepe::Integer)
#     check(ccall((:nc_delete_mp,libnetcdf),Cint,(Cstring,Cint),path,basepe))
# end

# function nc_set_base_pe(ncid::Integer,pe::Integer)
#     check(ccall((:nc_set_base_pe,libnetcdf),Cint,(Cint,Cint),ncid,pe))
# end

# function nc_inq_base_pe(ncid::Integer,pe)
#     check(ccall((:nc_inq_base_pe,libnetcdf),Cint,(Cint,Ptr{Cint}),ncid,pe))
# end

ext: jl


text:
@testset "Optimizers" begin

  function g(x)
     -x
  end
  optimizers=Any[]
  push!(optimizers,SGMCMC.SGDState(ones(3),0.01))
  push!(optimizers,SGMCMC.AdamState(ones(3),stepsize= 0.01))
  push!(optimizers,SGMCMC.AdagradState(ones(3),stepsize=0.01))
  push!(optimizers,SGMCMC.RelFrozenState(ones(3),stepsize=0.01))
  srand(2)
  ss=10^5
  for i=1:ss
      #@show sgds.x
      [SGMCMC.sample!(opt,g) for opt in optimizers]
  end
  for opt in optimizers
      @test isapprox(opt.x[1],0.0,atol=0.0001)
  end

end


text:
using CSV, DataFrames

@testset "LocalLevel" begin
    nile = CSV.File(StateSpaceModels.NILE) |> DataFrame

    @test has_fit_methods(LocalLevel)

    model = LocalLevel(nile.flow)

    # Test that getter functions throw error for model that hasn't been fitted yet
    @test_throws ErrorException get_innovations(model)
    @test_throws ErrorException get_innovations_variance(model)
    @test_throws ErrorException get_filtered_state(model)
    @test_throws ErrorException get_filtered_state_variance(model)
    @test_throws ErrorException get_predictive_state(model)
    @test_throws ErrorException get_predictive_state_variance(model)
    @test_throws ErrorException show(stdout, results(model))

    fit!(model)
    @test loglike(model) ≈ -632.5376 atol = 1e-5 rtol = 1e-5

    forec = forecast(model, 10)
    @test monotone_forecast_variance(forec)
    # simulating
    scenarios = simulate_scenarios(model, 10, 100_000)
    test_scenarios_adequacy_with_forecast(forec, scenarios)

    filter = kalman_filter(model)

    # Test that getter functions now work since model has been fitted
    @test get_innovations(model) == get_innovations(filter)
    @test get_innovations_variance(model) == get_innovations_variance(filter)
    @test get_filtered_state(model) == get_filtered_state(filter)
    @test get_filtered_state_variance(model) == get_filtered_state_variance(filter)
    @test get_predictive_state(model) == get_predictive_state(filter)
    @test get_predictive_state_variance(model) == get_predictive_state_variance(filter)

    # Durbin Koopman 2012 section 2.2.5
    a1 = 0.0
    P1 = 1e7
    scalar_filter = ScalarKalmanFilter(a1, P1, 1)
    model = LocalLevel(nile.flow)
    fit!(model; filter=scalar_filter)

    # Without the concentrated filter and score calculation this is close enough
    @test get_constrained_value(model, "sigma2_ε") ≈ 15099 rtol = 1e-3
    @test get_constrained_value(model, "sigma2_η") ≈ 1469.1 rtol = 1e-3

    # Fix some parameters
    model = LocalLevel(nile.flow)
    fix_hyperparameters!(model, Dict("sigma2_ε" => 15099.0))
    fit!(model; filter=scalar_filter)

    hyperparameters = get_hyperparameters(model)
    @test !isempty(hyperparameters.minimizer_hyperparameter_position)

    @test loglike(model; filter=scalar_filter) ≈ -632.54421 atol = 1e-5 rtol = 1e-5
    @test get_constrained_value(model, "sigma2_η") ≈ 1469.1 rtol = 1e-2

    # Estimate with Float32
    nile32 = Float32.(nile.flow)
    model = LocalLevel(nile32)
    fit!(model)
    @test loglike(model) ≈ -632.53766f0 atol = 1e-5 rtol = 1e-5

    # Missing values
    nile.flow[[collect(21:40); collect(61:80)]] .= NaN
    model = LocalLevel(nile.flow)
    fit!(model)
    @test loglike(model) ≈ -379.9899 atol = 1e-5 rtol = 1e-5

    filter = kalman_filter(model)
    smoother = kalman_smoother(model)
    @test filter.Ptt[end] == smoother.V[end] # by construction

    for t in 2:(length(model.system.y) - 1)
        @test filter.Ptt[t][1] > smoother.V[t][1] # by construction
    end

    # Forecasting of series with missing values
    # forecasting
    forec = forecast(model, 10)
    @test monotone_forecast_variance(forec)
    # simulating
    scenarios = simulate_scenarios(model, 10, 100_000)
    test_scenarios_adequacy_with_forecast(forec, scenarios)
end


text:
"""
```
hog_params = HOG([orientations = 9], [cell_size = 8], [block_size = 2], [block_stride = 1], [norm_method = "L2-norm"])
```

Histogram of Oriented Gradient (HOG) is a dense feature desciptor usually used for object detection. See "Histograms of Oriented Gradients for Human Detection" by Dalal and Triggs.

Parameters:
-    orientations   = number of orientation bins
-    cell_size      = size of a cell is cell_size x cell_size (in pixels)
-    block_size     = size of a block is block_size x block_size (in terms of cells)
-    block_stride   = stride of blocks. Controls how much adjacent blocks overlap.
-    norm_method    = block normalization method. Options: L2-norm, L2-hys, L1-norm, L2-sqrt.
"""
mutable struct HOG <: Params
    orientations::Int
    cell_size::Int
    block_size::Int
    block_stride::Int
    norm_method::String
end

function HOG(; orientations::Int = 9, cell_size::Int = 8, block_size::Int = 2, block_stride::Int = 1, norm_method::String = "L2-norm")
    HOG(orientations, cell_size, block_size, block_stride, norm_method)
end

function create_descriptor(img::AbstractArray{CT, 2}, params::HOG) where CT<:Images.NumberLike
    #compute gradient
    gx = imfilter(img, centered([-1 0 1]))
    gy = imfilter(img, centered([-1 0 1]'))
    mag = hypot.(gx, gy)
    phase = orientation.(gx, gy)

    create_hog_descriptor(mag, phase, params)
end

function create_descriptor(img::AbstractArray{CT, 2}, params::HOG) where CT<:Images.Color{T, N} where T where N
    #for color images, compute seperate gradient for each color channel and take one with largest norm as pixel's gradient vector
    rows, cols = size(img)
    gx = channelview(imfilter(img, centered([-1 0 1])))
    gy = channelview(imfilter(img, centered([-1 0 1]')))
    mag = hypot.(gx, gy)
    phase = orientation.(gx, gy)

    max_mag = zeros(rows, cols)
    max_phase = zeros(rows, cols)

    for j in axes(mag, 3)
        for i in axes(mag, 2)
            ind = argmax(view(mag, :, i, j))
            max_mag[i, j] = mag[ind, i, j]
            max_phase[i, j] = phase[ind, i, j]
        end
    end

    create_hog_descriptor(max_mag, max_phase, params)
end

function create_hog_descriptor(mag::AbstractArray{T, 2}, phase::AbstractArray{T, 2}, params::HOG) where T<:Images.NumberLike
    orientations = params.orientations
    cell_size = params.cell_size
    block_size = params.block_size
    block_stride = params.block_stride

    rows, cols = size(mag)
    if rows%cell_size!=0 || cols%cell_size!=0
        error("Height and Width of the image must be a multiple of cell_size.")
    end

    cell_rows::Int = rows/cell_size
    cell_cols::Int = cols/cell_size
    if (cell_rows-block_size)%block_stride!=0 || (cell_cols-block_size)%block_stride!=0
        error("Block size and block stride don't match.")
    end

    phase = abs.(phase*180/pi)

    #orientation binning for each cell
    hist = zeros(Float64, (orientations, cell_rows, cell_cols))
    R = CartesianIndices(axes(mag))

    for i in R
        trilinear_interpolate!(hist, mag[i], phase[i], orientations, i, cell_size, cell_rows, cell_cols, rows, cols)
    end

    function normalize(v, method)
        if method == "L2-norm"
            return v./sqrt(sum(abs2, v) + 1e-5)
        elseif method == "L2-hys"
            v = v./(sum(abs2, v) + 1e-5)
            v = min.(v, 0.2)
            return v./(sum(abs2, v) + 1e-5)
        elseif method == "L1-norm"
            return v./(sum(abs, v) + 1e-5)
        elseif method == "L1-sqrt"
            return sqrt.(v./(sum(abs, v) + 1e-5))
        end
    end

    #contrast normalization for each block
    descriptor_size::Int = ((cell_rows-block_size)/block_stride + 1) * ((cell_cols-block_size)/block_stride + 1) * (block_size*block_size) * orientations
    descriptor = Vector{Float64}(undef, descriptor_size)
    block_vector_size = block_size * block_size * orientations
    k = 1
    for j in 1:block_stride:cell_cols-block_size+1
        for i in 1:block_stride:cell_rows-block_size+1
            H = @view hist[:, i:i+block_size-1, j:j+block_size-1]
            h = @view H[:]
            descriptor[block_vector_size*(k-1)+1 : block_vector_size*k] = normalize(h, params.norm_method)
            k += 1
        end
    end

    return descriptor
end

function trilinear_interpolate!(hist, w, θ, orientations, i, cell_size, cell_rows, cell_cols, rows, cols)
    bin_θ1 = min(floor(Int, θ*orientations/180) + 1, orientations)
    bin_θ2 = bin_θ1%orientations + 1
    b_θ = 180/orientations

    if bin_θ1 != orientations
        θ1 = (bin_θ1-1)*180/orientations
        θ2 = (bin_θ2-1)*180/orientations
    else
        θ1 = (bin_θ1-1)*180/orientations
        θ2 = 180.0;
    end

    if (i[1]<=cell_size/2 || i[1]>=rows-cell_size/2) && (i[2]<=cell_size/2 || i[2]>=cols-cell_size/2)
        #linear interpolation for corner points
        bin_x = i[1] < cell_size/2 ? 1 : cell_rows
        bin_y = i[2] < cell_size/2 ? 1 : cell_cols

        hist[bin_θ1, bin_x, bin_y] += w*(1-(θ-θ1)/b_θ)
        hist[bin_θ2, bin_x, bin_y] += w*(1-(θ2-θ)/b_θ)

    elseif i[1]<=cell_size/2 || i[1]>=rows-cell_size/2
        #bilinear interpolation for (top/bottom) edge points
        bin_x = i[1] < cell_size/2 ? 1 : cell_rows
        bin_y1 = floor(Int, (i[2]+cell_size/2)/cell_size)
        bin_y2 = bin_y1 + 1

        y1 = (bin_y1-1)*cell_size+cell_size/2
        y2 = (bin_y2-1)*cell_size+cell_size/2
        b_y = cell_size

        hist[bin_θ1, bin_x, bin_y1] += w*(1-(θ-θ1)/b_θ)*(1-(i[2]-y1)/b_y)
        hist[bin_θ1, bin_x, bin_y2] += w*(1-(θ-θ1)/b_θ)*(1-(y2-i[2])/b_y)
        hist[bin_θ2, bin_x, bin_y1] += w*(1-(θ2-θ)/b_θ)*(1-(i[2]-y1)/b_y)
        hist[bin_θ2, bin_x, bin_y2] += w*(1-(θ2-θ)/b_θ)*(1-(y2-i[2])/b_y)

    elseif  i[2]<=cell_size/2 || i[2]>=cols-cell_size/2
        #bilinear interpolation for (left/right) edge points
        bin_x1 = floor(Int, (i[1]+cell_size/2)/cell_size)
        bin_x2 = bin_x1 + 1
        bin_y = i[2] < cell_size/2 ? 1 : cell_cols

        x1 = (bin_x1-1)*cell_size+cell_size/2
        x2 = (bin_x2-1)*cell_size+cell_size/2
        b_x = cell_size

        hist[bin_θ1, bin_x1, bin_y] += w*(1-(θ-θ1)/b_θ)*(1-(i[1]-x1)/b_x)
        hist[bin_θ1, bin_x2, bin_y] += w*(1-(θ-θ1)/b_θ)*(1-(x2-i[1])/b_x)
        hist[bin_θ2, bin_x1, bin_y] += w*(1-(θ2-θ)/b_θ)*(1-(i[1]-x1)/b_x)
        hist[bin_θ2, bin_x2, bin_y] += w*(1-(θ2-θ)/b_θ)*(1-(x2-i[1])/b_x)
    else
        #trilinear interpolation
        bin_x1 = floor(Int, (i[1]+cell_size/2)/cell_size)
        bin_x2 = bin_x1 + 1
        bin_y1 = floor(Int, (i[2]+cell_size/2)/cell_size)
        bin_y2 = bin_y1 + 1

        x1 = (bin_x1-1)*cell_size+cell_size/2
        x2 = (bin_x2-1)*cell_size+cell_size/2
        b_x = cell_size

        y1 = (bin_y1-1)*cell_size+cell_size/2
        y2 = (bin_y2-1)*cell_size+cell_size/2
        b_y = cell_size

        hist[bin_θ1, bin_x1, bin_y1] += w*(1-(θ-θ1)/b_θ)*(1-(i[1]-x1)/b_x)*(1-(i[2]-y1)/b_y)
        hist[bin_θ1, bin_x1, bin_y2] += w*(1-(θ-θ1)/b_θ)*(1-(i[1]-x1)/b_x)*(1-(y2-i[2])/b_y)
        hist[bin_θ1, bin_x2, bin_y1] += w*(1-(θ-θ1)/b_θ)*(1-(x2-i[1])/b_x)*(1-(i[2]-y1)/b_y)
        hist[bin_θ1, bin_x2, bin_y2] += w*(1-(θ-θ1)/b_θ)*(1-(x2-i[1])/b_x)*(1-(y2-i[2])/b_y)
        hist[bin_θ2, bin_x1, bin_y1] += w*(1-(θ2-θ)/b_θ)*(1-(i[1]-x1)/b_x)*(1-(i[2]-y1)/b_y)
        hist[bin_θ2, bin_x1, bin_y2] += w*(1-(θ2-θ)/b_θ)*(1-(i[1]-x1)/b_x)*(1-(y2-i[2])/b_y)
        hist[bin_θ2, bin_x2, bin_y1] += w*(1-(θ2-θ)/b_θ)*(1-(x2-i[1])/b_x)*(1-(i[2]-y1)/b_y)
        hist[bin_θ2, bin_x2, bin_y2] += w*(1-(θ2-θ)/b_θ)*(1-(x2-i[1])/b_x)*(1-(y2-i[2])/b_y)
    end
end


text:
isdefined(:OptionsMod) || @eval import Options
using OptionsMod
using Base.Test

# basic functionality
oo = Options(:a, true, :b, 7)
@test length(oo.key2index) == 2
@test oo[:a] == true
@test oo[:b] > 6
@test oo[:c] == nothing
@test sprint(show, oo) == "a = true, b = 7 ($CheckError)"

# other constructors
oo2 = Options(CheckWarn, :(a=true), :(b=7))
@test oo2[:a] == true
oo3 = @options a=true b=7
@test oo3[:b] == 7

# changing options
oo2[:b] = 6
oo2[:c] = "cat"
@test oo2[:b] < 7
@test oo2[:c] == "cat"

# simple example
function f1(a, b, o::Options)
	@defaults o op="plus"
    if op == "plus"
        return a + b
    else
        return a - b
    end
	@check_used o
end
f1(a, b) = f1(a, b, Options())
@test f1(3, 2) == 5
@test f1(3, 2, Options(:op, "plus")) == 5
@test f1(3, 2, Options(:op, "other")) == 1

# complex example
function complexfun(x, opts::Options)
    @defaults opts parent=3 both=7
    sub1, both1 = subfun1(x, opts)
    sub2, both2 = subfun2(x, opts)
    @check_used opts
    return parent, both, sub1, both1, sub2, both2
end
complexfun(x) = complexfun(x, Options())

function subfun1(x, opts::Options)
    @defaults opts sub1="sub1 default" both=0
    @check_used opts
    return sub1, both
end

function subfun2(x, opts::Options)
    @defaults opts sub2="sub2 default" both=22
    @check_used opts
    return sub2, both
end

@test complexfun(5) == (3,7,"sub1 default", 0, "sub2 default", 22)
opts = @options sub2=15
@test complexfun(5, opts) == (3,7,"sub1 default", 0, 15, 22)
@set_options opts both=8
@test complexfun(5, opts) == (3,8,"sub1 default", 8, 15, 8)
@set_options opts sub1a=5

@test_throws ErrorException complexfun(5, opts)


text:
_symbols(a; kwargs...) = Sym(__sympy__.symbols(a; kwargs...))
# split on comma (add space?)
symbols(a; kwargs...) = contains(a, ",") ? _symbols.(split(a, ","); kwargs...) : _symbols(a; kwargs...)

macro syms(xs...)
    # If the user separates declaration with commas, the top-level expression is a tuple
    if length(xs) == 1 && isa(xs[1], Expr) && xs[1].head == :tuple
        _gensyms(xs[1].args...)
    elseif length(xs) > 0
        _gensyms(xs...)
    end
end

max_stars_repo_name: jverzani/SymPyCall

max_issues_repo_name: jverzani/SymPyCall

max_forks_repo_name: jverzani/SymPyCall


text:
function train_network1d(datatyp, n_dims, η, β, number_epochs, Sb, L,
                        hidden_units_1, hidden_units_2, hidden_units_3,
                        hidden_units_4, hidden_units_5)

    #Load data
    x_train = h5open("examples/$(n_dims)d/traindata$(n_dims)d$(datatyp).h5", "r") do file
        read(file, "X")
    end
    y_train = h5open("examples/$(n_dims)d/traindata$(n_dims)d$(datatyp).h5", "r") do file
        read(file, "Y")
    end
    x_valid = h5open("examples/$(n_dims)d/validdata$(n_dims)d$(datatyp).h5", "r") do file
        read(file, "X")
    end
    y_valid = h5open("examples/$(n_dims)d/validdata$(n_dims)d$(datatyp).h5", "r") do file
        read(file, "Y")
    end
    println(size(x_train))
    println(size(x_valid))
    @info("Building model...")
    input_size = size(x_train)[1]
    model1d = Flux.Chain(
                    Dense(input_size, hidden_units_1, leakyrelu, initW=Flux.glorot_normal),
                    Dense(hidden_units_1, hidden_units_2, leakyrelu, initW=Flux.glorot_normal),
                    Dense(hidden_units_2, hidden_units_3, leakyrelu, initW=Flux.glorot_normal),
                    Dense(hidden_units_3, hidden_units_4, leakyrelu, initW=Flux.glorot_normal),
                    Dense(hidden_units_4, hidden_units_5, leakyrelu, initW=Flux.glorot_normal),
                    Dense(hidden_units_5, 2),
                    softmax)

    opt = ADAM(η)
    ps = Flux.params(model1d)[1:2:11]
    accuracy(ŷ, y) = mean(onecold(ŷ) .== onecold(y))
    sqnorm(x) = sum(abs2, x)
    loss(x, y) = Flux.crossentropy(model1d(x), y) + β * sum(sqnorm, ps)

    @info("Beginning training loop...")
    best_acc = 0.0
    last_improvement = 0
    for epoch_idx in 1:number_epochs
        # Create the full dataset
        train_data = DataLoader((x_train, y_train) ; batchsize=Sb, shuffle=true)
        Flux.train!(loss, params(model1d), train_data, opt)
        acc = accuracy(model1d(x_valid), y_valid)
        acc2 = accuracy(model1d(x_train), y_train)
        loss_idx = loss(x_train, y_train)
        parasum = sum(sqnorm, params(model1d))
        @show epoch_idx, acc, loss_idx, parasum, acc2
        #@save "networks/$(n_dims)d/model$(n_dims)d$(datatyp)-$(acc)-$(β).bson" model1d

        if acc > best_acc
            best_acc = acc
            last_improvement = epoch_idx
            @save "networks/$(n_dims)d/model$(n_dims)d$(datatyp)-$(acc)-$(β).bson" model1d
        end

        if epoch_idx - last_improvement >= L
            @warn("Early stopping")
            @show best_acc
            break
        end
    end
end