text:
"""
Struct for Merton Process

		mertonProcess=MertonProcess(σ::num1,λ::num2,μJ::num3,σJ::num4) where {num1,num2,num3,num4<: Number}

Where:\n
		σ  =	volatility of the process.
		λ  = 	jumps intensity.
		μJ =	jumps mean.
		σJ =	jumps variance.
"""
mutable struct MertonProcess{num <: Number, num1 <: Number, num2 <: Number, num3 <: Number, abstrUnderlying <: AbstractUnderlying, numtype <: Number} <: FiniteActivityProcess{numtype}
    σ::num
    λ::num1
    μJ::num2
    σJ::num3
    underlying::abstrUnderlying
    function MertonProcess(σ::num, λ::num1, μJ::num2, σJ::num3, underlying::abstrUnderlying) where {num <: Number, num1 <: Number, num2 <: Number, num3 <: Number, abstrUnderlying <: AbstractUnderlying}
        if σ <= 0
            error("volatility must be positive")
        elseif λ <= 0
            error("jump intensity must be positive")
        elseif σJ <= 0
            error("positive λ must be positive")
        else
            zero_typed = zero(num) + zero(num1) + zero(num2) + zero(num3)
            return new{num, num1, num2, num3, abstrUnderlying, typeof(zero_typed)}(σ, λ, μJ, σJ, underlying)
        end
    end
end

export MertonProcess;
compute_jump_size(mcProcess::MertonProcess, mcBaseData::MonteCarloConfiguration) = mcProcess.μJ + mcProcess.σJ * randn(mcBaseData.rng);
compute_drift(mcProcess::MertonProcess) = exp(mcProcess.μJ + mcProcess.σJ^2 / 2.0) - 1.0


text:
using JuliaInterp

# Recursively call itself
#= f(i, j) = i == 0 ? j : f(i - 1, j + 1)

using Profile
Profile.clear()
options = JuliaInterp.options(false, false, [@__MODULE__], [], UInt(0))
JuliaInterp.interpret_ast(@__MODULE__, Meta.parse("f(1_000, 0)"), options)
@profile JuliaInterp.interpret_ast(@__MODULE__, Meta.parse("f(1_000, 0)"), options)
# Profile.print()
Juno.profiler() =#

# Long stack trace calling other functions
f0(i) = i
for i in 1:1_000
    @eval $(Symbol("f", i))(i) = $(Symbol("f", i-1))(i)
end

using Profile
Profile.clear()
options = JuliaInterp.options(false, false, [@__MODULE__], [], UInt(0))
JuliaInterp.interpret_ast(@__MODULE__, Meta.parse("f1000(1)"), options)
@profile for i in 1:10 JuliaInterp.interpret_ast(@__MODULE__, Meta.parse("f1000(1)"), options); end
# Profile.print()
Juno.profiler()

# Tight loop
#= function f(X)
    s = 0
    for x in X
        s += x
    end
    return s
end
const X = rand(1:10, 10_000)

using Profile
Profile.clear()
options = JuliaInterp.options(false, false, [@__MODULE__], [], UInt(0))
JuliaInterp.interpret_ast(@__MODULE__, Meta.parse("f(X)"), options)
@profile for i in 1:10 JuliaInterp.interpret_ast(@__MODULE__, Meta.parse("f(X)"), options); end
# Profile.print()
Juno.profiler() =#

#= include("tracer.jl")

using Profile
Profile.clear()
@profile try tracer(["arrayops.jl"]); catch end
# Profile.print()
Juno.profiler() =#

ext: jl


text:
function make_boxes(box::Vector{T}, n::S, scale_factor::T) where {T<:AbstractFloat, S<:Integer}
    # Generates data for testing bvh, returns a set of n boxes inside box
    minx, miny, minz, maxx, maxy, maxz = box
    dx::T = abs(maxx - minx) * (1.0 - scale_factor)
    dy::T = abs(maxy - miny) * (1.0 - scale_factor)
    dz::T = abs(maxz - minz) * (1.0 - scale_factor)
    sx::T = abs(maxx - minx) * scale_factor
    sy::T = abs(maxy - miny) * scale_factor
    sz::T = abs(maxz - minz) * scale_factor
    newBoxes::Array{T,2} = zeros(6, n)
    for i=1:n
        a = rand() * dx + minx
        b = rand() * dy + miny
        c = rand() * dz + minz
        newBoxes[:,i] = [a, b, c, a+sx, b+sy, c+sz]
    end
    return newBoxes
end

function produce_bvh_data(bounding_boxes::Array{T,2}) where T<:AbstractFloat
  # BVH with one leaf per end node
  n::Int = size(bounding_boxes, 2)
  m::Int = 2*n-1
  outerbox::Vector{T} = build_containing_box(bounding_boxes)
  bvh_boxes::Array{T,2} = zeros(6, m)
  bvh_boxes[:,1] = outerbox
  bb2bvh::Array{Int,1} = ones(n) # bounding boxes pointing to their node in the bvh
  bvh2bb::Array{Int,1} = zeros(m)
  bb_idx::Array{Int,1} = collect(1:n)
  left_child::Array{Int} = ones(m)
  right_child::Array{Int} = ones(m)

  writeCursor::Int = 1
  #axis::Char = 'x'
  cutDirection::Array{Char} = ['x' for i::Int = 1:m]
  @showprogress for readCursor::Int = 1:m # sequence through the BVH nodes top-down and slice, if multiple leaves are left within
    #if readCursor % 1000 === 0
    #    println(readCursor, " / ", m)
    #end

    subset_idx = bb_idx[bb2bvh .== readCursor]

    if size(subset_idx, 1) == 0
        continue
    end

    if size(subset_idx, 1) == 1
        bvh2bb[readCursor] = subset_idx[1]
    end

    if size(subset_idx, 1) > 1
      axis = cutDirection[readCursor]
      idxs_left, idxs_right, axis = median_cut(bounding_boxes[:,subset_idx]; axis=axis)
      idxs_left, idxs_right = subset_idx[idxs_left], subset_idx[idxs_right]

      writeCursor += 1
      bvh_boxes[:,writeCursor] = build_containing_box(bounding_boxes[:,idxs_left])
      bb2bvh[idxs_left] .= writeCursor
      left_child[readCursor] = writeCursor
      cutDirection[writeCursor] = axis

      writeCursor += 1
      bvh_boxes[:,writeCursor] = build_containing_box(bounding_boxes[:,idxs_right])
      bb2bvh[idxs_right] .= writeCursor
      right_child[readCursor] = writeCursor
      cutDirection[writeCursor] = axis
    end
  end
  # 1D arrays seem to be faster than a 2D array, even if column-major...
  minx::Array{T,1} = bvh_boxes[1,:]
  miny::Array{T,1} = bvh_boxes[2,:]
  minz::Array{T,1} = bvh_boxes[3,:]
  maxx::Array{T,1} = bvh_boxes[4,:]
  maxy::Array{T,1} = bvh_boxes[5,:]
  maxz::Array{T,1} = bvh_boxes[6,:]
  return minx, miny, minz, maxx, maxy, maxz, bvh2bb, left_child, right_child, bb2bvh
end

function median_cut(bounding_boxes::Array{T,2}; axis::Char=x) where {T<:AbstractFloat}
    n::Int = size(bounding_boxes,2)
    a::Vector{T} = zeros(n)
    if axis == 'x'
        for i::Int = 1:n
            a[i] = bounding_boxes[1,i]
        end
        s = sortperm(a)
        m = floor(Int, size(a,1) / 2)
        idx_left = s[1:m]
        idx_right = s[m+1:end]
        axis = 'y'
    elseif axis == 'y'
        for i::Int = 1:n
            a[i] = bounding_boxes[2,i]
        end
        s = sortperm(a)
        m = floor(Int, size(a,1) / 2)
        idx_left = s[1:m]
        idx_right = s[m+1:end]
        axis = 'z'
    elseif axis == 'z'
        for i::Int = 1:n
            a[i] = bounding_boxes[3,i]
        end
        s = sortperm(a)
        m = floor(Int, size(a,1) / 2)
        idx_left = s[1:m]
        idx_right = s[m+1:end]
        axis = 'x'
    end
    return idx_left, idx_right, axis
end

function build_containing_box(boxes::Array{T,2}) where {T<:AbstractFloat}
    minx::T = Inf
    miny::T = Inf
    minz::T = Inf
    maxx::T = -1.0*Inf
    maxy::T = -1.0*Inf
    maxz::T = -1.0*Inf
    n::Int = size(boxes,2)

    for i::Int = 1:n
        if boxes[1,i] < minx # minPoint.x
            minx = boxes[1,i]
        end
        if boxes[4,i] > maxx # maxPoint.x
            maxx = boxes[4,i]
        end
        if boxes[2,i] < miny # minPoint.y
            miny = boxes[2,i]
        end
        if boxes[5,i] > maxy # maxPoint.y
            maxy = boxes[5,i]
        end
        if boxes[3,i] < minz # minPoint.z
            minz = boxes[3,i]
        end
        if boxes[6,i] > maxz #  maxPoint.z
            maxz = boxes[6,i]
        end
    end
    box::Vector{T} = [minx, miny, minz, maxx, maxy, maxz]
    return box
end

function produce_bounding_boxes(mesh::Mesh)
    n = size(mesh.v1x, 1)
    boxes::Array{Float64, 2} = zeros(6, n)
    for i=1:n
        minx = min(mesh.v1x[i], mesh.v2x[i], mesh.v3x[i])
        miny = min(mesh.v1y[i], mesh.v2y[i], mesh.v3y[i])
        minz = min(mesh.v1z[i], mesh.v2z[i], mesh.v3z[i])
        maxx = max(mesh.v1x[i], mesh.v2x[i], mesh.v3x[i])
        maxy = max(mesh.v1y[i], mesh.v2y[i], mesh.v3y[i])
        maxz = max(mesh.v1z[i], mesh.v2z[i], mesh.v3z[i])
        boxes[:,i] = [minx, miny, minz, maxx, maxy, maxz]
    end
    return boxes
end

function produce_bounding_boxes(cylinder::Cylinder)
    n = size(cylinder.m1x, 1)
    boxes::Array{Float64, 2} = zeros(6, n)
    for i=1:n
        minx = min(cylinder.m1x[i], cylinder.m2x[i])
        miny = min(cylinder.m1y[i], cylinder.m2y[i])
        minz = min(cylinder.m1z[i], cylinder.m2z[i])
        maxx = max(cylinder.m1x[i], cylinder.m2x[i])
        maxy = max(cylinder.m1y[i], cylinder.m2y[i])
        maxz = max(cylinder.m1z[i], cylinder.m2z[i])
        r = cylinder.radius[i]
        boxes[:,i] = [minx-r, miny-r, minz-r, maxx+r, maxy+r, maxz+r]
    end
    return boxes
end

function produce_bounding_boxes(cone::Cone)
    n = size(cone.m1x, 1)
    boxes::Array{Float64, 2} = zeros(6, n)
    for i=1:n
        minx = min(cone.m1x[i] - cone.radius_base[i], cone.v2x[i] - cone.radius_tip[i])
        miny = min(cone.m1y[i] - cone.radius_base[i], cone.v2y[i] - cone.radius_tip[i])
        minz = min(cone.m1z[i] - cone.radius_base[i], cone.v2z[i] - cone.radius_tip[i])
        maxx = max(cone.m1x[i] + cone.radius_base[i], cone.v2x[i] + cone.radius_tip[i])
        maxy = max(cone.m1y[i] + cone.radius_base[i], cone.v2y[i] + cone.radius_tip[i])
        maxz = max(cone.m1z[i] + cone.radius_base[i], cone.v2z[i] + cone.radius_tip[i])
        boxes[:,i] = [minx, miny, minz, maxx, maxy, maxz]
    end
    return boxes
end

function produce_bounding_boxes(ball::Ball)
    n = size(ball.p1x, 1)
    boxes::Array{Float64, 2} = zeros(6, n)
    for i=1:n
        minx = ball.p1x[i] - ball.r[i]
        miny = ball.p1y[i] - ball.r[i]
        minz = ball.p1z[i] - ball.r[i]
        maxx = ball.p1x[i] + ball.r[i]
        maxy = ball.p1y[i] + ball.r[i]
        maxz = ball.p1z[i] + ball.r[i]
        boxes[:,i] = [minx, miny, minz, maxx, maxy, maxz]
    end
    return boxes
end

function produce_bounding_boxes(disk::Disk)
    n = size(disk.p1x, 1)
    boxes::Array{Float64, 2} = zeros(6, n)
    # not entirely accurate (i.e., not "slim fit") but it works fine...
    for i=1:n
        minx = disk.p1x[i] - disk.r[i]
        miny = disk.p1y[i] - disk.r[i]
        minz = disk.p1z[i] - disk.r[i]
        maxx = disk.p1x[i] + disk.r[i]
        maxy = disk.p1y[i] + disk.r[i]
        maxz = disk.p1z[i] + disk.r[i]
        boxes[:,i] = [minx, miny, minz, maxx, maxy, maxz]
    end
    return boxes
end

