text:
module XYZ

using Parameters

export load_xyz, natoms, nframes, positions, atomnames

"""
    load_xyz(f::String)

Load a xyz trajectory from file `f`.
"""
function load_xyz(f::String)
    io = open(f)
    load_xyz(io)
end

"""
    load_xyz(io::IO)

Load a xyz trajectory from stream `io`.
"""
function load_xyz(io::IO)
    File(io)
end

"""
    @with_kw struct File

Stores information about a xyz trajectory file.
"""
@with_kw struct File
    io::IO
    natoms::Int64
    nframes::Int64
    posbytes::Array{Int64,1}
end

"""
    File(io::IO)

Construct a [`XYZ.File`](@ref) object from an IO stream `io`.
"""
function File(io::IO)
    loader = Loader(io)
    File(
        io=io,
        natoms=natoms(loader),
        nframes=nframes(loader),
        posbytes=posbytes(loader),
        )
end

"""
    iostream(f::File)

Get the [`IOStream`](@ref) associated with the [`XYZ.File`](@ref) object.
"""
iostream(f::File) = f.io

"""
    natoms(f::File)

Get the number of atoms.
"""
natoms(f::File) = f.natoms

"""
    nframes(f::File)

Get the number of frames.
"""
nframes(f::File) = f.nframes

#="""
    atomnames(f::File)

Get all atom names, the topology, of a frame.
"""
atomnames(f::File) = f.atomnames =#

"""
    posbytes(f::File)

Get the position of each frame in a Array{Int64,1}.
"""
posbytes(f::File) = f.posbytes

"""
    Base.eltype(::Type{File})

[`XYZ.File`](@ref) objects are iterators over [`XYZ.Frame`](@ref) objects.
"""
Base.eltype(::Type{File}) = Frame

function Base.getindex(f::File, i::Int64)
    1 <= i <= f.nframes || throw(BoundsError(f, i))
    return Frame(f, i)
end
Base.getindex(f::File, i::Number) = f[convert(Int64, i)]
Base.getindex(f::File, I) = [f[i] for i in I]
Base.firstindex(f::File) = 1
Base.lastindex(f::File) = f.nframes
Base.length(f::File) = f.nframes

function Base.iterate(f::File, frame::Int64=1)
    if frame > nframes(f)
        return nothing
    else
        return Frame(f, frame), frame + 1
    end
end

"""
    @with_kw struct Loader

Stores information from the xyz trajectory file pre-loading.
"""
@with_kw struct Loader
    nframes::Int64
    firststep::Int64
    laststep::Int64
    natoms::Int64
    posbytes::Array{Int64,1}
end

"""
    loader(io::IO)

Construct a [`XYZ.Loader`](@ref) object from an [`IOStream`](@ref).
"""
function Loader(io::IO)
    firststep = 1
    natoms = parse(Int64,readline(io))          # First block line in xyz file
    readline(io)                                # Skip commentary line
    posbytes = Int64[position(io)]              # Add line at which coords of 1st frame start
    for iat=1:natoms                            # Same atoms in different frames so only done in 1st
        l = readline(io)
    end
    while !eof(io)
        readline(io)                            # Skip first lines
        readline(io)
        append!(posbytes,position(io))
        for iat=1:natoms
            readline(io)
        end
    end
    nframes = length(posbytes)
    laststep = nframes

    Loader(
        nframes=nframes,
        firststep=firststep,
        laststep=laststep,
        natoms=natoms,
        posbytes=posbytes
        )
end

"""
    natoms(h::Loader)

Get the number of atoms.
"""
natoms(h::Loader)::Int64 = h.natoms

"""
    nframes(h::Loader)

Get the number of frames.
"""
nframes(h::Loader)::Int64 = h.nframes

#="""
    atomnames(h::Loader)

Get all atom names, the topology, of a frame.
"""
atomnames(h::Loader)::Array{String,1} = h.atomnames =#

"""
    posbytes(h::Loader)

Get the position of each frame in a Array{Int64,1}.
"""
posbytes(h::Loader)::Array{Int64,1} = h.posbytes

"""
    seekframe(f::File, index::Int64)

Move the file's [`IOStream`](@ref) to the position of the indicated frame.
"""
function seekframe(f::File, index::Int64)
    1 <= index <= f.nframes || throw(BoundsError(f, index))
    pos = posbytes(f)[index]
    seek(f.io, pos)
end

"""
    @with_kw struct Frame

Stores positions and labels.
"""
@with_kw struct Frame
    positions::Array{Float64,2}
    atomnames::Array{String,2}
end

"""
    Frame(f::File, index::Int64)

Construct a [`DCD.Frame`](@ref) object from a [`DCD.File`](@ref) `f` with the specified `index`.
"""
function Frame(f::File, index::Int64)
    seekframe(f, index)
    io = iostream(f)
    positions = Array{Float64,2}(undef, 3, natoms(f))
    atomnames = Array{String,2}(undef, 1, natoms(f))
    for iatom in 1:natoms(f)
        line = split(readline(io))[1:end]
        atomnames[1, iatom] = string(line[1])
        for dim in 2:4
            positions[dim-1, iatom] = parse(Float64,line[dim])
        end
    end

    Frame(
        positions=positions,
        atomnames=atomnames
        )
end

"""
    positions(f::Frame)

Get the current positions.
"""
positions(f::Frame) = f.positions

"""
    atomnames(f::Frame)

