From 0e67a1f8203150f77a9806b9d77a3a1b911df0e5 Mon Sep 17 00:00:00 2001 From: Andrei Mihu Date: Sat, 10 Nov 2018 14:45:38 +0000 Subject: [PATCH] DB defaults update, friend and group state cleanup. --- CHANGELOG.md | 10 + api/api.pb.go | 535 +++++++++--------- api/api.proto | 40 +- apigrpc/apigrpc.pb.go | 6 + apigrpc/apigrpc.swagger.json | 3 + migrate/sql/20180103142001_initial_schema.sql | 2 +- server/config.go | 10 +- server/core_authenticate.go | 16 +- server/core_friend.go | 13 +- server/core_group.go | 31 +- server/runtime_go_nakama.go | 25 +- server/runtime_lua.go | 10 +- server/runtime_lua_match_core.go | 7 +- server/runtime_lua_nakama.go | 110 +++- 14 files changed, 462 insertions(+), 356 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 780f7b317..0b9fcb62b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,17 @@ All notable changes to this project are documented below. The format is based on [keep a changelog](http://keepachangelog.com) and this project uses [semantic versioning](http://semver.org). ## [Unreleased] +### Added +- New runtime function to send raw realtime envelope data through streams. + +### Changed +- Change error message on database errors raised during authentication operations. +- New default for maximum number of open database connections. +- Friend state indicators are no longer offset when sent to clients. +- Group state indicators are no longer offset when sent to clients. + ### Fixed +- Correctly handle optional parameters in runtime functions to update account information. - Correctly handle context cancellation in single-statement database operations. ## [2.1.3] - 2018-11-02 diff --git a/api/api.pb.go b/api/api.pb.go index 9caecc026..fe65c3b6b 100644 --- a/api/api.pb.go +++ b/api/api.pb.go @@ -26,32 +26,28 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package type Friend_State int32 const ( - // Default case. Assumed as FRIEND state. - Friend_STATE_UNSPECIFIED Friend_State = 0 // The user is a friend of the current user. - Friend_FRIEND Friend_State = 1 - // The user has sent an invite to the current user. - Friend_INVITE_SENT Friend_State = 2 - // The current user has sent an invite to this user. - Friend_INVITE_RECEIVED Friend_State = 3 + Friend_FRIEND Friend_State = 0 + // The current user has sent an invite to the user. + Friend_INVITE_SENT Friend_State = 1 + // The current user has received an invite from this user. + Friend_INVITE_RECEIVED Friend_State = 2 // The current user has blocked this user. - Friend_BLOCKED Friend_State = 4 + Friend_BLOCKED Friend_State = 3 ) var Friend_State_name = map[int32]string{ - 0: "STATE_UNSPECIFIED", - 1: "FRIEND", - 2: "INVITE_SENT", - 3: "INVITE_RECEIVED", - 4: "BLOCKED", + 0: "FRIEND", + 1: "INVITE_SENT", + 2: "INVITE_RECEIVED", + 3: "BLOCKED", } var Friend_State_value = map[string]int32{ - "STATE_UNSPECIFIED": 0, - "FRIEND": 1, - "INVITE_SENT": 2, - "INVITE_RECEIVED": 3, - "BLOCKED": 4, + "FRIEND": 0, + "INVITE_SENT": 1, + "INVITE_RECEIVED": 2, + "BLOCKED": 3, } func (x Friend_State) String() string { @@ -66,32 +62,28 @@ func (Friend_State) EnumDescriptor() ([]byte, []int) { type GroupUserList_GroupUser_State int32 const ( - // Default case. Assumed as SUPERADMIN state. - GroupUserList_GroupUser_STATE_UNSPECIFIED GroupUserList_GroupUser_State = 0 // The user is a superadmin with full control of the group. - GroupUserList_GroupUser_SUPERADMIN GroupUserList_GroupUser_State = 1 + GroupUserList_GroupUser_SUPERADMIN GroupUserList_GroupUser_State = 0 // The user is an admin with additional privileges. - GroupUserList_GroupUser_ADMIN GroupUserList_GroupUser_State = 2 + GroupUserList_GroupUser_ADMIN GroupUserList_GroupUser_State = 1 // The user is a regular member. - GroupUserList_GroupUser_MEMBER GroupUserList_GroupUser_State = 3 + GroupUserList_GroupUser_MEMBER GroupUserList_GroupUser_State = 2 // The user has requested to join the group - GroupUserList_GroupUser_JOIN_REQUEST GroupUserList_GroupUser_State = 4 + GroupUserList_GroupUser_JOIN_REQUEST GroupUserList_GroupUser_State = 3 ) var GroupUserList_GroupUser_State_name = map[int32]string{ - 0: "STATE_UNSPECIFIED", - 1: "SUPERADMIN", - 2: "ADMIN", - 3: "MEMBER", - 4: "JOIN_REQUEST", + 0: "SUPERADMIN", + 1: "ADMIN", + 2: "MEMBER", + 3: "JOIN_REQUEST", } var GroupUserList_GroupUser_State_value = map[string]int32{ - "STATE_UNSPECIFIED": 0, - "SUPERADMIN": 1, - "ADMIN": 2, - "MEMBER": 3, - "JOIN_REQUEST": 4, + "SUPERADMIN": 0, + "ADMIN": 1, + "MEMBER": 2, + "JOIN_REQUEST": 3, } func (x GroupUserList_GroupUser_State) String() string { @@ -106,32 +98,28 @@ func (GroupUserList_GroupUser_State) EnumDescriptor() ([]byte, []int) { type UserGroupList_UserGroup_State int32 const ( - // Default case. Assumed as SUPERADMIN state. - UserGroupList_UserGroup_STATE_UNSPECIFIED UserGroupList_UserGroup_State = 0 // The user is a superadmin with full control of the group. - UserGroupList_UserGroup_SUPERADMIN UserGroupList_UserGroup_State = 1 + UserGroupList_UserGroup_SUPERADMIN UserGroupList_UserGroup_State = 0 // The user is an admin with additional privileges. - UserGroupList_UserGroup_ADMIN UserGroupList_UserGroup_State = 2 + UserGroupList_UserGroup_ADMIN UserGroupList_UserGroup_State = 1 // The user is a regular member. - UserGroupList_UserGroup_MEMBER UserGroupList_UserGroup_State = 3 + UserGroupList_UserGroup_MEMBER UserGroupList_UserGroup_State = 2 // The user has requested to join the group - UserGroupList_UserGroup_JOIN_REQUEST UserGroupList_UserGroup_State = 4 + UserGroupList_UserGroup_JOIN_REQUEST UserGroupList_UserGroup_State = 3 ) var UserGroupList_UserGroup_State_name = map[int32]string{ - 0: "STATE_UNSPECIFIED", - 1: "SUPERADMIN", - 2: "ADMIN", - 3: "MEMBER", - 4: "JOIN_REQUEST", + 0: "SUPERADMIN", + 1: "ADMIN", + 2: "MEMBER", + 3: "JOIN_REQUEST", } var UserGroupList_UserGroup_State_value = map[string]int32{ - "STATE_UNSPECIFIED": 0, - "SUPERADMIN": 1, - "ADMIN": 2, - "MEMBER": 3, - "JOIN_REQUEST": 4, + "SUPERADMIN": 0, + "ADMIN": 1, + "MEMBER": 2, + "JOIN_REQUEST": 3, } func (x UserGroupList_UserGroup_State) String() string { @@ -1668,10 +1656,10 @@ type Friend struct { // The user object. User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` // The friend status. - State int32 `protobuf:"varint,2,opt,name=state,proto3" json:"state,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + State *wrappers.Int32Value `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Friend) Reset() { *m = Friend{} } @@ -1706,11 +1694,11 @@ func (m *Friend) GetUser() *User { return nil } -func (m *Friend) GetState() int32 { +func (m *Friend) GetState() *wrappers.Int32Value { if m != nil { return m.State } - return 0 + return nil } // A collection of zero or more friends of the user. @@ -2049,10 +2037,10 @@ type GroupUserList_GroupUser struct { // User. User *User `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` // Their relationship to the group. - State int32 `protobuf:"varint,2,opt,name=state,proto3" json:"state,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + State *wrappers.Int32Value `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *GroupUserList_GroupUser) Reset() { *m = GroupUserList_GroupUser{} } @@ -2087,11 +2075,11 @@ func (m *GroupUserList_GroupUser) GetUser() *User { return nil } -func (m *GroupUserList_GroupUser) GetState() int32 { +func (m *GroupUserList_GroupUser) GetState() *wrappers.Int32Value { if m != nil { return m.State } - return 0 + return nil } // Import Facebook friends into the current user's account. @@ -4846,10 +4834,10 @@ type UserGroupList_UserGroup struct { // Group. Group *Group `protobuf:"bytes,1,opt,name=group,proto3" json:"group,omitempty"` // The user's relationship to the group. - State int32 `protobuf:"varint,2,opt,name=state,proto3" json:"state,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + State *wrappers.Int32Value `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *UserGroupList_UserGroup) Reset() { *m = UserGroupList_UserGroup{} } @@ -4884,11 +4872,11 @@ func (m *UserGroupList_UserGroup) GetGroup() *Group { return nil } -func (m *UserGroupList_UserGroup) GetState() int32 { +func (m *UserGroupList_UserGroup) GetState() *wrappers.Int32Value { if m != nil { return m.State } - return 0 + return nil } // A collection of zero or more users. @@ -5377,210 +5365,209 @@ func init() { func init() { proto.RegisterFile("api/api.proto", fileDescriptor_1b40cafcd4234784) } var fileDescriptor_1b40cafcd4234784 = []byte{ - // 3274 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x1a, 0x4d, 0x8f, 0x1b, 0x49, - 0x95, 0xf6, 0xb7, 0x9f, 0xc7, 0x33, 0x9e, 0xca, 0x07, 0xce, 0xe4, 0x73, 0x7b, 0xb3, 0x24, 0xab, - 0x85, 0xc9, 0x32, 0x61, 0x49, 0x60, 0x21, 0x9b, 0xf9, 0x70, 0x22, 0x6f, 0x92, 0x49, 0x68, 0xcf, - 0x64, 0x11, 0x08, 0x79, 0x6b, 0xba, 0x2b, 0x4e, 0x33, 0xed, 0x6e, 0x6f, 0x77, 0x7b, 0x32, 0xb3, - 0x12, 0x12, 0x42, 0x48, 0xec, 0x09, 0x21, 0x4e, 0x5c, 0x80, 0x15, 0x7b, 0x59, 0x81, 0xc4, 0x2f, - 0xe0, 0xce, 0x1d, 0x09, 0xb4, 0x37, 0xe0, 0x88, 0xc4, 0x0f, 0x40, 0xda, 0x0b, 0xaa, 0x57, 0xd5, - 0xed, 0xea, 0xb6, 0x3d, 0xb6, 0x33, 0x93, 0x20, 0x71, 0xb1, 0xba, 0x5e, 0xbd, 0x57, 0xf5, 0xea, - 0xd5, 0xfb, 0x2e, 0x43, 0x95, 0xf6, 0xec, 0x6b, 0xb4, 0x67, 0x2f, 0xf7, 0x7c, 0x2f, 0xf4, 0x08, - 0xb8, 0x74, 0x97, 0x76, 0xe9, 0x32, 0xed, 0xd9, 0x4b, 0x17, 0x3b, 0x9e, 0xd7, 0x71, 0xd8, 0x35, - 0x9c, 0xd9, 0xe9, 0x3f, 0xb9, 0x16, 0xda, 0x5d, 0x16, 0x84, 0xb4, 0xdb, 0x13, 0xc8, 0x4b, 0x17, - 0xd2, 0x08, 0xcf, 0x7c, 0xda, 0xeb, 0x31, 0x3f, 0x10, 0xf3, 0xfa, 0xbf, 0x35, 0x28, 0xae, 0x9a, - 0xa6, 0xd7, 0x77, 0x43, 0x72, 0x19, 0x72, 0xfd, 0x80, 0xf9, 0x75, 0xed, 0x92, 0x76, 0xb5, 0xb2, - 0x52, 0x5b, 0x1e, 0xec, 0xb3, 0xbc, 0x1d, 0x30, 0xdf, 0xc0, 0x59, 0x72, 0x1a, 0x0a, 0xcf, 0xa8, - 0xe3, 0xb0, 0xb0, 0x9e, 0xb9, 0xa4, 0x5d, 0x2d, 0x1b, 0x72, 0x44, 0x4e, 0x42, 0x9e, 0x75, 0xa9, - 0xed, 0xd4, 0xb3, 0x08, 0x16, 0x03, 0x72, 0x1d, 0x8a, 0x16, 0xdb, 0xb3, 0x4d, 0x16, 0xd4, 0x73, - 0x97, 0xb2, 0x57, 0x2b, 0x2b, 0x67, 0xd4, 0x65, 0xe5, 0xce, 0x1b, 0x88, 0x61, 0x44, 0x98, 0xe4, - 0x2c, 0x94, 0xcd, 0x7e, 0x10, 0x7a, 0xdd, 0xb6, 0x6d, 0xd5, 0xf3, 0xb8, 0x5c, 0x49, 0x00, 0x9a, - 0x16, 0x79, 0x1b, 0x2a, 0x7b, 0xcc, 0xb7, 0x9f, 0x1c, 0xb4, 0xf9, 0x59, 0xeb, 0x05, 0x64, 0x76, - 0x69, 0x59, 0x9c, 0x73, 0x39, 0x3a, 0xe7, 0xf2, 0x56, 0x24, 0x08, 0x03, 0x04, 0x3a, 0x07, 0xe8, - 0x17, 0xa1, 0x2a, 0xf7, 0x5c, 0xc7, 0xf5, 0xc8, 0x3c, 0x64, 0x6c, 0x0b, 0x4f, 0x5c, 0x36, 0x32, - 0xb6, 0xa5, 0x20, 0x08, 0xa6, 0x86, 0x10, 0x6e, 0xc3, 0x9c, 0x44, 0x68, 0xe0, 0x01, 0xe3, 0x63, - 0x6b, 0xea, 0xb1, 0x97, 0xa0, 0xd4, 0xa3, 0x41, 0xf0, 0xcc, 0xf3, 0x2d, 0x29, 0xa6, 0x78, 0xac, - 0x5f, 0x81, 0x05, 0xb9, 0xc2, 0x1d, 0x6a, 0xb2, 0x1d, 0xcf, 0xdb, 0xe5, 0x8b, 0x84, 0xde, 0x2e, - 0x73, 0xa3, 0x45, 0x70, 0xa0, 0xff, 0x45, 0x83, 0x45, 0x89, 0x79, 0x97, 0x76, 0xd9, 0x3a, 0x73, - 0x43, 0xe6, 0x73, 0xe1, 0xf4, 0x1c, 0x7a, 0xc0, 0xfc, 0x76, 0xcc, 0x57, 0x49, 0x00, 0x9a, 0x16, - 0x9f, 0xdc, 0xe9, 0xbb, 0x96, 0xc3, 0xf8, 0xa4, 0xdc, 0x58, 0x00, 0x9a, 0x16, 0x79, 0x03, 0x16, - 0x63, 0xf5, 0x68, 0x07, 0xcc, 0xf4, 0x5c, 0x2b, 0xc0, 0xdb, 0xca, 0x1a, 0xb5, 0x78, 0xa2, 0x25, - 0xe0, 0x84, 0x40, 0x2e, 0xa0, 0x4e, 0x58, 0xcf, 0xe1, 0x22, 0xf8, 0x4d, 0xce, 0x41, 0x39, 0xb0, - 0x3b, 0x2e, 0x0d, 0xfb, 0x3e, 0x93, 0xf7, 0x32, 0x00, 0x90, 0xcb, 0x30, 0xdf, 0xeb, 0xef, 0x38, - 0xb6, 0xd9, 0xde, 0x65, 0x07, 0xed, 0xbe, 0xef, 0xe0, 0xdd, 0x94, 0x8d, 0x39, 0x01, 0xbd, 0xc7, - 0x0e, 0xb6, 0x7d, 0x47, 0x7f, 0x2d, 0x16, 0xf0, 0x5d, 0xbc, 0xb1, 0x31, 0x67, 0xbf, 0x1c, 0x8b, - 0xb9, 0x15, 0x32, 0xda, 0x1d, 0x83, 0xb5, 0x0e, 0x8b, 0xab, 0x96, 0x75, 0xc7, 0xb7, 0x99, 0x6b, - 0x05, 0x06, 0xfb, 0xa0, 0xcf, 0x82, 0x90, 0xd4, 0x20, 0x6b, 0x5b, 0x41, 0x5d, 0xbb, 0x94, 0xbd, - 0x5a, 0x36, 0xf8, 0x27, 0xe7, 0x9b, 0xab, 0xae, 0x4b, 0xbb, 0x2c, 0xa8, 0x67, 0x10, 0x3e, 0x00, - 0xe8, 0xf7, 0xe1, 0xe4, 0xaa, 0x65, 0xdd, 0xf5, 0xbd, 0x7e, 0x8f, 0xab, 0x79, 0xbc, 0xce, 0x19, - 0x28, 0x75, 0x38, 0x70, 0x20, 0xe7, 0x22, 0x8e, 0x9b, 0x16, 0x9f, 0xe2, 0xf4, 0x6d, 0xbe, 0x8f, - 0x58, 0xaf, 0xc8, 0xc7, 0x4d, 0x2b, 0xd0, 0x3f, 0xd6, 0xe0, 0xcc, 0x6a, 0x3f, 0x7c, 0xca, 0xdc, - 0xd0, 0x36, 0x69, 0xc8, 0x84, 0x9e, 0x45, 0x6b, 0x5e, 0x87, 0x22, 0x15, 0xc7, 0x92, 0x56, 0x36, - 0xca, 0x1c, 0x24, 0x49, 0x84, 0x49, 0x56, 0xa0, 0x60, 0xfa, 0x8c, 0x86, 0x0c, 0x6f, 0x74, 0x94, - 0xb2, 0xaf, 0x79, 0x9e, 0xf3, 0x98, 0x3a, 0x7d, 0x66, 0x48, 0x4c, 0xae, 0x80, 0xd1, 0x09, 0xa5, - 0x41, 0xc6, 0xe3, 0x21, 0x16, 0xa5, 0xf9, 0xcd, 0xc2, 0x62, 0x64, 0xb1, 0x2f, 0x8a, 0xc5, 0xdf, - 0x68, 0x50, 0x57, 0x59, 0x44, 0x5b, 0x8b, 0x38, 0x5c, 0x49, 0x73, 0x58, 0x1f, 0xc1, 0xa1, 0xa0, - 0x78, 0x61, 0x0c, 0x7e, 0xa6, 0xc1, 0x59, 0x95, 0xc1, 0xc8, 0x94, 0x23, 0x1e, 0xdf, 0x4a, 0xf3, - 0x78, 0x76, 0x04, 0x8f, 0x31, 0xd1, 0x8b, 0x62, 0x93, 0xaf, 0x67, 0x77, 0x7b, 0x9e, 0x2f, 0xec, - 0x78, 0xc2, 0x7a, 0x02, 0x53, 0xff, 0x54, 0x83, 0xf3, 0xea, 0xd1, 0x06, 0xbe, 0x27, 0x3a, 0xdc, - 0x8d, 0xf4, 0xe1, 0xce, 0x8f, 0x38, 0x9c, 0x42, 0xf6, 0xd2, 0x34, 0x59, 0xb8, 0x94, 0x99, 0x34, - 0x59, 0x92, 0xbc, 0x34, 0x4d, 0x46, 0x77, 0x36, 0x93, 0x26, 0x0b, 0x8a, 0x17, 0xc6, 0x60, 0x03, - 0x4e, 0xac, 0x39, 0x9e, 0xb9, 0x7b, 0x44, 0x2f, 0xfa, 0x51, 0x16, 0xe6, 0xd7, 0x9f, 0x52, 0xd7, - 0x65, 0xce, 0x03, 0x16, 0x04, 0xb4, 0xc3, 0xc8, 0x79, 0x00, 0x53, 0x40, 0x06, 0x2e, 0xb4, 0x2c, - 0x21, 0x4d, 0x8b, 0x4f, 0x77, 0x05, 0xe6, 0x20, 0x58, 0x95, 0x25, 0xa4, 0x69, 0x91, 0x6b, 0x90, - 0x33, 0x3d, 0x4b, 0xf0, 0xcb, 0xcd, 0x27, 0x7d, 0xca, 0xa6, 0x1b, 0x5e, 0x5f, 0x11, 0xc7, 0x44, - 0x44, 0x1e, 0xfb, 0x02, 0xe6, 0x5a, 0x22, 0x30, 0x8a, 0xb0, 0x55, 0x12, 0x80, 0xa6, 0x95, 0x90, - 0x40, 0x3e, 0x65, 0x24, 0x75, 0x28, 0x9a, 0x9e, 0x1b, 0x32, 0x37, 0x94, 0x11, 0x2b, 0x1a, 0xf2, - 0x5c, 0x43, 0x48, 0x50, 0xe4, 0x1a, 0xc5, 0xc9, 0xb9, 0x86, 0x40, 0xe7, 0x00, 0x4e, 0xdc, 0xef, - 0x59, 0x31, 0x71, 0x69, 0x32, 0xb1, 0x40, 0x47, 0xe2, 0x6f, 0x02, 0xf0, 0x2c, 0xcd, 0x0e, 0x90, - 0xad, 0xf2, 0xc4, 0x9b, 0x56, 0xb0, 0xf5, 0x9f, 0x6b, 0x40, 0x92, 0x57, 0x71, 0xdf, 0x0e, 0x42, - 0xf2, 0x75, 0x28, 0x49, 0xe9, 0x8a, 0x6b, 0xe5, 0x0b, 0x2a, 0xda, 0x96, 0xa4, 0x30, 0x62, 0x5c, - 0x72, 0x11, 0x2a, 0x2e, 0xdb, 0x0f, 0xdb, 0x66, 0xdf, 0x0f, 0x3c, 0x5f, 0x5e, 0x14, 0x70, 0xd0, - 0x3a, 0x42, 0x38, 0x42, 0xcf, 0x67, 0x7b, 0x11, 0x82, 0x50, 0x30, 0xe0, 0x20, 0x81, 0xa0, 0xff, - 0x8a, 0x33, 0x84, 0x82, 0xc1, 0x28, 0x1b, 0xa9, 0x18, 0x81, 0x1c, 0xde, 0x87, 0xd0, 0x0c, 0xfc, - 0x26, 0x97, 0xa0, 0x62, 0xb1, 0xc0, 0xf4, 0xed, 0x5e, 0x68, 0x7b, 0xae, 0xdc, 0x4c, 0x05, 0xf1, - 0xd8, 0xeb, 0x50, 0xb7, 0xd3, 0x0e, 0x69, 0x47, 0x6e, 0x55, 0xe4, 0xe3, 0x2d, 0xda, 0xe1, 0x1a, - 0x45, 0xf7, 0x68, 0x48, 0x7d, 0xcc, 0x3e, 0x84, 0x0a, 0x94, 0x05, 0x64, 0xdb, 0x77, 0xf8, 0x7e, - 0x5e, 0x8f, 0xb9, 0x78, 0xff, 0x25, 0x03, 0xbf, 0xf5, 0x3b, 0x70, 0x72, 0x83, 0x39, 0x2c, 0x64, - 0x47, 0x54, 0xff, 0x6b, 0x40, 0xc4, 0x3a, 0x89, 0x13, 0x8e, 0x4f, 0x21, 0xf4, 0xbb, 0x70, 0x41, - 0x10, 0xdc, 0x67, 0xd4, 0x62, 0xfe, 0x8e, 0x47, 0x7d, 0xcb, 0x60, 0xa6, 0xc7, 0x7f, 0x05, 0xf1, - 0x6b, 0x30, 0xef, 0x0c, 0xe6, 0x06, 0x4b, 0x54, 0x15, 0x68, 0xd3, 0xd2, 0x97, 0x61, 0x49, 0x2c, - 0xb4, 0xe9, 0x85, 0xf6, 0x13, 0xee, 0x63, 0x6c, 0xcf, 0x1d, 0x7f, 0x0e, 0xdd, 0x84, 0x53, 0x02, - 0xbf, 0x15, 0x7a, 0x3e, 0xed, 0xb0, 0x87, 0x3b, 0x3f, 0x64, 0x66, 0xd8, 0xb4, 0xc8, 0x05, 0x00, - 0xd3, 0x73, 0x1c, 0x66, 0xa2, 0xe4, 0xc5, 0x5e, 0x0a, 0x84, 0x2f, 0xb5, 0xcb, 0x0e, 0xe4, 0x95, - 0xf0, 0x4f, 0x6e, 0x38, 0x7b, 0x5c, 0xed, 0x3c, 0x37, 0xba, 0x09, 0x39, 0xd4, 0xdb, 0x70, 0x76, - 0xc4, 0x26, 0x31, 0x57, 0xb7, 0x01, 0x3c, 0x84, 0xb4, 0x23, 0xe6, 0x2a, 0x2b, 0xaf, 0xa8, 0xca, - 0x38, 0x92, 0x43, 0xa3, 0xec, 0xc9, 0xaf, 0x40, 0xff, 0x44, 0x83, 0x82, 0xb8, 0xb2, 0x29, 0xcb, - 0x96, 0x93, 0x90, 0x0f, 0xc2, 0xc8, 0x6b, 0xe6, 0x0d, 0x31, 0xd0, 0x7f, 0x00, 0xf9, 0x16, 0xff, - 0x20, 0xa7, 0x60, 0xb1, 0xb5, 0xb5, 0xba, 0xd5, 0x68, 0x6f, 0x6f, 0xb6, 0x1e, 0x35, 0xd6, 0x9b, - 0x77, 0x9a, 0x8d, 0x8d, 0xda, 0x17, 0x08, 0x40, 0xe1, 0x8e, 0xd1, 0x6c, 0x6c, 0x6e, 0xd4, 0x34, - 0xb2, 0x00, 0x95, 0xe6, 0xe6, 0xe3, 0xe6, 0x56, 0xa3, 0xdd, 0x6a, 0x6c, 0x6e, 0xd5, 0x32, 0xe4, - 0x04, 0x2c, 0x48, 0x80, 0xd1, 0x58, 0x6f, 0x34, 0x1f, 0x37, 0x36, 0x6a, 0x59, 0x52, 0x81, 0xe2, - 0xda, 0xfd, 0x87, 0xeb, 0xf7, 0x1a, 0x1b, 0xb5, 0x9c, 0x7e, 0x03, 0x8a, 0x52, 0xaf, 0xc8, 0x97, - 0xa1, 0xf8, 0x44, 0x7c, 0xca, 0xf3, 0x12, 0x95, 0x51, 0x81, 0x65, 0x44, 0x28, 0xba, 0x05, 0x0b, - 0x77, 0x59, 0x98, 0x48, 0x47, 0x67, 0xd4, 0x48, 0xf2, 0x0a, 0xcc, 0x3d, 0x91, 0xf9, 0x05, 0x4a, - 0x39, 0x8b, 0x08, 0x95, 0x08, 0xc6, 0x85, 0xf8, 0x69, 0x16, 0xf2, 0xa8, 0xaf, 0xe9, 0x2a, 0x07, - 0x5d, 0x37, 0x37, 0x58, 0xcf, 0x57, 0x7c, 0xb3, 0x84, 0x34, 0xad, 0xd8, 0x72, 0xb3, 0xe3, 0x2d, - 0x37, 0x77, 0xb8, 0xe5, 0xe6, 0x93, 0x96, 0xbb, 0xc4, 0x7d, 0x53, 0x48, 0x2d, 0x1a, 0x52, 0xe9, - 0x83, 0xe3, 0x71, 0xca, 0xaa, 0x8b, 0x69, 0xab, 0x5e, 0x96, 0x56, 0x5d, 0x9a, 0xe8, 0x23, 0x11, - 0x8f, 0x2f, 0xc7, 0xac, 0x0e, 0x6b, 0x8b, 0xb0, 0x5b, 0x46, 0x6d, 0x28, 0x73, 0xc8, 0x3a, 0x86, - 0xd7, 0xb3, 0x50, 0xee, 0xd2, 0x7d, 0x39, 0x0b, 0x38, 0x5b, 0xea, 0xd2, 0x7d, 0x31, 0x99, 0x8a, - 0x07, 0x95, 0xa3, 0xc4, 0x83, 0xb9, 0x59, 0xe2, 0x81, 0xbe, 0x09, 0x65, 0xbc, 0x29, 0xf4, 0xe4, - 0xaf, 0x43, 0x01, 0xdd, 0x48, 0xa4, 0x4a, 0x8b, 0xaa, 0x2a, 0x09, 0x07, 0x24, 0x11, 0x78, 0xb5, - 0x9e, 0xf0, 0xdb, 0x72, 0xa4, 0xff, 0x47, 0x83, 0x6a, 0x5c, 0xf2, 0xe0, 0xa2, 0x1b, 0x50, 0x11, - 0xbe, 0x8a, 0xab, 0x50, 0xb4, 0xf2, 0xab, 0x43, 0x2b, 0x47, 0xf8, 0x83, 0x91, 0x01, 0x9d, 0xb8, - 0x76, 0x5a, 0xfa, 0x58, 0x93, 0x8c, 0xf2, 0xe1, 0x91, 0x4c, 0xf3, 0xbd, 0x09, 0xa6, 0x39, 0x0f, - 0xd0, 0xda, 0x7e, 0xd4, 0x30, 0x56, 0x37, 0x1e, 0x34, 0x37, 0x6b, 0x1a, 0x29, 0x43, 0x5e, 0x7c, - 0x66, 0xb8, 0xd5, 0x3e, 0x68, 0x3c, 0x58, 0x6b, 0x18, 0xb5, 0x2c, 0xa9, 0xc1, 0xdc, 0xbb, 0x0f, - 0x9b, 0x9b, 0x6d, 0xa3, 0xf1, 0x9d, 0xed, 0x46, 0x6b, 0xab, 0x96, 0xd3, 0x7f, 0xa6, 0xc1, 0xb9, - 0x26, 0xa6, 0xba, 0x51, 0xfe, 0x9d, 0xf2, 0xfd, 0xcf, 0x99, 0xbb, 0xbf, 0x09, 0x79, 0x9f, 0x05, - 0xb2, 0x2f, 0x72, 0xb8, 0x26, 0x0a, 0x44, 0xfd, 0x2b, 0x50, 0x7b, 0xd7, 0xb3, 0xdd, 0x69, 0x43, - 0xc6, 0xb7, 0xe0, 0x14, 0x47, 0xdf, 0xf2, 0xfa, 0x68, 0xe2, 0x6e, 0x18, 0xd1, 0xbc, 0x0a, 0xd5, - 0x30, 0x06, 0x0e, 0x08, 0xe7, 0x06, 0xc0, 0xa6, 0xa5, 0x3f, 0x80, 0x53, 0xf7, 0x6c, 0x73, 0xf7, - 0xb8, 0xea, 0xdc, 0x7f, 0x65, 0x61, 0x71, 0x28, 0x74, 0x4d, 0x19, 0xb3, 0xf8, 0xba, 0xde, 0x33, - 0x97, 0x29, 0xce, 0xa5, 0x88, 0xe3, 0xa6, 0x45, 0x6e, 0xa6, 0x52, 0xd5, 0xca, 0xca, 0xb9, 0x21, - 0x41, 0xb6, 0x42, 0xdf, 0x76, 0x3b, 0x42, 0x94, 0x83, 0x34, 0x8e, 0xab, 0x91, 0xe9, 0xf9, 0x0c, - 0x5d, 0x4f, 0xd6, 0x10, 0x03, 0xee, 0x59, 0x82, 0xfe, 0x8e, 0x98, 0xc8, 0xe3, 0x44, 0x3c, 0xe6, - 0xb6, 0xee, 0xf6, 0xbb, 0x6d, 0x31, 0x59, 0x10, 0xb6, 0xee, 0xf6, 0xbb, 0xad, 0x88, 0x30, 0x76, - 0x49, 0xc5, 0x94, 0x4b, 0x4a, 0xf9, 0x81, 0xd2, 0x51, 0xfc, 0x40, 0x79, 0xa6, 0xbc, 0xf0, 0x6d, - 0xa8, 0xb0, 0xfd, 0x9e, 0xed, 0xcb, 0xee, 0x17, 0x4c, 0x26, 0x16, 0xe8, 0x48, 0x4c, 0x20, 0xe7, - 0x53, 0x77, 0x17, 0xfd, 0x56, 0xd6, 0xc0, 0x6f, 0xa2, 0x43, 0x95, 0xfb, 0xbb, 0x81, 0x1c, 0xb8, - 0x5f, 0xaa, 0x1a, 0x95, 0x2e, 0xdd, 0xdf, 0x94, 0xa2, 0xd0, 0xff, 0xa6, 0xc1, 0xa9, 0xa1, 0xbb, - 0x46, 0xa7, 0x71, 0x03, 0x8a, 0x3e, 0x8e, 0x22, 0x87, 0x91, 0xa8, 0x04, 0x87, 0x53, 0x9b, 0x08, - 0x9b, 0xac, 0x41, 0x55, 0x68, 0x40, 0x44, 0x9e, 0x99, 0x86, 0x7c, 0x0e, 0x69, 0x0c, 0xb9, 0x46, - 0x2a, 0x31, 0xcd, 0x4e, 0x4a, 0x4c, 0x73, 0x43, 0x89, 0xe9, 0x32, 0xea, 0xf0, 0xde, 0xd4, 0x49, - 0xdb, 0x8f, 0x35, 0x38, 0x71, 0xdf, 0x76, 0x77, 0x8f, 0xaf, 0xda, 0x9f, 0xb9, 0x3a, 0xff, 0x93, - 0x06, 0x4b, 0x5c, 0xf4, 0xc9, 0x74, 0x3d, 0x36, 0xe6, 0x09, 0x35, 0xd7, 0x57, 0x21, 0xef, 0xd8, - 0x5d, 0x3b, 0xf2, 0x51, 0x87, 0x56, 0x55, 0x02, 0x93, 0x7c, 0x0d, 0x8a, 0x4f, 0x3c, 0xff, 0x19, - 0xf5, 0x2d, 0x69, 0x8f, 0x87, 0x71, 0x19, 0xa1, 0x2a, 0x71, 0x27, 0x97, 0x88, 0x3b, 0x3e, 0x2c, - 0x72, 0xee, 0x51, 0xe0, 0xc1, 0x61, 0x85, 0xc0, 0x98, 0xc0, 0x35, 0x38, 0x41, 0x76, 0xda, 0x13, - 0xe8, 0x2b, 0x70, 0x2a, 0xde, 0x73, 0x4a, 0xcf, 0xa7, 0x7f, 0xac, 0xc1, 0x55, 0x4e, 0x34, 0xa4, - 0x83, 0xc1, 0xaa, 0xef, 0xf5, 0x5d, 0xeb, 0xa1, 0x50, 0xc4, 0x59, 0x32, 0x75, 0xb2, 0x92, 0x14, - 0xfe, 0xb0, 0x5f, 0xdb, 0x1e, 0x96, 0xbe, 0xea, 0x29, 0xb3, 0x09, 0x4f, 0xa9, 0xff, 0x51, 0x83, - 0xf3, 0xa3, 0x59, 0x9c, 0x91, 0xaf, 0xb3, 0x50, 0x8e, 0xf6, 0x88, 0xdc, 0x7c, 0x49, 0x6e, 0x12, - 0x3c, 0x87, 0xbc, 0xc7, 0xde, 0xfd, 0x3f, 0x33, 0x40, 0x38, 0xc3, 0x0f, 0x68, 0x68, 0x3e, 0x1d, - 0xa8, 0x6c, 0xbc, 0x83, 0x36, 0xf5, 0x0e, 0xb7, 0xa1, 0x4a, 0xfb, 0xe1, 0x53, 0xcf, 0xb7, 0x43, - 0x1a, 0xda, 0x7b, 0xd3, 0xb4, 0x42, 0x92, 0x04, 0x78, 0x17, 0x74, 0x87, 0x39, 0x53, 0xc5, 0x18, - 0x81, 0x8a, 0x05, 0xb4, 0xed, 0xb6, 0x03, 0xfb, 0x43, 0x26, 0x0d, 0xf6, 0x50, 0x5e, 0x8b, 0x5d, - 0xdb, 0x6d, 0xd9, 0x1f, 0x32, 0xa4, 0xa3, 0xfb, 0x82, 0x2e, 0x3f, 0x0d, 0x1d, 0xdd, 0x47, 0xba, - 0x15, 0xc8, 0x7f, 0xd0, 0x67, 0xfe, 0x81, 0x7c, 0xe3, 0x98, 0xc0, 0x23, 0xa2, 0xea, 0xfb, 0x50, - 0xe7, 0x22, 0x1e, 0x59, 0x0b, 0x3e, 0x87, 0xa0, 0x5f, 0x87, 0x9a, 0x49, 0xcd, 0xa7, 0x8c, 0xee, - 0x38, 0x2c, 0xd9, 0x00, 0x58, 0x88, 0xe1, 0xd2, 0x97, 0xfe, 0x56, 0x83, 0x33, 0x7c, 0xeb, 0xd1, - 0x15, 0xdf, 0x17, 0xa1, 0x28, 0x33, 0x09, 0xa9, 0x83, 0x05, 0x91, 0x48, 0xa4, 0xaa, 0xce, 0xcc, - 0x50, 0xd5, 0x79, 0x8c, 0xfa, 0xf7, 0x6b, 0x0d, 0xae, 0x70, 0x0e, 0xd5, 0x04, 0x6a, 0x9c, 0x49, - 0x4f, 0x93, 0x52, 0x1d, 0xb7, 0x41, 0xff, 0x41, 0x83, 0x73, 0x23, 0xf9, 0x9b, 0x89, 0xa9, 0x97, - 0x65, 0xcd, 0x7f, 0xcf, 0xc0, 0xe9, 0x24, 0xb7, 0x31, 0x9f, 0xeb, 0x30, 0x6f, 0xd2, 0x90, 0x75, - 0x3c, 0xff, 0xa0, 0x1d, 0x84, 0xd4, 0x8f, 0x34, 0xee, 0x70, 0x01, 0x55, 0x23, 0x9a, 0x16, 0x27, - 0x21, 0xef, 0xc0, 0x5c, 0xbc, 0x08, 0x73, 0xad, 0xa9, 0x64, 0x5c, 0x89, 0x28, 0x1a, 0xae, 0x45, - 0xde, 0x06, 0xc0, 0xcd, 0x45, 0xa6, 0x94, 0x9d, 0x82, 0xbc, 0x8c, 0xf8, 0x98, 0x2a, 0xdd, 0x80, - 0x12, 0x73, 0x2d, 0x41, 0x9a, 0x9b, 0x82, 0xb4, 0xc8, 0x5c, 0x0b, 0x09, 0x63, 0x09, 0x17, 0x9e, - 0x43, 0xc2, 0xa5, 0x84, 0x84, 0xdf, 0x14, 0x71, 0x8b, 0x87, 0xac, 0x64, 0xbc, 0x1c, 0x67, 0x4c, - 0xfa, 0x2f, 0x34, 0xc8, 0xa3, 0x77, 0xe5, 0x6a, 0xd6, 0xe5, 0x1f, 0x4a, 0x68, 0xc3, 0x71, 0xd3, - 0x22, 0x97, 0x47, 0x39, 0xcf, 0xd2, 0x71, 0x38, 0x48, 0x02, 0xb9, 0xd8, 0x39, 0xe6, 0x0d, 0xfc, - 0xd6, 0x6f, 0x42, 0x19, 0x39, 0xc2, 0x74, 0xf1, 0x0d, 0x10, 0x5c, 0xb0, 0x91, 0x95, 0x2b, 0xe2, - 0x19, 0x11, 0x86, 0xfe, 0x0f, 0x0d, 0xe6, 0x54, 0x3f, 0x36, 0xd4, 0xa4, 0xa8, 0x43, 0x31, 0xe8, - 0xa3, 0x9b, 0x89, 0x8a, 0x08, 0x39, 0x54, 0x3b, 0xba, 0xd9, 0x64, 0x47, 0x97, 0xc8, 0xae, 0xb2, - 0x64, 0x71, 0xb8, 0x71, 0x9c, 0x4f, 0x35, 0x8e, 0x53, 0xa9, 0x7e, 0x61, 0xa6, 0x54, 0xff, 0x42, - 0xa2, 0x8b, 0x5b, 0x44, 0x39, 0xab, 0x9d, 0xda, 0x1f, 0x41, 0x4d, 0x3d, 0x21, 0xca, 0xe8, 0x16, - 0x54, 0x5d, 0xd5, 0x7b, 0x4b, 0x49, 0x25, 0x5e, 0x06, 0x54, 0x22, 0x23, 0x89, 0x3e, 0x8b, 0xcb, - 0x7e, 0x04, 0xf5, 0x47, 0xbe, 0xd7, 0xf5, 0x64, 0xd7, 0xf2, 0x18, 0xaa, 0xc2, 0xf7, 0xe1, 0x84, - 0xc1, 0xa8, 0x75, 0xf4, 0xd6, 0xa2, 0xa2, 0xe2, 0xd9, 0x84, 0x8a, 0x7f, 0x1f, 0xce, 0x0c, 0xed, - 0x10, 0x33, 0x7d, 0x6b, 0x44, 0x5f, 0xf1, 0xa2, 0x2a, 0xb8, 0x11, 0xcc, 0xa9, 0x5d, 0xc5, 0x77, - 0x21, 0x6b, 0xf4, 0xcc, 0x51, 0x8a, 0xd6, 0xa3, 0x07, 0x8e, 0x47, 0xe3, 0x6a, 0x55, 0x0e, 0xb9, - 0x28, 0x9e, 0x86, 0x61, 0xaf, 0xcd, 0xb9, 0x97, 0x9a, 0xc6, 0xc7, 0xf7, 0xd8, 0x81, 0xfe, 0x18, - 0x8a, 0x2d, 0x16, 0x04, 0xfc, 0x78, 0x5c, 0x1d, 0x51, 0x29, 0xc4, 0xa2, 0x25, 0x23, 0x1a, 0x0e, - 0x9e, 0xb5, 0x33, 0xca, 0xb3, 0x36, 0x57, 0xc8, 0xbe, 0xd5, 0x6b, 0x8b, 0x99, 0xe8, 0xbd, 0xc6, - 0xea, 0x6d, 0xe1, 0x9b, 0xf7, 0x67, 0x19, 0xa8, 0x26, 0x8e, 0x70, 0x8c, 0xd2, 0xe5, 0xfc, 0xec, - 0x71, 0x8b, 0x96, 0xbe, 0x5e, 0x0c, 0xd4, 0x3e, 0x6f, 0x3e, 0xd1, 0xe7, 0x25, 0x57, 0x60, 0xa1, - 0xc7, 0xfc, 0xae, 0x8d, 0xe7, 0x6c, 0xfb, 0x8c, 0x5a, 0xb2, 0x8e, 0x9e, 0x1f, 0x80, 0xb9, 0xcc, - 0xb9, 0x56, 0x2a, 0x88, 0xcf, 0x7c, 0x3b, 0x14, 0xcf, 0x29, 0x79, 0x43, 0x59, 0xe0, 0x3d, 0x0e, - 0xfe, 0xdf, 0x15, 0xd7, 0xfa, 0x33, 0xa8, 0x25, 0x24, 0xbb, 0x6a, 0xee, 0x1e, 0x67, 0x57, 0x5c, - 0x15, 0x7b, 0x2e, 0xa1, 0xd4, 0x0d, 0x58, 0x4c, 0x6f, 0x1c, 0x90, 0x37, 0x21, 0x47, 0xcd, 0xdd, - 0x48, 0x8d, 0xcf, 0xa9, 0x6a, 0x9c, 0x46, 0x36, 0x10, 0x53, 0x6f, 0xc0, 0x7c, 0xd2, 0x2e, 0xc8, - 0x75, 0x28, 0x0a, 0xed, 0x8e, 0x96, 0x39, 0x33, 0x76, 0x19, 0x23, 0xc2, 0xd4, 0xdf, 0x4f, 0x71, - 0x83, 0x6e, 0xe9, 0x79, 0x56, 0x1a, 0xdb, 0x7d, 0xfc, 0x28, 0x07, 0x30, 0xc8, 0x1b, 0x86, 0xec, - 0x8d, 0x5b, 0x85, 0x1d, 0x3a, 0x2c, 0xb6, 0x0a, 0x3e, 0x48, 0x37, 0x98, 0xb3, 0xc3, 0x0d, 0xe6, - 0x25, 0x28, 0x45, 0x09, 0x00, 0x0a, 0xb8, 0x6a, 0xc4, 0x63, 0x5e, 0x18, 0x07, 0x9e, 0x1f, 0xb6, - 0x3d, 0xdf, 0x62, 0x3e, 0xaa, 0x71, 0xd5, 0x28, 0x73, 0xc8, 0x43, 0x0e, 0x88, 0x43, 0x57, 0x01, - 0x27, 0xf0, 0x5b, 0xc4, 0x50, 0x99, 0xb7, 0x17, 0x11, 0x1e, 0xa7, 0xe6, 0x43, 0x5d, 0x93, 0xd2, - 0x50, 0xd7, 0x04, 0xff, 0xc5, 0x44, 0xdd, 0x36, 0x3e, 0x81, 0xa3, 0x22, 0x96, 0x38, 0x3b, 0x6e, - 0x03, 0xff, 0xc5, 0x73, 0x1e, 0x80, 0xe7, 0x17, 0xd4, 0xc4, 0x08, 0x0c, 0x82, 0x1d, 0xe6, 0x5a, - 0xab, 0x08, 0xe0, 0xd3, 0xd8, 0xda, 0x10, 0x0d, 0xc5, 0x8a, 0x98, 0xe6, 0x10, 0x83, 0x03, 0x12, - 0xbd, 0xa9, 0xb9, 0xc3, 0x7b, 0x53, 0xd5, 0x99, 0xcc, 0xe7, 0x1b, 0x89, 0x9c, 0x69, 0x7e, 0x22, - 0xad, 0x92, 0x31, 0xbd, 0xa5, 0x64, 0x4c, 0x0b, 0x13, 0x09, 0xa3, 0x7c, 0x49, 0xdf, 0x81, 0xf9, - 0x81, 0x26, 0xa0, 0xa6, 0xdd, 0x84, 0xca, 0x20, 0xa1, 0x8d, 0xb4, 0xed, 0xb4, 0xaa, 0x6d, 0x4a, - 0x82, 0xac, 0xa2, 0x8e, 0x55, 0xb7, 0xbf, 0x6a, 0x70, 0x32, 0x9d, 0x54, 0xff, 0x3f, 0xb4, 0xaf, - 0x3e, 0xcf, 0xc0, 0xc9, 0x6d, 0x74, 0x5f, 0xb2, 0xc5, 0x14, 0xc5, 0x41, 0xb5, 0x89, 0xaa, 0xcd, - 0xd4, 0x44, 0x7d, 0x07, 0xe6, 0x2c, 0x3b, 0xe8, 0x39, 0xf4, 0xa0, 0x8d, 0xd4, 0x99, 0x29, 0xa8, - 0x2b, 0x92, 0x62, 0x93, 0xa2, 0x03, 0x56, 0x5f, 0x6b, 0xa6, 0x49, 0x1e, 0x95, 0xb7, 0x9c, 0x1b, - 0xca, 0x0b, 0x51, 0x6e, 0x0a, 0xd2, 0xf8, 0xfd, 0xe8, 0x26, 0x94, 0x1c, 0x4f, 0x64, 0x40, 0xb2, - 0xc4, 0x9e, 0x70, 0xe0, 0x08, 0x9b, 0x53, 0x72, 0x95, 0xfd, 0xd0, 0x73, 0xd9, 0x54, 0x75, 0x76, - 0x8c, 0xad, 0xff, 0x39, 0x03, 0x44, 0x48, 0x7f, 0xca, 0xf6, 0x21, 0xf7, 0xe8, 0x53, 0x0b, 0x55, - 0x74, 0xc1, 0x6e, 0x0d, 0xfb, 0xbc, 0xc9, 0xb7, 0xa1, 0x78, 0xc4, 0xe7, 0x16, 0x68, 0xf2, 0x1a, - 0xf3, 0xb3, 0x5d, 0x63, 0xf4, 0x24, 0x57, 0x98, 0xee, 0x49, 0x4e, 0xff, 0x65, 0x0e, 0x72, 0xf8, - 0x5e, 0x94, 0x0e, 0x04, 0xea, 0xbf, 0x36, 0x32, 0xa9, 0x7f, 0x6d, 0xbc, 0x92, 0xd2, 0xd4, 0x28, - 0x1e, 0x28, 0xba, 0x38, 0xe1, 0xff, 0x00, 0x87, 0xbf, 0x47, 0xc6, 0xfa, 0x24, 0xdf, 0x23, 0x63, - 0x8d, 0x59, 0x52, 0x34, 0x46, 0x3e, 0x0c, 0x44, 0xe3, 0x84, 0x63, 0x2e, 0xa5, 0x1c, 0xf3, 0x45, - 0xa8, 0x28, 0x0f, 0xb2, 0x18, 0x11, 0xca, 0x06, 0x0c, 0xde, 0x63, 0x79, 0xc0, 0x10, 0x92, 0xe2, - 0xd3, 0x20, 0xa8, 0x05, 0xa0, 0x69, 0xf1, 0xda, 0xbf, 0x43, 0xbb, 0xcc, 0xc4, 0x70, 0xc2, 0x11, - 0x2a, 0xa2, 0xf6, 0x1f, 0x00, 0x45, 0x66, 0x1e, 0x84, 0x8c, 0xe2, 0xff, 0x66, 0xe7, 0x64, 0x49, - 0xc4, 0xc7, 0x4d, 0x6c, 0xc8, 0x7a, 0xae, 0x63, 0xbb, 0x22, 0x22, 0x94, 0x0c, 0x39, 0x4a, 0x3d, - 0x87, 0xce, 0xa7, 0x9f, 0x43, 0x53, 0xd1, 0x64, 0xe1, 0x28, 0xc9, 0x58, 0x6d, 0xa6, 0x64, 0xec, - 0x73, 0x0d, 0xaa, 0x71, 0xe9, 0x1b, 0xbd, 0x50, 0x62, 0xfa, 0x94, 0x78, 0xfb, 0x7c, 0x35, 0xfd, - 0xa8, 0x18, 0xe3, 0x0f, 0x46, 0x06, 0xf4, 0xe3, 0x1a, 0x7a, 0xe9, 0x13, 0x0d, 0xca, 0xf1, 0x0c, - 0xb9, 0x02, 0x79, 0x5c, 0x4e, 0xba, 0xc9, 0x11, 0x2f, 0xa9, 0x62, 0xfe, 0x65, 0x3f, 0x52, 0x5e, - 0x83, 0x3c, 0x96, 0x63, 0xe4, 0x4b, 0x90, 0x57, 0x1f, 0x64, 0x87, 0xdf, 0x50, 0xc5, 0xb4, 0xfe, - 0x51, 0x06, 0xce, 0x63, 0xfe, 0x7c, 0xc4, 0xff, 0x93, 0x90, 0xef, 0x42, 0x41, 0x04, 0x35, 0xe9, - 0xa6, 0x6e, 0xab, 0x3b, 0x1e, 0xba, 0xc3, 0x70, 0xc4, 0x43, 0x74, 0x43, 0xae, 0xb7, 0xf4, 0x04, - 0x4e, 0x8f, 0xc6, 0x18, 0x3c, 0xdd, 0x69, 0xe3, 0x9e, 0xee, 0x32, 0xa9, 0xa7, 0x3b, 0xd5, 0xd0, - 0xb2, 0x49, 0x43, 0xd3, 0x7f, 0x9a, 0x01, 0x82, 0xeb, 0x1e, 0xb5, 0x4c, 0x8a, 0xab, 0xa1, 0xec, - 0x98, 0x6a, 0x28, 0x97, 0xcc, 0xef, 0x37, 0x86, 0xab, 0xa1, 0x29, 0xfa, 0xbd, 0xe9, 0x52, 0xe9, - 0xce, 0x88, 0x52, 0x69, 0x8a, 0x66, 0x52, 0xba, 0x8e, 0xd2, 0x1f, 0xc3, 0xd2, 0xb0, 0x14, 0x82, - 0x41, 0x8a, 0x90, 0xca, 0xe7, 0x2f, 0x0c, 0xdd, 0xf3, 0x98, 0xf2, 0xe0, 0x27, 0x19, 0x38, 0x87, - 0xf3, 0xe9, 0x94, 0x6a, 0xa6, 0x36, 0xe5, 0xe3, 0x94, 0x9a, 0xdd, 0x1a, 0xda, 0x7e, 0xcc, 0xf2, - 0xcb, 0x69, 0x78, 0x52, 0xc9, 0x18, 0x9c, 0x1a, 0x89, 0x70, 0xbc, 0x3a, 0xb6, 0xf6, 0x6d, 0x38, - 0x63, 0x7a, 0xdd, 0xe5, 0xa7, 0xcc, 0xf7, 0x6c, 0xd3, 0xa1, 0x3b, 0x81, 0xc2, 0xfe, 0x5a, 0x79, - 0x13, 0xbf, 0x57, 0x7b, 0xf6, 0x23, 0xed, 0x7b, 0x59, 0xda, 0xb3, 0x7f, 0x97, 0xc9, 0x6d, 0xde, - 0x7b, 0xb4, 0xf6, 0xfb, 0x4c, 0x41, 0xcc, 0xec, 0x14, 0xf0, 0x06, 0xaf, 0xff, 0x37, 0x00, 0x00, - 0xff, 0xff, 0xc1, 0x95, 0x2c, 0x41, 0xdb, 0x31, 0x00, 0x00, + // 3255 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x1a, 0x4d, 0x8f, 0x23, 0x47, + 0x35, 0xed, 0x6f, 0x3f, 0x8f, 0x67, 0x3c, 0xbd, 0x1f, 0x78, 0xbc, 0x9f, 0xe9, 0x6c, 0xd8, 0x8d, + 0x02, 0xb3, 0xc9, 0x2c, 0x61, 0x17, 0x02, 0x9b, 0x9d, 0x0f, 0xef, 0xca, 0xd9, 0xdd, 0xd9, 0xa5, + 0x67, 0x66, 0x41, 0x70, 0x70, 0x6a, 0xba, 0x6b, 0x3c, 0xcd, 0xb4, 0xbb, 0x9d, 0xee, 0xf6, 0x7c, + 0x44, 0x42, 0x02, 0x84, 0x44, 0x4e, 0x08, 0x71, 0xe2, 0x02, 0x44, 0x1c, 0x50, 0x02, 0x12, 0xbf, + 0x80, 0x3b, 0x77, 0x24, 0x50, 0x6e, 0xc0, 0x11, 0x89, 0x7f, 0x80, 0x84, 0x50, 0xbd, 0xaa, 0xee, + 0xae, 0x6e, 0xdb, 0x63, 0x7b, 0x67, 0x36, 0x91, 0xb8, 0x58, 0x5d, 0xaf, 0xde, 0xab, 0x7a, 0xf5, + 0xea, 0x7d, 0x97, 0xa1, 0x4a, 0x7a, 0xd6, 0x4d, 0xd2, 0xb3, 0x16, 0x7b, 0x9e, 0x1b, 0xb8, 0x2a, + 0x38, 0x64, 0x8f, 0x74, 0xc9, 0x22, 0xe9, 0x59, 0x8d, 0x2b, 0x1d, 0xd7, 0xed, 0xd8, 0xf4, 0x26, + 0xce, 0x6c, 0xf7, 0x77, 0x6e, 0x06, 0x56, 0x97, 0xfa, 0x01, 0xe9, 0xf6, 0x38, 0x72, 0xe3, 0x72, + 0x1a, 0xe1, 0xc0, 0x23, 0xbd, 0x1e, 0xf5, 0x7c, 0x3e, 0xaf, 0xfd, 0x5b, 0x81, 0xe2, 0xb2, 0x61, + 0xb8, 0x7d, 0x27, 0x50, 0xaf, 0x41, 0xae, 0xef, 0x53, 0xaf, 0xae, 0x5c, 0x55, 0x6e, 0x54, 0x96, + 0x6a, 0x8b, 0xf1, 0x3e, 0x8b, 0x5b, 0x3e, 0xf5, 0x74, 0x9c, 0x55, 0xcf, 0x43, 0xe1, 0x80, 0xd8, + 0x36, 0x0d, 0xea, 0x99, 0xab, 0xca, 0x8d, 0xb2, 0x2e, 0x46, 0xea, 0x59, 0xc8, 0xd3, 0x2e, 0xb1, + 0xec, 0x7a, 0x16, 0xc1, 0x7c, 0xa0, 0xde, 0x82, 0xa2, 0x49, 0xf7, 0x2d, 0x83, 0xfa, 0xf5, 0xdc, + 0xd5, 0xec, 0x8d, 0xca, 0xd2, 0x82, 0xbc, 0xac, 0xd8, 0x79, 0x0d, 0x31, 0xf4, 0x10, 0x53, 0xbd, + 0x00, 0x65, 0xa3, 0xef, 0x07, 0x6e, 0xb7, 0x6d, 0x99, 0xf5, 0x3c, 0x2e, 0x57, 0xe2, 0x80, 0x96, + 0xa9, 0xbe, 0x0d, 0x95, 0x7d, 0xea, 0x59, 0x3b, 0x47, 0x6d, 0x76, 0xd6, 0x7a, 0x01, 0x99, 0x6d, + 0x2c, 0xf2, 0x73, 0x2e, 0x86, 0xe7, 0x5c, 0xdc, 0x0c, 0x05, 0xa1, 0x03, 0x47, 0x67, 0x00, 0xed, + 0x0a, 0x54, 0xc5, 0x9e, 0xab, 0xb8, 0x9e, 0x3a, 0x0b, 0x19, 0xcb, 0xc4, 0x13, 0x97, 0xf5, 0x8c, + 0x65, 0x4a, 0x08, 0x9c, 0xa9, 0x01, 0x84, 0x7b, 0x30, 0x23, 0x10, 0x9a, 0x78, 0xc0, 0xe8, 0xd8, + 0x8a, 0x7c, 0xec, 0x06, 0x94, 0x7a, 0xc4, 0xf7, 0x0f, 0x5c, 0xcf, 0x14, 0x62, 0x8a, 0xc6, 0xda, + 0x75, 0x98, 0x13, 0x2b, 0xdc, 0x27, 0x06, 0xdd, 0x76, 0xdd, 0x3d, 0xb6, 0x48, 0xe0, 0xee, 0x51, + 0x27, 0x5c, 0x04, 0x07, 0xda, 0x5f, 0x14, 0x98, 0x17, 0x98, 0x0f, 0x48, 0x97, 0xae, 0x52, 0x27, + 0xa0, 0x1e, 0x13, 0x4e, 0xcf, 0x26, 0x47, 0xd4, 0x6b, 0x47, 0x7c, 0x95, 0x38, 0xa0, 0x65, 0xb2, + 0xc9, 0xed, 0xbe, 0x63, 0xda, 0x94, 0x4d, 0x8a, 0x8d, 0x39, 0xa0, 0x65, 0xaa, 0xaf, 0xc3, 0x7c, + 0xa4, 0x1e, 0x6d, 0x9f, 0x1a, 0xae, 0x63, 0xfa, 0x78, 0x5b, 0x59, 0xbd, 0x16, 0x4d, 0x6c, 0x70, + 0xb8, 0xaa, 0x42, 0xce, 0x27, 0x76, 0x50, 0xcf, 0xe1, 0x22, 0xf8, 0xad, 0x5e, 0x84, 0xb2, 0x6f, + 0x75, 0x1c, 0x12, 0xf4, 0x3d, 0x2a, 0xee, 0x25, 0x06, 0xa8, 0xd7, 0x60, 0xb6, 0xd7, 0xdf, 0xb6, + 0x2d, 0xa3, 0xbd, 0x47, 0x8f, 0xda, 0x7d, 0xcf, 0xc6, 0xbb, 0x29, 0xeb, 0x33, 0x1c, 0xfa, 0x90, + 0x1e, 0x6d, 0x79, 0xb6, 0xf6, 0x6a, 0x24, 0xe0, 0x07, 0x78, 0x63, 0x23, 0xce, 0x7e, 0x2d, 0x12, + 0xf3, 0x46, 0x40, 0x49, 0x77, 0x04, 0xd6, 0x2a, 0xcc, 0x2f, 0x9b, 0xe6, 0x7d, 0xcf, 0xa2, 0x8e, + 0xe9, 0xeb, 0xf4, 0xfd, 0x3e, 0xf5, 0x03, 0xb5, 0x06, 0x59, 0xcb, 0xf4, 0xeb, 0xca, 0xd5, 0xec, + 0x8d, 0xb2, 0xce, 0x3e, 0x19, 0xdf, 0x4c, 0x75, 0x1d, 0xd2, 0xa5, 0x7e, 0x3d, 0x83, 0xf0, 0x18, + 0xa0, 0x3d, 0x82, 0xb3, 0xcb, 0xa6, 0xf9, 0xc0, 0x73, 0xfb, 0x3d, 0xa6, 0xe6, 0xd1, 0x3a, 0x0b, + 0x50, 0xea, 0x30, 0x60, 0x2c, 0xe7, 0x22, 0x8e, 0x5b, 0x26, 0x9b, 0x62, 0xf4, 0x6d, 0xb6, 0x0f, + 0x5f, 0xaf, 0xc8, 0xc6, 0x2d, 0xd3, 0xd7, 0x3e, 0x52, 0x60, 0x61, 0xb9, 0x1f, 0xec, 0x52, 0x27, + 0xb0, 0x0c, 0x12, 0x50, 0xae, 0x67, 0xe1, 0x9a, 0xb7, 0xa0, 0x48, 0xf8, 0xb1, 0x84, 0x95, 0x0d, + 0x33, 0x07, 0x41, 0x12, 0x62, 0xaa, 0x4b, 0x50, 0x30, 0x3c, 0x4a, 0x02, 0x8a, 0x37, 0x3a, 0x4c, + 0xd9, 0x57, 0x5c, 0xd7, 0x7e, 0x46, 0xec, 0x3e, 0xd5, 0x05, 0x26, 0x53, 0xc0, 0xf0, 0x84, 0xc2, + 0x20, 0xa3, 0xf1, 0x00, 0x8b, 0xc2, 0xfc, 0xa6, 0x61, 0x31, 0xb4, 0xd8, 0x17, 0xc5, 0xe2, 0xaf, + 0x15, 0xa8, 0xcb, 0x2c, 0xa2, 0xad, 0x85, 0x1c, 0x2e, 0xa5, 0x39, 0xac, 0x0f, 0xe1, 0x90, 0x53, + 0xbc, 0x30, 0x06, 0x3f, 0x55, 0xe0, 0x82, 0xcc, 0x60, 0x68, 0xca, 0x21, 0x8f, 0x6f, 0xa5, 0x79, + 0xbc, 0x30, 0x84, 0xc7, 0x88, 0xe8, 0x45, 0xb1, 0xc9, 0xd6, 0xb3, 0xba, 0x3d, 0xd7, 0xe3, 0x76, + 0x3c, 0x66, 0x3d, 0x8e, 0xa9, 0x7d, 0xac, 0xc0, 0x25, 0xf9, 0x68, 0xb1, 0xef, 0x09, 0x0f, 0x77, + 0x3b, 0x7d, 0xb8, 0x4b, 0x43, 0x0e, 0x27, 0x91, 0x7d, 0x66, 0x9a, 0xcc, 0x5d, 0xca, 0x54, 0x9a, + 0x2c, 0x48, 0x3e, 0x33, 0x4d, 0x46, 0x77, 0x36, 0x95, 0x26, 0x73, 0x8a, 0x17, 0xc6, 0x60, 0x13, + 0xce, 0xac, 0xd8, 0xae, 0xb1, 0x77, 0x42, 0x2f, 0xfa, 0x61, 0x16, 0x66, 0x57, 0x77, 0x89, 0xe3, + 0x50, 0xfb, 0x31, 0xf5, 0x7d, 0xd2, 0xa1, 0xea, 0x25, 0x00, 0x83, 0x43, 0x62, 0x17, 0x5a, 0x16, + 0x90, 0x96, 0xc9, 0xa6, 0xbb, 0x1c, 0x33, 0x0e, 0x56, 0x65, 0x01, 0x69, 0x99, 0xea, 0x4d, 0xc8, + 0x19, 0xae, 0xc9, 0xf9, 0x65, 0xe6, 0x93, 0x3e, 0x65, 0xcb, 0x09, 0x6e, 0x2d, 0xf1, 0x63, 0x22, + 0x22, 0x8b, 0x7d, 0x3e, 0x75, 0x4c, 0x1e, 0x18, 0x79, 0xd8, 0x2a, 0x71, 0x40, 0xcb, 0x4c, 0x48, + 0x20, 0x9f, 0x32, 0x92, 0x3a, 0x14, 0x0d, 0xd7, 0x09, 0xa8, 0x13, 0x88, 0x88, 0x15, 0x0e, 0x59, + 0xae, 0xc1, 0x25, 0xc8, 0x73, 0x8d, 0xe2, 0xf8, 0x5c, 0x83, 0xa3, 0x33, 0x00, 0x23, 0xee, 0xf7, + 0xcc, 0x88, 0xb8, 0x34, 0x9e, 0x98, 0xa3, 0x23, 0xf1, 0xd7, 0x01, 0x58, 0x96, 0x66, 0xf9, 0xc8, + 0x56, 0x79, 0xec, 0x4d, 0x4b, 0xd8, 0xda, 0xcf, 0x14, 0x50, 0x93, 0x57, 0xf1, 0xc8, 0xf2, 0x03, + 0xf5, 0xab, 0x50, 0x12, 0xd2, 0xe5, 0xd7, 0xca, 0x16, 0x94, 0xb4, 0x2d, 0x49, 0xa1, 0x47, 0xb8, + 0xea, 0x15, 0xa8, 0x38, 0xf4, 0x30, 0x68, 0x1b, 0x7d, 0xcf, 0x77, 0x3d, 0x71, 0x51, 0xc0, 0x40, + 0xab, 0x08, 0x61, 0x08, 0x3d, 0x8f, 0xee, 0x87, 0x08, 0x5c, 0xc1, 0x80, 0x81, 0x38, 0x82, 0xf6, + 0x4b, 0xc6, 0x10, 0x0a, 0x06, 0xa3, 0x6c, 0xa8, 0x62, 0x2a, 0xe4, 0xf0, 0x3e, 0xb8, 0x66, 0xe0, + 0xb7, 0x7a, 0x15, 0x2a, 0x26, 0xf5, 0x0d, 0xcf, 0xea, 0x05, 0x96, 0xeb, 0x88, 0xcd, 0x64, 0x10, + 0x8b, 0xbd, 0x36, 0x71, 0x3a, 0xed, 0x80, 0x74, 0xc4, 0x56, 0x45, 0x36, 0xde, 0x24, 0x1d, 0xa6, + 0x51, 0x64, 0x9f, 0x04, 0xc4, 0xc3, 0xec, 0x83, 0xab, 0x40, 0x99, 0x43, 0xb6, 0x3c, 0x9b, 0xed, + 0xe7, 0xf6, 0xa8, 0x83, 0xf7, 0x5f, 0xd2, 0xf1, 0x5b, 0xbb, 0x0f, 0x67, 0xd7, 0xa8, 0x4d, 0x03, + 0x7a, 0x42, 0xf5, 0xbf, 0x09, 0x2a, 0x5f, 0x27, 0x71, 0xc2, 0xd1, 0x29, 0x84, 0xf6, 0x00, 0x2e, + 0x73, 0x82, 0x47, 0x94, 0x98, 0xd4, 0xdb, 0x76, 0x89, 0x67, 0xea, 0xd4, 0x70, 0xd9, 0x2f, 0x27, + 0x7e, 0x15, 0x66, 0xed, 0x78, 0x2e, 0x5e, 0xa2, 0x2a, 0x41, 0x5b, 0xa6, 0xb6, 0x08, 0x0d, 0xbe, + 0xd0, 0xba, 0x1b, 0x58, 0x3b, 0xcc, 0xc7, 0x58, 0xae, 0x33, 0xfa, 0x1c, 0x9a, 0x01, 0xe7, 0x38, + 0xfe, 0x46, 0xe0, 0x7a, 0xa4, 0x43, 0x9f, 0x6c, 0x7f, 0x9f, 0x1a, 0x41, 0xcb, 0x54, 0x2f, 0x03, + 0x18, 0xae, 0x6d, 0x53, 0x03, 0x25, 0xcf, 0xf7, 0x92, 0x20, 0x6c, 0xa9, 0x3d, 0x7a, 0x24, 0xae, + 0x84, 0x7d, 0x32, 0xc3, 0xd9, 0x67, 0x6a, 0xe7, 0x3a, 0xe1, 0x4d, 0x88, 0xa1, 0xd6, 0x86, 0x0b, + 0x43, 0x36, 0x89, 0xb8, 0xba, 0x07, 0xe0, 0x22, 0xa4, 0x1d, 0x32, 0x57, 0x59, 0x7a, 0x59, 0x56, + 0xc6, 0xa1, 0x1c, 0xea, 0x65, 0x57, 0x7c, 0xf9, 0xda, 0x27, 0x0a, 0x14, 0xf8, 0x95, 0x4d, 0x58, + 0xb6, 0xbc, 0x09, 0x79, 0x3f, 0x88, 0xbd, 0xe6, 0xb1, 0xfe, 0x84, 0x63, 0x6a, 0xf7, 0x21, 0xbf, + 0xc1, 0x3e, 0x54, 0x80, 0xc2, 0x7d, 0xbd, 0xd5, 0x5c, 0x5f, 0xab, 0xbd, 0xa4, 0xce, 0x41, 0xa5, + 0xb5, 0xfe, 0xac, 0xb5, 0xd9, 0x6c, 0x6f, 0x34, 0xd7, 0x37, 0x6b, 0x8a, 0x7a, 0x06, 0xe6, 0x04, + 0x40, 0x6f, 0xae, 0x36, 0x5b, 0xcf, 0x9a, 0x6b, 0xb5, 0x8c, 0x5a, 0x81, 0xe2, 0xca, 0xa3, 0x27, + 0xab, 0x0f, 0x9b, 0x6b, 0xb5, 0xac, 0x76, 0x1b, 0x8a, 0x42, 0xbb, 0xd4, 0x2f, 0x41, 0x71, 0x87, + 0x7f, 0x8a, 0x53, 0xab, 0x32, 0xbb, 0x1c, 0x4b, 0x0f, 0x51, 0x34, 0x13, 0xe6, 0x1e, 0xd0, 0x20, + 0x91, 0x94, 0x4e, 0xa9, 0x97, 0xea, 0xcb, 0x30, 0xb3, 0x23, 0xb2, 0x0c, 0x94, 0x75, 0x16, 0x11, + 0x2a, 0x21, 0x8c, 0x89, 0xf2, 0xe3, 0x2c, 0xe4, 0x51, 0x6b, 0xd3, 0xb5, 0x0e, 0x3a, 0x70, 0x66, + 0xb6, 0xae, 0x27, 0x79, 0x68, 0x01, 0x69, 0x99, 0x91, 0xfd, 0x66, 0x47, 0xdb, 0x6f, 0xee, 0x78, + 0xfb, 0xcd, 0x27, 0xed, 0xb7, 0xc1, 0x3c, 0x54, 0x40, 0x4c, 0x12, 0x10, 0xe1, 0x89, 0xa3, 0x71, + 0xca, 0xb6, 0x8b, 0x69, 0xdb, 0x5e, 0x14, 0xb6, 0x5d, 0x1a, 0xeb, 0x29, 0x11, 0x8f, 0x2d, 0x47, + 0xcd, 0x0e, 0x6d, 0xf3, 0xe0, 0xcb, 0xfc, 0x6b, 0x5e, 0x2f, 0x33, 0xc8, 0x2a, 0x06, 0xd9, 0x0b, + 0x50, 0xee, 0x92, 0x43, 0x31, 0x0b, 0x38, 0x5b, 0xea, 0x92, 0x43, 0x3e, 0x99, 0x8a, 0x0a, 0x95, + 0x93, 0x44, 0x85, 0x99, 0x69, 0xa2, 0x82, 0xb6, 0x0e, 0x65, 0xbc, 0x29, 0xf4, 0xe7, 0xaf, 0x41, + 0x01, 0x9d, 0x49, 0xa8, 0x4a, 0xf3, 0xb2, 0x2a, 0x71, 0x37, 0x24, 0x10, 0x58, 0xcd, 0x9e, 0xf0, + 0xde, 0x62, 0xa4, 0xfd, 0x57, 0x81, 0x6a, 0x54, 0xf8, 0xe0, 0xa2, 0x6b, 0x50, 0xe1, 0x1e, 0x8b, + 0xa9, 0x50, 0xb8, 0xf2, 0x2b, 0x03, 0x2b, 0x87, 0xf8, 0xf1, 0x48, 0x87, 0x4e, 0x54, 0x41, 0x35, + 0x7e, 0xa7, 0x08, 0x46, 0xd9, 0xf0, 0xc5, 0x19, 0xe8, 0xbd, 0xd0, 0x40, 0x67, 0x01, 0x36, 0xb6, + 0x9e, 0x36, 0xf5, 0xe5, 0xb5, 0xc7, 0xad, 0xf5, 0xda, 0x4b, 0x6a, 0x19, 0xf2, 0xfc, 0x53, 0x61, + 0xb6, 0xfb, 0xb8, 0xf9, 0x78, 0xa5, 0xa9, 0xd7, 0x32, 0x6a, 0x0d, 0x66, 0xde, 0x7d, 0xd2, 0x5a, + 0x6f, 0xeb, 0xcd, 0x6f, 0x6d, 0x35, 0x37, 0x36, 0x6b, 0x59, 0xed, 0xa7, 0x0a, 0x5c, 0x6c, 0x61, + 0xda, 0x1b, 0xe6, 0xe2, 0xa9, 0x38, 0xf0, 0x9c, 0x79, 0xfc, 0x1b, 0x90, 0xf7, 0xa8, 0x2f, 0x7a, + 0x24, 0xc7, 0xeb, 0x23, 0x47, 0xd4, 0xbe, 0x0c, 0xb5, 0x77, 0x5d, 0xcb, 0x99, 0x34, 0x7c, 0x7c, + 0x03, 0xce, 0x31, 0xf4, 0x4d, 0xb7, 0x8f, 0x86, 0xee, 0x04, 0x21, 0xcd, 0x2b, 0x50, 0x0d, 0x22, + 0x60, 0x4c, 0x38, 0x13, 0x03, 0x5b, 0xa6, 0xf6, 0x18, 0xce, 0x3d, 0xb4, 0x8c, 0xbd, 0xd3, 0xaa, + 0x79, 0xff, 0x95, 0x85, 0xf9, 0x81, 0x30, 0x36, 0x61, 0xfc, 0x62, 0xeb, 0xba, 0x07, 0x0e, 0x95, + 0x5c, 0x4c, 0x11, 0xc7, 0x2d, 0x53, 0xbd, 0x93, 0x4a, 0x5b, 0x2b, 0x4b, 0x17, 0x07, 0x04, 0xb9, + 0x11, 0x78, 0x96, 0xd3, 0xe1, 0xa2, 0x8c, 0x53, 0xba, 0xb3, 0x90, 0xf7, 0x0d, 0xd7, 0xa3, 0xe8, + 0x80, 0xb2, 0x3a, 0x1f, 0x30, 0xff, 0xe2, 0xf7, 0xb7, 0xf9, 0x44, 0x1e, 0x27, 0xa2, 0x31, 0xb3, + 0x78, 0xa7, 0xdf, 0x6d, 0xf3, 0xc9, 0x02, 0xb7, 0x78, 0xa7, 0xdf, 0xdd, 0x08, 0x09, 0x23, 0xc7, + 0x54, 0x4c, 0x39, 0xa6, 0x94, 0x37, 0x28, 0x9d, 0xc4, 0x1b, 0x94, 0xa7, 0xca, 0x11, 0xdf, 0x86, + 0x0a, 0x3d, 0xec, 0x59, 0x9e, 0xe8, 0x84, 0xc1, 0x78, 0x62, 0x8e, 0x8e, 0xc4, 0x2a, 0xe4, 0x3c, + 0xe2, 0xec, 0xa1, 0xf7, 0xca, 0xea, 0xf8, 0xad, 0x6a, 0x50, 0x65, 0x5e, 0x2f, 0x96, 0x03, 0xf3, + 0x4e, 0x55, 0xbd, 0xd2, 0x25, 0x87, 0xeb, 0x42, 0x14, 0xda, 0xdf, 0x14, 0x38, 0x37, 0x70, 0xd7, + 0xe8, 0x3a, 0x6e, 0x43, 0xd1, 0xc3, 0x51, 0xe8, 0x36, 0x12, 0x55, 0xe1, 0x60, 0x9a, 0x13, 0x62, + 0xab, 0x2b, 0x50, 0xe5, 0x1a, 0x10, 0x92, 0x67, 0x26, 0x21, 0x9f, 0x41, 0x1a, 0x5d, 0xac, 0x91, + 0x4a, 0x52, 0xb3, 0xe3, 0x92, 0xd4, 0xdc, 0x40, 0x92, 0xba, 0x88, 0x3a, 0xbc, 0x3f, 0x71, 0x02, + 0xf7, 0x43, 0x05, 0xce, 0x3c, 0xb2, 0x9c, 0xbd, 0xd3, 0xab, 0xfc, 0xa7, 0xae, 0xd4, 0xff, 0xa4, + 0x40, 0x83, 0x89, 0x3e, 0x99, 0xba, 0x47, 0xc6, 0x3c, 0xa6, 0xfe, 0x7a, 0x13, 0xf2, 0xb6, 0xd5, + 0xb5, 0x82, 0x89, 0x1c, 0x2e, 0x62, 0xaa, 0x5f, 0x81, 0xe2, 0x8e, 0xeb, 0x1d, 0x10, 0xcf, 0x14, + 0xf6, 0x78, 0x1c, 0x97, 0x21, 0xaa, 0x14, 0x7d, 0x72, 0x89, 0xe8, 0xe3, 0xc1, 0x3c, 0xe3, 0x1e, + 0x05, 0xee, 0x1f, 0x57, 0x14, 0x8c, 0x08, 0x5f, 0xf1, 0x09, 0xb2, 0x93, 0x9e, 0x40, 0x5b, 0x82, + 0x73, 0xd1, 0x9e, 0x13, 0x7a, 0x3e, 0xed, 0x23, 0x05, 0x6e, 0x30, 0xa2, 0x01, 0x1d, 0xf4, 0x97, + 0x3d, 0xb7, 0xef, 0x98, 0x4f, 0xb8, 0x22, 0x4e, 0x93, 0xb5, 0xab, 0x4b, 0x49, 0xe1, 0x0f, 0xfa, + 0xb5, 0xad, 0x41, 0xe9, 0xcb, 0x9e, 0x32, 0x9b, 0xf0, 0x94, 0xda, 0x1f, 0x15, 0xb8, 0x34, 0x9c, + 0xc5, 0x29, 0xf9, 0xba, 0x00, 0xe5, 0x70, 0x8f, 0xd0, 0xcd, 0x97, 0xc4, 0x26, 0xfe, 0x73, 0xc8, + 0x7b, 0xe4, 0xdd, 0xff, 0x33, 0x03, 0x2a, 0x63, 0xf8, 0x31, 0x09, 0x8c, 0xdd, 0x58, 0x65, 0xa3, + 0x1d, 0x94, 0x89, 0x77, 0xb8, 0x07, 0x55, 0xd2, 0x0f, 0x76, 0x5d, 0xcf, 0x0a, 0x48, 0x60, 0xed, + 0x4f, 0xd2, 0x16, 0x49, 0x12, 0xe0, 0x5d, 0x90, 0x6d, 0x6a, 0x4f, 0x14, 0x63, 0x38, 0x2a, 0x16, + 0xd3, 0x96, 0xd3, 0xf6, 0xad, 0x0f, 0xa8, 0x30, 0xd8, 0x63, 0x79, 0x2d, 0x76, 0x2d, 0x67, 0xc3, + 0xfa, 0x80, 0x22, 0x1d, 0x39, 0xe4, 0x74, 0xf9, 0x49, 0xe8, 0xc8, 0x21, 0xd2, 0x2d, 0x41, 0xfe, + 0xfd, 0x3e, 0xf5, 0x8e, 0xc4, 0x7b, 0xc7, 0x18, 0x1e, 0x11, 0x55, 0x3b, 0x84, 0x3a, 0x13, 0xf1, + 0xd0, 0xba, 0xf0, 0x39, 0x04, 0xfd, 0x1a, 0xd4, 0x0c, 0x62, 0xec, 0x52, 0xb2, 0x6d, 0xd3, 0x64, + 0x33, 0x60, 0x2e, 0x82, 0x0b, 0x5f, 0xfa, 0x1b, 0x05, 0x16, 0xd8, 0xd6, 0xc3, 0xab, 0xbf, 0x2f, + 0x40, 0x51, 0x64, 0x12, 0x42, 0x07, 0x0b, 0x3c, 0x91, 0x48, 0x55, 0xa0, 0x99, 0x81, 0x0a, 0xf4, + 0x14, 0xf5, 0xef, 0x57, 0x0a, 0x5c, 0x67, 0x1c, 0xca, 0x09, 0xd4, 0x28, 0x93, 0x9e, 0x24, 0xa5, + 0x3a, 0x6d, 0x83, 0xfe, 0x83, 0x02, 0x17, 0x87, 0xf2, 0x37, 0x15, 0x53, 0x9f, 0x95, 0x35, 0xff, + 0x3d, 0x03, 0xe7, 0x93, 0xdc, 0x46, 0x7c, 0xae, 0xc2, 0xac, 0x41, 0x02, 0xda, 0x71, 0xbd, 0xa3, + 0xb6, 0x1f, 0x10, 0x2f, 0xd4, 0xb8, 0xe3, 0x05, 0x54, 0x0d, 0x69, 0x36, 0x18, 0x89, 0xfa, 0x0e, + 0xcc, 0x44, 0x8b, 0x50, 0xc7, 0x9c, 0x48, 0xc6, 0x95, 0x90, 0xa2, 0xe9, 0x98, 0xea, 0xdb, 0x00, + 0xb8, 0x39, 0xcf, 0x94, 0xb2, 0x13, 0x90, 0x97, 0x11, 0x1f, 0x53, 0xa5, 0xdb, 0x50, 0xa2, 0x8e, + 0xc9, 0x49, 0x73, 0x13, 0x90, 0x16, 0xa9, 0x63, 0x22, 0x61, 0x24, 0xe1, 0xc2, 0x73, 0x48, 0xb8, + 0x94, 0x90, 0xf0, 0x1b, 0x3c, 0x6e, 0xb1, 0x90, 0x95, 0x8c, 0x97, 0xa3, 0x8c, 0x49, 0xfb, 0xb9, + 0x02, 0x79, 0xf4, 0xae, 0x4c, 0xcd, 0xba, 0xec, 0x43, 0x0a, 0x6d, 0x38, 0x6e, 0x99, 0xea, 0xb5, + 0x61, 0xce, 0xb3, 0x74, 0x1a, 0x0e, 0x52, 0x85, 0x5c, 0xe4, 0x1c, 0xf3, 0x3a, 0x7e, 0x6b, 0x77, + 0xa0, 0x8c, 0x1c, 0x61, 0xba, 0xf8, 0x3a, 0x70, 0x2e, 0xe8, 0xd0, 0xfa, 0x15, 0xf1, 0xf4, 0x10, + 0x43, 0xfb, 0x87, 0x02, 0x33, 0xb2, 0x1f, 0x1b, 0x68, 0x55, 0xd4, 0xa1, 0xe8, 0xf7, 0xd1, 0xcd, + 0x84, 0x45, 0x84, 0x18, 0xca, 0xdd, 0xdd, 0x6c, 0xb2, 0xbb, 0xab, 0x8a, 0x0e, 0xb3, 0x60, 0x71, + 0xb0, 0x89, 0x9c, 0x4f, 0x35, 0x91, 0x53, 0xa9, 0x7e, 0x61, 0xaa, 0x54, 0xff, 0x72, 0xa2, 0xa3, + 0x5b, 0x44, 0x39, 0xcb, 0x5d, 0xdb, 0x1f, 0x40, 0x4d, 0x3e, 0x21, 0xca, 0xe8, 0x2e, 0x54, 0x1d, + 0xd9, 0x7b, 0x0b, 0x49, 0x25, 0x5e, 0x09, 0x64, 0x22, 0x3d, 0x89, 0x3e, 0x8d, 0xcb, 0x7e, 0x0a, + 0xf5, 0xa7, 0x9e, 0xdb, 0x75, 0x45, 0x07, 0xf3, 0x14, 0xaa, 0xc2, 0xf7, 0xe0, 0x8c, 0x4e, 0x89, + 0x79, 0xf2, 0x36, 0xa3, 0xa4, 0xe2, 0xd9, 0x84, 0x8a, 0x7f, 0x0f, 0x16, 0x06, 0x76, 0x88, 0x98, + 0xbe, 0x3b, 0xa4, 0xc7, 0x78, 0x45, 0x16, 0xdc, 0x10, 0xe6, 0xe4, 0x0e, 0xe3, 0xbb, 0x90, 0xd5, + 0x7b, 0xc6, 0x30, 0x45, 0xeb, 0x91, 0x23, 0xdb, 0x25, 0x51, 0xb5, 0x2a, 0x86, 0x4c, 0x14, 0xbb, + 0x41, 0xd0, 0x6b, 0x33, 0xee, 0x85, 0xa6, 0xb1, 0xf1, 0x43, 0x7a, 0xa4, 0x3d, 0x83, 0xe2, 0x06, + 0xf5, 0x7d, 0x76, 0x3c, 0xa6, 0x8e, 0xa8, 0x14, 0x7c, 0xd1, 0x92, 0x1e, 0x0e, 0xe3, 0x27, 0xee, + 0x8c, 0xf4, 0xc4, 0xcd, 0x14, 0xb2, 0x6f, 0xf6, 0xda, 0x7c, 0x26, 0x7c, 0xbb, 0x31, 0x7b, 0x9b, + 0xf8, 0xfe, 0xfd, 0x69, 0x06, 0xaa, 0x89, 0x23, 0x9c, 0xa2, 0x74, 0x19, 0x3f, 0xfb, 0xcc, 0xa2, + 0x85, 0xaf, 0xe7, 0x03, 0xb9, 0xe7, 0x9b, 0x4f, 0xf4, 0x7c, 0xd5, 0xeb, 0x30, 0xd7, 0xa3, 0x5e, + 0xd7, 0xc2, 0x73, 0xb6, 0x3d, 0x4a, 0x4c, 0x51, 0x47, 0xcf, 0xc6, 0x60, 0x26, 0x73, 0xa6, 0x95, + 0x12, 0xe2, 0x81, 0x67, 0x05, 0xfc, 0x69, 0x25, 0xaf, 0x4b, 0x0b, 0x7c, 0x9b, 0x81, 0x3f, 0xbf, + 0xe2, 0x5a, 0x3b, 0x80, 0x5a, 0x42, 0xb2, 0xcb, 0xc6, 0xde, 0x69, 0x76, 0xc8, 0x65, 0xb1, 0xe7, + 0x12, 0x4a, 0xdd, 0x84, 0xf9, 0xf4, 0xc6, 0xbe, 0xfa, 0x06, 0xe4, 0x88, 0xb1, 0x17, 0xaa, 0xf1, + 0x45, 0x59, 0x8d, 0xd3, 0xc8, 0x3a, 0x62, 0x6a, 0x4d, 0x98, 0x4d, 0xda, 0x85, 0x7a, 0x0b, 0x8a, + 0x5c, 0xbb, 0xc3, 0x65, 0x16, 0x46, 0x2e, 0xa3, 0x87, 0x98, 0xda, 0x7b, 0x29, 0x6e, 0xd0, 0x2d, + 0x3d, 0xcf, 0x4a, 0x23, 0x7b, 0x90, 0x1f, 0xe6, 0x00, 0xe2, 0xbc, 0x61, 0xc0, 0xde, 0x98, 0x55, + 0x58, 0x81, 0x4d, 0x23, 0xab, 0x60, 0x83, 0x74, 0x9b, 0x39, 0x3b, 0xd8, 0x66, 0x6e, 0x40, 0x29, + 0x4c, 0x00, 0x50, 0xc0, 0x55, 0x3d, 0x1a, 0xb3, 0xc2, 0xd8, 0x77, 0xbd, 0xa0, 0xed, 0x7a, 0x26, + 0xf5, 0x50, 0x8d, 0xab, 0x7a, 0x99, 0x41, 0x9e, 0x30, 0x40, 0x14, 0xba, 0x0a, 0x38, 0x81, 0xdf, + 0x3c, 0x86, 0x8a, 0xbc, 0xbd, 0x88, 0xf0, 0x28, 0x35, 0x1f, 0xe8, 0x9a, 0x94, 0x06, 0xba, 0x26, + 0xf8, 0x8f, 0x26, 0xe2, 0xb4, 0xf1, 0x39, 0x1c, 0x15, 0xb1, 0xc4, 0xd8, 0x71, 0x9a, 0xf8, 0x8f, + 0x9e, 0x4b, 0x00, 0x2c, 0xbf, 0x20, 0x06, 0x46, 0x60, 0xe0, 0xec, 0x50, 0xc7, 0x5c, 0x46, 0x00, + 0x9b, 0xc6, 0xd6, 0x06, 0x6f, 0x28, 0x56, 0xf8, 0x34, 0x83, 0xe8, 0x0c, 0x90, 0xe8, 0x4d, 0xcd, + 0x1c, 0xdf, 0x9b, 0xaa, 0x4e, 0x65, 0x3e, 0x5f, 0x4b, 0xe4, 0x4c, 0xb3, 0x63, 0x69, 0xa5, 0x8c, + 0xe9, 0x2d, 0x29, 0x63, 0x9a, 0x1b, 0x4b, 0x18, 0xe6, 0x4b, 0xda, 0x36, 0xcc, 0xc6, 0x9a, 0x80, + 0x9a, 0x76, 0x07, 0x2a, 0x71, 0x42, 0x1b, 0x6a, 0xdb, 0x79, 0x59, 0xdb, 0xa4, 0x04, 0x59, 0x46, + 0x1d, 0xa9, 0x6e, 0x7f, 0x55, 0xe0, 0x6c, 0x3a, 0xa9, 0xfe, 0x7f, 0x68, 0x5f, 0xfd, 0x27, 0x03, + 0x67, 0xb7, 0xd0, 0x7d, 0x89, 0x16, 0x53, 0x18, 0x07, 0xe5, 0x26, 0xaa, 0x32, 0x55, 0x13, 0xf5, + 0x1d, 0x98, 0x31, 0x2d, 0xbf, 0x67, 0x93, 0xa3, 0x36, 0x52, 0x67, 0x26, 0xa0, 0xae, 0x08, 0x8a, + 0x75, 0x82, 0x0e, 0x58, 0x7e, 0xb3, 0x99, 0x24, 0x79, 0x94, 0x5e, 0x74, 0x6e, 0x4b, 0xef, 0x44, + 0xb9, 0x09, 0x48, 0xa3, 0x57, 0xa4, 0x3b, 0x50, 0xb2, 0x5d, 0x9e, 0x01, 0x89, 0x12, 0x7b, 0xcc, + 0x81, 0x43, 0x6c, 0x46, 0xc9, 0x54, 0xf6, 0x03, 0xd7, 0xa1, 0x13, 0xd5, 0xd9, 0x11, 0xb6, 0xf6, + 0xe7, 0x0c, 0xa8, 0x5c, 0xfa, 0x13, 0xb6, 0x0f, 0x99, 0x47, 0x9f, 0x58, 0xa8, 0xbc, 0x0b, 0x76, + 0x77, 0xd0, 0xe7, 0x8d, 0xbf, 0x0d, 0xc9, 0x23, 0x3e, 0xb7, 0x40, 0x93, 0xd7, 0x98, 0x9f, 0xee, + 0x1a, 0xc3, 0x87, 0xb9, 0xc2, 0x64, 0x0f, 0x73, 0xda, 0x2f, 0x72, 0x90, 0xc3, 0x57, 0xa3, 0x74, + 0x20, 0x90, 0xff, 0xc1, 0x91, 0x49, 0xfd, 0x83, 0xe3, 0xe5, 0x94, 0xa6, 0x86, 0xf1, 0x40, 0xd2, + 0xc5, 0x31, 0xff, 0x0d, 0x38, 0xfe, 0x55, 0x32, 0xd2, 0x27, 0xf1, 0x2a, 0x19, 0x69, 0x4c, 0x43, + 0xd2, 0x18, 0xf1, 0x30, 0x10, 0x8e, 0x13, 0x8e, 0xb9, 0x94, 0x72, 0xcc, 0x57, 0xa0, 0x22, 0x3d, + 0xcb, 0x62, 0x44, 0x28, 0xeb, 0x10, 0xbf, 0xca, 0xb2, 0x80, 0xc1, 0x25, 0xc5, 0xa6, 0x81, 0x53, + 0x73, 0x40, 0xcb, 0x64, 0xb5, 0x7f, 0x87, 0x74, 0xa9, 0x81, 0xe1, 0x84, 0x21, 0x54, 0x78, 0xed, + 0x1f, 0x03, 0x79, 0x66, 0xee, 0x07, 0x94, 0xe0, 0x7f, 0x68, 0x67, 0x44, 0x49, 0xc4, 0xc6, 0x2d, + 0x6c, 0xc8, 0xba, 0x8e, 0x6d, 0x39, 0x3c, 0x22, 0x94, 0x74, 0x31, 0x4a, 0x3d, 0x8a, 0xce, 0xa6, + 0x1f, 0x45, 0x53, 0xd1, 0x64, 0xee, 0x24, 0xc9, 0x58, 0x6d, 0xaa, 0x64, 0xec, 0x47, 0x19, 0xa8, + 0x46, 0xa5, 0x6f, 0xf8, 0x4e, 0x89, 0xe9, 0x53, 0xe2, 0x05, 0xf4, 0x95, 0xf4, 0xd3, 0x62, 0x84, + 0x1f, 0x8f, 0x74, 0xe8, 0x47, 0x35, 0x74, 0xe3, 0x13, 0x05, 0xca, 0xd1, 0x8c, 0x7a, 0x1d, 0xf2, + 0xb8, 0x9c, 0x70, 0x93, 0x43, 0xde, 0x53, 0xf9, 0xfc, 0xe7, 0xf3, 0x54, 0x79, 0x13, 0xf2, 0x58, + 0x94, 0xa9, 0x5f, 0x84, 0xbc, 0xfc, 0x38, 0x3b, 0xf8, 0x9e, 0xca, 0xa7, 0xb5, 0x0f, 0x33, 0x70, + 0x09, 0xb3, 0xe8, 0x13, 0xfe, 0xc3, 0x44, 0xfd, 0x0e, 0x14, 0x78, 0x68, 0x13, 0xe7, 0xbd, 0x27, + 0xef, 0x78, 0xec, 0x0e, 0x83, 0x71, 0x0f, 0xd1, 0x75, 0xb1, 0x5e, 0x63, 0x07, 0xce, 0x0f, 0xc7, + 0x88, 0x1f, 0xf0, 0x94, 0x51, 0x0f, 0x78, 0x99, 0xd4, 0x03, 0x9e, 0x6c, 0x6e, 0xd9, 0xa4, 0xb9, + 0x69, 0x3f, 0xc9, 0x80, 0x8a, 0xeb, 0x9e, 0xb4, 0x58, 0x8a, 0x6a, 0xa2, 0xec, 0x88, 0x9a, 0x28, + 0x97, 0xcc, 0xf2, 0xd7, 0x06, 0x6b, 0xa2, 0x09, 0xba, 0xbe, 0xe9, 0x82, 0xe9, 0xfe, 0x90, 0x82, + 0x69, 0x82, 0x96, 0x52, 0xba, 0x9a, 0xd2, 0x9e, 0x41, 0x63, 0x50, 0x0a, 0x7e, 0x9c, 0x28, 0xa4, + 0xb2, 0xfa, 0xcb, 0x03, 0xf7, 0x3c, 0xa2, 0x48, 0xf8, 0x71, 0x06, 0x2e, 0xe2, 0x7c, 0x3a, 0xb1, + 0x9a, 0xaa, 0x59, 0xf9, 0x2c, 0xa5, 0x66, 0x77, 0x07, 0xb6, 0x1f, 0xb1, 0xfc, 0x62, 0x1a, 0x9e, + 0x54, 0x32, 0x0a, 0xe7, 0x86, 0x22, 0x9c, 0xae, 0x8e, 0xad, 0x7c, 0x13, 0x16, 0x0c, 0xb7, 0xbb, + 0xb8, 0x4b, 0x3d, 0xd7, 0x32, 0x6c, 0xb2, 0xed, 0x4b, 0xec, 0xaf, 0x94, 0xd7, 0xf1, 0x7b, 0xb9, + 0x67, 0x3d, 0x55, 0xbe, 0x9b, 0x25, 0x3d, 0xeb, 0xb7, 0x99, 0xdc, 0xfa, 0xc3, 0xa7, 0x2b, 0xbf, + 0xcf, 0x14, 0xf8, 0xcc, 0x76, 0x01, 0x6f, 0xf0, 0xd6, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x72, + 0x24, 0xf5, 0x19, 0xed, 0x31, 0x00, 0x00, } diff --git a/api/api.proto b/api/api.proto index e9bdb34b6..48fd2bdac 100644 --- a/api/api.proto +++ b/api/api.proto @@ -292,22 +292,20 @@ message DeleteStorageObjectsRequest { message Friend { // The friendship status. enum State { - // Default case. Assumed as FRIEND state. - STATE_UNSPECIFIED = 0; // The user is a friend of the current user. - FRIEND = 1; - // The user has sent an invite to the current user. - INVITE_SENT = 2; - // The current user has sent an invite to this user. - INVITE_RECEIVED = 3; + FRIEND = 0; + // The current user has sent an invite to the user. + INVITE_SENT = 1; + // The current user has received an invite from this user. + INVITE_RECEIVED = 2; // The current user has blocked this user. - BLOCKED = 4; + BLOCKED = 3; } // The user object. User user = 1; // The friend status. - int32 state = 2; // one of "Friend.State". + google.protobuf.Int32Value state = 2; // one of "Friend.State". } // A collection of zero or more friends of the user. @@ -368,22 +366,20 @@ message GroupUserList { message GroupUser { // The group role status. enum State { - // Default case. Assumed as SUPERADMIN state. - STATE_UNSPECIFIED = 0; // The user is a superadmin with full control of the group. - SUPERADMIN = 1; + SUPERADMIN = 0; // The user is an admin with additional privileges. - ADMIN = 2; + ADMIN = 1; // The user is a regular member. - MEMBER = 3; + MEMBER = 2; // The user has requested to join the group - JOIN_REQUEST = 4; + JOIN_REQUEST = 3; } // User. User user = 1; // Their relationship to the group. - int32 state = 2; + google.protobuf.Int32Value state = 2; } // User-role pairs for a group. @@ -872,22 +868,20 @@ message UserGroupList { message UserGroup { // The group role status. enum State { - // Default case. Assumed as SUPERADMIN state. - STATE_UNSPECIFIED = 0; // The user is a superadmin with full control of the group. - SUPERADMIN = 1; + SUPERADMIN = 0; // The user is an admin with additional privileges. - ADMIN = 2; + ADMIN = 1; // The user is a regular member. - MEMBER = 3; + MEMBER = 2; // The user has requested to join the group - JOIN_REQUEST = 4; + JOIN_REQUEST = 3; } // Group. Group group = 1; // The user's relationship to the group. - int32 state = 2; + google.protobuf.Int32Value state = 2; } // Group-role pairs for a user. diff --git a/apigrpc/apigrpc.pb.go b/apigrpc/apigrpc.pb.go index 3cc66abac..be3c30a16 100644 --- a/apigrpc/apigrpc.pb.go +++ b/apigrpc/apigrpc.pb.go @@ -211,6 +211,7 @@ type NakamaClient interface { ImportFacebookFriends(ctx context.Context, in *api.ImportFacebookFriendsRequest, opts ...grpc.CallOption) (*empty.Empty, error) // Immediately join an open group, or request to join a closed one. JoinGroup(ctx context.Context, in *api.JoinGroupRequest, opts ...grpc.CallOption) (*empty.Empty, error) + // Attempt to join an open and running tournament. JoinTournament(ctx context.Context, in *api.JoinTournamentRequest, opts ...grpc.CallOption) (*empty.Empty, error) // Kick a set of users from a group. KickGroupUsers(ctx context.Context, in *api.KickGroupUsersRequest, opts ...grpc.CallOption) (*empty.Empty, error) @@ -240,6 +241,7 @@ type NakamaClient interface { ListGroupUsers(ctx context.Context, in *api.ListGroupUsersRequest, opts ...grpc.CallOption) (*api.GroupUserList, error) // List leaderboard records. ListLeaderboardRecords(ctx context.Context, in *api.ListLeaderboardRecordsRequest, opts ...grpc.CallOption) (*api.LeaderboardRecordList, error) + // List leaderboard records that belong to a user. ListLeaderboardRecordsAroundOwner(ctx context.Context, in *api.ListLeaderboardRecordsAroundOwnerRequest, opts ...grpc.CallOption) (*api.LeaderboardRecordList, error) // Fetch list of running matches. ListMatches(ctx context.Context, in *api.ListMatchesRequest, opts ...grpc.CallOption) (*api.MatchList, error) @@ -251,6 +253,7 @@ type NakamaClient interface { ListTournaments(ctx context.Context, in *api.ListTournamentsRequest, opts ...grpc.CallOption) (*api.TournamentList, error) // List tournament records. ListTournamentRecords(ctx context.Context, in *api.ListTournamentRecordsRequest, opts ...grpc.CallOption) (*api.TournamentRecordList, error) + // List tournament records for a given owner. ListTournamentRecordsAroundOwner(ctx context.Context, in *api.ListTournamentRecordsAroundOwnerRequest, opts ...grpc.CallOption) (*api.TournamentRecordList, error) // List groups the current user belongs to. ListUserGroups(ctx context.Context, in *api.ListUserGroupsRequest, opts ...grpc.CallOption) (*api.UserGroupList, error) @@ -869,6 +872,7 @@ type NakamaServer interface { ImportFacebookFriends(context.Context, *api.ImportFacebookFriendsRequest) (*empty.Empty, error) // Immediately join an open group, or request to join a closed one. JoinGroup(context.Context, *api.JoinGroupRequest) (*empty.Empty, error) + // Attempt to join an open and running tournament. JoinTournament(context.Context, *api.JoinTournamentRequest) (*empty.Empty, error) // Kick a set of users from a group. KickGroupUsers(context.Context, *api.KickGroupUsersRequest) (*empty.Empty, error) @@ -898,6 +902,7 @@ type NakamaServer interface { ListGroupUsers(context.Context, *api.ListGroupUsersRequest) (*api.GroupUserList, error) // List leaderboard records. ListLeaderboardRecords(context.Context, *api.ListLeaderboardRecordsRequest) (*api.LeaderboardRecordList, error) + // List leaderboard records that belong to a user. ListLeaderboardRecordsAroundOwner(context.Context, *api.ListLeaderboardRecordsAroundOwnerRequest) (*api.LeaderboardRecordList, error) // Fetch list of running matches. ListMatches(context.Context, *api.ListMatchesRequest) (*api.MatchList, error) @@ -909,6 +914,7 @@ type NakamaServer interface { ListTournaments(context.Context, *api.ListTournamentsRequest) (*api.TournamentList, error) // List tournament records. ListTournamentRecords(context.Context, *api.ListTournamentRecordsRequest) (*api.TournamentRecordList, error) + // List tournament records for a given owner. ListTournamentRecordsAroundOwner(context.Context, *api.ListTournamentRecordsAroundOwnerRequest) (*api.TournamentRecordList, error) // List groups the current user belongs to. ListUserGroups(context.Context, *api.ListUserGroupsRequest) (*api.UserGroupList, error) diff --git a/apigrpc/apigrpc.swagger.json b/apigrpc/apigrpc.swagger.json index 278de47be..b5acb1038 100644 --- a/apigrpc/apigrpc.swagger.json +++ b/apigrpc/apigrpc.swagger.json @@ -1371,6 +1371,7 @@ }, "/v2/leaderboard/{leaderboard_id}/owner/{owner_id}": { "get": { + "summary": "List leaderboard records that belong to a user.", "operationId": "ListLeaderboardRecordsAroundOwner", "responses": { "200": { @@ -1947,6 +1948,7 @@ }, "/v2/tournament/{tournament_id}/join": { "post": { + "summary": "Attempt to join an open and running tournament.", "operationId": "JoinTournament", "responses": { "200": { @@ -1972,6 +1974,7 @@ }, "/v2/tournament/{tournament_id}/owner/{owner_id}": { "get": { + "summary": "List tournament records for a given owner.", "operationId": "ListTournamentRecordsAroundOwner", "responses": { "200": { diff --git a/migrate/sql/20180103142001_initial_schema.sql b/migrate/sql/20180103142001_initial_schema.sql index 975750e70..6be8bd36c 100644 --- a/migrate/sql/20180103142001_initial_schema.sql +++ b/migrate/sql/20180103142001_initial_schema.sql @@ -64,7 +64,7 @@ CREATE TABLE IF NOT EXISTS user_edge ( position BIGINT NOT NULL, -- Used for sort order on rows. update_time TIMESTAMPTZ DEFAULT now() NOT NULL, destination_id UUID NOT NULL, - state SMALLINT DEFAULT 0 NOT NULL, -- friend(0), invite(1), invited(2), blocked(3), deleted(4), archived(5) + state SMALLINT DEFAULT 0 NOT NULL, -- friend(0), invite_sent(1), invite_received(2), blocked(3), deleted(4), archived(5) UNIQUE (source_id, destination_id) ); diff --git a/server/config.go b/server/config.go index 9140936a5..c0b8c18d6 100644 --- a/server/config.go +++ b/server/config.go @@ -390,10 +390,10 @@ func NewSocketConfig() *SocketConfig { // DatabaseConfig is configuration relevant to the Database storage. type DatabaseConfig struct { - Addresses []string `yaml:"address" json:"address" usage:"List of CockroachDB servers (username:password@address:port/dbname)."` - ConnMaxLifetimeMs int `yaml:"conn_max_lifetime_ms" json:"conn_max_lifetime_ms" usage:"Time in milliseconds to reuse a database connection before the connection is killed and a new one is created."` - MaxOpenConns int `yaml:"max_open_conns" json:"max_open_conns" usage:"Maximum number of allowed open connections to the database."` - MaxIdleConns int `yaml:"max_idle_conns" json:"max_idle_conns" usage:"Maximum number of allowed open but unused connections to the database."` + Addresses []string `yaml:"address" json:"address" usage:"List of database servers (username:password@address:port/dbname). Default 'root@127.0.0.1:26257'."` + ConnMaxLifetimeMs int `yaml:"conn_max_lifetime_ms" json:"conn_max_lifetime_ms" usage:"Time in milliseconds to reuse a database connection before the connection is killed and a new one is created. Default 0 (unlimited)."` + MaxOpenConns int `yaml:"max_open_conns" json:"max_open_conns" usage:"Maximum number of allowed open connections to the database. Default 100."` + MaxIdleConns int `yaml:"max_idle_conns" json:"max_idle_conns" usage:"Maximum number of allowed open but unused connections to the database. Default 100."` } // NewDatabaseConfig creates a new DatabaseConfig struct. @@ -401,7 +401,7 @@ func NewDatabaseConfig() *DatabaseConfig { return &DatabaseConfig{ Addresses: []string{"root@127.0.0.1:26257"}, ConnMaxLifetimeMs: 0, - MaxOpenConns: 0, + MaxOpenConns: 100, MaxIdleConns: 100, } } diff --git a/server/core_authenticate.go b/server/core_authenticate.go index d6fb2c18b..01821ef24 100644 --- a/server/core_authenticate.go +++ b/server/core_authenticate.go @@ -51,7 +51,7 @@ func AuthenticateCustom(ctx context.Context, logger *zap.Logger, db *sql.DB, cus if err == sql.ErrNoRows { found = false } else { - logger.Error("Cannot find user with custom ID.", zap.Error(err), zap.String("customID", customID), zap.String("username", username), zap.Bool("create", create)) + logger.Error("Error looking up user by custom ID.", zap.Error(err), zap.String("customID", customID), zap.String("username", username), zap.Bool("create", create)) return "", "", false, status.Error(codes.Internal, "Error finding user account.") } } @@ -112,7 +112,7 @@ func AuthenticateDevice(ctx context.Context, logger *zap.Logger, db *sql.DB, dev // No user account found. //return "", "", status.Error(codes.NotFound, "Device ID not found.") } else { - logger.Error("Cannot find user with device ID.", zap.Error(err), zap.String("deviceID", deviceID), zap.String("username", username), zap.Bool("create", create)) + logger.Error("Error looking up user by device ID.", zap.Error(err), zap.String("deviceID", deviceID), zap.String("username", username), zap.Bool("create", create)) return "", "", false, status.Error(codes.Internal, "Error finding user account.") } } @@ -125,7 +125,7 @@ func AuthenticateDevice(ctx context.Context, logger *zap.Logger, db *sql.DB, dev var dbDisableTime pq.NullTime err = db.QueryRowContext(ctx, query, dbUserID).Scan(&dbUsername, &dbDisableTime) if err != nil { - logger.Error("Cannot find user with device ID.", zap.Error(err), zap.String("deviceID", deviceID), zap.String("username", username), zap.Bool("create", create)) + logger.Error("Error looking up user by device ID.", zap.Error(err), zap.String("deviceID", deviceID), zap.String("username", username), zap.Bool("create", create)) return "", "", false, status.Error(codes.Internal, "Error finding user account.") } @@ -221,7 +221,7 @@ func AuthenticateEmail(ctx context.Context, logger *zap.Logger, db *sql.DB, emai if err == sql.ErrNoRows { found = false } else { - logger.Error("Cannot find user with email.", zap.Error(err), zap.String("email", email), zap.String("username", username), zap.Bool("create", create)) + logger.Error("Error looking up user by email.", zap.Error(err), zap.String("email", email), zap.String("username", username), zap.Bool("create", create)) return "", "", false, status.Error(codes.Internal, "Error finding user account.") } } @@ -293,7 +293,7 @@ func AuthenticateFacebook(ctx context.Context, logger *zap.Logger, db *sql.DB, c if err == sql.ErrNoRows { found = false } else { - logger.Error("Cannot find user with Facebook ID.", zap.Error(err), zap.String("facebookID", facebookProfile.ID), zap.String("username", username), zap.Bool("create", create)) + logger.Error("Error looking up user by Facebook ID.", zap.Error(err), zap.String("facebookID", facebookProfile.ID), zap.String("username", username), zap.Bool("create", create)) return "", "", false, status.Error(codes.Internal, "Error finding user account.") } } @@ -359,7 +359,7 @@ func AuthenticateGameCenter(ctx context.Context, logger *zap.Logger, db *sql.DB, if err == sql.ErrNoRows { found = false } else { - logger.Error("Cannot find user with GameCenter ID.", zap.Error(err), zap.String("gameCenterID", playerID), zap.String("username", username), zap.Bool("create", create)) + logger.Error("Error looking up user by GameCenter ID.", zap.Error(err), zap.String("gameCenterID", playerID), zap.String("username", username), zap.Bool("create", create)) return "", "", false, status.Error(codes.Internal, "Error finding user account.") } } @@ -425,7 +425,7 @@ func AuthenticateGoogle(ctx context.Context, logger *zap.Logger, db *sql.DB, cli if err == sql.ErrNoRows { found = false } else { - logger.Error("Cannot find user with Google ID.", zap.Error(err), zap.String("googleID", googleProfile.Sub), zap.String("username", username), zap.Bool("create", create)) + logger.Error("Error looking up user by Google ID.", zap.Error(err), zap.String("googleID", googleProfile.Sub), zap.String("username", username), zap.Bool("create", create)) return "", "", false, status.Error(codes.Internal, "Error finding user account.") } } @@ -492,7 +492,7 @@ func AuthenticateSteam(ctx context.Context, logger *zap.Logger, db *sql.DB, clie if err == sql.ErrNoRows { found = false } else { - logger.Error("Cannot find user with Steam ID.", zap.Error(err), zap.String("steamID", steamID), zap.String("username", username), zap.Bool("create", create)) + logger.Error("Error looking up user by Steam ID.", zap.Error(err), zap.String("steamID", steamID), zap.String("username", username), zap.Bool("create", create)) return "", "", false, status.Error(codes.Internal, "Error finding user account.") } } diff --git a/server/core_friend.go b/server/core_friend.go index 515c23049..403fb0594 100644 --- a/server/core_friend.go +++ b/server/core_friend.go @@ -19,6 +19,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/golang/protobuf/ptypes/wrappers" "time" "context" @@ -60,8 +61,10 @@ FROM users, user_edge WHERE id = destination_id AND source_id = $1` } friends = append(friends, &api.Friend{ - User: user, - State: int32(state.Int64), + User: user, + State: &wrappers.Int32Value{ + Value: int32(state.Int64), + }, }) } if err = rows.Err(); err != nil { @@ -127,8 +130,10 @@ FROM users, user_edge WHERE id = destination_id AND source_id = $1` } friends = append(friends, &api.Friend{ - User: user, - State: int32(state.Int64) + 1, + User: user, + State: &wrappers.Int32Value{ + Value: int32(state.Int64), + }, }) } if err = rows.Err(); err != nil { diff --git a/server/core_group.go b/server/core_group.go index 05523b3d4..d9a7a0ac2 100644 --- a/server/core_group.go +++ b/server/core_group.go @@ -773,17 +773,13 @@ WHERE u.id = ge.source_id AND ge.destination_id = $1 AND u.disable_time = '1970- Online: tracker.StreamExists(PresenceStream{Mode: StreamModeNotifications, Subject: userID}), } - groupUser := &api.GroupUserList_GroupUser{User: user} - switch state.Int64 { - case 0: - groupUser.State = int32(api.GroupUserList_GroupUser_SUPERADMIN) - case 1: - groupUser.State = int32(api.GroupUserList_GroupUser_ADMIN) - case 2: - groupUser.State = int32(api.GroupUserList_GroupUser_MEMBER) - case 3: - groupUser.State = int32(api.GroupUserList_GroupUser_JOIN_REQUEST) + groupUser := &api.GroupUserList_GroupUser{ + User: user, + State: &wrappers.Int32Value{ + Value: int32(state.Int64), + }, } + groupUsers = append(groupUsers, groupUser) } @@ -855,16 +851,11 @@ WHERE group_edge.destination_id = $1 AND disable_time = '1970-01-01 00:00:00'` UpdateTime: ×tamp.Timestamp{Seconds: updateTime.Time.Unix()}, } - userGroup := &api.UserGroupList_UserGroup{Group: group} - switch userState.Int64 { - case 0: - userGroup.State = int32(api.UserGroupList_UserGroup_SUPERADMIN) - case 1: - userGroup.State = int32(api.UserGroupList_UserGroup_ADMIN) - case 2: - userGroup.State = int32(api.UserGroupList_UserGroup_MEMBER) - case 3: - userGroup.State = int32(api.UserGroupList_UserGroup_JOIN_REQUEST) + userGroup := &api.UserGroupList_UserGroup{ + Group: group, + State: &wrappers.Int32Value{ + Value: int32(userState.Int64), + }, } userGroups = append(userGroups, userGroup) diff --git a/server/runtime_go_nakama.go b/server/runtime_go_nakama.go index 189bba975..7ace78de3 100644 --- a/server/runtime_go_nakama.go +++ b/server/runtime_go_nakama.go @@ -278,11 +278,26 @@ func (n *RuntimeGoNakamaModule) AccountUpdateId(ctx context.Context, userID, use metadataWrapper = &wrappers.StringValue{Value: string(metadataBytes)} } - displayNameWrapper := &wrappers.StringValue{Value: displayName} - timezoneWrapper := &wrappers.StringValue{Value: timezone} - locationWrapper := &wrappers.StringValue{Value: location} - langWrapper := &wrappers.StringValue{Value: langTag} - avatarWrapper := &wrappers.StringValue{Value: avatarUrl} + var displayNameWrapper *wrappers.StringValue + if displayName != "" { + displayNameWrapper = &wrappers.StringValue{Value: displayName} + } + var timezoneWrapper *wrappers.StringValue + if timezone != "" { + timezoneWrapper = &wrappers.StringValue{Value: timezone} + } + var locationWrapper *wrappers.StringValue + if location != "" { + locationWrapper = &wrappers.StringValue{Value: location} + } + var langWrapper *wrappers.StringValue + if langTag != "" { + langWrapper = &wrappers.StringValue{Value: langTag} + } + var avatarWrapper *wrappers.StringValue + if avatarUrl != "" { + avatarWrapper = &wrappers.StringValue{Value: avatarUrl} + } return UpdateAccount(ctx, n.logger, n.db, u, username, displayNameWrapper, timezoneWrapper, locationWrapper, langWrapper, avatarWrapper, metadataWrapper) } diff --git a/server/runtime_lua.go b/server/runtime_lua.go index 9f4856124..d54967a1d 100644 --- a/server/runtime_lua.go +++ b/server/runtime_lua.go @@ -176,7 +176,7 @@ func NewRuntimeProviderLua(logger, startupLogger *zap.Logger, db *sql.DB, jsonpb if core != nil { return core, nil } - return NewRuntimeLuaMatchCore(logger, db, config, socialClient, leaderboardCache, leaderboardRankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, stdLibs, once, localCache, goMatchCreateFn, id, node, name, labelUpdateFn) + return NewRuntimeLuaMatchCore(logger, db, jsonpbUnmarshaler, config, socialClient, leaderboardCache, leaderboardRankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, stdLibs, once, localCache, goMatchCreateFn, id, node, name, labelUpdateFn) } runtimeProviderLua := &RuntimeProviderLua{ @@ -200,7 +200,7 @@ func NewRuntimeProviderLua(logger, startupLogger *zap.Logger, db *sql.DB, jsonpb // Set the current count assuming we'll warm up the pool in a moment. currentCount: config.GetRuntime().MinCount, newFn: func() *RuntimeLua { - r, err := newRuntimeLuaVM(logger, db, config, socialClient, leaderboardCache, leaderboardRankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, stdLibs, moduleCache, once, localCache, allMatchCreateFn, nil) + r, err := newRuntimeLuaVM(logger, db, jsonpbUnmarshaler, config, socialClient, leaderboardCache, leaderboardRankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, stdLibs, moduleCache, once, localCache, allMatchCreateFn, nil) if err != nil { logger.Fatal("Failed to initialize Lua runtime", zap.Error(err)) } @@ -212,7 +212,7 @@ func NewRuntimeProviderLua(logger, startupLogger *zap.Logger, db *sql.DB, jsonpb startupLogger.Info("Evaluating Lua runtime modules") - r, err := newRuntimeLuaVM(logger, db, config, socialClient, leaderboardCache, leaderboardRankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, stdLibs, moduleCache, once, localCache, allMatchCreateFn, func(execMode RuntimeExecutionMode, id string) { + r, err := newRuntimeLuaVM(logger, db, jsonpbUnmarshaler, config, socialClient, leaderboardCache, leaderboardRankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, stdLibs, moduleCache, once, localCache, allMatchCreateFn, func(execMode RuntimeExecutionMode, id string) { switch execMode { case RuntimeExecutionModeRPC: rpcFunctions[id] = func(ctx context.Context, queryParams map[string][]string, userID, username string, expiry int64, sessionID, clientIP, clientPort, payload string) (string, error, codes.Code) { @@ -1706,7 +1706,7 @@ func (r *RuntimeLua) Stop() { r.vm.Close() } -func newRuntimeLuaVM(logger *zap.Logger, db *sql.DB, config Config, socialClient *social.Client, leaderboardCache LeaderboardCache, rankCache LeaderboardRankCache, leaderboardScheduler LeaderboardScheduler, sessionRegistry *SessionRegistry, matchRegistry MatchRegistry, tracker Tracker, router MessageRouter, stdLibs map[string]lua.LGFunction, moduleCache *RuntimeLuaModuleCache, once *sync.Once, localCache *RuntimeLuaLocalCache, matchCreateFn RuntimeMatchCreateFunction, announceCallbackFn func(RuntimeExecutionMode, string)) (*RuntimeLua, error) { +func newRuntimeLuaVM(logger *zap.Logger, db *sql.DB, jsonpbUnmarshaler *jsonpb.Unmarshaler, config Config, socialClient *social.Client, leaderboardCache LeaderboardCache, rankCache LeaderboardRankCache, leaderboardScheduler LeaderboardScheduler, sessionRegistry *SessionRegistry, matchRegistry MatchRegistry, tracker Tracker, router MessageRouter, stdLibs map[string]lua.LGFunction, moduleCache *RuntimeLuaModuleCache, once *sync.Once, localCache *RuntimeLuaLocalCache, matchCreateFn RuntimeMatchCreateFunction, announceCallbackFn func(RuntimeExecutionMode, string)) (*RuntimeLua, error) { // Initialize a one-off runtime to ensure startup code runs and modules are valid. vm := lua.NewState(lua.Options{ CallStackSize: config.GetRuntime().CallStackSize, @@ -1743,7 +1743,7 @@ func newRuntimeLuaVM(logger *zap.Logger, db *sql.DB, config Config, socialClient callbacks.LeaderboardReset = fn } } - nakamaModule := NewRuntimeLuaNakamaModule(logger, db, config, socialClient, leaderboardCache, rankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, once, localCache, matchCreateFn, registerCallbackFn, announceCallbackFn) + nakamaModule := NewRuntimeLuaNakamaModule(logger, db, jsonpbUnmarshaler, config, socialClient, leaderboardCache, rankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, once, localCache, matchCreateFn, registerCallbackFn, announceCallbackFn) vm.PreloadModule("nakama", nakamaModule.Loader) r := &RuntimeLua{ logger: logger, diff --git a/server/runtime_lua_match_core.go b/server/runtime_lua_match_core.go index c52b5a4d7..63e936fee 100644 --- a/server/runtime_lua_match_core.go +++ b/server/runtime_lua_match_core.go @@ -19,6 +19,7 @@ import ( "database/sql" "errors" "fmt" + "github.com/golang/protobuf/jsonpb" "sync" "github.com/gofrs/uuid" @@ -54,7 +55,7 @@ type RuntimeLuaMatchCore struct { ctxCancelFn context.CancelFunc } -func NewRuntimeLuaMatchCore(logger *zap.Logger, db *sql.DB, config Config, socialClient *social.Client, leaderboardCache LeaderboardCache, rankCache LeaderboardRankCache, leaderboardScheduler LeaderboardScheduler, sessionRegistry *SessionRegistry, matchRegistry MatchRegistry, tracker Tracker, router MessageRouter, stdLibs map[string]lua.LGFunction, once *sync.Once, localCache *RuntimeLuaLocalCache, goMatchCreateFn RuntimeMatchCreateFunction, id uuid.UUID, node string, name string, labelUpdateFn RuntimeMatchLabelUpdateFunction) (RuntimeMatchCore, error) { +func NewRuntimeLuaMatchCore(logger *zap.Logger, db *sql.DB, jsonpbUnmarshaler *jsonpb.Unmarshaler, config Config, socialClient *social.Client, leaderboardCache LeaderboardCache, rankCache LeaderboardRankCache, leaderboardScheduler LeaderboardScheduler, sessionRegistry *SessionRegistry, matchRegistry MatchRegistry, tracker Tracker, router MessageRouter, stdLibs map[string]lua.LGFunction, once *sync.Once, localCache *RuntimeLuaLocalCache, goMatchCreateFn RuntimeMatchCreateFunction, id uuid.UUID, node string, name string, labelUpdateFn RuntimeMatchLabelUpdateFunction) (RuntimeMatchCore, error) { // Set up the Lua VM that will handle this match. vm := lua.NewState(lua.Options{ CallStackSize: config.GetRuntime().CallStackSize, @@ -78,10 +79,10 @@ func NewRuntimeLuaMatchCore(logger *zap.Logger, db *sql.DB, config Config, socia if core != nil { return core, nil } - return NewRuntimeLuaMatchCore(logger, db, config, socialClient, leaderboardCache, rankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, stdLibs, once, localCache, goMatchCreateFn, id, node, name, labelUpdateFn) + return NewRuntimeLuaMatchCore(logger, db, jsonpbUnmarshaler, config, socialClient, leaderboardCache, rankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, stdLibs, once, localCache, goMatchCreateFn, id, node, name, labelUpdateFn) } - nakamaModule := NewRuntimeLuaNakamaModule(logger, db, config, socialClient, leaderboardCache, rankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, once, localCache, allMatchCreateFn, nil, nil) + nakamaModule := NewRuntimeLuaNakamaModule(logger, db, jsonpbUnmarshaler, config, socialClient, leaderboardCache, rankCache, leaderboardScheduler, sessionRegistry, matchRegistry, tracker, router, once, localCache, allMatchCreateFn, nil, nil) vm.PreloadModule("nakama", nakamaModule.Loader) // Create the context to be used throughout this match. diff --git a/server/runtime_lua_nakama.go b/server/runtime_lua_nakama.go index b2b352ba4..111c5e9bd 100644 --- a/server/runtime_lua_nakama.go +++ b/server/runtime_lua_nakama.go @@ -28,6 +28,7 @@ import ( "encoding/hex" "encoding/json" "fmt" + "github.com/golang/protobuf/jsonpb" "io" "io/ioutil" "net/http" @@ -50,6 +51,7 @@ import ( type RuntimeLuaNakamaModule struct { logger *zap.Logger db *sql.DB + jsonpbUnmarshaler *jsonpb.Unmarshaler config Config socialClient *social.Client leaderboardCache LeaderboardCache @@ -69,10 +71,11 @@ type RuntimeLuaNakamaModule struct { matchCreateFn RuntimeMatchCreateFunction } -func NewRuntimeLuaNakamaModule(logger *zap.Logger, db *sql.DB, config Config, socialClient *social.Client, leaderboardCache LeaderboardCache, rankCache LeaderboardRankCache, leaderboardScheduler LeaderboardScheduler, sessionRegistry *SessionRegistry, matchRegistry MatchRegistry, tracker Tracker, router MessageRouter, once *sync.Once, localCache *RuntimeLuaLocalCache, matchCreateFn RuntimeMatchCreateFunction, registerCallbackFn func(RuntimeExecutionMode, string, *lua.LFunction), announceCallbackFn func(RuntimeExecutionMode, string)) *RuntimeLuaNakamaModule { +func NewRuntimeLuaNakamaModule(logger *zap.Logger, db *sql.DB, jsonpbUnmarshaler *jsonpb.Unmarshaler, config Config, socialClient *social.Client, leaderboardCache LeaderboardCache, rankCache LeaderboardRankCache, leaderboardScheduler LeaderboardScheduler, sessionRegistry *SessionRegistry, matchRegistry MatchRegistry, tracker Tracker, router MessageRouter, once *sync.Once, localCache *RuntimeLuaLocalCache, matchCreateFn RuntimeMatchCreateFunction, registerCallbackFn func(RuntimeExecutionMode, string, *lua.LFunction), announceCallbackFn func(RuntimeExecutionMode, string)) *RuntimeLuaNakamaModule { return &RuntimeLuaNakamaModule{ logger: logger, db: db, + jsonpbUnmarshaler: jsonpbUnmarshaler, config: config, socialClient: socialClient, leaderboardCache: leaderboardCache, @@ -160,6 +163,7 @@ func (n *RuntimeLuaNakamaModule) Loader(l *lua.LState) int { "stream_count": n.streamCount, "stream_close": n.streamClose, "stream_send": n.streamSend, + "stream_send_raw": n.streamSendRaw, "match_create": n.matchCreate, "match_list": n.matchList, "notification_send": n.notificationSend, @@ -2442,6 +2446,96 @@ func (n *RuntimeLuaNakamaModule) streamSend(l *lua.LState) int { return 0 } +func (n *RuntimeLuaNakamaModule) streamSendRaw(l *lua.LState) int { + // Parse input stream identifier. + streamTable := l.CheckTable(1) + if streamTable == nil { + l.ArgError(1, "expects a valid stream") + return 0 + } + stream := PresenceStream{} + conversionError := false + streamTable.ForEach(func(k lua.LValue, v lua.LValue) { + if conversionError { + return + } + + switch k.String() { + case "mode": + if v.Type() != lua.LTNumber { + conversionError = true + l.ArgError(3, "stream mode must be a number") + return + } + stream.Mode = uint8(lua.LVAsNumber(v)) + case "subject": + if v.Type() != lua.LTString { + conversionError = true + l.ArgError(3, "stream subject must be a string") + return + } + sid, err := uuid.FromString(v.String()) + if err != nil { + conversionError = true + l.ArgError(3, "stream subject must be a valid identifier") + return + } + stream.Subject = sid + case "descriptor": + if v.Type() != lua.LTString { + conversionError = true + l.ArgError(3, "stream descriptor must be a string") + return + } + did, err := uuid.FromString(v.String()) + if err != nil { + conversionError = true + l.ArgError(3, "stream descriptor must be a valid identifier") + return + } + stream.Subject = did + case "label": + if v.Type() != lua.LTString { + conversionError = true + l.ArgError(3, "stream label must be a string") + return + } + stream.Label = v.String() + } + }) + if conversionError { + return 0 + } + + envelopeMap := RuntimeLuaConvertLuaTable(l.CheckTable(2)) + envelopeBytes, err := json.Marshal(envelopeMap) + if err != nil { + l.ArgError(2, fmt.Sprintf("failed to convert envlope: %s", err.Error())) + return 0 + } + + envelope := &rtapi.Envelope{} + err = n.jsonpbUnmarshaler.Unmarshal(bytes.NewReader(envelopeBytes), envelope) + if err != nil { + l.ArgError(2, fmt.Sprintf("not a valid envlope: %s", err.Error())) + return 0 + } + + streamWire := &rtapi.Stream{ + Mode: int32(stream.Mode), + Label: stream.Label, + } + if stream.Subject != uuid.Nil { + streamWire.Subject = stream.Subject.String() + } + if stream.Descriptor != uuid.Nil { + streamWire.Descriptor_ = stream.Descriptor.String() + } + n.router.SendToStream(n.logger, stream, envelope) + + return 0 +} + func (n *RuntimeLuaNakamaModule) matchCreate(l *lua.LState) int { // Parse the name of the Lua module that should handle the match. module := l.CheckString(1) @@ -4484,7 +4578,7 @@ func (n *RuntimeLuaNakamaModule) groupUsersList(l *lua.LState) int { gt := l.CreateTable(0, 2) ut.RawSetString("user", ut) - ut.RawSetString("state", lua.LNumber(ug.State)) + ut.RawSetString("state", lua.LNumber(ug.State.Value)) groupUsers.RawSetInt(i+1, gt) } @@ -4534,7 +4628,7 @@ func (n *RuntimeLuaNakamaModule) userGroupsList(l *lua.LState) int { ugt := l.CreateTable(0, 2) ugt.RawSetString("group", gt) - ugt.RawSetString("state", lua.LNumber(ug.State)) + ugt.RawSetString("state", lua.LNumber(ug.State.Value)) userGroups.RawSetInt(i+1, ugt) } @@ -4566,31 +4660,31 @@ func (n *RuntimeLuaNakamaModule) accountUpdateId(l *lua.LState) int { displayNameL := l.Get(4) var displayName *wrappers.StringValue - if displayNameL != nil { + if displayNameL != lua.LNil { displayName = &wrappers.StringValue{Value: l.OptString(4, "")} } timezoneL := l.Get(5) var timezone *wrappers.StringValue - if timezoneL != nil { + if timezoneL != lua.LNil { timezone = &wrappers.StringValue{Value: l.OptString(5, "")} } locationL := l.Get(6) var location *wrappers.StringValue - if locationL != nil { + if locationL != lua.LNil { location = &wrappers.StringValue{Value: l.OptString(6, "")} } langL := l.Get(7) var lang *wrappers.StringValue - if langL != nil { + if langL != lua.LNil { lang = &wrappers.StringValue{Value: l.OptString(7, "")} } avatarL := l.Get(8) var avatar *wrappers.StringValue - if avatarL != nil { + if avatarL != lua.LNil { avatar = &wrappers.StringValue{Value: l.OptString(8, "")} } -- GitLab