function make_bvh(bb::AbstractArray{T}) where {T<:AbstractFloat}
    # create bvh from bounding boxes (6xN array)
    minx, miny, minz, maxx, maxy, maxz, bvh2bb, left_child, right_child, bb2bvh = produce_bvh_data(bb)
    bvh = Bvh(minx, miny, minz, maxx, maxy, maxz, bvh2bb, left_child, right_child)
    return bvh
end

function make_bvh(geometry::Geometry{T,S,A,E}) where {T<:AbstractFloat, S<:Integer, A<:AbstractArray, E<:AbstractArray}
    # use this function only for meshes; scenes are handled below...
    boxes = produce_bounding_boxes(geometry)
    minx, miny, minz, maxx, maxy, maxz, bvh2bb, left_child, right_child, bb2bvh = produce_bvh_data(boxes)
    bvh = Bvh(minx, miny, minz, maxx, maxy, maxz, bvh2bb, left_child, right_child)
    return bvh
end

function make_bvh(assets::Array{Asset{Float64, Int64},1}, mesh_bvhs::Array{Bvh{Float64, Int64, Array{Float64,1}, Array{Int64,1}},1})
    n = size(assets, 1)
    boxes::Array{Float64, 2} = zeros(6, n)
    for i=1:n
        p = assets[i].oidx

        xmin = mesh_bvhs[p].xmin[1]
        ymin = mesh_bvhs[p].ymin[1]
        zmin = mesh_bvhs[p].zmin[1]

        xmax = mesh_bvhs[p].xmax[1]
        ymax = mesh_bvhs[p].ymax[1]
        zmax = mesh_bvhs[p].zmax[1]

        x1, y1, z1 = transform_forward(xmin, ymin, zmin, assets[i])
        x2, y2, z2 = transform_forward(xmin, ymin, zmax, assets[i])
        x3, y3, z3 = transform_forward(xmin, ymax, zmin, assets[i])
        x4, y4, z4 = transform_forward(xmin, ymax, zmax, assets[i])
        x5, y5, z5 = transform_forward(xmax, ymin, zmin, assets[i])
        x6, y6, z6 = transform_forward(xmax, ymin, zmax, assets[i])
        x7, y7, z7 = transform_forward(xmax, ymax, zmin, assets[i])
        x8, y8, z8 = transform_forward(xmax, ymax, zmax, assets[i])

        txmin = min(x1, x2, x3, x4, x5, x6, x7, x8)
        tymin = min(y1, y2, y3, y4, y5, y6, y7, y8)
        tzmin = min(z1, z2, z3, z4, z5, z6, z7, z8)

        txmax = max(x1, x2, x3, x4, x5, x6, x7, x8)
        tymax = max(y1, y2, y3, y4, y5, y6, y7, y8)
        tzmax = max(z1, z2, z3, z4, z5, z6, z7, z8)

        boxes[:,i] = [txmin, tymin, tzmin, txmax, tymax, tzmax]
    end
    minx, miny, minz, maxx, maxy, maxz, bvh2bb, left_child, right_child, bb2bvh = produce_bvh_data(boxes)
    scene_bvh::Bvh{Float64, Int64, Array{Float64,1}, Array{Int64,1}} = Bvh(minx, miny, minz, maxx, maxy, maxz, bvh2bb, left_child, right_child)
    return scene_bvh
end

max_stars_repo_name: martinvanleeuwen/RenderJay

max_issues_repo_name: martinvanleeuwen/RenderJay

max_forks_repo_name: martinvanleeuwen/RenderJay


text:
# two function to get the data
# data based on John Hopkins CSSE repository
# https://github.com/CSSEGISandData/COVID-19

using CSV, DataFrames, Dates

function smooth(x)
# make log-transform and smooth data
    lx = log10.(x)
    b = (1/2)*ones(2)     # flat (rectangular) window -> moving average
    lx = filtfilt(b,lx)
    10 .^ lx
end

# read-in covid-19 time series
# for infected, the funcion returns the prevalence (active cases)
# this is calculated by subtracting dead and recovered from cumulative cases
function covid_ts(country, starting_date)

  df_confirmed = CSV.read("../data/time_series_19-covid-Confirmed.csv")
  df_death     = CSV.read("../data/time_series_19-covid-Deaths.csv")
  df_recovered = CSV.read("../data/time_series_19-covid-Recovered.csv")
  first_date = Date(2020,1,22)              # first entry in database: Jan 22, 2020
  countries = df_confirmed[:,2]

  inds = findall(x->x==country, countries)
  maxdays = size(df_confirmed)[2] - 4          # number of reported days
  days = Dates.value(starting_date - first_date) # days we are interested
  I = zeros(Int,maxdays-days)
  D = zeros(Int,maxdays-days)
  R = zeros(Int,maxdays-days)
  for i in inds
      I .+= collect(df_confirmed[i, 5 + days:end])  # sum over all Provinces/States in a country
      D .+= collect(df_death[i,     5 + days:end])
      R .+= collect(df_recovered[i, 5 + days:end])

      #=  Now I do smoothing in general
      # hack to interpolate wrong data on March 12
      ind_error = Dates.value(Date(2020,3,12)-starting_date) + 1  # time difference
      I[ind_error] = ceil(Int,sqrt(I[ind_error-1]*I[ind_error+1]))
      R[ind_error] = ceil(Int,sqrt(R[ind_error-1]*R[ind_error+1]))
      D[ind_error] = ceil(Int,sqrt(D[ind_error-1]*D[ind_error+1]))

      if countries[i] == "Switzerland" || countries[i] == "France"
          ind_error = Dates.value(Date(2020,3,15)-starting_date) + 1  # time difference
          I[ind_error] = ceil(Int,sqrt(I[ind_error-1]*I[ind_error+1]))
          R[ind_error] = ceil(Int,sqrt(R[ind_error-1]*R[ind_error+1]))
          D[ind_error] = ceil(Int,sqrt(D[ind_error-1]*D[ind_error+1]))
      end
      =#

  end
  I = I .- R .- D
  #I = smooth(I)
  1:length(I),I,R,D
end

covid_ts(country) = covid_ts(country, Date(2020,1,22))

# calculate arrival times: first records of confirmed cases > th for all countries
function arrival_times(th=0, pandemie_start=Date(2019,12,1))
  # th: threshold for arrival
  # pandemie_start: hypothetical starting date of the pandemie
  df_confirmed = CSV.read("../data/time_series_19-covid-Confirmed.csv")
  df_death     = CSV.read("../data/time_series_19-covid-Deaths.csv")
  df_recovered = CSV.read("../data/time_series_19-covid-Recovered.csv")
  first_date = Date(2020,1,22)          # first entry in database: Jan 22, 2020
  countries = df_confirmed[:,2]

  firsts = zeros(Int,length(countries))
  for i = 1:length(countries)
      R = collect(df_confirmed[i,5:end])
      x = findfirst(x->x>th, R)
      firsts[i] = x == nothing ? length(names(df_confirmed))-4 : x
  end

  # collect first records over Provinces/States of a country
  p = sortperm(countries)
  countries = countries[p]
  firsts = firsts[p]

  sep_countries = [countries[1]]
  sep_firsts    = [firsts[1]]
  c = countries[1]
  i = firsts[1]
  for i=2:length(countries)
      c1 = countries[i]
      i1 = firsts[i]
      if c1==c # same countrie
          if i1 < i
             sep_firsts[end] = i1
             i = i1
          end
      else
         push!(sep_countries,c1)
         push!(sep_firsts,i1)
         c = c1
         i = i1
      end
  end

  # print into csv-file
  arrivals = first_date .+ Day.(sep_firsts .- 1)
  time_diff = Dates.value.(arrivals .- pandemie_start)  # time difference in days to start of pandemie
  df = DataFrame(country=sep_countries, arrival_time=arrivals, time_dist=time_diff)  # put into dataframe
  CSV.write("../arrival_times.csv", df)

  # return vector of countries, dates of arrival
  sep_countries, sep_firsts, time_diff
end

max_stars_repo_name: AlexRyabov/covid

max_issues_repo_name: AlexRyabov/covid

max_forks_repo_name: AlexRyabov/covid


text:
"""
FRP fileformat

Used for generating Free Route segments

See EUROCONTROL NEST Manual for Frp fileformat description

Output:
TBD

Frp fileformat example
ALBANIA EX DIMIS N400421 E0203541
ALBANIA EX DOBAR N411958 E0202941
ALBANIA EX GOKEL N403554 E0190000
ALBANIA EX MAVAR N414012 E0203148
ALBANIA EX PAPIZ N405330 E0185706
ALBANIA EX PINDO N402851 E0205721
ALBANIA EX RETRA N421342 E0192006
ALBANIA EX RODON N412730 E0190600
ALBANIA E PETAK N414631 E0191850
ALBANIA A PETAK LATI
ALBANIA E AKIKA N423203 E0193614
ALBANIA E NIKRO N393957 E0200712
ALBANIA E TUMBO N400402 E0202822
ALBANIA E VJOSA N395855 E0202329
ALBANIA X ALELU N422845 E0195102
ALBANIA X EBELA N411136 E0185432
ALBANIA X PITAS N395400 E0195040
ALBANIA I DIRES N410328 E0191133
ALBANIA AD DIRES LATI
ALBANIA I DITAN N405644 E0191813
ALBANIA AD DITAN LATI
ALBANIA I ELBAK N405151 E0200452
ALBANIA AD ELBAK LATI
ALBANIA I INLOT N415847 E0192711
ALBANIA AD INLOT LATI
ALBANIA I ODRAS N413335 E0201027
ALBANIA AD ODRAS LATI
ALBANIA I RINAV N415901 E0194718
ALBANIA D RINAV LATI
ALBANIA I ADDER N403126 E0201817
ALBANIA I GRIBA N402830 E0193712
ALBANIA I MAGGI N411103 E0192236
ALBANIA I NURSO N403956 E0203217
ALBANIA I OVVER N403230 E0200046
ALBANIA I TR N412748 E0194251
ALBANIA I UMRES N412610 E0192553
ALBANIA I UNASA N412642 E0191801
ALBANIA I UNDER N410405 E0195651
ALBANIA I VALIN N411104 E0194600
ALBANIA I VOLBI N413855 E0194122
"""
module Frp

export read

using ..util

struct FreeRoutePoint
    type::AbstractString
    name::AbstractString
    # point::Union{Point, AbstractString, Missing}
    point::Union{Point_deg, AbstractString, Missing}
end

struct FreeRouteAirports
    type::AbstractString
    name::AbstractString
    airports::Vector{String}
end

struct FreeRouteArea
    freeroutepoints::Vector{FreeRoutePoint}
    freerouteairports::Vector{FreeRouteAirports}
end

function read(file)
    freerouteareas = Dict{String, FreeRouteArea}()
    freerouteareaname = ""
    freeroutepoints = Vector{FreeRoutePoint}()
    freerouteairports = Vector{FreeRouteAirports}()

    lines = sort(readlines(file))

    for line in lines
        line_elements = split(line, ' ')
        if line_elements[1] != freerouteareaname  # new freeroutearea
            if freerouteareaname != ""
                freerouteareas[freerouteareaname] = FreeRouteArea(
                freeroutepoints, freerouteairports)
            end
            freerouteareaname = line_elements[1]
            freeroutepoints = Vector{FreeRoutePoint}()
            freerouteairports = Vector{FreeRouteAirports}()
        end

        if line_elements[2] in ["E", "X", "EX", "I", "EI", "XI", "EXI"]
            point_type = convert(String, line_elements[2])
            point_name = convert(String, line_elements[3])
            if length(line_elements) > 4
                point = latlon(line_elements[4], line_elements[5])
            elseif length(line_elements) > 3
                # println(line_elements)
                point = line_elements[4]
            else
                # println(line_elements)
                point = missing
            end
            freeroutepoints = vcat(freeroutepoints, FreeRoutePoint(point_type,
            point_name, point))
        elseif line_elements[2] in ["D", "A", "AD"]
            point_type = convert(String, line_elements[2])
            point_name = convert(String, line_elements[3])
            airports = Vector{String}()
            if length(line_elements) ≤ 3
            elseif length(line_elements) == 4
                airports = [convert(String, line_elements[4])]
            else
                for airport in line_elements[4:end]
                    airports = vcat(airports, convert(String, airport))
                end
            end
            freerouteairports = vcat(freerouteairports, FreeRouteAirports(point_type,
            point_name, airports))
        else

        end
    end
    freerouteareas[freerouteareaname] = FreeRouteArea(
    freeroutepoints, freerouteairports)
    return freerouteareas
end

end # module


