text:
import ..Properties: @property

"""
    rate_of_impulse(plate, motion, elements::Source, velocities::Source)

Compute the rate of change of impulse of a vortex element and its
image relative to a plate.

Note that this is not just the rate of impulse of the vortex element
itself, but also includes the rate of impulse of the bound vortex
sheet generated in response to the vortex element.
"""
@property begin
    signature = rate_of_impulse(plate, motion, elements::Source, velocities::Source)
    reduce = (+)
    stype = ComplexF64
end

function rate_of_impulse(plate, motion, element, velocity, ::Type{Singleton})
    @get plate (c, α, L)
    @get motion (ċ, α̇)

    Γ = circulation(element)
    z = 2exp(-im*α)*(position(element) - c)/L
    ż = 2exp(-im*α)*(velocity - ċ)/L - im*α̇*z
    p̂ = imag(z) - im*real(√(z - 1)*√(z + 1))

    dp̂dt = -im*(ż + real((z/(√(z - 1)*√(z + 1)) - 1)*ż))

    0.5L*Γ*exp(im*α)*(dp̂dt + im*α̇*p̂)
end

"""
    vortex_impulse(plate, elements::Source)

Compute the impulse of a vortex element and its image relative to a plate.

Note that this is not just the impulse of the vortex element
itself, but also includes the impulse of the bound vortex
sheet generated in response to the vortex element.
"""
@property begin
    signature = vortex_impulse(plate, elements::Source)
    reduce = (+)
    stype = ComplexF64
end

function vortex_impulse(plate, element, ::Type{Singleton})
    @get plate (c, α, L)

    Γ = circulation(element)
    z = 2exp(-im*α)*(position(element) - c)/L
    p̂ = imag(z) - im*real(√(z - 1)*√(z + 1))

    0.5L*Γ*exp(im*α)*p̂
end

"""
    rate_of_angular_impulse(plate, motion, elements::Source, velocities::Source)

Compute the rate of change of angular impulse of a vortex element (about the centroid)
and its image relative to a plate.

Note that this is not just the rate of angular impulse of the vortex element
itself, but also includes the rate of angular impulse of the bound vortex
sheet generated in response to the vortex element.
"""
@property begin
    signature = rate_of_angular_impulse(plate, motion, elements::Source, velocities::Source)
    reduce = (+)
    stype = ComplexF64
end

function rate_of_angular_impulse(plate, motion, element, velocity, ::Type{Singleton})
    @get plate (c, α, L)
    @get motion (ċ, α̇)

    Γ = circulation(element)
    z = 2exp(-im*α)*(position(element) - c)/L
    ż = 2exp(-im*α)*(velocity - ċ)/L - im*α̇*z
    #Π = -0.5abs(z)^2 -0.5real(z*(√(z - 1)*√(z + 1)-z))

    dΠdt = -real(conj(z)*ż + ((z^2-1/2)/(√(z - 1)*√(z + 1)) - z)*ż)

    0.25L^2*Γ*dΠdt
end

"""
    force(plate, motion, elements, velocities, newelements = ())

Compute the force on `plate`, given its motion and the state of the ambient vorticity.

# Arguments

- `plate`: the plate
- `motion`: a structure that contains the velocity, acceleration, and angular velocity
  of the plate.
- `elements`: vortex elements representing the ambient vorticity
- `velocities`: the velocities of the vortex elements
- `newelements`: an optional argument listing vortex elements that are just added to the
  flow field (it can be an element that is contained in `elements`)
- `Δt`: this is only required if `newelements` is not empty, we assume that the new
  vortex elements are created over the span of `Δt`

# Returns

- `F`: the force exerted on the plate in complex coordinates
"""
function force(plate, motion, elements, velocities, newelements = (), Δt = 0.0)
    @get plate (c, α, L)
    @get motion (ċ, α̇, c̈)

    Ṗa = rate_of_impulse(plate, motion, elements, velocities)

    !isempty(newelements) && Δt == 0 && error("Δt should not be zero")

    for v in newelements
        Γ̇ = circulation(v)/Δt
        z = 2exp(-im*α)*(position(v) - c)/L
        p̂ = imag(z) - im*real(√(z - 1)*√(z + 1))

        Ṗa += exp(im*α)*0.5L*Γ̇*p̂
    end

    Ṗb = -im*π*exp(im*α)*(L/2)^2*( α̇*conj(exp(-im*α)*ċ)
                         - imag(exp(-im*α)*c̈)
                         )
    return -(Ṗa + Ṗb)
end

"""
    moment(plate, motion, elements, velocities, newelements = ())

Compute the moment on `plate` about its centroid, given its motion and the state of the ambient vorticity.

# Arguments

- `plate`: the plate
- `motion`: a structure that contains the velocity, acceleration, and angular velocity
  of the plate.
- `elements`: vortex elements representing the ambient vorticity
- `velocities`: the velocities of the vortex elements
- `newelements`: an optional argument listing vortex elements that are just added to the
  flow field (it can be an element that is contained in `elements`)
- `Δt`: this is only required if `newelements` is not empty, we assume that the new
  vortex elements are created over the span of `Δt`

# Returns

- `M`: the moment exerted on the plate (about the centroid)
"""
function moment(plate, motion, elements, velocities, newelements = (), Δt = 0.0)
    @get plate (c, α, L)
    @get motion (ċ, α̇, c̈, α̈)

    c̃̇ = ċ*exp(-im*α)

    Π̇a = rate_of_angular_impulse(plate, motion, elements, velocities)
    Π̇a += imag(conj(ċ)*vortex_impulse(plate,elements))

    !isempty(newelements) && Δt == 0 && error("Δt should not be zero")

    for v in newelements
        Γ̇ = circulation(v)/Δt
        z = 2exp(-im*α)*(position(v) - c)/L
        Π = -0.5abs(z)^2 -0.5real(z*(√(z - 1)*√(z + 1)-z))

        Π̇a += 0.25L^2*Γ̇*Π
    end

    Π̇b = 0.125π*(L/2)^4*α̈ + π*(L/2)^2*real(c̃̇)*imag(c̃̇)
    return -real.(Π̇a + Π̇b)
end


text:
# load ImpvolEquilibrium first so that methods are accessible
@everywhere include("../../../equilibrium.jl")
@everywhere using ImpvolEquilibrium

@everywhere include("../init_parameters.jl")

# parameters that govern counterfactual
@everywhere include("change_parameters.jl")

display([parameters[:S_nt][1,:,1,23] parameters[:w_njt][1,:,1,23]])

@time results = ImpvolEquilibrium.period_wrapper(parameters, 23)

ext: jl


text:
# sod shock tube problem
# build mesh
include("../src/DiscontinuousGalerkin.jl")
using DiscontinuousGalerkin
const CFL = 0.5
const Tend = 0.2
const γ=1.4 #gas constant
const xdiafragm = 0.0

function f(::Type{Val{:jac}},u::Vector)
  ρ = u[1]; v = u[2]/u[1]; ϵ=u[3]
  p = (ϵ-0.5*ρ*v^2)*(γ-1)
  F =[0.0 1.0 0.0;-v^2*(1+γ)/2 v*(3-γ) (γ-1);v^3*(γ-1)+γ*ϵ*v/ρ 3/2*v^2*(1-γ)+γ*ϵ/ρ γ*v]
  F
end

function f(u::Vector)
  ρ = u[1]; v = u[2]/u[1]; ϵ=u[3]
  p = (ϵ-0.5*ρ*v^2)*(γ-1)
  [u[2];u[2]^2/u[1]+p;(ϵ+p)*v]
end

#initial condition
function f0(x::Real)
  ufis_l = [1.0, 0.0,	1.0]
  ufis_r = [0.125 0.0 0.1]
  if x <= xdiafragm
    ρ,u,p = ufis_l
  else
    ρ,u,p = ufis_r
  end
  return [ρ, ρ*u, 1.0/(γ - 1.0)*p + 0.5*ρ*u*u]
end

positive(x) = max(0,x)
#define max wave speed (generic euler system)
function max_w_speed(u)
  ρ = u[:,1];v = u[:,2]./ρ;E = u[:,3]
  p = zeros(ρ); wave_speed = zeros(ρ)
  @. p = (γ-1)*(E-0.5*ρ*v*v)
  @. wave_speed = abs(v) + sqrt(γ*positive(p/ρ))
  return maximum(wave_speed)
end

function Nflux(ul::Vector, ur::Vector)
  ρl = ul[1]; vl = ul[2]/ul[1]; ϵl=ul[3]
  pl = (ϵl-0.5*ρl*vl^2)*(γ-1)
  ρr = ur[1]; vr = ur[2]/ur[1]; ϵr=ur[3]
  pr = (ϵr-0.5*ρr*vr^2)*(γ-1)
  zl = sqrt(ρl/pl)*[1;vl;pl]
  zr = sqrt(ρr/pr)*[1;vr;pr]
  zm = 0.5*(zl+zr)
  zln = (zr-zl)./(log(zr)-log(zl))
  F = zeros(ul)
  F[1] = zm[2]*zln[3]
  F[2] = zm[3]/zm[1]+zm[2]/zm[1]*F[1]
  F[2] = 0.5*zm[2]/zm[1]*((γ+1)/(γ-1)*zln[3]/zln[1]+F[2])
  F
end

function ve(u::Vector)
  ρ = u[1]; v = u[2]/u[1]; ϵ=u[3]
  p = (ϵ-0.5*ρ*v^2)*(γ-1)
  s = log(p)-γ*log(ρ)
  return [(γ-s)/(γ-1)-ρ*v^2/(2*p);ρ*v/p;-ρ/p]
end

function get_problem(N)
    mesh = Uniform1DFVMesh(N,-1.0,1.0,:ZERO_FLUX, :ZERO_FLUX)
    ConservationLawsProblem(f0,f,CFL,Tend,mesh)
end
prob = get_problem(20)

basis=legendre_basis(3)
limiter! = DGLimiter(prob, basis, Linear_MUSCL_Limiter())
@time sol = solve(prob, DiscontinuousGalerkinScheme(basis, rusanov_euler_num_flux); TimeIntegrator = SSPRK22(limiter!))

#Plot
using Plots
plot(sol)

max_stars_repo_name: Paulms/DiscontinuousGalerkin

max_issues_repo_name: Paulms/DiscontinuousGalerkin

max_forks_repo_name: Paulms/DiscontinuousGalerkin


text: include("optimizers.jl")


text:
"""
    contour(x, y, z)
Creates a contour plot of the plane spanning x::Vector, y::Vector, z::Matrix
"""
@recipe(Contour) do scene
    default = default_theme(scene)
    pop!(default, :color)
    Theme(;
        default...,
        color = theme(scene, :colormap),
        colorrange = AbstractPlotting.automatic,
        levels = 5,
        linewidth = 1.0,
        fillrange = false,
    )
end

"""
    contour3d(x, y, z)
Creates a 3D contour plot of the plane spanning x::Vector, y::Vector, z::Matrix,
with z-elevation for each level
"""
@recipe(Contour3d) do scene
    default_theme(scene, Contour)
end

function contourlines(::Type{<: Contour}, contours, cols)
    result = Point2f0[]
    colors = RGBA{Float32}[]
    for (color, c) in zip(cols, Contours.levels(contours))
        for elem in Contours.lines(c)
            append!(result, elem.vertices)
            push!(result, Point2f0(NaN32))
            append!(colors, fill(color, length(elem.vertices) + 1))
        end
    end
    result, colors
end

function contourlines(::Type{<: Contour3d}, contours, cols)
    result = Point3f0[]
    colors = RGBA{Float32}[]
    for (color, c) in zip(cols, Contours.levels(contours))
        for elem in Contours.lines(c)
            for p in elem.vertices
                push!(result, Point3f0(p[1], p[2], c.level))
            end
            push!(result, Point3f0(NaN32))
            append!(colors, fill(color, length(elem.vertices) + 1))
        end
    end
    result, colors
end

to_levels(x::AbstractVector{<: Number}, cnorm) = x
function to_levels(x::Integer, cnorm)
    range(cnorm[1], stop = cnorm[2], length = x)
end
import AbstractPlotting: convert_arguments
convert_arguments(::Type{<: Contour3d}, args...) = convert_arguments(Heatmap, args...)
convert_arguments(::Type{<: Contour}, args...) = convert_arguments(Volume, args...)
convert_arguments(::Type{<: Contour}, data::AbstractMatrix) = convert_arguments(Heatmap, data)

function plot!(plot::Contour{<: Tuple{X, Y, Z, Vol}}) where {X, Y, Z, Vol}
    x, y, z, volume = plot[1:4]
    @extract plot (color, levels, linewidth, alpha)
    valuerange = lift(x-> Vec2f0(extrema(x)), volume)
    cliprange = replace_automatic!(plot, :colorrange) do
        valuerange
    end
    cmap = lift(color, levels, linewidth, alpha, cliprange, valuerange) do _cmap, l, lw, alpha, cliprange, vrange
        levels = to_levels(l, vrange)
        nlevels = length(levels)
        N = nlevels * 50
        iso_eps = nlevels * ((vrange[2] - vrange[1]) / N) # TODO calculate this
        cmap = to_colormap(_cmap)
        v_interval = cliprange[1] .. cliprange[2]
        # resample colormap and make the empty area between iso surfaces transparent
        map(1:N) do i
            i01 = (i-1) / (N - 1)
            c = AbstractPlotting.interpolated_getindex(cmap, i01)
            isoval = vrange[1] + (i01 * (vrange[2] - vrange[1]))
            line = reduce(levels, init = false) do v0, level
                (isoval in v_interval) || return false
                v0 || (abs(level - isoval) <= iso_eps)
            end
            RGBAf0(Colors.color(c), line ? alpha : 0.0)
        end
    end
    volume!(plot, x, y, z, volume, colormap = cmap, colorrange = cliprange, algorithm = 7)
end

function plot!(plot::T) where T <: Union{Contour, Contour3d}
    x, y, z = plot[1:3]
    if to_value(plot[:fillrange])
        plot[:interpolate] = true
        # TODO normalize linewidth for heatmap
        plot[:linewidth] = map(x-> x ./ 10f0, plot[:linewidth])
        heatmap!(plot, Theme(plot), x, y, z)
    else
        result = lift(x, y, z, plot[:levels]) do x, y, z, levels
            t = eltype(z)
            levels = round(Int, levels)
            contours = Contours.contours(to_vector(x, size(z, 2), t), to_vector(y, size(z, 1), t), z, levels)
            cols = AbstractPlotting.resampled_colors(plot, levels)
            contourlines(T, contours, cols)
        end
        lines!(plot, lift(first, result); color = lift(last, result), linewidth = plot[:linewidth])
    end
    plot
