text:
function LongitudeCrossingDetector(arg0::OneAxisEllipsoid, arg1::jdouble)
    return LongitudeCrossingDetector((OneAxisEllipsoid, jdouble), arg0, arg1)
end

function LongitudeCrossingDetector(arg0::jdouble, arg1::jdouble, arg2::OneAxisEllipsoid, arg3::jdouble)
    return LongitudeCrossingDetector((jdouble, jdouble, OneAxisEllipsoid, jdouble), arg0, arg1, arg2, arg3)
end

function g(obj::LongitudeCrossingDetector, arg0::SpacecraftState)
    return jcall(obj, "g", jdouble, (SpacecraftState,), arg0)
end

function get_body(obj::LongitudeCrossingDetector)
    return jcall(obj, "getBody", OneAxisEllipsoid, ())
end

function get_longitude(obj::LongitudeCrossingDetector)
    return jcall(obj, "getLongitude", jdouble, ())
end


text:
include("termbox_structs.jl")
#=  Key constants. See also struct tb_event's key field.
 *
 * These are a safe subset of terminfo keys, which exist on all popular
 * terminals. Termbox uses only them to stay truly portable.
  =#
export TB_KEY_F1, TB_KEY_F2, TB_KEY_F3, TB_KEY_F4, TB_KEY_F5, TB_KEY_F6, TB_KEY_F7, TB_KEY_F8, TB_KEY_F9, TB_KEY_F10, TB_KEY_F11, TB_KEY_F12
export TB_KEY_INSERT, TB_KEY_DELETE, TB_KEY_HOME, TB_KEY_END, TB_KEY_PGUP, TB_KEY_PGDN
export TB_KEY_ARROW_UP, TB_KEY_ARROW_DOWN, TB_KEY_ARROW_LEFT, TB_KEY_ARROW_RIGHT
export TB_KEY_MOUSE_LEFT, TB_KEY_MOUSE_RIGHT, TB_KEY_MOUSE_MIDDLE
const TB_KEY_F1 =            (0xFFFF-0)
const TB_KEY_F2 =            (0xFFFF-1)
const TB_KEY_F3 =            (0xFFFF-2)
const TB_KEY_F4 =            (0xFFFF-3)
const TB_KEY_F5 =            (0xFFFF-4)
const TB_KEY_F6 =            (0xFFFF-5)
const TB_KEY_F7 =            (0xFFFF-6)
const TB_KEY_F8 =            (0xFFFF-7)
const TB_KEY_F9 =            (0xFFFF-8)
const TB_KEY_F10 =           (0xFFFF-9)
const TB_KEY_F11 =           (0xFFFF-10)
const TB_KEY_F12 =           (0xFFFF-11)
const TB_KEY_INSERT =        (0xFFFF-12)
const TB_KEY_DELETE =        (0xFFFF-13)
const TB_KEY_HOME =          (0xFFFF-14)
const TB_KEY_END =           (0xFFFF-15)
const TB_KEY_PGUP =          (0xFFFF-16)
const TB_KEY_PGDN =          (0xFFFF-17)
const TB_KEY_ARROW_UP =      (0xFFFF-18)
const TB_KEY_ARROW_DOWN =    (0xFFFF-19)
const TB_KEY_ARROW_LEFT =    (0xFFFF-20)
const TB_KEY_ARROW_RIGHT =   (0xFFFF-21)
const TB_KEY_MOUSE_LEFT =    (0xFFFF-22)
const TB_KEY_MOUSE_RIGHT =   (0xFFFF-23)
const TB_KEY_MOUSE_MIDDLE =  (0xFFFF-24)

#=  These are all ASCII code points below SPACE character and a BACKSPACE key.  =#
export TB_KEY_CTRL_TILDE, TB_KEY_CTRL_2, TB_KEY_CTRL_A, TB_KEY_CTRL_B, TB_KEY_CTRL_C, TB_KEY_CTRL_D, TB_KEY_CTRL_E, TB_KEY_CTRL_F, TB_KEY_CTRL_G, TB_KEY_BACKSPACE, TB_KEY_CTRL_H, TB_KEY_TAB
const TB_KEY_CTRL_TILDE =        0x00
const TB_KEY_CTRL_2 =            0x00 #=  clash with 'CTRL_TILDE'  =#
const TB_KEY_CTRL_A =            0x01
const TB_KEY_CTRL_B =            0x02
const TB_KEY_CTRL_C =            0x03
const TB_KEY_CTRL_D =            0x04
const TB_KEY_CTRL_E =            0x05
const TB_KEY_CTRL_F =            0x06
const TB_KEY_CTRL_G =            0x07
const TB_KEY_BACKSPACE =         0x08
const TB_KEY_CTRL_H =            0x08 #=  clash with 'CTRL_BACKSPACE'  =#
const TB_KEY_TAB =               0x09
export TB_KEY_CTRL_I, TB_KEY_CTRL_J, TB_KEY_CTRL_K, TB_KEY_CTRL_L, TB_KEY_ENTER, TB_KEY_CTRL_M, TB_KEY_CTRL_N, TB_KEY_CTRL_O, TB_KEY_CTRL_P, TB_KEY_CTRL_Q, TB_KEY_CTRL_R, TB_KEY_CTRL_S, TB_KEY_CTRL_T, TB_KEY_CTRL_U, TB_KEY_CTRL_V, TB_KEY_CTRL_W, TB_KEY_CTRL_X, TB_KEY_CTRL_Y, TB_KEY_CTRL_Z
const TB_KEY_CTRL_I =            0x09 #=  clash with 'TAB'  =#
const TB_KEY_CTRL_J =            0x0A
const TB_KEY_CTRL_K =            0x0B
const TB_KEY_CTRL_L =            0x0C
const TB_KEY_ENTER =             0x0D
const TB_KEY_CTRL_M =            0x0D #=  clash with 'ENTER'  =#
const TB_KEY_CTRL_N =            0x0E
const TB_KEY_CTRL_O =            0x0F
const TB_KEY_CTRL_P =            0x10
const TB_KEY_CTRL_Q =            0x11
const TB_KEY_CTRL_R =            0x12
const TB_KEY_CTRL_S =            0x13
const TB_KEY_CTRL_T =            0x14
const TB_KEY_CTRL_U =            0x15
const TB_KEY_CTRL_V =            0x16
const TB_KEY_CTRL_W =            0x17
const TB_KEY_CTRL_X =            0x18
const TB_KEY_CTRL_Y =            0x19
const TB_KEY_CTRL_Z =            0x1A
export TB_KEY_ESC, TB_KEY_CTRL_LSQ_BRACKET, TB_KEY_CTRL_3, TB_KEY_CTRL_4, TB_KEY_CTRL_BACKSLASH, TB_KEY_CTRL_5, TB_KEY_CTRL_RSQ_BRACKET, TB_KEY_CTRL_6, TB_KEY_CTRL_7, TB_KEY_CTRL_SLASH, TB_KEY_CTRL_UNDERSCORE, TB_KEY_SPACE, TB_KEY_BACKSPACE2, TB_KEY_CTRL_8
const TB_KEY_ESC =               0x1B
const TB_KEY_CTRL_LSQ_BRACKET =  0x1B #=  clash with 'ESC'  =#
const TB_KEY_CTRL_3 =            0x1B #=  clash with 'ESC'  =#
const TB_KEY_CTRL_4 =            0x1C
const TB_KEY_CTRL_BACKSLASH =    0x1C #=  clash with 'CTRL_4'  =#
const TB_KEY_CTRL_5 =            0x1D
const TB_KEY_CTRL_RSQ_BRACKET =  0x1D #=  clash with 'CTRL_5'  =#
const TB_KEY_CTRL_6 =            0x1E
const TB_KEY_CTRL_7 =            0x1F
const TB_KEY_CTRL_SLASH =        0x1F #=  clash with 'CTRL_7'  =#
const TB_KEY_CTRL_UNDERSCORE =   0x1F #=  clash with 'CTRL_7'  =#
const TB_KEY_SPACE =             0x20
const TB_KEY_BACKSPACE2 =        0x7F
const TB_KEY_CTRL_8 =            0x7F #=  clash with 'DELETE'  =#

