text:
module JNI

import Libdl

# jnienv.jl exports
export JNINativeInterface, JNIEnv, JNIInvokeInterface, JavaVM
# jni_md.h exports
export jint, jlong, jbyte
# jni.h exports
export jboolean, jchar, jshort, jfloat, jdouble, jsize, jprimitive
# constant export
export JNI_TRUE, JNI_FALSE
export JNI_VERSION_1_1, JNI_VERSION_1_2, JNI_VERSION_1_4, JNI_VERSION_1_6, JNI_VERSION_1_8
# export JNI_VERSION_9, JNI_VERSION_10 # Intentionally excluded, use JNI.JNI_VERSION_9
export JNI_OK, JNI_ERR, JNI_EDETACHED, JNI_EVERSION, JNI_ENOMEM, JNI_EEXIST, JNI_EINV
#export jnifunc

include("jnienv.jl")

const jniref = Ref(JNINativeInterface())
#global jnifunc
Base.@deprecate_binding jnifunc jniref[]

const ppenv = Ref(Ptr{JNIEnv}(C_NULL))
const ppjvm = Ref(Ptr{JavaVM}(C_NULL))
const jvmfunc = Ref{JNIInvokeInterface}()

# jni_md.h
const jint = Cint
#ifdef _LP64 /* 64-bit Solaris */
# typedef long jlong;
const jlong = Clonglong
const jbyte = Cchar

# jni.h

const jboolean = Cuchar
const jchar = Cushort
const jshort = Cshort
const jfloat = Cfloat
const jdouble = Cdouble
const jsize = jint
jprimitive = Union{jboolean, jchar, jshort, jfloat, jdouble, jint, jlong}

jobject = Ptr{Nothing}
jclass = Ptr{Nothing}
jthrowable = Ptr{Nothing}
jweak = Ptr{Nothing}
jmethodID = Ptr{Nothing}
jfieldID = Ptr{Nothing}
jstring = Ptr{Nothing}
jarray = Ptr{Nothing}
JNINativeMethod = Ptr{Nothing}
jobjectArray = Ptr{Nothing}
jbooleanArray = Ptr{Nothing}
jbyteArray = Ptr{Nothing}
jshortArray = Ptr{Nothing}
jintArray = Ptr{Nothing}
jlongArray = Ptr{Nothing}
jfloatArray = Ptr{Nothing}
jdoubleArray = Ptr{Nothing}
jcharArray = Ptr{Nothing}
jvalue = Int64

@enum jobjectRefType begin
    JNIInvalidRefType    = 0
    JNILocalRefType      = 1
    JNIGlobalRefType     = 2
    JNIWeakGlobalRefType = 3
end

"""
    AbstractJavaRef

    Abstract type for jobject in jni.h
    Must be convertible to a `Ptr{Nothing}` by `ccall` usually by overriding unsafe_convert.
"""
abstract type AbstractJavaRef end

const JNI_VERSION_1_1 = convert(Cint, 0x00010001)
const JNI_VERSION_1_2 = convert(Cint, 0x00010002)
const JNI_VERSION_1_4 = convert(Cint, 0x00010004)
const JNI_VERSION_1_6 = convert(Cint, 0x00010006)
const JNI_VERSION_1_8 = convert(Cint, 0x00010008)
const JNI_VERSION_9   = convert(Cint, 0x00090000)
const JNI_VERSION_10  = convert(Cint, 0x000a0000)

const JNI_TRUE = convert(Cchar, 1)
const JNI_FALSE = convert(Cchar, 0)

# Return Values
const JNI_OK           = convert(Cint, 0)               #/* success */
const JNI_ERR          = convert(Cint, -1)              #/* unknown error */
const JNI_EDETACHED    = convert(Cint, -2)              #/* thread detached from the VM */
const JNI_EVERSION     = convert(Cint, -3)              #/* JNI version error */
const JNI_ENOMEM       = convert(Cint, -4)              #/* not enough memory */
const JNI_EEXIST       = convert(Cint, -5)              #/* VM already created */
const JNI_EINVAL       = convert(Cint, -6)              #/* invalid arguments */

# There is likely over specification here
PtrIsCopy = Union{Ptr{jboolean},Ref{jboolean},Array{jboolean,}}
AnyString = Union{AbstractString,Cstring,Ptr{UInt8}}
jobject_arg = Union{jobject,AbstractJavaRef}
jobjectArray_arg = Union{jobjectArray,AbstractJavaRef}

struct JNIError <: Exception
    msg::String
end

struct JavaVMOption
    optionString::Ptr{UInt8}
    extraInfo::Ptr{Nothing}
end

struct JavaVMInitArgs
    version::Cint
    nOptions::Cint
    options::Ptr{JavaVMOption}
    ignoreUnrecognized::Cchar
end

function load_jni(penv::Ptr{JNIEnv})
    global jnienv = unsafe_load(penv)
    jniref[] = unsafe_load(jnienv.JNINativeInterface_) #The JNI Function table
    #global jnifunc = jniref[]
end
is_jni_loaded() = jniref[].GetVersion != C_NULL
is_env_loaded() = ppenv[] != C_NULL

"""
    init_new_vm(opts)

Initialize a new Java virtual machine.
"""
function init_new_vm(libpath,opts)
    libjvm = load_libjvm(libpath)
    create = Libdl.dlsym(libjvm, :JNI_CreateJavaVM)
    opt = [JavaVMOption(pointer(x), C_NULL) for x in opts]
    GC.@preserve opt begin
        vm_args = JavaVMInitArgs(JNI_VERSION_1_8, convert(Cint, length(opts)),
                                 convert(Ptr{JavaVMOption}, pointer(opt)), JNI_TRUE)
        res = ccall(create, Cint, (Ptr{Ptr{JavaVM}}, Ptr{Ptr{JNIEnv}}, Ptr{JavaVMInitArgs}), ppjvm, ppenv,
                    Ref(vm_args))
        res < 0 && throw(JNIError("Unable to initialise Java VM: $(res)"))
    end
    jvm = unsafe_load(ppjvm[])
    jvmfunc[] = unsafe_load(jvm.JNIInvokeInterface_)
    load_jni(ppenv[])
    return
end

"""
    init_current_vm()

Allow initialization from running VM. Uses the first VM it finds.
"""
function init_current_vm(libpath)
    libjvm = load_libjvm(libpath)
    pnum = Array{Cint}(undef, 1)
    ccall(Libdl.dlsym(libjvm, :JNI_GetCreatedJavaVMs), Cint, (Ptr{Ptr{JavaVM}}, Cint, Ptr{Cint}), ppjvm, 1, pnum)
    jvm = unsafe_load(ppjvm[])
    global jvmfunc[] = unsafe_load(jvm.JNIInvokeInterface_)
    ccall(jvmfunc[].GetEnv, Cint, (Ptr{Nothing}, Ptr{Ptr{JNIEnv}}, Cint), ppjvm[], ppenv, JNI.JNI_VERSION_1_8)
    load_jni(ppenv[])
end

function load_libjvm(libpath::AbstractString)
    libjvm = Libdl.dlopen(libpath)
    @debug("Loaded $libpath")
    libjvm
end

function load_libjvm(libpaths::NTuple{N,String}) where N
    Libdl.dlopen.(libpaths)
    load_libjvm(libpaths[end])
end

function destroy()
    if !is_env_loaded()
        throw(JNIError("Called destroy without initialising Java VM"))
    end
    res = ccall(jvmfunc[].DestroyJavaVM, Cint, (Ptr{Nothing},), ppjvm[])
    res < 0 && throw(JavaCallError("Unable to destroy Java VM"))
    ppenv[] = C_NULL
    ppjvm[] = C_NULL
    nothing
end

# === Below Generated by make_jni2.jl ===

GetVersion(penv=ppenv[]) =
  ccall(jniref[].GetVersion, jint, (Ptr{JNIEnv},), penv)

DefineClass(name::AnyString, loader::jobject_arg, buf::Array{jbyte,1}, len::Integer, penv=ppenv[]) =
  ccall(jniref[].DefineClass, jclass, (Ptr{JNIEnv}, Cstring, jobject, Ptr{jbyte}, jsize,), penv, name, loader, buf, len)

FindClass(name::AnyString, penv=ppenv[]) =
  ccall(jniref[].FindClass, jclass, (Ptr{JNIEnv}, Cstring,), penv, name)

FromReflectedMethod(method::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].FromReflectedMethod, jmethodID, (Ptr{JNIEnv}, jobject,), penv, method)

FromReflectedField(field::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].FromReflectedField, jfieldID, (Ptr{JNIEnv}, jobject,), penv, field)

ToReflectedMethod(cls::jclass, methodID::jmethodID, isStatic::jboolean, penv=ppenv[]) =
  ccall(jniref[].ToReflectedMethod, jobject, (Ptr{JNIEnv}, jclass, jmethodID, jboolean,), penv, cls, methodID, isStatic)

GetSuperclass(sub::jclass, penv=ppenv[]) =
  ccall(jniref[].GetSuperclass, jclass, (Ptr{JNIEnv}, jclass,), penv, sub)

IsAssignableFrom(sub::jclass, sup::jclass, penv=ppenv[]) =
  ccall(jniref[].IsAssignableFrom, jboolean, (Ptr{JNIEnv}, jclass, jclass,), penv, sub, sup)

ToReflectedField(cls::jclass, fieldID::jfieldID, isStatic::jboolean, penv=ppenv[]) =
  ccall(jniref[].ToReflectedField, jobject, (Ptr{JNIEnv}, jclass, jfieldID, jboolean,), penv, cls, fieldID, isStatic)

Throw(obj::jthrowable, penv=ppenv[]) =
  ccall(jniref[].Throw, jint, (Ptr{JNIEnv}, jthrowable,), penv, obj)

ThrowNew(clazz::jclass, msg::AnyString, penv=ppenv[]) =
  ccall(jniref[].ThrowNew, jint, (Ptr{JNIEnv}, jclass, Cstring,), penv, clazz, msg)

ExceptionOccurred(penv=ppenv[]) =
  ccall(jniref[].ExceptionOccurred, jthrowable, (Ptr{JNIEnv},), penv)

ExceptionDescribe(penv=ppenv[]) =
  ccall(jniref[].ExceptionDescribe, Nothing, (Ptr{JNIEnv},), penv)

ExceptionClear(penv=ppenv[]) =
  ccall(jniref[].ExceptionClear, Nothing, (Ptr{JNIEnv},), penv)

FatalError(msg::AnyString, penv=ppenv[]) =
  ccall(jniref[].FatalError, Nothing, (Ptr{JNIEnv}, Cstring,), penv, msg)

PushLocalFrame(capacity::jint, penv=ppenv[]) =
  ccall(jniref[].PushLocalFrame, jint, (Ptr{JNIEnv}, jint,), penv, capacity)

PopLocalFrame(result::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].PopLocalFrame, jobject, (Ptr{JNIEnv}, jobject,), penv, result)

NewGlobalRef(lobj::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].NewGlobalRef, jobject, (Ptr{JNIEnv}, jobject,), penv, lobj)

DeleteGlobalRef(gref::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].DeleteGlobalRef, Nothing, (Ptr{JNIEnv}, jobject,), penv, gref)

DeleteLocalRef(obj::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].DeleteLocalRef, Nothing, (Ptr{JNIEnv}, jobject,), penv, obj)

IsSameObject(obj1::jobject_arg, obj2::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].IsSameObject, jboolean, (Ptr{JNIEnv}, jobject, jobject,), penv, obj1, obj2)

NewLocalRef(ref::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].NewLocalRef, jobject, (Ptr{JNIEnv}, jobject,), penv, ref)

EnsureLocalCapacity(capacity::jint, penv=ppenv[]) =
  ccall(jniref[].EnsureLocalCapacity, jint, (Ptr{JNIEnv}, jint,), penv, capacity)

AllocObject(clazz::jclass, penv=ppenv[]) =
  ccall(jniref[].AllocObject, jobject, (Ptr{JNIEnv}, jclass,), penv, clazz)

NewObjectA(clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].NewObjectA, jobject, (Ptr{JNIEnv}, jclass, jmethodID, Ptr{jvalue},), penv, clazz, methodID, args)

GetObjectClass(obj::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].GetObjectClass, jclass, (Ptr{JNIEnv}, jobject,), penv, obj)

IsInstanceOf(obj::jobject_arg, clazz::jclass, penv=ppenv[]) =
  ccall(jniref[].IsInstanceOf, jboolean, (Ptr{JNIEnv}, jobject, jclass,), penv, obj, clazz)

GetMethodID(clazz::jclass, name::AnyString, sig::AnyString, penv=ppenv[]) =
  ccall(jniref[].GetMethodID, jmethodID, (Ptr{JNIEnv}, jclass, Cstring, Cstring,), penv, clazz, name, sig)

CallObjectMethodA(obj::jobject_arg, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallObjectMethodA, jobject, (Ptr{JNIEnv}, jobject, jmethodID, Ptr{jvalue},), penv, obj, methodID, args)

CallBooleanMethodA(obj::jobject_arg, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallBooleanMethodA, jboolean, (Ptr{JNIEnv}, jobject, jmethodID, Ptr{jvalue},), penv, obj, methodID, args)

CallByteMethodA(obj::jobject_arg, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallByteMethodA, jbyte, (Ptr{JNIEnv}, jobject, jmethodID, Ptr{jvalue},), penv, obj, methodID, args)

CallCharMethodA(obj::jobject_arg, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallCharMethodA, jchar, (Ptr{JNIEnv}, jobject, jmethodID, Ptr{jvalue},), penv, obj, methodID, args)

CallShortMethodA(obj::jobject_arg, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallShortMethodA, jshort, (Ptr{JNIEnv}, jobject, jmethodID, Ptr{jvalue},), penv, obj, methodID, args)

CallIntMethodA(obj::jobject_arg, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallIntMethodA, jint, (Ptr{JNIEnv}, jobject, jmethodID, Ptr{jvalue},), penv, obj, methodID, args)

