text:
################################################################################
# Fuel requirements ############################################################
################################################################################

"""Fuel required to launch a given module is based on its mass.
Specifically, to find the fuel required for a module, take its mass,
divide by three, round down, and subtract 2.
"""
fuelForModule(mass) = max(0, (mass ÷ 3) - 2)

"""Fuel itself requires fuel just like a module.
However, that fuel also requires fuel, and that fuel requires fuel, and so on.
"""
function rocketEqFuel(mass)
    totalFuel = 0
    additionalFuel = fuelForModule(mass)
    while additionalFuel > 0
        totalFuel += additionalFuel
        additionalFuel = fuelForModule(additionalFuel)
    end
    totalFuel
end

################################################################################
# Elf Virtual Machine (Intcode computer) #######################################
################################################################################

"""When running many virtual machines in parallel, each machine has an execution
state. If the vm is waiting for input from another vm, it is set to WaitForInput."""
@enum VMState begin
    Initialized = 0
    Running = 1
    WaitForInput = 2
    Halted = 99
end

mutable struct ElfVM
    memory::Vector{Int}
    extraMemory::Dict{Int, Int}
    instructionPointer::Int
    relativePointer::Int
    stdin::Vector{Int}
    stdout::Vector{Int}
    state::VMState
end

function ElfVM(memory)
    ElfVM(memory, Dict(), 0, 0, [], [], Initialized)
end

function Base.copy(vm::ElfVM)::ElfVM
    ElfVM(copy(vm.memory), copy(vm.extraMemory), vm.instructionPointer, vm.relativePointer, copy(vm.stdin), copy(vm.stdout), vm.state)
end

@enum Opcode begin
    Addition = 1
    Multiplication = 2
    ReadStdin = 3
    WriteStdout = 4
    JumpIfTrue = 5
    JumpIfFalse = 6
    LessThan = 7
    Equals = 8
    ShiftRelativeBase = 9
    Halt = 99
end

function set!(vm::ElfVM, i, v)
    if length(vm.memory) >= i + 1
        vm.memory[i + 1] = v
    else
        vm.extraMemory[i + 1] = v
    end
end

function get(vm::ElfVM, i)
    if length(vm.memory) >= i + 1
        vm.memory[i + 1]
    else
        if i + 1 in keys(vm.extraMemory)
            vm.extraMemory[i + 1]
        else
            vm.extraMemory[i + 1] = 0
        end
    end
end

current_instruction(vm) = get(vm, vm.instructionPointer)

params3(vm) = (get(vm, vm.instructionPointer + 1),
    get(vm, vm.instructionPointer + 2),
    get(vm, vm.instructionPointer + 3))

"""Decodes an instruction into a tuple (opcode, parameter_modes)"""
parse_instruction(with_parameter_modes::Int) = (Opcode(with_parameter_modes % 100), digits(with_parameter_modes ÷ 100))

"""Reads a parameter of the instruction, given a relative offset.
Can differentiate between different read modes. (position/immediate/..)
Missing read modes are assumed to be position mode."""
function read_param(vm::ElfVM, i::Int, parameter_modes::Vector{Int})::Int
    mode = i <= length(parameter_modes) ? parameter_modes[i] : 0
    value = get(vm, vm.instructionPointer + i)
    if mode == 0
        # position mode
        return get(vm, value)
    elseif mode == 1
        # immediate mode
        return value
    elseif mode == 2
        # relative mode
        return get(vm, vm.relativePointer + value)
    end

end

"""Writes the value to the register given as the i-th parameter of
the current operation."""
function write_param!(vm::ElfVM, i::Int, value, parameter_modes::Vector{Int})
    mode = i <= length(parameter_modes) ? parameter_modes[i] : 0
    parameter = get(vm, vm.instructionPointer + i)
    if mode == 0
        target = parameter
    elseif mode == 2
        target = vm.relativePointer + parameter
    end
    set!(vm, target, value)
end

"""Executes one instruction on the ElfVM and returns whether it is still active.
"""
function tick!(vm::ElfVM)
    @assert vm.state == Running "The vm is $(vm.state), you must not call tick!()."
    (opcode, parameter_modes) = parse_instruction(current_instruction(vm))
    if opcode == Addition
        # Addition
        a = read_param(vm, 1, parameter_modes)
        b = read_param(vm, 2, parameter_modes)
        c = a + b
        write_param!(vm, 3, c, parameter_modes)
        step!(vm, 4)
    elseif opcode == Multiplication
        # Multiplication
        a = read_param(vm, 1, parameter_modes)
        b = read_param(vm, 2, parameter_modes)
        c = a * b
        write_param!(vm, 3, c, parameter_modes)
        step!(vm, 4)
    elseif opcode == ReadStdin
        # If there is no input on stdin, the vm suspends.
        if length(vm.stdin) > 0
            a = popfirst!(vm.stdin)
            write_param!(vm, 1, a, parameter_modes)
            step!(vm, 2)
        else
            vm.state = WaitForInput
        end
    elseif opcode == WriteStdout
        # Write to stdout
        a = read_param(vm, 1, parameter_modes)
        push!(vm.stdout, a)
        step!(vm, 2)
    elseif opcode == JumpIfTrue
        # jump-if-true
        a = read_param(vm, 1, parameter_modes)
        if a != 0
            b = read_param(vm, 2, parameter_modes)
            vm.instructionPointer = b
        else
            step!(vm, 3)
        end
    elseif opcode == JumpIfFalse
        # jump-if-false
        a = read_param(vm, 1, parameter_modes)
        if a == 0
            b = read_param(vm, 2, parameter_modes)
            vm.instructionPointer = b
        else
            step!(vm, 3)
        end
    elseif opcode == LessThan
        # less than
        a = read_param(vm, 1, parameter_modes)
        b = read_param(vm, 2, parameter_modes)
        c = a < b ? 1 : 0
        write_param!(vm, 3, c, parameter_modes)
        step!(vm, 4)
    elseif opcode == Equals
        # equals
        a = read_param(vm, 1, parameter_modes)
        b = read_param(vm, 2, parameter_modes)
        c = a == b ? 1 : 0
        write_param!(vm, 3, c, parameter_modes)
        step!(vm, 4)
    elseif opcode == ShiftRelativeBase
        # Opcode 9 adjusts the relative base by the value of its only parameter.
        a = read_param(vm, 1, parameter_modes)
        vm.relativePointer += a
        step!(vm, 2)
    elseif opcode == Halt
        vm.state = Halted
    else
        throw("Opcode $opcode not implemented!")
    end
end

function step!(vm, n)
    vm.instructionPointer += n
end

function runnable(vm::ElfVM)::Bool
    if vm.state == Initialized
        true
    elseif vm.state == Running
        true
    elseif vm.state == WaitForInput
        length(vm.stdin) > 0
    elseif vm.state == Halted
        false
    else
        throw("VM state $(vm.state) not recognized.")
    end
end

function run!(vm::ElfVM)::VMState
    vm.state = Running
    while vm.state == Running
        tick!(vm)
    end
    vm.state
end

function runWithArguments(vm, noun, verb)
    set!(vm, 1, noun)
    set!(vm, 2, verb)
    run!(vm)
    get(vm, 0)
end

function findArguments(vm, output)
    for i in 0:99, j in 0:99
        if runWithArguments(copy(vm2), i, j) == output
            return (i, j)
        end
    end
end

################################################################################
# Multithreaded Elf Virtual Machine ############################################
################################################################################

mutable struct MultiThreadElfVM
    threads::Dict{Int, ElfVM}
    forwards::Dict{Int, Int}
end

function MultiThreadElfVM(bytecode::Vector{Int}, pids::Vector{Int}, forwards::Dict{Int, Int})
    vm = MultiThreadElfVM(Dict(), Dict())
    for pid in pids
        vm.threads[pid] = ElfVM(copy(bytecode))
    end
    vm.forwards = copy(forwards)
    vm
end

# Convenicene functions to work with stdin

function push_stdin!(vm::MultiThreadElfVM, pid, value)
    push!(vm.threads[pid].stdin, value)
end

"""A scheduler that runs all the threads."""
function run!(multi_thread::MultiThreadElfVM)
    # Right now, I hope that "Round Robin" is going to be good enought.
    runnable_threads::Vector{Int} = []
    suspended_threads::Set{Int} = Set()
    for (pid, thread) in multi_thread.threads
        if runnable(thread)
            push!(runnable_threads, pid)
        else
            push!(suspended_threads, pid)
        end
    end

    while length(runnable_threads) > 0
        # Pick the next runnable thread in line and do one execution
        pid = popfirst!(runnable_threads)
        thread = multi_thread.threads[pid]
        thread.state = Running
        # As a possible performance improvement, I could do several ticks
        # at once. This reduces overhead from context switching.
        tick!(thread)

        # Decide where this thread goes next
        if runnable(thread)
            push!(runnable_threads, pid)
        else
            push!(suspended_threads, pid)
        end

        # Take care of signal forwarding
        if length(thread.stdout) > 0 && pid in keys(multi_thread.forwards)
            target_pid = multi_thread.forwards[pid]
            target_thread = multi_thread.threads[target_pid]

            while length(thread.stdout) > 0
                push!(target_thread.stdin, popfirst!(thread.stdout))
            end

            # Check, if this wakes the target thread
            if runnable(target_thread) && target_pid in suspended_threads
                delete!(suspended_threads, target_pid)
                push!(runnable_threads, target_pid)
            end
        end
    end
end

################################################################################
# Wire pannels #################################################################
################################################################################

struct HorizontalWire
    x1::Int
    x2::Int
    y::Int
    offset::Int
end

struct VerticalWire
    x::Int
    y1::Int
    y2::Int
    offset::Int
end

@enum Direction begin
    Up = 1
    Left = 2
    Down = 3
    Right = 4
end

direction_keys = Dict('U' => Up, 'L' => Left, 'D' => Down, 'R' => Right)

function Direction(str::SubString)
    dir = direction_keys[str[1]]
    len = parse(Int, str[2:end])
    (dir, len)
end

parseDirectionString(str::String) = Direction.(split(str, ","))

function createWires(directions)
    wires = Vector{Any}(undef, length(directions))
    x = 0
    y = 0
    offset = 0
    for i in 1:length(directions)
        (d, l) = directions[i]
        if d == Up
            y1 = y
            y += l
            wires[i] = VerticalWire(x, y1, y, offset)
        elseif d == Down
            y1 = y
            y -= l
            wires[i] = VerticalWire(x, y1, y, offset)
        elseif d == Right
            x1 = x
            x += l
            wires[i] = HorizontalWire(x1, x, y, offset)
        elseif d == Left
            x1 = x
            x -= l
            wires[i] = HorizontalWire(x1, x, y, offset)
        end
        offset += l
    end
    wires
    end

intersect(w1::HorizontalWire, w2::HorizontalWire) = Nothing()
intersect(w1::VerticalWire, w2::VerticalWire) = Nothing()
intersect(w1::VerticalWire, w2::HorizontalWire) = intersect(w2, w1)
function intersect(w1::HorizontalWire, w2::VerticalWire)
    if w1.x1 < w2.x < w1.x2 || w1.x1 > w2.x > w1.x2
        if w2.y1 < w1.y < w2.y2 || w2.y1 > w1.y > w2.y2
            signalTime = w1.offset + w2.offset
            signalTime += abs(w1.x1 - w2.x)
            signalTime += abs(w2.y1 - w1.y)
            return (w2.x, w1.y, signalTime)
        end
    end
    Nothing()
end

function intersections(wires1, wires2)
    result = []
    for w1 in wires1, w2 in wires2
        intersection = intersect(w1, w2)
        if intersection != Nothing()
            push!(result, intersection)
        end
    end
    result
end

intersection_offset((_, _, offset)) = offset

manhattan((x, y, _)) = abs(x) + abs(y)

################################################################################
# Password Check ###############################################################
################################################################################

"""However, they do remember a few key facts about the password:

* It is a six-digit number.
* The value is within the range given in your puzzle input.
* Two adjacent digits are the same (like 22 in 122345).
* Going from left to right, the digits never decrease; they only ever increase or stay the same (like 111123 or 135679).
"""
function check_password(number)
    dgts = digits(number)[end:-1:1]
    pairFound = false
    for i in 2:6
        pairFound = pairFound || dgts[i - 1] == dgts[i]
        if dgts[i] < dgts[i - 1]
            return false
        end
    end
    pairFound
end

"""An Elf just remembered one more important detail:
the two adjacent matching digits are not part of a larger group of matching digits.
"""
function check_password_stronger(number)
    dgts = digits(number)[end:-1:1]
    pairFound = false
    seqCount = 1
    for i in 2:6
        if dgts[i - 1] == dgts[i]
            seqCount += 1
        else
            if seqCount == 2
                pairFound = true
            end
            seqCount = 1
        end
        if dgts[i] < dgts[i - 1]
            return false
        end
        end

    if seqCount == 2
        pairFound = true
    end

    pairFound
end

################################################################################
# Orbit Maps ###################################################################
################################################################################

mutable struct OrbitMap
    centers::Dict{String,String}
    depth::Dict{String,Int}
end

"""Takes a string like "XQQ)W94" and outputs the tuple ("XQQ", "W94").
This indicates, that XQQ (e.g. Sun) is orbited by W94 (e.g. Planet).
"""
orbitRelationship(str::String) = (str[1:3], str[5:7])

function cacheOrbitDepth(om::OrbitMap, object::String)::Int
    if object in keys(om.depth)
        om.depth[object]
    else
        depth = 1 + cacheOrbitDepth(om, om.centers[object])
        om.depth[object] = depth
    end
end

    """Builds an OrbitMap from a readlines input."""
function OrbitMap(lines::Vector{String})::OrbitMap
    orbitMap = OrbitMap(Dict(), Dict("COM" => 0))
    for (inside, outside) in orbitRelationship.(lines)
        orbitMap.centers[outside] = inside
    end

    for (outside, _) in orbitMap.centers
        cacheOrbitDepth(orbitMap, outside)
    end
    orbitMap
end

"""Determine the distance, using the property that we are on a tree."""
function distance(om::OrbitMap, a::String, b::String)::Int
    if a == b
        0
    elseif om.depth[a] > om.depth[b]
        1 + distance(om, om.centers[a], b)
    elseif om.depth[a] < om.depth[b]
        1 + distance(om, a, om.centers[b])
    else
        2 + distance(om, om.centers[a], om.centers[b])
    end
end


text:
using SHA

@testset "Client" begin

    host = "127.0.0.1"
    server_port = 8080
    server_url = "http://" * host * ":" * string(server_port)

    num_comm_rounds = 1
    fraction_clients = 0.1f0
    num_total_clients = 10
    chunksize = 256

    newconfig() = Fed.Config.QuantizedConfig{UInt8}(
        Fed.Config.BaseConfig(
            server_url,
            num_comm_rounds,
            fraction_clients,
            num_total_clients
        )
    )

    function start_testing_server()
        # dummy values for testing purpose
        weights = rand(Float32, 199210)
        strategy = Fed.Server.federated_averaging
        eval_hook = (weights::Vector{Float32}) -> (0.0f0, 0.0f0)
        config = newconfig()

        central_node = Fed.Server.CentralNode(
            host,
            server_port,
            weights,
            strategy,
            eval_hook,
            config
        )

        @async Fed.Server.start(central_node)
    end

    @testset "Start client" begin
        server = start_testing_server()

        train_hook = (weights::Vector{Float32}) -> weights
        config = newconfig()

        node = Fed.Client.Node(
            host,
            8081,
            train_hook,
            config
        )

        @async Fed.Client.start(node)
        sleep(2)
        @test true
    end