#=  These are non-existing ones.
 *
 * const TB_KEY_CTRL_1 clash with '1'
 * const TB_KEY_CTRL_9 clash with '9'
 * const TB_KEY_CTRL_0 clash with '0'
  =#

#=  Currently there is only one modifier. See also struct tb_event's mod
 * field.
  =#
const TB_MOD_ALT =  0x01

#=  Colors (see struct tb_cell's fg and bg fields).  =#
export TB_DEFAULT, TB_BLACK, TB_RED, TB_GREEN, TB_YELLOW, TB_BLUE, TB_MAGENTA, TB_CYAN, TB_WHITE
const TB_DEFAULT =  0x00
const TB_BLACK =    0x01
const TB_RED =      0x02
const TB_GREEN =    0x03
const TB_YELLOW =   0x04
const TB_BLUE =     0x05
const TB_MAGENTA =  0x06
const TB_CYAN =     0x07
const TB_WHITE =    0x08
export TB_COLORS
const TB_COLORS = [TB_DEFAULT,
                   TB_BLACK,
                   TB_RED,
                   TB_GREEN,
                   TB_YELLOW,
                   TB_BLUE,
                   TB_MAGENTA,
                   TB_CYAN,
                   TB_WHITE
                   ]
#=  Attributes, it is possible to use multiple attributes by combining them
 * using bitwise OR ('|'). Although, colors cannot be combined. But you can
 * combine attributes and a single color. See also struct tb_cell's fg and bg
 * fields.
  =#
export TB_BOLD, TB_UNDERLINE, TB_REVERSE
const TB_BOLD =       0x0100
const TB_UNDERLINE =  0x0200
const TB_REVERSE =    0x0400
const TB_ATTR = [0x0, TB_BOLD, TB_UNDERLINE, TB_REVERSE, TB_BOLD | TB_UNDERLINE]

export TB_EVENT_KEY, TB_EVENT_RESIZE, TB_EVENT_MOUSE
const TB_EVENT_KEY =     1
const TB_EVENT_RESIZE =  2
const TB_EVENT_MOUSE =   3

#=  Error codes returned by tb_init(). All of them are self-explanatory, except
 * the pipe trap error. Termbox uses unix pipes in order to deliver a message
 * from a signal handler (SIGWINCH) to the main event reading loop. Honestly in
 * most cases you should just check the returned code as < 0.
  =#
const TB_EUNSUPPORTED_TERMINAL = -1
const TB_EFAILED_TO_OPEN_TTY =   -2
const TB_EPIPE_TRAP_ERROR =      -3

#=  Initializes the termbox library. This function should be called before any
 * other functions. After successful initialization, the library must be
 * finalized using the tb_shutdown() function.
  =#
export tb_init, tb_shutdown
tb_init() = ccall((:tb_init, libtermbox), Cint,(),)
tb_shutdown() = ccall((:tb_shutdown, libtermbox), Nothing,(),)

#=  Returns the size of the internal back buffer (which is the same as
 * terminal's window size in characters). The internal buffer can be resized
 * after tb_clear() or tb_present() function calls. Both dimensions have an
 * unspecified negative value when called before tb_init() or after
 * tb_shutdown().
  =#
export tb_width, tb_height
tb_width() = ccall((:tb_width, libtermbox), Cint,(),)
tb_height() = ccall((:tb_height, libtermbox), Cint,(),)

#=  Clears the internal back buffer using TB_DEFAULT color or the
 * color/attributes set by tb_set_clear_attributes() function.
  =#
export tb_clear, tb_set_clear_attributes
tb_clear() = ccall((:tb_clear, libtermbox), Nothing,(),)
tb_set_clear_attributes(fg, bg) = ccall((:tb_set_clear_attributes, libtermbox), Nothing,(Cushort, Cushort), fg, bg)

#=  Synchronizes the internal back buffer with the terminal.  =#
export tb_present
tb_present() = ccall((:tb_present, libtermbox), Nothing,(),)

export TB_HIDE_CURSOR
const TB_HIDE_CURSOR =  -1

#=  Sets the position of the cursor. Upper-left character is (0, 0). If you pass
 * TB_HIDE_CURSOR as both coordinates, then the cursor will be hidden. Cursor
 * is hidden by default.
  =#
export tb_set_cursor
tb_set_cursor(cx, cy) = ccall((:tb_set_cursor, libtermbox), Nothing,(Cint, Cint), cx, cy)

#=  Changes cell's parameters in the internal back buffer at the specified
 * position.
  =#
export tb_put_cell, tb_change_cell
tb_put_cell(x, y, cell) = ccall((:tb_put_cell, libtermbox), Nothing,(Cint, Cint, Ptr{tb_cell}), x, y, cell)
tb_change_cell(x, y, ch, fg = 0x0001, bg = 0x0000) = ccall((:tb_change_cell, libtermbox), Nothing,(Cint, Cint, Cuint, Cushort, Cushort), x, y, ch, fg, bg)

#=  Copies the buffer from 'cells' at the specified position, assuming the
 * buffer is a two-dimensional array of size ('w' x 'h'), represented as a
 * one-dimensional buffer containing lines of cells starting from the top.
 *
 * (DEPRECATED: use tb_cell_buffer() instead and copy memory on your own)
  =#
export tb_blit
tb_blit(x, y, w, h, cells) = ccall((:tb_blit, libtermbox), Nothing,(Cint, Cint, Cint, Cint, Ptr{tb_cell}), x, y, w, h, cells)

#=  Returns a pointer to internal cell back buffer. You can get its dimensions
 * using tb_width() and tb_height() functions. The pointer stays valid as long
 * as no tb_clear() and tb_present() calls are made. The buffer is
 * one-dimensional buffer containing lines of cells starting from the top.
  =#
export tb_cell_buffer
tb_cell_buffer() = ccall((:tb_cell_buffer, libtermbox), Ptr{tb_cell}, ())

