text:
#ODBC API Function Definitions
#By Jacob Quinn, 2013
#In general, the ODBC functions are implemented to mirror the C header files (sql.h,sqlext.h,sqltypes.h,sqlucode.h)
#A few liberties are taken in utliizing standard Julia functions and idioms
#Format:
 #function name
 #URL reference
 #short function description
 #valid const definitions
 #relevant notes
 #working and tested status
 #function definition code

#Contents
 #Macros and Utility Functions
 #Handle Functions
 #Connection Functions
 #Resultset Metadata Functions
 #Query Functions
 #Resultset Retrieval Functions
 #DBMS Meta Functions
 #Error Handling and Diagnostics

###################################################		Macros and Utility Functions	####################################################################################################

#MULTIROWFETCH sets the default rowset fetch size used in retrieving resultset blocks from queries
const MULTIROWFETCH = 65535 #1024

const SQL_SUCCESS = int16(0)
const SQL_SUCCESS_WITH_INFO = int16(1)

const SQL_ERROR = int16(-1)
const SQL_INVALID_HANDLE = int16(-2)
const SQL_STILL_EXECUTING = int16(2)
const SQL_NO_DATA = int16(100)
#const SQL_PARAM_DATA_AVAILABLE
const RETURN_VALUES = [SQL_ERROR=>"SQL_ERROR",SQL_INVALID_HANDLE=>"SQL_INVALID_HANDLE",SQL_STILL_EXECUTING=>"SQL_STILL_EXECUTING",SQL_NO_DATA=>"SQL_NO_DATA"]

#Macros to to check if a function returned a success value or not; used with 'if' statements
#e.g. if @SUCCEEDED SQLDisconnect(dbc) print("Disconnected successfully") end
#ret_lu takes a function's return code and returns a text version by looking up its value in the RETURN_VALUES dict (defined above)
function ret_lu(ret)
	return get(RETURN_VALUES,ret,"SQL_DEFAULT_ERROR")
end

macro SUCCEEDED(func)
	global ret = ret_lu(func)
	:( return_code = $func; (return_code == SQL_SUCCESS || return_code == SQL_SUCCESS_WITH_INFO) ? true : false )
end

macro FAILED(func)
	global ret = ret_lu(func)
	:( return_code = $func; (return_code != SQL_SUCCESS && return_code != SQL_SUCCESS_WITH_INFO) ? true : false )
end

#http://msdn.microsoft.com/en-us/library/windows/desktop/ms712400(v=vs.85).aspx
function SQLDrivers(env::Ptr{Void},driver_desc::Array{Uint8,1},desc_length::Array{Int16,1},driver_attr::Array{Uint8,1},attr_length::Array{Int16,1})
	@windows_only ret = ccall( (:SQLDrivers, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int16,Ptr{Uint8},Int16,Ptr{Int16},Ptr{Uint8},Int16,Ptr{Int16}),
		env,SQL_FETCH_NEXT,driver_desc,length(driver_desc),desc_length,driver_attr,length(driver_attr),attr_length)
	@unix_only ret = ccall( (:SQLDrivers, odbc_dm),
			Int16, (Ptr{Void},Int16,Ptr{Uint8},Int16,Ptr{Int16},Ptr{Uint8},Int16,Ptr{Int16}),
			env,SQL_FETCH_NEXT,driver_desc,length(driver_desc),desc_length,driver_attr,length(driver_attr),attr_length)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms711004(v=vs.85).aspx
function SQLDataSources(env::Ptr{Void},dsn_desc::Array{Uint8,1},desc_length::Array{Int16,1},dsn_attr::Array{Uint8,1},attr_length::Array{Int16,1})
	@windows_only ret = ccall( (:SQLDataSources, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int16,Ptr{Uint8},Int16,Ptr{Int16},Ptr{Uint8},Int16,Ptr{Int16}),
		env,SQL_FETCH_NEXT,dsn_desc,length(dsn_desc),desc_length,dsn_attr,length(dsn_attr),attr_length)
	@unix_only ret = ccall( (:SQLDataSources, odbc_dm),
			Int16, (Ptr{Void},Int16,Ptr{Uint8},Int16,Ptr{Int16},Ptr{Uint8},Int16,Ptr{Int16}),
			env,SQL_FETCH_NEXT,dsn_desc,length(dsn_desc),desc_length,dsn_attr,length(dsn_attr),attr_length)
	return ret
end

###################################################		Handle Functions	####################################################################################################
#SQLAllocHandle
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms712455(v=vs.85).aspx
 #Description: allocates an environment, connection, statement, or descriptor handle
 #Valid handle types
 const SQL_HANDLE_ENV = int16(1)
 const SQL_HANDLE_DBC = int16(2)
 const SQL_HANDLE_STMT = int16(3)
 const SQL_HANDLE_DESC = int16(4)
 const SQL_NULL_HANDLE = C_NULL
 #Status: Tested on Windows, Linux, Mac 32/64-bit
function SQLAllocHandle(handletype::Int16, parenthandle::Ptr{Void}, handle::Array{Ptr{Void},1})
	@windows_only ret = ccall( (:SQLAllocHandle, odbc_dm), stdcall,
		Int16, (Int16,Ptr{Void},Ptr{Void}),
		handletype,parenthandle,handle)
	@unix_only ret = ccall( (:SQLAllocHandle, odbc_dm),
			Int16, (Int16,Ptr{Void},Ptr{Void}),
			handletype,parenthandle,handle)
	return ret
end
#SQLFreeHandle
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms710123(v=vs.85).aspx
 #Description: frees resources associated with a specific environment, connection, statement, or descriptor handle
 #See SQLAllocHandle for valid handle types
 #Status: Tested on Windows, Linux, Mac 32/64-bit
function SQLFreeHandle(handletype::Int16,handle::Ptr{Void})
	@windows_only ret = ccall( (:SQLFreeHandle, odbc_dm), stdcall,
		Int16, (Int16,Ptr{Void}),
		handletype,handle)
	@unix_only ret = ccall( (:SQLFreeHandle, odbc_dm),
			Int16, (Int16,Ptr{Void}),
			handletype,handle)
	return ret
end
#SQLSetEnvAttr
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms709285(v=vs.85).aspx
 #Description: sets attributes that govern aspects of environments
 #Valid attributes; valid values for attribute are indented
 const SQL_ATTR_CONNECTION_POOLING = 201
	const SQL_CP_OFF = uint(0)
	const SQL_CP_ONE_PER_DRIVER = uint(1)
	const SQL_CP_ONE_PER_HENV = uint(2)
	#const SQL_CP_DRIVER_AWARE =
	const SQL_CP_DEFAULT = SQL_CP_OFF
 const SQL_ATTR_CP_MATCH = 202
	const SQL_CP_RELAXED_MATCH = uint(1)
	const SQL_CP_STRICT_MATCH = uint(0)
 const SQL_ATTR_ODBC_VERSION = 200
	const SQL_OV_ODBC2 = 2
	const SQL_OV_ODBC3 = 3
	#const SQL_OV_ODBC3_80 =
 const SQL_ATTR_OUTPUT_NTS = 10001
	const SQL_TRUE = 1
	const SQL_FALSE = 0
 #Status: Tested on Windows, Linux, Mac 32/64-bit
function SQLSetEnvAttr{T<:Union(Int,Uint)}(env_handle::Ptr{Void},attribute::Int,value::T)
	@windows_only ret = ccall( (:SQLSetEnvAttr, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int,T,Int),
		env_handle,attribute,value,0)
	@unix_only ret = ccall( (:SQLSetEnvAttr, odbc_dm),
			Int16, (Ptr{Void},Int,T,Int),
			env_handle,attribute,value,0)
	return ret
end
#SQLGetEnvAttr
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms709276(v=vs.85).aspx
 #Description: returns the current setting of an environment attribute
 #Valid attributes: See SQLSetEnvAttr
 #Status:
function SQLGetEnvAttr(env::Ptr{Void},attribute::Int,value::Array{Int,1},bytes_returned::Array{Int,1})
	@windows_only ret = ccall( (:SQLGetEnvAttr, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int,Ptr{Int},Int,Ptr{Int}),
		env,attribute,value,0,bytes_returned)
	@unix_only ret = ccall( (:SQLGetEnvAttr, odbc_dm),
			Int16, (Ptr{Void},Int,Ptr{Int},Int,Ptr{Int}),
			env,attribute,value,0,bytes_returned)
	return ret
end
#SQLSetConnectAttr
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms713605(v=vs.85).aspx
 #Description: sets attributes that govern aspects of connections.
 #Valid attributes
	const SQL_ATTR_ACCESS_MODE = 101
		const SQL_MODE_READ_ONLY = uint(1)
		const SQL_MODE_READ_WRITE = uint(0)
	#const SQL_ATTR_ASYNC_DBC_EVENT
		#pointer
	#const SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE
		#const SQL_ASYNC_DBC_ENABLE_ON = uint()
		#const SQL_ASYNC_DBC_ENABLE_OFF = uint()
	#const SQL_ATTR_ASYNC_DBC_PCALLBACK
		#pointer
	#const SQL_ATTR_ASYNC_DBC_PCONTEXT
		#pointer
	const SQL_ATTR_ASYNC_ENABLE = 4
		const SQL_ASYNC_ENABLE_OFF = uint(0)
		const SQL_ASYNC_ENABLE_ON = uint(1)
	const SQL_ATTR_AUTOCOMMIT = 102
		const SQL_AUTOCOMMIT_OFF = uint(0)
		const SQL_AUTOCOMMIT_ON = uint(1)
	const SQL_ATTR_CONNECTION_TIMEOUT = 113
		#uint of how long you want the connection timeout
	const SQL_ATTR_CURRENT_CATALOG = 109
		#string/Ptr{Uint8} of default database to use
	#const SQL_ATTR_DBC_INFO_TOKEN
		#pointer
	const SQL_ATTR_ENLIST_IN_DTC = 1207
		#pointer: Pass a DTC OLE transaction object that specifies the transaction to export to SQL Server, or SQL_DTC_DONE to end the connection's DTC association.
	const SQL_ATTR_LOGIN_TIMEOUT = 103
		#uint of how long you want the login timeout
	const SQL_ATTR_METADATA_ID = 10014
		#SQL_TRUE, SQL_FALSE
	const SQL_ATTR_ODBC_CURSORS = 110
		const SQL_CUR_USE_IF_NEEDED = uint(0)
		const SQL_CUR_USE_ODBC = uint(1)
		const SQL_CUR_USE_DRIVER = uint(2)
	const SQL_ATTR_PACKET_SIZE = 112
		#uint for network packet size
	const SQL_ATTR_QUIET_MODE = 111
		#window handle pointer
	const SQL_ATTR_TRACE = 104
		const SQL_OPT_TRACE_OFF = uint(0)
		const SQL_OPT_TRACE_ON = uint(1)
	const SQL_ATTR_TRACEFILE = 105
		#A null-terminated character string containing the name of the trace file.
	const SQL_ATTR_TRANSLATE_LIB = 106
		#A null-terminated character string containing the name of a library containing the functions SQLDriverToDataSource and SQLDataSourceToDriver that the driver accesses to perform tasks such as character set translation.
	const SQL_ATTR_TRANSLATE_OPTION = 107
		#A 32-bit flag value that is passed to the translation DLL.
	const SQL_ATTR_TXN_ISOLATION = 108
		#A 32-bit bitmask that sets the transaction isolation level for the current connection.
	#Valid value_length
	const SQL_IS_POINTER = -4
	const SQL_IS_INTEGER = -6
	const SQL_IS_UINTEGER = -5
	const SQL_NTS = -3
	#length of string or binary stream
 #Status:
function SQLSetConnectAttr(dbc::Ptr{Void},attribute::Int,value::Union(String,Uint),value_length::Int)
	@windows_only ret = ccall( (:SQLSetConnectAttr, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int,typeof(value)==String?Ptr{Uint8}:Ptr{Uint},Int),
		dbc,attribute,value,value_length)
	@unix_only ret = ccall( (:SQLSetConnectAttr, odbc_dm),
			Int16, (Ptr{Void},Int,typeof(value)==String?Ptr{Uint8}:Ptr{Uint},Int),
			dbc,attribute,value,value_length)
	return ret
end
#SQLGetConnectAttr
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms710297(v=vs.85).aspx
 #Description: returns the current setting of a connection attribute.
 #Valid attributes: see SQLSetConnectAttr in addition to those below
	const SQL_ATTR_AUTO_IPD = 10001
		#SQL_TRUE, SQL_FALSE
	const SQL_ATTR_CONNECTION_DEAD = 1209
		const SQL_CD_TRUE = 1
		const SQL_CD_FALSE = 0
 #Status:
