text:
# Julia wrapper for header: /Volumes/BOOTCAMP/programs/compa_libs/libim_process_/include/libim_process_.h

@static Sys.iswindows() ? (const liblibim_process__ = "libim_process_") : (const liblibim_process__ = "liblibim_process_")  # Name of shared lib.

#MacroDefinition: imImageGamma(_image,_gamma) {float params[1];params[0]=_gamma;imProcessToneGamut(_image,_image,IM_GAMUT_POW,params);}
function imImageGamma(image::Ptr{imImage}, _gamma)
    params = vector{CFloat}(1);
    params[1] = _gamma
    return imProcessToneGamut(image, image, IM_GAMUT_POW, params)
end

#MacroDefinition: imImageBrightnessContrast(_image,_bright_shift,_contrast_factor) {float _params[2];_params[0]=bright_shift;_params[1]=contrast_factor;imProcessToneGamut(_image,_image,IM_GAMUT_BRIGHTCONT,_params);}
function imImageBrightnessContrast(image::Ptr{imImage}, bright_shift, contrast_factor)
    params = vector{CFloat}(2);
    params[1] = bright_shift
    params[2] = contrast_factor
    return imProcessToneGamut(image, image, IM_GAMUT_BRIGHTCONT, params)
end

#MacroDefinition: imImageLevel(_image,_start,_end) {float_params[2];_params[0]=_start;_params[1]=_end;imProcessToneGamut(_image,_image,IM_GAMUT_EXPAND,_params);}
function imImageLevel(image::Ptr{imImage}, _start, _end)
    params = vector{CFloat}(2);
    params[1] = _start
    params[2] = _end
    return imProcessToneGamut(image, image, IM_GAMUT_EXPAND, params)
end

#MacroDefinition: imImageEqualize(_image) imProcessEqualizeHistogram(_image,_image)
function imImageEqualize(image::Ptr{imImage})
    return imProcessEqualizeHistogram(image, image)
end

#MacroDefinition: imImageNegative(_image) imProcessNegative(_image,_image)
function imImageNegative(image::Ptr{imImage})
    return imProcessNegative(image, image)
end

#MacroDefinition: imImageAutoLevel(_image,_percent) imProcessExpandHistogram(_image,_image,_percent)
function imImageAutoLevel(image::Ptr{imImage}, percent)
    return imProcessExpandHistogram(image, image, percent)
end

const imUnaryPointOpFunc = Ptr{Cvoid}
const imUnaryPointColorOpFunc = Ptr{Cvoid}
const imMultiPointOpFunc = Ptr{Cvoid}
const imMultiPointColorOpFunc = Ptr{Cvoid}

# begin enum imUnaryOp
const imUnaryOp = UInt32
const IM_UN_EQL = 0
const IM_UN_ABS = 1
const IM_UN_LESS = 2
const IM_UN_INV = 3
const IM_UN_SQR = 4
const IM_UN_SQRT = 5
const IM_UN_LOG = 6
const IM_UN_EXP = 7
const IM_UN_SIN = 8
const IM_UN_COS = 9
const IM_UN_CONJ = 10
const IM_UN_CPXNORM = 11
const IM_UN_POSITIVES = 12
const IM_UN_NEGATIVES = 13
# end enum imUnaryOp

# begin enum imBinaryOp
const imBinaryOp = UInt32
const IM_BIN_ADD = 0
const IM_BIN_SUB = 1
const IM_BIN_MUL = 2
const IM_BIN_DIV = 3
const IM_BIN_DIFF = 4
const IM_BIN_POW = 5
const IM_BIN_MIN = 6
const IM_BIN_MAX = 7
# end enum imBinaryOp

# begin enum imLogicOp
const imLogicOp = UInt32
const IM_BIT_AND = 0
const IM_BIT_OR = 1
const IM_BIT_XOR = 2
# end enum imLogicOp
const imRenderFunc = Ptr{Cvoid}
const imRenderCondFunc = Ptr{Cvoid}

# begin enum imToneGamut
const imToneGamut = UInt32
const IM_GAMUT_NORMALIZE = 0
const IM_GAMUT_POW = 1
const IM_GAMUT_LOG = 2
const IM_GAMUT_EXP = 3
const IM_GAMUT_INVERT = 4
const IM_GAMUT_ZEROSTART = 5
const IM_GAMUT_SOLARIZE = 6
const IM_GAMUT_SLICE = 7
const IM_GAMUT_EXPAND = 8
const IM_GAMUT_CROP = 9
const IM_GAMUT_BRIGHTCONT = 10
# end enum imToneGamut

# begin enum imToneGamutFlags
const imToneGamutFlags = UInt32
const IM_GAMUT_MINMAX = 256
# end enum imToneGamutFlags

mutable struct imStats
    max::Cfloat
    min::Cfloat
    positive::Culong
    negative::Culong
    zeros::Culong
    mean::Cfloat
    stddev::Cfloat
end

function imProcessUnaryPointOp(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, func::imUnaryPointOpFunc, params::Ptr{Cfloat}, userdata::Ptr{Cvoid}, op_name::Ptr{UInt8})
  ccall( (:imProcessUnaryPointOp, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, imUnaryPointOpFunc, Ptr{Cfloat}, Ptr{Cvoid}, Ptr{UInt8}), src_image, dst_image, func, params, userdata, op_name)
end

function imProcessUnaryPointColorOp(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, func::imUnaryPointColorOpFunc, params::Ptr{Cfloat}, userdata::Ptr{Cvoid}, op_name::Ptr{UInt8})
  ccall( (:imProcessUnaryPointColorOp, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, imUnaryPointColorOpFunc, Ptr{Cfloat}, Ptr{Cvoid}, Ptr{UInt8}), src_image, dst_image, func, params, userdata, op_name)
end

function imProcessMultiPointOp(src_image::Ptr{Ptr{imImage}}, src_count::Cint, dst_image::Ptr{imImage}, func::imMultiPointOpFunc, params::Ptr{Cfloat}, userdata::Ptr{Cvoid}, op_name::Ptr{UInt8})
  ccall( (:imProcessMultiPointOp, libim_process_), Cint, (Ptr{Ptr{imImage}}, Cint, Ptr{imImage}, imMultiPointOpFunc, Ptr{Cfloat}, Ptr{Cvoid}, Ptr{UInt8}), src_image, src_count, dst_image, func, params, userdata, op_name)
end

function imProcessMultiPointColorOp(src_image::Ptr{Ptr{imImage}}, src_count::Cint, dst_image::Ptr{imImage}, func::imMultiPointColorOpFunc, params::Ptr{Cfloat}, userdata::Ptr{Cvoid}, op_name::Ptr{UInt8})
  ccall( (:imProcessMultiPointColorOp, libim_process_), Cint, (Ptr{Ptr{imImage}}, Cint, Ptr{imImage}, imMultiPointColorOpFunc, Ptr{Cfloat}, Ptr{Cvoid}, Ptr{UInt8}), src_image, src_count, dst_image, func, params, userdata, op_name)
end