export TB_INPUT_CURRENT, TB_INPUT_ESC, TB_INPUT_ALT, TB_INPUT_MOUSE
const TB_INPUT_CURRENT =  0 #=  000  =#
const TB_INPUT_ESC =      1 #=  001  =#
const TB_INPUT_ALT =      2 #=  010  =#
const TB_INPUT_MOUSE =    4 #=  100  =#

#=  Sets the termbox input mode. Termbox has two input modes:
 * 1. Esc input mode.
 *    When ESC sequence is in the buffer and it doesn't match any known
 *    ESC sequence  = > ESC means TB_KEY_ESC.
 * 2. Alt input mode.
 *    When ESC sequence is in the buffer and it doesn't match any known
 *    sequence  = > ESC enables TB_MOD_ALT modifier for the next keyboard event.
 *
 * If 'mode' is TB_INPUT_CURRENT, it returns the current input mode.
  =#
export tb_select_input_mode
tb_select_input_mode(mode) = ccall((:tb_select_input_mode, libtermbox), Cint,(Cint,), mode)

export TB_OUTPUT_CURRENT, TB_OUTPUT_NORMAL, TB_OUTPUT_256, TB_OUTPUT_216, TB_OUTPUT_GRAYSCALE
const TB_OUTPUT_CURRENT =    0
const TB_OUTPUT_NORMAL =     1
const TB_OUTPUT_256 =        2
const TB_OUTPUT_216 =        3
const TB_OUTPUT_GRAYSCALE =  4

#=  Sets the termbox output mode. Termbox has three output options:
 * 1. TB_OUTPUT_NORMAL      = > [1..8]
 *    This mode provides 8 different colors:
 *      black, red, green, yellow, blue, magenta, cyan, white
 *    Shortcut: TB_BLACK, TB_RED, ...
 *    Attributes: TB_BOLD, TB_UNDERLINE, TB_REVERSE
 *
 *    Example usage:
 *        tb_change_cell(x, y, '@', TB_BLACK | TB_BOLD, TB_RED);
 *
 * 2. TB_OUTPUT_256         = > [0..256]
 *    In this mode you can leverage the 256 terminal mode:
 *    0x00 - 0x07: the 8 colors as in TB_OUTPUT_NORMAL
 *    0x08 - 0x0f: TB_* | TB_BOLD
 *    0x10 - 0xe7: 216 different colors
 *    0xe8 - 0xff: 24 different shades of grey
 *
 *    Example usage:
 *        tb_change_cell(x, y, '@', 184, 240);
 *        tb_change_cell(x, y, '@', 0xb8, 0xf0);
 *
 * 2. TB_OUTPUT_216         = > [0..216]
 *    This mode supports the 3rd range of the 256 mode only.
 *    But you don't need to provide an offset.
 *
 * 3. TB_OUTPUT_GRAYSCALE   = > [0..23]
 *    This mode supports the 4th range of the 256 mode only.
 *    But you dont need to provide an offset.
 *
 * Execute build/src/demo/output to see its impact on your terminal.
 *
 * If 'mode' is TB_OUTPUT_CURRENT, it returns the current output mode.
  =#
export tb_select_output_mode
tb_select_output_mode(mode) = ccall((:tb_select_output_mode, libtermbox), Cint,(Cint,), mode)

#=  Wait for an event up to 'timeout' milliseconds and fill the 'event'
 * structure with it, when the event is available. Returns the type of the
 * event (one of TB_EVENT_* constants) or -1 if there was an error or 0 in case
 * there were no event during 'timeout' period.
  =#
export tb_peek_event
tb_peek_event(event, timeout = 0) = ccall((:tb_peek_event, libtermbox), Cint,(Ref{tb_event},Cint), event, timeout)

#=  Wait for an event forever and fill the 'event' structure with it, when the
 * event is available. Returns the type of the event (one of TB_EVENT_*
 * constants) or -1 if there was an error.
  =#
export tb_poll_event
tb_poll_event(event) = ccall((:tb_poll_event, libtermbox), Cint,(Ref{tb_event},), event)

#=  Utility utf8 functions.  =#
const TB_EOF =  -1
tb_utf8_char_length(c) = ccall((:tb_utf8_char_length, libtermbox), Cint,(Cchar,), c)
# SO_IMPORT int tb_utf8_char_length(char c);
tb_utf8_char_to_unicode(out, c) = ccall((:tb_utf8_char_to_unicode, libtermbox), Cint,(Ptr{Cuint}, Ptr{Cchar}), out, c)
# SO_IMPORT int tb_utf8_char_to_unicode(uint32_t *out, const char *c);
tb_utf8_unicode_to_char(out, c) = ccall((:tb_utf8_unicode_to_char, libtermbox), Cint,(Ptr{Cchar}, Cuint), out, c)
# SO_IMPORT int tb_utf8_unicode_to_char(char *out, uint32_t c);

ext: jl


text:
#!/usr/bin/env julia
include("sossltv.jl")
push!(PGFPlotsX.CUSTOM_PREAMBLE, raw"\usepackage{fontspec}")
push!(PGFPlotsX.CUSTOM_PREAMBLE, raw"\setmainfont{Asana-Math}")
s = sosframe("data/Statistikdatabasen_2020-07-28 11 46 15.csv")
pgfsave("../../images/infl_se_reg_kv65_98_18.svg",
    sexplot(s, "kvinnor"))
pgfsave("../../images/infl_se_reg_m65_98_18.svg",
    sexplot(s, "män"))

max_stars_repo_name: klpn/static-dust

max_issues_repo_name: klpn/static-dust

max_forks_repo_name: klpn/static-dust


text: stairsin20(s) = 20 * sum(Iterators.flatten(s))

max_stars_repo_name: UlrichBerntien/Codewars-Katas

max_issues_repo_name: UlrichBerntien/Codewars-Katas

max_forks_repo_name: UlrichBerntien/Codewars-Katas


text:
using MannKendall
using Test
# NoTrendData = ones(360)*rand(Int, 1)
TrendData = 1:100;
@testset "MannKendall.jl" begin
    # Write your tests here.
    TrendRes = mk_original_test(TrendData);

    @test TrendRes.trend == "increasing";
    @test TrendRes.h == true;
    @test TrendRes.p == 0.0;
    @test TrendRes.z == 14.73869998208331;
    @test TrendRes.τ == 1.0;
    @test TrendRes.s == 4950;
    @test TrendRes.var_s ==112750.0;

end


text:
# ---
# jupyter:
#   jupytext:
#     formats: ipynb,jl:hydrogen
#     text_representation:
#       extension: .jl
#       format_name: hydrogen
#       format_version: '1.3'
#       jupytext_version: 1.11.2
#   kernelspec:
#     display_name: Julia 1.6.2
#     language: julia
#     name: julia-1.6
# ---

# %% [markdown]
# * https://discourse.julialang.org/t/how-to-save-logging-output-to-a-log-file/14004/11
# * https://github.com/JuliaLogging/LoggingExtras.jl

