text:
# AVIO

import Base: read, read!, show, close, eof, isopen, seek, seekstart

export read, read!, pump, openvideo, opencamera, playvideo, viewcam, play, gettime

mutable struct StreamInfo
    stream_index0::Int             # zero-based
    pStream::Ptr{AVStream}
    stream::AVStream
    codec_ctx::AVCodecContext
end

abstract type StreamContext end

const EightBitTypes = Union{UInt8,N0f8,RGB{N0f8},Gray{N0f8}}
const PermutedArray{T,N,perm,iperm,AA <: Array} = Base.PermutedDimsArrays.PermutedDimsArray{T,N,perm,iperm,AA}
const VidArray{T,N} = Union{Array{T,N},PermutedArray{T,N}}

# TODO: move this to Base
Base.unsafe_convert(::Type{Ptr{T}}, A::PermutedArray{T}) where {T} = Base.unsafe_convert(Ptr{T}, parent(A))

# An audio-visual input stream/file
mutable struct AVInput{I}
    io::I
    apFormatContext::Vector{Ptr{AVFormatContext}}
    apAVIOContext::Vector{Ptr{AVIOContext}}
    avio_ctx_buffer_size::UInt
    aPacket::Vector{AVPacket}           # Reusable packet

    unknown_info::Vector{StreamInfo}
    video_info::Vector{StreamInfo}
    audio_info::Vector{StreamInfo}
    data_info::Vector{StreamInfo}
    subtitle_info::Vector{StreamInfo}
    attachment_info::Vector{StreamInfo}

    listening::Set{Int}
    stream_contexts::Array{StreamContext}

    isopen::Bool
end

function show(io::IO, avin::AVInput)
    println(io, "AVInput(", avin.io, ", ...), with")
    (len = length(avin.video_info))      > 0 && println(io, "  $len video stream(s)")
    (len = length(avin.audio_info))      > 0 && println(io, "  $len audio stream(s)")
    (len = length(avin.data_info))       > 0 && println(io, "  $len data stream(s)")
    (len = length(avin.subtitle_info))   > 0 && println(io, "  $len subtitle stream(s)")
    (len = length(avin.attachment_info)) > 0 && println(io, "  $len attachment stream(s)")
    (len = length(avin.unknown_info))    > 0 && println(io, "  $len unknown stream(s)")
end

mutable struct VideoTranscodeContext
    transcode_context::Ptr{SwsContext}

    transcode_interp::Cint
    target_pix_fmt::Cint
    target_bits_per_pixel::Int
    width::Int
    height::Int

    target_buf::Array{UInt8,3}  # TODO: this needs to be more general
    aTargetVideoFrame::Vector{AVFrame}
    apTargetDataBuffers::Vector{Ptr{UInt8}}
    apTargetLineSizes::Vector{Cint}
end

const TRANSCODE = true
const NO_TRANSCODE = false

mutable struct VideoReader{transcode} <: StreamContext
    avin::AVInput
    stream_info::StreamInfo

    stream_index0::Int
    pVideoCodecContext::Ptr{AVCodecContext}
    pVideoCodec::Ptr{AVCodec}
    aVideoFrame::Vector{AVFrame}   # Reusable frame
    aFrameFinished::Vector{Int32}

    format::Cint
    width::Cint
    height::Cint
    framerate::Rational
    aspect_ratio::Rational

    frame_queue::Vector{Vector{UInt8}}
    transcodeContext::VideoTranscodeContext
end

show(io::IO, vr::VideoReader) = print(io, "VideoReader(...)")

# Pump input for data
function pump(c::AVInput)
    pFormatContext = c.apFormatContext[1]

    while true
        !c.isopen && break

        Base.sigatomic_begin()
        av_read_frame(pFormatContext, pointer(c.aPacket)) < 0 && break
        Base.sigatomic_end()

        packet = c.aPacket[1]
        stream_index = packet.stream_index

        # If we're not listening to this stream, skip it
        if stream_index in c.listening
            # Decode the packet, and check if the frame is complete
            frameFinished = decode_packet(c.stream_contexts[stream_index + 1], c.aPacket)
            av_free_packet(pointer(c.aPacket))

            # If the frame is complete, we're done
            frameFinished && return stream_index
        else
            av_free_packet(pointer(c.aPacket))
        end
    end

    return -1
end

pump(r::StreamContext) = pump(r.avin)

function _read_packet(pavin::Ptr{AVInput}, pbuf::Ptr{UInt8}, buf_size::Cint)
    avin = unsafe_pointer_to_objref(pavin)
    out = unsafe_wrap(Array, pbuf, (buf_size,))
    convert(Cint, readbytes!(avin.io, out))
end

# This will point to _read_packet, but is set in __init__()
const read_packet = Ref{Ptr{Cvoid}}(C_NULL)

function open_avinput(avin::AVInput, io::IO, input_format=C_NULL, options=C_NULL)

    !isreadable(io) && error("IO not readable")

    # These allow control over how much of the stream to consume when
    # determining the stream type
    # TODO: Change these defaults if necessary, or allow user to set
    #av_opt_set(avin.apFormatContext[1], "probesize", "100000000", 0)
    #av_opt_set(avin.apFormatContext[1], "analyzeduration", "1000000", 0)

    # Allocate the io buffer used by AVIOContext
    # Must be done with av_malloc, because it could be reallocated
    if (avio_ctx_buffer = av_malloc(avin.avio_ctx_buffer_size)) == C_NULL
        error("unable to allocate AVIOContext buffer (out of memory)")
    end

    # Allocate AVIOContext
    if (avin.apAVIOContext[1] = avio_alloc_context(avio_ctx_buffer, avin.avio_ctx_buffer_size,
                                                   0, pointer_from_objref(avin),
                                                   read_packet[], C_NULL, C_NULL)) == C_NULL
        abuffer = [avio_ctx_buffer]
        av_freep(abuffer)
        error("Unable to allocate AVIOContext (out of memory)")
    end

    # pFormatContext->pb = pAVIOContext
    av_setfield(avin.apFormatContext[1], :pb, avin.apAVIOContext[1])

    # "Open" the input
    if avformat_open_input(avin.apFormatContext, C_NULL, input_format, options) != 0
        error("Unable to open input")
    end

    nothing
end

function open_avinput(
        avin::AVInput, source::AbstractString,
        input_format=C_NULL, options=C_NULL
    )
    if avformat_open_input(
            avin.apFormatContext,
           source,
           input_format,
           options
        ) != 0

        error("Could not open $source")
    end

    nothing
end

function AVInput(
        source::T, input_format=C_NULL, options=C_NULL;
        avio_ctx_buffer_size=65536
    ) where T <: Union{IO,AbstractString}

    # Register all codecs and formats

    aPacket = [AVPacket()]
    apFormatContext = Ptr{AVFormatContext}[avformat_alloc_context()]
    apAVIOContext = Ptr{AVIOContext}[C_NULL]

    # Allocate this object (needed to pass into AVIOContext in open_avinput)
    avin = AVInput{T}(source, apFormatContext, apAVIOContext, avio_ctx_buffer_size,
                      aPacket, [StreamInfo[] for i = 1:6]..., Set(Int[]), StreamContext[], false)

    # Make sure we deallocate everything on exit
    finalizer(close, avin)

    # Set up the format context and open the input, based on the type of source
    open_avinput(avin, source, input_format, options)
    avin.isopen = true
    # Get the stream information
    if avformat_find_stream_info(avin.apFormatContext[1], C_NULL) < 0
        error("Unable to find stream information")
    end

    # Load streams, codec_contexts
    formatContext = unsafe_load(avin.apFormatContext[1]);

    for i = 1:formatContext.nb_streams
        pStream = unsafe_load(formatContext.streams, i)
        stream = unsafe_load(pStream)
        codec_ctx = unsafe_load(stream.codec)
        codec_type = codec_ctx.codec_type

        stream_info = StreamInfo(i - 1, pStream, stream, codec_ctx)

        if codec_type == AVMEDIA_TYPE_VIDEO
            push!(avin.video_info, stream_info)
        elseif codec_type == AVMEDIA_TYPE_AUDIO
            push!(avin.audio_info, stream_info)
        elseif codec_type == AVMEDIA_TYPE_DATA
            push!(avin.data_info, stream_info)
        elseif codec_type == AVMEDIA_TYPE_SUBTITLE
            push!(avin.subtitle_info, stream_info)
        elseif codec_type == AVMEDIA_TYPE_ATTACHMENT
            push!(avin.attachment_info, stream_info)
        elseif codec_type == AVMEDIA_TYPE_UNKNOWN
            push!(avin.unknown_info, stream_info)
        end
    end

    resize!(avin.stream_contexts, formatContext.nb_streams)

    avin
end

function VideoReader(avin::AVInput, video_stream=1;
                     transcode::Bool=true,
                     transcode_interpolation=SWS_BILINEAR,
                     target_format=AV_PIX_FMT_RGB24)

    1 <= video_stream <= length(avin.video_info) || error("video stream $video_stream not found")

    stream_info = avin.video_info[video_stream]

    # Get basic stream info
    pVideoCodecContext = stream_info.stream.codec
    codecContext = stream_info.codec_ctx

    width, height = codecContext.width, codecContext.height
    pix_fmt = codecContext.pix_fmt
    pix_fmt < 0 && error("Unknown pixel format")

    framerate = codecContext.time_base.den // codecContext.time_base.num

    aspect_num = codecContext.sample_aspect_ratio.num
    aspect_den = codecContext.sample_aspect_ratio.den
    aspect_ratio = (aspect_den == 0) ? 0 // 1 : aspect_num // aspect_den

    # Find the decoder for the video stream
    pVideoCodec = avcodec_find_decoder(codecContext.codec_id)
    pVideoCodec == C_NULL && error("Unsupported Video Codec")

    # Open the decoder
    avcodec_open2(pVideoCodecContext, pVideoCodec, C_NULL) < 0 && error("Could not open codec")

    aVideoFrame = [AVFrame()]
    aFrameFinished = Int32[0]

    aTargetVideoFrame = [AVFrame()]

    # Set up transcoding
    # TODO: this should be optional
    pFmtDesc = av_pix_fmt_desc_get(target_format)
    bits_per_pixel = av_get_bits_per_pixel(pFmtDesc)

    if transcode && bits_per_pixel % 8 != 0
        error("Unsupported format (bits_per_pixel = $bits_per_pixel)")
    end

    N = Int64(bits_per_pixel >> 3)
    target_buf = Array{UInt8}(undef, bits_per_pixel >> 3, width, height)

    sws_context = sws_getContext(width, height, pix_fmt,
                                 width, height, target_format,
                                 transcode_interpolation, C_NULL, C_NULL, C_NULL)

    avpicture_fill(pointer(aTargetVideoFrame), target_buf, target_format, width, height)
    apTargetDataBuffers = reinterpret(Ptr{UInt8}, [aTargetVideoFrame[1].data])
    apTargetLineSizes   = reinterpret(Cint,       [aTargetVideoFrame[1].linesize])

    transcodeContext = VideoTranscodeContext(sws_context,
                                             transcode_interpolation,
                                             target_format,
                                             bits_per_pixel,
                                             width,
                                             height,
                                             target_buf,
                                             aTargetVideoFrame,
                                             apTargetDataBuffers,
                                             apTargetLineSizes)

    vr = VideoReader{transcode}(avin,
                                stream_info,

                                stream_info.stream_index0,
                                pVideoCodecContext,
                                pVideoCodec,
                                aVideoFrame,
                                aFrameFinished,

                                pix_fmt,
                                width,
                                height,
                                framerate,
                                aspect_ratio,

                                Vector{UInt8}[],
                                transcodeContext)

    idx0 = stream_info.stream_index0
    push!(avin.listening, idx0)
    avin.stream_contexts[idx0 + 1] = vr

    vr
end

VideoReader(s::T, args...; kwargs...) where {T <: Union{IO,AbstractString}} = VideoReader(AVInput(s), args...; kwargs... )

function decode_packet(r::VideoReader, aPacket)
    # Do we already have a complete frame that hasn't been consumed?
    if have_decoded_frame(r)
        apSourceDataBuffers = reinterpret(Ptr{UInt8}, [r.aVideoFrame[1].data])
        sz = avpicture_get_size(r.format, r.width, r.height)
        push!(r.frame_queue, copy(unsafe_wrap(Array, apSourceDataBuffers[1], sz)))
        reset_frame_flag!(r)
    end

    avcodec_decode_video2(r.pVideoCodecContext,
                          r.aVideoFrame,
                          r.aFrameFinished,
                          aPacket)

    return have_decoded_frame(r)