CallLongMethodA(obj::jobject_arg, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallLongMethodA, jlong, (Ptr{JNIEnv}, jobject, jmethodID, Ptr{jvalue},), penv, obj, methodID, args)

CallFloatMethodA(obj::jobject_arg, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallFloatMethodA, jfloat, (Ptr{JNIEnv}, jobject, jmethodID, Ptr{jvalue},), penv, obj, methodID, args)

CallDoubleMethodA(obj::jobject_arg, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallDoubleMethodA, jdouble, (Ptr{JNIEnv}, jobject, jmethodID, Ptr{jvalue},), penv, obj, methodID, args)

CallVoidMethodA(obj::jobject_arg, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallVoidMethodA, Nothing, (Ptr{JNIEnv}, jobject, jmethodID, Ptr{jvalue},), penv, obj, methodID, args)

CallNonvirtualObjectMethodA(obj::jobject_arg, clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallNonvirtualObjectMethodA, jobject, (Ptr{JNIEnv}, jobject, jclass, jmethodID, Ptr{jvalue},), penv, obj, clazz, methodID, args)

CallNonvirtualBooleanMethodA(obj::jobject_arg, clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallNonvirtualBooleanMethodA, jboolean, (Ptr{JNIEnv}, jobject, jclass, jmethodID, Ptr{jvalue},), penv, obj, clazz, methodID, args)

CallNonvirtualByteMethodA(obj::jobject_arg, clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallNonvirtualByteMethodA, jbyte, (Ptr{JNIEnv}, jobject, jclass, jmethodID, Ptr{jvalue},), penv, obj, clazz, methodID, args)

CallNonvirtualCharMethodA(obj::jobject_arg, clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallNonvirtualCharMethodA, jchar, (Ptr{JNIEnv}, jobject, jclass, jmethodID, Ptr{jvalue},), penv, obj, clazz, methodID, args)

CallNonvirtualShortMethodA(obj::jobject_arg, clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallNonvirtualShortMethodA, jshort, (Ptr{JNIEnv}, jobject, jclass, jmethodID, Ptr{jvalue},), penv, obj, clazz, methodID, args)

CallNonvirtualIntMethodA(obj::jobject_arg, clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallNonvirtualIntMethodA, jint, (Ptr{JNIEnv}, jobject, jclass, jmethodID, Ptr{jvalue},), penv, obj, clazz, methodID, args)

CallNonvirtualLongMethodA(obj::jobject_arg, clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallNonvirtualLongMethodA, jlong, (Ptr{JNIEnv}, jobject, jclass, jmethodID, Ptr{jvalue},), penv, obj, clazz, methodID, args)

CallNonvirtualFloatMethodA(obj::jobject_arg, clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallNonvirtualFloatMethodA, jfloat, (Ptr{JNIEnv}, jobject, jclass, jmethodID, Ptr{jvalue},), penv, obj, clazz, methodID, args)

CallNonvirtualDoubleMethodA(obj::jobject_arg, clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallNonvirtualDoubleMethodA, jdouble, (Ptr{JNIEnv}, jobject, jclass, jmethodID, Ptr{jvalue},), penv, obj, clazz, methodID, args)

CallNonvirtualVoidMethodA(obj::jobject_arg, clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallNonvirtualVoidMethodA, Nothing, (Ptr{JNIEnv}, jobject, jclass, jmethodID, Ptr{jvalue},), penv, obj, clazz, methodID, args)

GetFieldID(clazz::jclass, name::AnyString, sig::AnyString, penv=ppenv[]) =
  ccall(jniref[].GetFieldID, jfieldID, (Ptr{JNIEnv}, jclass, Cstring, Cstring,), penv, clazz, name, sig)

GetObjectField(obj::jobject_arg, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetObjectField, jobject, (Ptr{JNIEnv}, jobject, jfieldID,), penv, obj, fieldID)

GetBooleanField(obj::jobject_arg, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetBooleanField, jboolean, (Ptr{JNIEnv}, jobject, jfieldID,), penv, obj, fieldID)

GetByteField(obj::jobject_arg, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetByteField, jbyte, (Ptr{JNIEnv}, jobject, jfieldID,), penv, obj, fieldID)

GetCharField(obj::jobject_arg, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetCharField, jchar, (Ptr{JNIEnv}, jobject, jfieldID,), penv, obj, fieldID)

GetShortField(obj::jobject_arg, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetShortField, jshort, (Ptr{JNIEnv}, jobject, jfieldID,), penv, obj, fieldID)

GetIntField(obj::jobject_arg, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetIntField, jint, (Ptr{JNIEnv}, jobject, jfieldID,), penv, obj, fieldID)

GetLongField(obj::jobject_arg, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetLongField, jlong, (Ptr{JNIEnv}, jobject, jfieldID,), penv, obj, fieldID)

GetFloatField(obj::jobject_arg, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetFloatField, jfloat, (Ptr{JNIEnv}, jobject, jfieldID,), penv, obj, fieldID)

GetDoubleField(obj::jobject_arg, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetDoubleField, jdouble, (Ptr{JNIEnv}, jobject, jfieldID,), penv, obj, fieldID)

SetObjectField(obj::jobject_arg, fieldID::jfieldID, val::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].SetObjectField, Nothing, (Ptr{JNIEnv}, jobject, jfieldID, jobject,), penv, obj, fieldID, val)

SetBooleanField(obj::jobject_arg, fieldID::jfieldID, val::jboolean, penv=ppenv[]) =
  ccall(jniref[].SetBooleanField, Nothing, (Ptr{JNIEnv}, jobject, jfieldID, jboolean,), penv, obj, fieldID, val)

SetByteField(obj::jobject_arg, fieldID::jfieldID, val::jbyte, penv=ppenv[]) =
  ccall(jniref[].SetByteField, Nothing, (Ptr{JNIEnv}, jobject, jfieldID, jbyte,), penv, obj, fieldID, val)

SetCharField(obj::jobject_arg, fieldID::jfieldID, val::jchar, penv=ppenv[]) =
  ccall(jniref[].SetCharField, Nothing, (Ptr{JNIEnv}, jobject, jfieldID, jchar,), penv, obj, fieldID, val)

SetShortField(obj::jobject_arg, fieldID::jfieldID, val::jshort, penv=ppenv[]) =
  ccall(jniref[].SetShortField, Nothing, (Ptr{JNIEnv}, jobject, jfieldID, jshort,), penv, obj, fieldID, val)

SetIntField(obj::jobject_arg, fieldID::jfieldID, val::jint, penv=ppenv[]) =
  ccall(jniref[].SetIntField, Nothing, (Ptr{JNIEnv}, jobject, jfieldID, jint,), penv, obj, fieldID, val)

SetLongField(obj::jobject_arg, fieldID::jfieldID, val::jlong, penv=ppenv[]) =
  ccall(jniref[].SetLongField, Nothing, (Ptr{JNIEnv}, jobject, jfieldID, jlong,), penv, obj, fieldID, val)

SetFloatField(obj::jobject_arg, fieldID::jfieldID, val::jfloat, penv=ppenv[]) =
  ccall(jniref[].SetFloatField, Nothing, (Ptr{JNIEnv}, jobject, jfieldID, jfloat,), penv, obj, fieldID, val)

SetDoubleField(obj::jobject_arg, fieldID::jfieldID, val::jdouble, penv=ppenv[]) =
  ccall(jniref[].SetDoubleField, Nothing, (Ptr{JNIEnv}, jobject, jfieldID, jdouble,), penv, obj, fieldID, val)

GetStaticMethodID(clazz::jclass, name::AnyString, sig::AnyString, penv=ppenv[]) =
  ccall(jniref[].GetStaticMethodID, jmethodID, (Ptr{JNIEnv}, jclass, Cstring, Cstring,), penv, clazz, name, sig)

CallStaticObjectMethodA(clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallStaticObjectMethodA, jobject, (Ptr{JNIEnv}, jclass, jmethodID, Ptr{jvalue},), penv, clazz, methodID, args)

CallStaticBooleanMethodA(clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallStaticBooleanMethodA, jboolean, (Ptr{JNIEnv}, jclass, jmethodID, Ptr{jvalue},), penv, clazz, methodID, args)

CallStaticByteMethodA(clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallStaticByteMethodA, jbyte, (Ptr{JNIEnv}, jclass, jmethodID, Ptr{jvalue},), penv, clazz, methodID, args)

CallStaticCharMethodA(clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallStaticCharMethodA, jchar, (Ptr{JNIEnv}, jclass, jmethodID, Ptr{jvalue},), penv, clazz, methodID, args)

CallStaticShortMethodA(clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallStaticShortMethodA, jshort, (Ptr{JNIEnv}, jclass, jmethodID, Ptr{jvalue},), penv, clazz, methodID, args)

CallStaticIntMethodA(clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallStaticIntMethodA, jint, (Ptr{JNIEnv}, jclass, jmethodID, Ptr{jvalue},), penv, clazz, methodID, args)

CallStaticLongMethodA(clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallStaticLongMethodA, jlong, (Ptr{JNIEnv}, jclass, jmethodID, Ptr{jvalue},), penv, clazz, methodID, args)

CallStaticFloatMethodA(clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallStaticFloatMethodA, jfloat, (Ptr{JNIEnv}, jclass, jmethodID, Ptr{jvalue},), penv, clazz, methodID, args)

CallStaticDoubleMethodA(clazz::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallStaticDoubleMethodA, jdouble, (Ptr{JNIEnv}, jclass, jmethodID, Ptr{jvalue},), penv, clazz, methodID, args)

CallStaticVoidMethodA(cls::jclass, methodID::jmethodID, args::Array{jvalue,1}, penv=ppenv[]) =
  ccall(jniref[].CallStaticVoidMethodA, Nothing, (Ptr{JNIEnv}, jclass, jmethodID, Ptr{jvalue},), penv, cls, methodID, args)

GetStaticFieldID(clazz::jclass, name::AnyString, sig::AnyString, penv=ppenv[]) =
  ccall(jniref[].GetStaticFieldID, jfieldID, (Ptr{JNIEnv}, jclass, Cstring, Cstring,), penv, clazz, name, sig)

GetStaticObjectField(clazz::jclass, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetStaticObjectField, jobject, (Ptr{JNIEnv}, jclass, jfieldID,), penv, clazz, fieldID)

GetStaticBooleanField(clazz::jclass, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetStaticBooleanField, jboolean, (Ptr{JNIEnv}, jclass, jfieldID,), penv, clazz, fieldID)

GetStaticByteField(clazz::jclass, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetStaticByteField, jbyte, (Ptr{JNIEnv}, jclass, jfieldID,), penv, clazz, fieldID)

GetStaticCharField(clazz::jclass, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetStaticCharField, jchar, (Ptr{JNIEnv}, jclass, jfieldID,), penv, clazz, fieldID)

GetStaticShortField(clazz::jclass, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetStaticShortField, jshort, (Ptr{JNIEnv}, jclass, jfieldID,), penv, clazz, fieldID)

GetStaticIntField(clazz::jclass, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetStaticIntField, jint, (Ptr{JNIEnv}, jclass, jfieldID,), penv, clazz, fieldID)

GetStaticLongField(clazz::jclass, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetStaticLongField, jlong, (Ptr{JNIEnv}, jclass, jfieldID,), penv, clazz, fieldID)

GetStaticFloatField(clazz::jclass, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetStaticFloatField, jfloat, (Ptr{JNIEnv}, jclass, jfieldID,), penv, clazz, fieldID)

GetStaticDoubleField(clazz::jclass, fieldID::jfieldID, penv=ppenv[]) =
  ccall(jniref[].GetStaticDoubleField, jdouble, (Ptr{JNIEnv}, jclass, jfieldID,), penv, clazz, fieldID)

SetStaticObjectField(clazz::jclass, fieldID::jfieldID, value::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].SetStaticObjectField, Nothing, (Ptr{JNIEnv}, jclass, jfieldID, jobject,), penv, clazz, fieldID, value)

SetStaticBooleanField(clazz::jclass, fieldID::jfieldID, value::jboolean, penv=ppenv[]) =
  ccall(jniref[].SetStaticBooleanField, Nothing, (Ptr{JNIEnv}, jclass, jfieldID, jboolean,), penv, clazz, fieldID, value)

SetStaticByteField(clazz::jclass, fieldID::jfieldID, value::jbyte, penv=ppenv[]) =
  ccall(jniref[].SetStaticByteField, Nothing, (Ptr{JNIEnv}, jclass, jfieldID, jbyte,), penv, clazz, fieldID, value)

SetStaticCharField(clazz::jclass, fieldID::jfieldID, value::jchar, penv=ppenv[]) =
  ccall(jniref[].SetStaticCharField, Nothing, (Ptr{JNIEnv}, jclass, jfieldID, jchar,), penv, clazz, fieldID, value)

SetStaticShortField(clazz::jclass, fieldID::jfieldID, value::jshort, penv=ppenv[]) =
  ccall(jniref[].SetStaticShortField, Nothing, (Ptr{JNIEnv}, jclass, jfieldID, jshort,), penv, clazz, fieldID, value)

SetStaticIntField(clazz::jclass, fieldID::jfieldID, value::jint, penv=ppenv[]) =
  ccall(jniref[].SetStaticIntField, Nothing, (Ptr{JNIEnv}, jclass, jfieldID, jint,), penv, clazz, fieldID, value)

SetStaticLongField(clazz::jclass, fieldID::jfieldID, value::jlong, penv=ppenv[]) =
  ccall(jniref[].SetStaticLongField, Nothing, (Ptr{JNIEnv}, jclass, jfieldID, jlong,), penv, clazz, fieldID, value)

SetStaticFloatField(clazz::jclass, fieldID::jfieldID, value::jfloat, penv=ppenv[]) =
  ccall(jniref[].SetStaticFloatField, Nothing, (Ptr{JNIEnv}, jclass, jfieldID, jfloat,), penv, clazz, fieldID, value)