Get the current atom list
"""
atomnames(f::Frame) = f.atomnames

end # module


text:
#!/usr/bin/env julia
# -*- coding: utf-8 -*-

# ============================================================================
# ReMorse - Morse code encode/decode module for Julia
# Copyright (C) 2019 by Ralf Kilian
# Distributed under the MIT License (https://opensource.org/licenses/MIT)
#
# GitHub: https://github.com/urbanware-org/remorse
# GitLab: https://gitlab.com/urbanware-org/remorse
# ============================================================================

__version__ = "1.0.0"

MORSE_ALPHABET = Dict([
            ("a", "·−"), ("b", "−···"), ("c", "−·−·"), ("d", "−··"),
            ("e", "·"), ("f", "··−·"), ("g", "−−·"), ("h", "····"),
            ("i", "··"), ("j", "·−−−"), ("k", "−·−"), ("l", "·−··"),
            ("m", "−−"), ("n", "−·"), ("o", "−−−"), ("p", "·−−·"),
            ("q", "−−·−"), ("r", "·−·"), ("s", "···"), ("t", "−"),
            ("u", "··−"), ("v", "···−"), ("w", "·−−"), ("x", "−··−"),
            ("y", "−·−−"), ("z", "−−··"), ("1", "·−−−−"), ("2", "··−−−"),
            ("3", "···−−"), ("4", "····−"), ("5", "·····"), ("6", "−····"),
            ("7", "−−···"), ("8", "−−−··"), ("9", "−−−−·"), ("0", "−−−−−")])

function get_version()
    """
        Return the version of this module.
    """
    return __version__
end

function string2morse(string)
    """
        Convert (encode) a string into Morse code.
    """
    output = ""

    while occursin("  ", string)
        string = replace(string, "  " => " ")
    end

    for char in lowercase(strip(string))
        if "$char" == " "
            output = "$output   "
            continue
        end
        try
            char = MORSE_ALPHABET["$char"]
            output = "$output $char"
        catch
            continue
        end
    end

    return strip(output)
end

function morse2string(morse_code)
    """
        Convert (decode) Morse code into a string.
    """
    output = ""

    while occursin("   ", morse_code)
        morse_code = replace(morse_code, "   " => "  ")
    end

    morse_code = replace(morse_code, "." => "·")
    morse_code = replace(morse_code, "-" => "−")
    morse_code = replace(morse_code, "_" => "−")
    morse_code = replace(morse_code, "  " => " ~ ")

    morse = Dict(value => key for (key, value) in MORSE_ALPHABET)
    chars = split(morse_code)
    for char in chars
        if "$char" == "~"
            output = "$output "
            continue
        end
        try
            char = morse["$char"]
            output = "$output$char"
        catch
            continue
        end
    end

    return strip(output)
end

# EOF

ext: jl

max_stars_repo_name: urbanware-org/remorse

max_issues_repo_name: urbanware-org/remorse

max_forks_repo_name: urbanware-org/remorse


text:
type Fourier1d <: SuperRes #1D Static model
    freqs :: Vector{Int}
    filter :: Vector{Float64}
    x_max :: Float64
    approx_grid :: Vector{Float64}
    bounds :: Tuple{Vector{Float64},Vector{Float64}}
    function Fourier1d(f_c, x_max, filter = ones(2*f_c+1), n_approx = 10*f_c+1)
        # step to get rid of the unused frequencies
        ind = find(filter)
        freqs = -f_c:f_c
        filter = filter[ind]
        freqs = freqs[ind]
        new(freqs, filter, x_max,
            linspace(0, x_max, n_approx),
            ([0.0], [x_max]))
    end
end

function setBounds(model :: Fourier1d, bounds)
    model.bounds = bounds
    model.approx_grid = linspace(bounds[1][1], bounds[2][1], length(model.approx_grid))
end

function psi(model :: Fourier1d, theta :: Vector{Float64})
    # This function computes the direct problem for a single point theta
    psi_cpx =vec(Complex128[model.filter[k] * exp(-2im * pi * model.freqs[k] / model.x_max* theta[1])                                   for k in eachindex(model.freqs)])
    return [real(psi_cpx); imag(psi_cpx)]
end

function dpsi(model :: Fourier1d, theta :: Vector{Float64})
    # This function computes the gradient of psi
    dx = vec(Complex128[-model.filter[k] * model.freqs[k]/model.x_max* 2im * pi *
                        exp(-2im * pi * model.freqs[k] / model.x_max * theta[1]) for k in eachindex(model.freqs)])
    return reshape([real(dx); imag(dx)], 2*length(model.freqs), 1)
end

function getStartingPoint(model :: Fourier1d, v :: Vector{Float64})
    # This function gets an initial value for the location
    vals = Float64[dot(v,psi(model, [x])) for x = model.approx_grid]
    ind = indmin(vals);
    return [model.approx_grid[ind]]
end

parameterBounds(model :: Fourier1d) = model.bounds # Bounds for the parameters
dim(model :: Fourier1d) = 1

type DynamicFourier1d <: DynamicSuperRes #1D Space-time model
    static :: Fourier1d
    times :: Vector{Float64}
    v_max :: Float64
    grid_v :: Vector{Float64}
    bounds :: Tuple{Vector{Float64},Vector{Float64}}
    DynamicFourier1d(static, v_max, tau, K, num_v = 20) = new(static,
                                                              linspace(-tau*K, tau*K, 2*K+1),
                                                              v_max,
                                                              linspace(-v_max, v_max, num_v),
                                                              ([0; -v_max], [static.x_max; v_max]))
end
function setBounds(model :: DynamicFourier1d, bounds)
    setBounds(model.static, (bounds[1][1], bounds[2][1]))
    model.bounds = bounds
    model.grid_v = linspace(bounds[1][2], bounds[2][2], length(grid_v))
end

function getStartingPoint(model :: DynamicFourier1d, v :: Vector{Float64})
    # This function gets an initial value for the location
    vals = Float64[dot(v,psi(model, [x; vel])) for x = model.static.approx_grid, vel = model.grid_v]
    ind = indmin(vals);
    i,j = ind2sub(vals, ind)
    return [model.static.approx_grid[i]; model.grid_v[j]]
end

parameterBounds(model :: DynamicFourier1d) = model.bounds


text:
### derivatives-type.jl
#
# Copyright (C) 2016 Mosè Giordano.
#
# Maintainer: Mosè Giordano <mose AT gnu DOT org>
# Keywords: uncertainty, error propagation, physics
#
# This file is a part of Measurements.jl.
#
# License is MIT "Expat".
#
### Commentary:
#
# This file containes the definition of Derivatives type.  This is borrowed from
# Base.ImmutableDict type (see base/dict.jl in Julia source code), introduced in
# Julia 0.5.
#
### Code:

import Base: getindex, get, start, next, done, similar, length

immutable Derivatives{K, V} <: Associative{K,V}
    parent::Derivatives{K, V}
    key::K
    value::V
    Derivatives() = new() # represents an empty dictionary
    Derivatives(key, value) = (empty = new(); new(empty, key, value))
    Derivatives(parent::Derivatives, key, value) = new(parent, key, value)
end

Derivatives{K,V}(KV::Pair{K,V}) = Derivatives{K,V}(KV[1], KV[2])
Derivatives{K,V}(t::Derivatives{K,V}, KV::Pair) = Derivatives{K,V}(t, KV[1], KV[2])

function getindex(dict::Derivatives, key)
    while isdefined(dict, :parent)
        isequal(dict.key, key) && return dict.value
        dict = dict.parent
    end
    throw(KeyError(key))
end
function get(dict::Derivatives, key, default)
    while isdefined(dict, :parent)
        isequal(dict.key, key) && return dict.value
        dict = dict.parent
    end
    return default
end

# this actually defines reverse iteration (e.g. it should not be used for merge/copy/filter type operations)
start(t::Derivatives) = t
next{K,V}(::Derivatives{K,V}, t) = (Pair{K,V}(t.key, t.value), t.parent)
done(::Derivatives, t) = !isdefined(t, :parent)
function similar(t::Derivatives)
    while isdefined(t, :parent)
        t = t.parent
    end
    return t
end
length(t::Derivatives) = count(x->true, t)


text:
## Constants for testing

#for the genNewsvendorFunctions tests
const cSols = [8, 4, 4, 2, 4, 5, 9, 7, 5, 7, 8, 8, 3, 3, 9, 2, 8, 7, 9, 7]
const cCosts = [8.599038144844988, 1.5298942577297954, 1.3616845549380314, 0.9034083219842073, 1.4783011670220971, 2.057697717608458, 26.64083414920856, 2.2766748472183016, 2.011619605755156, 2.639757261643404, 6.694819245413914, 7.294936527821754, 0.9948002857800782, 1.0058771604635373, 14.11158547904508, 0.7559462763167646, 9.184175991907422, 4.180172295358156, 108.29380788495317, 3.756144725078732]

max_stars_repo_name: CausalML/DataPooling

max_issues_repo_name: CausalML/DataPooling

max_forks_repo_name: CausalML/DataPooling


text:
# This file is a part of Julia. License is MIT: http://julialang.org/license

"""
    LibGit2.GitRepo(path::AbstractString)

