text:
#=

This is a script that we use to run speed tests on two-dim grids.
Run like julia st_grid3.jl 1
Which will run for approximately 1 hour, increasing the sizes of the graphs.

=#

hours = parse(ARGS[1])

fn = "st_grid3_h$(hours).jld"
println(fn)

using Laplacians
using MATLAB

lapdir = Pkg.dir("Laplacians")

include("$(lapdir)/compare/matlabSafe.jl")
include("$(lapdir)/compare/compare_solvers_TL.jl")

ac_deg = function(a; verbose=false, args...)
    approxchol_lap(a; params=ApproxCholParams(:deg), verbose=verbose, args...)
end
ac_wdeg = function(a; verbose=false, args...)
    approxchol_lap(a; params=ApproxCholParams(:wdeg), verbose=verbose, args...)
end

test_ac = SolverTest(ac_deg, "ac")
test_acw = SolverTest(ac_wdeg, "ac_fast")
test_amg = SolverTest(AMGLapSolver, "pyamg")

tests = [test_ac test_acw test_amg]

# warm up the code
a = chimera(10000,1)
b = randn(10000)
b = b - mean(b)
for solver in tests
    f = solver.solver(a,verbose=true)
    x = f(b)
end

dic = Dict()

using JLD

n = 10000
t0 = time()

while time() - t0 < 60*60*hours

    n = 2*n
    println("-----------")
    println(n)

    nuse = round(Int,n^(1/3))
    a = grid3(nuse)

    tn = "grid3($(nuse))"
    b = randn(size(a,1))
    b = b - mean(b)
    b = b / norm(b)
    x = testVMatlabLap(tests, dic, a, b, verbose=true, tol=1e-8, testName=tn, test_icc=true)

    save(fn,"dic",dic)

end


text:
using ApproxFunOrthogonalPolynomials, InfiniteArrays, LinearAlgebra, Test

@testset "Domain" begin
    @test reverseorientation(Arc(1,2,(0.1,0.2))) == Arc(1,2,(0.2,0.1))
end

@time include("ClenshawTest.jl")
@time include("ChebyshevTest.jl")
@time include("ComplexTest.jl")
@time include("broadcastingtest.jl")
@time include("OperatorTest.jl")
@time include("ODETest.jl")
@time include("EigTest.jl")
@time include("VectorTest.jl")
@time include("JacobiTest.jl")
@time include("LaguerreTest.jl")
@time include("HermiteTest.jl")
@time include("SpacesTest.jl")
@time include("MultivariateTest.jl")
@time include("PDETest.jl")

include("SpeedTest.jl")
include("SpeedODETest.jl")
include("SpeedPDETest.jl")
include("SpeedOperatorTest.jl")

ext: jl


text:
# AUTO GENERATED FILE - DO NOT EDIT

export dashbio_ideogram

"""
    dashbio_ideogram(;kwargs...)

An Ideogram component.
The Ideogram component is used to draw and animate genome-wide
datasets for organisms such as human, mouse, and any other
eukaryote. The Ideogram component can be used to compare
homologous features between chromosomes, and depict
haploid, diploid, aneuploid genomes. It can also display
annotations on genomic data using histograms and overlays.

Reference: https://eweitz.github.io/ideogram/
Component's props: https://github.com/eweitz/ideogram/blob/master/api.md
Keyword arguments:
- `id` (String; required): The ID used to identify this component in Dash callbacks and used to identify Ideogram
instances.
- `ancestors` (Dict; optional): A map associating ancestor labels to colors. Used to color
chromosomes from different ancestors in polyploid genomes.
- `annotationHeight` (Real; optional): Not used if annotationsLayout is set to "overlay".
The height of histogram bars or the size of annotations tracks symbols
- `annotationTracks` (Array of Dicts; optional): A list of objects with metadata for each track, e.g., id, display name, color, shape.
- `annotations` (optional): A list of annotation objects. Annotation objects can also have a name, color, shape, and
track index. At the moment there is more keys specified and the docs need updating.. annotations has the following type: Array of lists containing elements 'name', 'chr', 'start', 'stop'.
Those elements have the following types:
  - `name` (String; optional)
  - `chr` (String; optional)
  - `start` (Real; optional)
  - `stop` (Real; optional)s
- `annotationsColor` (String; optional): Color of annotations.
- `annotationsData` (String; optional): Use this prop in a dash callback to return annotationData when hovered.
It is read-only, i.e., it cannot be used with dash.dependencies.Output but only with
dash.dependencies.Input
- `annotationsLayout` (a value equal to: 'tracks', 'histogram', 'overlay'; optional): Layout of ideogram annotations.
One of "tracks", "histogram", or "overlay".

"tracks": display annotations in tracks beside each chromosome.

"histogram": display annotations in a histogram. Clusters annotations by location. Each
cluster/bin is shown as a bar, the height of which represents the number of annotations on
genomic range.

"overlay": display annotations directly over chromosomes.
- `annotationsPath` (String; optional): An absolute or relative URL directing to a JSON file containing annotation objects (JSON).
- `assembly` (String; optional): Default: latest RefSeq assembly for specified organism.
The genome assembly to display.
Takes assembly name (e.g., "GRCh37"),
RefSeq accession (e.g., "GCF_000306695.2"),
or GenBank accession (e.g., "GCA_000005005.5")
- `barWidth` (Real; optional): Pixel width of histogram bars.
Only used if annotationsLayout is set to "histogram".
- `brush` (String; optional): Genomic coordinate range (e.g., "chr1:104325484-119977655") for a brush on a
chromosome. Useful when ideogram consists of one chromosome and you want to be
able to focus on a region within that chromosome,
and create an interactive sliding window to other regions
- `brushData` (optional): A dash callback that is activated when the 'brush' prop is used.
It will return an dictionary like so:
{'start': <value>, 'end': <value>, 'extent': <value>}
where start is the left most edge, end is right most edge, and extent is the total width of
the brush.
It is read-only, i.e., it cannot be used with dash.dependencies.Output but only with
dash.dependencies.Input. brushData has the following type: lists containing elements 'start', 'end', 'extent'.
Those elements have the following types:
  - `start` (String; optional)
  - `end` (String; optional)
  - `extent` (String; optional)
- `chrHeight` (Real; optional): The pixel height of the tallest chromosome in the ideogram
- `chrMargin` (Real; optional): The pixel space of margin between each chromosome.
- `chrWidth` (Real; optional): The pixel width of each chromosome.
- `chromosomes` (Array of Strings | Dict; optional): A list of the names of chromosomes to display. Useful for depicting a subset of the
chromosomes in the genome, e.g., a single chromosome.

If Homology (between two different species):
Ex: chromosomes={
      'human': ['1'],
      'mouse': ['4']
}

General case to specify specific chromosomes:
Ex: chromosomes=['1', '2']
- `className` (String; optional): The CSS class of the component wrapper
- `container` (String; optional): CSS styling and the id of the container holding the Ideogram in
react-ideogram.js, this is where all the d3 magic happens.
- `dataDir` (String; optional): Absolute or relative URL of the directory containing data needed to draw banded chromosomes.
You will need to set up your own database to grab data from a custom database.
- `filterable` (Bool; optional): Whether annotations should be filterable or not.
- `fullChromosomeLabels` (Bool; optional): Whether to include abbreviation species name in chromosome label. Used for homology.
- `histogramScaling` (a value equal to: 'absolute', 'relative'; optional): Scaling of histogram bars height
Only used if annotationsLayout is set to "histogram".
One of "absolute" or "relative".

"absolute": sets bar height relative to tallest bar in all chromosomes.
"relative": sets bar height relative to tallest bar in each chromosome.
- `homology` (optional): Used to compare two chromosomes.
The keys "chrOne" and "chrTwo" represent one chromosome each. Organism is the taxID or name.
Start is an array, containing start one and start two, in this order. Stop is an array,
containing stop one, and stop two, in this order.
Ex: homology={
    "chrOne": {
        organism": "9606",
        "start": [50000, 155701383],
        "stop": [900000, 156030895]
    },
    "chrTwo": {
        organism": "10090",
        "start": [10001, 50000000],
        "stop": [2781479, 57217415]
    }
}. homology has the following type: lists containing elements 'chrOne', 'chrTwo'.
Those elements have the following types:
  - `chrOne` (optional): . chrOne has the following type: lists containing elements 'organism', 'start', 'stop'.
Those elements have the following types:
  - `organism` (String; required)
  - `start` (Array of Reals; optional)
  - `stop` (Array of Reals; optional)
  - `chrTwo` (optional): . chrTwo has the following type: lists containing elements 'organism', 'start', 'stop'.
Those elements have the following types:
  - `organism` (String; required)
  - `start` (Array of Reals; optional)
  - `stop` (Array of Reals; optional)
- `localOrganism` (Dict; optional): Provide local JSON organism into this prop from a local user JSON file.
DataDir must not be initialized.
- `organism` (String | Real; optional): Organism(s) to show chromosomes for. Supply organism's name as a string (e.g., "human") or
organism's NCBI Taxonomy ID (taxid, e.g., 9606) to display chromosomes from a single
organism, or an array of organisms' names or taxids to display chromosomes from multiple
species.
- `orientation` (a value equal to: 'vertical', 'horizontal'; optional): The orientation of chromosomes on the page.
- `perspective` (a value equal to: 'comparative'; optional): Use perspective: 'comparative' to enable annotations between two chromosomes,
either within the same organism or different organisms. Used for homology.
- `ploidy` (Real; optional): The ploidy - number of chromosomes to depict for each chromosome set.
- `ploidyDesc` (Array of Dicts; optional): Description of ploidy in each chromosome set in terms of ancestry composition.
- `rangeSet` (Array of Dicts; optional): List of objects describing segments of recombination among chromosomes in a chromosome set.
- `resolution` (Real; optional): The resolution of cytogenetic bands to show for each chromosome.
The quantity refers to an approximate value in bands per haploid set (bphs).
One of 450, 550, or 850.
- `rotatable` (Bool; optional): Whether chromosomes are rotatable on click.
- `rotated` (Bool; optional): Dash callback that returns true if rotated, and false if not.
- `sex` (a value equal to: 'male', 'female'; optional): Useful for omitting chromosome Y in female animals.
Currently only supported for organisms that use XY sex-determination.
- `showAnnotTooltip` (Bool; optional): Whether to show a tooltip upon mousing over an annotation.
- `showBandLabels` (Bool; optional): Whether to show cytogenetic band labels, e.g., 1q21.
- `showChromosomeLabels` (Bool; optional): Whether to show chromosome labels, e.g., 1, 2, 3, X, Y.
- `showFullyBanded` (Bool; optional): Whether to show fully banded chromosomes for genomes that have sufficient data. Useful for
showing simpler chromosomes of cytogenetically well-characterized organisms, e.g., human,
beside chromosomes of less studied organisms, e.g., chimpanzee.
- `showNonNuclearChromosomes` (Bool; optional): Whether to show non-nuclear chromosomes,
e.g., for mitochondrial (MT) and chloroplast (CP) DNA.
- `style` (Dict; optional): The component's inline styles
"""
function dashbio_ideogram(; kwargs...)
        available_props = Symbol[:id, :ancestors, :annotationHeight, :annotationTracks, :annotations, :annotationsColor, :annotationsData, :annotationsLayout, :annotationsPath, :assembly, :barWidth, :brush, :brushData, :chrHeight, :chrMargin, :chrWidth, :chromosomes, :className, :container, :dataDir, :filterable, :fullChromosomeLabels, :histogramScaling, :homology, :localOrganism, :organism, :orientation, :perspective, :ploidy, :ploidyDesc, :rangeSet, :resolution, :rotatable, :rotated, :sex, :showAnnotTooltip, :showBandLabels, :showChromosomeLabels, :showFullyBanded, :showNonNuclearChromosomes, :style]
        wild_props = Symbol[]
        return Component("dashbio_ideogram", "Ideogram", "dash_bio", available_props, wild_props; kwargs...)
