text:
include("header.jl")
using Dates
date(x)=(join(stdout,[Dates.format(Dates.now(),"HH:MM:SS"), x,'\n'],' '); flush(stdout))
macro dbg(_x); end
#macro dbg(_x); :(@show $(esc(_x))); end

@testset "broadcast" begin

    rand11(f,t,d...)=rand(t,d...) .* t(0.8) .+ t(0.1)
    # we need symetric ones as well to test compare operations
    #broadcast dim sizes chosen in the lower limits of given kernels
    size12 = (((513,1025),(1,1025)),((1,1025),(513,1025)),#cuda13 vector-Ndim, first dim
              ((256,1),(256,1024)),((256,1024),(256,1)),#cuda14 vector-Ndim, other than first dim
              ((8,8,16,4),(8,8,1,4)),((8,8,16,4),(8,8,16,4)),#cuda16 3,4,5 dims generalised
              ((5,1,2,2,4,4,2),(5,5,1,2,4,4,1)),((5,5,1,2,4,4,1),(5,1,2,2,4,4,2)))#cuda17  more than 5 dim, generalised

    size11 = (1,(1,1),2,(2,1),(1,2),(2,2))
    # These are helper functions for gradients and rpow is used to define Array.^Number
    # The former is tested during gradcheck, rpow is tested with .^ operation
    exclude11 = ("invxback", "reluback", "sigmback", "tanhback", "eluback", "seluback", "rpow")

    broadcast_fns = Any[]
    for f in Knet.broadcast_ops
        if isa(f,Tuple); f=f[2]; end
        in(f, exclude11) && continue
        f0 = eval(Meta.parse(lstrip(f,'.')))
        f1 = x->broadcast(f0,x[1],x[2])
        f2 = (x1,x2)->broadcast(f0,x1,x2)
        push!(broadcast_fns, (f1,f2))
    end

    #Random.seed!(42)

    @testset "array-scalar" begin
        date("broadcast: array-scalar")
        for (f1,f) in broadcast_fns
            for t in (Float32, Float64)
                for n in size11
                    @dbg f,t,n,0
                    a = rand11(f,t,n)
                    s = rand11(f,t) .+ t(1)
                    @test gradcheck(f1, Any[a,s])
                    @test gradcheck(f1, Any[s,a])
                    if gpu() >= 0
                        g = KnetArray(a)
                        @test isapprox(f(a,s), f(g,s))
                        @test isapprox(f(s,a), f(s,g))
                        @test gradcheck(f1, Any[g,s])
                        @test gradcheck(f1, Any[s,g])
                    end
                end
            end
        end
    end

    @testset "array-vector" begin
        date("broadcast: array-vector")
        for (f1,f) in broadcast_fns
            for t in (Float32, Float64)
                for n1 in size11, n2 in size11
                    # max and min do not have broadcasting (different sized) versions defined in Base
                    # 0.5 and 0.6 use max.(x,y) syntax, 0.4 can also using @compat
                    # TODO: Fix this as part of general 0.6 compat work
                    if (f in (max,min) && n1 != n2); continue; end
                    @dbg f,t,n1,n2
                    a1 = rand11(f,t,n1)
                    a2 = rand11(f,t,n2) .+ t(1)
                    @test gradcheck(f1, Any[a1, a2])
                    if gpu() >= 0
                        g1 = KnetArray(a1)
                        g2 = KnetArray(a2)
                        @test isapprox(f(a1,a2),f(g1,g2))
                        @test gradcheck(f1, Any[g1, g2], rtol=0.1)
                    end
                end
            end
        end
    end

    @testset "array-array" begin
        date("broadcast: array-array")
        # for (f1,f) in broadcast_fns # takes too much time
        f = (x1,x2)->broadcast(+,x1,x2)
        f1 = x->broadcast(+,x[1],x[2])
        for t in (Float32, Float64)
            # multidim array broadcast
            # vector broadcast which is size bigger than 127 (more detail in src/broadcast.jl)
            for (n1,n2) in size12
                @dbg f,t,n1,n2 # Travis gives timeout here if no output
                a1 = rand11(f,t,n1)
                a2 = rand11(f,t,n2) .+ t(1)
                if t == Float64 # Float32 does not have enough precision for large arrays
                    @test gradcheck(f1, Any[a1, a2]; rtol=0.01)
                end
                if gpu() >= 0
                    g1 = KnetArray(a1)
                    g2 = KnetArray(a2)
                    @test isapprox(f(a1,a2),f(g1,g2))
                    if t == Float64
                        @test gradcheck(f1, Any[g1, g2]; rtol=0.01)
                    end
                end
            end
        end
    end

    @testset "ndims" begin # Issue #235
        if gpu() >= 0
            date("broadcast: ndims")
            a=rand(2,2,2) |> KnetArray
            b=rand(2,2) |> KnetArray
            c=rand(2) |> KnetArray
            @test a.*b == Array(a) .* Array(b)
            @test a.*c == Array(a) .* Array(c)
            @test b.*c == Array(b) .* Array(c)
        end
    end
end

date("broadcast: done")
nothing


text:
#################
# Shift & Scale #
#################
struct Shift{T, N} <: Bijector{N}
    a::T
end

Base.:(==)(b1::Shift{<:Any, N}, b2::Shift{<:Any, N}) where {N} = b1.a == b2.a

function Shift(a::Union{Real,AbstractArray}; dim::Val{D} = Val(ndims(a))) where D
    return Shift{typeof(a), D}(a)
end

# field is a numerical parameter
function Functors.functor(::Type{<:Shift{<:Any,N}}, x) where N
    function reconstruct_shift(xs)
        return Shift{typeof(xs.a),N}(xs.a)
    end
    return (a = x.a,), reconstruct_shift
end

up1(b::Shift{T, N}) where {T, N} = Shift{T, N + 1}(b.a)

(b::Shift)(x) = b.a .+ x
(b::Shift{<:Any, 2})(x::AbstractArray{<:AbstractMatrix}) = map(b, x)

inv(b::Shift{T, N}) where {T, N} = Shift{T, N}(-b.a)

# FIXME: implement custom adjoint to ensure we don't get tracking
logabsdetjac(b::Shift{T, N}, x) where {T, N} = _logabsdetjac_shift(b.a, x, Val(N))

_logabsdetjac_shift(a::Real, x::Real, ::Val{0}) = zero(eltype(x))
_logabsdetjac_shift(a::Real, x::AbstractVector{T}, ::Val{0}) where {T<:Real} = zeros(T, length(x))
_logabsdetjac_shift(a::T1, x::AbstractVector{T2}, ::Val{1}) where {T1<:Union{Real, AbstractVector}, T2<:Real} = zero(T2)
_logabsdetjac_shift(a::T1, x::AbstractMatrix{T2}, ::Val{1}) where {T1<:Union{Real, AbstractVector}, T2<:Real} = zeros(T2, size(x, 2))
_logabsdetjac_shift(a::T1, x::AbstractMatrix{T2}, ::Val{2}) where {T1<:Union{Real, AbstractVector}, T2<:Real} = zero(T2)
_logabsdetjac_shift(a::T1, x::AbstractArray{<:AbstractMatrix{T2}}, ::Val{2}) where {T1<:Union{Real, AbstractVector}, T2<:Real} = zeros(T2, size(x))

ext: jl