SetStaticDoubleField(clazz::jclass, fieldID::jfieldID, value::jdouble, penv=ppenv[]) =
  ccall(jniref[].SetStaticDoubleField, Nothing, (Ptr{JNIEnv}, jclass, jfieldID, jdouble,), penv, clazz, fieldID, value)

NewString(unicode::Array{jchar,1}, len::Integer, penv=ppenv[]) =
  ccall(jniref[].NewString, jstring, (Ptr{JNIEnv}, Ptr{jchar}, jsize,), penv, unicode, len)

GetStringLength(str::jstring, penv=ppenv[]) =
  ccall(jniref[].GetStringLength, jsize, (Ptr{JNIEnv}, jstring,), penv, str)

GetStringChars(str::jstring, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetStringChars, Ptr{jchar}, (Ptr{JNIEnv}, jstring, Ptr{jboolean},), penv, str, isCopy)

ReleaseStringChars(str::jstring, chars::Array{jchar,1}, penv=ppenv[]) =
  ccall(jniref[].ReleaseStringChars, Nothing, (Ptr{JNIEnv}, jstring, Ptr{jchar},), penv, str, chars)

NewStringUTF(utf::AnyString, penv=ppenv[]) =
  ccall(jniref[].NewStringUTF, jstring, (Ptr{JNIEnv}, Cstring,), penv, utf)

GetStringUTFLength(str::jstring, penv=ppenv[]) =
  ccall(jniref[].GetStringUTFLength, jsize, (Ptr{JNIEnv}, jstring,), penv, str)

GetStringUTFChars(str::jstring, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetStringUTFChars, Cstring, (Ptr{JNIEnv}, jstring, Ptr{jboolean},), penv, str, isCopy)

## Prior to this module we used UInt8 instead of Cstring, must match return value of above
#ReleaseStringUTFChars(str::jstring, chars::Ptr{UInt8}, penv=ppenv[]) =
#  ccall(jniref[].ReleaseStringUTFChars, Nothing, (Ptr{JNIEnv}, jstring, Ptr{UInt8},), penv, str, chars)
ReleaseStringUTFChars(str::jstring, chars::AnyString, penv=ppenv[]) =
  ccall(jniref[].ReleaseStringUTFChars, Nothing, (Ptr{JNIEnv}, jstring, Cstring,), penv, str, chars)

GetArrayLength(array::jarray, penv=ppenv[]) =
  ccall(jniref[].GetArrayLength, jsize, (Ptr{JNIEnv}, jarray,), penv, array)

NewObjectArray(len::Integer, clazz::jclass, init::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].NewObjectArray, jobjectArray, (Ptr{JNIEnv}, jsize, jclass, jobject,), penv, len, clazz, init)

GetObjectArrayElement(array::jobjectArray_arg, index::Integer, penv=ppenv[]) =
  ccall(jniref[].GetObjectArrayElement, jobject, (Ptr{JNIEnv}, jobjectArray, jsize,), penv, array, index)

SetObjectArrayElement(array::jobjectArray_arg, index::Integer, val::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].SetObjectArrayElement, Nothing, (Ptr{JNIEnv}, jobjectArray, jsize, jobject,), penv, array, index, val)

NewBooleanArray(len::Integer, penv=ppenv[]) =
  ccall(jniref[].NewBooleanArray, jbooleanArray, (Ptr{JNIEnv}, jsize,), penv, len)

NewByteArray(len::Integer, penv=ppenv[]) =
  ccall(jniref[].NewByteArray, jbyteArray, (Ptr{JNIEnv}, jsize,), penv, len)

NewCharArray(len::Integer, penv=ppenv[]) =
  ccall(jniref[].NewCharArray, jcharArray, (Ptr{JNIEnv}, jsize,), penv, len)

NewShortArray(len::Integer, penv=ppenv[]) =
  ccall(jniref[].NewShortArray, jshortArray, (Ptr{JNIEnv}, jsize,), penv, len)

NewIntArray(len::Integer, penv=ppenv[]) =
  ccall(jniref[].NewIntArray, jintArray, (Ptr{JNIEnv}, jsize,), penv, len)

NewLongArray(len::Integer, penv=ppenv[]) =
  ccall(jniref[].NewLongArray, jlongArray, (Ptr{JNIEnv}, jsize,), penv, len)

NewFloatArray(len::Integer, penv=ppenv[]) =
  ccall(jniref[].NewFloatArray, jfloatArray, (Ptr{JNIEnv}, jsize,), penv, len)

NewDoubleArray(len::Integer, penv=ppenv[]) =
  ccall(jniref[].NewDoubleArray, jdoubleArray, (Ptr{JNIEnv}, jsize,), penv, len)

GetBooleanArrayElements(array::jbooleanArray, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetBooleanArrayElements, Ptr{jboolean}, (Ptr{JNIEnv}, jbooleanArray, Ptr{jboolean},), penv, array, isCopy)

GetByteArrayElements(array::jbyteArray, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetByteArrayElements, Ptr{jbyte}, (Ptr{JNIEnv}, jbyteArray, Ptr{jboolean},), penv, array, isCopy)

GetCharArrayElements(array::jcharArray, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetCharArrayElements, Ptr{jchar}, (Ptr{JNIEnv}, jcharArray, Ptr{jboolean},), penv, array, isCopy)

GetShortArrayElements(array::jshortArray, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetShortArrayElements, Ptr{jshort}, (Ptr{JNIEnv}, jshortArray, Ptr{jboolean},), penv, array, isCopy)

GetIntArrayElements(array::jintArray, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetIntArrayElements, Ptr{jint}, (Ptr{JNIEnv}, jintArray, Ptr{jboolean},), penv, array, isCopy)

GetLongArrayElements(array::jlongArray, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetLongArrayElements, Ptr{jlong}, (Ptr{JNIEnv}, jlongArray, Ptr{jboolean},), penv, array, isCopy)

GetFloatArrayElements(array::jfloatArray, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetFloatArrayElements, Ptr{jfloat}, (Ptr{JNIEnv}, jfloatArray, Ptr{jboolean},), penv, array, isCopy)

GetDoubleArrayElements(array::jdoubleArray, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetDoubleArrayElements, Ptr{jdouble}, (Ptr{JNIEnv}, jdoubleArray, Ptr{jboolean},), penv, array, isCopy)

ReleaseBooleanArrayElements(array::jbooleanArray, elems::Ptr{jboolean}, mode::jint, penv=ppenv[]) =
  ccall(jniref[].ReleaseBooleanArrayElements, Nothing, (Ptr{JNIEnv}, jbooleanArray, Ptr{jboolean}, jint,), penv, array, elems, mode)

ReleaseByteArrayElements(array::jbyteArray, elems::Ptr{jbyte}, mode::jint, penv=ppenv[]) =
  ccall(jniref[].ReleaseByteArrayElements, Nothing, (Ptr{JNIEnv}, jbyteArray, Ptr{jbyte}, jint,), penv, array, elems, mode)

ReleaseCharArrayElements(array::jcharArray, elems::Ptr{jchar}, mode::jint, penv=ppenv[]) =
  ccall(jniref[].ReleaseCharArrayElements, Nothing, (Ptr{JNIEnv}, jcharArray, Ptr{jchar}, jint,), penv, array, elems, mode)

ReleaseShortArrayElements(array::jshortArray, elems::Ptr{jshort}, mode::jint, penv=ppenv[]) =
  ccall(jniref[].ReleaseShortArrayElements, Nothing, (Ptr{JNIEnv}, jshortArray, Ptr{jshort}, jint,), penv, array, elems, mode)

ReleaseIntArrayElements(array::jintArray, elems::Ptr{jint}, mode::jint, penv=ppenv[]) =
  ccall(jniref[].ReleaseIntArrayElements, Nothing, (Ptr{JNIEnv}, jintArray, Ptr{jint}, jint,), penv, array, elems, mode)

ReleaseLongArrayElements(array::jlongArray, elems::Ptr{jlong}, mode::jint, penv=ppenv[]) =
  ccall(jniref[].ReleaseLongArrayElements, Nothing, (Ptr{JNIEnv}, jlongArray, Ptr{jlong}, jint,), penv, array, elems, mode)

ReleaseFloatArrayElements(array::jfloatArray, elems::Ptr{jfloat}, mode::jint, penv=ppenv[]) =
  ccall(jniref[].ReleaseFloatArrayElements, Nothing, (Ptr{JNIEnv}, jfloatArray, Ptr{jfloat}, jint,), penv, array, elems, mode)

ReleaseDoubleArrayElements(array::jdoubleArray, elems::Ptr{jdouble}, mode::jint, penv=ppenv[]) =
  ccall(jniref[].ReleaseDoubleArrayElements, Nothing, (Ptr{JNIEnv}, jdoubleArray, Ptr{jdouble}, jint,), penv, array, elems, mode)

GetBooleanArrayRegion(array::jbooleanArray, start::Integer, l::Integer, buf::Array{jboolean,1}, penv=ppenv[]) =
  ccall(jniref[].GetBooleanArrayRegion, Nothing, (Ptr{JNIEnv}, jbooleanArray, jsize, jsize, Ptr{jboolean},), penv, array, start, l, buf)

GetByteArrayRegion(array::jbyteArray, start::Integer, len::Integer, buf::Array{jbyte,1}, penv=ppenv[]) =
  ccall(jniref[].GetByteArrayRegion, Nothing, (Ptr{JNIEnv}, jbyteArray, jsize, jsize, Ptr{jbyte},), penv, array, start, len, buf)

GetCharArrayRegion(array::jcharArray, start::Integer, len::Integer, buf::Array{jchar,1}, penv=ppenv[]) =
  ccall(jniref[].GetCharArrayRegion, Nothing, (Ptr{JNIEnv}, jcharArray, jsize, jsize, Ptr{jchar},), penv, array, start, len, buf)

GetShortArrayRegion(array::jshortArray, start::Integer, len::Integer, buf::Array{jshort,1}, penv=ppenv[]) =
  ccall(jniref[].GetShortArrayRegion, Nothing, (Ptr{JNIEnv}, jshortArray, jsize, jsize, Ptr{jshort},), penv, array, start, len, buf)

GetIntArrayRegion(array::jintArray, start::Integer, len::Integer, buf::Array{jint,1}, penv=ppenv[]) =
  ccall(jniref[].GetIntArrayRegion, Nothing, (Ptr{JNIEnv}, jintArray, jsize, jsize, Ptr{jint},), penv, array, start, len, buf)

GetLongArrayRegion(array::jlongArray, start::Integer, len::Integer, buf::Array{jlong,1}, penv=ppenv[]) =
  ccall(jniref[].GetLongArrayRegion, Nothing, (Ptr{JNIEnv}, jlongArray, jsize, jsize, Ptr{jlong},), penv, array, start, len, buf)

GetFloatArrayRegion(array::jfloatArray, start::Integer, len::Integer, buf::Array{jfloat,1}, penv=ppenv[]) =
  ccall(jniref[].GetFloatArrayRegion, Nothing, (Ptr{JNIEnv}, jfloatArray, jsize, jsize, Ptr{jfloat},), penv, array, start, len, buf)

GetDoubleArrayRegion(array::jdoubleArray, start::Integer, len::Integer, buf::Array{jdouble,1}, penv=ppenv[]) =
  ccall(jniref[].GetDoubleArrayRegion, Nothing, (Ptr{JNIEnv}, jdoubleArray, jsize, jsize, Ptr{jdouble},), penv, array, start, len, buf)

SetBooleanArrayRegion(array::jbooleanArray, start::Integer, l::Integer, buf::Array{jboolean,1}, penv=ppenv[]) =
  ccall(jniref[].SetBooleanArrayRegion, Nothing, (Ptr{JNIEnv}, jbooleanArray, jsize, jsize, Ptr{jboolean},), penv, array, start, l, buf)

SetByteArrayRegion(array::jbyteArray, start::Integer, len::Integer, buf::Array{jbyte,1}, penv=ppenv[]) =
  ccall(jniref[].SetByteArrayRegion, Nothing, (Ptr{JNIEnv}, jbyteArray, jsize, jsize, Ptr{jbyte},), penv, array, start, len, buf)

SetCharArrayRegion(array::jcharArray, start::Integer, len::Integer, buf::Array{jchar,1}, penv=ppenv[]) =
  ccall(jniref[].SetCharArrayRegion, Nothing, (Ptr{JNIEnv}, jcharArray, jsize, jsize, Ptr{jchar},), penv, array, start, len, buf)

SetShortArrayRegion(array::jshortArray, start::Integer, len::Integer, buf::Array{jshort,1}, penv=ppenv[]) =
  ccall(jniref[].SetShortArrayRegion, Nothing, (Ptr{JNIEnv}, jshortArray, jsize, jsize, Ptr{jshort},), penv, array, start, len, buf)

SetIntArrayRegion(array::jintArray, start::Integer, len::Integer, buf::Array{jint,1}, penv=ppenv[]) =
  ccall(jniref[].SetIntArrayRegion, Nothing, (Ptr{JNIEnv}, jintArray, jsize, jsize, Ptr{jint},), penv, array, start, len, buf)

SetLongArrayRegion(array::jlongArray, start::Integer, len::Integer, buf::Array{jlong,1}, penv=ppenv[]) =
  ccall(jniref[].SetLongArrayRegion, Nothing, (Ptr{JNIEnv}, jlongArray, jsize, jsize, Ptr{jlong},), penv, array, start, len, buf)

SetFloatArrayRegion(array::jfloatArray, start::Integer, len::Integer, buf::Array{jfloat,1}, penv=ppenv[]) =
  ccall(jniref[].SetFloatArrayRegion, Nothing, (Ptr{JNIEnv}, jfloatArray, jsize, jsize, Ptr{jfloat},), penv, array, start, len, buf)

