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

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

    function CoreDatabaseManager_Contains_Req(; kwargs...)
        obj = new(meta(CoreDatabaseManager_Contains_Req), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabaseManager_Contains_Req
const __meta_CoreDatabaseManager_Contains_Req = Ref{ProtoMeta}()
function meta(::Type{CoreDatabaseManager_Contains_Req})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabaseManager_Contains_Req)
            __meta_CoreDatabaseManager_Contains_Req[] = target = ProtoMeta(CoreDatabaseManager_Contains_Req)
            allflds = Pair{Symbol,Union{Type,String}}[:name => AbstractString]
            meta(target, CoreDatabaseManager_Contains_Req, 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_CoreDatabaseManager_Contains_Req[]
    end
end
function Base.getproperty(obj::CoreDatabaseManager_Contains_Req, name::Symbol)
    if name === :name
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    else
        getfield(obj, name)
    end
end

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

    function CoreDatabaseManager_Contains_Res(; kwargs...)
        obj = new(meta(CoreDatabaseManager_Contains_Res), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabaseManager_Contains_Res
const __meta_CoreDatabaseManager_Contains_Res = Ref{ProtoMeta}()
function meta(::Type{CoreDatabaseManager_Contains_Res})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabaseManager_Contains_Res)
            __meta_CoreDatabaseManager_Contains_Res[] = target = ProtoMeta(CoreDatabaseManager_Contains_Res)
            allflds = Pair{Symbol,Union{Type,String}}[:contains => Bool]
            meta(target, CoreDatabaseManager_Contains_Res, 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_CoreDatabaseManager_Contains_Res[]
    end
end
function Base.getproperty(obj::CoreDatabaseManager_Contains_Res, name::Symbol)
    if name === :contains
        return (obj.__protobuf_jl_internal_values[name])::Bool
    else
        getfield(obj, name)
    end
end

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

    function CoreDatabaseManager_Contains(; kwargs...)
        obj = new(meta(CoreDatabaseManager_Contains), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabaseManager_Contains
const __meta_CoreDatabaseManager_Contains = Ref{ProtoMeta}()
function meta(::Type{CoreDatabaseManager_Contains})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabaseManager_Contains)
            __meta_CoreDatabaseManager_Contains[] = target = ProtoMeta(CoreDatabaseManager_Contains)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, CoreDatabaseManager_Contains, 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_CoreDatabaseManager_Contains[]
    end
end

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

    function CoreDatabaseManager_Create_Req(; kwargs...)
        obj = new(meta(CoreDatabaseManager_Create_Req), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabaseManager_Create_Req
const __meta_CoreDatabaseManager_Create_Req = Ref{ProtoMeta}()
function meta(::Type{CoreDatabaseManager_Create_Req})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabaseManager_Create_Req)
            __meta_CoreDatabaseManager_Create_Req[] = target = ProtoMeta(CoreDatabaseManager_Create_Req)
            allflds = Pair{Symbol,Union{Type,String}}[:name => AbstractString]
            meta(target, CoreDatabaseManager_Create_Req, 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_CoreDatabaseManager_Create_Req[]
    end
end
function Base.getproperty(obj::CoreDatabaseManager_Create_Req, name::Symbol)
    if name === :name
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    else
        getfield(obj, name)
    end
end

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

    function CoreDatabaseManager_Create_Res(; kwargs...)
        obj = new(meta(CoreDatabaseManager_Create_Res), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabaseManager_Create_Res
const __meta_CoreDatabaseManager_Create_Res = Ref{ProtoMeta}()
function meta(::Type{CoreDatabaseManager_Create_Res})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabaseManager_Create_Res)
            __meta_CoreDatabaseManager_Create_Res[] = target = ProtoMeta(CoreDatabaseManager_Create_Res)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, CoreDatabaseManager_Create_Res, 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_CoreDatabaseManager_Create_Res[]
    end
end

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

    function CoreDatabaseManager_Create(; kwargs...)
        obj = new(meta(CoreDatabaseManager_Create), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabaseManager_Create
const __meta_CoreDatabaseManager_Create = Ref{ProtoMeta}()
function meta(::Type{CoreDatabaseManager_Create})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabaseManager_Create)
            __meta_CoreDatabaseManager_Create[] = target = ProtoMeta(CoreDatabaseManager_Create)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, CoreDatabaseManager_Create, 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_CoreDatabaseManager_Create[]
    end
end

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

    function CoreDatabaseManager_All_Req(; kwargs...)
        obj = new(meta(CoreDatabaseManager_All_Req), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabaseManager_All_Req
const __meta_CoreDatabaseManager_All_Req = Ref{ProtoMeta}()
function meta(::Type{CoreDatabaseManager_All_Req})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabaseManager_All_Req)
            __meta_CoreDatabaseManager_All_Req[] = target = ProtoMeta(CoreDatabaseManager_All_Req)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, CoreDatabaseManager_All_Req, 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_CoreDatabaseManager_All_Req[]
    end
end

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

    function CoreDatabaseManager_All_Res(; kwargs...)
        obj = new(meta(CoreDatabaseManager_All_Res), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabaseManager_All_Res
const __meta_CoreDatabaseManager_All_Res = Ref{ProtoMeta}()
function meta(::Type{CoreDatabaseManager_All_Res})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabaseManager_All_Res)
            __meta_CoreDatabaseManager_All_Res[] = target = ProtoMeta(CoreDatabaseManager_All_Res)
            allflds = Pair{Symbol,Union{Type,String}}[:names => Base.Vector{AbstractString}]
            meta(target, CoreDatabaseManager_All_Res, 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_CoreDatabaseManager_All_Res[]
    end
end
function Base.getproperty(obj::CoreDatabaseManager_All_Res, name::Symbol)
    if name === :names
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{AbstractString}
    else
        getfield(obj, name)
    end
end

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

    function CoreDatabaseManager_All(; kwargs...)
        obj = new(meta(CoreDatabaseManager_All), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabaseManager_All
const __meta_CoreDatabaseManager_All = Ref{ProtoMeta}()
function meta(::Type{CoreDatabaseManager_All})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabaseManager_All)
            __meta_CoreDatabaseManager_All[] = target = ProtoMeta(CoreDatabaseManager_All)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, CoreDatabaseManager_All, 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_CoreDatabaseManager_All[]
    end
end

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

    function CoreDatabaseManager(; kwargs...)
        obj = new(meta(CoreDatabaseManager), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabaseManager
const __meta_CoreDatabaseManager = Ref{ProtoMeta}()
function meta(::Type{CoreDatabaseManager})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabaseManager)
            __meta_CoreDatabaseManager[] = target = ProtoMeta(CoreDatabaseManager)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, CoreDatabaseManager, 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_CoreDatabaseManager[]
    end
end

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

    function CoreDatabase_Schema_Req(; kwargs...)
        obj = new(meta(CoreDatabase_Schema_Req), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabase_Schema_Req
const __meta_CoreDatabase_Schema_Req = Ref{ProtoMeta}()
function meta(::Type{CoreDatabase_Schema_Req})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabase_Schema_Req)
            __meta_CoreDatabase_Schema_Req[] = target = ProtoMeta(CoreDatabase_Schema_Req)
            allflds = Pair{Symbol,Union{Type,String}}[:name => AbstractString]
            meta(target, CoreDatabase_Schema_Req, 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_CoreDatabase_Schema_Req[]
    end
end
function Base.getproperty(obj::CoreDatabase_Schema_Req, name::Symbol)
    if name === :name
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    else
        getfield(obj, name)
    end
end

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

    function CoreDatabase_Schema_Res(; kwargs...)
        obj = new(meta(CoreDatabase_Schema_Res), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabase_Schema_Res
const __meta_CoreDatabase_Schema_Res = Ref{ProtoMeta}()
function meta(::Type{CoreDatabase_Schema_Res})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabase_Schema_Res)
            __meta_CoreDatabase_Schema_Res[] = target = ProtoMeta(CoreDatabase_Schema_Res)
            allflds = Pair{Symbol,Union{Type,String}}[:schema => AbstractString]
            meta(target, CoreDatabase_Schema_Res, 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_CoreDatabase_Schema_Res[]
    end
end
function Base.getproperty(obj::CoreDatabase_Schema_Res, name::Symbol)
    if name === :schema
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    else
        getfield(obj, name)
    end
end

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

    function CoreDatabase_Schema(; kwargs...)
        obj = new(meta(CoreDatabase_Schema), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabase_Schema
const __meta_CoreDatabase_Schema = Ref{ProtoMeta}()
function meta(::Type{CoreDatabase_Schema})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabase_Schema)
            __meta_CoreDatabase_Schema[] = target = ProtoMeta(CoreDatabase_Schema)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, CoreDatabase_Schema, 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_CoreDatabase_Schema[]
    end
end

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

    function CoreDatabase_Delete_Req(; kwargs...)
        obj = new(meta(CoreDatabase_Delete_Req), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabase_Delete_Req
const __meta_CoreDatabase_Delete_Req = Ref{ProtoMeta}()
function meta(::Type{CoreDatabase_Delete_Req})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabase_Delete_Req)
            __meta_CoreDatabase_Delete_Req[] = target = ProtoMeta(CoreDatabase_Delete_Req)
            allflds = Pair{Symbol,Union{Type,String}}[:name => AbstractString]
            meta(target, CoreDatabase_Delete_Req, 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_CoreDatabase_Delete_Req[]
    end
end
function Base.getproperty(obj::CoreDatabase_Delete_Req, name::Symbol)
    if name === :name
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    else
        getfield(obj, name)
    end
end

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

    function CoreDatabase_Delete_Res(; kwargs...)
        obj = new(meta(CoreDatabase_Delete_Res), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabase_Delete_Res
const __meta_CoreDatabase_Delete_Res = Ref{ProtoMeta}()
function meta(::Type{CoreDatabase_Delete_Res})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabase_Delete_Res)
            __meta_CoreDatabase_Delete_Res[] = target = ProtoMeta(CoreDatabase_Delete_Res)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, CoreDatabase_Delete_Res, 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_CoreDatabase_Delete_Res[]
    end
end

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

    function CoreDatabase_Delete(; kwargs...)
        obj = new(meta(CoreDatabase_Delete), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabase_Delete
const __meta_CoreDatabase_Delete = Ref{ProtoMeta}()
function meta(::Type{CoreDatabase_Delete})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabase_Delete)
            __meta_CoreDatabase_Delete[] = target = ProtoMeta(CoreDatabase_Delete)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, CoreDatabase_Delete, 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_CoreDatabase_Delete[]
    end
end

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

    function CoreDatabase(; kwargs...)
        obj = new(meta(CoreDatabase), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct CoreDatabase
const __meta_CoreDatabase = Ref{ProtoMeta}()
function meta(::Type{CoreDatabase})
    ProtoBuf.metalock() do
        if !isassigned(__meta_CoreDatabase)
            __meta_CoreDatabase[] = target = ProtoMeta(CoreDatabase)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, CoreDatabase, 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_CoreDatabase[]
    end
end

export CoreDatabaseManager_Contains_Req, CoreDatabaseManager_Contains_Res, CoreDatabaseManager_Contains, CoreDatabaseManager_Create_Req, CoreDatabaseManager_Create_Res, CoreDatabaseManager_Create, CoreDatabaseManager_All_Req, CoreDatabaseManager_All_Res, CoreDatabaseManager_All, CoreDatabaseManager, CoreDatabase_Schema_Req, CoreDatabase_Schema_Res, CoreDatabase_Schema, CoreDatabase_Delete_Req, CoreDatabase_Delete_Res, CoreDatabase_Delete, CoreDatabase


text:
#=
# 3. Applying pulse forcing to a flow
Here, we will show how to apply a transient force (a 'pulse') to a flow.
=#

using ViscousFlow
#-
using Plots

#=
For this case, we first seek to introduce a pulse to an otherwise quiescent fluid,
with no boundaries. The pulse shape will be a smooth dipole, directed upward.

We will start with the usual steps: specify the problem parameters and the discretization.
=#

Re = 200
xlim, ylim = (-2,2), (-2,4)
Δx,Δt = setstepsizes(Re,gridRe=4)

#=
### Construct the pulse
Now create the pulse. For the spatial shape of this pulse, we make use of a Gaussian
field, differentiated once in the `x` direction. We will center it at (0,0), and
give it a strength of 10.
=#
σx = 0.5
σy = 0.1
gauss = SpatialGaussian(σx,σy,0,0,10,deriv=1);

#=
Now we now 'shape' the pulse in time, also with a Gaussian. We center it at `t = 0.1`
with a half-width in time equal to 0.1.
=#
t0 = 0.1
σt = 0.1
pparams = PulseParams(gauss,t0,σt);

#=
### Construct the system structure
We supply these pulse characteristics with the keyword argument `pulses` as we
set up the usual system structure:
=#
sys = NavierStokes(Re,Δx,xlim,ylim,Δt,pulses=pparams)

#=
The remaining steps go just as they did for the previous examples. We will simulate
the pulse for 5 time units and make an animation of the results:
=#
u0 = newstate(sys)
tspan = (0.0,10.0) # longer than we need, but just being safe
integrator = init(u0,tspan,sys)
#-
step!(integrator,5.0)

#=
### Examine
=#
sol = integrator.sol
@gif for t in sol.t
    plot(vorticity(sol,sys,t),sys)
end every 5
#-
plot(streamfunction(integrator),sys,title="Streamfunction at t = $(round(integrator.t,digits=2))")

#=
We can also supply more than one pulse. Let's give 3, each separated by 1 time unit.
=#
pparams = [PulseParams(gauss,0.1,0.1), PulseParams(gauss,1.1,0.1), PulseParams(gauss,2.1,0.1)];
#-
sys = NavierStokes(Re,Δx,xlim,ylim,Δt,pulses=pparams)
#-
u0 = newstate(sys)
tspan = (0.0,10.0)
integrator = init(u0,tspan,sys)
#-
step!(integrator,4.0)
#=
### Examine
=#
sol = integrator.sol
@gif for t in sol.t
    plot(vorticity(sol,sys,t),sys)
end every 5

ext: jl


text:
using Test

using eQuilibrator
using Measurements
using Unitful

eq = eQuilibrator.Equilibrator()

@testset "eQuilibrator tests" begin

    @testset "equilibrator_type" begin
        # test getters and setters
        set_temperature(eq, 310u"K")
        @test get_temperature(eq) == 310u"K"

        set_ionic_strength(eq, 0.22u"M")
        @test get_ionic_strength(eq) == 0.22u"M"

        set_pH(eq, 7.9)
        @test get_pH(eq) == 7.9

        set_pMg(eq, 2.0)
        @test get_pMg(eq) == 2.0

        # test rest
        reset_equilibrator(eq)
        @test get_temperature(eq) == 298.15u"K"
        @test get_pH(eq) == 7.5
        @test get_pMg(eq) == 3.0
        @test get_ionic_strength(eq) == 0.25u"M"
    end

    @testset "utils" begin
        @test eQuilibrator._parse_units("kilojoule") == "kJ"
        r_str = "atp + h2o = adp + pi"

        @test bigg(r_str) ==
              "bigg.metabolite:atp + bigg.metabolite:h2o = bigg.metabolite:adp + bigg.metabolite:pi"
        @test kegg(r_str) == "kegg:atp + kegg:h2o = kegg:adp + kegg:pi"
        @test metanetx(r_str) ==
              "metanetx.chemical:atp + metanetx.chemical:h2o = metanetx.chemical:adp + metanetx.chemical:pi"
        @test chebi(r_str) == "CHEBI:atp + CHEBI:h2o = CHEBI:adp + CHEBI:pi"
    end

    @testset "univariate_reaction" begin
        # set to values in code examples
        set_temperature(eq, 298.15u"K")
        set_ionic_strength(eq, 0.25u"M")
        set_pH(eq, 7.4)
        set_pMg(eq, 3.0)
        r_str = "atp + h2o = adp + pi"

        ΔGstd = ustrip(u"kJ/mol", standard_dg_prime(eq, bigg(r_str)))
        @test ΔGstd.val ≈ -29.14 atol = 0.01
        @test ΔGstd.err ≈ 0.3 atol = 0.01

        ΔGphys = ustrip(u"kJ/mol", physiological_dg_prime(eq, bigg(r_str)))
        @test ΔGphys.val ≈ -46.26 atol = 0.01
        @test ΔGphys.err ≈ 0.3 atol = 0.01

        concentrations =
            Dict(bigg("atp") => 1u"mM", bigg("adp") => 100u"μM", bigg("pi") => 0.003u"M")

        ΔGprime =
            ustrip(u"kJ/mol", dg_prime(eq, bigg(r_str); concentrations = concentrations))
        @test ΔGprime.val ≈ -49.24 atol = 0.01
        @test ΔGprime.err ≈ 0.3 atol = 0.01

        rev_ind = ln_reversibility_index(eq, bigg(r_str))
        @test rev_ind.val ≈ -12.45 atol = 0.01
        @test rev_ind.err ≈ 0.08 atol = 0.01

        # test non-trivial reaction stoichiometry parsing
        rubisco = "rb15bp + co2 + h2o = 2 3pg"
        ΔGprime = ustrip(u"kJ/mol", standard_dg_prime(eq, bigg(rubisco)))
        @test ΔGprime.val ≈ -30.85 atol = 0.01

        # using a mixed reaction string
        mixed = "bigg.metabolite:atp + CHEBI:15377 = metanetx.chemical:MNXM7 + bigg.metabolite:pi"
        ΔGprime = ustrip(u"kJ/mol", standard_dg_prime(eq, mixed))
        @test ΔGprime.val ≈ -29.14 atol = 0.01
    end

    @testset "multivariate_reaction" begin
        ntp3 = "gtp + h2o = gdp + pi"
        adk3 = "adp + gdp = amp + gtp"

        μ, Q = standard_dg_prime_multi(
            eq,
            bigg.([ntp3, adk3]);
            uncertainty_representation = "fullrank",
        )

        @test ustrip(u"kJ/mol", μ[1]) ≈ -26.458180516735318 atol = 1e-4
        @test ustrip(u"kJ/mol", μ[2]) ≈ -2.9528792110924087 atol = 1e-4

        @test ustrip(u"kJ/mol", Q[1, 1]) ≈ -1.3542171841954138 atol = 1e-4
        @test ustrip(u"kJ/mol", Q[1, 2]) ≈ 0.0 atol = 1e-4
        @test ustrip(u"kJ/mol", Q[2, 1]) ≈ 1.2988666075161392 atol = 1e-4
        @test ustrip(u"kJ/mol", Q[2, 2]) ≈ -0.3082907615275239 atol = 1e-4
    end

    @testset "multicompartment_reaction" begin
        cyto_rxn = bigg("adp + pi = 4 h + h2o + atp")
        peri_rxn = bigg("4 h =")

        ψ = -0.17u"V"
        peri_ionic = 0.20u"M"
        peri_pMg = 3.0
        peri_pH = 7.0

        set_ionic_strength(eq, 250u"mM")
        set_pH(eq, 7.4)
        set_pMg(eq, 3.0)

        dg = multi_compartmental_standard_dg_prime(
            eq,
            cyto_rxn,
            peri_rxn;
            potential_difference = ψ,
            pH_outer = peri_pH,
            pMg_outer = peri_pMg,
            ionic_strength_outer = peri_ionic,
        )

        @test ustrip(u"kJ/mol", dg).val ≈ -45.59324113925093 atol = 1e-4
        @test ustrip(u"kJ/mol", dg).err ≈ 0.30427785529910256 atol = 1e-4
    end

    @testset "formation" begin
        mets = bigg.(["atp", "adp", "amp", "pi", "h2o"])

        set_temperature(eq, 298.15u"K")
        set_ionic_strength(eq, 0.25u"M")
        set_pH(eq, 7.4)
        set_pMg(eq, 3.0)

        standard_dgf_prime_mu, standard_dgf_cov = standard_dg_formation(eq, mets)

        @test ustrip(u"kJ/mol", standard_dgf_prime_mu[1]) ≈ -2270.4800916865584 atol = 1e-4
        @test ustrip(u"kJ/mol", standard_dgf_prime_mu[2]) ≈ -1395.6292467273274 atol = 1e-4
        @test ustrip(u"kJ/mol", standard_dgf_prime_mu[3]) ≈ -521.0449892833246 atol = 1e-4
        @test ustrip(u"kJ/mol", standard_dgf_prime_mu[4]) ≈ -1056.0794480718703 atol = 1e-4
        @test ustrip(u"kJ/mol", standard_dgf_prime_mu[5]) ≈ -152.0841309000395 atol = 1e-4

        @test ustrip(u"kJ/mol", standard_dgf_cov[1, 1]) ≈ 2.220056919789737 atol = 1e-4
        @test ustrip(u"kJ/mol", standard_dgf_cov[3, 3]) ≈ 1.4330175346264344 atol = 1e-4
        @test ustrip(u"kJ/mol", standard_dgf_cov[2, 1]) ≈ 1.695559565984625 atol = 1e-4
        @test ustrip(u"kJ/mol", standard_dgf_cov[3, 5]) ≈ 0.06507547358365794 atol = 1e-4
    end
end


text:
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md

""" Elasticity equations.

Field equation is:

    m∂²u/∂t² = ∇⋅σ - b

Weak form is: find u∈U such that ∀v in V

    δW := ∫ρ₀∂²u/∂t²⋅δu dV₀ + ∫S:δE dV₀ - ∫b₀⋅δu dV₀ - ∫t₀⋅δu dA₀ = 0

where

    ρ₀ = density
    b₀ = displacement load
    t₀ = displacement traction

Formulations
------------
plane stress, plane strain, 3D

References
----------

https://en.wikipedia.org/wiki/Linear_elasticity
https://en.wikipedia.org/wiki/Finite_strain_theory
https://en.wikipedia.org/wiki/Stress_measures
https://en.wikipedia.org/wiki/Mooney%E2%80%93Rivlin_solid
https://en.wikipedia.org/wiki/Strain_energy_density_function
https://en.wikipedia.org/wiki/Plane_stress
https://en.wikipedia.org/wiki/Hooke's_law

"""
type Elasticity <: FieldProblem
    # these are found from problem.properties for type Problem{Elasticity}
    formulation :: Symbol
    finite_strain :: Bool
    geometric_stiffness :: Bool
    store_fields :: Vector{Symbol}
end
function Elasticity()
    # formulations: plane_stress, plane_strain, continuum
    return Elasticity(:continuum, false, false, [])
end

function get_unknown_field_name(problem::Problem{Elasticity})
    return "displacement"
end

function get_formulation_type(problem::Problem{Elasticity})
    return :incremental
end

function assemble!(assembly::Assembly, problem::Problem{Elasticity}, element::Element, time=0.0)
    props = problem.properties
    gdofs = get_gdofs(problem, element)
    formulation = props.formulation
    if formulation in [:plane_stress, :plane_strain]
        formulation = :plane
    end
    Km, Kg, f = assemble(problem, element, time, Val{formulation})
    add!(assembly.K, gdofs, gdofs, Km)
    add!(assembly.Kg, gdofs, gdofs, Kg)
    add!(assembly.f, gdofs, f)
end

typealias Elasticity2DSurfaceElements Union{Poi1, Seg2, Seg3}
typealias Elasticity2DVolumeElements Union{Tri3, Tri6, Quad4, Quad8, Quad9}
typealias Elasticity3DSurfaceElements Union{Poi1, Tri3, Tri6, Quad4, Quad8, Quad9}
typealias Elasticity3DVolumeElements Union{Tet4, Wedge6, Hex8, Tet10, Hex20, Hex27}

""" Elasticity equations for 2d cases. """
function assemble{El<:Elasticity2DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time, ::Type{Val{:plane}})

    props = problem.properties
    dim = get_unknown_field_dimension(problem)
    nnodes = length(element)
    BL = zeros(3, dim*nnodes)
    BNL = zeros(4, dim*nnodes)
    Km = zeros(dim*nnodes, dim*nnodes)
    Kg = zeros(dim*nnodes, dim*nnodes)
    f = zeros(dim*nnodes)

    for ip in get_integration_points(element)

        detJ = element(ip, time, Val{:detJ})
        w = ip.weight*detJ
        N = element(ip, time)
        dN = element(ip, time, Val{:Grad})

        # kinematics

        gradu = element("displacement", ip, time, Val{:Grad})
        fill!(BL, 0.0)

        if props.finite_strain
            strain = 1/2*(gradu + gradu' + gradu'*gradu)
            F = eye(dim) + gradu
            for i=1:size(dN, 2)
                BL[1, 2*(i-1)+1] += F[1,1]*dN[1,i]
                BL[1, 2*(i-1)+2] += F[2,1]*dN[1,i]
                BL[2, 2*(i-1)+1] += F[1,2]*dN[2,i]
                BL[2, 2*(i-1)+2] += F[2,2]*dN[2,i]
                BL[3, 2*(i-1)+1] += F[1,1]*dN[2,i] + F[1,2]*dN[1,i]
                BL[3, 2*(i-1)+2] += F[2,1]*dN[2,i] + F[2,2]*dN[1,i]
            end
        else # linearized strain
            strain = 1/2*(gradu + gradu')
            F = eye(dim)
            for i=1:size(dN, 2)
                BL[1, 2*(i-1)+1] = dN[1,i]
                BL[2, 2*(i-1)+2] = dN[2,i]
                BL[3, 2*(i-1)+1] = dN[2,i]
                BL[3, 2*(i-1)+2] = dN[1,i]
            end
        end

        strain_vec = [strain[1,1]; strain[2,2]; strain[1,2]]

        # calculate stress
        E = element("youngs modulus", ip, time)
        nu = element("poissons ratio", ip, time)
        if props.formulation == :plane_stress
            D = E/(1.0 - nu^2) .* [
                1.0  nu 0.0
                nu  1.0 0.0
                0.0 0.0 (1.0-nu)/2.0]
        elseif props.formulation == :plane_strain
            D = E/((1+nu)*(1-2*nu)) .* [
                1-nu   nu 0
                nu   1-nu 0
                0    0    (1-2*nu)/2]
        else
            error("unknown plane formulation: $(props.formulation)")
        end
        # calculate stress
        stress_vec = D * ([1.0, 1.0, 2.0] .* strain_vec)

        :strain in props.store_fields && update!(ip, "strain", time => strain_vec)
        :stress in props.store_fields && update!(ip, "stress", time => stress_vec)
        :stress11 in props.store_fields && update!(ip, "stress11", time => stress_vec[1])
        :stress22 in props.store_fields && update!(ip, "stress22", time => stress_vec[2])
        :stress12 in props.store_fields && update!(ip, "stress12", time => stress_vec[3])

        Km += w*BL'*D*BL

        # stress = [stress_vec[1] stress_vec[3]; stress_vec[3] stress_vec[2]]
        # cauchy_stress = F'*stress*F/det(F)
        # cauchy_stress = [cauchy_stress[1,1]; cauchy_stress[2,2]; cauchy_stress[1,2]]
        # update!(ip, "cauchy stress", time => cauchy_stress)

        # material stiffness end

        if props.geometric_stiffness
            # take geometric stiffness into account

            fill!(BNL, 0.0)
            for i=1:size(dN, 2)
                BNL[1, 2*(i-1)+1] = dN[1,i]
                BNL[2, 2*(i-1)+1] = dN[2,i]
                BNL[3, 2*(i-1)+2] = dN[1,i]
                BNL[4, 2*(i-1)+2] = dN[2,i]
            end

            S2 = zeros(2*dim, 2*dim)
            S2[1,1] = stress_vec[1]
            S2[2,2] = stress_vec[2]
            S2[1,2] = S2[2,1] = stress_vec[3]
            S2[3:4,3:4] = S2[1:2,1:2]

            Kg += w*BNL'*S2*BNL # geometric stiffness

        end

        # rhs, internal and external load

        f -= w*BL'*stress_vec

        if haskey(element, "displacement load")
            b = element("displacement load", ip, time)
            f += w*vec(b*N)
        end

        for i=1:dim
            if haskey(element, "displacement load $i")
                b = element("displacement load $i", ip, time)
                f[i:dim:end] += w*vec(b*N)
            end
        end

    end

    return Km, Kg, f
end

function assemble{El<:Elasticity2DSurfaceElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:plane}})

    props = problem.properties
    dim = get_unknown_field_dimension(problem)
    nnodes = length(element)
    Km = zeros(dim*nnodes, dim*nnodes)
    Kg = zeros(dim*nnodes, dim*nnodes)
    f = zeros(dim*nnodes)

    for ip in get_integration_points(element)

        detJ = element(ip, time, Val{:detJ})
        w = ip.weight*detJ
        N = element(ip, time)

        if haskey(element, "displacement traction force")
            T = element("displacement traction force", ip, time)
            f += w*vec(T*N)
        end

        for i=1:dim
            # traction force for ith component
            if haskey(element, "displacement traction force $i")
                T = element("displacement traction force $i", ip, time)
                f[i:dim:end] += w*vec(T*N)
            end
        end

        if haskey(element, "nt displacement traction force")
            # traction force given in normal-tangential direction
            T = element("nt displacement traction force", ip, time)
            Q = element("normal-tangential coordinates", ip, time)
            f += w*vec(Q'*T*N)
        end

    end

    return Km, Kg, f
end

""" Elasticity equations, 3d, linear. """
function assemble{El<:Elasticity3DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_linear}})

    props = problem.properties
    dim = get_unknown_field_dimension(problem)
    nnodes = length(element)
    ndofs = dim*nnodes
    BL = zeros(6, ndofs)
    Km = zeros(ndofs, ndofs)
    Kg = zeros(ndofs, ndofs)
    f = zeros(ndofs)

    for ip in get_integration_points(element)
        detJ = element(ip, time, Val{:detJ})
        w = ip.weight*detJ
        N = element(ip, time)
        dN = element(ip, time, Val{:Grad})

        fill!(BL, 0.0)
        for i=1:nnodes
            BL[1, 3*(i-1)+1] = dN[1,i]
            BL[2, 3*(i-1)+2] = dN[2,i]
            BL[3, 3*(i-1)+3] = dN[3,i]
            BL[4, 3*(i-1)+1] = dN[2,i]
            BL[4, 3*(i-1)+2] = dN[1,i]
            BL[5, 3*(i-1)+2] = dN[3,i]
            BL[5, 3*(i-1)+3] = dN[2,i]
            BL[6, 3*(i-1)+1] = dN[3,i]
            BL[6, 3*(i-1)+3] = dN[1,i]
        end

        E = element("youngs modulus", ip, time)
        nu = element("poissons ratio", ip, time)

        D = E/((1.0+nu)*(1.0-2.0*nu)) * [
            1.0-nu nu nu 0.0 0.0 0.0
            nu 1.0-nu nu 0.0 0.0 0.0
            nu nu 1.0-nu 0.0 0.0 0.0
            0.0 0.0 0.0 0.5-nu 0.0 0.0
            0.0 0.0 0.0 0.0 0.5-nu 0.0
            0.0 0.0 0.0 0.0 0.0 0.5-nu]

        Km += w*BL'*D*BL

        if haskey(element, "displacement load")
            T = element("displacement load", ip, time)
            f += w*vec(T*N)
        end
        for i=1:dim
            if haskey(element, "displacement load $i")
                b = element("displacement load $i", ip, time)
                f[i:dim:end] += w*vec(b*N)
            end
        end

    end

    if get_formulation_type(problem) == :incremental
        if haskey(element, "displacement")
            u = vec(element["displacement"](time))
            f -= Kt*u
        end
    end

    return Km, Kg, f
end

""" Material and geometric stiffness for linear buckling analysis. """
function assemble{El<:Elasticity3DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_buckling}})

    props = problem.properties
    dim = get_unknown_field_dimension(problem)
    nnodes = length(element)
    ndofs = dim*nnodes
    BL = zeros(6, ndofs)
    BNL = zeros(9, ndofs)
    Km = zeros(ndofs, ndofs)
    Kg = zeros(ndofs, ndofs)
    f = zeros(ndofs)

    for ip in get_integration_points(element)
        detJ = element(ip, time, Val{:detJ})
        w = ip.weight*detJ
        N = element(ip, time)
        dN = element(ip, time, Val{:Grad})

        gradu = element("displacement", ip, time, Val{:Grad})
        strain = 1/2*(gradu' + gradu)

        fill!(BL, 0.0)
        for i=1:nnodes
            BL[1, 3*(i-1)+1] = dN[1,i]
            BL[2, 3*(i-1)+2] = dN[2,i]
            BL[3, 3*(i-1)+3] = dN[3,i]
            BL[4, 3*(i-1)+1] = dN[2,i]
            BL[4, 3*(i-1)+2] = dN[1,i]
            BL[5, 3*(i-1)+2] = dN[3,i]
            BL[5, 3*(i-1)+3] = dN[2,i]
            BL[6, 3*(i-1)+1] = dN[3,i]
            BL[6, 3*(i-1)+3] = dN[1,i]
        end

        fill!(BNL, 0.0)
        for i=1:size(dN, 2)
            BNL[1, 3*(i-1)+1] = dN[1,i]
            BNL[2, 3*(i-1)+1] = dN[2,i]
            BNL[3, 3*(i-1)+1] = dN[3,i]
            BNL[4, 3*(i-1)+2] = dN[1,i]
            BNL[5, 3*(i-1)+2] = dN[2,i]
            BNL[6, 3*(i-1)+2] = dN[3,i]
            BNL[7, 3*(i-1)+3] = dN[1,i]
            BNL[8, 3*(i-1)+3] = dN[2,i]
            BNL[9, 3*(i-1)+3] = dN[3,i]
        end

        E = element("youngs modulus", ip, time)
        nu = element("poissons ratio", ip, time)
        D = E/((1.0+nu)*(1.0-2.0*nu)) * [
            1.0-nu nu nu 0.0 0.0 0.0
            nu 1.0-nu nu 0.0 0.0 0.0
            nu nu 1.0-nu 0.0 0.0 0.0
            0.0 0.0 0.0 0.5-nu 0.0 0.0
            0.0 0.0 0.0 0.0 0.5-nu 0.0
            0.0 0.0 0.0 0.0 0.0 0.5-nu]

        strain_vec = [strain[1,1]; strain[2,2]; strain[3,3]; strain[1,2]; strain[2,3]; strain[1,3]]
        stress_vec = D * ([1.0, 1.0, 1.0, 2.0, 2.0, 2.0].*strain_vec)

        S3 = zeros(3*dim, 3*dim)
        S3[1,1] = stress_vec[1]
        S3[2,2] = stress_vec[2]
        S3[3,3] = stress_vec[3]
        S3[1,2] = S3[2,1] = stress_vec[4]
        S3[2,3] = S3[3,2] = stress_vec[5]
        S3[1,3] = S3[3,1] = stress_vec[6]
        S3[4:6,4:6] = S3[7:9,7:9] = S3[1:3,1:3]

        Km += w*BL'*D*BL
        Kg += w*BNL'*S3*BNL

    end

    return Km, Kg, f
end

""" Elasticity equations, 3d nonlinear. """
function assemble{El<:Elasticity3DVolumeElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum}})

    props = problem.properties
    dim = get_unknown_field_dimension(problem)
    nnodes = length(element)
    ndofs = dim*nnodes
    BL = zeros(6, ndofs)
    BNL = zeros(9, ndofs)
    Km = zeros(ndofs, ndofs)
    Kg = zeros(ndofs, ndofs)
    f = zeros(ndofs)

    for ip in get_integration_points(element)
        detJ = element(ip, time, Val{:detJ})
        w = ip.weight*detJ
        N = element(ip, time)
        dN = element(ip, time, Val{:Grad})

        # kinematics; calculate deformation gradient and strain

        gradu = zeros(dim, dim)
        if haskey(element, "displacement")
            gradu += element("displacement", ip, time, Val{:Grad})
        end
        strain = 1/2*(gradu' + gradu)

        F = eye(dim)
        if props.finite_strain
            F += gradu
            strain += 1/2*gradu'*gradu
        end

        # material stiffness start

        fill!(BL, 0.0)
        for i=1:nnodes
            BL[1, 3*(i-1)+1] = F[1,1]*dN[1,i]
            BL[1, 3*(i-1)+2] = F[2,1]*dN[1,i]
            BL[1, 3*(i-1)+3] = F[3,1]*dN[1,i]
            BL[2, 3*(i-1)+1] = F[1,2]*dN[2,i]
            BL[2, 3*(i-1)+2] = F[2,2]*dN[2,i]
            BL[2, 3*(i-1)+3] = F[3,2]*dN[2,i]
            BL[3, 3*(i-1)+1] = F[1,3]*dN[3,i]
            BL[3, 3*(i-1)+2] = F[2,3]*dN[3,i]
            BL[3, 3*(i-1)+3] = F[3,3]*dN[3,i]
            BL[4, 3*(i-1)+1] = F[1,1]*dN[2,i] + F[1,2]*dN[1,i]
            BL[4, 3*(i-1)+2] = F[2,1]*dN[2,i] + F[2,2]*dN[1,i]
            BL[4, 3*(i-1)+3] = F[3,1]*dN[2,i] + F[3,2]*dN[1,i]
            BL[5, 3*(i-1)+1] = F[1,2]*dN[3,i] + F[1,3]*dN[2,i]
            BL[5, 3*(i-1)+2] = F[2,2]*dN[3,i] + F[2,3]*dN[2,i]
            BL[5, 3*(i-1)+3] = F[3,2]*dN[3,i] + F[3,3]*dN[2,i]
            BL[6, 3*(i-1)+1] = F[1,3]*dN[1,i] + F[1,1]*dN[3,i]
            BL[6, 3*(i-1)+2] = F[2,3]*dN[1,i] + F[2,1]*dN[3,i]
            BL[6, 3*(i-1)+3] = F[3,3]*dN[1,i] + F[3,1]*dN[3,i]
        end

        strain_vec = [strain[1,1]; strain[2,2]; strain[3,3]; strain[1,2]; strain[2,3]; strain[1,3]]

        # calculate stress
        E = element("youngs modulus", ip, time)
        nu = element("poissons ratio", ip, time)
        D = E/((1.0+nu)*(1.0-2.0*nu)) * [
            1.0-nu nu nu 0.0 0.0 0.0
            nu 1.0-nu nu 0.0 0.0 0.0
            nu nu 1.0-nu 0.0 0.0 0.0
            0.0 0.0 0.0 0.5-nu 0.0 0.0
            0.0 0.0 0.0 0.0 0.5-nu 0.0
            0.0 0.0 0.0 0.0 0.0 0.5-nu]
        stress_vec = D * ([1.0, 1.0, 1.0, 2.0, 2.0, 2.0].*strain_vec)

        :strain in props.store_fields && update!(ip, "strain", time => strain_vec)
        :stress in props.store_fields && update!(ip, "stress", time => stress_vec)
        :stress11 in props.store_fields && update!(ip, "stress11", time => stress_vec[1])
        :stress22 in props.store_fields && update!(ip, "stress22", time => stress_vec[2])
        :stress33 in props.store_fields && update!(ip, "stress33", time => stress_vec[3])
        :stress12 in props.store_fields && update!(ip, "stress12", time => stress_vec[4])
        :stress23 in props.store_fields && update!(ip, "stress23", time => stress_vec[5])
        :stress13 in props.store_fields && update!(ip, "stress13", time => stress_vec[6])

        Km += w*BL'*D*BL

        # material stiffness end

        if props.geometric_stiffness
            # take geometric stiffness into account

            fill!(BNL, 0.0)

            for i=1:size(dN, 2)
                BNL[1, 3*(i-1)+1] = dN[1,i]
                BNL[2, 3*(i-1)+1] = dN[2,i]
                BNL[3, 3*(i-1)+1] = dN[3,i]
                BNL[4, 3*(i-1)+2] = dN[1,i]
                BNL[5, 3*(i-1)+2] = dN[2,i]
                BNL[6, 3*(i-1)+2] = dN[3,i]
                BNL[7, 3*(i-1)+3] = dN[1,i]
                BNL[8, 3*(i-1)+3] = dN[2,i]
                BNL[9, 3*(i-1)+3] = dN[3,i]
            end

            S3 = zeros(3*dim, 3*dim)
            S3[1,1] = stress_vec[1]
            S3[2,2] = stress_vec[2]
            S3[3,3] = stress_vec[3]
            S3[1,2] = S3[2,1] = stress_vec[4]
            S3[2,3] = S3[3,2] = stress_vec[5]
            S3[1,3] = S3[3,1] = stress_vec[6]
            S3[4:6,4:6] = S3[7:9,7:9] = S3[1:3,1:3]

            Kg += w*BNL'*S3*BNL

        end

        # external load start

        if haskey(element, "displacement load")
            T = element("displacement load", ip, time)
            f += w*vec(T*N)
        end

        for i=1:dim
            if haskey(element, "displacement load $i")
                b = element("displacement load $i", ip, time)
                f[i:dim:end] += w*vec(b*N)
            end
        end

        # external load end

        if get_formulation_type(problem) == :incremental
            f -= w*BL'*stress_vec
        end

    end

    return Km, Kg, f
end

""" Elasticity equations, surface traction for continuum formulation. """
function assemble{El<:Elasticity3DSurfaceElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum}})

    props = problem.properties
    dim = get_unknown_field_dimension(problem)
    nnodes = size(element, 2)
    Km = zeros(dim*nnodes, dim*nnodes)
    Kg = zeros(dim*nnodes, dim*nnodes)
    f = zeros(dim*nnodes)

    has_concentrated_forces = false
    for ip in get_integration_points(element)
        detJ = element(ip, time, Val{:detJ})
        w = ip.weight*detJ
        N = element(ip, time)
        if haskey(element, "displacement traction force")
            T = element("displacement traction force", ip, time)
            f += w*vec(T*N)
        end
        for i in 1:dim
            if haskey(element, "displacement traction force $i")
                T = element("displacement traction force $i", ip, time)
                f[i:dim:end] += w*vec(T*N)
            end
            if haskey(element, "concentrated force $i")
                has_concentrated_forces = true
                T = element("concentrated force $i", ip, time)
                f[i:dim:end] += w*vec(T*N)
            end
        end
        if haskey(element, "surface pressure")
            J = element(ip, time, Val{:Jacobian})'
            n = cross(J[:,1], J[:,2])
            n /= norm(n)
            # sign convention, positive pressure is towards surface
            p = -element("surface pressure", ip, time)
            f += w*p*vec(n*N)
        end
    end
    if has_concentrated_forces
        update!(element, "concentrated force", time => Any[f])
    end
    return Km, Kg, f
end

function assemble{El<:Elasticity3DSurfaceElements}(problem::Problem{Elasticity}, element::Element{El}, time::Real, ::Type{Val{:continuum_linear}})
    return assemble(problem, element, time, Val{:continuum})
end

""" Elasticity equations using ForwardDiff
"""
function assemble(problem::Problem{Elasticity}, element::Element, time::Real, ::Type{Val{:forwarddiff}})

    dim = get_unknown_field_dimension(problem)
    nnodes = size(element, 2)

    function get_residual_vector(u::Vector)
        u = reshape(u, dim, nnodes)
        u = Field([u[:,i] for i=1:nnodes])
        r = zeros(dim, nnodes)

        for ip in get_integration_points(element)

            JT = transpose(get_jacobian(element, ip, time))
            n, m = size(JT)
            if n == m
                w = ip.weight*det(JT)
            elseif m == 1
                w = ip.weight*norm(JT)
            elseif m == 2
                w = ip.weight*norm(cross(JT[:,1], JT[:,2]))
            else
                error("jacobian $JT")
            end

            # calculate internal forces
            if haskey(element, "youngs modulus") && haskey(element, "poissons ratio")
                grad = element(ip, time, Val{:grad})
                gradu = grad*u

                # kinematics
                F = I + gradu
                E = 1/2*(F'*F - I)

                # material
                young = element("youngs modulus", ip, time)
                poisson = element("poissons ratio", ip, time)
                mu = young/(2*(1+poisson))
                lambda = young*poisson/((1+poisson)*(1-2*poisson))
                if problem.properties.formulation == :plane_stress
                    lambda = 2*lambda*mu/(lambda + 2*mu)  # <- correction for plane stress
                end

                # stress
                S = lambda*trace(E)*I + 2*mu*E

                r += w*F*S*grad
            end

            # calculate external forces - volume load
            if haskey(element, "displacement load")
                basis = element(ip, time)
                b = element("displacement load", ip, time)
                r -= w*b*basis
            end

            # external forces - surface traction force
            if haskey(element, "displacement traction force")
                basis = element(ip, time)
                T = element("displacement traction force", ip, time)
                r -= w*T*basis
            end

        end

        return vec(r)

    end

    field = element("displacement", time)
    Km, allresults = ForwardDiff.jacobian(get_residual_vector, vec(field),
                     AllResults, cache=autodiffcache)
    Kg = zeros(Km)
    f = -ForwardDiff.value(allresults)
    return Km, Kg, f
end

###############################
#     Plastic material        #
###############################
#=
include("vonmises.jl")
abstract PlaneStressLinearElasticPlasticProblem <: LinearElasticityProblem

function PlaneStressLinearElasticPlasticProblem(name="plane stress linear elasticity", dim::Int=2, elements=[])
    return Problem{PlaneStressLinearElasticPlasticProblem}(name, dim, elements)
end

""" Elasticity equations, plane stress. """
function assemble!{E<:CG, P<:PlaneStressLinearElasticPlasticProblem}(assembly::Assembly, problem::Problem{P}, element::Element{E}, time::Real)

    gdofs = get_gdofs(element, problem.dim)
    ndim, nnodes = size(E)
    B = zeros(3, 2*nnodes)
    for ip in get_integration_points(element)
        w = ip.weight
        J = get_jacobian(element, ip, time)
        N = element(ip, time)
        if haskey(element, "youngs modulus") && haskey(element, "poissons ratio")
            nu = element("poissons ratio", ip, time)
            E_ = element("youngs modulus", ip, time)
            C = E_/(1.0 - nu^2) .* [
                1.0  nu 0.0
                nu  1.0 0.0
                0.0 0.0 (1.0-nu)/2.0]
            dN = element(ip, time, Val{:grad})
            fill!(B, 0.0)
            for i=1:size(dN, 2)
                B[1, 2*(i-1)+1] = dN[1,i]
                B[2, 2*(i-1)+2] = dN[2,i]
                B[3, 2*(i-1)+1] = dN[2,i]
                B[3, 2*(i-1)+2] = dN[1,i]
            end
            add!(assembly.stiffness_matrix, gdofs, gdofs, w*B'*C*B*det(J))
        end
        if haskey(element, "displacement load")
            b = element("displacement load", ip, time)
            add!(assembly.force_vector, gdofs, w*N'*b*det(J))
        end
        if haskey(element, "displacement traction force")
            T = element("displacement traction force", ip, time)
            L = w*T*N*norm(J)
            add!(assembly.force_vector, gdofs, vec(L))
        end
    end
end

include("elasticplastic.jl")

# Elasticity problems
abstract ElasticityProblem            <: AbstractProblem
abstract PlaneStressElasticityProblem <: ElasticityProblem

function get_unknown_field_name{P<:ElasticityProblem}(::Type{P})
    return "displacement"
end

function get_unknown_field_type{P<:ElasticityProblem}(::Type{P})
    return Vector{Float64}
end

=#

function call(problem::Problem, element::Element, ip, time::Float64, ::Type{Val{:E}})
    haskey(element, "displacement") || return nothing
    gradu = element("displacement", ip, time, Val{:Grad})
    eps = 0.5*(gradu + gradu')
    return eps
end

function call(problem::Problem, element::Element, ip, time::Float64, ::Type{Val{:S}})
    haskey(element, "displacement") || return nothing
    props = problem.properties
    eps = problem(element, ip, time, Val{:E})
    eps == nothing && return nothing
    E = element("youngs modulus", ip, time)
    nu = element("poissons ratio", ip, time)
    mu = E/(2.0*(1.0+nu))
    la = E*nu/((1.0+nu)*(1.0-2.0*nu))
    if props.formulation in [:plane_stress, :plane_strain]
        la = 2.0*la*mu/(la+2.0*mu)
    end
    S = la*trace(eps)*I + 2.0*mu*eps
    return S
end

function call(problem::Problem, element::Element, ip, time::Float64, ::Type{Val{:COORD}})
    haskey(element, "geometry") || return nothing
    return element("geometry", ip, time)
end


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

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

    function UniformWeighting(; kwargs...)
        obj = new(meta(UniformWeighting), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct UniformWeighting
const __meta_UniformWeighting = Ref{ProtoMeta}()
function meta(::Type{UniformWeighting})
    ProtoBuf.metalock() do
        if !isassigned(__meta_UniformWeighting)
            __meta_UniformWeighting[] = target = ProtoMeta(UniformWeighting)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, UniformWeighting, 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_UniformWeighting[]
    end
end

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

    function InverseDistanceWeighting(; kwargs...)
        obj = new(meta(InverseDistanceWeighting), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct InverseDistanceWeighting
const __meta_InverseDistanceWeighting = Ref{ProtoMeta}()
function meta(::Type{InverseDistanceWeighting})
    ProtoBuf.metalock() do
        if !isassigned(__meta_InverseDistanceWeighting)
            __meta_InverseDistanceWeighting[] = target = ProtoMeta(InverseDistanceWeighting)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, InverseDistanceWeighting, 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_InverseDistanceWeighting[]
    end
end

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

    function LinearIndex(; kwargs...)
        obj = new(meta(LinearIndex), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct LinearIndex
const __meta_LinearIndex = Ref{ProtoMeta}()
function meta(::Type{LinearIndex})
    ProtoBuf.metalock() do
        if !isassigned(__meta_LinearIndex)
            __meta_LinearIndex[] = target = ProtoMeta(LinearIndex)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, LinearIndex, 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_LinearIndex[]
    end
end

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

    function SingleKdTreeIndex(; kwargs...)
        obj = new(meta(SingleKdTreeIndex), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct SingleKdTreeIndex
const __meta_SingleKdTreeIndex = Ref{ProtoMeta}()
function meta(::Type{SingleKdTreeIndex})
    ProtoBuf.metalock() do
        if !isassigned(__meta_SingleKdTreeIndex)
            __meta_SingleKdTreeIndex[] = target = ProtoMeta(SingleKdTreeIndex)
            allflds = Pair{Symbol,Union{Type,String}}[:leafSize => Int32]
            meta(target, SingleKdTreeIndex, 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_SingleKdTreeIndex[]
    end
end
function Base.getproperty(obj::SingleKdTreeIndex, name::Symbol)
    if name === :leafSize
        return (obj.__protobuf_jl_internal_values[name])::Int32
    else
        getfield(obj, name)
    end
end

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

    function SquaredEuclideanDistance(; kwargs...)
        obj = new(meta(SquaredEuclideanDistance), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct SquaredEuclideanDistance
const __meta_SquaredEuclideanDistance = Ref{ProtoMeta}()
function meta(::Type{SquaredEuclideanDistance})
    ProtoBuf.metalock() do
        if !isassigned(__meta_SquaredEuclideanDistance)
            __meta_SquaredEuclideanDistance[] = target = ProtoMeta(SquaredEuclideanDistance)
            allflds = Pair{Symbol,Union{Type,String}}[]
            meta(target, SquaredEuclideanDistance, 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_SquaredEuclideanDistance[]
    end
end

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

    function NearestNeighborsIndex(; kwargs...)
        obj = new(meta(NearestNeighborsIndex), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct NearestNeighborsIndex
const __meta_NearestNeighborsIndex = Ref{ProtoMeta}()
function meta(::Type{NearestNeighborsIndex})
    ProtoBuf.metalock() do
        if !isassigned(__meta_NearestNeighborsIndex)
            __meta_NearestNeighborsIndex[] = target = ProtoMeta(NearestNeighborsIndex)
            fnum = Int[1,2,100,110,200]
            allflds = Pair{Symbol,Union{Type,String}}[:numberOfDimensions => Int32, :floatSamples => Base.Vector{FloatVector}, :linearIndex => LinearIndex, :singleKdTreeIndex => SingleKdTreeIndex, :squaredEuclideanDistance => SquaredEuclideanDistance]
            oneofs = Int[0,0,1,1,2]
            oneof_names = Symbol[Symbol("IndexType"),Symbol("DistanceFunction")]
            meta(target, NearestNeighborsIndex, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, oneofs, oneof_names)
        end
        __meta_NearestNeighborsIndex[]
    end
end
function Base.getproperty(obj::NearestNeighborsIndex, name::Symbol)
    if name === :numberOfDimensions
        return (obj.__protobuf_jl_internal_values[name])::Int32
    elseif name === :floatSamples
        return (obj.__protobuf_jl_internal_values[name])::Base.Vector{FloatVector}
    elseif name === :linearIndex
        return (obj.__protobuf_jl_internal_values[name])::LinearIndex
    elseif name === :singleKdTreeIndex
        return (obj.__protobuf_jl_internal_values[name])::SingleKdTreeIndex
    elseif name === :squaredEuclideanDistance
        return (obj.__protobuf_jl_internal_values[name])::SquaredEuclideanDistance
    else
        getfield(obj, name)
    end
end

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

    function KNearestNeighborsClassifier(; kwargs...)
        obj = new(meta(KNearestNeighborsClassifier), Dict{Symbol,Any}(), Set{Symbol}())
        values = obj.__protobuf_jl_internal_values
        symdict = obj.__protobuf_jl_internal_meta.symdict
        for nv in kwargs
            fldname, fldval = nv
            fldtype = symdict[fldname].jtyp
            (fldname in keys(symdict)) || error(string(typeof(obj), " has no field with name ", fldname))
            if fldval !== nothing
                values[fldname] = isa(fldval, fldtype) ? fldval : convert(fldtype, fldval)
            end
        end
        obj
    end
end # mutable struct KNearestNeighborsClassifier
const __meta_KNearestNeighborsClassifier = Ref{ProtoMeta}()
function meta(::Type{KNearestNeighborsClassifier})
    ProtoBuf.metalock() do
        if !isassigned(__meta_KNearestNeighborsClassifier)
            __meta_KNearestNeighborsClassifier[] = target = ProtoMeta(KNearestNeighborsClassifier)
            fnum = Int[1,3,100,101,110,111,200,210]
            allflds = Pair{Symbol,Union{Type,String}}[:nearestNeighborsIndex => NearestNeighborsIndex, :numberOfNeighbors => Int64Parameter, :stringClassLabels => StringVector, :int64ClassLabels => Int64Vector, :defaultStringLabel => AbstractString, :defaultInt64Label => Int64, :uniformWeighting => UniformWeighting, :inverseDistanceWeighting => InverseDistanceWeighting]
            oneofs = Int[0,0,1,1,2,2,3,3]
            oneof_names = Symbol[Symbol("ClassLabels"),Symbol("DefaultClassLabel"),Symbol("WeightingScheme")]
            meta(target, KNearestNeighborsClassifier, allflds, ProtoBuf.DEF_REQ, fnum, ProtoBuf.DEF_VAL, ProtoBuf.DEF_PACK, ProtoBuf.DEF_WTYPES, oneofs, oneof_names)
        end
        __meta_KNearestNeighborsClassifier[]
    end
end
function Base.getproperty(obj::KNearestNeighborsClassifier, name::Symbol)
    if name === :nearestNeighborsIndex
        return (obj.__protobuf_jl_internal_values[name])::NearestNeighborsIndex
    elseif name === :numberOfNeighbors
        return (obj.__protobuf_jl_internal_values[name])::Int64Parameter
    elseif name === :stringClassLabels
        return (obj.__protobuf_jl_internal_values[name])::StringVector
    elseif name === :int64ClassLabels
        return (obj.__protobuf_jl_internal_values[name])::Int64Vector
    elseif name === :defaultStringLabel
        return (obj.__protobuf_jl_internal_values[name])::AbstractString
    elseif name === :defaultInt64Label
        return (obj.__protobuf_jl_internal_values[name])::Int64
    elseif name === :uniformWeighting
        return (obj.__protobuf_jl_internal_values[name])::UniformWeighting
    elseif name === :inverseDistanceWeighting
        return (obj.__protobuf_jl_internal_values[name])::InverseDistanceWeighting
    else
        getfield(obj, name)
    end
end

export KNearestNeighborsClassifier, NearestNeighborsIndex, UniformWeighting, InverseDistanceWeighting, LinearIndex, SingleKdTreeIndex, SquaredEuclideanDistance


text:
function OPF_dual(optimizer,set_generators,set_nodes,set_demands,generators,demands,capacity,varcost,load_node,utility_node,links,links_rev,F_max_dict,B_dict,MapG,MapD)

m=Model(optimizer)

@variable(m, μ_G[g in set_generators]>= 0)
@variable(m, μ_D[d in set_demands]>= 0)
@variable(m, η_lower[link in links]>= 0)
@variable(m, η_upper[link in links]>= 0)
@variable(m, λ[set_nodes])
@variable(m, γ)

@objective(m, Min,     sum(μ_D[d]*demands[d,load_node]  for d in set_demands) +
                       sum(μ_G[g]*generators[g,capacity]  for g in set_generators)+
                       sum(F_max_dict[j]*(η_lower[j]+η_upper[j])   for j in links)
                       )

@constraint(m, constraint1[d in set_demands], -demands[d,utility_node]+ μ_D[d]+λ[MapD[d][2]]>= 0)

@constraint(m, constraint2[g in set_generators], generators[g,varcost]+ μ_G[g]-λ[MapG[g][2]]>= 0)

#@constraint(m, constraint3[n in set_nodes_ref],     sum(B_dict[j]*(λ[j[1]]-λ[j[2]]+η_upper[j] -η_lower[j]) for j in links if n == j[1])
#                                                     +γ == 0)

@constraint(m, constraint3[n in set_nodes_ref],     sum(B_dict[j]*(λ[j[1]]-λ[j[2]]+η_upper[j] -η_lower[j]) for j in links if n == j[1])
                                                      +sum(B_dict[j]*(-η_upper[j] +η_lower[j]) for j in links_rev if n == j[2] )+γ == 0)

#@constraint(m, constraint4[n in set_nodes_noref],  sum(B_dict[j]*(λ[j[1]]-λ[j[2]]+η_upper[j] -η_lower[j]) for j in links if n == j[1])
#                                                      == 0)

@constraint(m, constraint4[n in set_nodes_noref],  sum(B_dict[j]*(λ[j[1]]-λ[j[2]]+η_upper[j] -η_lower[j]) for j in links if n == j[1])
                                                      +sum(B_dict[j]*(-η_upper[j] +η_lower[j]) for j in links_rev if n == j[2] )== 0)

@time optimize!(m)

status = termination_status(m)
println("The solution status is: $status")

syscost_det=objective_value(m)

println("System Cost:",syscost_det)

Dual_constraint2=zeros(length(set_generators))

for g in set_generators
   Dual_constraint2[g]= JuMP.dual(constraint2[g])
end
println("Production level of generator g:", Dual_constraint2)

Dual_constraint1=zeros(length(set_demands))

for d in set_demands
   Dual_constraint1[d]= JuMP.dual(constraint1[d])
end
println("Consumption level of demand d: ", Dual_constraint1)

λ_value=zeros(length(set_nodes))
for n in set_nodes
  λ_value[n]=JuMP.value.(λ[n])
end
println("Electricity Price:",λ_value)

#Review this flow lines
#Review all the constraints

f_value=zeros(n_link)
global i=1

for j in links
global jj=j
if set_nodes_ref==jj[1]
global f_value[i]= B_dict[j]*(JuMP.dual(constraint3[j[1]])-JuMP.dual(constraint4[j[2]]))
elseif set_nodes_ref==jj[2]
global f_value[i]= B_dict[j]*(JuMP.dual(constraint4[j[1]])-JuMP.dual(constraint3[j[2]]))
else
global f_value[i]= B_dict[j]*(JuMP.dual(constraint4[j[1]])-JuMP.dual(constraint4[j[2]]))
end
println("Power Flow lines $j:", f_value[i])
global i=1+i
end

return (syscost_det,Dual_constraint2,Dual_constraint1,λ_value,f_value)
end

#cd("C:\\Users\\braya\\.julia\\dev\\DTU_BrayamValqui_SP2021\\src")
#include("Singlefile_OPF_dual.jl")


text:
module JuliaWordsUtils

    import Base: length, getindex, lastindex, firstindex

    export select_word_backward, get_word_backward, extend_word

    """
        CharArray is a Vector of Char with a few convenience methods.
    """
    struct CharArray
        c::Vector{Char}
        function CharArray(s::AbstractString,l::Integer)
            l > length(s) && error("Offset larger than string length.")
            ca = Char[]

            for (count,c) in enumerate(s)
                push!(ca,c)
                count >= l && break
            end
            new(ca)
        end
        CharArray(s::AbstractString) = CharArray(s,length(s))
    end

    length(s::CharArray) = length(s.c)
    getindex(s::CharArray,i::Integer) = s.c[i]
    getindex(s::CharArray,i::UnitRange) = string(s.c[i]...)
    lastindex(s::CharArray) = lastindex(s.c)
    firstindex(s::CharArray) = firstindex(s.c)

    # maybe not the most efficient way of doing this.
    global const word_boundaries = [
        ' ','\n','\t','(',')','[',']',',','\'',
        '*','+','-','/','\\','%','{','}','#',':',
        '&','|','?','!','"','$','=','>','<'
    ]
    global const word_boundaries_dot = [word_boundaries; '.']#includes dot in function of the context

    function is_word_boundary(s::Char,stop_at_dot::Bool)
        w = stop_at_dot ? word_boundaries_dot : word_boundaries
        for c in w
            s == c && return true
        end
        false
    end

    function extend_word_backward(it::Integer,ca::CharArray,stop_at_dot::Bool)
        it <= 1 && return 1
        while !is_word_boundary(ca[it],stop_at_dot)
            it == 1 && return it
            it = it-1
        end
        return it+1 #I stopped at the boundary
    end

    function extend_word_forward(it::Integer,ca::CharArray,stop_at_dot::Bool)
        it >= length(ca) && return length(ca)
        while !is_word_boundary(ca[it],stop_at_dot)
            it == length(ca) && return it
            it = it+1
        end
        return it-1 #I stopped at the boundary
    end

    function extend_word(pos::Integer,txt::String,stop_at_dot=true)
        ca = CharArray(txt)

        pos > length(ca) && return "",pos,pos
        pos < 1 && return "",pos,pos

        is_word_boundary(ca[pos],stop_at_dot) && return ca[pos:pos], pos, pos

        i = extend_word_backward(pos,ca,stop_at_dot)
        j = extend_word_forward(pos,ca,stop_at_dot)

        if j < length(txt) && ca[j+1] == '!' #allow for a single ! at the end of words
           j = j + 1
        end
        ca[i:j], i, j
    end

    function select_word_backward(pos::Integer,ca::CharArray,stop_at_dot::Bool)
        j = pos
        #allow for autocomplete on functions
        pos = ca[pos] == '(' ? pos-1 : pos
        pos = ca[pos] == '!' ? pos-1 : pos

        is_word_boundary(ca[pos],stop_at_dot) && return pos, pos

        i = extend_word_backward(pos,ca,stop_at_dot)

        #allow for \alpha and such
        i = (i > 1 && ca[i-1] == '\\') ? i-1 : i

        return (i,j)
    end
    select_word_backward(pos::Integer,txt::String,stop_at_dot=true) = select_word_backward(pos,CharArray(txt,pos),stop_at_dot)

    function get_word_backward(pos::Integer,txt::String,stop_at_dot=true)
        ca = CharArray(txt,pos)
        i,j = select_word_backward(pos,ca,stop_at_dot)
        ca[i:j]
    end

end # module


text:
using JuMP, Juniper, Ipopt, Cbc
m = Model()

mutable struct blink
    cost::Float64
    x::Float64
    t::Float64
end

cost = randn(5)
x = randn(5)
t = randn(5)

Blinks = [blink(cost[i], x[i], t[i]) for i = 1:5]
p = [(1,3)]
@variables m begin
    δ[a in Blinks], Bin,(start = (a.cost == 0))
end

#Some constraints
for i in p
    @constraint(m, sum(δ[Blinks[j]] for j in i) <= 1)
end

#Budget constraint
B = 90
@constraint(m,Bud, sum(δ[a]*a.cost for a in Blinks) <= B)

function low_level(Blinks,δ...)
    ind = Int[]
    for i = 1:length(δ)
        if isapprox(δ[i], round(δ[i]))
            push!(ind,i)
        else
            Blinks[i].x = 0.0
            Blinks[i].t = 0.0
        end
    end

    #SolveEquilibrium(Nodes,vcat(Links,Clinks[ind]),ODs)
    #SolveEquilibrium modifies x and t for each member. That problem solves fine
    return  sum(a.x*a.t for a in Blinks)
end

#Function to be registered
ll(δ...) = low_level(Blinks,δ...)

JuMP.register(m,:ll,length(Blinks),ll,autodiff=true)
solver = JuniperSolver(IpoptSolver(print_level=0);
                       mip_solver=CbcSolver(),
                       registered_functions=[Juniper.register(:ll,length(Blinks),ll,autodiff=true)])

setsolver(m, solver)

JuMP.setNLobjective(m,:Min,:($(Expr(:call, :ll, (δ[a] for a in Blinks)...))))

status = solve(m)


text:
module JuliaConSamplePackage
using ForwardDiff

export newton

"""
    newton(f, f′, x₀; maxiter = 100, tol = 1e-8)
Find `f`s root via Newton's method.
"""
function newton(f, f′, x₀; maxiter = 100, tol = 1e-8)
    xₙ₊₁ = x₀
    xₙ = NaN
    iter = 0
    while true
        fₓ₊₁ = f(xₙ₊₁)
        fₓ = f(xₙ)
        if abs(fₓ₊₁ - fₓ) < tol
            return xₙ₊₁
        end
        if iter > maxiter
            error("Did not converge!")
        end

        f′ₙ₊₁ = f′(xₙ₊₁)
        if f′ₙ₊₁ == 0.0
            error("Derivative is zero!")
        end
        xₙ₊₁, xₙ = xₙ₊₁ - fₓ₊₁/f′ₙ₊₁, xₙ₊₁
        iter += 1
    end
end

newton(f, x₀; maxiter = 100, tol = 1e-8) =
    newton(f, x -> ForwardDiff.derivative(f, x), x₀; maxiter = maxiter, tol = tol)

end


text:
"""
Get a function representing an expression's value, given coordinates and linear parameters
"""
function get_basefun(ex::Expr, coords::Vector{Symbol}, linpars::Vector{Symbol})
    q=quote
        bfun=($(coords...), $(linpars...)) -> ( $(ex) )
    end

    try
        eval(q)

        return bfun
    catch
        throw(error("get_basefun:ERROR:error when parsing basis function. Check inputs"))
    end
end

"""
Get base function derivative of a given order in respect to each coordinate
"""
function get_basefun_derivative(ex::Expr, coords::Vector{Symbol}, linpars::Vector{Symbol}, deriv_inds::Vector{Int64})
    excp=copy(ex)
    dinds=copy(deriv_inds)

    for i=1:size(dinds, 1)
        while dinds[i]>0
            dinds[i]-=1

            excp=differentiate(excp, coords[i])
        end
    end

    q=quote
        bfun=($(coords...), $(linpars...)) -> ( $excp )
    end

    try
        eval(q)

        return bfun
    catch
        throw(error("get_basefun_derivative:ERROR:wrong parsing of basis function derivative"))
    end
end

"""
Get linear contribution of a linear parameter for a basis function, as a function of position
"""
function get_linpar_contribution(ex::Expr, coords::Vector{Symbol}, linpars::Vector{Symbol},
    influencer::Symbol, deriv_inds::Vector{Int64})
    excp=copy(ex)
    dinds=copy(deriv_inds)

    for i=1:size(dinds, 1)
        while dinds[i]>0
            dinds[i]-=1

            excp=differentiate(excp, coords[i])
        end
    end

    excp=differentiate(excp, influencer)

    q=quote
        bfun=($(coords...), $(linpars...)) -> ( $excp )
    end

    try
        eval(q)

        return bfun
    catch
        throw(error("get_linpar_contribution:ERROR:error parsing linear transformation coefficient for basis function. Please verify linearity"))
    end
end


text:
struct ConstructorError
    context::Union{String, Nothing}
    context_mark::Union{Mark, Nothing}
    problem::Union{String, Nothing}
    problem_mark::Union{Mark, Nothing}
    note::Union{String, Nothing}

    function ConstructorError(context=nothing, context_mark=nothing,
                              problem=nothing, problem_mark=nothing,
                              note=nothing)
        new(context, context_mark, problem, problem_mark, note)
    end

end

function show(io::IO, error::ConstructorError)
    if error.context != nothing
        print(io, error.context, " at ", error.context_mark, ": ")
    end
    print(io, error.problem, " at ", error.problem_mark)
end

mutable struct Constructor
    constructed_objects::Dict{Node, Any}
    recursive_objects::Set{Node}
    yaml_constructors::Dict{Union{String, Nothing}, Function}
    yaml_multi_constructors::Dict{Union{String, Nothing}, Function}

    function Constructor(single_constructors = Dict(), multi_constructors = Dict())
        new(Dict{Node, Any}(), Set{Node}(),
            convert(Dict{Union{String, Nothing},Function}, single_constructors),
            convert(Dict{Union{String, Nothing},Function}, multi_constructors))
    end
end

function add_constructor!(func::Function, constructor::Constructor, tag::Union{String, Nothing})
    constructor.yaml_constructors[tag] = func
    constructor
end

function add_multi_constructor!(func::Function, constructor::Constructor, tag::Union{String, Nothing})
    constructor.yaml_multi_constructors[tag] = func
    constructor
end

Constructor(::Nothing) = Constructor(Dict{String,Function}())
SafeConstructor(constructors::Dict = Dict(), multi_constructors::Dict = Dict()) = Constructor(merge(copy(default_yaml_constructors), constructors), multi_constructors)

function construct_document(constructor::Constructor, node::Node)
    data = construct_object(constructor, node)
    empty!(constructor.constructed_objects)
    empty!(constructor.recursive_objects)
    data
end

function construct_object(constructor::Constructor, node::Node)
    if haskey(constructor.constructed_objects, node)
        return constructor.constructed_objects[node]
    end

    if in(node, constructor.recursive_objects)
        throw(ConstructorError(nothing, nothing,
                               "found unconstructable recursive node",
                               node.start_mark))
    end

    push!(constructor.recursive_objects, node)
    node_constructor = nothing
    tag_suffix = nothing
    if haskey(constructor.yaml_constructors, node.tag)
        node_constructor = constructor.yaml_constructors[node.tag]
    else
        for (tag_prefix, node_const) in constructor.yaml_multi_constructors
            if tag_prefix !== nothing && startswith(node.tag, tag_prefix)
                tag_suffix = node.tag[length(tag_prefix) + 1:end]
                node_constructor = node_const
                break
            end
        end

        if node_constructor === nothing
            if haskey(constructor.yaml_multi_constructors, nothing)
                tag_suffix = node.tag
                node_constructor = constructor.yaml_multi_constructors[nothing]
            elseif haskey(constructor.yaml_constructors, nothing)
                node_constructor = constructor.yaml_constructors[nothing]
            elseif node isa ScalarNode
                node_constructor = construct_scalar
            elseif node isa SequenceNode
                node_constructor = construct_sequence
            elseif node isa MappingNode
                node_constructor = construct_mapping
            end
        end
    end

    if tag_suffix === nothing
        data = node_constructor(constructor, node)
    else
        data = node_constructor(constructor, tag_suffix, node)
    end

    # TODO: Handle generators/iterators

    constructor.constructed_objects[node] = data
    delete!(constructor.recursive_objects, node)

    data
end

function construct_scalar(constructor::Constructor, node::Node)
    if !(node isa ScalarNode)
        throw(ConstructorError(nothing, nothing,
                               "expected a scalar node, but found $(typeof(node))",
                               node.start_mark))
    end
    node.value
end

function construct_sequence(constructor::Constructor, node::Node)
    if !(node isa SequenceNode)
        throw(ConstructorError(nothing, nothing,
                               "expected a sequence node, but found $(typeof(node))",
                               node.start_mark))
    end

    [construct_object(constructor, child) for child in node.value]
end

function flatten_mapping(node::MappingNode)
    merge = []
    index = 1
    while index <= length(node.value)
        key_node, value_node = node.value[index]
        if key_node.tag == "tag:yaml.org,2002:merge"
            node.value = node.value[setdiff(axes(node.value, 1), index)]
            if value_node isa MappingNode
                flatten_mapping(value_node)
                append!(merge, value_node.value)
            elseif value_node isa SequenceNode
                submerge = []
                for subnode in value_node.value
                    if typeof(subnode) != MappingNode
                        throw(ConstructorError("while constructing a mapping",
                                               node.start_mark,
                                               "expected a mapping node, but found $(typeof(subnode))",
                                               subnode.start_mark))
                    end
                    flatten_mapping(subnode)
                    push!(submerge, subnode.value)
                    for value in reverse(submerge)
                        append!(merge, value)
                    end
                end
            end
        elseif key_node.tag == "tag:yaml.org,2002:value"
            key_node.tag = "tag:yaml.org,2002:str"
            index += 1
        else
            index += 1
        end
    end

    if !isempty(merge)
        node.value = vcat(merge, node.value)
    end
end

function construct_mapping(dicttype::Union{Type,Function}, constructor::Constructor, node::MappingNode)
    flatten_mapping(node)
    mapping = dicttype()
    for (key_node, value_node) in node.value
        key = construct_object(constructor, key_node)
        value = construct_object(constructor, value_node)
        if !(value isa keytype(mapping))
            try
                key = keytype(mapping)(key) # try to cast
            catch
                throw(ConstructorError(nothing, nothing,
                                       "Cannot cast $key to the key type of $dicttype",
                                       node.start_mark))
            end
        end
        try
            mapping[key] = value
        catch
            throw(ConstructorError(nothing, nothing,
                                   "Cannot store $key=>$value in $dicttype",
                                   node.start_mark))
        end
    end
    mapping
end

construct_mapping(constructor::Constructor, node::Node) = construct_mapping(Dict{Any,Any}, constructor, node)

# create a construct_mapping instance for a specific dicttype
custom_mapping(dicttype::Type{D}) where D <: AbstractDict =
    (constructor::Constructor, node::Node) -> construct_mapping(dicttype, constructor, node)
function custom_mapping(dicttype::Function)
    dicttype_test = try dicttype() catch
        throw(ArgumentError("The dicttype Function cannot be called without arguments"))
    end
    if !(dicttype_test isa AbstractDict)
        throw(ArgumentError("The dicttype Function does not return an AbstractDict"))
    end
    return (constructor::Constructor, node::Node) -> construct_mapping(dicttype, constructor, node)
end

function construct_yaml_null(constructor::Constructor, node::Node)
    construct_scalar(constructor, node)
    nothing
end

const bool_values = Dict(
    "yes"   => true,
    "no"    => false,
    "true"  => true,
    "false" => false,
    "on"    => true,
    "off"   => false )

function construct_yaml_bool(constructor::Constructor, node::Node)
    value = construct_scalar(constructor, node)
    bool_values[lowercase(value)]
end

function construct_yaml_int(constructor::Constructor, node::Node)
    value = string(construct_scalar(constructor, node))
    value = lowercase(replace(value, "_" => ""))

    if in(':', value)
        # TODO
        #throw(ConstructorError(nothing, nothing,
            #"sexagesimal integers not yet implemented", node.start_mark))
        warn("sexagesimal integers not yet implemented. Returning String.")
        return value
    end

    if length(value) > 2 && value[1] == '0' && (value[2] == 'x' || value[2] == 'X')
        return parse(Int, value[3:end], base = 16)
    elseif length(value) > 1 && value[1] == '0'
        return parse(Int, value, base = 8)
    else
        return parse(Int, value, base = 10)
    end
end

function construct_yaml_float(constructor::Constructor, node::Node)
    value = string(construct_scalar(constructor, node))
    value = lowercase(replace(value, "_" => ""))

    if in(':', value)
        # TODO
        # throw(ConstructorError(nothing, nothing,
        #     "sexagesimal floats not yet implemented", node.start_mark))
        warn("sexagesimal floats not yet implemented. Returning String.")
        return value
    end

    if value == ".nan"
        return NaN
    end

    m = match(r"^([+\-]?)\.inf$", value)
    if m !== nothing
        if m.captures[1] == "-"
            return -Inf
        else
            return Inf
        end
    end

    return parse(Float64, value)
end

const timestamp_pat =
    r"^(\d{4})-    (?# year)
       (\d\d?)-    (?# month)
       (\d\d?)     (?# day)
      (?:
        (?:[Tt]|[ \t]+)
        (\d\d?):      (?# hour)
        (\d\d):       (?# minute)
        (\d\d)        (?# second)
        (?:\.(\d*))?  (?# fraction)
        (?:
          [ \t]*(Z|(?:[+\-])(\d\d?)
            (?:
                :(\d\d)
            )?)
        )?
      )?$"x

function construct_yaml_timestamp(constructor::Constructor, node::Node)
    value = construct_scalar(constructor, node)
    mat = match(timestamp_pat, value)
    if mat === nothing
        throw(ConstructorError(nothing, nothing,
            "could not make sense of timestamp format", node.start_mark))
    end

    yr = parse(Int, mat.captures[1])
    mn = parse(Int, mat.captures[2])
    dy = parse(Int, mat.captures[3])

    if mat.captures[4] === nothing
        return Date(yr, mn, dy)
    end

    h = parse(Int, mat.captures[4])
    m = parse(Int, mat.captures[5])
    s = parse(Int, mat.captures[6])

    if mat.captures[7] === nothing
        return DateTime(yr, mn, dy, h, m, s)
    end

    ms = 0
    if mat.captures[7] !== nothing
        ms = mat.captures[7]
        if length(ms) > 3
            ms = ms[1:3]
        end
        ms = parse(Int, string(ms, repeat("0", 3 - length(ms))))
    end

    delta_hr = 0
    delta_mn = 0

    if mat.captures[9] !== nothing
        delta_hr = parse(Int, mat.captures[9])
    end

    if mat.captures[10] !== nothing
        delta_mn = parse(Int, mat.captures[10])
    end

    # TODO: Also, I'm not sure if there is a way to numerically set the timezone
    # in Calendar.

    return DateTime(yr, mn, dy, h, m, s, ms)
end

function construct_yaml_omap(constructor::Constructor, node::Node)
    throw(ConstructorError(nothing, nothing,
        "omap type not yet implemented", node.start_mark))
end

function construct_yaml_pairs(constructor::Constructor, node::Node)
    throw(ConstructorError(nothing, nothing,
        "pairs type not yet implemented", node.start_mark))
end

function construct_yaml_set(constructor::Constructor, node::Node)
    throw(ConstructorError(nothing, nothing,
        "set type not yet implemented", node.start_mark))
end

function construct_yaml_str(constructor::Constructor, node::Node)
    string(construct_scalar(constructor, node))
end

function construct_yaml_seq(constructor::Constructor, node::Node)
    construct_sequence(constructor, node)
end

function construct_yaml_map(constructor::Constructor, node::Node)
    construct_mapping(constructor, node)
end

function construct_yaml_object(constructor::Constructor, node::Node)
    throw(ConstructorError(nothing, nothing,
        "object type not yet implemented", node.start_mark))
end

function construct_undefined(constructor::Constructor, node::Node)
    throw(ConstructorError(nothing, nothing,
        "could not determine a constructor for the tag '$(node.tag)'",
        node.start_mark))
end

function construct_yaml_binary(constructor::Constructor, node::Node)
    value = replace(string(construct_scalar(constructor, node)), "\n" => "")
    base64decode(value)
end

const default_yaml_constructors = Dict{Union{String, Nothing}, Function}(
        "tag:yaml.org,2002:null"      => construct_yaml_null,
        "tag:yaml.org,2002:bool"      => construct_yaml_bool,
        "tag:yaml.org,2002:int"       => construct_yaml_int,
        "tag:yaml.org,2002:float"     => construct_yaml_float,
        "tag:yaml.org,2002:binary"    => construct_yaml_binary,
        "tag:yaml.org,2002:timestamp" => construct_yaml_timestamp,
        "tag:yaml.org,2002:omap"      => construct_yaml_omap,
        "tag:yaml.org,2002:pairs"     => construct_yaml_pairs,
        "tag:yaml.org,2002:set"       => construct_yaml_set,
        "tag:yaml.org,2002:str"       => construct_yaml_str,
        "tag:yaml.org,2002:seq"       => construct_yaml_seq,
        "tag:yaml.org,2002:map"       => construct_yaml_map,
        nothing                       => construct_undefined,
    )


text:
export permanent
"""
    permanent(A)

Compute the permanent of the square matrix `A`. Works best if `A`
is relatively sparse. For a dense matrix, this will be slow.
"""
function permanent(A::Matrix{T}) where {T<:Number}
    r, c = size(A)
    if r != c
        error("Matrix must be square")
    end
    if r == 0
        return zero(T)
    end

    allow = [findall((x) -> x != 0, A[i, :]) for i = 1:r]
    PG = PermGen(allow)

    try
        first(PG)  # make sure PG is not empty
        return sum(prod(A[i, p[i]] for i = 1:r) for p in PG)
    catch
        return zero(T)
    end
end