end

function AbstractPlotting.data_limits(x::Contour{<: Tuple{X, Y, Z}}) where {X, Y, Z}
    AbstractPlotting.xyz_boundingbox(to_value.((x[1], x[2]))...)
end

@recipe(VolumeSlices, x, y, z, volume) do scene
    Theme(
        colormap = theme(scene, :colormap),
        colorrange = nothing,
        alpha = 0.1,
        contour = Theme(),
        heatmap = Theme(),
    )
end

convert_arguments(::Type{<: VolumeSlices}, x, y, z, volume) = convert_arguments(Contour, x, y, z, volume)
function plot!(vs::VolumeSlices)
    @extract vs (x, y, z, volume)
    replace_automatic!(vs, :colorrange) do
        map(extrema, volume)
    end
    keys = (:colormap, :alpha, :colorrange)
    contour!(vs, vs[:contour], x, y, z, volume)
    planes = (:xy, :xz, :yz)
    hattributes = vs[:heatmap]
    sliders = map(zip(planes, (x, y, z))) do plane_r
        plane, r = plane_r
        idx = node(plane, Node(1))
        vs[plane] = idx
        hmap = heatmap!(vs, hattributes, x, y, zeros(length(x[]), length(y[]))).plots[end]
        on(idx) do i
            transform!(hmap, (plane, r[][i]))
            indices = ntuple(Val(3)) do j
                planes[j] == plane ? i : (:)
            end
            hmap[3][] = view(volume[], indices...)
        end
        idx
    end
    plot!(scene, vs, rest)
end


text:
# ----------------------------------------------------------------------------------- #
# Copyright (c) 2019 Varnerlab
# Robert Frederick School of Chemical and Biomolecular Engineering
# Cornell University, Ithaca NY 14850

# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
# ----------------------------------------------------------------------------------- #

# ----------------------------------------------------------------------------------- #
# SolveAdjBalances: Solves adjoint model equations from TSTART to TSTOP given
# parameters in data_dictionary.
#
# Type: GRN-JULIA
# Version: 1.0
#
# Input arguments:
# TSTART  - Time start
# TSTOP  - Time stop
# Ts - Time step
# parameter_index - index of parameter that we want to look at
# data_dictionary  - Data dictionary instance (holds model parameters)
#
# Return arguments:
# TSIM - Simulation time vector
# X - Simulation state array (NTIME x NSPECIES)
# ----------------------------------------------------------------------------------- #
function SolveAdjBalances(TSTART,TSTOP,Ts,parameter_index,data_dictionary)

  # Get required stuff from DataFile struct -
  time_span = (TSTART,TSTOP)
  initial_condition_array = data_dictionary["initial_condition_array"];

  # which parameter are we looking at?
  data_dictionary["parameter_index"] = parameter_index

  # build problem object -
  problem_object = ODEProblem(AdjBalances, initial_condition_array, time_span, data_dictionary)

  # solve -
  solution = solve(problem_object, alg_hints=[:auto], reltol=1e-8,abstol=1e-8)

  # pull solution apart -
  T = solution.t

  # initialize the state array -
  number_of_times_steps = length(T)
  number_of_states = length(initial_condition_array)
  X = zeros(number_of_times_steps,number_of_states)
  for step_index=1:number_of_times_steps

      # grab the solution 0
      soln_array = solution.u[step_index]
      for state_index = 1:number_of_states
          X[step_index, state_index] = soln_array[state_index]
      end
  end

  # return -
  return (T,X)
end

# ----------------------------------------------------------------------------------- #
# SolveBalances: Solves model equations from TSTART to TSTOP given parameters in data_dictionary.
# Type: GRN-JULIA
# Version: 1.0
#
# Input arguments:
# TSTART  - Time start
# TSTOP  - Time stop
# Ts - Time step
# data_dictionary  - Data dictionary instance (holds model parameters)
#
# Return arguments:
# TSIM - Simulation time vector
# X - Simulation state array (NTIME x NSPECIES)
# ----------------------------------------------------------------------------------- #
function SolveBalances(TSTART,TSTOP,Ts,data_dictionary)

    # Get required stuff from DataFile struct -
    time_span = (TSTART,TSTOP)
    initial_condition_array = data_dictionary["initial_condition_array"];

    # build problem object -
    problem_object = ODEProblem(Balances, initial_condition_array, time_span, data_dictionary)

    # solve -
    solution = solve(problem_object, AutoTsit5(Rosenbrock23(autodiff=false)), reltol=1e-8,abstol=1e-8,saveat=Ts)

    # pull solution apart -
    T = solution.t

    # initialize the state array -
    number_of_times_steps = length(T)
    number_of_states = length(initial_condition_array)
    X = zeros(number_of_times_steps,number_of_states)
    for step_index=1:number_of_times_steps

        # grab the solution 0
        soln_array = solution.u[step_index]
        for state_index = 1:number_of_states
            X[step_index, state_index] = soln_array[state_index]
        end
    end

    # return -
    return (T,X)
end


text:
x = LinRange(0,2,100)
plot(x, [x.^α for α in 0:0.2:10], c = :plasma, colorbar = true,
    linez = collect(0:0.2:10)', legend = false, ylim = (-0.1,10),
    xlab = L"x", size = (600,300))
annotate!(0.5, 7.5, text(L"f(x) = x^\alpha", :purple))
annotate!(2.15, 10.2, text(L"\alpha", :purple))
# because colorbar_title is currently not implemented for GR
savefig("figpow.pdf")

max_stars_repo_name: lazarusA/helpfulJulia

max_issues_repo_name: lazarusA/helpfulJulia

max_forks_repo_name: lazarusA/helpfulJulia


text:
lines = readlines("input.txt")
x,y,aim = 0,0,0

for line = lines
    cmd, arg_s = split(line)
    arg_i = parse(Int, arg_s)
    if cmd == "forward"
        global x += arg_i
        global y += aim * arg_i
    elseif cmd == "down"
        global aim += arg_i
    elseif cmd == "up"
        global aim -= arg_i
    end
end

println(x*y)


text:
export iauEect00
"""
**  Equation of the equinoxes complementary terms, consistent with
**  IAU 2000 resolutions.
**
**  This function is part of the International Astronomical Union's
**  SOFA (Standards Of Fundamental Astronomy) software collection.
**
**  Status:  canonical model.
**
**  Given:
**     date1,date2  double   TT as a 2-part Julian Date (Note 1)
**
**  Returned (function value):
**                  double   complementary terms (Note 2)
**
**  Notes:
**
**  1) The TT date date1+date2 is a Julian Date, apportioned in any
**     convenient way between the two arguments.  For example,
**     JD(TT)=2450123.7 could be expressed in any of these ways,
**     among others:
**
**            date1          date2
**
**         2450123.7           0.0       (JD method)
**         2451545.0       -1421.3       (J2000 method)
**         2400000.5       50123.2       (MJD method)
**         2450123.5           0.2       (date & time method)
**
**     The JD method is the most natural and convenient to use in
**     cases where the loss of several decimal digits of resolution
**     is acceptable.  The J2000 method is best matched to the way
**     the argument is handled internally and will deliver the
**     optimum resolution.  The MJD method and the date & time methods
**     are both good compromises between resolution and convenience.
**
**  2) The "complementary terms" are part of the equation of the
**     equinoxes (EE), classically the difference between apparent and
**     mean Sidereal Time:
**
**        GAST = GMST + EE
**
**     with:
**
**        EE = dpsi * cos(eps)
**
**     where dpsi is the nutation in longitude and eps is the obliquity
**     of date.  However, if the rotation of the Earth were constant in
**     an inertial frame the classical formulation would lead to
**     apparent irregularities in the UT1 timescale traceable to side-
**     effects of precession-nutation.  In order to eliminate these
**     effects from UT1, "complementary terms" were introduced in 1994
**     (IAU, 1994) and took effect from 1997 (Capitaine and Gontier,
**     1993):
**
**        GAST = GMST + CT + EE
**
**     By convention, the complementary terms are included as part of
**     the equation of the equinoxes rather than as part of the mean
**     Sidereal Time.  This slightly compromises the "geometrical"
**     interpretation of mean sidereal time but is otherwise
**     inconsequential.
**
**     The present function computes CT in the above expression,
**     compatible with IAU 2000 resolutions (Capitaine et al., 2002, and
**     IERS Conventions 2003).
**
**  Called:
**     iauFal03     mean anomaly of the Moon
**     iauFalp03    mean anomaly of the Sun
**     iauFaf03     mean argument of the latitude of the Moon
**     iauFad03     mean elongation of the Moon from the Sun
**     iauFaom03    mean longitude of the Moon's ascending node
**     iauFave03    mean longitude of Venus
**     iauFae03     mean longitude of Earth
**     iauFapa03    general accumulated precession in longitude
**
**  References:
**
**     Capitaine, N. & Gontier, A.-M., Astron.Astrophys., 275,
**     645-650 (1993)
**
**     Capitaine, N., Wallace, P.T. and McCarthy, D.D., "Expressions to
**     implement the IAU 2000 definition of UT1", Astron.Astrophys., 406,
**     1135-1149 (2003)
**
**     IAU Resolution C7, Recommendation 3 (1994)
**
**     McCarthy, D. D., Petit, G. (eds.), IERS Conventions (2003),
**     IERS Technical Note No. 32, BKG (2004)
**
**  This revision:  2017 October 12
**
**  SOFA release 2018-01-30
**
**  Copyright (C) 2018 IAU SOFA Board.  See notes at end.
"""

# double iauEect00(double date1, double date2)

function iauEect00(date1::Real, date2::Real)
   return ccall((:iauEect00, libsofa_c), Cdouble,
         (Cdouble, Cdouble),
         convert(Float64, date1), convert(Float64, date2))
end


text:
SUITE["ZonedDateTime"] = BenchmarkGroup()
SUITE["ZonedDateTime"]["local"] = BenchmarkGroup()
SUITE["ZonedDateTime"]["utc"] = BenchmarkGroup()

SUITE["ZonedDateTime"]["local"]["standard"] = begin
    @benchmarkable ZonedDateTime($(DateTime(2015,1,1)), $(tz"America/Winnipeg"))
end
SUITE["ZonedDateTime"]["local"]["ambiguous"] = begin
    @benchmarkable ZonedDateTime($(DateTime(2015,11,1,1)), $(tz"America/Winnipeg"), 2)
end
SUITE["ZonedDateTime"]["utc"] = begin
    @benchmarkable ZonedDateTime($(DateTime(2015,1,1)), $(tz"America/Winnipeg"), from_utc=true)
end

SUITE["ZonedDateTime"]["range"] = BenchmarkGroup()

SUITE["ZonedDateTime"]["range"]["VariableTimeZone/TimePeriod"] = begin
    @benchmarkable collect($(gen_range(Hour(100), tz"America/Winnipeg")))
end
SUITE["ZonedDateTime"]["range"]["VariableTimeZone/DatePeriod"] = begin
    @benchmarkable collect($(gen_range(Day(100), tz"America/Winnipeg")))
end
SUITE["ZonedDateTime"]["range"]["FixedTimeZone/TimePeriod"] = begin
    @benchmarkable collect($(gen_range(Hour(100), tz"UTC")))
end
SUITE["ZonedDateTime"]["range"]["FixedTimeZone/DatePeriod"] = begin
    @benchmarkable collect($(gen_range(Day(100), tz"UTC")))
end

# https://github.com/JuliaTime/TimeZones.jl/pull/287#issuecomment-687358202
SUITE["ZonedDateTime"]["fill"] = begin
    f(zdt) = fill(zdt, 100)[end]
    @benchmarkable f($(ZonedDateTime(2000, 1, 2, tz"America/Winnipeg")))
end


text:
abstract type FunctionalResponse end

struct HollingTypeI{AT} <: FunctionalResponse
    A::AT
    HollingTypeI(a::A) where {A} = new{A}(a)
end
(fr::HollingTypeI)(c::T, r::T) where {T<:Biomass} = @fastmath fr.A * r

# aliases
LinearFunctionalResponse(a) = HollingTypeI(a)
LotkaVolterra(a) = HollingTypeI(a)

struct HollingTypeII{AT,HT} <: FunctionalResponse
    a::AT  ## attack rate
    h::HT ## handling time
    HollingTypeII(a::A, h::H) where {A,H} = new{A,H}(a, h)
end
(afr::HollingTypeII)(c, r) = @fastmath (afr.a * r) / (afr.a * afr.h * r + 1)
# aliases
MichaelisMenten(a, h) = HollingTypeII(a, h)

struct HollingTypeIII{AT,HT,BT} <: FunctionalResponse
    a::AT  ## attack rate
    h::HT ## handling time
    β::BT ## scaling
    HollingTypeIII(a::A, h::H, β::B) where {A,H,B} = new{A,H,B}(a, h, β)
end
(afr::HollingTypeIII)(c, r) = @fastmath (afr.a * r) / ((afr.a * afr.h * r)^β + 1)

struct CrowleyMartin{WT,UT,VT} <: FunctionalResponse
    w::WT
    u::UT
    v::VT
    CrowleyMartin(w::W, u::U, v::V) where {W,U,V} = new{W,U,V}(w, u, v)
end
(cmfr::CrowleyMartin)(c, r) =
    @fastmath (cmfr.w * c * r) / (1 + c * cmfr.u + r * cmfr.v + c * r * cmfr.u * cmfr.v)

struct Eating{R,W,FR,D} <: CellRule{R,W}
    functionalresponse::FR
    dt::D
end

Eating{R,W}(; functionalresponse::F = LotkaVolterra(1.5), dt::D = 0.1) where {R,W,F,D} =
    Eating{R,W}(functionalresponse, dt)

function DynamicGrids.applyrule(data, rule::Eating, (C, R), index)
    C > zero(C) || return zero(C), R
    R > zero(R) || return C, zero(R)

    fr = rule.functionalresponse(C, R)
    C += C * fr * rule.dt
    R -= C * fr * rule.dt

    # TODO
    # in the case this causes R to go extinct,
    # this should only grow C as much as the remaining value of R

    C > zero(C) || return zero(C), R
    R > zero(R) || return C, zero(R)
    return C, R
end