SetDoubleArrayRegion(array::jdoubleArray, start::Integer, len::Integer, buf::Array{jdouble,1}, penv=ppenv[]) =
  ccall(jniref[].SetDoubleArrayRegion, Nothing, (Ptr{JNIEnv}, jdoubleArray, jsize, jsize, Ptr{jdouble},), penv, array, start, len, buf)

RegisterNatives(clazz::jclass, methods::Array{JNINativeMethod,1}, nMethods::jint, penv=ppenv[]) =
  ccall(jniref[].RegisterNatives, jint, (Ptr{JNIEnv}, jclass, Ptr{JNINativeMethod}, jint,), penv, clazz, methods, nMethods)

UnregisterNatives(clazz::jclass, penv=ppenv[]) =
  ccall(jniref[].UnregisterNatives, jint, (Ptr{JNIEnv}, jclass,), penv, clazz)

MonitorEnter(obj::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].MonitorEnter, jint, (Ptr{JNIEnv}, jobject,), penv, obj)

MonitorExit(obj::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].MonitorExit, jint, (Ptr{JNIEnv}, jobject,), penv, obj)

GetJavaVM(vm::Array{JavaVM,1}, penv=ppenv[]) =
  ccall(jniref[].GetJavaVM, jint, (Ptr{JNIEnv}, Array{JavaVM,1},), penv, vm)

GetStringRegion(str::jstring, start::Integer, len::Integer, buf::Array{jchar,1}, penv=ppenv[]) =
  ccall(jniref[].GetStringRegion, Nothing, (Ptr{JNIEnv}, jstring, jsize, jsize, Ptr{jchar},), penv, str, start, len, buf)

GetStringUTFRegion(str::jstring, start::Integer, len::Integer, buf::AnyString, penv=ppenv[]) =
  ccall(jniref[].GetStringUTFRegion, Nothing, (Ptr{JNIEnv}, jstring, jsize, jsize, Cstring,), penv, str, start, len, buf)

GetPrimitiveArrayCritical(array::jarray, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetPrimitiveArrayCritical, Ptr{Nothing}, (Ptr{JNIEnv}, jarray, Ptr{jboolean},), penv, array, isCopy)

ReleasePrimitiveArrayCritical(array::jarray, carray::Ptr{Nothing}, mode::jint, penv=ppenv[]) =
  ccall(jniref[].ReleasePrimitiveArrayCritical, Nothing, (Ptr{JNIEnv}, jarray, Ptr{Nothing}, jint,), penv, array, carray, mode)

GetStringCritical(string::jstring, isCopy::PtrIsCopy, penv=ppenv[]) =
  ccall(jniref[].GetStringCritical, Ptr{jchar}, (Ptr{JNIEnv}, jstring, Ptr{jboolean},), penv, string, isCopy)

ReleaseStringCritical(string::jstring, cstring::Array{jchar,1}, penv=ppenv[]) =
  ccall(jniref[].ReleaseStringCritical, Nothing, (Ptr{JNIEnv}, jstring, Ptr{jchar},), penv, string, cstring)

NewWeakGlobalRef(obj::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].NewWeakGlobalRef, jweak, (Ptr{JNIEnv}, jobject,), penv, obj)

DeleteWeakGlobalRef(ref::jweak, penv=ppenv[]) =
  ccall(jniref[].DeleteWeakGlobalRef, Nothing, (Ptr{JNIEnv}, jweak,), penv, ref)

ExceptionCheck(penv=ppenv[]) =
  ccall(jniref[].ExceptionCheck, jboolean, (Ptr{JNIEnv},), penv)

NewDirectByteBuffer(address::Ptr{Nothing}, capacity::jlong, penv=ppenv[]) =
  ccall(jniref[].NewDirectByteBuffer, jobject, (Ptr{JNIEnv}, Ptr{Nothing}, jlong,), penv, address, capacity)

GetDirectBufferAddress(buf::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].GetDirectBufferAddress, Ptr{Nothing}, (Ptr{JNIEnv}, jobject,), penv, buf)

GetDirectBufferCapacity(buf::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].GetDirectBufferCapacity, jlong, (Ptr{JNIEnv}, jobject,), penv, buf)

GetObjectRefType(obj::jobject_arg, penv=ppenv[]) =
  ccall(jniref[].GetObjectRefType, jobjectRefType, (Ptr{JNIEnv}, jobject,), penv, obj)

# === Above Generated by make_jni2.jl ===

end


text:
# This file is a part of Julia. License is MIT: https://julialang.org/license

print(xs...)   = print(stdout::IO, xs...)
println(xs...) = println(stdout::IO, xs...)
println(io::IO) = print(io, '\n')

struct DevNullStream <: IO end
const devnull = DevNullStream()
isreadable(::DevNullStream) = false
iswritable(::DevNullStream) = true
isopen(::DevNullStream) = true
read(::DevNullStream, ::Type{UInt8}) = throw(EOFError())
write(::DevNullStream, ::UInt8) = 1
unsafe_write(::DevNullStream, ::Ptr{UInt8}, n::UInt)::Int = n
close(::DevNullStream) = nothing
flush(::DevNullStream) = nothing
wait_connected(::DevNullStream) = nothing
wait_readnb(::DevNullStream) = wait()
wait_readbyte(::DevNullStream) = wait()
wait_close(::DevNullStream) = wait()
eof(::DevNullStream) = true

let CoreIO = Union{Core.CoreSTDOUT, Core.CoreSTDERR}
    global write, unsafe_write
    write(io::CoreIO, x::UInt8) = Core.write(io, x)
    unsafe_write(io::CoreIO, x::Ptr{UInt8}, nb::UInt) = Core.unsafe_write(io, x, nb)
end

stdin = devnull
stdout = Core.stdout
stderr = Core.stderr

ext: jl

max_stars_repo_name: djsegal/julia-fork

max_issues_repo_name: djsegal/julia-fork

max_forks_repo_name: djsegal/julia-fork


text:
using LinearAlgebra
using Random

Random.seed!(123)

# CASE 1

x = randn(10)
y0 = randn(10)
y = copy(y0)

prox_col = (NormL1(0.1),IndBallL0(1))
ind_col = ((1:5,),(6:10,))

f = SlicedSeparableSum(prox_col,ind_col)
y, fy = prox(f,x,1.)
yn,fyn = ProximalOperators.prox_naive(f,x,1.)
y1,fy1 = prox(prox_col[1],x[ind_col[1]...],1.)
y2,fy2 = prox(prox_col[2],x[ind_col[2]...],1.)

@test abs(f(y)-fy)<1e-11
@test abs(fyn-fy)<1e-11
@test norm(yn-y)<1e-11
@test abs((fy1+fy2)-fy)<1e-11
@test norm(y-[y1;y2])<1e-11

# CASE 2

X1,X2 = randn(10,10),randn(10,10)
X = [X1; X2]

f = SlicedSeparableSum((NormL1(1.), NormL21(0.1)), ((1:10,:),(11:20,:)))

y,fy = prox(f,X,1.)
yn,fyn = ProximalOperators.prox_naive(f,X,1.)
y1,fy1 = prox(NormL1(1.),X1,1.)
y2,fy2 = prox(NormL21(0.1),X2,1.)

@test abs(f(y)-fy)<1e-11
@test abs(fyn-fy)<1e-11
@test norm(yn-y)<1e-11
@test abs((fy1+fy2)-fy)<1e-11
@test norm(y-[y1; y2])<1e-11

@test_throws MethodError SlicedSeparableSum((NormL1(1.), NormL21(0.1)), ((1.0,:),(11:20,:)))
@test_throws MethodError SlicedSeparableSum((NormL1(1.), randn()), ((1:10,:),(11:20,:)))

# CASE 3

x1, x2, x3 = randn(10), randn(10), randn(10)
X = [x1 x2 x3]

f = NormL2()
F = SlicedSeparableSum(f, ((:,1),(:,2),(:,3)))

y,Fy = prox(F,X,1.)
yn,Fyn = ProximalOperators.prox_naive(F,X,1.)
y1,fy1 = prox(f,x1,1.)
y2,fy2 = prox(f,x2,1.)
y3,fy3 = prox(f,x3,1.)

@test abs(F(y)-Fy)<1e-11
@test abs(Fyn-Fy)<1e-11
@test norm(yn-y)<1e-11
@test abs((fy1+fy2+fy3)-Fy)<1e-11
@test norm(y-[y1 y2 y3])<1e-11

# CASE 4

x = randn(10)
y0 = randn(10)
y = copy(y0)

prox_col = (NormL1(0.1),IndBallL0(1))
ind_col = ((collect(1:5),),(collect(6:10),))

f = SlicedSeparableSum(prox_col,ind_col)
y, fy = prox(f,x,1.)
yn,fyn = ProximalOperators.prox_naive(f,x,1.)
y1,fy1 = prox(prox_col[1],x[ind_col[1]...],1.)
y2,fy2 = prox(prox_col[2],x[ind_col[2]...],1.)

@test abs(f(y)-fy)<1e-11
@test abs(fyn-fy)<1e-11
@test norm(yn-y)<1e-11
@test abs((fy1+fy2)-fy)<1e-11
@test norm(y-[y1;y2])<1e-11

# Test with Quadratic (iterative)

Q = randn(5,10)
Q = Q'*Q
q = randn(10)
x = randn(10)
xx = vcat(x, x)
f = Quadratic(Q, q, iterative=true)
g = SlicedSeparableSum((f, f), ((1:10,), (11:20,)))
y, fy = prox(f, x)
yy, fyy = prox(g, xx)

@test yy ≈ vcat(y, y)
@test fyy ≈ 2*fy


text:
export SysLED

mutable struct SysLED <: AbstractDevice
    i::Int32
    stream::LabStream
    SysLED(i::Int32) = new(i)
end
SysLED(i::Int64) = SysLED(convert(Int32, i))

#No definition for IOBox since there are no LEDs
#Stream specific methods
function getwritecommand(stream::BeagleBoneStream, led::SysLED, val::Bool)
    led.i ∉ Int32[1,2,3,4] && error("SysLED $i not defined on BeagleBoneStream")
    return ("sysled", led.i, val)
end
function getreadcommand(stream::BeagleBoneStream, led::SysLED)
    led.i ∉ Int32[1,2,3,4] && error("SysLED $i not defined on BeagleBoneStream")
    return ("sysled", led.i)
end


text:
export simulate!, get_result

using  ModiaPlot
using  Measurements
import MonteCarloMeasurements
using  Unitful
using  Test
import DifferentialEquations

#---------------------------------------------------------------------
#                          Simulation
#---------------------------------------------------------------------

"""
    convertTimeVariable(t)

The function returns variable `t` in a normalized form:

1. If `t` has a unit, it is transformed to u"s" and the unit is stripped off.
2. `t` is converted to `Float64`.
"""
convertTimeVariable(t) = typeof(t) <: Unitful.AbstractQuantity ? convert(Float64, ustrip(uconvert(u"s", t))) : convert(Float64, t)

"""
    simulate!(model [, algorithm]; merge = nothing,
              tolerance = 1e-6, startTime = 0.0, stopTime = 1.0, interval = NaN,
              adaptive = true, log = true, logParameters = true, logStates = true,
              requiredFinalStates = nothing)

Simulate `model::SimulationModel` with `algorithm`
(= `alg` of [ODE Solvers of DifferentialEquations.jl](https://diffeq.sciml.ai/stable/solvers/ode_solve/)).
If the `algorithm` argument is missing, a default algorithm will be chosen from DifferentialEquations
(for details see [https://arxiv.org/pdf/1807.06430](https://arxiv.org/pdf/1807.06430), Figure 3).

The simulation results stored in `model` can be plotted with ModiaPlot.plot and the result values
can be retrieved with [`get_result`](@ref).

# Optional Arguments

- `merge`: Define parameters and init/start values that shall be merged with the previous values
           stored in `model`, before simulation is started.
- `tolerance`: Relative tolerance.
- `startTime`: Start time. If value is without unit, it is assumed to have unit [s].
- `stopTime`: Stop time. If value is without unit, it is assumed to have unit [s].
- `interval`: Interval to store result. If `interval=NaN`, it is internally selected as
              (stopTime-startTime)/500.
              If value is without unit, it is assumed to have unit [s].
- `adaptive`: = true, if the `algorithm` should use step-size control (if available).
              = false, if the `algorithm` should use a fixed step-size of `interval` (if available).
- `log`: = true, to log the simulation.
- `logParameters`: = true, to log the parameter and init/start values
- `logStates` : = true, to log the states, its init/start values and its units.
- `requiredFinalStates`: is not `nothing`: Check whether the ODE state vector at the final time instant with `@test`
              is in agreement to vector `requiredFinalStates` with respect to some tolerance. If this is not the case, print the
              final state vector (so that it can be included with copy-and-paste in the simulate!(..) call).

# Examples

```julia
using ModiaPlot
using DifferentialEquations

# Define model
inputSignal(t) = sin(t)

FirstOrder = Model(
    T = 0.2,
    x = Var(init=0.3),
    equations = :[u = inputSignal(time/u"s"),
                  T * der(x) + x = u,
                  y = 2*x]
)

# Modify parameters and initial values of model
FirstOrder2 = FirstOrder | Map(T = 0.4, x = Var(init=0.6))

# Instantiate model
firstOrder = @instantiateModel(FirstOrder2, logCode=true)

# Simulate with automatically selected algorithm and
# modified parameter and initial values
simulate!(firstOrder, stopTime = 1.0, merge = Map(T = 0.6, x = 0.9), logParameters=true)

# Plot variables "x", "u" in diagram 1, "der(x)" in diagram 2, both diagrams in figure 3
plot(firstOrder, [("x","u"), "der(x)"], figure=3)

# Retrieve "time" and "u" values:
get_result(firstOrder, "time")
get_result(firstOrder, "u")

# Simulate with Runge-Kutta 5/4 with step-size control
simulate!(firstOrder, Tsit5(), stopTime = 1.0)

# Simulate with Runge-Kutta 4 with fixed step size
simulate!(firstOrder, RK4(), stopTime = 1.0, adaptive=false)

# Simulate with algorithm that switches between
# Verners Runge-Kutta 6/5 algorithm if non-stiff region and
# Rosenbrock 4 (= A-stable method) if stiff region with step-size control
simulate!(firstOrder, AutoVern6(Rodas4()), stopTime = 1.0)

# Simulate with Sundials CVODE (BDF method with variable order 1-5) with step-size control
using Sundials
simulate!(firstOrder, CVODE_BDF(), stopTime = 1.0)
```
"""
function simulate!(m::Nothing, args...; kwargs...)
    @info "The call of simulate!(..) is ignored, since the first argument is nothing."
    return nothing