end

ext: jl


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

@doc raw"""DEPRECATED 1.9 - This group version of NetworkPolicyIngressRule is deprecated by networking/v1/NetworkPolicyIngressRule. This NetworkPolicyIngressRule matches traffic if and only if the traffic matches both ports AND from.

    IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule(;
        from=nothing,
        ports=nothing,
    )

    - from::Vector{IoK8sApiExtensionsV1beta1NetworkPolicyPeer} : List of sources which should be able to access the pods selected for this rule. Items in this list are combined using a logical OR operation. If this field is empty or missing, this rule matches all sources (traffic not restricted by source). If this field is present and contains at least one item, this rule allows traffic only if the traffic matches at least one item in the from list.
    - ports::Vector{IoK8sApiExtensionsV1beta1NetworkPolicyPort} : List of ports which should be made accessible on the pods selected for this rule. Each item in this list is combined using a logical OR. If this field is empty or missing, this rule matches all ports (traffic not restricted by port). If this field is present and contains at least one item, then this rule allows traffic only if the traffic matches at least one port in the list.
"""
mutable struct IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule <: SwaggerModel
    from::Any # spec type: Union{ Nothing, Vector{IoK8sApiExtensionsV1beta1NetworkPolicyPeer} } # spec name: from
    ports::Any # spec type: Union{ Nothing, Vector{IoK8sApiExtensionsV1beta1NetworkPolicyPort} } # spec name: ports

    function IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule(;from=nothing, ports=nothing)
        o = new()
        validate_property(IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule, Symbol("from"), from)
        setfield!(o, Symbol("from"), from)
        validate_property(IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule, Symbol("ports"), ports)
        setfield!(o, Symbol("ports"), ports)
        o
    end
end # type IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule

const _property_map_IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule = Dict{Symbol,Symbol}(Symbol("from")=>Symbol("from"), Symbol("ports")=>Symbol("ports"))
const _property_types_IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule = Dict{Symbol,String}(Symbol("from")=>"Vector{IoK8sApiExtensionsV1beta1NetworkPolicyPeer}", Symbol("ports")=>"Vector{IoK8sApiExtensionsV1beta1NetworkPolicyPort}")
Base.propertynames(::Type{ IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule }) = collect(keys(_property_map_IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule))
Swagger.property_type(::Type{ IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule[name]))}
Swagger.field_name(::Type{ IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule }, property_name::Symbol) =  _property_map_IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule[property_name]

function check_required(o::IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule)
    true
end

function validate_property(::Type{ IoK8sApiExtensionsV1beta1NetworkPolicyIngressRule }, name::Symbol, val)
end


text:
#const PV_PTR_DECL = (*)
#const FALSE = PV_FAIL
#const TRUE = PV_OK
const rs_bool = UInt16
const int8 = UInt8
const uns8 = Cuchar
const int16 = Int16
const uns16 = UInt16
const int32 = Cint
const uns32 = UInt32
const flt32 = Cfloat
const flt64 = Cdouble
const ulong64 = Culonglong
const long64 = Clonglong

const void_ptr = Ptr{Cvoid}
const void_ptr_ptr = Ptr{Ptr{Cvoid}}
const rs_bool_ptr = Ptr{rs_bool}
const char_ptr = Cstring
const int8_ptr = Ptr{int8}
const uns8_ptr = Ptr{uns8}
const int16_ptr = Ptr{int16}
const uns16_ptr = Ptr{uns16}
const int32_ptr = Ptr{int32}
const uns32_ptr = Ptr{uns32}
const flt32_ptr = Ptr{flt32}
const flt64_ptr = Ptr{flt64}
const ulong64_ptr = Ptr{ulong64}
const long64_ptr = Ptr{long64}
const rs_bool_const_ptr = Ptr{rs_bool}
const char_const_ptr = Cstring
const int8_const_ptr = Ptr{int8}
const uns8_const_ptr = Ptr{uns8}
const int16_const_ptr = Ptr{int16}
const uns16_const_ptr = Ptr{uns16}
const int32_const_ptr = Ptr{int32}
const uns32_const_ptr = Ptr{uns32}
const flt32_const_ptr = Ptr{flt32}
const flt64_const_ptr = Ptr{flt64}
const ulong64_const_ptr = Ptr{ulong64}
const long64_const_ptr = Ptr{long64}

const PVCAM_LIB_VERSION_MAJOR = 2
const MAX_CAM = 16
const CAM_NAME_LEN = 32
const PARAM_NAME_LEN = 32
const ERROR_MSG_LEN = 255
const CCD_NAME_LEN = 17
const MAX_ALPHA_SER_NUM_LEN = 32
const MAX_PP_NAME_LEN = 32
const MAX_SYSTEM_NAME_LEN = 32
const MAX_VENDOR_NAME_LEN = 32
const MAX_PRODUCT_NAME_LEN = 32
const MAX_CAM_PART_NUM_LEN = 32
const MAX_GAIN_NAME_LEN = 32
const MAX_CAM_SYSTEMS_INFO_LEN = 1024
const PP_MAX_PARAMETERS_PER_FEATURE = 10
const PL_MD_FRAME_SIGNATURE = 5328208
const PL_MD_EXT_TAGS_MAX_SUPPORTED = 255

# MS16_BYTE ( two_byte_value ) ( ( uns8 ) ( ( ( uns16 ) ( two_byte_value ) >> 8 ) & 0xFF ) )
# LS16_BYTE ( two_byte_value ) ( ( uns8 ) ( ( ( uns16 ) ( two_byte_value ) >> 0 ) & 0xFF ) )
# MS32_BYTE ( four_byte_value ) ( ( uns8 ) ( ( ( uns32 ) ( four_byte_value ) >> 24 ) & 0xFF ) )
# MH32_BYTE ( four_byte_value ) ( ( uns8 ) ( ( ( uns32 ) ( four_byte_value ) >> 16 ) & 0xFF ) )
# ML32_BYTE ( four_byte_value ) ( ( uns8 ) ( ( ( uns32 ) ( four_byte_value ) >> 8 ) & 0xFF ) )
# LS32_BYTE ( four_byte_value ) ( ( uns8 ) ( ( ( uns32 ) ( four_byte_value ) >> 0 ) & 0xFF ) )
# VAL_UNS16 ( ms_byte , ls_byte ) ( ( ( uns16 ) ( ( uns8 ) ( ms_byte ) ) << 8 ) | ( ( uns16 ) ( ( uns8 ) ( ls_byte ) ) << 0 ) )
# VAL_UNS32 ( ms_byte , mh_byte , ml_byte , ls_byte ) ( ( ( uns32 ) ( ( uns8 ) ( ms_byte ) ) << 24 ) | ( ( uns32 ) ( ( uns8 ) ( mh_byte ) ) << 16 ) | ( ( uns32 ) ( ( uns8 ) ( ml_byte ) ) << 8 ) | ( ( uns32 ) ( ( uns8 ) ( ls_byte ) ) << 0 ) )
# VAL_INT64 ( b0 , b1 , b2 , b3 , b4 , b5 , b6 , b7 ) ( ( ( long64 ) ( ( uns8 ) ( b0 ) ) << 56 ) | ( ( long64 ) ( ( uns8 ) ( b1 ) ) << 48 ) | ( ( long64 ) ( ( uns8 ) ( b2 ) ) << 40 ) | ( ( long64 ) ( ( uns8 ) ( b3 ) ) << 32 ) | ( ( long64 ) ( ( uns8 ) ( b4 ) ) << 24 ) | ( ( long64 ) ( ( uns8 ) ( b5 ) ) << 16 ) | ( ( long64 ) ( ( uns8 ) ( b6 ) ) << 8 ) | ( ( long64 ) ( ( uns8 ) ( b7 ) ) << 0 ) )

const TYPE_INT16 = 1
const TYPE_INT32 = 2
const TYPE_FLT64 = 4
const TYPE_UNS8 = 5
const TYPE_UNS16 = 6
const TYPE_UNS32 = 7
const TYPE_UNS64 = 8
const TYPE_ENUM = 9
const TYPE_BOOLEAN = 11
const TYPE_INT8 = 12
const TYPE_CHAR_PTR = 13
const TYPE_VOID_PTR = 14
const TYPE_VOID_PTR_PTR = 15
const TYPE_INT64 = 16
const TYPE_SMART_STREAM_TYPE = 17
const TYPE_SMART_STREAM_TYPE_PTR = 18
const TYPE_FLT32 = 19
const CLASS0 = 0
const CLASS2 = 2
const CLASS3 = 3