"""
    Shortcut to make many C->R layers. Instead of having all of the eating between pairs
    of species in a single rule, builds a ruleset where each rule is a single consumer-resource interaction.
"""
function FoodWebEating(
    consumernames::Vector{Symbol},
    resourcenames::Vector{Symbol},
    fr::FunctionalResponse,
    metaweb::Matrix;
    dt = 0.1,
)
    nspecies = size(metaweb)[1]

    allrules = Ruleset()
    for r = 1:length(resourcenames), c = 1:length(consumernames)
        if metaweb[r, c] == 1
            Csym = consumernames[c]
            Rsym = resourcenames[r]
            thisrule = Eating{Tuple{Csym,Rsym}}(functionalresponse = fr, dt = dt)
            allrules += thisrule
        end
    end

    return allrules
end


text:
#----------------------------------------
# OpenGL    GLSL      GLSL
# version   version   string
#----------------------------------------
#  2.0       110       "#version 110"
#  2.1       120
#  3.0       130
#  3.1       140
#  3.2       150       "#version 150"
#  3.3       330
#  4.0       400
#  4.1       410       "#version 410 core"
#  4.2       420
#  4.3       430
#  ES 2.0    100       "#version 100"
#  ES 3.0    300       "#version 300 es"
#----------------------------------------

const IMGUI_BACKEND_RENDERER_NAME = "imgui_impl_opengl3"

function init(ctx::Context)
    io::Ptr{ImGuiIO} = igGetIO()
    io.BackendRendererName = pointer(IMGUI_BACKEND_RENDERER_NAME)
    io.BackendFlags = unsafe_load(io.BackendFlags) | ImGuiBackendFlags_RendererHasVtxOffset  # version ≥ 320
    io.BackendFlags = unsafe_load(io.BackendFlags) | ImGuiBackendFlags_RendererHasViewports

    if unsafe_load(io.ConfigFlags) & ImGuiConfigFlags_ViewportsEnable == ImGuiConfigFlags_ViewportsEnable
        ImGui_ImplOpenGL3_InitPlatformInterface()
    end

    return true
end

function shutdown(ctx::Context)
    ImGui_ImplOpenGL3_ShutdownPlatformInterface()
    ImGui_ImplOpenGL3_DestroyDeviceObjects(ctx)
    return true
end

function new_frame(ctx::Context)
    if ctx.FontTexture == 0
        ImGui_ImplOpenGL3_CreateDeviceObjects(ctx)
    end
    return true
end

render(ctx::Context) = ImGui_ImplOpenGL3_RenderDrawData(ctx, igGetDrawData())


text:
#=
    Sorting networks that process 17,..25 values are given.

    These sorting networks should minimize conditional swaps.
    There may exist one or more comparable alternative solutions;
      those may perform marginally better for some kinds of hardware.

    Functions are written with groups of internally paralleli1zable
    statements given together and sequential steps are separated.

    `swapsort(x1::T, .., xn::T)::NTuple{n,T}`
    `swapsort(tup::NTuple{n,T})::NTuple{n,T}`

    networks were selected using software by John Gamble
        http://pages.ripco.net/~jgamble/nw.html
        http://search.cpan.org/dist/Algorithm-Networksort/
=#

const MORE_ARGS_MIN = 17
const MORE_ARGS_MAX = 25

#=
   sort NTuples of 17..25 values
=#

for N in collect(MORE_ARGS_MIN:MORE_ARGS_MAX)
    @eval swapsort(x::NTuple{$N, T}) where T = swapsort(x...)
end

#=
    sorting networks for 17..25 values
    using known compact realizations
=#

#    sort 17 values with 74 minmaxs in 12 parallel stages

function swapsort(a::T, b::T, c::T, d::T, e::T,
                f::T, g::T, h::T, i::T, j::T,
                k::T, l::T, m::T, n::T, o::T,
                p::T, q::T) where {T}

    a, q = minmax(a, q)
    b, j = minmax(b, j)
    c, k = minmax(c, k)
    d, l = minmax(d, l)
    e, m = minmax(e, m)
    f, n = minmax(f, n)
    g, o = minmax(g, o)
    h, p = minmax(h, p)

    a, i = minmax(a, i)
    b, f = minmax(b, f)
    c, g = minmax(c, g)
    d, h = minmax(d, h)
    j, n = minmax(j, n)
    k, o = minmax(k, o)
    l, p = minmax(l, p)

    i, q = minmax(i, q)
    a, e = minmax(a, e)
    f, j = minmax(f, j)
    g, k = minmax(g, k)
    h, l = minmax(h, l)
    b, d = minmax(b, d)
    n, p = minmax(n, p)

    i, m = minmax(i, m)
    e, q = minmax(e, q)
    a, c = minmax(a, c)
    f, h = minmax(f, h)
    j, l = minmax(j, l)

    e, i = minmax(e, i)
    m, q = minmax(m, q)
    d, j = minmax(d, j)
    h, n = minmax(h, n)
    a, b = minmax(a, b)

    e, g = minmax(e, g)
    i, k = minmax(i, k)
    m, o = minmax(m, o)
    c, q = minmax(c, q)
    d, f = minmax(d, f)
    h, j = minmax(h, j)
    l, n = minmax(l, n)

    c, i = minmax(c, i)
    g, m = minmax(g, m)
    k, q = minmax(k, q)

    c, e = minmax(c, e)
    g, i = minmax(g, i)
    k, m = minmax(k, m)
    o, q = minmax(o, q)

    c, d = minmax(c, d)
    e, f = minmax(e, f)
    g, h = minmax(g, h)
    i, j = minmax(i, j)
    k, l = minmax(k, l)
    m, n = minmax(m, n)
    o, p = minmax(o, p)
    b, q = minmax(b, q)

    b, i = minmax(b, i)
    d, k = minmax(d, k)
    f, m = minmax(f, m)
    h, o = minmax(h, o)
    j, q = minmax(j, q)

    b, e = minmax(b, e)
    d, g = minmax(d, g)
    f, i = minmax(f, i)
    h, k = minmax(h, k)
    j, m = minmax(j, m)
    l, o = minmax(l, o)
    n, q = minmax(n, q)

    b, c = minmax(b, c)
    d, e = minmax(d, e)
    f, g = minmax(f, g)
    h, i = minmax(h, i)
    j, k = minmax(j, k)
    l, m = minmax(l, m)
    n, o = minmax(n, o)
    p, q = minmax(p, q)

    return a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q
end

#    sort 18 values with 82 minmaxs in 13 parallel stages

function swapsort(a::T, b::T, c::T, d::T, e::T,
              f::T, g::T, h::T, i::T, j::T,
              k::T, l::T, m::T, n::T, o::T,
              p::T, q::T, r::T) where {T}

    a, q = minmax(a, q)
    b, r = minmax(b, r)
    c, k = minmax(c, k)
    d, l = minmax(d, l)
    e, m = minmax(e, m)
    f, n = minmax(f, n)
    g, o = minmax(g, o)
    h, p = minmax(h, p)

    a, i = minmax(a, i)
    b, j = minmax(b, j)
    c, g = minmax(c, g)
    d, h = minmax(d, h)
    k, o = minmax(k, o)
    l, p = minmax(l, p)

    i, q = minmax(i, q)
    j, r = minmax(j, r)
    a, e = minmax(a, e)
    b, f = minmax(b, f)
    g, k = minmax(g, k)
    h, l = minmax(h, l)

    i, m = minmax(i, m)
    j, n = minmax(j, n)
    e, q = minmax(e, q)
    f, r = minmax(f, r)
    a, c = minmax(a, c)
    b, d = minmax(b, d)

    e, i = minmax(e, i)
    f, j = minmax(f, j)
    m, q = minmax(m, q)
    n, r = minmax(n, r)
    a, b = minmax(a, b)

    e, g = minmax(e, g)
    f, h = minmax(f, h)
    i, k = minmax(i, k)
    j, l = minmax(j, l)
    m, o = minmax(m, o)
    n, p = minmax(n, p)
    c, q = minmax(c, q)
    d, r = minmax(d, r)

    c, i = minmax(c, i)
    d, j = minmax(d, j)
    g, m = minmax(g, m)
    h, n = minmax(h, n)
    k, q = minmax(k, q)
    l, r = minmax(l, r)

    c, e = minmax(c, e)
    d, f = minmax(d, f)
    g, i = minmax(g, i)
    h, j = minmax(h, j)
    k, m = minmax(k, m)
    l, n = minmax(l, n)
    o, q = minmax(o, q)
    p, r = minmax(p, r)

    c, d = minmax(c, d)
    e, f = minmax(e, f)
    g, h = minmax(g, h)
    i, j = minmax(i, j)
    k, l = minmax(k, l)
    m, n = minmax(m, n)
    o, p = minmax(o, p)
    q, r = minmax(q, r)

    b, q = minmax(b, q)
    d, k = minmax(d, k)
    f, m = minmax(f, m)
    h, o = minmax(h, o)

    b, i = minmax(b, i)
    j, q = minmax(j, q)
    d, g = minmax(d, g)
    h, k = minmax(h, k)
    l, o = minmax(l, o)

    b, e = minmax(b, e)
    f, i = minmax(f, i)
    j, m = minmax(j, m)
    n, q = minmax(n, q)

    b, c = minmax(b, c)
    d, e = minmax(d, e)
    f, g = minmax(f, g)
    h, i = minmax(h, i)
    j, k = minmax(j, k)
    l, m = minmax(l, m)
    n, o = minmax(n, o)
    p, q = minmax(p, q)

    return a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r
end

#    sort 19 values with 91 minmaxs in 14 parallel stages

function swapsort(a::T, b::T, c::T, d::T, e::T,
              f::T, g::T, h::T, i::T, j::T,
              k::T, l::T, m::T, n::T, o::T,
              p::T, q::T, r::T, s::T) where {T}

    a, q = minmax(a, q)
    b, r = minmax(b, r)
    c, s = minmax(c, s)
    d, l = minmax(d, l)
    e, m = minmax(e, m)
    f, n = minmax(f, n)
    g, o = minmax(g, o)
    h, p = minmax(h, p)

    a, i = minmax(a, i)
    b, j = minmax(b, j)
    c, k = minmax(c, k)
    d, h = minmax(d, h)
    l, p = minmax(l, p)

    i, q = minmax(i, q)
    j, r = minmax(j, r)
    k, s = minmax(k, s)
    a, e = minmax(a, e)
    b, f = minmax(b, f)
    c, g = minmax(c, g)
    h, l = minmax(h, l)

    i, m = minmax(i, m)
    j, n = minmax(j, n)
    k, o = minmax(k, o)
    e, q = minmax(e, q)
    f, r = minmax(f, r)
    g, s = minmax(g, s)
    a, c = minmax(a, c)
    b, d = minmax(b, d)

    e, i = minmax(e, i)
    f, j = minmax(f, j)
    g, k = minmax(g, k)
    m, q = minmax(m, q)
    n, r = minmax(n, r)
    o, s = minmax(o, s)
    a, b = minmax(a, b)

    e, g = minmax(e, g)
    f, h = minmax(f, h)
    i, k = minmax(i, k)
    j, l = minmax(j, l)
    m, o = minmax(m, o)
    n, p = minmax(n, p)
    q, s = minmax(q, s)
    d, r = minmax(d, r)

    c, q = minmax(c, q)
    d, j = minmax(d, j)
    g, m = minmax(g, m)
    h, n = minmax(h, n)
    l, r = minmax(l, r)

    c, i = minmax(c, i)
    k, q = minmax(k, q)
    d, f = minmax(d, f)
    h, j = minmax(h, j)
    l, n = minmax(l, n)
    p, r = minmax(p, r)

    c, e = minmax(c, e)
    g, i = minmax(g, i)
    k, m = minmax(k, m)
    o, q = minmax(o, q)

    c, d = minmax(c, d)
    e, f = minmax(e, f)
    g, h = minmax(g, h)
    i, j = minmax(i, j)
    k, l = minmax(k, l)
    m, n = minmax(m, n)
    o, p = minmax(o, p)
    q, r = minmax(q, r)

    b, q = minmax(b, q)
    d, s = minmax(d, s)
    f, m = minmax(f, m)
    h, o = minmax(h, o)

    b, i = minmax(b, i)
    d, k = minmax(d, k)
    j, q = minmax(j, q)
    l, s = minmax(l, s)

    b, e = minmax(b, e)
    d, g = minmax(d, g)
    f, i = minmax(f, i)
    h, k = minmax(h, k)
    j, m = minmax(j, m)
    l, o = minmax(l, o)
    n, q = minmax(n, q)
    p, s = minmax(p, s)

    b, c = minmax(b, c)
    d, e = minmax(d, e)
    f, g = minmax(f, g)
    h, i = minmax(h, i)
    j, k = minmax(j, k)
    l, m = minmax(l, m)
    n, o = minmax(n, o)
    p, q = minmax(p, q)
    r, s = minmax(r, s)

    return a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s
end

#    sort 20 values with 97 minmaxs in 14 parallel stages

