text:
# syntax: proto3
using ProtoBuf
import ProtoBuf.meta
import ..CoreMLProtobuf

mutable struct FeatureDescription <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function FeatureDescription(; kwargs...)
        obj = new(meta(FeatureDescription), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct FeatureDescription
const __meta_FeatureDescription = Ref{ProtoMeta}()
function meta(::Type{FeatureDescription})
    ProtoBuf.metalock() do
        if !isassigned(__meta_FeatureDescription)
            __meta_FeatureDescription[] = target = ProtoMeta(FeatureDescription)
            allflds = Pair{Symbol,Union{Type,String}}[:name => AbstractString, :shortDescription => AbstractString, :_type => FeatureType]
            meta(target, FeatureDescription, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_FeatureDescription[]
    end
end
function Base.getproperty(obj::FeatureDescription, name::Symbol)
    if name === :name
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :shortDescription
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :_type
        return (obj.__protobuf_jl_internal_values[name])::FeatureType
    else
        getfield(obj, name)
    end
end

mutable struct Metadata_UserDefinedEntry <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function Metadata_UserDefinedEntry(; kwargs...)
        obj = new(meta(Metadata_UserDefinedEntry), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct Metadata_UserDefinedEntry (mapentry)
const __meta_Metadata_UserDefinedEntry = Ref{ProtoMeta}()
function meta(::Type{Metadata_UserDefinedEntry})
    ProtoBuf.metalock() do
        if !isassigned(__meta_Metadata_UserDefinedEntry)
            __meta_Metadata_UserDefinedEntry[] = target = ProtoMeta(Metadata_UserDefinedEntry)
            allflds = Pair{Symbol,Union{Type,String}}[:key => AbstractString, :value => AbstractString]
            meta(target, Metadata_UserDefinedEntry, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_Metadata_UserDefinedEntry[]
    end
end
function Base.getproperty(obj::Metadata_UserDefinedEntry, name::Symbol)
    if name === :key
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :value
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    else
        getfield(obj, name)
    end
end

mutable struct Metadata <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function Metadata(; kwargs...)
        obj = new(meta(Metadata), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct Metadata
const __meta_Metadata = Ref{ProtoMeta}()
function meta(::Type{Metadata})
    ProtoBuf.metalock() do
        if !isassigned(__meta_Metadata)
            __meta_Metadata[] = target = ProtoMeta(Metadata)
            fnum = Int[1,2,3,4,100]
            allflds = Pair{Symbol,Union{Type,String}}[:shortDescription => AbstractString, :versionString => AbstractString, :author => AbstractString, :license => AbstractString, :userDefined => Base.Dict{AbstractString,AbstractString}]
            meta(target, Metadata, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_Metadata[]
    end
end
function Base.getproperty(obj::Metadata, name::Symbol)
    if name === :shortDescription
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :versionString
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :author
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :license
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :userDefined
        return (obj.__protobuf_jl_internal_values[name])::Base.Dict{AbstractString,AbstractString}
    else
        getfield(obj, name)
    end
end

mutable struct ModelDescription <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function ModelDescription(; kwargs...)
        obj = new(meta(ModelDescription), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct ModelDescription
const __meta_ModelDescription = Ref{ProtoMeta}()
function meta(::Type{ModelDescription})
    ProtoBuf.metalock() do
        if !isassigned(__meta_ModelDescription)
            __meta_ModelDescription[] = target = ProtoMeta(ModelDescription)
            fnum = Int[1,10,11,12,50,100]
            allflds = Pair{Symbol,Union{Type,String}}[:input => Base.Vector{FeatureDescription}, :output => Base.Vector{FeatureDescription}, :predictedFeatureName => AbstractString, :predictedProbabilitiesName => AbstractString, :trainingInput => Base.Vector{FeatureDescription}, :metadata => Metadata]
            meta(target, ModelDescription, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_ModelDescription[]
    end
end
function Base.getproperty(obj::ModelDescription, name::Symbol)
    if name === :input
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{FeatureDescription}
    elseif name === :output
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{FeatureDescription}
    elseif name === :predictedFeatureName
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :predictedProbabilitiesName
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :trainingInput
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{FeatureDescription}
    elseif name === :metadata
        return (obj.__protobuf_jl_internal_values[name])::Metadata
    else
        getfield(obj, name)
    end
end

mutable struct SerializedModel <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function SerializedModel(; kwargs...)
        obj = new(meta(SerializedModel), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct SerializedModel
const __meta_SerializedModel = Ref{ProtoMeta}()
function meta(::Type{SerializedModel})
    ProtoBuf.metalock() do
        if !isassigned(__meta_SerializedModel)
            __meta_SerializedModel[] = target = ProtoMeta(SerializedModel)
            allflds = Pair{Symbol,Union{Type,String}}[:identifier => AbstractString, :model => Vector{UInt8}]
            meta(target, SerializedModel, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_SerializedModel[]
    end
end
function Base.getproperty(obj::SerializedModel, name::Symbol)
    if name === :identifier
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :model
        return (obj.__protobuf_jl_internal_values[name])::Vector{UInt8}
    else
        getfield(obj, name)
    end
end

mutable struct Pipeline <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function Pipeline(; kwargs...)
        obj = new(meta(Pipeline), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct Pipeline (has cyclic type dependency)
const __meta_Pipeline = Ref{ProtoMeta}()
function meta(::Type{Pipeline})
    ProtoBuf.metalock() do
        if !isassigned(__meta_Pipeline)
            __meta_Pipeline[] = target = ProtoMeta(Pipeline)
            allflds = Pair{Symbol,Union{Type,String}}[:models => "Base.Vector{Model}", :names => Base.Vector{AbstractString}]
            meta(target, Pipeline, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_Pipeline[]
    end
end
function Base.getproperty(obj::Pipeline, name::Symbol)
    if name === :models
        return (obj.__protobuf_jl_internal_values[name])::Any
    elseif name === :names
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{AbstractString}
    else
        getfield(obj, name)
    end
end

mutable struct PipelineClassifier <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function PipelineClassifier(; kwargs...)
        obj = new(meta(PipelineClassifier), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct PipelineClassifier (has cyclic type dependency)
const __meta_PipelineClassifier = Ref{ProtoMeta}()
function meta(::Type{PipelineClassifier})
    ProtoBuf.metalock() do
        if !isassigned(__meta_PipelineClassifier)
            __meta_PipelineClassifier[] = target = ProtoMeta(PipelineClassifier)
            allflds = Pair{Symbol,Union{Type,String}}[:pipeline => Pipeline]
            meta(target, PipelineClassifier, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_PipelineClassifier[]
    end
end
function Base.getproperty(obj::PipelineClassifier, name::Symbol)
    if name === :pipeline
        return (obj.__protobuf_jl_internal_values[name])::Pipeline
    else
        getfield(obj, name)
    end
end

mutable struct PipelineRegressor <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function PipelineRegressor(; kwargs...)
        obj = new(meta(PipelineRegressor), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct PipelineRegressor (has cyclic type dependency)
const __meta_PipelineRegressor = Ref{ProtoMeta}()
function meta(::Type{PipelineRegressor})
    ProtoBuf.metalock() do
        if !isassigned(__meta_PipelineRegressor)
            __meta_PipelineRegressor[] = target = ProtoMeta(PipelineRegressor)
            allflds = Pair{Symbol,Union{Type,String}}[:pipeline => Pipeline]
            meta(target, PipelineRegressor, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_PipelineRegressor[]
    end
end
function Base.getproperty(obj::PipelineRegressor, name::Symbol)
    if name === :pipeline
        return (obj.__protobuf_jl_internal_values[name])::Pipeline
    else
        getfield(obj, name)
    end
end

mutable struct Model <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function Model(; kwargs...)
        obj = new(meta(Model), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct Model (has cyclic type dependency)
const __meta_Model = Ref{ProtoMeta}()
function meta(::Type{Model})
    ProtoBuf.metalock() do
        if !isassigned(__meta_Model)
            __meta_Model[] = target = ProtoMeta(Model)
            fnum = Int[1,2,10,200,201,202,300,301,302,303,304,400,401,402,403,404,500,501,555,556,600,601,602,603,604,606,607,609,610,900,2000,2001,2002,2003,2004,2005,3000]
            allflds = Pair{Symbol,Union{Type,String}}[:specificationVersion => Int32, :description => ModelDescription, :isUpdatable => Bool, :pipelineClassifier => PipelineClassifier, :pipelineRegressor => PipelineRegressor, :pipeline => Pipeline, :glmRegressor => GLMRegressor, :supportVectorRegressor => SupportVectorRegressor, :treeEnsembleRegressor => TreeEnsembleRegressor, :neuralNetworkRegressor => NeuralNetworkRegressor, :bayesianProbitRegressor => BayesianProbitRegressor, :glmClassifier => GLMClassifier, :supportVectorClassifier => SupportVectorClassifier, :treeEnsembleClassifier => TreeEnsembleClassifier, :neuralNetworkClassifier => NeuralNetworkClassifier, :kNearestNeighborsClassifier => KNearestNeighborsClassifier, :neuralNetwork => NeuralNetwork, :itemSimilarityRecommender => ItemSimilarityRecommender, :customModel => CustomModel, :linkedModel => LinkedModel, :oneHotEncoder => OneHotEncoder, :imputer => Imputer, :featureVectorizer => FeatureVectorizer, :dictVectorizer => DictVectorizer, :scaler => Scaler, :categoricalMapping => CategoricalMapping, :normalizer => Normalizer, :arrayFeatureExtractor => ArrayFeatureExtractor, :nonMaximumSuppression => NonMaximumSuppression, :identity => Identity, :textClassifier => CoreMLProtobuf.Specification.CoreMLModels.TextClassifier, :wordTagger => CoreMLProtobuf.Specification.CoreMLModels.WordTagger, :visionFeaturePrint => CoreMLProtobuf.Specification.CoreMLModels.VisionFeaturePrint, :soundAnalysisPreprocessing => CoreMLProtobuf.Specification.CoreMLModels.SoundAnalysisPreprocessing, :gazetteer => CoreMLProtobuf.Specification.CoreMLModels.Gazetteer, :wordEmbedding => CoreMLProtobuf.Specification.CoreMLModels.WordEmbedding, :serializedModel => SerializedModel]
            oneofs = Int[0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
            oneof_names = Symbol[Symbol("Type")]
            meta(target, Model, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, oneofs, oneof_names)
        end
        __meta_Model[]
    end
end
function Base.getproperty(obj::Model, name::Symbol)
    if name === :specificationVersion
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :description
        return (obj.__protobuf_jl_internal_values[name])::ModelDescription
    elseif name === :isUpdatable
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :pipelineClassifier
        return (obj.__protobuf_jl_internal_values[name])::PipelineClassifier
    elseif name === :pipelineRegressor
        return (obj.__protobuf_jl_internal_values[name])::PipelineRegressor
    elseif name === :pipeline
        return (obj.__protobuf_jl_internal_values[name])::Pipeline
    elseif name === :glmRegressor
        return (obj.__protobuf_jl_internal_values[name])::GLMRegressor
    elseif name === :supportVectorRegressor
        return (obj.__protobuf_jl_internal_values[name])::SupportVectorRegressor
    elseif name === :treeEnsembleRegressor
        return (obj.__protobuf_jl_internal_values[name])::TreeEnsembleRegressor
    elseif name === :neuralNetworkRegressor
        return (obj.__protobuf_jl_internal_values[name])::NeuralNetworkRegressor
    elseif name === :bayesianProbitRegressor
        return (obj.__protobuf_jl_internal_values[name])::BayesianProbitRegressor
    elseif name === :glmClassifier
        return (obj.__protobuf_jl_internal_values[name])::GLMClassifier
    elseif name === :supportVectorClassifier
        return (obj.__protobuf_jl_internal_values[name])::SupportVectorClassifier
    elseif name === :treeEnsembleClassifier
        return (obj.__protobuf_jl_internal_values[name])::TreeEnsembleClassifier
    elseif name === :neuralNetworkClassifier
        return (obj.__protobuf_jl_internal_values[name])::NeuralNetworkClassifier
    elseif name === :kNearestNeighborsClassifier
        return (obj.__protobuf_jl_internal_values[name])::KNearestNeighborsClassifier
    elseif name === :neuralNetwork
        return (obj.__protobuf_jl_internal_values[name])::NeuralNetwork
    elseif name === :itemSimilarityRecommender
        return (obj.__protobuf_jl_internal_values[name])::ItemSimilarityRecommender
    elseif name === :customModel
        return (obj.__protobuf_jl_internal_values[name])::CustomModel
    elseif name === :linkedModel
        return (obj.__protobuf_jl_internal_values[name])::LinkedModel
    elseif name === :oneHotEncoder
        return (obj.__protobuf_jl_internal_values[name])::OneHotEncoder
    elseif name === :imputer
        return (obj.__protobuf_jl_internal_values[name])::Imputer
    elseif name === :featureVectorizer
        return (obj.__protobuf_jl_internal_values[name])::FeatureVectorizer
    elseif name === :dictVectorizer
        return (obj.__protobuf_jl_internal_values[name])::DictVectorizer
    elseif name === :scaler
        return (obj.__protobuf_jl_internal_values[name])::Scaler
    elseif name === :categoricalMapping
        return (obj.__protobuf_jl_internal_values[name])::CategoricalMapping
    elseif name === :normalizer
        return (obj.__protobuf_jl_internal_values[name])::Normalizer
    elseif name === :arrayFeatureExtractor
        return (obj.__protobuf_jl_internal_values[name])::ArrayFeatureExtractor
    elseif name === :nonMaximumSuppression
        return (obj.__protobuf_jl_internal_values[name])::NonMaximumSuppression
    elseif name === :identity
        return (obj.__protobuf_jl_internal_values[name])::Identity
    elseif name === :textClassifier
        return (obj.__protobuf_jl_internal_values[name])::CoreMLProtobuf.Specification.CoreMLModels.TextClassifier
    elseif name === :wordTagger
        return (obj.__protobuf_jl_internal_values[name])::CoreMLProtobuf.Specification.CoreMLModels.WordTagger
    elseif name === :visionFeaturePrint
        return (obj.__protobuf_jl_internal_values[name])::CoreMLProtobuf.Specification.CoreMLModels.VisionFeaturePrint
    elseif name === :soundAnalysisPreprocessing
        return (obj.__protobuf_jl_internal_values[name])::CoreMLProtobuf.Specification.CoreMLModels.SoundAnalysisPreprocessing
    elseif name === :gazetteer
        return (obj.__protobuf_jl_internal_values[name])::CoreMLProtobuf.Specification.CoreMLModels.Gazetteer
    elseif name === :wordEmbedding
        return (obj.__protobuf_jl_internal_values[name])::CoreMLProtobuf.Specification.CoreMLModels.WordEmbedding
    elseif name === :serializedModel
        return (obj.__protobuf_jl_internal_values[name])::SerializedModel
    else
        getfield(obj, name)
    end
end

export Pipeline, PipelineClassifier, PipelineRegressor, FeatureDescription, Metadata_UserDefinedEntry, Metadata, ModelDescription, SerializedModel, Model, Pipeline, PipelineClassifier, PipelineRegressor, Model
# mapentries: "Metadata_UserDefinedEntry" => ("AbstractString", "AbstractString")


text:
export IAEAParticle, IAEAHeader
export IAEAPath

include("core.jl")
include("header.jl")
include("write.jl")
include("io.jl")
include("compressed.jl")

ext: jl


text:
using StackOverflow, HTTP

"""
    getcomments(sort::string = "creation", order::string = "desc")

    Prints 30 top comments in descending(default)/ascending order of their creation_date(default)/votes on the site.
"""

function getcomments(sort::String = "creation", order::String = "desc")

    r = HTTP.request("GET", "https://api.stackexchange.com/2.2/comments?order=$(order)&sort=$(sort)&site=stackoverflow")

    json_obj = StackOverflow.convert_HTTP_Response_To_JSON(r)

    for (k, v) in json_obj

        if occursin("items", k)
            for item in v
                for (key, value) in item
                    println("$(key) : $(value)")
                end
                println("\n")
            end
        end

    end

end


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

module BinaryPlatforms

export AbstractPlatform, Platform, HostPlatform, platform_dlext, tags, arch, os,
       os_version, libc, compiler_abi, libgfortran_version, libstdcxx_version,
       cxxstring_abi, parse_dl_name_version, detect_libgfortran_version,
       detect_libstdcxx_version, detect_cxxstring_abi, call_abi, wordsize, triplet,
       select_platform, platforms_match, platform_name
import .Libc.Libdl

### Submodule with information about CPU features
include("cpuid.jl")
using .CPUID

# This exists to ease compatibility with old-style Platform objects
abstract type AbstractPlatform; end

"""
    Platform

A `Platform` represents all relevant pieces of information that a julia process may need
to know about its execution environment, such as the processor architecture, operating
system, libc implementation, etc...  It is, at its heart, a key-value mapping of tags
(such as `arch`, `os`, `libc`, etc...) to values (such as `"arch" => "x86_64"`, or
`"os" => "windows"`, etc...).  `Platform` objects are extensible in that the tag mapping
is open for users to add their own mappings to, as long as the mappings do not conflict
with the set of reserved tags: `arch`, `os`, `os_version`, `libc`, `call_abi`,
`libgfortran_version`, `libstdcxx_version`, `cxxstring_abi` and `julia_version`.

Valid tags and values are composed of alphanumeric and period characters.  All tags and
values will be lowercased when stored to reduce variation.

Example:

    Platform("x86_64", "windows"; cuda = "10.1")
"""
struct Platform <: AbstractPlatform
    tags::Dict{String,String}
    # The "compare strategy" allows selective overriding on how a tag is compared
    compare_strategies::Dict{String,Function}

    function Platform(arch::String, os::String;
                      validate_strict::Bool = false,
                      compare_strategies::Dict{String,<:Function} = Dict{String,Function}(),
                      kwargs...)
        # A wee bit of normalization
        os = lowercase(os)
        arch = CPUID.normalize_arch(arch)

        tags = Dict{String,String}(
            "arch" => arch,
            "os" => os,
        )
        for (tag, value) in kwargs
            tag = lowercase(string(tag::Symbol))
            if tag ∈ ("arch", "os")
                throw(ArgumentError("Cannot double-pass key $(tag)"))
            end

            # Drop `nothing` values; this means feature is not present or use default value.
            if value === nothing
                continue
            end

            # Normalize things that are known to be version numbers so that comparisons are easy.
            # Note that in our effort to be extremely compatible, we actually allow something that
            # doesn't parse nicely into a VersionNumber to persist, but if `validate_strict` is
            # set to `true`, it will cause an error later on.
            if tag ∈ ("libgfortran_version", "libstdcxx_version", "os_version")
                if isa(value, VersionNumber)
                    value = string(value)
                elseif isa(value, AbstractString)
                    v = tryparse(VersionNumber, String(value))
                    if isa(v, VersionNumber)
                        value = string(v)
                    end
                end
            end

            # Use `add_tag!()` to add the tag to our collection of tags
            add_tag!(tags, tag, string(value)::String)
        end

        # Auto-map call_abi and libc where necessary:
        if os == "linux" && !haskey(tags, "libc")
            # Default to `glibc` on Linux
            tags["libc"] = "glibc"
        end
        if os == "linux" && arch ∈ ("armv7l", "armv6l") && "call_abi" ∉ keys(tags)
            # default `call_abi` to `eabihf` on 32-bit ARM
            tags["call_abi"] = "eabihf"
        end

        # If the user is asking for strict validation, do so.
        if validate_strict
            validate_tags(tags)
        end

        # By default, we compare julia_version only against major and minor versions:
        if haskey(tags, "julia_version") && !haskey(compare_strategies, "julia_version")
            compare_strategies["julia_version"] = (a::String, b::String, a_comparator, b_comparator) -> begin
                a = VersionNumber(a)
                b = VersionNumber(b)
                return a.major == b.major && a.minor == b.minor
            end
        end

        return new(tags, compare_strategies)
    end
end

# Simple tag insertion that performs a little bit of validation
function add_tag!(tags::Dict{String,String}, tag::String, value::String)
    # I know we said only alphanumeric and dots, but let's be generous so that we can expand
    # our support in the future while remaining as backwards-compatible as possible.  The
    # only characters that are absolutely disallowed right now are `-`, `+`, ` ` and things
    # that are illegal in filenames:
    nonos = raw"""+- /<>:"'\|?*"""
    if any(occursin(nono, tag) for nono in nonos)
        throw(ArgumentError("Invalid character in tag name \"$(tag)\"!"))
    end

    # Normalize and reject nonos
    value = lowercase(value)
    if any(occursin(nono, value) for nono in nonos)
        throw(ArgumentError("Invalid character in tag value \"$(value)\"!"))
    end
    tags[tag] = value
    return value
end

# Other `Platform` types can override this (I'm looking at you, `AnyPlatform`)
tags(p::Platform) = p.tags

# Make it act more like a dict
Base.getindex(p::AbstractPlatform, k::String) = getindex(tags(p), k)
Base.haskey(p::AbstractPlatform, k::String) = haskey(tags(p), k)
function Base.setindex!(p::AbstractPlatform, v::String, k::String)
    add_tag!(tags(p), k, v)
    return p
end

# Hash definitino to ensure that it's stable
function Base.hash(p::Platform, h::UInt)
    h += 0x506c6174666f726d % UInt
    h = hash(p.tags, h)
    h = hash(p.compare_strategies, h)
    return h
end

# Simple equality definition; for compatibility testing, use `platforms_match()`
function Base.:(==)(a::Platform, b::Platform)
    return a.tags == b.tags && a.compare_strategies == b.compare_strategies
end

# Allow us to easily serialize Platform objects
function Base.repr(p::Platform; context=nothing)
    str = string(
        "Platform(",
        repr(arch(p)),
        ", ",
        repr(os(p)),
        "; ",
        join(("$(k) = $(repr(v))" for (k, v) in tags(p) if k ∉ ("arch", "os")), ", "),
        ")",
    )
end

# Make showing the platform a bit more palatable
function Base.show(io::IO, p::Platform)
    str = string(platform_name(p), " ", arch(p))
    # Add on all the other tags not covered by os/arch:
    other_tags = sort(collect(filter(kv -> kv[1] ∉ ("os", "arch"), tags(p))))
    if !isempty(other_tags)
        str = string(str, " {", join([string(k, "=", v) for (k, v) in other_tags], ", "), "}")
    end
    print(io, str)
end

function validate_tags(tags::Dict)
    throw_invalid_key(k) = throw(ArgumentError("Key \"$(k)\" cannot have value \"$(tags[k])\""))
    # Validate `arch`
    if tags["arch"] ∉ ("x86_64", "i686", "armv7l", "armv6l", "aarch64", "powerpc64le")
        throw_invalid_key("arch")
    end
    # Validate `os`
    if tags["os"] ∉ ("linux", "macos", "freebsd", "windows")
        throw_invalid_key("os")
    end
    # Validate `os`/`arch` combination
    throw_os_mismatch() = throw(ArgumentError("Invalid os/arch combination: $(tags["os"])/$(tags["arch"])"))
    if tags["os"] == "windows" && tags["arch"] ∉ ("x86_64", "i686", "armv7l", "aarch64")
        throw_os_mismatch()
    end
    if tags["os"] == "macos" && tags["arch"] ∉ ("x86_64", "aarch64")
        throw_os_mismatch()
    end

    # Validate `os`/`libc` combination
    throw_libc_mismatch() = throw(ArgumentError("Invalid os/libc combination: $(tags["os"])/$(tags["libc"])"))
    if tags["os"] == "linux"
        # Linux always has a `libc` entry
        if tags["libc"] ∉ ("glibc", "musl")
            throw_libc_mismatch()
        end
    else
        # Nothing else is allowed to have a `libc` entry
        if haskey(tags, "libc")
            throw_libc_mismatch()
        end
    end

    # Validate `os`/`arch`/`call_abi` combination
    throw_call_abi_mismatch() = throw(ArgumentError("Invalid os/arch/call_abi combination: $(tags["os"])/$(tags["arch"])/$(tags["call_abi"])"))
    if tags["os"] == "linux" && tags["arch"] ∈ ("armv7l", "armv6l")
        # If an ARM linux has does not have `call_abi` set to something valid, be sad.
        if !haskey(tags, "call_abi") || tags["call_abi"] ∉ ("eabihf", "eabi")
            throw_call_abi_mismatch()
        end
    else
        # Nothing else should have a `call_abi`.
        if haskey(tags, "call_abi")
            throw_call_abi_mismatch()
        end
    end

    # Validate `libgfortran_version` is a parsable `VersionNumber`
    throw_version_number(k) = throw(ArgumentError("\"$(k)\" cannot have value \"$(tags[k])\", must be a valid VersionNumber"))
    if "libgfortran_version" in keys(tags) && tryparse(VersionNumber, tags["libgfortran_version"]) === nothing
        throw_version_number("libgfortran_version")
    end

    # Validate `cxxstring_abi` is one of the two valid options:
    if "cxxstring_abi" in keys(tags) && tags["cxxstring_abi"] ∉ ("cxx03", "cxx11")
        throw_invalid_key("cxxstring_abi")
    end

    # Validate `libstdcxx_version` is a parsable `VersionNumber`
    if "libstdcxx_version" in keys(tags) && tryparse(VersionNumber, tags["libstdcxx_version"]) === nothing
        throw_version_number("libstdcxx_version")
    end
end

function set_compare_strategy!(p::Platform, key::String, f::Function)
    if !haskey(p.tags, key)
        throw(ArgumentError("Cannot set comparison strategy for nonexistant tag $(key)!"))
    end
    p.compare_strategies[key] = f
end

function get_compare_strategy(p::Platform, key::String, default = compare_default)
    if !haskey(p.tags, key)
        throw(ArgumentError("Cannot get comparison strategy for nonexistant tag $(key)!"))
    end
    return get(p.compare_strategies, key, default)
end
get_compare_strategy(p::AbstractPlatform, key::String, default = compare_default) = default

"""
    compare_default(a::String, b::String, a_requested::Bool, b_requested::Bool)

Default comparison strategy that falls back to `a == b`.  This only ever happens if both
`a` and `b` request this strategy, as any other strategy is preferrable to this one.
"""
function compare_default(a::String, b::String, a_requested::Bool, b_requested::Bool)
    return a == b
end

"""
    compare_version_cap(a::String, b::String, a_comparator, b_comparator)

Example comparison strategy for `set_comparison_strategy!()` that implements a version
cap for host platforms that support _up to_ a particular version number.  As an example,
if an artifact is built for macOS 10.9, it can run on macOS 10.11, however if it were
built for macOS 10.12, it could not.  Therefore, the host platform of macOS 10.11 has a
version cap at `v"10.11"`.

Note that because both hosts and artifacts are represented with `Platform` objects it
is possible to call `platforms_match()` with two artifacts, a host and an artifact, an
artifact and a host, and even two hosts.  We attempt to do something intelligent for all
cases, but in the case of comparing version caps between two hosts, we return `true` only
if the two host platforms are in fact identical.
"""
function compare_version_cap(a::String, b::String, a_requested::Bool, b_requested::Bool)
    a = VersionNumber(a)
    b = VersionNumber(b)

    # If both b and a requested, then we fall back to equality:
    if a_requested && b_requested
        return a == b
    end

    # Otherwise, do the comparison between the the single version cap and the single version:
    if a_requested
        return b <= a
    else
        return a <= b
    end
end

"""
    HostPlatform(p::AbstractPlatform)

Convert a `Platform` to act like a "host"; e.g. if it has a version-bound tag such as
`"libstdcxx_version" => "3.4.26"`, it will treat that value as an upper bound, rather
than a characteristic.  `Platform` objects that define artifacts generally denote the
SDK or version that the artifact was built with, but for platforms, these versions are
generally the maximal version the platform can support.  The way this transformation
is implemented is to change the appropriate comparison strategies to treat these pieces
of data as bounds rather than points in any comparison.
"""
function HostPlatform(p::AbstractPlatform)
    if haskey(p, "os_version")
        set_compare_strategy!(p, "os_version", compare_version_cap)
    end
    if haskey(p, "libstdcxx_version")
        set_compare_strategy!(p, "libstdcxx_version", compare_version_cap)
    end
    return p
end

"""
    arch(p::AbstractPlatform)

Get the architecture for the given `Platform` object as a `String`.

# Examples
```jldoctest
julia> arch(Platform("aarch64", "Linux"))
"aarch64"

julia> arch(Platform("amd64", "freebsd"))
"x86_64"
```
"""
arch(p::AbstractPlatform) = get(tags(p), "arch", nothing)

"""
    os(p::AbstractPlatform)

Get the operating system for the given `Platform` object as a `String`.

# Examples
```jldoctest
julia> os(Platform("armv7l", "Linux"))
"linux"

julia> os(Platform("aarch64", "macos"))
"macos"
```
"""
os(p::AbstractPlatform) = get(tags(p), "os", nothing)

# As a special helper, it's sometimes useful to know the current OS at compile-time
function os()
    if Sys.iswindows()
        return "windows"
    elseif Sys.isapple()
        return "macos"
    elseif Sys.isbsd()
        return "freebsd"
    else
        return "linux"
    end
end

"""
    libc(p::AbstractPlatform)

Get the libc for the given `Platform` object as a `String`.  Returns `nothing` on
platforms with no explicit `libc` choices (which is most platforms).

# Examples
```jldoctest
julia> libc(Platform("armv7l", "Linux"))
"glibc"

julia> libc(Platform("aarch64", "linux"; libc="musl"))
"musl"

julia> libc(Platform("i686", "Windows"))
```
"""
libc(p::AbstractPlatform) = get(tags(p), "libc", nothing)

"""
    call_abi(p::AbstractPlatform)

Get the call ABI for the given `Platform` object as a `String`.  Returns `nothing` on
platforms with no explicit `call_abi` choices (which is most platforms).

# Examples
```jldoctest
julia> call_abi(Platform("armv7l", "Linux"))
"eabihf"

julia> call_abi(Platform("x86_64", "macos"))
```
"""
call_abi(p::AbstractPlatform) = get(tags(p), "call_abi", nothing)

const platform_names = Dict(
    "linux" => "Linux",
    "macos" => "macOS",
    "windows" => "Windows",
    "freebsd" => "FreeBSD",
    nothing => "Unknown",
)

"""
    platform_name(p::AbstractPlatform)

Get the "platform name" of the given platform, returning e.g. "Linux" or "Windows".
"""
function platform_name(p::AbstractPlatform)
    return platform_names[os(p)]
end

function VNorNothing(d::Dict, key)
    v = get(d, key, nothing)
    if v === nothing
        return nothing
    end
    return VersionNumber(v)::VersionNumber
end

"""
    libgfortran_version(p::AbstractPlatform)

Get the libgfortran version dictated by this `Platform` object as a `VersionNumber`,
or `nothing` if no compatibility bound is imposed.
"""
libgfortran_version(p::AbstractPlatform) = VNorNothing(tags(p), "libgfortran_version")

"""
    libstdcxx_version(p::AbstractPlatform)

Get the libstdc++ version dictated by this `Platform` object, or `nothing` if no
compatibility bound is imposed.
"""
libstdcxx_version(p::AbstractPlatform) = VNorNothing(tags(p), "libstdcxx_version")

"""
    cxxstring_abi(p::AbstractPlatform)

Get the c++ string ABI dictated by this `Platform` object, or `nothing` if no ABI is imposed.
"""
cxxstring_abi(p::AbstractPlatform) = get(tags(p), "cxxstring_abi", nothing)

"""
    os_version(p::AbstractPlatform)

Get the OS version dictated by this `Platform` object, or `nothing` if no OS version is
imposed/no data is available.  This is most commonly used by MacOS and FreeBSD objects
where we have high platform SDK fragmentation, and features are available only on certain
platform versions.
"""
os_version(p::AbstractPlatform) = VNorNothing(tags(p), "os_version")

"""
    wordsize(p::AbstractPlatform)

Get the word size for the given `Platform` object.

# Examples
```jldoctest
julia> wordsize(Platform("armv7l", "linux"))
32

julia> wordsize(Platform("x86_64", "macos"))
64
```
"""
wordsize(p::AbstractPlatform) = (arch(p) ∈ ("i686", "armv6l", "armv7l")) ? 32 : 64

"""
    triplet(p::AbstractPlatform; exclude_tags::Vector{String})

Get the target triplet for the given `Platform` object as a `String`.

# Examples
```jldoctest
julia> triplet(Platform("x86_64", "MacOS"))
"x86_64-apple-darwin"

julia> triplet(Platform("i686", "Windows"))
"i686-w64-mingw32"

julia> triplet(Platform("armv7l", "Linux"; libgfortran_version="3"))
"armv7l-linux-gnueabihf-libgfortran3"
```
"""
function triplet(p::AbstractPlatform)
    str = string(
        arch(p)::Union{Symbol,String},
        os_str(p),
        libc_str(p),
        call_abi_str(p),
    )

    # Tack on optional compiler ABI flags
    if libgfortran_version(p) !== nothing
        str = string(str, "-libgfortran", libgfortran_version(p).major)
    end
    if cxxstring_abi(p) !== nothing
        str = string(str, "-", cxxstring_abi(p))
    end
    if libstdcxx_version(p) !== nothing
        str = string(str, "-libstdcxx", libstdcxx_version(p).patch)
    end

    # Tack on all extra tags
    for (tag, val) in tags(p)
        if tag ∈ ("os", "arch", "libc", "call_abi", "libgfortran_version", "libstdcxx_version", "cxxstring_abi", "os_version")
            continue
        end
        str = string(str, "-", tag, "+", val)
    end
    return str
end

function os_str(p::AbstractPlatform)
    if os(p) == "linux"
        return "-linux"
    elseif os(p) == "macos"
        osvn = os_version(p)
        if osvn !== nothing
            return "-apple-darwin$(osvn.major)"
        else
            return "-apple-darwin"
        end
    elseif os(p) == "windows"
        return "-w64-mingw32"
    elseif os(p) == "freebsd"
        osvn = os_version(p)
        if osvn !== nothing
            return "-unknown-freebsd$(osvn.major).$(osvn.minor)"
        else
            return "-unknown-freebsd"
        end
    else
        return "-unknown"
    end
end

# Helper functions for Linux and FreeBSD libc/abi mishmashes
function libc_str(p::AbstractPlatform)
    lc = libc(p)
    if lc === nothing
        return ""
    elseif lc === "glibc"
        return "-gnu"
    else
        return string("-", lc)
    end
end
function call_abi_str(p::AbstractPlatform)
    cabi = call_abi(p)
    cabi === nothing ? "" : string(cabi::Union{Symbol,String})
end

Sys.isapple(p::AbstractPlatform) = os(p) == "macos"
Sys.islinux(p::AbstractPlatform) = os(p) == "linux"
Sys.iswindows(p::AbstractPlatform) = os(p) == "windows"
Sys.isfreebsd(p::AbstractPlatform) = os(p) == "freebsd"
Sys.isbsd(p::AbstractPlatform) = os(p) ∈ ("freebsd", "macos")

const arch_mapping = Dict(
    "x86_64" => "(x86_|amd)64",
    "i686" => "i\\d86",
    "aarch64" => "(aarch64|arm64)",
    "armv7l" => "arm(v7l)?", # if we just see `arm-linux-gnueabihf`, we assume it's `armv7l`
    "armv6l" => "armv6l",
    "powerpc64le" => "p(ower)?pc64le",
)
# Keep this in sync with `CPUID.ISAs_by_family`
# These are the CPUID side of the microarchitectures targeted by GCC flags in BinaryBuilder.jl
const arch_march_isa_mapping = let
    function get_set(arch, name)
        all = CPUID.ISAs_by_family[arch]
        return all[findfirst(x -> x.first == name, all)].second
    end
    Dict(
        "i686" => [
            "pentium4" => get_set("i686", "pentium4"),
            "prescott" => get_set("i686", "prescott"),
        ],
        "x86_64" => [
            "x86_64" => get_set("x86_64", "x86_64"),
            "avx" => get_set("x86_64", "sandybridge"),
            "avx2" => get_set("x86_64", "haswell"),
            "avx512" => get_set("x86_64", "skylake_avx512"),
        ],
        "armv6l" => [
            "arm1176jzfs" => get_set("armv6l", "arm1176jzfs"),
        ],
        "armv7l" => [
            "armv7l" => get_set("armv7l", "armv7l"),
            "neonvfpv4" => get_set("armv7l", "armv7l+neon+vfpv4"),
        ],
        "aarch64" => [
            "armv8_0" => get_set("aarch64", "armv8.0-a"),
            "armv8_1" => get_set("aarch64", "armv8.1-a"),
            "armv8_2_crypto" => get_set("aarch64", "armv8.2-a+crypto"),
            "armv8_4_crypto_sve" => get_set("aarch64", "armv8.4-a+crypto+sve"),
        ],
        "powerpc64le" => [
            "power8" => get_set("powerpc64le", "power8"),
        ]
    )
end
const os_mapping = Dict(
    "macos" => "-apple-darwin[\\d\\.]*",
    "freebsd" => "-(.*-)?freebsd[\\d\\.]*",
    "windows" => "-w64-mingw32",
    "linux" => "-(.*-)?linux",
)
const libc_mapping = Dict(
    "libc_nothing" => "",
    "glibc" => "-gnu",
    "musl" => "-musl",
)
const call_abi_mapping = Dict(
    "call_abi_nothing" => "",
    "eabihf" => "eabihf",
    "eabi" => "eabi",
)
const libgfortran_version_mapping = Dict(
    "libgfortran_nothing" => "",
    "libgfortran3" => "(-libgfortran3)|(-gcc4)", # support old-style `gccX` versioning
    "libgfortran4" => "(-libgfortran4)|(-gcc7)",
    "libgfortran5" => "(-libgfortran5)|(-gcc8)",
)
const cxxstring_abi_mapping = Dict(
    "cxxstring_nothing" => "",
    "cxx03" => "-cxx03",
    "cxx11" => "-cxx11",
)
const libstdcxx_version_mapping = Dict{String,String}(
    "libstdcxx_nothing" => "",
    "libstdcxx" => "-libstdcxx\\d+",
)

"""
    parse(::Type{Platform}, triplet::AbstractString)

Parses a string platform triplet back into a `Platform` object.
"""
function Base.parse(::Type{Platform}, triplet::AbstractString; validate_strict::Bool = false)
    # Helper function to collapse dictionary of mappings down into a regex of
    # named capture groups joined by "|" operators
    c(mapping) = string("(",join(["(?<$k>$v)" for (k, v) in mapping], "|"), ")")

    # We're going to build a mondo regex here to parse everything:
    triplet_regex = Regex(string(
        "^",
        # First, the core triplet; arch/os/libc/call_abi
        c(arch_mapping),
        c(os_mapping),
        c(libc_mapping),
        c(call_abi_mapping),
        # Next, optional things, like libgfortran/libstdcxx/cxxstring abi
        c(libgfortran_version_mapping),
        c(cxxstring_abi_mapping),
        c(libstdcxx_version_mapping),
        # Finally, the catch-all for extended tags
        "(?<tags>(?:-[^-]+\\+[^-]+)*)?",
        "\$",
    ))

    m = match(triplet_regex, triplet)
    if m !== nothing
        # Helper function to find the single named field within the giant regex
        # that is not `nothing` for each mapping we give it.
        get_field(m, mapping) = begin
            for k in keys(mapping)
                if m[k] !== nothing
                    # Convert our sentinel `nothing` values to actual `nothing`
                    if endswith(k, "_nothing")
                        return nothing
                    end
                    # Convert libgfortran/libstdcxx version numbers
                    if startswith(k, "libgfortran")
                        return VersionNumber(parse(Int,k[12:end]))
                    elseif startswith(k, "libstdcxx")
                        return VersionNumber(3, 4, parse(Int,m[k][11:end]))
                    else
                        return k
                    end
                end
            end
        end

        # Extract the information we're interested in:
        arch = get_field(m, arch_mapping)
        os = get_field(m, os_mapping)
        libc = get_field(m, libc_mapping)
        call_abi = get_field(m, call_abi_mapping)
        libgfortran_version = get_field(m, libgfortran_version_mapping)
        libstdcxx_version = get_field(m, libstdcxx_version_mapping)
        cxxstring_abi = get_field(m, cxxstring_abi_mapping)
        function split_tags(tagstr)
            tag_fields = filter(!isempty, split(tagstr, "-"))
            if isempty(tag_fields)
                return Pair{String,String}[]
            end
            return map(v -> Symbol(v[1]) => v[2], split.(tag_fields, "+"))
        end
        tags = split_tags(m["tags"])

        # Special parsing of os version number, if any exists
        function extract_os_version(os_name, pattern)
            m_osvn = match(pattern, m[os_name])
            if m_osvn !== nothing
                return VersionNumber(m_osvn.captures[1])
            end
            return nothing
        end
        os_version = nothing
        if os == "macos"
            os_version = extract_os_version("macos", r".*darwin([\d\.]+)")
        end
        if os == "freebsd"
            os_version = extract_os_version("freebsd", r".*freebsd([\d.]+)")
        end

        return Platform(
            arch, os;
            validate_strict,
            libc,
            call_abi,
            libgfortran_version,
            cxxstring_abi,
            libstdcxx_version,
            os_version,
            tags...,
        )
    end
    throw(ArgumentError("Platform `$(triplet)` is not an officially supported platform"))
end

function Base.tryparse(::Type{Platform}, triplet::AbstractString)
    try
        parse(Platform, triplet)
    catch e
        if isa(e, InterruptException)
            rethrow(e)
        end
        return nothing
    end
end

"""
    platform_dlext(p::AbstractPlatform = HostPlatform())

Return the dynamic library extension for the given platform, defaulting to the
currently running platform.  E.g. returns "so" for a Linux-based platform,
"dll" for a Windows-based platform, etc...
"""
function platform_dlext(p::AbstractPlatform = HostPlatform())
    if os(p) == "windows"
        return "dll"
    elseif os(p) == "macos"
        return "dylib"
    else
        return "so"
    end
end

"""
    parse_dl_name_version(path::String, platform::AbstractPlatform)

Given a path to a dynamic library, parse out what information we can
from the filename.  E.g. given something like "lib/libfoo.so.3.2",
this function returns `"libfoo", v"3.2"`.  If the path name is not a
valid dynamic library, this method throws an error.  If no soversion
can be extracted from the filename, as in "libbar.so" this method
returns `"libbar", nothing`.
"""
function parse_dl_name_version(path::String, os::String)
    # Use an extraction regex that matches the given OS
    local dlregex
    if os == "windows"
        # On Windows, libraries look like `libnettle-6.dll`
        dlregex = r"^(.*?)(?:-((?:[\.\d]+)*))?\.dll$"
    elseif os == "macos"
        # On OSX, libraries look like `libnettle.6.3.dylib`
        dlregex = r"^(.*?)((?:\.[\d]+)*)\.dylib$"
    else
        # On Linux and FreeBSD, libraries look like `libnettle.so.6.3.0`
        dlregex = r"^(.*?)\.so((?:\.[\d]+)*)$"
    end

    m = match(dlregex, basename(path))
    if m === nothing
        throw(ArgumentError("Invalid dynamic library path '$path'"))
    end

    # Extract name and version
    name = m.captures[1]
    version = m.captures[2]
    if version === nothing || isempty(version)
        version = nothing
    else
        version = VersionNumber(strip(version, '.'))
    end
    return name, version
end

# Adapter for `AbstractString`
function parse_dl_name_version(path::AbstractString, os::AbstractString)
    return parse_dl_name_version(string(path)::String, string(os)::String)
end

"""
    detect_libgfortran_version()

Inspects the current Julia process to determine the libgfortran version this Julia is
linked against (if any).
"""
function detect_libgfortran_version()
    libgfortran_paths = filter(x -> occursin("libgfortran", x), Libdl.dllist())
    if isempty(libgfortran_paths)
        # One day, I hope to not be linking against libgfortran in base Julia
        return nothing
    end
    libgfortran_path = first(libgfortran_paths)

    name, version = parse_dl_name_version(libgfortran_path, os())
    if version === nothing
        # Even though we complain about this, we allow it to continue in the hopes that
        # we shall march on to a BRIGHTER TOMORROW.  One in which we are not shackled
        # by the constraints of libgfortran compiler ABIs upon our precious programming
        # languages; one where the mistakes of yesterday are mere memories and not
        # continual maintenance burdens upon the children of the dawn; one where numeric
        # code may be cleanly implemented in a modern language and not bestowed onto the
        # next generation by grizzled ancients, documented only with a faded yellow
        # sticky note that bears a hastily-scribbled "good luck".
        @warn("Unable to determine libgfortran version from '$(libgfortran_path)'")
    end
    return version
end

"""
    detect_libstdcxx_version(max_minor_version::Int=30)

Inspects the currently running Julia process to find out what version of libstdc++
it is linked against (if any).  `max_minor_version` is the latest version in the
3.4 series of GLIBCXX where the search is performed.
"""
function detect_libstdcxx_version(max_minor_version::Int=30)
    libstdcxx_paths = filter(x -> occursin("libstdc++", x), Libdl.dllist())
    if isempty(libstdcxx_paths)
        # This can happen if we were built by clang, so we don't link against
        # libstdc++ at all.
        return nothing
    end

    # Brute-force our way through GLIBCXX_* symbols to discover which version we're linked against
    hdl = Libdl.dlopen(first(libstdcxx_paths))
    # Try all GLIBCXX versions down to GCC v4.8:
    # https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html
    for minor_version in max_minor_version:-1:18
        if Libdl.dlsym(hdl, "GLIBCXX_3.4.$(minor_version)"; throw_error=false) !== nothing
            Libdl.dlclose(hdl)
            return VersionNumber("3.4.$(minor_version)")
        end
    end
    Libdl.dlclose(hdl)
    return nothing
end

"""
    detect_cxxstring_abi()

Inspects the currently running Julia process to see what version of the C++11 string ABI
it was compiled with (this is only relevant if compiled with `g++`; `clang` has no
incompatibilities yet, bless its heart).  In reality, this actually checks for symbols
within LLVM, but that is close enough for our purposes, as you can't mix configurations
between Julia and LLVM; they must match.
"""
function detect_cxxstring_abi()
    # First, if we're not linked against libstdc++, then early-exit because this doesn't matter.
    libstdcxx_paths = filter(x -> occursin("libstdc++", x), Libdl.dllist())
    if isempty(libstdcxx_paths)
        # We were probably built by `clang`; we don't link against `libstdc++`` at all.
        return nothing
    end

    function open_libllvm(f::Function)
        for lib_name in ("libLLVM", "LLVM", "libLLVMSupport")
            hdl = Libdl.dlopen_e(lib_name)
            if hdl != C_NULL
                try
                    return f(hdl)
                finally
                    Libdl.dlclose(hdl)
                end
            end
        end
        error("Unable to open libLLVM!")
    end

    return open_libllvm() do hdl
        # Check for llvm::sys::getProcessTriple(), first without cxx11 tag:
        if Libdl.dlsym_e(hdl, "_ZN4llvm3sys16getProcessTripleEv") != C_NULL
            return "cxx03"
        elseif Libdl.dlsym_e(hdl, "_ZN4llvm3sys16getProcessTripleB5cxx11Ev") != C_NULL
            return "cxx11"
        else
            @warn("Unable to find llvm::sys::getProcessTriple() in libLLVM!")
            return nothing
        end
    end
end

"""
    host_triplet()

Build host triplet out of `Sys.MACHINE` and various introspective utilities that
detect compiler ABI values such as `libgfortran_version`, `libstdcxx_version` and
`cxxstring_abi`.  We do this without using any `Platform` tech as it must run before
we have much of that built.
"""
function host_triplet()
    str = Base.BUILD_TRIPLET

    if !occursin("-libgfortran", str)
        libgfortran_version = detect_libgfortran_version()
        if libgfortran_version !== nothing
            str = string(str, "-libgfortran", libgfortran_version.major)
        end
    end

    if !occursin("-cxx", str)
        cxxstring_abi = detect_cxxstring_abi()
        if cxxstring_abi !== nothing
            str = string(str, "-", cxxstring_abi)
        end
    end

    if !occursin("-libstdcxx", str)
        libstdcxx_version = detect_libstdcxx_version()
        if libstdcxx_version !== nothing
            str = string(str, "-libstdcxx", libstdcxx_version.patch)
        end
    end

    # Add on julia_version extended tag
    if !occursin("-julia_version+", str)
        str = string(str, "-julia_version+", VersionNumber(VERSION.major, VERSION.minor, VERSION.patch))
    end
    return str
end

"""
    HostPlatform()

Return the `Platform` object that corresponds to the current host system, with all
relevant comparison strategies set to host platform mode.  This is equivalent to:

    HostPlatform(parse(Platform, Base.BinaryPlatforms.host_triplet()))
"""
function HostPlatform()
    return HostPlatform(parse(Platform, host_triplet()))::Platform
end

"""
    platforms_match(a::AbstractPlatform, b::AbstractPlatform)

Return `true` if `a` and `b` are matching platforms, where matching is determined by
comparing all keys contained within the platform objects, and if both objects contain
entries for that key, they must match.  Comparison, by default, is performed using
the `==` operator, however this can be overridden on a key-by-key basis by adding
"comparison strategies" through `set_compare_strategy!(platform, key, func)`.

Note that as the comparison strategy is set on the `Platform` object, and not globally,
a custom comparison strategy is first looked for within the `a` object, then if none
is found, it is looked for in the `b` object.  Finally, if none is found in either, the
default of `==(ak, bk)` is used.  We throw an error if custom comparison strategies are
used on both `a` and `b` and they are not the same custom comparison.

The reserved tags `os_version` and `libstdcxx_version` use this mechanism to provide
bounded version constraints, where an artifact can specify that it was built using APIs
only available in macOS `v"10.11"` and later, or an artifact can state that it requires
a libstdc++ that is at least `v"3.4.22"`, etc...
"""
function platforms_match(a::AbstractPlatform, b::AbstractPlatform)
    for k in union(keys(tags(a)::Dict{String,String}), keys(tags(b)::Dict{String,String}))
        ak = get(tags(a), k, nothing)
        bk = get(tags(b), k, nothing)

        # Only continue if both `ak` and `bk` are not `nothing`
        if ak === nothing || bk === nothing
            continue
        end

        a_comp = get_compare_strategy(a, k)
        b_comp = get_compare_strategy(b, k)

        # Throw an error if `a` and `b` have both set non-default comparison strategies for `k`
        # and they're not the same strategy.
        if a_comp != compare_default && b_comp != compare_default && a_comp != b_comp
            throw(ArgumentError("Cannot compare Platform objects with two different non-default comparison strategies for the same key \"$(k)\""))
        end

        # Select the custom comparator, if we have one.
        comparator = a_comp
        if b_comp != compare_default
            comparator = b_comp
        end

        # Call the comparator, passing in which objects requested this comparison (one, the other, or both)
        # For some comparators this doesn't matter, but for non-symmetrical comparisons, it does.
        if !comparator(ak, bk, a_comp == comparator, b_comp == comparator)
            return false
        end
    end
    return true
end

function platforms_match(a::String, b::AbstractPlatform)
    return platforms_match(parse(Platform, a), b)
end
function platforms_match(a::AbstractPlatform, b::String)
    return platforms_match(a, parse(Platform, b))
end
platforms_match(a::String, b::String) = platforms_match(parse(Platform, a), parse(Platform, b))

# Adapters for AbstractString backedge avoidance
platforms_match(a::AbstractString, b::AbstractPlatform) = platforms_match(string(a)::String, b)
platforms_match(a::AbstractPlatform, b::AbstractString) = platforms_match(a, string(b)::String)
platforms_match(a::AbstractString, b::AbstractString) = platforms_match(string(a)::String, string(b)::String)

"""
    select_platform(download_info::Dict, platform::AbstractPlatform = HostPlatform())

Given a `download_info` dictionary mapping platforms to some value, choose
the value whose key best matches `platform`, returning `nothing` if no matches
can be found.

Platform attributes such as architecture, libc, calling ABI, etc... must all
match exactly, however attributes such as compiler ABI can have wildcards
within them such as `nothing` which matches any version of GCC.
"""
function select_platform(download_info::Dict, platform::AbstractPlatform = HostPlatform())
    ps = collect(filter(p -> platforms_match(p, platform), keys(download_info)))

    if isempty(ps)
        return nothing
    end

    # At this point, we may have multiple possibilities.  E.g. if, in the future,
    # Julia can be built without a direct dependency on libgfortran, we may match
    # multiple tarballs that vary only within their libgfortran ABI.  To narrow it
    # down, we just sort by triplet, then pick the last one.  This has the effect
    # of generally choosing the latest release (e.g. a `libgfortran5` tarball
    # rather than a `libgfortran3` tarball)
    p = last(sort(ps, by = p -> triplet(p)))
    return download_info[p]
end

end # module

max_stars_repo_name: udesou/julia

max_issues_repo_name: udesou/julia

max_forks_repo_name: udesou/julia


text:
"""
## SWSPlots

The SWSPlots module provides plotting functions to show maps with shear wave splitting
results.

"""
module SWSPlots

using Geodesy, Plots

using SWSs
using CircPlot

export
    plot_splits_bars,
    plot_splits_bars!,
    plot_splits_hist,
    plot_splits_hist!

const SWSArr = Union{SWS, Array{SWS}}
const PlotSubplot = Union{Plots.Plot,Plots.Subplot}

"""
    plot_splits_bars!(p::Plots.Plot, splits::SWSArr; km=false, scale=km?10:1e4, location=:station, kwargs...) -> p::Plots.Plot

Add to a `Plot`, `p`, a set of bars whose azimuth is aligned with the fast orientations ϕ
and whose length is proportional to δt, returning the modified `p`

    plot_splits_bars(splits; kwargs...) -> p::Plots.Plot

Return a new `Plot` `p`.

Set `km` to `true` to divide all distances by `1e3`.  `scale` can be used to set the
legnthscale of bars, and `location` can be one of `:station`, `:midpoint` or `:event`.
"""
function plot_splits_bars!(p::PlotSubplot, splits::SWSArr;
        km=false, scale=km?10:1e4, location=:station, kwargs...)
    s = splits
    x, y = if location == :station
        s[:sx], s[:sy]
    elseif location == :midpoint
        (s[:sx] + s[:ex])./2, (s[:sy] + s[:ey])./2
    elseif location == :event
        s[:ex], s[:ey]
    else
        throw(ArgumentError("`location` ($location) must be one of:" *
            " $([:station, :location, :midpoint])"))
    end
    if km
        x, y = x/1e3, y/1e3
    end
    ϕ = deg2rad.(s[:phi])
    dt = s[:dt]
    u, v = scale.*dt.*sin.(ϕ), scale.*dt.*cos.(ϕ)
    for (U,V) in zip((u,-u), (v,-v))
        quiver!(p, x, y, quiver=(U,V), arrow=(0,0), line=(stroke(4,:blue)); kwargs...)
    end
    p
end
plot_splits_bars(splits::SWSArr; kwargs...) = plot_splits_bars!(plot(), splits; kwargs...)
@doc (@doc plot_splits_bars!) plot_splits_bars

"""
    plot_splits_hist!(p::Plots.Plot, splits::SWSArr; km=false, binwidth=20, maxsize=km?5:5e3, minobs=3, kwargs...)
"""
function plot_splits_hist!(p::PlotSubplot, splits::SWSArr;
        km=false, binwidth=20, maxsize=km?5:5e3, minobs=3, kwargs...)
    s = splits
    stas, sx, sy = sta_coords(s)
    km && (sx /= 1e3; sy /= 1e3)
    hists = Array{Array{Plots.Shape}}(0)
    colours = [:red, :green, :blue, :orange, :white]
    for (i,sta) in enumerate(sort(stas))
        plot!(p, chistogram(s[s[:stnm] .== sta][:phi], binwidth, true, sx[i], sy[i],
            axial=true, azimuth=true, maxr=maxsize, minobs=minobs);
            c=colours[mod1(i, length(colours))], label=sta, kwargs...)
    end
    p
end
plot_splits_hist(splits::SWSArr; kwargs...) = plot_splits_hist!(plot(), splits; kwargs...)

"""
    sta_coords(s) -> stas, x, y

Return arrays of station names `stas`, x-coordinates, `x` and y-coordinates `y`.
"""
function sta_coords(s::SWSArr)
    stas = unique(s[:stnm])
    x, y = Float64[], Float64[]
    for sta in stas
        push!(x, s[s[:stnm] .== sta][1].sx)
        push!(y, s[s[:stnm] .== sta][1].sy)
    end
    stas, x, y
end

"""
    bar(ϕ, length, x=0, y=0, width=length/20) -> ::Shape

Return a `Plots.Shape` representing a bar oriented parallel to azimuth `ϕ` °
and `length` plot units long.  `width` specifies the bar width in plot units.
The bar is centred at `(x, y)`.
"""
function bar(ϕ, length, x=0., y=0., width=length/20.)
    l2 = length/2
    w2 = width/2
    ϕ = deg2rad(ϕ)
    sp, cp = sin(ϕ), cos(ϕ)
    p1x, p1y = l2*sp, l2*cp
    shape = Array{Tuple{Float64,Float64}}(4)
    i = 0
    for (lpm ,wpm) in zip((1, -1, -1, 1), (1, 1, -1, -1))
        i += 1
        shape[i] = (x + lpm*p1x + wpm*w2*sin(ϕ-π/2), y + lpm*p1y + wpm*w2*cos(ϕ-π/2))
    end
    Plots.Shape(shape)
end

end # module

max_stars_repo_name: anowacki/SWSPlots

max_issues_repo_name: anowacki/SWSPlots

max_forks_repo_name: anowacki/SWSPlots


text:
using Revise
using Cytof5

J = 32
N = [300, 100, 200]
K = 8
L = Dict(0 => 5, 1 => 3)

simdat = Cytof5.Model.genData(J, N, K, L)
d = Cytof5.Model.Data(simdat[:y])
c = Cytof5.Model.defaultConstants(d, K, L)
s = Cytof5.Model.genInitialState(c, d)


text:
using BenchmarkTools, OrdinaryDiffEq
BenchmarkTools.DEFAULT_PARAMETERS.gcsample = true
BenchmarkTools.DEFAULT_PARAMETERS.seconds = 300
f(u,p,t) = u
prob = ODEProblem(f,1.0,(0.0,1.0))

SUITE = BenchmarkGroup()
SUITE["algs"] = BenchmarkGroup()

SUITE["algs"]["Tsit5"] = @benchmarkable solve(prob, Tsit5())
SUITE["algs"]["Vern6"] = @benchmarkable solve(prob, Vern6())
SUITE["algs"]["Vern7"] = @benchmarkable solve(prob, Vern7())
SUITE["algs"]["Vern9"] = @benchmarkable solve(prob, Vern9())
SUITE["algs"]["Rosenbrock23"] = @benchmarkable solve(prob, Rosenbrock23())
SUITE["algs"]["BS3"] = @benchmarkable solve(prob, BS3())
SUITE["algs"]["KenCarp4"] = @benchmarkable solve(prob, KenCarp4())


text:
include("load.jl");

@testset "OptimalTrees.jl" begin
    include(string(OptimalTrees.OPTIMALTREES_ROOT, "/test/src.jl"))
end


text:
module CloudCovErr

include("cov.jl")

include("perstar.jl")

include("preprocess.jl")

include("decam.jl")
using .decam

end


text:
# This file is a part of SimilaritySearch.jl

import Base: push!

export ExhaustiveSearch, search

"""
    ExhaustiveSearch(dist::SemiMetric, db::AbstractVector)

Solves queries evaluating `dist` for the query and all elements in the dataset
"""
struct ExhaustiveSearch{DistanceType<:SemiMetric,DataType<:AbstractDatabase} <: AbstractSearchContext
    dist::DistanceType
    db::DataType
end

ExhaustiveSearch(dist::SemiMetric, db::AbstractVector) = ExhaustiveSearch(dist, convert(AbstractDatabase, db))
ExhaustiveSearch(dist::SemiMetric, db::Matrix) = ExhaustiveSearch(dist, convert(AbstractDatabase, db))
function ExhaustiveSearch(; dist=SqL2Distance(), db=VectorDatabase{Float32}())
    ExhaustiveSearch(dist, db)
end

getpools(index::ExhaustiveSearch) = nothing
Base.copy(seq::ExhaustiveSearch; dist=seq.dist, db=seq.db) = ExhaustiveSearch(dist, db)

"""
    search(seq::ExhaustiveSearch, q, res::KnnResult)

Solves the query evaluating all items in the given query.
"""
function search(seq::ExhaustiveSearch, q, res::KnnResult; pools=nothing)
    @inbounds for i in eachindex(seq)
        d = evaluate(seq.dist, seq[i], q)
        push!(res, i, d)
    end

    (res=res, cost=length(seq))
end

function Base.push!(seq::ExhaustiveSearch, u)
    push!(seq.db, u)
end

max_stars_repo_name: sadit/SimilaritySearch

max_issues_repo_name: sadit/NNS

max_forks_repo_name: sadit/SimilaritySearch


text:
"""Potential vorticity calculated as q = (f + ∂v/∂x - ∂u/∂y)/h."""
function PV!(Diag::DiagnosticVars,S::ModelSetup)

    @unpack q,dvdx,dudy,h_q = Diag.Vorticity
    @unpack f_q,ep = S.grid

    m,n = size(q)
    @boundscheck (m,n) == size(f_q) || throw(BoundsError())
    @boundscheck (m+2,n+2) == size(dvdx) || throw(BoundsError())
    @boundscheck (m+2+ep,n+2) == size(dudy) || throw(BoundsError())
    @boundscheck (m,n) == size(h_q) || throw(BoundsError())

    @inbounds for j ∈ 1:n
        for i ∈ 1:m
            q[i,j] = (f_q[i,j] + dvdx[i+1,j+1] - dudy[i+1+ep,j+1]) / h_q[i,j]
        end
    end
end

"""Transit function to call the specified advection scheme."""
function PVadvection!(Diag::DiagnosticVars,S::ModelSetup)
    if S.parameters.adv_scheme == "Sadourny"
        PV_Sadourny!(Diag)
    elseif S.parameters.adv_scheme == "ArakawaHsu"
        PV_ArakawaHsu!(Diag)
    end
end

"""Advection of potential vorticity qhv,qhu as in Sadourny, 1975
enstrophy conserving scheme."""
function PV_Sadourny!(Diag::DiagnosticVars)

    @unpack U,V = Diag.VolumeFluxes
    @unpack V_u,U_v = Diag.Vorticity
    @unpack q_u,q_v,qhv,qhu,ep = Diag.Vorticity

    Ixy!(V_u,V)
    Ixy!(U_v,U)

    m,n = size(qhv)
    @boundscheck (m+2-ep,n) == size(q_u) || throw(BoundsError())
    @boundscheck (m+2-ep,n) == size(V_u) || throw(BoundsError())

    @inbounds for j ∈ 1:n
        for i ∈ 1:m
            qhv[i,j] = q_u[i+1-ep,j] * V_u[i+1-ep,j]
        end
    end

    m,n = size(qhu)
    @boundscheck (m,n+2) == size(q_v) || throw(BoundsError())
    @boundscheck (m,n+2) == size(U_v) || throw(BoundsError())

    @inbounds for j ∈ 1:n
        for i ∈ 1:m
            qhu[i,j] = q_v[i,j+1] * U_v[i,j+1]
        end
    end
end

"""Advection of potential vorticity qhv,qhu as in Arakawa and Hsu, 1990
Energy and enstrophy conserving (in the limit of non-divergent mass flux) scheme with τ = 0."""
function PV_ArakawaHsu!(Diag::DiagnosticVars)

    @unpack U,V = Diag.VolumeFluxes
    @unpack qhv,qhu,ep = Diag.Vorticity
    @unpack qα,qβ,qγ,qδ = Diag.ArakawaHsu

    # Linear combinations of q and V=hv to yield qhv
    m,n = size(qhv)
    @inbounds for j ∈ 1:n
        for i ∈ 1:m
            qhv[i,j] = qα[1-ep+i,j]*V[2-ep+i,j+1] + qβ[1-ep+i,j]*V[1-ep+i,j+1] + qγ[1-ep+i,j]*V[1-ep+i,j] + qδ[1-ep+i,j]*V[2-ep+i,j]
        end
    end

    # Linear combinations of q and U=hu to yield qhu
    m,n = size(qhu)
    @inbounds for j ∈ 1:n
        for i ∈ 1:m
            qhu[i,j] = qα[i,j]*U[i,j+1] + qβ[i+1,j]*U[i+1,j+1] + qγ[i+1,j+1]*U[i+1,j+2] + qδ[i,j+1]*U[i,j+2]
        end
    end
end

""" Linear combination α of potential voriticity q according
to the energy and enstrophy conserving scheme of Arakawa and Hsu, 1990"""
function AHα!(α::Array{T,2},q::Array{T,2}) where {T<:AbstractFloat}
    m,n = size(α)
    @boundscheck (m+1,n+1) == size(q) || throw(BoundsError())

    one_twelve = T(1/12)

    @inbounds for j ∈ 1:n
        for i ∈ 1:m
            α[i,j] = one_twelve*(q[i,j] + q[i,j+1] + q[i+1,j+1])
        end
    end
end

""" Linear combination δ of potential voriticity q according
to the energy and enstrophy conserving scheme of Arakawa and Hsu, 1990 """
function AHβ!(β::Array{T,2},q::Array{T,2}) where {T<:AbstractFloat}
    m,n = size(β)
    @boundscheck (m,n+1) == size(q) || throw(BoundsError())

    one_twelve = T(1/12)

    @inbounds for j ∈ 1:n
        β[1,j] = one_twelve*(q[1,j] + q[1,j+1] + q[end,j+1])
        for i ∈ 2:m
            β[i,j] = one_twelve*(q[i,j] + q[i,j+1] + q[i-1,j+1])
        end
    end
end

""" Linear combination γ of potential voriticity q according
to the energy and enstrophy conserving scheme of Arakawa and Hsu, 1990 """
function AHγ!(γ::Array{T,2},q::Array{T,2}) where {T<:AbstractFloat}
    m,n = size(γ)
    @boundscheck (m,n+1) == size(q) || throw(BoundsError())

    one_twelve = T(1/12)

    @inbounds for j ∈ 1:n
        γ[1,j] = one_twelve*(q[1,j] + q[1,j+1] + q[end,j])
        for i ∈ 2:m
            γ[i,j] = one_twelve*(q[i,j] + q[i-1,j] + q[i,j+1])
        end
    end
end

""" Linear combination β of potential voriticity q according
to the energy and enstrophy conserving scheme of Arakawa and Hsu, 1990 """
function AHδ!(δ::Array{T,2},q::Array{T,2}) where {T<:AbstractFloat}
    m,n = size(δ)
    @boundscheck (m+1,n+1) == size(q) || throw(BoundsError())

    one_twelve = T(1/12)

    @inbounds for j ∈ 1:n
        for i ∈ 1:m
            δ[i,j] = one_twelve*(q[i,j] + q[i,j+1] + q[i+1,j])
        end
    end
end


text:
module AutoExpe

include("runExpe.jl")

export autoExpe
export addValuesToResults

end

max_stars_repo_name: ZacharieALES/AutoExpe

max_issues_repo_name: ZacharieALES/AutoExpe

max_forks_repo_name: ZacharieALES/AutoExpe


text:
# L2 norm (times a constant)

export NormL2

"""
**``L_2`` norm**

    NormL2(λ=1.0)

With a nonnegative scalar parameter λ, returns the function
```math
f(x) = λ\\cdot\\sqrt{x_1^2 + … + x_n^2}.
```
"""
struct NormL2{R <: Real} <: ProximableFunction
    lambda::R
    function NormL2{R}(lambda::R) where {R <: Real}
        if lambda < 0
            error("parameter λ must be nonnegative")
        else
            new(lambda)
        end
    end
end

is_convex(f::NormL2) = true

NormL2(lambda::R=1.0) where {R <: Real} = NormL2{R}(lambda)

function (f::NormL2)(x::AbstractArray)
    return f.lambda*norm(x)
end

function prox!(y::AbstractArray{T}, f::NormL2, x::AbstractArray{T}, gamma::Real=1.0) where T <: RealOrComplex
    normx = norm(x)
    scale = max(0, 1-f.lambda*gamma/normx)
    for i in eachindex(x)
        y[i] = scale*x[i]
    end
    return f.lambda*scale*normx
end

function gradient!(y::AbstractArray{T}, f::NormL2, x::AbstractArray{T}) where T <: Union{Real, Complex}
    fx = norm(x) # Value of f, without lambda
    if fx == 0
        y .= 0
    else
        y .= (f.lambda/fx).*x
    end
    return f.lambda*fx
end

fun_name(f::NormL2) = "Euclidean norm"
fun_dom(f::NormL2) = "AbstractArray{Real}, AbstractArray{Complex}"
fun_expr(f::NormL2) = "x ↦ λ||x||_2"
fun_params(f::NormL2) = "λ = $(f.lambda)"

function prox_naive(f::NormL2, x::AbstractArray{T}, gamma::Real=1.0) where T <: RealOrComplex
    normx = norm(x)
    scale = max(0, 1-f.lambda*gamma/normx)
    y = scale*x
    return y, f.lambda*scale*normx
end


text:
export sincosh

# Precomputed values
const inv_fact = [DoubleFloat64(1.0 / BigFloat(factorial(Int64(k)))) for k = 3:17]
const ninv_fact = length(inv_fact)

Base.ldexp(a::DoubleFloat64, exp::Int) = DoubleFloat64(ldexp(a.hi, exp), ldexp(a.lo, exp))
"""
	mul_pwr2(a::DoubleFloat64, b::Float64)

`a` * `b`,  where `b` is a power of 2.
"""
mul_pwr2(a::DoubleFloat64, b::Float64) = DoubleFloat64(a.hi * b, a.lo * b)

function Base.exp(a::DoubleFloat64)
   #= Strategy:  We first reduce the size of x by noting that

          exp(kr + m * log(2)) = 2^m * exp(r)^k

     where m and k are integers.  By choosing m appropriately
     we can make |kr| <= log(2) / 2 = 0.347.  Then exp(r) is
     evaluated using the familiar Taylor series.  Reducing the
     argument substantially speeds up the convergence.       =#

	k = 512.0
	inv_k = 1.0 / k

	if a.hi ≤ -709.0
		return zero(a)
	end

	if a.hi ≥ 709.0
		convert(DoubleFloat64, Inf)
	end

    if iszero(a)
        return one(a)
    end

    if isone(a)
      	return double_e
    end

    m = floor(a.hi / double_log2.hi + 0.5)
    r = mul_pwr2(a - double_log2 * m, inv_k)

	#
    p = square(r);
    s = r + mul_pwr2(p, 0.5)
    p *= r
    t = p * inv_fact[1]

 	i = 1
    while true
	 	s += t
	 	p *= r
	 	i += 1
	 	t = p * inv_fact[i]

	 	if abs(convert(Float64, t)) < inv_k * double_eps || i > 6
	 		break
	 	end
  	end

    s += t

    s = mul_pwr2(s, 2.0) + square(s)
    s = mul_pwr2(s, 2.0) + square(s)
    s = mul_pwr2(s, 2.0) + square(s)
    s = mul_pwr2(s, 2.0) + square(s)
    s = mul_pwr2(s, 2.0) + square(s)
    s = mul_pwr2(s, 2.0) + square(s)
    s = mul_pwr2(s, 2.0) + square(s)
    s = mul_pwr2(s, 2.0) + square(s)
    s = mul_pwr2(s, 2.0) + square(s)
    s += 1.0

    return ldexp(s, convert(Int, m))
end

function Base.log(a::DoubleFloat64{T}) where {T}
	#= Strategy.  The Taylor series for log converges much more
	 slowly than that of exp, due to the lack of the factorial
	 term in the denominator.  Hence this routine instead tries
	 to determine the root of the function

	     f(x) = exp(x) - a

	 using Newton iteration.  The iteration is given by

	     x' = x - f(x)/f'(x)
	        = x - (1 - a * exp(-x))
	        = x + a * exp(-x) - 1.

	 Only one iteration is needed, since Newton's iteration
	 approximately doubles the number of digits per iteration. =#

	if isone(a)
		return zero(DoubleFloat64{T})
	end

	if a.hi ≤ 0.0
		throw(DomainError("Passed non-positive argument to log."))
	end

	x = DoubleFloat64(log(a.hi)) # Initial approximation

	x + a * exp(-x) - 1.0
end

const sin_table = [DoubleFloat64(sin(k * big(π) * 0.0625)) for k = 1:4]
const cos_table = [DoubleFloat64(cos(k * big(π) * 0.0625)) for k = 1:4]

"""
	sin_taylor(a::DoubleFloat64)

Computes sin(a) using Taylor series. Assumes |a| <= π/32.
"""
function sin_taylor(a::DoubleFloat64)
	thresh = 0.5 * abs(convert(Float64, a)) * double_eps

	if iszero(a)
		return zero(a)
	end

	i = 1
	x = -square(a)
	s = a
	r = a
	while true
		r *= x
		t = r * inv_fact[i]
		s += t
		i += 2
		if i > ninv_fact || abs(convert(Float64, t)) < thresh
			break
		end
	end

	s
end

"""
	cos_taylor(a::DoubleFloat64)

Computes cos(a) using Taylor series. Assumes |a| <= π/32.
"""
function cos_taylor(a::DoubleFloat64)
	thresh = 0.5 * double_eps

	if iszero(a)
		return one(a)
	end

	x = -square(a)
	r = x
	s = 1.0 + mul_pwr2(r, 0.5)
	i = 2
	while true
		r *= x
		t = r * inv_fact[i]
		s += t
		i += 2
		if i > ninv_fact || abs(convert(Float64, t)) < thresh
			break
		end
	end

	s
end

function sincos_taylor(a::DoubleFloat64)
	if iszero(a)
		zero(a), one(a)
	end

  	sin_a = sin_taylor(a)
  	cos_a = sqrt(1.0 - square(sin_a))

  	sin_a, cos_a
end

function Base.sin(a::DoubleFloat64)
  #= Strategy.  To compute sin(x), we choose integers a, b so that

       x = s + a * (pi/2) + b * (pi/16)

     and |s| <= pi/32.  Using the fact that

       sin(pi/16) = 0.5 * sqrt(2 - sqrt(2 + sqrt(2)))

     we can compute sin(x) from sin(s), cos(s).  This greatly
     increases the convergence of the sine Taylor series. =#

	if iszero(a)
		return zero(a)
	end

	# approximately reduce modulo 2*pi
	z = round(a / double_2pi)
	r = a - double_2pi * z

		# approximately reduce modulo pi/2 and then modulo pi/16.

	q = floor(r.hi / double_pi2.hi + 0.5)
	t = r - double_pi2 * q
	j = convert(Int, q)
	q = floor(t.hi / double_pi16.hi + 0.5)
	t -= double_pi16 * q
	k = convert(Int, q)
	abs_k = abs(k)

	if j < -2 || j > 2
		# Cannot reduce modulo pi/2.
		return double_nan
	end

	if (abs_k > 4)
		# Cannot reduce modulo pi/16.
		return double_nan
	end

	if k == 0
		if j == 0
			return sin_taylor(t)
		elseif j == 1
			return cos_taylor(t)
		elseif j == -1
			return -cos_taylor(t)
		else
			return -sin_taylor(t)
		end
	end

	u = cos_table[abs_k]
	v = sin_table[abs_k]
  	sin_t, cos_t = sincos_taylor(t)

	if j == 0
		r = k > 0 ? u * sin_t + v * cos_t : u * sin_t - v * cos_t
  	elseif j == 1
		r = k > 0 ? u * cos_t - v * sin_t : u * cos_t + v * sin_t
	elseif j == -1
		r = k > 0 ? v * sin_t - u * cos_t : -u * cos_t - v * sin_t
	else
		r = k > 0 ? -u * sin_t - v * cos_t : v * cos_t - u * sin_t
	end

	r
end

function Base.cos(a::DoubleFloat64)
	if iszero(a)
		return one(a)
	end

	# approximately reduce modulo 2*pi
	z = round(a / double_2pi)
	r = a - double_2pi * z

		# approximately reduce modulo pi/2 and then modulo pi/16.

	q = floor(r.hi / double_pi2.hi + 0.5)
	t = r - double_pi2 * q
	j = convert(Int, q)
	q = floor(t.hi / double_pi16.hi + 0.5)
	t -= double_pi16 * q
	k = convert(Int, q)
	abs_k = abs(k)

	if j < -2 || j > 2
		# Cannot reduce modulo pi/2.
		return double_nan
	end

	if (abs_k > 4)
		# Cannot reduce modulo pi/16.
		return double_nan
	end

	if k == 0
		if j == 0
			return cos_taylor(t)
		elseif j == 1
			return -sin_taylor(t)
		elseif j == -1
			return sin_taylor(t)
		else
			return -cos_taylor(t)
		end
	end

	u = cos_table[abs_k]
	v = sin_table[abs_k]
  	sin_t, cos_t = sincos_taylor(t)

	if j == 0
		r = k > 0 ? u * cos_t - v * sin_t : u * cos_t + v * sin_t
  	elseif j == 1
		r = k > 0 ? -u * sin_t - v * cos_t : v * cos_t - u * sin_t
	elseif j == -1
		r = k > 0 ? u * sin_t + v * cos_t : u * sin_t - v * cos_t
	else
		r = k > 0 ? v * sin_t - u * cos_t : -u * cos_t - v * sin_t
	end

	r
end

function _sincos(a::DoubleFloat64)
	if iszero(a)
		return zero(a), one(a)
	end

	# approximately reduce modulo 2*pi
	z = round(a / double_2pi)
	r = a - double_2pi * z

	# approximately reduce modulo pi/2 and then modulo pi/16.
	q = floor(r.hi / double_pi2.hi + 0.5)
	t = r - double_pi2 * q
	j = convert(Int, q)
	abs_j = abs(j)
	q = floor(t.hi / double_pi16.hi + 0.5)
	t -= double_pi16 * q
	k = convert(Int, q)
	abs_k = abs(k)

	if abs_j > 2
		# Cannot reduce modulo pi/2.
		return double_nan, double_nan
	end

	if abs_k > 4
		# Cannot reduce modulo pi/16.
		return double_nan, double_nan
	end

  	sin_t, cos_t = sincos_taylor(t)

	if abs_k == 0
		s = sin_t
		c = cos_t
	else
		u = cos_table[abs_k]
		v = sin_table[abs_k]

		s = k > 0 ? u * sin_t + v * cos_t : u * sin_t - v * cos_t
		c = k > 0 ? u * cos_t - v * sin_t : u * cos_t + v * sin_t
	end

	if j == 0
		s, c
  	elseif j == 1
		c, -s
	elseif j == -1
		-c, s
	else
		-s, -c
	end
end

# if VERSION > v"0.7.0-DEV.1319"
# 	@inline Base.sincos(a::DoubleFloat64) = _sincos(a)
# else
export sincos
"""
	sincos(x)

Compute `(sin(x), cos(x))`. This is faster than computing the values
separetly.
"""
@inline sincos(a::DoubleFloat64) = _sincos(a)
# end

Base.atan(a::DoubleFloat64) = atan2(a, one(a))

function Base.atan2(y::DoubleFloat64, x::DoubleFloat64)
	#= Strategy: Instead of using Taylor series to compute
     arctan, we instead use Newton's iteration to solve
     the equation

        sin(z) = y/r    or    cos(z) = x/r

     where r = sqrt(x^2 + y^2).
     The iteration is given by

        z' = z + (y - sin(z)) / cos(z)          (for equation 1)
        z' = z - (x - cos(z)) / sin(z)          (for equation 2)

     Here, x and y are normalized so that x^2 + y^2 = 1.
     If |x| > |y|, then first iteration is used since the
     denominator is larger.  Otherwise, the second is used.
  	=#
	if iszero(x)
		if iszero(y)
			double_nan
		end

		return y.hi > 0.0 ? double_pi2 : -double_pi2
	elseif iszero(y)
		return x.hi > 0.0 ? zero(x) : double_pi
	end

	if x == y
		return y.hi > 0.0 ? double_pi4 : -double_3pi4
	end

	if x == -y
		return y.hi > 0.0 ? double_3pi4 : -double_pi4
	end

	r = sqrt(square(x) + square(y))
	xx = x / r
	yy = y / r

	# Compute double precision approximation to atan.
	z = DoubleFloat64(atan2(convert(Float64, y), convert(Float64, x)))

	if abs(xx.hi) > abs(yy.hi)
		# Use Newton iteration 1.  z' = z + (y - sin(z)) / cos(z)
		sin_z, cos_z = _sincos(z)
		z += (yy - sin_z) / cos_z
	else
		# Use Newton iteration 2.  z' = z - (x - cos(z)) / sin(z)
		sin_z, cos_z = _sincos(z)
		z -= (xx - cos_z) / sin_z
	end

	z
end

function Base.tan(a::DoubleFloat64)
	s, c = _sincos(a)
	s / c
end

function Base.asin(a::DoubleFloat64)
	abs_a = abs(a)

	if abs_a > 1.0
		throw(DomainError())
	end

	if isone(abs_a)
		return a.hi > 0.0 ? double_pi2 : -double_pi2
	end

	atan2(a, sqrt(1.0 - square(a)))
end

function Base.acos(a::DoubleFloat64)
	abs_a = abs(a)

	if abs_a > 1.0
		throw(DomainError())
	end

	if isone(abs_a)
		return a.hi > 0.0 ? zero(a) : -double_pi
	end

	atan2(sqrt(1.0 - square(a)), a)
end

function Base.sinh(a::DoubleFloat64)
	if iszero(a)
		return zero(a)
	end
	if a > 0.05 || a < -0.05
		ea = exp(a)
		return mul_pwr2(ea - inv(ea), 0.5)
	end

	# The computation below didn't yield a satisfying accuracy
	# Thus we just fallback to the Float64 formula which yields at least
	# a
	return DoubleFloat64(sinh(convert(Float64, a)))

	#
	#
	# #=  since a is small, using the above formula gives
    # a lot of cancellation.  So use Taylor series. =#
	# s = a
	# t = a
	# r = square(t)
	# m = 1.0
	# thresh = abs(convert(Float64, a)) * double_eps
	#
	# while true
	# 	m += 2.0
	# 	t *= r
	# 	t /= (m - 1) * m
	#
	# 	s += t
	#
	# 	if abs(t) < thresh
	# 		break
	# 	end
	# end
	#
	# s
end

function Base.cosh(a::DoubleFloat64)
	if iszero(a)
		return one(a)
	end
	ea = exp(a)
	mul_pwr2(ea + inv(ea), 0.5)
end

"""
	sincosh(x)

Compute `(sinh(x), cosh(x))`. This is faster than computing the values
separetly.
"""
function sincosh(a::DoubleFloat64)
	if abs(convert(Float64, a)) ≤ 0.05
		s = sinh(a)
		c = sqrt(1.0 + square(s))
	else
		ea = exp(a)
		inv_ea = inv(ea)
		s = mul_pwr2(ea - inv_ea, 0.5)
		c = mul_pwr2(ea + inv_ea, 0.5)
	end
	s, c
end

function Base.tanh(a::DoubleFloat64)
	if iszero(a)
		return zero(a)
	end
	if abs(convert(Float64, a)) > 0.05
		ea = exp(a)
		inv_ea = inv(ea)
		return (ea - inv_ea) / (ea + inv_ea)
	else
		s = sinh(a)
		c = sqrt(1.0 + square(s))
		return s / c
	end
end


text:
using GeometryTypes, Reactive, GLVisualize
using GLPlot;GLPlot.init()

slidera = GLPlot.play_widget(linspace(0.1f0, 40f0, 30))
sliderb = GLPlot.play_widget(linspace(0.1f0, 40f0, 30))
sliderc = GLPlot.play_widget(linspace(0.1f0, 40f0, 30))
sliderd = GLPlot.play_widget(linspace(0.001f0, 0.5f0, 30))

function lorenz(t0, a, b, c, h)
    Point3f0(
        t0[1] + h * a * (t0[2] - t0[1]),
        t0[2] + h * (t0[1] * (b - t0[3]) - t0[2]),
        t0[3] + h * (t0[1] * t0[2] - c * t0[3]),
    )
end
function lorenz(array::Vector, a=5.0,b=2.0,c=6.0,d=0.01)
    t0 = Point3f0(0.1, 0, 0)
    for i=eachindex(array)
        t0 = lorenz(t0, a,b,c,d)
        array[i] = t0
    end
    array
end
n = 100_000
points = foldp(lorenz, Array(Point3f0, n), slidera, sliderb, sliderc, sliderd)

# we set the boundingbox to nothing, since we don't need it and don't want to
# calculate it for every update (which is the default)
glplot(points, :lines, boundingbox=nothing, preferred_camera=:perspective)
# you can also visualize the points
glplot((Circle(Point2f0(0), 0.01f0), points), boundingbox=nothing, preferred_camera=:perspective)
# the above renders an antia aliased nice looking circle which could have outlines and glows.
# this makes it relatively slow. For optimal performance, one might need the command below
# which draws one (or n) pixel per point
glplot(points, :speed, boundingbox=nothing, preferred_camera=:perspective)


text:
function test_speed_params(gm::GlobalModel = minlp(true), solver = OCTHaGOn.SOLVER_SILENT)
    set_optimizer(gm, solver)
    bbl = gm.bbls[1]
    uniform_sample_and_eval!(bbl)

    # Trying different speed parameters
    ls_num_hyper_restarts = [1, 3]
    ls_num_tree_restarts = [3, 5]
    tree_mat = [[], []]
    time_mat = [[], []]
    for i=1:length(ls_num_hyper_restarts)
        for j=1:length(ls_num_tree_restarts)
            t1 = time()
            params = Dict(:ls_num_hyper_restarts => ls_num_hyper_restarts[i],
                          :ls_num_tree_restarts => ls_num_tree_restarts[j],
                          :max_depth => 2)
            learn_constraint!(bbl; params...)
            push!(time_mat[i], time() - t1)
            push!(tree_mat[i], bbl.learners[end])
        end
    end
    @test true
end

function test_classify_gradients()
    gm = minlp(true)
    set_optimizer(gm, SOLVER_SILENT)
    bbr = gm.bbls[3]
    uniform_sample_and_eval!(gm)
    idxs = collect(1:10)
    classify_curvature(bbr, idxs)
    @test !any(ismissing.(bbr.curvatures[idxs]))
    classify_curvature(bbr)
    @test all(bbr.curvatures .> 0)
    update_vexity(bbr)
    @test bbr.convex == true
    @test bbr.local_convexity == 1.
end

function test_infeasibility_cuts()
    gm = sagemark_to_GlobalModel(15, false)
    set_param(gm, :ignore_accuracy, true)
    uniform_sample_and_eval!(gm)
    learn_constraint!(gm)
    add_tree_constraints!(gm)
    optimize!(gm)
    bbc_idxs = [bbl isa BlackBoxClassifier for bbl in gm.bbls]
    add_infeasibility_cuts!(gm)
    optimize!(gm)
    while abs(gm.cost[end] - gm.cost[end-1]) > get_param(gm, :abstol)
        add_infeasibility_cuts!(gm)
        optimize!(gm)
    end
    @test true
end

function test_feasibility_sample()
    gm = speed_reducer()
    uniform_sample_and_eval!(gm)
    [set_param(bbl, :threshold_feasibility, 0.3) for bbl in gm.bbls if bbl isa BlackBoxClassifier]
    @test any(check_feasibility(gm) .!= 1)
    feasibility_sample(gm)
    @test all(check_feasibility(gm) .== 1)
end

function test_survey_method(gm::GlobalModel = minlp(true))
    uniform_sample_and_eval!(gm)
    bbrs = [bbl for bbl in gm.bbls if bbl isa BlackBoxRegressor]
    set_optimizer(gm, OCTHaGOn.SOLVER_SILENT)
    surveysolve(gm)
    bbcs = [bbl for bbl in gm.bbls if bbl isa BlackBoxClassifier]
    bbc_idxs = [x isa BlackBoxClassifier for x in gm.bbls]
    add_infeasibility_cuts!(gm)
    optimize!(gm)
    while abs(gm.cost[end] - gm.cost[end-1]) > get_param(gm, :abstol)
        add_infeasibility_cuts!(gm)
        optimize!(gm)
    end
    @test true
end

function test_concave_regressors(gm::GlobalModel = gear(true))
    set_optimizer(gm, SOLVER_SILENT)
    uniform_sample_and_eval!(gm)
    bbrs = [bbl for bbl in gm.bbls if bbl isa BlackBoxRegressor]
    if !isempty(bbrs)
        update_vexity.(bbrs)
    end
    bbr = bbrs[1]

    # Checking number of constraints
    init_constraints = count_constraints(gm.model)
    surveysolve(gm) # 1st tree (ORT)
    actual = bbr.actuals[end]
    optim = bbr.optima[end]
    learn_constraint!(bbr, "upper" => minimum(bbr.actuals)) # 2nd tree (Upper OCT)
    learn_constraint!(bbr, "reg" => 40,
                        regression_sparsity = 0, max_depth = 3) # 3th tree (Regressor on upper bounded samples)

    # Trying to add and remove individual constraints in random order to make sure no constraints accidentally remain.
    for i=1:length(bbr.learners)
        update_tree_constraints!(gm, bbr, i)
        for j=1:length(bbr.learners)
            update_tree_constraints!(gm, bbr, j)
            for k = 1:length(bbr.learners)
                update_tree_constraints!(gm, bbr, k)
                treekeys = collect(keys(bbr.active_trees))
                treevalues = collect(values(bbr.active_trees))
                if length(treevalues) >= 2
                    @test Pair(treevalues[1].first, treevalues[2].first) in OCTHaGOn.valid_pairs
                elseif length(treevalues) == 1
                    @test treevalues[1].first in OCTHaGOn.valid_singles || treevalues[1].first == "upper"
                end
                clear_tree_constraints!(gm)
                n_constraints = count_constraints(gm.model)
                @test n_constraints == init_constraints
            end
        end
    end
    update_tree_constraints!(gm, bbr, 2)
    update_tree_constraints!(gm, bbr, 3)
    @test active_lower_tree(bbr) == 3
    @test active_upper_tree(bbr) == 3
    optimize!(gm)
    clear_tree_constraints!(gm)
    @test init_constraints == count_constraints(gm.model)
end

function test_descent()
    gm = minlp(true)
    set_optimizer(gm, SOLVER_SILENT)
    uniform_sample_and_eval!(gm) # descent requires some samples
    x0 = DataFrame(string.(gm.vars) .=> [1, 0, 1, 0, 1, 0, 5.8])
    append!(gm.solution_history, x0)
    append!(gm.cost, 5.69)
    feas_gap(gm, x0)
    descend!(gm)
    @test isapprox(gm.cost[end], 6.09; atol = 3)

    gm = pool1(true)
    set_optimizer(gm, SOLVER_SILENT)
    uniform_sample_and_eval!(gm)
    x0 = DataFrame(string.(gm.vars) .=> [4.0, 3.0, 1.0, 4.0, 0, 7, 0])
    append!(gm.solution_history, x0)
    append!(gm.cost, 100)
    feas_gap(gm, x0)
    descend!(gm)
    @test isapprox(gm.cost[end], 23; atol = 3)

    gm = nlp3(true)
    set_optimizer(gm, SOLVER_SILENT)
    uniform_sample_and_eval!(gm)
    x0 = DataFrame(string.(gm.vars) .=>
    [1728.71, 16000.0, 69.9795, 3056.32,  2000.0,  91.323, 94.7197, 11.5857, 2.26271, 151.159, -1600.81])
    append!(gm.solution_history, x0)
    append!(gm.cost, -1600)
    feas_gap(gm, x0)
    descend!(gm)
    @test isapprox(gm.cost[end], -1161; atol = 4)
end

function test_recipe()
    gm = nlp2(true)
    set_optimizer(gm, SOLVER_SILENT)
    globalsolve_and_time!(gm)
    @test isapprox(gm.cost[end], 201; atol = 3)
end

test_speed_params()

test_classify_gradients()

test_infeasibility_cuts()

test_feasibility_sample()

test_survey_method()

test_concave_regressors()

test_descent()


text:
export regrid2d

"""
    `regrid2d(acqData::AcquisitionData, kspaceSize::NTuple{2,Int64}
              ; cgnr_iter::Int64=3, correctionMap::Array{ComplexF64}=ComplexF64[]) where D`

Regrid non-cartesian k-space data in `acqData` to a cartesian grid of size `kspaceSize`.
Uses the CGNR method to invert the non-cartesian Fourier encoding.

# Arguments:
* `acqData::AcquisitionData`        - AcquisitionData
* `ksize::NTuple{2,Int64}`          - size of the cartesian k-space grid
* `cgnr_iter::Int64=3`              - number of CGNR iterations
* `correctionMao::Array{ComplexF64}`- relaxation/b0 map
"""
function regrid2d(acqData::AcquisitionData, kspaceSize::NTuple{2,Int64}; cgnr_iter::Int64=3, correctionMap::Array{ComplexF64}=ComplexF64[]) where D
  dcf = samplingDensity(acqData,kspaceSize)

  nx,ny = kspaceSize
  numContr, numChan, numSl = numContrasts(acqData), numChannels(acqData), numSlices(acqData)
  Ireco = zeros(ComplexF64, prod(kspaceSize), numSl, numContr, numChan)

  kdata_cart = [zeros(ComplexF64,nx*ny,numChan) for j=1:numContr, k=1:numSl, rep=1:1]
  F = sqrt(prod(kspaceSize))*FFTOp(ComplexF64, kspaceSize)
  img = zeros(ComplexF64,nx*ny)
  for k = 1:numSl
    E = encodingOps2d_simple(acqData, kspaceSize, slice=k, correctionMap=correctionMap)
    for j = 1:numContr
      W = WeightingOp(dcf[j])
      solver = RegularizedLeastSquares.CGNR(W*E[j], iterations=cgnr_iter)
      for i = 1:numChan
        kdata = kData(acqData,j,i,k).* dcf[j]
        img .= solve(solver, kdata)
        kdata_cart[j,k,1][:,i] .= F*img
      end
    end
  end

  return AcquisitionData(CartesianTrajectory(ny,nx), kdata_cart, encodingSize=[nx,ny,1], fov=acqData.fov)
end