end
function simulate!(m::SimulationModel, algorithm=missing;
                   tolerance = 1e-6,
                   startTime = 0.0,
                   stopTime  = 1.0,
                   interval  = NaN,
                   adaptive::Bool      = true,
                   log::Bool           = false,
                   logParameters::Bool = false,
                   logStates::Bool     = false,
                   requiredFinalStates = nothing,
                   merge=nothing)
    initialized = false
    #try
        m.algorithmType = typeof(algorithm)
        tolerance = convert(Float64, tolerance)
        startTime = convertTimeVariable(startTime)
        stopTime  = convertTimeVariable(stopTime)
        interval  = convertTimeVariable(interval)
        interval  = isnan(interval) ? (stopTime - startTime)/500.0 : interval

        # Target type
        FloatType = getFloatType(m)

        # Initialize/re-initialize SimulationModel
        if log || logParameters || logStates
            println("... Simulate model ", m.modelName)
        end
        cpuStart::UInt64 = time_ns()
        cpuLast::UInt64  = cpuStart
        cpuStartIntegration::UInt64 = cpuStart
        success = init!(m, startTime, tolerance, merge, log, logParameters, logStates)
        if !success
            return nothing
        end
        initialized = true

        # Define problem and callbacks based on algorithm and model type
        tspan    = (startTime, stopTime)
        tspan2   = startTime:interval:stopTime
        tdir     = startTime <= stopTime ? 1 : -1
        abstol   = 0.1*tolerance
        problem  = DifferentialEquations.ODEProblem(derivatives!, m.x_start, tspan, m)
        callback = DifferentialEquations.FunctionCallingCallback(outputs!, funcat=tspan2, tdir=tdir)

        # Initial step size (the default of DifferentialEquations is too large) + step-size of fixed-step algorithm
        dt = adaptive ? interval/10 : interval    # initial step-size

        # Compute solution
        solution = ismissing(algorithm) ? DifferentialEquations.solve(problem, reltol=tolerance, abstol=abstol,
                                            save_everystep=false, save_start=false, save_end=true,
                                            callback=callback, adaptive=adaptive, dt=dt) :
                                        DifferentialEquations.solve(problem, algorithm, reltol=tolerance, abstol=abstol,
                                            save_everystep=false, save_start=false, save_end=true,
                                            callback=callback, adaptive=adaptive, dt=dt)
        if ismissing(algorithm)
            m.algorithmType = typeof(solution.alg)
        end

        # Terminate simulation
        finalStates = solution[:,end]
        terminate!(m, finalStates, solution.t[end])

        if log
            cpuTimeInitialization = convert(Float64, (cpuStartIntegration - cpuStart) * 1e-9)
            cpuTimeIntegration    = convert(Float64, (time_ns() - cpuStartIntegration) * 1e-9)
            cpuTime               = cpuTimeInitialization + cpuTimeIntegration

            println("      Termination at time = ", solution.t[end], " s")
            println("        cpuTime         = ", round(cpuTime, sigdigits=3), " s")
            #println("        cpuTime         = ", round(cpuTime              , sigdigits=3), " s (init: ",
            #                                      round(cpuTimeInitialization, sigdigits=3), " s, integration: ",
            #                                      round(cpuTimeIntegration   , sigdigits=3), " s)")
            println("        algorithm       = ", typeof(solution.alg))
            println("        FloatType       = ", FloatType)
            println("        interval        = ", interval, " s")
            println("        tolerance       = ", tolerance, " (relative tolerance)")
            println("        nEquations      = ", length(m.x_start))
            println("        nResults        = ", length(m.result))
            println("        nAcceptedSteps  = ", solution.destats.naccept)
            println("        nRejectedSteps  = ", solution.destats.nreject)
            println("        nGetDerivatives = ", m.nGetDerivatives, " (number of getDerivatives! calls)")
            println("        nf              = ", solution.destats.nf, " (number of getDerivatives! calls from integrator)")
            println("        nJac            = ", solution.destats.njacs, " (number of Jacobian computations)")
            println("        nErrTestFails   = ", solution.destats.nreject)
        end

        if !isnothing(requiredFinalStates)
            if length(finalStates) != length(requiredFinalStates)
                success = false
            else
                success = finalStates == requiredFinalStates || isapprox(finalStates, requiredFinalStates, rtol=1e-3)
            end

            if success
                @test success
            else
                if length(requiredFinalStates) > 0 && typeof(requiredFinalStates[1]) <: Measurements.Measurement
                    println(  "\nrequiredFinalStates = ", measurementToString(requiredFinalStates))
                    printstyled("finalStates         = ", measurementToString(finalStates), "\n\n", bold=true, color=:red)
                else
                    println(  "\nrequiredFinalStates = ", requiredFinalStates)
                    printstyled("finalStates         = ", finalStates, "\n\n", bold=true, color=:red)
                end
                @test finalStates == requiredFinalStates  #|| isapprox(finalStates, requiredFinalStates, rtol=1e-3)
            end
        end

        return solution
#=
    catch e
        if initialized
            terminate!(m, m.x_start, m.time)
        end

        if isa(e, ErrorException)
            printstyled("\nError from simulate!:\n", color=:red)
            printstyled(e.msg, "\n\n", color=:red)
            printstyled("Aborting simulate!\n\n", color=:red)
            empty!(m.result)
        else
            Base.rethrow()
        end
    end

    return nothing
=#
end

#---------------------------------------------------------------------
#        Provide ModiaPlot result access functions for SimulationModel
#---------------------------------------------------------------------

"""
    ModiaPlot.hasSignal(model::SimulationModel, name::String)

Return true if parameter or time-varying variable `name` (for example `a.b.c`)
is defined in the TinyModia SimulationModel (generated with [`TinyModia.@instantiateModel`](@ref)
that can be accessed and can be used for plotting.
"""
ModiaPlot.hasSignal(m::SimulationModel, name) =
    haskey(m.variables, name) ||
    name in m.zeroVariables ||
    !ismissing(get_value(m.p[1], name))

"""
    ModiaPlot.getNames(model::SimulationModel)

Return the variable names (parameters, time-varying variables) of a TinyModia SimulationModel
(generated with [`TinyModia.@instantiateModel`](@ref) that can be accessed
and can be used for plotting.
"""
function ModiaPlot.getNames(m::SimulationModel)
    names = get_names(m.p[1])
    append!(names, collect(m.zeroVariables))
    append!(names, collect( keys(m.variables) ) )
    return sort(names)
end

function ModiaPlot.getRawSignal(m::SimulationModel, name)
    if haskey(m.variables, name)
        resIndex = m.variables[name]
        negAlias = false
        if resIndex < 0
            resIndex = -resIndex
            negAlias = true
        end
        value  = m.result[1][resIndex]
        signal = Vector{typeof(value)}(undef, length(m.result))
        for (i, value_i) in enumerate(m.result)
            signal[i] = value_i[resIndex]
        end
        if negAlias
            signal = -signal
        end
        return (false, signal)

    elseif name in m.zeroVariables
        return (true, 0.0)

    else
        value = get_value(m.p[1], name)
        if ismissing(value)
            error("ModiaPlot.getRawSignal: ", name, " not in result of model ", m.modelName)
        end
        return (true, value)
    end
end

"""
    leaveName = get_leaveName(pathName::String)

 Return the `leaveName` of `pathName`.
"""
get_leaveName(pathName::String) =
    begin
        j = findlast('.', pathName);
        typeof(j) == Nothing || j >= length(pathName) ? pathName : pathName[j+1:end]
    end

function ModiaPlot.getDefaultHeading(m::SimulationModel)
    FloatType = get_leaveName( string( typeof( m.x_start[1] ) ) )

    algorithmName = string(m.algorithmType)
    i1 = findfirst("CompositeAlgorithm", algorithmName)
    if !isnothing(i1)
        i2 = findfirst("Vern" , algorithmName)
        i3 = findfirst("Rodas", algorithmName)
        success = false
        if !isnothing(i2) && !isnothing(i3)
            i2b = findnext(',', algorithmName, i2[1])
            i3b = findnext('{', algorithmName, i3[1])
            if !isnothing(i2b) && !isnothing(i3b)
                algorithmName = algorithmName[i2[1]:i2b[1]-1] * "(" * algorithmName[i3[1]:i3b[1]-1] * "())"
                success = true
            end
        end
        if !success
            algorithmName = "CompositeAlgorithm"
        end
    else
        i1 = findfirst('{', algorithmName)
        if !isnothing(i1)
            algorithmName = algorithmName[1:i1-1]
        end
        i1 = findlast('.', algorithmName)
        if !isnothing(i1)
            algorithmName = algorithmName[i1+1:end]
        end
    end

    if FloatType == "Float64"
        heading = m.modelName * " (" * algorithmName * ")"
    else
        heading = m.modelName * " (" * algorithmName * ", " * FloatType * ")"
    end
    return heading
end

"""
    signal = get_result(model, name; unit=true)

After a successful simulation of `model::SimulationModel`, return
the result for the signal `name::String` as vector of points
together with its unit. The time vector has path name `"time"`.
If `unit=false`, the signal is returned, **without unit**.

# Example

```julia
using ModiaBase
using Unitful

include("\$(ModiaBase.path)/demos/models/Model_Pendulum.jl")
using  .Model_Pendulum

pendulum = simulationModel(Pendulum)
simulate!(pendulum, stopTime=7.0)

time = get_result(pendulum, "time")  # vector with unit u"s"
phi  = get_result(pendulum, "phi")   # vector with unit u"rad"

import PyPlot
PyPlot.figure(4)   # Change to figure 4 (or create it, if it does not exist)
PyPlot.clf()       # Clear current figure
PyPlot.plot(ustrip(time), ustrip(phi), "b--", label="phi in " * string(unit(phi[1])))
PyPlot.xlabel("time in " * string(unit(time[1])))
PyPlot.legend()
```
"""
function get_result(m::SimulationModel, name::String; unit=true)
    #(xsig, xsigLegend, ysig, ysigLegend, yIsConstant) = ModiaPlot.getPlotSignal(m, "time", name)

    (isConstant, ysig) = ModiaPlot.getRawSignal(m, name)

    ysig = unit ? ysig : ustrip.(ysig)

    #=
    if yIsConstant
        if ndims(ysig) == 1
            ysig = fill(ysig[1], length(xsig))
        else
            ysig = fill(ysig[1,:], length(xsig))
        end
    end
    =#

    return ysig
end


text:
# Michelle Medina
# July 16, 2020
# Testing 2D cases for Nodal and Hierarchical Bases

# Testing calculating Nodal Basis function in 2D
xVal = collect(range(0.0, stop=1.0, length = 5))
yVal = collect(range(0.0, stop=1.0, length = 5))
nodal = calcNodal2D((x,y)->exp(x)*exp(y), xVal, yVal)
nodal2 = calcNodal2D((x,y)->exp(x)*sin(pi*y), xVal, yVal)

# Plotting 2D functions
using PyPlot
contourf(nodal.values)
colorbar()
show()

contourf(nodal2.values)
colorbar()
show()

# Going from nodal to hierarchical grid and sparse grid
modal = Nodal_2_H(nodal)
sparse = Nodal_2_H_sparse(nodal,3)
for l in 0:2, m in 0:2
	display(modal.levels[l+1,m+1].coefficients)
	display(sparse.levels[l+1,m+1].coefficients)
	println()
end

# Going back and forth between nodal and modal
back = H_2_Nodal(modal)
@test isapprox(nodal.values,back.values)

# Using interpolation instead of evaluate
modal2 = Nodal_2_H_new(nodal)

# Testing how coefficients fall off as level increases
using LinearAlgebra
A = []
for l in 0:maxlevel(modal,1)
	append!(A, norm(modal.levels[l+1].coefficients))
end

using PyPlot
plot(A)
show()


text:
# test_prepare.jl

@testset "Test DBInterface.prepare" begin
    con = DBInterface.connect(DuckDB.DB)

    DBInterface.execute(con, "CREATE TABLE test_table(i INTEGER, j DOUBLE)")
    stmt = DBInterface.prepare(con, "INSERT INTO test_table VALUES(?, ?)")

    DBInterface.execute(stmt, [1, 3.5])
    DBInterface.execute(stmt, [missing, nothing])
    DBInterface.execute(stmt, [2, 0.5])

    results = DBInterface.execute(con, "SELECT * FROM test_table")
    df = DataFrame(results)

    @test isequal(df.i, [1, missing, 2])
    @test isequal(df.j, [3.5, missing, 0.5])

    # execute many
    DBInterface.executemany(stmt, (col1 = [1, 2, 3, 4, 5], col2 = [1, 2, 4, 8, -0.5]))

    results = DBInterface.execute(con, "SELECT * FROM test_table")
    df = DataFrame(results)

    @test isequal(df.i, [1, missing, 2, 1, 2, 3, 4, 5])
    @test isequal(df.j, [3.5, missing, 0.5, 1, 2, 4, 8, -0.5])

    # verify that double-closing does not cause any problems
    DBInterface.close!(stmt)
    DBInterface.close!(stmt)
    DBInterface.close!(con)
    DBInterface.close!(con)
end