function imProcessUnArithmeticOp(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, op::Cint)
  ccall( (:imProcessUnArithmeticOp, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, op)
end

function imProcessArithmeticOp(src_image1::Ptr{imImage}, src_image2::Ptr{imImage}, dst_image::Ptr{imImage}, op::Cint)
  ccall( (:imProcessArithmeticOp, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Cint), src_image1, src_image2, dst_image, op)
end

function imProcessArithmeticConstOp(src_image::Ptr{imImage}, src_const::Cfloat, dst_image::Ptr{imImage}, op::Cint)
  ccall( (:imProcessArithmeticConstOp, libim_process_), Cvoid, (Ptr{imImage}, Cfloat, Ptr{imImage}, Cint), src_image, src_const, dst_image, op)
end

function imProcessBlendConst(src_image1::Ptr{imImage}, src_image2::Ptr{imImage}, dst_image::Ptr{imImage}, alpha::Cfloat)
  ccall( (:imProcessBlendConst, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Cfloat), src_image1, src_image2, dst_image, alpha)
end

function imProcessBlend(src_image1::Ptr{imImage}, src_image2::Ptr{imImage}, alpha_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessBlend, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image1, src_image2, alpha_image, dst_image)
end

function imProcessCompose(src_image1::Ptr{imImage}, src_image2::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessCompose, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image1, src_image2, dst_image)
end

function imProcessSplitComplex(src_image::Ptr{imImage}, dst_image1::Ptr{imImage}, dst_image2::Ptr{imImage}, polar::Cint)
  ccall( (:imProcessSplitComplex, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image1, dst_image2, polar)
end

function imProcessMergeComplex(src_image1::Ptr{imImage}, src_image2::Ptr{imImage}, dst_image::Ptr{imImage}, polar::Cint)
  ccall( (:imProcessMergeComplex, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Cint), src_image1, src_image2, dst_image, polar)
end

function imProcessMultipleMean(src_image_list::Ptr{Ptr{imImage}}, src_image_count::Cint, dst_image::Ptr{imImage})
  ccall( (:imProcessMultipleMean, libim_process_), Cvoid, (Ptr{Ptr{imImage}}, Cint, Ptr{imImage}), src_image_list, src_image_count, dst_image)
end

function imProcessMultipleStdDev(src_image_list::Ptr{Ptr{imImage}}, src_image_count::Cint, mean_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessMultipleStdDev, libim_process_), Cvoid, (Ptr{Ptr{imImage}}, Cint, Ptr{imImage}, Ptr{imImage}), src_image_list, src_image_count, mean_image, dst_image)
end

function imProcessAutoCovariance(src_image::Ptr{imImage}, mean_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessAutoCovariance, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image, mean_image, dst_image)
end

function imProcessMultiplyConj(src_image1::Ptr{imImage}, src_image2::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessMultiplyConj, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image1, src_image2, dst_image)
end

function imProcessQuantizeRGBUniform(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, do_dither::Cint)
  ccall( (:imProcessQuantizeRGBUniform, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, do_dither)
end

function imProcessQuantizeGrayUniform(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, grays::Cint)
  ccall( (:imProcessQuantizeGrayUniform, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, grays)
end

function imProcessExpandHistogram(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, percent::Cfloat)
  ccall( (:imProcessExpandHistogram, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cfloat), src_image, dst_image, percent)
end

function imProcessEqualizeHistogram(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessEqualizeHistogram, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessSplitYChroma(src_image::Ptr{imImage}, y_image::Ptr{imImage}, chroma_image::Ptr{imImage})
  ccall( (:imProcessSplitYChroma, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image, y_image, chroma_image)
end

function imProcessSplitHSI(src_image::Ptr{imImage}, h_image::Ptr{imImage}, s_image::Ptr{imImage}, i_image::Ptr{imImage})
  ccall( (:imProcessSplitHSI, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image, h_image, s_image, i_image)
end

function imProcessMergeHSI(h_image::Ptr{imImage}, s_image::Ptr{imImage}, i_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessMergeHSI, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), h_image, s_image, i_image, dst_image)
end

function imProcessSplitComponents(src_image::Ptr{imImage}, dst_image_list::Ptr{Ptr{imImage}})
  ccall( (:imProcessSplitComponents, libim_process_), Cvoid, (Ptr{imImage}, Ptr{Ptr{imImage}}), src_image, dst_image_list)
end

function imProcessMergeComponents(src_image_list::Ptr{Ptr{imImage}}, dst_image::Ptr{imImage})
  ccall( (:imProcessMergeComponents, libim_process_), Cvoid, (Ptr{Ptr{imImage}}, Ptr{imImage}), src_image_list, dst_image)
end

function imProcessNormalizeComponents(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessNormalizeComponents, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessReplaceColor(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, src_color::Ptr{Cfloat}, dst_color::Ptr{Cfloat})
  ccall( (:imProcessReplaceColor, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{Cfloat}, Ptr{Cfloat}), src_image, dst_image, src_color, dst_color)
end

function imProcessSetAlphaColor(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, src_color::Ptr{Cfloat}, dst_alpha::Cfloat)
  ccall( (:imProcessSetAlphaColor, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{Cfloat}, Cfloat), src_image, dst_image, src_color, dst_alpha)
end

function imProcessBitwiseOp(src_image1::Ptr{imImage}, src_image2::Ptr{imImage}, dst_image::Ptr{imImage}, op::Cint)
  ccall( (:imProcessBitwiseOp, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Cint), src_image1, src_image2, dst_image, op)
end

function imProcessBitwiseNot(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessBitwiseNot, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessBitMask(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, mask::Cuchar, op::Cint)
  ccall( (:imProcessBitMask, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cuchar, Cint), src_image, dst_image, mask, op)
end

function imProcessBitPlane(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, plane::Cint, do_reset::Cint)
  ccall( (:imProcessBitPlane, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, plane, do_reset)
end

function imProcessRenderOp(image::Ptr{imImage}, render_func::imRenderFunc, render_name::Ptr{UInt8}, params::Ptr{Cfloat}, plus::Cint)
  ccall( (:imProcessRenderOp, libim_process_), Cint, (Ptr{imImage}, imRenderFunc, Ptr{UInt8}, Ptr{Cfloat}, Cint), image, render_func, render_name, params, plus)
end

function imProcessRenderCondOp(image::Ptr{imImage}, render_cond_func::imRenderCondFunc, render_name::Ptr{UInt8}, params::Ptr{Cfloat})
  ccall( (:imProcessRenderCondOp, libim_process_), Cint, (Ptr{imImage}, imRenderCondFunc, Ptr{UInt8}, Ptr{Cfloat}), image, render_cond_func, render_name, params)
end

function imProcessRenderAddSpeckleNoise(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, percent::Cfloat)
  ccall( (:imProcessRenderAddSpeckleNoise, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cfloat), src_image, dst_image, percent)
end

function imProcessRenderAddGaussianNoise(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, mean::Cfloat, stddev::Cfloat)
  ccall( (:imProcessRenderAddGaussianNoise, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cfloat, Cfloat), src_image, dst_image, mean, stddev)
end

function imProcessRenderAddUniformNoise(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, mean::Cfloat, stddev::Cfloat)
  ccall( (:imProcessRenderAddUniformNoise, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cfloat, Cfloat), src_image, dst_image, mean, stddev)
end

function imProcessRenderRandomNoise(image::Ptr{imImage})
  ccall( (:imProcessRenderRandomNoise, libim_process_), Cint, (Ptr{imImage},), image)
end

function imProcessRenderConstant(image::Ptr{imImage}, value::Ptr{Cfloat})
  ccall( (:imProcessRenderConstant, libim_process_), Cint, (Ptr{imImage}, Ptr{Cfloat}), image, value)
end

function imProcessRenderWheel(image::Ptr{imImage}, internal_radius::Cint, external_radius::Cint)
  ccall( (:imProcessRenderWheel, libim_process_), Cint, (Ptr{imImage}, Cint, Cint), image, internal_radius, external_radius)
end

function imProcessRenderCone(image::Ptr{imImage}, radius::Cint)
  ccall( (:imProcessRenderCone, libim_process_), Cint, (Ptr{imImage}, Cint), image, radius)
end

function imProcessRenderTent(image::Ptr{imImage}, tent_width::Cint, tent_height::Cint)
  ccall( (:imProcessRenderTent, libim_process_), Cint, (Ptr{imImage}, Cint, Cint), image, tent_width, tent_height)
end

function imProcessRenderRamp(image::Ptr{imImage}, start::Cint, _end::Cint, vert_dir::Cint)
  ccall( (:imProcessRenderRamp, libim_process_), Cint, (Ptr{imImage}, Cint, Cint, Cint), image, start, _end, vert_dir)
end

function imProcessRenderBox(image::Ptr{imImage}, box_width::Cint, box_height::Cint)
  ccall( (:imProcessRenderBox, libim_process_), Cint, (Ptr{imImage}, Cint, Cint), image, box_width, box_height)
end

function imProcessRenderSinc(image::Ptr{imImage}, x_period::Cfloat, y_period::Cfloat)
  ccall( (:imProcessRenderSinc, libim_process_), Cint, (Ptr{imImage}, Cfloat, Cfloat), image, x_period, y_period)
end

function imProcessRenderGaussian(image::Ptr{imImage}, stddev::Cfloat)
  ccall( (:imProcessRenderGaussian, libim_process_), Cint, (Ptr{imImage}, Cfloat), image, stddev)
end

function imProcessRenderLapOfGaussian(image::Ptr{imImage}, stddev::Cfloat)
  ccall( (:imProcessRenderLapOfGaussian, libim_process_), Cint, (Ptr{imImage}, Cfloat), image, stddev)
end

function imProcessRenderCosine(image::Ptr{imImage}, x_period::Cfloat, y_period::Cfloat)
  ccall( (:imProcessRenderCosine, libim_process_), Cint, (Ptr{imImage}, Cfloat, Cfloat), image, x_period, y_period)
end

function imProcessRenderGrid(image::Ptr{imImage}, x_space::Cint, y_space::Cint)
  ccall( (:imProcessRenderGrid, libim_process_), Cint, (Ptr{imImage}, Cint, Cint), image, x_space, y_space)
end

function imProcessRenderChessboard(image::Ptr{imImage}, x_space::Cint, y_space::Cint)
  ccall( (:imProcessRenderChessboard, libim_process_), Cint, (Ptr{imImage}, Cint, Cint), image, x_space, y_space)
end

function imProcessToneGamut(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, op::Cint, params::Ptr{Cfloat})
  ccall( (:imProcessToneGamut, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint, Ptr{Cfloat}), src_image, dst_image, op, params)
end

function imProcessUnNormalize(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessUnNormalize, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessDirectConv(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessDirectConv, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessNegative(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessNegative, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessCalcAutoGamma(image::Ptr{imImage})
  ccall( (:imProcessCalcAutoGamma, libim_process_), Cfloat, (Ptr{imImage},), image)
end

function imProcessShiftHSI(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, h_shift::Cfloat, s_shift::Cfloat, i_shift::Cfloat)
  ccall( (:imProcessShiftHSI, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cfloat, Cfloat, Cfloat), src_image, dst_image, h_shift, s_shift, i_shift)
end

function imProcessThreshold(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, level::Cfloat, value::Cint)
  ccall( (:imProcessThreshold, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cfloat, Cint), src_image, dst_image, level, value)
end

function imProcessThresholdByDiff(src_image1::Ptr{imImage}, src_image2::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessThresholdByDiff, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image1, src_image2, dst_image)
end

function imProcessHysteresisThreshold(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, low_thres::Cint, high_thres::Cint)
  ccall( (:imProcessHysteresisThreshold, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, low_thres, high_thres)
end

function imProcessHysteresisThresEstimate(image::Ptr{imImage}, low_level::Ptr{Cint}, high_level::Ptr{Cint})
  ccall( (:imProcessHysteresisThresEstimate, libim_process_), Cvoid, (Ptr{imImage}, Ptr{Cint}, Ptr{Cint}), image, low_level, high_level)
end

function imProcessUniformErrThreshold(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessUniformErrThreshold, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessDifusionErrThreshold(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, level::Cint)
  ccall( (:imProcessDifusionErrThreshold, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, level)
end

function imProcessPercentThreshold(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, percent::Cfloat)
  ccall( (:imProcessPercentThreshold, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cfloat), src_image, dst_image, percent)
end

function imProcessOtsuThreshold(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessOtsuThreshold, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessMinMaxThreshold(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessMinMaxThreshold, libim_process_), Cfloat, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessLocalMaxThresEstimate(image::Ptr{imImage}, level::Ptr{Cint})
  ccall( (:imProcessLocalMaxThresEstimate, libim_process_), Cvoid, (Ptr{imImage}, Ptr{Cint}), image, level)
end

function imProcessSliceThreshold(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, start_level::Cfloat, end_level::Cfloat)
  ccall( (:imProcessSliceThreshold, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cfloat, Cfloat), src_image, dst_image, start_level, end_level)
end

function imProcessPixelate(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, box_size::Cint)
  ccall( (:imProcessPixelate, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, box_size)
end

function imProcessPosterize(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, level::Cint)
  ccall( (:imProcessPosterize, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, level)
end

function imProcessNormDiffRatio(image1::Ptr{imImage}, image2::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessNormDiffRatio, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), image1, image2, dst_image)
end

function imProcessAbnormalHyperionCorrection(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, threshold_consecutive::Cint, threshold_percent::Cint, image_abnormal::Ptr{imImage})
  ccall( (:imProcessAbnormalHyperionCorrection, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint, Cint, Ptr{imImage}), src_image, dst_image, threshold_consecutive, threshold_percent, image_abnormal)
end

function imProcessConvertDataType(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, cpx2real::Cint, gamma::Cfloat, abssolute::Cint, cast_mode::Cint)
  ccall( (:imProcessConvertDataType, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint, Cfloat, Cint, Cint), src_image, dst_image, cpx2real, gamma, abssolute, cast_mode)
end

function imProcessConvertColorSpace(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessConvertColorSpace, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessConvertToBitmap(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, cpx2real::Cint, gamma::Cfloat, abssolute::Cint, cast_mode::Cint)
  ccall( (:imProcessConvertToBitmap, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint, Cfloat, Cint, Cint), src_image, dst_image, cpx2real, gamma, abssolute, cast_mode)
end

function imProcessReduce(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, order::Cint)
  ccall( (:imProcessReduce, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, order)
end

function imProcessResize(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, order::Cint)
  ccall( (:imProcessResize, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, order)
end

function imProcessReduceBy4(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessReduceBy4, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessCrop(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, xmin::Cint, ymin::Cint)
  ccall( (:imProcessCrop, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, xmin, ymin)
end

function imProcessInsert(src_image::Ptr{imImage}, region_image::Ptr{imImage}, dst_image::Ptr{imImage}, xmin::Cint, ymin::Cint)
  ccall( (:imProcessInsert, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, region_image, dst_image, xmin, ymin)
end

function imProcessAddMargins(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, xmin::Cint, ymin::Cint)
  ccall( (:imProcessAddMargins, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, xmin, ymin)
end

function imProcessCalcRotateSize(width::Cint, height::Cint, new_width::Ptr{Cint}, new_height::Ptr{Cint}, cos0::Cdouble, sin0::Cdouble)
  ccall( (:imProcessCalcRotateSize, libim_process_), Cvoid, (Cint, Cint, Ptr{Cint}, Ptr{Cint}, Cdouble, Cdouble), width, height, new_width, new_height, cos0, sin0)
end

function imProcessRotate(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, cos0::Cdouble, sin0::Cdouble, order::Cint)
  ccall( (:imProcessRotate, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cdouble, Cdouble, Cint), src_image, dst_image, cos0, sin0, order)
end

function imProcessRotateRef(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, cos0::Cdouble, sin0::Cdouble, x::Cint, y::Cint, to_origin::Cint, order::Cint)
  ccall( (:imProcessRotateRef, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cdouble, Cdouble, Cint, Cint, Cint, Cint), src_image, dst_image, cos0, sin0, x, y, to_origin, order)
end

function imProcessRotate90(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, dir_clockwise::Cint)
  ccall( (:imProcessRotate90, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, dir_clockwise)
end

function imProcessRotate180(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessRotate180, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessMirror(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessMirror, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessFlip(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessFlip, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessRadial(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, k1::Cfloat, order::Cint)
  ccall( (:imProcessRadial, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cfloat, Cint), src_image, dst_image, k1, order)
end

function imProcessSwirl(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, k1::Cfloat, order::Cint)
  ccall( (:imProcessSwirl, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cfloat, Cint), src_image, dst_image, k1, order)
end

function imProcessInterlaceSplit(src_image::Ptr{imImage}, dst_image1::Ptr{imImage}, dst_image2::Ptr{imImage})
  ccall( (:imProcessInterlaceSplit, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image, dst_image1, dst_image2)
end

function imProcessGrayMorphConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel::Ptr{imImage}, ismax::Cint)
  ccall( (:imProcessGrayMorphConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel, ismax)
end

function imProcessGrayMorphErode(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessGrayMorphErode, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessGrayMorphDilate(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessGrayMorphDilate, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessGrayMorphOpen(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessGrayMorphOpen, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessGrayMorphClose(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessGrayMorphClose, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessGrayMorphTopHat(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessGrayMorphTopHat, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessGrayMorphWell(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessGrayMorphWell, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessGrayMorphGradient(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessGrayMorphGradient, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessBinMorphConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel::Ptr{imImage}, hit_white::Cint, iter::Cint)
  ccall( (:imProcessBinMorphConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, kernel, hit_white, iter)
end

function imProcessBinMorphErode(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint, iter::Cint)
  ccall( (:imProcessBinMorphErode, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, kernel_size, iter)
end

function imProcessBinMorphDilate(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint, iter::Cint)
  ccall( (:imProcessBinMorphDilate, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, kernel_size, iter)
end

function imProcessBinMorphOpen(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint, iter::Cint)
  ccall( (:imProcessBinMorphOpen, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, kernel_size, iter)
end

function imProcessBinMorphClose(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint, iter::Cint)
  ccall( (:imProcessBinMorphClose, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, kernel_size, iter)
end

function imProcessBinMorphOutline(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint, iter::Cint)
  ccall( (:imProcessBinMorphOutline, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, kernel_size, iter)
end

function imProcessBinMorphThin(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessBinMorphThin, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessMedianConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessMedianConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessRangeConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessRangeConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessRankClosestConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessRankClosestConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessRankMaxConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessRankMaxConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessRankMinConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessRankMinConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessRangeContrastThreshold(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint, min_range::Cint)
  ccall( (:imProcessRangeContrastThreshold, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, kernel_size, min_range)
end

function imProcessLocalMaxThreshold(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint, min_level::Cint)
  ccall( (:imProcessLocalMaxThreshold, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, kernel_size, min_level)
end

function imProcessConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel::Ptr{imImage})
  ccall( (:imProcessConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image, dst_image, kernel)
end

function imProcessConvolveSep(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel::Ptr{imImage})
  ccall( (:imProcessConvolveSep, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image, dst_image, kernel)
end

function imProcessConvolveDual(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel1::Ptr{imImage}, kernel2::Ptr{imImage})
  ccall( (:imProcessConvolveDual, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image, dst_image, kernel1, kernel2)
end

function imProcessConvolveRep(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel::Ptr{imImage}, count::Cint)
  ccall( (:imProcessConvolveRep, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel, count)
end

function imProcessCompassConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel::Ptr{imImage})
  ccall( (:imProcessCompassConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image, dst_image, kernel)
end

function imProcessRotateKernel(kernel::Ptr{imImage})
  ccall( (:imProcessRotateKernel, libim_process_), Cvoid, (Ptr{imImage},), kernel)
end

function imProcessDiffOfGaussianConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, stddev1::Cfloat, stddev2::Cfloat)
  ccall( (:imProcessDiffOfGaussianConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cfloat, Cfloat), src_image, dst_image, stddev1, stddev2)
end

function imProcessLapOfGaussianConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, stddev::Cfloat)
  ccall( (:imProcessLapOfGaussianConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cfloat), src_image, dst_image, stddev)
end

function imProcessMeanConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessMeanConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessGaussianConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, stddev::Cfloat)
  ccall( (:imProcessGaussianConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cfloat), src_image, dst_image, stddev)
end

function imProcessBarlettConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, kernel_size::Cint)
  ccall( (:imProcessBarlettConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, kernel_size)
end

function imProcessSobelConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessSobelConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessPrewittConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessPrewittConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessSplineEdgeConvolve(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessSplineEdgeConvolve, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessZeroCrossing(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessZeroCrossing, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessCanny(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, stddev::Cfloat)
  ccall( (:imProcessCanny, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cfloat), src_image, dst_image, stddev)
end

function imGaussianStdDev2KernelSize(stddev::Cfloat)
  ccall( (:imGaussianStdDev2KernelSize, libim_process_), Cint, (Cfloat,), stddev)
end

function imGaussianKernelSize2StdDev(kernel_size::Cint)
  ccall( (:imGaussianKernelSize2StdDev, libim_process_), Cfloat, (Cint,), kernel_size)
end

function imProcessUnsharp(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, stddev::Cfloat, amount::Cfloat, threshold::Cfloat)
  ccall( (:imProcessUnsharp, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cfloat, Cfloat, Cfloat), src_image, dst_image, stddev, amount, threshold)
end

function imProcessSharp(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, amount::Cfloat, threshold::Cfloat)
  ccall( (:imProcessSharp, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cfloat, Cfloat), src_image, dst_image, amount, threshold)
end

function imProcessSharpKernel(src_image::Ptr{imImage}, kernel::Ptr{imImage}, dst_image::Ptr{imImage}, amount::Cfloat, threshold::Cfloat)
  ccall( (:imProcessSharpKernel, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Cfloat, Cfloat), src_image, kernel, dst_image, amount, threshold)
end

function imProcessHoughLines(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessHoughLines, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessHoughLinesDraw(src_image::Ptr{imImage}, hough::Ptr{imImage}, hough_points::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessHoughLinesDraw, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image, hough, hough_points, dst_image)
end

function imProcessCrossCorrelation(src_image1::Ptr{imImage}, src_image2::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessCrossCorrelation, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Ptr{imImage}), src_image1, src_image2, dst_image)
end

function imProcessAutoCorrelation(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessAutoCorrelation, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessDistanceTransform(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessDistanceTransform, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessRegionalMaximum(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessRegionalMaximum, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessFFT(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessFFT, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessIFFT(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessIFFT, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessFFTraw(image::Ptr{imImage}, inverse::Cint, center::Cint, normalize::Cint)
  ccall( (:imProcessFFTraw, libim_process_), Cvoid, (Ptr{imImage}, Cint, Cint, Cint), image, inverse, center, normalize)
end

function imProcessSwapQuadrants(image::Ptr{imImage}, center2origin::Cint)
  ccall( (:imProcessSwapQuadrants, libim_process_), Cvoid, (Ptr{imImage}, Cint), image, center2origin)
end

function imProcessOpenMPSetMinCount(min_count::Cint)
  ccall( (:imProcessOpenMPSetMinCount, libim_process_), Cint, (Cint,), min_count)
end

function imProcessOpenMPSetNumThreads(count::Cint)
  ccall( (:imProcessOpenMPSetNumThreads, libim_process_), Cint, (Cint,), count)
end

function imCalcRMSError(image1::Ptr{imImage}, image2::Ptr{imImage})
  ccall( (:imCalcRMSError, libim_process_), Cfloat, (Ptr{imImage}, Ptr{imImage}), image1, image2)
end

function imCalcSNR(src_image::Ptr{imImage}, noise_image::Ptr{imImage})
  ccall( (:imCalcSNR, libim_process_), Cfloat, (Ptr{imImage}, Ptr{imImage}), src_image, noise_image)
end

function imCalcCountColors(image::Ptr{imImage})
  ccall( (:imCalcCountColors, libim_process_), Culong, (Ptr{imImage},), image)
end

function imCalcGrayHistogram(image::Ptr{imImage}, histo::Ptr{Culong}, cumulative::Cint)
  ccall( (:imCalcGrayHistogram, libim_process_), Cvoid, (Ptr{imImage}, Ptr{Culong}, Cint), image, histo, cumulative)
end

function imCalcHistogram(image::Ptr{imImage}, histo::Ptr{Culong}, plane::Cint, cumulative::Cint)
  ccall( (:imCalcHistogram, libim_process_), Cvoid, (Ptr{imImage}, Ptr{Culong}, Cint, Cint), image, histo, plane, cumulative)
end

function imCalcByteHistogram(data::Ptr{Cuchar}, count::Cint, histo::Ptr{Culong}, cumulative::Cint)
  ccall( (:imCalcByteHistogram, libim_process_), Cvoid, (Ptr{Cuchar}, Cint, Ptr{Culong}, Cint), data, count, histo, cumulative)
end

function imCalcUShortHistogram(data::Ptr{UInt16}, count::Cint, histo::Ptr{Culong}, cumulative::Cint)
  ccall( (:imCalcUShortHistogram, libim_process_), Cvoid, (Ptr{UInt16}, Cint, Ptr{Culong}, Cint), data, count, histo, cumulative)
end

function imCalcShortHistogram(data::Ptr{Int16}, count::Cint, histo::Ptr{Culong}, cumulative::Cint)
  ccall( (:imCalcShortHistogram, libim_process_), Cvoid, (Ptr{Int16}, Cint, Ptr{Culong}, Cint), data, count, histo, cumulative)
end

function imHistogramNew(data_type::Cint, hcount::Ptr{Cint})
  ccall( (:imHistogramNew, libim_process_), Ptr{Culong}, (Cint, Ptr{Cint}), data_type, hcount)
end

function imHistogramRelease(histo::Ptr{Culong})
  ccall( (:imHistogramRelease, libim_process_), Cvoid, (Ptr{Culong},), histo)
end

function imHistogramShift(data_type::Cint)
  ccall( (:imHistogramShift, libim_process_), Cint, (Cint,), data_type)
end

function imHistogramCount(data_type::Cint)
  ccall( (:imHistogramCount, libim_process_), Cint, (Cint,), data_type)
end

function imCalcImageStatistics(image::Ptr{imImage}, stats::Ptr{imStats})
  ccall( (:imCalcImageStatistics, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imStats}), image, stats)
end

function imCalcHistogramStatistics(image::Ptr{imImage}, stats::Ptr{imStats})
  ccall( (:imCalcHistogramStatistics, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imStats}), image, stats)
end

function imCalcHistoImageStatistics(image::Ptr{imImage}, median::Ptr{Cint}, mode::Ptr{Cint})
  ccall( (:imCalcHistoImageStatistics, libim_process_), Cvoid, (Ptr{imImage}, Ptr{Cint}, Ptr{Cint}), image, median, mode)
end

function imCalcPercentMinMax(image::Ptr{imImage}, percent::Cfloat, ignore_zero::Cint, min::Ptr{Cint}, max::Ptr{Cint})
  ccall( (:imCalcPercentMinMax, libim_process_), Cvoid, (Ptr{imImage}, Cfloat, Cint, Ptr{Cint}, Ptr{Cint}), image, percent, ignore_zero, min, max)
end

function imAnalyzeFindRegions(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, connect::Cint, touch_border::Cint)
  ccall( (:imAnalyzeFindRegions, libim_process_), Cint, (Ptr{imImage}, Ptr{imImage}, Cint, Cint), src_image, dst_image, connect, touch_border)
end

function imAnalyzeMeasureArea(image::Ptr{imImage}, area::Ptr{Cint}, region_count::Cint)
  ccall( (:imAnalyzeMeasureArea, libim_process_), Cvoid, (Ptr{imImage}, Ptr{Cint}, Cint), image, area, region_count)
end

function imAnalyzeMeasurePerimArea(image::Ptr{imImage}, perimarea::Ptr{Cfloat})
  ccall( (:imAnalyzeMeasurePerimArea, libim_process_), Cvoid, (Ptr{imImage}, Ptr{Cfloat}), image, perimarea)
end

function imAnalyzeMeasureCentroid(image::Ptr{imImage}, area::Ptr{Cint}, region_count::Cint, cx::Ptr{Cfloat}, cy::Ptr{Cfloat})
  ccall( (:imAnalyzeMeasureCentroid, libim_process_), Cvoid, (Ptr{imImage}, Ptr{Cint}, Cint, Ptr{Cfloat}, Ptr{Cfloat}), image, area, region_count, cx, cy)
end

function imAnalyzeMeasurePrincipalAxis(image::Ptr{imImage}, area::Ptr{Cint}, cx::Ptr{Cfloat}, cy::Ptr{Cfloat}, region_count::Cint, major_slope::Ptr{Cfloat}, major_length::Ptr{Cfloat}, minor_slope::Ptr{Cfloat}, minor_length::Ptr{Cfloat})
  ccall( (:imAnalyzeMeasurePrincipalAxis, libim_process_), Cvoid, (Ptr{imImage}, Ptr{Cint}, Ptr{Cfloat}, Ptr{Cfloat}, Cint, Ptr{Cfloat}, Ptr{Cfloat}, Ptr{Cfloat}, Ptr{Cfloat}), image, area, cx, cy, region_count, major_slope, major_length, minor_slope, minor_length)
end

function imAnalyzeMeasureHoles(image::Ptr{imImage}, connect::Cint, holes_count::Ptr{Cint}, area::Ptr{Cint}, perim::Ptr{Cfloat})
  ccall( (:imAnalyzeMeasureHoles, libim_process_), Cvoid, (Ptr{imImage}, Cint, Ptr{Cint}, Ptr{Cint}, Ptr{Cfloat}), image, connect, holes_count, area, perim)
end

function imAnalyzeMeasurePerimeter(image::Ptr{imImage}, perim::Ptr{Cfloat}, region_count::Cint)
  ccall( (:imAnalyzeMeasurePerimeter, libim_process_), Cvoid, (Ptr{imImage}, Ptr{Cfloat}, Cint), image, perim, region_count)
end

function imProcessPerimeterLine(src_image::Ptr{imImage}, dst_image::Ptr{imImage})
  ccall( (:imProcessPerimeterLine, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}), src_image, dst_image)
end

function imProcessRemoveByArea(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, connect::Cint, start_size::Cint, end_size::Cint, inside::Cint)
  ccall( (:imProcessRemoveByArea, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint, Cint, Cint, Cint), src_image, dst_image, connect, start_size, end_size, inside)
end

function imProcessFillHoles(src_image::Ptr{imImage}, dst_image::Ptr{imImage}, connect::Cint)
  ccall( (:imProcessFillHoles, libim_process_), Cvoid, (Ptr{imImage}, Ptr{imImage}, Cint), src_image, dst_image, connect)
end


text:
# UnitCommitment.jl: Optimization Package for Security-Constrained Unit Commitment
# Copyright (C) 2020, UChicago Argonne, LLC. All rights reserved.
# Released under the modified BSD license. See COPYING.md for more details.

using UnitCommitment, LinearAlgebra, Cbc, JuMP, JSON, GZip

@testset "Instance" begin
    @testset "read" begin
        instance = UnitCommitment.read_benchmark("test/case14")

        @test length(instance.lines) == 20
        @test length(instance.buses) == 14
        @test length(instance.units) == 6
        @test length(instance.contingencies) == 19
        @test length(instance.price_sensitive_loads) == 1
        @test instance.time == 4

        @test instance.lines[5].name                 == "l5"
        @test instance.lines[5].source.name          == "b2"
        @test instance.lines[5].target.name          == "b5"
        @test instance.lines[5].reactance            ≈  0.17388
        @test instance.lines[5].susceptance          ≈  10.037550333
        @test instance.lines[5].normal_flow_limit    == [1e8 for t in 1:4]
        @test instance.lines[5].emergency_flow_limit == [1e8 for t in 1:4]
        @test instance.lines[5].flow_limit_penalty   == [5e3 for t in 1:4]

        @test instance.lines[1].name                 == "l1"
        @test instance.lines[1].source.name          == "b1"
        @test instance.lines[1].target.name          == "b2"
        @test instance.lines[1].reactance            ≈  0.059170
        @test instance.lines[1].susceptance          ≈  29.496860773945
        @test instance.lines[1].normal_flow_limit    == [300.0 for t in 1:4]
        @test instance.lines[1].emergency_flow_limit == [400.0 for t in 1:4]
        @test instance.lines[1].flow_limit_penalty   == [1e3   for t in 1:4]

        @test instance.buses[9].name == "b9"
        @test instance.buses[9].load == [35.36638, 33.25495, 31.67138, 31.14353]

        unit = instance.units[1]
        @test unit.name                          == "g1"
        @test unit.bus.name                      == "b1"
        @test unit.ramp_up_limit                 == 1e6
        @test unit.ramp_down_limit               == 1e6
        @test unit.startup_limit                 == 1e6
        @test unit.shutdown_limit                == 1e6
        @test unit.must_run                      == [false for t in 1:4]
        @test unit.min_power_cost                == [1400. for t in 1:4]
        @test unit.min_uptime                    == 1
        @test unit.min_downtime                  == 1
        @test unit.provides_spinning_reserves    == [true for t in 1:4]
        for t in 1:1
            @test unit.cost_segments[1].mw[t]    == 10.0
            @test unit.cost_segments[2].mw[t]    == 20.0
            @test unit.cost_segments[3].mw[t]    == 5.0
            @test unit.cost_segments[1].cost[t] ≈  20.0
            @test unit.cost_segments[2].cost[t] ≈  30.0
            @test unit.cost_segments[3].cost[t] ≈  40.0
        end
        @test length(unit.startup_categories) == 3
        @test unit.startup_categories[1].delay == 1
        @test unit.startup_categories[2].delay == 2
        @test unit.startup_categories[3].delay == 3
        @test unit.startup_categories[1].cost == 1000.0
        @test unit.startup_categories[2].cost == 1500.0
        @test unit.startup_categories[3].cost == 2000.0

        unit = instance.units[2]
        @test unit.name     == "g2"
        @test unit.must_run == [false for t in 1:4]

        unit = instance.units[3]
        @test unit.name                          == "g3"
        @test unit.bus.name                      == "b3"
        @test unit.ramp_up_limit                 == 70.0
        @test unit.ramp_down_limit               == 70.0
        @test unit.startup_limit                 == 70.0
        @test unit.shutdown_limit                == 70.0
        @test unit.must_run                      == [true for t in 1:4]
        @test unit.min_power_cost                == [0. for t in 1:4]
        @test unit.min_uptime                    == 1
        @test unit.min_downtime                  == 1
        @test unit.provides_spinning_reserves    == [true for t in 1:4]
        for t in 1:4
            @test unit.cost_segments[1].mw[t]    ≈ 33
            @test unit.cost_segments[2].mw[t]    ≈ 33
            @test unit.cost_segments[3].mw[t]    ≈ 34
            @test unit.cost_segments[1].cost[t] ≈ 33.75
            @test unit.cost_segments[2].cost[t] ≈ 38.04
            @test unit.cost_segments[3].cost[t] ≈ 44.77853
        end

        @test instance.reserves.spinning == zeros(4)

        @test instance.contingencies[1].lines == [instance.lines[1]]
        @test instance.contingencies[1].units == []

        load = instance.price_sensitive_loads[1]
        @test load.name     == "ps1"
        @test load.bus.name == "b3"
        @test load.revenue  == [100. for t in 1:4]
        @test load.demand   == [50.  for t in 1:4]
    end

    @testset "slice" begin
        instance = UnitCommitment.read_benchmark("test/case14")
        modified = UnitCommitment.slice(instance, 1:2)

        # Should update all time-dependent fields
        @test modified.time == 2
        @test length(modified.power_balance_penalty) == 2
        @test length(modified.reserves.spinning) == 2
        for u in modified.units
            @test length(u.max_power) == 2
            @test length(u.min_power) == 2
            @test length(u.must_run) == 2
            @test length(u.min_power_cost) == 2
            @test length(u.provides_spinning_reserves) == 2
            for s in u.cost_segments
                @test length(s.mw) == 2
                @test length(s.cost) == 2
            end
        end
        for b in modified.buses
            @test length(b.load) == 2
        end
        for l in modified.lines
            @test length(l.normal_flow_limit) == 2
            @test length(l.emergency_flow_limit) == 2
            @test length(l.flow_limit_penalty) == 2
        end
        for ps in modified.price_sensitive_loads
            @test length(ps.demand) == 2
            @test length(ps.revenue) == 2
        end

        # Should be able to build model without errors
        optimizer = optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0)
        model = build_model(instance=modified,
                            optimizer=optimizer,
                            variable_names=true)
    end
end

ext: jl


text:
module TLRunner

include("../core/PTChain.jl")

function score_vec(vec)
    score = 0
    for i = 1:length(vec)
        if vec[i] == 0
            score += 2
        elseif vec[i] == -1
            score += 1
        elseif vec[i] == 1
            score += 0
        elseif abs(vec[i]) <= 4
            score += 2*abs(vec[i]) - 1
        elseif abs(vec[i]) <= 6
            score += 15 - 2*abs(vec[i])
        else
            score += abs(vec[i]) - 4
        end
    end
    score
end

function random_walk(x::Vector)
    n = length(x)
    direction = rand(1:n)
    y = copy(x)
    y[direction] = y[direction] + rand(-1:2:1)
    return y
end

Base.@ccallable function julia_main(ARGS::Vector{String})::Cint
	dims = 20
    start_x = rand(-20:20, dims)
    temps = [0, 1, 4, 7, 10, 15, 20]
    min_val, min_x, plot_vals = PTChain.greedyTempering(start_x, score_vec, temps, random_walk, 500, 500)
    println(min_val)
    return 0
end

end

max_stars_repo_name: jacob-ruth/pt-optimization

max_issues_repo_name: jacob-ruth/pt-optimization

max_forks_repo_name: jacob-ruth/pt-optimization


text:
# This file is inspired from Polyhedra.jl

const ABSZTOL(N::Type{<:AbstractFloat}) = N(10) * sqrt(eps(N))
const ABSZTOL(N::Type{Rational{INNER}}) where {INNER} = zero(N)

"""
    _leq(x::N, y::N; [kwargs...]) where {N<:Real}

Determine if `x` is smaller than or equal to `y`.

### Input

- `x`      -- number
- `y`      -- another number (of the same numeric type as `x`)
- `kwargs` -- not used

### Output

A boolean that is `true` iff `x <= y`.

### Algorithm

This is a fallback implementation for numbers of type `Real`. If the arguments
are floating point numbers, see `_leq(x::AbstractFloat, y::AbstractFloat)`.
"""
_leq(x::N, y::N; kwargs...) where {N<:Real} = x <= y

"""
    _leq(x::N, y::M; [kwargs...]) where {N<:Real, M<:Real}

Determine if `x` is smaller than or equal to `y`.

### Input

- `x`      -- number
- `y`      -- another number (of possibly different numeric type than `x`)
- `kwargs` -- optional arguments; see `?_leq` for the available options

### Output

A boolean that is `true` iff `x <= y`.

### Algorithm

This implementation calls Julia's `promote(x, y)` function, which converts all
arguments to a common numeric type, returning them as a tuple. The conversion
is such that the common type to which the values are converted can represent
them as faithfully as possible.
"""
_leq(x::N, y::M; kwargs...) where {N<:Real, M<:Real} =
    _leq(promote(x, y)...; kwargs...)

"""
    _geq(x::Real, y::Real; [kwargs...])

Determine if `x` is greater than or equal to `y`.

### Input

- `x` -- number
- `y` -- another number (of possibly different numeric type than `x`)

### Output

A boolean that is `true` iff `x >= y`.

### Algorithm

This function falls back to `_leq(y, x)`, with type promotion if needed. See the
documentation of `_leq` for further details.
"""
_geq(x::Real, y::Real; kwargs...) = _leq(y, x; kwargs...)

"""
    isapproxzero(x::N; ztol::Real=ABSZTOL(N)) where {N<:Real}

Determine if `x` is approximately zero.

### Input

- `x`    -- number
- `ztol` -- (optional, default: `ABSZTOL`) tolerance against zero

### Output

A boolean that is `true` iff `x ≈ 0`.

### Algorithm

It is considered that `x ≈ 0` whenever `x` (in absolute value) is smaller than
the tolerance for zero, `ztol`.
"""
function isapproxzero(x::N; ztol::Real=ABSZTOL(N)) where {N<:Real}
    return abs(x) <= ztol
end

"""
    _isapprox(x::N, y::N;
              rtol::Real=Base.rtoldefault(N),
              ztol::Real=ABSZTOL(N),
              atol::Real=zero(N)) where {N<:Real}

Determine if `x` is approximately equal to `y`.

### Input

- `x`    -- number
- `y`    -- another number (of the same numeric type as `x`)
- `rtol` -- (optional, default: `Base.rtoldefault(N)`) relative tolerance
- `ztol` -- (optional, default: `ABSZTOL(N)`) absolute tolerance for comparison
            against zero
- `atol` -- (optional, default: `zero(N)`) absolute tolerance

### Output

A boolean that is `true` iff `x ≈ y`.

### Algorithm

We first check if `x` and `y` are both approximately zero, using
`isapproxzero(x, y)`.
If that fails, we check if `x ≈ y`, using Julia's `isapprox(x, y)`.
In the latter check we use `atol` absolute tolerance and `rtol` relative
tolerance.

Comparing to zero with default tolerances is a special case in Julia's
`isapprox`, see the last paragraph in `?isapprox`. This function tries to
combine `isapprox` with its default values and a branch for `x ≈ y ≈ 0` which
includes `x == y == 0` but also admits a tolerance `ztol`.

Note that if `x = ztol` and `y = -ztol`, then `|x-y| = 2*ztol` and still
`_isapprox` returns `true`.
"""
function _isapprox(x::N, y::N;
                   rtol::Real=Base.rtoldefault(N),
                   ztol::Real=ABSZTOL(N),
                   atol::Real=zero(N)) where {N<:Real}
    if isapproxzero(x, ztol=ztol) && isapproxzero(y, ztol=ztol)
        return true
    else
        return isapprox(x, y, rtol=rtol, atol=atol)
    end
end

"""
    _leq(x::N, y::N;
         rtol::Real=Base.rtoldefault(N),
         ztol::Real=ABSZTOL(N),
         atol::Real=zero(N)) where {N<:AbstractFloat}

Determine if `x` is smaller than or equal to `y`.

### Input

- `x`    -- number
- `y`    -- another number (of the same numeric type as `x`)
- `rtol` -- (optional, default: `Base.rtoldefault(N)`) relative tolerance
- `ztol` -- (optional, default: `ABSZTOL(N)`) absolute tolerance for comparison
            against zero
- `atol` -- absolute tolerance

### Output

A boolean that is `true` iff `x <= y`.

### Algorithm

The `x <= y` comparison is split into `x < y` or `x ≈ y`; the latter is
implemented by extending Juila's built-in `isapprox(x, y)` with an absolute
tolerance that is used to compare against zero.
"""
function _leq(x::N, y::N;
              rtol::Real=Base.rtoldefault(N),
              ztol::Real=ABSZTOL(N),
              atol::Real=zero(N)) where {N<:AbstractFloat}
    return x <= y || _isapprox(x, y, rtol=rtol, ztol=ztol, atol=atol)
end


text:
### Middleware layers

"""
This sets `Access-Control-Allow-Origin` to the requester's origin.  In
production you would want to check the origin against a whitelist and throw an
error otherwise.
"""
function add_cors!(req::HTTP.Request)
    orig = HTTP.Messages.header(req, "Origin")
    push!(req.response.headers, Pair("Access-Control-Allow-Origin", orig))
    push!(req.response.headers, Pair("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE,PATCH,OPTIONS"))
    push!(req.response.headers, Pair("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"))
    return req
end

"""
Sets `Content-Type` for JSON responses.
"""
function content_type!(req::HTTP.Request)
    push!(req.response.headers,
        Pair("Content-Type", "application/json; charset=utf-8"))
    return req
end

"""
Log a line whenever you get a request.  HTTP.jl already does this.
"""
function hit_logger!(req::HTTP.Request)
    println(req.method, " request to: ", req.target,
        " at ", now())
    return req
end

"""
Log the request body.  Use with care, as the request body could be very large.
"""
function body_logger!(req::HTTP.Request)
    println(String(copy(req.body)))
    return req
end

"""
Attempt to parse the body of the request as a JSON and throw an error if it's not a JSON.  The resulting dict is discarded and endpoints need to do this again since we currently don't have a way to store things like this in the request.  In performance critical applications this should not be used.
"""
function require_json_body!(req::HTTP.Request)
    j = try
        body_as_dict(req)
    catch err
        error("POST requests to this server must contain a JSON-encoded body.")
    end
end

# Some default middleware
default_middleware = [hit_logger!, body_logger!, add_cors!, content_type!]


text:
module DungBase

using Dates, UUIDs, StaticArrays
import IntervalSets: width, (..), AbstractInterval, leftendpoint

export VideoFile, WholeVideo, FragmentedVideo, DisjointVideo, AbstractTimeLine, AbstractPeriod, Instantaneous, Prolonged, Temporal, Board, Calibration, POI, Metadata, Run, Experiment

export start, duration, stop, files, filenames

stop(x) = start(x) + duration(x)

include("videos.jl")

include("temporals.jl")

include("calibrations.jl")

include("pois.jl")

# include(joinpath(@__DIR__, "experimental_setup.jl"))

struct Metadata
    setup::Dict{Symbol, Any}
    comment::String
    date::DateTime
end

# Base.getproperty(x::Metadata, level::Symbol) = get(x.setup, level, missing)
#=getcoord(x::Run, poi::Symbol) = get(x.pois, poi, missing)
_getlevel(x::Metadata, level::Symbol) = get(x, level, missing)
getlevel(x::Run, level::Symbol) = _getlevel(x.metadata, level)=#

struct Run{T, M}
    data::T # pois::Dict{Symbol, T} or Track
    metadata::M
end

#=struct Run
    setup::Dict{Symbol, Any}
    pois::Dict{Symbol, POI}
    comment::String
    date::DateTime
end=#

struct Experiment
    runs::Vector{Run}
    description::String
end

end # module


text:
function main(ngrid, ntimesteps, kappa=1.0, xleft=0.0, xright=1.0, tleft=-1.0, tright=1.0)
  const dx = (xright-xleft)/(ngrid-1)
  const dt = 0.25dx * dx / kappa

  temp = Array{Float64}(ngrid+2)
  temp_new = Array{Float64}(ngrid+2)

  for i in 2:ngrid+1
    @inbounds temp[i] = 0.
  end

  temp[1] = tleft
  temp[ngrid+2] = tright

  for iteration in 1:ntimesteps
    for i in 2:ngrid+1
        @inbounds temp_new[i] = temp[i] + kappa*dt/(dx*dx)*(temp[i-1] - 2*temp[i] + temp[i+1])
    end
    for i in 2:ngrid+1
        @inbounds temp[i] = temp_new[i]
    end
  end

  println(temp[div(ngrid,2)+2])
end

ngrid = 1001
ntimesteps = 10000
nargs = length(ARGS)
if nargs > 0
    ngrid = parse(Int32, ARGS[1])
end
if nargs > 1
    ntimesteps = parse(Int32, ARGS[2])
end
main(10, 10)
@time main(ngrid, ntimesteps)


text:
struct RstStreamFrame
    stream_identifier::UInt32
    error_code::UInt32
end

==(a::RstStreamFrame, b::RstStreamFrame) =
    a.stream_identifier == b.stream_identifier &&
    a.error_code == b.error_code

function decode_rst_stream(header, payload)
    error_code = (UInt32(payload[1]) << 24 + UInt32(payload[2]) << 16 +
                  UInt32(payload[3]) << 8 + UInt32(payload[4]))

    return RstStreamFrame(header.stream_identifier, error_code)
end

function encode_rst_stream(frame)
    payload::Array{UInt8, 1} = [ UInt8(frame.error_code >> 24);
                                 UInt8(frame.error_code >> 16 & 0x000000ff);
                                 UInt8(frame.error_code >> 8 & 0x000000ff);
                                 UInt8(frame.error_code & 0x000000ff) ]

    return wrap_payload(payload, RST_STREAM, 0x0, frame.stream_identifier)
end


text:
# Embed functions on different data types
include("customembed_arrays.jl")
include("customembed_Dataset.jl")
include("customembed_sarrays.jl")

export cembed


text:
using Test
using DataStructures
using Logging

# LEARNINGS:
# - can use macros like @debug or @info to log with global logger
# - @debug isn't visible by default, have to tweak log levels
# - to use my own logger (e.g. writing to a file) I have to import Logging and init a SimpleLogger
#   ... this logger can also override the global logger

io = open("22.log", "w+")
logger = SimpleLogger(io)
global_logger(logger)

global total_games = 1
function recursive_combat(decks, isNewGame=false)
    game = 1
    if ! isNewGame
        global total_games += 1
        game = total_games
    end

    @info("\n=== Game $(game) ===")

    round = 0
    previous_rounds = Dict()
    while length(decks[1]) > 0 && length(decks[2]) > 0
        round += 1
        @info("\n-- Round $(round) (Game $(game)) --")
        for i in 1:2
            @info("Player $(i)'s deck: $(collect(decks[i]))")
        end

        p1_cards = join(collect(decks[1]), ",")
        p2_cards = join(collect(decks[2]), ",")
        key = (p1_cards, p2_cards)
        if in(key, keys(previous_rounds))
            @info("... the game instantly ends in a win for player 1")
            return 1, 2, decks
        end
        previous_rounds[key] = true

        # draw top card from each
        cards = Dict()
        for i in 1:2
            cards[i] = dequeue!(decks[i])
            @info("Player $(i) plays: $(cards[i])")
        end

        # If both players have at least as many cards remaining in their deck
        # as the value of the card they just drew, the winner of the round is
        # determined by playing a new game of Recursive Combat (see below).
        winner, loser = Nothing, Nothing
        if length(decks[1]) >= cards[1] && length(decks[2]) >= cards[2]
            new_decks = Dict()
            for p in 1:2
                # create a new deck of the correct length
                q = Queue{Int}()
                for card in collect(decks[p])[1:cards[p]]
                    enqueue!(q, card)
                end
                new_decks[p] = q
            end

            @info("Playing a sub-game to determine the winner...")
            winner, loser, _ = recursive_combat(new_decks)

            @info("\n...anyway, back to game $(game)")
        else
            # Otherwise, at least one player must not have enough cards left in
            # their deck to recurse; the winner of the round is the player with
            # the higher-value card.
            winner, loser = 2, 1
            if cards[1] > cards[2]
                winner, loser = 1, 2
            end
        end

        @info("Player $(winner) wins round $(round) of game $(game)!")

        # The winner keeps both cards, placing them on the bottom of their own deck
        # so that the winner's card is above the other card.
        enqueue!(decks[winner], cards[winner])
        enqueue!(decks[winner], cards[loser])
    end

    if game == 1
        @info ("== Post-game results ==")
        for i in 1:2
            @info("Player $(i)'s deck: $(collect(decks[i]))")
        end
    end

    if length(decks[1]) == 0
        # player 2 wins
        return 2, 1, decks
    else
        # player 1 wins
        return 1, 2, decks
    end
end

function combat(decks)
    round = 0
    while length(decks[1]) > 0 && length(decks[2]) > 0
        round += 1
        println("-- Round $(round) --")
        for i in 1:2
            println("Player $(i)'s deck: $(decks[i])")
        end

        # draw top card from each
        cards = Dict()
        for i in 1:2
            cards[i] = dequeue!(decks[i])
            println("Player $(i) players: $(cards[i])")
        end

        winner, loser = 2, 1
        if cards[1] > cards[2]
            winner, loser = 1, 2
        end

        println("Player $(winner) wins the round!")

        # The winner keeps both cards, placing them on the bottom of their own deck
        # so that the winner's card is above the other card.
        enqueue!(decks[winner], cards[winner])
        enqueue!(decks[winner], cards[loser])
    end

    println("== Post-game results ==")
    for i in 1:2
        println("Player $(i)'s deck: $(decks[i])")
    end

    if length(decks[1]) == 0
        return decks[2]
    else
        return decks[1]
    end
end

function run(fname, version=1)
    println("\n[Part $(version)] Running $(fname)...")
    f = open(fname, "r")
    lines = readlines(f)
    close(f)

    # initialize decks
    decks = Dict()
    decks[1] = Queue{Int}()
    decks[2] = Queue{Int}()

    # parse input
    current_player = 1
    for l in lines
        if l == "Player 1:"
            current_player = 1
        elseif l == "Player 2:"
            current_player = 2
        elseif l != ""
            num = parse(Int, l)
            enqueue!(decks[current_player], num)
        end
    end

    winning_deck = Nothing
    if version == 1
        winning_deck = combat(decks)
    else
        winner, loser, decks = recursive_combat(decks, true)
        winning_deck = decks[winner]
    end

    # compute score
    result = 0
    for (idx, val) in enumerate(reverse(collect(winning_deck)))
        result += (idx * val)
    end

    println("[Part $(version)] Running $(fname) got result = $(result)")
    return result
end

# @test run("22ex.txt") == 306
# run("22.txt")

@test run("22ex.txt", 2) == 291
# run("22ex.part2.txt", 2)
# @test run("22ex.part2.txt", 2) == 105 # should exit early... i think this is right result?
run("22.txt", 2)


text:
using DocStringExtensions
using KernelAbstractions
using CLIMA.Mesh.Geometry

import CLIMA.Mesh.Grids:
    _ξ1x1, _ξ2x1, _ξ3x1, _ξ1x2, _ξ2x2, _ξ3x2, _ξ1x3, _ξ2x3, _ξ3x3

using CLIMA.VariableTemplates
import CLIMA.VariableTemplates.varsindex

"""
    VecGrad{FT <: AbstractFloat,
         FTA2D <: AbstractArray{FT, 2},
         FTA3D <: AbstractArray{FT, 3},}

This data structure stores the spatial gradients of a velocity field.

# Fields

$(DocStringExtensions.FIELDS)

# Usage

    VecGrad(Npl, Nel, ::Type{FT}) where {FT <: AbstractFloat}

# Arguments for the inner constructor
 - `Npl`: Number of local degrees of freedom in a spectral element
 - `Nel`: Number of spectral elements
 - `FT`: Floating point precision
"""
struct VecGrad{
    FT <: AbstractFloat,
    FTA2D <: AbstractArray{FT, 2},
    FTA3D <: AbstractArray{FT, 3},
}
    "Device array storing the spatial gradient data"
    data::FTA3D
    "View of ∂u₁/∂x₁"
    ∂₁u₁::FTA2D
    "View of ∂u₁/∂x₂"
    ∂₂u₁::FTA2D
    "View of ∂u₁/∂x₃"
    ∂₃u₁::FTA2D
    "View of ∂u₂/∂x₁"
    ∂₁u₂::FTA2D
    "View of ∂u₂/∂x₂"
    ∂₂u₂::FTA2D
    "View of ∂u₂/∂x₃"
    ∂₃u₂::FTA2D
    "View of ∂u₃/∂x₁"
    ∂₁u₃::FTA2D
    "View of ∂u₃/∂x₂"
    ∂₂u₃::FTA2D
    "View of ∂u₃/∂x₃"
    ∂₃u₃::FTA2D

    function VecGrad(Npl, Nel, ::Type{FT}) where {FT <: AbstractFloat}
        DA = CLIMA.array_type()
        data = DA{FT}(undef, Npl, 9, Nel)

        ∂₁u₁, ∂₂u₁, ∂₃u₁ =
            view(data, :, 1, :), view(data, :, 2, :), view(data, :, 3, :)
        ∂₁u₂, ∂₂u₂, ∂₃u₂ =
            view(data, :, 4, :), view(data, :, 5, :), view(data, :, 6, :)
        ∂₁u₃, ∂₂u₃, ∂₃u₃ =
            view(data, :, 7, :), view(data, :, 8, :), view(data, :, 9, :)

        return new{FT, typeof(∂₁u₁), typeof(data)}(
            data,
            ∂₁u₁,
            ∂₂u₁,
            ∂₃u₁,
            ∂₁u₂,
            ∂₂u₂,
            ∂₃u₂,
            ∂₁u₃,
            ∂₂u₃,
            ∂₃u₃,
        )
    end
end
#--------------------------------------------------------------------------------------------------
"""
    Vorticity{FT <: AbstractFloat,
           FTA2D <: AbstractArray{FT, 2},
           FTA3D <: AbstractArray{FT, 3},}

This data structure stores the vorticity of a velocity field.

# Fields

$(DocStringExtensions.FIELDS)

# Usage

    Vorticity(Npl, Nel, ::Type{FT}) where {FT <: AbstractFloat}

# Arguments for the inner constructor
 - `Npl`: Number of local degrees of freedom in a spectral element
 - `Nel`: Number of spectral elements
 - `FT`: Floating point precision
"""
struct Vorticity{
    FT <: AbstractFloat,
    FTA2D <: AbstractArray{FT, 2},
    FTA3D <: AbstractArray{FT, 3},
}
    "Device array storing the vorticity data"
    data::FTA3D
    "View of x1 component of vorticity"
    Ω₁::FTA2D
    "View of x2 component of vorticity"
    Ω₂::FTA2D
    "View of x3 component of vorticity"
    Ω₃::FTA2D
    function Vorticity(Npl, Nel, ::Type{FT}) where {FT <: AbstractFloat}
        DA = CLIMA.array_type()
        data = DA{FT}(undef, Npl, 3, Nel)
        Ω₁ = view(data, :, 1, :)
        Ω₂ = view(data, :, 2, :)
        Ω₃ = view(data, :, 3, :)
        return new{FT, typeof(Ω₁), typeof(data)}(data, Ω₁, Ω₂, Ω₃)
    end
end
#--------------------------------------------------------------------------------------------------
"""
    compute_vec_grad(model::BalanceLaw,
                         Q::AbstractArray{FT},
                        dg::DGModel,
                     vgrad::VecGrad{FT},) where {FT <: AbstractFloat}

This function computes the spatial gradients of the velocity field.

# Arguments
 - `model`: BalanceLaw
 - `Q`: State array
 - `dg`: DGmodel
 - `vgrad`: Vector gradients
"""
function compute_vec_grad(
    model::BalanceLaw,
    Q::AbstractArray{FT},
    dg::DGModel,
) where {FT <: AbstractFloat}
    Nel = size(Q.realdata, 3) # # of spectral elements
    Npl = size(Q.realdata, 1) # # of dof per element
    qm1 = size(dg.grid.D, 2)  # poly order + 1
    DA = CLIMA.array_type()

    vgrad = VecGrad(Npl, Nel, FT)
    ind = [
        varsindex(vars_state_conservative(model, FT), :ρ)
        varsindex(vars_state_conservative(model, FT), :ρu)
    ]
    _ρ, _ρu, _ρv, _ρw = ind[1], ind[2], ind[3], ind[4]

    vgrad_data = vgrad.data
    vgeo = dg.grid.vgeo
    D = dg.grid.D
    sv = Q.data

    device = DA <: Array ? CPU() : CUDA()
    g = DA{FT}(undef, Npl, Nel, 3, 3)

    workgroup = (qm1, qm1)
    ndrange = (Nel * qm1, qm1)

    kernel = compute_vec_grad_kernel!(device, workgroup)
    event = kernel(
        sv,
        D,
        vgeo,
        g,
        vgrad_data,
        _ρ,
        _ρu,
        _ρv,
        _ρw,
        Val(qm1),
        ndrange = ndrange,
    )
    wait(event)

    return vgrad
end
#--------------------------------------------------------------------------------------------------
"""
    compute_vorticity(dg::DGModel,
                   vgrad::VecGrad{FT},
                    vort::Vorticity{FT},) where {FT <: AbstractFloat}

This function computes the vorticity of the velocity field.

# Arguments
 - `dg`: DGmodel
 - `vgrad`: Velocity gradients
 - `vort`: Vorticity
"""
function compute_vorticity(
    dg::DGModel,
    vgrad::VecGrad{FT},
) where {FT <: AbstractFloat}
    Npl = size(vgrad.∂₁u₁, 1)
    Nel = size(vgrad.∂₁u₁, 2)
    qm1 = size(dg.grid.D, 2)  # poly order + 1
    DA = CLIMA.array_type()
    device = DA <: Array ? CPU() : CUDA()

    vort = Vorticity(Npl, Nel, FT)

    vgrad_data = vgrad.data
    vort_data = vort.data

    Ω₁, Ω₂, Ω₃ = vort.Ω₁, vort.Ω₂, vort.Ω₃

    workgroup = (qm1, qm1)
    ndrange = (Nel * qm1, qm1)

    kernel = compute_vorticity_kernel!(device, workgroup)
    event = kernel(vgrad_data, vort_data, Val(qm1), ndrange = ndrange)
    wait(event)

    return vort
end
#--------------------------------------------------------------------------------------------------
@kernel function compute_vec_grad_kernel!(
    sv::AbstractArray{FT},
    D::AbstractArray{FT, 2},
    vgeo::AbstractArray{FT},
    g::AbstractArray{FT, 4},
    vgrad_data::AbstractArray{FT, 3},
    _ρ::Int,
    _ρu::Int,
    _ρv::Int,
    _ρw::Int,
    ::Val{qm1},
) where {qm1, FT <: AbstractFloat}

    e = @index(Group, Linear)
    i, j = @index(Local, NTuple)

    s_D = @localmem FT (qm1, qm1)
    s_U = @localmem FT (qm1, qm1)
    s_V = @localmem FT (qm1, qm1)
    s_W = @localmem FT (qm1, qm1)

    s_D[i, j] = D[i, j]
    @synchronize
    # computing derivatives with respect to ξ1
    for t in 1:qm1, s in 1:qm1
        ijk = j + ((s - 1) + (t - 1) * qm1) * qm1
        s_U[i, j] = s_D[i, j] * (sv[ijk, _ρu, e] / sv[ijk, _ρ, e])
        s_V[i, j] = s_D[i, j] * (sv[ijk, _ρv, e] / sv[ijk, _ρ, e])
        s_W[i, j] = s_D[i, j] * (sv[ijk, _ρw, e] / sv[ijk, _ρ, e])
        @synchronize
        if j == 1
            for r in 2:qm1
                s_U[i, 1] += s_U[i, r]
                s_V[i, 1] += s_V[i, r]
                s_W[i, 1] += s_W[i, r]
            end
        end
        @synchronize
        if j == 1
            g[i + ((s - 1) + (t - 1) * qm1) * qm1, e, 1, 1] = s_U[i, 1] # ∂u₁∂ξ₁
            g[i + ((s - 1) + (t - 1) * qm1) * qm1, e, 2, 1] = s_V[i, 1] # ∂u₂∂ξ₁
            g[i + ((s - 1) + (t - 1) * qm1) * qm1, e, 3, 1] = s_W[i, 1] # ∂u₃∂ξ₁
        end
    end
    @synchronize
    # computing derivatives with respect to ξ2
    for t in 1:qm1, r in 1:qm1
        ijk = r + ((j - 1) + (t - 1) * qm1) * qm1
        s_U[i, j] = s_D[i, j] * (sv[ijk, _ρu, e] / sv[ijk, _ρ, e])
        s_V[i, j] = s_D[i, j] * (sv[ijk, _ρv, e] / sv[ijk, _ρ, e])
        s_W[i, j] = s_D[i, j] * (sv[ijk, _ρw, e] / sv[ijk, _ρ, e])
        @synchronize
        if j == 1
            for s in 2:qm1
                s_U[i, 1] += s_U[i, s]
                s_V[i, 1] += s_V[i, s]
                s_W[i, 1] += s_W[i, s]
            end
        end
        @synchronize
        if j == 1
            g[r + ((i - 1) + (t - 1) * qm1) * qm1, e, 1, 2] = s_U[i, 1] # ∂u₁∂ξ₂
            g[r + ((i - 1) + (t - 1) * qm1) * qm1, e, 2, 2] = s_V[i, 1] # ∂u₂∂ξ₂
            g[r + ((i - 1) + (t - 1) * qm1) * qm1, e, 3, 2] = s_W[i, 1] # ∂u₃∂ξ₂
        end
    end
    @synchronize
    # computing derivatives with respect to ξ3
    for s in 1:qm1, r in 1:qm1
        ijk = r + ((s - 1) + (j - 1) * qm1) * qm1
        s_U[i, j] = s_D[i, j] * (sv[ijk, _ρu, e] / sv[ijk, _ρ, e])
        s_V[i, j] = s_D[i, j] * (sv[ijk, _ρv, e] / sv[ijk, _ρ, e])
        s_W[i, j] = s_D[i, j] * (sv[ijk, _ρw, e] / sv[ijk, _ρ, e])
        @synchronize
        if j == 1
            for t in 2:qm1
                s_U[i, 1] += s_U[i, t]
                s_V[i, 1] += s_V[i, t]
                s_W[i, 1] += s_W[i, t]
            end
        end
        @synchronize
        if j == 1
            g[r + ((s - 1) + (i - 1) * qm1) * qm1, e, 1, 3] = s_U[i, 1] # ∂u₁∂ξ₃
            g[r + ((s - 1) + (i - 1) * qm1) * qm1, e, 2, 3] = s_V[i, 1] # ∂u₂∂ξ₃
            g[r + ((s - 1) + (i - 1) * qm1) * qm1, e, 3, 3] = s_W[i, 1] # ∂u₃∂ξ₃
        end
    end
    @synchronize

    ∂₁u₁, ∂₂u₁, ∂₃u₁ = 1, 2, 3
    ∂₁u₂, ∂₂u₂, ∂₃u₂ = 4, 5, 6
    ∂₁u₃, ∂₂u₃, ∂₃u₃ = 7, 8, 9

    for k in 1:qm1
        ijk = i + ((j - 1) + (k - 1) * qm1) * qm1

        ξ1x1 = vgeo[ijk, _ξ1x1, e]
        ξ1x2 = vgeo[ijk, _ξ1x2, e]
        ξ1x3 = vgeo[ijk, _ξ1x3, e]
        ξ2x1 = vgeo[ijk, _ξ2x1, e]
        ξ2x2 = vgeo[ijk, _ξ2x2, e]
        ξ2x3 = vgeo[ijk, _ξ2x3, e]
        ξ3x1 = vgeo[ijk, _ξ3x1, e]
        ξ3x2 = vgeo[ijk, _ξ3x2, e]
        ξ3x3 = vgeo[ijk, _ξ3x3, e]

        vgrad_data[ijk, ∂₁u₁, e] =
            g[ijk, e, 1, 1] * ξ1x1 +
            g[ijk, e, 1, 2] * ξ2x1 +
            g[ijk, e, 1, 3] * ξ3x1
        vgrad_data[ijk, ∂₂u₁, e] =
            g[ijk, e, 1, 1] * ξ1x2 +
            g[ijk, e, 1, 2] * ξ2x2 +
            g[ijk, e, 1, 3] * ξ3x2
        vgrad_data[ijk, ∂₃u₁, e] =
            g[ijk, e, 1, 1] * ξ1x3 +
            g[ijk, e, 1, 2] * ξ2x3 +
            g[ijk, e, 1, 3] * ξ3x3

        vgrad_data[ijk, ∂₁u₂, e] =
            g[ijk, e, 2, 1] * ξ1x1 +
            g[ijk, e, 2, 2] * ξ2x1 +
            g[ijk, e, 2, 3] * ξ3x1
        vgrad_data[ijk, ∂₂u₂, e] =
            g[ijk, e, 2, 1] * ξ1x2 +
            g[ijk, e, 2, 2] * ξ2x2 +
            g[ijk, e, 2, 3] * ξ3x2
        vgrad_data[ijk, ∂₃u₂, e] =
            g[ijk, e, 2, 1] * ξ1x3 +
            g[ijk, e, 2, 2] * ξ2x3 +
            g[ijk, e, 2, 3] * ξ3x3

        vgrad_data[ijk, ∂₁u₃, e] =
            g[ijk, e, 3, 1] * ξ1x1 +
            g[ijk, e, 3, 2] * ξ2x1 +
            g[ijk, e, 3, 3] * ξ3x1
        vgrad_data[ijk, ∂₂u₃, e] =
            g[ijk, e, 3, 1] * ξ1x2 +
            g[ijk, e, 3, 2] * ξ2x2 +
            g[ijk, e, 3, 3] * ξ3x2
        vgrad_data[ijk, ∂₃u₃, e] =
            g[ijk, e, 3, 1] * ξ1x3 +
            g[ijk, e, 3, 2] * ξ2x3 +
            g[ijk, e, 3, 3] * ξ3x3
    end
end
#--------------------------------------------------------------------------------------------------
@kernel function compute_vorticity_kernel!(
    vgrad_data::AbstractArray{FT, 3},
    vort_data::AbstractArray{FT, 3},
    ::Val{qm1},
) where {qm1, FT <: AbstractFloat}

    e = @index(Group, Linear)
    i, j = @index(Local, NTuple)

    ∂₁u₁, ∂₂u₁, ∂₃u₁ = 1, 2, 3
    ∂₁u₂, ∂₂u₂, ∂₃u₂ = 4, 5, 6
    ∂₁u₃, ∂₂u₃, ∂₃u₃ = 7, 8, 9
    Ω₁, Ω₂, Ω₃ = 1, 2, 3

    for k in 1:qm1
        ijk = i + ((j - 1) + (k - 1) * qm1) * qm1

        vort_data[ijk, Ω₁, e] =
            vgrad_data[ijk, ∂₂u₃, e] - vgrad_data[ijk, ∂₃u₂, e]
        vort_data[ijk, Ω₂, e] =
            vgrad_data[ijk, ∂₃u₁, e] - vgrad_data[ijk, ∂₁u₃, e]
        vort_data[ijk, Ω₃, e] =
            vgrad_data[ijk, ∂₁u₂, e] - vgrad_data[ijk, ∂₂u₁, e]
    end
end
#--------------------------------------------------------------------------------------------------


text:
struct ARMAParams{T} <: AbstractParams
    c::Bool
    p::Vector{T}
    q::Vector{T}
    function ARMAParams(c::Bool, p::AbstractVector{T}, q::AbstractVector{T}) where T <: Integer
        return new{T}(c, p, q)
    end
end

ARMAParams(c::Bool,p::Integer,q::Integer) = ARMAParams(c, collect(1:p), collect(1:q))
ARMAParams(p::Integer,q::Integer) = ARMAParams(true, p, q)

function fit(params::ARMAParams, z::AbstractVector; n::Integer=2)
    P = isempty(params.p) ? 0 : maximum(params.p)
    Q = isempty(params.q) ? 0 : maximum(params.q)
    return ARMAModel{P,Q}(hannan_rissanen(z, params.c, params.p, params.q, n=n)...)
end

struct ARMAXModel{p,q,X,T} <: AbstractModel{T}
    μ::T
    ϕ::SVector{p,T}
    θ::SVector{q,T}
    β::SVector{X,T}
    σ2::T
    function ARMAXModel{p,q,X,T}(μ::T, ϕ::AbstractVector{T}, θ::AbstractVector{T}, β::AbstractVector{T}, σ2::T) where {p,q,X,T}
        return new{p,q,X,T}(μ, SVector{p,T}(ϕ), SVector{q,T}(θ), SVector{X,T}(β), σ2)
    end
end

const ARMAModel{p,q,T} = ARMAXModel{p,q,0,T}
ARMAModel{p,q}(μ::T,ϕ::AbstractVector{T},θ::AbstractVector{T},σ2::T) where {p,q,T} = ARMAXModel{p,q,0,T}(μ, ϕ, θ, T[], σ2)

function hannan_rissanen(z::AbstractVector, c::Bool, p::AbstractVector{<:Integer}, q::AbstractVector{<:Integer}; m::Integer=20, n::Integer=10)
    m >= 0 || throw(ArgumentError("order of first ar model should be positive"))
    T = typeof(zero(eltype(z)) / 1)
    N = length(z)
    P = isempty(p) ? 0 : maximum(p)
    Q = isempty(q) ? 0 : maximum(q)
    m = m + max(P, Q)
    ar = fit(ARParams(true, m), z)
    a = residuals(ar, z)[m + 1:N]
    x = zeros(T, 0, 0)
    Z, ztp1 = ls_matrix(z[m + 1:N], a, x, c, p, q)
    ϕ0 = Z \ ztp1
    ε = ztp1 - Z * ϕ0
    σ2 = dot(ε, ε) / (N - m - Q)
    μ, ϕ, θ, β = ls_params(ϕ0, c, p, q)
    σ2prev = Inf
    for k in 2:n
        arma = ARMAModel{P,Q}(μ, ϕ, θ, σ2)
        a = residuals(arma, z)[m + 1:N]
        ls_matrix!(Z, z[m + 1:N], a, x, c, p, q)
        ϕθ = Z \ ztp1
        ε = ztp1 - Z * ϕθ
        σ2prev = σ2
        σ2 = dot(ε, ε) / (N - m - Q)
        if (σ2 ≈ σ2prev) σ2 = σ2prev; break end
        μ, ϕ, θ, β = ls_params(ϕ0, c,  p, q)
    end
    return μ, ϕ, θ, σ2
end

hannan_rissanen(z::AbstractVector, c::Bool, p::Integer, q::Integer; m::Integer=20, n::Integer=1) = hannan_rissanen(z, c, collect(1:p), collect(1:q); m=m, n=n)
hannan_rissanen(z::AbstractVector, p::Integer, q::Integer; m::Integer=20, n::Integer=1) = hannan_rissanen(z, true, p, q; m=m, n=n)

function forecast(model::M,z::AbstractVector{T},a::AbstractVector{T}) where {p,q,T,M <: ARMAModel{p,q,T}}
    N = length(z)
    zhat = model.μ
    for j in 1:min(N, q)
        zhat -= model.θ[j] * a[N - j + 1]
    end
    for j in 1:min(N, p)
        zhat += model.ϕ[j] * z[N - j + 1]
    end
    return zhat
end

function forecast(model::M, z::AbstractVector{T}) where {p,q,T,M <: ARMAModel{p,q,T}}
    N = length(z)
    a = Vector{T}(undef, N + 1)
    a[1] = zero(T)
    for i in 1:N
        a[i + 1] = z[i] - model.μ
        for j in 1:min(q, i)
            a[i + 1] += model.θ[j] * a[i - j + 1]
        end
        for j in 1:min(p, i - 1)
            a[i + 1] -= model.ϕ[j] * z[i - j]
        end
    end
    return forecast(model,z,a[2:N+1])
end

function MA∞(model::M, m::Integer) where {p,q,T,M <: ARMAModel{p,q,T}}
    ψ = Vector{T}(undef, m)
    for j in 1:m
        ψ[j] = - (j > q ? zero(T) : model.θ[j])
        for k in 1:p
            ψ[j] += model.ϕ[k] * (j - k == 0 ? one(T) : j - k < 0 ? zero(T) : ψ[j - k])
        end
    end
    return MAModel{m}(model.μ / (1 - sum(model.ϕ)), .-ψ, model.σ2)
end

function AR∞(model::M, m::Integer) where {p,q,T,M <: ARMAModel{p,q,T}}
    π = Vector{T}(undef, m)
    for j in 1:m
        π[j] = (j > p ? zero(T) : model.ϕ[j])
        for k in 1:q
            π[j] += model.θ[k] * (j - k == 0 ? -one(T) : j - k < 0 ? zero(T) : π[j - k])
        end
    end
    μ = model.μ / (1 - sum(model.ϕ)) * (1 - sum(π))
    μ = isnan(μ) ? zero(T) : μ
    return ARModel{m}(μ, π, model.σ2)
end


text:
# finite difference tests

"""
  Performes finite difference tests to check that coordinate/metric/normal
  calculation of the given mesh can be complex stepped

  Tests are available for the following fields of the mesh:

   * coords
   * coords_interface
   * coords_bndry
   * dxidx
   * jac
   * nrm_face
   * nrm_bndry

TODO: add parallel tests
"""
function testMeshDerivatives(mesh, sbp, opts)

  deriv_cs = computeMeshDeriv(mesh, sbp, opts, mesh.coords)
  deriv_fd = computeMeshDeriv_fd(mesh, sbp, opts, mesh.coords)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  deriv_cs = computeMeshDeriv(mesh, sbp, opts, mesh.coords_interface)
  deriv_fd = computeMeshDeriv_fd(mesh, sbp, opts, mesh.coords_interface)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  deriv_cs = computeMeshDeriv(mesh, sbp, opts, mesh.coords_bndry)
  deriv_fd = computeMeshDeriv_fd(mesh, sbp, opts, mesh.coords_bndry)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  deriv_cs = computeMeshDeriv(mesh, sbp, opts, mesh.dxidx)
  deriv_fd = computeMeshDeriv_fd(mesh, sbp, opts, mesh.dxidx)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  deriv_cs = computeMeshDeriv(mesh, sbp, opts, mesh.jac)
  deriv_fd = computeMeshDeriv_fd(mesh, sbp, opts, mesh.jac)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 3e-4

  deriv_cs = computeMeshDeriv(mesh, sbp, opts, mesh.nrm_face)
  deriv_fd = computeMeshDeriv_fd(mesh, sbp, opts, mesh.nrm_face)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  deriv_cs = computeMeshDeriv(mesh, sbp, opts, mesh.nrm_bndry)
  deriv_fd = computeMeshDeriv_fd(mesh, sbp, opts, mesh.nrm_bndry)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  return nothing
end

"""
  Compute the derivative of the given mesh field with respect to the vertex
  coordinates (note that this is the derivative with respect to the 1D vector
  representation of the vertex coordinates, not mesh.vert_coord, which duplicates
  nodes).

  Uses the complex step method to compute the derivative.  The mesh must have
  been created with Tmsh = Complex128.

  **Inputs**

   * mesh
   * sbp
   * opts
   * field: a field of the mesh object that is in the "numerator" of the
            derivative.  Must be the array that is stored in the mesh, not
            a copy.
"""
function computeMeshDeriv(mesh, sbp, opts, field::AbstractArray)

  @assert eltype(mesh.vert_coords) == Complex128

  h = 1e-20
  pert = Complex128(0, h)
  numdof = mesh.dim*mesh.coord_numNodes

  dRdx = zeros(length(field), numdof)

  coords_vec = zeros(Complex128, numdof)
  coords3DTo1D(mesh, mesh.vert_coords, coords_vec, PdePumiInterface.AssignReduction{Complex128}())

  for i=1:numdof
    coords_vec[i] += pert
    coords1DTo3D(mesh, coords_vec, mesh.vert_coords)
    recalcCoordinatesAndMetrics(mesh, sbp, opts)

    for j=1:length(field)
      dRdx[j, i] = imag(field[j])/h
    end

    coords_vec[i] -= pert
    coords1DTo3D(mesh, coords_vec, mesh.vert_coords)
    recalcCoordinatesAndMetrics(mesh, sbp, opts)
  end

  return dRdx
end

"""
  Similar to [`computeMeshDeriv`](@ref), but computes the quantity using
  finite differences
"""
function computeMeshDeriv_fd(mesh::AbstractMesh{Tmsh}, sbp, opts, field::AbstractArray) where {Tmsh}

  h = 1e-6
  numdof = mesh.dim*mesh.coord_numNodes

  dRdx = zeros(length(field), numdof)

  coords_vec = zeros(Tmsh, numdof)
  coords3DTo1D(mesh, mesh.vert_coords, coords_vec, PdePumiInterface.AssignReduction{Tmsh}())

  R0 = copy(field)

  for i=1:numdof
    coords_vec[i] += h
    coords1DTo3D(mesh, coords_vec, mesh.vert_coords)
    recalcCoordinatesAndMetrics(mesh, sbp, opts)

    res_vec_i = sview(dRdx, :, i)
    R1 = copy(field)
    for j=1:length(R1)
      res_vec_i[j] = (R1[j] - R0[j])/h
    end

    coords_vec[i] -= h
    coords1DTo3D(mesh, coords_vec, mesh.vert_coords)
    recalcCoordinatesAndMetrics(mesh, sbp, opts)
  end

  return dRdx
end

#------------------------------------------------------------------------------
# test derivative of residual with respect to mesh quantities

"""
  Compares finite difference and complex step derivatives of the residual
  with respect to mesh quantities.  Checks the same quantities as
  [`testMeshDerivatives`](@ref)
"""
function testResidualDerivatives(mesh, eqn, sbp, opts)

  deriv_cs = computeResidualDeriv(mesh, eqn, sbp, opts, mesh.coords)
  deriv_fd = computeResidualDeriv_fd(mesh, eqn, sbp, opts, mesh.coords)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  deriv_cs = computeResidualDeriv(mesh, eqn, sbp, opts, mesh.coords_interface)
  deriv_fd = computeResidualDeriv_fd(mesh, eqn, sbp, opts, mesh.coords_interface)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  deriv_cs = computeResidualDeriv(mesh, eqn, sbp, opts, mesh.coords_bndry)
  deriv_fd = computeResidualDeriv_fd(mesh, eqn, sbp, opts, mesh.coords_bndry)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  deriv_cs = computeResidualDeriv(mesh, eqn, sbp, opts, mesh.dxidx)
  deriv_fd = computeResidualDeriv_fd(mesh, eqn, sbp, opts, mesh.dxidx)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  deriv_cs = computeResidualDeriv(mesh, eqn, sbp, opts, mesh.jac)
  deriv_fd = computeResidualDeriv_fd(mesh, eqn, sbp, opts, mesh.jac)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  deriv_cs = computeResidualDeriv(mesh, eqn, sbp, opts, mesh.nrm_face)
  deriv_fd = computeResidualDeriv_fd(mesh, eqn, sbp, opts, mesh.nrm_face)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  deriv_cs = computeResidualDeriv(mesh, eqn, sbp, opts, mesh.nrm_bndry)
  deriv_fd = computeResidualDeriv_fd(mesh, eqn, sbp, opts, mesh.nrm_bndry)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  return nothing
end

"""
  Computes the derivative of the residual with respect to a given field of the
  mesh.  See [`computeMeshDeriv`](@ref), has a similar setup, except it computes
  derivatives of mesh quantities with respect to mesh vertex coordinates.

  **Inputs**

   * mesh
   * sbp
   * eqn
   * opts
   * field: field of the mesh object.  Cannot be a copy of the array.
"""
function computeResidualDeriv(mesh, sbp, eqn, opts, field::AbstractArray)

  h = 1e-20
  pert = Complex128(0, h)
#  numdof = mesh.dim*mesh.coord_numNodes
  numdof = length(field)
  dRdx = zeros(mesh.numDof, numdof)

  for i=1:numdof
    field[i] += pert

    evalResidual(mesh, sbp, eqn, opts)
    res_vec_i = sview(dRdx, :, i)
    array3DTo1D(mesh, sbp, eqn, opts, imag(eqn.res)/h, res_vec_i)

    field[i] -= pert
  end

  return dRdx
end

function computeResidualDeriv_fd(mesh, sbp, eqn, opts, field::AbstractArray)

  h = 1e-6
  numdof = length(field)
  dRdx = zeros(mesh.numDof, numdof)

  R0 = zeros(eqn.res_vec)
  R1 = zeros(eqn.res_vec)
  evalResidual(mesh, sbp, eqn, opts)
  array3DTo1D(mesh, sbp, eqn, opts, eqn.res, R0)

  for i=1:numdof
    field[i] += h

    evalResidual(mesh, sbp, eqn, opts)
    array3DTo1D(mesh, sbp, eqn, opts, eqn.res, R1)
    res_vec_i = sview(dRdx, :, i)
    for j=1:length(R1)
      res_vec_i[j] = (R1[j] - R0[j])/h
    end

    field[i] -= h
  end

  return dRdx
end

#------------------------------------------------------------------------------
# Test gradient computed via adjoint

"""
  Tests the total derivative of a functional with respect to the
  mesh vertex coordinates against the total derivative computed via adjoint

  This solves the PDE once for every coordinate of every node in the mesh.
  This is very expensive unless done on a tiny mesh

  **Inputs**

   * mesh
   * sbp
   * eqn
   * opts
   * functional

"""
function testDJDx(mesh, sbp, eqn, opts, func::AbstractFunctional)

  solvePDE(mesh, sbp, eqn, opts)

  deriv_cs = computeDJDx_adjoint(mesh, sbp, eqn, opts, func)
  deriv_fd = computeDJDx_adjoint(mesh, sbp, eqn, opts, func)
  @test maximum(abs.(deriv_cs - deriv_fd)) < 1e-5

  return nothing
end

"""
  Computes total derivative of a functional J with respect ot the mesh vertex
  coordinates.
"""
function computeDJDx_fd(mesh, sbp, eqn, opts, func::AbstractFunctional)

  h = 1e-6
  J0 = evalFunctional(mesh, sbp, eqn, opts, func)

  numdof = mesh.dim*mesh.coord_numNodes
  coords_vec = zeros(Complex128, numdof)
  coords3DTo1D(mesh, mesh.vert_coords, coords_vec, PdePumiInterface.AssignReduction{Complex128}())

  DJDx = zeros(numdof)

  for i=1:numdof
    coords_vec[i] += h
    coords1DTo3D(mesh, coords_vec, mesh.vert_coords)
    recalcCoordinatesAndMetrics(mesh, sbp, opts)
    solvePDE(mesh, sbp, eqn, opts)

    J1 = evalFunctional(mesh, sbp, eqn, opts, func)
    DJDx[i] = (J1 - J0)/h

    coords_vec[i] -= h
    coords1DTo3D(mesh, coords_vec, mesh.vert_coords)
    recalcCoordinatesAndMetrics(mesh, sbp, opts)
    solvePDE(mesh, sbp, eqn, opts)
  end

  return real(DJDx)
end

"""
  Computes the total derivative of a functional J with respect to the mesh vertex
  coordinates using the (discrete) adjoint
"""
function computeDJDx_adjoint(mesh, sbp, eqn, opts, func::AbstractFunctional)

  dJdx = computedJdx_vec(mesh, sbp, eqn, opts, func)
  dRdx = computedRdx_vec(mesh, sbp, eqn, opts)

  psi_discrete = zeros(eqn.q_vec)
  calcAdjoint(mesh, sbp, eqn, opts, func, psi_discrete)

  DJDx = dJdx + dRdx.'*psi_discrete

  return real(DJDx)
end

"""
  Compute the vector form of dJdx.  The length is mesh.dim*mesh.coord_numNodes
"""
function computedJdx_vec(mesh, sbp, eqn, opts, func::AbstractFunctional)

  @assert eltype(mesh.vert_coords) == Complex128
  h = 1e-20
  pert = Complex128(0, h)

  numdof = mesh.dim*mesh.coord_numNodes
  coords_vec = zeros(Complex128, numdof)
  coords3DTo1D(mesh, mesh.vert_coords, coords_vec, PdePumiInterface.AssignReduction{Complex128}())

  dJdx = zeros(numdof)
  for i=1:numdof
    coords_vec[i] += pert
    coords1DTo3D(mesh, coords_vec, mesh.vert_coords)
    recalcCoordinatesAndMetrics(mesh, sbp, opts)

    J_val = evalFunctional(mesh, sbp, eqn, opts, func)
    dJdx[i] = imag(J_val)/h

    coords_vec[i] -= pert
    coords1DTo3D(mesh, coords_vec, mesh.vert_coords)
    recalcCoordinatesAndMetrics(mesh, sbp, opts)
  end

  return dJdx
end

"""
  Compute derivative of residual with repsect to the mesh vertex coordinates
  The result is a matrix mesh.numDof x mesh.dim*mesh.coord_numNodes
"""
function computedRdx_vec(mesh, sbp, eqn, opts)

  h = 1e-20
  pert = Complex128(0, h)
  numdof = mesh.dim*mesh.coord_numNodes
  dRdx = zeros(mesh.numDof, numdof)

  coords_vec = zeros(Complex128, numdof)
  coords3DTo1D(mesh, mesh.vert_coords, coords_vec, PdePumiInterface.AssignReduction{Complex128}())

  for i=1:numdof
    coords_vec[i] += pert
    coords1DTo3D(mesh, coords_vec, mesh.vert_coords)
    recalcCoordinatesAndMetrics(mesh, sbp, opts)

    evalResidual(mesh, sbp, eqn, opts)
    res_vec_i = sview(dRdx, :, i)
    array3DTo1D(mesh, sbp, eqn, opts, imag(eqn.res)/h, res_vec_i)

    coords_vec[i] -= pert
    coords1DTo3D(mesh, coords_vec, mesh.vert_coords)
    recalcCoordinatesAndMetrics(mesh, sbp, opts)
  end

  return dRdx
end


text:
# Statistics for an array of scalars

# Geometric mean
function gmean{T<:Real}(a::AbstractArray{T})
    s = 0.0
    n = length(a)
    for i in 1:n
        tmp = a[i]
        if tmp < 0.0
            throw(DomainError())
        elseif tmp == 0.0
            return 0.0
        else
            s += log(tmp)
        end
    end
    return exp(s / n)
end

# Harmonic mean
function hmean{T<:Real}(a::AbstractArray{T})
    s = 0.0
    n = length(a)
    for i in 1:n
        s += 1 / a[i]
    end
    return n / s
end

# Variation: std / mean
variation{T<:Real}(x::AbstractArray{T}, m::Real) = stdm(x, m) / m
variation{T<:Real}(x::AbstractArray{T}) = variation(x, mean(x))

# Standard error of the mean: std(a)
sem{T<:Real}(a::AbstractArray{T}) = sqrt(var(a) / length(a))

# Median absolute deviation
mad{T<:Real}(v::AbstractArray{T}, center::Real) = 1.4826 * median!(abs(v-center))

function mad{T<:Real}(v::AbstractArray{T})
    v = copy(v)
    center = median!(v)
    for i in 1:length(v)
        v[i] = abs(v[i]-center)
    end
    1.4826 * median!(v)
#    1.4826 * median!(v, checknan=false)
end

# Skewness
function skewness{T<:Real}(v::AbstractVector{T}, m::Real)
    n = length(v)
    cm2 = 0.0   # empirical 2nd centered moment (variance)
    cm3 = 0.0   # empirical 3rd centered moment
    for x_i in v
        z = x_i - m
        z2 = z * z

        cm2 += z2
        cm3 += z2 * z
    end
    cm3 /= n
    cm2 /= n
    return cm3 / (cm2^1.5)
end

skewness{T<:Real}(v::AbstractVector{T}) = skewness(v, mean(v))

# (excessive) Kurtosis
function kurtosis{T<:Real}(v::AbstractVector{T}, m::Real)
    n = length(v)
    cm2 = 0.0  # empirical 2nd centered moment (variance)
    cm4 = 0.0  # empirical 4th centered moment
    for x_i in v
        z = x_i - m
        z2 = z * z
        cm2 += z2
        cm4 += z2 * z2
    end
    cm4 /= n
    cm2 /= n
    return (cm4 / (cm2^2)) - 3.0
end

kurtosis{T<:Real}(v::AbstractVector{T}) = kurtosis(v, mean(v))

# Minimum and maximum
function minmax{T<:Real}(x::AbstractArray{T})
    if isempty(x)
        error("minmax: x cannot be empty.")
    end

    xmin = xmax = x[1]
    for i = 2:length(x)
        x_i = x[i]
        if x_i < xmin
            xmin = x_i
        elseif x_i > xmax
            xmax = x_i
        end
    end
    return xmin, xmax
end

# Mid-range
function midrange{T<:Real}(a::AbstractArray{T})
    xmin, xmax = minmax(a)
    return xmin + (xmax - xmin) / 2
end

# Range: xmax - xmin
function range{T<:Real}(a::AbstractArray{T})
    xmin, xmax = minmax(a)
    return xmax - xmin
end

# order (aka. rank), resolving ties using the mean rank
function tiedrank{T<:Real}(v::AbstractArray{T})
    n     = length(v)
    place = sortperm(v)
    ord   = Array(Float64, n)

    i = 1
    while i <= n
        j = i
        while j + 1 <= n && v[place[i]] == v[place[j + 1]]
            j += 1
        end

        if j > i
            m = sum(i:j) / (j - i + 1)
            for k = i:j
                ord[place[k]] = m
            end
        else
            ord[place[i]] = i
        end

        i = j + 1
    end

    return ord
end

tiedrank{T<:Real}(X::AbstractMatrix{T}) = tiedrank(reshape(X, length(X)))

# quantile and friends

quantile{T<:Real}(v::AbstractVector{T}) = quantile(v, [.0, .25, .5, .75, 1.0])
percentile{T<:Real}(v::AbstractVector{T}) = quantile(v, [1:99] / 100)
quartile{T<:Real}(v::AbstractVector{T}) = quantile(v, [.25, .5, .75])
quintile{T<:Real}(v::AbstractVector{T}) = quantile(v, [.2, .4, .6, .8])
decile{T<:Real}(v::AbstractVector{T}) = quantile(v, [.1, .2, .3, .4, .5, .6, .7, .8, .9])
iqr{T<:Real}(v::AbstractVector{T}) = quantile(v, [.25, .75])

# table & mode

function table{T}(a::AbstractArray{T})
    counts = Dict{T, Int}()
    for i = 1:length(a)
        tmp = a[i]
        counts[tmp] = get(counts, tmp, 0) + 1
    end
    return counts
end

function mode{T}(a::AbstractArray{T})
    if isempty(a)
        throw(ArgumentError("mode: a cannot be empty."))
    end
    tab = table(a)
    m = max(values(tab))
    for (k, v) in tab
        if v == m
            return k
        end
    end
end

function modes{T}(a::AbstractArray{T})
    if isempty(a)
        throw(ArgumentError("mode: a cannot be empty."))
    end
    res = Array(T, 0)
    tab = table(a)
    m = max(values(tab))
    for (k, v) in tab
        if v == m
            push!(res, k)
        end
    end
    return res
end

# Print out basic summary statistics
function describe{T<:Real}(a::AbstractArray{T})
    q00, q25, q50, q75, q10 = quantile(a, [0.00, 0.25, 0.50, 0.75, 1.00])
    @printf "Min:          %.6f\n" q00
    @printf "1st Quartile: %.6f\n" q25
    @printf "Median:       %.6f\n" q50
    @printf "Mean:         %.6f\n" mean(a)
    @printf "3rd Quartile: %.6f\n" q75
    @printf "Max:          %.6f\n" q10
    return
end


text:
nanosx800 = Piezo("NanoSX800",
                  -20.0V,
                  130.0V,
                  0.0V,
                  10.0V,
                  -50.0μm,
                  850.0μm,
                  50.0μm,
                  1150.0μm, #900μm,#nominal max displacement
#                  125μm, #disp_offset (so when the positioner is at -50.0μm it's actually at 125μm for force calculations)
                  7.0μF,
                  1,   #motion axis
                  77.1917g, #effective mass
                  (210.0Hz, 500.0Hz, 700.0Hz), #resonance frequencies without load
                  (0.2N/μm, 2.5N/μm, 2.5N/μm) #stiffnesses
                 )

register_positioner(nanosx800) #used on OCPI2