function swapsort(a::T, b::T, c::T, d::T, e::T,
              f::T, g::T, h::T, i::T, j::T,
              k::T, l::T, m::T, n::T, o::T,
              p::T, q::T, r::T, s::T, t::T) where {T}

    a, q = minmax(a, q)
    b, r = minmax(b, r)
    c, s = minmax(c, s)
    d, t = minmax(d, t)
    e, m = minmax(e, m)
    f, n = minmax(f, n)
    g, o = minmax(g, o)
    h, p = minmax(h, p)

    a, i = minmax(a, i)
    b, j = minmax(b, j)
    c, k = minmax(c, k)
    d, l = minmax(d, l)

    i, q = minmax(i, q)
    j, r = minmax(j, r)
    k, s = minmax(k, s)
    l, t = minmax(l, t)
    a, e = minmax(a, e)
    b, f = minmax(b, f)
    c, g = minmax(c, g)
    d, h = minmax(d, h)

    i, m = minmax(i, m)
    j, n = minmax(j, n)
    k, o = minmax(k, o)
    l, p = minmax(l, p)
    e, q = minmax(e, q)
    f, r = minmax(f, r)
    g, s = minmax(g, s)
    h, t = minmax(h, t)
    a, c = minmax(a, c)
    b, d = minmax(b, d)

    e, i = minmax(e, i)
    f, j = minmax(f, j)
    g, k = minmax(g, k)
    h, l = minmax(h, l)
    m, q = minmax(m, q)
    n, r = minmax(n, r)
    o, s = minmax(o, s)
    p, t = minmax(p, t)
    a, b = minmax(a, b)

    e, g = minmax(e, g)
    f, h = minmax(f, h)
    i, k = minmax(i, k)
    j, l = minmax(j, l)
    m, o = minmax(m, o)
    n, p = minmax(n, p)
    q, s = minmax(q, s)
    r, t = minmax(r, t)

    c, q = minmax(c, q)
    d, r = minmax(d, r)
    g, m = minmax(g, m)
    h, n = minmax(h, n)
    s, t = minmax(s, t)

    c, i = minmax(c, i)
    d, j = minmax(d, j)
    k, q = minmax(k, q)
    l, r = minmax(l, r)

    c, e = minmax(c, e)
    d, f = minmax(d, f)
    g, i = minmax(g, i)
    h, j = minmax(h, j)
    k, m = minmax(k, m)
    l, n = minmax(l, n)
    o, q = minmax(o, q)
    p, r = minmax(p, r)

    c, d = minmax(c, d)
    e, f = minmax(e, f)
    g, h = minmax(g, h)
    i, j = minmax(i, j)
    k, l = minmax(k, l)
    m, n = minmax(m, n)
    o, p = minmax(o, p)
    q, r = minmax(q, r)

    b, q = minmax(b, q)
    d, s = minmax(d, s)
    f, m = minmax(f, m)
    h, o = minmax(h, o)

    b, i = minmax(b, i)
    d, k = minmax(d, k)
    j, q = minmax(j, q)
    l, s = minmax(l, s)

    b, e = minmax(b, e)
    d, g = minmax(d, g)
    f, i = minmax(f, i)
    h, k = minmax(h, k)
    j, m = minmax(j, m)
    l, o = minmax(l, o)
    n, q = minmax(n, q)
    p, s = minmax(p, s)

    b, c = minmax(b, c)
    d, e = minmax(d, e)
    f, g = minmax(f, g)
    h, i = minmax(h, i)
    j, k = minmax(j, k)
    l, m = minmax(l, m)
    n, o = minmax(n, o)
    p, q = minmax(p, q)
    r, s = minmax(r, s)

    return a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t
end

#    sort 21 values with 107 minmaxs in 15 parallel stages

function swapsort(a::T, b::T, c::T, d::T, e::T,
              f::T, g::T, h::T, i::T, j::T,
              k::T, l::T, m::T, n::T, o::T,
              p::T, q::T, r::T, s::T, t::T,
              u::T) where {T}

    a, q = minmax(a, q)
    b, r = minmax(b, r)
    c, s = minmax(c, s)
    d, t = minmax(d, t)
    e, u = minmax(e, u)
    f, n = minmax(f, n)
    g, o = minmax(g, o)
    h, p = minmax(h, p)

    a, i = minmax(a, i)
    b, j = minmax(b, j)
    c, k = minmax(c, k)
    d, l = minmax(d, l)
    e, m = minmax(e, m)

    i, q = minmax(i, q)
    j, r = minmax(j, r)
    k, s = minmax(k, s)
    l, t = minmax(l, t)
    m, u = minmax(m, u)
    a, e = minmax(a, e)
    b, f = minmax(b, f)
    c, g = minmax(c, g)
    d, h = minmax(d, h)

    i, m = minmax(i, m)
    j, n = minmax(j, n)
    k, o = minmax(k, o)
    l, p = minmax(l, p)
    q, u = minmax(q, u)
    f, r = minmax(f, r)
    g, s = minmax(g, s)
    h, t = minmax(h, t)
    a, c = minmax(a, c)
    b, d = minmax(b, d)

    e, q = minmax(e, q)
    f, j = minmax(f, j)
    g, k = minmax(g, k)
    h, l = minmax(h, l)
    n, r = minmax(n, r)
    o, s = minmax(o, s)
    p, t = minmax(p, t)
    a, b = minmax(a, b)

    e, i = minmax(e, i)
    m, q = minmax(m, q)
    f, h = minmax(f, h)
    j, l = minmax(j, l)
    n, p = minmax(n, p)
    r, t = minmax(r, t)

    e, g = minmax(e, g)
    i, k = minmax(i, k)
    m, o = minmax(m, o)
    q, s = minmax(q, s)
    d, r = minmax(d, r)
    h, n = minmax(h, n)

    c, q = minmax(c, q)
    g, u = minmax(g, u)
    d, j = minmax(d, j)
    l, r = minmax(l, r)

    c, i = minmax(c, i)
    g, m = minmax(g, m)
    k, q = minmax(k, q)
    o, u = minmax(o, u)
    d, f = minmax(d, f)
    h, j = minmax(h, j)
    l, n = minmax(l, n)
    p, r = minmax(p, r)

    c, e = minmax(c, e)
    g, i = minmax(g, i)
    k, m = minmax(k, m)
    o, q = minmax(o, q)
    s, u = minmax(s, u)

    c, d = minmax(c, d)
    e, f = minmax(e, f)
    g, h = minmax(g, h)
    i, j = minmax(i, j)
    k, l = minmax(k, l)
    m, n = minmax(m, n)
    o, p = minmax(o, p)
    q, r = minmax(q, r)
    s, t = minmax(s, t)

    b, q = minmax(b, q)
    d, s = minmax(d, s)
    f, u = minmax(f, u)
    h, o = minmax(h, o)

    b, i = minmax(b, i)
    d, k = minmax(d, k)
    f, m = minmax(f, m)
    j, q = minmax(j, q)
    l, s = minmax(l, s)
    n, u = minmax(n, u)

    b, e = minmax(b, e)
    d, g = minmax(d, g)
    f, i = minmax(f, i)
    h, k = minmax(h, k)
    j, m = minmax(j, m)
    l, o = minmax(l, o)
    n, q = minmax(n, q)
    p, s = minmax(p, s)
    r, u = minmax(r, u)

    b, c = minmax(b, c)
    d, e = minmax(d, e)
    f, g = minmax(f, g)
    h, i = minmax(h, i)
    j, k = minmax(j, k)
    l, m = minmax(l, m)
    n, o = minmax(n, o)
    p, q = minmax(p, q)
    r, s = minmax(r, s)
    t, u = minmax(t, u)

    return a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u
end

#    sort 22 values with 114 minmaxs in 15 parallel stages

function swapsort(a::T, b::T, c::T, d::T, e::T,
              f::T, g::T, h::T, i::T, j::T,
              k::T, l::T, m::T, n::T, o::T,
              p::T, q::T, r::T, s::T, t::T,
              u::T, v::T) where {T}

    a, q = minmax(a, q)
    b, r = minmax(b, r)
    c, s = minmax(c, s)
    d, t = minmax(d, t)
    e, u = minmax(e, u)
    f, v = minmax(f, v)
    g, o = minmax(g, o)
    h, p = minmax(h, p)

    a, i = minmax(a, i)
    b, j = minmax(b, j)
    c, k = minmax(c, k)
    d, l = minmax(d, l)
    e, m = minmax(e, m)
    f, n = minmax(f, n)

    i, q = minmax(i, q)
    j, r = minmax(j, r)
    k, s = minmax(k, s)
    l, t = minmax(l, t)
    m, u = minmax(m, u)
    n, v = minmax(n, v)
    a, e = minmax(a, e)
    b, f = minmax(b, f)
    c, g = minmax(c, g)
    d, h = minmax(d, h)

    i, m = minmax(i, m)
    j, n = minmax(j, n)
    k, o = minmax(k, o)
    l, p = minmax(l, p)
    q, u = minmax(q, u)
    r, v = minmax(r, v)
    g, s = minmax(g, s)
    h, t = minmax(h, t)
    a, c = minmax(a, c)
    b, d = minmax(b, d)

    e, q = minmax(e, q)
    f, r = minmax(f, r)
    g, k = minmax(g, k)
    h, l = minmax(h, l)
    o, s = minmax(o, s)
    p, t = minmax(p, t)
    a, b = minmax(a, b)

    e, i = minmax(e, i)
    f, j = minmax(f, j)
    m, q = minmax(m, q)
    n, r = minmax(n, r)

    e, g = minmax(e, g)
    f, h = minmax(f, h)
    i, k = minmax(i, k)
    j, l = minmax(j, l)
    m, o = minmax(m, o)
    n, p = minmax(n, p)
    q, s = minmax(q, s)
    r, t = minmax(r, t)

    c, q = minmax(c, q)
    d, r = minmax(d, r)
    g, u = minmax(g, u)
    h, v = minmax(h, v)

    c, i = minmax(c, i)
    d, j = minmax(d, j)
    g, m = minmax(g, m)
    h, n = minmax(h, n)
    k, q = minmax(k, q)
    l, r = minmax(l, r)
    o, u = minmax(o, u)
    p, v = minmax(p, v)

    c, e = minmax(c, e)
    d, f = minmax(d, f)
    g, i = minmax(g, i)
    h, j = minmax(h, j)
    k, m = minmax(k, m)
    l, n = minmax(l, n)
    o, q = minmax(o, q)
    p, r = minmax(p, r)
    s, u = minmax(s, u)
    t, v = minmax(t, v)

    c, d = minmax(c, d)
    e, f = minmax(e, f)
    g, h = minmax(g, h)
    i, j = minmax(i, j)
    k, l = minmax(k, l)
    m, n = minmax(m, n)
    o, p = minmax(o, p)
    q, r = minmax(q, r)
    s, t = minmax(s, t)
    u, v = minmax(u, v)

    b, q = minmax(b, q)
    d, s = minmax(d, s)
    f, u = minmax(f, u)
    h, o = minmax(h, o)

    b, i = minmax(b, i)
    d, k = minmax(d, k)
    f, m = minmax(f, m)
    j, q = minmax(j, q)
    l, s = minmax(l, s)
    n, u = minmax(n, u)

    b, e = minmax(b, e)
    d, g = minmax(d, g)
    f, i = minmax(f, i)
    h, k = minmax(h, k)
    j, m = minmax(j, m)
    l, o = minmax(l, o)
    n, q = minmax(n, q)
    p, s = minmax(p, s)
    r, u = minmax(r, u)

    b, c = minmax(b, c)
    d, e = minmax(d, e)
    f, g = minmax(f, g)
    h, i = minmax(h, i)
    j, k = minmax(j, k)
    l, m = minmax(l, m)
    n, o = minmax(n, o)
    p, q = minmax(p, q)
    r, s = minmax(r, s)
    t, u = minmax(t, u)

    return a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v
end

#    sort 23 values with 122 minmaxs in 15 parallel stages

function swapsort(a::T, b::T, c::T, d::T, e::T,
              f::T, g::T, h::T, i::T, j::T,
              k::T, l::T, m::T, n::T, o::T,
              p::T, q::T, r::T, s::T, t::T,
              u::T, v::T, w::T) where {T}

    a, q = minmax(a, q)
    b, r = minmax(b, r)
    c, s = minmax(c, s)
    d, t = minmax(d, t)
    e, u = minmax(e, u)
    f, v = minmax(f, v)
    g, w = minmax(g, w)
    h, p = minmax(h, p)

    a, i = minmax(a, i)
    b, j = minmax(b, j)
    c, k = minmax(c, k)
    d, l = minmax(d, l)
    e, m = minmax(e, m)
    f, n = minmax(f, n)
    g, o = minmax(g, o)

    i, q = minmax(i, q)
    j, r = minmax(j, r)
    k, s = minmax(k, s)
    l, t = minmax(l, t)
    m, u = minmax(m, u)
    n, v = minmax(n, v)
    o, w = minmax(o, w)
    a, e = minmax(a, e)
    b, f = minmax(b, f)
    c, g = minmax(c, g)
    d, h = minmax(d, h)

    i, m = minmax(i, m)
    j, n = minmax(j, n)
    k, o = minmax(k, o)
    l, p = minmax(l, p)
    q, u = minmax(q, u)
    r, v = minmax(r, v)
    s, w = minmax(s, w)
    h, t = minmax(h, t)
    a, c = minmax(a, c)
    b, d = minmax(b, d)

    e, q = minmax(e, q)
    f, r = minmax(f, r)
    g, s = minmax(g, s)
    h, l = minmax(h, l)
    p, t = minmax(p, t)
    u, w = minmax(u, w)
    a, b = minmax(a, b)

    e, i = minmax(e, i)
    f, j = minmax(f, j)
    g, k = minmax(g, k)
    m, q = minmax(m, q)
    n, r = minmax(n, r)
    o, s = minmax(o, s)

    e, g = minmax(e, g)
    f, h = minmax(f, h)
    i, k = minmax(i, k)
    j, l = minmax(j, l)
    m, o = minmax(m, o)
    n, p = minmax(n, p)
    q, s = minmax(q, s)
    r, t = minmax(r, t)

    c, q = minmax(c, q)
    d, r = minmax(d, r)
    g, u = minmax(g, u)
    h, v = minmax(h, v)

    c, i = minmax(c, i)
    d, j = minmax(d, j)
    g, m = minmax(g, m)
    h, n = minmax(h, n)
    k, q = minmax(k, q)
    l, r = minmax(l, r)
    o, u = minmax(o, u)
    p, v = minmax(p, v)

    c, e = minmax(c, e)
    d, f = minmax(d, f)
    g, i = minmax(g, i)
    h, j = minmax(h, j)
    k, m = minmax(k, m)
    l, n = minmax(l, n)
    o, q = minmax(o, q)
    p, r = minmax(p, r)
    s, u = minmax(s, u)
    t, v = minmax(t, v)

    c, d = minmax(c, d)
    e, f = minmax(e, f)
    g, h = minmax(g, h)
    i, j = minmax(i, j)
    k, l = minmax(k, l)
    m, n = minmax(m, n)
    o, p = minmax(o, p)
    q, r = minmax(q, r)
    s, t = minmax(s, t)
    u, v = minmax(u, v)

    b, q = minmax(b, q)
    d, s = minmax(d, s)
    f, u = minmax(f, u)
    h, w = minmax(h, w)

    b, i = minmax(b, i)
    d, k = minmax(d, k)
    f, m = minmax(f, m)
    h, o = minmax(h, o)
    j, q = minmax(j, q)
    l, s = minmax(l, s)
    n, u = minmax(n, u)
    p, w = minmax(p, w)

    b, e = minmax(b, e)
    d, g = minmax(d, g)
    f, i = minmax(f, i)
    h, k = minmax(h, k)
    j, m = minmax(j, m)
    l, o = minmax(l, o)
    n, q = minmax(n, q)
    p, s = minmax(p, s)
    r, u = minmax(r, u)
    t, w = minmax(t, w)

    b, c = minmax(b, c)
    d, e = minmax(d, e)
    f, g = minmax(f, g)
    h, i = minmax(h, i)
    j, k = minmax(j, k)
    l, m = minmax(l, m)
    n, o = minmax(n, o)
    p, q = minmax(p, q)
    r, s = minmax(r, s)
    t, u = minmax(t, u)
    v, w = minmax(v, w)

    return a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w