function SQLGetConnectAttr{T,N}(dbc::Ptr{Void},attribute::Int,value::Array{T,N},bytes_returned::Array{Int,1})
	@windows_only ret = ccall( (:SQLGetConnectAttr, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int,Ptr{T},Int,Ptr{Int}),
		dbc,attribute,value,sizeof(T)*N,bytes_returned)
	@unix_only ret = ccall( (:SQLGetConnectAttr, odbc_dm),
			Int16, (Ptr{Void},Int,Ptr{T},Int,Ptr{Int}),
			dbc,attribute,value,sizeof(T)*N,bytes_returned)
	return ret
end
#SQLSetStmtAttr
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms712631(v=vs.85).aspx
 #Description: sets attributes related to a statement.
 #Valid attributes
	const SQL_ATTR_ROW_STATUS_PTR = 25
	const SQL_ATTR_ROWS_FETCHED_PTR  = 26
	const SQL_ATTR_ROW_ARRAY_SIZE = 27
		#this sets the rowset size for ExtendedFetch and FetchScroll
 #Valid value_length: See SQLSetConnectAttr; SQL_IS_POINTER, SQL_IS_INTEGER, SQL_IS_UINTEGER, SQL_NTS
 #Status:
function SQLSetStmtAttr(stmt::Ptr{Void},attribute::Int,value::Uint,value_length::Int)
	@windows_only ret = ccall( (:SQLSetStmtAttr, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int,Uint,Int),
		stmt,attribute,value,value_length)
	@unix_only ret = ccall( (:SQLSetStmtAttr, odbc_dm),
			Int16, (Ptr{Void},Int,Uint,Int),
			stmt,attribute,value,value_length)
	return ret
end
function SQLSetStmtAttr(stmt::Ptr{Void},attribute::Int,value::Array{Int},value_length::Int)
	@windows_only ret = ccall( (:SQLSetStmtAttr, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int,Ptr{Int},Int),
		stmt,attribute,value,value_length)
	@unix_only ret = ccall( (:SQLSetStmtAttr, odbc_dm),
			Int16, (Ptr{Void},Int,Ptr{Int},Int),
			stmt,attribute,value,value_length)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms715438(v=vs.85).aspx
function SQLGetStmtAttr{T,N}(stmt::Ptr{Void},attribute::Int,value::Array{T,N},bytes_returned::Array{Int,1})
	@windows_only ret = ccall( (:SQLGetStmtAttr, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int,Ptr{T},Int,Ptr{Int}),
		stmt,attribute,value,sizeof(T)*N,bytes_returned)
	@unix_only ret = ccall( (:SQLGetStmtAttr, odbc_dm),
			Int16, (Ptr{Void},Int,Ptr{T},Int,Ptr{Int}),
			stmt,attribute,value,sizeof(T)*N,bytes_returned)
	return ret
end
#SQLFreeStmt
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms709284(v=vs.85).aspx
 #Description: stops processing associated with a specific statement, closes any open cursors associated with the statement, discards pending results, or, optionally, frees all resources associated with the statement handle.
 #Valid param
	const SQL_CLOSE = uint16(0)
	const SQL_RESET_PARAMS = uint16(3)
	const SQL_UNBIND = uint16(2)
 #Status:
function SQLFreeStmt(stmt::Ptr{Void},param::Uint16)
	@windows_only ret = ccall( (:SQLFreeStmt, odbc_dm), stdcall,
		Int16, (Ptr{Void},Uint16),
		stmt, param)
	@unix_only ret = ccall( (:SQLFreeStmt, odbc_dm),
			Int16, (Ptr{Void},Uint16),
			stmt, param)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms713560(v=vs.85).aspx
function SQLSetDescField{T,N}(desc::Ptr{Void},i::Int16,field_id::Int16,value::Array{T,N},value_length::Array{Int,1})
	@windows_only ret = ccall( (:SQLSetDescField, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int16,Int16,Ptr{T},Int),
		desc,field_id,value,value_length)
	@unix_only ret = ccall( (:SQLSetDescField, odbc_dm),
			Int16, (Ptr{Void},Int16,Int16,Ptr{T},Int),
			desc,field_id,value,value_length)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms716370(v=vs.85).aspx
function SQLGetDescField{T,N}(desc::Ptr{Void},i::Int16,attribute::Int16,value::Array{T,N},bytes_returned::Array{Int,1})
	@windows_only ret = ccall( (:SQLGetDescField, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int16,Int16,Ptr{T},Int,Ptr{Int}),
		desc,attribute,value,sizeof(T)*N,bytes_returned)
	@unix_only ret = ccall( (:SQLGetDescField, odbc_dm),
			Int16, (Ptr{Void},Int16,Int16,Ptr{T},Int,Ptr{Int}),
			desc,attribute,value,sizeof(T)*N,bytes_returned)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms710921(v=vs.85).aspx
function SQLGetDescRec(desc::Ptr{Void},i::Int16,name::Array{Uint8,1},name_length::Array{Int16,1},type_ptr::Array{Int16,1},subtype_ptr::Array{Int16,1},length_ptr::Array{Int,1},precision_ptr::Array{Int16,1},scale_ptr::Array{Int16,1},nullable_ptr::Array{Int16,1},)
	@windows_only ret = ccall( (:SQLGetDescRec, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int16,Ptr{Uint8},Int16,Ptr{Int16},Ptr{Int16},Ptr{Int16},Ptr{Int},Ptr{Int16},Ptr{Int16},Ptr{Int16}),
		desc,i,name,length(name),name_length,type_ptr,subtype_ptr,length_ptr,precision_ptr,scale_ptr,nullable_ptr)
	@unix_only ret = ccall( (:SQLGetDescRec, odbc_dm),
			Int16, (Ptr{Void},Int16,Ptr{Uint8},Int16,Ptr{Int16},Ptr{Int16},Ptr{Int16},Ptr{Int},Ptr{Int16},Ptr{Int16},Ptr{Int16}),
			desc,i,name,length(name),name_length,type_ptr,subtype_ptr,length_ptr,precision_ptr,scale_ptr,nullable_ptr)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms715378(v=vs.85).aspx
function SQLCopyDesc(source_desc::Ptr{Void},dest_desc::Ptr{Void})
	@windows_only ret = ccall( (:SQLCopyDesc, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Void}),
		source_desc,dest_desc)
	@unix_only ret = ccall( (:SQLCopyDesc, odbc_dm),
			Int16, (Ptr{Void},Ptr{Void}),
			source_desc,dest_desc)
	return ret
end

###################################################		Connection Functions	####################################################################################################
#SQLConnect
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms711810(v=vs.85).aspx
 #Description: establishes connections to a driver and a data source
 #Status:
function SQLConnect(dbc::Ptr{Void},dsn::String,username::String,password::String)
	@windows_only ret = ccall( (:SQLConnect, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
		dbc,dsn,length(dsn),username,length(username),password,length(password))
	@unix_only ret = ccall( (:SQLConnect, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
			dbc,dsn,length(dsn),username,length(username),password,length(password))
	return ret
end
#SQLDriverConnect
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms715433(v=vs.85).aspx
 #Description:
 #Valid driver_prompt
	const SQL_DRIVER_COMPLETE = uint16(1)
	const SQL_DRIVER_COMPLETE_REQUIRED = uint16(3)
	const SQL_DRIVER_NOPROMPT = uint16(0)
	const SQL_DRIVER_PROMPT = uint16(2)
 #Status:
function SQLDriverConnect(dbc::Ptr{Void},window_handle::Ptr{Void},conn_string::String,out_conn::Ptr{Void},out_buff::Array{Int16,1},driver_prompt::Uint16)
	@windows_only ret = ccall( (:SQLDriverConnect, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Void},Ptr{Uint8},Int16,Ptr{Void},Int16,Ptr{Int16},Uint16),
		dbc,window_handle,conn_string,length(conn_string),out_conn,0,out_buff,driver_prompt)
	@unix_only ret = ccall( (:SQLDriverConnect, odbc_dm),
			Int16, (Ptr{Void},Ptr{Void},Ptr{Uint8},Int16,Ptr{Void},Int16,Ptr{Int16},Uint16),
			dbc,window_handle,conn_string,length(conn_string),out_conn,0,out_buff,driver_prompt)
	return ret
end
#SQLBrowseConnect
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms714565(v=vs.85).aspx
 #Description: supports an iterative method of discovering and enumerating the attributes and attribute values required to connect to a data source
 #Status:
function SQLBrowseConnect(dbc::Ptr{Void},instring::String,outstring::Array{Uint8,1},indicator::Array{Int16,1})
	@windows_only ret = ccall( (:SQLBrowseConnect, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Int16}),
		dbc,instring,length(instring),outstring,length(outstring),indicator)
	@unix_only ret = ccall( (:SQLBrowseConnect, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Int16}),
			dbc,instring,length(instring),outstring,length(outstring),indicator)
	return ret
end
#SQLDisconnect
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms713946(v=vs.85).aspx
 #Description: closes the connection associated with a specific connection handle
 #Status:
function SQLDisconnect(dbc::Ptr{Void})
	@windows_only ret = ccall( (:SQLDisconnect, odbc_dm), stdcall,
		Int16, (Ptr{Void},),
		dbc)
	@unix_only ret = ccall( (:SQLDisconnect, odbc_dm),
			Int16, (Ptr{Void},),
			dbc)
	return ret
end
#SQLGetFunctions
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms709291(v=vs.85).aspx
 #Descriptions:
 #Valid functionid

 #supported will be SQL_TRUE or SQL_FALSE
 #Status:
 #Major TODO
function SQLGetFunctions(dbc::Ptr{Void},functionid::Uint16,supported::Array{Uint16,1})
	@windows_only ret = ccall( (:SQLGetFunctions, odbc_dm), stdcall,
		Int16, (Ptr{Void},Uint16,Ptr{Uint16}),
		dbc,functionid,supported)
	@unix_only ret = ccall( (:SQLGetFunctions, odbc_dm),
			Int16, (Ptr{Void},Uint16,Ptr{Uint16}),
			dbc,functionid,supported)
	return ret
end
#SQLGetInfo
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms711681(v=vs.85).aspx
 #Description:
 #Status:
 #Major TODO
function SQLGetInfo{T,N}(dbc::Ptr{Void},attribute::Int,value::Array{T,N},bytes_returned::Array{Int,1})
	@windows_only ret = ccall( (:SQLGetInfo, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int,Ptr{T},Int,Ptr{Int}),
		dbc,attribute,value,sizeof(T)*N,bytes_returned)
	@unix_only ret = ccall( (:SQLGetInfo, odbc_dm),
			Int16, (Ptr{Void},Int,Ptr{T},Int,Ptr{Int}),
			dbc,attribute,value,sizeof(T)*N,bytes_returned)
	return ret
end

###################################################		Query Functions	####################################################################################################
#SQLNativeSql
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms714575(v=vs.85).aspx
 #Description: returns the SQL string as modified by the driver
 #Status:
function SQLNativeSql(dbc::Ptr{Void},query_string::String,output_string::Array{Uint8,1},length_ind::Array{Int,1})
	@windows_only ret = ccall( (:SQLNativeSql, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int,Ptr{Uint8},Int,Ptr{Int}),
		dbc,query_string,length(query_string),output_string,length(output_string),length_ind)
	@unix_only ret = ccall( (:SQLNativeSql, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int,Ptr{Uint8},Int,Ptr{Int}),
			dbc,query_string,length(query_string),output_string,length(output_string),length_ind)
	return ret
end
#SQLGetTypeInfo
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms714632(v=vs.85).aspx
 #Description:
 #valid sqltype
	#const SQL_ALL_TYPES =

 #Status:
function SQLGetTypeInfo(stmt::Ptr{Void},sqltype::Int16)
	@windows_only ret = ccall( (:SQLGetTypeInfo, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int16),
		stmt,sqltype)
	@unix_only ret = ccall( (:SQLGetTypeInfo, odbc_dm),
			Int16, (Ptr{Void},Int16),
			stmt,sqltype)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms713824(v=vs.85).aspx
function SQLPutData{T}(stmt::Ptr{Void},data::Array{T},data_length::Int)
	@windows_only ret = ccall( (:SQLPutData, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{T},Int),
		stmt,data,data_length)
	@unix_only ret = ccall( (:SQLPutData, odbc_dm),
			Int16, (Ptr{Void},Ptr{T},Int),
			stmt,data,data_length)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms710926(v=vs.85).aspx
function SQLPrepare(stmt::Ptr{Void},query_string::String)
	@windows_only ret = ccall( (:SQLPrepare, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16),
		stmt,query_string,length(query_string))
	@unix_only ret = ccall( (:SQLPrepare, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16),
			stmt,query_string,length(query_string))
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms713584(v=vs.85).aspx
function SQLExecute(stmt::Ptr{Void})
	@windows_only ret = ccall( (:SQLExecute, odbc_dm), stdcall,
		Int16, (Ptr{Void},),
		stmt)
	@unix_only ret = ccall( (:SQLExecute, odbc_dm),
			Int16, (Ptr{Void},),
			stmt)
	return ret
