text:
"""
    indexjoin(df::DataFrame...; kwargs)
    indexjoin(df::Array{DataFrame,1}; kwargs)

This function joins input DataFrames on their index columns (ones that are not filled with
`AbstractFloat` or `Bool` DataTypes)

# Argument
- `df::DataFrame...` to join.
"""
function indexjoin(df::Array{DataFrame,1};
    id::Array = [],
    indicator::Bool = false,
    fillmissing = 0.0,
    skipindex = [],
    kind = :outer,
)
    df = copy.(df[.!isempty.(df)])
    N = length(df)

    # all(length.(findvalue.(df)) .== 0) && (indicator = true)

    (df,id) = _make_unique(df, id, indicator; skipindex = skipindex)
    (df,id) = _add_indicator(df, id, indicator)
    idx = findindex.(df)

    df_ans = copy(df[1])
    for ii in 2:N
        cols = intersect(propertynames(df_ans), idx[ii])
        df_ans = if length(cols) == 0
            crossjoin(df_ans, df[ii])
        else
            if kind == :outer;     outerjoin(df_ans, df[ii], on=cols)
            elseif kind == :inner; innerjoin(df_ans, df[ii], on=cols)
            elseif kind == :left;  leftjoin(df_ans, df[ii],  on=cols)
            elseif kind == :right; rightjoin(df_ans, df[ii], on=cols)
            end
        end
    end

    df_ans = _fill_missing(df_ans, fillmissing)
    col = [findindex(df_ans); find_oftype(df_ans, AbstractFloat); find_oftype(df_ans, Bool)]
    return select(df_ans, col)
end

function indexjoin(df::Vararg{DataFrame};
    id::Array = [],
    indicator::Bool = false,
    fillmissing = 0.0,
    skipindex = [],
    kind = :outer
)
    return indexjoin(ensurearray(df);
        id = id,
        indicator = indicator,
        fillmissing = fillmissing,
        skipindex = skipindex,
        kind = kind)
end

"""
"""
function convertjoin(df::Array{DataFrame,1}; id=[])
    return indexjoin(df; id=id, indicator=false, fillmissing=1.0, skipindex=:units, kind=:left)
end

convertjoin(df::Vararg{DataFrame}; id=[]) = convertjoin(ensurearray(df); id=id)

"""
This function appends duplicate input value columns with the associated `id` to
track which column was associated with which input DataFrame.

Notes:
1. If each input DataFrame has only one value column and an indicator is NOT required,
    rename this to match the id.
2. If any of the input DataFrames contains the column `units`, `id` this, as well.
    This means that no joins are performed on unit columns to allow for operations that may
    convert between units.
"""
function _make_unique(df::Array{DataFrame,1}, id::AbstractArray, indicator::Bool; skipindex=[])
    N = length(df)

    col = propertynames.(df)
    val = findvalue.(df)
    flt = find_oftype.(df, AbstractFloat)

    # If there are no values, don't make any changes.
    all(length.(val) .== 0) && (return df, id)

    isempty(id) && (id = _generate_id(N))

    # If all value names are already unique, don't edit these.
    # !!!! What if they're already unique but there's an indicator?
    if length(unique([val...;])) == length([val...;])
        from = fill([], (N,))
        to = fill([], (N,))
    else
        from = val
        # If there is only one value column / input dataframe, we are NOT including an
        # indicator, and ids are defined, rename that one value column to match the given id.
        to = if (all(length.(val) .== 1) && !indicator)
            ensurearray.(id)
        else
            broadcast.(append, val, id)
        end
    end

    # Remove indicies to be skipped.
    for ii in 1:N
        for idx in intersect(ensurearray(skipindex), col[ii])
            from[ii] = push!(copy(from[ii]), idx)
            to[ii] = push!(copy(to[ii]), append(idx, id[ii]))
        end
    end

    if any(.!isempty.(from))
        df = [!isempty(from[ii]) ? edit_with(df[ii], Rename.(from[ii], to[ii])) : df[ii]
            for ii in 1:N]
    end
    return df, id
end

"""
If `indicator = true` is specified, add boolean `id` columns to the output DataFrame
indicating which input DataFrame was the source.
"""
function _add_indicator(df::Array{DataFrame,1}, id::Array, indicator::Bool)
    if indicator
        isempty(id) && (id = _generate_id(df))
        df = [edit_with(df[ii], Add(id[ii], true)) for ii in 1:length(df)]
    end
    return (df,id)
end

"""
"""
function _fill_missing(df::DataFrame, fillmissing)
    # Do we even want to fill missing values?
    fillmissing === false && (return df)
    fillmissing === true  && (fillmissing = 0.0)

    # Are there missing values to fill?
    dfmiss = df[:,any.(eachcol(ismissing.(df)))]
    isempty(dfmiss) && (return df)

    # Replace values.
    bool = find_oftype(dfmiss, Bool)
    num = find_oftype(dfmiss, AbstractFloat)

    # Fill missing strings.
    str = findindex(dfmiss)
    str_unique = unique.(skipmissing.(eachcol(df[:,str])));
    ii = length.(str_unique).==1

    !isempty(bool) && (df = edit_with(df, Replace.(bool, missing, false)))
    !isempty(num)  && (df = edit_with(df, Replace.(num, missing, fillmissing)))
    any(ii)        && (df = edit_with(df, Replace.(str[ii], missing, [str_unique[ii]...;])))
    return df
end

_fill_missing(df::DataFrame) = _fill_missing(df, 0.0)

max_stars_repo_name: NREL/SLiDE

max_issues_repo_name: NREL/SLiDE

max_forks_repo_name: NREL/SLiDE


text:
import Base: +, .+, -, .-, .*, *

function +{T,N}(x1::CuArray{T,N}, x2::CuArray{T,N})
    @assert length(x1) == length(x2)
    x1 .+ x2
end
.+(x1::CuArray, x2::CuArray) = mathop(:add, x1, x2)

function -{T,N}(x1::CuArray{T,N}, x2::CuArray{T,N})
    @assert length(x1) == length(x2)
    x1 .- x2
end
.-(x1::CuArray, x2::CuArray) = mathop(:sub, x1, x2)

function .*{T,N}(x1::CuArray{T,N}, x2::CuArray{T,N})
    @assert length(x1) == length(x2)
    mathop(:mul, x1, x2)
end

*(x1::CuMatrix, x2::CuMatrix) = BLAS.gemm('N', 'N', x1, x2)

Base.exp(x::CuArray) = mathop(:exp, x)
Base.log(x::CuArray) = mathop(:log, x)

function mathop{T}(op::Symbol, x1::CuArray{T}, x2::CuArray{T})
    s = Symbol(op, :_, cstring(T))
    f = functions[s]
    x = length(x1) >= length(x2) ? x1 : x2
    y = similar(x)
    launch(f, (length(y),), (CUvector(x1),CUvector(x2),CUvector(y)))
    y
end

function mathop{T}(op::Symbol, x::CuArray{T})
    s = Symbol(op, :_, cstring(T))
    f = functions[s]
    y = similar(x)
    launch(f, (length(y),), (CUvector(x),CUvector(y)))
    y
end

ext: jl


text:
import Base:convert
import SparseArrays: AbstractSparseMatrixCSC, SparseMatrixCSC

"""
Convert Julia array to KVXOPT matrix or spmatrix
"""
function julia_to_kvxopt(A)
    if issparse(A)
        J = zeros(Int64, length(A.rowval));
        for i = 1:size(A, 2)
            J[A.colptr[i]:A.colptr[i + 1] - 1] .= i - 1;
        end
        I = A.rowval .- 1
        V = A.nzval
        Ap = @pycall  kvxopt.spmatrix(PyCall.array2py(vec(V)), PyCall.array2py(vec(I)), PyCall.array2py(vec(J)), (size(A, 1), size(A, 2)))::PyObject;
    elseif isempty(A)
    Ap = pybuiltin("None");
  else
    sA = size(A)
    if length(sA) == 1
      sA = (sA[1], 1)
    end
    Ap = @pycall kvxopt.matrix(PyCall.array2py(vec(A)), sA)::PyObject;
    end
    return Ap;
end

"""
Convert KVXOPT spmatrix to SparseMatrixCSC
"""
function convert(::Type{T}, A::PyObject) where T <: AbstractSparseMatrixCSC
    if A.typecode == "d"
        r = SparseMatrixCSC(A.size[1], A.size[2],
                            vec(A.CCS[1])::Vector{Int64} .+ 1,
                            vec(A.CCS[2])::Vector{Int64} .+ 1,
                            vec(A.CCS[3])::Vector{Float64})::SparseMatrixCSC{Float64,Int64}
    elseif A.typecode == "z"
        r = SparseMatrixCSC(A.size[1], A.size[2],
                            vec(A.CCS[1])::Vector{Int64} .+ 1,
                            vec(A.CCS[2])::Vector{Int64} .+ 1,
                            vec(A.CCS[3])::Vector{ComplexF64})::SparseMatrixCSC{ComplexF64,Int64}
    end
    return r
end


text:
# ------------------------------------
# set initial conditions
# ------------------------------------
function set_initQbase(Qbase, cellxmax, cellymax, restart_file, init_rho, init_u, init_v, init_p, init_T,
                    specific_heat_ratio, out_file_front, out_ext, out_dir, restartnum, Rd, nval)

    restart_check = 0
    try Qbase = setup_restart_value(Qbase, cellxmax, cellymax, out_dir, restart_file, nval)
        println("Restart "*restart_file)
        restart_check = 2
    catch
        restart_check = 1
    end

    if restart_check == 1
        Qbase = setup_init_value(Qbase, cellxmax, cellymax, init_rho, init_u, init_v, init_p)
        println("Start Initial condition")
        restartnum = 0
        output_result(0, Qbase, cellxmax, cellymax, specific_heat_ratio, out_file_front, out_ext, out_dir, Rd, nval)
    end

    return Qbase, restartnum
end

function setup_init_value(Qbase, cellxmax, cellymax, init_rho, init_u, init_v, init_p)
    for j in 1:cellymax
        for i in 1:cellxmax
            Qbase[i,j,1] = init_rho
            Qbase[i,j,2] = init_u
            Qbase[i,j,3] = init_v
            Qbase[i,j,4] = init_p
        end
    end
    return Qbase
end

function setup_restart_value(Qbase, cellxmax, cellymax, out_dir, restart_file, nval)
    skipnum = 1
    fff = []
    open("result/"*restart_file, "r") do f
        fff = read(f, String)
    end
    fff = split(fff,"\n", keepempty = false)

    for i in 1+skipnum:length(fff)
        fff[i] = replace(fff[i]," \r" => "")
    end

    k = 1
    for i in 2:cellxmax-1
        for j in 2:cellymax-1
            temp = split(fff[k+skipnum]," ")
            for l in 1:nval
                Qbase[i,j,l] = parse(Float64,temp[l])
            end
            k = k+1
        end
    end
    return Qbase
end

# ------------------------------------
# find out if results were diverge
# ------------------------------------
function check_divrege(Qbase, cellxmax, cellymax, Rd, fwrite)
    ite = 0
    for j in 2:cellymax-1
        for i in 2:cellxmax-1
            T = Qbase[i,j,4]/(Qbase[i,j,1]*Rd)
            if T < 0 || isequal(T, NaN) == true
                open( fwrite, "a" ) do f
                    ai  = @sprintf("%4.0f", i)
                    aj  = @sprintf("%4.0f", j)
                    rho = @sprintf("%4.0e", Qbase[i,j,1])
                    p   = @sprintf("%4.0e", Qbase[i,j,4])

                    write(f, "\n")
                    write(f, " diverge ")
                    write(f, "\n")
                    write(f, " i = "*ai)
                    write(f, "\n")
                    write(f, " j = "*aj)
                    write(f, "\n")
                    write(f, " rho = "*rho)
                    write(f, "\n")
                    write(f, " p = "*p)
                    write(f, "\n")

                end
                ite = 1
            end
        end
    end

    if ite == 1
        println("\n")
        println("\n")
        println(" T<0 ")
        println(" diverge ")
        println("\n")
        throw(UndefVarError(:x))
    end