# Skipping MacroDefinition: PARAM_DD_INFO_LENGTH ( ( CLASS0 << 16 ) + ( TYPE_INT16 << 24 ) + 1 )
# Skipping MacroDefinition: PARAM_DD_VERSION ( ( CLASS0 << 16 ) + ( TYPE_UNS16 << 24 ) + 2 )
# Skipping MacroDefinition: PARAM_DD_RETRIES ( ( CLASS0 << 16 ) + ( TYPE_UNS16 << 24 ) + 3 )
# Skipping MacroDefinition: PARAM_DD_TIMEOUT ( ( CLASS0 << 16 ) + ( TYPE_UNS16 << 24 ) + 4 )
# Skipping MacroDefinition: PARAM_DD_INFO ( ( CLASS0 << 16 ) + ( TYPE_CHAR_PTR << 24 ) + 5 )
# Skipping MacroDefinition: PARAM_CAM_INTERFACE_TYPE ( ( CLASS0 << 16 ) + ( TYPE_ENUM << 24 ) + 10 )
# Skipping MacroDefinition: PARAM_CAM_INTERFACE_MODE ( ( CLASS0 << 16 ) + ( TYPE_ENUM << 24 ) + 11 )
# Skipping MacroDefinition: PARAM_ADC_OFFSET ( ( CLASS2 << 16 ) + ( TYPE_INT16 << 24 ) + 195 )
# Skipping MacroDefinition: PARAM_CHIP_NAME ( ( CLASS2 << 16 ) + ( TYPE_CHAR_PTR << 24 ) + 129 )
# Skipping MacroDefinition: PARAM_SYSTEM_NAME ( ( CLASS2 << 16 ) + ( TYPE_CHAR_PTR << 24 ) + 130 )
# Skipping MacroDefinition: PARAM_VENDOR_NAME ( ( CLASS2 << 16 ) + ( TYPE_CHAR_PTR << 24 ) + 131 )
# Skipping MacroDefinition: PARAM_PRODUCT_NAME ( ( CLASS2 << 16 ) + ( TYPE_CHAR_PTR << 24 ) + 132 )
# Skipping MacroDefinition: PARAM_CAMERA_PART_NUMBER ( ( CLASS2 << 16 ) + ( TYPE_CHAR_PTR << 24 ) + 133 )
# Skipping MacroDefinition: PARAM_COOLING_MODE ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 214 )
# Skipping MacroDefinition: PARAM_PREAMP_DELAY ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 502 )
# Skipping MacroDefinition: PARAM_COLOR_MODE ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 504 )
# Skipping MacroDefinition: PARAM_MPP_CAPABLE ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 224 )
# Skipping MacroDefinition: PARAM_PREAMP_OFF_CONTROL ( ( CLASS2 << 16 ) + ( TYPE_UNS32 << 24 ) + 507 )
# Skipping MacroDefinition: PARAM_PREMASK ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 53 )
# Skipping MacroDefinition: PARAM_PRESCAN ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 55 )
# Skipping MacroDefinition: PARAM_POSTMASK ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 54 )
# Skipping MacroDefinition: PARAM_POSTSCAN ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 56 )
# Skipping MacroDefinition: PARAM_PIX_PAR_DIST ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 500 )
# Skipping MacroDefinition: PARAM_PIX_PAR_SIZE ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 63 )
# Skipping MacroDefinition: PARAM_PIX_SER_DIST ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 501 )
# Skipping MacroDefinition: PARAM_PIX_SER_SIZE ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 62 )
# Skipping MacroDefinition: PARAM_SUMMING_WELL ( ( CLASS2 << 16 ) + ( TYPE_BOOLEAN << 24 ) + 505 )
# Skipping MacroDefinition: PARAM_FWELL_CAPACITY ( ( CLASS2 << 16 ) + ( TYPE_UNS32 << 24 ) + 506 )
# Skipping MacroDefinition: PARAM_PAR_SIZE ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 57 )
# Skipping MacroDefinition: PARAM_SER_SIZE ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 58 )
# Skipping MacroDefinition: PARAM_ACCUM_CAPABLE ( ( CLASS2 << 16 ) + ( TYPE_BOOLEAN << 24 ) + 538 )
# Skipping MacroDefinition: PARAM_FLASH_DWNLD_CAPABLE ( ( CLASS2 << 16 ) + ( TYPE_BOOLEAN << 24 ) + 539 )
# Skipping MacroDefinition: PARAM_READOUT_TIME ( ( CLASS2 << 16 ) + ( TYPE_FLT64 << 24 ) + 179 )
# Skipping MacroDefinition: PARAM_CLEARING_TIME ( ( CLASS2 << 16 ) + ( TYPE_INT64 << 24 ) + 180 )
# Skipping MacroDefinition: PARAM_POST_TRIGGER_DELAY ( ( CLASS2 << 16 ) + ( TYPE_INT64 << 24 ) + 181 )
# Skipping MacroDefinition: PARAM_PRE_TRIGGER_DELAY ( ( CLASS2 << 16 ) + ( TYPE_INT64 << 24 ) + 182 )
# Skipping MacroDefinition: PARAM_CLEAR_CYCLES ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 97 )
# Skipping MacroDefinition: PARAM_CLEAR_MODE ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 523 )
# Skipping MacroDefinition: PARAM_FRAME_CAPABLE ( ( CLASS2 << 16 ) + ( TYPE_BOOLEAN << 24 ) + 509 )
# Skipping MacroDefinition: PARAM_PMODE ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 524 )
# Skipping MacroDefinition: PARAM_TEMP ( ( CLASS2 << 16 ) + ( TYPE_INT16 << 24 ) + 525 )
# Skipping MacroDefinition: PARAM_TEMP_SETPOINT ( ( CLASS2 << 16 ) + ( TYPE_INT16 << 24 ) + 526 )
# Skipping MacroDefinition: PARAM_CAM_FW_VERSION ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 532 )
# Skipping MacroDefinition: PARAM_HEAD_SER_NUM_ALPHA ( ( CLASS2 << 16 ) + ( TYPE_CHAR_PTR << 24 ) + 533 )
# Skipping MacroDefinition: PARAM_PCI_FW_VERSION ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 534 )
# Skipping MacroDefinition: PARAM_FAN_SPEED_SETPOINT ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 710 )
# Skipping MacroDefinition: PARAM_CAM_SYSTEMS_INFO ( ( CLASS2 << 16 ) + ( TYPE_CHAR_PTR << 24 ) + 536 )
# Skipping MacroDefinition: PARAM_EXPOSURE_MODE ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 535 )
# Skipping MacroDefinition: PARAM_EXPOSE_OUT_MODE ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 560 )
# Skipping MacroDefinition: PARAM_BIT_DEPTH ( ( CLASS2 << 16 ) + ( TYPE_INT16 << 24 ) + 511 )
# Skipping MacroDefinition: PARAM_IMAGE_FORMAT ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 248 )
# Skipping MacroDefinition: PARAM_IMAGE_COMPRESSION ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 249 )
# Skipping MacroDefinition: PARAM_SCAN_MODE ( ( CLASS3 << 16 ) + ( TYPE_ENUM << 24 ) + 250 )
# Skipping MacroDefinition: PARAM_SCAN_DIRECTION ( ( CLASS3 << 16 ) + ( TYPE_ENUM << 24 ) + 251 )
# Skipping MacroDefinition: PARAM_SCAN_DIRECTION_RESET ( ( CLASS3 << 16 ) + ( TYPE_BOOLEAN << 24 ) + 252 )
# Skipping MacroDefinition: PARAM_SCAN_LINE_DELAY ( ( CLASS3 << 16 ) + ( TYPE_UNS16 << 24 ) + 253 )
# Skipping MacroDefinition: PARAM_SCAN_LINE_TIME ( ( CLASS3 << 16 ) + ( TYPE_INT64 << 24 ) + 254 )
# Skipping MacroDefinition: PARAM_SCAN_WIDTH ( ( CLASS3 << 16 ) + ( TYPE_UNS16 << 24 ) + 255 )
# Skipping MacroDefinition: PARAM_GAIN_INDEX ( ( CLASS2 << 16 ) + ( TYPE_INT16 << 24 ) + 512 )
# Skipping MacroDefinition: PARAM_SPDTAB_INDEX ( ( CLASS2 << 16 ) + ( TYPE_INT16 << 24 ) + 513 )
# Skipping MacroDefinition: PARAM_GAIN_NAME ( ( CLASS2 << 16 ) + ( TYPE_CHAR_PTR << 24 ) + 514 )
# Skipping MacroDefinition: PARAM_READOUT_PORT ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 247 )
# Skipping MacroDefinition: PARAM_PIX_TIME ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 516 )
# Skipping MacroDefinition: PARAM_SHTR_CLOSE_DELAY ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 519 )
# Skipping MacroDefinition: PARAM_SHTR_OPEN_DELAY ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 520 )
# Skipping MacroDefinition: PARAM_SHTR_OPEN_MODE ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 521 )
# Skipping MacroDefinition: PARAM_SHTR_STATUS ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 522 )
# Skipping MacroDefinition: PARAM_IO_ADDR ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 527 )
# Skipping MacroDefinition: PARAM_IO_TYPE ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 528 )
# Skipping MacroDefinition: PARAM_IO_DIRECTION ( ( CLASS2 << 16 ) + ( TYPE_ENUM << 24 ) + 529 )
# Skipping MacroDefinition: PARAM_IO_STATE ( ( CLASS2 << 16 ) + ( TYPE_FLT64 << 24 ) + 530 )
# Skipping MacroDefinition: PARAM_IO_BITDEPTH ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 531 )
# Skipping MacroDefinition: PARAM_GAIN_MULT_FACTOR ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 537 )
# Skipping MacroDefinition: PARAM_GAIN_MULT_ENABLE ( ( CLASS2 << 16 ) + ( TYPE_BOOLEAN << 24 ) + 541 )
# Skipping MacroDefinition: PARAM_PP_FEAT_NAME ( ( CLASS2 << 16 ) + ( TYPE_CHAR_PTR << 24 ) + 542 )
# Skipping MacroDefinition: PARAM_PP_INDEX ( ( CLASS2 << 16 ) + ( TYPE_INT16 << 24 ) + 543 )
# Skipping MacroDefinition: PARAM_ACTUAL_GAIN ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 544 )
# Skipping MacroDefinition: PARAM_PP_PARAM_INDEX ( ( CLASS2 << 16 ) + ( TYPE_INT16 << 24 ) + 545 )
# Skipping MacroDefinition: PARAM_PP_PARAM_NAME ( ( CLASS2 << 16 ) + ( TYPE_CHAR_PTR << 24 ) + 546 )
# Skipping MacroDefinition: PARAM_PP_PARAM ( ( CLASS2 << 16 ) + ( TYPE_UNS32 << 24 ) + 547 )
# Skipping MacroDefinition: PARAM_READ_NOISE ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 548 )
# Skipping MacroDefinition: PARAM_PP_FEAT_ID ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 549 )
# Skipping MacroDefinition: PARAM_PP_PARAM_ID ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 550 )
# Skipping MacroDefinition: PARAM_SMART_STREAM_MODE_ENABLED ( ( CLASS2 << 16 ) + ( TYPE_BOOLEAN << 24 ) + 700 )
# Skipping MacroDefinition: PARAM_SMART_STREAM_MODE ( ( CLASS2 << 16 ) + ( TYPE_UNS16 << 24 ) + 701 )
# Skipping MacroDefinition: PARAM_SMART_STREAM_EXP_PARAMS ( ( CLASS2 << 16 ) + ( TYPE_VOID_PTR << 24 ) + 702 )
# Skipping MacroDefinition: PARAM_SMART_STREAM_DLY_PARAMS ( ( CLASS2 << 16 ) + ( TYPE_VOID_PTR << 24 ) + 703 )
# Skipping MacroDefinition: PARAM_EXP_TIME ( ( CLASS3 << 16 ) + ( TYPE_UNS16 << 24 ) + 1 )
# Skipping MacroDefinition: PARAM_EXP_RES ( ( CLASS3 << 16 ) + ( TYPE_ENUM << 24 ) + 2 )
# Skipping MacroDefinition: PARAM_EXP_RES_INDEX ( ( CLASS3 << 16 ) + ( TYPE_UNS16 << 24 ) + 4 )
# Skipping MacroDefinition: PARAM_EXPOSURE_TIME ( ( CLASS3 << 16 ) + ( TYPE_UNS64 << 24 ) + 8 )
# Skipping MacroDefinition: PARAM_BOF_EOF_ENABLE ( ( CLASS3 << 16 ) + ( TYPE_ENUM << 24 ) + 5 )
# Skipping MacroDefinition: PARAM_BOF_EOF_COUNT ( ( CLASS3 << 16 ) + ( TYPE_UNS32 << 24 ) + 6 )
# Skipping MacroDefinition: PARAM_BOF_EOF_CLR ( ( CLASS3 << 16 ) + ( TYPE_BOOLEAN << 24 ) + 7 )
# Skipping MacroDefinition: PARAM_CIRC_BUFFER ( ( CLASS3 << 16 ) + ( TYPE_BOOLEAN << 24 ) + 299 )
# Skipping MacroDefinition: PARAM_FRAME_BUFFER_SIZE ( ( CLASS3 << 16 ) + ( TYPE_UNS64 << 24 ) + 300 )
# Skipping MacroDefinition: PARAM_BINNING_SER ( ( CLASS3 << 16 ) + ( TYPE_ENUM << 24 ) + 165 )
# Skipping MacroDefinition: PARAM_BINNING_PAR ( ( CLASS3 << 16 ) + ( TYPE_ENUM << 24 ) + 166 )
# Skipping MacroDefinition: PARAM_METADATA_ENABLED ( ( CLASS3 << 16 ) + ( TYPE_BOOLEAN << 24 ) + 168 )
# Skipping MacroDefinition: PARAM_ROI_COUNT ( ( CLASS3 << 16 ) + ( TYPE_UNS16 << 24 ) + 169 )
# Skipping MacroDefinition: PARAM_CENTROIDS_ENABLED ( ( CLASS3 << 16 ) + ( TYPE_BOOLEAN << 24 ) + 170 )
# Skipping MacroDefinition: PARAM_CENTROIDS_RADIUS ( ( CLASS3 << 16 ) + ( TYPE_UNS16 << 24 ) + 171 )
# Skipping MacroDefinition: PARAM_CENTROIDS_COUNT ( ( CLASS3 << 16 ) + ( TYPE_UNS16 << 24 ) + 172 )
# Skipping MacroDefinition: PARAM_CENTROIDS_MODE ( ( CLASS3 << 16 ) + ( TYPE_ENUM << 24 ) + 173 )
# Skipping MacroDefinition: PARAM_CENTROIDS_BG_COUNT ( ( CLASS3 << 16 ) + ( TYPE_ENUM << 24 ) + 174 )
# Skipping MacroDefinition: PARAM_CENTROIDS_THRESHOLD ( ( CLASS3 << 16 ) + ( TYPE_UNS32 << 24 ) + 175 )
# Skipping MacroDefinition: PARAM_TRIGTAB_SIGNAL ( ( CLASS3 << 16 ) + ( TYPE_ENUM << 24 ) + 180 )
# Skipping MacroDefinition: PARAM_LAST_MUXED_SIGNAL ( ( CLASS3 << 16 ) + ( TYPE_UNS8 << 24 ) + 181 )
# Skipping MacroDefinition: PARAM_FRAME_DELIVERY_MODE ( ( CLASS3 << 16 ) + ( TYPE_ENUM << 24 ) + 400 )

const PVCAM_FRAME_INFO_GUID = _TAG_PVCAM_FRAME_INFO_GUID
const FRAME_INFO = _TAG_FRAME_INFO

@cenum PL_OPEN_MODES::UInt32 begin
    OPEN_EXCLUSIVE = 0
end

@cenum PL_COOL_MODES::UInt32 begin
    NORMAL_COOL = 0
    CRYO_COOL = 1
    NO_COOL = 2
end

@cenum PL_MPP_MODES::UInt32 begin
    MPP_UNKNOWN = 0
    MPP_ALWAYS_OFF = 1
    MPP_ALWAYS_ON = 2
    MPP_SELECTABLE = 3
end

@cenum PL_SHTR_MODES::UInt32 begin
    SHTR_FAULT = 0
    SHTR_OPENING = 1
    SHTR_OPEN = 2
    SHTR_CLOSING = 3
    SHTR_CLOSED = 4
    SHTR_UNKNOWN = 5
end

@cenum PL_PMODES::UInt32 begin
    PMODE_NORMAL = 0
    PMODE_FT = 1
    PMODE_MPP = 2
    PMODE_FT_MPP = 3
    PMODE_ALT_NORMAL = 4
    PMODE_ALT_FT = 5
    PMODE_ALT_MPP = 6
    PMODE_ALT_FT_MPP = 7
end

@cenum PL_COLOR_MODES::UInt32 begin
    COLOR_NONE = 0
    COLOR_RESERVED = 1
    COLOR_RGGB = 2
    COLOR_GRBG = 3
    COLOR_GBRG = 4
    COLOR_BGGR = 5
end

@cenum PL_IMAGE_FORMATS::UInt32 begin
    PL_IMAGE_FORMAT_MONO16 = 0
    PL_IMAGE_FORMAT_BAYER16 = 1
    PL_IMAGE_FORMAT_MONO8 = 2
    PL_IMAGE_FORMAT_BAYER8 = 3
    PL_IMAGE_FORMAT_MONO24 = 4
    PL_IMAGE_FORMAT_BAYER24 = 5
    PL_IMAGE_FORMAT_RGB24 = 6
    PL_IMAGE_FORMAT_RGB48 = 7
    PL_IMAGE_FORMAT_RGB72 = 8
end

@cenum PL_IMAGE_COMPRESSIONS::UInt32 begin
    PL_IMAGE_COMPRESSION_NONE = 0
    PL_IMAGE_COMPRESSION_RESERVED8 = 8
    PL_IMAGE_COMPRESSION_BITPACK9 = 9
    PL_IMAGE_COMPRESSION_BITPACK10 = 10
    PL_IMAGE_COMPRESSION_BITPACK11 = 11
    PL_IMAGE_COMPRESSION_BITPACK12 = 12
    PL_IMAGE_COMPRESSION_BITPACK13 = 13
    PL_IMAGE_COMPRESSION_BITPACK14 = 14
    PL_IMAGE_COMPRESSION_BITPACK15 = 15
    PL_IMAGE_COMPRESSION_RESERVED16 = 16
    PL_IMAGE_COMPRESSION_BITPACK17 = 17
    PL_IMAGE_COMPRESSION_BITPACK18 = 18
    PL_IMAGE_COMPRESSION_RESERVED24 = 24
    PL_IMAGE_COMPRESSION_RESERVED32 = 32
end

@cenum PL_PARAM_ATTRIBUTES::UInt32 begin
    ATTR_CURRENT = 0
    ATTR_COUNT = 1
    ATTR_TYPE = 2
    ATTR_MIN = 3
    ATTR_MAX = 4
    ATTR_DEFAULT = 5
    ATTR_INCREMENT = 6
    ATTR_ACCESS = 7
    ATTR_AVAIL = 8
end

@cenum PL_PARAM_ACCESS::UInt32 begin
    ACC_READ_ONLY = 1
    ACC_READ_WRITE = 2
    ACC_EXIST_CHECK_ONLY = 3
    ACC_WRITE_ONLY = 4
end

@cenum PL_IO_TYPE::UInt32 begin
    IO_TYPE_TTL = 0
    IO_TYPE_DAC = 1
end

@cenum PL_IO_DIRECTION::UInt32 begin
    IO_DIR_INPUT = 0
    IO_DIR_OUTPUT = 1
    IO_DIR_INPUT_OUTPUT = 2
end

@cenum PL_READOUT_PORTS::UInt32 begin
    READOUT_PORT_0 = 0
    READOUT_PORT_1 = 1
end

@cenum PL_CLEAR_MODES::UInt32 begin
    CLEAR_NEVER = 0
    CLEAR_PRE_EXPOSURE = 1
    CLEAR_PRE_SEQUENCE = 2
    CLEAR_POST_SEQUENCE = 3
    CLEAR_PRE_POST_SEQUENCE = 4
    CLEAR_PRE_EXPOSURE_POST_SEQ = 5
    MAX_CLEAR_MODE = 6
end

@cenum PL_SHTR_OPEN_MODES::UInt32 begin
    OPEN_NEVER = 0
    OPEN_PRE_EXPOSURE = 1
    OPEN_PRE_SEQUENCE = 2
    OPEN_PRE_TRIGGER = 3
    OPEN_NO_CHANGE = 4
end

@cenum PL_EXPOSURE_MODES::UInt32 begin
    TIMED_MODE = 0
    STROBED_MODE = 1
    BULB_MODE = 2
    TRIGGER_FIRST_MODE = 3
    FLASH_MODE = 4
    VARIABLE_TIMED_MODE = 5
    INT_STROBE_MODE = 6
    MAX_EXPOSE_MODE = 7
    EXT_TRIG_INTERNAL = 1792
    EXT_TRIG_TRIG_FIRST = 2048
    EXT_TRIG_EDGE_RISING = 2304
end

@cenum PL_EXPOSE_OUT_MODES::UInt32 begin
    EXPOSE_OUT_FIRST_ROW = 0
    EXPOSE_OUT_ALL_ROWS = 1
    EXPOSE_OUT_ANY_ROW = 2
    EXPOSE_OUT_ROLLING_SHUTTER = 3
    MAX_EXPOSE_OUT_MODE = 4
end

@cenum PL_FAN_SPEEDS::UInt32 begin
    FAN_SPEED_HIGH = 0
    FAN_SPEED_MEDIUM = 1
    FAN_SPEED_LOW = 2
    FAN_SPEED_OFF = 3
end

@cenum PL_TRIGTAB_SIGNALS::UInt32 begin
    PL_TRIGTAB_SIGNAL_EXPOSE_OUT = 0
end

@cenum PL_FRAME_DELIVERY_MODES::UInt32 begin
    PL_FRAME_DELIVERY_MODE_MAX_FPS = 0
    PL_FRAME_DELIVERY_MODE_CONSTANT_INTERVALS = 1
end