end


text:
# Automatically generated using Clang.jl

const ai_real = Cfloat

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

struct aiAABB
    mMin::aiVector3D
    mMax::aiVector3D
end

# Skipping MacroDefinition: ai_assert ( expression ) ( void ) ( ( ! ! ( expression ) ) || ( Assimp : : aiAssertViolation ( # expression , __FILE__ , __LINE__ ) , 0 ) )
# Skipping MacroDefinition: ai_assert_entry ( ) ai_assert ( false )

struct aiVectorKey
    mTime::Cdouble
    mValue::aiVector3D
end

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

struct aiQuatKey
    mTime::Cdouble
    mValue::aiQuaternion
end

struct aiMeshKey
    mTime::Cdouble
    mValue::UInt32
end

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

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

const ai_uint32 = UInt32

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

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

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

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

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

struct aiCamera
    mName::aiString
    mPosition::aiVector3D
    mUp::aiVector3D
    mLookAt::aiVector3D
    mHorizontalFOV::Cfloat
    mClipPlaneNear::Cfloat
    mClipPlaneFar::Cfloat
    mAspect::Cfloat
    mOrthographicWidth::Cfloat
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 aiMetadata
    mNumProperties::UInt32
    aiString::Cint
    aiMetadataEntry::Cint
end

struct aiNode
    mName::aiString
    mTransformation::aiMatrix4x4
    mParent::Ptr{aiNode}
    mNumChildren::UInt32
    mChildren::Ptr{Ptr{aiNode}}
    mNumMeshes::UInt32
    mMeshes::Ptr{UInt32}
    mMetaData::Ptr{aiMetadata}
end

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

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

struct aiVertexWeight
    mVertexId::UInt32
    mWeight::ai_real
end

struct aiBone
    mName::aiString
    mNumWeights::UInt32
    mArmature::Ptr{aiNode}
    mNode::Ptr{aiNode}
    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::UInt32
    mWeight::Cfloat
end

struct aiMesh
    mPrimitiveTypes::UInt32
    mNumVertices::UInt32
    mNumFaces::UInt32
    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, UInt32}
    mFaces::Ptr{aiFace}
    mNumBones::UInt32
    mBones::Ptr{Ptr{aiBone}}
    mMaterialIndex::UInt32
    mName::aiString
    mNumAnimMeshes::UInt32
    mAnimMeshes::Ptr{Ptr{aiAnimMesh}}
    mMethod::UInt32
    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::UInt32
    mIndex::UInt32
    mDataLength::UInt32
    mType::aiPropertyTypeInfo
    mData::Cstring
end

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

struct aiTexel
    b::Cuchar
    g::Cuchar
    r::Cuchar
    a::Cuchar
end

struct aiTexture
    mWidth::UInt32
    mHeight::UInt32
    achFormatHint::NTuple{9, UInt8}
    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 aiColor3D
    r::ai_real
    g::ai_real
    b::ai_real
end

struct aiVector2D
    x::ai_real
    y::ai_real
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 aiScene
    mFlags::UInt32
    mRootNode::Ptr{aiNode}
    mNumMeshes::UInt32
    mMeshes::Ptr{Ptr{aiMesh}}
    mNumMaterials::UInt32
    mMaterials::Ptr{Ptr{aiMaterial}}
    mNumAnimations::UInt32
    mAnimations::Ptr{Ptr{aiAnimation}}
    mNumTextures::UInt32
    mTextures::Ptr{Ptr{aiTexture}}
    mNumLights::UInt32
    mLights::Ptr{Ptr{aiLight}}
    mNumCameras::UInt32
    mCameras::Ptr{Ptr{aiCamera}}
    mMetaData::Ptr{aiMetadata}
    mPrivate::Cstring
end

const aiFileOpenProc = Ptr{Cvoid}
const aiFileCloseProc = Ptr{Cvoid}
const aiUserData = Cstring

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

struct aiExportFormatDesc
    id::Cstring
    description::Cstring
    fileExtension::Cstring
end

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

const aiFileReadProc = Ptr{Cvoid}
const aiFileWriteProc = Ptr{Cvoid}
const aiFileTellProc = Ptr{Cvoid}
const aiFileSeek = Ptr{Cvoid}
const aiFileFlushProc = Ptr{Cvoid}

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

const AI_FALSE = 0
const AI_TRUE = 1
const aiLogStreamCallback = Ptr{Cvoid}

struct aiLogStream
    callback::aiLogStreamCallback
    user::Cstring
end

struct aiPropertyStore
    sentinel::UInt8
end

const aiBool = Cint
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"

# Skipping MacroDefinition: aiComponent_COLORSn ( n ) ( 1u << ( n + 20u ) )
# Skipping MacroDefinition: aiComponent_TEXCOORDSn ( n ) ( 1u << ( n + 25u ) )

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_MDL_HL1_READ_ANIMATIONS = "IMPORT_MDL_HL1_READ_ANIMATIONS"
const AI_CONFIG_IMPORT_MDL_HL1_READ_ANIMATION_EVENTS = "IMPORT_MDL_HL1_READ_ANIMATION_EVENTS"
const AI_CONFIG_IMPORT_MDL_HL1_READ_BLEND_CONTROLLERS = "IMPORT_MDL_HL1_READ_BLEND_CONTROLLERS"
const AI_CONFIG_IMPORT_MDL_HL1_READ_SEQUENCE_TRANSITIONS = "IMPORT_MDL_HL1_READ_SEQUENCE_TRANSITIONS"
const AI_CONFIG_IMPORT_MDL_HL1_READ_ATTACHMENTS = "IMPORT_MDL_HL1_READ_ATTACHMENTS"
const AI_CONFIG_IMPORT_MDL_HL1_READ_BONE_CONTROLLERS = "IMPORT_MDL_HL1_READ_BONE_CONTROLLERS"
const AI_CONFIG_IMPORT_MDL_HL1_READ_HITBOXES = "IMPORT_MDL_HL1_READ_HITBOXES"
const AI_CONFIG_IMPORT_MDL_HL1_READ_MISC_GLOBAL_INFO = "IMPORT_MDL_HL1_READ_MISC_GLOBAL_INFO"
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"

@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 = 2684354559
end

# Skipping MacroDefinition: AI_WONT_RETURN_SUFFIX __attribute__ ( ( noreturn ) )

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_DEG_TO_RAD ( x ) ( ( x ) * ( ai_real ) 0.0174532925 )
# Skipping MacroDefinition: AI_RAD_TO_DEG ( x ) ( ( x ) * ( ai_real ) 57.2957795 )
# Skipping MacroDefinition: AI_MAX_ALLOC ( type ) ( ( 256U * 1024 * 1024 ) / sizeof ( type ) )
# Skipping MacroDefinition: AI_DEBUG_INVALIDATE_PTR ( x ) x = NULL ;

const ai_int = Cint
const ai_uint = UInt32
const AI_FAST_ATOF_RELAVANT_DECIMALS = 15

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

struct aiImporterDesc
    mName::Cstring
    mAuthor::Cstring
    mMaintainer::Cstring
    mComments::Cstring
    mFlags::UInt32
    mMinMajor::UInt32
    mMinMinor::UInt32
    mMaxMajor::UInt32
    mMaxMinor::UInt32
    mFileExtensions::Cstring
end

const AI_DEFAULT_MATERIAL_NAME = "DefaultMaterial"

@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

const AI_TEXTURE_TYPE_MAX = aiTextureType_UNKNOWN