end

# ------------------------------------
# quicksort
# ------------------------------------
function quicksort(list, first, last, num_cell_data, standard_num)
    # list = zezros(m,n)
    x = list[Int(floor((first+last)/2)),standard_num]
    i = first
    j = last

    while true
        while list[i,standard_num] < x
            i = i+1
        end
        while x < list[j,standard_num]
            j = j-1
        end

        if (i >= j)
            break
        else
            for k in 1:num_cell_data
                t = list[i,k]
                list[i,k] = list[j,k]
                list[j,k] = t
            end
            i = i+1
            j = j-1
        end
    end

    if (first < i - 1)
        list = quicksort(list, first, i - 1,num_cell_data,standard_num)
    end
    if (j + 1 < last)
        list = quicksort(list, j + 1, last,num_cell_data,standard_num)
    end
    return list
end


text:
"""
   Traits for the HARPS-N spectrograph.
    https://plone.unige.ch/HARPS-N/
Author: Alex Wise and collaborators
Created: April 2021
"""

""" Delegates loading of code specifying types essential to the package.  """

import RvSpectMLBase: min_order, max_order, min_pixel_in_order, max_pixel_in_order, min_pixel, max_pixel

min_order(::HARPSN2D) = 1
max_order(::HARPSN2D) = 69

min_pixel_in_order(inst::HARPSN2D) = 1
max_pixel_in_order(inst::HARPSN2D) = 4096

min_pixel(::HARPSN1D) = 1
max_pixel(::HARPSN1D) = 300000 # TODO: Update once know size of HARPS-N's 1d extracted spectra

import RvSpectMLBase: bad_col_ranges

function bad_col_ranges(inst::HARPSN2D, ord::Int)
    [0:0] #placeholder function to be updated if/when we decide certain pixels should be excluded from analysis
end

import RvSpectMLBase: orders_to_use_default, min_col_default, max_col_default

orders_to_use_default(::HARPSN2D) = 1:69

min_col_default(::HARPSN2D, ord::Integer) = 300  # Avoid where continuum normalization effected by edges/scattered light
max_col_default(::HARPSN2D, ord::Integer) = 3800  # Avoid where continuum normalization effected by edges/scattered light

import RvSpectMLBase: get_pixel_range
function get_pixel_range(inst::HARPSN2D, ord::Integer)
    minc = max(min_col_default(inst, ord))
    maxc = min(max_col_default(inst, ord))
    return minc:maxc
end

import RvSpectMLBase: metadata_symbols_default, metadata_strings_default
# HARPS-N headers
metadata_symbols_default(::AnyHARPSN) = Symbol[:bjd, :exptime, :airmass]
metadata_strings_default(::AnyHARPSN) = String["MJD-OBS", "EXPTIME", "AIRMASS"]

import RvSpectMLBase: default_ccf_mask_v_width
default_ccf_mask_v_width(::AnyHARPSN) = 820.0 #approx one HARPS-N pixel

import RvSpectMLBase: get_inst_module
get_inst_module(::AnyHARPSN) = HARPSN

#not sure what this does right now
import RvSpectMLBase: get_λ_range
function get_λ_range(data::CLT) where { T1<:Real, T2<:Real, T3<:Real, A1<:AbstractArray{T1,2}, A2<:AbstractArray{T2,2}, A3<:AbstractArray{T3,2},
                                       IT<:AnyHARPSN, CLT<:Spectra2DBasic{T1,T2,T3,A1,A2,A3,IT} }
   (λmin, λmax) = NaNMath.extrema(data.λ)
   return (min=λmin, max=λmax)
end

default_λmin = 3800.0
default_λmax = 6900.0

max_stars_repo_name: RvSpectML/EchelleInstruments

max_issues_repo_name: RvSpectML/EchelleInstruments

max_forks_repo_name: RvSpectML/EchelleInstruments


text:
# using LazySets

□(x0, ε) = BallInf(x0, ε)

# general version for affine dynamics
function check_necessary(dyn1, dyn2, x0::AbstractVector{N}, P0::LazySet,
                         ε::Number, T::Number, m::Integer;
                         return_sets::Bool=false, log::Bool=false) where {N}
    if log
        println("running necessary check with $m iterations")
    end

    δ = T / m
    if return_sets
        Bs = Vector{LazySet{N}}()
        Ps = Vector{LazySet{N}}()
        push!(Bs, P0)
        push!(Ps, P0)
        P_last = P0
    end
    j_abort = m
    for j in 1:m
        # if log
        #     println("iteration $j")
        # end
        B = □(successor(dyn1, j * δ, x0), ε)
        P1 = successor(dyn2, δ, P0)
        P0 = intersection(P1, B)
        if return_sets
            push!(Bs, B)
            push!(Ps, P0)
        end
        if P0 isa EmptySet
            j_abort = j
            if return_sets
                P_last = P1
            end
            break
        end
    end
    if log
        println("finished necessary check after $j_abort iterations")
    end
    if return_sets
        return j_abort, P_last, Bs, Ps
    else
        return P0
    end
end

# more efficient version for linear dynamics
function check_necessary(A::AbstractMatrix{N}, B::AbstractMatrix{N},
                         x0::AbstractVector{N}, P0::LazySet, ε::Number,
                         T::Number, m::Integer;
                         return_sets::Bool=false, log::Bool=false) where {N}
    if log
        println("running necessary check with $m iterations")
    end

    δ = T / m
    Φ = exp(A * δ)
    Ψ = exp(B * δ)
    if return_sets
        Bs = Vector{LazySet{N}}()
        Ps = Vector{LazySet{N}}()
        push!(Bs, P0)
        push!(Ps, P0)
        P_last = P0
    end
    j_abort = m
    for j in 1:m
        # if log
        #     println("iteration $j")
        # end
        B = □(Φ^j * x0, ε)
        P1 = linear_map(Ψ, P0)
        P0 = intersection(P1, B)
        if return_sets
            push!(Bs, B)
            push!(Ps, P0)
        end
        if P0 isa EmptySet
            j_abort = j
            if return_sets
                P_last = P1
            end
            break
        end
    end
    if log
        println("finished necessary check after $j_abort iterations")
    end
    if return_sets
        return j_abort, P_last, Bs, Ps
    else
        return P0
    end
end

max_stars_repo_name: HySynth/HySynth

max_issues_repo_name: HySynth/HySynth

max_forks_repo_name: HySynth/HySynth


text:
アザラシでもできるJuliaでの x₁ のタイプ方法
（OS Windows, Editor Atom, Package: uber-juno)

x   xを入力できゅ．
x\  \を入力できゅ．
x\_ _を入力できゅ．
x\_1 ここでTabを押すできゅ．
x₁ でけたでキュ．

Enjoy Julia!

max_stars_repo_name: terasakisatoshi/juliaExer

max_issues_repo_name: terasakisatoshi/juliaExer

max_forks_repo_name: terasakisatoshi/juliaExer


text:
# Control whether timings are enabled or not, by default no
if parse(Bool, get(ENV, "DFTK_TIMING", "0"))
    timer_enabled() = true
else
    timer_enabled() = false
end

"""TimerOutput object used to store DFTK timings."""
const timer = TimerOutput()

"""
Shortened version of the `@timeit` macro from `TimerOutputs`,
which writes to the DFTK timer.
"""
macro timing(args...)
    if DFTK.timer_enabled()
        TimerOutputs.timer_expr(__module__, false, :($(DFTK.timer)), args...)
    else  # Disable taking timings
        :($(esc(last(args))))
    end
end

"""
Similar to `@timing`, but disabled in parallel runs.
Should be used to time threaded regions,
since TimerOutputs is not thread-safe and breaks otherwise.
"""
macro timing_seq(args...)
    if Threads.nthreads() == 1 && DFTK.timer_enabled()
        TimerOutputs.timer_expr(__module__, false, :($(DFTK.timer)), args...)
    else  # Disable taking timings
        :($(esc(last(args))))
    end
end


text:
"""
Internal function.

Checks `table_type` argument for validity, and throws error if not in
list of valid values.
"""
check_table_type(table_type) = begin
    table_type in [:ascii, :latex] && return

    msg = """
    $table_type is invalid argument for table_type.  See
    documentation for `TablePrinter`:

    table_type::Symbol (default :ascii)
        Controls which type of table is printed.  Currently has
        two options:
        1.  :ascii -- Prints an ASCII table to be displayed in
            the REPL
        2.  :latex -- Prints a LaTeX table for output
    """
    throw(ArgumentError(msg))
end

default_sep(table_type) = begin
    check_table_type(table_type)
    table_type == :ascii && return "|"
    table_type == :latex && return "&"
end

@with_kw mutable struct TableParams
    pad::Int            = 1
    table_type::Symbol  = :ascii
    se_pos::Symbol      = :below
    star::Bool          = true
    sep::String         = default_sep(table_type)
    align::String       = "c"
    TableParams(pad, table_type, se_pos, star, sep, align) = begin
        # Argument Checking
        return new(pad, table_type, se_pos, star, sep, align)
    end
end

mutable struct TablePrinter{N,M}
    table::IndexedTable{N,M}
    params::TableParams
    col_schema
    row_schema
end

"""
```
TablePrinter(table::IndexedTable{N,M}; kwargs...) where {N,M}
```
Maps out the column and row schemas, and constructs a `TablePrinter`
object for the given table.  Additional option parameters can be passed
as keyword arguments

Parameters
----------
pad::Int (default 1)
    The number of spaces to pad the separator characters on each side.
table_type::Symbol (default :ascii)
    Controls which type of table is printed.  Currently has two options:
    1.  :ascii -- Prints an ASCII table to be displayed in the REPL
    2.  :latex -- Prints a LaTeX table for output
"""
function TablePrinter(t::TexTable; kwargs...)
    table      = convert(IndexedTable, t)
    col_schema = generate_schema(table.col_index)
    row_schema = generate_schema(table.row_index)
    params     = TableParams(;kwargs...)

    return TablePrinter(table, params, col_schema, row_schema)
end

########################################################################
#################### Index Schemas #####################################
########################################################################

"""
```
new_group(idx1::TableIndex, idx2::TableIndex, level::Int)
```
Internal method. Compares two elements from an index (of type
`Index{N}`) and checks whether or not `idx2` is in a different group
than `idx1` at index-depth `level`.  An index starts a new group if
either its numeric position has changed, or the string value has
changed.

Calls itself recursively on each level above the given level to see
whether or not we have a new group at any of the higher levels.
"""
function new_group(idx1::TableIndex{N}, idx2::TableIndex{N},
                   level::Int) where N

    # Terminal case
    level == 0 && return false

    # In other levels, recurse backwards through the levels -- short
    # circuiting if we find any level where we're switching to a new
    # group
    return new_group(idx1, idx2, level-1) || begin
        same_num    = idx1.idx[level]  == idx2.idx[level]
        same_name   = idx1.name[level] == idx2.name[level]
        return (!same_num) | (!same_name)
    end
end

"""
```
get_level(idx::$Idx, i)
```
Extracts the `i`th level of the index `idx` (both the integer and name
component) and returns it as a tuple.
"""
get_level(idx::TableIndex, i) = idx.idx[i], idx.name[i]

