text:
DECLARATIVE_PACKAGES_DIR = Pkg.dir("DeclarativePackages")
DEFAULT_PROMPT = @windows ? "playground>" : "\\e[0;35m\\u@\\h:\\W (playground)> \\e[m"
NIGHTLY = v"0.5-"
DEFAULT_CONFIG = """
---
# This is just default location to store a new playground.
# This is used by create and activate if no --name or --path.
default_playground_path: .playground

# Default shell prompt when you activate a playground.
default_prompt: \"$(escape_string(DEFAULT_PROMPT))\"

# Uncomment below to change the default shell. Otherwise the SHELL
# Environment variable will be used.
# default_shell: /usr/local/bin/fish

# Default git settings when using install build
default_git_address: \"https://github.com/JuliaLang/julia.git\"
default_git_revision: master

# Allows you to isolate shell and julia history to each playground.
isolated_shell_history: true
isolated_julia_history: true
"""


text:
nz = 3 + 2 + 1 + 1 + 3 + 3 + 3 + 2
nθ = 3 + 1 + 1 + 1

idx = [3; 1; 2]
function residual(z, θ, κ)
    m = 3

    f = z[1:m]
    s = z[m .+ (1:2)]
    y1 = z[m + 2 .+ (1:1)]
    y2 = z[m + 2 + 1 .+ (1:1)]
    y3 = z[m + 2 + 1 + 1 .+ (1:3)]
    β = z[m + 2 + 1 + 1 + 3 .+ (1:3)]
    η = z[m + 2 + 1 + 1 + 3 + 3 .+ (1:3)]
    z = z[m + 2 + 1 + 1 + 3 + 3 + 3 .+ (1:2)]

    f̄ = θ[1:m]
    f_min = θ[m .+ (1:1)]
    f_max = θ[m + 1 .+ (1:1)]
    μ = θ[m + 1 + 1 .+ (1:1)]

    A = [0.0 0.0 μ; 1.0 0.0 0.0; 0.0 1.0 0.0]

    return [f - f̄ + [0.0; 0.0; -y1[1] + y2[1]] + transpose(A) * y3;
            [-y1[1]; -y2[1]] - z;
            f_max[1] - f[3] - s[1];
            f[3] - f_min[1] - s[2];
            A * f - β;
            -y3 - η;
            second_order_cone_product(β, η) - [κ; 0.0; 0.0];
            s .* z .- κ]
end

@variables z[1:nz], θ[1:nθ], κ[1:1]

r = residual(z, θ, κ)
r .= simplify(r)
r_func = eval(Symbolics.build_function(r, z, θ, κ)[2])

rz = Symbolics.jacobian(r, z)
rz = simplify.(rz)
rz_func = eval(Symbolics.build_function(rz, z, θ)[2])

rθ = Symbolics.jacobian(r, θ)
rθ = simplify.(rθ)
rθ_func = eval(Symbolics.build_function(rθ, z, θ)[2])

idx_ineq = collect([4, 5, 17, 18])
idx_soc = [collect([11, 12, 13]), collect([14, 15, 16])]

# ul = -1.0 * ones(m)
# uu = 1.0 * ones(m)
ū = [0.0; 0.0; 0.0]
u_min = 0.0
u_max = 1.0
scaling = 1.0
z0 = [ū; 1.0; 1.0; 0.0; 0.0; 0.0; 0.0; 0.0; 1.0; 0.1; 0.1; 1.0; 0.1; 0.1; 1.0; 1.0]

θ0 = [copy(ū); u_min; u_max; scaling]

# solver
opts_con = InteriorPointOptions(
    κ_init = 1.0,
    κ_tol = 1.0e-4,
    r_tol = 1.0e-8,
    diff_sol = false)

ip_con = interior_point(z0, θ0,
    r! = r_func, rz! = rz_func,
    rz = similar(rz, Float64),
    rθ! = rθ_func,
    rθ = similar(rθ, Float64),
    idx_ineq = idx_ineq,
    idx_soc = idx_soc,
    opts = opts_con)

opts_jac = InteriorPointOptions(
	κ_init = 1.0,
	κ_tol = 1.0e-3,
	r_tol = 1.0e-8,
	diff_sol = true)

ip_jac = interior_point(z0, θ0,
	r! = r_func, rz! = rz_func,
	rz = similar(rz, Float64),
	rθ! = rθ_func,
	rθ = similar(rθ, Float64),
	idx_ineq = idx_ineq,
  idx_soc = idx_soc,
	opts = opts_jac)

# interior_point_solve!(ip_con)
# interior_point_solve!(ip_jac)