text:
"""
This example sets up a cold bubble perturbation which develops into a non-linear
density current. This numerical test case is described by Straka et al. (1993).
Also see: http://www2.mmm.ucar.edu/projects/srnwp_tests/density/density.html

Straka et al. (1993). "Numerical Solutions of a Nonlinear Density-Current -
    A Benchmark Solution and Comparisons." International Journal for Numerical
    Methods in Fluids 17, pp. 1-22.
"""

using Logging
using Printf
using Statistics
using NCDatasets
using CUDA

using Oceananigans
using Oceananigans.Grids
using Oceananigans.Advection
using Oceananigans.OutputWriters
using Oceananigans.Utils
using JULES

using Oceananigans.Fields: cpudata

Logging.global_logger(OceananigansLogger())

const km = kilometers
const hPa = 100.0

Lx = 51.2km
Lz = 6.4km

Δ = 20.0  # grid spacing [m]

Nx = Int(Lx/Δ)
Ny = 1
Nz = Int(Lz/Δ)

topo = (Periodic, Periodic, Bounded)
domain = (x=(-Lx/2, Lx/2), y=(-Lx/2, Lx/2), z=(0, Lz))
grid = RegularCartesianGrid(topology=topo, size=(Nx, Ny, Nz), halo=(3, 3, 3); domain...)

tvar = Energy()

model = CompressibleModel(
                      grid = grid,
                     gases = DryEarth(),
 	         advection = WENO5(),
    thermodynamic_variable = tvar,
                   closure = IsotropicDiffusivity(ν=75.0, κ=75.0)
)

gas = model.gases.ρ
R, cₚ, cᵥ = gas.R, gas.cₚ, gas.cᵥ
g  = model.gravity
pₛ = 1000hPa
Tₛ = 300.0

# Define an approximately hydrostatic background state
θ₀(x, y, z) = Tₛ
p₀(x, y, z) = pₛ * (1 - g*z / (cₚ*Tₛ))^(cₚ/R)
T₀(x, y, z) = Tₛ * (p₀(x, y, z)/pₛ)^(R/cₚ)
ρ₀(x, y, z) = p₀(x, y, z) / (R*T₀(x, y, z))

# Define both energy and entropy
uᵣ, Tᵣ, ρᵣ, sᵣ = gas.u₀, gas.T₀, gas.ρ₀, gas.s₀  # Reference values
ρe₀(x, y, z) = ρ₀(x, y, z) * (uᵣ + cᵥ * (T₀(x, y, z) - Tᵣ) + g*z)
ρs₀(x, y, z) = ρ₀(x, y, z) * (sᵣ + cᵥ * log(T₀(x, y, z)/Tᵣ) - R * log(ρ₀(x, y, z)/ρᵣ))

# Define the initial density perturbation
θᶜ′ = -15.0
xᶜ, zᶜ = 0km, 2km
xʳ, zʳ = 2km, 2km
L(x, y, z) = sqrt(((x - xᶜ)/xʳ)^2 + ((z - zᶜ)/zʳ)^2)
θ′(x, y, z) = (L(x, y, z) <= 1) * θᶜ′ * (1 + cos(π*L(x, y, z))) / 2
ρ′(x, y, z) = -ρ₀(x, y, z) * θ′(x, y, z) / θ₀(x, y, z)

# Define initial state
ρᵢ(x, y, z) = ρ₀(x, y, z) + ρ′(x, y, z)
pᵢ(x, y, z) = p₀(x, y, z)
Tᵢ(x, y, z) = pᵢ(x, y, z) / (R * ρᵢ(x, y, z))

ρeᵢ(x, y, z) = ρᵢ(x, y, z) * (uᵣ + cᵥ * (Tᵢ(x, y, z) - Tᵣ) + g*z)
ρsᵢ(x, y, z) = ρᵢ(x, y, z) * (sᵣ + cᵥ * log(Tᵢ(x, y, z)/Tᵣ) - R * log(ρᵢ(x, y, z)/ρᵣ))

# Set initial state (which includes the thermal perturbation)
set!(model.tracers.ρ, ρᵢ)
tvar isa Energy  && set!(model.tracers.ρe, ρeᵢ)
tvar isa Entropy && set!(model.tracers.ρs, ρsᵢ)
update_total_density!(model)

function print_progress(simulation)
    model, Δt = simulation.model, simulation.Δt
    tvar = model.thermodynamic_variable
    ρᵢ, ρeᵢ, ρsᵢ = simulation.parameters

    zC = znodes(Cell, model.grid)
    ρ̄ᵢ = mean(ρᵢ.(0, 0, zC))
    ρ̄ = mean(cpudata(model.total_density))

    progress = 100 * model.clock.time / simulation.stop_time
    message = @sprintf("[%05.2f%%] iteration = %d, time = %s, CFL = %.4e, acoustic CFL = %.4e, ρ̄ = %.4e (relΔ = %.4e)",
                       progress, model.clock.iteration, prettytime(model.clock.time), cfl(model, Δt),
                       acoustic_cfl(model, Δt), ρ̄, (ρ̄ - ρ̄ᵢ) / ρ̄)

    if tvar isa Energy
        ρ̄ēᵢ = mean(ρeᵢ.(0, 0, zC))
        ρ̄ē = mean(cpudata(model.tracers.ρe))
        message *= @sprintf(", ρ̄ē = %.4e (relΔ = %.4e)", ρ̄ē, (ρ̄ē - ρ̄ēᵢ)/ρ̄ē)
    elseif tvar isa Entropy
        ρ̄s̄ᵢ = mean(ρsᵢ.(0, 0, zC))
        ρ̄s̄ = mean(cpudata(model.tracers.ρs))
        message *= @sprintf(", ρ̄s̄ = %.4e (relΔ = %.4e)", ρ̄s̄, (ρ̄s̄ - ρ̄s̄ᵢ)/ρ̄s̄)
    end

    @info message

    return nothing
end

simulation = Simulation(model, Δt=0.02, stop_time=1000, iteration_interval=50,
                        progress=print_progress, parameters=(ρᵢ, ρeᵢ, ρsᵢ))

fields = Dict(
    "ρ"  => model.total_density,
    "ρu" => model.momenta.ρu,
    "ρw" => model.momenta.ρw
)

tvar isa Energy  && push!(fields, "ρe" => model.tracers.ρe)
tvar isa Entropy && push!(fields, "ρs" => model.tracers.ρs)

simulation.output_writers[:fields] =
NetCDFOutputWriter(model, fields, filepath="nonlinear_density_current_$(typeof(tvar)).nc",
                   time_interval=10seconds)

# Save base state to NetCDF.
ds = simulation.output_writers[:fields].dataset
ds_ρ = defVar(ds, "ρ₀", Float32, ("xC", "yC", "zC"))
ds_ρe = defVar(ds, "ρe₀", Float32, ("xC", "yC", "zC"))

x, y, z = nodes((Cell, Cell, Cell), grid, reshape=true)
ds_ρ[:, :, :] = ρ₀.(x, y, z)
ds_ρe[:, :, :] = ρe₀.(x, y, z)

run!(simulation)


text:
using testCI
using Test

@testset "testCI.jl" begin
    @test testCI.lol("hiho") == "hiho"

end

max_stars_repo_name: renerichter/testCI

max_issues_repo_name: renerichter/testCI

max_forks_repo_name: renerichter/testCI


text:
package accrue.cryptoerase.runtime;

