text:
##################Utility Functions ###############################

#helper function  to get the model matrix from a dataframe given a formula
#IN: A dataframe and formula object
#OUT: the model matrix
function getModelMatrix(df::T, f::Formula)::Matrix{Float64} where
  T <: AbstractDataFrame
  return ModelMatrix(ModelFrame(f, df)).m
end

#Same as above but allows for an expression
function getModelMatrix(df::T, exp::V)::Matrix{Float64} where
  {T <: AbstractDataFrame, V <: CTExpr}

  #special case which crashes Formula
  if exp == Symbol("")
    return ones(Float64,size(df,1),1)
  end

  return getModelMatrix(df, get1SidedFormula(exp))
end

#helper function  to get the list of symbols in an expression
#IN: A dataframe and a string object, typically representing a formula
#OUT: a vector of symbols in the string object
function getSymbolsFromExpr(exp::V)::Vector{Symbol} where {V <: CTExpr}
  symStrings::Vector{String} = split(string(exp),
    ['|','=','~',' ','+','*','&',')','(','-'], keepempty=false)

  filter!(s::String->typeof(Meta.parse(s))≠Int,symStrings)

  #convert the strings to symbols
  return Symbol.(symStrings)
end

#helper function to create a one-sided formula given an expression
#IN: an expression and dataframe
#OUT: A one-sided formula object
function get1SidedFormula(RHS::T)::Formula where
  {T <: CTExpr}

  LHS::Nothing = nothing
  return @eval(@formula($LHS ~ $RHS))
end

#drops nulls  from dataframe given a list of symbols
#IN: a data frame and symbols
#OUT: dataframe less the null entires as dictated by the symbol list
dropNullsFromDF(df::DataFrame, syms::Vector{Symbol})::DataFrame =
  df[completecases(df[syms]),:]

#drops nulls  from dataframe given a list of symbols
#IN: a sub-dataframe and symbols, #OUT: subdataframe less the null entries
dropNullsFromDF(dfSub::SubDataFrame, syms::Vector{Symbol})::SubDataFrame =
    view(dfSub,completecases(dfSub[syms]))

#helper function for the above, takes in a single symbol
#IN: a subdataframe and symbol #OUT: subdataframe less the null entries
function dropNullsFromDF(df::T, s::Symbol) where {T<:AbstractDataFrame}

  return dropNullsFromDF(df, collect([s]))
end

#helper function for the above, de-nulls entire dataframe
#IN: a subdataframe #OUT: subdataframe less the null entries
function dropNullsFromDF(df::T) where {T<:AbstractDataFrame}
  return dropNullsFromDF(df, names(df))
end

#####################CTQR Type###########################
#=This is a storage object specific to the QR optimizations
meant to hold the QR factorization and a handle for X
Values: X matrix that is decomposed, Q matrix, and R matrix
The X matrix has dimensions of NxK. R is the inverse, stored
for computational efficiency.=#

struct CTQR
  X::Matrix{Float64}
  Q::Matrix{Float64}
  R::Matrix{Float64}

  N::Int
  K::Int
  RInv::Matrix{Float64}
end

#helper method which takes the inverse of the R matrix (which is used in a lot)
#IN: X matrix and its Q R decomposition in matrix form
#OUT: CTQR Object
function CTQR(X::Matrix{Float64},Q::Matrix{Float64},R::Matrix{Float64};keepX=true)::CTQR
  #=println("Keep: $keepX")
  println("X Size: $(size(X))")
  println("Q Size: $(size(Q))")
  println("R Size: $(size(R))")=#
  #display(R)

  CTQR(keepX ? X : Matrix{Float64}(),
    Q,
    R,
    size(X,1),
    size(X,2),
    (R)\Matrix{Float64}(I,size(X,2),size(X,2)))
end

#main constructor for the CTQR object
#IN: X Matrix
#OUT: CTQR object
function CTQR(X::Matrix{Float64}; keepX = true)::CTQR
  local Q::Matrix{Float64}
  local R::Matrix{Float64}
  local QRCompact::LinearAlgebra.QRCompactWY

  QRCompact = qr(X)
  Q = Matrix(QRCompact.Q)
  R = Matrix(QRCompact.R)

  #=if size(Q,1) == size(Q,2)
    Q = Q[:,1:size(R,1)]
  else
  #  @warn "CTQR Q matrix is already thin. Can delete this conditional statement
  #    using the code above the warning. Loc code 7893."
  end =#
  #println("gothere1.3")
  return CTQR(X,Q,R)
end

#default constructor to clear memory
CTQR() = CTQR(Matrix{Float64}(),Matrix{Float64}(),Matrix{Float64}(),
    0,0,Matrix{Float64}())::CTQR

#####################CTLM Model Type#########################
#This is designed to hold the minimal info for a linear model
#Plus the associated CTQR object
 mutable struct CTLM <: CTModel
  xqr::CTQR #handle to the xqr object
  X::Matrix{Float64} #the data and x matrix (handle)
  Y::Vector{Float64} #Y data

  N::Int #Number of data points (rows)
  K::Int #Number of data columns
  dof::Int
  β::Vector{Float64} #beta coefficient
  ε::Vector{Float64} #residuals

  XNames::Vector{Symbol} #names of the X variables
  YName::Symbol #names of the Y variables

  clusters::Vector{C} where C <: CTData #holds the clusters

end

function CTLM(X::Matrix{Float64}, Y::Vector{Float64}; clusters::Vector{C}=[nothing],
        XNames::Vector{Symbol} = Symbol.(:X, 1:size(X,2)),
        YName::Symbol = :Y, dof = size(X,1)-size(X,2))::CTLM where C<:CTData

    #println("flag5")
    #showall(X[1:100,1:2])
    #println("got here1")
    xqr::CTQR = CTQR(X, keepX=false)
    #println("flag6")
    #println("got here2")
    β::Vector{Float64} = Vector{Float64}(undef, xqr.K)
    getCoeff!(xqr,Y,β)
    #println("got here3")
    ε::Vector{Float64} = Vector{Float64}(undef, xqr.N)
    getResid!(X,Y,β,ε)
    #println("got here4")
    return CTLM(xqr, X, Y, xqr.N, xqr.K, dof, β, ε, XNames, YName, clusters)
end

#=Constructor and helper method which gets required info from DataFrame
IN: The source dataframe, a formula expression for the RHS,
    the dependent variable as a symbol, optionally names for X columns,
    Y and a switch to elliminate null values
OUT: A CTLM object
NOTE: RHS expression must be ordered with factors last, otherwise
    the factor names will be incorrect =#
