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

"""
    clone_backend(app_id, backend_environment_name, target_environment_name)
    clone_backend(app_id, backend_environment_name, target_environment_name, params::Dict{String,<:Any})

This operation clones an existing backend.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `target_environment_name`: The name of the destination backend environment to be created.

"""
clone_backend(appId, backendEnvironmentName, targetEnvironmentName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/environments/$(backendEnvironmentName)/clone", Dict{String, Any}("targetEnvironmentName"=>targetEnvironmentName); aws_config=aws_config)
clone_backend(appId, backendEnvironmentName, targetEnvironmentName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/environments/$(backendEnvironmentName)/clone", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("targetEnvironmentName"=>targetEnvironmentName), params)); aws_config=aws_config)

"""
    create_backend(app_id, app_name, backend_environment_name)
    create_backend(app_id, app_name, backend_environment_name, params::Dict{String,<:Any})

This operation creates a backend for an Amplify app. Backends are automatically created at
the time of app creation.

# Arguments
- `app_id`: The app ID.
- `app_name`: The name of the app.
- `backend_environment_name`: The name of the backend environment.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"resourceConfig"`: The resource configuration for the backend creation request.
- `"resourceName"`: The name of the resource.
"""
create_backend(appId, appName, backendEnvironmentName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend", Dict{String, Any}("appId"=>appId, "appName"=>appName, "backendEnvironmentName"=>backendEnvironmentName); aws_config=aws_config)
create_backend(appId, appName, backendEnvironmentName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("appId"=>appId, "appName"=>appName, "backendEnvironmentName"=>backendEnvironmentName), params)); aws_config=aws_config)

"""
    create_backend_api(app_id, backend_environment_name, resource_config, resource_name)
    create_backend_api(app_id, backend_environment_name, resource_config, resource_name, params::Dict{String,<:Any})

Creates a new backend API resource.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `resource_config`: The resource configuration for this request.
- `resource_name`: The name of this resource.

"""
create_backend_api(appId, backendEnvironmentName, resourceConfig, resourceName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api", Dict{String, Any}("backendEnvironmentName"=>backendEnvironmentName, "resourceConfig"=>resourceConfig, "resourceName"=>resourceName); aws_config=aws_config)
create_backend_api(appId, backendEnvironmentName, resourceConfig, resourceName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("backendEnvironmentName"=>backendEnvironmentName, "resourceConfig"=>resourceConfig, "resourceName"=>resourceName), params)); aws_config=aws_config)

"""
    create_backend_auth(app_id, backend_environment_name, resource_config, resource_name)
    create_backend_auth(app_id, backend_environment_name, resource_config, resource_name, params::Dict{String,<:Any})

Creates a new backend authentication resource.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `resource_config`: The resource configuration for this request object.
- `resource_name`: The name of this resource.

"""
create_backend_auth(appId, backendEnvironmentName, resourceConfig, resourceName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/auth", Dict{String, Any}("backendEnvironmentName"=>backendEnvironmentName, "resourceConfig"=>resourceConfig, "resourceName"=>resourceName); aws_config=aws_config)
create_backend_auth(appId, backendEnvironmentName, resourceConfig, resourceName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/auth", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("backendEnvironmentName"=>backendEnvironmentName, "resourceConfig"=>resourceConfig, "resourceName"=>resourceName), params)); aws_config=aws_config)

"""
    create_backend_config(app_id)
    create_backend_config(app_id, params::Dict{String,<:Any})

Creates a config object for a backend.

# Arguments
- `app_id`: The app ID.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"backendManagerAppId"`: The app ID for the backend manager.
"""
create_backend_config(appId; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/config"; aws_config=aws_config)
create_backend_config(appId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/config", params; aws_config=aws_config)

"""
    create_token(app_id)
    create_token(app_id, params::Dict{String,<:Any})

Generates a one-time challenge code to authenticate a user into your Amplify Admin UI.

# Arguments
- `app_id`: The app ID.

"""
create_token(appId; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/challenge"; aws_config=aws_config)
create_token(appId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/challenge", params; aws_config=aws_config)

"""
    delete_backend(app_id, backend_environment_name)
    delete_backend(app_id, backend_environment_name, params::Dict{String,<:Any})

Removes an existing environment from your Amplify project.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.

"""
delete_backend(appId, backendEnvironmentName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/environments/$(backendEnvironmentName)/remove"; aws_config=aws_config)
delete_backend(appId, backendEnvironmentName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/environments/$(backendEnvironmentName)/remove", params; aws_config=aws_config)

"""
    delete_backend_api(app_id, backend_environment_name, resource_name)
    delete_backend_api(app_id, backend_environment_name, resource_name, params::Dict{String,<:Any})

Deletes an existing backend API resource.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `resource_name`: The name of this resource.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"resourceConfig"`: Defines the resource configuration for the data model in your Amplify
  project.
"""
delete_backend_api(appId, backendEnvironmentName, resourceName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api/$(backendEnvironmentName)/remove", Dict{String, Any}("resourceName"=>resourceName); aws_config=aws_config)
delete_backend_api(appId, backendEnvironmentName, resourceName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api/$(backendEnvironmentName)/remove", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceName"=>resourceName), params)); aws_config=aws_config)

"""
    delete_backend_auth(app_id, backend_environment_name, resource_name)
    delete_backend_auth(app_id, backend_environment_name, resource_name, params::Dict{String,<:Any})

Deletes an existing backend authentication resource.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `resource_name`: The name of this resource.

"""
delete_backend_auth(appId, backendEnvironmentName, resourceName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/auth/$(backendEnvironmentName)/remove", Dict{String, Any}("resourceName"=>resourceName); aws_config=aws_config)
delete_backend_auth(appId, backendEnvironmentName, resourceName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/auth/$(backendEnvironmentName)/remove", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceName"=>resourceName), params)); aws_config=aws_config)

"""
    delete_token(app_id, session_id)
    delete_token(app_id, session_id, params::Dict{String,<:Any})

Deletes the challenge token based on the given appId and sessionId.

# Arguments
- `app_id`: The app ID.
- `session_id`: The session ID.

"""
delete_token(appId, sessionId; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/challenge/$(sessionId)/remove"; aws_config=aws_config)
delete_token(appId, sessionId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/challenge/$(sessionId)/remove", params; aws_config=aws_config)

"""
    generate_backend_apimodels(app_id, backend_environment_name, resource_name)
    generate_backend_apimodels(app_id, backend_environment_name, resource_name, params::Dict{String,<:Any})

Generates a model schema for an existing backend API resource.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `resource_name`: The name of this resource.

"""
generate_backend_apimodels(appId, backendEnvironmentName, resourceName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api/$(backendEnvironmentName)/generateModels", Dict{String, Any}("resourceName"=>resourceName); aws_config=aws_config)
generate_backend_apimodels(appId, backendEnvironmentName, resourceName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api/$(backendEnvironmentName)/generateModels", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceName"=>resourceName), params)); aws_config=aws_config)

"""
    get_backend(app_id)
    get_backend(app_id, params::Dict{String,<:Any})

Provides project-level details for your Amplify UI project.

# Arguments
- `app_id`: The app ID.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"backendEnvironmentName"`: The name of the backend environment.
"""
get_backend(appId; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/details"; aws_config=aws_config)
get_backend(appId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/details", params; aws_config=aws_config)

"""
    get_backend_api(app_id, backend_environment_name, resource_name)
    get_backend_api(app_id, backend_environment_name, resource_name, params::Dict{String,<:Any})

Gets the details for a backend API.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `resource_name`: The name of this resource.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"resourceConfig"`: Defines the resource configuration for the data model in your Amplify
  project.
"""
get_backend_api(appId, backendEnvironmentName, resourceName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api/$(backendEnvironmentName)/details", Dict{String, Any}("resourceName"=>resourceName); aws_config=aws_config)
get_backend_api(appId, backendEnvironmentName, resourceName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api/$(backendEnvironmentName)/details", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceName"=>resourceName), params)); aws_config=aws_config)

"""
    get_backend_apimodels(app_id, backend_environment_name, resource_name)
    get_backend_apimodels(app_id, backend_environment_name, resource_name, params::Dict{String,<:Any})

Generates a model schema for existing backend API resource.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `resource_name`: The name of this resource.

"""
get_backend_apimodels(appId, backendEnvironmentName, resourceName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api/$(backendEnvironmentName)/getModels", Dict{String, Any}("resourceName"=>resourceName); aws_config=aws_config)
get_backend_apimodels(appId, backendEnvironmentName, resourceName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api/$(backendEnvironmentName)/getModels", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceName"=>resourceName), params)); aws_config=aws_config)

"""
    get_backend_auth(app_id, backend_environment_name, resource_name)
    get_backend_auth(app_id, backend_environment_name, resource_name, params::Dict{String,<:Any})

Gets backend auth details.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `resource_name`: The name of this resource.

"""
get_backend_auth(appId, backendEnvironmentName, resourceName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/auth/$(backendEnvironmentName)/details", Dict{String, Any}("resourceName"=>resourceName); aws_config=aws_config)
get_backend_auth(appId, backendEnvironmentName, resourceName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/auth/$(backendEnvironmentName)/details", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceName"=>resourceName), params)); aws_config=aws_config)

