diff --git a/Makefile b/Makefile index 0fc54935..effcadba 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/connection/quic.go b/connection/quic.go index 10361088..d1b126da 100644 --- a/connection/quic.go +++ b/connection/quic.go @@ -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) diff --git a/connection/quic_test.go b/connection/quic_test.go index c860400e..26b71e48 100644 --- a/connection/quic_test.go +++ b/connection/quic_test.go @@ -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") } diff --git a/quic/quic_protocol.go b/quic/quic_protocol.go index 776b2eec..8c7baf87 100644 --- a/quic/quic_protocol.go +++ b/quic/quic_protocol.go @@ -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 { diff --git a/quic/quic_protocol_test.go b/quic/quic_protocol_test.go index a801b63e..9693a808 100644 --- a/quic/quic_protocol_test.go +++ b/quic/quic_protocol_test.go @@ -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 } diff --git a/tunnelrpc/pogs/sessionrpc.go b/tunnelrpc/pogs/sessionrpc.go index 5fa1642c..378fc205 100644 --- a/tunnelrpc/pogs/sessionrpc.go +++ b/tunnelrpc/pogs/sessionrpc.go @@ -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() diff --git a/tunnelrpc/tunnelrpc.capnp b/tunnelrpc/tunnelrpc.capnp index 3d2d1dd3..c24a7476 100644 --- a/tunnelrpc/tunnelrpc.capnp +++ b/tunnelrpc/tunnelrpc.capnp @@ -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 { diff --git a/tunnelrpc/tunnelrpc.capnp.go b/tunnelrpc/tunnelrpc.capnp.go index a198ca15..79261fce 100644 --- a/tunnelrpc/tunnelrpc.capnp.go +++ b/tunnelrpc/tunnelrpc.capnp.go @@ -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\xe36\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\x05dP\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\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.`\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,