Opens a git repository at `path`.
"""
function GitRepo(path::AbstractString)
    repo_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
    err = ccall((:git_repository_open, :libgit2), Cint,
                (Ptr{Ptr{Void}}, Cstring), repo_ptr_ptr, path)
    if err != Int(Error.GIT_OK)
        if repo_ptr_ptr[] != C_NULL
            close(GitRepo(repo_ptr_ptr[]))
        end
        throw(Error.GitError(err))
    end
    return GitRepo(repo_ptr_ptr[])
end

function GitRepoExt(path::AbstractString, flags::Cuint = Cuint(Consts.REPOSITORY_OPEN_DEFAULT))
    separator = @static is_windows() ? ";" : ":"
    repo_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
    err = ccall((:git_repository_open_ext, :libgit2), Cint,
                (Ptr{Ptr{Void}}, Cstring, Cuint, Cstring),
                 repo_ptr_ptr, path, flags, separator)
    if err != Int(Error.GIT_OK)
        if repo_ptr_ptr[] != C_NULL
            close(GitRepo(repo_ptr_ptr[]))
        end
        throw(Error.GitError(err))
    end
    return GitRepo(repo_ptr_ptr[])
end

function cleanup(r::GitRepo)
    if r.ptr != C_NULL
        ccall((:git_repository__cleanup, :libgit2), Void, (Ptr{Void},), r.ptr)
    end
end

function init(path::AbstractString, bare::Bool=false)
    repo_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
    @check ccall((:git_repository_init, :libgit2), Cint,
                (Ptr{Ptr{Void}}, Cstring, Cuint), repo_ptr_ptr, path, bare)
    return GitRepo(repo_ptr_ptr[])
end

function head_oid(repo::GitRepo)
    head_ref = head(repo)
    try
        return GitHash(head_ref)
    finally
        close(head_ref)
    end
end

function headname(repo::GitRepo)
    with(head(repo)) do href
        if isattached(repo)
            shortname(href)
        else
            "(detached from $(string(GitHash(href))[1:7]))"
        end
    end
end

function isbare(repo::GitRepo)
    return ccall((:git_repository_is_bare, :libgit2), Cint, (Ptr{Void},), repo.ptr) == 1
end

function isattached(repo::GitRepo)
    ccall((:git_repository_head_detached, :libgit2), Cint, (Ptr{Void},), repo.ptr) != 1
end

@doc """
    GitObject(repo::GitRepo, hash::AbstractGitHash)
    GitObject(repo::GitRepo, spec::AbstractString)

Return the specified object (`GitCommit`, `GitBlob`, `GitTree` or `GitTag`) from `repo`
specified by `hash`/`spec`.

- `hash` is a full (`GitHash`) or partial (`GitShortHash`) hash.
- `spec` is a textual specification: see https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for a full list.
""" GitObject

for T in (:GitCommit, :GitBlob, :GitTree, :GitTag)
    @eval @doc $"""
    $T(repo::GitRepo, hash::AbstractGitHash)
    $T(repo::GitRepo, spec::AbstractString)

Return a `$T` object from `repo` specified by `hash`/`spec`.

- `hash` is a full (`GitHash`) or partial (`GitShortHash`) hash.
- `spec` is a textual specification: see https://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for a full list.
""" $T
end

function (::Type{T}){T<:GitObject}(repo::GitRepo, spec::AbstractString)
    obj_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
    @check ccall((:git_revparse_single, :libgit2), Cint,
                 (Ptr{Ptr{Void}}, Ptr{Void}, Cstring), obj_ptr_ptr, repo.ptr, spec)
    return T(repo, obj_ptr_ptr[])
end

function (::Type{T}){T<:GitObject}(repo::GitRepo, oid::GitHash)
    oid_ptr  = Ref(oid)
    obj_ptr_ptr = Ref{Ptr{Void}}(C_NULL)

    @check ccall((:git_object_lookup, :libgit2), Cint,
                 (Ptr{Ptr{Void}}, Ptr{Void}, Ptr{GitHash}, Consts.OBJECT),
                 obj_ptr_ptr, repo.ptr, oid_ptr, Consts.OBJECT(T))

    return T(repo, obj_ptr_ptr[])
end
function (::Type{T}){T<:GitObject}(repo::GitRepo, oid::GitShortHash)
    oid_ptr  = Ref(oid.hash)
    obj_ptr_ptr = Ref{Ptr{Void}}(C_NULL)

    @check ccall((:git_object_lookup_prefix, :libgit2), Cint,
                 (Ptr{Ptr{Void}}, Ptr{Void}, Ptr{GitHash}, Csize_t, Consts.OBJECT),
                 obj_ptr_ptr, repo.ptr, oid_ptr, oid.len, Consts.OBJECT(T))

    return T(repo, obj_ptr_ptr[])
end

# TODO: deprecate this function
revparseid(repo::GitRepo, spec) = GitHash(GitUnknownObject(repo, spec))

"""
    LibGit2.gitdir(repo::GitRepo)

