text:
using DrWatson
@quickactivate "EPExperiments"

using EPExperiments
using Random
using Logging
using LoggingExtras
using JLD2
using FileIO
using CSV
using DataFrames

const LOG_DIR_NAME = "sir_nuts_baseline"
const LOG_FILENAME = "out.log"

@with_kw struct SIRNUTSBaseline
    experiment_name::String = "test"
    num_samples::Int = 100
    num_chains::Int = 4
    nuts_acceptance_ratio::Float64 = 0.65
    seed::Int = 1234
    data_file::String = "neg_binomial_data.jld2"
    cost_fn_name::Symbol = :cost_fn_sir
end

function sir_nuts_baseline(experiment_config)
    @unpack seed, num_samples, nuts_acceptance_ratio, num_chains = experiment_config
    @unpack cost_fn_name, data_file = experiment_config

    result_folder = mkpath(joinpath(
        datadir(LOG_DIR_NAME),
        savename(experiment_config)
    ))

    logger = TeeLogger(
        ConsoleLogger(),
        FileLogger(joinpath(result_folder, LOG_FILENAME))
    )

    Random.seed!(seed)

    input_data = load(datadir("sims", data_file))
    @unpack tmax, total_population, i_0_true, β_true, γ = input_data["params"]
    X, Y = input_data["X"], input_data["Y"]

    sir_exp = bayes_sir(
        Y,
        total_population,
        γ,
        COST_FUNCTIONS[cost_fn_name]
    )
    sir_turing = sir_exp.gamma2

    @time begin
    nuts_samples = sample(
        sir_turing,
        Turing.NUTS(nuts_acceptance_ratio),
        MCMCThreads(),
        num_samples,
        num_chains;
        discard_adapt=false
    )
    end

    @tagsave(joinpath(result_folder, "results.jld2"), Dict(
        "nuts_samples" => nuts_samples,
        "experiment_config" => experiment_config
    ))

    with_logger(logger) do
        @info "MCMC samples:" nuts_samples
    end
end

sir_nuts_baseline(SIRNUTSBaseline(
    experiment_name="nuts_baseline",
    num_samples=10000,
    num_chains=16,
    seed=1240
))


text:
# read the output vlimit
export psp_readvlimit

const READ_VLIMIT = [0x55, 0x0d]

"""
    psp_readvlimit(io)

Read the voltage limit.
"""
function psp_readvlimit(io_psp::IO)
  write(io_psp, READ_VLIMIT)
  vlimitstring = bytestring(read(io_psp,UInt8, 6))
  # U - if limit is set
  # u - if limit is being set
  if  uppercase(vlimitstring[1]) != 'U' ||
      vlimitstring[4:6] != "\r\r\n"
        error("PSP Invalid Response: ",vlimitstring)
  end
  parse(Float64,vlimitstring[2:3])
end

ext: jl


text:
type ReLU{A<:AbstractArray} <: Pointwise{A}
    output :: A
    gradInput :: A
end

ReLU(T::Type, s...) = ReLU(Array(T, s...), Array(T, s...))

function updateOutput!{A}(self :: ReLU{A}, input :: A)
    self.output = input .* (input .>= zero(eltype(input)))
    return self.output
end

function updateGradInput!{A}(self :: ReLU{A}, input :: A, gradOutput :: A)
    self.gradInput = gradOutput .* (input .>= zero(eltype(input)))
    return self.gradInput
end

export ReLU


text:
@test sum(normalize(wt)) == 1

num_samples, num_signals = size(data)
@test std(data, mean(data, 2), num_samples, num_signals) == std(data, vec(mean(data, 2)), num_samples, num_signals)
@test_approx_eq_eps std(data, mean(data, 2), num_samples, num_signals) [1.67369, 0.959536, 1.2842] ε

for i = 1:size(data, 2)

    # Compare standardized central moments
    @test_approx_eq_eps coskew(data, standardize=true)[i,i,i] expected_skewness[i] ε
    @test_approx_eq_eps cokurt(data, standardize=true)[i,i,i,i] expected_kurtosis[i] ε

    # Compare raw central moments
    @test_approx_eq_eps coskew(data, standardize=false)[i,i,i] expected_third_moment[i] ε
    @test_approx_eq_eps cokurt(data, standardize=false)[i,i,i,i] expected_fourth_moment[i] ε
end

@test_approx_eq_eps coskewness(data, wt) 0.100543398 ε
@test_approx_eq_eps cokurtosis(data, wt) 0.582933712 ε

@test_approx_eq_eps coskewness(data, wt, standardize=true) 0.148687894 ε
@test_approx_eq_eps cokurtosis(data, wt, standardize=true) 0.664085775 ε

@test_approx_eq_eps coskewness(data) 0.081011176 ε
@test_approx_eq_eps cokurtosis(data) 0.571876949 ε

@test_approx_eq_eps coskewness(data, bias=1) 0.084533401 ε
@test_approx_eq_eps cokurtosis(data, bias=1) 0.596741164 ε


text:
push!(LOAD_PATH, "./core/")

using core

cfgfile = ""
# cfgfile = "../input/markus-paper.cfg"
# cfgfile = "../input/gideon-master-thesis-isotropic.cfg"
# cfgfile = "../input/daniel-master-thesis-isotropic.cfg"

p_state = State_Setup(cfgfile)

Simulation_PlayPause(p_state, "LLG", "SIB", 100, 100)

max_stars_repo_name: ddkn/spirit

max_issues_repo_name: ddkn/spirit

max_forks_repo_name: ddkn/spirit


text:
module thermostat

using ReachabilityAnalysis, ModelingToolkit

const A1 = 40.0
const A2 = 30.0
const B = 0.5
const t1 = 75
const t2 = 65

const var = @variables t

