text:
export interpolateToGrid, interpolateToCommonGrid, interpolateToRefImage,
       indexFromBGToFG

function interpolateToGrid(image::ImageMeta{T,3}, fovOut::Vector{Float64},
                offsetOut::Vector{Float64}, gridSizeOut::Vector{Int64}; kargs...) where T

  rot = get(image, :rotation, [0.0,0.0,0.0])
  imOutAxis = interpolateToGrid(arraydata(image), rot, fovOut, offsetOut, gridSizeOut)
  return copyproperties(image, imOutAxis)
end

function interpolateToGrid(image::AxisArray{T,3}, rot::Vector{Float64}, fovOut::Vector{Float64},
                offsetOut::Vector{Float64}, gridSizeOut::Vector{Int64}; kargs...) where T

  pixspacing = collect(converttometer(pixelspacing(image)))
  offset = collect(converttometer(imcenter(image)))
  #pixspacing = collect(pixelspacing(image))
  #offset = collect(imcenter(image))

  pixelspacingOut = fovOut ./ gridSizeOut

  imOut = interpolateToGrid(image.data, pixspacing, offset, rot, fovOut, offsetOut, gridSizeOut)

  offset = (offsetOut .- 0.5.*fovOut .+ 0.5.*pixelspacingOut) .* 1000 .* u"mm"
  imOutAxis = AxisArray(imOut, (:x,:y,:z),tuple((pixelspacingOut .* 1000 .* u"mm")...),tuple(offset...))
  #offset = (offsetOut .- 0.5.*fovOut .+ 0.5.*pixelspacingOut)
  #imOutAxis = AxisArray(imOut, (:x,:y,:z),tuple((pixelspacingOut)...),tuple(offset...))

  return imOutAxis
end

function interpolateToGrid(image::Array{T,3}, pixspacing::Vector{Float64}, offset::Vector{Float64},
                           rot::Vector{Float64}, fovOut::Vector{Float64}, offsetOut::Vector{Float64},
                           gridSizeOut::Vector{Int64}; interpDegree=1) where T

  imOut = zeros(eltype(image), gridSizeOut[1], gridSizeOut[2], gridSizeOut[3])

  if interpDegree == 1
    interpType = BSpline(Linear())
  elseif interpDegree == 2
    interpType = BSpline(Quadratic(Reflect()))
  else
    interpType = BSpline(Cubic(Reflect()))
  end

  tmp = ( size(image,1)==1 ? NoInterp() : interpType,
          size(image,2)==1 ? NoInterp() : interpType,
          size(image,3)==1 ? NoInterp() : interpType )

  # Interpolations.jl
  imInterp = extrapolate(interpolate(image, tmp), zero(eltype(image)))

  imSize = [size(image,1),size(image,2),size(image,3)]

  imFov = imSize.*pixspacing

  offsetPixel = (-fovOut./2 + imFov./2 + offsetOut - offset)./ pixspacing
  #diffSpacing = (fovOut ./ gridSizeOut) ./ pixspacing
  diffSpacing = (fovOut ./ pixspacing ) ./ gridSizeOut
  pixelspacingOut = fovOut ./ gridSizeOut

  r = rot
  Rx = [1 0 0; 0 cos(r[1]) -sin(r[1]); 0 sin(r[1]) cos(r[1])]
  Ry = [cos(r[2]) 0 sin(r[2]); 0 1 0; -sin(r[2]) 0 cos(r[2])]
  Rz = [cos(r[3]) -sin(r[3]) 0; sin(r[3]) cos(r[3]) 0; 0 0 1]

  R = Rz*Ry*Rx

  ax = 0.5+gridSizeOut[1]/2
  ay = 0.5+gridSizeOut[2]/2
  az = 0.5+gridSizeOut[3]/2

  bx = R[:,1]*diffSpacing[1]
  by = R[:,2]*diffSpacing[2]
  bz = R[:,3]*diffSpacing[3]

  cx = gridSizeOut[1]/2*diffSpacing[1]+0.5+offsetPixel[1]
  cy = gridSizeOut[2]/2*diffSpacing[2]+0.5+offsetPixel[2]
  cz = gridSizeOut[3]/2*diffSpacing[3]+0.5+offsetPixel[3]

  _innerInterpolation!(imOut, imInterp, imSize, gridSizeOut, ax, ay, az, bx, by, bz, cx, cy, cz)

  return imOut
end

function _innerInterpolation!(imOut, imInterp, imSize, gridSizeOut, ax, ay, az, bx, by, bz, cx, cy, cz)
  for iz=1:gridSizeOut[3]
    for iy=1:gridSizeOut[2]
      v = (iz-az) .* bz + (iy-ay) .* by - ax .* bx
      for ix=1:gridSizeOut[1]
         for d=1:3
           v[d] += bx[d]
         end
         x,y,z = v[1]+cx, v[2]+cy, v[3]+cz
         imOut[ix,iy,iz] = imInterp(x, y, z)
      end
    end
  end
  return
end

### interpolateToRefImage ###

function interpolateToRefImage(background, foreground, R, t; offset=nothing)
  foreground = changeCenter(foreground, t)
  refVoxelSize = collect(converttometer(pixelspacing(background)))
  refSize = [size(background)...][1:3]
  refFov = [size(background)...][1:3].*refVoxelSize
  offset==nothing ? refOffset = collect(converttometer(imcenter(background))) : refOffset=offset
  if ndims(foreground) == 3
    @debug "interpTorefImage" refVoxelSize refSize refFov refOffset
    UInterp =  interpolateToGrid(foreground,refFov,refOffset,refSize,R)
    return UInterp
  end
end

function interpolateToRefImage(refImage, dynImage::ImageMeta{T,3}; offset=nothing,kargs...) where T
  refVoxelSize = collect(converttometer(pixelspacing(refImage)))
  refSize = collect(size(refImage))[1:3]
  refFov = collect(size(refImage))[1:3].*refVoxelSize
  (offset==nothing) ? refOffset = collect(converttometer(imcenter(refImage))) : refOffset=offset

  UInterp =  interpolateToGrid(dynImage,refFov,refOffset,refSize; kargs...)
  return UInterp
end

function interpolateToRefImage(refImage, dynImage::ImageMeta{T,4}; offset=nothing,kargs...) where T
  if timeaxis(dynImage.data) == nothing
    refVoxelSize = collect(converttometer(pixelspacing(refImage)))
    refSize = collect(size(refImage))[1:3]
    refFov = collect(size(refImage))[1:3].*refVoxelSize
    (offset==nothing) ? refOffset = collect(converttometer(imcenter(refImage))) : refOffset=offset

    U = zeros(eltype(dynImage),size(dynImage,1),refSize[1],refSize[2],refSize[3])
    for c=1:size(dynImage,1)
      U[c,:,:,:] = interpolateToGrid(dynImage[c,:,:,:], refFov, refOffset, refSize; kargs...)
    end

    UInterpAxis = AxisArray(U,AxisArrays.axes(dynImage)[1], AxisArrays.axes(refImage)...)
    UInterp = copyproperties(dynImage,UInterpAxis) #This is not entirely correct. dynImage has a different pixelspacing
  else
    refVoxelSize = collect(converttometer(pixelspacing(refImage)))
    refSize = collect(size(refImage))[1:3]
    refFov = collect(size(refImage))[1:3].*refVoxelSize
    (offset==nothing) ? refOffset = collect(converttometer(imcenter(refImage))) : refOffset=offset

    U = zeros(eltype(dynImage),refSize[1],refSize[2],refSize[3],size(dynImage,4))
    for l=1:size(dynImage,4)
      U[:,:,:,l] = interpolateToGrid(dynImage[:,:,:,l], refFov, refOffset, refSize; kargs...)
    end

    UInterpAxis = AxisArray(U,AxisArrays.axes(refImage)..., AxisArrays.axes(dynImage)[4])
    UInterp = copyproperties(dynImage,UInterpAxis) #This is not entirely correct. dynImage has a different pixelspacing
  end
  return UInterp
end

function interpolateToRefImage(refImage, dynImage::ImageMeta{T,5}; offset=nothing,kargs...) where T
  refVoxelSize = collect(converttometer(pixelspacing(refImage)))
  refSize = collect(size(refImage))[1:3]
  refFov = collect(size(refImage))[1:3].*refVoxelSize
  (offset==nothing) ? refOffset = collect(converttometer(imcenter(refImage))) : refOffset=offset

  U = zeros(eltype(dynImage),size(dynImage,1),refSize[1],refSize[2],refSize[3],size(dynImage,5))
  for c=1:size(dynImage,1)
    for l=1:size(dynImage,4)
      U[c,:,:,:,l] = interpolateToGrid(dynImage[c,:,:,:,l] ,refFov,refOffset,refSize; kargs...)
    end
  end
  UInterpAxis = AxisArray(U, AxisArrays.axes(dynImage)[1], AxisArrays.axes(refImage)..., AxisArrays.axes(dynImage)[5])
  UInterp = copyproperties(dynImage,UInterpAxis) #This is not entirely correct. dynImage has a different pixelspacing

  return UInterp
end

function changeCenter(im::ImageMeta{T,3}, newcenter) where T
  newRanges_ = collect(axisvalues(im)[1:3])
  newRanges = [newRanges_[d] .+ newcenter[d]*u"m" .- imcenter(im)[d] for d=1:3]

  im_ = AxisArray(im.data, Axis{:x}(newRanges[1]), Axis{:y}(newRanges[2]), Axis{:z}(newRanges[3]))

  return copyproperties(im,im_)
end

function changeCenter(im::ImageMeta{T,4}, newcenter) where T
  if timeaxis(im.data) == nothing
    newRanges_ = collect(axisvalues(im)[2:4])
    newRanges = [newRanges_[d] .+ newcenter[d]*u"m" .- imcenter(im)[d] for d=1:3]

    im_ = AxisArray(im.data, Axis{:color}(1:size(im,1)), Axis{:x}(newRanges[1]), Axis{:y}(newRanges[2]), Axis{:z}(newRanges[3]))
  else
    newRanges_ = collect(axisvalues(im)[1:3])
    newRanges = [newRanges_[d] .+ newcenter[d]*u"m" .- imcenter(im)[d] for d=1:3]

    im_ = AxisArray(im.data, Axis{:x}(newRanges[1]), Axis{:y}(newRanges[2]), Axis{:z}(newRanges[3]), timeaxis(im.data))
  end
  return copyproperties(im,im_)
end

function changeCenter(im::ImageMeta{T,5}, newcenter) where T
  newRanges_ = collect(axisvalues(im)[2:4])
  newRanges = [newRanges_[d] .+ newcenter[d]*u"m" .- imcenter(im)[d] for d=1:3]

  im_ = AxisArray(im.data, Axis{:color}(1:size(im,1)), Axis{:x}(newRanges[1]), Axis{:y}(newRanges[2]), Axis{:z}(newRanges[3]), timeaxis(im.data))

  return copyproperties(im,im_)
end

function interpolateToRefImage(dataBG, data, params::Dict)

  data_ = changeCenter(data, [params[:transX]+params[:transBGX],
                    params[:transY]+params[:transBGY],
                    params[:transZ]+params[:transBGZ]])

  data_["rotation"] = [params[:rotX]+params[:rotBGX],
                     params[:rotY]+params[:rotBGY],
                     params[:rotZ]+params[:rotBGZ]]

  return interpolateToRefImage(dataBG, data_, interpDegree=1)
end

# This version maps the bg on itself
function interpolateToRefImage(dataBG, params::Dict)
  dataBG__ = deepcopy(dataBG)
  dataBG_ = changeCenter(dataBG__, [params[:transBGX], params[:transBGY], params[:transBGZ]])

  dataBG_["rotation"] = [params[:rotBGX], params[:rotBGY], params[:rotBGZ]]

  dataBGInterp = interpolateToRefImage(dataBG, dataBG_, interpDegree=1)

  return dataBGInterp
end

# difficult to dispatch currently
function interpolateToRefImageAllFr(dataBG, im, params::Dict)

  L = size(im[1],4)

  data_all = zeros(eltype(im[1]),size(dataBG,1),size(dataBG,2),size(dataBG,3),L)

  data_ = [getindex(d,:,:,:,1) for d in im]
  dataInterp = interpolateToRefImage(dataBG, data_, params)
  data_all[:,:,:,1] = dataInterp[1]

  for l=2:L
    data_ = [getindex(d,:,:,:,l) for d in im]
    dataInterp = interpolateToRefImage(dataBG, data_, params)
    data_all[:,:,:,l] = dataInterp[1]
  end

  dataAllAxis = AxisArray(data_all,AxisArrays.axes(dataInterp[1])..., AxisArrays.axes(im[1])[4])
  return copyproperties(im[1], dataAllAxis)