"""
```
generate_schema(index::$Index [, level::Int])
```
Returns a vector of `Pair{Tuple{Int, Symbol},Int}`, where for each
`pair`, `pair.first` is a tuple of the positional and symbolic
components of the index level, and `pair.second` is the number of times
that this entry is repeated within `level`.

When called without a level specified, returns an `OrderedDict` of
`level=>generate_schema(index, level)` for each level.

Example
-------
If we had a column `c1` that looked like
```
julia> show(c1)
              |  test
-----------------------
         key1 | 0.867
         key2 | -0.902
         key3 | -0.494
         key4 | -0.903
         key5 | 0.864
         key6 | 2.212
         key7 | 0.533
         key8 | -0.272
         key9 | 0.502
        key10 | -0.517
-----------------------
Fixed Effects | Yes
```
Then `generate_schema` would return:
```
julia> generate_schema(c2.row_index, 1)
2-element Array{Any,1}:
 (1, Symbol(""))=>8
 (2, Symbol(""))=>1

julia> generate_schema(c2.row_index, 2)
9-element Array{Any,1}:
 (1, :key2)=>1
 (2, :key3)=>1
 (3, :key4)=>1
 (4, :key5)=>1
 (5, :key6)=>1
 (6, :key7)=>1
 (7, :key8)=>1
 (8, :key9)=>1
 (1, Symbol("Fixed Effects"))=>1
```
"""
function generate_schema(index::Index{N}, level::Int) where N
    # Argument Checking
    1 <= level <= N || throw(BoundsError("$level is invalid level"))

    # Initialize the level schema
    level_schema    = []
    idx             = get_level(index[1], level)
    count           = 1

    # Loop through the index values
    n       = length(index)
    for i = 1:n-1
        # If the next index is new, push it to the list
        if new_group(index[i], index[i+1], level)
            push!(level_schema, idx=>count)
            idx     = get_level(index[i+1], level)
            count   = 1
        else
            count  += 1
        end
    end
    push!(level_schema, idx=>count)
    return level_schema
end

function generate_schema(index::Index{N}) where N
    return OrderedDict(i=>generate_schema(index, i) for i=1:N)
end

"""
```
get_lengths(t::TablePrinter, col_schema=generate_schema(t.table.col_index))
```
Internal function.

Returns a vector of column lengths to be used in printing the table.
Has the same length as `t.columns`.  `col_schema` will be generated by
default if not passed.  It must be the output of
`generate_schema(t.col_index)`.

If any header requires more printing space than the columns themselves
would require, allocates the additional space equally among all the
columns it spans.
"""
function get_lengths(printer::TablePrinter{N,M},
                     col_schema=generate_schema(
                        printer.table.col_index)) where {N,M}

    # Get the underlying table and some parameters
    t   = printer.table
    pad = printer.params.pad
    sep = printer.params.sep

    # Start out with the assumption that we just need enough space for
    # the column contents
    k       = length(t.columns)
    lengths = col_length.(Ref(printer), t.columns)

    # Initialize a Block-Width Schema
    bw_schema = Dict()

    # Repeat this code twice so that everything updates fully
    for u = 1:2

    # Loop through the levels of the column index from the bottom up
    for i=M:-1:1
        level_schema = printer.col_schema[i]
        col_pos = 0
        bw_schema[i] = []

        for (s, p) in enumerate(level_schema)
            pos, name   = p.first
            block_size  = p.second
            fname       = format_name(printer, i, block_size, name)

            # Figure out the block width, accounting for the extra
            # space from the separators and the padding
            block_width = sum(lengths[(1:block_size) .+ col_pos])
            block_width+= (block_size-1)*(2*pad + length(sep))

            # If the block is not big enough for the formatted name,
            # then add extra whitespace to each column (evenly) until
            # there's enough.
            difference = length(fname) - block_width
            if difference > 0
                extra_space = div(difference, block_size)
                remainder   = rem(difference, block_size)
                for j = (1:block_size) .+ col_pos
                    lengths[j] += extra_space
                    if j <= remainder & u == 1
                        lengths[j] += 1
                    end
                end
            end

            # Add the block width to the block width schema
            push!(bw_schema[i], max(block_width, length(fname)))

            # Update the column position
            col_pos += block_size
        end
    end
    end

    return lengths, bw_schema
end

########################################################################
#################### Printer Methods ###################################
########################################################################

"""
```
mc(cols, val="", align="c")
"""
function mc(cols, val="", align="c")
    return "\\multicolumn{$cols}{$align}{$val}"
end

function format_name(printer::TablePrinter{N,M}, level::Int,
                     block_size::Int, name)::String where {N,M}
    # ASCII tables just print the centered name
    printer.params.table_type == :ascii && return string(name)

    # LaTeX tables need to print the name in a multi-column environment
    # except at the lowest level
    if printer.params.table_type == :latex
        if level == M
            return "$name"
        else
            align = printer.params.align
            return mc(block_size, name, align)
        end
    end
end

function align_name(printer::TablePrinter, len, name)
    @unpack table_type = printer.params

    table_type == :ascii && return center(name, len)
    table_type == :latex && return format("{:$len}", name)
end

"""
Returns the maximum length of the column entries, not accounting for the
header columns
"""
function col_length(p::TablePrinter, col::TableCol)
    @unpack pad, se_pos, star = p.params
    l = 0
    for key in keys(col.data)
        val, se, stars = get_vals(col, key)
        sl  = star ? length(stars) : 0
        if se_pos == :below
            l = max(l, length(val) + sl, length(se))
        elseif se_pos == :inline
            l = max(l, length(val) + sl + pad + length(se))
        elseif se_pos == :none
            l = max(l, length(val) + sl)
        end
    end
    return l
end

function newline(p::TablePrinter)
    @unpack table_type = p.params
    table_type == :ascii && return ""
    table_type == :latex && return "\\\\"
end

endline(p::TablePrinter) = "\n"

# subline not properly implemented yet
subline(p::TablePrinter, args...) = ""

function hline(p::TablePrinter)
    @unpack table_type = p.params
    table_type == :ascii && return "\n"*"-"^width(p)
    table_type == :latex && return " \\hline"
end

function hline(p::TablePrinter{N,M}, i::Int) where {N,M}
    t       = p.table
    n, m    = size(t)

    # Figure out what kind of line ending we're on
    i <   0     && return ""
    i ==  0     && return hline(p)
    if 0 < i < n
        ridx1       = t.row_index[i]
        ridx2       = t.row_index[i+1]
        return new_group(ridx1, ridx2, N-1) ? hline(p) : ""
    elseif i == n
        return ""
    else
        msg = "There are only $n rows.  $i is not a valid index"
        throw(BoundsError(msg))
    end
end

function width(p::TablePrinter)
    @unpack pad, sep = p.params
    sep_len = length(sep)
    lengths = get_lengths(p)[1]
    rh_len  = rowheader_length(p)
    pad_ws  = " "^pad

    # Compute Total Width
    len     = 0
    len    += rh_len + pad
    len    += sum(lengths)
    len    += map(x->2*pad + sep_len, lengths) |> sum
end

function top_matter(printer::TablePrinter{N,M}) where {N,M}
    @unpack table_type = printer.params
    @unpack col_schema = printer
    t = printer.table

    table_type == :ascii && return ""
    table_type == :latex && return begin
        align = ""
        for i=1:N
            align *= empty_row(t, i) ? "" : "r"
        end

        for (i, pair) in enumerate(col_schema[max(M-1,1)])
            align *= (M > 1) | (i==1) ? "|" : ""
            align *= "c"^pair.second
        end

        return "\\begin{tabular}{$align}\n\\toprule\n"
    end
end

"""
Count the number of non-empty row-index dimensions
"""
function nonempty_rows(t::IndexedTable{N,M}) where {N,M}
    c = 0
    for i=1:N
        c += empty_row(t, i) ? 0 : 1
    end
    return c
end

"""
Check whether the row index in dimension `i` is empty
"""
function empty_row(t::IndexedTable{N,M}, i::Int) where {N,M}
    names = get_name(t.row_index, i)
    return all(isempty.(string.(names)))
end

"""
Check whether the col index in dimension `i` is empty
"""
function empty_col(t::IndexedTable{N,M}, i::Int) where {N,M}
    names = get_name(t.col_index, i)
    return all(isempty.(string.(names)))
end

########################################################################
#################### Header Printing ###################################
########################################################################

function head(printer::TablePrinter{N,M}) where {N,M}

    t       = printer.table
    pad     = printer.params.pad
    pad_ws  = " "^pad
    sep     = printer.params.sep
    sep_len = length(sep)

    # Get the column lengths, column schema, block width schema, and
    # rowheader length
    lengths, bw_schema  = get_lengths(printer)
    col_schema          = printer.col_schema
    rh_length           = rowheader_length(printer)

    # Handle any top matter
    output  = ""
    output *= top_matter(printer)

    for i=1:M
        # Skip this iteration in the loop if the column-level is empty
        empty_col(t, i) && continue

        # Add whitespace to account for the rowheader length, and add a
        # separator
        for j=1:N
            rhj     = rowheader_length(printer, j)
            empty_row(t, j) && continue
            output *= format("{:$rhj}", "")
            output *= j < N ? pad_ws * sep * pad_ws : pad_ws
        end

        # Write each header
        for (s, pair) in enumerate(col_schema[i])
            block_len   = bw_schema[i][s]
            block_size  = pair.second
            name        = pair.first[2]
            name        = format_name(printer, i, block_size, name)
            header      = align_name(printer, block_len, name)

            # Write the header to the output
            output     *= sep * pad_ws * header * pad_ws
        end

        output *= newline(printer)
        output *= hline(printer,   -M + i)
        output *= subline(printer, -M + i)
        output *= endline(printer)
    end

    return output
end

########################################################################
#################### Body Printing #####################################
########################################################################

"""
```
empty_se(t::IndexedTable, ridx)
```
Internal printing function.

Computes for an indexed table `t` whether or not any of the entries
corresponding to row index `ridx` have nonempty standard errors.
"""
function empty_se(t::IndexedTable, ridx)
    n, m = size(t)
    for j=1:m
        cidx          = t.col_index[j]
        val, se, star = get_vals(t, ridx, cidx)
        isempty(se) || return false
    end
    return true
end

function body(printer::TablePrinter{N,M}) where {N,M}
    output = ""
    n, m = size(printer.table)
    for i=1:n
        output *= printline(printer, i)
        output *= newline(printer)
        output *= subline(printer, i)
        output *= hline(printer, i)
        output *= endline(printer)
    end
    return output
end

function printline(printer::TablePrinter, i)
    i >= 1  || throw(ArgumentError("$i is an invalid row number"))
    t       =  printer.table
    n, m    =  size(t)
    pad     =  printer.params.pad
    pad_ws  =  " "^pad
    sep     =  printer.params.sep
    sep_len =  length(sep)

    @unpack se_pos, star  =  printer.params

    # Get the column lengths, column schema, block width schema, and
    # rowheader length
    lengths, bw_schema  = get_lengths(printer)

    # Start writing the lines
    output   = ""
    output  *= rowheader(printer, i)
    ridx     = t.row_index[i]
    print_se = !empty_se(t, ridx)
    inline   = se_pos == :inline
    below    = se_pos == :below
    if below & print_se
        line2= rowheader(printer, i, empty=true)
    end

    for j = 1:m
        cidx    = t.col_index[j]
        val, se, stars = get_vals(t, ridx, cidx)

        # Are we printing the standard errors?
        use_se  = inline & print_se

        # Format and Print the value
        output  *= sep * pad_ws
        entry    = val
        entry   *= star ? stars : ""
        entry   *= use_se       ?
                   pad_ws * se  :
                   ""
        output  *= format("{:>$(lengths[j])}",entry) * pad_ws

        if below & print_se
            line2 *= sep * pad_ws
            line2 *= format("{:>$(lengths[j])}",se)
            line2 *= pad_ws
        end
    end

    if below & print_se
        output *= newline(printer)*endline(printer)
        output *= line2
    end
    return output