# %%
#using Logging
using LoggingExtras

# %%
io = open("a.txt", "w+")
logger = SimpleLogger(io)
with_logger(logger) do
    @info(" here is some context specific logging with SimpleLogger")
end
read("a.txt", String) |> print

# %%
flush(io)
read("a.txt", String) |> print

# %%
close(io)

# %%
io = open("b.txt", "w+")
logger = FileLogger(io)
with_logger(logger) do
    @info(" here is some context specific logging with FileLogger")
end
read("a.txt", String) |> print

# %%
close(io)

# %%
?FileLogger

# %%

max_stars_repo_name: genkuroki/public

max_issues_repo_name: genkuroki/public

max_forks_repo_name: genkuroki/public


text:
function dehydrated_value(value)
    return fix_parameters(Dict("_" => value), 1, supports_bytes=true)["_"]
end

@testset "ValueDehydrationTestCase" begin

    @testset "test_should_allow_nothing" begin
        @test dehydrated_value(nothing) == nothing
    end

    @testset "test_should_allow_boolean" begin
        @test dehydrated_value(true) == true
        @test dehydrated_value(false) == false
    end

    @testset "test_should_allow_integer" begin
        @test dehydrated_value(0) == 0
        @test dehydrated_value(0x7f) == 0x7f
        @test dehydrated_value(0x7FFF) == 0x7FFF
        @test dehydrated_value(0x7FFFFFFF) == 0x7FFFFFFF
        @test dehydrated_value(0x7FFFFFFFFFFFFFFF) == 0x7FFFFFFFFFFFFFFF
    end

    @testset "test_should_disallow_oversized_integer" begin
        @test_throws ErrorException dehydrated_value(0x10000000000000000)
        @test_throws ErrorException dehydrated_value(-0x10000000000000000)
    end

    @testset "test_should_allow_float" begin
        @test dehydrated_value(0.0) == 0.0
        @test dehydrated_value(3.1415926) == 3.1415926
    end

    @testset "test_should_allow_string" begin
        @test dehydrated_value("") == ""
        @test dehydrated_value("hello, world") == "hello, world"
    end

    @testset "test_should_allow_bytes" begin
        @test dehydrated_value(UInt8[]) == UInt8[]
        @test dehydrated_value(UInt8[1,2,3]) == UInt8[1,2,3]
    end

    @testset "test_should_allow_list" begin
        @test dehydrated_value([]) == []
        @test dehydrated_value([1,2,3]) == [1,2,3]
    end

    @testset "test_should_allow_dict" begin
        @test dehydrated_value(Dict()) == Dict()
        @test dehydrated_value(Dict("one"=>1, "two"=>2, "three"=>3)) == Dict("one"=>1, "two"=>2, "three"=>3)
        @test dehydrated_value(Dict("list"=>[1,2,3,[4,5,6]], "dict"=>Dict("a"=>1, "b"=>2))) == Dict("list"=>[1,2,3,[4,5,6]], "dict"=>Dict("a"=>1, "b"=>2))
    end

end


text:
"""
    PathResult(result, returncode, startvalue, iterations, laststep, steps, trace)

Construct a result of `trackpath`.

## Fields
* `result::Vector{T}`
* `returncode::Symbol`: :Success or :MaxIterations or :Diverged
* `startvalue::Vector{T}`
* `iterations::Int`
* `laststep::S`: If :Success this is just `finish`
* `steps::Vector{S}`: Empty if `record_steps=false` (default)
* `trace::Vector{Vector{T}}`: Empty if `record_trace=false` (default)
"""
struct PathResult{T<:Number, S<:Number}
    result::Vector{T}
    returncode::Symbol

    startvalue::Vector{T}
    iterations::Int
    laststep::S
    steps::Vector{S}
    trace::Vector{Vector{T}}
end

"""
    ConvergentCluster(points, convergence_point, t)

Construct a convergent cluster at time `t` with points ``w_1, ..., w_c`` where ``c`` is the
winding number of the `convergence_point`.
See Chapter 15.6 in The Numerical solution of systems of polynomials arising in
engineering and science[^1] for more details.

[^1]: Sommese, Andrew J., and Charles W. Wampler II. The Numerical solution of systems of polynomials arising in engineering and science. World Scientific, 2005.
"""
struct ConvergentCluster{T<:Number}
    points::Vector{Vector{T}}
    convergence_point::Vector{T}
    t::Float64
end

function Base.show(io::IO, cluster::ConvergentCluster)
    println(io, typeof(cluster),":")
    println(io, "* cluster points: ", cluster.points)
    println(io, "* convergence_point: ", cluster.convergence_point)
    println(io, "* t: ", cluster.t)
end

"""
    CauchyEndgameResult(result, returncode, iterations, R, λ, trace, nullable_cluster)

Construct a result of a `cauchyendgame`.

## Fields
* `result::Vector{T}`
* `returncode::Symbol`: `:Success`, `:IllConditionedZone` (the path tracking failed)
or `:MachineEpsilon`: (`t` got smaller than machine epsilon)
* `iterations::Int`: How many iterations of the power series was done
* `R`: The radius when the endgame started
* `λ`: The factor of the geometric series ``λ^kR``
* `trace::Vector{Vector{T}}`: The points ``x(λ^kR)`` for `k=0,1,...,iterations`
* `convergent_cluster::Nullable{ConvergentCluster{T}}`: The convergent cluster of the endgame.
"""
struct CauchyEndgameResult{T<:Number}
    result::Vector{T}
    returncode::Symbol
    iterations::Int
    R::Float64
    λ::Float64
    trace::Vector{Vector{T}}
    steps::Vector{Float64}
    convergent_cluster::Nullable{ConvergentCluster{T}}
end

"""
    Result(solution, returncode, iterations, affine_solution, projective_solution, startvalue, steps, trace, nullable_cluster)

Construct a result of `solve` with an `AbstractPredictorCorrectorAlgorithm`.

## Fields
* `solution::Vector{T}`: This has the same length as startvalue
* `returncode::Symbol`: :Success, :MaxIterations, :Diverged or :AtInfinity
* `iterations::Int`
* `endgame_iterations::Int`
* `affine_solution::Vector{T}`
* `project_solution::Vector{T}`
* `startvalue::Vector{T}`
* `trace::Vector{Vector{T}}`: Empty if `record_trace=false` (default)
* `convergent_cluster::Nullable{ConvergentCluster{T}}`: The convergent cluster of the endgame.
"""
struct Result{T<:Number}
    solution::Vector{T}
    returncode::Symbol
    iterations::Int
    endgame_iterations::Int

    affine_solution::Vector{T}
    projective_solution::Vector{T}

    startvalue::Vector{T}
    #* `steps::Vector{S}`: Empty if `record_steps=false` (default)
    trace::Vector{Vector{T}}
    steps::Vector{Float64}

    convergent_cluster::Nullable{ConvergentCluster{T}}
end