end

### indexFromBGToFG ###

function indexFromBGToFG(refImage, data, params::Dict; offset=nothing)

  image_ = data[1,:,:,:]

  image = changeCenter(image_, [params[:transX]+params[:transBGX],
                    params[:transY]+params[:transBGY],
                    params[:transZ]+params[:transBGZ]])

  image["rotation"] = [params[:rotX]+params[:rotBGX],
                     params[:rotY]+params[:rotBGY],
                     params[:rotZ]+params[:rotBGZ]]

  refVoxelSize = collect(converttometer(pixelspacing(refImage)))
  refSize = [size(refImage)...][1:3]
  refFov = [size(refImage)...][1:3].*refVoxelSize
  offset==nothing ? refOffset = collect(converttometer(imcenter(refImage))) : refOffset=offset

  fovOut = refFov
  offsetOut = refOffset
  gridSizeOut = refSize

  imVoxelSize = collect(converttometer(pixelspacing(image)))
  imSize = [size(image,1),size(image,2),size(image,3)]
  imFov = imSize.*imVoxelSize
  imOffset = collect(converttometer(imcenter(image)))
  rotation = get(image, "rotation", [0.0,0.0,0.0])

  offsetPixel = (-fovOut./2 + imFov./2 + offsetOut-imOffset)./ imVoxelSize
  #diffSpacing = (fovOut ./ gridSizeOut) ./ imVoxelSize
  diffSpacing = (fovOut ./ imVoxelSize ) ./ gridSizeOut

  r = rotation
  Rx = [1 0 0; 0 cos(r[1]) -sin(r[1]); 0 sin(r[1]) cos(r[1])]
  Ry = [cos(r[2]) 0 sin(r[2]); 0 1 0; -sin(r[2]) 0 cos(r[2])]
  Rz = [cos(r[3]) -sin(r[3]) 0; sin(r[3]) cos(r[3]) 0; 0 0 1]

  R = Rz*Ry*Rx

  ax = 0.5+gridSizeOut[1]/2
  ay = 0.5+gridSizeOut[2]/2
  az = 0.5+gridSizeOut[3]/2

  bx = R[:,1]*diffSpacing[1]
  by = R[:,2]*diffSpacing[2]
  bz = R[:,3]*diffSpacing[3]

  cx = gridSizeOut[1]/2*diffSpacing[1]+0.5+offsetPixel[1]
  cy = gridSizeOut[2]/2*diffSpacing[2]+0.5+offsetPixel[2]
  cz = gridSizeOut[3]/2*diffSpacing[3]+0.5+offsetPixel[3]

  ix, iy, iz = params[:sliceX],params[:sliceY],params[:sliceZ]

  v = (iz-az) .* bz + (iy-ay) .* by - ax .* bx

  for d=1:3
    v[d] += bx[d].*ix
  end
  x,y,z = v[1]+cx, v[2]+cy, v[3]+cz

  @debug "" x y z

  if x>=1 && y >=1 && z>= 1 && x<= imSize[1] && y<= imSize[2] && z<= imSize[3]
    return (round(Int64,x),round(Int64,y),round(Int64,z))
  else
    return (0,0,0)
  end

end


text:
#Go mode

function after_go(b::Buffer)
    setmode(b, b.mode[2])
    after(b)
end
function go_join(b::Buffer)
    n = parse_n(b::Buffer)
    join_lines(b, y(b):y(b)+n, "")
    after(b)
    escape(b)
end
function gogo(b::Buffer)
    b.cursor.pos[1] = parse_n(b)
    after(b)
    escape(b)
end

go_actions = Dict('g' => gogo,
                  'G' => gobottom,
                  'J' => go_join,
                  '\e' => escape,
                 )
go_mode = Mode("go", go_actions)

#Macro modes

function set_record_register(c)
    cv = string(c)
    function set(b)
        b.state[:recording] = cv
        #This is a bad solution since it assumes all key presses are saved and never purged
        b.state[:macroindex] = string(length(b.state[:actions])+1)
        escape(b)
        b.state[:log] = "Recording to register $c"
    end
end

register_recordmode = Mode("register macro", Action(set_record_register, x->true))

function start_record(b::Buffer)
    if !in(:recording, keys(b.state)) || b.state[:recording] == "\e"
        setmode(b, register_recordmode)
    else
        b.registers[b.state[:recording][1]] = join(b.state[:actions][parse(b.state[:macroindex]):end-1])
        b.state[:log] = "Finished recording to register $(b.state[:recording])"
        b.state[:recording] = "\e"
    end
end

#Macros can't refer to other macros with this solution, this produces two copies of the previous macro
function replay_register(c)
    function replay_macro(b::Buffer)
        escape(b)
        n = parse_n(b)
        resize!(b.args,0) #It would be better to just remove the numbers, this might be useful in the future
        if in(c, keys(b.registers))
            replay(b, b.registers[c], n)
        else
            b.state[:log] = "No macro in register $c"
        end
    end
end

replay_mode = Mode("replay", Action(replay_register, x->true))

#Delete mode

function after_delete(b::Buffer)
    p1 = [parse(b.state[:ly]), parse(b.state[:lx])]
    p2 = pos(b)
    delete_between(b, p1, p2, b.state[:register][1])
    clear_arg(b)
    b.state[:register] = "\""
    escape(b)
end

function delete_lines(b::Buffer)
    #We need a yank here
    n = parse_n(b.args)
    delete_lines(b, y(b):y(b)+n-1)
    escape(b)
end

delete_extras = Dict( 'd' => delete_lines,
                      '\e' => escape,
                     )
delete_actions = merge(movements, delete_extras)
delete_mode = Mode("delete", delete_actions)

function after_yank(b::Buffer)
    p1 = [parse(b.state[:ly]), parse(b.state[:lx])]
    p2 = pos(b)
    yank_between(b, p1, p2, b.state[:register][1])
    b.cursor.pos .= p1
    clear_arg(b)
    b.state[:register] = "\""
    escape(b)
end

function yank_lines(b::Buffer, range::Range)
    reg = b.state[:register][1]
    range = clamp_range(range, 1, height(b))
    b.registers[reg] = string('\e', join(b.text[range], '\n'))
    #Line copies add an escape symbol before the text
end

function yank_lines(b::Buffer)
    n = parse_n(b.args)
    yank_lines(b, y(b):y(b)+n-1)
    escape(b)
end

yank_extras = Dict( 'y' => yank_lines,
                      '\e' => escape,
                     )
yank_actions = merge(movements, yank_extras)
yank_mode = Mode("yank", yank_actions)

#bug or not? it does not reset the state[:register] if a non-yank/paste operation
#is performed, but we can reset it in the after procedures, not sure if there's a difference
function set_clipboard_register(c)
    cv = string(c)
    function set(b)
        b.state[:register] = cv
        escape(b)
    end
end

register_clipboardmode = Mode("register", Action(set_clipboard_register, x->true))
#Find char modes

#This doesn't quite work as intended with delete, the sensible approach in vim is to remove the last
# character as well (dtc is used for exlucive delete until)
function after_find(b::Buffer)
    setmode(b, b.mode[2])
    after(b)
end

function find_action(c::Char)
    function find(b::Buffer)
        b.cursor.pos[2] = findsymbol(b::Buffer, c)
        after(b)
    end
end

find_mode = Mode("find", Action(find_action, x->true))

function replace_action(c)
    function replace(b::Buffer)
        if c=='\e'
            escape(b)
        elseif c=='\x7f'
            escape(b)
        elseif c=='\r'
            deleteat(b, pos(b), 1)
            splitp(b)
            escape(b)
        else
            setline(b, string(line(b)[1:x(b)-1], c, line(b)[x(b)+1:end]))  #Warning: Unicode might not work here
            escape(b)
        end
    end
end
replace_mode = Mode("replace", Action(replace_action, x->true))

ext: jl


text:
# === PRIVATE METHODS BELOW HERE =================================================================== #
function _build_vff_reaction_table(path_to_reaction_file::String)::DataFrame

    # vff: CSV format with record structure
    # name,[ec;...],reactant,product,reversible

    # initialize -
    id_array = String[]
    forward_reaction_string = String[]
    reverse_reaction_string = String[]
    reversibility_array = Bool[]
    ec_number_array = Union{Missing,String}[]
    lower_bound_array = Union{Missing,Float64}[]
    upper_bound_array = Union{Missing,Float64}[]

    # get file buffer (array of strings) -
    vff_file_buffer = read_file_from_path(path_to_reaction_file)

    # process -
    for (_, reaction_line) in enumerate(vff_file_buffer)

        # skip comments and empty lines -
        if (occursin("//", reaction_line) == false && isempty(reaction_line) == false)

            # split around ,
            reaction_record_components_array = split(reaction_line, ",")

            # process each of the components -

            # 1: id -
            push!(id_array, string(reaction_record_components_array[1]))

            # 2: ec numbers -
            ec_number_component = reaction_record_components_array[2]
            if (ec_number_component == "[]")
                push!(ec_number_array, missing)
            else
                push!(ec_number_array, string(ec_number_component[2:end - 1]))
            end

            # 3: L phrase -
            push!(forward_reaction_string, string(reaction_record_components_array[3]))

            # 4: R phrase -
            push!(reverse_reaction_string, string(reaction_record_components_array[4]))

            # 5: reverse -
            is_reversible = parse(Bool, string(reaction_record_components_array[5]))
            push!(reversibility_array, is_reversible)

            # lower bound and upper bound -
            if (is_reversible == true)
                push!(lower_bound_array, -Inf)
            else
                push!(lower_bound_array, 0.0)
            end
            push!(upper_bound_array, Inf)
        end
    end

    # build the df -
    df_metabolic_reactions = DataFrame(id=id_array, forward_reaction=forward_reaction_string, reverse_reaction=reverse_reaction_string, reversibility=reversibility_array,
        ec_number=ec_number_array, lower_bound=lower_bound_array, upper_bound=upper_bound_array)

    # return -
    return df_metabolic_reactions
end

function _build_json_reaction_table(path_to_reaction_file::String)::DataFrame
end

function _build_sbml_reaction_table(path_to_reaction_file::String)::DataFrame
end

# === PRIVATE METHODS ABOVE HERE =================================================================== #

# === PUBLIC METHODS BELOW HERE ==================================================================== #
function build_gene_table(path_to_gene_file::String;
    logger::Union{Nothing,SimpleLogger}=nothing)::Some

    try

        # initialize -
        local_data_row = Union{String,Symbol,Missing,FASTA.Record}[]

        # ok - lets load the gene file
        open(FASTA.Reader, path_to_gene_file) do reader
            for record in reader
                push!(local_data_row, record)
            end
        end

        # create a data frame -
        sequence_data_frame = DataFrame(id=String[], description=String[], gene_sequence=Union{Missing,BioSequences.LongSequence}[])
        sequence_data_record = Union{String,Missing,BioSequences.LongSequence}[]
        for record in local_data_row

            # get attributes from record -
            id_value = FASTX.FASTA.identifier(record)
            description_value = FASTX.FASTA.description(record)
            sequence_value = FASTX.FASTA.sequence(record)

            # pack -
            push!(sequence_data_record, id_value)
            push!(sequence_data_record, description_value)
            push!(sequence_data_record, sequence_value)
            push!(sequence_data_frame, tuple(sequence_data_record...))
        end

        # return -
        return Some(sequence_data_frame)
    catch error

        # get the original error message -
        error_message = sprint(showerror, error, catch_backtrace())
        vl_error_obj = ErrorException(error_message)

        # Package the error -
        return Some(vl_error_obj)
    end
end

function build_gene_table(gene_path_array::Array{String,1};
    logger::Union{Nothing,SimpleLogger}=nothing)

    try

        # initialize -
        gene_table_dictionary::Dict{String,DataFrame}()

         # ok, so let process the array of files -
        for file_path in gene_path_array
            sequence_data_frame = build_gene_table(file_path; logger=logger) |> check
            gene_table_dictionary[file_path] = sequence_data_frame
        end

        # return a dictionary of gene tables -
        return Some(gene_table_dictionary)
    catch error

        # get the original error message -
        error_message = sprint(showerror, error, catch_backtrace())
        vl_error_obj = ErrorException(error_message)

        # Package the error -
        return Some(vl_error_obj)
    end