end

function rowheader(printer::TablePrinter{N,M}, i; empty=false) where {N,M}
    t       =  printer.table
    pad     =  printer.params.pad
    pad_ws  =  " "^pad
    sep     =  printer.params.sep
    sep_len =  length(sep)
    ridx    =  t.row_index

    output  = ""
    for j = 1:N
        # Check whether they're all empty
        empty_row(t, j) && continue

        # Otherwise, figure out if we need to print it this time round
        no_check    = (i == 1) | (j == N)
        print_name  = no_check ? true : new_group(ridx[i],ridx[i-1], j)

        # Print the separator and the padding
        output *= ((j==1) || empty_row(t, j-1))  ? "" : sep * pad_ws

        # Get length of rowheader for formatting
        len     = rowheader_length(printer, j)

        # Print the name or whitespace depending on `print_name`
        if print_name & !empty
            # Check the size of the row if we're printing
            block_size  = schema_lookup(printer.row_schema[j], i)

            # Add the row to the output
            name    = ridx[i].name[j]
            output *= format("{:>$len}",
                             format_row_name(printer, j, block_size,
                                             name))
        else
            output *= format("{:>$len}", "")
        end

        # Print the final padding
        output *= pad_ws
    end
    return output
end

function schema_lookup(schema, i)

    # Cumulative count sum
    counts  = map(x->x.second, schema) |> cumsum

    # Find insertion point for i
    idx     = searchsortedfirst(counts, i)

    # Return the block size at that point
    return schema[idx].second
end

function format_row_name(printer::TablePrinter{N,M}, level::Int,
                         block_size::Int, name)::String where {N,M}
    @unpack table_type = printer.params

    if table_type == :ascii
        fname = string(name)
    elseif table_type == :latex
        fname =  block_size == 1 ?  string(name) : mr(block_size,name)
    end
    return string(fname)
end

"""
```
mr(rows, val="", align="c")
"""
function mr(cols, val="")
    return "\\multirow{$cols}{*}{$val}"
end

########################################################################
#################### Footer ############################################
########################################################################

function foot(t::TablePrinter)
    @unpack table_type = t.params
    table_type == :ascii && return ""
    table_type == :latex && return "\\bottomrule\n\\end{tabular}"
end

########################################################################
#################### Printing ##########################################
########################################################################

function center(str::String, width::Int)

    l = length(str)
    if l > width
        return str
    else
        k   = div(width - l, 2)
        str = format("{:>$(l + k)}", str)
        str = format("{:<$width}", str)
        return str
    end
end

center(str::Symbol, width::Int) = center(string(str), width)

function getindex(t::IndexedTable, row)
    output = []
    for col in t.columns
        push!(output, col[row])
    end

    return output
end

show(io::IO, col::TableCol) = print(io, IndexedTable(col))

size(t::IndexedTable)= (length(t.row_index), length(t.col_index))

function rowheader_length(printer::TablePrinter, level::Int)
    t           = printer.table
    row_index   = t.row_index
    row_names   = get_name(row_index)
    row_schema  = printer.row_schema[level]
    n, m        = size(t)

    # Compute the max length
    l = 0
    for i=1:n
        idx = t.row_index[i]
        name  = idx.name[level]
        bsize = schema_lookup(row_schema, i)
        fname = format_row_name(printer, level, bsize, name)
        l = max(l, length(fname))
    end
    return l
end

"""
```
rowheader_length(printer::TablePrinter [, level::Int])
```
Computes the full length of the row-header.  If level is specified, it
computes the length of just the one level.  If no level is specified, it
computes the sum of all the level lengths, accounting for padding and
separator characters.
"""
function rowheader_length(printer::TablePrinter{N,M}) where {N,M}
    # Unpack
    t           = printer.table
    pad         = printer.params.pad
    sep         = printer.params.sep
    sep_len     = length(sep)
    total_pad   = 2*pad + sep_len

    # Offset it by one since there's no leading space
    l = -total_pad
    for i=1:N
        lh = rowheader_length(printer, i)
        l += lh
        l += lh > 0 ? total_pad : 0
    end
    return l
end

########################################################################
#################### REPL Output #######################################
########################################################################

function print(io::IO, p::TablePrinter)
    print(io, head(p)*body(p)*foot(p))
end

function print(io::IO, t::IndexedTable{N,M}; kwargs...) where {N,M}
    if all(size(t) .> 0)
        # Construct the printer
        printer = TablePrinter(t; kwargs...)
        print(io, printer)
    else
        print(io, "IndexedTable{$N,$M} of size $(size(t))")
    end
end

function print(t::IndexedTable; kwargs...)
    print(stdout, t; kwargs...)
end

show(io::IO, t::IndexedTable; kwargs...) = print(io, t; kwargs...)
show(t::IndexedTable; kwargs...) = print(t; kwargs...)

########################################################################
#################### String Output Methods #############################
########################################################################

function to_ascii(t::IndexedTable; kwargs...)
    any(size(t) .== 0) && throw(error("Can't export empty table"))
    p= TablePrinter(t; table_type = :ascii, kwargs...)
    return head(p)*body(p)*foot(p)
end

function to_tex(t::IndexedTable; kwargs...)
    any(size(t) .== 0) && throw(error("Can't export empty table"))
    p = TablePrinter(t; table_type = :latex, kwargs...)
    return head(p)*body(p)*foot(p)
end

########################################################################
#################### Latex Table Output ################################
########################################################################

function write_tex(outfile, t::IndexedTable)
    open(outfile, "w") do f
        write(f, to_tex(t))
    end
end


text:
function all_packages(package::AbstractPackage)
  packages = union(
    package.build_depends,
    map(x -> get(x, :depends, []), package.binaries)...
  )
  setdiff(packages, map(x -> x[:package], package.binaries))
end

function container(package::AbstractPackage, workdir="workspace")
  const name = package_name(package)
  const image_name = matchall(r"[a-z0-9-_\.]", name) |> join
  const build = builddir(package, workdir)

  env = {:LOGNAME => :RSDT, :DEBFULLNAME => package.maintainer, :EMAIL => package.email}
  # all dependencies except those declared in this here package
  image = RudeOil.image(image_name; packages=all_packages(package), env=env, volume="/$name")

  package.image |> image |> Container(volume=(build, "/$name"), workdir="/$name/$name")
end

function dh_make(package::AbstractPackage; workdir="workspace")
  const name = package_name(package)
  const tar = tarfile(package, workdir)

  if length(package.license) > 0
    `dh_make -i -a -r cdbs -l -f /$name/$(basename(tar)) -c $(package.license)`
  else
    `dh_make -i -a -r cdbs -l -f /$name/$(basename(tar))`
  end
end

dh_build(::AbstractPackage, args...) = `dpkg-buildpackage $args`
debuild(::AbstractPackage, args...) = `debuild -us -uc -S $args`

type Builder <: AbstractBuilder; end

function make(package::AbstractPackage, workdir="workspace"; kwargs...)
  make(package, package.build, workdir; kwargs...)
end
function make(package::AbstractPackage, builder::AbstractBuilder, workdir::String;
    source=true, binaries=true, domake=true, cpus=0)
  cmds = Cmd[]
  if domake; push!(cmds, dh_make(package, workdir=workdir)); end
  if binaries; push!(cmds, dh_build(package)); end
  if source; push!(cmds, debuild(package)); end

  if cpus > 0
    cmds = [setenv(c, ["MAKEFLAGS=-j$cpus"]) for c in cmds]
  end

  container(package, workdir), cmds
end

function test(func::Function, vm::RudeOil.MachineEnv, package::AbstractPackage, workdir)
  const name = package_name(package)
  c = container(package, workdir)
  c.workdir = "/$name"
  if isa(c.image, RudeOil.BuildImage)
    vm |> c.image |> run
  end
  c.interactive = true
  open(RudeOil.command(vm, c), "w", STDOUT) do stream
    write(stream, "dpkg -i $(package.name)*.deb\n" * func(name))
  end
end
function test(func::Function, machine::RudeOil.AbstractMachine, package::AbstractPackage, workdir)
  vm = activate(machine)
  test(func, vm, package, workdir)
end

max_stars_repo_name: UCL/DebbyPacker

max_issues_repo_name: UCL/DebbyPacker

max_forks_repo_name: UCL/DebbyPacker


text:
if basename(pwd()) == "aoc"
    cd("2018/4")
end

# presorted input data in shell
function loadshifts(filename::AbstractString)
    guards = Dict{Int,Dict{AbstractString,Vector{UnitRange{Int}}}}()
    activeguard = 0
    fellasleep = 0
    for line in eachline(filename)
        date, minutes, instr = match(r"\[(\S+) \d+:(\d+)\] (.*)", line)
        if startswith(instr, "Guard")
            activeguard = parse(Int, match(r"#(\d+)", line)[1])
        elseif instr == "falls asleep"
            fellasleep = parse(Int, minutes)
        else
            if !haskey(guards, activeguard)
                guards[activeguard] = Dict{AbstractString,Vector{UnitRange{Int}}}()
            end
            if !haskey(guards[activeguard], date)
                guards[activeguard][date] = UnitRange{Int}[]
            end
            wokeup = parse(Int, minutes) - 1
            push!(guards[activeguard][date], fellasleep:wokeup)
        end
    end
    guards
end

part1(filename::AbstractString) = part1(loadshifts(filename))
function part1(guards::Dict)
    _, sleepiestguardid = findmax(guards) do guard
        sum(sum.(broadcast.(length, values(guard))))
    end
    sleepyhead = guards[sleepiestguardid]
    _, sleepiestminute = findmax(0:59) do minute
        count(in.(minute, Iterators.flatten(values(sleepyhead))))
    end
    sleepiestguardid * (sleepiestminute - 1)
end
@assert part1("example.txt") == 240
part1("input.txt")

part2(filename::AbstractString) = part2(loadshifts(filename))
function part2(guards::Dict)
    ((daysasleep, atminute), sleepyid) = findmax(guards) do guard
        sleeps = vcat(values(guard)...)
        findmax(0:59) do minute
            count(minute in sleep for sleep in sleeps)
        end .- (0, 1)
    end
    sleepyid * atminute
end
@assert part2("example.txt") == 4455
part2("input.txt")

max_stars_repo_name: stellartux/advent-of-code

max_issues_repo_name: stellartux/advent-of-code

max_forks_repo_name: stellartux/advent-of-code


