text:
module LibAssimp

using assimp_jll
export assimp_jll

using CEnum

@cenum aiComponent::UInt32 begin
    aiComponent_NORMALS = 2
    aiComponent_TANGENTS_AND_BITANGENTS = 4
    aiComponent_COLORS = 8
    aiComponent_TEXCOORDS = 16
    aiComponent_BONEWEIGHTS = 32
    aiComponent_ANIMATIONS = 64
    aiComponent_TEXTURES = 128
    aiComponent_LIGHTS = 256
    aiComponent_CAMERAS = 512
    aiComponent_MESHES = 1024
    aiComponent_MATERIALS = 2048
    _aiComponent_Force32Bit = 0x000000009fffffff
end

const ai_real = Cfloat

const ai_int = Cint

const ai_uint = Cuint

struct aiVector3D
    x::ai_real
    y::ai_real
    z::ai_real
end

struct aiVector2D
    x::ai_real
    y::ai_real
end

struct aiColor4D
    r::ai_real
    g::ai_real
    b::ai_real
    a::ai_real
end

struct aiMatrix3x3
    a1::ai_real
    a2::ai_real
    a3::ai_real
    b1::ai_real
    b2::ai_real
    b3::ai_real
    c1::ai_real
    c2::ai_real
    c3::ai_real
end

struct aiMatrix4x4
    a1::ai_real
    a2::ai_real
    a3::ai_real
    a4::ai_real
    b1::ai_real
    b2::ai_real
    b3::ai_real
    b4::ai_real
    c1::ai_real
    c2::ai_real
    c3::ai_real
    c4::ai_real
    d1::ai_real
    d2::ai_real
    d3::ai_real
    d4::ai_real
end

struct aiQuaternion
    w::ai_real
    x::ai_real
    y::ai_real
    z::ai_real
end

const ai_int32 = Int32

const ai_uint32 = UInt32

struct aiPlane
    a::ai_real
    b::ai_real
    c::ai_real
    d::ai_real
end

struct aiRay
    pos::aiVector3D
    dir::aiVector3D
end

struct aiColor3D
    r::ai_real
    g::ai_real
    b::ai_real
end

struct aiString
    length::ai_uint32
    data::NTuple{1024, Cchar}
end

@cenum aiReturn::Int32 begin
    aiReturn_SUCCESS = 0
    aiReturn_FAILURE = -1
    aiReturn_OUTOFMEMORY = -3
    _AI_ENFORCE_ENUM_SIZE = 2147483647
end

@cenum aiOrigin::UInt32 begin
    aiOrigin_SET = 0
    aiOrigin_CUR = 1
    aiOrigin_END = 2
    _AI_ORIGIN_ENFORCE_ENUM_SIZE = 2147483647
end

@cenum aiDefaultLogStream::UInt32 begin
    aiDefaultLogStream_FILE = 1
    aiDefaultLogStream_STDOUT = 2
    aiDefaultLogStream_STDERR = 4
    aiDefaultLogStream_DEBUGGER = 8
    _AI_DLS_ENFORCE_ENUM_SIZE = 2147483647
end

struct aiMemoryInfo
    textures::Cuint
    materials::Cuint
    meshes::Cuint
    nodes::Cuint
    animations::Cuint
    cameras::Cuint
    lights::Cuint
    total::Cuint
end

# typedef size_t ( * aiFileWriteProc ) ( C_STRUCT aiFile * , const char * , size_t , size_t )
const aiFileWriteProc = Ptr{Cvoid}

# typedef size_t ( * aiFileReadProc ) ( C_STRUCT aiFile * , char * , size_t , size_t )
const aiFileReadProc = Ptr{Cvoid}

# typedef size_t ( * aiFileTellProc ) ( C_STRUCT aiFile * )
const aiFileTellProc = Ptr{Cvoid}

# typedef void ( * aiFileFlushProc ) ( C_STRUCT aiFile * )
const aiFileFlushProc = Ptr{Cvoid}

# typedef C_ENUM aiReturn ( * aiFileSeek ) ( C_STRUCT aiFile * , size_t , C_ENUM aiOrigin )
const aiFileSeek = Ptr{Cvoid}

# typedef C_STRUCT aiFile * ( * aiFileOpenProc ) ( C_STRUCT aiFileIO * , const char * , const char * )
const aiFileOpenProc = Ptr{Cvoid}

# typedef void ( * aiFileCloseProc ) ( C_STRUCT aiFileIO * , C_STRUCT aiFile * )
const aiFileCloseProc = Ptr{Cvoid}

const aiUserData = Ptr{Cchar}

struct aiFileIO
    OpenProc::aiFileOpenProc
    CloseProc::aiFileCloseProc
    UserData::aiUserData
end

struct aiFile
    ReadProc::aiFileReadProc
    WriteProc::aiFileWriteProc
    TellProc::aiFileTellProc
    FileSizeProc::aiFileTellProc
    SeekProc::aiFileSeek
    FlushProc::aiFileFlushProc
    UserData::aiUserData
end

@cenum aiImporterFlags::UInt32 begin
    aiImporterFlags_SupportTextFlavour = 1
    aiImporterFlags_SupportBinaryFlavour = 2
    aiImporterFlags_SupportCompressedFlavour = 4
    aiImporterFlags_LimitedSupport = 8
    aiImporterFlags_Experimental = 16
end

struct aiImporterDesc
    mName::Ptr{Cchar}
    mAuthor::Ptr{Cchar}
    mMaintainer::Ptr{Cchar}
    mComments::Ptr{Cchar}
    mFlags::Cuint
    mMinMajor::Cuint
    mMinMinor::Cuint
    mMaxMajor::Cuint
    mMaxMinor::Cuint
    mFileExtensions::Ptr{Cchar}
end

function aiGetImporterDesc(extension)
    ccall((:aiGetImporterDesc, libassimp), Ptr{aiImporterDesc}, (Ptr{Cchar},), extension)
end

# typedef void ( * aiLogStreamCallback ) ( const char * /* message */ , char * /* user */ )
const aiLogStreamCallback = Ptr{Cvoid}

struct aiLogStream
    callback::aiLogStreamCallback
    user::Ptr{Cchar}
end

struct aiPropertyStore
    sentinel::Cchar
end

const aiBool = Cint

struct aiFace
    mNumIndices::Cuint
    mIndices::Ptr{Cuint}
end

struct aiVertexWeight
    mVertexId::Cuint
    mWeight::Cfloat
end

struct aiBone
    mName::aiString
    mNumWeights::Cuint
    mWeights::Ptr{aiVertexWeight}
    mOffsetMatrix::aiMatrix4x4
end

struct aiAnimMesh
    mName::aiString
    mVertices::Ptr{aiVector3D}
    mNormals::Ptr{aiVector3D}
    mTangents::Ptr{aiVector3D}
    mBitangents::Ptr{aiVector3D}
    mColors::NTuple{8, Ptr{aiColor4D}}
    mTextureCoords::NTuple{8, Ptr{aiVector3D}}
    mNumVertices::Cuint
    mWeight::Cfloat
end

struct aiAABB
    mMin::aiVector3D
    mMax::aiVector3D
end

struct aiMesh
    mPrimitiveTypes::Cuint
    mNumVertices::Cuint
    mNumFaces::Cuint
    mVertices::Ptr{aiVector3D}
    mNormals::Ptr{aiVector3D}
    mTangents::Ptr{aiVector3D}
    mBitangents::Ptr{aiVector3D}
    mColors::NTuple{8, Ptr{aiColor4D}}
    mTextureCoords::NTuple{8, Ptr{aiVector3D}}
    mNumUVComponents::NTuple{8, Cuint}
    mFaces::Ptr{aiFace}
    mNumBones::Cuint
    mBones::Ptr{Ptr{aiBone}}
    mMaterialIndex::Cuint
    mName::aiString
    mNumAnimMeshes::Cuint
    mAnimMeshes::Ptr{Ptr{aiAnimMesh}}
    mMethod::Cuint
    mAABB::aiAABB
end

@cenum aiPropertyTypeInfo::UInt32 begin
    aiPTI_Float = 1
    aiPTI_Double = 2
    aiPTI_String = 3
    aiPTI_Integer = 4
    aiPTI_Buffer = 5
    _aiPTI_Force32Bit = 2147483647
end

struct aiMaterialProperty
    mKey::aiString
    mSemantic::Cuint
    mIndex::Cuint
    mDataLength::Cuint
    mType::aiPropertyTypeInfo
    mData::Ptr{Cchar}
end

struct aiMaterial
    mProperties::Ptr{Ptr{aiMaterialProperty}}
    mNumProperties::Cuint
    mNumAllocated::Cuint
end

struct aiVectorKey
    mTime::Cdouble
    mValue::aiVector3D
end

struct aiQuatKey
    mTime::Cdouble
    mValue::aiQuaternion
end

@cenum aiAnimBehaviour::UInt32 begin
    aiAnimBehaviour_DEFAULT = 0
    aiAnimBehaviour_CONSTANT = 1
    aiAnimBehaviour_LINEAR = 2
    aiAnimBehaviour_REPEAT = 3
    _aiAnimBehaviour_Force32Bit = 2147483647
end

struct aiNodeAnim
    mNodeName::aiString
    mNumPositionKeys::Cuint
    mPositionKeys::Ptr{aiVectorKey}
    mNumRotationKeys::Cuint
    mRotationKeys::Ptr{aiQuatKey}
    mNumScalingKeys::Cuint
    mScalingKeys::Ptr{aiVectorKey}
    mPreState::aiAnimBehaviour
    mPostState::aiAnimBehaviour
end

struct aiMeshKey
    mTime::Cdouble
    mValue::Cuint
end

struct aiMeshAnim
    mName::aiString
    mNumKeys::Cuint
    mKeys::Ptr{aiMeshKey}
end

struct aiMeshMorphKey
    mTime::Cdouble
    mValues::Ptr{Cuint}
    mWeights::Ptr{Cdouble}
    mNumValuesAndWeights::Cuint
end

struct aiMeshMorphAnim
    mName::aiString
    mNumKeys::Cuint
    mKeys::Ptr{aiMeshMorphKey}
end

struct aiAnimation
    mName::aiString
    mDuration::Cdouble
    mTicksPerSecond::Cdouble
    mNumChannels::Cuint
    mChannels::Ptr{Ptr{aiNodeAnim}}
    mNumMeshChannels::Cuint
    mMeshChannels::Ptr{Ptr{aiMeshAnim}}
    mNumMorphMeshChannels::Cuint
    mMorphMeshChannels::Ptr{Ptr{aiMeshMorphAnim}}
end

struct aiTexel
    data::NTuple{4, UInt8}
end

function Base.getproperty(x::Ptr{aiTexel}, f::Symbol)
    f === :b && return Ptr{Cuchar}(x + 0)
    f === :g && return Ptr{Cuchar}(x + 1)
    f === :r && return Ptr{Cuchar}(x + 2)
    f === :a && return Ptr{Cuchar}(x + 3)
    return getfield(x, f)
end

function Base.getproperty(x::aiTexel, f::Symbol)
    r = Ref{aiTexel}(x)
    ptr = Base.unsafe_convert(Ptr{aiTexel}, r)
    fptr = getproperty(ptr, f)
    GC.@preserve r unsafe_load(fptr)
end

function Base.setproperty!(x::Ptr{aiTexel}, f::Symbol, v)
    unsafe_store!(getproperty(x, f), v)
end

struct aiTexture
    mWidth::Cuint
    mHeight::Cuint
    achFormatHint::NTuple{9, Cchar}
    pcData::Ptr{aiTexel}
    mFilename::aiString
end

@cenum aiLightSourceType::UInt32 begin
    aiLightSource_UNDEFINED = 0
    aiLightSource_DIRECTIONAL = 1
    aiLightSource_POINT = 2
    aiLightSource_SPOT = 3
    aiLightSource_AMBIENT = 4
    aiLightSource_AREA = 5
    _aiLightSource_Force32Bit = 2147483647
end

struct aiLight
    mName::aiString
    mType::aiLightSourceType
    mPosition::aiVector3D
    mDirection::aiVector3D
    mUp::aiVector3D
    mAttenuationConstant::Cfloat
    mAttenuationLinear::Cfloat
    mAttenuationQuadratic::Cfloat
    mColorDiffuse::aiColor3D
    mColorSpecular::aiColor3D
    mColorAmbient::aiColor3D
    mAngleInnerCone::Cfloat
    mAngleOuterCone::Cfloat
    mSize::aiVector2D
end

struct aiCamera
    mName::aiString
    mPosition::aiVector3D
    mUp::aiVector3D
    mLookAt::aiVector3D
    mHorizontalFOV::Cfloat
    mClipPlaneNear::Cfloat
    mClipPlaneFar::Cfloat
    mAspect::Cfloat
end

@cenum aiMetadataType::UInt32 begin
    AI_BOOL = 0
    AI_INT32 = 1
    AI_UINT64 = 2
    AI_FLOAT = 3
    AI_DOUBLE = 4
    AI_AISTRING = 5
    AI_AIVECTOR3D = 6
    AI_META_MAX = 7
    FORCE_32BIT = 2147483647
end

struct aiMetadataEntry
    mType::aiMetadataType
    mData::Ptr{Cvoid}
end

struct aiMetadata
    mNumProperties::Cuint
    mKeys::Ptr{aiString}
    mValues::Ptr{aiMetadataEntry}
end

struct aiScene
    mFlags::Cuint
    # mRootNode::Ptr{aiNode}
    mRootNode::Ptr{Cvoid}
    mNumMeshes::Cuint
    mMeshes::Ptr{Ptr{aiMesh}}
    mNumMaterials::Cuint
    mMaterials::Ptr{Ptr{aiMaterial}}
    mNumAnimations::Cuint
    mAnimations::Ptr{Ptr{aiAnimation}}
    mNumTextures::Cuint
    mTextures::Ptr{Ptr{aiTexture}}
    mNumLights::Cuint
    mLights::Ptr{Ptr{aiLight}}
    mNumCameras::Cuint
    mCameras::Ptr{Ptr{aiCamera}}
    mMetaData::Ptr{aiMetadata}
    mPrivate::Ptr{Cchar}
end

function Base.getproperty(x::aiScene, f::Symbol)
    f === :mRootNode && return Ptr{aiNode}(getfield(x, f))
    return getfield(x, f)
end

function aiImportFile(pFile, pFlags)
    ccall((:aiImportFile, libassimp), Ptr{aiScene}, (Ptr{Cchar}, Cuint), pFile, pFlags)
end

function aiImportFileEx(pFile, pFlags, pFS)
    ccall((:aiImportFileEx, libassimp), Ptr{aiScene}, (Ptr{Cchar}, Cuint, Ptr{aiFileIO}), pFile, pFlags, pFS)
end

function aiImportFileExWithProperties(pFile, pFlags, pFS, pProps)
    ccall((:aiImportFileExWithProperties, libassimp), Ptr{aiScene}, (Ptr{Cchar}, Cuint, Ptr{aiFileIO}, Ptr{aiPropertyStore}), pFile, pFlags, pFS, pProps)
end