@cenum PL_CAM_INTERFACE_TYPES::UInt32 begin
    PL_CAM_IFC_TYPE_UNKNOWN = 0
    PL_CAM_IFC_TYPE_1394 = 256
    PL_CAM_IFC_TYPE_1394_A = 257
    PL_CAM_IFC_TYPE_1394_B = 258
    PL_CAM_IFC_TYPE_USB = 512
    PL_CAM_IFC_TYPE_USB_1_1 = 513
    PL_CAM_IFC_TYPE_USB_2_0 = 514
    PL_CAM_IFC_TYPE_USB_3_0 = 515
    PL_CAM_IFC_TYPE_USB_3_1 = 516
    PL_CAM_IFC_TYPE_PCI = 1024
    PL_CAM_IFC_TYPE_PCI_LVDS = 1025
    PL_CAM_IFC_TYPE_PCIE = 2048
    PL_CAM_IFC_TYPE_PCIE_LVDS = 2049
    PL_CAM_IFC_TYPE_PCIE_X1 = 2050
    PL_CAM_IFC_TYPE_PCIE_X4 = 2051
    PL_CAM_IFC_TYPE_VIRTUAL = 4096
    PL_CAM_IFC_TYPE_ETHERNET = 8192
end

@cenum PL_CAM_INTERFACE_MODES::UInt32 begin
    PL_CAM_IFC_MODE_UNSUPPORTED = 0
    PL_CAM_IFC_MODE_CONTROL_ONLY = 1
    PL_CAM_IFC_MODE_IMAGING = 2
end

@cenum PL_CENTROIDS_MODES::UInt32 begin
    PL_CENTROIDS_MODE_LOCATE = 0
    PL_CENTROIDS_MODE_TRACK = 1
    PL_CENTROIDS_MODE_BLOB = 2
end

@cenum PL_SCAN_MODES::UInt32 begin
    PL_SCAN_MODE_AUTO = 0
    PL_SCAN_MODE_PROGRAMMABLE_LINE_DELAY = 1
    PL_SCAN_MODE_PROGRAMMABLE_SCAN_WIDTH = 2
end

@cenum PL_SCAN_DIRECTIONS::UInt32 begin
    PL_SCAN_DIRECTION_DOWN = 0
    PL_SCAN_DIRECTION_UP = 1
    PL_SCAN_DIRECTION_DOWN_UP = 2
end

@cenum PP_FEATURE_IDS::UInt32 begin
    PP_FEATURE_RING_FUNCTION = 0
    PP_FEATURE_BIAS = 1
    PP_FEATURE_BERT = 2
    PP_FEATURE_QUANT_VIEW = 3
    PP_FEATURE_BLACK_LOCK = 4
    PP_FEATURE_TOP_LOCK = 5
    PP_FEATURE_VARI_BIT = 6
    PP_FEATURE_RESERVED = 7
    PP_FEATURE_DESPECKLE_BRIGHT_HIGH = 8
    PP_FEATURE_DESPECKLE_DARK_LOW = 9
    PP_FEATURE_DEFECTIVE_PIXEL_CORRECTION = 10
    PP_FEATURE_DYNAMIC_DARK_FRAME_CORRECTION = 11
    PP_FEATURE_HIGH_DYNAMIC_RANGE = 12
    PP_FEATURE_DESPECKLE_BRIGHT_LOW = 13
    PP_FEATURE_DENOISING = 14
    PP_FEATURE_DESPECKLE_DARK_HIGH = 15
    PP_FEATURE_ENHANCED_DYNAMIC_RANGE = 16
    PP_FEATURE_MAX = 17
end

@cenum PP_PARAMETER_IDS::UInt32 begin
    PP_PARAMETER_RF_FUNCTION = 0
    PP_FEATURE_BIAS_ENABLED = 10
    PP_FEATURE_BIAS_LEVEL = 11
    PP_FEATURE_BERT_ENABLED = 20
    PP_FEATURE_BERT_THRESHOLD = 21
    PP_FEATURE_QUANT_VIEW_ENABLED = 30
    PP_FEATURE_QUANT_VIEW_E = 31
    PP_FEATURE_BLACK_LOCK_ENABLED = 40
    PP_FEATURE_BLACK_LOCK_BLACK_CLIP = 41
    PP_FEATURE_TOP_LOCK_ENABLED = 50
    PP_FEATURE_TOP_LOCK_WHITE_CLIP = 51
    PP_FEATURE_VARI_BIT_ENABLED = 60
    PP_FEATURE_VARI_BIT_BIT_DEPTH = 61
    PP_FEATURE_DESPECKLE_BRIGHT_HIGH_ENABLED = 80
    PP_FEATURE_DESPECKLE_BRIGHT_HIGH_THRESHOLD = 81
    PP_FEATURE_DESPECKLE_BRIGHT_HIGH_MIN_ADU_AFFECTED = 82
    PP_FEATURE_DESPECKLE_DARK_LOW_ENABLED = 90
    PP_FEATURE_DESPECKLE_DARK_LOW_THRESHOLD = 91
    PP_FEATURE_DESPECKLE_DARK_LOW_MAX_ADU_AFFECTED = 92
    PP_FEATURE_DEFECTIVE_PIXEL_CORRECTION_ENABLED = 100
    PP_FEATURE_DYNAMIC_DARK_FRAME_CORRECTION_ENABLED = 110
    PP_FEATURE_HIGH_DYNAMIC_RANGE_ENABLED = 120
    PP_FEATURE_DESPECKLE_BRIGHT_LOW_ENABLED = 130
    PP_FEATURE_DESPECKLE_BRIGHT_LOW_THRESHOLD = 131
    PP_FEATURE_DESPECKLE_BRIGHT_LOW_MAX_ADU_AFFECTED = 132
    PP_FEATURE_DENOISING_ENABLED = 140
    PP_FEATURE_DENOISING_NO_OF_ITERATIONS = 141
    PP_FEATURE_DENOISING_GAIN = 142
    PP_FEATURE_DENOISING_OFFSET = 143
    PP_FEATURE_DENOISING_LAMBDA = 144
    PP_FEATURE_DESPECKLE_DARK_HIGH_ENABLED = 150
    PP_FEATURE_DESPECKLE_DARK_HIGH_THRESHOLD = 151
    PP_FEATURE_DESPECKLE_DARK_HIGH_MIN_ADU_AFFECTED = 152
    PP_FEATURE_ENHANCED_DYNAMIC_RANGE_ENABLED = 160
    PP_PARAMETER_ID_MAX = 161
end

struct smart_stream_type
    entries::uns16
    params::Ptr{uns32}
end

@cenum PL_SMT_MODES::UInt32 begin
    SMTMODE_ARBITRARY_ALL = 0
    SMTMODE_MAX = 1
end

@cenum PL_IMAGE_STATUSES::UInt32 begin
    READOUT_NOT_ACTIVE = 0
    EXPOSURE_IN_PROGRESS = 1
    READOUT_IN_PROGRESS = 2
    READOUT_COMPLETE = 3
    FRAME_AVAILABLE = 3
    READOUT_FAILED = 4
    ACQUISITION_IN_PROGRESS = 5
    MAX_CAMERA_STATUS = 6
end

@cenum PL_CCS_ABORT_MODES::UInt32 begin
    CCS_NO_CHANGE = 0
    CCS_HALT = 1
    CCS_HALT_CLOSE_SHTR = 2
    CCS_CLEAR = 3
    CCS_CLEAR_CLOSE_SHTR = 4
    CCS_OPEN_SHTR = 5
    CCS_CLEAR_OPEN_SHTR = 6
end

@cenum PL_IRQ_MODES::UInt32 begin
    NO_FRAME_IRQS = 0
    BEGIN_FRAME_IRQS = 1
    END_FRAME_IRQS = 2
    BEGIN_END_FRAME_IRQS = 3
end

@cenum PL_CIRC_MODES::UInt32 begin
    CIRC_NONE = 0
    CIRC_OVERWRITE = 1
    CIRC_NO_OVERWRITE = 2
end

@cenum PL_EXP_RES_MODES::UInt32 begin
    EXP_RES_ONE_MILLISEC = 0
    EXP_RES_ONE_MICROSEC = 1
    EXP_RES_ONE_SEC = 2
end

@cenum PL_SRC_MODES::UInt32 begin
    SCR_PRE_OPEN_SHTR = 0
    SCR_POST_OPEN_SHTR = 1
    SCR_PRE_FLASH = 2
    SCR_POST_FLASH = 3
    SCR_PRE_INTEGRATE = 4
    SCR_POST_INTEGRATE = 5
    SCR_PRE_READOUT = 6
    SCR_POST_READOUT = 7
    SCR_PRE_CLOSE_SHTR = 8
    SCR_POST_CLOSE_SHTR = 9
end

@cenum PL_CALLBACK_EVENT::UInt32 begin
    PL_CALLBACK_BOF = 0
    PL_CALLBACK_EOF = 1
    PL_CALLBACK_CHECK_CAMS = 2
    PL_CALLBACK_CAM_REMOVED = 3
    PL_CALLBACK_CAM_RESUMED = 4
    PL_CALLBACK_MAX = 5
end

struct rgn_type
    s1::uns16
    s2::uns16
    sbin::uns16
    p1::uns16
    p2::uns16
    pbin::uns16
end

struct io_struct
    io_port::uns16
    io_type::uns32
    state::flt64
    next::Ptr{io_struct}
end

const io_entry = io_struct

struct io_list
    pre_open::io_entry
    post_open::io_entry
    pre_flash::io_entry
    post_flash::io_entry
    pre_integrate::io_entry
    post_integrate::io_entry
    pre_readout::io_entry
    post_readout::io_entry
    pre_close::io_entry
    post_close::io_entry
end

struct active_camera_type
    shutter_close_delay::uns16
    shutter_open_delay::uns16
    rows::uns16
    cols::uns16
    prescan::uns16
    postscan::uns16
    premask::uns16
    postmask::uns16
    preflash::uns16
    clear_count::uns16
    preamp_delay::uns16
    mpp_selectable::rs_bool
    frame_selectable::rs_bool
    do_clear::int16
    open_shutter::int16
    mpp_mode::rs_bool
    frame_transfer::rs_bool
    alt_mode::rs_bool
    exp_res::uns32
    io_hdr::Ptr{io_list}
end

@cenum PL_MD_FRAME_FLAGS::UInt32 begin
    PL_MD_FRAME_FLAG_ROI_TS_SUPPORTED = 1
    PL_MD_FRAME_FLAG_UNUSED_2 = 2
    PL_MD_FRAME_FLAG_UNUSED_3 = 4
    PL_MD_FRAME_FLAG_UNUSED_4 = 16
    PL_MD_FRAME_FLAG_UNUSED_5 = 32
    PL_MD_FRAME_FLAG_UNUSED_6 = 64
    PL_MD_FRAME_FLAG_UNUSED_7 = 128
end

@cenum PL_MD_ROI_FLAGS::UInt32 begin
    PL_MD_ROI_FLAG_INVALID = 1
    PL_MD_ROI_FLAG_HEADER_ONLY = 2
    PL_MD_ROI_FLAG_UNUSED_3 = 4
    PL_MD_ROI_FLAG_UNUSED_4 = 16
    PL_MD_ROI_FLAG_UNUSED_5 = 32
    PL_MD_ROI_FLAG_UNUSED_6 = 64
    PL_MD_ROI_FLAG_UNUSED_7 = 128
end

struct md_frame_header
    signature::uns32
    version::uns8
    frameNr::uns32
    roiCount::uns16
    timestampBOF::uns32
    timestampEOF::uns32
    timestampResNs::uns32
    exposureTime::uns32
    exposureTimeResNs::uns32
    roiTimestampResNs::uns32
    bitDepth::uns8
    colorMask::uns8
    flags::uns8
    extendedMdSize::uns16
    imageFormat::uns8
    imageCompression::uns8
    _reserved::NTuple{6, uns8}
end

struct md_frame_roi_header
    roiNr::uns16
    timestampBOR::uns32
    timestampEOR::uns32
    roi::rgn_type
    flags::uns8
    extendedMdSize::uns16
    roiDataSize::uns32
    _reserved::NTuple{3, uns8}
end

@cenum PL_MD_EXT_TAGS::UInt32 begin
    PL_MD_EXT_TAG_PARTICLE_ID = 0
    PL_MD_EXT_TAG_PARTICLE_M0 = 1
    PL_MD_EXT_TAG_PARTICLE_M2 = 2
    PL_MD_EXT_TAG_MAX = 3
end

struct md_ext_item_info
    tag::PL_MD_EXT_TAGS
    type::uns16
    size::uns16
    name::Cstring
end

struct md_ext_item
    tagInfo::Ptr{md_ext_item_info}
    value::Ptr{Cvoid}
end

struct md_ext_item_collection
    list::NTuple{255, md_ext_item}
    map::NTuple{255, Ptr{md_ext_item}}
    count::uns16
end

struct md_frame_roi
    header::Ptr{md_frame_roi_header}
    data::Ptr{Cvoid}
    dataSize::uns32
    extMdData::Ptr{Cvoid}
    extMdDataSize::uns16
end

struct md_frame
    header::Ptr{md_frame_header}
    extMdData::Ptr{Cvoid}
    extMdDataSize::uns16
    impliedRoi::rgn_type
    roiArray::Ptr{md_frame_roi}
    roiCapacity::uns16
    roiCount::uns16
end

const PPVCAM_FRAME_INFO_GUID = Ptr{PVCAM_FRAME_INFO_GUID}
const PFRAME_INFO = Ptr{FRAME_INFO}
const smart_stream_type_ptr = Ptr{smart_stream_type}
const rgn_ptr = Ptr{rgn_type}
const rgn_const_ptr = Ptr{rgn_type}
const io_entry_ptr = Ptr{io_entry}
const io_list_ptr = Ptr{io_list}
const io_list_ptr_ptr = Ptr{Ptr{io_list}}
const active_camera_ptr = Ptr{active_camera_type}

# Skipping Typedef: CXType_FunctionProto pm_script_hook

const PL_CALLBACK_SIG_LEGACY = Ptr{Cvoid}
const PL_CALLBACK_SIG_EX = Ptr{Cvoid}
const PL_CALLBACK_SIG_EX2 = Ptr{Cvoid}
const PL_CALLBACK_SIG_EX3 = Ptr{Cvoid}


text:
"""
NOAA provides nighttime lights images as tif files. They can be opened as 2D arrays using the load_img function.
```julia
load_img("example.tif")
```
"""
function load_img(filepath)
    img = ArchGDAL.read((ArchGDAL.read(filepath)),1)
    img_trans = img' #tif loaded using ArchGDAL needs to be transposed
    return Array{Union{Missing, Float16}, 2}(img_trans)
end