function thermostat_on()
    invariant = HalfSpace(t <= t1)
    @system(x' = -Bx + A1, x ∈ invariant)
end

function thermostat_off()
    invariant = HalfSpace(t >= t2)
    @system(x' = -Bx + A2, x ∈ invariant)
end

function thermostat_hybrid()
    automaton = LightAutomaton(2)
    add_transition!(automaton, 1, 2, 1)
    add_transition!(automaton, 2, 1, 2)

    mode1 = thermostat_on()
    mode2 = thermostat_off()
    modes = [mode1, mode2]

    ## transition on -> off
    guard = HalfSpace(t >= t1)
    trans1 = ConstrainedIdentityMap(1, guard)
    ## transition off -> on
    guard = HalfSpace(t <= t2)
    trans2 = ConstrainedIdentityMap(1, guard)
    resetmaps = [trans1, trans2]

    return HybridSystem(automaton, modes, resetmaps, [AutonomousSwitching()])
end

function model(X0)
    H = thermostat_hybrid()
    return IVP(H, X0)
end

end  # module

max_stars_repo_name: mforets/ReachabilityLibrary

max_issues_repo_name: mforets/ReachabilityLibrary

max_forks_repo_name: mforets/ReachabilityLibrary


text:
# Definition of Boore & Thompson (2012) constant values to be used within subsequent functions
const m_ii_bt15 = [ 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0 ]
const r_jj_bt15 = [ 2.00, 3.17, 5.02, 7.96, 12.62, 20.00, 31.70, 50.24, 79.62, 126.20, 200.01, 317.00, 502.41, 796.26, 1262.00 ]
const num_m_ii_bt15 = 13
const num_r_jj_bt15 = 15

const coefs_wna_bt15 = [ 2.00	2.00	9.38E-01	-1.09E-02	2.00E+00	1.00E+00	1.86E+00	2.00E+00	1.07E+00	1.03E+00	1.00E+00;
2.50	2.00	9.06E-01	-1.38E-02	2.00E+00	1.00E+00	1.67E+00	2.00E+00	1.07E+00	1.05E+00	1.04E+00;
3.00	2.00	9.55E-01	-1.74E-02	2.00E+00	1.00E+00	1.17E+00	2.00E+00	1.28E+00	1.04E+00	1.03E+00;
3.50	2.00	9.55E-01	-2.27E-02	2.00E+00	1.00E+00	9.35E-01	2.00E+00	1.29E+00	1.04E+00	1.03E+00;
4.00	2.00	9.85E-01	-3.71E-02	2.00E+00	1.00E+00	6.72E-01	2.00E+00	1.37E+00	1.03E+00	1.02E+00;
4.50	2.00	1.01E+00	-7.99E-02	2.00E+00	1.00E+00	5.18E-01	2.00E+00	1.39E+00	1.04E+00	1.02E+00;
5.00	2.00	1.04E+00	-1.10E-01	2.00E+00	1.00E+00	4.31E-01	2.00E+00	1.34E+00	1.03E+00	1.01E+00;
5.50	2.00	1.03E+00	-1.28E-01	2.00E+00	1.00E+00	3.20E-01	2.00E+00	1.34E+00	1.05E+00	1.01E+00;
6.00	2.00	9.54E-01	-7.01E-02	2.00E+00	1.00E+00	2.23E-01	2.00E+00	1.16E+00	1.05E+00	1.00E+00;
6.50	2.00	9.52E-01	-6.39E-02	2.00E+00	1.00E+00	1.86E-01	2.00E+00	1.16E+00	1.05E+00	9.96E-01;
7.00	2.00	8.48E-01	2.92E-02	2.00E+00	1.00E+00	1.15E-01	2.00E+00	1.15E+00	1.07E+00	9.88E-01;
7.50	2.00	8.49E-01	3.80E-02	2.00E+00	1.00E+00	1.02E-01	2.00E+00	1.15E+00	1.07E+00	9.65E-01;
8.00	2.00	8.30E-01	3.78E-02	2.00E+00	1.00E+00	8.68E-02	2.00E+00	1.05E+00	1.08E+00	9.50E-01;
2.00	3.17	9.17E-01	-9.48E-03	2.00E+00	1.00E+00	3.35E+00	2.00E+00	1.01E+00	1.05E+00	1.02E+00;
2.50	3.17	9.17E-01	-2.05E-02	2.00E+00	1.00E+00	3.08E+00	2.00E+00	1.01E+00	1.05E+00	1.04E+00;
3.00	3.17	9.37E-01	-1.12E-02	2.00E+00	1.00E+00	1.89E+00	2.00E+00	1.19E+00	1.04E+00	1.03E+00;
3.50	3.17	9.36E-01	-1.44E-02	2.00E+00	1.00E+00	1.48E+00	2.00E+00	1.19E+00	1.04E+00	1.03E+00;
4.00	3.17	9.62E-01	-3.49E-02	2.00E+00	1.00E+00	9.96E-01	2.00E+00	1.27E+00	1.04E+00	1.02E+00;
4.50	3.17	9.66E-01	-4.16E-02	2.00E+00	1.00E+00	6.78E-01	2.00E+00	1.30E+00	1.04E+00	1.03E+00;
5.00	3.17	1.01E+00	-9.19E-02	2.00E+00	1.00E+00	5.24E-01	2.00E+00	1.34E+00	1.04E+00	1.02E+00;
5.50	3.17	1.02E+00	-1.15E-01	2.00E+00	1.00E+00	3.74E-01	2.00E+00	1.29E+00	1.05E+00	1.01E+00;
6.00	3.17	9.80E-01	-8.70E-02	2.00E+00	1.00E+00	2.67E-01	2.00E+00	1.15E+00	1.05E+00	9.85E-01;
6.50	3.17	9.45E-01	-5.79E-02	2.00E+00	1.00E+00	1.90E-01	2.00E+00	1.17E+00	1.06E+00	9.84E-01;
7.00	3.17	8.36E-01	4.35E-02	2.00E+00	1.00E+00	1.15E-01	2.00E+00	1.16E+00	1.07E+00	9.83E-01;
7.50	3.17	8.45E-01	3.80E-02	2.00E+00	1.00E+00	1.02E-01	2.00E+00	1.13E+00	1.08E+00	9.61E-01;
8.00	3.17	8.28E-01	3.80E-02	2.00E+00	1.00E+00	7.62E-02	2.00E+00	1.06E+00	1.08E+00	9.41E-01;
2.00	5.02	9.13E-01	-4.79E-03	2.00E+00	1.00E+00	5.72E+00	2.00E+00	9.90E-01	1.05E+00	1.04E+00;
2.50	5.02	9.02E-01	-3.31E-03	2.00E+00	1.00E+00	5.19E+00	2.00E+00	1.02E+00	1.05E+00	1.04E+00;
3.00	5.02	9.03E-01	-2.62E-03	2.00E+00	1.00E+00	3.71E+00	2.00E+00	1.04E+00	1.05E+00	1.05E+00;
3.50	5.02	9.09E-01	-2.44E-03	2.00E+00	1.00E+00	2.44E+00	2.00E+00	1.12E+00	1.05E+00	1.05E+00;
4.00	5.02	9.39E-01	-2.64E-02	2.00E+00	1.00E+00	1.49E+00	2.00E+00	1.21E+00	1.05E+00	1.05E+00;
4.50	5.02	9.36E-01	-2.14E-02	2.00E+00	1.00E+00	1.05E+00	2.00E+00	1.19E+00	1.04E+00	1.03E+00;
5.00	5.02	9.76E-01	-6.53E-02	2.00E+00	1.00E+00	6.74E-01	2.00E+00	1.25E+00	1.05E+00	1.03E+00;
5.50	5.02	9.95E-01	-9.77E-02	2.00E+00	1.00E+00	4.58E-01	2.00E+00	1.23E+00	1.06E+00	1.02E+00;
6.00	5.02	9.96E-01	-1.02E-01	2.00E+00	1.00E+00	3.34E-01	2.00E+00	1.21E+00	1.06E+00	1.01E+00;
6.50	5.02	8.88E-01	-1.34E-02	2.00E+00	1.00E+00	1.90E-01	2.00E+00	1.15E+00	1.07E+00	1.00E+00;
7.00	5.02	8.24E-01	5.87E-02	2.00E+00	1.00E+00	1.20E-01	2.00E+00	1.16E+00	1.07E+00	9.91E-01;
7.50	5.02	8.41E-01	3.74E-02	2.00E+00	1.00E+00	9.77E-02	2.00E+00	1.08E+00	1.08E+00	9.59E-01;
8.00	5.02	8.04E-01	6.20E-02	2.00E+00	1.00E+00	7.63E-02	2.00E+00	1.06E+00	1.08E+00	9.48E-01;
2.00	7.96	9.10E-01	-1.24E-02	2.00E+00	1.00E+00	1.07E+01	2.00E+00	9.03E-01	1.05E+00	1.03E+00;
2.50	7.96	9.03E-01	6.10E-04	2.00E+00	1.00E+00	7.60E+00	2.00E+00	1.01E+00	1.05E+00	1.05E+00;
3.00	7.96	8.93E-01	-4.72E-03	2.00E+00	1.00E+00	6.14E+00	2.00E+00	1.00E+00	1.06E+00	1.06E+00;
3.50	7.96	8.93E-01	-4.55E-03	2.00E+00	1.00E+00	3.78E+00	2.00E+00	1.00E+00	1.05E+00	1.05E+00;
4.00	7.96	9.15E-01	-2.36E-02	2.00E+00	1.00E+00	2.52E+00	2.00E+00	1.07E+00	1.06E+00	1.05E+00;
4.50	7.96	9.29E-01	-2.47E-02	2.00E+00	1.00E+00	1.51E+00	2.00E+00	1.16E+00	1.06E+00	1.05E+00;
5.00	7.96	9.71E-01	-6.76E-02	2.00E+00	1.00E+00	9.17E-01	2.00E+00	1.21E+00	1.06E+00	1.04E+00;
5.50	7.96	9.69E-01	-6.62E-02	2.00E+00	1.00E+00	6.06E-01	2.00E+00	1.20E+00	1.06E+00	1.03E+00;
6.00	7.96	9.49E-01	-6.62E-02	2.00E+00	1.00E+00	3.53E-01	2.00E+00	1.15E+00	1.06E+00	1.01E+00;
6.50	7.96	8.31E-01	4.55E-02	2.00E+00	1.00E+00	1.75E-01	2.00E+00	1.15E+00	1.07E+00	1.02E+00;
7.00	7.96	8.31E-01	4.58E-02	2.00E+00	1.00E+00	1.38E-01	2.00E+00	1.13E+00	1.07E+00	9.90E-01;
7.50	7.96	8.31E-01	4.14E-02	2.00E+00	1.00E+00	1.12E-01	2.00E+00	1.12E+00	1.08E+00	9.75E-01;
8.00	7.96	8.04E-01	6.82E-02	2.00E+00	1.00E+00	7.01E-02	2.00E+00	1.05E+00	1.08E+00	9.48E-01;
2.00	12.62	9.01E-01	-2.38E-04	2.00E+00	1.00E+00	1.39E+01	2.00E+00	9.03E-01	1.05E+00	1.05E+00;
2.50	12.62	8.78E-01	-2.16E-03	2.00E+00	1.00E+00	1.20E+01	2.00E+00	8.87E-01	1.06E+00	1.06E+00;
3.00	12.62	8.67E-01	-2.53E-03	2.00E+00	1.00E+00	9.21E+00	2.00E+00	8.98E-01	1.07E+00	1.06E+00;
3.50	12.62	8.88E-01	-4.74E-03	2.00E+00	1.00E+00	4.96E+00	2.00E+00	1.00E+00	1.07E+00	1.06E+00;
4.00	12.62	8.89E-01	-1.24E-02	2.00E+00	1.00E+00	3.28E+00	2.00E+00	1.02E+00	1.06E+00	1.06E+00;
4.50	12.62	8.90E-01	-1.27E-02	2.00E+00	1.00E+00	1.71E+00	2.00E+00	1.02E+00	1.06E+00	1.05E+00;
5.00	12.62	9.15E-01	-2.13E-02	2.00E+00	1.00E+00	9.17E-01	2.00E+00	1.14E+00	1.06E+00	1.05E+00;
5.50	12.62	9.69E-01	-6.63E-02	2.00E+00	1.00E+00	6.29E-01	2.00E+00	1.20E+00	1.06E+00	1.03E+00;
6.00	12.62	9.99E-01	-1.15E-01	2.00E+00	1.00E+00	5.22E-01	2.00E+00	1.16E+00	1.06E+00	1.02E+00;
6.50	12.62	8.21E-01	5.22E-02	2.00E+00	1.00E+00	1.75E-01	2.00E+00	1.08E+00	1.07E+00	1.00E+00;
7.00	12.62	8.42E-01	3.63E-02	2.00E+00	1.00E+00	1.49E-01	2.00E+00	1.10E+00	1.07E+00	9.84E-01;
7.50	12.62	8.18E-01	5.02E-02	2.00E+00	1.00E+00	1.12E-01	2.00E+00	1.09E+00	1.08E+00	9.69E-01;
8.00	12.62	8.02E-01	6.36E-02	2.00E+00	1.00E+00	7.30E-02	2.00E+00	1.07E+00	1.08E+00	9.47E-01;
2.00	20.00	8.67E-01	1.11E-03	2.00E+00	1.00E+00	2.31E+01	2.00E+00	8.44E-01	1.07E+00	1.05E+00;
2.50	20.00	8.79E-01	-2.62E-03	2.00E+00	1.00E+00	1.54E+01	2.00E+00	9.00E-01	1.07E+00	1.06E+00;
3.00	20.00	8.78E-01	-2.33E-03	2.00E+00	1.00E+00	1.24E+01	2.00E+00	9.00E-01	1.06E+00	1.05E+00;
3.50	20.00	8.78E-01	-9.54E-03	2.00E+00	1.00E+00	7.24E+00	2.00E+00	9.47E-01	1.07E+00	1.06E+00;
4.00	20.00	8.75E-01	-8.07E-03	2.00E+00	1.00E+00	4.40E+00	2.00E+00	9.51E-01	1.06E+00	1.06E+00;
4.50	20.00	8.82E-01	-1.08E-02	2.00E+00	1.00E+00	2.28E+00	2.00E+00	1.00E+00	1.07E+00	1.06E+00;
5.00	20.00	8.90E-01	-1.53E-02	2.00E+00	1.00E+00	1.35E+00	2.00E+00	1.01E+00	1.06E+00	1.04E+00;
5.50	20.00	8.86E-01	-1.56E-02	2.00E+00	1.00E+00	7.89E-01	2.00E+00	1.01E+00	1.06E+00	1.03E+00;
6.00	20.00	9.69E-01	-8.21E-02	2.00E+00	1.00E+00	5.22E-01	2.00E+00	1.15E+00	1.07E+00	1.03E+00;
6.50	20.00	9.68E-01	-8.34E-02	2.00E+00	1.00E+00	3.54E-01	2.00E+00	1.17E+00	1.06E+00	1.01E+00;
7.00	20.00	8.30E-01	3.98E-02	2.00E+00	1.00E+00	1.57E-01	2.00E+00	1.11E+00	1.08E+00	1.00E+00;
7.50	20.00	8.36E-01	4.00E-02	2.00E+00	1.00E+00	1.19E-01	2.00E+00	1.10E+00	1.07E+00	9.68E-01;
8.00	20.00	8.01E-01	6.36E-02	2.00E+00	1.00E+00	7.10E-02	2.00E+00	1.05E+00	1.08E+00	9.49E-01;
2.00	31.70	8.77E-01	-2.85E-03	2.00E+00	1.00E+00	2.84E+01	2.00E+00	8.36E-01	1.07E+00	1.06E+00;
2.50	31.70	8.72E-01	-2.76E-03	2.00E+00	1.00E+00	2.74E+01	2.00E+00	8.37E-01	1.07E+00	1.06E+00;
3.00	31.70	8.76E-01	-2.14E-03	2.00E+00	1.00E+00	1.88E+01	2.00E+00	9.14E-01	1.07E+00	1.06E+00;
3.50	31.70	8.55E-01	-9.99E-03	2.00E+00	1.00E+00	1.05E+01	2.00E+00	8.84E-01	1.09E+00	1.07E+00;
4.00	31.70	8.76E-01	-1.01E-02	2.00E+00	1.00E+00	6.42E+00	2.00E+00	9.42E-01	1.07E+00	1.06E+00;
4.50	31.70	8.68E-01	-7.45E-03	2.00E+00	1.00E+00	3.65E+00	2.00E+00	9.52E-01	1.07E+00	1.06E+00;
5.00	31.70	8.84E-01	-2.10E-02	2.00E+00	1.00E+00	1.97E+00	2.00E+00	9.67E-01	1.07E+00	1.05E+00;
5.50	31.70	8.91E-01	-2.11E-02	2.00E+00	1.00E+00	1.06E+00	2.00E+00	9.86E-01	1.06E+00	1.03E+00;
6.00	31.70	9.70E-01	-8.86E-02	2.00E+00	1.00E+00	6.97E-01	2.00E+00	1.13E+00	1.07E+00	1.03E+00;
6.50	31.70	9.66E-01	-8.88E-02	2.00E+00	1.00E+00	4.23E-01	2.00E+00	1.12E+00	1.07E+00	1.00E+00;
7.00	31.70	7.93E-01	7.72E-02	2.00E+00	1.00E+00	1.57E-01	2.00E+00	1.07E+00	1.07E+00	1.00E+00;
7.50	31.70	8.07E-01	6.50E-02	2.00E+00	1.00E+00	1.26E-01	2.00E+00	1.08E+00	1.08E+00	9.72E-01;
8.00	31.70	7.98E-01	6.55E-02	2.00E+00	1.00E+00	8.50E-02	2.00E+00	1.07E+00	1.08E+00	9.51E-01;
2.00	50.24	8.70E-01	-2.75E-03	2.00E+00	1.00E+00	3.34E+01	2.00E+00	8.31E-01	1.08E+00	1.06E+00;
2.50	50.24	8.63E-01	-1.52E-02	2.00E+00	1.00E+00	2.83E+01	2.00E+00	8.21E-01	1.08E+00	1.07E+00;
3.00	50.24	8.76E-01	-1.96E-03	2.00E+00	1.00E+00	1.80E+01	2.00E+00	9.11E-01	1.07E+00	1.07E+00;
3.50	50.24	8.54E-01	2.04E-03	2.00E+00	1.00E+00	1.37E+01	2.00E+00	8.84E-01	1.08E+00	1.07E+00;
4.00	50.24	8.79E-01	-1.08E-02	2.00E+00	1.00E+00	6.94E+00	2.00E+00	9.35E-01	1.07E+00	1.07E+00;
4.50	50.24	8.75E-01	-1.25E-02	2.00E+00	1.00E+00	4.72E+00	2.00E+00	9.33E-01	1.07E+00	1.06E+00;
5.00	50.24	8.79E-01	-1.76E-02	2.00E+00	1.00E+00	2.58E+00	2.00E+00	9.66E-01	1.07E+00	1.06E+00;
5.50	50.24	8.76E-01	-7.74E-03	2.00E+00	1.00E+00	1.30E+00	2.00E+00	9.89E-01	1.07E+00	1.05E+00;
6.00	50.24	8.97E-01	-3.42E-02	2.00E+00	1.00E+00	7.04E-01	2.00E+00	9.98E-01	1.07E+00	1.02E+00;
6.50	50.24	9.07E-01	-4.26E-02	2.00E+00	1.00E+00	4.49E-01	2.00E+00	1.04E+00	1.07E+00	1.01E+00;
7.00	50.24	9.07E-01	-4.26E-02	2.00E+00	1.00E+00	3.05E-01	2.00E+00	1.05E+00	1.07E+00	1.01E+00;
7.50	50.24	8.06E-01	6.49E-02	2.00E+00	1.00E+00	1.32E-01	2.00E+00	1.08E+00	1.07E+00	9.82E-01;
8.00	50.24	8.00E-01	6.46E-02	2.00E+00	1.00E+00	9.83E-02	2.00E+00	1.08E+00	1.08E+00	9.62E-01;
2.00	79.62	8.77E-01	-1.54E-02	2.00E+00	1.00E+00	2.13E+01	2.00E+00	8.24E-01	1.08E+00	1.06E+00;
2.50	79.62	8.74E-01	-1.34E-02	2.00E+00	1.00E+00	1.89E+01	2.00E+00	8.41E-01	1.07E+00	1.07E+00;
3.00	79.62	8.58E-01	-8.54E-03	2.00E+00	1.00E+00	1.51E+01	2.00E+00	8.63E-01	1.08E+00	1.08E+00;
3.50	79.62	8.70E-01	-1.69E-02	2.00E+00	1.00E+00	1.17E+01	2.00E+00	8.59E-01	1.07E+00	1.07E+00;
4.00	79.62	8.69E-01	-1.02E-02	2.00E+00	1.00E+00	6.79E+00	2.00E+00	9.17E-01	1.07E+00	1.06E+00;
4.50	79.62	8.64E-01	-9.08E-03	2.00E+00	1.00E+00	4.01E+00	2.00E+00	9.22E-01	1.08E+00	1.07E+00;
5.00	79.62	8.80E-01	-2.34E-02	2.00E+00	1.00E+00	2.25E+00	2.00E+00	9.66E-01	1.07E+00	1.06E+00;
5.50	79.62	8.77E-01	-1.97E-02	2.00E+00	1.00E+00	1.26E+00	2.00E+00	9.69E-01	1.07E+00	1.05E+00;
6.00	79.62	8.77E-01	-1.15E-02	2.00E+00	1.00E+00	7.06E-01	2.00E+00	1.05E+00	1.07E+00	1.04E+00;
6.50	79.62	8.93E-01	-2.12E-02	2.00E+00	1.00E+00	4.34E-01	2.00E+00	1.08E+00	1.07E+00	1.01E+00;
7.00	79.62	8.91E-01	-2.06E-02	2.00E+00	1.00E+00	3.06E-01	2.00E+00	1.11E+00	1.07E+00	1.00E+00;
7.50	79.62	8.87E-01	-1.92E-02	2.00E+00	1.00E+00	1.99E-01	2.00E+00	1.12E+00	1.07E+00	9.88E-01;
8.00	79.62	7.90E-01	6.96E-02	2.00E+00	1.00E+00	1.06E-01	2.00E+00	1.09E+00	1.08E+00	9.64E-01;
2.00	126.20	8.67E-01	-1.54E-02	2.00E+00	1.00E+00	1.06E+01	2.00E+00	8.24E-01	1.08E+00	1.07E+00;
2.50	126.20	8.70E-01	-1.99E-02	2.00E+00	1.00E+00	1.11E+01	2.00E+00	8.25E-01	1.08E+00	1.07E+00;
3.00	126.20	8.68E-01	-2.25E-02	2.00E+00	1.00E+00	9.66E+00	2.00E+00	8.31E-01	1.08E+00	1.07E+00;
3.50	126.20	8.69E-01	-2.90E-02	2.00E+00	1.00E+00	9.08E+00	2.00E+00	8.38E-01	1.08E+00	1.08E+00;
4.00	126.20	8.66E-01	-1.41E-02	2.00E+00	1.00E+00	5.26E+00	2.00E+00	9.05E-01	1.08E+00	1.08E+00;
4.50	126.20	8.67E-01	-1.24E-02	2.00E+00	1.00E+00	3.47E+00	2.00E+00	9.22E-01	1.07E+00	1.06E+00;
5.00	126.20	8.83E-01	-3.09E-02	2.00E+00	1.00E+00	2.31E+00	2.00E+00	9.33E-01	1.07E+00	1.05E+00;
5.50	126.20	8.87E-01	-3.49E-02	2.00E+00	1.00E+00	1.33E+00	2.00E+00	9.58E-01	1.07E+00	1.04E+00;
6.00	126.20	8.85E-01	-4.67E-03	2.00E+00	1.00E+00	6.42E-01	2.00E+00	1.11E+00	1.06E+00	1.04E+00;
6.50	126.20	8.83E-01	-7.45E-03	2.00E+00	1.00E+00	4.14E-01	2.00E+00	1.11E+00	1.06E+00	1.02E+00;
7.00	126.20	9.14E-01	-3.72E-02	2.00E+00	1.00E+00	3.05E-01	2.00E+00	1.13E+00	1.06E+00	9.97E-01;
7.50	126.20	8.54E-01	1.79E-02	2.00E+00	1.00E+00	1.91E-01	2.00E+00	1.12E+00	1.07E+00	9.80E-01;
8.00	126.20	8.06E-01	6.96E-02	2.00E+00	1.00E+00	1.13E-01	2.00E+00	1.17E+00	1.07E+00	9.62E-01;
2.00	200.01	8.56E-01	-1.56E-02	2.00E+00	1.00E+00	1.03E+01	2.00E+00	8.08E-01	1.09E+00	1.07E+00;
2.50	200.01	8.54E-01	-2.40E-02	2.00E+00	1.00E+00	1.13E+01	2.00E+00	7.70E-01	1.09E+00	1.09E+00;
3.00	200.01	8.57E-01	-2.40E-02	2.00E+00	1.00E+00	1.16E+01	2.00E+00	7.70E-01	1.09E+00	1.07E+00;
3.50	200.01	8.67E-01	-2.90E-02	2.00E+00	1.00E+00	9.08E+00	2.00E+00	8.30E-01	1.09E+00	1.08E+00;
4.00	200.01	8.69E-01	-2.93E-02	2.00E+00	1.00E+00	7.53E+00	2.00E+00	8.32E-01	1.08E+00	1.07E+00;
4.50	200.01	8.73E-01	-3.34E-02	2.00E+00	1.00E+00	5.56E+00	2.00E+00	8.32E-01	1.08E+00	1.07E+00;
5.00	200.01	8.81E-01	-3.48E-02	2.00E+00	1.00E+00	3.46E+00	2.00E+00	8.72E-01	1.08E+00	1.06E+00;
5.50	200.01	9.15E-01	-6.55E-02	2.00E+00	1.00E+00	2.27E+00	2.00E+00	9.25E-01	1.07E+00	1.05E+00;
6.00	200.01	9.16E-01	-5.45E-02	2.00E+00	1.00E+00	1.37E+00	2.00E+00	9.66E-01	1.07E+00	1.05E+00;
6.50	200.01	8.12E-01	6.67E-02	2.00E+00	1.00E+00	5.05E-01	2.00E+00	1.06E+00	1.06E+00	1.03E+00;
7.00	200.01	8.10E-01	7.00E-02	2.00E+00	1.00E+00	3.05E-01	2.00E+00	1.11E+00	1.06E+00	1.02E+00;
7.50	200.01	8.40E-01	3.43E-02	2.00E+00	1.00E+00	2.54E-01	2.00E+00	1.17E+00	1.07E+00	1.01E+00;
8.00	200.01	8.39E-01	3.23E-02	2.00E+00	1.00E+00	1.87E-01	2.00E+00	1.17E+00	1.07E+00	9.74E-01;
2.00	317.00	9.43E-01	-1.02E-01	2.00E+00	1.00E+00	1.21E+01	2.00E+00	7.87E-01	1.08E+00	1.08E+00;
2.50	317.00	8.98E-01	-6.21E-02	2.00E+00	1.00E+00	1.02E+01	2.00E+00	7.73E-01	1.09E+00	1.08E+00;
3.00	317.00	8.87E-01	-5.91E-02	2.00E+00	1.00E+00	1.05E+01	2.00E+00	7.62E-01	1.09E+00	1.09E+00;
3.50	317.00	8.88E-01	-5.91E-02	2.00E+00	1.00E+00	9.81E+00	2.00E+00	7.62E-01	1.09E+00	1.08E+00;
4.00	317.00	8.79E-01	-2.97E-02	2.00E+00	1.00E+00	7.52E+00	2.00E+00	8.23E-01	1.08E+00	1.08E+00;
4.50	317.00	8.67E-01	-3.08E-02	2.00E+00	1.00E+00	5.96E+00	2.00E+00	8.07E-01	1.08E+00	1.07E+00;
5.00	317.00	8.69E-01	-3.36E-02	2.00E+00	1.00E+00	5.00E+00	2.00E+00	8.24E-01	1.08E+00	1.08E+00;
5.50	317.00	9.22E-01	-6.81E-02	2.00E+00	1.00E+00	3.09E+00	2.00E+00	9.07E-01	1.08E+00	1.07E+00;
6.00	317.00	9.16E-01	-5.09E-02	2.00E+00	1.00E+00	2.01E+00	2.00E+00	9.57E-01	1.07E+00	1.05E+00;
6.50	317.00	9.05E-01	-5.09E-02	2.00E+00	1.00E+00	1.30E+00	2.00E+00	9.57E-01	1.07E+00	1.05E+00;
7.00	317.00	7.84E-01	9.62E-02	2.00E+00	1.00E+00	4.18E-01	2.00E+00	1.10E+00	1.06E+00	1.04E+00;
7.50	317.00	8.33E-01	3.42E-02	2.00E+00	1.00E+00	2.99E-01	2.00E+00	1.12E+00	1.07E+00	1.02E+00;
8.00	317.00	8.48E-01	3.23E-02	2.00E+00	1.00E+00	1.87E-01	2.00E+00	1.17E+00	1.07E+00	9.92E-01;
2.00	502.41	9.28E-01	-9.26E-02	2.00E+00	1.00E+00	6.71E+00	2.00E+00	7.45E-01	1.08E+00	1.08E+00;
2.50	502.41	9.23E-01	-9.30E-02	2.00E+00	1.00E+00	6.52E+00	2.00E+00	7.44E-01	1.09E+00	1.08E+00;
3.00	502.41	9.27E-01	-9.51E-02	2.00E+00	1.00E+00	6.52E+00	2.00E+00	7.57E-01	1.09E+00	1.07E+00;
3.50	502.41	9.27E-01	-9.25E-02	2.00E+00	1.00E+00	6.01E+00	2.00E+00	7.57E-01	1.09E+00	1.08E+00;
4.00	502.41	9.18E-01	-9.25E-02	2.00E+00	1.00E+00	6.01E+00	2.00E+00	7.57E-01	1.09E+00	1.08E+00;
4.50	502.41	8.63E-01	-1.46E-02	2.00E+00	1.00E+00	4.55E+00	2.00E+00	8.12E-01	1.07E+00	1.07E+00;
5.00	502.41	8.64E-01	-3.31E-02	2.00E+00	1.00E+00	3.53E+00	2.00E+00	8.25E-01	1.09E+00	1.08E+00;
5.50	502.41	9.22E-01	-6.59E-02	2.00E+00	1.00E+00	3.32E+00	2.00E+00	9.05E-01	1.07E+00	1.07E+00;
6.00	502.41	9.16E-01	-5.09E-02	2.00E+00	1.00E+00	2.01E+00	2.00E+00	9.57E-01	1.07E+00	1.06E+00;
6.50	502.41	8.75E-01	9.81E-03	2.00E+00	1.00E+00	1.25E+00	2.00E+00	9.97E-01	1.06E+00	1.05E+00;
7.00	502.41	7.79E-01	9.10E-02	2.00E+00	1.00E+00	5.57E-01	2.00E+00	1.07E+00	1.07E+00	1.05E+00;
7.50	502.41	7.96E-01	9.16E-02	2.00E+00	1.00E+00	2.64E-01	2.00E+00	1.16E+00	1.06E+00	1.04E+00;
8.00	502.41	8.53E-01	3.23E-02	2.00E+00	1.00E+00	1.92E-01	2.00E+00	1.17E+00	1.06E+00	1.00E+00;
2.00	796.26	9.17E-01	-8.91E-02	2.00E+00	1.00E+00	3.60E+00	2.00E+00	7.48E-01	1.09E+00	1.07E+00;
2.50	796.26	9.17E-01	-7.64E-02	2.00E+00	1.00E+00	3.60E+00	2.00E+00	7.79E-01	1.08E+00	1.08E+00;
3.00	796.26	9.14E-01	-7.40E-02	2.00E+00	1.00E+00	3.33E+00	2.00E+00	7.79E-01	1.08E+00	1.08E+00;
3.50	796.26	9.16E-01	-7.70E-02	2.00E+00	1.00E+00	3.36E+00	2.00E+00	7.86E-01	1.08E+00	1.08E+00;
4.00	796.26	9.18E-01	-7.88E-02	2.00E+00	1.00E+00	3.51E+00	2.00E+00	7.89E-01	1.08E+00	1.08E+00;
4.50	796.26	8.72E-01	-3.31E-02	2.00E+00	1.00E+00	2.60E+00	2.00E+00	8.12E-01	1.08E+00	1.08E+00;
5.00	796.26	8.72E-01	-3.09E-02	2.00E+00	1.00E+00	2.55E+00	2.00E+00	8.06E-01	1.08E+00	1.08E+00;
5.50	796.26	9.24E-01	-8.56E-02	2.00E+00	1.00E+00	2.12E+00	2.00E+00	8.66E-01	1.09E+00	1.08E+00;
6.00	796.26	9.02E-01	-5.29E-02	2.00E+00	1.00E+00	1.89E+00	2.00E+00	8.98E-01	1.08E+00	1.07E+00;
6.50	796.26	8.50E-01	9.81E-03	2.00E+00	1.00E+00	1.17E+00	2.00E+00	9.79E-01	1.07E+00	1.06E+00;
7.00	796.26	8.49E-01	8.98E-03	2.00E+00	1.00E+00	6.98E-01	2.00E+00	9.83E-01	1.07E+00	1.05E+00;
7.50	796.26	8.61E-01	2.80E-02	2.00E+00	1.00E+00	3.00E-01	2.00E+00	1.14E+00	1.06E+00	1.04E+00;
8.00	796.26	8.65E-01	2.74E-02	2.00E+00	1.00E+00	8.62E-02	2.00E+00	1.23E+00	1.06E+00	1.02E+00;
2.00	1262.00	7.65E-01	8.02E-02	2.00E+00	1.00E+00	8.90E-01	2.00E+00	8.18E-01	1.08E+00	1.07E+00;
2.50	1262.00	7.63E-01	8.02E-02	2.00E+00	1.00E+00	7.95E-01	2.00E+00	8.14E-01	1.08E+00	1.07E+00;
3.00	1262.00	7.64E-01	8.05E-02	2.00E+00	1.00E+00	7.48E-01	2.00E+00	8.18E-01	1.08E+00	1.07E+00;
3.50	1262.00	7.50E-01	8.04E-02	2.00E+00	1.00E+00	7.40E-01	2.00E+00	8.03E-01	1.09E+00	1.08E+00;
4.00	1262.00	9.87E-01	-1.40E-01	2.00E+00	1.00E+00	1.68E+00	2.00E+00	8.39E-01	1.08E+00	1.07E+00;
4.50	1262.00	9.82E-01	-1.45E-01	2.00E+00	1.00E+00	1.35E+00	2.00E+00	8.20E-01	1.09E+00	1.07E+00;
5.00	1262.00	9.93E-01	-1.40E-01	2.00E+00	1.00E+00	1.68E+00	2.00E+00	8.50E-01	1.07E+00	1.08E+00;
5.50	1262.00	9.72E-01	-1.21E-01	2.00E+00	1.00E+00	1.20E+00	2.00E+00	8.71E-01	1.08E+00	1.07E+00;
6.00	1262.00	9.00E-01	-5.20E-02	2.00E+00	1.00E+00	1.10E+00	2.00E+00	9.00E-01	1.08E+00	1.07E+00;
6.50	1262.00	8.51E-01	-8.69E-03	2.00E+00	1.00E+00	2.15E-01	2.00E+00	9.31E-01	1.08E+00	1.07E+00;
7.00	1262.00	8.74E-01	-4.90E-03	2.00E+00	1.00E+00	2.06E-03	2.00E+00	1.03E+00	1.07E+00	1.06E+00;
7.50	1262.00	9.11E-01	-2.45E-02	2.00E+00	1.00E+00	5.54E-06	2.00E+00	1.17E+00	1.06E+00	1.05E+00;
8.00	1262.00	9.16E-01	-2.36E-02	2.00E+00	1.00E+00	1.51E-09	2.00E+00	1.21E+00	1.05E+00	1.04E+00 ]

const coefs_ena_bt15 = [ 2.00	2.00	9.29E-01	-1.27E-02	2.00E+00	1.00E+00	1.41E+00	1.90E+00	1.15E+00	1.05E+00	1.05E+00;
2.50	2.00	9.20E-01	-2.34E-02	2.00E+00	1.00E+00	1.19E+00	1.89E+00	1.11E+00	1.05E+00	1.05E+00;
3.00	2.00	9.38E-01	-2.74E-02	2.00E+00	1.00E+00	8.36E-01	1.91E+00	1.19E+00	1.05E+00	1.05E+00;
3.50	2.00	9.80E-01	-5.66E-02	2.00E+00	1.00E+00	5.75E-01	1.89E+00	1.35E+00	1.05E+00	1.03E+00;
4.00	2.00	1.03E+00	-1.01E-01	2.00E+00	1.00E+00	5.04E-01	1.85E+00	1.34E+00	1.06E+00	1.02E+00;
4.50	2.00	1.04E+00	-1.14E-01	2.00E+00	1.00E+00	4.30E-01	1.79E+00	1.37E+00	1.05E+00	1.01E+00;
5.00	2.00	1.06E+00	-1.41E-01	2.00E+00	1.00E+00	3.77E-01	1.76E+00	1.43E+00	1.05E+00	9.81E-01;
5.50	2.00	1.06E+00	-1.41E-01	2.00E+00	1.00E+00	3.48E-01	1.72E+00	1.43E+00	1.06E+00	9.55E-01;
6.00	2.00	9.48E-01	-5.23E-02	2.00E+00	1.00E+00	2.23E-01	1.77E+00	1.29E+00	1.07E+00	9.54E-01;
6.50	2.00	9.48E-01	-5.22E-02	2.00E+00	1.00E+00	2.06E-01	1.77E+00	1.28E+00	1.07E+00	9.36E-01;
7.00	2.00	8.56E-01	2.30E-02	2.00E+00	1.00E+00	1.34E-01	1.88E+00	1.22E+00	1.08E+00	9.23E-01;
7.50	2.00	8.52E-01	2.46E-02	2.00E+00	1.00E+00	1.24E-01	1.88E+00	1.22E+00	1.08E+00	9.08E-01;
8.00	2.00	8.45E-01	2.16E-02	2.00E+00	1.00E+00	1.13E-01	1.82E+00	1.13E+00	1.08E+00	9.05E-01;
2.00	3.17	9.11E-01	-3.46E-02	2.00E+00	1.00E+00	2.70E+00	2.06E+00	9.58E-01	1.05E+00	1.06E+00;
2.50	3.17	9.10E-01	-3.94E-02	2.00E+00	1.00E+00	1.92E+00	2.03E+00	9.58E-01	1.07E+00	1.06E+00;
3.00	3.17	9.50E-01	-6.92E-02	2.00E+00	1.00E+00	1.21E+00	2.10E+00	1.07E+00	1.05E+00	1.06E+00;
3.50	3.17	9.73E-01	-4.57E-02	2.00E+00	1.00E+00	7.38E-01	2.05E+00	1.28E+00	1.06E+00	1.04E+00;
4.00	3.17	9.96E-01	-1.01E-01	2.00E+00	1.00E+00	5.96E-01	1.99E+00	1.19E+00	1.06E+00	1.03E+00;
4.50	3.17	9.99E-01	-9.17E-02	2.00E+00	1.00E+00	4.77E-01	1.90E+00	1.28E+00	1.05E+00	1.02E+00;
5.00	3.17	1.05E+00	-1.29E-01	2.00E+00	1.00E+00	4.23E-01	1.84E+00	1.41E+00	1.06E+00	9.81E-01;
5.50	3.17	9.97E-01	-8.61E-02	2.00E+00	1.00E+00	3.50E-01	1.73E+00	1.35E+00	1.07E+00	9.76E-01;
6.00	3.17	9.51E-01	-6.70E-02	2.00E+00	1.00E+00	2.86E-01	1.76E+00	1.30E+00	1.06E+00	9.45E-01;
6.50	3.17	9.04E-01	-1.56E-02	2.00E+00	1.00E+00	2.05E-01	1.78E+00	1.27E+00	1.07E+00	9.32E-01;
7.00	3.17	8.44E-01	3.24E-02	2.00E+00	1.00E+00	1.34E-01	1.88E+00	1.22E+00	1.08E+00	9.28E-01;
7.50	3.17	8.44E-01	3.26E-02	2.00E+00	1.00E+00	1.16E-01	1.89E+00	1.22E+00	1.07E+00	8.98E-01;
8.00	3.17	8.28E-01	3.91E-02	2.00E+00	1.00E+00	9.04E-02	1.87E+00	1.12E+00	1.09E+00	8.98E-01;
2.00	5.02	9.03E-01	-2.31E-02	2.00E+00	1.00E+00	4.70E+00	2.03E+00	9.16E-01	1.06E+00	1.06E+00;
2.50	5.02	9.09E-01	-1.77E-02	2.00E+00	1.00E+00	2.89E+00	2.06E+00	1.01E+00	1.07E+00	1.06E+00;
3.00	5.02	9.08E-01	-3.10E-02	2.00E+00	1.00E+00	2.07E+00	2.04E+00	1.00E+00	1.06E+00	1.05E+00;
3.50	5.02	9.40E-01	-4.10E-02	2.00E+00	1.00E+00	1.21E+00	2.08E+00	1.11E+00	1.07E+00	1.06E+00;
4.00	5.02	9.56E-01	-6.43E-02	2.00E+00	1.00E+00	7.86E-01	2.04E+00	1.15E+00	1.06E+00	1.04E+00;
4.50	5.02	9.53E-01	-6.41E-02	2.00E+00	1.00E+00	6.75E-01	1.92E+00	1.15E+00	1.07E+00	1.04E+00;
5.00	5.02	9.77E-01	-7.32E-02	2.00E+00	1.00E+00	5.21E-01	1.81E+00	1.28E+00	1.06E+00	1.01E+00;
5.50	5.02	1.02E+00	-1.24E-01	2.00E+00	1.00E+00	4.02E-01	1.81E+00	1.31E+00	1.06E+00	9.69E-01;
6.00	5.02	9.36E-01	-4.62E-02	2.00E+00	1.00E+00	2.86E-01	1.78E+00	1.28E+00	1.07E+00	9.61E-01;
6.50	5.02	8.92E-01	-1.15E-02	2.00E+00	1.00E+00	2.10E-01	1.80E+00	1.18E+00	1.07E+00	9.36E-01;
7.00	5.02	8.21E-01	5.64E-02	2.00E+00	1.00E+00	1.34E-01	1.89E+00	1.19E+00	1.07E+00	9.40E-01;
7.50	5.02	8.21E-01	4.97E-02	2.00E+00	1.00E+00	1.11E-01	1.92E+00	1.17E+00	1.08E+00	9.23E-01;
8.00	5.02	8.09E-01	5.00E-02	2.00E+00	1.00E+00	9.04E-02	1.90E+00	1.11E+00	1.08E+00	8.94E-01;
2.00	7.96	8.92E-01	-7.58E-03	2.00E+00	1.00E+00	8.62E+00	2.04E+00	9.17E-01	1.07E+00	1.07E+00;
2.50	7.96	8.96E-01	-1.84E-02	2.00E+00	1.00E+00	5.22E+00	2.06E+00	9.44E-01	1.07E+00	1.05E+00;
3.00	7.96	8.97E-01	-3.22E-02	2.00E+00	1.00E+00	3.75E+00	2.07E+00	9.16E-01	1.08E+00	1.06E+00;
3.50	7.96	8.92E-01	-3.79E-02	2.00E+00	1.00E+00	2.45E+00	2.05E+00	9.15E-01	1.08E+00	1.06E+00;
4.00	7.96	9.00E-01	-2.92E-02	2.00E+00	1.00E+00	1.44E+00	1.95E+00	9.95E-01	1.06E+00	1.04E+00;
4.50	7.96	9.52E-01	-6.98E-02	2.00E+00	1.00E+00	7.96E-01	2.06E+00	1.11E+00	1.06E+00	1.04E+00;
5.00	7.96	9.51E-01	-7.59E-02	2.00E+00	1.00E+00	5.52E-01	1.97E+00	1.11E+00	1.07E+00	1.02E+00;
5.50	7.96	9.58E-01	-7.26E-02	2.00E+00	1.00E+00	4.54E-01	1.88E+00	1.20E+00	1.07E+00	9.80E-01;
6.00	7.96	9.61E-01	-6.65E-02	2.00E+00	1.00E+00	3.30E-01	1.84E+00	1.18E+00	1.07E+00	9.59E-01;
6.50	7.96	8.89E-01	-1.09E-02	2.00E+00	1.00E+00	2.11E-01	1.85E+00	1.17E+00	1.07E+00	9.38E-01;
7.00	7.96	8.21E-01	5.64E-02	2.00E+00	1.00E+00	1.34E-01	1.89E+00	1.13E+00	1.08E+00	9.44E-01;
7.50	7.96	8.21E-01	5.26E-02	2.00E+00	1.00E+00	1.10E-01	1.95E+00	1.16E+00	1.07E+00	9.13E-01;
8.00	7.96	8.09E-01	5.02E-02	2.00E+00	1.00E+00	9.48E-02	1.89E+00	1.06E+00	1.08E+00	9.04E-01;
2.00	12.62	8.80E-01	-1.09E-02	2.00E+00	1.00E+00	1.44E+01	1.97E+00	8.61E-01	1.08E+00	1.07E+00;
2.50	12.62	8.77E-01	-1.29E-02	2.00E+00	1.00E+00	1.09E+01	1.98E+00	8.50E-01	1.08E+00	1.07E+00;
3.00	12.62	8.94E-01	-2.13E-02	2.00E+00	1.00E+00	6.61E+00	2.11E+00	9.07E-01	1.07E+00	1.07E+00;
3.50	12.62	8.92E-01	-3.71E-02	2.00E+00	1.00E+00	4.01E+00	2.16E+00	9.08E-01	1.08E+00	1.07E+00;
4.00	12.62	9.01E-01	-3.09E-02	2.00E+00	1.00E+00	2.09E+00	2.06E+00	9.64E-01	1.08E+00	1.06E+00;
4.50	12.62	9.45E-01	-7.00E-02	2.00E+00	1.00E+00	1.35E+00	2.15E+00	1.03E+00	1.07E+00	1.04E+00;
5.00	12.62	9.77E-01	-1.02E-01	2.00E+00	1.00E+00	9.01E-01	2.07E+00	1.06E+00	1.07E+00	1.01E+00;
5.50	12.62	1.01E+00	-1.29E-01	2.00E+00	1.00E+00	5.91E-01	2.00E+00	1.11E+00	1.07E+00	9.96E-01;
6.00	12.62	9.42E-01	-6.54E-02	2.00E+00	1.00E+00	3.90E-01	1.88E+00	1.14E+00	1.07E+00	9.74E-01;
6.50	12.62	9.40E-01	-7.12E-02	2.00E+00	1.00E+00	3.00E-01	1.87E+00	1.12E+00	1.07E+00	9.46E-01;
7.00	12.62	7.88E-01	8.40E-02	2.00E+00	1.00E+00	1.30E-01	1.94E+00	1.13E+00	1.08E+00	9.46E-01;
7.50	12.62	7.88E-01	8.09E-02	2.00E+00	1.00E+00	8.08E-02	2.11E+00	1.15E+00	1.07E+00	9.23E-01;
8.00	12.62	7.92E-01	7.05E-02	2.00E+00	1.00E+00	4.83E-02	2.28E+00	1.07E+00	1.08E+00	9.09E-01;
2.00	20.00	8.54E-01	-3.91E-03	2.00E+00	1.00E+00	6.77E+01	1.83E+00	7.47E-01	1.09E+00	1.08E+00;
2.50	20.00	8.48E-01	-3.92E-03	2.00E+00	1.00E+00	4.46E+01	1.85E+00	7.70E-01	1.09E+00	1.08E+00;
3.00	20.00	8.43E-01	-1.93E-03	2.00E+00	1.00E+00	2.99E+01	1.88E+00	7.54E-01	1.09E+00	1.07E+00;
3.50	20.00	8.38E-01	-5.17E-03	2.00E+00	1.00E+00	1.71E+01	1.87E+00	7.58E-01	1.08E+00	1.08E+00;
4.00	20.00	8.28E-01	2.97E-03	2.00E+00	1.00E+00	8.98E+00	1.85E+00	7.70E-01	1.08E+00	1.06E+00;
4.50	20.00	9.01E-01	-6.28E-02	2.00E+00	1.00E+00	5.92E+00	2.30E+00	8.47E-01	1.08E+00	1.06E+00;
5.00	20.00	8.99E-01	-5.38E-02	2.00E+00	1.00E+00	2.99E+00	2.14E+00	8.59E-01	1.08E+00	1.04E+00;
5.50	20.00	8.99E-01	-4.81E-02	2.00E+00	1.00E+00	1.45E+00	2.03E+00	9.10E-01	1.08E+00	1.02E+00;
6.00	20.00	8.89E-01	-4.06E-02	2.00E+00	1.00E+00	7.91E-01	1.94E+00	9.21E-01	1.07E+00	1.01E+00;
6.50	20.00	8.99E-01	-3.99E-02	2.00E+00	1.00E+00	5.11E-01	1.92E+00	1.02E+00	1.08E+00	9.93E-01;
7.00	20.00	9.00E-01	-4.37E-02	2.00E+00	1.00E+00	3.20E-01	1.92E+00	1.05E+00	1.07E+00	9.73E-01;
7.50	20.00	9.00E-01	-4.30E-02	2.00E+00	1.00E+00	2.34E-01	1.91E+00	1.08E+00	1.08E+00	9.42E-01;
8.00	20.00	7.78E-01	7.59E-02	2.00E+00	1.00E+00	4.83E-02	2.56E+00	1.06E+00	1.08E+00	9.28E-01;
2.00	31.70	8.45E-01	2.02E-03	2.00E+00	1.00E+00	2.00E+02	1.76E+00	7.32E-01	1.09E+00	1.09E+00;
2.50	31.70	8.45E-01	-5.58E-03	2.00E+00	1.00E+00	1.08E+02	1.70E+00	7.30E-01	1.10E+00	1.09E+00;
3.00	31.70	8.41E-01	-1.08E-02	2.00E+00	1.00E+00	8.64E+01	1.77E+00	6.97E-01	1.09E+00	1.09E+00;
3.50	31.70	8.33E-01	-5.48E-03	2.00E+00	1.00E+00	4.94E+01	1.81E+00	7.33E-01	1.09E+00	1.08E+00;
4.00	31.70	8.34E-01	-5.48E-03	2.00E+00	1.00E+00	2.98E+01	1.80E+00	7.21E-01	1.09E+00	1.08E+00;
4.50	31.70	8.34E-01	-5.48E-03	2.00E+00	1.00E+00	1.37E+01	1.86E+00	7.39E-01	1.09E+00	1.07E+00;
5.00	31.70	9.04E-01	-6.29E-02	2.00E+00	1.00E+00	8.88E+00	2.32E+00	8.18E-01	1.08E+00	1.06E+00;
5.50	31.70	8.92E-01	-5.15E-02	2.00E+00	1.00E+00	3.99E+00	2.16E+00	8.12E-01	1.08E+00	1.05E+00;
6.00	31.70	8.92E-01	-4.99E-02	2.00E+00	1.00E+00	2.05E+00	2.11E+00	8.49E-01	1.08E+00	1.02E+00;
6.50	31.70	8.97E-01	-5.50E-02	2.00E+00	1.00E+00	1.02E+00	2.04E+00	8.86E-01	1.07E+00	1.00E+00;
7.00	31.70	9.12E-01	-5.74E-02	2.00E+00	1.00E+00	5.88E-01	2.00E+00	9.85E-01	1.08E+00	9.96E-01;
7.50	31.70	8.98E-01	-4.83E-02	2.00E+00	1.00E+00	4.22E-01	1.88E+00	9.88E-01	1.08E+00	9.61E-01;
8.00	31.70	7.14E-01	1.34E-01	2.00E+00	1.00E+00	4.68E-02	2.85E+00	9.96E-01	1.08E+00	9.41E-01;
2.00	50.24	8.23E-01	9.71E-03	2.00E+00	1.00E+00	1.99E+02	1.45E+00	6.53E-01	1.10E+00	1.09E+00;
2.50	50.24	8.17E-01	4.57E-03	2.00E+00	1.00E+00	1.92E+02	1.52E+00	6.37E-01	1.10E+00	1.09E+00;
3.00	50.24	8.16E-01	4.75E-03	2.00E+00	1.00E+00	1.21E+02	1.53E+00	6.53E-01	1.09E+00	1.09E+00;
3.50	50.24	8.31E-01	-1.80E-03	2.00E+00	1.00E+00	6.94E+01	1.64E+00	7.11E-01	1.09E+00	1.08E+00;
4.00	50.24	8.28E-01	-1.80E-03	2.00E+00	1.00E+00	4.47E+01	1.70E+00	7.11E-01	1.09E+00	1.08E+00;
4.50	50.24	8.40E-01	-8.55E-03	2.00E+00	1.00E+00	2.47E+01	1.86E+00	7.43E-01	1.08E+00	1.08E+00;
5.00	50.24	8.41E-01	-1.05E-02	2.00E+00	1.00E+00	1.42E+01	1.87E+00	7.48E-01	1.09E+00	1.07E+00;
5.50	50.24	8.81E-01	-4.36E-02	2.00E+00	1.00E+00	7.52E+00	2.11E+00	8.01E-01	1.09E+00	1.06E+00;
6.00	50.24	9.08E-01	-6.64E-02	2.00E+00	1.00E+00	3.80E+00	2.20E+00	8.44E-01	1.08E+00	1.06E+00;
6.50	50.24	9.03E-01	-6.34E-02	2.00E+00	1.00E+00	1.81E+00	2.17E+00	8.72E-01	1.09E+00	1.04E+00;
7.00	50.24	8.99E-01	-6.06E-02	2.00E+00	1.00E+00	9.85E-01	2.07E+00	9.32E-01	1.08E+00	1.01E+00;
7.50	50.24	9.06E-01	-5.68E-02	2.00E+00	1.00E+00	5.25E-01	2.06E+00	9.78E-01	1.09E+00	9.83E-01;
8.00	50.24	9.02E-01	-5.65E-02	2.00E+00	1.00E+00	4.38E-01	1.85E+00	9.78E-01	1.09E+00	9.61E-01;
2.00	79.62	8.13E-01	9.64E-03	2.00E+00	1.00E+00	1.62E+02	1.47E+00	6.28E-01	1.10E+00	1.09E+00;
2.50	79.62	8.15E-01	4.60E-03	2.00E+00	1.00E+00	1.40E+02	1.52E+00	6.36E-01	1.10E+00	1.09E+00;
3.00	79.62	8.15E-01	3.78E-03	2.00E+00	1.00E+00	9.38E+01	1.57E+00	6.57E-01	1.09E+00	1.09E+00;
3.50	79.62	8.31E-01	-1.75E-03	2.00E+00	1.00E+00	5.71E+01	1.64E+00	7.08E-01	1.09E+00	1.08E+00;
4.00	79.62	8.31E-01	-1.58E-03	2.00E+00	1.00E+00	3.60E+01	1.73E+00	7.29E-01	1.09E+00	1.08E+00;
4.50	79.62	8.47E-01	-1.34E-02	2.00E+00	1.00E+00	2.20E+01	1.91E+00	7.56E-01	1.08E+00	1.08E+00;
5.00	79.62	8.40E-01	-1.03E-02	2.00E+00	1.00E+00	1.29E+01	1.85E+00	7.45E-01	1.08E+00	1.07E+00;
5.50	79.62	8.80E-01	-4.34E-02	2.00E+00	1.00E+00	6.95E+00	2.11E+00	8.01E-01	1.09E+00	1.06E+00;
6.00	79.62	9.08E-01	-6.79E-02	2.00E+00	1.00E+00	3.68E+00	2.18E+00	8.43E-01	1.08E+00	1.06E+00;
6.50	79.62	9.02E-01	-6.39E-02	2.00E+00	1.00E+00	1.76E+00	2.15E+00	8.73E-01	1.09E+00	1.04E+00;
7.00	79.62	8.99E-01	-6.06E-02	2.00E+00	1.00E+00	9.65E-01	2.07E+00	9.32E-01	1.08E+00	1.02E+00;
7.50	79.62	9.06E-01	-5.68E-02	2.00E+00	1.00E+00	5.25E-01	2.05E+00	9.78E-01	1.08E+00	9.87E-01;
8.00	79.62	9.06E-01	-6.15E-02	2.00E+00	1.00E+00	4.35E-01	1.87E+00	9.92E-01	1.09E+00	9.67E-01;
2.00	126.20	8.07E-01	1.13E-02	2.00E+00	1.00E+00	9.27E+01	1.48E+00	6.28E-01	1.10E+00	1.10E+00;
2.50	126.20	7.99E-01	1.14E-02	2.00E+00	1.00E+00	7.95E+01	1.51E+00	6.28E-01	1.10E+00	1.10E+00;
3.00	126.20	8.15E-01	1.60E-03	2.00E+00	1.00E+00	6.07E+01	1.56E+00	6.60E-01	1.10E+00	1.09E+00;
3.50	126.20	8.21E-01	4.21E-03	2.00E+00	1.00E+00	4.81E+01	1.68E+00	6.96E-01	1.09E+00	1.09E+00;
4.00	126.20	8.21E-01	4.21E-03	2.00E+00	1.00E+00	2.97E+01	1.68E+00	7.06E-01	1.09E+00	1.08E+00;
4.50	126.20	8.39E-01	-8.12E-03	2.00E+00	1.00E+00	1.85E+01	1.84E+00	7.39E-01	1.09E+00	1.08E+00;
5.00	126.20	8.36E-01	-9.62E-03	2.00E+00	1.00E+00	1.02E+01	1.85E+00	7.46E-01	1.08E+00	1.07E+00;
5.50	126.20	8.37E-01	2.48E-03	2.00E+00	1.00E+00	4.92E+00	1.91E+00	8.11E-01	1.08E+00	1.06E+00;
6.00	126.20	9.19E-01	-7.39E-02	2.00E+00	1.00E+00	3.31E+00	2.14E+00	8.67E-01	1.08E+00	1.05E+00;
6.50	126.20	9.04E-01	-6.36E-02	2.00E+00	1.00E+00	1.55E+00	2.12E+00	8.89E-01	1.08E+00	1.04E+00;
7.00	126.20	9.10E-01	-6.30E-02	2.00E+00	1.00E+00	9.99E-01	2.01E+00	9.37E-01	1.08E+00	1.01E+00;
7.50	126.20	9.10E-01	-5.98E-02	2.00E+00	1.00E+00	4.80E-01	2.11E+00	9.96E-01	1.09E+00	9.99E-01;
8.00	126.20	9.11E-01	-6.10E-02	2.00E+00	1.00E+00	3.88E-01	1.98E+00	1.03E+00	1.08E+00	9.65E-01;
2.00	200.01	8.03E-01	1.14E-02	2.00E+00	1.00E+00	5.52E+01	1.54E+00	6.35E-01	1.10E+00	1.10E+00;
2.50	200.01	8.05E-01	1.04E-02	2.00E+00	1.00E+00	5.48E+01	1.56E+00	6.42E-01	1.10E+00	1.10E+00;
3.00	200.01	7.96E-01	9.85E-03	2.00E+00	1.00E+00	4.57E+01	1.61E+00	6.42E-01	1.10E+00	1.09E+00;
3.50	200.01	8.17E-01	4.13E-03	2.00E+00	1.00E+00	3.42E+01	1.67E+00	6.94E-01	1.09E+00	1.09E+00;
4.00	200.01	8.21E-01	3.96E-03	2.00E+00	1.00E+00	2.26E+01	1.69E+00	7.14E-01	1.09E+00	1.09E+00;
4.50	200.01	8.36E-01	-5.16E-03	2.00E+00	1.00E+00	1.55E+01	1.81E+00	7.40E-01	1.08E+00	1.09E+00;
5.00	200.01	8.58E-01	-1.69E-02	2.00E+00	1.00E+00	8.78E+00	1.94E+00	7.98E-01	1.08E+00	1.08E+00;
5.50	200.01	8.57E-01	-2.11E-02	2.00E+00	1.00E+00	5.28E+00	1.92E+00	8.12E-01	1.08E+00	1.08E+00;
6.00	200.01	9.16E-01	-7.26E-02	2.00E+00	1.00E+00	3.31E+00	2.12E+00	8.67E-01	1.07E+00	1.05E+00;
6.50	200.01	9.12E-01	-6.39E-02	2.00E+00	1.00E+00	1.72E+00	2.09E+00	9.05E-01	1.07E+00	1.04E+00;
7.00	200.01	9.13E-01	-5.82E-02	2.00E+00	1.00E+00	9.01E-01	2.07E+00	9.64E-01	1.07E+00	1.01E+00;
7.50	200.01	9.09E-01	-4.69E-02	2.00E+00	1.00E+00	5.33E-01	2.03E+00	1.01E+00	1.07E+00	1.01E+00;
8.00	200.01	9.11E-01	-6.10E-02	2.00E+00	1.00E+00	3.73E-01	1.98E+00	1.06E+00	1.08E+00	9.65E-01;
2.00	317.00	7.96E-01	1.29E-02	2.00E+00	1.00E+00	3.56E+01	1.54E+00	6.16E-01	1.10E+00	1.10E+00;
2.50	317.00	8.04E-01	1.04E-02	2.00E+00	1.00E+00	3.17E+01	1.56E+00	6.42E-01	1.10E+00	1.09E+00;
3.00	317.00	7.98E-01	9.68E-03	2.00E+00	1.00E+00	2.78E+01	1.60E+00	6.45E-01	1.10E+00	1.09E+00;
3.50	317.00	8.17E-01	6.15E-03	2.00E+00	1.00E+00	2.27E+01	1.66E+00	6.91E-01	1.09E+00	1.08E+00;
4.00	317.00	8.07E-01	1.58E-02	2.00E+00	1.00E+00	1.68E+01	1.60E+00	7.06E-01	1.09E+00	1.09E+00;
4.50	317.00	8.36E-01	-2.58E-03	2.00E+00	1.00E+00	1.51E+01	1.77E+00	7.40E-01	1.08E+00	1.08E+00;
5.00	317.00	8.62E-01	-1.75E-02	2.00E+00	1.00E+00	9.30E+00	1.84E+00	7.97E-01	1.08E+00	1.08E+00;
5.50	317.00	8.50E-01	-1.08E-02	2.00E+00	1.00E+00	5.28E+00	1.90E+00	8.12E-01	1.08E+00	1.07E+00;
6.00	317.00	9.11E-01	-6.30E-02	2.00E+00	1.00E+00	3.75E+00	2.16E+00	8.89E-01	1.07E+00	1.06E+00;
6.50	317.00	9.01E-01	-4.47E-02	2.00E+00	1.00E+00	1.85E+00	2.09E+00	9.26E-01	1.07E+00	1.05E+00;
7.00	317.00	8.90E-01	-4.04E-02	2.00E+00	1.00E+00	1.17E+00	2.12E+00	9.31E-01	1.07E+00	1.03E+00;
7.50	317.00	9.09E-01	-4.71E-02	2.00E+00	1.00E+00	6.17E-01	2.27E+00	1.04E+00	1.08E+00	1.02E+00;
8.00	317.00	9.47E-01	-8.14E-02	2.00E+00	1.00E+00	5.15E-01	2.08E+00	1.13E+00	1.08E+00	9.94E-01;
2.00	502.41	7.98E-01	1.55E-02	2.00E+00	1.00E+00	1.93E+01	1.55E+00	6.24E-01	1.10E+00	1.09E+00;
2.50	502.41	8.09E-01	7.96E-03	2.00E+00	1.00E+00	1.93E+01	1.64E+00	6.51E-01	1.09E+00	1.09E+00;
3.00	502.41	7.97E-01	1.72E-02	2.00E+00	1.00E+00	1.70E+01	1.59E+00	6.58E-01	1.10E+00	1.09E+00;
3.50	502.41	7.99E-01	2.10E-02	2.00E+00	1.00E+00	1.63E+01	1.56E+00	6.81E-01	1.09E+00	1.09E+00;
4.00	502.41	7.99E-01	2.48E-02	2.00E+00	1.00E+00	1.17E+01	1.60E+00	7.12E-01	1.09E+00	1.09E+00;
4.50	502.41	8.36E-01	-3.24E-03	2.00E+00	1.00E+00	1.12E+01	1.77E+00	7.52E-01	1.09E+00	1.09E+00;
5.00	502.41	8.35E-01	-4.26E-03	2.00E+00	1.00E+00	8.83E+00	1.78E+00	7.54E-01	1.09E+00	1.09E+00;
5.50	502.41	8.53E-01	-1.36E-02	2.00E+00	1.00E+00	5.88E+00	1.89E+00	8.12E-01	1.08E+00	1.07E+00;
6.00	502.41	9.13E-01	-6.23E-02	2.00E+00	1.00E+00	4.09E+00	2.11E+00	8.79E-01	1.08E+00	1.07E+00;
6.50	502.41	9.03E-01	-4.36E-02	2.00E+00	1.00E+00	2.47E+00	2.11E+00	9.26E-01	1.08E+00	1.06E+00;
7.00	502.41	9.03E-01	-4.38E-02	2.00E+00	1.00E+00	1.52E+00	2.16E+00	9.33E-01	1.07E+00	1.05E+00;
7.50	502.41	1.14E+00	-2.86E-01	2.00E+00	1.00E+00	1.83E+00	2.33E+00	1.02E+00	1.08E+00	1.03E+00;
8.00	502.41	1.16E+00	-2.90E-01	2.00E+00	1.00E+00	1.29E+00	2.17E+00	1.10E+00	1.07E+00	1.02E+00;
2.00	796.26	9.55E-01	-1.31E-01	2.00E+00	1.00E+00	1.76E+01	2.00E+00	6.96E-01	1.10E+00	1.10E+00;
2.50	796.26	7.94E-01	2.00E-02	2.00E+00	1.00E+00	9.44E+00	1.60E+00	6.70E-01	1.10E+00	1.10E+00;
3.00	796.26	8.02E-01	1.36E-02	2.00E+00	1.00E+00	9.54E+00	1.62E+00	6.63E-01	1.10E+00	1.09E+00;
3.50	796.26	8.02E-01	1.34E-02	2.00E+00	1.00E+00	9.54E+00	1.54E+00	6.63E-01	1.10E+00	1.09E+00;
4.00	796.26	7.68E-01	5.02E-02	2.00E+00	1.00E+00	7.31E+00	1.51E+00	6.90E-01	1.10E+00	1.09E+00;
4.50	796.26	8.23E-01	6.32E-03	2.00E+00	1.00E+00	8.01E+00	1.74E+00	7.33E-01	1.10E+00	1.09E+00;
5.00	796.26	8.28E-01	1.78E-04	2.00E+00	1.00E+00	6.91E+00	1.75E+00	7.51E-01	1.09E+00	1.08E+00;
5.50	796.26	8.55E-01	-1.67E-02	2.00E+00	1.00E+00	5.63E+00	1.85E+00	7.99E-01	1.08E+00	1.07E+00;
6.00	796.26	8.52E-01	-1.20E-02	2.00E+00	1.00E+00	4.44E+00	2.00E+00	8.20E-01	1.08E+00	1.08E+00;
6.50	796.26	9.03E-01	-4.83E-02	2.00E+00	1.00E+00	3.06E+00	2.26E+00	9.14E-01	1.08E+00	1.07E+00;
7.00	796.26	9.35E-01	-7.41E-02	2.00E+00	1.00E+00	2.38E+00	2.05E+00	9.55E-01	1.08E+00	1.06E+00;
7.50	796.26	1.15E+00	-2.85E-01	2.00E+00	1.00E+00	2.49E+00	2.45E+00	1.03E+00	1.08E+00	1.05E+00;
8.00	796.26	1.18E+00	-3.10E-01	2.00E+00	1.00E+00	1.39E+00	2.42E+00	1.15E+00	1.07E+00	1.04E+00;
2.00	1262.00	1.06E+00	-2.31E-01	2.00E+00	1.00E+00	1.08E+01	1.97E+00	7.07E-01	1.10E+00	1.09E+00;
2.50	1262.00	1.06E+00	-2.32E-01	2.00E+00	1.00E+00	1.04E+01	1.94E+00	7.08E-01	1.10E+00	1.09E+00;
3.00	1262.00	1.06E+00	-2.32E-01	2.00E+00	1.00E+00	1.02E+01	1.94E+00	7.08E-01	1.09E+00	1.09E+00;
3.50	1262.00	1.06E+00	-2.36E-01	2.00E+00	1.00E+00	9.57E+00	1.96E+00	7.05E-01	1.10E+00	1.09E+00;
4.00	1262.00	1.05E+00	-2.36E-01	2.00E+00	1.00E+00	1.03E+01	1.96E+00	7.01E-01	1.10E+00	1.09E+00;
4.50	1262.00	1.07E+00	-2.37E-01	2.00E+00	1.00E+00	1.12E+01	2.07E+00	7.37E-01	1.10E+00	1.09E+00;
5.00	1262.00	8.30E-01	4.11E-03	2.00E+00	1.00E+00	4.26E+00	1.62E+00	7.53E-01	1.10E+00	1.08E+00;
5.50	1262.00	8.48E-01	-2.00E-02	2.00E+00	1.00E+00	4.02E+00	1.83E+00	7.85E-01	1.08E+00	1.08E+00;
6.00	1262.00	8.53E-01	-1.28E-02	2.00E+00	1.00E+00	3.56E+00	1.94E+00	8.23E-01	1.09E+00	1.09E+00;
6.50	1262.00	9.03E-01	-4.83E-02	2.00E+00	1.00E+00	3.17E+00	2.25E+00	9.14E-01	1.08E+00	1.07E+00;
7.00	1262.00	9.52E-01	-8.82E-02	2.00E+00	1.00E+00	3.14E+00	2.59E+00	9.79E-01	1.07E+00	1.06E+00;
7.50	1262.00	1.16E+00	-2.85E-01	2.00E+00	1.00E+00	2.56E+00	2.52E+00	1.04E+00	1.08E+00	1.06E+00;
8.00	1262.00	1.18E+00	-3.07E-01	2.00E+00	1.00E+00	3.10E+00	3.15E+00	1.15E+00	1.07E+00	1.05E+00 ]


text:
# __precompile__()
ENV["PLOTS_TEST"] = "true"
ENV["GKSwstype"] = "100"
module TrackRoots

export main, batch_main

using NDFiles, CSV, Images

const roottips = joinpath(Pkg.dir("RootTips"), "src", "roottips.jl")
const julia_ndfile = joinpath(tempdir(), "JULIA_NDFILE")

include(joinpath(Pkg.dir("TrackRoots"), "src", "utils.jl"))
include(joinpath(Pkg.dir("TrackRoots"), "src", "calibrates.jl"))
include(joinpath(Pkg.dir("TrackRoots"), "src", "tracks.jl"))
include(joinpath(Pkg.dir("TrackRoots"), "src", "saves.jl"))
include(joinpath(Pkg.dir("TrackRoots"), "src", "nodes.jl"))

function get_startpoints(stage)
    path = joinpath(stage.home, stage.base, "stage $(stage.id)")
    file = joinpath(path, "start_points.csv")
    if isfile(file)
        a = readcsv(file, Float64)
        n = size(a, 1)
        [Mark(a[i,1], a[i,2]) for i in 1:n]
    else
        Mark[]
    end
end

function main(ndfile::String)
    stages = nd2stages(ndfile)
    startpoints = get_startpoints.(stages)
    Δx = pixel_width(first(stages))
    main(stages, startpoints, Δx, STDERR)
end

function main(stages::Vector{Stage}, startpoints::Vector{Vector{Mark}}, Δx::Float64, output::IO)
    calibstages = stages2calib(stages, Δx)
    output == STDERR && info("Calibrated the data. Tracking the roots…")
    tracks = trackroot.(calibstages, startpoints)
    output == STDERR && info("Tracked the roots. Saving the results…")
    saveit(calibstages, tracks, output)
    output == STDERR && info("Done!")
end

#=function main(; ndfile::String = open_dialog("Pick an `.nd` file", head, ("*.nd",)), stages::Vector{Stage} = nd2stages(ndfile), Δx::T = pixel_width(first(stages))) where T<:Real
# function main(; ndfile::String = open_dialog("Pick an `.nd` file", GtkNullContainer(), ("*.nd",)), stages::Vector{Stage} = nd2stages(ndfile), Δx::T = pixel_width(stages)) where T<:Real
    startpoints = get_startpoints.(stages)
    info("Aquired the `.nd` file and the starting points of the root-tips. Calibrating the data…")
    main(stages, startpoints, Float64(Δx), STDERR)
end=#

# main(ndfile::String, startpoints::Vector{Vector{Mark}}, output::IO) = main(nd2stages(ndfile), startpoints, output)
# batch

function main(ndfile::String, startpoints::Vector{Vector{Mark}}, output::IO)
    stages = nd2stages(ndfile)
    Δx = pixel_width(first(stages))
    main(stages, startpoints, Δx, output)
end

isnd(file::String) = last(splitext(file)) == ".nd"

function findall_nd(home::String)
    ndfiles = String[]
    for (root, dirs, files) in walkdir(home)
        filter!(isnd, files)
        append!(ndfiles, joinpath.(home, root, files))
    end
    return ndfiles
end

function batch_main(home::String)
    ndfiles = findall_nd(home)
    n = length(ndfiles)
    info("Found $n `.nd` files")
    stagess = [Stage[] for _ in 1:n]
    startpointss = [[Mark[]] for _ in 1:n]
    @showprogress 1 "Collecting start points…" for i in 1:n
        stagess[i] = nd2stages(ndfiles[i])
        startpointss[i] = get_startpoints.(stagess[i])
    end
    @showprogress 1 "Processing the data…" for i in 1:n
        Δx = pixel_width(first(stagess[i]))
        main(stagess[i], startpointss[i], Δx, Base.DevNullStream())
    end
end

end # module


text:
_experimental_warning = """
!!! warning
    This API is experimental.  Backward incompatible change, including
    the removal of this API, is more likely to occur than other parts
    of this package.
"""

_shared_vector_warning = """
!!! warning
    The vector passed to the inner reducing function is valid only
    during its _immediate_ reduction step.  It must be reduced
    immediately _or_ copied.
"""

_shared_notes_unfold = """
Note that input is ignored.  To use the input in the downstream
reduction steps, use [`Zip`](@ref).
"""

_use_initializer = """
Pass [`OnInit`](@ref) or [`CopyInit`](@ref) object to `init` for creating
a dedicated (possibly mutable) state for each fold.
"""

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/map
# https://clojuredocs.org/clojure.core/map
"""
    Map(f)

Apply unary function `f` to each input and pass the result to the
inner reducing step.

$(_thx_clj("map"))

# Examples
```jldoctest
julia> using Transducers

julia> collect(Map(x -> 2x), 1:3)
3-element Vector{Int64}:
 2
 4
 6
```
"""
struct Map{F} <: Transducer
    f::F
end

Map(::Type{T}) where T = Map{Type{T}}(T)  # specialization workaround

OutputSize(::Type{<:Map}) = SizeStable()
isexpansive(::Map) = false
@inline next(rf::R_{Map}, result, input) = next(inner(rf), result, xform(rf).f(input))

Adapt.adapt_structure(to, xf::Map) = Map(Adapt.adapt(to, xf.f))

"""
    MapSplat(f)

Like `Map(f)` but calls `f(input...)` for each `input` and then pass
the result to the inner reducing step.

# Examples
```jldoctest
julia> using Transducers

julia> collect(MapSplat(*), zip(1:3, 10:10:30))
3-element Vector{Int64}:
 10
 40
 90
```
"""
struct MapSplat{F} <: Transducer
    f::F
end

MapSplat(::Type{T}) where T = MapSplat{Type{T}}(T)  # specialization workaround

OutputSize(::Type{<:MapSplat}) = SizeStable()
isexpansive(::MapSplat) = false
@inline next(rf::R_{MapSplat}, result, input) =
    next(inner(rf), result, xform(rf).f(input...))

Adapt.adapt_structure(to, xf::MapSplat) = MapSplat(Adapt.adapt(to, xf.f))

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/replace
# https://clojuredocs.org/clojure.core/replace
"""
    Replace(assoc)

Replace each input with the value in the associative container `assoc`
(e.g., a dictionary, array, string) if it matches with a key/index.
Otherwise output the input as-is.

$(_thx_clj("replace"))

# Examples
```jldoctest
julia> using Transducers

julia> collect(Replace(Dict('a' => 'A')), "abc")
3-element Vector{Char}:
 'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)
 'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
 'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)

julia> collect(Replace([:a, :b, :c]), 0:4)
5-element Vector{Any}:
 0
  :a
  :b
  :c
 4

julia> collect(Replace("abc"), 0:4)
5-element Vector{Any}:
 0
  'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
  'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
  'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
 4
```
"""
struct Replace{D} <: Transducer
    d::D  # dictionary-like object
end

OutputSize(::Type{<:Replace}) = SizeStable()
isexpansive(::Replace) = false
@inline next(rf::R_{Replace}, result, input) =
    next(inner(rf), result, get(xform(rf).d, input, input))

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/cat
# https://clojuredocs.org/clojure.core/cat
"""
    Cat()

Concatenate/flatten nested iterators.

$(_thx_clj("cat"))

# Examples
```jldoctest
julia> using Transducers

julia> collect(Cat(), [[1, 2], [3], [4, 5]]) == 1:5
true
```
"""
struct Cat <: Transducer
end

@inline function next(rf::R_{Cat}, acc, x)
    rf0, itr0 = retransform(inner(rf), x)
    return foldl_nocomplete(rf0, acc, itr0)
end

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/mapcat
# https://clojuredocs.org/clojure.core/mapcat
"""
    MapCat(f)

Concatenate output of `f` which is expected to return an iterable.

$(_thx_clj("mapcat"))

# Examples
```jldoctest
julia> using Transducers

julia> collect(MapCat(x -> 1:x), 1:3)
6-element Vector{Int64}:
 1
 1
 2
 1
 2
 3
```
"""
const MapCat = Composition{<:Map, <:Cat}

MapCat(f) = opcompose(Map(f), Cat())

"""
    TCat(basesize::Integer)

Threaded version of [`Cat`](@ref) (concatenate/flatten).

To use this transducer, all the downstream (inner) transducers must be
stateless (or of type [`ScanEmit`](@ref)) and the reducing function
must be associative.  See also: [Parallel processing tutorial](@ref
tutorial-parallel).

Note that the upstream (outer) transducers need not to be stateless as
long as it is called with non-parallel reduction such as
[`foldl`](@ref) and [`collect`](@ref).

# Examples
```jldoctest
julia> using Transducers

julia> 1:3 |> Map(x -> 1:x) |> TCat(1) |> tcollect
6-element Vector{Int64}:
 1
 1
 2
 1
 2
 3

julia> 1:3 |> Scan(+) |> Map(x -> 1:x) |> TCat(1) |> collect
10-element Vector{Int64}:
 1
 1
 2
 3
 1
 2
 3
 4
 5
 6
```
"""
struct TCat <: Transducer
    basesize::Int
    function TCat(basesize::Integer)
        @argcheck basesize > 0
        return new(Int(basesize))
    end
end

# Do not recurse into `start(inner(rf), ...)`; it's called via transduce
start(rf::R_{TCat}, init) = wrap(rf, init, Unseen())

function complete(rf::R_{TCat}, result)
    init, iresult = unwrap(rf, result)
    iresult isa Unseen && return init  # `next` never called
    return complete(inner(rf), iresult)
end

next(rf::R_{TCat}, result, input) =
    wrapping(rf, result) do init, acc
        rfi, itr = retransform(inner(rf), input)
        subresult = _transduce_assoc_nocomplete(
            rfi,
            init,
            itr,
            xform(rf).basesize,
        )
        subresult isa Reduced && return init, subresult
        acc isa Unseen && return init, subresult
        return init, combine(rfi, acc, subresult)
    end

function combine(rf::R_{TCat}, a, b)
    ua, ira = unwrap(rf, a)
    ira isa Unseen && return b  # this handles `irb isa Unseen` as well
    ub, irb = unwrap(rf, b)
    # @assert ua == ub  # == init
    irc = combine(inner(rf), ira, irb)
    return wrap(rf, ua, irc)
end

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/filter
# https://clojuredocs.org/clojure.core/filter
"""
    Filter(pred)

Skip items for which `pred` is evaluated to `false`.

$(_thx_clj("filter"))

# Examples
```jldoctest
julia> using Transducers

julia> 1:3 |> Filter(iseven) |> collect
1-element Vector{Int64}:
 2
```
"""
struct Filter{P} <: AbstractFilter
    pred::P
end

@inline next(rf::R_{Filter}, result, input) =
    xform(rf).pred(input) ? next(inner(rf), result, input) : result

Adapt.adapt_structure(to, xf::Filter) = Filter(Adapt.adapt(to, xf.pred))

"""
    NotA(T)

Skip items of type `T`.  Unlike `Filter(!ismissing)`, downstream
transducers can have a correct type information for `NotA(Missing)`.

See also: [`OfType`](@ref)

# Examples
```jldoctest
julia> using Transducers

julia> [1, missing, 2] |> NotA(Missing) |> collect
2-element Vector{Int64}:
 1
 2
```
"""
struct NotA{T} <: AbstractFilter end
NotA(T::Type) = NotA{T}()

@inline next(rf::R_{NotA{T}}, result, input) where T =
    input isa T ? result : next(inner(rf), result, input)

# **Side notes**.  Although in principle `NotA(Missing)` can yields a
# better performance than `Filter(!ismissing)` (by providing more type
# information to the compiler), it seems `Filter(!ismissing)` is
# enough for a small example.  See:
# https://discourse.julialang.org/t/19159/11

"""
    OfType(T)

Include only items of type `T`.

See also: [`NotA`](@ref)

# Examples
```jldoctest
julia> using Transducers

julia> [1, missing, 2] |> OfType(Int) |> collect
2-element Vector{Int64}:
 1
 2
```
"""
struct OfType{T} <: AbstractFilter end
OfType(T::Type) = OfType{T}()

@inline next(rf::R_{OfType{T}}, result, input) where T =
    _next_oftype(T, inner(rf), result, input)

# Following implementation yields semantically correct results for all
# cases.  However, as of writing (Julia 1.2.0-DEV), it seems those
# specializations are valuable for type-stability and performance.
# Hopefully compiler becomes smarter so that I can get rid of the code
# below.
@inline _next_oftype(T, inner, result, input) =
    input isa T ? next(inner, result, input) : result

# Workaround StackOverflowError in Julia 1.0
# https://travis-ci.com/JuliaFolds/Transducers.jl/jobs/171732596
if VERSION >= v"1.1-"

@inline _next_oftype(T, inner, result, input::Tuple) =
    _next_oftype_t(T, inner, result, (), input...)

# Following specialization is required for improving performance of
# ../benchmark/bench_missing_dot.jl.  Note that a mere type-stability
# of `transduce(rf, 0.0, zip(xs, ys))` can actually be achieved by the
# function `_next_oftype_t` below for generic tuple.  I don't know why
# the following manual expansion is better than `_next_oftype_t` when
# both are type stable.
@inline function _next_oftype(::Type{T}, inner, result,
                              (i1, i2)::Tuple{Any, Any}) where {T <: Tuple}
    if i1 isa nthtype(Val(1), T)
        if i2 isa nthtype(Val(2), T)
            return next(inner, result, (i1, i2))
        end
    end
    return result
end

@inline _next_oftype_t(::Type, inner, result, filtered::Tuple) =
    next(inner, result, filtered)

@inline function _next_oftype_t(
        ::Type{T}, inner, result, filtered::Tuple,
        i1, input...) where {T <: Tuple}
    if i1 isa nthtype(Val(1), T)
        return _next_oftype_t(
            Base.tuple_type_tail(T),
            inner,
            result,
            (filtered..., i1),
            input...)
    end
    return result
end
# Not using `Base.tail(input)` for a Tuple-of-(possibly)-Union seems
# to be a nice strategy for achieving type-stability.

end  # if

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/take
# https://clojuredocs.org/clojure.core/take
"""
    Take(n)

Take `n` items from the input sequence.

$(_thx_clj("take"))

# Examples
```jldoctest
julia> using Transducers

julia> 1:10 |> Take(2) |> collect
2-element Vector{Int64}:
 1
 2

julia> 1:2 |> Take(5) |> collect
2-element Vector{Int64}:
 1
 2
```

Using a low-level API, it's possible to distinguish if the output is
truncated or not:

```jldoctest; setup = :(using Transducers), filter = r"\\b(BangBang\\.)?push!!"
julia> transduce(Take(3), Completing(push!!), Init, 1:2)
2-element Vector{Int64}:
 1
 2

julia> transduce(Take(3), Completing(push!!), Init, 1:4)
Reduced([1, 2, 3])

julia> transduce(Take(3), Completing(push!!), Init, 1:0)
InitialValue(push!!)
```

See also [`transduce`](@ref foldl), [`Reduced`](@ref) and
[`Completing`](@ref).
"""
struct Take <: AbstractFilter
    n::Int

    function Take(n)
        @argcheck n >= 0
        return new(n)
    end
end

start(rf::R_{Take}, result) = wrap(rf, xform(rf).n, start(inner(rf), result))
complete(rf::R_{Take}, result) = complete(inner(rf), unwrap(rf, result)[2])

@inline next(rf::R_{Take}, result, input) =
    wrapping(rf, result) do n, iresult
        if n > 0
            iresult = next(inner(rf), iresult, input)
            n -= 1
        end
        if n <= 0
            iresult = reduced(complete(inner(rf), iresult))
        end
        return n, iresult
    end

"""
    TakeLast(n)

Take last `n` items from the input sequence.

# Examples
```jldoctest
julia> using Transducers

julia> 1:10 |> TakeLast(2) |> collect
2-element Vector{Int64}:
  9
 10

julia> 1:2 |> TakeLast(5) |> collect
2-element Vector{Int64}:
 1
 2
```
"""
struct TakeLast <: AbstractFilter
    n::Int

    function TakeLast(n)
        @argcheck n >= 0
        return new(n)
    end
end

function start(rf::R_{TakeLast}, result)
    n = xform(rf).n
    return wrap(rf, (-n, Union{}[]), start(inner(rf), result))
end

@inline next(rf::R_{TakeLast}, result, input) =
    wrapping(rf, result) do (c, buffer0), iresult
        c += 1
        n = xform(rf).n
        if c <= 0
            buffer = push!!(buffer0, input)
            (c, buffer), iresult
        else
            @assert length(buffer0) == n
            buffer = setindex!!(buffer0, input, c)
            (c < n ? c : 0, buffer), iresult
        end
    end

function complete(rf::R_{TakeLast}, result)
    (c, buffer), iresult = unwrap(rf, result)
    if c <= 0  # buffer is not full (or c is just wrapping)
        for i in 1:length(buffer)
            iresult = @next(inner(rf), iresult, @inbounds buffer[i])
        end
    else
        for i in c+1:length(buffer)
            iresult = @next(inner(rf), iresult, @inbounds buffer[i])
        end
        for i in 1:c
            iresult = @next(inner(rf), iresult, @inbounds buffer[i])
        end
    end
    return complete(inner(rf), iresult)
end

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/take-while
# https://clojuredocs.org/clojure.core/take-while
"""
    TakeWhile(pred)

Take items while `pred` returns `true`.  Abort the reduction when
`pred` returns `false` for the first time.

$(_thx_clj("take-while"))

# Examples
```jldoctest
julia> using Transducers

julia> [1, 2, 3, 1, 2] |> TakeWhile(x -> x < 3) |> collect
2-element Vector{Int64}:
 1
 2
```
"""
struct TakeWhile{P} <: AbstractFilter
    pred::P
end

@inline next(rf::R_{TakeWhile}, result, input) =
    if xform(rf).pred(input)
        next(inner(rf), result, input)
    else
        reduced(complete(inner(rf), result))
    end

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/take-nth
# https://clojuredocs.org/clojure.core/take-nth
"""
    TakeNth(n)

Output every `n` item to the inner reducing step.

$(_thx_clj("take-nth"))

# Examples
```jldoctest
julia> using Transducers

julia> 1:9 |> TakeNth(3) |> collect
3-element Vector{Int64}:
 1
 4
 7
```
"""
struct TakeNth <: AbstractFilter
    n::Int

    function TakeNth(n)
        @argcheck n > 0
        return new(n)
    end
end

start(rf::R_{TakeNth}, result) = wrap(rf, xform(rf).n, start(inner(rf), result))
complete(rf::R_{TakeNth}, result) = complete(inner(rf), unwrap(rf, result)[2])

@inline next(rf::R_{TakeNth}, result, input) =
    wrapping(rf, result) do c, iresult
        if c == xform(rf).n
            iresult = next(inner(rf), iresult, input)
            c = 1
        else
            c += 1
        end
        return c, iresult
    end

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/drop
# https://clojuredocs.org/clojure.core/drop
"""
    Drop(n)

Drop first `n` items.

$(_thx_clj("drop"))

# Examples
```jldoctest
julia> using Transducers

julia> 1:5 |> Drop(3) |> collect
2-element Vector{Int64}:
 4
 5
```
"""
struct Drop <: AbstractFilter
    n::Int

    function Drop(n)
        @argcheck n >= 0
        return new(n)
    end
end

start(rf::R_{Drop}, result) = wrap(rf, 0, start(inner(rf), result))
complete(rf::R_{Drop}, result) = complete(inner(rf), unwrap(rf, result)[2])

@inline next(rf::R_{Drop}, result, input) =
    wrapping(rf, result) do c, iresult
        if c >= xform(rf).n
            c, next(inner(rf), iresult, input)
        else
            c += 1
            c, iresult
        end
    end

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/drop-last
# https://clojuredocs.org/clojure.core/drop-last
"""
    DropLast(n)

Drop last `n` items.

$(_thx_clj("drop-last"))

# Examples
```jldoctest
julia> using Transducers

julia> 1:5 |> DropLast(2) |> collect
3-element Vector{Int64}:
 1
 2
 3

julia> 1:1 |> DropLast(2) |> collect == []
true

julia> 1:0 |> DropLast(2) |> collect == []
true
```
"""
struct DropLast <: AbstractFilter
    n::Int

    function DropLast(n)
        @argcheck n >= 0
        return new(n)
    end
end

function start(rf::R_{DropLast}, result)
    n = xform(rf).n + 1
    return wrap(rf, (-n, Union{}[]), start(inner(rf), result))
end

complete(rf::R_{DropLast}, result) = complete(inner(rf), unwrap(rf, result)[2])

@inline next(rf::R_{DropLast}, result, input) =
    wrapping(rf, result) do (c, buffer0), iresult
        c += 1
        n = xform(rf).n + 1
        if c <= 0
            buffer = push!!(buffer0, input)
            if c == 0
                @assert length(buffer) == n
                (c, buffer), next(inner(rf), iresult, buffer[1])
            else
                (c, buffer), iresult
            end
        elseif c >= n
            buffer = setindex!!(buffer0, input, c)
            (0, buffer), next(inner(rf), iresult, buffer[1])
        else
            buffer = setindex!!(buffer0, input, c)
            (c, buffer), next(inner(rf), iresult, buffer[c + 1])
        end
    end

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/drop-while
# https://clojuredocs.org/clojure.core/drop-while
"""
    DropWhile(pred)

Drop items while `pred` returns `true` consecutively.  It becomes a
no-op after `pred` returns a `false`.

$(_thx_clj("drop-while"))

# Examples
```jldoctest
julia> using Transducers

julia> collect(DropWhile(x -> x < 3), [1:5; 1:2])
5-element Vector{Int64}:
 3
 4
 5
 1
 2
```
"""
struct DropWhile{F} <: AbstractFilter
    pred::F
end

start(rf::R_{DropWhile}, result) = wrap(rf, true, start(inner(rf), result))
complete(rf::R_{DropWhile}, result) = complete(inner(rf), unwrap(rf, result)[2])

@inline next(rf::R_{DropWhile}, result, input) =
    wrapping(rf, result) do dropping, iresult
        if dropping
            dropping = xform(rf).pred(input)
            dropping && return (dropping, iresult)
        end
        dropping, next(inner(rf), iresult, input)
    end

"""
    FlagFirst()

Output `(isfirst, input)` where `isfirst::Bool` is `true` only for the
first iteration and `input` is the original input.

See also:
[`IterTools.flagfirst`](https://juliacollections.github.io/IterTools.jl/latest/#flagfirst(xs)-1)

# Examples
```jldoctest
julia> using Transducers

julia> collect(FlagFirst(), 1:3)
3-element Vector{Tuple{Bool, Int64}}:
 ($_true_str, 1)
 ($_false_str, 2)
 ($_false_str, 3)
```
"""
struct FlagFirst <: Transducer end

OutputSize(::Type{<:FlagFirst}) = SizeStable()
isexpansive(::FlagFirst) = false

start(rf::R_{FlagFirst}, result) = wrap(rf, true, start(inner(rf), result))
complete(rf::R_{FlagFirst}, result) = complete(inner(rf), unwrap(rf, result)[2])

@inline next(rf::R_{FlagFirst}, result, input) =
    wrapping(rf, result) do isfirst, iresult
        false, next(inner(rf), iresult, (isfirst, input))
    end

# https://docs.julialang.org/en/v1/base/iterators/#Base.Iterators.partition
# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/partition-all
# https://clojuredocs.org/clojure.core/partition-all
"""
    Partition(size, step = size, flush = false)
    Partition(size; step = size, flush = false)

Sliding window of width `size` and interval `step`. Yield vectors.

Note: `step` = `size` is the default.  Hence, the default behavior is
non-overlapping windows.

For small `size`, see [`Consecutive`](@ref) for a similar transducer that
yields tuples instead.

$_shared_vector_warning

$(_thx_clj("partition-all"))

# Examples
```jldoctest
julia> using Transducers

julia> 1:8 |> Partition(3) |> Map(copy) |> collect
2-element Vector{Vector{Int64}}:
 [1, 2, 3]
 [4, 5, 6]

julia> 1:8 |> Partition(3; flush=true) |> Map(copy) |> collect
3-element Vector{Vector{Int64}}:
 [1, 2, 3]
 [4, 5, 6]
 [7, 8]

julia> 1:8 |> Partition(3; step=1) |> Map(copy) |> collect
6-element Vector{Vector{Int64}}:
 [1, 2, 3]
 [2, 3, 4]
 [3, 4, 5]
 [4, 5, 6]
 [5, 6, 7]
 [6, 7, 8]
```
"""
struct Partition <: Transducer
    size::Int
    step::Int
    flush::Bool

    function Partition(size, step, flush)
        @argcheck size > 0
        @argcheck step > 0
        return new(size, step, flush)
    end
end

Partition(size, step; flush = false) = Partition(size; step = step, flush = flush)
Partition(size; step = size, flush = false) = Partition(size, step, flush)

isexpansive(::Partition) = false

function start(rf::R_{Partition}, result)
    buf = Union{}[]
    return wrap(rf, (0, 0, buf), start(inner(rf), result))
end

function next(rf::R_{Partition}, result, input)
    wrapping(rf, result) do (i, s, buf), iresult
        _window_next(rf, i, s, buf, iresult, input)
    end
end

function _window_next(rf, i, s, buf0, iresult, input)
    i += 1
    @assert 1 <= i <= xform(rf).size
    len = length(buf0)
    if s == 0 && len < xform(rf).size
        buf = push!!(buf0, input)
        if i == xform(rf).size
            # This is the first time `length(buf) == xform(rf).size` is
            # true.
            iinput = (@view buf[1:end]) :: DenseSubVector
            # Do not use `@view buf[:]` to make the indices
            # `UnitRange` instead of `OneTo`.
            @assert i == xform(rf).size
            i = 0
            s = xform(rf).step
            iresult = next(inner(rf), iresult, iinput)
            # Throw away buf[1] which is just consumed by the downstream:
            deleteat!(buf, 1)
        end
        return (i, s, buf), iresult
    elseif len < 2 * xform(rf).size - 1
        buf = push!!(buf0, input)
    else
        # TODO: optimize for size < step case
        buf = setindex!!(buf0, input, i + xform(rf).size - 1)
    end
    if i == xform(rf).size
        # Wrapping the window.  Next window will be i=1.
        # Copy tail to head.
        copyto!(buf,
                1,                  # destination offset
                buf,
                xform(rf).size + 1,  # source offset
                xform(rf).size - 1)  # size
    end
    s -= 1
    @assert 0 <= s < xform(rf).step
    if s == 0
        s = xform(rf).step
        iinput = @view buf[i:i + xform(rf).size - 1] # unsafe_view? @inbounds?
        iinput :: DenseSubVector
        iresult = next(inner(rf), iresult, iinput)
    end
    if i == xform(rf).size
        i = 0
    end
    return (i, s, buf), iresult
end

function complete(rf::R_{Partition}, result)
    (i, s, buf), iresult = unwrap(rf, result)
    if xform(rf).flush && s != xform(rf).step
        iinput = @view buf[i:i + xform(rf).size - 1] # unsafe_view? @inbounds?
        iinput = @view iinput[s + 1:end]
        iinput :: DenseSubVector
        iresult = @next(inner(rf), iresult, iinput)
    end
    return complete(inner(rf), iresult)
end

# TODO: implement SVector version of Partition

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/partition-by
# https://clojuredocs.org/clojure.core/partition-by
"""
    PartitionBy(f)

Group input sequence into chunks in which `f` returns a same value
consecutively.

$_shared_vector_warning

$(_thx_clj("partition-by"))

# Examples
```jldoctest
julia> using Transducers

julia> 1:9 |> PartitionBy(x -> (x + 1) ÷ 3) |> Map(copy) |> collect
4-element Vector{UnitRange{Int64}}:
 1:1
 2:4
 5:7
 8:9
```
"""
struct PartitionBy{F} <: Transducer
    f::F
end

struct Unseen end
is_prelude(::Unseen) = true

isexpansive(::PartitionBy) = false

function start(rf::R_{PartitionBy}, result)
    iinput = Union{}[]
    return wrap(rf, (iinput, Unseen()), start(inner(rf), result))
end

@inline function next(rf::R_{PartitionBy}, result, input)
    wrapping(rf, result) do (iinput, pval), iresult
        val = xform(rf).f(input)
        if pval isa Unseen || val == pval
            iinput = push!!(iinput, input)
        else
            iresult = next(inner(rf), iresult, iinput)
            iinput = empty!!(iinput)
            if !isreduced(iresult)
                iinput = push!!(iinput, input)
            end
        end
        return (iinput, val), iresult
    end
end

function complete(rf::R_{PartitionBy}, ps)
    (iinput, _), iresult = unwrap(rf, ps)
    if !isempty(iinput)
        iresult = @next(inner(rf), iresult, iinput)
    end
    return complete(inner(rf), iresult)
end

"""
    KeepSomething(f = identity)

Pass non-`nothing` output of `f` to the inner reducing step after
possibly unwrapping `Some`.

$(_thx_clj("keep"))

# Examples
```jldoctest KeepSomething
julia> using Transducers

julia> xf = KeepSomething() do x
           if x == 0
               :zero
           elseif x == 1
               Some(:one)
           elseif x == 2
               Some(nothing)
           end
       end;

julia> collect(xf, 0:3)
3-element Vector{Union{Nothing, Symbol}}:
 :zero
 :one
 nothing
```

Note that [`NotA(Nothing)`](@ref) can be used to avoid automatically
unwrapping `Some`:

```jldoctest KeepSomething
julia> [Some(1), 2, nothing] |> KeepSomething() |> collect
2-element Vector{Int64}:
 1
 2

julia> [Some(1), 2, nothing] |> NotA(Nothing) |> collect
2-element Vector{Any}:
  Some(1)
 2
```
"""
struct KeepSomething{F} <: Transducer
    f::F
end

KeepSomething() = KeepSomething(identity)

isexpansive(::KeepSomething) = false

function next(rf::R_{KeepSomething}, result, input)
    iinput = xform(rf).f(input)
    return iinput === nothing ? result : next(inner(rf), result, something(iinput))
end

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/distinct
# https://clojuredocs.org/clojure.core/distinct
"""
    Unique(by = identity)

Pass only unseen item to the inner reducing step.

The item is distinguished by the output of function `by` when given.

$(_thx_clj("distinct"))

!!! compat "Transducers.jl 0.4.2"

    New in version 0.4.2.

# Examples
```jldoctest
julia> using Transducers

julia> [1, 1, 2, -1, 3, 3, 2] |> Unique() |> collect
4-element Vector{Int64}:
  1
  2
 -1
  3

julia> [1, 1, 2, -1, 3, 3, 2] |> Unique(x -> x^2) |> collect
3-element Vector{Int64}:
 1
 2
 3
```
"""
struct Unique{P} <: AbstractFilter
    by::P
end

Unique() = Unique(identity)

function start(rf::R_{Unique}, result)
    seen = Set(Union{}[])
    return wrap(rf, seen, start(inner(rf), result))
end

complete(rf::R_{Unique}, result) = complete(inner(rf), unwrap(rf, result)[2])

function next(rf::R_{Unique}, result, input)
    wrapping(rf, result) do seen, iresult
        y = xform(rf).by(input)
        if y in seen
            return seen, iresult
        else
            seen′ = push!!(seen, y)
            return seen′, next(inner(rf), iresult, input)
        end
    end
end

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/interpose
# https://clojuredocs.org/clojure.core/interpose
"""
    Interpose(sep)

Interleave input items with a `sep`.

$(_thx_clj("interpose"))

# Examples
```jldoctest
julia> using Transducers

julia> collect(Interpose(missing), 1:3)
5-element Vector{Union{Missing, Int64}}:
 1
  missing
 2
  missing
 3
```
"""
struct Interpose{T} <: Transducer
    sep::T
end

start(rf::R_{Interpose}, result) = wrap(rf, Val(true), start(inner(rf), result))
complete(rf::R_{Interpose}, result) = complete(inner(rf), unwrap(rf, result)[2])

@inline next(rf::R_{Interpose}, result, input) =
    wrapping(rf, result) do isfirst, iresult
        if isfirst isa Val{false}
            iresult = next(inner(rf), iresult, xform(rf).sep)
        end
        return Val(false), next(inner(rf), iresult, input)
    end

# https://clojure.github.io/clojure/clojure.core-api.html#clojure.core/dedupe
# https://clojuredocs.org/clojure.core/dedupe
"""
    Dedupe()

De-duplicate _consecutive_ items.

$(_thx_clj("dedupe"))

# Examples
```jldoctest
julia> using Transducers

julia> collect(Dedupe(), [1, 1, 2, 1, 3, 3, 2])
5-element Vector{Int64}:
 1
 2
 1
 3
 2
```
"""
struct Dedupe <: AbstractFilter
end

start(rf::R_{Dedupe}, result) = wrap(rf, Unseen(), start(inner(rf), result))
complete(rf::R_{Dedupe}, result) = complete(inner(rf), unwrap(rf, result)[2])

@inline next(rf::R_{Dedupe}, result, input) =
    wrapping(rf, result) do prev, iresult
        if prev isa Unseen || prev != input
            return input, next(inner(rf), iresult, input)
        else
            return input, iresult
        end
    end

"""
    Scan(f, [init = Init])

Accumulate input with binary function `f` and pass the accumulated
result so far to the inner reduction step.

The inner reducing step receives the sequence `y₁, y₂, y₃, ..., yₙ, ...`
when the sequence `x₁, x₂, x₃, ..., xₙ, ...` is fed to `Scan(f)`.

    y₁ = f(init, x₁)
    y₂ = f(y₁, x₂)
    y₃ = f(y₂, x₃)
    ...
    yₙ = f(yₙ₋₁, xₙ)

This is a generalized version of the
[_prefix sum_](https://en.wikipedia.org/wiki/Prefix_sum) also known as
_cumulative sum_, _inclusive scan_, or _scan_.

Note that the associativity of `f` is not required when the transducer
is used in a process that gurantee an order, such as [`foldl`](@ref).

Unless `f` is a function with known identity element such as `+`, `*`,
`min`, `max`, and `append!`, the initial state `init` must be
provided.

$_use_initializer

See also: [`ScanEmit`](@ref), [`Iterated`](@ref).

# Examples
```jldoctest
julia> using Transducers

julia> collect(Scan(*), 1:3)
3-element Vector{Int64}:
 1
 2
 6

julia> 1:3 |> Map(x -> x + im) |> Scan(*) |> collect
3-element Vector{Complex{Int64}}:
 1 + 1im
 1 + 3im
 0 + 10im

julia> collect(Scan(*, 10), 1:3)
3-element Vector{Int64}:
 10
 20
 60
```
"""
struct Scan{F, T} <: Transducer
    f::F
    init::T
end

Scan(f) = Scan(_asmonoid(f), Init)  # TODO: DefaultInit?

isexpansive(::Scan) = false

function start(rf::R_{Scan}, result)

    wrap(rf, start(xform(rf).f, xform(rf).init), start(inner(rf), result))
end
# For now, using `start` on `rf.f` is only for invoking `initialize`
# on `rf.init`.  But maybe it's better to support `reducingfunction`?
# For example, use `unwrap_all` before feeding the accumulator to the
# inner reducing function?

complete(rf::R_{Scan}, result) = complete(inner(rf), unwrap(rf, result)[2])

function next(rf::R_{Scan}, result, input)
    wrapping(rf, result) do acc, iresult
        acc = xform(rf).f(acc, input)
        # TODO: Don't call inner when `acc` is an `InitialValue`?
        #       What about when `Reduced`?
        n = next(inner(rf), iresult, acc)
        return acc, n
    end
end

struct Scanx{F, T} <: Transducer
    f::F
    init::T
end

Scanx(f) = Scanx(_asmonoid(f), Init)  # TODO: DefaultInit?

isexpansive(::Scanx) = false

function start(rf::R_{Scanx}, result)
    return wrap(rf, start(xform(rf).f, Unseen()), start(inner(rf), result))
# For now, using `start` on `rf.f` is only for invoking `initialize`
# on `rf.init`.  But maybe it's better to support `reducingfunction`?
# For example, use `unwrap_all` before feeding the accumulator to the
# inner reducing function?
end

complete(rf::R_{Scanx}, result) = complete(inner(rf), unwrap(rf, result)[2])

function next(rf::R_{Scanx}, result, input)
    wrapping(rf, result) do acc, iresult
        if acc isa Unseen
            ival =  start(xform(rf).f, xform(rf).init)
            acc = xform(rf).f(ival, input)
            cur, n = acc, next(inner(rf), push!!(iresult,convert(typeof(input),ival)),input)
        else
            acc = xform(rf).f(acc, input)

            cur, n = acc, next(inner(rf), iresult, acc)
        end
        # TODO: Don't call inner when `acc` is an `InitialValue`?
        #       What about when `Reduced`?
        return cur, n
    end
end
"""
    ScanEmit(f, init[, onlast])

Accumulate input `x` with a function `f` with the call signature
`(u, x) -> (y, u)` and pass the result `y` to the inner reduction step.

The inner reducing step receives the sequence `y₁, y₂, y₃, ..., yₙ,
...` computed as follows

    u₀ = init
    y₁, u₁ = f(u₀, x₁)
    y₂, u₂ = f(u₁, x₂)
    y₃, u₃ = f(u₂, x₃)
    ...
    yₙ, uₙ = f(uₙ₋₁, xₙ)
    ...
    yₒₒ = onlast(uₒₒ)

when the sequence `x₁, x₂, x₃, ..., xₙ, ...` is fed to `ScanEmit(f)`.

$_use_initializer

See also: [`Scan`](@ref), [`Iterated`](@ref).

# Examples
```jldoctest
julia> using Transducers

julia> collect(ScanEmit(tuple, 0), 1:3)
3-element Vector{Int64}:
 0
 1
 2
```
"""
struct ScanEmit{F, T, L} <: Transducer
    f::F
    init::T
    onlast::L
end

ScanEmit(f, init) = ScanEmit(f, init, nothing)

isexpansive(xf::ScanEmit) = xf.onlast !== nothing

start(rf::R_{ScanEmit}, result) =
    wrap(rf, _initvalue(rf), start(inner(rf), result))

function next(rf::R_{ScanEmit}, result, input)
    wrapping(rf, result) do u0, iresult
        y1, u1 = xform(rf).f(u0, input)
        return u1, next(inner(rf), iresult, y1)
    end
end

function complete(rf::R_{ScanEmit}, result)
    u, iresult = unwrap(rf, result)
    if xform(rf).onlast !== nothing
        iresult = @next(inner(rf), iresult, xform(rf).onlast(u))
    end
    return complete(inner(rf), iresult)
end

function combine(rf::R_{ScanEmit}, a, b)
    ua, ira = unwrap(rf, a)
    ub, irb = unwrap(rf, b)
    irc = combine(inner(rf), ira, irb)
    yc, uc = xform(rf).f(ua, ub)
    irc = next(inner(rf), irc, yc)
    return wrap(rf, uc, irc)
end

"""
    AdHocXF(f, init, [onlast])

# Examples
```jldoctest
julia> using Transducers
       using Transducers: AdHocXF, @next
       using Setfield: @set!

julia> flushlast(rf, result) = rf(@next(rf, result, result.state));

julia> xf = AdHocXF(nothing, flushlast) do rf, result, input
           m = match(r"^name:(.*)", input)
           if m === nothing
               push!(result.state.lines, input)
               return result
           else
               chunk = result.state
               @set! result.state = (name=strip(m.captures[1]), lines=String[])
               push!(result.state.lines, input)
               if chunk === nothing
                   return result
               else
                   return rf(result, chunk)
               end
           end
       end;

julia> collect(xf, split(\"\"\"
       name: Map
       type: onetoone
       name: Cat
       type: expansive
       name: Filter
       type: contractive
       name: Cat |> Filter
       type: chaotic
       \"\"\", "\\n"; keepempty=false))
4-element Vector{NamedTuple{(:name, :lines), Tuple{SubString{String}, Vector{String}}}}:
 (name = "Map", lines = ["name: Map", "type: onetoone"])
 (name = "Cat", lines = ["name: Cat", "type: expansive"])
 (name = "Filter", lines = ["name: Filter", "type: contractive"])
 (name = "Cat |> Filter", lines = ["name: Cat |> Filter", "type: chaotic"])
```
"""
struct AdHocXF{F, T, L} <: Transducer
    f::F
    init::T
    onlast::L
end

AdHocXF(f, init) = AdHocXF(f, init, nothing)

struct ResultShim{S, R}
    state::S
    result::R
end

struct RFShim{F}
    rf::F
end

_setresult(shim, result::Reduced) = Reduced(@set shim.result = unreduced(result))
_setresult(shim, result) = @set shim.result = result

(f::RFShim)(shim::ResultShim) =
    _setresult(shim, complete(f.rf, shim.result))
(f::RFShim)(shim::ResultShim, input) =
    _setresult(shim, next(f.rf, shim.result, input))

start(rf::R_{AdHocXF}, result) =
    wrap(rf, _initvalue(rf), start(inner(rf), result))

@inline next(rf::R_{AdHocXF}, result, input) =
    wrapping(rf, result) do state, iresult
        shim = xform(rf).f(RFShim(inner(rf)), ResultShim(state, iresult), input)
        if shim isa Reduced
            return unreduced(shim).state, Reduced(unreduced(shim).result)
        else
            return shim.state, shim.result
        end
    end

function complete(rf::R_{AdHocXF}, result)
    state, iresult = unwrap(rf, result)
    onlast = xform(rf).onlast
    if onlast !== nothing
        shim = onlast(RFShim(inner(rf)), ResultShim(state, iresult))
        if shim isa Reduced
            return Reduced(unreduced(shim).result)
        else
            return shim.result
        end
    end
    return complete(inner(rf), iresult)
end

"""
    Iterated(f, init)

Generate a sequence `init`, `f(init)`, `f(f(init))`, `f(f(f(init)))`,
and so on.

$(_shared_notes_unfold)

$_use_initializer

See also: [`Scan`](@ref), [`ScanEmit`](@ref).

The idea is taken from
[`IterTools.iterated`](https://juliacollections.github.io/IterTools.jl/latest/#IterTools.iterated)

# Examples
```jldoctest
julia> using Transducers

julia> collect(Iterated(x -> 2x, 1), 1:5)
5-element Vector{Int64}:
  1
  2
  4
  8
 16

julia> collect(Zip(Map(identity), Iterated(x -> 2x, 1)), 1:5)
5-element Vector{Tuple{Int64, Int64}}:
 (1, 1)
 (2, 2)
 (3, 4)
 (4, 8)
 (5, 16)
```
"""
struct Iterated{F, T} <: Transducer
    f::F
    init::T
end

OutputSize(::Type{<:Iterated}) = SizeStable()
isexpansive(::Iterated) = false
start(rf::R_{Iterated}, result) =
    wrap(rf, _initvalue(rf), start(inner(rf), result))
complete(rf::R_{Iterated}, result) = complete(inner(rf), unwrap(rf, result)[2])
@inline next(rf::R_{Iterated}, result, ::Any) =
    wrapping(rf, result) do istate, iresult
        return xform(rf).f(istate), next(inner(rf), iresult, istate)
    end

"""
    Count([start[, step]])

Generate a sequence `start`, `start + step`, `start + step + step`,
and so on.

$(_shared_notes_unfold)

`start` defaults to 1 and `step` defaults to `oneunit(start)`.

See also:
[`Iterators.countfrom`](https://docs.julialang.org/en/v1/base/iterators/).
[`Enumerate`](@ref)

# Examples
```jldoctest
julia> using Transducers

julia> collect(Zip(Map(identity), Count()), -3:-1)
3-element Vector{Tuple{Int64, Int64}}:
 (-3, 1)
 (-2, 2)
 (-1, 3)

julia> using Dates

julia> 1:3 |> Zip(Map(identity), Count(Day(1))) |> MapSplat(*) |> collect ==
       [Day(1), Day(4), Day(9)]
true
```
"""
struct Count{T} <: Transducer
    start::T
    step::T
end

Count(start = 1) = Count(start, oneunit(start))

OutputSize(::Type{<:Count}) = SizeStable()
isexpansive(::Count) = false
start(rf::R_{Count}, result) = wrap(rf, xform(rf).start, start(inner(rf), result))
complete(rf::R_{Count}, result) = complete(inner(rf), unwrap(rf, result)[2])
@inline next(rf::R_{Count}, result, ::Any) =
    wrapping(rf, result) do istate, iresult
        return istate + xform(rf).step, next(inner(rf), iresult, istate)
    end

"""
    GetIndex(array)
    GetIndex{inbounds}(array)

Transform an integer input `i` to `array[i]`.

$_experimental_warning

# Examples
```jldoctest
julia> using Transducers
       using Transducers: GetIndex

julia> collect(GetIndex(1:10), [2, 3, 4])
3-element Vector{Int64}:
 2
 3
 4

julia> collect(GetIndex{true}(1:10), [2, 3, 4])
3-element Vector{Int64}:
 2
 3
 4
```
"""
struct GetIndex{inbounds, A} <: Transducer
    array::A
end

GetIndex{inbounds}(array::A) where {inbounds, A} = GetIndex{inbounds, A}(array)
GetIndex(array) = GetIndex{false}(array)

OutputSize(::Type{<:GetIndex}) = SizeStable()
isexpansive(::GetIndex) = false

@inline next(rf::R_{GetIndex{true}}, result, input) =
    next(inner(rf), result, @inbounds xform(rf).array[input])
@inline next(rf::R_{GetIndex{false}}, result, input) =
    next(inner(rf), result, xform(rf).array[input])

Base.:(==)(xf1::GetIndex{inbounds,A},
           xf2::GetIndex{inbounds,A}) where {inbounds,A} =
    xf1.array == xf2.array

Adapt.adapt_structure(to, xf::GetIndex{inbounds}) where {inbounds} =
    GetIndex{inbounds}(Adapt.adapt(to, xf.array))

"""
    SetIndex(array)
    SetIndex{inbounds}(array)

Perform `array[i] = v` for each input pair `(i, v)`.

$_experimental_warning

# Examples
```jldoctest
julia> using Transducers
       using Transducers: SetIndex

julia> ys = zeros(3);

julia> foldl(first ∘ tuple, SetIndex(ys), [(1, 11.1), (3, 33.3)], init=nothing)

julia> ys
3-element Vector{Float64}:
 11.1
  0.0
 33.3
```
"""
struct SetIndex{inbounds, A} <: Transducer
    array::A
end

SetIndex{inbounds}(array::A) where {inbounds, A} = SetIndex{inbounds, A}(array)
SetIndex(array) = SetIndex{false}(array)

OutputSize(::Type{<:SetIndex}) = SizeStable()
isexpansive(::SetIndex) = false

@inline next(rf::R_{SetIndex{true}}, result, input::NTuple{2, Any}) =
    next(inner(rf), result, (@inbounds xform(rf).array[input[1]] = input[2];))
@inline next(rf::R_{SetIndex{false}}, result, input::NTuple{2, Any}) =
    next(inner(rf), result, (xform(rf).array[input[1]] = input[2];))
# Index is `input[1]` due to `ZipSource`'s definition.  Is it better to
# flip, to be compatible with `Base.setindex!`?

Base.:(==)(xf1::SetIndex{inbounds,A},
           xf2::SetIndex{inbounds,A}) where {inbounds,A} =
    xf1.array == xf2.array

Adapt.adapt_structure(to, xf::SetIndex{inbounds}) where {inbounds} =
    SetIndex{inbounds}(Adapt.adapt(to, xf.array))

"""
    Inject(iterator)

Inject the output from `iterator` to the stream processed by the inner
reduction step.

$_experimental_warning

# Examples
```jldoctest
julia> using Transducers
       using Transducers: Inject

julia> collect(Inject(Iterators.cycle("hello")), 1:8)
8-element Vector{Tuple{Int64, Char}}:
 (1, 'h')
 (2, 'e')
 (3, 'l')
 (4, 'l')
 (5, 'o')
 (6, 'h')
 (7, 'e')
 (8, 'l')

julia> collect(Inject(Iterators.repeated([1 2])), 1:4)
4-element Vector{Tuple{Int64, Matrix{Int64}}}:
 (1, [1 2])
 (2, [1 2])
 (3, [1 2])
 (4, [1 2])

julia> collect(Inject(Iterators.product(1:2, 3:5)), 1:100)
6-element Vector{Tuple{Int64, Tuple{Int64, Int64}}}:
 (1, (1, 3))
 (2, (2, 3))
 (3, (1, 4))
 (4, (2, 4))
 (5, (1, 5))
 (6, (2, 5))
```
"""
struct Inject{T} <: Transducer
    iterator::T
end

isexpansive(::Inject) = false
start(rf::R_{Inject}, result) =
    wrap(rf, iterate(xform(rf).iterator), start(inner(rf), result))
complete(rf::R_{Inject}, result) = complete(inner(rf), unwrap(rf, result)[2])
@inline next(rf::R_{Inject}, result, input) =
    wrapping(rf, result) do istate, iresult
        istate === nothing && return istate, reduced(complete(inner(rf), iresult))
        y, s = istate
        iresult2 = next(inner(rf), iresult, (input, y))
        return iterate(xform(rf).iterator, s), iresult2
    end

"""
    Enumerate([start[, step]])

Transducer variant of `Base.enumerate`. The `start` and `step` arguments
are optional and have the same meaning as in [`Count`](@ref).

# Examples
```jldoctest
julia> using Transducers

julia> collect(Enumerate(), ["A", "B", "C"])
3-element Vector{Tuple{Int64, String}}:
 (1, "A")
 (2, "B")
 (3, "C")

julia> start=2; step=3;

julia> collect(Enumerate(start, step), ["A", "B", "C"])
3-element Vector{Tuple{Int64, String}}:
 (2, "A")
 (5, "B")
 (8, "C")

```
"""
struct Enumerate{T} <: Transducer
    start::T
    step::T
end

Enumerate(start = 1) = Enumerate(start, oneunit(start))

OutputSize(::Type{<:Enumerate}) = SizeStable()
isexpansive(::Enumerate) = false
start(rf::R_{Enumerate}, result) =
    wrap(rf, xform(rf).start, start(inner(rf), result))
complete(rf::R_{Enumerate}, result) = complete(inner(rf), unwrap(rf, result)[2])
@inline next(rf::R_{Enumerate}, result, input) =
    wrapping(rf, result) do i, iresult
        iresult2 = next(inner(rf), iresult, (i, input))
        i + xform(rf).step, iresult2
    end

"""
    ReduceIf(pred)

Stop fold when `pred(x)` returns `true` for the output `x` of the
upstream transducer.

# Examples
```jldoctest
julia> using Transducers

julia> foldl(right, ReduceIf(x -> x == 3), 1:10)
3
```
"""
struct ReduceIf{P} <: AbstractFilter
    pred::P
end

function next(rf::R_{ReduceIf}, result0, input)
    shouldreduce = xform(rf).pred(input)
    result = next(inner(rf), result0, input)
    if shouldreduce
        return reduced(complete(inner(rf), result))
    end
    return result
end

# More immediate version of `ReduceIf`.  Not sure if this is useful so
# not exporting it ATM.
struct AbortIf{P} <: AbstractFilter
    pred::P
end

next(rf::R_{AbortIf}, result, input) =
    if xform(rf).pred(input)
        return reduced(complete(inner(rf), result))
    else
        return next(inner(rf), result, input)
    end


text:
using Distributed
addprocs(6)
@everywhere using BenchmarkTools, DistributedArrays, DistributedJets, Jets, LinearAlgebra, Statistics

const SUITE = BenchmarkGroup()

@everywhere JopFoo_df!(d,m;diagonal,kwargs...) = d .= diagonal .* m
@everywhere function JopFoo(diag)
    spc = JetSpace(Float64, length(diag))
    JopLn(;df! = JopFoo_df!, dom = spc, rng = spc, s = (diagonal=diag,))
end

@everywhere JopBar_f!(d,m;kwargs...) = d .= m.^2
@everywhere JopBar_df!(δd,δm;mₒ,kwargs...) = δd .= 2 .* mₒ .* δm
@everywhere function JopBar(n)
    spc = JetSpace(Float64, n)
    JopNl(f! = JopBar_f!, df! = JopBar_df!, dom = spc, rng = spc)
end

_F = DArray(I->[JopBar(100) for i in I[1], j in I[2]], (50,10), workers()[1:3], [3,1])
F = @blockop _F
rangeF = range(F)
d₁ = rand(rangeF)
d₂ = rand(rangeF)
d₃ = rand(rangeF)
d₄ = zeros(rangeF)
α₁ = rand(Float64)
α₂ = rand(Float64)
α₃ = rand(Float64)
SUITE["DBArray"] = BenchmarkGroup()
SUITE["DBArray"]["construct"] = @benchmarkable rand($rangeF)
SUITE["DBArray"]["norm"] = @benchmarkable norm($d₁)
SUITE["DBArray"]["f-maximum"] = @benchmarkable maximum(abs, $d₁)
SUITE["DBArray"]["f-minimum"] = @benchmarkable minimum(abs, $d₁)
SUITE["DBArray"]["maximum"] = @benchmarkable maximum($d₁)
SUITE["DBArray"]["minimum"] = @benchmarkable minimum($d₁)
SUITE["DBArray"]["mapreduce"] = @benchmarkable mapreduce(abs, +, $d₁)
SUITE["DBArray"]["dot"] = @benchmarkable dot($d₁,$d₂)
SUITE["DBArray"]["mean"] = @benchmarkable mean($d₁)
SUITE["DBArray"]["var"] = @benchmarkable var($d₁)
SUITE["DBArray"]["var, mean"] = @benchmarkable var($d₁; mean=1.0)
SUITE["DBArray"]["extrema"] = @benchmarkable extrema($d₁)
SUITE["DBArray"]["broadcasting"] = @benchmarkable d₄ .= α₁*d₁ .+ α₂*d₂ .- α₃*d₃
SUITE["DBArray"]["space from DBArray"] = @benchmarkable space($d₁)

_F = DArray(I->[JopBar(100) for i in I[1], j in I[2]], (50,10), workers()[1:3], [3,1])
F = @blockop _F
domainF = domain(F)
rangeF = range(F)
m = rand(domain(F))
d = rand(range(F))
J = jacobian!(F, m)
SUITE["DBlock, homogeneous"] = BenchmarkGroup()
SUITE["DBlock, homogeneous"]["construct"] = @benchmarkable @blockop $_F
SUITE["DBlock, homogeneous"]["mul!"] = @benchmarkable mul!($d, $F, $m)
SUITE["DBlock, homogeneous"]["mul"] = @benchmarkable $F * $m
SUITE["DBlock, homogeneous"]["jacobian"] = @benchmarkable jacobian!($F, $m)
SUITE["DBlock, homogeneous"]["mul!, linear"] = @benchmarkable mul!($d, $J, $m)
SUITE["DBlock, homogeneous"]["mul, linear"] = @benchmarkable $J * $m
SUITE["DBlock, homogeneous"]["mul!, adjoint"] = @benchmarkable mul!($m, ($J)', $d)
SUITE["DBlock, homogeneous"]["mul, adjoint"] = @benchmarkable ($J)' * $d
SUITE["DBlock, homogeneous"]["adjoint"] = @benchmarkable $(J)'
SUITE["DBlock, homogeneous"]["shape"] = @benchmarkable shape($F)
SUITE["DBlock, homogeneous"]["size"] = @benchmarkable size($F)
SUITE["DBlock, homogeneous"]["domain"] = @benchmarkable domain($F)
SUITE["DBlock, homogeneous"]["range"] = @benchmarkable range($F)
SUITE["DBlock, homogeneous"]["dom,block"] = @benchmarkable getblock($m, 3)
SUITE["DBlock, homogeneous"]["dom,block!"] = @benchmarkable setblock!($m, 3, $(rand(100)))
SUITE["DBlock, homogeneous"]["rng,block"] = @benchmarkable getblock($d, 10)
SUITE["DBlock, homogeneous"]["rng,block!"] = @benchmarkable setblock!($d, 10, $(rand(100)))

F = @blockop _F perfstatfile="stats.json"
J = jacobian(F, m)
SUITE["DBlock, perfstat, homogeneous"] = BenchmarkGroup()
SUITE["DBlock, perfstat, homogeneous"]["mul!"] = @benchmarkable mul!($d, $F, $m)
SUITE["DBlock, perfstat, homogeneous"]["mul"] = @benchmarkable $F * $m
SUITE["DBlock, perfstat, homogeneous"]["mul!, linear"] = @benchmarkable mul!($d, $J, $m)
SUITE["DBlock, perfstat, homogeneous"]["mul, linear"] = @benchmarkable $J * $m
SUITE["DBlock, perfstat, homogeneous"]["mul!, adjoint"] = @benchmarkable mul!($m, ($J)', $d)
SUITE["DBlock, perfstat, homogeneous"]["mul, adjoint"] = @benchmarkable ($J)' * $d
rm("stats.json", force=true)

@everywhere function myblock(i,j)
    if iseven(i) && isodd(j)
        return JopFoo(rand(100))
    else
        return JopBar(100)
    end
end

_F = DArray(I->[myblock(i,j) for i in I[1], j in I[2]], (50,10), workers()[1:3], [3,1])
F = @blockop _F
domainF = domain(F)
rangeF = range(F)
m = rand(domain(F))
d = rand(range(F))
J = jacobian!(F, m)
SUITE["DBlock, heterogeneous"] = BenchmarkGroup()
SUITE["DBlock, heterogeneous"]["construct"] = @benchmarkable @blockop $_F
SUITE["DBlock, heterogeneous"]["mul!"] = @benchmarkable mul!($d, $F, $m)
SUITE["DBlock, heterogeneous"]["mul"] = @benchmarkable $F * $m
SUITE["DBlock, heterogeneous"]["jacobian"] = @benchmarkable jacobian!($F, $m)
SUITE["DBlock, heterogeneous"]["mul!, linear"] = @benchmarkable mul!($d, $J, $m)
SUITE["DBlock, heterogeneous"]["mul, linear"] = @benchmarkable $J * $m
SUITE["DBlock, heterogeneous"]["mul!, adjoint"] = @benchmarkable mul!($m, ($J)', $d)
SUITE["DBlock, heterogeneous"]["mul, adjoint"] = @benchmarkable ($J)' * $d
SUITE["DBlock, heterogeneous"]["adjoint"] = @benchmarkable $(J)'
SUITE["DBlock, heterogeneous"]["shape"] = @benchmarkable shape($F)
SUITE["DBlock, heterogeneous"]["size"] = @benchmarkable size($F)
SUITE["DBlock, heterogeneous"]["domain"] = @benchmarkable domain($F)
SUITE["DBlock, heterogeneous"]["range"] = @benchmarkable range($F)
SUITE["DBlock, heterogeneous"]["dom,block"] = @benchmarkable getblock($m, 3)
SUITE["DBlock, heterogeneous"]["dom,block!"] = @benchmarkable setblock!($m, 3, $(rand(100)))
SUITE["DBlock, heterogeneous"]["rng,block"] = @benchmarkable getblock($d, 10)
SUITE["DBlock, heterogeneous"]["rng,block!"] = @benchmarkable setblock!($d, 10, $(rand(100)))

_F = DArray(I->[JopBar(100) for i in I[1], j in I[2]], (50,10), workers()[1:6], [3,2])
F = @blockop _F
domainF= domain(F)
rangeF = range(F)
m = rand(domain(F))
d = rand(range(F))
J = jacobian!(F, m)
SUITE["DBlock, homogeneous, distributed model"] = BenchmarkGroup()
SUITE["DBlock, homogeneous, distributed model"]["construct"] = @benchmarkable @blockop $_F
SUITE["DBlock, homogeneous, distributed model"]["mul!"] = @benchmarkable mul!($d, $F, $m)
SUITE["DBlock, homogeneous, distributed model"]["mul"] = @benchmarkable $F * $m
SUITE["DBlock, homogeneous, distributed model"]["jacobian"] = @benchmarkable jacobian!($F, $m)
SUITE["DBlock, homogeneous, distributed model"]["mul!, linear"] = @benchmarkable mul!($d, $J, $m)
SUITE["DBlock, homogeneous, distributed model"]["mul, linear"] = @benchmarkable $J * $m
SUITE["DBlock, homogeneous, distributed model"]["mul!, adjoint"] = @benchmarkable mul!($m, ($J)', $d)
SUITE["DBlock, homogeneous, distributed model"]["mul, adjoint"] = @benchmarkable ($J)' * $d
SUITE["DBlock, homogeneous, distributed model"]["adjoint"] = @benchmarkable $(J)'
SUITE["DBlock, homogeneous, distributed model"]["shape"] = @benchmarkable shape($F)
SUITE["DBlock, homogeneous, distributed model"]["size"] = @benchmarkable size($F)
SUITE["DBlock, homogeneous, distributed model"]["domain"] = @benchmarkable domain($F)
SUITE["DBlock, homogeneous, distributed model"]["range"] = @benchmarkable range($F)
SUITE["DBlock, homogeneous, distributed model"]["dom,block"] = @benchmarkable getblock($m, 3)
SUITE["DBlock, homogeneous, distributed model"]["dom,block!"] = @benchmarkable setblock!($m, 3, $(rand(100)))
SUITE["DBlock, homogeneous, distributed model"]["rng,block"] = @benchmarkable getblock($d, 10)
SUITE["DBlock, homogeneous, distributed model"]["rng,block!"] = @benchmarkable setblock!($d, 10, $(rand(100)))

_F = DArray(I->[i == j ? JopBar(100) : JopZeroBlock(JetSpace(Float64,100),JetSpace(Float64,100)) for i in I[1], j in I[2]], (20,20), workers()[1:3], [3,1])
F = @blockop _F isdiag=true
domainF= domain(F)
rangeF = range(F)
m = rand(domain(F))
d = rand(range(F))
J = jacobian!(F, m)
SUITE["DBlock, homogeneous, block diagonal"] = BenchmarkGroup()
SUITE["DBlock, homogeneous, block diagonal"]["construct"] = @benchmarkable @blockop $_F
SUITE["DBlock, homogeneous, block diagonal"]["mul!"] = @benchmarkable mul!($d, $F, $m)
SUITE["DBlock, homogeneous, block diagonal"]["mul"] = @benchmarkable $F * $m
SUITE["DBlock, homogeneous, block diagonal"]["jacobian"] = @benchmarkable jacobian!($F, $m)
SUITE["DBlock, homogeneous, block diagonal"]["mul!, linear"] = @benchmarkable mul!($d, $J, $m)
SUITE["DBlock, homogeneous, block diagonal"]["mul, linear"] = @benchmarkable $J * $m
SUITE["DBlock, homogeneous, block diagonal"]["mul!, adjoint"] = @benchmarkable mul!($m, ($J)', $d)
SUITE["DBlock, homogeneous, block diagonal"]["mul, adjoint"] = @benchmarkable ($J)' * $d
SUITE["DBlock, homogeneous, block diagonal"]["adjoint"] = @benchmarkable $(J)'
SUITE["DBlock, homogeneous, block diagonal"]["shape"] = @benchmarkable shape($F)
SUITE["DBlock, homogeneous, block diagonal"]["size"] = @benchmarkable size($F)
SUITE["DBlock, homogeneous, block diagonal"]["domain"] = @benchmarkable domain($F)
SUITE["DBlock, homogeneous, block diagonal"]["range"] = @benchmarkable range($F)
SUITE["DBlock, homogeneous, block diagonal"]["dom,block"] = @benchmarkable getblock($m, 3)
SUITE["DBlock, homogeneous, block diagonal"]["dom,block!"] = @benchmarkable setblock!($m, 3, $(rand(100)))
SUITE["DBlock, homogeneous, block diagonal"]["rng,block"] = @benchmarkable getblock($d, 10)
SUITE["DBlock, homogeneous, block diagonal"]["rng,block!"] = @benchmarkable setblock!($d, 10, $(rand(100)))