# Skipping MacroDefinition: AI_MATKEY_NAME "?mat.name" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_TWOSIDED "$mat.twosided" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_SHADING_MODEL "$mat.shadingm" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_ENABLE_WIREFRAME "$mat.wireframe" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_BLEND_FUNC "$mat.blend" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_OPACITY "$mat.opacity" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_TRANSPARENCYFACTOR "$mat.transparencyfactor" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_BUMPSCALING "$mat.bumpscaling" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_SHININESS "$mat.shininess" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_REFLECTIVITY "$mat.reflectivity" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_SHININESS_STRENGTH "$mat.shinpercent" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_REFRACTI "$mat.refracti" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_COLOR_DIFFUSE "$clr.diffuse" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_COLOR_AMBIENT "$clr.ambient" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_COLOR_SPECULAR "$clr.specular" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_COLOR_EMISSIVE "$clr.emissive" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_COLOR_TRANSPARENT "$clr.transparent" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_COLOR_REFLECTIVE "$clr.reflective" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_GLOBAL_BACKGROUND_IMAGE "?bg.global" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_GLOBAL_SHADERLANG "?sh.lang" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_SHADER_VERTEX "?sh.vs" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_SHADER_FRAGMENT "?sh.fs" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_SHADER_GEO "?sh.gs" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_SHADER_TESSELATION "?sh.ts" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_SHADER_PRIMITIVE "?sh.ps" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_SHADER_COMPUTE "?sh.cs" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_TEXTURE ( type , N ) _AI_MATKEY_TEXTURE_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_TEXTURE_DIFFUSE ( N ) AI_MATKEY_TEXTURE ( aiTextureType_DIFFUSE , N )
# Skipping MacroDefinition: AI_MATKEY_TEXTURE_SPECULAR ( N ) AI_MATKEY_TEXTURE ( aiTextureType_SPECULAR , N )
# Skipping MacroDefinition: AI_MATKEY_TEXTURE_AMBIENT ( N ) AI_MATKEY_TEXTURE ( aiTextureType_AMBIENT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXTURE_EMISSIVE ( N ) AI_MATKEY_TEXTURE ( aiTextureType_EMISSIVE , N )
# Skipping MacroDefinition: AI_MATKEY_TEXTURE_NORMALS ( N ) AI_MATKEY_TEXTURE ( aiTextureType_NORMALS , N )
# Skipping MacroDefinition: AI_MATKEY_TEXTURE_HEIGHT ( N ) AI_MATKEY_TEXTURE ( aiTextureType_HEIGHT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXTURE_SHININESS ( N ) AI_MATKEY_TEXTURE ( aiTextureType_SHININESS , N )
# Skipping MacroDefinition: AI_MATKEY_TEXTURE_OPACITY ( N ) AI_MATKEY_TEXTURE ( aiTextureType_OPACITY , N )
# Skipping MacroDefinition: AI_MATKEY_TEXTURE_DISPLACEMENT ( N ) AI_MATKEY_TEXTURE ( aiTextureType_DISPLACEMENT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXTURE_LIGHTMAP ( N ) AI_MATKEY_TEXTURE ( aiTextureType_LIGHTMAP , N )
# Skipping MacroDefinition: AI_MATKEY_TEXTURE_REFLECTION ( N ) AI_MATKEY_TEXTURE ( aiTextureType_REFLECTION , N )
# Skipping MacroDefinition: AI_MATKEY_UVWSRC ( type , N ) _AI_MATKEY_UVWSRC_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_UVWSRC_DIFFUSE ( N ) AI_MATKEY_UVWSRC ( aiTextureType_DIFFUSE , N )
# Skipping MacroDefinition: AI_MATKEY_UVWSRC_SPECULAR ( N ) AI_MATKEY_UVWSRC ( aiTextureType_SPECULAR , N )
# Skipping MacroDefinition: AI_MATKEY_UVWSRC_AMBIENT ( N ) AI_MATKEY_UVWSRC ( aiTextureType_AMBIENT , N )
# Skipping MacroDefinition: AI_MATKEY_UVWSRC_EMISSIVE ( N ) AI_MATKEY_UVWSRC ( aiTextureType_EMISSIVE , N )
# Skipping MacroDefinition: AI_MATKEY_UVWSRC_NORMALS ( N ) AI_MATKEY_UVWSRC ( aiTextureType_NORMALS , N )
# Skipping MacroDefinition: AI_MATKEY_UVWSRC_HEIGHT ( N ) AI_MATKEY_UVWSRC ( aiTextureType_HEIGHT , N )
# Skipping MacroDefinition: AI_MATKEY_UVWSRC_SHININESS ( N ) AI_MATKEY_UVWSRC ( aiTextureType_SHININESS , N )
# Skipping MacroDefinition: AI_MATKEY_UVWSRC_OPACITY ( N ) AI_MATKEY_UVWSRC ( aiTextureType_OPACITY , N )
# Skipping MacroDefinition: AI_MATKEY_UVWSRC_DISPLACEMENT ( N ) AI_MATKEY_UVWSRC ( aiTextureType_DISPLACEMENT , N )
# Skipping MacroDefinition: AI_MATKEY_UVWSRC_LIGHTMAP ( N ) AI_MATKEY_UVWSRC ( aiTextureType_LIGHTMAP , N )
# Skipping MacroDefinition: AI_MATKEY_UVWSRC_REFLECTION ( N ) AI_MATKEY_UVWSRC ( aiTextureType_REFLECTION , N )
# Skipping MacroDefinition: AI_MATKEY_TEXOP ( type , N ) _AI_MATKEY_TEXOP_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_TEXOP_DIFFUSE ( N ) AI_MATKEY_TEXOP ( aiTextureType_DIFFUSE , N )
# Skipping MacroDefinition: AI_MATKEY_TEXOP_SPECULAR ( N ) AI_MATKEY_TEXOP ( aiTextureType_SPECULAR , N )
# Skipping MacroDefinition: AI_MATKEY_TEXOP_AMBIENT ( N ) AI_MATKEY_TEXOP ( aiTextureType_AMBIENT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXOP_EMISSIVE ( N ) AI_MATKEY_TEXOP ( aiTextureType_EMISSIVE , N )
# Skipping MacroDefinition: AI_MATKEY_TEXOP_NORMALS ( N ) AI_MATKEY_TEXOP ( aiTextureType_NORMALS , N )
# Skipping MacroDefinition: AI_MATKEY_TEXOP_HEIGHT ( N ) AI_MATKEY_TEXOP ( aiTextureType_HEIGHT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXOP_SHININESS ( N ) AI_MATKEY_TEXOP ( aiTextureType_SHININESS , N )
# Skipping MacroDefinition: AI_MATKEY_TEXOP_OPACITY ( N ) AI_MATKEY_TEXOP ( aiTextureType_OPACITY , N )
# Skipping MacroDefinition: AI_MATKEY_TEXOP_DISPLACEMENT ( N ) AI_MATKEY_TEXOP ( aiTextureType_DISPLACEMENT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXOP_LIGHTMAP ( N ) AI_MATKEY_TEXOP ( aiTextureType_LIGHTMAP , N )
# Skipping MacroDefinition: AI_MATKEY_TEXOP_REFLECTION ( N ) AI_MATKEY_TEXOP ( aiTextureType_REFLECTION , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPING ( type , N ) _AI_MATKEY_MAPPING_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_MAPPING_DIFFUSE ( N ) AI_MATKEY_MAPPING ( aiTextureType_DIFFUSE , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPING_SPECULAR ( N ) AI_MATKEY_MAPPING ( aiTextureType_SPECULAR , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPING_AMBIENT ( N ) AI_MATKEY_MAPPING ( aiTextureType_AMBIENT , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPING_EMISSIVE ( N ) AI_MATKEY_MAPPING ( aiTextureType_EMISSIVE , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPING_NORMALS ( N ) AI_MATKEY_MAPPING ( aiTextureType_NORMALS , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPING_HEIGHT ( N ) AI_MATKEY_MAPPING ( aiTextureType_HEIGHT , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPING_SHININESS ( N ) AI_MATKEY_MAPPING ( aiTextureType_SHININESS , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPING_OPACITY ( N ) AI_MATKEY_MAPPING ( aiTextureType_OPACITY , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPING_DISPLACEMENT ( N ) AI_MATKEY_MAPPING ( aiTextureType_DISPLACEMENT , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPING_LIGHTMAP ( N ) AI_MATKEY_MAPPING ( aiTextureType_LIGHTMAP , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPING_REFLECTION ( N ) AI_MATKEY_MAPPING ( aiTextureType_REFLECTION , N )
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND ( type , N ) _AI_MATKEY_TEXBLEND_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND_DIFFUSE ( N ) AI_MATKEY_TEXBLEND ( aiTextureType_DIFFUSE , N )
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND_SPECULAR ( N ) AI_MATKEY_TEXBLEND ( aiTextureType_SPECULAR , N )
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND_AMBIENT ( N ) AI_MATKEY_TEXBLEND ( aiTextureType_AMBIENT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND_EMISSIVE ( N ) AI_MATKEY_TEXBLEND ( aiTextureType_EMISSIVE , N )
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND_NORMALS ( N ) AI_MATKEY_TEXBLEND ( aiTextureType_NORMALS , N )
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND_HEIGHT ( N ) AI_MATKEY_TEXBLEND ( aiTextureType_HEIGHT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND_SHININESS ( N ) AI_MATKEY_TEXBLEND ( aiTextureType_SHININESS , N )
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND_OPACITY ( N ) AI_MATKEY_TEXBLEND ( aiTextureType_OPACITY , N )
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND_DISPLACEMENT ( N ) AI_MATKEY_TEXBLEND ( aiTextureType_DISPLACEMENT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND_LIGHTMAP ( N ) AI_MATKEY_TEXBLEND ( aiTextureType_LIGHTMAP , N )
# Skipping MacroDefinition: AI_MATKEY_TEXBLEND_REFLECTION ( N ) AI_MATKEY_TEXBLEND ( aiTextureType_REFLECTION , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U ( type , N ) _AI_MATKEY_MAPPINGMODE_U_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U_DIFFUSE ( N ) AI_MATKEY_MAPPINGMODE_U ( aiTextureType_DIFFUSE , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U_SPECULAR ( N ) AI_MATKEY_MAPPINGMODE_U ( aiTextureType_SPECULAR , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U_AMBIENT ( N ) AI_MATKEY_MAPPINGMODE_U ( aiTextureType_AMBIENT , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U_EMISSIVE ( N ) AI_MATKEY_MAPPINGMODE_U ( aiTextureType_EMISSIVE , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U_NORMALS ( N ) AI_MATKEY_MAPPINGMODE_U ( aiTextureType_NORMALS , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U_HEIGHT ( N ) AI_MATKEY_MAPPINGMODE_U ( aiTextureType_HEIGHT , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U_SHININESS ( N ) AI_MATKEY_MAPPINGMODE_U ( aiTextureType_SHININESS , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U_OPACITY ( N ) AI_MATKEY_MAPPINGMODE_U ( aiTextureType_OPACITY , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U_DISPLACEMENT ( N ) AI_MATKEY_MAPPINGMODE_U ( aiTextureType_DISPLACEMENT , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U_LIGHTMAP ( N ) AI_MATKEY_MAPPINGMODE_U ( aiTextureType_LIGHTMAP , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_U_REFLECTION ( N ) AI_MATKEY_MAPPINGMODE_U ( aiTextureType_REFLECTION , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V ( type , N ) _AI_MATKEY_MAPPINGMODE_V_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V_DIFFUSE ( N ) AI_MATKEY_MAPPINGMODE_V ( aiTextureType_DIFFUSE , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V_SPECULAR ( N ) AI_MATKEY_MAPPINGMODE_V ( aiTextureType_SPECULAR , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V_AMBIENT ( N ) AI_MATKEY_MAPPINGMODE_V ( aiTextureType_AMBIENT , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V_EMISSIVE ( N ) AI_MATKEY_MAPPINGMODE_V ( aiTextureType_EMISSIVE , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V_NORMALS ( N ) AI_MATKEY_MAPPINGMODE_V ( aiTextureType_NORMALS , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V_HEIGHT ( N ) AI_MATKEY_MAPPINGMODE_V ( aiTextureType_HEIGHT , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V_SHININESS ( N ) AI_MATKEY_MAPPINGMODE_V ( aiTextureType_SHININESS , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V_OPACITY ( N ) AI_MATKEY_MAPPINGMODE_V ( aiTextureType_OPACITY , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V_DISPLACEMENT ( N ) AI_MATKEY_MAPPINGMODE_V ( aiTextureType_DISPLACEMENT , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V_LIGHTMAP ( N ) AI_MATKEY_MAPPINGMODE_V ( aiTextureType_LIGHTMAP , N )
# Skipping MacroDefinition: AI_MATKEY_MAPPINGMODE_V_REFLECTION ( N ) AI_MATKEY_MAPPINGMODE_V ( aiTextureType_REFLECTION , N )
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS ( type , N ) _AI_MATKEY_TEXMAP_AXIS_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS_DIFFUSE ( N ) AI_MATKEY_TEXMAP_AXIS ( aiTextureType_DIFFUSE , N )
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS_SPECULAR ( N ) AI_MATKEY_TEXMAP_AXIS ( aiTextureType_SPECULAR , N )
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS_AMBIENT ( N ) AI_MATKEY_TEXMAP_AXIS ( aiTextureType_AMBIENT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS_EMISSIVE ( N ) AI_MATKEY_TEXMAP_AXIS ( aiTextureType_EMISSIVE , N )
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS_NORMALS ( N ) AI_MATKEY_TEXMAP_AXIS ( aiTextureType_NORMALS , N )
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS_HEIGHT ( N ) AI_MATKEY_TEXMAP_AXIS ( aiTextureType_HEIGHT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS_SHININESS ( N ) AI_MATKEY_TEXMAP_AXIS ( aiTextureType_SHININESS , N )
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS_OPACITY ( N ) AI_MATKEY_TEXMAP_AXIS ( aiTextureType_OPACITY , N )
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS_DISPLACEMENT ( N ) AI_MATKEY_TEXMAP_AXIS ( aiTextureType_DISPLACEMENT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS_LIGHTMAP ( N ) AI_MATKEY_TEXMAP_AXIS ( aiTextureType_LIGHTMAP , N )
# Skipping MacroDefinition: AI_MATKEY_TEXMAP_AXIS_REFLECTION ( N ) AI_MATKEY_TEXMAP_AXIS ( aiTextureType_REFLECTION , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM ( type , N ) _AI_MATKEY_UVTRANSFORM_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_DIFFUSE ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_DIFFUSE , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_SPECULAR ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_SPECULAR , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_AMBIENT ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_AMBIENT , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_EMISSIVE ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_EMISSIVE , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_NORMALS ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_NORMALS , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_HEIGHT ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_HEIGHT , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_SHININESS ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_SHININESS , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_OPACITY ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_OPACITY , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_DISPLACEMENT ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_DISPLACEMENT , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_LIGHTMAP ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_LIGHTMAP , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_REFLECTION ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_REFLECTION , N )
# Skipping MacroDefinition: AI_MATKEY_UVTRANSFORM_UNKNOWN ( N ) AI_MATKEY_UVTRANSFORM ( aiTextureType_UNKNOWN , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS ( type , N ) _AI_MATKEY_TEXFLAGS_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_DIFFUSE ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_DIFFUSE , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_SPECULAR ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_SPECULAR , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_AMBIENT ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_AMBIENT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_EMISSIVE ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_EMISSIVE , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_NORMALS ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_NORMALS , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_HEIGHT ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_HEIGHT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_SHININESS ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_SHININESS , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_OPACITY ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_OPACITY , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_DISPLACEMENT ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_DISPLACEMENT , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_LIGHTMAP ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_LIGHTMAP , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_REFLECTION ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_REFLECTION , N )
# Skipping MacroDefinition: AI_MATKEY_TEXFLAGS_UNKNOWN ( N ) AI_MATKEY_TEXFLAGS ( aiTextureType_UNKNOWN , N )
# Skipping MacroDefinition: aiGetMaterialFloat ( pMat , type , index , pKey , pOut ) aiGetMaterialFloatArray ( pMat , type , index , pKey , pOut , NULL )
# Skipping MacroDefinition: aiGetMaterialInteger ( pMat , type , index , pKey , pOut ) aiGetMaterialIntegerArray ( pMat , type , index , pKey , pOut , NULL )

@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 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

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

const AI_MAX_FACE_INDICES = Float32(0x07ff)
const AI_MAX_BONE_WEIGHTS = Float32(0x07ffffff)
const AI_MAX_VERTICES = Float32(0x07ffffff)
const AI_MAX_FACES = Float32(0x07ffffff)
const AI_MAX_NUMBER_OF_COLOR_SETS = 0x08
const AI_MAX_NUMBER_OF_TEXTURECOORDS = 0x08

# Skipping MacroDefinition: AI_PRIMITIVE_TYPE_FOR_N_INDICES ( n ) ( ( n ) > 3 ? aiPrimitiveType_POLYGON : ( aiPrimitiveType ) ( 1u << ( ( n ) - 1 ) ) )

@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 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_AIMETADATA = 7
    AI_META_MAX = 8
    FORCE_32BIT = 9
end

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

# Skipping MacroDefinition: AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR "$mat.gltf.pbrMetallicRoughness.baseColorFactor" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_TEXTURE aiTextureType_DIFFUSE , 1
# Skipping MacroDefinition: AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN , 0
# Skipping MacroDefinition: AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_GLTF_UNLIT "$mat.gltf.unlit" , 0 , 0
# Skipping MacroDefinition: AI_MATKEY_GLTF_TEXTURE_TEXCOORD ( type , N ) _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_GLTF_MAPPINGNAME ( type , N ) _AI_MATKEY_GLTF_MAPPINGNAME_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_GLTF_MAPPINGID ( type , N ) _AI_MATKEY_GLTF_MAPPINGID_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_GLTF_MAPPINGFILTER_MAG ( type , N ) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_GLTF_MAPPINGFILTER_MIN ( type , N ) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_GLTF_TEXTURE_SCALE ( type , N ) _AI_MATKEY_GLTF_SCALE_BASE , type , N
# Skipping MacroDefinition: AI_MATKEY_GLTF_TEXTURE_STRENGTH ( type , N ) _AI_MATKEY_GLTF_STRENGTH_BASE , type , N

@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_PopulateArmatureData = 16384
    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 = 2147483648
end

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

struct _IEEESingle
    Float::Cfloat
end

struct _IEEEDouble
    Double::Cdouble
end

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 AI_EMBEDDED_TEXNAME_PREFIX = "*"

# Skipping MacroDefinition: AI_MAKE_EMBEDDED_TEXNAME ( _n_ ) AI_EMBEDDED_TEXNAME_PREFIX # _n_

const HINTMAXTEXTURELEN = 9
const MAXLEN = 1024

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

const AI_SUCCESS = aiReturn_SUCCESS
const AI_FAILURE = aiReturn_FAILURE
const AI_OUTOFMEMORY = aiReturn_OUTOFMEMORY

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

const DLS_FILE = aiDefaultLogStream_FILE
const DLS_STDOUT = aiDefaultLogStream_STDOUT
const DLS_STDERR = aiDefaultLogStream_STDERR
const DLS_DEBUGGER = aiDefaultLogStream_DEBUGGER
const ai_int32 = Int32

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

struct aiRay
    pos::aiVector3D
    dir::aiVector3D
end

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

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

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
const PRINTF_INT64_MODIFIER = "l"
const PRINTF_INT32_MODIFIER = ""
const PRINTF_INT16_MODIFIER = "h"
const PRINTF_INTMAX_MODIFIER = PRINTF_INT64_MODIFIER
const PRINTF_INT64_HEX_WIDTH = "16"
const PRINTF_UINT64_HEX_WIDTH = "16"
const PRINTF_INT32_HEX_WIDTH = "8"
const PRINTF_UINT32_HEX_WIDTH = "8"
const PRINTF_INT16_HEX_WIDTH = "4"
const PRINTF_UINT16_HEX_WIDTH = "4"
const PRINTF_INT8_HEX_WIDTH = "2"
const PRINTF_UINT8_HEX_WIDTH = "2"
const PRINTF_INT64_DEC_WIDTH = "19"
const PRINTF_UINT64_DEC_WIDTH = "20"
const PRINTF_INT32_DEC_WIDTH = "10"
const PRINTF_UINT32_DEC_WIDTH = "10"
const PRINTF_INT16_DEC_WIDTH = "5"
const PRINTF_UINT16_DEC_WIDTH = "5"
const PRINTF_INT8_DEC_WIDTH = "3"
const PRINTF_UINT8_DEC_WIDTH = "3"
const PRINTF_INTMAX_HEX_WIDTH = PRINTF_UINT64_HEX_WIDTH
const PRINTF_UINTMAX_HEX_WIDTH = PRINTF_UINT64_HEX_WIDTH
const PRINTF_INTMAX_DEC_WIDTH = PRINTF_UINT64_DEC_WIDTH
const PRINTF_UINTMAX_DEC_WIDTH = PRINTF_UINT64_DEC_WIDTH

# Skipping MacroDefinition: PACK_STRUCT __attribute__ ( ( __packed__ ) )


text:
using QuantumCumulants
using Test
using OrdinaryDiffEq, ModelingToolkit

@testset "higher-order" begin

# Parameters
tspan = range(0.0,10.0,length=101)
ω = range(-2pi,2pi,length=201)

# Define parameters
@cnumbers Δ g γ κ ν

# Define hilbert space
hf = FockSpace(:cavity)
ha = NLevelSpace(:atom,(:g,:e))
h = hf ⊗ ha

# Define the fundamental operators
a = Destroy(h,:a)
s = Transition(h,:σ,:g,:e)

# Hamiltonian
H = Δ*a'*a + g*(a'*s + a*s')

# Collapse operators
J = [a,s,s']
rates = [κ,γ,ν]

# Custom filter function -- include only phase-invaraint terms
ϕ(x) = 0
ϕ(::Destroy) = -1
ϕ(::Create) = 1
function ϕ(t::Transition)
    if (t.i==:e && t.j==:g)
        1
    elseif (t.i==:g && t.j==:e)
        -1
    else
        0
    end
end
ϕ(avg::Average) = ϕ(avg.arguments[1])
function ϕ(t::QuantumCumulants.QMul)
    p = 0
    for arg in t.args_nc
        p += ϕ(arg)
    end
    return p
end
phase_invariant(x) = iszero(ϕ(x))

# Derive equations
he_n = meanfield(a'*a,H,J;rates=rates)

## Fourth order
he4 = complete(he_n;order=4,filter_func=phase_invariant)

# Numerical solution
ps = (Δ, g, γ, κ, ν)
p0 = (0.5, 1.5, 0.25, 1, 4)
sys4 = ODESystem(he4)
u0 = zeros(ComplexF64, length(he4))
prob4 = ODEProblem(sys4,u0,(0.0,tspan[end]),ps .=> p0)
sol4 = solve(prob4,RK4())

n4 = real.(getindex.(sol4.(tspan), 1))

# Correlation function and spectrum
c4 = CorrelationFunction(a', a, he4; steady_state=true, filter_func=phase_invariant)
S4 = Spectrum(c4,ps)
s4 = S4(ω,sol4.u[end],p0)

## Sixth order
he6 = complete(he_n;order=6,filter_func=phase_invariant)

# Numerical solution
ps = (Δ, g, γ, κ, ν)
p0 = (0.5, 1.5, 0.25, 1, 4)
sys6 = ODESystem(he6)
u0 = zeros(ComplexF64, length(he6))
prob6 = ODEProblem(sys6,u0,(0.0,tspan[end]),ps .=> p0)
sol6 = solve(prob6,RK4())

n6 = real.(getindex.(sol6.(tspan), 1))

# Correlation function and spectrum
c6 = CorrelationFunction(a', a, he6; steady_state=true, filter_func=phase_invariant)
S6 = Spectrum(c6,ps)
s6 = S6(ω,sol6.u[end],p0)

## Test
@test maximum(abs.(n6 .- n4)) < 0.05
@test maximum(abs.(s6 .- s4)) < 0.2

end # testset


text:
module Arbitrary

using Base.Iterators
using Random

using IterTools

export arbitrary
export Generate
export ArbState
export Small
export Fun, fun_isequal

# TODO: Create a SimpleTrait "Arbitrary"

# Create an iterator from a stateful function
struct Generate{T}
    fun::Function
end

Base.IteratorEltype(::Type{Generate{T}}) where {T} = Base.HasEltype()
Base.IteratorSize(::Type{Generate{T}}) where {T} = Base.IsInfinite()
Base.eltype(::Type{Generate{T}}) where {T} = T
Base.iterate(gen::Generate{T}, state::Nothing = nothing) where {T} =
    (gen.fun()::T, nothing)

# Internal state for arbitrary iterators
mutable struct ArbState
    rng::AbstractRNG
end

# Provide a default state
arbitrary(::Type{T}) where {T} = arbitrary(T, ArbState(MersenneTwister()))
arbitrary(::Type{T}, seed::UInt) where {T} =
    arbitrary(T, ArbState(MersenneTwister(seed)))

# Produce arbitrary values based on an RNG
random_arbitrary(::Type{T}, ast::ArbState) where {T} =
    Generate{T}(() -> rand(ast.rng, T))
random_arbitrary(r::AbstractRange{T}, ast::ArbState) where {T} =
    Generate{T}(() -> rand(ast.rng, r))

# Methods for particular types
arbitrary(::Type{Nothing}, ast::ArbState) = repeated(nothing)

arbitrary(::Type{Bool}, ast::ArbState) = random_arbitrary(Bool, ast)

arbitrary(::Type{Char}, ast::ArbState) =
    flatten([Char['a', 'b', 'c', 'A', 'B', 'C', '0', '1', '2',
                  '\'', '"', '`', '\\', '/',
                  ' ', '\t', '\r', '\n',
                  '\0'],
             random_arbitrary(Char, ast)])

arbitrary(::Type{S}, ast::ArbState) where {S<:Signed} =
    flatten([S[0, 1, 2, 3, -1, -2, 10, 100, -10,
               typemax(S), typemax(S)-1, typemin(S), typemin(S)+1],
             random_arbitrary(S, ast)])

arbitrary(::Type{U}, ast::ArbState) where {U<:Unsigned} =
    flatten([U[0, 1, 2, 3, 10, 100, typemax(U), typemax(U)-1],
             random_arbitrary(U, ast)])

const Floating = Union{Float16, Float32, Float64}
arbitrary(::Type{F}, ast::ArbState) where {F<:Floating} =
    flatten([F[0, 1, 2, 3, -1, -2, 10, 100, -10,
               1//2, 1//3, -1//2, 1//10, 1//100, -1//10,
               F(-0.0), F(Inf), F(-Inf), eps(F), 1+eps(F), 1-eps(F),
               F(NaN)],
             random_arbitrary(F, ast)])

arbitrary(::Type{BigInt}, ast::ArbState) =
    flatten([BigInt[0, 1, 2, 3, -1, -2, 10, 100, -10,
                    big(10)^10, big(10)^100, -big(10)^10],
             imap(big, random_arbitrary(Int, ast))])

arbitrary(::Type{BigFloat}, ast::ArbState) =
    flatten([BigFloat[0, 1, 2, 3, -1, -2, 10, 100, -10,
                      1//2, 1//3, -1//2, 1//10, 1//100, -1//10,
                      big(10)^10, big(10)^100, big(10)^1000, -big(10)^10,
                      big(10)^-10, big(10)^-100, big(10)^-1000, -big(10)^-10],
             imap(big, random_arbitrary(Float64, ast))])

const BigRational = Rational{BigInt}
function mkrat(arb::Iterators.Stateful)::BigRational
    enum = big(popfirst!(arb)::Int)
    denom = big(0)
    while denom == 0
        denom = big(popfirst!(arb)::Int)
    end
    BigRational(enum, denom)
end
arbitrary(::Type{BigRational}, ast::ArbState) =
    flatten([BigRational[0, 1, 2, 3, -1, -2, 10, 100, -10,
                         1//2, 1//3, -1//2, 1//10, 1//100, -1//10,
                         big(10)^10, big(10)^100, -big(10)^10,
                         1//big(10)^10, 1//big(10)^100, -1//big(10)^10],
             Generate{BigRational}(
                 let iter = Iterators.Stateful(random_arbitrary(Int, ast))
                     () -> mkrat(iter)
                 end)])

struct Small{T}
    value::T
end
Base.getindex(s::Small{T}) where {T} = s.value

arbitrary(::Type{Small{U}}, ast::ArbState) where {U <: Unsigned} =
    imap(Small{U}, flatten([U[0, 1, 2, 3, 10, 100, 1000],
                            random_arbitrary(U(0):U(1000), ast)]))

arbitrary(::Type{Ref{T}}, ast::ArbState) where {T} =
    imap(x -> Ref{T}(x), arbitrary(T, ast))

arbitrary(::Type{Tuple{}}, ast::ArbState) =
    repeated(Tuple{}())

arbitrary(::Type{Tuple{T}}, ast::ArbState) where {T} =
    imap(x -> Tuple{T}((x,)), arbitrary(T, ast))

arbitrary(::Type{Tuple{T1, T2}}, ast::ArbState) where {T1, T2} =
    imap((x, y) -> Tuple{T1, T2}((x, y)),
         arbitrary(T1, ast), arbitrary(T2, ast))

@generated function arbitrary(::Type{T}, ast::ArbState) where {T <: Tuple}
    N = fieldcount(T)
    @assert N > 2
    quote
        zip($((:(arbitrary($(fieldtype(T, i)), ast)) for i in 1:N)...))
    end
end

arbitrary(::Type{Array{T, 0}}, ast::ArbState) where {T} =
    imap(x -> fill(x, ()), arbitrary(T, ast))

function arbitrary(::Type{Array{T, 1}}, ast::ArbState) where {T}
    lengths = Iterators.Stateful(arbitrary(Small{UInt}, ast))
    elems = Iterators.Stateful(arbitrary(T, ast))
    Generate{Array{T, 1}}(
        () -> begin
                  len = popfirst!(lengths)
                  xs = Array{T, 1}(undef, len[] % 100)
                  for i in eachindex(xs)
                      xs[i] = popfirst!(elems)
                  end
                  xs
              end)
end

function arbitrary(::Type{Array{T, 2}}, ast::ArbState) where {T}
    lengths =
        Iterators.Stateful(arbitrary(Tuple{Small{UInt}, Small{UInt}}, ast))
    elems = Iterators.Stateful(arbitrary(T, ast))
    Generate{Array{T, 2}}(
        () -> begin
                  len1, len2 = popfirst!(lengths)
                  xs = Array{T, 2}(undef, len1[] % 10, len2[] % 10)
                  for i in eachindex(xs)
                      xs[i] = popfirst!(elems)
                  end
                  xs
              end)
end

mutable struct Fun{T, R}
    arb
    dict::Dict{T, R}
    function Fun{T, R}(arb) where {T, R}
        new{T, R}(Iterators.Stateful(arb), Dict{T, R}())
    end
end

function arbitrary(::Type{Fun{T, R}}, ast::ArbState) where {T, R}
    # TODO: Use different ArbStates for different functions
    Generate{Fun{T, R}}(() -> Fun{T, R}(arbitrary(R, ast)))
end

struct NotFound end
function (f::Fun{T,R})(x::T)::R where {T, R}
    r = get(f.dict, x, NotFound())
    r !== NotFound() && return r
    f.dict[x] = popfirst!(f.arb)
end

function fun_isequal(::Type{T}, f, g) where {T}
    # T = common(argtype(f), argtype(g))
    xs = collect(take(arbitrary(T), 100))
    all(isequal(f(x), g(x)) for x in xs)
end

end


text:
using Random, Test
using ModelStatisticsLH

## ---------  Setup

# User defined struct to store
mutable struct TestStruct
    x
    y
    z
end

Base.size(TestStruct) = ();
Base.length(TestStruct) = 1;
Base.isequal(t1 :: TestStruct, t2 :: TestStruct) =
    (t1.x == t2.x) && (t1.y == t2.y) && (t1.z == t2.z);

function constructors_test()
    rng = MersenneTwister(434);
    @testset "Constructors" begin
        T = (:x, :y);
        ms = ModelStats{T}();
        @test n_vars(ms) == 0

        mMeta = Dict{Symbol, Any}([:test => true]);
        ms = ModelStats{T}(mMeta);
        @test n_vars(ms) == 0
        @test get_meta(ms, :test) == true

        vInfoV = make_test_var_infos(rng);
        nVars = length(vInfoV);
        ms = ModelStats{T}(mMeta, vInfoV);
        @test n_vars(ms) == nVars

        # Vector of VarInfo as input
        viV = Vector{VarInfo}();
        for (vName, vi) in vInfoV
            push!(viV, vi);
        end
        ms = ModelStats{T}(mMeta, viV);
        @test n_vars(ms) == nVars
    end
end

function retrieve_test()
    rng = MersenneTwister(434);
    @testset "Retrieve" begin
        nVars = 6;
        ms = make_test_model_stats(:test, nVars, rng);
        @test nVars == n_vars(ms)
        varNames = var_names(ms);
        @test length(varNames) == nVars

        for varName in varNames
            @test has_variable(ms, varName)
            vm = var_meta(ms, varName);
            @test eltype(ms, varName) == eltype(vm)
            @test var_name(vm) == varName
            valueV = getproperty(ms, varName);
            value2V = get_values(ms, varName);
            @test valueV == value2V;
            @test check_var(vm, valueV; silent = false);

            # Set values
            value3V = make_test_values(vm, rng);
            @test size(value3V) == size(valueV)
            @test check_var(vm, value3V; silent = false);
            set_values!(ms, varName, value3V);
            valueV = get_values(ms, varName);
            @test isequal(valueV, value3V);

            # Test dot notation
            if varName == :var1
                valueV = get_values(ms, varName);
                value2V = ms.var1;
                @test isequal(valueV, value2V);
                T = eltype(valueV);
                value3V = value2V .+ one(T);
                ms.var1 = value3V;
                @test ms.var1 == value3V
            end
        end
        # @test validate_stats(ms)

        # tbM = data_table(ms);
        # @test isa(tbM, Matrix{String})
        # @test isequal(tbM, ["g1" "1.0" "2" "3.0" "4"; "g2" "3.5" "4" "5.5" "6"; "g3" "6.0" "7" "8.0" "9"])
        # println(tbM);

        varName = :new1;
        @test !has_variable(ms, varName)
        @test get_values(ms, varName; defaultValue = 1) == 1
        newValueV = 12 .+ (1 : 4);
        vInfo = VarInfo(:new1, "new variable", eltype(newValueV);
            lb = 10, ub = 20, size = size(newValueV));
        @test check_var_info(vInfo; silent = false);
        add_variable!(ms, vInfo, newValueV);
        @test n_vars(ms) == nVars + 1
        @test has_variable(ms, varName)
        valueV = get_values(ms, varName)
        @test isequal(valueV, newValueV)
        # @test isequal(get_value(ms, varName, 2), valueV[2])

        # varName = :new2
        # add_variable!(ms, (varName, 7, 43, "Description $varName"), newValueV);
        # valueV = get_values(ms, varName);
        # @test isequal(valueV, newValueV)

        delete_variable!(ms, varName);
        @test !has_variable(ms, varName)
        @test n_vars(ms) == nVars
    end
end

function getindex_test()
    rng = MersenneTwister(434);
	@testset "getindex and setindex" begin
        nVars = 3;
        ms = make_test_model_stats(:test, nVars, rng);

        varName = :new1;
        newValueV = rand(rng, 4,3,2);
        vInfo = VarInfo(varName, string(varName), eltype(newValueV);
            size = size(newValueV));
        @test check_var_info(vInfo; silent = false);
        add_variable!(ms, vInfo, newValueV);
        @test ms.new1[2:3, 1:2, 1] == newValueV[2:3, 1:2, 1]

        ms.new1[3,2,2] = 0.2;
        @test ms.new1[3,2,2] == 0.2;
        ms.new1[2:3, 1:2, 1] .= 0.3;
        @test all(ms.new1[2:3, 1:2, 1] .== 0.3);
        x = rand(rng, 2, 2);
        ms.new1[2:3, 1:2, 1] .= x;
        @test all(ms.new1[2:3, 1:2, 1] .== x)
    end
end

function struct_test()
    rng = MersenneTwister(434);
    @testset "Arbitrary structs" begin
        nVars = 3;
        ms = make_test_model_stats(:test, nVars, rng);

        varName = :new1;
        newValueV = TestStruct(1, 2, 3);
        vInfo = VarInfo(varName, string(varName), TestStruct;
            size = size(newValueV));
        @test check_var_info(vInfo; silent = false);
        add_variable!(ms, vInfo, newValueV);
        @test ms.new1 == newValueV

        newValueV = TestStruct(4,5,6);
        ms.new1 = newValueV;
        @test ms.new1 == newValueV;

        varName = :new2;
        newValueV = [TestStruct(1,2,3), TestStruct(2,3,4)];
        vInfo = VarInfo(varName, string(varName), Vector{TestStruct};
            size = size(newValueV));
        @test check_var_info(vInfo; silent = false);
        add_variable!(ms, vInfo, newValueV);
        @test all(ms.new2 .== newValueV)
    end
end

@testset "ModelStats" begin
    constructors_test();
    retrieve_test();
    getindex_test();
    struct_test();
end

# ------------


text:
function subs(a::Number, ::Pair{Symbol, T}) where T <: Union{Int, Float64, Expr}
    return a
end

function subs(s::Symbol, arg::Pair{Symbol, T}) where T <: Union{Int, Float64, Expr}
    k, v = arg
    return s == k ? v : s
end

function subs(ex::Expr, arg::Pair{Symbol, T}) where T <: Union{Int, Float64, Expr}
    ne = copy(ex)
    for i=2:length(ne.args)
        ne.args[i] = subs(ne.args[i], arg)
    end
    return ne
end


text:
import LanguageServer: LanguageServerInstance, Document, Pkg
using LanguageServer, CSTParser, StaticLint, SymbolServer

server = LanguageServerInstance(IOBuffer(), IOBuffer(), true, dirname(Pkg.Types.Context().env.project_file), first(Base.DEPOT_PATH))
@async run(server)
t = time()
while server.symbol_server isa Nothing && time() - t < 60
    sleep(1)
end

server.runlinter = true
LanguageServer.process(LanguageServer.parse(LanguageServer.JSONRPC.Request, JSON.parse(init_request)), server)

function getresult(server)
    str = String(take!(server.pipe_out))
    JSON.parse(str[findfirst("{", str)[1]:end])["result"]["contents"]
end

testtext = """
module testmodule
struct testtype
    a
    b::Float64
    c::Vector{Float64}
end
function testfunction(a, b::Float64, c::testtype)
    return c
end
end
testmodule
"""
LanguageServer.process(LanguageServer.JSONRPC.Request{Val{Symbol("textDocument/didOpen")},LanguageServer.DidOpenTextDocumentParams}(0, LanguageServer.DidOpenTextDocumentParams(LanguageServer.TextDocumentItem("testdoc", "julia", 0, testtext))), server)

doc = server.documents[LanguageServer.URI2("testdoc")]
LanguageServer.parse_all(doc, server)

# clear init output
take!(server.pipe_out)

LanguageServer.process(LanguageServer.parse(LanguageServer.JSONRPC.Request, JSON.parse("""{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"testdoc"},"position":{"line":3,"character":11}}}""")), server)
res = getresult(server)

@test res["value"] == StaticLint.CoreTypes.Float64.doc

LanguageServer.process(LanguageServer.parse(LanguageServer.JSONRPC.Request, JSON.parse("""{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"testdoc"},"position":{"line":7,"character":12}}}""")), server)
res = getresult(server)
@test occursin(r"c::testtype", res["value"])

LanguageServer.process(LanguageServer.parse(LanguageServer.JSONRPC.Request, JSON.parse("""{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"testdoc"},"position":{"line":9,"character":1}}}""")), server)
res = getresult(server)
@test res["value"] == "Closes `ModuleH` expression."


text:
function covidPlot2(cases,death,pop,name)
p1 = plot()
hspan!(p1,[0,1e2], color  = :red, alpha   = 0.6, labels = false);
hspan!(p1,[0,1e1], color  = :white, alpha = 0.1, labels = false);
hspan!(p1,[0,1e0], color  = :white, alpha = 0.1, labels = false);
hspan!(p1,[0,1e-1], color = :white, alpha = 0.1, labels = false);
hspan!(p1,[0,1e-2], color = :white, alpha = 0.1, labels = false);
hspan!(p1,[0,1e-3], color = :white, alpha = 0.1, labels = false);
hspan!(p1,[0,1e-4], color = :white, alpha = 0.1, labels = false);
hspan!(p1,[0,1e-5], color = :white, alpha = 0.1, labels = false);
hspan!(p1,[0,1e-6], color = :white, alpha = 0.1, labels = false);
scatter!(1:size(cases)[2],
      100*cases[1,:]./pop,lab=name*" COVID Cases",
      scale=:log10,
      yticks = [1e-6,1e-5,1e-4,1e-3,1e-2,1e-1,1,1e1,1e2],
      yaxis="Percent of Country", xaxis="Days since Jan 22",
      marker =:o,
      color =:green)
scatter!(1:size(cases)[2],
      100*death[1,:]./pop,lab=name*" COVID Deaths",
      scale=:log10,
      yticks = [1e-6,1e-5,1e-4,1e-3,1e-2,1e-1,1,1e1,1e2],
      yaxis="Percent of Country", xaxis="Days since Jan 22",
      marker =:x,
      color =:black)
 plot!(xscale=:identity,xticks=0:100:500, legend=:bottomright)
 labelCases = cases[1,end];
 labelDeath = death[1,end];
 annotate!(size(cases)[2]+5, 200*cases[1,end]./pop, ha="left",va="bottom","$labelCases")
 annotate!(size(cases)[2]+5, 200*death[1,end]./pop, ha="left",va="bottom","$labelDeath")
 xlims!((0,500))
 ylims!((1e-6,100))
 png(p1,"Figures/UnitedStates/$name.png")
end


text:
"""
**AtiyahBott** is a module containing an implementation of the Atiyah-Bott residue formula in the Julia language.
The theory and the algorithm behind the package is described in the paper
"Effective computations of the Atiyah-Bott formula" by Giosuè Muratore and
Csaba Schneider (https://arxiv.org/pdf/2105.11183.pdf).

The colorations (useful to speed up the code) are up to projective spaces of dimension 29.
The full list is here: https://github.com/mgemath/Colorations/.
"""
module AtiyahBott

using Combinatorics
using LightGraphs
using ProgressMeter
using Downloads
using CodecZlib
using Nemo

const current_dir = @__DIR__

include("Marked.jl")
include("GraphFunctions.jl")
include("EquivariantClasses.jl")
include("Checks.jl")
include("Main.jl")

end # module


text:
function build_mps(m::NEOSMathProgModel)
    # Max width (8) for names in fixed MPS format
    # TODO: replace names by alpha-numeric
    #   to enable more variables and constraints.
    #   Although to be honest no one should be using
    #   this with that many constraints/variables
    @assert length(m.f) <= 9999999
    @assert length(m.rowub) <= 9999999

    mps = "NAME          NEOSMathProgModel\n"

    rowSense, _hasranged = extract_rowSense(m)

    mps = addROWS(m, mps, rowSense)
    mps = addCOLS(m, mps)
    mps = addRHS(m, mps, rowSense)
    if _hasranged
        mps = addRANGES(m, mps, rowSense)
    end
    mps = addBOUNDS(m, mps)
    mps = addSOS(m, mps)

    mps *= "ENDATA\n"

    if m.solver.gzipmodel
        return gzip(mps)
    else
        return mps
    end
end

function addROWS(m::NEOSMathProgModel, mps::ASCIIString, rowSense::Vector{Symbol})
    # Objective and constraint names
    mps *= "ROWS\n N  OBJ\n"

    for c in 1:m.nrow
        if rowSense[c] == :(<=)
            senseChar = 'L'
        elseif rowSense[c] == :(==)
            senseChar = 'E'
        elseif rowSense[c] == :(>=)
            senseChar = 'G'
        else
            senseChar = 'E'
        end
        mps *= " $senseChar  C$c\n"
    end
    mps
end

function extract_rowSense(m::NEOSMathProgModel)
    rowSense = Array(Symbol, length(m.rowub))
    _hasranged = false
    for r=1:m.nrow
    	if (m.rowlb[r] == -Inf && m.rowub[r] != Inf) || (m.rowlb[r] == typemin(eltype(m.rowlb)) && m.rowub[r] != typemax(eltype(m.rowub)))
    		rowSense[r] = :(<=) # LE constraint
    	elseif (m.rowlb[r] != -Inf && m.rowub[r] == Inf)  || (m.rowlb[r] != typemin(eltype(m.rowlb)) && m.rowub[r] == typemax(eltype(m.rowub)))
    		rowSense[r] = :(>=) # GE constraint
    	elseif m.rowlb[r] == m.rowub[r]
    		rowSense[r] = :(==) # Eq constraint
    	else
            rowSense[r] = :ranged
            _hasranged = true
    	end
    end
    rowSense, _hasranged
end

function addCOLS(m::NEOSMathProgModel, mps::ASCIIString)
    A = convert(SparseMatrixCSC{Float64, Int32}, m.A)

    _intgrpOPEN = false

    mps *= "COLUMNS\n"
    for col in 1:m.ncol
    	if m.colcat != :nothing
	        t = m.colcat[col]
	        if t == :SemiCont || t == :SemiInt
                throw(NEOSSolverError("The MPS file writer does not currently support semicontinuous or semi-integer variables"))
            end
	        if (t == :Bin || t == :Int) && !_intgrpOPEN
	            mps *= "    MARKER    'MARKER'                 'INTORG'\n"
	            _intgrpOPEN = true
	        elseif (t == :Cont || t == :Fixed) && _intgrpOPEN
	            mps *= "    MARKER    'MARKER'                 'INTEND'\n"
	            _intgrpOPEN = false
	        end
	    end
    	if abs(m.f[col]) > 1e-10 # Non-zeros
    		# Flip signs for maximisation
            mps *= "    V$(rpad(col, 7))  $(rpad("OBJ", 8))  $((m.sense==:Max?-1:1)*m.f[col])\n"
	    end
        if length(A.colptr) > col
            for ind in A.colptr[col]:(A.colptr[col+1]-1)
            	if abs(A.nzval[ind]) > 1e-10 # Non-zero
    	            mps *= "    V$(rpad(col, 7))  C$(rpad(A.rowval[ind], 7))  $(A.nzval[ind])\n"
    	        end
            end
        end
    end
    if _intgrpOPEN
        mps *= "    MARKER    'MARKER'                 'INTEND'\n"
    end

    return mps
end

function addRHS(m::NEOSMathProgModel, mps::ASCIIString, rowSense::Vector{Symbol})
    mps *= "RHS\n"
    for c in 1:m.nrow
        mps *= "    rhs       C$(rpad(c, 7))  $(rowSense[c] == :(<=)?m.rowub[c]:m.rowlb[c])\n"
    end
    mps
end

function addRANGES(m::NEOSMathProgModel, mps::ASCIIString, rowSense::Vector{Symbol})
    mps *= "RANGES\n"
    for r=1:m.nrow
        if rowSense[r] == :ranged
            mps *= "    rhs       C$(rpad(r, 7))  $(m.rowub[r] - m.rowlb[r])\n"
        end
    end
    mps
end

function addBOUNDS(m::NEOSMathProgModel, mps::ASCIIString)
    mps *= "BOUNDS\n"
    for col in 1:m.ncol
        if m.colub[col] == Inf
            if m.collb[col] == -Inf
                mps *= boundstring("FR", col)
                continue
            else
                mps *= boundstring("PL", col)
            end
        else
            mps *= boundstring("UP", col, m.colub[col])
        end
        if m.collb[col] == -Inf
            mps *= boundstring("MI", col)
        elseif m.collb[col] != 0
            mps *= boundstring("LO", col, m.collb[col])
        end
    end
    mps
end

function boundstring(ty::ASCIIString, vidx::Integer)
    @assert ty in ["FR", "MI", "PL"]
    " $ty BOUNDS    V$(rpad(vidx, 7))\n"
end
function boundstring(ty::ASCIIString, vidx::Integer, val)
    @assert ty in ["LO", "UP"]
    " $ty BOUNDS    V$(rpad(vidx, 7))  $(val)\n"
end

function addSOS(m::NEOSMathProgModel, mps::ASCIIString)
    for (n_sos, sos) in enumerate(m.sos)
        mps *= "SOS\n S$(sos.order) SOS$(n_sos)\n"
        for (i, v) in enumerate(sos.indices)
            mps *= "    V$(rpad(v, 7))  $(sos.weights[i])\n"
        end
    end
    mps
end

function gzip(s::ASCIIString)
    return "<base64>"*bytestring(encode(Base64, readbytes(s.data |> ZlibDeflateInputStream)))*"</base64>"
end


text:
"""Container for data parsed by PowerModels"""
struct PowerModelsData
    data::Dict{String, Any}
end

"""
Constructs PowerModelsData from a raw file.
Currently Supports MATPOWER and PSSE data files parsed by PowerModels.
"""
function PowerModelsData(file::Union{String, IO}; kwargs...)
    pm_dict = parse_file(file; kwargs...)
    pm_data = PowerModelsData(pm_dict)
    correct_pm_transformer_status!(pm_data)
    return pm_data
end

"""
Constructs a System from PowerModelsData.
Supports kwargs to supply formatters for different device types,
such as `bus_name_formatter` or `gen_name_formatter`.

# Examples
```julia
sys = System(
    pm_data, configpath = "ACTIVSg25k_validation.json",
    bus_name_formatter = x->string(x["name"]*"-"*string(x["index"])),
    load_name_formatter = x->strip(join(x["source_id"], "_"))
)
```
"""
function System(pm_data::PowerModelsData; kwargs...)
    runchecks = get(kwargs, :runchecks, true)
    data = pm_data.data
    if length(data["bus"]) < 1
        throw(DataFormatError("There are no buses in this file."))
    end

    @info "Constructing System from Power Models" data["name"] data["source_type"]

    sys = System(data["baseMVA"]; kwargs...)

    bus_number_to_bus = read_bus!(sys, data; kwargs...)
    read_loads!(sys, data, bus_number_to_bus; kwargs...)
    read_loadzones!(sys, data, bus_number_to_bus; kwargs...)
    read_gen!(sys, data, bus_number_to_bus; kwargs...)
    read_branch!(sys, data, bus_number_to_bus; kwargs...)
    read_shunt!(sys, data, bus_number_to_bus; kwargs...)
    read_dcline!(sys, data, bus_number_to_bus; kwargs...)
    if runchecks
        check!(sys)
    end
    return sys
end

function correct_pm_transformer_status!(pm_data::PowerModelsData)
    for (k, branch) in pm_data.data["branch"]
        if !branch["transformer"] &&
           pm_data.data["bus"][string(branch["f_bus"])]["base_kv"] !=
           pm_data.data["bus"][string(branch["t_bus"])]["base_kv"]
            branch["transformer"] = true
            @warn "Branch $k endpoints have different voltage levels, converting to transformer."
        end
    end
end

"""
Internal component name retreval from pm2ps_dict
"""
function _get_pm_dict_name(device_dict)
    return get(device_dict, "name", string(device_dict["index"]))
end

"""
Creates a PowerSystems.Bus from a PowerSystems bus dictionary
"""
function make_bus(bus_dict::Dict{String, Any})
    bus = Bus(
        bus_dict["number"],
        bus_dict["name"],
        bus_dict["bustype"],
        bus_dict["angle"],
        bus_dict["voltage"],
        bus_dict["voltagelimits"],
        bus_dict["basevoltage"],
        bus_dict["area"],
        bus_dict["zone"],
    )
    return bus
end

function make_bus(bus_name, bus_number, d, bus_types, area)
    bus = make_bus(Dict{String, Any}(
        "name" => bus_name,
        "number" => bus_number,
        "bustype" => bus_types[d["bus_type"]],
        "angle" => d["va"],
        "voltage" => d["vm"],
        "voltagelimits" => (min = d["vmin"], max = d["vmax"]),
        "basevoltage" => d["base_kv"],
        "area" => area,
        "zone" => nothing,
    ),)
    return bus
end

# "From http://www.pserc.cornell.edu/matpower/MATPOWER-manual.pdf Table B-1"
IS.@scoped_enum MatpowerBusType begin
    MATPOWER_PQ = 1
    MATPOWER_PV = 2
    MATPOWER_REF = 3
    MATPOWER_ISOLATED = 4
end

function Base.convert(::Type{BusTypes.BusType}, x::MatpowerBusTypes.MatpowerBusType)
    map = Dict(
        MatpowerBusTypes.MATPOWER_ISOLATED => BusTypes.ISOLATED,
        MatpowerBusTypes.MATPOWER_PQ => BusTypes.PQ,
        MatpowerBusTypes.MATPOWER_PV => BusTypes.PV,
        MatpowerBusTypes.MATPOWER_REF => BusTypes.REF,
    )
    return map[x]
end

# Disabling this because not all matpower files define areas even when bus definitions
# contain area references.
#function read_area!(sys::System, data; kwargs...)
#    if !haskey(data, "areas")
#        @info "There are no Areas in this file"
#        return
#    end
#
#    for (key, val) in data["areas"]
#        area = Area(string(val["col_1"]))
#        add_component!(sys, area; skip_validation = SKIP_PM_VALIDATION)
#    end
#end

function read_bus!(sys::System, data; kwargs...)
    @info "Reading bus data"
    bus_number_to_bus = Dict{Int, Bus}()

    bus_types = instances(MatpowerBusTypes.MatpowerBusType)
    bus_data = sort(collect(data["bus"]), by = x -> parse(Int64, x[1]))

    if isempty(bus_data)
        @error "No bus data found" # TODO : need for a model without a bus
    end

    _get_name = get(kwargs, :bus_name_formatter, _get_pm_dict_name)
    for (i, (d_key, d)) in enumerate(bus_data)
        # d id the data dict for each bus
        # d_key is bus key
        d["name"] = get(d, "name", string(d["bus_i"]))
        bus_name = _get_name(d)
        bus_number = Int(d["bus_i"])

        area_name = string(d["area"])
        area = get_component(Area, sys, area_name)
        if isnothing(area)
            area = Area(area_name)
            add_component!(sys, area; skip_validation = SKIP_PM_VALIDATION)
        end

        bus = make_bus(bus_name, bus_number, d, bus_types, area)
        bus_number_to_bus[bus.number] = bus

        add_component!(sys, bus; skip_validation = SKIP_PM_VALIDATION)
    end

    return bus_number_to_bus
end

function make_load(d, bus; kwargs...)
    _get_name = get(kwargs, :load_name_formatter, x -> strip(join(x["source_id"])))
    return PowerLoad(;
        name = _get_name(d),
        available = true,
        model = LoadModels.ConstantPower,
        bus = bus,
        activepower = d["pd"],
        reactivepower = d["qd"],
        maxactivepower = d["pd"],
        maxreactivepower = d["qd"],
    )
end

function read_loads!(sys::System, data, bus_number_to_bus::Dict{Int, Bus}; kwargs...)
    if !haskey(data, "load")
        @error "There are no loads in this file"
        return
    end

    for d_key in keys(data["load"])
        d = data["load"][d_key]
        if d["pd"] != 0.0
            bus = bus_number_to_bus[d["load_bus"]]
            load = make_load(d, bus; kwargs...)

            add_component!(sys, load; skip_validation = SKIP_PM_VALIDATION)
        end
    end
end

function make_loadzone(name, activepower, reactivepower; kwargs...)
    _get_name = get(kwargs, :loadzone_name_formatter, _get_pm_dict_name)
    return LoadZone(;
        name = name,
        maxactivepower = sum(activepower),
        maxreactivepower = sum(reactivepower),
    )
end

function read_loadzones!(sys::System, data, bus_number_to_bus::Dict{Int, Bus}; kwargs...)
    zones = Set{Int}()
    for (i, bus) in data["bus"]
        push!(zones, bus["zone"])
    end

    for zone in zones
        buses = [
            bus_number_to_bus[b["bus_i"]]
            for (b_key, b) in data["bus"] if b["zone"] == zone
        ]
        bus_names = Set{String}()
        for bus in buses
            push!(bus_names, get_name(bus))
        end

        active_power = Vector{Float64}()
        reactive_power = Vector{Float64}()

        for (key, load) in data["load"]
            load_bus = bus_number_to_bus[load["load_bus"]]
            if get_name(load_bus) in bus_names
                push!(active_power, load["pd"])
                push!(reactive_power, load["qd"])
            end
        end

        load_zone = make_loadzone(string(zone), active_power, reactive_power; kwargs...)
        for bus in buses
            set_load_zone!(bus, load_zone)
        end
        add_component!(sys, load_zone; skip_validation = SKIP_PM_VALIDATION)
    end
end

function make_hydro_gen(gen_name, d, bus, sys_mbase)
    ramp_agc = get(d, "ramp_agc", get(d, "ramp_10", get(d, "ramp_30", abs(d["pmax"]))))
    curtailcost = TwoPartCost(0.0, 0.0)

    return HydroEnergyReservoir(
        name = gen_name,
        available = Bool(d["gen_status"]),
        bus = bus,
        activepower = d["pg"],
        reactivepower = d["qg"],
        rating = calculate_rating(d["pmax"], d["qmax"]),
        primemover = convert(PrimeMovers.PrimeMover, d["type"]),
        activepowerlimits = (min = d["pmin"], max = d["pmax"]),
        reactivepowerlimits = (min = d["qmin"], max = d["qmax"]),
        ramplimits = (up = ramp_agc / d["mbase"], down = ramp_agc / d["mbase"]),
        timelimits = nothing,
        op_cost = curtailcost,
        basepower = d["mbase"] / sys_mbase,
        storage_capacity = 0.0, #TODO: Implement better Solution for this
        inflow = 0.0,
        initial_storage = 0.0,
    )
end

function make_renewable_dispatch(gen_name, d, bus, sys_mbase)
    cost = TwoPartCost(0.0, 0.0)
    generator = RenewableDispatch(;
        name = gen_name,
        available = Bool(d["gen_status"]),
        bus = bus,
        activepower = d["pg"],
        reactivepower = d["qg"],
        rating = float(d["pmax"]),
        primemover = convert(PrimeMovers.PrimeMover, d["type"]),
        reactivepowerlimits = (min = d["qmin"], max = d["qmax"]),
        powerfactor = 1.0,
        op_cost = cost,
        basepower = d["mbase"] / sys_mbase,
    )

    return generator
end

function make_renewable_fix(gen_name, d, bus, sys_mbase)
    generator = RenewableFix(;
        name = gen_name,
        available = Bool(d["gen_status"]),
        bus = bus,
        activepower = d["pg"],
        reactivepower = d["qg"],
        rating = float(d["pmax"]),
        primemover = convert(PrimeMovers.PrimeMover, d["type"]),
        powerfactor = 1.0,
        basepower = d["mbase"] / sys_mbase,
    )

    return generator
end

function make_generic_battery(gen_name, d, bus)
    error("Not implemented yet.")
end

"""
The polynomial term follows the convention that for an n-degree polynomial, at least n + 1 components are needed.
    c(p) = c_n*p^n+...+c_1p+c_0
    c_o is stored in the  field in of the Econ Struct
"""
function make_thermal_gen(gen_name::AbstractString, d::Dict, bus::Bus, sys_mbase::Number)
    if haskey(d, "model")
        model = GeneratorCostModels.GeneratorCostModel(d["model"])
        if model == GeneratorCostModels.PIECEWISE_LINEAR
            cost_component = d["cost"]
            power_p = [i for (ix, i) in enumerate(cost_component) if isodd(ix)]
            cost_p = [i for (ix, i) in enumerate(cost_component) if iseven(ix)]
            cost = [(p, c) for (p, c) in zip(cost_p, power_p)]
            fixed = max(
                0.0,
                cost[1][1] -
                (cost[2][1] - cost[1][1]) / (cost[2][2] - cost[1][2]) * cost[1][2],
            )
            cost = [(c[1] - fixed, c[2]) for c in cost]
        elseif model == GeneratorCostModels.POLYNOMIAL
            if d["ncost"] == 0
                cost = (0.0, 0.0)
                fixed = 0.0
            elseif d["ncost"] == 1
                cost = (0.0, 0.0)
                fixed = d["cost"][1]
            elseif d["ncost"] == 2
                cost = (0.0, d["cost"][1])
                fixed = d["cost"][2]
            elseif d["ncost"] == 3
                cost = (d["cost"][1], d["cost"][2])
                fixed = d["cost"][3]
            else
                throw(DataFormatError("invalid value for ncost: $(d["ncost"]). PowerSystems only supports polynomials up to second degree"))
            end
        end
        startup = d["startup"]
        shutdn = d["shutdown"]
    else
        @warn "Generator cost data not included for Generator: $gen_name"
        tmpcost = ThreePartCost(nothing)
        cost = tmpcost.variable
        fixed = tmpcost.fixed
        startup = tmpcost.startup
        shutdn = tmpcost.shutdn
    end

    # Ignoring due to  GitHub #148: ramp_agc isn't always present. This value may not be correct.
    ramp_lim = get(d, "ramp_10", get(d, "ramp_30", abs(d["pmax"])))

    op_cost =
        ThreePartCost(; variable = cost, fixed = fixed, startup = startup, shutdn = shutdn)

    thermal_gen = ThermalStandard(
        name = gen_name,
        status = Bool(d["gen_status"]),
        available = true,
        bus = bus,
        activepower = d["pg"],
        reactivepower = d["qg"],
        rating = sqrt(d["pmax"]^2 + d["qmax"]^2),
        primemover = convert(PrimeMovers.PrimeMover, d["type"]),
        fuel = convert(ThermalFuels.ThermalFuel, d["fuel"]),
        activepowerlimits = (min = d["pmin"], max = d["pmax"]),
        reactivepowerlimits = (min = d["qmin"], max = d["qmax"]),
        ramplimits = (up = ramp_lim / d["mbase"], down = ramp_lim / d["mbase"]),
        timelimits = nothing,
        op_cost = op_cost,
        basepower = d["mbase"] / sys_mbase,
    )

    return thermal_gen
end

"""
Transfer generators to ps_dict according to their classification
"""
function read_gen!(sys::System, data, bus_number_to_bus::Dict{Int, Bus}; kwargs...)
    @info "Reading generator data"

    if !haskey(data, "gen")
        @error "There are no Generators in this file"
        return nothing
    end

    genmap_file = get(kwargs, :genmap_file, nothing)
    genmap = get_generator_mapping(genmap_file)
    sys_mbase = data["baseMVA"]

    for (name, pm_gen) in data["gen"]
        if haskey(kwargs, :gen_name_formatter)
            _get_name = kwargs[:gen_name_formatter]
        elseif haskey(pm_gen, "name")
            _get_name = _get_pm_dict_name
        elseif haskey(pm_gen, "source_id")
            _get_name =
                d -> strip(
                    string(d["source_id"][1]) *
                    "-" *
                    string(d["source_id"][2]) *
                    "-" *
                    string(d["index"]),
                )
        end

        gen_name = _get_name(pm_gen)

        bus = bus_number_to_bus[pm_gen["gen_bus"]]
        pm_gen["fuel"] = get(pm_gen, "fuel", "OTHER")
        pm_gen["type"] = get(pm_gen, "type", "OT")
        @debug "Found generator" gen_name bus pm_gen["fuel"] pm_gen["type"]

        gen_type = get_generator_type(pm_gen["fuel"], pm_gen["type"], genmap)
        if gen_type == ThermalStandard
            generator = make_thermal_gen(gen_name, pm_gen, bus, sys_mbase)
        elseif gen_type == HydroEnergyReservoir
            generator = make_hydro_gen(gen_name, pm_gen, bus, sys_mbase)
        elseif gen_type == RenewableDispatch
            generator = make_renewable_dispatch(gen_name, pm_gen, bus, sys_mbase)
        elseif gen_type == RenewableFix
            generator = make_renewable_fix(gen_name, pm_gen, bus, sys_mbase)
        elseif gen_type == GenericBattery
            @warn "Skipping GenericBattery"
            continue
            # TODO
            #generator = make_generic_battery(gen_name, pm_gen, bus)
        else
            @error "Skipping unsupported generator" gen_type
            continue
        end

        add_component!(sys, generator; skip_validation = SKIP_PM_VALIDATION)
    end
end

function make_branch(name, d, bus_f, bus_t)
    primary_shunt = d["b_fr"]
    alpha = d["shift"]
    branch_type = get_branch_type(d["tap"], alpha)

    if d["transformer"]
        if branch_type == Line
            throw(DataFormatError("Data is mismatched; this cannot be a line. $d"))
        elseif branch_type == Transformer2W
            value = make_transformer_2w(name, d, bus_f, bus_t)
        elseif branch_type == TapTransformer
            value = make_tap_transformer(name, d, bus_f, bus_t)
        elseif branch_type == PhaseShiftingTransformer
            value = make_phase_shifting_transformer(name, d, bus_f, bus_t, alpha)
        else
            error("Unsupported branch type $branch_type")
        end
    else
        # The get_branch_type() logic doesn't work for this data.
        # tap can be 1.0 for this data.
        value = make_line(name, d, bus_f, bus_t)
    end

    return value
end

function make_line(name, d, bus_f, bus_t)
    pf = get(d, "pf", 0.0)
    qf = get(d, "qf", 0.0)

    return Line(;
        name = name,
        available = d["br_status"] == 1,
        activepower_flow = pf,
        reactivepower_flow = qf,
        arc = Arc(bus_f, bus_t),
        r = d["br_r"],
        x = d["br_x"],
        b = (from = d["b_fr"], to = d["b_to"]),
        rate = d["rate_a"],
        anglelimits = (min = d["angmin"], max = d["angmax"]),
    )
end

function make_transformer_2w(name, d, bus_f, bus_t)
    pf = get(d, "pf", 0.0)
    qf = get(d, "qf", 0.0)
    return Transformer2W(;
        name = name,
        available = d["br_status"] == 1,
        activepower_flow = pf,
        reactivepower_flow = qf,
        arc = Arc(bus_f, bus_t),
        r = d["br_r"],
        x = d["br_x"],
        primaryshunt = d["b_fr"],  # TODO: which b ??
        rate = d["rate_a"],
    )
end

function make_tap_transformer(name, d, bus_f, bus_t)
    pf = get(d, "pf", 0.0)
    qf = get(d, "qf", 0.0)
    return TapTransformer(;
        name = name,
        available = d["br_status"] == 1,
        activepower_flow = pf,
        reactivepower_flow = qf,
        arc = Arc(bus_f, bus_t),
        r = d["br_r"],
        x = d["br_x"],
        tap = d["tap"],
        primaryshunt = d["b_fr"],  # TODO: which b ??
        rate = d["rate_a"],
    )
end

function make_phase_shifting_transformer(name, d, bus_f, bus_t, alpha)
    pf = get(d, "pf", 0.0)
    qf = get(d, "qf", 0.0)
    return PhaseShiftingTransformer(;
        name = name,
        available = d["br_status"] == 1,
        activepower_flow = pf,
        reactivepower_flow = qf,
        arc = Arc(bus_f, bus_t),
        r = d["br_r"],
        x = d["br_x"],
        tap = d["tap"],
        primaryshunt = d["b_fr"],  # TODO: which b ??
        α = alpha,
        rate = d["rate_a"],
    )
end

function read_branch!(sys::System, data, bus_number_to_bus::Dict{Int, Bus}; kwargs...)
    @info "Reading branch data"
    if !haskey(data, "branch")
        @info "There is no Branch data in this file"
        return
    end

    _get_name = get(kwargs, :branch_name_formatter, _get_pm_dict_name)

    for (d_key, d) in data["branch"]
        d["name"] = get(d, "name", d_key)
        name = _get_name(d)
        bus_f = bus_number_to_bus[d["f_bus"]]
        bus_t = bus_number_to_bus[d["t_bus"]]
        value = make_branch(name, d, bus_f, bus_t)

        add_component!(sys, value; skip_validation = SKIP_PM_VALIDATION)
    end
end

function make_dcline(name, d, bus_f, bus_t)
    return HVDCLine(;
        name = name,
        available = d["br_status"] == 1,
        activepower_flow = get(d, "pf", 0.0),
        arc = Arc(bus_f, bus_t),
        activepowerlimits_from = (min = d["pminf"], max = d["pmaxf"]),
        activepowerlimits_to = (min = d["pmint"], max = d["pmaxt"]),
        reactivepowerlimits_from = (min = d["qminf"], max = d["qmaxf"]),
        reactivepowerlimits_to = (min = d["qmint"], max = d["qmaxt"]),
        loss = (l0 = d["loss0"], l1 = d["loss1"]),
    )
end

function read_dcline!(sys::System, data, bus_number_to_bus::Dict{Int, Bus}; kwargs...)
    @info "Reading DC Line data"
    if !haskey(data, "dcline")
        @info "There is no DClines data in this file"
        return
    end

    _get_name = get(kwargs, :branch_name_formatter, _get_pm_dict_name)

    for (d_key, d) in data["dcline"]
        d["name"] = get(d, "name", d_key)
        name = _get_name(d)
        bus_f = bus_number_to_bus[d["f_bus"]]
        bus_t = bus_number_to_bus[d["t_bus"]]

        dcline = make_dcline(name, d, bus_f, bus_t)
        add_component!(sys, dcline, skip_validation = SKIP_PM_VALIDATION)
    end
end

function make_shunt(name, d, bus)
    return FixedAdmittance(;
        name = name,
        available = Bool(d["status"]),
        bus = bus,
        Y = (-d["gs"] - d["bs"]im),
    )
end

function read_shunt!(sys::System, data, bus_number_to_bus::Dict{Int, Bus}; kwargs...)
    @info "Reading branch data"
    if !haskey(data, "shunt")
        @info "There is no shunt data in this file"
        return
    end

    _get_name = get(kwargs, :shunt_name_formatter, _get_pm_dict_name)

    for (d_key, d) in data["shunt"]
        d["name"] = get(d, "name", d_key)
        name = _get_name(d)
        bus = bus_number_to_bus[d["shunt_bus"]]
        shunt = make_shunt(name, d, bus)

        add_component!(sys, shunt; skip_validation = SKIP_PM_VALIDATION)
    end
end


text:
function error_terms(N)
    ϕ = 1.172104
    a = 1.081792
    b = 4.492075
    h = a / N
    μ = b * N
    E1 = exp(-π*(π-2ϕ)/h)
    E2 = exp(μ-2π*ϕ/h)
    E3 = exp(μ*(1-cosh(a)*sin(ϕ)))
    return E1, E2, E3
end


text:
@testset "Simulate Forwaird" begin

    @testset "Simulate Forward - Kernel Function" begin
        kern(x) = pdf.(Distributions.Exponential(1/0.5), x)
        forwardEvents = HawkesProcesses.simulate_forward([5, 9], 20, 10, 0.5, 0.5, kern)
        @test length(forwardEvents) >= 0
    end

    @testset "Simulate Forward - Kernel Distribution" begin
        kernD = Distributions.Exponential(1/0.5)
        forwardEvents = HawkesProcesses.simulate_forward([5, 9], 20, 10, 0.5, 0.5, kernD)
        @test length(forwardEvents) >= 0
    end

end