text:
@testset verbose = true "Test Reflection API" begin
    using JavaCall: Reflection

    @testset "Find class" begin
        @testset "Object Class" begin
            expected = Reflection.ClassDescriptor(
                C_NULL,
                :JObject,
                :jobject,
                "Ljava/lang/Object;"
            )
            objclass = Reflection.findclass(Symbol("java.lang.Object"))

            @test objclass == expected
            @test Reflection.superclass(objclass) === nothing
            @test_false Reflection.isinterface(objclass)
        end

        @testset "Integer Class" begin
            expected = Reflection.ClassDescriptor(
                C_NULL,
                :JInteger,
                :jobject,
                "Ljava/lang/Integer;"
            )
            expectedsuperclass = Reflection.ClassDescriptor(
                C_NULL,
                :JNumber,
                :jobject,
                "Ljava/lang/Number;"
            )
            integerclass = Reflection.findclass(Symbol("java.lang.Integer"))
            @test integerclass == expected
            @test Reflection.superclass(integerclass) == expectedsuperclass
            @test_false Reflection.isinterface(integerclass)
        end

        @testset "Runnable Interface" begin
            expected = Reflection.ClassDescriptor(
                C_NULL,
                :JRunnable,
                :jobject,
                "Ljava/lang/Runnable;"
            )
            runnableinterface = Reflection.findclass(Symbol("java.lang.Runnable"))
            @test runnableinterface == expected
            @test Reflection.isinterface(runnableinterface)
        end
    end

    @testset "Find methods" begin
        methods = Reflection.classmethods(Symbol("java.lang.String"))
        @test length(methods) > 0
        @test_isa methods Vector{Reflection.MethodDescriptor}

        found_getbytes = false
        found_equals = false
        found_format = false
        found_getchars = false

        # byte[] getBytes()
        getbytes = Reflection.MethodDescriptor(
            "getBytes",
            Reflection.ClassDescriptor(
                C_NULL,
                :(Vector{Int8}),
                :jbyteArray,
                "[B",
                Reflection.ClassDescriptor(C_NULL, :Int8, :jbyte, "B")
            ),
            [],
            Reflection.ModifiersDescriptor(false, true)
        )

        # boolean equals(Object)
        equals = Reflection.MethodDescriptor(
            "equals",
            Reflection.ClassDescriptor(C_NULL, :Bool, :jboolean, "Z"),
            [Reflection.ClassDescriptor(C_NULL, :JObject, :jobject, "Ljava/lang/Object;")],
            Reflection.ModifiersDescriptor(false, true)
        )

        # static String format(String, Object...)
        format = Reflection.MethodDescriptor(
            "format",
            Reflection.ClassDescriptor(C_NULL, :JString, :jobject, "Ljava/lang/String;"),
            [
                Reflection.ClassDescriptor(C_NULL, :JString, :jobject, "Ljava/lang/String;"),
                Reflection.ClassDescriptor(
                    C_NULL,
                    :(Vector{JObject}),
                    :jobjectArray,
                    "[Ljava/lang/Object;",
                    Reflection.ClassDescriptor(C_NULL, :JObject, :jobject, "Ljava/lang/Object;")
                )
            ],
            Reflection.ModifiersDescriptor(true, true)
        )

        # void getChars(int, int, char[], int)
        getchars = Reflection.MethodDescriptor(
            "getChars",
            Reflection.ClassDescriptor(C_NULL, :Nothing, :jvoid, "V"),
            [
                Reflection.ClassDescriptor(C_NULL, :Int32, :jint, "I"),
                Reflection.ClassDescriptor(C_NULL, :Int32, :jint, "I"),
                Reflection.ClassDescriptor(
                    C_NULL,
                    :(Vector{Char}),
                    :jcharArray,
                    "[C",
                    Reflection.ClassDescriptor(C_NULL, :Char, :jchar, "C")),
                Reflection.ClassDescriptor(C_NULL, :Int32, :jint, "I")
            ],
            Reflection.ModifiersDescriptor(false, true)
        )

        for m in methods
            if getbytes == m
                found_getbytes = true
            elseif equals == m
                found_equals = true
            elseif format == m
                found_format = true
            elseif getchars == m
                found_getchars = true
            end
        end
        @test found_getbytes
        @test found_equals
        @test found_format
        @test found_getchars
    end

    @testset "Find Declared Methods" begin
        methods = Reflection.classdeclaredmethods(Symbol("java.lang.String"))
        @test length(methods) > 0
        @test_isa methods Vector{Reflection.MethodDescriptor}

        found_getbytes = false
        found_equals = false
        found_format = false
        found_notify = false

        # byte[] getBytes()
        getbytes = Reflection.MethodDescriptor(
            "getBytes",
            Reflection.ClassDescriptor(
                C_NULL,
                :(Vector{Int8}),
                :jbyteArray,
                "[B",
                Reflection.ClassDescriptor(C_NULL, :Int8, :jbyte, "B")
            ),
            [],
            Reflection.ModifiersDescriptor(false, true)
        )

        # boolean equals(Object)
        equals = Reflection.MethodDescriptor(
            "equals",
            Reflection.ClassDescriptor(C_NULL, :Bool, :jboolean, "Z"),
            [Reflection.ClassDescriptor(C_NULL, :JObject, :jobject, "Ljava/lang/Object;")],
            Reflection.ModifiersDescriptor(false, true)
        )

        # static String format(String, Object...)
        format = Reflection.MethodDescriptor(
            "format",
            Reflection.ClassDescriptor(C_NULL, :JString, :jobject, "Ljava/lang/String;"),
            [
                Reflection.ClassDescriptor(C_NULL, :JString, :jobject, "Ljava/lang/String;"),
                Reflection.ClassDescriptor(
                    C_NULL,
                    :(Vector{JObject}),
                    :jobjectArray,
                    "[Ljava/lang/Object;",
                    Reflection.ClassDescriptor(C_NULL, :JObject, :jobject, "Ljava/lang/Object;")
                )
            ],
            Reflection.ModifiersDescriptor(true, true)
        )

        # void notify()
        notify = Reflection.MethodDescriptor(
            "notify",
            Reflection.ClassDescriptor(C_NULL, :Nothing, :jvoid, "V"),
            [],
            Reflection.ModifiersDescriptor(false, true)
        )

        for m in methods
            if getbytes == m
                found_getbytes = true
            elseif equals == m
                found_equals = true
            elseif format == m
                found_format = true
            elseif notify == m
                found_notify = true
            end
        end
        @test found_getbytes
        # Equals is declared, as it is overriden, and should be found
        @test found_equals
        @test found_format
        # Notify is inherited and should not be found
        @test_false found_notify
    end

    @testset "Find Constructors" begin
        constructors = Reflection.classconstructors(Symbol("java.lang.String"))

        @test length(constructors) > 0
        @test_isa constructors Vector{Reflection.ConstructorDescriptor}

        found_bytes = false
        found_chars = false
        found_string = false
        found_builder = false

        # String(byte[] bytes, int offset, int length, Charset charset)
        bytes = Reflection.ConstructorDescriptor([
            Reflection.ClassDescriptor(
                C_NULL,
                :(Vector{Int8}),
                :jbyteArray,
                "[B",
                Reflection.ClassDescriptor(C_NULL, :Int8, :jbyte, "B")),
            Reflection.ClassDescriptor(C_NULL, :Int32, :jint, "I"),
            Reflection.ClassDescriptor(C_NULL, :Int32, :jint, "I"),
            Reflection.ClassDescriptor(C_NULL, :JCharset, :jobject, "Ljava/nio/charset/Charset;")
        ])

        # String(char[] value, int offset, int count)
        chars = Reflection.ConstructorDescriptor([
            Reflection.ClassDescriptor(
                C_NULL,
                :(Vector{Char}),
                :jcharArray,
                "[C",
                Reflection.ClassDescriptor(C_NULL, :Char, :jchar, "C")),
            Reflection.ClassDescriptor(C_NULL, :Int32, :jint, "I"),
            Reflection.ClassDescriptor(C_NULL, :Int32, :jint, "I")
        ])

        # String(String original)
        string = Reflection.ConstructorDescriptor([
            Reflection.ClassDescriptor(C_NULL, :JString, :jobject, "Ljava/lang/String;")
        ])

        # String(StringBuilder builder)
        builder = Reflection.ConstructorDescriptor([
            Reflection.ClassDescriptor(C_NULL, :JStringBuilder, :jobject, "Ljava/lang/StringBuilder;")
        ])

        for c in constructors
            if c == bytes
                found_bytes = true
            elseif c == chars
                found_chars = true
            elseif c == string
                found_string = true
            elseif c == builder
                found_builder = true
            end
        end

        @test found_bytes
        @test found_chars
        @test found_string
        @test found_builder
    end

    @testset "Find Fields" begin
        fields = Reflection.classfields(Symbol("Test"))
        @test length(fields) > 0

        foundboolean = false
        foundinteger = false
        foundstring = false
        foundobjectarr = false

        booleanfield = Reflection.FieldDescriptor(
            "booleanField",
            Reflection.ClassDescriptor(C_NULL, :Bool, :jboolean, "Z"),
            Reflection.ModifiersDescriptor(false, true)
        )

        integerfield = Reflection.FieldDescriptor(
            "integerField",
            Reflection.ClassDescriptor(C_NULL, :Int32, :jint, "I"),
            Reflection.ModifiersDescriptor(true, true)
        )

        stringfield = Reflection.FieldDescriptor(
            "stringField",
            Reflection.ClassDescriptor(C_NULL, :JString, :jobject, "Ljava/lang/String;"),
            Reflection.ModifiersDescriptor(false, true)
        )

        objectarrfield = Reflection.FieldDescriptor(
            "objectArrField",
            Reflection.ClassDescriptor(
                C_NULL,
                :(Vector{JObject}),
                :jobjectArray,
                "[Ljava/lang/Object;",
                Reflection.ClassDescriptor(C_NULL, :JObject, :jobject, "Ljava/lang/Object;")
            ),
            Reflection.ModifiersDescriptor(false, true)
        )

        for f in fields
            if f == booleanfield
                foundboolean = true
            elseif f == integerfield
                foundinteger = true
            elseif f == stringfield
                foundstring = true
            elseif f == objectarrfield
                foundobjectarr = true
            end
        end

        @test foundboolean
        @test foundinteger
        @test foundstring
        @test foundobjectarr
    end
end


text:
# Copyright 2022 RelationalAI, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Functions for accessing transaction results, including an implementation
# of the Tables.jl interfaces.

import JSON3
import Tables

struct TransactionResult
    _data::JSON3.Object
end

_data(result::TransactionResult) = getfield(result, :_data)

Base.getindex(result::TransactionResult, key) = _data(result)[key]

function Base.propertynames(result::TransactionResult, private::Bool=false)
    data = _data(result)
    names = (keys(data)..., :relations)
    if private
        names = (names..., fieldnames(TransactionResult)...)
    end
    return names
end
function Base.getproperty(result::TransactionResult, name::Symbol)
    name in fieldnames(TransactionResult) && return getfield(result, name)
    data = _data(result)
    name == :relations && return Relations(data.output)
    return data[name]
end

function Base.show(io::IO, result::TransactionResult)
    if result.aborted
        println(io, "aborted")
        return nothing
    end
    count = 0
    for relation in result.relations
        if relation.name == "abort" && length(schema(relation)) == 0
            continue  # ignore ic results
        end
        count > 0 && println(io)
        show(io, relation)
        count += 1
    end
    show_problems(result)
end

show_result(io::IO, rsp::JSON3.Object) = show(io, TransactionResult(rsp))
show_result(rsp::JSON3.Object) = show(stdout, TransactionResult(rsp))

"""
    show_problems([io::IO], rsp)

Print the problems associated with the given transaction response to the output
stream `io`.
"""
function show_problems(io::IO, rsp::JSON3.Object)
    isnothing(rsp) && return nothing
    @assert rsp.type == "TransactionResult"
    problems = rsp.problems
    isnothing(problems) && return nothing
    for (i, problem) in enumerate(problems)
        if get(problem, "is_error", false)
            kind = "error: "
        elseif get(problem, "is_exception", false)
            kind = "exception: "
        else
            kind = ""
        end
        i > 1 && println(io)
        println(io, "$kind$(problem.message)")
        report = get(problem, "report", nothing)
        isnothing(report) && continue
        println(io, strip(report))
    end
    return nothing
end

show_problems(rsp::JSON3.Object) = show_problems(stdout, rsp)
show_problems(result::TransactionResult) = show_problems(_data(result))
show_problems(io::IO, result::TransactionResult) = show_problems(io, _data(result))

struct Relations
    _data::JSON3.Array
end

_data(relations::Relations) = getfield(relations, :_data)

Base.getindex(relations::Relations, key::Int) = Relation(_data(relations)[key])

Base.length(relations::Relations) = length(_data(relations))

function Base.iterate(relations::Relations, i = 1)
    data = _data(relations)
    i > length(data) && return nothing
    item = data[i]
    return Relation(item), i + 1
end

struct Relation
    _data::JSON3.Object
    _types::Vector{Type}
    _names::Vector{Symbol}
    _getrow::Function

    function Relation(data)
        item = data.rel_key
        relkey = cat(item.keys, item.values; dims = 1)
        types = [datatype(rtype) for rtype in relkey]
        names = [Symbol("Column$i") for i in 1:length(types)]
        getrow = _make_getrow(relkey, data.columns)
        return new(data, types, names, getrow)
    end
end

_data(relation::Relation) = getfield(relation, :_data)
_names(relation::Relation) = getfield(relation, :_names)
_types(relation::Relation) = getfield(relation, :_types)
_getrow(relation::Relation) = getfield(relation, :_getrow)