function Base.show(io::IO, res::Result)
    println(io, typeof(res),":")
    println(io, "------------------------------")
    println(io, "* solution: ", res.solution)
    println(io, "* returncode: ", res.returncode)
    println(io, "------------------------------")
    println(io, "* iterations: ", res.iterations)
    println(io, "* endgame_iterations: ", res.endgame_iterations)
    println(io, "* affine_solution: ", res.affine_solution)
    println(io, "* projective_solution: ", res.projective_solution)
    println(io, "* startvalue: ", res.startvalue)
    println(io, "* steps: ", length(res.steps), " entries")
    println(io, "* trace: ", length(res.trace), " entries")
    println(io, "* convergent cluster: ", get(map(string, res.convergent_cluster), "---"))
end

function Base.show(io::IO, res::CauchyEndgameResult)
    println(io, typeof(res),":")
    println(io, "------------------------------")
    println(io, "* result: ", res.result)
    println(io, "* returncode: ", res.returncode)
    println(io, "------------------------------")
    println(io, "* iterations: ", res.iterations)
    println(io, "* R: ", res.R)
    println(io, "* λ: ", res.λ)
    println(io, "* trace: ", length(res.trace), " entries")
    println(io, "* convergent cluster: ", get(map(string, res.convergent_cluster), "---"))
end

function Base.show(io::IO, res::PathResult)
    println(io, typeof(res),":")
    println(io, "------------------------------")
    println(io, "* result: ", res.result)
    println(io, "* returncode: ", res.returncode)
    println(io, "------------------------------")
    println(io, "* startvalue: ", res.startvalue)
    println(io, "* iterations: ", res.iterations)
    println(io, "* laststep: ", res.laststep)
    println(io, "* steps: ", length(res.steps), " entries")
    println(io, "* trace: ", length(res.trace), " entries")
end

"""
    nosuccess(result)

Checks whether the returncode is something else than `:Success`
"""
nosuccess(result::PathResult) = result.returncode != :Success
nosuccess(result::Result) = result.returncode != :Success
nosuccess(result::CauchyEndgameResult) = result.returncode != :Success


text:
# # Usage example:
# npts = 10
# rho = 0.9
# sig = 0.01
# gridpts, transition = rouwenhorst(npts, rho, sig)

function RouwenNormalize!(A)
    A[2:end-1, :] ./= 2
    nothing
end

function rouwenupdate!(Πold, Πnew, p, q)
    Nold = size(Πold, 1)
    Πnew[1:Nold, 1:Nold] = p*Πold
    Πnew[1:Nold, 2:(Nold+1)] .+= (1-p)*Πold
    Πnew[2:(Nold+1), 1:Nold] .+= (1-q)*Πold
    Πnew[2:(Nold+1), 2:(Nold+1)] .+= q*Πold
    nothing
end

function rouwenmat(N, p, q)
    initmat = [p 1-p;1-q q]
    if N==2
        ret = initmat
    else
        currmat = initmat
        for n = 3:N
            nextmat = fill(0., (n, n))
            rouwenupdate!(currmat, nextmat, p, q)
            currmat = nextmat
            RouwenNormalize!(currmat)
        end
        ret = currmat
    end
    return(ret)
end

function rouwenhorst(npts, ρ, σ)
    # Discretizes
    # y′ = ρ y +  σ ϵ

    ω = σ/sqrt(1-ρ^2) # Long run std dev
    # println("Long run variance: $ω")
    q = (1+ρ)/2

    points = range(-ω*sqrt(npts - 1),
                   ω*sqrt(npts-1),
                   length=npts)

    # points = GenGrid(uniform(npts, bds))
    Π = rouwenmat(npts, q, q)
    return points, Π
end

max_stars_repo_name: pereiragc/rouwenhorst

max_issues_repo_name: pereiragc/rouwenhorst

max_forks_repo_name: pereiragc/rouwenhorst


text:
using Test
using Pkg
using AutoViz
using NBInclude
using Colors
using Random
using AutomotiveDrivingModels

@nbinclude(joinpath(dirname(pathof(AutoViz)),"..", "notebooks", "tutorial.ipynb"))
@nbinclude(joinpath(dirname(pathof(AutoViz)),"..", "notebooks", "overlay_tutorial.ipynb"))
@nbinclude(joinpath(dirname(pathof(AutoViz)),"..", "doc", "AutoViz.ipynb"))

rw = gen_straight_roadway(3, 100.0)
car = ArrowCar(0.0, 0.0, 0.0, id=1)
car2 = ArrowCar(1.0, 1.0, 1.0, color=colorant"green", text="text")

render([rw, car, "some text"])

render([rw, car, car2, "some text"], cam=CarFollowCamera(0))

render([rw, car, car2], overlays=[TextOverlay(text=["overlay"], color=colorant"blue")])


text:
#####################################
# Warning - misc stuff, not for usage

using Revise
using DataFrames
using CSV
using BenchmarkTools
using SymSpellChecker
using Profile
using ProfileView
using Logging
using DataVoyager

dfcs = CSV.read(joinpath(@__DIR__, "original_bench.csv"))
dfjl = CSV.read(joinpath(@__DIR__, "bench.csv"))

insertcols!(dfjl, 1, :implementation => "Julia")

df = vcat(dfcs, dfjl)

CSV.write("/home/skoffer/Projects/BabySteps/Spellcheck/benches.csv", df)

v = Voyager(df)

v = Voyager(df[df.dict_name .== "30k", :])

###########################################

df = CSV.read(joinpath(@__DIR__, "words.csv"))
df = sort(df, :med_val, rev = true)
@show head(df)

word = "preard" # Why is it so slow???
word = "coretedu"

ASSETS_PATH = joinpath(@__DIR__, "..", "..", "assets")
# ASSETS_PATH = "/home/skoffer/.julia/dev/SymSpellChecker/assets/"

dicts = [
    joinpath(ASSETS_PATH, "frequency_dictionary_en_30_000.txt"),
    joinpath(ASSETS_PATH, "frequency_dictionary_en_82_765.txt"),
    joinpath(ASSETS_PATH, "frequency_dictionary_en_500_000.txt"),
]

prefix_length = 5
max_edit = 2

# df = DataFrame(word = String[], min_val = Float64[], med_val = Float64[], avg_val = Float64[])
const d = SymSpell(dicts[1], max_dictionary_edit_distance = max_edit, prefix_length = prefix_length)

lookup(d, word, verbosity = SymSpellChecker.VerbosityCLOSEST)

# 189.313 μs (85 allocations: 12.27 KiB)
# 135.744 μs (85 allocations: 12.27 KiB)
# 111.050 μs (86 allocations: 12.38 KiB)
@btime lookup($d, $word, verbosity = $SymSpellChecker.VerbosityCLOSEST)
@time (for _ in 1:1000; lookup(d, word, verbosity = SymSpellChecker.VerbosityCLOSEST); end)
@time (for _ in 1:1000; lookup(d, word, verbosity = SymSpellChecker.VerbosityCLOSEST); end)

@profview (for _ in 1:1000; lookup(d, word, verbosity = SymSpellChecker.VerbosityCLOSEST); end)