"""
Images in the form of 2D arrays can be saved as tif files.
```julia
save_img("example.tif", img)
```
"""
function save_img(filepath,img)
    GeoArrays.write!(filepath,GeoArray(img'))
end

"""
NOAA provides images for each month since April 2012. Images of the same place taken at different times can be stacked together to make a 3D array representating a panel data. In this package, we refer to such arrays as datacubes. JLD files containing 3D arrays can be loaded using the load_datacube function.
```julia
load_datacube("example.jld")
```
"""
function load_datacube(datacube_path)
    datacube = load(datacube_path)["data"]
    return datacube
end

"""
3D arrays can be saved as JLD files.
```julia
save_datacube("example.jld", datacube)
```
"""
function save_datacube(filepath, datacube)
    save(filepath, "data", datacube)
end

"""
Loads all images (tif files) in a folder and generates a datacube. The function prints the file names to you the order in which they are loaded.
```julia
make_datacube("~/Downloads/ntl_images")
```
"""
function make_datacube(folder_path)
        files = readdir(folder_path)
        print(files)
        paths = folder_path .* "/".* files
        datacube = []
        for path in paths
            push!(datacube, load_img(path))
        end
        return Array{Union{Missing, Float16}, 3}(cat(datacube...,dims = 3))
end


text:
type CircularArray{T,N}
	data::AbstractArray{T,N}
	cdim::Integer # dimension to cycle along
	cl::Integer # size of cycle dimension
	head::Integer # starting point of the array
end

# CONSTRUCTORS

function CircularArray(A,cdim)
	if cdim > ndims(A)
		error("A does not have enough dimensions to be indexed along dimension $c_dim")
	end
	CircularArray(A,cdim,size(A,cdim),1)
end

function CircularArray(A)
	CircularArray(A,ndims(A))
end

# helper function
function circ_slice(A::CircularArray, index...)
	slice = vcat([A.head:A.cl],[1:A.head-1])
	idx::Array{Any,1} = [i for i in index] # enables indexing by slicing, etc.
	idx[A.cdim] = slice[index[A.cdim]]
	return idx
end

# ACCESSOR
# colons dont seem to work in native julia getindex, setindex
function getindex(A::CircularArray, index...)
	idx = circ_slice(A,index...)
	getindex(A.data,idx...)
end

# MUTATORS
function setindex!(A::CircularArray, newdata, index...)
	idx = circ_slice(A,index...)
	setindex!(A.data,newdata,idx...)
end

function advance_head!(A::CircularArray, offset::Integer)
	A.head += offset
end

function reset_head!(A::CircularArray)
	A.head = 1
end


text:
using Documenter, PortHamiltonian

makedocs(format = :html,
    sitename = "PortHamiltonian"
)

max_stars_repo_name: flavioluiz/phjulia

max_issues_repo_name: flavioluiz/phjulia

max_forks_repo_name: flavioluiz/phjulia


text:
function get_branch_to_pm(ix::Int64, branch::PSY.PhaseShiftingTransformer)
    PM_branch = Dict{String,Any}(
        "br_r"        => branch.r,
        "rate_a"      => branch.rate,
        "shift"       => branch.α,
        "rate_b"      => branch.rate,
        "br_x"        => branch.x,
        "rate_c"      => branch.rate,
        "g_to"        => 0.0,
        "g_fr"        => 0.0,
        "b_fr"        => branch.primaryshunt/2,
        "f_bus"       => branch.connectionpoints.from.number,
        "br_status"   => Float64(branch.available),
        "t_bus"       => branch.connectionpoints.to.number,
        "b_to"        => branch.primaryshunt/2,
        "index"       => ix,
        "angmin"      => -π/2,
        "angmax"      =>  π/2,
        "transformer" => true,
        "tap"         => branch.tap,
    )
    return PM_branch
end

function get_branch_to_pm(ix::Int64, branch::PSY.Transformer2W)
    PM_branch = Dict{String,Any}(
        "br_r"        => branch.r,
        "rate_a"      => branch.rate,
        "shift"       => 0.0,
        "rate_b"      => branch.rate,
        "br_x"        => branch.x,
        "rate_c"      => branch.rate,
        "g_to"        => 0.0,
        "g_fr"        => 0.0,
        "b_fr"        => branch.primaryshunt/2,
        "f_bus"       => branch.connectionpoints.from.number,
        "br_status"   => Float64(branch.available),
        "t_bus"       => branch.connectionpoints.to.number,
        "b_to"        => branch.primaryshunt/2,
        "index"       => ix,
        "angmin"      => -π/2,
        "angmax"      =>  π/2,
        "transformer" => true,
        "tap"         => 0.0,
    )
    return PM_branch
end

function get_branch_to_pm(ix::Int64, branch::PSY.TapTransformer)
    PM_branch = Dict{String,Any}(
        "br_r"        => branch.r,
        "rate_a"      => branch.rate,
        "shift"       => 0.0,
        "rate_b"      => branch.rate,
        "br_x"        => branch.x,
        "rate_c"      => branch.rate,
        "g_to"        => 0.0,
        "g_fr"        => 0.0,
        "b_fr"        => branch.primaryshunt/2,
        "f_bus"       => branch.connectionpoints.from.number,
        "br_status"   => Float64(branch.available),
        "t_bus"       => branch.connectionpoints.to.number,
        "b_to"        => branch.primaryshunt/2,
        "index"       => ix,
        "angmin"      => -π/2,
        "angmax"      =>  π/2,
        "transformer" => true,
        "tap"         => branch.tap
    )
    return PM_branch
end

function get_branch_to_pm(ix::Int64, branch::PSY.Line)
    PM_branch = Dict{String,Any}(
        "br_r"        => branch.r,
        "rate_a"      => branch.rate,
        "shift"       => 0.0,
        "rate_b"      => branch.rate,
        "br_x"        => branch.x,
        "rate_c"      => branch.rate,
        "g_to"        => 0.0,
        "g_fr"        => 0.0,
        "b_fr"        => branch.b.from,
        "f_bus"       => branch.connectionpoints.from.number,
        "br_status"   => Float64(branch.available),
        "t_bus"       => branch.connectionpoints.to.number,
        "b_to"        => branch.b.to,
        "index"       => ix,
        "angmin"      => branch.anglelimits.min,
        "angmax"      => branch.anglelimits.max,
        "transformer" => false,
        "tap"         => 1.0,
    )
    return PM_branch
end

function get_branch_to_pm(ix::Int64, branch::PSY.HVDCLine)
    PM_branch = Dict{String,Any}(
        "loss1"         => branch.loss.l1,
        "mp_pmax"       => branch.reactivepowerlimits_from.max,
        "model"         => 2,
        "shutdown"      => 0.0,
        "pmaxt"         => branch.activepowerlimits_to.max,
        "pmaxf"         => branch.activepowerlimits_from.max,
        "startup"       => 0.0,
        "loss0"         => branch.loss.l1,
        "pt"            => 0.0,
        "vt"            => branch.connectionpoints.to.voltage,
        "qmaxf"         => branch.reactivepowerlimits_from.max,
        "pmint"         => branch.activepowerlimits_to.min,
        "f_bus"         => branch.connectionpoints.from.number,
        "mp_pmin"       => branch.reactivepowerlimits_from.min,
        "br_status"     => Float64(branch.available),
        "t_bus"         => branch.connectionpoints.to.number,
        "index"         => ix,
        "qmint"         => branch.reactivepowerlimits_to.min,
        "qf"            => 0.0,
        "cost"          => 0.0,
        "pminf"         => branch.activepowerlimits_from.min,
        "qt"            => 0.0,
        "qminf"         => branch.reactivepowerlimits_from.min,
        "vf"            => branch.connectionpoints.from.voltage,
        "qmaxt"         => branch.reactivepowerlimits_to.max,
        "ncost"         => 0,
        "pf"            => 0.0
    )
    return PM_branch
end

function get_branches_to_pm(branches::Array{T}) where {T <: PSY.Branch}

        PM_ac_branches = Dict{String,Any}()
        PM_dc_branches = Dict{String,Any}()

        for (ix, branch) in enumerate(branches)
            if isa(branch,PSY.DCLine)
                PM_dc_branches["$(ix)"] = get_branch_to_pm(ix, branch)
            else
                PM_ac_branches["$(ix)"] = get_branch_to_pm(ix, branch)
            end
        end

    return PM_ac_branches, PM_dc_branches
end

function get_buses_to_pm(buses::Array{PSY.Bus})
    PM_buses = Dict{String,Any}()
    for bus in buses
        PM_bus = Dict{String,Any}(
        "zone"     => 1,
        "bus_i"    => bus.number,
        "bus_type" => 2,
        "vmax"     => bus.voltagelimits.max,
        "area"     => 1,
        "vmin"     => bus.voltagelimits.min,
        "index"    => bus.number,
        "va"       => bus.angle,
        "vm"       => bus.voltage,
        "base_kv"  => bus.basevoltage,
        "pni"      => 0.0,
        "qni"      => 0.0,
        )
        PM_buses["$(bus.number)"] = PM_bus
    end
    PM_buses["$(buses[1].number)"]["bus_type"] = 3
    return PM_buses
end

function pass_to_pm(sys::PSY.System)

    ac_lines, dc_lines = get_branches_to_pm(sys.branches)

    PM_translation = Dict{String,Any}(
    "bus"            => get_buses_to_pm(sys.buses),
    "branch"         => ac_lines,
    "baseMVA"        => sys.basepower,
    "per_unit"       => true,
    "storage"        => Dict{String,Any}(),
    "dcline"         => dc_lines,
    "gen"            => Dict{String,Any}(),
    "shunt"          => Dict{String,Any}(),
    "load"           => Dict{String,Any}(),
    )

    # TODO: this function adds overhead in large number of time_steps
    # We can do better later.

    PM_translation = PM.replicate(PM_translation,sys.time_periods)

    return PM_translation

end


text:
module Test_cplyap

using LinearAlgebra
using MatrixEquations
using Test

@testset "Testing positive continuous Lyapunov equation solvers" begin

n = 30
m = 5
p = 3
Ty = Float64

@testset "Positive continuous Lyapunov equations" begin

reltol = eps(float(100))
a = -1; b = 2im; @time u = plyapc(a,b)
@test abs(a*u*u'+u*u'*a'+b*b') < reltol

reltol = eps(float(100f0))
a = -1f0; b = 2f0im; @time u = plyapc(a,b)
@test abs(a*u*u'+u*u'*a'+b*b') < reltol

for Ty in (Float64, Float32)

ar = rand(Ty,n,n)
ar = ar-2*norm(ar)*Matrix(I,n,n)
ac = rand(Ty,n,n)+im*rand(Ty,n,n)
ac = ac-2*norm(ac)*Matrix(I,n,n)
br = rand(Ty,n,m)
brw = rand(Ty,n,n+m)
bc = br+im*rand(Ty,n,m)
bcw = brw+im*rand(Ty,n,n+m)
cr = rand(Ty,p,n)
crt = rand(Ty,n+p,n)
cc = cr+im*rand(Ty,p,n)
cct = crt+im*rand(Ty,n+p,n)
Ty == Float64 ? reltol = eps(float(100)) : reltol = eps(100*n*one(Ty))

@time u = plyapc(ar,br);
x = u*u'; @test norm(ar*x+x*ar'+br*br')/norm(x)/norm(ar) < reltol

@time u = plyapc(ar,brw);
x = u*u'; @test norm(ar*x+x*ar'+brw*brw')/norm(x)/norm(ar) < reltol

@time u = plyapc(ar,I,br);
x = u*u'; @test norm(ar*x+x*ar'+br*br')/norm(x)/norm(ar) < reltol

@time u = plyapc(ar',cr')
x = u'*u; @test norm(ar'*x+x*ar+cr'*cr)/norm(x)/norm(ar) < reltol

@time u = plyapc(ar',crt')
x = u'*u; @test norm(ar'*x+x*ar+crt'*crt)/norm(x)/norm(ar) < reltol

@time u = plyapc(ac,bc);
x = u*u'; @test norm(ac*x+x*ac'+bc*bc')/norm(x)/norm(ac) < reltol

@time u = plyapc(ac,bcw);
x = u*u'; @test norm(ac*x+x*ac'+bcw*bcw')/norm(x)/norm(ac) < reltol

@time u = plyapc(ac',cc');
x = u'*u; @test norm(ac'*x+x*ac+cc'*cc)/norm(x)/norm(ac) < reltol

@time u = plyapc(ac',cct');
x = u'*u; @test norm(ac'*x+x*ac+cct'*cct)/norm(x)/norm(ac) < reltol

@time u = plyapc(ac',I,cc');
x = u'*u; @test norm(ac'*x+x*ac+cc'*cc)/norm(x)/norm(ac) < reltol

@time u = plyapc(ac,br);
x = u*u'; @test norm(ac*x+x*ac'+br*br')/norm(x)/norm(ac) < reltol

@time u = plyapc(ac',cr');
x = u'*u; @test norm(ac'*x+x*ac+cr'*cr)/norm(x)/norm(ac) < reltol

@time u = plyapc(ar,bc);
x = u*u'; @test norm(ar*x+x*ar'+bc*bc')/norm(x)/norm(ar) < reltol

@time u = plyapc(ar',cc');
x = u'*u; @test norm(ar'*x+x*ar+cc'*cc)/norm(x)/norm(ar)  < reltol

end
end

@testset "Positive continuous generalized Lyapunov equations" begin

reltol = eps(float(100))
a = -1; ee = 4; b = 2im; @time u = plyapc(a,ee,b)
@test abs(a*u*u'*ee'+ee*u*u'*a'+b*b') < reltol

reltol = eps(float(100f0))
a = -1f0; ee = 4f0; b = 2f0im; @time u = plyapc(a,ee,b)
@test abs(a*u*u'*ee'+ee*u*u'*a'+b*b')  < reltol

for Ty in (Float64, Float32)

ar = rand(Ty,n,n)
ar = ar-2*norm(ar)*Matrix(I,n,n)
er = rand(n,n)
ar = er*ar
ac = rand(Ty,n,n)+im*rand(Ty,n,n)
ac = ac-2*norm(ac)*Matrix(I,n,n)
ec = er+im*rand(Ty,n,n)
ac = ec*ac
br = rand(Ty,n,m)
brw = rand(Ty,n,n+m)
bc = br+im*rand(Ty,n,m)
bcw = brw+im*rand(Ty,n,n+m)
cr = rand(Ty,p,n)
crt = rand(Ty,n+p,n)
cc = cr+im*rand(Ty,p,n)
cct = crt+im*rand(Ty,n+p,n)
Ty == Float64 ? reltol = eps(float(100)) : reltol = eps(100*n*one(Ty))

@time u = plyapc(ar,er,br);
x = u*u'; @test norm(ar*x*er'+er*x*ar'+br*br')/norm(x)/norm(ar) < reltol

@time u = plyapc(ar,er,brw);
x = u*u'; @test norm(ar*x*er'+er*x*ar'+brw*brw')/norm(x)/norm(ar) < reltol

@time u = plyapc(ar',er',cr');
x = u'*u; @test norm(ar'*x*er+er'*x*ar+cr'*cr)/norm(x)/norm(ar) < reltol

@time u = plyapc(ar',er',crt');
x = u'*u; @test norm(ar'*x*er+er'*x*ar+crt'*crt)/norm(x)/norm(ar) < reltol

@time u = plyapc(ac,ec,bc);
x = u*u'; @test norm(ac*x*ec'+ec*x*ac'+bc*bc')/norm(x)/norm(ac)/norm(ec) < reltol

@time u = plyapc(ac,ec,bcw);
x = u*u'; @test norm(ac*x*ec'+ec*x*ac'+bcw*bcw')/norm(x)/norm(ac)/norm(ec) < reltol

@time u = plyapc(ac',ec',cc');
x = u'*u; @test norm(ac'*x*ec+ec'*x*ac+cc'*cc)/norm(x)/norm(ac) < reltol

@time u = plyapc(ac',ec',cct');
x = u'*u; @test norm(ac'*x*ec+ec'*x*ac+cct'*cct)/norm(x)/norm(ac) < reltol

@time u = plyapc(ar,er,bc);
x = u*u'; @test norm(ar*x*er'+er*x*ar'+bc*bc')/norm(x)/norm(ar) < reltol

@time u = plyapc(ar',er',cc');
x = u'*u; @test norm(ar'*x*er+er'*x*ar+cc'*cc)/norm(x)/norm(ar) < reltol

@time u = plyapc(ac,ec,br);
x = u*u'; @test norm(ac*x*ec'+ec*x*ac'+br*br')/norm(x)/norm(ac)/norm(ec) < reltol

@time u = plyapc(ac',ec',cr');
x = u'*u; @test norm(ac'*x*ec+ec'*x*ac+cr'*cr)/norm(x)/norm(ac) < reltol

end
end

