text:
module FactorFF
using Hecke, Markdown

function Hecke.norm(f::PolyElem{<: Generic.FunctionFieldElem})
    K = base_ring(f)
    P = polynomial_to_power_sums(f, degree(f)*degree(K))
    PQ = elem_type(base_field(K))[tr(x) for x in P]
    return power_sums_to_polynomial(PQ)
end

function from_mpoly(f::MPolyElem, S::PolyRing{<:Generic.Rat})
  @assert ngens(parent(f)) == 2
  @assert base_ring(f) == base_ring(base_ring(S))
  R = parent(numerator(gen(base_ring(S))))
  @assert isa(R, PolyRing)
  F = [zero(R) for i=0:degree(f, 1)]
  for (c, e) = zip(coefficients(f), exponent_vectors(f))
    setcoeff!(F[e[1]+1], e[2], c)
  end
  o = one(parent(F[1]))
  return S(map(x->base_ring(S)(x//o), F))
end

function Hecke.factor(f::Generic.Poly{<:Generic.Rat})
  Pf = parent(f)
  R, r = PolynomialRing(base_ring(base_ring(f)), 2)
  d = lcm(map(denominator, coefficients(f)))
  Fc = MPolyBuildCtx(R)
  for i=0:degree(f)
    c = numerator(coeff(f, i)*d)
    for j=0:degree(c)
      push_term!(Fc, coeff(c, j), [i,j])
    end
  end
  lf = factor(finish(Fc))
  @assert is_constant(lf.unit)

  fa = Fac(Pf(constant_coefficient(lf.unit)), Dict((from_mpoly(k, Pf), e) for (k,e) = lf))
  @assert sum(degree(x)*y for (x,y) = fa) == degree(f)
  return fa
end

function Hecke.factor(f::Generic.Poly{<:Generic.Rat{T}}, F::Generic.FunctionField{T}) where {T}
  return factor(map_coefficients(F, f))
end
#plain vanilla Trager, possibly doomed in pos. small char.
function Hecke.factor(f::Generic.Poly{<:Generic.FunctionFieldElem})
  if !is_squarefree(f)
    sf = gcd(f, derivative(f))
    f = divexact(f, sf)
  else
    sf = one(parent(f))
  end
  lc = leading_coefficient(f)
  f = divexact(f, lc)
  i = 0
  local N
  g = f
  t = gen(parent(f))
  a = gen(base_ring(t))

  while true
    if !iszero(constant_coefficient(g))
      N = norm(g)
      if is_squarefree(N)
        break
      end
    end
    i += 1
    g = evaluate(g, t-a)
    if i > 10
      error("not plausible")
    end
  end

  fN = factor(N)
  @assert isone(fN.unit)
  D = Fac(parent(f)(lc), Dict((gcd(map_coefficients(base_ring(f), p, parent = parent(f)), g)(t+i*a), k) for (p,k) = fN.fac))
  if !isone(sf)
    for k = keys(D.fac)
      D.fac[k] += valuation(sf, k)
    end
  end
  return D
end

#TODO: don't think this startegy is optimal, but it works...
function Hecke.splitting_field(f::Generic.Poly{<:Generic.Rat})
  f = divexact(f, gcd(f, derivative(f)))

  lf = factor(f)
  lf = [x for x = keys(lf.fac) if degree(x) > 1]
  if length(lf) == 0
    return base_ring(f)
  end

  while true
    G, b = FunctionField(lf[1], "b", cached = false)
    if length(lf) == 1 && degree(G) < 3
      return G
    end

    f = prod(lf)

    GT, t = PolynomialRing(G, cached = false)
    g = divexact(map_coefficients(G, f, parent = GT), t-b)

    i = 0
    local N
    while true
      if !iszero(constant_coefficient(g))
        N = norm(g)
        if is_squarefree(N)
          break
        end
      end
      i += 1
      g = evaluate(g, t-b)
      if i > 10
        error("not plausible")
      end
    end

    fN = factor(N)
    lf = [x for x = keys(fN.fac) if degree(x) > degree(G)]
      #the gcd of x with deg(x) == deg(G) will yield a linear
      #factor, hence does not contribute further
    if length(lf) == 0
      return G
    end
  end
end

@doc Markdown.doc"""
    swinnerton_dyer(V::Vector, x::Generic.Poly{<:Generic.Rat})
    swinnerton_dyer(n::Int, x::Generic.Poly{<:Generic.Rat})

Compute the minimal polynomial of $\sum \pm \sqrt{t+v_i}$ evaluated at $x$.
$t$ is the generator of the base field of the parent of $x$.

In the second variant, the polynomial has roots $\sum\pm\sqrt{t+i}$ for
  $i=1,\ldots,n$.
"""
function Hecke.swinnerton_dyer(V::Vector, x::Generic.Poly{<:Generic.Rat})
  n = length(V)
  @assert characteristic(parent(x)) == 0 || characteristic(parent(x)) > length(V)
  S = base_ring(x)
  T = gen(S)
  X = gen(parent(x))
  l = [(X^2 + T + i) for i = V]
  l = [ vcat([2*one(S)], polynomial_to_power_sums(x, 2^n)) for x = l]
  while n > 1
    i = 1
    while 2*i <= n
      l[i] = [sum(binomial(fmpz(h), fmpz(j))*l[2*i-1][j+1]*l[2*i][h-j+1] for j=0:h) for h=0:length(l[1])-1]
      i += 1
    end
    if isodd(n)
      l[i] = l[n]
      n = i
    else
      n = i-1
    end
  end
  f = power_sums_to_polynomial(l[1][2:end], parent(x))
  if x == gen(parent(x))
    return f
  else
    return f(x)
  end
end

function Hecke.swinnerton_dyer(n::Int, x::Generic.Poly{<:Generic.Rat})
  return swinnerton_dyer(x, collect(1:n))
end

end


text:
# Restricted Permutation Generator

export RPG

"""
    RPG(n::Int, allow::Dict{Int,Set{Int}})

Create a list of all length-`n` repetition-free lists `p` in which `p[k]`
must be an element of `allow[k]`.
"""
function RPG(
    n::Int,
    allow::Dict{Int,Set{Int}},
    forbid::BitSet = BitSet(),
)::Vector{Vector{Int}}
    @assert n > 0 "`n` must be positive, got $n"

    result = Vector{Vector{Int}}()

    if n == 1
        for k ∈ allow[1]
            if k ∉ forbid
                p = [k]
                push!(result, p)
            end
        end
        return result
    end

    for last ∈ allow[n]
        if last ∉ forbid
            push!(forbid, last)

            sub_result = RPG(n - 1, allow, forbid)

            for p in sub_result
                push!(p, last)
                push!(result, p)
            end
            pop!(forbid, last)
        end
    end
    return result

end

"""
    make_allow(A::Matrix)

Given a matrix, create an "allow" dictionary where the
allowed values for key `k` are the indices of the zeros
in row `k`.
"""
function make_allow(A::Matrix)
    r, c = size(A)
    allow = Dict{Int,Set{Int}}()

    for i = 1:r
        row = A[i, :]
        allow[i] = Set(findall(t -> t == 0, row))
    end
    return allow

end

ext: jl


text:
using GtkObservables, Gtk.ShortNames, Colors

# Create some controls
n = slider(1:10)
dd = dropdown(["one"=>()->println("you picked \"one\""),
               "two"=>()->println("two for tea"),
               "three"=>()->println("three is a magic number")],
              label="dropdown")
cb = checkbox(true, label="make window visible")

# To illustrate some of Observables's propagation, we create a textbox
# that shares the observable with the slider.
tb = textbox(Int; observable=n.observable)

# Set up the mapping for the dropdown callbacks
cbhandle = on(dd.mappedsignal) do cb  # assign to variable to prevent garbage collection
    cb()
end

# Lay out the GUI. You can alternatively use `glade` and pass the
# widgets to the constructors above (see the implementation of
# `player` in `extrawidgets.jl` for an example).
mainwin = Window("GtkObservables")
vbox = Box(:v)
hbox = Box(:h)
push!(vbox, hbox)
push!(hbox, n)
push!(hbox, tb)
push!(vbox, dd)
push!(vbox, cb)
push!(mainwin, vbox)

# Create the auxillary window and link its visibility to the checkbox
cnvs = canvas()
auxwin = Window(cnvs)
showwin = map(cb) do val
    set_gtk_property!(auxwin, "visible", val)
end
# Also make sure it gets destroyed when we destroy the main window
signal_connect(mainwin, "destroy") do w
    destroy(auxwin)
end
# Draw something in the auxillary window
draw(cnvs) do c
    fill!(c, colorant"orange")
end
Gtk.showall(auxwin)

Gtk.showall(mainwin)


text:
using ModelingToolkit, ModelingToolkitStandardLibrary, OrdinaryDiffEq
using ModelingToolkitStandardLibrary.Blocks

@parameters t

@testset "Constant" begin
    @named src = Constant(k=2)
    @named int = Integrator()
    @named iosys = ODESystem([
        connect(src.output, int.input),
        ],
        t,
        systems=[int, src],
    )
    sys = structural_simplify(iosys)

    prob = ODEProblem(sys, Pair[int.x=>0.0], (0.0, 10.0))

    sol = solve(prob, Rodas4())
    @test sol[src.output.u][end] ≈ 2 atol=1e-3
end

@testset "Sine" begin
    sine(t, frequency, amplitude, phase, offset, start_time) = offset + ifelse(t < start_time, 0, amplitude* sin(2*pi*frequency*(t - start_time) + phase))

    frequency=1
    amplitude=2
    phase=0
    offset=1
    start_time=0

    @named src = Sine(frequency=frequency, amplitude=amplitude, phase=phase, offset=offset, start_time=start_time)
    @named int = Integrator()
    @named iosys = ODESystem([
        connect(src.output, int.input),
        ],
        t,
        systems=[int, src],
    )
    sys = structural_simplify(iosys)

    prob = ODEProblem(sys, Pair[int.x=>0.0], (0.0, 10.0))

    sol = solve(prob, Rodas4())
    @test sol[src.output.u] ≈ sine.(sol.t, frequency, amplitude, phase, offset, start_time) atol=1e-3
end

@testset "Cosine" begin
    cosine(t, frequency, amplitude, phase, offset, start_time) = offset + ifelse(t < start_time, 0, amplitude* cos(2*pi*frequency*(t - start_time) + phase))

    frequency=1
    amplitude=2
    phase=0
    offset=1
    start_time=0

    @named src = Cosine(frequency=frequency, amplitude=amplitude, phase=phase, offset=offset, start_time=start_time)
    @named int = Integrator()
    @named iosys = ODESystem([
        connect(src.output, int.input),
        ],
        t,
        systems=[int, src],
    )
    sys = structural_simplify(iosys)

    prob = ODEProblem(sys, Pair[int.x=>0.0], (0.0, 10.0))

    sol = solve(prob, Rodas4())
    @test sol[src.output.u] ≈ cosine.(sol.t, frequency, amplitude, phase, offset, start_time) atol=1e-3
end

@testset "ContinuousClock" begin
    cont_clock(t, offset, start_time) = offset + ifelse(t < start_time, 0, t - start_time)

    offset, start_time = 1, 0

    @named src = ContinuousClock(offset=offset, start_time=start_time)
    @named int = Integrator()
    @named iosys = ODESystem([
        connect(src.output, int.input),
        ],
        t,
        systems=[int, src],
    )
    sys = structural_simplify(iosys)

    prob = ODEProblem(sys, Pair[int.x=>0.0], (0.0, 10.0))

    sol = solve(prob, Rodas4())
    @test sol[src.output.u] ≈ cont_clock.(sol.t, offset, start_time) atol=1e-3
end

@testset "Ramp" begin
    ramp(t, offset, height, duration, start_time) = offset + ifelse(t < start_time, 0, ifelse(t < (start_time + duration), (t - start_time) * height / duration, height))

    offset, height, duration, start_time = 1, 2, 2, 0

    @named src = Ramp(offset=offset, height=height, duration=duration, start_time=start_time)
    @named int = Integrator()
    @named iosys = ODESystem([
        connect(src.output, int.input),
        ],
        t,
        systems=[int, src],
    )
    sys = structural_simplify(iosys)

    prob = ODEProblem(sys, Pair[int.x=>0.0], (0.0, 10.0))

    sol = solve(prob, Rodas4())
    @test sol[src.output.u] ≈ ramp.(sol.t, offset, height, duration, start_time) atol=1e-3
end

@testset "Step" begin
    step(t, offset, height, start_time) = offset + ifelse(t < start_time, 0, height)

    offset, height, start_time = 1, 2, 5

    @named src = Step(offset=offset, height=height, start_time=start_time)
    @named int = Integrator()
    @named iosys = ODESystem([
        connect(src.output, int.input),
        ],
        t,
        systems=[int, src],
    )
    sys = structural_simplify(iosys)

    prob = ODEProblem(sys, Pair[int.x=>0.0], (0.0, 10.0))

    sol = solve(prob, Rodas4())
    @test sol[src.output.u] ≈ step.(sol.t, offset, height, start_time) atol=1e-3
end

@testset "ExpSine" begin
    exp_sine(t, amplitude, frequency, damping, phase, start_time) = offset + ifelse(t < start_time, 0, amplitude * exp(-damping * (t - start_time)) * sin(2*pi*frequency*(t - start_time) + phase))

    frequency, amplitude, damping, phase, offset, start_time = 3, 2, 0.10, 0, 0, 0

    @named src = ExpSine(frequency=frequency, amplitude=amplitude, damping=damping, phase=phase, offset=offset, start_time=start_time)
    @named int = Integrator()
    @named iosys = ODESystem([
        connect(src.output, int.input),
        ],
        t,
        systems=[int, src],
    )
    sys = structural_simplify(iosys)

    prob = ODEProblem(sys, Pair[int.x=>0.0], (0.0, 10.0))

    sol = solve(prob, Rodas4())
    @test sol[src.output.u] ≈ exp_sine.(sol.t, amplitude, frequency, damping, phase, start_time) atol=1e-3
end


text:
###
# This script is designed for multi-core parallelizaition
# run
# julia -p N 9_subway_preps.jl
# where N is the number of cores you want to use.
#
# For a reasonable running time use a machine with at least 32 cores
#
#

using Distributed
println("using $(Distributed.nworkers()) worker(s)")

@everywhere using Pkg
@everywhere Pkg.activate(".")

using HTTP, CSV, DataFrames, OpenStreetMapX
@everywhere using HTTP
@everywhere using CSV
@everywhere using DataFrames
@everywhere using OpenStreetMapX

preread = OpenStreetMapX.get_map_data(".", "las_vegas.osm");

@everywhere const map_data = OpenStreetMapX.get_map_data(".", "las_vegas.osm");

println("The map contains $(length(map_data.nodes)) nodes")

function point_to_node(point::LLA, map_data::OpenStreetMapX.MapData)
    nearest_node(map_data.nodes,ENU(point, map_data.bounds), map_data)
end

sbws_la = CSV.read("Subway_LV.csv")

N = nrow(sbws_la)
N = 4 # omit this line to get a real-life scale computation, but it is long

@everywhere function calc_distances(i,N, sbws_la)
    open(string(lpad(i,4,"0"),"_distance.csv"),"w") do f
        for j in 1:N
            dista = 0.0
            route = [sbws_la.node[i]]
            if sbws_la.node[i] != sbws_la.node[j]
                route, dista, time = shortest_route(map_data, sbws_la.node[i], sbws_la.node[j])
            end
            println(f,"$i,$j,$dista,$(join(route,"#"))")
        end
    end
end

all_no = @distributed (+) for i in 1:N
    calc_distances(i, N, sbws_la)
    1
end

println("Finished for $all_no nodes")


text:
"""
Genie utilities for working over HTTP.
"""
module HTTPUtils

import HTTP

"""
    Base.Dict(req::HTTP.Request) :: Dict{String,String}

Converts a `HTTP.Request` to a `Dict`.
"""
function Base.Dict(req::HTTP.Request) :: Dict{String,String}
  result = Dict{String,String}()
  for (k,v) in Dict(req.headers)
    result[lowercase(string(k))] = lowercase(string(v))
  end

  result
end

end


text:
#!/usr/bin/env julia
include("rf_cfchange.jl")
imgdir = joinpath("..", "..", "images")

se = map(s->map(a->agsrrs(a, 93, s, 1980, 2015), keys(ages)), [1;2])

function savesexplot(d, trans)
	close()
	plotsex(d, trans)
	savefig(joinpath(imgdir, "Sv8015_$(d[:sex])$(d[:age])RfInd$(ucfirst("$(trans)")).svg"))
	close()
end

function saverdiffplot(ds)
	close()
	plotrdiffps(keys(ages), ds, map(sds->sds[:rdiffs_cbs], ds))
	savefig(joinpath(imgdir, "Sv8015_$(ds[1][:sex])Rdiffs.svg"))
	close()
end

savesexplot(se[1][3], :log)
savesexplot(se[1][3], :lin)
saverdiffplot(se[1])
saverdiffplot(se[2])

max_stars_repo_name: klpn/static-dust

max_issues_repo_name: klpn/static-dust

max_forks_repo_name: klpn/static-dust


text:
module MyModule
function complexfunc(a::Int, b::Int)::Float64
    x = rand(Float64, (a, a))
    for i in 1:b
        x += rand(Float64, (a, a))
    end

    z::Float64 = 0.0
    for j in 1:a
        z += x[j, j]
    end

    z
end
end

max_stars_repo_name: gobuki/jlrs

max_issues_repo_name: gobuki/jlrs

max_forks_repo_name: gobuki/jlrs


text:
"""
Callback-based algorithm for decomposition on topology for Ground Structure with
Discrete Diameters.

Solver object to store parameter values.
"""
struct CallbackTopo <: GroundStructureSolver
    mastersolver
    subsolver
    timelimit::Float64 # seconds
    writemodels::Bool

    function CallbackTopo(mastersolver, subsolver;
                          timelimit=Inf, writemodels=false)
        new(mastersolver, subsolver, timelimit, writemodels)
    end
end

"Callbacks for decomposition based on topology"
function PipeLayout.optimize(inst::Instance, topo::Topology,
                             solver::CallbackTopo)
    # initialization
    finaltime = time() + solver.timelimit

    # reuse master problem from IterTopo algorithm
    model, y, q = make_semimaster(inst, topo, solver.mastersolver)
    solver.writemodels && writeLP(model, "master.lp", genericnames=false)

    # get access to SCIP.Optimizer instance (not factory)
    scip::SCIP.Optimizer = JuMP.backend(model)

    # enforce tree topology with constraint handler (higher prio)
    treetopohdlr = TreeTopoHdlr(scip)
    SCIP.include_conshdlr(scip, treetopohdlr; needs_constraints=true,
                          enforce_priority=-15,
                          check_priority=-7_000_000)
    SCIP.add_constraint(scip, treetopohdlr, TreeTopoCons(topo, y))

    # enforce feasible subproblems with constraint handler (lower prio)
    semisubhdlr = SemiSubHdlr(scip, solver.subsolver, finaltime)
    SCIP.include_conshdlr(scip, semisubhdlr; needs_constraints=true,
                          enforce_priority=-16,
                          check_priority=-7_100_000)
    SCIP.add_constraint(scip, semisubhdlr,
                        SemiSubCons(inst, topo, y, q))

    # solve the master (including callback)
    JuMP.optimize!(model)
    status = JuMP.termination_status(model)
    if !(status in (MOI.OPTIMAL, MOI.INFEASIBLE, MOI.TIME_LIMIT, MOI.NODE_LIMIT))
        error("Unexpected status: $(status)")
    end

    # actually, we solved it, but the master does not know
    if status == MOI.INFEASIBLE && semisubhdlr.best_solution !== nothing
        status = MOI.OPTIMAL
    end
    @debug "  solved, status: $(status)."

    # TODO: extract dual bound, nnodes?
    Result(status, semisubhdlr.best_solution, semisubhdlr.primal_bound, Inf, -1)
end


text:
"""
    Search.Sphere(x, y, z, radius)
    Search.Sphere(center, radius)

Create a `Search.Sphere` that can be used for spatial lookup.

See also `AbstractRegion`
"""
struct Sphere{T <: Real} <: AbstractRegion{T}
    x::T
    y::T
    z::T
    radius::T
end

@inline function Sphere(center::AbstractVector{T}, radius::Number) where {T}
    @assert length(center) == 3
    @inbounds return Sphere{T}(center[1], center[2], center[3], radius)
end

function boundingbox(region::Sphere{T}) where T
    xmin = region.x - region.radius
    xmax = region.x + region.radius
    ymin = region.y - region.radius
    ymax = region.y + region.radius
    zmin = region.z - region.radius
    zmax = region.z + region.radius

    return BoundingBox{T}(xmin, ymin, zmin, xmax, ymax, zmax)
end

@inline function in(p::StaticVector{3, <:Real}, sphere::Sphere)
    diff = p - SVector(sphere.x, sphere.y, sphere.z)
    r² = sphere.radius * sphere.radius
    return dot(diff, diff) <= r²
end

@inline function volume(s::Sphere{T}) where T
     (convert(T, 4) / convert(T, 3)) * pi * s.radius * s.radius
end


text:
"""
    combinedims(array_of_arrays)

Combine the dimensions of a nested array structure into a new, flat array.

This is the inverse operation of `splitdims` / `splitdimsview`.

See also `combinedimsview`, the lazy version of this function.

# Example

```julia
julia> combinedims([[1, 2], [3, 4]])
2×2 Array{Int64,2}:
 1  3
 2  4
```
"""
combinedims(a::AbstractArray{<:AbstractArray{<:Any, N}, M}) where {N,M} = _combinedims(a, Val(ntuple(identity, Val(N))))

function _combinedims(a::AbstractArray, ::Val{dims}) where {dims}
    outeraxes = axes(a)
    inneraxes = _inneraxes(a)
    newaxes = (inneraxes..., outeraxes...) # TODO support permutation
    T = inner_eltype(a)

    out = similar(a, T, newaxes)
    for i in CartesianIndices(inneraxes)
        for j in CartesianIndices(outeraxes)
            out[i.I..., j.I...] = a[j][i]
        end
    end
    return out
end

_inneraxes(a) = axes(first(a)) # Can specialize this for static arrays, for example

inner_eltype(a) = Any
inner_eltype(a::AbstractArray{<:AbstractArray{T}}) where {T} = T

## Lazy version

struct CombineDimsArray{T, N, A} <: AbstractArray{T, N}
    parent::A
end

Base.parent(a::CombineDimsArray) = a.parent

Base.size(a::CombineDimsArray) = (size(first(parent(a)))..., size(parent(a))...)
axes(a::CombineDimsArray) = (axes(first(parent(a)))..., axes(parent(a))...)
Base.IndexStyle(::CombineDimsArray) = Base.IndexCartesian()
@propagate_inbounds function Base.getindex(a::CombineDimsArray{T, N}, i::Vararg{Int, N}) where {T, N}
    outer_ndims = ndims(parent(a))
    inner_ndims = N - outer_ndims
    outer_inds = ntuple(j -> @inbounds(return i[j+inner_ndims]), Val(outer_ndims))
    inner_inds = ntuple(j -> @inbounds(return i[j]), Val(inner_ndims))
    return parent(a)[outer_inds...][inner_inds...]
end

"""
    combinedimsview(array_of_arrays)

Lazily create a flat array view of a nested array structure.

This is the inverse operation of `splitdims` / `splitdimsview`.

See also `combinedims`, the eager version of this function.
"""
function combinedimsview(a::AbstractArray{<:AbstractArray{T, N}, M}) where {T, N, M}
    return CombineDimsArray{inner_eltype(a), N + M, typeof(a)}(a)
end


text:
function solve()
    n = readline()
    if n[end] in ['2', '4', '5', '7', '9']
        "hon"
    elseif n[end] in ['0', '1', '6', '8']
        "pon"
    else
        "bon"
    end
end

println(solve())

max_stars_repo_name: aishikawa/atcoder-julia

max_issues_repo_name: aishikawa/atcoder-julia

max_forks_repo_name: aishikawa/atcoder-julia


text:
## https://developer.spotify.com/documentation/web-api/reference/#/operations/get-playlist

"""
    playlist_get(playlist_id::String; additional_types::String="track", fields::String="",
    market::String="US")

**Summary**: Get details about a playlist owned by a Spotify user.

# Arguments
- `playlist_id::String` : Alphanumeric ID of the playlist

# Optional keywords
- `additional_types::String` : "track" (default) or "episode"
- `fields::String` : Filters for the query, a comma-separated list of the fields to return.
                     For example, to get just the added date and user ID of the adder,
                     fields = "items(added_at,added_by.id)". Default is set to "", which means
                     all fields are returned.
- `market::String` : An ISO 3166-1 alpha-2 country code. If a country code is specified,
                     only episodes that are available in that market will be returned.
                     Default is set to "US".

# Example
```julia-repl
julia> Spotify.playlist_get("37i9dQZF1E4vUblDJbCkV3")[1]
JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 15 entries:
  :collaborative => false
  :description   => "With Roo Panes, Hiss Golden Messenger, Nathaniel Rateliff and more"
  :external_urls => {…
  :followers     => {…
  :href          => "https://api.spotify.com/v1/playlists/37i9dQZF1E4vUblDJbCkV3?additional_types=track"
  :id            => "37i9dQZF1E4vUblDJbCkV3"
  :images        => JSON3.Object[{…
  :name          => "Lord Huron Radio"
  :owner         => {…
  :primary_color => nothing
  :public        => false
  :snapshot_id   => "MTYzNTg2NzMxNCwwMDAwMDAwMGU3MTgwNDkzOWE5NTQ2NGM1NmYzNTYyZDhhZTc1ZGNh"
  :tracks        => {…
  :type          => "playlist"
  :uri           => "spotify:playlist:37i9dQZF1E4vUblDJbCkV3"
```
"""
function playlist_get(playlist_id; additional_types::String="track", fields::String="",
                      market::String="US")

    url1 = "playlists/$(playlist_id)?additional_types=$additional_types"
    url2 = "&fields=$fields&market=$market"

    return Spotify.spotify_request(url1 * url2)

end

## https://developer.spotify.com/documentation/web-api/reference/#/operations/get-playlists-tracks

"""
    playlist_get_tracks(playlist_id::String; additional_types="track", limit=50,
    offset=0, market="US")

**Summary**: Get details about the items of a playlist.

# Arguments
- `playlist_id::String` : Alphanumeric ID of the playlist

# Optional keywords
- `additional_types::String` : "track" (default) or "episode"
- `fields::String` : Filters for the query, a comma-separated list of the fields to return.
                     For example, to get just the added date and user ID of the adder,
                     fields = "items(added_at,added_by.id)". Default is set to "", which means
                     all fields are returned.
- `limit::Int64` : Maximum number of items to return, default is set to 20
- `offset::Int64` : Index of the first item to return, default is set to 0
- `market::String` : An ISO 3166-1 alpha-2 country code. If a country code is specified,
                     only episodes that are available in that market will be returned.
                     Default is set to "US".

# Example
```julia-repl
julia> Spotify.playlist_get_tracks("37i9dQZF1E4vUblDJbCkV3")[1]
JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 7 entries:
  :href     => "https://api.spotify.com/v1/playlists/37i9dQZF1E4vUblDJbCkV3/tracks?offset=0&limit=20&market=US&additional_types=…
  :items    => JSON3.Object[{…
  :limit    => 20
  :next     => "https://api.spotify.com/v1/playlists/37i9dQZF1E4vUblDJbCkV3/tracks?offset=20&limit=20&market=US&additional_types…
  :offset   => 0
  :previous => nothing
  :total    => 50
```
"""
function playlist_get_tracks(playlist_id; additional_types::String="track", fields::String="",
                             limit::Int64=20, offset::Int64=0, market::String="US")

    url1 = "playlists/$(playlist_id)/tracks?additional_types=$additional_types"
    url2 = "&fields=$fields&limit=$limit&offset=$offset&market=$market"

    return Spotify.spotify_request(url1 * url2)

end

## https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-list-of-current-users-playlists

"""
    playlist_get_current_user(limit::Int64=20, offset::Int64=0)

**Summary**: Get a list of the playlists owned or followed by the current Spotify user.

# Optional keywords
- `limit::Int64` : Maximum number of items to return, default is set to 20
- `offset::Int64` : Index of the first item to return, default is set to 0

# Example
```julia-repl
julia> Spotify.playlist_get_current_user()[1]
[ Info: We try the request without checking if current grant includes scope playlist-read-private.
JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 7 entries:
  :href     => "https://api.spotify.com/v1/users/your_user_id/playlists?offset=0&limit=20"
  :items    => JSON3.Object[{…
  :limit    => 20
  :next     => nothing
  :offset   => 0
  :previous => nothing
  :total    => 2
```
"""
function playlist_get_current_user(;limit::Int64=20, offset::Int64=0)

    return Spotify.spotify_request("me/playlists?limit=$limit&offset=$offset"; scope = "playlist-read-private")

end

## https://developer.spotify.com/documentation/web-api/reference/#/operations/get-list-users-playlists

"""
    playlist_get_user(user_id::String; limit::Int64=20, offset::Int64=0)

**Summary**: Get a list of the playlists owned or followed by a Spotify user.

# Arguments
- `user_id::String` : Alphanumeric ID of the user or name (e.g. "smedjan")

# Optional keywords
- `limit::Int64` : Maximum number of items to return, default is set to 20
- `offset::Int64` : Index of the first item to return, default is set to 0

# Example
```julia-repl
julia> Spotify.playlist_get_user("smedjan")[1]
JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 7 entries:
  :href     => "https://api.spotify.com/v1/users/smedjan/playlists?offset=0&limit=20"
  :items    => JSON3.Object[{…
  :limit    => 20
  :next     => "https://api.spotify.com/v1/users/smedjan/playlists?offset=20&limit=20"
  :offset   => 0
  :previous => nothing
  :total    => 98
```
"""
function playlist_get_user(user_id; limit::Int64=20, offset::Int64=0)

    return Spotify.spotify_request("users/$user_id/playlists?limit=$limit&offset=$offset")

end

## https://developer.spotify.com/documentation/web-api/reference/#/operations/get-featured-playlists

"""
    playlist_get_featured(;country::String="US", limit::Int64=20, locale::String="en_US",
                               offset::Int64=0, timestamp::String="$(Dates.now())")

**Summary**: Get a list of Spotify featured playlists (shown, for example, on a Spotify player's 'Browse' tab).

# Optional keywords
- `country::String` : An ISO 3166-1 alpha-2 country code. Provide this parameter if you want
                      the list of returned items to be relevant to a particular country.
                      Default is set to "US".
- `limit::Int64` : Maximum number of items to return, default is set to 20
- `locale::String` : The desired language, consisting of a lowercase ISO 639-1 language code and an uppercase
                     ISO 3166-1 alpha-2 country code, joined by an underscore. For example: es_MX, meaning "Spanish (Mexico)".
                     Provide this parameter if you want the results returned in a particular language (where available).
                     Default is set to "en_US".
- `offset::Int64` : Index of the first item to return, default is set to 0
- `timestamp::String` : A timestamp in ISO 8601 format: yyyy-MM-ddTHH:mm:ss. Use this parameter to specify the user's local time
                        to get results tailored for that specific date and time in the day.
                        Default is set to user's current time.

# Example
```julia-repl
julia> Spotify.playlist_get_featured(locale="en_UK")[1]
JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 2 entries:
  :message   => "Tuesday jams"
  :playlists => {…
```
"""
function playlist_get_featured(;country::String="US", limit::Int64=20, locale::String="en_US",
                               offset::Int64=0, timestamp::String="$(Dates.now())")

    url1 = "browse/featured-playlists?country=$country&limit=$limit"
    url2 = "&locale=$locale&offset=$offset&timestamp=$timestamp"

    return Spotify.spotify_request(url1 * url2)

end

## https://developer.spotify.com/documentation/web-api/reference/#/operations/get-a-categories-playlists

"""
    playlist_get_category(category_id::String; country::String="US", limit::Int64=20, offset::Int64=0)

**Summary**: Get a list of Spotify playlists tagged with a particular category.

# Arguments
- `category_id::String` : The unique string identifying the Spotify category, e.g. "dinner", "party" etc.

# Optional keywords
- `country::String` : An ISO 3166-1 alpha-2 country code. Provide this parameter if you want
                      the list of returned items to be relevant to a particular country.
                      Default is set to "US".
- `limit::Int64` : Maximum number of items to return, default is set to 20
- `offset::Int64` : Index of the first item to return, default is set to 0

# Example
```julia-repl
julia> Spotify.playlist_get_category("party")[1]
JSON3.Object{Base.CodeUnits{UInt8, String}, Vector{UInt64}} with 1 entry:
  :playlists => {…
```
"""
function playlist_get_category(category_id; country::String="US", limit::Int64=20, offset::Int64=0)

    url1 = "browse/categories/$category_id/playlists?country=$country"
    url2 = "&limit=$limit&offset=$offset"

    return Spotify.spotify_request(url1 * url2)

end

## https://developer.spotify.com/documentation/web-api/reference/#/operations/get-playlist-cover

"""
    playlist_get_cover_image(playlist_id::String)

**Summary**: Get the current image associated with a specific playlist.

# Arguments
- `playlist_id::String` : Alphanumeric ID of the playlist

# Example
```julia-repl
julia> Spotify.playlist_get_cover_image("37i9dQZF1E4vUblDJbCkV3")[1]
1-element JSON3.Array{JSON3.Object, Base.CodeUnits{UInt8, String}, Vector{UInt64}}:
 {
   "height": nothing,
      "url": "https://seeded-session-images.scdn.co/v1/img/artist/6ltzsmQQbmdoHHbLZ4ZN25/en",
    "width": nothing
}
```
"""
function playlist_get_cover_image(playlist_id)

    return Spotify.spotify_request("playlists/$playlist_id/images")

end


text:
using WordTokenizers
using InternedStrings

"simply the built-in split function for the origin tokenize method in subword-nmt"
whitespace_tokenize(str::AbstractString) = split(str)

"get vocab with frequency counts"
function get_vocab(vfile::AbstractString; normalizer)
    vocab = Dict{String, Int}()
    open(vfile) do io
        for line ∈ eachline(io)
            line = normalize(normalizer, line)
            for word ∈ intern.(tokenize(line))
                vocab[word] = get(vocab, word, 0) + 1
            end
        end
    end
    vocab
end

struct BPELearner
    num_sym::Int
    min_freq::Int
    endsym::String
    vfiles::Vector{String}

    stats::Statistic
    result::Vector{Pair{String, String}}

    normalizer::AbstractNormalizer

    function BPELearner(vfiles::Vector{String}, num_sym::Int;
                        min_freq::Int = 2, endsym::String = "</w>",
                        normalizer=UnNormalizer())
        vocab = mapreduce((f)->get_vocab(f; normalizer=normalizer), merge!, vfiles)
        stats = Statistic(vocab)
        endsym != "</w>" && set_endsym(endsym)
        new(num_sym, min_freq, endsym, vfiles,
            stats,
            Vector{Pair{String, String}}(undef, num_sym),
            normalizer)
    end
end

"add a new file to learner"
function add!(bper::BPELearner, vfile::String)
    push!(bper.vfiles, vfile)
    nv = get_vocab(vfile; normalizer=bper.normalizer)
    update!(bper.stats, nv)
end

"learn a BPE map"
function learn!(bper::BPELearner)
    if isassigned(bper.result)
        bper.result = Vector(undef, bper.num_sym)
    end

    for i ∈ 1:bper.num_sym
        mfp = most_freq(bper.stats)
        get_freq(bper.stats, mfp) < bper.min_freq && (resize!(bper.result, i-1); break)
        merge_pair!(bper.stats, mfp)
        bper.result[i] = mfp
    end
end

"emit the BPE map to ofile; can add one-line comment to the header(first line)"
function emit(bper::BPELearner, ofile::AbstractString; comment::String = "")
    @assert '\n' ∉ comment && '\r' ∉ comment
    open(ofile, "w+") do fo
        write(fo, ":$comment#endsym:$(bper.endsym)\n")
        for (f, s) ∈ bper.result
            write(fo, f, " ", s, "\n")
        end
    end
    ofile
end

function Base.show(io::IO, b::BPELearner)
    println(io, "BPELearner(",
            "num_sym=$(b.num_sym), ",
            "min_freq=$(b.min_freq), ",
            "endsym=\"$(b.endsym)\", ",
            "normailzer=$(typeof(b.normalizer)))")
    io
end


text:
function read_groups(lines)
    groups = []
    current_group = []
    for line in lines
        if isempty(line)
            push!(groups, current_group)
            current_group = []
        else
            push!(current_group, line)
        end
    end
    push!(groups, current_group)
    groups
end

function calc_group_sum(groups)
    s = 0
    for group in groups
        s += length(Set(question for person in group for question in person))
    end
    s
end

function main()
    lines = readlines("../resources/input_06.txt")
    groups = read_groups(lines)
    result = calc_group_sum(groups)
    println(result)
end

main()


text:
# This file was generated by the Julia Swagger Code Generator
# Do not modify this file directly. Modify the swagger specification instead.

@doc raw"""
    ObjsSubteamPrefs(;
        channels=nothing,
        groups=nothing,
    )

    - channels::Vector{DefsChannelId}
    - groups::Vector{DefsGroupId}
"""
mutable struct ObjsSubteamPrefs <: SwaggerModel
    channels::Any # spec type: Union{ Nothing, Vector{DefsChannelId} } # spec name: channels
    groups::Any # spec type: Union{ Nothing, Vector{DefsGroupId} } # spec name: groups

    function ObjsSubteamPrefs(;channels=nothing, groups=nothing)
        o = new()
        validate_property(ObjsSubteamPrefs, Symbol("channels"), channels)
        setfield!(o, Symbol("channels"), channels)
        validate_property(ObjsSubteamPrefs, Symbol("groups"), groups)
        setfield!(o, Symbol("groups"), groups)
        o
    end
end # type ObjsSubteamPrefs

const _property_map_ObjsSubteamPrefs = Dict{Symbol,Symbol}(Symbol("channels")=>Symbol("channels"), Symbol("groups")=>Symbol("groups"))
const _property_types_ObjsSubteamPrefs = Dict{Symbol,String}(Symbol("channels")=>"Vector{DefsChannelId}", Symbol("groups")=>"Vector{DefsGroupId}")
Base.propertynames(::Type{ ObjsSubteamPrefs }) = collect(keys(_property_map_ObjsSubteamPrefs))
Swagger.property_type(::Type{ ObjsSubteamPrefs }, name::Symbol) = Union{Nothing,eval(Base.Meta.parse(_property_types_ObjsSubteamPrefs[name]))}
Swagger.field_name(::Type{ ObjsSubteamPrefs }, property_name::Symbol) =  _property_map_ObjsSubteamPrefs[property_name]

function check_required(o::ObjsSubteamPrefs)
    (getproperty(o, Symbol("channels")) === nothing) && (return false)
    (getproperty(o, Symbol("groups")) === nothing) && (return false)
    true
end

function validate_property(::Type{ ObjsSubteamPrefs }, name::Symbol, val)
end


text:
import MixedModels: GeneralizedLinearMixedModel,
                    pirls!,
                    setβθ!,
                    setθ!
import Distributions: Distribution,
                      Bernoulli,
                      Binomial,
                      Gamma,
                      Gaussian,
                      InverseGaussian,
                      Poisson

import GLM: Link,
            CauchitLink,
            CloglogLink,
            LogitLink,
            IdentityLink,
            InverseLink,
            LogLink,
            ProbitLink,
            SqrtLink

import RCall: rcopy,
              RClass,
              rcopytype,
              reval,
              S4Sxp,
              sexp,
              protect,
              unprotect,
              sexpclass,
              @rput,
              @rget
# if RCall is available, then so is DataFrames
using DataFrames
import CategoricalArrays: CategoricalArray
import Tables: columntable, ColumnTable

# # from R
function rcopy(::Type{GeneralizedLinearMixedModel}, s::Ptr{S4Sxp})
    data = nothing;
    # try
    #     data = rcopy(s[:frame]);
    # catch err
    #     if !isa(err, DimensionMismatch) # matrix columns -- cbind!
    #         throw(err)
    #     end
    # go back up to the original data frame
    # this will only work if that data frame is still available in the
    # current environment. There may be a better way to unwind this
    # but that will involve more R black magic
    data = rcopy(R"eval($(s[:call][:data]))")
    # end

    try
        contrasts = rcopy(s[:call][:contrasts])
        @error "Contrasts must be specified in the dataframe, not the glmer() call"
    catch err
        if !isa(err, BoundsError) # this is the error we were expecting
            rethrow(err)
        end
        # no extra contrasts defined, we continue on our way
    end

    contrasts = get_r_contrasts(s[:frame])

    wts = []
    try
        wts = rcopy(s[:call][:weights])
        wts = data[!, wts]
    catch err
        if !isa(err, BoundsError)
            rethrow(err)
        end
        # no weights defined, we continue on our way
        try
            wts = rcopy(s[:resp][:n])
        catch err
            if !isa(err, BoundsError)
                rethrow(err)
            end
            # no weights here either, we continue on our way
        end
    end

    # the function terms are constructed but reference non existent vars
    # need to somehow recontr
    f = convert_r_to_julia(s[:call][:formula])
    family = rcopy(R"$(s[:resp])$family$family")
    if family in ("quasi", "quasibinomial", "quasipoisson")
        throw(ArgumentError("quasi families are not supported"))
    elseif family in ("gaussian", "Gamma", "inverse.gaussian")
        throw(ArgumentError("GLMMs with dispersion parameters are known to give incorrect results in MixedModels.jl (see PR#291), aborting."))
    elseif family in ("poisson", "binomial")
        family = titlecase(family)
    else
        throw(ArgumentError("Unknown and hence unsupported family: $family"))
    end

    family = eval(Symbol(family))

    link = rcopy(R"$(s[:resp])$family$link")
    link in ["logit", "probit", "cauchit",
             "log", "identity", "inverse", "sqrt",
             "cloglog"] || throw(ArgumentError("Link $urlink not supported"))
    link = titlecase(link) * "Link"
    link = eval(Symbol(link))

    nAGQ = rcopy(s[:devcomp][:dims][:nAGQ])
    fast = nAGQ == 0
    if nAGQ == 0
        nAGQ = 1
    end

    m = GeneralizedLinearMixedModel(f,columntable(data), family(), link(), wts=wts)
    m.optsum.feval = rcopy(s[:optinfo][:feval])
    θ = rcopyarray(s[:theta])
    β = rcopyarray(s[:beta])

    if length(θ) != length(m.θ)
        @error """You're probably using || in R with a categorical variable,
                  whose translation is currently unsupported with MixedModels 3.0."""
        throw(ArgumentError("Parameter vectors in R and Julia are different sizes."))
    end

    θ = _reorder_theta_from_lme4(θ, m)

    m.optsum.final = fast ? θ : [β; θ]
    m.optsum.optimizer = Symbol("$(rcopy(s[:optinfo][:optimizer])) (lme4)")
    m.optsum.returnvalue = rcopy(s[:optinfo][:conv][:opt]) == 0 ? :FAILURE : :SUCCESS
    m.optsum.fmin = rcopy(s[:devcomp][:cmp][:dev])
    m.optsum.nAGQ = nAGQ
    setpar! = fast ? setθ! : setβθ!
    return pirls!(setpar!(m, m.optsum.final), fast)
end

rcopytype(::Type{RClass{:glmerMod}}, s::Ptr{S4Sxp}) = GeneralizedLinearMixedModel

# from Julia
function sexp(::Type{RClass{:glmerMod}}, x::Tuple{GeneralizedLinearMixedModel{T}, DataFrame}) where T
    m, tbl = x
    m.optsum.feval > 0 || throw(ArgumentError("Model must be fitted"))

    distribution =  Distribution(m.resp)
    family = urfamily = replace(string(distribution), Regex("{.*}") => "")
    # ["Bernoulli","Binomial","Gamma", "Poisson", "InverseGaussian"]
    # R families: binomial, gaussian, Gamma, inverse.gaussian, poisson
    #             quasi, quasibinomial, quasipoisson
    # should we @warn for the way GLMM deviance is defined in lme4?
    # we construct this piece-by-piece because this keeps the warnings
    # and everything in sync
    supported = ("Bernoulli", "Binomial", "Poisson")
    if family in ("Bernoulli", "Binomial")
        family = "binomial"
    elseif family == "Poisson"
        family = "poisson"
    elseif family in ("Gamma","Gaussian","InverseGaussian")
        throw(ArgumentError("GLMMs with dispersion parameters are known to give incorrect results in MixedModels.jl (see PR#291), aborting."))
    else
        throw(ArgumentError("Family $family is not supported"))
    end

    urlink = string(Link(m.resp))
    link = lowercase(replace(urlink, "Link()" => ""))

    link in ["logit", "probit", "cauchit",
             "log", "identity", "inverse", "sqrt",
             "cloglog"] || throw(ArgumentError("Link $urlink not supported"))

    if length(m.optsum.initial) - length(m.β) < 0
        nAGQ = 0
    else
        nAGQ = m.optsum.nAGQ
    end

    # if !isempty(m.sqrtwts)
    #     @error "weights are not currently supported"
    # end

    jellyme4_data = tbl
    if urfamily == "Bernoulli"
        lhs = m.formula.lhs
        # should we check for PooledArray? brings in another dependency...
        if !(jellyme4_data[!,lhs.sym] isa CategoricalArray)
            @warn "Response was not categorical, converting in place"
            categorical!(jellyme4_data, [lhs.sym])
        end
    end
    formula = convert_julia_to_r(m.formula)

    jellyme4_theta = _reorder_theta_to_lme4(m)
    jellyme4_beta = m.β
    jellyme4_weights = m.wt
    length(jellyme4_weights) > 0 || (jellyme4_weights = nothing)
    fval = m.optsum.fmin
    feval = m.optsum.feval
    conv = m.optsum.returnvalue == :SUCCESS ? 0 : 1
    optimizer = String(m.optsum.optimizer)
    message = "fit with MixedModels.jl"
    rsteps = 1;

    betastart = nAGQ > 0 ? "fixef=jellyme4_beta, " : ""

    GLMER = LMER in ("afex::lmer_alt", "lmer_alt") ? LMER : "lme4::glmer"

    @rput jellyme4_data
    @rput jellyme4_theta
    @rput jellyme4_beta
    @rput jellyme4_weights

    set_r_contrasts!("jellyme4_data", m.formula)

    r = """
        jellyme4_mod <- $(GLMER)(formula = $(formula),
                               data=jellyme4_data,
                               family=$family(link="$link"),
                               nAGQ=$(nAGQ),
                               weights=jellyme4_weights,
                               control=lme4::glmerControl(optimizer="nloptwrap",
                                                          optCtrl=list(maxeval=$(rsteps)),
                                        calc.derivs=FALSE,
                                        check.nobs.vs.nRE= "warning"),
                                start=list($(betastart)theta=jellyme4_theta))
         jellyme4_mod@optinfo\$feval <- $(feval)
         jellyme4_mod@optinfo\$message <- "$(message)"
         jellyme4_mod@optinfo\$optimizer <- "$(optimizer)"
         jellyme4_mod
    """
    @debug r
    @warn """Some accuracy is lost in translation for GLMMs. This is fine with plotting, but proceed with caution for inferences.
             You can try letting the model "reconverge" in lme4 with
                 update(model, control=glmerControl(optimizer="nloptwrap", calc.derivs=FALSE)).""" maxlog=1
    @info "lme4 handles deviance for GLMMs differently than MixedModels.jl" maxlog=1
    @info "for the correct comparison, examine -2*logLik(RModel) and deviance(JuliaModel)" maxlog=1
    r = reval(r)
    r = protect(sexp(r))
    unprotect(1)
    r
end

sexpclass(x::Tuple{GeneralizedLinearMixedModel{T}, DataFrame}) where T = RClass{:glmerMod}

# generalize to ColumnTable, which is what MixedModels actually requires
function sexp(ss::Type{RClass{:glmerMod}}, x::Tuple{GeneralizedLinearMixedModel{T}, ColumnTable}) where T
    m, t  = x
    sexp(ss, (m, DataFrame(t)))
end

sexpclass(x::Tuple{GeneralizedLinearMixedModel{T}, ColumnTable}) where T = RClass{:glmerMod}


text:
export segy_scan

"""
    segy_scan(dir::String, filt::String, keys::Array{String,1}, blocksize::Int;
                           chunksize::Int = 1024,
                           pool::WorkerPool = WorkerPool(workers()),
                           verbosity::Int = 1,
                           delim_keys::Array{String,1}=["SourceX","SourceY"])

    returns: SeisCon

Scan header fields `keys` of files in `dir` matching the filter `filt` in blocks
containing `blocksize` continguous traces. The scanning of files is distributed to workers
in `pool`, the default pool is all workers.

`chunksize` determines how many MB of data will be loaded into memory at a time.

`verbosity` set to 0 silences updates on the current file being scanned.

`delim_keys` is the list of headers to check for changes that flag the start of
a new block (ensemble).

"""
function segy_scan(dir::String, filt::String, keys::Array{String,1},
                    blocksize::Int;
                    chunksize::Int = 1024,
                    pool::WorkerPool = WorkerPool(workers()),
                    verbosity::Int = 1,
                    filter::Bool = true,
                    delim_keys::Array{String,1}=["SourceX","SourceY"])

    endswith(dir, "/") ? nothing : dir *= "/"
    filter ? (filenames = searchdir(dir, filt)) : (filenames = [filt])
    files = map(x -> dir*x, filenames)
    files_sort = files[sortperm(filesize.(files), rev = true)]
    run_scan(f) = scan_file(f, keys, blocksize, chunksize=chunksize,
                verbosity=verbosity, delim_keys=delim_keys)
    s = pmap(pool, run_scan, files_sort, delim_keys)

    return merge(s)
end

function segy_scan(dirs::Array{String,1}, filt::String, keys::Array{String,1},
                    blocksize::Int;
                    chunksize::Int = 1024,
                    pool::WorkerPool = WorkerPool(workers()),
                    verbosity::Int = 1,
                    filter::Bool = true,
                    delim_keys::Array{String,1}=["SourceX","SourceY"])

    files = Array{String,1}()
    for dir in dirs
        endswith(dir, "/") ? nothing : dir *= "/"
        filter ? (filenames = searchdir(dir, filt)) : (filenames = [filt])
        append!(files, map(x -> dir*x, filenames))
    end
    files_sort = files[sortperm(filesize.(files), rev = true)]
    run_scan(f) = scan_file(f, keys, blocksize, chunksize=chunksize,
                        verbosity=verbosity, delim_keys=delim_keys)
    s = pmap(pool, run_scan, files_sort)

    return merge(s)
end

"""
    segy_scan(dir::String, filt::String, keys::Array{String,1})

If no `blocksize` is specified, the scanner automatically detects source locations and returns
blocks of continguous traces for each source location.
"""
function segy_scan(dir::String, filt::String, keys::Array{String,1};
                    chunksize::Int = 1024,
                    pool::WorkerPool = WorkerPool(workers()),
                    verbosity::Int = 1,
                    filter::Bool = true,
                    delim_keys::Array{String,1}=["SourceX","SourceY"])

    endswith(dir, "/") ? nothing : dir *= "/"
    filter ? (filenames = searchdir(dir, filt)) : (filenames = [filt])
    files = map(x -> dir*x, filenames)
    files_sort = files[sortperm(filesize.(files), rev = true)]
    run_scan(f) = scan_file(f, keys, chunksize=chunksize, verbosity=verbosity,
                            delim_keys=delim_keys)
    s = pmap(run_scan, files_sort)

    return merge(s)
end

"""
    segy_scan(dir::Array{String,1}, filt::String, keys::Array{String,1})

Scans all files whose name contains `filt` in each directory of `dir`.
"""
function segy_scan(dirs::Array{String,1}, filt::String, keys::Array{String,1};
                    chunksize::Int = 1024,
                    pool::WorkerPool = WorkerPool(workers()),
                    verbosity::Int = 1,
                    filter::Bool = true,
                    delim_keys::Array{String,1}=["SourceX","SourceY"])

    files = Array{String,1}()
    for dir in dirs
        endswith(dir, "/") ? nothing : dir *= "/"
        filter ? (filenames = searchdir(dir, filt)) : (filenames = [filt])
        append!(files, map(x -> dir*x, filenames))
    end
    files_sort = files[sortperm(filesize.(files), rev = true)]
    run_scan(f) = scan_file(f, keys, chunksize=chunksize, verbosity=verbosity,
                            delim_keys=delim_keys)
    s = pmap(pool, run_scan, files_sort)

    return merge(s)
end

searchdir(path,filt) = filter(x->occursin(filt,x), readdir(path))


text:
using Test
using JSONPointer
using OrderedCollections

@testset "Basic Tests" begin
    doc = Dict(
        "foo" => ["bar", "baz"],
        "" => 0,
        "a/b" => 1,
        "c%d" => 2,
        "e^f" => 3,
        "g|h" => 4,
        "i\\j" => 5,
        "k\"l" => 6,
        " " => 7,
        "m~n" => 8
    )

    @test doc[j""] == doc
    @test doc[j"/foo"] == ["bar", "baz"]
    @test doc[JSONPointer.Pointer("/foo/0"; shift_index = true)] == "bar"
    @test doc[j"/foo/1"] == "bar"
    @test doc[j"/"] == 0
    @test doc[j"/a~1b"] == 1
    @test doc[j"/c%d"] == 2
    @test doc[j"/e^f"] == 3
    @test doc[j"/g|h"] == 4
    @test doc[JSONPointer.Pointer("/i\\j")] == 5
    @test doc[j"/k\"l"] == 6
    @test doc[j"/ "] == 7
    @test doc[j"/m~0n"] == 8

    for k in (
        j"",
        j"/foo",
        j"/foo/1",
        j"/",
        j"/a~1b",
        j"/c%d",
        j"/e^f",
        j"/g|h",
        JSONPointer.Pointer("/i\\j"),
        j"/k\"l",
        j"/ ",
        j"/m~0n",
    )
        @test haskey(doc, k)
    end
end

@testset "URI Fragment Tests" begin
    doc = Dict(
        "foo" => ["bar", "baz"],
        ""=> 0,
        "a/b"=> 1,
        "c%d"=> 2,
        "e^f"=> 3,
        "g|h"=> 4,
        "i\\j"=> 5,
        "k\"l"=> 6,
        " "=> 7,
        "m~n"=> 8,
    )

    @test doc[j"#"] == doc
    @test doc[j"#/foo"] == ["bar", "baz"]
    @test doc[JSONPointer.Pointer("#/foo/0"; shift_index = true)] == "bar"
    @test doc[j"#/foo/1"] == "bar"
    @test doc[j"#/"] == 0
    @test doc[j"#/a~1b"] == 1
    @test doc[j"#/c%25d"] == 2
    @test doc[j"#/e%5Ef"] == 3
    @test doc[j"#/g%7Ch"] == 4
    @test doc[j"#/i%5Cj"] == 5
    @test doc[j"#/k%22l"] == 6
    @test doc[j"#/%20"] == 7
    @test doc[j"#/m~0n"] == 8
end

@testset "WrongInputTests" begin
    @test_throws ArgumentError JSONPointer.Pointer("some/thing")
    doc = [0, 1, 2]
    @test_throws(
        ErrorException(
            "JSON pointer does not match the data-structure. I tried (and " *
            "failed) to index $(doc) with the key: a"
        ),
        doc[j"/a"],
    )
    @test_throws BoundsError doc[j"/10"]
end

@testset "JSONPointer Advanced" begin
    a = j"/a/2/d::array"
    b = j"/a/2/e::object"
    c = j"/a/2/f::boolean"

    @test a.tokens == ["a", 2, "d"]
    @test eltype(a) <: Vector{Any}
    @test eltype(b) <: OrderedDict{String, Any}
    @test eltype(c) <: Bool
end

@testset "construct Dict with JSONPointer" begin
    p1 = j"/a/1/b"
    p2 = j"/cd/2/ef"

    data = Dict(p1 =>1, p2 => 2)
    @test data[p1] == 1
    @test data[p2] == 2
    @test haskey(data, p1)
    @test haskey(data, p2)
    @test !haskey(data, j"/x")
    @test !haskey(data, j"/ba/5")

    p1 = j"/ab/1"
    p2 = j"/cd/2/ef"

    data = OrderedDict(p1 => "This", p2 => "Is my Data")
    @test data[p1] == "This"
    @test data[p2] == "Is my Data"
end

@testset "access deep nested object" begin
    data = [Dict("a" => 10)]
    @test data[j"/1/a"] == 10

    p1 = j"/a/b/c/d/e/f/g/1/2/a/b/c"
    data = Dict(p1 => "sooo deep")
    @test data[p1] == "sooo deep"
    @test get(data, p1, missing) == "sooo deep"

    @test haskey(data, j"/a/b/c")
    @test haskey(data, j"/a/b/c/d")
    @test haskey(data, j"/a/b/c/d/e/f/g/1")
    @test !haskey(data, j"/a/b/c/d/e/f/g/2")

    @test isa(data[j"/a/b/c"], AbstractDict)
    @test isa(data[j"/a/b/c/d"], AbstractDict)
    @test isa(data[j"/a/b/c/d/e"], AbstractDict)
    @test isa(data[j"/a/b/c/d/e/f/g"], Array)
    @test ismissing(data[j"/a/b/c/d/e/f/g/1/1"])

    @test get(data, j"/a/f", missing) |> ismissing
    @test get(data, j"/a/b/c/d/e/f/g/5", 10000) == 10000

    @test_throws KeyError data[j"/a/f"]
    @test_throws KeyError data[j"/x"]
    @test_throws BoundsError data[j"/a/b/c/d/e/f/g/5"]

    data = [[10, 20, 30, ["me"]]]
    @test data[j"/1"] == [10, 20, 30, ["me"]]
    @test data[j"/1/2"] == 20
    @test data[j"/1/4"] == ["me"]
    @test data[j"/1/4/1"] == "me"

    # need to add get for Array?
    @test_broken get(data, j"/1", missing) |> ismissing
end

@testset "literal string for a Number" begin
    p1 = j"/\5"
    p2 = j"/\559"
    p3 = j"/\900/10"

    d = Dict(p1 => 1, p2 => 2, p3 => 3)
    @test d[p1] == 1
    @test d["5"] == 1
    @test d[p2] == 2
    @test d["559"] == 2

    @test d[p3] == 3
    @test isa(d["900"], Array)
end

@testset "unique" begin
    p = [j"/a", j"/b", j"/a"]
    up = unique(p)
    @test length(up) == 2
    @test j"/a" in up
    @test j"/b" in up
end

@testset "Failed setindex!" begin
    d = Dict("a" => [1])
    @test_throws ErrorException d[j"/a/b"] = 1
end

@testset "grow object and array" begin
    d = Dict(j"/a" => Dict())
    d[j"/a/b"] = []
    d[j"/a/b/2"] = 1
    d[j"/a/b/5"] = 2
    @test_throws Exception d[j"/a/5"] = "something"
    @test_throws Exception d[j"/a/b/gd"] = "nothing"

    @test isa(d[j"/a/b"], Array)
    @test isa(d[j"/a/b/1"], Missing)
end

@testset "Enforce type on JSONPointer" begin
    p1 = j"/a/1::string"
    p2 = j"/a/2::number"
    p3 = j"/a/3::object"
    p4 = j"/a/4::array"
    p5 = j"/a/5::boolean"
    p6 = j"/a/6::null"

    data = Dict(p1 =>"string", p2 => 1, p3 => Dict(), p4 => [], p5 => true, p6 => missing)
    @test data[p1] == "string"
    @test data[p2] == 1

    @test_throws ErrorException data[p1] = 1
    @test_throws ErrorException data[p2] = "string"

    d = Dict(p1 =>missing, p2 => missing, p3 => missing, p4 => missing, p5 => missing)
    @test d[p1] == ""
    @test d[p2] == 0
    @test isa(d[p3], OrderedDict)
    @test isa(d[p4], Array{Any, 1})
    @test d[p5] == false
end

@testset "Exceptions" begin
    # error on undefined datatype
    @test_throws ErrorException JSONPointer.Pointer("/a::nothing")
    @test_throws ErrorException JSONPointer.Pointer("/a/1::Int")

    # error for 0 based indexing
    @test_throws ArgumentError JSONPointer.Pointer("/0")
    @test_throws ArgumentError JSONPointer.Pointer("/a/0")
    @test isa(JSONPointer.Pointer("/0"; shift_index = true), JSONPointer.Pointer)

end

@testset "Miscellaneous" begin
    p1 = j"/a/b/1/c"

    @test p1 == j"/a/b/1/c"
    @test p1 != j"/b/a/1/c"

    arr = [1,2,3]
    haskey(arr, j"/1")
    !haskey(arr, j"/4")
end


text:
# Interpolation
xs = 1:5
ys = 1:8
g = Float64[x^2 * sin(y) for x in xs, y in ys]

gitp_quad2d = interpolate(g, BSpline(Quadratic(Line(OnCell()))))
using Gadfly
display(plot(x=xs,y=ys,z=g,Geom.contour))
display(plot(x=1:.1:5, y=1:.1:8, z=[gitp_quad2d(x,y) for x in 1:.1:5, y in 1:.1:8], Geom.contour))

xs = [1; 2]
ys = [3; 9]
g = ys
myinterp = LinearInterpolation([1 3; 2 4], BSpline(Linear()))
myinterp(1.5,1.5)

function grid_shift(A, row_vals, )

myinterp = LinearInterpolation([1 3; 2 4], BSpline(Linear()))
myinterp(1.5,1.5)

function interpolate_cols(X, Y, X_grid::Array; extrapolation_bc = Throw())
    #linear interpolation of a column of Y on that column of X, evaluated at point x
    Y_interp = similar(X_grid)
    for col in eachindex(X_grid[1,:])
        li = LinearInterpolation(X[:,col], Y[:,col],extrapolation_bc=extrapolation_bc)
        Y_interp[:,col] = li.(X_grid[:,col])
    end
    return Y_interp
end

A = [1. 3.; 2. 4.; 3. 5.]
A_vals = [6.; 7.; 8.]
Y_vals = [3; 5]

function invert_rule(A,A_vals)
    A_interp = similar(A)
    for col in eachindex(A[1,:])
        li = LinearInterpolation(A[:,col], A_vals, extrapolation_bc = Line())
        # use extrapolate and do different for each side fixed value/line
        A_interp[:,col] = li.(A_vals)
    end
    return A_interp
end

A_inv = invert_rule(A, A_vals)
li = interpolate(invert_rule(A, A_vals), BSpline(Linear()))
li(1.5,1.5)

function grid_shift(A, A_vals_old, A_vals_new, Y_vals_old, Y_vals_new)
    A_grid = zeros( eltype(A_inv[1]), length(A[:,1]), length(Y_vals) )

    # Find relative coordinates of new basis
    li = LinearInterpolation(Y_vals_old, 1:length(Y_vals_old), extrapolation_bc=Line())
    Y_ind = li(Y_vals_new)
    li = LinearInterpolation(A_vals_old, 1:length(A_vals_old), extrapolation_bc=Line())
    A_ind = li(A_vals_new)

    # Bi-linear interpolation on new coordinates
    li = interpolate(A_inv, BSpline(Linear()) )  #extrapolate with boundary rules
    [ A_grid[i,j] = li(A_ind, Y_ind) for  (i, A_ind) in enumerate(A_ind), (j, Y_ind) in enumerate(Y_ind)]
    return A_grid
end

A_inv = [1. 3.; 2. 4.; 2.5 5.5]
A_vals = [6.; 7.; 8.]
Y_vals = [3; 5]
Y_vals_new = [3.1; 4.9]
A_shift = grid_shift(A, A_vals, A_vals, Y_vals, Y_vals_new)
Plots.heatmap(A_inv)
Plots.heatmap(A_shift)
plot()
Plotly.plot(A_inv, st=:surface, camera=(-30,30))
Plotly.plot(A_shift, st=:surface, camera=(-30,30))

#############
plot(A_vals, Y_vals, A_inv, st=:scatter, camera=(45,45))
li = interpolate(A_inv, BSpline(Linear()))
plot(li, st=:surface, camera=(-30,30))
li(1.5,1.5)

A_vals_new = [6.5; 7.; 8.5]

Y_vals_new = [3; 5]
grid_shift(A_inv, A_vals, Y_vals, A_vals_new, Y_vals_new)

A_vals_old = [3.5;4.0;5.0;7.0]
scatter(A_vals_old)
scatter!(A_vals_new)
A_vals_new = [3.6;4.0;6;7.0]
li = LinearInterpolation(A_vals_old, 1:length(A_vals_old), extrapolation_bc=Line())
li(A_vals_new)

# Find indices for new grid bases
li_A = LinearInterpolation(A_vals_old, A_vals_new, extrapolation_bc=Line())
@show A_inds = li_A(A_vals_old) .- minimum(A_vals_old) .+ 1
li_Y = LinearInterpolation(Y_vals_old, Y_vals_new, extrapolation_bc=Line())
@show Y_inds = li_Y(Y_vals_old) .- minimum(Y_vals_old) .+ 1

A = [1. 3.; 2. 4.; 3. 5.]
A_vals = [6.; 7.; 8.]
Y_vals = [3; 5]
Y_vals_new = [4]
A_shift = grid_shift(A, A_vals, A_vals, Y_vals, Y_vals_new)
plot(repeat(A_vals,1,length(Y_vals)),repeat(Y_vals', length(A_vals),1), A, st=:surface, camera=(-30,30))
Plotly.plot(A_shift, st=:surface, camera=(-30,30))

A |> size
repeat(A_vals,1,length(Y_vals)) |> size
repeat(Y_vals', length(A_vals),1) |> size
using Plots
pyplot()

plot(A_vals, Y_vals, vec(A), st=:surface, camera=(-30,30))

vec(A)
A

A = [3. 4; 5 6; 7 7]
A_vals = [6.; 7.; 8.]
A_vals_new = [3.1;5;6.9]
Y_vals = [3; 5]
Y_vals_new = [2.5; 4.5]
li = interpolate([1;2;3], A_vals, BSpline(Linear()))
li = extrapolate(interpolate(A[:,1], A_vals, Gridded(Linear())), extrapolation_bc = (0.,Line()))
minimum(A[:,1])
maximum(A[:,1])
li(A_vals_new)
A_inv1 = invert_rule(A,A_vals)
A_inv2 = invert_rule(A,A_vals_new)
A_shift = grid_shift(A, A_vals, A_vals_new, Y_vals, Y_vals)
plotly()
plot(repeat(A_vals,length(Y_vals)),vec(repeat(Y_vals', length(A_vals),1 )),vec(A), st=:scatter, camera=(-30,30))
plot!(repeat(A_vals_new,length(Y_vals)),vec(repeat(Y_vals', length(A_vals_new),1 )),vec(A_shift), st=:scatter, camera=(-30,30))

plotly()
plot(repeat(A_vals,length(Y_vals)),vec(repeat(Y_vals', length(A_vals),1 )),vec(A_inv1), st=:scatter, camera=(-30,30))
plot!(repeat(A_vals_new,length(Y_vals)),vec(repeat(Y_vals', length(A_vals_new),1 )),vec(A_inv2), st=:scatter, camera=(-30,30))

plotly()
plot(repeat(A_vals,length(Y_vals)),vec(repeat(Y_vals', length(A_vals),1 )),vec(A), st=:scatter, camera=(-30,30))
plot!(repeat(A_vals,length(Y_vals)),vec(repeat(Y_vals', length(A_vals),1 )),vec(A_inv), st=:scatter, camera=(-30,30))

plot!(repeat(A_vals_new,length(Y_vals_new)),vec(repeat(Y_vals_new', length(A_vals_new),1 )),vec(A_shift), st=:scatter, camera=(-30,30))

using Plots, Interpolations
B = [x^2 for x in 1.:10]
scatter(1.:10,B, legend=:bottomright)
li = extrapolate(interpolate(B, BSpline(Linear())), 0.)
x2=0.:11.
B_interp = li(x2)
scatter(x2, B_interp)
B_interp = extrapolate(interpolate(B, BSpline(Linear())), 0.)(x2)


text:
import Base: one, zero, realmax, eps, issubnormal, isnan, isfinite

one{N, ES, mode}(T::Type{Sigmoid{N, ES, mode}}) = reinterpret(T, @invertbit)
zero{N, ES, mode}(T::Type{Sigmoid{N, ES, mode}}) = reinterpret(T, zero(@UInt))

@generated function maxpos{N, ES, mode}(T::Type{Sigmoid{N, ES, mode}})
  v = (@signbit) - increment(Sigmoid{N, ES, mode})
  :(reinterpret(T, $v))
end
realmax{N,ES,mode}(T::Type{Sigmoid{N, ES, mode}}) = maxpos(T)

@generated function minpos{N, ES, mode}(T::Type{Sigmoid{N, ES, mode}})
  v = zero(@UInt) + increment(Sigmoid{N, ES, mode})
  :(reinterpret(T, $v))
end
realmin{N,ES,mode}(T::Type{Sigmoid{N, ES, mode}}) = minpos(T)

@generated function maxneg{N, ES, mode}(T::Type{Sigmoid{N, ES, mode}})
  v = zero(@UInt) - increment(Sigmoid{N, ES, mode})
  :(reinterpret(T, $v))
end

@generated function minneg{N, ES, mode}(T::Type{Sigmoid{N, ES, mode}})
  v = (@signbit) + increment(Sigmoid{N, ES, mode})
  :(reinterpret(T, $v))
end

@generated function eps{N, ES, mode}(T::Type{Sigmoid{N, ES, mode}})
  if mode == :ubit
  else
  end
end

#no subnormals, no NaNs
issubnormal{N,ES,mode}(x::Sigmoid{N, ES, mode}) = false
isnan{N,ES,mode}(x::Sigmoid{N, ES, mode}) = false
isfinite{N,ES,mode}(x::Sigmoid{N, ES, mode}) = (@u(x) != @signbit)
#isfinite{N,ES}(x::Sigmoid{N, ES, :upper}) = false
#isfinite{N,ES}(x::Sigmoid{N, ES, :lower}) = false
#isfinite{N,ES}(x::Sigmoid{N, ES, :cross}) = false

#iszeroinf
iszeroinf(x::Sigmoid) = reinterpret(@UInt, x) & (~@signbit) == 0

#special constant type symbols
struct ∞; end
struct ∞n; end

Base.:-(::Type{∞}) = ∞n
Base.convert{N, ES, mode}(T::Type{Sigmoid{N, ES, mode}}, ::Type{∞}) = T(Inf)
Base.convert{N, ES, mode}(T::Type{Sigmoid{N, ES, mode}}, ::Type{∞n}) = T(Inf)

export ∞

max_stars_repo_name: ityonemo/SigmoidNumbers

max_issues_repo_name: ityonemo/SigmoidNumbers

max_forks_repo_name: ityonemo/SigmoidNumbers


text:
using Pkg

# Activate the project’s Julia environment
Pkg.activate(".julia")

# Download all required packages listed in Manifest.toml
Pkg.instantiate()

# Set Python executable and re-build PyCall
ENV["PYTHON"] = Sys.which("python")
Pkg.build("PyCall")
using PyCall
println("Using Python executable at '$(PyCall.python)'")


text:
function _precompile_()
    ccall(:jl_generating_output, Cint, ()) == 1 || return nothing
    precompile(Tuple{typeof(VectorizationBase.T_shift),Type{Float32}})
    precompile(Tuple{typeof(VectorizationBase.T_shift),Type{Int32}})
    precompile(Tuple{typeof(VectorizationBase.llvmtype),Type{T} where T})
    precompile(Tuple{typeof(VectorizationBase.mask_type),Type{Float32}})
    precompile(Tuple{typeof(VectorizationBase.pick_vector_width),Int64,Type{Float32}})
    precompile(Tuple{typeof(VectorizationBase.pick_vector_width),Int64,Type{Float64}})
    precompile(Tuple{typeof(VectorizationBase.pick_vector_width),Type{Float32}})
    precompile(Tuple{typeof(VectorizationBase.pick_vector_width),Val{3},Type{Float32}})
    precompile(Tuple{typeof(VectorizationBase.pick_vector_width),Val{3},Type{Float64}})
    precompile(Tuple{typeof(VectorizationBase.vzero),Val{8},Type{Float32}})
    precompile(Tuple{typeof(which(VectorizationBase.pick_vector_width_val,(Vararg{Any,N} where N,)).generator.gen),Any,Any})
end


text:
using FactCheck, MarketData
FactCheck.setstyle(:compact)
FactCheck.onlystats(true)

facts("Unit tests confirm correct algorithm implementation") do

    p = plot(cl, op)

    context("plot object attributes") do
        @fact typeof(p.x1)   --> Winston.HalfAxisX
        @fact p.attr[:title] --> "AAPL Close"
    end
end


text:
### A Pluto.jl notebook ###
# v0.16.1

using Markdown
using InteractiveUtils

# ╔═╡ c9638116-dbb8-403e-8d91-fca7da74c537
begin
	using Images
end

# ╔═╡ 604d28a6-22c3-11ec-2d40-39598d3636ed
md"""
# Local Binary Patterns

Local Binary Patterns (LBP) are a commonly used feature in texture analysis. The method is rotation invariant and also grayscale invariant. LBP works by thresholding the neighborhood of each pixel and considers the result as a binary number.
"""

# ╔═╡ 9f638f37-9ab4-4ca7-9156-3e80441702b2
load("images/lbp.png")

# ╔═╡ 06e3821f-ac6f-4be2-95e2-65a6e11ba82e
begin
	img = load("images/casent0173484.jpg")
	gray_image = Gray.(img)
end

# ╔═╡ df6364ad-162a-4f98-bc10-04be07f0aa8a
md"""
Load image and convert to grayscale.
"""

# ╔═╡ 9924f0a1-642c-4632-8855-5f340805748e
const offsets = [
	[- 1, - 1], [- 1, 0], [- 1, 1],
	[0, 1], [1, 1], [1, 0],
	[1, - 1], [0, - 1]
]

# ╔═╡ 2ae72e48-30ee-44ee-93ee-801df4060be2
bit_pattern = falses(length(offsets))

# ╔═╡ ac2a9681-90cb-450f-aa75-4efcfe02a71d
function _lbp(bit_pattern::BitVector)
	res = sum((b * 1) << (length(bit_pattern) - i) for (i, b) in enumerate(bit_pattern))
	return n0f8(res / 256)
end

# ╔═╡ 706130bf-064e-40da-b80a-30d7ec59da78
function lbp(img::Array{T,2}) where T <: Gray
	res = zeros(size(img))
	R = CartesianIndices(size(img))
	bit_pattern = falses(length(offsets))
	for I in R
		for (i, o) in enumerate(offsets) bit_pattern[i] = img[I] >= bilinear_interpolation(img, I[1] + o[1], I[2] + o[2]) end
		res[I] = _lbp(bit_pattern)
	end
	return res
end

# ╔═╡ c95d159e-e957-45e5-9697-e5d4e912ca02
RGB.(lbp(gray_image))

# ╔═╡ be87bd3a-15d7-43c1-8504-dad5daec23cb
md"""
1. local minimum
2. experiment with larger subimages than 3x3
3. find most common textures
"""

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0"

[compat]
Images = "~0.24.1"
"""

# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised

[[AbstractFFTs]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "485ee0867925449198280d4af84bdb46a2a404d0"
uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c"
version = "1.0.1"

[[Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.1"

[[ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"

[[ArrayInterface]]
deps = ["Compat", "IfElse", "LinearAlgebra", "Requires", "SparseArrays", "Static"]
git-tree-sha1 = "b8d49c34c3da35f220e7295659cd0bab8e739fed"
uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
version = "3.1.33"

[[Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

[[AxisAlgorithms]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"]
git-tree-sha1 = "a4d07a1c313392a77042855df46c5f534076fab9"
uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950"
version = "1.0.0"

[[AxisArrays]]
deps = ["Dates", "IntervalSets", "IterTools", "RangeArrays"]
git-tree-sha1 = "d127d5e4d86c7680b20c35d40b503c74b9a39b5e"
uuid = "39de3d68-74b9-583c-8d2d-e117c070f3a9"
version = "0.4.4"

[[Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[CEnum]]
git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9"
uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
version = "0.4.1"

[[CatIndices]]
deps = ["CustomUnitRanges", "OffsetArrays"]
git-tree-sha1 = "a0f80a09780eed9b1d106a1bf62041c2efc995bc"
uuid = "aafaddc9-749c-510e-ac4f-586e18779b91"
version = "0.2.2"

[[ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "e8a30e8019a512e4b6c56ccebc065026624660e8"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "1.7.0"

[[ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"

[[ColorVectorSpace]]
deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "SpecialFunctions", "Statistics", "TensorCore"]
git-tree-sha1 = "45efb332df2e86f2cb2e992239b6267d97c9e0b6"
uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4"
version = "0.9.7"

[[Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.8"

[[Compat]]
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
git-tree-sha1 = "31d0151f5716b655421d9d75b7fa74cc4e744df2"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.39.0"

[[CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"

[[ComputationalResources]]
git-tree-sha1 = "52cb3ec90e8a8bea0e62e275ba577ad0f74821f7"
uuid = "ed09eef8-17a6-5b46-8889-db040fac31e3"
version = "0.3.2"

[[CoordinateTransformations]]
deps = ["LinearAlgebra", "StaticArrays"]
git-tree-sha1 = "6d1c23e740a586955645500bbec662476204a52c"
uuid = "150eb455-5306-5404-9cee-2592286d6298"
version = "0.6.1"

[[CustomUnitRanges]]
git-tree-sha1 = "1a3f97f907e6dd8983b744d2642651bb162a3f7a"
uuid = "dc8bdbbb-1ca9-579f-8c36-e416f6a65cce"
version = "1.0.2"

[[DataAPI]]
git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.9.0"

[[DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "7d9d316f04214f7efdbb6398d545446e246eff02"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.10"

[[Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[DelimitedFiles]]
deps = ["Mmap"]
uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"

[[Distances]]
deps = ["LinearAlgebra", "Statistics", "StatsAPI"]
git-tree-sha1 = "9f46deb4d4ee4494ffb5a40a27a2aced67bdd838"
uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7"
version = "0.10.4"

[[Distributed]]
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"

[[DocStringExtensions]]
deps = ["LibGit2"]
git-tree-sha1 = "a32185f5428d3986f47c2ab78b1f216d5e6cc96f"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.8.5"

[[Downloads]]
deps = ["ArgTools", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"

[[EllipsisNotation]]
deps = ["ArrayInterface"]
git-tree-sha1 = "8041575f021cba5a099a456b4163c9a08b566a02"
uuid = "da5c29d0-fa7d-589e-88eb-ea29b0a81949"
version = "1.1.0"

[[FFTViews]]
deps = ["CustomUnitRanges", "FFTW"]
git-tree-sha1 = "70a0cfd9b1c86b0209e38fbfe6d8231fd606eeaf"
uuid = "4f61f5a4-77b1-5117-aa51-3ab5ef4ef0cd"
version = "0.3.1"

[[FFTW]]
deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"]
git-tree-sha1 = "463cb335fa22c4ebacfd1faba5fde14edb80d96c"
uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
version = "1.4.5"

[[FFTW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c6033cc3892d0ef5bb9cd29b7f2f0331ea5184ea"
uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a"
version = "3.3.10+0"

[[FileIO]]
deps = ["Pkg", "Requires", "UUIDs"]
git-tree-sha1 = "3c041d2ac0a52a12a27af2782b34900d9c3ee68c"
uuid = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
version = "1.11.1"

[[FixedPointNumbers]]
deps = ["Statistics"]
git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
version = "0.8.4"

[[Graphics]]
deps = ["Colors", "LinearAlgebra", "NaNMath"]
git-tree-sha1 = "1c5a84319923bea76fa145d49e93aa4394c73fc2"
uuid = "a2bd30eb-e257-5431-a919-1863eab51364"
version = "1.1.1"

[[IdentityRanges]]
deps = ["OffsetArrays"]
git-tree-sha1 = "be8fcd695c4da16a1d6d0cd213cb88090a150e3b"
uuid = "bbac6d45-d8f3-5730-bfe4-7a449cd117ca"
version = "0.3.1"

[[IfElse]]
git-tree-sha1 = "28e837ff3e7a6c3cdb252ce49fb412c8eb3caeef"
uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
version = "0.1.0"

[[ImageAxes]]
deps = ["AxisArrays", "ImageCore", "Reexport", "SimpleTraits"]
git-tree-sha1 = "794ad1d922c432082bc1aaa9fa8ffbd1fe74e621"
uuid = "2803e5a7-5153-5ecf-9a86-9b4c37f5f5ac"
version = "0.6.9"

[[ImageContrastAdjustment]]
deps = ["ColorVectorSpace", "ImageCore", "ImageTransformations", "Parameters"]
git-tree-sha1 = "2e6084db6cccab11fe0bc3e4130bd3d117092ed9"
uuid = "f332f351-ec65-5f6a-b3d1-319c6670881a"
version = "0.3.7"

[[ImageCore]]
deps = ["AbstractFFTs", "Colors", "FixedPointNumbers", "Graphics", "MappedArrays", "MosaicViews", "OffsetArrays", "PaddedViews", "Reexport"]
git-tree-sha1 = "db645f20b59f060d8cfae696bc9538d13fd86416"
uuid = "a09fc81d-aa75-5fe9-8630-4744c3626534"
version = "0.8.22"

[[ImageDistances]]
deps = ["ColorVectorSpace", "Distances", "ImageCore", "ImageMorphology", "LinearAlgebra", "Statistics"]
git-tree-sha1 = "6378c34a3c3a216235210d19b9f495ecfff2f85f"
uuid = "51556ac3-7006-55f5-8cb3-34580c88182d"
version = "0.2.13"

[[ImageFiltering]]
deps = ["CatIndices", "ColorVectorSpace", "ComputationalResources", "DataStructures", "FFTViews", "FFTW", "ImageCore", "LinearAlgebra", "OffsetArrays", "Requires", "SparseArrays", "StaticArrays", "Statistics", "TiledIteration"]
git-tree-sha1 = "bf96839133212d3eff4a1c3a80c57abc7cfbf0ce"
uuid = "6a3955dd-da59-5b1f-98d4-e7296123deb5"
version = "0.6.21"

[[ImageIO]]
deps = ["FileIO", "Netpbm", "OpenEXR", "PNGFiles", "TiffImages", "UUIDs"]
git-tree-sha1 = "13c826abd23931d909e4c5538643d9691f62a617"
uuid = "82e4d734-157c-48bb-816b-45c225c6df19"
version = "0.5.8"

[[ImageMagick]]
deps = ["FileIO", "ImageCore", "ImageMagick_jll", "InteractiveUtils", "Libdl", "Pkg", "Random"]
git-tree-sha1 = "5bc1cb62e0c5f1005868358db0692c994c3a13c6"
uuid = "6218d12a-5da1-5696-b52f-db25d2ecc6d1"
version = "1.2.1"

[[ImageMagick_jll]]
deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pkg", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "ea2b6fd947cdfc43c6b8c15cff982533ec1f72cd"
uuid = "c73af94c-d91f-53ed-93a7-00f77d67a9d7"
version = "6.9.12+0"

[[ImageMetadata]]
deps = ["AxisArrays", "ColorVectorSpace", "ImageAxes", "ImageCore", "IndirectArrays"]
git-tree-sha1 = "ae76038347dc4edcdb06b541595268fca65b6a42"
uuid = "bc367c6b-8a6b-528e-b4bd-a4b897500b49"
version = "0.9.5"

[[ImageMorphology]]
deps = ["ColorVectorSpace", "ImageCore", "LinearAlgebra", "TiledIteration"]
git-tree-sha1 = "68e7cbcd7dfaa3c2f74b0a8ab3066f5de8f2b71d"
uuid = "787d08f9-d448-5407-9aad-5290dd7ab264"
version = "0.2.11"

[[ImageQualityIndexes]]
deps = ["ColorVectorSpace", "ImageCore", "ImageDistances", "ImageFiltering", "OffsetArrays", "Statistics"]
git-tree-sha1 = "1198f85fa2481a3bb94bf937495ba1916f12b533"
uuid = "2996bd0c-7a13-11e9-2da2-2f5ce47296a9"
version = "0.2.2"

[[ImageShow]]
deps = ["Base64", "FileIO", "ImageCore", "OffsetArrays", "Requires", "StackViews"]
git-tree-sha1 = "832abfd709fa436a562db47fd8e81377f72b01f9"
uuid = "4e3cecfd-b093-5904-9786-8bbb286a6a31"
version = "0.3.1"

[[ImageTransformations]]
deps = ["AxisAlgorithms", "ColorVectorSpace", "CoordinateTransformations", "IdentityRanges", "ImageCore", "Interpolations", "OffsetArrays", "Rotations", "StaticArrays"]
git-tree-sha1 = "e4cc551e4295a5c96545bb3083058c24b78d4cf0"
uuid = "02fcd773-0e25-5acc-982a-7f6622650795"
version = "0.8.13"

[[Images]]
deps = ["AxisArrays", "Base64", "ColorVectorSpace", "FileIO", "Graphics", "ImageAxes", "ImageContrastAdjustment", "ImageCore", "ImageDistances", "ImageFiltering", "ImageIO", "ImageMagick", "ImageMetadata", "ImageMorphology", "ImageQualityIndexes", "ImageShow", "ImageTransformations", "IndirectArrays", "OffsetArrays", "Random", "Reexport", "SparseArrays", "StaticArrays", "Statistics", "StatsBase", "TiledIteration"]
git-tree-sha1 = "8b714d5e11c91a0d945717430ec20f9251af4bd2"
uuid = "916415d5-f1e6-5110-898d-aaa5f9f070e0"
version = "0.24.1"

[[Imath_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "87f7662e03a649cffa2e05bf19c303e168732d3e"
uuid = "905a6f67-0a94-5f89-b386-d35d92009cd1"
version = "3.1.2+0"

[[IndirectArrays]]
git-tree-sha1 = "c2a145a145dc03a7620af1444e0264ef907bd44f"
uuid = "9b13fd28-a010-5f03-acff-a1bbcff69959"
version = "0.5.1"

[[Inflate]]
git-tree-sha1 = "f5fc07d4e706b84f72d54eedcc1c13d92fb0871c"
uuid = "d25df0c9-e2be-5dd7-82c8-3ad0b3e990b9"
version = "0.1.2"

[[IntelOpenMP_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d979e54b71da82f3a65b62553da4fc3d18c9004c"
uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0"
version = "2018.0.3+2"

[[InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[Interpolations]]
deps = ["AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"]
git-tree-sha1 = "61aa005707ea2cebf47c8d780da8dc9bc4e0c512"
uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
version = "0.13.4"

[[IntervalSets]]
deps = ["Dates", "EllipsisNotation", "Statistics"]
git-tree-sha1 = "3cc368af3f110a767ac786560045dceddfc16758"
uuid = "8197267c-284f-5f27-9208-e0e47529a953"
version = "0.5.3"

[[IrrationalConstants]]
git-tree-sha1 = "f76424439413893a832026ca355fe273e93bce94"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
version = "0.1.0"

[[IterTools]]
git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.3.0"

[[JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.3.0"

[[JpegTurbo_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943"
uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
version = "2.1.0+0"

[[LazyArtifacts]]
deps = ["Artifacts", "Pkg"]
uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3"

[[LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"

[[LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"

[[LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"

[[LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"

[[Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[Libtiff_jll]]
deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9"
uuid = "89763e89-9b03-5906-acba-b20f662cd828"
version = "4.3.0+0"

[[LinearAlgebra]]
deps = ["Libdl"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

[[LogExpFunctions]]
deps = ["ChainRulesCore", "DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "34dc30f868e368f8a17b728a1238f3fcda43931a"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.3"

[[Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"

[[MKL_jll]]
deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"]
git-tree-sha1 = "5455aef09b40e5020e1520f551fa3135040d4ed0"
uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7"
version = "2021.1.1+2"

[[MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "5a5bc6bf062f0f95e62d0fe0a2d99699fed82dd9"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.8"

[[MappedArrays]]
git-tree-sha1 = "e8b359ef06ec72e8c030463fe02efe5527ee5142"
uuid = "dbb5928d-eab1-5f90-85c2-b9b0edb7c900"
version = "0.4.1"

[[Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"

[[Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.0.2"

[[Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[MosaicViews]]
deps = ["MappedArrays", "OffsetArrays", "PaddedViews", "StackViews"]
git-tree-sha1 = "b34e3bc3ca7c94914418637cb10cc4d1d80d877d"
uuid = "e94cdb99-869f-56ef-bcf0-1ae2bcbe0389"
version = "0.3.3"

[[MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"

[[NaNMath]]
git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb"
uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
version = "0.3.5"

[[Netpbm]]
deps = ["ColorVectorSpace", "FileIO", "ImageCore"]
git-tree-sha1 = "09589171688f0039f13ebe0fdcc7288f50228b52"
uuid = "f09324ee-3d7c-5217-9330-fc30815ba969"
version = "1.0.1"

[[NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"

[[OffsetArrays]]
deps = ["Adapt"]
git-tree-sha1 = "c0e9e582987d36d5a61e650e6e543b9e44d9914b"
uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
version = "1.10.7"

[[OpenEXR]]
deps = ["Colors", "FileIO", "OpenEXR_jll"]
git-tree-sha1 = "327f53360fdb54df7ecd01e96ef1983536d1e633"
uuid = "52e1d378-f018-4a11-a4be-720524705ac7"
version = "0.3.2"

[[OpenEXR_jll]]
deps = ["Artifacts", "Imath_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "923319661e9a22712f24596ce81c54fc0366f304"
uuid = "18a262bb-aa17-5467-a713-aee519bc75cb"
version = "3.1.1+0"

[[OpenLibm_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "05823500-19ac-5b8b-9628-191a04bc5112"

[[OpenSpecFun_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1"
uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.5+0"

[[OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

[[PNGFiles]]
deps = ["Base64", "CEnum", "ImageCore", "IndirectArrays", "OffsetArrays", "libpng_jll"]
git-tree-sha1 = "e14c485f6beee0c7a8dcf6128bf70b85f1fe201e"
uuid = "f57f5aa1-a3ce-4bc8-8ab9-96f992907883"
version = "0.3.9"

[[PaddedViews]]
deps = ["OffsetArrays"]
git-tree-sha1 = "646eed6f6a5d8df6708f15ea7e02a7a2c4fe4800"
uuid = "5432bcbf-9aad-5242-b902-cca2824c8663"
version = "0.5.10"

[[Parameters]]
deps = ["OrderedCollections", "UnPack"]
git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe"
uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
version = "0.12.3"

[[Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[[PkgVersion]]
deps = ["Pkg"]
git-tree-sha1 = "a7a7e1a88853564e551e4eba8650f8c38df79b37"
uuid = "eebad327-c553-4316-9ea0-9fa01ccd7688"
version = "0.1.1"

[[Preferences]]
deps = ["TOML"]
git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.2"

[[Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[[ProgressMeter]]
deps = ["Distributed", "Printf"]
git-tree-sha1 = "afadeba63d90ff223a6a48d2009434ecee2ec9e8"
uuid = "92933f4c-e287-5a05-a399-4b506db050ca"
version = "1.7.1"

[[REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[Random]]
deps = ["Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[RangeArrays]]
git-tree-sha1 = "b9039e93773ddcfc828f12aadf7115b4b4d225f5"
uuid = "b3c3ace0-ae52-54e7-9d0b-2c1406fd6b9d"
version = "0.3.2"

[[Ratios]]
deps = ["Requires"]
git-tree-sha1 = "01d341f502250e81f6fec0afe662aa861392a3aa"
uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439"
version = "0.4.2"

[[Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"

[[Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.1.3"

[[Rotations]]
deps = ["LinearAlgebra", "StaticArrays", "Statistics"]
git-tree-sha1 = "2ed8d8a16d703f900168822d83699b8c3c1a5cd8"
uuid = "6038ab10-8711-5258-84ad-4b1120ba62dc"
version = "1.0.2"

[[SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"

[[Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[SharedArrays]]
deps = ["Distributed", "Mmap", "Random", "Serialization"]
uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383"

[[SimpleTraits]]
deps = ["InteractiveUtils", "MacroTools"]
git-tree-sha1 = "5d7e3f4e11935503d3ecaf7186eac40602e7d231"
uuid = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
version = "0.9.4"

[[Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

[[SortingAlgorithms]]
deps = ["DataStructures"]
git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508"
uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
version = "1.0.1"

[[SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[[SpecialFunctions]]
deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"]
git-tree-sha1 = "793793f1df98e3d7d554b65a107e9c9a6399a6ed"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "1.7.0"

[[StackViews]]
deps = ["OffsetArrays"]
git-tree-sha1 = "46e589465204cd0c08b4bd97385e4fa79a0c770c"
uuid = "cae243ae-269e-4f55-b966-ac2d0dc13c15"
version = "0.1.1"

[[Static]]
deps = ["IfElse"]
git-tree-sha1 = "a8f30abc7c64a39d389680b74e749cf33f872a70"
uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
version = "0.3.3"

[[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "3240808c6d463ac46f1c1cd7638375cd22abbccb"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.12"

[[Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[[StatsAPI]]
git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.0.0"

[[StatsBase]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "8cbbc098554648c84f79a463c9ff0fd277144b6c"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.33.10"

[[TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"

[[Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"

[[TensorCore]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6"
uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50"
version = "0.1.1"

[[Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[TiffImages]]
deps = ["ColorTypes", "DocStringExtensions", "FileIO", "FixedPointNumbers", "IndirectArrays", "Inflate", "OffsetArrays", "OrderedCollections", "PkgVersion", "ProgressMeter"]
git-tree-sha1 = "632a8d4dbbad6627a4d2d21b1c6ebcaeebb1e1ed"
uuid = "731e570b-9d59-4bfa-96dc-6df516fadf69"
version = "0.4.2"

[[TiledIteration]]
deps = ["OffsetArrays"]
git-tree-sha1 = "5683455224ba92ef59db72d10690690f4a8dc297"
uuid = "06e1c1a7-607b-532d-9fad-de7d9aa2abac"
version = "0.3.1"

[[UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[[UnPack]]
git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
version = "1.0.2"

[[Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[WoodburyMatrices]]
deps = ["LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "59e2ad8fd1591ea019a5259bd012d7aee15f995c"
uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6"
version = "0.5.3"

[[Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

[[Zstd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.0+0"

[[libpng_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c"
uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f"
version = "1.6.38+0"

[[nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"

[[p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"
"""

# ╔═╡ Cell order:
# ╠═c9638116-dbb8-403e-8d91-fca7da74c537
# ╟─604d28a6-22c3-11ec-2d40-39598d3636ed
# ╟─9f638f37-9ab4-4ca7-9156-3e80441702b2
# ╠═06e3821f-ac6f-4be2-95e2-65a6e11ba82e
# ╟─df6364ad-162a-4f98-bc10-04be07f0aa8a
# ╠═9924f0a1-642c-4632-8855-5f340805748e
# ╠═2ae72e48-30ee-44ee-93ee-801df4060be2
# ╠═ac2a9681-90cb-450f-aa75-4efcfe02a71d
# ╠═706130bf-064e-40da-b80a-30d7ec59da78
# ╠═c95d159e-e957-45e5-9697-e5d4e912ca02
# ╠═be87bd3a-15d7-43c1-8504-dad5daec23cb
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002

max_stars_repo_name: NanoSparten/thesis

max_issues_repo_name: NanoSparten/thesis

max_forks_repo_name: NanoSparten/thesis