end

# Converts a grabbed frame to the correct format (RGB by default)
# TODO: type stability?
function retrieve(r::VideoReader{TRANSCODE}) # true=transcode

    while !have_frame(r)
        idx = pump(r.avin)
        idx == r.stream_index0 && break
        idx == -1 && throw(EOFError())
    end

    t = r.transcodeContext

    if t.target_bits_per_pixel % 8 != 0
        error("Unsupported video retrieval format.  Please allocate the buffer yourself and call retrieve!()")
    end

    if t.target_bits_per_pixel == 8
        buf = permuteddimsview(Matrix{Gray{N0f8}}(undef, r.width, r.height), (2, 1))
    else
        buf = permuteddimsview(Matrix{RGB{N0f8}}(undef, r.width, r.height), (2, 1))
    end

    retrieve!(r, buf)
end

function retrieve(r::VideoReader{NO_TRANSCODE}) # false=don't transcode
    while !have_frame(r)
        idx = pump(r.avin)
        idx == r.stream_index0 && break
        idx == -1 && throw(EOFError())
    end

    # TODO: set actual dimensions ?
    buf_sz = avpicture_get_size(r.format, r.width, r.height)
    buf = Array(UInt8, buf_sz)

    retrieve!(r, buf)
end

# Converts a grabbed frame to the correct format (RGB by default)
function retrieve!(r::VideoReader{TRANSCODE}, buf::VidArray{T}) where T <: EightBitTypes
    while !have_frame(r)
        idx = pump(r.avin)
        idx == r.stream_index0 && break
        idx == -1 && throw(EOFError())
    end

    if !bufsize_check(r, buf)
        error("Buffer is the wrong size")
    end

    t = r.transcodeContext

    # Set up target buffer
    if pointer(buf) != t.apTargetDataBuffers[1]
        avpicture_fill(pointer(t.aTargetVideoFrame),
                       buf,
                       t.target_pix_fmt,
                       r.width, r.height)
        t.apTargetDataBuffers = reinterpret(Ptr{UInt8}, [t.aTargetVideoFrame[1].data])
        t.apTargetLineSizes   = reinterpret(Cint,       [t.aTargetVideoFrame[1].linesize])

    end

    apSourceDataBuffers = isempty(r.frame_queue) ? reinterpret(Ptr{UInt8}, [r.aVideoFrame[1].data]) :
                                                   reinterpret(Ptr{UInt8}, [popfirst!(r.frame_queue)])
    apSourceLineSizes   = reinterpret(Cint, [r.aVideoFrame[1].linesize])

    Base.sigatomic_begin()
    sws_scale(t.transcode_context,
              apSourceDataBuffers,
              apSourceLineSizes,
              zero(Int32),
              r.height,
              t.apTargetDataBuffers,
              t.apTargetLineSizes)
    Base.sigatomic_end()

    reset_frame_flag!(r)

    return buf
end

function retrieve!(r::VideoReader{NO_TRANSCODE}, buf::VidArray{T}) where T <: EightBitTypes
    while !have_frame(r)
        idx = pump(r.avin)
        idx == r.stream_index0 && break
        idx == -1 && throw(EOFError())
    end

    if !bufsize_check(r, buf)
        error("Buffer is the wrong size")
    end
end

# Utility functions

# Not exported
open(filename::AbstractString) = AVInput(filename)
openvideo(args...; kwargs...) = VideoReader(args...; kwargs...)

read(r::VideoReader) = retrieve(r)
read!(r::VideoReader, buf::AbstractArray{T}) where {T <: EightBitTypes} = retrieve!(r, buf)

isopen(avin::AVInput{I}) where {I <: IO} = isopen(avin.io)
isopen(avin::AVInput) = avin.isopen
isopen(r::VideoReader) = isopen(r.avin)

bufsize_check(r::VideoReader{NO_TRANSCODE}, buf::VidArray{T}) where {T <: EightBitTypes} = (length(buf) * sizeof(T) == avpicture_get_size(r.format, r.width, r.height))
bufsize_check(r::VideoReader{TRANSCODE}, buf::VidArray{T}) where {T <: EightBitTypes} = bufsize_check(r.transcodeContext, buf)
bufsize_check(t::VideoTranscodeContext, buf::VidArray{T}) where {T <: EightBitTypes} = (length(buf) * sizeof(T) == avpicture_get_size(t.target_pix_fmt, t.width, t.height))

have_decoded_frame(r) = r.aFrameFinished[1] > 0  # TODO: make sure the last frame was made available
have_frame(r::StreamContext) = !isempty(r.frame_queue) || have_decoded_frame(r)
have_frame(avin::AVInput) = any(Bool[have_frame(avin.stream_contexts[i + 1]) for i in avin.listening])

reset_frame_flag!(r) = (r.aFrameFinished[1] = 0)

function seconds_to_timestamp(s::Float64, time_base::AVRational)
    return round(Int64, floor(s *  convert(Float64, time_base.den) / convert(Float64, time_base.num)))
end

"""
    gettime(s::VideoReader;video_stream::Integer=1)

Return timestamp of current position in seconds.
"""
function gettime(s::VideoReader;video_stream::Integer=1)
    time_base = s.avin.video_info[video_stream].stream.time_base
    frameindex = s.aVideoFrame[video_stream].pkt_dts   #av_frame_get_best_effort_timestamp(s.aVideoFrame)
    return frameindex * (time_base.num/time_base.den)
end

"""
    seek(s::VideoReader, seconds::AbstractFloat, seconds_min::AbstractFloat=-1.0,  seconds_max::AbstractFloat=-1.0, video_stream::Integer=1, forward::Bool=false)

Seek through VideoReader object.
"""
function seek(s::VideoReader, seconds::AbstractFloat,
              seconds_min::AbstractFloat=-1.0,  seconds_max::AbstractFloat=-1.0,
              video_stream::Integer=1, forward::Bool=false)
    !isopen(s) && throw(ErrorException("Video input stream is not open!"))

    fc = s.avin.apFormatContext[1]

    pCodecContext = s.pVideoCodecContext # AVCodecContext

    seek(s.avin, seconds, seconds_min, seconds_max, video_stream, forward)
    avcodec_flush_buffers(pCodecContext)

    stream_info = s.avin.video_info[video_stream]
    stream = stream_info.stream
    first_dts = stream.first_dts

    actualTimestamp = s.aVideoFrame[video_stream].pkt_dts   #av_frame_get_best_effort_timestamp(s.aVideoFrame)
    dts = first_dts + seconds_to_timestamp(seconds, stream.time_base)

    pStream = stream_info.pStream
    frame_rate = av_stream_get_r_frame_rate(pStream)
    frameskip = round(Int64, (stream.time_base.den / stream.time_base.num) / (frame_rate.num / frame_rate.den))

    while actualTimestamp < (dts - frameskip)
        while !have_frame(s)
            idx = pump(s.avin)
            idx == s.stream_index0 && break
            idx == -1 && throw(EOFError())
        end
        reset_frame_flag!(s)
        actualTimestamp = s.aVideoFrame[video_stream].pkt_dts   #av_frame_get_best_effort_timestamp(s.aVideoFrame)
    end
    return(s)
end

"""
    seek(s::VideoReader, seconds::AbstractFloat, seconds_min::AbstractFloat=-1.0,  seconds_max::AbstractFloat=-1.0, video_stream::Integer=1, forward::Bool=false)

Seek through AVInput object.
"""
function seek(avin::AVInput{T}, seconds::AbstractFloat,
              seconds_min::AbstractFloat=-1.0,  seconds_max::AbstractFloat=-1.0,
              video_stream::Integer=1, forward::Bool=false) where T <: AbstractString

    #Using 10 seconds before and after the desired timestamp, since the seek function
    #seek to the nearest keyframe, and 10 seconds is the longest GOP length seen in
    #practical usage.
    max_interval = 10.0

    # AVFormatContext
    fc = avin.apFormatContext[1]

    # Get stream information
    stream_info = avin.video_info[video_stream]
    seek_stream_index = stream_info.stream_index0
    stream = stream_info.stream
    first_dts = stream.first_dts
    time_base = stream.time_base

    if first_dts == AV_NOPTS_VALUE
        throw(ErrorException("Unable to seek (no DTS value received from container)."))
    end

    #Timestamp calculations
    if seconds_min < 0
        seconds_min = max(seconds - max_interval, 0.0)
    end

    if seconds_max < 0
        seconds_max = seconds + max_interval
    end

    dts = first_dts + seconds_to_timestamp(seconds, time_base)
    min_dts = first_dts + seconds_to_timestamp(seconds_min, time_base)
    #max_dts = first_dts + seconds_to_timestamp(seconds_max, time_base)

    flags = AVSEEK_FLAG_ANY
    if !forward
        flags = AVSEEK_FLAG_BACKWARD
    end

    # Seek
    ret = avformat_seek_file(fc, seek_stream_index, min_dts, dts, dts, flags)
    ret < 0 && throw(ErrorException("Could not seek in stream"))

    return avin
end
"""
    seekstart(s::VideoReader, video_stream=1)

Seek to start of VideoReader object.
"""
function seekstart(s::VideoReader, video_stream=1)
    return seek(s, 0.0, 0.0, 0.0, video_stream, false)
end

"""
    seekstart(avin::AVInput{T}, video_stream=1) where T <: AbstractString

Seek to start of AVInput object.
"""
function seekstart(avin::AVInput{T}, video_stream=1) where T <: AbstractString
    return seek(avin, 0.0, 0.0, 0.0, video_stream, false)
end

## This doesn't work...
#seekstart{T<:IO}(avin::AVInput{T}, video_stream = 1) = seekstart(avin.io)
seekstart(avin::AVInput{T}, video_stream=1) where {T <: IO} = throw(ErrorException("Sorry, Seeking is not supported from IO streams"))

function eof(avin::AVInput)
    !isopen(avin) && return true
    have_frame(avin) && return false
    got_frame = (pump(avin) != -1)
    return !got_frame
end

function eof(avin::AVInput{I}) where I <: IO
    !isopen(avin) && return true
    have_frame(avin) && return false
    return eof(avin.io)
end

eof(r::VideoReader) = eof(r.avin)

close(r::VideoReader) = close(r.avin)
_close(r::VideoReader) = avcodec_close(r.pVideoCodecContext)

# Free AVIOContext object when done
function close(avin::AVInput)
    Base.sigatomic_begin()
    isopen = avin.isopen
    avin.isopen = false
    Base.sigatomic_end()

    !isopen && return

    for i in avin.listening
        _close(avin.stream_contexts[i + 1])
    end

    # Fix for segmentation fault issue #44
    empty!(avin.listening)

    Base.sigatomic_begin()
    if avin.apFormatContext[1] != C_NULL
        avformat_close_input(avin.apFormatContext)
    end
    Base.sigatomic_end()

    Base.sigatomic_begin()
    if avin.apAVIOContext[1] != C_NULL
        p = av_pointer_to_field(avin.apAVIOContext[1], :buffer)
        p != C_NULL && av_freep(p)
        av_freep(avin.apAVIOContext)
    end
    Base.sigatomic_end()
end

### Camera Functions

# These are set in __init__()
const DEFAULT_CAMERA_FORMAT = Ref{Any}()
const CAMERA_DEVICES = String[]
const DEFAULT_CAMERA_DEVICE = Ref{String}()
const DEFAULT_CAMERA_OPTIONS = AVDict()

function get_camera_devices(ffmpeg, idev, idev_name)
    camera_devices = String[]

    read_vid_devs = false
    lines = FFMPEG.exe(`-list_devices true -f $idev -i $idev_name`,collect=true)

    for line in lines
        if occursin("video devices",line)
            read_vid_devs = true
            continue
        elseif occursin("audio devices",line) || occursin("exit", line) || occursin("error", line)
            read_vid_devs = false
            continue
        end

        if read_vid_devs
            m = match(r"""\[.*"(.*)".?""", line)
            if m != nothing
                push!(camera_devices, m.captures[1])
            end

            # Alternative format (TODO: could be combined with the regex above)
            m = match(r"""\[.*\] \[[0-9]\] (.*)""", line)
            if m != nothing
                push!(camera_devices, m.captures[1])
            end
        end
    end

    return camera_devices
end

function opencamera(
        device=DEFAULT_CAMERA_DEVICE[],
        format=DEFAULT_CAMERA_FORMAT[],
        options = DEFAULT_CAMERA_OPTIONS,
        args...;
        kwargs...
    )
    camera = AVInput(device, format, options)
    VideoReader(camera, args...; kwargs...)
end


text:
include("dataStructure.jl")