end
#SQLExecDirect
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms713611(v=vs.85).aspx
 #Description: executes a preparable statement
 #Status:
function SQLExecDirect(stmt::Ptr{Void},query::String)
	@windows_only ret = ccall( (:SQLExecDirect, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int),
		stmt,query,length(query))
	@unix_only ret = ccall( (:SQLExecDirect, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int),
			stmt,query,length(query))
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms714112(v=vs.85).aspx
function SQLCancel(stmt::Ptr{Void})
	@windows_only ret = ccall( (:SQLCancel, odbc_dm), stdcall,
		Int16, (Ptr{Void},),
		stmt)
	@unix_only ret = ccall( (:SQLCancel, odbc_dm),
			Int16, (Ptr{Void},),
			stmt)
	return ret
end

###################################################		Resultset Metadata Functions	####################################################################################################
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms715393(v=vs.85).aspx
function SQLNumResultCols(stmt::Ptr{Void},cols::Array{Int16,1})
	@windows_only ret = ccall( (:SQLNumResultCols, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Int16}),
		stmt, cols)
	@unix_only ret = ccall( (:SQLNumResultCols, odbc_dm),
			Int16, (Ptr{Void},Ptr{Int16}),
			stmt, cols)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms711835(v=vs.85).aspx
function SQLRowCount(stmt::Ptr{Void},rows::Array{Int,1})
	@windows_only ret = ccall( (:SQLRowCount, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Int}),
		stmt, rows)
	@unix_only ret = ccall( (:SQLRowCount, odbc_dm),
			Int16, (Ptr{Void},Ptr{Int}),
			stmt, rows)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms713558(v=vs.85).aspx
function SQLColAttribute(stmt::Ptr{Void},x::Int,)
	@windows_only ret = ccall( (:SQLColAttribute, odbc_dm), stdcall,
		Int16, (Ptr{Void},Uint16,Uint16,Ptr,Int16,Ptr{Int16},Ptr{Int}),
		stmt,x,)
	@unix_only ret = ccall( (:SQLColAttribute, odbc_dm),
			Int16, (Ptr{Void},Uint16,Uint16,Ptr,Int16,Ptr{Int16},Ptr{Int}),
			stmt,x,)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms716289(v=vs.85).aspx
function SQLDescribeCol(stmt::Ptr{Void},x::Int,column_name::Array{Uint8,1},name_length::Array{Int16,1},datatype::Array{Int16,1},column_size::Array{Int,1},decimal_digits::Array{Int16,1},nullable::Array{Int16,1})
	@windows_only ret = ccall( (:SQLDescribeCol, odbc_dm), stdcall,
		Int16, (Ptr{Void},Uint16,Ptr{Uint8},Int16,Ptr{Int16},Ptr{Int16},Ptr{Uint},Ptr{Int16},Ptr{Int16}),
		stmt,x,column_name,length(column_name),name_length,datatype,column_size,decimal_digits,nullable)
	@unix_only ret = ccall( (:SQLDescribeCol, odbc_dm),
			Int16, (Ptr{Void},Uint16,Ptr{Uint8},Int16,Ptr{Int16},Ptr{Int16},Ptr{Uint},Ptr{Int16},Ptr{Int16}),
			stmt,x,column_name,length(column_name),name_length,datatype,column_size,decimal_digits,nullable)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms710188(v=vs.85).aspx
function SQLDescribeParam(stmt::Ptr{Void},x::Int,sqltype::Array{Int16,1},column_size::Array{Int,1},decimal_digits::Array{Int16,1},nullable::Array{Int16,1})
	@windows_only ret = ccall( (:SQLDescribeParam, odbc_dm), stdcall,
		Int16, (Ptr{Void},Uint16,Ptr{Int16},Ptr{Int},Ptr{Int16},Ptr{Int16}),
		stmt,x,sqltype,column_size,decimal_digits,nullable)
	@unix_only ret = ccall( (:SQLDescribeParam, odbc_dm),
			Int16, (Ptr{Void},Uint16,Ptr{Int16},Ptr{Int},Ptr{Int16},Ptr{Int16}),
			stmt,x,sqltype,column_size,decimal_digits,nullable)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms712366(v=vs.85).aspx
function SQLParamData(stmt::Ptr{Void},ptr_buffer::Array{Ptr{Void},1})
	@windows_only ret = ccall( (:SQLParamData, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Void}),
		stmt,ptr_buffer)
	@unix_only ret = ccall( (:SQLParamData, odbc_dm),
			Int16, (Ptr{Void},Ptr{Void}),
			stmt,ptr_buffer)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms715409(v=vs.85).aspx
function SQLNumParams(stmt::Ptr{Void},param_count::Array{Int16,1})
	@windows_only ret = ccall( (:SQLNumParams, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Int16}),
		stmt,param_count)
	@unix_only ret = ccall( (:SQLNumParams, odbc_dm),
			Int16, (Ptr{Void},Ptr{Int16}),
			stmt,param_count)
	return ret
end

###################################################		Resultset Retrieval Functions	####################################################################################################
#SQLBindParameter
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms710963(v=vs.85).aspx
 #Description:
 #valid iotype
	const SQL_PARAM_INPUT = int16(1) #SQLBindParameter
	const SQL_PARAM_OUTPUT = int16(4) #SQLBindParameter
	const SQL_PARAM_INPUT_OUTPUT = int16(2) #SQLBindParameter
	#const SQL_PARAM_INPUT_OUTPUT_STREAM = int16() #SQLBindParameter
	#const SQL_PARAM_OUTPUT_STREAM = int16() #SQLBindParameter
 #Status:
function SQLBindParameter{T}(stmt::Ptr{Void},x::Int,iotype::Int16,ctype::Int16,sqltype::Int16,column_size::Int,decimal_digits::Int,param_value::Array{T},param_size::Int)
	@windows_only ret = ccall( (:SQLBindParameter, odbc_dm), stdcall,
		Int16, (Ptr{Void},Uint16,Int16,Int16,Int16,Uint,Int16,Ptr{T},Int,Ptr{Void}),
		stmt,x,iotype,ctype,sqltype,column_size,decimal_digits,param_value,param_size,C_NULL)
	@unix_only ret = ccall( (:SQLBindParameter, odbc_dm),
			Int16, (Ptr{Void},Uint16,Int16,Int16,Int16,Uint,Int16,Ptr{T},Int,Ptr{Void}),
			stmt,x,iotype,ctype,sqltype,column_size,decimal_digits,param_value,param_size,C_NULL)
	return ret
end
SQLSetParam = SQLBindParameter
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms711010(v=vs.85).aspx
function SQLBindCols{T,N}(stmt::Ptr{Void},x::Int,ctype::Int16,holder::Array{T,N},jlsize::Int,indicator::Array{Int,1})
	@windows_only ret = ccall( (:SQLBindCol, odbc_dm), stdcall,
		Int16, (Ptr{Void},Uint16,Int16,Ptr{T},Int,Ptr{Int}),
		stmt,x,ctype,holder,jlsize,indicator)
	@unix_only ret = ccall( (:SQLBindCol, odbc_dm),
			Int16, (Ptr{Void},Uint16,Int16,Ptr{T},Int,Ptr{Int}),
			stmt,x,ctype,holder,jlsize,indicator)
	return ret
end
function SQLBindCols(stmt::Ptr{Void},x::Int,ctype::Int16,holder::Array{UTF8String,1},jlsize::Int,indicator::Array{Int,1})
	@windows_only ret = ccall( (:SQLBindCol, odbc_dm), stdcall,
		Int16, (Ptr{Void},Uint16,Int16,Ptr{Uint8},Int,Ptr{Int}),
		stmt,x,ctype,holder,jlsize,indicator)
	@unix_only ret = ccall( (:SQLBindCol, odbc_dm),
			Int16, (Ptr{Void},Uint16,Int16,Ptr{Uint8},Int,Ptr{Int}),
			stmt,x,ctype,holder,jlsize,indicator)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms711707(v=vs.85).aspx
function SQLSetCursorName(stmt::Ptr{Void},cursor::String)
	@windows_only ret = ccall( (:SQLSetCursorName, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16),
		stmt,cursor,length(cursor))
	@unix_only ret = ccall( (:SQLSetCursorName, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16),
			stmt,cursor,length(cursor))
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms716209(v=vs.85).aspx
function SQLGetCursorName(stmt::Ptr{Void},cursor::Array{Uint8,1},cursor_length::Array{Int16,1})
	@windows_only ret = ccall( (:SQLGetCursorName, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Int16}),
		stmt,cursor,length(cursor),cursor_length)
	@unix_only ret = ccall( (:SQLGetCursorName, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Int16}),
			stmt,cursor,length(cursor),cursor_length)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms715441(v=vs.85).aspx
function SQLGetData{T,N}(stmt::Ptr{Void},i::Int,ctype::Int16,value::Array{T,N},bytes_returned::Array{Int,1})
	@windows_only ret = ccall( (:SQLGetData, odbc_dm), stdcall,
		Int16, (Ptr{Void},Uint16,Int16,Ptr{T},Int,Ptr{Int}),
		stmt,i,ctype,value,sizeof(T)*N,bytes_returned)
	@unix_only ret = ccall( (:SQLGetData, odbc_dm),
			Int16, (Ptr{Void},Uint16,Int16,Ptr{T},Int,Ptr{Int}),
			stmt,i,ctype,value,sizeof(T)*N,bytes_returned)
	return ret
end
#SQLFetchScroll
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms714682(v=vs.85).aspx
 #Description:
 #valid fetch_orientation
	const SQL_FETCH_NEXT = int16(1)
	const SQL_FETCH_PRIOR = int16(4)
	const SQL_FETCH_FIRST = int16(2)
	const SQL_FETCH_LAST = int16(3)
	const SQL_FETCH_ABSOLUTE = int16(5)
	const SQL_FETCH_RELATIVE = int16(6)
	const SQL_FETCH_BOOKMARK = int16(8)
 #Status:
function SQLFetchScroll(stmt::Ptr{Void},fetch_orientation::Int16,fetch_offset::Int)
	@windows_only ret = ccall( (:SQLFetchScroll, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int16,Int),
		stmt,fetch_orientation,fetch_offset)
	@unix_only ret = ccall( (:SQLFetchScroll, odbc_dm),
			Int16, (Ptr{Void},Int16,Int),
			stmt,fetch_orientation,fetch_offset)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms713591(v=vs.85).aspx
function SQLExtendedFetch(stmt::Ptr{Void},fetch_orientation::Uint16,fetch_offset::Int,row_count_ptr::Array{Int,1},row_status_array::Array{Int16,1})
	@windows_only ret = ccall( (:SQLExtendedFetch, odbc_dm), stdcall,
		Int16, (Ptr{Void},Uint16,Int,Ptr{Int},Ptr{Int16}),
		stmt,fetch_orientation,fetch_offset,row_count_ptr,row_status_array)
	@unix_only ret = ccall( (:SQLExtendedFetch, odbc_dm),
			Int16, (Ptr{Void},Uint16,Int,Ptr{Int},Ptr{Int16}),
			stmt,fetch_orientation,fetch_offset,row_count_ptr,row_status_array)
	return ret
end
#SQLSetPos
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms713507(v=vs.85).aspx
 #Description:
 #valid operation
	const SQL_POSITION = uint16(0) #SQLSetPos
	const SQL_REFRESH = uint16(1) #SQLSetPos
	const SQL_UPDATE = uint16(2) #SQLSetPos
	const SQL_DELETE = uint16(3) #SQLSetPos
 #valid lock_type
	const SQL_LOCK_NO_CHANGE = uint16(0) #SQLSetPos
	const SQL_LOCK_EXCLUSIVE = uint16(1) #SQLSetPos
	const SQL_LOCK_UNLOCK = uint16(2) #SQLSetPos
 #Status
function SQLSetPos{T}(stmt::Ptr{Void},rownumber::T,operation::Uint16,lock_type::Uint16)
	@windows_only ret = ccall( (:SQLSetPos, odbc_dm), stdcall,
		Int16, (Ptr{Void},T,Uint16,Uint16),
		stmt,rownumber,operation,lock_type)
	@unix_only ret = ccall( (:SQLSetPos, odbc_dm),
			Int16, (Ptr{Void},T,Uint16,Uint16),
			stmt,rownumber,operation,lock_type)
	return ret
end #T can be Uint64 or Uint16 it seems
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms714673(v=vs.85).aspx
function SQLMoreResults(stmt::Ptr{Void})
	@windows_only ret = ccall( (:SQLMoreResults, odbc_dm), stdcall,
		Int16, (Ptr{Void},),
		stmt)
	@unix_only ret = ccall( (:SQLMoreResults, odbc_dm),
			Int16, (Ptr{Void},),
			stmt)
	return ret
end
#SQLEndTran
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms716544(v=vs.85).aspx
 #Description:
 #valid completion_type
	const SQL_COMMIT = int16(0) #SQLEndTran
	const SQL_ROLLBACK = int16(1) #SQLEndTran
 #Status:
function SQLEndTran(handletype::Int16,handle::Ptr{Void},completion_type::Int16)
	@windows_only ret = ccall( (:SQLEndTran, odbc_dm), stdcall,
		Int16, (Int16,Ptr{Void},Int16),
		handletype,handle,completion_type)
	@unix_only ret = ccall( (:SQLEndTran, odbc_dm),
			Int16, (Int16,Ptr{Void},Int16),
			handletype,handle,completion_type)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms709301(v=vs.85).aspx
function SQLCloseCursor(stmt::Ptr{Void})
	@windows_only ret = ccall( (:SQLCloseCursor, odbc_dm), stdcall,
		Int16, (Ptr{Void},),
		stmt)
	@unix_only ret = ccall( (:SQLCloseCursor, odbc_dm),
			Int16, (Ptr{Void},),
			stmt)
	return ret
end
#SQLBulkOperations
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms712471(v=vs.85).aspx
 #Description:
 #valid operation
	const SQL_ADD = uint16(4) #SQLBulkOperations
	const SQL_UPDATE_BY_BOOKMARK = uint16(5) #SQLBulkOperations
	const SQL_DELETE_BY_BOOKMARK = uint16(6) #SQLBulkOperations
	const SQL_FETCH_BY_BOOKMARK = uint16(7) #SQLBulkOperations
 #Status:
function SQLBulkOperations(stmt::Ptr{Void},operation::Uint16)
	@windows_only ret = ccall( (:SQLBulkOperations, odbc_dm), stdcall,
		Int16, (Ptr{Void},Uint16),
		stmt,operation)
	@unix_only ret = ccall( (:SQLBulkOperations, odbc_dm),
			Int16, (Ptr{Void},Uint16),
			stmt,operation)
	return ret
end