@code_warntype lookup(d, word, false, nothing, false, SymSpellChecker.VerbosityCLOSEST, max_edit)

disable_logging(LogLevel(-100000))
begin
    io = open(joinpath(@__DIR__, "log.txt"), "w")
    logger = SimpleLogger(io)
    global_logger(logger)
    lookup(d, word, false, nothing, false, SymSpellChecker.VerbosityCLOSEST, max_edit)
    flush(io)
end

disable_logging(Logging.Debug)

cnt = [2550, 1098, 348]
lookup(d, word, false, nothing, false, SymSpellChecker.VerbosityCLOSEST, max_edit)

@profview lookup(d, word, false, nothing, false, SymSpellChecker.VerbosityCLOSEST, max_edit)
@profview (for _ in 1:100; lookup(d, word, false, nothing, false, SymSpellChecker.VerbosityCLOSEST, max_edit); end)
length(d.deletes["prear"])
d.words[d.deletes["prear"]]

length(d.deletes["rear"])

hashset1 = Set()
candidates = String[]
candidate = "prear"
SymSpellChecker.add_edits!(hashset1, candidates, candidate, length(candidate))
l = length(candidates)
for i in 1:l
    SymSpellChecker.add_edits!(hashset1, candidates, candidates[i], length(candidates[i]))
end
pushfirst!(candidates, "prear")

for word in candidates
    @show length(d.deletes[word])
end

sum(length(d.deletes[word]) for word in candidates)

d.words[d.deletes[candidates[1]][1]][1]
cnt = [0, 0, 0]

let suggestion_len = d.words[d.deletes[candidates[2]][1]][3], phrase_len = length(word),
    suggestion = d.words[d.deletes[candidates[2]][1]][1], candidate_len = length(candidates[2]),
    candidate = candidates[2]
    @show suggestion_len, candidate_len
    @show suggestion, candidate
    @btime $suggestion_len > $prefix_length ? $prefix_length : $suggestion_len
    SymSpellChecker.light_filter(cnt, suggestion, candidates,
        phrase_len, prefix_length, suggestion_len, candidate_len,
        2, d.prefix_length)
    @btime SymSpellChecker.light_filter($cnt, $suggestion, $candidates,
        $phrase_len, $prefix_length, $suggestion_len, $candidate_len,
        2, $d.prefix_length)
    # @code_typed SymSpellChecker.light_filter(cnt, suggestion, candidates,
    #     phrase_len, prefix_length, suggestion_len, candidate_len,
    #     2, d.prefix_length)
end

d

@btime SymSpellChecker.light_filter($cnt, $d.words[$d.deletes[$candidates[2]][1]][1], $candidates[2],
length($word), $prefix_length, $d.words[$d.deletes[$candidates[2]][1]][3], length($candidates[2]),
2, $d.prefix_length)

@code_warntype SymSpellChecker.light_filter(cnt, d.words[d.deletes[candidates[2]][1]][1], candidates[2],
length(word), prefix_length, d.words[d.deletes[candidates[2]][1]][3], length(candidates[2]),
2, d.prefix_length)

phrase_len = length(candidates[2])
suggestion_len = d.words[d.deletes[candidates[2]][1]][3]
max_edit_distance_2 = 2

@btime $phrase_len - $suggestion_len > $max_edit_distance_2

function f1(phrase_len, suggestion_len, candidate_len,
        max_edit_distance_2, prefix_length, phrase_prefix_len)
    phrase_len - suggestion_len > max_edit_distance_2 && return false
    suggestion_len - phrase_len > max_edit_distance_2 && return false
    suggestion_len < candidate_len && return false

    suggestion_prefix_len = suggestion_len > prefix_length ? prefix_length : suggestion_len
    if (suggestion_prefix_len > phrase_prefix_len) &&
        (suggestion_prefix_len - candidate_len > max_edit_distance_2)
        return false
    end
    true
end

let suggestion_len = d.words[d.deletes[candidates[2]][1]][3], phrase_len = length(word),
    suggestion = d.words[d.deletes[candidates[2]][1]][1], candidate_len = length(candidates[2]),
    candidate = candidates[2]
    @btime f1($phrase_len, $suggestion_len, $candidate_len,
            2, $prefix_length, $prefix_length)
end

length(word)

function light_filter2(cnt, suggestion, candidate,
        phrase_len, phrase_prefix_len, suggestion_len, candidate_len,
        max_edit_distance_2, prefix_length)
    # cnt[1] += 1
    # phrase and suggestion lengths
    # diff > allowed/current best distance
    # if abs(suggestion_len - phrase_len) > max_edit_distance_2 ||
    #     # suggestion must be for a different delete
    #     # string, in same bin only because of hash
    #     # collision
    #     (suggestion_len < candidate_len) ||
    #     # if suggestion len = delete len, then it
    #     # either equals delete or is in same bin
    #     # only because of hash collision
    #     (suggestion_len == candidate_len && suggestion != candidate)
    #     continue
    # end
    abs(phrase_len - suggestion_len) > max_edit_distance_2 && return false
    suggestion_len < candidate_len && return false
    # suggestion_len == candidate_len && suggestion != candidate && return false

    # suggestion_prefix_len = min(suggestion_len, prefix_length)
    # suggestion_prefix_len = suggestion_len
    # suggestion_prefix_len = suggestion_len > prefix_length ? prefix_length : suggestion_len

    suggestion_len > phrase_prefix_len && return false
    # ((min(suggestion_len, prefix_length) > phrase_prefix_len) &
    #     (min(suggestion_len, prefix_length) - candidate_len > max_edit_distance_2)) &&
    #     return false

    # True Damerau-Levenshtein Edit Distance: adjust
    # distance, if both distances>0
    # We allow simultaneous edits (deletes) of
    # max_edit_distance on on both the dictionary and
    # the phrase term. For replaces and adjacent
    # transposes the resulting edit distance stays
    # <= max_edit_distance. For inserts and deletes the
    # resulting edit distance might exceed
    # max_edit_distance. To prevent suggestions of a
    # higher edit distance, we need to calculate the
    # resulting edit distance, if there are
    # simultaneous edits on both sides.
    # Example: (bank==bnak and bank==bink, but
    # bank!=kanb and bank!=xban and bank!=baxn for
    # max_edit_distance=1). Two deletes on each side of
    # a pair makes them all equal, but the first two
    # pairs have edit distance=1, the others edit
    # distance=2.
    #
    # if candidate_len == 0
    #     # suggestions which have no common chars with
    #     # phrase (phrase_len<=max_edit_distance &&
    #     # suggestion_len<=max_edit_distance)
    #
    #     distance = max(phrase_len, suggestion_len)
    #     distance > max_edit_distance_2 && return false
    # end

    # suggestion_id in considered_suggestions && return false
    true
end

function z(cnt, suggestion, candidate,
        phrase_len, phrase_prefix_len, suggestion_len, candidate_len,
        max_edit_distance_2, prefix_length)
    true
end