@testset "Positive 2x2 continuous Lyapunov equations" begin

A = [-1.1 1.; -1. -1.]
E = [1. 1.; 0. 1.]
R = [1. 1.; 0. 1.]
reltol = eps(float(100))

U, scale, β, α = plyap2(A, R, adj = true, disc = false)
X = U'*U; @test norm(A'*X+X*A+scale^2*R'*R)/max(1,norm(X))/norm(A) < reltol &&
                norm(β*U-U*A)/max(1,norm(U))/norm(A) < reltol &&
                norm(α*U/scale - scale*R)/max(1,norm(scale*R)) < reltol

U, scale, β, α = plyap2(A, R, adj = false, disc = false)
X = U*U'; @test norm(A*X+X*A'+scale^2*R*R')/max(1,norm(X))/norm(A) < reltol &&
                norm(U*β-A*U)/max(1,norm(U))/norm(A) < reltol &&
                norm(U*α/scale - scale*R)/max(1,norm(scale*R)) < reltol

U, scale, β, α = pglyap2(A, E, R, adj = true, disc = false)
X = U'*U; @test norm(A'*X*E+E'*X*A+scale^2*R'*R)/max(1,norm(X))/norm(A) < reltol &&
                norm(β*U*E-U*A)/max(1,norm(U))/norm(A) < reltol &&
                norm(α*U*E/scale - scale*R)/max(1,norm(scale*R)) < reltol

U, scale, β, α = pglyap2(A, E, R, adj = false, disc = false)
X = U*U'; @test norm(A*X*E'+E*X*A'+scale^2*R*R')/max(1,norm(X))/norm(A) < reltol &&
                norm(A*U-E*U*β)/max(1,norm(U))/norm(A) < reltol &&
                norm(E*U*α/scale - scale*R)/max(1,norm(scale*R)) < reltol

A = [-1.1 1.; -1. -1.]/10; A = convert(Matrix{Float32},A)
E = [1. 1.; 0. 1.]; E = convert(Matrix{Float32},E)
R = [1. 1.; 0. 1.]; R = convert(Matrix{Float32},R)
reltol = eps(100f0)

U, scale, β, α = plyap2(A, R, adj = true, disc = false)
X = U'*U; @test norm(A'*X+X*A+scale^2*R'*R)/max(1,norm(X))/norm(A) < reltol &&
                norm(β*U-U*A)/max(1,norm(U))/norm(A) < reltol &&
                norm(α*U/scale - scale*R)/max(1,norm(scale*R)) < reltol

U, scale, β, α = plyap2(A, R, adj = false, disc = false)
X = U*U'; @test norm(A*X+X*A'+scale^2*R*R')/max(1,norm(X))/norm(A) < reltol &&
                norm(U*β-A*U)/max(1,norm(U))/norm(A) < reltol &&
                norm(U*α/scale - scale*R)/max(1,norm(scale*R)) < reltol

U, scale, β, α = pglyap2(A, E, R, adj = true, disc = false)
X = U'*U; @test norm(A'*X*E+E'*X*A+scale^2*R'*R)/max(1,norm(X))/norm(A) < reltol &&
                norm(β*U*E-U*A)/max(1,norm(U))/norm(A) < reltol &&
                norm(α*U*E/scale - scale*R)/max(1,norm(scale*R)) < reltol

U, scale, β, α = pglyap2(A, E, R, adj = false, disc = false)
X = U*U'; @test norm(A*X*E'+E*X*A'+scale^2*R*R')/max(1,norm(X))/norm(A) < reltol &&
                norm(A*U-E*U*β)/max(1,norm(U))/norm(A) < reltol &&
                norm(E*U*α/scale - scale*R)/max(1,norm(scale*R)) < reltol

end

@testset "Continuous positive Lyapunov equations - Schur form" begin

for Ty in (Float64, Float32)

ar = rand(Ty,n,n)
ar = ar-2*norm(ar)*Matrix(I,n,n)
as,  = schur(ar)
ac = rand(Ty,n,n)+im*rand(Ty,n,n)
ac = ac-2*norm(ac)*Matrix(I,n,n)
acs,  = schur(ac)
br = rand(Ty,n,m)
bc = br+im*rand(Ty,n,m)
cr = rand(Ty,p,n)
cc = cr+im*rand(Ty,p,n)
Ty == Float64 ? reltol = eps(float(100)) : reltol = eps(100*n*one(Ty))

@time u = plyaps(as,br);
x = u*u'; @test norm(as*x+x*as'+br*br')/norm(x)/norm(as) < reltol

@time u = plyaps(as,ar);
x = u*u'; @test norm(as*x+x*as'+ar*ar')/norm(x)/norm(as) < reltol

@time u = plyaps(as,I,br);
x = u*u'; @test norm(as*x+x*as'+br*br')/norm(x)/norm(as) < reltol

@time u = plyaps(as',cr');
x = u'*u; @test norm(as'*x+x*as+cr'*cr)/norm(x)/norm(as) < reltol

@time u = plyaps(as',ar');
x = u'*u; @test norm(as'*x+x*as+ar'*ar)/norm(x)/norm(as) < reltol

@time u = plyaps(acs,bc);
x = u*u'; @test norm(acs*x+x*acs'+bc*bc')/norm(x)/norm(as) < reltol

@time u = plyaps(acs',cc');
x = u'*u; @test norm(acs'*x+x*acs+cc'*cc)/norm(x)/norm(as) < reltol

@time u = plyaps(acs',I,cc');
x = u'*u; @test norm(acs'*x+x*acs+cc'*cc)/norm(x)/norm(as) < reltol

F = UpperTriangular(rand(Ty,n,n))
R = copy(F)
@time plyapcs!(as,R,adj = true);
x = R'*R; @test norm(as'*x+x*as+F'*F)/norm(x)/norm(as) < reltol

F = UpperTriangular(rand(Ty,n,n))
R = copy(F)
@time plyapcs!(as,I,R,adj = true);
x = R'*R; @test norm(as'*x+x*as+F'*F)/norm(x)/norm(as) < reltol

F = UpperTriangular(rand(Ty,n,n))
R = copy(F)
@time plyapcs!(as,R,adj = false);
x = R*R'; @test norm(as*x+x*as'+F*F')/norm(x)/norm(as) < reltol

F = UpperTriangular(rand(Ty,n,n)+im*rand(Ty,n,n))
R = copy(F)
@time plyapcs!(acs,R,adj = true);
x = R'*R; @test norm(acs'*x+x*acs+F'*F)/norm(x)/norm(acs) < reltol

F = UpperTriangular(rand(Ty,n,n)+im*rand(Ty,n,n))
R = copy(F)
@time plyapcs!(acs,R,adj = false);
x = R*R'; @test norm(acs*x+x*acs'+F*F')/norm(x)/norm(acs) < reltol

er = rand(Ty,n,n)
ar = er*ar
as, es = schur(ar,er)
ec = er+im*rand(Ty,n,n)
ac = ec*ac
acs, ecs = schur(ac,ec)

@time u = plyaps(as,es,br);
x = u*u'; @test norm(as*x*es'+es*x*as'+br*br')/norm(x)/norm(as) < reltol

@time u = plyaps(as,es,ar);
x = u*u'; @test norm(as*x*es'+es*x*as'+ar*ar')/norm(x)/norm(as) < reltol

@time u = plyaps(as',es',cr');
x = u'*u; @test norm(as'*x*es+es'*x*as+cr'*cr)/norm(x)/norm(as) < reltol

@time u = plyaps(as',es',ar');
x = u'*u; @test norm(as'*x*es+es'*x*as+ar'*ar)/norm(x)/norm(as) < reltol

@time u = plyaps(acs,ecs,bc);
x = u*u'; @test norm(acs*x*ecs'+ecs*x*acs'+bc*bc')/norm(x)/norm(as) < reltol

@time u = plyaps(acs',ecs',cc');
x = u'*u; @test norm(acs'*x*ecs+ecs'*x*acs+cc'*cc)/norm(x)/norm(as) < reltol

F = UpperTriangular(rand(Ty,n,n))
R = copy(F)
@time plyapcs!(as,es,R,adj = true);
x = R'*R; @test norm(as'*x*es+es'*x*as+F'*F)/norm(x)/norm(as) < reltol

F = UpperTriangular(rand(Ty,n,n))
R = copy(F)
@time plyapcs!(as,es,R,adj = false);
x = R*R'; @test norm(as*x*es'+es*x*as'+F*F')/norm(x)/norm(as) < reltol

F = UpperTriangular(rand(Ty,n,n)+im*rand(Ty,n,n))
R = copy(F)
@time plyapcs!(acs,ecs,R,adj = false);
x = R*R'; @test norm(acs*x*ecs'+ecs*x*acs'+F*F')/norm(x)/norm(acs) < reltol

F = UpperTriangular(rand(Ty,n,n)+im*rand(Ty,n,n))
R = copy(F)
@time plyapcs!(acs,ecs,R,adj = true);
x = R'*R; @test norm(acs'*x*ecs+ecs'*x*acs+F'*F)/norm(x)/norm(acs) < reltol

end

end
end

end


text:
using AstroBase
using Test

import SPICE

@testset "Utils" begin
    @testset "sec2rad" begin
        # Radians <-> arcseconds
        @test sec2rad(3600) == deg2rad(1)
        @test rad2sec(1) == rad2deg(1) * 3600
    end
    @testset "normalize_angle" begin
        @testset for a = -15.0:0.1:15.0, b = -15.0:0.2:15.0
            c = normalize_angle(a, b)
            @test (b - π) <= c
            @test c <= (b + π)
            two_k = round((a - c) / π)
            @test c ≈ a - two_k * π atol=1.0e-14
        end
    end
    @testset "frame" begin
        y = zeros(3)
        @test all(AstroBase.Util.frame(y) .== SPICE.frame(y))
        x = randn(3)
        @testset for i in 1:3
            exp = SPICE.frame(x)
            act = AstroBase.Util.frame(x)
            @test act[i] ≈ exp[i]
        end
    end
    @testset "plane_section" begin
        xy = plane_section([1.0, 2.0, 3.0], zeros(3), [0.0, 0.0, 1.0])
    end
end


text:
@testset "eig2length.jl" begin

end


text:
const ContactImplicitMPC = Main
include(joinpath(@__DIR__, "..", "src/dynamics", "hopper_3D", "visuals.jl"))
T = Float64
vis = Visualizer()
open(vis)

# get hopper model
s_sim = get_simulation("hopper_3D", "sine2_3D_lc", "sinusoidal")
model_sim = s_sim.model
env_sim = s_sim.env

s = get_simulation("hopper_3D", "flat_3D_lc", "flat")
model = s.model
env = s.env

nq = model.dim.q
nu = model.dim.u
nc = model.dim.c

# get trajectory
# ref_traj = deepcopy(get_trajectory(s.model, s.env,
#     joinpath(module_dir(), "src/dynamics/hopper_3D/gaits/gait_in_place.jld2"),
#     load_type = :joint_traj))
ref_traj = deepcopy(get_trajectory(s.model, s.env,
    joinpath(module_dir(), "src/dynamics/hopper_3D/gaits/gait_forward.jld2"),
    load_type = :joint_traj))

# time
H = ref_traj.H
h = ref_traj.h
N_sample = 10
H_mpc = 20
h_sim = h / N_sample
H_sim = 1200 # 12000

# barrier parameter
κ_mpc = 1.0e-4

obj = TrackingObjective(model, env, H_mpc,
    q = [Diagonal(1.0e-1 * [3,3,0.1,5e+1,5e+1,5e+1,10])   for t = 1:H_mpc],
    u = [Diagonal(1.0e-0 * [1e-1, 1e-1, 1e1]) for t = 1:H_mpc],
    γ = [Diagonal(1.0e-100 * ones(model.dim.c)) for t = 1:H_mpc],
    b = [Diagonal(1.0e-100 * ones(model.dim.c * friction_dim(env))) for t = 1:H_mpc])

# obj = TrackingObjective(model, env, H_mpc,
#     q = [Diagonal(1.0e-1 * [1,1,0.1,5e+1,5e+1,5e+1,10])   for t = 1:H_mpc],
#     u = [Diagonal(1.0e-0 * [1e-1, 1e-1, 1e1]) for t = 1:H_mpc],
#     γ = [Diagonal(1.0e-100 * ones(model.dim.c)) for t = 1:H_mpc],
#     b = [Diagonal(1.0e-100 * ones(model.dim.c * friction_dim(env))) for t = 1:H_mpc])

p = linearized_mpc_policy(ref_traj, s, obj,
    H_mpc = H_mpc,
    N_sample = N_sample,
    κ_mpc = κ_mpc,
    n_opts = NewtonOptions(
        r_tol = 3e-4,
        max_iter = 5),
    mpc_opts = LinearizedMPCOptions(
        # altitude_update = false,
        altitude_update = true,
        altitude_impact_threshold = 0.05,
        altitude_verbose = true,
        # live_plotting = true,
        )
    )

p = linearized_mpc_policy(ref_traj, s, obj,
    H_mpc = H_mpc,
    N_sample = N_sample,
    κ_mpc = κ_mpc,
	# mode = :configurationforce,
	mode = :configuration,
	ip_type = :mehrotra,
    n_opts = NewtonOptions(
		r_tol = 3e-4,
		max_iter = 5,
		max_time = ref_traj.h, # HARD REAL TIME
		),
    mpc_opts = LinearizedMPCOptions(
        # live_plotting=true,
        altitude_update = true,
        altitude_impact_threshold = 0.05,
        altitude_verbose = true,
        ),
	ip_opts = InteriorPointOptions(
		max_iter = 100,
		verbose = false,
		r_tol = 1.0e-4,
		κ_tol = 1.0e-4,
		diff_sol = true,
		# κ_reg = 1e-3,
		# γ_reg = 1e-1,
		solver = :empty_solver,
		),
    )

q1_ref = copy(ref_traj.q[2])
q0_ref = copy(ref_traj.q[1])
q1_sim = SVector{model.dim.q}(q1_ref)
q0_sim = SVector{model.dim.q}(copy(q1_sim - (q1_ref - q0_ref) / N_sample))
@assert norm((q1_sim - q0_sim) / h_sim - (q1_ref - q0_ref) / h) < 1.0e-8

sim = simulator(s_sim, q0_sim, q1_sim, h_sim, H_sim,
    p = p,
    ip_opts = InteriorPointOptions(
        r_tol = 1.0e-8,
        κ_init = 1.0e-8,
        κ_tol = 2.0e-8),
    sim_opts = SimulatorOptions(warmstart = true))

telap = @elapsed status = ContactImplicitMPC.simulate!(sim, verbose = true)
# @profiler status = ContactImplicitMPC.simulate!(sim)
H_sim * h_sim / (telap * 0.35)

plot_surface!(vis, env_sim, n=100, xlims=[-0.3, 1.5], ylims=[-1.1, 0.3])
visualize_robot!(vis, model, sim.traj)
plot_lines!(vis, model_sim, sim.traj.q[1:11000], offset=0.0)

plt = plot(layout=(3,1), legend=false)
plot!(plt[1,1], hcat(Vector.(vcat([fill(ref_traj.q[i], N_sample) for i=1:H]...))...)',
    color=:red, linewidth=3.0)