function soc_projection(x, x_min, x_max, scaling)
    ip_con.z .= [x; 1.0; 1.0; 0.0; 0.0; 0.0; 0.0; 0.0; 1.0; 0.1; 0.1; 1.0; 0.1; 0.1; 1.0; 1.0]
    ip_con.θ .= [x; x_min; x_max; scaling]

    status = interior_point_solve!(ip_con)

    !status && (@warn "projection failure (res norm: $(norm(ip_con.r, Inf))) \n
    	               z = $(ip_con.z), \n
    				   θ = $(ip_con.θ)")

	return @view ip_con.z[1:3]
end

# soc_projection([100.0, 0.0, -1.0], 0.0, 1.0, 1.0)

function soc_projection_jacobian(x, x_min, x_max, scaling)
    ip_con.z .= [x; 1.0; 1.0; 0.0; 0.0; 0.0; 0.0; 0.0; 1.0; 0.1; 0.1; 1.0; 0.1; 0.1; 1.0; 1.0]
    ip_con.θ .= [x; x_min; x_max; scaling]

	interior_point_solve!(ip_jac)

	return view(ip_jac.δz, 1:3, 1:3)
end

# soc_projection_jacobian([0.0, 0.0, 1.0], 0.0, 10.0, 1.0)

ext: jl

max_issues_repo_name: thowell/DirectMotionPlanning


text:
# The translation pass turns Julia expressions into SQL expressions
# Frustratingly, _primary tables are translated differently from secondary tables, so translate must propagate the `_primary` keyword
struct SQLExpression
    call::Symbol
    arguments::Vector{Any}
    SQLExpression(call, arguments...) = new(call, Any[arguments...])
end

function nest(sql_expression)
    SQLExpression(:AS, SQLExpression(:FROM, sql_expression), :__TABLE__)
end

function translate(something::Union{Char,AbstractString}; _primary=true)
    repr(something)
end

function translate(something; _primary=true)
    something
end
function translate(source_row::SourceRow; _primary=true)
    source_row.table_name
end
function translate(call::Expr; _primary=true)
    arguments, keywords = split_call(call)
    translate_call(arguments...; _primary=_primary, keywords...)
end

# A 1-1 mapping between Julia functions and SQL functions
function translate_default(location, function_type, SQL_call)
    result = :(
        function translate_call($function_type, arguments...; _primary=true)
        $SQLExpression($SQL_call, $map(
                argument -> $translate(argument; _primary=_primary),
                arguments
            )...)
    end
    )
    result.args[2].args[1] = location
    result
end

macro translate_default(a_function, SQL_call)
    translate_default(__source__, a_function, SQL_call) |> esc
end

@translate_default ::typeof(==) :(=)

@translate_default ::typeof(!=) Symbol("<>")

@translate_default ::typeof(!) :NOT

@translate_default ::typeof(&) :AND

@translate_default ::typeof(|) :OR

@translate_default ::typeof(*) :*

@translate_default ::typeof(/) :/

@translate_default ::typeof(+) :+

@translate_default ::typeof(-) :-

@translate_default ::typeof(%) :%

@translate_default ::typeof(abs) :ABS

function as(pair; _primary=true)
    SQLExpression(:AS,
        translate(pair.second.code; _primary=_primary),
        pair.first
    )
end

@translate_default ::typeof(coalesce) :COALESCE

@translate_default ::typeof(char) :CHAR

function translate_call(::typeof(convert), ::Type{Int}, it; _primary=true)
    SQLExpression(:UNICODE, translate(it))
end

@translate_default ::typeof(hex) :HEX

@translate_default ::typeof(QueryOperators.drop) :OFFSET

function translate_call(::typeof(QueryOperators.filter), iterator, call, call_expression; _primary=true)
    SQLExpression(:WHERE,
        translate(iterator; _primary=_primary),
        translate(call(model_row(iterator)).code; _primary=_primary)
    )
end

function translate_call(::typeof(format), time_type, format_string; _primary=true)
    SQLExpression(
        :STRFTIME,
        translate(format_string; _primary=_primary),
        translate(time_type; _primary=_primary)
    )
end

function translate_call(::typeof(getproperty), source_tables::Database, table_name; _primary=true)
    translated = translate(table_name; _primary=_primary)
    if _primary
        SQLExpression(:FROM, translated)
    else
        translated
    end
end
function translate_call(::typeof(getproperty), source_row::SourceRow, column_name; _primary=true)
    translated = translate(column_name; _primary=_primary)
    if _primary
        translated
    else
        SQLExpression(:., source_row.table_name, translated)
    end
end

function translate_call(::typeof(QueryOperators.groupby), ungrouped, group_function, group_function_expression, map_selector, map_function_expression; _primary=true)
    model = model_row(ungrouped)
    SQLExpression(Symbol("GROUP BY"),
        nest(translate_call(
            QueryOperators.map,
            ungrouped,
            map_selector, map_function_expression,
            _primary=_primary
        )),
        translate(group_function(model).code; _primary=_primary)
    )
end

@translate_default ::typeof(if_else) :CASE

@translate_default ::typeof(in) :IN

@translate_default ::typeof(instr) :INSTR

@translate_default ::typeof(isequal) Symbol("IS NOT DISTINCT FROM")

@translate_default ::typeof(isless) :<

@translate_default ::typeof(ismissing) Symbol("IS NULL")

@translate_default ::typeof(join) :GROUP_CONCAT

function translate_call(::typeof(QueryOperators.join), source1, source2, key1, key1_expression, key2, key2_expression, combine, combine_expression; _primary=true)
    model_row_1 = model_row(source1)
    model_row_2 = model_row(source2)
    SQLExpression(:SELECT,
        SQLExpression(:ON,
            SQLExpression(Symbol("INNER JOIN"),
                translate(source1),
                # mark as not _primary to suppress FROM
                translate(source2; _primary=false)
            ),
            # mark both as not _primary to always be explicit about table
            SQLExpression(:(=),
                translate(key1(model_row_1).code; _primary=false),
                translate(key2(model_row_2).code; _primary=false)
            )
        ),
        # mark both as not _primary to always be explicit about table
        Generator(
            pair -> as(pair; _primary=false),
            pairs(combine(model_row_1, model_row_2))
        )...
    )
end

@translate_default ::typeof(length) :COUNT

@translate_default ::typeof(lowercase) :LOWER

function translate_call(::typeof(QueryOperators.map), select_table, call, call_expression; _primary=true)
    inner = translate(select_table; _primary=_primary)
    if inner.call == :SELECT
        inner = nest(inner)
    end
    SQLExpression(
        :SELECT, inner,
        Generator(
            pair -> as(pair; _primary=_primary),
            pairs(call(model_row(select_table)))
        )...
    )
end

@translate_default ::typeof(max) :max
@translate_default ::typeof(maximum) :max

@translate_default ::typeof(mean) :AVG

@translate_default ::typeof(min) :min
@translate_default ::typeof(minimum) :min

translate_call(::typeof(occursin), needle, haystack; _primary=true) =
    SQLExpression(
        :LIKE,
        translate(haystack; _primary=_primary),
        translate(needle; _primary=_primary)
    )

function translate_call(::typeof(QueryOperators.orderby), unordered, key_function, key_function_expression; _primary=true)
    SQLExpression(Symbol("ORDER BY"),
        translate(unordered; _primary=_primary),
        translate(key_function(model_row(unordered)).code; _primary=_primary)
    )
end

function translate_call(::typeof(QueryOperators.orderby_descending), unordered, key_function, key_function_expression; _primary=true)
    SQLExpression(Symbol("ORDER BY"),
        translate(unordered; _primary=_primary),
        SQLExpression(:DESC,
            translate(key_function(model_row(unordered)).code; _primary=_primary)
        )
    )
end

@translate_default ::typeof(repr) :QUOTE

function translate_call(::typeof(rand), ::Type{Int}; _primary=true)
    SQLExpression(:RANDOM)
end

@translate_default ::typeof(randstring) :RANDOMBLOB

function translate_call(::typeof(replace), it, pair; _primary=true)
    SQLExpression(:REPLACE,
        translate(it; _primary=_primary),
        translate(pair.first; _primary=_primary),
        translate(pair.second; _primary=_primary)
    )
end

function translate_call(::typeof(round), it; _primary=true, digits=0)
    SQLExpression(:ROUND,
        translate(it; _primary=_primary),
        translate(digits; _primary=_primary)
    )
end

@translate_default ::typeof(string) :||

@translate_default ::typeof(strip) :TRIM

@translate_default ::Type{SubString} :SUBSTR

@translate_default ::typeof(sum) :SUM

@translate_default ::typeof(QueryOperators.take) :LIMIT

function translate_call(::typeof(QueryOperators.thenby), unordered, key_function, key_function_expression; _primary=true)
    original = translate(unordered; _primary=_primary)
    SQLExpression(original.call, original.arguments...,
        translate(key_function(model_row(unordered)).code; _primary=_primary)
    )
end

function translate_call(::typeof(QueryOperators.thenby_descending), unordered, key_function, key_function_expression; _primary=true)
    original = translate(unordered; _primary=_primary)
    SQLExpression(original.call, original.arguments...,
        SQLExpression(:DESC,
            translate(key_function(model_row(unordered)).code; _primary=_primary)
        )
    )
end

@translate_default ::typeof(type_of) :TYPEOF

function translate_call(::typeof(QueryOperators.unique), repeated, key_function, key_function_expression; _primary=true)
    result = translate(repeated; _primary=_primary)
    SQLExpression(Symbol(string(result.call, " DISTINCT")), result.arguments...)
end

@translate_default ::typeof(uppercase) :UPPER


text:
include("DislocationProcessing.jl")
include("FEMProcessing.jl")
include("IntegrationProcessing.jl")
include("DislocationFEM.jl")

max_stars_repo_name: dcelisgarza/DDD

max_forks_repo_name: dcelisgarza/DDD


text:
module Utilitas

	using Pkg: add,dependencies
	using TOML: parse
	using Downloads: download
	using JLFzf: inter_fzf
	using JSON3: read

	function __init__()
		reglist = parse(seekstart(download("https://raw.githubusercontent.com/JuliaRegistries/General/master/Registry.toml", IOBuffer())))["packages"]
		global k = [c for (b,c) in [a for (a, b) in values(reglist)]]
	end

	export search, seadd, gelat, chklat, chkall

	include("pkgops.jl")
end


text:
# """
#     nearest_neighbour(cities)
# Finds a TSP route through cities using nearest-neighbour approach
# """
# function nearest_neighbour(grid::Grid)
#     # route = Array(City, length(cities) + 1)
#     route::Array{City} = [grid.cities[1]]
#     visited = zeros(Bool, length(grid.cities))
#     visited[1] = true
#     while length(route) != length(grid.cities)
#         current = route[end]
#         nearest = find_nearest(current, grid, visited)
#         push!(route, nearest)
#         visited[nearest.id] = true
#     end
#     push!(route, grid.cities[1])
#     return Route(route)
# end

function nearest_neighbour(cities::Array{City})
    # route = Array(City, length(cities) + 1)
    route::Array{City} = [cities[1]]
    visited = zeros(Bool, length(cities))
    visited[1] = true
    while length(route) != length(cities)
        current = route[end]
        nearest = find_nearest(current, cities, visited)
        push!(route, nearest)
        visited[nearest.id] = true
    end
    push!(route, cities[1])
    return Route(route)
end

function nearest_neighbour(cities::Array{City}, rs::Float64)
    # route = Array(City, length(cities) + 1)
    route::Array{City} = [cities[1]]
    visited = zeros(Bool, length(cities))
    visited[1] = true
    while length(route) != length(cities)
        current = route[end]
        nearest = find_nearest(current, cities, visited, rs)
        push!(route, nearest)
        visited[nearest.id] = true
    end
    push!(route, cities[1])
    return Route(route)
end

# """
#     nearest_neighbour_2(cities)
# Nearest neighbour, look at both ends at the same
# NOTE: apparently worse initial distance than regular NN
# """
# function nearest_neighbour_2(grid::Grid)
#     route::Array{City} = Array(City, length(grid.cities) + 1)
#     route[1] = route[end] = grid.cities[1]
#     visited = zeros(Bool, length(grid.cities))
#     visited[1] = true
#     head = tail = grid.cities[1]
#     head_idx = 1
#     tail_idx = length(grid.cities)+1
#     # while length(route) < length(cities)
#     while head_idx < tail_idx - length(grid.cities) % 2
#         head_idx += 1
#         tail_idx -= 1
#         println(route)
#         println("head: $head_idx, tail: $tail_idx")
#         next = find_nearest(head, grid, visited)
#         prev = find_nearest(tail, grid, visited)
#         if next == prev
#             println("conflict")
#             if score(route[head_idx-1], next) < score(route[tail_idx+1], next)
#                 # the found point is closer to "head" than the "tail"
#                 route[head_idx] = next
#                 visited[next.id] = true
#                 prev = find_nearest(tail, grid, visited) # new head is second nearest
#             else # found point is closer to the tail
#                 route[tail_idx] = prev
#                 visited[prev.id] = true
#                 next = find_nearest(head, grid, visited)
#             end
#         end
#         println("Setting $head_idx to $next")
#         route[head_idx] = next
#         visited[next.id] = true
#         if head_idx < tail_idx
#             println("Setting $tail_idx to $prev")
#             route[tail_idx] = prev
#             visited[prev.id] = true
#         end

#     end
#     return Route(route)
# end

# function find_nearest(current::City, grid::Grid, visited::Array{Bool})
#     nearest = 0
#     for id in 1:length(grid.cities)
#         city = grid.cities[id]
#         if visited[city.id]
#             continue
#         end
#         if nearest == 0
#             nearest = city
#         elseif distance(current, city, grid) < distance(current, nearest, grid)
#             nearest = city
#         end
#     end
#     return nearest
# end

function find_nearest(current::City, cities::Array{City}, visited::Array{Bool})
    nearest = 0
    for id in 1:length(cities)
        city = cities[id]
        if visited[city.id]
            continue
        end
        if nearest == 0
            nearest = city
        elseif distance(current, city) < distance(current, nearest)
            nearest = city
        end
    end
    return nearest
end

function find_nearest(current::City, cities::Array{City}, visited::Array{Bool}, rs::Float64)
    nearest = 0
    for id in 1:length(cities)
        city = cities[id]
        if visited[city.id]
            continue
        end
        if nearest == 0
            nearest = city
        elseif distance(current, city) * (rand() * rs + 1) < distance(current, nearest) * (rand() * rs + 1)
            nearest = city
        end
    end
    return nearest
end


text:
# Test some ADL features in a grid flipping domain
path = joinpath(dirname(pathof(PDDL)), "..", "test", "adl")

domain = load_domain(joinpath(path, "flip-domain.pddl"))
@test domain.name == Symbol("flip")
problem = load_problem(joinpath(path, "flip-problem.pddl"))
@test problem.name == Symbol("flip-problem")

state = init_state(problem)
state = execute(pddl"(flip_column c1)", state, domain)
state = execute(pddl"(flip_column c3)", state, domain)
state = execute(pddl"(flip_row r2)", state, domain)

@test satisfy(problem.goal, state, domain)[1] == true

# Test all ADL features in assembly domain
path = joinpath(dirname(pathof(PDDL)), "..", "test", "adl")

domain = load_domain(joinpath(path, "assembly-domain.pddl"))
problem = load_problem(joinpath(path, "assembly-problem.pddl"))

# Test for static predicates
@test pddl"(requires ?a ?r)" in get_static_predicates(domain)
@test length(get_static_predicates(domain)) == 6

# Our goal is to assemble a frob
state = init_state(problem)

# Commit charger to assembly of frob
state = execute(pddl"(commit charger frob)", state, domain)
# Once commited, we can't commit again
@test available(pddl"(commit charger frob)", state, domain) == false

# We can't add a tube to the frob before adding the widget and fastener
@test available(pddl"(assemble tube frob)", state, domain) == false
state = execute(pddl"(assemble widget frob)", state, domain)
@test available(pddl"(assemble tube frob)", state, domain) == false
state = execute(pddl"(assemble fastener frob)", state, domain)

# Having added both widget and fastener, now we can add the tube
@test available(pddl"(assemble tube frob)", state, domain) == true
state = execute(pddl"(assemble tube frob)", state, domain)

# We've completely assembled a frob!
@test satisfy(problem.goal, state, domain)[1] == true


text:
module Py2ToPy3

export change

function patexcept(line)
    r = Regex("(.*)(except .*)(, )(.*:)")
    m = match(r, line)
    (m, m isa RegexMatch ? string(m[1], m[2], " as ", m[4]) : line)
end

function patraise(line)
    r = Regex("(.*)(raise [^,]*)(, )(.*)")
    m = match(r, line)
    (m, m isa RegexMatch ? string(m[1], m[2], "(", m[4], ")") : line)
end

function patprint(line)
    r = Regex("(.*)(print )(.*)")
    m = match(r, line)
    (m, m isa RegexMatch ? string(m[1], "print(", m[3], ")") : line)
end

function patpickle(line)
    r = Regex("(.*)(import )(cPickle)(.*)")
    m = match(r, line)
    (m, m isa RegexMatch ? string(m[1], m[2], "pickle", m[4]) : line)
end

function upgrade(filename::String, overwrite::Bool)
    io = IOBuffer()
    for line in readlines(filename)
        for f in (patexcept, patraise, patprint, patpickle)
            m, s = f(line)
            if m isa RegexMatch
                line = s
                break
            end
        end
        println(io, line)
    end
    s = String(take!(io))
    if overwrite
        write(filename, s)
    else
        print(s)
    end
end

function change(filenames=ARGS; overwrite=false)
    if isempty(filenames)
    else
        for filename in filenames
            upgrade(filename, overwrite)
        end
    end
end

end # module Py2ToPy3


text:
__precompile__()

module Adiff

using LinearAlgebra
import Base: length, getindex, copy
import Base: +, -, *, /, ^, abs, sqrt, log, exp, zero, sin, cos
import LinearAlgebra: norm, dot, svd

#  macros
macro swap(x,y)
  quote
    local tmp = $(esc(x))
    $(esc(x)) = $(esc(y))
    $(esc(y)) = tmp
  end
end
δ(i,j)         = i==j ? Float64(1) : Float64(0)
tupfy(f,N)     = :(@inbounds $(Expr(:tuple, [f(i) for i in 1:N]...)))
tupfy2(f,N)    = :(@inbounds $(Expr(:tuple, [f(i,j) for j in 1:N for i in 1:j]...)))
# structures
struct Grad{N}
  v::NTuple{N,Float64}
end
struct Hess{N}
  v::NTuple{N,Float64}
end
struct D1{N} <: Real
  v::Float64
  g::Grad{N}
end
struct D2{N,M} <: Real
  v::Float64
  g::Grad{N}
  h::Hess{M}
end
Ders{N} = Union{Grad{N}, Hess{N}}
# constructors
Grad(V...)                    = V .|> Float64 |> Grad
Hess(V...)                    = V .|> Float64 |> Hess
Grad(V::Array)                = (V...,) .|> Float64 |> Grad
Hess(V::Array)                = (V...,) .|> Float64 |> Hess
D2(v::Real)                   = D2(Float64(v),Grad(1.0))
D2{N}(v::Real)    where N     = D2(Float64(v),zero(Grad{N}),zero(Hess{N}))
D2{N,M}(v::Real)  where {N,M} = D2(Float64(v),zero(Grad{N}),zero(Hess{N}))
D2(v::Float64, g::Grad{N}) where N = D2(v, g, zero(Hess{N}))
D2(x::Array{<:Real}) = begin
  N     = length(x)
  grad  = init(Grad{N})
  hess  = init(Hess{N})
  return [D2(Float64(x), grad[i], hess[i]) for (i,x) in enumerate(x)]
end
# D1
D1(v::Real)                   = D1(Float64(v),Grad(1.0))
D1{N}(v::Real)    where N     = D1(Float64(v),zero(Grad{N}))
# D1(v::Float64, g::Grad{N}) where N = D1(v, g)
D1(x::Array{<:Real}) = begin
  N     = length(x)
  grad  = init(Grad{N})
  return [D1(Float64(x), grad[i]) for (i,x) in enumerate(x)]
end
#
@inline Base.@propagate_inbounds getindex(x::Grad{N}, I...) where N = x.v[I...]
@inline Base.@propagate_inbounds getindex(x::Hess{N}, I...) where N = x.v[I...]
@inline Base.@propagate_inbounds getindex(x::Hess{N}, I,J)  where N = ((I>J) && @swap(I,J); x.v[(J-1)J/2+I])
@inline length(x::D2{N,M}) where {N,M} = N
@inline length(x::Grad{N}) where N     = N
@inline length(x::Hess{N}) where N     = N
@inline @generated zero(::Type{Grad{N}})             where N = :(Grad($(tupfy(i->Float64(0),N))))
@inline @generated zero(::Type{Hess{N}})             where N = :(Hess($(tupfy(i->Float64(0),(N+1)N/2))))
@inline @generated init(::Type{Grad{N}})             where N = tupfy(j->:(Grad($(tupfy(i->δ(i,j),N)))),N)
@inline @generated init(::Type{Hess{N}})             where N = tupfy(i->zero(Hess{N}),N)
@inline @generated +(x::T, y::T)    where T<:Ders{N} where N = :(T($(tupfy(i->:(x[$i]+y[$i]),N))))
@inline @generated -(x::T, y::T)    where T<:Ders{N} where N = :(T($(tupfy(i->:(x[$i]-y[$i]),N))))
@inline @generated -(y::T)          where T<:Ders{N} where N = :(T($(tupfy(i->:(-y[$i]),N))))
@inline @generated *(x::Real, y::T) where T<:Ders{N} where N = :(T($(tupfy(i->:(x*y[$i]),N))))
@inline @generated *(y::T, x::Real) where T<:Ders{N} where N = :(T($(tupfy(i->:(x*y[$i]),N))))
@inline @generated /(y::T, x::Real) where T<:Ders{N} where N = :(T($(tupfy(i->:(y[$i]/x),N))))
@inline @generated *(x::Grad{N}, y::Grad{N})         where N = :(Hess($(tupfy2((i,j)->:(x[$i]y[$j]),N))))
# D1 operators,  this can be improved
# scale/shift operators
@inline +(x::Real, y::D1)  = D1(x+y.v, y.g)
@inline +(y::D1, x::Real)  = D1(x+y.v, y.g)
@inline -(x::Real, y::D1)  = D1(x-y.v, -y.g)
@inline -(y::D1, x::Real)  = D1(y.v-x, y.g)
@inline *(x::Real, y::D1)  = D1(x*y.v, x*y.g)
@inline *(y::D1, x::Real)  = D1(x*y.v, x*y.g)
@inline /(y::D1, x::Real)  = D1(y.v/x, y.g/x)
@inline /(x::Real, y::D1)  = D1(x/y.v, (-x/y.v^2)*y.g)
# dual operators
S = Union{Int64, Float64}
@inline +(x::D1, y::D1)    = D1(x.v+y.v, x.g+y.g)
@inline -(x::D1, y::D1)    = D1(x.v-y.v, x.g-y.g)
@inline -(x::D1)           = D1(-x.v, -x.g)
@inline *(x::D1, y::D1)    = D1(x.v*y.v, x.v*y.g+y.v*x.g)
@inline /(x::D1, y::D1)    = x*(1/y)
@inline ^(x::D1, n::S)     = D1(x.v^n, (n*x.v^(n-1))*x.g)
@inline log(x::D1)         = D1(log(x.v),  x.g/x.v)
@inline exp(x::D1)         = D2(exp(x.v), exp(x.v)*x.g)
@inline sin(x::D1)         = D1(sin(x.v),  cos(x.v)*x.g)
@inline cos(x::D1)         = D1(cos(x.v), -sin(x.v)*x.g)
@inline sqrt(x::D1)        = x^0.5
@inline abs(x::D1)         = x.v ≥ 0 ? x : -x
@inline dot(x::Array{D1}, y::Array{D1}) = sum(x.*y)
@inline norm(x::Array{D1}) = sqrt(dot(x,x))
# data retrieving methods
@inline D1eval(f, x)           = f(D1(x))
@inline Real(x::D1)            = x.v
@inline val(x::D1)             = x.v
@inline grad(x::Real)          = 0
@inline grad(x::D1{N}) where N = [x.g[i]   for i in 1:N]
@inline hess(x::D1{N}) where N = zeros(N,N)
#
#
# D2 operators
#
# scale/shift operators
@inline +(x::Real, y::D2)  = D2(x+y.v, y.g,   y.h)
@inline +(y::D2, x::Real)  = D2(x+y.v, y.g,   y.h)
@inline -(x::Real, y::D2)  = D2(x-y.v, -y.g,  -y.h)
@inline -(y::D2, x::Real)  = D2(y.v-x, y.g,   y.h)
@inline *(x::Real, y::D2)  = D2(x*y.v, x*y.g, x*y.h)
@inline *(y::D2, x::Real)  = D2(x*y.v, x*y.g, x*y.h)
@inline /(y::D2, x::Real)  = D2(y.v/x, y.g/x, y.h/x)
@inline /(x::Real, y::D2)  = D2(x/y.v, (-x/y.v^2)*y.g, (2x/y.v^3)*(y.g*y.g) - (x/y.v^2)*y.h)
# dual operators
S = Union{Int64, Float64}
@inline +(x::D2, y::D2)    = D2(x.v+y.v, x.g+y.g, x.h+y.h)
@inline -(x::D2, y::D2)    = D2(x.v-y.v, x.g-y.g, x.h-y.h)
@inline -(x::D2)           = D2(-x.v, -x.g, -x.h)
@inline *(x::D2, y::D2)    = D2(x.v*y.v, x.v*y.g+y.v*x.g, x.v*y.h+y.v*x.h+x.g*y.g+y.g*x.g)
@inline /(x::D2, y::D2)    = x*(1/y)
@inline ^(x::D2, n::S)     = D2(x.v^n, (n*x.v^(n-1))*x.g, (n*(n-1)*x.v^(n-2))*(x.g*x.g)+(n*x.v^(n-1))*x.h)
@inline log(x::D2)         = D2(log(x.v),  x.g/x.v,      -(x.g*x.g)/x.v^2 + x.h/x.v)
@inline exp(x::D2)         = D2(exp(x.v), exp(x.v)*x.g, exp(x.v)*(x.g*x.g) + exp(x.v)*x.h)
@inline sin(x::D2)         = D2(sin(x.v),  cos(x.v)*x.g, -sin(x.v)*(x.g*x.g) + cos(x.v)*x.h)
@inline cos(x::D2)         = D2(cos(x.v), -sin(x.v)*x.g, -cos(x.v)*(x.g*x.g) - sin(x.v)*x.h)
@inline sqrt(x::D2)        = x^0.5
@inline abs(x::D2)         = x.v ≥ 0 ? x : -x
@inline dot(x::Array{D2}, y::Array{D2}) = sum(x.*y)
@inline norm(x::Array{D2{N,M}} where {N,M}) = sqrt(dot(x,x))
# data retrieving methods
@inline D2eval(f::F, x::T) where {F,T} = f(D2(x))
@inline Real(x::D2)                    = x.v
@inline val(x::D2)                     = x.v
@inline grad(x::D2{N,M})   where{N,M}  = [x.g[i]   for i in 1:N]
@inline hess(x::D2{N,M})   where{N,M}  = [x.h[i,j] for i in 1:N, j in 1:N]
end


text:
export  Peng_solution,
        Schoenberg_solution_initialBC,
        taper_initial_field!,
        initialize_planewave

include("./planewave.jl")


text:
mutable struct Document
    _path::String
    _text_document::TextDocument
    _open_in_editor::Bool
    _workspace_file::Bool
    cst::EXPR
    diagnostics::Vector{Diagnostic}
    server
    root::Document

    function Document(text_document::TextDocument, workspace_file::Bool, server=nothing)
        path = something(uri2filepath(get_uri(text_document)), "")
        path == "" || isabspath(path) || throw(LSRelativePath("Relative path `$path` is not valid."))
        cst = CSTParser.parse(get_text(text_document), true)
        doc = new(path, text_document, false, workspace_file, cst, [], server)
        set_doc(doc.cst, doc)
        setroot(doc, doc)
        return doc
    end
end

Base.display(doc::Document) = println("Doc: $(basename(doc._uri)) ")

function set_doc(x::EXPR, doc)
    if !StaticLint.hasmeta(x)
        x.meta = StaticLint.Meta()
    end
    x.meta.error = doc
end

function get_path(doc)
    return doc._path
end

function get_text(doc::Document)
    return get_text(doc._text_document)
end

function get_uri(doc::Document)
    return get_uri(doc._text_document)
end

function get_version(doc::Document)
    return get_version(doc._text_document)
end

function get_text_document(doc::Document)
    return doc._text_document
end

function set_text_document!(doc::Document, text_document)
    doc._text_document = text_document
end

function set_open_in_editor(doc::Document, value::Bool)
    doc._open_in_editor = value
end

function get_open_in_editor(doc::Document)
    return doc._open_in_editor
end

function is_workspace_file(doc::Document)
    return doc._workspace_file
end

function set_is_workspace_file(doc::Document, value::Bool)
    doc._workspace_file = value
end

function applytextdocumentchanges(doc::Document, change)
    text_document = apply_text_edits(doc._text_document, [change], get_version(doc._text_document))
    set_text_document!(doc, text_document)
end

get_offset(doc::Document, line::Integer, character::Integer) = get_offset(doc._text_document, line, character)
get_offset(doc::Document, p::Position) = get_offset(doc, p.line, p.character)
get_offset(doc::Document, r::Range) = get_offset(doc, r.start):get_offset(doc, r.stop)

# get_offset, but correct
get_offset3(args...) = index_at(args...) - 1

index_at(doc::Document, pos, args...) = index_at(doc._text_document, pos, args...)

get_position_from_offset(doc::Document, offset::Integer) = get_position_from_offset(doc._text_document, offset)

Range(doc::Document, rng::UnitRange) = Range(doc._text_document, rng)


text:
module YAXTools
using Distributed
import ..YAXArrays: YAXdir
export freshworkermodule, passobj, @everywhereelsem,
@loadOrGenerate, PickAxisArray
struct PickAxisArray{T,N,AT<:AbstractArray,P,PERM}
    parent::AT
end

function PickAxisArray(parent, indmask, perm=nothing)
    f  = findall(isequal(true),indmask)
    f2 = findall(isequal(Colon()), indmask)
    o = sort([f;f2])
    o = isempty(f2) ? o : replace(o, map(i->i=>Colon(),f2)...)
    nsub = 0
    for i in 1:length(o)
      if o[i] isa Colon
        nsub +=1
      else
        o[i] = o[i]-nsub
      end
    end
    if perm !== nothing
      length(perm) != length(f2) && error("Not a valid permutation")
      perm = (perm...,)
    end
    PickAxisArray{eltype(parent),length(indmask),typeof(parent),(o...,),perm}(parent)
end
indmask(p::PickAxisArray{<:Any,<:Any,<:Any,i}) where i = i
getind(i,j) = i[j]
getind(i,j::Colon) = j
permout(::PickAxisArray{<:Any,<:Any,<:Any,<:Any,P},x) where P = permutedims(x,P)
permout(::PickAxisArray{<:Any,<:Any,<:Any,<:Any,nothing},x) = x
function Base.view(p::PickAxisArray, i::Integer...)
  inew = map(j->getind(i,j),indmask(p))
  r = permout(p,view(p.parent,inew...))
  r
end
function Base.getindex(p::PickAxisArray, i::Integer...)
    inew = map(j->getind(i,j),indmask(p))
    permout(p,getindex(p.parent,inew...))
end
anycol(t::Tuple{}) = false
anycol(t::Tuple) = anycol(first(t), Base.tail(t))
anycol(::Colon,t::Tuple) = true
anycol(i,::Tuple{}) = false
anycol(::Colon,::Tuple{}) = true
anycol(i,t::Tuple) = anycol(first(t),Base.tail(t))
ncol(t::Tuple) = ncol(first(t), Base.tail(t),0)
ncol(::Colon,t::Tuple,n) = ncol(first(t),Base.tail(t), n+1)
ncol(i,::Tuple{},n) = n
ncol(::Colon,::Tuple{},n) = n+1
ncol(i,t::Tuple,n) = ncol(first(t),Base.tail(t),n)

function Base.eltype(p::PickAxisArray{T}) where T
  im = indmask(p)
  if anycol(im)
    Array{T,ncol(im)}
  else
    T
  end
end
Base.getindex(p::PickAxisArray,i::CartesianIndex) = p[i.I...]

"""
    macro loadOrGenerate(x...,expression)

Takes a list of `variablename=>"Storage Name"` pairs. Checks if all datasets can be found
on disk and loads them. If not, the datasets will be regenerated by evaluating the given expression.

To force recalculation, call `YAXArrays.recalculate(true)` before evaluating the macro.

### Example

The following lines will check if cubes with the names "Filled" and "Normalized"
exist on disk, load them and assign the variable names `cube_filled` and `cube_norm`.
If the datasets to not exist on disk, they are generated and saved under the given names.

````julia
@loadOrGenerate cube_filled=>"Filled" cube_norm=>"Normalized" begin
cube_filled = mapCube(gapFillMSC,d)
cube_norm   = mapCube(normalize_TS,d)
end

````
"""
macro loadOrGenerate(x...)
  code=x[end]
  x=x[1:end-1]
  x2=map(x) do i
    isa(i,Symbol) ? (i,string(i)) : (i.head==:call && i.args[1]==:(=>)) ? (i.args[2],i.args[3]) : error("Wrong Argument type")
  end
  xnames=map(i->i[2],x2)
  loadEx=map(x2) do i
    :($(i[1]) = loadcube($(i[2])))
  end
  loadEx=Expr(:block,loadEx...)
  saveEx=map(x2) do i
    :(savecube($(i[1]),$(i[2])))
  end
  saveEx=Expr(:block,saveEx...)
  rmEx=map(x2) do i
    :(rmcube($(i[2])))
  end
  rmEx=Expr(:block,rmEx...)
  esc(quote
    if !YAXArrays.recalculate() && all(i->isdir(joinpath(YAXdir(),i)),$xnames)
      $loadEx
    else
      $rmEx
      $code
      $saveEx
    end
  end)
end

# Here we define ouur own reexport macro copied from
# https://github.com/simonster/Reexport.jl/blob/master/src/Reexport.jl

macro reexport(ex)
    isa(ex, Expr) && (ex.head == :module ||
                      ex.head == :using ||
                      (ex.head == :toplevel &&
                       all(e->isa(e, Expr) && e.head == :using, ex.args))) ||
        error("@reexport: syntax error")

    if ex.head == :module
        modules = Any[ex.args[2]]
        ex = Expr(:toplevel, ex, :(using .$(ex.args[2])))
    elseif ex.head == :using && all(e->isa(e, Symbol), ex.args)
        modules = Any[ex.args[end]]
    elseif ex.head == :using && ex.args[1].head == :(:)
        symbols = [e.args[end] for e in ex.args[1].args[2:end]]
        return esc(Expr(:toplevel, ex, :(eval(Expr(:export, $symbols...)))))
    else
        modules = Any[e.args[end] for e in ex.args]
    end

    esc(Expr(:toplevel, ex,
             [:(eval(Expr(:export, names($mod)...))) for mod in modules]...))
end

end


text:
@doc raw"""
PathIntegralLinear is a path integral along a linear path

```math
\phi (\tau; q^-, q^+) = (1-\tau) q^- + \tau q^+ .
```
"""
struct PathIntegralLinear <: PathIntegral end

# function evaluate(path::PathIntegralLinear{T}, i::Int, τ::T) where {T}
#     if i == 1
#         return one(T)-τ
#     elseif i == 2
#         return τ
#     else
#         error("PathIntegralLinear has only two basis functions, not ", k, ".")
#     end
# end

# function derivative(path::PathIntegralLinear{T}, i::Int, τ::T) where {T}
#     if i == 1
#         return -one(T)
#     elseif i == 2
#         return +one(T)
#     else
#         error("PathIntegralLinear has only two basis functions, not ", k, ".")
#     end
# end

evaluate_l(path::PathIntegralLinear, τ::T) where {T} = one(T)-τ
evaluate_r(path::PathIntegralLinear, τ::T) where {T} = τ

derivative_l(path::PathIntegralLinear, τ::T) where {T} = -one(T)
derivative_r(path::PathIntegralLinear, τ::T) where {T} = +one(T)


text:
import Base.Random: rand

export bsmutate, bsmutate!

@doc """bsmutate(p::Population, mutprob::Float64)

Return a new population with a single locus of each individual in the original
population mutated (bit flipped if `ls.a == 2`) with probability `mutprob`.
"""
function bsmutate(p::Population, mutprob::Float64)
  np = Population(p)
  bsmutate!(np, mutprob)
  return np
end

@doc """bsmutate(mp::MetaPopulation, mutprob::Float64)
"""
function bsmutate(mp::MetaPopulation, mutprob::Float64)
  np = MetaPopulation(mp)
  bsmutate!(np, mutprob)
  return np
end

@doc """bsmutate(g::Genotype, mutprob::Float64)
"""
function bsmutate(g::Genotype, mutprob::Float64)
  ng = Genotype(g)
  if rand() < mutprob
    bsmutate!(ng)
  end
  return ng
end

@doc """bsmutate!(g::Genotype)

Mutate a single locus within the given genotype.
"""
function bsmutate!(g::Genotype)
  mask = AlleleMask(1) << rand(0:(g.landscape.n - 1))
  g.alleles = g.alleles $ mask
end

@doc """bsmutate(p::Population, ls::Landscape)

Mutate a population in-place by mutating up to one locus of each bitstring in
the population.
"""
function bsmutate!(p::Population, mutprob::Float64)
  for g = p.genotypes
    if rand() < mutprob
      bsmutate!(g)
    end
  end
end

@doc """bsmutate!(p::MetaPopulation, ls::Landscape, mutprob::Float64)
"""
function bsmutate!(mp::MetaPopulation, mutprob::Float64)
  for p = mp.populations
    bsmutate!(p, mutprob)
  end
end


text:
using BSplineKit

using Documenter
using Literate

const MAKE_FAST = "--fast" in ARGS  # skip some checks in makedocs

docmeta = quote
    using BSplineKit
    import Random
    Random.seed!(42)
end

# This is to make sure that doctests in docstrings are executed correctly.
DocMeta.setdocmeta!(BSplineKit, :DocTestSetup, docmeta; recursive=true)
DocMeta.setdocmeta!(BSplineKit.BandedTensors, :DocTestSetup,
                    :(using BSplineKit.BandedTensors); recursive=true)

with_checks = !MAKE_FAST

# Generate examples using Literate
# See https://github.com/fredrikekre/Literate.jl/blob/master/docs/make.jl
example_dir = joinpath(@__DIR__, "..", "examples")
output_dir = joinpath(@__DIR__, "src/generated")

for example in ["interpolation.jl", "approximation.jl", "heat.jl", ]
    filename = joinpath(example_dir, example)
    Literate.markdown(filename, output_dir, documenter=true)
end
@time makedocs(
    sitename="BSplineKit.jl",
    format=Documenter.HTML(
        prettyurls=true,
        # load assets in <head>
        assets=["assets/tomate.js"],
    ),
    modules=[BSplineKit],
    pages=[
        "Home" => "index.md",
        "Examples" => [
            "generated/interpolation.md",
            "generated/approximation.md",
            "generated/heat.md",
        ],
        "Library" => [
            "bsplines.md",
            "splines.md",
            "interpolation.md",
            "approximation.md",
            "recombination.md",
            "tensors.md",
            "galerkin.md",
            "collocation.md",
            "boundary_conditions.md",
            "Internals" => ["diffops.md"],
        ],
    ],
    doctest=with_checks,
    linkcheck=with_checks,
    checkdocs=:all,
)

# Documenter can also automatically deploy documentation to gh-pages.
# See "Hosting Documentation" and deploydocs() in the Documenter manual
# for more information.
deploydocs(
    repo = "github.com/jipolanco/BSplineKit.jl",
    forcepush = true,
    push_preview = true,  # PRs deploy at https://jipolanco.github.io/BSplineKit.jl/previews/PR??
)

max_stars_repo_name: jipolanco/BasisSplines

max_issues_repo_name: jipolanco/BasisSplines

max_forks_repo_name: jipolanco/BasisSplines


text:
@testset "Herm" begin
  include("Herm/Spaces.jl")
  include("Herm/Genus.jl")
  include("Herm/GenusRep.jl")
  include("Herm/Lattices.jl")
  include("Herm/LocallyIsometricSublattice.jl")
  include("Herm/Mass.jl")
end


text:
import Base: setindex!, haskey, getindex

struct TableBlock
  depth::Int
  entry::Dict{String, Union{TableBlock, Some}}
end

TableBlock() = TableBlock(0)
TableBlock(depth) = TableBlock(depth, Dict())

@inline haskey(tb::TableBlock, x) = haskey(tb.entry, x)

function _setentry!(tb::TableBlock, value, key; maxdepth=typemax(Int))
  (haskey(tb, key) || !any(isequal('.'), key) || tb.depth >= maxdepth) &&
    return setindex!(tb.entry, value, key)

  scope, id = split(key, '.'; limit=2)

  ctb = haskey(tb, scope) ? tb.entry[scope] : begin
    _ctb = TableBlock(tb.depth+1)
    setindex!(tb.entry, _ctb, scope)
    _ctb
  end
  return _setentry!(ctb, value, id)
end

function _getentry(tb::TableBlock, key; maxdepth=typemax(Int), error=false)
  (haskey(tb, key) || !any(isequal('.'), key) || tb.depth >= maxdepth) &&
    (error ? (return getindex(tb.entry, key)) : (return get(tb.entry, key, nothing)))

  scope, id = split(key, '.'; limit=2)

  if !haskey(tb, scope)
    error ? throw(KeyError(scope)) : return nothing
  else
    ctb = tb.entry[scope]
    !(ctb isa TableBlock) && (error ? throw(KeyError(scope)) : return nothing)
    return _getentry(ctb, id)
  end
end

struct HierarchicalTable
  maxdepth::Int
  head::TableBlock
end

HierarchicalTable() = HierarchicalTable(typemax(Int))
HierarchicalTable(maxdepth) = HierarchicalTable(maxdepth, TableBlock())

setindex!(ht::HierarchicalTable, value, key) = _setentry!(ht.head, Some(value), key; maxdepth=ht.maxdepth)

getindex(ht::HierarchicalTable, key) = something(_getentry(ht.head, key; maxdepth=ht.maxdepth, error=true))

haskey(ht::HierarchicalTable, key) = !isnothing(_getentry(ht.head, key))

const GLOBAL_MT = default_methods!(HierarchicalTable())

lookup(mt::HierarchicalTable, scope, name) = lookup(mt, join((scope, name), '.'))
function lookup(mt::HierarchicalTable, key)
  global GLOBAL_MT
  mtv = _getentry(mt.head, key)
  if isnothing(mtv)
    gmtv = _getentry(GLOBAL_MT.head, key)
    return isnothing(gmtv) ? gmtv : something(gmtv)
  else
    return something(mtv)
  end
end


text:
# AUTO GENERATED FILE - DO NOT EDIT

export vtk_pointdata

"""
    vtk_pointdata(;kwargs...)
    vtk_pointdata(children::Any;kwargs...)
    vtk_pointdata(children_maker::Function;kwargs...)

A PointData component.
PointData is exposing a vtkPointData to a downstream element
Keyword arguments:
- `children` (Array of a list of or a singular dash component, string or numbers | a list of or a singular dash component, string or number; optional)
"""
function vtk_pointdata(; kwargs...)
        available_props = Symbol[:children]
        wild_props = Symbol[]
        return Component("vtk_pointdata", "PointData", "dash_vtk", available_props, wild_props; kwargs...)
end

vtk_pointdata(children::Any; kwargs...) = vtk_pointdata(;kwargs..., children = children)
vtk_pointdata(children_maker::Function; kwargs...) = vtk_pointdata(children_maker(); kwargs...)

max_stars_repo_name: rodrigomologni/dash-vtk

max_issues_repo_name: rodrigomologni/dash-vtk

max_forks_repo_name: rodrigomologni/dash-vtk


text:
"""
Divide & Conquer (Bisection method )

-has Bisection method
1. normal way
2.Recursion [most used] [] <---

functions:
Context: divide & Conquer:
1. search() [the Easiest]
2. Right()
3. Left()

A recursive Algorithm
1       n/2         n
|        |          |

1/ look at  n/2 index

Compare left & compare right (do that in sequence)

if a[n/2] < a[n/2 ] ; n/2 middle index (Index)

"""
function search(arr, i = 1, val) #1
    val = findfirst(arr, i) #init val
    if val < arr[i] #terminal condition
        return
        for i in enumerate(length(arr))  #range(1, len(arr)):
            #check modulo is length of array is divisible by 2
            first = findfirst(arr)
            #TODO: Continue ...  <--- here
            if arr[i-1] < val && val <= arr[i]    #  |      |
                return i
            end

            # else if arr[i] > val && arr[i+1] >val
        end
        #end #close if
    end #close for

    #else
end
#end

#TODO: Bisection method #TODO: Revision #Sanity-check
#=
function searchRecursive(arr,i) #only ifs allowed
    if val < arr[i] #fallback condition
        return
    if arr[i] == val #special case(unicorn)

        #left side
    elseif arr[i-1] < val &&  arr[i] >= val   #val <= arr[i]  |      |
        bisect_left(a, x, low = 0, high = None) #3
    end
        #right side ()
    elseif arr[i-1] > val &&  arr[i] val <
        #TODO fill it
        bisect_right(a, x, low=0, high=None) #2
    end
=#
#=
function  bisect_right(a, x, low=0, high=None) #2
    if hi isa nothing # Searching to the end
        hi = length(a) # get length

    while low < high # More than one possibility
        mid = (low+high)//2 # Bisect (find midpoint)
    if x < a[mid] high = mid # Value < middle? Go left
        else low = mid+1 # Otherwise: go right
        return low
    end

#left side
function bisect_left(a, x, low = 0, high = None) #3
    if hi isa nothing # Searching to the end
        hi = length(a) # get length

    while low > high
        # check n
        mid = (low+high)//2
        return high
    end
end
=#

"""iseven
    Returns whether a number isEven or not
```input:
m: a number

```
output:
checkBool value or nothing
```
"""
function iseven(m) # \nerleg #͍
    ƞ = 0
    ƞ = m
    check = nothing
    condition = ƞ % 2
    if condition == 0
        check = true
    elseif Condition != 0
        check = false
    else# faulty input, or Unexpected error happened
        return check
    end
    return check
end

iseven(2);
iseven(0);
iseven(6);
iseven(3)
"""Testing Area here
        |   ----    |   ----    |
        left        mid         right
1)if value[left] < value[mid] #expected - do none
2)if value[left] > value[mid] #Action : swap (function call on recursion)
3)id value[left] == value[mid] #return

1) if value[right] < value[mid] #expected - do none
2) if value[right] > value[mid]
3) if value[right] == value[mid] #retrun

Infer: generalize: Mid stays the same - whether left or right
1) if value[i]< value[mid] # call left
2) if value[i] > value[mid] # call right
3) if value[i] == value[mid] # return
------
only way is recursion for floats:
beats mit 6.001 (freshmen can't do recursion) & 6.006 lecture @ (searching for time...)
|  -------       |        ------          |
l                m                        r
if (first(arr) - last(arr) )

function goleft(arr, i)
end

function goright(arr, i)

end
"""
"""
gets the Eucldian distance between 2 numbers
""" #Done: removed isEven(x)
sumInterval(a::Int64, b::Int64) = (abs(max(a, b)) + abs(min(a, b))) # was (max(a, b) - abs(min(a, b))) #Unsymmetric
function isMod(a::Int64, b::Int64)
    dif = sumInterval(a, b)  #% 2 == 0 #? fl = true : fl = false;
    res = nothing
    if dif % 2 == 0  #rem(dif, 2) == 0 #Particular definition error
        res = true
    elseif dif % 2 != 0 #isEven(dif) != 0
        res = false
    else # sth else happened during evaluation of rem
        return res
    end
    return res
end
isMod(1, 3)
using BenchmarkTools
@benchmark isEven(100)
@benchmark 100 % 2 == 0
#=
BenchmarkTools.Trial: 10000 samples with 1000 evaluations.
 Range (min … max):  0.001 ns … 19.500 ns  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     0.001 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   0.037 ns ±  0.200 ns  ┊ GC (mean ± σ):  0.00% ± 0.00%

  █                                                        ▁
  █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█ ▂
Infer: isEven(x) adds an overhead reflected in a relative lag
#Recommendation: as possible, do not use isEven(x)

  =#

function dist(a::Int64, b::Int64)
    return sumInterval(a, b)
end
#Solve problem: A. in the Abstract Domain
function ϟ(a, b) #\upkoppa
    return a + b
end
using BenchmarkTools
@benchmark ϟ(1, 3) # maximum time:     0.100 ns (0.00% GC)
#=
BenchmarkTools.Trial: 10000 samples with 1000 evaluations.
 Range (min … max):  0.001 ns … 2.200 ns  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     0.001 ns             ┊ GC (median):    0.00%
 Time  (mean ± σ):   0.042 ns ± 0.063 ns  ┊ GC (mean ± σ):  0.00% ± 0.00%

  █                                                       ▃
  █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█ ▂=#

@benchmark ϟ(1, 10^6) # maximum time:     44.800 ns (0.00% GC)
#=
BenchmarkTools.Trial: 10000 samples with 1000 evaluations.
 Range (min … max):  4.700 ns …  2.682 μs  ┊ GC (min … max): 0.00% … 0.00%
 Time  (median):     5.000 ns              ┊ GC (median):    0.00%
 Time  (mean ± σ):   8.556 ns ± 43.835 ns  ┊ GC (mean ± σ):  0.00% ± 0.00%

  █▄▃▄▄▄▄▄▂▂▂▂▃▂▁▁                                           ▂
  ██████████████████▇▇▇▆▇▆▆▇▆▆▄▆▅▅▅▄▅▆▅▅▄▄▅▅▅▆▅▄▆▆▆▇▇▆▆▆▆▅▁▅ █
  4.7 ns       Histogram: log(frequency) by time     27.4 ns <=
  #
#= there exits a huge dichotomy
#infer: UnOptimized
an increase of a 10^6 yeilds an increase in time maximum by  447.99999999999994 times
=# =#
@time ϟ(1, 3) #  0.000000 seconds # in @time,  we care about allocation
@time ϟ(1, 10^6)

#using Base.Threads

#nthreads() # 1

using BenchmarkTools
global strError = "ERROR: Unexpected argument(s), faulty input"
@benchmark sumInterval(10^2, 10^3)

#=

#special case
if arr[m]  == idx return m; # isa try
else
#go right
if arr[m] < idx return dichotomy (array, m+1, right)
else
#go left
return Dichotomy ( array , l eft ,m-1 ) ;

look at middle n/2

=#

#--- testing Area

"""
```input:
    sumInterval: a Calculated  Eucledian Distance (between 2 points)

```

```output:
```
"""

using BenchmarkTools
@benchmark midCriterion(1, 3) # |3 - 1| = 2 is isEven -true-> retrun isMidCriterion ->true  #  maximum time:     13.900 ns (0.00% GC)
@benchmark midCriterion(1, 10^6) # maximum time:     maximum time:     36.800 ns (0.00% GC)
#=increasing problem by 10^6 yeilds a relative increase in Computation time by  2.6474820143884887 times
=#
#2.2. middle Computation
"""
middle = 4-1 /2= 3/2 = 1.5 [false] (do ceil & floor) -> ceil = 2 , floor = 1
returns mid Criterion

```input
    m: middle part given by formula `m = b - a`
    checks
```

```output check:: Bool
  returns a Bool check given by `check= midCriterion(m)`
```

"""
function middle(a, b) # working
    criterion = nothing
    criterion = midCriterion(a, b)
    # check = nothing;check = midCriterion(m) #b-a
    check = nothing
    above = nothing
    below = nothing
    condition = criterion #   b-a
    if condition == true
        #return true #a.s. #euclidean Distance divided by 2 returing a whole integer
        check = Int(ϟ(a, b) // 2) # sumInterval(a, b) // 2 #* 1.0 # | b - a | // 2 isa Integer #sumInterval -to-> ϟ

    elseif condition == false
        #return false #a.s.# check = sumInterval(a,b)//2*1.0
        #GET Ceil & Floor
        check = ϟ(a, b) / 2 # sumInterval(a, b) / 2 * 1.0 # freely allowing floats, to be ceiled & floored
        above = Int(ceil(check)) #nearest index above
        below = Int(floor(check))
    else # faulty Input or Unexpected Error Occured
        return check  # nothing
    end
    return condition, check, above, below
end
#
middle(1, 4) #false # (false, 2.5, 3, 2)
middle(1, 3) #true  #
sumInterval(1, 3) # (true, 2//1, nothing, nothing)
#need functional notation so that output of middle(a,b) | middleExtraction argiments

function middleExtraction(condition, checkedValue; above = nothing, below = nothing)
    ⫙ = []
    criterion = nothing
    criterion = condition
    if criterion == true # there is only 1 value
        # only get the checkedValue
        push!(⫙, checkedValue)
    elseif criterion == false
        #then we have above & below to get (know for sure that below is under above)

        push!(⫙, above)
        push!(⫙, below)
    else # faulty input or Unexpected error Occured
        return
    end

    return q
end
#=
⫙ = middleExtraction(true,2) #\forkv
l = length(⫙)
if l ==1
    ♐ =
elseif  l ==2
    ♐ =
else #error faulty Input
    return

end
return

#Relationship between 2 consecutive Rationals is 1 99% a.s.
"""BisectSort
```input:
v: a concrete Vector (implements an AbstractArray{T,1})
a:
```

```output:
```
"""
#Solve problem: B. in the Applied Domain

#TODO: Check this function
function BisectSort(v, a::Int64, b::Int64)
    #TODO:  check sanity
    #1. get the ranges  & indicies of current vector
    firstindex(v, a)
    firstindex(v, b)
    aVal = a #_first = first(v) # Warning   #   <---
    bVal = b #_last = last(v) # Warning     #   <---
    bIdx = lastindex(b)
    aIdx = firstindex(a)
    #set terminal condition: in
    sumInterval = sumInterval(aIdx, bIdx)
    if sumInterval == 1
        # compare a, b  last compare
        a, b = compare(a, b) #possibl error (includes swap if first 1st larger than 2nd)
        #
        return
        #end
    elseif sumInterval > 1  # a-b> 1#there are still indicies to explore
        #calculate next mini-subrange (blookup? -> not recursive, middle ->Yes )
        #blookupRecursive()
        #BisectSort()
        return middle(a, b)#1.5 false , 1.5  ()
    else
        println(strError)
    end
end

function BisectSort(v::Vector)
    #1. get the ranges  & indicies of current vector
    aVal = first(v)
    bVal = last(v)
    bIdx = lastindex(v)
    aIdx = firstindex(v)

    #set terminal condition: in
    sumInterval = sumInterval(aIdx, bIdx) #checks distance of an array
    if sumInterval == 1 #fallback condition
        # compare a, b  last compare
        a, b = compare(v, aIdx, bIdx) #erroreous #maybe it's because it's nothing
        #
        return a, b
        #end
    elseif sumInterval > 1  # a-b> 1#there are still indicies to explore
        #calculate next mini-subrange (blookup? -> not recursive, middle ->Yes )

        #blookupRecursive()
        # BisectSort(a,b)  #TODO:
        return BisectSort(v, aVal, bVal) # reality
    #return middle(a, b)#1.5 false , 1.5  #ideal expectation
    else
        println(strError)
    end
end

"""here there is no array is provided (assumes user is proficient, knows what he's doing)
Right hand argument is assumed to have a lower side, if not , then swap
```input:
```
```output:
```
"""
swp = include("swap.jl")

"""compares
```input:

```
```output:
```
it fails if there is are Redundant values (as it returns the first (of beginning & ending ))
"""
function compare(arr) #errornous #warning becareful from its values

    aVal = first(arr) # arr[aIdx] # 5 v[1]= 5
    bVal = last(arr) #arr[bIdx] # v[last] = 1  5>1
    aIdx = firstindex(arr)
    bIdx = lastindex(arr) # bVal)
    #if aVal < bVal
    if aVal > bVal   # a > b #should be a < b
        #1. Swap values
        aVal, bVal = oldschoolSwap(aVal, bVal) #correct #x, y) # (bVal, aVal) #ERROR T not defined
        #2. Swap  array indicies(with correct orders)
        arr[aIdx], arr[bIdx] = oldschoolSwap(arr[aIdx], arr[bIdx])

    elseif aVal < bVal # at that level (diff length) of indicies # the array is correct
        return aVal, bVal

    else #faulty input , Unexpected code
        println(strError)
        return
    end
    return aVal, bVal, arr  #min, max #deketed values
end
#Applied Domain
v = [8, 4, 2]
aVal = first(v)
bVal = last(v)
aIdx = firstindex(v)
bIdx = lastindex(v)
#Q.are all 2 necessary (not 3)
#1. Swap values
aVal, bVal = oldschoolSwap(aVal, bVal) #correct #x, y) # (bVal, aVal) #ERROR T not defined
#2. Swap indicies
v[aIdx], v[bIdx] = oldschoolSwap(v[aIdx], v[bIdx])

res = collect(compare(v)) #correct swap indecies & values
aVal = first(v)# 8 #2
bVal = last(v) # 2 #8
aIdx = firstindex(v)#1
bIdx = lastindex(v)#3
#----
aVal = first(res)# 8 #2
bVal = last(res) # 2 #8
aIdx = firstindex(res)#1
bIdx = lastindex(res)#3 # should be 3 #displayed 2  #why?
#---
aVal = first(v)
bVal = last(v)
bIdx = lastindex(v)
aIdx = firstindex(v)
#set terminal condition: in
sumInterval = sumInterval(aIdx, bIdx)

#----
res == v
res === v
typeof(v)
typeof(res)
#-----------------------------------
#check indicies : a< b
aIdx > bIdx ? true : false
#check valuse: aVal > bVal <---- Infer: swap (TODO:Automatic)
aVal > bIdx ? true : false
a, b = oldschoolSwap(v[aIdx], v[bIdx])
v[aIdx], v[bIdx] = v[aIdx], v[bIdx] # swap is not functioning, as expected
v[aIdx], v[bIdx] = v[aIdx], v[bIdx]
#manual work - working !
tmp = v[aIdx]
v[aIdx] = v[bIdx]
v[bIdx] = tmp

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

#@benchmark v[aIdx], v[bIdx] =
@benchmark oldschoolSwap(v[aIdx], v[bIdx])
"""
run betrics

    @btime   80.498 ns (1 allocation: 32 bytes)
    @time 0.000008 seconds (1 allocation: 32 bytes)
    @benchmark
    BenchmarkTools.Trial: 10000 samples with 963 evaluations.
    Range (min … max):   80.893 ns …  2.189 μs  ┊ GC (min … max): 0.00% … 95.18%
    Time  (median):      86.604 ns              ┊ GC (median):    0.00%
    Time  (mean ± σ):   101.256 ns ± 55.861 ns  ┊ GC (mean ± σ):  1.05% ±  2.30%

    ▅▇█▄▂▁▃▅▃▂▂ ▁ ▁▁▂▁                                           ▁
    ███████████████████████████▇▇▇▇▇▇▇▇▇▆▇▆▆▇▇▇▆▆▆▆▆▇▆▆▆▆▅▆▅▅▄▄▆ █
    80.9 ns       Histogram: log(frequency) by time       239 ns <

    Memory estimate: 32 bytes, allocs estimate: 1.
"""
function oldschoolSwap(x, y)
    tmp = x
    x = y
    y = tmp
    return x, y
end
#returning firstindex(aVal) = lastIndex(bVal) = 1
#infer: a swap must be done by the condition: aVal > bVal

#testing compare
v = [8, 4, 2] #[5, 3, 1]

res = compare(v)#, firstindex(v), firstindex(v)) #ERROR!  2,8, [2,4,8]

function swap(a, b)
    #    a, b = nothing
    if typeof(a) == typeof(b) == Float64 || typeof(a) == typeof(b) == Array{T,N}
        # swap floats  (or arrays)
        a, b = swp.swap!(a, b)

    else
        #faulty input
        println(strError) #defaults to this
    end
    return a, b
end

#testRun
# v = collect(1:3) #given intRange, collect it as a vector v=1,2,3 #that is vector of index
v = [10, 7, 3] #that's a typical scenario!
sumInterval(3, 1)

#res = BisectSort(v)

aVal = first(v)
bVal = last(v)
aIdx = firstindex(v)
bIdx = lastindex(v)
#set terminal condition: in
sumInterval = sumInterval(aIdx, bIdx) #checks distance of an array
stack = []
if sumInterval > 1  # a-b> 1#there are still indicies to explore
    #calculate next mini-subrange (blookup? -> not recursive, middle ->Yes )
    #blookupRecursive()
    # BisectSort(a,b)  #TODO:

    push!(stack, BisectSort(v, aVal, bVal)) # reality  #error here possibly
end
stack #nothing
compare(v)

max_stars_repo_name: adamwillisMastery/DeepLearner

max_issues_repo_name: adamwillisMastery/DeepLearner

max_forks_repo_name: adamwillisXanax/DeepLearner


text:
RectGrid(nrows, ncols)::Grid{Rect,NonPeriodic} = Grid(Rect, NonPeriodic, nrows, ncols)

PeriodicRectGrid(nrows, ncols)::Grid{Rect,Periodic} = Grid(Rect, Periodic, nrows, ncols)

function Base.display(grid::Grid{Rect})
    nrows, ncols = grid.nrows, grid.ncols
    output = "+"
    for col in 1:ncols
        output *= is_connected(grid[1, col], north(grid, 1, col)) ? "   +" : "---+"
    end
    output *= "\n"

    for row in 1:(nrows)
        top = is_connected(grid[row, 1], west(grid, row, 1)) ? " " : "|"
        bottom = "+"
        for col in 1:(ncols)
            cell = grid[row, col]
            body = "   "
            east_boundary = is_connected(cell, east(grid, cell)) ? " " : "|"
            top *= body * east_boundary
            south_boundary = is_connected(cell, south(grid, cell)) ? "   " : "---"
            corner = "+"
            bottom *= south_boundary * corner
        end
        output = output * top * "\n"
        output = output * bottom * "\n"
    end
    print(output)
    return nothing
end


text:
# Some handy functions

"""
    Compute the Kullback-Leibler-Divergence of the two Vectors `a` and `b`.
"""
function compute_KL_divergence(a::Vector{T}, b::Vector{T}) where {T}
    # normalization
    a /= maximum(a)
    b /= maximum(b)
    # make histograms
    h1 = fit(Histogram, a)
    edges = h1.edges
    h2 = fit(Histogram, b, edges...)
    # get the probabilities
    pdf1 = h1.weights / sum(h1.weights)
    pdf2 = h2.weights / sum(h2.weights)
    # compute KL-divergence
    return kl_divergence(pdf2, pdf1)
end

"""
    Return the local maxima of the given time series s and its indices
"""
function get_maxima(s::Vector{T}) where {T}
    maximas = T[]
    maximas_idx = Int[]
    N = length(s)
    flag = false
    first_point = 0
    for i = 2:N-1
        if s[i-1] < s[i] && s[i+1] < s[i]
            flag = false
            Base.push!(maximas, s[i])
            Base.push!(maximas_idx, i)
        end
        # handling constant values
        if flag
            if s[i+1] < s[first_point]
                flag = false
                Base.push!(maximas, s[first_point])
                Base.push!(maximas_idx, first_point)
            elseif s[i+1] > s[first_point]
                flag = false
            end
        end
        if s[i-1] < s[i] && s[i+1] == s[i]
            flag = true
            first_point = i
        end
    end
    # make sure there is no empty vector returned
    if isempty(maximas)
        maximas_s, maximas_idx_s = findmax(s)
        Base.push!(maximas, maximas_s)
        Base.push!(maximas_idx, maximas_idx_s)
    end
    return maximas, maximas_idx
end

"""
    compute_delta_L(s, τs, (js,) T_max; KNN = 3, w = 1, metric = Euclidean) → ΔL

    Compute the overall L-decrease `ΔL` of a given embedding of the time series
    `s::Vector` with the delay values `τs` up to a maximum `T`-value `T_max`. We
    respect the Theiler window `w`, the chosen `metric` and the number of considered
    nearest neighbors `KNN`. It is also possible to compute `ΔL` for a multivariate
    input `Y::Dataset`. Then one additionally needs to supply a vector `js`, which
    lists the chosen time series corresponding to the given delay values in `τs`.
    This is similar to the procedure in [`genembed`]@ref. The computations are based
    on z-standardized input for ensuring comparability.
"""
function compute_delta_L(s::Vector{T}, τs::Vector{Int}, T_max::Int;
        KNN::Int = 3, w::Int = 1, metric = Euclidean(), tws::AbstractRange{Int} = 2:T_max
    ) where {T}
    ts = DelayEmbeddings.standardize(Dataset(s))
    tss = vec(Matrix(Dataset(ts)))
    ΔL = 0
    Y_act = ts
    for i = 1 : (length(τs)-1)
        τ = τs[i+1]
        # embedding one cycle
        Y_next = DelayEmbeddings.hcat_lagged_values(Y_act, tss, τ)
        # compute ΔL for this cycle
        ΔL += uzal_cost_pecuzal_mcdts(Y_act, Y_next, T_max; K = KNN, w,
                                                    metric, tws)
        Y_act = Y_next
    end
    return ΔL
end

function compute_delta_L(Y::Dataset{D, T}, τs::Vector{Int}, js::Vector{Int},
        T_max::Int; KNN::Int = 3, w::Int = 1, metric = Euclidean(),
        tws::AbstractRange{Int} = 2:T_max) where {D, T}
    @assert length(τs) == length(js)
    ts = DelayEmbeddings.standardize(Y)
    ΔL = 0
    Y_act = Dataset(ts[:,js[1]])
    for i = 1: (length(τs)-1)
        τ = τs[i+1]
        # embedding one cycle
        Y_next = DelayEmbeddings.hcat_lagged_values(Y_act, ts[:,js[i+1]], τ)
        # compute ΔL for this cycle
        ΔL += uzal_cost_pecuzal_mcdts(Y_act, Y_next, T_max; K = KNN, w,
                                                    metric, tws)
        Y_act = Y_next
    end
    return ΔL
end


text:
# specification colnames
function get_colnames(specification::ParameterTable)
    if !haskey(specification.variables, :sorted_vars) ||
            (length(specification.variables[:sorted_vars]) == 0)
        colnames = specification.variables[:observed_vars]
    else
        is_obs = [var ∈ specification.variables[:observed_vars] for var in specification.variables[:sorted_vars]]
        colnames = specification.variables[:sorted_vars][is_obs]
    end
    return colnames
end

function get_colnames(specification::RAMMatrices)
    if isnothing(specification.colnames)
        @warn "Your RAMMatrices do not contain column names. Please make shure the order of variables in your data is correct!"
        return nothing
    else
        colnames = specification.colnames[specification.F_ind]
        return colnames
    end
end

function get_colnames(specification::Nothing)
    return nothing
end


text:
module RPG #end

# NOTES:

using SimpleDirectMediaLayer, SDLGamesLib
SDL2 = SimpleDirectMediaLayer

import SDLGamesLib: QuitException, start!, GameTimer, WallTimer, started, elapsed, update!,
    pollEvent!, bitcat, unitVec, leftJustified, rightJustified, render

import Statistics: mean

using ApplicationBuilderAppUtils

# True if this file is being run through the interpreter, and false if being
# compiled.
debug = true

# Override SDL libs locations if this script is being compiled for mac .app builds
if get(ENV, "COMPILING_APPLE_BUNDLE", "false") == "true"
    #  (note that you can still change these values b/c no functions have
    #  actually been called yet, and so the original constants haven't been
    #  "compiled in".)
    eval(SDL2, :(libSDL2 = "libSDL2.dylib"))
    eval(SDL2, :(libSDL2_ttf = "libSDL2_ttf.dylib"))
    eval(SDL2, :(libSDL2_mixer = "libSDL2_mixer.dylib"))
    debug = false
end

const assets = "assets" # directory path for game assets relative to pwd().

include("config.jl")
include("../assets/configs.jl")
include("player.jl")
include("game.jl")
include("display.jl")
include("keyboard.jl")
include("menu.jl")

using SDLGamesLib.Animations
using SDLGamesLib.Animations: Sprite

const kGAME_NAME = "Paddle Battle"
const kSAFE_GAME_NAME = "PaddleBattle"
const kBUNDLE_ORGANIZATION = "nhdalyMadeThis"

SDLGamesLib.set_default_font(defaultFontName, defaultFontSize)
# -------------- Game ------------------------------

# Game State Globals
renderer = win = nothing
p1 = Player()
p2 = Player()
cam = nothing
scoreA = 0
scoreB = 0
paused = Ref(true) # start paused to show the initial menu.
game_started = Ref(true)
playing = Ref(true)
debugText = false
audioEnabled = true
last_10_frame_times = [1.]
timer = SDLGamesLib.frame_timer
i = 1

sceneStack = []  # Used to keep track of the current scene

include("../assets/game_configs.jl")

e = nothing  # FOR DEBUGGING ONLY!

struct UserError
    msg
end

"""
    runSceneGameLoop(scene, renderer, win, inSceneVar::Ref{Bool})
The main game loop. Implements the poll, render, update loop, delegating to the
current scene (pushes it to the top of sceneStack).
 - Polls SDL events and passes them to `handleEvents!(scene, e, t)`.
 - Calls `render(scene, renderer, win)`.
 - Calls `performUpdates!(scene, dt)`.
This loop continues until the provided `inSceneVar` is false, then pops the
scene off the sceneStack.
"""
function runSceneGameLoop(scene, renderer, win, inSceneVar::Ref{Bool})
    global last_10_frame_times, i, e
    push!(sceneStack, scene)
    start!(timer)
    while (inSceneVar[])
        # Don't run if game is paused by system (resizing, lost focus, etc)
        while SDLGamesLib.window_paused[] != 0  # Note that this will be fixed by windowEventWatcher
            _ = pollEvent!()
            sleep(0.5)  # maybe increase this?
        end
        # Reload config for debug
        if (debug) reloadConfigsFiles() end

        # Handle Events
        errorMsg = ""
        try
            hadEvents = true
            while hadEvents
                e,hadEvents = pollEvent!()
                t = SDLGamesLib.getEventType(e)
                handleEvents!(scene,e,t)
            end
        catch e
            if isa(e, UserError)
                errorMsg = e.msg
            else
                rethrow()
            end
        end

        # Render
        render(scene, renderer, win)
        if (debug && debugText) renderFPS(renderer,last_10_frame_times) end
        if (errorMsg != "") renderText(renderer, cam, errorMsg, UIPixelPos(winWidth[]*1/2, 200)) end
        SDL2.RenderPresent(renderer)

        # Update
        dt = elapsed(timer)
        # Don't let the game proceed at fewer than this frames per second. If an
        # update takes too long, allow the game to actually slow, rather than
        # having too big of frames.
        min_fps = 20.0
        dt = min(dt, 1.0/min_fps)
        start!(timer)
        if debug
            last_10_frame_times = push!(last_10_frame_times, dt)
            if length(last_10_frame_times) > 10; pop!(last_10_frame_times) ; end
        end

        performUpdates!(scene, dt)
        #sleep(0.01)

        if (playing[] == false)
            throw(QuitException())
        end

        i += 1
    end
    pop!(sceneStack)
end
# Scenes must overload these functions:
#  render(scene, renderer, win)
#  handleEvents!(scene, e,t)
# Scenes can optionally overload this function:
function performUpdates!(scene, dt) end  # default

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

function renderFPS(renderer,last_10_frame_times)
    fps = Int(floor(1.0/mean(last_10_frame_times)))
    txt = "FPS: $fps"
    renderText(renderer, cam, txt, UIPixelPos(winWidth[]*1/5, 200))
end

# -------------- Game Scene ---------------------
struct GameScene end

module P
using ..RPG: WorldPos, SDL2, Vector2D, unitVec
mutable struct Character
    health::Int
    color::SDL2.Color
    pos::WorldPos
    Character(health, color, pos) = new(health, color, pos,)
    #                                    # movement
    #                                    true, pos, pos)
    #
    ## Movement
    #resting::Bool
    #nextPos::WorldPos
    #lastPos::WorldPos
end

const a = P.Character(10, SDL2.Color(0xff,0,0,0xff), WorldPos( 0,0))
const b = P.Character(10, SDL2.Color(0,0xff,0,0xff), WorldPos(-1,0))
const c = P.Character(10, SDL2.Color(0,0,0xff,0xff), WorldPos(-2,0))
const d = P.Character(10, SDL2.Color(0,0xff,0xff,0xff), WorldPos(-3,0))
const e = P.Character(10, SDL2.Color(0xff,0,0xff,0xff), WorldPos(-4,0))

const party = [a,b,c,d,e]
const ready = Ref(true)

function reset_party()
    for (i,p) in enumerate(party)
        p.pos = WorldPos(-i, 0)
    end
    party[:] = [a,b,c,d,e]
end
reset_party()

const animspeed = 0.5
end

function follow_along(move)
    P.ready[] = false  # Lock character movement until the front char has swapped out

    # Note that this is totallllly not thread-safe, and should probably be updated to being
    # some kind of game-specific event mechanism, or made threadsafe.
    @async begin
        p = P.party

        function swap_chars(p_a, p_b)
            p[p_a].pos, p[p_b].pos = p[p_b].pos, p[p_a].pos  # swap positions
            p[p_a],     p[p_b]     = p[p_b],     p[p_a]  # swap place in party
        end

        # Bump along like a worm
        @async begin
            # Move front character by `move`
            old_pos = p[1].pos;  p[1].pos += move; sleep(P.animspeed)
            # Bump the rest along every update
            for i in 2:length(p)
                old_pos, p[i].pos = p[i].pos, old_pos; sleep(P.animspeed)
            end
        end

        # Cascade front moving to back
        @async begin
            # Wait while the front rests && 2nd-place bumps up
            front_id = 1 ; sleep(2*P.animspeed)
            P.ready[] = true  # Unlock movement once we've swapped
            # Then Cascade the front character back through the group
            for i in 2:length(p)
                swap_chars(front_id, front_id+1)
                front_id = front_id+1 ; sleep(P.animspeed)
            end
        end
    end
#end
end

#function update_characters()
#    for p in P.party[1:end]
#        if p.resting
#            # Skip this round
#            p.resting = false
#        else
#            p.pos, p.lastPos = p.nextPos, p.pos
#        end
#    end
#end
#function step1(move)
#    lastPos = P.party[1].pos
#    # attack
#    P.party[1].pos += move
#    P.party[1].resting = true
#    # set targets
#    P.party[2].nextPos = lastPos
#    P.party[2].resting = false
#end
#function step2()
#    P.party[1].nextPos = P.party[2].pos
#    # set targets
#    P.party[2].nextPos = P.party[1].pos
#    for i in 3:length(P.party)
#        P.party[i].nextPos = P.party[i-1].lastPos
#    end
#end
#function step3()
#    P.party[1].nextPos = P.party[3].pos
#    # set targets
#    P.party[3].nextPos = P.party[1].pos
#end
#function step4()
#    P.party[:] = circshift(P.party, -1)
#end

function handleEvents!(scene::GameScene, e,t)
    global playing,paused
    # Handle Events
    if (t == SDL2.KEYDOWN || t == SDL2.KEYUP);  handleGameKeyPress(e,t);
    elseif (t == SDL2.MOUSEWHEEL); handleMouseScroll(e)
    #elseif (t == SDL2.MOUSEBUTTONUP || t == SDL2.MOUSEBUTTONDOWN)
    #elseif (t == SDL2.MOUSEMOTION); handleMousePan(e)
    elseif (t == SDL2.QUIT)
        playing[] = false;
    end

    if (paused[])
         pause!(timer)
         enterPauseGameLoop(renderer,win)
         unpause!(timer)
    end
end
function handleMouseScroll(e)
    #SDLGamesLib.zoomFromMouseScroll(e, cam)
    zoomFromMouseScroll(e, cam)
end
function zoomFromMouseScroll(e, cam)
    my = bitcat(SDL2.Sint32, e[24:-1:21])

    # TODO: move cam based on mouse pos during scroll
    #  want to keep mouse pos over same WorldPos while scrolling.
    #  ie: toScreenPos(toWorldPos(ScreenPixelPos(mx,my),cam),cam) ==
    #         toScreenPos(toWorldPos(ScreenPixelPos(mx,my),cam2),cam2)
    # zoom
    aspectRatio = cam.w[] / cam.h[]
    cam.w[] -= my * kCamZoomRate  # If scrolling up, zoom in (shrink camera).
    cam.h[] -= my * kCamZoomRate  # (positive `my` is scrolling up)
    if cam.w[] <= kCamMinSize
        cam.w[] = kCamMinSize
        cam.h[] = kCamMinSize / aspectRatio
    elseif cam.h[] <= kCamMinSize
        cam.w[] = kCamMinSize * aspectRatio
        cam.h[] = kCamMinSize
    end
end

#function handleGameMouseClick!(e, clickType)
#    mx = bitcat(UInt32, e[24:-1:21])
#    my = bitcat(UInt32, e[28:-1:25])
#    mButton = e[17]
#    if mButton == SDL2.BUTTON_RIGHT
#        p = toWorldPos(UIPixelPos(mx,my), cam)
#    end
#end

const K_ARROW_KEYS = (SDL2.SDLK_RIGHT, SDL2.SDLK_LEFT, SDL2.SDLK_UP, SDL2.SDLK_DOWN)
function handleGameKeyPress(e,t)
    global paused,debugText
    keySym = getKeySym(e)
    keyDown = (t == SDL2.KEYDOWN)
    keyRepeat = (getKeyRepeat(e) != 0)

#    if (keySym == keySettings[:keyP1Collector])
#        buyCollector(p1)
#    elseif (keySym == keySettings[:keyP2Collector])
#        buyCollector(p2)
#    elseif (keySym == keySettings[:keyP1Fighter])
#        buyFighter(p1)
#    elseif (keySym == keySettings[:keyP2Fighter])
#        buyFighter(p2)
#    elseif (keySym == keySettings[:keyP1Attack] && keyDown && !keyRepeat)
#        attackToggle(p2, p1)
#    elseif (keySym == keySettings[:keyP2Attack] && keyDown && !keyRepeat)
#        attackToggle(p1, p2)
    if keyDown && keySym ∈ K_ARROW_KEYS
        if false
        elseif (keySym == SDL2.SDLK_RIGHT)
            move = Vector2D(1,0)
        elseif (keySym == SDL2.SDLK_LEFT)
            move = Vector2D(-1,0)
        elseif (keySym == SDL2.SDLK_UP)
            move = Vector2D(0,1)
        elseif (keySym == SDL2.SDLK_DOWN)
            move = Vector2D(0,-1)
        end

        if !P.ready[]
            return
        end
        follow_along(move)
    else
        # Fallback
        handlePauseKeyPress(e,t)
    end
end

unitRenderColor(::Type{Fighter}) = kFighterColor
unitRenderColor(::Type{Collector}) = kCollectorColor
playerRenderColor(p::Player) = (if (p === p1) kP1Color elseif (p === p2) kP2Color end)

function render(scene::GameScene, renderer, win)
    global scoreA,scoreB,last_10_frame_times,paused,playing

    SetRenderDrawColor(renderer, kBackgroundColor)
    SDL2.RenderClear(renderer)

    renderScore(renderer)

    #renderFoodParticles(cam,renderer, curFoodParticles)

    box = WorldDims(0.8, 0.8)
    for p in P.party
        renderRectCentered(cam, renderer, p.pos, box, p.color)
    end
    #for u in p1.units.units
    #    render(u, kP1Color, cam, renderer)
    #end
    #for u in p2.units.units
    #    render(u, kP2Color, cam, renderer)
    #end

    # UI text at bottom
    renderText(renderer, cam, "P1: $(display_key_setting(:keyP1Collector)): collector (\$$(build_cost(Collector)))   $(display_key_setting(:keyP1Fighter)): scout (\$$(build_cost(Fighter))) $(display_key_setting(:keyP1Attack)): Attack",
               UIPixelPos(5, winHeight[] - kUIFontSize)
               ; fontSize=kUIFontSize, align=leftJustified)
    renderText(renderer, cam, "P2: $(display_key_setting(:keyP2Collector)): collector (\$$(build_cost(Collector)))   $(display_key_setting(:keyP2Fighter)): scout (\$$(build_cost(Fighter))) $(display_key_setting(:keyP2Attack)): Attack",
               UIPixelPos(winWidth[]-5, winHeight[] - kUIFontSize)
               ; fontSize=kUIFontSize, align=rightJustified)

    # BuildOp UI
    function drawBuildOps(p, xPos)
        buildOpsHeight = kBuildOpsRenderHeight
        for b in p.build_ops
            pos = UIPixelPos(xPos, winHeight[] - buildOpsHeight)
            percent = time_remaining(b) / b.buildLength
            renderProgressBar(percent, cam, renderer, pos,
                    UIPixelDims(200, 10), blendAlphaColors(playerRenderColor(p), unitRenderColor(b.unitType)),
                    kBuildOpsBgColor, healthBarOutlineColor)
            buildOpsHeight += 10
        end
    end
    drawBuildOps(p1, winWidth[]/4)
    drawBuildOps(p2, winWidth[]*3/4)

end

function renderScore(renderer)
    # Size the text with a single-digit score so it doesn't move when score hits double-digits.
    txtDims = toUIPixelDims(sizeText("Player 1: 0", defaultFontName, defaultFontSize), cam)
    hcat_render_text(["Player 1: $(floor(p1.money))","Player 2: $(floor(p2.money))"], renderer, cam,
         100, UIPixelPos(screenCenterX(), 20)
         ; fixedWidth = txtDims.w)
end

function performUpdates!(scene::GameScene, dt)
    global p1, p2
    reloadConfigsFiles(["../assets/configs.jl", "../assets/game_configs.jl"])
    update!(p1, dt)
    update!(p2, dt)

    performAttackUpdate!(dt)

    #moveCamIfMouseOnEdge!(dt)
    #updateFoodParticles(dt)
    yield()
end

foodSheetDriftVel = Vector2D(0,0)
function updateFoodParticles(dt)
    global curFoodParticles,worldFoodSheetOffset,foodSheetDriftVel
    curFoodParticles = foodDistribution(cam.pos, WorldDims(cam.w[],cam.h[]))

    worldFoodSheetOffset += foodSheetDriftVel * dt
    #range = (kFoodSheetDriftMaxSpeed_sqrd - magSqrd(foodSheetDriftVel))
    driftAccel = Vector2D(rand(-kFoodSheetDriftAccel:0.01:kFoodSheetDriftAccel, 2)...) * dt
    foodSheetDriftVel += driftAccel
    if magSqrd(foodSheetDriftVel) > kFoodSheetDriftMaxSpeed_sqrd
        foodSheetDriftVel -= foodSheetDriftVel * (0.1 * dt)
    end

    collectorDims = WorldDims(collectorRenderWidth,collectorRenderWidth)
    for p in curFoodParticles
        for c in p1.units.collectors
            if overlapping(toWorldPos(p.pos), p.size, c.pos, collectorDims)
                destroyFoodParticle(p)
                p1.money += p.amountFood
            end
        end
    end
end

function moveCamIfMouseOnEdge!(dt)
    x,y = Int[1], Int[1]
    #SDL2.PumpEvents()
    SDL2.GetMouseState(pointer(x), pointer(y))
    if (winWidth[] - x[]) < kMouseEdgeDetectionWidth
        cam.pos += Vector2D(kCamPanRate,0) * dt
    elseif x[] < kMouseEdgeDetectionWidth
        cam.pos += Vector2D(-kCamPanRate,0) * dt
    end
    if y[] < kMouseEdgeDetectionWidth
        cam.pos += Vector2D(0,kCamPanRate) * dt
    elseif (winHeight[] - y[]) < kMouseEdgeDetectionWidth
        cam.pos += Vector2D(0,-kCamPanRate) * dt
    end
end

function enterWinnerGameLoop(renderer,win, winnerName)
    # Reset the buttons to the beginning of the game.
    buttons[:bRestart].enabled = false # Nothing to restart
    buttons[:bNewContinue].text = "New Game"
    global paused,game_started; paused[] = true; game_started[] = false;

    scene = PauseScene("$winnerName wins!!", "")
    runSceneGameLoop(scene, renderer, win, paused)

    # When the pause scene returns, reset the game before starting.
    resetGame()
end
function resetGame()
    global scoreA,scoreB, p1, p2, cam, attackingMap
    cam = Camera(WorldPos(0,0),
             Threads.Atomic{Float32}(50),
             Threads.Atomic{Float32}(50))

    scoreB = scoreA = 0
    p1 = Player()
    add_unit!(p1.units, Collector(p1.units, WorldPos(-250,50)))
    add_unit!(p1.units, Fighter(p1.units, WorldPos(-200,200)))
    add_unit!(p1.units, Fighter(p1.units, WorldPos(-200,-200)))

    p2 = Player()
    add_unit!(p2.units, Collector(p2.units, WorldPos(250,50)))
    add_unit!(p2.units, Fighter(p2.units, WorldPos(200,200)))
    add_unit!(p2.units, Fighter(p2.units, WorldPos(200,-200)))

    attackingMap = Dict(p1=>false, p2=>false)
end

mutable struct KeyControls
    rightDown::Bool
    leftDown::Bool
    KeyControls() = new(false,false)
end
const paddleAKeys = KeyControls()
const paddleBKeys = KeyControls()
mutable struct GameControls
    escapeDown::Bool
    GameControls() = new(false)
end
const gameControls = GameControls()

randScreenPos(cam) = UIPixelPos(rand(0:winWidth[]), rand(0:winHeight[]))
randWorldPosOnScreen(cam) = toWorldPos(randScreenPos(cam), cam)
getKeySym(e) = bitcat(UInt32, e[24:-1:21])
getKeyRepeat(e) = bitcat(UInt8, e[14:-1:14])
function handlePauseKeyPress(e,t)
    global paused,debugText
    keySym = getKeySym(e)
    keyDown = (t == SDL2.KEYDOWN)

    if (keySym == SDL2.SDLK_ESCAPE)
        if (!gameControls.escapeDown && keyDown)
            if game_started[]  # Escape shouldn't start the game.
                paused[] = !paused[]
            end
        end
        gameControls.escapeDown = keyDown
    elseif (keySym == SDL2.SDLK_BACKQUOTE)
        keyDown && (debugText = !debugText)
    end
end

function randPosAroundCollectors(p, randRange)
    if isempty(p.units.collectors)
        randPos = randWorldPosOnScreen(cam)
    else
        randCollectorPos = rand(p.units.collectors).pos
        randPos = WorldPos(rand(-randRange:randRange) + randCollectorPos.x,
                        rand(-randRange:randRange) + randCollectorPos.y)
    end
end
function randPosAroundFighters(p, randRange)
    if isempty(p.units.fighters)
        throw(UserError("Must have a scout to create Collector."))
    else
        randFighterPos = rand(p.units.fighters).pos
        randPos = WorldPos(rand(-randRange:randRange) + randFighterPos.x,
                        rand(-randRange:randRange) + randFighterPos.y)
    end
end
function buyCollector(p)
    purchase_collector!(p, randPosAroundFighters(p, kRandPurchaseCollectorPosRange))
end
function buyFighter(p)
    randRange = 300
    if isempty(p.units.collectors)
        audioEnabled && SDL2.Mix_PlayChannel( Int32(-1), badKeySound, Int32(0) )
    else
        purchase_fighter!(p, randPosAroundCollectors(p, kRandPurchaseFighterPosRange))
    end
end

attackingMap = Dict(p1=>false, p2=>false)
function attackToggle(pTarget, p)
    attackingMap[p] = !attackingMap[p]
    if attackingMap[p]
        # sick units on pTarget's units
        for f in p.units.fighters
            if isempty(pTarget.units.units)
                break
            end
            f.attackTargetUnit = rand(pTarget.units.units)
        end
    else
        for f in p.units.fighters
            f.attackTargetUnit = nothing
        end
    end
end
function performAttackUpdate!(dt)
    # Move units towards pTarget's units
    units_to_destroy = []
    for f in [p1.units.fighters..., p2.units.fighters...]
        # Stop attacking if target already dead or not attacking anything
        if f.attackTargetUnit == nothing || f.attackTargetUnit.health <= 0
            f.attackTargetUnit = nothing
            continue
        end
        targetVec = f.attackTargetUnit.pos - f.pos
        if (magSqrd(targetVec) > 1) targetVec = unitVec(targetVec) end
        f.pos += targetVec * kFighterSpeed * dt

        if overlapping(f.pos,kFighterSize, f.attackTargetUnit.pos, kFighterSize)
            attack!(f.attackTargetUnit, f)
            push!(units_to_destroy, f)
        end
    end
    for f in units_to_destroy
        set_health!(f, 0)
        destroy_unit!(f)
    end
end

# -------------- Pause Scene ---------------------
struct PauseScene
    titleText::String
    subtitleText::String
end
function enterPauseGameLoop(renderer,win)
    global paused
    scene = PauseScene("$kGAME_NAME", "Main Menu")
    runSceneGameLoop(scene, renderer, win, paused)
end
function handleEvents!(scene::PauseScene, e,t)
    global playing,paused
    # Handle Events
    if (t == SDL2.KEYDOWN || t == SDL2.KEYUP);  handlePauseKeyPress(e,t);
    elseif (t == SDL2.MOUSEBUTTONUP || t == SDL2.MOUSEBUTTONDOWN)
        b = handleMouseClickButton!(e,t);
        if (b != nothing); run(b); end
    elseif (t == SDL2.MOUSEMOTION)
        handleMouseMotion_Pause(e)
    elseif (t == SDL2.QUIT);
        playing[]=false; paused[]=false;
    end
end

heartIcon = nothing
jlLogoIcon = nothing
knight_run_anim = nothing
knight_jump_anim = nothing
knight_attack_anim = nothing
function render(scene::PauseScene, renderer, win)
    global heartIcon, jlLogoIcon
    if heartIcon == nothing || jlLogoIcon == nothing
        heart_surface = SDL2.LoadBMP("assets/heart.bmp")
        heartIcon = SDL2.CreateTextureFromSurface(renderer, heart_surface) # Will be C_NULL on failure.
        SDL2.FreeSurface(heart_surface)
        jlLogo_surface = SDL2.LoadBMP("assets/jllogo.bmp")
        jlLogoIcon = SDL2.CreateTextureFromSurface(renderer, jlLogo_surface) # Will be C_NULL on failure.
        SDL2.FreeSurface(jlLogo_surface)
    end
    screenRect = SDL2.Rect(0,0, winWidth_highDPI[], winWidth_highDPI[])
    # First render the scene under the pause menu so it looks like the pause is over it.
    if (length(sceneStack) > 1) render(sceneStack[end-1], renderer, win) end
    color = kBackgroundColor
    SDL2.SetRenderDrawColor(renderer, Int64(color.r), Int64(color.g), Int64(color.b), 200) # transparent
    SDL2.RenderFillRect(renderer, Ref(screenRect))
    renderText(renderer, cam, scene.titleText, screenOffsetFromCenter(0,-149)
               ; fontSize=kPauseSceneTitleFontSize)
    renderText(renderer, cam, scene.subtitleText, screenOffsetFromCenter(0,-109); fontSize = kPauseSceneSubtitleFontSize)
    for b in values(buttons)
        render(b, cam, renderer)
    end
    renderText(renderer, cam, "Player 1 Controls", UIPixelPos(paddleAControlsX(),winHeight[]-169); fontSize = kControlsHeaderFontSize)
    renderText(renderer, cam, "Player 2 Controls", UIPixelPos(paddleBControlsX(),winHeight[]-169); fontSize = kControlsHeaderFontSize)
    renderText(renderer, cam, kCopyrightNotices[1], UIPixelPos(screenCenterX(), winHeight[] - 20);
            fontName="assets/fonts/FiraCode/ttf/FiraCode-Regular.ttf",
            fontSize=10)
    renderText(renderer, cam, kCopyrightNotices[2], UIPixelPos(screenCenterX(), winHeight[] - 8);
            fontName="assets/fonts/FiraCode/ttf/FiraCode-Regular.ttf",
            fontSize=10)

    _, heartPos, _, jlLogoPos =
      hcat_render_text(kProgrammedWithJuliaText, renderer, cam,
         0, UIPixelPos(screenCenterX(), winHeight[] - 35);
          fontName="assets/fonts/FiraCode/ttf/FiraCode-Regular.ttf",
          fontSize=16)
    render(heartIcon, heartPos, cam, renderer; size=UIPixelDims(16,16))
    render(jlLogoIcon, jlLogoPos, cam, renderer; size=UIPixelDims(16,16))

    global knight_run_anim
    knight_ss = Animations.load_bmp(renderer, "assets/knight_spritesheet.bmp")
    p, d = ScreenPixelPos(knight_pos...), ScreenPixelDims(knight_dims...)
    h = Vector2D(knight_dims[1], 0)
    v = Vector2D(0, knight_dims[2])

    # Initialize
    knight_run_anim === nothing && begin
        global knight_run_anim = Animation(
            [ Sprite(knight_ss, p + knight_run_offset*v + i*h, d) for i in 0:6],
            knight_anim_delays, loopanim_callback)
        global knight_jump_anim = Animation(
            [ Sprite(knight_ss, p + knight_jump_offset*v + i*h, d) for i in 0:6],
            knight_anim_delays, loopanim_callback)
        global knight_attack_anim = Animation(
            [ Sprite(knight_ss, p + 4*v + i*h, d) for i in 0:6],
            knight_anim_delays, loopanim_callback)
    end
    render(knight_run_anim, screenCenter() + Vector2D(-50,-200), cam, renderer, size=knight_display_scale)
    render(knight_jump_anim, screenCenter() + Vector2D(50,-200), cam, renderer, size=knight_display_scale)
    render(knight_attack_anim, screenCenter() + Vector2D(150,-200), cam, renderer, size=knight_display_scale)

    render(knight_attack_anim, screenCenter() + Vector2D(150,-200), cam, renderer, size=knight_display_scale)
    for (pos, anim) in heart_anims
        render(anim, pos, cam, renderer, size=1)
    end
end
function performUpdates!(scene::PauseScene, dt)
    update!(knight_run_anim, dt)
    update!(knight_jump_anim, dt)
    update!(knight_attack_anim, dt)
    for (pos, anim) in heart_anims
        update!(anim, dt)
    end
end

struct HeartFrame
    size::Float32
end
function render(f::HeartFrame, args...; kwargs...)
    render(heartIcon, args...; kwargs..., size=f.size)
end

heart_anims = Tuple{AbstractPos,Animation}[]

clickedButton = nothing
function handleMouseClickButton!(e, clickType)
    global clickedButton
    mx = bitcat(UInt32, e[24:-1:21])
    my = bitcat(UInt32, e[28:-1:25])
    mouse_pos = UIPixelPos(mx,my)
    mButton = e[17]
    if mButton != SDL2.BUTTON_LEFT
        return
    end
    didClickButton = false
    for b in values(buttons)
        if mouseOnButton(mouse_pos,b,cam)
            if (clickType == SDL2.MOUSEBUTTONDOWN)
                clickedButton = b
                didClickButton = true
                break
            elseif clickedButton == b && clickType == SDL2.MOUSEBUTTONUP
                clickedButton = nothing
                didClickButton = true
                return b
            end
        end
    end
    if clickedButton != nothing && clickType == SDL2.MOUSEBUTTONUP && didClickButton == false
        clickedButton = nothing
    end

    return nothing
end

function handleMouseMotion_Pause(e)
    mx = bitcat(UInt32, e[24:-1:21])
    my = bitcat(UInt32, e[28:-1:25])
    mouse_pos = UIPixelPos(mx,my)
    # TODO: lol remove this silly glitter
    pulse_sizes = 2.0*sin.(range(0.1, stop=0.9π, length=10))
    pushfirst!(heart_anims,
            (mouse_pos, Animation(HeartFrame.(pulse_sizes), fill(0.1,10), (_...)->pop!(heart_anims))))
end

function mouseOnButton(m::UIPixelPos, b::CheckboxButton, cam)
    return mouseOnButton(m, b.button, cam)
end
function mouseOnButton(m::UIPixelPos, b::AbstractButton, cam)
    if (!b.enabled) return false end
    topLeft = topLeftPos(b.pos, b.dims)
    if m.x > topLeft.x && m.x <= topLeft.x + b.dims.w &&
        m.y > topLeft.y && m.y <= topLeft.y + b.dims.h
        return true
    end
    return false
end

function load_audio_files()
    global pingSound, scoreSound, badKeySound
    pingSound = SDL2.Mix_LoadWAV( "$assets/ping.wav" );
    scoreSound = SDL2.Mix_LoadWAV( "$assets/score.wav" );
    badKeySound = SDL2.Mix_LoadWAV( "$assets/ping.wav" );
end

function game_main(ARGS)
    global renderer, win, paused,game_started, cam
    win = nothing
    try
        SDL2.init()
        ApplicationBuilderAppUtils.cd_to_bundle_resources()
        #init_prefspath()
        #load_prefs_backup()
        load_audio_files()
        music = SDL2.Mix_LoadMUS( "$assets/music.wav" );
        win,renderer = SDLGamesLib.makeWinRenderer(kGAME_NAME)
        global paused,game_started; paused[] = true; game_started[] = false;
        # Warm up
        for i in 1:3
            pollEvent!()
            SDL2.SetRenderDrawColor(renderer, 200, 200, 200, 255)
            SDL2.RenderClear(renderer)
            SDL2.RenderPresent(renderer)
            #sleep(0.01)
        end
        audioEnabled && SDL2.Mix_PlayMusic( music, Int32(-1) )
        recenterButtons!()
        resetGame();  # Initialize game stuff.
        #println("Preferences file: $(repr(prefsfile))")
        playing[] = paused[] = true
        scene = GameScene()

        runSceneGameLoop(scene, renderer, win, playing)
    catch e
        if isa(e, QuitException)
            SDLGamesLib.quitSDL(win)
        else
            rethrow()  # Every other kind of exception
        end
    end
        return 0
end
julia_main() = julia_main(String[])
Base.@ccallable function julia_main(ARGS::Vector{String})::Cint
    game_main(ARGS)
end

# julia_main()  # no julia_main if currently compiling.

end


text:
module Allocate_Arrays
    using Get_Sim_Params

    export xi, q_FS, q_diff, xi12, nu0, ke, du, vth_e
    export Te, Efield, ne, Qextra, p, u, rho, T
    export Q_DT, ni, mu_ion, xiab, L_ab, k_DT, nu_DT, U1D, F1D
    export R1D, U1D_c, U1D_p, G1D, C1D
    export dr_shell, r_shell
    export T0, N0, V0

    xi = zeros(Float64, nz)
    q_FS = zeros(Float64, nz)
    q_diff = zeros(Float64, nz)
    xi12 = zeros(Float64, nz)
    nu0 = zeros(Float64, nz)
    ke = zeros(Float64, nz)
    du = zeros(Float64, nz)
    vth_e = zeros(Float64, nz)
    Te = zeros(Float64, nz)
    Efield = zeros(Float64, nz)
    ne = zeros(Float64, nz)
    Qextra = zeros(Float64, nz)

    p = zeros(Float64, nz, nspec+1)
    u = zeros(Float64, nz, nspec+1)
    rho = zeros(Float64, nz, nspec+1)
    T = zeros(Float64, nz, nspec+1)
    Q_DT = zeros(Float64, nz, nspec+1)

    ni = zeros(Float64, nz, nspec)
    mu_ion = zeros(Float64, nz, nspec)

    xiab = zeros(Float64, nz, nspec, nspec)
    L_ab = zeros(Float64, nz, nspec, nspec)
    k_DT = zeros(Float64, nz, nspec+1, nspec+1)
    nu_DT = zeros(Float64, nz, nspec+1, nspec+1)

    U1D = zeros(Float64, nz, neqi+1)
    F1D = zeros(Float64, nz, neqi+1)
    R1D = zeros(Float64, nz, neqi+1)
    U1D_p = zeros(Float64, nz, neqi+1)
    U1D_c = zeros(Float64, nz, neqi+1)
    G1D = zeros(Float64, nz, neqi+1)

    C1D = zeros(Float64, nz, neqi)

    r_shell = zeros(Float64, nspec)
    dr_shell = zeros(Float64, nspec)

    r0 = zeros(Float64, nspec, nregions+1)
    den0 = zeros(Float64, nspec, nregions+1)
    temp0 = zeros(Float64, nspec, nregions+1)
    vel0 = zeros(Float64, nspec, nregions+1)

    T0 = zeros(Float64, nz, nspec)
    N0 = zeros(Float64, nz, nspec)
    V0 = zeros(Float64, nz, nspec)

end

max_stars_repo_name: cbellei/JUPL

max_issues_repo_name: cbellei/JUPL

max_forks_repo_name: cbellei/JUPL


text:
import Pkg; Pkg.add(Pkg.PackageSpec(url="https://github.com/JuliaComputing/JuliaAcademyData.jl"))
using JuliaAcademyData; activate("Foundations of machine learning")

# # Motivation
#
# Hello, and welcome! We're excited to be your gateway into machine learning. ML is a rapidly growing field that's buzzing with opportunity. Why? Because the tools and skills employed by ML specialists are extremely powerful and allow them to draw conclusions from large data sets quickly and with relative ease.
#
# Take the Celeste project, for example. This is a project that took 178 **tera**bytes of data on the visible sky and used it to catalogue 188 millions stars and galaxies. "Cataloguing" these stars meant identifying characteristics like their locations, colors, sizes, and morphologies. This is an amazing feat, *especially* because this entire calculation took under 15 minutes.
#
# <img src="https://raw.githubusercontent.com/JuliaComputing/JuliaAcademyData.jl/master/courses/Foundations%20of%20machine%20learning/data/Celeste.png" alt="Drawing" style="width: 1000px;"/>
#
# How are Celeste's calculations so fast? To achieve performance on this scale, the Celeste team uses the Julia programming language to write their software and supercomputers from Lawrence Berkeley National Lab's NERSC as their hardware. In this course, we unfortunately won't be able to give you access to a top 10 supercomputer, but we will teach you how to use Julia!
#
# We're confident that this course will put you on your way to understanding many of the important concepts and "buzz words" in ML. To get you started, we'll teach you how to teach a machine to tell the difference between images of apples and bananas, i.e to **classify** images as being one or the other type of fruit.
#
# Like Project Celeste, we'll use the [Julia programming language](https://julialang.org/) to do this. In particular, we'll be working in [Jupyter notebooks](http://jupyter.org/) like this one! (Perhaps you already know that the "ju" in Jupyter comes from Julia.)

#-

# ## What do the images we want to classify look like?
#
# We can use the `Images.jl` package in Julia to load sample images from this dataset. Most of the data we will use live in the `data` folder in this repository.

using Images  # To execute hit <shift> + enter

#-

apple = load(datapath("data/10_100.jpg"))

#-

banana = load(datapath("data/104_100.jpg"))

# The dataset consists of many images of different fruits, viewed from different positions.
# These images are [available on GitHub here](https://github.com/Horea94/Fruit-Images-Dataset).

#-

# ## What is the goal?

#-

# The ultimate goal is to feed one of these images to the computer and for it to identify whether the image represents an apple or a banana!  To do so, we will **train** the computer to learn **for itself** how to
# distinguish the two images.
#
# The following notebooks will walk you step by step through the underlying math and machine learning concepts you need to know in order to accomplish this classification.
#
# They alternate between two different types of notebooks: those labelled **ML** (Machine Learning), which are designed to give a high-level overview of the concepts we need for machine learning, but which gloss over some of the technical details; and those labelled **Tools**, which dive into the details of coding in Julia that will be key to actually implement the machine learning algorithms ourselves.
#
# The notebooks contain many **Exercises**. By doing these exercises in Julia, you will learn the basics of machine learning!

max_stars_repo_path: Courses/Foundations of machine learning/00.Motivation-Classifying-fruit.jl

max_stars_repo_name: fercarozzi/JuliaAcademyMaterials

max_issues_repo_name: fercarozzi/JuliaAcademyMaterials

max_forks_repo_name: fercarozzi/JuliaAcademyMaterials


text:
# Energy

function NbodyEnergy(u,Gm)
"""
     Nbody problem Hamiltonian (Cartesian Coordinates)
"""

    dim=2
    nbody=length(Gm)

 @inbounds begin
    x = view(u,1:7)   # x
    y = view(u,8:14)  # y
    v = view(u,15:21) # x′
    w = view(u,22:28) # y′

    H=zero(eltype(u))
    P=zero(eltype(u))

    for i in 1:nbody
        H+=Gm[i]*(v[i]*v[i]+w[i]*w[i])
        for j in i+1:nbody
            r = ((x[i]-x[j])^2+(y[i]-y[j])^2)^(1/2)
            P+=(Gm[i]/r)*Gm[j]
        end
    end

    return(H/2-P)
    end

end

# OdeProblem

function f(du,u,p,t)
  @inbounds begin
  x = view(u,1:7)   # x
  y = view(u,8:14)  # y
  v = view(u,15:21) # x′
  w = view(u,22:28) # y′
  du[1:7] .= v
  du[8:14].= w
  for i in 15:28
    du[i] = zero(u[1])
  end
  for i=1:7,j=1:7
    if i != j
      r = ((x[i]-x[j])^2 + (y[i] - y[j])^2)^(3/2)
      du[14+i] += j*(x[j] - x[i])/r
      du[21+i] += j*(y[j] - y[i])/r
    end
  end
  end
end

# DynamicalOdeProblem

function dotv(dv,q,v,par,t)
@inbounds begin
  x = view(q,1:7)   # x
  y = view(q,8:14)  # y
  vx = view(v,1:7)   # x′
  vy = view(v,8:14)  # y′
  for i in 1:14
    dv[i] = zero(x[1])
  end
  for i=1:7,j=1:7
    if i != j
      r = ((x[i]-x[j])^2 + (y[i] - y[j])^2)^(3/2)
      dv[i] += j*(x[j] - x[i])/r
      dv[7+i] += j*(y[j] - y[i])/r
    end
  end
  end
end

function dotq(dq,q,v,par,t)
@inbounds begin
  x = view(q,1:7)   # x
  y = view(q,8:14)  # y
  vx = view(v,1:7)   # x′
  vy = view(v,8:14)  # y′
  dq[1:7] .= vx
  dq[8:14].= vy
  end
end

#
#  Second Order Problem
#

function f2nd!(ddu,du,u,p,t)
  @inbounds begin
  x = view(u,1:7)   # x
  y = view(u,8:14)  # y
  vx = view(du,1:7) # x′
  vy = view(du,8:14) # y′

  for i in 1:14
    ddu[i] = zero(x[1])
  end

  for i=1:7,j=1:7
    if i != j
      r = ((x[i]-x[j])^2 + (y[i] - y[j])^2)^(3/2)
      ddu[i] += j*(x[j] - x[i])/r
      ddu[7+i] += j*(y[j] - y[i])/r
    end
  end
  end
end