function aiImportFileFromMemory(pBuffer, pLength, pFlags, pHint)
    ccall((:aiImportFileFromMemory, libassimp), Ptr{aiScene}, (Ptr{Cchar}, Cuint, Cuint, Ptr{Cchar}), pBuffer, pLength, pFlags, pHint)
end

function aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, pProps)
    ccall((:aiImportFileFromMemoryWithProperties, libassimp), Ptr{aiScene}, (Ptr{Cchar}, Cuint, Cuint, Ptr{Cchar}, Ptr{aiPropertyStore}), pBuffer, pLength, pFlags, pHint, pProps)
end

function aiApplyPostProcessing(pScene, pFlags)
    ccall((:aiApplyPostProcessing, libassimp), Ptr{aiScene}, (Ptr{aiScene}, Cuint), pScene, pFlags)
end

function aiGetPredefinedLogStream(pStreams, file)
    ccall((:aiGetPredefinedLogStream, libassimp), aiLogStream, (aiDefaultLogStream, Ptr{Cchar}), pStreams, file)
end

function aiAttachLogStream(stream)
    ccall((:aiAttachLogStream, libassimp), Cvoid, (Ptr{aiLogStream},), stream)
end

function aiEnableVerboseLogging(d)
    ccall((:aiEnableVerboseLogging, libassimp), Cvoid, (aiBool,), d)
end

function aiDetachLogStream(stream)
    ccall((:aiDetachLogStream, libassimp), aiReturn, (Ptr{aiLogStream},), stream)
end

function aiDetachAllLogStreams()
    ccall((:aiDetachAllLogStreams, libassimp), Cvoid, ())
end

function aiReleaseImport(pScene)
    ccall((:aiReleaseImport, libassimp), Cvoid, (Ptr{aiScene},), pScene)
end

function aiGetErrorString()
    ccall((:aiGetErrorString, libassimp), Ptr{Cchar}, ())
end

function aiIsExtensionSupported(szExtension)
    ccall((:aiIsExtensionSupported, libassimp), aiBool, (Ptr{Cchar},), szExtension)
end

function aiGetExtensionList(szOut)
    ccall((:aiGetExtensionList, libassimp), Cvoid, (Ptr{aiString},), szOut)
end

function aiGetMemoryRequirements(pIn, in)
    ccall((:aiGetMemoryRequirements, libassimp), Cvoid, (Ptr{aiScene}, Ptr{aiMemoryInfo}), pIn, in)
end

function aiCreatePropertyStore()
    ccall((:aiCreatePropertyStore, libassimp), Ptr{aiPropertyStore}, ())
end

function aiReleasePropertyStore(p)
    ccall((:aiReleasePropertyStore, libassimp), Cvoid, (Ptr{aiPropertyStore},), p)
end

function aiSetImportPropertyInteger(store, szName, value)
    ccall((:aiSetImportPropertyInteger, libassimp), Cvoid, (Ptr{aiPropertyStore}, Ptr{Cchar}, Cint), store, szName, value)
end

function aiSetImportPropertyFloat(store, szName, value)
    ccall((:aiSetImportPropertyFloat, libassimp), Cvoid, (Ptr{aiPropertyStore}, Ptr{Cchar}, ai_real), store, szName, value)
end

function aiSetImportPropertyString(store, szName, st)
    ccall((:aiSetImportPropertyString, libassimp), Cvoid, (Ptr{aiPropertyStore}, Ptr{Cchar}, Ptr{aiString}), store, szName, st)
end

function aiSetImportPropertyMatrix(store, szName, mat)
    ccall((:aiSetImportPropertyMatrix, libassimp), Cvoid, (Ptr{aiPropertyStore}, Ptr{Cchar}, Ptr{aiMatrix4x4}), store, szName, mat)
end

function aiCreateQuaternionFromMatrix(quat, mat)
    ccall((:aiCreateQuaternionFromMatrix, libassimp), Cvoid, (Ptr{aiQuaternion}, Ptr{aiMatrix3x3}), quat, mat)
end

function aiDecomposeMatrix(mat, scaling, rotation, position)
    ccall((:aiDecomposeMatrix, libassimp), Cvoid, (Ptr{aiMatrix4x4}, Ptr{aiVector3D}, Ptr{aiQuaternion}, Ptr{aiVector3D}), mat, scaling, rotation, position)
end

function aiTransposeMatrix4(mat)
    ccall((:aiTransposeMatrix4, libassimp), Cvoid, (Ptr{aiMatrix4x4},), mat)
end

function aiTransposeMatrix3(mat)
    ccall((:aiTransposeMatrix3, libassimp), Cvoid, (Ptr{aiMatrix3x3},), mat)
end

function aiTransformVecByMatrix3(vec, mat)
    ccall((:aiTransformVecByMatrix3, libassimp), Cvoid, (Ptr{aiVector3D}, Ptr{aiMatrix3x3}), vec, mat)
end

function aiTransformVecByMatrix4(vec, mat)
    ccall((:aiTransformVecByMatrix4, libassimp), Cvoid, (Ptr{aiVector3D}, Ptr{aiMatrix4x4}), vec, mat)
end

function aiMultiplyMatrix4(dst, src)
    ccall((:aiMultiplyMatrix4, libassimp), Cvoid, (Ptr{aiMatrix4x4}, Ptr{aiMatrix4x4}), dst, src)
end

function aiMultiplyMatrix3(dst, src)
    ccall((:aiMultiplyMatrix3, libassimp), Cvoid, (Ptr{aiMatrix3x3}, Ptr{aiMatrix3x3}), dst, src)
end

function aiIdentityMatrix3(mat)
    ccall((:aiIdentityMatrix3, libassimp), Cvoid, (Ptr{aiMatrix3x3},), mat)
end

function aiIdentityMatrix4(mat)
    ccall((:aiIdentityMatrix4, libassimp), Cvoid, (Ptr{aiMatrix4x4},), mat)
end

function aiGetImportFormatCount()
    ccall((:aiGetImportFormatCount, libassimp), Csize_t, ())
end

function aiGetImportFormatDescription(pIndex)
    ccall((:aiGetImportFormatDescription, libassimp), Ptr{aiImporterDesc}, (Csize_t,), pIndex)
end

struct aiExportFormatDesc
    id::Ptr{Cchar}
    description::Ptr{Cchar}
    fileExtension::Ptr{Cchar}
end

function aiGetExportFormatCount()
    ccall((:aiGetExportFormatCount, libassimp), Csize_t, ())
end

function aiGetExportFormatDescription(pIndex)
    ccall((:aiGetExportFormatDescription, libassimp), Ptr{aiExportFormatDesc}, (Csize_t,), pIndex)
end

function aiReleaseExportFormatDescription(desc)
    ccall((:aiReleaseExportFormatDescription, libassimp), Cvoid, (Ptr{aiExportFormatDesc},), desc)
end

function aiCopyScene(pIn, pOut)
    ccall((:aiCopyScene, libassimp), Cvoid, (Ptr{aiScene}, Ptr{Ptr{aiScene}}), pIn, pOut)
end

function aiFreeScene(pIn)
    ccall((:aiFreeScene, libassimp), Cvoid, (Ptr{aiScene},), pIn)
end

function aiExportScene(pScene, pFormatId, pFileName, pPreprocessing)
    ccall((:aiExportScene, libassimp), aiReturn, (Ptr{aiScene}, Ptr{Cchar}, Ptr{Cchar}, Cuint), pScene, pFormatId, pFileName, pPreprocessing)
end

function aiExportSceneEx(pScene, pFormatId, pFileName, pIO, pPreprocessing)
    ccall((:aiExportSceneEx, libassimp), aiReturn, (Ptr{aiScene}, Ptr{Cchar}, Ptr{Cchar}, Ptr{aiFileIO}, Cuint), pScene, pFormatId, pFileName, pIO, pPreprocessing)
end

struct aiExportDataBlob
    size::Csize_t
    data::Ptr{Cvoid}
    name::aiString
    next::Ptr{aiExportDataBlob}
end

function aiExportSceneToBlob(pScene, pFormatId, pPreprocessing)
    ccall((:aiExportSceneToBlob, libassimp), Ptr{aiExportDataBlob}, (Ptr{aiScene}, Ptr{Cchar}, Cuint), pScene, pFormatId, pPreprocessing)
end

function aiReleaseExportBlob(pData)
    ccall((:aiReleaseExportBlob, libassimp), Cvoid, (Ptr{aiExportDataBlob},), pData)
end

@cenum aiPrimitiveType::UInt32 begin
    aiPrimitiveType_POINT = 1
    aiPrimitiveType_LINE = 2
    aiPrimitiveType_TRIANGLE = 4
    aiPrimitiveType_POLYGON = 8
    _aiPrimitiveType_Force32Bit = 2147483647
end

@cenum aiMorphingMethod::UInt32 begin
    aiMorphingMethod_VERTEX_BLEND = 1
    aiMorphingMethod_MORPH_NORMALIZED = 2
    aiMorphingMethod_MORPH_RELATIVE = 3
    _aiMorphingMethod_Force32Bit = 2147483647
end

@cenum aiTextureOp::UInt32 begin
    aiTextureOp_Multiply = 0
    aiTextureOp_Add = 1
    aiTextureOp_Subtract = 2
    aiTextureOp_Divide = 3
    aiTextureOp_SmoothAdd = 4
    aiTextureOp_SignedAdd = 5
    _aiTextureOp_Force32Bit = 2147483647
end

@cenum aiTextureMapMode::UInt32 begin
    aiTextureMapMode_Wrap = 0
    aiTextureMapMode_Clamp = 1
    aiTextureMapMode_Decal = 3
    aiTextureMapMode_Mirror = 2
    _aiTextureMapMode_Force32Bit = 2147483647
end

@cenum aiTextureMapping::UInt32 begin
    aiTextureMapping_UV = 0
    aiTextureMapping_SPHERE = 1
    aiTextureMapping_CYLINDER = 2
    aiTextureMapping_BOX = 3
    aiTextureMapping_PLANE = 4
    aiTextureMapping_OTHER = 5
    _aiTextureMapping_Force32Bit = 2147483647
end

@cenum aiTextureType::UInt32 begin
    aiTextureType_NONE = 0
    aiTextureType_DIFFUSE = 1
    aiTextureType_SPECULAR = 2
    aiTextureType_AMBIENT = 3
    aiTextureType_EMISSIVE = 4
    aiTextureType_HEIGHT = 5
    aiTextureType_NORMALS = 6
    aiTextureType_SHININESS = 7
    aiTextureType_OPACITY = 8
    aiTextureType_DISPLACEMENT = 9
    aiTextureType_LIGHTMAP = 10
    aiTextureType_REFLECTION = 11
    aiTextureType_BASE_COLOR = 12
    aiTextureType_NORMAL_CAMERA = 13
    aiTextureType_EMISSION_COLOR = 14
    aiTextureType_METALNESS = 15
    aiTextureType_DIFFUSE_ROUGHNESS = 16
    aiTextureType_AMBIENT_OCCLUSION = 17
    aiTextureType_UNKNOWN = 18
    _aiTextureType_Force32Bit = 2147483647
end

@cenum aiShadingMode::UInt32 begin
    aiShadingMode_Flat = 1
    aiShadingMode_Gouraud = 2
    aiShadingMode_Phong = 3
    aiShadingMode_Blinn = 4
    aiShadingMode_Toon = 5
    aiShadingMode_OrenNayar = 6
    aiShadingMode_Minnaert = 7
    aiShadingMode_CookTorrance = 8
    aiShadingMode_NoShading = 9
    aiShadingMode_Fresnel = 10
    _aiShadingMode_Force32Bit = 2147483647
end

@cenum aiTextureFlags::UInt32 begin
    aiTextureFlags_Invert = 1
    aiTextureFlags_UseAlpha = 2
    aiTextureFlags_IgnoreAlpha = 4
    _aiTextureFlags_Force32Bit = 2147483647
end

@cenum aiBlendMode::UInt32 begin
    aiBlendMode_Default = 0
    aiBlendMode_Additive = 1
    _aiBlendMode_Force32Bit = 2147483647
end

struct aiUVTransform
    mTranslation::aiVector2D
    mScaling::aiVector2D
    mRotation::ai_real
end

function aiGetMaterialProperty(pMat, pKey, type, index, pPropOut)
    ccall((:aiGetMaterialProperty, libassimp), aiReturn, (Ptr{aiMaterial}, Ptr{Cchar}, Cuint, Cuint, Ptr{Ptr{aiMaterialProperty}}), pMat, pKey, type, index, pPropOut)
end

function aiGetMaterialFloatArray(pMat, pKey, type, index, pOut, pMax)
    ccall((:aiGetMaterialFloatArray, libassimp), aiReturn, (Ptr{aiMaterial}, Ptr{Cchar}, Cuint, Cuint, Ptr{ai_real}, Ptr{Cuint}), pMat, pKey, type, index, pOut, pMax)
end

function aiGetMaterialIntegerArray(pMat, pKey, type, index, pOut, pMax)
    ccall((:aiGetMaterialIntegerArray, libassimp), aiReturn, (Ptr{aiMaterial}, Ptr{Cchar}, Cuint, Cuint, Ptr{Cint}, Ptr{Cuint}), pMat, pKey, type, index, pOut, pMax)
end

function aiGetMaterialColor(pMat, pKey, type, index, pOut)
    ccall((:aiGetMaterialColor, libassimp), aiReturn, (Ptr{aiMaterial}, Ptr{Cchar}, Cuint, Cuint, Ptr{aiColor4D}), pMat, pKey, type, index, pOut)
end

function aiGetMaterialUVTransform(pMat, pKey, type, index, pOut)
    ccall((:aiGetMaterialUVTransform, libassimp), aiReturn, (Ptr{aiMaterial}, Ptr{Cchar}, Cuint, Cuint, Ptr{aiUVTransform}), pMat, pKey, type, index, pOut)
end

function aiGetMaterialString(pMat, pKey, type, index, pOut)
    ccall((:aiGetMaterialString, libassimp), aiReturn, (Ptr{aiMaterial}, Ptr{Cchar}, Cuint, Cuint, Ptr{aiString}), pMat, pKey, type, index, pOut)
end

function aiGetMaterialTextureCount(pMat, type)
    ccall((:aiGetMaterialTextureCount, libassimp), Cuint, (Ptr{aiMaterial}, aiTextureType), pMat, type)
end

function aiGetMaterialTexture(mat, type, index, path, mapping, uvindex, blend, op, mapmode, flags)
    ccall((:aiGetMaterialTexture, libassimp), aiReturn, (Ptr{aiMaterial}, aiTextureType, Cuint, Ptr{aiString}, Ptr{aiTextureMapping}, Ptr{Cuint}, Ptr{ai_real}, Ptr{aiTextureOp}, Ptr{aiTextureMapMode}, Ptr{Cuint}), mat, type, index, path, mapping, uvindex, blend, op, mapmode, flags)
end

struct aiNode
    data::NTuple{1144, UInt8}
end