Returns the location of the "git" files of `repo`:

 - for normal repositories, this is the location of the `.git` folder.
 - for bare repositories, this is the location of the repository itself.

See also `workdir`, `path`
"""
function gitdir(repo::GitRepo)
    return unsafe_string(ccall((:git_repository_path, :libgit2), Cstring,
                        (Ptr{Void},), repo.ptr))
end

"""
    LibGit2.workdir(repo::GitRepo)

The location of the working directory of `repo`. This will throw an error for bare
repositories.

!!! note

    This will typically be the parent directory of `gitdir(repo)`, but can be different in
    some cases: e.g. if either the `core.worktree` configuration variable or the
    `GIT_WORK_TREE` environment variable is set.

See also `gitdir`, `path`
"""
function workdir(repo::GitRepo)
    sptr = ccall((:git_repository_workdir, :libgit2), Cstring,
                (Ptr{Void},), repo.ptr)
    sptr == C_NULL && throw(GitError(Error.Object, Error.ERROR, "No working directory found."))
    return unsafe_string(sptr)
end

"""
    LibGit2.path(repo::GitRepo)

The base file path of the repository `repo`.

 - for normal repositories, this will typically be the parent directory of the ".git"
   directory (note: this may be different than the working directory, see `workdir` for
   more details).
 - for bare repositories, this is the location of the "git" files.

See also `gitdir`, `workdir`.
"""
function path(repo::GitRepo)
    d = gitdir(repo)
    if isdirpath(d)
        d = dirname(d) # strip trailing separator
    end
    if isbare(repo)
        return d
    else
        parent, base = splitdir(d)
        return base == ".git" ? parent : d
    end
end

"""
    peel([T,] obj::GitObject)

Recursively peel `obj` until an object of type `T` is obtained. If no `T` is provided,
then `obj` will be peeled until the type changes.

- A `GitTag` will be peeled to the object it references.
- A `GitCommit` will be peeled to a `GitTree`.
"""
function peel{T<:GitObject}(::Type{T}, obj::GitObject)
    new_ptr_ptr = Ref{Ptr{Void}}(C_NULL)

    @check ccall((:git_object_peel, :libgit2), Cint,
                (Ptr{Ptr{Void}}, Ptr{Void}, Cint), new_ptr_ptr, obj.ptr, Consts.OBJECT(T))

    return T(obj.repo, new_ptr_ptr[])
end
peel(obj::GitObject) = peel(GitObject, obj)

function checkout_tree(repo::GitRepo, obj::GitObject;
                       options::CheckoutOptions = CheckoutOptions())
    @check ccall((:git_checkout_tree, :libgit2), Cint,
                 (Ptr{Void}, Ptr{Void}, Ptr{CheckoutOptions}),
                 repo.ptr, obj.ptr, Ref(options))
end

function checkout_index(repo::GitRepo, idx::Nullable{GitIndex} = Nullable{GitIndex}();
                        options::CheckoutOptions = CheckoutOptions())
    @check ccall((:git_checkout_index, :libgit2), Cint,
                 (Ptr{Void}, Ptr{Void}, Ptr{CheckoutOptions}),
                 repo.ptr,
                 isnull(idx) ? C_NULL : Base.get(idx).ptr,
                 Ref(options))
end

function checkout_head(repo::GitRepo; options::CheckoutOptions = CheckoutOptions())
    @check ccall((:git_checkout_head, :libgit2), Cint,
                 (Ptr{Void}, Ptr{CheckoutOptions}),
                 repo.ptr, Ref(options))
end

"""Updates some entries, determined by the `pathspecs`, in the index from the target commit tree."""
function reset!{T<:AbstractString, S<:GitObject}(repo::GitRepo, obj::Nullable{S}, pathspecs::T...)
    @check ccall((:git_reset_default, :libgit2), Cint,
                 (Ptr{Void}, Ptr{Void}, Ptr{StrArrayStruct}),
                 repo.ptr,
                 isnull(obj) ? C_NULL: Base.get(obj).ptr,
                 collect(pathspecs))
    return head_oid(repo)
end

"""Sets the current head to the specified commit oid and optionally resets the index and working tree to match."""
function reset!(repo::GitRepo, obj::GitObject, mode::Cint;
               checkout_opts::CheckoutOptions = CheckoutOptions())
    @check ccall((:git_reset, :libgit2), Cint,
                 (Ptr{Void}, Ptr{Void}, Cint, Ptr{CheckoutOptions}),
                  repo.ptr, obj.ptr, mode, Ref(checkout_opts))
    return head_oid(repo)
end

function clone(repo_url::AbstractString, repo_path::AbstractString,
               clone_opts::CloneOptions)
    clone_opts_ref = Ref(clone_opts)
    repo_ptr_ptr = Ref{Ptr{Void}}(C_NULL)
    @check ccall((:git_clone, :libgit2), Cint,
            (Ptr{Ptr{Void}}, Cstring, Cstring, Ref{CloneOptions}),
            repo_ptr_ptr, repo_url, repo_path, clone_opts_ref)
    return GitRepo(repo_ptr_ptr[])
end

function fetchheads(repo::GitRepo)
    fhr = Ref{Vector{FetchHead}}(FetchHead[])
    ffcb = fetchhead_foreach_cb()
    @check ccall((:git_repository_fetchhead_foreach, :libgit2), Cint,
                  (Ptr{Void}, Ptr{Void}, Ptr{Void}),
                   repo.ptr, ffcb, fhr)
    return fhr[]
end

"""
    LibGit2.remotes(repo::GitRepo)