end

function build_protein_table(path_to_protein_file::String;
    logger::Union{Nothing,SimpleLogger}=nothing)::Some

    try

        # initialize -
        local_data_row = Union{String,Symbol,Missing,FASTA.Record}[]

        # ok - lets load the gene file
        open(FASTA.Reader, path_to_protein_file) do reader
            for record in reader
                push!(local_data_row, record)
            end
        end

        # create a data frame -
        sequence_data_frame = DataFrame(id=String[], description=String[], protein_sequence=Union{Missing,BioSequences.LongSequence}[])
        for record in local_data_row

            # init a row -
            sequence_data_record = Union{String,Missing,BioSequences.LongSequence}[]

            # get attributes from record -
            id_value = FASTX.FASTA.identifier(record)
            description_value = FASTX.FASTA.description(record)
            sequence_value = FASTX.FASTA.sequence(record)

            # pack -
            push!(sequence_data_record, id_value)
            push!(sequence_data_record, description_value)
            push!(sequence_data_record, sequence_value)
            push!(sequence_data_frame, tuple(sequence_data_record...))
        end

        # return -
        return Some(sequence_data_frame)
    catch error

        # get the original error message -
        error_message = sprint(showerror, error, catch_backtrace())
        vl_error_obj = ErrorException(error_message)

        # Package the error -
        return Some(vl_error_obj)
    end
end

function build_protein_table(protein_path_array::Array{String,1};
    logger::Union{Nothing,SimpleLogger}=nothing)::Some

    try

        # initialize -
        protein_table_dictionary::Dict{String,DataFrame}()

        # ok, so let process the array of files -
        for file_path in protein_path_array
            sequence_data_frame = build_protein_table(file_path; logger=logger) |> check
            protein_table_dictionary[file_path] = sequence_data_frame
        end

        # return a dictionary of protein tables -
        return Some(protein_table_dictionary)
    catch error

        # get the original error message -
        error_message = sprint(showerror, error, catch_backtrace())
        vl_error_obj = ErrorException(error_message)

        # Package the error -
        return Some(vl_error_obj)
    end
end

function build_metabolic_reaction_table(path_to_reaction_file::String;
    logger::Union{Nothing,SimpleLogger}=nothing)::Some

    try

        # what is the set of extensions that we can parse?
        extension_set = Set{String}()
        push!(extension_set, ".vff")
        push!(extension_set, ".json")
        push!(extension_set, ".sbml")
        push!(extension_set, ".xml")

        # get the file name from the path -
        reaction_filename = basename(path_to_reaction_file)

        # do we support this extension?
        reaction_file_extension = string(last(splitext(reaction_filename)))
        if (in(reaction_file_extension, extension_set) == false)
            throw(ArgumentError("Reaction file extension not supported: $(reaction_file_extension)"))
        end

        # ok: if we get here then we support this extension -
        reaction_table = nothing
        if (reaction_file_extension == ".vff")
            reaction_table = _build_vff_reaction_table(path_to_reaction_file)
        elseif (reaction_file_extension == ".json")
            reaction_table = _build_json_reaction_table(path_to_reaction_file)
        elseif (reaction_file_extension == ".sbml" || reaction_file_extension == ".xml")
            reaction_table = _build_sbml_reaction_table(path_to_reaction_file)
        end

        # return -
        return Some(reaction_table)
    catch error

        # get the original error message -
        error_message = sprint(showerror, error, catch_backtrace())
        vl_error_obj = ErrorException(error_message)

        # Package the error -
        return Some(vl_error_obj)
    end
end

function write_system_model_file(path::String; kwargs...)::Some

    try

        # initialize -
        kwargs_dictionary = Dict(kwargs)
        system_dictionary = Dict{String,Any}()

        # package all the key=>value pairs into the system_dictionary -

        # pack stuff into the dictionary -
        system_dictionary["stoichiometric_matrix"] = stoichiometric_matrix
        system_dictionary["species_bounds_array"] = species_bounds_array
        system_dictionary["flux_bounds_array"] = flux_bounds_array
        system_dictionary["reaction_table"] = reaction_table
        system_dictionary["objective_coefficient_array"] = objective_coefficient_array
        system_dictionary["is_minimum_flag"] = true

        # write -
        bson(path, system=system_dictionary)

        # return -
        return Some(nothing)
    catch error

        # get the original error message -
        error_message = sprint(showerror, error, catch_backtrace())
        vl_error_obj = ErrorException(error_message)

        # Package the error -
        return Some(vl_error_obj)
    end
end
# === PUBLIC METHODS ABOVE HERE ==================================================================== #


text:
struct ConvergenceState
   obj::Float64
   ub::Float64
   lb::Float64
   int_abs::Float64
   int_rel::Float64
   rlx_abs::Float64
   rlx_rel::Float64
   time::Float64
   iter::Int
   num_frac::Int
   function ConvergenceState(obj::Float64, ub::Float64, lb::Float64, int_abs::Float64, int_rel::Float64,
                             rlx_abs::Float64, rlx_rel::Float64, time::Float64, iter::Int, num_frac::Int)
      return new(obj, ub, lb, int_abs, int_rel, rlx_abs, rlx_rel, time, iter, num_frac)
   end
   function ConvergenceState(obj::Float64, ub::Float64, lb::Float64, time::Float64, iter::Int, num_frac::Int)
      return new(obj, ub, lb, ub-lb, (ub-lb)/abs(lb), obj-lb, (obj-lb)/abs(lb), time, iter, num_frac)
   end
end

mutable struct Termination
   abstol::Float64
   reltol::Float64
   rlx_abstol::Float64
   rlx_reltol::Float64
   time_limit::Float64
   max_iter::Int
   inttol::Float64
   allow_frac::Symbol

   """
   Termination(;abstol::Float64=10^-10,
               reltol::Float64=10^-10,
               rlx_abstol::Float64=10^-10,
               rlx_reltol::Float64=10^-10,
               time_limit::Float64=Inf,
               max_iter::Int=2147483647,
               inttol::Float64=10^-9,
               allow_frac::Symbol=:binary_solve)

   Define the stopping conditions for `JuDGE.solve()` / `JuDGE.branch_and_price()`.

   ### Optional Arguments
   `abstol` is the absolute tolerance for the best integer-feasible objective value and the lower bound.

   `reltol` is the relative tolerance for the best integer-feasible objective value and the lower bound.

   `rlx_abstol` is the absolute tolerance for the relaxed master objective value and the lower bound.

   `rlx_reltol` is the relative tolerance for the relaxed master objective value and the lower bound.

   `time_limit` is the maximum duration in seconds.

   `max_iter` is the maximum number of iterations.

   `inttol` is the maximum deviation from 0 or 1 for any binary/integer variable for integer feasible solutions.

   `allow_frac` indicates whether a fractional solution will be returned; possible values are:
   	`:binary_solve` a binary solve of master will be performed (if needed) prior to the solution being returned;
   	`:binary_solve_return_relaxation` a binary solve of master will be performed (if needed), updating the upper bound,
   	but the master problem relation will be returned;
   	`:first_fractional` will return the first fractional master solution found;
   	`:no_binary_solve` will simply return the solution to the relaxed master problem when terminated.

   ### Examples
      Termination(rlx_abstol=10^-6)
      Termination(abstol=10^-3,inttol=10^-6)
   """
   function Termination(;abstol::Float64=10^-10,reltol::Float64=10^-10,rlx_abstol::Float64=10^-10,
                        rlx_reltol::Float64=10^-10,time_limit::Float64=Inf,max_iter::Int=2147483647,
                        inttol::Float64=10^-9,allow_frac::Symbol=:binary_solve)
      if allow_frac ∉ [:binary_solve,:binary_solve_return_relaxation,:first_fractional,:no_binary_solve]
         error("'allow_frac' can take values: :binary_solve, :binary_solve_return_relaxation, :first_fractional or :no_binary_solve")
      end
      return new(abstol, reltol, rlx_abstol, rlx_reltol, time_limit, max_iter, inttol, allow_frac)
   end
end

function display(cs::ConvergenceState;relaxation::Bool=true)
   print("")
   if cs.obj==Inf
      print("          ")
   elseif cs.obj>=0
      print(" ")
   end
   Printf.@printf(" %e  | ",cs.obj)

   if cs.ub==Inf
      print("          ")
   elseif cs.ub>=0
      print(" ")
   end
   Printf.@printf("%e ",cs.ub)

   if cs.lb==-Inf
      print("         ")
   elseif cs.lb>=0
      print(" ")
   end
   Printf.@printf("%e  |  ",cs.lb)

   if relaxation
      temp1=cs.rlx_abs
      temp2=cs.rlx_rel
   else
      temp1=cs.int_abs
      temp2=cs.int_rel
   end

   if temp1==Inf
      print("          ")
   elseif temp1>=0
      print(" ")
   end
   Printf.@printf("%e   ",temp1)

   if temp2==Inf || isnan(temp2)
      print("          ")
   elseif temp2>=0
      print(" ")
   end
   Printf.@printf("%e  |   ",temp2)

   Printf.@printf("%9d  | %9.3f  %7d",cs.num_frac,cs.time,cs.iter)
   if relaxation
      println("")
   else
      println("*")
   end
end

function InitialConvergenceState()
   ConvergenceState(Inf,Inf,-Inf,Inf,Inf,Inf,Inf,0.0,0,0)
end

function has_converged(b::Termination, a::ConvergenceState)
   if a.int_abs <= b.abstol || a.int_rel <= b.reltol || a.rlx_abs <= b.rlx_abstol || a.rlx_rel <= b.rlx_reltol || a.time > b.time_limit || a.iter >= b.max_iter
      true
   else
      false
   end
end


text:
function eraseFile(filename::String)

    Base.Filesystem.rm(filename)

    # if is_unix()
    #
    #     run(`rm $filename`)
    #
    # elseif is_windows()
    #
    # end
end


text:
__precompile__()

"""
HTSEngineAPI is a wrapper of hts_engine_API that provides speech waveform
synthesis from Hidden Markov Models (HMMs) trained by the HMM-based
speech synthesis system (HTS).
"""
module HTSEngineAPI

export
    @htscall, # e.g. @htscall(:HTS_Engine_clear, Void, (Ptr{HTS_Engine},), &engine)

    # Internal types
    HTS_Audio,
    HTS_Window,
    HTS_Pattern,
    HTS_Question,
    HTS_Node,
    HTS_Tree,
    HTS_Model,
    HTS_ModelSet,
    HTS_LabelString,
    HTS_Label,
    HTS_SStream,
    HTS_SStreamSet,
    HTS_SMatrices,
    HTS_PStream,
    HTS_PStreamSet,
    HTS_GStream,
    HTS_GStreamSet,
    HTS_Condition,

    # The speech synthesis engine
    HTS_Engine,

    initialize,
    load,
    refresh,
    clear,

    # Set/Get parameters of HTS engine
    set_sampling_frequency,
    get_sampling_frequency,
    set_fperiod,
    get_fperiod,
    set_audio_buff_size,
    get_audio_buff_size,
    set_stop_flag,
    get_stop_flag,
    set_volume,
    get_volume,
    set_msd_threshold,
    get_msd_threshold,
    set_gv_weight,
    get_gv_weight,
    set_speed,
    set_phoneme_alignment_flag,
    set_alpha,
    get_alpha,
    set_beta,
    get_beta,
    add_half_tone,
    set_duration_interpolation_weight,
    get_duration_interpolation_weight,
    set_parameter_interpolation_weight,
    get_parameter_interpolation_weight,
    set_gv_interpolation_weight,
    get_gv_interpolation_weight,

    get_total_state,
    get_state_duration,
    get_nvoices,
    get_nstream,
    get_nstate,
    get_fullcontext_label_format,
    get_fullcontext_label_version,
    get_total_frame,
    get_nsamples,

    get_generated_parameter,
    get_generated_speech,

    # Synthesis
    synthesize_from_fn,
    synthesize_from_strings,

    # Save
    save_information,
    save_label,
    save_generated_parameter,
    save_generated_speech,
    save_riff

using BinDeps

# Load dependency
deps = joinpath(Pkg.dir("HTSEngineAPI"), "deps", "deps.jl")
if isfile(deps)
    include(deps)
else
    error("HTSEngineAPI not properly installed. Please run Pkg.build(\"HTSEngineAPI\")")
end

for fname in [
              "macros",
              "internals",
              "htsengine"
              ]
    include(string(fname, ".jl"))