function f2(d, candidates)
    phrase_len = 6
    cnt = [0, 0, 0]
    res = true
    for candidate in candidates
        candidate_len = length(candidate)
        for sugg in d.words[d.deletes[candidate]]
            suggestion = sugg[1]
            suggestion_len = sugg[3]

            # z(cnt, suggestion, candidate,
            #     phrase_len, prefix_length, suggestion_len, candidate_len,
            #     2, d.prefix_length)

            res = res ⊻ SymSpellChecker.light_filter(cnt, suggestion, candidate,
                phrase_len, d.prefix_length, suggestion_len, candidate_len,
                2, d.prefix_length)
        end
    end
end

f2(d, candidates)

@btime f2($d, $candidates)
@code_warntype f2(d, candidates)

function f3(d, med_res)
    phrase = "preard"
    phrase_len = length(phrase)
    cnt = [0, 0, 0]
    res = true
    for (suggestion, candidate, suggestion_len, candidate_len) in med_res
        res = res ⊻ SymSpellChecker.medium_filter(suggestion, candidate, phrase,
            phrase_len, suggestion_len, candidate_len,
            2, d.prefix_length,
            SymSpellChecker.VerbosityCLOSEST) && continue

        # res = res ⊻ SymSpellChecker.light_filter(cnt, suggestion, candidate,
        #     phrase_len, d.prefix_length, suggestion_len, candidate_len,
        #     2, d.prefix_length)
    end
end

f3(d, med_res)
# Original: 72.282 μs (1 allocation: 112 bytes)
# Without delete_in_prefix: 52.799 μs (1 allocation: 112 bytes)
# withous delete with array of char: 9.409 μs (1 allocation: 112 bytes)
# Original with array of char:
@btime f3($d, $med_res)
med_res = Tuple{String, String}[]
med_res = map(x -> (collect(string(x[1])), collect(string(x[2])), length(x[1]), length(x[2])), split.(readlines(joinpath(@__DIR__, "medium_suggestions.csv")), ","))

med_res

function f4(heavy_res, phrase)
    v2 = Vector{Int}(undef, 6 + 2)
    v0 = similar(v2)
    # phrase = collect("preard")
    distance = 0
    for suggestion in heavy_res
        distance += SymSpellChecker.evaluate3!(phrase, suggestion, 2, v0, v2)
    end
    distance
end

heavy_res = readlines(joinpath(@__DIR__, "heavy_suggestions.csv"))
heavy_res = collect.(readlines(joinpath(@__DIR__, "heavy_suggestions.csv")))

phrase = collect("preard")
# 1022
f4(heavy_res, phrase)

# 33.964 μs (2 allocations: 288 bytes)
# Vector version (22.187 μs (2 allocations: 288 bytes))
@btime f4($heavy_res, $phrase)

lookup(d, word, verbosity = SymSpellChecker.VerbosityCLOSEST)

# 189.313 μs (85 allocations: 12.27 KiB)
@btime lookup($d, $word, verbosity = $SymSpellChecker.VerbosityCLOSEST)

x = [1, 2, 3, 4, 5, 6, 7]
y = [4, 2, 6, 5, 6, 7]

y[4:end]
x[5:end]

@btime @views $x[5:end] == $y[4:end]
@btime $x[5:end] == $y[4:end]

function equal_suffixes(x, x_len, y, y_len, delta)
    id1 = x_len - delta + 1
    id2 = y_len - delta + 1
    for i in 0:(x_len - id1)
        @inbounds x[id1 + i] != y[id2 + i] && return true
    end

    return false
end

equal_suffixes(x, 7, y, 6, 3)

@btime equal_suffixes($x, 7, $y, 6, 3)


text:
struct TrackedFFJORD{R,M,F,P,RE,T,A,K} <: DiffEqFlux.CNFLayer
    model::M
    forw_n_back::F
    p::P
    re::RE
    tspan::T
    args::A
    kwargs::K
    time_dep::Bool

    function TrackedFFJORD(
        model,
        tspan,
        time_dep::Bool,
        regularize::Bool,
        args...;
        dynamics = nothing,
        kwargs...,
    )
        p, re = Flux.destructure(model)
        if isnothing(dynamics)
            function forw_n_back(m, z, t, e)
                mz, back =
                    time_dep ? Tracker.forward(z -> m(z, t), z) : Tracker.forward(m, z)
                eJ = back(e)[1]
                return mz, eJ
            end
        else
            forw_n_back = dynamics
        end
        new{
            regularize,
            typeof(model),
            typeof(forw_n_back),
            typeof(p),
            typeof(re),
            typeof(tspan),
            typeof(args),
            typeof(kwargs),
        }(
            model,
            forw_n_back,
            p,
            re,
            tspan,
            args,
            kwargs,
            time_dep,
        )
    end
end

@fastmath function _ffjord(u, p, t, re, forw_n_back, e, regularize, M)
    m = re(p)::M
    if regularize
        z = u[1:end-3, :]
        mz, eJ = forw_n_back(m, z, t, e)
        trace_jac = sum(eJ .* e, dims = 1)
        return vcat(mz, -trace_jac, sum(abs2.(mz), dims = 1), norm_batched(eJ) .^ 2)
    else
        z = u[1:end-1, :]
        mz, eJ = forw_n_back(m, z, t, e)
        trace_jac = sum(eJ .* e, dims = 1)
        return vcat(mz, -trace_jac)
    end
end

@fastmath function (n::TrackedFFJORD{false,M})(
    x,
    p = n.p,
    e = CUDA.randn(Float32, size(x)...);
    regularize = false,
) where {M}
    sense = SensitivityADPassThrough()
    tspan = _convert_tspan(n.tspan, p)
    ffjord_ = (u, p, t) -> _ffjord(u, p, t, n.re, n.forw_n_back, e, regularize, M)
    ff = ODEFunction{false}(ffjord_, tgrad = n.time_dep ? nothing : DiffEqFlux.basic_tgrad)
    if regularize
        _z = TrackedArray(CUDA.zeros(Float32, 3, size(x, 2)))

        prob = ODEProblem{false}(ff, vcat(x, _z), tspan, p)
        sol = solve(prob, n.args...; sensealg = sense, n.kwargs...)

        pred = sol.u[1]::TrackedArray{Float32,2,CuArray{Float32,2}}
        z = pred[1:end-3, :]
        delta_logp = pred[end-2, :]
        λ₁ = pred[end-1, :]
        λ₂ = pred[end, :]
    else
        _z = TrackedArray(CUDA.zeros(Float32, 1, size(x, 2)))

        prob = ODEProblem{false}(ff, vcat(x, _z), tspan, p)
        sol = solve(prob, n.args...; sensealg = sense, n.kwargs...)

        pred = sol.u[1]::TrackedArray{Float32,2,CuArray{Float32,2}}
        z = pred[1:end-1, :]
        delta_logp = pred[end, :]
        λ₁ = _z[1, :]
        λ₂ = _z[1, :]
    end

    nfe = sol.destats.nf::Int
    logpz = reshape(sum(-(log(eltype(z)(2π)) .+ CUDA.pow.(z, 2)) ./ 2, dims = 1), :)
    logpx = logpz .- delta_logp

    return logpx, λ₁, λ₂, nfe, nothing