end

#    sort 24 values with 127 minmaxs in 15 parallel stages

function swapsort(a::T, b::T, c::T, d::T, e::T,
              f::T, g::T, h::T, i::T, j::T,
              k::T, l::T, m::T, n::T, o::T,
              p::T, q::T, r::T, s::T, t::T,
              u::T, v::T, w::T, x::T) where {T}

    a, q = minmax(a, q)
    b, r = minmax(b, r)
    c, s = minmax(c, s)
    d, t = minmax(d, t)
    e, u = minmax(e, u)
    f, v = minmax(f, v)
    g, w = minmax(g, w)
    h, x = minmax(h, x)

    a, i = minmax(a, i)
    b, j = minmax(b, j)
    c, k = minmax(c, k)
    d, l = minmax(d, l)
    e, m = minmax(e, m)
    f, n = minmax(f, n)
    g, o = minmax(g, o)
    h, p = minmax(h, p)

    i, q = minmax(i, q)
    j, r = minmax(j, r)
    k, s = minmax(k, s)
    l, t = minmax(l, t)
    m, u = minmax(m, u)
    n, v = minmax(n, v)
    o, w = minmax(o, w)
    p, x = minmax(p, x)
    a, e = minmax(a, e)
    b, f = minmax(b, f)
    c, g = minmax(c, g)
    d, h = minmax(d, h)

    i, m = minmax(i, m)
    j, n = minmax(j, n)
    k, o = minmax(k, o)
    l, p = minmax(l, p)
    q, u = minmax(q, u)
    r, v = minmax(r, v)
    s, w = minmax(s, w)
    t, x = minmax(t, x)
    a, c = minmax(a, c)
    b, d = minmax(b, d)

    e, q = minmax(e, q)
    f, r = minmax(f, r)
    g, s = minmax(g, s)
    h, t = minmax(h, t)
    u, w = minmax(u, w)
    v, x = minmax(v, x)
    a, b = minmax(a, b)

    e, i = minmax(e, i)
    f, j = minmax(f, j)
    g, k = minmax(g, k)
    h, l = minmax(h, l)
    m, q = minmax(m, q)
    n, r = minmax(n, r)
    o, s = minmax(o, s)
    p, t = minmax(p, t)
    w, x = minmax(w, x)

    e, g = minmax(e, g)
    f, h = minmax(f, h)
    i, k = minmax(i, k)
    j, l = minmax(j, l)
    m, o = minmax(m, o)
    n, p = minmax(n, p)
    q, s = minmax(q, s)
    r, t = minmax(r, t)

    c, q = minmax(c, q)
    d, r = minmax(d, r)
    g, u = minmax(g, u)
    h, v = minmax(h, v)

    c, i = minmax(c, i)
    d, j = minmax(d, j)
    g, m = minmax(g, m)
    h, n = minmax(h, n)
    k, q = minmax(k, q)
    l, r = minmax(l, r)
    o, u = minmax(o, u)
    p, v = minmax(p, v)

    c, e = minmax(c, e)
    d, f = minmax(d, f)
    g, i = minmax(g, i)
    h, j = minmax(h, j)
    k, m = minmax(k, m)
    l, n = minmax(l, n)
    o, q = minmax(o, q)
    p, r = minmax(p, r)
    s, u = minmax(s, u)
    t, v = minmax(t, v)

    c, d = minmax(c, d)
    e, f = minmax(e, f)
    g, h = minmax(g, h)
    i, j = minmax(i, j)
    k, l = minmax(k, l)
    m, n = minmax(m, n)
    o, p = minmax(o, p)
    q, r = minmax(q, r)
    s, t = minmax(s, t)
    u, v = minmax(u, v)

    b, q = minmax(b, q)
    d, s = minmax(d, s)
    f, u = minmax(f, u)
    h, w = minmax(h, w)

    b, i = minmax(b, i)
    d, k = minmax(d, k)
    f, m = minmax(f, m)
    h, o = minmax(h, o)
    j, q = minmax(j, q)
    l, s = minmax(l, s)
    n, u = minmax(n, u)
    p, w = minmax(p, w)

    b, e = minmax(b, e)
    d, g = minmax(d, g)
    f, i = minmax(f, i)
    h, k = minmax(h, k)
    j, m = minmax(j, m)
    l, o = minmax(l, o)
    n, q = minmax(n, q)
    p, s = minmax(p, s)
    r, u = minmax(r, u)
    t, w = minmax(t, w)

    b, c = minmax(b, c)
    d, e = minmax(d, e)
    f, g = minmax(f, g)
    h, i = minmax(h, i)
    j, k = minmax(j, k)
    l, m = minmax(l, m)
    n, o = minmax(n, o)
    p, q = minmax(p, q)
    r, s = minmax(r, s)
    t, u = minmax(t, u)
    v, w = minmax(v, w)

    return a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x
end

#    sort 25 values with 138 minmaxs in 15 parallel stages

function swapsort(a::T, b::T, c::T, d::T, e::T,
              f::T, g::T, h::T, i::T, j::T,
              k::T, l::T, m::T, n::T, o::T,
              p::T, q::T, r::T, s::T, t::T,
              u::T, v::T, w::T, x::T, y::T) where {T}

    a, q = minmax(a, q)
    b, r = minmax(b, r)
    c, s = minmax(c, s)
    d, t = minmax(d, t)
    e, u = minmax(e, u)
    f, v = minmax(f, v)
    g, w = minmax(g, w)
    h, x = minmax(h, x)
    i, y = minmax(i, y)

    a, i = minmax(a, i)
    b, j = minmax(b, j)
    c, k = minmax(c, k)
    d, l = minmax(d, l)
    e, m = minmax(e, m)
    f, n = minmax(f, n)
    g, o = minmax(g, o)
    h, p = minmax(h, p)
    q, y = minmax(q, y)

    i, q = minmax(i, q)
    j, r = minmax(j, r)
    k, s = minmax(k, s)
    l, t = minmax(l, t)
    m, u = minmax(m, u)
    n, v = minmax(n, v)
    o, w = minmax(o, w)
    p, x = minmax(p, x)
    a, e = minmax(a, e)
    b, f = minmax(b, f)
    c, g = minmax(c, g)
    d, h = minmax(d, h)

    i, m = minmax(i, m)
    j, n = minmax(j, n)
    k, o = minmax(k, o)
    l, p = minmax(l, p)
    q, u = minmax(q, u)
    r, v = minmax(r, v)
    s, w = minmax(s, w)
    t, x = minmax(t, x)
    a, c = minmax(a, c)
    b, d = minmax(b, d)

    e, q = minmax(e, q)
    f, r = minmax(f, r)
    g, s = minmax(g, s)
    h, t = minmax(h, t)
    m, y = minmax(m, y)
    v, x = minmax(v, x)
    a, b = minmax(a, b)

    e, i = minmax(e, i)
    f, j = minmax(f, j)
    g, k = minmax(g, k)
    h, l = minmax(h, l)
    m, q = minmax(m, q)
    n, r = minmax(n, r)
    o, s = minmax(o, s)
    p, t = minmax(p, t)
    u, y = minmax(u, y)

    e, g = minmax(e, g)
    f, h = minmax(f, h)
    i, k = minmax(i, k)
    j, l = minmax(j, l)
    m, o = minmax(m, o)
    n, p = minmax(n, p)
    q, s = minmax(q, s)
    r, t = minmax(r, t)
    u, w = minmax(u, w)

    c, q = minmax(c, q)
    d, r = minmax(d, r)
    g, u = minmax(g, u)
    h, v = minmax(h, v)
    k, y = minmax(k, y)

    c, i = minmax(c, i)
    d, j = minmax(d, j)
    g, m = minmax(g, m)
    h, n = minmax(h, n)
    k, q = minmax(k, q)
    l, r = minmax(l, r)
    o, u = minmax(o, u)
    p, v = minmax(p, v)
    s, y = minmax(s, y)

    c, e = minmax(c, e)
    d, f = minmax(d, f)
    g, i = minmax(g, i)
    h, j = minmax(h, j)
    k, m = minmax(k, m)
    l, n = minmax(l, n)
    o, q = minmax(o, q)
    p, r = minmax(p, r)
    s, u = minmax(s, u)
    t, v = minmax(t, v)
    w, y = minmax(w, y)

    c, d = minmax(c, d)
    e, f = minmax(e, f)
    g, h = minmax(g, h)
    i, j = minmax(i, j)
    k, l = minmax(k, l)
    m, n = minmax(m, n)
    o, p = minmax(o, p)
    q, r = minmax(q, r)
    s, t = minmax(s, t)
    u, v = minmax(u, v)
    w, x = minmax(w, x)

    b, q = minmax(b, q)
    d, s = minmax(d, s)
    f, u = minmax(f, u)
    h, w = minmax(h, w)
    j, y = minmax(j, y)

    b, i = minmax(b, i)
    d, k = minmax(d, k)
    f, m = minmax(f, m)
    h, o = minmax(h, o)
    j, q = minmax(j, q)
    l, s = minmax(l, s)
    n, u = minmax(n, u)
    p, w = minmax(p, w)
    r, y = minmax(r, y)

    b, e = minmax(b, e)
    d, g = minmax(d, g)
    f, i = minmax(f, i)
    h, k = minmax(h, k)
    j, m = minmax(j, m)
    l, o = minmax(l, o)
    n, q = minmax(n, q)
    p, s = minmax(p, s)
    r, u = minmax(r, u)
    t, w = minmax(t, w)
    v, y = minmax(v, y)

    b, c = minmax(b, c)
    d, e = minmax(d, e)
    f, g = minmax(f, g)
    h, i = minmax(h, i)
    j, k = minmax(j, k)
    l, m = minmax(l, m)
    n, o = minmax(n, o)
    p, q = minmax(p, q)
    r, s = minmax(r, s)
    t, u = minmax(t, u)
    v, w = minmax(v, w)
    x, y = minmax(x, y)

    return a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y
end


text:
glb{N,ES}(x::Vnum{N,ES}) = isulp(x) ? prev(x) : x
lub{N,ES}(x::Vnum{N,ES}) = isulp(x) ? next(x) : x
upper_ulp{N,ES}(x::Vnum{N,ES}) = isulp(x) ? x : next(x)
lower_ulp{N,ES}(x::Vnum{N,ES}) = isulp(x) ? x : prev(x)

outer_exact{N,ES}(x::Vnum{N,ES}) = reinterpret((@Int), x) < 0 ? lub(x) : glb(x)
inner_exact{N,ES}(x::Vnum{N,ES}) = reinterpret((@Int), x) < 0 ? glb(x) : lub(x)

function outer_ulp{N,ES}(x::Vnum{N,ES})
  xint = reinterpret(@Int, x)
  if xint == 0
    throw(NaNError(:inner_exact, [x]))
  elseif xint < 0
    lower_ulp(x)
  else
    upper_ulp(x)
  end
end

function inner_ulp{N,ES}(x::Vnum{N,ES})
  xint = reinterpret(@Int, x)
  if xint == 0
    throw(NaNError(:inner_exact, [x]))
  elseif xint < 0
    upper_ulp(x)
  else
    lower_ulp(x)
  end
end

max_stars_repo_name: ityonemo/SigmoidNumbers

max_issues_repo_name: ityonemo/SigmoidNumbers

max_forks_repo_name: ityonemo/SigmoidNumbers


text:
using DashBootstrapComponents

button = html_div(
    [
        dbc_button("Block button", color = "primary"),
        dbc_button("Block button", color = "secondary"),
    ],
    className = "d-grid gap-2 d-md-block",
);

max_issues_repo_name: sthagen/dash-bootstrap-components

max_forks_repo_name: sthagen/dash-bootstrap-components