# Returns a getrow lambda function that returns the requested row number as a
# `Tuple` of values. This function "lowers" symbols from type space to values
# in the corresponding position in the tuple.
function _make_getrow(relkey, columns)
    if columns == [[]]
        # Special case for when the relation is `true` in rel (only contains `()`):
        # This means that the relation is _only specialized values_, so we can just return
        # the specialized values from the relkey directly.
        return row -> _relname_to_symbol.(Tuple(relkey))
    end
    col = 1
    getters = []
    for item in relkey
        if startswith(item, ":")  # symbol
            let sym = _relname_to_symbol(item)
                push!(getters, _ -> sym)
            end
        else
            let col = col
                push!(getters, row -> columns[col][row])
            end
            col += 1
        end
    end
    @assert col == length(columns) + 1  "for $relkey: $col != $(length(columns) + 1)"
    @assert length(getters) == length(relkey)
    return row -> Tuple(getter(row) for getter in getters)
end
_relname_to_symbol(relname::String) = Symbol(relname[2:end])

Base.eltype(::Relation) = RelRow
Base.getindex(relation::Relation, key::Int) = getrow(relation, key)

function Base.propertynames(relation::Relation, private::Bool=false)
    data = _data(relation)
    names = (keys(data)..., :name)
    if private
        names = (names..., fieldnames(Relation)...)
    end
    return names
end
function Base.getproperty(relation::Relation, name::Symbol)
    name in fieldnames(Relation) && return getfield(result, name)
    data = _data(relation)
    name == :name && return data.rel_key.name
    return _data(relation)[name]
end

function Base.iterate(relation::Relation, i = 1)
    i > length(relation) && return nothing
    return RelRow(relation, i), i + 1
end

function Base.length(relation::Relation)
    cols = _data(relation).columns
    length(cols) == 0 && return 0  # empty relation
    return length(cols[1])
end

function getrow(relation::Relation, row::Int)::Tuple
    return _getrow(relation)(row)
end

function Base.show(io::IO, relation::Relation)
    types = ["$item" for item in schema(relation)]
    sig = join(types, "/")
    println(io, "// $(relation.name) $sig")
    for (i, row) in enumerate(relation)
        i > 1 && println(io, ";")
        values = [_gen_literal(item) for item in row]
        print(io, join(values, ", "))
    end
    println(io)
    return nothing
end

schema(relation::Relation) = _types(relation)

# todo: review list of rel primitive types
const _typemap = Dict{String,DataType}(
    "Any" => Any,          # todo
    "AutoNumber" => Int,   # todo
    "Date" => String,      # todo
    "DateTime" => String,  # todo
    "Char" => Char,
    "RelationalAITypes.FilePos" => Int,
    "Float16" => Float16,
    "Float32" => Float32,
    "Float64" => Float64,
    "Hash" => String,      # todo
    "Missing" => Nothing,
    "Int8" => Int8,
    "Int16" => Int16,
    "Int32" => Int32,
    "Int64" => Int64,
    "Int128" => Int128,
    "RelName" => String,
    "String" => String,
    "Symbol" => Symbol,
    "UInt8" => UInt8,
    "UInt16" => UInt16,
    "UInt32" => UInt32,
    "UInt64" => UInt64,
    "UInt128" => UInt128)

# Returns the Julia data type corresponding to the given Rel type string.
function datatype(reltype::String)
    dt = get(_typemap, reltype, nothing)
    !isnothing(dt) && return dt
    startswith(reltype, ":") && return Symbol
    @assert false "unknown type: $reltype"
    return nothing
end

# Implementation of the Tables.jl `AbstractRow` interface.

Tables.columnnames(relation::Relation) = _names(relation)
Tables.istable(::Type{Relation}) = true
Tables.rowaccess(::Type{Relation}) = true
Tables.rows(relation::Relation) = relation

function Tables.schema(relation::Relation)
    return Tables.Schema(_names(relation), _types(relation))
end

struct RelRow <: Tables.AbstractRow
    _relation::Relation
    values::Tuple

    function RelRow(relation::Relation, row::Int)
        new(relation, getrow(relation, row))
    end
end

_names(row::RelRow) = _names(_relation(row))
_relation(row::RelRow) = getfield(row, :_relation)
_values(row::RelRow) = getfield(row, :values)
_indexof(row, name) = findfirst(==(name), _names(row))

Base.getindex(row::RelRow, key::Int) = _values(row)[key]

function Base.propertynames(row::RelRow)
    return (_names(row)..., fieldnames(RelRow))
end
function Base.getproperty(row::RelRow, name::Symbol)
    name in _names(row) && return getcolumn(row, name)
    return getfield(row, name)
end

getcolumn(row::RelRow, col::Int) = _values(row)[col]

function getcolumn(row::RelRow, name::Symbol)
    col = _indexof(row, name)
    return _values(row)[col]
end

Tables.columnnames(row::RelRow) = _names(row)
Tables.getcolumn(row::RelRow, col::Int) = getcolumn(row, col)
Tables.getcolumn(row::RelRow, name::Symbol) = getcolumn(row, name)

max_stars_repo_name: RelationalAI/rai-sdk-julia

max_issues_repo_name: RelationalAI/rai-sdk-julia

max_forks_repo_name: RelationalAI/rai-sdk-julia


text:
const ACUMatrix{T} = Union{CuMatrix{T}, CUDA.CUSPARSE.CuSparseMatrix{T}}

@testset "cuda/gnngraph" begin
    s = [1,1,2,3,4]
    t = [2,5,3,5,5]
    s, t = [s; t], [t; s]  #symmetrize
    g = GNNGraph(s, t, graph_type=GRAPH_T)
    g_gpu = g |> gpu

    @testset "functor" begin
        s_cpu, t_cpu = edge_index(g)
        s_gpu, t_gpu = edge_index(g_gpu)
        @test s_gpu isa CuVector{Int}
        @test Array(s_gpu) == s_cpu
        @test t_gpu isa CuVector{Int}
        @test Array(t_gpu) == t_cpu
    end

    @testset "adjacency_matrix" begin
        # See https://github.com/JuliaGPU/CUDA.jl/pull/1093

        mat = adjacency_matrix(g)
        mat_gpu = adjacency_matrix(g_gpu)
        @test mat_gpu isa ACUMatrix{Int}
        @test Array(mat_gpu) == mat
    end

    @testset "normalized_laplacian" begin
        mat = normalized_laplacian(g)
        mat_gpu = normalized_laplacian(g_gpu)
        @test mat_gpu isa ACUMatrix{Float32}
        @test Array(mat_gpu) == mat
    end

    @testset "scaled_laplacian" begin
        @test_broken begin
            mat = scaled_laplacian(g)
            mat_gpu = scaled_laplacian(g_gpu)
            @test mat_gpu isa ACUMatrix{Float32}
            @test Array(mat_gpu) == mat
        end
    end
end


text:
using PEGParser

@grammar lispgrammar begin
  start = cell{ _1 }
  expr = lst | atom
  cell = list(expr, space)
  lst = (lparen + +(cell) + rparen){ _2.children }
  atom = string | boolean | number | sym
  boolean = ("#t" | "#f"){ _1 == "#t" ? true : false }
  number = (-space + float){ parse(Float64, _1.value) } | (-space + integer){ parse(Int, _1.value) }
  string = (dquote + r"[^\"]*" + dquote){ _2.value }
  sym = r"[^() ]+"{ symbol(_0) }

  dquote = "\""
  lparen = "("
  rparen = ")"
  space = r"[ \n\r\t]*"
end

toexpr(node, cvalues, ::MatchRule{:start}) = cvalues

function toexpr(node, cvalues, ::MatchRule{:cell})
  if length(cvalues) > 1
    return Expr(:call, cvalues...)
  else
    return cvalues[1]
  end
end

data = "(println \"test: \" (* 10 (- 5 6)))"
(ast, pos, error) = parse(lispgrammar, data)
println(ast)
code = transform(toexpr, ast)
dump(code)
println("code: $(code)")
eval(code)


text:
# NOTE: filter is special because we may need to decompose into filter + joins
function build_node_ex!(stash, join_hist, ::Type{Filter}, args, index, primary)
    join_arg_idxs, filter_arg_idxs = Vector{Int}(), Vector{Int}()
    process_args!(stash, join_hist, Filter, args, index, primary)
end

"""

The strategy is to sort the args into filters that happen before the join,
join arguments, and filters that happen after the join.
"""
# NOTE: :filter has its own definition because it may be decomposed into
#       filters and join
function process_args!(stash, join_hist, ::Type{Filter}, exs, index, primary)::Tuple{Expr, Set{Symbol}}
    # for an early (before join) filter -- i.e., a filters that only concerns a
    # single source -- we don't know join path until we inspect which source is used
    # map a source to a vector of args
    early_filters = Dict{Set{Symbol}, Vector{Expr}}()
    early_srcs_used = Set{Symbol}()

    join_srcs_used = Set{Symbol}()
    join_args = Vector{Expr}()
    join_helpers_ex = Expr(:ref, InnerJoin)

    # TODO: there may be late filters that join sources not involved in the join!!
    # Take care of those!!!
    # late_filter_srcs_used = Set{Symbol}()
    late_filter_args = Vector{Expr}()

    for ex in exs
        # look for equijoins
        if ex.head == :call && ex.args[1] == :(==)
            # NOTE: Not particurlaly efficient, should probably just check
            # whether join or filter and not build a helper_ex
            verb, srcs_used, helper_ex = join_or_filter(ex, join_hist, index)
            if verb == :join
                union!(join_srcs_used, srcs_used)
                push!(join_helpers_ex.args, helper_ex)
                push!(join_args, ex)
            elseif verb == :filter
                if length(srcs_used) == 1 # so, an early filter
                    _early_filter_args, = get!(
                        early_filters, srcs_used, Vector{Expr}()
                    )
                    push!(_early_filter_args, ex)
                    push!(early_srcs_used, first(srcs_used))
                else
                    push!(late_filter_args, ex)
                end
            end
        else # definitely a filter -- is it early or late?
            srcs_used = Set{Symbol}()
            # NOTE: Again, not efficient! Check for sources used, then build
            # f_ex later!
            f_ex = build_f_ex!(srcs_used, ex, index, primary)
            helper_ex = Expr(:call, Filter, Expr(:tuple, f_ex))
            # check if the srcs_used have previously been joined, since this determines
            # whether the filter is early or late
            unique_src_hists = unique([ join_hist[src] for src in srcs_used ])
            if length(unique_src_hists) == 1 # early
                _early_filter_args = get!(
                    early_filters, first(unique_src_hists), Vector{Expr}()
                )
                push!(_early_filter_args, ex)
                union!(early_srcs_used, srcs_used)
            else # late
                push!(late_filter_args, ex)
            end
        end
    end

    # If there is no join, assume we can just throw everything in there ...
    # NOTE: But this throws away late filters, which is inconsistent with how
    # we handle unmerged join histories elsewhere.
    if length(join_args) == 0
        src_nodes_ex = Expr(:tuple)
        # if just an early join, should only be one src_hist
        # TODO: handle case where multipe src_hists (what should that behavior be?
        #       It should probably just error -- maybe we need a principle, that
        #       each manipulation verb must only return a single table)
        # @assert length(keys(early_filters)) == 1

        src_hist = first(keys(early_filters))
        push!(src_nodes_ex.args, stash[src_hist])
        _args = early_filters[src_hist]
        args = aggregate(_args)
        f_ex, ai = build_f_ex!(Set{Symbol}(), args, index, primary)
        # @show f_ex
        helpers_ex = Expr(:ref, Filter, Expr(:call, Filter, f_ex, ai))
        early_filter_node_ex = Expr(
            :call, Node{Filter}, src_nodes_ex, _args, helpers_ex
        )

        return early_filter_node_ex, early_srcs_used
    end

    # if there is a join ...

    for src_hist in keys(early_filters)
        node_ex = stash[src_hist]
        _args = early_filters[src_hist]
        args = aggregate(_args)
        f_ex, ai = build_f_ex!(Set{Symbol}(), args, index, primary)
        # @show f_ex
        helpers_ex = Expr(:ref, Filter, Expr(:call, Filter, f_ex, ai))
        stash[src_hist] = Expr(
            :call, Node{Filter}, Expr(:tuple, node_ex), _args, helpers_ex
        )
    end

    join_src_nodes_ex = Expr(:tuple)
    # unique should be redundant... TODO: straighten out this logic
    for src_hist in unique([ join_hist[src] for src in join_srcs_used ])
        push!(join_src_nodes_ex.args, stash[src_hist])
    end

    join_node_ex = Expr(
        :call, Node{:innerjoin}, join_src_nodes_ex,
        join_args, join_helpers_ex
    )

    # If there are late filters...
    if length(late_filter_args) > 0
        args = aggregate(late_filter_args)
        # TODO: don't throw away the sources used information
        f_ex, ai = build_f_ex!(Set{Symbol}(), args, index, primary)
        helpers_ex = Expr(:ref, Filter, Expr(:call, Filter, f_ex, ai))
        late_filter_node_ex = Expr(
            :call, Node{Filter}, Expr(:tuple, join_node_ex), late_filter_args,
            helpers_ex
        )
        return late_filter_node_ex, join_srcs_used
    else
        return join_node_ex, join_srcs_used
    end

    # NOTE: We are assuming here that no late filters mention sources not
    # involved in the join AND that all sources involved in early filters are involved in the join

    # NOTE: Currently, one can include early filters that refer to histories that
    # are not referenced in the join and hence are not included in the resultant
    # node. We should raise a warning