include("parseCpp.jl")

error_message = "File extension not found"

function parseFiles(filenames::Array{String})::AbstractArray{control_block}

    # specify global error message
    global error_message

    # preallocate the return array from the number of filenames
    output = AbstractArray{control_block,length(filenames)}

    # go through all the files
    for name in filenames
        # grab file contents for parser
        handle = open(name)

        # convert to string, the output is a array of UInt8's
        contents = String(read(handle))
        close(handle)

        # get the file extension to select parser
        ext = getFileExtension(name)

        # select parser based on file extension
        if (ext =="cpp")
            control_blocks = parseCpp(contents)

        else
            # if no parser was found for that file
            println("Parser not found for $name, skipping $name.")
        end
    end

    return output
end

parseFiles(["test.cpp"])

ext: jl

max_stars_repo_name: aklapatch/CodeVisualized

max_issues_repo_name: aklapatch/CodeVisualized

max_forks_repo_name: aklapatch/CodeVisualized


text:
import Statistics: mean

global policy = Nothing()

# y_n ~ Pr_P(O|I)
@interface sample_n(sf::SFunc{I,O,P}, x::I, n::Int)::Vector{O}
# Becomes:
abstract type SampleN <: Interface end
interface_signature(s::SampleN) = signature
function sample_n(sf::SFunc{I,O,P}, x::I, n::Int)::Vector{O}
    global policy
    return sample_n(policy, sf, x, n)
end
function sample_n(policy::Policy, sf, x, n)
    imp = get_imp(policy, SampleN, sf, x, n)
    return sample_n(imp, sf, x, n)
end

@implement sample_n(sf::AddPlusDiagGaussVecs, x::Tuple{Vector, Vector}, n::Int)
    return x[1] + x[2] +
           rand(Normal(), (size(x[1]), n)).*exp(logstd)
end
#### ^ CONVERTED BY MACRO INTO >
## Struct (e.g. to hold hypers):
struct SampleNABC123 <: SampleN end
impl_signature(o::SampleNABC123) = signature
# And methods:
function sample_n(imp::SampleNABC123, sf::AddPlusDiagGaussVecs, x::Tuple{Vector, Vector}, n::Int)
    #... as above declaration
end
function sample_n(policy::Nothing, sf::AddPlusDiagGaussVecs, x::Tuple{Vector, Vector}, n::Int) = sample_n(SampleNABC123(), sf, x, n)

# When user then calls
# sample_n(sf, x)
# 1) Calls the @op_def, validating the input signature, which calls sample_n_imp,
# 2) sample_n_imp exists for each imp, so it multiple dispatches to get precedence, calling the appropriate sample_n(imp, ...)
# 3) sample_n(imp, ...) contains the actual op_imp definition - you can always call this directly if you know which op_imp you want

### Policies
function with_policy(f, new_policy)
    global policy
    last_policy, policy = policy, new_policy
    result = f() # TODO Exceptions
    policy = last_policy
    return result
end

# Use like:
with_policy(policy) do
    sample_n(sf, x, 10)
end


text:
JSONRPC.parse_params(::Type{Val{Symbol("textDocument/codeAction")}}, params) = CodeActionParams(params)
function process(r::JSONRPC.Request{Val{Symbol("textDocument/codeAction")},CodeActionParams}, server)
    commands = Command[]
    doc = getdocument(server, URI2(r.params.textDocument.uri))
    offset = get_offset(doc, r.params.range.start)
    offset1 = get_offset(doc, r.params.range.stop)
    x = get_expr(getcst(doc), offset)
    arguments = Any[r.params.textDocument.uri, offset, offset1] # use the same arguments for all commands
    if x isa EXPR
        if refof(x) isa StaticLint.Binding && refof(x).val isa SymbolServer.ModuleStore
            push!(commands, Command("Explicitly import used package variables.", "ExplicitPackageVarImport", arguments))
        end
        if parentof(x) isa EXPR && typof(parentof(x)) === CSTParser.Using &&  refof(x) isa StaticLint.Binding
            if refof(x).type === StaticLint.CoreTypes.Module || (refof(x).val isa StaticLint.Binding && refof(x).val.type === StaticLint.CoreTypes.Module) || refof(x).val isa SymbolServer.ModuleStore
                push!(commands, Command("Re-export package variables.", "ReexportModule", arguments))
            end
        end
        if is_in_fexpr(x, is_single_line_func)
            push!(commands, Command("Expand function definition.", "ExpandFunction", arguments))
        end
        if is_in_fexpr(x, CSTParser.defines_struct)
            push!(commands, Command("Add default constructor", "AddDefaultConstructor", arguments))
        end
        # if r.params.range.start.line != r.params.range.stop.line # selection across _line_offsets
        #     push!(commands, Command("Wrap in `if` block.", "WrapIfBlock", arguments))
        # end
    end

    return commands
end

JSONRPC.parse_params(::Type{Val{Symbol("workspace/executeCommand")}}, params) = ExecuteCommandParams(params)
function process(r::JSONRPC.Request{Val{Symbol("workspace/executeCommand")},ExecuteCommandParams}, server)
    uri = r.params.arguments[1]
    offset = r.params.arguments[2]
    doc = getdocument(server, URI2(uri))
    x = get_expr(getcst(doc), offset)
    if r.params.command == "ExplicitPackageVarImport"
        explicitly_import_used_variables(x, r.id + 1, server)
    elseif r.params.command == "ExpandFunction"
        expand_inline_func(x, r.id + 1, server)
    elseif r.params.command == "AddDefaultConstructor"
        add_default_constructor(x, r.id + 1, server)
    elseif r.params.command == "ReexportModule"
        if refof(x).type === StaticLint.CoreTypes.Module || (refof(x).val isa StaticLint.Binding && refof(x).val.type === StaticLint.CoreTypes.Module)
            reexport_module(x, r.id + 1, server)
        elseif refof(x).val isa SymbolServer.ModuleStore
            reexport_package(x, r.id + 1, server)
        end
    elseif r.params.command == "WrapIfBlock"
        wrap_block(get_expr(getcst(doc), r.params.arguments[2]:r.params.arguments[3]), r.id + 1, server, :if)
    end
end

function find_using_statement(x::EXPR)
    for ref in refof(x).refs
        if parentof(ref) isa EXPR && typof(parentof(ref)) === CSTParser.Using
            return parentof(ref)
        end
    end
    return nothing
end

function explicitly_import_used_variables(x::EXPR, id, server)
    !(refof(x) isa StaticLint.Binding && refof(x).val isa SymbolServer.ModuleStore) && return
    using_stmt = find_using_statement(x)
    using_stmt isa Nothing && return

    tdes = Dict{String,TextDocumentEdit}()
    vars = Set{String}() # names that need to be imported

    # Find uses of `x` and mark edits
    for ref in refof(x).refs
        if parentof(ref) isa EXPR && typof(parentof(ref)) == CSTParser.BinaryOpCall && length(parentof(ref).args) == 3 && kindof(parentof(ref).args[2]) === CSTParser.Tokens.DOT && parentof(ref).args[1] == ref
            typof(parentof(ref).args[3]) !== CSTParser.Quotenode && continue # some malformed EXPR, skip
            childname = parentof(ref).args[3].args[1]
            StaticLint.hasref(childname) && refof(childname) isa StaticLint.Binding && continue # check this isn't the name of something being explictly overwritten
            !haskey(refof(x).val.vals, valof(childname)) && continue # skip, perhaps mark as missing ref ?

            file, offset = get_file_loc(ref)
            if !haskey(tdes, file._uri)
                tdes[file._uri] = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[])
            end
            push!(tdes[file._uri].edits, TextEdit(Range(file, offset .+ (0:parentof(ref).span)), valof(childname)))
            push!(vars, valof(childname))
        end
    end
    isempty(tdes) && return

    # Add `using x: vars...` statement
    if parentof(using_stmt) isa EXPR && (typof(parentof(using_stmt)) === CSTParser.Block || typof(parentof(using_stmt)) === CSTParser.FileH)
        # this should cover all cases
        i1 = 0
        for i = 1:length(parentof(using_stmt).args)
            if using_stmt === parentof(using_stmt).args[i]
                i1 = i
                break
            end
        end
        i1 == 0 && return WorkspaceEdit(missing, missing)

        file, offset = get_file_loc(using_stmt)
        insertpos = get_next_line_offset(using_stmt)
        insertpos == -1 && return

        if !haskey(tdes, file._uri)
            tdes[file._uri] = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[])
        end
        push!(tdes[file._uri].edits, TextEdit(Range(file, insertpos .+ (0:0)), string("using ", valof(x), ": ", join(vars, ", "), "\n")))
    else
        return
    end

    JSONRPCEndpoints.send_request(server.jr_endpoint, "workspace/applyEdit", ApplyWorkspaceEditParams(missing, WorkspaceEdit(nothing, collect(values(tdes)))))
end

is_single_line_func(x) = CSTParser.defines_function(x) && typof(x) !== CSTParser.FunctionDef

function expand_inline_func(x, id, server)
    func = _get_parent_fexpr(x, is_single_line_func)
    sig = func.args[1]
    op = func.args[2]
    body = func.args[3]
    if typof(body) == CSTParser.Block && body.args !== nothing length(body.args) == 1
        file, offset = get_file_loc(func)
        tde = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[
            TextEdit(Range(file, offset .+ (0:func.fullspan)), string("function ", get_text(file)[offset .+ (1:sig.span)], "\n    ", get_text(file)[offset + sig.fullspan + op.fullspan .+ (1:body.span)], "\nend\n"))
        ])
        JSONRPCEndpoints.send_request(server.jr_endpoint, "workspace/applyEdit", ApplyWorkspaceEditParams(missing, WorkspaceEdit(nothing, TextDocumentEdit[tde])))
    elseif (typof(body) === CSTParser.Begin || typof(body) === CSTParser.InvisBrackets) && body.args isa Vector{EXPR} && length(body.args) == 3 &&
        typof(body.args[2]) === CSTParser.Block && body.args[2].args isa Vector{EXPR}
        file, offset = get_file_loc(func)
        newtext = string("function ", get_text(file)[offset .+ (1:sig.span)])
        blockoffset = offset + sig.fullspan + op.fullspan + body.args[1].fullspan
        for i = 1:length(body.args[2].args)
            newtext = string(newtext, "\n    ", get_text(file)[blockoffset .+ (1:body.args[2].args[i].span)])
            blockoffset += body.args[2].args[i].fullspan
        end
        newtext = string(newtext, "\nend\n")
        tde = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[TextEdit(Range(file, offset .+ (0:func.fullspan)), newtext)])
        JSONRPCEndpoints.send_request(server.jr_endpoint, "workspace/applyEdit", ApplyWorkspaceEditParams(missing, WorkspaceEdit(nothing, TextDocumentEdit[tde])))
    end
end

function add_default_constructor(x::EXPR, id, server)
    sexpr = _get_parent_fexpr(x, CSTParser.defines_struct)
    !(sexpr.args isa Vector{EXPR}) && return
    ismutable = length(sexpr.args) == 5
    name = CSTParser.get_name(sexpr)
    sig = sexpr.args[2 + ismutable]
    block = sexpr.args[3 + ismutable]

    isempty(block.args) && return
    any(CSTParser.defines_function(a) for a in block.args) && return # constructor already exists

    newtext = string("\n    function $(valof(name))(args...)\n\n        new")
    # if DataType is parameterised do something here

    newtext = string(newtext, "(")
    for i in 1:length(block.args)
        newtext = string(newtext, "", valof(CSTParser.get_arg_name(block.args[i])))
        newtext = string(newtext, i < length(block.args) ? ", " : ")\n    end")
    end
    file, offset = get_file_loc(last(block.args))
    offset += last(block.args).span
    tde = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[TextEdit(Range(file, offset:offset), newtext)])

    JSONRPCEndpoints.send_request(server.jr_endpoint, "workspace/applyEdit", ApplyWorkspaceEditParams(missing, WorkspaceEdit(nothing, TextDocumentEdit[tde])))
end

function is_in_fexpr(x::EXPR, f)
    if f(x)
        return true
    elseif parentof(x) isa EXPR
        return is_in_fexpr(parentof(x), f)
    else
        return false
    end
end

function _get_parent_fexpr(x::EXPR, f)
    if f(x)
        return x
    elseif parentof(x) isa EXPR
        return _get_parent_fexpr(parentof(x), f)
    end
end
function get_next_line_offset(x)
    file, offset = get_file_loc(x)
    # get next line after using_stmt
    insertpos = -1
    line_offsets = get_line_offsets(file)
    for i = 1:length(line_offsets) - 1
        if line_offsets[i] < offset + x.span <= line_offsets[i + 1]
            insertpos = line_offsets[i + 1]
        end
    end
    return insertpos