text:
const TLDs = [
    "aaa",
    "aarp",
    "abarth",
    "abb",
    "abbott",
    "abbvie",
    "abc",
    "able",
    "abogado",
    "abudhabi",
    "ac",
    "academy",
    "accenture",
    "accountant",
    "accountants",
    "aco",
    "active",
    "actor",
    "ad",
    "adac",
    "ads",
    "adult",
    "ae",
    "aeg",
    "aero",
    "aetna",
    "af",
    "afamilycompany",
    "afl",
    "africa",
    "ag",
    "agakhan",
    "agency",
    "ai",
    "aig",
    "aigo",
    "airbus",
    "airforce",
    "airtel",
    "akdn",
    "al",
    "alfaromeo",
    "alibaba",
    "alipay",
    "allfinanz",
    "allstate",
    "ally",
    "alsace",
    "alstom",
    "am",
    "amazon",
    "americanexpress",
    "americanfamily",
    "amex",
    "amfam",
    "amica",
    "amsterdam",
    "an",
    "analytics",
    "android",
    "anquan",
    "anz",
    "ao",
    "aol",
    "apartments",
    "app",
    "apple",
    "aq",
    "aquarelle",
    "ar",
    "arab",
    "aramco",
    "archi",
    "army",
    "arpa",
    "art",
    "arte",
    "as",
    "asda",
    "asia",
    "associates",
    "at",
    "athleta",
    "attorney",
    "au",
    "auction",
    "audi",
    "audible",
    "audio",
    "auspost",
    "author",
    "auto",
    "autos",
    "avianca",
    "aw",
    "aws",
    "ax",
    "axa",
    "az",
    "azure",
    "ba",
    "baby",
    "baidu",
    "banamex",
    "bananarepublic",
    "band",
    "bank",
    "bar",
    "barcelona",
    "barclaycard",
    "barclays",
    "barefoot",
    "bargains",
    "baseball",
    "basketball",
    "bauhaus",
    "bayern",
    "bb",
    "bbc",
    "bbt",
    "bbva",
    "bcg",
    "bcn",
    "bd",
    "be",
    "beats",
    "beauty",
    "beer",
    "bentley",
    "berlin",
    "best",
    "bestbuy",
    "bet",
    "bf",
    "bg",
    "bh",
    "bharti",
    "bi",
    "bible",
    "bid",
    "bike",
    "bing",
    "bingo",
    "bio",
    "biz",
    "bj",
    "bl",
    "black",
    "blackfriday",
    "blanco",
    "blockbuster",
    "blog",
    "bloomberg",
    "blue",
    "bm",
    "bms",
    "bmw",
    "bn",
    "bnl",
    "bnpparibas",
    "bo",
    "boats",
    "boehringer",
    "bofa",
    "bom",
    "bond",
    "boo",
    "book",
    "booking",
    "boots",
    "bosch",
    "bostik",
    "boston",
    "bot",
    "boutique",
    "box",
    "bq",
    "br",
    "bradesco",
    "bridgestone",
    "broadway",
    "broker",
    "brother",
    "brussels",
    "bs",
    "bt",
    "budapest",
    "bugatti",
    "build",
    "builders",
    "business",
    "buy",
    "buzz",
    "bv",
    "bw",
    "by",
    "bz",
    "bzh",
    "ca",
    "cab",
    "cafe",
    "cal",
    "call",
    "calvinklein",
    "cam",
    "camera",
    "camp",
    "cancerresearch",
    "canon",
    "capetown",
    "capital",
    "capitalone",
    "car",
    "caravan",
    "cards",
    "care",
    "career",
    "careers",
    "cars",
    "cartier",
    "casa",
    "case",
    "caseih",
    "cash",
    "casino",
    "cat",
    "catering",
    "catholic",
    "cba",
    "cbn",
    "cbre",
    "cbs",
    "cc",
    "cd",
    "ceb",
    "center",
    "ceo",
    "cern",
    "cf",
    "cfa",
    "cfd",
    "cg",
    "ch",
    "chanel",
    "channel",
    "charity",
    "chase",
    "chat",
    "cheap",
    "chintai",
    "chloe",
    "christmas",
    "chrome",
    "chrysler",
    "church",
    "ci",
    "cipriani",
    "circle",
    "cisco",
    "citadel",
    "citi",
    "citic",
    "city",
    "cityeats",
    "ck",
    "cl",
    "claims",
    "cleaning",
    "click",
    "clinic",
    "clinique",
    "clothing",
    "cloud",
    "club",
    "clubmed",
    "cm",
    "cn",
    "co",
    "coach",
    "codes",
    "coffee",
    "college",
    "cologne",
    "com",
    "comcast",
    "commbank",
    "community",
    "company",
    "compare",
    "computer",
    "comsec",
    "condos",
    "construction",
    "consulting",
    "contact",
    "contractors",
    "cooking",
    "cookingchannel",
    "cool",
    "coop",
    "corsica",
    "country",
    "coupon",
    "coupons",
    "courses",
    "cpa",
    "cr",
    "credit",
    "creditcard",
    "creditunion",
    "cricket",
    "crown",
    "crs",
    "cruise",
    "cruises",
    "csc",
    "cu",
    "cuisinella",
    "cv",
    "cw",
    "cx",
    "cy",
    "cymru",
    "cyou",
    "cz",
    "dabur",
    "dad",
    "dance",
    "data",
    "date",
    "dating",
    "datsun",
    "day",
    "dclk",
    "dds",
    "de",
    "deal",
    "dealer",
    "deals",
    "degree",
    "delivery",
    "dell",
    "deloitte",
    "delta",
    "democrat",
    "dental",
    "dentist",
    "desi",
    "design",
    "dev",
    "dhl",
    "diamonds",
    "diet",
    "digital",
    "direct",
    "directory",
    "discount",
    "discover",
    "dish",
    "diy",
    "dj",
    "dk",
    "dm",
    "dnp",
    "do",
    "docs",
    "doctor",
    "dodge",
    "dog",
    "doha",
    "domains",
    "doosan",
    "dot",
    "download",
    "drive",
    "dtv",
    "dubai",
    "duck",
    "dunlop",
    "duns",
    "dupont",
    "durban",
    "dvag",
    "dvr",
    "dz",
    "earth",
    "eat",
    "ec",
    "eco",
    "edeka",
    "edu",
    "education",
    "ee",
    "eg",
    "eh",
    "email",
    "emerck",
    "energy",
    "engineer",
    "engineering",
    "enterprises",
    "epost",
    "epson",
    "equipment",
    "er",
    "ericsson",
    "erni",
    "es",
    "esq",
    "estate",
    "esurance",
    "et",
    "etisalat",
    "eu",
    "eurovision",
    "eus",
    "events",
    "everbank",
    "exchange",
    "expert",
    "exposed",
    "express",
    "extraspace",
    "fage",
    "fail",
    "fairwinds",
    "faith",
    "family",
    "fan",
    "fans",
    "farm",
    "farmers",
    "fashion",
    "fast",
    "fedex",
    "feedback",
    "ferrari",
    "ferrero",
    "fi",
    "fiat",
    "fidelity",
    "fido",
    "film",
    "final",
    "finance",
    "financial",
    "fire",
    "firestone",
    "firmdale",
    "fish",
    "fishing",
    "fit",
    "fitness",
    "fj",
    "fk",
    "flickr",
    "flights",
    "flir",
    "florist",
    "flowers",
    "flsmidth",
    "fly",
    "fm",
    "fo",
    "foo",
    "food",
    "foodnetwork",
    "football",
    "ford",
    "forex",
    "forsale",
    "forum",
    "foundation",
    "fox",
    "fr",
    "free",
    "fresenius",
    "frl",
    "frogans",
    "frontdoor",
    "frontier",
    "ftr",
    "fujitsu",
    "fujixerox",
    "fun",
    "fund",
    "furniture",
    "futbol",
    "fyi",
    "ga",
    "gal",
    "gallery",
    "gallo",
    "gallup",
    "game",
    "games",
    "gap",
    "garden",
    "gay",
    "gb",
    "gbiz",
    "gd",
    "gdn",
    "ge",
    "gea",
    "gent",
    "genting",
    "george",
    "gf",
    "gg",
    "ggee",
    "gh",
    "gi",
    "gift",
    "gifts",
    "gives",
    "giving",
    "gl",
    "glade",
    "glass",
    "gle",
    "global",
    "globo",
    "gm",
    "gmail",
    "gmbh",
    "gmo",
    "gmx",
    "gn",
    "godaddy",
    "gold",
    "goldpoint",
    "golf",
    "goo",
    "goodhands",
    "goodyear",
    "goog",
    "google",
    "gop",
    "got",
    "gov",
    "gp",
    "gq",
    "gr",
    "grainger",
    "graphics",
    "gratis",
    "green",
    "gripe",
    "grocery",
    "group",
    "gs",
    "gt",
    "gu",
    "guardian",
    "gucci",
    "guge",
    "guide",
    "guitars",
    "guru",
    "gw",
    "gy",
    "hair",
    "hamburg",
    "hangout",
    "haus",
    "hbo",
    "hdfc",
    "hdfcbank",
    "health",
    "healthcare",
    "help",
    "helsinki",
    "here",
    "hermes",
    "hgtv",
    "hiphop",
    "hisamitsu",
    "hitachi",
    "hiv",
    "hk",
    "hkt",
    "hm",
    "hn",
    "hockey",
    "holdings",
    "holiday",
    "homedepot",
    "homegoods",
    "homes",
    "homesense",
    "honda",
    "honeywell",
    "horse",
    "hospital",
    "host",
    "hosting",
    "hot",
    "hoteles",
    "hotels",
    "hotmail",
    "house",
    "how",
    "hr",
    "hsbc",
    "ht",
    "htc",
    "hu",
    "hughes",
    "hyatt",
    "hyundai",
    "ibm",
    "icbc",
    "ice",
    "icu",
    "id",
    "ie",
    "ieee",
    "ifm",
    "iinet",
    "ikano",
    "il",
    "im",
    "imamat",
    "imdb",
    "immo",
    "immobile",
    "in",
    "inc",
    "industries",
    "infiniti",
    "info",
    "ing",
    "ink",
    "institute",
    "insurance",
    "insure",
    "int",
    "intel",
    "international",
    "intuit",
    "investments",
    "io",
    "ipiranga",
    "iq",
    "ir",
    "irish",
    "is",
    "iselect",
    "ismaili",
    "ist",
    "istanbul",
    "it",
    "itau",
    "itv",
    "iveco",
    "iwc",
    "jaguar",
    "java",
    "jcb",
    "jcp",
    "je",
    "jeep",
    "jetzt",
    "jewelry",
    "jio",
    "jlc",
    "jll",
    "jm",
    "jmp",
    "jnj",
    "jo",
    "jobs",
    "joburg",
    "jot",
    "joy",
    "jp",
    "jpmorgan",
    "jprs",
    "juegos",
    "juniper",
    "kaufen",
    "kddi",
    "ke",
    "kerryhotels",
    "kerrylogistics",
    "kerryproperties",
    "kfh",
    "kg",
    "kh",
    "ki",
    "kia",
    "kim",
    "kinder",
    "kindle",
    "kitchen",
    "kiwi",
    "km",
    "kn",
    "koeln",
    "komatsu",
    "kosher",
    "kp",
    "kpmg",
    "kpn",
    "kr",
    "krd",
    "kred",
    "kuokgroup",
    "kw",
    "ky",
    "kyoto",
    "kz",
    "la",
    "lacaixa",
    "ladbrokes",
    "lamborghini",
    "lamer",
    "lancaster",
    "lancia",
    "lancome",
    "land",
    "landrover",
    "lanxess",
    "lasalle",
    "lat",
    "latino",
    "latrobe",
    "law",
    "lawyer",
    "lb",
    "lc",
    "lds",
    "lease",
    "leclerc",
    "lefrak",
    "legal",
    "lego",
    "lexus",
    "lgbt",
    "li",
    "liaison",
    "lidl",
    "life",
    "lifeinsurance",
    "lifestyle",
    "lighting",
    "like",
    "lilly",
    "limited",
    "limo",
    "lincoln",
    "linde",
    "link",
    "lipsy",
    "live",
    "living",
    "lixil",
    "lk",
    "llc",
    "llp",
    "loan",
    "loans",
    "locker",
    "locus",
    "loft",
    "lol",
    "london",
    "lotte",
    "lotto",
    "love",
    "lpl",
    "lplfinancial",
    "lr",
    "ls",
    "lt",
    "ltd",
    "ltda",
    "lu",
    "lundbeck",
    "lupin",
    "luxe",
    "luxury",
    "lv",
    "ly",
    "ma",
    "macys",
    "madrid",
    "maif",
    "maison",
    "makeup",
    "man",
    "management",
    "mango",
    "map",
    "market",
    "marketing",
    "markets",
    "marriott",
    "marshalls",
    "maserati",
    "mattel",
    "mba",
    "mc",
    "mcd",
    "mcdonalds",
    "mckinsey",
    "md",
    "me",
    "med",
    "media",
    "meet",
    "melbourne",
    "meme",
    "memorial",
    "men",
    "menu",
    "meo",
    "merckmsd",
    "metlife",
    "mf",
    "mg",
    "mh",
    "miami",
    "microsoft",
    "mil",
    "mini",
    "mint",
    "mit",
    "mitsubishi",
    "mk",
    "ml",
    "mlb",
    "mls",
    "mm",
    "mma",
    "mn",
    "mo",
    "mobi",
    "mobile",
    "mobily",
    "moda",
    "moe",
    "moi",
    "mom",
    "monash",
    "money",
    "monster",
    "montblanc",
    "mopar",
    "mormon",
    "mortgage",
    "moscow",
    "moto",
    "motorcycles",
    "mov",
    "movie",
    "movistar",
    "mp",
    "mq",
    "mr",
    "ms",
    "msd",
    "mt",
    "mtn",
    "mtpc",
    "mtr",
    "mu",
    "museum",
    "mutual",
    "mutuelle",
    "mv",
    "mw",
    "mx",
    "my",
    "mz",
    "na",
    "nab",
    "nadex",
    "nagoya",
    "name",
    "nationwide",
    "natura",
    "navy",
    "nba",
    "nc",
    "ne",
    "nec",
    "net",
    "netbank",
    "netflix",
    "network",
    "neustar",
    "new",
    "newholland",
    "news",
    "next",
    "nextdirect",
    "nexus",
    "nf",
    "nfl",
    "ng",
    "ngo",
    "nhk",
    "ni",
    "nico",
    "nike",
    "nikon",
    "ninja",
    "nissan",
    "nissay",
    "nl",
    "no",
    "nokia",
    "northwesternmutual",
    "norton",
    "now",
    "nowruz",
    "nowtv",
    "np",
    "nr",
    "nra",
    "nrw",
    "ntt",
    "nu",
    "nyc",
    "nz",
    "obi",
    "observer",
    "off",
    "office",
    "okinawa",
    "olayan",
    "olayangroup",
    "oldnavy",
    "ollo",
    "om",
    "omega",
    "one",
    "ong",
    "onl",
    "online",
    "onyourside",
    "ooo",
    "open",
    "oracle",
    "orange",
    "org",
    "organic",
    "orientexpress",
    "origins",
    "osaka",
    "otsuka",
    "ott",
    "ovh",
    "pa",
    "page",
    "pamperedchef",
    "panasonic",
    "panerai",
    "paris",
    "pars",
    "partners",
    "parts",
    "party",
    "passages",
    "pay",
    "pccw",
    "pe",
    "pet",
    "pf",
    "pfizer",
    "pg",
    "ph",
    "pharmacy",
    "phd",
    "philips",
    "phone",
    "photo",
    "photography",
    "photos",
    "physio",
    "piaget",
    "pics",
    "pictet",
    "pictures",
    "pid",
    "pin",
    "ping",
    "pink",
    "pioneer",
    "pizza",
    "pk",
    "pl",
    "place",
    "play",
    "playstation",
    "plumbing",
    "plus",
    "pm",
    "pn",
    "pnc",
    "pohl",
    "poker",
    "politie",
    "porn",
    "post",
    "pr",
    "pramerica",
    "praxi",
    "press",
    "prime",
    "pro",
    "prod",
    "productions",
    "prof",
    "progressive",
    "promo",
    "properties",
    "property",
    "protection",
    "pru",
    "prudential",
    "ps",
    "pt",
    "pub",
    "pw",
    "pwc",
    "py",
    "qa",
    "qpon",
    "quebec",
    "quest",
    "qvc",
    "racing",
    "radio",
    "raid",
    "re",
    "read",
    "realestate",
    "realtor",
    "realty",
    "recipes",
    "red",
    "redstone",
    "redumbrella",
    "rehab",
    "reise",
    "reisen",
    "reit",
    "reliance",
    "ren",
    "rent",
    "rentals",
    "repair",
    "report",
    "republican",
    "rest",
    "restaurant",
    "review",
    "reviews",
    "rexroth",
    "rich",
    "richardli",
    "ricoh",
    "rightathome",
    "ril",
    "rio",
    "rip",
    "rmit",
    "ro",
    "rocher",
    "rocks",
    "rodeo",
    "rogers",
    "room",
    "rs",
    "rsvp",
    "ru",
    "rugby",
    "ruhr",
    "run",
    "rw",
    "rwe",
    "ryukyu",
    "sa",
    "saarland",
    "safe",
    "safety",
    "sakura",
    "sale",
    "salon",
    "samsclub",
    "samsung",
    "sandvik",
    "sandvikcoromant",
    "sanofi",
    "sap",
    "sapo",
    "sarl",
    "sas",
    "save",
    "saxo",
    "sb",
    "sbi",
    "sbs",
    "sc",
    "sca",
    "scb",
    "schaeffler",
    "schmidt",
    "scholarships",
    "school",
    "schule",
    "schwarz",
    "science",
    "scjohnson",
    "scor",
    "scot",
    "sd",
    "se",
    "search",
    "seat",
    "secure",
    "security",
    "seek",
    "select",
    "sener",
    "services",
    "ses",
    "seven",
    "sew",
    "sex",
    "sexy",
    "sfr",
    "sg",
    "sh",
    "shangrila",
    "sharp",
    "shaw",
    "shell",
    "shia",
    "shiksha",
    "shoes",
    "shop",
    "shopping",
    "shouji",
    "show",
    "showtime",
    "shriram",
    "si",
    "silk",
    "sina",
    "singles",
    "site",
    "sj",
    "sk",
    "ski",
    "skin",
    "sky",
    "skype",
    "sl",
    "sling",
    "sm",
    "smart",
    "smile",
    "sn",
    "sncf",
    "so",
    "soccer",
    "social",
    "softbank",
    "software",
    "sohu",
    "solar",
    "solutions",
    "song",
    "sony",
    "soy",
    "spa",
    "space",
    "spiegel",
    "sport",
    "spot",
    "spreadbetting",
    "sr",
    "srl",
    "srt",
    "ss",
    "st",
    "stada",
    "staples",
    "star",
    "starhub",
    "statebank",
    "statefarm",
    "statoil",
    "stc",
    "stcgroup",
    "stockholm",
    "storage",
    "store",
    "stream",
    "studio",
    "study",
    "style",
    "su",
    "sucks",
    "supplies",
    "supply",
    "support",
    "surf",
    "surgery",
    "suzuki",
    "sv",
    "swatch",
    "swiftcover",
    "swiss",
    "sx",
    "sy",
    "sydney",
    "symantec",
    "systems",
    "sz",
    "tab",
    "taipei",
    "talk",
    "taobao",
    "target",
    "tatamotors",
    "tatar",
    "tattoo",
    "tax",
    "taxi",
    "tc",
    "tci",
    "td",
    "tdk",
    "team",
    "tech",
    "technology",
    "tel",
    "telecity",
    "telefonica",
    "temasek",
    "tennis",
    "teva",
    "tf",
    "tg",
    "th",
    "thd",
    "theater",
    "theater",
    "tiaa",
    "tickets",
    "tienda",
    "tiffany",
    "tips",
    "tires",
    "tirol",
    "tj",
    "tjmaxx",
    "tjx",
    "tk",
    "tkmaxx",
    "tl",
    "tm",
    "tmall",
    "tn",
    "to",
    "today",
    "tokyo",
    "tools",
    "top",
    "toray",
    "toshiba",
    "total",
    "tours",
    "town",
    "toyota",
    "toys",
    "tp",
    "tr",
    "trade",
    "trading",
    "training",
    "travel",
    "travelchannel",
    "travelers",
    "travelersinsurance",
    "trust",
    "trv",
    "tt",
    "tube",
    "tui",
    "tunes",
    "tushu",
    "tv",
    "tvs",
    "tw",
    "tz",
    "ua",
    "ubank",
    "ubs",
    "uconnect",
    "ug",
    "uk",
    "um",
    "unicom",
    "university",
    "uno",
    "uol",
    "ups",
    "us",
    "uy",
    "uz",
    "va",
    "vacations",
    "vana",
    "vanguard",
    "vc",
    "ve",
    "vegas",
    "ventures",
    "verisign",
    "vermögensberater",
    "vermögensberatung",
    "versicherung",
    "vet",
    "vg",
    "vi",
    "viajes",
    "video",
    "vig",
    "viking",
    "villas",
    "vin",
    "vip",
    "virgin",
    "visa",
    "vision",
    "vista",
    "vistaprint",
    "viva",
    "vivo",
    "vlaanderen",
    "vn",
    "vodka",
    "volkswagen",
    "volvo",
    "vote",
    "voting",
    "voto",
    "voyage",
    "vu",
    "vuelos",
    "wales",
    "walmart",
    "walter",
    "wang",
    "wanggou",
    "warman",
    "watch",
    "watches",
    "weather",
    "weatherchannel",
    "webcam",
    "weber",
    "website",
    "wed",
    "wedding",
    "weibo",
    "weir",
    "wf",
    "whoswho",
    "wien",
    "wiki",
    "williamhill",
    "win",
    "windows",
    "wine",
    "winners",
    "wme",
    "wolterskluwer",
    "woodside",
    "work",
    "works",
    "world",
    "wow",
    "ws",
    "wtc",
    "wtf",
    "xbox",
    "xerox",
    "xfinity",
    "xihuan",
    "xin",
    "xperia",
    "xxx",
    "xyz",
    "yachts",
    "yahoo",
    "yamaxun",
    "yandex",
    "ye",
    "yodobashi",
    "yoga",
    "yokohama",
    "you",
    "youtube",
    "yt",
    "yun",
    "za",
    "zappos",
    "zara",
    "zero",
    "zip",
    "zippo",
    "zm",
    "zone",
    "zuerich",
    "zw",
    "δοκιμή",
    "ελ",
    "ευ",
    "бг",
    "бел",
    "дети",
    "ею",
    "испытание",
    "католик",
    "ком",
    "мкд",
    "мон",
    "москва",
    "онлайн",
    "орг",
    "рус",
    "рф",
    "сайт",
    "срб",
    "укр",
    "қаз",
    "հայ",
    "טעסט",
    "ישראל",
    "קום",
    "آزمایشی",
    "إختبار",
    "ابوظبي",
    "اتصالات",
    "ارامكو",
    "الاردن",
    "البحرين",
    "الجزائر",
    "السعودية",
    "العليان",
    "المغرب",
    "امارات",
    "ایران",
    "بارت",
    "بازار",
    "بيتك",
    "بھارت",
    "تونس",
    "سودان",
    "سورية",
    "شبكة",
    "عراق",
    "عرب",
    "عمان",
    "فلسطين",
    "قطر",
    "كاثوليك",
    "كوم",
    "مصر",
    "مليسيا",
    "موبايلي",
    "موريتانيا",
    "موقع",
    "همراه",
    "پاكستان",
    "پاکستان",
    "ڀارت",
    "कॉम",
    "नेट",
    "परीक्षा",
    "भारत",
    "भारतम्",
    "भारोत",
    "संगठन",
    "বাংলা",
    "ভারত",
    "ভাৰত",
    "ਭਾਰਤ",
    "ભારત",
    "ଭାରତ",
    "இந்தியா",
    "இலங்கை",
    "சிங்கப்பூர்",
    "பரிட்சை",
    "భారత్",
    "ಭಾರತ",
    "ഭാരതം",
    "ලංකා",
    "คอม",
    "ไทย",
    "ລາວ",
    "გე",
    "みんな",
    "アマゾン",
    "クラウド",
    "グーグル",
    "コム",
    "ストア",
    "セール",
    "テスト",
    "ファッション",
    "ポイント",
    "世界",
    "中信",
    "中国",
    "中國",
    "中文网",
    "亚马逊",
    "企业",
    "佛山",
    "信息",
    "健康",
    "八卦",
    "公司",
    "公益",
    "台湾",
    "台灣",
    "商城",
    "商店",
    "商标",
    "嘉里",
    "嘉里大酒店",
    "在线",
    "大众汽车",
    "大拿",
    "天主教",
    "娱乐",
    "家電",
    "工行",
    "广东",
    "微博",
    "慈善",
    "我爱你",
    "手机",
    "手表",
    "招聘",
    "政务",
    "政府",
    "新加坡",
    "新闻",
    "时尚",
    "書籍",
    "机构",
    "测试",
    "淡马锡",
    "測試",
    "游戏",
    "澳門",
    "点看",
    "珠宝",
    "移动",
    "组织机构",
    "网址",
    "网店",
    "网站",
    "网络",
    "联通",
    "诺基亚",
    "谷歌",
    "购物",
    "通販",
    "集团",
    "電訊盈科",
    "飞利浦",
    "食品",
    "餐厅",
    "香格里拉",
    "香港",
    "닷넷",
    "닷컴",
    "삼성",
    "테스트",
    "한국",
]