end

"""

Decide whether a query arg that looks like `lhs == rhs` should belong to a
join node or to a filter node.
"""
function join_or_filter(ex, join_hist, index)::Tuple{Symbol, Set{Symbol}, Expr}
    srcs_used1, srcs_used2 = Set{Symbol}(), Set{Symbol}() # lhs, rhs
    lhs, rhs = ex.args[2], ex.args[3]
    f_ex1, arg_fields1 = build_f_ex!(srcs_used1, lhs, index, primary)
    f_ex2, arg_fields2 = build_f_ex!(srcs_used2, rhs, index, primary)
    nsrcs1, nsrcs2 = length(srcs_used1), length(srcs_used2)

    # check if histories of sources on each side are unmerged
    # (this would entail a non-equijoin, which are not currently supported)
    src_hists1 = unique([ join_hist[src] for src in srcs_used1 ])
    src_hists2 = unique([ join_hist[src] for src in srcs_used2 ])
    if (length(src_hists1) > 1) | (length(src_hists2) > 1)
        throw(ArgumentError("This type of join not (yet) supported."))
    end
    # now we know that each side's histories have been joined somewhere in past,
    # or one side refers to no sources (just literals or names from enclosing scope)
    if length(src_hists1) * length(src_hists2) == 0 # filter
        srcs_used = Set{Symbol}()
        f_ex = build_f_ex!(srcs_used, ex, index, primary)
        return :filter, srcs_used,
               Expr(:call, Filter, Expr(:tuple, f_ex))
    else # join
        return :join, union(srcs_used1, srcs_used2),
            Expr(
                :call, InnerJoin,
                Expr(
                    :tuple, Expr(:tuple, f_ex1, f_ex2),
                    Expr(:tuple, arg_fields1, arg_fields2)
                )
            )
    end
end

aggregate(args) = foldl((x,y)->:( $x & $y ), args)


text:
# ---
# title: 783. Minimum Distance Between BST Nodes
# id: problem783
# author: Tian Jun
# date: 2020-10-31
# difficulty: Easy
# categories: Tree, Recursion
# link: <https://leetcode.com/problems/minimum-distance-between-bst-nodes/description/>
# hidden: true
# ---
#
# Given a Binary Search Tree (BST) with the root node `root`, return the minimum
# difference between the values of any two different nodes in the tree.
#
# **Example :**
#
#
#
#     Input: root = [4,2,6,1,3,null,null]
#     Output: 1
#     Explanation:
#     Note that root is a TreeNode object, not an array.
#
#     The given tree [4,2,6,1,3,null,null] is represented by the following diagram:
#
#               4
#             /   \
#           2      6
#          / \
#         1   3
#
#     while the minimum difference in this tree is 1, it occurs between node 1 and node 2, also between node 3 and node 2.
#
#
# **Note:**
#
#   1. The size of the BST will be between 2 and `100`.
#   2. The BST is always valid, each node's value is an integer, and each node's value is different.
#   3. This question is the same as 530: <https://leetcode.comhttps://leetcode.com/problems/minimum-absolute-difference-in-bst/>
#
#
## @lc code=start
using LeetCode

## add your code here:
## @lc code=end


text:
<!DOCTYPE html>

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

Incorrect username or password.
Signup error. Maybe that user already exists?
Login

<form action="/auth/login" method="post">
    <input type="hidden" name="goto" value=goto>
    username:
    <input type="text" name="username" id="loginUsername">

    password:
    <input type="password" name="password" id="loginPassword">

    <input type="submit" value="login">
</form>

Create Account

<form action="/auth/create_account" method="post">
    <input type="hidden" name="goto" value=goto>
    username:
    <input type="text" name="username" id="signupUsername">

    password:
    <input type="password" name="password" id="signupPassword">

    <input type="submit" value="create account">
</form>


text:
module ForDisplayStructs
using Base: Int32, isvisible
export ScrollCallbackSubscribable, KeyboardCallbackSubscribable, MouseCallbackSubscribable,MouseStruct,parameter_type,Mask,TextureSpec,forDisplayObjects, ActorWithOpenGlObjects, KeyboardStruct,TextureUniforms,MainImageUniforms, MaskTextureUniforms,ForWordsDispStruct

using ColorTypes,Parameters,Observables,ModernGL,GLFW,Rocket, Dictionaries,FreeTypeAbstraction, ..DataStructs

"""
data needed for definition of mask  - data that will be displayed over main image
this struct is parametarized by type of 3 dimensional array that will be used  to store data
"""
@with_kw  struct Mask{arrayType}
  path::String #path to this file in Hdf5
  maskId::Int64 #unique associated with id taken from Hdf5 file system
  maskName::String #unique for class not unique for instance for example it can be name of the organ that will be segmented - need to be unique in instance but across instances needs to be named the same
  maskArrayObs::Observable{Array{arrayType}} # observable array used to store information that will be displayed over main image
  colorRGBA::RGBA #associated RGBA  that will be displayed based on the values in maskArrayObs
end
"""
hold reference numbers that will be used to access and modify given uniform value in a shader
"""
abstract type TextureUniforms end

"""
hold reference numbers that will be used to access and modify given uniform value
In order to have easy fast access to the values set the most recent values will also be stored inside
In order to improve usability  we will also save with what data type this mask is associated
for example Int, uint, float etc
"""
@with_kw struct MaskTextureUniforms <: TextureUniforms
samplerName::String =""#name of the sampler - mainly for debugging purposes
samplerRef ::Int32 =Int32(0) #reference to sampler of the texture
colorsMaskRef ::Int32 =Int32(0) #reference to uniform holding color of this mask
isVisibleRef::Int32 =Int32(0)# reference to uniform that points weather we
maskMinValue::Int32 =Int32(0)# minimum value associated with possible value of mask
maskMAxValue::Int32 =Int32(0)# maximum value associated with possible value of mask
maskRangeValue::Int32 =Int32(0)# range of values associated with possible value of mask
maskContribution::Int32 =Int32(0)# controlls contribution  of given mask to the overall image - maximum value is 1 minimum 0 if we have 3 masks and all control contribution is set to 1 and all are visible their corresponding influence to pixel color is 33%
end

"""
Holding references to ..Uniforms used to controll main image
"""
@with_kw struct MainImageUniforms<: TextureUniforms
samplerName::String =""#name of the sampler - mainly for debugging purposes
samplerRef ::Int32 =Int32(0) #reference to   sampler of the texture
isVisibleRef::Int32 =Int32(0)# reference to uniform that points weather we
# ..Uniforms controlling windowing
min_shown_white::Int32 =Int32(0)
max_shown_black::Int32 =Int32(0)
displayRange::Int32 =Int32(0)
# ..Uniforms controlling  displaying masks diffrence
isMaskDiffrenceVis::Int32 =Int32(0)
mainImageContribution::Float32= 1.0 # controlls contribution  of given mask to the overall image - maximum value is 1 minimum 0 if we have 3 masks and all control contribution is set to 1 and all are visible their corresponding influence to pixel color is 33%

end

"""
Holding the data needed to create and  later reference the textures

name::String=""               #human readable name by which we can reference texture
numb::Int32 =-1               #needed to enable swithing between textures generally convinient when between 0-9; needed only if texture is to be modified by mouse input
whichCreated::Int32 =-1       #marks which one this texture was when created - so first in list second ... - needed for convinient accessing ..Uniforms in shaders
isMainImage ::Bool = false  #true if this texture represents main image
isNuclearMask ::Bool = false # used for example in case of nuclear imagiing studies
isContinuusMask ::Bool = false # in case of masks if mask is continuus color display we set multiple colors in a vector
color::RGB = RGB(0.0,0.0,0.0) #needed in case for the masks in order to establish the range of colors we are intrested in in case of binary mask there is no point to supply more than one color (supply Vector with length = 1)
colorSet::Vector{RGB}=[]    #set of colors that can be used for mask with continous values
strokeWidth::Int32 =Int32(3)#marking how thick should be the line that is left after acting with the mouse ...
isEditable::Bool =false     #if true we can modify given  texture using mouse interaction
GL_Rtype::UInt32 =UInt32(0)           #GlRtype - for example GL_R8UI or GL_R16I
OpGlType ::UInt32 =UInt32(0)          #open gl type - for example GL_UNSIGNED_BYTE or GL_SHORT
actTextrureNumb ::UInt32 =UInt32(0)          #usefull to be able to activate the texture using GL_Activetexture - with proper open GL constant
associatedActiveNumer ::Int64 =Int64(0)          #usefull to be able to activate the texture using GL_Activetexture - with proper open GL constant
ID::Base.RefValue{UInt32} = Ref(UInt32(0))   #id of Texture
isVisible::Bool= true       #if false it should be invisible
uniforms::TextureUniforms=MaskTextureUniforms()# holds values needed to control ..Uniforms in a shader
minAndMaxValue::Vector{T} = []#entry one is minimum possible value for this mask, and second entry is maximum possible value for this mask

"""
@with_kw mutable struct TextureSpec{T}
  name::String=""               #human readable name by which we can reference texture
  numb::Int32 =-1               #needed to enable swithing between textures generally convinient when between 0-9; needed only if texture is to be modified by mouse input
  whichCreated::Int32 =-1       #marks which one this texture was when created - so first in list second ... - needed for convinient accessing ..Uniforms in shaders
  isMainImage ::Bool = false  #true if this texture represents main image
  isNuclearMask ::Bool = false # used for example in case of nuclear imagiing studies
  isContinuusMask ::Bool = false # in case of masks if mask is continuus color display we set multiple colors in a vector
  color::RGB = RGB(0.0,0.0,0.0) #needed in case for the masks in order to establish the range of colors we are intrested in in case of binary mask there is no point to supply more than one color (supply Vector with length = 1)
  colorSet::Vector{RGB}=[]    #set of colors that can be used for mask with continous values
  strokeWidth::Int32 =Int32(3)#marking how thick should be the line that is left after acting with the mouse ...
  isEditable::Bool =false     #if true we can modify given  texture using mouse interaction
  GL_Rtype::UInt32 =UInt32(0)           #GlRtype - for example GL_R8UI or GL_R16I
  OpGlType ::UInt32 =UInt32(0)          #open gl type - for example GL_UNSIGNED_BYTE or GL_SHORT
  actTextrureNumb ::UInt32 =UInt32(0)          #usefull to be able to activate the texture using GL_Activetexture - with proper open GL constant
  associatedActiveNumer ::Int64 =Int64(0)          #usefull to be able to activate the texture using GL_Activetexture - with proper open GL constant
  ID::Base.RefValue{UInt32} = Ref(UInt32(0))   #id of Texture
  isVisible::Bool= true       #if false it should be invisible
  uniforms::TextureUniforms=MaskTextureUniforms()# holds values needed to control ..Uniforms in a shader
  minAndMaxValue::Vector{T} = []#entry one is minimum possible value for this mask, and second entry is maximum possible value for this mask
  maskContribution::Float32= 1.0 # controlls contribution  of given mask to the overall image - maximum value is 1 minimum 0 if we have 3 masks and all control contribution is set to 1 and all are visible their corresponding influence to pixel color is 33%
end

#utility function to check type associated
parameter_type(::Type{TextureSpec{T}}) where {T} = T
parameter_type(x::TextureSpec) = parameter_type(typeof(x))

"""
given Vector of TextureSpecs
it creates dictionary where keys are associated names
and values are indicies where they are found in a list
"""
function getLocationDict(listt)::Dictionary{String, Int64}
   return Dictionary(map(it->it.name,listt),collect(eachindex(listt)))

end#getLocationDict

"""
Defined in order to hold constant objects needed to display images
listOfTextSpecifications::Vector{TextureSpec} = [TextureSpec()]
window = []
vertex_shader::UInt32 =1
fragment_shader::UInt32=1
shader_program::UInt32=1
stopListening::Base.Threads.Atomic{Bool}= Threads.Atomic{Bool}(0)# enables unlocking GLFW context for futher actions
vbo::UInt32 =1 #vertex buffer object id
ebo::UInt32 =1 #element buffer object id
mainImageUniforms::MainImageUniforms = MainImageUniforms()# struct with references to main image
TextureIndexes::Dictionary{String, Int64}=Dictionary{String, Int64}()  #gives a way of efficient querying by supplying dictionary where key is a name we are intrested in and a key is index where it is located in our array
numIndexes::Dictionary{Int32, Int64} =Dictionary{Int32, Int64}() # a way for fast query using assigned numbers
gslsStr::String="" # string giving information about used openg gl gsls version
windowControlStruct::WindowControlStruct=WindowControlStruct()# holding data usefull to controll display window

"""
@with_kw  struct forDisplayObjects
  listOfTextSpecifications::Vector{TextureSpec} = [TextureSpec()]
  window = []
  vertex_shader::UInt32 =1
  fragment_shader::UInt32=1
  shader_program::UInt32=1
  stopListening::Base.Threads.Atomic{Bool}= Threads.Atomic{Bool}(0)# enables unlocking GLFW context for futher actions
  vbo::UInt32 =1 #vertex buffer object id
  ebo::UInt32 =1 #element buffer object id
  mainImageUniforms::MainImageUniforms = MainImageUniforms()# struct with references to main image
  TextureIndexes::Dictionary{String, Int64}=Dictionary{String, Int64}()  #gives a way of efficient querying by supplying dictionary where key is a name we are intrested in and a key is index where it is located in our array
  numIndexes::Dictionary{Int32, Int64} =Dictionary{Int32, Int64}() # a way for fast query using assigned numbers
  gslsStr::String="" # string giving information about used openg gl gsls version
  windowControlStruct::WindowControlStruct=WindowControlStruct()# holding data usefull to controll display window