"""
    get_backend_job(app_id, backend_environment_name, job_id)
    get_backend_job(app_id, backend_environment_name, job_id, params::Dict{String,<:Any})

Returns information about a specific job.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `job_id`: The ID for the job.

"""
get_backend_job(appId, backendEnvironmentName, jobId; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("GET", "/backend/$(appId)/job/$(backendEnvironmentName)/$(jobId)"; aws_config=aws_config)
get_backend_job(appId, backendEnvironmentName, jobId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("GET", "/backend/$(appId)/job/$(backendEnvironmentName)/$(jobId)", params; aws_config=aws_config)

"""
    get_token(app_id, session_id)
    get_token(app_id, session_id, params::Dict{String,<:Any})

Gets the challenge token based on the given appId and sessionId.

# Arguments
- `app_id`: The app ID.
- `session_id`: The session ID.

"""
get_token(appId, sessionId; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("GET", "/backend/$(appId)/challenge/$(sessionId)"; aws_config=aws_config)
get_token(appId, sessionId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("GET", "/backend/$(appId)/challenge/$(sessionId)", params; aws_config=aws_config)

"""
    list_backend_jobs(app_id, backend_environment_name)
    list_backend_jobs(app_id, backend_environment_name, params::Dict{String,<:Any})

Lists the jobs for the backend of an Amplify app.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"jobId"`: The ID for the job.
- `"maxResults"`: The maximum number of results that you want in the response.
- `"nextToken"`: The token for the next set of results.
- `"operation"`: Filters the list of response objects to include only those with the
  specified operation name.
- `"status"`: Filters the list of response objects to include only those with the specified
  status.
"""
list_backend_jobs(appId, backendEnvironmentName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/job/$(backendEnvironmentName)"; aws_config=aws_config)
list_backend_jobs(appId, backendEnvironmentName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/job/$(backendEnvironmentName)", params; aws_config=aws_config)

"""
    remove_all_backends(app_id)
    remove_all_backends(app_id, params::Dict{String,<:Any})

Removes all backend environments from your Amplify project.

# Arguments
- `app_id`: The app ID.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"cleanAmplifyApp"`: Cleans up the Amplify Console app if this value is set to true.
"""
remove_all_backends(appId; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/remove"; aws_config=aws_config)
remove_all_backends(appId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/remove", params; aws_config=aws_config)

"""
    remove_backend_config(app_id)
    remove_backend_config(app_id, params::Dict{String,<:Any})

Removes the AWS resources that are required to access the Amplify Admin UI.

# Arguments
- `app_id`: The app ID.

"""
remove_backend_config(appId; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/config/remove"; aws_config=aws_config)
remove_backend_config(appId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/config/remove", params; aws_config=aws_config)

"""
    update_backend_api(app_id, backend_environment_name, resource_name)
    update_backend_api(app_id, backend_environment_name, resource_name, params::Dict{String,<:Any})

Updates an existing backend API resource.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `resource_name`: The name of this resource.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"resourceConfig"`: Defines the resource configuration for the data model in your Amplify
  project.
"""
update_backend_api(appId, backendEnvironmentName, resourceName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api/$(backendEnvironmentName)", Dict{String, Any}("resourceName"=>resourceName); aws_config=aws_config)
update_backend_api(appId, backendEnvironmentName, resourceName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/api/$(backendEnvironmentName)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceName"=>resourceName), params)); aws_config=aws_config)

"""
    update_backend_auth(app_id, backend_environment_name, resource_config, resource_name)
    update_backend_auth(app_id, backend_environment_name, resource_config, resource_name, params::Dict{String,<:Any})

Updates an existing backend authentication resource.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `resource_config`: The resource configuration for this request object.
- `resource_name`: The name of this resource.

"""
update_backend_auth(appId, backendEnvironmentName, resourceConfig, resourceName; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/auth/$(backendEnvironmentName)", Dict{String, Any}("resourceConfig"=>resourceConfig, "resourceName"=>resourceName); aws_config=aws_config)
update_backend_auth(appId, backendEnvironmentName, resourceConfig, resourceName, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/auth/$(backendEnvironmentName)", Dict{String, Any}(mergewith(_merge, Dict{String, Any}("resourceConfig"=>resourceConfig, "resourceName"=>resourceName), params)); aws_config=aws_config)

"""
    update_backend_config(app_id)
    update_backend_config(app_id, params::Dict{String,<:Any})

Updates the AWS resources that are required to access the Amplify Admin UI.

# Arguments
- `app_id`: The app ID.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"loginAuthConfig"`: Describes the Amazon Cognito configuration for Admin UI access.
"""
update_backend_config(appId; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/config/update"; aws_config=aws_config)
update_backend_config(appId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/config/update", params; aws_config=aws_config)

"""
    update_backend_job(app_id, backend_environment_name, job_id)
    update_backend_job(app_id, backend_environment_name, job_id, params::Dict{String,<:Any})

Updates a specific job.

# Arguments
- `app_id`: The app ID.
- `backend_environment_name`: The name of the backend environment.
- `job_id`: The ID for the job.

# Optional Parameters
Optional parameters can be passed as a `params::Dict{String,<:Any}`. Valid keys are:
- `"operation"`: Filters the list of response objects to include only those with the
  specified operation name.
- `"status"`: Filters the list of response objects to include only those with the specified
  status.
"""
update_backend_job(appId, backendEnvironmentName, jobId; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/job/$(backendEnvironmentName)/$(jobId)"; aws_config=aws_config)
update_backend_job(appId, backendEnvironmentName, jobId, params::AbstractDict{String}; aws_config::AbstractAWSConfig=global_aws_config()) = amplifybackend("POST", "/backend/$(appId)/job/$(backendEnvironmentName)/$(jobId)", params; aws_config=aws_config)


text:
abstract type CNFLayer <: Function end
Flux.trainable(m::CNFLayer) = (m.p,)

struct FFJORD{M,P,RE,Distribution,Bool,T,A,K} <: CNFLayer
    model::M
    p::P
    re::RE
    basedist::Distribution
    monte_carlo::Bool
    tspan::T
    args::A
    kwargs::K

    function FFJORD(model,tspan,args...;p = nothing,basedist=nothing,monte_carlo=false,kwargs...)
        _p,re = Flux.destructure(model)
        if p === nothing
            p = _p
        end
        if basedist === nothing
            size_input = size(model[1].W)[2]
            basedist = MvNormal(zeros(size_input), I + zeros(size_input,size_input))
        end
        new{typeof(model),typeof(p),typeof(re),typeof(basedist),
            typeof(monte_carlo),typeof(tspan),typeof(args),typeof(kwargs)}(
            model,p,re,basedist,monte_carlo,tspan,args,kwargs)
    end
end

function jacobian_fn(f, x::AbstractVector)
   y::AbstractVector, back = Zygote.pullback(f, x)
   ȳ(i) = [i == j for j = 1:length(y)]
   vcat([transpose(back(ȳ(i))[1]) for i = 1:length(y)]...)
 end

function ffjord(du,u,p,t,re,monte_carlo,e)
    z = @view u[1:end-1]
    m = re(p)
    if monte_carlo
        _, back = Zygote.pullback(m,z)
        eJ = back(e)[1]
        trace_jac = (eJ.*e)[1]
    else
        J = jacobian_fn(m, z)
        trace_jac = length(z) == 1 ? sum(J) : tr(J)
    end
    du[1:end-1] = m(z)
    du[end] = -trace_jac
end

function (n::FFJORD)(x,p=n.p,monte_carlo=n.monte_carlo)
    e = monte_carlo ? randn(Float32,length(x)) : nothing
    ffjord_ = (du,u,p,t)->ffjord(du,u,p,t,n.re,monte_carlo,e)
    prob = ODEProblem{true}(ffjord_,vcat(x,0f0),n.tspan,p)
    pred = solve(prob,Tsit5(),n.args...;n.kwargs...)[:,end]
    pz = n.basedist
    z = pred[1:end-1]
    delta_logp = pred[end]
    logpz = log.(pdf(pz, z))
    logpx = logpz .- delta_logp
    return logpx[1]
end

ext: jl


text:
module SIMDAlignment

export
    # wrapper types
    seq_t,
    submat_t,
    alignment_t,
    # functions
    paralign_score

import Bio
using Bio.Seq
using Bio.Align

# 1-byte alphabets
typealias Byte Union{Int8,UInt8,DNANucleotide,RNANucleotide,AminoAcid}

# sequence
immutable seq_t
    data::Ptr{UInt8}
    len::Csize_t
    offset::Csize_t
    reversed::Bool
    packed::Bool
end

function Base.convert{T<:Byte}(::Type{seq_t}, seq::Vector{T})
    return seq_t(pointer(seq), length(seq), 0, false, false)
end

function Base.call(::Type{seq_t}, seq::Vector, offset::Int=0, reversed::Bool=false)
    return seq_t(pointer(seq), length(seq), offset, reversed, false)
end

function Base.convert(::Type{seq_t}, seq::NucleotideSequence)
    byteseq = reinterpret(UInt8, seq.data)
    return seq_t(pointer(byteseq), length(seq), seq.part.start - 1, false, true)
end

function Base.call{T}(::Type{seq_t}, seq::NucleotideSequence{T}, reversed::Bool=false)
    byteseq = reinterpret(UInt8, seq.data)
    len = length(seq)
    if len == 0
        offset = 0
    else
        offset = (reversed ? seq.part.stop : seq.part.start) - 1
    end
    return seq_t(pointer(byteseq), length(seq), offset, reversed, true)
end

# substitution matrix
immutable submat_t{T}
    data::Ptr{T}
    size::Cint
end

function Base.convert{T}(::Type{submat_t}, submat::Matrix{T})
    m, n = size(submat)
    @assert m == n
    return submat_t{T}(pointer(submat), convert(Cint, n))
end

function Base.convert{T}(::Type{submat_t}, submat::SubstitutionMatrix{T})
    return submat_t(submat.data)
end

# alignment result
type alignment_t
    score::Int64
    trace::Ptr{UInt8}
    seqlen::Csize_t
    reflen::Csize_t
    endpos_seq::Csize_t
    endpos_ref::Csize_t
    function alignment_t()
        return new(0, C_NULL, 0, 0, 0, 0)
    end
end

function Bio.Align.score(aln::alignment_t)
    return aln.score
end

function Base.show(io::IO, aln::alignment_t)
    print(io, aln.score)
end

const libsimdalign = Pkg.dir("SIMDAlignment", "deps", "libsimdalign.so")

function make_buffer()
    buffer = ccall((:make_buffer, libsimdalign), Ptr{Void}, ())
    @assert buffer != C_NULL "failed to allocate a buffer"
    return buffer
end

function free_buffer(buffer)
    ccall((:free_buffer, libsimdalign), Void, (Ptr{Void},), buffer)
end

@generated function paralign_score{score_t}(submat::Matrix{score_t}, gap_open::score_t, gap_extend::score_t, seq::seq_t, refs::Vector{seq_t})
    func = score_t === Int8  ? :(:paralign_score_i8x32)  :
           score_t === Int16 ? :(:paralign_score_i16x16) :
           score_t === Int32 ? :(:paralign_score_i32x8) :
           error("not supported type: $score_t")
    quote
        alns = Vector{alignment_t}()
        for _ in 1:length(refs)
            push!(alns, alignment_t())
        end
        buffer = make_buffer()
        ret = ccall(
            ($(func), libsimdalign),
            Cint,
            (Ptr{Void}, submat_t{score_t}, score_t, score_t, seq_t, Ptr{seq_t}, Cint, Ptr{Void}),
            buffer, submat_t(submat), gap_open, gap_extend, seq, pointer(refs), length(refs), alns
        )
        free_buffer(buffer)
        @assert ret == 0 "failed to align"
        return alns
    end
end

function paralign_score{score_t}(submat::Union{Matrix{score_t},SubstitutionMatrix{score_t}}, gap_open, gap_extend, seq, refs)
    paralign_score(
        convert(Matrix{score_t}, submat),
        score_t(gap_open),
        score_t(gap_extend),
        seq_t(seq),
        [seq_t(ref) for ref in refs]
    )
end

end # module


text:
include("../base.jl")

import Random
println("hola")
println("hola")
println("hola")

f(x, y) = (y/5.5)+x^2

println("hola")
println("hola")
x = collect(-5:0.5:5)
y = collect(0:0.5:10)
nvalues = length(x)
objs = Array{Number}(undef, nvalues)
for i=1:nvalues
    objs[i] = f(x[i], y[i])
end

setIndividualType(CGPGenotype)
setRandomSeed(54)
setGPExperimentInfo()
setStopCondition(maxIterations=1000)
setEvaluator([FitnessFunction(compareFunctions, objs, x, y, weight=-1)])
setGenerator(rampedHalfHalfGenerator, popSize = 100, generateOneByOne = false)
setSelector(tournamentSelector, 4, nSelected=2)
setCrossoverOperator(subtreeCross, probability=0.9)
setMutationOperator(pointMutation, 0.2, probability=0.1)
setReplacementOperator(replaceWorstIndividuals, needsComparison=true)

@time runGenJ(verbose=false)

max_stars_repo_name: SergioGmezM/GeneticJulia

max_issues_repo_name: SergioGmezM/GeneticJulia

max_forks_repo_name: SergioGmezM/GeneticJulia


text:
module NormalTest

using Test
using ReactiveMP
using Random
using LinearAlgebra
using Distributions

@testset "Normal" begin

    @testset "Univariate conversions" begin

        check_basic_statistics = (left, right) -> begin
            @test mean(left)         ≈ mean(right)
            @test median(left)       ≈ median(right)
            @test mode(left)         ≈ mode(right)
            @test weightedmean(left) ≈ weightedmean(right)
            @test var(left)          ≈ var(right)
            @test std(left)          ≈ std(right)
            @test cov(left)          ≈ cov(right)
            @test invcov(left)       ≈ invcov(right)
            @test precision(left)    ≈ precision(right)
            @test entropy(left)      ≈ entropy(right)
            @test pdf(left, 1.0)     ≈ pdf(right, 1.0)
            @test pdf(left, -1.0)    ≈ pdf(right, -1.0)
            @test pdf(left, 0.0)     ≈ pdf(right, 0.0)
            @test logpdf(left, 1.0)  ≈ logpdf(right, 1.0)
            @test logpdf(left, -1.0) ≈ logpdf(right, -1.0)
            @test logpdf(left, 0.0)  ≈ logpdf(right, 0.0)
        end

        types  = ReactiveMP.union_types(UnivariateNormalDistributionsFamily{Float64})
        etypes = ReactiveMP.union_types(UnivariateNormalDistributionsFamily)

        rng   = MersenneTwister(1234)

        for type in types
            left = convert(type, rand(rng, Float64), rand(rng, Float64))
            for type in [ types..., etypes... ]
                right = convert(type, left)
                check_basic_statistics(left, right)

                p1 = prod(ProdPreserveTypeLeft(), left, right)
                @test typeof(p1) <: typeof(left)

                p2 = prod(ProdPreserveTypeRight(), left, right)
                @test typeof(p2) <: typeof(right)

                p3 = prod(ProdAnalytical(), left, right)

                check_basic_statistics(p1, p2)
                check_basic_statistics(p2, p3)
                check_basic_statistics(p1, p3)
            end
        end

    end

    @testset "Multivariate conversions" begin

        check_basic_statistics = (left, right, dims) -> begin
            @test mean(left)         ≈ mean(right)
            @test mode(left)         ≈ mode(right)
            @test weightedmean(left) ≈ weightedmean(right)
            @test var(left)          ≈ var(right)
            @test cov(left)          ≈ cov(right)
            @test invcov(left)       ≈ invcov(right)
            @test logdetcov(left)    ≈ logdetcov(right)
            @test precision(left)    ≈ precision(right)
            @test length(left)       === length(right)
            @test ndims(left)        === ndims(right)
            @test size(left)         === size(right)
            @test entropy(left)      ≈ entropy(right)
            @test all(mean_cov(left) .≈ mean_cov(right))
            @test all(mean_invcov(left) .≈ mean_invcov(right))
            @test all(mean_precision(left) .≈ mean_precision(right))
            @test all(weightedmean_cov(left) .≈ weightedmean_cov(right))
            @test all(weightedmean_invcov(left) .≈ weightedmean_invcov(right))
            @test all(weightedmean_precision(left) .≈ weightedmean_precision(right))
            @test pdf(left, fill(1.0, dims))  ≈ pdf(right, fill(1.0, dims))
            @test pdf(left, fill(-1.0, dims)) ≈ pdf(right, fill(-1.0, dims))
            @test pdf(left, fill(0.0, dims))  ≈ pdf(right, fill(0.0, dims))
            @test logpdf(left, fill(1.0, dims))  ≈ logpdf(right, fill(1.0, dims))
            @test logpdf(left, fill(-1.0, dims)) ≈ logpdf(right, fill(-1.0, dims))
            @test logpdf(left, fill(0.0, dims))  ≈ logpdf(right, fill(0.0, dims))
        end

        types  = ReactiveMP.union_types(MultivariateNormalDistributionsFamily{Float64})
        etypes = ReactiveMP.union_types(MultivariateNormalDistributionsFamily)

        dims  = (2, 3, 5)
        rng   = MersenneTwister(1234)

        for dim in dims
            for type in types
                left = convert(type, rand(rng, Float64, dim), Matrix(Diagonal(rand(rng, Float64, dim))))
                for type in [ types..., etypes... ]
                    right = convert(type, left)
                    check_basic_statistics(left, right, dim)

                    p1 = prod(ProdPreserveTypeLeft(), left, right)
                    @test typeof(p1) <: typeof(left)

                    p2 = prod(ProdPreserveTypeRight(), left, right)
                    @test typeof(p2) <: typeof(right)

                    p3 = prod(ProdAnalytical(), left, right)

                    check_basic_statistics(p1, p2, dim)
                    check_basic_statistics(p2, p3, dim)
                    check_basic_statistics(p1, p3, dim)
                end
            end
        end

    end

    @testset "Variate forms promotions" begin

        @test promote_variate_type(Univariate, NormalMeanVariance)          === NormalMeanVariance
        @test promote_variate_type(Univariate, NormalMeanPrecision)         === NormalMeanPrecision
        @test promote_variate_type(Univariate, NormalWeightedMeanPrecision) === NormalWeightedMeanPrecision

        @test promote_variate_type(Multivariate, NormalMeanVariance)          === MvNormalMeanCovariance
        @test promote_variate_type(Multivariate, NormalMeanPrecision)         === MvNormalMeanPrecision
        @test promote_variate_type(Multivariate, NormalWeightedMeanPrecision) === MvNormalWeightedMeanPrecision

        @test promote_variate_type(Univariate, MvNormalMeanCovariance)        === NormalMeanVariance
        @test promote_variate_type(Univariate, MvNormalMeanPrecision)         === NormalMeanPrecision
        @test promote_variate_type(Univariate, MvNormalWeightedMeanPrecision) === NormalWeightedMeanPrecision

        @test promote_variate_type(Multivariate, MvNormalMeanCovariance)        === MvNormalMeanCovariance
        @test promote_variate_type(Multivariate, MvNormalMeanPrecision)         === MvNormalMeanPrecision
        @test promote_variate_type(Multivariate, MvNormalWeightedMeanPrecision) === MvNormalWeightedMeanPrecision

    end

    @testset "Sampling" begin
        rng = MersenneTwister(1234)

        univariate_types = [
            ReactiveMP.union_types(UnivariateNormalDistributionsFamily{Float64})...,
            ReactiveMP.union_types(UnivariateNormalDistributionsFamily{Float32})...
        ]

        for T in (Float32, Float64)
            let # NormalMeanVariance
                μ, v = 10randn(rng), 10rand(rng)
                d    = convert(NormalMeanVariance{T}, μ, v)

                @test typeof(rand(d) ) <: T

                samples = rand(rng, d, 5_000)

                @test isapprox(mean(samples), μ, atol = 0.5)
                @test isapprox(var(samples), v, atol = 0.5)
            end

            let # NormalMeanPrecision
                μ, w = 10randn(rng), 10rand(rng)
                d    = convert(NormalMeanPrecision{T}, μ, w)

                @test typeof(rand(d) ) <: T

                samples = rand(rng, d, 5_000)

                @test isapprox(mean(samples), μ, atol = 0.5)
                @test isapprox(inv(var(samples)), w, atol = 0.5)
            end

            let # WeightedMeanPrecision
                wμ, w = 10randn(rng), 10rand(rng)
                d     = convert(NormalWeightedMeanPrecision{T}, wμ, w)

                @test typeof(rand(d) ) <: T

                samples = rand(rng, d, 5_000)

                @test isapprox(inv(var(samples)) * mean(samples), wμ, atol = 0.5)
                @test isapprox(inv(var(samples)), w, atol = 0.5)
            end
        end

    end

end

end


text:
using .CUDA

function midpoint_definite_integral_cu(f, xmin, xmax, N)
    x = cu(collect(range(xmin, length = N, stop = xmax)))
    dx = (xmax - xmin) / (N - 1)
    # sum_ = zero(typeof(f(xmin))) * dx * 0
    # for x_ in x
    #     x_ != 0 && !isnan(f(x_)) && (sum_ += f(x_) * dx)
    # end
    return sum(f.(x) .* dx)
end

include("../methods/cuda/carrmadan.jl")
include("../methods/cuda/lewis.jl")
include("../methods/cuda/carrmadan_lewis.jl")


text:
module Absynth

using MacroTools: walk, postwalk, prewalk, @capture, @match, replace, striplines
using Combinatorics
using LinearAlgebra
using MultivariatePolynomials
using DynamicPolynomials
using Dates
using DataFrames: DataFrame, unstack, rename!
using ProgressMeter

const Var = AbstractVariable
const Poly = AbstractPolynomialLike
const SymOrNum = Union{Symbol,Number}

include("nlsat/NLSat.jl")

using Absynth.NLSat

export Z3Solver, SMTSolver, SMTSolverZ3, SMTSolverYices

include("utils.jl")
include("poly.jl")
include("invariant.jl")
include("cfinite.jl")
include("show.jl")
include("template.jl")
include("types.jl")
include("iterators.jl")

export FullSymbolic, UpperTriangular, UnitUpperTriangular, Companion, UserSpecific
export Invariant, @invariant
export solutions, models, synth
export RecSystem, loop
export RecTemplate
export AllPermutations, FixedPermutations
export AllPartitions, FixedPartitions
export Strategy
export @cstr

include("../benchmark/examples.jl")

end # module


text:
######### StanSample Bernoulli example  ###########

using StanSample, DataFrames

bernoulli_model = "
data {
  int<lower=1> N;
  int<lower=0,upper=1> y[N];
}
parameters {
  real<lower=0,upper=1> theta;
}
model {
  theta ~ beta(1,1);
  y ~ bernoulli(theta);
}
";

bernoulli_data = [
  Dict("N" => 10, "y" => [0, 1, 0, 0, 0, 0, 0, 0, 0, 0]),
  Dict("N" => 10, "y" => [0, 1, 0, 1, 0, 0, 0, 0, 0, 1]),
  Dict("N" => 10, "y" => [0, 1, 0, 1, 0, 1, 1, 0, 0, 1]),
  Dict("N" => 10, "y" => [1, 1, 1, 1, 1, 1, 1, 1, 0, 1])
]

# Keep tmpdir across multiple runs to prevent re-compilation

sm = SampleModel("bernoulli", bernoulli_model);
rc = stan_sample(sm; data=bernoulli_data);

if success(rc)
  dfa = read_samples(sm;
    output_format=:dataframes,
    include_internals=true
  )

  for i in 1:size(dfa, 1)
    mean(Array(dfa[i]), dims=1) |> display
  end
end


text:
using PlanOut
using Base.Test

tests = ["core_ops", "random_ops"]

for t in tests
    fp = joinpath(dirname(@__FILE__), "test_$t.jl")
    println("$fp ...")
    include(fp)
end


text:
##
# give a stream view to a block from any seekable iostream
immutable BlockIO <: IO
    s::IO
    r::UnitRange
    l::Int

    function find_end_pos(bio::BlockIO, end_byte::Char)
        seekend(bio)
        try
            while(!eof(bio.s) && (end_byte != read(bio, UInt8))) continue end
        end
        position(bio.s)
    end
    function find_start_pos(bio::BlockIO, end_byte::Char)
        (bio.r.start == 1) && (return bio.r.start)
        seekstart(bio)
        !eof(bio.s) && while(end_byte != read(bio, UInt8)) continue end
        position(bio.s)+1
    end

    function BlockIO(s::IO, r::UnitRange, match_ends::Union{Char,Void}=nothing)
        # TODO: use mark when available
        seekend(s)
        ep = position(s)

        r = min(r.start,ep+1):min(r.start+length(r)-1,ep)
        bio = new(s, r, length(r))
        if(nothing != match_ends)
            p1 = find_start_pos(bio, match_ends)
            p2 = find_end_pos(bio, match_ends)
            r = p1:p2
            bio = new(s, r, length(r))
        end
        seekstart(bio)
        bio
    end
end

BlockIO(bio::BlockIO, match_ends::Union{Char,Void}=nothing) = BlockIO(bio.s, bio.r, match_ends)

close(bio::BlockIO) = close(bio.s)
eof(bio::BlockIO) = (position(bio) >= bio.l)
read(bio::BlockIO, x::Type{UInt8}) = read(bio.s, x)
read!(bio::BlockIO, a::Vector{UInt8}) = (length(a) <= nb_available(bio)) ? read!(bio.s, a) : throw(EOFError())
read!{T}(bio::BlockIO, a::Array{T}) = (length(a)*sizeof(T) <= nb_available(bio)) ? read!(bio.s, a) : throw(EOFError())

readbytes(bio::BlockIO, nb::Integer) = bytestring(read!(bio, Array(UInt8, nb)))
readall(bio::BlockIO) = readbytes(bio, nb_available(bio))

peek(bio::BlockIO) = peek(bio.s)
write(bio::BlockIO, p::Ptr, nb::Integer) = write(bio, p, int(nb))
write(bio::BlockIO, p::Ptr, nb::Int) = write(bio.s, p, nb)
write(bio::BlockIO, x::UInt8) = write(bio, UInt8[x])
write{T}(bio::BlockIO, a::Array{T}, len) = write_sub(bio, a, 1, len)
write{T}(bio::BlockIO, a::Array{T}) = write(bio, a, length(a))
write_sub{T}(bio::BlockIO, a::Array{T}, offs, len) = isbits(T) ? write(bio, pointer(a,offs), len*sizeof(T)) : error("$T is not bits type")

nb_available(bio::BlockIO) = (bio.l - position(bio))
position(bio::BlockIO) = position(bio.s) - bio.r.start + 1

filesize(bio::BlockIO) = bio.l

seek(bio::BlockIO, n::Integer) = seek(bio.s, n+bio.r.start-1)
seekend(bio::BlockIO) = seek(bio, filesize(bio))
seekstart(bio::BlockIO) = seek(bio, 0)
skip(bio::BlockIO, n::Integer) = seek(bio, n+position(bio))


text:
#=
This file is part of Pseudospectra.jl.

Julia translation
copyright 2017 Ralph Smith

Portions derived from EigTool
Copyright (c) 2002-2014, The Chancellor, Masters and Scholars
of the University of Oxford, and the EigTool Developers. All rights reserved.

SPDX-License-Identifier: BSD-3-Clause
License-Filename: LICENSES/BSD-3-Clause_Eigtool
=#

"""
    grcar(N)

construct a Grcar non-normal matrix of rank N

This is a popular example in the field of matrix iterations
of a matrix whose spectrum is in the right half-plane but
whose numerical range is not.  It's also a popular example
in the study of nonsymmetric Toeplitz matrices.  The matrix
was first described in [^Grcar1989] and its pseudospectra were first
plotted in [^Trefethen1991].

[^Grcar1989]: J. F. Grcar, "Operator coefficient methods for linear equations", tech. report SAND89-8691, Sandia National Labs, 1989
[^Trefethen1991]: L. N. Trefethen, "Psuedospectra of matrices", in "Numerical Analysis 1991" (Dundee 1991), Longman Sci. Tech., Harlow, 1992, 234-266.
"""
function grcar(N::Integer)
  G = (diagm(0 => ones(N)) - diagm(-1 => ones(N-1)) +
      diagm(1 => ones(N-1)) + diagm(2 => ones(N-2)) +
      diagm(3 => ones(N-3)))
end

"""
    cheb(N)

construct a matrix representing differentiation of rank N+1 Chebyshev
value-space basis, based on [Trefethen2000]

[^Trefethen2000] L.N.Trefethen, *Spectral Methods in MATLAB*, SIAM, Philadelphia, 2000.
"""
function cheb(N::Integer)
    if N==0
        return 0.0,1.0
    end
    x = cos.((π/N)*collect(0:N))
    c = vcat(2,ones(N-1),2) .* map(x -> (-1)^x,0:N)
    dX = x .- x'
    D = (c*(1 ./ c)') ./ (dX + I)
    D = D - diagm(0 => vec(sum(D, dims=2)))
    return D,x
end

"""
    advdiff(N,η=0.015)

construct the matrix representing an advection-diffusion operator via
Chebyshev collocation.
"""
function advdiff(N,η=0.015)
    D,x = cheb(N)
    # rescale to interval 0:1
    D = 2*D
    x = (x .+ 1)*(1/2)
    L = η*D^2 + D
    # impose boundary conditions
    L = L[2:N,2:N]
    # Gauss-Chebyshev quadratrure weights
    w = sqrt.(π*sqrt.(x-x.^2)*(1/(2N)))
    # convert to L2 norm on function space
    w = w[2:N]
    L = diagm(0 => w) * L * diagm(0 => 1.0 ./ w)
end

"""
    orrsommerfeld(N,R=5722,α=1.0)

construct a matrix representing the Orr-Sommerfeld operator in the
rank N+1 Chebyshev value-space basis.
Note: this imposes a norm of dubious physical meaning, since a clever
trick is used to suppress spurious eigenvalues.

[^HS1994] W.Z.Huang and D.M.Sloan, "The pseudospectral method for solving differential eigenvalue equations," J. Comput. Phys. 111, 399-409 (1994).
"""
function orrsommerfeld(N,R=5722,α=1.0)
    D,x = cheb(N)
    D2 = D^2
    D2 = D2[2:N,2:N]
    S = diagm(0 => [0; 1 ./(1 .- x[2:N].^2); 0])
    D4 = (diagm(0 => 1 .- x.^2)*D^4 - 8*diagm(0 => x)*D^3 - 12*D^2)*S
    D4 = D4[2:N,2:N]
    a2 = α^2
    A = (D4-2*a2*D2+a2^2*I)*(1/R) - 2α*im*I - α*im*diagm(0 => 1 .- x[2:N].^2)*(D2-a2*I)
    B = D2-a2*I
    C = B\A
end

"""
    trefethen_tutorial(N) -> B,A

compute the matrices used for tutorial purposes
in [^Trefethen1999]. `A` is the Chebyshev discretization
of a Schrödinger operator with complex potential.
`B` includes weight factors so that a basic L2 norm is appropriate.

[^Trefethen1999]: L.N.Trefethen, "Computation of Pseudospectra", Acta Numerica 1999.
"""
function trefethen_tutorial(N)
    D = zeros(N+2,N+2)
    iran = 0:(N+1)
    ci = vcat(2,ones(N),2)
    x = cos(π*iran*(1/(N+1)))
    for j=0:N+1
        cj = ((j==0) || (j==N+1)) ? 2 : 1
        denom = cj * (x[iran+1]-x[j+1])
        denom[j+1] = 1
        D[iran+1,j+1] = ci .* (-1.0).^(iran+j) ./ denom
        if (j > 0) && (j<N+1)
            D[j+1,j+1] = -(1/2)*x[j+1] / (1-x[j+1]^2)
        end
    end
    D[1,1] = (2*(N+1)^2+1)/6
    D[N+2,N+2] = -(2*(N+1)^2+1)/6
    L = 10.0
    D = D / L
    A = D^2
    # absorb boundary conditions
    x = x[2:N+1]
    x = L*x
    A = A[2:N+1,2:N+1]
    A = A + (3+3im) * diagm(0 => x.^2) - (1/16)*diagm(0=> x.^4)
    # absorb Chebyshev weights
    w = sqrt.(π*sqrt(L^2 - x.^2) * (1 / (2*(N+1))))
    B = zeros(eltype(A),N,N)
    for j=1:N
        B[:,j] = w .* A[:,j] * (1/w[j])
    end
    B,A
end

"""
    convdiff_fd(N)

construct matrix representation of 2-D NxN convection-diffusion operator

convdiff_fd(N) returns matrix C of dimension N^2 representing the
operator
         -ϵ ∇^2 u  + ∂u/∂y

on the unit square with Dirichlet boundary conditions. The
discretisation is done using finite differences (see, e.g., [^Hemmingsson1998]),
resulting in large, sparse matrices. The code is based on a
routine by Daniel Loghin.

[^Hemmingsson1998]: L. Hemmingsson, "A Semi-circulant Preconditioner for the Convection-Diffusion Equation", Numer. Math 81, 211-248 (1998).

"""
function convdiff_fd(N)

    # Diffusion parameter
    e = 1e-2

    # Wind blowing in y-direction.
    w1 = 0
    w2 = 1

    # Set up the grid size (more points in y direction due to wind)
    n1 = N
    n2 = 4*N
    h1 = 1/(n1+1)
    h2 = 1/(n2+1)

    # Generate 1D finite difference matrices
    alpha1 = w1/h1
    beta1 = 2*e/h1^2
    alpha2 = w2/h2
    beta2 = 2*e/h2^2

    A1 = spdiagm(-1 => (-alpha1-beta1)*ones(n1-1),
                  0 => 2*beta1*ones(n1),
                  1 => (alpha1-beta1)*ones(n1-1))
    A2 = spdiagm(-1 => (-alpha2-beta2)*ones(n2-1),
                  0 => 2*beta2*ones(n2),
                  1 => (alpha2-beta2)*ones(n2-1))

    # Now compute the 2D finite difference matrix
    C = kron(sparse(1.0I,n2,n2),A1) + kron(A2,sparse(1.0I,n1,n1))
end

function gallery5(T=Float64)
    @assert T <: Real
    A = hcat([-9,70,-575,3891,1024],
             [11,-69,575,-3891,-1024],
             [-21,141,-1149,7782,2048],
             [63,-421,3451,-23345,-6144],
             [-252,1684,-13801,93365,24572])
    Matrix{T}(A)
end

"""
    kahan(N)

construct Kahan's matrix of rank N

Kahan's matrix [^Kahan1966] was devised to illustrate that QR
factorisation with column pivoting is not a fail-safe
method for determining the rank of the matrix. Rank
determination is related to the "distance to singularity"
of a matrix [^Higham1988], or in other words, how large a perturbation
is needed to make the matrix singular. The pseudospectra are
shown in [^Trefethen1991].

[^Higham1988]: N. J. Higham, "Matrix nearness problems and applications", NA Rep. 161, Dept. of Maths., U. of Manchester, June 1988.
[^Kahan1966]: W. Kahan, "Numerical linear algebra", Canad. Math. Bull. 9, pp. 757-801, 1966.
[^Trefethen1991]: L. N. Trefethen, "Psuedospectra of matrices", in "Numerical Analysis 1991" (Dundee 1991), Longman Sci. Tech., Harlow, 1992, 234-266.
"""
function kahan(N)
    s = (1/10)^(1/(N-1))
    c = sqrt(1-s^2)

    col = -s.^(0:N-1)*c
    K = triu(repmat(col,1,N),1)+diagm(0 => s.^(0:N-1))
end

"""
    demmel(N,M)

construct Demmel's matrix of rank N with edge value M

Demmel's matrix was perhaps the first matrix
whose pseudospectra (with N=3) appeared in [^Demmel1987]
Demmel devised the matrix in order to disprove
a conjecture of Van Loan's [^VanLoan1985].

[^Demmel1987]: J. W. Demmel, "A counterexample for two conjectures about stability", IEEE Trans. Auto. Control, AC-32, pp. 340-343, 1987.
[^VanLoan1985]: C. Van Loan, "How near is a stable matrix to an unstable matrix?", in R. Brualdi, et al., eds, Contemporary Mathematics 47, Amer. Math. Soc., 1985
"""
function demmel(N,M=1e4)
    isdefined(Main, :ToeplitzMatrices) ||
        throw(ErrorException("this function requires the ToeplitzMatrices package"))
  B = M^(1/(N-1))
  c = vcat(ones(1), zeros(N-1))
  r = B.^(0:N-1)
  D = -full(Main.ToeplitzMatrices.Toeplitz(c,r))
end

"""
    landau_fox_li(N,F)

construct a Landau matrix of rank N for Fresnel number F

The discretization of a Fox-Li operator in the theory of laser cavities
by [^Landau1977] is one of the earliest applications of pseudospectra.

[^Landau1977]: H. J. Landau, "The notion of approximate eigenvalues applied to an integral equation of laser theory", Quart. Appl. Math. 35 (1977), pp. 165-172.
"""
function landau_fox_li(N,F=0)
    (F == 0) && (F = (N > 200) ? 32 : 12)
    # calculate Gaussian quadrature nodes and weights
    β = 0.5 * (1 .- (2.0 * collect(1:N-1)).^(-2)) .^(-1/2)
    T = diagm(1 => β) + diagm(-1 => β)
    ep = eigen(T)
    d,V = ep.values, ep.vectors
    idx = sortperm(d)
    nodes = d[idx]
    w = zeros(N)
    w[1:N] = 2*V[1,idx].^2
    B = zeros(N,N) .+ 0im
    for k in 1:N
        B[k,:] = w' * sqrt(F*im) .* exp.(-im*π*F*(nodes[k] .- nodes').^2)
    end
    w = sqrt.(w)
    for j in 1:N
        B[:,j] = w .* B[:,j] * (1/w[j])
    end
    B
end

"""
    supg(N)

construct a SUPG matrix for an NxN mesh

The matrix arises from SUPG discretisation of an advection-diffusion operator.

This demo is based on a function by Mark Embree, which
was essentially distilled from the IFISS software of
Elman and Silvester.  See [^Fischer1999] and [^DJS].

For this example, whilst the eigenvalues computed by eigs
are inaccurate due to the sensitivity of the problem, the
approximate pseudospectra are very good approximations to
the true ones.

[^Fischer1999]: B. Fischer, A. Ramage, D. Silvester and A. Wathen, "Towards Parameter-Free Streamline Upwinding for Advection-Diffusion Problems", Comput. Methods Appl. Mech. Eng., 179, 1999, 185-202.
[^DJS]: http://www.ma.umist.ac.uk/djs/software.html
"""
function supg(N)
    h = 1/(N+1)
    theta = 0
    nu = (N < 20) ? 0.01 : 0.0001

    # Compute the "optimal" upwinding parameter
    hbar = h/(max(sin(theta), cos(theta)))
    delta = max(0, 1/2 - nu/hbar)

    w = [-sin(theta),cos(theta)]
    wx2 = w[1]^2
    wy2 = w[2]^2

    if (N > 10)
        A = spzeros(N*N, N*N)
        v = ones(N)
        for j=1:N
            blk =  v*(nu*[-1/3 8/3 -1/3] +
                      h*[-w[1]/3  0 w[1]/3] +
                      delta*h*[(wy2-2*wx2)/3 4/3*(wx2+wy2) (wy2-2*wx2)/3])
            A[N*(j-1)+1:N*j, N*(j-1)+1:N*j] = spdiagm(-1 => blk[1:end-1,1],
                                                       0 => blk[:,2],
                                                       1 => blk[1:end-1,3])
            if (j>1)
                blk = v*(nu*[-1/3 -1/3 -1/3] +
                         h*[-(w[1]+w[2])/12 -w[2]/3 (w[1]-w[2])/12] +
                         delta*h*
                         [(-(wx2+wy2)/6-w[1]*w[2]/2) (wx2-2*wy2)/3 (-(wx2+wy2)/6+w[1]*w[2]/2)])
                A[N*(j-1)+1:N*j, N*(j-2)+1:N*(j-1)] = spdiagm(-1 => blk[1:end-1,1],
                                                               0 => blk[:,2],
                                                               1 => blk[1:end-1,3])
            end
            if (j<N)
                blk = v*(nu*[-1/3 -1/3 -1/3] +
                         h*[(w[2]-w[1])/12 w[2]/3 (w[1]+w[2])/12] +
                         delta*h*
                         [(-(wx2+wy2)/6+w[1]*w[2]/2) (wx2-2*wy2)/3 (-(wx2+wy2)/6-w[1]*w[2]/2)])
                A[N*(j-1)+1:N*j, N*j+1:N*(j+1)] = spdiagm(-1 => blk[1:end-1,1],
                                                           0 => blk[:,2],
                                                           1 => blk[1:end-1,3])
            end
        end

    else
        nn = N*N
        H = zeros(nn,nn)
        S = zeros(nn,nn)
        U = zeros(nn,nn)

        for j=1:N
            for k=1:N
                row = (j-1)*N+k
                H[row, row] = 8/3
                (k > 1) && (H[row, row-1] = -1/3)
                (k < N) && (H[row, row+1] = -1/3)
                (j > 1) && (H[row, row-N] = -1/3)
                (j < N) && (H[row, row+N] = -1/3)
                ((j > 1) & (k > 1)) && (H[row, row-N-1] = -1/3)
                ((j > 1) & (k < N)) && (H[row, row-N+1] = -1/3)
                ((j < N) & (k > 1)) && (H[row, row+N-1] = -1/3)
                ((j < N) & (k < N)) && (H[row, row+N+1] = -1/3)
            end
        end

        for j=1:N
            for k=1:N
                row = (j-1)*N+k
                S[row, row] = 0
                (k > 1) && (S[row, row-1] = -1/3*w[1])
                (k < N) && (S[row, row+1] =  1/3*w[1])
                (j > 1) && (S[row, row-N] = -1/3*w[2])
                (j < N) && (S[row, row+N] =  1/3*w[2])
                ((j > 1) & (k > 1)) && (S[row, row-N-1] = -(w[1]+w[2])/12)
                ((j > 1) & (k < N)) && (S[row, row-N+1] =  (w[1]-w[2])/12)
                ((j < N) & (k > 1)) && (S[row, row+N-1] =  (w[2]-w[1])/12)
                ((j < N) & (k < N)) && (S[row, row+N+1] =  (w[1]+w[2])/12)
            end
        end

        for j=1:N
            for k=1:N
                row = (j-1)*N+k
                U[row, row] = 4/3*(wx2+wy2)
                (k > 1) && (U[row, row-1] = (wy2-2*wx2)/3)
                (k < N) && (U[row, row+1] = (wy2-2*wx2)/3)
                (j > 1) && (U[row, row-N] = (wx2-2*wy2)/3)
                (j < N) && (U[row, row+N] = (wx2-2*wy2)/3)
                ((j > 1) & (k > 1)) && (U[row, row-N-1] = -(wx2+wy2)/6 - w[1]*w[2]/2)
                ((j > 1) & (k < N)) && (U[row, row-N+1] = -(wx2+wy2)/6 + w[1]*w[2]/2)
                ((j < N) & (k > 1)) && (U[row, row+N-1] = -(wx2+wy2)/6 + w[1]*w[2]/2)
                ((j < N) & (k < N)) && (U[row, row+N+1] = -(wx2+wy2)/6 - w[1]*w[2]/2)
            end
        end

        A = nu*H + h*S + delta*h*U
    end
    A
end # supg

"""
    olmstead(N)

load Olmstead matrix from file (`N ∈ {500,1000}`)

!!! note

    This function requires a Matrix Market file from [http://math.nist.gov/MatrixMarket/data/NEP/olmstead/olmstead.html]
"""
function olmstead(N)
    isdefined(Main, :MatrixMarket) ||
        throw(ErrorException("this function requires the MatrixMarket package"))
    if N==500
        A = Main.MatrixMarket.mmread(joinpath(dirname(@__FILE__),"data","olm500.mtx"))
    elseif N==1000
        A = Main.MatrixMarket.mmread(joinpath(dirname(@__FILE__),"data","olm1000.mtx"))
    else
        throw(ArgumentError("no data available for size $N"))
    end
    A
end
"""
    rdbrusselator(N)

load reaction-diffusion Brusselator matrix from file (`N ∈ {800,3200}`)

!!! note

    This function requires a Matrix Market file from [http://math.nist.gov/MatrixMarket/data/NEP/brussel/brussel.html]
"""
function rdbrusselator(N)
    isdefined(Main, :MatrixMarket) ||
        throw(ErrorException("this function requires the MatrixMarket package"))
    if N==800
        A = Main.MatrixMarket.mmread(joinpath(dirname(@__FILE__),"data","rdb800l.mtx"))
    elseif N==3200
        A = Main.MatrixMarket.mmread(joinpath(dirname(@__FILE__),"data","rdb3200l.mtx"))
    else
        throw(ArgumentError("no data available for size $N"))
    end
    A
end


text:
"""
    abs_val(num)

Program to find the absolute value of a number

# Example
```julia
abs_val(-100) # returns 100
abs_val(0) # returns 0
abs(123.1) # returns 123.1
-1000 == abs_val(-1000) #returns false
1000 == abs_val(1000) #returns true
```

Contributed By:- [Ashwani Rathee](https://github.com/ashwani-rathee) and [Rratic](https://github.com/Rratic)
"""
function abs_val(num::N) where {N<:Real}
    return num < 0 ? -num : num
end

"""
    abs_max(x)

Program to find the max absolute value in a vector

# Example
```julia
abs_max([1,3,4]) # returns 4
abs_max([-3,1,2]) # returns -3
abs_max([-7,-3,6]) #returns -7
```

Contributed By:- [Ashwani Rathee](https://github.com/ashwani-rathee) and [Rratic](https://github.com/Rratic)
"""
function abs_max(x::Vector{N}) where {N<:Real}
    _max = x[1]
    for i in x
        if abs(i) > abs(_max)
            _max = i
        end
    end
    return _max
end

"""
    abs_min(num)

Program to find the min absolute value in a vector

# Example
```julia
abs_min([1,3,4]) # returns 1
abs_min([-3,1,2]) # returns 1
abs_min([-7,-3,6]) #returns -3
```

Contributed By:- [Ashwani Rathee](https://github.com/ashwani-rathee) and [Rratic](https://github.com/Rratic)
"""
function abs_min(x::Vector{N}) where {N<:Real}
    _min = x[1]
    for i in x
        if abs(i) < abs(_min)
            _min = i
        end
    end
    return _min
end

max_issues_repo_name: AugustoCL/Julia

max_forks_repo_name: AugustoCL/Julia


text:
@testset "pwc_density" begin
    # test a few specific examples
    @testset "examples" begin
        @test pwc_density([0.]) == [0.0, 0.0]
        @test pwc_density([0., 1.]) == [0.0, 1.0, 0.0]
        @test pwc_density([0, 1, 3]) == [0.0, 0.5, 0.25, 0.0]
    end

    # test 1-S pwc_density for sum == 1
    @testset "1-S sum == 1" begin
        @testset for len in [2, 5, 10, 50, 100, 500, 1000]
            x = sort(randn(len))
            d = pwc_density(x)
            @test sum(d[2:end-1] .* diff(x)) ≈ 1.  atol=100eps()
        end
    end

    # test 2-S pwc_density for sum == 1
    @testset "2-S sum == 1" begin
        @testset for len in [2, 5, 10, 50, 100, 500, 1000]
            x = ArrayPartition((sort(randn(len)) for _ in 1:2)...)
            d = pwc_density(x.x...)
            for s in 1:2
                @test sum(d[s][s, 1, 2:end] .* diff(x.x[s])) ≈ 1.  atol=100eps()
            end
        end
    end

    # test left/right consistency of `pwc_density` with 2 species
    @testset "left/right" begin
        @testset for len in [2, 3, 10, 100]
            x = ArrayPartition((sort(randn(len)) for _ in 1:2)...)
            d = pwc_density(x.x...)
            for s in 1:2
                @test d[s][s, 1, 2:end] == d[s][s, 2, 1:end-1]
            end
        end
    end

    # test consistency of `pwc_density` with 1 and 2 species
    @testset "1-S/2-S" begin
        @testset for len in [2, 3, 10, 100]
            x = ArrayPartition((sort(randn(len)) for _ in 1:2)...)
            d = pwc_density(x.x...)
            for s in 1:2
                @test d[s][s, 1, 2:end] == pwc_density(x.x[s])[2:end-1]
            end
        end
    end
end

@testset "pwc_densities" begin
    # test left/right consistency of `pwc_densities` with N species
    @testset "left/right" begin
        @testset for N in 1:5
            @testset for len in [2, 3, 10, 100]
                x = ArrayPartition((sort(randn(len)) for _ in 1:N)...)
                d = pwc_densities(x.x...)
                for s in 1:N
                    @test d[s][s, 1, 2:end] == d[s][s, 2, 1:end-1]
                end
            end
        end
    end

    # test N-S pwc_densities for sum == 1
    @testset "sum == 1" begin
        @testset for N in 1:5
            @testset for len in [2, 5, 10, 50, 100, 500, 1000]
                x = ArrayPartition((sort(randn(len)) for _ in 1:N)...)
                d = pwc_densities(x.x...)
                for s in 1:N
                    @test sum(d[s][s, 1, 2:end] .* diff(x.x[s])) ≈ 1.  atol=100eps()
                end
            end
        end
    end

    # test consistency of `pwc_densities` with 1 and N species
    @testset "1-S/N-S" begin
        @testset for N in 1:5
            @testset for len in [2, 3, 10, 100]
                x = ArrayPartition((sort(randn(len)) for _ in 1:N)...)
                d = pwc_densities(x.x...)
                for s in 1:N
                    @test d[s][s:s, :, :] == pwc_densities(x.x[s])[1]
                end
            end
        end
    end
end

# test 1-S/2-S pwc_density == pwc_densities
@testset "pwc_density == pwc_densities" begin
    @testset "1-S" begin
        @testset for len in [2, 3, 10, 100]
            x = sort(randn(len))
            @test pwc_density(x)[2:end-1] == pwc_densities(x)[1][1, 1, 2:end]
        end
    end

    @testset "2-S" begin
        @testset for len in [2, 3, 10, 100]
            x = ArrayPartition((sort(randn(len)) for _ in 1:2)...)
            @test pwc_density(x.x...) == pwc_densities(x.x...)
        end
    end

    @testset "2-S (common points)" begin
        common = collect(-1:0.1:1)
        @testset for lengths in [(2,3), (5,10), (50,100)]
            x = ArrayPartition((sort(vcat(randn(l), common)) for l in lengths)...)
            @test pwc_density(x.x...) == pwc_densities(x.x...)
        end
    end
end


text:
#   Generating exports
export sodium_init
export crypto_auth_hmacsha512256
export crypto_auth_hmacsha512256_verify
export crypto_auth_bytes
export crypto_auth_keybytes
export crypto_auth_primitive
export crypto_auth
export crypto_auth_verify
export crypto_auth_hmacsha256
export crypto_auth_hmacsha256_verify
export crypto_box_curve25519xsalsa20poly1305
export crypto_box_curve25519xsalsa20poly1305_open
export crypto_box_curve25519xsalsa20poly1305_keypair
export crypto_box_curve25519xsalsa20poly1305_beforenm
export crypto_box_curve25519xsalsa20poly1305_afternm
export crypto_box_curve25519xsalsa20poly1305_open_afternm
export crypto_box_publickeybytes
export crypto_box_secretkeybytes
export crypto_box_beforenmbytes
export crypto_box_noncebytes
export crypto_box_zerobytes
export crypto_box_boxzerobytes
export crypto_box_macbytes
export crypto_box_primitive
export crypto_box_keypair
export crypto_box_beforenm
export crypto_box_afternm
export crypto_box_open_afternm
export crypto_box
export crypto_box_open
export crypto_core_hsalsa20
export crypto_core_salsa20
export crypto_core_salsa2012
export crypto_core_salsa208
export crypto_generichash_blake2b
export crypto_generichash_blake2b_init
export crypto_generichash_blake2b_update
export crypto_generichash_blake2b_final
export crypto_generichash_bytes_min
export crypto_generichash_bytes_max
export crypto_generichash_keybytes_min
export crypto_generichash_keybytes_max
export crypto_generichash_blockbytes
export crypto_generichash_primitive
export crypto_generichash
export crypto_generichash_init
export crypto_generichash_update
export crypto_generichash_final
export crypto_hash_sha512
export crypto_hash
export crypto_hash_sha256
export crypto_hashblocks_sha256
export crypto_hashblocks_sha512
export crypto_onetimeauth_poly1305_ref_implementation_name
export crypto_onetimeauth_poly1305_set_implementation
export crypto_onetimeauth_pick_best_implementation
export crypto_onetimeauth_poly1305
export crypto_onetimeauth_poly1305_verify
export crypto_onetimeauth_bytes
export crypto_onetimeauth_keybytes
export crypto_onetimeauth_primitive
export crypto_onetimeauth
export crypto_onetimeauth_verify
export crypto_scalarmult_curve25519
export crypto_scalarmult_curve25519_base
export crypto_scalarmult_bytes
export crypto_scalarmult_scalarbytes
export crypto_scalarmult_primitive
export crypto_scalarmult_base
export crypto_scalarmult
export crypto_secretbox_xsalsa20poly1305
export crypto_secretbox_xsalsa20poly1305_open
export crypto_secretbox_keybytes
export crypto_secretbox_noncebytes
export crypto_secretbox_zerobytes
export crypto_secretbox_boxzerobytes
export crypto_secretbox_primitive
export crypto_secretbox
export crypto_secretbox_open
export crypto_shorthash_siphash24
export crypto_shorthash_bytes
export crypto_shorthash_keybytes
export crypto_shorthash_primitive
export crypto_shorthash
export crypto_sign_ed25519
export crypto_sign_ed25519_open
export crypto_sign_ed25519_keypair
export crypto_sign_ed25519_seed_keypair
export crypto_sign_bytes
export crypto_sign_publickeybytes
export crypto_sign_secretkeybytes
export crypto_sign_primitive
export crypto_sign_seed_keypair
export crypto_sign_keypair
export crypto_sign
export crypto_sign_open
export crypto_sign_edwards25519sha512batch
export crypto_sign_edwards25519sha512batch_open
export crypto_sign_edwards25519sha512batch_keypair
export crypto_stream_xsalsa20
export crypto_stream_xsalsa20_xor
export crypto_stream_xsalsa20_beforenm
export crypto_stream_xsalsa20_afternm
export crypto_stream_xsalsa20_xor_afternm
export crypto_stream_keybytes
export crypto_stream_noncebytes
export crypto_stream_primitive
export crypto_stream
export crypto_stream_xor
export crypto_stream_aes128ctr
export crypto_stream_aes128ctr_xor
export crypto_stream_aes128ctr_beforenm
export crypto_stream_aes128ctr_afternm
export crypto_stream_aes128ctr_xor_afternm
export crypto_stream_salsa20
export crypto_stream_salsa20_xor
export crypto_stream_salsa20_beforenm
export crypto_stream_salsa20_afternm
export crypto_stream_salsa20_xor_afternm
export crypto_stream_salsa2012
export crypto_stream_salsa2012_xor
export crypto_stream_salsa2012_beforenm
export crypto_stream_salsa2012_afternm
export crypto_stream_salsa2012_xor_afternm
export crypto_stream_salsa208
export crypto_stream_salsa208_xor
export crypto_stream_salsa208_beforenm
export crypto_stream_salsa208_afternm
export crypto_stream_salsa208_xor_afternm
export crypto_verify_16
export crypto_verify_32
export randombytes_set_implementation
export randombytes
export randombytes_implementation_name
export randombytes_random
export randombytes_stir
export randombytes_uniform
export randombytes_buf
export randombytes_close
export randombytes_salsa20_implementation_name
export randombytes_salsa20_random
export randombytes_salsa20_random_stir
export randombytes_salsa20_random_uniform
export randombytes_salsa20_random_buf
export randombytes_salsa20_random_close
export randombytes_sysrandom_implementation_name
export randombytes_sysrandom
export randombytes_sysrandom_stir
export randombytes_sysrandom_uniform
export randombytes_sysrandom_buf
export randombytes_sysrandom_close
export _sodium_alignedcalloc
export sodium_memzero
export sodium_memcmp
export sodium_version_string
export sodium_library_version_major
export sodium_library_version_minor
export crypto_generichash_state
export crypto_auth_hmacsha512256_BYTES
export crypto_auth_hmacsha512256_KEYBYTES
export crypto_auth_hmacsha512256_ref
export crypto_auth_hmacsha512256_ref_verify
export crypto_auth_BYTES
export crypto_auth_KEYBYTES
export crypto_auth_PRIMITIVE
export crypto_auth_hmacsha256_BYTES
export crypto_auth_hmacsha256_KEYBYTES
export crypto_auth_hmacsha256_ref
export crypto_auth_hmacsha256_ref_verify
export crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES
export crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES
export crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES
export crypto_box_curve25519xsalsa20poly1305_NONCEBYTES
export crypto_box_curve25519xsalsa20poly1305_ZEROBYTES
export crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES
export crypto_box_curve25519xsalsa20poly1305_MACBYTES
export crypto_box_curve25519xsalsa20poly1305_ref
export crypto_box_curve25519xsalsa20poly1305_ref_open
export crypto_box_curve25519xsalsa20poly1305_ref_keypair
export crypto_box_curve25519xsalsa20poly1305_ref_beforenm
export crypto_box_curve25519xsalsa20poly1305_ref_afternm
export crypto_box_curve25519xsalsa20poly1305_ref_open_afternm
export crypto_box_PUBLICKEYBYTES
export crypto_box_SECRETKEYBYTES
export crypto_box_BEFORENMBYTES
export crypto_box_NONCEBYTES
export crypto_box_ZEROBYTES
export crypto_box_BOXZEROBYTES
export crypto_box_MACBYTES
export crypto_box_PRIMITIVE
export crypto_core_hsalsa20_OUTPUTBYTES
export crypto_core_hsalsa20_INPUTBYTES
export crypto_core_hsalsa20_KEYBYTES
export crypto_core_hsalsa20_CONSTBYTES
export crypto_core_hsalsa20_ref2
export crypto_core_salsa2012_OUTPUTBYTES
export crypto_core_salsa2012_INPUTBYTES
export crypto_core_salsa2012_KEYBYTES
export crypto_core_salsa2012_CONSTBYTES
export crypto_core_salsa2012_ref
export crypto_core_salsa208_OUTPUTBYTES
export crypto_core_salsa208_INPUTBYTES
export crypto_core_salsa208_KEYBYTES
export crypto_core_salsa208_CONSTBYTES
export crypto_core_salsa208_ref
export crypto_core_salsa20_OUTPUTBYTES
export crypto_core_salsa20_INPUTBYTES
export crypto_core_salsa20_KEYBYTES
export crypto_core_salsa20_CONSTBYTES
export crypto_core_salsa20_ref
export crypto_generichash_blake2b_BYTES_MIN
export crypto_generichash_blake2b_BYTES_MAX
export crypto_generichash_blake2b_KEYBYTES_MIN
export crypto_generichash_blake2b_KEYBYTES_MAX
export crypto_generichash_blake2b_BLOCKBYTES
export crypto_generichash_blake2b_ref
export crypto_generichash_blake2b_ref_init
export crypto_generichash_blake2b_ref_update
export crypto_generichash_blake2b_ref_final
export crypto_generichash_BYTES_MIN
export crypto_generichash_BYTES_MAX
export crypto_generichash_KEYBYTES_MIN
export crypto_generichash_KEYBYTES_MAX
export crypto_generichash_BLOCKBYTES
export crypto_generichash_PRIMITIVE
export crypto_hashblocks_sha256_STATEBYTES
export crypto_hashblocks_sha256_BLOCKBYTES
export crypto_hashblocks_sha256_ref
export crypto_hashblocks_sha512_STATEBYTES
export crypto_hashblocks_sha512_BLOCKBYTES
export crypto_hashblocks_sha512_ref
export crypto_hash_sha512_BYTES
export crypto_hash_sha512_BLOCKBYTES
export crypto_hash_sha512_ref
export crypto_hash_BYTES
export crypto_hash_BLOCKBYTES
export crypto_hash_PRIMITIVE
export crypto_hash_sha256_BYTES
export crypto_hash_sha256_BLOCKBYTES
export crypto_hash_sha256_ref
export crypto_onetimeauth_poly1305_BYTES
export crypto_onetimeauth_poly1305_KEYBYTES
export crypto_onetimeauth_BYTES
export crypto_onetimeauth_KEYBYTES
export crypto_onetimeauth_PRIMITIVE
export crypto_scalarmult_curve25519_BYTES
export crypto_scalarmult_curve25519_SCALARBYTES
export crypto_scalarmult_curve25519_ref
export crypto_scalarmult_curve25519_ref_base
export crypto_scalarmult_BYTES
export crypto_scalarmult_SCALARBYTES
export crypto_scalarmult_PRIMITIVE
export crypto_secretbox_xsalsa20poly1305_KEYBYTES
export crypto_secretbox_xsalsa20poly1305_NONCEBYTES
export crypto_secretbox_xsalsa20poly1305_ZEROBYTES
export crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES
export crypto_secretbox_xsalsa20poly1305_ref
export crypto_secretbox_xsalsa20poly1305_ref_open
export crypto_secretbox_KEYBYTES
export crypto_secretbox_NONCEBYTES
export crypto_secretbox_ZEROBYTES
export crypto_secretbox_BOXZEROBYTES
export crypto_secretbox_PRIMITIVE
export crypto_shorthash_siphash24_BYTES
export crypto_shorthash_siphash24_KEYBYTES
export crypto_shorthash_siphash24_ref
export crypto_shorthash_BYTES
export crypto_shorthash_KEYBYTES
export crypto_shorthash_PRIMITIVE
export crypto_sign_ed25519_SECRETKEYBYTES
export crypto_sign_ed25519_PUBLICKEYBYTES
export crypto_sign_ed25519_BYTES
export crypto_sign_ed25519_ref10
export crypto_sign_ed25519_ref10_open
export crypto_sign_ed25519_ref10_keypair
export crypto_sign_ed25519_ref10_seed_keypair
export crypto_sign_edwards25519sha512batch_SECRETKEYBYTES
export crypto_sign_edwards25519sha512batch_PUBLICKEYBYTES
export crypto_sign_edwards25519sha512batch_BYTES
export crypto_sign_edwards25519sha512batch_ref
export crypto_sign_edwards25519sha512batch_ref_open
export crypto_sign_edwards25519sha512batch_ref_keypair
export crypto_sign_BYTES
export crypto_sign_PUBLICKEYBYTES
export crypto_sign_SECRETKEYBYTES
export crypto_sign_PRIMITIVE
export crypto_stream_aes128ctr_KEYBYTES
export crypto_stream_aes128ctr_NONCEBYTES
export crypto_stream_aes128ctr_BEFORENMBYTES
export crypto_stream_aes128ctr_portable
export crypto_stream_aes128ctr_portable_xor
export crypto_stream_aes128ctr_portable_beforenm
export crypto_stream_aes128ctr_portable_afternm
export crypto_stream_aes128ctr_portable_xor_afternm
export crypto_stream_xsalsa20_KEYBYTES
export crypto_stream_xsalsa20_NONCEBYTES
export crypto_stream_xsalsa20_ref
export crypto_stream_xsalsa20_ref_xor
export crypto_stream_xsalsa20_ref_beforenm
export crypto_stream_xsalsa20_ref_afternm
export crypto_stream_xsalsa20_ref_xor_afternm
export crypto_stream_KEYBYTES
export crypto_stream_NONCEBYTES
export crypto_stream_PRIMITIVE
export crypto_stream_salsa2012_KEYBYTES
export crypto_stream_salsa2012_NONCEBYTES
export crypto_stream_salsa2012_ref
export crypto_stream_salsa2012_ref_xor
export crypto_stream_salsa2012_ref_beforenm
export crypto_stream_salsa2012_ref_afternm
export crypto_stream_salsa2012_ref_xor_afternm
export crypto_stream_salsa208_KEYBYTES
export crypto_stream_salsa208_NONCEBYTES
export crypto_stream_salsa208_ref
export crypto_stream_salsa208_ref_xor
export crypto_stream_salsa208_ref_beforenm
export crypto_stream_salsa208_ref_afternm
export crypto_stream_salsa208_ref_xor_afternm
export crypto_stream_salsa20_KEYBYTES
export crypto_stream_salsa20_NONCEBYTES
export crypto_stream_salsa20_ref
export crypto_stream_salsa20_ref_xor
export crypto_stream_salsa20_ref_beforenm
export crypto_stream_salsa20_ref_afternm
export crypto_stream_salsa20_ref_xor_afternm
export crypto_verify_16_BYTES
export crypto_verify_16_ref
export crypto_verify_32_BYTES
export crypto_verify_32_ref


text:
# Tests related to validated integration

using TaylorModels
using LinearAlgebra: norm
using Test

# const _num_tests = 1000
# const α_mid = TaylorModels.α_mid

setformat(:full)

# This is based on an example from Buenger, Numer Algor (2018) 78:1001–1017,
# which shows the efectivity of shrink-wrapping
@testset "Testing `shrink_wrapping` 1" begin
    _order = 2
    set_variables("x", numvars=1, order=2*_order)
    x0 = IntervalBox(0..0, 1)
    dom = IntervalBox(-1..1, 1)
    for δ in 1/16:1/16:1
        Δ = @interval(-δ, δ)
        p = TaylorModelN(TaylorN(1, order=_order), Δ, x0, dom)
        # Usual TM case
        result = p * p
        rem_result = δ*(2+δ)*dom[1]
        range_result = dom[1]^2 + rem_result
        @test result(dom) == range_result
        @test remainder(result) == rem_result
        # Shrink-wrapping:
        q = [ p ]
        TaylorModels.shrink_wrapping!(q)
        @test p(dom) == q[1](dom)
        @test remainder(q[1]) ⊆ Δ
        @test remainder(q[1]) == x0[1]
        # Result using shrink-wrapped variables
        result_sw = q[1] * q[1]
        @test remainder(result_sw) ⊆ rem_result
        @test result_sw(dom) ⊆ range_result
    end
end

# This is based on the example of Sect 4 of M. Berz, K. Makino,
# in https://bt.pa.msu.edu/pub/papers/VIShrink06/VIShrink06.pdf
@testset "Testing `shrink_wrapping` 2" begin
    function two_state1!(v)
        x, y = v
        x_2 = x^2
        y_2 = y^2
        r_2 = x_2 + y_2
        s = sqrt(1 + r_2)
        v[1] = x * s
        v[2] = y * s
        return v
    end

    function two_state2!(v)
        x1, y1 = v
        x1_2 = x1^2
        y1_2 = y1^2
        r1_2 = x1_2 + y1_2
        r1 = sqrt( 1 + 4*r1_2 )
        s1 = 2 / (1+r1)
        ss = sqrt( s1 )
        v[1] = x1 * ss
        v[2] = y1 * ss
        return v
    end

    local B = IntervalBox( -1 .. 1, 2)
    local δ = 0.05
    local ib = δ * B
    local mib = IntervalBox( 0..0, 2)

    # Diverges using naive Interval arithmetic methods
    ib0 = [ib...]
    for iter = 1:210 # iter is twice the number of iterates
        two_state1!(ib0)
        two_state2!(ib0)
    end
    @test minimum(diam.(ib0)) > 1e6

    # Taylor model controls grow and behaves *essentially* as the identity
    # (due to the normalization to the symmetric box) after two iterates
    order = 10
    set_variables("x y", order=2*order)
    vm = [TaylorModelN(normalize_taylor(TaylorN(i, order=order), ib, true),
        0..0, mib, B) for i = 1:2]
    vm0 = deepcopy(vm)
    for iter = 1:1_000
        two_state1!(vm0)
        two_state2!(vm0)
    end
    @test maximum(remainder.(vm0)) < 1e-6 # 2.08e-7
    # Constant and linear terms are identic to the initial ones
    @test all(constant_term.(vm0) .== constant_term.(vm))
    @test all(linear_polynomial.(vm0) .== linear_polynomial.(vm))
    # Maximum difference of polynomials is very small
    @test norm(polynomial(vm0[1] - vm[1]), Inf) < 1e-19

    # Taylor model with shrink-wrapping after two iterates
    vm0 .= deepcopy.(vm)
    for iter = 1:1_000
        two_state1!(vm0)
        two_state2!(vm0)
        TaylorModels.shrink_wrapping!(vm0)
    end
    @test maximum(remainder.(vm0)) < 1e-8 #2.2e-13
    # The dominating difference is in the linear term
    @test norm(polynomial(vm0[1] - vm[1]), Inf) == norm(vm0[1][1] - vm[1][1], Inf)

    # Taylor model with shrink-wrapping after each iterate
    vm0 .= deepcopy.(vm)
    for iter = 1:1_000
        two_state1!(vm0)
        TaylorModels.shrink_wrapping!(vm0)
        two_state2!(vm0)
        TaylorModels.shrink_wrapping!(vm0)
    end
    @test maximum(remainder.(vm0)) < 2.2e-13
    # The dominating difference is in the linear term
    @test norm(polynomial(vm0[1] - vm[1]), Inf) == norm(vm0[1][1] - vm[1][1], Inf)

    # Test AssertionError
    vm = [TaylorModelN(TaylorN(i, order=order), 0..0, mib, ib) for i = 1:2]
    @test_throws AssertionError TaylorModels.shrink_wrapping!(vm)
end


text:
dimz = (X(), Y())

@testset "permutedims" begin
    @test permutedims((Y(1:2), X(1)), dimz) == (X(1), Y(1:2))
    @test permutedims((X(1),), dimz) == (X(1), nothing)
    @test permutedims((Y(), X()), dimz) == (X(:), Y(:))
    @test permutedims([Y(), X()], dimz) == (X(:), Y(:))
    @test permutedims((Y, X),     dimz) == (X(:), Y(:))
    @test permutedims([Y, X],     dimz) == (X(:), Y(:))
    @test permutedims(dimz, (Y(), X())) == (Y(:), X(:))
    @test permutedims(dimz, [Y(), X()]) == (Y(:), X(:))
    @test permutedims(dimz, (Y, X)    ) == (Y(:), X(:))
    @test permutedims(dimz, [Y, X]    ) == (Y(:), X(:))
end

a = [1 2 3; 4 5 6]
da = DimensionalArray(a, (X((143, 145)), Y((-38, -36))))
dimz = dims(da)

@testset "slicedims" begin
    @test slicedims(dimz, (1:2, 3)) == ((X(LinRange(143,145,2)),), (Y(-36.0),))
    @test slicedims(dimz, (2:2, :)) == ((X(LinRange(145,145,1)), Y(LinRange(-38.0,-36.0,3))), ())
end

@testset "dims2indices" begin
    emptyval = Colon()
    @test dims2indices(dimz, (Y(),), emptyval) == (Colon(), Colon())
    @test dims2indices(dimz, (Y(1),), emptyval) == (Colon(), 1)
    # Time is just ignored if it's not in dims. Should this be an error?
    @test dims2indices(dimz, (Time(4), X(2))) == (2, Colon())
    @test dims2indices(dimz, (Y(2), X(3:7)), emptyval) == (3:7, 2)
    @test dims2indices(dimz, (X(2), Y([1, 3, 4])), emptyval) == (2, [1, 3, 4])
    @test dims2indices(da, (X(2), Y([1, 3, 4])), emptyval) == (2, [1, 3, 4])
    emptyval=()
    @test dims2indices(dimz, (Y,), emptyval) == ((), Colon())
    @test dims2indices(dimz, (Y, X), emptyval) == (Colon(), Colon())
    @test dims2indices(da, X, emptyval) == (Colon(), ())
end

@testset "dimnum" begin
    @test dimnum(da, X) == 1
    @test dimnum(da, Y()) == 2
    @test dimnum(da, (Y, X())) == (2, 1)
end

@testset "reducedims" begin
    @test reducedims((X(:), Y(1:5))) == (X(1), Y(1))
end


text:
module PkgCompat

export package_versions, package_completions

import Pkg
import Pkg.Types: VersionRange

import ..Pluto

# Should be in Base
flatmap(args...) = vcat(map(args...)...)

# Should be in Base
function select(f::Function, xs)
	for x ∈ xs
		if f(x)
			return x
		end
	end
	nothing
end

#=

NOTE ABOUT PUBLIC/INTERNAL PKG API

Pkg.jl exposes lots of API, but only some of it is "public": guaranteed to remain available. API is public if it is listed here:
https://pkgdocs.julialang.org/v1/api/

In this file, I labeled functions by their status using 🐸, ⚠, etc.

A status in brackets (like this) means that it is only called within this file, and the fallback might be in a caller function.

---

I tried to only use public API, except:
- I use the `Pkg.Types.Context` value as first argument for many functions, since the server process manages multiple notebook processes, each with their own package environment. We could get rid of this, by settings `Base.ACTIVE_PROJECT[]` before and after each Pkg call. (This is temporarily activating the notebook environment.) This does have a performance impact, since the project and manifest caches are regenerated every time.
- https://github.com/JuliaLang/Pkg.jl/issues/2607 seems to be impossible with the current public API.
- Some functions try to use internal API for optimization/better features.

=#

###
# CONTEXT
###

const PkgContext = if isdefined(Pkg, :Context)
	Pkg.Context
elseif isdefined(Pkg, :Types) && isdefined(Pkg.Types, :Context)
	Pkg.Types.Context
elseif isdefined(Pkg, :API) && isdefined(Pkg.API, :Context)
	Pkg.API.Context
else
	Pkg.Types.Context
end

# 🐸 "Public API", but using PkgContext
load_ctx(env_dir)::PkgContext = PkgContext(env=Pkg.Types.EnvCache(joinpath(env_dir, "Project.toml")))

# 🐸 "Public API", but using PkgContext
create_empty_ctx()::PkgContext = load_ctx(mktempdir())

# ⚠ Internal API with fallback
function load_ctx(original::PkgContext)
	new = load_ctx(env_dir(original))

	try
		new.env.original_project = original.env.original_project
		new.env.original_manifest = original.env.original_manifest
	catch e
		@warn "Pkg compat: failed to set original_project" exception=(e,catch_backtrace())
	end

	new
end

# ⚠ Internal API with fallback
function mark_original!(ctx::PkgContext)
	try
		ctx.env.original_project = deepcopy(ctx.env.project)
		ctx.env.original_manifest = deepcopy(ctx.env.manifest)
	catch e
		@warn "Pkg compat: failed to set original_project" exception=(e,catch_backtrace())
	end
end

# ⚠ Internal API with fallback
function is_original(ctx::PkgContext)::Bool
	try
		ctx.env.original_project == ctx.env.project &&
		ctx.env.original_manifest == ctx.env.manifest
	catch e
		@warn "Pkg compat: failed to get original_project" exception=(e,catch_backtrace())
		false
	end
end

# 🐸 "Public API", but using PkgContext
env_dir(ctx::PkgContext) = dirname(ctx.env.project_file)

project_file(x::AbstractString) = joinpath(x, "Project.toml")
manifest_file(x::AbstractString) = joinpath(x, "Manifest.toml")
project_file(ctx::PkgContext) = joinpath(env_dir(ctx), "Project.toml")
manifest_file(ctx::PkgContext) = joinpath(env_dir(ctx), "Manifest.toml")
function read_project_file(x)::String
	path = project_file(x)
	isfile(path) ? read(path, String) : ""
end
function read_manifest_file(x)::String
	path = manifest_file(x)
	isfile(path) ? read(path, String) : ""
end

# ⚠ Internal API with fallback
function withio(f::Function, ctx::PkgContext, io::IO)
    @static if :io ∈ fieldnames(PkgContext)
        old_io = ctx.io
        ctx.io = io
        result = try
			f()
		finally
        	ctx.io = old_io
			nothing
		end
        result
    else
        f()
    end
end

###
# REGISTRIES
###

# (⛔ Internal API)
"Return paths to all installed registries."
_get_registry_paths() = @static if isdefined(Pkg, :Types) && isdefined(Pkg.Types, :registries)
	Pkg.Types.registries()
elseif isdefined(Pkg, :Registry) && isdefined(Pkg.Registry, :reachable_registries)
	registry_specs = Pkg.Registry.reachable_registries()
	[s.path for s in registry_specs]
elseif isdefined(Pkg, :Types) && isdefined(Pkg.Types, :collect_registries)
	registry_specs = Pkg.Types.collect_registries()
	[s.path for s in registry_specs]
else
	String[]
end

# (⛔ Internal API)
_get_registries() = map(_get_registry_paths()) do r
	@static if isdefined(Pkg, :Registry) && isdefined(Pkg.Registry, :RegistryInstance)
		Pkg.Registry.RegistryInstance(r)
	else
		r => Pkg.Types.read_registry(joinpath(r, "Registry.toml"))
	end
end

# (⛔ Internal API)
"Contains all registries as `Pkg.Types.Registry` structs."
const _parsed_registries = Ref(_get_registries())

# (⛔ Internal API)
"Re-parse the installed registries from disk."
function refresh_registry_cache()
	_parsed_registries[] = _get_registries()
end

# ⚠✅ Internal API with fallback
const _updated_registries_compat = @static if isdefined(Pkg, :UPDATED_REGISTRY_THIS_SESSION) && Pkg.UPDATED_REGISTRY_THIS_SESSION isa Ref{Bool}
	Pkg.UPDATED_REGISTRY_THIS_SESSION
else
	Ref(false)
end

# ✅ Public API
function update_registries(; force::Bool=false)
	if force || !_updated_registries_compat[]
		Pkg.Registry.update()
		try
			refresh_registry_cache()
		catch
		end
		_updated_registries_compat[] = true
	end
end

###
# Instantiate
###

# ⚠✅ Internal API with fallback
function instantiate(ctx; update_registry::Bool)
	@static if hasmethod(Pkg.instantiate, Tuple{}, (:update_registry,))
		Pkg.instantiate(ctx; update_registry)
	else
		Pkg.instantiate(ctx)
	end
end

###
# Standard Libraries
###

# (⚠ Internal API with fallback)
_stdlibs() = try
	stdlibs = values(Pkg.Types.stdlibs())
	T = eltype(stdlibs)
	if T == String
		stdlibs
	elseif T <: Tuple{String,Any}
		first.(stdlibs)
	else
		error()
	end
catch e
	@warn "Pkg compat: failed to load standard libraries." exception=(e,catch_backtrace())

	String["CRC32c", "Future", "Sockets", "MbedTLS_jll", "Random", "ArgTools", "libLLVM_jll", "GMP_jll", "Pkg", "Serialization", "LibSSH2_jll", "SHA", "OpenBLAS_jll", "REPL", "LibUV_jll", "nghttp2_jll", "Unicode", "Profile", "SparseArrays", "LazyArtifacts", "CompilerSupportLibraries_jll", "Base64", "Artifacts", "PCRE2_jll", "Printf", "p7zip_jll", "UUIDs", "Markdown", "TOML", "OpenLibm_jll", "Test", "MPFR_jll", "Mmap", "SuiteSparse", "LibGit2", "LinearAlgebra", "Logging", "NetworkOptions", "LibGit2_jll", "LibOSXUnwind_jll", "Dates", "LibUnwind_jll", "Libdl", "LibCURL_jll", "dSFMT_jll", "Distributed", "InteractiveUtils", "Downloads", "SharedArrays", "SuiteSparse_jll", "LibCURL", "Statistics", "Zlib_jll", "FileWatching", "DelimitedFiles", "Tar", "MozillaCACerts_jll"]
end

# ⚠ Internal API with fallback
is_stdlib(package_name::AbstractString) = package_name ∈ _stdlibs()

global_ctx = PkgContext()

###
# Package names
###

# ⚠ Internal API with fallback
function package_completions(partial_name::AbstractString)::Vector{String}
	String[
		filter(s -> startswith(s, partial_name), collect(_stdlibs()));
		_registered_package_completions(partial_name)
	]
end

# (⚠ Internal API with fallback)
function _registered_package_completions(partial_name::AbstractString)::Vector{String}
	# compat
	try
		@static if hasmethod(Pkg.REPLMode.complete_remote_package, (String,))
			Pkg.REPLMode.complete_remote_package(partial_name)
		else
			Pkg.REPLMode.complete_remote_package(partial_name, 1, length(partial_name))[1]
		end
	catch e
		@warn "Pkg compat: failed to autocomplete packages" exception=(e,catch_backtrace())
		String[]
	end
end

###
# Package versions
###

# (⛔ Internal API)
"""
Return paths to all found registry entries of a given package name.

# Example
```julia
julia> Pluto.PkgCompat._registry_entries("Pluto")
1-element Vector{String}:
 "/Users/fons/.julia/registries/General/P/Pluto"
```
"""
function _registry_entries(package_name::AbstractString, registries::Vector=_parsed_registries[])::Vector{String}
	flatmap(registries) do (rpath, r)
		packages = values(r["packages"])
		String[
			joinpath(rpath, d["path"])
			for d in packages
			if d["name"] == package_name
		]
	end
end

# (⛔ Internal API)
function _package_versions_from_path(registry_entry_fullpath::AbstractString)::Vector{VersionNumber}
	# compat
    vd = @static if isdefined(Pkg, :Operations) && isdefined(Pkg.Operations, :load_versions) && hasmethod(Pkg.Operations.load_versions, (String,))
        Pkg.Operations.load_versions(registry_entry_fullpath)
    else
        Pkg.Operations.load_versions(PkgContext(), registry_entry_fullpath)
    end
	vd |> keys |> collect
end

# ⚠ Internal API with fallback
# See https://github.com/JuliaLang/Pkg.jl/issues/2607
"""
Return all registered versions of the given package. Returns `["stdlib"]` for standard libraries, and a `Vector{VersionNumber}` for registered packages.
"""
function package_versions(package_name::AbstractString)::Vector
    if is_stdlib(package_name)
        ["stdlib"]
    else
		try
			@static(if isdefined(Pkg, :Registry) && isdefined(Pkg.Registry, :uuids_from_name)
				flatmap(_parsed_registries[]) do reg
					uuids_with_name = Pkg.Registry.uuids_from_name(reg, package_name)
					flatmap(uuids_with_name) do u
						pkg = get(reg, u, nothing)
						if pkg !== nothing
							info = Pkg.Registry.registry_info(pkg)
							collect(keys(info.version_info))
						else
							[]
						end
					end
				end
			else
				ps = _registry_entries(package_name)
				flatmap(_package_versions_from_path, ps)
			end) |> sort
		catch e
			@warn "Pkg compat: failed to get installable versions." exception=(e,catch_backtrace())
			["latest"]
		end
    end
end

# ⚠ Internal API with fallback
"Does a package with this name exist in one of the installed registries?"
package_exists(package_name::AbstractString)::Bool =
    package_versions(package_name) |> !isempty

# 🐸 "Public API", but using PkgContext
function dependencies(ctx)
	try
		# ctx.env.manifest
		@static if hasmethod(Pkg.dependencies, (PkgContext,))
			Pkg.dependencies(ctx)
		else
			Pkg.dependencies(ctx.env)
		end
	catch e
		if !occursin(r"expected.*exist.*manifest", sprint(showerror, e))
			@error """
			Pkg error: you might need to use

			Pluto.reset_notebook_environment(notebook_path)

			to reset this notebook's environment.

			Before doing so, consider sending your notebook file to https://github.com/fonsp/Pluto.jl/issues together with the following info:
			""" Pluto.PLUTO_VERSION VERSION exception=(e,catch_backtrace())
		end

		Dict()

	end
end

function project(ctx::PkgContext)
	@static if hasmethod(Pkg.project, (PkgContext,))
		Pkg.project(ctx)
	else
		Pkg.project(ctx.env)
	end
end

# 🐸 "Public API", but using PkgContext
"Find a package in the manifest. Return `nothing` if not found."
_get_manifest_entry(ctx::PkgContext, package_name::AbstractString) =
    select(e -> e.name == package_name, values(dependencies(ctx)))

# ⚠ Internal API with fallback
"""
Find a package in the manifest given its name, and return its installed version. Return `"stdlib"` for a standard library, and `nothing` if not found.
"""
function get_manifest_version(ctx::PkgContext, package_name::AbstractString)
    if is_stdlib(package_name)
        "stdlib"
    else
        entry = _get_manifest_entry(ctx, package_name)
		entry === nothing ? nothing : entry.version
    end
end

###
# WRITING COMPAT ENTRIES
###

_project_key_order = ["name", "uuid", "keywords", "license", "desc", "deps", "compat"]
project_key_order(key::String) =
    something(findfirst(x -> x == key, _project_key_order), length(_project_key_order) + 1)

# ✅ Public API
function _modify_compat(f!::Function, ctx::PkgContext)::PkgContext
	toml = Pkg.TOML.parsefile(project_file(ctx))
	compat = get!(Dict, toml, "compat")

	f!(compat)

	isempty(compat) && delete!(toml, "compat")

	write(project_file(ctx), sprint() do io
		Pkg.TOML.print(io, toml; sorted=true, by=(key -> (project_key_order(key), key)))
	end)

	return load_ctx(ctx)
end

# ✅ Public API
"""
Add any missing [`compat`](https://pkgdocs.julialang.org/v1/compatibility/) entries to the `Project.toml` for all direct dependencies. This serves as a 'fallback' in case someone (with a different Julia version) opens your notebook without being able to load the `Manifest.toml`. Return the new `PkgContext`.

The automatic compat entry is: `"~" * string(installed_version)`.
"""
function write_auto_compat_entries(ctx::PkgContext)::PkgContext
	_modify_compat(ctx) do compat
		for p in keys(project(ctx).dependencies)
			if !haskey(compat, p)
				m_version = get_manifest_version(ctx, p)
				if m_version !== nothing && !is_stdlib(p)
					compat[p] = "~" * string(VersionNumber(m_version.major, m_version.minor, m_version.patch))  # drop build number
				end
			end
		end
	end
end

# ✅ Public API
"""
Remove any automatically-generated [`compat`](https://pkgdocs.julialang.org/v1/compatibility/) entries from the `Project.toml`. This will undo the effects of [`write_auto_compat_entries`](@ref) but leave other (e.g. manual) compat entries intact. Return the new `PkgContext`.
"""
function clear_auto_compat_entries(ctx::PkgContext)::PkgContext
	if isfile(project_file(ctx))
		_modify_compat(ctx) do compat
			for p in keys(compat)
				m_version = get_manifest_version(ctx, p)
				if m_version !== nothing && !is_stdlib(p)
					if compat[p] == "~" * string(m_version)
						delete!(compat, p)
					end
				end
			end
		end
	else
		ctx
	end
end

# ✅ Public API
"""
Remove any [`compat`](https://pkgdocs.julialang.org/v1/compatibility/) entries from the `Project.toml` for standard libraries. These entries are created when an old version of Julia uses a package that later became a standard library, like https://github.com/JuliaPackaging/Artifacts.jl. Return the new `PkgContext`.
"""
function clear_stdlib_compat_entries(ctx::PkgContext)::PkgContext
	if isfile(project_file(ctx))
		_modify_compat(ctx) do compat
			for p in keys(compat)
				if is_stdlib(p)
					@info "Removing compat entry for stdlib" p
					delete!(compat, p)
				end
			end
		end
	else
		ctx
	end
end

end