end

function reexport_package(x::EXPR, id, server)
    using_stmt = parentof(x)
    file, offset = get_file_loc(x)
    insertpos = get_next_line_offset(using_stmt)
    insertpos == -1 && return

    tde = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[
        TextEdit(Range(file, insertpos .+ (0:0)), string("export ", join(sort(collect(refof(x).val.exported)), ", "), "\n"))
    ])

    JSONRPCEndpoints.send_request(server.jr_endpoint, "workspace/applyEdit", ApplyWorkspaceEditParams(missing, WorkspaceEdit(nothing, TextDocumentEdit[tde])))
end

# TODO move to StaticLint
# to be called where typof(x) === CSTParser.ModuleH/BareModule
function find_exported_names(x::EXPR)
    exported_vars = EXPR[]
    for i in 1:length(x.args[3].args)
        expr = x.args[3].args[i]
        if typof(expr) == CSTParser.Export &&
            for j = 2:length(expr)
                if CSTParser.isidentifier(expr.args[j]) && StaticLint.hasref(expr.args[j])
                    push!(exported_vars, expr.args[j])
                end
            end
        end
    end
    return exported_vars
end

function reexport_module(x::EXPR, id, server)
    using_stmt = parentof(x)
    mod_expr = refof(x).val isa StaticLint.Binding ? refof(x).val.val : refof(x).val
    (mod_expr.args isa Nothing || length(mod_expr.args) < 3 || typof(mod_expr.args[3]) != CSTParser.Block || mod_expr.args[3].args isa Nothing) && return # module expr without block
    # find export EXPR
    exported_names = find_exported_names(mod_expr)

    isempty(exported_names) && return
    file, offset = get_file_loc(x)
    insertpos = get_next_line_offset(using_stmt)
    insertpos == -1 && return
    names = filter!(s->!isempty(s), collect(CSTParser.str_value.(exported_names)))
    tde = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[
        TextEdit(Range(file, insertpos .+ (0:0)), string("export ", join(sort(names), ", "), "\n"))
    ])

    JSONRPCEndpoints.send_request(server.jr_endpoint, "workspace/applyEdit", ApplyWorkspaceEditParams(missing, WorkspaceEdit(nothing, TextDocumentEdit[tde])))
end

function wrap_block(x, id, server, type) end
function wrap_block(x::EXPR, id, server, type)
    file, offset = get_file_loc(x) # rese
    l0, _ = get_position_at(file, offset)
    l1, _ = get_position_at(file, offset + x.span)
    if type == :if
        tde = TextDocumentEdit(VersionedTextDocumentIdentifier(file._uri, file._version), TextEdit[
            TextEdit(Range(file, offset .+ (0:0)), "if CONDITION\n"),
            TextEdit(Range(file, offset + x.span .+ (0:0)), "\nend")
        ])
    end

    JSONRPCEndpoints.send_request(server.jr_endpoint, "workspace/applyEdit", ApplyWorkspaceEditParams(missing, WorkspaceEdit(nothing, TextDocumentEdit[tde])))
end


text:
# Solver Parameters

# Verbose Ranges

@enum verboseRange NONE INTERIM SNAPSHOTS DEBUG ALL

# -------------------------
# Solver Parameters
# -------------------------
"""
Line Search Parameters (Notation from Toussaint Notes (2020))

`paramA::Float16`         # Used in Line Search, should be [0.01, 0.3]

`paramB::Float16`         # Used in Line Search, should be [0.1, 0.8]

----
Iteration Counter Parameters

`maxOuterIters::Int32`    # Number of Outer Loop iterations

`maxNewtonSteps::Int32`   # Number of Newton Steps per Outer Loop iterations

----
Exit Condition Parameter

`rTol::Float64`           # When steps are within rTol, loop will stop.

----
Penalty Update Parameters

`penaltyStep::Float16`    # Multiplies the penalty parameter per outer loop

`penaltyMax::Float64`     # Maximum value of the penalty parameter

----
Trust Region Parameters (Notation from Nocedal et Yuan (1998))

`trSizeStart::Float32`    # Starting size of the trust region

`trc1::Float16`           # Success Size Increase Parameter (1 < c1)

`trc2::Float16`           # Taylor Series Error Parameter (0 < c2 < 1)

`trc3::Float16`           # Failed Size Reduction Parameter (0 < c3 < c4)

`trc4::Float16`           # Failed Size Reduction Parameter (c3 < c4 < 1)
"""
struct solverParams
    # Line Search Parameters (Notation from Toussaint Notes (2020))
    paramA::Float16         # Error allowed should be [0.01, 0.3]
    paramB::Float16         # Reduction Factor should be [0.1, 0.8]
    # Iteration Counter Parameters
    maxOuterIters::Int32    # Number of Outer Loop iterations
    maxNewtonSteps::Int32   # Number of Newton Steps per Outer Loop iterations
    # Exit Condition Parameter
    rTol::Float64           # When steps are within rTol, loop will stop.
    # Penalty Update Parameters
    penaltyStep::Float16    # Multiplies the penalty parameter per outer loop
    penaltyMax::Float64     # Maximum value of the penalty parameter
    # Trust Region Parameters (Notation from Nocedal et Yuan (1998))
    trSizeStart::Float32    # Starting size of the trust region
    trc1::Float16           # Success Size Increase Parameter (1 < c1)
    trc2::Float16           # Taylor Series Error Parameter (0 < c2 < 1)
    trc3::Float16           # Failed Size Reduction Parameter (0 < c3 < c4)
    trc4::Float16           # Failed Size Reduction Parameter (c3 < c4 < 1)
    # Printing Parameters
    verbose::verboseRange   # Print debug information?
end

"""
Prints the struct variables in the `solverParams` struct.

See also: [`solverParams`](@ref) for more information.
"""
function solParamPrint(sp::solverParams)
    println()
    println("Beginning solver with parameters: ")
    println("(Line Search) : a = $(sp.paramA), b = $(sp.paramB)")
    print("(Loop #)      : Outer = $(sp.maxOuterIters), ")
    println("Newton = $(sp.maxNewtonSteps)")
    println("(or End at)   : Δ(∇L) = $(sp.rTol)")
    println("(Penalty)     : Δρ = $(sp.penaltyStep), ρMax = $(sp.penaltyMax)")
    println("(Trust Region): Δ = $(sp.trSizeStart)")
    println("                c1 = $(sp.trc1) (with 1 < c1 -> $(1 < sp.trc1))")
    print("                c2 = $(sp.trc2) (with 0 < c2 < 1 -> ")
    println("$(0 < sp.trc2) & $(sp.trc2 < 1))")
    println("                c3 = $(sp.trc3), c4 = $(sp.trc4) ")
    print("                (with 0 < c3 < c4 < 1) -> $(0 < sp.trc3) & ")
    println("$(sp.trc3 < sp.trc4) & $(sp.trc4 < 1)")
    println("(Verbose)     : $(sp.verbose)")
end

max_stars_repo_name: danineamati/TrajOptSOCPs


text:
@testset "RayClassGroup" begin

  @testset "Big prime" begin
    k, _ = wildanger_field(2, 13)
    Zk = maximal_order(k)
    p = next_prime(fmpz(2)^100)
    r, mr = ray_class_group(ideal(Zk, p), n_quo = 2)
    @test order(domain(mr)) == 2
  end

  @testset "quadratic field" begin

    Qx,x=PolynomialRing(FlintQQ,"x")
    K,a=NumberField(x^2+199,"a")
    O=maximal_order(K)
    C,mC=class_group(O)

    for i=9:13
      R,mR=ray_class_group(ideal(O,i), p_part=3)
      for r in R
        @test r== mR\(mR(r))
      end
      R1,mR1=ray_class_group(ideal(O,i), n_quo=3)
      for r in R1
        @test r== mR1\(mR1(r))
      end
      q,mq=quo(R,3)
      @test Hecke.isisomorphic(R1,q)
    end

    Qx,x=PolynomialRing(FlintQQ,"x")
    K,a=NumberField(x^2-5,"a")
    O=maximal_order(K)
    C,mC=class_group(O, redo = true)
    inf_plc=real_places(K)

    for i=9:13
      R,mR=ray_class_group(ideal(O,i),inf_plc,p_part=2)
      for r in R
        @test r== mR\(mR(r))
      end
      R1,mR1=ray_class_group(ideal(O,i),inf_plc)
      for r in R1
        @test r== mR1\(mR1(r))
      end
      R2,mR2=ray_class_group(ideal(O,i), inf_plc, n_quo=2)
      for r in R2
        @test r== mR2\(mR2(r))
      end
      q,mq=quo(R,2)
      @test Hecke.isisomorphic(q,R2)
      q1,mq1=quo(R1,2)
      @test Hecke.isisomorphic(q1,R2)
    end

  end

  @testset "stable subgroups" begin

    Qx,x=PolynomialRing(FlintQQ,"x");
    f=x^2+1;
    K,a=NumberField(f,"a");
    O=maximal_order(K);
    C,mC=class_group(O);
    r,mr=ray_class_group(ideal(O,3*5*7), n_quo=8);
    act=Hecke._act_on_ray_class(mr);
    x=Hecke.stable_subgroups(r,[8],act,op = quo);
    y=subgroups(r, quotype=[8])
    i=0
    for el in y
      if Hecke.is_stable(act,el[2])
        i+=1
      end
    end
    @test length(x)==i

    x=Hecke.stable_subgroups(r,[2,4],act,op = quo);
    y=subgroups(r, quotype=[2,4])
    i=0
    for el in y
      if Hecke.is_stable(act,el[2])
        i+=1
      end
    end
    @test length(x)==i

    r,mr=ray_class_group(ideal(O,9*19*29), n_quo=9);
    act=Hecke._act_on_ray_class(mr);
    x=Hecke.stable_subgroups(r,[9],act,op = quo);
    y=subgroups(r, quotype=[9])
    i=0
    for el in y
      if Hecke.is_stable(act,el[2])
        i+=1
      end
    end
    @test length(x)==i

    x=Hecke.stable_subgroups(r,[3,9],act,op = quo);
    y=subgroups(r, quotype=[3,9])
    i=0
    for el in y
      if Hecke.is_stable(act,el[2])
        i+=1
      end
    end
    @test length(x)==i
  end

end


text:
Compat.@compat function check_derivative(f::Function, g::Function, x::Number)
    auto_g = derivative(f)
    return maximum(abs.(g(x) - auto_g(x)))
end

Compat.@compat function check_gradient{T <: Number}(f::Function, g::Function, x::Vector{T})
    auto_g = gradient(f)
    return maximum(abs.(g(x) - auto_g(x)))
end

Compat.@compat function check_second_derivative(f::Function, h::Function, x::Number)
    auto_h = second_derivative(f)
    return maximum(abs.(h(x) - auto_h(x)))
end

Compat.@compat function check_hessian{T <: Number}(f::Function, h::Function, x::Vector{T})
    auto_h = hessian(f)
    return maximum(abs.(h(x) - auto_h(x)))
end


text:
using LinearAlgebra

