text:
#
# AT.jl --
#
# Implement Julia interface to Andor SDK.
#
#-------------------------------------------------------------------------------
#
# This file is part of "AndorCameras.jl" released under the MIT license.
#
# Copyright (C) 2017-2021, Éric Thiébaut.
#

"""
    using AndorCameras.AT

makes all Andor cameras constants and low-level functions available (they are
all prefixed with `AT.`).

"""
module AT

import ..WideStrings

# Types.
struct Handle; val::Cint; end # wrap AT_H in <atcore.h>
const BOOL    = Cint          # AT_BOOL in <atcore.h>
const INT     = Int64         # AT_64 in <atcore.h>
const BYTE    = UInt8         # AT_U8 in <atcore.h>
const FLOAT   = Cdouble       # for {Set,Get}Float
const STRING  = Cwstring      # constant string of wide characters (not output buffer)

struct Status
    func::Symbol
    code::Cint
end

# Constants.
let filename = joinpath(@__DIR__,"..","deps","deps.jl")
    isfile(filename) || error(
        "Package `AndorCameras` not properly installed.  Run ",
        "`Pkg.build(\"AndorCameras\")` to create file \"", filename, "\".")
    filename
end |> include

"""
    @call(func, rtype, proto, args...)

yields code to call C function `func` in Andor SDK library assuming `rtype`
is the return type of the function, `proto` is a tuple of the argument types
and `args...` are the arguments.

The return type `rtype` must be `Cint` and the produced code is wrapped so
that an instance of `AT.Status` is returned with the status code and the
symbolic name of the called SDK function.

"""
macro call(func, rtype, args...)
    rtype == :Cint || error("return type must be `Cint`")
    qfunc = quoted(func)
    expr = Expr(:call, :ccall, Expr(:tuple, qfunc, :_DLL), rtype, args...)
    return quote
        Status($qfunc, $(esc(expr)))
    end
end
quoted(x::QuoteNode) = x
quoted(x::Symbol) = QuoteNode(x)
quoted(x::AbstractString) = quoted(Symbol(x))

boolean(x::Ref{BOOL}) = (x[] != FALSE)

InitialiseLibrary() = @call(:AT_InitialiseLibrary, Cint, ())

FinaliseLibrary() = @call(:AT_FinaliseLibrary, Cint, ())

Open(index) = begin
    result = Ref{Handle}()
    status = @call(:AT_Open, Cint, (Cint, Ref{Handle}), index, result)
    return status, result[]
end

Close(handle) = @call(:AT_Close, Cint, (Handle,), handle)

# FIXME: not yet interfaced:
# typedef int (AT_EXP_CONV *FeatureCallback)(AT_H Hndl, const AT_WC* Feature, void* Context);
# int AT_EXP_CONV AT_RegisterFeatureCallback(AT_H Hndl, const AT_WC* Feature,
#                                            FeatureCallback EvCallback, void* Context);
# int AT_EXP_CONV AT_UnregisterFeatureCallback(AT_H Hndl, const AT_WC* Feature,
#                                              FeatureCallback EvCallback, void* Context);

IsImplemented(handle, feature) = begin
    result = Ref{BOOL}(FALSE)
    status = @call(:AT_IsImplemented, Cint, (Handle, STRING, Ref{BOOL}),
                   handle, feature, result)
    return status, boolean(result)
end

IsReadable(handle, feature) = begin
    result = Ref{BOOL}(FALSE)
    status = @call(:AT_IsReadable, Cint, (Handle, STRING, Ref{BOOL}),
                   handle, feature, result)
    return status, boolean(result)
end

IsWritable(handle, feature) = begin
    result = Ref{BOOL}(FALSE)
    status = @call(:AT_IsWritable, Cint, (Handle, STRING, Ref{BOOL}),
                   handle, feature, result)
    return status, boolean(result)
end

IsReadOnly(handle, feature) = begin
    result = Ref{BOOL}(FALSE)
    status = @call(:AT_IsReadOnly, Cint, (Handle, STRING, Ref{BOOL}),
                   handle, feature, result)
    return status, boolean(result)
end

SetInt(handle, feature, value::Integer) =
    @call(:AT_SetInt, Cint, (Handle, STRING, INT),
          handle, feature, value)

GetInt(handle, feature) = begin
    result = Ref{INT}()
    status = @call(:AT_GetInt, Cint, (Handle, STRING, Ref{INT}),
                   handle, feature, result)
    return status, result[]
end

GetIntMin(handle, feature) = begin
    result = Ref{INT}()
    status = @call(:AT_GetIntMin, Cint, (Handle, STRING, Ref{INT}),
                   handle, feature, result)
    return status, result[]
end

GetIntMax(handle, feature) = begin
    result = Ref{INT}();
    status = @call(:AT_GetIntMax, Cint, (Handle, STRING, Ref{INT}),
                   handle, feature, result)
    return status, result[]
end

SetFloat(handle, feature, value::Real) =
    @call(:AT_SetFloat, Cint, (Handle, STRING, FLOAT),
          handle, feature, value)

GetFloat(handle, feature) = begin
    result = Ref{FLOAT}()
    status = @call(:AT_GetFloat, Cint, (Handle, STRING, Ref{FLOAT}),
                   handle, feature, result)
    return status, result[]
end

GetFloatMin(handle, feature) = begin
    result = Ref{FLOAT}();
    status = @call(:AT_GetFloatMin, Cint, (Handle, STRING, Ref{FLOAT}),
                   handle, feature, result)
    return status, result[]
end

GetFloatMax(handle, feature) = begin
    result = Ref{FLOAT}()
    status = @call(:AT_GetFloatMax, Cint, (Handle, STRING, Ref{FLOAT}),
                   handle, feature, result)
    return status, result[]
end

SetBool(handle, feature, value::Bool) =
    @call(:AT_SetBool, Cint, (Handle, STRING, BOOL),
          handle, feature, (value ? TRUE : FALSE))

GetBool(handle, feature) = begin
    result = Ref{BOOL}();
    status = @call(:AT_GetBool, Cint, (Handle, STRING, Ref{BOOL}),
                   handle, feature, result)
    return status, boolean(result)
end

SetEnumIndex(handle, feature, enum::Integer) =
    @call(:AT_SetEnumIndex, Cint, (Handle, STRING, Cint),
          handle, feature, enum)

SetEnumerated(handle, feature, enum::Integer) =
    @call(:AT_SetEnumerated, Cint, (Handle, STRING, Cint),
          handle, feature, enum)

SetEnumString(handle, feature, value) =
    @call(:AT_SetEnumString, Cint, (Handle, STRING, STRING),
          handle, feature, value)

SetEnumeratedString(handle, feature, value) =
    @call(:AT_SetEnumeratedString, Cint, (Handle, STRING, STRING),
          handle, feature, value)

GetEnumIndex(handle, feature) = begin
    result = Ref{Cint}();
    status = @call(:AT_GetEnumIndex, Cint, (Handle, STRING, Ref{Cint}),
                   handle, feature, result)
    return status, Int(result[])
end

GetEnumerated(handle, feature) = begin
    result = Ref{Cint}()
    status = @call(:AT_GetEnumerated, Cint, (Handle, STRING, Ref{Cint}),
                   handle, feature, result)
    return status, Int(result[])
end

GetEnumCount(handle, feature) = begin
    result = Ref{Cint}()
    status = @call(:AT_GetEnumCount, Cint, (Handle, STRING, Ref{Cint}),
                   handle, feature, result)
    return status, Int(result[])
end

GetEnumeratedCount(handle, feature) = begin
    result = Ref{Cint}()
    status = @call(:AT_GetEnumeratedCount, Cint,
                   (Handle, STRING, Ref{Cint}),
                   handle, feature, result)
    return status, Int(result[])
end

IsEnumIndexAvailable(handle, feature, enum::Integer) = begin
    result = Ref{BOOL}()
    status = @call(:AT_IsEnumIndexAvailable, Cint,
                   (Handle, STRING, Cint, Ref{BOOL}),
                   handle, feature, enum, result)
    return status, boolean(result)
end

IsEnumeratedIndexAvailable(handle, feature, enum::Integer) = begin
    result = Ref{BOOL}()
    status = @call(:AT_IsEnumeratedIndexAvailable, Cint,
                   (Handle, STRING, Cint, Ref{BOOL}),
                   handle, feature, enum, result)
    return status, boolean(result)
end

IsEnumIndexImplemented(handle, feature, enum::Integer) = begin
    result = Ref{BOOL}()
    status = @call(:AT_IsEnumIndexImplemented, Cint,
                   (Handle, STRING, Cint, Ref{BOOL}),
                   handle, feature, enum, result)
    return status, boolean(result)
end

IsEnumeratedIndexImplemented(handle, feature, enum::Integer) = begin
    result = Ref{BOOL}()
    status = @call(:AT_IsEnumeratedIndexImplemented, Cint,
                   (Handle, STRING, Cint, Ref{BOOL}),
                   handle, feature, enum, result)
    return status, boolean(result)
end

GetEnumStringByIndex(handle, feature, enum::Integer, buf::DenseVector{Cwchar_t}) =
    GetEnumStringByIndex(handle, feature, enum, pointer(buf), length(buf))

GetEnumStringByIndex(handle, feature, enum::Integer, ptr::Ptr{Cwchar_t}, len::Integer) =
    @call(:AT_GetEnumStringByIndex, Cint,
          (Handle, STRING, Cint, Ptr{Cwchar_t}, Cint),
          handle, feature, enum, ptr, len)

GetEnumeratedString(handle, feature, enum::Integer, buf::DenseVector{Cwchar_t}) =
    GetEnumeratedString(handle, feature, enum, pointer(buf), length(buf))

GetEnumeratedString(handle, feature, enum::Integer, ptr::Ptr{Cwchar_t}, len::Integer) =
    @call(:AT_GetEnumeratedString, Cint,
          (Handle, STRING, Cint, Ptr{Cwchar_t}, Cint),
          handle, feature, enum, ptr, len)

Command(handle, feature) =
    @call(:AT_Command, Cint, (Handle, STRING), handle, feature)

SetString(handle, feature, value) =
    @call(:AT_SetString, Cint, (Handle, STRING, STRING),
          handle, feature, value)

GetString(handle, feature, buf::DenseVector{Cwchar_t}) =
    GetString(handle, feature, pointer(buf), length(buf))

GetString(handle, feature, ptr::Ptr{Cwchar_t}, len::Integer) =
    @call(:AT_GetString, Cint, (Handle, STRING, Ptr{Cwchar_t}, Cint),
          handle, feature, ptr, len)

GetStringMaxLength(handle, feature) = begin
    result = Ref{Cint}()
    status = @call(:AT_GetStringMaxLength, Cint,
                   (Handle, STRING, Ref{Cint}),
                   handle, feature, result)
    return status, Int(result[])
end

QueueBuffer(handle, buf::DenseVector{BYTE}) =
    QueueBuffer(handle, pointer(buf), sizeof(buf))

QueueBuffer(handle, ptr::Ptr{BYTE}, siz::Integer) =
    @call(:AT_QueueBuffer, Cint, (Handle, Ptr{BYTE}, Cint),
          handle, ptr, siz)

WaitBuffer(handle, timeout::Integer) = begin
    refptr = Ref{Ptr{BYTE}}()
    refsiz = Ref{Cint}()
    status = @call(:AT_WaitBuffer, Cint,
                   (Handle, Ref{Ptr{BYTE}}, Ref{Cint}, Cuint),
                   handle, refptr, refsiz, timeout)
    return status, refptr[], Int(refsiz[])
end

Flush(handle) = @call(:AT_Flush, Cint, (Handle,), handle)

end


text:
using CreditApprovalMockingStub
using Test

using Mocking
Mocking.activate()

@testset "Stubs" begin

# 1. setup patches

check_background_success_patch =
    @patch function check_background(first_name, last_name)
        println("check_background stub ==> simulating success")
        return true
    end

check_background_failure_patch =
    @patch function check_background(first_name, last_name)
        println("check_background stub ==> simulating failure")
        return false
    end

create_account_patch =
    @patch function create_account(first_name, last_name, email)
        println("create_account stub is called")
        return 314
    end

# 2. test

# test background check failure case
apply(check_background_failure_patch) do
    @test open_account("john", "doe", "jdoe@julia-is-awesome.com") == :failure
end

# test background check successful case
apply(check_background_success_patch) do
    @test open_account("peter", "doe", "pdoe@julia-is-awesome.com") == :success
end

# apply two stubs
# apply([check_background_success_patch, create_account_patch]) do
#     @test open_account("peter", "doe", "pdoe@julia-is-awesome.com") == :success
# end

end # testset

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

@testset "Mocking" begin

let check_background_call_count = 0,
    create_account_call_count = 0,
    notify_downstream_call_count = 0,
    notify_downstream_received_proper_account_number = false

    # 1. create mock function
    check_background_success_patch =
        @patch function check_background(first_name, last_name)
            check_background_call_count += 1
            println("check_background mock is called, simulating success")
            return true
        end

    create_account_patch =
        @patch function create_account(first_name, last_name, email)
            create_account_call_count += 1
            println("create account_number mock is called")
            return 314
        end

    notify_downstream_patch =
        @patch function notify_downstream(account_number)
            notify_downstream_call_count += 1
            if account_number > 0
                notify_downstream_received_proper_account_number = true
            end
            println("notify downstream mock is called")
            return nothing
        end

    # 2. establish expectation
    function verify()
        @test check_background_call_count  == 1
        @test create_account_call_count    == 1
        @test notify_downstream_call_count == 1
        @test notify_downstream_received_proper_account_number
    end

    # 3. exercise and test return value
    apply([check_background_success_patch, create_account_patch, notify_downstream_patch]) do
        @test open_account("peter", "doe", "pdoe@julia-is-awesome.com") == :success
    end

    # 4. verify our previous expectation
    verify()
end #let

end #testset

ext: jl


text:
try Pkg.clone("https://github.com/zsunberg/LightDarkPOMDPs.jl") end
Pkg.build("LightDarkPOMDPs")
using POMDPs
using LightDarkPOMDPs

Pkg.add("Reel");            using Reel
Pkg.add("POMDPToolbox");    using POMDPToolbox
Pkg.add("ParticleFilters"); using ParticleFilters
Pkg.add("Plots");           using Plots
Pkg.add("PyPlot");

pomdp = LightDark2D()
filter = SIRParticleFilter(pomdp, 10000, rng=MersenneTwister(5))
policy = FunctionPolicy(b -> -0.3*mean(b))