end

"""
Holding necessery data to display text  - like font related
"""
@with_kw struct ForWordsDispStruct
fontFace::FTFont=FTFont(Ptr{FreeTypeAbstraction.FreeType.__JL_FT_FaceRec_}(),false) # font we will use to display text
textureSpec::TextureSpec =TextureSpec{UInt8}() # texture specification of texture used to display text
fragment_shader_words::UInt32=1 #reference to fragment shader used to display text
vbo_words::Base.RefValue{UInt32}=Ref(UInt32(1)) #reference to vertex buffer object used to display text
shader_program_words::UInt32=1

end #ForWordsDispStruct

"""
Holding necessery data to controll keyboard shortcuts

isCtrlPressed::Bool = false# left - scancode 37 right 105 - Int32
isShiftPressed::Bool = false # left - scancode 50 right 62- Int32
isAltPressed::Bool= false# left - scancode 64 right 108- Int32
isEnterPressed::Bool= false# scancode 36
isTAbPressed::Bool= false#
isSpacePressed::Bool= false#
isF1Pressed::Bool= false
isF2Pressed::Bool= false
isF3Pressed::Bool= false

lastKeysPressed::Vector{String}=[] # last pressed keys - it listenes to keys only if ctrl/shift or alt is pressed- it clears when we release those case or when we press enter
#informations about what triggered sending this particular struct to the  actor
mostRecentScanCode ::GLFW.Key=GLFW.KEY_KP_4
mostRecentKeyName ::String=""
mostRecentAction ::GLFW.Action= GLFW.RELEASE

"""
@with_kw struct KeyboardStruct
  isCtrlPressed::Bool = false# left - scancode 37 right 105 - Int32
  isShiftPressed::Bool = false # left - scancode 50 right 62- Int32
  isAltPressed::Bool= false# left - scancode 64 right 108- Int32
  isEnterPressed::Bool= false# scancode 36
  isTAbPressed::Bool= false#
  isSpacePressed::Bool= false#
  isF1Pressed::Bool= false
  isF2Pressed::Bool= false
  isF3Pressed::Bool= false
  isF4Pressed::Bool= false
  isF5Pressed::Bool= false
  isF6Pressed::Bool= false
  isPlusPressed::Bool= false
  isMinusPressed::Bool= false
  isZPressed::Bool= false
  lastKeysPressed::Vector{String}=[] # last pressed keys - it listenes to keys only if ctrl/shift or alt is pressed- it clears when we release those case or when we press enter
 #informations about what triggered sending this particular struct to the  actor
  mostRecentScanCode ::GLFW.Key=GLFW.KEY_KP_4
  mostRecentKeyName ::String=""
  mostRecentAction ::GLFW.Action= GLFW.RELEASE

end
"""
Holding necessery data to controll mouse interaction
"""
@with_kw struct MouseStruct
  isLeftButtonDown ::Bool = false # true if left button was pressed and not yet released
  isRightButtonDown ::Bool = false# true if right button was pressed and not yet released
  lastCoordinates::Vector{CartesianIndex{2}} = [] # list of accumulated mouse coordinates
end#MouseStruct

"""
struct that enables reacting to  the input  from mouse click  and drag the input will be
    Cartesian index represening (x,y)
     x and y position  of the mouse - will be recorded only if left mouse button is pressed or keep presssed
"""
@with_kw  mutable struct MouseCallbackSubscribable <: Subscribable{MouseStruct}
    #true if left button is presed down - we make it true if the left button is pressed over image and false if mouse get out of the window or we get information about button release
    isLeftButtonDown ::Bool
    isRightButtonDown ::Bool
    #coordinates marking 4 corners of
    #the quad that displays our medical image with the masks
    xmin::Int32
    ymin::Int32
    xmax::Int32
    ymax::Int32
#used to draw left button lines (creating lines)
 #store of the cartesian coordinates that is used to batch actions
#- so if mouse is moving rapidly we would store bunch of coordinates and then modify texture in batch
    coordinatesStoreForLeftClicks ::Vector{CartesianIndex{2}}
    lastCoordinate::CartesianIndex{2}#generally when we draw lines we remove points from array above yet w need to leave last one in order to keep continuity of futher line
    isBusy::Base.Threads.Atomic{Bool} # indicate to check weather the system is ready to receive the input

    subject :: Subject{MouseStruct} # coordinates of mouse

end

"""
Object that enables managing input from keyboard - it stores the information also about
needed keys wheather they are kept pressed
examples of keyboard input (raw GLFW input we process below)
    action RELEASE GLFW.Action
    key s StringPRESS
    key s String
    action PRESS GLFW.Action
    key s StringRELEASE
    key s String
    action RELEASE GLFW.Action

"""
@with_kw mutable struct KeyboardCallbackSubscribable <: Subscribable{KeyboardStruct}
# true when pressed and kept true until released
# true if corresponding keys are kept pressed and become flase when relesed
    isCtrlPressed::Bool= false # left - scancode 37 right 105 - Int32
    isShiftPressed::Bool = false # left - scancode 50 right 62- Int32
    isAltPressed::Bool= false# left - scancode 64 right 108- Int32
    isEnterPressed::Bool= false# scancode 36
    isTAbPressed::Bool= false# scancode 36
    isSpacePressed::Bool= false# scancode 36
    isF1Pressed::Bool= false
    isF2Pressed::Bool= false
    isF3Pressed::Bool= false
    isF4Pressed::Bool= false
    isF5Pressed::Bool= false
    isF6Pressed::Bool= false
    isPlusPressed::Bool= false
    isMinusPressed::Bool= false
    isZPressed::Bool= false
    lastKeysPressed::Vector{String}=[] # last pressed keys - it listenes to keys only if ctrl/shift or alt is pressed- it clears when we release those case or when we press enter
    subject :: Subject{KeyboardStruct} =Subject(KeyboardStruct, scheduler = AsyncScheduler())
end

"""
struct that enables reacting to  the input from scrolling
"""
mutable struct ScrollCallbackSubscribable <: Subscribable{Int64}
    isBusy::Base.Threads.Atomic{Bool} # indicate to check weather the system is ready to receive the input
    numberToSend::Int64# number  that will indicate how many slices to skip and in positive or negative direction
    subject :: Subject{Int64}
end

"""
Actor that is able to store a state to keep needed data for proper display

  currentDisplayedSlice::Int=1 # stores information what slice number we are currently displaying
    mainForDisplayObjects:: forDisplayObjects=forDisplayObjects() # stores objects needed to  display using OpenGL and GLFW
    onScrollData::FullScrollableDat = FullScrollableDat()
    textureToModifyVec::Vector{TextureSpec}=[] # texture that we want currently to modify - if list is empty it means that we do not intend to modify any texture
    isSliceChanged::Bool= false # set to true when slice is changed set to false when we start interacting with this slice - thanks to this we know that when we start drawing on one slice and change the slice the line would star a new on new slice
    textDispObj::ForWordsDispStruct =ForWordsDispStruct()# set of objects and constants needed for text diplay
    currentlyDispDat::SingleSliceDat =SingleSliceDat() # holds the data displayed or in case of scrollable data view for accessing it
    calcDimsStruct::CalcDimsStruct=CalcDimsStruct()   #data for calculations of necessary constants needed to calculate window size , mouse position ...
    valueForMasToSet::valueForMasToSetStruct=valueForMasToSetStruct() # value that will be used to set  pixels where we would interact with mouse
    lastRecordedMousePosition::CartesianIndex{3} = CartesianIndex(1,1,1) # last position of the mouse  related to right click - usefull to know onto which slice to change when dimensions of scroll change
    forUndoVector::AbstractArray=[] # holds lambda functions that when invoked will  undo last operations
    maxLengthOfForUndoVector::Int64 = 10 # number controls how many step at maximum we can get back
    isBusy::Base.Threads.Atomic{Bool}= Threads.Atomic{Bool}(0) # used to indicate by some functions that actor is busy and some interactions should be ceased

"""
@with_kw mutable struct ActorWithOpenGlObjects <: NextActor{Any}
    currentDisplayedSlice::Int=1 # stores information what slice number we are currently displaying
    mainForDisplayObjects:: forDisplayObjects=forDisplayObjects() # stores objects needed to  display using OpenGL and GLFW
    onScrollData::FullScrollableDat = FullScrollableDat()
    textureToModifyVec::Vector{TextureSpec}=[] # texture that we want currently to modify - if list is empty it means that we do not intend to modify any texture
    isSliceChanged::Bool= false # set to true when slice is changed set to false when we start interacting with this slice - thanks to this we know that when we start drawing on one slice and change the slice the line would star a new on new slice
    textDispObj::ForWordsDispStruct =ForWordsDispStruct()# set of objects and constants needed for text diplay
    currentlyDispDat::SingleSliceDat =SingleSliceDat() # holds the data displayed or in case of scrollable data view for accessing it
    calcDimsStruct::CalcDimsStruct=CalcDimsStruct()   #data for calculations of necessary constants needed to calculate window size , mouse position ...
    valueForMasToSet::valueForMasToSetStruct=valueForMasToSetStruct() # value that will be used to set  pixels where we would interact with mouse
    lastRecordedMousePosition::CartesianIndex{3} = CartesianIndex(1,1,1) # last position of the mouse  related to right click - usefull to know onto which slice to change when dimensions of scroll change
    forUndoVector::AbstractArray=[] # holds lambda functions that when invoked will  undo last operations
    maxLengthOfForUndoVector::Int64 = 15 # number controls how many step at maximum we can get back
    isBusy::Base.Threads.Atomic{Bool}= Threads.Atomic{Bool}(0) # used to indicate by some functions that actor is busy and some interactions should be ceased
    end

end #module


text:
# handling status and errors
const MESSAGE_BY_STATUS =
    Dict(CURAND_STATUS_SUCCESS => "CURAND_STATUS_SUCCESS",
         CURAND_STATUS_VERSION_MISMATCH => "CURAND_STATUS_VERSION_MISMATCH",
         CURAND_STATUS_NOT_INITIALIZED => "CURAND_STATUS_NOT_INITIALIZED",
         CURAND_STATUS_ALLOCATION_FAILED => "CURAND_STATUS_ALLOCATION_FAILED",
         CURAND_STATUS_TYPE_ERROR => "CURAND_STATUS_TYPE_ERROR",
         CURAND_STATUS_OUT_OF_RANGE => "CURAND_STATUS_OUT_OF_RANGE",
         CURAND_STATUS_LENGTH_NOT_MULTIPLE => "CURAND_STATUS_LENGTH_NOT_MULTIPLE",
         CURAND_STATUS_DOUBLE_PRECISION_REQUIRED =>
           "CURAND_STATUS_DOUBLE_PRECISION_REQUIRED",
         CURAND_STATUS_LAUNCH_FAILURE => "CURAND_STATUS_LAUNCH_FAILURE",
         CURAND_STATUS_PREEXISTING_FAILURE => "CURAND_STATUS_PREEXISTING_FAILURE",
         CURAND_STATUS_INITIALIZATION_FAILED =>
           "CURAND_STATUS_INITIALIZATION_FAILED",
         CURAND_STATUS_ARCH_MISMATCH => "CURAND_STATUS_ARCH_MISMATCH",
         CURAND_STATUS_INTERNAL_ERROR => "CURAND_STATUS_INTERNAL_ERROR")

function error_message(status::UInt32)
    return "cuRAND operation failed with status: " * MESSAGE_BY_STATUS[status]
end

function statuscheck(status::UInt32)
    if status != CURAND_STATUS_SUCCESS
        warn(error_message(status) * " ($status)")
        Base.show_backtrace(STDOUT, backtrace())
        throw(error_message(status))
    end
end

function create_generator(rng_type::Int=CURAND_RNG_PSEUDO_DEFAULT)
    aptr = Ptr{Void}[0]
    statuscheck(ccall((:curandCreateGenerator, libcurand),
                      curandStatus_t, (Ptr{Void}, Cint), aptr, rng_type))
    return RNG(aptr[1], rng_type)
end

function create_generator_host(rng_type::Int=CURAND_RNG_PSEUDO_DEFAULT)
    aptr = Ptr{Void}[0]
    statuscheck(ccall((:curandCreateGeneratorHost, libcurand),
                      curandStatus_t, (Ptr{Void}, Cint), aptr, rng_type))
    return RNG(aptr[1], rng_type)
end

function destroy_generator(rng::RNG)
    statuscheck(ccall((:curandDestroyGenerator, libcurand),
                      curandStatus_t, (Ptr{Void},), rng.ptr))
end

function get_version()
    ver = Ref{Cint}(0)
    statuscheck(ccall((:curandGetVersion, libcurand),
                      curandStatus_t, (Ref{Cint},), ver))
    return ver[]