Returns a vector of the names of the remotes of `repo`.
"""
function remotes(repo::GitRepo)
    sa_ref = Ref(StrArrayStruct())
    @check ccall((:git_remote_list, :libgit2), Cint,
                  (Ptr{StrArrayStruct}, Ptr{Void}), sa_ref, repo.ptr)
    res = convert(Vector{String}, sa_ref[])
    free(sa_ref)
    return res
end

function Base.show(io::IO, repo::GitRepo)
    print(io, "LibGit2.GitRepo(")
    show(io, path(repo))
    print(io, ")")
end

max_stars_repo_name: oxinabox/julia

max_issues_repo_name: oxinabox/julia

max_forks_repo_name: oxinabox/julia


text:
using TextAnalysis
using Word2Vec
include("x1 io.jl")
include("x2 preprocessing.jl")
include("x3 aspect_aware_word_embedding.jl")

function mergeWithStrongLinks!(tokIDGroups::Vector{Vector{Int32}}, vocab::Dict{String,Int32}, strongLinkForest::Dict{IDPair,IDPostfixes})
    # insert strong-link phrases into vocab
    numStrongLinks = 0
    for (idPair, postfixes) in strongLinkForest
        numStrongLinks += length(postfixes)
    end
    println("numStrongLinks: ", numStrongLinks)
    numOldPhrases = length(vocab)
    phrases = Vector{String}(undef, numOldPhrases + numStrongLinks)
    for (phrase, phraseID) in vocab
        phrases[phraseID] = phrase
    end
    strongLinkIDs = Dict{Vector{Int32},Int32}()
    for (idPair, postfixes) in strongLinkForest
        prefix = phrases[idPair[1]] * "-" * phrases[idPair[2]]
        for postfix in postfixes
            phrase = prefix
            for id in postfix
                phrase *= "-" * phrases[id]
            end
            phraseID = length(vocab) + 1
            vocab[phrase] = phraseID
            phrases[phraseID] = phrase
            strongLinkIDs[[idPair...,postfix...]] = phraseID
        end
    end

    # scan through token groups to find occurence of strong-link phrases and convert them to the new entries of vocab
    numGroups = length(tokIDGroups)
    for (groupID, tokIDGroup) in enumerate(tokIDGroups)
        groupSize = length(tokIDGroup)
        strongLinksDetected = Dict{Int32,Int32}()
        for i in 1:groupSize - 1
            idPair = (tokIDGroup[i], tokIDGroup[i + 1])
            if haskey(strongLinkForest, idPair)
                postfixes = strongLinkForest[idPair]
                for postfix in postfixes
                    if i + 1 + length(postfix) > groupSize
                        continue
                    end
                    if tokIDGroup[i + 2:i + 1 + length(postfix)] == postfix
                        phraseSize = 2 + length(postfix)
                        if haskey(strongLinksDetected, i)
                            if strongLinksDetected[i] > phraseSize
                                continue
                            end
                        end
                        strongLinksDetected[i] = phraseSize
                    end
                end
            end
        end
        phraseStarts = [i for i in 1:groupSize]
        for (phrasePos, phraseSize) in strongLinksDetected
            if phraseStarts[phrasePos] != phrasePos
                continue
            end
            if phraseStarts[phrasePos + phraseSize - 1] != phrasePos + phraseSize - 1
                continue
            end
            phraseStarts[phrasePos:phrasePos + phraseSize - 1] .= phrasePos
        end
        newTokIDGroup = Vector{Int32}()
        for i in 1:groupSize
            if phraseStarts[i] != i
                continue
            end
            phraseEnd = i
            for j in i + 1:groupSize
                if phraseStarts[j] != i
                    break
                end
                phraseEnd = j
            end
            if phraseEnd == i
                push!(newTokIDGroup, tokIDGroup[i])
            else
                push!(newTokIDGroup, strongLinkIDs[tokIDGroup[i:phraseEnd]])
            end
        end
        tokIDGroups[groupID] = newTokIDGroup
    end
end

function word2Phrase!(tokIDGroups::Vector{Vector{Int32}}, vocab::Dict{String,Int32}, maxIter::Int, minFreq::Int)
    # scan through tokIDGroups to build unigram freqs and bigram freqs
    numPhrases = length(vocab)
    phrases = Vector{String}(undef, numPhrases)
    unigramFreqs = Vector{Int32}(undef, numPhrases)
    stopWordIDs = Set{Int32}()
    for (phrase, phraseID) in vocab
        phrases[phraseID] = phrase
        unigramFreqs[phraseID] = 0
        if phrase in stopWords
            push!(stopWordIDs, phraseID)
        end
    end
    bigramFreqs = Dict{Tuple{Int32,Int32},Int32}()
    bigramOccurrences = Dict{Tuple{Int32,Int32},Set{Int32}}()
    for (groupID, tokIDGroup) in enumerate(tokIDGroups)
        groupSize = length(tokIDGroup)
        for (i, tokID) in enumerate(tokIDGroup)
            unigramFreqs[tokID] += 1
            if i + 1 <= groupSize
                bigram = (tokID, tokIDGroup[i + 1])
                if bigram[1] in stopWordIDs || bigram[2] in stopWordIDs
                    continue
                end
                if haskey(bigramFreqs, bigram)
                    bigramFreqs[bigram] += 1
                    push!(bigramOccurrences[bigram], groupID)
                else
                    bigramFreqs[bigram] = 1
                    bigramOccurrences[bigram] = Set{Int32}([groupID])
                end
            end
        end
    end

    for iter in 1:maxIter
        if iter % 1000 == 0
            println("word2phrase iter $iter")
        end

        bestScore = 0.0
        bestBigram = (0, 0)
        for (bigram, freq) in bigramFreqs
            if freq <= minFreq
                continue
            end
            score = (freq - minFreq) / (unigramFreqs[bigram[1]] * unigramFreqs[bigram[2]])
            if score > bestScore
                bestScore = score
                bestBigram = bigram
            end
        end
        if bestScore == 0.0
            break
        end

        newPhrase = phrases[bestBigram[1]] * "-" * phrases[bestBigram[2]]
        newPhraseID = if !haskey(vocab, newPhrase)
            push!(phrases, newPhrase)
            length(phrases)
        else
            vocab[newPhrase]
        end
        vocab[newPhrase] = newPhraseID

        push!(unigramFreqs, 0)
        occurrences = bigramOccurrences[bestBigram]
        for groupID in occurrences
            # update group in tokIDGroups
            oldTokIDGroup = tokIDGroups[groupID]
            newTokIDGroup = Vector{Int32}()
            oldGroupSize = length(oldTokIDGroup)
            i = 1
            while i <= oldGroupSize
                if oldTokIDGroup[i] == bestBigram[1] && i + 1 <= oldGroupSize
                    if oldTokIDGroup[i + 1] == bestBigram[2]
                        push!(newTokIDGroup, newPhraseID)
                        i += 2
                    else
                        push!(newTokIDGroup, oldTokIDGroup[i])
                        i += 1
                    end
                else
                    push!(newTokIDGroup, oldTokIDGroup[i])
                    i += 1
                end
            end
            tokIDGroups[groupID] = newTokIDGroup

            # subtract freqs from unigramFreqs and bigramFreqs
            oldBigramSet = Set{Tuple{Int32,Int32}}()
            for (i, tokID) in enumerate(oldTokIDGroup)
                unigramFreqs[tokID] -= 1
                if i < oldGroupSize
                    bigram = (tokID, oldTokIDGroup[i + 1])
                    if bigram[1] in stopWordIDs || bigram[2] in stopWordIDs
                        continue
                    end
                    bigramFreqs[bigram] -= 1
                    push!(oldBigramSet, bigram)
                end
            end

            # add freqs to unigramFreqs and bigramFreqs
            newGroupSize = length(newTokIDGroup)
            newBigramSet = Set{Tuple{Int32,Int32}}()
            for (i, tokID) in enumerate(newTokIDGroup)
                unigramFreqs[tokID] += 1
                if i < newGroupSize
                    bigram = (tokID, newTokIDGroup[i + 1])
                    if bigram[1] in stopWordIDs || bigram[2] in stopWordIDs
                        continue
                    end
                    if haskey(bigramFreqs, bigram)
                        bigramFreqs[bigram] += 1
                    else
                        bigramFreqs[bigram] = 1
                    end
                    push!(newBigramSet, bigram)
                end
            end

            # removed dispearing bigram occurences
            for bigram in oldBigramSet
                if bigram ∉ newBigramSet
                    delete!(bigramOccurrences[bigram], groupID)
                end
            end

            # insert new bigram occurrences
            for bigram in newBigramSet
                if bigram ∉ oldBigramSet
                    if haskey(bigramOccurrences, bigram)
                        push!(bigramOccurrences[bigram], groupID)
                    else
                        bigramOccurrences[bigram] = Set{Int32}([groupID])
                    end
                end
            end
        end
    end
end

function detectPhrases(titles::Vector{String}, fileName::String)
    numCPUs = length(Sys.cpu_info())
    jobs = Channel{Tuple{Int,Int}}(numCPUs)
    Segments = Vector{Tuple{Int,Int}}
    TokenGroups = Vector{Vector{StemmedToken}}
    SegmentedTokenGroups = Tuple{Segments, TokenGroups}
    results = Channel{SegmentedTokenGroups}()
    function runJob(iCPU::Int)
        stemmer = Stemmer("english")
        mySegments = Segments()
        myTokGroups = TokenGroups()
        for job in jobs
            push!(mySegments, job)
            for title in titles[job[1]:job[2]]
                toksOfTitle = unhyphenAndStem(stemmer, lowercase.(tokenize(title)))
                push!(myTokGroups, toksOfTitle)
            end
        end
        put!(results, (mySegments, myTokGroups))
        # println("$iCPU done")
    end
    function makeJobs(batchSize::Int)
        n = length(titles)
        for i in 1:batchSize:n
            put!(jobs, (i, min(i + batchSize - 1, n)))
        end
    end
    bind(jobs, @async makeJobs(1000))
    for iCPU in 1:numCPUs
        Threads.@spawn runJob(iCPU)
    end
    tokGroups = TokenGroups(undef, length(titles))
    for iCPU in 1:numCPUs
        segmentedTokenGroups = take!(results)
        segments = segmentedTokenGroups[1]
        offset = 1
        for segment in segments
            tokGroups[segment[1]:segment[2]] = segmentedTokenGroups[2][offset:offset+segment[2]-segment[1]]
            offset += segment[2]-segment[1] + 1
        end
    end

    vocab, strongLinkForest, tokIDGroups = getVocab(tokGroups)
    println("old vocab size: ", length(vocab))
    mergeWithStrongLinks!(tokIDGroups, vocab, strongLinkForest)
    println("new vocab size: ", length(vocab))
    word2Phrase!(tokIDGroups, vocab, 30000, 5)
    println("vocab size after word2phrase: ", length(vocab))
    saveTrainingFile(fileName, tokIDGroups, vocab)
end

nipsTitles = loadTitles("DualAspectTopicRepresentation/data/NIPS.txt")
detectPhrases(nipsTitles, "DualAspectTopicRepresentation/workspace/NIPS.awe.training.txt")
trainWordEmbedding(
    "DualAspectTopicRepresentation/workspace/NIPS.awe.training.txt",
    "DualAspectTopicRepresentation/workspace/NIPS.awe.model.txt",
    200, 3)

max_stars_repo_path: src/02 train_embedding.jl

max_issues_repo_path: src/02 train_embedding.jl

max_forks_repo_path: src/02 train_embedding.jl


text:
using ProgressMeter

# glorot_uniform(dims...) = (rand(Float32, dims...) .- 0.5f0) .* sqrt(24.0f0/sum(dims))
# glorot_normal(dims...) = randn(Float32, dims...) .* sqrt(2.0f0/sum(dims))
#
# https://github.com/FluxML/Flux.jl/issues/442

_nfan(dims...) = prod(dims[1:end-2]) * sum(dims[end-1:end])
my_glorot_uniform(dims...) = (rand(Float32, dims...) .- 0.5f0) .* sqrt(24.0f0/_nfan(dims...))
myConv(args...; kwargs...) = Conv(args..., init=my_glorot_uniform; kwargs...)
myConvTranspose(args...; kwargs...) = ConvTranspose(args..., init=my_glorot_uniform; kwargs...)

function param_count(model)
    ps = Flux.params(model)
    res = 0
    for p in keys(ps.params.dict)
        res += prod(size(p))
    end
    res / 1000 / 1000
end

struct Flatten end

function (l::Flatten)(input)
    reshape(input, :, size(input, 4))
end

struct Sigmoid end
function (l::Sigmoid)(input)
    σ.(input)
end

struct ReLU end

function (l::ReLU)(input)
    relu.(input)
end

##############################
## MNIST models
##############################

function get_LeNet5()
    Chain(myConv((3,3), 1=>32, relu, pad=(1,1)),
          MaxPool((2,2)),
          myConv((3,3), 32=>64, relu, pad=(1,1)),
          MaxPool((2,2)),
          Flatten(),
          Dense(7 * 7 * 64, 200, relu),
          Dense(200, 10),
          # softmax,
          ) |> gpu
end

function get_Madry_model()
    Chain(myConv((5,5), 1=>32, pad=(2,2), relu),
          MaxPool((2,2)),
          myConv((5,5), 32=>64, pad=(2,2), relu),
          MaxPool((2,2)),
          Flatten(),
          Dense(7*7*64, 1024),
          Dense(1024, 10),
          # softmax,
          ) |> gpu
end

##############################
## MNIST AE models
##############################

function dense_AE()
    # FIXME why leakyrelu
    error("deprecated. replace anonymous functions")
    encoder = Chain(Flatten(),
                    Dense(28 * 28, 32, relu)) |> gpu
    decoder = Chain(Dense(32, 28 * 28),
                    x -> reshape(x, 28, 28, 1, :),
                    # FIXME use clamp?
                    # reshape(clamp.(x, 0, 1), 28, 28)
                    Sigmoid()) |> gpu
    Chain(encoder, decoder)
end

"""From https://discourse.julialang.org/t/upsampling-in-flux-jl/25919/3
"""
function upsample(x)
    ratio = (2, 2, 1, 1)
    (h, w, c, n) = size(x)
    y = similar(x, (1, ratio[1], 1, ratio[2], 1, 1))
    fill!(y, 1)
    z = reshape(x, (h, 1, w, 1, c, n))  .* y
    reshape(permutedims(z, (2,1,4,3,5,6)), size(x) .* ratio)
end

function CNN_AE()
    # FIXME padding='same'?
    encoder = Chain(myConv((3,3), 1=>16, pad=(1,1), relu),
                    # BatchNorm(16)
                    MaxPool((2,2)))
    decoder = Chain(myConv((3,3), 16=>16, pad=(1,1), relu),
                    upsample,
                    myConv((3,3), 16=>1, pad=(1,1)),
                    Sigmoid())
    Chain(encoder, decoder) |> gpu
end

function CNN2_AE()
    encoder = Chain(myConv((3,3), 1=>16, pad=(1,1), relu),
                    MaxPool((2,2)),
                    myConv((3,3), 16=>8, pad=(1,1), relu),
                    MaxPool((2,2)))
    decoder = Chain(myConv((3,3), 8=>8, pad=(1,1), relu),
                    upsample,
                    myConv((3,3), 8=>16, pad=(1,1), relu),
                    upsample,
                    myConv((3,3), 16=>1, pad=(1,1)),
                    Sigmoid())
    Chain(encoder, decoder) |> gpu
end

##############################
## CIFAR models
##############################

function get_CIFAR10_CNN_model()
    # DEPRECATED
    Chain(myConv((5,5), 3=>16, relu),
          MaxPool((2,2)),
          myConv((5,5), 16=>8, relu),
          MaxPool((2,2)),
          Flatten(),
          Dense(200, 10),
          # softmax
          ) |> gpu
end

struct ResidualBlock
  conv_layers
  norm_layers
  shortcut
end
Flux.@treelike ResidualBlock

function (block::ResidualBlock)(input)
    local value = copy.(input)
    for i in 1:length(block.conv_layers)-1
        value = relu.((block.norm_layers[i])((block.conv_layers[i])(value)))
    end
    relu.(((block.norm_layers[end])((block.conv_layers[end])(value)))
          + block.shortcut(input))
end

"""Identity block, consisting of Conv-BN-Conv-BN + input
"""
function identity_block(kernel_size, filters)
    # conv BN RELU
    local conv_layers = []
    local norm_layers = []
    push!(conv_layers, myConv(kernel_size, filters, pad=1, stride=1))
    push!(conv_layers, myConv(kernel_size, filters, pad=1, stride=1))
    push!(norm_layers, BatchNorm(filters[2]))
    push!(norm_layers, BatchNorm(filters[2]))
    ResidualBlock(Tuple(conv_layers), Tuple(norm_layers), identity)
end

function conv_block(kernel_size, filters, stride)
    local conv_layers = []
    local norm_layers = []
    # half the feature map
    push!(conv_layers, myConv(kernel_size, filters[1]=>filters[2], pad=1, stride=stride))
    push!(conv_layers, myConv(kernel_size, filters[2]=>filters[2], pad=1))
    push!(norm_layers, BatchNorm(filters[2]))
    push!(norm_layers, BatchNorm(filters[2]))
    shortcut = Chain(myConv((1,1), filters,
                          pad = (0,0),
                          stride = stride),
                     BatchNorm(filters[2]))
    return ResidualBlock(Tuple(conv_layers), Tuple(norm_layers), shortcut)
end

function res_block(num_blocks, kernel_size, filters)
    local layers = []
    # conv1 = conv_block(kernel_size, filters, stride=conv_stride)
    # push!(layers, conv1)
    for i = 1:num_blocks
        id_layer = identity_block(kernel_size, filters)
        push!(layers, id_layer)
    end
    return Chain(layers...)
end

# TODO resnet v2 with pre-activations. But it does not seem to change the result
# much, so not a priority
function resnet(depth)
    # num_blocks: 3,5,9,11
    # (6*num_blocks + 2)
    # 20, 32, 56, 68
    # USE 9, resnet56
    (depth - 2) % 6 == 0 || error("resnet error")
    n = convert(Int, (depth - 2) / 6)

    Chain(
        myConv((3,3), 3=>16, stride=(1,1), pad=1),
        BatchNorm(16),
        # 32,32,16

        # 2n 32x32, 16
        conv_block((3,3), 16=>16, 1),
        res_block(n-1, (3,3), 16=>16),

        conv_block((3,3), 16=>32, 2),
        res_block(n-1, (3,3), 32=>32),

        conv_block((3,3), 32=>64, 2),
        res_block(n-1, (3,3), 64=>64),

        MeanPool((8,8)),
        Flatten(),
        Dense(64,10),
        # softmax
    ) |> gpu
end

function WRN(depth, k)
    # depth = n * 6 + 4 (conv layers, not including dense)
    # w28-10: depth 28, widen factor 10
    # TODO wide resnet w28-10 (https://arxiv.org/abs/1605.07146)
    #
    # use filters = [16, 16, 32, 64] for a non-wide version
    # filters = [16, 160, 320, 640]
    (depth - 4) % 6 == 0 || error("WRN error")
    n = convert(Int, (depth - 4) / 6)
    filters = [16, 16*k, 32*k, 64*k]
    Chain(
        myConv((3,3), 3=>16, stride=(1,1), pad=1),
        BatchNorm(16),

        conv_block((3,3), 16=>filters[2], 1),
        res_block(n, (3,3), filters[2]=>filters[2]),

        conv_block((3,3), filters[2]=>filters[3], 2),
        res_block(n, (3,3), filters[3]=>filters[3]),

        conv_block((3,3), filters[3]=>filters[4], 2),
        res_block(n, (3,3), filters[4]=>filters[4]),

        MeanPool((8,8)),
        Flatten(),
        Dense(filters[4],10),
        # softmax
    ) |> gpu
end

##############################
## CIFAR10 AE models
##############################

function cifar10_AE()
    encoder = Chain(myConv((3,3), 3=>64, pad=(1,1)),
                    BatchNorm(64),
                    ReLU(),
                    MaxPool((2,2)),
                    myConv((3,3), 64=>32, pad=(1,1)),
                    BatchNorm(32),
                    ReLU(),
                    MaxPool((2,2)),
                    myConv((3,3), 32=>16, pad=(1,1)),
                    BatchNorm(16),
                    ReLU(),
                    MaxPool((2,2)))
    decoder = Chain(myConv((3,3), 16=>16, pad=(1,1), relu),
                    upsample,
                    myConv((3,3), 16=>32, pad=(1,1), relu),
                    upsample,
                    myConv((3,3), 32=>64, pad=(1,1), relu),
                    upsample,
                    myConv((3,3), 64=>3, pad=(1,1)),
                    Sigmoid())
    Chain(encoder, decoder) |> gpu
end

function cifar10_deep_AE()
    encoder = Chain(myConv((3,3), 3=>32, pad=(1,1), relu),
                    myConv((3,3), 32=>32, pad=(1,1), relu),

                    # DEBUG using conv with stride 2 instead of maxpool
                    # MaxPool((2,2)),
                    # myConv((3,3), 32=>32, stride=2, relu)
                    myConv((1,1), 32=>32, pad=0, stride=2, relu),

                    myConv((3,3), 32=>64, pad=(1,1), relu),
                    myConv((3,3), 64=>64, pad=(1,1), relu),

                    # MaxPool((2,2)),
                    # myConv((3,3), 64=>64, stride=2, relu)
                    myConv((1,1), 64=>64, pad=0, stride=2, relu),

                    myConv((3,3), 64=>128, pad=(1,1), relu),
                    myConv((3,3), 128=>128, pad=(1,1), relu),
                    # MaxPool((2,2)),
                    # myConv((3,3), 128=>256, pad=(1,1), relu),
                    # myConv((3,3), 256=>256, pad=(1,1), relu)
                    )

    decoder = Chain(
        # myConvTranspose((2,2), 256=>128, stride=2, pad=0),
        # myConv((3,3), 128=>128, pad=1, relu),

        # DEBUG using upsample instead of ConvTrans
        myConvTranspose((2,2), 128=>64, stride=2, pad=0),
        # upsample,
        myConv((3,3), 64=>64, pad=1, relu),

        myConvTranspose((2,2), 64=>32, stride=2, pad=0),
        # upsample,

        myConv((3,3), 32=>32, pad=1, relu),
        myConv((3,3), 32=>3, pad=1),
        Sigmoid())

    Chain(encoder, decoder) |> gpu
end

struct Dunet
    down_layers
    up_layers
    final_layers
end
Flux.@treelike Dunet

function (l::Dunet)(input)
    local value = copy.(input)
    local saved = []
    for i in 1:length(l.down_layers)
        value = (l.down_layers[i])(value)
        push!(saved, value)
    end
    pop!(saved)
    for i in 1:length(l.up_layers)
        prev = pop!(saved)
        value = (l.up_layers[i])(value)
        value = cat(value, prev, dims=3)
    end
    # finally add this to original input
    value = l.final_layers(value)
    value + input
end

function dunet_downlayers()
    Tuple([Chain(myConv((3,3), 3=>32, pad=(1,1), relu),
                 myConv((3,3), 32=>32, pad=(1,1), relu)),
           Chain(MaxPool((2,2)),
                 myConv((3,3), 32=>64, pad=(1,1), relu),
                 myConv((3,3), 64=>64, pad=(1,1), relu)),
           Chain(MaxPool((2,2)),
                 myConv((3,3), 64=>128, pad=(1,1), relu),
                 myConv((3,3), 128=>128, pad=(1,1), relu)),
           Chain(MaxPool((2,2)),
                 myConv((3,3), 128=>256, pad=(1,1), relu),
                 myConv((3,3), 256=>256, pad=(1,1), relu)),
           Chain(MaxPool((2,2)),
                 myConv((3,3), 256=>512, pad=(1,1), relu),
                 myConv((3,3), 512=>512, pad=(1,1), relu))])
end

function dunet_uplayers()
    # NOTE: for pad=same I should use pad=0 here
    Tuple([Chain(myConvTranspose((2,2), 512=>256, stride=2, pad=0)),
           Chain(myConv((3,3), 512=>256, pad=1, relu),
                 myConv((3,3), 256=>256, pad=1, relu),
                 myConvTranspose((2,2), 256=>128, stride=2, pad=0)),
           Chain(myConv((3,3), 256=>128, pad=1, relu),
                 myConv((3,3), 128=>128, pad=1, relu),
                 myConvTranspose((2,2), 128=>64, stride=2, pad=0)),
           Chain(myConv((3,3), 128=>64, pad=1, relu),
                 myConv((3,3), 64=>64, pad=1, relu),
                 myConvTranspose((2,2), 64=>32, stride=2, pad=0))])
end

function dunet_finallayer()
    Chain(myConv((3,3), 64=>32, pad=1, relu),
          myConv((3,3), 32=>32, pad=1, relu),
          myConv((3,3), 32=>3, pad=1),
          Sigmoid())
end

function dunet()
    down = dunet_downlayers()
    up = dunet_uplayers()
    final = dunet_finallayer()
    Dunet(down, up, final) |> gpu
end

max_stars_repo_name: lihebi/AdvAE

max_issues_repo_name: lihebi/AdvAE

max_forks_repo_name: lihebi/AdvAE