sim = HistoryRecorder(max_steps=30, rng=MersenneTwister(7))
hist = simulate(sim, pomdp, policy, filter)

pyplot()
frames = Frames(MIME("image/png"), fps=2)
for i in 1:length(hist)
    v = view(hist, 1:i)
    plot(pomdp, xlim=(-3, 10), ylim=(-4,8), aspect_ratio=:equal)
    plot!(v)
    b = belief_hist(v)[end]
    plt = plot!(b)
    push!(frames, plt);
    print(".")
end
println()
write("out.gif", frames);


text:
int_rules_6_7_8 = @theory begin

    #= ::Subsection::Closed:: =#
    #= 6.7.8*u*hyper(a+b*log(c*x^n))^p =#
    @apply_utils Antiderivative(sinh(~(b') * log(~(c') * (~x) ^ ~(n'))) ^ ~(p'), ~x) => Antiderivative(((~c * (~x) ^ ~n) ^ ~b / 2 - 1 / (2 * (~c * (~x) ^ ~n) ^ ~b)) ^ ~p, ~x) <-- FreeQ(~c, ~x) && RationalQ(~b, ~n, ~p)
    @apply_utils Antiderivative(cosh(~(b') * log(~(c') * (~x) ^ ~(n'))) ^ ~(p'), ~x) => Antiderivative(((~c * (~x) ^ ~n) ^ ~b / 2 + 1 / (2 * (~c * (~x) ^ ~n) ^ ~b)) ^ ~p, ~x) <-- FreeQ(~c, ~x) && RationalQ(~b, ~n, ~p)
    @apply_utils Antiderivative(sinh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))), ~x) => (-(~x) * sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n)))) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 - 1) + (~b * ~d * ~n * ~x * cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n)))) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 - 1) <-- FreeQ([~a, ~b, ~c, ~d, ~n], ~x) && NeQ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 - 1, 0)
    @apply_utils Antiderivative(cosh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))), ~x) => (-(~x) * cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n)))) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 - 1) + (~b * ~d * ~n * ~x * sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n)))) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 - 1) <-- FreeQ([~a, ~b, ~c, ~d, ~n], ~x) && NeQ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 - 1, 0)
    @apply_utils Antiderivative(sinh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~p, ~x) => ((-(~x) * sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ ~p) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - 1) + (~b * ~d * ~n * ~p * ~x * cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) * sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ (~p - 1)) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - 1)) - (((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * ~p * (~p - 1)) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - 1)) * Antiderivative(sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ (~p - 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~n], ~x) && (IGtQ(~p, 1) && NeQ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - 1, 0))
    @apply_utils Antiderivative(cosh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~p, ~x) => (-(~x) * cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ ~p) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - 1) + (~b * ~d * ~n * ~p * ~x * cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ (~p - 1) * sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n)))) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - 1) + (((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * ~p * (~p - 1)) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - 1)) * Antiderivative(cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ (~p - 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~n], ~x) && (IGtQ(~p, 1) && NeQ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - 1, 0))
    @apply_utils Antiderivative(sinh(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => (1 / (2 ^ ~p * (~b) ^ ~p * (~d) ^ ~p * (~p) ^ ~p)) * Antiderivative(ExpandIntegrand((-(ℯ ^ (-(~a) * ~b * (~d) ^ 2 * ~p)) * (~x) ^ (-1 / ~p) + ℯ ^ (~a * ~b * (~d) ^ 2 * ~p) * (~x) ^ (1 / ~p)) ^ ~p, ~x), ~x) <-- FreeQ([~a, ~b, ~d], ~x) && (IGtQ(~p, 0) && EqQ((~b) ^ 2 * (~d) ^ 2 * (~p) ^ 2 - 1, 0))
    @apply_utils Antiderivative(cosh(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => (1 / 2 ^ ~p) * Antiderivative(ExpandIntegrand((ℯ ^ (-(~a) * ~b * (~d) ^ 2 * ~p) * (~x) ^ (-1 / ~p) + ℯ ^ (~a * ~b * (~d) ^ 2 * ~p) * (~x) ^ (1 / ~p)) ^ ~p, ~x), ~x) <-- FreeQ([~a, ~b, ~d], ~x) && (IGtQ(~p, 0) && EqQ((~b) ^ 2 * (~d) ^ 2 * (~p) ^ 2 - 1, 0))
    #= Antiderivative(sinh((~d')*((~a')+(~b')*log((~x))))^(~p'),~x) :=  ℯ^(a*d*p)/2^p*Antiderivative(x^(b*d*p)*(1-1/(ℯ^(2*a*d)*x^(2*b*d)))^p,x) <--  FreeQ([a,b,d],x) && IntegerQ(p) =#
    #= Antiderivative(cosh((~d')*((~a')+(~b')*log((~x))))^(~p'),~x) :=  ℯ^(a*d*p)/2^p*Antiderivative(x^(b*d*p)*(1+1/(ℯ^(2*a*d)*x^(2*b*d)))^p,x) <--  FreeQ([a,b,d],x) && IntegerQ(p) =#
    @apply_utils Antiderivative(sinh(~(d') * (~(a') + ~(b') * log(~x))) ^ ~p, ~x) => (sinh(~d * (~a + ~b * log(~x))) ^ ~p / ((~x) ^ (~b * ~d * ~p) * (1 - 1 / (ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d))) ^ ~p)) * Antiderivative((~x) ^ (~b * ~d * ~p) * (1 - 1 / (ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d))) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~p], ~x) && Not(IntegerQ(~p))
    @apply_utils Antiderivative(cosh(~(d') * (~(a') + ~(b') * log(~x))) ^ ~p, ~x) => (cosh(~d * (~a + ~b * log(~x))) ^ ~p / ((~x) ^ (~b * ~d * ~p) * (1 + 1 / (ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d))) ^ ~p)) * Antiderivative((~x) ^ (~b * ~d * ~p) * (1 + 1 / (ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d))) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~p], ~x) && Not(IntegerQ(~p))
    @apply_utils Antiderivative(sinh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => (~x / (~n * (~c * (~x) ^ ~n) ^ (1 / ~n))) * Subst(Antiderivative((~x) ^ (1 / ~n - 1) * sinh(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative(cosh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => (~x / (~n * (~c * (~x) ^ ~n) ^ (1 / ~n))) * Subst(Antiderivative((~x) ^ (1 / ~n - 1) * cosh(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * sinh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))), ~x) => (-((~m + 1)) * (~e * ~x) ^ (~m + 1) * sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n)))) / ((~b) ^ 2 * (~d) ^ 2 * ~e * (~n) ^ 2 - ~e * (~m + 1) ^ 2) + (~b * ~d * ~n * (~e * ~x) ^ (~m + 1) * cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n)))) / ((~b) ^ 2 * (~d) ^ 2 * ~e * (~n) ^ 2 - ~e * (~m + 1) ^ 2) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~m, ~n], ~x) && NeQ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 - (~m + 1) ^ 2, 0)
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * cosh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))), ~x) => (-((~m + 1)) * (~e * ~x) ^ (~m + 1) * cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n)))) / ((~b) ^ 2 * (~d) ^ 2 * ~e * (~n) ^ 2 - ~e * (~m + 1) ^ 2) + (~b * ~d * ~n * (~e * ~x) ^ (~m + 1) * sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n)))) / ((~b) ^ 2 * (~d) ^ 2 * ~e * (~n) ^ 2 - ~e * (~m + 1) ^ 2) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~m, ~n], ~x) && NeQ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 - (~m + 1) ^ 2, 0)
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * sinh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~p, ~x) => ((-((~m + 1)) * (~e * ~x) ^ (~m + 1) * sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ ~p) / ((~b) ^ 2 * (~d) ^ 2 * ~e * (~n) ^ 2 * (~p) ^ 2 - ~e * (~m + 1) ^ 2) + (~b * ~d * ~n * ~p * (~e * ~x) ^ (~m + 1) * cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) * sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ (~p - 1)) / ((~b) ^ 2 * (~d) ^ 2 * ~e * (~n) ^ 2 * (~p) ^ 2 - ~e * (~m + 1) ^ 2)) - (((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * ~p * (~p - 1)) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - (~m + 1) ^ 2)) * Antiderivative((~e * ~x) ^ ~m * sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ (~p - 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~m, ~n], ~x) && (IGtQ(~p, 1) && NeQ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - (~m + 1) ^ 2, 0))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * cosh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~p, ~x) => (-((~m + 1)) * (~e * ~x) ^ (~m + 1) * cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ ~p) / ((~b) ^ 2 * (~d) ^ 2 * ~e * (~n) ^ 2 * (~p) ^ 2 - ~e * (~m + 1) ^ 2) + (~b * ~d * ~n * ~p * (~e * ~x) ^ (~m + 1) * sinh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) * cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ (~p - 1)) / ((~b) ^ 2 * (~d) ^ 2 * ~e * (~n) ^ 2 * (~p) ^ 2 - ~e * (~m + 1) ^ 2) + (((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * ~p * (~p - 1)) / ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - (~m + 1) ^ 2)) * Antiderivative((~e * ~x) ^ ~m * cosh(~d * (~a + ~b * log(~c * (~x) ^ ~n))) ^ (~p - 2), ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~m, ~n], ~x) && (IGtQ(~p, 1) && NeQ((~b) ^ 2 * (~d) ^ 2 * (~n) ^ 2 * (~p) ^ 2 - (~m + 1) ^ 2, 0))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * sinh(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => ((~m + 1) ^ ~p / (2 ^ ~p * (~b) ^ ~p * (~d) ^ ~p * (~p) ^ ~p)) * Antiderivative(ExpandIntegrand((~e * ~x) ^ ~m * (-(ℯ ^ ((-(~a) * ~b * (~d) ^ 2 * ~p) / (~m + 1))) * (~x) ^ (-((~m + 1)) / ~p) + ℯ ^ ((~a * ~b * (~d) ^ 2 * ~p) / (~m + 1)) * (~x) ^ ((~m + 1) / ~p)) ^ ~p, ~x), ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~m], ~x) && (IGtQ(~p, 0) && EqQ((~b) ^ 2 * (~d) ^ 2 * (~p) ^ 2 - (~m + 1) ^ 2, 0))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * cosh(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => (1 / 2 ^ ~p) * Antiderivative(ExpandIntegrand((~e * ~x) ^ ~m * (ℯ ^ ((-(~a) * ~b * (~d) ^ 2 * ~p) / (~m + 1)) * (~x) ^ (-((~m + 1)) / ~p) + ℯ ^ ((~a * ~b * (~d) ^ 2 * ~p) / (~m + 1)) * (~x) ^ ((~m + 1) / ~p)) ^ ~p, ~x), ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~m], ~x) && (IGtQ(~p, 0) && EqQ((~b) ^ 2 * (~d) ^ 2 * (~p) ^ 2 - (~m + 1) ^ 2, 0))
    #= Antiderivative(((~e')*(~x))^(~m')*sinh((~d')*((~a')+(~b')*log((~x))))^(~p'),~x) :=  ℯ^(a*d*p)/2^p*Antiderivative((e*x)^m*x^(b*d*p)*(1-1/(ℯ^(2*a*d)*x^(2*b*d)))^p,x) <--  FreeQ([a,b,d,e,m],x) && IntegerQ(p) =#
    #= Antiderivative(((~e')*(~x))^(~m')*cosh((~d')*((~a')+(~b')*log((~x))))^(~p'),~x) :=  ℯ^(a*d*p)/2^p*Antiderivative((e*x)^m*x^(b*d*p)*(1+1/(ℯ^(2*a*d)*x^(2*b*d)))^p,x) <--  FreeQ([a,b,d,e,m],x) && IntegerQ(p) =#
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * sinh(~(d') * (~(a') + ~(b') * log(~x))) ^ ~p, ~x) => (sinh(~d * (~a + ~b * log(~x))) ^ ~p / ((~x) ^ (~b * ~d * ~p) * (1 - 1 / (ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d))) ^ ~p)) * Antiderivative((~e * ~x) ^ ~m * (~x) ^ (~b * ~d * ~p) * (1 - 1 / (ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d))) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~m, ~p], ~x) && Not(IntegerQ(~p))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * cosh(~(d') * (~(a') + ~(b') * log(~x))) ^ ~p, ~x) => (cosh(~d * (~a + ~b * log(~x))) ^ ~p / ((~x) ^ (~b * ~d * ~p) * (1 + 1 / (ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d))) ^ ~p)) * Antiderivative((~e * ~x) ^ ~m * (~x) ^ (~b * ~d * ~p) * (1 + 1 / (ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d))) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~m, ~p], ~x) && Not(IntegerQ(~p))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * sinh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => ((~e * ~x) ^ (~m + 1) / (~e * ~n * (~c * (~x) ^ ~n) ^ ((~m + 1) / ~n))) * Subst(Antiderivative((~x) ^ ((~m + 1) / ~n - 1) * sinh(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~m, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * cosh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => ((~e * ~x) ^ (~m + 1) / (~e * ~n * (~c * (~x) ^ ~n) ^ ((~m + 1) / ~n))) * Subst(Antiderivative((~x) ^ ((~m + 1) / ~n - 1) * cosh(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~m, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative((~(h') * (~(e') + ~(f') * log(~(g') * (~x) ^ ~(m')))) ^ ~(q') * sinh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))), ~x) => ((-(ℯ ^ (-(~a) * ~d)) * (~c * (~x) ^ ~n) ^ (-(~b) * ~d)) / (2 * (~x) ^ (-(~b) * ~d * ~n))) * Antiderivative((~x) ^ (-(~b) * ~d * ~n) * (~h * (~e + ~f * log(~g * (~x) ^ ~m))) ^ ~q, ~x) + ((ℯ ^ (~a * ~d) * (~c * (~x) ^ ~n) ^ (~b * ~d)) / (2 * (~x) ^ (~b * ~d * ~n))) * Antiderivative((~x) ^ (~b * ~d * ~n) * (~h * (~e + ~f * log(~g * (~x) ^ ~m))) ^ ~q, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~g, ~h, ~m, ~n, ~q], ~x)
    @apply_utils Antiderivative((~(h') * (~(e') + ~(f') * log(~(g') * (~x) ^ ~(m')))) ^ ~(q') * cosh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))), ~x) => ((ℯ ^ (-(~a) * ~d) * (~c * (~x) ^ ~n) ^ (-(~b) * ~d)) / (2 * (~x) ^ (-(~b) * ~d * ~n))) * Antiderivative((~x) ^ (-(~b) * ~d * ~n) * (~h * (~e + ~f * log(~g * (~x) ^ ~m))) ^ ~q, ~x) + ((ℯ ^ (~a * ~d) * (~c * (~x) ^ ~n) ^ (~b * ~d)) / (2 * (~x) ^ (~b * ~d * ~n))) * Antiderivative((~x) ^ (~b * ~d * ~n) * (~h * (~e + ~f * log(~g * (~x) ^ ~m))) ^ ~q, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~g, ~h, ~m, ~n, ~q], ~x)
    @apply_utils Antiderivative((~(i') * ~x) ^ ~(r') * (~(h') * (~(e') + ~(f') * log(~(g') * (~x) ^ ~(m')))) ^ ~(q') * sinh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))), ~x) => ((-(ℯ ^ (-(~a) * ~d)) * (~i * ~x) ^ ~r * (~c * (~x) ^ ~n) ^ (-(~b) * ~d)) / (2 * (~x) ^ (~r - ~b * ~d * ~n))) * Antiderivative((~x) ^ (~r - ~b * ~d * ~n) * (~h * (~e + ~f * log(~g * (~x) ^ ~m))) ^ ~q, ~x) + ((ℯ ^ (~a * ~d) * (~i * ~x) ^ ~r * (~c * (~x) ^ ~n) ^ (~b * ~d)) / (2 * (~x) ^ (~r + ~b * ~d * ~n))) * Antiderivative((~x) ^ (~r + ~b * ~d * ~n) * (~h * (~e + ~f * log(~g * (~x) ^ ~m))) ^ ~q, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~g, ~h, ~i, ~m, ~n, ~q, ~r], ~x)
    @apply_utils Antiderivative((~(i') * ~x) ^ ~(r') * (~(h') * (~(e') + ~(f') * log(~(g') * (~x) ^ ~(m')))) ^ ~(q') * cosh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))), ~x) => ((ℯ ^ (-(~a) * ~d) * (~i * ~x) ^ ~r * (~c * (~x) ^ ~n) ^ (-(~b) * ~d)) / (2 * (~x) ^ (~r - ~b * ~d * ~n))) * Antiderivative((~x) ^ (~r - ~b * ~d * ~n) * (~h * (~e + ~f * log(~g * (~x) ^ ~m))) ^ ~q, ~x) + ((ℯ ^ (~a * ~d) * (~i * ~x) ^ ~r * (~c * (~x) ^ ~n) ^ (~b * ~d)) / (2 * (~x) ^ (~r + ~b * ~d * ~n))) * Antiderivative((~x) ^ (~r + ~b * ~d * ~n) * (~h * (~e + ~f * log(~g * (~x) ^ ~m))) ^ ~q, ~x) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~f, ~g, ~h, ~i, ~m, ~n, ~q, ~r], ~x)
    @apply_utils Antiderivative(tanh(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => Antiderivative((-1 + ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d)) ^ ~p / (1 + ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~p], ~x)
    @apply_utils Antiderivative(coth(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => Antiderivative((-1 - ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d)) ^ ~p / (1 - ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~p], ~x)
    @apply_utils Antiderivative(tanh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => (~x / (~n * (~c * (~x) ^ ~n) ^ (1 / ~n))) * Subst(Antiderivative((~x) ^ (1 / ~n - 1) * tanh(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative(coth(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => (~x / (~n * (~c * (~x) ^ ~n) ^ (1 / ~n))) * Subst(Antiderivative((~x) ^ (1 / ~n - 1) * coth(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * tanh(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => Antiderivative(((~e * ~x) ^ ~m * (-1 + ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d)) ^ ~p) / (1 + ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~m, ~p], ~x)
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * coth(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => Antiderivative(((~e * ~x) ^ ~m * (-1 - ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d)) ^ ~p) / (1 - ℯ ^ (2 * ~a * ~d) * (~x) ^ (2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~m, ~p], ~x)
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * tanh(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => ((~e * ~x) ^ (~m + 1) / (~e * ~n * (~c * (~x) ^ ~n) ^ ((~m + 1) / ~n))) * Subst(Antiderivative((~x) ^ ((~m + 1) / ~n - 1) * tanh(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~m, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * coth(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => ((~e * ~x) ^ (~m + 1) / (~e * ~n * (~c * (~x) ^ ~n) ^ ((~m + 1) / ~n))) * Subst(Antiderivative((~x) ^ ((~m + 1) / ~n - 1) * coth(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~m, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative(sech(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => 2 ^ ~p * ℯ ^ (-(~a) * ~d * ~p) * Antiderivative((~x) ^ (-(~b) * ~d * ~p) / (1 + ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d], ~x) && IntegerQ(~p)
    @apply_utils Antiderivative(csch(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => 2 ^ ~p * ℯ ^ (-(~a) * ~d * ~p) * Antiderivative((~x) ^ (-(~b) * ~d * ~p) / (1 - ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d], ~x) && IntegerQ(~p)
    @apply_utils Antiderivative(sech(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => ((sech(~d * (~a + ~b * log(~x))) ^ ~p * (1 + ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p) / (~x) ^ (-(~b) * ~d * ~p)) * Antiderivative((~x) ^ (-(~b) * ~d * ~p) / (1 + ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~p], ~x) && Not(IntegerQ(~p))
    @apply_utils Antiderivative(csch(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => ((csch(~d * (~a + ~b * log(~x))) ^ ~p * (1 - ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p) / (~x) ^ (-(~b) * ~d * ~p)) * Antiderivative((~x) ^ (-(~b) * ~d * ~p) / (1 - ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~p], ~x) && Not(IntegerQ(~p))
    @apply_utils Antiderivative(sech(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => (~x / (~n * (~c * (~x) ^ ~n) ^ (1 / ~n))) * Subst(Antiderivative((~x) ^ (1 / ~n - 1) * sech(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative(csch(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => (~x / (~n * (~c * (~x) ^ ~n) ^ (1 / ~n))) * Subst(Antiderivative((~x) ^ (1 / ~n - 1) * csch(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * sech(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => 2 ^ ~p * ℯ ^ (-(~a) * ~d * ~p) * Antiderivative(((~e * ~x) ^ ~m * (~x) ^ (-(~b) * ~d * ~p)) / (1 + ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~m], ~x) && IntegerQ(~p)
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * csch(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => 2 ^ ~p * ℯ ^ (-(~a) * ~d * ~p) * Antiderivative(((~e * ~x) ^ ~m * (~x) ^ (-(~b) * ~d * ~p)) / (1 - ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~m], ~x) && IntegerQ(~p)
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * sech(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => ((sech(~d * (~a + ~b * log(~x))) ^ ~p * (1 + ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p) / (~x) ^ (-(~b) * ~d * ~p)) * Antiderivative(((~e * ~x) ^ ~m * (~x) ^ (-(~b) * ~d * ~p)) / (1 + ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~m, ~p], ~x) && Not(IntegerQ(~p))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * csch(~(d') * (~(a') + ~(b') * log(~x))) ^ ~(p'), ~x) => ((csch(~d * (~a + ~b * log(~x))) ^ ~p * (1 - ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p) / (~x) ^ (-(~b) * ~d * ~p)) * Antiderivative(((~e * ~x) ^ ~m * (~x) ^ (-(~b) * ~d * ~p)) / (1 - ℯ ^ (-2 * ~a * ~d) * (~x) ^ (-2 * ~b * ~d)) ^ ~p, ~x) <-- FreeQ([~a, ~b, ~d, ~e, ~m, ~p], ~x) && Not(IntegerQ(~p))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * sech(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => ((~e * ~x) ^ (~m + 1) / (~e * ~n * (~c * (~x) ^ ~n) ^ ((~m + 1) / ~n))) * Subst(Antiderivative((~x) ^ ((~m + 1) / ~n - 1) * sech(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~m, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative((~(e') * ~x) ^ ~(m') * csch(~(d') * (~(a') + ~(b') * log(~(c') * (~x) ^ ~(n')))) ^ ~(p'), ~x) => ((~e * ~x) ^ (~m + 1) / (~e * ~n * (~c * (~x) ^ ~n) ^ ((~m + 1) / ~n))) * Subst(Antiderivative((~x) ^ ((~m + 1) / ~n - 1) * csch(~d * (~a + ~b * log(~x))) ^ ~p, ~x), ~x, ~c * (~x) ^ ~n) <-- FreeQ([~a, ~b, ~c, ~d, ~e, ~m, ~n, ~p], ~x) && (NeQ(~c, 1) || NeQ(~n, 1))
    @apply_utils Antiderivative(sinh(~(a') * ~x * log(~(b') * ~x)) * log(~(b') * ~x), ~x) => cosh(~a * ~x * log(~b * ~x)) / ~a - Antiderivative(sinh(~a * ~x * log(~b * ~x)), ~x) <-- FreeQ([~a, ~b], ~x)
    @apply_utils Antiderivative(cosh(~(a') * ~x * log(~(b') * ~x)) * log(~(b') * ~x), ~x) => sinh(~a * ~x * log(~b * ~x)) / ~a - Antiderivative(cosh(~a * ~x * log(~b * ~x)), ~x) <-- FreeQ([~a, ~b], ~x)
    @apply_utils Antiderivative((~x) ^ ~(m') * sinh(~(a') * (~x) ^ ~(n') * log(~(b') * ~x)) * log(~(b') * ~x), ~x) => cosh(~a * (~x) ^ ~n * log(~b * ~x)) / (~a * ~n) - (1 / ~n) * Antiderivative((~x) ^ ~m * sinh(~a * (~x) ^ ~n * log(~b * ~x)), ~x) <-- FreeQ([~a, ~b, ~m, ~n], ~x) && EqQ(~m, ~n - 1)
    @apply_utils Antiderivative((~x) ^ ~(m') * cosh(~(a') * (~x) ^ ~(n') * log(~(b') * ~x)) * log(~(b') * ~x), ~x) => sinh(~a * (~x) ^ ~n * log(~b * ~x)) / (~a * ~n) - (1 / ~n) * Antiderivative((~x) ^ ~m * cosh(~a * (~x) ^ ~n * log(~b * ~x)), ~x) <-- FreeQ([~a, ~b, ~m, ~n], ~x) && EqQ(~m, ~n - 1)
end

max_stars_repo_path: src/rules/6 Hyperbolic functions/6.7 Miscellaneous/6.7.8 u hyper(a+b log(c x^n))^p.jl


text:
using UnitTestDesign
using Documenter

CI = get(ENV, "CI", nothing) == "true"

makedocs(;
    modules=[UnitTestDesign],
    authors="Andrew Dolgert <adolgert@uw.edu>",
    repo="https://github.com/adolgert/UnitTestDesign.jl/blob/{commit}{path}#L{line}",
    sitename="UnitTestDesign.jl",
    format=Documenter.HTML(;
        prettyurls=CI,
        canonical="https://adolgert.github.io/UnitTestDesign.jl",
        assets=String[],
    ),
    pages=[
        "Home" => "index.md",
        "Manual" => [
            "Guide" => "man/guide.md",
            "Examples" => "man/examples.md",
            "Extended Example" => "man/example_extended.md",
            "Testing Methods" => "man/methods.md",
            "Engines" => "man/engines.md",
            "IPOG" => "man/ipog.md"
            ],
        "Reference" => "reference.md",
        "Contributing" => "contributing.md"
    ]
)

if CI
    deploydocs(;
        devbranch = "main",
        repo="github.com/adolgert/UnitTestDesign.jl",
        deploy_config=Documenter.GitHubActions()
    )
end


text:
# ---------------------------------------------------------------------------- #
#
#   include_egads.jl
#
#   Julia function calls for egads functionality. This file is automatically
#     generated using the Clang.jl C-wrapper.
#
#   egads.jl
#   Spring 2018
#
#   Max Opgenoord
#
# ---------------------------------------------------------------------------- #

# Julia wrapper for header: EngSketchPad/include/egads.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function EG_alloc(nbytes::Cint)
    ccall((:EG_alloc, libegads_include), Ptr{Void}, (Cint,), nbytes)
end

function EG_calloc(nele::Cint, size::Cint)
    ccall((:EG_calloc, libegads_include), Ptr{Void}, (Cint, Cint), nele, size)
end

function EG_reall(ptr, nbytes::Cint)
    ccall((:EG_reall, libegads_include), Ptr{Void}, (Ptr{Void}, Cint), ptr, nbytes)
end

function EG_free(pointer)
    ccall((:EG_free, libegads_include), Void, (Ptr{Void},), pointer)
end

function EG_revision(major, minor, OCCrev)
    ccall((:EG_revision, libegads_include), Void, (Ptr{Cint}, Ptr{Cint}, Ptr{Cstring}), major, minor, OCCrev)
end

function EG_open(context)
    ccall((:EG_open, libegads_include), Cint, (Ptr{ego},), context)
end

function EG_loadModel(context::ego, bflg::Cint, name, model)
    ccall((:EG_loadModel, libegads_include), Cint, (ego, Cint, Cstring, Ptr{ego}), context, bflg, name, model)
end

function EG_saveModel(model::ego, name)
    ccall((:EG_saveModel, libegads_include), Cint, (ego, Cstring), model, name)
end

function EG_deleteObject(object::ego)
    ccall((:EG_deleteObject, libegads_include), Cint, (ego,), object)
end

function EG_makeTransform(context::ego, xform, oform)
    ccall((:EG_makeTransform, libegads_include), Cint, (ego, Ptr{Cdouble}, Ptr{ego}), context, xform, oform)
end

function EG_getTransformation(oform::ego, xform)
    ccall((:EG_getTransformation, libegads_include), Cint, (ego, Ptr{Cdouble}), oform, xform)
end

function EG_getContext(object::ego, context)
    ccall((:EG_getContext, libegads_include), Cint, (ego, Ptr{ego}), object, context)
end

function EG_setOutLevel(context::ego, outLevel::Cint)
    ccall((:EG_setOutLevel, libegads_include), Cint, (ego, Cint), context, outLevel)
end

function EG_getInfo(object::ego, oclass, mtype, topObj, prev, next)
    ccall((:EG_getInfo, libegads_include), Cint, (ego, Ptr{Cint}, Ptr{Cint}, Ptr{ego}, Ptr{ego}, Ptr{ego}), object, oclass, mtype, topObj, prev, next)
end

function EG_copyObject(object::ego, oform, copy)
    ccall((:EG_copyObject, libegads_include), Cint, (ego, Ptr{Void}, Ptr{ego}), object, oform, copy)
end

function EG_flipObject(object::ego, flippedCopy)
    ccall((:EG_flipObject, libegads_include), Cint, (ego, Ptr{ego}), object, flippedCopy)
end

function EG_close(context::ego)
    ccall((:EG_close, libegads_include), Cint, (ego,), context)
end

function EG_setUserPointer(context::ego, ptr)
    ccall((:EG_setUserPointer, libegads_include), Cint, (ego, Ptr{Void}), context, ptr)
end

function EG_getUserPointer(context::ego, ptr)
    ccall((:EG_getUserPointer, libegads_include), Cint, (ego, Ptr{Ptr{Void}}), context, ptr)
end

function EG_attributeAdd(obj::ego, name, _type::Cint, len::Cint, ints, reals, str)
    ccall((:EG_attributeAdd, libegads_include), Cint, (ego, Cstring, Cint, Cint, Ptr{Cint}, Ptr{Cdouble}, Cstring), obj, name, _type, len, ints, reals, str)
end

function EG_attributeDel(object::ego, name)
    ccall((:EG_attributeDel, libegads_include), Cint, (ego, Cstring), object, name)
end

function EG_attributeNum(obj::ego, num)
    ccall((:EG_attributeNum, libegads_include), Cint, (ego, Ptr{Cint}), obj, num)
end

function EG_attributeGet(obj::ego, index::Cint, name, atype, len, ints, reals, str)
    ccall((:EG_attributeGet, libegads_include), Cint, (ego, Cint, Ptr{Cstring}, Ptr{Cint}, Ptr{Cint}, Ptr{Ptr{Cint}}, Ptr{Ptr{Cdouble}}, Ptr{Cstring}), obj, index, name, atype, len, ints, reals, str)
end

function EG_attributeRet(obj::ego, name, atype, len, ints, reals, str)
    ccall((:EG_attributeRet, libegads_include), Cint, (ego, Cstring, Ptr{Cint}, Ptr{Cint}, Ptr{Ptr{Cint}}, Ptr{Ptr{Cdouble}}, Ptr{Cstring}), obj, name, atype, len, ints, reals, str)
end

function EG_attributeDup(src::ego, dst::ego)
    ccall((:EG_attributeDup, libegads_include), Cint, (ego, ego), src, dst)
end

function EG_getGeometry(geom::ego, oclass, mtype, refGeom, ivec, rvec)
    ccall((:EG_getGeometry, libegads_include), Cint, (ego, Ptr{Cint}, Ptr{Cint}, Ptr{ego}, Ptr{Ptr{Cint}}, Ptr{Ptr{Cdouble}}), geom, oclass, mtype, refGeom, ivec, rvec)
end

function EG_makeGeometry(context::ego, oclass::Cint, mtype::Cint, refGeom::ego, ivec, rvec, geom)
    ccall((:EG_makeGeometry, libegads_include), Cint, (ego, Cint, Cint, ego, Ptr{Cint}, Ptr{Cdouble}, Ptr{ego}), context, oclass, mtype, refGeom, ivec, rvec, geom)
end

function EG_getRange(geom::ego, range, periodic)
    ccall((:EG_getRange, libegads_include), Cint, (ego, Ptr{Cdouble}, Ptr{Cint}), geom, range, periodic)
end

function EG_evaluate(geom::ego, param, results)
    ccall((:EG_evaluate, libegads_include), Cint, (ego, Ptr{Cdouble}, Ptr{Cdouble}), geom, param, results)
end

function EG_invEvaluate(geom::ego, xyz, param, results)
    ccall((:EG_invEvaluate, libegads_include), Cint, (ego, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), geom, xyz, param, results)
end

function EG_invEvaluateGuess(geom::ego, xyz, param, results)
    ccall((:EG_invEvaluateGuess, libegads_include), Cint, (ego, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), geom, xyz, param, results)
end

function EG_arcLength(geom::ego, t1::Cdouble, t2::Cdouble, alen)
    ccall((:EG_arcLength, libegads_include), Cint, (ego, Cdouble, Cdouble, Ptr{Cdouble}), geom, t1, t2, alen)
end

function EG_curvature(geom::ego, param, results)
    ccall((:EG_curvature, libegads_include), Cint, (ego, Ptr{Cdouble}, Ptr{Cdouble}), geom, param, results)
end

function EG_approximate(context::ego, maxdeg::Cint, tol::Cdouble, sizes, xyzs, bspline)
    ccall((:EG_approximate, libegads_include), Cint, (ego, Cint, Cdouble, Ptr{Cint}, Ptr{Cdouble}, Ptr{ego}), context, maxdeg, tol, sizes, xyzs, bspline)
end

function EG_fitTriangles(context::ego, npts::Cint, xyzs, ntris::Cint, tris, tric, tol::Cdouble, bspline)
    ccall((:EG_fitTriangles, libegads_include), Cint, (ego, Cint, Ptr{Cdouble}, Cint, Ptr{Cint}, Ptr{Cint}, Cdouble, Ptr{ego}), context, npts, xyzs, ntris, tris, tric, tol, bspline)
end

function EG_otherCurve(surface::ego, curve::ego, tol::Cdouble, newcurve)
    ccall((:EG_otherCurve, libegads_include), Cint, (ego, ego, Cdouble, Ptr{ego}), surface, curve, tol, newcurve)
end

function EG_isSame(geom1::ego, geom2::ego)
    ccall((:EG_isSame, libegads_include), Cint, (ego, ego), geom1, geom2)
end

function EG_isoCline(surface::ego, UV::Cint, val::Cdouble, newcurve)
    ccall((:EG_isoCline, libegads_include), Cint, (ego, Cint, Cdouble, Ptr{ego}), surface, UV, val, newcurve)
end

function EG_convertToBSpline(geom::ego, bspline)
    ccall((:EG_convertToBSpline, libegads_include), Cint, (ego, Ptr{ego}), geom, bspline)
end

function EG_convertToBSplineRange(geom::ego, range, bspline)
    ccall((:EG_convertToBSplineRange, libegads_include), Cint, (ego, Ptr{Cdouble}, Ptr{ego}), geom, range, bspline)
end

function EG_skinning(context::ego, nCurves::Cint, curves, skinning_degree::Cint, surface)
    ccall((:EG_skinning, libegads_include), Cint, (ego, Cint, Ptr{ego}, Cint, Ptr{ego}), context, nCurves, curves, skinning_degree, surface)
end

function EG_tolerance(topo::ego, tol)
    ccall((:EG_tolerance, libegads_include), Cint, (ego, Ptr{Cdouble}), topo, tol)
end

function EG_getTolerance(topo::ego, tol)
    ccall((:EG_getTolerance, libegads_include), Cint, (ego, Ptr{Cdouble}), topo, tol)
end

function EG_setTolerance(topo::ego, tol::Cdouble)
    ccall((:EG_setTolerance, libegads_include), Cint, (ego, Cdouble), topo, tol)
end

function EG_getTopology(topo::ego, geom, oclass, _type, limits, nChildren, children, sense)
    ccall((:EG_getTopology, libegads_include), Cint, (ego, Ptr{ego}, Ptr{Cint}, Ptr{Cint}, Ptr{Cdouble}, Ptr{Cint}, Ptr{Ptr{ego}}, Ptr{Ptr{Cint}}), topo, geom, oclass, _type, limits, nChildren, children, sense)
end

function EG_makeTopology(context::ego, geom::ego, oclass::Cint, mtype::Cint, limits, nChildren::Cint, children, senses, topo)
    ccall((:EG_makeTopology, libegads_include), Cint, (ego, ego, Cint, Cint, Ptr{Cdouble}, Cint, Ptr{ego}, Ptr{Cint}, Ptr{ego}), context, geom, oclass, mtype, limits, nChildren, children, senses, topo)
end

function EG_makeLoop(nedge::Cint, edges, geom::ego, toler::Cdouble, result)
    ccall((:EG_makeLoop, libegads_include), Cint, (Cint, Ptr{ego}, ego, Cdouble, Ptr{ego}), nedge, edges, geom, toler, result)
end

function EG_getArea(object::ego, limits, area)
    ccall((:EG_getArea, libegads_include), Cint, (ego, Ptr{Cdouble}, Ptr{Cdouble}), object, limits, area)
end

function EG_makeFace(object::ego, mtype::Cint, limits, face)
    ccall((:EG_makeFace, libegads_include), Cint, (ego, Cint, Ptr{Cdouble}, Ptr{ego}), object, mtype, limits, face)
end

function EG_getBodyTopos(body::ego, src::ego, oclass::Cint, ntopo, topos)
    ccall((:EG_getBodyTopos, libegads_include), Cint, (ego, ego, Cint, Ptr{Cint}, Ptr{Ptr{ego}}), body, src, oclass, ntopo, topos)
end

function EG_indexBodyTopo(body::ego, src::ego)
    ccall((:EG_indexBodyTopo, libegads_include), Cint, (ego, ego), body, src)
end

function EG_objectBodyTopo(body::ego, oclass::Cint, index::Cint, obj)
    ccall((:EG_objectBodyTopo, libegads_include), Cint, (ego, Cint, Cint, Ptr{ego}), body, oclass, index, obj)
end

function EG_inTopology(topo::ego, xyz)
    ccall((:EG_inTopology, libegads_include), Cint, (ego, Ptr{Cdouble}), topo, xyz)
end

function EG_inFace(face::ego, uv)
    ccall((:EG_inFace, libegads_include), Cint, (ego, Ptr{Cdouble}), face, uv)
end

function EG_getEdgeUV(face::ego, edge::ego, sense::Cint, t::Cdouble, UV)
    ccall((:EG_getEdgeUV, libegads_include), Cint, (ego, ego, Cint, Cdouble, Ptr{Cdouble}), face, edge, sense, t, UV)
end

function EG_getPCurve(face::ego, edge::ego, sense::Cint, mtype, ivec, rvec)
    ccall((:EG_getPCurve, libegads_include), Cint, (ego, ego, Cint, Ptr{Cint}, Ptr{Ptr{Cint}}, Ptr{Ptr{Cdouble}}), face, edge, sense, mtype, ivec, rvec)
end

function EG_getBody(object::ego, body)
    ccall((:EG_getBody, libegads_include), Cint, (ego, Ptr{ego}), object, body)
end

function EG_makeSolidBody(context::ego, stype::Cint, rvec, body)
    ccall((:EG_makeSolidBody, libegads_include), Cint, (ego, Cint, Ptr{Cdouble}, Ptr{ego}), context, stype, rvec, body)
end

function EG_getBoundingBox(topo::ego, bbox)
    ccall((:EG_getBoundingBox, libegads_include), Cint, (ego, Ptr{Cdouble}), topo, bbox)
end

function EG_getMassProperties(topo::ego, result)
    ccall((:EG_getMassProperties, libegads_include), Cint, (ego, Ptr{Cdouble}), topo, result)
end

function EG_isEquivalent(topo1::ego, topo2::ego)
    ccall((:EG_isEquivalent, libegads_include), Cint, (ego, ego), topo1, topo2)
end

function EG_sewFaces(nobj::Cint, objs, toler::Cdouble, flag::Cint, result)
    ccall((:EG_sewFaces, libegads_include), Cint, (Cint, Ptr{ego}, Cdouble, Cint, Ptr{ego}), nobj, objs, toler, flag, result)
end

function EG_replaceFaces(body::ego, nobj::Cint, objs, result)
    ccall((:EG_replaceFaces, libegads_include), Cint, (ego, Cint, Ptr{ego}, Ptr{ego}), body, nobj, objs, result)
end

function EG_mapBody(sBody::ego, dBody::ego, fAttr, mapBody)
    ccall((:EG_mapBody, libegads_include), Cint, (ego, ego, Cstring, Ptr{ego}), sBody, dBody, fAttr, mapBody)
end

function EG_matchBodyFaces(body1::ego, body2::ego, toler::Cdouble, nmatch, match)
    ccall((:EG_matchBodyFaces, libegads_include), Cint, (ego, ego, Cdouble, Ptr{Cint}, Ptr{Ptr{Cint}}), body1, body2, toler, nmatch, match)
end

function EG_setTessParam(context::ego, iparam::Cint, value::Cdouble, oldvalue)
    ccall((:EG_setTessParam, libegads_include), Cint, (ego, Cint, Cdouble, Ptr{Cdouble}), context, iparam, value, oldvalue)
end

function EG_makeTessGeom(obj::ego, params, sizes, tess)
    ccall((:EG_makeTessGeom, libegads_include), Cint, (ego, Ptr{Cdouble}, Ptr{Cint}, Ptr{ego}), obj, params, sizes, tess)
end

function EG_getTessGeom(tess::ego, sizes, xyz)
    ccall((:EG_getTessGeom, libegads_include), Cint, (ego, Ptr{Cint}, Ptr{Ptr{Cdouble}}), tess, sizes, xyz)
end

function EG_makeTessBody(object::ego, params, tess)
    ccall((:EG_makeTessBody, libegads_include), Cint, (ego, Ptr{Cdouble}, Ptr{ego}), object, params, tess)
end

function EG_remakeTess(tess::ego, nobj::Cint, objs, params)
    ccall((:EG_remakeTess, libegads_include), Cint, (ego, Cint, Ptr{ego}, Ptr{Cdouble}), tess, nobj, objs, params)
end

function EG_mapTessBody(tess::ego, body::ego, mapTess)
    ccall((:EG_mapTessBody, libegads_include), Cint, (ego, ego, Ptr{ego}), tess, body, mapTess)
end

function EG_locateTessBody(tess::ego, npt::Cint, ifaces, uv, itri, results)
    ccall((:EG_locateTessBody, libegads_include), Cint, (ego, Cint, Ptr{Cint}, Ptr{Cdouble}, Ptr{Cint}, Ptr{Cdouble}), tess, npt, ifaces, uv, itri, results)
end

function EG_getTessEdge(tess::ego, eIndex::Cint, len, xyz, t)
    ccall((:EG_getTessEdge, libegads_include), Cint, (ego, Cint, Ptr{Cint}, Ptr{Ptr{Cdouble}}, Ptr{Ptr{Cdouble}}), tess, eIndex, len, xyz, t)
end

function EG_getTessFace(tess::ego, fIndex::Cint, len, xyz, uv, ptype, pindex, ntri, tris, tric)
    ccall((:EG_getTessFace, libegads_include), Cint, (ego, Cint, Ptr{Cint}, Ptr{Ptr{Cdouble}}, Ptr{Ptr{Cdouble}}, Ptr{Ptr{Cint}}, Ptr{Ptr{Cint}}, Ptr{Cint}, Ptr{Ptr{Cint}}, Ptr{Ptr{Cint}}), tess, fIndex, len, xyz, uv, ptype, pindex, ntri, tris, tric)
end

function EG_getTessLoops(tess::ego, fIndex::Cint, nloop, lIndices)
    ccall((:EG_getTessLoops, libegads_include), Cint, (ego, Cint, Ptr{Cint}, Ptr{Ptr{Cint}}), tess, fIndex, nloop, lIndices)
end

function EG_getTessQuads(tess::ego, nquad, fIndices)
    ccall((:EG_getTessQuads, libegads_include), Cint, (ego, Ptr{Cint}, Ptr{Ptr{Cint}}), tess, nquad, fIndices)
end

function EG_makeQuads(tess::ego, params, fIndex::Cint)
    ccall((:EG_makeQuads, libegads_include), Cint, (ego, Ptr{Cdouble}, Cint), tess, params, fIndex)
end

function EG_getQuads(tess::ego, fIndex::Cint, len, xyz, uv, ptype, pindex, npatch)
    ccall((:EG_getQuads, libegads_include), Cint, (ego, Cint, Ptr{Cint}, Ptr{Ptr{Cdouble}}, Ptr{Ptr{Cdouble}}, Ptr{Ptr{Cint}}, Ptr{Ptr{Cint}}, Ptr{Cint}), tess, fIndex, len, xyz, uv, ptype, pindex, npatch)
end

function EG_getPatch(tess::ego, fIndex::Cint, patch::Cint, nu, nv, ipts, bounds)
    ccall((:EG_getPatch, libegads_include), Cint, (ego, Cint, Cint, Ptr{Cint}, Ptr{Cint}, Ptr{Ptr{Cint}}, Ptr{Ptr{Cint}}), tess, fIndex, patch, nu, nv, ipts, bounds)
end

function EG_quadTess(tess::ego, quadTess)
    ccall((:EG_quadTess, libegads_include), Cint, (ego, Ptr{ego}), tess, quadTess)
end

function EG_insertEdgeVerts(tess::ego, eIndex::Cint, vIndex::Cint, npts::Cint, t)
    ccall((:EG_insertEdgeVerts, libegads_include), Cint, (ego, Cint, Cint, Cint, Ptr{Cdouble}), tess, eIndex, vIndex, npts, t)
end

function EG_deleteEdgeVert(tess::ego, eIndex::Cint, vIndex::Cint, dir::Cint)
    ccall((:EG_deleteEdgeVert, libegads_include), Cint, (ego, Cint, Cint, Cint), tess, eIndex, vIndex, dir)
end

function EG_moveEdgeVert(tess::ego, eIndex::Cint, vIndex::Cint, t::Cdouble)
    ccall((:EG_moveEdgeVert, libegads_include), Cint, (ego, Cint, Cint, Cdouble), tess, eIndex, vIndex, t)
end

function EG_openTessBody(tess::ego)
    ccall((:EG_openTessBody, libegads_include), Cint, (ego,), tess)
end

function EG_initTessBody(object::ego, tess)
    ccall((:EG_initTessBody, libegads_include), Cint, (ego, Ptr{ego}), object, tess)
end

function EG_statusTessBody(tess::ego, body, state, np)
    ccall((:EG_statusTessBody, libegads_include), Cint, (ego, Ptr{ego}, Ptr{Cint}, Ptr{Cint}), tess, body, state, np)
end

function EG_setTessEdge(tess::ego, eIndex::Cint, len::Cint, xyz, t)
    ccall((:EG_setTessEdge, libegads_include), Cint, (ego, Cint, Cint, Ptr{Cdouble}, Ptr{Cdouble}), tess, eIndex, len, xyz, t)
end

function EG_setTessFace(tess::ego, fIndex::Cint, len::Cint, xyz, uv, ntri::Cint, tris)
    ccall((:EG_setTessFace, libegads_include), Cint, (ego, Cint, Cint, Ptr{Cdouble}, Ptr{Cdouble}, Cint, Ptr{Cint}), tess, fIndex, len, xyz, uv, ntri, tris)
end

function EG_localToGlobal(tess::ego, index::Cint, _local::Cint, _global)
    ccall((:EG_localToGlobal, libegads_include), Cint, (ego, Cint, Cint, Ptr{Cint}), tess, index, _local, _global)
end

function EG_getGlobal(tess::ego, _global::Cint, ptype, pindex, xyz)
    ccall((:EG_getGlobal, libegads_include), Cint, (ego, Cint, Ptr{Cint}, Ptr{Cint}, Ptr{Cdouble}), tess, _global, ptype, pindex, xyz)
end

function EG_solidBoolean(src::ego, tool::ego, oper::Cint, model)
    ccall((:EG_solidBoolean, libegads_include), Cint, (ego, ego, Cint, Ptr{ego}), src, tool, oper, model)
end

function EG_intersection(src::ego, tool::ego, nedge, facEdg, model)
    ccall((:EG_intersection, libegads_include), Cint, (ego, ego, Ptr{Cint}, Ptr{Ptr{ego}}, Ptr{ego}), src, tool, nedge, facEdg, model)
end

function EG_imprintBody(src::ego, nedge::Cint, facEdg, result)
    ccall((:EG_imprintBody, libegads_include), Cint, (ego, Cint, Ptr{ego}, Ptr{ego}), src, nedge, facEdg, result)
end

function EG_filletBody(src::ego, nedge::Cint, edges, radius::Cdouble, result, facemap)
    ccall((:EG_filletBody, libegads_include), Cint, (ego, Cint, Ptr{ego}, Cdouble, Ptr{ego}, Ptr{Ptr{Cint}}), src, nedge, edges, radius, result, facemap)
end

function EG_chamferBody(src::ego, nedge::Cint, edges, faces, dis1::Cdouble, dis2::Cdouble, result, facemap)
    ccall((:EG_chamferBody, libegads_include), Cint, (ego, Cint, Ptr{ego}, Ptr{ego}, Cdouble, Cdouble, Ptr{ego}, Ptr{Ptr{Cint}}), src, nedge, edges, faces, dis1, dis2, result, facemap)
end

function EG_hollowBody(src::ego, nface::Cint, faces, offset::Cdouble, join::Cint, result, facemap)
    ccall((:EG_hollowBody, libegads_include), Cint, (ego, Cint, Ptr{ego}, Cdouble, Cint, Ptr{ego}, Ptr{Ptr{Cint}}), src, nface, faces, offset, join, result, facemap)
end

function EG_extrude(src::ego, dist::Cdouble, dir, result)
    ccall((:EG_extrude, libegads_include), Cint, (ego, Cdouble, Ptr{Cdouble}, Ptr{ego}), src, dist, dir, result)
end

function EG_rotate(src::ego, angle::Cdouble, axis, result)
    ccall((:EG_rotate, libegads_include), Cint, (ego, Cdouble, Ptr{Cdouble}, Ptr{ego}), src, angle, axis, result)
end

function EG_sweep(src::ego, spine::ego, mode::Cint, result)
    ccall((:EG_sweep, libegads_include), Cint, (ego, ego, Cint, Ptr{ego}), src, spine, mode, result)
end

function EG_loft(nsec::Cint, secs, opt::Cint, result)
    ccall((:EG_loft, libegads_include), Cint, (Cint, Ptr{ego}, Cint, Ptr{ego}), nsec, secs, opt, result)
end

function EG_blend(nsec::Cint, secs, rc1, rcN, result)
    ccall((:EG_blend, libegads_include), Cint, (Cint, Ptr{ego}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{ego}), nsec, secs, rc1, rcN, result)
end

function EG_ruled(nsec::Cint, secs, result)
    ccall((:EG_ruled, libegads_include), Cint, (Cint, Ptr{ego}, Ptr{ego}), nsec, secs, result)
end
# Julia wrapper for header: EngSketchPad/include/egadsErrors.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

# Julia wrapper for header: EngSketchPad/include/egadsTypes.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

# Julia wrapper for header: EngSketchPad/include/common.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

# Julia wrapper for header: EngSketchPad/include/egadsBlendSens.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function EG_blend_init(nSection::Cint, sections, rc1, rc1_dot, rcN, rcN_dot, nStrips, cache)
    ccall((:EG_blend_init, libegads_include), Cint, (Cint, Ptr{ego}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cint}, Ptr{Ptr{Void}}), nSection, sections, rc1, rc1_dot, rcN, rcN_dot, nStrips, cache)
end

function EG_blend_pos(cache, sIndex::Cint, objs, imax, ts)
    ccall((:EG_blend_pos, libegads_include), Cint, (Ptr{Void}, Cint, Ptr{Ptr{ego}}, Ptr{Cint}, Ptr{Ptr{Cdouble}}), cache, sIndex, objs, imax, ts)
end

function EG_blend_sens(cache, sIndex::Cint, xyzs, xyzs_dot, tbeg, tbeg_dot, tend, tend_dot)
    ccall((:EG_blend_sens, libegads_include), Cint, (Ptr{Void}, Cint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), cache, sIndex, xyzs, xyzs_dot, tbeg, tbeg_dot, tend, tend_dot)
end

function EG_blend_seval(cache, sIndex::Cint, uv, xyz, vel)
    ccall((:EG_blend_seval, libegads_include), Cint, (Ptr{Void}, Cint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), cache, sIndex, uv, xyz, vel)
end

function EG_sens_free(cache)
    ccall((:EG_sens_free, libegads_include), Void, (Ptr{Void},), cache)
end
# Julia wrapper for header: EngSketchPad/include/egadsSplineFit.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function EG_spline1dEval(ivec, data, t::Cdouble, point)
    ccall((:EG_spline1dEval, libegads_include), Cint, (Ptr{Cint}, Ptr{Cdouble}, Cdouble, Ptr{Cdouble}), ivec, data, t, point)
end

function EG_spline1dEval_psens(ivec, data, rdata_xyz, xyz_dot, t::Cdouble, point, point_dot)
    ccall((:EG_spline1dEval_psens, libegads_include), Cint, (Ptr{Cint}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Cdouble, Ptr{Cdouble}, Ptr{Cdouble}), ivec, data, rdata_xyz, xyz_dot, t, point, point_dot)
end

function EG_spline1dDeriv(ivec, data, der::Cint, t::Cdouble, deriv)
    ccall((:EG_spline1dDeriv, libegads_include), Cint, (Ptr{Cint}, Ptr{Cdouble}, Cint, Cdouble, Ptr{Cdouble}), ivec, data, der, t, deriv)
end

function EG_spline1dFit(endx::Cint, imaxx::Cint, xyz, kn, tol::Cdouble, header, rdata)
    ccall((:EG_spline1dFit, libegads_include), Cint, (Cint, Cint, Ptr{Cdouble}, Ptr{Cdouble}, Cdouble, Ptr{Cint}, Ptr{Ptr{Cdouble}}), endx, imaxx, xyz, kn, tol, header, rdata)
end

function EG_spline1dFit_psens(endx::Cint, imaxx::Cint, xyz, kn, tol::Cdouble, header, rdata, rdata_xyz)
    ccall((:EG_spline1dFit_psens, libegads_include), Cint, (Cint, Cint, Ptr{Cdouble}, Ptr{Cdouble}, Cdouble, Ptr{Cint}, Ptr{Ptr{Cdouble}}, Ptr{Ptr{Cdouble}}), endx, imaxx, xyz, kn, tol, header, rdata, rdata_xyz)
end

function EG_spline2dEval(ivec, data, uv, point)
    ccall((:EG_spline2dEval, libegads_include), Cint, (Ptr{Cint}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), ivec, data, uv, point)
end

function EG_spline2dEval_psens(ivec, data, data_dot, xyz_dot, uv, point, point_dot)
    ccall((:EG_spline2dEval_psens, libegads_include), Cint, (Ptr{Cint}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), ivec, data, data_dot, xyz_dot, uv, point, point_dot)
end

function EG_spline2dDeriv(ivec, data, der::Cint, uv, deriv)
    ccall((:EG_spline2dDeriv, libegads_include), Cint, (Ptr{Cint}, Ptr{Cdouble}, Cint, Ptr{Cdouble}, Ptr{Cdouble}), ivec, data, der, uv, deriv)
end

function EG_spline2dAprx(e::Cint, im::Cint, jm::Cint, xyz, uknot, vknot, vdata, wesT, easT, south, snor, north, nnor, tol::Cdouble, header, rdata)
    ccall((:EG_spline2dAprx, libegads_include), Cint, (Cint, Cint, Cint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cint}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Cdouble, Ptr{Cint}, Ptr{Ptr{Cdouble}}), e, im, jm, xyz, uknot, vknot, vdata, wesT, easT, south, snor, north, nnor, tol, header, rdata)
end
# Julia wrapper for header: EngSketchPad/include/egadsTris.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

# Julia wrapper for header: EngSketchPad/include/egg.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function eggGenerate(uv, nbnd, gridP)
    ccall((:eggGenerate, libegads_include), Cint, (Ptr{Cdouble}, Ptr{Cint}, Ptr{Ptr{Void}}), uv, nbnd, gridP)
end

function eggMorph(gridP, uvnew, newGridP)
    ccall((:eggMorph, libegads_include), Cint, (Ptr{Void}, Ptr{Cdouble}, Ptr{Ptr{Void}}), gridP, uvnew, newGridP)
end

function eggInfo(gridP, npnt, nbnd, uv, p, ntri, tris)
    ccall((:eggInfo, libegads_include), Cint, (Ptr{Void}, Ptr{Cint}, Ptr{Cint}, Ptr{Ptr{Cdouble}}, Ptr{Ptr{Cint}}, Ptr{Cint}, Ptr{Ptr{Cint}}), gridP, npnt, nbnd, uv, p, ntri, tris)
end

# function eggDump(gridP, fp)
#     ccall((:eggDump, libegads_include), Cint, (Ptr{Void}, Ptr{FILE}), gridP, fp)
# end
#
# function eggLoad(fp, gridP)
#     ccall((:eggLoad, libegads_include), Cint, (Ptr{FILE}, Ptr{Ptr{Void}}), fp, gridP)
# end

function eggFree(gridP)
    ccall((:eggFree, libegads_include), Cint, (Ptr{Void},), gridP)
end
# Julia wrapper for header: EngSketchPad/include/emp.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function EMP_Init(start)
    ccall((:EMP_Init, libegads_include), Cint, (Ptr{Clong},), start)
end

function EMP_Done(start)
    ccall((:EMP_Done, libegads_include), Clong, (Ptr{Clong},), start)
end

function EMP_ThreadCreate(entry, arg)
    ccall((:EMP_ThreadCreate, libegads_include), Ptr{Void}, (Ptr{Void}, Ptr{Void}), entry, arg)
end

function EMP_ThreadExit()
    ccall((:EMP_ThreadExit, libegads_include), Void, ())
end

function EMP_ThreadWait(thread)
    ccall((:EMP_ThreadWait, libegads_include), Void, (Ptr{Void},), thread)
end

function EMP_ThreadSpin()
    ccall((:EMP_ThreadSpin, libegads_include), Void, ())
end

function EMP_ThreadID()
    ccall((:EMP_ThreadID, libegads_include), Clong, ())
end

function EMP_ThreadDestroy(thread)
    ccall((:EMP_ThreadDestroy, libegads_include), Void, (Ptr{Void},), thread)
end

function EMP_LockCreate()
    ccall((:EMP_LockCreate, libegads_include), Ptr{Void}, ())
end

function EMP_LockSet(lock)
    ccall((:EMP_LockSet, libegads_include), Void, (Ptr{Void},), lock)
end

function EMP_LockTest(lock)
    ccall((:EMP_LockTest, libegads_include), Cint, (Ptr{Void},), lock)
end

function EMP_LockRelease(lock)
    ccall((:EMP_LockRelease, libegads_include), Void, (Ptr{Void},), lock)
end

function EMP_LockDestroy(lock)
    ccall((:EMP_LockDestroy, libegads_include), Void, (Ptr{Void},), lock)
end

function EMP_for(maxproc::Cint, nindex::Cint, forFn)
    ccall((:EMP_for, libegads_include), Cint, (Cint, Cint, Ptr{Void}), maxproc, nindex, forFn)
end

function EMP_sum(maxproc::Cint, nindex::Cint, sumFn, sum)
    ccall((:EMP_sum, libegads_include), Cint, (Cint, Cint, Ptr{Void}, Ptr{Cdouble}), maxproc, nindex, sumFn, sum)
end

function EMP_min(maxproc::Cint, nindex::Cint, minFn, min, imin)
    ccall((:EMP_min, libegads_include), Cint, (Cint, Cint, Ptr{Void}, Ptr{Cdouble}, Ptr{Cint}), maxproc, nindex, minFn, min, imin)
end
# Julia wrapper for header: EngSketchPad/include/prm.h
# Automatically generated using Clang.jl wrap_c, version 0.0.0

function prm_CreateU(nvrt::Cint, u, xyz, tol::Cdouble, periodic)
    ccall((:prm_CreateU, libegads_include), Cint, (Cint, Ptr{Cdouble}, Ptr{prmXYZ}, Cdouble, Ptr{Cint}), nvrt, u, xyz, tol, periodic)
end

function prm_CreateUV(UVtype::Cint, ntri::Cint, tri, uvf, nvrt::Cint, ptype, pindx, uv, xyz, periodic, ppnts)
    ccall((:prm_CreateUV, libegads_include), Cint, (Cint, Cint, Ptr{prmTri}, Ptr{prmUVF}, Cint, Ptr{Cint}, Ptr{Cint}, Ptr{prmUV}, Ptr{prmXYZ}, Ptr{Cint}, Ptr{Ptr{Cint}}), UVtype, ntri, tri, uvf, nvrt, ptype, pindx, uv, xyz, periodic, ppnts)
end

function prm_SmoothU(periodic::Cint, nvrt::Cint, nvar::Cint, u, xyz)
    ccall((:prm_SmoothU, libegads_include), Cint, (Cint, Cint, Cint, Ptr{Cdouble}, Ptr{Cdouble}), periodic, nvrt, nvar, u, xyz)
end

function prm_SmoothUV(_type::Cint, periodic::Cint, ppnts, ntri::Cint, tri, nvrt::Cint, nvar::Cint, uv, xyz)
    ccall((:prm_SmoothUV, libegads_include), Cint, (Cint, Cint, Ptr{Cint}, Cint, Ptr{prmTri}, Cint, Cint, Ptr{prmUV}, Ptr{Cdouble}), _type, periodic, ppnts, ntri, tri, nvrt, nvar, uv, xyz)
end

function prm_NormalizeU(halo::Cdouble, periodic::Cint, nvrt::Cint, u)
    ccall((:prm_NormalizeU, libegads_include), Cint, (Cdouble, Cint, Cint, Ptr{Cdouble}), halo, periodic, nvrt, u)
end

function prm_NormalizeUV(halo::Cdouble, periodic::Cint, nvrt::Cint, uv)
    ccall((:prm_NormalizeUV, libegads_include), Cint, (Cdouble, Cint, Cint, Ptr{prmUV}), halo, periodic, nvrt, uv)
end

function prm_LimitGridSize(limit::Cint)
    ccall((:prm_LimitGridSize, libegads_include), Cint, (Cint,), limit)
end

function prm_FixedCfit(nvrt::Cint, nvar::Cint, u, var, periodic::Cint, nu::Cint, cfit, rmserr, maxerr)
    ccall((:prm_FixedCfit, libegads_include), Cint, (Cint, Cint, Ptr{Cdouble}, Ptr{Cdouble}, Cint, Cint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), nvrt, nvar, u, var, periodic, nu, cfit, rmserr, maxerr)
end

function prm_FixedGrid(nvrt::Cint, nvar::Cint, uv, var, ntri::Cint, tri, periodic::Cint, ppnts, nu::Cint, nv::Cint, grid, rmserr, maxerr, dotmin)
    ccall((:prm_FixedGrid, libegads_include), Cint, (Cint, Cint, Ptr{prmUV}, Ptr{Cdouble}, Cint, Ptr{prmTri}, Cint, Ptr{Cint}, Cint, Cint, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), nvrt, nvar, uv, var, ntri, tri, periodic, ppnts, nu, nv, grid, rmserr, maxerr, dotmin)
end

function prm_BestCfit(nvrt::Cint, nvar::Cint, u, var, tol::Cdouble, periodic::Cint, nu, cfit, rmserr, maxerr)
    ccall((:prm_BestCfit, libegads_include), Cint, (Cint, Cint, Ptr{Cdouble}, Ptr{Cdouble}, Cdouble, Cint, Ptr{Cint}, Ptr{Ptr{Cdouble}}, Ptr{Cdouble}, Ptr{Cdouble}), nvrt, nvar, u, var, tol, periodic, nu, cfit, rmserr, maxerr)
end

function prm_BestGrid(nvrt::Cint, nvar::Cint, uv, var, ntri::Cint, tri, tol::Cdouble, periodic::Cint, ppnts, nu, nv, grid, rmserr, maxerr, dotmin)
    ccall((:prm_BestGrid, libegads_include), Cint, (Cint, Cint, Ptr{prmUV}, Ptr{Cdouble}, Cint, Ptr{prmTri}, Cdouble, Cint, Ptr{Cint}, Ptr{Cint}, Ptr{Cint}, Ptr{Ptr{Cdouble}}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), nvrt, nvar, uv, var, ntri, tri, tol, periodic, ppnts, nu, nv, grid, rmserr, maxerr, dotmin)
end

function prm_EvalCfit(tree::cfitTree, uu::Cdouble, var, dt, dtt)
    ccall((:prm_EvalCfit, libegads_include), Cint, (cfitTree, Cdouble, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), tree, uu, var, dt, dtt)
end

function prm_EvalGrid(tree::gridTree, uv::prmUV, var, du, dv, duu, duv, dvv)
    ccall((:prm_EvalGrid, libegads_include), Cint, (gridTree, prmUV, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}, Ptr{Cdouble}), tree, uv, var, du, dv, duu, duv, dvv)
end

function prm_FreeCfit(tree)
    ccall((:prm_FreeCfit, libegads_include), Cint, (Ptr{cfitTree},), tree)
end

function prm_FreeGrid(tree)
    ccall((:prm_FreeGrid, libegads_include), Cint, (Ptr{gridTree},), tree)
end


text:
# `RequestParser` handles all the `HttpParser` module stuff for `HttpServer`
#
# The `HttpParser` module wraps [Joyent's `http-parser` C library][hprepo].
# A new `HttpParser` is created for each TCP connection being handled by
# our server.  Each `HttpParser` is initialized with a set of callback
# functions. When new data comes in, it is fed into the `http-parser` which
# executes the callbacks as different elements are parsed.  Finally, it calls
# on_message_complete when the incoming `Request` is fully built. The parser
# does not care if it receives just one byte at a time, or multiple requests.
# It will simply parse in order and run the callbacks normally.
#
# Note that this is not a module, it is included directly in `HttpServer.jl`
#
# [hprepo]: https://github.com/joyent/http-parser
#
using HttpParser
using HttpCommon
export RequestParser,
       clean!,
       add_data

# Datatype Tuples for the different `cfunction` signatures used by `HttpParser`
HTTP_CB      = (Int, (Ptr{Parser},))
HTTP_DATA_CB = (Int, (Ptr{Parser}, Ptr{Cchar}, Csize_t,))

# All the `HttpParser` callbacks to be run in C land
# Each one adds data to the `Request` until it is complete
#
function on_message_begin(parser)
    pd(parser).request = Request()

    return 0
end

function on_url(parser, at, len)
    r = pd(parser).request
    r.resource = string(r.resource, unsafe_string(convert(Ptr{UInt8}, at), Int(len)))
    return 0
end

function on_status_complete(parser)
    return 0
end

# Gather the header_field, set the field
# on header value, set the value for the current field
# there might be a better way to do
# this: https://github.com/joyent/node/blob/master/src/node_http_parser.cc#L207

function on_header_field(parser, at, len)
    par = pd(parser)
    if par.num_fields == par.num_values
        par.num_fields += 1
        push!(par.vec_fields, "")
    end
    header = unsafe_string(convert(Ptr{UInt8}, at))
    header_field = header[1:len]
    par.vec_fields[par.num_fields] = string(par.vec_fields[par.num_fields], header_field)
    return 0
end

function on_header_value(parser, at, len)
    par = pd(parser)
    if par.num_values != par.num_fields
        par.num_values += 1
        push!(par.vec_values, "")
    end
    s = unsafe_string(convert(Ptr{UInt8}, at), Int(len))
    header_value = s[1:len]
    par.vec_values[par.num_values] = string(par.vec_values[par.num_values], header_value)
    return 0
end

function on_headers_complete(parser)
    par = pd(parser)
    r = par.request
    merge!(r.headers, Dict(zip(par.vec_fields, par.vec_values)))
    par.num_fields = 0
    par.num_values = 0
    empty!(par.vec_fields)
    empty!(par.vec_values)
    p = unsafe_load(parser)
    # get first two bits of p.type_and_flags
    ptype = p.type_and_flags & 0x03
    if ptype == 0
        r.method = http_method_str(convert(Int, p.method))
    elseif ptype == 1
        r.headers["status_code"] = string(convert(Int, p.status_code))
    end
    r.headers["http_major"] = string(convert(Int, p.http_major))
    r.headers["http_minor"] = string(convert(Int, p.http_minor))
    r.headers["Keep-Alive"] = string(http_should_keep_alive(parser))
    return 0
end

function on_body(parser, at, len)
    r = pd(parser).request
    # write(pd(parser).data, convert(Ptr{UInt8}, at), len)
    append!(r.data, unsafe_wrap(Array,convert(Ptr{UInt8}, at), (len,)))
    r.data
    return 0
end

function on_message_complete(parser)
    state = pd(parser)
    r = state.request
    # r.data = takebuf_array(state.data)

    # Get the `parser.id` from the C pointer `parser`.
    # Retrieve our callback function from the global Dict.
    # Call it with the completed `Request`
    #
    state.complete_cb(r)
    return 0
end

default_complete_cb(r::Request) = nothing

mutable struct RequestParserState
    request::Request
    complete_cb::Function
    num_fields::Int
    num_values::Int
    vec_fields::Vector{String}
    vec_values::Vector{String}
end
RequestParserState() = RequestParserState(Request(),default_complete_cb,0,0,Vector{String}(),Vector{String}())

pd(p::Ptr{Parser}) = (unsafe_load(p).data)::RequestParserState

# `ClientParser` wraps our `HttpParser`
# Constructed with `on_message_complete` function.
#
struct ClientParser
    parser::Parser
    settings::ParserSettings

    function ClientParser(on_message_complete::Function)
        parser = Parser()
        parser.data = RequestParserState()
        http_parser_init(parser)
        parser.data.complete_cb = on_message_complete

        settings = ParserSettings(on_message_begin_cb, on_url_cb,
                                  on_status_complete_cb, on_header_field_cb,
                                  on_header_value_cb, on_headers_complete_cb,
                                  on_body_cb, on_message_complete_cb)

        new(parser, settings)
    end
end

# Passes `request_data` into `parser`
function add_data(parser::ClientParser, request_data::Vector{UInt8})
    http_parser_execute(parser.parser, parser.settings, request_data)
end


text:
using DynamicHMC, LogDensityProblems
using Distributions, Parameters, Random
using ForwardDiff, StatsPlots

include(string(pwd(),"/src/simulation.jl"))
include(string(pwd(),"/gali_bayesian.jl"))
include(string(pwd(),"/mcmc/priors_v2.jl"))
include(string(pwd(),"/mcmc/foos.jl"))

yy,shocks = simulate_dsge(GAMMA_0,GAMMA_1,PSI,PI,500)

prob = DSGE_Model(yy[:,2],1/3)

prob((bet = 0.99,epsilon = 6,theta=2/3,sig=1,s2=1,phi=1,phi_pi=1.5,phi_y=0.5/4,rho_v=0.5))

t = problem_transform(prob)

P = TransformedLogDensity(t,prob)

aa = [0.99,6,2/3,1,1,1,1.5,0.5/4,0.5]

bb = TransformVariables.inverse(t,(bet = 0.99,epsilon = 6,theta=2/3,sig=1,s2=1,phi=1,phi_pi=1.5,phi_y=0.5/4,rho_v=0.5))

LogDensityProblems.logdensity(P,bb)

grad_p = ADgradient(:Zygote,P)

#grads = Calculus.gradient(P)

res = @time mcmc_with_warmup(Random.GLOBAL_RNG, grad_p,10000)

posterior = transform.(t, res.chain)

post_array = zeros(10000,9)

for i in 1:10000
    @unpack bet, epsilon, theta, sig, s2,phi,phi_pi,phi_y,rho_v = posterior[i,:][1]
    post_array[i,:] = [bet epsilon theta sig s2 phi phi_pi phi_y rho_v]
end

StatsPlots.density(post_array[:,1], legend = :none)
title!(latexify("beta()"))
vline!([true_pars[:bet]])
vline!([mean(post_array[:,1])])

StatsPlots.density(post_array[:,2], legend = :none)
title!(latexify("epsilon()"))
vline!([true_pars[:epsilon]])
vline!([mean(post_array[:,2])])

StatsPlots.density(post_array[:,3], legend = :none)
title!(latexify("theta()"))
vline!([true_pars[:theta]])
vline!([mean(post_array[:,3])])

StatsPlots.density(post_array[:,4], legend = :none)
title!(latexify("sigma()"))
vline!([true_pars[:sig]])
vline!([mean(post_array[:,4])])

StatsPlots.density(post_array[:,5], legend = :none)
title!(latexify("sigma()^2"))
vline!([true_pars[:s2]])
vline!([mean(post_array[:,5])])

StatsPlots.density(post_array[:,6], legend = :none)
title!(latexify("phi()"))
vline!([true_pars[:phi]])
vline!([mean(post_array[:,6])Tra])

StatsPlots.density(post_array[:,7], legend = :none)
title!(latexify("phi()_pi",cdot = false))
vline!([true_pars[:phi_pi]])
vline!([mean(post_array[:,7])])

StatsPlots.density(post_array[:,8], legend = :none)
title!(latexify("phi()_y",cdot = false))
vline!([true_pars[:phi_y]])
vline!([mean(post_array[:,8])])

StatsPlots.density(post_array[:,9], legend = :none)
title!(latexify("rho()_v",cdot = false))
vline!([true_pars[:rho_v]])
vline!([mean(post_array[:,9])])

max_stars_repo_name: danmrc/DSGE-HMC

max_issues_repo_name: danmrc/DSGE-HMC

max_forks_repo_name: danmrc/DSGE-HMC


text:
using DelimitedFiles

export fuel_required, fuel_required_including_fuel

fuel_required(mass) = clamp(mass ÷ 3 - 2, 0, typemax(Int))

function fuel_required_including_fuel(mass)
    fuel = fuel_required(mass)
    fuel == 0 ? 0 : fuel + fuel_required_including_fuel(fuel)
end

d01_inputpath = joinpath(@__DIR__, "input.txt")
d01_inputread(path) = vec(readdlm(path, '\n', Int))
d01_answer1(input) = sum(fuel_required, input)
d01_answer2(input) = sum(fuel_required_including_fuel, input)


text:
#===============================================================================

    typedefs.jl - LR, June 2020

    Holds some definitions of types.

===============================================================================#
const DType = Float64
const CType = Complex{DType}
const IType = Int64

# Types for state handling. The type of representation is chosen by including the
# corresponding file.
include("state_reps/rep_integer.jl")

# Index in the single-particle basis
# Notes:
#   -   Limited to 256 for now, can be extended arbitrarily.
#   -   Don't make unsigned: differenes (which are needed!) will also be unsigned
#       then -> this does prevent us from checking the positivity.
# const BasisIndex = Int16

# Index in the many-body Hilbert space.
# Notes:
#   -   This is the dimension of the many-body Hilbert space, a few millions
#       should be reachable.
const HilbertIndex = UInt32

# Default datatypes for the lookup dictionaries.
const LookupDict = Dict{HilbertIndex,FullState}
const InvLookupDict = Dict{FullState,HilbertIndex}

# Type for index in sparse matrices.
# Notes:
#   -   This must be at least as large as HilbertIndex, however, since there will
#       be many entries UInt64 is recommended for large runs (with more than dim H = 1e6).
#   -   This requirement is a bit unintuitive at first, but it has to do how the
#       sparse matrices are stored (compressed format, see the CSC standard).
#   -   Naturally, a larger datatype will increase memory consumption, but this is
#       what we have to live with for larger runs.
const SparseIndexType = UInt64

# Types for storage of numerical coefficients.
const WaveFunction{T<:Union{DType,CType}} = Array{T,1}
const OneBodyCoeffTensor{T<:DType} = Array{T,2}
const TwoBodyCoeffTensor{T<:DType} = Array{T,4}

abstract type Orbital end

struct Hamiltonian
    """ Datatype that represents the Hamiltonian. Merely holds all necessary
        information to construct a sparse matrix and is used only for better
        readability.
    """
    row::Vector{HilbertIndex}
    col::Vector{HilbertIndex}
    data::Vector{DType}
    n_fock::HilbertIndex
end


text:
using InterpretableModels: bbo_floor_int_searchrange, nnzeroasint, sign_predict
using InterpretableModels: sign_accuracy, sign_misclassification_rate, aspct
using InterpretableModels: as_sign_labels, nonzeroindices, uptobutexcluding

@testset "bbo_floor_int_searchrange" begin
    lb, ub = bbo_floor_int_searchrange(5)
    @test floor(Int, lb) == -5
    @test floor(Int, ub) ==  5

    lb, ub = bbo_floor_int_searchrange(10)
    @test floor(Int, lb) == -10
    @test floor(Int, ub) ==  10
end

@testset "nnzeroasint" begin
    @test nnzeroasint(Int[]) == 0
    @test nnzeroasint([1]) == 1
    @test nnzeroasint([0, 1]) == 1
    @test nnzeroasint([2, 0]) == 1
    @test nnzeroasint([3, 3]) == 2
    @test nnzeroasint([4, 0, 5]) == 2
end

@testset "sign_predict" begin
    @test sign_predict([1, 2], [1 -1;-1 0]) == Int[-1, -1]
    @test sign_predict([1.11, 2.456], [1 -1;-1 0]) == Int[-1, -1]

    @test sign_predict([1, 0], [1 -1;-1 0]) == Int[ 1, -1]
    @test sign_predict([1.45, 0.13], [1 -1;-1 0]) == Int[ 1, -1]
end

@testset "sign_accuracy and sign_misclassification_rate" begin
    yhat = y = [1, -1, 1]
    @test sign_accuracy(yhat, y) == 1.0
    @test sign_misclassification_rate(yhat, y) == 0.0
end

@testset "aspct" begin
    @test aspct(0.50) == 50.0
    @test aspct(0.334) == 33.4
end

@testset "as_sign_labels" begin
    @test as_sign_labels([1, -1]) == [1, -1]
    @test as_sign_labels([2, -3]) == [1, -1]
    @test as_sign_labels([-2,  0]) == [-1, -1]
    @test as_sign_labels([-10, 4, 0, 2]) == [-1, 1, -1, 1]

    @test as_sign_labels([-7.6, 3, 0.0]) == [-1, 1, -1]

    @test as_sign_labels([:a, :b, :a]) == [1, -1, 1]
    @test as_sign_labels([:a, :a]) == [1, 1]

    @test as_sign_labels(["a"]) == [1]
    @test as_sign_labels(["bt", "a"]) == [-1, 1]
end

@testset "nonzeroindices" begin
    @test nonzeroindices([1, 0]) == Int[1]
    @test nonzeroindices([1.2, -3]) == Int[1, 2]
    @test nonzeroindices(Float64[]) == Int[]
    @test nonzeroindices(Int[]) == Int[]
    @test nonzeroindices([0]) == Int[]

    @test nonzeroindices([-3, 1.2], false) == Int[1, 2] # Given in same order as stated
    @test nonzeroindices([-3, 1.2], true) == Int[2, 1]  # 2nd one comes before since it has higher value

    @test nonzeroindices([4, 0, -3, 1.2], false) == Int[1, 3, 4]
    @test nonzeroindices([4, 0, -3, 1.2], true) == Int[1, 4, 3]
end

@testset "uptobutexcluding" begin
    @test uptobutexcluding(5, []) == Int[1, 2, 3, 4, 5]
    @test uptobutexcluding(4, [1]) == Int[2, 3, 4]
    @test uptobutexcluding(6, [3, 1]) == Int[2, 4, 5, 6]
    @test uptobutexcluding(3, [3, 1]) == Int[2]

    @test uptobutexcluding(1, [2]) == Int[1]
    @test uptobutexcluding(1, [1]) == Int[]
    @test uptobutexcluding(0, []) == Int[]

    @test uptobutexcluding(3, ["3"]) == Int[1, 2, 3]
end


text:
# --------------------------- basic VFIT ----------------------------

# simple Vfit
function vfit!(EV0::AbstractMatrix, t::dcdp_tmpvars, prim::dcdp_primitives)
    ubV, dubV, dubV_σ, q, lse, tmp, tmp_cart, Πψtmp, IminusTEVp = t.ubVfull, t.dubVfull, t.dubV_σ, t.q, t.lse, t.tmp, t.tmp_cart, t.Πψtmp, t.IminusTEVp
    β, Πz, anticipate_e = prim.β, prim.Πz, prim.anticipate_e

    if anticipate_e
        logsumexp3!(lse,tmp,ubV)
    else
        maximum!(add_1_dim(lse), ubV)
    end
    A_mul_B_md!(EV0,Πz,lse,1)
end

# preserves ubV & updates derivatives
# function vfit!(EV0::AbstractMatrix, dEV0::AbstractArray3, ubV::AbstractArray3, dubV::AbstractArray4, q::AbstractArray3, lse::AbstractMatrix, tmp::AbstractMatrix, Πz::AbstractMatrix)
function vfit!(EV0::AbstractMatrix, dEV0::AbstractArray3, dEV0σ::AbstractMatrix, t::dcdp_tmpvars, prim::dcdp_primitives)
    ubV, dubV, dubV_σ, q, lse, tmp, tmp_cart, Πψtmp, IminusTEVp = t.ubVfull, t.dubVfull, t.dubV_σ, t.q, t.lse, t.tmp, t.tmp_cart, t.Πψtmp, t.IminusTEVp
    β, Πz, anticipate_e = prim.β, prim.Πz, prim.anticipate_e

    if anticipate_e
        logsumexp_and_softmax3!(lse,q,tmp,ubV) # FIXME!!
    else
        findmax!(add_1_dim(lse), add_1_dim(tmp_cart), ubV)
        fill!(q, 0.0)
        @inbounds @simd for i in tmp_cart
            q[i] = 1.0
        end
    end
    A_mul_B_md!(EV0,Πz,lse,1)
    sumdubV = @view(dubV[:,:,:,1])
    sumprod!(sumdubV,dubV,q)                # maybe use rind in a SparseMatrixCSC{Bool} for nzvals and then multiply?
    A_mul_B_md!(dEV0,Πz,sumdubV,1)

    # ∂EV/∂σ = I ⊗ Πz * ∑( Pr(d) * ∂ubV/∂σ[zspace, ψspace, d]  )
    if length(dEV0σ) > 0
        sumprod!(tmp, dubV_σ, q)
        @views A_mul_B_md!(dEV0σ, Πz, tmp, 1)
    end
end

function vfit!(EV0::AbstractMatrix, dEV0::AbstractArray3, t::dcdp_tmpvars, prim::dcdp_primitives)
    vfit!(EV0, dEV0, Matrix{Float64}(undef,0,0), t, prim)
end

# destroys ubV and updates derivatives
function vfit_destroy_ubV!(EV0::AbstractMatrix, dEV0::AbstractArray3, t::dcdp_tmpvars, prim::dcdp_primitives)
    t2 = dcdp_tmpvars(t.ubVfull, t.dubVfull, t.dubV_σ, t.ubVfull, t.lse, t.tmp, t.tmp_cart, t.Πψtmp, t.IminusTEVp, t.anticipate_e)
    vfit!(EV0, dEV0, t2, prim)
end

# --------------------------- VFIT until conv ----------------------------

function solve_inf_vfit!(EV0::AbstractMatrix, t::dcdp_tmpvars, prim::dcdp_primitives; maxit::Integer=60, vftol::Real=1e-11)
    ubV, dubV, dubV_σ, q, lse, tmp, tmp_cart, Πψtmp, IminusTEVp = t.ubVfull, t.dubVfull, t.dubV_σ, t.q, t.lse, t.tmp, t.tmp_cart, t.Πψtmp, t.IminusTEVp
    β, Πz, anticipate_e = prim.β, prim.Πz, prim.anticipate_e

    iter = zero(maxit)
    while true
        vfit!(tmp, t, prim)
        bnds = extrema(tmp.-EV0) .* β ./ (1.0 .- β)
        ubV[:,:,1] .= β .* (EV0 .= tmp)
        iter += 1
        converged = all(abs.(bnds) .< vftol)
        if converged  ||  iter >= maxit
            return converged, iter, bnds
        end
    end
end

# --------------------------- basic pfit ----------------------------

function pfit!(EV0::AbstractMatrix, t::dcdp_tmpvars, prim::dcdp_primitives; vftol::Real=1e-11)

    ubV, dubV, dubV_σ, q, lse, tmp, tmp_cart, Πψtmp, IminusTEVp = t.ubVfull, t.dubVfull, t.dubV_σ, t.q, t.lse, t.tmp, t.tmp_cart, t.Πψtmp, t.IminusTEVp
    β, Πz, anticipate_e = prim.β, prim.Πz, prim.anticipate_e

    ΔEV = lse
    @views q0 = ubV[:,:,1]

    if anticipate_e
        logsumexp_and_softmax3!(ΔEV, q0, tmp, ubV)
    else
        findmax!(add_1_dim(ΔEV), add_1_dim(tmp_cart), ubV)
        q0 .= last.(getfield.(tmp_cart, :I)) .== 1         # update q0 as Pr(d=0|x)
    end
    A_mul_B_md!(tmp, Πz, ΔEV, 1)

    # compute difference & check bnds
    bnds = extrema(ΔEV .= EV0 .- tmp) .* -β ./ (1.0 .- β)
    if all(abs.(bnds) .< vftol)
        EV0 .= tmp
        return bnds
    end

    # full PFit
    for j in 1:size(EV0, 2)
        q0j = @view(q0[:,j])
        ΔEVj = @view(ΔEV[:,j])

        update_IminusTVp!(IminusTEVp, Πz, β, q0j)
        fact = lu(IminusTEVp)
        ldiv!(fact, ΔEVj)                          # Vtmp = [I - T'(V)] \ [V - T(V)]
    end
    EV0 .-= ΔEV                               # update V
    return extrema(ΔEV) .* -β ./ (1.0 .- β)   # get norm
end

# --------------------------- pfit until convergence ----------------------------

function solve_inf_pfit!(EV0::AbstractMatrix, t::dcdp_tmpvars, prim::dcdp_primitives; maxit::Integer=30, vftol::Real=1e-11)
    ubV, dubV, dubV_σ, q, lse, tmp, tmp_cart, Πψtmp, IminusTEVp = t.ubVfull, t.dubVfull, t.dubV_σ, t.q, t.lse, t.tmp, t.tmp_cart, t.Πψtmp, t.IminusTEVp
    β, Πz, anticipate_e = prim.β, prim.Πz, prim.anticipate_e

    iter = zero(maxit)
    while true
        bnds = pfit!(EV0, t, prim; vftol=vftol)
        iter += 1
        converged = all(abs.(bnds) .< vftol)
        if converged  ||  iter >= maxit
            return converged, iter, bnds
        end
        ubV[:,:,1] .= β .* EV0
    end
end

# --------------------------- inf horizon gradient ----------------------------

# note -- this destroys ubV
function gradinf!(dEV0::AbstractArray3{T}, dEV0σ::AbstractMatrix{T}, t::dcdp_tmpvars, prim::dcdp_primitives, do_σ::Bool=false) where {T}

    ubV, dubV, dubV_σ, q, lse, tmp, tmp_cart, Πψtmp, IminusTEVp = t.ubVfull, t.dubVfull, t.dubV_σ, t.q, t.lse, t.tmp, t.tmp_cart, t.Πψtmp, t.IminusTEVp
    β, Πz, anticipate_e = prim.β, prim.Πz, prim.anticipate_e

    size(dubV,4) >= 2 || throw(DimensionMismatch("Need dubV with at least 2+ action possibilities"))
    nθ = size(dubV,3)

    @views sumdubV   = dubV[:,:,:,1]
    @views ΠsumdubV  = dubV[:,:,:,2]

    @views ΠsumdubVj = lse[:,1:nθ] # Array{T}(nz,nθ)
    @views dev0tmpj  = tmp[:,1:nθ] # Array{T}(nz,nθ)

    q = ubV

    if anticipate_e
        softmax3!(q, lse, tmp)
    else
        findmax!(add_1_dim(lse), add_1_dim(tmp_cart), ubV)
        fill!(q, 0.0)
        for i in tmp_cart
            q[i] = 1.0
        end
    end

    # for dubV/dθt
    sumprod!(sumdubV, dubV, q)
    A_mul_B_md!(ΠsumdubV, Πz, sumdubV, 1)

    # for dubV/dσ
    if do_σ
        @views sumdubV_σ   = dubV_σ[:,:,1]
        @views ΠsumdubV_σ  = dubV_σ[:,:,2]
        @views ΠsumdubV_σj = lse[:,1] # Array{T}(nz)
        @views dev0tmp_σj = tmp[:,1] # Array{T}(nz)

        sumprod!(sumdubV_σ, dubV_σ, q)
        A_mul_B_md!(ΠsumdubV_σ, Πz, sumdubV_σ, 1)
    end

    for j in 1:size(dubV,2)
        @views update_IminusTVp!(IminusTEVp, Πz, β, q[:,j,1])
        fact = lu(IminusTEVp)

        # Note: cannot do this with @view(dEV0[:,j,:])
        @views ΠsumdubVj .= ΠsumdubV[:,j,:]
        ldiv!(dev0tmpj, fact, ΠsumdubVj) # ΠsumdubV[:,j,:])
        dEV0[:,j,:] .= dev0tmpj

        if do_σ
            @views ΠsumdubV_σj .= ΠsumdubV_σ[:,j]
            ldiv!(dev0tmp_σj, fact, ΠsumdubV_σj) # ΠsumdubV[:,j,:])
            dEV0σ[:,j] .= dev0tmp_σj
        end
    end
end

function gradinf!(dEV0::AbstractArray3{T}, t::dcdp_tmpvars, prim::dcdp_primitives) where {T}
    zeros2 = Array{T,2}(undef,0,0)
    gradinf!(dEV0, zeros2, t, prim, false)
end

# --------------------------- double vfit/pfit loop -----------------------

function solve_inf_vfit_pfit!(EV0::AbstractMatrix, t::dcdp_tmpvars, prim::dcdp_primitives; vftol::Real=1e-9, maxit0::Integer=40, maxit1::Integer=20)
    solve_inf_vfit!(EV0, t, prim; maxit=maxit0, vftol=vftol)

    # try-catch loop in case we have insane parameters that have Pr(no action) = 0, producing a singular IminusTEVp matrix.
    converged, iter, bnds = try
        solve_inf_pfit!(EV0, t, prim; maxit=maxit1, vftol=vftol)
    catch
        @warn "pfit threw error. trying vfit."
        solve_inf_vfit!(EV0, t, prim; maxit=5000, vftol=vftol)
    end
    return converged, iter, bnds
end

# --------------------------- helper function  ----------------------------

function sumprod!(red::AbstractArray3{T}, big::AbstractArray4, small::AbstractArray3) where {T}
    nz,nψ,nv,nd = size(big)
    (nz,nψ,nd,) == size(small) || throw(DimensionMismatch())
    (nz,nψ,nv,) == size(red)   || throw(DimensionMismatch())

    # can't do this b/c of src/vfit.jl#13-14 above where red = big[:,:,:,1]
    # fill!(red, zero(T))
    # @inbounds for d in 1:nd, v in 1:nv
    #     @views red[:,:,v] .+= small[:,:,d] .* big[:,:,v,d]
    # end

    # first loop w/ equals
    @inbounds for v in 1:nv
        @views red[:,:,v] .= small[:,:,1] .* big[:,:,v,1]
    end

    # second set w/ plus equals
    @inbounds for d in 2:nd, v in 1:nv
        @views red[:,:,v] .+= small[:,:,d] .* big[:,:,v,d]
    end
end

function sumprod!(red::AbstractMatrix{T}, big::AbstractArray3, small::AbstractArray3) where {T}
    nz,nψ,nd = size(big)
    (nz,nψ,nd) == size(small) || throw(DimensionMismatch())
    (nz,nψ) == size(red) || throw(DimensionMismatch())

    fill!(red, zero(T))
    @inbounds for d in 1:nd
        @views red .+= small[:,:,d] .* big[:,:,d]
    end
end


text:
## type join (closest common ancestor, or least upper bound) ##

typejoin() = None
typejoin(t::ANY) = t
typejoin(t::ANY, ts...) = typejoin(t, typejoin(ts...))
function typejoin(a::ANY, b::ANY)
    if isa(a,TypeConstructor); a = a.body; end
    if isa(b,TypeConstructor); b = b.body; end
    if a <: b
        return b
    elseif b <: a
        return a
    end
    if isa(a,TypeVar)
        return typejoin(a.ub, b)
    end
    if isa(b,TypeVar)
        return typejoin(a, b.ub)
    end
    if isa(a,UnionType) || isa(b,UnionType)
        u = Union(a, b)
        if !isa(u,UnionType)
            return u
        end
        return reduce(typejoin, None, u.types)
    end
    if isa(a,Tuple)
        if !isa(b,Tuple)
            return Any
        end
        la = length(a)::Int; lb = length(b)::Int
        if la==0 || lb==0
            return Tuple
        end
        if la < lb
            if isvarargtype(a[la])
                c = cell(la)
                c[la] = Vararg{typejoin(a[la].parameters[1], tailjoin(b,la))}
                n = la-1
            else
                c = cell(la+1)
                c[la+1] = Vararg{tailjoin(b,la+1)}
                n = la
            end
        elseif lb < la
            if isvarargtype(b[lb])
                c = cell(lb)
                c[lb] = Vararg{typejoin(b[lb].parameters[1], tailjoin(a,lb))}
                n = lb-1
            else
                c = cell(lb+1)
                c[lb+1] = Vararg{tailjoin(a,lb+1)}
                n = lb
            end
        else
            c = cell(la)
            n = la
        end
        for i=1:n
            ai = a[i]; bi = b[i]
            va = false
            if isvarargtype(ai); va=true; ai = ai.parameters[1]; end
            if isvarargtype(bi); va=true; bi = bi.parameters[1]; end
            t = typejoin(ai,bi)
            c[i] = va ? Vararg{t} : t
        end
        return tuple(c...)
    elseif isa(b,Tuple)
        return Any
    end
    while !is(b,Any)
        if a <: b
            return b
        end
        if a <: b.name.primary
            return b.name.primary
        end
        b = super(b)
    end
    return Any
end

# reduce typejoin over tup[i:end]
function tailjoin(tup, i)
    t = None
    for j = i:length(tup)
        tj = tup[j]
        t = typejoin(t, isvarargtype(tj)?tj.parameters[1]:tj)
    end
    return t
end

## promotion mechanism ##

promote_type()  = None
promote_type(T) = T
promote_type(T, S   ) = typejoin(T, S)
promote_type(T, S...) = promote_type(T, promote_type(S...))

promote_type(::Type{None}, ::Type{None}) = None
promote_type{T}(::Type{T}, ::Type{T}) = T
promote_type{T}(::Type{T}, ::Type{None}) = T
promote_type{T}(::Type{None}, ::Type{T}) = T

# Try promote_rule in both orders. Typically only one is defined,
# and there is a fallback returning None below, so the common case is
#   promote_type(T, S) =>
#   promote_result(T, S, result, None) =>
#   typejoin(result, None) => result
promote_type{T,S}(::Type{T}, ::Type{S}) =
    promote_result(T, S, promote_rule(T,S), promote_rule(S,T))

promote_rule(T, S) = None

promote_result(t,s,T,S) = promote_type(T,S)
# If no promote_rule is defined, both directions give None. In that
# case use typejoin on the original types instead.
promote_result{T,S}(::Type{T},::Type{S},::Type{None},::Type{None}) = typejoin(T, S)

promote() = ()
promote(x) = (x,)
function promote{T,S}(x::T, y::S)
    (convert(promote_type(T,S),x), convert(promote_type(T,S),y))
end
promote_typeof(x) = typeof(x)
promote_typeof(x, xs...) = promote_type(typeof(x), promote_typeof(xs...))
function promote(x, y, z)
    (convert(promote_typeof(x,y,z), x),
     convert(promote_typeof(x,y,z), y),
     convert(promote_typeof(x,y,z), z))
end
function promote(x, y, zs...)
    tuple(convert(promote_typeof(x,y,zs...), x),
          convert(promote_typeof(x,y,zs...), y),
          convert((promote_typeof(x,y,zs...)...), zs)...)
end
# TODO: promote{T}(x::T, ys::T...) here to catch all circularities?

## promotions in arithmetic, etc. ##

# Because of the promoting fallback definitions for Number, we need
# a special case for undefined promote_rule on numeric types.
# Otherwise, typejoin(T,S) is called (returning Number) so no conversion
# happens, and +(promote(x,y)...) is called again, causing a stack
# overflow.
promote_result{T<:Number,S<:Number}(::Type{T},::Type{S},::Type{None},::Type{None}) =
    promote_to_super(T, S, typejoin(T,S))

# promote numeric types T and S to typejoin(T,S) if T<:S or S<:T
# for example this makes promote_type(Integer,Real) == Real without
# promoting arbitrary pairs of numeric types to Number.
promote_to_super{T<:Number          }(::Type{T}, ::Type{T}, ::Type{T}) = T
promote_to_super{T<:Number,S<:Number}(::Type{T}, ::Type{S}, ::Type{T}) = T
promote_to_super{T<:Number,S<:Number}(::Type{T}, ::Type{S}, ::Type{S}) = S
promote_to_super{T<:Number,S<:Number}(::Type{T}, ::Type{S}, ::Type) =
    error("no promotion exists for ", T, " and ", S)

+(x::Number, y::Number) = +(promote(x,y)...)
*(x::Number, y::Number) = *(promote(x,y)...)
-(x::Number, y::Number) = -(promote(x,y)...)
/(x::Number, y::Number) = /(promote(x,y)...)
^(x::Number, y::Number) = ^(promote(x,y)...)

(&)(x::Integer, y::Integer) = (&)(promote(x,y)...)
(|)(x::Integer, y::Integer) = (|)(promote(x,y)...)
($)(x::Integer, y::Integer) = ($)(promote(x,y)...)

==(x::Number, y::Number) = (==)(promote(x,y)...)
< (x::Real, y::Real)     = (< )(promote(x,y)...)
<=(x::Real, y::Real)     = (<=)(promote(x,y)...)

div(x::Real, y::Real) = div(promote(x,y)...)
fld(x::Real, y::Real) = fld(promote(x,y)...)
rem(x::Real, y::Real) = rem(promote(x,y)...)
mod(x::Real, y::Real) = mod(promote(x,y)...)

mod1(x::Real, y::Real) = mod1(promote(x,y)...)
rem1(x::Real, y::Real) = rem1(promote(x,y)...)
fld1(x::Real, y::Real) = fld1(promote(x,y)...)

max(x::Real, y::Real) = max(promote(x,y)...)
min(x::Real, y::Real) = min(promote(x,y)...)
minmax(x::Real, y::Real) = minmax(promote(x, y)...)

## catch-alls to prevent infinite recursion when definitions are missing ##

no_op_err(name, T) = error(name," not defined for ",T)
+{T<:Number}(x::T, y::T) = no_op_err("+", T)
*{T<:Number}(x::T, y::T) = no_op_err("*", T)
-{T<:Number}(x::T, y::T) = no_op_err("-", T)
/{T<:Number}(x::T, y::T) = no_op_err("/", T)
^{T<:Number}(x::T, y::T) = no_op_err("^", T)

(&){T<:Integer}(x::T, y::T) = no_op_err("&", T)
(|){T<:Integer}(x::T, y::T) = no_op_err("|", T)
($){T<:Integer}(x::T, y::T) = no_op_err("\$", T)

=={T<:Number}(x::T, y::T) = x === y
<{T<:Real}(x::T, y::T) = no_op_err("<", T)

max{T<:Real}(x::T, y::T) = ifelse(y < x, x, y)
min{T<:Real}(x::T, y::T) = ifelse(x < y, x, y)
minmax{T<:Real}(x::T, y::T) = x < y ? (x, y) : (y, x)

max_stars_repo_name: jakebolewski/julia

max_issues_repo_name: jakebolewski/julia

max_forks_repo_name: jakebolewski/julia


text:
using RegressionAndOtherStories

hdi = CSV.read(ros_data("HDI", "hdi.dat"), DataFrame; delim=" ")
f = open(ros_datadir("HDI", "hdi.csv"), "w")
CSV.write(f, hdi)
close(f)

hdi = CSV.read(ros_datadir("HDI", "hdi.csv"), DataFrame)