function CTLM(df::DataFrame,  XExpr::T, YSym::Symbol;
    XNames::Vector{Symbol}=[Symbol(:Intercept)], YName::Symbol=:Y,
    eliminateNulls=true, withinSym::V = nothing, clusterSym::R = nothing,
        fixedEffectsSym = nothing)::CTLM  where {
        T <: CTExpr, V<:Union{Symbol,Nothing}, R<:Union{Symbol, Nothing}}

    #NOTE: Delete when code is fully updated
    if fixedEffectsSym ≠ nothing
      error("fixedEffectsSym no longer used. Replace within withinSym and/or clusterSym")
    end

    #get the list of symbols from the expression for X
    XSym::Vector{Symbol} = getSymbolsFromExpr(XExpr)

    #println("flag2.2")
    #form an array of all symbols for which we want to drop nulls
    viewArray::Vector{Symbol} = [XSym; YSym]
    if withinSym ≠ nothing && withinSym ∉ viewArray
      viewArray = [viewArray; withinSym]
    end
    if clusterSym ≠ nothing && clusterSym ∉ viewArray
      viewArray = [viewArray; clusterSym]
    end
    dfSub::SubDataFrame = view(df[viewArray],1:size(df,1))
    #println("flag1")
    if eliminateNulls     # if we are going to drop nulls
      dfSub = dropNullsFromDF(dfSub)
    end

    #println("flag3.2")
    #println("$(typeof(dfSub[withinSym]))")
    #get the within and clustering symbols
    if withinSym ≠ nothing
      within::Vector{W where W <: CTData}  = Vector{W where W <: CTData}(dfSub[withinSym])
    end

    #println("flag4.2")
    if clusterSym ≠ nothing
      clusters::Vector{C where C <: CTData}  = Vector{C where C <: CTData}(dfSub[clusterSym])
    else
      clusters = [nothing]
    end

    #println("flag2")
    #drop the columns which arn't going into the model matrix
    dfSub = view(dfSub[[XSym; YSym]],1:size(dfSub,1))
    #println("flag3")

    #get the factor expanded model matrix (Adds the dummies)
    XModelMatrix::Matrix{Float64} = getModelMatrix(dfSub, XExpr)
    #println("flag41")

    #this is a check to make sure the factor expansion follows other columns
    if length(XSym) > 1
        for i ∈ 2:length(XSym) #all types
            if typeof(dfSub[XSym[i-1]])<:CategoricalArray &&
                !(typeof(dfSub[XSym[i]])<:CategoricalArray)
                warn("Type of $(typeof(dfSub[i])) is preceeded by type of
                    factor. Column names are likely MISALIGNED. Put factors
                    after numerical variables in RHS expressions.")
            end
        end
    end

    #Now assign the names as appropriate
    XNamesFull::Vector{Symbol} = Vector{Symbol}(undef, size(XModelMatrix,2))
    for i ∈ 1:length(XNamesFull)
        XNamesFull[i] = i≤length(XNames) ? XNames[i] : Symbol(:X,i)
    end

    #get the appropriate matrices and construct the CTLM object

    #println("gothere1")

    if withinSym != nothing
      #println("flag3a")
            #println(typeof(Vector(dfSub[fixedEffectsSym])))
        return CTLM(XModelMatrix, Vector{Float64}(dfSub[YSym]),
          within, clusters = clusters,
            XNames=XNamesFull, YName=YName)
    else
      #  println("flag3b")
        return CTLM(XModelMatrix,
            Vector{Float64}(dfSub[YSym]), clusters = clusters,
            XNames=XNamesFull, YName=YName)
    end

end

#transforms the data using the within estimator, including an adjustment to dof
function CTLM(X::Matrix{Float64}, Y::Vector{Float64}, within::Vector{W};
    clusters::Vector{C} = [nothing],
    XNames::Vector{Symbol} = Symbol.(:X, 1:size(X,2)),
    YName::Symbol = :Y)::CTLM where {W<:CTData, C<:CTData}

    #println("flag4")
    #we get the unique values and make a two way table
    #tVars::Vector{T} = unique(tFI)
    iVars::Vector{W} = unique(within)
    iN::Int = length(iVars)
    iTable::Dict = Dict(iVars[i] => i for i::Int ∈ 1:iN)

    K::Int = size(X,2)
    N::Int = size(X,1)

    #now create the codified versions
    #Xi::Matrix{Float64} = Matrix{Float64}(length(iVars),size(X,2))
    withinCode::Vector{Int} = ((x::W)->iTable[x]).(within)

    meanXY::Matrix{Float64} = zeros(iN,K+1)
    NXY::Vector{Int} = zeros(iN)

    #println("$N,$K,$iN,$(size(NXY))")
    @fastmath for r::Int ∈ 1:N
      meanXY[withinCode[r],K+1] += Y[r]
      NXY[withinCode[r]] += 1.0
    end

    @fastmath for c::Int ∈2:K, r ∈1:N
      meanXY[withinCode[r],c] += X[r,c]
    end

    meanXY ./= NXY

    @fastmath for c::Int ∈2:K, r::Int ∈1:N
      X[r,c] -= meanXY[withinCode[r],c]
    end

    @fastmath for r::Int ∈ 1:N
      Y[r] -= meanXY[withinCode[r],K+1]
    end

    #println("got here 2")
    return CTLM(X, Y, clusters=clusters, XNames=XNames, YName=YName, dof = N - iN - K)
end

#this function calculates the Pearson correlation coefficient of the predicted values
#relative to the realized values
getR(lin::CTLM)::Float64 = cor(lin.Y, lin.Y .- lin.ε)

function getR²(lin::CTLM; adjusted::Bool = true, percentage::Bool = false)::Float64
  R²::Float64 = getR(lin)^.2
  R² = adjusted ? R² - (1-R²)*(lin.N-lin.dof+1)/lin.dof : R²
  R² = percentage ? R²*100 : R²

  return R²
end

#fucntion for getting regression coefficients
getTerm(lm::CTLM, s::Symbol) = (lm.β[findfirst(lm.XNames, s)])::Float64

######2SLS constructor
#Holds the modelling componenets for a 2SLS model (except errors)
#Variable descriptions are in the struct
# Runs standard 2SLS using QR optimization
mutable struct CT2SLS <: CTModel
    zaqr::CTQR #QR decomposition of Za (Z|W)
    xaqr::CTQR #QR decomposition of fitted 1st stage values (X̃|W)

    X::Matrix{Float64} #Endogeneous covariates
    W::Matrix{Float64} #Exogeneous covariates
    Y::Vector{Float64} #Dependent var
    Z::Matrix{Float64} #IV data

    N::Int #number of data points
    K::Int # of endogeneous covariates
    L::Int # of instrumental variables
    KW::Int # of exogeneous covariates
    dof::Int

    Π1::Matrix{Float64} #first stage results
    Ξ1::Matrix{Float64} #first stage residuals

    δ2::Vector{Float64} #2SLS coefficients
    ξ2::Vector{Float64} #2SLS residuals

    XNames::Vector{Symbol} #names of the X variables
    WNames::Vector{Symbol} #names of the W variables
    YName::Symbol #names of the Y variables
    ZNames::Vector{Symbol} #names of the Z variables

    #CT2SLS()
end

#= Convenience constructor for CT2SLS that allocates a 0 element array for the
case of no exogeneous covariates. NOTE: no exog covariates implies no intercept,
so there probably should be  some exogeneous covariates
#IN: X Matrix, Y Vector, and the Z matrix of Instrumental variables
#OUT: CT2SLS object=#
CT2SLS(X::Matrix{Float64},Y::Vector{Float64},Z::Matrix{Float64};
    XNames::Vector{Symbol} = Symbol.(:X, 1:size(X,2)),
    YName::Symbol = :Y,
    ZNames::Vector{Symbol} = Symbol.(:Z, 1:size(Z,2)))::CT2SLS =
        CT2SLS(X,Matrix{Float64}(undef, Size(X,1),0),Y,Z)

#=Main constructor for CT2SLS object
IN: Endogeneous matrix X, Exogeneous matrix W, Dependent vector Y,
instrumental zariable matrix Z
OUT: A 2SLS object

#NOTE: not sure about the dof
=#
function CT2SLS(X::Matrix{Float64}, W::Matrix{Float64},
  Y::Vector{Float64},Z::Matrix{Float64};
  XNames::Vector{Symbol} = Symbol.(:X, 1:size(X,2)),
  WNames::Vector{Symbol} = Symbol.(:W, 1:size(W,2)),
  YName::Symbol = :Y,
  ZNames::Vector{Symbol} = Symbol.(:Z, 1:size(Z,2)),
  dof::Int = size(X,1) - size(X,2) - size(W,2))::CT2SLS

  #memory pre-allocaiton
  N::Int = size(X,1) #number of data points
  K::Int = size(X,2) # of endogeneous variables
  L::Int = size(Z,2) # of instrumental variables
  KW::Int = size(W,2)# of exogeneous covariates

  Π1::Matrix{Float64} = Matrix{Float64}(undef, L+KW,K)
  X̂::Matrix{Float64} = Matrix{Float64}(N,K) #holds fitted first stage values
  Ξ1::Matrix{Float64} = similar(X̂) #holds first stage residuals
  δ2::Vector{Float64} = Vector{Float64}(undef, K+KW)
  ξ2::Vector{Float64} = similar(Y)
  #Xa::Matrix{Float64} = Matrix{Float64}(N,K+KW) #fitted 1st stage plus exog covariates

  #start with setting up and running the first stage
  ZW::Matrix{Float64} = [Z W]
  zaqr::CTQR = CTQR(ZW, keepX=false) #augment the matrices to ZW and get the QR
  getCoeff!(zaqr, X, Π1) #get the first stage coefficients
  BLAS.gemm!('N','N',1.0,ZW,Π1,0.0,X̂) #get the fitted first stage values
  getResid!(ZW, X, Π1, Ξ1) #get the residuals

  #now run the second stage
  xaqr::CTQR = CTQR([X̂ W], keepX = false) #augment X̂W and get the QR
  getCoeff!(xaqr, Y, δ2) #get the 2SLS coefficients
  getResid!([X W], Y, δ2, ξ2) #get the 2SLS residuals

  #Finally, return the constructed model
  return CT2SLS(zaqr, xaqr, X, W, Y, Z, N, K, L, KW, dof, Π1, Ξ1, δ2, ξ2,
    XNames, WNames, YName, ZNames)
end

#Constructor and helper method which gets required info from DataFrame
#IN: The source dataframe, a formula expression/symbol for X, W, Y, and Z
# the dependent variable as a symbol
#OUT: A CTLM object
function CT2SLS(df::DataFrame, XExpr::T, WExpr::U, YSym::Symbol, ZExpr::V;
    XNames::Vector{Symbol} = Vector{Symbol}(),
    WNames::Vector{Symbol} = Vector{Symbol}([:Intercept]),
    YName::Symbol = :Y,
    ZNames::Vector{Symbol} = Vector{Symbol}(),
    eliminateNulls=true)::CT2SLS where {T <: CTExpr, U <: CTExpr, V <: CTExpr}

    #get the list of symbols for X, W and Z
    XSym::Vector{Symbol} = getSymbolsFromExpr(XExpr)
    WSym::Vector{Symbol} = getSymbolsFromExpr(WExpr)
    ZSym::Vector{Symbol} = getSymbolsFromExpr(ZExpr)

    #make a view so if we drop nulls it doesn't affect the original
    dfSub::SubDataFrame = view(df[ [XSym; WSym; YSym; ZSym]],1:size(df,1))

    # if we are going to drop nulls
    if eliminateNulls
        dfSub = dropNullsFromDF(dfSub)
    end

    #get the model matrices, which will expand all factors
    XModelMatrix::Matrix{Float64} = getModelMatrix(dfSub, XExpr)
    WModelMatrix::Matrix{Float64} = getModelMatrix(dfSub, WExpr)
    ZModelMatrix::Matrix{Float64} = getModelMatrix(dfSub, ZExpr)

    #this is a check to make sure the factor expansion follows other columns
    #We must repeat the check on each variable matrix
    for symVec::Vector{Symbol} ∈ [XSym, WSym, ZSym]
        if length(symVec) > 1
            for i ∈ 2:length(symVec) #all types
                if typeof(dfSub[symVec[i-1]])<:CategoricalArray &&
                    !(typeof(dfSub[symVec[i]])<:CategoricalArray)
                    warn("Type of $(typeof(dfSub[i])) is preceeded by type of
                        factor. Column names are likely MISALIGNED. Put factors
                        after numerical variables in RHS expressions.")
                end
            end
        end
    end

    #now create the namesfor the expanded matrix
    XNamesFull::Vector{Symbol} = Vector{Symbol}(undef, size(XModelMatrix,2))
    for i ∈ 1:length(XNamesFull)
        XNamesFull[i] = i≤length(XNames) ? XNames[i] : Symbol(:X,i)
    end

    WNamesFull::Vector{Symbol} = Vector{Symbol}(undef, size(WModelMatrix,2))
    for i ∈ 1:length(WNamesFull)
        WNamesFull[i] = i≤length(WNames) ? WNames[i] : Symbol(:W,i)
    end

    ZNamesFull::Vector{Symbol} = Vector{Symbol}(undef, size(ZModelMatrix,2))
    for i ∈ 1:length(ZNamesFull)
        ZNamesFull[i] = i ≤ length(ZNames) ? ZNames[i] : Symbol(:Z,i)
    end

    #get the appropriate matrices and construct the CT2SLS object
    return CT2SLS(XModelMatrix, WModelMatrix, Vector{Float64}(undef, dfSub[YSym]),
        ZModelMatrix, XNames=XNamesFull, WNames=WNamesFull,
        YName=YName, ZNames=ZNamesFull)

end

#default constructor to help with memory management
CT2SLS() = CT2SLS(CTQR(), CTQR(), Matrix{Float64}(), Matrix{Float64}(),
    Vector{Float64}(), Matrix{Float64}(), 0, 0, 0, 0, Matrix{Float64}(),
    Matrix{Float64}(), Vector{Float64}(), Vector{Float64}(),
    Vector{Symbol}(), Vector{Symbol}(), Symbol(), Vector{Symbol}())::CT2SLS

#=function get1stStage
#The purpose is to get the first stage of the IV as a linear model
#Unfortunately, we need to copy some of the data, so this can be expensive,
#although Z and W should only be copied once
#IN: an IV object
#OUT: a vector of CTLM objects, one for each focal (X) variable in the
#initial regression=#
function get1stStage(iv::CT2SLS)::Vector{CTLM}
    ZW::Matrix{Float64} =  [iv.Z iv.W]
    iv1st::Vector = Vector{CTLM}()

    for i ∈ 1:length(iv.XNames)
        push!(iv1st, CTLM(iv.zaqr, [iv.Z iv.W], iv.X[:,i],
            iv.zaqr.N, iv.zaqr.K, iv.Π1[:,i], iv.Ξ1[:,i],
            [iv.ZNames; iv.WNames], iv.XNames[i]))
    end

    return iv1st
end

#########################Project!##############################
#=gets the projection matrix

IN: THe CTQR decomposition and the memory for  the projection matrix
OUT: Writes and returns the projection matrix
NOTE: This method will allocate the projection matrix if no second
argument is supplied. =#
function project!(xqr::CTQR, P::Matrix{Float64}=Matrix{Float64}(undef, xqr.N, xqr.N)
  )::Matrix{Float64}

  #use the BLAS library for fast matrix algebra
  return BLAS.gemm!('N','T',1.0,xqr.Q,xqr.Q,0.0,P)

end

#=This version gets only the diagonal of the projection matrix
IN: THe CTQR decomposition and the memory for  the projection diagonal
OUT: Writes and returns the projection matrix=#
function project!(xqr::CTQR, P::Vector{Float64})::Vector{Float64}
  #get the diagonal quickly
  #equivlenet to diag(Q*Q')
  P .= 0.0
  @fastmath for j::Int ∈ 1:xqr.K, i::Int ∈ 1:xqr.N
    P[i] += xqr.Q[i,j] * xqr.Q[i,j]
  end

  return P

end

#=This version runs either of the above methods after generating
the xqr object given an independent variable matrix
IN: Independent variable X matrix and the memory for  the projection matrix
or vector for the diagonal
OUT: Writes and returns the projection matrix=#
function project!(X::Matrix{Float64},
  P::Array{Float64}=Matrix{Float64}(undef, size(X,1),size(X,1)))::Array{Float64}

  return project!(CTQR(X),P)
end

#=simple test function to verify the projection optimizations
output should be identical to the matrix function above
IN: Independent variable X matrix, memory for the projection matrix
OUT: Writes and returns teh projection matrix=#
function projectSlow!(X::Matrix{Float64},P::Matrix{Float64})
  P .= (X * ((X' * X)\Matrix{Float64}(I,size(X,2),size(X,2))) * X')
  return P
end

#########################getResid!#########################
#=gets the residuals in the 2SLS framework

Note this is a wrapper function which can accept multiple independent
and multiple dependent variables. NOTE the change in the naming convention
relative to other verisons of this method (due to the 2SLS context)
IN: QR decomposition of the RHS variables, LHS dependent variable matrix,
a coefficient matrix, optionally the memory for the residual matrix
OUT: Writes and returns the residual matrix=#
function getResid!(ZW::Matrix{Float64}, X::Matrix{Float64}, Π1::Matrix{Float64},
  Ξ1::Matrix{Float64}=similar(X))::Matrix{Float64}

  #get the residuals by reference
  for i ∈ 1:size(X,2) #get the vector of reisduals multiple times
    getResid!(ZW, view(X,:,i), view(Π1,:,i), view(Ξ1,:,i))
  end
  return Ξ1
end

#=Main method to get residuals
IN: X matrix the RHS variables, LHS dependent variable,
a coefficient vector, optionally the memory for the residual vector
OUT: Writes and returns the residual vector=#
function getResid!(X::Matrix{Float64}, Y::T,
  β::T, ε::T=similar(Y))::T where T<:StridedVector{Float64}

  return BLAS.axpy!(1.0, Y, BLAS.gemv!('N',-1.0, X, β,0.0,ε)) #ε=Y-Xβ
end

#########################getCoef!###########################
# Gets the coefficients in a regression

#=This is a wrapper function which gets a matrix of coefficients for use in
# the first stage of 2SLS. NOTE the change in the naming convention
relative to other verisons of this method (due to the 2SLS context)
IN: QR decomposition of the RHS variables, LHS dependent variable matrix,
optionally the memory for the coefficient matrix
OUT: Writes and returns the coefficient matrix=#
function getCoeff!(zaqr::CTQR, X::Matrix{Float64},
  Π1::Matrix{Float64} = Matrix{Float64}(undef, zaqr.K, size(X,2)))::Matrix{Float64}

  for i ∈ 1:size(X,2) # for each dependent variable vector
    getCoeff!(zaqr, view(X,:,i), view(Π1,:,i)) #run the regression as needed
  end

  return Π1
end

#=Main method to get the regression coefficients
IN: QR decomposition of X matrix the RHS variables, LHS dependent variable,
optionally the memory for the coefficient vector
OUT: Writes and returns the coefficient vector=#
function getCoeff!(xqr::CTQR, Y::T,
  β::T = Vector{Float64}(undef, xqr.K))::T where  T<:StridedVector{Float64}

  #println("got here 5")
  #println("xqr.RInv size: $(size(xqr.RInv)) xqr.Q size:$(size(xqr.Q))")
  M::Matrix{Float64} = BLAS.gemm('N', 'T', xqr.RInv, xqr.Q)
  #println("got here 6")

  return  BLAS.gemv!('N',1.0,M,Y,0.0,β)
end

#=Convenience method to get the regression coefficients
IN: X matrix the RHS variables, LHS dependent variable,
optionally the memory for the coefficient vector
OUT: Writes and returns the coefficeint vector=#
getCoeff!(X::Vector{Float64}, Y::Vector{Float64}) =
  getCoeff!(CTQR(X), Y, Vector{Float64}(undef, size(X,2)))::Vector{Float64}

###################getHomosked!#######################
#Gets the covariance matrix under Homoskedastic assumptions σ^2[X'X]^-1

#main method to get the covariance matrix
#IN: The QR decomposition from the regression, a vector of residuals,
#optionally memory for the covariance matrix
#OUT: Writes and returns the covariance matrix
function getHomoskedΣ!(xqr::CTQR, ε::Vector{Float64},
  Σ::Matrix{Float64} = Matrix{Float64}(undef, lin.K, lin.K); dofCorrect::Float64 = 1.0)::Matrix{Float64}

  return dofCorrect .* BLAS.gemm!('N','T',(ε⋅ε)/(xqr.N-xqr.K),xqr.RInv,xqr.RInv,0.0,Σ) #[X'X]^-1*σ2
end

#=helper method for the above function which extracts the QR decomposition
from a linear model
IN: A linear model, optionally memory for the covariance matrix
OUT: WRites and returns the covariance matrix=#
function getHomoskedΣ!(lin::CTLM,
  Σ::Matrix{Float64}=Matrix{Float64}(undef, lin.K, lin.K))::Matrix{Float64}

  return getHomoskedΣ!(lin.xqr, lin.ε, Σ, dofCorrect = lin.N / lin.dof)
end

#=helper method for the above function which extracts the QR decomposition
from a CT2SLS object
IN: A linear model, optionally memory for the covariance matrix
OUT: WRites and returns the covariance matrix=#
function getHomoskedΣ!(iv::CT2SLS,
  Σ::Matrix{Float64}=Matrix{Float64}(undef, iv.xaqr.K, iv.xaqr.K))::Matrix{Float64}

  return getHomoskedΣ!(iv.xaqr, iv.ξ2, Σ, iv.N / iv.dof)
end

#=Simple test function to verify the QR-related optimizations
Output should be identical to the standard methods
IN: Independent variable X matrix
OUT: Returns the covariance matrix=#
getHomoskedΣSlow(X::Matrix{Float64}, ε::Vector{Float64})::Matrix{Float64} =
  (X'*X)\Matrix{Float64}(I,size(X,2),size(X,2))*(ε⋅ε)/(size(X,1)-size(X,2))

#Convenience method for above: IN: A linear model #OUT: A covariance matrix
getHomoskedΣSlow(lin::CTLM)::Matrix{Float64} =
  getHomoskedΣSlow(lin.X, lin.Y.-lin.X * lin.β)

#Convenience method for above: IN: A CT2SLS object #OUT: A covariance matrix
getHomoskedΣSlow(iv::CT2SLS)::Matrix{Float64} =
  getHomoskedΣSlow([[iv.Z iv.W]*iv.Π1 iv.W], iv.Y.-[iv.X iv.W] * iv.δ2)

#########################getNeweyWest ##########OLS Only
function getNeweyWest!(X::Matrix{Float64}, xqr::CTQR, ε::Vector{Float64}, lag::Int,
  Σ::Matrix{Float64} = Matrix{Float64}(undef, xqr.K, xqr.K), dofCorrect::Float64 = 1.0)::Matrix{Float64}

  #pre-allocate for the spectral matrix

  Rv::Matrix{Float64} = Matrix{Float64}(undef, xqr.K, xqr.K) #pre-allocate working matrix
  RRInv::Matrix{Float64} = BLAS.gemm('N', 'T', xqr.RInv, xqr.RInv) #this is equivelent to [X'X]^-1

  #need to multiply through by the error
  Xe::Matrix{Float64} = X .* ε
  ST::Matrix{Float64} = BLAS.gemm('T','N',1.0/xqr.N, Xe, Xe)
  for v::Int ∈ 1:lag
    #overwrites Rv with (1/N)R'R
    BLAS.gemm!('T', 'N', 1.0/xqr.N, view(Xe, (v+1):(xqr.N), :),view(Xe, 1:(xqr.N-v), :), 0.0, Rv)
    #Rv .= view(Xe, (v+1):(xqr.N), :)' * view(Xe, 1:(xqr.N-v), :) .* (1.0/xqr.N)
    ST .+= (lag + 1 .- v)/(lag+1.) .* (Rv .+ Rv')
  end

  #this is [X'X]^-1S=[R'R]^-1S
  RRInvS::Matrix{Float64} = BLAS.gemm('N', 'N', RRInv, ST)

  #finally we have T[X'X]^-1S[X'X]^-1
  BLAS.gemm!('N','N',Float64(xqr.N), RRInvS, RRInv, 0.0, Σ)
  #println("$(diag(Σ .* dofCorrect))")
  return Σ .* dofCorrect
end

function getNeweyWest!(lin::CTLM, lag::Int,
  Σ::Matrix{Float64} = Matrix{Float64}(undef, lin.K, lin.K))::Matrix{Float64}

  return getNeweyWest!(lin.X, lin.xqr, lin.ε, lag, Σ, lin.N/lin.dof)
end

#helper function in case the input requires a single argument function
getNeweyWestFunc(lag::Int) = (lin::CTLM)-> getNeweyWest!(lin, lag)

#testing for NeweyWest
function getNeweyWestSlow(X::Matrix{Float64}, ε::Vector{Float64}, lag::Int)
  N::Int, K::Int = size(X)

  #first form the spectral matrix

  #initial value for spectral matrix
  xxt::Matrix{Float64} = Matrix{Float64}(undef, K,K)
  xxt .= zeros(K,K)
  for t::Int ∈ 1:N
    xxt .+= (X[t, :] * X[t, :]') .* ε[t]^2
  end
  ST::Matrix{Float64} =  xxt ./ N

  #make the rest of the spectral matrix
  for v::Int ∈ 1:lag
    xxt .= zeros(K,K)
    for t::Int ∈ (1+v):(N)
      xxt .+= (X[t, :] * X[t-v, :]') .* ε[t]*ε[t-v]
    end
    xxt ./= N
    ST .+= (lag + 1. - v)/(lag + 1.) .* (xxt .+ xxt')
  end

  XXInv::Matrix{Float64} = (X' * X) \ Matrix{Float64}(I,K,K)

  ret::Matrix = N*XXInv*ST* XXInv
  return ret
end

getNeweyWestSlow(lin::CTLM, lag::Int) = getNeweyWestSlow(lin.X, lin.Y .- lin.X * lin.β, lag)

getNeweyWestFuncSlow(lag::Int)::Function = (lin::CTLM)-> getNeweyWestSlow(lin, lag)
###################getWhiteERRORs ###OLS only

function getWhiteΣ!(xqr::CTQR, ε::Vector{Float64},
  Σ::Matrix{Float64} = Matrix{Float64}(undef, xqr.K, xqr.K), dofCorrect::Float64=1.0)::Matrix{Float64}

  Λ::Vector{Float64} = ε.^2.0

  QRtInv::Matrix{Float64} = BLAS.gemm('N','T',xqr.Q,xqr.RInv) #Q(R')^-1
  RInvQΛ::Matrix{Float64} = QRtInv'

  #loop to scale the matrix by Λ (modified part of modified white)
  @fastmath for j ∈ 1:xqr.N, i∈1:xqr.K
    RInvQΛ[i,j] *= Λ[j]
  end

  #final multiplicaiton and assignment
  return BLAS.gemm!('N','N',1.0,RInvQΛ, QRtInv,0.0,Σ) .* dofCorrect #R^-1Q'ΛQ(R')^-1
end

function getWhiteΣ!(lin::CTLM,
  Σ::Matrix{Float64} = Matrix{Float64}(undef, lin.K, lin.K))::Matrix{Float64}

  return getWhiteΣ!(lin.xqr, lin.ε, Σ, lin.N/lin.dof)
end

#for testing purposes only
function getWhiteΣSlow(X::Matrix{Float64}, ε::Vector{Float64})
  XXInv::Matrix{Float64} = (X' * X)\Matrix{Float64}(I, size(X,2), size(X,2))

  return XXInv * X' * diagm(ε) .^ 2.0 * X * XXInv
end

#Convenience method for above: IN: A linear model #OUT: A covariance matrix
getWhiteΣSlow(lin::CTLM) = getWhiteΣSlow(lin.X, lin.Y.-lin.X * lin.β)

###########################getClustered SEs
#method for getting clustered errors
#from http://cameron.econ.ucdavis.edu/research/Cameron_Miller_JHR_2015_February.pdf
#forumala: [X'X]^-1*B*[X'X]^-1 where B= sum over G (Xg'*εg*εg'*Xg) and g is indexed for G clusters
function getClustered!(X::Matrix{Float64}, xqr::CTQR, ε::Vector{Float64}, clusters::Vector{C},
    Σ::Matrix{Float64} = Matrix{Float64}(undef, xqr.K, xqr.K),
    dof::Int = xqr.N-xqr.K)::Matrix{Float64} where C<:CTData

  #convenience vectors and values
  cVars::Vector{C} = unique(clusters)
  G::Int = length(cVars)
  cTable::Dict = Dict(cVars[i] => i for i::Int ∈ 1:G)
  clusterCode::Vector{Int} = ((x::C)->cTable[x]).(clusters)

  #iterate through the groups
  B::Matrix{Float64} = zeros(xqr.K, xqr.K)
  @fastmath for i::Int ∈ 1:G
    Xg::SubArray{Float64,2} = view(X, clusterCode .== i, :)
    ug::SubArray{Float64,1} = view(ε, clusterCode .== i)
    B .+= Xg'*ug*ug'*Xg
  end

  # Calc [X'X]^-1*B*[X'X]^-1
  RRInv::Matrix{Float64} =  BLAS.gemm('N','T',xqr.RInv,xqr.RInv)
  RRInvB::Matrix{Float64} = BLAS.gemm('N','N',RRInv,B)

  dofCorrect::Float64 = G/(G-1.)*(xqr.N-1.)/dof #small sample correction
  BLAS.gemm!('N','N',dofCorrect,RRInvB,RRInv,0.0,Σ)

  @fastmath for i ∈ 1:xqr.K
    Σ[i,i] = abs(Σ[i,i]) > 10. ^ -20. ? Σ[i,i] : 0.0
    if Σ[i,i] < 0.
      error("Negative variance ($i): $(diag(Σ))")
    end
  end

  #println("$(diag(Σ))")
  return Σ
end

function getClustered!(lin::CTLM, Σ::Matrix{Float64} = Matrix{Float64}(undef, lin.K, lin.K))::Matrix{Float64}

  return getClustered!(lin.X, lin.xqr, lin.ε, lin.clusters, Σ, lin.dof)
end

###################getMWErrors!##############################
#Main method to get the modified white SEs Does #[X'X]^-1X'ΛX[X'X]^-1

#=Main method to calculate the modified white SEs
IN: A CTQR decomposition object, a residuals vector,
optional memory for a covariance matrix
OUT: Writes and returns the covariance matrix=#
function getModWhiteΣ!(xqr::CTQR, ε::Vector{Float64},
  Σ::Matrix{Float64} = Matrix{Float64}(undef, xqr.K, xqr.K), dofCorrect::Float64 = 1.0)::Matrix{Float64}

  Λ::Vector{Float64} = similar(ε)

  project!(xqr,Λ) #get the projection diagonal
  Λ .= (ε./(1.0.-Λ)).^2.0

  QRtInv::Matrix{Float64} = BLAS.gemm('N','T',xqr.Q,xqr.RInv) #Q(R')^-1
  RInvQΛ::Matrix{Float64} = QRtInv'

  #loop to scale the matrix by Λ (modified part of modified white)
  @fastmath for j ∈ 1:xqr.N, i∈1:xqr.K
    RInvQΛ[i,j] *= Λ[j]
  end

  #final multiplicaiton and assignment
  return BLAS.gemm!('N','N',dofCorrect,RInvQΛ, QRtInv,0.0,Σ) #R^-1Q'ΛQ(R')^-1
end

#=helper method which extracts the required components from a linear model
IN: A linear model, optionally memory for the covariance matrix
OUT: Writes and allocates the covariance matrix=#
function getModWhiteΣ!(lin::CTLM,
  Σ::Matrix{Float64} = Matrix{Float64}(undef, lin.K, lin.K))::Matrix{Float64}

  return getModWhiteΣ!(lin.xqr, lin.ε, Σ, lin.N/lin.dof)
end

#=helper method which extracts the required components from a 2SLS model
IN: A 2SLS model, optionally memory for the covariance matrix
OUT: Writes and allocates the covariance matrix=#
function getModWhiteΣ!(iv::CT2SLS,
  Σ::Matrix{Float64}=Matrix{Float64}(undef, iv.xaqr.K, iv.xaqr.K))::Matrix{Float64}

  return getModWhiteΣ!(iv.xaqr, iv.ξ2, Σ, iv.N/iv.dof)
end

#=Simple test function to verify the QR-related optimizations
Output should be identical to the standard methods
IN: Independent variable X matrix
OUT: Returns the covariance matrix=#
function getModWhiteΣSlow(X::Matrix{Float64}, ε::Vector{Float64})
  XXInv::Matrix{Float64} = (X' * X)\Matrix{Float64}(I,size(X,2),size(X,2))

  P::Matrix{Float64} = X * (XXInv) * X'
  return XXInv * X' * diagm(ε  ./ (1.0 .- diag(P))) .^ 2.0 * X * XXInv

end

#Convenience method for above: IN: A linear model #OUT: A covariance matrix
getModWhiteΣSlow(lin::CTLM) = getModWhiteΣSlow(lin.X, lin.Y.-lin.X * lin.β)

#Convenience method for above: IN: A 2SLS object #OUT: A covariance matrix
getModWhiteΣSlow(iv::CT2SLS)::Matrix{Float64} =
  getModWhiteΣSlow([[iv.Z iv.W]*iv.Π1 iv.W], iv.Y.-[iv.X iv.W] * iv.δ2)

  #################testing methods for this module
  #NOTE: These need to be re-written
function LMtest()

  #Number of Observations
  N::Int = 200
  K::Int = 2

  #Allocate
  X::Matrix{Float64} = Matrix{Float64}(undef, N,K)
  Y::Vector{Float64} = Vector{Float64}(undef, N)
  ε::Vector{Float64} = similar(Y)

  #parameters for the simulation
  σ2::Vector{Float64} = [2.0^2.0 for i::Int ∈ 1:N]
  σ2[1:ceil(Int, N/2)] .= 0.5^2.0
  β::Vector{Float64} = [(1.0 * i) for i::Int ∈ 1:K]
  #println("β: ", β)
  #println("σ2: $σ2")

  #this will hold the sampled beta
  e::Vector{Float64} = similar(ε)

  #run the simulation
  X[:,1] .= 1.0 #intercept
  for i ∈ 2:K
    X[:,i] .= rand(Uniform(),N)
  end

  ε .= map((s2::Float64)->rand(Normal(0.0,s2^0.5)),σ2)
  Y .=  X*β .+ ε

  #get the linear model
  lin::CTLM = CTLM(X, Y)

  #get the homoskedastic SEs
  ΣHomosked::Matrix{Float64} = getHomoskedΣ!(lin)
  ΣHomoskedSlow::Matrix{Float64} = getHomoskedΣSlow(lin)

  #print the coefficients
  println("Coefficients: ",lin.β)
  println("Homoskedastic Errors: ", diag(ΣHomosked).^.5)
  println("Check: ", diag(ΣHomoskedSlow).^.5)

  #get the modified white SEs
  ΣWhite::Matrix{Float64} = similar(ΣHomosked)
  getModWhiteΣ!(lin, ΣWhite)
  ΣWhiteSlow::Matrix{Float64} = getModWhiteΣSlow(lin)

  #print the coefficients
  println("Modified White Errors: ",diag(ΣWhite).^.5)
  println("Check: ", diag(ΣWhiteSlow).^.5)

    #=Π1::Matrix{Float64} = Matrix{Float64}(K,2)
  getCoeff!(lin.xqr, [Y 2.*Y], Π1)
  println("1st stage Z: $(lin.X)")
  println("1st Stage X: $([Y 2.*Y])" )
  println("1st Stage Test Coef: $Π1" )
  Ξ::Matrix{Float64} = getResid!(lin.xqr, [Y 2.*Y], Π1)
  println("1st Stage Resid: $Ξ" )=#

  #test the project routines
  Pa::Vector{Float64} = Vector{Float64}(undef, N)
  PM::Matrix{Float64} = Matrix{Float64}(undef, N,N)
  PS::Matrix{Float64} = Matrix{Float64}(undef, N,N)

  project!(X,PM)
  project!(X,Pa)

  projectSlow!(X,PS)
  println("P: ", Pa[1:5])
  println("P (from full matrix): ", PM[1:3,1:3])
  println("P Slow: ", diag(PS)[1:10])
end

function IVTest()

  srand(11)

  N::Int = 200 #Number of Observations
  K::Int = 3 # of endogneous covariates
  L::Int = 4 # of instruments
  KW::Int = 5# of exog covariates

  #Allocate
  X::Matrix{Float64} = Matrix{Float64}(undef, N,K)
  Z::Matrix{Float64} = Matrix{Float64}(undef, N,L)
  W::Matrix{Float64} = Matrix{Float64}(undef, N,KW)
  Y::Vector{Float64} = Vector{Float64}(undef, N)
  A::Vector{Float64} = Vector{Float64}(undef, N)

  Π1::Matrix{Float64} = Matrix{Float64}(undef, L+KW,K)
  π2::Vector{Float64} = Vector{Float64}(undef, L+KW)
  Ξ1::Matrix{Float64} = similar(X)
  e2::Vector{Float64} = similar(Y)

  #parameters for the simulation
  σ2::Vector{Float64} = [2.0^2 for i::Int ∈ 1:N]
  σ2[1:ceil(Int, N/2)] .= 0.5^2.0

  #generate π2 coefficients (pattern is 1 times the index, ie 1 2 3 ...)
  π2 .= [(10*i) for i::Int ∈ 1:(L+KW)]
  π2[L+1] .= 1.0 #intercept term
  #println("π2: ",π2)

  #generate Π1, pattern is δ2 times 1/10 the index, ie ie .1δ2 .2δ2 .3δ2 ...)
  for i ∈ 1:(L+KW), j∈1:K
    Π1[i,j] .= i + j^2
  end
  Π1[L+1,:] .= 1.0 #set the intercept term
  #display(Π1)

  #generate the exogeneous variables
  for i ∈ 2:KW
    W[:,i] .= rand(Uniform(-10,10),N)
  end
  W[:,1] .= 1.0 #intercept

  #generate the instrumental variables
  for i ∈ 1:L
    Z[:,i] .= rand(Uniform(-10,10),N)
  end

  #map((s2::Float64)->rand(Normal(0.0,s2^0.5)),σ2)
  #generate the errors
  for i ∈ 1:N
    for j ∈ 1:K
      Ξ1[i,j] = rand(Normal(0.0,σ2[i]^0.5))
    end
    e2[i] = rand(Normal(0.0,σ2[i]^0.5))
  end

  #println(Ξ1)
  #populate Y and X
  X .= [Z W]*Π1 .+ Ξ1
  Y .= [Z W]*π2 .+ e2

  #add some endogeneity
  for i ∈ 1:K
    A .= rand(Uniform(-i,i),N)
    X[:,i] .+= A
    Y .+= A .* 10
  end

  #probably is a more graceful way to do this
  XNames::Vector{Symbol} = [Symbol("X$i") for i = 1:K]
  WNames::Vector{Symbol} = [Symbol("W$i") for i = 1:KW]
  ZNames::Vector{Symbol} = [Symbol("Z$i") for i = 1:L]

  iv::CT2SLS = CT2SLS(X,W,Y,Z, XNames=XNames, YName=:Y, WNames=WNames, ZNames=ZNames)
  println("coefficients: \n", [XNames; WNames] ,"\n", iv.δ2)

  #get the homoskedastic SEs
  ΣHomosked::Matrix{Float64} = getHomoskedΣ!(iv)
  ΣHomoskedSlow::Matrix{Float64} = getHomoskedΣSlow(iv)

  #print the coefficients
  println("Homoskedastic Errors: ", diag(ΣHomosked).^.5)
  println("Check: ", diag(ΣHomoskedSlow).^.5)

  #get the modified white SEs
  ΣWhite::Matrix{Float64} = getModWhiteΣ!(iv)
  ΣWhiteSlow::Matrix{Float64} = getModWhiteΣSlow(iv)

  #print the coefficients
  println("Modified White Errors: ",diag(ΣWhite).^.5)
  println("Check: ", diag(ΣWhiteSlow).^.5)

  iv1st::Vector{CTLM} = get1stStage(iv)
  println("1st Stage results: \n $(iv1st[1].XNames)")
  for iv1 ∈ iv1st
      println("coefficients $(iv1.YName):  $(iv1.β )")
      println("Error (Homosked $(iv1.YName)): $(diag(getHomoskedΣ!(iv1)).^.5)")
  end

  oStream::IOStream = open(
    "C:\\Users\\Clinton\\Dropbox\\Projects\\Summer17RTester\\Summer17RTester\\IVTestOut.csv","w+")

  write(oStream, [string.(iv.XNames); string.(iv.WNames)]::Vector{String})
  writecsv(oStream, [X W Y Z])
  close(oStream)
end

if DEBUG_CTMOD
  #LMtest()
  IVTest()
  #IOTest()
  #print(perfTestStr(10^6))
end

max_stars_repo_name: clintonTE/CCA

max_issues_repo_name: clintonTE/CCA

max_forks_repo_name: clintonTE/CCA


text:
# Automatically generated using Clang.jl wrap_c, version 0.0.0

const CURL = Cvoid
const CURLSH = Cvoid

const curl_socket_t = Cint
const CURL_SOCKET_BAD = -1

# begin enum curl_sslbackend
const curl_sslbackend = UInt32
const CURLSSLBACKEND_NONE = (UInt32)(0)
const CURLSSLBACKEND_OPENSSL = (UInt32)(1)
const CURLSSLBACKEND_GNUTLS = (UInt32)(2)
const CURLSSLBACKEND_NSS = (UInt32)(3)
const CURLSSLBACKEND_OBSOLETE4 = (UInt32)(4)
const CURLSSLBACKEND_GSKIT = (UInt32)(5)
const CURLSSLBACKEND_POLARSSL = (UInt32)(6)
const CURLSSLBACKEND_WOLFSSL = (UInt32)(7)
const CURLSSLBACKEND_SCHANNEL = (UInt32)(8)
const CURLSSLBACKEND_DARWINSSL = (UInt32)(9)
const CURLSSLBACKEND_AXTLS = (UInt32)(10)
const CURLSSLBACKEND_MBEDTLS = (UInt32)(11)
# end enum curl_sslbackend

const CURLSSLBACKEND_LIBRESSL = CURLSSLBACKEND_OPENSSL
const CURLSSLBACKEND_BORINGSSL = CURLSSLBACKEND_OPENSSL
const CURLSSLBACKEND_CYASSL = CURLSSLBACKEND_WOLFSSL

mutable struct curl_httppost
    next::Ptr{Cvoid}
    name::Ptr{UInt8}
    namelength::Clong
    contents::Ptr{UInt8}
    contentslength::Clong
    buffer::Ptr{UInt8}
    bufferlength::Clong
    contenttype::Ptr{UInt8}
    contentheader::Ptr{Cvoid}
    more::Ptr{Cvoid}
    flags::Clong
    showfilename::Ptr{UInt8}
    userp::Ptr{Cvoid}
    contentlen::curl_off_t
end

const CURL_HTTPPOST_FILENAME = 1 << 0
const CURL_HTTPPOST_READFILE = 1 << 1
const CURL_HTTPPOST_PTRNAME = 1 << 2
const CURL_HTTPPOST_PTRCONTENTS = 1 << 3
const CURL_HTTPPOST_BUFFER = 1 << 4
const CURL_HTTPPOST_PTRBUFFER = 1 << 5
const CURL_HTTPPOST_CALLBACK = 1 << 6
const CURL_HTTPPOST_LARGE = 1 << 7

const curl_progress_callback = Ptr{Cvoid}
const curl_xferinfo_callback = Ptr{Cvoid}

const CURL_MAX_READ_SIZE = 524288
const CURL_MAX_WRITE_SIZE = 16384
const CURL_MAX_HTTP_HEADER = 100 * 1024
const CURL_WRITEFUNC_PAUSE = 0x10000001

const curl_write_callback = Ptr{Cvoid}
const curl_resolver_start_callback = Ptr{Cvoid}

const CURLFINFOFLAG_KNOWN_FILENAME = 1 << 0
const CURLFINFOFLAG_KNOWN_FILETYPE = 1 << 1
const CURLFINFOFLAG_KNOWN_TIME = 1 << 2
const CURLFINFOFLAG_KNOWN_PERM = 1 << 3
const CURLFINFOFLAG_KNOWN_UID = 1 << 4
const CURLFINFOFLAG_KNOWN_GID = 1 << 5
const CURLFINFOFLAG_KNOWN_SIZE = 1 << 6
const CURLFINFOFLAG_KNOWN_HLINKCOUNT = 1 << 7
const CURL_CHUNK_BGN_FUNC_OK = 0
const CURL_CHUNK_BGN_FUNC_FAIL = 1
const CURL_CHUNK_BGN_FUNC_SKIP = 2
const CURL_CHUNK_END_FUNC_OK = 0
const CURL_CHUNK_END_FUNC_FAIL = 1
const CURL_FNMATCHFUNC_MATCH = 0
const CURL_FNMATCHFUNC_NOMATCH = 1
const CURL_FNMATCHFUNC_FAIL = 2
const CURL_SEEKFUNC_OK = 0
const CURL_SEEKFUNC_FAIL = 1
const CURL_SEEKFUNC_CANTSEEK = 2
const CURL_READFUNC_ABORT = 0x10000000
const CURL_READFUNC_PAUSE = 0x10000001
const CURL_SOCKOPT_OK = 0
const CURL_SOCKOPT_ERROR = 1
const CURL_SOCKOPT_ALREADY_CONNECTED = 2

# begin enum curlfiletype
const curlfiletype = UInt32
const CURLFILETYPE_FILE = (UInt32)(0)
const CURLFILETYPE_DIRECTORY = (UInt32)(1)
const CURLFILETYPE_SYMLINK = (UInt32)(2)
const CURLFILETYPE_DEVICE_BLOCK = (UInt32)(3)
const CURLFILETYPE_DEVICE_CHAR = (UInt32)(4)
const CURLFILETYPE_NAMEDPIPE = (UInt32)(5)
const CURLFILETYPE_SOCKET = (UInt32)(6)
const CURLFILETYPE_DOOR = (UInt32)(7)
const CURLFILETYPE_UNKNOWN = (UInt32)(8)
# end enum curlfiletype

mutable struct curl_fileinfo
    filename::Ptr{UInt8}
    filetype::curlfiletype
    time::time_t
    perm::UInt32
    uid::Cint
    gid::Cint
    size::curl_off_t
    hardlinks::Clong
    strings::Cvoid
    flags::UInt32
    b_data::Ptr{UInt8}
    b_size::Csize_t
    b_used::Csize_t
end

const curl_chunk_bgn_callback = Ptr{Cvoid}
const curl_chunk_end_callback = Ptr{Cvoid}
const curl_fnmatch_callback = Ptr{Cvoid}
const curl_seek_callback = Ptr{Cvoid}
const curl_read_callback = Ptr{Cvoid}

# begin enum curlsocktype
const curlsocktype = UInt32
const CURLSOCKTYPE_IPCXN = (UInt32)(0)
const CURLSOCKTYPE_ACCEPT = (UInt32)(1)
const CURLSOCKTYPE_LAST = (UInt32)(2)
# end enum curlsocktype

const curl_sockopt_callback = Ptr{Cvoid}

mutable struct curl_sockaddr
    family::Cint
    socktype::Cint
    protocol::Cint
    addrlen::UInt32
    addr::Cvoid
end

const curl_opensocket_callback = Ptr{Cvoid}
const curl_closesocket_callback = Ptr{Cvoid}

# begin enum curlioerr
const curlioerr = UInt32
const CURLIOE_OK = (UInt32)(0)
const CURLIOE_UNKNOWNCMD = (UInt32)(1)
const CURLIOE_FAILRESTART = (UInt32)(2)
const CURLIOE_LAST = (UInt32)(3)
# end enum curlioerr

# begin enum curliocmd
const curliocmd = UInt32
const CURLIOCMD_NOP = (UInt32)(0)
const CURLIOCMD_RESTARTREAD = (UInt32)(1)
const CURLIOCMD_LAST = (UInt32)(2)
# end enum curliocmd

const curl_ioctl_callback = Ptr{Cvoid}
const curl_malloc_callback = Ptr{Cvoid}
const curl_free_callback = Ptr{Cvoid}
const curl_realloc_callback = Ptr{Cvoid}
const curl_strdup_callback = Ptr{Cvoid}
const curl_calloc_callback = Ptr{Cvoid}

# begin enum curl_infotype
const curl_infotype = UInt32
const CURLINFO_TEXT = (UInt32)(0)
const CURLINFO_HEADER_IN = (UInt32)(1)
const CURLINFO_HEADER_OUT = (UInt32)(2)
const CURLINFO_DATA_IN = (UInt32)(3)
const CURLINFO_DATA_OUT = (UInt32)(4)
const CURLINFO_SSL_DATA_IN = (UInt32)(5)
const CURLINFO_SSL_DATA_OUT = (UInt32)(6)
const CURLINFO_END = (UInt32)(7)
# end enum curl_infotype

const curl_debug_callback = Ptr{Cvoid}

# begin enum CURLcode
const CURLcode = UInt32
const CURLE_OK = (UInt32)(0)
const CURLE_UNSUPPORTED_PROTOCOL = (UInt32)(1)
const CURLE_FAILED_INIT = (UInt32)(2)
const CURLE_URL_MALFORMAT = (UInt32)(3)
const CURLE_NOT_BUILT_IN = (UInt32)(4)
const CURLE_COULDNT_RESOLVE_PROXY = (UInt32)(5)
const CURLE_COULDNT_RESOLVE_HOST = (UInt32)(6)
const CURLE_COULDNT_CONNECT = (UInt32)(7)
const CURLE_WEIRD_SERVER_REPLY = (UInt32)(8)
const CURLE_REMOTE_ACCESS_DENIED = (UInt32)(9)
const CURLE_FTP_ACCEPT_FAILED = (UInt32)(10)
const CURLE_FTP_WEIRD_PASS_REPLY = (UInt32)(11)
const CURLE_FTP_ACCEPT_TIMEOUT = (UInt32)(12)
const CURLE_FTP_WEIRD_PASV_REPLY = (UInt32)(13)
const CURLE_FTP_WEIRD_227_FORMAT = (UInt32)(14)
const CURLE_FTP_CANT_GET_HOST = (UInt32)(15)
const CURLE_HTTP2 = (UInt32)(16)
const CURLE_FTP_COULDNT_SET_TYPE = (UInt32)(17)
const CURLE_PARTIAL_FILE = (UInt32)(18)
const CURLE_FTP_COULDNT_RETR_FILE = (UInt32)(19)
const CURLE_OBSOLETE20 = (UInt32)(20)
const CURLE_QUOTE_ERROR = (UInt32)(21)
const CURLE_HTTP_RETURNED_ERROR = (UInt32)(22)
const CURLE_WRITE_ERROR = (UInt32)(23)
const CURLE_OBSOLETE24 = (UInt32)(24)
const CURLE_UPLOAD_FAILED = (UInt32)(25)
const CURLE_READ_ERROR = (UInt32)(26)
const CURLE_OUT_OF_MEMORY = (UInt32)(27)
const CURLE_OPERATION_TIMEDOUT = (UInt32)(28)
const CURLE_OBSOLETE29 = (UInt32)(29)
const CURLE_FTP_PORT_FAILED = (UInt32)(30)
const CURLE_FTP_COULDNT_USE_REST = (UInt32)(31)
const CURLE_OBSOLETE32 = (UInt32)(32)
const CURLE_RANGE_ERROR = (UInt32)(33)
const CURLE_HTTP_POST_ERROR = (UInt32)(34)
const CURLE_SSL_CONNECT_ERROR = (UInt32)(35)
const CURLE_BAD_DOWNLOAD_RESUME = (UInt32)(36)
const CURLE_FILE_COULDNT_READ_FILE = (UInt32)(37)
const CURLE_LDAP_CANNOT_BIND = (UInt32)(38)
const CURLE_LDAP_SEARCH_FAILED = (UInt32)(39)
const CURLE_OBSOLETE40 = (UInt32)(40)
const CURLE_FUNCTION_NOT_FOUND = (UInt32)(41)
const CURLE_ABORTED_BY_CALLBACK = (UInt32)(42)
const CURLE_BAD_FUNCTION_ARGUMENT = (UInt32)(43)
const CURLE_OBSOLETE44 = (UInt32)(44)
const CURLE_INTERFACE_FAILED = (UInt32)(45)
const CURLE_OBSOLETE46 = (UInt32)(46)
const CURLE_TOO_MANY_REDIRECTS = (UInt32)(47)
const CURLE_UNKNOWN_OPTION = (UInt32)(48)
const CURLE_TELNET_OPTION_SYNTAX = (UInt32)(49)
const CURLE_OBSOLETE50 = (UInt32)(50)
const CURLE_PEER_FAILED_VERIFICATION = (UInt32)(51)
const CURLE_GOT_NOTHING = (UInt32)(52)
const CURLE_SSL_ENGINE_NOTFOUND = (UInt32)(53)
const CURLE_SSL_ENGINE_SETFAILED = (UInt32)(54)
const CURLE_SEND_ERROR = (UInt32)(55)
const CURLE_RECV_ERROR = (UInt32)(56)
const CURLE_OBSOLETE57 = (UInt32)(57)
const CURLE_SSL_CERTPROBLEM = (UInt32)(58)
const CURLE_SSL_CIPHER = (UInt32)(59)
const CURLE_SSL_CACERT = (UInt32)(60)
const CURLE_BAD_CONTENT_ENCODING = (UInt32)(61)
const CURLE_LDAP_INVALID_URL = (UInt32)(62)
const CURLE_FILESIZE_EXCEEDED = (UInt32)(63)
const CURLE_USE_SSL_FAILED = (UInt32)(64)
const CURLE_SEND_FAIL_REWIND = (UInt32)(65)
const CURLE_SSL_ENGINE_INITFAILED = (UInt32)(66)
const CURLE_LOGIN_DENIED = (UInt32)(67)
const CURLE_TFTP_NOTFOUND = (UInt32)(68)
const CURLE_TFTP_PERM = (UInt32)(69)
const CURLE_REMOTE_DISK_FULL = (UInt32)(70)
const CURLE_TFTP_ILLEGAL = (UInt32)(71)
const CURLE_TFTP_UNKNOWNID = (UInt32)(72)
const CURLE_REMOTE_FILE_EXISTS = (UInt32)(73)
const CURLE_TFTP_NOSUCHUSER = (UInt32)(74)
const CURLE_CONV_FAILED = (UInt32)(75)
const CURLE_CONV_REQD = (UInt32)(76)
const CURLE_SSL_CACERT_BADFILE = (UInt32)(77)
const CURLE_REMOTE_FILE_NOT_FOUND = (UInt32)(78)
const CURLE_SSH = (UInt32)(79)
const CURLE_SSL_SHUTDOWN_FAILED = (UInt32)(80)
const CURLE_AGAIN = (UInt32)(81)
const CURLE_SSL_CRL_BADFILE = (UInt32)(82)
const CURLE_SSL_ISSUER_ERROR = (UInt32)(83)
const CURLE_FTP_PRET_FAILED = (UInt32)(84)
const CURLE_RTSP_CSEQ_ERROR = (UInt32)(85)
const CURLE_RTSP_SESSION_ERROR = (UInt32)(86)
const CURLE_FTP_BAD_FILE_LIST = (UInt32)(87)
const CURLE_CHUNK_FAILED = (UInt32)(88)
const CURLE_NO_CONNECTION_AVAILABLE = (UInt32)(89)
const CURLE_SSL_PINNEDPUBKEYNOTMATCH = (UInt32)(90)
const CURLE_SSL_INVALIDCERTSTATUS = (UInt32)(91)
const CURLE_HTTP2_STREAM = (UInt32)(92)
const CURLE_RECURSIVE_API_CALL = (UInt32)(93)
const CURL_LAST = (UInt32)(94)
# end enum CURLcode

const curl_conv_callback = Ptr{Cvoid}
const curl_ssl_ctx_callback = Ptr{Cvoid}

# begin enum curl_proxytype
const curl_proxytype = UInt32
const CURLPROXY_HTTP = (UInt32)(0)
const CURLPROXY_HTTP_1_0 = (UInt32)(1)
const CURLPROXY_HTTPS = (UInt32)(2)
const CURLPROXY_SOCKS4 = (UInt32)(4)
const CURLPROXY_SOCKS5 = (UInt32)(5)
const CURLPROXY_SOCKS4A = (UInt32)(6)
const CURLPROXY_SOCKS5_HOSTNAME = (UInt32)(7)
# end enum curl_proxytype

const CURLSSH_AUTH_ANY = ~0
const CURLSSH_AUTH_NONE = 0
const CURLSSH_AUTH_PUBLICKEY = 1 << 0
const CURLSSH_AUTH_PASSWORD = 1 << 1
const CURLSSH_AUTH_HOST = 1 << 2
const CURLSSH_AUTH_KEYBOARD = 1 << 3
const CURLSSH_AUTH_AGENT = 1 << 4
const CURLSSH_AUTH_GSSAPI = 1 << 5
const CURLSSH_AUTH_DEFAULT = CURLSSH_AUTH_ANY
const CURLGSSAPI_DELEGATION_NONE = 0
const CURLGSSAPI_DELEGATION_POLICY_FLAG = 1 << 0
const CURLGSSAPI_DELEGATION_FLAG = 1 << 1
const CURL_ERROR_SIZE = 256

# begin enum curl_khtype
const curl_khtype = UInt32
const CURLKHTYPE_UNKNOWN = (UInt32)(0)
const CURLKHTYPE_RSA1 = (UInt32)(1)
const CURLKHTYPE_RSA = (UInt32)(2)
const CURLKHTYPE_DSS = (UInt32)(3)
const CURLKHTYPE_ECDSA = (UInt32)(4)
const CURLKHTYPE_ED25519 = (UInt32)(5)
# end enum curl_khtype

mutable struct curl_khkey
    key::Ptr{UInt8}
    len::Csize_t
    keytype::Cvoid
end

# begin enum curl_khstat
const curl_khstat = UInt32
const CURLKHSTAT_FINE_ADD_TO_FILE = (UInt32)(0)
const CURLKHSTAT_FINE = (UInt32)(1)
const CURLKHSTAT_REJECT = (UInt32)(2)
const CURLKHSTAT_DEFER = (UInt32)(3)
const CURLKHSTAT_LAST = (UInt32)(4)
# end enum curl_khstat

# begin enum curl_khmatch
const curl_khmatch = UInt32
const CURLKHMATCH_OK = (UInt32)(0)
const CURLKHMATCH_MISMATCH = (UInt32)(1)
const CURLKHMATCH_MISSING = (UInt32)(2)
const CURLKHMATCH_LAST = (UInt32)(3)
# end enum curl_khmatch

const curl_sshkeycallback = Ptr{Cvoid}

# begin enum curl_usessl
const curl_usessl = UInt32
const CURLUSESSL_NONE = (UInt32)(0)
const CURLUSESSL_TRY = (UInt32)(1)
const CURLUSESSL_CONTROL = (UInt32)(2)
const CURLUSESSL_ALL = (UInt32)(3)
const CURLUSESSL_LAST = (UInt32)(4)
# end enum curl_usessl

const CURLSSLOPT_ALLOW_BEAST = 1 << 0
const CURLSSLOPT_NO_REVOKE = 1 << 1
const CURL_HET_DEFAULT = Clong(200)

const curl_ftpssl = curl_usessl
const CURLFTPSSL_NONE = CURLUSESSL_NONE
const CURLFTPSSL_TRY = CURLUSESSL_TRY
const CURLFTPSSL_CONTROL = CURLUSESSL_CONTROL
const CURLFTPSSL_ALL = CURLUSESSL_ALL
const CURLFTPSSL_LAST = CURLUSESSL_LAST

# begin enum curl_ftpccc
const curl_ftpccc = UInt32
const CURLFTPSSL_CCC_NONE = (UInt32)(0)
const CURLFTPSSL_CCC_PASSIVE = (UInt32)(1)
const CURLFTPSSL_CCC_ACTIVE = (UInt32)(2)
const CURLFTPSSL_CCC_LAST = (UInt32)(3)
# end enum curl_ftpccc

# begin enum curl_ftpauth
const curl_ftpauth = UInt32
const CURLFTPAUTH_DEFAULT = (UInt32)(0)
const CURLFTPAUTH_SSL = (UInt32)(1)
const CURLFTPAUTH_TLS = (UInt32)(2)
const CURLFTPAUTH_LAST = (UInt32)(3)
# end enum curl_ftpauth

# begin enum curl_ftpcreatedir
const curl_ftpcreatedir = UInt32
const CURLFTP_CREATE_DIR_NONE = (UInt32)(0)
const CURLFTP_CREATE_DIR = (UInt32)(1)
const CURLFTP_CREATE_DIR_RETRY = (UInt32)(2)
const CURLFTP_CREATE_DIR_LAST = (UInt32)(3)
# end enum curl_ftpcreatedir

# begin enum curl_ftpmethod
const curl_ftpmethod = UInt32
const CURLFTPMETHOD_DEFAULT = (UInt32)(0)
const CURLFTPMETHOD_MULTICWD = (UInt32)(1)
const CURLFTPMETHOD_NOCWD = (UInt32)(2)
const CURLFTPMETHOD_SINGLECWD = (UInt32)(3)
const CURLFTPMETHOD_LAST = (UInt32)(4)
# end enum curl_ftpmethod

const CURLHEADER_UNIFIED = 0
const CURLHEADER_SEPARATE = 1 << 0
const CURLPROTO_HTTP = 1 << 0
const CURLPROTO_HTTPS = 1 << 1
const CURLPROTO_FTP = 1 << 2
const CURLPROTO_FTPS = 1 << 3
const CURLPROTO_SCP = 1 << 4
const CURLPROTO_SFTP = 1 << 5
const CURLPROTO_TELNET = 1 << 6
const CURLPROTO_LDAP = 1 << 7
const CURLPROTO_LDAPS = 1 << 8
const CURLPROTO_DICT = 1 << 9
const CURLPROTO_FILE = 1 << 10
const CURLPROTO_TFTP = 1 << 11
const CURLPROTO_IMAP = 1 << 12
const CURLPROTO_IMAPS = 1 << 13
const CURLPROTO_POP3 = 1 << 14
const CURLPROTO_POP3S = 1 << 15
const CURLPROTO_SMTP = 1 << 16
const CURLPROTO_SMTPS = 1 << 17
const CURLPROTO_RTSP = 1 << 18
const CURLPROTO_RTMP = 1 << 19
const CURLPROTO_RTMPT = 1 << 20
const CURLPROTO_RTMPE = 1 << 21
const CURLPROTO_RTMPTE = 1 << 22
const CURLPROTO_RTMPS = 1 << 23
const CURLPROTO_RTMPTS = 1 << 24
const CURLPROTO_GOPHER = 1 << 25
const CURLPROTO_SMB = 1 << 26
const CURLPROTO_SMBS = 1 << 27
const CURLPROTO_ALL = ~0
const CURLOPTTYPE_LONG = 0
const CURLOPTTYPE_OBJECTPOINT = 10000
const CURLOPTTYPE_STRINGPOINT = 10000
const CURLOPTTYPE_FUNCTIONPOINT = 20000
const CURLOPTTYPE_OFF_T = 30000

# begin enum CURLoption
const CURLoption = UInt32
const CURLOPT_WRITEDATA = (UInt32)(10001)
const CURLOPT_URL = (UInt32)(10002)
const CURLOPT_PORT = (UInt32)(3)
const CURLOPT_PROXY = (UInt32)(10004)
const CURLOPT_USERPWD = (UInt32)(10005)
const CURLOPT_PROXYUSERPWD = (UInt32)(10006)
const CURLOPT_RANGE = (UInt32)(10007)
const CURLOPT_READDATA = (UInt32)(10009)
const CURLOPT_ERRORBUFFER = (UInt32)(10010)
const CURLOPT_WRITEFUNCTION = (UInt32)(20011)
const CURLOPT_READFUNCTION = (UInt32)(20012)
const CURLOPT_TIMEOUT = (UInt32)(13)
const CURLOPT_INFILESIZE = (UInt32)(14)
const CURLOPT_POSTFIELDS = (UInt32)(10015)
const CURLOPT_REFERER = (UInt32)(10016)
const CURLOPT_FTPPORT = (UInt32)(10017)
const CURLOPT_USERAGENT = (UInt32)(10018)
const CURLOPT_LOW_SPEED_LIMIT = (UInt32)(19)
const CURLOPT_LOW_SPEED_TIME = (UInt32)(20)
const CURLOPT_RESUME_FROM = (UInt32)(21)
const CURLOPT_COOKIE = (UInt32)(10022)
const CURLOPT_HTTPHEADER = (UInt32)(10023)
const CURLOPT_HTTPPOST = (UInt32)(10024)
const CURLOPT_SSLCERT = (UInt32)(10025)
const CURLOPT_KEYPASSWD = (UInt32)(10026)
const CURLOPT_CRLF = (UInt32)(27)
const CURLOPT_QUOTE = (UInt32)(10028)
const CURLOPT_HEADERDATA = (UInt32)(10029)
const CURLOPT_COOKIEFILE = (UInt32)(10031)
const CURLOPT_SSLVERSION = (UInt32)(32)
const CURLOPT_TIMECONDITION = (UInt32)(33)
const CURLOPT_TIMEVALUE = (UInt32)(34)
const CURLOPT_CUSTOMREQUEST = (UInt32)(10036)
const CURLOPT_STDERR = (UInt32)(10037)
const CURLOPT_POSTQUOTE = (UInt32)(10039)
const CURLOPT_OBSOLETE40 = (UInt32)(10040)
const CURLOPT_VERBOSE = (UInt32)(41)
const CURLOPT_HEADER = (UInt32)(42)
const CURLOPT_NOPROGRESS = (UInt32)(43)
const CURLOPT_NOBODY = (UInt32)(44)
const CURLOPT_FAILONERROR = (UInt32)(45)
const CURLOPT_UPLOAD = (UInt32)(46)
const CURLOPT_POST = (UInt32)(47)
const CURLOPT_DIRLISTONLY = (UInt32)(48)
const CURLOPT_APPEND = (UInt32)(50)
const CURLOPT_NETRC = (UInt32)(51)
const CURLOPT_FOLLOWLOCATION = (UInt32)(52)
const CURLOPT_TRANSFERTEXT = (UInt32)(53)
const CURLOPT_PUT = (UInt32)(54)
const CURLOPT_PROGRESSFUNCTION = (UInt32)(20056)
const CURLOPT_PROGRESSDATA = (UInt32)(10057)
const CURLOPT_AUTOREFERER = (UInt32)(58)
const CURLOPT_PROXYPORT = (UInt32)(59)
const CURLOPT_POSTFIELDSIZE = (UInt32)(60)
const CURLOPT_HTTPPROXYTUNNEL = (UInt32)(61)
const CURLOPT_INTERFACE = (UInt32)(10062)
const CURLOPT_KRBLEVEL = (UInt32)(10063)
const CURLOPT_SSL_VERIFYPEER = (UInt32)(64)
const CURLOPT_CAINFO = (UInt32)(10065)
const CURLOPT_MAXREDIRS = (UInt32)(68)
const CURLOPT_FILETIME = (UInt32)(69)
const CURLOPT_TELNETOPTIONS = (UInt32)(10070)
const CURLOPT_MAXCONNECTS = (UInt32)(71)
const CURLOPT_OBSOLETE72 = (UInt32)(72)
const CURLOPT_FRESH_CONNECT = (UInt32)(74)
const CURLOPT_FORBID_REUSE = (UInt32)(75)
const CURLOPT_RANDOM_FILE = (UInt32)(10076)
const CURLOPT_EGDSOCKET = (UInt32)(10077)
const CURLOPT_CONNECTTIMEOUT = (UInt32)(78)
const CURLOPT_HEADERFUNCTION = (UInt32)(20079)
const CURLOPT_HTTPGET = (UInt32)(80)
const CURLOPT_SSL_VERIFYHOST = (UInt32)(81)
const CURLOPT_COOKIEJAR = (UInt32)(10082)
const CURLOPT_SSL_CIPHER_LIST = (UInt32)(10083)
const CURLOPT_HTTP_VERSION = (UInt32)(84)
const CURLOPT_FTP_USE_EPSV = (UInt32)(85)
const CURLOPT_SSLCERTTYPE = (UInt32)(10086)
const CURLOPT_SSLKEY = (UInt32)(10087)
const CURLOPT_SSLKEYTYPE = (UInt32)(10088)
const CURLOPT_SSLENGINE = (UInt32)(10089)
const CURLOPT_SSLENGINE_DEFAULT = (UInt32)(90)
const CURLOPT_DNS_USE_GLOBAL_CACHE = (UInt32)(91)
const CURLOPT_DNS_CACHE_TIMEOUT = (UInt32)(92)
const CURLOPT_PREQUOTE = (UInt32)(10093)
const CURLOPT_DEBUGFUNCTION = (UInt32)(20094)
const CURLOPT_DEBUGDATA = (UInt32)(10095)
const CURLOPT_COOKIESESSION = (UInt32)(96)
const CURLOPT_CAPATH = (UInt32)(10097)
const CURLOPT_BUFFERSIZE = (UInt32)(98)
const CURLOPT_NOSIGNAL = (UInt32)(99)
const CURLOPT_SHARE = (UInt32)(10100)
const CURLOPT_PROXYTYPE = (UInt32)(101)
const CURLOPT_ACCEPT_ENCODING = (UInt32)(10102)
const CURLOPT_PRIVATE = (UInt32)(10103)
const CURLOPT_HTTP200ALIASES = (UInt32)(10104)
const CURLOPT_UNRESTRICTED_AUTH = (UInt32)(105)
const CURLOPT_FTP_USE_EPRT = (UInt32)(106)
const CURLOPT_HTTPAUTH = (UInt32)(107)
const CURLOPT_SSL_CTX_FUNCTION = (UInt32)(20108)
const CURLOPT_SSL_CTX_DATA = (UInt32)(10109)
const CURLOPT_FTP_CREATE_MISSING_DIRS = (UInt32)(110)
const CURLOPT_PROXYAUTH = (UInt32)(111)
const CURLOPT_FTP_RESPONSE_TIMEOUT = (UInt32)(112)
const CURLOPT_IPRESOLVE = (UInt32)(113)
const CURLOPT_MAXFILESIZE = (UInt32)(114)
const CURLOPT_INFILESIZE_LARGE = (UInt32)(30115)
const CURLOPT_RESUME_FROM_LARGE = (UInt32)(30116)
const CURLOPT_MAXFILESIZE_LARGE = (UInt32)(30117)
const CURLOPT_NETRC_FILE = (UInt32)(10118)
const CURLOPT_USE_SSL = (UInt32)(119)
const CURLOPT_POSTFIELDSIZE_LARGE = (UInt32)(30120)
const CURLOPT_TCP_NODELAY = (UInt32)(121)
const CURLOPT_FTPSSLAUTH = (UInt32)(129)
const CURLOPT_IOCTLFUNCTION = (UInt32)(20130)
const CURLOPT_IOCTLDATA = (UInt32)(10131)
const CURLOPT_FTP_ACCOUNT = (UInt32)(10134)
const CURLOPT_COOKIELIST = (UInt32)(10135)
const CURLOPT_IGNORE_CONTENT_LENGTH = (UInt32)(136)
const CURLOPT_FTP_SKIP_PASV_IP = (UInt32)(137)
const CURLOPT_FTP_FILEMETHOD = (UInt32)(138)
const CURLOPT_LOCALPORT = (UInt32)(139)
const CURLOPT_LOCALPORTRANGE = (UInt32)(140)
const CURLOPT_CONNECT_ONLY = (UInt32)(141)
const CURLOPT_CONV_FROM_NETWORK_FUNCTION = (UInt32)(20142)
const CURLOPT_CONV_TO_NETWORK_FUNCTION = (UInt32)(20143)
const CURLOPT_CONV_FROM_UTF8_FUNCTION = (UInt32)(20144)
const CURLOPT_MAX_SEND_SPEED_LARGE = (UInt32)(30145)
const CURLOPT_MAX_RECV_SPEED_LARGE = (UInt32)(30146)
const CURLOPT_FTP_ALTERNATIVE_TO_USER = (UInt32)(10147)
const CURLOPT_SOCKOPTFUNCTION = (UInt32)(20148)
const CURLOPT_SOCKOPTDATA = (UInt32)(10149)
const CURLOPT_SSL_SESSIONID_CACHE = (UInt32)(150)
const CURLOPT_SSH_AUTH_TYPES = (UInt32)(151)
const CURLOPT_SSH_PUBLIC_KEYFILE = (UInt32)(10152)
const CURLOPT_SSH_PRIVATE_KEYFILE = (UInt32)(10153)
const CURLOPT_FTP_SSL_CCC = (UInt32)(154)
const CURLOPT_TIMEOUT_MS = (UInt32)(155)
const CURLOPT_CONNECTTIMEOUT_MS = (UInt32)(156)
const CURLOPT_HTTP_TRANSFER_DECODING = (UInt32)(157)
const CURLOPT_HTTP_CONTENT_DECODING = (UInt32)(158)
const CURLOPT_NEW_FILE_PERMS = (UInt32)(159)
const CURLOPT_NEW_DIRECTORY_PERMS = (UInt32)(160)
const CURLOPT_POSTREDIR = (UInt32)(161)
const CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 = (UInt32)(10162)
const CURLOPT_OPENSOCKETFUNCTION = (UInt32)(20163)
const CURLOPT_OPENSOCKETDATA = (UInt32)(10164)
const CURLOPT_COPYPOSTFIELDS = (UInt32)(10165)
const CURLOPT_PROXY_TRANSFER_MODE = (UInt32)(166)
const CURLOPT_SEEKFUNCTION = (UInt32)(20167)
const CURLOPT_SEEKDATA = (UInt32)(10168)
const CURLOPT_CRLFILE = (UInt32)(10169)
const CURLOPT_ISSUERCERT = (UInt32)(10170)
const CURLOPT_ADDRESS_SCOPE = (UInt32)(171)
const CURLOPT_CERTINFO = (UInt32)(172)
const CURLOPT_USERNAME = (UInt32)(10173)
const CURLOPT_PASSWORD = (UInt32)(10174)
const CURLOPT_PROXYUSERNAME = (UInt32)(10175)
const CURLOPT_PROXYPASSWORD = (UInt32)(10176)
const CURLOPT_NOPROXY = (UInt32)(10177)
const CURLOPT_TFTP_BLKSIZE = (UInt32)(178)
const CURLOPT_SOCKS5_GSSAPI_SERVICE = (UInt32)(10179)
const CURLOPT_SOCKS5_GSSAPI_NEC = (UInt32)(180)
const CURLOPT_PROTOCOLS = (UInt32)(181)
const CURLOPT_REDIR_PROTOCOLS = (UInt32)(182)
const CURLOPT_SSH_KNOWNHOSTS = (UInt32)(10183)
const CURLOPT_SSH_KEYFUNCTION = (UInt32)(20184)
const CURLOPT_SSH_KEYDATA = (UInt32)(10185)
const CURLOPT_MAIL_FROM = (UInt32)(10186)
const CURLOPT_MAIL_RCPT = (UInt32)(10187)
const CURLOPT_FTP_USE_PRET = (UInt32)(188)
const CURLOPT_RTSP_REQUEST = (UInt32)(189)
const CURLOPT_RTSP_SESSION_ID = (UInt32)(10190)
const CURLOPT_RTSP_STREAM_URI = (UInt32)(10191)
const CURLOPT_RTSP_TRANSPORT = (UInt32)(10192)
const CURLOPT_RTSP_CLIENT_CSEQ = (UInt32)(193)
const CURLOPT_RTSP_SERVER_CSEQ = (UInt32)(194)
const CURLOPT_INTERLEAVEDATA = (UInt32)(10195)
const CURLOPT_INTERLEAVEFUNCTION = (UInt32)(20196)
const CURLOPT_WILDCARDMATCH = (UInt32)(197)
const CURLOPT_CHUNK_BGN_FUNCTION = (UInt32)(20198)
const CURLOPT_CHUNK_END_FUNCTION = (UInt32)(20199)
const CURLOPT_FNMATCH_FUNCTION = (UInt32)(20200)
const CURLOPT_CHUNK_DATA = (UInt32)(10201)
const CURLOPT_FNMATCH_DATA = (UInt32)(10202)
const CURLOPT_RESOLVE = (UInt32)(10203)
const CURLOPT_TLSAUTH_USERNAME = (UInt32)(10204)
const CURLOPT_TLSAUTH_PASSWORD = (UInt32)(10205)
const CURLOPT_TLSAUTH_TYPE = (UInt32)(10206)
const CURLOPT_TRANSFER_ENCODING = (UInt32)(207)
const CURLOPT_CLOSESOCKETFUNCTION = (UInt32)(20208)
const CURLOPT_CLOSESOCKETDATA = (UInt32)(10209)
const CURLOPT_GSSAPI_DELEGATION = (UInt32)(210)
const CURLOPT_DNS_SERVERS = (UInt32)(10211)
const CURLOPT_ACCEPTTIMEOUT_MS = (UInt32)(212)
const CURLOPT_TCP_KEEPALIVE = (UInt32)(213)
const CURLOPT_TCP_KEEPIDLE = (UInt32)(214)
const CURLOPT_TCP_KEEPINTVL = (UInt32)(215)
const CURLOPT_SSL_OPTIONS = (UInt32)(216)
const CURLOPT_MAIL_AUTH = (UInt32)(10217)
const CURLOPT_SASL_IR = (UInt32)(218)
const CURLOPT_XFERINFOFUNCTION = (UInt32)(20219)
const CURLOPT_XOAUTH2_BEARER = (UInt32)(10220)
const CURLOPT_DNS_INTERFACE = (UInt32)(10221)
const CURLOPT_DNS_LOCAL_IP4 = (UInt32)(10222)
const CURLOPT_DNS_LOCAL_IP6 = (UInt32)(10223)
const CURLOPT_LOGIN_OPTIONS = (UInt32)(10224)
const CURLOPT_SSL_ENABLE_NPN = (UInt32)(225)
const CURLOPT_SSL_ENABLE_ALPN = (UInt32)(226)
const CURLOPT_EXPECT_100_TIMEOUT_MS = (UInt32)(227)
const CURLOPT_PROXYHEADER = (UInt32)(10228)
const CURLOPT_HEADEROPT = (UInt32)(229)
const CURLOPT_PINNEDPUBLICKEY = (UInt32)(10230)
const CURLOPT_UNIX_SOCKET_PATH = (UInt32)(10231)
const CURLOPT_SSL_VERIFYSTATUS = (UInt32)(232)
const CURLOPT_SSL_FALSESTART = (UInt32)(233)
const CURLOPT_PATH_AS_IS = (UInt32)(234)
const CURLOPT_PROXY_SERVICE_NAME = (UInt32)(10235)
const CURLOPT_SERVICE_NAME = (UInt32)(10236)
const CURLOPT_PIPEWAIT = (UInt32)(237)
const CURLOPT_DEFAULT_PROTOCOL = (UInt32)(10238)
const CURLOPT_STREAM_WEIGHT = (UInt32)(239)
const CURLOPT_STREAM_DEPENDS = (UInt32)(10240)
const CURLOPT_STREAM_DEPENDS_E = (UInt32)(10241)
const CURLOPT_TFTP_NO_OPTIONS = (UInt32)(242)
const CURLOPT_CONNECT_TO = (UInt32)(10243)
const CURLOPT_TCP_FASTOPEN = (UInt32)(244)
const CURLOPT_KEEP_SENDING_ON_ERROR = (UInt32)(245)
const CURLOPT_PROXY_CAINFO = (UInt32)(10246)
const CURLOPT_PROXY_CAPATH = (UInt32)(10247)
const CURLOPT_PROXY_SSL_VERIFYPEER = (UInt32)(248)
const CURLOPT_PROXY_SSL_VERIFYHOST = (UInt32)(249)
const CURLOPT_PROXY_SSLVERSION = (UInt32)(250)
const CURLOPT_PROXY_TLSAUTH_USERNAME = (UInt32)(10251)
const CURLOPT_PROXY_TLSAUTH_PASSWORD = (UInt32)(10252)
const CURLOPT_PROXY_TLSAUTH_TYPE = (UInt32)(10253)
const CURLOPT_PROXY_SSLCERT = (UInt32)(10254)
const CURLOPT_PROXY_SSLCERTTYPE = (UInt32)(10255)
const CURLOPT_PROXY_SSLKEY = (UInt32)(10256)
const CURLOPT_PROXY_SSLKEYTYPE = (UInt32)(10257)
const CURLOPT_PROXY_KEYPASSWD = (UInt32)(10258)
const CURLOPT_PROXY_SSL_CIPHER_LIST = (UInt32)(10259)
const CURLOPT_PROXY_CRLFILE = (UInt32)(10260)
const CURLOPT_PROXY_SSL_OPTIONS = (UInt32)(261)
const CURLOPT_PRE_PROXY = (UInt32)(10262)
const CURLOPT_PROXY_PINNEDPUBLICKEY = (UInt32)(10263)
const CURLOPT_ABSTRACT_UNIX_SOCKET = (UInt32)(10264)
const CURLOPT_SUPPRESS_CONNECT_HEADERS = (UInt32)(265)
const CURLOPT_REQUEST_TARGET = (UInt32)(10266)
const CURLOPT_SOCKS5_AUTH = (UInt32)(267)
const CURLOPT_SSH_COMPRESSION = (UInt32)(268)
const CURLOPT_MIMEPOST = (UInt32)(10269)
const CURLOPT_TIMEVALUE_LARGE = (UInt32)(30270)
const CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS = (UInt32)(271)
const CURLOPT_RESOLVER_START_FUNCTION = (UInt32)(20272)
const CURLOPT_RESOLVER_START_DATA = (UInt32)(10273)
const CURLOPT_HAPROXYPROTOCOL = (UInt32)(274)
const CURLOPT_DNS_SHUFFLE_ADDRESSES = (UInt32)(275)
const CURLOPT_TLS13_CIPHERS = (UInt32)(10276)
const CURLOPT_PROXY_TLS13_CIPHERS = (UInt32)(10277)
const CURLOPT_DISALLOW_USERNAME_IN_URL = (UInt32)(278)
const CURLOPT_MAXAGE_CONN = UInt32(288)
const CURLOPT_LASTENTRY = (UInt32)(10299)
# end enum CURLoption

const CURLOPT_XFERINFODATA = CURLOPT_PROGRESSDATA
const CURLOPT_SERVER_RESPONSE_TIMEOUT = CURLOPT_FTP_RESPONSE_TIMEOUT
const CURLOPT_POST301 = CURLOPT_POSTREDIR
const CURLOPT_SSLKEYPASSWD = CURLOPT_KEYPASSWD
const CURLOPT_FTPAPPEND = CURLOPT_APPEND
const CURLOPT_FTPLISTONLY = CURLOPT_DIRLISTONLY
const CURLOPT_FTP_SSL = CURLOPT_USE_SSL
const CURLOPT_SSLCERTPASSWD = CURLOPT_KEYPASSWD
const CURLOPT_KRB4LEVEL = CURLOPT_KRBLEVEL
const CURL_IPRESOLVE_WHATEVER = 0
const CURL_IPRESOLVE_V4 = 1
const CURL_IPRESOLVE_V6 = 2
const CURLOPT_RTSPHEADER = CURLOPT_HTTPHEADER

# begin enum ANONYMOUS
const CURL_HTTP_VERSION_NONE = (UInt32)(0)
const CURL_HTTP_VERSION_1_0 = (UInt32)(1)
const CURL_HTTP_VERSION_1_1 = (UInt32)(2)
const CURL_HTTP_VERSION_2_0 = (UInt32)(3)
const CURL_HTTP_VERSION_2TLS = (UInt32)(4)
const CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE = (UInt32)(5)
const CURL_HTTP_VERSION_LAST = (UInt32)(6)
# end enum ANONYMOUS

const CURL_HTTP_VERSION_2 = CURL_HTTP_VERSION_2_0

# begin enum ANONYMOUS
const CURL_RTSPREQ_NONE = (UInt32)(0)
const CURL_RTSPREQ_OPTIONS = (UInt32)(1)
const CURL_RTSPREQ_DESCRIBE = (UInt32)(2)
const CURL_RTSPREQ_ANNOUNCE = (UInt32)(3)
const CURL_RTSPREQ_SETUP = (UInt32)(4)
const CURL_RTSPREQ_PLAY = (UInt32)(5)
const CURL_RTSPREQ_PAUSE = (UInt32)(6)
const CURL_RTSPREQ_TEARDOWN = (UInt32)(7)
const CURL_RTSPREQ_GET_PARAMETER = (UInt32)(8)
const CURL_RTSPREQ_SET_PARAMETER = (UInt32)(9)
const CURL_RTSPREQ_RECORD = (UInt32)(10)
const CURL_RTSPREQ_RECEIVE = (UInt32)(11)
const CURL_RTSPREQ_LAST = (UInt32)(12)
# end enum ANONYMOUS

# begin enum CURL_NETRC_OPTION
const CURL_NETRC_OPTION = UInt32
const CURL_NETRC_IGNORED = (UInt32)(0)
const CURL_NETRC_OPTIONAL = (UInt32)(1)
const CURL_NETRC_REQUIRED = (UInt32)(2)
const CURL_NETRC_LAST = (UInt32)(3)
# end enum CURL_NETRC_OPTION

# begin enum ANONYMOUS
const CURL_SSLVERSION_DEFAULT = (UInt32)(0)
const CURL_SSLVERSION_TLSv1 = (UInt32)(1)
const CURL_SSLVERSION_SSLv2 = (UInt32)(2)
const CURL_SSLVERSION_SSLv3 = (UInt32)(3)
const CURL_SSLVERSION_TLSv1_0 = (UInt32)(4)
const CURL_SSLVERSION_TLSv1_1 = (UInt32)(5)
const CURL_SSLVERSION_TLSv1_2 = (UInt32)(6)
const CURL_SSLVERSION_TLSv1_3 = (UInt32)(7)
const CURL_SSLVERSION_LAST = (UInt32)(8)
# end enum ANONYMOUS

# begin enum ANONYMOUS
const CURL_SSLVERSION_MAX_NONE = (UInt32)(0)
const CURL_SSLVERSION_MAX_DEFAULT = (UInt32)(65536)
const CURL_SSLVERSION_MAX_TLSv1_0 = (UInt32)(262144)
const CURL_SSLVERSION_MAX_TLSv1_1 = (UInt32)(327680)
const CURL_SSLVERSION_MAX_TLSv1_2 = (UInt32)(393216)
const CURL_SSLVERSION_MAX_TLSv1_3 = (UInt32)(458752)
const CURL_SSLVERSION_MAX_LAST = (UInt32)(524288)
# end enum ANONYMOUS

# begin enum CURL_TLSAUTH
const CURL_TLSAUTH = UInt32
const CURL_TLSAUTH_NONE = (UInt32)(0)
const CURL_TLSAUTH_SRP = (UInt32)(1)
const CURL_TLSAUTH_LAST = (UInt32)(2)
# end enum CURL_TLSAUTH

const CURL_REDIR_GET_ALL = 0
const CURL_REDIR_POST_301 = 1
const CURL_REDIR_POST_302 = 2
const CURL_REDIR_POST_303 = 4
const CURL_REDIR_POST_ALL = (CURL_REDIR_POST_301 | CURL_REDIR_POST_302) | CURL_REDIR_POST_303

# begin enum curl_TimeCond
const curl_TimeCond = UInt32
const CURL_TIMECOND_NONE = (UInt32)(0)
const CURL_TIMECOND_IFMODSINCE = (UInt32)(1)
const CURL_TIMECOND_IFUNMODSINCE = (UInt32)(2)
const CURL_TIMECOND_LASTMOD = (UInt32)(3)
const CURL_TIMECOND_LAST = (UInt32)(4)
# end enum curl_TimeCond

struct curl_mime_s end

const curl_mime = Cvoid

struct curl_mimepart_s end

const curl_mimepart = Cvoid

# begin enum CURLformoption
const CURLformoption = UInt32
const CURLFORM_NOTHING = (UInt32)(0)
const CURLFORM_COPYNAME = (UInt32)(1)
const CURLFORM_PTRNAME = (UInt32)(2)
const CURLFORM_NAMELENGTH = (UInt32)(3)
const CURLFORM_COPYCONTENTS = (UInt32)(4)
const CURLFORM_PTRCONTENTS = (UInt32)(5)
const CURLFORM_CONTENTSLENGTH = (UInt32)(6)
const CURLFORM_FILECONTENT = (UInt32)(7)
const CURLFORM_ARRAY = (UInt32)(8)
const CURLFORM_OBSOLETE = (UInt32)(9)
const CURLFORM_FILE = (UInt32)(10)
const CURLFORM_BUFFER = (UInt32)(11)
const CURLFORM_BUFFERPTR = (UInt32)(12)
const CURLFORM_BUFFERLENGTH = (UInt32)(13)
const CURLFORM_CONTENTTYPE = (UInt32)(14)
const CURLFORM_CONTENTHEADER = (UInt32)(15)
const CURLFORM_FILENAME = (UInt32)(16)
const CURLFORM_END = (UInt32)(17)
const CURLFORM_OBSOLETE2 = (UInt32)(18)
const CURLFORM_STREAM = (UInt32)(19)
const CURLFORM_CONTENTLEN = (UInt32)(20)
const CURLFORM_LASTENTRY = (UInt32)(21)
# end enum CURLformoption

mutable struct curl_forms
    option::CURLformoption
    value::Ptr{UInt8}
end

# begin enum CURLFORMcode
const CURLFORMcode = UInt32
const CURL_FORMADD_OK = (UInt32)(0)
const CURL_FORMADD_MEMORY = (UInt32)(1)
const CURL_FORMADD_OPTION_TWICE = (UInt32)(2)
const CURL_FORMADD_NULL = (UInt32)(3)
const CURL_FORMADD_UNKNOWN_OPTION = (UInt32)(4)
const CURL_FORMADD_INCOMPLETE = (UInt32)(5)
const CURL_FORMADD_ILLEGAL_ARRAY = (UInt32)(6)
const CURL_FORMADD_DISABLED = (UInt32)(7)
const CURL_FORMADD_LAST = (UInt32)(8)
# end enum CURLFORMcode

const curl_formget_callback = Ptr{Cvoid}

mutable struct curl_slist
    data::Ptr{UInt8}
    next::Ptr{Cvoid}
end

const curl_ssl_backend = Cvoid

# begin enum CURLsslset
const CURLsslset = UInt32
const CURLSSLSET_OK = (UInt32)(0)
const CURLSSLSET_UNKNOWN_BACKEND = (UInt32)(1)
const CURLSSLSET_TOO_LATE = (UInt32)(2)
const CURLSSLSET_NO_BACKENDS = (UInt32)(3)
# end enum CURLsslset

mutable struct curl_certinfo
    num_of_certs::Cint
    certinfo::Ptr{Ptr{Cvoid}}
end

mutable struct curl_tlssessioninfo
    backend::curl_sslbackend
    internals::Ptr{Cvoid}
end

const CURLINFO_STRING = 0x00100000
const CURLINFO_LONG = 0x00200000
const CURLINFO_DOUBLE = 0x00300000
const CURLINFO_SLIST = 0x00400000
const CURLINFO_PTR = 0x00400000
const CURLINFO_SOCKET = 0x00500000
const CURLINFO_OFF_T = 0x00600000
const CURLINFO_MASK = 0x000fffff
const CURLINFO_TYPEMASK = 0x00f00000

# begin enum CURLINFO
const CURLINFO = UInt32
const CURLINFO_NONE = (UInt32)(0)
const CURLINFO_EFFECTIVE_URL = (UInt32)(1048577)
const CURLINFO_RESPONSE_CODE = (UInt32)(2097154)
const CURLINFO_TOTAL_TIME = (UInt32)(3145731)
const CURLINFO_NAMELOOKUP_TIME = (UInt32)(3145732)
const CURLINFO_CONNECT_TIME = (UInt32)(3145733)
const CURLINFO_PRETRANSFER_TIME = (UInt32)(3145734)
const CURLINFO_SIZE_UPLOAD = (UInt32)(3145735)
const CURLINFO_SIZE_UPLOAD_T = (UInt32)(6291463)
const CURLINFO_SIZE_DOWNLOAD = (UInt32)(3145736)
const CURLINFO_SIZE_DOWNLOAD_T = (UInt32)(6291464)
const CURLINFO_SPEED_DOWNLOAD = (UInt32)(3145737)
const CURLINFO_SPEED_DOWNLOAD_T = (UInt32)(6291465)
const CURLINFO_SPEED_UPLOAD = (UInt32)(3145738)
const CURLINFO_SPEED_UPLOAD_T = (UInt32)(6291466)
const CURLINFO_HEADER_SIZE = (UInt32)(2097163)
const CURLINFO_REQUEST_SIZE = (UInt32)(2097164)
const CURLINFO_SSL_VERIFYRESULT = (UInt32)(2097165)
const CURLINFO_FILETIME = (UInt32)(2097166)
const CURLINFO_FILETIME_T = (UInt32)(6291470)
const CURLINFO_CONTENT_LENGTH_DOWNLOAD = (UInt32)(3145743)
const CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = (UInt32)(6291471)
const CURLINFO_CONTENT_LENGTH_UPLOAD = (UInt32)(3145744)
const CURLINFO_CONTENT_LENGTH_UPLOAD_T = (UInt32)(6291472)
const CURLINFO_STARTTRANSFER_TIME = (UInt32)(3145745)
const CURLINFO_CONTENT_TYPE = (UInt32)(1048594)
const CURLINFO_REDIRECT_TIME = (UInt32)(3145747)
const CURLINFO_REDIRECT_COUNT = (UInt32)(2097172)
const CURLINFO_PRIVATE = (UInt32)(1048597)
const CURLINFO_HTTP_CONNECTCODE = (UInt32)(2097174)
const CURLINFO_HTTPAUTH_AVAIL = (UInt32)(2097175)
const CURLINFO_PROXYAUTH_AVAIL = (UInt32)(2097176)
const CURLINFO_OS_ERRNO = (UInt32)(2097177)
const CURLINFO_NUM_CONNECTS = (UInt32)(2097178)
const CURLINFO_SSL_ENGINES = (UInt32)(4194331)
const CURLINFO_COOKIELIST = (UInt32)(4194332)
const CURLINFO_LASTSOCKET = (UInt32)(2097181)
const CURLINFO_FTP_ENTRY_PATH = (UInt32)(1048606)
const CURLINFO_REDIRECT_URL = (UInt32)(1048607)
const CURLINFO_PRIMARY_IP = (UInt32)(1048608)
const CURLINFO_APPCONNECT_TIME = (UInt32)(3145761)
const CURLINFO_CERTINFO = (UInt32)(4194338)
const CURLINFO_CONDITION_UNMET = (UInt32)(2097187)
const CURLINFO_RTSP_SESSION_ID = (UInt32)(1048612)
const CURLINFO_RTSP_CLIENT_CSEQ = (UInt32)(2097189)
const CURLINFO_RTSP_SERVER_CSEQ = (UInt32)(2097190)
const CURLINFO_RTSP_CSEQ_RECV = (UInt32)(2097191)
const CURLINFO_PRIMARY_PORT = (UInt32)(2097192)
const CURLINFO_LOCAL_IP = (UInt32)(1048617)
const CURLINFO_LOCAL_PORT = (UInt32)(2097194)
const CURLINFO_TLS_SESSION = (UInt32)(4194347)
const CURLINFO_ACTIVESOCKET = (UInt32)(5242924)
const CURLINFO_TLS_SSL_PTR = (UInt32)(4194349)
const CURLINFO_HTTP_VERSION = (UInt32)(2097198)
const CURLINFO_PROXY_SSL_VERIFYRESULT = (UInt32)(2097199)
const CURLINFO_PROTOCOL = (UInt32)(2097200)
const CURLINFO_SCHEME = (UInt32)(1048625)
const CURLINFO_TOTAL_TIME_T = (UInt32)(6291506)
const CURLINFO_NAMELOOKUP_TIME_T = (UInt32)(6291507)
const CURLINFO_CONNECT_TIME_T = (UInt32)(6291508)
const CURLINFO_PRETRANSFER_TIME_T = (UInt32)(6291509)
const CURLINFO_STARTTRANSFER_TIME_T = (UInt32)(6291510)
const CURLINFO_REDIRECT_TIME_T = (UInt32)(6291511)
const CURLINFO_APPCONNECT_TIME_T = (UInt32)(6291512)
const CURLINFO_LASTONE = (UInt32)(56)
# end enum CURLINFO

const CURLINFO_HTTP_CODE = CURLINFO_RESPONSE_CODE

# begin enum curl_closepolicy
const curl_closepolicy = UInt32
const CURLCLOSEPOLICY_NONE = (UInt32)(0)
const CURLCLOSEPOLICY_OLDEST = (UInt32)(1)
const CURLCLOSEPOLICY_LEAST_RECENTLY_USED = (UInt32)(2)
const CURLCLOSEPOLICY_LEAST_TRAFFIC = (UInt32)(3)
const CURLCLOSEPOLICY_SLOWEST = (UInt32)(4)
const CURLCLOSEPOLICY_CALLBACK = (UInt32)(5)
const CURLCLOSEPOLICY_LAST = (UInt32)(6)
# end enum curl_closepolicy

const CURL_GLOBAL_SSL = 1 << 0
const CURL_GLOBAL_WIN32 = 1 << 1
const CURL_GLOBAL_ALL = CURL_GLOBAL_SSL | CURL_GLOBAL_WIN32
const CURL_GLOBAL_NOTHING = 0
const CURL_GLOBAL_DEFAULT = CURL_GLOBAL_ALL
const CURL_GLOBAL_ACK_EINTR = 1 << 2

# begin enum curl_lock_data
const curl_lock_data = UInt32
const CURL_LOCK_DATA_NONE = (UInt32)(0)
const CURL_LOCK_DATA_SHARE = (UInt32)(1)
const CURL_LOCK_DATA_COOKIE = (UInt32)(2)
const CURL_LOCK_DATA_DNS = (UInt32)(3)
const CURL_LOCK_DATA_SSL_SESSION = (UInt32)(4)
const CURL_LOCK_DATA_CONNECT = (UInt32)(5)
const CURL_LOCK_DATA_PSL = (UInt32)(6)
const CURL_LOCK_DATA_LAST = (UInt32)(7)
# end enum curl_lock_data

# begin enum curl_lock_access
const curl_lock_access = UInt32
const CURL_LOCK_ACCESS_NONE = (UInt32)(0)
const CURL_LOCK_ACCESS_SHARED = (UInt32)(1)
const CURL_LOCK_ACCESS_SINGLE = (UInt32)(2)
const CURL_LOCK_ACCESS_LAST = (UInt32)(3)
# end enum curl_lock_access

const curl_lock_function = Ptr{Cvoid}
const curl_unlock_function = Ptr{Cvoid}

# begin enum CURLSHcode
const CURLSHcode = UInt32
const CURLSHE_OK = (UInt32)(0)
const CURLSHE_BAD_OPTION = (UInt32)(1)
const CURLSHE_IN_USE = (UInt32)(2)
const CURLSHE_INVALID = (UInt32)(3)
const CURLSHE_NOMEM = (UInt32)(4)
const CURLSHE_NOT_BUILT_IN = (UInt32)(5)
const CURLSHE_LAST = (UInt32)(6)
# end enum CURLSHcode

# begin enum CURLSHoption
const CURLSHoption = UInt32
const CURLSHOPT_NONE = (UInt32)(0)
const CURLSHOPT_SHARE = (UInt32)(1)
const CURLSHOPT_UNSHARE = (UInt32)(2)
const CURLSHOPT_LOCKFUNC = (UInt32)(3)
const CURLSHOPT_UNLOCKFUNC = (UInt32)(4)
const CURLSHOPT_USERDATA = (UInt32)(5)
const CURLSHOPT_LAST = (UInt32)(6)
# end enum CURLSHoption

# begin enum CURLversion
const CURLversion = UInt32
const CURLVERSION_FIRST = (UInt32)(0)
const CURLVERSION_SECOND = (UInt32)(1)
const CURLVERSION_THIRD = (UInt32)(2)
const CURLVERSION_FOURTH = (UInt32)(3)
const CURLVERSION_FIFTH = (UInt32)(4)
const CURLVERSION_LAST = (UInt32)(5)
# end enum CURLversion

const CURLVERSION_NOW = CURLVERSION_FIFTH

mutable struct curl_version_info_data
    age::CURLversion
    version::Ptr{UInt8}
    version_num::UInt32
    host::Ptr{UInt8}
    features::Int32
    ssl_version::Ptr{UInt8}
    ssl_version_num::Int32
    libz_version::Ptr{UInt8}
    protocols::Ptr{Ptr{UInt8}}
    ares::Ptr{UInt8}
    ares_num::Int32
    libidn::Ptr{UInt8}
    iconv_ver_num::Int32
    libssh_version::Ptr{UInt8}
    brotli_ver_num::UInt32
    brotli_version::Ptr{UInt8}
end

const CURL_VERSION_IPV6 = 1 << 0
const CURL_VERSION_KERBEROS4 = 1 << 1
const CURL_VERSION_SSL = 1 << 2
const CURL_VERSION_LIBZ = 1 << 3
const CURL_VERSION_NTLM = 1 << 4
const CURL_VERSION_GSSNEGOTIATE = 1 << 5
const CURL_VERSION_DEBUG = 1 << 6
const CURL_VERSION_ASYNCHDNS = 1 << 7
const CURL_VERSION_SPNEGO = 1 << 8
const CURL_VERSION_LARGEFILE = 1 << 9
const CURL_VERSION_IDN = 1 << 10
const CURL_VERSION_SSPI = 1 << 11
const CURL_VERSION_CONV = 1 << 12
const CURL_VERSION_CURLDEBUG = 1 << 13
const CURL_VERSION_TLSAUTH_SRP = 1 << 14
const CURL_VERSION_NTLM_WB = 1 << 15
const CURL_VERSION_HTTP2 = 1 << 16
const CURL_VERSION_GSSAPI = 1 << 17
const CURL_VERSION_KERBEROS5 = 1 << 18
const CURL_VERSION_UNIX_SOCKETS = 1 << 19
const CURL_VERSION_PSL = 1 << 20
const CURL_VERSION_HTTPS_PROXY = 1 << 21
const CURL_VERSION_MULTI_SSL = 1 << 22
const CURL_VERSION_BROTLI = 1 << 23
const CURLPAUSE_RECV = 1 << 0
const CURLPAUSE_RECV_CONT = 0
const CURLPAUSE_SEND = 1 << 2
const CURLPAUSE_SEND_CONT = 0
const CURLPAUSE_ALL = CURLPAUSE_RECV | CURLPAUSE_SEND
const CURLPAUSE_CONT = CURLPAUSE_RECV_CONT | CURLPAUSE_SEND_CONT

const CURLE_OBSOLETE16 = CURLE_HTTP2
const CURLE_OBSOLETE10 = CURLE_FTP_ACCEPT_FAILED
const CURLE_OBSOLETE12 = CURLE_FTP_ACCEPT_TIMEOUT

const CURLOPT_ENCODING = CURLOPT_ACCEPT_ENCODING
const CURLE_FTP_WEIRD_SERVER_REPLY = CURLE_WEIRD_SERVER_REPLY
const CURLE_UNKNOWN_TELNET_OPTION = CURLE_UNKNOWN_OPTION
const CURLE_SSL_PEER_CERTIFICATE = CURLE_PEER_FAILED_VERIFICATION
const CURLE_OBSOLETE = CURLE_OBSOLETE50
const CURLE_BAD_PASSWORD_ENTERED = CURLE_OBSOLETE46
const CURLE_BAD_CALLING_ORDER = CURLE_OBSOLETE44
const CURLE_FTP_USER_PASSWORD_INCORRECT = CURLE_OBSOLETE10
const CURLE_FTP_CANT_RECONNECT = CURLE_OBSOLETE16
const CURLE_FTP_COULDNT_GET_SIZE = CURLE_OBSOLETE32
const CURLE_FTP_COULDNT_SET_ASCII = CURLE_OBSOLETE29
const CURLE_FTP_WEIRD_USER_REPLY = CURLE_OBSOLETE12
const CURLE_FTP_WRITE_ERROR = CURLE_OBSOLETE20
const CURLE_LIBRARY_NOT_FOUND = CURLE_OBSOLETE40
const CURLE_MALFORMAT_USER = CURLE_OBSOLETE24
const CURLE_SHARE_IN_USE = CURLE_OBSOLETE57
const CURLE_URL_MALFORMAT_USER = CURLE_NOT_BUILT_IN
const CURLE_FTP_ACCESS_DENIED = CURLE_REMOTE_ACCESS_DENIED
const CURLE_FTP_COULDNT_SET_BINARY = CURLE_FTP_COULDNT_SET_TYPE
const CURLE_FTP_QUOTE_ERROR = CURLE_QUOTE_ERROR
const CURLE_TFTP_DISKFULL = CURLE_REMOTE_DISK_FULL
const CURLE_TFTP_EXISTS = CURLE_REMOTE_FILE_EXISTS
const CURLE_HTTP_RANGE_ERROR = CURLE_RANGE_ERROR
const CURLE_FTP_SSL_FAILED = CURLE_USE_SSL_FAILED
const CURLE_OPERATION_TIMEOUTED = CURLE_OPERATION_TIMEDOUT
const CURLE_HTTP_NOT_FOUND = CURLE_HTTP_RETURNED_ERROR
const CURLE_HTTP_PORT_FAILED = CURLE_INTERFACE_FAILED
const CURLE_FTP_COULDNT_STOR_FILE = CURLE_UPLOAD_FAILED
const CURLE_FTP_PARTIAL_FILE = CURLE_PARTIAL_FILE
const CURLE_FTP_BAD_DOWNLOAD_RESUME = CURLE_BAD_DOWNLOAD_RESUME
const CURLE_ALREADY_COMPLETE = 99999
const CURLOPT_FILE = CURLOPT_WRITEDATA
const CURLOPT_INFILE = CURLOPT_READDATA
const CURLOPT_WRITEHEADER = CURLOPT_HEADERDATA
const CURLOPT_WRITEINFO = CURLOPT_OBSOLETE40
const CURLOPT_CLOSEPOLICY = CURLOPT_OBSOLETE72

# multi.h

const CURLM = Cvoid

# begin enum CURLMcode
const CURLMcode = Cint
const CURLM_CALL_MULTI_PERFORM = (Int32)(-1)
const CURLM_OK = (Int32)(0)
const CURLM_BAD_HANDLE = (Int32)(1)
const CURLM_BAD_EASY_HANDLE = (Int32)(2)
const CURLM_OUT_OF_MEMORY = (Int32)(3)
const CURLM_INTERNAL_ERROR = (Int32)(4)
const CURLM_BAD_SOCKET = (Int32)(5)
const CURLM_UNKNOWN_OPTION = (Int32)(6)
const CURLM_ADDED_ALREADY = (Int32)(7)
const CURLM_RECURSIVE_API_CALL = (Int32)(8)
const CURLM_LAST = (Int32)(9)
# end enum CURLMcode

const CURLM_CALL_MULTI_SOCKET = CURLM_CALL_MULTI_PERFORM
const CURLPIPE_NOTHING = Clong(0)
const CURLPIPE_HTTP1 = Clong(1)
const CURLPIPE_MULTIPLEX = Clong(2)

# begin enum CURLMSG
const CURLMSG = UInt32
const CURLMSG_NONE = (UInt32)(0)
const CURLMSG_DONE = (UInt32)(1)
const CURLMSG_LAST = (UInt32)(2)
# end enum CURLMSG

mutable struct CURLMsg
    msg::CURLMSG
    easy_handle::Ptr{CURL}
    data::Cvoid
end

const CURL_WAIT_POLLIN = 0x0001
const CURL_WAIT_POLLPRI = 0x0002
const CURL_WAIT_POLLOUT = 0x0004

mutable struct curl_waitfd
    fd::curl_socket_t
    events::Int16
    revents::Int16
end

const CURL_POLL_NONE = 0
const CURL_POLL_IN = 1
const CURL_POLL_OUT = 2
const CURL_POLL_INOUT = 3
const CURL_POLL_REMOVE = 4
const CURL_SOCKET_TIMEOUT = CURL_SOCKET_BAD
const CURL_CSELECT_IN = 0x01
const CURL_CSELECT_OUT = 0x02
const CURL_CSELECT_ERR = 0x04

const curl_socket_callback = Ptr{Cvoid}
const curl_multi_timer_callback = Ptr{Cvoid}

# begin enum CURLMoption
const CURLMoption = UInt32
const CURLMOPT_SOCKETFUNCTION = (UInt32)(20001)
const CURLMOPT_SOCKETDATA = (UInt32)(10002)
const CURLMOPT_PIPELINING = (UInt32)(3)
const CURLMOPT_TIMERFUNCTION = (UInt32)(20004)
const CURLMOPT_TIMERDATA = (UInt32)(10005)
const CURLMOPT_MAXCONNECTS = (UInt32)(6)
const CURLMOPT_MAX_HOST_CONNECTIONS = (UInt32)(7)
const CURLMOPT_MAX_PIPELINE_LENGTH = (UInt32)(8)
const CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE = (UInt32)(30009)
const CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE = (UInt32)(30010)
const CURLMOPT_PIPELINING_SITE_BL = (UInt32)(10011)
const CURLMOPT_PIPELINING_SERVER_BL = (UInt32)(10012)
const CURLMOPT_MAX_TOTAL_CONNECTIONS = (UInt32)(13)
const CURLMOPT_PUSHFUNCTION = (UInt32)(20014)
const CURLMOPT_PUSHDATA = (UInt32)(10015)
const CURLMOPT_LASTENTRY = (UInt32)(10016)
# end enum CURLMoption

const CURL_PUSH_OK = 0
const CURL_PUSH_DENY = 1

struct curl_pushheaders end

const curl_push_callback = Ptr{Cvoid}

ext: jl


text:
const h     = 6.626_070_040e-34*J*s
const h_bar = h / (2pi)
const electron_rest_mass = 9.10938356e-31 * kg
const c     = 299_792_458.0 * m / s
const electron_rest_energy = c^2 * electron_rest_mass
const r_c   = h_bar / (c*electron_rest_mass) # reduced compton wavelength of electron
const alpha = 1/137.04 # fine structure constant


text:
module TestSetfield

include("preamble.jl")
using Setfield: @lens, Lens, Setfield, set

struct LensWrapper <: Lens
    lens::Lens
end

Setfield.get(obj, lens::LensWrapper) = get(obj, lens.lens)
Setfield.set(obj, lens::LensWrapper, value) = set(obj, lens.lens, value)

mutable struct Mutable
    a
    b
end

@testset "nested mutable" begin
    x = orig = Mutable((x=Mutable(1, 2), y=3), 4);
    @set!! x.a.x.a = 10;
    @test x.a.x.a == orig.a.x.a == 10
end

@testset "arrays" begin
    v = [1, 2, Mutable(1, 2)]
    x = orig = Mutable((x=v, y=3), 4);
    @set!! x.a.x[3].a = 10;
    @test x.a.x[3].a == orig.a.x[3].a == 10
    @test x.a.x === v
end

@testset "index lenses" begin
    @static if isdefined(Setfield, :ConstIndexLens)
        @testset "ConstIndexLens" begin
            v = [1, 2, 3]
            i = j = 1
            @set!! v[$(i + j)] = 20
            @test v[2] == 20
        end
    end
    @testset "DynamicIndexLens" begin
        v = [1, 2, 3]
        @set!! v[end] = 30
        @test v[3] == 30
    end
end

@testset "default to immutable" begin
    x = Mutable((x=Mutable(1, 2), y=3), 4);
    l = prefermutation(LensWrapper(@lens _.a.x.a))
    y = set(x, l, 10)
    @test y !== x
    @test y.a.x.a == 10
end

end  # module


text:
module LibIIO

using Libdl
using CEnum
include("ctypes.jl")
include("libiio_common.jl")
include("libiio_api.jl")
include("libiio_utils.jl")

end # module


text:
using Luna

a = 13e-6
gas = :Ar
pres = 5
flength = 15e-2

τfwhm = 30e-15
λ0 = 800e-9
energy = 1e-6

grid = Grid.EnvGrid(flength, λ0, (160e-9, 3000e-9), 1e-12)

m = Capillary.MarcatiliMode(a, gas, pres, loss=false, model=:full)
aeff = let m=m
    z -> Modes.Aeff(m, z=z)
end

densityfun = let dens0=PhysData.density(gas, pres)
    z -> dens0
end

linop, βfun!, β1, αfun = LinearOps.make_const_linop(grid, m, λ0)

responses = (Nonlinear.Kerr_env(PhysData.γ3_gas(gas)),)

inputs = Fields.GaussField(λ0=λ0, τfwhm=τfwhm, energy=energy)
Eω, transform, FT = Luna.setup(grid, densityfun, responses, inputs, βfun!, aeff)

statsfun = Stats.default(grid, Eω, m, linop, transform; gas=gas, windows=((150e-9, 300e-9),))
output = Output.MemoryOutput(0, grid.zmax, 201, statsfun)

Luna.run(Eω, grid, linop, transform, FT, output)

##
Plotting.pygui(true)
Plotting.stats(output)
Plotting.prop_2D(output)
Plotting.time_1D(output, [5e-2, 10e-2, 11e-2])
Plotting.time_1D(output, [5e-2, 10e-2, 11e-2], y=:Et, oversampling=16)
Plotting.spec_1D(output, [5e-2, 10e-2, 11e-2])


text:
include("print_no_obj.jl")
include("print_info.jl")
include("print_maximin.jl")
include("print_cc_maximin.jl")

function print_neighbourhood(x::Neighbourhood)
    Printf.@printf("\n  f : %5.3f", x.f)
    Printf.@printf("\n  infeas :	[")
    map(x -> Printf.@printf(" %5.1f", x), x.infeas)
    Printf.@printf("    ]")
    Printf.@printf("\n  overlaps :	[")
    map(x -> Printf.@printf("  %5.1f", x), x.ol)
    Printf.@printf("    ]")
    Printf.@printf("\n  item use :	[")
    map(x -> Printf.@printf("  %5.1f", x), x.iu)
    Printf.@printf("    ]\n")
end


text:
# Titania - polaron mobility; for Titania and other corrosion relevant oxides
# Just an initial sketch - before getting the major-leagues (DFT calcs) out.
println("   My Oberon! what visions have I seen!")
println("   Methought I was enamour'd of an ass.")

push!(LOAD_PATH,"../src/") # load module from local directory

using PolaronMobility

##### load in library routines... #####
# Plot figures with Plots, which defaults to Pyplot backend
#using Plots
#default(grid=false) # No silly dotted grid lines
#default(size=(400,300)) # A good small size for two-column EPS output
#default(size=(800,600)) # Nice size for small-ish PNGs for slides

# Physical constants
const hbar = const ħ = 1.05457162825e-34;          # kg m2 / s
const eV = const q = const ElectronVolt = 1.602176487e-19;                         # kg m2 / s2
const me=MassElectron = 9.10938188e-31;                          # kg
const Boltzmann = const kB =  1.3806504e-23;                  # kg m2 / K s2
const ε_0 = 8.854E-12 #Units: C2N−1m−2, permittivity of free space

#####
# Call simulation

Trange=100:50:600

# Rutile - spectra and effective mass from:
# Hendry et al. PRB 69, 081101 (2004)
# DOI: https://doi.org/10.1103/PhysRevB.69.081101
f=24E12 # p.3 LHS, 2nd para
meff=1.2 # ¬  - perpendicular # p.3 LHS, 4th para
#meff=0.6 # || - parallel

# F. A. GRANT
# Rev. Mod. Phys. 31, 646 – Published 1 July 1959
# DOI: https://doi.org/10.1103/RevModPhys.31.646
# Early paper --> some of this static dielectric will be free charges in the defective Titania
ϵ_static=173.0 # p. 650 LHS
ϵ_optic=8.4

# Optical dielectric constants via:
# https://www.azom.com/article.aspx?ArticleID=1179 - optical properties
ϵ_optic=2.49^2 # Anatase: 6.2

anatase=polaronmobility(Trange, ϵ_optic, ϵ_static, f, meff)
savepolaron("anatase",anatase)

ϵ_optic=2.903^2 # Rutile: 8.427

rutile=polaronmobility(Trange, ϵ_optic, ϵ_static, f, meff)
savepolaron("rutile",rutile)

# Mobility of Electronic Charge Carriers in Titanium Dioxide
# T. Bak, M. K. Nowotny, L. R. Sheppard, and J. Nowotny*
# J. Phys. Chem. C 2008, 112, 12981–12987
# DOI: https://doi.org/10.1021/jp801028j
# Lots of nice comparison; single crystal mobility data; Arrhenius plots etc.

# Materials Project DFT dielectric constants
# mp-554278 - Bg=2.677 eV
ϵ_optic=6.2
ϵ_static=35.47

rutilemp=polaronmobility(Trange, ϵ_optic, ϵ_static, f, meff)
savepolaron("rutile-mp",rutilemp)

# mp-52620 V2O5 - Bg=2.156 eV
ϵ_optic=4.88
ϵ_static=13.67

vanadium=polaronmobility(Trange, ϵ_optic, ϵ_static, f, meff)
savepolaron("vanadium",vanadium)

# mp-19399 Cr2O5 - Bg=2.437 eV
ϵ_optic=6.32
ϵ_static=11.05

chromium=polaronmobility(Trange, ϵ_optic, ϵ_static, f, meff)
savepolaron("chromium",chromium)

# mp-7048 Al2O3 - Bg=4.455
ϵ_optic=3.16
ϵ_static=8.98

alumina=polaronmobility(Trange, ϵ_optic, ϵ_static, f, meff)
savepolaron("alumina",alumina)

println("That's me!")

# Rather basic analysis via the shell:
# Extract 300 K data point:
# grep "^300" *.dat | awk '{print $1,$4}'

# Have a look at 'alpha' parameter'
# grep Alpha *.dat


text:
function query_projection(id)
    rq = HTTP.request("GET", "http://api.brain-map.org/api/v2/data/WellKnownFile/query.json?criteria=well_known_file_type[name\$eq'ImagesResampledTo25MicronARA'][attachable_id\$eq$id]")
    data = JSON.parse(String(rq.data))
    data["msg"][1]
end

"""
    download_projection(id, filename)

Download a volumetric image for a particular connectivity (projection)
dataset specified by its experiment `id` (available from the banner in
http://connectivity.brain-map.org/). Specify the `filename` used for
saving the dataset.
"""
function download_projection(id, filename)
    info = query_projection(id)
    download("http://api.brain-map.org"*info["download_link"], filename)
end


text:
__precompile__()
"""
A package that provides a new REPL that has syntax highlighting,
bracket matching and other nifty features.
"""
module OhMyREPL

using Base.CoreLogging: global_logger
using Tokenize
using Crayons

export colorscheme!, colorschemes, enable_autocomplete_brackets, enable_highlight_markdown, test_colorscheme

include("repl_pass.jl")
include("repl.jl")
include("passes/Passes.jl")

include("BracketInserter.jl")
include("prompt.jl")

import .BracketInserter.enable_autocomplete_brackets

include("overprint.jl")
include("progress.jl")
include("logger_core.jl")

function colorscheme!(name::String)
    Passes.SyntaxHighlighter.activate!(Passes.SyntaxHighlighter.SYNTAX_HIGHLIGHTER_SETTINGS,
                                       name)
end

function colorschemes()
    show(Passes.SyntaxHighlighter.SYNTAX_HIGHLIGHTER_SETTINGS)
end

const TEST_STR = """

function funcdef(x::Float64, y::Int64)
    y = 100_000
    x = :foo
    s = "I am a happy string"
    @time 1+1
    #= Comments look like this =#
    z = funccall(x, y)
    5 * 3 + 2 - 1
end
"""

function test_colorscheme(name::String, str::String = TEST_STR)
    syntaxpass = get_pass(PASS_HANDLER, "SyntaxHighlighter")
    active = syntaxpass.active
    try
        colorscheme!(name)
        test_pass(syntaxpass, str)
    finally
        syntaxpass.active = active
    end
    return
end

function test_colorscheme(cs::Passes.SyntaxHighlighter.ColorScheme, str::String = TEST_STR)
    syntaxpass = get_pass(PASS_HANDLER, "SyntaxHighlighter")
    active = syntaxpass.active
    name = "plzdontnameyourcolorschemethis"
    try
        Passes.SyntaxHighlighter.add!(syntaxpass, name, cs)
        colorscheme!(name)
        test_pass(syntaxpass, str)
    finally
        syntaxpass.active = active
        if haskey(syntaxpass.schemes, name)
            delete!(syntaxpass.schemes, name)
        end
    end
    return
end

showpasses(io::IO = stdout) = Base.show(io, PASS_HANDLER)

const HIGHLIGHT_MARKDOWN = Ref(true)
enable_highlight_markdown(v::Bool) = HIGHLIGHT_MARKDOWN[] = v

function __init__()
    options = Base.JLOptions()
    # command-line -- do not activate OhMyREPL functionality
    if (options.isinteractive != 1) && options.commands != C_NULL
        return
    end

    # Set up the logger
    global_logger(OhMyLogger(stderr))
    atexit() do
        logger = global_logger()
        if logger isa OhMyLogger
            global_logger(OhMyLogger(Core.stderr, min_enabled_level(logger)))
        end
    end

    # Setup REPL functionality
    if isdefined(Base, :active_repl)
        Prompt.insert_keybindings()
    else
        atreplinit() do repl
            repl.interface = REPL.setup_interface(repl)
            Prompt.insert_keybindings()
            update_interface(repl.interface)
            main_mode = repl.interface.modes[1]
            p = repl.interface.modes[5]
            # These are inserted here because we only want to insert them for the Julia mode
            d = Dict(
            # Up Arrow
            "\e[A" => (s,o...)-> begin
                REPL.LineEdit.edit_move_up(s) || LineEdit.enter_prefix_search(s, p, true)
                Prompt.rewrite_with_ANSI(s)
            end,
            # Down Arrow
            "\e[B" => (s,o...)-> begin
                 REPL.LineEdit.edit_move_down(s) || LineEdit.enter_prefix_search(s, p, false)
                 Prompt.rewrite_with_ANSI(s)
            end
            )
            main_mode.keymap_dict = LineEdit.keymap([d, main_mode.keymap_dict])
        end
    end

    if ccall(:jl_generating_output, Cint, ()) == 0
        include(joinpath(@__DIR__, "refresh_lines.jl"))
        include(joinpath(@__DIR__, "output_prompt_overwrite.jl"))
        include(joinpath(@__DIR__, "MarkdownHighlighter.jl"))
    end
end

end # module


text:
# General visualization utils

"""
    $(SIGNATURES)
Initialize empty visualizer window with home axis.  New browser window will be opened based on `show=true`.
"""
function startDefaultVisualization(;show::Bool=true,
                                    draworigin::Bool=true,
                                    originscale::Float64=1.0  )
    #
    global drawtransform

    viz = MeshCat.Visualizer()
    if draworigin
      setobject!( viz[:origin], Triad(originscale) )
      settransform!( viz[:origin], drawtransform ∘ (Translation(0.0, 0.0, 0.0) ∘ LinearMap( CTs.Quat(1.0,0,0,0))) )
    end

    # open a new browser tab if required
    show && open(viz)

    return viz
end

# tagsOnPoses = Dict{Symbol, Vector{TagkTl}}()

#