text:
# Autogenerated wrapper script for LAMMPS_jll for i686-linux-gnu-libgfortran5-cxx03-mpi+mpitrampoline
export liblammps, lmp

using CompilerSupportLibraries_jll
using MPIABI
using MPItrampoline_jll
JLLWrappers.@generate_wrapper_header("LAMMPS")
JLLWrappers.@declare_library_product(liblammps, "liblammps.so.0")
JLLWrappers.@declare_executable_product(lmp)
function __init__()
    JLLWrappers.@generate_init_header(CompilerSupportLibraries_jll, MPIABI, MPItrampoline_jll)
    JLLWrappers.@init_library_product(
        liblammps,
        "lib/liblammps.so",
        RTLD_LAZY | RTLD_DEEPBIND,
    )

    JLLWrappers.@init_executable_product(
        lmp,
        "bin/lmp",
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
using Revise
using AutonomousMerging
using AutomotiveDrivingModels
using Random
using POMDPs
using POMDPSimulators
using DeepQLearning
using Flux
using BSON
using Reel
using RLInterface
using AutoViz
AutoViz.set_color_theme(OFFICETHEME)
include("scripts/make_gif.jl")

rng = MersenneTwister(1)

mdp = GenerativeMergingMDP(random_n_cars=true, min_cars=16,max_cars=16, traffic_speed = :mixed, driver_type=:binary, initial_ego_velocity=5.0,
                           observe_cooperation=true);
for i=2:mdp.max_cars+1
    mdp.driver_models[i] = CooperativeIDM();
end
# pomdp = FullyObservablePOMDP(mdp)
# up = MergingUpdater(mdp)
# bmdp = GenerativeBeliefMDP{typeof(pomdp), MergingUpdater, MergingBelief,Int64}(pomdp, up)

s0 = initialstate(mdp, rng)

svec = convert_s(Vector{Float64}, s0, mdp)

input_dims = length(svec)

model = Chain(Dense(input_dims, 64, relu), Dense(64, 32, relu), Dense(32, n_actions(mdp)))
# do not run if you just want to load a policy
# solver = DeepQLearningSolver(qnetwork = model,
#                       max_steps = 1_000_000,
#                       eps_fraction = 0.5,
#                       eps_end = 0.01,
#                       eval_freq = 10_000,
#                       save_freq = 10_000,
#                       target_update_freq = 5000,
#                       batch_size = 32,
#                       learning_rate = 1e-4,
#                       train_start = 10000,
#                       log_freq = 1000,
#                       num_ep_eval = 1000,
#                       double_q = true,
#                       dueling = false,
#                       prioritized_replay = true,
#                       verbose = true,
#                       rng = rng)

# policy = solve(solver, mdp)

# BSON.@save "policy_true.bson" policy

# BSON.@load joinpath(solver.logdir,"policy_true.bson") policy
BSON.@load "log15/qnetwork.bson" qnetwork
Flux.loadparams!(model, qnetwork)
policy = NNPolicy(mdp, model, collect(actions(mdp)), 1);

env = MDPEnvironment(mdp)
DeepQLearning.evaluation(solver.evaluation_policy,
                policy, env,
                solver.num_ep_eval,
                solver.max_episode_length,
                solver.verbose)

# policy = MaskedPolicy(policy)

for i=1:10
    s0 = initialstate(mdp, rng);
    hr = HistoryRecorder(rng = rng, max_steps=100);
    hist = simulate(hr, mdp, policy, s0);
    @show undiscounted_reward(hist)
    if undiscounted_reward(hist) > 0.0
        make_gif(hist, mdp, nothing, "out$i.gif")
    end
end

include("visualizer.jl");

i = 36
s = state_hist(hist)[i]
c = AutoViz.render(s.scene, mdp.env.roadway,  cam = StaticCamera(VecE2(-25.0, -10.0), 10.0),
                [MergingNeighborsOverlay(target_id=EGO_ID, env=mdp.env)],
                car_colors=get_car_type_colors(s0.scene, mdp.driver_models))

write_to_png(c, "snap-bis$i.png")

i = 36
collect(action_hist(hist))[i], state_hist(hist)[i].ego_info.acc, get_by_id(state_hist(hist)[i].scene, 1).state.v

make_gif(hist, mdp)

## run many simulations

function quick_evaluation(mdp::MDP, policy::Policy, rng::AbstractRNG, n_eval=1000)
    avg_r, avg_dr, c_rate, avg_steps, t_out = 0.0, 0.0, 0.0, 0.0, 0.0
    @showprogress for i=1:n_eval
        s0 = initialstate(mdp, rng)
        hr = HistoryRecorder(rng = rng, max_steps=100)
        hist = simulate(hr, mdp, policy, s0)
        avg_r += undiscounted_reward(hist)
        avg_dr += discounted_reward(hist)
        c_rate += undiscounted_reward(hist) <= -1
        t_out += n_steps(hist) >= hr.max_steps ? 1.0 : 0.0
        avg_steps += n_steps(hist)
    end
    avg_r /= n_eval
    avg_dr /= n_eval
    c_rate /= n_eval
    avg_steps /= n_eval
    t_out /= n_eval
    return avg_r, avg_dr, c_rate, avg_steps, t_out
end

avg_r, avg_dr, c_rate, avg_steps, t_out = quick_evaluation(bmdp, policy, rng, 100)

println("Collisions ", c_rate*100)
println("Avg steps ", avg_steps)
println("Time outs ", t_out*100)
println("avg disc reward ", avg_dr)
println("avg reward ", avg_r)

simlist = [Sim(mdp, policy, max_steps=200, rng=MersenneTwister(i)) for i=1:1000];

res = run_parallel(simlist) do sim, hist
    return [:steps=>n_steps(hist), :dreward=>discounted_reward(hist), :reward=>undiscounted_reward(hist)]
end

n_collisions = sum(res[:reward] .< 0.0)
avg_steps = mean(res[:steps])
avg_dreward = mean(res[:dreward])
avg_reward = mean(res[:reward])
collision_ind = findfirst(res[:reward] .< 0.0)
rng = MersenneTwister(collision_ind)

s0 = initialstate(mdp, rng)
hr = HistoryRecorder(rng = rng, max_steps=100)
hist = simulate(hr, mdp, policy, s0)
n_steps(hist)
undiscounted_reward(hist)

include("visualizer.jl");

frames = Frames(MIME("image/png"), fps=4);
for step in 1:n_steps(hist)
    s = state_hist(hist)[step+1]
    a = collect(action_hist(hist))[step]
    f = AutoViz.render(s.scene, mdp.env.roadway,
          SceneOverlay[
                       IDOverlay(),
                       MergingNeighborsOverlay(target_id=EGO_ID, env=mdp.env),
                       DistToMergeOverlay(target_id=EGO_ID, env=mdp.env),
                       MaskingOverlay(mdp=mdp)
                       #    NeighborsOverlay(EGO_ID),
                    #    CarFollowingStatsOverlay(EGO_ID),
                        ],
          cam=CarFollowCamera(EGO_ID, 10.0),
          car_colors = Dict{Int64, Colorant}(1 => COLOR_CAR_EGO))
    push!(frames, f)
end

write("out.gif", frames)

## Env version

obs = reset!(env)
act = action(policy, op)
vals = actionvalues(policy, op)
op, rew, done, info = step!(env, act)

s = env.state

action(policy, s)
actionvalues(policy, s)

using ProgressMeter
avg_r = 0.0
@showprogress for i=1:1000
    global avg_r
    s0 = initialstate(mdp, rng)
    hr = HistoryRecorder(rng = rng, max_steps=100)
    hist = simulate(hr, mdp, policy, s0)
    avg_r += undiscounted_reward(hist)
end

avg_r/1000


text:
include(joinpath(@__DIR__, "main.jl"))

# You can run `Pkg.test("MiniLoggers", test_args = ["foo", "bar"])` or just
# `Pkg.test(test_args = ["foo", "bar"])` to select only specific tests. If no `test_args`
# is given or you are running usual `> ] test` command, then all tests are executed.
if isempty(ARGS)
    MiniLoggersTest.runtests()
else
    MiniLoggersTest.runtests(ARGS)
end


text:
@testset "Chunk Scopes" begin
    wid1, wid2 = addprocs(2, exeflags=["-t 2"])
    @everywhere [wid1,wid2] using Dagger
    Dagger.addprocs!(Dagger.Sch.eager_context(), [wid1,wid2])
    fetch(Dagger.@spawn 1+1) # Force scheduler to pick up new workers

    # Tests run locally
    @test Dagger.system_uuid(myid()) == Dagger.system_uuid(wid2)
    @test Dagger.system_uuid(wid1) == Dagger.system_uuid(wid2)

    # Test different nodes by creating fake UUIDs
    wid1_uuid, wid2_uuid = uuid4(), uuid4()
    @everywhere Dagger.SYSTEM_UUIDS[$wid1] = $wid1_uuid
    @everywhere Dagger.SYSTEM_UUIDS[$wid2] = $wid2_uuid

    # Emulate running "remotely"
    @test Dagger.system_uuid(wid1) == wid1_uuid
    @test Dagger.system_uuid(wid2) == wid2_uuid
    @test Dagger.system_uuid(myid()) != Dagger.system_uuid(wid2)
    @test Dagger.system_uuid(wid1) != Dagger.system_uuid(wid2)

    ns1, ns2 = NodeScope(wid1_uuid), NodeScope(wid2_uuid)
    ns1_ch = Dagger.tochunk(nothing, OSProc(), ns1)
    ns2_ch = Dagger.tochunk(nothing, OSProc(), ns2)

    ps1, ps2 = ProcessScope(wid1), ProcessScope(wid2)
    ps1_ch = Dagger.tochunk(nothing, OSProc(), ps1)
    ps2_ch = Dagger.tochunk(nothing, OSProc(), ps2)

    es1, es2 = ExactScope(Dagger.ThreadProc(wid1, 1)), ExactScope(Dagger.ThreadProc(wid2, 2))
    es1_ch = Dagger.tochunk(nothing, OSProc(), es1)
    es2_ch = Dagger.tochunk(nothing, OSProc(), es2)

    @testset "Node Scope" begin
        @everywhere node_scope_test(ch...) = Dagger.system_uuid()

        # One node
        ts = fetch.([Dagger.@spawn node_scope_test(isodd(i) ? ns1_ch : ns2_ch) for i in 1:20])
        @test all(x->x==wid1_uuid, ts[1:2:20])
        @test all(x->x==wid2_uuid, ts[2:2:20])

        # Same node
        t = fetch(Dagger.@spawn node_scope_test(ns1_ch, ns1_ch))
        @test t == wid1_uuid

        # Different nodes
        for (ch1, ch2) in [(ns1_ch, ns2_ch), (ns2_ch, ns1_ch)]
            @test_throws_unwrap Dagger.ThunkFailedException ex.reason<"Scopes are not compatible:" fetch(Dagger.@spawn ch1 + ch2)
        end
    end
    @testset "Process Scope" begin
        @everywhere process_scope_test(ch...) = myid()
        @test ps1.parent.uuid == Dagger.system_uuid(wid1)
        @test ps2.parent.uuid == Dagger.system_uuid(wid2)

        # One process
        ts = fetch.([Dagger.@spawn process_scope_test(isodd(i) ? ps1_ch : ps2_ch) for i in 1:20])
        @test all(x->x==wid1, ts[1:2:20])
        @test all(x->x==wid2, ts[2:2:20])

        # Same process
        t = fetch(Dagger.@spawn process_scope_test(ps1_ch, ps1_ch))
        @test t == wid1

        # Different process
        for (ch1, ch2) in [(ps1_ch, ps2_ch), (ps2_ch, ps1_ch)]
            @test_throws_unwrap Dagger.ThunkFailedException ex.reason<"Scopes are not compatible:" fetch(Dagger.@spawn ch1 + ch2)
        end

        # Same process and node
        @test fetch(Dagger.@spawn process_scope_test(ps1_ch, ns1_ch)) == wid1

        # Different process and node
        for (ch1, ch2) in [(ps1_ch, ns2_ch), (ns2_ch, ps1_ch)]
            @test_throws_unwrap Dagger.ThunkFailedException ex.reason<"Scopes are not compatible:" fetch(Dagger.@spawn ch1 + ch2)
        end
    end
    @testset "Exact Scope" begin
        @everywhere exact_scope_test(ch...) = Dagger.thunk_processor()
        @test es1.parent.wid == wid1
        @test es1.parent.parent.uuid == Dagger.system_uuid(wid1)
        @test es2.parent.wid == wid2
        @test es2.parent.parent.uuid == Dagger.system_uuid(wid2)

        # One process
        ts = fetch.([Dagger.@spawn exact_scope_test(isodd(i) ? es1_ch : es2_ch) for i in 1:20])
        @test all(x->x.owner==wid1, ts[1:2:20])
        @test all(x->x.owner==wid2&&x.tid==2, ts[2:2:20])

        # Same process
        t = fetch(Dagger.@spawn exact_scope_test(es1_ch, es1_ch))
        @test t.owner == wid1 && t.tid == 1

        # Different process, different processor
        for (ch1, ch2) in [(es1_ch, es2_ch), (es2_ch, es1_ch)]
            @test_throws_unwrap Dagger.ThunkFailedException ex.reason<"Scopes are not compatible:" fetch(Dagger.@spawn ch1 + ch2)
        end

        # Same process, different processor
        es1_2 = ExactScope(Dagger.ThreadProc(wid1, 2))
        es1_2_ch = Dagger.tochunk(nothing, OSProc(), es1_2)
        for (ch1, ch2) in [(es1_ch, es1_2_ch), (es1_2_ch, es1_ch)]
            @test_throws_unwrap Dagger.ThunkFailedException ex.reason<"Scopes are not compatible:" fetch(Dagger.@spawn ch1 + ch2)
        end
    end
    @testset "Union Scope" begin
        # One inner scope
        us_es1_ch = Dagger.tochunk(nothing, OSProc(), UnionScope(es1))
        @test fetch(Dagger.@spawn exact_scope_test(us_es1_ch)) == es1.processor

        # Multiple redundant inner scopes
        us_es1_multi_ch = Dagger.tochunk(nothing, OSProc(), UnionScope(es1, es1))
        @test fetch(Dagger.@spawn exact_scope_test(us_es1_multi_ch)) == es1.processor

        # No inner scopes
        @test_throws ArgumentError UnionScope()

        # Same inner scope
        @test fetch(Dagger.@spawn exact_scope_test(us_es1_ch, us_es1_ch)) == es1.processor

        # Extra unmatched inner scope
        us_es1_es2_ch = Dagger.tochunk(nothing, OSProc(), UnionScope(es1, es2))
        for (ch1, ch2) in [(us_es1_ch, us_es1_es2_ch), (us_es1_es2_ch, us_es1_ch)]
            @test fetch(Dagger.@spawn exact_scope_test(ch1, ch2)) == es1.processor
        end
        us_res = Dagger.constrain(UnionScope(es1, es2), UnionScope(es1))
        @test us_res isa UnionScope
        @test es1 in us_res.scopes
        @test !(es2 in us_res.scopes)
    end
    # TODO: Test scope propagation

    rmprocs([wid1, wid2])
end


text:
@testset "Vortex Sheets" begin
    @testset "Sheet construction" begin
        N = 100
        zs = rand(ComplexF64, N)
        Γs = accumulate(+, rand(N))
        δ = rand()

        sheet = Vortex.Sheet(zs, Γs, δ)

        @test circulation(sheet) ≈ circulation(sheet.blobs)
    end

    @testset "Sheet induced velocities" begin
        N = 100
        zs = rand(ComplexF64, N)
        Γs = accumulate(+, rand(N))
        δ = rand()
        sheet = Vortex.Sheet(zs, Γs, δ)

        ws = allocate_velocity(sheet)
        wb = allocate_velocity(sheet.blobs)

        self_induce_velocity!(ws, sheet, 0)
        for (i, t) in enumerate(sheet.blobs), s in sheet.blobs
            wb[i] += induce_velocity(t, s, 0)
        end
        @test wb ≈ ws
        @test wb ≈ induce_velocity(sheet, sheet, 0)

        sheet₊ = Vortex.Sheet(Vector{Vortex.Blob}(undef, 10), rand(10), 0.0)
        Δt = 1e-2
        advect!(sheet₊, sheet, ws, Δt)
        advect!(sheet, sheet, ws, Δt)

        @test sheet₊.Ss ==  sheet.Ss
        @test !(sheet₊.Ss === sheet.Ss)

        @test sheet₊.blobs == sheet.blobs
        @test !(sheet₊.blobs === sheet.blobs)

        @test sheet₊.δ  ==  sheet.δ
    end

    @testset "Sheet surgery" begin
        N = 100
        zs = rand(ComplexF64, N)
        Γs = accumulate(+, rand(N))
        δ = 0.05
        sheet = Vortex.Sheet(zs, Γs, δ)

        truncate_n = 50
        ΣΓ = circulation(sheet)
        ΔΓ₀ = Γs[truncate_n] - Γs[1]
        ΔΓ  = Sheets.truncate!(sheet, truncate_n)
        @test ΔΓ₀ ≈ ΔΓ

        @test Sheets.compute_trapezoidal_weights(sheet.Ss) ≈ circulation.(sheet.blobs)
        @test ΔΓ + circulation(sheet) ≈ ΣΓ

        Γ = circulation(sheet)
        sheet₊ = Sheets.split!(sheet, rand(3:length(sheet)-3))
        @test Γ ≈ sum(circulation, (sheet, sheet₊))

        @test Sheets.compute_trapezoidal_weights(sheet.Ss) ≈ circulation.(sheet.blobs)
        @test Sheets.compute_trapezoidal_weights(sheet₊.Ss) ≈ circulation.(sheet₊.blobs)

        N = 200
        θ = range(π, 0, length = N)
        zs = complex.(cos.(θ))
        Γs = sin.(θ)
        Sheets.redistribute_points!(sheet, zs, Γs)
        fill!(Γs, 0.0)
        @test sheet.Ss != Γs
        @test Sheets.compute_trapezoidal_weights(sheet.Ss) ≈ getfield.(sheet.blobs, :S)
        @test Elements.position.(sheet.blobs) == getfield.(sheet.blobs, :z)
        @test sheet.zs == Elements.position.(sheet.blobs)

        Sheets.remesh!(sheet, 0.005)
        @test length(sheet) == 400
        @test sheet.zs ≈ range(-1, 1, length = 400)
        @test norm(sheet.Ss .- sqrt.(1 .- range(-1,1, length=400).^2)) ≤ 1e-3

        θ = range(π, 0, length = N)
        zs = complex.(cos.(θ))
        Γs = sin.(θ)
        Sheets.redistribute_points!(sheet, zs, Γs)
        sheet₁ = deepcopy(sheet)
        sheet₂ = deepcopy(sheet)

        @test_logs (:warn, "Cannot remesh, sheet length smaller than nominal spacing") (:warn, "Filter not applied, total sheet length smaller than nominal spacing") Sheets.filter!(sheet₁, 3.0, 0.03)
        @test sheet₁.zs == sheet₂.zs
        @test sheet₁.Ss == sheet₂.Ss
        @test sheet₁.blobs == sheet₂.blobs

        @test_logs (:warn, "Cannot remesh, sheet length smaller than nominal spacing") Sheets.remesh!(sheet₂, 3.0)
        @test sheet₁.zs == sheet₂.zs
        @test sheet₁.Ss == sheet₂.Ss
        @test sheet₁.blobs == sheet₂.blobs

        Sheets.remesh!(sheet₂, 0.01)
        Sheets.filter_position!(sheet₂, 0.03)

        property = copy(sheet₁.Ss)
        Sheets.filter!(sheet₁, 0.01, 0.03, (property,))

        @test sheet₁.zs == sheet₂.zs
        @test sheet₁.Ss == sheet₂.Ss
        @test sheet₁.Ss == property
    end
end