end

end # module HTSEngineAPI


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

mutable struct IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus <: SwaggerModel
    acceptedNames::Any # spec type: Union{ Nothing, IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionNames } # spec name: acceptedNames
    conditions::Any # spec type: Union{ Nothing, Vector{IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionCondition} } # spec name: conditions
    storedVersions::Any # spec type: Union{ Nothing, Vector{String} } # spec name: storedVersions

    function IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus(;acceptedNames=nothing, conditions=nothing, storedVersions=nothing)
        o = new()
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus, Symbol("acceptedNames"), acceptedNames)
        setfield!(o, Symbol("acceptedNames"), acceptedNames)
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus, Symbol("conditions"), conditions)
        setfield!(o, Symbol("conditions"), conditions)
        validate_property(IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus, Symbol("storedVersions"), storedVersions)
        setfield!(o, Symbol("storedVersions"), storedVersions)
        o
    end
end # type IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus

const _property_map_IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus = Dict{Symbol,Symbol}(Symbol("acceptedNames")=>Symbol("acceptedNames"), Symbol("conditions")=>Symbol("conditions"), Symbol("storedVersions")=>Symbol("storedVersions"))
const _property_types_IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus = Dict{Symbol,String}(Symbol("acceptedNames")=>"IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionNames", Symbol("conditions")=>"Vector{IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionCondition}", Symbol("storedVersions")=>"Vector{String}")
Base.propertynames(::Type{ IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus }) = collect(keys(_property_map_IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus))
Swagger.property_type(::Type{ IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus }, name::Symbol) = Union{Nothing,eval(Meta.parse(_property_types_IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus[name]))}
Swagger.field_name(::Type{ IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus }, property_name::Symbol) =  _property_map_IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus[property_name]

function check_required(o::IoK8sApiextensionsApiserverPkgApisApiextensionsV1beta1CustomResourceDefinitionStatus)
    (getproperty(o, Symbol("acceptedNames")) === nothing) && (return false)
    (getproperty(o, Symbol("conditions")) === nothing) && (return false)
    (getproperty(o, Symbol("storedVersions")) === nothing) && (return false)
    true
end

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


text:
include("test_utilities.jl")
include("../src/iterative_bi_lanczos.jl")