plot!(plt[1,1], hcat(Vector.(sim.traj.q)...)', color=:blue, linewidth=1.0)
plot!(plt[2,1], hcat(Vector.(vcat([fill(ref_traj.u[i][1:nu], N_sample) for i=1:H]...))...)',
    color=:red, linewidth=3.0)
plot!(plt[2,1], hcat(Vector.([u[1:nu] for u in sim.traj.u]*N_sample)...)', color=:blue, linewidth=1.0)
plot!(plt[3,1], hcat(Vector.([γ[1:nc] for γ in sim.traj.γ]*N_sample)...)', color=:blue, linewidth=1.0)

visualize_robot!(vis, model, sim.traj, sample=10)

# filename = "hopper_3d_sine"
# MeshCat.convert_frames_to_video(
#     "/home/simon/Downloads/$filename.tar",
#     "/home/simon/Documents/$filename.mp4", overwrite=true)
#
# convert_video_to_gif(
#     "/home/simon/Documents/$filename.mp4",
#     "/home/simon/Documents/$filename.gif", overwrite=true)


text:
############################################################
# joRHS ## #################################################
############################################################

# Authors: Philipp Witte (pwitte@eos.ubc.ca), Henryk Modzelewski (hmodzelewski@eos.ubc.ca)
# Date: January 2017

export joRHS, joRHSexception

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

struct joRHS{vDT<:Number} <: joAbstractLinearOperator{vDT,vDT}
	name::String
	m::Integer
	n::Integer
	info::Info
	geometry::Geometry
	data
end

mutable struct joRHSexception <: Exception
	msg :: String
end

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

## outer constructors

"""
    joRHS
        name::String
        m::Integer
        n::Integer
        info::Info
        geometry::Geometry
        data

Abstract sparse vector for right-hand-sides of the modeling operators. The `joRHS` vector has the\\
dimensions of the full time history of the wavefields, but contains only the data defined at the \\
source or receiver positions (i.e. wavelets or shot records).

Constructor
==========

    joRHS(info, geometry, data)

Examples
========

Assuming `Pr` and `Ps` are projection operators of type `joProjection` and `dobs` and `q` are\\
seismic vectors of type `joData`, then a `joRHS` vector can be created as follows:

    rhs = Pr'*dobs    # right-hand-side with injected observed data
    rhs = Ps'*q    # right-hand-side with injected wavelet

"""
function joRHS(info,geometry,data;vDT::DataType=Float32)
	vDT == Float32 || throw(joRHSexception("Domain type not supported"))
	# length of vector
	m = info.n * sum(info.nt)
	n = 1
	return joRHS{Float32}("joRHS",m,n,info,geometry,data)
end

####################################################################
## overloaded Base functions

# conj(jo)
conj{vDT}(A::joRHS{vDT}) =
	joRHS{vDT}("conj("*A.name*")",A.m,A.n,A.info,A.geometry,A.data)

# transpose(jo)
transpose{vDT}(A::joRHS{vDT}) =
	joRHS{vDT}(""*A.name*".'",A.n,A.m,A.info,A.geometry,A.data)

# ctranspose(jo)
ctranspose{vDT}(A::joRHS{vDT}) =
	joRHS{vDT}(""*A.name*"'",A.n,A.m,A.info,A.geometry,A.data)

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

# +(joRHS,joRHS)
function +{avDT,bvDT}(A::joRHS{avDT}, B::joRHS{bvDT})

	# Error checking
	size(A) == size(B) || throw(joRHSexception("shape mismatch"))
	compareInfo(A.info, B.info) == true || throw(joRHSexception("info mismatch"))
	isequal(A.geometry.nt,B.geometry.nt) == true || throw(joRHSexception("sample number mismatch"))
	isequal(A.geometry.dt,B.geometry.dt) == true || throw(joRHSexception("sample interval mismatch"))
	isequal(A.geometry.t,B.geometry.t) == true || throw(joRHSexception("recording time mismatch"))

	# Size
	m = A.info.n * sum(A.info.nt)
	n = 1

	# merge geometries and data
	xloc = Array{Any}(A.info.nsrc)
	yloc = Array{Any}(A.info.nsrc)
	zloc = Array{Any}(A.info.nsrc)
	dt = Array{Any}(A.info.nsrc)
	nt = Array{Any}(A.info.nsrc)
	t = Array{Any}(A.info.nsrc)
	data = Array{Any}(A.info.nsrc)

	for j=1:A.info.nsrc
		xloc[j] = [vec(A.geometry.xloc[j])' vec(B.geometry.xloc[j])']
		yloc[j] = [vec(A.geometry.yloc[j])' vec(B.geometry.yloc[j])']
		zloc[j] = [vec(A.geometry.zloc[j])' vec(B.geometry.zloc[j])']
		dt[j] = A.geometry.dt[j]
		nt[j] = A.geometry.nt[j]
		t[j] = A.geometry.t[j]
		data[j] = [A.data[j] B.data[j]]
	end
	geometry = Geometry(xloc,yloc,zloc,dt,nt,t)
	nvDT = promote_type(avDT,bvDT)

	return joRHS{nvDT}("joRHS",m,n,A.info,geometry,data)
end

# -(joRHS,joRHS)
function -{avDT,bvDT}(A::joRHS{avDT}, B::joRHS{bvDT})

	# Error checking
	size(A) == size(B) || throw(joRHSexception("shape mismatch"))
	compareInfo(A.info, B.info) == true || throw(joRHSexception("info mismatch"))
	isequal(A.geometry.nt,B.geometry.nt) == true || throw(joRHSexception("sample number mismatch"))
	isequal(A.geometry.dt,B.geometry.dt) == true || throw(joRHSexception("sample interval mismatch"))
	isequal(A.geometry.t,B.geometry.t) == true || throw(joRHSexception("recording time mismatch"))

	# Size
	m = A.info.n * sum(A.info.nt)
	n = 1

	# merge geometries and data
	xloc = Array{Any}(A.info.nsrc)
	yloc = Array{Any}(A.info.nsrc)
	zloc = Array{Any}(A.info.nsrc)
	dt = Array{Any}(A.info.nsrc)
	nt = Array{Any}(A.info.nsrc)
	t = Array{Any}(A.info.nsrc)
	data = Array{Any}(A.info.nsrc)

	for j=1:A.info.nsrc
		xloc[j] = [vec(A.geometry.xloc[j])' vec(B.geometry.xloc[j])']
		yloc[j] = [vec(A.geometry.yloc[j])' vec(B.geometry.yloc[j])']
		zloc[j] = [vec(A.geometry.zloc[j])' vec(B.geometry.zloc[j])']
		dt[j] = A.geometry.dt[j]
		nt[j] = A.geometry.nt[j]
		t[j] = A.geometry.t[j]
		data[j] = [A.data[j] -B.data[j]]
	end
	geometry = Geometry(xloc,yloc,zloc,dt,nt,t)
	nvDT = promote_type(avDT,bvDT)

	return joRHS{nvDT}("joRHS",m,n,A.info,geometry,data)
end

max_stars_repo_name: SINBADconsortium/opesciSLIM

max_issues_repo_name: SINBADconsortium/opesciSLIM

max_forks_repo_name: SINBADconsortium/opesciSLIM


text:
"""
    AbstractPeriodToken

A token used in parsing or formatting a period string. Each subtype must
define the tryparsenext and format methods.

"""
abstract type AbstractPeriodToken end

"""
    tryparsenext(tok::AbstractPeriodToken, str::String, i::Int, len::Int)

`tryparsenext` parses for the `tok` token in `str` starting at index `i`.
`len` is the length of the string.

If parsing succeeds, returns a tuple of 2 elements `(res, idx)`, where:

* `res` is the result of the parsing.
* `idx::Int`, is the index _after_ the index at which parsing ended.
"""
function tryparsenext end

# Information for parsing and formatting date time values.
struct SimpleDateFormat{S,T<:Tuple}
    tokens::T
end

### Token types ###

struct PeriodPart{letter} <: AbstractPeriodToken
    width::Int
    fixed::Bool
end

@inline min_width(d::PeriodPart) = d.fixed ? d.width : 1
@inline max_width(d::PeriodPart) = d.fixed ? d.width : 0

function _show_content(io::IO, d::PeriodPart{c}) where {c}
    for i = 1:d.width
        print(io, c)
    end
end

function Base.show(io::IO, d::PeriodPart{c}) where {c}
    print(io, "PeriodPart(")
    _show_content(io, d)
    print(io, ")")
end

### Parse tokens

for c in "ysqmwdx"
    @eval begin
        @inline function tryparsenext(d::PeriodPart{$c}, str, i, len)
            return tryparsenext_base10(str, i, len, min_width(d), max_width(d))
        end
    end
end

for (tok, fn) in zip("uU", Any[Dates.monthabbr_to_value, Dates.monthname_to_value])
    @eval @inline function tryparsenext(d::PeriodPart{$tok}, str, i, len, locale)
        next = tryparsenext_word(str, i, len, locale, max_width(d))
        next === nothing && return nothing
        word, i = next
        val = $fn(word, locale)
        val == 0 && return nothing
        return val, i
    end
end

### Format tokens

for (c, fn) in zip("ysqmwdx", Any[year, semester, quarter, month, week, day, undated])
    @eval function format(io, d::PeriodPart{$c}, p)
        print(io, string($fn(p), base = 10, pad = d.width))
    end
end

for (tok, fn) in zip("uU", Any[Dates.monthabbr, Dates.monthname])
    @eval function format(io, d::PeriodPart{$tok}, p)
        print(io, $fn(month(p)))
    end
end

### Delimiters

struct Delim{T,length} <: AbstractPeriodToken
    d::T
end

Delim(d::T) where {T<:AbstractChar} = Delim{T,1}(d)
Delim(d::String) = Delim{String,length(d)}(d)

@inline function tryparsenext(d::Delim{<:AbstractChar,N}, str, i::Int, len) where {N}
    for j = 1:N
        i > len && return nothing
        next = iterate(str, i)
        @assert next !== nothing
        c, i = next
        c != d.d && return nothing
    end
    return true, i
end

@inline function tryparsenext(d::Delim{String,N}, str, i::Int, len) where {N}
    i1 = i
    i2 = firstindex(d.d)
    for j = 1:N
        if i1 > len
            return nothing
        end
        next1 = iterate(str, i1)
        @assert next1 !== nothing
        c1, i1 = next1
        next2 = iterate(d.d, i2)
        @assert next2 !== nothing
        c2, i2 = next2
        if c1 != c2
            return nothing
        end
    end
    return true, i1
end

@inline function format(io, d::Delim, dt)
    print(io, d.d)
end

function _show_content(io::IO, d::Delim{<:AbstractChar,N}) where {N}
    if d.d in keys(CONVERSION_SPECIFIERS)
        for i = 1:N
            print(io, '\\', d.d)
        end
    else
        for i = 1:N
            print(io, d.d)
        end
    end
end

function _show_content(io::IO, d::Delim)
    for c in d.d
        if c in keys(CONVERSION_SPECIFIERS)
            print(io, '\\')
        end
        print(io, c)
    end
end

function Base.show(io::IO, d::Delim)
    print(io, "Delim(")
    _show_content(io, d)
    print(io, ")")
end

### DateFormat construction

abstract type DayOfWeekToken end # special addition to Period types

# Map conversion specifiers or character codes to tokens.
# Note: Allow addition of new character codes added by packages
const CONVERSION_SPECIFIERS = Dict{Char,Type}(
    'y' => Year,
    's' => Semester,
    'q' => Quarter,
    'm' => Month,
    'u' => Month,
    'U' => Month,
    'w' => Week,
    'd' => Day,
    'x' => Undated,
)

# Default values are needed when a conversion specifier is used in a DateFormat for parsing
# and we have reached the end of the input string.
# Note: Allow `Any` value as a default to support extensibility
const CONVERSION_DEFAULTS = IdDict{Type,Any}(
    Year => Int64(1),
    Semester => Int64(1),
    Quarter => Int64(1),
    Month => Int64(1),
    Week => Int64(0),
    Day => Int64(1),
    Undated => Int64(1),
)

# Specifies the required fields in order to parse a TimeType
# Note: Allows for addition of new TimeTypes
const CONVERSION_TRANSLATIONS = IdDict{Type,Any}(
    Year => (Year,),
    Semester => (Year, Semester),
    Quarter => (Year, Quarter),
    Month => (Year, Month),
    Week => (Year, Week),
    Day => (Year, Month, Day),
    YearDate => (Year,),
    SemesterDate => (Year, Semester),
    QuarterDate => (Year, Quarter),
    MonthDate => (Year, Month),
    WeekDate => (Year, Week),
    DayDate => (Year, Month, Day),
    UndatedDate => (Undated,),
)

"""
    SimpleDateFormat(format::AbstractString) -> SimpleDateFormat

Construct a period formatting object that can be used for parsing period strings or
formatting a period object as a string. The following character codes can be used to construct the `format`
string:

| Code       | Matches   | Comment                                                      |
|:-----------|:----------|:-------------------------------------------------------------|
| `y`        | 1996, 96  | Returns year of 1996, 0096                                   |
| `s`        | 1, 2      | Returns semester 1 or 2                                      |
| `q`        | 1, ..., 4 | Returns quarter 1, 2, 3, 4                                   |
| `m`        | 1, 01     | Matches 1 or 2-digit months                                  |
| `u`        | Jan       | Matches abbreviated months according to the `locale` keyword |
| `U`        | January   | Matches full month names according to the `locale` keyword   |
| `w`        | 1,..., 53 | Returns week 01 to 53                                        |
| `d`        | 1, 01     | Matches 1 or 2-digit days                                    |
| `yyyymmdd` | 19960101  | Matches fixed-width year, month, and day                     |
| `x`        | 1, ...    | Matches undated period                                       |

Characters not listed above are normally treated as delimiters between slots.
For example a `dt` string of "1996-Q1" would have a `format` string like
"y-Qq". If you need to use a code character as a delimiter you can escape it using
backslash. The date "1995y01m" would have the format "y\\ym\\m".

Creating a SimpleDateFormat object is expensive. Whenever possible, create it once and use it many times
or try the [`periodformat""`](@ref @periodformat_str) string macro. Using this macro creates the SimpleDateFormat
object once at macro expansion time and reuses it later. There are also several [pre-defined formatters](@ref
Common-Period-Formatters), listed later.

See [`DateTime`](@ref) and [`format`](@ref) for how to use a DateFormat object to parse and write Date strings
respectively.
"""
function SimpleDateFormat(f::AbstractString)
    tokens = AbstractPeriodToken[]
    prev = ()
    prev_offset = 1

    letters = String(collect(keys(CONVERSION_SPECIFIERS)))
    for m in eachmatch(Regex("(?<!\\\\)([\\Q$letters\\E])\\1*"), f)
        tran = replace(f[prev_offset:prevind(f, m.offset)], r"\\(.)" => s"\1")

        if !isempty(prev)
            letter, width = prev
            typ = CONVERSION_SPECIFIERS[letter]

            push!(tokens, PeriodPart{letter}(width, isempty(tran)))
        end

        if !isempty(tran)
            push!(tokens, Delim(length(tran) == 1 ? first(tran) : tran))
        end

        letter = f[m.offset]
        width = length(m.match)

        prev = (letter, width)
        prev_offset = m.offset + width
    end

    tran = replace(f[prev_offset:lastindex(f)], r"\\(.)" => s"\1")

    if !isempty(prev)
        letter, width = prev
        typ = CONVERSION_SPECIFIERS[letter]

        push!(tokens, PeriodPart{letter}(width, false))
    end

    if !isempty(tran)
        push!(tokens, Delim(length(tran) == 1 ? first(tran) : tran))
    end

    tokens_tuple = (tokens...,)
    return SimpleDateFormat{Symbol(f),typeof(tokens_tuple)}(tokens_tuple)
end

function Base.show(io::IO, pf::SimpleDateFormat)
    print(io, "periodformat\"")
    for t in pf.tokens
        _show_content(io, t)
    end
    print(io, '"')
end

Base.Broadcast.broadcastable(x::SimpleDateFormat) = Ref(x)

"""
    periodformat"Y-m-d"

Create a [`SimpleDateFormat`](@ref) object. Similar to `SimpleDateFormat("Y-m-d")`
but creates the DateFormat object once during macro expansion.

See [`SimpleDateFormat`](@ref) for details about format specifiers.
"""
macro periodformat_str(str)
    SimpleDateFormat(str)
end

default_format(::Type{YearDate}) = YearFormat
default_format(::Type{SemesterDate}) = SemesterFormat
default_format(::Type{QuarterDate}) = QuarterFormat
default_format(::Type{MonthDate}) = MonthFormat
default_format(::Type{WeekDate}) = WeekFormat
default_format(::Type{DayDate}) = DayFormat
default_format(::Type{UndatedDate}) = UndatedFormat

# Standard formats

"""
    Periods.YearFormat

# Example
```jldoctest
julia> Periods.format(Periods(2018, Year), YearFormat )
"2018"
```
"""
const YearFormat = SimpleDateFormat("y")
"""
    Periods.SemesterFormat

# Example
```jldoctest
julia> Periods.format(Periods(2018, 1, Semester), SemesterFormat )
"2018-S1"
```
"""
const SemesterFormat = SimpleDateFormat("y-Ss")
"""
    Periods.QuarterFormat

# Example
```jldoctest
julia> Periods.format(Periods(2018, 2, Quarter), QuarterFormat )
"2018-Q2"
```
"""
const QuarterFormat = SimpleDateFormat("y-Qq")
"""
    Periods.MonthFormat

# Example
```jldoctest
julia> Periods.format(Periods(2018, 3, Month), MonthFormat )
"2018-03"
```
"""
const MonthFormat = SimpleDateFormat("y-mm")
"""
    Periods.WeekFormat

# Example
```jldoctest
julia> Periods.format(Periods(2018, 4, Week), WeekFormat )
"2018-W04"
```
"""
const WeekFormat = SimpleDateFormat("y-Www")
"""
    Periods.DayFormat

# Example
```jldoctest
julia> Periods.format(Periods(2018, 3, 11, Day), DayFormat )
"2018-03-11"
```
"""
const DayFormat = SimpleDateFormat("y-mm-dd")
"""
    Periods.UndatedFormat

# Example
```jldoctest
julia> Periods.format(Periods(11, Undated), DayFormat )
"2018-03-11"
```
"""
const UndatedFormat = SimpleDateFormat("x")

### API

"""
    SimpleDate(p::AbstractString, format::AbstractString) -> SimpleDate

Construct a `SimpleDate` by parsing the `p` period string following the pattern given
in the `format` string (see [`SimpleDateFormat`](@ref) for syntax).

!!! note
    This method creates a `SimpleDateFormat` object each time it is called. It is recommended
    that you create a [`SimpleDateFormat`](@ref) object instead and use that as the second
    argument to avoid performance loss when using the same format repeatedly.

# Example
```jldoctest
julia> SimpleDate("2020-01-01", "yyyy-mm-dd")
2020-01-01

julia> a = ("2020-01-01", "2020-01-02");

julia> [SimpleDate(p, dateformat"yyyy-mm-dd") for p ∈ a] # preferred
2-element Vector{SimpleDate}:
 2020-01-01
 2020-01-02
```
"""
function SimpleDate(p::AbstractString, format::AbstractString)
    parse(SimpleDate, p, SimpleDateFormat(format))
end

for TP in (:Year, :Semester, :Quarter, :Month, :Week, :Day, :Undated)
    sd = Symbol(TP, "Date")
    sf = Symbol(TP, "Format")
    @eval begin
        function $sd(p::AbstractString, format::AbstractString)
            parse($sd, p, SimpleDateFormat(format))
        end

        function $sd(p::AbstractString)
            parse($sd, p, $sf)
        end
    end
end

"""
    SimpleDate(p::AbstractString, pf::SimpleDateFormat) -> SimpleDate

Construct a `SimpleDate` by parsing the `p` period string following the
pattern given in the [`SimpleDateFormat`](@ref) object.

Similar to `SimpleDate(::AbstractString, ::AbstractString)` but more efficient when
repeatedly parsing similarly formatted period strings with a pre-created
`SimpleDateFormat` object.
"""
SimpleDate(p::AbstractString, pf::SimpleDateFormat) = parse(SimpleDate, p, pf)

for TP in
    (:YearDate, :SemesterDate, :QuarterDate, :MonthDate, :WeekDate, :DayDate, :UndatedDate)
    @eval begin
        @generated function format(io::IO, p::$TP, fmt::SimpleDateFormat{<:Any,T}) where {T}
            N = fieldcount(T)
            quote
                ts = fmt.tokens
                Base.@nexprs $N i -> format(io, ts[i], p)
            end
        end

        function format(p::$TP, fmt::SimpleDateFormat, bufsize = 10)
            # preallocate to reduce resizing
            io = IOBuffer(Vector{UInt8}(undef, bufsize), read = true, write = true)
            format(io, p, fmt)
            String(io.data[1:io.ptr-1])
        end
    end
end

"""
    format(p::SimpleDate, format::AbstractString) -> AbstractString

Construct a string by using a `SimpleDate` object and applying the provided `format`. The
following character codes can be used to construct the `format` string:

| Code       | Examples  | Comment                                                      |
|:-----------|:----------|:-------------------------------------------------------------|
| `y`        | 6         | Numeric year with a fixed width                              |
| `Y`        | 1996      | Numeric year with a minimum width                            |
| `m`        | 1, 12     | Numeric month with a minimum width                           |
| `u`        | Jan       | Month name shortened to 3-chars according to the `locale`    |
| `U`        | January   | Full month name according to the `locale` keyword            |
| `d`        | 1, 31     | Day of the month with a minimum width                        |
| `s`        | 1, 2      | Semester of the year                                         |
| `q`        | 1, 4      | Quarter of the year                                          |
| `w`        | 1, 53     | Week of the year with a minimum width                        |
The number of sequential code characters indicate the width of the code. A format of
`yyyy-mm` specifies that the code `y` should have a width of four while `m` a width of two.
Codes that yield numeric digits have an associated mode: fixed-width or minimum-width.
The fixed-width mode left-pads the value with zeros when it is shorter than the specified
width and truncates the value when longer. Minimum-width mode works the same as fixed-width
except that it does not truncate values longer than the width.

When creating a `format` you can use any non-code characters as a separator. For example to
generate the string "1996-Q1" you could use `format`: "yyyy-Qq".
Note that if you need to use a code character as a literal you can use the escape character
backslash. The string "1996y01m" can be produced with the format "yyyy\\ymm\\m".
"""

# show
function Base.print(io::IO, y::YearDate)
    format(io, y, YearFormat)
end

function Base.print(io::IO, s::SemesterDate)
    format(io, s, SemesterFormat)
end

function Base.print(io::IO, q::QuarterDate)
    format(io, q, QuarterFormat)
end

function Base.print(io::IO, m::MonthDate)
    format(io, m, MonthFormat)
end

function Base.print(io::IO, w::WeekDate)
    format(io, w, WeekFormat)
end

#function Base.print(io::IO, d::DayDate)
#    format(io, d, DayFormat)
#end

function Base.print(io::IO, u::UndatedDate)
    format(io, u, UndatedFormat)
end

function Base.print(io::IO, dd::DayDate)
    # don't use format - bypassing IOBuffer creation
    # saves a bit of time here.
    y, m, d = yearmonthday(dd)
    yy = y < 0 ? @sprintf("%05i", y) : lpad(y, 4, "0")
    mm = lpad(m, 2, "0")
    dd = lpad(d, 2, "0")
    print(io, "$yy-$mm-$dd")
end

for date_type in
    (:DayDate, :WeekDate, :MonthDate, :QuarterDate, :SemesterDate, :YearDate)
    # Human readable output (i.e. "2012-01-01")
    @eval Base.show(io::IO, ::MIME"text/plain", dt::$date_type) = print(io, dt)
    # Parsable output (i.e. Date("2012-01-01"))
    @eval Base.show(io::IO, dt::$date_type) = print(io, typeof(dt), "(\"", dt, "\")")
    # Parsable output will have type info displayed, thus it is implied
    @eval Base.typeinfo_implicit(::Type{$date_type}) = true
end

function simpleperiod(s::String) SimpleDate
    p = nothing
    try
        parts = split(s, '-')
        y = Base.parse(Int64, parts[1])
        if length(parts) == 1
            p = YearDate(y)
        elseif length(parts) == 2
            f = parts[2][1]
            if f == 'S'
                s = Base.parse(Int64, parts[2][2:end])
                p = SemesterDate(y, s)
            elseif f == 'Q'
                s = Base.parse(Int64, parts[2][2:end])
                p = QuarterDate(y, s)
            elseif f == 'W'
                s = Base.parse(Int64, parts[2][2:end])
                p = WeekDate(y, s)
            else
                s = Base.parse(Int64, parts[2])
                p = MonthDate(y, s)
            end
        elseif length(parts) == 3
            m = Base.parse(Int64, parts[2])
            d = Base.parse(Int64, parts[3])
            p = DayDate(y, m, d)
        else
            error("Can't parse $s")
        end
    catch
        error("Can't parse $s")
    end
    return p
end

simpleperiod(u::Int64) = UndatedDate(u)


text:
#=
Copyright (c) 2018-2022 Chris Coey, Lea Kapelevich, and contributors

This Julia package Hypatia.jl is released under the MIT license; see LICENSE
file in the root directory or at https://github.com/chriscoey/Hypatia.jl
=#

portfolio_insts = [
    [(num_stocks, false, true)
    for num_stocks in vcat(10, 1000, 2000:2000:20000)] # includes compile run
    ]

insts = OrderedDict()
insts["nat"] = (nothing, portfolio_insts)
insts["ext"] = (:SOCExpPSD, portfolio_insts)
return (PortfolioJuMP, insts)


text:
# sumS and sumS2 are padded by 1 pixel at the start of each dimension, to avoid writting code to specifically deal with the first line and first column of the images.

# 2D SEARCH AREA SUM-TABLES.

function znccSumArrays!( search::AbstractArray{T,2}, sumS::A{U,2}, sumS2::A{U,2}
                       ) where {T<:Real, U<:Real}
    h, w = size(search);
    @inbounds for c in 2:w+1
        for r in 2:h+1
			 sumS[r,c] = search[h-r+2,w-c+2]   +  sumS[r-1,c] +  sumS[r,c-1] -  sumS[r-1,c-1];
            sumS2[r,c] = search[h-r+2,w-c+2]^2 + sumS2[r-1,c] + sumS2[r,c-1] - sumS2[r-1,c-1];
        end
    end
end

function znccSumValues( sumS::Array{T,2}, sumS2::Array{T,2},
                        row, col, ss, si ) where {T<:Real}

    pad = 1;
    row = row + pad;
    col = col + pad;
    r0, r1 = max( 1, row - si[1] ), min( ss[1] + pad, row );
    c0, c1 = max( 1, col - si[2] ), min( ss[2] + pad, col );

    opS  = 0.0
    opS += sumS[ r1, c1 ];
    opS -= sumS[ r1, c0 ];
    opS -= sumS[ r0, c1 ];
    opS += sumS[ r0, c0 ];

    opS2  = 0.0
    opS2 += sumS2[ r1, c1 ];
    opS2 -= sumS2[ r1, c0 ];
    opS2 -= sumS2[ r0, c1 ];
    opS2 += sumS2[ r0, c0 ];

    return opS, opS2
end

# 3D SEARCH VOLUME SUM-TABLES.

# optimized sumarea, reusing previous operations
function znccSumArrays!( SA::AbstractArray{U,3}, S::Array{T,3}, S2::Array{T,3}
                       ) where {T<:Real,U<:Real}

     h,  w,  d = size(SA);
    @inbounds for z in 2:d+1
        for c in 2:w+1
            topSum  = 0.0;
            topSum2 = 0.0;
            for r in 2:h+1
                SAVal  = SA[h-r+2,w-c+2,d-z+2]
                SAVal2 = SAVal*SAVal;

                 S[r,c,z] = SAVal  +  S[r,c-1,z] +  S[r,c,z-1] -  S[r,c-1,z-1] +  topSum;
                S2[r,c,z] = SAVal2 + S2[r,c-1,z] + S2[r,c,z-1] - S2[r,c-1,z-1] + topSum2;

                 topSum  += SAVal;
                topSum2  += SAVal2;
            end
        end
    end
end

function znccSumValues( sumS::Array{T,3}, sumS2::Array{T,3},
                        row, col, zet, ss, si ) where {T<:Real}
    pad = 1;
    row = row + pad;
    col = col + pad;
    zet = zet + pad;
    r0, r1 = max( 1, row - si[1] ), min( ss[1] + pad, row );
    c0, c1 = max( 1, col - si[2] ), min( ss[2] + pad, col );
    z0, z1 = max( 1, zet - si[3] ), min( ss[3] + pad, zet );

    opS  = 0.0;
    opS += sumS[ r1, c1, z1 ]
    opS -= sumS[ r0, c1, z1 ]
    opS -= sumS[ r1, c0, z1 ]
    opS -= sumS[ r1, c1, z0 ]
    opS += sumS[ r1, c0, z0 ]
    opS += sumS[ r0, c1, z0 ]
    opS += sumS[ r0, c0, z1 ]
    opS -= sumS[ r0, c0, z0 ]

    opS2  = 0.0;
    opS2 += sumS2[ r1, c1, z1 ]
    opS2 -= sumS2[ r0, c1, z1 ]
    opS2 -= sumS2[ r1, c0, z1 ]
    opS2 -= sumS2[ r1, c1, z0 ]
    opS2 += sumS2[ r1, c0, z0 ]
    opS2 += sumS2[ r0, c1, z0 ]
    opS2 += sumS2[ r0, c0, z1 ]
    opS2 -= sumS2[ r0, c0, z0 ]

    return opS, opS2
end


text:
using TianJun
using Test

@testset "TianJun.jl" begin
    # Write your tests here.
end


text:
#This code only gets loaded when the functionality of Imagine.jl is available (on a Windows machine with NIDAQmx installed)

using Imagine

function slicetiming_experiment(out_bname::AbstractString, rig::AbstractString, pos_name, las_name, cam_name, mod_cyc, z_spacing, z_pad; ncycs_mean=ceil(Int, 20.0/ustrip(length(mod_cyc)*sample_rate)), sample_rate = 100000Hz, cal=-1, toffsets = default_toffsets(), allow_shifts=true, allow_rotations=false, subpixel=true)
    coms0 = pos_commands(rig, pos_name, mod_cyc, ncycs_mean; sample_rate =sample_rate)
    pos = getpositioners(coms0)
    pos_mon = getpositionermonitors(coms0)
    #run commands
    warn("This method must be run on the microscope computer while the piezo is on and connected (both MON and MOD connections)")
    write_commands(out_bname * "_piezo_only.json", [pos; pos_mon], 0, 0, 0.01s; exp_trig_mode = ["External Start"], isbidi=true, skip_validation=true)
    recs = Imagine.run_imagine(out_bname * "_piezo_only", [pos; pos_mon]; ai_trig_dest = "PFI2", ao_trig_dest = "PFI1", trigger_source = "Port2/Line0", skip_validation = true)
    return slicetiming_experiment([pos; pos_mon], recs, las_name, cam_name, z_spacing, z_pad; cal = cal, toffsets=toffsets, allow_shifts=allow_shifts, allow_rotations=allow_rotations, subpixel=subpixel)
end