import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import java.util.ArrayList;

public final class CryptoLibrary {
    public static byte[] encryptStrings(PublicKey key, ArrayList plaintext)
	throws Exception {
	return new byte[100];
    }

    public static byte[] encrypt(PublicKey key, byte[] plaintext)
	throws Exception {
	return new byte[100];
    }

    public static ArrayList decryptStrings(PrivateKey key, byte[] ciphertext)
	throws Exception {
	return new ArrayList();
    }

    public static byte[] decrypt(PrivateKey key, byte[] ciphertext)
	throws Exception {
	return new byte[100];
    }

    public static ArrayList compressStrings(ArrayList strings) {
	String result = "";
	for (int i = 0; i < strings.size(); i++) {
	    if ((String)strings.get(i) == "foo") {
		result += "a";
	    } else {
		result += "b";
	    }
	}
	ArrayList resultList = new ArrayList();
	resultList.add(result);
	return resultList;
    }

    public static ArrayList decompressStrings(ArrayList compressed) {
	ArrayList strings = new ArrayList();
	strings.add(compressed.get(0));
	return strings;
    }
}

max_stars_repo_name: HarvardPL/cryptoerase

max_issues_repo_name: HarvardPL/cryptoerase

max_forks_repo_name: HarvardPL/cryptoerase


text:
using MathProgBase, Cbc

struct KPDSupply{T<:Integer}
    item::String
    weight::T
    value::T
    quant::T
end
Base.show(io::IO, kdps::KPDSupply) = print(io, kdps.quant, " ", kdps.item, " ($(kdps.weight) kg, $(kdps.value) €)")