@testset "Test DBInterface.prepare with various types" begin
    con = DBInterface.connect(DuckDB.DB)

    type_names = [
        "BOOLEAN",
        "TINYINT",
        "SMALLINT",
        "INTEGER",
        "BIGINT",
        "UTINYINT",
        "USMALLINT",
        "UINTEGER",
        "UBIGINT",
        "FLOAT",
        "DOUBLE",
        "DATE",
        "TIME",
        "TIMESTAMP",
        "VARCHAR",
        "INTEGER"
    ]
    type_values = [
        Bool(true),
        Int8(3),
        Int16(4),
        Int32(8),
        Int64(20),
        UInt8(42),
        UInt16(300),
        UInt32(420421),
        UInt64(43294832),
        Float32(0.5),
        Float64(0.25),
        Date(1992, 9, 20),
        Time(23, 10, 33),
        DateTime(1992, 9, 20, 23, 10, 33),
        String("hello world"),
        missing
    ]
    for i in 1:size(type_values, 1)
        stmt = DBInterface.prepare(con, string("SELECT ?::", type_names[i], " a"))
        result = DataFrame(DBInterface.execute(stmt, [type_values[i]]))
        @test isequal(result.a, [type_values[i]])
    end
end

@testset "DBInterface.prepare: named parameters not supported yet" begin
    con = DBInterface.connect(DuckDB.DB)

    DBInterface.execute(con, "CREATE TABLE test_table(i INTEGER, j DOUBLE)")
    @test_throws DuckDB.QueryException DBInterface.prepare(con, "INSERT INTO test_table VALUES(:col1, :col2)")

    DBInterface.close!(con)
end


text:
#Mean functions
export ConstantMean, LinearMean, LinearDiffMean

abstract type MeanFunc end

#-------------
#Constant mean
#-------------
immutable ConstantMean <: MeanFunc
    m::Float64
end
(cm::ConstantMean)(x) = cm.m

#-----------
#Linear mean
#-----------

#Proportional to each parameter's absolute value
type LinearMean <: MeanFunc
    k::Vector{Float64}
end
(m::LinearMean)(x) = dot(m.k, x)

#----------------------
#Linear difference mean
#----------------------

#Mean function outputs proportional to the parameter at scl_idx and the vector
#norm of the difference between the parameters at msr_idx and ref_idx.
type LinearDiffMean <: MeanFunc
    k::Float64
    scl_idx::Int
    msr_idx::Vector{Int}
    ref_idx::Vector{Int}
end

function (m::LinearDiffMean)(x)
    return m.k * x[m.scl_idx] * norm(x[m.msr_idx] - x[m.ref_idx])
end


text:
module Julia_docs_test

#import packages

# package code goes here
include("test.jl")

end # module


text:
module GOEnrichment

using Printf
using CSV
using LightGraphs
using DataStructures
using DataFrames
using HypothesisTests
#using LightGraphs
### Gene ontology enrichments
export parseontology, load_annot_long, ontologygraphs, extendannotation, enrichtest

include("parse_ontology.jl")
include("annotations.jl")
include("gograph.jl")
include("enrichment.jl")

end # module


text:
const ArrayOrDict = Union{Array, Dict}

"""
    write_to_json(path::String, tw::ArrayOrDict)

General functon to write Dict or Array of Dict as tweet as json for better
persistance. The method expect the following parameters:
- path: path to save the file with file name (see the example)
- tw: Array of Dict or Dict object to write as json
# Example
```
julia> tweet = Dict("asdf" => "asdf")
Dict{String,String} with 1 entry:
  "asdf" => "asdf"

julia> tweets = [tweet, tweet]
2-element Array{Dict{String,String},1}:
 Dict("asdf" => "asdf")
 Dict("asdf" => "asdf")

julia> write_to_json("./temp/all_tweets.json",tweet)
File writting was successful!

julia> write_to_json("./temp/single_tweet.json",tweet)
File writting was successful!
```
"""
function write_to_json(path::String, tw::ArrayOrDict)
    try
        open(path, "w") do f JSON.print(f, tw)  end
        print("File writting was successful! \n")
    catch ex
        error("Error while writting file: $ex \n")
    end
end

"""
    read_from_json(path::String)

Given a path of json file the method should be able to read files as Dict type or Array
of Dict. The method expect the following parameters:
- path: path of the json file to load

# Example
```
julia> read_from_json("./temp/all_tweets.json")
File loading successful!
Dict{String,Any} with 1 entry:
  "asdf" => "asdf
```
"""
function read_from_json(path::String)
    try
        tws = nothing
        open(path, "r") do f
            dict_txt = read(f, String)
            tws=JSON.parse(dict_txt)
        end
        print("File loading successful!\n")
        return tws
    catch ex
        error("Error while reading file: $ex")
    end
end


text:
module DynamicProgramming

using Interpolations

export dp_map, dp_loop, dp_forward

# function implementing parallel map with data grouping
function pmap_group(f, lst, group_size::Int)
    np = nprocs()  # determine the number of processes available
    n = length(lst)
    results = Array(Float64, n)
    i = 1
    # function to produce the next work item from the queue.
    # in this case it's just an index.
    nextidx() = (idx=i; i+=group_size; idx)
    @sync begin
        for p=1:np
            if p != myid() || np == 1
                @async begin
                    while true
                        idx = nextidx()
                        if idx > n
                            break
                        end
                    results[idx:idx+group_size-1] = remotecall_fetch(p, map, f, lst[idx:idx+group_size-1])
                    end
                end
            end
        end
    end
    results
end

# compute value function and optimal input
function step_u(ts::Int64, x::Array{Float64, 1},
              ugrid::FloatRange{Float64}, theta::Array{Float64, 1}, V, f::Function, phi::Function)
    V_max = -Inf        # maximum value
    u_max = ugrid[1]    # maximizing input
    for u in ugrid
        V_u = phi(x, u, theta) + V[f(ts, x, u, theta)...]
        if V_u > V_max
            V_max = V_u
            u_max = u
        end
    end
    return (V_max, u_max)
end

function step(ts::Int64, x::Array{Float64, 1},
              ugrid::FloatRange{Float64}, theta::Array{Float64, 1}, V, f::Function, phi::Function)
    return step_u(ts, x, ugrid, theta, V, f, phi)[1]
end

# dynamic programming function
function dp_map(n, f::Function, phi::Function, ugrid::FloatRange{Float64}, xgrid::Tuple,
            theta0::Array{Float64, 1}, N, group_size::Int64)

    J = zeros([length(gridvals) for gridvals in xgrid]..., N)

    for t = N-1:-1:1
        if n == 2
            V = interpolate(xgrid, J[:, :, t+1], Gridded(Linear()))
            X = [[i, j] for i in xgrid[1], j in xgrid[2]]
            J[:, :, t] = pmap_group(x->step(t, x, ugrid, theta0, V, f, phi), X, group_size)
        elseif n == 4
            println(t)
            V = interpolate(xgrid, J[:, :, :, :, t+1], Gridded(Linear()))
            X = [[i, j, k, l] for i in xgrid[1], j in xgrid[2], k in xgrid[3], l in xgrid[4]]
            J[:, :, :, :, t] = pmap_group(x->step(t, x, ugrid, theta0, V, f, phi), X, group_size)
        else
            error("Dynamic programming function has not been defined for this value of n")
        end
    end
    return J
end

function dp_loop(n, f::Function, phi::Function, ugrid::FloatRange{Float64}, xgrid::Tuple,
            theta0::Array{Float64, 1}, N::Int64)

    J = SharedArray(Float64, [length(gridvals) for gridvals in xgrid]..., N)
    u = SharedArray(Float64, [length(gridvals) for gridvals in xgrid]..., N-1)

    if n == 4
        for t = N-1:-1:1
            println(t)
            V = interpolate(xgrid, J[:, :, :, :, t+1], Gridded(Linear()))

            @sync @parallel for i = 1:length(xgrid[1])
                for j = 1:length(xgrid[2])
                    for k= 1:length(xgrid[3])
                        for l = 1:length(xgrid[4])
                            (J[i, j, k, l, t], u[i, j, k, l, t]) = step_u(t,
                                            [xgrid[1][i], xgrid[2][j], xgrid[3][k], xgrid[4][l]],
                                            ugrid, theta0, V, f, phi)
                        end
                    end
                end
            end
        end
    elseif n == 2
        for t = N-1:-1:1
            V = interpolate(xgrid, J[:, :, t+1], Gridded(Linear()))

            @sync @parallel for i = 1:length(xgrid[1])
                for j = 1:length(xgrid[2])
                    (J[i, j, t], u[i, j, t]) = step_u(t,
                                            [xgrid[1][i], xgrid[2][j]],
                                            ugrid, theta0, V, f, phi)
                end
            end
        end
    else
        error("Dynamic programming function has not been defined for this value of n")
    end
    return (J, u)
end

function dp_forward(n, Jvals, uvals, f, x0, xgrid, theta0, N)
    u_opt = zeros(N-1)
    x = zeros(n, N)
    x[:, 1] = x0
    for t=1:N-1
        if n == 4
            u = interpolate(xgrid, uvals[:, :, :, :, t], Gridded(Linear()))
        elseif n == 2
            u = interpolate(xgrid, uvals[:, :, t], Gridded(Linear()))
        else
            error("Dynamic programming function has not been defined for this value of n")
        end
        u_opt[t] = u[x[:, t]...]
        x[:, t+1] = f(t, x[:, t], u_opt[t], theta0)
    end

    return (x, u_opt)
end

end # Module


text:
##
<|(f,x) = f(x)
export <|
##


text:
import InteractiveUtils

using UUIDs
const Cthulhu = Base.PkgId(UUID("f68482b8-f384-11e8-15f7-abe071a5a75f"), "Cthulhu")

#
# syntax highlighting
#

const _pygmentize = Ref{Union{String,Nothing}}()
function pygmentize()
    if !isassigned(_pygmentize)
        _pygmentize[] = Sys.which("pygmentize")
    end
    return _pygmentize[]
end

function highlight(io::Base.TTY, code, lexer)
    highlighter = pygmentize()
    have_color = get(io, :color, false)
    if highlighter === nothing || !have_color
        print(io, code)
        return code
    else
        custom_lexer = joinpath(dirname(@__DIR__), "res", "pygments", "$lexer.py")
        if isfile(custom_lexer)
            lexer = `$custom_lexer -x`
        end

        pipe = open(`$highlighter -f terminal -P bg=dark -l $lexer`, "r+")
        print(pipe, code)
        close(pipe.in)
        print(io, read(pipe, String))
    end
end

highlight(io, code, lexer) = print(io, code)

#
# code_* replacements
#

code_lowered(job::CompilerJob; kwargs...) =
    InteractiveUtils.code_lowered(job.source.f, job.source.tt; kwargs...)

function code_typed(job::CompilerJob; interactive::Bool=false, kwargs...)
    # TODO: use the compiler driver to get the Julia method instance (we might rewrite it)
    if interactive
        # call Cthulhu without introducing a dependency on Cthulhu
        mod = get(Base.loaded_modules, Cthulhu, nothing)
        mod===nothing && error("Interactive code reflection requires Cthulhu; please install and load this package first.")
        descend_code_typed = getfield(mod, :descend_code_typed)
        descend_code_typed(job.source.f, job.source.tt; kwargs...)
    else
        InteractiveUtils.code_typed(job.source.f, job.source.tt; kwargs...)
    end
end

function code_warntype(io::IO, job::CompilerJob; interactive::Bool=false, kwargs...)
    # TODO: use the compiler driver to get the Julia method instance (we might rewrite it)
    if interactive
        @assert io == stdout
        # call Cthulhu without introducing a dependency on Cthulhu
        mod = get(Base.loaded_modules, Cthulhu, nothing)
        mod===nothing && error("Interactive code reflection requires Cthulhu; please install and load this package first.")
        descend_code_warntype = getfield(mod, :descend_code_warntype)
        descend_code_warntype(job.source.f, job.source.tt; kwargs...)
    else
        InteractiveUtils.code_warntype(io, job.source.f, job.source.tt; kwargs...)
    end
end
code_warntype(job::CompilerJob; kwargs...) = code_warntype(stdout, job; kwargs...)

"""
    code_llvm([io], job; optimize=true, raw=false, dump_module=false)

Prints the device LLVM IR generated for the given compiler job to `io` (default `stdout`).

The following keyword arguments are supported:

- `optimize`: determines if the code is optimized, which includes kernel-specific
  optimizations if `kernel` is true
- `raw`: return the raw IR including all metadata
- `dump_module`: display the entire module instead of just the function

See also: [`@device_code_llvm`](@ref), `InteractiveUtils.code_llvm`
"""
function code_llvm(io::IO, job::CompilerJob; optimize::Bool=true, raw::Bool=false,
                   debuginfo::Symbol=:default, dump_module::Bool=false)
    # NOTE: jl_dump_function_ir supports stripping metadata, so don't do it in the driver
    ir, entry = GPUCompiler.codegen(:llvm, job; optimize=optimize, strip=false, validate=false)
    str = ccall(:jl_dump_function_ir, Ref{String},
                (LLVM.API.LLVMValueRef, Bool, Bool, Ptr{UInt8}),
                entry, !raw, dump_module, debuginfo)
    highlight(io, str, "llvm")
end
code_llvm(job::CompilerJob; kwargs...) = code_llvm(stdout, job; kwargs...)

"""
    code_native([io], f, types; cap::VersionNumber, kernel=false, raw=false)

Prints the native assembly generated for the given compiler job to `io` (default `stdout`).

The following keyword arguments are supported:

- `cap` which device to generate code for
- `kernel`: treat the function as an entry-point kernel
- `raw`: return the raw code including all metadata

See also: [`@device_code_native`](@ref), `InteractiveUtils.code_llvm`
"""
function code_native(io::IO, job::CompilerJob; raw::Bool=false, dump_module::Bool=false)
    asm, _ = GPUCompiler.codegen(:asm, job; strip=!raw, only_entry=!dump_module, validate=false)
    highlight(io, asm, source_code(job.target))