function Base.getproperty(x::Ptr{aiNode}, f::Symbol)
    f === :mName && return Ptr{aiString}(x + 0)
    f === :mTransformation && return Ptr{aiMatrix4x4}(x + 1028)
    f === :mParent && return Ptr{Ptr{aiNode}}(x + 1096)
    f === :mNumChildren && return Ptr{Cuint}(x + 1104)
    f === :mChildren && return Ptr{Ptr{Ptr{aiNode}}}(x + 1112)
    f === :mNumMeshes && return Ptr{Cuint}(x + 1120)
    f === :mMeshes && return Ptr{Ptr{Cuint}}(x + 1128)
    f === :mMetaData && return Ptr{Ptr{aiMetadata}}(x + 1136)
    return getfield(x, f)
end

function Base.getproperty(x::aiNode, f::Symbol)
    r = Ref{aiNode}(x)
    ptr = Base.unsafe_convert(Ptr{aiNode}, r)
    fptr = getproperty(ptr, f)
    GC.@preserve r unsafe_load(fptr)
end

function Base.setproperty!(x::Ptr{aiNode}, f::Symbol, v)
    unsafe_store!(getproperty(x, f), v)
end

@cenum aiPostProcessSteps::UInt32 begin
    aiProcess_CalcTangentSpace = 1
    aiProcess_JoinIdenticalVertices = 2
    aiProcess_MakeLeftHanded = 4
    aiProcess_Triangulate = 8
    aiProcess_RemoveComponent = 16
    aiProcess_GenNormals = 32
    aiProcess_GenSmoothNormals = 64
    aiProcess_SplitLargeMeshes = 128
    aiProcess_PreTransformVertices = 256
    aiProcess_LimitBoneWeights = 512
    aiProcess_ValidateDataStructure = 1024
    aiProcess_ImproveCacheLocality = 2048
    aiProcess_RemoveRedundantMaterials = 4096
    aiProcess_FixInfacingNormals = 8192
    aiProcess_SortByPType = 32768
    aiProcess_FindDegenerates = 65536
    aiProcess_FindInvalidData = 131072
    aiProcess_GenUVCoords = 262144
    aiProcess_TransformUVCoords = 524288
    aiProcess_FindInstances = 1048576
    aiProcess_OptimizeMeshes = 2097152
    aiProcess_OptimizeGraph = 4194304
    aiProcess_FlipUVs = 8388608
    aiProcess_FlipWindingOrder = 16777216
    aiProcess_SplitByBoneCount = 33554432
    aiProcess_Debone = 67108864
    aiProcess_GlobalScale = 134217728
    aiProcess_EmbedTextures = 268435456
    aiProcess_ForceGenNormals = 536870912
    aiProcess_DropNormals = 1073741824
    aiProcess_GenBoundingBoxes = 0x0000000080000000
end

function aiGetLegalString()
    ccall((:aiGetLegalString, libassimp), Ptr{Cchar}, ())
end

function aiGetVersionMinor()
    ccall((:aiGetVersionMinor, libassimp), Cuint, ())
end

function aiGetVersionMajor()
    ccall((:aiGetVersionMajor, libassimp), Cuint, ())
end

function aiGetVersionRevision()
    ccall((:aiGetVersionRevision, libassimp), Cuint, ())
end

# no prototype is found for this function at version.h:90:24, please use with caution
function aiGetBranchName()
    ccall((:aiGetBranchName, libassimp), Ptr{Cchar}, ())
end

function aiGetCompileFlags()
    ccall((:aiGetCompileFlags, libassimp), Cuint, ())
end

const AI_CONFIG_GLOB_MEASURE_TIME = "GLOB_MEASURE_TIME"

const AI_CONFIG_IMPORT_NO_SKELETON_MESHES = "IMPORT_NO_SKELETON_MESHES"

const AI_CONFIG_PP_SBBC_MAX_BONES = "PP_SBBC_MAX_BONES"

const AI_SBBC_DEFAULT_MAX_BONES = 60

const AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE = "PP_CT_MAX_SMOOTHING_ANGLE"

const AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX = "PP_CT_TEXTURE_CHANNEL_INDEX"

const AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE = "PP_GSN_MAX_SMOOTHING_ANGLE"

const AI_CONFIG_IMPORT_MDL_COLORMAP = "IMPORT_MDL_COLORMAP"

const AI_CONFIG_PP_RRM_EXCLUDE_LIST = "PP_RRM_EXCLUDE_LIST"

const AI_CONFIG_PP_PTV_KEEP_HIERARCHY = "PP_PTV_KEEP_HIERARCHY"

const AI_CONFIG_PP_PTV_NORMALIZE = "PP_PTV_NORMALIZE"

const AI_CONFIG_PP_PTV_ADD_ROOT_TRANSFORMATION = "PP_PTV_ADD_ROOT_TRANSFORMATION"

const AI_CONFIG_PP_PTV_ROOT_TRANSFORMATION = "PP_PTV_ROOT_TRANSFORMATION"

const AI_CONFIG_PP_FD_REMOVE = "PP_FD_REMOVE"

const AI_CONFIG_PP_FD_CHECKAREA = "PP_FD_CHECKAREA"

const AI_CONFIG_PP_OG_EXCLUDE_LIST = "PP_OG_EXCLUDE_LIST"

const AI_CONFIG_PP_SLM_TRIANGLE_LIMIT = "PP_SLM_TRIANGLE_LIMIT"

const AI_SLM_DEFAULT_MAX_TRIANGLES = 1000000

const AI_CONFIG_PP_SLM_VERTEX_LIMIT = "PP_SLM_VERTEX_LIMIT"

const AI_SLM_DEFAULT_MAX_VERTICES = 1000000

const AI_CONFIG_PP_LBW_MAX_WEIGHTS = "PP_LBW_MAX_WEIGHTS"

const AI_LMW_MAX_WEIGHTS = 0x04

const AI_CONFIG_PP_DB_THRESHOLD = "PP_DB_THRESHOLD"

const AI_DEBONE_THRESHOLD = Float32(1.0)

const AI_CONFIG_PP_DB_ALL_OR_NONE = "PP_DB_ALL_OR_NONE"

const PP_ICL_PTCACHE_SIZE = 12

const AI_CONFIG_PP_ICL_PTCACHE_SIZE = "PP_ICL_PTCACHE_SIZE"

const AI_CONFIG_PP_RVC_FLAGS = "PP_RVC_FLAGS"

const AI_CONFIG_PP_SBP_REMOVE = "PP_SBP_REMOVE"

const AI_CONFIG_PP_FID_ANIM_ACCURACY = "PP_FID_ANIM_ACCURACY"

const AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS = "PP_FID_IGNORE_TEXTURECOORDS"

const AI_UVTRAFO_SCALING = 0x01

const AI_UVTRAFO_ROTATION = 0x02

const AI_UVTRAFO_TRANSLATION = 0x04

const AI_UVTRAFO_ALL = (AI_UVTRAFO_SCALING | AI_UVTRAFO_ROTATION) | AI_UVTRAFO_TRANSLATION

const AI_CONFIG_PP_TUV_EVALUATE = "PP_TUV_EVALUATE"

const AI_CONFIG_FAVOUR_SPEED = "FAVOUR_SPEED"

const AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS = "IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS"

const AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS = "IMPORT_FBX_READ_ALL_MATERIALS"

const AI_CONFIG_IMPORT_FBX_READ_MATERIALS = "IMPORT_FBX_READ_MATERIALS"

const AI_CONFIG_IMPORT_FBX_READ_TEXTURES = "IMPORT_FBX_READ_TEXTURES"

const AI_CONFIG_IMPORT_FBX_READ_CAMERAS = "IMPORT_FBX_READ_CAMERAS"

const AI_CONFIG_IMPORT_FBX_READ_LIGHTS = "IMPORT_FBX_READ_LIGHTS"

const AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS = "IMPORT_FBX_READ_ANIMATIONS"

const AI_CONFIG_IMPORT_FBX_STRICT_MODE = "IMPORT_FBX_STRICT_MODE"

const AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS = "IMPORT_FBX_PRESERVE_PIVOTS"

const AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES = "IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES"

const AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING = "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"

const AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES = "AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES"

const AI_CONFIG_FBX_CONVERT_TO_M = "AI_CONFIG_FBX_CONVERT_TO_M"

const AI_CONFIG_IMPORT_GLOBAL_KEYFRAME = "IMPORT_GLOBAL_KEYFRAME"

const AI_CONFIG_IMPORT_MD3_KEYFRAME = "IMPORT_MD3_KEYFRAME"

const AI_CONFIG_IMPORT_MD2_KEYFRAME = "IMPORT_MD2_KEYFRAME"

const AI_CONFIG_IMPORT_MDL_KEYFRAME = "IMPORT_MDL_KEYFRAME"

const AI_CONFIG_IMPORT_MDC_KEYFRAME = "IMPORT_MDC_KEYFRAME"

const AI_CONFIG_IMPORT_SMD_KEYFRAME = "IMPORT_SMD_KEYFRAME"

const AI_CONFIG_IMPORT_UNREAL_KEYFRAME = "IMPORT_UNREAL_KEYFRAME"

const AI_CONFIG_IMPORT_SMD_LOAD_ANIMATION_LIST = "IMPORT_SMD_LOAD_ANIMATION_LIST"

const AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL = "IMPORT_AC_SEPARATE_BFCULL"

const AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION = "IMPORT_AC_EVAL_SUBDIVISION"

const AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS = "UNREAL_HANDLE_FLAGS"

const AI_CONFIG_IMPORT_TER_MAKE_UVS = "IMPORT_TER_MAKE_UVS"

const AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS = "IMPORT_ASE_RECONSTRUCT_NORMALS"

const AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART = "IMPORT_MD3_HANDLE_MULTIPART"

const AI_CONFIG_IMPORT_MD3_SKIN_NAME = "IMPORT_MD3_SKIN_NAME"

const AI_CONFIG_IMPORT_MD3_SHADER_SRC = "IMPORT_MD3_SHADER_SRC"

const AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY = "IMPORT_LWO_ONE_LAYER_ONLY"

const AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD = "IMPORT_MD5_NO_ANIM_AUTOLOAD"

const AI_CONFIG_IMPORT_LWS_ANIM_START = "IMPORT_LWS_ANIM_START"

const AI_CONFIG_IMPORT_LWS_ANIM_END = "IMPORT_LWS_ANIM_END"

const AI_CONFIG_IMPORT_IRR_ANIM_FPS = "IMPORT_IRR_ANIM_FPS"

const AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE = "IMPORT_OGRE_MATERIAL_FILE"

const AI_CONFIG_IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME = "IMPORT_OGRE_TEXTURETYPE_FROM_FILENAME"

const AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT = "AI_CONFIG_ANDROID_JNI_ASSIMP_MANAGER_SUPPORT"

const AI_CONFIG_IMPORT_IFC_SKIP_SPACE_REPRESENTATIONS = "IMPORT_IFC_SKIP_SPACE_REPRESENTATIONS"

const AI_CONFIG_IMPORT_IFC_CUSTOM_TRIANGULATION = "IMPORT_IFC_CUSTOM_TRIANGULATION"

const AI_CONFIG_IMPORT_IFC_SMOOTHING_ANGLE = "IMPORT_IFC_SMOOTHING_ANGLE"

const AI_IMPORT_IFC_DEFAULT_SMOOTHING_ANGLE = Float32(10.0)

const AI_CONFIG_IMPORT_IFC_CYLINDRICAL_TESSELLATION = "IMPORT_IFC_CYLINDRICAL_TESSELLATION"

const AI_IMPORT_IFC_DEFAULT_CYLINDRICAL_TESSELLATION = 32

const AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION = "IMPORT_COLLADA_IGNORE_UP_DIRECTION"

const AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES = "IMPORT_COLLADA_USE_COLLADA_NAMES"

const AI_CONFIG_EXPORT_XFILE_64BIT = "EXPORT_XFILE_64BIT"

const AI_CONFIG_EXPORT_POINT_CLOUDS = "EXPORT_POINT_CLOUDS"

const AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY = "GLOBAL_SCALE_FACTOR"

const AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT = Float32(1.0)

const AI_CONFIG_APP_SCALE_KEY = "APP_SCALE_FACTOR"

# Skipping MacroDefinition: ASSIMP_API __attribute__ ( ( visibility ( "default" ) ) )

# Skipping MacroDefinition: AI_FORCE_INLINE inline

# Skipping MacroDefinition: AI_WONT_RETURN_SUFFIX __attribute__ ( ( noreturn ) )

# Skipping MacroDefinition: C_STRUCT struct

# Skipping MacroDefinition: C_ENUM enum

const ASSIMP_AI_REAL_TEXT_PRECISION = 8

const AI_MATH_PI = 3.141592653589793

const AI_MATH_TWO_PI = AI_MATH_PI * 2.0

const AI_MATH_HALF_PI = AI_MATH_PI * 0.5

const AI_MATH_PI_F = Float32(3.1415926538)

const AI_MATH_TWO_PI_F = AI_MATH_PI_F * Float32(2.0)

const AI_MATH_HALF_PI_F = AI_MATH_PI_F * Float32(0.5)

# Skipping MacroDefinition: AI_NO_EXCEPT noexcept

const MAXLEN = 1024

const AI_SUCCESS = aiReturn_SUCCESS

const AI_FAILURE = aiReturn_FAILURE

const AI_OUTOFMEMORY = aiReturn_OUTOFMEMORY

const DLS_FILE = aiDefaultLogStream_FILE

const DLS_STDOUT = aiDefaultLogStream_STDOUT

const DLS_STDERR = aiDefaultLogStream_STDERR

const DLS_DEBUGGER = aiDefaultLogStream_DEBUGGER

const AI_FALSE = 0

const AI_TRUE = 1

const AI_EMBEDDED_TEXNAME_PREFIX = "*"

# Skipping MacroDefinition: PACK_STRUCT __attribute__ ( ( __packed__ ) )

const HINTMAXTEXTURELEN = 9

const AI_MAX_FACE_INDICES = 0x7fff

const AI_MAX_BONE_WEIGHTS = 0x7fffffff

const AI_MAX_VERTICES = 0x7fffffff

const AI_MAX_FACES = 0x7fffffff

const AI_MAX_NUMBER_OF_COLOR_SETS = 0x08

const AI_MAX_NUMBER_OF_TEXTURECOORDS = 0x08

const AI_DEFAULT_MATERIAL_NAME = "DefaultMaterial"

const AI_TEXTURE_TYPE_MAX = aiTextureType_UNKNOWN

const AI_MATKEY_NAME = ("?mat.name", 0, 0)

const AI_MATKEY_TWOSIDED = ("\$mat.twosided", 0, 0)

const AI_MATKEY_SHADING_MODEL = ("\$mat.shadingm", 0, 0)

const AI_MATKEY_ENABLE_WIREFRAME = ("\$mat.wireframe", 0, 0)

const AI_MATKEY_BLEND_FUNC = ("\$mat.blend", 0, 0)

const AI_MATKEY_OPACITY = ("\$mat.opacity", 0, 0)

const AI_MATKEY_TRANSPARENCYFACTOR = ("\$mat.transparencyfactor", 0, 0)