end

@fastmath function (n::TrackedFFJORD{true,M})(
    x,
    p = n.p,
    e = CUDA.randn(size(x)...);
    regularize = false,
) where {M}
    tspan = _convert_tspan(n.tspan, p)
    sense = SensitivityADPassThrough()
    sv = SavedValues(eltype(tspan), eltype(p))
    svcb = SavingCallback((u, t, integrator) -> integrator.EEst * integrator.dt, sv)
    ffjord_ = (u, p, t) -> _ffjord(u, p, t, n.re, n.forw_n_back, e, false, M)
    ff = ODEFunction{false}(ffjord_, tgrad = n.time_dep ? nothing : DiffEqFlux.basic_tgrad)
    _z = TrackedArray(CUDA.zeros(Float32, 1, size(x, 2)))

    prob = ODEProblem{false}(ff, vcat(x, _z), tspan, p)
    sol = solve(prob, n.args...; sensealg = sense, callback = svcb, n.kwargs...)
    pred = sol.u[1]::TrackedArray{Float32,2,CuArray{Float32,2}}
    z = pred[1:end-1, :]
    delta_logp = pred[end, :]

    logpz = reshape(sum(-(log(eltype(z)(2π)) .+ CUDA.pow.(z, 2)) ./ 2, dims = 1), :)
    logpx = logpz .- delta_logp

    nfe = sol.destats.nf::Int

    return logpx, _z, _z, nfe, sv
end

function jacobian_fn(f, x::AbstractMatrix, t, tdep::Bool)
    y, back = tdep ? Tracker.forward(x -> f(x, t), x) : Tracker.forward(f, x)
    z = similar(y)
    fill!(z, 0)
    vec = similar(x, size(x, 1), size(x, 1), size(x, 2))
    for i = 1:size(y, 1)
        z[i, :] .+= 1
        vec[i, :, :] = data(back(z)[1])
    end
    return vec, y
end

_trace_batched(x::AbstractArray{T,3}) where {T} =
    reshape([tr(x[:, :, i]) for i = 1:size(x, 3)], 1, size(x, 3))

function _deterministic_ffjord(u, p, t, re, M, tdep)
    m = re(p)::M
    z = u[1:end-1, :]
    vec, mz = jacobian_fn(m, z, t, tdep)
    trace_jac = _trace_batched(vec)
    return vcat(mz, -trace_jac)
end

function sample(n::TrackedFFJORD{B,M}, indims::Int, p = n.p; nsamples::Int = 1) where {B,M}
    z_samples = CUDA.randn(indims, nsamples)
    ffjord_ = (u, p, t) -> _deterministic_ffjord(u, p, t, n.re, M, n.time_dep)
    _z = TrackedArray(CUDA.zeros(Float32, 1, nsamples))
    prob = ODEProblem{false}(ffjord_, vcat(z_samples, _z), [n.tspan[2], n.tspan[1]], p)
    x_gen = solve(prob, n.args...; sensealg = SensitivityADPassThrough(), n.kwargs...)
    return x_gen.u[1][1:end-1, :]
end


text:
module Units

using ..Makie: VecLike
#=
Absolute is the default, so any number not having a unit is treated as absolute
struct Absolute{T}
    number::T
end
=#
using AbstractNumbers, StaticArrays, GeometryTypes

abstract type Unit{T} <: AbstractNumber{T} end

# We should always poison any calculation involving Units
promote_rule(::Type{<: Unit}, ::Type{T}) where T <: Number = Unit{T}
promote_rule(::Type{T}, ::Type{<: Unit}) where T <: Number = Unit{T}

# This is kind of wrong, since we need a scene for correct conversion.
# The correct version is to_absolute(scene, x::Unit)
Base.convert(::Type{Number}, x::Unit) = x.number

"""
Unit is relative to bounding frame.
E.g. if the area is IRect(0, 0, 100, 100)
Point(0.5rel, 0.5rel) == Point(50, 50)
"""
struct Relative{T <: Number} <: Unit{T}
    number::T
end
AbstractNumbers.basetype(::Type{<: Relative}) = Relative

"""
Unit is pixels on screen.
This one is a bit tricky, since it refers to a static attribute (pixels on screen don't change)
but since every visual is attached to a camera, the exact scale might change.
So in the end, this is just relative to some normed camera - the value on screen, depending on the camera,
will not actually sit on those pixels. Only camera that guarantees the correct mapping is the
`:pixel` camera type.
"""
struct Pixel{T} <: Unit{T}
    number::T
end
AbstractNumbers.basetype(::Type{<: Pixel}) = Pixel

"""
Millimeter on screen. This unit respects the dimension and pixel density of the screen
to represent millimeters on the screen. This is the must use unit for layouting,
that needs to look the same on all kind of screens. Similar as with the [`Pixel`](@ref) unit,
a camera can change the actually displayed dimensions of any object using the millimeter unit.
"""
struct Millimeter{T} <: Unit{T}
    number::T
end
AbstractNumbers.basetype(::Type{<: Millimeter}) = Millimeter

const rel = Relative(1)
const px = Pixel(1)
const mm = Millimeter(1)

"""
Default doesn't do anything
"""
function to_absolute(scene, x)
    x
end

function to_absolute(scene, x::AbstractVector{<: Millimeter})
    to_pixel(scene, x .* pixel_per_mm(scene))
end

function to_absolute(scene, x::Relative)
    x * minimum(widths(scene))
end

similar_vec(::Type{V}, T) where V <: StaticVector = similar_type(V, T)
similar_vec(::Type{NTuple{N, T}}, t) where {N, T} = NTuple{N, t}

function to_absolute(scene, x::V) where V <: VecLike{N, T} where {N, T <: Relative}
    x .* convert(V, Relative.(widths(scene)))
end

function to_absolute(scene, x::VecLike{N, <: Pixel}) where N
    vec3 = to_nd(x, Val{3}, 0)
    vec4 = to_nd(vec3, Val{4}, isa(x, Point) ? 1 : 0)
    projected = to_value(scene[:camera].projectionview) .* vec4
    vec3 = to_nd(projected ./ projected[4], Val{3}, 0)
end

function get_scaled_dpi(window)
    monitor = GLFW.GetPrimaryMonitor()
    props = GLWindow.MonitorProperties(monitor)
    # it seems like small displays with high dpi make mm look quite big.
    # so lets scale it a bit. 518 is a bit arbitrary, but the scale of my
    # screen on which I test everything, hence it will make you see things as I do.
    scaling = minimum(props.physicalsize) / 518
    min(props.dpi...) * scaling # we do not start fiddling with differently scaled xy dpi's
end

end

using .Units

using .Units: px, rel, mm, Millimeter, Pixel, Relative, to_absolute
export px, rel, mm, Millimeter, Pixel, Relative, to_absolute