TUN-6688: Update RegisterUdpSession capnproto to include trace context

This commit is contained in:
Devin Carr 2022-09-07 15:06:06 -07:00
parent 11cbff4ff7
commit e380333520
8 changed files with 361 additions and 279 deletions

View File

@ -291,7 +291,7 @@ github-mac-upload:
.PHONY: tunnelrpc-deps
tunnelrpc-deps:
which capnp # https://capnproto.org/install.html
which capnpc-go # go get zombiezen.com/go/capnproto2/capnpc-go
which capnpc-go # go install zombiezen.com/go/capnproto2/capnpc-go@latest
capnp compile -ogo tunnelrpc/tunnelrpc.capnp
.PHONY: quic-deps

View File

@ -258,7 +258,7 @@ func (q *QUICConnection) handleRPCStream(rpcStream *quicpogs.RPCServerStream) er
}
// RegisterUdpSession is the RPC method invoked by edge to register and run a session
func (q *QUICConnection) RegisterUdpSession(ctx context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeAfterIdleHint time.Duration) error {
func (q *QUICConnection) RegisterUdpSession(ctx context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeAfterIdleHint time.Duration, traceContext string) error {
// Each session is a series of datagram from an eyeball to a dstIP:dstPort.
// (src port, dst IP, dst port) uniquely identifies a session, so it needs a dedicated connected socket.
originProxy, err := ingress.DialUDP(dstIP, dstPort)

View File

@ -652,7 +652,7 @@ type mockSessionRPCServer struct {
calledUnregisterChan chan struct{}
}
func (s mockSessionRPCServer) RegisterUdpSession(ctx context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeIdleAfter time.Duration) error {
func (s mockSessionRPCServer) RegisterUdpSession(ctx context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeIdleAfter time.Duration, traceContext string) error {
return fmt.Errorf("mockSessionRPCServer doesn't implement RegisterUdpSession")
}

View File

@ -247,12 +247,8 @@ func NewRPCClientStream(ctx context.Context, stream io.ReadWriteCloser, logger *
}, nil
}
func (rcs *RPCClientStream) RegisterUdpSession(ctx context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeIdleAfterHint time.Duration) error {
resp, err := rcs.client.RegisterUdpSession(ctx, sessionID, dstIP, dstPort, closeIdleAfterHint)
if err != nil {
return err
}
return resp.Err
func (rcs *RPCClientStream) RegisterUdpSession(ctx context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeIdleAfterHint time.Duration, traceContext string) (*tunnelpogs.RegisterUdpSessionResponse, error) {
return rcs.client.RegisterUdpSession(ctx, sessionID, dstIP, dstPort, closeIdleAfterHint, traceContext)
}
func (rcs *RPCClientStream) UnregisterUdpSession(ctx context.Context, sessionID uuid.UUID, message string) error {

View File

@ -110,45 +110,74 @@ func TestConnectResponseMeta(t *testing.T) {
}
func TestRegisterUdpSession(t *testing.T) {
clientStream, serverStream := newMockRPCStreams()
unregisterMessage := "closed by eyeball"
sessionRPCServer := mockSessionRPCServer{
sessionID: uuid.New(),
dstIP: net.IP{172, 16, 0, 1},
dstPort: 8000,
closeIdleAfter: testCloseIdleAfterHint,
unregisterMessage: unregisterMessage,
var tests = []struct {
name string
sessionRPCServer mockSessionRPCServer
}{
{
name: "RegisterUdpSession (no trace context)",
sessionRPCServer: mockSessionRPCServer{
sessionID: uuid.New(),
dstIP: net.IP{172, 16, 0, 1},
dstPort: 8000,
closeIdleAfter: testCloseIdleAfterHint,
unregisterMessage: unregisterMessage,
traceContext: "",
},
},
{
name: "RegisterUdpSession (with trace context)",
sessionRPCServer: mockSessionRPCServer{
sessionID: uuid.New(),
dstIP: net.IP{172, 16, 0, 1},
dstPort: 8000,
closeIdleAfter: testCloseIdleAfterHint,
unregisterMessage: unregisterMessage,
traceContext: "1241ce3ecdefc68854e8514e69ba42ca:b38f1bf5eae406f3:0:1",
},
},
}
logger := zerolog.Nop()
sessionRegisteredChan := make(chan struct{})
go func() {
protocol, err := DetermineProtocol(serverStream)
assert.NoError(t, err)
rpcServerStream, err := NewRPCServerStream(serverStream, protocol)
assert.NoError(t, err)
err = rpcServerStream.Serve(sessionRPCServer, nil, &logger)
assert.NoError(t, err)
serverStream.Close()
close(sessionRegisteredChan)
}()
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
logger := zerolog.Nop()
clientStream, serverStream := newMockRPCStreams()
sessionRegisteredChan := make(chan struct{})
go func() {
protocol, err := DetermineProtocol(serverStream)
assert.NoError(t, err)
rpcServerStream, err := NewRPCServerStream(serverStream, protocol)
assert.NoError(t, err)
err = rpcServerStream.Serve(test.sessionRPCServer, nil, &logger)
assert.NoError(t, err)
rpcClientStream, err := NewRPCClientStream(context.Background(), clientStream, &logger)
assert.NoError(t, err)
serverStream.Close()
close(sessionRegisteredChan)
}()
assert.NoError(t, rpcClientStream.RegisterUdpSession(context.Background(), sessionRPCServer.sessionID, sessionRPCServer.dstIP, sessionRPCServer.dstPort, testCloseIdleAfterHint))
rpcClientStream, err := NewRPCClientStream(context.Background(), clientStream, &logger)
assert.NoError(t, err)
// Different sessionID, the RPC server should reject the registraion
assert.Error(t, rpcClientStream.RegisterUdpSession(context.Background(), uuid.New(), sessionRPCServer.dstIP, sessionRPCServer.dstPort, testCloseIdleAfterHint))
reg, err := rpcClientStream.RegisterUdpSession(context.Background(), test.sessionRPCServer.sessionID, test.sessionRPCServer.dstIP, test.sessionRPCServer.dstPort, testCloseIdleAfterHint, test.sessionRPCServer.traceContext)
assert.NoError(t, err)
assert.NoError(t, reg.Err)
assert.NoError(t, rpcClientStream.UnregisterUdpSession(context.Background(), sessionRPCServer.sessionID, unregisterMessage))
// Different sessionID, the RPC server should reject the registraion
reg, err = rpcClientStream.RegisterUdpSession(context.Background(), uuid.New(), test.sessionRPCServer.dstIP, test.sessionRPCServer.dstPort, testCloseIdleAfterHint, test.sessionRPCServer.traceContext)
assert.NoError(t, err)
assert.Error(t, reg.Err)
// Different sessionID, the RPC server should reject the unregistraion
assert.Error(t, rpcClientStream.UnregisterUdpSession(context.Background(), uuid.New(), unregisterMessage))
assert.NoError(t, rpcClientStream.UnregisterUdpSession(context.Background(), test.sessionRPCServer.sessionID, unregisterMessage))
rpcClientStream.Close()
<-sessionRegisteredChan
// Different sessionID, the RPC server should reject the unregistraion
assert.Error(t, rpcClientStream.UnregisterUdpSession(context.Background(), uuid.New(), unregisterMessage))
rpcClientStream.Close()
<-sessionRegisteredChan
})
}
}
func TestManageConfiguration(t *testing.T) {
@ -198,9 +227,10 @@ type mockSessionRPCServer struct {
dstPort uint16
closeIdleAfter time.Duration
unregisterMessage string
traceContext string
}
func (s mockSessionRPCServer) RegisterUdpSession(_ context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeIdleAfter time.Duration) error {
func (s mockSessionRPCServer) RegisterUdpSession(_ context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeIdleAfter time.Duration, traceContext string) error {
if s.sessionID != sessionID {
return fmt.Errorf("expect session ID %s, got %s", s.sessionID, sessionID)
}
@ -213,6 +243,9 @@ func (s mockSessionRPCServer) RegisterUdpSession(_ context.Context, sessionID uu
if s.closeIdleAfter != closeIdleAfter {
return fmt.Errorf("expect closeIdleAfter %d, got %d", s.closeIdleAfter, closeIdleAfter)
}
if s.traceContext != traceContext {
return fmt.Errorf("expect traceContext %s, got %s", s.traceContext, traceContext)
}
return nil
}

View File

@ -14,7 +14,7 @@ import (
)
type SessionManager interface {
RegisterUdpSession(ctx context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeAfterIdleHint time.Duration) error
RegisterUdpSession(ctx context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeAfterIdleHint time.Duration, traceContext string) error
UnregisterUdpSession(ctx context.Context, sessionID uuid.UUID, message string) error
}
@ -50,12 +50,19 @@ func (i SessionManager_PogsImpl) RegisterUdpSession(p tunnelrpc.SessionManager_r
closeIdleAfterHint := time.Duration(p.Params.CloseAfterIdleHint())
traceContext, err := p.Params.TraceContext()
if err != nil {
return err
}
resp := RegisterUdpSessionResponse{}
registrationErr := i.impl.RegisterUdpSession(p.Ctx, sessionID, dstIP, dstPort, closeIdleAfterHint)
registrationErr := i.impl.RegisterUdpSession(p.Ctx, sessionID, dstIP, dstPort, closeIdleAfterHint, traceContext)
if registrationErr != nil {
resp.Err = registrationErr
}
// TUN-6689: Add spans to return path for RegisterUdpSession
result, err := p.Results.NewResult()
if err != nil {
return err
@ -85,13 +92,17 @@ func (i SessionManager_PogsImpl) UnregisterUdpSession(p tunnelrpc.SessionManager
}
type RegisterUdpSessionResponse struct {
Err error
Err error
Spans []byte // Spans in protobuf format
}
func (p *RegisterUdpSessionResponse) Marshal(s tunnelrpc.RegisterUdpSessionResponse) error {
if p.Err != nil {
return s.SetErr(p.Err.Error())
}
if err := s.SetSpans(p.Spans); err != nil {
return err
}
return nil
}
@ -103,6 +114,10 @@ func (p *RegisterUdpSessionResponse) Unmarshal(s tunnelrpc.RegisterUdpSessionRes
if respErr != "" {
p.Err = fmt.Errorf(respErr)
}
p.Spans, err = s.Spans()
if err != nil {
return err
}
return nil
}
@ -116,7 +131,7 @@ func (c SessionManager_PogsClient) Close() error {
return c.Conn.Close()
}
func (c SessionManager_PogsClient) RegisterUdpSession(ctx context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeAfterIdleHint time.Duration) (*RegisterUdpSessionResponse, error) {
func (c SessionManager_PogsClient) RegisterUdpSession(ctx context.Context, sessionID uuid.UUID, dstIP net.IP, dstPort uint16, closeAfterIdleHint time.Duration, traceContext string) (*RegisterUdpSessionResponse, error) {
client := tunnelrpc.SessionManager{Client: c.Client}
promise := client.RegisterUdpSession(ctx, func(p tunnelrpc.SessionManager_registerUdpSession_Params) error {
if err := p.SetSessionId(sessionID[:]); err != nil {
@ -127,6 +142,7 @@ func (c SessionManager_PogsClient) RegisterUdpSession(ctx context.Context, sessi
}
p.SetDstPort(dstPort)
p.SetCloseAfterIdleHint(int64(closeAfterIdleHint))
p.SetTraceContext(traceContext)
return nil
})
result, err := promise.Result().Struct()

View File

@ -148,12 +148,13 @@ interface TunnelServer extends (RegistrationServer) {
struct RegisterUdpSessionResponse {
err @0 :Text;
spans @1 :Data;
}
interface SessionManager {
# Let the edge decide closeAfterIdle to make sure cloudflared doesn't close session before the edge closes its side
registerUdpSession @0 (sessionId :Data, dstIp :Data, dstPort: UInt16, closeAfterIdleHint: Int64) -> (result :RegisterUdpSessionResponse);
unregisterUdpSession @1 (sessionId :Data, message: Text) -> ();
registerUdpSession @0 (sessionId :Data, dstIp :Data, dstPort :UInt16, closeAfterIdleHint :Int64, traceContext :Text = "") -> (result :RegisterUdpSessionResponse);
unregisterUdpSession @1 (sessionId :Data, message :Text) -> ();
}
struct UpdateConfigurationResponse {

View File

@ -3593,12 +3593,12 @@ type RegisterUdpSessionResponse struct{ capnp.Struct }
const RegisterUdpSessionResponse_TypeID = 0xab6d5210c1f26687
func NewRegisterUdpSessionResponse(s *capnp.Segment) (RegisterUdpSessionResponse, error) {
st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1})
st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2})
return RegisterUdpSessionResponse{st}, err
}
func NewRootRegisterUdpSessionResponse(s *capnp.Segment) (RegisterUdpSessionResponse, error) {
st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1})
st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2})
return RegisterUdpSessionResponse{st}, err
}
@ -3631,12 +3631,26 @@ func (s RegisterUdpSessionResponse) SetErr(v string) error {
return s.Struct.SetText(0, v)
}
func (s RegisterUdpSessionResponse) Spans() ([]byte, error) {
p, err := s.Struct.Ptr(1)
return []byte(p.Data()), err
}
func (s RegisterUdpSessionResponse) HasSpans() bool {
p, err := s.Struct.Ptr(1)
return p.IsValid() || err != nil
}
func (s RegisterUdpSessionResponse) SetSpans(v []byte) error {
return s.Struct.SetData(1, v)
}
// RegisterUdpSessionResponse_List is a list of RegisterUdpSessionResponse.
type RegisterUdpSessionResponse_List struct{ capnp.List }
// NewRegisterUdpSessionResponse creates a new list of RegisterUdpSessionResponse.
func NewRegisterUdpSessionResponse_List(s *capnp.Segment, sz int32) (RegisterUdpSessionResponse_List, error) {
l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 1}, sz)
l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 0, PointerCount: 2}, sz)
return RegisterUdpSessionResponse_List{l}, err
}
@ -3681,7 +3695,7 @@ func (c SessionManager) RegisterUdpSession(ctx context.Context, params func(Sess
Options: capnp.NewCallOptions(opts),
}
if params != nil {
call.ParamsSize = capnp.ObjectSize{DataSize: 16, PointerCount: 2}
call.ParamsSize = capnp.ObjectSize{DataSize: 16, PointerCount: 3}
call.ParamsFunc = func(s capnp.Struct) error { return params(SessionManager_registerUdpSession_Params{Struct: s}) }
}
return SessionManager_registerUdpSession_Results_Promise{Pipeline: capnp.NewPipeline(c.Client.Call(call))}
@ -3776,12 +3790,12 @@ type SessionManager_registerUdpSession_Params struct{ capnp.Struct }
const SessionManager_registerUdpSession_Params_TypeID = 0x904e297b87fbecea
func NewSessionManager_registerUdpSession_Params(s *capnp.Segment) (SessionManager_registerUdpSession_Params, error) {
st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 16, PointerCount: 2})
st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 16, PointerCount: 3})
return SessionManager_registerUdpSession_Params{st}, err
}
func NewRootSessionManager_registerUdpSession_Params(s *capnp.Segment) (SessionManager_registerUdpSession_Params, error) {
st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 16, PointerCount: 2})
st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 16, PointerCount: 3})
return SessionManager_registerUdpSession_Params{st}, err
}
@ -3839,12 +3853,31 @@ func (s SessionManager_registerUdpSession_Params) SetCloseAfterIdleHint(v int64)
s.Struct.SetUint64(8, uint64(v))
}
func (s SessionManager_registerUdpSession_Params) TraceContext() (string, error) {
p, err := s.Struct.Ptr(2)
return p.Text(), err
}
func (s SessionManager_registerUdpSession_Params) HasTraceContext() bool {
p, err := s.Struct.Ptr(2)
return p.IsValid() || err != nil
}
func (s SessionManager_registerUdpSession_Params) TraceContextBytes() ([]byte, error) {
p, err := s.Struct.Ptr(2)
return p.TextBytes(), err
}
func (s SessionManager_registerUdpSession_Params) SetTraceContext(v string) error {
return s.Struct.SetText(2, v)
}
// SessionManager_registerUdpSession_Params_List is a list of SessionManager_registerUdpSession_Params.
type SessionManager_registerUdpSession_Params_List struct{ capnp.List }
// NewSessionManager_registerUdpSession_Params creates a new list of SessionManager_registerUdpSession_Params.
func NewSessionManager_registerUdpSession_Params_List(s *capnp.Segment, sz int32) (SessionManager_registerUdpSession_Params_List, error) {
l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 16, PointerCount: 2}, sz)
l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 16, PointerCount: 3}, sz)
return SessionManager_registerUdpSession_Params_List{l}, err
}
@ -4424,7 +4457,7 @@ func (c CloudflaredServer) RegisterUdpSession(ctx context.Context, params func(S
Options: capnp.NewCallOptions(opts),
}
if params != nil {
call.ParamsSize = capnp.ObjectSize{DataSize: 16, PointerCount: 2}
call.ParamsSize = capnp.ObjectSize{DataSize: 16, PointerCount: 3}
call.ParamsFunc = func(s capnp.Struct) error { return params(SessionManager_registerUdpSession_Params{Struct: s}) }
}
return SessionManager_registerUdpSession_Results_Promise{Pipeline: capnp.NewPipeline(c.Client.Call(call))}
@ -4533,231 +4566,234 @@ func CloudflaredServer_Methods(methods []server.Method, s CloudflaredServer_Serv
return methods
}
const schema_db8274f9144abc7e = "x\xda\xccZ}t\x1c\xd5u\xbfwfW#\x19\xad" +
"G\xc3,\x96\xb5\xc7B\x8d\x8e]j'\x06d\xd7)" +
"u\xd3H2\xb2\x83\x84?4\xbbV\x0e1&\x87\xd1" +
"\xee\x934\xea\xee\xcc23+l\x07\xe2\x0fl\x0c\x1c" +
"B0\xb1\xf9pBc\x9b\xd2\x9e\x98$\x85`\x9a\xba" +
"\x07Z\x9c\x86\x10Cpp\x0e\xa4&\x86\xa6\x89\xe3\xb6" +
"\xf8\x98R\x0cn\x8e\xdb\x98\xe9\xb93;\x1f\xda]$" +
"+\xce\x1f\xf9ou\xe7\xbe\xf7\xee\xfb\xbd\xdf\xfdx\xf7" +
"\xe9\xea;\x1a\xba\xb8\x8e\xf8F\x11@9\x10\xafs\xd8" +
"\xbc\x9fl\xd83\xe7\x9f\xb7\x80\x92Bt\xbe\xf8l_" +
"\xf2\x9c\xbd\xe58\xc4y\x01`\xe1\xe3\xc2\x06\x94\x0f\x0a" +
"\x02\x80\xfc\x8c\xf0\x1f\x80\xce\x9d3\x9e\xfc\xfa\xe3Kw" +
"\xde\x01R\x8a\x0f\x95\x01\x17>R\xdf\x87\xf2\xb7\xeaI" +
"\xf3\x1b\xf5\xdb\xe5\x86\x06\x01\xc0\xb9^\xba\xea\xc6\xe4\xab" +
"GH;:u\x8c\xa6~\xaf~\x1e\xcaHj\xf2\xf9" +
"z\x9a\xfaS\x85\x1f\xef\xfb\xe4\xae\x97\xb7\x82\x94\xe2\xc6" +
"M\xfdv\xc3\x06\x94\xcf\xbb\x9a\xe7\x1aV\x01:\xef\xef" +
"\x9c\xf9\xc4\xde#?\xdc\x06\xd2\x15\x08eK\xa5i?" +
"C@y\xce\xb4\xbf\x05t^9{\xe3\x07\x07~\xb0" +
"\xe8N\x90\xe6\x92\x02\x92\xc2\x0b\xd3\xda9@\xf9\xadi" +
"\x9d\x80\xce\xa9\xd3\xff\xb7\xfd\x0bsW\xde\x0f\xca\\\xe4" +
"\x00\xe2\x1ci\x9c\x9f\x96\"\x8d\xcb.!k:\x97\xbd" +
"r0\xb5\xf0\xc1\x9d\x15\xa6\xbb\x8ag/\x99\x87r\xbc" +
"\x91\x0c\xc2\xc6[\x01\x9dO\xff\xc9\xd3\xf7\xf5<\xb8i" +
"\x17HW\x05\xeb\xb1\xc654\xdb\xe6FZ\xef\x7f\xa6" +
"\x7f\xf5H\xe9\xda\xef>X6\xc8\x9deo\xe3<R" +
"8\xe8\xce\xd0>6\xe7\xe6\xef\xbd\xf0\xf4C\xa0\xccG" +
"t\xde\x1c\xfc\xf8\xeb\xfc\xa3\xfb\x8f\xc3\x00\x0ad\xdf\xc2" +
"\x96\xc4>\xda\xdd\xdc\x04\xe9\xfe\xf8\x13\xcf\xfe\xc3\xfdO" +
"o\xff*(W \x02\xb8h~)\xf1\xbf\xa4\xb07" +
"A\xab\xed<\xf6\xdc\xca\xc2\x8e\xdd\xfb<|\xdc\xef\x87" +
"\x13\x1c\x071gk\xef\xaf\x0b\x03\x8fe\x1e+#\x17" +
"\xa7O\xcf%\xce \xe0\xc2\xa3\x896\x04t\x16\xfd\xec" +
"\xe4\xaa\x15\xdf\x19\xfa\x9b\xc8\xd8w\xa6o\xa0\xb1\xdb\x87" +
"\xce\x1cjJ\x17\x9e\xa8@\xc4\xdd\xec\xdb\xd3\xf7\xa3\x8c" +
"\xa2{\x98\xd3\xc9\x84o]~}\xc3\xba\x93\xcb\x9e\x04" +
"i\xbe?M\xab\x98\xa6i\xc6^z\xec\x0f\xe7\xbct" +
"\xebS\xa0\\\x85\x01X-\xf4\x0d\xe5E\"\xed/v" +
"|\xce\xfe\xe7~~\xdf\x81*\x8e\xed\x107\xa0\xfc\xb8" +
"\xbb\xca^\xf13\xf2Q\xfa\xe5\xc4n\xe2?T\x1f\xfe" +
"\xa7\x03\x95\xfcu1>(\x0e\xa2\xfc\x8a\xe8\" \xba" +
"\xfb\xbb\xe7\xd0\xee\x8f\xd7\x7f\xfd\xfdgj\xaa\xbf\xd74" +
"\x88r\\r\x0fV\"\"]\xd6\x8bo>\xdf\x11\xfb" +
"n\x94i\x8fK\xa7\x08\xea\x83\xaeB\xeb;K\x12\xfa" +
"\xbb[\x9e\xaf\x00\xc5U\xfc\xdc\xa5}(\x17.\xa5\xd9" +
"\xb4KI9\xf6\xc9\xd1\xed\xd2\x89\x9f\xbe\xe0\x81\xe2\xed" +
"<.\x8f\xd2\xce?&\x13j}7~\xe5\x81\xf8\xc9" +
"\xaf\xbcH\xc6E| Nn\xb5\xb0[6Q\x1e\x90" +
"\xe9\xa7\"7\xf3\x80N\xea\xc9?\xfb\xf6\x92\xdc\x1b/" +
"\xd7\xe0\xa8|t\xc6\x19\xf9\xad\x19\xf4\xeb\x8d\x19\x04\xea" +
"\x89\xf9O}\xe1\xed/\x1d}\xad\xbc\x13w\xedE\xcd" +
".iz\x9bi\xedsk\xf7\\\xaf97\x1c\xaf\x04" +
"\xc6\xd5\xd4\x9a\xbf\x83\xf2\xe6f\x9a\xee\xf6f\x9a.`" +
"h-\xed_4\x8f\xa2|\xd6\xd5~\xcf\x9d\x9b;\xa9" +
"\xb6l\xfa\xe9\xa7\xdf\x8c\x90\xeal\xf3/\x11b\xce\xca" +
"\xcf\xde8\xdap\xfb\x89\x13Q\xb3\xdenv\x01>\xef" +
"\x0e\xfd\xc7\x7fyh\xe4\xa6o\x1f9\x19%\xd2L\x93" +
"\x88\xf4_\x7f}\xea\xcb\xa7\x0b\xb9\x7fw]\xc6?\x9c" +
"\x96\x99\x8b\x09\xce\x8e\x99\xe4\xc3\xcdm\x89\xa5\xed\xc7\xfa" +
"OE\xf1N\xb4,!\x859-4\xf9\xa2\x9b\xbb\xd9" +
"\xdakn8U\xc5\xb4\xa5-\x8bQ\x1ehq\xb1n" +
"\xd9\x8e\xb2\x96j\x06p\xc6\xfen\xc7\x0dO|\x7f\xe5" +
"\x19\xcf\x8b][>\x97Z@\xb6\xdc\xf7\xc5\x9eU\x7f" +
"\xda~\xe8Lt\x1bJ\x8a\xfcJf)Zi\xe8\x9a" +
"\xd3\x9f\x99s\xdf\x0f\xce\xd4r\x9em\xa9y(\xefJ" +
"\x11\\;H\xf9\xdde\x7f\xf9ZJL}P\x01m" +
"\x1d\xe9>\x93\x1aE\xf9p\xca\x0dh\xa9\x17\x89\xd0{" +
"\xffj\xdf\xbf\x9e;r\xdd\xd9\xaa=\x1c\x9cE\xdc\x9f" +
"E\xd3\x1e\x9e%\xc8\x87g]\x01\xe0\xdcy\xfc\xf3\xeb" +
"~r\xc7\xfbg+\x19\xe6\x1arhV\x1a\xe5\xd7\xdd" +
"\x11Gg\x11a\x1fZ\xfd\x9f\x1bO\xef\x9a\xf1\xeb\xaa" +
"\xb9oi\x1dEy[+inn}Q\xbe\xecr" +
"\xf2\xc4W\x85\xc7:z6\xbe|.rT\xe7[\xfb" +
"\x08\x9e\x07\x85\xaf\x9d\xd8\xf4\xf3\xcf\xff&\x0a\xcf\xb9\xd6" +
"_\x12<\x89\xcb\x09\x9e\xdb\xde}\xe4\xba/\xaf\xfd\xe6" +
"\x87\x11\x82\xcc\xbf|\x0b\x0d\xb5K\xba\xce\xf2f1\x96" +
"\xbd\xca\xff\x99\xbd2\xab\x16\xf5\xe2\xe2\xee\x92=\xc2t" +
"[\xcb\xaa6K\xb3N\xabh\xe8\x16\xebGT\x9a\xf8" +
"\x18@\x0c\x01$u\x14@\xb9\x99G%\xcf\xa1\x84\x98" +
"$\xa2H\x1a\x09GxTl\x0e%\x8eKR\x84\x95" +
"ni\x07P\xf2<*\xeb8D>\x89<\x80Tz" +
"\x00@Y\xc7\xa3\xb2\x95C\xa7\xc8\xcc\x82\xaa3\x1dD" +
"{\xa9ib#p\xd8\x08\xe8\x98\xcc6\xd7\xab\x83y" +
"\x10YD,\x8c\xdejc\x028L\x00:#F\xc9" +
"\xb4\x06t\x1b\xb5|\x9a\x0d\x99\xcc\xc2\x11\xac\x03\x0e\xeb" +
"\x00'\xda^\x86Y\x96f\xe8+T]\x1df&\x00" +
"\xed\xac\x9e\x8f\x03\x04\xd9\x0b\xfd<'u\xec\x06N\x9a" +
"/`\x98i\xd0'\xab\xf4\xb1\xfd\xc0I\xad\x82c\xb2" +
"a\xcd\xb2\x99\x89\x03\xb9\xa2;7o\xe8]\xe8\x94t" +
"\xef\x032\xd3\xfb \xd2\xaa]\xd8\x8f\xa1u|\xb5u" +
"\xd7\xe65\xa6\xdbb\xaf>dT@\xdeW\x0b\xf2\xbe" +
"2\xe4[#\x90o^\x02\xa0\xdc\xc6\xa3r\x17\x87\x12" +
"_\xc6|\xdb<\x00e\x13\x8f\xca\xbd\x1c:Yw\x91" +
"\xde\x1c\x00\x04h\x0e1\xd5.\x99\xcc\"\xd9t\xc0~" +
"\x1e]\xd0\xa7\x03n\x1cc&\xd9\xee\x1f\x82\xa8\x9a\xd9" +
"\x91\xe0\xa0&@z\xe9:\xcd\xb25}x\xb5+\xef" +
"\xec7\xf2Zv=\xed\xaa\xd1\xb5\xb3u1\x00\xa2t" +
"\xd9\x1a\x00\xe4$i\x09@\xa76\xac\x1b&sr\x9a" +
"\x955t\x9d\x01\x9f\xb57\x0e\xaayU\xcf\xb2`\xa1" +
"\xba\xea\x85\xbc\x052\xcc\x1cc\xe6\x95j\x84\xbe\xb3\xfb" +
"US\xe5\x0b\x96\xd2\x18\xe0\xb8t\x0d\x80\xd2\xc3\xa3\xd2" +
"\x1f\xc1q\x05\xe1\xb8\x9cG\xe5\x86\x08\x8e\x03\x84c?" +
"\x8f\xcaZ\x0e\x1d\xc3\xd4\x865\xfdZ\x06\xbc\x19e\xa0" +
"e\xebj\x81\x11fe<6\x1aE[3t\x0b\x9b" +
"\xc2\xac\x03\x88M\x11\xa4\x84\xc98y\xa5O)\x9fQ" +
"\x86>;\xcd\xac\x92\x90\xb7-%\x16\xec$\xb1\x18@" +
"\xa9\xe7QIr\xd8i2\xab\x94\xb7\xb1),'~" +
"\x17\xab\xfa\xf0Eh\x98\xaeE\xc3\x05\x00J\x8eG\xa5" +
"\xc8!\x96\xd1+,\x89D\x03\x1e=\x16\xde\xb2\x1b@" +
"\xb1yT6q\xe8X\xde\"\xbd\x809\x1f\xd1\xb6\x9c" +
"e\xf7\x16\xfd\xbf6\xe6,\xbb\xdf0m\x14\x80C\x01" +
"\x88\xb7\x86\xc5\xba\x87\xc8\xa7zsyv\x9d\xc6\xeb6" +
"\xc6\x81\xc38L\xe8T\x1e?D\x0al\x9e\xb7\xfb\xbb" +
"\x99Kd\xf8#\x1e\x95?\x8e\xec\xa6\x83\xe2\xd8\xd5<" +
"*\x9f\xe2\xd0Q\xb3Y\xa3\xa4\xdb\xab\x81W\x87+8" +
"\x9fa fM\x16\xd2\xc1_\xb6\xbe\x86[\x1b\xfa\x90" +
"6\\2U;\x02x\xa9\x98Sm6\xee\x93{\xce" +
"y\xfe\x02\xce9\xa8+\xa6|\xce~d\xaa8i\xd1" +
"T\x0bV\x14\x9bt-l\xe8T?\xc1\xa3rM\xed" +
"\x03\xdcX`\x96\xa5\x0e\xb3\xaa\xf0\x10\xaf\x89\x89\xce\xb2" +
"\xb4\xeb4\xf3\x92\xcc\x95&\xb3\x84R\xde&+\x1a\x1d" +
"\xc73\x83\xb85\x9bG\xe5j\x0e\x13\xf8\xa1\xe3\xd91" +
"\xff\x81\xf0\x8c\xda\x98i\x1a&6\x85I\xb8\x0cI\xb6" +
"\xbc\x00\x1az\x0f\xb3U-\x8f\xe4\x96A\xa5Z\x01\xdc" +
"dq%\x84\xcd\x13\xcf\xee$\xef(\x8c;)\xa2w" +
"\x13\x8f\xca,\x0e\x9daS\xcd\xb2~f\xa2f\xe4V" +
"\xaa\xba\x91\xe1Y\xb6\x8a\xac\xd3\xa7\xba\xa8\xcb\x0f\xdb\x82" +
"`\xd4\xc4\xe3MV\x06\xa1<\xbc\xbf\xcd\xb39\x19\xd8" +
"|{{\x98\x8c\x83c\xde<\x18f\x8b \x1e\xdeM" +
"\xcer\x17\x8f\xca\xceH^\xd9A\x91\xf3~\x1e\x95\xaf" +
"q(\xc5bI\x8c\x01H\x8f\x10Kv\xf2\xa8\xec\xe1" +
"\xc6\xa7l6\xc6t\xbbG\x1b\x06\x81Y\xa1\x94L\xec" +
"\xd1\x86\x19\xf0\xd6\xc5\xc6\xd6\xfaI\xf00\x06-#\xcf" +
"l\xd6\xc3\xb2y\x95\\n\x8cy\xdf\xcbd\xf4\x0fu" +
"\"\xde\xa6\xab\xbc\x87\xf8+\xfaUR\x84\x0e\xed\xa1\xe3" +
"\x0a,R\xdcL`\xad7\xb9\x17\x0c\xaa8\x10zL" +
"\x99\x07h\xfdN\x82\x8e\xbbg\x1c\xe7\xfcKB\xaf\xf3" +
"I1\x7fq\x18\x10\x82\x9a \x06\x1c\xc6\x00;\xb3\xee" +
"\x84U\xa106\x99U\x9d\x9eY\x1epT\x84\xf9\xf7" +
"X\xf4/\xff\x92\xb4\x0f8)!8\xbe\xe5\xe8\x8f\x17" +
"\xaa\x0a\xaa\xd8DQfU\xd1\xd6\x04C\xb7h\xad\x08" +
"\xff\x17\xd7\xe2\xbf\x19\xf2\xdfOhwo\x89\xd2\xbf\x9c" +
"\xd0v\xec\x0e\x99.\xc58\x8f\xfe\x8f\xee\x03P\xf6\xf0" +
"\xa8|\x93\xc3N\xaf\xd6\xc2\xa6\xb0iS\xa6\xacWQ" +
",7\xa0-\xab\xe6\xc3\xa4\xe7\x98\xac\x98W\xb3l)" +
"\x96\xab'@\x04\x0e\xd1\xf5\x93B\xd1d\x96\x85\x9a\xa1" +
"+%5\xaf\xf1\xf6\xfa\xa0\xe2\xd5K\x85~\x93\x8di" +
"h\x94\xacn\xdbf\x05\xa1h[\x17R\x0f\x87\x00Q" +
"\x90\x14\xb4\xbc\x0bP\xa4`\xa2\xca\xb1\x8bGey\x04" +
"\xa0^\xca\x91\xd7\xf1\xa8\xac\x0e\x01R\xbe\x07\xa0\xac\xe6" +
"Q\xb9\x99C\xb1T\xd2\x82\xa4\xe0\xe4\x8d\xac{\xda " +
"\xaeT\x0b\x95\xb9\xa1\xd7\xe2\xd2\xac`\xd8,\xbf\xde\xe3" +
"h.\xdc\xf1\x85\xc6\xe6\x8a \xe9'\xb3\xdf\xa7\xaao" +
"\xe2\x8b\x16\x81\x03\x15\xb8\xb7\xd7\xc2}Ad\x1f\xbe\xc9" +
"+\x06\xc3}\x08\x7f\xc1\xd6\xfbV\xb5\xb1\x02%=\x1f" +
"\xee\xf2f\xbaA\xb8>\xd4\x99j,r}p\xb9\x91" +
"U\xf3\x95!D\xacL\x86\xd1\xb2\xe5\xc2\xc3Ct\xd1" +
"U\xc56\x17V\x02\xe6\x1a\x7fby=\xf6\x01d\xd6" +
"!\x8f\x99\xad\x18b#o\xc6%\x00\x99\xdbH~\x17" +
"\x86\xf0\xc8\xdb0\x05\x90\xd9D\xf2{1\xb8\x85\xcaw" +
"\xe3~\x80\xcc\xbd$~\x98\xd4c\xbc\xeb\xbd\xf2.w" +
"\xfa\x9d$\xdfC\xf2x,\x89q\x00\xf9Q\x9c\x07\x90" +
"y\x98\xe4\x07H^\xc7%\xb1\x0e@~\x0aG\x012" +
"O\x92\xfcY\x92\x0b\xf1$]\xc4\xe5\x83h\x02d\xfe" +
"\x9e\xe4\xdf'y\xfd\xcc$\xd6\x03\xc8\x87\\\xf9\xf3$" +
"\xff\x11\xc9\x1bZ\x92\xd8\x00 \x1f\xc6-\x00\x99\x1f\x92" +
"\xfc5\x92O\xc3$N\x03\x90\x8f\xe2n\x80\xcck$" +
"\xff7\x92_R\x97\xc4K\x00\xe4\xb7\\{\x8e\x91\xfc" +
"W$o\x8c%\xb1\x11@\xfe\x05\xee\x03\xc8\xfc\x8a\xe4" +
"\xffM\xf2\x84\x90\xc4\x04\x80\xfc\x8e\xbb\xaf\xd3$\xaf\xe7" +
"*.\x81>\x8d+nz\xbca\x05<a\xe5p\x84" +
"\x9e\x8f\xf5\x1b\"\xdd\xe6P\x0c\xfb\xcb\x80(\x02:E" +
"\xc3\xc8\xaf\x1c\xef\x1e\xa2\xad\x0e[\xfe\xad\xb2)\xec\xaf" +
"\x01\x920\xa8\xd3@4\xf4\xde\\\x10\xb3*\x03\xa4o" +
"\x89fu\x97l\xa3T\x846\xe2b.\x08\x16fI" +
"_f\x1a\x85\xd5\xc8\xcc\x82\xa6\xab\xf9I\x02g\x03p" +
"\xd8\x00\xe5H\xe5\xcf=q\x14\xfd\xe8;r\xc0h\xae" +
"\x92\xd1m\xc5\xc5\xab\xd5\xe1\x8ak\xc7\xbc0\xbb\x06\xae" +
"=\x7fA\x98^E=\x12'\xdb\xc6\xd4|\xa9\xba\xa2" +
"\xae\x9bb\xe9\x97\xee\xf4J\xc7\xc9n\x16~\x9b\xac\"" +
"~\xd5(\x84\x06\xaaK\x894\xb3\xda\x82~Qd\xc3" +
"\xfb\xc3k\x83\xbf\xdfE\xed\x91kV^\xb5\x99ew" +
"\x17\xb1\x98\xd7X\xee\xb3\xcc\x14\xa3\xd5E\xcd\xe2)6" +
"\xd9\x8db|E\x86\x91\xc7\x00\xda8W\xde\xf0\x05\xe3" +
"9\xccl\xefW\xaf>dP\xc9$D\xeb\xc4\xa9\x8d" +
"N3K\xbc\x90\xb3\x08\xfb\x9b\x93\xd7\xb9S\x89\xd6i" +
"\xd6\xe6ra\xa2[c\x8d\xf9j\xd4\xa1\xfe%(\xd2" +
"! r\xaf\xe5Q\x19\x89\x90\x9b\xf5\xd5\xe8\x10\xa4\xc3" +
"\xd6\xa0\xc4s\xe5\xde \xa5\xdf\"\x8f\xcam\x1c\x8aj" +
"\xc9\x1e\xc1\xa6\xf0\xcdh\x1c\x08\xe3\xdbW\xc4\xf5^=" +
"\xc7\x00\xd7\xf9\xee\x1aI\xca\xc1c\xc6o\x05\xe3G\x96" +
"\xdf\x16Lz\x80AC\xbfb\xe5\x8f\xecRtz\x8b" +
"\x12og\xba\x05\xb1\xffV\x82~3\\zj\x03p" +
"\xd27\x04\x0c\x1f\x00\xd0\xef\xf7K\x8f\x9a\xc0I\xbb\x04" +
"\xe4\x82\xe7,\xf4\x9f\xad\xa4\xbb\xef\x01N\xda& \x1f" +
"\xbcF\xa1\xdf \xeeX?\x0d\x81\x93n\x170\x16<" +
"\x03\xa2\xdf^\x96n\x19\x05N\xd2\x04\x8c\x07\x0f]\xe8" +
"\xbf{H7m\x01N\x1a\x08\xdb\xa0\xd0\xe9\xed\xa3\x0b" +
"\x1d\x9f\xf3\xd0\xe6\xb2~|S\xd4\xd3\x02\xe8B\xc7\xbf" +
"\x94\xf1\x1fu+s\xb5\xfc\xbe\x1e\x88Y\xd5f]T" +
"({\x01\x0e\xcb\x11\x0e\xbaP\x89a\xa4\xbb\x0ep\xb1" +
"]\x91*?\x99b!\xea\x8f\xff-c._\xcbj" +
"Z'\xe8\x0fG\xe6\xa5\x8a\xbc\x91Ge&7I\xc1" +
"]3tz\x06\xfb\xe4\x17i0\xcd\xff\x07\xc1\xfcG" +
")\\\xff\x88G\xe5X\xc4\xad_'\xe1\xab<*o" +
"F\xca\xd17\xc8\xd7\x8f\xf1\xa8|\x10\xb6\xfc\xdf\xbb\x07" +
"@\xf9\x80\xc7t\xa4\xd2\x92\xce\x93\xe2o\xa8\x1eq\xeb" +
",\xf4\xea\xac8>\x00\x90\xa9\xa7:%\xe9\xd6Y1" +
"\xaf\xce\x92p\x10 \xd3D\xf2Y\xd1:\xab\x05\xd7\x00" +
"df\x92|6\x8e\xbfh\x0b%3,\x7f\xf3\xc6\xf0" +
"rM\xaf\x99\xbc\xfd7\x08\xb4\x97\xa9Z\xbed2\xa8" +
"\xbc\x82\xf4\xf6D\xca\x19\xefq\xc2\xebCf\x88\x849" +
"\xb4\x82\x1e\xe5\x14Z\x1c\x13e\xb2\xbcQ\xca\x0d\xe5U" +
"\x93\xe52\xcc\x14\xbc\x80\xd0\xcf\xc7\x95z\x8c\xfc\xb3\x00" +
"@\xf8\xa8\x1b!\xfb\x84\x99q\xa9i\x1ahV\\5" +
"\x16\x84W\x8d\xe0\xa6\xb1&\xbc\xe1I\\W\xf9\x8a7" +
"\x18^\x8e\xda\xb2j\xc9bU\x98\x00\xcf\xcc\xa0\xcde" +
"\x8d\x18\xa5|.\xcd@\xb0\xcd\xf5U\xb7\xba\xd8d\xd1" +
"W\xf4#a\xa3\x1b\x09\xfd\x97I\xf4\x1f %e7" +
"p\xd2\x0a\x8a\x84\xfe#\x19\xfa/\xe4R\xf7~\xe0\xa4" +
"?\xa7H\xe8\xbf\x0f\xa3\xff\xe8)u\xbc\x04\x9c\xd4\x11" +
"y\xbb\xf1\xf1\xa9z\xbb\xf1>\xb8\xfe@\x1f\xca\x09\x95" +
"\xab\xcc\xa8\x14\xa1\xa2\x8d\x88\x8b\xe8\xecx\x095r\x9c" +
"Sz\xf0\xb8\xe0w\x82\xe0\xffS*bN\xc3\xc5v" +
"\xd0\xfc\xd4\xf8\xff\x01\x00\x00\xff\xff|\xba\xdf\xe8"
const schema_db8274f9144abc7e = "x\xda\xccZ{t\x1c\xe5u\xbfwfW#\x19\xc9" +
"\xaba\x96H\x96#\xab\xd1\xb1Kqb@v\x9d\x82" +
"\x9bF\x92\x91\x1cV\xf8\xa1\xd9\xb5s\xa8\xb1s\x18\xed" +
"~\x92F\x9d\x9dYff\x85\xe5\xe0\xd886\x06\x0e" +
"\x10 6`'n\x8c\x1d\xda\x83\x09)\x0e\xa6)=" +
"\xa4\xc5i\x1c\x12H\x1c\x9c\x03\xa9\x89I\xd3\xc6q[" +
"\xfb\x98R\x0c4\xc7m\xcc\xf4\xdc\x99\x9d\x87v\x17=" +
" \x7f\xe4\xbf\xd5\x9d\xfb=\xee\xef\xfb\xdd\xc7w?]" +
"}\xa0\xae\x8b\xeb\x88oN\x00\xc8\x87\xe35\x0e\x9b\xff" +
"\xd3\x8d\xfb\xe6\xfd\xd3V\x90[\x10\x9d/<\xd7\x97\xbc" +
"`o=\x09q^\x00X\xf4\x98\xb0\x11\xa5g\x05\x01" +
"@zF\xf8\x0f@\xe7\x8e\x8f<\xf5\xb5\xc7zw~" +
"\x11\xc4\x16>T\x06\\\xb4\xbb\xb6\x0f\xa5'kI\xf3" +
"\xf1\xda\x1dR]\x9d\x00\xe0\xdc ^uS\xf2\xe5c" +
"\xa4\x1d\x9d:FS\xbfU;\x1f%$5\xe9b-" +
"M\xfd\xa9\xfcO\xf6\x7fr\xd7K\xdb@l\xe1\xc6M" +
"}\xa6n#J\x17]\xcd\x0bu\xab\x00\x9d\xb7w6" +
"?\xf1\xe8\xb1\x1fl\x07\xf1r\x84\xd2N\xc5\x19?G" +
"@i\xde\x8c\xbf\x01t~\xfc\xeeM\xef\x1c\xfe\xfe\xe2" +
";@\xbc\x82\x14\x90\x14\x8e\xceh\xe7\x00\xa5_\xcc\xe8" +
"\x04t\xce\x9e\xfb\xbf\x1d\x9f\xbfb\xe5\xfd _\x81\x9c" +
"?\xc5\xc5\x19-\x1c\xe0\xa2\xcb.iC@\xa7s\xd9" +
"\x8f\x9fmY\xf4\xd0\xce\xb2\xbds\xa4ym\xfd|\x94" +
"R\xf5\xb4\xa3\xde\xfa[\x01\x9dO\xff\xc9\xd3\xf7\xf5<" +
"\xb4e\x17\x88W\x05\x0b>^\xbf\x96\x16<ZO\x0b" +
"\xfe\xcf\xcc\xaf\x1c+^\xf7\xed\x87J;rg9]" +
"?\x9f\x14.\xba3\xb4\x8f\xce\xbb\xf9\xbbG\x9f~\x18" +
"\xe4\x05\x88\xce\xeb\x03\x1f\x7f\x95\xdf{\xf0$\xacA\x81" +
"6\xb8h}\xc3~2/\xdf@\xba?\xf9\xc4s\x7f" +
"\x7f\xff\xd3;\xbe\x02\xf2\xe5\x88\x00.\x9c\xc7\x1b\xfe\x97" +
"\x14N7\xd0j;O|ge\xfe\x81=\xfb=\x80" +
"\xdc\xef\x0d39\x0eb\xce\xb6\xd4o\xf2k\x0ed\x0e" +
"\x94\xa0\x8b\xd3'\x9cy\x1e\xc9\xee\x99\xae\xdd\x8b\x7f~" +
"z\xd5\x8ao\x0d\xfeudlGb#\x8d\xdd1x" +
"\xfeHc:\xffD5D\x16$\x0e\xa2\xd4\x9b D" +
"\xba\x13\xb4\xc7'\xe7\xdcP\xb7\xe1\xf4\xb2\xa7@\\\xe0" +
"O\xb37\x91\xa6iF_<\xf0\x87\xf3^\xbc\xf5\x10" +
"\xc8Wa\x00\xd6n\xfa\x86\xd23\xee\xd8\xd8\xc9y\x07" +
"\xbf\xf3\xcb\xfb\x0eW\x90Ll\xdc\x88\xd2\xbcFZ\xe5" +
"c\x8d\x9f\x91d\xfa\xe5\xc4\xd6\xf3\xef)\x8f\xfc\xe3\xe1" +
"r\x02{'\xd58\x80\xd2\x0a\xd2[\x94jt\xed\xbb" +
"\xfb\xc8\x9e\x8f\xd7~\xed\xedg\xaa\xaa\xdf\"\x0e\xa0\xb4" +
"]\xa4\x05n\x17\x89I\x97\xa5\xf0\xf5\xe7;b\xdf\x8e" +
"Rm\xde\xa5g\x09\xeak/%\x85\xd67\x966\xe8" +
"on}\xbe\x0c\x14W\xf1\xb5K\xfbPz\xe3R\x9a" +
"\xed\x8c\xab\x1c\xfb\xe4\xc8\x0e\xf1\xd4\xcf\x8ez\xa0x\x96" +
"o\x97F\xc8\xf2G%:\xb8\xbe\x9b\xbe\xfc`\xfc\xf4" +
"\x97_\xa0\xcdE\x9c N~\xb5\xe8\x88d\xa2\xf4\xaa" +
"\xe4\x9e\xb6\xd4\xc4\x03:-O\xfd\xe97\x97\xe6^{" +
"\xa9\xca\x89Hr\xd3yi}\x13\xfd\xfa\xf3&\x02\xf5" +
"\xd4\x82C\x9f?s\xef\xf1WJ\x96\xb8k?\xd3\xe4" +
"\x92\xe6\x87M\xb4\xf6\x85u\xfbnP\x9d\x1bO\x96\x03" +
"\xe3j\x9ei\xfa\x16J\xd8\xecz\xab;]\xc0\xd0j" +
"\xdaJ\xf3\x08JEW\xfb\x96f\x9a\x9b;\xad\xcc\xda" +
"\xf2\xb3O\xbf\x1e!U\xb1\xf9W\x081g\xe5go" +
"\x1a\xa9\xdbt\xeaTt[j\xb3\x0b\xf0&w\xe8?" +
"\xfc\xf3\xc3\xc3\xeb\xbfy\xect\x94H\xcd&\x11\xe9\xbf" +
"\xfe\xea\xec\x97\xce\xe5s\xff\xee\xba\x8c\x7f8\xbb\x9b\x97" +
"\x10\x9c\x87\x9a)\xa44\xb55\xf4\xb6\x9f\xe8?\x1b\xc5" +
"\xfb\xdeYKI\xe1\xb1Y4\xf9\xe2\x9b\xbb\xd9\xbak" +
"n<[\xc1\xb4\xa3\xb3\x96\xa0\xf4\xea,\x17\xebY;" +
"P:\xd3\xd2\x04\xe0\x8c\xfe\xed\x037>\xf1\xbd\x95\xe7" +
"=/v\xf7\xf2Z\xcbB\xda\xcb}_\xe8Yum" +
"\xfb\x91\xf3Q3\x8e\xb7\x9cw]\xb2\x85V\x1a\xbc\xe6" +
"\xdcg\xe6\xdd\xf7\xfd\xf3eG\xe5*\xc6g\xcfG\xe9" +
"\xb2\xd9\x04\x978\xbb\x13\xf0\xcde\x7f\xf9JK\xa2\xe5" +
"\x9d2hkHw\xf1\xec\x11\x94R\xa4\xbb\xa8w\xf6" +
"\x0bD\xe8G\xbf\xbe\xff_.\x1c\xbb\xfe\xdd\x0a\x1b\xae" +
"m%\xee\xb7\xd2\xb4\xa9VAJ\xb5^\x0e\xe0\xdcq" +
"\xf2s\x1b~\xfa\xc5\xb7\xdf-g\x98\xbb\x91\xee\xd64" +
"Jk\xdc\x11r+\x11\xf6\xe1\xd5\xff\xb9\xf9\xdc\xae\x8f" +
"\xfc\xa6b\xee\xb7ZGP\x8a\xcf!M\x9c\xf3\x82\xb4" +
"\x8b~9/\x0b\x07:z6\xbft!rT\x9b\xe6" +
"\xf4\x11<\x0f\x09_=\xb5\xe5\x97\x9f\xfbm\x14\x9e\xb1" +
"9\xbf\"x\xee\x9dC\xf0\xdc\xf6\xe6\xee\xeb\xbf\xb4\xee" +
"\x1b\xefE\x08\xf2\xe4\x9c\xad4\xd4.\xea:\xd3\xccB" +
",{\x95\xff3{eV)\xe8\x85%\xddE{\x98" +
"\xe9\xb6\x9aUl\x96f\x9dV\xc1\xd0-\xd6\x8f(7" +
"\xf21\x80\x18\x02\x88\xca\x08\x80|3\x8f\xb2\xc6\xa1\x88" +
"\x98$\xa2\x88*\x09\x87y\x94m\x0eE\x8eKR\x84" +
"\x15oi\x07\x905\x1e\xe5\x0d\x1c\"\x9fD\x1e@," +
">\x08 o\xe0Q\xde\xc6\xa1S`f^\xd1\x99\x0e" +
"\x09\xbb\xd74\xb1\x1e8\xac\x07tLf\x9bc\xca\x80" +
"\x06\x09\x16\x11\x0b#\xb7\xda\xd8\x00\x1c6\x00:\xc3F" +
"\xd1\xb4\xd6\xe86\xaaZ\x9a\x0d\x9a\xcc\xc2a\xac\x01\x0e" +
"k\x00'2/\xc3,K5\xf4\x15\x8a\xae\x0c1\x13" +
"\x80,\xab\xe5\xe3\x00A\xfaB?\xd1\x89\x1d{\x80\x13" +
"\x17\x08\x18f\x1a\xf4\xc9*~\xec pb\xab\xe0\x98" +
"lH\xb5lf\xe2\x9a\\\xc1\x9d\x9b7\xf4.t\x8a" +
"\xba\xf7\x01\x99\xe9}H\xd0\xaa]\xd8\x8f\xe1\xee\xf8\xca" +
"\xdd]\xa7\xa9L\xb7\x13)}\xd0(\x83\xbc\xaf\x1a\xe4" +
"}%\xc8\xb7E \xbf})\x80|\x1b\x8f\xf2\x9d\x1c" +
"\x8a|\x09\xf3\xed\xf3\x01\xe4-<\xca\xf7p\xe8d\xdd" +
"ER9\x00\x08\xd0\x1cd\x8a]4\x99E\xb2\x99\x80" +
"\xfd<\xba\xa0\xcf\x04\xdc<\xcaL\xda\xbb\x7f\x08\x09\xc5" +
"\xcc\x0e\x07\x075\x01\xd2\xbd\x1bT\xcbV\xf5\xa1\xd5\xae" +
"\xbc\xb3\xdf\xd0\xd4\xec\x18YU\xef\xee\xb3u\x09\x00\xa2" +
"x\xd9Z\x00\xe4Dq)@\xa7:\xa4\x1b&sr" +
"\xaa\x955t\x9d\x01\x9f\xb57\x0f(\x9a\xa2gY\xb0" +
"PM\xe5B\xde\x02\x19f\x8e2\xf3J%B\xdf\xb9" +
"\xfd\x8a\xa9\xf0yK\xae\x0fp\xec]\x0b \xf7\xf0(" +
"\xf7Gp\\A8.\xe7Q\xbe1\x82\xe3\x1a\xc2\xb1" +
"\x9fGy\x1d\x87\x8ea\xaaC\xaa~\x1d\x03\xde\x8c2" +
"\xd0\xb2u%\xcf\x08\xb3\x12\x1e\x9b\x8d\x82\xad\x1a\xba\x85" +
"\x8da\xd6\x01\xc4\xc6\x08R\xc2d\x9c\xbc\xd2\xa7\x94\xcf" +
"(C\x9f\x9bfVQ\xd0lK\x8e\x05\x964,\x01" +
"\x90ky\x94\x93\x1cv\x9a\xcc*j66\x86\xe5\xc4" +
"\xefbU\x1f\xbed\xb0\xe8\xa6t\x84\\>|\xdb\x17" +
"\x86\xe4\xc2\x12zw\x11z\xdbx\x94\xef'\x16\xa2\xc7" +
"\xc2{\xf7\x00\xc8\xf7\xf3(\x7f\x95C1\xc6%1\x86" +
"(\xee\xa6\xb8\xf1\x08\x8f\xf2\xd79t,o\xe5\x14`" +
"\xce\x87\xb9-g\xd9\xa9\x82\xff\xd7\xe6\x9ce\xf7\x1b\xa6" +
"\x8d\x02p(\x00\x91\xd9\xb0X\xf7 9Z*\xa7\xb1" +
"\xebU^\xb71\x0e\x1c\xc6\xc9zS\xc9\xb2\xeb\x0c\x8a" +
".l\x83]:$\x10q\x06\xc0D^\xe8\x11*A" +
"\x91\xd0\x0b\x0f\xbe\xf9W\x10{\xfe\x88G\xf9\x8f#\xe6" +
"w\x90\x01W\xf3(\x7f\x8aCG\xc9f\x8d\xa2n\xaf" +
"\x06^\x19*s\x92\x0c\x83D\xd6d!\x7f\xfcek" +
"\xab\xc4\x01C\x1fT\x87\x8a\xa6bGN\xa8X\xc8)" +
"6\x1b\xf7\xc9%\x86\xc6O\x81\x18A!2mb\xf8" +
"\xa1\xac\x8c\x1a\x09S\xc9[Ql\xd2\xd5\xb0!\x1a|" +
"\x82G\xf9\x9a\xea\x87\xbb9\xcf,K\x19b\x15\xf1$" +
"^\x15\x13\x9de\xc9\xea4\xf3\xb2\xd2\x95&\xb3\x84\xa2" +
"f\xd3.\xea\x1d\xc7\xdb\x06\x91q.\x8f\xf2\xd5\x1c6" +
"\xe0{\x8e\xb7\x8f\x05\x0f\x86g\xd4\xc6L\xd30\xb11" +
"\xcc\xda%H\xb2\xa5\x05\xd0\xd0{\x98\xad\xa8\x1a\x92\x1f" +
"\x07\xa5m\x19p\x93\x05\xa2\x106O<\xb7\x93\xdc)" +
"?\xee\xa4\xc8\x1f\x1ay\x94?\xca\xa13D\\\xedg" +
"&\xaaFn\xa5\xa2\x1b\x19\x9eeC\"\x97V\x9a9" +
"\xddE]~\xd8\x16\x04\xa3&\x1eo\xb2\x12\x08\xa5\xe1" +
"\xfdm\xde\x9e#\x11\xa0=\xcc\xde\xc11\xdf>\x10F" +
"\x80 \x80\xdeE\xcer'\x8f\xf2\xceH\"z\xa0/" +
"\x1a\x02bI\x8c\x01\x88\xbb\x89%;y\x94\xf7q\xe3" +
"s<\x1be\xba\xdd\xa3\x0e\x81\xc0\xacPJ[\xecQ" +
"\x87\x18\xf0\xd6\x87\x0d\xc6\xb5\x93\xe0a\x0cX\x86\xc6l" +
"\xd6\xc3\xb2\x9aB.7\xca\xbc\xef%2\xfa\x87:\x11" +
"o\xd3\x15\xdeC\xfcM\xf8eU\xc4\x83\xdaC\xea\x06" +
"\xd0.X\x18\xba\x95\xc0\xc2Z\xa8\xcd*(\xba5\x95" +
"X\xe2\xad\xef\xc5\x8b\x0a\x9a\x84NU\xa2\x0aZ\xbf\x93" +
"\xb8\xe4\xc2\x82\xe3\xe2\xc3\xd2\xd0\xba\xc0\xb8%\xa1qA" +
"\x9d\x11\x03\x0ec\x80\x9dYw\xc2\x0a\x0bc\x93\xed\xaa" +
"\xd3\xdb\x16a\x1bs\x0b;\xffn\x8c~CA\x14\xf7" +
"\x03'6\x08\x8e\xbfs\xf4\xc7\x0b\x15EZl\xa2@" +
"\xb4\xaa`\xab\x82\xa1[\xb4V\xc4E\x96Ts\x11\xb3" +
"J\x92\xdc\x1a\xf5\x90R\x92|`O\xe8\x0c^\x92\x04" +
"\x10\xf7\xee\x07\x90\xf7\xf1(\x7f\x83\xc3N\xaf~\xc3\xc6" +
"\xb0\x13Tb\xb5W\xa5,7\xa0-\xabha\xcet" +
"LV\xd0\x94,\xeb\xc5RE\x06\x88\xc0!\xba\xae\x94" +
"/\x98\xcc\xb2P5t\xb9\xa8h*o\x8f\x05U\xb4" +
"^\xcc\xf7\x9blTE\xa3hu\xdb6\xcb\x0b\x05\xdb" +
"\x9aJ\x8d\x1d\x02DqTP5\x17\xa0H\x11F\xd5" +
"h\x17\x8f\xf2\xf2\x08@)J\xa3\xd7\xf3(\xaf\x0e\x01" +
"\x92\xbf\x0b \xaf\xe6Q\xbe\x99\xc3D\xb1\xa8\x06y\xc3" +
"\xd1\x8c\xac{\xda\x90X\xa9\xe4\xcb\xd3G\xca\xe2\xd2," +
"o\xd8L\x1b\xf38\x9a\x0b-\x9ej\xf8.\x8b\xa3~" +
"\xbe\xfb}\xaa$'\xbe\xbc\x118P\x86{{5\xdc" +
"\x17F\xec\xf0\xb7\xbcb \xb4C\xf8\x0b6\x16D\x1d" +
"\x96\xa7\xbc\xe8\xc3]2\xa6\x1b\x84\x1bB\x9d\xe9\xc6\"" +
"\xd7\x07\x97\x1bYE+\x0f!\x89\xf2|\x19\xadl\xa6" +
"\x1e\x1e\xa2\x8b\xae*\xb4\xb9\xb0\x120\xd7\xf8\x13Kc" +
"\xd8\x07\x90\xd9\x80<f\xb6a\x88\x8dt;.\x05\xc8" +
"\xdcF\xf2;1\x84G\xda\x8e-\x00\x99-$\xbf\x07" +
"\x83\x9b\xadt\x17\x1e\x04\xc8\xdcC\xe2GH=\xc6\xbb" +
"\xde+\xedr\xa7\xdfI\xf2}$\x8f\xc7\x92\x18\x07\x90" +
"\xf6\xe2|\x80\xcc#$?L\xf2\x1a.\x895\x00\xd2" +
"!\x1c\x01\xc8<E\xf2\xe7H.\xc4\x93t\xb9\x97\x9e" +
"E\x13 \xf3w$\xff\x1e\xc9k\x9b\x93X\x0b \x1d" +
"q\xe5\xcf\x93\xfcG$\xaf\x9b\x95\xc4:\x00\xe9\x87\xb8" +
"\x15 \xf3\x03\x92\xbfB\xf2\x19\x98\xa4\xd2W:\x8e{" +
"\x002\xaf\x90\xfc_I~IM\x12/\x01\x90~\xe1" +
"\xee\xe7\x04\xc9\x7fM\xf2\xfaX\x92\xeae\xe9\xdfp?" +
"@\xe6\xd7$\xffo\x927\x08Il\x00\x90\xdep\xed" +
":G\xf2Z\xae\xecb\xe9\xd3\xb8\xec\xf6\xc8\x1bV\xc0" +
"\x13V\x0aG\xe8\xf9X\xbf\x91\xa0\x1b\"&\xc2\xa65" +
" &\x00\x9d\x82ah+\xc7\xbbG\xc2V\x86,\xff" +
"\xa6\xda\x18\xf6\xec\x00I\x18\x94r\x900\xf4T.\x88" +
"Y\xe5\x01\xd2\xdf\x89ju\x17m\xa3X\x806\xe2b" +
".\x08\x16fQ_f\x1a\xf9\xd5\xc8\xcc\xbc\xaa+\xda" +
"$\x81\xb3\x0e8\xac\x83R\xa4\xf2\xe7\x9e8\x8a\xbe\xff" +
"\xbd;`4W\xce\xe8\xb6\xc2\x92\xd5\xcaPY\xed0" +
"\x7f\x92\xda!\xa1G\xe2d\xdb\xa8\xa2\x15+\x8b\xee\x9a" +
"iV\x87\xe9N\xaf\xba\x9c\xec\xf2\xe1\xb7\xde\xca\xe2W" +
"\x95ZiMe)\x91fV[\xa1J\xb1t0\xbc" +
"Y\xf8\xf6.n\x8f\xdc\xc44\xc5f\x96\xdd]\xc0\x82" +
"\xa6\xb2\xdcg\x99\x99\x88V\x17\xd1Rjj\xa9l\\" +
"\xd1\xe6\x1a\x8c\x91\x07\x062\x9c+\x19<e<\x87\x98" +
"\xed\xfdJ\xe9\x83\x06\x95LB\xb4\x94\x9c\xde\xe84\xb3" +
"\x12S9\x8b\xb0g:y)<\x9dh\x9dfm." +
"\x17&\xbaXV\x99\xafJ\x1d\xea\xdf\x93\"\xcd/\"" +
"\xf7:\x1e\xe5\xe1\x08\xb9\x19\xa5\xda\x1c\x8fr!\xac\x17" +
"\xf2\xe9\xb0\xdd(\xf2\\\xa9\xdfH\xe9\xb7\xc0\xa3|\x1b" +
"\x87\x09\xa5h\x0fcc\xf8\x0e5\x0e\x84\xf1-1\xe2" +
"zJ\xcf1\xc0\x0d\xbe\xbbF\x92r\xf0@\xf2\x81`" +
"|\xdf\xf2\xdb\x82I\x0f0x$([\xf9}\x1b\x19" +
"\x9d\xde\xa2\xc4\xdbf\xb7 \xf6\xdf_\xd0o\xb0\x8b\x87" +
"6\x02'>.`\xf8\xa8\x80\xfe\x1b\x82\xb8\xd7\x04N" +
"\xdc% \x17<\x91\xa1\xff\x14&\xdeu7p\xe2v" +
"\x01\xf9\xe0\x85\x0b\xfd\xa6s\xc7\xd8\x0c\x04N\xdc$`" +
",x[D\xbfe-\xde2\x02\x9c\xa8\x0a\x18\x0f\x1e" +
"\xcf\xd0\x7fK\x11\xd7o\x05N\\\x13\xb6V\xa1\xd3\xb3" +
"\xa3\x0b\x1d\x9f\xf3\xd0\xe6\xb2~|\xa3\xd5\xd3\x02\xe8B" +
"\xc7\xbf\xb7\xf1\xefwqs\xb5\xfc^!$\xb2\x8a\xcd" +
"\xba\xa8P\xf6\x02\x1c\x96\"\x1ct\xa1\x1c\xc3H\xc7>" +
"\xd27\xfa\x80\x8d\x93\x0a?\x99f!\xea\x8f\xff\x801" +
"\x97\xaf\xb6kZ'\xe89G\xe6\xa5\x8a\xbc\x9eG\xb9" +
"\x99\x9b\xa4\xe0\xae\x1a:\xbd\x0d\xfb\xe4O\xd0`\x9a\xff" +
"\x0f\x82\xf9\x8fS\xb8\xfe\x11\x8f\xf2\x89\x88[\xbfJ\xc2" +
"\x97y\x94_\x8f\x94\xa3\xaf\x91\xaf\x9f\xe0Q~'|" +
"Fx\xebn\x00\xf9\x1d\x1e\xd3\x91JK\xbcH\x8a\xbf" +
"\xa5z\xc4\xad\xb3\xd0\xab\xb3\xe2\xf8 @\xa6\x96\xea\x94" +
"\xa4[g\xc5\xbc:K\xc4\x01\x80L#\xc9?\x1a\xad" +
"\xb3f\xe1Z\x80L3\xc9\xe7\xe2\xf8k\xb7P4\xc3" +
"\xf2W3\x86\x96\xabz\xd5\xe4\xed\xbfk\xa0\xbdLQ" +
"\xb5\xa2\xc9\xa0\xfc\x0a\x92\xea\x89\x943\xde\x83\x87\xd7\xc6" +
"\xcc\x10\x09sh\x05-\xceitA&\xcad\x9aQ" +
"\xcc\x0dj\x8a\xc9r\x19f\x0a^@\xe8\xe7\xe3r-" +
"F\xfe\x03\x01 |(\x8e\x90}\xc2\xcc\xd8k\x9a\x06" +
"\x9aeW\x8d\x85\xe1U#\xb8i\xac\x0dox\"\xd7" +
"U\xba\xe2\x0d\x84\x97\xa3\xb6\xacR\xb4X\x05&\xc03" +
"3\xe8\x84Y\xc3FQ\xcb\xa5\x19\x08\xb69Vq\xab" +
"\x8bM\x16}\x13~$\xacw#\xa1\xff\xda\x89\xfe\xa3" +
"\xa6(\xef\x01N\\A\x91\xd0\x7fxC\xff\xd5]\xec" +
">\x08\x9c\xf8g\x14\x09\xfd7g\xf4\x1fR\xc5\x8e\x17" +
"\x81\x13;\"\xefA>>\x15\xefA\xde\x07\xd7\x1f\xe8" +
"C)\xa1r\xe5\x19\x95\"T\xb4\x11\xf1!:;^" +
"B\x8d\x1c\xe7\xb4\x1eQ\xa6\xfc\xf6\x10\xfc\xd3KY\xcc" +
"\xa9\xfb\xb0M6?5\xfe\x7f\x00\x00\x00\xff\xff\xda\xbc" +
"\xea\xa1"
func init() {
schemas.Register(schema_db8274f9144abc7e,