###################################################		DBMS Meta Functions	####################################################################################################
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms711683(v=vs.85).aspx
function SQLColumns(stmt::Ptr{Void},catalog::String,schema::String,table::String,column::String)
	@windows_only ret = ccall( (:SQLColumnPrivileges, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
		stmt,catalog,length(catalog),schema,length(schema),table,length(table),column,length(column))
	@unix_only ret = ccall( (:SQLColumnPrivileges, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
			stmt,catalog,length(catalog),schema,length(schema),table,length(table),column,length(column))
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms716336(v=vs.85).aspx
function SQLColumnPrivileges(stmt::Ptr{Void},catalog::String,schema::String,table::String,column::String)
	@windows_only ret = ccall( (:SQLColumnPrivileges, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
		stmt,catalog,length(catalog),schema,length(schema),table,length(table),column,length(column))
	@unix_only ret = ccall( (:SQLColumnPrivileges, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
			stmt,catalog,length(catalog),schema,length(schema),table,length(table),column,length(column))
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms709315(v=vs.85).aspx
function SQLForeignKeys(stmt::Ptr{Void},pkcatalog::String,pkschema::String,pktable::String,fkcatalog::String,fkschema::String,fktable::String)
	@windows_only ret = ccall( (:SQLForeignKeys, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
		stmt,pkcatalog,length(pkcatalog),pkschema,length(pkschema),pktable,length(pktable),fkcatalog,length(fkcatalog),fkschema,length(fkschema),fktable,length(fktable))
	@unix_only ret = ccall( (:SQLForeignKeys, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
			stmt,pkcatalog,length(pkcatalog),pkschema,length(pkschema),pktable,length(pktable),fkcatalog,length(fkcatalog),fkschema,length(fkschema),fktable,length(fktable))
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms711005(v=vs.85).aspx
function SQLPrimaryKeys(stmt::Ptr{Void},catalog::String,schema::String,table::String)
	@windows_only ret = ccall( (:SQLPrimaryKeys, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
		stmt,catalog,length(catalog),schema,length(schema),table,length(table))
	@unix_only ret = ccall( (:SQLPrimaryKeys, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
			stmt,catalog,length(catalog),schema,length(schema),table,length(table))
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms711701(v=vs.85).aspx
function SQLProcedureColumns(stmt::Ptr{Void},catalog::String,schema::String,proc::String,column::String)
	@windows_only ret = ccall( (:SQLProcedureColumns, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
		stmt,catalog,length(catalog),schema,length(schema),proc,length(proc),column,length(column))
	@unix_only ret = ccall( (:SQLProcedureColumns, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
			stmt,catalog,length(catalog),schema,length(schema),proc,length(proc),column,length(column))
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms715368(v=vs.85).aspx
function SQLProcedures(stmt::Ptr{Void},catalog::String,schema::String,proc::String)
	@windows_only ret = ccall( (:SQLProcedures, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
		stmt,catalog,length(catalog),schema,length(schema),proc,length(proc))
	@unix_only ret = ccall( (:SQLProcedures, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
			stmt,catalog,length(catalog),schema,length(schema),proc,length(proc))
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms711831(v=vs.85).aspx
function SQLTables(stmt::Ptr{Void},catalog::String,schema::String,table::String,table_type::String)
	@windows_only ret = ccall( (:SQLTables, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
		stmt,catalog,length(catalog),schema,length(schema),table,length(table),table_type,length(table_type))
	@unix_only ret = ccall( (:SQLTables, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
			stmt,catalog,length(catalog),schema,length(schema),table,length(table),table_type,length(table_type))
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms713565(v=vs.85).aspx
function SQLTablePrivileges(stmt::Ptr{Void},catalog::String,schema::String,table::String)
	@windows_only ret = ccall( (:SQLTablePrivileges, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
		stmt,catalog,length(catalog),schema,length(schema),table,length(table))
	@unix_only ret = ccall( (:SQLTablePrivileges, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16),
			stmt,catalog,length(catalog),schema,length(schema),table,length(table))
	return ret
end
#SQLStatistics
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms711022(v=vs.85).aspx
 #Description:
 #valid unique
	const SQL_INDEX_ALL = uint16(1) #SQLStatistics
	const SQL_INDEX_CLUSTERED = uint16(1) #SQLStatistics
	const SQL_INDEX_HASHED = uint16(2) #SQLStatistics
	const SQL_INDEX_OTHER = uint16(3) #SQLStatistics
	const SQL_INDEX_UNIQUE = uint16(0) #SQLStatistics
 #valid reserved
	const SQL_ENSURE = uint16(1) #SQLStatistics
	const SQL_QUICK = uint16(0) #SQLStatistics
 #Status:
function SQLStatistics(stmt::Ptr{Void},catalog::String,schema::String,table::String,unique::Uint16,reserved::Uint16)
	@windows_only ret = ccall( (:SQLStatistics, odbc_dm), stdcall,
		Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Uint16,Uint16),
		stmt,catalog,length(catalog),schema,length(schema),table,length(table),unique,reserved)
	@unix_only ret = ccall( (:SQLStatistics, odbc_dm),
			Int16, (Ptr{Void},Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Uint16,Uint16),
			stmt,catalog,length(catalog),schema,length(schema),table,length(table),unique,reserved)
	return ret
end
#SQLSpecialColumns
 #http://msdn.microsoft.com/en-us/library/windows/desktop/ms714602(v=vs.85).aspx
 #Description:
 #valid id_type
	const SQL_BEST_ROWID = int16(1) #SQLSpecialColumns
	const SQL_ROWVER = int16(2) #SQLSpecialColumns
 #valid scope
	const SQL_SCOPE_CURROW = int16(0) #SQLSpecialColumns
	const SQL_SCOPE_SESSION = int16(2) #SQLSpecialColumns
	const SQL_SCOPE_TRANSACTION = int16(1) #SQLSpecialColumns
 #valid nullable
	const SQL_NO_NULLS = int16(0) #SQLSpecialColumns
	const SQL_NULLABLE = int16(1) #SQLSpecialColumns
	#const SQL_NULLABLE_UNKNOWN = int16() #SQLSpecialColumns
 #Status:
function SQLSpecialColumns(stmt::Ptr{Void},id_type::Int16,catalog::String,schema::String,table::String,scope::Int16,nullable::Int16)
	@windows_only ret = ccall( (:SQLSpecialColumns, odbc_dm), stdcall,
		Int16, (Ptr{Void},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Int16,Int16),
		stmt,id_type,catalog,length(catalog),schema,length(schema),table,length(table),scope,nullable)
	@unix_only ret = ccall( (:SQLSpecialColumns, odbc_dm),
			Int16, (Ptr{Void},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Ptr{Uint8},Int16,Int16,Int16),
			stmt,id_type,catalog,length(catalog),schema,length(schema),table,length(table),scope,nullable)
	return ret
end
###################################################		Error Handling Functions	####################################################################################################
#TODO: add consts
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms710181(v=vs.85).aspx
function SQLGetDiagField(handletype::Int16,handle::Ptr{Void},i::Int16,diag_id::Int16,diag_info::Array{Uint,1},buffer_length::Int16,diag_length::Array{Int16,1})
	@windows_only ret = ccall( (:SQLGetDiagField, odbc_dm), stdcall,
		Int16, (Int16,Ptr{Void},Int16,Int16,Ptr{Uint8},Int16,Ptr{Int16}),
		handletype,handle,i,diag_id,diag_info,buffer_length,msg_length)
	@unix_only ret = ccall( (:SQLGetDiagField, odbc_dm),
			Int16, (Int16,Ptr{Void},Int16,Int16,Ptr{Uint8},Int16,Ptr{Int16}),
			handletype,handle,i,diag_id,diag_info,buffer_length,msg_length)
	return ret
end
#http://msdn.microsoft.com/en-us/library/windows/desktop/ms716256(v=vs.85).aspx
function SQLGetDiagRec(handletype::Int16,handle::Ptr{Void},i::Int16,state::Array{Uint8,1},native::Array{Int,1},error_msg::Array{Uint8,1},msg_length::Array{Int16,1})
	@windows_only ret = ccall( (:SQLGetDiagRec, odbc_dm), stdcall,
		Int16, (Int16,Ptr{Void},Int16,Ptr{Uint8},Ptr{Int},Ptr{Uint8},Int16,Ptr{Int16}),
		handletype,handle,i,state,native,error_msg,length(error_msg),msg_length)
	@unix_only ret = ccall( (:SQLGetDiagRec, odbc_dm),
			Int16, (Int16,Ptr{Void},Int16,Ptr{Uint8},Ptr{Int},Ptr{Uint8},Int16,Ptr{Int16}),
			handletype,handle,i,state,native,error_msg,length(error_msg),msg_length)
	return ret
end


text:
export Vec3d, vec3d, norm2, norm, Ray, ray_at_dist

import Base: show

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

"A 3-D vector. Use `vec3d` to create instances of this object"
const Vec3d = StaticVector{3, Float64}

"""
    vec3d(x, y, z)

Create a `Vec3d` object
"""
vec3d(x, y, z) = SVector{3, Float64}(x, y, z)

"""
    norm2(v::Vec3d)

Squared length of the vector. It is faster to compute than the length, since
no squared-root operation is required.

# Example
```jldoctest
julia> norm2(vec3d(1, 0, 0))
1.0
julia> norm2(vec3d(3, 1, 2))
14.0
```
"""
norm2(v::Vec3d) = v[1]^2 + v[2]^2 + v[3]^2

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

"""
    struct Ray

A ray originating from some point and having a direction. The direction
is always normalized. It contains the following fields:
- `origin`
- `dir`

You can compute the point reached by the ray after some time `t` with the
function `ray_at_dist`. This can be short-handed using the ray as a function:
```jldoctest
julia> r = Ray(vec3d(0, 0, 0), vec3d(1, 0, 0));
julia> ray_at_dist(r, 10) ≈ r(10)
true
```
"""
struct Ray
    "Point where the ray originates"
    origin::Vec3d
    "Normalized direction of the ray"
    dir::Vec3d

    Ray(o, d) = new(o, normalize(d))
end

function show(io::IO, r::Ray)
    println(string("Ray([$(r.origin[1]), $(r.origin[2]), $(r.origin[3])] + ",
                   "t * [$(r.dir[1]), $(r.dir[2]), $(r.dir[3])]"))
end

"""
    ray_at_dist(ray::Ray, dist::Number)

Return the point (a `Vec3d` type) reached by the ray after having
travelled a distance `dist`.
"""
ray_at_dist(ray::Ray, dist::Number) = ray.origin + dist * ray.dir

(r::Ray)(dist::Number) = ray_at_dist(r, dist)

ext: jl


text:
# directly taken from https://github.com/FluxML/Flux.jl/blob/27c4c77dc5abd8e791f4ca4e68a65fc7a91ebcfd/src/utils.jl#L544-L566
batchindex(xs, i) = (reverse(Base.tail(reverse(axes(xs))))..., i)

function batch(xs)
  data = first(xs) isa AbstractArray ?
    similar(first(xs), size(first(xs))..., length(xs)) :
    Vector{eltype(xs)}(undef, length(xs))
  for (i, x) in enumerate(xs)
    data[batchindex(data, i)...] = x
  end
  return data
end

struct ProcessBatchMsg end

mutable struct BatchStrategy
    buffer::Vector{Any}
    reqs::Vector{Mailbox}
    model::Mailbox
    batch_wait_timeout_s::Float64
    max_batch_size::Int
    timer::Union{Nothing, Timer}
    n_ongoing_batches::Int
end

"""
    BatchStrategy(model;kwargs...)

# Keyword Arguments

- `model::Mailbox`, an actor which wraps the model. This actor must accepts
  [`RequestMsg`](@ref) as input and reply with a [`ReplyMsg`](@ref)
  correspondingly.
- `batch_wait_timeout_s=0.0`, time to wait before handling the next batch.
- `max_batch_size=8, the maximum batch size to handle each time.

Everytime we processed a batch, we create a timer and wait for at most
`batch_wait_timeout_s` to handle the next batch. If we get `max_batch_size`
requests before reaching `batch_wait_timeout_s`, the timer is reset. If
`batch_wait_timeout_s==0`, we process the available requests immediately.

!!! warning
    The `model` must reply in a non-blocking way (by using [`async_rep`](@ref) or).
    Otherwise, there may be deadlock (see test cases if you are interested).
"""
function BatchStrategy(
    model;
    batch_wait_timeout_s=0.0,
    max_batch_size=8,
)
    mb = self()
    if batch_wait_timeout_s == 0.
        timer = nothing
    else
        timer = Timer(batch_wait_timeout_s) do timer
            mb[ProcessBatchMsg()]
        end
    end
    BatchStrategy(
        Vector(),
        Vector{Mailbox}(),
        model,
        batch_wait_timeout_s,
        max_batch_size,
        nothing,
        0
    )
end

function reset_timer!(s::BatchStrategy)
    isnothing(s.timer) || close(s.timer)
    mb = self()
    s.timer = Timer(s.batch_wait_timeout_s) do t
        mb[ProcessBatchMsg()]
    end
end

function handle(s::BatchStrategy, req::RequestMsg)
    push!(s.buffer, req.msg)
    push!(s.reqs, req.from)

    if length(s.buffer) == 1
        if s.batch_wait_timeout_s == 0
            if s.n_ongoing_batches == 0
                s(ProcessBatchMsg())
            end
        else
            reset_timer!(s) # set a timer to insert a ProcessBatchMsg to self()
        end
    elseif length(s.buffer) == s.max_batch_size
        s(ProcessBatchMsg())
    end
end

function (s::BatchStrategy)(::ProcessBatchMsg)
    if !isempty(s.buffer)
        @info "???" s.buffer
        data = length(s.buffer) == 1 ? reshape(s.buffer[1], size(s.buffer[1])..., 1) : batch(s.buffer)
        empty!(s.buffer)
        s.n_ongoing_batches += 1
        req(s.model, data)
    end
end

function (s::BatchStrategy)(msg::ReplyMsg)
    for res in msg.msg
        rep(popfirst!(s.reqs), res)
    end
    s.n_ongoing_batches -= 1
    s(ProcessBatchMsg())
end

# X**


text:
#
# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons
# Licensed under the MIT license. See LICENSE file in the project root for details.
#

# ToDo: This is not a good test...

using Test
using FMIBuild


text:
#
# This file is part of the DiscreteEvents.jl Julia package, MIT license
#
# Paul Bayer, 2020
#
# This is a Julia package for discrete event simulation
#

# --- Clock states ----------
struct Undefined <: ClockState end
struct Idle <: ClockState end
struct Empty <: ClockState end
struct Busy <: ClockState end
struct Halted <: ClockState end

# --- Clock events -----------
struct Clear <: ClockEvent end
struct Diag <: ClockEvent end   # ask for the stacktrace of an async clock
struct Done <: ClockEvent       # notication of a worker clock to master
    t::UInt
end
struct Error <: ClockEvent
    exc::Exception
end
struct Finish <: ClockEvent     # ask a worker clock to finish
    tend::Float64
end
struct Forward{T <: Union{DiscreteEvent,DiscreteCond,Sample}} <: ClockEvent
    ev::T
    id::Int
end
struct Init <: ClockEvent
    info::Any
end
struct Query <: ClockEvent end
struct Register{T <: Union{DiscreteEvent,DiscreteCond,Sample}} <: ClockEvent
    x::T
end
struct Reset <: ClockEvent
    type::Bool
end
struct Response <: ClockEvent
    x::Any
end
struct Resume <: ClockEvent end
struct Run <: ClockEvent
    duration::Float64
    sync::Bool
end
struct Start <: ClockEvent end
struct Startup <: ClockEvent
    m::Ref{Clock}
    id::Int
end
struct Step <: ClockEvent end
struct Stop <: ClockEvent end
struct Sync <: ClockEvent end

# --- default transition for clocks
function step!(A::AbstractClock, q::ClockState, σ::ClockEvent)
    println(stderr, "Warning: undefined transition ",
            "$(typeof(A)), ::$(typeof(q)), ::$(typeof(σ)))")
end


text:
export PresenceUpdate,
    TypingStart,
    UserUpdate

"""
Sent when a [`User`](@ref)'s [`Presence`](@ref) is updated.
"""
struct PresenceUpdate <: AbstractEvent
    presence::Presence
end
@boilerplate PresenceUpdate :docs :mock
PresenceUpdate(; kwargs...) = PresenceUpdate(Presence(; kwargs...))
PresenceUpdate(d::Dict{Symbol, Any}) = PresenceUpdate(; d...)

"""
Sent when a [`User`](@ref) begins typing.
"""
struct TypingStart <: AbstractEvent
    channel_id::Snowflake
    guild_id::Optional{Snowflake}
    user_id::Snowflake
    timestamp::DateTime
end
@boilerplate TypingStart :constructors :docs :mock

"""
Sent when a [`User`](@ref)'s details are updated.
"""
struct UserUpdate <: AbstractEvent
    user::User
end
@boilerplate UserUpdate :docs :mock
UserUpdate(; kwargs...) = UserUpdate(User(; kwargs...))
UserUpdate(d::Dict{Symbol, Any}) = UserUpdate(; d...)


text: if true end

max_stars_repo_name: gabriel-doriath-dohler/pjulia

max_issues_repo_name: gabriel-doriath-dohler/pjulia

max_forks_repo_name: gabriel-doriath-dohler/pjulia


text:
"""
	Function that trains a random forest given the data and the parameters
	Returns training and validation R^2
"""
function trainrandomforest(train::DataFrame, val::DataFrame,
						   max_depth::Int, n_estimators::Int, max_features::Int)
	Xtr = convert(Matrix, train[!, 2:end])
	Ytr = train[!, 1]
	Xva = convert(Matrix, val[!, 2:end])
	Yva = val[!, 1]
	rf = RandomForestClassifier(max_depth=max_depth,
	                            n_estimators=n_estimators,
	                            max_features=max_features)
	fit!(rf, Xtr, Ytr)
	predictTr = predict(rf, Xtr)
	predictVa = predict(rf, Xva)
	R2tr = 1 - sum((predictTr .- Ytr) .^ 2)/sum((Ytr .- mean(Ytr)) .^ 2)
	R2va = 1 - sum((predictVa .- Yva) .^ 2)/sum((Yva .- mean(Ytr)) .^ 2)
	return R2tr, R2va
end


text:
# # Wiring diagrams in TikZ
#
#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/generated/graphics/tikz_wiring_diagrams.ipynb)
#
# Catlab can draw morphism expressions as TikZ pictures. To use this feature,
# LaTeX must be installed and the Julia package
# [TikzPictures.jl](https://github.com/sisl/TikzPictures.jl) must be loaded.
#
# For best results, it is recommended to load the packages
# [Convex.j](https://github.com/JuliaOpt/Convex.jl) and
# [SCS.jl](https://github.com/JuliaOpt/SCS.jl). When available they are used to
# optimize the layout of the outer ports.

using Catlab.WiringDiagrams, Catlab.Graphics

import Convex, SCS
import TikzPictures

# ## Examples

# ### Symmetric monoidal category

using Catlab.Doctrines

A, B, C, D = Ob(FreeSymmetricMonoidalCategory, :A, :B, :C, :D)
f, g = Hom(:f, A, B), Hom(:g, B, A);

# To start, here are a few very simple examples.

to_tikz(f, labels=true)
#-
to_tikz(f⋅g, labels=true)
#-
to_tikz(f⊗g, labels=true, orientation=TopToBottom)

# Here is a more complex example, involving generators with compound domains and
# codomains.

h, k = Hom(:h, C, D),  Hom(:k, D, C)
m, n = Hom(:m, B⊗A, A⊗B), Hom(:n, D⊗C, C⊗D)
q = Hom(:l, A⊗B⊗C⊗D, D⊗C⊗B⊗A)

to_tikz((f⊗g⊗h⊗k)⋅(m⊗n)⋅q⋅(n⊗m)⋅(h⊗k⊗f⊗g))

# Identities and braidings appear as wires.

to_tikz(id(A), labels=true)
#-
to_tikz(braid(A,B), labels=true, labels_pos=0.25)
#-
to_tikz(braid(A,B) ⋅ (g⊗f) ⋅ braid(A,B))

# The isomorphism $A \otimes B \otimes C \to C \otimes B \otimes A$ induced by
# the permutation $(3\ 2\ 1)$ is a composite of braidings and identities.

σ = (braid(A,B) ⊗ id(C)) ⋅ (id(B) ⊗ braid(A,C) ⋅ (braid(B,C) ⊗ id(A)))

to_tikz(σ, arrowtip="Stealth", arrowtip_pos="-0.1pt",
        labels=true, labels_pos="0.1pt")

# By default, anchor points are added along identity and braiding wires to
# reproduce the expression structure in the layout. The anchors can be disabled
# to get a more "unbiased" layout.

to_tikz(σ, anchor_wires=false, arrowtip="Stealth", arrowtip_pos="-0.1pt",
        labels=true, labels_pos="0.1pt")

# ### Biproduct category

A, B, C = Ob(FreeBiproductCategory, :A, :B, :C)
f = Hom(:f, A, B)

to_tikz(mcopy(A), labels=true)
#-
to_tikz(delete(A), labels=true)
#-
to_tikz(mcopy(A)⋅(f⊗f)⋅mmerge(B), labels=true)
#-
to_tikz(mcopy(A⊗B), orientation=TopToBottom, labels=true)
#-
to_tikz(mcopy(A⊗B⊗C), orientation=TopToBottom, labels=true)

# ### Compact closed category

# The unit and co-unit of a compact closed category appear as caps and cups.

A, B = Ob(FreeCompactClosedCategory, :A, :B)

to_tikz(dunit(A), arrowtip="Stealth", labels=true)
#-
to_tikz(dcounit(A), arrowtip="Stealth", labels=true)

# In a self-dual compact closed category, such as a bicategory of relations,
# every morphism $f: A \to B$ has a transpose $f^\dagger: B \to A$ given by
# bending wires:

A, B = Ob(FreeBicategoryRelations, :A, :B)
f = Hom(:f, A, B)

to_tikz((dunit(A) ⊗ id(B)) ⋅ (id(A) ⊗ f ⊗ id(B)) ⋅ (id(A) ⊗ dcounit(B)))

# ### Abelian bicategory of relations

# In an abelian bicategory of relations, such as the category of linear
# relations, the duplication morphisms $\Delta_X: X \to X \otimes X$ and
# addition morphisms $\blacktriangledown_X: X \otimes X \to X$ belong to a
# bimonoid. Among other things, this means that the following two morphisms are
# equal.

X = Ob(FreeAbelianBicategoryRelations, :X)

to_tikz(plus(X) ⋅ mcopy(X))
#-
to_tikz((mcopy(X)⊗mcopy(X)) ⋅ (id(X)⊗braid(X,X)⊗id(X)) ⋅ (plus(X)⊗plus(X)))

# ## Custom styles

# The visual appearance of wiring diagrams can be customized using the builtin
# options or by redefining the TikZ styles for the boxes or wires.

A, B, = Ob(FreeSymmetricMonoidalCategory, :A, :B)
f, g = Hom(:f, A, B), Hom(:g, B, A)

pic = to_tikz(f⋅g, styles=Dict(
  "box" => ["draw", "fill"=>"{rgb,255: red,230; green,230; blue,250}"],
))
#-
X = Ob(FreeAbelianBicategoryRelations, :X)

to_tikz(plus(X) ⋅ mcopy(X), styles=Dict(
  "junction" => ["circle", "draw", "fill"=>"red", "inner sep"=>"0"],
  "variant junction" => ["circle", "draw", "fill"=>"blue", "inner sep"=>"0"],
))

# By default, the boxes are rectangular (`:rectangle`). Other available shapes
# include circles (`:circle`), ellipses (`:ellipse`), triangles (`:triangle`,
# `:invtriangle`), and trapezoids (`:trapezium`, `:invtrapezium`).

to_tikz(f⋅g, box_shape=:circle)
#-
to_tikz(f⋅g, box_shape=:triangle, rounded_boxes=false)
#-
to_tikz(f⋅g, box_shape=:invtriangle, rounded_boxes=false)
#-
to_tikz(f⋅g, box_shape=:invtriangle, orientation=TopToBottom, rounded_boxes=false)
#-
to_tikz(f⋅g, box_shape=:trapezium)
#-
to_tikz(f⋅g, box_shape=:invtrapezium)

# ## Output formats

# The function `to_tikz` returns an object of type `TikZ.Document`, representing
# a TikZ picture and its TikZ library dependencies as an abstract syntax tree.
# When displayed interactively, this object is compiled by LaTeX to PDF and then
# converted to SVG.

# To generate the LaTeX source code, use the builtin pretty-printer. This
# feature does not require LaTeX or TikzPictures.jl to be installed.

import Catlab.Graphics: TikZ

doc = to_tikz(f⋅g)
TikZ.pprint(doc)


text:
function barely_solve(input)
    dict = Dict{Int64, Array{Int64}}()
    for (i, n) in enumerate(input)
        dict[n] = [i]
    end
    latest = input[end]
    for i in length(input) + 1:2020
        latest = length(dict[latest]) < 2 ? 0 : dict[latest][end] - dict[latest][end - 1]
        !haskey(dict, latest) ? dict[latest] = [i] : push!(dict[latest], i)
    end
    latest
end

# TO DO: Find an efficient way to do this

function slow_solve(input)
    dict = Dict{Int64, Array{Int64}}()
    for (i, n) in enumerate(input)
        dict[n] = [i, 0]
    end
    latest = input[end]
    for i in length(input) + 1:30000000
        latest = dict[latest][2] == 0 ? 0 : dict[latest][1] - dict[latest][2]
        if !haskey(dict, latest)
            dict[latest] = [i, 0]
        else
            dict[latest][2] = dict[latest][1]
            dict[latest][1] = i
        end
    end
    latest
end

@assert barely_solve([0, 3, 6]) == 436 ["test case 1 failed"]
@assert barely_solve([1, 3, 2]) == 1   ["test case 1a failed"]
@assert barely_solve([2, 1, 3]) == 10  ["test case 1b failed"]
@assert slow_solve([0, 3, 6]) == 175594 ["test case 2 failed"]
@assert slow_solve([1, 3, 2]) == 2578   ["test case 2a failed"]
@assert slow_solve([2, 1, 3]) == 3544142  ["test case 2b failed"]

println("First star: " * string(barely_solve([15, 12, 0, 14, 3, 1])))
println("Second star: " * string(slow_solve([15, 12, 0, 14, 3, 1])))


text:
prev(n::Int, t::Int, T::Int) = mod(t-n-1, T) + 1

include("thermal.jl")
include("variable.jl")
include("storage.jl")
include("transmission.jl")

struct Operations{R,G1,G2,G3,I,T,P}
    thermal::ThermalGeneratorOperations{R,G1,T,P}
    variable::VariableGeneratorOperations{R,G2,T,P}
    storage::StorageOperations{R,G3,T,P}
    transmission::TransmissionOperations{R,I,T,P}
end

function loadoperations(
    techs::Technologies,
    regions::Dict{String,Int}, periods::Dict{String,Int}, T::Int,
    resourcepath::String
)

    R = length(regions)
    P = length(periods)

    thermal = ThermalGeneratorOperations{T,P}(
        techs.thermal, regions, joinpath(resourcepath, "thermal"))

    variable = VariableGeneratorOperations{T}(
        techs.variable, regions, periods,
        joinpath(resourcepath, "variable"))

    storages = StorageOperations{T,P}(
        techs.storage, regions, joinpath(resourcepath, "storage"))

    transmission = TransmissionOperations{T,P}(
        techs.interface, joinpath(resourcepath, "transmission"))

    return Operations(thermal, variable, storages, transmission)

end

welfare(x::Operations) =
    welfare(x.thermal) + welfare(x.variable) + welfare(x.storage)

ucap(x::Operations) =
    sum(x.thermal.ucap) + sum(x.variable.ucap) + sum(x.storage.ucap)

energy(x::Operations, r::Int, t::Int, p::Int) =
    x.thermal.totalenergy[r,t,p] +
    x.variable.totalenergy[r,t,p] +
    x.storage.totalenergy[r,t,p]

raisereserve(x::Operations, r::Int, t::Int, p::Int) =
    x.thermal.totalraisereserve[r,t,p] +
    x.variable.totalraisereserve[r,t,p] +
    x.storage.totalraisereserve[r,t,p]

lowerreserve(x::Operations, r::Int, t::Int, p::Int) =
    x.thermal.totallowerreserve[r,t,p] +
    x.variable.totallowerreserve[r,t,p] +
    x.storage.totallowerreserve[r,t,p]


text:
type L1RDASolver <: RegressionSolver end

function solve(model::RegressionModel,
			   method::RegERM, ::L1RDASolver,
			   X::AbstractMatrix, y::AbstractVector,
			   tolerance::Float64 = 1e-8, k::Int=1,
			   iterations::Int = 1000)
    (N,d) = size(X)
    (λ,ρ,γ) = method.params.λ, method.params.ρ, method.params.γ

    # define a derivative for a loss function
    function loss_grad(theta::Vector, i::Int)
        grad_model = gradient(model.f, X[i,:], theta)
        grad_loss = derivs(loss(method), values(model, X[i,:], theta), [y[i]])
        vec(broadcast(*, grad_loss',grad_model))
    end

    # Maintain current state in w, previous state in w_previous and initial dual average in g
    (w, w_previous, g) = copy(model.theta), copy(model.theta), zeros(d)

    for t=1:iterations
        λ_rda = λ+(ρ*γ)/sqrt(t)
        idx = int(ceil(N*rand(k)))

        eval = (X[idx,:]*w).*y[idx]
        grad = map(i->loss_grad(w,i), idx[find(eval .< 1)])

        # calculate dual average
        g = ((t-1)/t).*g - (1/t).*sum(grad)

        # find a close form solution
        w = -(sqrt(t)/γ).*(g - λ_rda.*sign(g))
        w[w .<= λ_rda] = 0

        # check the stopping criteria w.r.t. Tolerance
        if vecnorm(w - w_previous) < tolerance
            break
        end
    end
    -w
end


text:
import Base: quit
export reveal_area, create_similar_surface

# Some convenience functionalities

const suffix = "Leaf"

# Quit the Gtk application
function quit(app::Gtk.GApplication)
  ccall((:g_application_quit, Gtk.libgio), Void, (Ptr{GObject}, ), app)
end

"""
```julia
reveal_area(
    canvas::Gtk.GtkWidget,
    x::Integer,
    y::Integer,
    width::Integer,
    height::Integer)
```
Selectively update portions of a widget.

This is a wrapper around the C function `gtk_widget_queue_draw_area`.
"""
reveal_area(
    canvas::Gtk.GtkWidget,
    x::Integer,
    y::Integer,
    width::Integer,
    height::Integer) =
  ccall(
    (:gtk_widget_queue_draw_area, Gtk.libgtk),
    Void,
    (Ptr{GObject}, Cint, Cint, Cint, Cint),
    canvas, x, y, width, height)
reveal_area(
    canvas::Ptr{GObject},
    x::Integer,
    y::Integer,
    width::Integer,
    height::Integer) =
  reveal_area(GObject(canvas), x, y, width, height)

"""
```julia
window(widget::Gtk.GtkWidget)::GObject
```
Get the GdkWindow as a GObject.

This is a wrapper for the `gtk_widget_get_window` C function.
"""
window(widget::Gtk.GtkWidget) =
    GObject(ccall(
        (:gtk_widget_get_window, Gtk.libgtk),
        Ptr{GObject},
        (Ptr{GObject}, ),
        widget))

"""
```julia
create_similar_surface(
    w::GObject,
    content::Gtk.GEnum,
    width::Cint,
    height::Cint)
create_similar_surface(
    w::Gtk.GtkWidget,
    content::Gtk.GEnum = Gtk.GEnum(Cairo.CONTENT_COLOR_ALPHA))
```
This is a wrapper for the `gdk_window_create_similar_surface` C function.

The second form calls the first with width and height information taken from
the widget.
"""
function create_similar_surface(
    w::GObject,
    content::Gtk.GEnum,
    width::Cint,
    height::Cint)
  CairoSurface(
    ccall(
      (:gdk_window_create_similar_surface, Gtk.libgdk),
      Ptr{Void},
      (Ptr{GObject}, Gtk.GEnum, Cint, Cint),
      w, content, width, height),
    width, height)
end
create_similar_surface(w::Gtk.GtkWidget, content::Gtk.GEnum=Gtk.GEnum(Cairo.CONTENT_COLOR_ALPHA)) =
  create_similar_surface(window(w), content, width(w), height(w))
create_similar_surface(w::Ptr{GObject}, content::Gtk.GEnum=Gtk.GEnum(Cairo.CONTENT_COLOR_ALPHA)) =
  create_similar_surface(GObject(w), content)


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

# RUN: julia --startup-file=no %s %t && llvm-link -S %t/* -o %t/module.ll
# RUN: cat %t/module.ll | FileCheck %s

## Notes:
# This script uses the `emit` function (defined llvmpasses.jl) to emit either
# optimized or unoptimized LLVM IR. Each function is emitted individually and
# `llvm-link` is used to create a single module that can be passed to opt.
# The order in which files are emitted and linked is important since `lit` will
# process the test cases in order.

include(joinpath("..", "testhelpers", "llvmpasses.jl"))

import Base.FastMath

# CHECK: call fast float @llvm.sqrt.f32(float %0)
emit(FastMath.sqrt_fast, Float32)

max_stars_repo_name: TimoLarson/julia

max_issues_repo_name: TimoLarson/julia

max_forks_repo_name: TimoLarson/julia


text:
using Revise
using ADCME
using ADSeismic
using PyPlot
using DelimitedFiles
matplotlib.use("agg")

param = ElasticPropagatorParams(NX=150, NY=150, NSTEP=500, DELTAT=1e-4, DELTAX=1.0, DELTAY=1.0,
                                vp_ref = 3300.0, USE_PML_XMIN=true, USE_PML_XMAX=true, USE_PML_YMIN=true, USE_PML_YMAX=true)

source = Ricker(param, 15.0, 100.0, 1e6)
srci = [param.NX ÷ 2]
srcj = [param.NY ÷ 2]
srctype = [0] #0: velocity; 1: stress
srcv = reshape(source, :, 1)

# srci = [param.NX ÷ 2, param.NX ÷ 2]
# srcj = [param.NY ÷ 2, param.NY ÷ 2]
# srctype = [2,3]
# srcv = tf.concat([reshape(source, :, 1), reshape(source, :, 1)],1)
src = ElasticSource(srci, srcj, srctype, srcv)

vp = 3000.
vs = vp / 1.732
rho = 2800.
λ, μ, ρ = compute_lame_parameters(param.NX, param.NY, vp, vs, rho)
model = ElasticPropagatorSolver(param, src, ρ, λ, μ)

sess = Session(); init(sess)
vx = run(sess, model.vx)

p = visualize_wavefield(vx, param)
saveanim(p, "elastic-wavefield.gif")


text:
"""    nintegrate(f, xmin::NTuple{N,Any}, xmax::NTuple{N,Any};
               reltol = 1e-6, abstol = 1e-12,
               maxevals = 1000000)

Approximate numerical integration routine based on an adaptive algorithm
[^BEG1991].

- `f` is the integrand.
- `xmin` and `xmax` are tuples specifiying the boundaries of the integration
  domain.
- `reltol`, `abstol` and `maxevals` are optional keyword arguments that
  determine the termination criteria.

Returns a tuple of the approximated integral, error estimate, number of
functions evaluations and an object of type `Regions` (a set of subregions in
which the integration domain was subdivided).

[^BEG1991]: J. Berntsen, T. O. Espelid, A. Genz, "An Adaptive Algorithm for the
Approximate Calculation of Multiple Integrals," ACM Trans. Math. Soft., 17 (4),
437-451 (1991).
"""
function nintegrate(
    f::F, xmin::NTuple{N,Any}, xmax::NTuple{N,Any};
    reltol::Float64 = 1e-6, abstol::Float64 = eps(), maxevals::Int = 1000000
) where {F,N}
    # find the center and half-widths of the whole integration domain
    tx = map((a, b) -> (a + b) / 2, xmin, xmax)
    th = map((a, b) -> (b - a) / 2, xmin, xmax)
    T = Base.promote_typeof(tx..., th...)
    x, h = map(T, tx), map(T, th)
    r = Region(integral_type(f, x), x, h)

    # apply the integration rule to the whole domain
    # and initiate the regions heap
    _p = zeros(MMatrix{2,N,T})
    I, E = apply_rule!(f, r, _p)
    regions = BinaryMaxHeap{typeof(r)}()
    push!(regions, r)
    evals = L = L₁₁

    # adaptively subdivide regions until the termination criteria is met
    while evals < maxevals && E > abs(I) * reltol && E > abstol
        r = pop!(regions)
        r₁, r₂ = divide(r)
        I₁, E₁ = apply_rule!(f, r₁, _p)
        I₂, E₂ = apply_rule!(f, r₂, _p)
        ΔI, ΔE = error_estimates!(r₁, r₂, r, I₁, I₂, E₁, E₂)

        push!(regions, r₁)
        push!(regions, r₂)

        evals += 2L
        I += ΔI
        E += ΔE
    end

    return I, E, evals, Regions(regions.valtree)
end

"""    nintegrate(f, regions::Regions)

Approximate numerical integration routine that takes the integrand `f` and a
`Regions` object which is a subdivision of the integration domain.
"""
nintegrate(f::F, regions::Regions) where {F} = nintegrate(f, regions.v)
function nintegrate(f::F, regions::Vector{Region{N,T,R}}) where {F,N,R,T}
    _p = zeros(MMatrix{2,N,T})
    I  = zero(R)
    for r in regions
        I += apply_rule(f, r, _p)
    end
    return I
end

"""    nintegrate{T<:WPoint}(f, W::Vector{T})

Approximate numerical integration routine that takes the integrand `f` and a
`WPoints` object (set of  weights and nodes on integration domain). A `WPoints`
can be obtained from a `Regions` object `R` by calling `weightedpoints(R)`.
"""
function nintegrate(f::F, wp::WPoints{N,T}) where {F,N,T}
    w = weights(wp)
    p = points(wp)

    isempty(w) && throw(ArgumentError("W must contain at least one element"))

    I = w[1] * evaluate(f, p[1])
    @inbounds @simd for i = 2:length(w)
        I += w[i] * evaluate(f, p[i])
    end

    return I
end

"""    weightedpoints(regions::Regions)

Build a `WPoints` (`W`) from a `Regions` object `regions`.  The resulting
object can be used to approximate de integral of a function `f` by calling
`nintegrate(f, W)`
"""
weightedpoints(regions::Regions) = weightedpoints(idem, regions.v)

"""    weightedpoints(f, regions::Regions)

It works the same as `weightedpoints(::Regions)`, but allows a transformation
`f` that takes a weight and a tuple `x` of point coordinates f(w, p) and
returns a `WPoints`.
"""
weightedpoints(f::F, regions::Regions) where {F} = weightedpoints(f, regions.v)
function weightedpoints(f::F, regions::Vector{Region{N,T,R}}) where {F,N,R,T}
    _p = zeros(MMatrix{2,N,T})
    w = Vector{R}()
    p = Vector{SVector{N,T}}()
    wp = WPoints(w, p)
    for r in regions
        weightedpoints!(f, wp, r, _p)
    end
    return wp
end

function divide(r::Region)
    i = r.axis.x
    r₁ = deepcopy(r)
    r₂ = deepcopy(r)
    r₁.x[i] -= r.h[i] / 2
    r₂.x[i] += r.h[i] / 2
    r₁.h[i] = r₂.h[i] = r.h[i] / 2
    return r₁, r₂
end

function apply_rule!(f::F, r::Region, P) where {F}
    I, N₁, N₂, N₃, N₄, fu, fuα₁, fuα₂ = _apply_rule(f, r, P)
    r.axis.x = choose_axis(r.h, fu, fuα₁, fuα₂)
    E = compute_error(N₁, N₂, N₃, N₄)
    V = prod(r.h)
    I = r.I.x = V * I
    E = r.E.x = 8V * E
    return I, E
end

function choose_axis(h, fu, fuα₁, fuα₂)
    r = (α₁ / α₂)^2
    fc = 2fu * (1 - r)
    Df₁ = chop(abs(fuα₁[1] - r * fuα₂[1] - fc))
    Df₂ = chop(abs(fuα₁[2] - r * fuα₂[2] - fc))
    Df₃ = chop(abs(fuα₁[3] - r * fuα₂[3] - fc))

    if Df₁ == Df₂ == Df₃
        return argmax(h)
    else
        return argmax((Df₁, Df₂, Df₃))
    end
end

function compute_error(N₁, N₂, N₃, N₄)
    N₁⃰ = N₂⃰ = N₃⃰ = zero(N₁)

    @inbounds for i = 1:length(s₁)
        N₁⃰ = max(N₁⃰, abs(μ₁[i] * N₁ + N₂) * s₁[i])
        N₂⃰ = max(N₂⃰, abs(μ₂[i] * N₂ + N₃) * s₂[i])
        N₃⃰ = max(N₃⃰, abs(μ₃[i] * N₃ + N₄) * s₃[i])
    end
    @inbounds for i = length(s₁)+1:length(s₃)
        N₂⃰ = max(N₂⃰, abs(μ₂[i] * N₂ + N₃) * s₂[i])
        N₃⃰ = max(N₃⃰, abs(μ₃[i] * N₃ + N₄) * s₃[i])
    end
    @inbounds for i = length(s₃)+1:length(s₂)
        N₂⃰ = max(N₂⃰, abs(μ₂[i] * N₂ + N₃) * s₂[i])
    end

    if c[1] * N₁⃰ ≤ N₂⃰ && c[2] * N₂⃰ ≤ N₃⃰
        return c[3] * N₁⃰
    else
        return c[4] * max(N₁⃰, N₂⃰, N₃⃰)
    end
end

function error_estimates!(r₁, r₂, r, I₁, I₂, E₁, E₂)
    ΔI = I₁ + I₂ - r.I.x

    E₂⃰ = abs(ΔI)
    if (E₁⃰ = E₁ + E₂) > 0
        E₁ += c[5] * E₁ * E₂⃰ / E₁⃰
        E₂ += c[5] * E₂ * E₂⃰ / E₁⃰
    end
    E₁ += c[6] * E₂⃰
    E₂ += c[6] * E₂⃰

    ΔE = E₁ + E₂ - r.E.x
    r₁.E.x = E₁
    r₂.E.x = E₂

    return ΔI, ΔE
end


text:
module Utils

using PyCall, DataFrames, KernelDensity, Statistics, StatsPlots, PlotlyBase

export corner, load_pickle, sub_dict

include("load.jl")
include("plots.jl")

function __init__()
    py"""
    import numpy as np
    import pickle

    def load_pickle(fpath):
        with open(fpath, "rb") as f:
            data = pickle.load(f)
        return data
    """
end
load_pickle = py"load_pickle"

end # module


text:
# Timings from implicit 256 core runs

using PyPlot

# 1 thread, 4 thread, 16 thread
# advance, krylov, Jacobian, facevalue, faceflux, exchange_message
t1 = [147.05, 123.81, 17.85, 3.28, 24.91, 4.96] ./ 3
t2 = [153.08, 129.88, 17.50, 3.19, 23.99, 4.97] ./ 3
t3 = [198.51, 172.18, 17.51, 3.23, 24.04, 12.99] ./ 3

t1_percent = [100.0, 84.2, 12.1, 2.2, 17.0, 3.4]
t2_percent = [100.0, 84.9, 11.4, 2.1, 15.7, 3.2]
t3_percent = [100.0, 86.7, 8.9, 1.6, 12.1, 6.5]

# set width of bar
const barWidth = 0.3

# Set position of bar on X axis
r1 = collect(0:length(t1)-1)
r2 = [x + barWidth for x in r1]
r3 = [x + barWidth for x in r2]

fig = figure("bar_timing",figsize=(14,6))
ax = plt.axes()
#axis("tight")

# Make the plot
a1 = bar(r1, t1, width=barWidth, edgecolor="white", label="1 thread * 256 MPI")
a2 = bar(r2, t2, width=barWidth, edgecolor="white", label="4 threads * 64 MPI")
a3 = bar(r3, t3, width=barWidth, edgecolor="white", label="16 threads * 16 MPI")

# Add xticks on the middle of the group bars
xlabel("module", fontweight=:bold, fontsize=18)
xticks([r + barWidth for r in 0:length(t1)-1],
   ["Advance", "Krylov", "Jacobian", "FaceValue", "FaceFlux", "MessagePass"],
   fontsize=18)
plt.minorticks_on()
ax.tick_params(axis=:x, which=:minor, bottom=false)
ax.yaxis.grid(true, linestyle="--")
#ax.yaxis.grid(true, which="minor")
ylabel("time [s]", fontsize=18)
ax.set_title("Timings per time step for 256 cores, implicit 2nd Order Linde + BiCGSTAB",fontsize=18)

# Create legend & Show graphic
legend(fontsize=18)

function autolabel(rects, t_percent)
   """Attach a text label above each bar in *rects*, displaying its height."""
   for (i, rect) in enumerate(rects)
      i == 1 && continue
      height = rect.get_height()
      percent = t_percent[i]
      ax.annotate(string(percent),
         xy=(rect.get_x() + rect.get_width() / 2, height),
         xytext=(0, 3),  # 3 points vertical offset
         textcoords="offset points",
         ha=:center, va=:bottom)
   end
end

autolabel(a1, t1_percent)
autolabel(a2, t2_percent)
autolabel(a3, t3_percent)


text:
# The SteinRectangularDomainMetaKernel is a "meta" kernel of the form:
#
# kR(x, y) = \prod_{j: l[j] > -inf} (x_j - l_j)(y_j - l_j) *
#            \prod_{k: u[k] <  inf} (x_k - u_k)(y_k - u_k) *
#            k(x,y)
#
# on the domain [l_1, u_1] x ... x [l_d, u_d].
# We assume subtypes of this define the fields:
#
# l, u, and basekernel.

mutable struct SteinRectangularDomainMetaKernel <: SteinKernel
    # the base kernel k(x,y)
    basekernel::SteinKernel
    # the lower bound vector (l_1, ..., l_d)
    l::Array{Float64,1}
    # the upper bound vector (u_1, ..., u_d)
    u::Array{Float64,1}
end

# domain is [l,u]^d
SteinRectangularDomainMetaKernel(basekernel::SteinKernel, l::Float64, u::Float64, d::Int64) =
SteinRectangularDomainMetaKernel(basekernel, l * ones(d), u * ones(d))

# HELPER FUNCTIONS

function w(ker::SteinRectangularDomainMetaKernel,
           x::Array{Float64,1})
    J = find(ker.l .> -Inf)
    K = find(ker.u .< Inf)
    prodl = prod(x[J] - ker.l[J])
    produ = prod(ker.u[K] - x[K])
    prodl * produ
end

function w(ker::SteinRectangularDomainMetaKernel,
           x::Array{Float64,1},
           y::Array{Float64,1})
    w(ker, x) * w(ker, y)
end

function alpha(ker::SteinRectangularDomainMetaKernel,
               x::Array{Float64,1})
    l = ker.l; u = ker.u
    d = length(x)
    fullprod = w(ker, x)
    result = zeros(d)

    for j in 1:d
        finitel = l[j] > -Inf
        finiteu = u[j] < Inf
        if !finitel && !finiteu
            continue
        end

        if !finitel && finiteu
            result[j] = fullprod / (x[j] - u[j])
        elseif finitel && !finiteu
            result[j] = fullprod / (x[j] - l[j])
        else
            result[j] = fullprod * (2*x[j] - l[j] - u[j]) / ((x[j] - l[j]) * (x[j] - u[j]))
        end
    end
    result
end

# Definition of kernel

function k(ker::SteinRectangularDomainMetaKernel,
           x::Array{Float64,1},
           y::Array{Float64,1})
    w(ker, x, y) * k(ker.basekernel, x, y)
end

function gradxk(ker::SteinRectangularDomainMetaKernel,
                x::Array{Float64,1},
                y::Array{Float64,1})
    wx = w(ker, x)
    wy = w(ker, y)
    wx * wy * gradxk(ker.basekernel, x, y) + wy * alpha(ker, x) * k(ker.basekernel, x, y)
end

function gradxyk(ker::SteinRectangularDomainMetaKernel,
                 x::Array{Float64,1},
                 y::Array{Float64,1})
    wx = w(ker, x)
    wy = w(ker, y)
    ax = alpha(ker, x)
    ay = alpha(ker, y)
    dot(ax, ay) * k(ker.basekernel, x, y) +
        wx * dot(ay, gradxk(ker.basekernel, x, y)) +
        wy * dot(ax, gradyk(ker.basekernel, x, y)) +
        wx * wy * gradxyk(ker.basekernel, x, y)
end


text:
function compute(rows, mx, my)
    # initialize position
    x = 1
    y = 1

    width = length(rows[1])
    height = length(rows)

    trees_encountered = 0
    while y <= height
        # is tree?
        temp_x = (x == 0) ? width : x # 1 indexed arrays :(
        if rows[y][temp_x] == '#'
            trees_encountered += 1
        end

        # move
        x = (x + mx) % width
        y = y + my
    end

    return trees_encountered
end

function run(fname)
    println("Running", fname, " ...")
    f = open(fname, "r")
    rows = readlines(f)
    close(f)
    result = compute(rows, 1, 1)
    result2 = compute(rows, 3, 1)
    result3 = compute(rows, 5, 1)
    result4 = compute(rows, 7, 1)
    result5 = compute(rows, 1, 2)

    out = result * result2 * result3 * result4 * result5

    println("Final result for ", fname, " was: ", out)
    return out
end

@assert run("3ex.txt") == 336

run("3.txt")


text:
using Test
using SparseIR

include("__conftest.jl")

function _check_smooth(u, s, uscale, fudge_factor)
    ε = eps(eltype(s))
    x = u.knots[(begin + 1):(end - 1)]

    jump = abs.(u(x .+ ε) - u(x .- ε))
    compare_below = abs.(u(x .- ε) - u(x .- 3ε))
    compare_above = abs.(u(x .+ 3ε) - u(x .+ ε))
    compare = min.(compare_below, compare_above)
    compare = max.(compare, uscale * ε)

    # loss of precision
    compare .*= fudge_factor * (first(s) ./ s)
    @test all(jump .< compare)
end

@testset "sve.jl" begin
    @testset "smooth with Λ = $Λ" for Λ in (10, 42, 10_000)
        basis = DimensionlessBasis(fermion, Λ; sve_result=sve_logistic[Λ])
        _check_smooth(basis.u, basis.s, 2 * maximum(basis.u(1)), 24)
        _check_smooth(basis.v, basis.s, 50, 20)
    end

    @testset "num roots u with Λ = $Λ" for Λ in (10, 42, 10_000)
        basis = DimensionlessBasis(fermion, Λ; sve_result=sve_logistic[Λ])
        for ui in basis.u
            ui_roots = SparseIR.roots(ui)
            @test length(ui_roots) == ui.l
        end
    end

    @testset "num roots û with stat = $stat, Λ = $Λ" for stat in (fermion, boson),
        Λ in (10, 42, 10_000)

        basis = DimensionlessBasis(stat, Λ; sve_result=sve_logistic[Λ])
        for i in [1, 2, 8, 11]
            x₀ = SparseIR.findextrema(basis.uhat[i])
            @test i ≤ length(x₀) ≤ i + 1
        end
    end
end


text:
#Demo 3: Monochrome 2x2 array of subplots
#-------------------------------------------------------------------------------
using InspectDR
using Colors

#==Input
===============================================================================#
#Constants
#-------------------------------------------------------------------------------
black = RGB24(0, 0, 0)
gray50 = RGB24(.5, .5, .5)

#Input data
#-------------------------------------------------------------------------------
x=collect(-10:0.1:10)
titles = ["Linear", "Quadratic", "Cubic", "Quartic"]

linetypes = []
for lstyle in [:solid, :dash, :dot, :dashdot]
	push!(linetypes, line(color=black, width=3, style=lstyle))
	push!(linetypes, line(color=gray50, width=3, style=lstyle))
end

#==Generate plot
===============================================================================#
mplot = InspectDR.Multiplot(title="Powers of X")
mplot.ncolumns = 2
xlabel = "X-Axis (X-Unit)"
ylabel = "Y-Axis (Y-Unit)"

plotlist = InspectDR.Plot
for i in 1:4
	plot = add(mplot, InspectDR.Plot2D) #Generate empty plot
	plot.layout.legend.enabled = true
	plot.layout.legend.width = 80
	a = plot.annotation
		a.xlabel = xlabel
		a.ylabel = ylabel
		a.title = titles[i]

	for scalei in 1:8
#		id = "$scalei(x/10)^$i"
		id = "ref×$scalei"
		wfrm = add(plot, x, scalei*((x/10).^i), id=id)
		wfrm.line = linetypes[scalei]
	end
end

#Display
#-------------------------------------------------------------------------------
gplot = display(InspectDR.GtkDisplay(), mplot)

#==Save multi-plot to file
===============================================================================#
InspectDR.write_png("export_monochrome.png", mplot)
InspectDR.write_svg("export_monochrome.svg", mplot)

:DONE


text:
"""
Sparse representation of `Matrix{Bool}`, when all "falses" are "structural".
It uses compressed sparse column (CSC) representation, except no
non-zero values need to be stored.
"""
struct SparseMaskMatrix <: AbstractMatrix{Bool}
    m::Int              # rows number
    n::Int              # cols number
    colptr::Vector{Int} # indices of column starts in rowval vector
    rowval::Vector{Int} # indices of rows of true matrix elements

    function SparseMaskMatrix(m::Integer, n::Integer, colptr::Vector{Int}, rowval::Vector{Int})
        length(colptr) == n+1 || throw(ArgumentError("col pointers ($(length(colptr))) does not match columns count ($n)"))
        colptr[end] == length(rowval)+1 || throw(ArgumentError("colptr[end] does not match rowval length"))
        new(Int(m), Int(n), colptr, rowval)
    end

    function SparseMaskMatrix(m::Integer=0, n::Integer=0) # empty mask
        new(m, n, fill(1, n+1), Vector{Int}())
    end
end

Base.isequal(x::SparseMaskMatrix, y::SparseMaskMatrix) =
    x.m == y.m && x.n == y.n &&
    x.colptr == y.colptr &&
    x.rowval == y.rowval # though potentially rows may have different order within one column

Base.:(==)(x::SparseMaskMatrix, y::SparseMaskMatrix) = isequal(x, y)

Base.copy(mtx::SparseMaskMatrix) = SparseMaskMatrix(mtx.m, mtx.n, copy(mtx.colptr), copy(mtx.rowval))

"""
    SparseMaskMatrix(m::Integer, rowvals_percol::Vector{Vector{Int}}) -> SparseMaskMatrix

Construct `SparseMaskMatrix` given the vector of true row indices per each column
and the total number of rows (`m`).
"""
function SparseMaskMatrix(m::Integer, rowvals_percol::AbstractVector{Vector{Int}})
    colptr = sizehint!(Vector{Int}(), length(rowvals_percol)+1)
    nrowvals_cumlenp1 = 1
    for rowvals in rowvals_percol
        push!(colptr, nrowvals_cumlenp1)
        nrowvals_cumlenp1 += length(rowvals)
    end
    push!(colptr, nrowvals_cumlenp1)
    allrowvals = sizehint!(Vector{Int}(), nrowvals_cumlenp1-1)
    for rowvals in rowvals_percol
        append!(allrowvals, rowvals)
    end
    SparseMaskMatrix(m, length(rowvals_percol), colptr, allrowvals)
end

"""
    SparseMaskMatrix(sets, elm2ix::Dict{T, Int}) where T -> SparseMaskMatrix

Construct `SparseMaskMatrix` from the collection of sets.

# Arguments
 * `sets`: a collection of sets, one set per mask matrix column
 * `elm2ix`: maps set element to its index (mask row index)
"""
function SparseMaskMatrix(sets, elm2ix::AbstractDict{T, Int}) where T
    isempty(sets) && return SparseMaskMatrix(length(elm2ix), 0, fill(0, 1), Vector{Int}())

    elm_ixs = Vector{Int}()
    set_ranges = Vector{Int}()
    sizehint!(set_ranges, length(sets))
    for s in sets
        push!(set_ranges, length(elm_ixs)+1)
        append!(elm_ixs, sort!([elm2ix[e] for e in s]))
    end
    push!(set_ranges, length(elm_ixs)+1)
    return SparseMaskMatrix(length(elm2ix), length(sets), set_ranges, elm_ixs)
end

"""
    SparseMaskMatrix(mtx::AbstractMatrix{Bool}) -> SparseMaskMatrix

Sparse representation of boolean matrix.
"""
function SparseMaskMatrix(mtx::AbstractMatrix{Bool})
    colptr = sizehint!(Vector{Int}(), size(mtx, 2)+1)
    rowval = Vector{Int}()
    @inbounds for j in 1:size(mtx, 2)
        push!(colptr, length(rowval)+1)
        for i in 1:size(mtx, 1)
            mtx[i, j] && push!(rowval, i)
        end
    end
    push!(colptr, length(rowval)+1)
    return SparseMaskMatrix(size(mtx)..., colptr, rowval)
end

Base.size(mtx::SparseMaskMatrix) = (mtx.m, mtx.n)
function Base.size(mtx::SparseMaskMatrix, dim::Integer)
    (1 <= dim <= 2) || throw(ArgumentError("SparseMaskMatrix does not have dimension #$dim"))
    dim == 1 ? mtx.m : mtx.n
end
@inline _colrange(mtx::SparseMaskMatrix, col::Integer) = mtx.colptr[col]:(mtx.colptr[col+1]-1)

@inline Base.getindex(mtx::SparseMaskMatrix, ::Colon, col::Integer) = mtx.rowval[_colrange(mtx, col)]

Base.@propagate_inbounds function Base.getindex(mtx::SparseMaskMatrix, ::Colon, cols::AbstractVector{Int})
    rowvals = Vector{Int}()
    colptr = Vector{Int}()
    for col in cols
        # FIXME avoid temp array alloc
        push!(colptr, length(rowvals)+1)
        append!(rowvals, mtx[:, col])
    end
    push!(colptr, length(rowvals)+1)
    SparseMaskMatrix(mtx.m, length(cols), colptr, rowvals)
end

function Base.getindex(mtx::SparseMaskMatrix,
                       rows::AbstractVector{Int},
                       cols::AbstractVector{Int})
    old2new = Dict{Int,Vector{Int}}()
    for (newix, oldix) in enumerate(rows)
        push!(get!(() -> Vector{Int}(), old2new, oldix), newix)
    end
    rowval = Vector{Int}()
    thiscol = Vector{Int}()
    colptr = [1]
    nonew = Vector{Int}()
    @inbounds for j in cols
        @assert 1 <= j <= mtx.n
        # collect new row indices of j-th column
        empty!(thiscol)
        for i in _colrange(mtx, j)
            newrows = get(old2new, mtx.rowval[i], nonew)
            append!(thiscol, newrows)
        end
        append!(rowval, sort!(thiscol))
        push!(colptr, length(rowval)+1)
    end
    SparseMaskMatrix(length(rows), length(cols), colptr, rowval)
end

Base.getindex(mtx::SparseMaskMatrix, rows::AbstractVector{Int}, ::Colon) =
    getindex(mtx, rows, Base.OneTo(mtx.n))

Base.getindex(mtx::SparseMaskMatrix, row::Integer, col::Integer) =
    !isempty(searchsorted(view(mtx, :, col), row))

Base.@propagate_inbounds function Base.getindex(mtx::SparseMaskMatrix, ::Colon, colmask::AbstractVector{Bool})
    length(colmask) == size(mtx, 2) || throw(ArgumentError("Column mask length should match the number of columns"))
    mtx[:, findall(colmask)]
end

Base.view(mtx::SparseMaskMatrix, ::Colon, col::Integer) = view(mtx.rowval, _colrange(mtx, col))

function Base.convert(::Type{Matrix{Bool}}, mtx::SparseMaskMatrix)
    res = fill(false, size(mtx))
    @inbounds for i in 1:size(mtx, 2)
        for j in _colrange(mtx, i)
            res[mtx.rowval[j], i] = true
        end
    end
    return res
end

Base.convert(::Type{Matrix}, mtx::SparseMaskMatrix) = convert(Matrix{Bool}, mtx)

function Base.sum(mtx::SparseMaskMatrix, dim::Integer)
    (dim != 1) && throw(ArgumentError("sum(SparseMaskMatrix, dim=$dim) not implemented"))
    return [colptr[i+1] - colptr[i] for i in 1:n]
end

Base.sum(mtx::SparseMaskMatrix) = length(mtx.rowval)

function Base.permutedims(mtx::SparseMaskMatrix, perm)
    if perm == [1, 2]
        return copy(mtx)
    elseif perm != [2, 1] # only transpose
        throw(ArgumentError("permutedims(A::SparseMaskMatrix, perm) does not support perm=$perm"))
    end
    trueixs = sizehint!(Vector{Tuple{Int,Int}}(), sum(mtx)) # col-row coords of trues in t(mtx)
    for i in 1:mtx.n
        @inbounds for j in view(mtx, :, i)
            push!(trueixs, (j, i)) # new
        end
    end
    sort!(trueixs) # sort first by the new column then row
    # find column ranges (FIXME could use searchsorted...)
    colptr = sizehint!(Vector{Int}(), mtx.m+1)
    for i in eachindex(trueixs)
        @inbounds curcol = first(trueixs[i])
        while length(colptr) < curcol
            push!(colptr, i)
        end
    end
    while length(colptr) <= mtx.m
        push!(colptr, length(trueixs)+1)
    end
    return SparseMaskMatrix(mtx.n, mtx.m, colptr, last.(trueixs))
end

Base.transpose(mtx::SparseMaskMatrix) = permutedims(mtx, [2, 1])