text:
# Tests for Revenue Russell DEA Models
@testset "RevenueRussellDEAModel" begin

    # Test using Book data
    X = [1; 1; 1; 1; 1; 1; 1; 1];
    Y = [7 7; 4 8; 8 4; 3 5; 3 3; 8 2; 6 4; 1.5 5];
    P = [1 1; 1 1; 1 1; 1 1; 1 1; 1 1; 1 1; 1 1];

    # Revenue Russell
    revenuerddf = dearevenuerddf(X, Y, P, :ERG)

    @test typeof(revenuerddf) == RevenueReverseDDFDEAModel

    @test nobs(revenuerddf) == 8
    @test ninputs(revenuerddf) == 1
    @test noutputs(revenuerddf) == 2
    @test ismonetary(revenuerddf) == false

    @test efficiency(revenuerddf) == efficiency(revenuerddf, :Economic)
    @test efficiency(revenuerddf, :Economic)   ≈ [0.0; 0.25; 0.25; 13/28; 4/7; 2/3; 11/35; 9/11]
    @test efficiency(revenuerddf, :Technical)  ≈ [0.0; 0.0; 0.0; 13/28; 4/7; 1/3; 11/35; 37/55]
    @test efficiency(revenuerddf, :Allocative) ≈ [0.0; 0.25; 0.25; 0.0; 0.0; 1/3; 0.0; 8/55]
    @test normfactor(revenuerddf) ≈ [14.0; 8.0; 8.0; 168/13; 14.0; 6.0; 140/11; 55/6] atol = 1e-5

    # With monetary = true
    revenurrddfmon = dearevenuerddf(X, Y, P, :ERG, monetary = true)

    @test ismonetary(revenurrddfmon) == true

    @test efficiency(revenurrddfmon) ≈ efficiency(revenuerddf) .* normfactor(revenuerddf)
    @test efficiency(revenurrddfmon, :Technical) ≈ efficiency(revenuerddf, :Technical) .* normfactor(revenuerddf)
    @test efficiency(revenurrddfmon, :Allocative) ≈ efficiency(revenuerddf, :Allocative) .* normfactor(revenuerddf)

    # With CRS (Same result in this example)
    revenurrddfcrs = dearevenuerddf(X, Y, P, :ERG, rts = :CRS)

    @test efficiency(revenurrddfcrs, :Economic)   ≈ [0.0; 0.25; 0.25; 13/28; 4/7; 2/3; 11/35; 9/11]
    @test efficiency(revenurrddfcrs, :Technical)  ≈ [0.0; 0.0; 0.0; 13/28; 4/7; 1/3; 11/35; 37/55]
    @test efficiency(revenurrddfcrs, :Allocative) ≈ [0.0; 0.25; 0.25; 0.0; 0.0; 1/3; 0.0; 8/55]

    # Print
    show(IOBuffer(), revenuerddf)

    # Test errors
    @test_throws DimensionMismatch dearevenuerddf([1; 2 ; 3], [4 ; 5], [1; 1; 1], :ERG) #  Different number of observations
    @test_throws DimensionMismatch dearevenuerddf([1; 2; 3], [4; 5; 6], [1; 2; 3; 4], :ERG) # Different number of observation in prices
    @test_throws DimensionMismatch dearevenuerddf([1 1; 2 2; 3 3 ], [4; 5; 6], [1 1 1; 2 2 2; 3 3 3], :ERG) # Different number of output prices and outputs
    @test_throws ArgumentError dearevenuerddf([1; 2; 3], [4; 5; 6], [4; 5; 6], :Error) # Invalid associated efficiency measure
    @test_throws ArgumentError dearevenuerddf([1; 2; 3], [4; 5; 6], [1; 2; 3], :ERG, rts = :Error) # Invalid returns to scale

end


text:
@testset "Attributes" begin
    @testset "is_set_by_optimize" begin
        @test MOI.is_set_by_optimize(MOI.TerminationStatus())
        @test !MOI.is_set_by_optimize(MOI.ConstraintSet())
        @test !MOI.is_set_by_optimize(MOI.ObjectiveSense())
    end
    @testset "is_copyable" begin
        @test !MOI.is_copyable(MOI.TerminationStatus())
        @test !MOI.is_copyable(MOI.ConstraintSet())
        @test MOI.is_copyable(MOI.ObjectiveSense())
    end
    @testset "supports" begin
        model = DummyModel()
        @test_throws ArgumentError MOI.supports(model, MOI.TerminationStatus())
        @test_throws ArgumentError begin
            MOI.supports(model, MOI.ConstraintSet(),
                         MOI.ConstraintIndex{MOI.SingleVariable,
                                             MOI.EqualTo{Float64}})
        end
        @test MOI.supports(model, MOI.ObjectiveSense())
    end
    @testset "set vector" begin
        attr = MOI.VariablePrimalStart()
        err = DimensionMismatch("Number of indices (1) does not match the " *
                                "number of values (2) set to `$attr`.")
        model = DummyModel()
        x = MOI.VariableIndex(1)
        @test_throws err MOI.set(model, MOI.VariablePrimalStart(), [x],
                                 ones(2))
    end
end


text:
using Base.Test
using QuantumOptics

@testset "spin" begin

D(op1::Operator, op2::Operator) = abs(tracedistance_nh(full(op1), full(op2)))