"""
    risk_contribution(weights, covariance_matrix)

Calculates the relative contribution to portfolio risk based on the passed asset weights and covariance matrix. The risk contributions are normalized, hence sum to 1.

# Arguments
- `weights`:                Vector of asset weights in portfolio.
- `covariance_matrix`:      Covariance matrix of asset returns.
"""
function risk_contribution(weights, covariance_matrix)
    normalize((weights' * covariance_matrix)' .* weights, 1)
end


text:
## utility functions mainly used by the private math functions in priv.jl

function is_fma_fast end
for T in (Float32, Float64)
    @eval is_fma_fast(::Type{$T}) = $(muladd(nextfloat(one(T)), nextfloat(one(T)), -nextfloat(one(T), 2)) != zero(T))
end
const FMA_FAST = is_fma_fast(Float64) && is_fma_fast(Float32)

@inline isnegzero(x::T) where {T<:AbstractFloat} = x === T(-0.0)

@inline ispinf(x::T) where {T<:AbstractFloat} = x == T(Inf)
@inline isninf(x::T) where {T<:AbstractFloat} = x == T(-Inf)

# _sign emits better native code than sign but does not properly handle the Inf/NaN cases
@inline _sign(d::T) where {T<:AbstractFloat} = flipsign(one(T), d)

@inline integer2float(::Type{Float64}, m::Int) = reinterpret(Float64, (m % Int64) << significand_bits(Float64))
@inline integer2float(::Type{Float32}, m::Int) = reinterpret(Float32, (m % Int32) << significand_bits(Float32))

@inline float2integer(d::Float64) = (reinterpret(Int64, d) >> significand_bits(Float64)) % Int
@inline float2integer(d::Float32) = (reinterpret(Int32, d) >> significand_bits(Float32)) % Int

@inline pow2i(::Type{T}, q::Int) where {T<:Union{Float32,Float64}} = integer2float(T, q + exponent_bias(T))

# sqrt without the domain checks which we don't need since we handle the checks ourselves
if VERSION < v"0.7-"
    _sqrt(x::T) where {T<:Union{Float32,Float64}} = Base.sqrt_llvm_fast(x)
else
    _sqrt(x::T) where {T<:Union{Float32,Float64}} = Base.sqrt_llvm(x)
end


text:
module Catlab

include("core/Core.jl")
include("doctrines/Doctrines.jl")
include("wiring_diagrams/WiringDiagrams.jl")
include("graphics/Graphics.jl")
include("programs/Programs.jl")
include("linear_algebra/LinearAlgebra.jl")
include("experimental/Experimental.jl")

end


text:
gv1 = [1.0]
gll1 = [-100.0]
gv2 = [3.0]
gll2 = [-50.0]
gv3 = [5.0]
gll3 = [-10.0]

    try

        println("++++++++++++++++++++++++++++++++")
        println("Testing GMHRunner with $(nprocs()) processes")
        println("++++++++++++++++++++++++++++++++")

        #create all required objects
        gmhpolicies = [policy(:mh,gmhnprops1),policy(:mh,gmhnprops1,store=:all,jobsegments=:test)]
        gmhrunners = [runner(p,rniter1,gmhnprops1;numburnin = rnburnin1) for p in gmhpolicies]
        gmhchainsamples = [8,13]

        for i=1:length(gmhpolicies)
            indicator1,tunerstate1,chain1 = GeneralizedMetropolisHastings.createcommon(gmhrunners[i],rtuner1,rnparas1,gmhnprops1,gmhnprops1)
            indicator2,tunerstate2,chain2 = GeneralizedMetropolisHastings.createcommon(gmhrunners[i],rtuner2,rnparas1,gmhnprops1,gmhnprops1)
            indicatorstate1 = samplerstate(rsampler1,1,Float64,Float64)
            remotesegments1 = remotesegments(gmhpolicies[i],rmodel1,rsampler1,gmhnprops1)

            println("Testing GMHRunner with $(gmhnprops1) proposals and $(remotesegments1.numsegments) segments")
            @test numproposals(indicator1) == numsamples(indicator1) == gmhnprops1
            @test numtunesteps(tunerstate1) == 2
            @test numparas(chain1) == rnparas1 && numsamples(chain1) == gmhchainsamples[i]
            @test remotesegments1.numsegments == GeneralizedMetropolisHastings._numjobsegments(gmhpolicies[i],gmhnprops1)
            @test remotesegments1.numproposalspersegment == GeneralizedMetropolisHastings._numproposalspersegment(gmhnprops1,remotesegments1.numsegments)
            for j=1:remotesegments1.numsegments
                @test remotesegments1.remote[j].where == collect(GeneralizedMetropolisHastings._processnumbers(gmhpolicies[i],remotesegments1.numsegments))[j]
            end

            println("Testing of preparenext! function")
            setfrom(indicatorstate1,gv1,gll1) ; setproposals(indicatorstate1,gv2,gll2) ; setsegment(remotesegments1,gv2,gll2,gv3,gll3,1) ; setindicator(indicator1,[1.0,0.0,0.0],[3,1,1])
            indicatorstate1 = preparenext!(gmhrunners[i],indicatorstate1,remotesegments1,indicator1)
            testfrom(indicatorstate1,gv3,gll3)
            setfrom(indicatorstate1,gv1,gll1) ; setproposals(indicatorstate1,gv2,gll2) ; setsegment(remotesegments1,gv2,gll2,gv3,gll3,1) ; setindicator(indicator1,[0.0,0.0,1.0],[3,3,3])
            indicatorstate1 = preparenext!(gmhrunners[i],indicatorstate1,remotesegments1,indicator1)
            testfrom(indicatorstate1,gv1,gll1)

            println("Testing of store! function")
            #test storing a value into the chain
            setfrom(indicatorstate1,gv1,gll1) ; setproposals(indicatorstate1,gv2,gll2) ; setsegment(remotesegments1,gv2,gll2,gv3,gll3,2) ; setindicator(indicator1,[1.0,0.0,0.0],[3,1,2])
            store!(gmhrunners[i],indicatorstate1,remotesegments1,indicator1,chain1)
            teststore(chain1,gv3,gll3[1],2,2,2)
            setfrom(indicatorstate1,gv1,gll1) ; setproposals(indicatorstate1,gv2,gll2) ; setsegment(remotesegments1,gv2,gll2,gv3,gll3,2) ; setindicator(indicator1,[0.0,0.0,1.0],[3,3,3])
            store!(gmhrunners[i],indicatorstate1,remotesegments1,indicator1,chain1)
            teststore(chain1,gv1,gll1[1],4,2,4)

            #reset the samplerstates used below
            indicatorstate1 = samplerstate(rsampler1,1,Float64,Float64)
            indicatorstate2 = samplerstate(rsampler1,1,Float64,Float64)
            println("Testing of auxiliary! function")
            srand(rinitseed1) ; initialize!(gmhrunners[i],rmodel1,indicatorstate1,chain1,false) ; propose!(indicatorstate1) ; geometry!(rmodel1,proposals(indicatorstate1))
            srand(rinitseed1) ; initialize!(gmhrunners[i],rmodel1,indicatorstate2,chain1,false) ; auxiliary!(gmhrunners[i],rmodel1,indicatorstate2)
            testfrom(indicatorstate2,indicatorstate1.from.values,indicatorstate1.from.loglikelihood)
            testproposals(indicatorstate2,indicatorstate1.proposals.values,indicatorstate1.proposals.loglikelihood)

            println("Testing of iterate! function")
            #carry out the individual steps of an interation
            srand(rinitseed1)
            initialize!(gmhrunners[i],rmodel1,indicatorstate1,chain1,false)
            auxiliary!(gmhrunners[i],rmodel1,indicatorstate1)
            segmentacceptances = iterate!(remotesegments1,indicatorstate1)
            transitionprobability!(indicator1,acceptance!(indicatorstate1),segmentacceptances)
            sampleindicator!(indicator1)
            srand(rinitseed1)
            initialize!(gmhrunners[i],rmodel1,indicatorstate2,chain1,false)
            iterate!(gmhrunners[i],rmodel1,indicatorstate2,remotesegments1,indicator1,chain1,false)
            #compare the values from both steps
            testfrom(indicatorstate2,indicatorstate1.from.values,indicatorstate1.from.loglikelihood)
            testproposals(indicatorstate2,indicatorstate1.proposals.values,indicatorstate1.proposals.loglikelihood)

            println("Testing of tune! function")
            accepted!(tunerstate1,indicator1)
            accepted!(tunerstate2,indicator2)
            tvals1 = tune(rtuner1,tunerstate1)
            tvals2 = tune(rtuner2,tunerstate2)
            cov1 = cov(indicatorstate1.density.distribution)

            @test index(tunerstate1) == 1
            tune!(gmhrunners[i],rsampler1,indicatorstate1,remotesegments1,rtuner1,tunerstate1)
            @test index(tunerstate1) == 2 && cov1 == cov(indicatorstate1.density.distribution)

            @test index(tunerstate2) == 1
            tune!(gmhrunners[i],rsampler1,indicatorstate1,remotesegments1,rtuner2,tunerstate2)
            @test index(tunerstate2) == 2
            @test_approx_eq cov1*tvals2*tvals2 cov(indicatorstate1.density.distribution)

            for j=1:remotesegments1.numsegments
                @test_approx_eq cov1*tvals2*tvals2 cov(fetch(remotesegments1.remote[j]).samplerstate.density.distribution)
            end

            #run the whole mcmc
            println("Testing of run! function")
            srand(435) ; gmhc = run!(gmhrunners[i],rmodel1,rsampler1,rtuner1)
            @test numsamples(gmhc) == gmhchainsamples[i]
            println("Results of the run!")
            show(round(samples(gmhc),3)) ; println()
            show(round(loglikelihood(gmhc),3)) ; println()
        end
    catch e
        rmprocs(workers())
        throw(e)
    end

gmhpolicy = policy(:mh,gmhnprops1)
gmhrunner = runner(gmhpolicy,rniter1,gmhnprops1;numburnin = rnburnin1)
println("====================")
println("Test show() function")
show(gmhrunner)
println("End  show() function")
println("====================")
println()

println("==============================")
println("Testing of GMHRunner completed")
println("==============================")

# nothing


text:
"""
    new_includer_file(
        package_name::AbstractString,
        package_path:: AbstractString,
        precompiles_rootpath::AbstractString,
        os::Union{Vector{String}, Nothing},
        else_os::Union{String, Nothing},
        version::Union{Vector{VersionNumber}, Nothing},
        else_version::Union{VersionNumber, Nothing})

Creates a "precompile_includer.jl" file.

`package_path = pathof_noload(package_name)`
`precompiles_rootpath`: where the precompile files are stored.

# # Examples
```julia
SnoopCompile.new_includer_file("MatLang", "./src/MatLang.jl", "./deps/SnoopCompile/precompile", ["windows", "linux"], "linux", [v"1.0", v"1.4"], v"1.4")
```
"""
function new_includer_file(
    package_name::AbstractString,
    package_path:: AbstractString,
    precompiles_rootpath_in::AbstractString,
    os::Union{Vector{String}, Nothing},
    else_os::Union{String, Nothing},
    version::Union{Vector{VersionNumber}, Nothing},
    else_version::Union{VersionNumber, Nothing})

    # make the precompile path relative to src folder
    # this is the only path that is written to the disk by the bot, and it should be relative to make it generic.
    precompiles_rootpath = GoodPath(relpath(precompiles_rootpath_in, dirname(package_path)))

    os = standardize_osname(os)
    else_os = standardize_osname(else_os)

    # find multistr, ismultiversion, ismultios
    if isnothing(os)
        ismultios = false
        multistr = ""
        if isnothing(version)
            ismultiversion = false
            multiversionstr = ""
        else
            ismultiversion = true
            multiversionstr = _multiversion(package_name, precompiles_rootpath, version, else_version)
            multistr = multiversionstr
        end #if nothing vesion
    else
        ismultios = true
        if isnothing(version)
            ismultiversion = false
            multistr = _multios(package_name, precompiles_rootpath, os, else_os, ismultiversion)
        else
            ismultiversion = true
            multistr = _multios(package_name, precompiles_rootpath, os, else_os, ismultiversion, version, else_version)
        end # if nothing version
    end # if nothing os

    default_precompile_file_name = "$precompiles_rootpath/precompile_$package_name.jl"

    precompile_config = """
    should_precompile = true

    # Don't edit the following! Instead change the script for `snoop_bot`.
    ismultios = $ismultios
    ismultiversion = $ismultiversion
    # precompile_enclosure
    @static if !should_precompile
        # nothing
    elseif !ismultios && !ismultiversion
        @static if isfile(joinpath(@__DIR__, "$default_precompile_file_name"))
            include("$default_precompile_file_name")
            _precompile_()
        end
    else
        $multistr
    end # precompile_enclosure
    """

    includer_file = "$(dirname(package_path))/precompile_includer.jl"
    @info "$includer_file file will be created/overwritten"
    Base.write(includer_file, precompile_config)
end

"""
Helper function for multios code generation
"""
function _multios(package_name, precompiles_rootpath, os_in, else_os, ismultiversion, version = nothing, else_version = nothing)
    os = similar(os_in, Any)
    os[:] = os_in[:]

    push!(os, string(else_os))

    os_length = length(os)
    multistr = ""
    for (iOs, eachos) in enumerate(os)

        if iOs == 1
            os_phrase = "@static if Sys.is$eachos()"
        elseif iOs == os_length
            os_phrase = "else"
        else
            os_phrase = "elseif Sys.is$eachos()"
        end
        multistr = multistr * "$os_phrase \n"

        if iOs == os_length && isnothing(else_os)
            continue
        end

        if ismultiversion
            multiversionstr = _multiversion(package_name, precompiles_rootpath, version, else_version, eachos)
            multistr = multistr * """
                $multiversionstr
            """
        else
            precompile_file_name = "$precompiles_rootpath/$eachos/precompile_$package_name.jl"
            multistr = multistr * """
                @static if isfile(joinpath(@__DIR__, "$precompile_file_name"))
                    include("$precompile_file_name")
                    _precompile_()
                end
            """
        end
    end # for os

    multistr = multistr * """
        end
    """
    return multistr
end

"""
Helper function for multi Julia version code generation
"""
function _multiversion(package_name, precompiles_rootpath, version_in, else_version, eachos = "")
    version = similar(version_in, Any)
    version[:] = version_in[:]

    sort!(version)

    push!(version, else_version)

    version_length = length(version)
    multiversionstr = ""
    for (iversion, eachversion) in enumerate(version)

        if iversion == 1
            lowerbound = VersionNumber(eachversion.major, eachversion.minor, 0, ("DEV",))
            higherbound = VersionNumber(eachversion.major, eachversion.minor, 9)
            version_phrase = "@static if v\"$lowerbound\" <= VERSION <= v\"$higherbound\""
        elseif iversion == version_length
            version_phrase = "else"
        else
            lowerbound = VersionNumber(eachversion.major, eachversion.minor, 0, ("DEV",))
            higherbound = VersionNumber(eachversion.major, eachversion.minor, 9)
            version_phrase = "elseif v\"$lowerbound\" <= VERSION <= v\"$higherbound\""
        end
        multiversionstr = multiversionstr * "$version_phrase \n"

        if  iversion == version_length && isnothing(else_version)
            continue
        end

        precompile_file_name = "$precompiles_rootpath/$eachos/$(VersionFloat(eachversion))/precompile_$package_name.jl"
        multiversionstr = multiversionstr * """
            @static if isfile(joinpath(@__DIR__, "$precompile_file_name"))
                include("$precompile_file_name")
                _precompile_()
            end
        """
    end # for version

    multiversionstr = multiversionstr * """
        end
    """
    return multiversionstr
end
################################################################
"""
    add_includer(package_name::AbstractString, package_path::AbstractString)

Writes the `include(precompile_includer.jl)` to the package file.

`package_path = pathof_noload(package_name)`
"""
function add_includer(package_name::AbstractString, package_path::AbstractString)
    if !isfile(package_path)
        error("$package_path file doesn't exist")
    end

    # read package
    package_text = Base.read(package_path, String)

    # Checks if any other precompile code already exists (only finds explicitly written _precompile_)
    if occursin("_precompile_()",package_text)
        if occursin("""include("../deps/SnoopCompile/precompile/precompile_$package_name.jl")""", package_text)
            @warn """removing SnoopCompile < v"1.2.2" code"""  # For backward compatibility
            replace(package_text, "_precompile_()"=>"")
            replace(package_text, """include("../deps/SnoopCompile/precompile/precompile_$package_name.jl")"""=>"")
        else
            error("""Please remove `_precompile_()` and any other code that includes a `_precompile_()` function from $package_path
            SnoopCompile automatically creates the code.
            """)
        end
    elseif occursin(r"#\s*include\(\"precompile_includer.jl\"\)", package_text)
        error("""Please uncomment `\"include(\"precompile_includer.jl\")\"`
        Set `should_precompile = false` instead for disabling precompilation.
        """)
    end

    # Adding include to source
    if occursin("include(\"precompile_includer.jl\")", package_text)
        # has precompile_includer
        @info "Package already has \"include(\"precompile_includer.jl\")\""
        return nothing
    else
        # no precompile_includer
        @info "SnoopCompile will try to write  \"include(\"precompile_includer.jl\")\" before end of the module in $package_path. Assume that the last `end` is the end of a module."

        # open lines
        package_lines = Base.open(package_path) do io
            Base.readlines(io, keep=true)
        end

        ## find end of a module
        # assumes that the last `end` is the end of a module
        endline = length(package_lines)
        for iLine = endline:-1:1
            if any(occursin.([r"end(\s)*#(\s)*module", "end"], Ref(package_lines[iLine])))
                endline = iLine
                break
            end
        end

        # add line or error
        try
            code = """
            include("precompile_includer.jl")
            """
            insert!(package_lines,endline,code) # add new empty line before the end
        catch e
            @error("Error occured during writing", e)
            return nothing
        end

        # write the lines
        if package_lines != nothing
            open(package_path, "w") do io
                for l in package_lines
                    Base.write(io, l)
                end
            end
        end

        if !occursin("include(\"precompile_includer.jl\")", Base.read(package_path, String))
            # TODO should we error here?
            @warn """CompileBot failed to add `"include(\"precompile_includer.jl\")"` to $package_path. You should do that manually!"""
        end
    end

    write_gitattributes(package_path)

end

"""
    write_gitattributes(package_path)
Add gitattributes to prevent line ending issues
"""
function write_gitattributes(package_path)
    gitattributes = """
    # Set default behaviour to automatically normalize line endings.
    * text=auto

    # Force bash scripts to always use lf line endings so that if a repo is accessed
    # in Unix via a file share from Windows, the scripts will work.
    *.sh text eol=lf
    """
    package_root_path = dirname(dirname(package_path))
    gitattributes_path = "$package_root_path/.gitattributes"
    if !isfile(gitattributes_path)
        Base.write(gitattributes_path, gitattributes)
    else
        if !occursin("text=auto", Base.read(gitattributes_path, String))
            gitattributes_lines = Base.open(gitattributes_path) do io
                Base.readlines(io, keep=true)
            end
            append!(gitattributes_lines, gitattributes) # add new empty line before the end
            open(gitattributes_path, "w") do io
                for l in gitattributes_lines
                    Base.write(io, l)
                end
            end
        end
    end

end


text:
module W2vUtils

  export
  W2vData,
  nwords,
  projdim,
  vocabulary,
  wordindex,
  projection,
  distance,
  nearest_words,
  analogy,
  load

  include("common.jl")
  include("w2v_data.jl")

end # module


text:
#=
Some positive integers n have the property that the sum [ n + reverse(n) ] consists entirely of odd (decimal) digits. For instance, 36 + 63 = 99 and 409 + 904 = 1313. We will call such numbers reversible; so 36, 63, 409, and 904 are reversible. Leading zeroes are not allowed in either n or reverse(n).

There are 120 reversible numbers below one-thousand.

How many reversible numbers are there below one-billion (10^9)?
=#

#=
Notes:
- Went with a lazy brute force approach here
- It does give an answer in under a minute though, so I'm not going to improve on it
=#
include("projecteulerutils.jl")
function isReversibleNum(x)
  d = digits(x)
  rev = nd(d)
  if d[1] == 0 # No leading zeros allowed
    return 0
  end
  for i in digits(x+rev)
    if isodd(i) == false
      return 0
    end
  end
  return 1
end

function calc()
  count = 0
  for i in collect(1:10^8)
    count = count + isReversibleNum(i)
  end
  count
end
@time println(calc())

max_stars_repo_name: daniel-beard/JuliaProjectEuler

max_issues_repo_name: daniel-beard/JuliaProjectEuler

max_forks_repo_name: daniel-beard/JuliaProjectEuler


text:
@testset "Document" begin
    s = """
    \"""
    𝔽𝔽

    \"""
    struct A end
    """
    d = JuliaFormatter.Document(s)
    ranges = Dict(1 => 1:4, 2 => 5:7, 3 => 8:8, 4 => 9:12, 5 => 13:25, 6 => 26:25)
    @test ranges == d.line_to_range
end


text:
using CGP
using Logging
using Base.Test

CGP.Config.init("cfg/test.yaml")
Logging.configure(level=INFO)

info("Chromosome tests")
include("test/chromosome.jl")
info("Mutation tests")
include("test/mutation.jl")
info("Crossover tests")
include("test/crossover.jl")
info("Distance tests")
include("test/distance.jl")
info("Evolution tests")
include("test/ea.jl")
info("Function tests")
include("test/functions.jl")


text:
#!/usr/bin/env julia

using Pkg

Pkg.add("Plots")
Pkg.add(url="https://github.com/JuliaArrays/StaticArrays.jl")


text:
"""
**SeisPOCS**

*Projection Onto Convex Sets interpolation of seismic records.*

**IN**

* in: input data that can have up to 5 dimensions
* p=1., exponent for thresholding (1 is equivalent to soft thres. high number is equivalent to hard thresholding)
* alpha=1 add-back ratio for imputation step. Use 1 for noise free data, and < 1 for denoising of original traces.
* dt=0.001 sampling rate along the time axis (in seconds)
* fmax=99999. maximum temporal frequency to process.
* padt=2 padding to use for the time axis
* padx=1 padding to use for the spatial axes
* Niter=100 number of iterations

**OUT**

* d_out: interpolated data
"""
function SeisPOCS(in;p=1.,dt=0.001,fmax=99999.,padt=2,padx=1,Niter=100,alpha=1)

    perci = 0.999999;
    percf = 0.0;
    nt = size(in,1)
    nx1 = size(in,2)
    nx2 = size(in,3)
    nx3 = size(in,4)
    nx4 = size(in,5)
    d = zeros(Float32,nt,nx1,nx2,nx3,nx4)
    d[1:nt,1:nx1,1:nx2,1:nx3,1:nx4] = in
    nf = padt*nextpow2(nt)
    dw = 2.*pi/nf/dt
    nw = round(Int,nf/2) + 1
    fmax = fmax < 0.5/dt ? fmax : 0.5/dt
    if(fmax*dt*nf < nw)
	iw_max = round(Int,floor(fmax*dt*nf))
    else
	iw_max = round(Int,floor(0.5/dt))
    end
    nx1 > 1 ? nk1 = padx*nextpow2(nx1) : nk1 = 1
    nx2 > 1 ? nk2 = padx*nextpow2(nx2) : nk2 = 1
    nx3 > 1 ? nk3 = padx*nextpow2(nx3) : nk3 = 1
    nx4 > 1 ? nk4 = padx*nextpow2(nx4) : nk4 = 1
    nk = nk1*nk2*nk3*nk4
    # generate sampling operator from the padded data
    T = CalculateSampling(d)
    T = T[1:1,:,:,:,:]
    if (sum(T[:])/length(T[:]) < 0.05)
	println(sum(T[:])/length(T[:]))
	return in
    else
	T = Pad5D(T,1,nk1,nk2,nk3,nk4)
	T = T[1,:,:,:,:]
	d = Pad5D(d,nf,nk1,nk2,nk3,nk4)
	D = fft(d,1)
	for iw=1:iw_max
	    x = D[iw,:,:,:,:]
	    y = copy(x)
	    for iter = 1 : Niter
		Y = fft(y)
		amp = sort(vec(abs.(Y[:])))
		perc = perci + (iter-1)*((percf-perci)/Niter);
		cutoff = amp[round(Int,floor(perc*nk)+1)];
		for j = 1 : nk1*nk2*nk3*nk4
		    if (abs(Y[j]) < cutoff)
			Y[j] = 0.
		    else
			Y[j] = Y[j]*(1 - (cutoff/(abs(Y[j]) + 0.0000001))^p)
		    end
		end
		y = ifft(Y)
		y = alpha*x + (1-alpha*T).*y
	    end
	    D[iw,:,:,:,:] = y
	end
	# symmetries
	for iw=nw+1:nf
	    D[iw,:,:,:,:] = conj(D[nf-iw+2,:,:,:,:])
	end
	d = ifft(D,1)
	d = real(d[1:nt,1:nx1,1:nx2,1:nx3,1:nx4])
	return d
    end
end

max_stars_repo_name: fercarozzi/myseismicjulia

max_issues_repo_name: fercarozzi/myseismicjulia

max_forks_repo_name: fercarozzi/myseismicjulia


text:
mutable struct TestRobot1d <: AbstractRobot
    "Device name"
    devname::String
    "Position"
    x::Float64
    "Reference Position"
    xᵣ::Float64
    "Name of the axis"
    axis::String
    "Time that the program should sleep for each move"
    Δt::Float64
end

"""
`TestRobot1d(devname, axis="θ";dt=0.0)`

Creates a test robot with a single degree of freedom. Useful for testing the
interfaces and simulating experiments.

 * `devname`: a string with the device name
 * `axis`: a string with the name of the axis
 * `dt`: number of seconds that the program should wait before moving on. Useful to simulate an actual system that is not instantaneous.

This test actuator tries to simulate the wind tunnel turntable so that it has
a position and a reference that can be changed.
"""
TestRobot1d(devname, axis="θ";dt=0.0) = TestRobot1d(devname, 0.0, 0.0, axis, dt)

"""
`move(dev::TestRobot1d, x; a=false, r=false, sync=true)`

Move the test robot to a new position.
It tries to emulate the `WMesaP` interface.
"""
function move(dev::TestRobot1d, x; a=false, r=false, sync=true)
    if r
        dev.x += x
    elseif a
        dev.x = x
    else
        dev.x = x + dev.xᵣ
    end

    sync && sleep(dev.Δt)

    p = dev.x - dev.xᵣ
    println("Movement: θ = $p")
end

numaxes(dev::TestRobot1d) = 1
axesnames(dev::TestRobot1d) = [dev.axis]

moveto(dev::TestRobot1d, x) = move(dev, x[1]; a=false, r=false, sync=true)

rmove(dev::TestRobot1d, x; sync=true) = move(dev, x, r=true, sync=sync)
devposition(dev::TestRobot1d) = dev.x - dev.xᵣ
absposition(dev::TestRobot1d) = dev.x

setreference(dev::TestRobot1d, x=0) = (dev.xᵣ = dev.x - x)
setabsreference(dev::TestRobot1d) = (dev.xᵣ = 0)

waituntildone(dev::TestRobot1d) = sleep(dev.Δt)
stopmotion(dev::TestRobot1d) = sleep(dev.Δt/5)

mutable struct TestRobot <: AbstractCartesianRobot
    devname::String
    n::Int
    x::Vector{Float64}
    xr::Vector{Float64}
    axes::Vector{String}
    axidx::Dict{String,Int}
    Δt::Float64
end

"""
`TestRobot(devname, axes=["x", "y", "z"]; dt=0.0)`

Creates a cartesian robot with several axes. It tries to emulate the interface
used by the wind tunnel's cartesian robot (see the `RoboSimples` package at
<https://github.com/pjsjipt/RoboSimples.jl>).
"""
function TestRobot(devname, axes=["x", "y", "z"]; dt=0.0)
    n = length(axes)
    axidx = Dict{String,Int}()
    axes = axes[1:n]
    for (i, ax) in enumerate(axes)
        axidx[ax] = i
    end

    TestRobot(devname, n, zeros(n), zeros(n), axes, axidx, dt)
end

numaxes(dev::TestRobot) = dev.n
axesnames(dev::TestRobot) = dev.axes

function move(dev::TestRobot, ax::Integer, mm; r=false)
    if r
        dev.x[ax] += mm
    else
        dev.x[ax] = mm
    end
    sleep(dev.Δt)
    println("Position: $ax -> $(dev.axes[ax]) = $(dev.x[ax])")
end

move(dev::TestRobot, ax, mm; r=false) =
    move(dev, dev.axidx[string(ax)], mm; r=r)

function move(dev::TestRobot, axes::AbstractVector,
                                x::AbstractVector; r=false)
    ndof = length(axes)

    for i in 1:ndof
        move(dev, axes[i], x[i]; r=r)
    end
    return
end

moveto(dev::TestRobot, x::AbstractVector) = move(dev, dev.axes, x, r=false)

moveX(dev::TestRobot, mm) = move(dev, mm, dev.axidx["x"]; r=false)
moveY(dev::TestRobot, mm) = move(dev, mm, dev.axidx["y"]; r=false)
moveZ(dev::TestRobot, mm) = move(dev, mm, dev.axidx["z"]; r=false)

rmoveX(dev::TestRobot, mm) = move(dev, mm, dev.axidx["x"]; r=true)
rmoveY(dev::TestRobot, mm) = move(dev, mm, dev.axidx["y"]; r=true)
rmoveZ(dev::TestRobot, mm) = move(dev, mm, dev.axidx["z"]; r=true)

devposition(dev::TestRobot, ax) = dev.x[dev.axidx[string(ax)]]
devposition(dev::TestRobot, ax::Integer) = dev.x[ax]

devposition(dev::TestRobot, axes::AbstractVector) = dev.x[axes]

function devposition(dev::TestRobot)
    pos = Dict{String,Float64}()

    for i in 1:numaxes(dev)
        pos[dev.axes[i]] = dev.x[i]
    end
    return pos
end

positionX(dev::TestRobot) = devposition(dev, "x")
positionY(dev::TestRobot) = devposition(dev, "y")
positionZ(dev::TestRobot) = devposition(dev, "z")

setreference(dev::TestRobot, ax::Integer, mm=0) = dev.x[ax] = mm
setreference(dev::TestRobot, ax, mm=0) = dev.x[dev.axidx[string(ax)]] = mm

function setreference(dev::TestRobot, ax::AbstractVector, mm=0)
    nax = length(ax)
    if length(mm) == 1
        mm = fill(mm[1], nax)
    end

    for i in 1:nax
        setreference(dev, ax[i], mm[i])
    end

end

setreferenceX(dev::TestRobot, mm=0) = dev.x[dev.axidx["x"]] = mm
setreferenceY(dev::TestRobot, mm=0) = dev.x[dev.axidx["y"]] = mm
setreferenceZ(dev::TestRobot, mm=0) = dev.x[dev.axidx["z"]] = mm


text:
"""
    function groebner(
            polynomials;
            reduced=true,
            ordering=:input,
            certify=false,
            forsolve=false,
            linalg=:exact,
            rng=MersenneTwister(42),
            loglevel=Warn
    )

Computes a Groebner basis of the ideal generated by array `polynomials`.

If `reduced` is set, returns the reduced basis, which is **unique** (default).

Uses the ordering inherited from `polynomials` by default.
If `ordering` parameter is explicitly specified, it takes precedence.
Possible orderings to specify are

- :input for preserving the input ordering (default)
- :lex for lexicographic
- :deglex for graded lexicographic
- :degrevlex for graded reverse lexicographic

Graded orderings tend to be the fastest.

The algorithm is randomized. The obtained result will be correct with probability > 0.9999.
Set `certify` to `true` to obtain correct result guaranteedly.

Set `forsolve` to `true` to tell the algorithm to automatically select parameters
for producing a basis that further can used for **solving the input system**. In this case,
the output basis will be in generic position in lexicographic monomial order.
The computation will, however, fail, if the input polynomial system is not solvable.

The `linalg` parameter is responsible for linear algebra backend to be used.
Currently, available options are

- `:exact` for exact sparse linear algebra (default)
- `:prob` for probabilistic sparse linear algebra. Tends to be faster

The algorithm randomized hashing and linear algebra backend depend on random generator `rng`.

Verboseness can be tweaked with the `loglevel` parameter (default is that only warnings are produced).

"""
function groebner(
            polynomials::Vector{Poly};
            reduced::Bool=true,
            ordering::Symbol=:input,
            certify::Bool=false,
            forsolve::Bool=false,
            linalg::Symbol=:exact,
            rng::Rng=Random.MersenneTwister(42),
            loglevel::Logging.LogLevel=Logging.Warn
            ) where {Poly, Rng<:Random.AbstractRNG}

    #= set the logger =#
    prev_logger = Logging.global_logger(ConsoleLogger(stderr, loglevel))

    #= extract ring information, exponents and coefficients
       from input polynomials =#
    # Copies input, so that polynomials would not be changed itself.
    ring, exps, coeffs = convert_to_internal(polynomials, ordering)

    #= check and set algorithm parameters =#
    metainfo = set_metaparameters(ring, ordering, certify, forsolve, linalg, rng)
    # now ring stores computation ordering
    # metainfo is now a struct to store target ordering

    #= change input ordering if needed =#
    assure_ordering!(ring, exps, coeffs, metainfo)

    #= compute the groebner basis =#
    if ring.ch != 0
        # bexps, bcoeffs = groebner_ff(ring, exps, coeffs, reduced, rng, metainfo)
        # if finite field
        # Always returns UInt coefficients #
        bexps, bcoeffs = groebner_ff(ring, exps, coeffs, reduced, metainfo)
    else
        # if rational coefficients
        # Always returns rational coefficients #
        bexps, bcoeffs = groebner_qq(ring, exps, coeffs, reduced, metainfo)
    end

    # ordering in bexps here matches target ordering in metainfo

    #= revert logger =#
    Logging.global_logger(prev_logger)

    # ring contains ordering of computation, it is the requested ordering
    #= convert result back to representation of input =#
    convert_to_output(ring, polynomials, bexps, bcoeffs, metainfo)
end

#######################################
# isgroebner

"""
    function isgroebner(
                polynomials;
                ordering=:input,
                certify=true,
                rng=MersenneTwister(42),
                loglevel=Logging.Warn
    )

Checks if `polynomials` forms a Groebner basis.

Uses the ordering on `polynomials` by default.
If `ordering` is explicitly specialized, it takes precedence.

One may set `certify` to `false` to speed up the computation a bit.
The obtained result will be correct with probability > 0.9999

"""
function isgroebner(
            polynomials::Vector{Poly};
            ordering=:input,
            certify::Bool=true,
            rng::Rng=Random.MersenneTwister(42),
            loglevel::LogLevel=Logging.Warn
    ) where {Poly, Rng<:Random.AbstractRNG}

    #= set the logger =#
    prev_logger = Logging.global_logger(ConsoleLogger(stderr, loglevel))

    #= extract ring information, exponents and coefficients
       from input polynomials =#
    # Copies input, so that polys would not be changed itself.
    ring, exps, coeffs = convert_to_internal(polynomials, ordering)

    #= check and set algorithm parameters =#
    metainfo = set_metaparameters(ring, ordering, certify, false, :exact, rng)
    # now ring stores computation ordering
    # metainfo is now a struct to store target ordering

    #= change input ordering if needed =#
    assure_ordering!(ring, exps, coeffs, metainfo)

    #= compute the groebner basis =#
    if ring.ch != 0
        # if finite field
        # Always returns UInt coefficients #
        flag = isgroebner_ff(ring, exps, coeffs, metainfo)
    else
        # if rational coefficients
        # Always returns rational coefficients #
        flag = isgroebner_qq(ring, exps, coeffs, metainfo)
    end

    #=
    Assuming ordering of `bexps` here matches `ring.ord`
    =#

    #= revert logger =#
    Logging.global_logger(prev_logger)

    flag
end

#######################################
# normalform

"""
    function normalform(
                basis::Vector{Poly},
                tobereduced::Poly;
                ordering::Symbol=:input,
                rng::Rng=Random.MersenneTwister(42),
                loglevel=Logging.Warn
    )

Computes the normal form of `tobereduced` w.r.t `basis`.
The latter is assumed to be a Groebner basis.

Uses the ordering on `basispolys` by default.
If `ordering` is explicitly specialized, it takes precedence.

"""
function normalform(
            basispolys::Vector{Poly},
            tobereduced::Poly;
            ordering::Symbol=:input,
            rng::Rng=Random.MersenneTwister(42),
            loglevel::LogLevel=Logging.Warn
            ) where {Poly, Rng<:Random.AbstractRNG}

    iszero(tobereduced) && return tobereduced

    if !isgroebner(basispolys)
        @warn "Input basis does not look like a groebner basis"
    end

    first(normalform(
            basispolys, [tobereduced],
            ordering=ordering, rng=rng, loglevel=loglevel)
    )
end

function normalform(
            basispolys::Vector{Poly},
            tobereduced::Vector{Poly};
            ordering::Symbol=:input,
            rng::Rng=Random.MersenneTwister(42),
            loglevel::LogLevel=Logging.Warn
            ) where {Poly, Rng<:Random.AbstractRNG}

    #= set the logger =#
    prev_logger = Logging.global_logger(ConsoleLogger(stderr, loglevel))

    #= extract ring information, exponents and coefficients
       from input basis polynomials =#
    # Copies input, so that polys would not be changed itself.
    ring1, basisexps, basiscoeffs = convert_to_internal(basispolys, ordering)
    ring2, tbrexps, tbrcoeffs = convert_to_internal(tobereduced, ordering)

    @assert ring1.nvars == ring2.nvars && ring1.ch == ring2.ch
    @assert ring1.ord == ring2.ord

    ring = ring1

    #= check and set algorithm parameters =#
    metainfo = set_metaparameters(ring, ordering, false, false, :exact, rng)

    #= change input ordering if needed =#
    assure_ordering!(ring, basisexps, basiscoeffs, metainfo)
    assure_ordering!(ring, tbrexps, tbrcoeffs, metainfo)

    # We assume basispolys is already a Groebner basis! #

    #= compute the groebner basis =#
    bexps, bcoeffs = normal_form_f4(
                        ring, basisexps, basiscoeffs,
                        tbrexps, tbrcoeffs, rng)

    #=
    Assuming ordering of `bexps` here matches `ring.ord`
    =#

    #= revert logger =#
    Logging.global_logger(prev_logger)

    # ring contains ordering of computation, it is the requested ordering
    #= convert result back to representation of input =#
    convert_to_output(ring, tobereduced, bexps, bcoeffs, metainfo)
end

#######################################
# fglm

"""
    function fglm(
            basis;
            rng=MersenneTwister(42),
            loglevel=Warn
    )

Applies fglm to `basis` and returns a Groebner basis in `lex` ordering.

Assumes `basis` is already a Groebner basis.

"""
function fglm(
            basis::Vector{Poly};
            rng::Rng=Random.MersenneTwister(42),
            loglevel::Logging.LogLevel=Logging.Warn
            ) where {Poly, Rng<:Random.AbstractRNG}

    #= set the logger =#
    prev_logger = Logging.global_logger(ConsoleLogger(stderr, loglevel))

    #= extract ring information, exponents and coefficients
       from input polynomials =#
    # Copies input, so that polynomials would not be changed itself.
    ring, exps, coeffs = convert_to_internal(basis, :input)

    metainfo = set_metaparameters(ring, :lex, false, false, :exact, rng)

    bexps, bcoeffs = fglm_f4(ring, exps, coeffs, metainfo)

    # lol
    ring.ord = :lex

    # ordering in bexps here matches target ordering in metainfo

    #= revert logger =#
    Logging.global_logger(prev_logger)

    # ring contains ordering of computation, it is the requested ordering
    #= convert result back to representation of input =#
    convert_to_output(ring, basis, bexps, bcoeffs, metainfo)
end

#######################################
# kbase

"""
    function kbase(
            basis;
            rng=MersenneTwister(42),
            loglevel=Warn
    )

Computes the basis of polynomial ring modulo the zero-dimensional ideal
generated by `basis` as a basis of vector space.

"""
function kbase(
            basis::Vector{Poly};
            rng::Rng=Random.MersenneTwister(42),
            loglevel::Logging.LogLevel=Logging.Warn
            ) where {Poly, Rng<:Random.AbstractRNG}

    #= set the logger =#
    prev_logger = Logging.global_logger(ConsoleLogger(stderr, loglevel))

    #= extract ring information, exponents and coefficients
       from input polynomials =#
    # Copies input, so that polynomials would not be changed itself.
    ring, exps, coeffs = convert_to_internal(basis, :input)

    metainfo = set_metaparameters(ring, :input, false, false, :exact, rng)

    bexps, bcoeffs = kbase_f4(ring, exps, coeffs, metainfo)

    # ordering in bexps here matches target ordering in metainfo

    #= revert logger =#
    Logging.global_logger(prev_logger)

    # ring contains ordering of computation, it is the requested ordering
    #= convert result back to representation of input =#
    convert_to_output(ring, basis, bexps, bcoeffs, metainfo)
end


text:
using Printf

# Note the creation of the enum must be outside the function!
@enum Color begin
    red = 1
    blue = 2
    green = 3
end

function enum_examples()
    println("--------------------------------------")
    println("Enum examples")

    println()

    println("We can create enums")
    favourite_color = green::Color
    println(favourite_color)
end

max_stars_repo_name: James-P-D/JuliaDump

max_issues_repo_name: James-P-D/JuliaDump

max_forks_repo_name: James-P-D/JuliaDump


text:
@testset "Decimal" begin
      x = Decimal(420, 0)
      @test Decimal(420, 0) ==
      Decimal(4200, -1) ==
      Decimal(42, 1) ==
      Decimal("420") ==
      Decimal("420.0") ==
      Decimal("420E0") ==
      Decimal("42E1") ==
      Decimal("42.0E1") ==
      parse(Decimal, "420") ==
      Decimal(420) ==
      420 ==
      420.0

      @test string(Decimals.One) == "1"
      @test string(x) == "420"
      @test string(Decimal(1234, -4)) == "0.1234"
      @test string(Decimal(123400, -6)) == "0.1234"
      @test string(strip_trailing_zeros(Decimal(123400, -6))) == "0.1234"

      @testset "Hash" begin
            d = Dict(d"4.2" => true, d"0.5" => true)
            @test d[d"4.2000"]
            @test d[Decimal(42, -1)]
            @test d[0.5]
            @test d[1//2]
            @test d[5//10]
            @test d[d"5E-1"]
      end
end


text:
@require DataStreams begin

    using TableTraits
    using DataStreams
    using WeakRefStrings
    using DataValues
    using IteratorInterfaceExtensions

    struct DataStreamIterator{T, S<:DataStreams.Data.Source, TC, TSC}
        source::S
        schema::DataStreams.Data.Schema
    end

    IteratorInterfaceExtensions.isiterable(x::DataStreams.Data.Source) = true
    TableTraits.isiterabletable(x::DataStreams.Data.Source) = true

    function TableTraits.getiterator(source::S) where {S <: DataStreams.Data.Source}
        if !Data.streamtype(S, Data.Field)
            error("Only sources that support field-based streaming are supported by IterableTables.")
        end

        schema = Data.schema(source)

        col_expressions = Array{Expr,1}()
        columns_tuple_type = Expr(:curly, :Tuple)
        columns_tuple_type_source = Expr(:curly, :Tuple)

        for i in 1:schema.cols
            if Data.types(schema)[i] <: WeakRefString
                col_type = String
            elseif Data.types(schema)[i] >: Missing && Missings.T(Data.types(schema)[i]) <: WeakRefString
                col_type = DataValue{String}
            elseif Data.types(schema)[i] >: Missing
                col_type = DataValue{Missings.T(Data.types(schema)[i])}
            else
                col_type = Data.types(schema)[i]
            end

            push!(col_expressions, Expr(:(::), schema.header[i], col_type))
            push!(columns_tuple_type.args, col_type)
            push!(columns_tuple_type_source.args, Data.types(schema)[i])
        end
        t_expr = NamedTuples.make_tuple(col_expressions)

        t2 = :(DataStreamIterator{Float64,Float64,Float64,Float64})
        t2.args[2] = t_expr
        t2.args[3] = typeof(source)
        t2.args[4] = columns_tuple_type
        t2.args[5] = columns_tuple_type_source

        t = eval(t2)

        e_df = t(source, schema)

        return e_df
    end

    function Base.length(iter::DataStreamIterator{T,S,TC,TSC}) where {T,S <: DataStreams.Data.Source,TC,TSC}
        return iter.schema.rows
    end

    function Base.eltype(iter::DataStreamIterator{T,S,TC,TSC}) where {T,S <: DataStreams.Data.Source,TC,TSC}
        return T
    end

    function Base.start(iter::DataStreamIterator{T,S,TC,TSC}) where {T,S <: DataStreams.Data.Source,TC,TSC}
        return 1
    end

    function _convertion_helper_for_datastreams(source, row, col, T, T2)
        v = Data.streamfrom(source, Data.Field, T, row, col)
        if v===missing
            return DataValue{T2}()
        else
            return DataValue{T2}(convert(T2, v))
        end
    end

    @generated function Base.next(iter::DataStreamIterator{T,S,TC,TSC}, state) where {T,S <: DataStreams.Data.Source,TC,TSC}
        constructor_call = Expr(:call, :($T))
        for i in 1:length(TC.types)
            if TC.types[i] <: String && TSC.types[i] <: WeakRefString
                get_expression = :(Data.streamfrom(source, Data.Field, $(TSC.types[i]), row, $i))
            elseif TC.types[i] <: DataValue && Missings.T(TSC.types[i]) <: WeakRefString
                get_expression = :(_convertion_helper_for_datastreams(source, row, $i, $(TSC.types[i]), String))
            elseif TC.types[i] <: DataValue
                get_expression = :(_convertion_helper_for_datastreams(source, row, $i, $(TSC.types[i]), $(Missings.T(TSC.types[i]))))
            else
                get_expression = :(Data.streamfrom(source, Data.Field, $(TC.types[i]), row, $i))
            end
            push!(constructor_call.args, get_expression)
        end

        quote
            source = iter.source
            row = state
            a = $constructor_call
            return a, state+1
        end
    end

    function Base.done(iter::DataStreamIterator{T,S,TC,TSC}, state) where {T,S <: DataStreams.Data.Source,TC,TSC}
        return Data.isdone(iter.source,state,1)
    end

    # DataStreams Source

    mutable struct DataStreamSource{TSource,TE} <: Data.Source
        _schema::Data.Schema
        data::TSource
        iterate_state
        current_row::Int
        current_val::TE
        function DataStreamSource{TSource,TE}(schema, data) where {TSource,TE}
            x = new(schema, data)
            x.current_row = 0
            return x
        end
    end

    function Data.isdone(source::DataStreamSource{TSource,TE}, row, col) where {TSource,TE}
        row==source.current_row || row==source.current_row+1 || error()

        if source.current_row==0
            source.iterate_state = start(source.data)
        end

        if row==source.current_row+1
            if done(source.data, source.iterate_state)
                return true
            else
                (source.current_val, source.iterate_state) = next(source.data, source.iterate_state)
                source.current_row = source.current_row+1
            end
        end

        return false
    end

    Data.streamtype(::Type{T}, ::Type{Data.Field}) where {T <: DataStreamSource} = true

    function Data.streamfrom(source::DataStreamSource, ::Type{Data.Field}, ::Type{T}, row, col) where {T}
        row==source.current_row || row==source.current_row+1 || error()

        if source.current_row==0
            source.iterate_state = start(source.data)
        end

        if row==source.current_row+1
            (source.current_val, source.iterate_state) = next(source.data, source.iterate_state)
            source.current_row = source.current_row+1
        end

        return source.current_val[col]::T
    end

    function Data.streamfrom(source::DataStreamSource, ::Type{Data.Field}, ::Type{Nullable{T}}, row, col) where {T}
        row==source.current_row || row==source.current_row+1 || error()

        if source.current_row==0
            source.iterate_state = start(source.data)
        end

        if row==source.current_row+1
            (source.current_val, source.iterate_state) = next(source.data, source.iterate_state)
            source.current_row = source.current_row+1
        end

        val = source.current_val[col]

        if typeof(val) <: DataValue
            if isnull(val)
                return Nullable{T}()
            else
                return Nullable{T}(get(val))
            end
        else
            return Nullable{T}(val)
        end
    end

    function Data.schema(source::DataStreamSource)
        return source._schema
    end

    function Data.schema(source::DataStreamSource, ::Type{Data.Field})
        return Data.schema(source)
    end

    function get_datastreams_source(source::S) where {S}
        isiterabletable(source) || error()

        iter = getiterator(source)

        column_types = TableTraits.column_types(iter)
        column_names = TableTraits.column_names(iter)

        for (i,v) in enumerate(column_types)
            if v <: DataValue
                column_types[i] = Nullable{v.parameters[1]}
            end
        end

        schema = Data.Schema(column_names, column_types, -1)
        source = DataStreamSource{typeof(iter),eltype(iter)}(schema, iter)
        return source
    end

end


text:
using Distributions
using Base.Test

# RealInterval
r = RealInterval(1.5, 4.0)
@test minimum(r) == 1.5
@test maximum(r) == 4.0

@test partype(Gamma(1, 2)) == Float64
@test partype(Gamma(1.1, 2)) == Float64
@test partype(Normal(1//1, 2//1)) == Rational{Int64}
@test partype(MvNormal(rand(Float32, 5), eye(Float32, 5))) == Float32

# special cases
@test partype(Kolmogorov()) == Float64
@test partype(Hypergeometric(2, 2, 2)) == Float64
@test partype(DiscreteUniform(0, 4)) == Float64

A = rand(1:10, 5, 5)
B = rand(Float32, 4)
C = 1//2
Z = Distributions.ZeroVector(Float64, 5)
L = rand(Float32, 4, 4)
D = PDMats.PDMat(L * L')
@test Distributions.promote_eltype(A, B) == (convert(Array{Float32}, A), convert(Array{Float32}, B))
@test Distributions.promote_eltype(A, C) == (convert(Array{Rational{Int}}, A), convert(Float32, C))
AA, DD = Distributions.promote_eltype(A, D)
@test AA == convert(Array{Float32}, A)
@test DD.mat == convert(PDMats.PDMat{Float32}, D).mat
ZZ, DD = Distributions.promote_eltype(Z, D)
@test ZZ == Distributions.ZeroVector{Float32}(5)
@test DD.mat == convert(PDMats.PDMat{Float32}, D).mat
@test Distributions.convert_eltype(Float32, A) == convert(Array{Float32}, A)
@test Distributions.convert_eltype(Float32, Z) == Distributions.ZeroVector{Float32}(length(Z))
@test Distributions.convert_eltype(Float64, D).mat == convert(PDMats.PDMat{Float64}, D).mat
@test typeof(convert(Distributions.ZeroVector{Float32}, Z)) == Distributions.ZeroVector{Float32}