function solve(gear::Vector{KPDSupply{T}}, capacity::Integer) where T<:Integer
    w = getfield.(gear, :weight)
    v = getfield.(gear, :value)
    q = getfield.(gear, :quant)
    sol = mixintprog(-v, w', '<', capacity, :Int, 0, q, CbcSolver())
    sol.status == :Optimal || error("this problem could not be solved")

    if all(q .== 1) # simpler case
        return gear[sol.sol == 1.0]
    else
        pack = similar(gear, 0)
        s = round.(Int, sol.sol)
        for (i, g) in enumerate(gear)
            iszero(s[i]) && continue
            push!(pack, KPDSupply(g.item, g.weight, g.value, s[i]))
        end
        return pack
    end
end

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
using DifferentialGeometries: Cov, Con

@testset "Changing coordinates: 2D polar to 2D hyperbolic" begin
  c = ToCartesian(r->[r[1] * cos(r[2]), r[1] * sin(r[2])], 2)
  c⁻¹ = FromCartesian(x->[sqrt(x[1]^2 + x[2]^2), atan(x[2], x[1])], 2)

  h = ToCartesian(r->[r[2] * exp(r[1]), r[2] * exp(-r[1])], 2)
  h⁻¹ = FromCartesian(x->[log(sqrt(x[1] / x[2])), sqrt(x[1] * x[2])], 2)

  x = rand(2)
  r = c⁻¹(x)
  u = h \ x
  # check some logic else it's all for nought
  @assert h(u) ≈ x
  @assert h⁻¹(x) ≈ u
  @assert c⁻¹(h(u)) ≈ r
  @assert c \ h(u) ≈ r
  @assert h \ (c(r)) ≈ u

  f(Rθ) = ((R,θ)=Rθ; return [R^2 * tan(θ), sinh(θ) / R]) #an arbitrary function
  function foo(AVec, BVec, original, novel)
    vofr = CovariantVector(f, original, true) # v of r
    zofu = CovariantVector(U->f(c⁻¹(h(U))), novel, true) # z of u
    @test vofr(r, true) ≈ zofu(u, true) # the same thing
    vofu = convert(vofr, novel) # v of u
    @test vofr(r, true) ≈ vofu(u, true)
  end

  for (V1, V2, c1, c2) ∈ Iterators.product((Cov, Con),
                                           (Cov, Con),
                                           (c, c⁻¹),
                                           (h, h⁻¹))
    foo(V1, V2, c1, c2)
  end
end

max_stars_repo_name: jwscook/DifferentialGeometries

max_issues_repo_name: jwscook/DifferentialGeometries

max_forks_repo_name: jwscook/DifferentialGeometries


text:
__precompile__(true)
module JuML
export importcsv,
       Seq,
       DataFrame,
       Factor,
       Covariate,
       BoolVariate,
       DateTimeVariate,
       factor,
       covariate,
       getname,
       getlevels,
       isordinal,
       xgblogit,
       cvxgblogit,
       predict,
       getstats,
       getgroupstats,
       getauc,
       getlogloss,
       cache,
       CovariateStats,
       FactorStats,
       LevelStats,
       tryread,
       slice,
       nextslice,
       map,
       XGBClassifier,
       fit

include("const.jl")
include("DataStructures/seq.jl")
include("DataStructures/list.jl")
include("DataStructures/tree.jl")
include("util.jl")
include("DataImport/dataimport.jl")
include("DataFrame/dataframe.jl")
include("DataFrame/groupstats.jl")

include("Covariates/groupstatscovariate.jl")

include("Factors/factor.jl")
include("Factors/constfactor.jl")
include("Factors/filefactor.jl")
include("Factors/ordinalfactor.jl")
include("Factors/cachedfactor.jl")
include("Factors/filecachedfactor.jl")
include("Factors/bincovfactor.jl")
include("Factors/boolvarfactor.jl")
include("Factors/maplevelfactor.jl")
include("Factors/permutefactor.jl")
include("Factors/widerfactor.jl")
include("Factors/bindatetimefactor.jl")

include("IntVariates/intvariate.jl")
include("IntVariates/fileintvariate.jl")

include("Covariates/covariate.jl")
include("Covariates/constcovariate.jl")
include("Covariates/filecovariate.jl")
include("Covariates/cachedcovariate.jl")
include("Covariates/filecachedcovariate.jl")
include("Covariates/transcovariate.jl")
include("Covariates/trans2covariate.jl")
include("Covariates/parsefactorcovariate.jl")
include("Covariates/ifelsecovariate.jl")
include("Covariates/unixdatecovariate.jl")
include("Covariates/transdatetimecovariate.jl")
include("Covariates/randcovariate.jl")

include("BoolVariates/boolvariate.jl")
include("BoolVariates/cachedboolvariate.jl")
include("BoolVariates/filecachedboolvariate.jl")
include("BoolVariates/transboolvariate.jl")
include("BoolVariates/trans2boolvariate.jl")
include("BoolVariates/transcovboolvariate.jl")
include("BoolVariates/trans2covboolvariate.jl")
include("BoolVariates/transdatetimeboolvariate.jl")
include("BoolVariates/trans2datetimeboolvariate.jl")
include("BoolVariates/groupstatsboolvariate.jl")

include("DateTimeVariates/datetimevariate.jl")
include("DateTimeVariates/filedatetimevariate.jl")
include("DateTimeVariates/transdatetimevariate.jl")
include("DateTimeVariates/trans2datetimevariate.jl")

include("XGBoost/tree.jl")
include("XGBoost/split.jl")
include("XGBoost/logistic.jl")

include("MLJ/MLJ_XGBoost.jl")

end

max_stars_repo_name: Statfactory/JuML

max_issues_repo_name: Statfactory/JuML

max_forks_repo_name: Statfactory/JuML


text:
using BSONSerializer

struct MyType
    str::String
    num::Int
end

@BSONSerializable(MyType)

instance = MyType("hey", 101)
bson = BSONSerializer.serialize(instance)
#println(bson)

new_instance = BSONSerializer.deserialize(bson)
@assert new_instance == instance


text:
module PackageAnalyzer

# Standard libraries
using Pkg, TOML, UUIDs, Printf
# Third-party packages
using LicenseCheck # for `find_license` and `is_osi_approved`
using JSON3 # for interfacing with `tokei` to count lines of code
using Tokei_jll # count lines of code
using GitHub # Use GitHub API to get extra information about the repo
using Git

export general_registry, find_package, find_packages
export analyze, analyze!

# borrowed from <https://github.com/JuliaRegistries/RegistryTools.jl/blob/77cae9ef6a075e1d6ec1592bc3e166234d3f01c8/src/builtin_pkgs.jl>
const stdlibs = isdefined(Pkg.Types, :stdlib) ? Pkg.Types.stdlib : Pkg.Types.stdlibs
const STDLIBS = stdlibs()

include("count_loc.jl")
const LicenseTableEltype=@NamedTuple{license_filename::String, licenses_found::Vector{String}, license_file_percent_covered::Float64}
const ContributionTableElType=@NamedTuple{login::Union{String,Missing}, id::Union{Int,Missing}, name::Union{String,Missing}, type::String, contributions::Int}

struct Package
    name::String # name of the package
    uuid::UUID # uuid of the package
    repo::String # URL of the repository
    subdir::String # subdirectory of the package in the repo
    reachable::Bool # can the repository be cloned?
    docs::Bool # does it have documentation?
    runtests::Bool # does it have the test/runtests.jl file?
    github_actions::Bool # does it use GitHub Actions?
    travis::Bool # does it use Travis CI?
    appveyor::Bool # does it use AppVeyor?
    cirrus::Bool # does it use Cirrus CI?
    circle::Bool # does it use Circle CI?
    drone::Bool # does it use Drone CI?
    buildkite::Bool # does it use Buildkite?
    azure_pipelines::Bool # does it use Azure Pipelines?
    gitlab_pipeline::Bool # does it use Gitlab Pipeline?
    license_files::Vector{LicenseTableEltype} # a table of all possible license files
    licenses_in_project::Vector{String} # any licenses in the `license` key of the Project.toml
    lines_of_code::Vector{LoCTableEltype} # table of lines of code
    contributors::Vector{ContributionTableElType} # table of contributor data
end
function Package(name, uuid, repo;
                 subdir="",
                 reachable=false,
                 docs=false,
                 runtests=false,
                 github_actions=false,
                 travis=false,
                 appveyor=false,
                 cirrus=false,
                 circle=false,
                 drone=false,
                 buildkite=false,
                 azure_pipelines=false,
                 gitlab_pipeline=false,
                 license_files=LicenseTableEltype[],
                 licenses_in_project=String[],
                 lines_of_code=LoCTableEltype[],
                 contributors=ContributionTableElType[],
                 )
    return Package(name, uuid, repo, subdir, reachable, docs, runtests, github_actions, travis,
                   appveyor, cirrus, circle, drone, buildkite, azure_pipelines, gitlab_pipeline,
                   license_files, licenses_in_project, lines_of_code, contributors)
end

"""
    RegistryEntry(path::String)

Light data structure pointing to the directory where an entry of a registry is
stored.
"""
struct RegistryEntry
    path::String
end

# define `isequal`, `==`, and `hash` just in terms of the fields
for f in (:isequal, :(==))
    @eval begin
        function Base.$f(A::Package, B::Package)
            for i = 1:fieldcount(Package)
                $f(getfield(A, i), getfield(B, i)) || return false
            end
            true
        end
    end
end

Base.hash(A::Package, h::UInt) = hash(:Package, hash(ntuple(i -> getfield(A, i), fieldcount(Package)), h))

function Base.show(io::IO, p::Package)
    body = """
        Package $(p.name):
          * repo: $(p.repo)
        """
    if !isempty(p.subdir)
        body *= """
            * in subdirectory: $(p.subdir)
        """
    end
    body *= """
          * uuid: $(p.uuid)
          * is reachable: $(p.reachable)
        """
    if p.reachable
        if !isempty(p.lines_of_code)
            l_src = count_julia_loc(p, "src")
            l_test = count_julia_loc(p, "test")
            l_docs = count_docs(p)
            l_readme = count_readme(p)

            p_test = @sprintf("%.1f", 100*l_test / (l_test + l_src))
            p_docs = @sprintf("%.1f", 100*l_docs / (l_docs + l_src))
            body *= """
                  * Julia code in `src`: $(l_src) lines
                  * Julia code in `test`: $(l_test) lines ($(p_test)% of `test` + `src`)
                  * documention in `docs`: $(l_docs) lines ($(p_docs)% of `docs` + `src`)
                  * documention in README: $(l_readme) lines
                """
        end
        if isempty(p.license_files)
            body *= "  * no license found\n"
        else
            lic = p.license_files[1]
            license_string = join(lic.licenses_found, ", ")
            body *= "  * has license(s) in file: $(license_string)\n"
            body *= "    * filename: $(lic.license_filename)\n"
            body *= "    * OSI approved: $(all(is_osi_approved, lic.licenses_found))\n"
        end
        if !isempty(p.licenses_in_project)
            lic_project = join(p.licenses_in_project, ", ")
            body *= "  * has license(s) in Project.toml: $(lic_project)\n"
            body *= "    * OSI approved: $(all(is_osi_approved, p.licenses_in_project))\n"
        end
        if !isempty(p.contributors)
            n_anon = count_contributors(p; type="Anonymous")
            body *= "  * number of contributors: $(count_contributors(p)) (and $(n_anon) anonymous contributors)\n"
            body *= "  * number of commits: $(count_commits(p))\n"
        end
        body *= """
              * has `docs/make.jl`: $(p.docs)
              * has `test/runtests.jl`: $(p.runtests)
            """
        ci_services = (p.github_actions => "GitHub Actions",
                       p.travis => "Travis",
                       p.appveyor => "AppVeyor",
                       p.cirrus => "Cirrus",
                       p.circle => "Circle",
                       p.drone => "Drone CI",
                       p.buildkite => "Buildkite",
                       p.azure_pipelines => "Azure Pipelines",
                       p.gitlab_pipeline => "GitLab Pipeline",
                       )
        if any(first.(ci_services))
            body *= "  * has continuous integration: true\n"
            for (k, v) in ci_services
                if k
                    body *= "    * $(v)\n"
                end
            end
        else
            body *= "  * has continuous integration: false\n"
        end
    end
    print(io, strip(body))
end

"""
    general_registry() -> String

Guess the path of the General registry.
"""
general_registry() =
    first(joinpath(d, "registries", "General") for d in Pkg.depots() if isfile(joinpath(d, "registries", "General", "Registry.toml")))

"""
    find_package(pkg; registry = general_registry()) -> RegistryEntry

Returns the [RegistryEntry](@ref) for the package `pkg`.
The singular version of [`find_packages`](@ref).
"""
function find_package(pkg::AbstractString; registry=general_registry())
    registry_entries = find_packages([pkg]; registry)
    if isempty(registry_entries)
        if pkg ∈ values(STDLIBS)
            throw(ArgumentError("Standard library $pkg not present in registry"))
        else
            throw(ArgumentError("$pkg not found in registry"))
        end
    end
    return only(registry_entries)
end

"""
    find_packages(; registry = general_registry()) -> Vector{RegistryEntry}
    find_packages(names::AbstractString...; registry = general_registry()) -> Vector{RegistryEntry}
    find_packages(names; registry = general_registry()) -> Vector{RegistryEntry}

Find all packages in the given registry (specified by the `registry` keyword
argument), the General registry by default. Return a vector of
[RegistryEntry](@ref) pointing to to the directories of each package in the
registry.

Pass a list of package `names` as the first argument to return the paths corresponding to those packages,
or individual package names as separate arguments.
"""
find_packages

find_packages(names::AbstractString...; registry = general_registry()) =  find_packages(names; registry=registry)

function find_packages(names; registry = general_registry())
    if names !== nothing
        entries = RegistryEntry[]
        for name in names
            path = joinpath(registry, string(uppercase(first(name))), name)
            if isdir(path)
               push!(entries, RegistryEntry(path))
            elseif name ∉ values(STDLIBS)
                @error("Could not find package in registry!", name, path)
            end
        end
        return entries
    end
end

# The UUID of the "julia" pseudo-package in the General registry
const JULIA_UUID = "1222c4b2-2114-5bfd-aeef-88e4692bbb3e"

function find_packages(; registry = general_registry(),
                       filter = (uuid, p) -> !endswith(p["name"], "_jll") && uuid != JULIA_UUID)
    # Get the list of packages in the registry by parsing the `Registry.toml`
    # file in the given directory.
    packages = TOML.parsefile(joinpath(registry, "Registry.toml"))["packages"]
    # Get the directories of all packages.  Filter out JLL packages: they are
    # automatically generated and we know that they don't have testing nor
    # documentation. We also filter out the "julia" package which is not a real
    # package and just points at the Julia source code.
    return [RegistryEntry(joinpath(registry, splitpath(p["path"])...)) for (uuid, p) in packages if filter(uuid, p)]
end

"""
    PackageAnalyzer.github_auth(token::String="")

Obtain a GitHub authetication.  Use the `token` argument if it is non-empty,
otherwise use the `GITHUB_TOKEN` and `GITHUB_AUTH` environment variables, if set
and of length 40.  If all these methods fail, return an anonymous
authentication.
"""
function github_auth(token::String="")
    auth = if !isempty(token)
        GitHub.authenticate(token)
    elseif haskey(ENV, "GITHUB_TOKEN") && length(ENV["GITHUB_TOKEN"]) == 40
        GitHub.authenticate(ENV["GITHUB_TOKEN"])
    elseif haskey(ENV, "GITHUB_AUTH") && length(ENV["GITHUB_AUTH"]) == 40
        GitHub.authenticate(ENV["GITHUB_AUTH"])
    else
        GitHub.AnonymousAuth()
    end
end

"""
    analyze!(root, package::RegistryEntry; auth::GitHub.Authorization=github_auth()) -> Package

Analyze the package whose entry in the registry is in the `dir` directory,
cloning the package code to `joinpath(root, uuid)` where `uuid` is the UUID
of the package, if such a directory does not already exist.

If the GitHub authentication is non-anonymous and the repository is on GitHub,
the list of contributors to the repository is also collected, after waiting for
`sleep` seconds.  Only the number of contributors will be shown in the summary.
See [`PackageAnalyzer.github_auth`](@ref) to obtain a GitHub authentication.
"""
function analyze!(root, pkg::RegistryEntry; auth::GitHub.Authorization=github_auth(), sleep=0)
    # Parse the `Package.toml` file in the given directory.
    toml = TOML.parsefile(joinpath(pkg.path, "Package.toml"))
    name = toml["name"]::String
    uuid_string = toml["uuid"]::String
    uuid = UUID(uuid_string)
    repo = toml["repo"]::String
    subdir = get(toml, "subdir", "")::String

    dest = joinpath(root, uuid_string)

    isdir(dest) && return analyze_path(dest; repo, subdir, auth, sleep)

    return analyze_path!(dest, repo; name, uuid, subdir, auth, sleep)
end

"""
    analyze_path!(dest::AbstractString, repo::AbstractString; name="", uuid=UUID(UInt128(0)), subdir="", auth=github_auth(), sleep=0) -> Package

Analyze the Julia package located at the URL given by `repo` by cloning it to `dest`
and calling `analyze_path(dest)`.

If the clone fails, it returns a `Package` with `reachable=false`. If a `name` and `uuid` are provided,
these are used to populate the corresponding fields of the `Package`. If the clone succeeds, the `name`
and `uuid` are taken instead from the Project.toml in the package itself, and the values passed here
are ignored.

If the GitHub authentication `auth` is non-anonymous and the repository is on
GitHub, the list of contributors to the repository is also collected, after
waiting for `sleep` seconds for each entry.  See
[`PackageAnalyzer.github_auth`](@ref) to obtain a GitHub authentication.
"""
function analyze_path!(dest::AbstractString, repo::AbstractString; name="", uuid=UUID(UInt128(0)), subdir="", auth=github_auth(), sleep=0)
    reachable = try
        # Clone only latest commit on the default branch.  Note: some
        # repositories aren't reachable because the author made them private or
        # deleted them.  In these cases git would ask for username and password,
        # so we close STDIN to prevent git from prompting for username/password.
        # We need to use `detach` to make closing STDIN effective, suggested by
        # @staticfloat.
        run(pipeline(detach(`$(git()) clone -q --depth 1 $(repo) $(dest)`); stdin=devnull, stderr=devnull))
        true
    catch
        # The repository may be unreachable
        false
    end
    return reachable ? analyze_path(dest; repo, reachable, subdir, auth, sleep) : Package(name, uuid, repo; subdir)
end

"""
    analyze!(root, registry_entries::AbstractVector{<:RegistryEntry}; auth::GitHub.Authorization=github_auth(), sleep=0) -> Vector{Package}

Analyze all packages in the iterable `registry_entries`, using threads, cloning them to `root`
if a directory with their `uuid` does not already exist.  Returns a
`Vector{Package}`.

If the GitHub authentication is non-anonymous and the repository is on GitHub,
the list of contributors to the repositories is also collected, after waiting
for `sleep` seconds for each entry (useful to avoid getting rate-limited by
GitHub).  See [`PackageAnalyzer.github_auth`](@ref) to obtain a GitHub
authentication.
"""
function analyze!(root, registry_entries::AbstractVector{RegistryEntry}; auth::GitHub.Authorization=github_auth(), sleep=0)
    inputs = Channel{Tuple{Int, RegistryEntry}}(length(registry_entries))
    for (i,r) in enumerate(registry_entries)
        put!(inputs, (i,r))
    end
    close(inputs)
    outputs = Channel{Tuple{Int, Package}}(length(registry_entries))
    Threads.foreach(inputs) do (i, r)
        put!(outputs, (i, analyze!(root, r; auth, sleep)))
    end
    close(outputs)
    return last.(sort!(collect(outputs); by = first))
end

"""
    analyze(package::RegistryEntry; auth::GitHub.Authorization=github_auth(), sleep=0) -> Package
    analyze(packages::AbstractVector{<:RegistryEntry}; auth::GitHub.Authorization=github_auth(), sleep=0) -> Vector{Package}

Analyzes a package or list of packages using the information in their directory
in a registry by creating a temporary directory and calling `analyze!`,
cleaning up the temporary directory afterwards.

If the GitHub authentication is non-anonymous and the repository is on GitHub,
the list of contributors to the repository is also collected after waiting for
`sleep` seconds (useful to avoid getting rate-limited by GitHub).  Only the
number of contributors will be shown in the summary.  See
[`PackageAnalyzer.github_auth`](@ref) to obtain a GitHub authentication.

## Example
```julia
julia> analyze(find_package("BinaryBuilder"))
Package BinaryBuilder:
  * repo: https://github.com/JuliaPackaging/BinaryBuilder.jl.git
  * uuid: 12aac903-9f7c-5d81-afc2-d9565ea332ae
  * is reachable: true
  * Julia code in `src`: 4758 lines
  * Julia code in `test`: 1566 lines (24.8% of `test` + `src`)
  * documention in `docs`: 998 lines (17.3% of `docs` + `src`)
  * documention in README: 22 lines
  * has license(s) in file: MIT
    * filename: LICENSE.md
    * OSI approved: true
  * number of contributors: 53 (and 0 anonymous contributors)
  * number of commits: 1516
  * has `docs/make.jl`: true
  * has `test/runtests.jl`: true
  * has continuous integration: true
    * GitHub Actions
    * Azure Pipelines

```
"""
function analyze(p; auth::GitHub.Authorization=github_auth(), sleep=0)
    mktempdir() do root
        analyze!(root, p; auth, sleep)
    end
end

function parse_project(dir)
    bad_project = (; name = "Invalid Project.toml", uuid = UUID(UInt128(0)), licenses_in_project=String[])
    project_path = joinpath(dir, "Project.toml")
    if !isfile(project_path)
        project_path = joinpath(dir, "JuliaProject.toml")
    end
    isfile(project_path) || return bad_project
    project = TOML.tryparsefile(project_path)
    project isa TOML.ParserError && return bad_project
    haskey(project, "name") && haskey(project, "uuid") || return bad_project
    uuid = tryparse(UUID, project["uuid"]::String)
    uuid === nothing && return bad_project
    licenses_in_project = get(project, "license", String[])
    if licenses_in_project isa String
        licenses_in_project = [licenses_in_project]
    end
    return (; name = project["name"]::String, uuid, licenses_in_project)
end

"""
    analyze(name_or_dir_or_url::AbstractString; repo = "", reachable=true, subdir="", registry=general_registry(), auth::GitHub.Authorization=github_auth())

Analyze the package pointed to by the mandatory argument and return a summary of
its properties.

If `name_or_dir_or_url` is a valid Julia identifier, it is assumed to be the name of a
package available in `registry`.  The function then uses [`find_package`](@ref)
to find its entry in the registry and analyze its content.

If `name_or_dir_or_url` is a filesystem path, analyze the package whose source code is
located at `name_or_dir_or_url`. Optionally `repo` and `reachable` a boolean indicating
whether or not the package is reachable online, since these can't be inferred
from the source code.  The `subdir` keyword arguments indicates the subdirectory
of `dir` under which the Julia package can be found.

Otherwise, `name_or_dir_or_url` is assumed to be a URL. The repository is cloned to a temporary directory
and analyzed.

If the GitHub authentication is non-anonymous and the repository is on GitHub,
the list of contributors to the repository is also collected.  Only the number
of contributors will be shown in the summary.  See
[`PackageAnalyzer.github_auth`](@ref) to obtain a GitHub authentication.

## Example

You can analyze a package just by its name, whether you have it installed
locally or not:

```julia
julia> analyze("Pluto")
Package Pluto:
  * repo: https://github.com/fonsp/Pluto.jl.git
  * uuid: c3e4b0f8-55cb-11ea-2926-15256bba5781
  * is reachable: true
  * Julia code in `src`: 6896 lines
  * Julia code in `test`: 3682 lines (34.8% of `test` + `src`)
  * documention in `docs`: 0 lines (0.0% of `docs` + `src`)
  * documention in README: 110 lines
  * has license(s) in file: MIT
    * filename: LICENSE
    * OSI approved: true
  * has license(s) in Project.toml: MIT
    * OSI approved: true
  * number of contributors: 73 (and 1 anonymous contributors)
  * number of commits: 940
  * has `docs/make.jl`: false
  * has `test/runtests.jl`: true
  * has continuous integration: true
    * GitHub Actions
```
"""
function analyze(name_or_dir_or_url::AbstractString; repo = "", reachable=true, subdir="", registry=general_registry(), auth::GitHub.Authorization=github_auth(), sleep=0)
    if Base.isidentifier(name_or_dir_or_url)
        # The argument looks like a package name rather than a directory: find
        # the package in `registry` and analyze it
        return analyze(find_package(name_or_dir_or_url; registry); auth, sleep)
    elseif isdir(name_or_dir_or_url)
        return analyze_path(name_or_dir_or_url; repo, reachable, subdir, auth, sleep)
    else
        repo = name_or_dir_or_url
        dest = mktempdir()
        return analyze_path!(dest, repo; subdir, auth, sleep)
    end
end

"""
    analyze(m::Module; kwargs...) -> Package

If you want to analyze a package which is already loaded in the current session,
you can simply call `analyze`, which uses `pkgdir` to determine its source code:

```julia
julia> using DataFrames

julia> analyze(DataFrames)
Package DataFrames:
  * repo:
  * uuid: a93c6f00-e57d-5684-b7b6-d8193f3e46c0
  * is reachable: true
  * Julia code in `src`: 15809 lines
  * Julia code in `test`: 17512 lines (52.6% of `test` + `src`)
  * documention in `docs`: 3885 lines (19.7% of `docs` + `src`)
  * documention in README: 21 lines
  * has license(s) in file: MIT
    * filename: LICENSE.md
    * OSI approved: true
  * has `docs/make.jl`: true
  * has `test/runtests.jl`: true
  * has continuous integration: true
    * GitHub Actions
```
"""
analyze(m::Module; kwargs...) = analyze_path(pkgdir(m); kwargs...)

"""
    analyze_path(dir::AbstractString; repo = "", reachable=true, subdir="", auth::GitHub.Authorization=github_auth(), sleep=0) -> Package

Analyze the package whose source code is located at the local path `dir`.  If
the package's repository is hosted on GitHub and `auth` is a non-anonymous
GitHub authentication, wait for `sleep` seconds before collecting the list of
its contributors.
"""
function analyze_path(dir::AbstractString; repo = "", reachable=true, subdir="", auth::GitHub.Authorization=github_auth(), sleep=0)
    # we will look for docs, tests, license, and count lines of code
    # in the `pkgdir`; we will look for CI in the `dir`.
    pkgdir = joinpath(dir, subdir)
    name, uuid, licenses_in_project = parse_project(pkgdir)
    docs = isfile(joinpath(pkgdir, "docs", "make.jl")) || isfile(joinpath(pkgdir, "doc", "make.jl"))
    runtests = isfile(joinpath(pkgdir, "test", "runtests.jl"))
    travis = isfile(joinpath(dir, ".travis.yml"))
    appveyor = isfile(joinpath(dir, "appveyor.yml"))
    cirrus = isfile(joinpath(dir, ".cirrus.yml"))
    circle = isfile(joinpath(dir, ".circleci", "config.yml"))
    drone = isfile(joinpath(dir, ".drone.yml"))
    azure_pipelines = isfile(joinpath(dir, "azure-pipelines.yml"))
    buildkite = isfile(joinpath(dir, ".buildkite", "pipeline.yml"))
    gitlab_pipeline = isfile(joinpath(dir, ".gitlab-ci.yml"))
    github_workflows = joinpath(dir, ".github", "workflows")
    if isdir(github_workflows)
        # Find all workflows
        files = readdir(github_workflows)
        # Exclude TagBot and CompatHelper
        filter(f -> lowercase(f) ∉ ("compathelper.yml", "tagbot.yml"), files)
        # Assume all other files are GitHub Actions for CI.  May not
        # _always_ be the case, but it's a good first-order approximation.
        github_actions = length(files) > 0
    else
        github_actions = false
    end
    license_files = find_licenses(dir)
    if isdir(pkgdir)
        if !isempty(subdir)
            # Look for licenses at top-level and in the subdirectory
            subdir_licenses_files = [(; license_filename = joinpath(subdir, row.license_filename), row.licenses_found, row.license_file_percent_covered) for row in find_licenses(pkgdir)]
            license_files = [subdir_licenses_files; license_files]
        end
        lines_of_code = count_loc(pkgdir)
    else
        license_files = LicenseTableEltype[]
        lines_of_code = LoCTableEltype[]
    end

    # If the repository is on GitHub and we have a non-anonymous GitHub
    # authentication, get the list of contributors
    contributors = if !(auth isa GitHub.AnonymousAuth) && occursin("github.com", repo)
        Base.sleep(sleep)
        repo_name = replace(replace(repo, r"^https://github\.com/" => ""), r"\.git$" => "")
        contribution_table(repo_name; auth)
    else
        ContributionTableElType[]
    end

    Package(name, uuid, repo; subdir, reachable, docs, runtests, travis, appveyor, cirrus,
            circle, drone, buildkite, azure_pipelines, gitlab_pipeline, github_actions,
            license_files, licenses_in_project, lines_of_code, contributors)
end

function contribution_table(repo_name; auth)
    return try
        parse_contributions.(GitHub.contributors(GitHub.Repo(repo_name); auth, params=Dict("anon"=>"true"))[1])
    catch e
        @error "Could not obtain contributors for $(repo_name)" exception=(e, catch_backtrace())
        ContributionTableElType[]
    end
end

function parse_contributions(c)
    contrib = c["contributor"]
    if contrib.typ == "Anonymous"
        return (; login = missing, id = missing, contrib.name, type=contrib.typ, contributions = c["contributions"])
    else
        return (; contrib.login, contrib.id, name = missing, type=contrib.typ, contributions = c["contributions"])
    end
end

#####
##### Counting things
#####

count_commits(table) = sum(row.contributions for row in table; init=0)
count_commits(pkg::Package) = count_commits(pkg.contributors)

count_contributors(table; type="User") = count(row.type == type for row in table)
count_contributors(pkg::Package; kwargs...) = count_contributors(pkg.contributors; kwargs...)

count_julia_loc(table, dir) = sum(row.code for row in table if row.directory == dir && row.language == :Julia; init=0)

function count_docs(table, dirs = ("docs", "doc"))
    rm_langs = (:TOML, :SVG, :CSS, :Javascript)
    sum(row.code + row.comments for row in table if lowercase(row.directory) in dirs && row.language ∉ rm_langs && row.sublanguage ∉ rm_langs; init=0)
end

count_readme(table) = count_docs(table, ("readme", "readme.md"))

count_julia_loc(pkg::Package, args...) = count_julia_loc(pkg.lines_of_code, args...)
count_docs(pkg::Package, args...) = count_docs(pkg.lines_of_code, args...)
count_readme(pkg::Package, args...) = count_readme(pkg.lines_of_code, args...)

end # module


text:
mutable struct RDB_Package
    header::RDB_MSG_HDR_t
    entry_headers::Vector{RDB_MSG_ENTRY_HDR_t}
    data_blocks::Vector{Vector{UInt8}}
end

function Base.read(io::IO, ::Type{RDB_MSG_HDR_t}, already_read_magic_no::Bool=false)
    if !already_read_magic_no
        scan_for_value(io, RDB_MAGIC_NO)
    end

    version = read(io, UInt16)
    headerSize = read(io, UInt32)
    dataSize = read(io, UInt32)
    frameNo = read(io, UInt32)
    simTime = read(io, Cdouble)
    RDB_MSG_HDR_t(RDB_MAGIC_NO, version, headerSize, dataSize, frameNo, simTime)
end
function Base.read!(io::IO, structure::RDB_MSG_HDR_t, already_read_magic_no::Bool=false)
    if !already_read_magic_no
        scan_for_value(io, RDB_MAGIC_NO)
    end

    structure.magicNo = RDB_MAGIC_NO
    structure.version = read(io, UInt16)
    structure.headerSize = read(io, UInt32)
    structure.dataSize = read(io, UInt32)
    structure.frameNo = read(io, UInt32)
    structure.simTime = read(io, Cdouble)
    structure
end
# function Base.write(io::IO, header::RDB_MSG_HDR_t)
#     write(io, header.magicNo)
#     write(io, header.version)
#     write(io, header.headerSize)
#     write(io, header.dataSize)
#     write(io, header.frameNo)
#     write(io, header.simTime)
# end
# function Base.show(io::IO, header::RDB_MSG_HDR_t)
#     println(io, "RDB_MSG_HDR_t:")
#     println(io, "\tmagicNo:    %s", hex(header.magicNo))
#     println(io, "\tversion:    %s", hex(header.version))
#     println(io, "\theaderSize: %d", header.headerSize)
#     println(io, "\tdataSize:   %d", header.dataSize)
#     println(io, "\tframeNo:    %d", header.frameNo)
#     @printf(io, "\tsimTime:    %.16e", header.simTime)
# end
function Base.print(io::IO, header::RDB_MSG_HDR_t)

    @printf(io, "(%d %d %10.3f)", header.dataSize, header.frameNo, header.simTime)
end

# function Base.read(io, ::Type{RDB_MSG_ENTRY_HDR_t})
#     headerSize = read(io, UInt32)
#     dataSize = read(io, UInt32)
#     elementSize = read(io, UInt32)
#     pkgId = read(io, UInt16)
#     flags = read(io, UInt16)
#     RDB_MSG_ENTRY_HDR_t(headerSize, dataSize, elementSize, pkgId, flags)
# end
# function Base.write(io::IO, header::RDB_MSG_ENTRY_HDR_t)
#     write(io, header.headerSize)
#     write(io, header.dataSize)
#     write(io, header.elementSize)
#     write(io, header.pkgId)
#     write(io, header.flags)
# end

function Base.read(io::IO, ::Type{RDB_Package}, already_read_magic_no::Bool=false)

    header = read(io, RDB_MSG_HDR_t, already_read_magic_no)

    entry_headers = RDB_MSG_ENTRY_HDR_t[]
    data_blocks = Vector{UInt8}[]

    bytes_remaining = header.dataSize
    while bytes_remaining > 0
        entry_header = read(io, RDB_MSG_ENTRY_HDR_t)
        bytes_remaining -= entry_header.headerSize

        data_block = readbytes(io, entry_header.dataSize)
        bytes_remaining -= entry_header.dataSize

        push!(entry_headers, entry_header)
        push!(data_blocks, data_block)
    end

    RDB_Package(header, entry_headers, data_blocks)
end

function Base.show(io::IO, pkg::RDB_Package)
    println(io, "RDB_Package:")
    println(io, "header: ", pkg.header)
    println(io, "nentries: ", length(pkg.entry_headers))
    #= Xiaobai
    for eh in pkg.entry_headers
        @printf(io, "\t[%d %d %s %s]\n", eh.dataSize, eh.elementSize, rdb_pkg_id_to_string(eh.pkgId), hex(eh.flags))
    end
    =#
    # Xiaobai
    for i=1:length(pkg.entry_headers)
        eh=pkg.entry_headers[i]
        data=pkg.data_blocks[i]
        @printf(io, "\t[%d %d %s %s]\n", eh.dataSize, eh.elementSize, rdb_pkg_id_to_string(eh.pkgId), hex(eh.flags))
        if rdb_pkg_id_to_string(eh.pkgId)=="DRIVER_CTRL"
            #=
            playerId=convert(UInt32,data[1])
            println("playerId is ",playerId)
            println("size is ",size(data))
            index=findn(data)
            println("non-zero index is ",index)
            println("non-zero value is",data[index])
            =#
            println("data is ", data)
        end
    end
    # Xiaobai
end

function write_udp_packet_with_start_end_of_frame(io::IO, elem::RDB_PACKAGE_ELEMENT, frameNo::Integer, simTime::Real, flags::UInt16=0x0000)

    # println("sending $(typeof(elem)) packet")
    #calculate dataSize
    dataSize=convert(UInt32, sizeof(elem) + 3*sizeof(RDB_MSG_ENTRY_HDR_t))

    # write the RDB_MSG_HDR_t
    write(io, RDB_MAGIC_NO)
    write(io, RDB_VERSION)
    write(io, convert(UInt32, sizeof(RDB_MSG_HDR_t)))
    write(io, dataSize)
    write(io, convert(UInt32, frameNo))
    write(io, convert(Cdouble, simTime))

    #write start of frame
        # write the RDB_MSG_ENTRY_HDR_t
    write(io, convert(UInt32, sizeof(RDB_MSG_ENTRY_HDR_t)))
    write(io, convert(UInt32, 0))
    write(io, convert(UInt32, 0))
    write(io, RDB_PKG_ID_START_OF_FRAME::UInt16)
    write(io, flags)

    #write the entry
        # write the RDB_MSG_ENTRY_HDR_t
    write(io, convert(UInt32, sizeof(RDB_MSG_ENTRY_HDR_t)))
    write(io, convert(UInt32, sizeof(elem)))
    write(io, convert(UInt32, sizeof(elem)))
    write(io, rdb_type_to_pkg_id(elem)::UInt16)
    write(io, flags)

        # write the entry
    write(io, elem)

    #write end of frame
        # write the RDB_MSG_ENTRY_HDR_t
    write(io, convert(UInt32, sizeof(RDB_MSG_ENTRY_HDR_t)))
    write(io, convert(UInt32, 0))
    write(io, convert(UInt32, 0))
    write(io, RDB_PKG_ID_END_OF_FRAME::UInt16)
    write(io, flags)
end

###Xiaobai

function write_udp_packet(io::IO, elem::RDB_PACKAGE_ELEMENT, frameNo::Integer, simTime::Real, flags::UInt16=0x0000)

    # println("sending $(typeof(elem)) packet")

    # write the RDB_MSG_HDR_t
    write(io, RDB_MAGIC_NO)
    write(io, RDB_VERSION)
    write(io, convert(UInt32, sizeof(RDB_MSG_HDR_t)))
    write(io, convert(UInt32, sizeof(elem) + sizeof(RDB_MSG_ENTRY_HDR_t)))
    write(io, convert(UInt32, frameNo))
    write(io, convert(Cdouble, simTime))

    # write the RDB_MSG_ENTRY_HDR_t
    write(io, convert(UInt32, sizeof(RDB_MSG_ENTRY_HDR_t)))
    write(io, convert(UInt32, sizeof(elem)))
    write(io, convert(UInt32, sizeof(elem)))
    write(io, rdb_type_to_pkg_id(elem)::UInt16)
    write(io, flags)

    # write the entry
    write(io, elem)
end

##Xiaobdi
function write_udp_packets(io::IO, elements::Array{RDB_PACKAGE_ELEMENT}, frameNo::Integer, simTime::Real, flags::UInt16=0x0000)

    # println("sending $(typeof(elem)) packet")
    # println(sizeof(elements))
    # write the RDB_MSG_HDR_t
    write(io, RDB_MAGIC_NO)
    write(io, RDB_VERSION)
    write(io, convert(UInt32, sizeof(RDB_MSG_HDR_t)))
    write(io, convert(UInt32, sizeof(elements[1])*length(elements) + sizeof(RDB_MSG_ENTRY_HDR_t)))
    write(io, convert(UInt32, frameNo))
    write(io, convert(Cdouble, simTime))

    # write the RDB_MSG_ENTRY_HDR_t
    entry_hdr = create_udp_entry_header(elements, flags)
    write(io,entry_hdr)

    # write the entry
    for elem in elements
        write(io, elem)
    end
end

function write_udp_packet(io::IO, ::RDB_START_OF_FRAME_t, frameNo::Integer, simTime::Real, flags::UInt16=0x0000)

    # println("sending start of frame")

    # write the RDB_MSG_HDR_t
    write(io, RDB_MAGIC_NO)
    write(io, RDB_VERSION)
    write(io, convert(UInt32, sizeof(RDB_MSG_HDR_t)))
    write(io, convert(UInt32, sizeof(RDB_MSG_ENTRY_HDR_t)))
    write(io, convert(UInt32, frameNo))
    write(io, convert(Cdouble, simTime))

    # write the RDB_MSG_ENTRY_HDR_t
    write(io, convert(UInt32, sizeof(RDB_MSG_ENTRY_HDR_t)))
    write(io, convert(UInt32, 0))
    write(io, convert(UInt32, 0))
    write(io, RDB_PKG_ID_START_OF_FRAME::UInt16)
    write(io, flags)
end
function write_udp_packet(io::IO, ::RDB_END_OF_FRAME_t, frameNo::Integer, simTime::Real, flags::UInt16=0x0000)

    # println("sending end of frame")

    # write the RDB_MSG_HDR_t
    write(io, RDB_MAGIC_NO)
    write(io, RDB_VERSION)
    write(io, convert(UInt32, sizeof(RDB_MSG_HDR_t)))
    write(io, convert(UInt32, sizeof(RDB_MSG_ENTRY_HDR_t)))
    write(io, convert(UInt32, frameNo))
    write(io, convert(Cdouble, simTime))

    # write the RDB_MSG_ENTRY_HDR_t
    write(io, convert(UInt32, sizeof(RDB_MSG_ENTRY_HDR_t)))
    write(io, convert(UInt32, 0))
    write(io, convert(UInt32, 0))
    write(io, RDB_PKG_ID_END_OF_FRAME::UInt16)
    write(io, flags)
end

max_stars_repo_name: sisl/VirtualTestDrive

max_issues_repo_name: sisl/VirtualTestDrive

max_forks_repo_name: sisl/VirtualTestDrive