# Test creation
@test_throws AssertionError SpinBasis(1//3)
@test_throws AssertionError SpinBasis(-1//2)
@test_throws AssertionError SpinBasis(0)

for spinnumber=[1//2, 1, 3//2, 4//2]
    spinbasis = SpinBasis(spinnumber)
    I = operators.identityoperator(spinbasis)
    Zero = SparseOperator(spinbasis)
    sx = sigmax(spinbasis)
    sy = sigmay(spinbasis)
    sz = sigmaz(spinbasis)
    sp = sigmap(spinbasis)
    sm = sigmam(spinbasis)

    # Test traces
    @test 0 == trace(sx)
    @test 0 == trace(sy)
    @test 0 == trace(sz)

    # Test kommutation relations
    kommutator(x, y) = x*y - y*x

    @test 1e-12 > D(kommutator(sx, sx), Zero)
    @test 1e-12 > D(kommutator(sx, sy), 2im*sz)
    @test 1e-12 > D(kommutator(sx, sz), -2im*sy)
    @test 1e-12 > D(kommutator(sy, sx), -2im*sz)
    @test 1e-12 > D(kommutator(sy, sy), Zero)
    @test 1e-12 > D(kommutator(sy, sz), 2im*sx)
    @test 1e-12 > D(kommutator(sz, sx), 2im*sy)
    @test 1e-12 > D(kommutator(sz, sy), -2im*sx)
    @test 1e-12 > D(kommutator(sz, sz), Zero)

    # Test creation and anihilation operators
    @test 0 == D(sp, 0.5*(sx + 1im*sy))
    @test 0 == D(sm, 0.5*(sx - 1im*sy))
    @test 0 == D(sx, (sp + sm))
    @test 0 == D(sy, -1im*(sp - sm))

    # Test commutation relations with creation and anihilation operators
    @test 1e-12 > D(kommutator(sp, sm), sz)
    @test 1e-12 > D(kommutator(sz, sp), 2*sp)
    @test 1e-12 > D(kommutator(sz, sm), -2*sm)

    # Test v x (v x u) relation: [sa, [sa, sb]] = 4*(1-delta_{ab})*sb
    @test 1e-12 > D(kommutator(sx, kommutator(sx, sx)), Zero)
    @test 1e-12 > D(kommutator(sx, kommutator(sx, sy)), 4*sy)
    @test 1e-12 > D(kommutator(sx, kommutator(sx, sz)), 4*sz)
    @test 1e-12 > D(kommutator(sy, kommutator(sy, sx)), 4*sx)
    @test 1e-12 > D(kommutator(sy, kommutator(sy, sy)), Zero)
    @test 1e-12 > D(kommutator(sy, kommutator(sy, sz)), 4*sz)
    @test 1e-12 > D(kommutator(sz, kommutator(sz, sx)), 4*sx)
    @test 1e-12 > D(kommutator(sz, kommutator(sz, sy)), 4*sy)
    @test 1e-12 > D(kommutator(sz, kommutator(sz, sz)), Zero)

    # Test spinup and spindown states
    @test 1 ≈ norm(spinup(spinbasis))
    @test 1 ≈ norm(spindown(spinbasis))
    @test 0 ≈ norm(sp*spinup(spinbasis))
    @test 0 ≈ norm(sm*spindown(spinbasis))
end

# Test special relations for spin 1/2

spinbasis = SpinBasis(1//2)
I = identityoperator(spinbasis)
Zero = SparseOperator(spinbasis)
sx = sigmax(spinbasis)
sy = sigmay(spinbasis)
sz = sigmaz(spinbasis)
sp = sigmap(spinbasis)
sm = sigmam(spinbasis)

# Test antikommutator
antikommutator(x, y) = x*y + y*x

@test 0 ≈ D(antikommutator(sx, sx), 2*I)
@test 0 ≈ D(antikommutator(sx, sy), Zero)
@test 0 ≈ D(antikommutator(sx, sz), Zero)
@test 0 ≈ D(antikommutator(sy, sx), Zero)
@test 0 ≈ D(antikommutator(sy, sy), 2*I)
@test 0 ≈ D(antikommutator(sy, sz), Zero)
@test 0 ≈ D(antikommutator(sz, sx), Zero)
@test 0 ≈ D(antikommutator(sz, sy), Zero)
@test 0 ≈ D(antikommutator(sz, sz), 2*I)

# Test if involutory for spin 1/2
@test 0 ≈ D(sx*sx, I)
@test 0 ≈ D(sy*sy, I)
@test 0 ≈ D(sz*sz, I)
@test 0 ≈ D(-1im*sx*sy*sz, I)

# Test consistency of spin up and down with sigmap and sigmam
@test 1e-11 > norm(sm*spinup(spinbasis) - spindown(spinbasis))
@test 1e-11 > norm(sp*spindown(spinbasis) - spinup(spinbasis))

end # testset


text:
#module AutoPhase

#using NMR.DataSet
import Optim

export entropy, AutoPhaseCorrect, AutoPhaseCorrectChen

ent(x) = x*log(x)

"""
`entropy(spect::Data1D)` computes the entropy in the real part of an
NMR spectrum as defined by Chen et al. in
*Journal of Magnetic Resonance* **158** (2002) 164–168.
This quantity can be optimised with respect to zero- and first-order
phase correction for automatic (unsupervised) phase correction.
"""
function entropy(spect::Data1D)
    h=abs.(real.(val(spect)))
    h/=sum(h)
    return -sum(ent.(h))
end

# penalty(x) computes the sum of squares of all negative points in x
function penalty(x)
    x /= sum(abs.(x))
    return sum([k<0.0 ? k*k : 0.0 for k in x])
end

# this is the minimisation target for automatic phase correction
function goalfun(x,spect,γ=0.0e-5)
    piv=0.5*(spect.istop+spect.istart)
    c=PhaseCorrect(spect,Ph0=x[1]*10,Ph1=x[2],Pivot=piv);
    return entropy(c)+γ*penalty(real.(val(c)));
end

"""
`AutoPhaseCorrectChen(spect::Data1D;verbose=false)`
performs zero- and first-order phase correction of `spect`
using a minimum entropy algorithm  by Chen et al. in
*Journal of Magnetic Resonance* **158** (2002) 164–168.
It uses the Nelder-Mead algorithm, as implemented in the `Optim.jl`
package.
"""
function AutoPhaseCorrectChen(spect::Data1D;verbose=false,γ=0.0)
  piv=0.5*(spect.istop+spect.istart)
  result=Optim.optimize(x->goalfun(x,spect,γ),[0.1,0.2],Optim.NelderMead(),Optim.Options(show_trace=false,g_tol=1.0e-9));
  if verbose print(result) end;
  pc=Optim.minimizer(result);
  scorr = PhaseCorrect(spect,Ph0=pc[1]*10,Ph1=pc[2],Pivot=piv);
  if (real(integral(scorr))<0.0) scorr = -1.0*scorr end;
  return scorr ;
end

function unwrap(a;p=π,tol=0.25)
    l=length(a)
    w=zeros(Float64,l)
    offset=0
    for k=1:(l-1)
        if( (p-a[k])<p*tol && (a[k+1]+p)<p*tol)
            offset+=2*p;
        elseif( (a[k]+p)<p*tol && (p-a[k+1])<p*tol)
            offset-=2*p;
        end
        w[k+1]=offset;
    end

    return a+w
end

"""
`AutoPhaseCorrect(spect::Data1D)`
performs zero- and first-order phase correction of `spect`
using a the algorithm by van der Waals and Geerens,
*Journal of Magnetic Resonance* **86** (1990) 127-154.
It works by recognising the peaks in the magnitude mode spectrum
and then representing the phase at each peak location
through a linear regression.
"""
function AutoPhaseCorrect(s::NMR.Data1D;exclude=false,threshold=10)
    # --- Step 1: basic phase adjustment
    phase0=angle(sum(s.dat))
    s1=NMR.PhaseCorrect(s,Ph0=-phase0)

    # --- Step 2: recognise peaks in the absolute mode spectrum
    s2=abs(s1);
    pks=NMR.peaks(s2,threshold=threshold);

    # --- Step 3: obtain list of peak phases
    ppos=[NMR.ind2pos(s1,x) for x in pks.positions]

    if exclude!=false
        i=NMR.ind2pos(s,exclude[1]);
        j=NMR.ind2pos(s,exclude[2]);
        ppos=filter(x->(x<i||x>j),ppos)
    end
    pind = [NMR.pos2ind(s,k) for k in ppos]
    pphase=[angle(s1.dat[p]) for p in ppos]
    α=NMR.polyfit(pind,unwrap(pphase),1)
    # print(α,"\n")
    s3=NMR.PhaseCorrect(s1,Ph0=-α[1],Ph1=-α[2])
    return s3
end

#end

max_stars_repo_name: marcel-utz/NMR

max_issues_repo_name: marcel-utz/NMR


text:
using ReachabilityAnalysis
using ReachabilityAnalysis: translate, solve
using Plots
using LaTeXStrings

### deterministic case

# IVP parameters
A = [0.0 1; -4π 0]
b = [1.0, -1.0]
B = hcat(b)
X0 = BallInf([0.0, 10.0], 0.1)
X = Universe(2)
u = -3.0
U_raw = Singleton([u])
U = ConstantInput(linear_map(B, U_raw))
X_homog = Universe(3)

# discretization parameters
δ = 0.1
alg = Forward()

# homogenization parameters
αs = [1.0]

# result for heterogeneous system
P_heterog = @ivp(x' = A*x + u, x ∈ X, u ∈ U, x(0) ∈ X0)
Pd_heterog = discretize(P_heterog, δ, alg)
Ω0_heterog = Pd_heterog.x0

# result for homogenized system
Ω0_homog = []
for α in αs
    local A_homog = [A b*u/α; zeros(1, 3)]
    local X0_homog = cartesian_product(X0, Singleton([α]))
    local P_homog = @ivp(x' = A_homog*x, x ∈ X_homog, x(0) ∈ X0_homog)

    Pd_homog = discretize(P_homog, δ, alg)
    local Ω0 = Projection(Pd_homog.x0, [1, 2])
#     Ω0 = overapproximate(Ω0, PolarDirections(30))  # workaround because σ is not available
    push!(Ω0_homog, Ω0)  # project auxiliary variable
end

# plot sets
plot(leg=:bottomleft, legendfontsize=20, tickfontsize=20)
plot!(Ω0_heterog, alpha=0, color=:blue, linecolor=:blue, linealpha=1, lw=2, lab=L"\Omega_0~\textrm{heterog}")
for i in eachindex(αs)
    plot!(Ω0_homog[i], alpha=0.3, color=:green, linecolor=:green, linealpha=1, lw=2, lab=L"\Omega_0~\textrm{homog}")
end
plot!(X0, alpha=1, color="yellow", lab=L"X_0")
# sampling initial states at time t from vertices and edges of X0
# and then plotting the reachable states for some random input signal
x0s = vcat(sample(X0, 0, include_vertices=true),
           sample(X0, 100, sampler=LazySets.FaceSampler(1)))
for x0 in x0s
    local P = @ivp(x' = A*x + u, x ∈ X, u ∈ U, x(0) ∈ x0)
    sol = solve(P, δ, ORBIT(δ=δ/10))
    plot!(sol, vars=(1, 2), c=:magenta, seriestype=:path, marker=:none)
end

savefig("homogenize_deterministic.pdf")

### nondeterministic case

U_raw = BallInf([u], 0.2)
U = ConstantInput(linear_map(B, U_raw))

# result for heterogeneous system
P_heterog = @ivp(x' = A*x + u, x ∈ X, u ∈ U, x(0) ∈ X0)
Pd_heterog = discretize(P_heterog, δ, alg)
Ω0_heterog = Pd_heterog.x0

# result for homogenized system
Ω0_homog = []
for α in αs
    local A_homog = [A b*u/α; zeros(1, 3)]
    local X0_homog = cartesian_product(X0, Singleton([α]))
    U_raw_homog = cartesian_product(translate(U_raw, -[u]), Singleton([0.0]))
    B_homog = [B zeros(size(B, 1)); zeros(size(B, 2)) 0]
    U_homog = ConstantInput(linear_map(B_homog, U_raw_homog))
    local P_homog = @ivp(x' = A_homog*x + u, x ∈ X_homog, u ∈ U_homog, x(0) ∈ X0_homog)

    Pd_homog = discretize(P_homog, δ, alg)
    push!(Ω0_homog, Projection(Pd_homog.x0, [1, 2]))  # project auxiliary variable
end

# plot sets
plot(leg=:bottomleft, legendfontsize=20, tickfontsize=20)
plot!(Ω0_heterog, alpha=0, color=:blue, linecolor=:blue, linealpha=1, lw=2, lab=L"\Omega_0~\textrm{heterog}")
for i in eachindex(αs)
    plot!(Ω0_homog[i], alpha=0.3, color=:green, linecolor=:green, linealpha=1, lw=2, lab=L"\Omega_0~\textrm{homog}")
end
plot!(X0, alpha=1, color="yellow", lab=L"X_0")
# sampling initial states at time t from vertices and edges of X0
# and then plotting the reachable states for some random input signal
x0s = vcat(sample(X0, 0, include_vertices=true),
           sample(X0, 100, sampler=LazySets.FaceSampler(1)))
for x0 in x0s
    local P = @ivp(x' = A*x + u, x ∈ X, u ∈ U, x(0) ∈ x0)
    sol = solve(P, δ, ORBIT(δ=δ/10))
    plot!(sol, vars=(1, 2), c=:magenta, seriestype=:path, marker=:none)
end

savefig("homogenize_nondeterministic.pdf")


text:
#
# Date created: 2022-03-15
# Author: aradclif
#
#
############################################################################################

function outerloop(N::Int, D)
    params = D.parameters
    block = Expr(:block)
    for d = N:-1:1
        if params[d] !== Val{1}
            push!(block.args, Expr(:(=), Symbol(:i_, d), Expr(:call, :axes, :A, d)))
        end
    end
    Expr(:for, block)
end

function innerloop(N::Int, D)
    params = D.parameters
    block = Expr(:block)
    for d = N:-1:1
        if params[d] === Val{1}
            push!(block.args, Expr(:(=), Symbol(:i_, d), Expr(:call, :axes, :A, d)))
        end
    end
    Expr(:for, block)
end

function loop(J::NTuple{N, Int}) where {N}
    Expr(:for, Expr(:block, ntuple(d -> Expr(:(=), Symbol(:i_, J[d]), Expr(:call, :axes, :A, J[d])), N)...))
end

################
function nonreduceloop(d::Int)
    Expr(:for, Expr(:(=), Symbol(:i_, d), Expr(:call, :indices, Expr(:tuple, :A, :B), d)))
end
l4 = nonreduceloop(4)
l2 = nonreduceloop(2)

function reduceloop(d::Int)
    Expr(:for, Expr(:(=), Symbol(:i_, d), Expr(:call, :axes, :A, d)))
end
l3 = reduceloop(3)
l1 = reduceloop(1)

function nonreducekernel(dims::Vector{Int})
    ds = sort(dims, rev=true)
    loops = nonreduceloop_first(first(ds))
    lₒ = loops
    for i = 2:length(ds)
        lᵢ = nonreduceloop(ds[i])
        push!(lₒ.args, lᵢ)
        lₒ = lᵢ
    end
    loops
end
function reducekernel(dims::Vector{Int})
    ds = sort(dims, rev=true)
    loops = reduceloop(first(ds))
    lₒ = loops
    for i = 2:length(ds)
        lᵢ = reduceloop(ds[i])
        push!(lₒ.args, lᵢ)
        lₒ = lᵢ
    end
    loops
end

lastfor(e::Expr) = length(e.args) ≥ 2 && e.args[2].head === :for ? lastfor(e.args[2]) : e
lastforb(e::Expr) = length(e.args) ≥ 2 && ls.args[1].head === :for ? lastforb(e.args[1]) : e
function lastfor(e::Expr)
    if length(e.args) ≥ 2 && e.args[2].head === :for
        lastfor(e.args[2])
    else# e.head === :block
        e.head === :block && e.args[1].head === :for ? lastfor(e.args[1]) : e
    end
end

e = reducekernel([1, 3])
el = lastfor(e)

e2 = nonreducekernel([2, 4])
el2 = lastfor(e2)
push!(el2.args, e)
push!(lastfor(el2).args, Expr(:call, :+, a, 1))

prog = "for i_4 = indices((A, B), 4)
          for i_2 = indices((A, B), 2)
              for i_3 = axes(A, 3)
                  for i_1 = axes(A, 1)
                      A[i_1, i_2, i_3, i_4] + 1
                  end
              end
          end
      end"
ex2 = Meta.parse(prog)


text:
using ProblemParser
using Utils

using Underscores

const file = find_input(@__FILE__)
const input = parse(Split(",", Convert(Int8)), slurp(file))

function solve(input, days)
    ages = zeros(Int, 9) |> zerobased
    for age in input
        ages[age] += 1
    end
    for _ in 1:days
        ages = circshift(ages, -1)
        ages[6] += ages[8]
    end
    sum(ages)
end

assertequal(solve(input, 80), 350917)
assertequal(solve(input, 256), 1592918715629)

max_stars_repo_name: CmdQ/AoC


text:
mutable struct MetaInfo
    # data and filled range
    data::Vector{UInt8}
    filled::UnitRange{Int}
    # true iff values are indexed by keys (e.g. <ID=...>).
    dict::Bool
    # indexes
    tag::UnitRange{Int}
    val::UnitRange{Int}
    dictkey::Vector{UnitRange{Int}}
    dictval::Vector{UnitRange{Int}}
end

"""
    VCF.MetaInfo()
Create an unfilled VCF metainfo.
"""
function MetaInfo()
    return MetaInfo(UInt8[], 1:0, false, 1:0, 1:0, UnitRange{Int}[], UnitRange{Int}[])
end

"""
    VCF.MetaInfo(data::Vector{UInt8})
Create a VCF metainfo from `data` containing a VCF header line.
This function verifies the format and indexes fields for accessors.
Note that the ownership of `data` is transferred to a new metainfo object.
"""
function MetaInfo(data::Vector{UInt8})
    return convert(MetaInfo, data)
end

function Base.convert(::Type{MetaInfo}, data::Vector{UInt8})
    metainfo = MetaInfo(data, 1:0, false, 1:0, 1:0, UnitRange{Int}[], UnitRange{Int}[])
    index!(metainfo)
    return metainfo
end

"""
    VCF.MetaInfo(str::AbstractString)
Create a VCF metainfo from `str` containing a VCF header line.
This function verifies the format and indexes fields for accessors.
"""
function MetaInfo(str::AbstractString)
    return convert(MetaInfo, str)
end

function Base.convert(::Type{MetaInfo}, str::AbstractString)
    return MetaInfo(Vector{UInt8}(str))
end

function initialize!(metainfo::MetaInfo)
    metainfo.filled = 1:0
    metainfo.dict = false
    metainfo.tag = 1:0
    metainfo.val = 1:0
    empty!(metainfo.dictkey)
    empty!(metainfo.dictval)
    return metainfo
end

function datarange(metainfo::MetaInfo)
    return metainfo.filled
end

function isfilled(metainfo::MetaInfo)
    return !isempty(metainfo.filled)
end

function Base.:(==)(metainfo1::MetaInfo, metainfo2::MetaInfo)
    if isfilled(metainfo1) == isfilled(metainfo2) == true
        r1 = datarange(metainfo1)
        r2 = datarange(metainfo2)
        return length(r1) == length(r2) && memcmp(pointer(metainfo1.data, first(r1)), pointer(metainfo2.data, first(r2)), length(r1)) == 0
    else
        return isfilled(metainfo1) == isfilled(metainfo2) == false
    end
end

function checkfilled(metainfo::MetaInfo)
    if !isfilled(metainfo)
        throw(ArgumentError("unfilled VCF metainfo"))
    end
end

function MetaInfo(base::MetaInfo; tag = nothing, value = nothing)
    checkfilled(base)
    buf = IOBuffer()
    print(buf, "##")
    if tag == nothing
        write(buf, base.data[base.tag])
    else
        print(buf, tag)
    end
    print(buf, '=')
    if value == nothing
        write(buf, base.data[base.val])
    elseif isa(value, String)
        print(buf, value)
    elseif isa(value, AbstractDict) || isa(value, Vector)
        print(buf, '<')
        for (i, (key, val)) in enumerate(value)
            if i != 1
                print(buf, ',')
            end
            print(buf, key, '=')
            if needs_quote(val)
                print(buf, '"', escape_string(val), '"')
            else
                print(buf, val)
            end
        end
        print(buf, '>')
    end
    return MetaInfo(take!(buf))
end

function needs_quote(val::String)
    return occursin(" ", val) || occursin(",", val) || occursin("\"", val) || occursin("\\", val)
end

function isequaltag(metainfo::MetaInfo, tag::AbstractString)
    checkfilled(metainfo)
    return length(metainfo.tag) == sizeof(tag) &&
           memcmp(pointer(metainfo.data, first(metainfo.tag)), pointer(tag), length(metainfo.tag)) == 0
end

function BioCore.metainfotag(metainfo::MetaInfo)
    checkfilled(metainfo)
    return String(metainfo.data[metainfo.tag])
end

function BioCore.metainfoval(metainfo::MetaInfo)
    checkfilled(metainfo)
    return String(metainfo.data[metainfo.val])
end

function Base.keys(metainfo::MetaInfo)
    checkfilled(metainfo)
    if !metainfo.dict
        throw(ArgumentError("not a dictionary"))
    end
    return [String(metainfo.data[r]) for r in metainfo.dictkey]
end

function Base.values(metainfo::MetaInfo)
    checkfilled(metainfo)
    if !metainfo.dict
        throw(ArgumentError("not a dictionary"))
    end
    vals = String[]
    for r in metainfo.dictval
        push!(vals, extract_metainfo_value(metainfo.data, r))
    end
    return vals
end

function Base.getindex(metainfo::MetaInfo, key::String)
    checkfilled(metainfo)
    if !metainfo.dict
        throw(ArgumentError("not a dictionary"))
    end
    for (i, r) in enumerate(metainfo.dictkey)
        n = length(r)
        if n == sizeof(key) && memcmp(pointer(metainfo.data, first(r)), pointer(key), n) == 0
            return extract_metainfo_value(metainfo.data, metainfo.dictval[i])
        end
    end
    throw(KeyError(key))
end

function extract_metainfo_value(data::Vector{UInt8}, range::UnitRange{Int})
    lo = first(range)
    hi = last(range)
    if length(range) ≥ 2 && data[lo] == data[hi] == UInt8('"')
        return unescape_string(String(data[lo+1:hi-1]))
    else
        return String(data[lo:hi])
    end
end

function Base.show(io::IO, metainfo::MetaInfo)
    print(io, summary(metainfo), ':')
    if isfilled(metainfo)
        println(io)
        println(io, "    tag: ", BioCore.metainfotag(metainfo))
        print(io, "  value:")
        if metainfo.dict
            for (key, val) in zip(keys(metainfo), values(metainfo))
                print(io, ' ', key, "=\"", val, '"')
            end
        else
            print(io, ' ', BioCore.metainfoval(metainfo))
        end
    else
        print(io, " <not filled>")
    end
end

function Base.write(io::IO, metainfo::MetaInfo)
    checkfilled(metainfo)
    return write(io, metainfo.data)
end


text:
# This file is auto-generated by AWSMetadata.jl
using AWS
using AWS.AWSServices: apigatewaymanagementapi
using AWS.Compat
using AWS.UUIDs

"""
    delete_connection(connection_id)
    delete_connection(connection_id, params::Dict{String,<:Any})

Delete the connection with the provided id.

# Arguments
- `connection_id`:

"""
function delete_connection(connectionId; aws_config::AbstractAWSConfig=global_aws_config())
    return apigatewaymanagementapi(
        "DELETE",
        "/@connections/$(connectionId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function delete_connection(
    connectionId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return apigatewaymanagementapi(
        "DELETE",
        "/@connections/$(connectionId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    get_connection(connection_id)
    get_connection(connection_id, params::Dict{String,<:Any})

Get information about the connection with the provided id.

# Arguments
- `connection_id`:

"""
function get_connection(connectionId; aws_config::AbstractAWSConfig=global_aws_config())
    return apigatewaymanagementapi(
        "GET",
        "/@connections/$(connectionId)";
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function get_connection(
    connectionId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return apigatewaymanagementapi(
        "GET",
        "/@connections/$(connectionId)",
        params;
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end

"""
    post_to_connection(data, connection_id)
    post_to_connection(data, connection_id, params::Dict{String,<:Any})

Sends the provided data to the specified connection.

# Arguments
- `data`: The data to be sent to the client specified by its connection id.
- `connection_id`: The identifier of the connection that a specific client is using.

"""
function post_to_connection(
    Data, connectionId; aws_config::AbstractAWSConfig=global_aws_config()
)
    return apigatewaymanagementapi(
        "POST",
        "/@connections/$(connectionId)",
        Dict{String,Any}("Data" => Data);
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end
function post_to_connection(
    Data,
    connectionId,
    params::AbstractDict{String};
    aws_config::AbstractAWSConfig=global_aws_config(),
)
    return apigatewaymanagementapi(
        "POST",
        "/@connections/$(connectionId)",
        Dict{String,Any}(mergewith(_merge, Dict{String,Any}("Data" => Data), params));
        aws_config=aws_config,
        feature_set=SERVICE_FEATURE_SET,
    )
end


text:
@with_kw struct CROWN <: Solver
    method = :DeepPolyRelax  # alternative is :ParallelRelax
end

struct SymbolicBound
    # B(x) ≤≥ Λx + γ
    Λ::Union{Matrix{Float64}, UniformScaling{Bool}}  # UniformScaling for I
    γ::Union{Vector{Float64}, Float64}  # Float64 for 0.
end

function backward_linear(solver::CROWN, L::Layer, input::SymbolicBound)
    Λ = input.Λ * L.weights
    γ = input.Λ * L.bias .+ input.γ
    return SymbolicBound(Λ, γ)
end

function backward_act(solver::CROWN, L::Layer{ReLU}, input::SymbolicBound, lbs, ubs; upper=false)
    flip = upper ? -1. : 1.  # Λ⁺ and Λ⁻ are flipped for upper bound vs lower bound
    Λ⁺ = max.(flip * input.Λ, 0)
    Λ⁻ = min.(flip * input.Λ, 0)

    if solver.method == :DeepPolyRelax
        λ_l = relaxed_relu_gradient_lower.(lbs, ubs)
        λ_u = relaxed_relu_gradient.(lbs, ubs)
    elseif solver.method == :ParallelRelax
        λ_l = relaxed_relu_gradient.(lbs, ubs)
        λ_u = λ_l
    else
        throw(ArgumentError("Don't know relaxation method $(solver.method)!"))
    end

    β_l = zero(lbs)
    β_u = λ_u .* max.(-lbs, 0)

    Λ = flip * (Λ⁻ .* λ_u' + Λ⁺ .* λ_l')
    γ = flip * (Λ⁻ * β_u + Λ⁺ * β_l) .+ input.γ

    return SymbolicBound(Λ, γ)
end

function backward_act(solver::CROWN, L::Layer{Id}, input::SymbolicBound, lbs, ubs; upper=false)
    return input
end

"""
Calculates parameters of linear bounding function of the network via symbolic
backward propagation, given pre-activation bounds of the intermediate neurons.
By default a lower bound is calculated, for upper bound, set upper=true

solver - the solver to use for symbolic backward propagation
net - the network to generate the bounding function for
lbs - lower bounds on the pre-activation values of the intermediate neurons
ubs - upper bounds on the pre-activation values of the intermediate neurons
input - not needed as of now
upper - whether to calculate upper bound, if false, we calculate lower bound
"""
function backward_network(solver, net, lbs, ubs, input; upper=false)
    # assumes that last layer is linear!
    Z = SymbolicBound(I, 0.)
    Z = backward_linear(solver, net.layers[end], Z)
    for i in reverse(1:length(net.layers)-1)
        layer = net.layers[i]

        Ẑ = backward_act(solver, layer, Z, lbs[i], ubs[i], upper=upper)
        Z = backward_linear(solver, layer, Ẑ)
    end

    return Z
end

"""
Calculates pre-activation bounds for each of the neurons in the network starting
at from_layer.

solver - the solver to use for calculating bounds
net - the network the bounds are calculated for
input_set - input constraints for the network (right now LazySet, Hyperrectangle)

from_layer::Int - calculate bounds from that layer onwards to the last layer
lbs - lower bounds to use. Need bounds for all layers from the start to from_layer-1
ubs - upper bounds to use. See lbs for more info
printing - whether to print progress of bounds computation
"""
function calc_bounds(solver::CROWN, net, input_set; from_layer=1, lbs=nothing, ubs=nothing, printing=false)
    layers = from_layer == 1 ? [] : net.layers[1:from_layer-1]
    lbs = isnothing(lbs) ? [] : lbs
    ubs = isnothing(ubs) ? [] : ubs

    for (i, l) in enumerate(net.layers[from_layer:end])
        if printing
            println("Layer ", from_layer + i-1)
        end

        push!(layers, l)
        nn_part = Network(layers)

        Zl = backward_network(solver, nn_part, lbs, ubs, input_set)
        Zu = backward_network(solver, nn_part, lbs, ubs, input_set, upper=true)

        sym = SymbolicInterval([Zl.Λ Zl.γ], [Zu.Λ Zu.γ], input_set)
        lb, ub = bounds(sym)
        push!(lbs, lb)
        push!(ubs, ub)
    end

    return lbs, ubs
end


text:
module TreeViewWidget
    using WebIO
    using UUIDs
    using Observables

    export TreeViewNode, TreeViewRoot, TreeView, eachnode

    # note: should not be "selected", because Jupyter already uses that
    const SELECTED_CLASS = "selected2"

    # used by single_select_js, and by TreeView observable constructor
    const SELECTION_OBSERVABLE_NAME = "selected_node"

    include("treeview.jl")
    include("html.jl")
    include("nodeIterator.jl")
end


text:
"""
Uniform Function Call Syntax [^UFCS] wrapper.

Usage:

```julia
PyCall.PyObject(self::MyModule.MyType) = PyBase.UFCS.wrap(self)
```

It then translates Python method call `self.NAME(*args, **kwargs)` to

```julia
MyModule.MyType.NAME(self, args...; kwargs...)  # or
MyModule.MyType.NAME!(self, args...; kwargs...)
```

in Julia where `NAME` is a placeholder (i.e., it can be a method named
`solve` or `plot`).  If both `NAME` and `NAME!` exist, `NAME!` is used
unless `False` is passed to the special keyword argument `inplace`, i.e.,

```python
# in Python:                               #    in Julia:
self.NAME(*args, **kwargs)                 # => NAME(self, args...; kwargs...)
                                           # or NAME!(self, args...; kwargs...)
self.NAME(*args, inplace=False, **kwargs)  # => NAME(self, args...; kwargs...)
self.NAME(*args, inplace=True, **kwargs)   # => NAME!(self, args...; kwargs...)
```

The modules in which method `NAME` is searched can be specified as a
keyword argument to `PyBase.UFCS.wrap`:

```julia
using MyBase, MyModule
PyCall.PyObject(self::MyType) = PyBase.UFCS.wrap(self,
                                                 modules = [MyBase, MyModule])
```

The first match in the list of modules is used.

Usual method overloading of

```julia
PyBase.__getattr__(self::MyModule.MyType, name::Symbol)  # and/or
PyBase.__getattr__(self::MyModule.MyType, ::Val{name})
```

can still control the behavior of Python's `__getattr__` *if* `name`
is not already handled by the above UFCS mechanism.

[^UFCS]: [Uniform Function Call Syntax --- Wikipedia](https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax)
"""
module UFCS

import PyCall
using ..PyBase
using ..JuliaAPI: JuliaObject, convert_pyindices

struct Shim{T} <: PyBase.AbstractShim
    self::T
    methods::Dict{Symbol, Any}
    modules::Vector{Module}
end
# If this is not fast enough, we can get the UUID of the modules, put
# them in the type parameter, and then generate the wrapper in a
# @generated or @pure function.

_process_method(location::Tuple{Symbol, Any}) = location

function _process_method(location::Function)
    n = nameof(location)
    if n == :anonymous
        throw(ArgumentError(
            "Use `(name::Symbol, f)` to specify an anonymous function"))
    end
    return (n, location)
end

process_methods(methods::Dict{Symbol, Any}) = methods

process_methods(methods::AbstractVector) =
    Dict{Symbol, Any}(_process_method.(methods))
# TODO: error on repeated keys

Shim(self::T;
     methods = [],
     modules::Vector{Module} = [parentmodule(T)]) where T =
    Shim(self,
         process_methods(methods),
         modules)

"""
    PyBase.UFCS.wrap(self; methods, modules) :: PyObject

"Uniform Function Call Syntax" wrapper.  See [`PyBase.UFCS`](@ref) for details.
"""
wrap(self; kwargs...) = JuliaObject(Shim(self; kwargs...))

struct MethodShim
    name::Symbol
    f
    shim::Shim
end

(f::MethodShim)(args...; kwargs...) = f.f(f.shim.self, args...; kwargs...)

function Base.show(io::IO, f::MethodShim)
    print(io, "[shim] ")
    show(io, f.f)
end

PyCall.docstring(f::MethodShim) = PyCall.docstring(f.f)

struct DualMethodShim
    name::Symbol
    inp
    oop
    shim::Shim
end

struct Unspecified end

function (f::DualMethodShim)(args...;
                             inplace::Union{Unspecified, Bool} = Unspecified(),
                             kwargs...)
    if inplace isa Unspecified
        if applicable(f.inp, f.shim.self, args...)
            # Default to inplace=true.
            return f.inp(f.shim.self, args...; kwargs...)
        elseif applicable(f.oop, f.shim.self, args...)
            return f.oop(f.shim.self, args...; kwargs...)
        else
            error("$(f.inp) and $(f.oop) do not support given arguments")
        end
    end
    if inplace
        f.inp(f.shim.self, args...; kwargs...)
    else
        f.oop(f.shim.self, args...; kwargs...)
    end
end

function Base.show(io::IO, f::DualMethodShim)
    print(io, "[shim] ")
    show(io, f.inp)
    print(io, " | ")
    show(io, f.oop)
end

function PyCall.docstring(f::DualMethodShim)
    oop_name = string(f.oop)
    inp_name = string(f.inp)
    return """
    A wrapper of $oop_name and $inp_name.

    If keyword argument `inplace=True` (default) is given, it
    calls $inp_name.  If `inplace=False` is given, it calls
    $oop_name.

    ---

    $(PyCall.docstring(f.oop))

    ---

    $(PyCall.docstring(f.inp))
    """
end

function lookup_function(modules, name)
    for m in modules
        if isdefined(m, name)
            return getproperty(m, name)
        end
    end
end

function PyBase.__getattr__(shim::Shim, name::Symbol)
    if haskey(shim.methods, name)
        return MethodShim(name, shim.methods[name], shim)
    end
    name! = Symbol(name, :!)
    inp_fun = lookup_function(shim.modules, name!)
    oop_fun = lookup_function(shim.modules, name)
    if inp_fun != nothing && oop_fun != nothing
        return DualMethodShim(name, inp_fun, oop_fun, shim)
    elseif inp_fun != nothing
        return MethodShim(name, inp_fun, shim)
    elseif oop_fun != nothing
        return MethodShim(name, oop_fun, shim)
    else
        return PyBase.__getattr__(shim.self, name)
    end
end

function PyBase.__dir__(shim::Shim)
    member_names = PyBase.__dir__(shim.self)
    append!(member_names, String.(keys(shim.methods)))
    append!(member_names, vcat(PyBase.__dir__.(shim.modules)...))
    return member_names
end

end  # module


text:
#AbstractTensor
function LA.norm(v::AbstractTensor)
    n = sqrt(LA.dot(v,v))
    isreal(n) || error("norm should be real")
    return real(n)
end

function LA.rmul!(v::AbstractTensor,a)
    apply!(v, x -> x .= a .* x)
end

function LA.axpby!(a,v::AbstractTensor{<:Any,N},b,w::AbstractTensor{<:Any,N}) where {N}
    TO.tensoradd!(a,v,1:N,b,w,1:N)
end

function LA.axpy!(a,v::AbstractTensor{<:Any,N},w::AbstractTensor{<:Any,N}) where {N}
    LA.axpby!(a,v,1,w)
end

#DTensor
Base.fill!(a::DTensor, w) = (fill!(a.array, w); a)
function LA.mul!(w::DTensor,v::DTensor,a)
    DTensor(LA.mul!(w.array, v.array, a))
end

function LA.dot(v::T,w::T) where {T<:DTensor{S,N}} where {S,N}
    LA.dot(v.array,w.array)
end

#DASTensor
function Base.fill!(a::DASTensor, w)
    initwith!(a, (T,d...) -> fill(w,d...))
    a
end

function LA.mul!(w::DASTensor,v::DASTensor,a)
    kw, kv = keys(w), keys(v)
    for k in setdiff(kw,kv)
        delete!(kw.tensor, k)
    end
    for k in setdiff(kv,kw)
        w[k] = a .* v[k]
    end
    for k in intersect(kw,kv)
        copyto!(w[k], a .* v[k])
    end
    return w
end

function LA.dot(v::T,w::T) where {T<:DASTensor{S,N}} where {S,N}
    ks = intersect(keys(v),keys(w))
    result = zero(S)
    for k in ks
        result += LA.dot(v[k],w[k])
    end
    return result
end


text:
"""
 0 - NotSolved
 1 - Optimal
 2 - Infeasible
 3 - Unbounded
 4 - Time limit
 5 - Iteration limit
"""
const LPIP_NOT_SOLVED = 0
const LPIP_OPTIMAL = 1
const LPIP_INFEASIBLE = 2
const LPIP_DUAL_INFEASIBLE = 3
const LPIP_TIME_LIMIT = 4
const LPIP_ITERATION_LIMIT = 5

function interior_points(A::AbstractMatrix{T}, b::AbstractVector{T}, c::AbstractVector{T},
                         d::T, l::Int, params::Params) where T
    lpip_pb = LPIPLinearProblem{T}(A, b, c, d, l)
    return interior_points(lpip_pb, params)
end

function interior_points(lpip_pb::LPIPLinearProblem{T}, params::Params) where T
    print_header(params, lpip_pb)
    t0 = time() # Start the timer
    newton_system = NewtonSystem{T}(lpip_pb, params)
    # Interior points iteration
    for i in 1:params.max_iter
        # Optimality test
        check_optimality(lpip_pb, params) == LPIP_OPTIMAL && return Result(lpip_pb, LPIP_OPTIMAL, i, time() - t0)
        check_unbounded(lpip_pb, params) == LPIP_DUAL_INFEASIBLE && return Result(lpip_pb, LPIP_DUAL_INFEASIBLE, 0, time() - t0)
        check_infeasible(lpip_pb, params) == LPIP_INFEASIBLE && return Result(lpip_pb, LPIP_INFEASIBLE, 0, time() - t0)
        # Solve the system and fill newton directions
        solve_kkt(newton_system, lpip_pb, params)
        # Update x, s, p
        update_lpip_pb_vars!(lpip_pb.variables.x, lpip_pb.variables.s, lpip_pb.variables.p,
                             newton_system.d_result, params.alpha, lpip_pb.n, lpip_pb.m)
        # Check if time limit was reached
        check_time_limit(params.time_limit, t0) == LPIP_TIME_LIMIT && return Result(lpip_pb, LPIP_TIME_LIMIT, i, time() - t0)
        # Print result of the iteration
        print_evolution(params, lpip_pb, i, t0)
    end
    # Iteration limit
    return Result(lpip_pb, LPIP_ITERATION_LIMIT, params.max_iter, time() - t0)
end

function check_optimality(lpip_pb::LPIPLinearProblem{T}, params::Params) where T
    if abs(dot(lpip_pb.variables.x, lpip_pb.variables.s)) < params.tol
        return LPIP_OPTIMAL
    end
    return LPIP_NOT_SOLVED
end

function check_time_limit(time_limit::Float64, t0::Float64)
    if time() - t0 > time_limit
        return LPIP_TIME_LIMIT # Time limit
    end
    return LPIP_NOT_SOLVED
end

function check_infeasible(lpip_pb::LPIPLinearProblem{T}, params::Params) where T
    if abs(dot(lpip_pb.b, lpip_pb.variables.p)) >= params.infeasible_unbounded_tol
        return LPIP_INFEASIBLE
    end
    return LPIP_NOT_SOLVED
end

function check_unbounded(lpip_pb::LPIPLinearProblem{T}, params::Params) where T
    if abs(dot(lpip_pb.c, lpip_pb.variables.x)) >= params.infeasible_unbounded_tol
        return LPIP_DUAL_INFEASIBLE
    end
    return LPIP_NOT_SOLVED
end

function update_lpip_pb_vars!(x::AbstractVector{T}, s::AbstractVector{T}, p::AbstractVector{T},
                              d::AbstractVector{T}, alpha::Float64, n::Int, m::Int) where T
    # Find step lenghts
    beta_primal = 1
    beta_dual = 1

    @inbounds for i in 1:n
        if d[i] <= 0
            if beta_primal > - x[i] / d[i]
                beta_primal = - x[i] / d[i]
            end
        end
        if d[n + m + i] <= 0
            if beta_dual > - s[i] / d[n + m + i]
                beta_dual = - s[i] / d[n + m + i]
            end
        end
    end

    alpha_beta_primal = alpha * beta_primal
    alpha_beta_dual = alpha * beta_dual

    @inbounds  for i in 1:n
        x[i] += alpha_beta_primal*d[i]
        s[i] += alpha_beta_dual*d[n + m + i]
    end
    @inbounds for i in 1:m
        p[i] += alpha_beta_dual*d[n + i]
    end
    return
end