const AI_MATKEY_BUMPSCALING = ("\$mat.bumpscaling", 0, 0)

const AI_MATKEY_SHININESS = ("\$mat.shininess", 0, 0)

const AI_MATKEY_REFLECTIVITY = ("\$mat.reflectivity", 0, 0)

const AI_MATKEY_SHININESS_STRENGTH = ("\$mat.shinpercent", 0, 0)

const AI_MATKEY_REFRACTI = ("\$mat.refracti", 0, 0)

const AI_MATKEY_COLOR_DIFFUSE = ("\$clr.diffuse", 0, 0)

const AI_MATKEY_COLOR_AMBIENT = ("\$clr.ambient", 0, 0)

const AI_MATKEY_COLOR_SPECULAR = ("\$clr.specular", 0, 0)

const AI_MATKEY_COLOR_EMISSIVE = ("\$clr.emissive", 0, 0)

const AI_MATKEY_COLOR_TRANSPARENT = ("\$clr.transparent", 0, 0)

const AI_MATKEY_COLOR_REFLECTIVE = ("\$clr.reflective", 0, 0)

const AI_MATKEY_GLOBAL_BACKGROUND_IMAGE = ("?bg.global", 0, 0)

const AI_MATKEY_GLOBAL_SHADERLANG = ("?sh.lang", 0, 0)

const AI_MATKEY_SHADER_VERTEX = ("?sh.vs", 0, 0)

const AI_MATKEY_SHADER_FRAGMENT = ("?sh.fs", 0, 0)

const AI_MATKEY_SHADER_GEO = ("?sh.gs", 0, 0)

const AI_MATKEY_SHADER_TESSELATION = ("?sh.ts", 0, 0)

const AI_MATKEY_SHADER_PRIMITIVE = ("?sh.ps", 0, 0)

const AI_MATKEY_SHADER_COMPUTE = ("?sh.cs", 0, 0)

const _AI_MATKEY_TEXTURE_BASE = "\$tex.file"

const _AI_MATKEY_UVWSRC_BASE = "\$tex.uvwsrc"

const _AI_MATKEY_TEXOP_BASE = "\$tex.op"

const _AI_MATKEY_MAPPING_BASE = "\$tex.mapping"

const _AI_MATKEY_TEXBLEND_BASE = "\$tex.blend"

const _AI_MATKEY_MAPPINGMODE_U_BASE = "\$tex.mapmodeu"

const _AI_MATKEY_MAPPINGMODE_V_BASE = "\$tex.mapmodev"

const _AI_MATKEY_TEXMAP_AXIS_BASE = "\$tex.mapaxis"

const _AI_MATKEY_UVTRANSFORM_BASE = "\$tex.uvtrafo"

const _AI_MATKEY_TEXFLAGS_BASE = "\$tex.flags"

const AI_SCENE_FLAGS_INCOMPLETE = 0x01

const AI_SCENE_FLAGS_VALIDATED = 0x02

const AI_SCENE_FLAGS_VALIDATION_WARNING = 0x04

const AI_SCENE_FLAGS_NON_VERBOSE_FORMAT = 0x08

const AI_SCENE_FLAGS_TERRAIN = 0x10

const AI_SCENE_FLAGS_ALLOW_SHARED = 0x20

const aiProcess_ConvertToLeftHanded = ((aiProcess_MakeLeftHanded | aiProcess_FlipUVs) | aiProcess_FlipWindingOrder) | 0

const aiProcessPreset_TargetRealtime_Fast = (((((aiProcess_CalcTangentSpace | aiProcess_GenNormals) | aiProcess_JoinIdenticalVertices) | aiProcess_Triangulate) | aiProcess_GenUVCoords) | aiProcess_SortByPType) | 0

const aiProcessPreset_TargetRealtime_Quality = (((((((((((aiProcess_CalcTangentSpace | aiProcess_GenSmoothNormals) | aiProcess_JoinIdenticalVertices) | aiProcess_ImproveCacheLocality) | aiProcess_LimitBoneWeights) | aiProcess_RemoveRedundantMaterials) | aiProcess_SplitLargeMeshes) | aiProcess_Triangulate) | aiProcess_GenUVCoords) | aiProcess_SortByPType) | aiProcess_FindDegenerates) | aiProcess_FindInvalidData) | 0

const aiProcessPreset_TargetRealtime_MaxQuality = (((aiProcessPreset_TargetRealtime_Quality | aiProcess_FindInstances) | aiProcess_ValidateDataStructure) | aiProcess_OptimizeMeshes) | 0

const AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR = ("\$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0)

const AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR = ("\$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0)

const AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR = ("\$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0)

const AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE = (aiTextureType_DIFFUSE, 1)

const AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE = (aiTextureType_UNKNOWN, 0)

const AI_MATKEY_GLTF_ALPHAMODE = ("\$mat.gltf.alphaMode", 0, 0)

const AI_MATKEY_GLTF_ALPHACUTOFF = ("\$mat.gltf.alphaCutoff", 0, 0)

const AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS = ("\$mat.gltf.pbrSpecularGlossiness", 0, 0)

const AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR = ("\$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0)

const AI_MATKEY_GLTF_UNLIT = ("\$mat.gltf.unlit", 0, 0)

const _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE = "\$tex.file.texCoord"

const _AI_MATKEY_GLTF_MAPPINGNAME_BASE = "\$tex.mappingname"

const _AI_MATKEY_GLTF_MAPPINGID_BASE = "\$tex.mappingid"

const _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE = "\$tex.mappingfiltermag"

const _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE = "\$tex.mappingfiltermin"

const _AI_MATKEY_GLTF_SCALE_BASE = "\$tex.scale"

const _AI_MATKEY_GLTF_STRENGTH_BASE = "\$tex.strength"

const ASSIMP_CFLAGS_SHARED = 0x01

const ASSIMP_CFLAGS_STLPORT = 0x02

const ASSIMP_CFLAGS_DEBUG = 0x04

const ASSIMP_CFLAGS_NOBOOST = 0x08

const ASSIMP_CFLAGS_SINGLETHREADED = 0x10

# exports
const PREFIXES = ["ai", "AI"]
for name in names(@__MODULE__; all=true), prefix in PREFIXES
    if startswith(string(name), prefix)
        @eval export $name
    end
end

end # module


text:
# Use baremodule to shave off a few KB from the serialized `.ji` file
baremodule Kaleido_jll
using Base
using Base: UUID
import JLLWrappers

JLLWrappers.@generate_main_file_header("Kaleido")
JLLWrappers.@generate_main_file("Kaleido", UUID("f7e6163d-2fa5-5f23-b69c-1db539e41963"))
end  # module Kaleido_jll

ext: jl


text:
using ReservoirComputing
using MLJLinearModels
#model parameters
const approx_res_size = 30
const radius = 1.2
const activation = tanh
const degree = 6
const sigma = 0.1
const beta = 0.0
const alpha = 1.0
const nla_type = NLADefault()
const in_size = 3
const out_size = 3
const extended_states = false
const delta = 0.5

const train_len = 50
const predict_len = 12
data = ones(Float64, in_size, 100)
train = data[:, 1:1+train_len-1]
test = data[:, train_len:train_len+predict_len-1]

#constructor 1
esn = ESN(approx_res_size,
    train,
    degree,
    radius,
    activation = activation,
    sigma = sigma,
    alpha = alpha,
    nla_type = nla_type,
    extended_states = extended_states)

W_out = ESNtrain(esn, beta)

fit1 = ESNfitted(esn, W_out; autonomous=false)
@test size(fit1) == size(train)

fit2 = ESNfitted(esn, W_out; autonomous=true)
@test size(fit1) == size(train)


text:
"""
Top level parser supporting regular expression features
captures, backreferences and subroutines.
Collects subroutines in field `subroutines::Vector` and
indices of named capture groups in field `names::Dict`.

!!! note
    implicitly called in [`match`](@ref)
See also [`Backreference`](@ref), [`Capture`](@ref), [`Subroutine`](@ref)
"""
@auto_hash_equals struct ParserWithCaptures{P,S,T} <: WrappedParser{P,S,T}
    parser::P
    subroutines::Vector{ParserTypes} ## todo: rename subroutines
    names::Dict{Symbol,Vector{Int}}
    ParserWithCaptures(parser,captures,names) =
        new{typeof(parser),state_type(parser),result_type(parser)}(parser,captures,names)
end
function print_constructor(io::IO, x::ParserWithCaptures)
    print_constructor(io,x.parser)
    print(io, " |> regular expression combinator",
          ( length(x.subroutines)>0 ? " with $(length(x.subroutines)) capturing groups" : "" ) )
end
"""
    _iterate(p::ParserWithCaptures, sequence::SequenceWithCaptures,a...)

`Base.empty!(sequence)` before iteration.
"""
function _iterate(p::ParserWithCaptures, sequence::SequenceWithCaptures,a...)
    Base.empty!(sequence)
    _iterate(p.parser, sequence, a...)
end
"""
    ParserWithCaptures(x)

Return `ParserWithCaptures` if captures are used, `x` otherwise.
Two passes of `deepmap_parser(indexed_captures_,...)` are used
(1. to assign `Capture` indices and
 2. to use index number for `Backreference` and `Subroutine`).

See also [`indexed_captures_`](@ref)
"""
ParserWithCaptures(x) =
    let cs = ParserWithCaptures(x,ParserTypes[],Dict{Symbol,Int}())
        pass1 = ParserWithCaptures(deepmap_parser(indexed_captures_,NoDict(),x,cs,false),cs.subroutines,cs.names)
        r = ParserWithCaptures(deepmap_parser(indexed_captures_,NoDict(),pass1.parser,pass1,false),pass1.subroutines,pass1.names)
        isempty(r.subroutines) ? r.parser : r
    end

import ..CombinedParsers: MatchesIterator
function MatchesIterator(p::ParserWithCaptures,s::AbstractString,idx=1)
    MatchesIterator(p, SequenceWithCaptures(s,p), idx)
end

# _iterate(parser::ParserWithCaptures, sequence::AbstractString, till, next_i, after, state::Nothing) =
#     _iterate(parser, sequence, till, next_i, next_i, state)

SequenceWithCaptures(x,cs::CombinedParser) = x
function SequenceWithCaptures(x,cs::ParserWithCaptures)
    ## @show S=typeof(x)
    SequenceWithCaptures(
        x,cs.subroutines,
        Vector{String}[ String[] for c in cs.subroutines ],
        cs.names,
        nothing)
end

set_options(set::UInt32,unset::UInt32,parser::ParserWithCaptures) =
    ParserWithCaptures(set_options(set,unset,parser.parser),
                       ParserTypes[ set_options(set,unset,p) for p in parser.subroutines],
                       parser.names)

function deepmap_parser(f::Function,mem::AbstractDict,x::ParserWithCaptures,a...;kw...)
    ParserWithCaptures(deepmap_parser(f,mem,x.parser,a...;kw...),
                       [ deepmap_parser(f,mem,p,a...;kw...) for p in x.subroutines ],
                       x.names)
end

ParserWithCaptures(x::ParserWithCaptures) = x

"""
https://www.pcre.org/original/doc/html/pcrepattern.html#SEC16
"""
function subroutine_index_reset(context::ParserWithCaptures,x::Capture)
    if x.index<0
        index = length(context.subroutines)+1
        push!(context.subroutines,Capture(x,index))
        if x.name !== nothing
            push!(get!(context.names,x.name) do
                  Int[]
                  end,
                  index)
        end
        index, true
    else
        x.index, false
    end
end

import ..CombinedParsers: JoinSubstring, Transformation
JoinSubstring(x::ParserWithCaptures) =
    ParserWithCaptures(JoinSubstring(x.parser),x.subroutines,x.names)
Transformation{T}(t,x::ParserWithCaptures) where T =
    ParserWithCaptures(Transformation{T}(t,x.parser),x.subroutines,x.names)

function deepmap_parser(::typeof(indexed_captures_),mem::AbstractDict,x::Backreference,context,a...)
    get!(mem,x) do
        idx = capture_index(x.name,Symbol(""),x.index,context)
        if idx < 1 || idx>lastindex(context.subroutines)
            x.name === nothing ? x.fallback() : x
        else
            Backreference(x.fallback,x.name, idx)
        end
    end
end
function deepmap_parser(::typeof(indexed_captures_),mem::AbstractDict,x::Subroutine,context,a...)
    get!(mem,x) do
        index = capture_index(x.name,x.delta,x.index, context)
        if index <= 0 || index>length(context.subroutines)
            Subroutine{Any,Any}(x.name,Symbol(""),index)
        else
            sr = context.subroutines[index]
            Subroutine{state_type(sr),result_type(sr)}(
                x.name,Symbol(""),index)
        end
    end
end

"""
    deepmap_parser(f::typeof(indexed_captures_),mem::AbstractDict,x::DupSubpatternNumbers,context,reset_index)

set `reset_index===true'.
"""
function deepmap_parser(f::typeof(indexed_captures_),mem::AbstractDict,x::DupSubpatternNumbers,context,reset_index)
    get!(mem,x) do
        DupSubpatternNumbers(deepmap_parser(
            indexed_captures_,mem,
            x.parser,context,
            true))
    end
end

"""
    deepmap_parser(::typeof(indexed_captures_),mem::AbstractDict,x::Either,context,reset_index)

Method dispatch, resetting `lastindex(context.subroutines)` if `reset_index===true'.
"""
deepmap_parser(::typeof(indexed_captures_),mem::AbstractDict,x::Either{<:Tuple},context,reset_index) =
    indexed_captures_(mem,x,context,reset_index)
deepmap_parser(::typeof(indexed_captures_),mem::AbstractDict,x::Either{<:Vector},context,reset_index) =
    indexed_captures_(mem,x,context,reset_index)
function indexed_captures_(mem::AbstractDict,x::Either,context,reset_index)
    if reset_index
        idx = lastindex(context.subroutines)
        branches = Any[]
        for p in reverse(x.options) ## keep first for subroutines
            while lastindex(context.subroutines)>idx
                pop!(context.subroutines)
            end
            push!(branches,deepmap_parser(
                indexed_captures_,
                mem,
                p,context,false))
        end
        Either{result_type(x)}(tuple( branches... ))
    else
        Either{result_type(x)}(
            tuple( (deepmap_parser(indexed_captures_,mem,p,context,false) for p in x.options )...))
    end
end

"""
    deepmap_parser(f::typeof(indexed_captures_),mem::AbstractDict,x::Capture,context,a...)

Map the capture my setting `index` to  `nextind(context,x)`.

Registers result in `context.subroutines` if no previous subroutine with the same index exists
(see also [`DupSubpatternNumbers`](@ref)).
"""
function deepmap_parser(f::typeof(indexed_captures_),mem::AbstractDict,x::Capture,context,a...)
    get!(mem,x) do
        index,reset=subroutine_index_reset(context,x)
        r = Capture(
            x.name,
            deepmap_parser(indexed_captures_,mem,x.parser,context,a...),
            index
        )
        reset && ( context.subroutines[index] = r )
        r
    end
end

##Base.getindex(x::ParserWithCaptures, i) = ParserWithCaptures(getindex(i,x)

"For use in ParserWithCaptures to enforce different indices for identical captures."
struct NoDict{K,V} <: AbstractDict{K,V} end
NoDict() = NoDict{Any,Any}()

import Base: get!
Base.get!(f::Function,d::NoDict,k) = f()


text:
function remove_padding(header, payload)
    is_padded = header.flags & 0x8 == 0x8

    if is_padded
        pad_length = payload[1]
        return getindex(payload, 2:(length(payload) - pad_length))
    else
        return payload
    end
end

function wrap_payload(payload, typ, flags, stream_identifier)
    len = length(payload)
    result = encode_header(FrameHeader(len, typ, flags, stream_identifier))
    append!(result, payload)

    return result
end


text:
# The following tests are primarily regression tests - checking that
# the results are the same as when the tests were written, regardless
# of correctness.
#
# The general strategy is that a number of project files have been
# stored. These are read and expanded to minimal stub packages, which
# are then registered in a newly created registry. The resulting
# registries after some selections of packages have been added have
# also been stored and are compared against.
#
# The project files have been extracted from the git history of the
# Flux and Images packages. The patch numbers have been faked to get
# more version samples out of their git histories. The FirstTest1
# project file is derived from this package.

# Set up packages and registry directories in a temporary location.
if VERSION >= v"1.2"
    testdir = mktempdir(prefix = "LocalRegistryTests")
else
    testdir = mktempdir()
end
packages_dir = joinpath(testdir, "packages")
if packages_dir ∉ LOAD_PATH
    push!(LOAD_PATH, packages_dir)
end
registry_dir = joinpath(testdir, "TestRegistry")

# Create a new registry.
create_registry(registry_dir, "git@example.com:Julia/TestRegistry.git",
                description = "For testing purposes only.",
                uuid = "ed6ca2f6-392d-11ea-3224-d3daf7fee369",
                gitconfig = TEST_GITCONFIG, push = false)

# Add the FirstTest1 package and check against the stored `registry1`.
prepare_package(packages_dir, "FirstTest1.toml")
using FirstTest
register(FirstTest, registry = registry_dir,
         gitconfig = TEST_GITCONFIG, push = false)
@test check_result(registry_dir, "registry1")

# Reregister the same version of FirstTest to verify that nothing
# happens,
@test_logs (:info, "This version has already been registered and is unchanged.") register(FirstTest, registry = registry_dir, gitconfig = TEST_GITCONFIG, push = false)
@test check_result(registry_dir, "registry1")

# Add 29 versions of the Flux project files and check against `registry2`.
for n = 1:29
    prepare_package(packages_dir, "Flux$(n).toml")
    using Flux
    register(Flux, registry = registry_dir,
             gitconfig = TEST_GITCONFIG, push = false)
end
@test check_result(registry_dir, "registry2")

# Add 15 versions of the Images project files and check against `registry3`.
for n = 1:15
    prepare_package(packages_dir, "Images$(n).toml")
    using Images
    register(Images, registry = registry_dir,
             gitconfig = TEST_GITCONFIG, push = false)
end
@test check_result(registry_dir, "registry3")

# Start over with a fresh registry and add all 46 project files but in
# shuffled order. Check that this also matches `registry3`.
registry_dir = joinpath(testdir, "test2", "TestRegistry")
create_registry(registry_dir, "git@example.com:Julia/TestRegistry.git",
                description = "For testing purposes only.",
                uuid = "ed6ca2f6-392d-11ea-3224-d3daf7fee369",
                gitconfig = TEST_GITCONFIG, push = false)
project_files = vcat("FirstTest1.toml",
                     ["Flux$(n).toml" for n = 1:29],
                     ["Images$(n).toml" for n = 1:15])
Random.seed!(13)
shuffle!(project_files)
for project_file in project_files
    prepare_package(packages_dir, project_file)
    package = match(r"[a-zA-Z]+", project_file).match
    # Register by path instead of module in this test.
    register(joinpath(packages_dir, package), registry = registry_dir,
             gitconfig = TEST_GITCONFIG, push = false)
end
@test check_result(registry_dir, "registry3")

pop!(LOAD_PATH)


text:
"""
    rewind_ptrs!(ptrs)

Rewind the given vector of pointers.
"""
function rewind_ptrs!(ptrs::AbstractVector{<:Integer})
  @inbounds for i in (length(ptrs)-1):-1:1
    ptrs[i+1] = ptrs[i]
  end
  ptrs[1] = 1
end

"""
    length_to_ptrs!(ptrs)

Given a vector of integers, mutate it from length state to pointer state.
"""
function length_to_ptrs!(ptrs::AbstractArray{<:Integer})
  ptrs[1] = 1
  @inbounds for i in 1:(length(ptrs)-1)
    ptrs[i+1] += ptrs[i]
  end
end

function allocate_matrix end
function allocate_matrix_and_vector end

"""
    allocate_vector(::Type{V},indices) where V

Allocate a vector of type `V` indexable at the indices `indices`
"""
function allocate_vector(::Type{V},indices) where V
  n = length(indices)
  allocate_vector(V,n)
end

function allocate_vector(::Type{V},n::Integer) where V
  T = eltype(V)
  zeros(T,n)
end

"""
    allocate_in_range(::Type{V},matrix) where V

Allocate a vector of type `V` in the range of matrix `matrix`.
"""
function allocate_in_range(::Type{V},matrix) where V
  n = size(matrix,1)
  allocate_vector(V,n)
end

"""
    allocate_in_domain(::Type{V},matrix) where V

Allocate a vector of type `V` in the domain of matrix `matrix`.
"""
function allocate_in_domain(::Type{V},matrix) where V
  n = size(matrix,2)
  allocate_vector(V,n)
end

"""
    copy_entries!(a,b)

Copy the entries of array `b` into array `a`. Returns `a`.
"""
function copy_entries!(a,b)
  if a !== b
    copyto!(a,b)
  end
  a
end

"""
    add_entry!(combine::Function,A,v,i...)
    add_entry!(A,v,i...)

Add an entry. Returns A.
"""
@inline function add_entry!(combine::Function,args...)
  @abstractmethod
end

@inline function add_entry!(args...)
  add_entry!(+,args...)
end

@inline function add_entry!(combine::Function,A::AbstractMatrix,v,i,j)
  aij = A[i,j]
  A[i,j] = combine(aij,v)
  A
end

@inline function add_entry!(combine::Function,A::AbstractVector,v,i)
  ai = A[i]
  A[i] = combine(ai,v)
  A
end

@inline function add_entry!(combine::Function,A::AbstractMatrix,v::Nothing,i,j)
  A
end

@inline function add_entry!(combine::Function,A::AbstractVector,v::Nothing,i)
  A
end

# Warning: the usage of @inline and @noinline seems to have dramatic performance
# implications. Do not change it.

@noinline function add_entries!(A,vs,is,js)
  add_entries!(+,A,vs,is,js)
end

@noinline function add_entries!(A,vs,is)
  add_entries!(+,A,vs,is)
end

"""
    add_entries!(combine::Function,A,vs,is,js)

Add several entries only for positive input indices. Returns A.
"""
@inline function add_entries!(combine::Function,A,vs,is,js)
  _add_entries!(combine,A,vs,is,js)
end

@inline function _add_entries!(combine::Function,A,vs::Nothing,is,js)
  for (lj,j) in enumerate(js)
    if j>0
      for (li,i) in enumerate(is)
        if i>0
          add_entry!(combine,A,nothing,i,j)
        end
      end
    end
  end
  A
end

@inline function _add_entries!(combine::Function,A,vs,is,js)
  for (lj,j) in enumerate(js)
    if j>0
      for (li,i) in enumerate(is)
        if i>0
          vij = vs[li,lj]
          add_entry!(combine,A,vij,i,j)
        end
      end
    end
  end
  A
end

@inline function add_entries!(combine::Function,A,vs,is)
  _add_entries!(combine,A,vs,is)
end

@inline function _add_entries!(combine::Function,A,vs::Nothing,is)
  for (li, i) in enumerate(is)
    if i>0
      add_entry!(A,nothing,i)
    end
  end
  A
end

@inline function _add_entries!(combine::Function,A,vs,is)
  for (li, i) in enumerate(is)
    if i>0
      vi = vs[li]
      add_entry!(A,vi,i)
    end
  end
  A
end

@inline function add_entries!(combine::Function,A::AbstractMatrix,vs::Nothing,is,js)
  A
end

@inline function add_entries!(combine::Function,A::AbstractVector,vs::Nothing,is)
  A
end

"""
    muladd!(c,a,b)

Matrix multiply a*b and add to result to c. Returns c.
"""
function muladd!(c,a,b)
  _muladd!(c,a,b)
  c
end

@static if VERSION >= v"1.3"
  function _muladd!(c,a,b)
    mul!(c,a,b,1,1)
  end
else
  function _muladd!(c,a,b)
    @assert length(c) == size(a,1)
    @assert length(b) == size(a,2)
    @inbounds for j in 1:size(a,2)
      for i in 1:size(a,1)
        c[i] += a[i,j]*b[j]
      end
    end
  end
end

#
# Some API associated with assembly routines
#
# Generate a counter to count the nz values
# for an array type A
#
#    a = nz_counter(A,(rows,cols))
#
# Do a loop to count the number of nz values
# Do the loop only when needed by using the LoopStyle
# For instance, when assembling a dense vector the loop
# is not needed
# A nz value is counted by calling add_entry!
#
#    if LoopStyle(a) == Loop()
#      add_entry!(a,nothing,i,j)
#      add_entry!(a,v,i,j)
#      add_entries!(a,nothing,is,js)
#      add_entries!(a,vs,is,js)
#    end
#
# Now we can allocate the nz values
# This can be the vectors in coo format or
# it can already be the final array for dense vectors
#
#    b = nz_allocation(a)
#
# Do a loop to set entries
# We can use nothing if we want to add an entry to the sparsity
# pattern but we don't want to set a value to it yet
#
#    add_entry!(b,nothing,i,j)
#    add_entry!(b,v,i,j)
#    add_entries!(b,nothing,is,js)
#    add_entries!(b,vs,is,js)
#
# Create the final array
# from the nz values
#
#    c = create_from_nz(b)
#
# We can also do a loop and update
# the entries of c
#
#    fill!(c,0) or LinearAlgebra.fillstored!(c,0)
#    add_entry!(c,v,i,j)
#    add_entries!(c,vs,is,js)
#

struct Loop end
struct DoNotLoop end
LoopStyle(::Type) = DoNotLoop()
LoopStyle(::T) where T = LoopStyle(T)

# By default process, matrix and vector separately
# but, in some situations, create_from_nz of the vector
# can reuse data from the one computed in
# create_from_nz for the matrix (e.g., GridapDistributed)
function create_from_nz(a,b)
  A = create_from_nz(a)
  B = create_from_nz(b)
  A,B
end
# See comment above for create_from_nz. The same applies here
# for nz_allocation.
function nz_allocation(a,b)
  nz_allocation(a),nz_allocation(b)
end

# For dense arrays

struct ArrayBuilder{T}
  array_type::Type{T}
end

ArrayBuilder(a::ArrayBuilder) = a

get_array_type(::ArrayBuilder{T}) where T = T

struct ArrayCounter{T,A}
  axes::A
  function ArrayCounter{T}(axes::A) where {T,A<:Tuple{Vararg{AbstractUnitRange}}}
    new{T,A}(axes)
  end
end

LoopStyle(::Type{<:ArrayCounter}) = DoNotLoop()

@inline add_entry!(c::Function,a::ArrayCounter,v,i,j) = a
@inline add_entry!(c::Function,a::ArrayCounter,v,i) = a
@inline add_entries!(c::Function,a::ArrayCounter,v,i,j) = a
@inline add_entries!(c::Function,a::ArrayCounter,v,i) = a

#nz_counter(::Type{T},axes) where T = ArrayCounter{T}(axes)
nz_counter(::ArrayBuilder{T},axes) where T = ArrayCounter{T}(axes)

nz_allocation(a::ArrayCounter{T}) where T = fill!(similar(T,map(length,a.axes)),zero(eltype(T)))

create_from_nz(a::AbstractArray) = a

# For sparse matrices

struct MinCPU end

struct MinMemory{T}
  maxnnz::T
end

MinMemory() = MinMemory(nothing)

struct SparseMatrixBuilder{T,A}
  matrix_type::Type{T}
  approach::A
end

SparseMatrixBuilder(::Type{T}) where T = SparseMatrixBuilder(T,MinMemory())
SparseMatrixBuilder(a::SparseMatrixBuilder) = a

get_array_type(::SparseMatrixBuilder{T}) where T = T

mutable struct CounterCOO{T,A}
  nnz::Int
  axes::A
  function CounterCOO{T}(axes::A) where {T,A<:NTuple{2,AbstractUnitRange}}
    nnz = 0
    new{T,A}(nnz,axes)
  end
end

LoopStyle(::Type{<:CounterCOO}) = Loop()

@inline function add_entry!(::Function,a::CounterCOO{T},v,i,j) where T
  if is_entry_stored(T,i,j)
    a.nnz = a.nnz + 1
  end
  a
end

struct AllocationCOO{T,A,B,C}
  counter::CounterCOO{T,A}
  I::B
  J::B
  V::C
end

LoopStyle(::Type{<:AllocationCOO}) = Loop()

@inline function add_entry!(::typeof(+),a::AllocationCOO{T},::Nothing,i,j) where T
  if is_entry_stored(T,i,j)
    a.counter.nnz = a.counter.nnz + 1
    k = a.counter.nnz
    a.I[k] = i
    a.J[k] = j
  end
  nothing
end

@inline function add_entry!(::typeof(+),a::AllocationCOO{T},v,i,j) where T
  if is_entry_stored(T,i,j)
    a.counter.nnz = a.counter.nnz + 1
    k = a.counter.nnz
    a.I[k] = i
    a.J[k] = j
    a.V[k] = v
  end
  nothing
end

#function nz_counter(::Type{T},axes) where T<:AbstractSparseMatrix
#  CounterCOO{T}(axes)
#end

function nz_counter(::SparseMatrixBuilder{T},axes) where T<:AbstractSparseMatrix
  CounterCOO{T}(axes)
end

function nz_allocation(a::CounterCOO{T}) where T
  counter = CounterCOO{T}(a.axes)
  I,J,V = allocate_coo_vectors(T,a.nnz)
  AllocationCOO(counter,I,J,V)
end

function create_from_nz(a::AllocationCOO{T}) where T
  m,n = map(length,a.counter.axes)
  finalize_coo!(T,a.I,a.J,a.V,m,n)
  sparse_from_coo(T,a.I,a.J,a.V,m,n)
end

# The following methods can be implemented for sparse matrices
# instead of nz_counter, nz_allocation, and create_from_nz

"""
    sparse_from_coo(::Type,I,J,V,m,n)
"""
function sparse_from_coo(::Type,I,J,V,m,n)
  @abstractmethod
end

"""
    is_entry_stored(::Type,i,j) -> Bool

Tells if the entry with coordinates `[i,j]` will be stored in the coo vectors.
"""
function is_entry_stored(::Type,i,j)
  @abstractmethod
end

"""
    finalize_coo!(::Type,I,J,V,m,n)

Check and insert diagonal entries in COO vectors if needed.
"""
function finalize_coo!(::Type,I,J,V,m,n)
  @abstractmethod
end

function nz_index(A::AbstractSparseMatrix,i,j)
  @abstractmethod
end

"""
    push_coo!(::Type, I,J,V,i,j,v)
Inserts entries in COO vectors for further building a sparse matrix of type T.
"""
function push_coo!(::Type,I,J,V,i,j,v)
  @abstractmethod
end

function add_entry!(combine::Function,A::AbstractSparseMatrix,v::Number,i,j)
  k = nz_index(A,i,j)
  nz = nonzeros(A)
  Aij = nz[k]
  nz[k] = combine(v,Aij)
  A
end

function copy_entries!(a::T,b::T) where T<:AbstractSparseMatrix
  na = nonzeros(a)
  nb = nonzeros(b)
  if na !== nb
    copyto!(na,nb)
  end
end

function allocate_coo_vectors(
   ::Type{<:AbstractSparseMatrix{Tv,Ti}},n::Integer) where {Tv,Ti}
  (zeros(Ti,n), zeros(Ti,n), zeros(Tv,n))
end


text:
function setnumbeats!(system::CVSystem,n::Int64)
    # total time needed for all past/current cardiac cycles
    ttotal = sum(system.heart.activation.th);

    # increment number of cycles if new cycle is starting
    if system.t[n+2] >= ttotal
        system.solverparams.numbeats+=1;
    end
end

max_stars_repo_name: dcanuto/CardioModeling

max_issues_repo_name: dcanuto/CardioModeling

max_forks_repo_name: dcanuto/CardioModeling


text:
# d = find_ccalls(Threads.nthreads, Tuple{})
# d = find_ccalls(time, Tuple{})
# d = find_ccalls(muladd, Tuple{Array{Float64,2},Array{Float64,2},Array{Float64,2}})

f1() = ccall(:jl_errno, Int, (Int,), 11)
f2() = ccall(:jl_errno, Int, (Int, Int), 21, 22)
f3() = ccall(:jl_errno, Int, (Int, Int, Int), 31, 32, 33)

@testset "ccalls" begin
    m1 = irgen(f1, Tuple{})
    m2 = irgen(f2, Tuple{})
    m3 = irgen(f3, Tuple{})
    LLVM.verify(m1)
    LLVM.verify(m2)
    LLVM.verify(m3)
end

function f()
    n = Int(unsafe_load(cglobal(:jl_n_threads, Cint)))
    return 2n
end

@testset "cglobal" begin
    m = irgen(f, Tuple{})
    LLVM.verify(m)
    @test f() == @jlrun f()
end

@testset "extern" begin
    f() = @extern(:time, Cvoid, (Ptr{Cvoid},), C_NULL)
    m = irgen(f, Tuple{})
    LLVM.verify(m)
    @test "time" in [name(f) for f in LLVM.functions(m)]
end


text:
using Test
using PyCall
using DFTK
using Unitful
using UnitfulAtomic

ase = pyimport_e("ase")
if !ispynull(ase)
    py"""
    import ase
    """

    @testset "ase.Atoms -> DFTK lattice / atoms / magnetisation -> ase.Atoms" begin
        py"""
        import ase
        cell = [[3.21, 0.0, 0.0], [-1.605, 2.7799415461480477, 0.0], [0.0, 0.0, 5.21304]]
        positions = [[0.0, 0.0, 0.0], [0.0, 1.85329, 2.60652]]
        magmoms = [1.0, 2.0]
        atoms = ase.Atoms(symbols='Mg2', pbc=True, cell=cell,
                          positions=positions, magmoms=magmoms)
        """

        lattice = load_lattice(py"atoms")
        @test lattice[:, 1] ≈ austrip(1u"Å") * [3.21, 0.0, 0.0]
        @test lattice[:, 2] ≈ austrip(1u"Å") * [-1.605, 2.7799415461480477, 0.0]
        @test lattice[:, 3] ≈ austrip(1u"Å") * [0.0, 0.0, 5.21304]

        @test load_lattice(py"atoms") == load_lattice(py"atoms.cell")

        atoms = load_atoms(py"atoms")
        @test length(atoms) == 1
        @test all(at isa ElementCoulomb for (at, positions) in atoms)
        @test atoms[1][1].symbol == :Mg
        @test atoms[1][2][1] ≈ [0, 0, 0]
        @test atoms[1][2][2] ≈ [1/3, 2/3, 1/2] atol=1e-5

        magnetic_moments = load_magnetic_moments(py"atoms")
        @test length(magnetic_moments) == 1
        @test all(at isa ElementCoulomb for (at, magmoms) in magnetic_moments)
        @test magnetic_moments[1][1].symbol == :Mg
        @test magnetic_moments[1][2][1] == 1.0
        @test magnetic_moments[1][2][2] == 2.0

        newatoms = ase_atoms(lattice, atoms, magnetic_moments)
        @test all(py"$newatoms.cell == atoms.cell")
        @test all(py"$newatoms.symbols == atoms.symbols")
        @test py"$newatoms.get_positions()" ≈  py"atoms.get_positions()"
        @test (  py"$newatoms.get_initial_magnetic_moments()"
               ≈ py"atoms.get_initial_magnetic_moments()")
    end
end


text:
# This file allows the user to configure a system simulation from a simplified
#   Excel parameter file.

export initialiseFromSimplifiedExcel

"""
```
initialiseFromSimplifiedExcel( mpSim::ManpowerSimulation,
                               fileName::String )
```
This function initialises the manpower simulation `mpSim` from the simplified
configuration file with name `fileName`. If the filename does not have the
extension `.xlsx`, it will be added.

This function returns `nothing`.
"""
function initialiseFromSimplifiedExcel( mpSim::ManpowerSimulation,
    fileName::String )::Void

    tmpFileName = endswith( fileName, ".xlsx" ) ? fileName : fileName * ".xlsx"

    # Complain if file doesn't exist.
    if !ispath( tmpFileName )
        warn( "File is not an Excel file. Not making any changes." )
        return
    end  # if !ispath( tmpFileName )

    tmpPath = Base.source_path()
    tmpPath = tmpPath isa Void ? "" : dirname( tmpPath )
    mpSim.parFileName = joinpath( tmpPath, tmpFileName )

    XLSX.openxlsx( tmpFileName ) do xf
        pSheet = xf[ 1 ]
        mpSim.dbName = joinpath( mpSim.parFileName[ 1:(end-5) ], mpSim.dbName )

        if !ispath( dirname( mpSim.dbName ) )
            mkpath( dirname( mpSim.dbName ) )
        end  # if !ispath( dirname( mpSim.dbName ) )

        mpSim.simDB = SQLite.DB( mpSim.dbName )
        setSimulationLength( mpSim, 1200 )
        setDatabaseCommitTime( mpSim, 120 )
        setSimStartDate( mpSim, Date( now() ) )
        readStatesAndAttrs( mpSim, pSheet )
        readAllTransitions( mpSim, pSheet )
    end  # XLSX.openxlsx( tmpFileName ) do xf

    # Make sure the databases are okay, and save configuration to database.
    initialise( mpSim )
    saveSimConfigToDatabase( mpSim )

    return

end  # initialiseFromSimplifiedExcel( mpSim, fileName )

"""
```
readStatesAndAttrs( mpSim::ManpowerSimulation,
                    pSheet::XLSX.Worksheet )
```
This function configures the attributes and states in the manpowre simulation
`mpSim` from the simplified Excel configuration sheet `pSheet`.

This function returns `nothing`.
"""
function readStatesAndAttrs( mpSim::ManpowerSimulation,
    pSheet::XLSX.Worksheet )::Void

    nRows, nCols = XLSX.size( XLSX.get_dimension( pSheet ) )

    # Find the node block.
    nodeRow = 1

    while ( nodeRow <= nRows ) &&
        ( isa( pSheet[ "A$nodeRow" ], Missings.Missing ) ||
        ( pSheet[ "A$nodeRow" ] != "Knopen" )   )
        nodeRow += 1
    end  # while ( nodeRow <= nRows ) && ...

    # Find node block header row.
    nodeRow += 1

    while ( nodeRow <= nRows ) &&
        ( isa( pSheet[ "A$nodeRow" ], Missings.Missing ) ||
        ( pSheet[ "A$nodeRow" ] != "Name" ) )
        nodeRow += 1
    end  # while ( nodeRow <= nRows ) && ...

    # Find number of columns in node block.
    nCols = 1
    targetCol = 0
    popCol = 0

    while isa( pSheet[ XLSX.CellRef( nodeRow, nCols + 1 ) ], String )
        nCols += 1
        cRef = XLSX.CellRef( nodeRow, nCols )

        if pSheet[ cRef ] == "Pop?"
            popCol = nCols
        elseif pSheet[ cRef ] == "Real"
            targetCol = nCols
        end  # if pSheet[ cRef ] == "Pop?"
    end  # while isa( pSheet[ XLSX.CellRef( nodeRow, nCols + 1 ) ], String )

    nAttrs = nCols - popCol

    # Find number of states, in and out included.
    nodeRow += 1
    nStates = 0

    while isa( pSheet[ "A$(nodeRow + nStates)" ], String )
        nStates += 1
    end  # while isa( pSheet[ "A$(nodeRow + nStates)" ], String )

    # Read the attributes.
    nodeRow -= 1
    attrNames = Vector{String}( nAttrs )

    for ii in 1:nAttrs
        jj = popCol + ii
        attrNames[ ii ] = pSheet[ XLSX.CellRef( nodeRow, jj ) ]
        attrValues = vec( pSheet[ XLSX.CellRange( nodeRow + 1, jj,
            nodeRow + nStates, jj ) ] )
        filter!( val -> !isa( val, Missings.Missing ), attrValues )
        newAttr = PersonnelAttribute( attrNames[ ii ], isFixed = false )
        setPossibleValues!( newAttr,
            Vector{String}( strip.( attrValues ) ) )
        addAttribute!( mpSim, newAttr )
    end  # for ii in 1:nAttrs

    # Read the states.
    for ii in 1:nStates
        jj = nodeRow + ii
        stateName = strip( pSheet[ "A$jj" ] )

        # Ignore the in and out states.
        if lowercase( stateName ) ∈ [ "in", "out" ]
            continue
        end  # if lowercase( stateName ) ∈ [ "in", "out" ]

        # Check if state should be used.
        isStateInSim = lowercase( strip(
            pSheet[ XLSX.CellRef( jj, popCol ) ] ) ) == "yes"

        if !isStateInSim
            continue
        end  # if !isStateInSim

        newState = State( stateName )
        setStateTarget!( newState, pSheet[ XLSX.CellRef( jj, targetCol ) ] )

        # Add requirements to state.
        for kk in eachindex( attrNames )
            attrVal = pSheet[ XLSX.CellRef( jj, popCol + kk ) ]

            if isa( attrVal, String )
                addRequirement!( newState, attrNames[ kk ], attrVal )
            end
        end  # for kk in eachindex( attrNames )

        addState!( mpSim, newState )
    end  # for ii in 1:nStates

    return

end  # readStatesAndAttrs( mpSim, pSheet )

"""
```
readAllTransitions( mpSim::ManpowerSimulation,
                    pSheet::XLSX.Worksheet )
```
This function configures all the transitions in the manpower simulation `mpSim`
from the simplified Excel configuration sheet `pSheet`. This includes all
transitions: recruitment, retirement, forced resignations, and through
transitions (one in-system state to another).

This function returns `nothing`.
"""
function readAllTransitions( mpSim::ManpowerSimulation,
    pSheet::XLSX.Worksheet )::Void

    nRows, nCols = XLSX.size( XLSX.get_dimension( pSheet ) )

    # Find the transition types block.
    transTypeRow = 1

    while ( transTypeRow <= nRows ) &&
        ( isa( pSheet[ "B$transTypeRow" ], Missings.Missing ) ||
        ( pSheet[ "B$transTypeRow" ] != "Transitietypes" ) )
        transTypeRow += 1
    end  # while ( transTypeRow <= nRows ) && ...

    # Read all transition types and their priority.
    transTypeRow += 1

    while isa( pSheet[ "B$transTypeRow" ], String )
        prio = pSheet[ "C$transTypeRow" ]
        setTransTypePriority!( mpSim, pSheet[ "B$transTypeRow" ],
            isa( prio, Int ) ? prio : 0 )
        transTypeRow += 1
    end  # while isa( pSheet[ "B$transTypeRow" ], String )

    # Find the transition block.
    transRow = 1

    while ( transRow <= nRows ) &&
        ( isa( pSheet[ "A$transRow" ], Missings.Missing ) ||
        ( pSheet[ "A$transRow" ] != "Pijlen" ) )
        transRow += 1
    end  # while ( transRow <= nRows ) && ...

    # Find transition block header row.
    transRow += 1

    while ( transRow <= nRows ) &&
        ( isa( pSheet[ "A$transRow" ], Missings.Missing ) ||
        ( pSheet[ "A$transRow" ] != "From" ) )
        transRow += 1
    end  # while ( transRow <= nRows ) && ...

    # Find number of columns in node block.
    nCols = 1

    while isa( pSheet[ XLSX.CellRef( transRow, nCols + 1 ) ], String )
        nCols += 1
    end  # while isa( pSheet[ XLSX.CellRef( transRow, nCols + 1 ) ], String )

    # Find number of transitions, in and out included.
    transRow += 1
    nTrans = 0

    while isa( pSheet[ "A$(transRow + nTrans)" ], String )
        nTrans += 1
    end  # while isa( pSheet[ "A$(transRow + nTrans)" ], String )

    # Detect in/out/through transitions.
    transRow -= 1
    recruitList = find( map( (1:nTrans) + transRow ) do ii
        return ( lowercase( strip( pSheet[ "A$ii" ] ) ) == "in" ) &&
            ( lowercase( strip( pSheet[ "B$ii" ] ) ) ∉ [ "in", "out" ] )
    end )  # map( (1:nTrans) + transRow ) do ii
    throughList = find( map( (1:nTrans) + transRow ) do ii
        return ( lowercase( strip( pSheet[ "A$ii" ] ) ) ∉ [ "in", "out" ] ) &&
            ( lowercase( strip( pSheet[ "B$ii" ] ) ) ∉ [ "in", "out" ] )
    end )  # map( (1:nTrans) + transRow ) do ii
    outList = find( map( (1:nTrans) + transRow ) do ii
        return ( lowercase( strip( pSheet[ "A$ii" ] ) ) ∉ [ "in", "out" ] ) &&
            ( lowercase( strip( pSheet[ "B$ii" ] ) ) == "out" )
    end )  # map( (1:nTrans) + transRow ) do ii

    if length( recruitList ) + length( throughList ) + length( outList ) <
        nTrans
        warn( "Improperly defined transitions in list. Ignoring those." )
    end  # if length( recruitList ) + ...

    # Build the recruitment schemes.
    for ii in recruitList
        jj = ii + transRow
        recName = strip( pSheet[ "C$jj" ] )
        newRecScheme = Recruitment( recName, 12 )
        targetState = strip( pSheet[ "B$jj" ] )

        if !haskey( mpSim.stateList, targetState )
            warn( "Transition $ii is recruitment for an unknown state '$targetState'. Skipping." )
            continue
        end  # if haskey( mpSim.stateList, targetState )

        setRecruitState( newRecScheme, targetState )
        numToRecruit = pSheet[ "G$jj" ]

        if numToRecruit < 0
            warn( "Transition $ii is a recruitment line with a negative flux. Setting flux to zero." )
        end  # if numToRecruit < 0

        numToRecruit = max( 0, numToRecruit )

        if pSheet[ "N$jj" ] == "yes"
            setRecruitmentFixed( newRecScheme, numToRecruit )
        else
            setRecruitmentLimits( newRecScheme, 0, numToRecruit )
        end  # if pSheet[ "N$jj" ] == "yes"

        ageLimits = [ pSheet[ "K$jj" ], pSheet[ "L$jj" ] ] * 12.0

        if ageLimits[ 1 ] >= ageLimits[ 2 ]
            setRecruitmentAge( newRecScheme, ageLimits[ 1 ] )
        else
            setAgeDistribution( newRecScheme,
                Dict( ageLimits[ 1 ] => 1.0, ageLimits[ 2 ] => 1.0 ), :pUnif )
        end  # if ageLimits[ 1 ] >= ageLimits[ 2 ]

        addRecruitmentScheme!( mpSim, newRecScheme )
    end  # for ii in recruitList

    # XXX The big trick is to separate the retirement transitions from the
    #   forced resignations.
    transDetails = Array{String}( length( throughList ), 2 )
    hasFiredOnFail = falses( throughList )
    isFiredOnFail = Vector{Bool}( length( outList ) )

    for ii in eachindex( throughList )
        jj = throughList[ ii ] + transRow
        transDetails[ ii, 1 ] = strip( pSheet[ "A$jj" ] )
        transDetails[ ii, 2 ] = strip( pSheet[ "D$jj" ] )
    end  # for ii in eachindex( throughList )

    # Identify which through transitions have a fire on fail clause, and which
    #   out transitions are fire on fail clauses.
    for ii in eachindex( outList )
        jj = outList[ ii ] + transRow
        outDetails = [ strip( pSheet[ "A$jj" ] ), strip( pSheet[ "D$jj" ] ) ]
        transInd = findfirst( kk -> transDetails[ kk, : ] == outDetails,
            eachindex( throughList ) )
        isFiredOnFail[ ii ] = transInd > 0

        if isFiredOnFail[ ii ]
            hasFiredOnFail[ transInd ] = true
        end  # if isFiredOnFail[ ii ]
    end  # for ii in eachindex( outList )

    outList = outList[ .!( isFiredOnFail ) ]

    # Attach retirement schemes to states.
    for ii in outList
        jj = ii + transRow
        stateName = strip( pSheet[ "A$jj" ] )

        if !haskey( mpSim.stateList, stateName )
            warn( "Transition $ii is retirement from an unknown state '$stateName'. Skipping." )
            continue
        end  # if !haskey( mpSim.stateList, stateName )

        stateRetAge = pSheet[ "H$jj" ] * 12.0
        setStateRetirementAge!( mpSim.stateList[ stateName ], stateRetAge )
    end  # for jj in outList

    # Build the through transitions.
    for ii in eachindex( throughList )
        jj = throughList[ ii ] + transRow
        startState = strip( pSheet[ "A$jj" ] )
        endState = strip( pSheet[ "B$jj" ] )

        if !haskey( mpSim.stateList, startState ) ||
            !haskey( mpSim.stateList, endState )
            warn( "Transition $ii has an unknown source or target state. Skipping." )
            continue
        end  # if !haskey( mpSim.stateList, startState ) || ...

        newTrans = Transition( strip( pSheet[ "C$jj" ] ),
            mpSim.stateList[ startState ], mpSim.stateList[ endState ],
            freq = 12.0, isFiredOnFail = hasFiredOnFail[ ii ] )

        if !hasFiredOnFail[ ii ]
            setMaxAttempts( newTrans, -1 )
        end  # if !hasFiredOnFail[ ii ]

        maxFlux = pSheet[ "G$jj" ]

        if !isa( maxFlux, Missings.Missing )
            setMaxFlux( newTrans, maxFlux )
        end  # if !isa( maxFlux, Missings.Missing )

        condVal = pSheet[ "H$jj" ]

        if !isa( condVal, Missings.Missing )
            cond = processCondition( "age", ">=", condVal )
            addCondition!( newTrans, cond[ 1 ] )
        end  # if !isa( pSheet[ "H$jj" ], Missings.Missing )

        condVal = pSheet[ "I$jj" ]

        if !isa( condVal, Missings.Missing )
            cond = processCondition( "tenure", ">=", condVal )
            addCondition!( newTrans, cond[ 1 ] )
        end  # if !isa( pSheet[ "I$jj" ], Missings.Missing )

        condVal = pSheet[ "J$jj" ]

        if !isa( condVal, Missings.Missing )
            cond = processCondition( "time in state", ">=", condVal )
            addCondition!( newTrans, cond[ 1 ] )
        end  # if !isa( pSheet[ "J$jj" ], Missings.Missing )

        setHasPriority( newTrans, isa( pSheet[ "N$jj" ], String ) &&
            ( pSheet[ "N$jj" ] == "yes" ) )
        addTransition!( mpSim, newTrans )
    end  # for ii in throughList

    return

end  # readAllTransitions( mpSim, pSheet )


text:
import Distributions
import Random

function _draw_sample(rng::Random.AbstractRNG,
                      T::Type,
                      distribution::Nothing)
    return zero(T)
end

function _draw_sample(rng::Random.AbstractRNG,
                      T::Type,
                      distribution::Distributions.Sampleable)
    numerical_value = rand(rng, distribution)
    return T(numerical_value)
end


text:
"""
    Origin(indices...)
    Origin(origin::Tuple)
    Origin(origin::CartesianIndex)

A helper type to construct OffsetArray with given origin.

The `origin` of an array is defined as the index of its first element, i.e., `first.(axes(A))`.

# Example

```jldoctest; setup=:(using OffsetArrays)
julia> a = [1 2; 3 4];

julia> OffsetArray(a, OffsetArrays.Origin(0, 1))
2×2 OffsetArray(::$(Array{Int,2}), 0:1, 1:2) with eltype $Int with indices 0:1×1:2:
 1  2
 3  4

julia> OffsetArray(a, OffsetArrays.Origin(0)) # short notation for `Origin(0, 0)`
2×2 OffsetArray(::$(Array{Int, 2}), 0:1, 0:1) with eltype $Int with indices 0:1×0:1:
 1  2
 3  4
```
"""
struct Origin{T<:Union{Tuple, Int}}
    index::T
end
Origin(I::NTuple{N, Int}) where N = Origin{typeof(I)}(I)
Origin(I::CartesianIndex) = Origin(I.I)
Origin(I1::Int, In::Int...) = Origin((I1, In...))
# Origin(0) != Origin((0, )) but they work the same with broadcasting
Origin(n::Int) = Origin{Int}(n)

(o::Origin)(A::AbstractArray) = o.index .- first.(axes(A))

Base.Broadcast.broadcastable(o::Origin) = Ref(o)


text:
# Simulate n random numbers generated as follows: half of the random
# numbers are drawn from the standard univariate normal, and half of
# the random numbers are drawn from a univariate normal with zero mean
# and a standard deviation of 3. The return value is a vector of
# floats of length n.
function normdatasim(n::Int)

  # Check input "n".
  if n <= 0
    throw(ArgumentError("Argument \"n\" should be positive"))
  end

  # Generate the random numbers.
  n1 = round(Int,0.5*n);
  n2 = round(Int,0.2*n);
  n3 = n - n1 - n2;
  return vcat(randn(n1),4*randn(n2),6*randn(n3))
end

# Simulate n random numbers generated as follows: 50% of the random
# numbers are drawn from the standard univariate normal; 20% are
# drawn from a t distribution with 4 degrees of freedom; and the
# remaining 30% are drawn from a t distribution with 6 degrees of
# freedom. The return value is a vector of floats of length n.
function normtmixdatasim(n::Int)

  # Check input "n".
  if n <= 0
    throw(ArgumentError("Argument \"n\" should be positive"))
  end

  # Generate the random numbers.
  n1 = round(Int,0.5*n);
  n2 = round(Int,0.2*n);
  n3 = n - n1 - n2;
  return vcat(randn(n1),rand(TDist(4),n2),rand(TDist(6),n3))
end

max_stars_repo_name: stephenslab/mixsqp-paper

max_issues_repo_name: stephenslab/mixsqp-paper

max_forks_repo_name: stephenslab/mixsqp-paper


text:
#!/usr/bin/env julia
using DocOpt, HDF5, DataStructures, ZMQ
using Pope: LJH

doc = """
Pope (Pass one pulse examiner)
Usage:
  popewatchesmatter.jl <preknowledge>
  popewatchesmatter.jl [--overwriteoutput] [--forcenowrite] <preknowledge>
  popewatchesmatter.jl -h | --help

Options:
Help exposition:
  --overwriteoutput    Use this flag to allow popewatchesmatter to overwrite existing output files.(mostly for testing)
  --forcenowrite       Use this flag to change the matter writing status to `\"forced\"`,`false` before checking the writing status. (testing only)

  Looks at $(LJH.sentinel_file_path) to determine ljh path to analyze. Starts analyzing the next file to be written by matter.
  <preknowledge> points to a valid HDF5 file in the pope preknowledge format.
  Output filename will be determined by a call to `Pope.outputname`
  If this file doesn't exist yet you can use `LJH.write_sentinel_file("fake.ljh",true)` to create it.
"""

arguments = docopt(doc, version=v"0.0.1")
preknowledge_filename = expanduser(arguments["<preknowledge>"])

"zmq_reporter(port,message,rep_period_s,endchannel=Channel{Bool}(1))
Create a ZMQ Pub socket on `port` that sends `message` every `rep_period_s` until `isready(endchannel).`
Used to report to monitory.py in nasa_daq."
function zmq_reporter(port,message,rep_period_s,endchannel=Channel{Bool}(1))
  ctx=Context()
  socket = Socket(ctx, ZMQ.PUB)
  ZMQ.connect(socket,"tcp://localhost:$port")
  while !isready(endchannel)
    sleep(rep_period_s)
    ZMQ.send(socket, Message(message))
  end
  ZMQ.close(socket)
end
@schedule zmq_reporter(Pope.MONITOR_PORT, "Pope watching", 2)

function get_preknowledge_file(preknowledge_filename)
  if ishdf5(preknowledge_filename)
    pkfile = h5open(preknowledge_filename,"r")
  else
    println("ERROR: $preknowledge_filename is not an hdf5 file")
    exit()
  end
end

function get_output_file(ljhpath)
  output_file = Pope.outputname(ljhpath,"pope")
  println("output filename: $output_file")
  if !isfile(output_file) || arguments["--overwriteoutput"]
    if !isdir(dirname(output_file))
      println("ERROR: $(dirname(output_file)) is not an existing directory, cannot create output file.")
      println("Did you delete the directory matter was writing to as it was writing? ")
      exit()
    end
    output_file = h5open(output_file,"w")
    return output_file
  else
    println("ERROR: $output_file already exists, cannot use it as output file")
    exit()
  end
end

function wait_for_writing_status(status)
  println("waiting for matter writing status = $status")
  while true
    ljhpath, writingbool = LJH.matter_writing_status()
    if writingbool == status
      return ljhpath, writingbool
    end
    watch_file(LJH.sentinel_file_path)
  end
end

function launch_continuous_analysis(preknowledge_filename, ljhpath, output_file)
  println("starting Pope analysis:")
  pkfile = get_preknowledge_file(preknowledge_filename)
  @show ljhpath
  @show pkfile.filename
  @show output_file
  println("")
  readers = Pope.Readers()
  for name in names(pkfile)
    channel_number = startswith(name,"chan") ? parse(Int,name[5:end]) : parse(Int,name) # handle chan1 or 1
    ljh_filename = LJH.fnames(ljhpath,channel_number)
    analyzer = try
      analyzer = Pope.analyzer_from_preknowledge(pkfile[name])
    catch
      println("Channel $channel_number: failed to generate analyzer from preknowledge file")
      continue
    end
    product_writer = Pope.make_buffered_hdf5_and_zmq_multisink(output_file,channel_number,analyzer)
    reader = Pope.make_reader(ljh_filename, analyzer, product_writer, progress_meter=false)
    push!(readers, reader)
  end
  close(pkfile)
  schedule(readers)
  println("Analysis started for $(length(readers)) channels.")
  monitor_endchannel = Channel{Bool}(1)
  @schedule zmq_reporter(Pope.MONITOR_PORT, "Pope analyzing", 2, monitor_endchannel)
  readers,monitor_endchannel
end

function finish_analysis(readers,monitor_endchannel)
  Pope.stop(readers)
  try
    wait(readers) # they should process all available data before wait returns
  catch ex
    println("WARNING: There were one or more errors in the reader tasks.")
    Base.show(ex)
  end
  isready(monitor_endchannel) && error("monitor_endchannel already ready")
  put!(monitor_endchannel,true)
end

function summarize_readers(readers)
  c = counter(collect(r.status for r in readers))
  println("Summary of channel analzyer statuses:")
  for (k,v) in c
    println("\t$v channels have status: $k")
  end
end

Pope.init_for_zmqdatasink(Pope.ZMQ_PORT,verbose=true)
println("popewatchesmatter on pid $(getpid())")
println("popewatchesmatter will run until interrupted, OR\nthe MATTER sentinel file points to a file called \"endpope\"")
function run()
  while true
    ljhpath0, writingbool = wait_for_writing_status(true)
    if ljhpath0 == "endpope" break end
    println("Matter has started writing $ljhpath0, starting POPE")
    output_file = get_output_file(ljhpath0)
    readers,monitor_endchannel = launch_continuous_analysis(preknowledge_filename, ljhpath0, output_file)
    ljhpath1, writingbool = wait_for_writing_status(false)
    if ljhpath0 != ljhpath1
      println("WARNING: ljhpath changed between open and close")
      println("writing status true: $ljhpath0")
      println("writing status false: $ljhpath1")
    end
    println("Matter has stopped writing $ljhpath0, waiting 3 seconds before Pope finishes analysis.")
    sleep(3) # give some time for ljh files to be finalized by matter
    finish_analysis(readers,monitor_endchannel)
    close(output_file)
    println("Pope finished analyzing $ljhpath0")
    summarize_readers(readers)
  end
end
if arguments["--forcenowrite"]
  LJH.write_sentinel_file("forced",false)
  println("Changed matter sentinel file to contain \"forced\", false.")
end
run()
println("popewatchesmatter finished.")
flush(STDOUT)


text:
export @region, @neighbor, @nearest, @surround, @face
using MacroTools
using MacroTools: @match, postwalk

abstract type PlaceHolder end
name(ph::PlaceHolder) = ph.name
Base.show(io::IO, ph::PlaceHolder) = print(io, name(ph))

const PlaceHolderMap = Dict{Symbol, Type}()

function _placeholder_expr(typename)
    quote
        Core.@__doc__ struct $(typename) <: PlaceHolder
            name::Symbol
        end
    end
end

function _placeholder_var_expr(type_::Type, var)
    :(Core.@__doc__ $(esc(var)) = $(type_(var)))
end

declare_placeholder(type_::Type, var::Symbol) = _placeholder_var_expr(type_, var)

function declare_placeholder(type_::Type, vars)
    @assert vars.head == :tuple || vars.head == :escape "invalid syntax, expect tuple, got $vars ($vars.head)"

    ex = quote end
    for each in vars.args
        def = _placeholder_var_expr(type_, each)
        push!(ex.args, def)
    end
    push!(ex.args, esc(vars))
    ex
end

make_region(alias::Symbol, vars) = declare_placeholder(PlaceHolderMap[alias], vars)
make_neighbor(k::Int, vars) = declare_placeholder(Neighbor{k}, vars)

function register_holder_macro_entry(name::QuoteNode, val)
    mname = Symbol("@$(name.value)")
    docstr =
"""
    @$(name.value) vars...

Declare place holders for `$val`. See doc of `$val` for details.
"""

    quote
        PlaceHolderMap[$name] = $(esc(val))

        export $mname # export this macro
        macro $(esc(name.value))(vars)
            make_region($name, vars)
        end

        @doc $docstr $mname
    end
end

"""
    @register_holder alias => typename
    @register_holder typename alias_list

Define place holder types and register their alias in `PlaceHolderMap`.

### Example

register a simple `Vertex` type with alias `vertex`.

```julia
@register_holder :vertex => Vertex
```

register a parametric type `Neighbor{K}` with different alias.

```julia
@register_holder Neighbor{K} begin
    :nearest => Neighbor{1}
    :next_nearest => Neighbor{2}
end
```
"""
macro register_holder end

macro register_holder(typename, list)
    ex = _placeholder_expr(typename)

    for each in list.args
        if @capture(each, name_ => val_)
            def = register_holder_macro_entry(name, val)
            push!(ex.args, def)
        end
    end
    # push expr return value
    push!(ex.args, true)
    ex
end

macro register_holder(pair)
    @capture(pair, name_ => typename_)
    quote
        $(_placeholder_expr(typename))

        $(register_holder_macro_entry(name, typename))
        true
    end
end

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

"""
    Vertex <: PlaceHolder

Place holder for vertex on lattice. This represents
all the vertexes on a lattice/region.
"""
@register_holder :vertex => Vertex

"""
    Neighbor{K} <: PlaceHolder

Place holder for near-neighbor correlation. This represents
k-th near-neighbor on a lattice/region. e.g `Neighbor{1}` means
the nearest neighbor.
"""
@register_holder Neighbor{K} begin
    :nearest => Neighbor{1}
    :next_nearest => Neighbor{2}
end

"""
    Surround <: PlaceHolder

Place holder for surrounding area of a vertex.
"""
@register_holder :surround => Surround
@register_holder :face => Face

################################################################################
# Factory Macros
macro region(alias::QuoteNode, vars)
    make_region(alias.value, vars)
end

macro neighbor(k::Int, vars)
    make_neighbor(k, vars)
end

max_stars_repo_name: Roger-luo/QuHamiltonian

max_issues_repo_name: Roger-luo/QuHamiltonian

max_forks_repo_name: Roger-luo/QuHamiltonian


text:
function SimpleValueChecker(arg0::jdouble, arg1::jdouble)
    return SimpleValueChecker((jdouble, jdouble), arg0, arg1)
end

function SimpleValueChecker(arg0::jdouble, arg1::jdouble, arg2::jint)
    return SimpleValueChecker((jdouble, jdouble, jint), arg0, arg1, arg2)
end

function converged(obj::SimpleValueChecker, arg0::jint, arg1::PointValuePair, arg2::PointValuePair)
    return jcall(obj, "converged", jboolean, (jint, PointValuePair, PointValuePair), arg0, arg1, arg2)
end


text:
## TRIGGER
# Trigger level
set_trig_lev(obj::T;ch="1",lev=1) where {T<:F335x2} = write(obj,"TRIG$ch:LEV$lev")

## OUTPUT FUNCTION
# Duty Cycle
set_duty(obj::T;ch="1",func="square",duty=0.01) where {T<:F335x2} = write(obj,"SOURce$ch:FUNC:$func:DCYC $duty")

## SYNC
# Sync Source
set_sync_sour(obj::T;sour=1) where {T<:F335x2} = write(obj,"OUTP:SYNC:SOUR ch$sour")
# Sync Polarity
set_sync_pol(obj::T;ch="1",pol="normal") where {T<:F335x2} = write(obj,"OUTP$ch:SYNC:POL $pol")
# Phase sync
set_phase_sync(obj::T;ch="1") where {T<:F335x2} = write(obj,"SOURce$ch:PHAS:SYNC")

## BURST
# Burst on
set_burst_stat(obj::T;ch="1",st="off") where {T<:F335x2} = write(obj,"SOUR$ch:BURS:STAT $st")
# Burst mode
set_burst_mode(obj::T;ch="1",md="triggered") where {T<:F335x2} = write(obj,"SOUR$ch:BURS:MODE $md")
# Burst polarity
set_burst_pol(obj::T;ch="1",pol="normal") where {T<:F335x2} = write(obj,"SOUR$ch:BURS:GATE:POL $pol")
# Burst ncycles
set_burst_ncyc(obj::T;ch="1",nc=1) where {T<:F335x2} = write(obj,"SOUR$ch:BURS:NCYC $nc")
# Burst period
set_burst_per(obj::T;ch="1",per=0.01) where {T<:F335x2} = write(obj,"SOUR$ch:BURS:INT:PER $nc")
# Burst phase
set_burst_phase(obj::T;ch="1",unit="deg",phase=0) where {T<:F335x2} = write(obj,"UNIT:ANGL $unit\n;SOUR$ch:BURS:PHAS $phase")

## ARBITRARY WAVEFORMS
# Send arb waveform to volatile memory
function send_arb(obj::T;ch="1",wfm=wfm,dt=1e-6,arb="mywfm") where {T<:F335x2}
	write(obj, "FORM:BORD SWAP")
	arb_bytes = string(length(wfm) * 4)
	arb_bytes_len = string(length(arb_bytes))
	header = "SOURce$ch:DATA:ARBitrary "*arb*", #"*arb_bytes_len*arb_bytes
	header = Vector{UInt8}(header)
	binblock_bytes = reinterpret(UInt8, wfm)[:]
	viWrite(obj.handle, [header; binblock_bytes])
end


text:
using CSV, Interpolations, DataFrames

"""
    Performance(twa, tws, boat_perf)

Type to hold sailing craft performance information.

Arguments:

- twa: Array of true wind angles for each point in polar plot.
- tws: Array of true wind speeds for each point in polar plot.
- boat_perf: Dierckx 2D spline instance.

"""
mutable struct Performance
    twa
    tws
    boat_perf
    uncertainty::Float64
end

"""
    load_file(path)

Load the file specified by path.
"""
function load_file(path)
    df = CSV.read(path, delim=';', datarow=1)
    perf = convert(Array{Float64}, df[2:end, 2:end])
    tws = convert(Array{Float64}, df[1, 2:end])
    twa = map(x->parse(Float64, x), df[2:end, 1])
    return twa, dropdims(tws, dims=1), perf
end

"""
    setup_interpolation(tws, twa, perf)

Return interpolation object.
"""
function setup_interpolation(tws, twa, perf)
    knots = (twa, tws)
    itp = interpolate(knots, perf, Gridded(Linear()))
    return itp
end

"""
    perf_interp(itp, twa, tws)

Return interpolated performance.
"""
function perf_interp(itp, twa, tws)
    return itp[twa, tws]
end

function h(cudi::Float64, cusp::Float64, bearing::Float64)
    cusp*sin(deg2rad(cudi-bearing))
end

function current(polar, cudi::Float64, cusp::Float64, widi::Float64,
    wisp::Float64, bearing::Float64, heading::Float64)
    vs = perf_interp(polar, min_angle(widi, heading), wisp)
    return (acos(h(cudi, cusp, bearing)/vs)*180/π - bearing)
end

"""
correct_speed(polar, cudi, cusp, widi, wisp, bearing)

Identify corrected speed for routing.
"""
function correct_speed(polar, cudi::Float64, cusp::Float64, widi::Float64,
          wisp::Float64, bearing::Float64)
    h1 = 0.0
    h2 = current(polar, cudi, cusp, widi, wisp, bearing, h1)
    while h2 - h1 > 0.1
        h1 = h2
        h2 = current(polar, cudi, cusp, widi, wisp, bearing, h1)
    end
    bearing = bearing + h2
    @inbounds vs = perf_interp(polar, min_angle(widi, bearing), wisp)
    return vs + cusp
end


text:
using HTTP, JSON3
todos = Dict(     # type is Dict{Int64, String}
               1 => "Getting groceries",
               2 => "Visiting my therapist",
               3 => "Getting a haircut"
)

json_string = JSON3.write(todos)
# "{\"2\":\"Visiting my therapist\",\"3\":\"Getting a haircut\",\"1\":\"Getting groceries\"}"
todos2 = JSON3.read(json_string)
# JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 3 entries:
#   Symbol("2") => "Visiting my therapist"
#   Symbol("3") => "Getting a haircut"
#   Symbol("1") => "Getting groceries"

todos2[1]  # "Getting groceries"

resp = HTTP.Response(
               200,
               ["Content-Type" => "application/json"],
               body=JSON3.write(todos)
           )

# HTTP.Messages.Response:
# """
# HTTP/1.1 200 OK
# Content-Type: application/json

# {"2":"Visiting my therapist","3":"Getting a haircut","1":"Getting groceries"}"""

body = HTTP.payload(resp) # this gives a Vector of UInt8 bytes
io = IOBuffer(body)
todos = JSON3.read(io)
# or combined in one line:
todos = JSON3.read(IOBuffer(HTTP.payload(resp)))
# JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 3 entries:
#   Symbol("2") => "Visiting my therapist"
#   Symbol("3") => "Getting a haircut"
#   Symbol("1") => "Getting groceries"


text:
function mnistgrid(images, nrow, filename=nothing)
    yy = reshape(images, 28, 28, size(images)[end])
    yy = permutedims(yy, (2,1,3))
    yy = Images.imresize(yy, 40, 40)
    yy = Gray.(mosaicview(yy, 0.5f0, nrow=nrow, npad=1, rowmajor=true))
    if filename == nothing
        display(yy)
    else
        save(filename, yy)
    end
end

max_stars_repo_name: ilkerkesen/draw

max_issues_repo_name: ilkerkesen/draw

max_forks_repo_name: ilkerkesen/draw


text:
function mark_corner_frame_with_borders(r)
    home=[]
    home = move_to_corner!(r)
    mark_corner_frame(r)
    move_to_home!(r,home)
    end
function move_to_border!(r,side)
    count=0
    while isborder(r,side)==0
        move!(r,side)
        count +=1
    end
    return count
end
function move_to_corner!(r)
home=[]
    while isborder(r,Nord)==0 || isborder(r,West)==0
        x = move_to_border!(r,Nord)
        y = move_to_border!(r,West)
        push!(home,x)
        push!(home,y)
    end
    return home
end
function countmove!(r,side,count)
    for i in 1:count
        move!(r,side)
    end
end
function mark_corner_frame(r)
    putmarker!(r)
    for side in [Sud,Ost,Nord,West]
        while isborder(r,side)==0
            move!(r,side)
        end
        putmarker!(r)
    end
end
function move_to_home!(r,home)
    reverse!(home)
    for i = 1:length(home)
        if i%2==0
            countmove!(r,Sud,home[i])
        else
            countmove!(r,Ost,home[i])
        end
    end
end
mark_corner_frame_with_borders(r)


text:
module MyPkg

# Write your package code here.
function add_nums(a,b)
    a+b
end
function Simpson(f, a, b)
    # Simpson Formula
    # (b-a)/6 * (f(a) + 4*f((a+b)/2) + f(b))
    h = (b - a)/2
    x = a:h:b
    sum((x[3] - x[1])/6*(f(x[3]) + 4*f(x[2]/2) + f(x[1])))
end

end


text:
#!/bin/sh
# ########## Begin Slurm header ##########
#SBATCH --nodes=1
#SBATCH --ntasks-per-node=1
#SBATCH --time=1:00:00
#SBATCH --mem=10gb
#SBATCH --cpus-per-task=48
#SBATCH --job-name=diag-test
#SBATCH --output="logs/diag-test-%j.out"
########### End Slurm header ##########
#=
# load modules
# not needed - julia installed locally

exec julia --color=no --startup-file=no "${BASH_SOURCE[0]}" "$@"
=#
println("diagonalization_speed.jl")

# check ARGS length and print usage if wrong

## environment
import Pkg
using LinearAlgebra # for BLAS threads

BLAS.set_num_threads(96)

println("Working Directory:          $(pwd())" )
println("Running on host:            $(gethostname())" )
println("Job id:                     $(get(ENV, "SLURM_JOB_ID", ""))" )
println("Job name:                   $(get(ENV, "SLURM_JOB_NAME", ""))" )
println("Number of nodes allocated:  $(get(ENV, "SLURM_JOB_NUM_MODES", ""))" )
println("Number of cores allocated:  $(get(ENV, "SLURM_NTASKS", ""))" )
println("#threads of Julia:          $(Threads.nthreads())")
println("#threads of BLAS:           $(BLAS.get_num_threads())")
@show ARGS

Pkg.activate(".")
Pkg.instantiate(; io=stdout)
Pkg.status(; io=stdout)

## imports
using SimLib
using LinearAlgebra

using XXZNumerics

## constants and ARGS
const PREFIX = joinpath(path_prefix(), "cusp-zoom2-test")
@show PREFIX
const GEOMETRY = :box_pbc
const DIM = 1
const N = 15
const ALPHA = 6
const FIELDS = collect(-0.11:0.005:-0.05)
const ρs = [1.0]
const SHOTS = 2#200

@show GEOMETRY
@show DIM
@show N
@show ALPHA
@show FIELDS
@show ρs
@show SHOTS

const LOCATION = SaveLocation(; prefix=PREFIX)
## functions

## main

println()
logmsg("Starting!")

@time begin
    ## DO STUFF
    ensdd = EnsembleDataDescriptor(GEOMETRY, DIM, N, ALPHA, SHOTS, ρs, FIELDS, :ensembles, zbasis(N), LOCATION)
    logmsg("Computing $ensdd")
    save(create(ensdd); suffix="p_1")
    logmsg("Done!")
end
## REMEMBER TO SET RESOURCE HEADER FOR SLURM!


text:
using Pkg
using Pollen
using DataAugmentation

p = Pollen.documentationproject(DataAugmentation)
Pollen.serve(p)


text:
module RangeArrays

include("matrix.jl")
include("repeatedrange.jl")

export RangeMatrix, RepeatedRangeMatrix

end # module