end
code_native(job::CompilerJob; kwargs...) =
    code_native(stdout, func, types; kwargs...)

#
# @device_code_* functions
#

function emit_hooked_compilation(inner_hook, ex...)
    user_code = ex[end]
    user_kwargs = ex[1:end-1]
    quote
        # wipe the compile cache to force recompilation
        empty!(GPUCompiler.compilecache)

        local kernels = 0
        function outer_hook(job)
            kernels += 1
            $inner_hook(job; $(map(esc, user_kwargs)...))
        end

        if GPUCompiler.compile_hook[] != nothing
            error("Chaining multiple @device_code calls is unsupported")
        end
        try
            GPUCompiler.compile_hook[] = outer_hook
            $(esc(user_code))
        finally
            GPUCompiler.compile_hook[] = nothing
        end

        if kernels == 0
            error("no kernels executed while evaluating the given expression")
        end

        nothing
    end
end

"""
    @device_code_lowered ex

Evaluates the expression `ex` and returns the result of
`InteractiveUtils.code_lowered` for every compiled GPU kernel.

See also: `InteractiveUtils.@code_lowered`
"""
macro device_code_lowered(ex...)
    quote
        buf = Any[]
        function hook(job::CompilerJob)
            append!(buf, code_lowered(job))
        end
        $(emit_hooked_compilation(:hook, ex...))
        buf
    end
end

"""
    @device_code_typed ex

Evaluates the expression `ex` and returns the result of
`InteractiveUtils.code_typed` for every compiled GPU kernel.

See also: `InteractiveUtils.@code_typed`
"""
macro device_code_typed(ex...)
    quote
        output = Dict{CompilerJob,Any}()
        function hook(job::CompilerJob)
            output[job] = code_typed(job)
        end
        $(emit_hooked_compilation(:hook, ex...))
        output
    end
end

"""
    @device_code_warntype [io::IO=stdout] ex

Evaluates the expression `ex` and prints the result of
`InteractiveUtils.code_warntype` to `io` for every compiled GPU kernel.

See also: `InteractiveUtils.@code_warntype`
"""
macro device_code_warntype(ex...)
    function hook(job::CompilerJob; io::IO=stdout, kwargs...)
        println(io, "$job")
        println(io)
        code_warntype(io, job; kwargs...)
    end
    emit_hooked_compilation(hook, ex...)
end

"""
    @device_code_llvm [io::IO=stdout, ...] ex

Evaluates the expression `ex` and prints the result of InteractiveUtils.code_llvm
to `io` for every compiled GPU kernel. For other supported keywords, see
[`GPUCompiler.code_llvm`](@ref).

See also: InteractiveUtils.@code_llvm
"""
macro device_code_llvm(ex...)
    function hook(job::CompilerJob; io::IO=stdout, kwargs...)
        println(io, "; $job")
        code_llvm(io, job; kwargs...)
    end
    emit_hooked_compilation(hook, ex...)
end

"""
    @device_code_native [io::IO=stdout, ...] ex

Evaluates the expression `ex` and prints the result of [`GPUCompiler.code_native`](@ref) to `io`
for every compiled GPU kernel. For other supported keywords, see
[`GPUCompiler.code_native`](@ref).
"""
macro device_code_native(ex...)
    function hook(job::CompilerJob; io::IO=stdout, kwargs...)
        println(io, "// $job")
        println(io)
        code_native(io, job; kwargs...)
    end
    emit_hooked_compilation(hook, ex...)
end

"""
    @device_code dir::AbstractString=... [...] ex

Evaluates the expression `ex` and dumps all intermediate forms of code to the directory
`dir`.
"""
macro device_code(ex...)
    only(xs) = (@assert length(xs) == 1; first(xs))
    localUnique = 1
    function hook(job::CompilerJob; dir::AbstractString)
        name = something(job.source.name, nameof(job.source.f))
        fn = "$(name)_$(localUnique)"
        mkpath(dir)

        open(joinpath(dir, "$fn.lowered.jl"), "w") do io
            code = only(code_lowered(job))
            println(io, code)
        end

        open(joinpath(dir, "$fn.typed.jl"), "w") do io
            if VERSION >= v"1.1.0"
                code = only(code_typed(job; debuginfo=:source))
            else
                code = only(code_typed(job))
            end
            println(io, code)
        end

        open(joinpath(dir, "$fn.unopt.ll"), "w") do io
            code_llvm(io, job; dump_module=true, raw=true, optimize=false)
        end

        open(joinpath(dir, "$fn.opt.ll"), "w") do io
            code_llvm(io, job; dump_module=true, raw=true)
        end

        open(joinpath(dir, "$fn.asm"), "w") do io
            code_native(io, job)
        end

        localUnique += 1
    end
    emit_hooked_compilation(hook, ex...)
end


text:
include("testfunctions.jl")
@testset "DQMC Parameters" begin
    P1 = MonteCarlo.DQMCParameters(beta=5.0) #defaults to delta_tau = 0.1
    @test all((P1.beta, P1.delta_tau, P1.slices) .== (5.0, 0.1, 50))

    P2 = MonteCarlo.DQMCParameters(beta=5.0, delta_tau=0.01)
    @test all((P2.beta, P2.delta_tau, P2.slices) .== (5.0, 0.01, 500))

    P3 = MonteCarlo.DQMCParameters(beta=50.0, slices=20)
    @test all((P3.beta, P3.delta_tau, P3.slices) .== (50.0, 2.5, 20))

    P4 = MonteCarlo.DQMCParameters(delta_tau=0.1, slices=50)
    @test all((P4.beta, P4.delta_tau, P4.slices) .== (5.0, 0.1, 50))
end

@testset "DQMC" begin
    m = HubbardModelAttractive(8, 1);

    # constructors
    dqmc = DQMC(m; beta=5.0)

    # generic checkerboard
    sq = MonteCarlo.SquareLattice(4);
    @test MonteCarlo.build_checkerboard(sq) == ([1.0 3.0 5.0 7.0 9.0 11.0 13.0 15.0 1.0 2.0 4.0 6.0 9.0 10.0 12.0 14.0 2.0 3.0 4.0 5.0 8.0 10.0 11.0 16.0 6.0 7.0 8.0 12.0 13.0 14.0 15.0 16.0; 2.0 4.0 6.0 8.0 10.0 12.0 14.0 16.0 5.0 3.0 8.0 7.0 13.0 11.0 16.0 15.0 6.0 7.0 1.0 9.0 12.0 14.0 15.0 13.0 10.0 11.0 5.0 9.0 1.0 2.0 3.0 4.0; 1.0 5.0 9.0 13.0 17.0 21.0 25.0 29.0 2.0 3.0 8.0 11.0 18.0 19.0 24.0 27.0 4.0 6.0 7.0 10.0 16.0 20.0 22.0 31.0 12.0 14.0 15.0 23.0 26.0 28.0 30.0 32.0], UnitRange[1:8, 9:16, 17:24, 25:32], 4)

    m = HubbardModelAttractive(8, 2, mu=0.5)
    mc1 = DQMC(m, beta=5.0)
    mc2 = DQMC(m, beta=5.0, checkerboard=false)
    mc2.conf = deepcopy(mc1.conf)
    MonteCarlo.init_hopping_matrices(mc1, m)
    MonteCarlo.init_hopping_matrices(mc2, m)
    MonteCarlo.build_stack(mc1, mc1.s)
    MonteCarlo.build_stack(mc2, mc2.s)
    @test MonteCarlo.slice_matrix(mc1, m, 1, 1.) == MonteCarlo.slice_matrix(mc2, m, 1, 1.)

    mc = DQMC(m, beta=5.0, checkerboard=true, delta_tau=0.1)
    MonteCarlo.init_hopping_matrices(mc, m)
    hop_mat_exp_chkr = foldl(*,mc.s.chkr_hop_half) * sqrt.(mc.s.chkr_mu)
    r = MonteCarlo.effreldiff(mc.s.hopping_matrix_exp,hop_mat_exp_chkr)
    r[findall(x -> x==zero(x), hop_mat_exp_chkr)] .= 0.
    @test maximum(MonteCarlo.absdiff(mc.s.hopping_matrix_exp,hop_mat_exp_chkr)) <= mc.p.delta_tau

    # initial greens test
    mc = DQMC(m, beta=5.0, safe_mult=1)
    MonteCarlo.build_stack(mc, mc.s)
    MonteCarlo.propagate(mc)
    # With this we effectively test calculate_greens without wrap_greens
    greens, = calculate_greens_and_logdet(mc, mc.s.current_slice)
    MonteCarlo.wrap_greens!(mc, greens, mc.s.current_slice+1, -1)
    @test greens ≈ mc.s.greens
    # here with a single implied wrap
    greens, = calculate_greens_and_logdet(mc, mc.s.current_slice-1)
    @test maximum(MonteCarlo.absdiff(greens, mc.s.greens)) < 1e-12

    # wrap greens test
    for k in 0:9
        MonteCarlo.wrap_greens!(mc, mc.s.greens, mc.s.current_slice - k, -1)
    end
    greens, = calculate_greens_and_logdet(mc, mc.s.current_slice-11)
    @test maximum(MonteCarlo.absdiff(greens, mc.s.greens)) < 1e-9

    # Check greens reconstruction used in replay
    mc = DQMC(m, beta=5.0, safe_mult=5)
    # Make sure this works with any values
    for k in shuffle(0:MonteCarlo.nslices(mc))
        G1, _ = calculate_greens_and_logdet(mc, k)
        G2 = MonteCarlo.calculate_greens(mc, k)
        @test G1 ≈ G2
    end

    include("slice_matrices.jl")
end

@testset "Unequal Time Stack" begin
    m = HubbardModelAttractive(6, 1);
    dqmc = DQMC(m; beta=15.0, safe_mult=5)
    MonteCarlo.initialize_stack(dqmc, dqmc.ut_stack)

    MonteCarlo.build_stack(dqmc, dqmc.ut_stack)
    MonteCarlo.build_stack(dqmc, dqmc.s)

    # test B(τ, 1) / B_l1 stacks
    @test dqmc.s.u_stack ≈ dqmc.ut_stack.forward_u_stack
    @test dqmc.s.d_stack ≈ dqmc.ut_stack.forward_d_stack
    @test dqmc.s.t_stack ≈ dqmc.ut_stack.forward_t_stack

    # generate B(β, τ) / B_Nl stacks
    while dqmc.s.direction == -1
        MonteCarlo.propagate(dqmc)
    end

    # test B(β, τ) / B_Nl stacks
    # Note: dqmc.s doesn't generate the full stack here
    @test dqmc.s.u_stack[2:end] ≈ dqmc.ut_stack.backward_u_stack[2:end]
    @test dqmc.s.d_stack[2:end] ≈ dqmc.ut_stack.backward_d_stack[2:end]
    @test dqmc.s.t_stack[2:end] ≈ dqmc.ut_stack.backward_t_stack[2:end]

    while !(
            MonteCarlo.current_slice(dqmc) == 1 &&
            dqmc.s.direction == -1
        )
        MonteCarlo.propagate(dqmc)
    end

    # Check equal time greens functions from equal time and unequal time
    # calculation against each other
    for slice in 0:MonteCarlo.nslices(dqmc)
        G1 = deepcopy(MonteCarlo.calculate_greens(dqmc, slice))
        G2 = deepcopy(MonteCarlo.calculate_greens(dqmc, slice, slice))
        @test maximum(abs.(G1 .- G2)) < 1e-14
    end

    # Check G(t, 0) + G(0, beta - t) = 0
    for slice in 0:MonteCarlo.nslices(dqmc)-1
        G1 = MonteCarlo.greens(dqmc, slice, 0)
        G2 = MonteCarlo.greens(dqmc, slice, MonteCarlo.nslices(dqmc))
        @test G1 ≈ -G2 atol = 1e-13
    end

    # Check Iterators
    # For some reason Gkl/Gk0 errors jump in the last 10 steps
    # when using UnequalTimeStack

    # As in G(τ = Δτ * k, 0)
    # Note: G(0, l) = G(M-l, 0)
    Gk0s = [deepcopy(MonteCarlo.greens(dqmc, slice, 0)) for slice in 0:MonteCarlo.nslices(dqmc)]

    # Calculated from UnequalTimeStack (high precision)
    it = MonteCarlo.GreensIterator(dqmc, :, 0, dqmc.p.safe_mult)
    for (i, G) in enumerate(it)
        @test maximum(abs.(G .- Gk0s[i])) < 1e-14
    end

    # Calculated from mc.s.greens using UDT decompositions (lower precision)
    it = MonteCarlo.GreensIterator(dqmc, :, 0, 4dqmc.p.safe_mult)
    for (i, G) in enumerate(it)
        @test maximum(abs.(G .- Gk0s[i])) < 1e-11
    end

    Gkks = map(0:MonteCarlo.nslices(dqmc)) do slice
        g = MonteCarlo.calculate_greens(dqmc, slice)
        deepcopy(MonteCarlo._greens!(dqmc, dqmc.s.greens_temp, g))
    end
    G0ks = [deepcopy(MonteCarlo.greens(dqmc, 0, slice)) for slice in 0:MonteCarlo.nslices(dqmc)]
    MonteCarlo.calculate_greens(dqmc, 0) # restore mc.s.greens

    # high precision
    it = MonteCarlo.CombinedGreensIterator(dqmc, dqmc.p.safe_mult)
    for (i, (G0k, Gk0, Gkk)) in enumerate(it)
        @test maximum(abs.(Gk0 .- Gk0s[i+1])) < 1e-14
        @test maximum(abs.(G0k .- G0ks[i+1])) < 1e-14
        @test maximum(abs.(Gkk .- Gkks[i+1])) < 1e-14
    end

    # low precision
    it = MonteCarlo.CombinedGreensIterator(dqmc, 4dqmc.p.safe_mult)
    for (i, (G0k, Gk0, Gkk)) in enumerate(it)
        @test maximum(abs.(Gk0 .- Gk0s[i+1])) < 1e-10
        @test maximum(abs.(G0k .- G0ks[i+1])) < 1e-10
        @test maximum(abs.(Gkk .- Gkks[i+1])) < 1e-10
    end