end

# TODO: curandSetStream

function set_pseudo_random_generator_seed(rng::RNG, seed::Int64)
    statuscheck(ccall((:curandSetPseudoRandomGeneratorSeed, libcurand),
                      curandStatus_t, (Ptr{Void}, Clonglong), rng.ptr, seed))
end

function set_generator_offset(rng::RNG, offset::Int64)
    statuscheck(ccall((:curandSetGeneratorOffset, libcurand),
                      curandStatus_t, (Ptr{Void}, Clonglong), rng.ptr, offset))
end

function set_generator_ordering(rng::RNG, order::Int)
    statuscheck(ccall((:curandSetGeneratorOrdering, libcurand),
                      curandStatus_t, (Ptr{Void}, Cint), rng.ptr, order))
end

function set_quasi_random_generator_dimensions(rng::RNG, num_dimensions::UInt)
    statuscheck(ccall((:curandSetQuasiRandomGeneratorDimensions, libcurand),
                      curandStatus_t, (Ptr{Void}, Cuint),
                      rng.ptr, num_dimensions))
end

"""
Generate 64-bit quasirandom numbers.
"""
function generate(rng::RNG, n::UInt)
    sz = Int(n)
    arr = CudaArray(UInt32, sz)
    statuscheck(ccall((:curandGenerate, libcurand),
                      curandStatus_t, (Ptr{Void}, Ptr{UInt32}, Csize_t),
                      rng.ptr, arr.ptr.ptr, n))
    return arr
end

"""
Generate uniformly distributed floats.

Valid RNG types are:
 - CURAND_RNG_QUASI_SOBOL64
 - CURAND_RNG_QUASI_SCRAMBLED_SOBOL64
"""
function generate_long_long(rng::RNG, n::UInt)
    sz = Int(n)
    arr = CudaArray(UInt64, sz)
    statuscheck(ccall((:curandGenerateLongLong, libcurand),
                      curandStatus_t, (Ptr{Void}, Ptr{Culonglong}, Csize_t),
                      rng.ptr, arr.ptr.ptr, n))
    return arr
end

# uniform
function generate_uniform(rng::RNG, n::UInt)
    sz = Int(n)
    arr = CudaArray(Float32, sz)
    statuscheck(ccall((:curandGenerateUniform, libcurand),
                      curandStatus_t, (Ptr{Void}, Ptr{Float32}, Csize_t),
                      rng.ptr, arr.ptr.ptr, n))
    return arr
end

function generate_uniform_double(rng::RNG, n::UInt)
    sz = Int(n)
    arr = CudaArray(Float64, sz)
    statuscheck(ccall((:curandGenerateUniformDouble, libcurand),
                      curandStatus_t, (Ptr{Void}, Ptr{Float64}, Csize_t),
                      rng.ptr, arr.ptr.ptr, n))
    return arr
end

# normal
function generate_normal(rng::RNG, n::UInt, mean::Float32, stddev::Float32)
    sz = Int(n)
    arr = CudaArray(Float32, sz)
    statuscheck(ccall((:curandGenerateNormal, libcurand),
                      curandStatus_t,
                      (Ptr{Void}, Ptr{Float32}, Csize_t, Cfloat, Cfloat),
                      rng.ptr, arr.ptr.ptr, n, mean, stddev))
    return arr
end

function generate_normal_double(rng::RNG, n::UInt, mean::Float64, stddev::Float64)
    sz = Int(n)
    arr = CudaArray(Float64, sz)
    statuscheck(ccall((:curandGenerateNormalDouble, libcurand),
                      curandStatus_t,
                      (Ptr{Void}, Ptr{Float64}, Csize_t, Cdouble, Cdouble),
                      rng.ptr, arr.ptr.ptr, n, mean, stddev))
    return arr
end

# lognormal
function generate_log_normal(rng::RNG, n::UInt, mean::Float32, stddev::Float32)
    sz = Int(n)
    arr = CudaArray(Float32, sz)
    statuscheck(ccall((:curandGenerateLogNormal, libcurand),
                      curandStatus_t,
                      (Ptr{Void}, Ptr{Float32}, Csize_t, Cfloat, Cfloat),
                      rng.ptr, arr.ptr.ptr, n, mean, stddev))
    return arr
end

function generate_log_normal_double(rng::RNG, n::UInt, mean::Float64, stddev::Float64)
    sz = Int(n)
    arr = CudaArray(Float64, sz)
    statuscheck(ccall((:curandGenerateLogNormalDouble, libcurand),
                      curandStatus_t,
                      (Ptr{Void}, Ptr{Float64}, Csize_t, Cdouble, Cdouble),
                      rng.ptr, arr.ptr.ptr, n, mean, stddev))
    return arr
end

# Poisson
"""Construct the histogram array for a Poisson distribution."""
function create_poisson_distribtion(lambda::Float64)
    aptr = Ptr{Void}[0]
    statuscheck(ccall((:curandCreatePoissonDistribution, libcurand),
                      curandStatus_t, (Cdouble, Ptr{Void}), lambda, aptr))
    return DiscreteDistribution(aptr[1])
end

"""Destroy the histogram array for a discrete distribution (e.g. Poisson)."""
function destroy_distribution(dd::DiscreteDistribution)
    statuscheck(ccall((:curandDestroyDistribution, libcurand),
                      curandStatus_t, (Ptr{Void},), dd.ptr))
end

"""Generate Poisson-distributed unsigned ints."""
function generate_poisson(rng::RNG, n::UInt, lambda::Float64)
    sz = Int(n)
    arr = CudaArray(UInt32, sz)
    statuscheck(ccall((:curandGeneratePoisson, libcurand),
                      curandStatus_t,
                      (Ptr{Void}, Ptr{Cuint}, Csize_t, Cdouble),
                      rng.ptr, arr.ptr.ptr, n, lambda))
    return arr
end

# seeds
"""Generate the starting state of the generator. """
function generate_seeds(rng::RNG)
    statuscheck(ccall((:curandGenerateSeeds, libcurand),
                      curandStatus_t, (Ptr{Void},), rng.ptr))
end

# TODO: implement curandGetDirectionVectors32
# TODO: implement curandGetScrambleConstants32
# TODO: implement curandGetDirectionVectors64
# TODO: implement curandGetScrambleConstants64


text:
function make_operation(@nospecialize(op), args)
    if op === (*)
        args = filter(!_isone, args)
        if isempty(args)
            return 1
        end
    elseif op === (+)
        args = filter(!_iszero, args)
        if isempty(args)
            return 0
        end
    end
    return op(args...)
end

function build_expr(head::Symbol, args)
    ex = Expr(head)
    append!(ex.args, args)
    ex
end

# used in parsing
isblock(x) = length(x) == 1 && x[1] isa Expr && x[1].head == :block
function flatten_expr!(x)
    isb = isblock(x)
    if isb
        x = MacroTools.striplines(x[1])
        filter!(z->z isa Symbol || z.head != :line, x.args)
        x = (x.args...,)
    end
    x
end

function detime_dvs(op)
    if !istree(op)
        op
    elseif operation(op) isa Sym
        Sym{Real}(nameof(operation(op)))
    else
        similarterm(op, operation(op),detime_dvs.(arguments(op)))
    end
end

function retime_dvs(op::Sym,dvs,iv)
    Sym{FnType{Tuple{symtype(iv)}, Real}}(nameof(op))(iv)
end

function retime_dvs(op, dvs, iv)
    istree(op) ?
        similarterm(op, operation(op), retime_dvs.(arguments(op),(dvs,),(iv,))) :
        op
end

is_derivative(O::Term) = isa(operation(O), Differential)
is_derivative(::Any) = false

"""
    get_variables(O) -> Vector{Union{Sym, Term}}

Returns the variables in the expression. Note that the returned variables are
not wrapped in the `Num` type.

# Examples
```julia
julia> @parameters t
(t,)

julia> @variables x y z(t)
(x, y, z(t))

julia> ex = x + y + sin(z)
(x + y) + sin(z(t))

julia> ModelingToolkit.get_variables(ex)
3-element Vector{Any}:
 x
 y
 z(t)
```
"""
get_variables(e::Num, varlist=nothing) = get_variables(value(e), varlist)
get_variables!(vars, e, varlist=nothing) = vars

is_singleton(e::Term) = operation(e) isa Sym
is_singleton(e::Sym) = true
is_singleton(e) = false

get_variables!(vars, e::Number, varlist=nothing) = vars

function get_variables!(vars, e::Symbolic, varlist=nothing)
    if is_singleton(e)
        if isnothing(varlist) || any(isequal(e), varlist)
            push!(vars, e)
        end
    else
        foreach(x -> get_variables!(vars, x, varlist), arguments(e))
    end
    return (vars isa AbstractVector) ? unique!(vars) : vars
end

function get_variables!(vars, e::Equation, varlist=nothing)
  get_variables!(vars, e.rhs, varlist)
end

get_variables(e, varlist=nothing) = get_variables!([], e, varlist)

modified_states!(mstates, e::Equation, statelist=nothing) = get_variables!(mstates, e.lhs, statelist)

# variable substitution
# Piracy but mild
"""
    substitute(expr, s::Pair)
    substitute(expr, s::Dict)
    substitute(expr, s::Vector)

Performs the substitution on `expr` according to rule(s) `s`.

# Examples
```julia
julia> @parameters t
(t,)

julia> @variables x y z(t)
(x, y, z(t))

julia> ex = x + y + sin(z)
(x + y) + sin(z(t))

julia> substitute(ex, Dict([x => z, sin(z) => z^2]))
(z(t) + y) + (z(t) ^ 2)
```
"""
# cannot use Union{Pair, Vector, Dict} -- leads to ambiguity
substitute(expr::Num, s::Pair; kw...) = Num(substituter(s)(value(expr); kw...))
substitute(expr::Num, s::Vector; kw...) = Num(substituter(s)(value(expr); kw...))
substitute(expr::Num, s::Dict; kw...) = Num(substituter(s)(value(expr); kw...))
# TODO: move this to SymbolicUtils
substitute(expr, s::Pair; kw...) = substituter([s[1] => s[2]])(expr; kw...)
substitute(expr, s::Vector; kw...) = substituter(s)(expr; kw...)

substituter(pair::Pair) = substituter((pair,))
function substituter(pairs)
    dict = Dict(value(k) => value(v)  for (k, v) in pairs)
    (expr; kw...) -> SymbolicUtils.substitute(expr, dict; kw...)
end

macro showarr(x)
    n = string(x)
    quote
        y = $(esc(x))
        println($n, " = ", summary(y))
        Base.print_array(stdout, y)
        println()
        y
    end
end

@deprecate substitute_expr!(expr,s) substitute(expr,s)

function states_to_sym(states::Set)
    function _states_to_sym(O)
        if O isa Equation
            Expr(:(=), _states_to_sym(O.lhs), _states_to_sym(O.rhs))
        elseif istree(O)
            op = operation(O)
            args = arguments(O)
            if op isa Sym
                O in states && return tosymbol(O)
                # dependent variables
                return build_expr(:call, Any[nameof(op); _states_to_sym.(args)])
            else
                canonical, O = canonicalexpr(O)
                return canonical ? O : build_expr(:call, Any[op; _states_to_sym.(args)])
            end
        elseif O isa Num
            return _states_to_sym(value(O))
        else
            return toexpr(O)
        end
    end
end
states_to_sym(states) = states_to_sym(Set(states))

"""
    toparam(s::Sym) -> Sym{<:Parameter}

Maps the variable to a paramter.
"""
toparam(s::Sym) = Sym{Parameter{symtype(s)}}(s.name)
toparam(s::Sym{<:Parameter}) = s

"""
    tovar(s::Sym) -> Sym{Real}
    tovar(s::Sym{<:Parameter}) -> Sym{Real}

Maps the variable to a state.
"""
tovar(s::Sym{<:Parameter}) = Sym{symtype(s)}(s.name)
tovar(s::Sym) = s

Base.Symbol(x::Union{Num,Symbolic}) = tosymbol(x)
tosymbol(x; kwargs...) = x
tosymbol(x::Sym; kwargs...) = nameof(x)
tosymbol(t::Num; kwargs...) = tosymbol(value(t); kwargs...)

"""
    tosymbol(x::Union{Num,Symbolic}; states=nothing, escape=true) -> Symbol

Convert `x` to a symbol. `states` are the states of a system, and `escape`
means if the target has escapes like `val"y⦗t⦘"`. If `escape` then it will only
output `y` instead of `y⦗t⦘`.

# Examples
```julia
julia> @parameters t; @variables z(t)
(z(t),)

julia> ModelingToolkit.tosymbol(z)
Symbol("z⦗t⦘")
```
"""
function tosymbol(t::Term; states=nothing, escape=true)
    if operation(t) isa Sym
        if states !== nothing && !(t in states)
            return nameof(operation(t))
        end
        op = nameof(operation(t))
        args = arguments(t)
    elseif operation(t) isa Differential
        term = diff2term(t)
        op = Symbol(operation(term))
        args = arguments(term)
    else
        @goto err
    end

    return escape ? Symbol(op, "⦗", join(args, ", "), "⦘") : op
    @label err
    error("Cannot convert $t to a symbol")
end

