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

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

    function GPUOptions_Experimental_VirtualDevices(; kwargs...)
        obj = new(meta(GPUOptions_Experimental_VirtualDevices), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct GPUOptions_Experimental_VirtualDevices
const __meta_GPUOptions_Experimental_VirtualDevices = Ref{ProtoMeta}()
function meta(::Type{GPUOptions_Experimental_VirtualDevices})
    ProtoBuf.metalock() do
        if !isassigned(__meta_GPUOptions_Experimental_VirtualDevices)
            __meta_GPUOptions_Experimental_VirtualDevices[] = target = ProtoMeta(GPUOptions_Experimental_VirtualDevices)
            pack = Symbol[:memory_limit_mb,:priority]
            allflds = Pair{Symbol,Union{Type,String}}[:memory_limit_mb => Base.Vector{Float32}, :priority => Base.Vector{Int32}]
            meta(target, GPUOptions_Experimental_VirtualDevices, allflds, ProtoBuf.DEF_REQ, ProtoBuf.DEF_FNUM, ProtoBuf.DEF_VAL, pack, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_GPUOptions_Experimental_VirtualDevices[]
    end
end
function Base.getproperty(obj::GPUOptions_Experimental_VirtualDevices, name::Symbol)
    if name === :memory_limit_mb
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{Float32}
    elseif name === :priority
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{Int32}
    else
        getfield(obj, name)
    end
end

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

    function GPUOptions_Experimental(; kwargs...)
        obj = new(meta(GPUOptions_Experimental), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct GPUOptions_Experimental
const __meta_GPUOptions_Experimental = Ref{ProtoMeta}()
function meta(::Type{GPUOptions_Experimental})
    ProtoBuf.metalock() do
        if !isassigned(__meta_GPUOptions_Experimental)
            __meta_GPUOptions_Experimental[] = target = ProtoMeta(GPUOptions_Experimental)
            fnum = Int[1,2,3,4,5,7,8,9]
            allflds = Pair{Symbol,Union{Type,String}}[:virtual_devices => Base.Vector{GPUOptions_Experimental_VirtualDevices}, :use_unified_memory => Bool, :num_dev_to_dev_copy_streams => Int32, :collective_ring_order => AbstractString, :timestamped_allocator => Bool, :kernel_tracker_max_interval => Int32, :kernel_tracker_max_bytes => Int32, :kernel_tracker_max_pending => Int32]
            meta(target, GPUOptions_Experimental, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_GPUOptions_Experimental[]
    end
end
function Base.getproperty(obj::GPUOptions_Experimental, name::Symbol)
    if name === :virtual_devices
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{GPUOptions_Experimental_VirtualDevices}
    elseif name === :use_unified_memory
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :num_dev_to_dev_copy_streams
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :collective_ring_order
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :timestamped_allocator
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :kernel_tracker_max_interval
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :kernel_tracker_max_bytes
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :kernel_tracker_max_pending
        return (obj.__protobuf_jl_internal_values[name])::Int32
    else
        getfield(obj, name)
    end
end

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

    function GPUOptions(; kwargs...)
        obj = new(meta(GPUOptions), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct GPUOptions
const __meta_GPUOptions = Ref{ProtoMeta}()
function meta(::Type{GPUOptions})
    ProtoBuf.metalock() do
        if !isassigned(__meta_GPUOptions)
            __meta_GPUOptions[] = target = ProtoMeta(GPUOptions)
            fnum = Int[1,4,2,3,5,6,7,8,9]
            allflds = Pair{Symbol,Union{Type,String}}[:per_process_gpu_memory_fraction => Float64, :allow_growth => Bool, :allocator_type => AbstractString, :deferred_deletion_bytes => Int64, :visible_device_list => AbstractString, :polling_active_delay_usecs => Int32, :polling_inactive_delay_msecs => Int32, :force_gpu_compatible => Bool, :experimental => GPUOptions_Experimental]
            meta(target, GPUOptions, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_GPUOptions[]
    end
end
function Base.getproperty(obj::GPUOptions, name::Symbol)
    if name === :per_process_gpu_memory_fraction
        return (obj.__protobuf_jl_internal_values[name])::Float64
    elseif name === :allow_growth
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :allocator_type
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :deferred_deletion_bytes
        return (obj.__protobuf_jl_internal_values[name])::Int64
    elseif name === :visible_device_list
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :polling_active_delay_usecs
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :polling_inactive_delay_msecs
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :force_gpu_compatible
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :experimental
        return (obj.__protobuf_jl_internal_values[name])::GPUOptions_Experimental
    else
        getfield(obj, name)
    end
end

const OptimizerOptions_Level = (;[
    Symbol("L1") => Int32(0),
    Symbol("L0") => Int32(-1),
]...)

const OptimizerOptions_GlobalJitLevel = (;[
    Symbol("DEFAULT") => Int32(0),
    Symbol("OFF") => Int32(-1),
    Symbol("ON_1") => Int32(1),
    Symbol("ON_2") => Int32(2),
]...)

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

    function OptimizerOptions(; kwargs...)
        obj = new(meta(OptimizerOptions), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct OptimizerOptions
const __meta_OptimizerOptions = Ref{ProtoMeta}()
function meta(::Type{OptimizerOptions})
    ProtoBuf.metalock() do
        if !isassigned(__meta_OptimizerOptions)
            __meta_OptimizerOptions[] = target = ProtoMeta(OptimizerOptions)
            fnum = Int[1,2,6,4,3,5]
            allflds = Pair{Symbol,Union{Type,String}}[:do_common_subexpression_elimination => Bool, :do_constant_folding => Bool, :max_folded_constant_in_bytes => Int64, :do_function_inlining => Bool, :opt_level => Int32, :global_jit_level => Int32]
            meta(target, OptimizerOptions, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_OptimizerOptions[]
    end
end
function Base.getproperty(obj::OptimizerOptions, name::Symbol)
    if name === :do_common_subexpression_elimination
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :do_constant_folding
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :max_folded_constant_in_bytes
        return (obj.__protobuf_jl_internal_values[name])::Int64
    elseif name === :do_function_inlining
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :opt_level
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :global_jit_level
        return (obj.__protobuf_jl_internal_values[name])::Int32
    else
        getfield(obj, name)
    end
end

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

    function GraphOptions(; kwargs...)
        obj = new(meta(GraphOptions), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct GraphOptions
const __meta_GraphOptions = Ref{ProtoMeta}()
function meta(::Type{GraphOptions})
    ProtoBuf.metalock() do
        if !isassigned(__meta_GraphOptions)
            __meta_GraphOptions[] = target = ProtoMeta(GraphOptions)
            fnum = Int[2,3,4,9,5,6,7,8,10]
            allflds = Pair{Symbol,Union{Type,String}}[:enable_recv_scheduling => Bool, :optimizer_options => OptimizerOptions, :build_cost_model => Int64, :build_cost_model_after => Int64, :infer_shapes => Bool, :place_pruned_graph => Bool, :enable_bfloat16_sendrecv => Bool, :timeline_step => Int32, :rewrite_options => RewriterConfig]
            meta(target, GraphOptions, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_GraphOptions[]
    end
end
function Base.getproperty(obj::GraphOptions, name::Symbol)
    if name === :enable_recv_scheduling
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :optimizer_options
        return (obj.__protobuf_jl_internal_values[name])::OptimizerOptions
    elseif name === :build_cost_model
        return (obj.__protobuf_jl_internal_values[name])::Int64
    elseif name === :build_cost_model_after
        return (obj.__protobuf_jl_internal_values[name])::Int64
    elseif name === :infer_shapes
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :place_pruned_graph
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :enable_bfloat16_sendrecv
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :timeline_step
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :rewrite_options
        return (obj.__protobuf_jl_internal_values[name])::RewriterConfig
    else
        getfield(obj, name)
    end
end

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

    function ThreadPoolOptionProto(; kwargs...)
        obj = new(meta(ThreadPoolOptionProto), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct ThreadPoolOptionProto
const __meta_ThreadPoolOptionProto = Ref{ProtoMeta}()
function meta(::Type{ThreadPoolOptionProto})
    ProtoBuf.metalock() do
        if !isassigned(__meta_ThreadPoolOptionProto)
            __meta_ThreadPoolOptionProto[] = target = ProtoMeta(ThreadPoolOptionProto)
            allflds = Pair{Symbol,Union{Type,String}}[:num_threads => Int32, :global_name => AbstractString]
            meta(target, ThreadPoolOptionProto, 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_ThreadPoolOptionProto[]
    end
end
function Base.getproperty(obj::ThreadPoolOptionProto, name::Symbol)
    if name === :num_threads
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :global_name
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    else
        getfield(obj, name)
    end
end

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

    function RPCOptions(; kwargs...)
        obj = new(meta(RPCOptions), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct RPCOptions
const __meta_RPCOptions = Ref{ProtoMeta}()
function meta(::Type{RPCOptions})
    ProtoBuf.metalock() do
        if !isassigned(__meta_RPCOptions)
            __meta_RPCOptions[] = target = ProtoMeta(RPCOptions)
            allflds = Pair{Symbol,Union{Type,String}}[:use_rpc_for_inprocess_master => Bool, :compression_algorithm => AbstractString, :compression_level => Int32, :cache_rpc_response => Bool, :disable_session_connection_sharing => Bool]
            meta(target, RPCOptions, 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_RPCOptions[]
    end
end
function Base.getproperty(obj::RPCOptions, name::Symbol)
    if name === :use_rpc_for_inprocess_master
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :compression_algorithm
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :compression_level
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :cache_rpc_response
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :disable_session_connection_sharing
        return (obj.__protobuf_jl_internal_values[name])::Bool
    else
        getfield(obj, name)
    end
end

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

    function SessionMetadata(; kwargs...)
        obj = new(meta(SessionMetadata), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct SessionMetadata
const __meta_SessionMetadata = Ref{ProtoMeta}()
function meta(::Type{SessionMetadata})
    ProtoBuf.metalock() do
        if !isassigned(__meta_SessionMetadata)
            __meta_SessionMetadata[] = target = ProtoMeta(SessionMetadata)
            allflds = Pair{Symbol,Union{Type,String}}[:name => AbstractString, :version => Int64]
            meta(target, SessionMetadata, 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_SessionMetadata[]
    end
end
function Base.getproperty(obj::SessionMetadata, name::Symbol)
    if name === :name
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :version
        return (obj.__protobuf_jl_internal_values[name])::Int64
    else
        getfield(obj, name)
    end
end

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

    function ConfigProto_DeviceCountEntry(; kwargs...)
        obj = new(meta(ConfigProto_DeviceCountEntry), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct ConfigProto_DeviceCountEntry (mapentry)
const __meta_ConfigProto_DeviceCountEntry = Ref{ProtoMeta}()
function meta(::Type{ConfigProto_DeviceCountEntry})
    ProtoBuf.metalock() do
        if !isassigned(__meta_ConfigProto_DeviceCountEntry)
            __meta_ConfigProto_DeviceCountEntry[] = target = ProtoMeta(ConfigProto_DeviceCountEntry)
            allflds = Pair{Symbol,Union{Type,String}}[:key => AbstractString, :value => Int32]
            meta(target, ConfigProto_DeviceCountEntry, 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_ConfigProto_DeviceCountEntry[]
    end
end
function Base.getproperty(obj::ConfigProto_DeviceCountEntry, name::Symbol)
    if name === :key
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :value
        return (obj.__protobuf_jl_internal_values[name])::Int32
    else
        getfield(obj, name)
    end
end

const ConfigProto_Experimental_MlirBridgeRollout = (;[
    Symbol("MLIR_BRIDGE_ROLLOUT_UNSPECIFIED") => Int32(0),
    Symbol("MLIR_BRIDGE_ROLLOUT_ENABLED") => Int32(1),
    Symbol("MLIR_BRIDGE_ROLLOUT_DISABLED") => Int32(2),
]...)

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

    function ConfigProto_Experimental(; kwargs...)
        obj = new(meta(ConfigProto_Experimental), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct ConfigProto_Experimental
const __meta_ConfigProto_Experimental = Ref{ProtoMeta}()
function meta(::Type{ConfigProto_Experimental})
    ProtoBuf.metalock() do
        if !isassigned(__meta_ConfigProto_Experimental)
            __meta_ConfigProto_Experimental[] = target = ProtoMeta(ConfigProto_Experimental)
            fnum = Int[1,3,4,5,6,7,8,9,10,11,12,13,17,16,14,15]
            allflds = Pair{Symbol,Union{Type,String}}[:collective_group_leader => AbstractString, :executor_type => AbstractString, :recv_buf_max_chunk => Int32, :use_numa_affinity => Bool, :collective_deterministic_sequential_execution => Bool, :collective_nccl => Bool, :share_session_state_in_clusterspec_propagation => Bool, :disable_thread_spinning => Bool, :share_cluster_devices_in_session => Bool, :session_metadata => SessionMetadata, :optimize_for_static_graph => Bool, :enable_mlir_bridge => Bool, :mlir_bridge_rollout => Int32, :enable_mlir_graph_optimization => Bool, :disable_output_partition_graphs => Bool, :xla_fusion_autotuner_thresh => Int64]
            meta(target, ConfigProto_Experimental, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_ConfigProto_Experimental[]
    end
end
function Base.getproperty(obj::ConfigProto_Experimental, name::Symbol)
    if name === :collective_group_leader
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :executor_type
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :recv_buf_max_chunk
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :use_numa_affinity
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :collective_deterministic_sequential_execution
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :collective_nccl
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :share_session_state_in_clusterspec_propagation
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :disable_thread_spinning
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :share_cluster_devices_in_session
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :session_metadata
        return (obj.__protobuf_jl_internal_values[name])::SessionMetadata
    elseif name === :optimize_for_static_graph
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :enable_mlir_bridge
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :mlir_bridge_rollout
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :enable_mlir_graph_optimization
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :disable_output_partition_graphs
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :xla_fusion_autotuner_thresh
        return (obj.__protobuf_jl_internal_values[name])::Int64
    else
        getfield(obj, name)
    end
end

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

    function ConfigProto(; kwargs...)
        obj = new(meta(ConfigProto), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct ConfigProto
const __meta_ConfigProto = Ref{ProtoMeta}()
function meta(::Type{ConfigProto})
    ProtoBuf.metalock() do
        if !isassigned(__meta_ConfigProto)
            __meta_ConfigProto[] = target = ProtoMeta(ConfigProto)
            fnum = Int[1,2,5,9,12,3,4,6,7,8,10,11,13,14,15,17,16]
            allflds = Pair{Symbol,Union{Type,String}}[:device_count => Base.Dict{AbstractString,Int32}, :intra_op_parallelism_threads => Int32, :inter_op_parallelism_threads => Int32, :use_per_session_threads => Bool, :session_inter_op_thread_pool => Base.Vector{ThreadPoolOptionProto}, :placement_period => Int32, :device_filters => Base.Vector{AbstractString}, :gpu_options => GPUOptions, :allow_soft_placement => Bool, :log_device_placement => Bool, :graph_options => GraphOptions, :operation_timeout_in_ms => Int64, :rpc_options => RPCOptions, :cluster_def => ClusterDef, :isolate_session_state => Bool, :share_cluster_devices_in_session => Bool, :experimental => ConfigProto_Experimental]
            meta(target, ConfigProto, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_ConfigProto[]
    end
end
function Base.getproperty(obj::ConfigProto, name::Symbol)
    if name === :device_count
        return (obj.__protobuf_jl_internal_values[name])::Base.Dict{AbstractString,Int32}
    elseif name === :intra_op_parallelism_threads
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :inter_op_parallelism_threads
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :use_per_session_threads
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :session_inter_op_thread_pool
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{ThreadPoolOptionProto}
    elseif name === :placement_period
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :device_filters
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{AbstractString}
    elseif name === :gpu_options
        return (obj.__protobuf_jl_internal_values[name])::GPUOptions
    elseif name === :allow_soft_placement
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :log_device_placement
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :graph_options
        return (obj.__protobuf_jl_internal_values[name])::GraphOptions
    elseif name === :operation_timeout_in_ms
        return (obj.__protobuf_jl_internal_values[name])::Int64
    elseif name === :rpc_options
        return (obj.__protobuf_jl_internal_values[name])::RPCOptions
    elseif name === :cluster_def
        return (obj.__protobuf_jl_internal_values[name])::ClusterDef
    elseif name === :isolate_session_state
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :share_cluster_devices_in_session
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :experimental
        return (obj.__protobuf_jl_internal_values[name])::ConfigProto_Experimental
    else
        getfield(obj, name)
    end
end

const RunOptions_TraceLevel = (;[
    Symbol("NO_TRACE") => Int32(0),
    Symbol("SOFTWARE_TRACE") => Int32(1),
    Symbol("HARDWARE_TRACE") => Int32(2),
    Symbol("FULL_TRACE") => Int32(3),
]...)

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

    function RunOptions_Experimental_RunHandlerPoolOptions(; kwargs...)
        obj = new(meta(RunOptions_Experimental_RunHandlerPoolOptions), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct RunOptions_Experimental_RunHandlerPoolOptions
const __meta_RunOptions_Experimental_RunHandlerPoolOptions = Ref{ProtoMeta}()
function meta(::Type{RunOptions_Experimental_RunHandlerPoolOptions})
    ProtoBuf.metalock() do
        if !isassigned(__meta_RunOptions_Experimental_RunHandlerPoolOptions)
            __meta_RunOptions_Experimental_RunHandlerPoolOptions[] = target = ProtoMeta(RunOptions_Experimental_RunHandlerPoolOptions)
            allflds = Pair{Symbol,Union{Type,String}}[:priority => Int64]
            meta(target, RunOptions_Experimental_RunHandlerPoolOptions, 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_RunOptions_Experimental_RunHandlerPoolOptions[]
    end
end
function Base.getproperty(obj::RunOptions_Experimental_RunHandlerPoolOptions, name::Symbol)
    if name === :priority
        return (obj.__protobuf_jl_internal_values[name])::Int64
    else
        getfield(obj, name)
    end
end

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

    function RunOptions_Experimental(; kwargs...)
        obj = new(meta(RunOptions_Experimental), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct RunOptions_Experimental
const __meta_RunOptions_Experimental = Ref{ProtoMeta}()
function meta(::Type{RunOptions_Experimental})
    ProtoBuf.metalock() do
        if !isassigned(__meta_RunOptions_Experimental)
            __meta_RunOptions_Experimental[] = target = ProtoMeta(RunOptions_Experimental)
            allflds = Pair{Symbol,Union{Type,String}}[:collective_graph_key => Int64, :use_run_handler_pool => Bool, :run_handler_pool_options => RunOptions_Experimental_RunHandlerPoolOptions]
            meta(target, RunOptions_Experimental, 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_RunOptions_Experimental[]
    end
end
function Base.getproperty(obj::RunOptions_Experimental, name::Symbol)
    if name === :collective_graph_key
        return (obj.__protobuf_jl_internal_values[name])::Int64
    elseif name === :use_run_handler_pool
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :run_handler_pool_options
        return (obj.__protobuf_jl_internal_values[name])::RunOptions_Experimental_RunHandlerPoolOptions
    else
        getfield(obj, name)
    end
end

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

    function RunOptions(; kwargs...)
        obj = new(meta(RunOptions), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct RunOptions
const __meta_RunOptions = Ref{ProtoMeta}()
function meta(::Type{RunOptions})
    ProtoBuf.metalock() do
        if !isassigned(__meta_RunOptions)
            __meta_RunOptions[] = target = ProtoMeta(RunOptions)
            fnum = Int[1,2,3,5,6,7,8]
            allflds = Pair{Symbol,Union{Type,String}}[:trace_level => Int32, :timeout_in_ms => Int64, :inter_op_thread_pool => Int32, :output_partition_graphs => Bool, :debug_options => DebugOptions, :report_tensor_allocations_upon_oom => Bool, :experimental => RunOptions_Experimental]
            meta(target, RunOptions, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, ProtoBuf.DEF_ONEOFS, ProtoBuf.DEF_ONEOF_NAMES)
        end
        __meta_RunOptions[]
    end
end
function Base.getproperty(obj::RunOptions, name::Symbol)
    if name === :trace_level
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :timeout_in_ms
        return (obj.__protobuf_jl_internal_values[name])::Int64
    elseif name === :inter_op_thread_pool
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :output_partition_graphs
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :debug_options
        return (obj.__protobuf_jl_internal_values[name])::DebugOptions
    elseif name === :report_tensor_allocations_upon_oom
        return (obj.__protobuf_jl_internal_values[name])::Bool
    elseif name === :experimental
        return (obj.__protobuf_jl_internal_values[name])::RunOptions_Experimental
    else
        getfield(obj, name)
    end
end

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

    function RunMetadata_FunctionGraphs(; kwargs...)
        obj = new(meta(RunMetadata_FunctionGraphs), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct RunMetadata_FunctionGraphs
const __meta_RunMetadata_FunctionGraphs = Ref{ProtoMeta}()
function meta(::Type{RunMetadata_FunctionGraphs})
    ProtoBuf.metalock() do
        if !isassigned(__meta_RunMetadata_FunctionGraphs)
            __meta_RunMetadata_FunctionGraphs[] = target = ProtoMeta(RunMetadata_FunctionGraphs)
            allflds = Pair{Symbol,Union{Type,String}}[:partition_graphs => Base.Vector{GraphDef}, :pre_optimization_graph => GraphDef, :post_optimization_graph => GraphDef]
            meta(target, RunMetadata_FunctionGraphs, 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_RunMetadata_FunctionGraphs[]
    end
end
function Base.getproperty(obj::RunMetadata_FunctionGraphs, name::Symbol)
    if name === :partition_graphs
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{GraphDef}
    elseif name === :pre_optimization_graph
        return (obj.__protobuf_jl_internal_values[name])::GraphDef
    elseif name === :post_optimization_graph
        return (obj.__protobuf_jl_internal_values[name])::GraphDef
    else
        getfield(obj, name)
    end
end

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

    function RunMetadata(; kwargs...)
        obj = new(meta(RunMetadata), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct RunMetadata
const __meta_RunMetadata = Ref{ProtoMeta}()
function meta(::Type{RunMetadata})
    ProtoBuf.metalock() do
        if !isassigned(__meta_RunMetadata)
            __meta_RunMetadata[] = target = ProtoMeta(RunMetadata)
            allflds = Pair{Symbol,Union{Type,String}}[:step_stats => StepStats, :cost_graph => CostGraphDef, :partition_graphs => Base.Vector{GraphDef}, :function_graphs => Base.Vector{RunMetadata_FunctionGraphs}]
            meta(target, RunMetadata, 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_RunMetadata[]
    end
end
function Base.getproperty(obj::RunMetadata, name::Symbol)
    if name === :step_stats
        return (obj.__protobuf_jl_internal_values[name])::StepStats
    elseif name === :cost_graph
        return (obj.__protobuf_jl_internal_values[name])::CostGraphDef
    elseif name === :partition_graphs
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{GraphDef}
    elseif name === :function_graphs
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{RunMetadata_FunctionGraphs}
    else
        getfield(obj, name)
    end
end

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

    function TensorConnection(; kwargs...)
        obj = new(meta(TensorConnection), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct TensorConnection
const __meta_TensorConnection = Ref{ProtoMeta}()
function meta(::Type{TensorConnection})
    ProtoBuf.metalock() do
        if !isassigned(__meta_TensorConnection)
            __meta_TensorConnection[] = target = ProtoMeta(TensorConnection)
            allflds = Pair{Symbol,Union{Type,String}}[:from_tensor => AbstractString, :to_tensor => AbstractString]
            meta(target, TensorConnection, 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_TensorConnection[]
    end
end
function Base.getproperty(obj::TensorConnection, name::Symbol)
    if name === :from_tensor
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :to_tensor
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    else
        getfield(obj, name)
    end
end

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

    function CallableOptions_FeedDevicesEntry(; kwargs...)
        obj = new(meta(CallableOptions_FeedDevicesEntry), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct CallableOptions_FeedDevicesEntry (mapentry)
const __meta_CallableOptions_FeedDevicesEntry = Ref{ProtoMeta}()
function meta(::Type{CallableOptions_FeedDevicesEntry})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CallableOptions_FeedDevicesEntry)
            __meta_CallableOptions_FeedDevicesEntry[] = target = ProtoMeta(CallableOptions_FeedDevicesEntry)
            allflds = Pair{Symbol,Union{Type,String}}[:key => AbstractString, :value => AbstractString]
            meta(target, CallableOptions_FeedDevicesEntry, 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_CallableOptions_FeedDevicesEntry[]
    end
end
function Base.getproperty(obj::CallableOptions_FeedDevicesEntry, 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 CallableOptions_FetchDevicesEntry <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function CallableOptions_FetchDevicesEntry(; kwargs...)
        obj = new(meta(CallableOptions_FetchDevicesEntry), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct CallableOptions_FetchDevicesEntry (mapentry)
const __meta_CallableOptions_FetchDevicesEntry = Ref{ProtoMeta}()
function meta(::Type{CallableOptions_FetchDevicesEntry})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CallableOptions_FetchDevicesEntry)
            __meta_CallableOptions_FetchDevicesEntry[] = target = ProtoMeta(CallableOptions_FetchDevicesEntry)
            allflds = Pair{Symbol,Union{Type,String}}[:key => AbstractString, :value => AbstractString]
            meta(target, CallableOptions_FetchDevicesEntry, 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_CallableOptions_FetchDevicesEntry[]
    end
end
function Base.getproperty(obj::CallableOptions_FetchDevicesEntry, 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 CallableOptions <: ProtoType
    __protobuf_jl_internal_meta::ProtoMeta
    __protobuf_jl_internal_values::Dict{Symbol,Any}
    __protobuf_jl_internal_defaultset::Set{Symbol}

    function CallableOptions(; kwargs...)
        obj = new(meta(CallableOptions), 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))
            values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
        end
        obj
    end
end # mutable struct CallableOptions
const __meta_CallableOptions = Ref{ProtoMeta}()
function meta(::Type{CallableOptions})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CallableOptions)
            __meta_CallableOptions[] = target = ProtoMeta(CallableOptions)
            allflds = Pair{Symbol,Union{Type,String}}[:feed => Base.Vector{AbstractString}, :fetch => Base.Vector{AbstractString}, :target => Base.Vector{AbstractString}, :run_options => RunOptions, :tensor_connection => Base.Vector{TensorConnection}, :feed_devices => Base.Dict{AbstractString,AbstractString}, :fetch_devices => Base.Dict{AbstractString,AbstractString}, :fetch_skip_sync => Bool]
            meta(target, CallableOptions, 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_CallableOptions[]
    end
end
function Base.getproperty(obj::CallableOptions, name::Symbol)
    if name === :feed
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{AbstractString}
    elseif name === :fetch
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{AbstractString}
    elseif name === :target
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{AbstractString}
    elseif name === :run_options
        return (obj.__protobuf_jl_internal_values[name])::RunOptions
    elseif name === :tensor_connection
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{TensorConnection}
    elseif name === :feed_devices
        return (obj.__protobuf_jl_internal_values[name])::Base.Dict{AbstractString,AbstractString}
    elseif name === :fetch_devices
        return (obj.__protobuf_jl_internal_values[name])::Base.Dict{AbstractString,AbstractString}
    elseif name === :fetch_skip_sync
        return (obj.__protobuf_jl_internal_values[name])::Bool
    else
        getfield(obj, name)
    end
end

export GPUOptions_Experimental_VirtualDevices, GPUOptions_Experimental, GPUOptions, OptimizerOptions_Level, OptimizerOptions_GlobalJitLevel, OptimizerOptions, GraphOptions, ThreadPoolOptionProto, RPCOptions, SessionMetadata, ConfigProto_DeviceCountEntry, ConfigProto_Experimental_MlirBridgeRollout, ConfigProto_Experimental, ConfigProto, RunOptions_TraceLevel, RunOptions_Experimental_RunHandlerPoolOptions, RunOptions_Experimental, RunOptions, RunMetadata_FunctionGraphs, RunMetadata, TensorConnection, CallableOptions_FeedDevicesEntry, CallableOptions_FetchDevicesEntry, CallableOptions
# mapentries: "CallableOptions_FeedDevicesEntry" => ("AbstractString", "AbstractString"), "CallableOptions_FetchDevicesEntry" => ("AbstractString", "AbstractString"), "ConfigProto_DeviceCountEntry" => ("AbstractString", "Int32")


text:
#### Diagnose environment variables

"""
    environment_vars(state::Vars, aux::Vars, N_up::Int)

A NamedTuple of environment variables
"""
function environment_vars(state::Vars, aux::Vars, N_up::Int)
    return (
        a = environment_area(state, aux, N_up),
        w = environment_w(state, aux, N_up),
    )
end

"""
    environment_area(
        state::Vars,
        aux::Vars,
        N_up::Int,
    )

Returns the environmental area fraction, given:
 - `state`, state variables
 - `aux`, auxiliary variables
 - `N_up`, number of updrafts
"""
function environment_area(state::Vars, aux::Vars, N_up::Int)
    up = state.turbconv.updraft
    return 1 - sum(vuntuple(i -> up[i].ρa, N_up)) / state.ρ
end

"""
    environment_w(
        state::Vars,
        aux::Vars,
        N_up::Int,
    )

Returns the environmental vertical velocity, given:
 - `state`, state variables
 - `aux`, auxiliary variables
 - `N_up`, number of updrafts
"""
function environment_w(state::Vars, aux::Vars, N_up::Int)
    ρ_inv = 1 / state.ρ
    a_en = environment_area(state, aux, N_up)
    up = state.turbconv.updraft
    return (state.ρu[3] - sum(vuntuple(i -> up[i].ρaw, N_up))) / a_en * ρ_inv
end

"""
    grid_mean_b(
        state::Vars,
        aux::Vars,
        N_up::Int,
    )

Returns the grid-mean buoyancy with respect to the
reference state, given:
 - `state`, state variables
 - `aux`, auxiliary variables
 - `N_up`, number of updrafts
"""
function grid_mean_b(state::Vars, aux::Vars, N_up::Int)
    ρ_inv = 1 / state.ρ
    a_en = environment_area(state, aux, N_up)
    up = state.turbconv.updraft
    en_aux = aux.turbconv.environment
    up_aux = aux.turbconv.updraft
    up_buoy = sum(vuntuple(i -> up_aux[i].buoyancy * up[i].ρa * ρ_inv, N_up))
    return a_en * en_aux.buoyancy + up_buoy
end

ext: jl

max_stars_repo_name: mwarusz/CLIMA

max_issues_repo_name: mwarusz/CLIMA

max_forks_repo_name: mwarusz/CLIMA


text:
# ---
# title: 889. Construct Binary Tree from Preorder and Postorder Traversal
# id: problem889
# author: Indigo
# date: 2021-02-01
# difficulty: Medium
# categories: Tree
# link: <https://leetcode.com/problems/construct-binary-tree-from-preorder-and-postorder-traversal/description/>
# hidden: true
# ---
#
# Return any binary tree that matches the given preorder and postorder
# traversals.
#
# Values in the traversals `pre` and `post` are distinct positive integers.
#
#
#
# **Example 1:**
#
#
#
#     Input: pre = [1,2,4,5,3,6,7], post = [4,5,2,6,7,3,1]
#     Output: [1,2,3,4,5,6,7]
#
#
#
#
# **Note:**
#
#   * `1 <= pre.length == post.length <= 30`
#   * `pre[]` and `post[]` are both permutations of `1, 2, ..., pre.length`.
#   * It is guaranteed an answer exists. If there exists multiple answers, you can return any of them.
#
#
## @lc code=start
using LeetCode

function construct_from_pre_post(pre::Vector{Int}, post::Vector{Int})
    if isempty(pre)
        return nothing
    end
    root = TreeNode(pre[1])
    if length(pre) == 1
        return root
    end
    idx = findfirst(==(pre[2]), post)
    root.left = construct_from_pre_post(pre[2:1+idx], post[1:idx])
    root.right = construct_from_pre_post(pre[2+idx:end], post[1+idx:end-1])
    root
end
## @lc code=end


text:
using PyPlot
using Triangulate

N = Float64[ 0  -2  2  2  1 -1 -2
             0  -2 -2  0  2  2  0 ]

T = [ 7  2  3  4  5  6
      2  3  4  5  6  7
      1  1  1  1  1  1 ]

E = [ 7  2  3  4  5  6
      2  3  4  5  6  7 ]

tri = Triangulation(N, T, E, 4)

figure(1)
draw_triangles(tri)
enumerate_triangles(tri)
enumerate_vertices(tri)
enumerate_bdry_edges(tri, 0.1)
#local_enumerate_vertices(tri, 0.3)
mark_first_local_vertex(tri, 0.3)
axis("off")
axis("equal")
savefig("good_triangulation.pdf")

max_stars_repo_name: billmclean/ComputationalMathsNotes

max_issues_repo_name: billmclean/ComputationalMathsNotes

max_forks_repo_name: billmclean/ComputationalMathsNotes


text:
#using Gtk, Test

@testset "tree" begin

window = GtkWindow("GtkTree", 300, 100) #errors out #<----
boxtop = GtkBox(:v) # vertical box, basic structure

wscroll = GtkScrolledWindow()

function itemlist(types, rownames)

    @assert length(types) == length(rownames)

    list = GtkTreeStore(types...)   #treeStore : list of typew
    tv = GtkTreeView(GtkTreeModel(list))  # <--- Root  Tv TreeView argument: Gtkmodel Argument : list
    cols = GtkTreeViewColumn[]  # default reeview col list
# Rendering Engine:
    for i=1:length(types)
        r1 = GtkCellRendererText() #1. RenderTesxt
        c1 = GtkTreeViewColumn(rownames[i], r1, Dict([("text",i-1)]))
        Gtk.G_.sort_column_id(c1,i-1) #sort ide by
        push!(cols,c1) #apply_changes: c1 onto-> cols
        #Gtk.G_.max_width(c1,Int(200/n))
        push!(tv,c1)
    end

    return (tv,list,cols)
end

tv, store, cols = itemlist([Int, String], ["No", "Name"])
treeModel = GtkTreeModel(store)
#rendered Items
push!(wscroll, tv)  # Treview onto wScroll
push!(boxtop, wscroll) #schroll onto boxtop
push!(window, boxtop) #boctop onto window

wscroll.height_request[Int] = 300

showall(window);

##

push!(store, (1, "London"))
iter = push!(store, (2, "Grenoble"))
iter2 = pushfirst!(store, (0, "Slough"))
deleteat!(store, iter2)

@test isvalid(store,iter)
@test Gtk.ncolumns(treeModel) == 2

path = Gtk.path(treeModel,iter)
@test depth(path) == 1
@test string(path) == "1"
@test prev(path)
@test string(path) == "0"

success, iter = Gtk.iter(treeModel,path)
@test success == true
@test store[iter] == (1, "London")

iter = Gtk.iter_from_string_index(store,"0")
@test isvalid(store,iter)
@test store[iter] == (1, "London")

iter = insert!(store, iter, (0,"Paris"); how = :sibling, where=:before)
@test store[iter] == (0,"Paris")

@test store[[1]] == (0,"Paris")

iter = insert!(store, iter, (3,"Paris child"); how = :parent, where=:after)
path = Gtk.path(treeModel,iter)
@test depth(path) == 2
@test depth(store, iter) == 1

iter = insert!(store, [3], (4, "Barcelona"); how = :sibling, where=:after)
@test store[[4],2] == "Barcelona"
store[[4],2] = "Madrid"
splice!(store, [4])

##

selection = GAccessor.selection(tv)
@test hasselection(selection) == false

iter = Gtk.iter_from_string_index(store,"0")
select!(selection, iter)

@test length(selection) == 1

iters = Gtk.selected_rows(selection)
@test length(iters) == 1
@test store[iters[1],1] == 0

empty!(store)

end

max_stars_repo_name: adamwillisMastery/DeepLearner

max_issues_repo_name: adamwillisMastery/DeepLearner

max_forks_repo_name: adamwillisXanax/DeepLearner


text:
export
    OperatorConv,
    SpectralConv,
    OperatorKernel

struct OperatorConv{P, T, S, TT}
    weight::T
    in_channel::S
    out_channel::S
    transform::TT
end

function OperatorConv{P}(
    weight::T,
    in_channel::S,
    out_channel::S,
    transform::TT
) where {P, T, S, TT<:AbstractTransform}
    return OperatorConv{P, T, S, TT}(weight, in_channel, out_channel, transform)
end

"""
    OperatorConv(
        ch, modes, transform;
        init=c_glorot_uniform, permuted=false, T=ComplexF32
    )

## Arguments

* `ch`: Input and output channel size, e.g. `64=>64`.
* `modes`: The modes to be preserved.
* `Transform`: The trafo to operate the transformation.
* `permuted`: Whether the dim is permuted. If `permuted=true`, layer accepts
    data in the order of `(ch, ..., batch)`, otherwise the order is `(..., ch, batch)`.

## Example

```jldoctest
julia> OperatorConv(2=>5, (16, ), FourierTransform)
OperatorConv(2 => 5, (16,), FourierTransform, permuted=false)

julia> OperatorConv(2=>5, (16, ), FourierTransform, permuted=true)
OperatorConv(2 => 5, (16,), FourierTransform, permuted=true)
```
"""
function OperatorConv(
    ch::Pair{S, S},
    modes::NTuple{N, S},
    Transform::Type{<:AbstractTransform};
    init=c_glorot_uniform,
    permuted=false,
    T::DataType=ComplexF32
) where {S<:Integer, N}
    in_chs, out_chs = ch
    scale = one(T) / (in_chs * out_chs)
    weights = scale * init(prod(modes), in_chs, out_chs)
    transform = Transform(modes)

    return OperatorConv{permuted}(weights, in_chs, out_chs, transform)
end

function SpectralConv(
    ch::Pair{S, S},
    modes::NTuple{N, S};
    init=c_glorot_uniform,
    permuted=false,
    T::DataType=ComplexF32
) where {S<:Integer, N}
    return OperatorConv(ch, modes, FourierTransform, init=init, permuted=permuted, T=T)
end

Flux.@functor OperatorConv{true}
Flux.@functor OperatorConv{false}

Base.ndims(oc::OperatorConv) = ndims(oc.transform)

ispermuted(::OperatorConv{P}) where {P} = P

function Base.show(io::IO, l::OperatorConv{P}) where {P}
    print(io, "OperatorConv($(l.in_channel) => $(l.out_channel), $(l.transform.modes), $(nameof(typeof(l.transform))), permuted=$P)")
end

function operator_conv(m::OperatorConv, 𝐱::AbstractArray)
    𝐱_transformed = transform(m.transform, 𝐱) # [size(x)..., in_chs, batch]
    𝐱_truncated = truncate_modes(m.transform, 𝐱_transformed) # [modes..., in_chs, batch]
    𝐱_applied_pattern = apply_pattern(𝐱_truncated, m.weight) # [modes..., out_chs, batch]
    𝐱_padded = pad_modes(𝐱_applied_pattern, (size(𝐱_transformed)[1:end-2]..., size(𝐱_applied_pattern)[end-1:end]...)) # [size(x)..., out_chs, batch] <- [modes..., out_chs, batch]
    𝐱_inversed = inverse(m.transform, 𝐱_padded)

    return 𝐱_inversed
end

function (m::OperatorConv{false})(𝐱)
    𝐱ᵀ = permutedims(𝐱, (ntuple(i->i+1, ndims(m))..., 1, ndims(m)+2)) # [x, in_chs, batch] <- [in_chs, x, batch]
    𝐱_out = operator_conv(m, 𝐱ᵀ) # [x, out_chs, batch]
    𝐱_outᵀ = permutedims(𝐱_out, (ndims(m)+1, 1:ndims(m)..., ndims(m)+2)) # [out_chs, x, batch] <- [x, out_chs, batch]

    return 𝐱_outᵀ
end

function (m::OperatorConv{true})(𝐱)
    return operator_conv(m, 𝐱) # [x, out_chs, batch]
end

############
# operator #
############

struct OperatorKernel{L, C, F}
    linear::L
    conv::C
    σ::F
end

"""
    OperatorKernel(ch, modes, σ=identity; permuted=false)

## Arguments

* `ch`: Input and output channel size for spectral convolution, e.g. `64=>64`.
* `modes`: The Fourier modes to be preserved for spectral convolution.
* `σ`: Activation function.
* `permuted`: Whether the dim is permuted. If `permuted=true`, layer accepts
    data in the order of `(ch, ..., batch)`, otherwise the order is `(..., ch, batch)`.

## Example

```jldoctest
julia> OperatorKernel(2=>5, (16, ), FourierTransform)
OperatorKernel(2 => 5, (16,), FourierTransform, σ=identity, permuted=false)

julia> using Flux

julia> OperatorKernel(2=>5, (16, ), FourierTransform, relu)
OperatorKernel(2 => 5, (16,), FourierTransform, σ=relu, permuted=false)

julia> OperatorKernel(2=>5, (16, ), FourierTransform, relu, permuted=true)
OperatorKernel(2 => 5, (16,), FourierTransform, σ=relu, permuted=true)
```
"""
function OperatorKernel(
    ch::Pair{S, S},
    modes::NTuple{N, S},
    Transform::Type{<:AbstractTransform},
    σ=identity;
    permuted=false
) where {S<:Integer, N}
    linear = permuted ? Conv(Tuple(ones(Int, length(modes))), ch) : Dense(ch.first, ch.second)
    conv = OperatorConv(ch, modes, Transform; permuted=permuted)

    return OperatorKernel(linear, conv, σ)
end

Flux.@functor OperatorKernel

function Base.show(io::IO, l::OperatorKernel)
    print(
        io,
        "OperatorKernel(" *
            "$(l.conv.in_channel) => $(l.conv.out_channel), " *
            "$(l.conv.transform.modes), " *
            "$(nameof(typeof(l.conv.transform))), " *
            "σ=$(string(l.σ)), " *
            "permuted=$(ispermuted(l.conv))" *
        ")"
    )
end

function (m::OperatorKernel)(𝐱)
    return m.σ.(m.linear(𝐱) + m.conv(𝐱))
end

#########
# utils #
#########

c_glorot_uniform(dims...) = Flux.glorot_uniform(dims...) + Flux.glorot_uniform(dims...)*im

# [prod(modes), out_chs, batch] <- [prod(modes), in_chs, batch] * [out_chs, in_chs, prod(modes)]
einsum(𝐱₁, 𝐱₂) = @tullio 𝐲[m, o, b] := 𝐱₁[m, i, b] * 𝐱₂[m, i, o]

function apply_pattern(𝐱_truncated, 𝐰)
    x_size = size(𝐱_truncated) # [m.modes..., in_chs, batch]

    𝐱_flattened = reshape(𝐱_truncated, :, x_size[end-1:end]...) # [prod(m.modes), in_chs, batch], only 3-dims
    𝐱_weighted = einsum(𝐱_flattened, 𝐰) # [prod(m.modes), out_chs, batch], only 3-dims
    𝐱_shaped = reshape(𝐱_weighted, x_size[1:end-2]..., size(𝐱_weighted)[2:3]...) # [m.modes..., out_chs, batch]

    return 𝐱_shaped
end

pad_modes(𝐱::AbstractArray, dims::NTuple) = pad_modes!(similar(𝐱, dims), 𝐱)

function pad_modes!(𝐱_padded::AbstractArray, 𝐱::AbstractArray)
    fill!(𝐱_padded, eltype(𝐱)(0)) # zeros(eltype(𝐱), dims)
    𝐱_padded[map(d->1:d, size(𝐱))...] .= 𝐱

    return 𝐱_padded
end

function ChainRulesCore.rrule(::typeof(pad_modes), 𝐱::AbstractArray, dims::NTuple)
    function pad_modes_pullback(𝐲̄)
        return NoTangent(), view(𝐲̄, map(d->1:d, size(𝐱))...), NoTangent()
    end

    return pad_modes(𝐱, dims), pad_modes_pullback
end


text:
using LazyArrays: ApplyArray
using Accessors: set
using Random

export MultiChain
struct MultiChain{T} <: AbstractVector{T}
    chains
end

export getchains

Base.size(mc::MultiChain) = size(samples(mc))

getchains(mc::MultiChain) = getfield(mc, :chains)

function Base.getindex(mc::MultiChain, n::Int)
    getindex(samples(mc), n)
end

Base.propertynames(mc::MultiChain) = propertynames(first(samples(mc)))

Base.getproperty(mc::MultiChain, p::Symbol) = ApplyArray(vcat, getproperty.(getchains(mc), p)...)

MultiChain(chains::AbstractChain...) = MultiChain([chains...])

function MultiChain(chains::Vector{<:AbstractChain{T}}) where {T}
    return MultiChain{T}(chains)
end

function TupleVectors.summarize(mc::MultiChain)
    summarize(samples(mc))
end

function newchain(rng, nchains::Int, config::ChainConfig{T}, args...) where {T}
    chains = T[newchain(rng, config, args...) for n in 1:nchains]
    return MultiChain(chains...)
end

function newchain(nchains::Int, config::ChainConfig{T}, args...) where {T}
    newchain(Random.GLOBAL_RNG, nchains, config, args...)
end

function sample!(chains::MultiChain, n::Int)
    rawchains = getchains(chains)
    for i in 1:length(rawchains)
        sample!(rawchains[i], n)
    end

    return chains
end

function samples(mc::MultiChain{T}) where {T}
    chs = getchains(mc)
    # Get the appropriate NamedTuple to use as a template
    nt = unwrap(samples(first(chs)))

    # For each leaf of our template, ...
    for lens in lenses(nt)
        # Get the corresponding leaves of the chains...
        vecs = (lens(unwrap(ch)) for ch in chs)

        # and concatenate them.
        nt = set(nt, lens, ApplyArray(vcat, vecs...))
    end
    return TupleVector{T, typeof(nt)}(nt)
end

function Base.showarg(io::IO, mc::MultiChain{T}, toplevel) where T
    io = IOContext(io, :compact => true)
    numchains = length(getchains(mc))
    print(io, "MultiChain")
    if toplevel
        println(io, " with $numchains chains and schema ", schema(T))
    end
end

function Base.show(io::IO, ::MIME"text/plain", mc::MultiChain)
    summary(io, mc)
    print(io, summarize(mc))
end

NestedTuples.rmap(f, mc::MultiChain) = rmap.(f, getchains(mc))


text:
export decision_stump

import ..DSModel

using mlpack._Internal.io

import mlpack_jll
const decision_stumpLibrary = mlpack_jll.libmlpack_julia_decision_stump

# Call the C binding of the mlpack decision_stump binding.
function decision_stump_mlpackMain()
  success = ccall((:decision_stump, decision_stumpLibrary), Bool, ())
  if !success
    # Throw an exception---false means there was a C++ exception.
    throw(ErrorException("mlpack binding error; see output"))
  end
end

" Internal module to hold utility functions. "
module decision_stump_internal
  import ..decision_stumpLibrary

import ...DSModel

# Get the value of a model pointer parameter of type DSModel.
function IOGetParamDSModel(paramName::String)::DSModel
  DSModel(ccall((:IO_GetParamDSModelPtr, decision_stumpLibrary), Ptr{Nothing}, (Cstring,), paramName))
end

# Set the value of a model pointer parameter of type DSModel.
function IOSetParamDSModel(paramName::String, model::DSModel)
  ccall((:IO_SetParamDSModelPtr, decision_stumpLibrary), Nothing, (Cstring, Ptr{Nothing}), paramName, model.ptr)
end

# Serialize a model to the given stream.
function serializeDSModel(stream::IO, model::DSModel)
  buf_len = UInt[0]
  buf_ptr = ccall((:SerializeDSModelPtr, decision_stumpLibrary), Ptr{UInt8}, (Ptr{Nothing}, Ptr{UInt}), model.ptr, Base.pointer(buf_len))
  buf = Base.unsafe_wrap(Vector{UInt8}, buf_ptr, buf_len[1]; own=true)
  write(stream, buf)
end
# Deserialize a model from the given stream.
function deserializeDSModel(stream::IO)::DSModel
  buffer = read(stream)
  DSModel(ccall((:DeserializeDSModelPtr, decision_stumpLibrary), Ptr{Nothing}, (Ptr{UInt8}, UInt), Base.pointer(buffer), length(buffer)))
end
end # module

"""
    decision_stump(; [bucket_size, input_model, labels, test, training, verbose])

This program implements a decision stump, which is a single-level decision tree.
 The decision stump will split on one dimension of the input data, and will
split into multiple buckets.  The dimension and bins are selected by maximizing
the information gain of the split.  Optionally, the minimum number of training
points in each bin can be specified with the `bucket_size` parameter.

The decision stump is parameterized by a splitting dimension and a vector of
values that denote the splitting values of each bin.

This program enables several applications: a decision tree may be trained or
loaded, and then that decision tree may be used to classify a given set of test
points.  The decision tree may also be saved to a file for later usage.

To train a decision stump, training data should be passed with the `training`
parameter, and their corresponding labels should be passed with the `labels`
option.  Optionally, if `labels` is not specified, the labels are assumed to be
the last dimension of the training dataset.  The `bucket_size` parameter
controls the minimum number of training points in each decision stump bucket.

For classifying a test set, a decision stump may be loaded with the
`input_model` parameter (useful for the situation where a stump has already been
trained), and a test set may be specified with the `test` parameter.  The
predicted labels can be saved with the `predictions` output parameter.

Because decision stumps are trained in batch, retraining does not make sense and
thus it is not possible to pass both `training` and `input_model`; instead,
simply build a new decision stump with the training data.

After training, a decision stump can be saved with the `output_model` output
parameter.  That stump may later be re-used in subsequent calls to this program
(or others).

# Arguments

 - `bucket_size::Int`: The minimum number of training points in each
      decision stump bucket.  Default value `6`.

 - `input_model::DSModel`: Decision stump model to load.
 - `labels::Array{Int, 1}`: Labels for the training set. If not specified,
      the labels are assumed to be the last row of the training data.
 - `test::Array{Float64, 2}`: A dataset to calculate predictions for.
 - `training::Array{Float64, 2}`: The dataset to train on.
 - `verbose::Bool`: Display informational messages and the full list of
      parameters and timers at the end of execution.  Default value `false`.

# Return values

 - `output_model::DSModel`: Output decision stump model to save.
 - `predictions::Array{Int, 1}`: The output matrix that will hold the
      predicted labels for the test set.

"""
function decision_stump(;
                        bucket_size::Union{Int, Missing} = missing,
                        input_model::Union{DSModel, Missing} = missing,
                        labels = missing,
                        test = missing,
                        training = missing,
                        verbose::Union{Bool, Missing} = missing,
                        points_are_rows::Bool = true)
  # Force the symbols to load.
  ccall((:loadSymbols, decision_stumpLibrary), Nothing, ());

  IORestoreSettings("Decision Stump")

  # Process each input argument before calling mlpackMain().
  if !ismissing(bucket_size)
    IOSetParam("bucket_size", convert(Int, bucket_size))
  end
  if !ismissing(input_model)
    decision_stump_internal.IOSetParamDSModel("input_model", convert(DSModel, input_model))
  end
  if !ismissing(labels)
    IOSetParamURow("labels", labels)
  end
  if !ismissing(test)
    IOSetParamMat("test", test, points_are_rows)
  end
  if !ismissing(training)
    IOSetParamMat("training", training, points_are_rows)
  end
  if verbose !== nothing && verbose === true
    IOEnableVerbose()
  else
    IODisableVerbose()
  end

  IOSetPassed("output_model")
  IOSetPassed("predictions")
  # Call the program.
  decision_stump_mlpackMain()

  return decision_stump_internal.IOGetParamDSModel("output_model"),
         IOGetParamURow("predictions")
end


text:
curr_path = @__DIR__

function getrandom(select::Array)
    return select[rand(1:length(select))]
end

# Prints possible languages
function getlanguages()
    possible_languages = "$curr_path/data"
    return join(readdir(possible_languages), ", ")
end

function typeoftoken(token::SubString)
    return token[1] == '%' && token[end] == '%' ? "function" : "default"
end


text:
module SVMLightWriter

using Printf, SparseArrays, Requires, ProgressMeter

export dump_svmlight_file

function dump_svmlight_file(x::AbstractArray, y, f::IO; zero_based = true, query_id = nothing)
    @assert size(x, 2) == length(y)
    noqid = isnothing(query_id)
    noqid || @assert length(query_id) == length(y)
    @inbounds @showprogress "dumpsvm..." for j in 1:length(y)
        print(f, y[j])
        noqid || print(f, " qid:", query_id[j])
        for i in 1:size(x, 1)
            v = x[i, j]
            iszero(v) && continue
            i′ = ifelse(zero_based, i - 1, i)
            print(f, ' ', i′, ':')
            @printf(f, "%.4g", v)
        end
        println(f)
    end
end

function dump_svmlight_file(x::SparseMatrixCSC, y, f::IO; zero_based = true, query_id = nothing)
    @assert size(x, 2) == length(y)
    noqid = isnothing(query_id)
    noqid || @assert length(query_id) == length(y)
    @inbounds @showprogress "dumpsvm..." for j in 1:length(y)
        print(f, y[j])
        noqid || print(f, " qid:", query_id[j])
        for n in x.colptr[j]:(x.colptr[j + 1] - 1)
            i = x.rowval[n]
            i′ = ifelse(zero_based, i - 1, i)
            print(f, ' ', i′, ':')
            @printf(f, "%.4g", x.nzval[n])
        end
        println(f)
    end
end

dump_svmlight_file(x, y, file::String; ka...) = open(file, "w") do f
    dump_svmlight_file(x, y, f; ka...)
end

@init @require PyCall="438e738f-606a-5dbb-bf0a-cddfbfd45ab0" begin
dump_svmlight_file(x::PyCall.PyObject, a...; ka...) =
    PyCall.pyimport("sklearn.datasets").dump_svmlight_file(x, a..., ka...)
end

end # module


text:
abstract type AbstractGPLayer end;

struct SVGPLayer{GPType} <: AbstractGPLayer
    dim::Int
    gps::Vector{GPType}
    function SVGPLayer(dim,μ,Σ,Z,kernel,μ₀)
        gps = [SVGP_Base(copy(μ),copy(Σ),copy(Z),deepcopy(kernel),deepcopy(μ₀)) for _ in 1:dim]
        new{SVGP_Base}(dim,gps)
    end
end

Base.length(l::SVGPLayer) = l.dim
Base.getindex(l::SVGPLayer,i::Int) = l.gps[i]

function propagate(l::AbstractGPLayer,samples::AbstractVector{<:AbstractArray})
    compute_invK.(l.gps)
    propagate.([l],samples)
end
function propagate(l::AbstractGPLayer,samples::AbstractArray{<:Real})
    ## Return the parametrization m + eps *sqrt(S)
    mu(l,samples) + randn(size(samples,1),l.dim).*sqrt.(diag_sigma(l,samples))
end

mu(l::AbstractGPLayer,x) = reduce(hcat,[mu(gp,x) for gp in l.gps])
diag_sigma(l::AbstractGPLayer,x) = reduce(hcat,[diag_sigma(gp,x) for gp in l.gps])

kl_divergence(l::AbstractGPLayer) = sum(kl_divergence(gp) for gp in l.gps)

abstract type AbstractGPBase end;

mutable struct SVGP_Base{T} <: AbstractGPBase
    dim::Int
    μ::Vector{T}
    Σ::Matrix{T}
    μ₀::AGP.PriorMean
    kernel::KernelFunctions.Kernel
    Z::Matrix
    invKmm::Matrix{T}
    function SVGP_Base(dim,Z::Matrix{T},kernel=SqExponentialKernel(),μ₀=ZeroMean()) where {T}
        new{T}(dim,zeros(T,dim),diagm(ones(T,dim)),μ₀,kernel,Z,diagm(ones(T,dim)))
    end
    function SVGP_Base(μ::Vector{T},Σ::Matrix{T},Z::Matrix,kernel::KernelFunctions.Kernel,μ₀::AGP.PriorMean) where {T}
        new{T}(length(μ),μ,Σ,μ₀,kernel,Z,diagm(ones(T,length(μ))))
    end
end

function compute_invK(gp::SVGP_Base)
    gp.invKmm = inv(KernelFunctions.kernelmatrix(gp.kernel,gp.Z,obsdim=1)+1e-5I)
end

function κ(gp::SVGP_Base,X::AbstractArray,invKmm)
    ## Return the K_XZ K
    try
        KernelFunctions.kernelmatrix(gp.kernel,X,gp.Z,obsdim=1)*invKmm
    catch e
        @show size(X)
        @show size(gp.Z)
        rethrow(e)
    end
end

_k(gp::AbstractGPBase,x,y) = KernelFunctions.kernelmatrix(gp.kernel,x,y,obsdim=1)
_diagk(gp::AbstractGPBase,x) = KernelFunctions.kerneldiagmatrix(gp.kernel,x,obsdim=1).+1e-5

mu(gp::SVGP_Base,x)= gp.μ₀ + κ(gp,x,gp.invKmm)*(gp.μ-gp.μ₀)
diag_sigma(gp::SVGP_Base,x) = diag_sigma(gp,x,κ(gp,x,gp.invKmm))
diag_sigma(gp::SVGP_Base,x,κ) = _diagk(gp,x) - AGP.opt_diag(κ*(gp.invKmm-gp.Σ),κ)

kl_divergence(gp::SVGP_Base) = 0.5*(-logdet(gp.Σ)-logdet(gp.invKmm)+AGP.opt_trace(gp.invKmm,gp.Σ)+dot(gp.μ-gp.μ₀,gp.invKmm*(gp.μ-gp.μ₀))-length(gp.μ))


text:
struct IterationLog
    header::Array{String, 1}
    keywords::Array{Symbol, 1}
    types::Vector
    entries::Array{Any, 1}
    fmt::String
end

# function IterationLog()
#     header = [ "It", "ϵₙ", "ηₙ=|xₙ-xₙ₋₁|", "λₙ=ηₙ/ηₙ₋₁", "Time", "Newton steps"]
#     keywords = [:it, :err, :gain, :time, :nit]
#     IterationLog(header, keywords, [])
# end

function IterationLog(;kw...)
    keywords = Symbol[]
    header = String[]
    elts = []
    types= []
    for (k,(v,t)) in kw
        push!(types, t)
        push!(keywords, k)
        push!(header, v)
        if t<:Int
            push!(elts, "{:>8}")
        elseif t<:Real
            push!(elts, "{:>12.4e}")
        else
            error("Don't know how to format type $t")
        end
    end
    fmt = join(elts, " | ")
    IterationLog(header, keywords, types, [], fmt)
end

function append!(log::IterationLog; verbose=true, entry...)
    d = Dict(entry)
    push!(log.entries, d)
    verbose && show_entry(log, d)
end

function initialize(log::IterationLog; verbose=true, message=nothing)
    verbose && show_start(log; message=message)
end

function finalize(log::IterationLog; verbose=true)
    verbose && show_end(log)
end

function show(log::IterationLog)
    show_start(log)
    for entry in log.entries
        show_entry(log,entry)
    end
    show_end(log)
end

function show_start(log::IterationLog; message=nothing)
    # println(repeat("-", 66))
    # @printf "%-6s%-16s%-16s%-16s%-16s%-5s\n" "It" "ϵₙ" "ηₙ=|xₙ-xₙ₋₁|" "λₙ=ηₙ/ηₙ₋₁" "Time" "Newton steps"
    # println(repeat("-", 66))

    l = []
    for t in log.types
        if t<:Int
            push!(l, "{:>8}")
        elseif t<:Real
            push!(l, "{:>12}")
        end
    end

    a = join(l, " | ")
    s = format(a, log.header...)

    if message !== nothing
        println(repeat("-", length(s)))
        println(message)
    end
    println(repeat("-", length(s)))

    println(s)
    println(repeat("-", length(s)))
end

function show_entry(log::IterationLog, entry)

    vals = [entry[k] for k in log.keywords]
    printfmt(log.fmt, vals...)
    print("\n")

end

function show_end(log::IterationLog)
    println(repeat("-", 66))
end

###

mutable struct IterationTrace
    trace::Array{Any,1}
end

mutable struct TimeIterationResult
    dr::AbstractDecisionRule
    iterations::Int
    complementarities::Bool
    dprocess::AbstractDiscretizedProcess
    x_converged::Bool
    x_tol::Float64
    err::Float64
    log::IterationLog
    trace::Union{Nothing,IterationTrace}
end

converged(r::TimeIterationResult) = r.x_converged
function Base.show(io::IO, r::TimeIterationResult)
    @printf io "Results of Time Iteration Algorithm\n"
    @printf io " * Complementarities: %s\n" string(r.complementarities)
    @printf io " * Discretized Process type: %s\n" string(typeof(r.dprocess))
    @printf io " * Decision Rule type: %s\n" string(typeof(r.dr))
    @printf io " * Number of iterations: %s\n" string(r.iterations)
    @printf io " * Convergence: %s\n" converged(r)
    @printf io "   * |x - x'| < %.1e: %s\n" r.x_tol r.x_converged
end

function newton2(fun, dfun, x0::MSM; maxit=50, dampen=1.0, verbose=false, bcksteps = 5)

    r0 = fun(x0)

    err = norm(r0)

    local x1

    x1data = deepcopy(x0.data)
    x1 = MSM(x1data, x0.sizes)

    for n=1:maxit

        r0 = fun(x0)
        err_0 = norm(r0)

        j = dfun(x0)
        δ = (j\r0)
        for i=0:(bcksteps-1)
            u = 0.5^i
            x1.data[:] .= x0.data - δ.data*u
            r1 = fun(x1)
            err_1 = norm(r1)
            if verbose
                println( "-    $i: ", err_1)
            end
            if err_1<err_0
                break
            end
        end

        if verbose
            println(n, " | ", norm(r0), " | ",  norm(δ))
        end

        x0 = x1

    end

    return x0

end

"""
Computes a global solution for a model via backward time iteration. The time iteration is applied to the residuals of the arbitrage equations.

If the initial guess for the decision rule is not explicitly provided, the initial guess is provided by `ConstantDecisionRule`.
If the stochastic process for the model is not explicitly provided, the process is taken from the default provided by the model object, `model.exogenous`

# Arguments
* `model::NumericModel`: Model object that describes the current model environment.
* `process`: The stochastic process associated with the exogenous variables in the model.
* `init_dr`: Initial guess for the decision rule.
# Returns
* `dr`: Solved decision rule.
"""
function time_iteration(model;
    dr0=Dolo.ConstantDecisionRule(model),
    discretization=Dict(),
    interpolation=:cubic,
    verbose=true,
    details=true,
    ignore_constraints=false,
    trace = false,
    tol_η = 1e-8,
    tol_ε = 1e-8,
    maxit=500
)

    F = Euler(model; discretization=discretization, interpolation=interpolation, dr0=dr0,  ignore_constraints=ignore_constraints)

    complementarities = false

    if interpolation != :cubic
        error("Interpolation option ($interpolation) is currently not recognized.")
    end

    ti_trace = trace ? IterationTrace([x0]) : nothing

    z0 = deepcopy(F.x0)
    z1 = deepcopy(z0)

    log = IterationLog(
        it = ("n", Int),
        err =  ("ϵₙ=|F(xₙ,xₙ)|", Float64),
        sa =  ("ηₙ=|xₙ-xₙ₋₁|", Float64),
        lam = ("λₙ=ηₙ/ηₙ₋₁",Float64),
        elapsed = ("Time", Float64)
    )

    initialize(log, verbose=verbose; message="Time Iteration")

    local err_η, z0, z1

    err_η_0 = NaN

    it = 0

    while it<=maxit

        it += 1

        t1 = time_ns()

        r0 = F(z0, z0; set_future=true)

        err_ε= norm(r0)
        if err_ε<tol_ε
            break
        end

        fun = u->F(u, z0; set_future=false)
        dfun = u->df_A(F,u, z0; set_future=false)

        sol = newton2(
            fun, dfun,
            z0, verbose=false
        )

        z1 = sol
        δ = z1 - z0

        trace && push!(ti_trace.trace, z1)

        err_η = norm(δ)
        gain = err_η / err_η_0
        err_η_0 = err_η

        if err_η<tol_η
            break
        end

        # z0.data[:] .= z1.data
        z0 = z1

        elapsed = time_ns() - t1

        elapsed /= 1000000000

        append!(log; verbose=verbose, it=it, err=err_ε, sa=err_η, lam=gain, elapsed=elapsed)

    end

    finalize(log, verbose=verbose)

    res = TimeIterationResult(F.dr.dr, it, complementarities, F.dprocess, err_η<tol_η, tol_η, err_η, log, ti_trace)

    return res

end

function improved_time_iteration(model;
    dr0=Dolo.ConstantDecisionRule(model),
    discretization=Dict(),
    interpolation=:cubic,
    verbose=true,
    details=true,
    ignore_constraints=false,
    trace = false,
    tol_η = 1e-8,
    tol_ε = 1e-8,
    tol_ν = 1e-10,
    maxit=500,
    smaxit=500
)

    F = Euler(model; discretization=discretization, interpolation=interpolation, dr0=dr0, ignore_constraints=ignore_constraints)

    complementarities = false

    if interpolation != :cubic
        error("Interpolation option ($interpolation) is currently not recognized.")
    end

    ti_trace = trace ? IterationTrace([x0]) : nothing

    z0 = deepcopy(F.x0)

    local err_η, err_ε

    log = IterationLog(;
        it=("It",Int),
        err= ("ϵₙ=|F(xₙ,xₙ)|",Float64),
        sa= ("ηₙ=|xₙ-xₙ₋₁|", Float64),
        time=("Time", Float64)
    )
    initialize(log; verbose=verbose, message="Improved Time Iteration")

    it = 0
    while it<=maxit

        t1 = time_ns()

        it += 1

        r = F(z0, z0; set_future=true)

        err_ε = norm(r)

        J = df_A(F, z0, z0 ; set_future=false)
        L = df_B(F, z0, z0 ; set_future=false)

        mult!(L, -1.0)
        prediv!(L, J) # J\L

        π = -J\r

        count = 0

        u = π
        δ = π
        for i=1:smaxit
            count +=1
            u = L*u
            δ += u
            if norm(u)<tol_ν
                break
            end
        end

        z0 = z0 + δ

        err_η = norm(δ)

        elapsed = time_ns() - t1

        append!(log; verbose=verbose,
            it = it,
            err = err_ε,
            sa = err_η,
            time = elapsed
        )

        if err_η<tol_η
            break
        end

    end

    finalize(log, verbose=verbose)

    res = ImprovedTimeIterationResult(
        F.dr.dr,
        it,
        err_ε,
        err_η,
        err_η<tol_η,
        complementarities,
        F.dprocess,
        tol_ν,
        NaN,
        0,
        0,
        0,
        ti_trace
    )

    res
end

function update_guess(F, x0, p0, dp, tol=1e-8, maxit=1000)
    df = dFdp(F, x0, x0, p0, dp)
    J = Dolo.df_A(F, x0, x0)
    L = Dolo.df_B(F, x0, x0)
    Dolo.prediv!(L, J)
    Dolo.mult!(L, -1.0)
    dπ = -J\df
    dx = dπ
    i = 0
    while i<=maxit
        i += 1
        err = Dolo.norm(dπ)
        if err<tol
            break
        end
        dπ = L*dπ
        dx += dπ
    end
    return dx, i
end


text:
# Copyright 2018 Erik Edin
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
Selecting which features and scenarios to run, based on tags.

# Exports

    TagSelector
    select(::TagSelector, tags::AbstractVector{String}) :: Bool
    parsetagselector(::String) :: TagSelector
"""
module Selection

using Behavior.Gherkin

export select, parsetagselector, TagSelector, newparsetagselector

"""
Abstract type for a tag expression.
Each tag expression can be matched against a set of tags.
"""
abstract type TagExpression end

"""
    matches(ex::TagExpression, tags::AbstractVector{String}) :: Bool

Returns true if `tags` matches the tag expression `ex`, false otherwise.
This must be implemented for each `TagExpression` subtype.
"""
matches(::TagExpression, tags::AbstractVector{String}) :: Bool = error("Implement this in TagExpression types")

"""
Tag is an expression that matches against a single tag.

It will match if the tag in the `value` is in the `tags` set.
"""
struct Tag <: TagExpression
    value::String
end
matches(ex::Tag, tags::AbstractVector{String}) = ex.value in tags

"""
Not matches a tag set if and only if the `inner` tag expression _does not_ match.
"""
struct Not <: TagExpression
    inner::TagExpression
end
matches(ex::Not, tags::AbstractVector{String}) = !matches(ex.inner, tags)

"""
All is a tag expression that matches any tags or no tags.
"""
struct All <: TagExpression end
matches(::All, ::AbstractVector{String}) = true

"""
Any matches any tags in a list.
"""
struct Any <: TagExpression
    exs::Vector{TagExpression}
end
matches(anyex::Any, tags::AbstractVector{String}) = any(ex -> matches(ex, tags), anyex.exs)

"""
    Or(::TagExpression, ::TagExpression)

Match either expression.
"""
struct Or <: TagExpression
    a::TagExpression
    b::TagExpression
end

struct OrResult <: TagExpression
    b::TagExpression
end

"""
    Parentheses(::TagExpression)

An expression in parentheses.
"""
struct Parentheses <: TagExpression
    ex::TagExpression
end

"""
    NothingExpression

Represents an empty parse result.
"""
struct NothingExpression <: TagExpression end

"""
    parsetagexpression(s::String) :: TagExpression

Parse the string `s` into a `TagExpression`.
"""
function parsetagexpression(s::String) :: TagExpression
    if isempty(strip(s))
        All()
    elseif startswith(s, "not ")
        tag = replace(s, "not " => "")
        Not(parsetagexpression(tag))
    else
        tags = split(s, ",")
        Any([Tag(t) for t in tags])
    end
end

"""
TagSelector is used to select a feature or scenario based on its tags.

The `TagSelector` is created by parsing a tag expression in string form. Then the
`select` method can be used to query if a given feature or scenario should be selected for execution.
"""
struct TagSelector
    expression::TagExpression
end

"""
    selectscenario(::TagSelector, feature::Feature, scenario::Scenario) :: Boolean

Check if a given scenario ought to be included in the execution. Returns true if that is the case,
false otherwise.
"""
function select(ts::TagSelector, feature::Feature, scenario::Gherkin.AbstractScenario) :: Bool
    tags = vcat(feature.header.tags, scenario.tags)
    matches(ts.expression, tags)
end

"""
    select(::TagSelector, feature::Feature) :: Union{Feature,Nothing}

Filter a feature and its scenarios based on the selected tags.
Returns a feature with zero or more scenarios, or nothing if the feature
and none of the scenarios matched the tag selector.
"""
function select(ts::TagSelector, feature::Feature) :: Feature
    newscenarios = [scenario
                    for scenario in feature.scenarios
                    if select(ts, feature, scenario)]
    Feature(feature, newscenarios)
end

"""
    parsetagselector(s::String) :: TagSelector

Parse a string into a `TagSelector` struct. This can then be used with the `select` query to determine
if a given feature or scenario should be selected for execution.

# Examples
```julia-repl
julia> # Will match any feature/scenario with the tag @foo
julia> parsetagselector("@foo")

julia> # Will match any feature/scenario without the tag @bar
julia> parsetagselector("not @bar")
```
"""
function parsetagselector(s::String) :: TagSelector
    TagSelector(parsetagexpression(s))
end

"""
NewTagSelector is used to select a feature or scenario based on its tags.
"""
struct NewTagSelector
    expression::TagExpression
end

"""
    newparsetagselector(s::String) :: NewTagSelector

"""
function newparsetagselector(s::String) :: NewTagSelector
    input = TagExpressionInput(s)
    parser = AnyTagExpression()
    # TODO For now expect success all the time, until I have
    # tests for failure during parsing.
    result = parser(input)

    NewTagSelector(result.value)
end

function select(ts::NewTagSelector, feature::Feature) :: Feature
    select(ts.expression, feature)
end

"""
    selectscenario(::TagExpression, feature::Feature, scenario::Scenario) :: Boolean

Check if a given scenario ought to be included in the execution. Returns true if that is the case,
false otherwise.
"""
function select(ts::TagExpression, feature::Feature, scenario::Gherkin.AbstractScenario) :: Bool
    tags = vcat(feature.header.tags, scenario.tags)
    matches(ts, tags)
end

"""
    select(::TagExpression, feature::Feature) :: Union{Feature,Nothing}

Filter a feature and its scenarios based on the selected tags.
Returns a feature with zero or more scenarios, or nothing if the feature
and none of the scenarios matched the tag selector.
"""
function select(ts::TagExpression, feature::Feature) :: Feature
    newscenarios = [scenario
                    for scenario in feature.scenarios
                    if select(ts, feature, scenario)]
    Feature(feature, newscenarios)
end

const AllScenarios = TagSelector(All())

##
## Parser combinators for tag expressions
##
## This will soonish replace most of the code above.
##

struct TagExpressionInput
    source::String
    position::Int

    function TagExpressionInput(source::String, position::Int = 1)
        nextnonwhitespace = findnext(c -> c != ' ', source, position)
        newposition = if nextnonwhitespace !== nothing
            nextnonwhitespace
        else
            length(source) + 1
        end
        new(source, newposition)
    end
end

currentchar(input::TagExpressionInput) = (input.source[input.position], TagExpressionInput(input.source, input.position + 1))
iseof(input::TagExpressionInput) = input.position > length(input.source)

abstract type ParseResult{T} end

struct OKParseResult{T} <: ParseResult{T}
    value::T
    newinput::TagExpressionInput
end

struct BadParseResult{T} <: ParseResult{T}
    newinput::TagExpressionInput
end

abstract type TagExpressionParser{T} end

"""
    AnyTagExpression()

Consumes any type of tag expression. The actual parser constructor is defined further down below,
after all expression types have been defined.
"""
struct AnyTagExpression <: TagExpressionParser{TagExpression} end

"""
    Repeating(::TagExpressionParser)

Repeat a given parser while it succeeds.
"""
struct Repeating{T} <: TagExpressionParser{Vector{T}}
    inner::TagExpressionParser{T}
end

function (parser::Repeating{T})(input::TagExpressionInput) :: ParseResult{Vector{T}} where {T}
    result = Vector{T}()
    currentinput = input

    while true
        innerresult = parser.inner(currentinput)
        if innerresult isa BadParseResult{T}
            break
        end
        push!(result, innerresult.value)
        currentinput = innerresult.newinput
    end

    OKParseResult{Vector{T}}(result, currentinput)
end

"""
    Transforming(::TagExpressionParser, f::Function)

Transforms an OK parse result using a provided function
"""
struct Transforming{S, T} <: TagExpressionParser{T}
    inner::TagExpressionParser{S}
    f::Function
end

function (parser::Transforming{S, T})(input::TagExpressionInput) :: ParseResult{T}  where {S, T}
    result = parser.inner(input)
    if result isa OKParseResult{S}
        OKParseResult{T}(parser.f(result.value), result.newinput)
    else
        BadParseResult{T}(input)
    end
end

struct TakeUntil <: TagExpressionParser{String}
    anyof::String
end
function (parser::TakeUntil)(input::TagExpressionInput) :: ParseResult{String}
    delimiterindex = findnext(c -> contains(parser.anyof, c), input.source, input.position)
    lastindex = if delimiterindex !== nothing
        delimiterindex - 1
    else
        length(input.source)
    end
    s = input.source[input.position:lastindex]
    OKParseResult{String}(s, TagExpressionInput(input.source, lastindex + 1))
end

SingleTagParser() = Transforming{Vector{String}, Tag}(
    SequenceParser{String}(
        Literal("@"),
        TakeUntil("() "),
    ),
    s -> Tag(join(s)))

"""
    SequenceParser{T}(parsers...)

Consumes a sequence of other parsers.
"""
struct SequenceParser{T} <: TagExpressionParser{Vector{T}}
    inner::Vector{TagExpressionParser{<:T}}

    SequenceParser{T}(parsers...) where {T} = new(collect(parsers))
end

function (parser::SequenceParser{T})(input::TagExpressionInput) :: ParseResult{Vector{T}} where {T}
    values = Vector{T}()
    currentinput = input

    for p in parser.inner
        result = p(currentinput)

        if result isa BadParseResult
            return BadParseResult{Vector{T}}(input)
        end
        push!(values, result.value)
        currentinput = result.newinput
    end

    OKParseResult{Vector{T}}(values, currentinput)
end

"""
    Literal(::String)

Consumes an exact literal string.
"""
struct Literal <: TagExpressionParser{String}
    value::String
end

function (parser::Literal)(input::TagExpressionInput) :: ParseResult{String}
    n = length(parser.value)
    endposition = min(input.position + n - 1, length(input.source))
    actual = input.source[input.position:endposition]
    if parser.value == actual
        OKParseResult{String}(actual, TagExpressionInput(input.source, endposition + 1))
    else
        BadParseResult{String}(input)
    end
end

const NotBits = Union{String, TagExpression}
"""
    NotTagParser()

Consumes a logical not of some tag expression.
"""
NotTagParser() = Transforming{Vector{NotBits}, Not}(
    SequenceParser{NotBits}(
        Literal("not"),
        AnyTagExpression()
    ),
    xs -> Not(xs[2])
)

const OrBits = Union{String, TagExpression}
"""
    OrParser()

Consumes a logical or expression.
"""
OrParser() = Transforming{Vector{OrBits}, OrResult}(
    SequenceParser{OrBits}(
        Literal("or"),
        SingleTagParser()
    ),
    xs -> OrResult(xs[2])
)

# TODO Create And expression parser

const ParenthesesBits = Union{String, TagExpression}
"""
    ParenthesesParser()

Consumes a tag expression in parentheses.
"""
ParenthesesParser() = Transforming{Vector{ParenthesesBits}, Parentheses}(
    SequenceParser{ParenthesesBits}(
        Literal("("),
        AnyTagExpression(),
        Literal(")")
    ),
    xs -> Parentheses(xs[2])
)

"""
    AnyOfParser(parsers...)

Consume any of the supplied parsers.
"""
struct AnyOfParser <: TagExpressionParser{TagExpression}
    parsers::Vector{TagExpressionParser{<:TagExpression}}

    AnyOfParser(parsers...) = new(collect(parsers))
end

function (parser::AnyOfParser)(input::TagExpressionInput) :: ParseResult{TagExpression}
    results = Vector{OKParseResult{<:TagExpression}}()

    for p in parser.parsers
        result = p(input)
        if result isa OKParseResult
            push!(results, result)
        end
    end

    if isempty(results)
        BadParseResult{TagExpression}(input)
    else
        # Return the longest successful parse
        resultlength = result -> result.newinput.position - input.position
        maxresultlength = maximum(resultlength, results)
        maxresultindex = findfirst(result -> resultlength(result) == maxresultlength, results)
        maxresult = results[maxresultindex]
        OKParseResult{TagExpression}(maxresult.value, maxresult.newinput)
    end
end

"""
    NothingParser()

Consumes nothing and always succeeds.
"""
struct NothingParser <: TagExpressionParser{TagExpression} end

function (parser::NothingParser)(input::TagExpressionInput) :: ParseResult{TagExpression}
    OKParseResult{TagExpression}(NothingExpression(), input)
end

#
# The AnyTagExpression constructor is defined here at the bottom, where it
# can find all expression types.
#

const StartExprParser = AnyOfParser(
    ParenthesesParser(),
    NotTagParser(),
    SingleTagParser()
)

const EndExprParser = AnyOfParser(
    OrParser(),
    SingleTagParser(),
    NothingParser(),
)

function combineResult(a::TagExpression, other::OrResult) :: TagExpression
    Or(a, other.b)
end

function combineResult(a::TagExpression, ::NothingExpression) :: TagExpression
    a
end

function (::AnyTagExpression)(input::TagExpressionInput) :: ParseResult{TagExpression}
    combineStartAndEnd = (vs) -> combineResult(vs...)
    inner = Transforming{Vector{TagExpression}, TagExpression}(
        SequenceParser{TagExpression}(
            StartExprParser,
            EndExprParser,
        ),
        combineStartAndEnd
    )
    inner(input)
end

end