end


text:
using Krotov
using Documenter
using Pkg
using Plots

gr()
ENV["GKSwstype"] = "100"

include(joinpath(@__DIR__, "download_dumps.jl"))

# Generate examples
include("generate.jl")

DocMeta.setdocmeta!(Krotov, :DocTestSetup, :(using Krotov); recursive=true)

PROJECT_TOML = Pkg.TOML.parsefile(joinpath(@__DIR__, "..", "Project.toml"))
VERSION = PROJECT_TOML["version"]
NAME = PROJECT_TOML["name"]
AUTHORS = join(PROJECT_TOML["authors"], ", ") * " and contributors"
GITHUB = "https://github.com/JuliaQuantumControl/Krotov.jl"

println("Starting makedocs")

makedocs(;
    authors=AUTHORS,
    sitename="Krotov.jl",
    modules=[Krotov],
    format=Documenter.HTML(;
        prettyurls=true,
        canonical="https://juliaquantumcontrol.github.io/Krotov.jl",
        assets=String[],
        footer="[$NAME.jl]($GITHUB) v$VERSION docs powered by [Documenter.jl](https://github.com/JuliaDocs/Documenter.jl).",
        mathengine=KaTeX()
    ),
    pages=[
        "Home" => "index.md",
        "Overview" => "overview.md",
        "Examples" => [
            "List of Examples" => "examples/index.md",
            "Example 1 (TLS)" => "examples/simple_state_to_state.md",
            "Example 2 (Diss. Gate)" => "examples/rho_3states.md",
            "Example 3 (Parametrization)" => "examples/state_to_state_parametrizations.md",
            "Example 4 (PE)" => "examples/perfect_entanglers.md",
        ],
        "API" => "api.md",
    ]
)

println("Finished makedocs")

rm(joinpath(@__DIR__, "build", "examples", ".gitignore"))

deploydocs(; repo="github.com/JuliaQuantumControl/Krotov.jl")


text:
struct Spline{order,T,P<:AbstractVector} <: Basis{T}
    points::P
end
Spline{o,T}(pts::P) where {o,T,P} = Spline{o,T,P}(pts)

const LinearSpline = Spline{1}
const HeavisideSpline = Spline{0}

Spline{o}(pts::AbstractVector{T}) where {o,T} = Spline{o,float(T)}(pts)
Spline{o}(S::Spline) where {o} = Spline{o}(S.points)

for Typ in (:LinearSpline, :HeavisideSpline)
    STyp = string(Typ)
    @eval function summary(io::IO, L::$Typ)
        print(io, "$($STyp)(")
        print(IOContext(io, :limit=>true), L.points)
        print(io,")")
    end
end

axes(B::Spline{o}) where o =
    (Inclusion(first(B.points)..last(B.points)), OneTo(length(B.points)+o-1))
==(A::Spline{o}, B::Spline{o}) where o = A.points == B.points

function getindex(B::LinearSpline{T}, x::Number, k::Int) where T
    x ∈ axes(B,1) && 1 ≤ k ≤ size(B,2)|| throw(BoundsError())

    p = B.points
    n = length(p)

    k > 1 && x ≤ p[k-1] && return zero(T)
    k < n && x ≥ p[k+1] && return zero(T)
    x == p[k] && return one(T)
    x < p[k] && return (x-p[k-1])/(p[k]-p[k-1])
    return (x-p[k+1])/(p[k]-p[k+1]) # x ≥ p[k]
end

function getindex(B::HeavisideSpline{T}, x::Number, k::Int) where T
    x ∈ axes(B,1) && 1 ≤ k ≤ size(B,2)|| throw(BoundsError())

    p = B.points
    n = length(p)

    p[k] < x < p[k+1] && return one(T)
    p[k] == x && return one(T)/2
    p[k+1] == x && return one(T)/2
    return zero(T)
end

grid(L::HeavisideSpline) = L.points[1:end-1] .+ diff(L.points)/2
grid(L::LinearSpline) = L.points

## Sub-bases

## Mass matrix
function similar(AB::QMul2{<:QuasiAdjoint{<:Any,<:LinearSpline},<:LinearSpline}, ::Type{T}) where T
    n = size(AB,1)
    SymTridiagonal(Vector{T}(undef, n), Vector{T}(undef, n-1))
end
#
@simplify function *(Ac::QuasiAdjoint{<:Any,<:LinearSpline}, B::LinearSpline)
    M = Mul(Ac, B)
    copyto!(similar(M, eltype(M)), M)
end

function copyto!(dest::SymTridiagonal,
                 AB::QMul2{<:QuasiAdjoint{<:Any,<:LinearSpline},<:LinearSpline}) where T
    Ac,B = AB.A,AB.B
    A = parent(Ac)
    A.points == B.points || throw(ArgumentError())
    dv,ev = dest.dv,dest.ev
    x = A.points; n = length(x)
    length(dv) == n || throw(DimensionMismatch())

    dv[1] = (x[2]-x[1])/3
    @inbounds for k = 2:n-1
        dv[k] = (x[k+1]-x[k-1])/3
    end
    dv[n] = (x[n] - x[n-1])/3

    @inbounds for k = 1:n-1
        ev[k] = (x[k+1]-x[k])/6
    end

    dest
end

@simplify function *(Ac::QuasiAdjoint{<:Any,<:HeavisideSpline}, B::HeavisideSpline)
    A = parent(Ac)
    A.points == B.points || throw(ArgumentError("Cannot multiply incompatible splines"))
    Diagonal(diff(A.points))
end

## Derivative
function copyto!(dest::MulQuasiMatrix{<:Any,<:Tuple{<:HeavisideSpline,<:Any}},
                 M::QMul2{<:Derivative,<:LinearSpline})
    D, L = M.A, M.B
    H, A = dest.args
    x = H.points

    axes(dest) == axes(M) || throw(DimensionMismatch("axes must be same"))
    x == L.points || throw(ArgumentError("Cannot multiply incompatible splines"))
    bandwidths(A) == (0,1) || throw(ArgumentError("Not implemented"))

    d = diff(x)
    A[band(0)] .= inv.((-).(d))
    A[band(1)] .= inv.(d)

    dest
end

function similar(M::QMul2{<:Derivative,<:LinearSpline}, ::Type{T}) where T
    D, B = M.A, M.B
    n = size(B,2)
    ApplyQuasiMatrix(*, HeavisideSpline{T}(B.points),
        BandedMatrix{T}(undef, (n-1,n), (0,1)))
end

@simplify function *(D::Derivative, L::LinearSpline)
    M = Mul(D, L)
    copyto!(similar(M, eltype(M)), M)
end

##
# sum
##

function _sum(A::HeavisideSpline, dims)
    @assert dims == 1
    permutedims(diff(A.points))
end

function _sum(P::LinearSpline, dims)
    d = diff(P.points)
    ret = Array{float(eltype(d))}(undef, length(d)+1)
    ret[1] = d[1]/2
    for k = 2:length(d)
        ret[k] = (d[k-1] + d[k])/2
    end
    ret[end] = d[end]/2
    permutedims(ret)
end

_cumsum(H::HeavisideSpline{T}, dims) where T = LinearSpline(H.points) * tril(Ones{T}(length(H.points),length(H.points)-1) .* diff(H.points)',-1)


text:
### A Pluto.jl notebook ###
# v0.14.0

using Markdown
using InteractiveUtils

# ╔═╡ 15b8afb9-ace9-4b5b-894e-dce9dda5bf5f
begin
	using Pkg

	try
		using DataFrames

	catch ArgumentError
		Pkg.add("DataFrames")
		using DataFrames
	end
end

# ╔═╡ 9608fdc8-807e-4be2-91f8-950c0ceec2dd
begin
	try
		using CategoricalArrays

	catch ArgumentError
		Pkg.add("CategoricalArrays")
		using CategoricalArrays
	end

	using PlutoUI
	using BenchmarkTools
end

# ╔═╡ 45d72214-919c-11eb-2e69-23c0786baacb
md"""
### Multiple dispatch to handle branching behavior

Src: [Julia 1.0 Cookbook -  Bogumił Kamiński , Przemysław Szufel - 2018](https://www.packtpub.com/product/julia-1-0-programming-cookbook/9781788998369)
"""

# ╔═╡ 25b36455-0e5a-4318-9bd3-0440ac0b0080
df = DataFrame(s = categorical(["a", "b", "c"]),
		n = 1.:3.,
		f = [sin, cos, missing]
		)

# ╔═╡ 173f0e52-1430-457d-ae2f-9277342194a7
typeof(df)

# ╔═╡ ced242ca-2352-4b3f-bf32-a095705756ef
md"""
Let us write a function to display the different types of data:
"""

# ╔═╡ a70143ea-4920-413f-a6c1-515eef6c4f78
begin
	simple_describe(v) = "Unknown Type"

	simple_describe(v::Vector{<: Number}) = "Numeric"

	simple_describe(v::CategoricalArray) = "Categorical"
end

# ╔═╡ 995ebcfe-5e8d-448c-a4ee-f992df4e0404
with_terminal() do
	println(methods(simple_describe))
end

# ╔═╡ 224a9eaa-7062-481f-8af3-098ba1988c5d
md"""
And now we can create a function that walks through a data frame:
"""

# ╔═╡ 6b7104b1-2a92-4278-996d-bf0acd972770
simple_display(df::DataFrame) = foreach(
		attr -> println(attr, ": ", simple_describe(df[!, attr])),
		propertynames(df)
	)

# ╔═╡ e432f0a0-45de-4f23-aab7-09a30b1b7bdc
simple_display₁(df::DataFrame) = foreach(
		c -> println(c[1], ": ", simple_describe(c[2])),
		eachcol(df)
	)

# ╔═╡ 5309bf0c-f34e-4496-8fb3-567f4f66f4e2
with_terminal() do
	simple_display(df)
end

# ╔═╡ ea0410df-31c6-4c95-bd1a-1b2873eade53
with_terminal() do
	simple_display₁(df)
end

# ╔═╡ 20453809-0799-43ba-a2a5-528cf462e3c5
md"""
**Remarks**

Such an approach to dispatching is not only convenient but can also speed up computations. In particular, the DataFrame type does not convey information about column type to the compiler, so this technique is especially useful. It is called a *barrier function*.
"""

# ╔═╡ 62b4299f-fc9c-4774-b0f4-5ea1bc2a53a6
ndf = DataFrame(x=1:10^6)

# ╔═╡ 4ae4fc10-2ce1-4240-9988-f1a37646c8e8
function helper(x)
	s = zero(eltype(x))
	for v ∈ x; s += v; end
	s
end

# ╔═╡ 2d7c22b4-9843-44d0-84e6-c8e53a4fbf73
function fn1(df)
	s = eltype(df[!, 1]) |> zero
	for v ∈ df[!, 1]; s += v; end
	s
end

# ╔═╡ b4d08c1c-7b97-429f-9c22-e5d18c43b89b
fn2(df) = helper(df[!, 1])

# ╔═╡ b4bb2738-7049-4045-8735-f7d1f1bf0313
with_terminal() do
	@btime fn1(ndf)
end

# ╔═╡ e23a7eb8-d676-49e5-9984-f2d6a93c3a19
with_terminal() do
	@btime fn2(ndf)
end

# ╔═╡ 85f955f5-0802-4738-8a90-88772b575ba2
md"""
The reason for the difference is that `fn1` is not specialized by the `Julia compiler` to the type of `df[!, 1]`, while in `fn2`, the work is passed to a helper function that knows the type of `x` at compilation time, and `Julia` is able to generate efficient code computing the desired value.
"""

# ╔═╡ Cell order:
# ╟─45d72214-919c-11eb-2e69-23c0786baacb
# ╠═15b8afb9-ace9-4b5b-894e-dce9dda5bf5f
# ╠═9608fdc8-807e-4be2-91f8-950c0ceec2dd
# ╠═25b36455-0e5a-4318-9bd3-0440ac0b0080
# ╠═173f0e52-1430-457d-ae2f-9277342194a7
# ╟─ced242ca-2352-4b3f-bf32-a095705756ef
# ╠═a70143ea-4920-413f-a6c1-515eef6c4f78
# ╠═995ebcfe-5e8d-448c-a4ee-f992df4e0404
# ╟─224a9eaa-7062-481f-8af3-098ba1988c5d
# ╠═6b7104b1-2a92-4278-996d-bf0acd972770
# ╠═e432f0a0-45de-4f23-aab7-09a30b1b7bdc
# ╠═5309bf0c-f34e-4496-8fb3-567f4f66f4e2
# ╠═ea0410df-31c6-4c95-bd1a-1b2873eade53
# ╟─20453809-0799-43ba-a2a5-528cf462e3c5
# ╠═62b4299f-fc9c-4774-b0f4-5ea1bc2a53a6
# ╠═4ae4fc10-2ce1-4240-9988-f1a37646c8e8
# ╠═2d7c22b4-9843-44d0-84e6-c8e53a4fbf73
# ╠═b4d08c1c-7b97-429f-9c22-e5d18c43b89b
# ╠═b4bb2738-7049-4045-8735-f7d1f1bf0313
# ╠═e23a7eb8-d676-49e5-9984-f2d6a93c3a19
# ╟─85f955f5-0802-4738-8a90-88772b575ba2

max_stars_repo_name: pascal-p/julia-notebooks

max_issues_repo_name: pascal-p/julia-notebooks

max_forks_repo_name: pascal-p/julia-notebooks


text:
using Images

arr=rand(3,512,512)
img=colorview(RGB,arr)

clipped = img[1:224,1:224]

max_stars_repo_name: terasakisatoshi/juliaExer

max_issues_repo_name: terasakisatoshi/juliaExer

max_forks_repo_name: terasakisatoshi/juliaExer