@testset begin

    function Test1(n=5)
        @info "Testing Basics"
        A = rand(n, n)
        ibl = IterativeBiLanczos(A)
        V, W, T = ibl(n - 1)
        println("These are: V, W, T")
        display(V)
        display(W)
        display(T)
        println("Orthogonality between W,V is: ")
        display(W'*V)
        orthogonalError = norm(W'*V - I, Inf)
        println("Testing Factorizations W'*A*V ≈ T")
        factorization = W'*A*V
        display(factorization)
        factError = norm(factorization - T, Inf)
        if orthogonalError > 1e-10
            @warn "The orthogonalization error for bi-lanczos is: $(orthogonalError), which is kinda big, please
            check your code."

        elseif factError > 1e-10
            @warn "The factorizations error is $(factError), which is big, check your code. "
        end
        return factError < 1e-10 && orthogonalError < 1e-10
    end

    @info "Testing basics of Bi-Lanczos on a 5 by 5 real matrix with float64"
    @test Test1()

end


text:
using ArgParse
# using LinearAlgebra

s = ArgParseSettings()
@add_arg_table s begin
    "--part2"
    help = "Do part 2"
    action = :store_true
    "--test"
    help = "Run test data"
    action = :store_true
end

mutable struct InfiniteImage
    set::Set{Tuple{Int, Int}}
    minx::Int
    maxx::Int
    miny::Int
    maxy::Int
    outside::Bool
end

InfiniteImage() = InfiniteImage(Set(), 0, 0, 0,0, false)

function set!(image::InfiniteImage, x::Int, y::Int)
    if isempty(image.set)
        image.minx = image.maxx = x
        image.miny = image.maxy = y
    end
    sz = length(image.set)
    push!(image.set, (x, y))
    tz = length(image.set)
    if tz != sz +1
        println("Added $x, $y to no effect")
    end
    image.minx = min(x, image.minx)
    image.miny = min(y, image.miny)
    image.maxx = max(x, image.maxx)
    image.maxy = max(y, image.maxy)
end

function isset(i::InfiniteImage, x::Int, y::Int)
    if x >= i.minx && x <= i.maxx && y >= i.miny && y<=i.maxy
        (x, y) ∈ i.set
    else
        i.outside
    end
end

function size(image::InfiniteImage)
    return length(image.set)
end

parsed_args = parse_args(ARGS, s)
test_suffix = parsed_args["test"] ? "_test" : ""
initial_image = InfiniteImage()
input = readlines("input/day_20$test_suffix.txt")
lookup = [c == '#' for c in input[1]]

for (y, l) in enumerate(input[3:end])
    for (x, c) in enumerate(l)
        if c=='#'
            set!(initial_image, x, y)
        end
    end
end

function Base.show(io::IO, i::InfiniteImage)
    println(io, "($(i.minx), $(i.miny))x($(i.maxx),$(i.maxy)) : $(size(i)) pixels set")
    for y in i.miny:i.maxy
        l :: Vector{Char} = []
        for x in i.minx:i.maxx
            push!(l, isset(i, x, y) ? '#' : '.')
        end
        println(io,String(l))
    end
end

function evolve_image(image::InfiniteImage) :: InfiniteImage
    evolved = InfiniteImage()
    sub = [(-1, -1), (0, -1), (1, -1), (-1, 0), (0, 0), (1, 0), (-1, 1), (0, 1), (1, 1)]
    for y in (image.miny - 1):(image.maxy + 1)
        for x in (image.minx - 1):(image.maxx + 1)
            function setbit(acc, off) :: Int
                (acc << 1) | (isset(image, x + off[1], y + off[2]) ? 1 : 0)
            end
            idx = reduce(setbit, sub; init = 0)
            if lookup[idx + 1]
                set!(evolved, x, y)
            end
        end
    end
    evolved.outside = lookup[1] ? !image.outside : false
    evolved
end

function part1()
    ev = evolve_image(initial_image)
    ev = evolve_image(ev)
    size(ev)
end

function part2()
    ev = initial_image
    for i in 1:50
        ev = evolve_image(ev)
    end
    size(ev)
end

p = parsed_args["part2"] ? part2 : part1
answer = p()
println("The answer is: $answer")


text:
#=
MIT License

Copyright (c) 2022 Rafael Dias

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=#
println("Quantos m3 precisa:")
metros_cubicos_concreto = parse(Float32, readline())
println("Especificação do cimento")
println("Composto: I, II, III, IV, V:")
cimento_composto = readline()
println("Adição: S, E, Z, F, ARI, B, P, RS, BP:")
cimento_adicao = readline()
println("Classe de resistência: 25, 32, 40:")
cimento_resistencia = parse(Int, readline())
cimento_tipo = "CP$(cimento_composto)-$(cimento_adicao) $(cimento_resistencia)"
println("Peso específico do cimento (kg/m3): ")
cimento_gama = parse(Float32, readline())       # kg/m3

println("Especificação da areia")
println("Módulo de finura: ")
areia_mod_finura = parse(Float32, readline()) #2.4
println("Peso específico da areia (kg/m3): ")
areia_gama = parse(Float32, readline()) #2650.0         # kg/m3
println("Massa unitária da areia (kg/m3): ")
areia_massa_unit = parse(Float32, readline()) #1450.0   # kg/m3

println("Especificação da brita")
println("Peso específico da brita (kg/m3): ")
brita_gama = parse(Float32, readline()) #2750.0         # kg/m3
println("Massa unitária da brita (kg/m3): ")
brita_massa_unit = parse(Float32, readline()) #1550.0   # kg/m3
println("Diâmetro máximo da brita (mm): ")
brita_diametro_max = parse(Float32, readline()) #19.0   # mm
#=
proporcao_britas
proporcao_britas = B0B1
proporcao_britas = B1B2
proporcao_britas = B2B3
proporcao_britas = B3B4
=#
println("Proporção de brita: B0B1, B1B2, B2B3, B3B4:")
proporcao_britas = readline() #"B0B1"
if proporcao_britas == "B0B1"
    brita_ba = 0.3
    brita_bb = 0.7
elseif proporcao_britas == "B1B2"
    brita_ba = 0.5
    brita_bb = 0.5
elseif proporcao_britas == "B2B3"
    brita_ba = 0.5
    brita_bb = 0.5
else
    proporcao_britas == "B3B4"
    brita_ba = 0.5
    brita_bb = 0.5
end

println("Especificação do concreto")
println("fck do concreto (MPa):")
concreto_fck = parse(Float32, readline()) #20  # MPa
println("Abatimento do concreto (mm):")
concreto_abatimento = parse(Float32, readline()) #100.0  # mm
println("Tolerância do abatimento (mm):")
concreto_abat_toler = parse(Float32, readline()) #10.0  # (+/-)mm
# desvio padrão depende do controle de qualidade na execução do concreto
# 4.0 5.5 7.0
println("Desvio padrão (preparação): 4, 5.5, 7")
concreto_sd = parse(Float32, readline()) #7.0
concreto_fcj = concreto_fck + (1.645 * concreto_sd)   # MPa
# 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90
println("Classe de resistência do concreto: 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90:")
concreto_classe_resistencia = parse(Float32, readline()) #20

println("Tipo de agregado graúdo:")
println("1 para basalto e diabásio")
println("2 para granito e gnaisse")
println("3 para calcário")
println("4 para arenito")
opcao_agregado = parse(Int, readline()) #2
if opcao_agregado == 1
    global concreto_alfa_E = 1.2
    global descricao_agregado = "Basalto e Diabásio"
elseif opcao_agregado == 2
    global concreto_alfa_E = 1.0
    global descricao_agregado = "Granito e Gnaisse"
elseif opcao_agregado == 3
    global concreto_alfa_E = 0.9
    global descricao_agregado = "Calcário"
elseif opcao_agregado == 4
    global concreto_alfa_E = 0.7
    global descricao_agregado = "Arenito"
end

if concreto_classe_resistencia < 55
    global concreto_Eci = concreto_alfa_E * (5600.0 * sqrt(concreto_fck)) / 1000.0   # GPa
else
    global concreto_Eci = (21.5e3 * concreto_alfa_E * ((concreto_fck / 10.0) + 1.25)^(1.0 / 3.0)) / 1000.0   # GPa
end

# Consultar curva de Abrams e encontrar relação A/C dado o fcm do concreto
println("     ***************** ATENÇÃO ***************************")
println("     Encontrar na tabela a relação A/C (curva de Abrams) \n\r     para fcj=$(concreto_fcj) MPa:")
println("     *****************************************************")
concreto_rel_ac = parse(Float32, readline()) #0.51

# Consultar tabela para consumo de água
println("     ***************** ATENÇÃO ***************************")
println("     Encontrar na tabela o consumo de água (l):")
println("     *****************************************************")
consumo_agua = parse(Float32, readline()) #205.0                                # l
consumo_cimento = consumo_agua / concreto_rel_ac    # kg/m3
consumo_agregado_graudo = 0.69 * brita_massa_unit  # kg/m3
consumo_agr_b1 = consumo_agregado_graudo * brita_ba # kg/m3
consumo_agr_b2 = consumo_agregado_graudo * brita_bb # kg/m3
volume_areia = 1.0 - ((consumo_cimento / cimento_gama) + (consumo_agregado_graudo / brita_gama) + (consumo_agua / 1000.0))   # m3
consumo_areia = volume_areia * areia_gama

# Apresentação do traço
_c = consumo_cimento / consumo_cimento
_a = consumo_areia / consumo_cimento
_b1 = consumo_agr_b1 / consumo_cimento
_b2 = consumo_agr_b2 / consumo_cimento
_ac = consumo_agua / consumo_cimento

Cmd(`clear`)
println("\n\n")
println("     *****************************************************")
println("     *                                                   *")
if isapprox(_b2, 0.0)
    println("     *    TRAÇO: $(round(_c, digits=3)) : $(round(_a, digits=3)) : $(round(_b1, digits=3)) : $(round(_ac, digits=3))")
else
    println("     *    TRAÇO: $(round(_c, digits=3)) : $(round(_a, digits=3)) : $(round(_b1, digits=3)) : $(round(_b2, digits=3)) : $(round(_ac, digits=3))")
end
println("     *                                                   *")
println("     *****************************************************")
println("\n\n====================== RESUMO por 1m3 ========================")
println("Consumo cimento (kg):\t\t$(round(consumo_cimento ,digits=1)) --> $(round(consumo_cimento / 50.0,digits=1, )) sacos de 50kg")
println("Consumo areia (kg):\t\t$(round(consumo_areia ,digits=1))")
println("Consumo brita $(SubString(proporcao_britas, 1, 2)) (kg):\t\t$(round(consumo_agr_b1 ,digits=1))")
println("Consumo brita $(SubString(proporcao_britas, 3, 4)) (kg):\t\t$(round(consumo_agr_b2 ,digits=1))")
println("Consumo água (l):\t\t$(round(consumo_agua ,digits=1)) --> $(round(consumo_agua / 20, digits=1)) latas de 20l")

quantidade = metros_cubicos_concreto
consumo_cimento *= quantidade
consumo_areia *= quantidade
consumo_agr_b1 *= quantidade
consumo_agr_b2 *= quantidade
consumo_agua *= quantidade
println("\n\n====================== RESUMO para $(quantidade)m3 ========================")
println("Consumo cimento (kg):\t\t$(round(consumo_cimento ,digits=1)) --> $(round(consumo_cimento / 50.0,digits=1)) sacos de 50kg")
println("Consumo areia (kg):\t\t$(round(consumo_areia ,digits=1))")
println("Consumo brita $(SubString(proporcao_britas, 1, 2)) (kg):\t\t$(round(consumo_agr_b1 ,digits=1))")
println("Consumo brita $(SubString(proporcao_britas, 3, 4)) (kg):\t\t$(round(consumo_agr_b2 ,digits=1))")
println("Consumo água (l):\t\t$(round(consumo_agua ,digits=1)) --> $(round(consumo_agua / 20, digits=1)) latas de 20l")
println("\n")
println("================== Propriedades do Concreto ==================")
println("Cimento:\t\t\t$(cimento_tipo)")
println("Classe de Resistência:\t\tC$(concreto_classe_resistencia)")
println("Desvio Padrão (MPa):\t\t$(concreto_sd)")
println("Agregado Graúdo:\t\t$(descricao_agregado)")
println("fck (MPa):\t\t\t$(round(concreto_fck ,digits=1))")
println("fcj (MPa):\t\t\t$(round(concreto_fcj ,digits=1))")
println("Eci (GPa):\t\t\t$(round(concreto_Eci ,digits=1))")
println("Abatimento (mm):\t\t$(round(concreto_abatimento ,digits=1)) +/- $(round(concreto_abat_toler ,digits=1))")
println("\n\n")

max_stars_repo_name: rsd-consultorias/scripts-engenharia

max_issues_repo_name: rsd-consultorias/scripts-engenharia

max_forks_repo_name: rsd-consultorias/scripts-engenharia


text:
using KernelBenchmarks
using Test

using Cassette
using SIMD
import ProgressMeter

# Setup a Cassette Context that records `vload` and `vstore` options.
Cassette.@context TraceCtx

function Cassette.overdub(ctx::TraceCtx, ::typeof(SIMD.vload), x...)
    push!(ctx.metadata.loads, x)
    return SIMD.vload(x...)
end

function Cassette.overdub(ctx::TraceCtx, ::typeof(SIMD.vstore), x...)
    push!(ctx.metadata.stores, x)
    return SIMD.vstore(x...)
end

struct TraceMeta
    loads::Vector{Any}
    stores::Vector{Any}
end
TraceMeta() = TraceMeta(Any[], Any[])

function pointercheck(pointers, vectype, unroll, iter, A)
    @nospecialize

    # Are all pointers unique?
    @test allunique(pointers)

    # Are they grouped by the unroll amount?
    for group in Iterators.partition(pointers, unroll)
        @test all(isequal(sizeof(vectype)), diff(group))
    end

    # If the iterator is Sequential, then the pointers should be sorted.
    # Otherwise, they shouldn't be sorted.
    if iter == KernelBenchmarks.Sequential
        @test issorted(pointers)
    elseif iter == KernelBenchmarks.PseudoRandom
        @test !issorted(pointers)
    # Throw an error to try to keep this test from breaking.
    else
        error()
    end

    # Generate all of the addresses we'd expect to write.
    base = convert(Int, pointer(A))
    len = div(sizeof(A), sizeof(vectype))
    expected = [base + sizeof(vectype) * (i-1) for i in 1:len]
    @test sort(pointers) == expected
end

#####
##### Test Set
#####

@testset "KernelBenchmarks.jl" begin
    # Test over a very large range of parameters.
    # I'm sorry Julia compiler :(

    # Allocate a decent size array to serve as our test bed.
    A = rand(Float32, 2^11)
    B = rand(Float64, 2^10)

    # Setup iteration space
    kernels = [ReadOnly, WriteOnly, ReadWrite]
    loadtypes = [Standard, Nontemporal]
    storetypes = [Standard, Nontemporal]
    iterators = [Sequential, PseudoRandom]
    eltypes = [Float32, Float64]
    widths = [1,2,4,8,16]
    unroll = [1,2,4,8]

    iter = Iterators.product(
        kernels,
        loadtypes,
        storetypes,
        iterators,
        eltypes,
        widths,
        unroll
    )

    ProgressMeter.@showprogress 1 "Testing ... " for tup in iter
        # unpack tuple
        kernel      = tup[1]
        loadtype    = tup[2]
        storetype   = tup[3]
        iterator    = tup[4]
        eltype      = tup[5]
        vectorsize  = tup[6]
        unroll      = tup[7]

        # Invalid combination
        eltype == Float64 && unroll == 16 && continue

        kp = KernelBenchmarks.KernelParam(
            kernel = kernel,
            loadtype = loadtype,
            storetype = storetype,
            iterator = iterator,
            eltype = eltype,
            vectorsize = vectorsize,
            unroll = unroll,
        )

        V = eltype == Float32 ? A : B

        # Get a record of all the stores
        # Disable pre/post hooks to try to get faster compile times.
        ctx = Cassette.disablehooks(TraceCtx(metadata = TraceMeta()))
        Cassette.overdub(ctx, KernelBenchmarks.execute!, V, kp)
        trace = ctx.metadata

        ### Setup
        vectype = Vec{vectorsize,eltype}
        loads = trace.loads
        stores = trace.stores

        if kernel == ReadOnly
            @test isempty(stores)
        elseif kernel == WriteOnly
            @test isempty(loads)
        elseif kernel == ReadWrite
            @test length(stores) == length(loads)
        end

        # Check load type
        if in(kernel, (ReadOnly, ReadWrite))
            # Are all the loads the correct vector type
            @test all(isequal(vectype), getindex.(loads, 1))

            # All loads should be aligned
            @test all(isequal(Val(true)), getindex.(loads, 3))

            # Test for standard/nontemporal stores
            if loadtype == KernelBenchmarks.Standard
                @test all(isequal(Val(false)), getindex.(loads, 4))
            else
                @test all(isequal(Val(true)), getindex.(loads, 4))
            end

            # Pointer Check
            pointers = convert.(Int, getindex.(loads, 2))
            pointercheck(pointers, vectype, unroll, iterator, V)
        end

        if in(kernel, (WriteOnly, ReadWrite))
            # Are all the stores the correct vector type
            @test all(isequal(vectype), typeof.(getindex.(stores, 1)))

            # All stores should be aligned
            @test all(isequal(Val(true)), getindex.(stores, 3))

            # Test for standard/nontemporal stores
            if storetype == KernelBenchmarks.Standard
                @test all(isequal(Val(false)), getindex.(stores, 4))
            else
                @test all(isequal(Val(true)), getindex.(stores, 4))
            end

            # Pointer Check
            pointers = convert.(Int, getindex.(stores, 2))
            pointercheck(pointers, vectype, unroll, iterator, V)
        end
    end
end

@testset "Testing Coverage" begin
    for unroll in (1,2,4,8)
        A = ones(Float32, 2^10)
        KernelBenchmarks.random_write(A, Val(8), Val(false), Val(true), Val(unroll))
        @test all(isone, A)
    end

    for unroll in (1,2,4,8)
        A = zeros(Float32, 2^10)
        KernelBenchmarks.random_readwrite(A, Val(8), Val(false), Val(true), Val(unroll))
        @test all(isone, A)
    end
end


text:
# Port of possible implementation of std::merge (second version),
# https://en.cppreference.com/w/cpp/algorithm/merge
# TODO: contribute to base.

"""
    mergesorted!(dest::AbstractVector, a, b; by=identity, lt=isless)

Merge sorted iterators `a` and `b`, storing the result in `dest`.
`dest` should be of the appropriate length to store all elements of `a` and `b`;
it is not resized.

For equivalent elements in `a` and `b`, the elements from `a`
(preserving their original order) precede the elements from `b`
(preserving their original order).

Elements are compared by `(x, y) -> lt(by(x), by(y))`

The behavior is undefined if `dest` overlaps `a` or `b` (though the `a` and `b`
may overlap each other) or if `a` or `b` are not sorted.

Adapted from https://en.cppreference.com/w/cpp/algorithm/merge.
"""
@inline function mergesorted!(dest::AbstractVector, a, b; by=identity, lt=isless)
    i = 1
    it_a = iterate(a)
    it_b = iterate(b)
    while it_a !== nothing
        val_a, state_a = it_a
        if it_b === nothing
            dest[i] = val_a
            i += 1
            copyto!(dest, i, Iterators.rest(a, state_a))
            return dest
        end
        val_b, state_b = it_b
        if lt(by(val_b), by(val_a))
            dest[i] = val_b
            it_b = iterate(b, state_b)
        else
            dest[i] = val_a
            it_a = iterate(a, state_a)
        end
        i += 1
    end
    if it_b !== nothing
        val_b, state_b = it_b
        dest[i] = val_b
        i += 1
        copyto!(dest, i, Iterators.rest(b, state_b))
    end
    return dest
end

# from https://github.com/JuliaOpt/MathOptInterface.jl/blob/d3106f434293a2aae7c664a22a30a7bd4069111a/src/Utilities/functions.jl#L390.
# TODO: contribute to Base
function combine!(x::AbstractVector; by=identity, keep=x->true, combine)
    @boundscheck issorted(x; by=by) || throw(ArgumentError("Input is not sorted."))
    if length(x) > 0
        i1 = firstindex(x)
        for i2 in eachindex(x)[2:end]
            if by(x[i1]) == by(x[i2])
                x[i1] = combine(x[i1], x[i2])
            else
                if !keep(x[i1])
                    x[i1] = x[i2]
                else
                    x[i1 + 1] = x[i2]
                    i1 += 1
                end
            end
        end
        if !keep(x[i1])
            i1 -= 1
        end
        resize!(x, i1)
    end
    return x
end


text:
using Test

@testset "Corpora" begin

    include("../src/Corpora.jl")
    wiki_path = "../corpora/simplewikiselect"
    nyt_path = "../corpora/nytselect"

    @testset "Corpus constructor" begin
        global c = Corpora.Corpus(wiki_path)
        @test c.corpus_path == abspath("$wiki_path.txt")
        @test c.meta_path == abspath("../corpora/simplewikiselect.meta.json")
    end

    @testset "Document retrival" begin
        target = 11
        line = ""
        open(c.corpus_path) do f
            for i in 1:target
                line = readline(f)
            end
        end
        @test line == Corpora.get_text(c, target)

        open(c.corpus_path) do f
            @test line == Corpora.get_text(f, c, target)
        end

        indices = [15, 100, 789]
        texts = [Corpora.get_text(c, idx) for idx in indices]
        @test texts == Corpora.get_texts(c, indices)
    end

    if isfile("$nyt_path.txt")
        @testset "NYT corpus" begin
            nyt = Corpora.Corpus(nyt_path)
            target = 101
            line = ""
            open(nyt.corpus_path) do f
                for i in 1:target
                    line = readline(f)
                end
            end
            @test line == Corpora.get_text(nyt, target)
        end
    end

end


text:
function extrap_prep{N,d}(::Type{Throw}, ::Val{N}, ::Val{d})
    xsym = Symbol("xs_", d)
    :(lbound(etp, $d) <= $xsym <= ubound(etp, $d) || throw(BoundsError()))
end

function extrap_prep{N,d}(::Type{Throw}, ::Val{N}, ::Val{d}, ::Val{:lo})
    xsym = Symbol("xs_", d)
    :(lbound(etp, $d) <= $xsym || throw(BoundsError()))
end

function extrap_prep{N,d}(::Type{Throw}, ::Val{N}, ::Val{d}, ::Val{:hi})
    xsym = Symbol("xs_", d)
    :($xsym <= ubound(etp, $d) || throw(BoundsError()))
end


text:
###
# Authors: Daniel Thuerck
# NEC Laboratories Europe GmbH, Copyright (c) 2021, All rights reserved.
#
# THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
#
# SOFTWARE LICENSE AGREEMENT
# ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY
# BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS
# OF THIS LICENSE AGREEMENT. IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY
# NOT USE OR DOWNLOAD THE SOFTWARE.
#
# This is a license agreement ("Agreement") between your academic institution or non-profit
# organization or self (called "Licensee" or "You" in this Agreement) and NEC Laboratories Europe
# GmbH (called "Licensor" in this Agreement). All rights not specifically granted to you in this
# Agreement are reserved for Licensor.
#
# RESERVATION OF OWNERSHIP AND GRANT OF LICENSE: Licensor retains exclusive
# ownership of any copy of the Software (as defined below) licensed under this Agreement and hereby
# grants to Licensee a personal, non-exclusive, non-transferable license to use the Software for
# noncommercial research purposes, without the right to sublicense, pursuant to the terms and
# conditions of this Agreement. NO EXPRESS OR IMPLIED LICENSES TO ANY OF LICENSOR’S
# PATENT RIGHTS ARE GRANTED BY THIS LICENSE. As used in this Agreement, the term
# "Software" means (i) the actual copy of all or any portion of code for program routines made
# accessible to Licensee by Licensor pursuant to this Agreement, inclusive of backups, updates, and/or
# merged copies permitted hereunder or subsequently supplied by Licensor, including all or any file
# structures, programming instructions, user interfaces and screen formats and sequences as well as any
# and all documentation and instructions related to it, and (ii) all or any derivatives and/or modifications
# created or made by You to any of the items specified in (i).
#
# CONFIDENTIALITY/PUBLICATIONS: Licensee acknowledges that the Software is proprietary to
# Licensor, and as such, Licensee agrees to receive all such materials and to use the Software only in
# accordance with the terms of this Agreement. Licensee agrees to use reasonable effort to protect the
# Software from unauthorized use, reproduction, distribution, or publication. All publication materials
# mentioning features or use of this software must explicitly include an acknowledgement the software
# was developed by NEC Laboratories Europe GmbH.
#
# COPYRIGHT: The Software is owned by Licensor.
#
# PERMITTED USES: The Software may be used for your own noncommercial internal research
# purposes. You understand and agree that Licensor is not obligated to implement any suggestionsand/or
# feedback you might provide regarding the Software, but to the extent Licensor does so, you are
# not entitled to any compensation related thereto.
#
# DERIVATIVES: You may create derivatives of or make modifications to the Software, however, You
# agree that all and any such derivatives and modifications will be owned by Licensor and become a part
# of the Software licensed to You under this Agreement. You may only use such derivatives and
# modifications for your own noncommercial internal research purposes, and you may not otherwise
# use, distribute or copy such derivatives and modifications in violation of this Agreement.
#
# BACKUPS: If Licensee is an organization, it may make that number of copies of the Software
# necessary for internal noncommercial use at a single site within its organization provided that all
# information appearing in or on the original labels, including the copyright and trademark notices are
# copied onto the labels of the copies.
#
# USES NOT PERMITTED: You may not distribute, copy or use the Software except as explicitly
# permitted herein. Licensee has not been granted any trademark license as part of this Agreement.
# Neither the name of NEC Laboratories Europe GmbH nor the names of its contributors may be used to
# endorse or promote products derived from this Software without specific prior written permission.
# You may not sell, rent, lease, sublicense, lend, time-share or transfer, in whole or in part, or provide
# third parties access to prior or present versions (or any parts thereof) of the Software.
#
# ASSIGNMENT: You may not assign this Agreement or your rights hereunder without the prior
# written consent of Licensor. Any attempted assignment without such consent shall be null and void.
#
# TERM: The term of the license granted by this Agreement is from Licensee's acceptance of this
# Agreement by downloading the Software or by using the Software until terminated as provided below.
# The Agreement automatically terminates without notice if you fail to comply with any provision of
# this Agreement. Licensee may terminate this Agreement by ceasing using the Software. Upon any
# termination of this Agreement, Licensee will delete any and all copies of the Software. You agree that
# all provisions which operate to protect the proprietary rights of Licensor shall remain in force should
# breach occur and that the obligation of confidentiality described in this Agreement is binding in
# perpetuity and, as such, survives the term of the Agreement.
#
# FEE: Provided Licensee abides completely by the terms and conditions of this Agreement, there is no
# fee due to Licensor for Licensee's use of the Software in accordance with this Agreement.
#
# DISCLAIMER OF WARRANTIES: THE SOFTWARE IS PROVIDED "AS-IS" WITHOUT
# WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR
# MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE OR OF NON-
# INFRINGEMENT. LICENSEE BEARS ALL RISK RELATING TO QUALITY AND
# PERFORMANCE OF THE SOFTWARE AND RELATED MATERIALS.
#
# SUPPORT AND MAINTENANCE: No Software support or training by the Licensor is provided as
# part of this Agreement.
#
# EXCLUSIVE REMEDY AND LIMITATION OF LIABILITY: To the maximum extent permitted
# under applicable law, Licensor shall not be liable for direct, indirect, special, incidental, or
# consequential damages or lost profits related to Licensee's use of and/or inability to use the Software,
# even if Licensor is advised of the possibility of such damage.
#
# EXPORT REGULATION: Licensee agrees to comply with any and all applicable export control laws,
# regulations, and/or other laws related to embargoes and sanction programs administered by law.
#
# SEVERABILITY: If any provision(s) of this Agreement shall be held to be invalid, illegal, or
# unenforceable by a court or other tribunal of competent jurisdiction, the validity, legality and
# enforceability of the remaining provisions shall not in any way be affected or impaired thereby.
#
# NO IMPLIED WAIVERS: No failure or delay by Licensor in enforcing any right or remedy under this
# Agreement shall be construed as a waiver of any future or other exercise of such right or remedy by
# Licensor.
#
# GOVERNING LAW: This Agreement shall be construed and enforced in accordance with the laws of
# Germany without reference to conflict of laws principles. You consent to the personal jurisdiction of
# the courts of this country and waive their rights to venue outside of Germany.
#
# ENTIRE AGREEMENT AND AMENDMENTS: This Agreement constitutes the sole and entire
# agreement between Licensee and Licensor as to the matter set forth herein and supersedes any
# previous agreements, understandings, and arrangements between the parties relating hereto.
#
# THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
###

# Utilities

# issues:
function parse_param(n)
    if typeof(n) == Symbol
        return (n, :Any)
    elseif typeof(n) == Expr
        # nexted type
        tname = n.args[1]

        ttpl = []
        if typeof(n.args[2]) == Expr
            for arg in n.args[2].args
                push!(ttpl, arg)
            end
        else
            ttpl = n.args[2]
        end

        return (tname, ttpl)
    end

    println("Error parsing type:", n)
    return :Error
end

# Extract all function definitions
mutable struct CCallableFunctionDefExtracter <: jast_visit_transform
    # temporary values during the search
    in_ccallable::Bool

    # results
    results::Vector{Any}

    function CCallableFunctionDefExtracter()
        new(false, [])
    end
end

function visit(t::CCallableFunctionDefExtracter, n::Expr)

    # check whether we encounter a @ccacllable function
    if n.head == :macrocall
        if n.args[1].head == :. && typeof(n.args[1].args[2]) == QuoteNode
            # apparently, we cannot use @ccallable directly as it is a macro
            if n.args[1].args[2].value == Symbol("@ccallable")
                t.in_ccallable = true
            end
        end
    end

    # find function name
    if n.head == :function
        # only collect ccallable functions
        if t.in_ccallable
            call_node = n.args[1]

            # find return type
            ret = nothing
            if n.args[1].head == Symbol("::")
                # function->args[1]: function symbol and parameters
                call_node = n.args[1].args[1]

                # function->args[2]: return type
                ret = n.args[1].args[2]
            end

            # find arguments and types
            args = []
            for argdef in call_node.args[2:length(call_node.args)]
                push!(args, argdef)
            end

            push!(t.results, (call_node.args[1], ret, args))
        end
    end

    for c in n.args
        visit(t, c)
    end

    # leave macrocall scope
    if n.head == :macrocall
        t.in_ccallable = false
    end
end

# Extract all struct definitions
mutable struct StructDefExtracter <: jast_visit_transform
    # results
    results

    function StructDefExtracter()
        new([])
    end
end

function visit(t::StructDefExtracter, n::Expr)
    if n.head == :struct
        sname = nothing
        if typeof(n.args[2]) == Symbol
            sname = n.args[2]
        else
            # inheritance -> ignore for C
            sname = n.args[2].args[1]
        end

        push!(t.results, (sname, n.args[3].args))
    else
        for c in n.args
            visit(t, c)
        end
    end
end

# Delete all line info nodes
mutable struct LineNumberNodeRemoval! <: jast_delete_transform
end

function apply(t::LineNumberNodeRemoval!, n::LineNumberNode)
    return true
end

function apply(t::LineNumberNodeRemoval!, n::Expr)

    if n.head == :line
        return true
    else

        total = length(n.args)
        i = 0

        while i < total
            if apply(t, n.args[i + 1])
                if n.head == :macrocall
                    n.args[i + 1] = nothing
                else
                    deleteat!(n.args, i + 1)
                    total -= 1
                end
            else
                i += 1
            end
        end
    end

    return false
end

# extract all composite types that we potentially need to translate
mutable struct CompositeTypeExprExtractor <: jast_visit_transform
    # temporary values during the search
    in_ccallable::Bool

    results::Vector{Any}

    function CompositeTypeExprExtractor()
        new(false, [])
    end
end

function visit(t::CompositeTypeExprExtractor, n::Expr)
    if n.head == :struct
        sname = nothing
        if typeof(n.args[2]) == Symbol
            sname = n.args[2]
        else
            # inheritance -> ignore for C
            sname = n.args[2].args[1]
        end

        # find inner structs and tuples, if there are any
        for child in n.args[3].args
            visit(t, child)
        end

        push!(t.results, (sname, n.args[3]))

        return

    elseif n.head == Symbol("curly")
        if n.args[1] == Symbol("Vector")
            push!(t.results, (nothing, n))
        elseif n.args[1] == Symbol("Array")
            push!(t.results, (nothing, n))
        elseif n.args[1] == Symbol("Tuple")
            for child in n.args
                visit(t, child)
            end

            push!(t.results, (nothing, n))
        end

        return

    # check whether we encounter a @ccacllable function
    elseif n.head == Symbol("macrocall")
        if n.args[1].head == :. && typeof(n.args[1].args[2]) == QuoteNode
            # apparently, we cannot use @ccallable directly as it is a macro
            if n.args[1].args[2].value == Symbol("@ccallable")
                t.in_ccallable = true
            end
        end

    # find function name
    elseif n.head == Symbol("function")
        # only collect ccallable functions
        if t.in_ccallable

            call_node = n.args[1]

            # find return type
            ret = nothing
            if n.args[1].head == Symbol("::")
                # function->args[1]: function symbol and parameters
                call_node = n.args[1].args[1]

                # function->args[2]: return type
                ret = n.args[1].args[2]
                visit(t, ret)
            end

            # find arguments and types
            args = []
            for argdef in call_node.args[2:length(call_node.args)]
                push!(args, argdef)
                visit(t, argdef)
            end
        end
    end

    for c in n.args
        visit(t, c)
    end
end

max_stars_repo_name: nec-research/jCall

max_issues_repo_name: nec-research/jCall

max_forks_repo_name: nec-research/jCall


text:
module BenchmarkExt

using Base.Iterators

using Logging: @logmsg, LogLevel
using Statistics
using UUIDs: uuid4
using Printf
using Profile
using TOML
using StructTypes
using JSON3

abstract type AbstractBenchmark end
StructTypes.StructType(::Type{AbstractBenchmark}) = StructTypes.AbstractType()

########################################
# Preferences
########################################

include("preferences.jl")

# Public unexported API:
#    set_preferences,
#    save_preferences!,
#    load_preferences!

########################################
# Parameters
########################################

include("parameters.jl")

export loadparams!

########################################
# Trial Data
########################################

include("trials.jl")

export gctime,
       memory,
       allocs,
       params,
       ratio,
       judge,
       isinvariant,
       isregression,
       isimprovement,
       median,
       mean,
       rmskew!,
       rmskew,
       trim

########################################
# Benchmark Data
########################################

include("groups.jl")

export BenchmarkGroup,
       invariants,
       regressions,
       improvements,
       @tagged,
       addgroup!,
       leaves,
       @benchmarkset,
       @case

########################################
# Execution Strategy
########################################

include("execution.jl")

export tune!,
       warmup,
       @ballocated,
       @benchmark,
       @benchmarkable,
       @belapsed,
       @btime,
       @bprofile

########################################
# Serialization
########################################

include("serialization.jl")

########################################
# Pretty printing
########################################

include("pprints/trial_classical.jl")
include("pprints/trial_fancy.jl")

########################################
# Initialization
########################################

include("init.jl")

end # module BenchmarkExt


text:
# Interface of a Shape:
#  can_intersect(s::Shape), returns Bool
#  area(s::Shape), returns Float64
#  obj_bounds(s::Shape), returns BoundingBox
#  world_bounds(s::Shape), returns BoundingBox
#  intersect(r::Ray, s::Shape) returns (Union{DifferentialGeometry,Void}, tMin, rayEps)
#  intersectP(r::Ray, s::Shape) returns Bool

import Base.intersect

export Sphere, Disk, Cylinder, Triangle, Paraboloid, Cone, Box
export cone_between_points

world_to_obj(S::Shape)::Transformation = S.world_to_obj
obj_to_world(S::Shape)::Transformation = S.obj_to_world

include("shapes/sphere.jl")
include("shapes/cylinder.jl")
include("shapes/disk.jl")
include("shapes/triangle.jl")
include("shapes/paraboloid.jl")
include("shapes/cone.jl")
include("shapes/box.jl")

#include("shapes/plane.jl")

max_stars_repo_name: dronir/GRAYTR

max_issues_repo_name: dronir/GRAYTR

max_forks_repo_name: dronir/GRAYTR


text:
using Lumberjack
using DataFrames
using GZip
using Inflate
include(Pkg.dir("BismarkSummary","src","moabs-format-to-dict-parser.jl"))

function get_bismark_cx_report_filenames_with_metadata_from_plite_pipeline(
                      metadata_path, pipeline_path,run_number,num_jobs,step_name="methylationextractor",
                      report_name="bismark_dedup.CX_report.txt.gz")
    metadata=readtable(metadata_path)
    metadata=metadata[1:num_jobs]
    files = map( x->joinpath(pipeline_path, "output","run$run_number", "job$x",step_name, report_name), 0:(num_jobs-1) )
    metadata[:filename]=files
    return metadata
end

function appendlist(x)
    return (x,)
end

function less_than(a,b)
      (t,u,v)=split(a,'.')
      (x,y,z)=split(b,'.')
      if t == x && int(u) <= int(y)
          return true
      else
        return false
      end
end

function get_cpg_dinucleotide_dict(d::Dict)
    last_count  = 0
    last_strand = ""
    cpg_dict = Dict()
    for key in sort(collect(keys(d)),lt=less_than )

        this_count = d[key]
        (this_seq_id,this_pos,this_strand)=split(key, '.' )
       # println(this_strand)
        if (last_strand == "+" ) && (int(last_pos) == (int(this_pos) - 1) )  && ( this_strand == "-") && ( this_seq_id == last_seq_id)
            cpg_dict[ join( [this_seq_id,last_pos,this_pos], ".") ] = this_count + last_count
        end
        (last_seq_id,last_pos,last_strand,last_count)=(this_seq_id,this_pos,this_strand, this_count)
    end
    return cpg_dict
end
# when there is a ragel parser, we read only what we want here
# - i.e. CG context
function memory_read_file(filename)
    io = open(filename)
    Lumberjack.info("reading all")
    file=readall(io)
    Lumberjack.info("finished reading all")
    close(io)
    return file
end

function memory_read_gzip_file(filename)
    io = open(filename)
    Lumberjack.info("reading all")
    file_gz=readbytes(io)
    Lumberjack.info("finished reading all")
    Lumberjack.info("decompressing")
    file = gunzip(file_gz)
    Lumberjack.info("finished decompressing")
    Lumberjack.info("convert to ASCIIString")
    file_str=convert(ASCIIString,file)
    Lumberjack.info("finished conversion to ASCIIString")
    close(io)
    return file_str
end

function read_gzip_file(filename)
   gzio=gzopen(filename,"r")
   line_num =0
   lines=ASCIIString[]
   for line in eachline(gzio)
        line=chomp(line)
        push!(lines,line)
        line_num +=1
        if line_num % 1000000 == 0
            Lumberjack.info("full on speed like road runner $line_num already!")
        end
    end
    #pop!(lines) # clears out the final row which due to a bug in GZlib gives and empty string
    return lines
end

function get_coverage_dict!(d::Dict,filenames)
    for filename in filenames
        # open file and add counts to dictionary of CpGs
        (path,ext)=splitext(filename)
        Lumberjack.info("Processing $filename: Extension: $ext")
        if ext != ".gz"
            file_str=memory_read_file(filename)
        else
            file_str=memory_read_gzip_file(filename)
        end
        Lumberjack.info("split line")
        lines=split(file_str,'\n')
        Lumberjack.info("done split")
        idx =0
        for line in lines
            fields=split(line,'\t')
            if length(fields) == 7
                if fields[6] != "CG"
                   continue
                end
                d[ join( [ fields[1],fields[2],fields[3] ], "." )  ] = int64(fields[4]) + int64(fields[5])
                if idx % 1000000 == 0
                    Lumberjack.info("processed $idx rows")
                end
                idx+=1
            end
        end
    end
end

function get_coverage_dict_moabs!(d::Dict,filenames; gc_disable=false)
    Lumberjack.info("Calculating coverage index based on MOABS formatted file.  (get_coverage_dict_moabs)")
    for filename in filenames
        # open file and add counts to dictionary of CpGs
        (path,ext)=splitext(filename)
        Lumberjack.info("Processing $filename: Extension: $ext")
        if ext != ".gz"
            file_str=memory_read_file(filename)
        else
            file_str=memory_read_gzip_file(filename)
        end
        Lumberjack.info("Parsing MOABS format")
        moabs_dict=MOABSParserImpl.parse_moabs(file_str,d,gcdisable=gc_disable)
        num_keys=length(collect(keys(d)))
        Lumberjack.info("Finished Parsing MOABS format: num cpgs seen $num_keys")
    end
end

# generalise this a bit
function cpg_cumulative_coverage(cpg_dict)
      cov_counts = [0,0,0,0,0]
      tot = 0
      meth_count =0
      for value in values(cpg_dict)
          if value > 1
              cov_counts[1] +=1
          end
          if value > 3
              cov_counts[2] +=1
          end
          if value > 5
              cov_counts[3] +=1
          end
          if value > 10
             cov_counts[4] +=1
          end
          if value > 15
             cov_counts[5] +=1
          end
          tot +=1
          meth_count += value
      end
      return (meth_count / tot, cov_counts ./ tot )
end

function temporary_write(row,group,cpg_coverage::DataFrame, grouped_metadata::DataFrame,report_dir)
     cpg_coverage_copy=copy(cpg_coverage)
     cpg_coverage_copy[group] = grouped_metadata[1:row,group]
     output_file=joinpath(report_dir,"cpg_coverage-tmp-$row.tsv")
     writetable(output_file, cpg_coverage_copy)
     Lumberjack.info("Written tmp coverage table to $output_file")
end

function make_coverage_stats_table(metadata::DataFrame, group::Symbol, report_dir::ASCIIString;
                                   format="bismark-cx", gc_disable=false )
    grouped_metadata = by( metadata, group,
        df ->  appendlist( df[:filename] )
    )
    cpg_coverage=DataFrame(depth=Float32[],gt_1=Float32[], gt_3=Float32[], gt_5=Float32[], gt_10=Float32[], gt_15=Float32[])

    Lumberjack.info("PROCESSING FOR $format")
    for row = 1:nrow( grouped_metadata)
       eachgroup = grouped_metadata[row,:]
       d=Dict{ASCIIString,Int32}()
       for files_tuple in eachgroup[:x1]
           files=files_tuple[1]
           if format == "bismark-cx"
             file=get_coverage_dict!(d,files)
           end

          if format == "moabs-cpg"
             file=get_coverage_dict_moabs!(d,files, gc_disable=gc_disable)
          end
       end
       Lumberjack.info("Done group $row")
       cpg_dict=nothing
       if format == "bismark_cx"
           cpg_dict= get_cpg_dinucleotide_dict(d)
       end
       if format == "moabs-cpg"
           cpg_dict= d
       end
       #Lumberjack.debug("cpg coverage dictionary: $cpg_dict")
       (depth,cov)=cpg_cumulative_coverage(cpg_dict)
       unshift!(cov,depth)
       push!(cpg_coverage,cov)
       temporary_write(row,group,cpg_coverage,grouped_metadata,report_dir)
       cpg_dict=nothing
    end
    cpg_coverage[group] = grouped_metadata[:,group]
    output_file=joinpath(report_dir,"cpg_coverage.tsv")
    writetable(output_file, cpg_coverage)
    Lumberjack.info("Written coverage table to $output_file")
    return cpg_coverage
end


text:
using UnitfulLsqFit
using Unitful
using LsqFit
using Test

L = 1000
@. model(x, p) = p[1] + p[2] * exp(-((x - p[3]) / p[4])^2) + p[5] * x
x = range(-5, 5; length=L)
p0 = [1.0, 10.8, -0.3, 1.2, 0.7]
y = model(x, p0) + randn(L)
@testset "UnitfulLsqFit.jl" begin
    r = curve_fit(
        model, x * u"m", y * u"s", [0.0u"s", 1.0u"s", 0.0u"m", 1.0u"m", 1.0u"s/m"]
    )
    print("\nManually check accuracy:\n\nTruth\tResult\n",'━'^35,'\n')
    for (a, b) in zip(p0, r.param)
        print(a, '\t', b, '\n')
    end
    println()
    @test r.converged
    @test unit.(r.param) == [u"s", u"s", u"m", u"m", u"s/m"]
    r = curve_fit(model, x * u"m", y, [0.0, 1.0, 0.0u"m", 1.0u"m", 1.0u"1/m"])
    @test r.converged
    r = curve_fit(model, x, y * u"s", [0.0u"s", 1.0u"s", 0.0, 1.0, 1.0u"s"])
    @test r.converged
    @test_throws Exception curve_fit(
        model, x * u"m", y * u"s", [0.0u"s", 1.0u"s", 0.0u"m", 1.0u"s"]
    )
    @test_throws Exception curve_fit(
        model, x * u"m", y * u"m", [0.0u"s", 1.0u"s", 0.0u"m", 1.0u"s/m"]
    )
end


text:
# IFS structs and basic utilities.

"Iterated function system"
struct IFS
	linear::Vector{Matrix{Float64}}
	trans::Vector{Vector{Float64}}
	numMaps::Int
	dimAmbient::Int

	IFS(linear::Vector{Matrix{Float64}}, trans::Vector{Vector{Float64}}, numMaps::Int, dimAmbient::Int) = new(linear, trans, numMaps, dimAmbient)
	IFS(linear::Vector{Matrix{Float64}}, trans::Vector{Vector{Float64}}) = IFS(linear, trans, size(trans, 1), size(trans[1], 1))
end

"Weighted iterated function system"
mutable struct WIFS
	linear::Vector{Matrix{Float64}}
	trans::Vector{Vector{Float64}}
	weights::Vector
	numMaps::Int
	dimAmbient::Int

	WIFS(linear::Vector{Matrix{Float64}}, trans::Vector{Vector{Float64}}, weights::Vector) = isprobvec(weights) ? new(linear, trans, weights, size(trans, 1), size(trans[1], 1)) : error("Not prob. vec!")
	WIFS(ifs::IFS, weights::Vector) = WIFS(ifs.linear, ifs.trans, weights)
	WIFS(ifs::IFS) = WIFS(ifs, ones(ifs.numMaps) ./ ifs.numMaps)
	WIFS(linear::Vector{Matrix{Float64}}, trans::Vector{Vector{Float64}}) = WIFS(IFS(linear, trans))
end

"Nonlinear iterated function system"
struct IFSNonlinear
	maps::Vector{Function}
	weights::Vector
	numMaps::Int
	dimAmbient::Int

	IFSNonlinear(maps::Vector{Function}, weights::Vector, dimAmbient::Int) = new(maps, weights, size(maps, 1), dimAmbient)
	IFSNonlinear(maps::Vector{Function}, dimAmbient::Int) = new(maps, ones(size(maps, 1)) ./ size(maps, 1), size(maps, 1), dimAmbient)
end

"PredefinedIFS as a module"
module PredefinedIFS

import ..IFS
import ..WIFS

SierpinskiTriangle = IFS([[1 / 2 0; 0 1 / 2],
				  [1 / 2 0; 0 1 / 2],
				  [1 / 2 0; 0 1 / 2]],
				 [[0, 0],
				  [1 / 2, 0],
				  [1 / 4, 1 / 4 * sqrt(3)]])
BarnsleyFern = WIFS([[0  0; 0 0.16],
					 [ 0.85  0.04; -0.04 0.85],
					 [ 0.2  -0.26; 0.23 0.22],
					 [-0.15  0.28; 0.26 0.24]],
					[[0, 0],
					 [0, 1.6],
					 [0, 1.6],
				 	 [0, 0.44]],
					[0.01, 0.84, 0.08, 0.07])
HeighwayDragon = IFS([[1 / 2 -1 / 2; 1 / 2 1 / 2],
					[-1 / 2 -1 / 2; 1 / 2 -1 / 2]],
					[[0., 0.], [1.,0.]])
Twindragon = IFS([[1 / 2 -1 / 2; 1 / 2 1 / 2],
					[-1 / 2 1 / 2; -1 / 2 -1 / 2]],
					[[0., 0.], [1., 0.]])
Terdragon = IFS([[1 / 2 1 / (2 * sqrt(3)); -1 / (2 * sqrt(3)) 1 / 2],
					[0 -1 / sqrt(3); 1 / sqrt(3) 0],
					[1 / 2 1 / (2 * sqrt(3)); -1 / (2 * sqrt(3)) 1 / 2]],
					[[0, 0], [1 / 2, -1 / (2 * sqrt(3))], [1 / 2, 1 / (2 * sqrt(3))]])

function BaranskiCarpet(v::Vector=[0.3, 0.7], h::Vector=[0.1, 0.8, 0.1], pos::Matrix=[1 0 1; 0 1 1])::IFS
	pos = reverse(pos; dims=1)
	linear = [ [h[x[2]] 0; 0 v[x[1]]] for x in findall(pos .> 0)]
	trans = [ [sum(h[1:x[2] - 1]),  sum(v[1:x[1] - 1])] for x in findall(pos .> 0)]

	return IFS(linear, trans)
end

BedMcCarpet(pos::Matrix=[1 0 1; 0 1 1]) = BaranskiCarpet(ones(size(pos, 1)) ./ size(pos, 1), ones(size(pos, 2)) ./ size(pos, 2), pos)

end # end of module PredefinedIFS

"""
Generate points via probabilistic method in the attractor of IFS.
"""
function itrPtsProb(linearIFS::Vector{Matrix{Float64}}, transIFS::Vector{Vector{Float64}}, weights::Vector{Float64}, maxNumPts::Int)::Vector{Vector{Float64}}
	probDistr = Categorical(weights)
	ptsSet = fill(zeros(Float64, 2), maxNumPts)
	ptsSet[1] = ([1 0; 0 1] - linearIFS[1]) \ transIFS[1]
	for i = 2:maxNumPts
		temptIndex = rand(probDistr)
		ptsSet[i] = linearIFS[temptIndex] * ptsSet[i - 1] + transIFS[temptIndex]
	end
	return ptsSet
end
itrPtsProb(wifs::WIFS, maxNumPts::Int=1000) = itrPtsProb(wifs.linear, wifs.trans, wifs.weights, maxNumPts)
itrPtsProb(ifs::IFS, maxNumPts::Int) = itrPtsProb(WIFS(ifs), maxNumPts)
function itrPtsProb(ifs::IFSNonlinear, maxNumPts::Int=1000, initialPt::Vector{Float64}=[0., 0.])
	maps = ifs.maps
	probDistr = Categorical(ifs.weights)
	ptsSet = fill(zeros(Float64, 2), maxNumPts)
	ptsSet[1] = initialPt
	for i = 2:maxNumPts
		ptsSet[i] = maps[rand(probDistr)](ptsSet[i - 1])
	end
	return ptsSet
end


text:
using Pkg
cd(@__DIR__)
Pkg.activate(".")
#Pkg.add("Flux")
#Pkg.add("MLDatasets")
#Pkg.add("BetaML")
#Pkg.add("Images")
#Pkg.add("FileIO")
#Pkg.add("ImageTransformations")
#Pkg.add("MLDatasets")
#Pkg.instantiate()
#Pkg.update()
using Random
Random.seed!(123);
using DelimitedFiles
using Statistics
using Flux
using Flux: Data.DataLoader
using Flux: onehotbatch, onecold, crossentropy
using Flux: @epochs
using MLDatasets # For loading the training data
using Images, FileIO, ImageTransformations # For loading the actual images

################################################################################
# Helper functions

function cleanImg!(img,threshold=0.3,radius=0)
    (R,C) = size(img)
    for c in 1:C
        for r in 1:R
            if img[r,c] <= threshold
                allneighmoursunderthreshold = true
                for c2 in max(1,c-radius):min(C,c+radius)
                    for r2 in max(1,r-radius):min(R,r+radius)
                        if img[r2,c2] > threshold
                            allneighmoursunderthreshold = false
                            break
                        end
                    end
                end
                if allneighmoursunderthreshold
                    img[r,c] = Gray(0.0)
                end
            end
        end
    end
    return img
end

accuracy(ŷ, y) =  (mean(onecold(ŷ) .== onecold(y)))
loss(x, y)     = Flux.crossentropy(model(x), y)

################################################################################
# Definition and training of the model
# (including extra images to MNIST db)
x_train, y_train = MLDatasets.MNIST.traindata()
x_train          = permutedims(x_train,(2,1,3)) # For correct img axis
x_train          = convert(Array{Float32,3},x_train)
y_train_add      = convert(Array{Int64,1},dropdims(readdlm("./data/additionalTestingImgs/img_labels.txt"),dims=2))
x_train_add_path = ["./data/additionalTestingImgs/test$(i).png" for i in 1:64]
x_train_add_imgs = load.(x_train_add_path)
x_train_add_imgs = [Gray.(i) for i in x_train_add_imgs]
x_train_add_imgs = [imresize(i, (28,28)) for i in x_train_add_imgs]
x_train_add_imgs = [1.0 .- i for i in x_train_add_imgs]
x_train_add_imgs = cleanImg!.(x_train_add_imgs, 0.3,1)
x_train_add_imgs = convert.(Array{Float32,2},x_train_add_imgs)

resample = 30 # 15
x_train_add_imgs2 = Array{Float32,2}[]
[append!(x_train_add_imgs2,x_train_add_imgs) for i in 1:resample]
x_train = cat(x_train, reshape(reduce(hcat, x_train_add_imgs2), 28, 28, :), dims=3)

y_train_add2 = Int64[]
[append!(y_train_add2,y_train_add) for i in 1:resample]
append!(y_train,y_train_add2)

#x_train_imgs     = convert(Array{Gray{N0f8},3},deepcopy(x_train))
x_train          = reshape(x_train,(28,28,1,60000+64*resample))

y_train          = onehotbatch(y_train, 0:9)
train_data       = DataLoader((x_train, y_train), batchsize=128)
x_test, y_test   = MLDatasets.MNIST.testdata()
x_test           = permutedims(x_test,(2,1,3)) # For correct img axis
x_test           = convert(Array{Float32,3},x_test)
x_test           = reshape(x_test,(28,28,1,10000))
y_test           = onehotbatch(y_test, 0:9)
#train_data       = DataLoader((x_test, y_test), batchsize=128)

model = Chain(
    # 28x28 => 14x14
    Conv((5, 5), 1=>8, pad=2, stride=2, relu),
    # 14x14 => 7x7
    Conv((3, 3), 8=>16, pad=1, stride=2, relu),
    # 7x7 => 4x4
    Conv((3, 3), 16=>32, pad=1, stride=2, relu),
    # 4x4 => 2x2
    Conv((3, 3), 32=>32, pad=1, stride=2, relu),
    # Average pooling on each width x height feature map
    GlobalMeanPool(),
    flatten,
    Dense(32, 10),
    softmax
)

#=
# alternative model, but slower and less accurate
alt_model = Chain(
  Conv((2,2), 1=>16, relu),
  x -> maxpool(x, (2,2)),
  Conv((2,2), 16=>8, relu),
  x -> maxpool(x, (2,2)),
  x -> reshape(x, :, size(x, 4)),
  Dense(288, 10), softmax
)
=#

opt = Flux.ADAM()
ps  = Flux.params(model)
number_epochs = 5
@epochs number_epochs Flux.train!(loss, ps, train_data, opt)

accuracy(model(x_train), y_train) # 0.95
accuracy(model(x_test), y_test) # 0.95

################################################################################
# Loading imgs

# Imgs obtained with photo -> Gimp: Colour -> auto white levels then: Levels -> Input levels -> Reduce the value on the left
folder = "class"
imgs_y = convert(Array{Int64,1},dropdims(readdlm("./data/$(folder)/img_labels.txt"),dims=2))
imgs_path = ["./data/$(folder)/img$(i).png" for i in 1:20]
imgs = load.(imgs_path)
imgs = [Gray.(i) for i in imgs]
imgs = [imresize(i, (28,28)) for i in imgs]
imgs = [1.0 .- i for i in imgs]
imgs = cleanImg!.(imgs, 0.3,1)
imgs = cat(imgs...,dims=3)
imgs = reshape(imgs,(28,28,1,size(imgs,3)))

################################################################################
# Doing the actual classification and printing results...

imgs_est = model(imgs)
imgs_ŷ = onecold(imgs_est, 0:9)
probs = maximum(imgs_est,dims=1)

nImgs = length(imgs_y)
println("*** Classification report")
println("Overall accuracy: $(mean(imgs_ŷ .== imgs_y))")
println("")
println("#id \t succ  \t true \t est \t prob")
for i in 1:nImgs
   resultSymbol = imgs_ŷ[i] == imgs_y[i] ? "✔" : "❌"
   println("$i \t $(resultSymbol) \t $(imgs_y[i])    \t $(imgs_ŷ[i])   \t $(probs[i])" )
end

max_stars_repo_name: sylvaticus/IntroSPMLJuliaCourse

max_issues_repo_name: sylvaticus/IntroSPMLJuliaCourse

max_forks_repo_name: sylvaticus/IntroSPMLJuliaCourse


text:
# test_utils.jl : utilities for testing SimpleMultigrid

# log resnorm
function log(mg,ϵ,β)
    println(string("+","-"^30,"+"))
    println(string("|"," "^4,@sprintf("ϵ = %6.3e, β = %2.0f ",ϵ,β)," "^4,"|"))
    println(string("+","-"^9,"+","-"^20,"+"))
    println(string("| V-cycle |  |rʰ|"," "^7,"ratio","  |"))
    println(string("+","-"^9,"+","-"^20,"+"))
    println(string(@sprintf("|   %4i  |",0),@sprintf("  %6.3e",mg.resnorm[1])," "^8," |"))
    for i in 2:length(mg.resnorm)
        println(string(@sprintf("|   %4i  |",i-1),@sprintf("  %6.3e",mg.resnorm[i]),@sprintf("  %3.2f",mg.resnorm[i]/mg.resnorm[i-1]),"   |"))
    end
    println(string("+","-"^9,"+","-"^20,"+"))
end

# log resnorm
function log(mg,d)
    println(string("+","-"^30,"+"))
	println(string("|"," "^11,@sprintf("n = %4i",(size(mg.grids[1].A,1))^(1/d)+1)," "^11,"|"))
    println(string("+","-"^9,"+","-"^20,"+"))
    println(string("| V-cycle |  |rʰ|"," "^7,"ratio","  |"))
    println(string("+","-"^9,"+","-"^20,"+"))
    println(string(@sprintf("|   %4i  |",0),@sprintf("  %6.3e",mg.resnorm[1])," "^8," |"))
    for i in 2:length(mg.resnorm)
        println(string(@sprintf("|   %4i  |",i-1),@sprintf("  %6.3e",mg.resnorm[i]),@sprintf("  %3.2f",mg.resnorm[i]/mg.resnorm[i-1]),"   |"))
    end
    println(string("+","-"^9,"+","-"^20,"+"))
end