"""
    makesym(x::Union{Num,Symbolic}, kwargs...) -> Sym

`makesym` takes the same arguments as [`tosymbol`](@ref), but it converts a
`Term` in the form of `x(t)` to a `Sym` in the form of `x⦗t⦘`.

# Examples
```julia
julia> @parameters t; @variables x(t)
(x(t),)

julia> ModelingToolkit.makesym(x)
x⦗t⦘
```
"""
makesym(t::Symbolic; kwargs...) = Sym{symtype(t)}(tosymbol(t; kwargs...))
makesym(t::Num; kwargs...) = makesym(value(t); kwargs...)

function lower_varname(var::Symbolic, idv, order)
    order == 0 && return var
    name = string(nameof(operation(var)))
    underscore = 'ˍ'
    idx = findlast(underscore, name)
    append = string(idv)^order
    if idx === nothing
        newname = Symbol(name, underscore, append)
    else
        nidx = nextind(name, idx)
        newname = Symbol(name[1:idx], name[nidx:end], append)
    end
    return Sym{symtype(operation(var))}(newname)(arguments(var)[1])
end

function lower_varname(t::Symbolic, iv)
    var, order = var_from_nested_derivative(t)
    lower_varname(var, iv, order)
end
lower_varname(t::Sym, iv) = t

function lower_mapnames(umap::AbstractArray{T}) where {T<:Pair}
    T[value(k) => value(v) for (k, v) in umap]
end
function lower_mapnames(umap::AbstractArray{T},name) where {T<:Pair}
    T[lower_varname(value(k), name) => value(v) for (k, v) in umap]
end
function lower_mapnames(umap::NTuple{N,T}) where {N,T<:Pair}
    ntuple(i->value(umap[i][1]) => value(umap[i][2]),N)
end
function lower_mapnames(umap::NTuple{N,T},name) where {N,T<:Pair}
    ntuple(i->lower_varname(value(umap[i][1]), name) => value(umap[i][2]),N)
end

lower_mapnames(umap::AbstractArray) = umap # Ambiguity
lower_mapnames(umap::AbstractArray,name) = umap
lower_mapnames(umap::Tuple) = umap
lower_mapnames(umap::Tuple, name) = umap

function flatten_differential(O::Term)
    @assert is_derivative(O) "invalid differential: $O"
    is_derivative(arguments(O)[1]) || return (arguments(O)[1], operation(O).x, 1)
    (x, t, order) = flatten_differential(arguments(O)[1])
    isequal(t, operation(O).x) || throw(ArgumentError("non-matching differentials on lhs: $t, $(operation(O).x)"))
    return (x, t, order + 1)
end

"""
    diff2term(x::Term) -> Term
    diff2term(x) -> x

Convert a differential variable to a `Term`. Note that it only takes a `Term`
not a `Num`.
```julia
julia> ModelingToolkit.diff2term(ModelingToolkit.value(D(D(x))))
xˍtt(t)
```
"""
function diff2term(O)
    istree(O) || return O
    if is_derivative(O)
        (x, t, order) = flatten_differential(O)
        return lower_varname(x, t, order)
    end
    return Term{Real}(operation(O), diff2term.(arguments(O)))
end


text:
"""
    abstract type AbstractBlock

Abstract supertype of all blocks. You should not subtype form this,
but instead from [`Block`](#) or [`WrapperBlock`](#).
"""
abstract type AbstractBlock end

"""
    abstract type Block

A block describes the meaning of a piece of data in the context of a learning task.
For example, for supervised learning tasks, there is an input and a target
and we want to learn to predict targets from inputs. Learning to predict a
cat/dog label from 2D images is a supervised image classification task that can
be represented with the `Block`s `Image{2}()` and `Label(["cat", "dog"])`.

`Block`s are used in virtually every part of the high-level interfaces, from data
processing over model creation to visualization.

## Extending

Consider the following when subtyping `Block`. A block

- Does not hold observation data itself. Instead they are used in conjunction with
  data to annotate it with some meaning.
- If it has any fields, they should be metadata that cannot be
  derived from the data itself and is constant for every sample in
  the dataset. For example `Label` holds all possible classes which
  are constant for the learning problem.

### Interfaces

There are many interfaces that can be implemented for a `Block`. See the docstrings
of each function for more info about how to implement it.

- [`checkblock`](#)`(block, obs)`: check whether an observation is a valid block
- [`mockblock`](#)`(block)`: randomly generate an observation
- [`blocklossfn`](#)`(predblock, yblock)`: loss function for comparing two blocks
- [`blockmodel`](#)`(inblock, outblock[, backbone])`: construct a task-specific model
- [`blockbackbone`](#)`(inblock)`: construct a backbone model that takes in specific data
- [`showblock!`](#)`(block, obs)`: visualize an observation

"""
abstract type Block <: AbstractBlock end

"""
    checkblock(block, obs)
    checkblock(blocks, obss)

Check whether `obs` is compatible with `block`, returning a `Bool`.

## Examples

```julia
checkblock(Image{2}(), rand(RGB, 16, 16)) == true
```

```julia
checkblock(
    (Image{2}(),        Label(["cat", "dog"])),
    (rand(RGB, 16, 16), "cat"                ),
) == true
```

## Extending

An implementation of `checkblock` should be as specific as possible. The
default method returns `false`, so you only need to implement methods for valid types
and return `true`.
"""
checkblock(::Block, obs) = false

function checkblock(blocks::Tuple, obss::Tuple)
    @assert length(blocks) == length(obss)
    return all(checkblock(block, obs) for (block, obs) in zip(blocks, obss))
end

"""
    mockblock(block)
    mockblock(blocks)

Randomly generate an instance of `block`. It always holds that
`checkblock(block, mockblock(block)) === true`.
"""
mockblock(blocks::Tuple) = map(mockblock, blocks)

"""
    setup(Block, data)

Create an instance of block type `Block` from data container `data`.

## Examples

```julia
setup(Label, ["cat", "dog", "cat"]) == Label(["cat", "dog"])
```

    setup(Encoding, block, data; kwargs...)

Create an encoding using statistics derived from a data container `data`
with observations of block `block`. Used when some arguments of the encoding
are dependent on the dataset. `data` should be the training dataset. Additional
`kwargs` are passed through to the regular constructor of `Encoding`.

## Examples

```julia
(images, labels), blocks = loaddataset("imagenette2-160", (Image, Label))
setup(ImagePreprocessing, Image{2}(), images; buffered = false)
```

```julia
data, block = loaddataset("adult_sample", TableRow)
setup(TabularPreprocessing, block, data)
```
"""
function setup end

# ## Utilities

typify(T::Type) = T
typify(t::Tuple) = Tuple{map(typify, t)...}
typify(block::FastAI.AbstractBlock) = typeof(block)

# Continous


text:
@doc raw"""
    Oblique{N,M,𝔽} <: AbstractPowerManifold{𝔽}

The oblique manifold $\mathcal{OB}(n,m)$ is the set of 𝔽-valued matrices with unit norm
column endowed with the metric from the embedding. This yields exactly the same metric as
considering the product metric of the unit norm vectors, i.e. [`PowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.PowerManifold) of the
$(n-1)$-dimensional [`Sphere`](@ref).

The [`Sphere`](@ref) is stored internally within `M.manifold`, such that all functions of
[`AbstractPowerManifold`](https://juliamanifolds.github.io/ManifoldsBase.jl/stable/manifolds.html#ManifoldsBase.AbstractPowerManifold)  can be used directly.

# Constructor

    Oblique(n,m)

Generate the manifold of matrices $\mathbb R^{n × m}$ such that the $m$ columns are unit
vectors, i.e. from the [`Sphere`](@ref)`(n-1)`.
"""
struct Oblique{N,M,𝔽,S} <:
       AbstractPowerManifold{𝔽,Sphere{S,𝔽},ArrayPowerRepresentation} where {N,M}
    manifold::Sphere{S,𝔽}
end

function Oblique(n::Int, m::Int, field::AbstractNumbers=ℝ)
    return Oblique{n,m,field,n - 1}(Sphere(n - 1, field))
end

Base.:^(M::Sphere{N,𝔽}, m::Int) where {N,𝔽} = Oblique{manifold_dimension(M) + 1,m,𝔽,N}(M)

@doc raw"""
    check_point(M::Oblique{n,m},p)

Checks whether `p` is a valid point on the [`Oblique`](@ref)`{m,n}` `M`, i.e. is a matrix
of `m` unit columns from $\mathbb R^{n}$, i.e. each column is a point from
[`Sphere`](@ref)`(n-1)`.
"""
check_point(::Oblique, ::Any)
function check_point(M::Oblique{n,m}, p; kwargs...) where {n,m}
    return check_point(PowerManifold(M.manifold, m), p; kwargs...)
end
@doc raw"""
    check_vector(M::Oblique p, X; kwargs...)

Checks whether `X` is a valid tangent vector to `p` on the [`Oblique`](@ref) `M`.
This means, that `p` is valid, that `X` is of correct dimension and columnswise
a tangent vector to the columns of `p` on the [`Sphere`](@ref).
"""
function check_vector(M::Oblique{n,m}, p, X; kwargs...) where {n,m}
    return check_vector(PowerManifold(M.manifold, m), p, X; kwargs...)
end

get_iterator(::Oblique{n,m}) where {n,m} = Base.OneTo(m)

@generated function manifold_dimension(::Oblique{n,m,𝔽}) where {n,m,𝔽}
    return (n * real_dimension(𝔽) - 1) * m
end
power_dimensions(::Oblique{n,m}) where {n,m} = (m,)

@generated representation_size(::Oblique{n,m}) where {n,m} = (n, m)

@doc raw"""
    parallel_transport_to(M::Oblique, p, X, q)

Compute the parallel transport on the [`Oblique`](@ref) manifold by
doing a column wise parallel transport on the [`Sphere`](@ref)

"""
parallel_transport_to(::Oblique, p, X, q)

function Base.show(io::IO, ::Oblique{n,m,𝔽}) where {n,m,𝔽}
    return print(io, "Oblique($(n),$(m); field = $(𝔽))")
end


text:
using Random; Random.seed!(1234)

include("src/data.jl")
using .DataUtil
include("src/forward_stepwise/selective_inference.jl")
using .SIforSFS
include("src/forward_stepwise/data_splitting.jl")
import .DS
using LinearAlgebra:I
using ProgressMeter
using Plots, StatsPlots, Statistics

function main()
    # parameters
    N = 100
    β₀ = 0.0
    𝛃 = [0.25, 0.25, 0.25, 0.25, 0.25, 0, 0, 0, 0, 0]
    p = length(𝛃)
    k = 9
    α = 0.05
    iter_size = 100

    # generating objects of comparison methods
    events = (Active(), ActiveOrder(), ActiveSign(), ActiveSignOrder())

    CI_DS = fill(NaN, p, iter_size)
    CI_selective = fill(NaN, p, iter_size, length(events))

    CI_length(CI) = CI.right - CI.left
    # experiment
    @showprogress for i = 1:iter_size
        𝐗, 𝐲_obs = centering(make_dataset(β₀, 𝛃, N)...)
        try
            # selective
            for (j, e) in enumerate(events)
                𝐴_obs, CIs = parametric_SFS_CI(𝐗, 𝐲_obs, k, I; selection_event=e, α=α)
                CI_selective[𝐴_obs, i, j] = CI_length.(CIs)
            end
            # DS
            𝐴_obs, CIs = DS.DS_CI(𝐗, 𝐲_obs, k, I; α=α)
            CI_DS[𝐴_obs, i] = CI_length.(CIs)
        catch e
            print("ignore this result: ")
            println(e)
        end
    end

    filter_nan(CIs) = filter(ci -> !isnan(ci), CIs)
    results = [filter_nan(CI_selective[:,:,j]) for j in eachindex(events)]
    push!(results, filter_nan(CI_DS))
    Cs = [:red3, :orange3, :green3, :blue3, :purple3]
    p = plot()
    for i in eachindex(results)
        violin!(p, fill(i, length(results[i])), results[i]; c=Cs[i], label=nothing)
    end
    plot!(p; xticks=(1:length(results), ["Homotopy", "Homotopy-H", "Homotopy-S", "Polytope", "DS"]))
    plot!(p; xlabel="method", ylabel="length of confidence interval")
    # scatter!(p, 1:length(results), median.(results); c=:magenta, label=nothing)
    plot!(p; guidefontsize=16, legendfontsize=12, tickfontsize=10)
    plot!(p; ylims=(0, 7))
    savefig(p, "img/CI_length.pdf")
end


text:
using DifferentialEquations
using Plots

function sir_ode(du,u,p,t)
    S,I,R = u
    b,g = p
    du[1] = -b*S*I
    du[2] = b*S*I-g*I
    du[3] = g*I
end

params = [0.1,0.05]
init = [0.999,0.001,0.0]
tspan = (0.0,200.0)
sir_prob = ODEProblem(sir_ode,init,tspan,params)
sir_sol = solve(sir_prob,saveat = 0.1)

plt = plot(sir_sol)
gui(plt)

max_stars_repo_name: uncharted-aske/pyCHIME

max_issues_repo_name: uncharted-aske/pyCHIME

max_forks_repo_name: uncharted-aske/pyCHIME