diff --git a/.golangci.yml b/.golangci.yml index cf941da80..3452b8be0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -49,6 +49,11 @@ linters-settings: excludes: - G602 - G108 + tagliatelle: + case: + use-field-name: true + rules: + json: snake linters: disable-all: true @@ -70,6 +75,7 @@ linters: - govet - unconvert - errorlint + - tagliatelle severity: default-severity: error diff --git a/.mockery.yaml b/.mockery.yaml index 106bba565..601de9ed2 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -120,9 +120,6 @@ packages: github.com/anyproto/anytype-heart/space/internal/components/participantwatcher: interfaces: ParticipantWatcher: - github.com/anyproto/anytype-heart/space/internal/components/invitemigrator: - interfaces: - InviteMigrator: github.com/anyproto/anytype-heart/space/internal/components/aclnotifications: interfaces: AclNotification: @@ -242,7 +239,7 @@ packages: github.com/anyproto/anytype-heart/core/api/core: interfaces: AccountService: - ExportService: + EventService: ClientCommands: github.com/anyproto/anytype-heart/core/block/template: interfaces: @@ -253,3 +250,6 @@ packages: github.com/anyproto/anytype-heart/core/block/editor/chatobject: interfaces: StoreObject: + github.com/anyproto/anytype-heart/core/block/chats/chatsubscription: + interfaces: + Service: diff --git a/clientlibrary/service/service.pb.go b/clientlibrary/service/service.pb.go index b721fdbac..3e38c5be7 100644 --- a/clientlibrary/service/service.pb.go +++ b/clientlibrary/service/service.pb.go @@ -25,368 +25,373 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package func init() { proto.RegisterFile("pb/protos/service/service.proto", fileDescriptor_93a29dc403579097) } var fileDescriptor_93a29dc403579097 = []byte{ - // 5766 bytes of a gzipped FileDescriptorProto + // 5854 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x9d, 0xdd, 0x6f, 0x24, 0x49, - 0x52, 0xc0, 0xd7, 0x2f, 0x2c, 0xd4, 0x71, 0x0b, 0xf4, 0xc2, 0xb2, 0xb7, 0xdc, 0xcd, 0xcc, 0xce, - 0x87, 0x3d, 0x33, 0x1e, 0xb7, 0x67, 0x67, 0xf6, 0x8b, 0x3b, 0x24, 0xe8, 0xb1, 0xc7, 0xde, 0xbe, - 0xb5, 0xbd, 0xc6, 0xdd, 0x9e, 0x11, 0x2b, 0x21, 0x51, 0xee, 0x4a, 0xb7, 0x0b, 0x57, 0x57, 0xd6, - 0x55, 0x65, 0x7b, 0xa6, 0x0f, 0x81, 0x40, 0x20, 0x10, 0x08, 0xc4, 0x89, 0x2f, 0xc1, 0x13, 0x12, - 0x7f, 0x01, 0x7f, 0x06, 0x8f, 0xf7, 0xc8, 0x23, 0xda, 0xfd, 0x33, 0x78, 0x00, 0x55, 0x66, 0x56, - 0x7e, 0x44, 0x45, 0x64, 0x95, 0xf7, 0x9e, 0x66, 0xe4, 0xf8, 0x45, 0x44, 0x7e, 0x44, 0x66, 0x46, - 0x66, 0x65, 0x55, 0x47, 0x37, 0x8b, 0xb3, 0xed, 0xa2, 0xe4, 0x82, 0x57, 0xdb, 0x15, 0x2b, 0xaf, - 0xd2, 0x19, 0x6b, 0xfe, 0x1d, 0xca, 0x3f, 0x0f, 0xde, 0x8c, 0xf3, 0x95, 0x58, 0x15, 0xec, 0xbd, - 0x77, 0x2d, 0x39, 0xe3, 0x8b, 0x45, 0x9c, 0x27, 0x95, 0x42, 0xde, 0x7b, 0xc7, 0x4a, 0xd8, 0x15, - 0xcb, 0x85, 0xfe, 0xfb, 0x93, 0xff, 0xfd, 0xbf, 0xb5, 0xe8, 0xad, 0x9d, 0x2c, 0x65, 0xb9, 0xd8, - 0xd1, 0x1a, 0x83, 0x2f, 0xa3, 0x6f, 0x8f, 0x8a, 0x62, 0x9f, 0x89, 0x17, 0xac, 0xac, 0x52, 0x9e, - 0x0f, 0xee, 0x0c, 0xb5, 0x83, 0xe1, 0x49, 0x31, 0x1b, 0x8e, 0x8a, 0x62, 0x68, 0x85, 0xc3, 0x13, - 0xf6, 0xa3, 0x25, 0xab, 0xc4, 0x7b, 0x77, 0xc3, 0x50, 0x55, 0xf0, 0xbc, 0x62, 0x83, 0xf3, 0xe8, - 0x57, 0x46, 0x45, 0x31, 0x61, 0x62, 0x97, 0xd5, 0x15, 0x98, 0x88, 0x58, 0xb0, 0xc1, 0x46, 0x4b, - 0xd5, 0x07, 0x8c, 0x8f, 0xfb, 0xdd, 0xa0, 0xf6, 0x33, 0x8d, 0xbe, 0x55, 0xfb, 0xb9, 0x58, 0x8a, - 0x84, 0xbf, 0xca, 0x07, 0xef, 0xb7, 0x15, 0xb5, 0xc8, 0xd8, 0xbe, 0x1d, 0x42, 0xb4, 0xd5, 0x97, - 0xd1, 0x2f, 0xbe, 0x8c, 0xb3, 0x8c, 0x89, 0x9d, 0x92, 0xd5, 0x05, 0xf7, 0x75, 0x94, 0x68, 0xa8, - 0x64, 0xc6, 0xee, 0x9d, 0x20, 0xa3, 0x0d, 0x7f, 0x19, 0x7d, 0x5b, 0x49, 0x4e, 0xd8, 0x8c, 0x5f, - 0xb1, 0x72, 0x80, 0x6a, 0x69, 0x21, 0xd1, 0xe4, 0x2d, 0x08, 0xda, 0xde, 0xe1, 0xf9, 0x15, 0x2b, - 0x05, 0x6e, 0x5b, 0x0b, 0xc3, 0xb6, 0x2d, 0xa4, 0x6d, 0xff, 0xf5, 0x5a, 0xf4, 0xdd, 0xd1, 0x6c, - 0xc6, 0x97, 0xb9, 0x38, 0xe0, 0xb3, 0x38, 0x3b, 0x48, 0xf3, 0xcb, 0x23, 0xf6, 0x6a, 0xe7, 0xa2, - 0xe6, 0xf3, 0x39, 0x1b, 0x3c, 0xf5, 0x5b, 0x55, 0xa1, 0x43, 0xc3, 0x0e, 0x5d, 0xd8, 0xf8, 0xfe, - 0xf0, 0x7a, 0x4a, 0xba, 0x2c, 0x7f, 0xbf, 0x16, 0xdd, 0x80, 0x65, 0x99, 0xf0, 0xec, 0x8a, 0xd9, - 0xd2, 0x7c, 0xd4, 0x61, 0xd8, 0xc7, 0x4d, 0x79, 0x3e, 0xbe, 0xae, 0x9a, 0x2e, 0x51, 0x16, 0xbd, - 0xed, 0x86, 0xcb, 0x84, 0x55, 0x72, 0x38, 0x3d, 0xa0, 0x23, 0x42, 0x23, 0xc6, 0xf3, 0xc3, 0x3e, - 0xa8, 0xf6, 0x96, 0x46, 0x03, 0xed, 0x2d, 0xe3, 0x95, 0x71, 0x76, 0x1f, 0xb5, 0xe0, 0x10, 0xc6, - 0xd7, 0x83, 0x1e, 0xa4, 0x76, 0xf5, 0x07, 0xd1, 0x2f, 0xbd, 0xe4, 0xe5, 0x65, 0x55, 0xc4, 0x33, - 0xa6, 0x87, 0xc2, 0x3d, 0x5f, 0xbb, 0x91, 0xc2, 0xd1, 0xb0, 0xde, 0x85, 0x39, 0x41, 0xdb, 0x08, - 0xbf, 0x28, 0x18, 0x9c, 0x83, 0xac, 0x62, 0x2d, 0xa4, 0x82, 0x16, 0x42, 0xda, 0xf6, 0x65, 0x34, - 0xb0, 0xb6, 0xcf, 0xfe, 0x90, 0xcd, 0xc4, 0x28, 0x49, 0x60, 0xaf, 0x58, 0x5d, 0x49, 0x0c, 0x47, - 0x49, 0x42, 0xf5, 0x0a, 0x8e, 0x6a, 0x67, 0xaf, 0xa2, 0x77, 0x80, 0xb3, 0x83, 0xb4, 0x92, 0x0e, - 0xb7, 0xc2, 0x56, 0x34, 0x66, 0x9c, 0x0e, 0xfb, 0xe2, 0xda, 0xf1, 0x9f, 0xae, 0x45, 0xdf, 0x41, - 0x3c, 0x9f, 0xb0, 0x05, 0xbf, 0x62, 0x83, 0xc7, 0xdd, 0xd6, 0x14, 0x69, 0xfc, 0x7f, 0x70, 0x0d, - 0x0d, 0x24, 0x4c, 0x26, 0x2c, 0x63, 0x33, 0x41, 0x86, 0x89, 0x12, 0x77, 0x86, 0x89, 0xc1, 0x9c, - 0x11, 0xd6, 0x08, 0xf7, 0x99, 0xd8, 0x59, 0x96, 0x25, 0xcb, 0x05, 0xd9, 0x97, 0x16, 0xe9, 0xec, - 0x4b, 0x0f, 0x45, 0xea, 0xb3, 0xcf, 0xc4, 0x28, 0xcb, 0xc8, 0xfa, 0x28, 0x71, 0x67, 0x7d, 0x0c, - 0xa6, 0x3d, 0xcc, 0xa2, 0x5f, 0x76, 0x5a, 0x4c, 0x8c, 0xf3, 0x73, 0x3e, 0xa0, 0xdb, 0x42, 0xca, - 0x8d, 0x8f, 0x8d, 0x4e, 0x0e, 0xa9, 0xc6, 0xf3, 0xd7, 0x05, 0x2f, 0xe9, 0x6e, 0x51, 0xe2, 0xce, - 0x6a, 0x18, 0x4c, 0x7b, 0xf8, 0xfd, 0xe8, 0x2d, 0x3d, 0x4b, 0x36, 0xeb, 0xd9, 0x5d, 0x74, 0x0a, - 0x85, 0x0b, 0xda, 0xbd, 0x0e, 0xaa, 0x65, 0xfe, 0x30, 0x9d, 0x97, 0xf5, 0xec, 0x83, 0x9b, 0xd7, - 0xd2, 0x0e, 0xf3, 0x96, 0xd2, 0xe6, 0x79, 0xf4, 0xab, 0xbe, 0xf9, 0x9d, 0x38, 0x9f, 0xb1, 0x6c, - 0xf0, 0x30, 0xa4, 0xae, 0x18, 0xe3, 0x6a, 0xb3, 0x17, 0x6b, 0x27, 0x3b, 0x4d, 0xe8, 0xc9, 0xf4, - 0x0e, 0xaa, 0x0d, 0xa6, 0xd2, 0xbb, 0x61, 0xa8, 0x65, 0x7b, 0x97, 0x65, 0x8c, 0xb4, 0xad, 0x84, - 0x1d, 0xb6, 0x0d, 0xa4, 0x6d, 0x97, 0xd1, 0xaf, 0x99, 0x6e, 0xae, 0xf3, 0x02, 0x29, 0xaf, 0x17, - 0x9d, 0x4d, 0xa2, 0x1f, 0x5d, 0xc8, 0xf8, 0x7a, 0xd4, 0x0f, 0x6e, 0xd5, 0x47, 0xcf, 0x28, 0x78, - 0x7d, 0xc0, 0x7c, 0x72, 0x37, 0x0c, 0x69, 0xdb, 0x7f, 0xb3, 0x16, 0x7d, 0x4f, 0xcb, 0x9e, 0xe7, - 0xf1, 0x59, 0xc6, 0xe4, 0x12, 0x7f, 0xc4, 0xc4, 0x2b, 0x5e, 0x5e, 0x4e, 0x56, 0xf9, 0x8c, 0x48, - 0x67, 0x70, 0xb8, 0x23, 0x9d, 0x21, 0x95, 0x74, 0x61, 0xfe, 0x28, 0x7a, 0xb7, 0x09, 0x8a, 0x8b, - 0x38, 0x9f, 0xb3, 0x1f, 0x56, 0x3c, 0x1f, 0x15, 0xe9, 0x28, 0x49, 0xca, 0xc1, 0x10, 0xef, 0x7a, - 0xc8, 0x99, 0x12, 0x6c, 0xf7, 0xe6, 0x9d, 0xf4, 0x59, 0xb7, 0xb2, 0xe0, 0x05, 0x4c, 0x9f, 0x9b, - 0xe6, 0x13, 0xbc, 0xa0, 0xd2, 0x67, 0x1f, 0x69, 0x59, 0x3d, 0xac, 0xd7, 0x20, 0xdc, 0xea, 0xa1, - 0xbb, 0xe8, 0xdc, 0x0e, 0x21, 0x76, 0x0d, 0x68, 0x1a, 0x8a, 0xe7, 0xe7, 0xe9, 0xfc, 0xb4, 0x48, - 0xea, 0x31, 0xf4, 0x00, 0xaf, 0xb3, 0x83, 0x10, 0x6b, 0x00, 0x81, 0x6a, 0x6f, 0x7f, 0x67, 0xb3, - 0x4c, 0x3d, 0x2f, 0xed, 0x95, 0x7c, 0x71, 0xc0, 0xe6, 0xf1, 0x6c, 0xa5, 0x27, 0xd3, 0x0f, 0x43, - 0xb3, 0x18, 0xa4, 0x4d, 0x21, 0x3e, 0xba, 0xa6, 0x96, 0x2e, 0xcf, 0xbf, 0xaf, 0x45, 0x77, 0xbd, - 0x38, 0xd1, 0xc1, 0xa4, 0x4a, 0x3f, 0xca, 0x93, 0x13, 0x56, 0x89, 0xb8, 0x14, 0x83, 0xef, 0x07, - 0x62, 0x80, 0xd0, 0x31, 0x65, 0xfb, 0xc1, 0x37, 0xd2, 0xb5, 0xbd, 0x3e, 0xa9, 0x57, 0x09, 0x3d, - 0xff, 0xf8, 0xbd, 0x2e, 0x25, 0x70, 0xf6, 0xb9, 0x1d, 0x42, 0x6c, 0xaf, 0x4b, 0xc1, 0x38, 0xbf, - 0x4a, 0x05, 0xdb, 0x67, 0x39, 0x2b, 0xdb, 0xbd, 0xae, 0x54, 0x7d, 0x84, 0xe8, 0x75, 0x02, 0xb5, - 0x33, 0x9d, 0xe7, 0xcd, 0x64, 0x1a, 0x9b, 0x01, 0x23, 0xad, 0x5c, 0xe3, 0x51, 0x3f, 0x98, 0xa8, - 0xa1, 0xd8, 0xaf, 0x8d, 0x04, 0x6b, 0xa8, 0x90, 0x5e, 0x35, 0x34, 0xa8, 0xdd, 0x98, 0x3b, 0xde, - 0x4e, 0xd8, 0x15, 0xbf, 0x84, 0x1b, 0x73, 0xd7, 0x80, 0x02, 0x88, 0x8d, 0x39, 0x0a, 0xda, 0xe4, - 0xc3, 0xf1, 0xf3, 0x22, 0x65, 0xaf, 0x40, 0xf2, 0xe1, 0x2a, 0xd7, 0x62, 0x22, 0xf9, 0x40, 0x30, - 0xed, 0xe1, 0x28, 0xfa, 0x05, 0x29, 0xfc, 0x21, 0x4f, 0xf3, 0xc1, 0x4d, 0x44, 0xa9, 0x16, 0x18, - 0xab, 0xb7, 0x68, 0x00, 0x94, 0xb8, 0xfe, 0xab, 0xce, 0x04, 0xee, 0x11, 0x4a, 0x20, 0x09, 0x58, - 0xef, 0xc2, 0x6c, 0xd6, 0x27, 0x85, 0xf5, 0x6c, 0x39, 0xb9, 0x88, 0xcb, 0x34, 0x9f, 0x0f, 0x30, - 0x5d, 0x47, 0x4e, 0x64, 0x7d, 0x18, 0x07, 0xc2, 0x49, 0x2b, 0x8e, 0x8a, 0xa2, 0xac, 0x27, 0x61, - 0x2c, 0x9c, 0x7c, 0x24, 0x18, 0x4e, 0x2d, 0x14, 0xf7, 0xb6, 0xcb, 0x66, 0x59, 0x9a, 0x07, 0xbd, - 0x69, 0xa4, 0x8f, 0x37, 0x8b, 0x82, 0xe0, 0x3d, 0x60, 0xf1, 0x15, 0x6b, 0x6a, 0x86, 0xb5, 0x8c, - 0x0b, 0x04, 0x83, 0x17, 0x80, 0x76, 0x8b, 0x2d, 0xc5, 0x87, 0xf1, 0x25, 0xab, 0x1b, 0x98, 0xd5, - 0x4b, 0xf8, 0x00, 0xd3, 0xf7, 0x08, 0x62, 0x8b, 0x8d, 0x93, 0xda, 0xd5, 0x32, 0x7a, 0x47, 0xca, - 0x8f, 0xe3, 0x52, 0xa4, 0xb3, 0xb4, 0x88, 0xf3, 0x66, 0xeb, 0x86, 0xcd, 0x22, 0x2d, 0xca, 0xb8, - 0xdc, 0xea, 0x49, 0x6b, 0xb7, 0xff, 0xb2, 0x16, 0xbd, 0x0f, 0xfd, 0x1e, 0xb3, 0x72, 0x91, 0xca, - 0x13, 0x80, 0x4a, 0x4d, 0xf9, 0x83, 0x4f, 0xc2, 0x46, 0x5b, 0x0a, 0xa6, 0x34, 0x9f, 0x5e, 0x5f, - 0xd1, 0xe6, 0x7d, 0x13, 0xbd, 0x2b, 0xfa, 0xa2, 0x4c, 0x5a, 0x27, 0x64, 0x93, 0x66, 0xab, 0x23, - 0x85, 0x44, 0xde, 0xd7, 0x82, 0xc0, 0x08, 0x3f, 0xcd, 0xab, 0xc6, 0x3a, 0x36, 0xc2, 0xad, 0x38, - 0x38, 0xc2, 0x3d, 0xcc, 0x8e, 0xf0, 0xe3, 0xe5, 0x59, 0x96, 0x56, 0x17, 0x69, 0x3e, 0xd7, 0x49, - 0xbe, 0xaf, 0x6b, 0xc5, 0x30, 0xcf, 0xdf, 0xe8, 0xe4, 0x30, 0x27, 0x3a, 0x58, 0x48, 0x27, 0x20, - 0x4c, 0x36, 0x3a, 0x39, 0xbb, 0xf7, 0xb2, 0xd2, 0x7a, 0xd3, 0x0f, 0xf6, 0x5e, 0x8e, 0x6a, 0x2d, - 0x25, 0xf6, 0x5e, 0x6d, 0xca, 0xee, 0xbd, 0xdc, 0x3a, 0x54, 0x3c, 0xbb, 0x62, 0xa7, 0x65, 0x0a, - 0xf6, 0x5e, 0x5e, 0xf9, 0x1a, 0x86, 0xd8, 0x7b, 0x51, 0xac, 0x9d, 0xa8, 0x2c, 0xb1, 0xcf, 0xc4, - 0x44, 0xc4, 0x62, 0x59, 0x81, 0x89, 0xca, 0xb1, 0x61, 0x10, 0x62, 0xa2, 0x22, 0x50, 0xed, 0xed, - 0x77, 0xa3, 0x48, 0x9d, 0x97, 0xc8, 0x33, 0x2d, 0x7f, 0xed, 0xd1, 0x07, 0x29, 0xde, 0x81, 0xd6, - 0xfb, 0x01, 0xc2, 0xa6, 0x57, 0xea, 0xef, 0xf2, 0xa8, 0x6e, 0x80, 0x6a, 0x48, 0x11, 0x91, 0x5e, - 0x01, 0x04, 0x16, 0x74, 0x72, 0xc1, 0x5f, 0xe1, 0x05, 0xad, 0x25, 0xe1, 0x82, 0x6a, 0xc2, 0x1e, - 0x9e, 0xeb, 0x82, 0x62, 0x87, 0xe7, 0x4d, 0x31, 0x42, 0x87, 0xe7, 0x90, 0xb1, 0x31, 0xe3, 0x1a, - 0x7e, 0xc6, 0xf9, 0xe5, 0x22, 0x2e, 0x2f, 0x41, 0xcc, 0x78, 0xca, 0x0d, 0x43, 0xc4, 0x0c, 0xc5, - 0xda, 0x98, 0x71, 0x1d, 0xd6, 0xc9, 0xf9, 0x69, 0x99, 0x81, 0x98, 0xf1, 0x6c, 0x68, 0x84, 0x88, - 0x19, 0x02, 0xb5, 0xb3, 0x93, 0xeb, 0x6d, 0xc2, 0xe0, 0x71, 0x8d, 0xa7, 0x3e, 0x61, 0xd4, 0x71, - 0x0d, 0x82, 0xc1, 0x10, 0xda, 0x2f, 0xe3, 0xe2, 0x02, 0x0f, 0x21, 0x29, 0x0a, 0x87, 0x50, 0x83, - 0xc0, 0xfe, 0x9e, 0xb0, 0xb8, 0x9c, 0x5d, 0xe0, 0xfd, 0xad, 0x64, 0xe1, 0xfe, 0x36, 0x0c, 0xec, - 0x6f, 0x25, 0x78, 0x99, 0x8a, 0x8b, 0x43, 0x26, 0x62, 0xbc, 0xbf, 0x7d, 0x26, 0xdc, 0xdf, 0x2d, - 0xd6, 0x66, 0xff, 0xae, 0xc3, 0xc9, 0xf2, 0xac, 0x9a, 0x95, 0xe9, 0x19, 0x1b, 0x04, 0xac, 0x18, - 0x88, 0xc8, 0xfe, 0x49, 0x58, 0xfb, 0xfc, 0xc9, 0x5a, 0x74, 0xb3, 0xe9, 0x76, 0x5e, 0x55, 0x7a, - 0xed, 0xf3, 0xdd, 0x7f, 0x84, 0xf7, 0x2f, 0x81, 0x13, 0x8f, 0x33, 0x7a, 0xa8, 0x39, 0xb9, 0x01, - 0x5e, 0xa4, 0xd3, 0xbc, 0x32, 0x85, 0xfa, 0xa4, 0x8f, 0x75, 0x47, 0x81, 0xc8, 0x0d, 0x7a, 0x29, - 0xda, 0xb4, 0x4c, 0xf7, 0x4f, 0x23, 0x1b, 0x27, 0x15, 0x48, 0xcb, 0x9a, 0xf6, 0x76, 0x08, 0x22, - 0x2d, 0xc3, 0x49, 0x18, 0x0a, 0xfb, 0x25, 0x5f, 0x16, 0x55, 0x47, 0x28, 0x00, 0x28, 0x1c, 0x0a, - 0x6d, 0x58, 0xfb, 0x7c, 0x1d, 0xfd, 0xba, 0x1b, 0x7e, 0x6e, 0x63, 0x6f, 0xd1, 0x31, 0x85, 0x35, - 0xf1, 0xb0, 0x2f, 0x6e, 0x33, 0x8a, 0xc6, 0xb3, 0xd8, 0x65, 0x22, 0x4e, 0xb3, 0x6a, 0xb0, 0x8e, - 0xdb, 0x68, 0xe4, 0x44, 0x46, 0x81, 0x71, 0x70, 0x7e, 0xdb, 0x5d, 0x16, 0x59, 0x3a, 0x6b, 0x3f, - 0x4c, 0xd2, 0xba, 0x46, 0x1c, 0x9e, 0xdf, 0x5c, 0x0c, 0xce, 0xd7, 0x75, 0xea, 0x27, 0xff, 0x33, - 0x5d, 0x15, 0x0c, 0x9f, 0xaf, 0x3d, 0x24, 0x3c, 0x5f, 0x43, 0x14, 0xd6, 0x67, 0xc2, 0xc4, 0x41, - 0xbc, 0xe2, 0x4b, 0x62, 0xbe, 0x36, 0xe2, 0x70, 0x7d, 0x5c, 0xcc, 0xee, 0x0d, 0x8c, 0x87, 0x71, - 0x2e, 0x58, 0x99, 0xc7, 0xd9, 0x5e, 0x16, 0xcf, 0xab, 0x01, 0x31, 0xc7, 0xf8, 0x14, 0xb1, 0x37, - 0xa0, 0x69, 0xa4, 0x19, 0xc7, 0xd5, 0x5e, 0x7c, 0xc5, 0xcb, 0x54, 0xd0, 0xcd, 0x68, 0x91, 0xce, - 0x66, 0xf4, 0x50, 0xd4, 0xdb, 0xa8, 0x9c, 0x5d, 0xa4, 0x57, 0x2c, 0x09, 0x78, 0x6b, 0x90, 0x1e, - 0xde, 0x1c, 0x14, 0xe9, 0xb4, 0x09, 0x5f, 0x96, 0x33, 0x46, 0x76, 0x9a, 0x12, 0x77, 0x76, 0x9a, - 0xc1, 0xb4, 0x87, 0xbf, 0x58, 0x8b, 0x7e, 0x43, 0x49, 0xdd, 0x27, 0x3c, 0xbb, 0x71, 0x75, 0x71, - 0xc6, 0xe3, 0x32, 0x19, 0x7c, 0x80, 0xd9, 0x41, 0x51, 0xe3, 0xfa, 0xc9, 0x75, 0x54, 0x60, 0xb3, - 0xd6, 0x79, 0xb7, 0x1d, 0x71, 0x68, 0xb3, 0x7a, 0x48, 0xb8, 0x59, 0x21, 0x0a, 0x27, 0x10, 0x29, - 0x57, 0x07, 0x80, 0xeb, 0xa4, 0xbe, 0x7f, 0x0a, 0xb8, 0xd1, 0xc9, 0xc1, 0xf9, 0xb1, 0x16, 0xfa, - 0xd1, 0xb2, 0x45, 0xd9, 0xc0, 0x23, 0x66, 0xd8, 0x17, 0x27, 0x3d, 0x9b, 0x51, 0x11, 0xf6, 0xdc, - 0x1a, 0x19, 0xc3, 0xbe, 0x38, 0xe1, 0xd9, 0x99, 0xd6, 0x42, 0x9e, 0x91, 0xa9, 0x6d, 0xd8, 0x17, - 0x87, 0xd9, 0x97, 0x66, 0x9a, 0x75, 0xe1, 0x61, 0xc0, 0x0e, 0x5c, 0x1b, 0x36, 0x7b, 0xb1, 0xda, - 0xe1, 0x5f, 0xad, 0x45, 0xdf, 0xb5, 0x1e, 0x0f, 0x79, 0x92, 0x9e, 0xaf, 0x14, 0xf4, 0x22, 0xce, - 0x96, 0xac, 0x1a, 0x3c, 0xa1, 0xac, 0xb5, 0x59, 0x53, 0x82, 0xa7, 0xd7, 0xd2, 0x81, 0x63, 0x67, - 0x54, 0x14, 0xd9, 0x6a, 0xca, 0x16, 0x45, 0x46, 0x8e, 0x1d, 0x0f, 0x09, 0x8f, 0x1d, 0x88, 0xc2, - 0xac, 0x7c, 0xca, 0xeb, 0x9c, 0x1f, 0xcd, 0xca, 0xa5, 0x28, 0x9c, 0x95, 0x37, 0x08, 0xcc, 0x95, - 0xa6, 0x7c, 0x87, 0x67, 0x19, 0x9b, 0x89, 0xf6, 0x2d, 0x11, 0xa3, 0x69, 0x89, 0x70, 0xae, 0x04, - 0x48, 0x7b, 0x2a, 0xd7, 0xec, 0x21, 0xe3, 0x92, 0x3d, 0x5b, 0x1d, 0xa4, 0xf9, 0xe5, 0x00, 0x4f, - 0x0b, 0x2c, 0x40, 0x9c, 0xca, 0xa1, 0x20, 0xdc, 0xab, 0x9e, 0xe6, 0x09, 0xc7, 0xf7, 0xaa, 0xb5, - 0x24, 0xbc, 0x57, 0xd5, 0x04, 0x34, 0x79, 0xc2, 0x28, 0x93, 0xb5, 0x24, 0x6c, 0x52, 0x13, 0xd8, - 0x54, 0xa8, 0x9f, 0x14, 0x91, 0x53, 0x21, 0x78, 0x36, 0xb4, 0xd1, 0xc9, 0xc1, 0x3d, 0x97, 0x76, - 0x80, 0x46, 0x04, 0x30, 0x7e, 0x27, 0xc8, 0xc0, 0xd0, 0x6f, 0x76, 0xc3, 0x7b, 0x4c, 0xcc, 0x2e, - 0xf0, 0xd0, 0xf7, 0x90, 0x70, 0xe8, 0x43, 0x14, 0xb6, 0xd5, 0x94, 0x9b, 0xdd, 0xfc, 0x3a, 0x1e, - 0x78, 0xad, 0x9d, 0xfc, 0x46, 0x27, 0x07, 0xdb, 0x6a, 0xbc, 0xa0, 0xdb, 0x4a, 0xc9, 0xc2, 0x6d, - 0x65, 0x18, 0x58, 0x7a, 0x25, 0x90, 0x87, 0x64, 0xeb, 0xb4, 0xa2, 0x77, 0x4c, 0xb6, 0xd1, 0xc9, - 0x69, 0x27, 0xff, 0x64, 0xf6, 0x87, 0x4a, 0x7a, 0xc4, 0xeb, 0xc1, 0xf7, 0x22, 0xce, 0xd2, 0x24, - 0x16, 0x6c, 0xca, 0x2f, 0x59, 0x8e, 0x6f, 0xc5, 0x74, 0x69, 0x15, 0x3f, 0xf4, 0x14, 0xc2, 0x5b, - 0xb1, 0xb0, 0x22, 0x8c, 0x13, 0x45, 0x9f, 0x56, 0x6c, 0x27, 0xae, 0x88, 0x29, 0xd2, 0x43, 0xc2, - 0x71, 0x02, 0x51, 0x98, 0x08, 0x2b, 0xf9, 0xf3, 0xd7, 0x05, 0x2b, 0x53, 0x96, 0xcf, 0x18, 0x9e, - 0x08, 0x43, 0x2a, 0x9c, 0x08, 0x23, 0x34, 0xdc, 0x04, 0xee, 0xc6, 0x82, 0x3d, 0x5b, 0x4d, 0xd3, - 0x05, 0xab, 0x44, 0xbc, 0x28, 0xf0, 0x4d, 0x20, 0x80, 0xc2, 0x9b, 0xc0, 0x36, 0xdc, 0x3a, 0x73, - 0x32, 0x33, 0x6d, 0xfb, 0xd6, 0x1a, 0x24, 0x02, 0xb7, 0xd6, 0x08, 0x14, 0x36, 0xac, 0x05, 0xd0, - 0xa7, 0x0f, 0x2d, 0x2b, 0xc1, 0xa7, 0x0f, 0x34, 0xdd, 0x3a, 0xc9, 0x33, 0xcc, 0xa4, 0x1e, 0x9a, - 0x1d, 0x45, 0x9f, 0xb8, 0x43, 0x74, 0xb3, 0x17, 0x8b, 0x1f, 0x1d, 0x9e, 0xb0, 0x2c, 0x96, 0xeb, - 0x61, 0xe0, 0x7c, 0xae, 0x61, 0xfa, 0x1c, 0x1d, 0x3a, 0xac, 0x76, 0xf8, 0x67, 0x6b, 0xd1, 0x7b, - 0x98, 0xc7, 0x2f, 0x0a, 0xe9, 0xf7, 0x71, 0xb7, 0x2d, 0x45, 0x12, 0xd7, 0xf2, 0xc2, 0x1a, 0xf6, - 0x66, 0x49, 0x23, 0xb2, 0xb7, 0xf6, 0x74, 0x01, 0xfc, 0x6c, 0xd0, 0x94, 0x1f, 0x72, 0xc4, 0xcd, - 0x92, 0x10, 0x6f, 0x37, 0x5a, 0x7e, 0xb9, 0x2a, 0xb0, 0xd1, 0x32, 0x36, 0xb4, 0x98, 0xd8, 0x68, - 0x21, 0x98, 0x1d, 0x9d, 0x6e, 0xf5, 0x5e, 0xa6, 0xe2, 0x42, 0x26, 0x72, 0x60, 0x74, 0x7a, 0x65, - 0x35, 0x10, 0x31, 0x3a, 0x49, 0x18, 0xa6, 0x3a, 0x0d, 0x58, 0x8f, 0x4d, 0x6c, 0x2e, 0x37, 0x86, - 0xdc, 0x91, 0x79, 0xbf, 0x1b, 0x84, 0xf1, 0xda, 0x88, 0xf5, 0x9e, 0xea, 0x61, 0xc8, 0x02, 0xd8, - 0x57, 0x6d, 0xf6, 0x62, 0xb5, 0xc3, 0x3f, 0x89, 0xbe, 0xd3, 0xaa, 0xd8, 0x1e, 0x8b, 0xc5, 0xb2, - 0x64, 0xc9, 0x60, 0xbb, 0xa3, 0xdc, 0x0d, 0x68, 0x5c, 0x3f, 0xee, 0xaf, 0xd0, 0x4a, 0xfe, 0x1b, - 0x4e, 0x85, 0x95, 0x29, 0xc3, 0x93, 0x90, 0x49, 0x9f, 0x0d, 0x26, 0xff, 0xb4, 0x4e, 0x6b, 0xff, - 0xee, 0x46, 0xd7, 0xe8, 0x2a, 0x4e, 0x33, 0xf9, 0x14, 0xf8, 0x83, 0x90, 0x51, 0x0f, 0x0d, 0xee, - 0xdf, 0x49, 0x95, 0xd6, 0xcc, 0x2c, 0xc7, 0xb8, 0xb3, 0xef, 0x7b, 0x44, 0xcf, 0x04, 0xc8, 0xb6, - 0x6f, 0xab, 0x27, 0xad, 0xdd, 0x8a, 0x66, 0xc9, 0xab, 0xff, 0xec, 0x06, 0x39, 0xe6, 0x55, 0xab, - 0x22, 0x91, 0xbe, 0xd5, 0x93, 0xd6, 0x5e, 0xff, 0x38, 0x7a, 0xb7, 0xed, 0x55, 0x2f, 0x44, 0xdb, - 0x9d, 0xa6, 0xc0, 0x5a, 0xf4, 0xb8, 0xbf, 0x82, 0x76, 0xff, 0xaf, 0xe6, 0xc0, 0x5b, 0xf9, 0x9f, - 0xf1, 0xc5, 0x82, 0xe5, 0x09, 0x4b, 0x1a, 0x8d, 0xaa, 0xde, 0x98, 0x7d, 0x4a, 0xdb, 0x35, 0x0a, - 0x43, 0x57, 0xc3, 0x94, 0xe8, 0x37, 0xbf, 0x81, 0xa6, 0x2e, 0xda, 0x7f, 0xae, 0x45, 0x0f, 0xd0, - 0xa2, 0x35, 0x81, 0xeb, 0x15, 0xf1, 0x77, 0xfa, 0x38, 0xc2, 0x34, 0x4d, 0x51, 0x47, 0x3f, 0x83, - 0x05, 0x5d, 0xe4, 0x7f, 0x5b, 0x8b, 0x6e, 0x5b, 0xc5, 0x3a, 0xbc, 0x77, 0x78, 0x7e, 0x9e, 0xa5, - 0x33, 0x21, 0x1f, 0xf5, 0x6a, 0x15, 0xba, 0x39, 0x29, 0x8d, 0xee, 0xe6, 0x0c, 0x68, 0xea, 0xb2, - 0xfd, 0xe3, 0x5a, 0x74, 0xcb, 0x6d, 0x4e, 0xf9, 0x9c, 0x58, 0x1d, 0xbb, 0x36, 0x8a, 0xd5, 0xe0, - 0x63, 0xba, 0x0d, 0x30, 0xde, 0x94, 0xeb, 0x93, 0x6b, 0xeb, 0xd9, 0xbd, 0xfa, 0x67, 0x69, 0x25, - 0x78, 0xb9, 0x9a, 0x5c, 0xf0, 0x57, 0xcd, 0xdb, 0x58, 0xfe, 0x6a, 0xa1, 0x81, 0xa1, 0x43, 0x10, - 0x7b, 0x75, 0x9c, 0x6c, 0xb9, 0xb2, 0x6f, 0x6d, 0x55, 0x84, 0x2b, 0x87, 0xe8, 0x70, 0xe5, 0x93, - 0x76, 0xad, 0x6c, 0x6a, 0x65, 0x5f, 0x31, 0xdb, 0xc0, 0x8b, 0xda, 0x7e, 0xcd, 0xec, 0x7e, 0x37, - 0x68, 0x33, 0x66, 0x2d, 0xde, 0x4d, 0xcf, 0xcf, 0x4d, 0x9d, 0xf0, 0x92, 0xba, 0x08, 0x91, 0x31, - 0x13, 0xa8, 0xdd, 0xf4, 0xed, 0xa5, 0x19, 0x93, 0x8f, 0xaa, 0xbe, 0x38, 0x3f, 0xcf, 0x78, 0x9c, - 0x80, 0x4d, 0x5f, 0x2d, 0x1e, 0xba, 0x72, 0x62, 0xd3, 0x87, 0x71, 0xf6, 0x12, 0x4c, 0x2d, 0xad, - 0xc7, 0x5c, 0x3e, 0x4b, 0x33, 0x78, 0x99, 0x5b, 0x6a, 0x1a, 0x21, 0x71, 0x09, 0xa6, 0x05, 0xd9, - 0xc4, 0xac, 0x16, 0xd5, 0x63, 0xa5, 0x29, 0xff, 0xbd, 0xb6, 0xa2, 0x23, 0x26, 0x12, 0x33, 0x04, - 0xb3, 0x87, 0x2a, 0xb5, 0xf0, 0xb4, 0x90, 0xc6, 0x6f, 0xb5, 0xb5, 0x94, 0x84, 0x38, 0x54, 0xf1, - 0x09, 0xbb, 0x87, 0xaf, 0xff, 0xbe, 0xcb, 0x5f, 0xe5, 0xd2, 0xe8, 0xed, 0xb6, 0x4a, 0x23, 0x23, - 0xf6, 0xf0, 0x90, 0xd1, 0x86, 0x3f, 0x8f, 0x7e, 0x5e, 0x1a, 0x2e, 0x79, 0x31, 0xb8, 0x81, 0x28, - 0x94, 0xce, 0xd5, 0xe7, 0x9b, 0xa4, 0xdc, 0xde, 0x99, 0x31, 0xb1, 0x71, 0x5a, 0xc5, 0x73, 0xf8, - 0xbe, 0x82, 0xed, 0x71, 0x29, 0x25, 0xee, 0xcc, 0xb4, 0x29, 0x3f, 0x2a, 0x8e, 0x78, 0xa2, 0xad, - 0x23, 0x35, 0x34, 0xc2, 0x50, 0x54, 0xb8, 0x90, 0x4d, 0xa6, 0x8f, 0xe2, 0xab, 0x74, 0x6e, 0x12, - 0x1e, 0x35, 0x7d, 0x55, 0x20, 0x99, 0xb6, 0xcc, 0xd0, 0x81, 0x88, 0x64, 0x9a, 0x84, 0x9d, 0xc9, - 0xd8, 0x32, 0xfb, 0xcd, 0x31, 0xf4, 0x38, 0x3f, 0xe7, 0x75, 0xea, 0x7d, 0x90, 0xe6, 0x97, 0x70, - 0x32, 0x76, 0x4c, 0xe2, 0x3c, 0x31, 0x19, 0xf7, 0xd1, 0xb3, 0xbb, 0xa6, 0xe6, 0x8c, 0xd6, 0x5e, - 0xd4, 0x50, 0x1a, 0x60, 0xd7, 0x64, 0x8e, 0x72, 0x21, 0x47, 0xec, 0x9a, 0x42, 0xbc, 0xed, 0x62, - 0xe3, 0x3c, 0xe3, 0x39, 0xec, 0x62, 0x6b, 0xa1, 0x16, 0x12, 0x5d, 0xdc, 0x82, 0xec, 0x7c, 0xdc, - 0x88, 0xd4, 0xa9, 0xdf, 0x28, 0xcb, 0xc0, 0x7c, 0x6c, 0x54, 0x0d, 0x40, 0xcc, 0xc7, 0x28, 0xa8, - 0xfd, 0x9c, 0x44, 0xdf, 0xaa, 0x9b, 0xf4, 0xb8, 0x64, 0x57, 0x29, 0x83, 0x77, 0x8a, 0x1c, 0x09, - 0x31, 0xfe, 0x7d, 0xc2, 0x8e, 0xac, 0xd3, 0xbc, 0x2a, 0xb2, 0xb8, 0xba, 0xd0, 0xb7, 0x4c, 0xfc, - 0x3a, 0x37, 0x42, 0x78, 0xcf, 0xe4, 0x5e, 0x07, 0x65, 0x27, 0xf5, 0x46, 0x66, 0xa6, 0x98, 0x75, - 0x5c, 0xb5, 0x35, 0xcd, 0x6c, 0x74, 0x72, 0xf6, 0x51, 0xce, 0x7e, 0x9c, 0x65, 0xac, 0x5c, 0x35, - 0xb2, 0xc3, 0x38, 0x4f, 0xcf, 0x59, 0x25, 0xc0, 0xa3, 0x1c, 0x4d, 0x0d, 0x21, 0x46, 0x3c, 0xca, - 0x09, 0xe0, 0x76, 0x37, 0x09, 0x3c, 0x8f, 0xf3, 0x84, 0xbd, 0x06, 0xbb, 0x49, 0x68, 0x47, 0x32, - 0xc4, 0x6e, 0x92, 0x62, 0xed, 0x23, 0x8d, 0x67, 0x19, 0x9f, 0x5d, 0xea, 0x25, 0xc0, 0xef, 0x60, - 0x29, 0x81, 0x6b, 0xc0, 0xed, 0x10, 0x62, 0x17, 0x01, 0x29, 0x38, 0x61, 0x45, 0x16, 0xcf, 0xe0, - 0xc5, 0x32, 0xa5, 0xa3, 0x65, 0xc4, 0x22, 0x00, 0x19, 0x50, 0x5c, 0x7d, 0x61, 0x0d, 0x2b, 0x2e, - 0xb8, 0xaf, 0x76, 0x3b, 0x84, 0xd8, 0x65, 0x50, 0x0a, 0x26, 0x45, 0x96, 0x0a, 0x30, 0x0c, 0x94, - 0x86, 0x94, 0x10, 0xc3, 0xc0, 0x27, 0x80, 0xc9, 0x43, 0x56, 0xce, 0x19, 0x6a, 0x52, 0x4a, 0x82, - 0x26, 0x1b, 0xc2, 0xde, 0xa2, 0x57, 0x75, 0xe7, 0xc5, 0x0a, 0xdc, 0xa2, 0xd7, 0xd5, 0xe2, 0xc5, - 0x8a, 0xb8, 0x45, 0xef, 0x01, 0xa0, 0x88, 0xc7, 0x71, 0x25, 0xf0, 0x22, 0x4a, 0x49, 0xb0, 0x88, - 0x0d, 0x61, 0xd7, 0x68, 0x55, 0xc4, 0xa5, 0x00, 0x6b, 0xb4, 0x2e, 0x80, 0x73, 0xb5, 0xe2, 0x26, - 0x29, 0xb7, 0x33, 0x89, 0xea, 0x15, 0x26, 0xf6, 0x52, 0x96, 0x25, 0x15, 0x98, 0x49, 0x74, 0xbb, - 0x37, 0x52, 0x62, 0x26, 0x69, 0x53, 0x20, 0x94, 0xf4, 0x73, 0x19, 0xac, 0x76, 0xe0, 0xb1, 0xcc, - 0xed, 0x10, 0x62, 0xe7, 0xa7, 0xa6, 0xd0, 0x3b, 0x71, 0x59, 0xa6, 0xf5, 0xe2, 0xbf, 0x8e, 0x17, - 0xa8, 0x91, 0x13, 0xf3, 0x13, 0xc6, 0x81, 0xe1, 0xd5, 0x4c, 0xdc, 0x58, 0xc1, 0xe0, 0xd4, 0x7d, - 0x27, 0xc8, 0xd8, 0x8c, 0x53, 0x4a, 0x9c, 0xbb, 0x01, 0x58, 0x6b, 0x22, 0x57, 0x03, 0xd6, 0xbb, - 0x30, 0xe7, 0x85, 0x3e, 0xe3, 0xe2, 0x90, 0x5f, 0xb1, 0x29, 0x7f, 0xfe, 0x3a, 0xad, 0xea, 0x4d, - 0xa0, 0x5e, 0xb9, 0x9f, 0x12, 0x96, 0x30, 0x98, 0x78, 0xa1, 0xaf, 0x53, 0xc9, 0x26, 0x10, 0xa0, - 0x2c, 0x47, 0xec, 0x15, 0x9a, 0x40, 0x40, 0x8b, 0x86, 0x23, 0x12, 0x88, 0x10, 0x6f, 0xcf, 0xf1, - 0x8c, 0x73, 0xfd, 0x15, 0x87, 0x29, 0x6f, 0x72, 0x39, 0xca, 0x1a, 0x04, 0x89, 0xa3, 0x94, 0xa0, - 0x82, 0xdd, 0x5f, 0x1a, 0xff, 0x76, 0x88, 0xdd, 0x27, 0xec, 0xb4, 0x87, 0xd9, 0x83, 0x1e, 0x24, - 0xe2, 0xca, 0x5e, 0x70, 0xa1, 0x5c, 0xb5, 0xef, 0xb7, 0x3c, 0xe8, 0x41, 0x3a, 0x67, 0x82, 0x6e, - 0xb5, 0x9e, 0xc5, 0xb3, 0xcb, 0x79, 0xc9, 0x97, 0x79, 0xb2, 0xc3, 0x33, 0x5e, 0x82, 0x33, 0x41, - 0xaf, 0xd4, 0x00, 0x25, 0xce, 0x04, 0x3b, 0x54, 0x6c, 0x06, 0xe7, 0x96, 0x62, 0x94, 0xa5, 0x73, - 0xb8, 0xa3, 0xf6, 0x0c, 0x49, 0x80, 0xc8, 0xe0, 0x50, 0x10, 0x09, 0x22, 0xb5, 0xe3, 0x16, 0xe9, - 0x2c, 0xce, 0x94, 0xbf, 0x6d, 0xda, 0x8c, 0x07, 0x76, 0x06, 0x11, 0xa2, 0x80, 0xd4, 0x73, 0xba, - 0x2c, 0xf3, 0x71, 0x2e, 0x38, 0x59, 0xcf, 0x06, 0xe8, 0xac, 0xa7, 0x03, 0x82, 0x69, 0x75, 0xca, - 0x5e, 0xd7, 0xa5, 0xa9, 0xff, 0xc1, 0xa6, 0xd5, 0xfa, 0xef, 0x43, 0x2d, 0x0f, 0x4d, 0xab, 0x80, - 0x03, 0x95, 0xd1, 0x4e, 0x54, 0xc0, 0x04, 0xb4, 0xfd, 0x30, 0xb9, 0xdf, 0x0d, 0xe2, 0x7e, 0x26, - 0x62, 0x95, 0xb1, 0x90, 0x1f, 0x09, 0xf4, 0xf1, 0xd3, 0x80, 0xf6, 0xb8, 0xc5, 0xab, 0xcf, 0x05, - 0x9b, 0x5d, 0xb6, 0xee, 0xeb, 0xf9, 0x05, 0x55, 0x08, 0x71, 0xdc, 0x42, 0xa0, 0x78, 0x17, 0x8d, - 0x67, 0x3c, 0x0f, 0x75, 0x51, 0x2d, 0xef, 0xd3, 0x45, 0x9a, 0xb3, 0x9b, 0x5f, 0x23, 0xd5, 0x91, - 0xa9, 0xba, 0x69, 0x93, 0xb0, 0xe0, 0x42, 0xc4, 0xe6, 0x97, 0x84, 0x6d, 0x4e, 0x0e, 0x7d, 0x1e, - 0xb6, 0x5f, 0x66, 0x68, 0x59, 0x39, 0xa4, 0x5f, 0x66, 0xa0, 0x58, 0xba, 0x92, 0x2a, 0x46, 0x3a, - 0xac, 0xf8, 0x71, 0xf2, 0xa8, 0x1f, 0x6c, 0xb7, 0x3c, 0x9e, 0xcf, 0x9d, 0x8c, 0xc5, 0xa5, 0xf2, - 0xba, 0x15, 0x30, 0x64, 0x31, 0x62, 0xcb, 0x13, 0xc0, 0xc1, 0x14, 0xe6, 0x79, 0xde, 0xe1, 0xb9, - 0x60, 0xb9, 0xc0, 0xa6, 0x30, 0xdf, 0x98, 0x06, 0x43, 0x53, 0x18, 0xa5, 0x00, 0xe2, 0x56, 0x9e, - 0x07, 0x31, 0x71, 0x14, 0x2f, 0xd0, 0x8c, 0x4d, 0x9d, 0xf5, 0x28, 0x79, 0x28, 0x6e, 0x01, 0xe7, - 0x3c, 0x64, 0x76, 0xbd, 0x4c, 0xe3, 0x72, 0x6e, 0x4e, 0x37, 0x92, 0xc1, 0x63, 0xda, 0x8e, 0x4f, - 0x12, 0x0f, 0x99, 0xc3, 0x1a, 0x60, 0xda, 0x19, 0x2f, 0xe2, 0xb9, 0xa9, 0x29, 0x52, 0x03, 0x29, - 0x6f, 0x55, 0xf5, 0x7e, 0x37, 0x08, 0xfc, 0xbc, 0x48, 0x13, 0xc6, 0x03, 0x7e, 0xa4, 0xbc, 0x8f, - 0x1f, 0x08, 0x82, 0xec, 0xad, 0xae, 0xb7, 0xda, 0xd1, 0x8d, 0xf2, 0x44, 0xef, 0x63, 0x87, 0x44, - 0xf3, 0x00, 0x2e, 0x94, 0xbd, 0x11, 0x3c, 0x18, 0xa3, 0xcd, 0x01, 0x6d, 0x68, 0x8c, 0x9a, 0xf3, - 0xd7, 0x3e, 0x63, 0x14, 0x83, 0xb5, 0xcf, 0x1f, 0xeb, 0x31, 0xba, 0x1b, 0x8b, 0xb8, 0xce, 0xdb, - 0x5f, 0xa4, 0xec, 0x95, 0xde, 0x08, 0x23, 0xf5, 0x6d, 0xa8, 0xa1, 0x7c, 0x17, 0x1b, 0xec, 0x8a, - 0xb7, 0x7b, 0xf3, 0x01, 0xdf, 0x7a, 0x87, 0xd0, 0xe9, 0x1b, 0x6c, 0x15, 0xb6, 0x7b, 0xf3, 0x01, - 0xdf, 0xfa, 0x93, 0x12, 0x9d, 0xbe, 0xc1, 0x77, 0x25, 0xb6, 0x7b, 0xf3, 0xda, 0xf7, 0x9f, 0x37, - 0x03, 0xd7, 0x75, 0x5e, 0xe7, 0x61, 0x33, 0x91, 0x5e, 0x31, 0x2c, 0x9d, 0xf4, 0xed, 0x19, 0x34, - 0x94, 0x4e, 0xd2, 0x2a, 0xce, 0x47, 0xdd, 0xb0, 0x52, 0x1c, 0xf3, 0x2a, 0x95, 0x97, 0x44, 0x9e, - 0xf6, 0x30, 0xda, 0xc0, 0xa1, 0x4d, 0x53, 0x48, 0xc9, 0x3e, 0xee, 0xf6, 0x50, 0x7b, 0x3d, 0xff, - 0x51, 0xc0, 0x5e, 0xfb, 0x96, 0xfe, 0x56, 0x4f, 0xda, 0x3e, 0x78, 0xf6, 0x98, 0xe6, 0x91, 0xe1, - 0x84, 0xa1, 0xab, 0x84, 0x31, 0x65, 0x1e, 0x25, 0xbb, 0xcf, 0x4e, 0x1f, 0xf7, 0x57, 0xe8, 0x70, - 0x3f, 0x4a, 0x92, 0x7e, 0xee, 0xdd, 0x67, 0xee, 0x8f, 0xfb, 0x2b, 0x68, 0xf7, 0x7f, 0xd9, 0x6c, - 0x6b, 0xa0, 0x7f, 0x3d, 0x06, 0x9f, 0xf4, 0xb1, 0x08, 0xc6, 0xe1, 0xd3, 0x6b, 0xe9, 0xe8, 0x82, - 0xfc, 0x6d, 0xb3, 0x7f, 0x6f, 0x50, 0xf9, 0x8e, 0x94, 0x7c, 0xb7, 0x5a, 0x0f, 0xc9, 0x50, 0x54, - 0x59, 0x18, 0x0e, 0xcc, 0x8f, 0xae, 0xa9, 0xe5, 0x7c, 0x61, 0xd0, 0x83, 0xf5, 0xbb, 0xbc, 0x4e, - 0x79, 0x42, 0x96, 0x1d, 0x1a, 0x16, 0xe8, 0xe3, 0xeb, 0xaa, 0x51, 0x43, 0xd5, 0x81, 0xe5, 0x37, - 0x76, 0x9e, 0xf6, 0x34, 0xec, 0x7d, 0x75, 0xe7, 0xc3, 0xeb, 0x29, 0xe9, 0xb2, 0xfc, 0xc7, 0x5a, - 0x74, 0xcf, 0x63, 0xed, 0xe3, 0x0c, 0x70, 0xe8, 0xf2, 0x83, 0x80, 0x7d, 0x4a, 0xc9, 0x14, 0xee, - 0xb7, 0xbe, 0x99, 0xb2, 0xfd, 0x1c, 0x9f, 0xa7, 0xb2, 0x97, 0x66, 0x82, 0x95, 0xed, 0xcf, 0xf1, - 0xf9, 0x76, 0x15, 0x35, 0xa4, 0x3f, 0xc7, 0x17, 0xc0, 0x9d, 0xcf, 0xf1, 0x21, 0x9e, 0xd1, 0xcf, - 0xf1, 0xa1, 0xd6, 0x82, 0x9f, 0xe3, 0x0b, 0x6b, 0x50, 0xab, 0x4b, 0x53, 0x04, 0x75, 0x6c, 0xde, - 0xcb, 0xa2, 0x7f, 0x8a, 0xfe, 0xe4, 0x3a, 0x2a, 0xc4, 0xfa, 0xaa, 0x38, 0x79, 0xcd, 0xb3, 0x47, - 0x9b, 0x7a, 0x57, 0x3d, 0xb7, 0x7b, 0xf3, 0xda, 0xf7, 0x8f, 0xf4, 0xe6, 0xca, 0xac, 0x26, 0xbc, - 0x94, 0x9f, 0x62, 0xdc, 0x0c, 0xad, 0x0e, 0xb5, 0x05, 0xb7, 0xe7, 0x1f, 0xf5, 0x83, 0x89, 0xea, - 0xd6, 0x84, 0xee, 0xf4, 0x61, 0x97, 0x21, 0xd0, 0xe5, 0xdb, 0xbd, 0x79, 0x62, 0x19, 0x51, 0xbe, - 0x55, 0x6f, 0xf7, 0x30, 0xe6, 0xf7, 0xf5, 0xe3, 0xfe, 0x0a, 0xda, 0xfd, 0x95, 0xce, 0x5a, 0x5d, - 0xf7, 0xb2, 0x9f, 0xb7, 0xba, 0x4c, 0x4d, 0xbc, 0x6e, 0x1e, 0xf6, 0xc5, 0x43, 0xf9, 0x8b, 0xbb, - 0x84, 0x76, 0xe5, 0x2f, 0xe8, 0x32, 0xfa, 0xe1, 0xf5, 0x94, 0x74, 0x59, 0xfe, 0x61, 0x2d, 0xba, - 0x49, 0x96, 0x45, 0xc7, 0xc1, 0xc7, 0x7d, 0x2d, 0x83, 0x78, 0xf8, 0xe4, 0xda, 0x7a, 0xba, 0x50, - 0xff, 0xbc, 0x16, 0xdd, 0x0a, 0x14, 0x4a, 0x05, 0xc8, 0x35, 0xac, 0xfb, 0x81, 0xf2, 0xe9, 0xf5, - 0x15, 0xa9, 0xe5, 0xde, 0xc5, 0x27, 0xed, 0x4f, 0xab, 0x05, 0x6c, 0x4f, 0xe8, 0x4f, 0xab, 0x75, - 0x6b, 0xc1, 0x33, 0xa6, 0xf8, 0xac, 0xd9, 0xf3, 0xa1, 0x67, 0x4c, 0xf2, 0x82, 0x66, 0xf0, 0xa3, - 0x2d, 0x18, 0x87, 0x39, 0x79, 0xfe, 0xba, 0x88, 0xf3, 0x84, 0x76, 0xa2, 0xe4, 0xdd, 0x4e, 0x0c, - 0x07, 0xcf, 0xe6, 0x6a, 0xe9, 0x09, 0x6f, 0xf6, 0x71, 0x0f, 0x28, 0x7d, 0x83, 0x04, 0xcf, 0xe6, - 0x5a, 0x28, 0xe1, 0x4d, 0x67, 0x8d, 0x21, 0x6f, 0x20, 0x59, 0x7c, 0xd8, 0x07, 0x05, 0x3b, 0x04, - 0xe3, 0xcd, 0x1c, 0xf9, 0x3f, 0x0a, 0x59, 0x69, 0x1d, 0xfb, 0x6f, 0xf5, 0xa4, 0x09, 0xb7, 0x13, - 0x26, 0x3e, 0x63, 0x71, 0xc2, 0xca, 0xa0, 0x5b, 0x43, 0xf5, 0x72, 0xeb, 0xd2, 0x98, 0xdb, 0x1d, - 0x9e, 0x2d, 0x17, 0xb9, 0xee, 0x4c, 0xd2, 0xad, 0x4b, 0x75, 0xbb, 0x05, 0x34, 0x3c, 0x95, 0xb4, - 0x6e, 0x65, 0x7a, 0xf9, 0x30, 0x6c, 0xc6, 0xcb, 0x2a, 0x37, 0x7b, 0xb1, 0x74, 0x3d, 0x75, 0x18, - 0x75, 0xd4, 0x13, 0x44, 0xd2, 0x56, 0x4f, 0x1a, 0x1e, 0x0f, 0x3a, 0x6e, 0x4d, 0x3c, 0x6d, 0x77, - 0xd8, 0x6a, 0x85, 0xd4, 0xe3, 0xfe, 0x0a, 0xf0, 0x30, 0x56, 0x47, 0xd5, 0x41, 0x5a, 0x89, 0xbd, - 0x34, 0xcb, 0x06, 0x9b, 0x81, 0x30, 0x69, 0xa0, 0xe0, 0x61, 0x2c, 0x02, 0x13, 0x91, 0xdc, 0x1c, - 0x5e, 0xe6, 0x83, 0x2e, 0x3b, 0x92, 0xea, 0x15, 0xc9, 0x2e, 0x0d, 0x0e, 0xd4, 0x9c, 0xa6, 0x36, - 0xb5, 0x1d, 0x86, 0x1b, 0xae, 0x55, 0xe1, 0xed, 0xde, 0x3c, 0x78, 0xda, 0x2f, 0x29, 0xb9, 0xb2, - 0xdc, 0xa5, 0x4c, 0x78, 0x2b, 0xc9, 0xbd, 0x0e, 0x0a, 0x1c, 0x4a, 0xaa, 0x61, 0xf4, 0x32, 0x4d, - 0xe6, 0x4c, 0xa0, 0x0f, 0xaa, 0x5c, 0x20, 0xf8, 0xa0, 0x0a, 0x80, 0xa0, 0xeb, 0xd4, 0xdf, 0xcd, - 0x69, 0xec, 0x38, 0xc1, 0xba, 0x4e, 0x2b, 0x3b, 0x54, 0xa8, 0xeb, 0x50, 0x1a, 0xcc, 0x06, 0xc6, - 0xad, 0xfe, 0xcc, 0xc5, 0xc3, 0x90, 0x19, 0xf0, 0xad, 0x8b, 0xcd, 0x5e, 0x2c, 0x58, 0x51, 0xac, - 0xc3, 0x74, 0x91, 0x0a, 0x6c, 0x45, 0x71, 0x6c, 0xd4, 0x48, 0x68, 0x45, 0x69, 0xa3, 0x54, 0xf5, - 0xea, 0x1c, 0x61, 0x9c, 0x84, 0xab, 0xa7, 0x98, 0x7e, 0xd5, 0x33, 0x6c, 0xeb, 0xb9, 0x6a, 0x6e, - 0x42, 0x46, 0x5c, 0xe8, 0xcd, 0x32, 0x12, 0xdb, 0xf2, 0xf5, 0x67, 0x08, 0x86, 0x66, 0x1d, 0x4a, - 0x01, 0x3e, 0x2f, 0xa8, 0xb9, 0xe6, 0xd1, 0x6f, 0x51, 0xb0, 0xb8, 0x8c, 0xf3, 0x19, 0xba, 0x39, - 0x95, 0x06, 0x5b, 0x64, 0x68, 0x73, 0x4a, 0x6a, 0x80, 0xa7, 0xf6, 0xfe, 0xfb, 0xc5, 0xc8, 0x50, - 0x30, 0x2f, 0xf2, 0xfa, 0xaf, 0x17, 0x3f, 0xe8, 0x41, 0xc2, 0xa7, 0xf6, 0x0d, 0x60, 0xce, 0xdd, - 0x95, 0xd3, 0x0f, 0x02, 0xa6, 0x7c, 0x34, 0xb4, 0x11, 0xa6, 0x55, 0x40, 0x50, 0x3b, 0x67, 0x8b, - 0x9f, 0xb3, 0x15, 0x16, 0xd4, 0xee, 0x21, 0xe1, 0xe7, 0x6c, 0x15, 0x0a, 0xea, 0x36, 0x0a, 0xf2, - 0x4c, 0x77, 0x1f, 0xb4, 0x1e, 0xd0, 0x77, 0xb7, 0x3e, 0x1b, 0x9d, 0x1c, 0x18, 0x39, 0xbb, 0xe9, - 0x95, 0xf7, 0x98, 0x02, 0x29, 0xe8, 0x6e, 0x7a, 0x85, 0x3f, 0xa5, 0xd8, 0xec, 0xc5, 0xc2, 0x1b, - 0x01, 0xb1, 0x60, 0xaf, 0x9b, 0x47, 0xf5, 0x48, 0x71, 0xa5, 0xbc, 0xf5, 0xac, 0xfe, 0x7e, 0x37, - 0x68, 0xef, 0xdf, 0x1e, 0x97, 0x7c, 0xc6, 0xaa, 0x4a, 0x7f, 0x01, 0xd6, 0xbf, 0xe0, 0xa4, 0x65, - 0x43, 0xf0, 0xfd, 0xd7, 0xbb, 0x61, 0xc8, 0xf9, 0x6c, 0xa3, 0x12, 0xd9, 0xaf, 0x49, 0xad, 0xa3, - 0x9a, 0xed, 0x0f, 0x49, 0x6d, 0x74, 0x72, 0x76, 0x78, 0x69, 0xa9, 0xfb, 0xf9, 0xa8, 0xfb, 0xa8, - 0x3a, 0xf6, 0xe5, 0xa8, 0x07, 0x3d, 0x48, 0xed, 0xea, 0xb3, 0xe8, 0xcd, 0x03, 0x3e, 0x9f, 0xb0, - 0x3c, 0x19, 0x7c, 0xcf, 0xbf, 0xc1, 0xcb, 0xe7, 0xc3, 0xfa, 0xcf, 0xc6, 0xe8, 0x0d, 0x4a, 0x6c, - 0xef, 0x20, 0xee, 0xb2, 0xb3, 0xe5, 0x7c, 0x22, 0x62, 0x01, 0xee, 0x20, 0xca, 0xbf, 0x0f, 0x6b, - 0x01, 0x71, 0x07, 0xd1, 0x03, 0x80, 0xbd, 0x69, 0xc9, 0x18, 0x6a, 0xaf, 0x16, 0x04, 0xed, 0x69, - 0xc0, 0x66, 0x11, 0xc6, 0x5e, 0x9d, 0xa8, 0xc3, 0x3b, 0x83, 0x56, 0x47, 0x4a, 0x89, 0x2c, 0xa2, - 0x4d, 0xd9, 0xe0, 0x56, 0xd5, 0x97, 0x5f, 0xf3, 0x59, 0x2e, 0x16, 0x71, 0xb9, 0x02, 0xc1, 0xad, - 0x6b, 0xe9, 0x00, 0x44, 0x70, 0xa3, 0xa0, 0x1d, 0xb5, 0x4d, 0x33, 0xcf, 0x2e, 0xf7, 0x79, 0xc9, - 0x97, 0x22, 0xcd, 0x19, 0xfc, 0xa2, 0x8b, 0x69, 0x50, 0x97, 0x21, 0x46, 0x2d, 0xc5, 0xda, 0x2c, - 0x57, 0x12, 0xea, 0x3a, 0xa3, 0xfc, 0x04, 0x7e, 0x25, 0x78, 0x09, 0x1f, 0x67, 0x2a, 0x2b, 0x10, - 0x22, 0xb2, 0x5c, 0x12, 0x06, 0x7d, 0x7f, 0x9c, 0xe6, 0x73, 0xb4, 0xef, 0x8f, 0xdd, 0xaf, 0x2a, - 0xdf, 0xa2, 0x01, 0x3b, 0xa0, 0x54, 0xa3, 0xa9, 0x01, 0xa0, 0x5f, 0x65, 0x46, 0x1b, 0xdd, 0x25, - 0x88, 0x01, 0x85, 0x93, 0xc0, 0xd5, 0x17, 0x05, 0xcb, 0x59, 0xd2, 0x5c, 0xda, 0xc3, 0x5c, 0x79, - 0x44, 0xd0, 0x15, 0x24, 0xed, 0x5c, 0x24, 0xe5, 0x27, 0xcb, 0xfc, 0xb8, 0xe4, 0xe7, 0x69, 0xc6, - 0x4a, 0x30, 0x17, 0x29, 0x75, 0x47, 0x4e, 0xcc, 0x45, 0x18, 0x67, 0x6f, 0x7f, 0x48, 0xa9, 0xf7, - 0x3b, 0x0e, 0xd3, 0x32, 0x9e, 0xc1, 0xdb, 0x1f, 0xca, 0x46, 0x1b, 0x23, 0x4e, 0x06, 0x03, 0xb8, - 0x93, 0xe8, 0x28, 0xd7, 0xf9, 0x4a, 0xc6, 0x87, 0x7e, 0x95, 0x56, 0x7e, 0x6b, 0xb8, 0x02, 0x89, - 0x8e, 0x36, 0x87, 0x91, 0x44, 0xa2, 0x13, 0xd6, 0xb0, 0x4b, 0x89, 0xe4, 0x8e, 0xf4, 0xad, 0x26, - 0xb0, 0x94, 0x28, 0x1b, 0x8d, 0x90, 0x58, 0x4a, 0x5a, 0x10, 0x98, 0x90, 0x9a, 0x61, 0x30, 0x47, - 0x27, 0x24, 0x23, 0x0d, 0x4e, 0x48, 0x2e, 0x65, 0x27, 0x8a, 0x71, 0x9e, 0x8a, 0x34, 0xce, 0x26, - 0x4c, 0x1c, 0xc7, 0x65, 0xbc, 0x60, 0x82, 0x95, 0x70, 0xa2, 0xd0, 0xc8, 0xd0, 0x63, 0x88, 0x89, - 0x82, 0x62, 0xb5, 0xc3, 0xdf, 0x8e, 0xde, 0xae, 0xd7, 0x7d, 0x96, 0xeb, 0x5f, 0xa0, 0x7a, 0x2e, - 0x7f, 0xba, 0x6e, 0xf0, 0x8e, 0xb1, 0x31, 0x11, 0x25, 0x8b, 0x17, 0x8d, 0xed, 0xb7, 0xcc, 0xdf, - 0x25, 0xf8, 0x78, 0xad, 0x8e, 0xe7, 0x23, 0x2e, 0xd2, 0xf3, 0x7a, 0x9b, 0xad, 0x5f, 0x60, 0x02, - 0xf1, 0xec, 0x8a, 0x87, 0x81, 0x4f, 0xb1, 0x60, 0x9c, 0x9d, 0xa7, 0x5d, 0xe9, 0x09, 0x2b, 0x32, - 0x38, 0x4f, 0x7b, 0xda, 0x12, 0x20, 0xe6, 0x69, 0x14, 0xb4, 0x83, 0xd3, 0x15, 0x4f, 0x59, 0xb8, - 0x32, 0x53, 0xd6, 0xaf, 0x32, 0x53, 0xef, 0x9d, 0x90, 0x2c, 0x7a, 0xfb, 0x90, 0x2d, 0xce, 0x58, - 0x59, 0x5d, 0xa4, 0x05, 0xf5, 0x3d, 0x64, 0x4b, 0x74, 0x7e, 0x0f, 0x99, 0x40, 0xed, 0x4a, 0x60, - 0x81, 0x71, 0x75, 0x14, 0x2f, 0x98, 0xfc, 0xb0, 0x0c, 0x58, 0x09, 0x1c, 0x23, 0x0e, 0x44, 0xac, - 0x04, 0x24, 0xec, 0xbc, 0x5e, 0x66, 0x99, 0x13, 0x36, 0xaf, 0x23, 0xac, 0x3c, 0x8e, 0x57, 0x0b, - 0x96, 0x0b, 0x6d, 0x12, 0x9c, 0xc9, 0x3b, 0x26, 0x71, 0x9e, 0x38, 0x93, 0xef, 0xa3, 0xe7, 0x4c, - 0x4d, 0x5e, 0xc3, 0x1f, 0xf3, 0x52, 0xa8, 0xdf, 0x97, 0x3b, 0x2d, 0x33, 0x30, 0x35, 0xf9, 0x8d, - 0xea, 0x91, 0xc4, 0xd4, 0x14, 0xd6, 0x70, 0x7e, 0x4b, 0xc4, 0x2b, 0xc3, 0x0b, 0x56, 0x9a, 0x38, - 0x79, 0xbe, 0x88, 0xd3, 0x4c, 0x47, 0xc3, 0xf7, 0x03, 0xb6, 0x09, 0x1d, 0xe2, 0xb7, 0x44, 0xfa, - 0xea, 0x3a, 0xbf, 0xbe, 0x12, 0x2e, 0x21, 0x78, 0x44, 0xd0, 0x61, 0x9f, 0x78, 0x44, 0xd0, 0xad, - 0x65, 0x77, 0xee, 0x96, 0x95, 0xdc, 0x4a, 0x12, 0x3b, 0x3c, 0x81, 0xe7, 0x85, 0x8e, 0x4d, 0x00, - 0x12, 0x3b, 0xf7, 0xa0, 0x82, 0x4d, 0x0d, 0x2c, 0xb6, 0x97, 0xe6, 0x71, 0x96, 0xfe, 0x18, 0xa6, - 0xf5, 0x8e, 0x9d, 0x86, 0x20, 0x52, 0x03, 0x9c, 0xc4, 0x5c, 0xed, 0x33, 0x31, 0x4d, 0xeb, 0xa9, - 0xff, 0x7e, 0xa0, 0xdd, 0x24, 0xd1, 0xed, 0xca, 0x21, 0x9d, 0x6f, 0x1f, 0xc3, 0x66, 0x1d, 0x15, - 0xc5, 0xa4, 0x5e, 0x55, 0x4f, 0xd8, 0x8c, 0xa5, 0x85, 0x18, 0x7c, 0x14, 0x6e, 0x2b, 0x80, 0x13, - 0x17, 0x2d, 0x7a, 0xa8, 0x39, 0x8f, 0xef, 0xeb, 0xb9, 0x64, 0xa2, 0x7e, 0x78, 0xf5, 0xb4, 0x62, - 0xa5, 0x4e, 0x34, 0xf6, 0x99, 0x00, 0xa3, 0xd3, 0xe1, 0x86, 0x0e, 0x58, 0x57, 0x94, 0x18, 0x9d, - 0x61, 0x0d, 0x7b, 0xd8, 0xe7, 0x70, 0xfa, 0xdb, 0x01, 0xf2, 0xba, 0xe3, 0x23, 0xd2, 0x98, 0x43, - 0x11, 0x87, 0x7d, 0x34, 0x6d, 0xb3, 0xb5, 0xb6, 0xdb, 0x51, 0xbe, 0x1a, 0xc3, 0x2b, 0x13, 0x88, - 0x25, 0x89, 0x11, 0xd9, 0x5a, 0x00, 0x77, 0x0e, 0xc3, 0x4b, 0x1e, 0x27, 0xb3, 0xb8, 0x12, 0xc7, - 0xf1, 0x2a, 0xe3, 0x71, 0x22, 0xd7, 0x75, 0x78, 0x18, 0xde, 0x30, 0x43, 0x17, 0xa2, 0x0e, 0xc3, - 0x29, 0xd8, 0xcd, 0xce, 0xe4, 0xef, 0xc9, 0xea, 0xab, 0xa4, 0x30, 0x3b, 0x93, 0xe5, 0x85, 0xd7, - 0x48, 0xef, 0x86, 0x21, 0xfb, 0x0a, 0x9c, 0x12, 0xc9, 0x34, 0xe4, 0x16, 0xa6, 0xe3, 0x25, 0x20, - 0xef, 0x07, 0x08, 0xfb, 0x59, 0x16, 0xf5, 0xf7, 0xe6, 0x27, 0xc4, 0x84, 0xfe, 0x42, 0xfc, 0x23, - 0x4c, 0xd7, 0x85, 0xbc, 0x1b, 0x6a, 0x5b, 0x3d, 0x69, 0x9b, 0x66, 0xee, 0x5c, 0xc4, 0x62, 0x94, - 0x24, 0x87, 0xac, 0x42, 0xde, 0x67, 0xaf, 0x85, 0x43, 0x2b, 0x25, 0xd2, 0xcc, 0x36, 0x65, 0x03, - 0xbd, 0x96, 0x3d, 0x4f, 0x52, 0xa1, 0x65, 0xcd, 0x05, 0xed, 0x47, 0x6d, 0x03, 0x6d, 0x8a, 0xa8, - 0x15, 0x4d, 0xdb, 0xb9, 0xbc, 0x66, 0xa6, 0x7c, 0x3e, 0xcf, 0x98, 0x86, 0x4e, 0x58, 0xac, 0x3e, - 0x90, 0xb9, 0xdd, 0xb6, 0x85, 0x82, 0xc4, 0x5c, 0x1e, 0x54, 0xb0, 0x69, 0x64, 0x8d, 0xa9, 0x47, - 0x52, 0x4d, 0xc3, 0x6e, 0xb4, 0xcd, 0x78, 0x00, 0x91, 0x46, 0xa2, 0xa0, 0x7d, 0xed, 0xae, 0x16, - 0xef, 0xb3, 0xa6, 0x25, 0xe0, 0x17, 0xb8, 0xa4, 0xb2, 0x23, 0x26, 0x5e, 0xbb, 0x43, 0x30, 0xbb, - 0x4f, 0x00, 0x1e, 0x9e, 0xad, 0xc6, 0x09, 0xdc, 0x27, 0x40, 0x7d, 0xc9, 0x10, 0xfb, 0x04, 0x8a, - 0xf5, 0xbb, 0xce, 0x9c, 0x7b, 0x1d, 0xc4, 0x95, 0xad, 0x1c, 0xd2, 0x75, 0x28, 0x18, 0xea, 0x3a, - 0x4a, 0xc1, 0x6f, 0x52, 0xf7, 0x68, 0x0d, 0x69, 0x52, 0xec, 0x5c, 0x6d, 0xbd, 0x0b, 0xb3, 0xb9, - 0x7f, 0x2d, 0x3c, 0x61, 0x71, 0x62, 0x2a, 0x86, 0xe8, 0xba, 0x72, 0x22, 0xf7, 0xc7, 0x38, 0xed, - 0xe4, 0xf7, 0xa2, 0x81, 0xaa, 0x46, 0xe9, 0xba, 0xb9, 0x85, 0x15, 0xb1, 0x26, 0x88, 0x89, 0xca, - 0x27, 0x9c, 0xc4, 0xcd, 0xeb, 0xa2, 0x29, 0xd7, 0x0e, 0xf4, 0x6b, 0xa1, 0x15, 0x48, 0xdc, 0xfc, - 0x66, 0x6f, 0xd1, 0x44, 0xe2, 0xd6, 0xad, 0xe5, 0x7c, 0x8c, 0x08, 0x74, 0xd9, 0x5e, 0xc9, 0x17, - 0xb0, 0x4c, 0x9f, 0x06, 0xbb, 0x07, 0xd1, 0x20, 0x3e, 0x46, 0xd4, 0x4f, 0xd3, 0xae, 0x41, 0xe6, - 0xec, 0x40, 0x5e, 0x4f, 0xc3, 0x7f, 0x05, 0x45, 0x09, 0x89, 0x35, 0xa8, 0x05, 0x39, 0x3f, 0x9d, - 0x3a, 0x7e, 0x59, 0xa6, 0x22, 0xcd, 0xe7, 0x53, 0xce, 0x33, 0x78, 0x64, 0x39, 0x1a, 0x0f, 0x5d, - 0x29, 0xf5, 0xd3, 0xa9, 0x2d, 0xca, 0x2e, 0x71, 0xa3, 0xf1, 0x68, 0x29, 0xf8, 0x79, 0x9a, 0x65, - 0x20, 0x72, 0x46, 0xe3, 0x61, 0x23, 0x21, 0x22, 0xc7, 0x27, 0x9c, 0x1f, 0xfc, 0x1c, 0xcb, 0xd3, - 0x7f, 0x7d, 0x02, 0x7a, 0x07, 0xea, 0x38, 0x42, 0xea, 0x07, 0x3f, 0x21, 0xe4, 0xfc, 0x80, 0xe9, - 0x18, 0xfb, 0x29, 0x97, 0x4d, 0xa8, 0x8e, 0x40, 0xd4, 0x0f, 0x98, 0x52, 0xb0, 0xf3, 0x4e, 0xf2, - 0xf1, 0xb2, 0xba, 0xf0, 0x8f, 0x0c, 0xd4, 0xe6, 0x50, 0x7d, 0xb6, 0xf5, 0x29, 0xf8, 0x41, 0x21, - 0x9f, 0x1d, 0x7a, 0x30, 0x71, 0x3d, 0xad, 0x53, 0x49, 0x15, 0xe6, 0xd9, 0xfb, 0xff, 0xf5, 0xd5, - 0x8d, 0xb5, 0x9f, 0x7e, 0x75, 0x63, 0xed, 0x7f, 0xbe, 0xba, 0xb1, 0xf6, 0x93, 0xaf, 0x6f, 0xbc, - 0xf1, 0xd3, 0xaf, 0x6f, 0xbc, 0xf1, 0xdf, 0x5f, 0xdf, 0x78, 0xe3, 0xcb, 0x37, 0x2b, 0x95, 0x9b, - 0x9d, 0xfd, 0x5c, 0x51, 0x72, 0xc1, 0x9f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc7, 0xe9, - 0x8b, 0xe6, 0x86, 0x80, 0x00, 0x00, + 0x52, 0xc0, 0xcf, 0x3c, 0xb0, 0x50, 0xc7, 0x2d, 0xd0, 0x0b, 0xcb, 0xdd, 0x72, 0x37, 0xdf, 0x63, + 0xcf, 0x8c, 0xc7, 0xed, 0xd9, 0x99, 0xfd, 0xe2, 0x0e, 0x09, 0x7a, 0xec, 0xb1, 0xb7, 0x6f, 0x6d, + 0xaf, 0x71, 0xb7, 0x67, 0xc4, 0x4a, 0x48, 0x94, 0xbb, 0xd2, 0xed, 0xc2, 0xd5, 0x95, 0x75, 0x55, + 0xd9, 0x9e, 0xe9, 0x43, 0x20, 0x10, 0x27, 0x10, 0x08, 0xc4, 0x89, 0x2f, 0xc1, 0x13, 0x12, 0x7f, + 0x01, 0x7f, 0x01, 0xcf, 0x3c, 0xde, 0x23, 0x8f, 0x68, 0xf7, 0x1f, 0x41, 0x95, 0x99, 0x95, 0x1f, + 0x51, 0x11, 0x59, 0xe5, 0xe5, 0x69, 0x46, 0x8e, 0x5f, 0x44, 0xe4, 0x47, 0x64, 0x66, 0x64, 0x56, + 0x56, 0x75, 0x74, 0xb3, 0x38, 0xdb, 0x2e, 0x4a, 0x2e, 0x78, 0xb5, 0x5d, 0xb1, 0xf2, 0x2a, 0x9d, + 0xb1, 0xe6, 0xdf, 0xa1, 0xfc, 0xf3, 0xe0, 0xad, 0x38, 0x5f, 0x89, 0x55, 0xc1, 0xde, 0xfb, 0xb6, + 0x25, 0x67, 0x7c, 0xb1, 0x88, 0xf3, 0xa4, 0x52, 0xc8, 0x7b, 0xef, 0x5a, 0x09, 0xbb, 0x62, 0xb9, + 0xd0, 0x7f, 0x7f, 0xfa, 0x5f, 0x3f, 0xf9, 0xb9, 0xe8, 0xed, 0x9d, 0x2c, 0x65, 0xb9, 0xd8, 0xd1, + 0x1a, 0x83, 0x2f, 0xa2, 0x6f, 0x8d, 0x8a, 0x62, 0x9f, 0x89, 0x97, 0xac, 0xac, 0x52, 0x9e, 0x0f, + 0xee, 0x0e, 0xb5, 0x83, 0xe1, 0x49, 0x31, 0x1b, 0x8e, 0x8a, 0x62, 0x68, 0x85, 0xc3, 0x13, 0xf6, + 0xa3, 0x25, 0xab, 0xc4, 0x7b, 0xf7, 0xc2, 0x50, 0x55, 0xf0, 0xbc, 0x62, 0x83, 0xf3, 0xe8, 0x57, + 0x47, 0x45, 0x31, 0x61, 0x62, 0x97, 0xd5, 0x15, 0x98, 0x88, 0x58, 0xb0, 0xc1, 0x46, 0x4b, 0xd5, + 0x07, 0x8c, 0x8f, 0x07, 0xdd, 0xa0, 0xf6, 0x33, 0x8d, 0xbe, 0x59, 0xfb, 0xb9, 0x58, 0x8a, 0x84, + 0xbf, 0xce, 0x07, 0xb7, 0xdb, 0x8a, 0x5a, 0x64, 0x6c, 0xdf, 0x09, 0x21, 0xda, 0xea, 0xab, 0xe8, + 0x97, 0x5e, 0xc5, 0x59, 0xc6, 0xc4, 0x4e, 0xc9, 0xea, 0x82, 0xfb, 0x3a, 0x4a, 0x34, 0x54, 0x32, + 0x63, 0xf7, 0x6e, 0x90, 0xd1, 0x86, 0xbf, 0x88, 0xbe, 0xa5, 0x24, 0x27, 0x6c, 0xc6, 0xaf, 0x58, + 0x39, 0x40, 0xb5, 0xb4, 0x90, 0x68, 0xf2, 0x16, 0x04, 0x6d, 0xef, 0xf0, 0xfc, 0x8a, 0x95, 0x02, + 0xb7, 0xad, 0x85, 0x61, 0xdb, 0x16, 0xd2, 0xb6, 0xff, 0x7a, 0x2d, 0xfa, 0xee, 0x68, 0x36, 0xe3, + 0xcb, 0x5c, 0x1c, 0xf0, 0x59, 0x9c, 0x1d, 0xa4, 0xf9, 0xe5, 0x11, 0x7b, 0xbd, 0x73, 0x51, 0xf3, + 0xf9, 0x9c, 0x0d, 0x9e, 0xf9, 0xad, 0xaa, 0xd0, 0xa1, 0x61, 0x87, 0x2e, 0x6c, 0x7c, 0x7f, 0x70, + 0x3d, 0x25, 0x5d, 0x96, 0xbf, 0x5f, 0x8b, 0x6e, 0xc0, 0xb2, 0x4c, 0x78, 0x76, 0xc5, 0x6c, 0x69, + 0x3e, 0xec, 0x30, 0xec, 0xe3, 0xa6, 0x3c, 0x1f, 0x5d, 0x57, 0x4d, 0x97, 0xe8, 0xcf, 0xd6, 0xa2, + 0xef, 0xc0, 0x12, 0xa9, 0x9e, 0x1f, 0x15, 0xc5, 0xe0, 0x49, 0x87, 0x55, 0x43, 0x9a, 0x72, 0xbc, + 0x7f, 0x0d, 0x0d, 0x5d, 0x84, 0x3f, 0x89, 0xbe, 0x0d, 0x4b, 0x70, 0x90, 0x56, 0x62, 0x54, 0x14, + 0xd5, 0x60, 0xbb, 0xc3, 0x5c, 0x03, 0x1a, 0xff, 0x4f, 0xfa, 0x2b, 0x04, 0x5a, 0xe0, 0x84, 0x5d, + 0xf1, 0xcb, 0x5e, 0x2d, 0x60, 0xc8, 0xde, 0x2d, 0xe0, 0x6a, 0xe8, 0x22, 0x64, 0xd1, 0x3b, 0xee, + 0x98, 0x9d, 0xb0, 0x4a, 0xce, 0x69, 0x0f, 0xe9, 0x61, 0xa9, 0x11, 0xe3, 0xf4, 0x51, 0x1f, 0x54, + 0x7b, 0x4b, 0xa3, 0x81, 0xf6, 0x96, 0xf1, 0xca, 0x38, 0x7b, 0x80, 0x5a, 0x70, 0x08, 0xe3, 0xeb, + 0x61, 0x0f, 0x52, 0xbb, 0xfa, 0xc3, 0xe8, 0x97, 0x5f, 0xf1, 0xf2, 0xb2, 0x2a, 0xe2, 0x19, 0xd3, + 0xf3, 0xd1, 0x7d, 0x5f, 0xbb, 0x91, 0xc2, 0x29, 0x69, 0xbd, 0x0b, 0x73, 0x66, 0x8e, 0x46, 0xf8, + 0x79, 0xc1, 0xe0, 0x42, 0x60, 0x15, 0x6b, 0x21, 0x35, 0x73, 0x40, 0x48, 0xdb, 0xbe, 0x8c, 0x06, + 0xd6, 0xf6, 0xd9, 0x1f, 0xb1, 0x99, 0x18, 0x25, 0x09, 0xec, 0x15, 0xab, 0x2b, 0x89, 0xe1, 0x28, + 0x49, 0xa8, 0x5e, 0xc1, 0x51, 0xed, 0xec, 0x75, 0xf4, 0x2e, 0x70, 0x26, 0x43, 0x35, 0x49, 0x06, + 0x5b, 0x61, 0x2b, 0x1a, 0x33, 0x4e, 0x87, 0x7d, 0x71, 0x27, 0xfe, 0x11, 0xcf, 0x27, 0x6c, 0xc1, + 0xaf, 0x18, 0x88, 0x7f, 0xd4, 0x9a, 0x22, 0x89, 0xf8, 0x0f, 0x6b, 0x20, 0x61, 0x32, 0x61, 0x19, + 0x9b, 0x09, 0x32, 0x4c, 0x94, 0xb8, 0x33, 0x4c, 0x0c, 0xe6, 0x8c, 0xb0, 0x46, 0xb8, 0xcf, 0xc4, + 0xce, 0xb2, 0x2c, 0x59, 0x2e, 0xc8, 0xbe, 0xb4, 0x48, 0x67, 0x5f, 0x7a, 0x28, 0x52, 0x9f, 0x7d, + 0x26, 0x46, 0x59, 0x46, 0xd6, 0x47, 0x89, 0x3b, 0xeb, 0x63, 0x30, 0xed, 0x61, 0x16, 0xfd, 0x8a, + 0xd3, 0x62, 0x62, 0x9c, 0x9f, 0xf3, 0x01, 0xdd, 0x16, 0x52, 0x6e, 0x7c, 0x6c, 0x74, 0x72, 0x48, + 0x35, 0x5e, 0xbc, 0x29, 0x78, 0x49, 0x77, 0x8b, 0x12, 0x77, 0x56, 0xc3, 0x60, 0xda, 0xc3, 0x1f, + 0x44, 0x6f, 0xeb, 0x09, 0xb2, 0x49, 0x2a, 0xee, 0xa1, 0xb3, 0x27, 0xcc, 0x2a, 0xee, 0x77, 0x50, + 0x2d, 0xf3, 0x87, 0xe9, 0xbc, 0xac, 0x67, 0x1f, 0xdc, 0xbc, 0x96, 0x76, 0x98, 0xb7, 0x94, 0x36, + 0xcf, 0xa3, 0x5f, 0xf3, 0xcd, 0xef, 0xc4, 0xf9, 0x8c, 0x65, 0x83, 0x47, 0x21, 0x75, 0xc5, 0x18, + 0x57, 0x9b, 0xbd, 0x58, 0x3b, 0xd9, 0x69, 0x42, 0x4f, 0xa6, 0x77, 0x51, 0x6d, 0x30, 0x95, 0xde, + 0x0b, 0x43, 0x2d, 0xdb, 0xbb, 0x2c, 0x63, 0xa4, 0x6d, 0x25, 0xec, 0xb0, 0x6d, 0x20, 0x6d, 0xbb, + 0x8c, 0x7e, 0xdd, 0x74, 0x73, 0x9d, 0x9c, 0x49, 0x79, 0xbd, 0xe8, 0x6c, 0x12, 0xfd, 0xe8, 0x42, + 0xc6, 0xd7, 0xe3, 0x7e, 0x70, 0xab, 0x3e, 0x7a, 0x46, 0xc1, 0xeb, 0x03, 0xe6, 0x93, 0x7b, 0x61, + 0x48, 0xdb, 0xfe, 0x9b, 0xb5, 0xe8, 0x7b, 0x5a, 0xf6, 0x22, 0x8f, 0xcf, 0x32, 0x26, 0x57, 0xf7, + 0x23, 0x26, 0x5e, 0xf3, 0xf2, 0x72, 0xb2, 0xca, 0x67, 0x44, 0x4e, 0x89, 0xc3, 0x1d, 0x39, 0x25, + 0xa9, 0xa4, 0x0b, 0xf3, 0xc7, 0x26, 0x7d, 0xda, 0xb9, 0x88, 0xf3, 0x39, 0xfb, 0x61, 0xc5, 0xf3, + 0x51, 0x91, 0x8e, 0x92, 0xa4, 0x1c, 0x0c, 0xf1, 0xae, 0x87, 0x9c, 0x29, 0xc1, 0x76, 0x6f, 0xde, + 0xd9, 0xc3, 0xe8, 0x56, 0x16, 0xbc, 0x80, 0x7b, 0x98, 0xa6, 0xf9, 0x04, 0x2f, 0xa8, 0x3d, 0x8c, + 0x8f, 0xb4, 0xac, 0x1e, 0xd6, 0x6b, 0x10, 0x6e, 0xf5, 0xd0, 0x5d, 0x74, 0xee, 0x84, 0x10, 0xbb, + 0x06, 0x34, 0x0d, 0xc5, 0xf3, 0xf3, 0x74, 0x7e, 0x5a, 0x24, 0xf5, 0x18, 0x7a, 0x88, 0xd7, 0xd9, + 0x41, 0x88, 0x35, 0x80, 0x40, 0xb5, 0xb7, 0xbf, 0xb3, 0xa9, 0xbe, 0x9e, 0x97, 0xf6, 0x4a, 0xbe, + 0x38, 0x60, 0xf3, 0x78, 0xb6, 0xd2, 0x93, 0xe9, 0x07, 0xa1, 0x59, 0x0c, 0xd2, 0xa6, 0x10, 0x1f, + 0x5e, 0x53, 0x4b, 0x97, 0xe7, 0xdf, 0xd7, 0xa2, 0x7b, 0x5e, 0x9c, 0xe8, 0x60, 0x52, 0xa5, 0x1f, + 0xe5, 0xc9, 0x09, 0xab, 0x44, 0x5c, 0x8a, 0xc1, 0xf7, 0x03, 0x31, 0x40, 0xe8, 0x98, 0xb2, 0xfd, + 0xe0, 0x6b, 0xe9, 0xda, 0x5e, 0x9f, 0xd4, 0xab, 0x84, 0x9e, 0x7f, 0xfc, 0x5e, 0x97, 0x12, 0x38, + 0xfb, 0xdc, 0x09, 0x21, 0xb6, 0xd7, 0xa5, 0x60, 0x9c, 0x5f, 0xa5, 0x82, 0xed, 0xb3, 0x9c, 0x95, + 0xed, 0x5e, 0x57, 0xaa, 0x3e, 0x42, 0xf4, 0x3a, 0x81, 0xda, 0xb3, 0x03, 0xc7, 0x9b, 0xaa, 0x38, + 0x38, 0x3b, 0x70, 0x0d, 0x28, 0x80, 0x38, 0x3b, 0x40, 0x41, 0x3b, 0xa3, 0x7a, 0xb5, 0x32, 0x19, + 0xcd, 0x66, 0xa0, 0xb0, 0xad, 0x9c, 0xe6, 0x71, 0x3f, 0x98, 0x68, 0x49, 0xb1, 0x5f, 0x1b, 0x09, + 0xb6, 0xa4, 0x42, 0x7a, 0xb5, 0xa4, 0x41, 0xd1, 0x96, 0x54, 0x9b, 0xa6, 0x40, 0x4b, 0x2a, 0xa0, + 0x47, 0x4b, 0x1a, 0xd0, 0x26, 0x39, 0x8e, 0x9f, 0x97, 0x29, 0x7b, 0x0d, 0x92, 0x1c, 0x57, 0xb9, + 0x16, 0x13, 0x49, 0x0e, 0x82, 0x69, 0x0f, 0x47, 0xd1, 0x2f, 0x4a, 0xe1, 0x0f, 0x79, 0x9a, 0x0f, + 0x6e, 0x22, 0x4a, 0xb5, 0xc0, 0x58, 0xbd, 0x45, 0x03, 0xa0, 0xc4, 0xf5, 0x5f, 0x75, 0xc6, 0x71, + 0x9f, 0x50, 0x02, 0xc9, 0xc6, 0x7a, 0x17, 0x66, 0xb3, 0x4b, 0x29, 0xac, 0x67, 0xe5, 0xc9, 0x45, + 0x5c, 0xa6, 0xf9, 0x7c, 0x80, 0xe9, 0x3a, 0x72, 0x22, 0xbb, 0xc4, 0x38, 0x10, 0x4e, 0x5a, 0x71, + 0x54, 0x14, 0x65, 0x3d, 0xd9, 0x63, 0xe1, 0xe4, 0x23, 0xc1, 0x70, 0x6a, 0xa1, 0xb8, 0xb7, 0x5d, + 0x36, 0xcb, 0xd2, 0x3c, 0xe8, 0x4d, 0x23, 0x7d, 0xbc, 0x59, 0x14, 0x04, 0xef, 0x01, 0x8b, 0xaf, + 0x58, 0x53, 0x33, 0xac, 0x65, 0x5c, 0x20, 0x18, 0xbc, 0x00, 0xb4, 0x5b, 0x79, 0x29, 0x3e, 0x8c, + 0x2f, 0x59, 0xdd, 0xc0, 0xac, 0x4e, 0x15, 0x06, 0x98, 0xbe, 0x47, 0x10, 0x5b, 0x79, 0x9c, 0xd4, + 0xae, 0x96, 0xd1, 0xbb, 0x52, 0x7e, 0x1c, 0x97, 0x22, 0x9d, 0xa5, 0x45, 0x9c, 0x37, 0x5b, 0x44, + 0x6c, 0x16, 0x69, 0x51, 0xc6, 0xe5, 0x56, 0x4f, 0x5a, 0xbb, 0xfd, 0x97, 0xb5, 0xe8, 0x36, 0xf4, + 0x7b, 0xcc, 0xca, 0x45, 0x2a, 0x4f, 0x1a, 0x2a, 0x3d, 0xc3, 0x7e, 0x1c, 0x36, 0xda, 0x52, 0x30, + 0xa5, 0xf9, 0xe4, 0xfa, 0x8a, 0x36, 0xbf, 0x9c, 0xe8, 0xdd, 0xd7, 0xe7, 0x65, 0xd2, 0x3a, 0x0e, + 0x9d, 0x34, 0x5b, 0x2a, 0x29, 0x24, 0xf2, 0xcb, 0x16, 0x04, 0x46, 0xf8, 0x69, 0x5e, 0x35, 0xd6, + 0xb1, 0x11, 0x6e, 0xc5, 0xc1, 0x11, 0xee, 0x61, 0x76, 0x84, 0x1f, 0x2f, 0xcf, 0xb2, 0xb4, 0xba, + 0x48, 0xf3, 0xb9, 0xde, 0x4c, 0xf8, 0xba, 0x56, 0x0c, 0xf7, 0x13, 0x1b, 0x9d, 0x1c, 0xe6, 0x44, + 0x07, 0x0b, 0xe9, 0x04, 0x84, 0xc9, 0x46, 0x27, 0x67, 0xf7, 0x78, 0x56, 0x7a, 0x90, 0x56, 0x02, + 0xec, 0xf1, 0x1c, 0xd5, 0x5a, 0x4a, 0xec, 0xf1, 0xda, 0x94, 0xdd, 0xe3, 0xb9, 0x75, 0xa8, 0x78, + 0x76, 0xc5, 0x4e, 0xcb, 0x14, 0xec, 0xf1, 0xbc, 0xf2, 0x35, 0x0c, 0xb1, 0xc7, 0xa3, 0x58, 0x3b, + 0x51, 0x59, 0x62, 0x9f, 0x89, 0x89, 0x88, 0xc5, 0xb2, 0x02, 0x13, 0x95, 0x63, 0xc3, 0x20, 0xc4, + 0x44, 0x45, 0xa0, 0xda, 0xdb, 0xef, 0x45, 0x91, 0x3a, 0x97, 0x91, 0x67, 0x67, 0xfe, 0xda, 0xa3, + 0x0f, 0x6c, 0xbc, 0x83, 0xb3, 0xdb, 0x01, 0xc2, 0xa6, 0x71, 0xea, 0xef, 0xf2, 0x48, 0x70, 0x80, + 0x6a, 0x48, 0x11, 0x91, 0xc6, 0x01, 0x04, 0x16, 0x74, 0x72, 0xc1, 0x5f, 0xe3, 0x05, 0xad, 0x25, + 0xe1, 0x82, 0x6a, 0xc2, 0x3e, 0x29, 0xd1, 0x05, 0xc5, 0x9e, 0x94, 0x34, 0xc5, 0x08, 0x3d, 0x29, + 0x81, 0x8c, 0x8d, 0x19, 0xd7, 0xf0, 0x73, 0xce, 0x2f, 0x17, 0x71, 0x79, 0x09, 0x62, 0xc6, 0x53, + 0x6e, 0x18, 0x22, 0x66, 0x28, 0xd6, 0xc6, 0x8c, 0xeb, 0xb0, 0xde, 0x04, 0x9c, 0x96, 0x19, 0x88, + 0x19, 0xcf, 0x86, 0x46, 0x88, 0x98, 0x21, 0x50, 0x3b, 0x3b, 0xb9, 0xde, 0x26, 0x0c, 0x1e, 0x0b, + 0x79, 0xea, 0x13, 0x46, 0x1d, 0x0b, 0x21, 0x18, 0x0c, 0xa1, 0xfd, 0x32, 0x2e, 0x2e, 0xf0, 0x10, + 0x92, 0xa2, 0x70, 0x08, 0x35, 0x08, 0xec, 0xef, 0x09, 0x8b, 0xcb, 0xd9, 0x05, 0xde, 0xdf, 0x4a, + 0x16, 0xee, 0x6f, 0xc3, 0xc0, 0xfe, 0x56, 0x82, 0x57, 0xa9, 0xb8, 0x38, 0x64, 0x22, 0xc6, 0xfb, + 0xdb, 0x67, 0xc2, 0xfd, 0xdd, 0x62, 0x6d, 0xf6, 0xef, 0x3a, 0x9c, 0x2c, 0xcf, 0xaa, 0x59, 0x99, + 0x9e, 0xb1, 0x41, 0xc0, 0x8a, 0x81, 0x88, 0xec, 0x9f, 0x84, 0xb5, 0xcf, 0x9f, 0xae, 0x45, 0x37, + 0x9b, 0x6e, 0xe7, 0x55, 0xa5, 0xd7, 0x3e, 0xdf, 0xfd, 0x87, 0x78, 0xff, 0x12, 0x38, 0xf1, 0xec, + 0xaa, 0x87, 0x9a, 0x93, 0x1b, 0xe0, 0x45, 0x3a, 0xcd, 0x2b, 0x53, 0xa8, 0x8f, 0xfb, 0x58, 0x77, + 0x14, 0x88, 0xdc, 0xa0, 0x97, 0xa2, 0x4d, 0xcb, 0x74, 0xff, 0x34, 0xb2, 0x71, 0x52, 0x81, 0xb4, + 0xac, 0x69, 0x6f, 0x87, 0x20, 0xd2, 0x32, 0x9c, 0x84, 0xa1, 0xb0, 0x5f, 0xf2, 0x65, 0x51, 0x75, + 0x84, 0x02, 0x80, 0xc2, 0xa1, 0xd0, 0x86, 0xb5, 0xcf, 0x37, 0xd1, 0x6f, 0xb8, 0xe1, 0xe7, 0x36, + 0xf6, 0x16, 0x1d, 0x53, 0x58, 0x13, 0x0f, 0xfb, 0xe2, 0x36, 0xa3, 0x68, 0x3c, 0x8b, 0x5d, 0x26, + 0xe2, 0x34, 0xab, 0x06, 0xeb, 0xb8, 0x8d, 0x46, 0x4e, 0x64, 0x14, 0x18, 0x07, 0xe7, 0xb7, 0xdd, + 0x65, 0x91, 0xa5, 0xb3, 0xf6, 0x43, 0x2b, 0xad, 0x6b, 0xc4, 0xe1, 0xf9, 0xcd, 0xc5, 0xe0, 0x7c, + 0x5d, 0xa7, 0x7e, 0xf2, 0x3f, 0xd3, 0x55, 0xc1, 0xf0, 0xf9, 0xda, 0x43, 0xc2, 0xf3, 0x35, 0x44, + 0x61, 0x7d, 0x26, 0x4c, 0x1c, 0xc4, 0x2b, 0xbe, 0x24, 0xe6, 0x6b, 0x23, 0x0e, 0xd7, 0xc7, 0xc5, + 0xec, 0xde, 0xc0, 0x78, 0x18, 0xe7, 0x82, 0x95, 0x79, 0x9c, 0xed, 0x65, 0xf1, 0xbc, 0x1a, 0x10, + 0x73, 0x8c, 0x4f, 0x11, 0x7b, 0x03, 0x9a, 0x46, 0x9a, 0x71, 0x5c, 0xed, 0xc5, 0x57, 0xbc, 0x4c, + 0x05, 0xdd, 0x8c, 0x16, 0xe9, 0x6c, 0x46, 0x0f, 0x45, 0xbd, 0x8d, 0xca, 0xd9, 0x45, 0x7a, 0xc5, + 0x92, 0x80, 0xb7, 0x06, 0xe9, 0xe1, 0xcd, 0x41, 0x91, 0x4e, 0x9b, 0xf0, 0x65, 0x39, 0x63, 0x64, + 0xa7, 0x29, 0x71, 0x67, 0xa7, 0x19, 0x4c, 0x7b, 0xf8, 0xc9, 0x5a, 0xf4, 0x9b, 0x4a, 0xea, 0x3e, + 0x49, 0xda, 0x8d, 0xab, 0x8b, 0x33, 0x1e, 0x97, 0xc9, 0xe0, 0x7d, 0xcc, 0x0e, 0x8a, 0x1a, 0xd7, + 0x4f, 0xaf, 0xa3, 0x02, 0x9b, 0xb5, 0xce, 0xbb, 0xed, 0x88, 0x43, 0x9b, 0xd5, 0x43, 0xc2, 0xcd, + 0x0a, 0x51, 0x38, 0x81, 0x48, 0xb9, 0x3a, 0x68, 0x5c, 0x27, 0xf5, 0xfd, 0xd3, 0xc6, 0x8d, 0x4e, + 0x0e, 0xce, 0x8f, 0xb5, 0xd0, 0x8f, 0x96, 0x2d, 0xca, 0x06, 0x1e, 0x31, 0xc3, 0xbe, 0x38, 0xe9, + 0xd9, 0x8c, 0x8a, 0xb0, 0xe7, 0xd6, 0xc8, 0x18, 0xf6, 0xc5, 0x09, 0xcf, 0xce, 0xb4, 0x16, 0xf2, + 0x8c, 0x4c, 0x6d, 0xc3, 0xbe, 0x38, 0xcc, 0xbe, 0x34, 0xd3, 0xac, 0x0b, 0x8f, 0x02, 0x76, 0xe0, + 0xda, 0xb0, 0xd9, 0x8b, 0xd5, 0x0e, 0xff, 0x6a, 0x2d, 0xfa, 0xae, 0xf5, 0x78, 0xc8, 0x93, 0xf4, + 0x7c, 0xa5, 0xa0, 0x97, 0x71, 0xb6, 0x64, 0xd5, 0xe0, 0x29, 0x65, 0xad, 0xcd, 0x9a, 0x12, 0x3c, + 0xbb, 0x96, 0x0e, 0x1c, 0x3b, 0xa3, 0xa2, 0xc8, 0x56, 0x53, 0xb6, 0x28, 0x32, 0x72, 0xec, 0x78, + 0x48, 0x78, 0xec, 0x40, 0x14, 0x66, 0xe5, 0x53, 0x5e, 0xe7, 0xfc, 0x68, 0x56, 0x2e, 0x45, 0xe1, + 0xac, 0xbc, 0x41, 0x60, 0xae, 0x34, 0xe5, 0x3b, 0x3c, 0xcb, 0xd8, 0x4c, 0xb4, 0x6f, 0xa3, 0x18, + 0x4d, 0x4b, 0x84, 0x73, 0x25, 0x40, 0xda, 0x53, 0xb9, 0x66, 0x0f, 0x19, 0x97, 0xec, 0xf9, 0xea, + 0x20, 0xcd, 0x2f, 0x07, 0x78, 0x5a, 0x60, 0x01, 0xe2, 0x54, 0x0e, 0x05, 0xe1, 0x5e, 0xf5, 0x34, + 0x4f, 0x38, 0xbe, 0x57, 0xad, 0x25, 0xe1, 0xbd, 0xaa, 0x26, 0xa0, 0xc9, 0x13, 0x46, 0x99, 0xac, + 0x25, 0x61, 0x93, 0x9a, 0xc0, 0xa6, 0x42, 0xfd, 0x44, 0x8a, 0x9c, 0x0a, 0xc1, 0x33, 0xa8, 0x8d, + 0x4e, 0x0e, 0xee, 0xb9, 0xb4, 0x03, 0x34, 0x22, 0x80, 0xf1, 0xbb, 0x41, 0x06, 0x86, 0x7e, 0xb3, + 0x1b, 0xde, 0x63, 0x62, 0x76, 0x81, 0x87, 0xbe, 0x87, 0x84, 0x43, 0x1f, 0xa2, 0xb0, 0xad, 0xa6, + 0xdc, 0xec, 0xe6, 0xd7, 0xf1, 0xc0, 0x6b, 0xed, 0xe4, 0x37, 0x3a, 0x39, 0xd8, 0x56, 0xe3, 0x05, + 0xdd, 0x56, 0x4a, 0x16, 0x6e, 0x2b, 0xc3, 0xc0, 0xd2, 0x2b, 0x81, 0x3c, 0x24, 0x5b, 0xa7, 0x15, + 0xbd, 0x63, 0xb2, 0x8d, 0x4e, 0x4e, 0x3b, 0xf9, 0x27, 0xb3, 0x3f, 0x54, 0xd2, 0x23, 0x5e, 0x0f, + 0xbe, 0x97, 0x71, 0x96, 0x26, 0xb1, 0x60, 0x53, 0x7e, 0xc9, 0x72, 0x7c, 0x2b, 0xa6, 0x4b, 0xab, + 0xf8, 0xa1, 0xa7, 0x10, 0xde, 0x8a, 0x85, 0x15, 0x61, 0x9c, 0x28, 0xfa, 0xb4, 0x62, 0x3b, 0x71, + 0x45, 0x4c, 0x91, 0x1e, 0x12, 0x8e, 0x13, 0x88, 0xc2, 0x44, 0x58, 0xc9, 0x5f, 0xbc, 0x29, 0x58, + 0x99, 0xb2, 0x7c, 0xc6, 0xf0, 0x44, 0x18, 0x52, 0xe1, 0x44, 0x18, 0xa1, 0xe1, 0x26, 0x70, 0x37, + 0x16, 0xec, 0xf9, 0x6a, 0x9a, 0x2e, 0x58, 0x25, 0xe2, 0x45, 0x81, 0x6f, 0x02, 0x01, 0x14, 0xde, + 0x04, 0xb6, 0xe1, 0xd6, 0x99, 0x93, 0x99, 0x69, 0xdb, 0xb7, 0xe3, 0x20, 0x11, 0xb8, 0x1d, 0x47, + 0xa0, 0xb0, 0x61, 0x2d, 0x80, 0x3e, 0x7d, 0x68, 0x59, 0x09, 0x3e, 0x7d, 0xa0, 0xe9, 0xd6, 0x49, + 0x9e, 0x61, 0x26, 0xf5, 0xd0, 0xec, 0x28, 0xfa, 0xc4, 0x1d, 0xa2, 0x9b, 0xbd, 0x58, 0xfc, 0xe8, + 0xf0, 0x84, 0x65, 0xb1, 0x5c, 0x0f, 0x03, 0xe7, 0x73, 0x0d, 0xd3, 0xe7, 0xe8, 0xd0, 0x61, 0xb5, + 0xc3, 0x3f, 0x5f, 0x8b, 0xde, 0xc3, 0x3c, 0x7e, 0x5e, 0x48, 0xbf, 0x4f, 0xba, 0x6d, 0x29, 0x92, + 0xb8, 0xfe, 0x17, 0xd6, 0xb0, 0x37, 0x58, 0x1a, 0x91, 0xbd, 0x1d, 0xa8, 0x0b, 0xe0, 0x67, 0x83, + 0xa6, 0xfc, 0x90, 0x23, 0x6e, 0xb0, 0x84, 0x78, 0xbb, 0xd1, 0xf2, 0xcb, 0x55, 0x81, 0x8d, 0x96, + 0xb1, 0xa1, 0xc5, 0xc4, 0x46, 0x0b, 0xc1, 0xec, 0xe8, 0x74, 0xab, 0xf7, 0x2a, 0x15, 0x17, 0x32, + 0x91, 0x03, 0xa3, 0xd3, 0x2b, 0xab, 0x81, 0x88, 0xd1, 0x49, 0xc2, 0x30, 0xd5, 0x69, 0xc0, 0x7a, + 0x6c, 0x62, 0x73, 0xb9, 0x31, 0xe4, 0x8e, 0xcc, 0x07, 0xdd, 0x20, 0x8c, 0xd7, 0x46, 0xac, 0xf7, + 0x54, 0x8f, 0x42, 0x16, 0xc0, 0xbe, 0x6a, 0xb3, 0x17, 0xab, 0x1d, 0xfe, 0x69, 0xf4, 0x9d, 0x56, + 0xc5, 0xf6, 0x58, 0x2c, 0x96, 0x25, 0x4b, 0xc0, 0x6d, 0xf1, 0x76, 0xb9, 0x1b, 0x90, 0xb8, 0x2d, + 0x1e, 0x54, 0x68, 0x25, 0xff, 0x0d, 0xa7, 0xc2, 0xca, 0x94, 0xe1, 0x69, 0xc8, 0xa4, 0xcf, 0x06, + 0x93, 0x7f, 0x5a, 0xa7, 0xb5, 0x7f, 0x77, 0xa3, 0x6b, 0x74, 0x15, 0xa7, 0x99, 0x7c, 0x0a, 0xfc, + 0x7e, 0xc8, 0xa8, 0x87, 0x06, 0xf7, 0xef, 0xa4, 0x4a, 0x6b, 0x66, 0x96, 0x63, 0xdc, 0xd9, 0xf7, + 0x3d, 0xa6, 0x67, 0x02, 0x64, 0xdb, 0xb7, 0xd5, 0x93, 0xd6, 0x6e, 0x45, 0xb3, 0xe4, 0xd5, 0x7f, + 0x76, 0x83, 0x1c, 0xf3, 0xaa, 0x55, 0x91, 0x48, 0xdf, 0xea, 0x49, 0xdb, 0x57, 0x15, 0xda, 0x5e, + 0xf5, 0x42, 0xb4, 0xdd, 0x69, 0x0a, 0xac, 0x45, 0x4f, 0xfa, 0x2b, 0x68, 0xf7, 0xff, 0x6a, 0x0e, + 0xbc, 0x95, 0xff, 0x19, 0x5f, 0x2c, 0x58, 0x9e, 0xb0, 0xa4, 0xd1, 0xa8, 0xea, 0x8d, 0xd9, 0x27, + 0xb4, 0x5d, 0xa3, 0x30, 0x74, 0x35, 0x4c, 0x89, 0x7e, 0xeb, 0x6b, 0x68, 0xea, 0xa2, 0xfd, 0xe7, + 0x5a, 0xf4, 0x10, 0x2d, 0x5a, 0x13, 0xb8, 0x5e, 0x11, 0x7f, 0xb7, 0x8f, 0x23, 0x4c, 0xd3, 0x14, + 0x75, 0xf4, 0xff, 0xb0, 0xa0, 0x8b, 0xfc, 0x6f, 0x6b, 0xd1, 0x1d, 0xab, 0x58, 0x87, 0xf7, 0x0e, + 0xcf, 0xcf, 0xb3, 0x74, 0x26, 0xe4, 0xa3, 0x5e, 0xad, 0x42, 0x37, 0x27, 0xa5, 0xd1, 0xdd, 0x9c, + 0x01, 0x4d, 0x5d, 0xb6, 0x7f, 0x5c, 0x8b, 0x6e, 0xb9, 0xcd, 0x29, 0x9f, 0x13, 0xab, 0x63, 0xd7, + 0x46, 0xb1, 0x1a, 0x7c, 0x44, 0xb7, 0x01, 0xc6, 0x9b, 0x72, 0x7d, 0x7c, 0x6d, 0x3d, 0xbb, 0x57, + 0xff, 0x34, 0xad, 0x04, 0x2f, 0x57, 0x93, 0x0b, 0xfe, 0xba, 0x79, 0xf5, 0xce, 0x5f, 0x2d, 0x34, + 0x30, 0x74, 0x08, 0x62, 0xaf, 0x8e, 0x93, 0x2d, 0x57, 0xf6, 0x15, 0xbd, 0x8a, 0x70, 0xe5, 0x10, + 0x1d, 0xae, 0x7c, 0xd2, 0xae, 0x95, 0x4d, 0xad, 0xec, 0xfb, 0x84, 0x1b, 0x78, 0x51, 0xdb, 0xef, + 0x14, 0x3e, 0xe8, 0x06, 0x6d, 0xc6, 0xac, 0xc5, 0xbb, 0xe9, 0xf9, 0xb9, 0xa9, 0x13, 0x5e, 0x52, + 0x17, 0x21, 0x32, 0x66, 0x02, 0xb5, 0x9b, 0xbe, 0xbd, 0x34, 0x63, 0xf2, 0x51, 0xd5, 0xe7, 0xe7, + 0xe7, 0x19, 0x8f, 0x13, 0xb0, 0xe9, 0xab, 0xc5, 0x43, 0x57, 0x4e, 0x6c, 0xfa, 0x30, 0xce, 0x5e, + 0x82, 0xa9, 0xa5, 0xf5, 0x98, 0xcb, 0x67, 0x69, 0x06, 0x2f, 0x8d, 0x4b, 0x4d, 0x23, 0x24, 0x2e, + 0xc1, 0xb4, 0x20, 0x9b, 0x98, 0xd5, 0xa2, 0x7a, 0xac, 0x34, 0xe5, 0xbf, 0xdf, 0x56, 0x74, 0xc4, + 0x44, 0x62, 0x86, 0x60, 0xf6, 0x50, 0xa5, 0x16, 0x9e, 0x16, 0xd2, 0xf8, 0xad, 0xb6, 0x96, 0x92, + 0x10, 0x87, 0x2a, 0x3e, 0x61, 0xf7, 0xf0, 0xf5, 0xdf, 0x77, 0xf9, 0xeb, 0x5c, 0x1a, 0xbd, 0xd3, + 0x56, 0x69, 0x64, 0xc4, 0x1e, 0x1e, 0x32, 0xda, 0xf0, 0x67, 0xd1, 0x2f, 0x48, 0xc3, 0x25, 0x2f, + 0x06, 0x37, 0x10, 0x85, 0xd2, 0xb9, 0x62, 0x7d, 0x93, 0x94, 0xdb, 0x3b, 0x33, 0x26, 0x36, 0x4e, + 0xab, 0x78, 0x0e, 0xdf, 0x8b, 0xb0, 0x3d, 0x2e, 0xa5, 0xc4, 0x9d, 0x99, 0x36, 0xe5, 0x47, 0xc5, + 0x11, 0x4f, 0xb4, 0x75, 0xa4, 0x86, 0x46, 0x18, 0x8a, 0x0a, 0x17, 0xb2, 0xc9, 0xf4, 0x51, 0x7c, + 0x95, 0xce, 0x4d, 0xc2, 0xa3, 0xa6, 0xaf, 0x0a, 0x24, 0xd3, 0x96, 0x19, 0x3a, 0x10, 0x91, 0x4c, + 0x93, 0xb0, 0x33, 0x19, 0x5b, 0x66, 0xbf, 0x39, 0x86, 0x1e, 0xe7, 0xe7, 0xbc, 0x4e, 0xbd, 0x0f, + 0xd2, 0xfc, 0x12, 0x4e, 0xc6, 0x8e, 0x49, 0x9c, 0x27, 0x26, 0xe3, 0x3e, 0x7a, 0x76, 0xd7, 0xd4, + 0x9c, 0xd1, 0xda, 0x8b, 0x1a, 0x4a, 0x03, 0xec, 0x9a, 0xcc, 0x51, 0x2e, 0xe4, 0x88, 0x5d, 0x53, + 0x88, 0xb7, 0x5d, 0x6c, 0x9c, 0x67, 0x3c, 0x87, 0x5d, 0x6c, 0x2d, 0xd4, 0x42, 0xa2, 0x8b, 0x5b, + 0x90, 0x9d, 0x8f, 0x1b, 0x91, 0x3a, 0xf5, 0x1b, 0x65, 0x19, 0x98, 0x8f, 0x8d, 0xaa, 0x01, 0x88, + 0xf9, 0x18, 0x05, 0xb5, 0x9f, 0x93, 0xe8, 0x9b, 0x75, 0x93, 0x1e, 0x97, 0xec, 0x2a, 0x65, 0xf0, + 0x4e, 0x91, 0x23, 0x21, 0xc6, 0xbf, 0x4f, 0xd8, 0x91, 0x75, 0x9a, 0x57, 0x45, 0x16, 0x57, 0x17, + 0xfa, 0x96, 0x89, 0x5f, 0xe7, 0x46, 0x08, 0xef, 0x99, 0xdc, 0xef, 0xa0, 0xec, 0xa4, 0xde, 0xc8, + 0xcc, 0x14, 0xb3, 0x8e, 0xab, 0xb6, 0xa6, 0x99, 0x8d, 0x4e, 0xce, 0x3e, 0xca, 0xd9, 0x8f, 0xb3, + 0x8c, 0x95, 0xab, 0x46, 0x76, 0x18, 0xe7, 0xe9, 0x39, 0xab, 0x04, 0x78, 0x94, 0xa3, 0xa9, 0x21, + 0xc4, 0x88, 0x47, 0x39, 0x01, 0xdc, 0xee, 0x26, 0x81, 0xe7, 0x71, 0x9e, 0xb0, 0x37, 0x60, 0x37, + 0x09, 0xed, 0x48, 0x86, 0xd8, 0x4d, 0x52, 0xac, 0x7d, 0xa4, 0xf1, 0x3c, 0xe3, 0xb3, 0x4b, 0xbd, + 0x04, 0xf8, 0x1d, 0x2c, 0x25, 0x70, 0x0d, 0xb8, 0x13, 0x42, 0xec, 0x22, 0x20, 0x05, 0x27, 0xac, + 0xc8, 0xe2, 0x19, 0xbc, 0x58, 0xa6, 0x74, 0xb4, 0x8c, 0x58, 0x04, 0x20, 0x03, 0x8a, 0xab, 0x2f, + 0xac, 0x61, 0xc5, 0x05, 0xf7, 0xd5, 0xee, 0x84, 0x10, 0xbb, 0x0c, 0x4a, 0xc1, 0xa4, 0xc8, 0x52, + 0x01, 0x86, 0x81, 0xd2, 0x90, 0x12, 0x62, 0x18, 0xf8, 0x04, 0x30, 0x79, 0xc8, 0xca, 0x39, 0x43, + 0x4d, 0x4a, 0x49, 0xd0, 0x64, 0x43, 0xd8, 0x5b, 0xf4, 0xaa, 0xee, 0xbc, 0x58, 0x81, 0x5b, 0xf4, + 0xba, 0x5a, 0xbc, 0x58, 0x11, 0xb7, 0xe8, 0x3d, 0x00, 0x14, 0xf1, 0x38, 0xae, 0x04, 0x5e, 0x44, + 0x29, 0x09, 0x16, 0xb1, 0x21, 0xec, 0x1a, 0xad, 0x8a, 0xb8, 0x14, 0x60, 0x8d, 0xd6, 0x05, 0x70, + 0xae, 0x56, 0xdc, 0x24, 0xe5, 0x76, 0x26, 0x51, 0xbd, 0xc2, 0xc4, 0x5e, 0xca, 0xb2, 0xa4, 0x02, + 0x33, 0x89, 0x6e, 0xf7, 0x46, 0x4a, 0xcc, 0x24, 0x6d, 0x0a, 0x84, 0x92, 0x7e, 0x2e, 0x83, 0xd5, + 0x0e, 0x3c, 0x96, 0xb9, 0x13, 0x42, 0xec, 0xfc, 0xd4, 0x14, 0x7a, 0x27, 0x2e, 0xcb, 0xb4, 0x5e, + 0xfc, 0xd7, 0xf1, 0x02, 0x35, 0x72, 0x62, 0x7e, 0xc2, 0x38, 0x30, 0xbc, 0x9a, 0x89, 0x1b, 0x2b, + 0x18, 0x9c, 0xba, 0xef, 0x06, 0x19, 0x9b, 0x71, 0x4a, 0x89, 0x73, 0x37, 0x00, 0x6b, 0x4d, 0xe4, + 0x6a, 0xc0, 0x7a, 0x17, 0xe6, 0xbc, 0x38, 0x68, 0x5c, 0x1c, 0xf2, 0x2b, 0x36, 0xe5, 0x2f, 0xde, + 0xa4, 0x55, 0xbd, 0x09, 0xd4, 0x2b, 0xf7, 0x33, 0xc2, 0x12, 0x06, 0x13, 0x2f, 0x0e, 0x76, 0x2a, + 0xd9, 0x04, 0x02, 0x94, 0xe5, 0x88, 0xbd, 0x46, 0x13, 0x08, 0x68, 0xd1, 0x70, 0x44, 0x02, 0x11, + 0xe2, 0xed, 0x39, 0x9e, 0x71, 0xae, 0x3f, 0xd9, 0x31, 0xe5, 0x4d, 0x2e, 0x47, 0x59, 0x83, 0x20, + 0x71, 0x94, 0x12, 0x54, 0xb0, 0xfb, 0x4b, 0xe3, 0xdf, 0x0e, 0xb1, 0x07, 0x84, 0x9d, 0xf6, 0x30, + 0x7b, 0xd8, 0x83, 0x44, 0x5c, 0xd9, 0x0b, 0x2e, 0x94, 0xab, 0xf6, 0xfd, 0x96, 0x87, 0x3d, 0x48, + 0xe7, 0x4c, 0xd0, 0xad, 0xd6, 0xf3, 0x78, 0x76, 0x39, 0x2f, 0xf9, 0x32, 0x4f, 0x76, 0x78, 0xc6, + 0x4b, 0x70, 0x26, 0xe8, 0x95, 0x1a, 0xa0, 0xc4, 0x99, 0x60, 0x87, 0x8a, 0xcd, 0xe0, 0xdc, 0x52, + 0x8c, 0xb2, 0x74, 0x0e, 0x77, 0xd4, 0x9e, 0x21, 0x09, 0x10, 0x19, 0x1c, 0x0a, 0x22, 0x41, 0xa4, + 0x76, 0xdc, 0x22, 0x9d, 0xc5, 0x99, 0xf2, 0xb7, 0x4d, 0x9b, 0xf1, 0xc0, 0xce, 0x20, 0x42, 0x14, + 0x90, 0x7a, 0x4e, 0x97, 0x65, 0x3e, 0xce, 0x05, 0x27, 0xeb, 0xd9, 0x00, 0x9d, 0xf5, 0x74, 0x40, + 0x30, 0xad, 0x4e, 0xd9, 0x9b, 0xba, 0x34, 0xf5, 0x3f, 0xd8, 0xb4, 0x5a, 0xff, 0x7d, 0xa8, 0xe5, + 0xa1, 0x69, 0x15, 0x70, 0xa0, 0x32, 0xda, 0x89, 0x0a, 0x98, 0x80, 0xb6, 0x1f, 0x26, 0x0f, 0xba, + 0x41, 0xdc, 0xcf, 0x44, 0xac, 0x32, 0x16, 0xf2, 0x23, 0x81, 0x3e, 0x7e, 0x1a, 0xd0, 0x1e, 0xb7, + 0x78, 0xf5, 0xb9, 0x60, 0xb3, 0xcb, 0xd6, 0x7d, 0x3d, 0xbf, 0xa0, 0x0a, 0x21, 0x8e, 0x5b, 0x08, + 0x14, 0xef, 0xa2, 0xf1, 0x8c, 0xe7, 0xa1, 0x2e, 0xaa, 0xe5, 0x7d, 0xba, 0x48, 0x73, 0x76, 0xf3, + 0x6b, 0xa4, 0x3a, 0x32, 0x55, 0x37, 0x6d, 0x12, 0x16, 0x5c, 0x88, 0xd8, 0xfc, 0x92, 0xb0, 0xcd, + 0xc9, 0xa1, 0xcf, 0xc3, 0xf6, 0xcb, 0x0c, 0x2d, 0x2b, 0x87, 0xf4, 0xcb, 0x0c, 0x14, 0x4b, 0x57, + 0x52, 0xc5, 0x48, 0x87, 0x15, 0x3f, 0x4e, 0x1e, 0xf7, 0x83, 0xed, 0x96, 0xc7, 0xf3, 0xb9, 0x93, + 0xb1, 0xb8, 0x54, 0x5e, 0xb7, 0x02, 0x86, 0x2c, 0x46, 0x6c, 0x79, 0x02, 0x38, 0x98, 0xc2, 0x3c, + 0xcf, 0x3b, 0x3c, 0x17, 0x2c, 0x17, 0xd8, 0x14, 0xe6, 0x1b, 0xd3, 0x60, 0x68, 0x0a, 0xa3, 0x14, + 0x40, 0xdc, 0xca, 0xf3, 0x20, 0x26, 0x8e, 0xe2, 0x05, 0x9a, 0xb1, 0xa9, 0xb3, 0x1e, 0x25, 0x0f, + 0xc5, 0x2d, 0xe0, 0x9c, 0x87, 0xcc, 0xae, 0x97, 0x69, 0x5c, 0xce, 0xcd, 0xe9, 0x46, 0x32, 0x78, + 0x42, 0xdb, 0xf1, 0x49, 0xe2, 0x21, 0x73, 0x58, 0x03, 0x4c, 0x3b, 0xe3, 0x45, 0x3c, 0x37, 0x35, + 0x45, 0x6a, 0x20, 0xe5, 0xad, 0xaa, 0x3e, 0xe8, 0x06, 0x81, 0x9f, 0x97, 0x69, 0xc2, 0x78, 0xc0, + 0x8f, 0x94, 0xf7, 0xf1, 0x03, 0x41, 0x90, 0xbd, 0xd5, 0xf5, 0xd6, 0x1f, 0xd5, 0xca, 0x13, 0xbd, + 0x8f, 0x1d, 0x12, 0xcd, 0x03, 0xb8, 0x50, 0xf6, 0x46, 0xf0, 0x60, 0x8c, 0x36, 0x07, 0xb4, 0xa1, + 0x31, 0x6a, 0xce, 0x5f, 0xfb, 0x8c, 0x51, 0x0c, 0xd6, 0x3e, 0x7f, 0xac, 0xc7, 0xe8, 0x6e, 0x2c, + 0xe2, 0x3a, 0x6f, 0x7f, 0x99, 0xb2, 0xd7, 0x7a, 0x23, 0x8c, 0xd4, 0xb7, 0xa1, 0x86, 0xf2, 0x5d, + 0x6c, 0xb0, 0x2b, 0xde, 0xee, 0xcd, 0x07, 0x7c, 0xeb, 0x1d, 0x42, 0xa7, 0x6f, 0xb0, 0x55, 0xd8, + 0xee, 0xcd, 0x07, 0x7c, 0xeb, 0x4f, 0x57, 0x74, 0xfa, 0x06, 0xdf, 0xaf, 0xd8, 0xee, 0xcd, 0x6b, + 0xdf, 0x7f, 0xd1, 0x0c, 0x5c, 0xd7, 0x79, 0x9d, 0x87, 0xcd, 0x44, 0x7a, 0xc5, 0xb0, 0x74, 0xd2, + 0xb7, 0x67, 0xd0, 0x50, 0x3a, 0x49, 0xab, 0x38, 0x5f, 0xf0, 0xc3, 0x4a, 0x71, 0xcc, 0xab, 0x54, + 0x5e, 0x12, 0x79, 0xd6, 0xc3, 0x68, 0x03, 0x87, 0x36, 0x4d, 0x21, 0x25, 0xfb, 0xb8, 0xdb, 0x43, + 0xed, 0xf5, 0xfc, 0xc7, 0x01, 0x7b, 0xed, 0x5b, 0xfa, 0x5b, 0x3d, 0x69, 0xfb, 0xe0, 0xd9, 0x63, + 0x9a, 0x47, 0x86, 0x13, 0x86, 0xae, 0x12, 0xc6, 0x94, 0x79, 0x94, 0xec, 0x3e, 0x3b, 0x7d, 0xd2, + 0x5f, 0xa1, 0xc3, 0xfd, 0x28, 0x49, 0xfa, 0xb9, 0x77, 0x9f, 0xb9, 0x3f, 0xe9, 0xaf, 0xa0, 0xdd, + 0xff, 0x65, 0xb3, 0xad, 0x81, 0xfe, 0xf5, 0x18, 0x7c, 0xda, 0xc7, 0x22, 0x18, 0x87, 0xcf, 0xae, + 0xa5, 0xa3, 0x0b, 0xf2, 0xb7, 0xcd, 0xfe, 0xbd, 0x41, 0xe5, 0x3b, 0x52, 0xf2, 0xdd, 0x6a, 0x3d, + 0x24, 0x43, 0x51, 0x65, 0x61, 0x38, 0x30, 0x3f, 0xbc, 0xa6, 0x96, 0xf3, 0x39, 0x49, 0x0f, 0xd6, + 0xef, 0xf2, 0x3a, 0xe5, 0x09, 0x59, 0x76, 0x68, 0x58, 0xa0, 0x8f, 0xae, 0xab, 0x46, 0x0d, 0x55, + 0x07, 0x96, 0xdf, 0xf2, 0x79, 0xd6, 0xd3, 0xb0, 0xf7, 0x75, 0x9f, 0x0f, 0xae, 0xa7, 0xa4, 0xcb, + 0xf2, 0x1f, 0x6b, 0xd1, 0x7d, 0x8f, 0xb5, 0x8f, 0x33, 0xc0, 0xa1, 0xcb, 0x0f, 0x02, 0xf6, 0x29, + 0x25, 0x53, 0xb8, 0xdf, 0xfe, 0x7a, 0xca, 0xf6, 0xb3, 0x7f, 0x9e, 0xca, 0x5e, 0x9a, 0x09, 0x56, + 0xb6, 0x3f, 0xfb, 0xe7, 0xdb, 0x55, 0xd4, 0x90, 0xfe, 0xec, 0x5f, 0x00, 0x77, 0x3e, 0xfb, 0x87, + 0x78, 0x46, 0x3f, 0xfb, 0x87, 0x5a, 0x0b, 0x7e, 0xf6, 0x2f, 0xac, 0x41, 0xad, 0x2e, 0x4d, 0x11, + 0xd4, 0xb1, 0x79, 0x2f, 0x8b, 0xfe, 0x29, 0xfa, 0xd3, 0xeb, 0xa8, 0x10, 0xeb, 0xab, 0xe2, 0xe4, + 0x35, 0xcf, 0x1e, 0x6d, 0xea, 0x5d, 0xf5, 0xdc, 0xee, 0xcd, 0x6b, 0xdf, 0x3f, 0xd2, 0x9b, 0x2b, + 0xb3, 0x9a, 0xf0, 0x52, 0x7e, 0xf2, 0x71, 0x33, 0xb4, 0x3a, 0xd4, 0x16, 0xdc, 0x9e, 0x7f, 0xdc, + 0x0f, 0x26, 0xaa, 0x5b, 0x13, 0xba, 0xd3, 0x87, 0x5d, 0x86, 0x40, 0x97, 0x6f, 0xf7, 0xe6, 0x89, + 0x65, 0x44, 0xf9, 0x56, 0xbd, 0xdd, 0xc3, 0x98, 0xdf, 0xd7, 0x4f, 0xfa, 0x2b, 0x68, 0xf7, 0x57, + 0x3a, 0x6b, 0x75, 0xdd, 0xcb, 0x7e, 0xde, 0xea, 0x32, 0x35, 0xf1, 0xba, 0x79, 0xd8, 0x17, 0x0f, + 0xe5, 0x2f, 0xee, 0x12, 0xda, 0x95, 0xbf, 0xa0, 0xcb, 0xe8, 0x07, 0xd7, 0x53, 0xd2, 0x65, 0xf9, + 0x87, 0xb5, 0xe8, 0x26, 0x59, 0x16, 0x1d, 0x07, 0x1f, 0xf5, 0xb5, 0x0c, 0xe2, 0xe1, 0xe3, 0x6b, + 0xeb, 0xe9, 0x42, 0xfd, 0xf3, 0x5a, 0x74, 0x2b, 0x50, 0x28, 0x15, 0x20, 0xd7, 0xb0, 0xee, 0x07, + 0xca, 0x27, 0xd7, 0x57, 0xa4, 0x96, 0x7b, 0x17, 0x9f, 0xb4, 0x3f, 0xe1, 0x16, 0xb0, 0x3d, 0xa1, + 0x3f, 0xe1, 0xd6, 0xad, 0x05, 0xcf, 0x98, 0xe2, 0xb3, 0x66, 0xcf, 0x87, 0x9e, 0x31, 0xc9, 0x0b, + 0x9a, 0xc1, 0x8f, 0xb6, 0x60, 0x1c, 0xe6, 0xe4, 0xc5, 0x9b, 0x22, 0xce, 0x13, 0xda, 0x89, 0x92, + 0x77, 0x3b, 0x31, 0x1c, 0x3c, 0x9b, 0xab, 0xa5, 0x27, 0xbc, 0xd9, 0xc7, 0x3d, 0xa4, 0xf4, 0x0d, + 0x12, 0x3c, 0x9b, 0x6b, 0xa1, 0x84, 0x37, 0x9d, 0x35, 0x86, 0xbc, 0x81, 0x64, 0xf1, 0x51, 0x1f, + 0x14, 0xec, 0x10, 0x8c, 0x37, 0x73, 0xe4, 0xff, 0x38, 0x64, 0xa5, 0x75, 0xec, 0xbf, 0xd5, 0x93, + 0x26, 0xdc, 0x4e, 0x98, 0xf8, 0x94, 0xc5, 0x09, 0x2b, 0x83, 0x6e, 0x0d, 0xd5, 0xcb, 0xad, 0x4b, + 0x63, 0x6e, 0x77, 0x78, 0xb6, 0x5c, 0xe4, 0xba, 0x33, 0x49, 0xb7, 0x2e, 0xd5, 0xed, 0x16, 0xd0, + 0xf0, 0x54, 0xd2, 0xba, 0x95, 0xe9, 0xe5, 0xa3, 0xb0, 0x19, 0x2f, 0xab, 0xdc, 0xec, 0xc5, 0xd2, + 0xf5, 0xd4, 0x61, 0xd4, 0x51, 0x4f, 0x10, 0x49, 0x5b, 0x3d, 0x69, 0x78, 0x3c, 0xe8, 0xb8, 0x35, + 0xf1, 0xb4, 0xdd, 0x61, 0xab, 0x15, 0x52, 0x4f, 0xfa, 0x2b, 0xc0, 0xc3, 0x58, 0x1d, 0x55, 0x07, + 0x69, 0x25, 0xf6, 0xd2, 0x2c, 0x1b, 0x6c, 0x06, 0xc2, 0xa4, 0x81, 0x82, 0x87, 0xb1, 0x08, 0x4c, + 0x44, 0x72, 0x73, 0x78, 0x99, 0x0f, 0xba, 0xec, 0x48, 0xaa, 0x57, 0x24, 0xbb, 0x34, 0x38, 0x50, + 0x73, 0x9a, 0xda, 0xd4, 0x76, 0x18, 0x6e, 0xb8, 0x56, 0x85, 0xb7, 0x7b, 0xf3, 0xe0, 0x69, 0xbf, + 0xa4, 0xe4, 0xca, 0x72, 0x8f, 0x32, 0xe1, 0xad, 0x24, 0xf7, 0x3b, 0x28, 0x70, 0x28, 0xa9, 0x86, + 0xd1, 0xab, 0x34, 0x99, 0x33, 0x81, 0x3e, 0xa8, 0x72, 0x81, 0xe0, 0x83, 0x2a, 0x00, 0x82, 0xae, + 0x53, 0x7f, 0x37, 0xa7, 0xb1, 0xe3, 0x04, 0xeb, 0x3a, 0xad, 0xec, 0x50, 0xa1, 0xae, 0x43, 0x69, + 0x30, 0x1b, 0x18, 0xb7, 0xfa, 0x33, 0x17, 0x8f, 0x42, 0x66, 0xc0, 0xb7, 0x2e, 0x36, 0x7b, 0xb1, + 0x60, 0x45, 0xb1, 0x0e, 0xd3, 0x45, 0x2a, 0xb0, 0x15, 0xc5, 0xb1, 0x51, 0x23, 0xa1, 0x15, 0xa5, + 0x8d, 0x52, 0xd5, 0xab, 0x73, 0x84, 0x71, 0x12, 0xae, 0x9e, 0x62, 0xfa, 0x55, 0xcf, 0xb0, 0xad, + 0xe7, 0xaa, 0xb9, 0x09, 0x19, 0x71, 0xa1, 0x37, 0xcb, 0x48, 0x6c, 0x3b, 0xbf, 0xec, 0x60, 0xc1, + 0xd0, 0xac, 0x43, 0x29, 0xc0, 0xe7, 0x05, 0xcd, 0x6f, 0x41, 0x4c, 0x98, 0x18, 0x15, 0x05, 0x8b, + 0xcb, 0x38, 0x9f, 0xa1, 0x9b, 0x53, 0xf3, 0xdb, 0x0e, 0x1e, 0x19, 0xda, 0x9c, 0x92, 0x1a, 0xe0, + 0xa9, 0xbd, 0xff, 0x7e, 0x31, 0x32, 0x14, 0xcc, 0x8b, 0xbc, 0xfe, 0xeb, 0xc5, 0x0f, 0x7b, 0x90, + 0xf0, 0xa9, 0x7d, 0x03, 0x98, 0x73, 0x77, 0xe5, 0xf4, 0xfd, 0x80, 0x29, 0x1f, 0x0d, 0x6d, 0x84, + 0x69, 0x15, 0x10, 0xd4, 0xce, 0xd9, 0xe2, 0x67, 0x6c, 0x85, 0x05, 0xb5, 0x7b, 0x48, 0xf8, 0x19, + 0x5b, 0x85, 0x82, 0xba, 0x8d, 0x82, 0x3c, 0xd3, 0xdd, 0x07, 0xad, 0x07, 0xf4, 0xdd, 0xad, 0xcf, + 0x46, 0x27, 0x07, 0x46, 0xce, 0x6e, 0x7a, 0xe5, 0x3d, 0xa6, 0x40, 0x0a, 0xba, 0x9b, 0x5e, 0xe1, + 0x4f, 0x29, 0x36, 0x7b, 0xb1, 0xf0, 0x46, 0x40, 0x2c, 0xd8, 0x9b, 0xe6, 0x51, 0x3d, 0x52, 0x5c, + 0x29, 0x6f, 0x3d, 0xab, 0x7f, 0xd0, 0x0d, 0xda, 0xfb, 0xb7, 0xc7, 0x25, 0x9f, 0xb1, 0xaa, 0xd2, + 0x5f, 0x80, 0xf5, 0x2f, 0x38, 0x69, 0xd9, 0x10, 0x7c, 0xff, 0xf5, 0x5e, 0x18, 0x72, 0x3e, 0xdb, + 0xa8, 0x44, 0xf6, 0x6b, 0x52, 0xeb, 0xa8, 0x66, 0xfb, 0x43, 0x52, 0x1b, 0x9d, 0x9c, 0x1d, 0x5e, + 0x5a, 0xea, 0x7e, 0x3e, 0xea, 0x01, 0xaa, 0x8e, 0x7d, 0x39, 0xea, 0x61, 0x0f, 0x52, 0xbb, 0xfa, + 0x34, 0x7a, 0xeb, 0x80, 0xcf, 0x27, 0x2c, 0x4f, 0x06, 0xdf, 0xf3, 0x6f, 0xf0, 0xf2, 0xf9, 0xb0, + 0xfe, 0xb3, 0x31, 0x7a, 0x83, 0x12, 0xdb, 0x3b, 0x88, 0xbb, 0xec, 0x6c, 0x39, 0x9f, 0x88, 0x58, + 0x80, 0x3b, 0x88, 0xf2, 0xef, 0xc3, 0x5a, 0x40, 0xdc, 0x41, 0xf4, 0x00, 0x60, 0x6f, 0x5a, 0x32, + 0x86, 0xda, 0xab, 0x05, 0x41, 0x7b, 0x1a, 0xb0, 0x59, 0x84, 0xb1, 0x57, 0x27, 0xea, 0xf0, 0xce, + 0xa0, 0xd5, 0x91, 0x52, 0x22, 0x8b, 0x68, 0x53, 0x36, 0xb8, 0x55, 0xf5, 0xe5, 0xd7, 0x7c, 0x96, + 0x8b, 0x45, 0x5c, 0xae, 0x40, 0x70, 0xeb, 0x5a, 0x3a, 0x00, 0x11, 0xdc, 0x28, 0x68, 0x47, 0x6d, + 0xd3, 0xcc, 0xb3, 0xcb, 0x7d, 0x5e, 0xf2, 0xa5, 0x48, 0x73, 0x06, 0xbf, 0xe8, 0x62, 0x1a, 0xd4, + 0x65, 0x88, 0x51, 0x4b, 0xb1, 0x36, 0xcb, 0x95, 0x84, 0xba, 0xce, 0x28, 0x3f, 0xb5, 0x5f, 0x09, + 0x5e, 0xc2, 0xc7, 0x99, 0xca, 0x0a, 0x84, 0x88, 0x2c, 0x97, 0x84, 0x41, 0xdf, 0x1f, 0xa7, 0xf9, + 0x1c, 0xed, 0xfb, 0x63, 0xf7, 0xab, 0xca, 0xb7, 0x68, 0xc0, 0x0e, 0x28, 0xd5, 0x68, 0x6a, 0x00, + 0xe8, 0x57, 0x99, 0xd1, 0x46, 0x77, 0x09, 0x62, 0x40, 0xe1, 0x24, 0x70, 0xf5, 0x79, 0xc1, 0x72, + 0x96, 0x34, 0x97, 0xf6, 0x30, 0x57, 0x1e, 0x11, 0x74, 0x05, 0x49, 0x3b, 0x17, 0x49, 0xf9, 0xc9, + 0x32, 0x3f, 0x2e, 0xf9, 0x79, 0x9a, 0xb1, 0x12, 0xcc, 0x45, 0x4a, 0xdd, 0x91, 0x13, 0x73, 0x11, + 0xc6, 0xd9, 0xdb, 0x1f, 0x52, 0xea, 0xfd, 0x5e, 0xc4, 0xb4, 0x8c, 0x67, 0xf0, 0xf6, 0x87, 0xb2, + 0xd1, 0xc6, 0x88, 0x93, 0xc1, 0x00, 0xee, 0x24, 0x3a, 0xca, 0x75, 0xbe, 0x92, 0xf1, 0xa1, 0x5f, + 0xa5, 0x95, 0xdf, 0x1a, 0xae, 0x40, 0xa2, 0xa3, 0xcd, 0x61, 0x24, 0x91, 0xe8, 0x84, 0x35, 0xec, + 0x52, 0x22, 0xb9, 0x23, 0x7d, 0xab, 0x09, 0x2c, 0x25, 0xca, 0x46, 0x23, 0x24, 0x96, 0x92, 0x16, + 0x04, 0x26, 0xa4, 0x66, 0x18, 0xcc, 0xd1, 0x09, 0xc9, 0x48, 0x83, 0x13, 0x92, 0x4b, 0xd9, 0x89, + 0x62, 0x9c, 0xa7, 0x22, 0x8d, 0xb3, 0x09, 0x13, 0xc7, 0x71, 0x19, 0x2f, 0x98, 0x60, 0x25, 0x9c, + 0x28, 0x34, 0x32, 0xf4, 0x18, 0x62, 0xa2, 0xa0, 0x58, 0xed, 0xf0, 0x77, 0xa2, 0x77, 0xea, 0x75, + 0x9f, 0xe5, 0xfa, 0x97, 0xae, 0x5e, 0xc8, 0xdf, 0x29, 0x1c, 0xbc, 0x6b, 0x6c, 0x4c, 0x44, 0xc9, + 0xe2, 0x45, 0x63, 0xfb, 0x6d, 0xf3, 0x77, 0x09, 0x3e, 0x59, 0xab, 0xe3, 0xf9, 0x88, 0x8b, 0xf4, + 0xbc, 0xde, 0x66, 0xeb, 0x17, 0x98, 0x40, 0x3c, 0xbb, 0xe2, 0x61, 0xe0, 0x53, 0x2c, 0x18, 0x67, + 0xe7, 0x69, 0x57, 0x7a, 0xc2, 0x8a, 0x0c, 0xce, 0xd3, 0x9e, 0xb6, 0x04, 0x88, 0x79, 0x1a, 0x05, + 0xed, 0xe0, 0x74, 0xc5, 0x53, 0x16, 0xae, 0xcc, 0x94, 0xf5, 0xab, 0xcc, 0xd4, 0x7b, 0x27, 0x24, + 0x8b, 0xde, 0x39, 0x64, 0x8b, 0x33, 0x56, 0x56, 0x17, 0x69, 0x41, 0x7d, 0x0f, 0xd9, 0x12, 0x9d, + 0xdf, 0x43, 0x26, 0x50, 0xbb, 0x12, 0x58, 0x60, 0x5c, 0x1d, 0xc5, 0x0b, 0x26, 0x3f, 0x2c, 0x03, + 0x56, 0x02, 0xc7, 0x88, 0x03, 0x11, 0x2b, 0x01, 0x09, 0x3b, 0xaf, 0x97, 0x59, 0xe6, 0x84, 0xcd, + 0xeb, 0x08, 0x2b, 0x8f, 0xe3, 0xd5, 0x82, 0xe5, 0x42, 0x9b, 0x04, 0x67, 0xf2, 0x8e, 0x49, 0x9c, + 0x27, 0xce, 0xe4, 0xfb, 0xe8, 0x39, 0x53, 0x93, 0xd7, 0xf0, 0xc7, 0xbc, 0x14, 0xea, 0x27, 0xec, + 0x4e, 0xcb, 0x0c, 0x4c, 0x4d, 0x7e, 0xa3, 0x7a, 0x24, 0x31, 0x35, 0x85, 0x35, 0x9c, 0xdf, 0x2c, + 0xf1, 0xca, 0xf0, 0x92, 0x95, 0x26, 0x4e, 0x5e, 0x2c, 0xe2, 0x34, 0xd3, 0xd1, 0xf0, 0xfd, 0x80, + 0x6d, 0x42, 0x87, 0xf8, 0xcd, 0x92, 0xbe, 0xba, 0xce, 0xaf, 0xbc, 0x84, 0x4b, 0x08, 0x1e, 0x11, + 0x74, 0xd8, 0x27, 0x1e, 0x11, 0x74, 0x6b, 0xd9, 0x9d, 0xbb, 0x65, 0x25, 0xb7, 0x92, 0xc4, 0x0e, + 0x4f, 0xe0, 0x79, 0xa1, 0x63, 0x13, 0x80, 0xc4, 0xce, 0x3d, 0xa8, 0x60, 0x53, 0x03, 0x8b, 0xed, + 0xa5, 0x79, 0x9c, 0xa5, 0x3f, 0x86, 0x69, 0xbd, 0x63, 0xa7, 0x21, 0x88, 0xd4, 0x00, 0x27, 0x31, + 0x57, 0xfb, 0x4c, 0x4c, 0xd3, 0x7a, 0xea, 0x7f, 0x10, 0x68, 0x37, 0x49, 0x74, 0xbb, 0x72, 0x48, + 0xe7, 0xdb, 0xc7, 0xb0, 0x59, 0x47, 0x45, 0x31, 0xa9, 0x57, 0xd5, 0x13, 0x36, 0x63, 0x69, 0x21, + 0x06, 0x1f, 0x86, 0xdb, 0x0a, 0xe0, 0xc4, 0x45, 0x8b, 0x1e, 0x6a, 0xce, 0xe3, 0xfb, 0x7a, 0x2e, + 0x99, 0xa8, 0x5f, 0xd9, 0x3d, 0xad, 0x58, 0xa9, 0x13, 0x8d, 0x7d, 0x26, 0xc0, 0xe8, 0x74, 0xb8, + 0xa1, 0x03, 0xd6, 0x15, 0x25, 0x46, 0x67, 0x58, 0xc3, 0x1e, 0xf6, 0x39, 0x9c, 0xfe, 0x76, 0x80, + 0xbc, 0xee, 0xf8, 0x98, 0x34, 0xe6, 0x50, 0xc4, 0x61, 0x1f, 0x4d, 0xdb, 0x6c, 0xad, 0xed, 0x76, + 0x94, 0xaf, 0xc6, 0xf0, 0xca, 0x04, 0x62, 0x49, 0x62, 0x44, 0xb6, 0x16, 0xc0, 0x9d, 0xc3, 0xf0, + 0x92, 0xc7, 0xc9, 0x2c, 0xae, 0xc4, 0x71, 0xbc, 0xca, 0x78, 0x9c, 0xc8, 0x75, 0x1d, 0x1e, 0x86, + 0x37, 0xcc, 0xd0, 0x85, 0xa8, 0xc3, 0x70, 0x0a, 0x76, 0xb3, 0x33, 0xf9, 0xe3, 0xc1, 0xfa, 0x2a, + 0x29, 0xcc, 0xce, 0x64, 0x79, 0xe1, 0x35, 0xd2, 0x7b, 0x61, 0xc8, 0xbe, 0x02, 0xa7, 0x44, 0x32, + 0x0d, 0xb9, 0x85, 0xe9, 0x78, 0x09, 0xc8, 0xed, 0x00, 0x61, 0x3f, 0xcb, 0xa2, 0xfe, 0xde, 0xfc, + 0x54, 0x99, 0xd0, 0x5f, 0x88, 0x7f, 0x8c, 0xe9, 0xba, 0x90, 0x77, 0x43, 0x6d, 0xab, 0x27, 0x6d, + 0xd3, 0xcc, 0x9d, 0x8b, 0x58, 0x8c, 0x92, 0xe4, 0x90, 0x55, 0xc8, 0xfb, 0xec, 0xb5, 0x70, 0x68, + 0xa5, 0x44, 0x9a, 0xd9, 0xa6, 0x6c, 0xa0, 0xd7, 0xb2, 0x17, 0x49, 0x2a, 0xb4, 0xac, 0xb9, 0xa0, + 0xfd, 0xb8, 0x6d, 0xa0, 0x4d, 0x11, 0xb5, 0xa2, 0x69, 0x3b, 0x97, 0xd7, 0xcc, 0x94, 0xcf, 0xe7, + 0x19, 0xd3, 0xd0, 0x09, 0x8b, 0xd5, 0x07, 0x32, 0xb7, 0xdb, 0xb6, 0x50, 0x90, 0x98, 0xcb, 0x83, + 0x0a, 0x36, 0x8d, 0xac, 0x31, 0xf5, 0x48, 0xaa, 0x69, 0xd8, 0x8d, 0xb6, 0x19, 0x0f, 0x20, 0xd2, + 0x48, 0x14, 0xb4, 0xaf, 0xdd, 0xd5, 0xe2, 0x7d, 0xd6, 0xb4, 0x04, 0xfc, 0x02, 0x97, 0x54, 0x76, + 0xc4, 0xc4, 0x6b, 0x77, 0x08, 0x66, 0xf7, 0x09, 0xc0, 0xc3, 0xf3, 0xd5, 0x38, 0x81, 0xfb, 0x04, + 0xa8, 0x2f, 0x19, 0x62, 0x9f, 0x40, 0xb1, 0x7e, 0xd7, 0x99, 0x73, 0xaf, 0x83, 0xb8, 0xb2, 0x95, + 0x43, 0xba, 0x0e, 0x05, 0x43, 0x5d, 0x47, 0x29, 0xf8, 0x4d, 0xea, 0x1e, 0xad, 0x21, 0x4d, 0x8a, + 0x9d, 0xab, 0xad, 0x77, 0x61, 0x36, 0xf7, 0xaf, 0x85, 0x27, 0x2c, 0x4e, 0x4c, 0xc5, 0x10, 0x5d, + 0x57, 0x4e, 0xe4, 0xfe, 0x18, 0xa7, 0x9d, 0xfc, 0x7e, 0x34, 0x50, 0xd5, 0x28, 0x5d, 0x37, 0xb7, + 0xb0, 0x22, 0xd6, 0x04, 0x31, 0x51, 0xf9, 0x84, 0x93, 0xb8, 0x79, 0x5d, 0x34, 0xe5, 0xda, 0x81, + 0x7e, 0x2d, 0xb4, 0x02, 0x89, 0x9b, 0xdf, 0xec, 0x2d, 0x9a, 0x48, 0xdc, 0xba, 0xb5, 0x9c, 0x8f, + 0x11, 0x81, 0x2e, 0xdb, 0x2b, 0xf9, 0x02, 0x96, 0xe9, 0x93, 0x60, 0xf7, 0x20, 0x1a, 0xc4, 0xc7, + 0x88, 0xfa, 0x69, 0xda, 0x35, 0xc8, 0x9c, 0x1d, 0xc8, 0xeb, 0x69, 0xf8, 0xaf, 0xa0, 0x28, 0x21, + 0xb1, 0x06, 0xb5, 0x20, 0xfb, 0x1e, 0x72, 0x13, 0x47, 0xa3, 0x2c, 0x1b, 0xdc, 0xc6, 0x43, 0xc3, + 0xfd, 0xc0, 0xc3, 0x9d, 0x10, 0xe2, 0xfc, 0xf0, 0xeb, 0xf8, 0x55, 0x99, 0x8a, 0x34, 0x9f, 0x4f, + 0x39, 0xcf, 0xe0, 0x41, 0xe8, 0x68, 0x3c, 0x74, 0xa5, 0xd4, 0x0f, 0xbf, 0xb6, 0x28, 0xbb, 0x70, + 0x8e, 0xc6, 0xa3, 0xa5, 0xe0, 0xe7, 0x69, 0x96, 0x81, 0x78, 0x1c, 0x8d, 0x87, 0x8d, 0x84, 0x88, + 0x47, 0x9f, 0x70, 0x7e, 0xae, 0x74, 0x2c, 0x9f, 0x29, 0xe8, 0x73, 0xd5, 0xbb, 0x50, 0xc7, 0x11, + 0x52, 0x3f, 0x57, 0x0a, 0x21, 0xe7, 0xe7, 0x57, 0xc7, 0xd8, 0x0f, 0xc4, 0x6c, 0x42, 0x75, 0x04, + 0xa2, 0x7e, 0x7e, 0x95, 0x82, 0x9d, 0x37, 0x9d, 0x8f, 0x97, 0xd5, 0x85, 0x7f, 0x10, 0xa1, 0xb6, + 0x9c, 0xea, 0x63, 0xb0, 0xcf, 0xc0, 0xcf, 0x14, 0xf9, 0xec, 0xd0, 0x83, 0x89, 0x4b, 0x6f, 0x9d, + 0x4a, 0xaa, 0x30, 0xcf, 0x6f, 0xff, 0xf7, 0x97, 0x37, 0xd6, 0x7e, 0xf6, 0xe5, 0x8d, 0xb5, 0xff, + 0xfd, 0xf2, 0xc6, 0xda, 0x4f, 0xbf, 0xba, 0xf1, 0x8d, 0x9f, 0x7d, 0x75, 0xe3, 0x1b, 0xff, 0xf3, + 0xd5, 0x8d, 0x6f, 0x7c, 0xf1, 0x56, 0xa5, 0x32, 0xbe, 0xb3, 0x9f, 0x2f, 0x4a, 0x2e, 0xf8, 0xb3, + 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xf4, 0x6f, 0x9e, 0xb4, 0xc9, 0x82, 0x00, 0x00, } // This is a compile-time assertion to ensure that this generated file @@ -406,6 +411,9 @@ type ClientCommandsHandler interface { WalletConvert(context.Context, *pb.RpcWalletConvertRequest) *pb.RpcWalletConvertResponse AccountLocalLinkNewChallenge(context.Context, *pb.RpcAccountLocalLinkNewChallengeRequest) *pb.RpcAccountLocalLinkNewChallengeResponse AccountLocalLinkSolveChallenge(context.Context, *pb.RpcAccountLocalLinkSolveChallengeRequest) *pb.RpcAccountLocalLinkSolveChallengeResponse + AccountLocalLinkCreateApp(context.Context, *pb.RpcAccountLocalLinkCreateAppRequest) *pb.RpcAccountLocalLinkCreateAppResponse + AccountLocalLinkListApps(context.Context, *pb.RpcAccountLocalLinkListAppsRequest) *pb.RpcAccountLocalLinkListAppsResponse + AccountLocalLinkRevokeApp(context.Context, *pb.RpcAccountLocalLinkRevokeAppRequest) *pb.RpcAccountLocalLinkRevokeAppResponse WalletCreateSession(context.Context, *pb.RpcWalletCreateSessionRequest) *pb.RpcWalletCreateSessionResponse WalletCloseSession(context.Context, *pb.RpcWalletCloseSessionRequest) *pb.RpcWalletCloseSessionResponse // Workspace @@ -440,6 +448,7 @@ type ClientCommandsHandler interface { // *** SpaceDelete(context.Context, *pb.RpcSpaceDeleteRequest) *pb.RpcSpaceDeleteResponse SpaceInviteGenerate(context.Context, *pb.RpcSpaceInviteGenerateRequest) *pb.RpcSpaceInviteGenerateResponse + SpaceInviteChange(context.Context, *pb.RpcSpaceInviteChangeRequest) *pb.RpcSpaceInviteChangeResponse SpaceInviteGetCurrent(context.Context, *pb.RpcSpaceInviteGetCurrentRequest) *pb.RpcSpaceInviteGetCurrentResponse SpaceInviteGetGuest(context.Context, *pb.RpcSpaceInviteGetGuestRequest) *pb.RpcSpaceInviteGetGuestResponse SpaceInviteRevoke(context.Context, *pb.RpcSpaceInviteRevokeRequest) *pb.RpcSpaceInviteRevokeResponse @@ -748,6 +757,7 @@ type ClientCommandsHandler interface { ChatSubscribeToMessagePreviews(context.Context, *pb.RpcChatSubscribeToMessagePreviewsRequest) *pb.RpcChatSubscribeToMessagePreviewsResponse ChatUnsubscribeFromMessagePreviews(context.Context, *pb.RpcChatUnsubscribeFromMessagePreviewsRequest) *pb.RpcChatUnsubscribeFromMessagePreviewsResponse ObjectChatAdd(context.Context, *pb.RpcObjectChatAddRequest) *pb.RpcObjectChatAddResponse + ChatReadAll(context.Context, *pb.RpcChatReadAllRequest) *pb.RpcChatReadAllResponse // mock AI RPCs for compatibility between branches. Not implemented in main AIWritingTools(context.Context, *pb.RpcAIWritingToolsRequest) *pb.RpcAIWritingToolsResponse AIAutofill(context.Context, *pb.RpcAIAutofillRequest) *pb.RpcAIAutofillResponse @@ -921,6 +931,66 @@ func AccountLocalLinkSolveChallenge(b []byte) (resp []byte) { return resp } +func AccountLocalLinkCreateApp(b []byte) (resp []byte) { + defer func() { + if PanicHandler != nil { + if r := recover(); r != nil { + resp, _ = (&pb.RpcAccountLocalLinkCreateAppResponse{Error: &pb.RpcAccountLocalLinkCreateAppResponseError{Code: pb.RpcAccountLocalLinkCreateAppResponseError_UNKNOWN_ERROR, Description: "panic recovered"}}).Marshal() + PanicHandler(r) + } + } + }() + + in := new(pb.RpcAccountLocalLinkCreateAppRequest) + if err := in.Unmarshal(b); err != nil { + resp, _ = (&pb.RpcAccountLocalLinkCreateAppResponse{Error: &pb.RpcAccountLocalLinkCreateAppResponseError{Code: pb.RpcAccountLocalLinkCreateAppResponseError_BAD_INPUT, Description: err.Error()}}).Marshal() + return resp + } + + resp, _ = clientCommandsHandler.AccountLocalLinkCreateApp(context.Background(), in).Marshal() + return resp +} + +func AccountLocalLinkListApps(b []byte) (resp []byte) { + defer func() { + if PanicHandler != nil { + if r := recover(); r != nil { + resp, _ = (&pb.RpcAccountLocalLinkListAppsResponse{Error: &pb.RpcAccountLocalLinkListAppsResponseError{Code: pb.RpcAccountLocalLinkListAppsResponseError_UNKNOWN_ERROR, Description: "panic recovered"}}).Marshal() + PanicHandler(r) + } + } + }() + + in := new(pb.RpcAccountLocalLinkListAppsRequest) + if err := in.Unmarshal(b); err != nil { + resp, _ = (&pb.RpcAccountLocalLinkListAppsResponse{Error: &pb.RpcAccountLocalLinkListAppsResponseError{Code: pb.RpcAccountLocalLinkListAppsResponseError_BAD_INPUT, Description: err.Error()}}).Marshal() + return resp + } + + resp, _ = clientCommandsHandler.AccountLocalLinkListApps(context.Background(), in).Marshal() + return resp +} + +func AccountLocalLinkRevokeApp(b []byte) (resp []byte) { + defer func() { + if PanicHandler != nil { + if r := recover(); r != nil { + resp, _ = (&pb.RpcAccountLocalLinkRevokeAppResponse{Error: &pb.RpcAccountLocalLinkRevokeAppResponseError{Code: pb.RpcAccountLocalLinkRevokeAppResponseError_UNKNOWN_ERROR, Description: "panic recovered"}}).Marshal() + PanicHandler(r) + } + } + }() + + in := new(pb.RpcAccountLocalLinkRevokeAppRequest) + if err := in.Unmarshal(b); err != nil { + resp, _ = (&pb.RpcAccountLocalLinkRevokeAppResponse{Error: &pb.RpcAccountLocalLinkRevokeAppResponseError{Code: pb.RpcAccountLocalLinkRevokeAppResponseError_BAD_INPUT, Description: err.Error()}}).Marshal() + return resp + } + + resp, _ = clientCommandsHandler.AccountLocalLinkRevokeApp(context.Background(), in).Marshal() + return resp +} + func WalletCreateSession(b []byte) (resp []byte) { defer func() { if PanicHandler != nil { @@ -1481,6 +1551,26 @@ func SpaceInviteGenerate(b []byte) (resp []byte) { return resp } +func SpaceInviteChange(b []byte) (resp []byte) { + defer func() { + if PanicHandler != nil { + if r := recover(); r != nil { + resp, _ = (&pb.RpcSpaceInviteChangeResponse{Error: &pb.RpcSpaceInviteChangeResponseError{Code: pb.RpcSpaceInviteChangeResponseError_UNKNOWN_ERROR, Description: "panic recovered"}}).Marshal() + PanicHandler(r) + } + } + }() + + in := new(pb.RpcSpaceInviteChangeRequest) + if err := in.Unmarshal(b); err != nil { + resp, _ = (&pb.RpcSpaceInviteChangeResponse{Error: &pb.RpcSpaceInviteChangeResponseError{Code: pb.RpcSpaceInviteChangeResponseError_BAD_INPUT, Description: err.Error()}}).Marshal() + return resp + } + + resp, _ = clientCommandsHandler.SpaceInviteChange(context.Background(), in).Marshal() + return resp +} + func SpaceInviteGetCurrent(b []byte) (resp []byte) { defer func() { if PanicHandler != nil { @@ -6521,6 +6611,26 @@ func ObjectChatAdd(b []byte) (resp []byte) { return resp } +func ChatReadAll(b []byte) (resp []byte) { + defer func() { + if PanicHandler != nil { + if r := recover(); r != nil { + resp, _ = (&pb.RpcChatReadAllResponse{Error: &pb.RpcChatReadAllResponseError{Code: pb.RpcChatReadAllResponseError_UNKNOWN_ERROR, Description: "panic recovered"}}).Marshal() + PanicHandler(r) + } + } + }() + + in := new(pb.RpcChatReadAllRequest) + if err := in.Unmarshal(b); err != nil { + resp, _ = (&pb.RpcChatReadAllResponse{Error: &pb.RpcChatReadAllResponseError{Code: pb.RpcChatReadAllResponseError_BAD_INPUT, Description: err.Error()}}).Marshal() + return resp + } + + resp, _ = clientCommandsHandler.ChatReadAll(context.Background(), in).Marshal() + return resp +} + func AIWritingTools(b []byte) (resp []byte) { defer func() { if PanicHandler != nil { @@ -6643,6 +6753,12 @@ func CommandAsync(cmd string, data []byte, callback func(data []byte)) { cd = AccountLocalLinkNewChallenge(data) case "AccountLocalLinkSolveChallenge": cd = AccountLocalLinkSolveChallenge(data) + case "AccountLocalLinkCreateApp": + cd = AccountLocalLinkCreateApp(data) + case "AccountLocalLinkListApps": + cd = AccountLocalLinkListApps(data) + case "AccountLocalLinkRevokeApp": + cd = AccountLocalLinkRevokeApp(data) case "WalletCreateSession": cd = WalletCreateSession(data) case "WalletCloseSession": @@ -6699,6 +6815,8 @@ func CommandAsync(cmd string, data []byte, callback func(data []byte)) { cd = SpaceDelete(data) case "SpaceInviteGenerate": cd = SpaceInviteGenerate(data) + case "SpaceInviteChange": + cd = SpaceInviteChange(data) case "SpaceInviteGetCurrent": cd = SpaceInviteGetCurrent(data) case "SpaceInviteGetGuest": @@ -7203,6 +7321,8 @@ func CommandAsync(cmd string, data []byte, callback func(data []byte)) { cd = ChatUnsubscribeFromMessagePreviews(data) case "ObjectChatAdd": cd = ObjectChatAdd(data) + case "ChatReadAll": + cd = ChatReadAll(data) case "AIWritingTools": cd = AIWritingTools(data) case "AIAutofill": @@ -7347,6 +7467,48 @@ func (h *ClientCommandsHandlerProxy) AccountLocalLinkSolveChallenge(ctx context. call, _ := actualCall(ctx, req) return call.(*pb.RpcAccountLocalLinkSolveChallengeResponse) } +func (h *ClientCommandsHandlerProxy) AccountLocalLinkCreateApp(ctx context.Context, req *pb.RpcAccountLocalLinkCreateAppRequest) *pb.RpcAccountLocalLinkCreateAppResponse { + actualCall := func(ctx context.Context, req any) (any, error) { + return h.client.AccountLocalLinkCreateApp(ctx, req.(*pb.RpcAccountLocalLinkCreateAppRequest)), nil + } + for _, interceptor := range h.interceptors { + toCall := actualCall + currentInterceptor := interceptor + actualCall = func(ctx context.Context, req any) (any, error) { + return currentInterceptor(ctx, req, "AccountLocalLinkCreateApp", toCall) + } + } + call, _ := actualCall(ctx, req) + return call.(*pb.RpcAccountLocalLinkCreateAppResponse) +} +func (h *ClientCommandsHandlerProxy) AccountLocalLinkListApps(ctx context.Context, req *pb.RpcAccountLocalLinkListAppsRequest) *pb.RpcAccountLocalLinkListAppsResponse { + actualCall := func(ctx context.Context, req any) (any, error) { + return h.client.AccountLocalLinkListApps(ctx, req.(*pb.RpcAccountLocalLinkListAppsRequest)), nil + } + for _, interceptor := range h.interceptors { + toCall := actualCall + currentInterceptor := interceptor + actualCall = func(ctx context.Context, req any) (any, error) { + return currentInterceptor(ctx, req, "AccountLocalLinkListApps", toCall) + } + } + call, _ := actualCall(ctx, req) + return call.(*pb.RpcAccountLocalLinkListAppsResponse) +} +func (h *ClientCommandsHandlerProxy) AccountLocalLinkRevokeApp(ctx context.Context, req *pb.RpcAccountLocalLinkRevokeAppRequest) *pb.RpcAccountLocalLinkRevokeAppResponse { + actualCall := func(ctx context.Context, req any) (any, error) { + return h.client.AccountLocalLinkRevokeApp(ctx, req.(*pb.RpcAccountLocalLinkRevokeAppRequest)), nil + } + for _, interceptor := range h.interceptors { + toCall := actualCall + currentInterceptor := interceptor + actualCall = func(ctx context.Context, req any) (any, error) { + return currentInterceptor(ctx, req, "AccountLocalLinkRevokeApp", toCall) + } + } + call, _ := actualCall(ctx, req) + return call.(*pb.RpcAccountLocalLinkRevokeAppResponse) +} func (h *ClientCommandsHandlerProxy) WalletCreateSession(ctx context.Context, req *pb.RpcWalletCreateSessionRequest) *pb.RpcWalletCreateSessionResponse { actualCall := func(ctx context.Context, req any) (any, error) { return h.client.WalletCreateSession(ctx, req.(*pb.RpcWalletCreateSessionRequest)), nil @@ -7739,6 +7901,20 @@ func (h *ClientCommandsHandlerProxy) SpaceInviteGenerate(ctx context.Context, re call, _ := actualCall(ctx, req) return call.(*pb.RpcSpaceInviteGenerateResponse) } +func (h *ClientCommandsHandlerProxy) SpaceInviteChange(ctx context.Context, req *pb.RpcSpaceInviteChangeRequest) *pb.RpcSpaceInviteChangeResponse { + actualCall := func(ctx context.Context, req any) (any, error) { + return h.client.SpaceInviteChange(ctx, req.(*pb.RpcSpaceInviteChangeRequest)), nil + } + for _, interceptor := range h.interceptors { + toCall := actualCall + currentInterceptor := interceptor + actualCall = func(ctx context.Context, req any) (any, error) { + return currentInterceptor(ctx, req, "SpaceInviteChange", toCall) + } + } + call, _ := actualCall(ctx, req) + return call.(*pb.RpcSpaceInviteChangeResponse) +} func (h *ClientCommandsHandlerProxy) SpaceInviteGetCurrent(ctx context.Context, req *pb.RpcSpaceInviteGetCurrentRequest) *pb.RpcSpaceInviteGetCurrentResponse { actualCall := func(ctx context.Context, req any) (any, error) { return h.client.SpaceInviteGetCurrent(ctx, req.(*pb.RpcSpaceInviteGetCurrentRequest)), nil @@ -11267,6 +11443,20 @@ func (h *ClientCommandsHandlerProxy) ObjectChatAdd(ctx context.Context, req *pb. call, _ := actualCall(ctx, req) return call.(*pb.RpcObjectChatAddResponse) } +func (h *ClientCommandsHandlerProxy) ChatReadAll(ctx context.Context, req *pb.RpcChatReadAllRequest) *pb.RpcChatReadAllResponse { + actualCall := func(ctx context.Context, req any) (any, error) { + return h.client.ChatReadAll(ctx, req.(*pb.RpcChatReadAllRequest)), nil + } + for _, interceptor := range h.interceptors { + toCall := actualCall + currentInterceptor := interceptor + actualCall = func(ctx context.Context, req any) (any, error) { + return currentInterceptor(ctx, req, "ChatReadAll", toCall) + } + } + call, _ := actualCall(ctx, req) + return call.(*pb.RpcChatReadAllResponse) +} func (h *ClientCommandsHandlerProxy) AIWritingTools(ctx context.Context, req *pb.RpcAIWritingToolsRequest) *pb.RpcAIWritingToolsResponse { actualCall := func(ctx context.Context, req any) (any, error) { return h.client.AIWritingTools(ctx, req.(*pb.RpcAIWritingToolsRequest)), nil diff --git a/cmd/grpcserver/grpc.go b/cmd/grpcserver/grpc.go index 827fd3c39..7b9af97ec 100644 --- a/cmd/grpcserver/grpc.go +++ b/cmd/grpcserver/grpc.go @@ -38,6 +38,7 @@ import ( "github.com/anyproto/anytype-heart/pb/service" "github.com/anyproto/anytype-heart/pkg/lib/logging" "github.com/anyproto/anytype-heart/util/conc" + "github.com/anyproto/anytype-heart/util/grpcprocess" "github.com/anyproto/anytype-heart/util/vcs" ) @@ -180,6 +181,9 @@ func main() { } unaryInterceptors = appendInterceptor(unaryInterceptors, mw) + unaryInterceptors = append(unaryInterceptors, grpcprocess.ProcessInfoInterceptor( + "/anytype.ClientCommands/AccountLocalLinkNewChallenge", + )) server := grpc.NewServer(grpc.MaxRecvMsgSize(20*1024*1024), grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(unaryInterceptors...)), diff --git a/core/account.go b/core/account.go index b1296c39b..d5d94996b 100644 --- a/core/account.go +++ b/core/account.go @@ -4,13 +4,14 @@ import ( "context" "github.com/anyproto/any-sync/net" - "google.golang.org/grpc/peer" "github.com/anyproto/anytype-heart/core/anytype/config" "github.com/anyproto/anytype-heart/core/application" "github.com/anyproto/anytype-heart/core/session" + walletComp "github.com/anyproto/anytype-heart/core/wallet" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/space/spacecore/storage/migrator" + "github.com/anyproto/anytype-heart/util/grpcprocess" ) func (mw *Middleware) AccountCreate(cctx context.Context, req *pb.RpcAccountCreateRequest) *pb.RpcAccountCreateResponse { @@ -248,7 +249,7 @@ func (mw *Middleware) AccountChangeJsonApiAddr(ctx context.Context, req *pb.RpcA func (mw *Middleware) AccountLocalLinkNewChallenge(ctx context.Context, request *pb.RpcAccountLocalLinkNewChallengeRequest) *pb.RpcAccountLocalLinkNewChallengeResponse { info := getClientInfo(ctx) - + info.Name = request.AppName challengeId, err := mw.applicationService.LinkLocalStartNewChallenge(request.Scope, &info) code := mapErrorCode(err, errToCode(session.ErrTooManyChallengeRequests, pb.RpcAccountLocalLinkNewChallengeResponseError_TOO_MANY_REQUESTS), @@ -282,16 +283,56 @@ func (mw *Middleware) AccountLocalLinkSolveChallenge(_ context.Context, req *pb. } } +func (mw *Middleware) AccountLocalLinkCreateApp(_ context.Context, req *pb.RpcAccountLocalLinkCreateAppRequest) *pb.RpcAccountLocalLinkCreateAppResponse { + appKey, err := mw.applicationService.LinkLocalCreateApp(req) + code := mapErrorCode(err, + errToCode(application.ErrApplicationIsNotRunning, pb.RpcAccountLocalLinkCreateAppResponseError_ACCOUNT_IS_NOT_RUNNING), + ) + return &pb.RpcAccountLocalLinkCreateAppResponse{ + AppKey: appKey, + Error: &pb.RpcAccountLocalLinkCreateAppResponseError{ + Code: code, + Description: getErrorDescription(err), + }, + } +} + +func (mw *Middleware) AccountLocalLinkListApps(_ context.Context, req *pb.RpcAccountLocalLinkListAppsRequest) *pb.RpcAccountLocalLinkListAppsResponse { + apps, err := mw.applicationService.LinkLocalListApps() + code := mapErrorCode(err, + errToCode(application.ErrApplicationIsNotRunning, pb.RpcAccountLocalLinkListAppsResponseError_ACCOUNT_IS_NOT_RUNNING), + ) + + return &pb.RpcAccountLocalLinkListAppsResponse{ + App: apps, + Error: &pb.RpcAccountLocalLinkListAppsResponseError{ + Code: code, + Description: getErrorDescription(err), + }, + } +} + +func (mw *Middleware) AccountLocalLinkRevokeApp(_ context.Context, req *pb.RpcAccountLocalLinkRevokeAppRequest) *pb.RpcAccountLocalLinkRevokeAppResponse { + err := mw.applicationService.LinkLocalRevokeApp(req) + code := mapErrorCode(err, + errToCode(walletComp.ErrAppLinkNotFound, pb.RpcAccountLocalLinkRevokeAppResponseError_NOT_FOUND), + errToCode(application.ErrApplicationIsNotRunning, pb.RpcAccountLocalLinkRevokeAppResponseError_ACCOUNT_IS_NOT_RUNNING), + ) + return &pb.RpcAccountLocalLinkRevokeAppResponse{ + Error: &pb.RpcAccountLocalLinkRevokeAppResponseError{ + Code: code, + Description: getErrorDescription(err), + }, + } +} + func getClientInfo(ctx context.Context) pb.EventAccountLinkChallengeClientInfo { - p, ok := peer.FromContext(ctx) + info, ok := grpcprocess.FromContext(ctx) if !ok { return pb.EventAccountLinkChallengeClientInfo{} } - - // todo: get process info return pb.EventAccountLinkChallengeClientInfo{ - ProcessName: p.Addr.String(), - ProcessPath: "", - SignatureVerified: false, + ProcessName: info.Name, + ProcessPath: info.Path, } } diff --git a/core/acl/aclservice.go b/core/acl/aclservice.go index 30df9d270..99af7b824 100644 --- a/core/acl/aclservice.go +++ b/core/acl/aclservice.go @@ -9,7 +9,9 @@ import ( "github.com/anyproto/any-sync/app" "github.com/anyproto/any-sync/commonspace/acl/aclclient" + "github.com/anyproto/any-sync/commonspace/object/acl/aclrecordproto" "github.com/anyproto/any-sync/commonspace/object/acl/list" + "github.com/anyproto/any-sync/commonspace/object/acl/recordverifier" "github.com/anyproto/any-sync/coordinator/coordinatorclient" "github.com/anyproto/any-sync/coordinator/coordinatorproto" "github.com/anyproto/any-sync/identityrepo/identityrepoproto" @@ -45,7 +47,8 @@ type AccountPermissions struct { type AclService interface { app.Component - GenerateInvite(ctx context.Context, spaceId string) (domain.InviteInfo, error) + GenerateInvite(ctx context.Context, spaceId string, inviteType model.InviteType, permissions model.ParticipantPermissions) (domain.InviteInfo, error) + ChangeInvite(ctx context.Context, spaceId string, permissions model.ParticipantPermissions) error RevokeInvite(ctx context.Context, spaceId string) error GetCurrentInvite(ctx context.Context, spaceId string) (domain.InviteInfo, error) GetGuestUserInvite(ctx context.Context, spaceId string) (domain.InviteInfo, error) @@ -82,6 +85,7 @@ type aclService struct { accountService account.Service coordClient coordinatorclient.CoordinatorClient identityRepo identityRepoClient + recordVerifier recordverifier.AcceptorVerifier } func (a *aclService) Init(ap *app.App) (err error) { @@ -92,6 +96,7 @@ func (a *aclService) Init(ap *app.App) (err error) { a.inviteService = app.MustComponent[inviteservice.InviteService](ap) a.coordClient = app.MustComponent[coordinatorclient.CoordinatorClient](ap) a.identityRepo = app.MustComponent[identityRepoClient](ap) + a.recordVerifier = recordverifier.New() return nil } @@ -398,47 +403,76 @@ func (a *aclService) Join(ctx context.Context, spaceId, networkId string, invite if err != nil { return convertedOrInternalError("get invite payload", err) } - if invitePayload.InviteType == model.InvitePayload_JoinAsGuest { + switch invitePayload.InviteType { + case model.InviteType_Guest: guestKey, err := crypto.UnmarshalEd25519PrivateKeyProto(invitePayload.GuestKey) if err != nil { return convertedOrInternalError("unmarshal invite key", err) } return a.joinAsGuest(ctx, invitePayload.SpaceId, guestKey) - } - inviteKey, err := crypto.UnmarshalEd25519PrivateKeyProto(invitePayload.AclKey) - if err != nil { - return convertedOrInternalError("unmarshal invite key", err) - } - aclHeadId, err := a.joiningClient.RequestJoin(ctx, spaceId, list.RequestJoinPayload{ - InviteKey: inviteKey, - Metadata: a.spaceService.AccountMetadataPayload(), - }) - if err != nil { - if errors.Is(err, coordinatorproto.ErrSpaceIsDeleted) { - return space.ErrSpaceDeleted + case model.InviteType_Member: + inviteKey, err := crypto.UnmarshalEd25519PrivateKeyProto(invitePayload.AclKey) + if err != nil { + return convertedOrInternalError("unmarshal invite key", err) } - if errors.Is(err, list.ErrInsufficientPermissions) { - err = a.joiningClient.CancelRemoveSelf(ctx, spaceId) - if err != nil { - return convertedOrAclRequestError(err) + aclHeadId, err := a.joiningClient.RequestJoin(ctx, spaceId, list.RequestJoinPayload{ + InviteKey: inviteKey, + Metadata: a.spaceService.AccountMetadataPayload(), + }) + // nolint: nestif + if err != nil { + if errors.Is(err, coordinatorproto.ErrSpaceIsDeleted) { + return space.ErrSpaceDeleted } - err = a.spaceService.CancelLeave(ctx, spaceId) - if err != nil { - return convertedOrInternalError("cancel leave", err) + if errors.Is(err, list.ErrInsufficientPermissions) { + err = a.joiningClient.CancelRemoveSelf(ctx, spaceId) + if err != nil { + return convertedOrAclRequestError(err) + } + err = a.spaceService.CancelLeave(ctx, spaceId) + if err != nil { + return convertedOrInternalError("cancel leave", err) + } } + return convertedOrAclRequestError(err) + } + err = a.spaceService.Join(ctx, spaceId, aclHeadId) + if err != nil { + return convertedOrInternalError("join space", err) + } + err = a.spaceService.TechSpace().SpaceViewSetData(ctx, spaceId, + domain.NewDetails(). + SetString(bundle.RelationKeyName, invitePayload.SpaceName). + SetString(bundle.RelationKeyIconImage, invitePayload.SpaceIconCid)) + if err != nil { + return convertedOrInternalError("set space data", err) + } + case model.InviteType_WithoutApprove: + inviteKey, err := crypto.UnmarshalEd25519PrivateKeyProto(invitePayload.AclKey) + if err != nil { + return convertedOrInternalError("unmarshal invite key", err) + } + aclHeadId, err := a.joiningClient.InviteJoin(ctx, spaceId, list.InviteJoinPayload{ + InviteKey: inviteKey, + Metadata: a.spaceService.AccountMetadataPayload(), + }) + if err != nil { + if errors.Is(err, coordinatorproto.ErrSpaceIsDeleted) { + return space.ErrSpaceDeleted + } + return convertedOrAclRequestError(err) + } + err = a.spaceService.InviteJoin(ctx, spaceId, aclHeadId) + if err != nil { + return convertedOrInternalError("join space", err) + } + err = a.spaceService.TechSpace().SpaceViewSetData(ctx, spaceId, + domain.NewDetails(). + SetString(bundle.RelationKeyName, invitePayload.SpaceName). + SetString(bundle.RelationKeyIconImage, invitePayload.SpaceIconCid)) + if err != nil { + return convertedOrInternalError("set space data", err) } - return convertedOrAclRequestError(err) - } - err = a.spaceService.Join(ctx, spaceId, aclHeadId) - if err != nil { - return convertedOrInternalError("join space", err) - } - err = a.spaceService.TechSpace().SpaceViewSetData(ctx, spaceId, - domain.NewDetails(). - SetString(bundle.RelationKeyName, invitePayload.SpaceName). - SetString(bundle.RelationKeyIconImage, invitePayload.SpaceIconCid)) - if err != nil { - return convertedOrInternalError("set space data", err) } return nil } @@ -472,12 +506,12 @@ func (a *aclService) ViewInvite(ctx context.Context, inviteCid cid.Cid, inviteFi if err != nil { return domain.InviteView{}, convertedOrAclRequestError(err) } - lst, err := list.BuildAclListWithIdentity(a.accountService.Keys(), store, list.NoOpAcceptorVerifier{}) + lst, err := list.BuildAclListWithIdentity(a.accountService.Keys(), store, a.recordVerifier) if err != nil { return domain.InviteView{}, convertedOrAclRequestError(err) } for _, inv := range lst.AclState().Invites() { - if inviteKey.GetPublic().Equals(inv) { + if inviteKey.GetPublic().Equals(inv.Key) { return res, nil } } @@ -533,26 +567,82 @@ func (a *aclService) GetCurrentInvite(ctx context.Context, spaceId string) (doma return a.inviteService.GetCurrent(ctx, spaceId) } -func (a *aclService) GenerateInvite(ctx context.Context, spaceId string) (result domain.InviteInfo, err error) { +func (a *aclService) ChangeInvite(ctx context.Context, spaceId string, permissions model.ParticipantPermissions) (err error) { if spaceId == a.accountService.PersonalSpaceID() { err = ErrPersonalSpace return } current, err := a.inviteService.GetCurrent(ctx, spaceId) if err == nil { - return current, nil + if current.InviteType != domain.InviteTypeAnyone { + return inviteservice.ErrInviteNotExists + } + } + acceptSpace, err := a.spaceService.Get(ctx, spaceId) + if err != nil { + return convertedOrSpaceErr(err) + } + aclClient := acceptSpace.CommonSpace().AclClient() + acl := acceptSpace.CommonSpace().Acl() + acl.RLock() + invites := acl.AclState().Invites(aclrecordproto.AclInviteType_AnyoneCanJoin) + if len(invites) == 0 { + acl.RUnlock() + return inviteservice.ErrInviteNotExists + } + acl.RUnlock() + var ( + invite = invites[0] + invitePermissions = domain.ConvertParticipantPermissions(permissions) + ) + if invite.Permissions == invitePermissions { + return ErrIncorrectPermissions + } + err = aclClient.ChangeInvite(ctx, invites[0].Id, invitePermissions) + if err != nil { + return convertedOrAclRequestError(err) + } + err = a.inviteService.Change(ctx, spaceId, invitePermissions) + if err != nil { + return convertedOrInternalError("change invite", err) + } + return nil +} + +func (a *aclService) GenerateInvite(ctx context.Context, spaceId string, invType model.InviteType, permissions model.ParticipantPermissions) (result domain.InviteInfo, err error) { + if spaceId == a.accountService.PersonalSpaceID() { + err = ErrPersonalSpace + return + } + var ( + inviteExists = false + inviteType = domain.InviteType(invType) + ) + current, err := a.inviteService.GetCurrent(ctx, spaceId) + if err == nil { + inviteExists = true + if current.InviteType == inviteType { + return current, nil + } } acceptSpace, err := a.spaceService.Get(ctx, spaceId) if err != nil { return } aclClient := acceptSpace.CommonSpace().AclClient() - res, err := aclClient.GenerateInvite() + aclPermissions := domain.ConvertParticipantPermissions(permissions) + res, err := aclClient.GenerateInvite(inviteExists, inviteType == domain.InviteTypeDefault, aclPermissions) if err != nil { err = convertedOrInternalError("couldn't generate acl invite", err) return } - return a.inviteService.Generate(ctx, spaceId, res.InviteKey, func() error { + params := inviteservice.GenerateInviteParams{ + SpaceId: spaceId, + Key: res.InviteKey, + InviteType: inviteType, + Permissions: aclPermissions, + } + return a.inviteService.Generate(ctx, params, func() error { err := aclClient.AddRecord(ctx, res.InviteRec) if err != nil { return convertedOrAclRequestError(err) diff --git a/core/acl/aclservice_test.go b/core/acl/aclservice_test.go index 627997f98..39af82587 100644 --- a/core/acl/aclservice_test.go +++ b/core/acl/aclservice_test.go @@ -11,12 +11,15 @@ import ( "github.com/anyproto/any-sync/commonspace/acl/aclclient/mock_aclclient" "github.com/anyproto/any-sync/commonspace/mock_commonspace" "github.com/anyproto/any-sync/commonspace/object/accountdata" + "github.com/anyproto/any-sync/commonspace/object/acl/aclrecordproto" "github.com/anyproto/any-sync/commonspace/object/acl/list" "github.com/anyproto/any-sync/commonspace/object/acl/list/mock_list" + "github.com/anyproto/any-sync/commonspace/object/acl/recordverifier" "github.com/anyproto/any-sync/commonspace/object/acl/syncacl/headupdater" "github.com/anyproto/any-sync/commonspace/spacesyncproto" "github.com/anyproto/any-sync/commonspace/sync/syncdeps" "github.com/anyproto/any-sync/commonspace/syncstatus" + "github.com/anyproto/any-sync/consensus/consensusproto" "github.com/anyproto/any-sync/coordinator/coordinatorclient/mock_coordinatorclient" "github.com/anyproto/any-sync/coordinator/coordinatorproto" "github.com/anyproto/any-sync/net/peer" @@ -108,6 +111,7 @@ func newFixture(t *testing.T) *fixture { Register(fx.mockConfig). Register(fx.aclService) require.NoError(t, fx.a.Start(ctx)) + fx.aclService.recordVerifier = recordverifier.NewValidateFull() return fx } @@ -365,7 +369,7 @@ func TestService_ViewInvite(t *testing.T) { InviteRevokes: invRecIds, }) require.NoError(t, err) - err = aclList.AddRawRecord(list.WrapAclRecord(removeInv)) + err = aclList.AddRawRecord(list.WrapAclRecord(removeInv.Rec)) require.NoError(t, err) recs, err := aclList.RecordsAfter(ctx, "") require.NoError(t, err) @@ -387,6 +391,192 @@ func TestService_ViewInvite(t *testing.T) { }) } +func TestService_ChangeInvite(t *testing.T) { + t.Run("change invite", func(t *testing.T) { + fx := newFixture(t) + defer fx.finish(t) + spaceId := "spaceId" + fx.mockAccountService.EXPECT().PersonalSpaceID().Return("personal") + mockSpace := mock_clientspace.NewMockSpace(t) + mockCommonSpace := mock_commonspace.NewMockSpace(fx.ctrl) + fx.mockInviteService.EXPECT().GetCurrent(ctx, spaceId).Return(domain.InviteInfo{ + InviteType: domain.InviteTypeAnyone, + InviteFileCid: "testCid", + }, nil) + fx.mockSpaceService.EXPECT().Get(ctx, spaceId).Return(mockSpace, nil) + mockSpace.EXPECT().CommonSpace().Return(mockCommonSpace) + exec := list.NewAclExecutor(spaceId) + type cmdErr struct { + cmd string + err error + } + cmds := []cmdErr{ + {"a.init::a", nil}, + {"a.invite_anyone::invId,r", nil}, + } + for _, cmd := range cmds { + err := exec.Execute(cmd.cmd) + require.Equal(t, cmd.err, err, cmd) + } + acl := mockSyncAcl{exec.ActualAccounts()["a"].Acl} + invId := acl.AclState().Invites(aclrecordproto.AclInviteType_AnyoneCanJoin)[0].Id + mockCommonSpace.EXPECT().Acl().Return(acl) + aclClient := mock_aclclient.NewMockAclSpaceClient(fx.ctrl) + mockCommonSpace.EXPECT().AclClient().Return(aclClient) + aclClient.EXPECT().ChangeInvite(ctx, invId, list.AclPermissionsWriter).Return(nil) + fx.mockInviteService.EXPECT().Change(ctx, spaceId, list.AclPermissionsWriter).Return(nil) + err := fx.ChangeInvite(ctx, spaceId, model.ParticipantPermissions_Writer) + require.NoError(t, err) + }) + t.Run("different invite type", func(t *testing.T) { + fx := newFixture(t) + defer fx.finish(t) + spaceId := "spaceId" + fx.mockAccountService.EXPECT().PersonalSpaceID().Return("personal") + fx.mockInviteService.EXPECT().GetCurrent(ctx, spaceId).Return(domain.InviteInfo{ + InviteType: domain.InviteTypeDefault, + InviteFileCid: "testCid", + }, nil) + err := fx.ChangeInvite(ctx, spaceId, model.ParticipantPermissions_Writer) + require.Equal(t, inviteservice.ErrInviteNotExists, err) + }) +} + +func TestService_GenerateInvite(t *testing.T) { + t.Run("new default invite", func(t *testing.T) { + fx := newFixture(t) + defer fx.finish(t) + spaceId := "spaceId" + keys, err := accountdata.NewRandom() + require.NoError(t, err) + fx.mockAccountService.EXPECT().PersonalSpaceID().Return("personal") + fx.mockInviteService.EXPECT().GetCurrent(ctx, spaceId).Return(domain.InviteInfo{}, inviteservice.ErrInviteNotExists) + mockSpace := mock_clientspace.NewMockSpace(t) + mockCommonSpace := mock_commonspace.NewMockSpace(fx.ctrl) + mockAclClient := mock_aclclient.NewMockAclSpaceClient(fx.ctrl) + mockSpace.EXPECT().CommonSpace().Return(mockCommonSpace) + mockCommonSpace.EXPECT().AclClient().Return(mockAclClient) + fx.mockSpaceService.EXPECT().Get(ctx, spaceId).Return(mockSpace, nil) + rec := &consensusproto.RawRecord{ + Payload: []byte("test"), + } + mockAclClient.EXPECT().GenerateInvite(false, true, list.AclPermissionsReader). + Return(list.InviteResult{ + InviteRec: rec, + InviteKey: keys.SignKey, + }, nil) + params := inviteservice.GenerateInviteParams{ + SpaceId: spaceId, + InviteType: domain.InviteTypeDefault, + Key: keys.SignKey, + Permissions: list.AclPermissionsReader, + } + mockAclClient.EXPECT().AddRecord(ctx, rec).Return(nil) + fx.mockInviteService.EXPECT().Generate(ctx, params, mock.Anything). + RunAndReturn(func(ctx2 context.Context, params inviteservice.GenerateInviteParams, f func() error) (domain.InviteInfo, error) { + return domain.InviteInfo{ + InviteFileCid: "testCid", + }, f() + }) + info, err := fx.GenerateInvite(ctx, spaceId, model.InviteType_Member, model.ParticipantPermissions_Reader) + require.NoError(t, err) + require.Equal(t, "testCid", info.InviteFileCid) + }) + t.Run("new anyone can join invite", func(t *testing.T) { + fx := newFixture(t) + defer fx.finish(t) + spaceId := "spaceId" + keys, err := accountdata.NewRandom() + require.NoError(t, err) + fx.mockAccountService.EXPECT().PersonalSpaceID().Return("personal") + fx.mockInviteService.EXPECT().GetCurrent(ctx, spaceId).Return(domain.InviteInfo{}, inviteservice.ErrInviteNotExists) + mockSpace := mock_clientspace.NewMockSpace(t) + mockCommonSpace := mock_commonspace.NewMockSpace(fx.ctrl) + mockAclClient := mock_aclclient.NewMockAclSpaceClient(fx.ctrl) + mockSpace.EXPECT().CommonSpace().Return(mockCommonSpace) + mockCommonSpace.EXPECT().AclClient().Return(mockAclClient) + fx.mockSpaceService.EXPECT().Get(ctx, spaceId).Return(mockSpace, nil) + rec := &consensusproto.RawRecord{ + Payload: []byte("test"), + } + mockAclClient.EXPECT().GenerateInvite(false, false, list.AclPermissionsReader). + Return(list.InviteResult{ + InviteRec: rec, + InviteKey: keys.SignKey, + }, nil) + params := inviteservice.GenerateInviteParams{ + SpaceId: spaceId, + InviteType: domain.InviteTypeAnyone, + Key: keys.SignKey, + Permissions: list.AclPermissionsReader, + } + mockAclClient.EXPECT().AddRecord(ctx, rec).Return(nil) + fx.mockInviteService.EXPECT().Generate(ctx, params, mock.Anything). + RunAndReturn(func(ctx2 context.Context, params inviteservice.GenerateInviteParams, f func() error) (domain.InviteInfo, error) { + return domain.InviteInfo{ + InviteFileCid: "testCid", + }, f() + }) + info, err := fx.GenerateInvite(ctx, spaceId, model.InviteType_WithoutApprove, model.ParticipantPermissions_Reader) + require.NoError(t, err) + require.Equal(t, "testCid", info.InviteFileCid) + }) + t.Run("anyone can join invite after default invite", func(t *testing.T) { + fx := newFixture(t) + defer fx.finish(t) + spaceId := "spaceId" + keys, err := accountdata.NewRandom() + require.NoError(t, err) + fx.mockAccountService.EXPECT().PersonalSpaceID().Return("personal") + fx.mockInviteService.EXPECT().GetCurrent(ctx, spaceId).Return(domain.InviteInfo{ + InviteType: domain.InviteTypeDefault, + }, nil) + mockSpace := mock_clientspace.NewMockSpace(t) + mockCommonSpace := mock_commonspace.NewMockSpace(fx.ctrl) + mockAclClient := mock_aclclient.NewMockAclSpaceClient(fx.ctrl) + mockSpace.EXPECT().CommonSpace().Return(mockCommonSpace) + mockCommonSpace.EXPECT().AclClient().Return(mockAclClient) + fx.mockSpaceService.EXPECT().Get(ctx, spaceId).Return(mockSpace, nil) + rec := &consensusproto.RawRecord{ + Payload: []byte("test"), + } + mockAclClient.EXPECT().GenerateInvite(true, false, list.AclPermissionsReader). + Return(list.InviteResult{ + InviteRec: rec, + InviteKey: keys.SignKey, + }, nil) + params := inviteservice.GenerateInviteParams{ + SpaceId: spaceId, + InviteType: domain.InviteTypeAnyone, + Key: keys.SignKey, + Permissions: list.AclPermissionsReader, + } + mockAclClient.EXPECT().AddRecord(ctx, rec).Return(nil) + fx.mockInviteService.EXPECT().Generate(ctx, params, mock.Anything). + RunAndReturn(func(ctx2 context.Context, params inviteservice.GenerateInviteParams, f func() error) (domain.InviteInfo, error) { + return domain.InviteInfo{ + InviteFileCid: "testCid", + }, f() + }) + info, err := fx.GenerateInvite(ctx, spaceId, model.InviteType_WithoutApprove, model.ParticipantPermissions_Reader) + require.NoError(t, err) + require.Equal(t, "testCid", info.InviteFileCid) + }) + t.Run("invite already exists", func(t *testing.T) { + fx := newFixture(t) + defer fx.finish(t) + spaceId := "spaceId" + fx.mockAccountService.EXPECT().PersonalSpaceID().Return("personal") + fx.mockInviteService.EXPECT().GetCurrent(ctx, spaceId).Return(domain.InviteInfo{ + InviteType: domain.InviteTypeAnyone, + InviteFileCid: "testCid", + }, nil) + info, err := fx.GenerateInvite(ctx, spaceId, model.InviteType_WithoutApprove, model.ParticipantPermissions_Reader) + require.NoError(t, err) + require.Equal(t, "testCid", info.InviteFileCid) + }) +} + func TestService_Join(t *testing.T) { t.Run("join success", func(t *testing.T) { fx := newFixture(t) @@ -468,6 +658,35 @@ func TestService_Join(t *testing.T) { err = fx.Join(ctx, "spaceId", "", realCid, key) require.NoError(t, err) }) + t.Run("join success without approve", func(t *testing.T) { + fx := newFixture(t) + defer fx.finish(t) + cidString, err := cidutil.NewCidFromBytes([]byte("spaceId")) + require.NoError(t, err) + realCid, err := cid.Decode(cidString) + require.NoError(t, err) + key, err := crypto.NewRandomAES() + require.NoError(t, err) + inviteKey, _, err := crypto.GenerateRandomEd25519KeyPair() + require.NoError(t, err) + protoKey, err := inviteKey.Marshall() + require.NoError(t, err) + fx.mockInviteService.EXPECT().GetPayload(ctx, realCid, key).Return(&model.InvitePayload{ + AclKey: protoKey, + InviteType: model.InviteType_WithoutApprove, + }, nil) + metadataPayload := []byte("metadata") + fx.mockSpaceService.EXPECT().AccountMetadataPayload().Return(metadataPayload) + fx.mockJoiningClient.EXPECT().InviteJoin(ctx, "spaceId", list.InviteJoinPayload{ + InviteKey: inviteKey, + Metadata: metadataPayload, + }).Return("aclHeadId", nil) + fx.mockSpaceService.EXPECT().InviteJoin(ctx, "spaceId", "aclHeadId").Return(nil) + fx.mockSpaceService.EXPECT().TechSpace().Return(&clientspace.TechSpace{TechSpace: fx.mockTechSpace}) + fx.mockTechSpace.EXPECT().SpaceViewSetData(ctx, "spaceId", mock.Anything).Return(nil) + err = fx.Join(ctx, "spaceId", "", realCid, key) + require.NoError(t, err) + }) t.Run("join fail, different network", func(t *testing.T) { // given fx := newFixture(t) diff --git a/core/anytype/bootstrap.go b/core/anytype/bootstrap.go index 0ec5d9456..ca10ee62a 100644 --- a/core/anytype/bootstrap.go +++ b/core/anytype/bootstrap.go @@ -41,6 +41,8 @@ import ( "github.com/anyproto/anytype-heart/core/block/bookmark" decorator "github.com/anyproto/anytype-heart/core/block/bookmark/bookmarkimporter" "github.com/anyproto/anytype-heart/core/block/chats" + "github.com/anyproto/anytype-heart/core/block/chats/chatrepository" + "github.com/anyproto/anytype-heart/core/block/chats/chatsubscription" "github.com/anyproto/anytype-heart/core/block/collection" "github.com/anyproto/anytype-heart/core/block/dataviewservice" "github.com/anyproto/anytype-heart/core/block/detailservice" @@ -264,6 +266,8 @@ func Bootstrap(a *app.App, components ...app.Component) { Register(files.New()). Register(fileoffloader.New()). Register(fileacl.New()). + Register(chatrepository.New()). + Register(chatsubscription.New()). Register(chats.New()). Register(sourceimpl.New()). Register(spacefactory.New()). diff --git a/core/anytype/config/config.go b/core/anytype/config/config.go index 1892258a8..1c90428e4 100644 --- a/core/anytype/config/config.go +++ b/core/anytype/config/config.go @@ -490,7 +490,7 @@ func (c *Config) GetNetworkMode() pb.RpcAccountNetworkMode { func (c *Config) GetPublishServer() publishclient.Config { publishPeerId := "12D3KooWEQPgbxGPvkny8kikS3zqfziM7JsQBnJHXHL9ByCcATs7" - publishAddr := "load-balancer.anytype.io:4940" + publishAddr := "anytype-publish-server.anytype.io:4940" if peerId := os.Getenv("ANYTYPE_PUBLISH_PEERID"); peerId != "" { if addr := os.Getenv("ANYTYPE_PUBLISH_ADDRESS"); addr != "" { @@ -510,8 +510,8 @@ func (c *Config) GetPublishServer() publishclient.Config { } func (c *Config) GetPushConfig() PushConfig { - pushPeerId := "12D3KooWR8Ci1XidFCCXoZppGrUmiy4D1Mjoux9xK6QoZrpbQC3J" - pushAddr := "stage1-anytype-push-server1.toolpad.org:4940" + pushPeerId := "12D3KooWMATrdteJNq2YvYhtq3RDeWxq6RVXDAr36MsGd5RJzXDn" + pushAddr := "anytype-push-server.anytype.io:4941" if peerId := os.Getenv("ANYTYPE_PUSH_PEERID"); peerId != "" { if addr := os.Getenv("ANYTYPE_PUSH_ADDRESS"); addr != "" { diff --git a/core/api/core/core.go b/core/api/core/core.go index 3c3ef1099..2155c0939 100644 --- a/core/api/core/core.go +++ b/core/api/core/core.go @@ -11,8 +11,8 @@ type AccountService interface { GetInfo(ctx context.Context) (*model.AccountInfo, error) } -type ExportService interface { - ExportSingleInMemory(ctx context.Context, spaceId string, objectId string, format model.ExportFormat) (res string, err error) +type EventService interface { + Broadcast(event *pb.Event) } type ClientCommands interface { @@ -39,7 +39,7 @@ type ClientCommands interface { ObjectSearchUnsubscribe(context.Context, *pb.RpcObjectSearchUnsubscribeRequest) *pb.RpcObjectSearchUnsubscribeResponse ObjectSetDetails(context.Context, *pb.RpcObjectSetDetailsRequest) *pb.RpcObjectSetDetailsResponse ObjectSetIsArchived(context.Context, *pb.RpcObjectSetIsArchivedRequest) *pb.RpcObjectSetIsArchivedResponse - ObjectListExport(context.Context, *pb.RpcObjectListExportRequest) *pb.RpcObjectListExportResponse + ObjectExport(context.Context, *pb.RpcObjectExportRequest) *pb.RpcObjectExportResponse // Type ObjectCreateObjectType(context.Context, *pb.RpcObjectCreateObjectTypeRequest) *pb.RpcObjectCreateObjectTypeResponse diff --git a/core/api/core/mock_apicore/mock_ClientCommands.go b/core/api/core/mock_apicore/mock_ClientCommands.go index f25a2e232..dba9a67b8 100644 --- a/core/api/core/mock_apicore/mock_ClientCommands.go +++ b/core/api/core/mock_apicore/mock_ClientCommands.go @@ -561,51 +561,51 @@ func (_c *MockClientCommands_ObjectCreateRelationOption_Call) RunAndReturn(run f return _c } -// ObjectListExport provides a mock function with given fields: _a0, _a1 -func (_m *MockClientCommands) ObjectListExport(_a0 context.Context, _a1 *pb.RpcObjectListExportRequest) *pb.RpcObjectListExportResponse { +// ObjectExport provides a mock function with given fields: _a0, _a1 +func (_m *MockClientCommands) ObjectExport(_a0 context.Context, _a1 *pb.RpcObjectExportRequest) *pb.RpcObjectExportResponse { ret := _m.Called(_a0, _a1) if len(ret) == 0 { - panic("no return value specified for ObjectListExport") + panic("no return value specified for ObjectExport") } - var r0 *pb.RpcObjectListExportResponse - if rf, ok := ret.Get(0).(func(context.Context, *pb.RpcObjectListExportRequest) *pb.RpcObjectListExportResponse); ok { + var r0 *pb.RpcObjectExportResponse + if rf, ok := ret.Get(0).(func(context.Context, *pb.RpcObjectExportRequest) *pb.RpcObjectExportResponse); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*pb.RpcObjectListExportResponse) + r0 = ret.Get(0).(*pb.RpcObjectExportResponse) } } return r0 } -// MockClientCommands_ObjectListExport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ObjectListExport' -type MockClientCommands_ObjectListExport_Call struct { +// MockClientCommands_ObjectExport_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ObjectExport' +type MockClientCommands_ObjectExport_Call struct { *mock.Call } -// ObjectListExport is a helper method to define mock.On call +// ObjectExport is a helper method to define mock.On call // - _a0 context.Context -// - _a1 *pb.RpcObjectListExportRequest -func (_e *MockClientCommands_Expecter) ObjectListExport(_a0 interface{}, _a1 interface{}) *MockClientCommands_ObjectListExport_Call { - return &MockClientCommands_ObjectListExport_Call{Call: _e.mock.On("ObjectListExport", _a0, _a1)} +// - _a1 *pb.RpcObjectExportRequest +func (_e *MockClientCommands_Expecter) ObjectExport(_a0 interface{}, _a1 interface{}) *MockClientCommands_ObjectExport_Call { + return &MockClientCommands_ObjectExport_Call{Call: _e.mock.On("ObjectExport", _a0, _a1)} } -func (_c *MockClientCommands_ObjectListExport_Call) Run(run func(_a0 context.Context, _a1 *pb.RpcObjectListExportRequest)) *MockClientCommands_ObjectListExport_Call { +func (_c *MockClientCommands_ObjectExport_Call) Run(run func(_a0 context.Context, _a1 *pb.RpcObjectExportRequest)) *MockClientCommands_ObjectExport_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*pb.RpcObjectListExportRequest)) + run(args[0].(context.Context), args[1].(*pb.RpcObjectExportRequest)) }) return _c } -func (_c *MockClientCommands_ObjectListExport_Call) Return(_a0 *pb.RpcObjectListExportResponse) *MockClientCommands_ObjectListExport_Call { +func (_c *MockClientCommands_ObjectExport_Call) Return(_a0 *pb.RpcObjectExportResponse) *MockClientCommands_ObjectExport_Call { _c.Call.Return(_a0) return _c } -func (_c *MockClientCommands_ObjectListExport_Call) RunAndReturn(run func(context.Context, *pb.RpcObjectListExportRequest) *pb.RpcObjectListExportResponse) *MockClientCommands_ObjectListExport_Call { +func (_c *MockClientCommands_ObjectExport_Call) RunAndReturn(run func(context.Context, *pb.RpcObjectExportRequest) *pb.RpcObjectExportResponse) *MockClientCommands_ObjectExport_Call { _c.Call.Return(run) return _c } diff --git a/core/api/core/mock_apicore/mock_EventService.go b/core/api/core/mock_apicore/mock_EventService.go new file mode 100644 index 000000000..c342114ba --- /dev/null +++ b/core/api/core/mock_apicore/mock_EventService.go @@ -0,0 +1,68 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_apicore + +import ( + pb "github.com/anyproto/anytype-heart/pb" + mock "github.com/stretchr/testify/mock" +) + +// MockEventService is an autogenerated mock type for the EventService type +type MockEventService struct { + mock.Mock +} + +type MockEventService_Expecter struct { + mock *mock.Mock +} + +func (_m *MockEventService) EXPECT() *MockEventService_Expecter { + return &MockEventService_Expecter{mock: &_m.Mock} +} + +// Broadcast provides a mock function with given fields: event +func (_m *MockEventService) Broadcast(event *pb.Event) { + _m.Called(event) +} + +// MockEventService_Broadcast_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Broadcast' +type MockEventService_Broadcast_Call struct { + *mock.Call +} + +// Broadcast is a helper method to define mock.On call +// - event *pb.Event +func (_e *MockEventService_Expecter) Broadcast(event interface{}) *MockEventService_Broadcast_Call { + return &MockEventService_Broadcast_Call{Call: _e.mock.On("Broadcast", event)} +} + +func (_c *MockEventService_Broadcast_Call) Run(run func(event *pb.Event)) *MockEventService_Broadcast_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*pb.Event)) + }) + return _c +} + +func (_c *MockEventService_Broadcast_Call) Return() *MockEventService_Broadcast_Call { + _c.Call.Return() + return _c +} + +func (_c *MockEventService_Broadcast_Call) RunAndReturn(run func(*pb.Event)) *MockEventService_Broadcast_Call { + _c.Call.Return(run) + return _c +} + +// NewMockEventService creates a new instance of MockEventService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockEventService(t interface { + mock.TestingT + Cleanup(func()) +}) *MockEventService { + mock := &MockEventService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/api/core/mock_apicore/mock_ExportService.go b/core/api/core/mock_apicore/mock_ExportService.go deleted file mode 100644 index 03c40c5a5..000000000 --- a/core/api/core/mock_apicore/mock_ExportService.go +++ /dev/null @@ -1,96 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mock_apicore - -import ( - context "context" - - model "github.com/anyproto/anytype-heart/pkg/lib/pb/model" - mock "github.com/stretchr/testify/mock" -) - -// MockExportService is an autogenerated mock type for the ExportService type -type MockExportService struct { - mock.Mock -} - -type MockExportService_Expecter struct { - mock *mock.Mock -} - -func (_m *MockExportService) EXPECT() *MockExportService_Expecter { - return &MockExportService_Expecter{mock: &_m.Mock} -} - -// ExportSingleInMemory provides a mock function with given fields: ctx, spaceId, objectId, format -func (_m *MockExportService) ExportSingleInMemory(ctx context.Context, spaceId string, objectId string, format model.ExportFormat) (string, error) { - ret := _m.Called(ctx, spaceId, objectId, format) - - if len(ret) == 0 { - panic("no return value specified for ExportSingleInMemory") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, model.ExportFormat) (string, error)); ok { - return rf(ctx, spaceId, objectId, format) - } - if rf, ok := ret.Get(0).(func(context.Context, string, string, model.ExportFormat) string); ok { - r0 = rf(ctx, spaceId, objectId, format) - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func(context.Context, string, string, model.ExportFormat) error); ok { - r1 = rf(ctx, spaceId, objectId, format) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockExportService_ExportSingleInMemory_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ExportSingleInMemory' -type MockExportService_ExportSingleInMemory_Call struct { - *mock.Call -} - -// ExportSingleInMemory is a helper method to define mock.On call -// - ctx context.Context -// - spaceId string -// - objectId string -// - format model.ExportFormat -func (_e *MockExportService_Expecter) ExportSingleInMemory(ctx interface{}, spaceId interface{}, objectId interface{}, format interface{}) *MockExportService_ExportSingleInMemory_Call { - return &MockExportService_ExportSingleInMemory_Call{Call: _e.mock.On("ExportSingleInMemory", ctx, spaceId, objectId, format)} -} - -func (_c *MockExportService_ExportSingleInMemory_Call) Run(run func(ctx context.Context, spaceId string, objectId string, format model.ExportFormat)) *MockExportService_ExportSingleInMemory_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(model.ExportFormat)) - }) - return _c -} - -func (_c *MockExportService_ExportSingleInMemory_Call) Return(res string, err error) *MockExportService_ExportSingleInMemory_Call { - _c.Call.Return(res, err) - return _c -} - -func (_c *MockExportService_ExportSingleInMemory_Call) RunAndReturn(run func(context.Context, string, string, model.ExportFormat) (string, error)) *MockExportService_ExportSingleInMemory_Call { - _c.Call.Return(run) - return _c -} - -// NewMockExportService creates a new instance of MockExportService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockExportService(t interface { - mock.TestingT - Cleanup(func()) -}) *MockExportService { - mock := &MockExportService{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/core/api/docs/docs.go b/core/api/docs/docs.go index ba601807b..e77cd9c9e 100644 --- a/core/api/docs/docs.go +++ b/core/api/docs/docs.go @@ -6,21 +6,21 @@ import "github.com/swaggo/swag/v2" const docTemplate = `{ "schemes": {{ marshal .Schemes }}, - "components": {"schemas":{"apimodel.CheckboxPropertyLinkValue":{"properties":{"checkbox":{"description":"The checkbox value of the property","example":true,"type":"boolean"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"done","type":"string"}},"type":"object"},"apimodel.CheckboxPropertyValue":{"properties":{"checkbox":{"description":"The checkbox value of the property","example":true,"type":"boolean"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"done","type":"string"},"name":{"description":"The name of the property","example":"Done","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.Color":{"description":"The color of the icon","enum":["grey","yellow","orange","red","pink","purple","blue","ice","teal","lime"],"example":"yellow","type":"string","x-enum-varnames":["ColorGrey","ColorYellow","ColorOrange","ColorRed","ColorPink","ColorPurple","ColorBlue","ColorIce","ColorTeal","ColorLime"]},"apimodel.CreateObjectRequest":{"properties":{"body":{"description":"The body of the object","example":"This is the body of the object. Markdown syntax is supported here.","type":"string"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"name":{"description":"The name of the object","example":"My object","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set on the object","items":{"$ref":"#/components/schemas/apimodel.PropertyLinkWithValue"},"type":"array","uniqueItems":false},"template_id":{"description":"The id of the template to use","example":"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge","type":"string"},"type_key":{"description":"The key of the type of object to create","example":"page","type":"string"}},"required":["type_key"],"type":"object"},"apimodel.CreatePropertyRequest":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"}},"required":["format","name"],"type":"object"},"apimodel.CreateSpaceRequest":{"properties":{"description":{"description":"The description of the space","example":"The local-first wiki","type":"string"},"name":{"description":"The name of the space","example":"New Space","type":"string"}},"required":["name"],"type":"object"},"apimodel.CreateTagRequest":{"properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"name":{"description":"The name of the tag","example":"In progress","type":"string"}},"required":["color","name"],"type":"object"},"apimodel.CreateTypeRequest":{"properties":{"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"layout":{"$ref":"#/components/schemas/apimodel.TypeLayout"},"name":{"description":"The name of the type","example":"Page","type":"string"},"plural_name":{"description":"The plural name of the type","example":"Pages","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties linked to the type","items":{"$ref":"#/components/schemas/apimodel.PropertyLink"},"type":"array","uniqueItems":false}},"required":["layout","name"],"type":"object"},"apimodel.DatePropertyLinkValue":{"properties":{"date":{"description":"The date value of the property","example":"2025-02-14T12:34:56Z","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"last_modified_date","type":"string"}},"type":"object"},"apimodel.DatePropertyValue":{"properties":{"date":{"description":"The date value of the property","example":"2025-02-14T12:34:56Z","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"last_modified_date","type":"string"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.DisplayCodeResponse":{"properties":{"challenge_id":{"description":"The challenge id associated with the displayed code and needed to solve the challenge for token","example":"67647f5ecda913e9a2e11b26","type":"string"}},"type":"object"},"apimodel.EmailPropertyLinkValue":{"properties":{"email":{"description":"The email value of the property","example":"example@example.com","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"email","type":"string"}},"type":"object"},"apimodel.EmailPropertyValue":{"properties":{"email":{"description":"The email value of the property","example":"example@example.com","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"email","type":"string"},"name":{"description":"The name of the property","example":"Email","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.EmojiIcon":{"properties":{"emoji":{"description":"The emoji of the icon","example":"📄","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.IconFormat"}},"type":"object"},"apimodel.FileIcon":{"properties":{"file":{"description":"The file of the icon","example":"bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.IconFormat"}},"type":"object"},"apimodel.FilesPropertyLinkValue":{"properties":{"files":{"description":"The file values of the property","example":["['fileId']"],"items":{"type":"string"},"type":"array","uniqueItems":false},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"files","type":"string"}},"type":"object"},"apimodel.FilesPropertyValue":{"properties":{"files":{"description":"The file values of the property","example":["['fileId']"],"items":{"type":"string"},"type":"array","uniqueItems":false},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"files","type":"string"},"name":{"description":"The name of the property","example":"Files","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.Filter":{"properties":{"condition":{"description":"The filter condition","enum":["equal","not_equal","greater","less","greater_or_equal","less_or_equal","like","not_like","in","not_in","empty","not_empty","all_in","not_all_in","exact_in","not_exact_in","exists"],"example":"contains","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the filter","example":"67bf3f21cda9134102e2422c","type":"string"},"property_key":{"description":"The property key used for filtering","example":"name","type":"string"},"value":{"description":"The value used for filtering","example":"Some value...","type":"string"}},"type":"object"},"apimodel.Icon":{"description":"The icon of the object","oneOf":[{"$ref":"#/components/schemas/apimodel.EmojiIcon"},{"$ref":"#/components/schemas/apimodel.FileIcon"},{"$ref":"#/components/schemas/apimodel.NamedIcon"}],"type":"object"},"apimodel.IconFormat":{"description":"The format of the icon","enum":["icon"],"type":"string","x-enum-varnames":["IconFormatEmoji","IconFormatFile","IconFormatIcon"]},"apimodel.Member":{"description":"The member","properties":{"global_name":{"description":"The global name of the member in the network","example":"john.any","type":"string"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The profile object id of the member","example":"_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ","type":"string"},"identity":{"description":"The identity of the member in the network","example":"AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ","type":"string"},"name":{"description":"The name of the member","example":"John Doe","type":"string"},"object":{"description":"The data model of the object","example":"member","type":"string"},"role":{"description":"The role of the member","enum":["viewer","editor","owner","no_permission"],"example":"owner","type":"string"},"status":{"description":"The status of the member","enum":["joining","active","removed","declined","removing","canceled"],"example":"active","type":"string"}},"type":"object"},"apimodel.MemberResponse":{"properties":{"member":{"$ref":"#/components/schemas/apimodel.Member"}},"type":"object"},"apimodel.MultiSelectPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"tag","type":"string"},"multi_select":{"description":"The selected tag values of the property","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.MultiSelectPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"tag","type":"string"},"multi_select":{"description":"The selected tag values of the property","items":{"$ref":"#/components/schemas/apimodel.Tag"},"type":"array","uniqueItems":false},"name":{"description":"The name of the property","example":"Tag","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.NamedIcon":{"properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"format":{"$ref":"#/components/schemas/apimodel.IconFormat"},"name":{"description":"The name of the icon","example":"document","type":"string"}},"type":"object"},"apimodel.NumberPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"height","type":"string"},"number":{"description":"The number value of the property","example":42,"type":"number"}},"type":"object"},"apimodel.NumberPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"height","type":"string"},"name":{"description":"The name of the property","example":"Height","type":"string"},"number":{"description":"The number value of the property","example":42,"type":"number"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.Object":{"properties":{"archived":{"description":"Whether the object is archived","example":false,"type":"boolean"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the object","example":"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ","type":"string"},"layout":{"$ref":"#/components/schemas/apimodel.ObjectLayout"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object":{"description":"The data model of the object","example":"object","type":"string"},"properties":{"description":"The properties of the object","items":{"$ref":"#/components/schemas/apimodel.PropertyWithValue"},"type":"array","uniqueItems":false},"snippet":{"description":"The snippet of the object, especially important for notes as they don't have a name","example":"The beginning of the object body...","type":"string"},"space_id":{"description":"The id of the space the object is in","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"type":{"$ref":"#/components/schemas/apimodel.Type"}},"type":"object"},"apimodel.ObjectLayout":{"description":"The layout of the object","example":"basic","type":"string","x-enum-varnames":["ObjectLayoutBasic","ObjectLayoutProfile","ObjectLayoutAction","ObjectLayoutNote","ObjectLayoutBookmark","ObjectLayoutSet","ObjectLayoutCollection","ObjectLayoutParticipant"]},"apimodel.ObjectResponse":{"properties":{"object":{"$ref":"#/components/schemas/apimodel.ObjectWithBody"}},"type":"object"},"apimodel.ObjectWithBody":{"description":"The object","properties":{"archived":{"description":"Whether the object is archived","example":false,"type":"boolean"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the object","example":"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ","type":"string"},"layout":{"description":"The layout of the object","example":"basic","type":"string","x-enum-varnames":["ObjectLayoutBasic","ObjectLayoutProfile","ObjectLayoutAction","ObjectLayoutNote","ObjectLayoutBookmark","ObjectLayoutSet","ObjectLayoutCollection","ObjectLayoutParticipant"]},"markdown":{"description":"The markdown body of the object","example":"# This is the title\n...","type":"string"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object":{"description":"The data model of the object","example":"object","type":"string"},"properties":{"description":"The properties of the object","items":{"$ref":"#/components/schemas/apimodel.PropertyWithValue"},"type":"array","uniqueItems":false},"snippet":{"description":"The snippet of the object, especially important for notes as they don't have a name","example":"The beginning of the object body...","type":"string"},"space_id":{"description":"The id of the space the object is in","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"type":{"$ref":"#/components/schemas/apimodel.Type"}},"type":"object"},"apimodel.ObjectsPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"creator","type":"string"},"objects":{"description":"The object values of the property","example":["['objectId']"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.ObjectsPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"creator","type":"string"},"name":{"description":"The name of the property","example":"Created by","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"objects":{"description":"The object values of the property","example":["['objectId']"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.PhonePropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"phone","type":"string"},"phone":{"description":"The phone value of the property","example":"+1234567890","type":"string"}},"type":"object"},"apimodel.PhonePropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"phone","type":"string"},"name":{"description":"The name of the property","example":"Phone","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"phone":{"description":"The phone value of the property","example":"+1234567890","type":"string"}},"type":"object"},"apimodel.Property":{"description":"The property","properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"last_modified_date","type":"string"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.PropertyFormat":{"description":"The format of the property used for filtering","enum":["text","number","select","multi_select","date","files","checkbox","url","email","phone","objects"],"type":"string","x-enum-varnames":["PropertyFormatText","PropertyFormatNumber","PropertyFormatSelect","PropertyFormatMultiSelect","PropertyFormatDate","PropertyFormatFiles","PropertyFormatCheckbox","PropertyFormatUrl","PropertyFormatEmail","PropertyFormatPhone","PropertyFormatObjects"]},"apimodel.PropertyLink":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"description":"The key of the property","example":"last_modified_date","type":"string"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"}},"required":["format","key","name"],"type":"object"},"apimodel.PropertyLinkWithValue":{"oneOf":[{"$ref":"#/components/schemas/apimodel.TextPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.NumberPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.SelectPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.MultiSelectPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.DatePropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.FilesPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.CheckboxPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.URLPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.EmailPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.PhonePropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.ObjectsPropertyLinkValue"}],"type":"object"},"apimodel.PropertyResponse":{"properties":{"property":{"$ref":"#/components/schemas/apimodel.Property"}},"type":"object"},"apimodel.PropertyWithValue":{"oneOf":[{"$ref":"#/components/schemas/apimodel.TextPropertyValue"},{"$ref":"#/components/schemas/apimodel.NumberPropertyValue"},{"$ref":"#/components/schemas/apimodel.SelectPropertyValue"},{"$ref":"#/components/schemas/apimodel.MultiSelectPropertyValue"},{"$ref":"#/components/schemas/apimodel.DatePropertyValue"},{"$ref":"#/components/schemas/apimodel.FilesPropertyValue"},{"$ref":"#/components/schemas/apimodel.CheckboxPropertyValue"},{"$ref":"#/components/schemas/apimodel.URLPropertyValue"},{"$ref":"#/components/schemas/apimodel.EmailPropertyValue"},{"$ref":"#/components/schemas/apimodel.PhonePropertyValue"},{"$ref":"#/components/schemas/apimodel.ObjectsPropertyValue"}],"type":"object"},"apimodel.SearchRequest":{"properties":{"query":{"description":"The search term to look for in object names and snippets","example":"test","type":"string"},"sort":{"$ref":"#/components/schemas/apimodel.SortOptions"},"types":{"description":"The types of objects to search for, specified by key or ID","example":["page","678043f0cda9133be777049f","bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.SelectPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"status","type":"string"},"select":{"description":"The selected tag value of the property","type":"string"}},"type":"object"},"apimodel.SelectPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"status","type":"string"},"name":{"description":"The name of the property","example":"Status","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"select":{"$ref":"#/components/schemas/apimodel.Tag"}},"type":"object"},"apimodel.Sort":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the sort","example":"67bf3f21cda9134102e2422c","type":"string"},"property_key":{"description":"The property key used for sorting","example":"name","type":"string"},"sort_type":{"description":"The sort direction","enum":["asc","desc","custom"],"example":"asc","type":"string"}},"type":"object"},"apimodel.SortDirection":{"default":"desc","description":"The direction to sort the search results","enum":["asc","desc"],"type":"string","x-enum-varnames":["Asc","Desc"]},"apimodel.SortOptions":{"description":"The sorting criteria and direction for the search results","properties":{"direction":{"$ref":"#/components/schemas/apimodel.SortDirection"},"property_key":{"$ref":"#/components/schemas/apimodel.SortProperty"}},"type":"object"},"apimodel.SortProperty":{"default":"last_modified_date","description":"The property to sort the search results by","enum":["created_date","last_modified_date","last_opened_date","name"],"type":"string","x-enum-varnames":["CreatedDate","LastModifiedDate","LastOpenedDate","Name"]},"apimodel.Space":{"description":"The space","properties":{"description":{"description":"The description of the space","example":"The local-first wiki","type":"string"},"gateway_url":{"description":"The gateway url to serve files and media","example":"http://127.0.0.1:31006","type":"string"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the space","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"name":{"description":"The name of the space","example":"My Space","type":"string"},"network_id":{"description":"The network id of the space","example":"N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU","type":"string"},"object":{"description":"The data model of the object","example":"space","type":"string"}},"type":"object"},"apimodel.SpaceResponse":{"properties":{"space":{"$ref":"#/components/schemas/apimodel.Space"}},"type":"object"},"apimodel.Tag":{"description":"The selected tag value of the property","properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"id":{"description":"The id of the tag","example":"bafyreiaixlnaefu3ci22zdenjhsdlyaeeoyjrsid5qhfeejzlccijbj7sq","type":"string"},"key":{"description":"The key of the tag","example":"67b0d3e3cda913b84c1299b1","type":"string"},"name":{"description":"The name of the tag","example":"in-progress","type":"string"},"object":{"description":"The data model of the object","example":"tag","type":"string"}},"type":"object"},"apimodel.TagResponse":{"properties":{"tag":{"$ref":"#/components/schemas/apimodel.Tag"}},"type":"object"},"apimodel.TemplateResponse":{"properties":{"template":{"$ref":"#/components/schemas/apimodel.ObjectWithBody"}},"type":"object"},"apimodel.TextPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"description","type":"string"},"text":{"description":"The text value of the property","example":"Some text...","type":"string"}},"type":"object"},"apimodel.TextPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"description","type":"string"},"name":{"description":"The name of the property","example":"Description","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"text":{"description":"The text value of the property","example":"Some text...","type":"string"}},"type":"object"},"apimodel.TokenResponse":{"properties":{"app_key":{"description":"The app key used to authenticate requests","example":"zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=","type":"string"}},"type":"object"},"apimodel.Type":{"description":"The type of the object","properties":{"archived":{"description":"Whether the type is archived","example":false,"type":"boolean"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the type (which is unique across spaces)","example":"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu","type":"string"},"key":{"description":"The key of the type (can be the same across spaces for known types)","example":"page","type":"string"},"layout":{"description":"The layout of the object","example":"basic","type":"string","x-enum-varnames":["ObjectLayoutBasic","ObjectLayoutProfile","ObjectLayoutAction","ObjectLayoutNote","ObjectLayoutBookmark","ObjectLayoutSet","ObjectLayoutCollection","ObjectLayoutParticipant"]},"name":{"description":"The name of the type","example":"Page","type":"string"},"object":{"description":"The data model of the object","example":"type","type":"string"},"plural_name":{"description":"The plural name of the type","example":"Pages","type":"string"},"properties":{"description":"The properties linked to the type","items":{"$ref":"#/components/schemas/apimodel.Property"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.TypeLayout":{"description":"The layout of the type","example":"basic","type":"string","x-enum-varnames":["TypeLayoutBasic","TypeLayoutProfile","TypeLayoutAction","TypeLayoutNote"]},"apimodel.TypeResponse":{"properties":{"type":{"$ref":"#/components/schemas/apimodel.Type"}},"type":"object"},"apimodel.URLPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"source","type":"string"},"url":{"description":"The URL value of the property","example":"https://example.com","type":"string"}},"type":"object"},"apimodel.URLPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"source","type":"string"},"name":{"description":"The name of the property","example":"Source","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"url":{"description":"The URL value of the property","example":"https://example.com","type":"string"}},"type":"object"},"apimodel.UpdateObjectRequest":{"properties":{"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"name":{"description":"The name of the object","example":"My object","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set for the object","items":{"$ref":"#/components/schemas/apimodel.PropertyLinkWithValue"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.UpdatePropertyRequest":{"properties":{"name":{"description":"The name to set for the property","example":"Last modified date","type":"string"}},"required":["name"],"type":"object"},"apimodel.UpdateSpaceRequest":{"properties":{"description":{"description":"The description of the space","example":"The local-first wiki","type":"string"},"name":{"description":"The name of the space","example":"New Space","type":"string"}},"type":"object"},"apimodel.UpdateTagRequest":{"properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"name":{"description":"The name to set for the tag","example":"In progress","type":"string"}},"type":"object"},"apimodel.UpdateTypeRequest":{"properties":{"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"layout":{"description":"The layout of the type","example":"basic","type":"string","x-enum-varnames":["TypeLayoutBasic","TypeLayoutProfile","TypeLayoutAction","TypeLayoutNote"]},"name":{"description":"The name to set for the type","example":"Page","type":"string"},"plural_name":{"description":"The plural name to set for the type","example":"Pages","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set for the type","items":{"$ref":"#/components/schemas/apimodel.PropertyLink"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.View":{"properties":{"filters":{"description":"The list of filters","items":{"$ref":"#/components/schemas/apimodel.Filter"},"type":"array","uniqueItems":false},"id":{"description":"The id of the view","example":"67bf3f21cda9134102e2422c","type":"string"},"layout":{"description":"The layout of the view","enum":["grid","table"],"example":"grid","type":"string"},"name":{"description":"The name of the view","example":"All","type":"string"},"sorts":{"description":"The list of sorts","items":{"$ref":"#/components/schemas/apimodel.Sort"},"type":"array","uniqueItems":false}},"type":"object"},"pagination.PaginatedResponse-apimodel_Member":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Member"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Object":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Object"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Property":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Property"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Space":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Space"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Tag":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Tag"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Type":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Type"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_View":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.View"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginationMeta":{"description":"The pagination metadata for the response","properties":{"has_more":{"description":"Indicates if there are more items available beyond the current result set","example":true,"type":"boolean"},"limit":{"description":"The maximum number of items returned in the result set","example":100,"type":"integer"},"offset":{"description":"The number of items skipped before starting to collect the result set","example":0,"type":"integer"},"total":{"description":"The total number of items available for the endpoint","example":1000,"type":"integer"}},"type":"object"},"util.ForbiddenError":{"properties":{"code":{"example":"forbidden","type":"string"},"message":{"example":"Forbidden","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":403,"type":"integer"}},"type":"object"},"util.GoneError":{"properties":{"code":{"example":"resource_gone","type":"string"},"message":{"example":"Resource is gone","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":410,"type":"integer"}},"type":"object"},"util.NotFoundError":{"properties":{"code":{"example":"object_not_found","type":"string"},"message":{"example":"Resource not found","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":404,"type":"integer"}},"type":"object"},"util.RateLimitError":{"properties":{"code":{"example":"rate_limit_exceeded","type":"string"},"message":{"example":"Rate limit exceeded","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":429,"type":"integer"}},"type":"object"},"util.ServerError":{"properties":{"code":{"example":"internal_server_error","type":"string"},"message":{"example":"Internal server error","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":500,"type":"integer"}},"type":"object"},"util.UnauthorizedError":{"properties":{"code":{"example":"unauthorized","type":"string"},"message":{"example":"Unauthorized","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":401,"type":"integer"}},"type":"object"},"util.ValidationError":{"properties":{"code":{"example":"bad_request","type":"string"},"message":{"example":"Bad request","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":400,"type":"integer"}},"type":"object"}},"securitySchemes":{"bearerauth":{"bearerFormat":"JWT","scheme":"bearer","type":"http"}}}, + "components": {"schemas":{"apimodel.AddObjectsToListRequest":{"properties":{"objects":{"description":"The list of object IDs to add to the list","example":["[\"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ\"]"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.CheckboxPropertyLinkValue":{"properties":{"checkbox":{"description":"The checkbox value of the property","example":true,"type":"boolean"},"key":{"example":"done","type":"string"}},"type":"object"},"apimodel.CheckboxPropertyValue":{"properties":{"checkbox":{"description":"The checkbox value of the property","example":true,"type":"boolean"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"done","type":"string"},"name":{"description":"The name of the property","example":"Done","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.Color":{"description":"The color of the icon","enum":["grey","yellow","orange","red","pink","purple","blue","ice","teal","lime"],"example":"yellow","type":"string","x-enum-varnames":["ColorGrey","ColorYellow","ColorOrange","ColorRed","ColorPink","ColorPurple","ColorBlue","ColorIce","ColorTeal","ColorLime"]},"apimodel.CreateApiKeyResponse":{"properties":{"api_key":{"description":"The api key used to authenticate requests","example":"zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=","type":"string"}},"type":"object"},"apimodel.CreateChallengeResponse":{"properties":{"challenge_id":{"description":"The challenge id associated with the displayed code and needed to solve the challenge for api_key","example":"67647f5ecda913e9a2e11b26","type":"string"}},"type":"object"},"apimodel.CreateObjectRequest":{"properties":{"body":{"description":"The body of the object","example":"This is the body of the object. Markdown syntax is supported here.","type":"string"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"name":{"description":"The name of the object","example":"My object","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set on the object; see ListTypes or GetType endpoints for linked properties","items":{"$ref":"#/components/schemas/apimodel.PropertyLinkWithValue"},"type":"array","uniqueItems":false},"template_id":{"description":"The id of the template to use","example":"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge","type":"string"},"type_key":{"description":"The key of the type of object to create","example":"page","type":"string"}},"required":["type_key"],"type":"object"},"apimodel.CreatePropertyRequest":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"description":"The key of the property; should always be snake_case, otherwise it will be converted to snake_case","example":"some_user_defined_property_key","type":"string"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"}},"required":["format","name"],"type":"object"},"apimodel.CreateSpaceRequest":{"properties":{"description":{"description":"The description of the space","example":"The local-first wiki","type":"string"},"name":{"description":"The name of the space","example":"New Space","type":"string"}},"required":["name"],"type":"object"},"apimodel.CreateTagRequest":{"properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"name":{"description":"The name of the tag","example":"In progress","type":"string"}},"required":["color","name"],"type":"object"},"apimodel.CreateTypeRequest":{"properties":{"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"key":{"description":"The key of the type; should always be snake_case, otherwise it will be converted to snake_case","example":"some_user_defined_type_key","type":"string"},"layout":{"$ref":"#/components/schemas/apimodel.TypeLayout"},"name":{"description":"The name of the type","example":"Page","type":"string"},"plural_name":{"description":"The plural name of the type","example":"Pages","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties linked to the type","items":{"$ref":"#/components/schemas/apimodel.PropertyLink"},"type":"array","uniqueItems":false}},"required":["layout","name","plural_name"],"type":"object"},"apimodel.DatePropertyLinkValue":{"properties":{"date":{"description":"The date value of the property","example":"2025-02-14T12:34:56Z","type":"string"},"key":{"example":"last_modified_date","type":"string"}},"type":"object"},"apimodel.DatePropertyValue":{"properties":{"date":{"description":"The date value of the property","example":"2025-02-14T12:34:56Z","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"last_modified_date","type":"string"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.EmailPropertyLinkValue":{"properties":{"email":{"description":"The email value of the property","example":"example@example.com","type":"string"},"key":{"example":"email","type":"string"}},"type":"object"},"apimodel.EmailPropertyValue":{"properties":{"email":{"description":"The email value of the property","example":"example@example.com","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"email","type":"string"},"name":{"description":"The name of the property","example":"Email","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.EmojiIcon":{"properties":{"emoji":{"description":"The emoji of the icon","example":"📄","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.IconFormat"}},"type":"object"},"apimodel.FileIcon":{"properties":{"file":{"description":"The file of the icon","example":"bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.IconFormat"}},"type":"object"},"apimodel.FilesPropertyLinkValue":{"properties":{"files":{"description":"The file ids of the property","example":["['file_id']"],"items":{"type":"string"},"type":"array","uniqueItems":false},"key":{"example":"files","type":"string"}},"type":"object"},"apimodel.FilesPropertyValue":{"properties":{"files":{"description":"The file values of the property","example":["['file_id']"],"items":{"type":"string"},"type":"array","uniqueItems":false},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"files","type":"string"},"name":{"description":"The name of the property","example":"Files","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.Filter":{"properties":{"condition":{"description":"The filter condition","enum":["equal","not_equal","greater","less","greater_or_equal","less_or_equal","like","not_like","in","not_in","empty","not_empty","all_in","not_all_in","exact_in","not_exact_in","exists"],"example":"contains","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the filter","example":"67bf3f21cda9134102e2422c","type":"string"},"property_key":{"description":"The property key used for filtering","example":"name","type":"string"},"value":{"description":"The value used for filtering","example":"Some value...","type":"string"}},"type":"object"},"apimodel.Icon":{"description":"The icon of the object","oneOf":[{"$ref":"#/components/schemas/apimodel.EmojiIcon"},{"$ref":"#/components/schemas/apimodel.FileIcon"},{"$ref":"#/components/schemas/apimodel.NamedIcon"}],"type":"object"},"apimodel.IconFormat":{"description":"The format of the icon","enum":["emoji","file","icon"],"type":"string","x-enum-varnames":["IconFormatEmoji","IconFormatFile","IconFormatIcon"]},"apimodel.IconName":{"description":"The name of the icon","example":"document","type":"string","x-enum-varnames":["IconNameAccessibility","IconNameAddCircle","IconNameAirplane","IconNameAlarm","IconNameAlbums","IconNameAlertCircle","IconNameAmericanFootball","IconNameAnalytics","IconNameAperture","IconNameApps","IconNameArchive","IconNameArrowBackCircle","IconNameArrowDownCircle","IconNameArrowForwardCircle","IconNameArrowRedoCircle","IconNameArrowRedo","IconNameArrowUndoCircle","IconNameArrowUndo","IconNameArrowUpCircle","IconNameAtCircle","IconNameAttach","IconNameBackspace","IconNameBagAdd","IconNameBagCheck","IconNameBagHandle","IconNameBagRemove","IconNameBag","IconNameBalloon","IconNameBan","IconNameBandage","IconNameBarChart","IconNameBarbell","IconNameBarcode","IconNameBaseball","IconNameBasket","IconNameBasketball","IconNameBatteryCharging","IconNameBatteryDead","IconNameBatteryFull","IconNameBatteryHalf","IconNameBeaker","IconNameBed","IconNameBeer","IconNameBicycle","IconNameBinoculars","IconNameBluetooth","IconNameBoat","IconNameBody","IconNameBonfire","IconNameBook","IconNameBookmark","IconNameBookmarks","IconNameBowlingBall","IconNameBriefcase","IconNameBrowsers","IconNameBrush","IconNameBug","IconNameBuild","IconNameBulb","IconNameBus","IconNameBusiness","IconNameCafe","IconNameCalculator","IconNameCalendarClear","IconNameCalendarNumber","IconNameCalendar","IconNameCall","IconNameCameraReverse","IconNameCamera","IconNameCarSport","IconNameCar","IconNameCard","IconNameCaretBackCircle","IconNameCaretBack","IconNameCaretDownCircle","IconNameCaretDown","IconNameCaretForwardCircle","IconNameCaretForward","IconNameCaretUpCircle","IconNameCaretUp","IconNameCart","IconNameCash","IconNameCellular","IconNameChatboxEllipses","IconNameChatbox","IconNameChatbubbleEllipses","IconNameChatbubble","IconNameChatbubbles","IconNameCheckbox","IconNameCheckmarkCircle","IconNameCheckmarkDoneCircle","IconNameChevronBackCircle","IconNameChevronDownCircle","IconNameChevronForwardCircle","IconNameChevronUpCircle","IconNameClipboard","IconNameCloseCircle","IconNameCloudCircle","IconNameCloudDone","IconNameCloudDownload","IconNameCloudOffline","IconNameCloudUpload","IconNameCloud","IconNameCloudyNight","IconNameCloudy","IconNameCodeSlash","IconNameCode","IconNameCog","IconNameColorFill","IconNameColorFilter","IconNameColorPalette","IconNameColorWand","IconNameCompass","IconNameConstruct","IconNameContact","IconNameContract","IconNameContrast","IconNameCopy","IconNameCreate","IconNameCrop","IconNameCube","IconNameCut","IconNameDesktop","IconNameDiamond","IconNameDice","IconNameDisc","IconNameDocumentAttach","IconNameDocumentLock","IconNameDocumentText","IconNameDocument","IconNameDocuments","IconNameDownload","IconNameDuplicate","IconNameEar","IconNameEarth","IconNameEasel","IconNameEgg","IconNameEllipse","IconNameEllipsisHorizontalCircle","IconNameEllipsisVerticalCircle","IconNameEnter","IconNameExit","IconNameExpand","IconNameExtensionPuzzle","IconNameEyeOff","IconNameEye","IconNameEyedrop","IconNameFastFood","IconNameFemale","IconNameFileTrayFull","IconNameFileTrayStacked","IconNameFileTray","IconNameFilm","IconNameFilterCircle","IconNameFingerPrint","IconNameFish","IconNameFitness","IconNameFlag","IconNameFlame","IconNameFlashOff","IconNameFlash","IconNameFlashlight","IconNameFlask","IconNameFlower","IconNameFolderOpen","IconNameFolder","IconNameFootball","IconNameFootsteps","IconNameFunnel","IconNameGameController","IconNameGift","IconNameGitBranch","IconNameGitCommit","IconNameGitCompare","IconNameGitMerge","IconNameGitNetwork","IconNameGitPullRequest","IconNameGlasses","IconNameGlobe","IconNameGolf","IconNameGrid","IconNameHammer","IconNameHandLeft","IconNameHandRight","IconNameHappy","IconNameHardwareChip","IconNameHeadset","IconNameHeartCircle","IconNameHeartDislikeCircle","IconNameHeartDislike","IconNameHeartHalf","IconNameHeart","IconNameHelpBuoy","IconNameHelpCircle","IconNameHome","IconNameHourglass","IconNameIceCream","IconNameIdCard","IconNameImage","IconNameImages","IconNameInfinite","IconNameInformationCircle","IconNameInvertMode","IconNameJournal","IconNameKey","IconNameKeypad","IconNameLanguage","IconNameLaptop","IconNameLayers","IconNameLeaf","IconNameLibrary","IconNameLink","IconNameListCircle","IconNameList","IconNameLocate","IconNameLocation","IconNameLockClosed","IconNameLockOpen","IconNameLogIn","IconNameLogOut","IconNameLogoAlipay","IconNameLogoAmazon","IconNameLogoAmplify","IconNameLogoAndroid","IconNameMagnet","IconNameMailOpen","IconNameMailUnread","IconNameMail","IconNameMaleFemale","IconNameMale","IconNameMan","IconNameMap","IconNameMedal","IconNameMedical","IconNameMedkit","IconNameMegaphone","IconNameMenu","IconNameMicCircle","IconNameMicOffCircle","IconNameMicOff","IconNameMic","IconNameMoon","IconNameMove","IconNameMusicalNote","IconNameMusicalNotes","IconNameNavigateCircle","IconNameNavigate","IconNameNewspaper","IconNameNotificationsCircle","IconNameNotificationsOffCircle","IconNameNotificationsOff","IconNameNotifications","IconNameNuclear","IconNameNutrition","IconNameOptions","IconNamePaperPlane","IconNamePartlySunny","IconNamePauseCircle","IconNamePause","IconNamePaw","IconNamePencil","IconNamePeopleCircle","IconNamePeople","IconNamePersonAdd","IconNamePersonCircle","IconNamePersonRemove","IconNamePerson","IconNamePhoneLandscape","IconNamePhonePortrait","IconNamePieChart","IconNamePin","IconNamePint","IconNamePizza","IconNamePlanet","IconNamePlayBackCircle","IconNamePlayBack","IconNamePlayCircle","IconNamePlayForwardCircle","IconNamePlayForward","IconNamePlaySkipBackCircle","IconNamePlaySkipBack","IconNamePlaySkipForwardCircle","IconNamePlaySkipForward","IconNamePlay","IconNamePodium","IconNamePower","IconNamePricetag","IconNamePricetags","IconNamePrint","IconNamePrism","IconNamePulse","IconNamePush","IconNameQrCode","IconNameRadioButtonOff","IconNameRadioButtonOn","IconNameRadio","IconNameRainy","IconNameReader","IconNameReceipt","IconNameRecording","IconNameRefreshCircle","IconNameRefresh","IconNameReloadCircle","IconNameReload","IconNameRemoveCircle","IconNameRepeat","IconNameResize","IconNameRestaurant","IconNameRibbon","IconNameRocket","IconNameRose","IconNameSad","IconNameSave","IconNameScale","IconNameScanCircle","IconNameScan","IconNameSchool","IconNameSearchCircle","IconNameSearch","IconNameSend","IconNameServer","IconNameSettings","IconNameShapes","IconNameShareSocial","IconNameShare","IconNameShieldCheckmark","IconNameShieldHalf","IconNameShield","IconNameShirt","IconNameShuffle","IconNameSkull","IconNameSnow","IconNameSparkles","IconNameSpeedometer","IconNameSquare","IconNameStarHalf","IconNameStar","IconNameStatsChart","IconNameStopCircle","IconNameStop","IconNameStopwatch","IconNameStorefront","IconNameSubway","IconNameSunny","IconNameSwapHorizontal","IconNameSwapVertical","IconNameSyncCircle","IconNameSync","IconNameTabletLandscape","IconNameTabletPortrait","IconNameTelescope","IconNameTennisball","IconNameTerminal","IconNameText","IconNameThermometer","IconNameThumbsDown","IconNameThumbsUp","IconNameThunderstorm","IconNameTicket","IconNameTime","IconNameTimer","IconNameToday","IconNameToggle","IconNameTrailSign","IconNameTrain","IconNameTransgender","IconNameTrashBin","IconNameTrash","IconNameTrendingDown","IconNameTrendingUp","IconNameTriangle","IconNameTrophy","IconNameTv","IconNameUmbrella","IconNameUnlink","IconNameVideocamOff","IconNameVideocam","IconNameVolumeHigh","IconNameVolumeLow","IconNameVolumeMedium","IconNameVolumeMute","IconNameVolumeOff","IconNameWalk","IconNameWallet","IconNameWarning","IconNameWatch","IconNameWater","IconNameWifi","IconNameWine","IconNameWoman"]},"apimodel.Member":{"description":"The member","properties":{"global_name":{"description":"The global name of the member in the network","example":"john.any","type":"string"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The profile object id of the member","example":"_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ","type":"string"},"identity":{"description":"The identity of the member in the network","example":"AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ","type":"string"},"name":{"description":"The name of the member","example":"John Doe","type":"string"},"object":{"description":"The data model of the object","example":"member","type":"string"},"role":{"description":"The role of the member","enum":["viewer","editor","owner","no_permission"],"example":"owner","type":"string"},"status":{"description":"The status of the member","enum":["joining","active","removed","declined","removing","canceled"],"example":"active","type":"string"}},"type":"object"},"apimodel.MemberResponse":{"properties":{"member":{"$ref":"#/components/schemas/apimodel.Member"}},"type":"object"},"apimodel.MultiSelectPropertyLinkValue":{"properties":{"key":{"example":"tag","type":"string"},"multi_select":{"description":"The selected tag ids of the property; see ListTags endpoint for valid values","example":["['tag_id']"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.MultiSelectPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"tag","type":"string"},"multi_select":{"description":"The selected tag values of the property","items":{"$ref":"#/components/schemas/apimodel.Tag"},"type":"array","uniqueItems":false},"name":{"description":"The name of the property","example":"Tag","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.NamedIcon":{"properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"format":{"$ref":"#/components/schemas/apimodel.IconFormat"},"name":{"$ref":"#/components/schemas/apimodel.IconName"}},"type":"object"},"apimodel.NumberPropertyLinkValue":{"properties":{"key":{"example":"height","type":"string"},"number":{"description":"The number value of the property","example":42,"type":"number"}},"type":"object"},"apimodel.NumberPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"height","type":"string"},"name":{"description":"The name of the property","example":"Height","type":"string"},"number":{"description":"The number value of the property","example":42,"type":"number"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.Object":{"properties":{"archived":{"description":"Whether the object is archived","example":false,"type":"boolean"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the object","example":"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ","type":"string"},"layout":{"$ref":"#/components/schemas/apimodel.ObjectLayout"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object":{"description":"The data model of the object","example":"object","type":"string"},"properties":{"description":"The properties of the object","items":{"$ref":"#/components/schemas/apimodel.PropertyWithValue"},"type":"array","uniqueItems":false},"snippet":{"description":"The snippet of the object, especially important for notes as they don't have a name","example":"The beginning of the object body...","type":"string"},"space_id":{"description":"The id of the space the object is in","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"type":{"$ref":"#/components/schemas/apimodel.Type"}},"type":"object"},"apimodel.ObjectLayout":{"description":"The layout of the object","example":"basic","type":"string","x-enum-varnames":["ObjectLayoutBasic","ObjectLayoutProfile","ObjectLayoutAction","ObjectLayoutNote","ObjectLayoutBookmark","ObjectLayoutSet","ObjectLayoutCollection","ObjectLayoutParticipant"]},"apimodel.ObjectResponse":{"properties":{"object":{"$ref":"#/components/schemas/apimodel.ObjectWithBody"}},"type":"object"},"apimodel.ObjectWithBody":{"description":"The object","properties":{"archived":{"description":"Whether the object is archived","example":false,"type":"boolean"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the object","example":"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ","type":"string"},"layout":{"description":"The layout of the object","example":"basic","type":"string","x-enum-varnames":["ObjectLayoutBasic","ObjectLayoutProfile","ObjectLayoutAction","ObjectLayoutNote","ObjectLayoutBookmark","ObjectLayoutSet","ObjectLayoutCollection","ObjectLayoutParticipant"]},"markdown":{"description":"The markdown body of the object","example":"# This is the title\n...","type":"string"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object":{"description":"The data model of the object","example":"object","type":"string"},"properties":{"description":"The properties of the object","items":{"$ref":"#/components/schemas/apimodel.PropertyWithValue"},"type":"array","uniqueItems":false},"snippet":{"description":"The snippet of the object, especially important for notes as they don't have a name","example":"The beginning of the object body...","type":"string"},"space_id":{"description":"The id of the space the object is in","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"type":{"$ref":"#/components/schemas/apimodel.Type"}},"type":"object"},"apimodel.ObjectsPropertyLinkValue":{"properties":{"key":{"example":"creator","type":"string"},"objects":{"description":"The object ids of the property","example":["['object_id']"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.ObjectsPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"creator","type":"string"},"name":{"description":"The name of the property","example":"Created by","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"objects":{"description":"The object values of the property","example":["['object_id']"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.PhonePropertyLinkValue":{"properties":{"key":{"example":"phone","type":"string"},"phone":{"description":"The phone value of the property","example":"+1234567890","type":"string"}},"type":"object"},"apimodel.PhonePropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"phone","type":"string"},"name":{"description":"The name of the property","example":"Phone","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"phone":{"description":"The phone value of the property","example":"+1234567890","type":"string"}},"type":"object"},"apimodel.Property":{"description":"The property","properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"last_modified_date","type":"string"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.PropertyFormat":{"description":"The format of the property used for filtering","enum":["text","number","select","multi_select","date","files","checkbox","url","email","phone","objects"],"type":"string","x-enum-varnames":["PropertyFormatText","PropertyFormatNumber","PropertyFormatSelect","PropertyFormatMultiSelect","PropertyFormatDate","PropertyFormatFiles","PropertyFormatCheckbox","PropertyFormatUrl","PropertyFormatEmail","PropertyFormatPhone","PropertyFormatObjects"]},"apimodel.PropertyLink":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"description":"The key of the property","example":"last_modified_date","type":"string"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"}},"required":["format","key","name"],"type":"object"},"apimodel.PropertyLinkWithValue":{"oneOf":[{"$ref":"#/components/schemas/apimodel.TextPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.NumberPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.SelectPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.MultiSelectPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.DatePropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.FilesPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.CheckboxPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.URLPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.EmailPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.PhonePropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.ObjectsPropertyLinkValue"}],"type":"object"},"apimodel.PropertyResponse":{"properties":{"property":{"$ref":"#/components/schemas/apimodel.Property"}},"type":"object"},"apimodel.PropertyWithValue":{"oneOf":[{"$ref":"#/components/schemas/apimodel.TextPropertyValue"},{"$ref":"#/components/schemas/apimodel.NumberPropertyValue"},{"$ref":"#/components/schemas/apimodel.SelectPropertyValue"},{"$ref":"#/components/schemas/apimodel.MultiSelectPropertyValue"},{"$ref":"#/components/schemas/apimodel.DatePropertyValue"},{"$ref":"#/components/schemas/apimodel.FilesPropertyValue"},{"$ref":"#/components/schemas/apimodel.CheckboxPropertyValue"},{"$ref":"#/components/schemas/apimodel.URLPropertyValue"},{"$ref":"#/components/schemas/apimodel.EmailPropertyValue"},{"$ref":"#/components/schemas/apimodel.PhonePropertyValue"},{"$ref":"#/components/schemas/apimodel.ObjectsPropertyValue"}],"type":"object"},"apimodel.SearchRequest":{"properties":{"query":{"description":"The text to search within object names and content; use types field for type filtering","example":"test","type":"string"},"sort":{"$ref":"#/components/schemas/apimodel.SortOptions"},"types":{"description":"The types of objects to include in results (e.g., \"page\", \"task\", \"bookmark\"); see ListTypes endpoint for valid values","example":["page","task","bookmark"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.SelectPropertyLinkValue":{"properties":{"key":{"example":"status","type":"string"},"select":{"description":"The selected tag id of the property; see ListTags endpoint for valid values","example":"tag_id","type":"string"}},"type":"object"},"apimodel.SelectPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"status","type":"string"},"name":{"description":"The name of the property","example":"Status","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"select":{"$ref":"#/components/schemas/apimodel.Tag"}},"type":"object"},"apimodel.Sort":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the sort","example":"67bf3f21cda9134102e2422c","type":"string"},"property_key":{"description":"The property key used for sorting","example":"name","type":"string"},"sort_type":{"description":"The sort direction","enum":["asc","desc","custom"],"example":"asc","type":"string"}},"type":"object"},"apimodel.SortDirection":{"default":"desc","description":"The direction to sort the search results by","enum":["asc","desc"],"type":"string","x-enum-varnames":["Asc","Desc"]},"apimodel.SortOptions":{"description":"The sorting options for the search results","properties":{"direction":{"$ref":"#/components/schemas/apimodel.SortDirection"},"property_key":{"$ref":"#/components/schemas/apimodel.SortProperty"}},"type":"object"},"apimodel.SortProperty":{"default":"last_modified_date","description":"The key of the property to sort the search results by","enum":["created_date","last_modified_date","last_opened_date","name"],"type":"string","x-enum-varnames":["CreatedDate","LastModifiedDate","LastOpenedDate","Name"]},"apimodel.Space":{"description":"The space","properties":{"description":{"description":"The description of the space","example":"The local-first wiki","type":"string"},"gateway_url":{"description":"The gateway url to serve files and media","example":"http://127.0.0.1:31006","type":"string"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the space","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"name":{"description":"The name of the space","example":"My Space","type":"string"},"network_id":{"description":"The network id of the space","example":"N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU","type":"string"},"object":{"description":"The data model of the object","example":"space","type":"string"}},"type":"object"},"apimodel.SpaceResponse":{"properties":{"space":{"$ref":"#/components/schemas/apimodel.Space"}},"type":"object"},"apimodel.Tag":{"description":"The selected tag value of the property","properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"id":{"description":"The id of the tag","example":"bafyreiaixlnaefu3ci22zdenjhsdlyaeeoyjrsid5qhfeejzlccijbj7sq","type":"string"},"key":{"description":"The key of the tag","example":"67b0d3e3cda913b84c1299b1","type":"string"},"name":{"description":"The name of the tag","example":"in-progress","type":"string"},"object":{"description":"The data model of the object","example":"tag","type":"string"}},"type":"object"},"apimodel.TagResponse":{"properties":{"tag":{"$ref":"#/components/schemas/apimodel.Tag"}},"type":"object"},"apimodel.TemplateResponse":{"properties":{"template":{"$ref":"#/components/schemas/apimodel.ObjectWithBody"}},"type":"object"},"apimodel.TextPropertyLinkValue":{"properties":{"key":{"example":"description","type":"string"},"text":{"description":"The text value of the property","example":"Some text...","type":"string"}},"type":"object"},"apimodel.TextPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"description","type":"string"},"name":{"description":"The name of the property","example":"Description","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"text":{"description":"The text value of the property","example":"Some text...","type":"string"}},"type":"object"},"apimodel.Type":{"description":"The type of the object","properties":{"archived":{"description":"Whether the type is archived","example":false,"type":"boolean"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the type (which is unique across spaces)","example":"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu","type":"string"},"key":{"description":"The key of the type (can be the same across spaces for known types)","example":"page","type":"string"},"layout":{"description":"The layout of the object","enum":["basic","profile","action","note","bookmark","set","set","collection","participant"],"type":"string","x-enum-varnames":["ObjectLayoutBasic","ObjectLayoutProfile","ObjectLayoutAction","ObjectLayoutNote","ObjectLayoutBookmark","ObjectLayoutSet","ObjectLayoutCollection","ObjectLayoutParticipant"]},"name":{"description":"The name of the type","example":"Page","type":"string"},"object":{"description":"The data model of the object","example":"type","type":"string"},"plural_name":{"description":"The plural name of the type","example":"Pages","type":"string"},"properties":{"description":"The properties linked to the type","items":{"$ref":"#/components/schemas/apimodel.Property"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.TypeLayout":{"description":"The layout of the type","enum":["basic","profile","action","note"],"type":"string","x-enum-varnames":["TypeLayoutBasic","TypeLayoutProfile","TypeLayoutAction","TypeLayoutNote"]},"apimodel.TypeResponse":{"properties":{"type":{"$ref":"#/components/schemas/apimodel.Type"}},"type":"object"},"apimodel.URLPropertyLinkValue":{"properties":{"key":{"example":"source","type":"string"},"url":{"description":"The URL value of the property","example":"https://example.com","type":"string"}},"type":"object"},"apimodel.URLPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"source","type":"string"},"name":{"description":"The name of the property","example":"Source","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"url":{"description":"The URL value of the property","example":"https://example.com","type":"string"}},"type":"object"},"apimodel.UpdateObjectRequest":{"properties":{"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"name":{"description":"The name of the object","example":"My object","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set for the object; see ListTypes or GetType endpoints for linked properties","items":{"$ref":"#/components/schemas/apimodel.PropertyLinkWithValue"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.UpdatePropertyRequest":{"properties":{"key":{"description":"The key to set for the property; ; should always be snake_case, otherwise it will be converted to snake_case","example":"some_user_defined_property_key","type":"string"},"name":{"description":"The name to set for the property","example":"Last modified date","type":"string"}},"required":["name"],"type":"object"},"apimodel.UpdateSpaceRequest":{"properties":{"description":{"description":"The description of the space","example":"The local-first wiki","type":"string"},"name":{"description":"The name of the space","example":"New Space","type":"string"}},"type":"object"},"apimodel.UpdateTagRequest":{"properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"name":{"description":"The name to set for the tag","example":"In progress","type":"string"}},"type":"object"},"apimodel.UpdateTypeRequest":{"properties":{"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"key":{"description":"The key to set for the type; should always be snake_case, otherwise it will be converted to snake_case","example":"some_user_defined_type_key","type":"string"},"layout":{"$ref":"#/components/schemas/apimodel.TypeLayout"},"name":{"description":"The name to set for the type","example":"Page","type":"string"},"plural_name":{"description":"The plural name to set for the type","example":"Pages","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set for the type","items":{"$ref":"#/components/schemas/apimodel.PropertyLink"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.View":{"properties":{"filters":{"description":"The list of filters","items":{"$ref":"#/components/schemas/apimodel.Filter"},"type":"array","uniqueItems":false},"id":{"description":"The id of the view","example":"67bf3f21cda9134102e2422c","type":"string"},"layout":{"description":"The layout of the view","enum":["grid","table"],"example":"grid","type":"string"},"name":{"description":"The name of the view","example":"All","type":"string"},"sorts":{"description":"The list of sorts","items":{"$ref":"#/components/schemas/apimodel.Sort"},"type":"array","uniqueItems":false}},"type":"object"},"pagination.PaginatedResponse-apimodel_Member":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Member"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Object":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Object"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Property":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Property"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Space":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Space"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Tag":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Tag"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Type":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Type"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_View":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.View"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginationMeta":{"description":"The pagination metadata for the response","properties":{"has_more":{"description":"Indicates if there are more items available beyond the current result set","example":true,"type":"boolean"},"limit":{"description":"The maximum number of items returned in the result set","example":100,"type":"integer"},"offset":{"description":"The number of items skipped before starting to collect the result set","example":0,"type":"integer"},"total":{"description":"The total number of items available for the endpoint","example":1000,"type":"integer"}},"type":"object"},"util.ForbiddenError":{"properties":{"code":{"example":"forbidden","type":"string"},"message":{"example":"Forbidden","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":403,"type":"integer"}},"type":"object"},"util.GoneError":{"properties":{"code":{"example":"resource_gone","type":"string"},"message":{"example":"Resource is gone","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":410,"type":"integer"}},"type":"object"},"util.NotFoundError":{"properties":{"code":{"example":"object_not_found","type":"string"},"message":{"example":"Resource not found","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":404,"type":"integer"}},"type":"object"},"util.RateLimitError":{"properties":{"code":{"example":"rate_limit_exceeded","type":"string"},"message":{"example":"Rate limit exceeded","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":429,"type":"integer"}},"type":"object"},"util.ServerError":{"properties":{"code":{"example":"internal_server_error","type":"string"},"message":{"example":"Internal server error","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":500,"type":"integer"}},"type":"object"},"util.UnauthorizedError":{"properties":{"code":{"example":"unauthorized","type":"string"},"message":{"example":"Unauthorized","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":401,"type":"integer"}},"type":"object"},"util.ValidationError":{"properties":{"code":{"example":"bad_request","type":"string"},"message":{"example":"Bad request","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":400,"type":"integer"}},"type":"object"}},"securitySchemes":{"bearerauth":{"bearerFormat":"JWT","scheme":"bearer","type":"http"}}}, "info": {"contact":{"email":"support@anytype.io","name":"Anytype Support","url":"https://anytype.io/contact"},"description":"{{escape .Description}}","license":{"name":"Any Source Available License 1.0","url":"https://github.com/anyproto/anytype-api/blob/main/LICENSE.md"},"termsOfService":"https://anytype.io/terms_of_use","title":"{{.Title}}","version":"{{.Version}}"}, "externalDocs": {"description":"OpenAPI","url":"https://swagger.io/resources/open-api/"}, - "paths": {"/auth/display_code":{"post":{"description":"Generates a one-time authentication challenge for granting API access to the user's vault. Upon providing a valid ` + "`" + `app_name` + "`" + `, the server issues a unique ` + "`" + `challenge_id` + "`" + ` and displays a short code within the Anytype Desktop On success, the service returns a unique challenge ID. This challenge ID must then be used with the token endpoint (see below) to solve the challenge and retrieve an authentication token. This mechanism ensures that only trusted applications and authorized users gain access.","operationId":"createAuthChallenge","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The name of the app requesting API access","in":"query","name":"app_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.DisplayCodeResponse"}}},"description":"The challenge ID associated with the started challenge"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Start new challenge","tags":["Auth"]}},"/auth/token":{"post":{"description":"After receiving a challenge ID from the display_code endpoint, the client calls this endpoint to provide the corresponding 4-digit code (also via a query parameter) along with the challenge ID. The endpoint verifies that the challenge solution is correct and, if it is, returns a permanent app key. This endpoint is central to the authentication process, as it validates the user's identity and issues a token that can be used for further interactions with the API.","operationId":"solveAuthChallenge","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the challenge to solve","in":"query","name":"challenge_id","required":true,"schema":{"type":"string"}},{"description":"4-digit code retrieved from Anytype Desktop app","in":"query","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TokenResponse"}}},"description":"The app key that can be used in the Authorization header for subsequent requests"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Solve challenge","tags":["Auth"]}},"/search":{"post":{"description":"Executes a global search over every space accessible by the authenticated user. The request body must specify the ` + "`" + `query` + "`" + ` text, optional filters on object types (e.g., \"page\", \"task\"), and sort directives (default: descending by last updated timestamp). Pagination is controlled via ` + "`" + `offset` + "`" + ` and ` + "`" + `limit` + "`" + ` query parameters to facilitate lazy loading in client UIs. The response returns a unified list of matched objects with their metadata and properties.","operationId":"searchGlobal","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SearchRequest"}}},"description":"The search parameters used to filter and sort the results","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects matching the search criteria"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects across all spaces","tags":["Search"]}},"/spaces":{"get":{"description":"Retrieves a paginated list of all spaces that are accessible by the authenticated user. Each space record contains detailed information such as the space ID, name, icon (derived either from an emoji or image URL), and additional metadata. This endpoint is key to displaying a user’s workspaces.","operationId":"listSpaces","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Space"}}},"description":"The list of spaces accessible by the authenticated user"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List spaces","tags":["Spaces"]},"post":{"description":"Creates a new space based on a supplied name and description in the JSON request body. The endpoint is subject to rate limiting and automatically applies default configurations such as generating a random icon and initializing the workspace with default settings (for example, a default dashboard or home page). On success, the new space’s full metadata is returned, enabling the client to immediately switch context to the new internal.","operationId":"createSpace","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateSpaceRequest"}}},"description":"The space to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SpaceResponse"}}},"description":"The created space"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create space","tags":["Spaces"]}},"/spaces/{space_id}":{"get":{"description":"Fetches full details about a single space identified by its space ID. The response includes metadata such as the space name, icon, and various workspace IDs (home, archive, profile, etc.). This detailed view supports use cases such as displaying space-specific settings.","operationId":"getSpace","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to retrieve","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SpaceResponse"}}},"description":"The space details"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get space","tags":["Spaces"]},"patch":{"description":"Updates the name or description of an existing space. The request body should contain the new name and/or description in JSON format. This endpoint is useful for renaming or rebranding a workspace without needing to recreate it. The updated space’s metadata is returned in the response.","operationId":"updateSpace","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to update","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateSpaceRequest"}}},"description":"The space details to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SpaceResponse"}}},"description":"The updated space"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update space","tags":["Spaces"]}},"/spaces/{space_id}/lists/{list_id}/objects":{"post":{"description":"Adds one or more objects to a specific list (collection only) by submitting a JSON array of object IDs. Upon success, the endpoint returns a confirmation message. This endpoint is vital for building user interfaces that allow drag‑and‑drop or multi‑select additions to collections, enabling users to dynamically manage their collections without needing to modify the underlying object data.","operationId":"addListObjects","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the list belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list to which objects will be added","in":"path","name":"list_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array"}}},"description":"The list of object IDs to add to the list","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects added successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Add objects to list","tags":["Lists"]}},"/spaces/{space_id}/lists/{list_id}/objects/{object_id}":{"delete":{"description":"Removes a given object from the specified list (collection only) in a space. The endpoint takes the space, list, and object identifiers as path parameters and is subject to rate limiting. It is used for dynamically managing collections without affecting the underlying object data.","operationId":"removeListObject","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the list belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list from which the object will be removed","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to remove from the list","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects removed successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Remove object from list","tags":["Lists"]}},"/spaces/{space_id}/lists/{list_id}/views":{"get":{"description":"Returns a paginated list of views defined for a specific list (query or collection) within a space. Each view includes details such as layout, applied filters, and sorting options, enabling clients to render the list according to user preferences and context. This endpoint is essential for applications that need to display lists in various formats (e.g., grid, table) or with different sorting/filtering criteria.","operationId":"getListViews","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the list belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list to retrieve views for","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_View"}}},"description":"The list of views associated with the specified list"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get list views","tags":["Lists"]}},"/spaces/{space_id}/lists/{list_id}/{view_id}/objects":{"get":{"description":"Returns a paginated list of objects associated with a specific list (query or collection) within a space. When a view ID is provided, the objects are filtered and sorted according to the view's configuration. If no view ID is specified, all list objects are returned without filtering and sorting. This endpoint helps clients to manage grouped objects (for example, tasks within a list) by returning information for each item of the list.","operationId":"getListObjects","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the list belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list to retrieve objects for","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the view to retrieve objects for","in":"path","name":"view_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects associated with the specified list"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get objects in list","tags":["Lists"]}},"/spaces/{space_id}/members":{"get":{"description":"Returns a paginated list of members belonging to the specified space. Each member record includes the member’s profile ID, name, icon (which may be derived from an emoji or image), network identity, global name, status (e.g. joining, active) and role (e.g. Viewer, Editor, Owner). This endpoint supports collaborative features by allowing clients to show who is in a space and manage access rights.","operationId":"listMembers","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to list members for","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Member"}}},"description":"The list of members in the space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List members","tags":["Members"]}},"/spaces/{space_id}/members/{member_id}":{"get":{"description":"Fetches detailed information about a single member within a space. The endpoint returns the member’s identifier, name, icon, identity, global name, status and role. The member_id path parameter can be provided as either the member's ID (starting with ` + "`" + `_participant` + "`" + `) or the member's identity. This is useful for user profile pages, permission management, and displaying member-specific information in collaborative environments.","operationId":"getMember","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to get the member from","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Member ID or Identity","in":"path","name":"member_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.MemberResponse"}}},"description":"The member details"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Member not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get member","tags":["Members"]}},"/spaces/{space_id}/objects":{"get":{"description":"Retrieves a paginated list of objects in the given space. The endpoint takes query parameters for pagination (offset and limit) and returns detailed data about each object including its ID, name, icon, type information, a snippet of the content (if applicable), layout, space ID, blocks and details. It is intended for building views where users can see all objects in a space at a glance.","operationId":"listObjects","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which to list objects","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects in the specified space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List objects","tags":["Objects"]},"post":{"description":"Creates a new object in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include key details such as the object name, icon, description, body content (which may support Markdown), source URL (required for bookmark objects), template identifier, and the type_key (which is the non-unique identifier of the type of object to create). Post-creation, additional operations (like setting featured properties or fetching bookmark metadata) may occur. The endpoint then returns the full object data, ready for further interactions.","operationId":"createObject","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which to create the object","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateObjectRequest"}}},"description":"The object to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The created object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create object","tags":["Objects"]}},"/spaces/{space_id}/objects/{object_id}":{"delete":{"description":"This endpoint “deletes” an object by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the object’s details after it has been archived. Proper error handling is in place for situations such as when the object isn’t found or the deletion cannot be performed because of permission issues.","operationId":"deleteObject","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which the object exists","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to delete","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The deleted object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete object","tags":["Objects"]},"get":{"description":"Fetches the full details of a single object identified by the object ID within the specified space. The response includes not only basic metadata (ID, name, icon, type) but also the complete set of blocks (which may include text, files, properties and dataviews) and extra details (such as timestamps and linked member information). This endpoint is essential when a client needs to render or edit the full object view.","operationId":"getObject","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which the object exists","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to retrieve","in":"path","name":"object_id","required":true,"schema":{"type":"string"}},{"description":"The format to return the object body in","in":"query","name":"format","schema":{"default":"\"md\"","enum":["md"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The retrieved object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get object","tags":["Objects"]},"patch":{"description":"This endpoint updates an existing object in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the details to be updated. The endpoint then returns the full object data, ready for further interactions.","operationId":"updateObject","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which the object exists","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to update","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateObjectRequest"}}},"description":"The details of the object to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The updated object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update object","tags":["Objects"]}},"/spaces/{space_id}/properties":{"get":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ Retrieves a paginated list of properties available within a specific space. Each property record includes its unique identifier, name and format. This information is essential for clients to understand the available properties for filtering or creating objects.","operationId":"listProperties","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to list properties for","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Property"}}},"description":"The list of properties in the specified space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List properties","tags":["Properties"]},"post":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ Creates a new property in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include property details such as the name and format. The endpoint then returns the full property data, ready for further interactions.","operationId":"createProperty","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to create the property in","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreatePropertyRequest"}}},"description":"The property to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The created property"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create property","tags":["Properties"]}},"/spaces/{space_id}/properties/{property_id}":{"delete":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ This endpoint “deletes” a property by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the property’s details after it has been archived. Proper error handling is in place for situations such as when the property isn’t found or the deletion cannot be performed because of permission issues.","operationId":"deleteProperty","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the property belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to delete","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The deleted property"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete property","tags":["Properties"]},"get":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ Fetches detailed information about one specific property by its ID. This includes the property’s unique identifier, name and format. This detailed view assists clients in showing property options to users and in guiding the user interface (such as displaying appropriate input fields or selection options).","operationId":"getProperty","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the property belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to retrieve","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The requested property"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get property","tags":["Properties"]},"patch":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ This endpoint updates an existing property in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the name to be updated. The endpoint then returns the full property data, ready for further interactions.","operationId":"updateProperty","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the property belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to update","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdatePropertyRequest"}}},"description":"The property to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The updated property"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update property","tags":["Properties"]}},"/spaces/{space_id}/properties/{property_id}/tags":{"get":{"description":"This endpoint retrieves a paginated list of tags available for a specific property within a space. Each tag record includes its unique identifier, name, and color. This information is essential for clients to display select or multi-select options to users when they are creating or editing objects. The endpoint also supports pagination through offset and limit parameters.","operationId":"listTags","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to list tags for","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to list tags for","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Tag"}}},"description":"The list of tags"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Property not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List tags","tags":["Tags"]},"post":{"description":"This endpoint creates a new tag for a given property id in a space. The creation process is subject to rate limiting. The tag is identified by its unique identifier within the specified space. The request must include the tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to add new tag options to a property.","operationId":"createTag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to create the tag in","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to create the tag for","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateTagRequest"}}},"description":"The tag to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The created tag"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create tag","tags":["Tags"]}},"/spaces/{space_id}/properties/{property_id}/tags/{tag_id}":{"delete":{"description":"This endpoint “deletes” a tag by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the tag’s details after it has been archived. Proper error handling is in place for situations such as when the tag isn’t found or the deletion cannot be performed because of permission issues.","operationId":"deleteTag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to delete the tag from","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to delete the tag for","in":"path","name":"property_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the tag to delete","in":"path","name":"tag_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The deleted tag"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete tag","tags":["Tags"]},"get":{"description":"This endpoint retrieves a tag for a given property id. The tag is identified by its unique identifier within the specified space. The response includes the tag's details such as its ID, name, and color. This is useful for clients to display or when editing a specific tag option.","operationId":"getTag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to retrieve the tag from","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to retrieve the tag for","in":"path","name":"property_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the tag to retrieve","in":"path","name":"tag_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The retrieved tag"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get tag","tags":["Tags"]},"patch":{"description":"This endpoint updates a tag for a given property id in a space. The update process is subject to rate limiting. The tag is identified by its unique identifier within the specified space. The request must include the tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to edit existing tags for a property.","operationId":"updateTag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to update the tag in","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to update the tag for","in":"path","name":"property_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the tag to update","in":"path","name":"tag_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateTagRequest"}}},"description":"The tag to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The updated tag"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update tag","tags":["Tags"]}},"/spaces/{space_id}/search":{"post":{"description":"Performs a focused search within a single space (specified by the space_id path parameter). Like the global search, it accepts pagination parameters and a JSON payload containing the search query, object types, and sorting preferences. The search is limited to the provided space and returns a list of objects that match the query. This allows clients to implement space‑specific filtering without having to process extraneous results.","operationId":"searchSpace","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to search in","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SearchRequest"}}},"description":"The search parameters used to filter and sort the results","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects matching the search criteria"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects within a space","tags":["Search"]}},"/spaces/{space_id}/types":{"get":{"description":"This endpoint retrieves a paginated list of object types (e.g. 'Page', 'Note', 'Task') available within the specified space. Each type’s record includes its unique identifier, type key, display name, icon, and layout. While a type's id is truly unique, a type's key can be the same across spaces for known types, e.g. 'page' for 'Page'. Clients use this information when offering choices for object creation or for filtering objects by type through search.","operationId":"listTypes","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to retrieve types from","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Type"}}},"description":"The list of types"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List types","tags":["Types"]},"post":{"description":"Creates a new object type in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include type details such as the name, icon, and layout. The endpoint then returns the full type data, ready to be used for creating objects.","operationId":"createType","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which to create the type","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateTypeRequest"}}},"description":"The type to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The created type"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create type","tags":["Types"]}},"/spaces/{space_id}/types/{type_id}":{"delete":{"description":"This endpoint “deletes” an object type by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the type’s details after it has been archived. Proper error handling is in place for situations such as when the type isn’t found or the deletion cannot be performed because of permission issues.","operationId":"deleteType","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space from which to delete the type","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the type to delete","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The deleted type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete type","tags":["Types"]},"get":{"description":"Fetches detailed information about one specific object type by its ID. This includes the type’s unique key, name, icon, and layout. This detailed view assists clients in understanding the expected structure and style for objects of that type and in guiding the user interface (such as displaying appropriate icons or layout hints).","operationId":"getType","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space from which to retrieve the type","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the type to retrieve","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The requested type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get type","tags":["Types"]},"patch":{"description":"This endpoint updates an existing object type in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the name and properties to be updated. The endpoint then returns the full type data, ready for further interactions.","operationId":"updateType","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which the type exists","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the type to update","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateTypeRequest"}}},"description":"The type details to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The updated type"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update type","tags":["Types"]}},"/spaces/{space_id}/types/{type_id}/templates":{"get":{"description":"This endpoint returns a paginated list of templates that are associated with a specific object type within a space. Templates provide pre‑configured structures for creating new objects. Each template record contains its identifier, name, and icon, so that clients can offer users a selection of templates when creating objects.","operationId":"listTemplates","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the type belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object type to retrieve templates for","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"List of templates"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List templates","tags":["Templates"]}},"/spaces/{space_id}/types/{type_id}/templates/{template_id}":{"get":{"description":"Fetches full details for one template associated with a particular object type in a space. The response provides the template’s identifier, name, icon, and any other relevant metadata. This endpoint is useful when a client needs to preview or apply a template to prefill object creation fields.","operationId":"getTemplate","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the template belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object type to which the template belongs","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the template to retrieve","in":"path","name":"template_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TemplateResponse"}}},"description":"The requested template"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get template","tags":["Templates"]}}}, + "paths": {"/v1/auth/api_keys":{"post":{"description":"After receiving a ` + "`" + `challenge_id` + "`" + ` from the ` + "`" + `/v1/auth/challenges` + "`" + ` endpoint, the client calls this endpoint to provide the corresponding 4-digit code along with the challenge ID. The endpoint verifies that the challenge solution is correct and, if it is, returns an ` + "`" + `api_key` + "`" + `. This endpoint is central to the authentication process, as it validates the user's identity and issues a key that can be used for further interactions with the API.","operationId":"create_api_key","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the challenge to solve","in":"query","name":"challenge_id","required":true,"schema":{"type":"string"}},{"description":"The 4-digit code retrieved from Anytype Desktop app","in":"query","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateApiKeyResponse"}}},"description":"The API key that can be used in the Authorization header for subsequent requests"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Create API Key","tags":["Auth"]}},"/v1/auth/challenges":{"post":{"description":"Generates a one-time authentication challenge for granting API access to the user's vault. Upon providing a valid ` + "`" + `app_name` + "`" + `, the server issues a unique ` + "`" + `challenge_id` + "`" + ` and displays a 4-digit code within the Anytype Desktop. The ` + "`" + `challenge_id` + "`" + ` must then be used with the ` + "`" + `/v1/auth/api_keys` + "`" + ` endpoint to solve the challenge and retrieve an authentication token. This mechanism ensures that only trusted applications and authorized users gain access.","operationId":"create_auth_challenge","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The name of the app requesting API access","in":"query","name":"app_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateChallengeResponse"}}},"description":"The challenge ID associated with the started challenge"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Create Challenge","tags":["Auth"]}},"/v1/search":{"post":{"description":"Executes a global search over all spaces accessible to the authenticated user. The request body must specify the ` + "`" + `query` + "`" + ` text (currently matching only name and snippet of an object), optional filters on types (e.g., \"page\", \"task\"), and sort directives (default: descending by last modified date). Pagination is controlled via ` + "`" + `offset` + "`" + ` and ` + "`" + `limit` + "`" + ` query parameters to facilitate lazy loading in client UIs. The response returns a unified list of matched objects with their metadata and properties.","operationId":"search_global","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SearchRequest"}}},"description":"The search parameters used to filter and sort the results","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects matching the search criteria"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects across all spaces","tags":["Search"]}},"/v1/spaces":{"get":{"description":"Retrieves a paginated list of all spaces that are accessible by the authenticated user. Each space record contains detailed information such as the space ID, name, icon (derived either from an emoji or image URL), and additional metadata. This endpoint is key to displaying a user’s workspaces.","operationId":"list_spaces","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Space"}}},"description":"The list of spaces accessible by the authenticated user"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List spaces","tags":["Spaces"]},"post":{"description":"Creates a new space based on a supplied name and description in the JSON request body. The endpoint is subject to rate limiting and automatically applies default configurations such as generating a random icon and initializing the workspace with default settings (for example, a default dashboard or home page). On success, the new space’s full metadata is returned, enabling the client to immediately switch context to the new internal.","operationId":"create_space","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateSpaceRequest"}}},"description":"The space to create","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SpaceResponse"}}},"description":"The created space"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create space","tags":["Spaces"]}},"/v1/spaces/{space_id}":{"get":{"description":"Fetches full details about a single space identified by its space ID. The response includes metadata such as the space name, icon, and various workspace IDs (home, archive, profile, etc.). This detailed view supports use cases such as displaying space-specific settings.","operationId":"get_space","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to retrieve; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SpaceResponse"}}},"description":"The space details"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get space","tags":["Spaces"]},"patch":{"description":"Updates the name or description of an existing space. The request body should contain the new name and/or description in JSON format. This endpoint is useful for renaming or rebranding a workspace without needing to recreate it. The updated space’s metadata is returned in the response.","operationId":"update_space","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to update; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateSpaceRequest"}}},"description":"The space details to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SpaceResponse"}}},"description":"The updated space"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update space","tags":["Spaces"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects":{"post":{"description":"Adds one or more objects to a specific list (collection only) by submitting a JSON array of object IDs. Upon success, the endpoint returns a confirmation message. This endpoint is vital for building user interfaces that allow drag‑and‑drop or multi‑select additions to collections, enabling users to dynamically manage their collections without needing to modify the underlying object data.","operationId":"add_list_objects","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list to which objects will be added; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']","in":"path","name":"list_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.AddObjectsToListRequest"}}},"description":"The list of object IDs to add to the list; must be retrieved from SearchSpace or GlobalSearch endpoints or obtained from response context","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects added successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Add objects to list","tags":["Lists"]}},"/v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}":{"delete":{"description":"Removes a given object from the specified list (collection only) in a space. The endpoint takes the space, list, and object identifiers as path parameters and is subject to rate limiting. It is used for dynamically managing collections without affecting the underlying object data.","operationId":"remove_list_object","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list from which the object will be removed; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to remove from the list; must be retrieved from SearchSpace or GlobalSearch endpoints or obtained from response context","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects removed successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Remove object from list","tags":["Lists"]}},"/v1/spaces/{space_id}/lists/{list_id}/views":{"get":{"description":"Returns a paginated list of views defined for a specific list (query or collection) within a space. Each view includes details such as layout, applied filters, and sorting options, enabling clients to render the list according to user preferences and context. This endpoint is essential for applications that need to display lists in various formats (e.g., grid, table) or with different sorting/filtering criteria.","operationId":"get_list_views","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list to retrieve views for; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_View"}}},"description":"The list of views associated with the specified list"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get list views","tags":["Lists"]}},"/v1/spaces/{space_id}/lists/{list_id}/views/{view_id}/objects":{"get":{"description":"Returns a paginated list of objects associated with a specific list (query or collection) within a space. When a view ID is provided, the objects are filtered and sorted according to the view's configuration. If no view ID is specified, all list objects are returned without filtering and sorting. This endpoint helps clients to manage grouped objects (for example, tasks within a list) by returning information for each item of the list.","operationId":"get_list_objects","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list to retrieve objects for; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the view to retrieve objects for; must be retrieved from ListViews endpoint or omitted if you want to get all objects in the list","in":"path","name":"view_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects associated with the specified list"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get objects in list","tags":["Lists"]}},"/v1/spaces/{space_id}/members":{"get":{"description":"Returns a paginated list of members belonging to the specified space. Each member record includes the member’s profile ID, name, icon (which may be derived from an emoji or image), network identity, global name, status (e.g. joining, active) and role (e.g. Viewer, Editor, Owner). This endpoint supports collaborative features by allowing clients to show who is in a space and manage access rights.","operationId":"list_members","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to list members for; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Member"}}},"description":"The list of members in the space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List members","tags":["Members"]}},"/v1/spaces/{space_id}/members/{member_id}":{"get":{"description":"Fetches detailed information about a single member within a space. The endpoint returns the member’s identifier, name, icon, identity, global name, status and role. The member_id path parameter can be provided as either the member's ID (starting with ` + "`" + `_participant` + "`" + `) or the member's identity. This is useful for user profile pages, permission management, and displaying member-specific information in collaborative environments.","operationId":"get_member","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to get the member from; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Member ID or Identity; must be retrieved from ListMembers endpoint or obtained from response context","in":"path","name":"member_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.MemberResponse"}}},"description":"The member details"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Member not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get member","tags":["Members"]}},"/v1/spaces/{space_id}/objects":{"get":{"description":"Retrieves a paginated list of objects in the given space. The endpoint takes query parameters for pagination (offset and limit) and returns detailed data about each object including its ID, name, icon, type information, a snippet of the content (if applicable), layout, space ID, blocks and details. It is intended for building views where users can see all objects in a space at a glance.","operationId":"list_objects","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space in which to list objects; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects in the specified space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List objects","tags":["Objects"]},"post":{"description":"Creates a new object in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include key details such as the object name, icon, description, body content (which may support Markdown), source URL (required for bookmark objects), template identifier, and the type_key (which is the non-unique identifier of the type of object to create). Post-creation, additional operations (like setting featured properties or fetching bookmark metadata) may occur. The endpoint then returns the full object data, ready for further interactions.","operationId":"create_object","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space in which to create the object; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateObjectRequest"}}},"description":"The object to create","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The created object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create object","tags":["Objects"]}},"/v1/spaces/{space_id}/objects/{object_id}":{"delete":{"description":"This endpoint “deletes” an object by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the object’s details after it has been archived. Proper error handling is in place for situations such as when the object isn’t found or the deletion cannot be performed because of permission issues.","operationId":"delete_object","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space in which the object exists; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to delete; must be retrieved from ListObjects, SearchSpace or GlobalSearch endpoints or obtained from response context","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The deleted object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete object","tags":["Objects"]},"get":{"description":"Fetches the full details of a single object identified by the object ID within the specified space. The response includes not only basic metadata (ID, name, icon, type) but also the complete set of blocks (which may include text, files, properties and dataviews) and extra details (such as timestamps and linked member information). This endpoint is essential when a client needs to render or edit the full object view.","operationId":"get_object","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space in which the object exists; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to retrieve; must be retrieved from ListObjects, SearchSpace or GlobalSearch endpoints or obtained from response context","in":"path","name":"object_id","required":true,"schema":{"type":"string"}},{"description":"The format to return the object body in","in":"query","name":"format","schema":{"default":"\"md\"","enum":["md"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The retrieved object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get object","tags":["Objects"]},"patch":{"description":"This endpoint updates an existing object in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the details to be updated. The endpoint then returns the full object data, ready for further interactions.","operationId":"update_object","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space in which the object exists; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to update; must be retrieved from ListObjects, SearchSpace or GlobalSearch endpoints or obtained from response context","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateObjectRequest"}}},"description":"The details of the object to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The updated object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update object","tags":["Objects"]}},"/v1/spaces/{space_id}/properties":{"get":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ Retrieves a paginated list of properties available within a specific space. Each property record includes its unique identifier, name and format. This information is essential for clients to understand the available properties for filtering or creating objects.","operationId":"list_properties","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to list properties for; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Property"}}},"description":"The list of properties in the specified space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List properties","tags":["Properties"]},"post":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ Creates a new property in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include property details such as the name and format. The endpoint then returns the full property data, ready for further interactions.","operationId":"create_property","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to create the property in; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreatePropertyRequest"}}},"description":"The property to create","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The created property"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create property","tags":["Properties"]}},"/v1/spaces/{space_id}/properties/{property_id}":{"delete":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ This endpoint “deletes” a property by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the property’s details after it has been archived. Proper error handling is in place for situations such as when the property isn’t found or the deletion cannot be performed because of permission issues.","operationId":"delete_property","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to which the property belongs; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to delete; must be retrieved from ListProperties endpoint or obtained from response context","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The deleted property"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete property","tags":["Properties"]},"get":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ Fetches detailed information about one specific property by its ID. This includes the property’s unique identifier, name and format. This detailed view assists clients in showing property options to users and in guiding the user interface (such as displaying appropriate input fields or selection options).","operationId":"get_property","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to which the property belongs; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to retrieve; must be retrieved from ListProperties endpoint or obtained from response context","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The requested property"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get property","tags":["Properties"]},"patch":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ This endpoint updates an existing property in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the name to be updated. The endpoint then returns the full property data, ready for further interactions.","operationId":"update_property","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to which the property belongs; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to update; must be retrieved from ListProperties endpoint or obtained from response context","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdatePropertyRequest"}}},"description":"The property to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The updated property"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update property","tags":["Properties"]}},"/v1/spaces/{space_id}/properties/{property_id}/tags":{"get":{"description":"This endpoint retrieves a paginated list of tags available for a specific property within a space. Each tag record includes its unique identifier, name, and color. This information is essential for clients to display select or multi-select options to users when they are creating or editing objects. The endpoint also supports pagination through offset and limit parameters.","operationId":"list_tags","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to list tags for; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to list tags for; must be retrieved from ListProperties endpoint or obtained from response context","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Tag"}}},"description":"The list of tags"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Property not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List tags","tags":["Tags"]},"post":{"description":"This endpoint creates a new tag for a given property id in a space. The creation process is subject to rate limiting. The tag is identified by its unique identifier within the specified space. The request must include the tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to add new tag options to a property.","operationId":"create_tag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to create the tag in; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to create the tag for; must be retrieved from ListProperties endpoint or obtained from response context","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateTagRequest"}}},"description":"The tag to create","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The created tag"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create tag","tags":["Tags"]}},"/v1/spaces/{space_id}/properties/{property_id}/tags/{tag_id}":{"delete":{"description":"This endpoint “deletes” a tag by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the tag’s details after it has been archived. Proper error handling is in place for situations such as when the tag isn’t found or the deletion cannot be performed because of permission issues.","operationId":"delete_tag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to delete the tag from; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to delete the tag for; must be retrieved from ListProperties endpoint or obtained from response context","in":"path","name":"property_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the tag to delete; must be retrieved from ListTags endpoint or obtained from response context","in":"path","name":"tag_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The deleted tag"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete tag","tags":["Tags"]},"get":{"description":"This endpoint retrieves a tag for a given property id. The tag is identified by its unique identifier within the specified space. The response includes the tag's details such as its ID, name, and color. This is useful for clients to display or when editing a specific tag option.","operationId":"get_tag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to retrieve the tag from; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to retrieve the tag for; must be retrieved from ListProperties endpoint or obtained from response context","in":"path","name":"property_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the tag to retrieve; must be retrieved from ListTags endpoint or obtained from response context","in":"path","name":"tag_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The retrieved tag"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get tag","tags":["Tags"]},"patch":{"description":"This endpoint updates a tag for a given property id in a space. The update process is subject to rate limiting. The tag is identified by its unique identifier within the specified space. The request must include the tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to edit existing tags for a property.","operationId":"update_tag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to update the tag in; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to update the tag for; must be retrieved from ListProperties endpoint or obtained from response context","in":"path","name":"property_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the tag to update; must be retrieved from ListTags endpoint or obtained from response context","in":"path","name":"tag_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateTagRequest"}}},"description":"The tag to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The updated tag"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update tag","tags":["Tags"]}},"/v1/spaces/{space_id}/search":{"post":{"description":"Performs a search within a single space (specified by the ` + "`" + `space_id` + "`" + ` path parameter). Like the global search, it accepts pagination parameters and a JSON payload containing the search ` + "`" + `query` + "`" + `, ` + "`" + `types` + "`" + `, and sorting preferences. The search is limited to the provided space and returns a list of objects that match the query. This allows clients to implement space‑specific filtering without having to process extraneous results.","operationId":"search_space","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to search in; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SearchRequest"}}},"description":"The search parameters used to filter and sort the results","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects matching the search criteria"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects within a space","tags":["Search"]}},"/v1/spaces/{space_id}/types":{"get":{"description":"This endpoint retrieves a paginated list of types (e.g. 'Page', 'Note', 'Task') available within the specified space. Each type’s record includes its unique identifier, type key, display name, icon, and layout. While a type's id is truly unique, a type's key can be the same across spaces for known types, e.g. 'page' for 'Page'. Clients use this information when offering choices for object creation or for filtering objects by type through search.","operationId":"list_types","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to retrieve types from; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Type"}}},"description":"The list of types"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List types","tags":["Types"]},"post":{"description":"Creates a new type in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include type details such as the name, icon, and layout. The endpoint then returns the full type data, ready to be used for creating objects.","operationId":"create_type","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space in which to create the type; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateTypeRequest"}}},"description":"The type to create","required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The created type"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create type","tags":["Types"]}},"/v1/spaces/{space_id}/types/{type_id}":{"delete":{"description":"This endpoint “deletes” an type by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the type’s details after it has been archived. Proper error handling is in place for situations such as when the type isn’t found or the deletion cannot be performed because of permission issues.","operationId":"delete_type","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space from which to delete the type; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the type to delete; must be retrieved from ListTypes endpoint or obtained from response context","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The deleted type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete type","tags":["Types"]},"get":{"description":"Fetches detailed information about one specific type by its ID. This includes the type’s unique key, name, icon, and layout. This detailed view assists clients in understanding the expected structure and style for objects of that type and in guiding the user interface (such as displaying appropriate icons or layout hints).","operationId":"get_type","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space from which to retrieve the type; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the type to retrieve; must be retrieved from ListTypes endpoint or obtained from response context","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The requested type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get type","tags":["Types"]},"patch":{"description":"This endpoint updates an existing type in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the name and properties to be updated. The endpoint then returns the full type data, ready for further interactions.","operationId":"update_type","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space in which the type exists; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the type to update; must be retrieved from ListTypes endpoint or obtained from response context","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateTypeRequest"}}},"description":"The type details to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The updated type"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update type","tags":["Types"]}},"/v1/spaces/{space_id}/types/{type_id}/templates":{"get":{"description":"This endpoint returns a paginated list of templates that are associated with a specific type within a space. Templates provide pre‑configured structures for creating new objects. Each template record contains its identifier, name, and icon, so that clients can offer users a selection of templates when creating objects.","operationId":"list_templates","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to which the type belongs; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the type to retrieve templates for; must be retrieved from ListTypes endpoint or obtained from response context","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"List of templates"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List templates","tags":["Templates"]}},"/v1/spaces/{space_id}/types/{type_id}/templates/{template_id}":{"get":{"description":"Fetches full details for one template associated with a particular type in a space. The response provides the template’s identifier, name, icon, and any other relevant metadata. This endpoint is useful when a client needs to preview or apply a template to prefill object creation fields.","operationId":"get_template","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-05-20","type":"string"}},{"description":"The ID of the space to which the template belongs; must be retrieved from ListSpaces endpoint","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the type to which the template belongs; must be retrieved from ListTypes endpoint or obtained from response context","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the template to retrieve; must be retrieved from ListTemplates endpoint or obtained from response context","in":"path","name":"template_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TemplateResponse"}}},"description":"The requested template"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get template","tags":["Templates"]}}}, "openapi": "3.1.0", "servers": [ - {"url":"http://localhost:31009/v1"} + {"url":"http://localhost:31009"} ] }` // SwaggerInfo holds exported Swagger Info so clients can modify it var SwaggerInfo = &swag.Spec{ - Version: "2025-04-22", + Version: "2025-05-20", Title: "Anytype API", - Description: "This API empowers seamless interaction with Anytype's resources—spaces, objects, properties, types, templates, and beyond.", + Description: "This API enables seamless interaction with Anytype's resources - spaces, objects, properties, types, templates, and beyond.", InfoInstanceName: "swagger", SwaggerTemplate: docTemplate, LeftDelim: "{{", diff --git a/core/api/docs/openapi.json b/core/api/docs/openapi.json new file mode 100644 index 000000000..75acd4100 --- /dev/null +++ b/core/api/docs/openapi.json @@ -0,0 +1,6072 @@ +{ + "components": { + "schemas": { + "apimodel.AddObjectsToListRequest": { + "properties": { + "objects": { + "description": "The list of object IDs to add to the list", + "example": [ + "[\"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ\"]" + ], + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "apimodel.CheckboxPropertyLinkValue": { + "properties": { + "checkbox": { + "description": "The checkbox value of the property", + "example": true, + "type": "boolean" + }, + "key": { + "example": "done", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.CheckboxPropertyValue": { + "properties": { + "checkbox": { + "description": "The checkbox value of the property", + "example": true, + "type": "boolean" + }, + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "done", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Done", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.Color": { + "description": "The color of the icon", + "enum": [ + "grey", + "yellow", + "orange", + "red", + "pink", + "purple", + "blue", + "ice", + "teal", + "lime" + ], + "example": "yellow", + "type": "string", + "x-enum-varnames": [ + "ColorGrey", + "ColorYellow", + "ColorOrange", + "ColorRed", + "ColorPink", + "ColorPurple", + "ColorBlue", + "ColorIce", + "ColorTeal", + "ColorLime" + ] + }, + "apimodel.CreateApiKeyResponse": { + "properties": { + "api_key": { + "description": "The api key used to authenticate requests", + "example": "zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.CreateChallengeResponse": { + "properties": { + "challenge_id": { + "description": "The challenge id associated with the displayed code and needed to solve the challenge for api_key", + "example": "67647f5ecda913e9a2e11b26", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.CreateObjectRequest": { + "properties": { + "body": { + "description": "The body of the object", + "example": "This is the body of the object. Markdown syntax is supported here.", + "type": "string" + }, + "icon": { + "$ref": "#/components/schemas/apimodel.Icon" + }, + "name": { + "description": "The name of the object", + "example": "My object", + "type": "string" + }, + "properties": { + "description": "⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set on the object; see ListTypes or GetType endpoints for linked properties", + "items": { + "$ref": "#/components/schemas/apimodel.PropertyLinkWithValue" + }, + "type": "array", + "uniqueItems": false + }, + "template_id": { + "description": "The id of the template to use", + "example": "bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge", + "type": "string" + }, + "type_key": { + "description": "The key of the type of object to create", + "example": "page", + "type": "string" + } + }, + "required": [ + "type_key" + ], + "type": "object" + }, + "apimodel.CreatePropertyRequest": { + "properties": { + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "key": { + "description": "The key of the property; should always be snake_case, otherwise it will be converted to snake_case", + "example": "some_user_defined_property_key", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Last modified date", + "type": "string" + } + }, + "required": [ + "format", + "name" + ], + "type": "object" + }, + "apimodel.CreateSpaceRequest": { + "properties": { + "description": { + "description": "The description of the space", + "example": "The local-first wiki", + "type": "string" + }, + "name": { + "description": "The name of the space", + "example": "New Space", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "apimodel.CreateTagRequest": { + "properties": { + "color": { + "$ref": "#/components/schemas/apimodel.Color" + }, + "name": { + "description": "The name of the tag", + "example": "In progress", + "type": "string" + } + }, + "required": [ + "color", + "name" + ], + "type": "object" + }, + "apimodel.CreateTypeRequest": { + "properties": { + "icon": { + "$ref": "#/components/schemas/apimodel.Icon" + }, + "key": { + "description": "The key of the type; should always be snake_case, otherwise it will be converted to snake_case", + "example": "some_user_defined_type_key", + "type": "string" + }, + "layout": { + "$ref": "#/components/schemas/apimodel.TypeLayout" + }, + "name": { + "description": "The name of the type", + "example": "Page", + "type": "string" + }, + "plural_name": { + "description": "The plural name of the type", + "example": "Pages", + "type": "string" + }, + "properties": { + "description": "⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties linked to the type", + "items": { + "$ref": "#/components/schemas/apimodel.PropertyLink" + }, + "type": "array", + "uniqueItems": false + } + }, + "required": [ + "layout", + "name", + "plural_name" + ], + "type": "object" + }, + "apimodel.DatePropertyLinkValue": { + "properties": { + "date": { + "description": "The date value of the property", + "example": "2025-02-14T12:34:56Z", + "type": "string" + }, + "key": { + "example": "last_modified_date", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.DatePropertyValue": { + "properties": { + "date": { + "description": "The date value of the property", + "example": "2025-02-14T12:34:56Z", + "type": "string" + }, + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "last_modified_date", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Last modified date", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.EmailPropertyLinkValue": { + "properties": { + "email": { + "description": "The email value of the property", + "example": "example@example.com", + "type": "string" + }, + "key": { + "example": "email", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.EmailPropertyValue": { + "properties": { + "email": { + "description": "The email value of the property", + "example": "example@example.com", + "type": "string" + }, + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "email", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Email", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.EmojiIcon": { + "properties": { + "emoji": { + "description": "The emoji of the icon", + "example": "📄", + "type": "string" + }, + "format": { + "$ref": "#/components/schemas/apimodel.IconFormat" + } + }, + "type": "object" + }, + "apimodel.FileIcon": { + "properties": { + "file": { + "description": "The file of the icon", + "example": "bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay", + "type": "string" + }, + "format": { + "$ref": "#/components/schemas/apimodel.IconFormat" + } + }, + "type": "object" + }, + "apimodel.FilesPropertyLinkValue": { + "properties": { + "files": { + "description": "The file ids of the property", + "example": [ + "['file_id']" + ], + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + }, + "key": { + "example": "files", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.FilesPropertyValue": { + "properties": { + "files": { + "description": "The file values of the property", + "example": [ + "['file_id']" + ], + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + }, + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "files", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Files", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.Filter": { + "properties": { + "condition": { + "description": "The filter condition", + "enum": [ + "equal", + "not_equal", + "greater", + "less", + "greater_or_equal", + "less_or_equal", + "like", + "not_like", + "in", + "not_in", + "empty", + "not_empty", + "all_in", + "not_all_in", + "exact_in", + "not_exact_in", + "exists" + ], + "example": "contains", + "type": "string" + }, + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the filter", + "example": "67bf3f21cda9134102e2422c", + "type": "string" + }, + "property_key": { + "description": "The property key used for filtering", + "example": "name", + "type": "string" + }, + "value": { + "description": "The value used for filtering", + "example": "Some value...", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.Icon": { + "description": "The icon of the object", + "oneOf": [ + { + "$ref": "#/components/schemas/apimodel.EmojiIcon" + }, + { + "$ref": "#/components/schemas/apimodel.FileIcon" + }, + { + "$ref": "#/components/schemas/apimodel.NamedIcon" + } + ], + "type": "object" + }, + "apimodel.IconFormat": { + "description": "The format of the icon", + "enum": [ + "emoji", + "file", + "icon" + ], + "type": "string", + "x-enum-varnames": [ + "IconFormatEmoji", + "IconFormatFile", + "IconFormatIcon" + ] + }, + "apimodel.IconName": { + "description": "The name of the icon", + "example": "document", + "type": "string", + "x-enum-varnames": [ + "IconNameAccessibility", + "IconNameAddCircle", + "IconNameAirplane", + "IconNameAlarm", + "IconNameAlbums", + "IconNameAlertCircle", + "IconNameAmericanFootball", + "IconNameAnalytics", + "IconNameAperture", + "IconNameApps", + "IconNameArchive", + "IconNameArrowBackCircle", + "IconNameArrowDownCircle", + "IconNameArrowForwardCircle", + "IconNameArrowRedoCircle", + "IconNameArrowRedo", + "IconNameArrowUndoCircle", + "IconNameArrowUndo", + "IconNameArrowUpCircle", + "IconNameAtCircle", + "IconNameAttach", + "IconNameBackspace", + "IconNameBagAdd", + "IconNameBagCheck", + "IconNameBagHandle", + "IconNameBagRemove", + "IconNameBag", + "IconNameBalloon", + "IconNameBan", + "IconNameBandage", + "IconNameBarChart", + "IconNameBarbell", + "IconNameBarcode", + "IconNameBaseball", + "IconNameBasket", + "IconNameBasketball", + "IconNameBatteryCharging", + "IconNameBatteryDead", + "IconNameBatteryFull", + "IconNameBatteryHalf", + "IconNameBeaker", + "IconNameBed", + "IconNameBeer", + "IconNameBicycle", + "IconNameBinoculars", + "IconNameBluetooth", + "IconNameBoat", + "IconNameBody", + "IconNameBonfire", + "IconNameBook", + "IconNameBookmark", + "IconNameBookmarks", + "IconNameBowlingBall", + "IconNameBriefcase", + "IconNameBrowsers", + "IconNameBrush", + "IconNameBug", + "IconNameBuild", + "IconNameBulb", + "IconNameBus", + "IconNameBusiness", + "IconNameCafe", + "IconNameCalculator", + "IconNameCalendarClear", + "IconNameCalendarNumber", + "IconNameCalendar", + "IconNameCall", + "IconNameCameraReverse", + "IconNameCamera", + "IconNameCarSport", + "IconNameCar", + "IconNameCard", + "IconNameCaretBackCircle", + "IconNameCaretBack", + "IconNameCaretDownCircle", + "IconNameCaretDown", + "IconNameCaretForwardCircle", + "IconNameCaretForward", + "IconNameCaretUpCircle", + "IconNameCaretUp", + "IconNameCart", + "IconNameCash", + "IconNameCellular", + "IconNameChatboxEllipses", + "IconNameChatbox", + "IconNameChatbubbleEllipses", + "IconNameChatbubble", + "IconNameChatbubbles", + "IconNameCheckbox", + "IconNameCheckmarkCircle", + "IconNameCheckmarkDoneCircle", + "IconNameChevronBackCircle", + "IconNameChevronDownCircle", + "IconNameChevronForwardCircle", + "IconNameChevronUpCircle", + "IconNameClipboard", + "IconNameCloseCircle", + "IconNameCloudCircle", + "IconNameCloudDone", + "IconNameCloudDownload", + "IconNameCloudOffline", + "IconNameCloudUpload", + "IconNameCloud", + "IconNameCloudyNight", + "IconNameCloudy", + "IconNameCodeSlash", + "IconNameCode", + "IconNameCog", + "IconNameColorFill", + "IconNameColorFilter", + "IconNameColorPalette", + "IconNameColorWand", + "IconNameCompass", + "IconNameConstruct", + "IconNameContact", + "IconNameContract", + "IconNameContrast", + "IconNameCopy", + "IconNameCreate", + "IconNameCrop", + "IconNameCube", + "IconNameCut", + "IconNameDesktop", + "IconNameDiamond", + "IconNameDice", + "IconNameDisc", + "IconNameDocumentAttach", + "IconNameDocumentLock", + "IconNameDocumentText", + "IconNameDocument", + "IconNameDocuments", + "IconNameDownload", + "IconNameDuplicate", + "IconNameEar", + "IconNameEarth", + "IconNameEasel", + "IconNameEgg", + "IconNameEllipse", + "IconNameEllipsisHorizontalCircle", + "IconNameEllipsisVerticalCircle", + "IconNameEnter", + "IconNameExit", + "IconNameExpand", + "IconNameExtensionPuzzle", + "IconNameEyeOff", + "IconNameEye", + "IconNameEyedrop", + "IconNameFastFood", + "IconNameFemale", + "IconNameFileTrayFull", + "IconNameFileTrayStacked", + "IconNameFileTray", + "IconNameFilm", + "IconNameFilterCircle", + "IconNameFingerPrint", + "IconNameFish", + "IconNameFitness", + "IconNameFlag", + "IconNameFlame", + "IconNameFlashOff", + "IconNameFlash", + "IconNameFlashlight", + "IconNameFlask", + "IconNameFlower", + "IconNameFolderOpen", + "IconNameFolder", + "IconNameFootball", + "IconNameFootsteps", + "IconNameFunnel", + "IconNameGameController", + "IconNameGift", + "IconNameGitBranch", + "IconNameGitCommit", + "IconNameGitCompare", + "IconNameGitMerge", + "IconNameGitNetwork", + "IconNameGitPullRequest", + "IconNameGlasses", + "IconNameGlobe", + "IconNameGolf", + "IconNameGrid", + "IconNameHammer", + "IconNameHandLeft", + "IconNameHandRight", + "IconNameHappy", + "IconNameHardwareChip", + "IconNameHeadset", + "IconNameHeartCircle", + "IconNameHeartDislikeCircle", + "IconNameHeartDislike", + "IconNameHeartHalf", + "IconNameHeart", + "IconNameHelpBuoy", + "IconNameHelpCircle", + "IconNameHome", + "IconNameHourglass", + "IconNameIceCream", + "IconNameIdCard", + "IconNameImage", + "IconNameImages", + "IconNameInfinite", + "IconNameInformationCircle", + "IconNameInvertMode", + "IconNameJournal", + "IconNameKey", + "IconNameKeypad", + "IconNameLanguage", + "IconNameLaptop", + "IconNameLayers", + "IconNameLeaf", + "IconNameLibrary", + "IconNameLink", + "IconNameListCircle", + "IconNameList", + "IconNameLocate", + "IconNameLocation", + "IconNameLockClosed", + "IconNameLockOpen", + "IconNameLogIn", + "IconNameLogOut", + "IconNameLogoAlipay", + "IconNameLogoAmazon", + "IconNameLogoAmplify", + "IconNameLogoAndroid", + "IconNameMagnet", + "IconNameMailOpen", + "IconNameMailUnread", + "IconNameMail", + "IconNameMaleFemale", + "IconNameMale", + "IconNameMan", + "IconNameMap", + "IconNameMedal", + "IconNameMedical", + "IconNameMedkit", + "IconNameMegaphone", + "IconNameMenu", + "IconNameMicCircle", + "IconNameMicOffCircle", + "IconNameMicOff", + "IconNameMic", + "IconNameMoon", + "IconNameMove", + "IconNameMusicalNote", + "IconNameMusicalNotes", + "IconNameNavigateCircle", + "IconNameNavigate", + "IconNameNewspaper", + "IconNameNotificationsCircle", + "IconNameNotificationsOffCircle", + "IconNameNotificationsOff", + "IconNameNotifications", + "IconNameNuclear", + "IconNameNutrition", + "IconNameOptions", + "IconNamePaperPlane", + "IconNamePartlySunny", + "IconNamePauseCircle", + "IconNamePause", + "IconNamePaw", + "IconNamePencil", + "IconNamePeopleCircle", + "IconNamePeople", + "IconNamePersonAdd", + "IconNamePersonCircle", + "IconNamePersonRemove", + "IconNamePerson", + "IconNamePhoneLandscape", + "IconNamePhonePortrait", + "IconNamePieChart", + "IconNamePin", + "IconNamePint", + "IconNamePizza", + "IconNamePlanet", + "IconNamePlayBackCircle", + "IconNamePlayBack", + "IconNamePlayCircle", + "IconNamePlayForwardCircle", + "IconNamePlayForward", + "IconNamePlaySkipBackCircle", + "IconNamePlaySkipBack", + "IconNamePlaySkipForwardCircle", + "IconNamePlaySkipForward", + "IconNamePlay", + "IconNamePodium", + "IconNamePower", + "IconNamePricetag", + "IconNamePricetags", + "IconNamePrint", + "IconNamePrism", + "IconNamePulse", + "IconNamePush", + "IconNameQrCode", + "IconNameRadioButtonOff", + "IconNameRadioButtonOn", + "IconNameRadio", + "IconNameRainy", + "IconNameReader", + "IconNameReceipt", + "IconNameRecording", + "IconNameRefreshCircle", + "IconNameRefresh", + "IconNameReloadCircle", + "IconNameReload", + "IconNameRemoveCircle", + "IconNameRepeat", + "IconNameResize", + "IconNameRestaurant", + "IconNameRibbon", + "IconNameRocket", + "IconNameRose", + "IconNameSad", + "IconNameSave", + "IconNameScale", + "IconNameScanCircle", + "IconNameScan", + "IconNameSchool", + "IconNameSearchCircle", + "IconNameSearch", + "IconNameSend", + "IconNameServer", + "IconNameSettings", + "IconNameShapes", + "IconNameShareSocial", + "IconNameShare", + "IconNameShieldCheckmark", + "IconNameShieldHalf", + "IconNameShield", + "IconNameShirt", + "IconNameShuffle", + "IconNameSkull", + "IconNameSnow", + "IconNameSparkles", + "IconNameSpeedometer", + "IconNameSquare", + "IconNameStarHalf", + "IconNameStar", + "IconNameStatsChart", + "IconNameStopCircle", + "IconNameStop", + "IconNameStopwatch", + "IconNameStorefront", + "IconNameSubway", + "IconNameSunny", + "IconNameSwapHorizontal", + "IconNameSwapVertical", + "IconNameSyncCircle", + "IconNameSync", + "IconNameTabletLandscape", + "IconNameTabletPortrait", + "IconNameTelescope", + "IconNameTennisball", + "IconNameTerminal", + "IconNameText", + "IconNameThermometer", + "IconNameThumbsDown", + "IconNameThumbsUp", + "IconNameThunderstorm", + "IconNameTicket", + "IconNameTime", + "IconNameTimer", + "IconNameToday", + "IconNameToggle", + "IconNameTrailSign", + "IconNameTrain", + "IconNameTransgender", + "IconNameTrashBin", + "IconNameTrash", + "IconNameTrendingDown", + "IconNameTrendingUp", + "IconNameTriangle", + "IconNameTrophy", + "IconNameTv", + "IconNameUmbrella", + "IconNameUnlink", + "IconNameVideocamOff", + "IconNameVideocam", + "IconNameVolumeHigh", + "IconNameVolumeLow", + "IconNameVolumeMedium", + "IconNameVolumeMute", + "IconNameVolumeOff", + "IconNameWalk", + "IconNameWallet", + "IconNameWarning", + "IconNameWatch", + "IconNameWater", + "IconNameWifi", + "IconNameWine", + "IconNameWoman" + ] + }, + "apimodel.Member": { + "description": "The member", + "properties": { + "global_name": { + "description": "The global name of the member in the network", + "example": "john.any", + "type": "string" + }, + "icon": { + "$ref": "#/components/schemas/apimodel.Icon" + }, + "id": { + "description": "The profile object id of the member", + "example": "_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ", + "type": "string" + }, + "identity": { + "description": "The identity of the member in the network", + "example": "AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ", + "type": "string" + }, + "name": { + "description": "The name of the member", + "example": "John Doe", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "member", + "type": "string" + }, + "role": { + "description": "The role of the member", + "enum": [ + "viewer", + "editor", + "owner", + "no_permission" + ], + "example": "owner", + "type": "string" + }, + "status": { + "description": "The status of the member", + "enum": [ + "joining", + "active", + "removed", + "declined", + "removing", + "canceled" + ], + "example": "active", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.MemberResponse": { + "properties": { + "member": { + "$ref": "#/components/schemas/apimodel.Member" + } + }, + "type": "object" + }, + "apimodel.MultiSelectPropertyLinkValue": { + "properties": { + "key": { + "example": "tag", + "type": "string" + }, + "multi_select": { + "description": "The selected tag ids of the property; see ListTags endpoint for valid values", + "example": [ + "['tag_id']" + ], + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "apimodel.MultiSelectPropertyValue": { + "properties": { + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "tag", + "type": "string" + }, + "multi_select": { + "description": "The selected tag values of the property", + "items": { + "$ref": "#/components/schemas/apimodel.Tag" + }, + "type": "array", + "uniqueItems": false + }, + "name": { + "description": "The name of the property", + "example": "Tag", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.NamedIcon": { + "properties": { + "color": { + "$ref": "#/components/schemas/apimodel.Color" + }, + "format": { + "$ref": "#/components/schemas/apimodel.IconFormat" + }, + "name": { + "$ref": "#/components/schemas/apimodel.IconName" + } + }, + "type": "object" + }, + "apimodel.NumberPropertyLinkValue": { + "properties": { + "key": { + "example": "height", + "type": "string" + }, + "number": { + "description": "The number value of the property", + "example": 42, + "type": "number" + } + }, + "type": "object" + }, + "apimodel.NumberPropertyValue": { + "properties": { + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "height", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Height", + "type": "string" + }, + "number": { + "description": "The number value of the property", + "example": 42, + "type": "number" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.Object": { + "properties": { + "archived": { + "description": "Whether the object is archived", + "example": false, + "type": "boolean" + }, + "icon": { + "$ref": "#/components/schemas/apimodel.Icon" + }, + "id": { + "description": "The id of the object", + "example": "bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ", + "type": "string" + }, + "layout": { + "$ref": "#/components/schemas/apimodel.ObjectLayout" + }, + "name": { + "description": "The name of the object", + "example": "My object", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "object", + "type": "string" + }, + "properties": { + "description": "The properties of the object", + "items": { + "$ref": "#/components/schemas/apimodel.PropertyWithValue" + }, + "type": "array", + "uniqueItems": false + }, + "snippet": { + "description": "The snippet of the object, especially important for notes as they don't have a name", + "example": "The beginning of the object body...", + "type": "string" + }, + "space_id": { + "description": "The id of the space the object is in", + "example": "bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1", + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/apimodel.Type" + } + }, + "type": "object" + }, + "apimodel.ObjectLayout": { + "description": "The layout of the object", + "example": "basic", + "type": "string", + "x-enum-varnames": [ + "ObjectLayoutBasic", + "ObjectLayoutProfile", + "ObjectLayoutAction", + "ObjectLayoutNote", + "ObjectLayoutBookmark", + "ObjectLayoutSet", + "ObjectLayoutCollection", + "ObjectLayoutParticipant" + ] + }, + "apimodel.ObjectResponse": { + "properties": { + "object": { + "$ref": "#/components/schemas/apimodel.ObjectWithBody" + } + }, + "type": "object" + }, + "apimodel.ObjectWithBody": { + "description": "The object", + "properties": { + "archived": { + "description": "Whether the object is archived", + "example": false, + "type": "boolean" + }, + "icon": { + "$ref": "#/components/schemas/apimodel.Icon" + }, + "id": { + "description": "The id of the object", + "example": "bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ", + "type": "string" + }, + "layout": { + "description": "The layout of the object", + "example": "basic", + "type": "string", + "x-enum-varnames": [ + "ObjectLayoutBasic", + "ObjectLayoutProfile", + "ObjectLayoutAction", + "ObjectLayoutNote", + "ObjectLayoutBookmark", + "ObjectLayoutSet", + "ObjectLayoutCollection", + "ObjectLayoutParticipant" + ] + }, + "markdown": { + "description": "The markdown body of the object", + "example": "# This is the title\n...", + "type": "string" + }, + "name": { + "description": "The name of the object", + "example": "My object", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "object", + "type": "string" + }, + "properties": { + "description": "The properties of the object", + "items": { + "$ref": "#/components/schemas/apimodel.PropertyWithValue" + }, + "type": "array", + "uniqueItems": false + }, + "snippet": { + "description": "The snippet of the object, especially important for notes as they don't have a name", + "example": "The beginning of the object body...", + "type": "string" + }, + "space_id": { + "description": "The id of the space the object is in", + "example": "bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1", + "type": "string" + }, + "type": { + "$ref": "#/components/schemas/apimodel.Type" + } + }, + "type": "object" + }, + "apimodel.ObjectsPropertyLinkValue": { + "properties": { + "key": { + "example": "creator", + "type": "string" + }, + "objects": { + "description": "The object ids of the property", + "example": [ + "['object_id']" + ], + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "apimodel.ObjectsPropertyValue": { + "properties": { + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "creator", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Created by", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + }, + "objects": { + "description": "The object values of the property", + "example": [ + "['object_id']" + ], + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "apimodel.PhonePropertyLinkValue": { + "properties": { + "key": { + "example": "phone", + "type": "string" + }, + "phone": { + "description": "The phone value of the property", + "example": "+1234567890", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.PhonePropertyValue": { + "properties": { + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "phone", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Phone", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + }, + "phone": { + "description": "The phone value of the property", + "example": "+1234567890", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.Property": { + "description": "The property", + "properties": { + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "last_modified_date", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Last modified date", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.PropertyFormat": { + "description": "The format of the property used for filtering", + "enum": [ + "text", + "number", + "select", + "multi_select", + "date", + "files", + "checkbox", + "url", + "email", + "phone", + "objects" + ], + "type": "string", + "x-enum-varnames": [ + "PropertyFormatText", + "PropertyFormatNumber", + "PropertyFormatSelect", + "PropertyFormatMultiSelect", + "PropertyFormatDate", + "PropertyFormatFiles", + "PropertyFormatCheckbox", + "PropertyFormatUrl", + "PropertyFormatEmail", + "PropertyFormatPhone", + "PropertyFormatObjects" + ] + }, + "apimodel.PropertyLink": { + "properties": { + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "key": { + "description": "The key of the property", + "example": "last_modified_date", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Last modified date", + "type": "string" + } + }, + "required": [ + "format", + "key", + "name" + ], + "type": "object" + }, + "apimodel.PropertyLinkWithValue": { + "oneOf": [ + { + "$ref": "#/components/schemas/apimodel.TextPropertyLinkValue" + }, + { + "$ref": "#/components/schemas/apimodel.NumberPropertyLinkValue" + }, + { + "$ref": "#/components/schemas/apimodel.SelectPropertyLinkValue" + }, + { + "$ref": "#/components/schemas/apimodel.MultiSelectPropertyLinkValue" + }, + { + "$ref": "#/components/schemas/apimodel.DatePropertyLinkValue" + }, + { + "$ref": "#/components/schemas/apimodel.FilesPropertyLinkValue" + }, + { + "$ref": "#/components/schemas/apimodel.CheckboxPropertyLinkValue" + }, + { + "$ref": "#/components/schemas/apimodel.URLPropertyLinkValue" + }, + { + "$ref": "#/components/schemas/apimodel.EmailPropertyLinkValue" + }, + { + "$ref": "#/components/schemas/apimodel.PhonePropertyLinkValue" + }, + { + "$ref": "#/components/schemas/apimodel.ObjectsPropertyLinkValue" + } + ], + "type": "object" + }, + "apimodel.PropertyResponse": { + "properties": { + "property": { + "$ref": "#/components/schemas/apimodel.Property" + } + }, + "type": "object" + }, + "apimodel.PropertyWithValue": { + "oneOf": [ + { + "$ref": "#/components/schemas/apimodel.TextPropertyValue" + }, + { + "$ref": "#/components/schemas/apimodel.NumberPropertyValue" + }, + { + "$ref": "#/components/schemas/apimodel.SelectPropertyValue" + }, + { + "$ref": "#/components/schemas/apimodel.MultiSelectPropertyValue" + }, + { + "$ref": "#/components/schemas/apimodel.DatePropertyValue" + }, + { + "$ref": "#/components/schemas/apimodel.FilesPropertyValue" + }, + { + "$ref": "#/components/schemas/apimodel.CheckboxPropertyValue" + }, + { + "$ref": "#/components/schemas/apimodel.URLPropertyValue" + }, + { + "$ref": "#/components/schemas/apimodel.EmailPropertyValue" + }, + { + "$ref": "#/components/schemas/apimodel.PhonePropertyValue" + }, + { + "$ref": "#/components/schemas/apimodel.ObjectsPropertyValue" + } + ], + "type": "object" + }, + "apimodel.SearchRequest": { + "properties": { + "query": { + "description": "The text to search within object names and content; use types field for type filtering", + "example": "test", + "type": "string" + }, + "sort": { + "$ref": "#/components/schemas/apimodel.SortOptions" + }, + "types": { + "description": "The types of objects to include in results (e.g., \"page\", \"task\", \"bookmark\"); see ListTypes endpoint for valid values", + "example": [ + "page", + "task", + "bookmark" + ], + "items": { + "type": "string" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "apimodel.SelectPropertyLinkValue": { + "properties": { + "key": { + "example": "status", + "type": "string" + }, + "select": { + "description": "The selected tag id of the property; see ListTags endpoint for valid values", + "example": "tag_id", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.SelectPropertyValue": { + "properties": { + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "status", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Status", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + }, + "select": { + "$ref": "#/components/schemas/apimodel.Tag" + } + }, + "type": "object" + }, + "apimodel.Sort": { + "properties": { + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the sort", + "example": "67bf3f21cda9134102e2422c", + "type": "string" + }, + "property_key": { + "description": "The property key used for sorting", + "example": "name", + "type": "string" + }, + "sort_type": { + "description": "The sort direction", + "enum": [ + "asc", + "desc", + "custom" + ], + "example": "asc", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.SortDirection": { + "default": "desc", + "description": "The direction to sort the search results by", + "enum": [ + "asc", + "desc" + ], + "type": "string", + "x-enum-varnames": [ + "Asc", + "Desc" + ] + }, + "apimodel.SortOptions": { + "description": "The sorting options for the search results", + "properties": { + "direction": { + "$ref": "#/components/schemas/apimodel.SortDirection" + }, + "property_key": { + "$ref": "#/components/schemas/apimodel.SortProperty" + } + }, + "type": "object" + }, + "apimodel.SortProperty": { + "default": "last_modified_date", + "description": "The key of the property to sort the search results by", + "enum": [ + "created_date", + "last_modified_date", + "last_opened_date", + "name" + ], + "type": "string", + "x-enum-varnames": [ + "CreatedDate", + "LastModifiedDate", + "LastOpenedDate", + "Name" + ] + }, + "apimodel.Space": { + "description": "The space", + "properties": { + "description": { + "description": "The description of the space", + "example": "The local-first wiki", + "type": "string" + }, + "gateway_url": { + "description": "The gateway url to serve files and media", + "example": "http://127.0.0.1:31006", + "type": "string" + }, + "icon": { + "$ref": "#/components/schemas/apimodel.Icon" + }, + "id": { + "description": "The id of the space", + "example": "bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1", + "type": "string" + }, + "name": { + "description": "The name of the space", + "example": "My Space", + "type": "string" + }, + "network_id": { + "description": "The network id of the space", + "example": "N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "space", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.SpaceResponse": { + "properties": { + "space": { + "$ref": "#/components/schemas/apimodel.Space" + } + }, + "type": "object" + }, + "apimodel.Tag": { + "description": "The selected tag value of the property", + "properties": { + "color": { + "$ref": "#/components/schemas/apimodel.Color" + }, + "id": { + "description": "The id of the tag", + "example": "bafyreiaixlnaefu3ci22zdenjhsdlyaeeoyjrsid5qhfeejzlccijbj7sq", + "type": "string" + }, + "key": { + "description": "The key of the tag", + "example": "67b0d3e3cda913b84c1299b1", + "type": "string" + }, + "name": { + "description": "The name of the tag", + "example": "in-progress", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "tag", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.TagResponse": { + "properties": { + "tag": { + "$ref": "#/components/schemas/apimodel.Tag" + } + }, + "type": "object" + }, + "apimodel.TemplateResponse": { + "properties": { + "template": { + "$ref": "#/components/schemas/apimodel.ObjectWithBody" + } + }, + "type": "object" + }, + "apimodel.TextPropertyLinkValue": { + "properties": { + "key": { + "example": "description", + "type": "string" + }, + "text": { + "description": "The text value of the property", + "example": "Some text...", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.TextPropertyValue": { + "properties": { + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "description", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Description", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + }, + "text": { + "description": "The text value of the property", + "example": "Some text...", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.Type": { + "description": "The type of the object", + "properties": { + "archived": { + "description": "Whether the type is archived", + "example": false, + "type": "boolean" + }, + "icon": { + "$ref": "#/components/schemas/apimodel.Icon" + }, + "id": { + "description": "The id of the type (which is unique across spaces)", + "example": "bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu", + "type": "string" + }, + "key": { + "description": "The key of the type (can be the same across spaces for known types)", + "example": "page", + "type": "string" + }, + "layout": { + "description": "The layout of the object", + "enum": [ + "basic", + "profile", + "action", + "note", + "bookmark", + "set", + "set", + "collection", + "participant" + ], + "type": "string", + "x-enum-varnames": [ + "ObjectLayoutBasic", + "ObjectLayoutProfile", + "ObjectLayoutAction", + "ObjectLayoutNote", + "ObjectLayoutBookmark", + "ObjectLayoutSet", + "ObjectLayoutCollection", + "ObjectLayoutParticipant" + ] + }, + "name": { + "description": "The name of the type", + "example": "Page", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "type", + "type": "string" + }, + "plural_name": { + "description": "The plural name of the type", + "example": "Pages", + "type": "string" + }, + "properties": { + "description": "The properties linked to the type", + "items": { + "$ref": "#/components/schemas/apimodel.Property" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "apimodel.TypeLayout": { + "description": "The layout of the type", + "enum": [ + "basic", + "profile", + "action", + "note" + ], + "type": "string", + "x-enum-varnames": [ + "TypeLayoutBasic", + "TypeLayoutProfile", + "TypeLayoutAction", + "TypeLayoutNote" + ] + }, + "apimodel.TypeResponse": { + "properties": { + "type": { + "$ref": "#/components/schemas/apimodel.Type" + } + }, + "type": "object" + }, + "apimodel.URLPropertyLinkValue": { + "properties": { + "key": { + "example": "source", + "type": "string" + }, + "url": { + "description": "The URL value of the property", + "example": "https://example.com", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.URLPropertyValue": { + "properties": { + "format": { + "$ref": "#/components/schemas/apimodel.PropertyFormat" + }, + "id": { + "description": "The id of the property", + "example": "bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a", + "type": "string" + }, + "key": { + "description": "The key of the property", + "example": "source", + "type": "string" + }, + "name": { + "description": "The name of the property", + "example": "Source", + "type": "string" + }, + "object": { + "description": "The data model of the object", + "example": "property", + "type": "string" + }, + "url": { + "description": "The URL value of the property", + "example": "https://example.com", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.UpdateObjectRequest": { + "properties": { + "icon": { + "$ref": "#/components/schemas/apimodel.Icon" + }, + "name": { + "description": "The name of the object", + "example": "My object", + "type": "string" + }, + "properties": { + "description": "⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set for the object; see ListTypes or GetType endpoints for linked properties", + "items": { + "$ref": "#/components/schemas/apimodel.PropertyLinkWithValue" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "apimodel.UpdatePropertyRequest": { + "properties": { + "key": { + "description": "The key to set for the property; ; should always be snake_case, otherwise it will be converted to snake_case", + "example": "some_user_defined_property_key", + "type": "string" + }, + "name": { + "description": "The name to set for the property", + "example": "Last modified date", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "apimodel.UpdateSpaceRequest": { + "properties": { + "description": { + "description": "The description of the space", + "example": "The local-first wiki", + "type": "string" + }, + "name": { + "description": "The name of the space", + "example": "New Space", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.UpdateTagRequest": { + "properties": { + "color": { + "$ref": "#/components/schemas/apimodel.Color" + }, + "name": { + "description": "The name to set for the tag", + "example": "In progress", + "type": "string" + } + }, + "type": "object" + }, + "apimodel.UpdateTypeRequest": { + "properties": { + "icon": { + "$ref": "#/components/schemas/apimodel.Icon" + }, + "key": { + "description": "The key to set for the type; should always be snake_case, otherwise it will be converted to snake_case", + "example": "some_user_defined_type_key", + "type": "string" + }, + "layout": { + "$ref": "#/components/schemas/apimodel.TypeLayout" + }, + "name": { + "description": "The name to set for the type", + "example": "Page", + "type": "string" + }, + "plural_name": { + "description": "The plural name to set for the type", + "example": "Pages", + "type": "string" + }, + "properties": { + "description": "⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set for the type", + "items": { + "$ref": "#/components/schemas/apimodel.PropertyLink" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "apimodel.View": { + "properties": { + "filters": { + "description": "The list of filters", + "items": { + "$ref": "#/components/schemas/apimodel.Filter" + }, + "type": "array", + "uniqueItems": false + }, + "id": { + "description": "The id of the view", + "example": "67bf3f21cda9134102e2422c", + "type": "string" + }, + "layout": { + "description": "The layout of the view", + "enum": [ + "grid", + "table" + ], + "example": "grid", + "type": "string" + }, + "name": { + "description": "The name of the view", + "example": "All", + "type": "string" + }, + "sorts": { + "description": "The list of sorts", + "items": { + "$ref": "#/components/schemas/apimodel.Sort" + }, + "type": "array", + "uniqueItems": false + } + }, + "type": "object" + }, + "pagination.PaginatedResponse-apimodel_Member": { + "properties": { + "data": { + "description": "The list of items in the current result set", + "items": { + "$ref": "#/components/schemas/apimodel.Member" + }, + "type": "array", + "uniqueItems": false + }, + "pagination": { + "$ref": "#/components/schemas/pagination.PaginationMeta" + } + }, + "type": "object" + }, + "pagination.PaginatedResponse-apimodel_Object": { + "properties": { + "data": { + "description": "The list of items in the current result set", + "items": { + "$ref": "#/components/schemas/apimodel.Object" + }, + "type": "array", + "uniqueItems": false + }, + "pagination": { + "$ref": "#/components/schemas/pagination.PaginationMeta" + } + }, + "type": "object" + }, + "pagination.PaginatedResponse-apimodel_Property": { + "properties": { + "data": { + "description": "The list of items in the current result set", + "items": { + "$ref": "#/components/schemas/apimodel.Property" + }, + "type": "array", + "uniqueItems": false + }, + "pagination": { + "$ref": "#/components/schemas/pagination.PaginationMeta" + } + }, + "type": "object" + }, + "pagination.PaginatedResponse-apimodel_Space": { + "properties": { + "data": { + "description": "The list of items in the current result set", + "items": { + "$ref": "#/components/schemas/apimodel.Space" + }, + "type": "array", + "uniqueItems": false + }, + "pagination": { + "$ref": "#/components/schemas/pagination.PaginationMeta" + } + }, + "type": "object" + }, + "pagination.PaginatedResponse-apimodel_Tag": { + "properties": { + "data": { + "description": "The list of items in the current result set", + "items": { + "$ref": "#/components/schemas/apimodel.Tag" + }, + "type": "array", + "uniqueItems": false + }, + "pagination": { + "$ref": "#/components/schemas/pagination.PaginationMeta" + } + }, + "type": "object" + }, + "pagination.PaginatedResponse-apimodel_Type": { + "properties": { + "data": { + "description": "The list of items in the current result set", + "items": { + "$ref": "#/components/schemas/apimodel.Type" + }, + "type": "array", + "uniqueItems": false + }, + "pagination": { + "$ref": "#/components/schemas/pagination.PaginationMeta" + } + }, + "type": "object" + }, + "pagination.PaginatedResponse-apimodel_View": { + "properties": { + "data": { + "description": "The list of items in the current result set", + "items": { + "$ref": "#/components/schemas/apimodel.View" + }, + "type": "array", + "uniqueItems": false + }, + "pagination": { + "$ref": "#/components/schemas/pagination.PaginationMeta" + } + }, + "type": "object" + }, + "pagination.PaginationMeta": { + "description": "The pagination metadata for the response", + "properties": { + "has_more": { + "description": "Indicates if there are more items available beyond the current result set", + "example": true, + "type": "boolean" + }, + "limit": { + "description": "The maximum number of items returned in the result set", + "example": 100, + "type": "integer" + }, + "offset": { + "description": "The number of items skipped before starting to collect the result set", + "example": 0, + "type": "integer" + }, + "total": { + "description": "The total number of items available for the endpoint", + "example": 1000, + "type": "integer" + } + }, + "type": "object" + }, + "util.ForbiddenError": { + "properties": { + "code": { + "example": "forbidden", + "type": "string" + }, + "message": { + "example": "Forbidden", + "type": "string" + }, + "object": { + "example": "error", + "type": "string" + }, + "status": { + "example": 403, + "type": "integer" + } + }, + "type": "object" + }, + "util.GoneError": { + "properties": { + "code": { + "example": "resource_gone", + "type": "string" + }, + "message": { + "example": "Resource is gone", + "type": "string" + }, + "object": { + "example": "error", + "type": "string" + }, + "status": { + "example": 410, + "type": "integer" + } + }, + "type": "object" + }, + "util.NotFoundError": { + "properties": { + "code": { + "example": "object_not_found", + "type": "string" + }, + "message": { + "example": "Resource not found", + "type": "string" + }, + "object": { + "example": "error", + "type": "string" + }, + "status": { + "example": 404, + "type": "integer" + } + }, + "type": "object" + }, + "util.RateLimitError": { + "properties": { + "code": { + "example": "rate_limit_exceeded", + "type": "string" + }, + "message": { + "example": "Rate limit exceeded", + "type": "string" + }, + "object": { + "example": "error", + "type": "string" + }, + "status": { + "example": 429, + "type": "integer" + } + }, + "type": "object" + }, + "util.ServerError": { + "properties": { + "code": { + "example": "internal_server_error", + "type": "string" + }, + "message": { + "example": "Internal server error", + "type": "string" + }, + "object": { + "example": "error", + "type": "string" + }, + "status": { + "example": 500, + "type": "integer" + } + }, + "type": "object" + }, + "util.UnauthorizedError": { + "properties": { + "code": { + "example": "unauthorized", + "type": "string" + }, + "message": { + "example": "Unauthorized", + "type": "string" + }, + "object": { + "example": "error", + "type": "string" + }, + "status": { + "example": 401, + "type": "integer" + } + }, + "type": "object" + }, + "util.ValidationError": { + "properties": { + "code": { + "example": "bad_request", + "type": "string" + }, + "message": { + "example": "Bad request", + "type": "string" + }, + "object": { + "example": "error", + "type": "string" + }, + "status": { + "example": 400, + "type": "integer" + } + }, + "type": "object" + } + }, + "securitySchemes": { + "bearerauth": { + "bearerFormat": "JWT", + "scheme": "bearer", + "type": "http" + } + } + }, + "info": { + "contact": { + "email": "support@anytype.io", + "name": "Anytype Support", + "url": "https://anytype.io/contact" + }, + "description": "This API enables seamless interaction with Anytype's resources - spaces, objects, properties, types, templates, and beyond.", + "license": { + "name": "Any Source Available License 1.0", + "url": "https://github.com/anyproto/anytype-api/blob/main/LICENSE.md" + }, + "termsOfService": "https://anytype.io/terms_of_use", + "title": "Anytype API", + "version": "2025-05-20" + }, + "externalDocs": { + "description": "OpenAPI", + "url": "https://swagger.io/resources/open-api/" + }, + "paths": { + "/v1/auth/api_keys": { + "post": { + "description": "After receiving a `challenge_id` from the `/v1/auth/challenges` endpoint, the client calls this endpoint to provide the corresponding 4-digit code along with the challenge ID. The endpoint verifies that the challenge solution is correct and, if it is, returns an `api_key`. This endpoint is central to the authentication process, as it validates the user's identity and issues a key that can be used for further interactions with the API.", + "operationId": "create_api_key", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the challenge to solve", + "in": "query", + "name": "challenge_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The 4-digit code retrieved from Anytype Desktop app", + "in": "query", + "name": "code", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.CreateApiKeyResponse" + } + } + }, + "description": "The API key that can be used in the Authorization header for subsequent requests" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "summary": "Create API Key", + "tags": [ + "Auth" + ] + } + }, + "/v1/auth/challenges": { + "post": { + "description": "Generates a one-time authentication challenge for granting API access to the user's vault. Upon providing a valid `app_name`, the server issues a unique `challenge_id` and displays a 4-digit code within the Anytype Desktop. The `challenge_id` must then be used with the `/v1/auth/api_keys` endpoint to solve the challenge and retrieve an authentication token. This mechanism ensures that only trusted applications and authorized users gain access.", + "operationId": "create_auth_challenge", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The name of the app requesting API access", + "in": "query", + "name": "app_name", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.CreateChallengeResponse" + } + } + }, + "description": "The challenge ID associated with the started challenge" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "summary": "Create Challenge", + "tags": [ + "Auth" + ] + } + }, + "/v1/search": { + "post": { + "description": "Executes a global search over all spaces accessible to the authenticated user. The request body must specify the `query` text (currently matching only name and snippet of an object), optional filters on types (e.g., \"page\", \"task\"), and sort directives (default: descending by last modified date). Pagination is controlled via `offset` and `limit` query parameters to facilitate lazy loading in client UIs. The response returns a unified list of matched objects with their metadata and properties.", + "operationId": "search_global", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The number of items to skip before starting to collect the result set", + "in": "query", + "name": "offset", + "schema": { + "default": 0, + "type": "integer" + } + }, + { + "description": "The number of items to return", + "in": "query", + "name": "limit", + "schema": { + "default": 100, + "maximum": 1000, + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.SearchRequest" + } + } + }, + "description": "The search parameters used to filter and sort the results", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pagination.PaginatedResponse-apimodel_Object" + } + } + }, + "description": "The list of objects matching the search criteria" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Search objects across all spaces", + "tags": [ + "Search" + ] + } + }, + "/v1/spaces": { + "get": { + "description": "Retrieves a paginated list of all spaces that are accessible by the authenticated user. Each space record contains detailed information such as the space ID, name, icon (derived either from an emoji or image URL), and additional metadata. This endpoint is key to displaying a user’s workspaces.", + "operationId": "list_spaces", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The number of items to skip before starting to collect the result set", + "in": "query", + "name": "offset", + "schema": { + "default": 0, + "type": "integer" + } + }, + { + "description": "The number of items to return", + "in": "query", + "name": "limit", + "schema": { + "default": 100, + "maximum": 1000, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pagination.PaginatedResponse-apimodel_Space" + } + } + }, + "description": "The list of spaces accessible by the authenticated user" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "List spaces", + "tags": [ + "Spaces" + ] + }, + "post": { + "description": "Creates a new space based on a supplied name and description in the JSON request body. The endpoint is subject to rate limiting and automatically applies default configurations such as generating a random icon and initializing the workspace with default settings (for example, a default dashboard or home page). On success, the new space’s full metadata is returned, enabling the client to immediately switch context to the new internal.", + "operationId": "create_space", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.CreateSpaceRequest" + } + } + }, + "description": "The space to create", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.SpaceResponse" + } + } + }, + "description": "The created space" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Create space", + "tags": [ + "Spaces" + ] + } + }, + "/v1/spaces/{space_id}": { + "get": { + "description": "Fetches full details about a single space identified by its space ID. The response includes metadata such as the space name, icon, and various workspace IDs (home, archive, profile, etc.). This detailed view supports use cases such as displaying space-specific settings.", + "operationId": "get_space", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to retrieve; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.SpaceResponse" + } + } + }, + "description": "The space details" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Space not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Get space", + "tags": [ + "Spaces" + ] + }, + "patch": { + "description": "Updates the name or description of an existing space. The request body should contain the new name and/or description in JSON format. This endpoint is useful for renaming or rebranding a workspace without needing to recreate it. The updated space’s metadata is returned in the response.", + "operationId": "update_space", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to update; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.UpdateSpaceRequest" + } + } + }, + "description": "The space details to update", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.SpaceResponse" + } + } + }, + "description": "The updated space" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ForbiddenError" + } + } + }, + "description": "Forbidden" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Space not found" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Update space", + "tags": [ + "Spaces" + ] + } + }, + "/v1/spaces/{space_id}/lists/{list_id}/objects": { + "post": { + "description": "Adds one or more objects to a specific list (collection only) by submitting a JSON array of object IDs. Upon success, the endpoint returns a confirmation message. This endpoint is vital for building user interfaces that allow drag‑and‑drop or multi‑select additions to collections, enabling users to dynamically manage their collections without needing to modify the underlying object data.", + "operationId": "add_list_objects", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the list to which objects will be added; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']", + "in": "path", + "name": "list_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.AddObjectsToListRequest" + } + } + }, + "description": "The list of object IDs to add to the list; must be retrieved from SearchSpace or GlobalSearch endpoints or obtained from response context", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Objects added successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Not found" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Add objects to list", + "tags": [ + "Lists" + ] + } + }, + "/v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}": { + "delete": { + "description": "Removes a given object from the specified list (collection only) in a space. The endpoint takes the space, list, and object identifiers as path parameters and is subject to rate limiting. It is used for dynamically managing collections without affecting the underlying object data.", + "operationId": "remove_list_object", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the list from which the object will be removed; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']", + "in": "path", + "name": "list_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the object to remove from the list; must be retrieved from SearchSpace or GlobalSearch endpoints or obtained from response context", + "in": "path", + "name": "object_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + }, + "description": "Objects removed successfully" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Not found" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Remove object from list", + "tags": [ + "Lists" + ] + } + }, + "/v1/spaces/{space_id}/lists/{list_id}/views": { + "get": { + "description": "Returns a paginated list of views defined for a specific list (query or collection) within a space. Each view includes details such as layout, applied filters, and sorting options, enabling clients to render the list according to user preferences and context. This endpoint is essential for applications that need to display lists in various formats (e.g., grid, table) or with different sorting/filtering criteria.", + "operationId": "get_list_views", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the list to retrieve views for; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']", + "in": "path", + "name": "list_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The number of items to skip before starting to collect the result set", + "in": "query", + "name": "offset", + "schema": { + "default": 0, + "type": "integer" + } + }, + { + "description": "The number of items to return", + "in": "query", + "name": "limit", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pagination.PaginatedResponse-apimodel_View" + } + } + }, + "description": "The list of views associated with the specified list" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Get list views", + "tags": [ + "Lists" + ] + } + }, + "/v1/spaces/{space_id}/lists/{list_id}/views/{view_id}/objects": { + "get": { + "description": "Returns a paginated list of objects associated with a specific list (query or collection) within a space. When a view ID is provided, the objects are filtered and sorted according to the view's configuration. If no view ID is specified, all list objects are returned without filtering and sorting. This endpoint helps clients to manage grouped objects (for example, tasks within a list) by returning information for each item of the list.", + "operationId": "get_list_objects", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the list to retrieve objects for; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']", + "in": "path", + "name": "list_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the view to retrieve objects for; must be retrieved from ListViews endpoint or omitted if you want to get all objects in the list", + "in": "path", + "name": "view_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The number of items to skip before starting to collect the result set", + "in": "query", + "name": "offset", + "schema": { + "default": 0, + "type": "integer" + } + }, + { + "description": "The number of items to return", + "in": "query", + "name": "limit", + "schema": { + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pagination.PaginatedResponse-apimodel_Object" + } + } + }, + "description": "The list of objects associated with the specified list" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Get objects in list", + "tags": [ + "Lists" + ] + } + }, + "/v1/spaces/{space_id}/members": { + "get": { + "description": "Returns a paginated list of members belonging to the specified space. Each member record includes the member’s profile ID, name, icon (which may be derived from an emoji or image), network identity, global name, status (e.g. joining, active) and role (e.g. Viewer, Editor, Owner). This endpoint supports collaborative features by allowing clients to show who is in a space and manage access rights.", + "operationId": "list_members", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to list members for; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The number of items to skip before starting to collect the result set", + "in": "query", + "name": "offset", + "schema": { + "default": 0, + "type": "integer" + } + }, + { + "description": "The number of items to return", + "in": "query", + "name": "limit", + "schema": { + "default": 100, + "maximum": 1000, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pagination.PaginatedResponse-apimodel_Member" + } + } + }, + "description": "The list of members in the space" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "List members", + "tags": [ + "Members" + ] + } + }, + "/v1/spaces/{space_id}/members/{member_id}": { + "get": { + "description": "Fetches detailed information about a single member within a space. The endpoint returns the member’s identifier, name, icon, identity, global name, status and role. The member_id path parameter can be provided as either the member's ID (starting with `_participant`) or the member's identity. This is useful for user profile pages, permission management, and displaying member-specific information in collaborative environments.", + "operationId": "get_member", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to get the member from; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Member ID or Identity; must be retrieved from ListMembers endpoint or obtained from response context", + "in": "path", + "name": "member_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.MemberResponse" + } + } + }, + "description": "The member details" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Member not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Get member", + "tags": [ + "Members" + ] + } + }, + "/v1/spaces/{space_id}/objects": { + "get": { + "description": "Retrieves a paginated list of objects in the given space. The endpoint takes query parameters for pagination (offset and limit) and returns detailed data about each object including its ID, name, icon, type information, a snippet of the content (if applicable), layout, space ID, blocks and details. It is intended for building views where users can see all objects in a space at a glance.", + "operationId": "list_objects", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space in which to list objects; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The number of items to skip before starting to collect the result set", + "in": "query", + "name": "offset", + "schema": { + "default": 0, + "type": "integer" + } + }, + { + "description": "The number of items to return", + "in": "query", + "name": "limit", + "schema": { + "default": 100, + "maximum": 1000, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pagination.PaginatedResponse-apimodel_Object" + } + } + }, + "description": "The list of objects in the specified space" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "List objects", + "tags": [ + "Objects" + ] + }, + "post": { + "description": "Creates a new object in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include key details such as the object name, icon, description, body content (which may support Markdown), source URL (required for bookmark objects), template identifier, and the type_key (which is the non-unique identifier of the type of object to create). Post-creation, additional operations (like setting featured properties or fetching bookmark metadata) may occur. The endpoint then returns the full object data, ready for further interactions.", + "operationId": "create_object", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space in which to create the object; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.CreateObjectRequest" + } + } + }, + "description": "The object to create", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.ObjectResponse" + } + } + }, + "description": "The created object" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Create object", + "tags": [ + "Objects" + ] + } + }, + "/v1/spaces/{space_id}/objects/{object_id}": { + "delete": { + "description": "This endpoint “deletes” an object by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the object’s details after it has been archived. Proper error handling is in place for situations such as when the object isn’t found or the deletion cannot be performed because of permission issues.", + "operationId": "delete_object", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space in which the object exists; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the object to delete; must be retrieved from ListObjects, SearchSpace or GlobalSearch endpoints or obtained from response context", + "in": "path", + "name": "object_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.ObjectResponse" + } + } + }, + "description": "The deleted object" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ForbiddenError" + } + } + }, + "description": "Forbidden" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Delete object", + "tags": [ + "Objects" + ] + }, + "get": { + "description": "Fetches the full details of a single object identified by the object ID within the specified space. The response includes not only basic metadata (ID, name, icon, type) but also the complete set of blocks (which may include text, files, properties and dataviews) and extra details (such as timestamps and linked member information). This endpoint is essential when a client needs to render or edit the full object view.", + "operationId": "get_object", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space in which the object exists; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the object to retrieve; must be retrieved from ListObjects, SearchSpace or GlobalSearch endpoints or obtained from response context", + "in": "path", + "name": "object_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The format to return the object body in", + "in": "query", + "name": "format", + "schema": { + "default": "\"md\"", + "enum": [ + "md" + ], + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.ObjectResponse" + } + } + }, + "description": "The retrieved object" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Get object", + "tags": [ + "Objects" + ] + }, + "patch": { + "description": "This endpoint updates an existing object in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the details to be updated. The endpoint then returns the full object data, ready for further interactions.", + "operationId": "update_object", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space in which the object exists; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the object to update; must be retrieved from ListObjects, SearchSpace or GlobalSearch endpoints or obtained from response context", + "in": "path", + "name": "object_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.UpdateObjectRequest" + } + } + }, + "description": "The details of the object to update", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.ObjectResponse" + } + } + }, + "description": "The updated object" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Update object", + "tags": [ + "Objects" + ] + } + }, + "/v1/spaces/{space_id}/properties": { + "get": { + "description": "⚠ Warning: Properties are experimental and may change in the next update. ⚠ Retrieves a paginated list of properties available within a specific space. Each property record includes its unique identifier, name and format. This information is essential for clients to understand the available properties for filtering or creating objects.", + "operationId": "list_properties", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to list properties for; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The number of items to skip before starting to collect the result set", + "in": "query", + "name": "offset", + "schema": { + "default": 0, + "type": "integer" + } + }, + { + "description": "The number of items to return", + "in": "query", + "name": "limit", + "schema": { + "default": 100, + "maximum": 1000, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pagination.PaginatedResponse-apimodel_Property" + } + } + }, + "description": "The list of properties in the specified space" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "List properties", + "tags": [ + "Properties" + ] + }, + "post": { + "description": "⚠ Warning: Properties are experimental and may change in the next update. ⚠ Creates a new property in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include property details such as the name and format. The endpoint then returns the full property data, ready for further interactions.", + "operationId": "create_property", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to create the property in; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.CreatePropertyRequest" + } + } + }, + "description": "The property to create", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.PropertyResponse" + } + } + }, + "description": "The created property" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Create property", + "tags": [ + "Properties" + ] + } + }, + "/v1/spaces/{space_id}/properties/{property_id}": { + "delete": { + "description": "⚠ Warning: Properties are experimental and may change in the next update. ⚠ This endpoint “deletes” a property by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the property’s details after it has been archived. Proper error handling is in place for situations such as when the property isn’t found or the deletion cannot be performed because of permission issues.", + "operationId": "delete_property", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to which the property belongs; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the property to delete; must be retrieved from ListProperties endpoint or obtained from response context", + "in": "path", + "name": "property_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.PropertyResponse" + } + } + }, + "description": "The deleted property" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ForbiddenError" + } + } + }, + "description": "Forbidden" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Delete property", + "tags": [ + "Properties" + ] + }, + "get": { + "description": "⚠ Warning: Properties are experimental and may change in the next update. ⚠ Fetches detailed information about one specific property by its ID. This includes the property’s unique identifier, name and format. This detailed view assists clients in showing property options to users and in guiding the user interface (such as displaying appropriate input fields or selection options).", + "operationId": "get_property", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to which the property belongs; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the property to retrieve; must be retrieved from ListProperties endpoint or obtained from response context", + "in": "path", + "name": "property_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.PropertyResponse" + } + } + }, + "description": "The requested property" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Get property", + "tags": [ + "Properties" + ] + }, + "patch": { + "description": "⚠ Warning: Properties are experimental and may change in the next update. ⚠ This endpoint updates an existing property in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the name to be updated. The endpoint then returns the full property data, ready for further interactions.", + "operationId": "update_property", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to which the property belongs; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the property to update; must be retrieved from ListProperties endpoint or obtained from response context", + "in": "path", + "name": "property_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.UpdatePropertyRequest" + } + } + }, + "description": "The property to update", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.PropertyResponse" + } + } + }, + "description": "The updated property" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ForbiddenError" + } + } + }, + "description": "Forbidden" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Update property", + "tags": [ + "Properties" + ] + } + }, + "/v1/spaces/{space_id}/properties/{property_id}/tags": { + "get": { + "description": "This endpoint retrieves a paginated list of tags available for a specific property within a space. Each tag record includes its unique identifier, name, and color. This information is essential for clients to display select or multi-select options to users when they are creating or editing objects. The endpoint also supports pagination through offset and limit parameters.", + "operationId": "list_tags", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to list tags for; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the property to list tags for; must be retrieved from ListProperties endpoint or obtained from response context", + "in": "path", + "name": "property_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pagination.PaginatedResponse-apimodel_Tag" + } + } + }, + "description": "The list of tags" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Property not found" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "List tags", + "tags": [ + "Tags" + ] + }, + "post": { + "description": "This endpoint creates a new tag for a given property id in a space. The creation process is subject to rate limiting. The tag is identified by its unique identifier within the specified space. The request must include the tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to add new tag options to a property.", + "operationId": "create_tag", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to create the tag in; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the property to create the tag for; must be retrieved from ListProperties endpoint or obtained from response context", + "in": "path", + "name": "property_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.CreateTagRequest" + } + } + }, + "description": "The tag to create", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.TagResponse" + } + } + }, + "description": "The created tag" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Create tag", + "tags": [ + "Tags" + ] + } + }, + "/v1/spaces/{space_id}/properties/{property_id}/tags/{tag_id}": { + "delete": { + "description": "This endpoint “deletes” a tag by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the tag’s details after it has been archived. Proper error handling is in place for situations such as when the tag isn’t found or the deletion cannot be performed because of permission issues.", + "operationId": "delete_tag", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to delete the tag from; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the property to delete the tag for; must be retrieved from ListProperties endpoint or obtained from response context", + "in": "path", + "name": "property_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the tag to delete; must be retrieved from ListTags endpoint or obtained from response context", + "in": "path", + "name": "tag_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.TagResponse" + } + } + }, + "description": "The deleted tag" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ForbiddenError" + } + } + }, + "description": "Forbidden" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Delete tag", + "tags": [ + "Tags" + ] + }, + "get": { + "description": "This endpoint retrieves a tag for a given property id. The tag is identified by its unique identifier within the specified space. The response includes the tag's details such as its ID, name, and color. This is useful for clients to display or when editing a specific tag option.", + "operationId": "get_tag", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to retrieve the tag from; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the property to retrieve the tag for; must be retrieved from ListProperties endpoint or obtained from response context", + "in": "path", + "name": "property_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the tag to retrieve; must be retrieved from ListTags endpoint or obtained from response context", + "in": "path", + "name": "tag_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.TagResponse" + } + } + }, + "description": "The retrieved tag" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Get tag", + "tags": [ + "Tags" + ] + }, + "patch": { + "description": "This endpoint updates a tag for a given property id in a space. The update process is subject to rate limiting. The tag is identified by its unique identifier within the specified space. The request must include the tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to edit existing tags for a property.", + "operationId": "update_tag", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to update the tag in; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the property to update the tag for; must be retrieved from ListProperties endpoint or obtained from response context", + "in": "path", + "name": "property_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the tag to update; must be retrieved from ListTags endpoint or obtained from response context", + "in": "path", + "name": "tag_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.UpdateTagRequest" + } + } + }, + "description": "The tag to update", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.TagResponse" + } + } + }, + "description": "The updated tag" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ForbiddenError" + } + } + }, + "description": "Forbidden" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Update tag", + "tags": [ + "Tags" + ] + } + }, + "/v1/spaces/{space_id}/search": { + "post": { + "description": "Performs a search within a single space (specified by the `space_id` path parameter). Like the global search, it accepts pagination parameters and a JSON payload containing the search `query`, `types`, and sorting preferences. The search is limited to the provided space and returns a list of objects that match the query. This allows clients to implement space‑specific filtering without having to process extraneous results.", + "operationId": "search_space", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to search in; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The number of items to skip before starting to collect the result set", + "in": "query", + "name": "offset", + "schema": { + "default": 0, + "type": "integer" + } + }, + { + "description": "The number of items to return", + "in": "query", + "name": "limit", + "schema": { + "default": 100, + "maximum": 1000, + "type": "integer" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.SearchRequest" + } + } + }, + "description": "The search parameters used to filter and sort the results", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pagination.PaginatedResponse-apimodel_Object" + } + } + }, + "description": "The list of objects matching the search criteria" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Search objects within a space", + "tags": [ + "Search" + ] + } + }, + "/v1/spaces/{space_id}/types": { + "get": { + "description": "This endpoint retrieves a paginated list of types (e.g. 'Page', 'Note', 'Task') available within the specified space. Each type’s record includes its unique identifier, type key, display name, icon, and layout. While a type's id is truly unique, a type's key can be the same across spaces for known types, e.g. 'page' for 'Page'. Clients use this information when offering choices for object creation or for filtering objects by type through search.", + "operationId": "list_types", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to retrieve types from; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The number of items to skip before starting to collect the result set", + "in": "query", + "name": "offset", + "schema": { + "default": 0, + "type": "integer" + } + }, + { + "description": "The number of items to return", + "in": "query", + "name": "limit", + "schema": { + "default": 100, + "maximum": 1000, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pagination.PaginatedResponse-apimodel_Type" + } + } + }, + "description": "The list of types" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "List types", + "tags": [ + "Types" + ] + }, + "post": { + "description": "Creates a new type in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include type details such as the name, icon, and layout. The endpoint then returns the full type data, ready to be used for creating objects.", + "operationId": "create_type", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space in which to create the type; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.CreateTypeRequest" + } + } + }, + "description": "The type to create", + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.TypeResponse" + } + } + }, + "description": "The created type" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Create type", + "tags": [ + "Types" + ] + } + }, + "/v1/spaces/{space_id}/types/{type_id}": { + "delete": { + "description": "This endpoint “deletes” an type by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the type’s details after it has been archived. Proper error handling is in place for situations such as when the type isn’t found or the deletion cannot be performed because of permission issues.", + "operationId": "delete_type", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space from which to delete the type; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the type to delete; must be retrieved from ListTypes endpoint or obtained from response context", + "in": "path", + "name": "type_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.TypeResponse" + } + } + }, + "description": "The deleted type" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ForbiddenError" + } + } + }, + "description": "Forbidden" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Delete type", + "tags": [ + "Types" + ] + }, + "get": { + "description": "Fetches detailed information about one specific type by its ID. This includes the type’s unique key, name, icon, and layout. This detailed view assists clients in understanding the expected structure and style for objects of that type and in guiding the user interface (such as displaying appropriate icons or layout hints).", + "operationId": "get_type", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space from which to retrieve the type; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the type to retrieve; must be retrieved from ListTypes endpoint or obtained from response context", + "in": "path", + "name": "type_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.TypeResponse" + } + } + }, + "description": "The requested type" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Get type", + "tags": [ + "Types" + ] + }, + "patch": { + "description": "This endpoint updates an existing type in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the name and properties to be updated. The endpoint then returns the full type data, ready for further interactions.", + "operationId": "update_type", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space in which the type exists; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the type to update; must be retrieved from ListTypes endpoint or obtained from response context", + "in": "path", + "name": "type_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.UpdateTypeRequest" + } + } + }, + "description": "The type details to update", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.TypeResponse" + } + } + }, + "description": "The updated type" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ValidationError" + } + } + }, + "description": "Bad request" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.RateLimitError" + } + } + }, + "description": "Rate limit exceeded" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Update type", + "tags": [ + "Types" + ] + } + }, + "/v1/spaces/{space_id}/types/{type_id}/templates": { + "get": { + "description": "This endpoint returns a paginated list of templates that are associated with a specific type within a space. Templates provide pre‑configured structures for creating new objects. Each template record contains its identifier, name, and icon, so that clients can offer users a selection of templates when creating objects.", + "operationId": "list_templates", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to which the type belongs; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the type to retrieve templates for; must be retrieved from ListTypes endpoint or obtained from response context", + "in": "path", + "name": "type_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The number of items to skip before starting to collect the result set", + "in": "query", + "name": "offset", + "schema": { + "default": 0, + "type": "integer" + } + }, + { + "description": "The number of items to return", + "in": "query", + "name": "limit", + "schema": { + "default": 100, + "maximum": 1000, + "type": "integer" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/pagination.PaginatedResponse-apimodel_Object" + } + } + }, + "description": "List of templates" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "List templates", + "tags": [ + "Templates" + ] + } + }, + "/v1/spaces/{space_id}/types/{type_id}/templates/{template_id}": { + "get": { + "description": "Fetches full details for one template associated with a particular type in a space. The response provides the template’s identifier, name, icon, and any other relevant metadata. This endpoint is useful when a client needs to preview or apply a template to prefill object creation fields.", + "operationId": "get_template", + "parameters": [ + { + "description": "The version of the API to use", + "in": "header", + "name": "Anytype-Version", + "required": true, + "schema": { + "default": "2025-05-20", + "type": "string" + } + }, + { + "description": "The ID of the space to which the template belongs; must be retrieved from ListSpaces endpoint", + "in": "path", + "name": "space_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the type to which the template belongs; must be retrieved from ListTypes endpoint or obtained from response context", + "in": "path", + "name": "type_id", + "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "The ID of the template to retrieve; must be retrieved from ListTemplates endpoint or obtained from response context", + "in": "path", + "name": "template_id", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/apimodel.TemplateResponse" + } + } + }, + "description": "The requested template" + }, + "401": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.UnauthorizedError" + } + } + }, + "description": "Unauthorized" + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.NotFoundError" + } + } + }, + "description": "Resource not found" + }, + "410": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.GoneError" + } + } + }, + "description": "Resource deleted" + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/util.ServerError" + } + } + }, + "description": "Internal server error" + } + }, + "security": [ + { + "bearerauth": [] + } + ], + "summary": "Get template", + "tags": [ + "Templates" + ] + } + } + }, + "openapi": "3.1.0", + "servers": [ + { + "url": "http://localhost:31009" + } + ] +} diff --git a/core/api/docs/swagger.yaml b/core/api/docs/openapi.yaml similarity index 80% rename from core/api/docs/swagger.yaml rename to core/api/docs/openapi.yaml index bcc088d0b..b6202c63b 100644 --- a/core/api/docs/swagger.yaml +++ b/core/api/docs/openapi.yaml @@ -1,13 +1,22 @@ components: schemas: + apimodel.AddObjectsToListRequest: + properties: + objects: + description: The list of object IDs to add to the list + example: + - '["bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ"]' + items: + type: string + type: array + uniqueItems: false + type: object apimodel.CheckboxPropertyLinkValue: properties: checkbox: description: The checkbox value of the property example: true type: boolean - format: - $ref: '#/components/schemas/apimodel.PropertyFormat' key: example: done type: string @@ -63,6 +72,21 @@ components: - ColorIce - ColorTeal - ColorLime + apimodel.CreateApiKeyResponse: + properties: + api_key: + description: The api key used to authenticate requests + example: zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6= + type: string + type: object + apimodel.CreateChallengeResponse: + properties: + challenge_id: + description: The challenge id associated with the displayed code and needed + to solve the challenge for api_key + example: 67647f5ecda913e9a2e11b26 + type: string + type: object apimodel.CreateObjectRequest: properties: body: @@ -77,7 +101,8 @@ components: type: string properties: description: '⚠ Warning: Properties are experimental and may change in the - next update. ⚠ The properties to set on the object' + next update. ⚠ The properties to set on the object; see ListTypes or GetType + endpoints for linked properties' items: $ref: '#/components/schemas/apimodel.PropertyLinkWithValue' type: array @@ -97,6 +122,11 @@ components: properties: format: $ref: '#/components/schemas/apimodel.PropertyFormat' + key: + description: The key of the property; should always be snake_case, otherwise + it will be converted to snake_case + example: some_user_defined_property_key + type: string name: description: The name of the property example: Last modified date @@ -134,6 +164,11 @@ components: properties: icon: $ref: '#/components/schemas/apimodel.Icon' + key: + description: The key of the type; should always be snake_case, otherwise + it will be converted to snake_case + example: some_user_defined_type_key + type: string layout: $ref: '#/components/schemas/apimodel.TypeLayout' name: @@ -154,6 +189,7 @@ components: required: - layout - name + - plural_name type: object apimodel.DatePropertyLinkValue: properties: @@ -161,8 +197,6 @@ components: description: The date value of the property example: "2025-02-14T12:34:56Z" type: string - format: - $ref: '#/components/schemas/apimodel.PropertyFormat' key: example: last_modified_date type: string @@ -192,22 +226,12 @@ components: example: property type: string type: object - apimodel.DisplayCodeResponse: - properties: - challenge_id: - description: The challenge id associated with the displayed code and needed - to solve the challenge for token - example: 67647f5ecda913e9a2e11b26 - type: string - type: object apimodel.EmailPropertyLinkValue: properties: email: description: The email value of the property example: example@example.com type: string - format: - $ref: '#/components/schemas/apimodel.PropertyFormat' key: example: email type: string @@ -258,15 +282,13 @@ components: apimodel.FilesPropertyLinkValue: properties: files: - description: The file values of the property + description: The file ids of the property example: - - '[''fileId'']' + - '[''file_id'']' items: type: string type: array uniqueItems: false - format: - $ref: '#/components/schemas/apimodel.PropertyFormat' key: example: files type: string @@ -276,7 +298,7 @@ components: files: description: The file values of the property example: - - '[''fileId'']' + - '[''file_id'']' items: type: string type: array @@ -349,12 +371,409 @@ components: apimodel.IconFormat: description: The format of the icon enum: + - emoji + - file - icon type: string x-enum-varnames: - IconFormatEmoji - IconFormatFile - IconFormatIcon + apimodel.IconName: + description: The name of the icon + example: document + type: string + x-enum-varnames: + - IconNameAccessibility + - IconNameAddCircle + - IconNameAirplane + - IconNameAlarm + - IconNameAlbums + - IconNameAlertCircle + - IconNameAmericanFootball + - IconNameAnalytics + - IconNameAperture + - IconNameApps + - IconNameArchive + - IconNameArrowBackCircle + - IconNameArrowDownCircle + - IconNameArrowForwardCircle + - IconNameArrowRedoCircle + - IconNameArrowRedo + - IconNameArrowUndoCircle + - IconNameArrowUndo + - IconNameArrowUpCircle + - IconNameAtCircle + - IconNameAttach + - IconNameBackspace + - IconNameBagAdd + - IconNameBagCheck + - IconNameBagHandle + - IconNameBagRemove + - IconNameBag + - IconNameBalloon + - IconNameBan + - IconNameBandage + - IconNameBarChart + - IconNameBarbell + - IconNameBarcode + - IconNameBaseball + - IconNameBasket + - IconNameBasketball + - IconNameBatteryCharging + - IconNameBatteryDead + - IconNameBatteryFull + - IconNameBatteryHalf + - IconNameBeaker + - IconNameBed + - IconNameBeer + - IconNameBicycle + - IconNameBinoculars + - IconNameBluetooth + - IconNameBoat + - IconNameBody + - IconNameBonfire + - IconNameBook + - IconNameBookmark + - IconNameBookmarks + - IconNameBowlingBall + - IconNameBriefcase + - IconNameBrowsers + - IconNameBrush + - IconNameBug + - IconNameBuild + - IconNameBulb + - IconNameBus + - IconNameBusiness + - IconNameCafe + - IconNameCalculator + - IconNameCalendarClear + - IconNameCalendarNumber + - IconNameCalendar + - IconNameCall + - IconNameCameraReverse + - IconNameCamera + - IconNameCarSport + - IconNameCar + - IconNameCard + - IconNameCaretBackCircle + - IconNameCaretBack + - IconNameCaretDownCircle + - IconNameCaretDown + - IconNameCaretForwardCircle + - IconNameCaretForward + - IconNameCaretUpCircle + - IconNameCaretUp + - IconNameCart + - IconNameCash + - IconNameCellular + - IconNameChatboxEllipses + - IconNameChatbox + - IconNameChatbubbleEllipses + - IconNameChatbubble + - IconNameChatbubbles + - IconNameCheckbox + - IconNameCheckmarkCircle + - IconNameCheckmarkDoneCircle + - IconNameChevronBackCircle + - IconNameChevronDownCircle + - IconNameChevronForwardCircle + - IconNameChevronUpCircle + - IconNameClipboard + - IconNameCloseCircle + - IconNameCloudCircle + - IconNameCloudDone + - IconNameCloudDownload + - IconNameCloudOffline + - IconNameCloudUpload + - IconNameCloud + - IconNameCloudyNight + - IconNameCloudy + - IconNameCodeSlash + - IconNameCode + - IconNameCog + - IconNameColorFill + - IconNameColorFilter + - IconNameColorPalette + - IconNameColorWand + - IconNameCompass + - IconNameConstruct + - IconNameContact + - IconNameContract + - IconNameContrast + - IconNameCopy + - IconNameCreate + - IconNameCrop + - IconNameCube + - IconNameCut + - IconNameDesktop + - IconNameDiamond + - IconNameDice + - IconNameDisc + - IconNameDocumentAttach + - IconNameDocumentLock + - IconNameDocumentText + - IconNameDocument + - IconNameDocuments + - IconNameDownload + - IconNameDuplicate + - IconNameEar + - IconNameEarth + - IconNameEasel + - IconNameEgg + - IconNameEllipse + - IconNameEllipsisHorizontalCircle + - IconNameEllipsisVerticalCircle + - IconNameEnter + - IconNameExit + - IconNameExpand + - IconNameExtensionPuzzle + - IconNameEyeOff + - IconNameEye + - IconNameEyedrop + - IconNameFastFood + - IconNameFemale + - IconNameFileTrayFull + - IconNameFileTrayStacked + - IconNameFileTray + - IconNameFilm + - IconNameFilterCircle + - IconNameFingerPrint + - IconNameFish + - IconNameFitness + - IconNameFlag + - IconNameFlame + - IconNameFlashOff + - IconNameFlash + - IconNameFlashlight + - IconNameFlask + - IconNameFlower + - IconNameFolderOpen + - IconNameFolder + - IconNameFootball + - IconNameFootsteps + - IconNameFunnel + - IconNameGameController + - IconNameGift + - IconNameGitBranch + - IconNameGitCommit + - IconNameGitCompare + - IconNameGitMerge + - IconNameGitNetwork + - IconNameGitPullRequest + - IconNameGlasses + - IconNameGlobe + - IconNameGolf + - IconNameGrid + - IconNameHammer + - IconNameHandLeft + - IconNameHandRight + - IconNameHappy + - IconNameHardwareChip + - IconNameHeadset + - IconNameHeartCircle + - IconNameHeartDislikeCircle + - IconNameHeartDislike + - IconNameHeartHalf + - IconNameHeart + - IconNameHelpBuoy + - IconNameHelpCircle + - IconNameHome + - IconNameHourglass + - IconNameIceCream + - IconNameIdCard + - IconNameImage + - IconNameImages + - IconNameInfinite + - IconNameInformationCircle + - IconNameInvertMode + - IconNameJournal + - IconNameKey + - IconNameKeypad + - IconNameLanguage + - IconNameLaptop + - IconNameLayers + - IconNameLeaf + - IconNameLibrary + - IconNameLink + - IconNameListCircle + - IconNameList + - IconNameLocate + - IconNameLocation + - IconNameLockClosed + - IconNameLockOpen + - IconNameLogIn + - IconNameLogOut + - IconNameLogoAlipay + - IconNameLogoAmazon + - IconNameLogoAmplify + - IconNameLogoAndroid + - IconNameMagnet + - IconNameMailOpen + - IconNameMailUnread + - IconNameMail + - IconNameMaleFemale + - IconNameMale + - IconNameMan + - IconNameMap + - IconNameMedal + - IconNameMedical + - IconNameMedkit + - IconNameMegaphone + - IconNameMenu + - IconNameMicCircle + - IconNameMicOffCircle + - IconNameMicOff + - IconNameMic + - IconNameMoon + - IconNameMove + - IconNameMusicalNote + - IconNameMusicalNotes + - IconNameNavigateCircle + - IconNameNavigate + - IconNameNewspaper + - IconNameNotificationsCircle + - IconNameNotificationsOffCircle + - IconNameNotificationsOff + - IconNameNotifications + - IconNameNuclear + - IconNameNutrition + - IconNameOptions + - IconNamePaperPlane + - IconNamePartlySunny + - IconNamePauseCircle + - IconNamePause + - IconNamePaw + - IconNamePencil + - IconNamePeopleCircle + - IconNamePeople + - IconNamePersonAdd + - IconNamePersonCircle + - IconNamePersonRemove + - IconNamePerson + - IconNamePhoneLandscape + - IconNamePhonePortrait + - IconNamePieChart + - IconNamePin + - IconNamePint + - IconNamePizza + - IconNamePlanet + - IconNamePlayBackCircle + - IconNamePlayBack + - IconNamePlayCircle + - IconNamePlayForwardCircle + - IconNamePlayForward + - IconNamePlaySkipBackCircle + - IconNamePlaySkipBack + - IconNamePlaySkipForwardCircle + - IconNamePlaySkipForward + - IconNamePlay + - IconNamePodium + - IconNamePower + - IconNamePricetag + - IconNamePricetags + - IconNamePrint + - IconNamePrism + - IconNamePulse + - IconNamePush + - IconNameQrCode + - IconNameRadioButtonOff + - IconNameRadioButtonOn + - IconNameRadio + - IconNameRainy + - IconNameReader + - IconNameReceipt + - IconNameRecording + - IconNameRefreshCircle + - IconNameRefresh + - IconNameReloadCircle + - IconNameReload + - IconNameRemoveCircle + - IconNameRepeat + - IconNameResize + - IconNameRestaurant + - IconNameRibbon + - IconNameRocket + - IconNameRose + - IconNameSad + - IconNameSave + - IconNameScale + - IconNameScanCircle + - IconNameScan + - IconNameSchool + - IconNameSearchCircle + - IconNameSearch + - IconNameSend + - IconNameServer + - IconNameSettings + - IconNameShapes + - IconNameShareSocial + - IconNameShare + - IconNameShieldCheckmark + - IconNameShieldHalf + - IconNameShield + - IconNameShirt + - IconNameShuffle + - IconNameSkull + - IconNameSnow + - IconNameSparkles + - IconNameSpeedometer + - IconNameSquare + - IconNameStarHalf + - IconNameStar + - IconNameStatsChart + - IconNameStopCircle + - IconNameStop + - IconNameStopwatch + - IconNameStorefront + - IconNameSubway + - IconNameSunny + - IconNameSwapHorizontal + - IconNameSwapVertical + - IconNameSyncCircle + - IconNameSync + - IconNameTabletLandscape + - IconNameTabletPortrait + - IconNameTelescope + - IconNameTennisball + - IconNameTerminal + - IconNameText + - IconNameThermometer + - IconNameThumbsDown + - IconNameThumbsUp + - IconNameThunderstorm + - IconNameTicket + - IconNameTime + - IconNameTimer + - IconNameToday + - IconNameToggle + - IconNameTrailSign + - IconNameTrain + - IconNameTransgender + - IconNameTrashBin + - IconNameTrash + - IconNameTrendingDown + - IconNameTrendingUp + - IconNameTriangle + - IconNameTrophy + - IconNameTv + - IconNameUmbrella + - IconNameUnlink + - IconNameVideocamOff + - IconNameVideocam + - IconNameVolumeHigh + - IconNameVolumeLow + - IconNameVolumeMedium + - IconNameVolumeMute + - IconNameVolumeOff + - IconNameWalk + - IconNameWallet + - IconNameWarning + - IconNameWatch + - IconNameWater + - IconNameWifi + - IconNameWine + - IconNameWoman apimodel.Member: description: The member properties: @@ -408,13 +827,14 @@ components: type: object apimodel.MultiSelectPropertyLinkValue: properties: - format: - $ref: '#/components/schemas/apimodel.PropertyFormat' key: example: tag type: string multi_select: - description: The selected tag values of the property + description: The selected tag ids of the property; see ListTags endpoint + for valid values + example: + - '[''tag_id'']' items: type: string type: array @@ -454,14 +874,10 @@ components: format: $ref: '#/components/schemas/apimodel.IconFormat' name: - description: The name of the icon - example: document - type: string + $ref: '#/components/schemas/apimodel.IconName' type: object apimodel.NumberPropertyLinkValue: properties: - format: - $ref: '#/components/schemas/apimodel.PropertyFormat' key: example: height type: string @@ -613,15 +1029,13 @@ components: type: object apimodel.ObjectsPropertyLinkValue: properties: - format: - $ref: '#/components/schemas/apimodel.PropertyFormat' key: example: creator type: string objects: - description: The object values of the property + description: The object ids of the property example: - - '[''objectId'']' + - '[''object_id'']' items: type: string type: array @@ -650,7 +1064,7 @@ components: objects: description: The object values of the property example: - - '[''objectId'']' + - '[''object_id'']' items: type: string type: array @@ -658,8 +1072,6 @@ components: type: object apimodel.PhonePropertyLinkValue: properties: - format: - $ref: '#/components/schemas/apimodel.PropertyFormat' key: example: phone type: string @@ -795,17 +1207,19 @@ components: apimodel.SearchRequest: properties: query: - description: The search term to look for in object names and snippets + description: The text to search within object names and content; use types + field for type filtering example: test type: string sort: $ref: '#/components/schemas/apimodel.SortOptions' types: - description: The types of objects to search for, specified by key or ID + description: The types of objects to include in results (e.g., "page", "task", + "bookmark"); see ListTypes endpoint for valid values example: - page - - 678043f0cda9133be777049f - - bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q + - task + - bookmark items: type: string type: array @@ -813,13 +1227,13 @@ components: type: object apimodel.SelectPropertyLinkValue: properties: - format: - $ref: '#/components/schemas/apimodel.PropertyFormat' key: example: status type: string select: - description: The selected tag value of the property + description: The selected tag id of the property; see ListTags endpoint + for valid values + example: tag_id type: string type: object apimodel.SelectPropertyValue: @@ -868,7 +1282,7 @@ components: type: object apimodel.SortDirection: default: desc - description: The direction to sort the search results + description: The direction to sort the search results by enum: - asc - desc @@ -877,7 +1291,7 @@ components: - Asc - Desc apimodel.SortOptions: - description: The sorting criteria and direction for the search results + description: The sorting options for the search results properties: direction: $ref: '#/components/schemas/apimodel.SortDirection' @@ -886,7 +1300,7 @@ components: type: object apimodel.SortProperty: default: last_modified_date - description: The property to sort the search results by + description: The key of the property to sort the search results by enum: - created_date - last_modified_date @@ -967,8 +1381,6 @@ components: type: object apimodel.TextPropertyLinkValue: properties: - format: - $ref: '#/components/schemas/apimodel.PropertyFormat' key: example: description type: string @@ -1002,13 +1414,6 @@ components: example: Some text... type: string type: object - apimodel.TokenResponse: - properties: - app_key: - description: The app key used to authenticate requests - example: zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6= - type: string - type: object apimodel.Type: description: The type of the object properties: @@ -1029,7 +1434,16 @@ components: type: string layout: description: The layout of the object - example: basic + enum: + - basic + - profile + - action + - note + - bookmark + - set + - set + - collection + - participant type: string x-enum-varnames: - ObjectLayoutBasic @@ -1061,7 +1475,11 @@ components: type: object apimodel.TypeLayout: description: The layout of the type - example: basic + enum: + - basic + - profile + - action + - note type: string x-enum-varnames: - TypeLayoutBasic @@ -1075,8 +1493,6 @@ components: type: object apimodel.URLPropertyLinkValue: properties: - format: - $ref: '#/components/schemas/apimodel.PropertyFormat' key: example: source type: string @@ -1120,7 +1536,8 @@ components: type: string properties: description: '⚠ Warning: Properties are experimental and may change in the - next update. ⚠ The properties to set for the object' + next update. ⚠ The properties to set for the object; see ListTypes or + GetType endpoints for linked properties' items: $ref: '#/components/schemas/apimodel.PropertyLinkWithValue' type: array @@ -1128,6 +1545,11 @@ components: type: object apimodel.UpdatePropertyRequest: properties: + key: + description: The key to set for the property; ; should always be snake_case, + otherwise it will be converted to snake_case + example: some_user_defined_property_key + type: string name: description: The name to set for the property example: Last modified date @@ -1159,15 +1581,13 @@ components: properties: icon: $ref: '#/components/schemas/apimodel.Icon' - layout: - description: The layout of the type - example: basic + key: + description: The key to set for the type; should always be snake_case, otherwise + it will be converted to snake_case + example: some_user_defined_type_key type: string - x-enum-varnames: - - TypeLayoutBasic - - TypeLayoutProfile - - TypeLayoutAction - - TypeLayoutNote + layout: + $ref: '#/components/schemas/apimodel.TypeLayout' name: description: The name to set for the type example: Page @@ -1431,33 +1851,90 @@ info: email: support@anytype.io name: Anytype Support url: https://anytype.io/contact - description: This API empowers seamless interaction with Anytype's resources—spaces, + description: This API enables seamless interaction with Anytype's resources - spaces, objects, properties, types, templates, and beyond. license: name: Any Source Available License 1.0 url: https://github.com/anyproto/anytype-api/blob/main/LICENSE.md termsOfService: https://anytype.io/terms_of_use title: Anytype API - version: "2025-04-22" + version: "2025-05-20" openapi: 3.1.0 paths: - /auth/display_code: + /v1/auth/api_keys: post: - description: Generates a one-time authentication challenge for granting API - access to the user's vault. Upon providing a valid `app_name`, the server - issues a unique `challenge_id` and displays a short code within the Anytype - Desktop On success, the service returns a unique challenge ID. This challenge - ID must then be used with the token endpoint (see below) to solve the challenge - and retrieve an authentication token. This mechanism ensures that only trusted - applications and authorized users gain access. - operationId: createAuthChallenge + description: After receiving a `challenge_id` from the `/v1/auth/challenges` + endpoint, the client calls this endpoint to provide the corresponding 4-digit + code along with the challenge ID. The endpoint verifies that the challenge + solution is correct and, if it is, returns an `api_key`. This endpoint is + central to the authentication process, as it validates the user's identity + and issues a key that can be used for further interactions with the API. + operationId: create_api_key parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" + type: string + - description: The ID of the challenge to solve + in: query + name: challenge_id + required: true + schema: + type: string + - description: The 4-digit code retrieved from Anytype Desktop app + in: query + name: code + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + type: object + responses: + "201": + content: + application/json: + schema: + $ref: '#/components/schemas/apimodel.CreateApiKeyResponse' + description: The API key that can be used in the Authorization header for + subsequent requests + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ValidationError' + description: Bad request + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' + description: Internal server error + summary: Create API Key + tags: + - Auth + /v1/auth/challenges: + post: + description: Generates a one-time authentication challenge for granting API + access to the user's vault. Upon providing a valid `app_name`, the server + issues a unique `challenge_id` and displays a 4-digit code within the Anytype + Desktop. The `challenge_id` must then be used with the `/v1/auth/api_keys` + endpoint to solve the challenge and retrieve an authentication token. This + mechanism ensures that only trusted applications and authorized users gain + access. + operationId: create_auth_challenge + parameters: + - description: The version of the API to use + in: header + name: Anytype-Version + required: true + schema: + default: "2025-05-20" type: string - description: The name of the app requesting API access in: query @@ -1471,101 +1948,44 @@ paths: schema: type: object responses: - "200": + "201": content: application/json: schema: - $ref: '#/components/schemas/apimodel.DisplayCodeResponse' + $ref: '#/components/schemas/apimodel.CreateChallengeResponse' description: The challenge ID associated with the started challenge "400": content: application/json: schema: $ref: '#/components/schemas/util.ValidationError' - description: Invalid input + description: Bad request "500": content: application/json: schema: $ref: '#/components/schemas/util.ServerError' description: Internal server error - summary: Start new challenge + summary: Create Challenge tags: - Auth - /auth/token: + /v1/search: post: - description: After receiving a challenge ID from the display_code endpoint, - the client calls this endpoint to provide the corresponding 4-digit code (also - via a query parameter) along with the challenge ID. The endpoint verifies - that the challenge solution is correct and, if it is, returns a permanent - app key. This endpoint is central to the authentication process, as it validates - the user's identity and issues a token that can be used for further interactions - with the API. - operationId: solveAuthChallenge + description: 'Executes a global search over all spaces accessible to the authenticated + user. The request body must specify the `query` text (currently matching only + name and snippet of an object), optional filters on types (e.g., "page", "task"), + and sort directives (default: descending by last modified date). Pagination + is controlled via `offset` and `limit` query parameters to facilitate lazy + loading in client UIs. The response returns a unified list of matched objects + with their metadata and properties.' + operationId: search_global parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" - type: string - - description: The ID of the challenge to solve - in: query - name: challenge_id - required: true - schema: - type: string - - description: 4-digit code retrieved from Anytype Desktop app - in: query - name: code - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - type: object - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/apimodel.TokenResponse' - description: The app key that can be used in the Authorization header for - subsequent requests - "400": - content: - application/json: - schema: - $ref: '#/components/schemas/util.ValidationError' - description: Invalid input - "500": - content: - application/json: - schema: - $ref: '#/components/schemas/util.ServerError' - description: Internal server error - summary: Solve challenge - tags: - - Auth - /search: - post: - description: 'Executes a global search over every space accessible by the authenticated - user. The request body must specify the `query` text, optional filters on - object types (e.g., "page", "task"), and sort directives (default: descending - by last updated timestamp). Pagination is controlled via `offset` and `limit` - query parameters to facilitate lazy loading in client UIs. The response returns - a unified list of matched objects with their metadata and properties.' - operationId: searchGlobal - parameters: - - description: The version of the API to use - in: header - name: Anytype-Version - required: true - schema: - default: "2025-04-22" + default: "2025-05-20" type: string - description: The number of items to skip before starting to collect the result set @@ -1612,20 +2032,20 @@ paths: summary: Search objects across all spaces tags: - Search - /spaces: + /v1/spaces: get: description: Retrieves a paginated list of all spaces that are accessible by the authenticated user. Each space record contains detailed information such as the space ID, name, icon (derived either from an emoji or image URL), and additional metadata. This endpoint is key to displaying a user’s workspaces. - operationId: listSpaces + operationId: list_spaces parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - description: The number of items to skip before starting to collect the result set @@ -1672,14 +2092,14 @@ paths: the workspace with default settings (for example, a default dashboard or home page). On success, the new space’s full metadata is returned, enabling the client to immediately switch context to the new internal. - operationId: createSpace + operationId: create_space parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string requestBody: content: @@ -1689,7 +2109,7 @@ paths: description: The space to create required: true responses: - "200": + "201": content: application/json: schema: @@ -1724,22 +2144,23 @@ paths: summary: Create space tags: - Spaces - /spaces/{space_id}: + /v1/spaces/{space_id}: get: description: Fetches full details about a single space identified by its space ID. The response includes metadata such as the space name, icon, and various workspace IDs (home, archive, profile, etc.). This detailed view supports use cases such as displaying space-specific settings. - operationId: getSpace + operationId: get_space parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to retrieve + - description: The ID of the space to retrieve; must be retrieved from ListSpaces + endpoint in: path name: space_id required: true @@ -1780,16 +2201,17 @@ paths: body should contain the new name and/or description in JSON format. This endpoint is useful for renaming or rebranding a workspace without needing to recreate it. The updated space’s metadata is returned in the response. - operationId: updateSpace + operationId: update_space parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to update + - description: The ID of the space to update; must be retrieved from ListSpaces + endpoint in: path name: space_id required: true @@ -1850,84 +2272,7 @@ paths: summary: Update space tags: - Spaces - /spaces/{space_id}/lists/{list_id}/{view_id}/objects: - get: - description: Returns a paginated list of objects associated with a specific - list (query or collection) within a space. When a view ID is provided, the - objects are filtered and sorted according to the view's configuration. If - no view ID is specified, all list objects are returned without filtering and - sorting. This endpoint helps clients to manage grouped objects (for example, - tasks within a list) by returning information for each item of the list. - operationId: getListObjects - parameters: - - description: The version of the API to use - in: header - name: Anytype-Version - required: true - schema: - default: "2025-04-22" - type: string - - description: The ID of the space to which the list belongs - in: path - name: space_id - required: true - schema: - type: string - - description: The ID of the list to retrieve objects for - in: path - name: list_id - required: true - schema: - type: string - - description: The ID of the view to retrieve objects for - in: path - name: view_id - required: true - schema: - type: string - - description: The number of items to skip before starting to collect the result - set - in: query - name: offset - schema: - default: 0 - type: integer - - description: The number of items to return - in: query - name: limit - schema: - type: integer - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/pagination.PaginatedResponse-apimodel_Object' - description: The list of objects associated with the specified list - "401": - content: - application/json: - schema: - $ref: '#/components/schemas/util.UnauthorizedError' - description: Unauthorized - "404": - content: - application/json: - schema: - $ref: '#/components/schemas/util.NotFoundError' - description: Not found - "500": - content: - application/json: - schema: - $ref: '#/components/schemas/util.ServerError' - description: Internal server error - security: - - bearerauth: [] - summary: Get objects in list - tags: - - Lists - /spaces/{space_id}/lists/{list_id}/objects: + /v1/spaces/{space_id}/lists/{list_id}/objects: post: description: Adds one or more objects to a specific list (collection only) by submitting a JSON array of object IDs. Upon success, the endpoint returns @@ -1935,22 +2280,24 @@ paths: that allow drag‑and‑drop or multi‑select additions to collections, enabling users to dynamically manage their collections without needing to modify the underlying object data. - operationId: addListObjects + operationId: add_list_objects parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to which the list belongs + - description: The ID of the space to which the list belongs; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the list to which objects will be added + - description: 'The ID of the list to which objects will be added; must be retrieved + from SearchSpace endpoint with types: [''collection'', ''set'']' in: path name: list_id required: true @@ -1960,10 +2307,9 @@ paths: content: application/json: schema: - items: - type: string - type: array - description: The list of object IDs to add to the list + $ref: '#/components/schemas/apimodel.AddObjectsToListRequest' + description: The list of object IDs to add to the list; must be retrieved + from SearchSpace or GlobalSearch endpoints or obtained from response context required: true responses: "200": @@ -2007,34 +2353,37 @@ paths: summary: Add objects to list tags: - Lists - /spaces/{space_id}/lists/{list_id}/objects/{object_id}: + /v1/spaces/{space_id}/lists/{list_id}/objects/{object_id}: delete: description: Removes a given object from the specified list (collection only) in a space. The endpoint takes the space, list, and object identifiers as path parameters and is subject to rate limiting. It is used for dynamically managing collections without affecting the underlying object data. - operationId: removeListObject + operationId: remove_list_object parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to which the list belongs + - description: The ID of the space to which the list belongs; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the list from which the object will be removed + - description: 'The ID of the list from which the object will be removed; must + be retrieved from SearchSpace endpoint with types: [''collection'', ''set'']' in: path name: list_id required: true schema: type: string - - description: The ID of the object to remove from the list + - description: The ID of the object to remove from the list; must be retrieved + from SearchSpace or GlobalSearch endpoints or obtained from response context in: path name: object_id required: true @@ -2082,7 +2431,7 @@ paths: summary: Remove object from list tags: - Lists - /spaces/{space_id}/lists/{list_id}/views: + /v1/spaces/{space_id}/lists/{list_id}/views: get: description: Returns a paginated list of views defined for a specific list (query or collection) within a space. Each view includes details such as layout, @@ -2090,22 +2439,24 @@ paths: according to user preferences and context. This endpoint is essential for applications that need to display lists in various formats (e.g., grid, table) or with different sorting/filtering criteria. - operationId: getListViews + operationId: get_list_views parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to which the list belongs + - description: The ID of the space to which the list belongs; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the list to retrieve views for + - description: 'The ID of the list to retrieve views for; must be retrieved + from SearchSpace endpoint with types: [''collection'', ''set'']' in: path name: list_id required: true @@ -2153,7 +2504,88 @@ paths: summary: Get list views tags: - Lists - /spaces/{space_id}/members: + /v1/spaces/{space_id}/lists/{list_id}/views/{view_id}/objects: + get: + description: Returns a paginated list of objects associated with a specific + list (query or collection) within a space. When a view ID is provided, the + objects are filtered and sorted according to the view's configuration. If + no view ID is specified, all list objects are returned without filtering and + sorting. This endpoint helps clients to manage grouped objects (for example, + tasks within a list) by returning information for each item of the list. + operationId: get_list_objects + parameters: + - description: The version of the API to use + in: header + name: Anytype-Version + required: true + schema: + default: "2025-05-20" + type: string + - description: The ID of the space to which the list belongs; must be retrieved + from ListSpaces endpoint + in: path + name: space_id + required: true + schema: + type: string + - description: 'The ID of the list to retrieve objects for; must be retrieved + from SearchSpace endpoint with types: [''collection'', ''set'']' + in: path + name: list_id + required: true + schema: + type: string + - description: The ID of the view to retrieve objects for; must be retrieved + from ListViews endpoint or omitted if you want to get all objects in the + list + in: path + name: view_id + required: true + schema: + type: string + - description: The number of items to skip before starting to collect the result + set + in: query + name: offset + schema: + default: 0 + type: integer + - description: The number of items to return + in: query + name: limit + schema: + type: integer + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/pagination.PaginatedResponse-apimodel_Object' + description: The list of objects associated with the specified list + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/util.UnauthorizedError' + description: Unauthorized + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/util.NotFoundError' + description: Not found + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/util.ServerError' + description: Internal server error + security: + - bearerauth: [] + summary: Get objects in list + tags: + - Lists + /v1/spaces/{space_id}/members: get: description: Returns a paginated list of members belonging to the specified space. Each member record includes the member’s profile ID, name, icon (which @@ -2161,16 +2593,17 @@ paths: (e.g. joining, active) and role (e.g. Viewer, Editor, Owner). This endpoint supports collaborative features by allowing clients to show who is in a space and manage access rights. - operationId: listMembers + operationId: list_members parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to list members for + - description: The ID of the space to list members for; must be retrieved from + ListSpaces endpoint in: path name: space_id required: true @@ -2214,7 +2647,7 @@ paths: summary: List members tags: - Members - /spaces/{space_id}/members/{member_id}: + /v1/spaces/{space_id}/members/{member_id}: get: description: Fetches detailed information about a single member within a space. The endpoint returns the member’s identifier, name, icon, identity, global @@ -2222,22 +2655,24 @@ paths: the member's ID (starting with `_participant`) or the member's identity. This is useful for user profile pages, permission management, and displaying member-specific information in collaborative environments. - operationId: getMember + operationId: get_member parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to get the member from + - description: The ID of the space to get the member from; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: Member ID or Identity + - description: Member ID or Identity; must be retrieved from ListMembers endpoint + or obtained from response context in: path name: member_id required: true @@ -2273,7 +2708,7 @@ paths: summary: Get member tags: - Members - /spaces/{space_id}/objects: + /v1/spaces/{space_id}/objects: get: description: Retrieves a paginated list of objects in the given space. The endpoint takes query parameters for pagination (offset and limit) and returns detailed @@ -2281,16 +2716,17 @@ paths: of the content (if applicable), layout, space ID, blocks and details. It is intended for building views where users can see all objects in a space at a glance. - operationId: listObjects + operationId: list_objects parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space in which to list objects + - description: The ID of the space in which to list objects; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true @@ -2343,16 +2779,17 @@ paths: of object to create). Post-creation, additional operations (like setting featured properties or fetching bookmark metadata) may occur. The endpoint then returns the full object data, ready for further interactions. - operationId: createObject + operationId: create_object parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space in which to create the object + - description: The ID of the space in which to create the object; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true @@ -2366,7 +2803,7 @@ paths: description: The object to create required: true responses: - "200": + "201": content: application/json: schema: @@ -2401,29 +2838,31 @@ paths: summary: Create object tags: - Objects - /spaces/{space_id}/objects/{object_id}: + /v1/spaces/{space_id}/objects/{object_id}: delete: description: This endpoint “deletes” an object by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the object’s details after it has been archived. Proper error handling is in place for situations such as when the object isn’t found or the deletion cannot be performed because of permission issues. - operationId: deleteObject + operationId: delete_object parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space in which the object exists + - description: The ID of the space in which the object exists; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the object to delete + - description: The ID of the object to delete; must be retrieved from ListObjects, + SearchSpace or GlobalSearch endpoints or obtained from response context in: path name: object_id required: true @@ -2484,22 +2923,24 @@ paths: text, files, properties and dataviews) and extra details (such as timestamps and linked member information). This endpoint is essential when a client needs to render or edit the full object view. - operationId: getObject + operationId: get_object parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space in which the object exists + - description: The ID of the space in which the object exists; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the object to retrieve + - description: The ID of the object to retrieve; must be retrieved from ListObjects, + SearchSpace or GlobalSearch endpoints or obtained from response context in: path name: object_id required: true @@ -2554,22 +2995,24 @@ paths: using a JSON payload. The update process is subject to rate limiting. The payload must include the details to be updated. The endpoint then returns the full object data, ready for further interactions. - operationId: updateObject + operationId: update_object parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space in which the object exists + - description: The ID of the space in which the object exists; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the object to update + - description: The ID of the object to update; must be retrieved from ListObjects, + SearchSpace or GlobalSearch endpoints or obtained from response context in: path name: object_id required: true @@ -2630,23 +3073,24 @@ paths: summary: Update object tags: - Objects - /spaces/{space_id}/properties: + /v1/spaces/{space_id}/properties: get: description: '⚠ Warning: Properties are experimental and may change in the next update. ⚠ Retrieves a paginated list of properties available within a specific space. Each property record includes its unique identifier, name and format. This information is essential for clients to understand the available properties for filtering or creating objects.' - operationId: listProperties + operationId: list_properties parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to list properties for + - description: The ID of the space to list properties for; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true @@ -2696,16 +3140,17 @@ paths: The creation process is subject to rate limiting. The payload must include property details such as the name and format. The endpoint then returns the full property data, ready for further interactions.' - operationId: createProperty + operationId: create_property parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to create the property in + - description: The ID of the space to create the property in; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true @@ -2719,7 +3164,7 @@ paths: description: The property to create required: true responses: - "200": + "201": content: application/json: schema: @@ -2754,7 +3199,7 @@ paths: summary: Create property tags: - Properties - /spaces/{space_id}/properties/{property_id}: + /v1/spaces/{space_id}/properties/{property_id}: delete: description: '⚠ Warning: Properties are experimental and may change in the next update. ⚠ This endpoint “deletes” a property by marking it as archived. The @@ -2762,22 +3207,24 @@ paths: the property’s details after it has been archived. Proper error handling is in place for situations such as when the property isn’t found or the deletion cannot be performed because of permission issues.' - operationId: deleteProperty + operationId: delete_property parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to which the property belongs + - description: The ID of the space to which the property belongs; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the property to delete + - description: The ID of the property to delete; must be retrieved from ListProperties + endpoint or obtained from response context in: path name: property_id required: true @@ -2838,22 +3285,24 @@ paths: detailed view assists clients in showing property options to users and in guiding the user interface (such as displaying appropriate input fields or selection options).' - operationId: getProperty + operationId: get_property parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to which the property belongs + - description: The ID of the space to which the property belongs; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the property to retrieve + - description: The ID of the property to retrieve; must be retrieved from ListProperties + endpoint or obtained from response context in: path name: property_id required: true @@ -2901,22 +3350,24 @@ paths: using a JSON payload. The update process is subject to rate limiting. The payload must include the name to be updated. The endpoint then returns the full property data, ready for further interactions.' - operationId: updateProperty + operationId: update_property parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to which the property belongs + - description: The ID of the space to which the property belongs; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the property to update + - description: The ID of the property to update; must be retrieved from ListProperties + endpoint or obtained from response context in: path name: property_id required: true @@ -2983,29 +3434,31 @@ paths: summary: Update property tags: - Properties - /spaces/{space_id}/properties/{property_id}/tags: + /v1/spaces/{space_id}/properties/{property_id}/tags: get: description: This endpoint retrieves a paginated list of tags available for a specific property within a space. Each tag record includes its unique identifier, name, and color. This information is essential for clients to display select or multi-select options to users when they are creating or editing objects. The endpoint also supports pagination through offset and limit parameters. - operationId: listTags + operationId: list_tags parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to list tags for + - description: The ID of the space to list tags for; must be retrieved from + ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the property to list tags for + - description: The ID of the property to list tags for; must be retrieved from + ListProperties endpoint or obtained from response context in: path name: property_id required: true @@ -3048,22 +3501,24 @@ paths: the tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to add new tag options to a property. - operationId: createTag + operationId: create_tag parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to create the tag in + - description: The ID of the space to create the tag in; must be retrieved from + ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the property to create the tag for + - description: The ID of the property to create the tag for; must be retrieved + from ListProperties endpoint or obtained from response context in: path name: property_id required: true @@ -3077,7 +3532,7 @@ paths: description: The tag to create required: true responses: - "200": + "201": content: application/json: schema: @@ -3112,35 +3567,38 @@ paths: summary: Create tag tags: - Tags - /spaces/{space_id}/properties/{property_id}/tags/{tag_id}: + /v1/spaces/{space_id}/properties/{property_id}/tags/{tag_id}: delete: description: This endpoint “deletes” a tag by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the tag’s details after it has been archived. Proper error handling is in place for situations such as when the tag isn’t found or the deletion cannot be performed because of permission issues. - operationId: deleteTag + operationId: delete_tag parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to delete the tag from + - description: The ID of the space to delete the tag from; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the property to delete the tag for + - description: The ID of the property to delete the tag for; must be retrieved + from ListProperties endpoint or obtained from response context in: path name: property_id required: true schema: type: string - - description: The ID of the tag to delete + - description: The ID of the tag to delete; must be retrieved from ListTags + endpoint or obtained from response context in: path name: tag_id required: true @@ -3199,28 +3657,31 @@ paths: is identified by its unique identifier within the specified space. The response includes the tag's details such as its ID, name, and color. This is useful for clients to display or when editing a specific tag option. - operationId: getTag + operationId: get_tag parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to retrieve the tag from + - description: The ID of the space to retrieve the tag from; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the property to retrieve the tag for + - description: The ID of the property to retrieve the tag for; must be retrieved + from ListProperties endpoint or obtained from response context in: path name: property_id required: true schema: type: string - - description: The ID of the tag to retrieve + - description: The ID of the tag to retrieve; must be retrieved from ListTags + endpoint or obtained from response context in: path name: tag_id required: true @@ -3269,28 +3730,31 @@ paths: tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to edit existing tags for a property. - operationId: updateTag + operationId: update_tag parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to update the tag in + - description: The ID of the space to update the tag in; must be retrieved from + ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the property to update the tag for + - description: The ID of the property to update the tag for; must be retrieved + from ListProperties endpoint or obtained from response context in: path name: property_id required: true schema: type: string - - description: The ID of the tag to update + - description: The ID of the tag to update; must be retrieved from ListTags + endpoint or obtained from response context in: path name: tag_id required: true @@ -3357,24 +3821,25 @@ paths: summary: Update tag tags: - Tags - /spaces/{space_id}/search: + /v1/spaces/{space_id}/search: post: - description: Performs a focused search within a single space (specified by the - space_id path parameter). Like the global search, it accepts pagination parameters - and a JSON payload containing the search query, object types, and sorting - preferences. The search is limited to the provided space and returns a list - of objects that match the query. This allows clients to implement space‑specific - filtering without having to process extraneous results. - operationId: searchSpace + description: Performs a search within a single space (specified by the `space_id` + path parameter). Like the global search, it accepts pagination parameters + and a JSON payload containing the search `query`, `types`, and sorting preferences. + The search is limited to the provided space and returns a list of objects + that match the query. This allows clients to implement space‑specific filtering + without having to process extraneous results. + operationId: search_space parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to search in + - description: The ID of the space to search in; must be retrieved from ListSpaces + endpoint in: path name: space_id required: true @@ -3425,25 +3890,25 @@ paths: summary: Search objects within a space tags: - Search - /spaces/{space_id}/types: + /v1/spaces/{space_id}/types: get: - description: This endpoint retrieves a paginated list of object types (e.g. - 'Page', 'Note', 'Task') available within the specified space. Each type’s - record includes its unique identifier, type key, display name, icon, and layout. - While a type's id is truly unique, a type's key can be the same across spaces - for known types, e.g. 'page' for 'Page'. Clients use this information when - offering choices for object creation or for filtering objects by type through - search. - operationId: listTypes + description: This endpoint retrieves a paginated list of types (e.g. 'Page', + 'Note', 'Task') available within the specified space. Each type’s record includes + its unique identifier, type key, display name, icon, and layout. While a type's + id is truly unique, a type's key can be the same across spaces for known types, + e.g. 'page' for 'Page'. Clients use this information when offering choices + for object creation or for filtering objects by type through search. + operationId: list_types parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to retrieve types from + - description: The ID of the space to retrieve types from; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true @@ -3488,20 +3953,21 @@ paths: tags: - Types post: - description: Creates a new object type in the specified space using a JSON payload. + description: Creates a new type in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include type details such as the name, icon, and layout. The endpoint then returns the full type data, ready to be used for creating objects. - operationId: createType + operationId: create_type parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space in which to create the type + - description: The ID of the space in which to create the type; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true @@ -3515,7 +3981,7 @@ paths: description: The type to create required: true responses: - "200": + "201": content: application/json: schema: @@ -3550,29 +4016,31 @@ paths: summary: Create type tags: - Types - /spaces/{space_id}/types/{type_id}: + /v1/spaces/{space_id}/types/{type_id}: delete: - description: This endpoint “deletes” an object type by marking it as archived. - The deletion process is performed safely and is subject to rate limiting. - It returns the type’s details after it has been archived. Proper error handling - is in place for situations such as when the type isn’t found or the deletion - cannot be performed because of permission issues. - operationId: deleteType + description: This endpoint “deletes” an type by marking it as archived. The + deletion process is performed safely and is subject to rate limiting. It returns + the type’s details after it has been archived. Proper error handling is in + place for situations such as when the type isn’t found or the deletion cannot + be performed because of permission issues. + operationId: delete_type parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space from which to delete the type + - description: The ID of the space from which to delete the type; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the type to delete + - description: The ID of the type to delete; must be retrieved from ListTypes + endpoint or obtained from response context in: path name: type_id required: true @@ -3627,27 +4095,29 @@ paths: tags: - Types get: - description: Fetches detailed information about one specific object type by - its ID. This includes the type’s unique key, name, icon, and layout. This - detailed view assists clients in understanding the expected structure and - style for objects of that type and in guiding the user interface (such as - displaying appropriate icons or layout hints). - operationId: getType + description: Fetches detailed information about one specific type by its ID. + This includes the type’s unique key, name, icon, and layout. This detailed + view assists clients in understanding the expected structure and style for + objects of that type and in guiding the user interface (such as displaying + appropriate icons or layout hints). + operationId: get_type parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space from which to retrieve the type + - description: The ID of the space from which to retrieve the type; must be + retrieved from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the type to retrieve + - description: The ID of the type to retrieve; must be retrieved from ListTypes + endpoint or obtained from response context in: path name: type_id required: true @@ -3690,26 +4160,28 @@ paths: tags: - Types patch: - description: This endpoint updates an existing object type in the specified - space using a JSON payload. The update process is subject to rate limiting. - The payload must include the name and properties to be updated. The endpoint - then returns the full type data, ready for further interactions. - operationId: updateType + description: This endpoint updates an existing type in the specified space using + a JSON payload. The update process is subject to rate limiting. The payload + must include the name and properties to be updated. The endpoint then returns + the full type data, ready for further interactions. + operationId: update_type parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space in which the type exists + - description: The ID of the space in which the type exists; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the type to update + - description: The ID of the type to update; must be retrieved from ListTypes + endpoint or obtained from response context in: path name: type_id required: true @@ -3770,29 +4242,31 @@ paths: summary: Update type tags: - Types - /spaces/{space_id}/types/{type_id}/templates: + /v1/spaces/{space_id}/types/{type_id}/templates: get: description: This endpoint returns a paginated list of templates that are associated - with a specific object type within a space. Templates provide pre‑configured - structures for creating new objects. Each template record contains its identifier, - name, and icon, so that clients can offer users a selection of templates when - creating objects. - operationId: listTemplates + with a specific type within a space. Templates provide pre‑configured structures + for creating new objects. Each template record contains its identifier, name, + and icon, so that clients can offer users a selection of templates when creating + objects. + operationId: list_templates parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to which the type belongs + - description: The ID of the space to which the type belongs; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the object type to retrieve templates for + - description: The ID of the type to retrieve templates for; must be retrieved + from ListTypes endpoint or obtained from response context in: path name: type_id required: true @@ -3836,34 +4310,37 @@ paths: summary: List templates tags: - Templates - /spaces/{space_id}/types/{type_id}/templates/{template_id}: + /v1/spaces/{space_id}/types/{type_id}/templates/{template_id}: get: description: Fetches full details for one template associated with a particular - object type in a space. The response provides the template’s identifier, name, - icon, and any other relevant metadata. This endpoint is useful when a client - needs to preview or apply a template to prefill object creation fields. - operationId: getTemplate + type in a space. The response provides the template’s identifier, name, icon, + and any other relevant metadata. This endpoint is useful when a client needs + to preview or apply a template to prefill object creation fields. + operationId: get_template parameters: - description: The version of the API to use in: header name: Anytype-Version required: true schema: - default: "2025-04-22" + default: "2025-05-20" type: string - - description: The ID of the space to which the template belongs + - description: The ID of the space to which the template belongs; must be retrieved + from ListSpaces endpoint in: path name: space_id required: true schema: type: string - - description: The ID of the object type to which the template belongs + - description: The ID of the type to which the template belongs; must be retrieved + from ListTypes endpoint or obtained from response context in: path name: type_id required: true schema: type: string - - description: The ID of the template to retrieve + - description: The ID of the template to retrieve; must be retrieved from ListTemplates + endpoint or obtained from response context in: path name: template_id required: true @@ -3906,4 +4383,4 @@ paths: tags: - Templates servers: -- url: http://localhost:31009/v1 +- url: http://localhost:31009 diff --git a/core/api/docs/swagger.json b/core/api/docs/swagger.json deleted file mode 100644 index 6809ef2d4..000000000 --- a/core/api/docs/swagger.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "components": {"schemas":{"apimodel.CheckboxPropertyLinkValue":{"properties":{"checkbox":{"description":"The checkbox value of the property","example":true,"type":"boolean"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"done","type":"string"}},"type":"object"},"apimodel.CheckboxPropertyValue":{"properties":{"checkbox":{"description":"The checkbox value of the property","example":true,"type":"boolean"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"done","type":"string"},"name":{"description":"The name of the property","example":"Done","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.Color":{"description":"The color of the icon","enum":["grey","yellow","orange","red","pink","purple","blue","ice","teal","lime"],"example":"yellow","type":"string","x-enum-varnames":["ColorGrey","ColorYellow","ColorOrange","ColorRed","ColorPink","ColorPurple","ColorBlue","ColorIce","ColorTeal","ColorLime"]},"apimodel.CreateObjectRequest":{"properties":{"body":{"description":"The body of the object","example":"This is the body of the object. Markdown syntax is supported here.","type":"string"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"name":{"description":"The name of the object","example":"My object","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set on the object","items":{"$ref":"#/components/schemas/apimodel.PropertyLinkWithValue"},"type":"array","uniqueItems":false},"template_id":{"description":"The id of the template to use","example":"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge","type":"string"},"type_key":{"description":"The key of the type of object to create","example":"page","type":"string"}},"required":["type_key"],"type":"object"},"apimodel.CreatePropertyRequest":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"}},"required":["format","name"],"type":"object"},"apimodel.CreateSpaceRequest":{"properties":{"description":{"description":"The description of the space","example":"The local-first wiki","type":"string"},"name":{"description":"The name of the space","example":"New Space","type":"string"}},"required":["name"],"type":"object"},"apimodel.CreateTagRequest":{"properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"name":{"description":"The name of the tag","example":"In progress","type":"string"}},"required":["color","name"],"type":"object"},"apimodel.CreateTypeRequest":{"properties":{"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"layout":{"$ref":"#/components/schemas/apimodel.TypeLayout"},"name":{"description":"The name of the type","example":"Page","type":"string"},"plural_name":{"description":"The plural name of the type","example":"Pages","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties linked to the type","items":{"$ref":"#/components/schemas/apimodel.PropertyLink"},"type":"array","uniqueItems":false}},"required":["layout","name"],"type":"object"},"apimodel.DatePropertyLinkValue":{"properties":{"date":{"description":"The date value of the property","example":"2025-02-14T12:34:56Z","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"last_modified_date","type":"string"}},"type":"object"},"apimodel.DatePropertyValue":{"properties":{"date":{"description":"The date value of the property","example":"2025-02-14T12:34:56Z","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"last_modified_date","type":"string"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.DisplayCodeResponse":{"properties":{"challenge_id":{"description":"The challenge id associated with the displayed code and needed to solve the challenge for token","example":"67647f5ecda913e9a2e11b26","type":"string"}},"type":"object"},"apimodel.EmailPropertyLinkValue":{"properties":{"email":{"description":"The email value of the property","example":"example@example.com","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"email","type":"string"}},"type":"object"},"apimodel.EmailPropertyValue":{"properties":{"email":{"description":"The email value of the property","example":"example@example.com","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"email","type":"string"},"name":{"description":"The name of the property","example":"Email","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.EmojiIcon":{"properties":{"emoji":{"description":"The emoji of the icon","example":"📄","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.IconFormat"}},"type":"object"},"apimodel.FileIcon":{"properties":{"file":{"description":"The file of the icon","example":"bafybeieptz5hvcy6txplcvphjbbh5yjc2zqhmihs3owkh5oab4ezauzqay","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.IconFormat"}},"type":"object"},"apimodel.FilesPropertyLinkValue":{"properties":{"files":{"description":"The file values of the property","example":["['fileId']"],"items":{"type":"string"},"type":"array","uniqueItems":false},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"files","type":"string"}},"type":"object"},"apimodel.FilesPropertyValue":{"properties":{"files":{"description":"The file values of the property","example":["['fileId']"],"items":{"type":"string"},"type":"array","uniqueItems":false},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"files","type":"string"},"name":{"description":"The name of the property","example":"Files","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.Filter":{"properties":{"condition":{"description":"The filter condition","enum":["equal","not_equal","greater","less","greater_or_equal","less_or_equal","like","not_like","in","not_in","empty","not_empty","all_in","not_all_in","exact_in","not_exact_in","exists"],"example":"contains","type":"string"},"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the filter","example":"67bf3f21cda9134102e2422c","type":"string"},"property_key":{"description":"The property key used for filtering","example":"name","type":"string"},"value":{"description":"The value used for filtering","example":"Some value...","type":"string"}},"type":"object"},"apimodel.Icon":{"description":"The icon of the object","oneOf":[{"$ref":"#/components/schemas/apimodel.EmojiIcon"},{"$ref":"#/components/schemas/apimodel.FileIcon"},{"$ref":"#/components/schemas/apimodel.NamedIcon"}],"type":"object"},"apimodel.IconFormat":{"description":"The format of the icon","enum":["icon"],"type":"string","x-enum-varnames":["IconFormatEmoji","IconFormatFile","IconFormatIcon"]},"apimodel.Member":{"description":"The member","properties":{"global_name":{"description":"The global name of the member in the network","example":"john.any","type":"string"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The profile object id of the member","example":"_participant_bafyreigyfkt6rbv24sbv5aq2hko1bhmv5xxlf22b4bypdu6j7hnphm3psq_23me69r569oi1_AAjEaEwPF4nkEh9AWkqEnzcQ8HziBB4ETjiTpvRCQvWnSMDZ","type":"string"},"identity":{"description":"The identity of the member in the network","example":"AAjEaEwPF4nkEh7AWkqEnzcQ8HziGB4ETjiTpvRCQvWnSMDZ","type":"string"},"name":{"description":"The name of the member","example":"John Doe","type":"string"},"object":{"description":"The data model of the object","example":"member","type":"string"},"role":{"description":"The role of the member","enum":["viewer","editor","owner","no_permission"],"example":"owner","type":"string"},"status":{"description":"The status of the member","enum":["joining","active","removed","declined","removing","canceled"],"example":"active","type":"string"}},"type":"object"},"apimodel.MemberResponse":{"properties":{"member":{"$ref":"#/components/schemas/apimodel.Member"}},"type":"object"},"apimodel.MultiSelectPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"tag","type":"string"},"multi_select":{"description":"The selected tag values of the property","items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.MultiSelectPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"tag","type":"string"},"multi_select":{"description":"The selected tag values of the property","items":{"$ref":"#/components/schemas/apimodel.Tag"},"type":"array","uniqueItems":false},"name":{"description":"The name of the property","example":"Tag","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.NamedIcon":{"properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"format":{"$ref":"#/components/schemas/apimodel.IconFormat"},"name":{"description":"The name of the icon","example":"document","type":"string"}},"type":"object"},"apimodel.NumberPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"height","type":"string"},"number":{"description":"The number value of the property","example":42,"type":"number"}},"type":"object"},"apimodel.NumberPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"height","type":"string"},"name":{"description":"The name of the property","example":"Height","type":"string"},"number":{"description":"The number value of the property","example":42,"type":"number"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.Object":{"properties":{"archived":{"description":"Whether the object is archived","example":false,"type":"boolean"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the object","example":"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ","type":"string"},"layout":{"$ref":"#/components/schemas/apimodel.ObjectLayout"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object":{"description":"The data model of the object","example":"object","type":"string"},"properties":{"description":"The properties of the object","items":{"$ref":"#/components/schemas/apimodel.PropertyWithValue"},"type":"array","uniqueItems":false},"snippet":{"description":"The snippet of the object, especially important for notes as they don't have a name","example":"The beginning of the object body...","type":"string"},"space_id":{"description":"The id of the space the object is in","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"type":{"$ref":"#/components/schemas/apimodel.Type"}},"type":"object"},"apimodel.ObjectLayout":{"description":"The layout of the object","example":"basic","type":"string","x-enum-varnames":["ObjectLayoutBasic","ObjectLayoutProfile","ObjectLayoutAction","ObjectLayoutNote","ObjectLayoutBookmark","ObjectLayoutSet","ObjectLayoutCollection","ObjectLayoutParticipant"]},"apimodel.ObjectResponse":{"properties":{"object":{"$ref":"#/components/schemas/apimodel.ObjectWithBody"}},"type":"object"},"apimodel.ObjectWithBody":{"description":"The object","properties":{"archived":{"description":"Whether the object is archived","example":false,"type":"boolean"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the object","example":"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ","type":"string"},"layout":{"description":"The layout of the object","example":"basic","type":"string","x-enum-varnames":["ObjectLayoutBasic","ObjectLayoutProfile","ObjectLayoutAction","ObjectLayoutNote","ObjectLayoutBookmark","ObjectLayoutSet","ObjectLayoutCollection","ObjectLayoutParticipant"]},"markdown":{"description":"The markdown body of the object","example":"# This is the title\n...","type":"string"},"name":{"description":"The name of the object","example":"My object","type":"string"},"object":{"description":"The data model of the object","example":"object","type":"string"},"properties":{"description":"The properties of the object","items":{"$ref":"#/components/schemas/apimodel.PropertyWithValue"},"type":"array","uniqueItems":false},"snippet":{"description":"The snippet of the object, especially important for notes as they don't have a name","example":"The beginning of the object body...","type":"string"},"space_id":{"description":"The id of the space the object is in","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"type":{"$ref":"#/components/schemas/apimodel.Type"}},"type":"object"},"apimodel.ObjectsPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"creator","type":"string"},"objects":{"description":"The object values of the property","example":["['objectId']"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.ObjectsPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"creator","type":"string"},"name":{"description":"The name of the property","example":"Created by","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"objects":{"description":"The object values of the property","example":["['objectId']"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.PhonePropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"phone","type":"string"},"phone":{"description":"The phone value of the property","example":"+1234567890","type":"string"}},"type":"object"},"apimodel.PhonePropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"phone","type":"string"},"name":{"description":"The name of the property","example":"Phone","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"phone":{"description":"The phone value of the property","example":"+1234567890","type":"string"}},"type":"object"},"apimodel.Property":{"description":"The property","properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"last_modified_date","type":"string"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"}},"type":"object"},"apimodel.PropertyFormat":{"description":"The format of the property used for filtering","enum":["text","number","select","multi_select","date","files","checkbox","url","email","phone","objects"],"type":"string","x-enum-varnames":["PropertyFormatText","PropertyFormatNumber","PropertyFormatSelect","PropertyFormatMultiSelect","PropertyFormatDate","PropertyFormatFiles","PropertyFormatCheckbox","PropertyFormatUrl","PropertyFormatEmail","PropertyFormatPhone","PropertyFormatObjects"]},"apimodel.PropertyLink":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"description":"The key of the property","example":"last_modified_date","type":"string"},"name":{"description":"The name of the property","example":"Last modified date","type":"string"}},"required":["format","key","name"],"type":"object"},"apimodel.PropertyLinkWithValue":{"oneOf":[{"$ref":"#/components/schemas/apimodel.TextPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.NumberPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.SelectPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.MultiSelectPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.DatePropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.FilesPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.CheckboxPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.URLPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.EmailPropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.PhonePropertyLinkValue"},{"$ref":"#/components/schemas/apimodel.ObjectsPropertyLinkValue"}],"type":"object"},"apimodel.PropertyResponse":{"properties":{"property":{"$ref":"#/components/schemas/apimodel.Property"}},"type":"object"},"apimodel.PropertyWithValue":{"oneOf":[{"$ref":"#/components/schemas/apimodel.TextPropertyValue"},{"$ref":"#/components/schemas/apimodel.NumberPropertyValue"},{"$ref":"#/components/schemas/apimodel.SelectPropertyValue"},{"$ref":"#/components/schemas/apimodel.MultiSelectPropertyValue"},{"$ref":"#/components/schemas/apimodel.DatePropertyValue"},{"$ref":"#/components/schemas/apimodel.FilesPropertyValue"},{"$ref":"#/components/schemas/apimodel.CheckboxPropertyValue"},{"$ref":"#/components/schemas/apimodel.URLPropertyValue"},{"$ref":"#/components/schemas/apimodel.EmailPropertyValue"},{"$ref":"#/components/schemas/apimodel.PhonePropertyValue"},{"$ref":"#/components/schemas/apimodel.ObjectsPropertyValue"}],"type":"object"},"apimodel.SearchRequest":{"properties":{"query":{"description":"The search term to look for in object names and snippets","example":"test","type":"string"},"sort":{"$ref":"#/components/schemas/apimodel.SortOptions"},"types":{"description":"The types of objects to search for, specified by key or ID","example":["page","678043f0cda9133be777049f","bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q"],"items":{"type":"string"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.SelectPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"status","type":"string"},"select":{"description":"The selected tag value of the property","type":"string"}},"type":"object"},"apimodel.SelectPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"status","type":"string"},"name":{"description":"The name of the property","example":"Status","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"select":{"$ref":"#/components/schemas/apimodel.Tag"}},"type":"object"},"apimodel.Sort":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the sort","example":"67bf3f21cda9134102e2422c","type":"string"},"property_key":{"description":"The property key used for sorting","example":"name","type":"string"},"sort_type":{"description":"The sort direction","enum":["asc","desc","custom"],"example":"asc","type":"string"}},"type":"object"},"apimodel.SortDirection":{"default":"desc","description":"The direction to sort the search results","enum":["asc","desc"],"type":"string","x-enum-varnames":["Asc","Desc"]},"apimodel.SortOptions":{"description":"The sorting criteria and direction for the search results","properties":{"direction":{"$ref":"#/components/schemas/apimodel.SortDirection"},"property_key":{"$ref":"#/components/schemas/apimodel.SortProperty"}},"type":"object"},"apimodel.SortProperty":{"default":"last_modified_date","description":"The property to sort the search results by","enum":["created_date","last_modified_date","last_opened_date","name"],"type":"string","x-enum-varnames":["CreatedDate","LastModifiedDate","LastOpenedDate","Name"]},"apimodel.Space":{"description":"The space","properties":{"description":{"description":"The description of the space","example":"The local-first wiki","type":"string"},"gateway_url":{"description":"The gateway url to serve files and media","example":"http://127.0.0.1:31006","type":"string"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the space","example":"bafyreigyfkt6rbv24sbv5aq2hko3bhmv5xxlf22b4bypdu6j7hnphm3psq.23me69r569oi1","type":"string"},"name":{"description":"The name of the space","example":"My Space","type":"string"},"network_id":{"description":"The network id of the space","example":"N83gJpVd9MuNRZAuJLZ7LiMntTThhPc6DtzWWVjb1M3PouVU","type":"string"},"object":{"description":"The data model of the object","example":"space","type":"string"}},"type":"object"},"apimodel.SpaceResponse":{"properties":{"space":{"$ref":"#/components/schemas/apimodel.Space"}},"type":"object"},"apimodel.Tag":{"description":"The selected tag value of the property","properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"id":{"description":"The id of the tag","example":"bafyreiaixlnaefu3ci22zdenjhsdlyaeeoyjrsid5qhfeejzlccijbj7sq","type":"string"},"key":{"description":"The key of the tag","example":"67b0d3e3cda913b84c1299b1","type":"string"},"name":{"description":"The name of the tag","example":"in-progress","type":"string"},"object":{"description":"The data model of the object","example":"tag","type":"string"}},"type":"object"},"apimodel.TagResponse":{"properties":{"tag":{"$ref":"#/components/schemas/apimodel.Tag"}},"type":"object"},"apimodel.TemplateResponse":{"properties":{"template":{"$ref":"#/components/schemas/apimodel.ObjectWithBody"}},"type":"object"},"apimodel.TextPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"description","type":"string"},"text":{"description":"The text value of the property","example":"Some text...","type":"string"}},"type":"object"},"apimodel.TextPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"description","type":"string"},"name":{"description":"The name of the property","example":"Description","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"text":{"description":"The text value of the property","example":"Some text...","type":"string"}},"type":"object"},"apimodel.TokenResponse":{"properties":{"app_key":{"description":"The app key used to authenticate requests","example":"zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6=","type":"string"}},"type":"object"},"apimodel.Type":{"description":"The type of the object","properties":{"archived":{"description":"Whether the type is archived","example":false,"type":"boolean"},"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"id":{"description":"The id of the type (which is unique across spaces)","example":"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu","type":"string"},"key":{"description":"The key of the type (can be the same across spaces for known types)","example":"page","type":"string"},"layout":{"description":"The layout of the object","example":"basic","type":"string","x-enum-varnames":["ObjectLayoutBasic","ObjectLayoutProfile","ObjectLayoutAction","ObjectLayoutNote","ObjectLayoutBookmark","ObjectLayoutSet","ObjectLayoutCollection","ObjectLayoutParticipant"]},"name":{"description":"The name of the type","example":"Page","type":"string"},"object":{"description":"The data model of the object","example":"type","type":"string"},"plural_name":{"description":"The plural name of the type","example":"Pages","type":"string"},"properties":{"description":"The properties linked to the type","items":{"$ref":"#/components/schemas/apimodel.Property"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.TypeLayout":{"description":"The layout of the type","example":"basic","type":"string","x-enum-varnames":["TypeLayoutBasic","TypeLayoutProfile","TypeLayoutAction","TypeLayoutNote"]},"apimodel.TypeResponse":{"properties":{"type":{"$ref":"#/components/schemas/apimodel.Type"}},"type":"object"},"apimodel.URLPropertyLinkValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"key":{"example":"source","type":"string"},"url":{"description":"The URL value of the property","example":"https://example.com","type":"string"}},"type":"object"},"apimodel.URLPropertyValue":{"properties":{"format":{"$ref":"#/components/schemas/apimodel.PropertyFormat"},"id":{"description":"The id of the property","example":"bafyreids36kpw5ppuwm3ce2p4ezb3ab7cihhkq6yfbwzwpp4mln7rcgw7a","type":"string"},"key":{"description":"The key of the property","example":"source","type":"string"},"name":{"description":"The name of the property","example":"Source","type":"string"},"object":{"description":"The data model of the object","example":"property","type":"string"},"url":{"description":"The URL value of the property","example":"https://example.com","type":"string"}},"type":"object"},"apimodel.UpdateObjectRequest":{"properties":{"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"name":{"description":"The name of the object","example":"My object","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set for the object","items":{"$ref":"#/components/schemas/apimodel.PropertyLinkWithValue"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.UpdatePropertyRequest":{"properties":{"name":{"description":"The name to set for the property","example":"Last modified date","type":"string"}},"required":["name"],"type":"object"},"apimodel.UpdateSpaceRequest":{"properties":{"description":{"description":"The description of the space","example":"The local-first wiki","type":"string"},"name":{"description":"The name of the space","example":"New Space","type":"string"}},"type":"object"},"apimodel.UpdateTagRequest":{"properties":{"color":{"$ref":"#/components/schemas/apimodel.Color"},"name":{"description":"The name to set for the tag","example":"In progress","type":"string"}},"type":"object"},"apimodel.UpdateTypeRequest":{"properties":{"icon":{"$ref":"#/components/schemas/apimodel.Icon"},"layout":{"description":"The layout of the type","example":"basic","type":"string","x-enum-varnames":["TypeLayoutBasic","TypeLayoutProfile","TypeLayoutAction","TypeLayoutNote"]},"name":{"description":"The name to set for the type","example":"Page","type":"string"},"plural_name":{"description":"The plural name to set for the type","example":"Pages","type":"string"},"properties":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set for the type","items":{"$ref":"#/components/schemas/apimodel.PropertyLink"},"type":"array","uniqueItems":false}},"type":"object"},"apimodel.View":{"properties":{"filters":{"description":"The list of filters","items":{"$ref":"#/components/schemas/apimodel.Filter"},"type":"array","uniqueItems":false},"id":{"description":"The id of the view","example":"67bf3f21cda9134102e2422c","type":"string"},"layout":{"description":"The layout of the view","enum":["grid","table"],"example":"grid","type":"string"},"name":{"description":"The name of the view","example":"All","type":"string"},"sorts":{"description":"The list of sorts","items":{"$ref":"#/components/schemas/apimodel.Sort"},"type":"array","uniqueItems":false}},"type":"object"},"pagination.PaginatedResponse-apimodel_Member":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Member"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Object":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Object"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Property":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Property"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Space":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Space"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Tag":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Tag"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_Type":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.Type"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginatedResponse-apimodel_View":{"properties":{"data":{"description":"The list of items in the current result set","items":{"$ref":"#/components/schemas/apimodel.View"},"type":"array","uniqueItems":false},"pagination":{"$ref":"#/components/schemas/pagination.PaginationMeta"}},"type":"object"},"pagination.PaginationMeta":{"description":"The pagination metadata for the response","properties":{"has_more":{"description":"Indicates if there are more items available beyond the current result set","example":true,"type":"boolean"},"limit":{"description":"The maximum number of items returned in the result set","example":100,"type":"integer"},"offset":{"description":"The number of items skipped before starting to collect the result set","example":0,"type":"integer"},"total":{"description":"The total number of items available for the endpoint","example":1000,"type":"integer"}},"type":"object"},"util.ForbiddenError":{"properties":{"code":{"example":"forbidden","type":"string"},"message":{"example":"Forbidden","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":403,"type":"integer"}},"type":"object"},"util.GoneError":{"properties":{"code":{"example":"resource_gone","type":"string"},"message":{"example":"Resource is gone","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":410,"type":"integer"}},"type":"object"},"util.NotFoundError":{"properties":{"code":{"example":"object_not_found","type":"string"},"message":{"example":"Resource not found","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":404,"type":"integer"}},"type":"object"},"util.RateLimitError":{"properties":{"code":{"example":"rate_limit_exceeded","type":"string"},"message":{"example":"Rate limit exceeded","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":429,"type":"integer"}},"type":"object"},"util.ServerError":{"properties":{"code":{"example":"internal_server_error","type":"string"},"message":{"example":"Internal server error","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":500,"type":"integer"}},"type":"object"},"util.UnauthorizedError":{"properties":{"code":{"example":"unauthorized","type":"string"},"message":{"example":"Unauthorized","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":401,"type":"integer"}},"type":"object"},"util.ValidationError":{"properties":{"code":{"example":"bad_request","type":"string"},"message":{"example":"Bad request","type":"string"},"object":{"example":"error","type":"string"},"status":{"example":400,"type":"integer"}},"type":"object"}},"securitySchemes":{"bearerauth":{"bearerFormat":"JWT","scheme":"bearer","type":"http"}}}, - "info": {"contact":{"email":"support@anytype.io","name":"Anytype Support","url":"https://anytype.io/contact"},"description":"This API empowers seamless interaction with Anytype's resources—spaces, objects, properties, types, templates, and beyond.","license":{"name":"Any Source Available License 1.0","url":"https://github.com/anyproto/anytype-api/blob/main/LICENSE.md"},"termsOfService":"https://anytype.io/terms_of_use","title":"Anytype API","version":"2025-04-22"}, - "externalDocs": {"description":"OpenAPI","url":"https://swagger.io/resources/open-api/"}, - "paths": {"/auth/display_code":{"post":{"description":"Generates a one-time authentication challenge for granting API access to the user's vault. Upon providing a valid `app_name`, the server issues a unique `challenge_id` and displays a short code within the Anytype Desktop On success, the service returns a unique challenge ID. This challenge ID must then be used with the token endpoint (see below) to solve the challenge and retrieve an authentication token. This mechanism ensures that only trusted applications and authorized users gain access.","operationId":"createAuthChallenge","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The name of the app requesting API access","in":"query","name":"app_name","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.DisplayCodeResponse"}}},"description":"The challenge ID associated with the started challenge"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Start new challenge","tags":["Auth"]}},"/auth/token":{"post":{"description":"After receiving a challenge ID from the display_code endpoint, the client calls this endpoint to provide the corresponding 4-digit code (also via a query parameter) along with the challenge ID. The endpoint verifies that the challenge solution is correct and, if it is, returns a permanent app key. This endpoint is central to the authentication process, as it validates the user's identity and issues a token that can be used for further interactions with the API.","operationId":"solveAuthChallenge","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the challenge to solve","in":"query","name":"challenge_id","required":true,"schema":{"type":"string"}},{"description":"4-digit code retrieved from Anytype Desktop app","in":"query","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TokenResponse"}}},"description":"The app key that can be used in the Authorization header for subsequent requests"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Invalid input"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"summary":"Solve challenge","tags":["Auth"]}},"/search":{"post":{"description":"Executes a global search over every space accessible by the authenticated user. The request body must specify the `query` text, optional filters on object types (e.g., \"page\", \"task\"), and sort directives (default: descending by last updated timestamp). Pagination is controlled via `offset` and `limit` query parameters to facilitate lazy loading in client UIs. The response returns a unified list of matched objects with their metadata and properties.","operationId":"searchGlobal","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SearchRequest"}}},"description":"The search parameters used to filter and sort the results","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects matching the search criteria"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects across all spaces","tags":["Search"]}},"/spaces":{"get":{"description":"Retrieves a paginated list of all spaces that are accessible by the authenticated user. Each space record contains detailed information such as the space ID, name, icon (derived either from an emoji or image URL), and additional metadata. This endpoint is key to displaying a user’s workspaces.","operationId":"listSpaces","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Space"}}},"description":"The list of spaces accessible by the authenticated user"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List spaces","tags":["Spaces"]},"post":{"description":"Creates a new space based on a supplied name and description in the JSON request body. The endpoint is subject to rate limiting and automatically applies default configurations such as generating a random icon and initializing the workspace with default settings (for example, a default dashboard or home page). On success, the new space’s full metadata is returned, enabling the client to immediately switch context to the new internal.","operationId":"createSpace","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateSpaceRequest"}}},"description":"The space to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SpaceResponse"}}},"description":"The created space"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create space","tags":["Spaces"]}},"/spaces/{space_id}":{"get":{"description":"Fetches full details about a single space identified by its space ID. The response includes metadata such as the space name, icon, and various workspace IDs (home, archive, profile, etc.). This detailed view supports use cases such as displaying space-specific settings.","operationId":"getSpace","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to retrieve","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SpaceResponse"}}},"description":"The space details"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get space","tags":["Spaces"]},"patch":{"description":"Updates the name or description of an existing space. The request body should contain the new name and/or description in JSON format. This endpoint is useful for renaming or rebranding a workspace without needing to recreate it. The updated space’s metadata is returned in the response.","operationId":"updateSpace","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to update","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateSpaceRequest"}}},"description":"The space details to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SpaceResponse"}}},"description":"The updated space"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Space not found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update space","tags":["Spaces"]}},"/spaces/{space_id}/lists/{list_id}/objects":{"post":{"description":"Adds one or more objects to a specific list (collection only) by submitting a JSON array of object IDs. Upon success, the endpoint returns a confirmation message. This endpoint is vital for building user interfaces that allow drag‑and‑drop or multi‑select additions to collections, enabling users to dynamically manage their collections without needing to modify the underlying object data.","operationId":"addListObjects","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the list belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list to which objects will be added","in":"path","name":"list_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array"}}},"description":"The list of object IDs to add to the list","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects added successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Add objects to list","tags":["Lists"]}},"/spaces/{space_id}/lists/{list_id}/objects/{object_id}":{"delete":{"description":"Removes a given object from the specified list (collection only) in a space. The endpoint takes the space, list, and object identifiers as path parameters and is subject to rate limiting. It is used for dynamically managing collections without affecting the underlying object data.","operationId":"removeListObject","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the list belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list from which the object will be removed","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to remove from the list","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"string"}}},"description":"Objects removed successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Remove object from list","tags":["Lists"]}},"/spaces/{space_id}/lists/{list_id}/views":{"get":{"description":"Returns a paginated list of views defined for a specific list (query or collection) within a space. Each view includes details such as layout, applied filters, and sorting options, enabling clients to render the list according to user preferences and context. This endpoint is essential for applications that need to display lists in various formats (e.g., grid, table) or with different sorting/filtering criteria.","operationId":"getListViews","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the list belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list to retrieve views for","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_View"}}},"description":"The list of views associated with the specified list"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get list views","tags":["Lists"]}},"/spaces/{space_id}/lists/{list_id}/{view_id}/objects":{"get":{"description":"Returns a paginated list of objects associated with a specific list (query or collection) within a space. When a view ID is provided, the objects are filtered and sorted according to the view's configuration. If no view ID is specified, all list objects are returned without filtering and sorting. This endpoint helps clients to manage grouped objects (for example, tasks within a list) by returning information for each item of the list.","operationId":"getListObjects","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the list belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the list to retrieve objects for","in":"path","name":"list_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the view to retrieve objects for","in":"path","name":"view_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects associated with the specified list"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get objects in list","tags":["Lists"]}},"/spaces/{space_id}/members":{"get":{"description":"Returns a paginated list of members belonging to the specified space. Each member record includes the member’s profile ID, name, icon (which may be derived from an emoji or image), network identity, global name, status (e.g. joining, active) and role (e.g. Viewer, Editor, Owner). This endpoint supports collaborative features by allowing clients to show who is in a space and manage access rights.","operationId":"listMembers","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to list members for","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Member"}}},"description":"The list of members in the space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List members","tags":["Members"]}},"/spaces/{space_id}/members/{member_id}":{"get":{"description":"Fetches detailed information about a single member within a space. The endpoint returns the member’s identifier, name, icon, identity, global name, status and role. The member_id path parameter can be provided as either the member's ID (starting with `_participant`) or the member's identity. This is useful for user profile pages, permission management, and displaying member-specific information in collaborative environments.","operationId":"getMember","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to get the member from","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"Member ID or Identity","in":"path","name":"member_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.MemberResponse"}}},"description":"The member details"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Member not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get member","tags":["Members"]}},"/spaces/{space_id}/objects":{"get":{"description":"Retrieves a paginated list of objects in the given space. The endpoint takes query parameters for pagination (offset and limit) and returns detailed data about each object including its ID, name, icon, type information, a snippet of the content (if applicable), layout, space ID, blocks and details. It is intended for building views where users can see all objects in a space at a glance.","operationId":"listObjects","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which to list objects","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects in the specified space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List objects","tags":["Objects"]},"post":{"description":"Creates a new object in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include key details such as the object name, icon, description, body content (which may support Markdown), source URL (required for bookmark objects), template identifier, and the type_key (which is the non-unique identifier of the type of object to create). Post-creation, additional operations (like setting featured properties or fetching bookmark metadata) may occur. The endpoint then returns the full object data, ready for further interactions.","operationId":"createObject","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which to create the object","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateObjectRequest"}}},"description":"The object to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The created object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create object","tags":["Objects"]}},"/spaces/{space_id}/objects/{object_id}":{"delete":{"description":"This endpoint “deletes” an object by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the object’s details after it has been archived. Proper error handling is in place for situations such as when the object isn’t found or the deletion cannot be performed because of permission issues.","operationId":"deleteObject","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which the object exists","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to delete","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The deleted object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete object","tags":["Objects"]},"get":{"description":"Fetches the full details of a single object identified by the object ID within the specified space. The response includes not only basic metadata (ID, name, icon, type) but also the complete set of blocks (which may include text, files, properties and dataviews) and extra details (such as timestamps and linked member information). This endpoint is essential when a client needs to render or edit the full object view.","operationId":"getObject","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which the object exists","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to retrieve","in":"path","name":"object_id","required":true,"schema":{"type":"string"}},{"description":"The format to return the object body in","in":"query","name":"format","schema":{"default":"\"md\"","enum":["md"],"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The retrieved object"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get object","tags":["Objects"]},"patch":{"description":"This endpoint updates an existing object in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the details to be updated. The endpoint then returns the full object data, ready for further interactions.","operationId":"updateObject","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which the object exists","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object to update","in":"path","name":"object_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateObjectRequest"}}},"description":"The details of the object to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.ObjectResponse"}}},"description":"The updated object"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update object","tags":["Objects"]}},"/spaces/{space_id}/properties":{"get":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ Retrieves a paginated list of properties available within a specific space. Each property record includes its unique identifier, name and format. This information is essential for clients to understand the available properties for filtering or creating objects.","operationId":"listProperties","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to list properties for","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Property"}}},"description":"The list of properties in the specified space"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List properties","tags":["Properties"]},"post":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ Creates a new property in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include property details such as the name and format. The endpoint then returns the full property data, ready for further interactions.","operationId":"createProperty","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to create the property in","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreatePropertyRequest"}}},"description":"The property to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The created property"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create property","tags":["Properties"]}},"/spaces/{space_id}/properties/{property_id}":{"delete":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ This endpoint “deletes” a property by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the property’s details after it has been archived. Proper error handling is in place for situations such as when the property isn’t found or the deletion cannot be performed because of permission issues.","operationId":"deleteProperty","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the property belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to delete","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The deleted property"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete property","tags":["Properties"]},"get":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ Fetches detailed information about one specific property by its ID. This includes the property’s unique identifier, name and format. This detailed view assists clients in showing property options to users and in guiding the user interface (such as displaying appropriate input fields or selection options).","operationId":"getProperty","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the property belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to retrieve","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The requested property"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get property","tags":["Properties"]},"patch":{"description":"⚠ Warning: Properties are experimental and may change in the next update. ⚠ This endpoint updates an existing property in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the name to be updated. The endpoint then returns the full property data, ready for further interactions.","operationId":"updateProperty","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the property belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to update","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdatePropertyRequest"}}},"description":"The property to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.PropertyResponse"}}},"description":"The updated property"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update property","tags":["Properties"]}},"/spaces/{space_id}/properties/{property_id}/tags":{"get":{"description":"This endpoint retrieves a paginated list of tags available for a specific property within a space. Each tag record includes its unique identifier, name, and color. This information is essential for clients to display select or multi-select options to users when they are creating or editing objects. The endpoint also supports pagination through offset and limit parameters.","operationId":"listTags","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to list tags for","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to list tags for","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Tag"}}},"description":"The list of tags"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Property not found"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List tags","tags":["Tags"]},"post":{"description":"This endpoint creates a new tag for a given property id in a space. The creation process is subject to rate limiting. The tag is identified by its unique identifier within the specified space. The request must include the tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to add new tag options to a property.","operationId":"createTag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to create the tag in","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to create the tag for","in":"path","name":"property_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateTagRequest"}}},"description":"The tag to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The created tag"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create tag","tags":["Tags"]}},"/spaces/{space_id}/properties/{property_id}/tags/{tag_id}":{"delete":{"description":"This endpoint “deletes” a tag by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the tag’s details after it has been archived. Proper error handling is in place for situations such as when the tag isn’t found or the deletion cannot be performed because of permission issues.","operationId":"deleteTag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to delete the tag from","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to delete the tag for","in":"path","name":"property_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the tag to delete","in":"path","name":"tag_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The deleted tag"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete tag","tags":["Tags"]},"get":{"description":"This endpoint retrieves a tag for a given property id. The tag is identified by its unique identifier within the specified space. The response includes the tag's details such as its ID, name, and color. This is useful for clients to display or when editing a specific tag option.","operationId":"getTag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to retrieve the tag from","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to retrieve the tag for","in":"path","name":"property_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the tag to retrieve","in":"path","name":"tag_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The retrieved tag"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get tag","tags":["Tags"]},"patch":{"description":"This endpoint updates a tag for a given property id in a space. The update process is subject to rate limiting. The tag is identified by its unique identifier within the specified space. The request must include the tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to edit existing tags for a property.","operationId":"updateTag","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to update the tag in","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the property to update the tag for","in":"path","name":"property_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the tag to update","in":"path","name":"tag_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateTagRequest"}}},"description":"The tag to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TagResponse"}}},"description":"The updated tag"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update tag","tags":["Tags"]}},"/spaces/{space_id}/search":{"post":{"description":"Performs a focused search within a single space (specified by the space_id path parameter). Like the global search, it accepts pagination parameters and a JSON payload containing the search query, object types, and sorting preferences. The search is limited to the provided space and returns a list of objects that match the query. This allows clients to implement space‑specific filtering without having to process extraneous results.","operationId":"searchSpace","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to search in","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.SearchRequest"}}},"description":"The search parameters used to filter and sort the results","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"The list of objects matching the search criteria"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Search objects within a space","tags":["Search"]}},"/spaces/{space_id}/types":{"get":{"description":"This endpoint retrieves a paginated list of object types (e.g. 'Page', 'Note', 'Task') available within the specified space. Each type’s record includes its unique identifier, type key, display name, icon, and layout. While a type's id is truly unique, a type's key can be the same across spaces for known types, e.g. 'page' for 'Page'. Clients use this information when offering choices for object creation or for filtering objects by type through search.","operationId":"listTypes","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to retrieve types from","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Type"}}},"description":"The list of types"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List types","tags":["Types"]},"post":{"description":"Creates a new object type in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include type details such as the name, icon, and layout. The endpoint then returns the full type data, ready to be used for creating objects.","operationId":"createType","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which to create the type","in":"path","name":"space_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.CreateTypeRequest"}}},"description":"The type to create","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The created type"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Create type","tags":["Types"]}},"/spaces/{space_id}/types/{type_id}":{"delete":{"description":"This endpoint “deletes” an object type by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the type’s details after it has been archived. Proper error handling is in place for situations such as when the type isn’t found or the deletion cannot be performed because of permission issues.","operationId":"deleteType","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space from which to delete the type","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the type to delete","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The deleted type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ForbiddenError"}}},"description":"Forbidden"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Delete type","tags":["Types"]},"get":{"description":"Fetches detailed information about one specific object type by its ID. This includes the type’s unique key, name, icon, and layout. This detailed view assists clients in understanding the expected structure and style for objects of that type and in guiding the user interface (such as displaying appropriate icons or layout hints).","operationId":"getType","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space from which to retrieve the type","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the type to retrieve","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The requested type"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get type","tags":["Types"]},"patch":{"description":"This endpoint updates an existing object type in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the name and properties to be updated. The endpoint then returns the full type data, ready for further interactions.","operationId":"updateType","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space in which the type exists","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the type to update","in":"path","name":"type_id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.UpdateTypeRequest"}}},"description":"The type details to update","required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TypeResponse"}}},"description":"The updated type"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ValidationError"}}},"description":"Bad request"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.RateLimitError"}}},"description":"Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Update type","tags":["Types"]}},"/spaces/{space_id}/types/{type_id}/templates":{"get":{"description":"This endpoint returns a paginated list of templates that are associated with a specific object type within a space. Templates provide pre‑configured structures for creating new objects. Each template record contains its identifier, name, and icon, so that clients can offer users a selection of templates when creating objects.","operationId":"listTemplates","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the type belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object type to retrieve templates for","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The number of items to skip before starting to collect the result set","in":"query","name":"offset","schema":{"default":0,"type":"integer"}},{"description":"The number of items to return","in":"query","name":"limit","schema":{"default":100,"maximum":1000,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/pagination.PaginatedResponse-apimodel_Object"}}},"description":"List of templates"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"List templates","tags":["Templates"]}},"/spaces/{space_id}/types/{type_id}/templates/{template_id}":{"get":{"description":"Fetches full details for one template associated with a particular object type in a space. The response provides the template’s identifier, name, icon, and any other relevant metadata. This endpoint is useful when a client needs to preview or apply a template to prefill object creation fields.","operationId":"getTemplate","parameters":[{"description":"The version of the API to use","in":"header","name":"Anytype-Version","required":true,"schema":{"default":"2025-04-22","type":"string"}},{"description":"The ID of the space to which the template belongs","in":"path","name":"space_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the object type to which the template belongs","in":"path","name":"type_id","required":true,"schema":{"type":"string"}},{"description":"The ID of the template to retrieve","in":"path","name":"template_id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/apimodel.TemplateResponse"}}},"description":"The requested template"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.UnauthorizedError"}}},"description":"Unauthorized"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.NotFoundError"}}},"description":"Resource not found"},"410":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.GoneError"}}},"description":"Resource deleted"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/util.ServerError"}}},"description":"Internal server error"}},"security":[{"bearerauth":[]}],"summary":"Get template","tags":["Templates"]}}}, - "openapi": "3.1.0", - "servers": [ - {"url":"http://localhost:31009/v1"} - ] -} \ No newline at end of file diff --git a/core/api/handler/auth.go b/core/api/handler/auth.go index 3e92b1008..83f6070ee 100644 --- a/core/api/handler/auth.go +++ b/core/api/handler/auth.go @@ -10,28 +10,31 @@ import ( "github.com/anyproto/anytype-heart/core/api/util" ) +/* +TO BE DEPRECATED // DisplayCodeHandler starts a new challenge and returns the challenge ID // -// @Summary Start new challenge -// @Description Generates a one-time authentication challenge for granting API access to the user's vault. Upon providing a valid `app_name`, the server issues a unique `challenge_id` and displays a short code within the Anytype Desktop On success, the service returns a unique challenge ID. This challenge ID must then be used with the token endpoint (see below) to solve the challenge and retrieve an authentication token. This mechanism ensures that only trusted applications and authorized users gain access. -// @ID createAuthChallenge -// @Tags Auth -// @Accept json -// @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param app_name query string true "The name of the app requesting API access" -// @Success 200 {object} apimodel.DisplayCodeResponse "The challenge ID associated with the started challenge" -// @Failure 400 {object} util.ValidationError "Invalid input" -// @Failure 500 {object} util.ServerError "Internal server error" -// @Router /auth/display_code [post] +// @Summary Start challenge +// @Description Generates a one-time authentication challenge for granting API access to the user's vault. Upon providing a valid `app_name`, the server issues a unique `challenge_id` and displays a short code within the Anytype Desktop. The `challenge_id` must then be used with the token endpoint (see below) to solve the challenge and retrieve an authentication token. This mechanism ensures that only trusted applications and authorized users gain access. +// @ID create_auth_challenge +// @Tags Auth +// @Accept json +// @Produce json +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param app_name query string true "The name of the app requesting API access" +// @Success 200 {object} apimodel.DisplayCodeResponse "The challenge ID associated with the started challenge" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Router /v1/auth/display_code [post] +*/ func DisplayCodeHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { appName := c.Query("app_name") - challengeId, err := s.NewChallenge(c.Request.Context(), appName) + challengeId, err := s.CreateChallenge(c.Request.Context(), appName) code := util.MapErrorCode(err, util.ErrToCode(service.ErrMissingAppName, http.StatusBadRequest), - util.ErrToCode(service.ErrFailedGenerateChallenge, http.StatusInternalServerError)) + util.ErrToCode(service.ErrFailedCreateNewChallenge, http.StatusInternalServerError)) if code != http.StatusOK { apiErr := util.CodeToAPIError(code, err.Error()) @@ -39,25 +42,28 @@ func DisplayCodeHandler(s *service.Service) gin.HandlerFunc { return } - c.JSON(http.StatusOK, apimodel.DisplayCodeResponse{ChallengeId: challengeId}) + c.JSON(299, apimodel.DisplayCodeResponse{ChallengeId: challengeId}) } } +/* +TO BE DEPRECATED // TokenHandler retrieves an authentication token using a code and challenge ID // // @Summary Solve challenge -// @Description After receiving a challenge ID from the display_code endpoint, the client calls this endpoint to provide the corresponding 4-digit code (also via a query parameter) along with the challenge ID. The endpoint verifies that the challenge solution is correct and, if it is, returns a permanent app key. This endpoint is central to the authentication process, as it validates the user's identity and issues a token that can be used for further interactions with the API. -// @ID solveAuthChallenge +// @Description After receiving a `challenge_id` from the `display_code` endpoint, the client calls this endpoint to provide the corresponding 4-digit code along with the challenge ID. The endpoint verifies that the challenge solution is correct and, if it is, returns a permanent `app_key`. This endpoint is central to the authentication process, as it validates the user's identity and issues a token that can be used for further interactions with the API. +// @ID solve_auth_challenge // @Tags Auth // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) // @Param challenge_id query string true "The ID of the challenge to solve" // @Param code query string true "4-digit code retrieved from Anytype Desktop app" // @Success 200 {object} apimodel.TokenResponse "The app key that can be used in the Authorization header for subsequent requests" -// @Failure 400 {object} util.ValidationError "Invalid input" +// @Failure 400 {object} util.ValidationError "Bad request" // @Failure 500 {object} util.ServerError "Internal server error" -// @Router /auth/token [post] +// @Router /v1/auth/token [post] +*/ func TokenHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { challengeId := c.Query("challenge_id") @@ -65,7 +71,7 @@ func TokenHandler(s *service.Service) gin.HandlerFunc { appKey, err := s.SolveChallenge(c.Request.Context(), challengeId, code) errCode := util.MapErrorCode(err, - util.ErrToCode(service.ErrInvalidInput, http.StatusBadRequest), + util.ErrToCode(util.ErrBad, http.StatusBadRequest), util.ErrToCode(service.ErrFailedAuthenticate, http.StatusInternalServerError), ) @@ -75,6 +81,84 @@ func TokenHandler(s *service.Service) gin.HandlerFunc { return } - c.JSON(http.StatusOK, apimodel.TokenResponse{AppKey: appKey}) + c.JSON(299, apimodel.TokenResponse{AppKey: appKey}) + } +} + +// CreateChallengeHandler creates a new challenge for API key generation +// +// @Summary Create Challenge +// @Description Generates a one-time authentication challenge for granting API access to the user's vault. Upon providing a valid `app_name`, the server issues a unique `challenge_id` and displays a 4-digit code within the Anytype Desktop. The `challenge_id` must then be used with the `/v1/auth/api_keys` endpoint to solve the challenge and retrieve an authentication token. This mechanism ensures that only trusted applications and authorized users gain access. +// @ID create_auth_challenge +// @Tags Auth +// @Accept json +// @Produce json +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param app_name query string true "The name of the app requesting API access" +// @Success 201 {object} apimodel.CreateChallengeResponse "The challenge ID associated with the started challenge" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Router /v1/auth/challenges [post] +func CreateChallengeHandler(s *service.Service) gin.HandlerFunc { + return func(c *gin.Context) { + request := apimodel.CreateChallengeRequest{} + if err := c.ShouldBindJSON(&request); err != nil { + apiErr := util.CodeToAPIError(http.StatusBadRequest, err.Error()) + c.JSON(http.StatusBadRequest, apiErr) + return + } + + challengeId, err := s.CreateChallenge(c.Request.Context(), request.AppName) + code := util.MapErrorCode(err, + util.ErrToCode(service.ErrMissingAppName, http.StatusBadRequest), + util.ErrToCode(service.ErrFailedCreateNewChallenge, http.StatusInternalServerError)) + + if code != http.StatusOK { + apiErr := util.CodeToAPIError(code, err.Error()) + c.JSON(code, apiErr) + return + } + + c.JSON(http.StatusCreated, apimodel.CreateChallengeResponse{ChallengeId: challengeId}) + } +} + +// CreateApiKeyHandler creates a new api key using a code and challenge ID +// +// @Summary Create API Key +// @Description After receiving a `challenge_id` from the `/v1/auth/challenges` endpoint, the client calls this endpoint to provide the corresponding 4-digit code along with the challenge ID. The endpoint verifies that the challenge solution is correct and, if it is, returns an `api_key`. This endpoint is central to the authentication process, as it validates the user's identity and issues a key that can be used for further interactions with the API. +// @ID create_api_key +// @Tags Auth +// @Accept json +// @Produce json +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param challenge_id query string true "The ID of the challenge to solve" +// @Param code query string true "The 4-digit code retrieved from Anytype Desktop app" +// @Success 201 {object} apimodel.CreateApiKeyResponse "The API key that can be used in the Authorization header for subsequent requests" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 500 {object} util.ServerError "Internal server error" +// @Router /v1/auth/api_keys [post] +func CreateApiKeyHandler(s *service.Service) gin.HandlerFunc { + return func(c *gin.Context) { + request := apimodel.CreateApiKeyRequest{} + if err := c.ShouldBindJSON(&request); err != nil { + apiErr := util.CodeToAPIError(http.StatusBadRequest, err.Error()) + c.JSON(http.StatusBadRequest, apiErr) + return + } + + apiKey, err := s.SolveChallenge(c.Request.Context(), request.ChallengeId, request.Code) + errCode := util.MapErrorCode(err, + util.ErrToCode(util.ErrBad, http.StatusBadRequest), + util.ErrToCode(service.ErrFailedAuthenticate, http.StatusInternalServerError), + ) + + if errCode != http.StatusOK { + apiErr := util.CodeToAPIError(errCode, err.Error()) + c.JSON(errCode, apiErr) + return + } + + c.JSON(http.StatusCreated, apimodel.CreateApiKeyResponse{ApiKey: apiKey}) } } diff --git a/core/api/handler/list.go b/core/api/handler/list.go index 5395b5a22..eded6726d 100644 --- a/core/api/handler/list.go +++ b/core/api/handler/list.go @@ -5,6 +5,7 @@ import ( "github.com/gin-gonic/gin" + apimodel "github.com/anyproto/anytype-heart/core/api/model" "github.com/anyproto/anytype-heart/core/api/pagination" "github.com/anyproto/anytype-heart/core/api/service" "github.com/anyproto/anytype-heart/core/api/util" @@ -14,12 +15,12 @@ import ( // // @Summary Get list views // @Description Returns a paginated list of views defined for a specific list (query or collection) within a space. Each view includes details such as layout, applied filters, and sorting options, enabling clients to render the list according to user preferences and context. This endpoint is essential for applications that need to display lists in various formats (e.g., grid, table) or with different sorting/filtering criteria. -// @Id getListViews +// @Id get_list_views // @Tags Lists // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to which the list belongs" -// @Param list_id path string true "The ID of the list to retrieve views for" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint" +// @Param list_id path string true "The ID of the list to retrieve views for; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']" // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) // @Param limit query int false "The number of items to return" // @Success 200 {object} pagination.PaginatedResponse[apimodel.View] "The list of views associated with the specified list" @@ -27,7 +28,7 @@ import ( // @Failure 404 {object} util.NotFoundError "Not found" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/lists/{list_id}/views [get] +// @Router /v1/spaces/{space_id}/lists/{list_id}/views [get] func GetListViewsHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -55,13 +56,13 @@ func GetListViewsHandler(s *service.Service) gin.HandlerFunc { // // @Summary Get objects in list // @Description Returns a paginated list of objects associated with a specific list (query or collection) within a space. When a view ID is provided, the objects are filtered and sorted according to the view's configuration. If no view ID is specified, all list objects are returned without filtering and sorting. This endpoint helps clients to manage grouped objects (for example, tasks within a list) by returning information for each item of the list. -// @Id getListObjects +// @Id get_list_objects // @Tags Lists // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to which the list belongs" -// @Param list_id path string true "The ID of the list to retrieve objects for" -// @Param view_id path string true "The ID of the view to retrieve objects for" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint" +// @Param list_id path string true "The ID of the list to retrieve objects for; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']" +// @Param view_id path string true "The ID of the view to retrieve objects for; must be retrieved from ListViews endpoint or omitted if you want to get all objects in the list" // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) // @Param limit query int false "The number of items to return" // @Success 200 {object} pagination.PaginatedResponse[apimodel.Object] "The list of objects associated with the specified list" @@ -69,7 +70,7 @@ func GetListViewsHandler(s *service.Service) gin.HandlerFunc { // @Failure 404 {object} util.NotFoundError "Not found" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/lists/{list_id}/{view_id}/objects [get] +// @Router /v1/spaces/{space_id}/lists/{list_id}/views/{view_id}/objects [get] func GetObjectsInListHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -102,35 +103,35 @@ func GetObjectsInListHandler(s *service.Service) gin.HandlerFunc { // // @Summary Add objects to list // @Description Adds one or more objects to a specific list (collection only) by submitting a JSON array of object IDs. Upon success, the endpoint returns a confirmation message. This endpoint is vital for building user interfaces that allow drag‑and‑drop or multi‑select additions to collections, enabling users to dynamically manage their collections without needing to modify the underlying object data. -// @Id addListObjects +// @Id add_list_objects // @Tags Lists // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to which the list belongs" -// @Param list_id path string true "The ID of the list to which objects will be added" -// @Param objects body []string true "The list of object IDs to add to the list" -// @Success 200 {object} string "Objects added successfully" -// @Failure 400 {object} util.ValidationError "Bad request" -// @Failure 401 {object} util.UnauthorizedError "Unauthorized" -// @Failure 404 {object} util.NotFoundError "Not found" -// @Failure 429 {object} util.RateLimitError "Rate limit exceeded" -// @Failure 500 {object} util.ServerError "Internal server error" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint" +// @Param list_id path string true "The ID of the list to which objects will be added; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']" +// @Param objects body apimodel.AddObjectsToListRequest true "The list of object IDs to add to the list; must be retrieved from SearchSpace or GlobalSearch endpoints or obtained from response context" +// @Success 200 {object} string "Objects added successfully" +// @Failure 400 {object} util.ValidationError "Bad request" +// @Failure 401 {object} util.UnauthorizedError "Unauthorized" +// @Failure 404 {object} util.NotFoundError "Not found" +// @Failure 429 {object} util.RateLimitError "Rate limit exceeded" +// @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/lists/{list_id}/objects [post] +// @Router /v1/spaces/{space_id}/lists/{list_id}/objects [post] func AddObjectsToListHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") listId := c.Param("list_id") - objects := []string{} - if err := c.ShouldBindJSON(&objects); err != nil { + request := apimodel.AddObjectsToListRequest{} + if err := c.ShouldBindJSON(&request); err != nil { apiErr := util.CodeToAPIError(http.StatusBadRequest, err.Error()) c.JSON(http.StatusBadRequest, apiErr) return } - err := s.AddObjectsToList(c, spaceId, listId, objects) + err := s.AddObjectsToList(c, spaceId, listId, request) code := util.MapErrorCode(err, util.ErrToCode(service.ErrFailedAddObjectsToList, http.StatusInternalServerError), ) @@ -149,13 +150,13 @@ func AddObjectsToListHandler(s *service.Service) gin.HandlerFunc { // // @Summary Remove object from list // @Description Removes a given object from the specified list (collection only) in a space. The endpoint takes the space, list, and object identifiers as path parameters and is subject to rate limiting. It is used for dynamically managing collections without affecting the underlying object data. -// @Id removeListObject +// @Id remove_list_object // @Tags Lists // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to which the list belongs" -// @Param list_id path string true "The ID of the list from which the object will be removed" -// @Param object_id path string true "The ID of the object to remove from the list" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to which the list belongs; must be retrieved from ListSpaces endpoint" +// @Param list_id path string true "The ID of the list from which the object will be removed; must be retrieved from SearchSpace endpoint with types: ['collection', 'set']" +// @Param object_id path string true "The ID of the object to remove from the list; must be retrieved from SearchSpace or GlobalSearch endpoints or obtained from response context" // @Success 200 {object} string "Objects removed successfully" // @Failure 400 {object} util.ValidationError "Bad request" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" @@ -163,7 +164,7 @@ func AddObjectsToListHandler(s *service.Service) gin.HandlerFunc { // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/lists/{list_id}/objects/{object_id} [delete] +// @Router /v1/spaces/{space_id}/lists/{list_id}/objects/{object_id} [delete] func RemoveObjectFromListHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") diff --git a/core/api/handler/member.go b/core/api/handler/member.go index b91e17495..be642b59c 100644 --- a/core/api/handler/member.go +++ b/core/api/handler/member.go @@ -15,18 +15,18 @@ import ( // // @Summary List members // @Description Returns a paginated list of members belonging to the specified space. Each member record includes the member’s profile ID, name, icon (which may be derived from an emoji or image), network identity, global name, status (e.g. joining, active) and role (e.g. Viewer, Editor, Owner). This endpoint supports collaborative features by allowing clients to show who is in a space and manage access rights. -// @Id listMembers +// @Id list_members // @Tags Members // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to list members for" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to list members for; must be retrieved from ListSpaces endpoint" // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) // @Param limit query int false "The number of items to return" default(100) maximum(1000) // @Success 200 {object} pagination.PaginatedResponse[apimodel.Member] "The list of members in the space" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/members [get] +// @Router /v1/spaces/{space_id}/members [get] func ListMembersHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -52,18 +52,18 @@ func ListMembersHandler(s *service.Service) gin.HandlerFunc { // // @Summary Get member // @Description Fetches detailed information about a single member within a space. The endpoint returns the member’s identifier, name, icon, identity, global name, status and role. The member_id path parameter can be provided as either the member's ID (starting with `_participant`) or the member's identity. This is useful for user profile pages, permission management, and displaying member-specific information in collaborative environments. -// @Id getMember +// @Id get_member // @Tags Members // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to get the member from" -// @Param member_id path string true "Member ID or Identity" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to get the member from; must be retrieved from ListSpaces endpoint" +// @Param member_id path string true "Member ID or Identity; must be retrieved from ListMembers endpoint or obtained from response context" // @Success 200 {object} apimodel.MemberResponse "The member details" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Member not found" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/members/{member_id} [get] +// @Router /v1/spaces/{space_id}/members/{member_id} [get] func GetMemberHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -90,13 +90,13 @@ func GetMemberHandler(s *service.Service) gin.HandlerFunc { // // @Summary Update member // @Description Modifies a member's status and role in a space. Use this endpoint to approve a joining member by setting the status to `active` and specifying a role (`reader` or `writer`), reject a joining member by setting the status to `declined`, remove a member by setting the status to `removed`, or update an active member's role. This endpoint enables fine-grained control over member access and permissions. -// @Id updateMember +// @Id update_member // @Tags Members // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to update the member in" -// @Param member_id path string true "The ID of the member to update" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to update the member in; must be retrieved from ListSpaces endpoint" +// @Param member_id path string true "The ID or Identity of the member to update; must be retrieved from ListMembers endpoint or obtained from response context" // @Param body body apimodel.UpdateMemberRequest true "The request body containing the member's new status and role" // @Success 200 {object} apimodel.MemberResponse "Member updated successfully" // @Failure 400 {object} util.ValidationError "Bad request" @@ -105,7 +105,7 @@ func GetMemberHandler(s *service.Service) gin.HandlerFunc { // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/members/{member_id} [patch] +// @Router /v1/spaces/{space_id}/members/{member_id} [patch] func UpdateMemberHandler(s *SpaceService) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") diff --git a/core/api/handler/object.go b/core/api/handler/object.go index 1f491d6de..613b335e5 100644 --- a/core/api/handler/object.go +++ b/core/api/handler/object.go @@ -15,18 +15,18 @@ import ( // // @Summary List objects // @Description Retrieves a paginated list of objects in the given space. The endpoint takes query parameters for pagination (offset and limit) and returns detailed data about each object including its ID, name, icon, type information, a snippet of the content (if applicable), layout, space ID, blocks and details. It is intended for building views where users can see all objects in a space at a glance. -// @Id listObjects +// @Id list_objects // @Tags Objects // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space in which to list objects" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space in which to list objects; must be retrieved from ListSpaces endpoint" // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) // @Param limit query int false "The number of items to return" default(100) maximum(1000) // @Success 200 {object} pagination.PaginatedResponse[apimodel.Object] "The list of objects in the specified space" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/objects [get] +// @Router /v1/spaces/{space_id}/objects [get] func ListObjectsHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -54,12 +54,12 @@ func ListObjectsHandler(s *service.Service) gin.HandlerFunc { // // @Summary Get object // @Description Fetches the full details of a single object identified by the object ID within the specified space. The response includes not only basic metadata (ID, name, icon, type) but also the complete set of blocks (which may include text, files, properties and dataviews) and extra details (such as timestamps and linked member information). This endpoint is essential when a client needs to render or edit the full object view. -// @Id getObject +// @Id get_object // @Tags Objects // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space in which the object exists" -// @Param object_id path string true "The ID of the object to retrieve" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space in which the object exists; must be retrieved from ListSpaces endpoint" +// @Param object_id path string true "The ID of the object to retrieve; must be retrieved from ListObjects, SearchSpace or GlobalSearch endpoints or obtained from response context" // @Param format query apimodel.BodyFormat false "The format to return the object body in" default("md") // @Success 200 {object} apimodel.ObjectResponse "The retrieved object" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" @@ -67,7 +67,7 @@ func ListObjectsHandler(s *service.Service) gin.HandlerFunc { // @Failure 410 {object} util.GoneError "Resource deleted" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/objects/{object_id} [get] +// @Router /v1/spaces/{space_id}/objects/{object_id} [get] func GetObjectHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -96,20 +96,20 @@ func GetObjectHandler(s *service.Service) gin.HandlerFunc { // // @Summary Create object // @Description Creates a new object in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include key details such as the object name, icon, description, body content (which may support Markdown), source URL (required for bookmark objects), template identifier, and the type_key (which is the non-unique identifier of the type of object to create). Post-creation, additional operations (like setting featured properties or fetching bookmark metadata) may occur. The endpoint then returns the full object data, ready for further interactions. -// @Id createObject +// @Id create_object // @Tags Objects // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space in which to create the object" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space in which to create the object; must be retrieved from ListSpaces endpoint" // @Param object body apimodel.CreateObjectRequest true "The object to create" -// @Success 200 {object} apimodel.ObjectResponse "The created object" +// @Success 201 {object} apimodel.ObjectResponse "The created object" // @Failure 400 {object} util.ValidationError "Bad request" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/objects [post] +// @Router /v1/spaces/{space_id}/objects [post] func CreateObjectHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -139,7 +139,7 @@ func CreateObjectHandler(s *service.Service) gin.HandlerFunc { return } - c.JSON(http.StatusOK, apimodel.ObjectResponse{Object: object}) + c.JSON(http.StatusCreated, apimodel.ObjectResponse{Object: object}) } } @@ -147,13 +147,13 @@ func CreateObjectHandler(s *service.Service) gin.HandlerFunc { // // @Summary Update object // @Description This endpoint updates an existing object in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the details to be updated. The endpoint then returns the full object data, ready for further interactions. -// @Id updateObject +// @Id update_object // @Tags Objects // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space in which the object exists" -// @Param object_id path string true "The ID of the object to update" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space in which the object exists; must be retrieved from ListSpaces endpoint" +// @Param object_id path string true "The ID of the object to update; must be retrieved from ListObjects, SearchSpace or GlobalSearch endpoints or obtained from response context" // @Param object body apimodel.UpdateObjectRequest true "The details of the object to update" // @Success 200 {object} apimodel.ObjectResponse "The updated object" // @Failure 400 {object} util.ValidationError "Bad request" @@ -163,7 +163,7 @@ func CreateObjectHandler(s *service.Service) gin.HandlerFunc { // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/objects/{object_id} [patch] +// @Router /v1/spaces/{space_id}/objects/{object_id} [patch] func UpdateObjectHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -199,12 +199,12 @@ func UpdateObjectHandler(s *service.Service) gin.HandlerFunc { // // @Summary Delete object // @Description This endpoint “deletes” an object by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the object’s details after it has been archived. Proper error handling is in place for situations such as when the object isn’t found or the deletion cannot be performed because of permission issues. -// @Id deleteObject +// @Id delete_object // @Tags Objects // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space in which the object exists" -// @Param object_id path string true "The ID of the object to delete" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space in which the object exists; must be retrieved from ListSpaces endpoint" +// @Param object_id path string true "The ID of the object to delete; must be retrieved from ListObjects, SearchSpace or GlobalSearch endpoints or obtained from response context" // @Success 200 {object} apimodel.ObjectResponse "The deleted object" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 403 {object} util.ForbiddenError "Forbidden" @@ -213,7 +213,7 @@ func UpdateObjectHandler(s *service.Service) gin.HandlerFunc { // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/objects/{object_id} [delete] +// @Router /v1/spaces/{space_id}/objects/{object_id} [delete] func DeleteObjectHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") diff --git a/core/api/handler/property.go b/core/api/handler/property.go index 271a93675..45bea7648 100644 --- a/core/api/handler/property.go +++ b/core/api/handler/property.go @@ -15,18 +15,18 @@ import ( // // @Summary List properties // @Description ⚠ Warning: Properties are experimental and may change in the next update. ⚠ Retrieves a paginated list of properties available within a specific space. Each property record includes its unique identifier, name and format. This information is essential for clients to understand the available properties for filtering or creating objects. -// @Id listProperties +// @Id list_properties // @Tags Properties // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to list properties for" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to list properties for; must be retrieved from ListSpaces endpoint" // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) // @Param limit query int false "The number of items to return" default(100) maximum(1000) // @Success 200 {object} pagination.PaginatedResponse[apimodel.Property] "The list of properties in the specified space" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/properties [get] +// @Router /v1/spaces/{space_id}/properties [get] func ListPropertiesHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -52,19 +52,19 @@ func ListPropertiesHandler(s *service.Service) gin.HandlerFunc { // // @Summary Get property // @Description ⚠ Warning: Properties are experimental and may change in the next update. ⚠ Fetches detailed information about one specific property by its ID. This includes the property’s unique identifier, name and format. This detailed view assists clients in showing property options to users and in guiding the user interface (such as displaying appropriate input fields or selection options). -// @Id getProperty +// @Id get_property // @Tags Properties // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to which the property belongs" -// @Param property_id path string true "The ID of the property to retrieve" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to which the property belongs; must be retrieved from ListSpaces endpoint" +// @Param property_id path string true "The ID of the property to retrieve; must be retrieved from ListProperties endpoint or obtained from response context" // @Success 200 {object} apimodel.PropertyResponse "The requested property" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Resource not found" // @Failure 410 {object} util.GoneError "Resource deleted" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/properties/{property_id} [get] +// @Router /v1/spaces/{space_id}/properties/{property_id} [get] func GetPropertyHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -91,20 +91,20 @@ func GetPropertyHandler(s *service.Service) gin.HandlerFunc { // // @Summary Create property // @Description ⚠ Warning: Properties are experimental and may change in the next update. ⚠ Creates a new property in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include property details such as the name and format. The endpoint then returns the full property data, ready for further interactions. -// @Id createProperty +// @Id create_property // @Tags Properties // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to create the property in" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to create the property in; must be retrieved from ListSpaces endpoint" // @Param property body apimodel.CreatePropertyRequest true "The property to create" -// @Success 200 {object} apimodel.PropertyResponse "The created property" +// @Success 201 {object} apimodel.PropertyResponse "The created property" // @Failure 400 {object} util.ValidationError "Bad request" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/properties [post] +// @Router /v1/spaces/{space_id}/properties [post] func CreatePropertyHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -129,7 +129,7 @@ func CreatePropertyHandler(s *service.Service) gin.HandlerFunc { return } - c.JSON(http.StatusOK, apimodel.PropertyResponse{Property: property}) + c.JSON(http.StatusCreated, apimodel.PropertyResponse{Property: property}) } } @@ -137,13 +137,13 @@ func CreatePropertyHandler(s *service.Service) gin.HandlerFunc { // // @Summary Update property // @Description ⚠ Warning: Properties are experimental and may change in the next update. ⚠ This endpoint updates an existing property in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the name to be updated. The endpoint then returns the full property data, ready for further interactions. -// @Id updateProperty +// @Id update_property // @Tags Properties // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to which the property belongs" -// @Param property_id path string true "The ID of the property to update" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to which the property belongs; must be retrieved from ListSpaces endpoint" +// @Param property_id path string true "The ID of the property to update; must be retrieved from ListProperties endpoint or obtained from response context" // @Param property body apimodel.UpdatePropertyRequest true "The property to update" // @Success 200 {object} apimodel.PropertyResponse "The updated property" // @Failure 400 {object} util.ValidationError "Bad request" @@ -154,7 +154,7 @@ func CreatePropertyHandler(s *service.Service) gin.HandlerFunc { // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/properties/{property_id} [patch] +// @Router /v1/spaces/{space_id}/properties/{property_id} [patch] func UpdatePropertyHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -191,12 +191,12 @@ func UpdatePropertyHandler(s *service.Service) gin.HandlerFunc { // // @Summary Delete property // @Description ⚠ Warning: Properties are experimental and may change in the next update. ⚠ This endpoint “deletes” a property by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the property’s details after it has been archived. Proper error handling is in place for situations such as when the property isn’t found or the deletion cannot be performed because of permission issues. -// @Id deleteProperty +// @Id delete_property // @Tags Properties // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to which the property belongs" -// @Param property_id path string true "The ID of the property to delete" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to which the property belongs; must be retrieved from ListSpaces endpoint" +// @Param property_id path string true "The ID of the property to delete; must be retrieved from ListProperties endpoint or obtained from response context" // @Success 200 {object} apimodel.PropertyResponse "The deleted property" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 403 {object} util.ForbiddenError "Forbidden" @@ -205,7 +205,7 @@ func UpdatePropertyHandler(s *service.Service) gin.HandlerFunc { // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/properties/{property_id} [delete] +// @Router /v1/spaces/{space_id}/properties/{property_id} [delete] func DeletePropertyHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") diff --git a/core/api/handler/search.go b/core/api/handler/search.go index 408f80c9e..81e129f02 100644 --- a/core/api/handler/search.go +++ b/core/api/handler/search.go @@ -14,12 +14,12 @@ import ( // GlobalSearchHandler searches and retrieves objects across all spaces // // @Summary Search objects across all spaces -// @Description Executes a global search over every space accessible by the authenticated user. The request body must specify the `query` text, optional filters on object types (e.g., "page", "task"), and sort directives (default: descending by last updated timestamp). Pagination is controlled via `offset` and `limit` query parameters to facilitate lazy loading in client UIs. The response returns a unified list of matched objects with their metadata and properties. -// @Id searchGlobal +// @Description Executes a global search over all spaces accessible to the authenticated user. The request body must specify the `query` text (currently matching only name and snippet of an object), optional filters on types (e.g., "page", "task"), and sort directives (default: descending by last modified date). Pagination is controlled via `offset` and `limit` query parameters to facilitate lazy loading in client UIs. The response returns a unified list of matched objects with their metadata and properties. +// @Id search_global // @Tags Search // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) // @Param limit query int false "The number of items to return" default(100) maximum(1000) // @Param request body apimodel.SearchRequest true "The search parameters used to filter and sort the results" @@ -27,7 +27,7 @@ import ( // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /search [post] +// @Router /v1/search [post] func GlobalSearchHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { offset := c.GetInt("offset") @@ -58,13 +58,13 @@ func GlobalSearchHandler(s *service.Service) gin.HandlerFunc { // SearchHandler searches and retrieves objects within a space // // @Summary Search objects within a space -// @Description Performs a focused search within a single space (specified by the space_id path parameter). Like the global search, it accepts pagination parameters and a JSON payload containing the search query, object types, and sorting preferences. The search is limited to the provided space and returns a list of objects that match the query. This allows clients to implement space‑specific filtering without having to process extraneous results. -// @Id searchSpace +// @Description Performs a search within a single space (specified by the `space_id` path parameter). Like the global search, it accepts pagination parameters and a JSON payload containing the search `query`, `types`, and sorting preferences. The search is limited to the provided space and returns a list of objects that match the query. This allows clients to implement space‑specific filtering without having to process extraneous results. +// @Id search_space // @Tags Search // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to search in" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to search in; must be retrieved from ListSpaces endpoint" // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) // @Param limit query int false "The number of items to return" default(100) maximum(1000) // @Param request body apimodel.SearchRequest true "The search parameters used to filter and sort the results" @@ -72,7 +72,7 @@ func GlobalSearchHandler(s *service.Service) gin.HandlerFunc { // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/search [post] +// @Router /v1/spaces/{space_id}/search [post] func SearchHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceID := c.Param("space_id") diff --git a/core/api/handler/space.go b/core/api/handler/space.go index 767f07a73..0eec45cee 100644 --- a/core/api/handler/space.go +++ b/core/api/handler/space.go @@ -15,17 +15,17 @@ import ( // // @Summary List spaces // @Description Retrieves a paginated list of all spaces that are accessible by the authenticated user. Each space record contains detailed information such as the space ID, name, icon (derived either from an emoji or image URL), and additional metadata. This endpoint is key to displaying a user’s workspaces. -// @Id listSpaces +// @Id list_spaces // @Tags Spaces // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) // @Param limit query int false "The number of items to return" default(100) maximum(1000) // @Success 200 {object} pagination.PaginatedResponse[apimodel.Space] "The list of spaces accessible by the authenticated user" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces [get] +// @Router /v1/spaces [get] func ListSpacesHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { offset := c.GetInt("offset") @@ -52,17 +52,17 @@ func ListSpacesHandler(s *service.Service) gin.HandlerFunc { // // @Summary Get space // @Description Fetches full details about a single space identified by its space ID. The response includes metadata such as the space name, icon, and various workspace IDs (home, archive, profile, etc.). This detailed view supports use cases such as displaying space-specific settings. -// @Id getSpace +// @Id get_space // @Tags Spaces // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to retrieve" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to retrieve; must be retrieved from ListSpaces endpoint" // @Success 200 {object} apimodel.SpaceResponse "The space details" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Space not found" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id} [get] +// @Router /v1/spaces/{space_id} [get] func GetSpaceHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -88,19 +88,19 @@ func GetSpaceHandler(s *service.Service) gin.HandlerFunc { // // @Summary Create space // @Description Creates a new space based on a supplied name and description in the JSON request body. The endpoint is subject to rate limiting and automatically applies default configurations such as generating a random icon and initializing the workspace with default settings (for example, a default dashboard or home page). On success, the new space’s full metadata is returned, enabling the client to immediately switch context to the new internal. -// @Id createSpace +// @Id create_space // @Tags Spaces // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) // @Param name body apimodel.CreateSpaceRequest true "The space to create" -// @Success 200 {object} apimodel.SpaceResponse "The created space" +// @Success 201 {object} apimodel.SpaceResponse "The created space" // @Failure 400 {object} util.ValidationError "Bad request" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces [post] +// @Router /v1/spaces [post] func CreateSpaceHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { var req apimodel.CreateSpaceRequest @@ -124,7 +124,7 @@ func CreateSpaceHandler(s *service.Service) gin.HandlerFunc { return } - c.JSON(http.StatusOK, apimodel.SpaceResponse{Space: space}) + c.JSON(http.StatusCreated, apimodel.SpaceResponse{Space: space}) } } @@ -132,12 +132,12 @@ func CreateSpaceHandler(s *service.Service) gin.HandlerFunc { // // @Summary Update space // @Description Updates the name or description of an existing space. The request body should contain the new name and/or description in JSON format. This endpoint is useful for renaming or rebranding a workspace without needing to recreate it. The updated space’s metadata is returned in the response. -// @Id updateSpace +// @Id update_space // @Tags Spaces // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to update" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to update; must be retrieved from ListSpaces endpoint" // @Param name body apimodel.UpdateSpaceRequest true "The space details to update" // @Success 200 {object} apimodel.SpaceResponse "The updated space" // @Failure 400 {object} util.ValidationError "Bad request" @@ -147,7 +147,7 @@ func CreateSpaceHandler(s *service.Service) gin.HandlerFunc { // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id} [patch] +// @Router /v1/spaces/{space_id} [patch] func UpdateSpaceHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") diff --git a/core/api/handler/tag.go b/core/api/handler/tag.go index 4d43cbb61..e47d7ab28 100644 --- a/core/api/handler/tag.go +++ b/core/api/handler/tag.go @@ -15,18 +15,18 @@ import ( // // @Summary List tags // @Description This endpoint retrieves a paginated list of tags available for a specific property within a space. Each tag record includes its unique identifier, name, and color. This information is essential for clients to display select or multi-select options to users when they are creating or editing objects. The endpoint also supports pagination through offset and limit parameters. -// @Id listTags +// @Id list_tags // @Tags Tags // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to list tags for" -// @Param property_id path string true "The ID of the property to list tags for" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to list tags for; must be retrieved from ListSpaces endpoint" +// @Param property_id path string true "The ID of the property to list tags for; must be retrieved from ListProperties endpoint or obtained from response context" // @Success 200 {object} pagination.PaginatedResponse[apimodel.Tag] "The list of tags" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Property not found" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/properties/{property_id}/tags [get] +// @Router /v1/spaces/{space_id}/properties/{property_id}/tags [get] func ListTagsHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -54,20 +54,20 @@ func ListTagsHandler(s *service.Service) gin.HandlerFunc { // // @Summary Get tag // @Description This endpoint retrieves a tag for a given property id. The tag is identified by its unique identifier within the specified space. The response includes the tag's details such as its ID, name, and color. This is useful for clients to display or when editing a specific tag option. -// @Id getTag +// @Id get_tag // @Tags Tags // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to retrieve the tag from" -// @Param property_id path string true "The ID of the property to retrieve the tag for" -// @Param tag_id path string true "The ID of the tag to retrieve" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to retrieve the tag from; must be retrieved from ListSpaces endpoint" +// @Param property_id path string true "The ID of the property to retrieve the tag for; must be retrieved from ListProperties endpoint or obtained from response context" +// @Param tag_id path string true "The ID of the tag to retrieve; must be retrieved from ListTags endpoint or obtained from response context" // @Success 200 {object} apimodel.TagResponse "The retrieved tag" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Resource not found" // @Failure 410 {object} util.GoneError "Resource deleted" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/properties/{property_id}/tags/{tag_id} [get] +// @Router /v1/spaces/{space_id}/properties/{property_id}/tags/{tag_id} [get] func GetTagHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -95,21 +95,21 @@ func GetTagHandler(s *service.Service) gin.HandlerFunc { // // @Summary Create tag // @Description This endpoint creates a new tag for a given property id in a space. The creation process is subject to rate limiting. The tag is identified by its unique identifier within the specified space. The request must include the tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to add new tag options to a property. -// @Id createTag +// @Id create_tag // @Tags Tags // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to create the tag in" -// @Param property_id path string true "The ID of the property to create the tag for" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to create the tag in; must be retrieved from ListSpaces endpoint" +// @Param property_id path string true "The ID of the property to create the tag for; must be retrieved from ListProperties endpoint or obtained from response context" // @Param tag body apimodel.CreateTagRequest true "The tag to create" -// @Success 200 {object} apimodel.TagResponse "The created tag" +// @Success 201 {object} apimodel.TagResponse "The created tag" // @Failure 400 {object} util.ValidationError "Bad request" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/properties/{property_id}/tags [post] +// @Router /v1/spaces/{space_id}/properties/{property_id}/tags [post] func CreateTagHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -135,7 +135,7 @@ func CreateTagHandler(s *service.Service) gin.HandlerFunc { return } - c.JSON(http.StatusOK, apimodel.TagResponse{Tag: option}) + c.JSON(http.StatusCreated, apimodel.TagResponse{Tag: option}) } } @@ -143,14 +143,14 @@ func CreateTagHandler(s *service.Service) gin.HandlerFunc { // // @Summary Update tag // @Description This endpoint updates a tag for a given property id in a space. The update process is subject to rate limiting. The tag is identified by its unique identifier within the specified space. The request must include the tag's name and color. The response includes the tag's details such as its ID, name, and color. This is useful for clients when users want to edit existing tags for a property. -// @Id updateTag +// @Id update_tag // @Tags Tags // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to update the tag in" -// @Param property_id path string true "The ID of the property to update the tag for" -// @Param tag_id path string true "The ID of the tag to update" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to update the tag in; must be retrieved from ListSpaces endpoint" +// @Param property_id path string true "The ID of the property to update the tag for; must be retrieved from ListProperties endpoint or obtained from response context" +// @Param tag_id path string true "The ID of the tag to update; must be retrieved from ListTags endpoint or obtained from response context" // @Param tag body apimodel.UpdateTagRequest true "The tag to update" // @Success 200 {object} apimodel.TagResponse "The updated tag" // @Failure 400 {object} util.ValidationError "Bad request" @@ -161,7 +161,7 @@ func CreateTagHandler(s *service.Service) gin.HandlerFunc { // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/properties/{property_id}/tags/{tag_id} [patch] +// @Router /v1/spaces/{space_id}/properties/{property_id}/tags/{tag_id} [patch] func UpdateTagHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -198,13 +198,13 @@ func UpdateTagHandler(s *service.Service) gin.HandlerFunc { // // @Summary Delete tag // @Description This endpoint “deletes” a tag by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the tag’s details after it has been archived. Proper error handling is in place for situations such as when the tag isn’t found or the deletion cannot be performed because of permission issues. -// @Id deleteTag +// @Id delete_tag // @Tags Tags // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to delete the tag from" -// @Param property_id path string true "The ID of the property to delete the tag for" -// @Param tag_id path string true "The ID of the tag to delete" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to delete the tag from; must be retrieved from ListSpaces endpoint" +// @Param property_id path string true "The ID of the property to delete the tag for; must be retrieved from ListProperties endpoint or obtained from response context" +// @Param tag_id path string true "The ID of the tag to delete; must be retrieved from ListTags endpoint or obtained from response context" // @Success 200 {object} apimodel.TagResponse "The deleted tag" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 403 {object} util.ForbiddenError "Forbidden" @@ -213,7 +213,7 @@ func UpdateTagHandler(s *service.Service) gin.HandlerFunc { // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/properties/{property_id}/tags/{tag_id} [delete] +// @Router /v1/spaces/{space_id}/properties/{property_id}/tags/{tag_id} [delete] func DeleteTagHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") diff --git a/core/api/handler/template.go b/core/api/handler/template.go index e72209c57..22669851e 100644 --- a/core/api/handler/template.go +++ b/core/api/handler/template.go @@ -14,20 +14,20 @@ import ( // ListTemplatesHandler retrieves a list of templates for a type in a space // // @Summary List templates -// @Description This endpoint returns a paginated list of templates that are associated with a specific object type within a space. Templates provide pre‑configured structures for creating new objects. Each template record contains its identifier, name, and icon, so that clients can offer users a selection of templates when creating objects. -// @Id listTemplates +// @Description This endpoint returns a paginated list of templates that are associated with a specific type within a space. Templates provide pre‑configured structures for creating new objects. Each template record contains its identifier, name, and icon, so that clients can offer users a selection of templates when creating objects. +// @Id list_templates // @Tags Templates // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to which the type belongs" -// @Param type_id path string true "The ID of the object type to retrieve templates for" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to which the type belongs; must be retrieved from ListSpaces endpoint" +// @Param type_id path string true "The ID of the type to retrieve templates for; must be retrieved from ListTypes endpoint or obtained from response context" // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) // @Param limit query int false "The number of items to return" default(100) maximum(1000) // @Success 200 {object} pagination.PaginatedResponse[apimodel.Object] "List of templates" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/types/{type_id}/templates [get] +// @Router /v1/spaces/{space_id}/types/{type_id}/templates [get] func ListTemplatesHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -56,21 +56,21 @@ func ListTemplatesHandler(s *service.Service) gin.HandlerFunc { // GetTemplateHandler retrieves a template for a type in a space // // @Summary Get template -// @Description Fetches full details for one template associated with a particular object type in a space. The response provides the template’s identifier, name, icon, and any other relevant metadata. This endpoint is useful when a client needs to preview or apply a template to prefill object creation fields. -// @Id getTemplate +// @Description Fetches full details for one template associated with a particular type in a space. The response provides the template’s identifier, name, icon, and any other relevant metadata. This endpoint is useful when a client needs to preview or apply a template to prefill object creation fields. +// @Id get_template // @Tags Templates // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to which the template belongs" -// @Param type_id path string true "The ID of the object type to which the template belongs" -// @Param template_id path string true "The ID of the template to retrieve" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to which the template belongs; must be retrieved from ListSpaces endpoint" +// @Param type_id path string true "The ID of the type to which the template belongs; must be retrieved from ListTypes endpoint or obtained from response context" +// @Param template_id path string true "The ID of the template to retrieve; must be retrieved from ListTemplates endpoint or obtained from response context" // @Success 200 {object} apimodel.TemplateResponse "The requested template" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Resource not found" // @Failure 410 {object} util.GoneError "Resource deleted" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/types/{type_id}/templates/{template_id} [get] +// @Router /v1/spaces/{space_id}/types/{type_id}/templates/{template_id} [get] func GetTemplateHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") diff --git a/core/api/handler/type.go b/core/api/handler/type.go index 19978da04..dc5395dc1 100644 --- a/core/api/handler/type.go +++ b/core/api/handler/type.go @@ -14,19 +14,19 @@ import ( // ListTypesHandler retrieves a list of types in a space // // @Summary List types -// @Description This endpoint retrieves a paginated list of object types (e.g. 'Page', 'Note', 'Task') available within the specified space. Each type’s record includes its unique identifier, type key, display name, icon, and layout. While a type's id is truly unique, a type's key can be the same across spaces for known types, e.g. 'page' for 'Page'. Clients use this information when offering choices for object creation or for filtering objects by type through search. -// @Id listTypes +// @Description This endpoint retrieves a paginated list of types (e.g. 'Page', 'Note', 'Task') available within the specified space. Each type’s record includes its unique identifier, type key, display name, icon, and layout. While a type's id is truly unique, a type's key can be the same across spaces for known types, e.g. 'page' for 'Page'. Clients use this information when offering choices for object creation or for filtering objects by type through search. +// @Id list_types // @Tags Types // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space to retrieve types from" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space to retrieve types from; must be retrieved from ListSpaces endpoint" // @Param offset query int false "The number of items to skip before starting to collect the result set" default(0) // @Param limit query int false "The number of items to return" default(100) maximum(1000) // @Success 200 {object} pagination.PaginatedResponse[apimodel.Type] "The list of types" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/types [get] +// @Router /v1/spaces/{space_id}/types [get] func ListTypesHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -51,20 +51,20 @@ func ListTypesHandler(s *service.Service) gin.HandlerFunc { // GetTypeHandler retrieves a type in a space // // @Summary Get type -// @Description Fetches detailed information about one specific object type by its ID. This includes the type’s unique key, name, icon, and layout. This detailed view assists clients in understanding the expected structure and style for objects of that type and in guiding the user interface (such as displaying appropriate icons or layout hints). -// @Id getType +// @Description Fetches detailed information about one specific type by its ID. This includes the type’s unique key, name, icon, and layout. This detailed view assists clients in understanding the expected structure and style for objects of that type and in guiding the user interface (such as displaying appropriate icons or layout hints). +// @Id get_type // @Tags Types // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space from which to retrieve the type" -// @Param type_id path string true "The ID of the type to retrieve" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space from which to retrieve the type; must be retrieved from ListSpaces endpoint" +// @Param type_id path string true "The ID of the type to retrieve; must be retrieved from ListTypes endpoint or obtained from response context" // @Success 200 {object} apimodel.TypeResponse "The requested type" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 404 {object} util.NotFoundError "Resource not found" // @Failure 410 {object} util.GoneError "Resource deleted" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/types/{type_id} [get] +// @Router /v1/spaces/{space_id}/types/{type_id} [get] func GetTypeHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -90,21 +90,21 @@ func GetTypeHandler(s *service.Service) gin.HandlerFunc { // CreateTypeHandler creates a new type in a space // // @Summary Create type -// @Description Creates a new object type in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include type details such as the name, icon, and layout. The endpoint then returns the full type data, ready to be used for creating objects. -// @Id createType +// @Description Creates a new type in the specified space using a JSON payload. The creation process is subject to rate limiting. The payload must include type details such as the name, icon, and layout. The endpoint then returns the full type data, ready to be used for creating objects. +// @Id create_type // @Tags Types // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space in which to create the type" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space in which to create the type; must be retrieved from ListSpaces endpoint" // @Param type body apimodel.CreateTypeRequest true "The type to create" -// @Success 200 {object} apimodel.TypeResponse "The created type" +// @Success 201 {object} apimodel.TypeResponse "The created type" // @Failure 400 {object} util.ValidationError "Bad request" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/types [post] +// @Router /v1/spaces/{space_id}/types [post] func CreateTypeHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -129,21 +129,21 @@ func CreateTypeHandler(s *service.Service) gin.HandlerFunc { return } - c.JSON(http.StatusOK, apimodel.TypeResponse{Type: object}) + c.JSON(http.StatusCreated, apimodel.TypeResponse{Type: object}) } } // UpdateTypeHandler updates a type in a space // // @Summary Update type -// @Description This endpoint updates an existing object type in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the name and properties to be updated. The endpoint then returns the full type data, ready for further interactions. -// @Id updateType +// @Description This endpoint updates an existing type in the specified space using a JSON payload. The update process is subject to rate limiting. The payload must include the name and properties to be updated. The endpoint then returns the full type data, ready for further interactions. +// @Id update_type // @Tags Types // @Accept json // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space in which the type exists" -// @Param type_id path string true "The ID of the type to update" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space in which the type exists; must be retrieved from ListSpaces endpoint" +// @Param type_id path string true "The ID of the type to update; must be retrieved from ListTypes endpoint or obtained from response context" // @Param type body apimodel.UpdateTypeRequest true "The type details to update" // @Success 200 {object} apimodel.TypeResponse "The updated type" // @Failure 400 {object} util.ValidationError "Bad request" @@ -153,7 +153,7 @@ func CreateTypeHandler(s *service.Service) gin.HandlerFunc { // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/types/{type_id} [patch] +// @Router /v1/spaces/{space_id}/types/{type_id} [patch] func UpdateTypeHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") @@ -188,13 +188,13 @@ func UpdateTypeHandler(s *service.Service) gin.HandlerFunc { // DeleteTypeHandler deletes a type in a space // // @Summary Delete type -// @Description This endpoint “deletes” an object type by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the type’s details after it has been archived. Proper error handling is in place for situations such as when the type isn’t found or the deletion cannot be performed because of permission issues. -// @Id deleteType +// @Description This endpoint “deletes” an type by marking it as archived. The deletion process is performed safely and is subject to rate limiting. It returns the type’s details after it has been archived. Proper error handling is in place for situations such as when the type isn’t found or the deletion cannot be performed because of permission issues. +// @Id delete_type // @Tags Types // @Produce json -// @Param Anytype-Version header string true "The version of the API to use" default(2025-04-22) -// @Param space_id path string true "The ID of the space from which to delete the type" -// @Param type_id path string true "The ID of the type to delete" +// @Param Anytype-Version header string true "The version of the API to use" default(2025-05-20) +// @Param space_id path string true "The ID of the space from which to delete the type; must be retrieved from ListSpaces endpoint" +// @Param type_id path string true "The ID of the type to delete; must be retrieved from ListTypes endpoint or obtained from response context" // @Success 200 {object} apimodel.TypeResponse "The deleted type" // @Failure 401 {object} util.UnauthorizedError "Unauthorized" // @Failure 403 {object} util.ForbiddenError "Forbidden" @@ -203,7 +203,7 @@ func UpdateTypeHandler(s *service.Service) gin.HandlerFunc { // @Failure 429 {object} util.RateLimitError "Rate limit exceeded" // @Failure 500 {object} util.ServerError "Internal server error" // @Security bearerauth -// @Router /spaces/{space_id}/types/{type_id} [delete] +// @Router /v1/spaces/{space_id}/types/{type_id} [delete] func DeleteTypeHandler(s *service.Service) gin.HandlerFunc { return func(c *gin.Context) { spaceId := c.Param("space_id") diff --git a/core/api/model/auth.go b/core/api/model/auth.go index a569ed70c..4402207b6 100644 --- a/core/api/model/auth.go +++ b/core/api/model/auth.go @@ -1,9 +1,28 @@ package apimodel +// TO BE DEPRECATED type DisplayCodeResponse struct { ChallengeId string `json:"challenge_id" example:"67647f5ecda913e9a2e11b26"` // The challenge id associated with the displayed code and needed to solve the challenge for token } +// TO BE DEPRECATED type TokenResponse struct { AppKey string `json:"app_key" example:"zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6="` // The app key used to authenticate requests } + +type CreateChallengeRequest struct { + AppName string `json:"app_name" example:"anytype_mcp"` // The name of the app that is requesting the challenge +} + +type CreateChallengeResponse struct { + ChallengeId string `json:"challenge_id" example:"67647f5ecda913e9a2e11b26"` // The challenge id associated with the displayed code and needed to solve the challenge for api_key +} + +type CreateApiKeyRequest struct { + ChallengeId string `json:"challenge_id" example:"67647f5ecda913e9a2e11b26"` // The challenge id associated with the previously displayed code + Code string `json:"code" example:"1234"` // The 4-digit code retrieved from Anytype Desktop app +} + +type CreateApiKeyResponse struct { + ApiKey string `json:"api_key" example:"zhSG/zQRmgADyilWPtgdnfo1qD60oK02/SVgi1GaFt6="` // The api key used to authenticate requests +} diff --git a/core/api/model/icon.go b/core/api/model/icon.go index fccbc62f1..c35dd98d5 100644 --- a/core/api/model/icon.go +++ b/core/api/model/icon.go @@ -3,7 +3,6 @@ package apimodel import ( "encoding/json" "fmt" - "unicode" "github.com/anyproto/anytype-heart/core/api/util" ) @@ -59,7 +58,814 @@ func (c *Color) UnmarshalJSON(data []byte) error { } } -var iconOptionToColor = map[float64]Color{ +type IconName string + +const ( + IconNameAccessibility IconName = "accessibility" + IconNameAddCircle IconName = "add-circle" + IconNameAirplane IconName = "airplane" + IconNameAlarm IconName = "alarm" + IconNameAlbums IconName = "albums" + IconNameAlertCircle IconName = "alert-circle" + IconNameAmericanFootball IconName = "american-football" + IconNameAnalytics IconName = "analytics" + IconNameAperture IconName = "aperture" + IconNameApps IconName = "apps" + IconNameArchive IconName = "archive" + IconNameArrowBackCircle IconName = "arrow-back-circle" + IconNameArrowDownCircle IconName = "arrow-down-circle" + IconNameArrowForwardCircle IconName = "arrow-forward-circle" + IconNameArrowRedoCircle IconName = "arrow-redo-circle" + IconNameArrowRedo IconName = "arrow-redo" + IconNameArrowUndoCircle IconName = "arrow-undo-circle" + IconNameArrowUndo IconName = "arrow-undo" + IconNameArrowUpCircle IconName = "arrow-up-circle" + IconNameAtCircle IconName = "at-circle" + IconNameAttach IconName = "attach" + IconNameBackspace IconName = "backspace" + IconNameBagAdd IconName = "bag-add" + IconNameBagCheck IconName = "bag-check" + IconNameBagHandle IconName = "bag-handle" + IconNameBagRemove IconName = "bag-remove" + IconNameBag IconName = "bag" + IconNameBalloon IconName = "balloon" + IconNameBan IconName = "ban" + IconNameBandage IconName = "bandage" + IconNameBarChart IconName = "bar-chart" + IconNameBarbell IconName = "barbell" + IconNameBarcode IconName = "barcode" + IconNameBaseball IconName = "baseball" + IconNameBasket IconName = "basket" + IconNameBasketball IconName = "basketball" + IconNameBatteryCharging IconName = "battery-charging" + IconNameBatteryDead IconName = "battery-dead" + IconNameBatteryFull IconName = "battery-full" + IconNameBatteryHalf IconName = "battery-half" + IconNameBeaker IconName = "beaker" + IconNameBed IconName = "bed" + IconNameBeer IconName = "beer" + IconNameBicycle IconName = "bicycle" + IconNameBinoculars IconName = "binoculars" + IconNameBluetooth IconName = "bluetooth" + IconNameBoat IconName = "boat" + IconNameBody IconName = "body" + IconNameBonfire IconName = "bonfire" + IconNameBook IconName = "book" + IconNameBookmark IconName = "bookmark" + IconNameBookmarks IconName = "bookmarks" + IconNameBowlingBall IconName = "bowling-ball" + IconNameBriefcase IconName = "briefcase" + IconNameBrowsers IconName = "browsers" + IconNameBrush IconName = "brush" + IconNameBug IconName = "bug" + IconNameBuild IconName = "build" + IconNameBulb IconName = "bulb" + IconNameBus IconName = "bus" + IconNameBusiness IconName = "business" + IconNameCafe IconName = "cafe" + IconNameCalculator IconName = "calculator" + IconNameCalendarClear IconName = "calendar-clear" + IconNameCalendarNumber IconName = "calendar-number" + IconNameCalendar IconName = "calendar" + IconNameCall IconName = "call" + IconNameCameraReverse IconName = "camera-reverse" + IconNameCamera IconName = "camera" + IconNameCarSport IconName = "car-sport" + IconNameCar IconName = "car" + IconNameCard IconName = "card" + IconNameCaretBackCircle IconName = "caret-back-circle" + IconNameCaretBack IconName = "caret-back" + IconNameCaretDownCircle IconName = "caret-down-circle" + IconNameCaretDown IconName = "caret-down" + IconNameCaretForwardCircle IconName = "caret-forward-circle" + IconNameCaretForward IconName = "caret-forward" + IconNameCaretUpCircle IconName = "caret-up-circle" + IconNameCaretUp IconName = "caret-up" + IconNameCart IconName = "cart" + IconNameCash IconName = "cash" + IconNameCellular IconName = "cellular" + IconNameChatboxEllipses IconName = "chatbox-ellipses" + IconNameChatbox IconName = "chatbox" + IconNameChatbubbleEllipses IconName = "chatbubble-ellipses" + IconNameChatbubble IconName = "chatbubble" + IconNameChatbubbles IconName = "chatbubbles" + IconNameCheckbox IconName = "checkbox" + IconNameCheckmarkCircle IconName = "checkmark-circle" + IconNameCheckmarkDoneCircle IconName = "checkmark-done-circle" + IconNameChevronBackCircle IconName = "chevron-back-circle" + IconNameChevronDownCircle IconName = "chevron-down-circle" + IconNameChevronForwardCircle IconName = "chevron-forward-circle" + IconNameChevronUpCircle IconName = "chevron-up-circle" + IconNameClipboard IconName = "clipboard" + IconNameCloseCircle IconName = "close-circle" + IconNameCloudCircle IconName = "cloud-circle" + IconNameCloudDone IconName = "cloud-done" + IconNameCloudDownload IconName = "cloud-download" + IconNameCloudOffline IconName = "cloud-offline" + IconNameCloudUpload IconName = "cloud-upload" + IconNameCloud IconName = "cloud" + IconNameCloudyNight IconName = "cloudy-night" + IconNameCloudy IconName = "cloudy" + IconNameCodeSlash IconName = "code-slash" + IconNameCode IconName = "code" + IconNameCog IconName = "cog" + IconNameColorFill IconName = "color-fill" + IconNameColorFilter IconName = "color-filter" + IconNameColorPalette IconName = "color-palette" + IconNameColorWand IconName = "color-wand" + IconNameCompass IconName = "compass" + IconNameConstruct IconName = "construct" + IconNameContact IconName = "contact" + IconNameContract IconName = "contract" + IconNameContrast IconName = "contrast" + IconNameCopy IconName = "copy" + IconNameCreate IconName = "create" + IconNameCrop IconName = "crop" + IconNameCube IconName = "cube" + IconNameCut IconName = "cut" + IconNameDesktop IconName = "desktop" + IconNameDiamond IconName = "diamond" + IconNameDice IconName = "dice" + IconNameDisc IconName = "disc" + IconNameDocumentAttach IconName = "document-attach" + IconNameDocumentLock IconName = "document-lock" + IconNameDocumentText IconName = "document-text" + IconNameDocument IconName = "document" + IconNameDocuments IconName = "documents" + IconNameDownload IconName = "download" + IconNameDuplicate IconName = "duplicate" + IconNameEar IconName = "ear" + IconNameEarth IconName = "earth" + IconNameEasel IconName = "easel" + IconNameEgg IconName = "egg" + IconNameEllipse IconName = "ellipse" + IconNameEllipsisHorizontalCircle IconName = "ellipsis-horizontal-circle" + IconNameEllipsisVerticalCircle IconName = "ellipsis-vertical-circle" + IconNameEnter IconName = "enter" + IconNameExit IconName = "exit" + IconNameExpand IconName = "expand" + IconNameExtensionPuzzle IconName = "extension-puzzle" + IconNameEyeOff IconName = "eye-off" + IconNameEye IconName = "eye" + IconNameEyedrop IconName = "eyedrop" + IconNameFastFood IconName = "fast-food" + IconNameFemale IconName = "female" + IconNameFileTrayFull IconName = "file-tray-full" + IconNameFileTrayStacked IconName = "file-tray-stacked" + IconNameFileTray IconName = "file-tray" + IconNameFilm IconName = "film" + IconNameFilterCircle IconName = "filter-circle" + IconNameFingerPrint IconName = "finger-print" + IconNameFish IconName = "fish" + IconNameFitness IconName = "fitness" + IconNameFlag IconName = "flag" + IconNameFlame IconName = "flame" + IconNameFlashOff IconName = "flash-off" + IconNameFlash IconName = "flash" + IconNameFlashlight IconName = "flashlight" + IconNameFlask IconName = "flask" + IconNameFlower IconName = "flower" + IconNameFolderOpen IconName = "folder-open" + IconNameFolder IconName = "folder" + IconNameFootball IconName = "football" + IconNameFootsteps IconName = "footsteps" + IconNameFunnel IconName = "funnel" + IconNameGameController IconName = "game-controller" + IconNameGift IconName = "gift" + IconNameGitBranch IconName = "git-branch" + IconNameGitCommit IconName = "git-commit" + IconNameGitCompare IconName = "git-compare" + IconNameGitMerge IconName = "git-merge" + IconNameGitNetwork IconName = "git-network" + IconNameGitPullRequest IconName = "git-pull-request" + IconNameGlasses IconName = "glasses" + IconNameGlobe IconName = "globe" + IconNameGolf IconName = "golf" + IconNameGrid IconName = "grid" + IconNameHammer IconName = "hammer" + IconNameHandLeft IconName = "hand-left" + IconNameHandRight IconName = "hand-right" + IconNameHappy IconName = "happy" + IconNameHardwareChip IconName = "hardware-chip" + IconNameHeadset IconName = "headset" + IconNameHeartCircle IconName = "heart-circle" + IconNameHeartDislikeCircle IconName = "heart-dislike-circle" + IconNameHeartDislike IconName = "heart-dislike" + IconNameHeartHalf IconName = "heart-half" + IconNameHeart IconName = "heart" + IconNameHelpBuoy IconName = "help-buoy" + IconNameHelpCircle IconName = "help-circle" + IconNameHome IconName = "home" + IconNameHourglass IconName = "hourglass" + IconNameIceCream IconName = "ice-cream" + IconNameIdCard IconName = "id-card" + IconNameImage IconName = "image" + IconNameImages IconName = "images" + IconNameInfinite IconName = "infinite" + IconNameInformationCircle IconName = "information-circle" + IconNameInvertMode IconName = "invert-mode" + IconNameJournal IconName = "journal" + IconNameKey IconName = "key" + IconNameKeypad IconName = "keypad" + IconNameLanguage IconName = "language" + IconNameLaptop IconName = "laptop" + IconNameLayers IconName = "layers" + IconNameLeaf IconName = "leaf" + IconNameLibrary IconName = "library" + IconNameLink IconName = "link" + IconNameListCircle IconName = "list-circle" + IconNameList IconName = "list" + IconNameLocate IconName = "locate" + IconNameLocation IconName = "location" + IconNameLockClosed IconName = "lock-closed" + IconNameLockOpen IconName = "lock-open" + IconNameLogIn IconName = "log-in" + IconNameLogOut IconName = "log-out" + IconNameLogoAlipay IconName = "logo-alipay" + IconNameLogoAmazon IconName = "logo-amazon" + IconNameLogoAmplify IconName = "logo-amplify" + IconNameLogoAndroid IconName = "logo-android" + IconNameMagnet IconName = "magnet" + IconNameMailOpen IconName = "mail-open" + IconNameMailUnread IconName = "mail-unread" + IconNameMail IconName = "mail" + IconNameMaleFemale IconName = "male-female" + IconNameMale IconName = "male" + IconNameMan IconName = "man" + IconNameMap IconName = "map" + IconNameMedal IconName = "medal" + IconNameMedical IconName = "medical" + IconNameMedkit IconName = "medkit" + IconNameMegaphone IconName = "megaphone" + IconNameMenu IconName = "menu" + IconNameMicCircle IconName = "mic-circle" + IconNameMicOffCircle IconName = "mic-off-circle" + IconNameMicOff IconName = "mic-off" + IconNameMic IconName = "mic" + IconNameMoon IconName = "moon" + IconNameMove IconName = "move" + IconNameMusicalNote IconName = "musical-note" + IconNameMusicalNotes IconName = "musical-notes" + IconNameNavigateCircle IconName = "navigate-circle" + IconNameNavigate IconName = "navigate" + IconNameNewspaper IconName = "newspaper" + IconNameNotificationsCircle IconName = "notifications-circle" + IconNameNotificationsOffCircle IconName = "notifications-off-circle" + IconNameNotificationsOff IconName = "notifications-off" + IconNameNotifications IconName = "notifications" + IconNameNuclear IconName = "nuclear" + IconNameNutrition IconName = "nutrition" + IconNameOptions IconName = "options" + IconNamePaperPlane IconName = "paper-plane" + IconNamePartlySunny IconName = "partly-sunny" + IconNamePauseCircle IconName = "pause-circle" + IconNamePause IconName = "pause" + IconNamePaw IconName = "paw" + IconNamePencil IconName = "pencil" + IconNamePeopleCircle IconName = "people-circle" + IconNamePeople IconName = "people" + IconNamePersonAdd IconName = "person-add" + IconNamePersonCircle IconName = "person-circle" + IconNamePersonRemove IconName = "person-remove" + IconNamePerson IconName = "person" + IconNamePhoneLandscape IconName = "phone-landscape" + IconNamePhonePortrait IconName = "phone-portrait" + IconNamePieChart IconName = "pie-chart" + IconNamePin IconName = "pin" + IconNamePint IconName = "pint" + IconNamePizza IconName = "pizza" + IconNamePlanet IconName = "planet" + IconNamePlayBackCircle IconName = "play-back-circle" + IconNamePlayBack IconName = "play-back" + IconNamePlayCircle IconName = "play-circle" + IconNamePlayForwardCircle IconName = "play-forward-circle" + IconNamePlayForward IconName = "play-forward" + IconNamePlaySkipBackCircle IconName = "play-skip-back-circle" + IconNamePlaySkipBack IconName = "play-skip-back" + IconNamePlaySkipForwardCircle IconName = "play-skip-forward-circle" + IconNamePlaySkipForward IconName = "play-skip-forward" + IconNamePlay IconName = "play" + IconNamePodium IconName = "podium" + IconNamePower IconName = "power" + IconNamePricetag IconName = "pricetag" + IconNamePricetags IconName = "pricetags" + IconNamePrint IconName = "print" + IconNamePrism IconName = "prism" + IconNamePulse IconName = "pulse" + IconNamePush IconName = "push" + IconNameQrCode IconName = "qr-code" + IconNameRadioButtonOff IconName = "radio-button-off" + IconNameRadioButtonOn IconName = "radio-button-on" + IconNameRadio IconName = "radio" + IconNameRainy IconName = "rainy" + IconNameReader IconName = "reader" + IconNameReceipt IconName = "receipt" + IconNameRecording IconName = "recording" + IconNameRefreshCircle IconName = "refresh-circle" + IconNameRefresh IconName = "refresh" + IconNameReloadCircle IconName = "reload-circle" + IconNameReload IconName = "reload" + IconNameRemoveCircle IconName = "remove-circle" + IconNameRepeat IconName = "repeat" + IconNameResize IconName = "resize" + IconNameRestaurant IconName = "restaurant" + IconNameRibbon IconName = "ribbon" + IconNameRocket IconName = "rocket" + IconNameRose IconName = "rose" + IconNameSad IconName = "sad" + IconNameSave IconName = "save" + IconNameScale IconName = "scale" + IconNameScanCircle IconName = "scan-circle" + IconNameScan IconName = "scan" + IconNameSchool IconName = "school" + IconNameSearchCircle IconName = "search-circle" + IconNameSearch IconName = "search" + IconNameSend IconName = "send" + IconNameServer IconName = "server" + IconNameSettings IconName = "settings" + IconNameShapes IconName = "shapes" + IconNameShareSocial IconName = "share-social" + IconNameShare IconName = "share" + IconNameShieldCheckmark IconName = "shield-checkmark" + IconNameShieldHalf IconName = "shield-half" + IconNameShield IconName = "shield" + IconNameShirt IconName = "shirt" + IconNameShuffle IconName = "shuffle" + IconNameSkull IconName = "skull" + IconNameSnow IconName = "snow" + IconNameSparkles IconName = "sparkles" + IconNameSpeedometer IconName = "speedometer" + IconNameSquare IconName = "square" + IconNameStarHalf IconName = "star-half" + IconNameStar IconName = "star" + IconNameStatsChart IconName = "stats-chart" + IconNameStopCircle IconName = "stop-circle" + IconNameStop IconName = "stop" + IconNameStopwatch IconName = "stopwatch" + IconNameStorefront IconName = "storefront" + IconNameSubway IconName = "subway" + IconNameSunny IconName = "sunny" + IconNameSwapHorizontal IconName = "swap-horizontal" + IconNameSwapVertical IconName = "swap-vertical" + IconNameSyncCircle IconName = "sync-circle" + IconNameSync IconName = "sync" + IconNameTabletLandscape IconName = "tablet-landscape" + IconNameTabletPortrait IconName = "tablet-portrait" + IconNameTelescope IconName = "telescope" + IconNameTennisball IconName = "tennisball" + IconNameTerminal IconName = "terminal" + IconNameText IconName = "text" + IconNameThermometer IconName = "thermometer" + IconNameThumbsDown IconName = "thumbs-down" + IconNameThumbsUp IconName = "thumbs-up" + IconNameThunderstorm IconName = "thunderstorm" + IconNameTicket IconName = "ticket" + IconNameTime IconName = "time" + IconNameTimer IconName = "timer" + IconNameToday IconName = "today" + IconNameToggle IconName = "toggle" + IconNameTrailSign IconName = "trail-sign" + IconNameTrain IconName = "train" + IconNameTransgender IconName = "transgender" + IconNameTrashBin IconName = "trash-bin" + IconNameTrash IconName = "trash" + IconNameTrendingDown IconName = "trending-down" + IconNameTrendingUp IconName = "trending-up" + IconNameTriangle IconName = "triangle" + IconNameTrophy IconName = "trophy" + IconNameTv IconName = "tv" + IconNameUmbrella IconName = "umbrella" + IconNameUnlink IconName = "unlink" + IconNameVideocamOff IconName = "videocam-off" + IconNameVideocam IconName = "videocam" + IconNameVolumeHigh IconName = "volume-high" + IconNameVolumeLow IconName = "volume-low" + IconNameVolumeMedium IconName = "volume-medium" + IconNameVolumeMute IconName = "volume-mute" + IconNameVolumeOff IconName = "volume-off" + IconNameWalk IconName = "walk" + IconNameWallet IconName = "wallet" + IconNameWarning IconName = "warning" + IconNameWatch IconName = "watch" + IconNameWater IconName = "water" + IconNameWifi IconName = "wifi" + IconNameWine IconName = "wine" + IconNameWoman IconName = "woman" +) + +var validIconNames = func() map[IconName]struct{} { + m := make(map[IconName]struct{}, 390) + for _, v := range []IconName{ + IconNameAccessibility, + IconNameAddCircle, + IconNameAirplane, + IconNameAlarm, + IconNameAlbums, + IconNameAlertCircle, + IconNameAmericanFootball, + IconNameAnalytics, + IconNameAperture, + IconNameApps, + IconNameArchive, + IconNameArrowBackCircle, + IconNameArrowDownCircle, + IconNameArrowForwardCircle, + IconNameArrowRedoCircle, + IconNameArrowRedo, + IconNameArrowUndoCircle, + IconNameArrowUndo, + IconNameArrowUpCircle, + IconNameAtCircle, + IconNameAttach, + IconNameBackspace, + IconNameBagAdd, + IconNameBagCheck, + IconNameBagHandle, + IconNameBagRemove, + IconNameBag, + IconNameBalloon, + IconNameBan, + IconNameBandage, + IconNameBarChart, + IconNameBarbell, + IconNameBarcode, + IconNameBaseball, + IconNameBasket, + IconNameBasketball, + IconNameBatteryCharging, + IconNameBatteryDead, + IconNameBatteryFull, + IconNameBatteryHalf, + IconNameBeaker, + IconNameBed, + IconNameBeer, + IconNameBicycle, + IconNameBinoculars, + IconNameBluetooth, + IconNameBoat, + IconNameBody, + IconNameBonfire, + IconNameBook, + IconNameBookmark, + IconNameBookmarks, + IconNameBowlingBall, + IconNameBriefcase, + IconNameBrowsers, + IconNameBrush, + IconNameBug, + IconNameBuild, + IconNameBulb, + IconNameBus, + IconNameBusiness, + IconNameCafe, + IconNameCalculator, + IconNameCalendarClear, + IconNameCalendarNumber, + IconNameCalendar, + IconNameCall, + IconNameCameraReverse, + IconNameCamera, + IconNameCarSport, + IconNameCar, + IconNameCard, + IconNameCaretBackCircle, + IconNameCaretBack, + IconNameCaretDownCircle, + IconNameCaretDown, + IconNameCaretForwardCircle, + IconNameCaretForward, + IconNameCaretUpCircle, + IconNameCaretUp, + IconNameCart, + IconNameCash, + IconNameCellular, + IconNameChatboxEllipses, + IconNameChatbox, + IconNameChatbubbleEllipses, + IconNameChatbubble, + IconNameChatbubbles, + IconNameCheckbox, + IconNameCheckmarkCircle, + IconNameCheckmarkDoneCircle, + IconNameChevronBackCircle, + IconNameChevronDownCircle, + IconNameChevronForwardCircle, + IconNameChevronUpCircle, + IconNameClipboard, + IconNameCloseCircle, + IconNameCloudCircle, + IconNameCloudDone, + IconNameCloudDownload, + IconNameCloudOffline, + IconNameCloudUpload, + IconNameCloud, + IconNameCloudyNight, + IconNameCloudy, + IconNameCodeSlash, + IconNameCode, + IconNameCog, + IconNameColorFill, + IconNameColorFilter, + IconNameColorPalette, + IconNameColorWand, + IconNameCompass, + IconNameConstruct, + IconNameContact, + IconNameContract, + IconNameContrast, + IconNameCopy, + IconNameCreate, + IconNameCrop, + IconNameCube, + IconNameCut, + IconNameDesktop, + IconNameDiamond, + IconNameDice, + IconNameDisc, + IconNameDocumentAttach, + IconNameDocumentLock, + IconNameDocumentText, + IconNameDocument, + IconNameDocuments, + IconNameDownload, + IconNameDuplicate, + IconNameEar, + IconNameEarth, + IconNameEasel, + IconNameEgg, + IconNameEllipse, + IconNameEllipsisHorizontalCircle, + IconNameEllipsisVerticalCircle, + IconNameEnter, + IconNameExit, + IconNameExpand, + IconNameExtensionPuzzle, + IconNameEyeOff, + IconNameEye, + IconNameEyedrop, + IconNameFastFood, + IconNameFemale, + IconNameFileTrayFull, + IconNameFileTrayStacked, + IconNameFileTray, + IconNameFilm, + IconNameFilterCircle, + IconNameFingerPrint, + IconNameFish, + IconNameFitness, + IconNameFlag, + IconNameFlame, + IconNameFlashOff, + IconNameFlash, + IconNameFlashlight, + IconNameFlask, + IconNameFlower, + IconNameFolderOpen, + IconNameFolder, + IconNameFootball, + IconNameFootsteps, + IconNameFunnel, + IconNameGameController, + IconNameGift, + IconNameGitBranch, + IconNameGitCommit, + IconNameGitCompare, + IconNameGitMerge, + IconNameGitNetwork, + IconNameGitPullRequest, + IconNameGlasses, + IconNameGlobe, + IconNameGolf, + IconNameGrid, + IconNameHammer, + IconNameHandLeft, + IconNameHandRight, + IconNameHappy, + IconNameHardwareChip, + IconNameHeadset, + IconNameHeartCircle, + IconNameHeartDislikeCircle, + IconNameHeartDislike, + IconNameHeartHalf, + IconNameHeart, + IconNameHelpBuoy, + IconNameHelpCircle, + IconNameHome, + IconNameHourglass, + IconNameIceCream, + IconNameIdCard, + IconNameImage, + IconNameImages, + IconNameInfinite, + IconNameInformationCircle, + IconNameInvertMode, + IconNameJournal, + IconNameKey, + IconNameKeypad, + IconNameLanguage, + IconNameLaptop, + IconNameLayers, + IconNameLeaf, + IconNameLibrary, + IconNameLink, + IconNameListCircle, + IconNameList, + IconNameLocate, + IconNameLocation, + IconNameLockClosed, + IconNameLockOpen, + IconNameLogIn, + IconNameLogOut, + IconNameLogoAlipay, + IconNameLogoAmazon, + IconNameLogoAmplify, + IconNameLogoAndroid, + IconNameMagnet, + IconNameMailOpen, + IconNameMailUnread, + IconNameMail, + IconNameMaleFemale, + IconNameMale, + IconNameMan, + IconNameMap, + IconNameMedal, + IconNameMedical, + IconNameMedkit, + IconNameMegaphone, + IconNameMenu, + IconNameMicCircle, + IconNameMicOffCircle, + IconNameMicOff, + IconNameMic, + IconNameMoon, + IconNameMove, + IconNameMusicalNote, + IconNameMusicalNotes, + IconNameNavigateCircle, + IconNameNavigate, + IconNameNewspaper, + IconNameNotificationsCircle, + IconNameNotificationsOffCircle, + IconNameNotificationsOff, + IconNameNotifications, + IconNameNuclear, + IconNameNutrition, + IconNameOptions, + IconNamePaperPlane, + IconNamePartlySunny, + IconNamePauseCircle, + IconNamePause, + IconNamePaw, + IconNamePencil, + IconNamePeopleCircle, + IconNamePeople, + IconNamePersonAdd, + IconNamePersonCircle, + IconNamePersonRemove, + IconNamePerson, + IconNamePhoneLandscape, + IconNamePhonePortrait, + IconNamePieChart, + IconNamePin, + IconNamePint, + IconNamePizza, + IconNamePlanet, + IconNamePlayBackCircle, + IconNamePlayBack, + IconNamePlayCircle, + IconNamePlayForwardCircle, + IconNamePlayForward, + IconNamePlaySkipBackCircle, + IconNamePlaySkipBack, + IconNamePlaySkipForwardCircle, + IconNamePlaySkipForward, + IconNamePlay, + IconNamePodium, + IconNamePower, + IconNamePricetag, + IconNamePricetags, + IconNamePrint, + IconNamePrism, + IconNamePulse, + IconNamePush, + IconNameQrCode, + IconNameRadioButtonOff, + IconNameRadioButtonOn, + IconNameRadio, + IconNameRainy, + IconNameReader, + IconNameReceipt, + IconNameRecording, + IconNameRefreshCircle, + IconNameRefresh, + IconNameReloadCircle, + IconNameReload, + IconNameRemoveCircle, + IconNameRepeat, + IconNameResize, + IconNameRestaurant, + IconNameRibbon, + IconNameRocket, + IconNameRose, + IconNameSad, + IconNameSave, + IconNameScale, + IconNameScanCircle, + IconNameScan, + IconNameSchool, + IconNameSearchCircle, + IconNameSearch, + IconNameSend, + IconNameServer, + IconNameSettings, + IconNameShapes, + IconNameShareSocial, + IconNameShare, + IconNameShieldCheckmark, + IconNameShieldHalf, + IconNameShield, + IconNameShirt, + IconNameShuffle, + IconNameSkull, + IconNameSnow, + IconNameSparkles, + IconNameSpeedometer, + IconNameSquare, + IconNameStarHalf, + IconNameStar, + IconNameStatsChart, + IconNameStopCircle, + IconNameStop, + IconNameStopwatch, + IconNameStorefront, + IconNameSubway, + IconNameSunny, + IconNameSwapHorizontal, + IconNameSwapVertical, + IconNameSyncCircle, + IconNameSync, + IconNameTabletLandscape, + IconNameTabletPortrait, + IconNameTelescope, + IconNameTennisball, + IconNameTerminal, + IconNameText, + IconNameThermometer, + IconNameThumbsDown, + IconNameThumbsUp, + IconNameThunderstorm, + IconNameTicket, + IconNameTime, + IconNameTimer, + IconNameToday, + IconNameToggle, + IconNameTrailSign, + IconNameTrain, + IconNameTransgender, + IconNameTrashBin, + IconNameTrash, + IconNameTrendingDown, + IconNameTrendingUp, + IconNameTriangle, + IconNameTrophy, + IconNameTv, + IconNameUmbrella, + IconNameUnlink, + IconNameVideocamOff, + IconNameVideocam, + IconNameVolumeHigh, + IconNameVolumeLow, + IconNameVolumeMedium, + IconNameVolumeMute, + IconNameVolumeOff, + IconNameWalk, + IconNameWallet, + IconNameWarning, + IconNameWatch, + IconNameWater, + IconNameWifi, + IconNameWine, + IconNameWoman, + } { + m[v] = struct{}{} + } + return m +}() + +func (n *IconName) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + name := IconName(s) + if _, ok := validIconNames[name]; !ok { + return util.ErrBadInput(fmt.Sprintf("invalid icon name: %q", s)) + } + *n = name + return nil +} + +var IconOptionToColor = map[float64]Color{ 1: ColorGrey, 2: ColorYellow, 3: ColorOrange, @@ -72,6 +878,19 @@ var iconOptionToColor = map[float64]Color{ 10: ColorLime, } +var ColorToIconOption = map[Color]int64{ + ColorGrey: 1, + ColorYellow: 2, + ColorOrange: 3, + ColorRed: 4, + ColorPink: 5, + ColorPurple: 6, + ColorBlue: 7, + ColorIce: 8, + ColorTeal: 9, + ColorLime: 10, +} + var ColorOptionToColor = map[string]Color{ "grey": ColorGrey, "yellow": ColorYellow, @@ -102,10 +921,6 @@ func StringPtr(s string) *string { return &s } -func ColorPtr(c Color) *Color { - return &c -} - type Icon struct { WrappedIcon `swaggerignore:"true"` } @@ -162,49 +977,11 @@ type FileIcon struct { func (FileIcon) isIcon() {} +// TODO: the enum gen for IconFormat through swaggo is bugged; only the last enum (before: "icon") is used type NamedIcon struct { - Format IconFormat `json:"format" enums:"icon"` // The format of the icon - Name string `json:"name" example:"document"` // The name of the icon - Color *Color `json:"color,omitempty" example:"yellow" enums:"grey,yellow,orange,red,pink,purple,blue,ice,teal,lime"` // The color of the icon + Format IconFormat `json:"format" enums:"emoji,file,icon"` // The format of the icon + Name IconName `json:"name" example:"document"` // The name of the icon + Color Color `json:"color" example:"yellow" enums:"grey,yellow,orange,red,pink,purple,blue,ice,teal,lime"` // The color of the icon } func (NamedIcon) isIcon() {} - -func IsEmoji(s string) bool { - if s == "" { - return false - } - for _, r := range s { - if unicode.Is(unicode.Cf, r) || unicode.Is(unicode.So, r) || unicode.Is(unicode.Sk, r) { - continue - } else { - return false - } - } - return true -} - -// GetIcon returns the appropriate Icon implementation. -func GetIcon(gatewayUrl string, iconEmoji string, iconImage string, iconName string, iconOption float64) Icon { - if iconName != "" { - return Icon{NamedIcon{ - Format: IconFormatIcon, - Name: iconName, - Color: ColorPtr(iconOptionToColor[iconOption]), - }} - } - if iconEmoji != "" { - return Icon{EmojiIcon{ - Format: IconFormatEmoji, - Emoji: iconEmoji, - }} - } - if iconImage != "" { - return Icon{FileIcon{ - Format: IconFormatFile, - File: fmt.Sprintf("%s/image/%s", gatewayUrl, iconImage), - }} - } - - return Icon{NamedIcon{Format: ""}} -} diff --git a/core/api/model/list.go b/core/api/model/list.go index f8a58a2e0..253b01056 100644 --- a/core/api/model/list.go +++ b/core/api/model/list.go @@ -1,5 +1,9 @@ package apimodel +type AddObjectsToListRequest struct { + Objects []string `json:"objects" example:"[\"bafyreie6n5l5nkbjal37su54cha4coy7qzuhrnajluzv5qd5jvtsrxkequ\"]"` // The list of object IDs to add to the list +} + type View struct { Id string `json:"id" example:"67bf3f21cda9134102e2422c"` // The id of the view Name string `json:"name" example:"All"` // The name of the view diff --git a/core/api/model/object.go b/core/api/model/object.go index cb2e4df42..b474735dd 100644 --- a/core/api/model/object.go +++ b/core/api/model/object.go @@ -47,13 +47,13 @@ type CreateObjectRequest struct { Body string `json:"body" example:"This is the body of the object. Markdown syntax is supported here."` // The body of the object TemplateId string `json:"template_id" example:"bafyreictrp3obmnf6dwejy5o4p7bderaaia4bdg2psxbfzf44yya5uutge"` // The id of the template to use TypeKey string `json:"type_key" binding:"required" example:"page"` // The key of the type of object to create - Properties []PropertyLinkWithValue `json:"properties" oneOf:"TextPropertyLinkValue,NumberPropertyLinkValue,SelectPropertyLinkValue,MultiSelectPropertyLinkValue,DatePropertyLinkValue,FilesPropertyLinkValue,CheckboxPropertyLinkValue,URLPropertyLinkValue,EmailPropertyLinkValue,PhonePropertyLinkValue,ObjectsPropertyLinkValue"` // ⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set on the object + Properties []PropertyLinkWithValue `json:"properties" oneOf:"TextPropertyLinkValue,NumberPropertyLinkValue,SelectPropertyLinkValue,MultiSelectPropertyLinkValue,DatePropertyLinkValue,FilesPropertyLinkValue,CheckboxPropertyLinkValue,URLPropertyLinkValue,EmailPropertyLinkValue,PhonePropertyLinkValue,ObjectsPropertyLinkValue"` // ⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set on the object; see ListTypes or GetType endpoints for linked properties } type UpdateObjectRequest struct { Name *string `json:"name,omitempty" example:"My object"` // The name of the object Icon *Icon `json:"icon,omitempty" oneOf:"EmojiIcon,FileIcon,NamedIcon"` // The icon to set for the object - Properties *[]PropertyLinkWithValue `json:"properties,omitempty" oneOf:"TextPropertyLinkValue,NumberPropertyLinkValue,SelectPropertyLinkValue,MultiSelectPropertyLinkValue,DatePropertyLinkValue,FilesPropertyLinkValue,CheckboxPropertyLinkValue,URLPropertyLinkValue,EmailPropertyLinkValue,PhonePropertyLinkValue,ObjectsPropertyLinkValue"` // ⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set for the object + Properties *[]PropertyLinkWithValue `json:"properties,omitempty" oneOf:"TextPropertyLinkValue,NumberPropertyLinkValue,SelectPropertyLinkValue,MultiSelectPropertyLinkValue,DatePropertyLinkValue,FilesPropertyLinkValue,CheckboxPropertyLinkValue,URLPropertyLinkValue,EmailPropertyLinkValue,PhonePropertyLinkValue,ObjectsPropertyLinkValue"` // ⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set for the object; see ListTypes or GetType endpoints for linked properties } type ObjectResponse struct { diff --git a/core/api/model/property.go b/core/api/model/property.go index 9afc35bff..4f90bf63f 100644 --- a/core/api/model/property.go +++ b/core/api/model/property.go @@ -42,11 +42,13 @@ type PropertyResponse struct { } type CreatePropertyRequest struct { + Key string `json:"key" example:"some_user_defined_property_key"` // The key of the property; should always be snake_case, otherwise it will be converted to snake_case Name string `json:"name" binding:"required" example:"Last modified date"` // The name of the property Format PropertyFormat `json:"format" binding:"required" enums:"text,number,select,multi_select,date,files,checkbox,url,email,phone,objects"` // The format of the property } type UpdatePropertyRequest struct { + Key *string `json:"key,omitempty" example:"some_user_defined_property_key"` // The key to set for the property; ; should always be snake_case, otherwise it will be converted to snake_case Name *string `json:"name,omitempty" binding:"required" example:"Last modified date"` // The name to set for the property } @@ -56,6 +58,8 @@ type Property struct { Key string `json:"key" example:"last_modified_date"` // The key of the property Name string `json:"name" example:"Last modified date"` // The name of the property Format PropertyFormat `json:"format" enums:"text,number,select,multi_select,date,files,checkbox,url,email,phone,objects"` // The format of the property + // Rk is internal-only to simplify lookup on entry, won't be serialized to property responses + RelationKey string `json:"-" swaggerignore:"true"` } type PropertyLink struct { @@ -212,10 +216,10 @@ func (DatePropertyValue) isPropertyWithValue() {} type FilesPropertyValue struct { PropertyBase - Key string `json:"key" example:"files"` // The key of the property - Name string `json:"name" example:"Files"` // The name of the property - Format PropertyFormat `json:"format" enums:"files"` // The format of the property - Files []string `json:"files" example:"['fileId']"` // The file values of the property + Key string `json:"key" example:"files"` // The key of the property + Name string `json:"name" example:"Files"` // The name of the property + Format PropertyFormat `json:"format" enums:"files"` // The format of the property + Files []string `json:"files" example:"['file_id']"` // The file values of the property } func (FilesPropertyValue) isPropertyWithValue() {} @@ -262,10 +266,10 @@ func (PhonePropertyValue) isPropertyWithValue() {} type ObjectsPropertyValue struct { PropertyBase - Key string `json:"key" example:"creator"` // The key of the property - Name string `json:"name" example:"Created by"` // The name of the property - Format PropertyFormat `json:"format" enums:"objects"` // The format of the property - Objects []string `json:"objects" example:"['objectId']"` // The object values of the property + Key string `json:"key" example:"creator"` // The key of the property + Name string `json:"name" example:"Created by"` // The name of the property + Format PropertyFormat `json:"format" enums:"objects"` // The format of the property + Objects []string `json:"objects" example:"['object_id']"` // The object values of the property } func (ObjectsPropertyValue) isPropertyWithValue() {} @@ -279,173 +283,158 @@ func (p PropertyLinkWithValue) MarshalJSON() ([]byte, error) { } func (p *PropertyLinkWithValue) UnmarshalJSON(data []byte) error { - var raw struct { - Format PropertyFormat `json:"format"` - } - if err := json.Unmarshal(data, &raw); err != nil { + var aux map[string]json.RawMessage + if err := json.Unmarshal(data, &aux); err != nil { return err } - - switch raw.Format { - case PropertyFormatText: + switch { + case aux["text"] != nil: var v TextPropertyLinkValue if err := json.Unmarshal(data, &v); err != nil { return err } p.WrappedPropertyLinkWithValue = v - case PropertyFormatNumber: + case aux["number"] != nil: var v NumberPropertyLinkValue if err := json.Unmarshal(data, &v); err != nil { return err } p.WrappedPropertyLinkWithValue = v - case PropertyFormatSelect: + case aux["select"] != nil: var v SelectPropertyLinkValue if err := json.Unmarshal(data, &v); err != nil { return err } p.WrappedPropertyLinkWithValue = v - case PropertyFormatMultiSelect: + case aux["multi_select"] != nil: var v MultiSelectPropertyLinkValue if err := json.Unmarshal(data, &v); err != nil { return err } p.WrappedPropertyLinkWithValue = v - case PropertyFormatDate: + case aux["date"] != nil: var v DatePropertyLinkValue if err := json.Unmarshal(data, &v); err != nil { return err } p.WrappedPropertyLinkWithValue = v - case PropertyFormatFiles: + case aux["files"] != nil: var v FilesPropertyLinkValue if err := json.Unmarshal(data, &v); err != nil { return err } p.WrappedPropertyLinkWithValue = v - case PropertyFormatCheckbox: + case aux["checkbox"] != nil: var v CheckboxPropertyLinkValue if err := json.Unmarshal(data, &v); err != nil { return err } p.WrappedPropertyLinkWithValue = v - case PropertyFormatUrl: + case aux["url"] != nil: var v URLPropertyLinkValue if err := json.Unmarshal(data, &v); err != nil { return err } p.WrappedPropertyLinkWithValue = v - case PropertyFormatEmail: + case aux["email"] != nil: var v EmailPropertyLinkValue if err := json.Unmarshal(data, &v); err != nil { return err } p.WrappedPropertyLinkWithValue = v - case PropertyFormatPhone: + case aux["phone"] != nil: var v PhonePropertyLinkValue if err := json.Unmarshal(data, &v); err != nil { return err } p.WrappedPropertyLinkWithValue = v - case PropertyFormatObjects: + case aux["objects"] != nil: var v ObjectsPropertyLinkValue if err := json.Unmarshal(data, &v); err != nil { return err } p.WrappedPropertyLinkWithValue = v default: - return util.ErrBadInput(fmt.Sprintf("invalid property link value format: %q", raw.Format)) + return util.ErrBadInput("could not determine property link value type") } - return nil } type WrappedPropertyLinkWithValue interface{ isPropertyLinkWithValue() } type TextPropertyLinkValue struct { - Key string `json:"key" example:"description"` - Format PropertyFormat `json:"format" enums:"text"` - Text string `json:"text" example:"Some text..."` // The text value of the property + Key string `json:"key" example:"description"` + Text string `json:"text" example:"Some text..."` // The text value of the property } func (TextPropertyLinkValue) isPropertyLinkWithValue() {} type NumberPropertyLinkValue struct { - Key string `json:"key" example:"height"` - Format PropertyFormat `json:"format" enums:"number"` - Number *float64 `json:"number" example:"42"` // The number value of the property + Key string `json:"key" example:"height"` + Number *float64 `json:"number" example:"42"` // The number value of the property } func (NumberPropertyLinkValue) isPropertyLinkWithValue() {} type SelectPropertyLinkValue struct { - Key string `json:"key" example:"status"` - Format PropertyFormat `json:"format" enums:"select"` - Select *string `json:"select,omitempty"` // The selected tag value of the property + Key string `json:"key" example:"status"` + Select *string `json:"select,omitempty" example:"tag_id"` // The selected tag id of the property; see ListTags endpoint for valid values } func (SelectPropertyLinkValue) isPropertyLinkWithValue() {} type MultiSelectPropertyLinkValue struct { - Key string `json:"key" example:"tag"` - Format PropertyFormat `json:"format" enums:"multi_select"` - MultiSelect []string `json:"multi_select,omitempty"` // The selected tag values of the property + Key string `json:"key" example:"tag"` + MultiSelect []string `json:"multi_select,omitempty" example:"['tag_id']"` // The selected tag ids of the property; see ListTags endpoint for valid values } func (MultiSelectPropertyLinkValue) isPropertyLinkWithValue() {} type DatePropertyLinkValue struct { - Key string `json:"key" example:"last_modified_date"` - Format PropertyFormat `json:"format" enums:"date"` - Date *string `json:"date" example:"2025-02-14T12:34:56Z"` // The date value of the property + Key string `json:"key" example:"last_modified_date"` + Date *string `json:"date" example:"2025-02-14T12:34:56Z"` // The date value of the property } func (DatePropertyLinkValue) isPropertyLinkWithValue() {} type FilesPropertyLinkValue struct { - Key string `json:"key" example:"files"` - Format PropertyFormat `json:"format" enums:"files"` - Files []string `json:"files" example:"['fileId']"` // The file values of the property + Key string `json:"key" example:"files"` + Files []string `json:"files" example:"['file_id']"` // The file ids of the property } func (FilesPropertyLinkValue) isPropertyLinkWithValue() {} type CheckboxPropertyLinkValue struct { - Key string `json:"key" example:"done"` - Format PropertyFormat `json:"format" enums:"checkbox"` - Checkbox bool `json:"checkbox" example:"true"` // The checkbox value of the property + Key string `json:"key" example:"done"` + Checkbox bool `json:"checkbox" example:"true"` // The checkbox value of the property } func (CheckboxPropertyLinkValue) isPropertyLinkWithValue() {} type URLPropertyLinkValue struct { - Key string `json:"key" example:"source"` - Format PropertyFormat `json:"format" enums:"url"` - Url string `json:"url" example:"https://example.com"` // The URL value of the property + Key string `json:"key" example:"source"` + Url string `json:"url" example:"https://example.com"` // The URL value of the property } func (URLPropertyLinkValue) isPropertyLinkWithValue() {} type EmailPropertyLinkValue struct { - Key string `json:"key" example:"email"` - Format PropertyFormat `json:"format" enums:"email"` - Email string `json:"email" example:"example@example.com"` // The email value of the property + Key string `json:"key" example:"email"` + Email string `json:"email" example:"example@example.com"` // The email value of the property } func (EmailPropertyLinkValue) isPropertyLinkWithValue() {} type PhonePropertyLinkValue struct { - Key string `json:"key" example:"phone"` - Format PropertyFormat `json:"format" enums:"phone"` - Phone string `json:"phone" example:"+1234567890"` // The phone value of the property + Key string `json:"key" example:"phone"` + Phone string `json:"phone" example:"+1234567890"` // The phone value of the property } func (PhonePropertyLinkValue) isPropertyLinkWithValue() {} type ObjectsPropertyLinkValue struct { - Key string `json:"key" example:"creator"` - Format PropertyFormat `json:"format" enums:"objects"` - Objects []string `json:"objects" example:"['objectId']"` // The object values of the property + Key string `json:"key" example:"creator"` + Objects []string `json:"objects" example:"['object_id']"` // The object ids of the property } func (ObjectsPropertyLinkValue) isPropertyLinkWithValue() {} diff --git a/core/api/model/search.go b/core/api/model/search.go index 717752586..eb3207b6e 100644 --- a/core/api/model/search.go +++ b/core/api/model/search.go @@ -1,5 +1,12 @@ package apimodel +import ( + "encoding/json" + "fmt" + + "github.com/anyproto/anytype-heart/core/api/util" +) + type SortDirection string const ( @@ -7,6 +14,20 @@ const ( Desc SortDirection = "desc" ) +func (sd *SortDirection) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + switch SortDirection(s) { + case Asc, Desc: + *sd = SortDirection(s) + return nil + default: + return util.ErrBadInput(fmt.Sprintf("invalid sort direction: %q", s)) + } +} + type SortProperty string const ( @@ -16,13 +37,27 @@ const ( Name SortProperty = "name" ) +func (sp *SortProperty) UnmarshalJSON(data []byte) error { + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + switch SortProperty(s) { + case CreatedDate, LastModifiedDate, LastOpenedDate, Name: + *sp = SortProperty(s) + return nil + default: + return util.ErrBadInput(fmt.Sprintf("invalid sort property: %q", s)) + } +} + type SearchRequest struct { - Query string `json:"query" example:"test"` // The search term to look for in object names and snippets - Types []string `json:"types" example:"page,678043f0cda9133be777049f,bafyreightzrdts2ymxyaeyzspwdfo2juspyam76ewq6qq7ixnw3523gs7q"` // The types of objects to search for, specified by key or ID - Sort SortOptions `json:"sort"` // The sorting criteria and direction for the search results + Query string `json:"query" example:"test"` // The text to search within object names and content; use types field for type filtering + Types []string `json:"types" example:"page,task,bookmark"` // The types of objects to include in results (e.g., "page", "task", "bookmark"); see ListTypes endpoint for valid values + Sort SortOptions `json:"sort"` // The sorting options for the search results } type SortOptions struct { - PropertyKey SortProperty `json:"property_key" enums:"created_date,last_modified_date,last_opened_date,name" default:"last_modified_date"` // The property to sort the search results by - Direction SortDirection `json:"direction" enums:"asc,desc" default:"desc"` // The direction to sort the search results + PropertyKey SortProperty `json:"property_key" enums:"created_date,last_modified_date,last_opened_date,name" default:"last_modified_date"` // The key of the property to sort the search results by + Direction SortDirection `json:"direction" enums:"asc,desc" default:"desc"` // The direction to sort the search results by } diff --git a/core/api/model/type.go b/core/api/model/type.go index a0e5a4d65..1dca6233d 100644 --- a/core/api/model/type.go +++ b/core/api/model/type.go @@ -35,29 +35,33 @@ type TypeResponse struct { } type CreateTypeRequest struct { - Name string `json:"name" binding:"required" example:"Page"` // The name of the type - PluralName string `json:"plural_name" example:"Pages"` // The plural name of the type - Icon Icon `json:"icon" oneOf:"EmojiIcon,FileIcon,NamedIcon"` // The icon of the type - Layout TypeLayout `json:"layout" binding:"required" example:"basic"` // The layout of the type - Properties []PropertyLink `json:"properties"` // ⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties linked to the type + Key string `json:"key" example:"some_user_defined_type_key"` // The key of the type; should always be snake_case, otherwise it will be converted to snake_case + Name string `json:"name" binding:"required" example:"Page"` // The name of the type + PluralName string `json:"plural_name" binding:"required" example:"Pages"` // The plural name of the type + Icon Icon `json:"icon" oneOf:"EmojiIcon,FileIcon,NamedIcon"` // The icon of the type + Layout TypeLayout `json:"layout" binding:"required" enums:"basic,profile,action,note"` // The layout of the type + Properties []PropertyLink `json:"properties"` // ⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties linked to the type } type UpdateTypeRequest struct { + Key *string `json:"key,omitempty" example:"some_user_defined_type_key"` // The key to set for the type; should always be snake_case, otherwise it will be converted to snake_case Name *string `json:"name,omitempty" example:"Page"` // The name to set for the type PluralName *string `json:"plural_name,omitempty" example:"Pages"` // The plural name to set for the type Icon *Icon `json:"icon,omitempty" oneOf:"EmojiIcon,FileIcon,NamedIcon"` // The icon to set for the type - Layout *TypeLayout `json:"layout,omitempty" example:"basic"` // The layout to set for the type + Layout *TypeLayout `json:"layout,omitempty" enums:"basic,profile,action,note"` // The layout to set for the type Properties *[]PropertyLink `json:"properties,omitempty"` // ⚠ Warning: Properties are experimental and may change in the next update. ⚠ The properties to set for the type } type Type struct { - Object string `json:"object" example:"type"` // The data model of the object - Id string `json:"id" example:"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu"` // The id of the type (which is unique across spaces) - Key string `json:"key" example:"page"` // The key of the type (can be the same across spaces for known types) - Name string `json:"name" example:"Page"` // The name of the type - PluralName string `json:"plural_name" example:"Pages"` // The plural name of the type - Icon Icon `json:"icon" oneOf:"EmojiIcon,FileIcon,NamedIcon"` // The icon of the type - Archived bool `json:"archived" example:"false"` // Whether the type is archived - Layout ObjectLayout `json:"layout" example:"basic"` // The layout of the type - Properties []Property `json:"properties"` // The properties linked to the type + Object string `json:"object" example:"type"` // The data model of the object + Id string `json:"id" example:"bafyreigyb6l5szohs32ts26ku2j42yd65e6hqy2u3gtzgdwqv6hzftsetu"` // The id of the type (which is unique across spaces) + Key string `json:"key" example:"page"` // The key of the type (can be the same across spaces for known types) + Name string `json:"name" example:"Page"` // The name of the type + PluralName string `json:"plural_name" example:"Pages"` // The plural name of the type + Icon Icon `json:"icon" oneOf:"EmojiIcon,FileIcon,NamedIcon"` // The icon of the type + Archived bool `json:"archived" example:"false"` // Whether the type is archived + Layout ObjectLayout `json:"layout" enums:"basic,profile,action,note,bookmark,set,set,collection,participant"` // The layout of the type + Properties []Property `json:"properties"` // The properties linked to the type + // Uk is internal-only to simplify lookup on entry, won't be serialized to type responses + UniqueKey string `json:"-" swaggerignore:"true"` } diff --git a/core/api/server/middleware.go b/core/api/server/middleware.go index 880fef86e..f93285a8b 100644 --- a/core/api/server/middleware.go +++ b/core/api/server/middleware.go @@ -12,10 +12,14 @@ import ( apicore "github.com/anyproto/anytype-heart/core/api/core" "github.com/anyproto/anytype-heart/core/api/util" + "github.com/anyproto/anytype-heart/core/event" "github.com/anyproto/anytype-heart/pb" + "github.com/anyproto/anytype-heart/pkg/lib/logging" ) -const ApiVersion = "2025-04-22" +const ApiVersion = "2025-05-20" + +var log = logging.Logger("api-server") var ( ErrMissingAuthorizationHeader = errors.New("missing authorization header") @@ -23,17 +27,21 @@ var ( ErrInvalidToken = errors.New("invalid token") ) -// rateLimit is a middleware that limits the number of requests per second. -func (s *Server) rateLimit(max float64) gin.HandlerFunc { - lmt := tollbooth.NewLimiter(max, nil) +// ensureRateLimit creates a shared write-rate limiter middleware. +func ensureRateLimit(rate float64, burst int, isRateLimitDisabled bool) gin.HandlerFunc { + lmt := tollbooth.NewLimiter(rate, nil) + lmt.SetBurst(burst) lmt.SetIPLookup(limiter.IPLookup{ Name: "RemoteAddr", IndexFromRight: 0, }) return func(c *gin.Context) { - httpError := tollbooth.LimitByRequest(lmt, c.Writer, c.Request) - if httpError != nil { + if isRateLimitDisabled { + c.Next() + return + } + if httpError := tollbooth.LimitByRequest(lmt, c.Writer, c.Request); httpError != nil { apiErr := util.CodeToAPIError(httpError.StatusCode, httpError.Message) c.AbortWithStatusJSON(httpError.StatusCode, apiErr) return @@ -62,7 +70,7 @@ func (s *Server) ensureAuthenticated(mw apicore.ClientCommands) gin.HandlerFunc // Validate the key - if the key exists in the KeyToToken map, it is considered valid. // Otherwise, attempt to create a new session using the key and add it to the map upon successful validation. s.mu.Lock() - token, exists := s.KeyToToken[key] + apiSession, exists := s.KeyToToken[key] s.mu.Unlock() if !exists { @@ -72,19 +80,44 @@ func (s *Server) ensureAuthenticated(mw apicore.ClientCommands) gin.HandlerFunc c.AbortWithStatusJSON(http.StatusUnauthorized, apiErr) return } - token = response.Token + apiSession = ApiSessionEntry{ + Token: response.Token, + // TODO: enable once app name is returned + // AppName: response.AppName, + } s.mu.Lock() - s.KeyToToken[key] = token + s.KeyToToken[key] = apiSession s.mu.Unlock() } // Add token to request context for downstream services (subscriptions, events, etc.) - c.Set("token", token) + c.Set("token", apiSession.Token) + c.Set("apiAppName", apiSession.AppName) c.Next() } } +// ensureAnalyticsEvent is a middleware that ensures broadcasting an analytics event after a successful request. +func (s *Server) ensureAnalyticsEvent(code string, eventService apicore.EventService) gin.HandlerFunc { + return func(c *gin.Context) { + c.Next() + + status := c.Writer.Status() + payload, err := util.NewAnalyticsEventForApi(c.Request.Context(), code, status) + if err != nil { + log.Errorf("failed to create api analytics event: %v", err) + return + } + + eventService.Broadcast(event.NewEventSingleMessage("", &pb.EventMessageValueOfPayloadBroadcast{ + PayloadBroadcast: &pb.EventPayloadBroadcast{ + Payload: payload, + }, + })) + } +} + // ensureMetadataHeader is a middleware that ensures the metadata header is set. func (s *Server) ensureMetadataHeader() gin.HandlerFunc { return func(c *gin.Context) { diff --git a/core/api/server/middleware_test.go b/core/api/server/middleware_test.go index c62968bd4..b3da083c0 100644 --- a/core/api/server/middleware_test.go +++ b/core/api/server/middleware_test.go @@ -34,7 +34,7 @@ func TestEnsureAuthenticated(t *testing.T) { t.Run("missing auth header", func(t *testing.T) { // given fx := newFixture(t) - fx.KeyToToken = make(map[string]string) + fx.KeyToToken = make(map[string]ApiSessionEntry) middleware := fx.ensureAuthenticated(fx.mwMock) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) @@ -54,7 +54,7 @@ func TestEnsureAuthenticated(t *testing.T) { t.Run("invalid auth header format", func(t *testing.T) { // given fx := newFixture(t) - fx.KeyToToken = make(map[string]string) + fx.KeyToToken = make(map[string]ApiSessionEntry) middleware := fx.ensureAuthenticated(fx.mwMock) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) @@ -75,7 +75,7 @@ func TestEnsureAuthenticated(t *testing.T) { t.Run("valid token creation", func(t *testing.T) { // given fx := newFixture(t) - fx.KeyToToken = make(map[string]string) + fx.KeyToToken = make(map[string]ApiSessionEntry) tokenExpected := "valid-token" fx.mwMock. @@ -108,7 +108,7 @@ func TestEnsureAuthenticated(t *testing.T) { t.Run("invalid token", func(t *testing.T) { // given fx := newFixture(t) - fx.KeyToToken = make(map[string]string) + fx.KeyToToken = make(map[string]ApiSessionEntry) middleware := fx.ensureAuthenticated(fx.mwMock) w := httptest.NewRecorder() c, _ := gin.CreateTestContext(w) @@ -139,9 +139,8 @@ func TestEnsureAuthenticated(t *testing.T) { } func TestRateLimit(t *testing.T) { - fx := newFixture(t) router := gin.New() - router.GET("/", fx.rateLimit(1), func(c *gin.Context) { + router.GET("/", ensureRateLimit(1, 1, false), func(c *gin.Context) { c.String(http.StatusOK, "OK") }) @@ -170,4 +169,51 @@ func TestRateLimit(t *testing.T) { // then require.Equal(t, http.StatusTooManyRequests, w.Code) }) + + t.Run("burst of size 2 allows two requests", func(t *testing.T) { + burstRouter := gin.New() + burstRouter.GET("/", ensureRateLimit(1, 2, false), func(c *gin.Context) { + c.String(http.StatusOK, "OK") + }) + + // first request (within burst) + w1 := httptest.NewRecorder() + req1 := httptest.NewRequest("GET", "/", nil) + req1.RemoteAddr = "1.2.3.4:5678" + burstRouter.ServeHTTP(w1, req1) + require.Equal(t, http.StatusOK, w1.Code) + + // second request (within burst) + w2 := httptest.NewRecorder() + req2 := httptest.NewRequest("GET", "/", nil) + req2.RemoteAddr = "1.2.3.4:5678" + burstRouter.ServeHTTP(w2, req2) + require.Equal(t, http.StatusOK, w2.Code) + + // third request should be rate-limited + w3 := httptest.NewRecorder() + req3 := httptest.NewRequest("GET", "/", nil) + req3.RemoteAddr = "1.2.3.4:5678" + burstRouter.ServeHTTP(w3, req3) + require.Equal(t, http.StatusTooManyRequests, w3.Code) + }) + + t.Run("disabled rate limit allows all requests", func(t *testing.T) { + // given + disabledRouter := gin.New() + disabledRouter.GET("/", ensureRateLimit(1, 1, true), func(c *gin.Context) { + c.String(http.StatusOK, "OK") + }) + + // when + for i := 0; i < 5; i++ { + w := httptest.NewRecorder() + req := httptest.NewRequest("GET", "/", nil) + req.RemoteAddr = "1.2.3.4:5678" + disabledRouter.ServeHTTP(w, req) + + // then + require.Equal(t, http.StatusOK, w.Code) + } + }) } diff --git a/core/api/server/router.go b/core/api/server/router.go index 59323025b..1f2a56a39 100644 --- a/core/api/server/router.go +++ b/core/api/server/router.go @@ -9,7 +9,6 @@ import ( apicore "github.com/anyproto/anytype-heart/core/api/core" _ "github.com/anyproto/anytype-heart/core/api/docs" "github.com/anyproto/anytype-heart/core/api/handler" - "github.com/anyproto/anytype-heart/core/api/pagination" ) @@ -18,13 +17,15 @@ const ( defaultPageSize = 100 minPageSize = 1 maxPageSize = 1000 - maxWriteRequestsPerSecond = 1 + maxWriteRequestsPerSecond = 1 // allow sustained 1 request per second + maxBurstRequests = 60 // allow all requests in the first second ) // NewRouter builds and returns a *gin.Engine with all routes configured. -func (s *Server) NewRouter(mw apicore.ClientCommands) *gin.Engine { - debug := os.Getenv("ANYTYPE_API_DEBUG") == "1" - if !debug { + +func (s *Server) NewRouter(mw apicore.ClientCommands, eventService apicore.EventService, openapiYAML []byte, openapiJSON []byte) *gin.Engine { + isDebug := os.Getenv("ANYTYPE_API_DEBUG") == "1" + if !isDebug { gin.SetMode(gin.ReleaseMode) } @@ -32,9 +33,10 @@ func (s *Server) NewRouter(mw apicore.ClientCommands) *gin.Engine { router.Use(gin.Recovery()) router.Use(s.ensureMetadataHeader()) - if debug { + if isDebug { router.Use(gin.Logger()) } + paginator := pagination.New(pagination.Config{ DefaultPage: defaultPage, DefaultPageSize: defaultPageSize, @@ -42,17 +44,34 @@ func (s *Server) NewRouter(mw apicore.ClientCommands) *gin.Engine { MaxPageSize: maxPageSize, }) + // Shared ratelimiter with option to disable it through env var + isRateLimitDisabled := os.Getenv("ANYTYPE_API_DISABLE_RATE_LIMIT") == "1" + writeRateLimitMW := ensureRateLimit(maxWriteRequestsPerSecond, maxBurstRequests, isRateLimitDisabled) + // Swagger route router.GET("/swagger/*any", func(c *gin.Context) { target := "https://developers.anytype.io/docs/reference" c.Redirect(http.StatusMovedPermanently, target) }) + router.GET("/docs/openapi.yaml", func(c *gin.Context) { + c.Data(http.StatusOK, "application/x-yaml", openapiYAML) + }) + + router.GET("/docs/openapi.json", func(c *gin.Context) { + c.Data(http.StatusOK, "application/json", openapiJSON) + }) + // Auth routes (no authentication required) - authGroup := router.Group("/v1/auth") + authGroup := router.Group("/v1") { - authGroup.POST("/display_code", handler.DisplayCodeHandler(s.service)) - authGroup.POST("/token", handler.TokenHandler(s.service)) + // TO BE DEPRECATED + authGroup.POST("/auth/display_code", handler.DisplayCodeHandler(s.service)) + // TO BE DEPRECATED + authGroup.POST("/auth/token", handler.TokenHandler(s.service)) + + authGroup.POST("/auth/challenges", handler.CreateChallengeHandler(s.service)) + authGroup.POST("/auth/api_keys", handler.CreateApiKeyHandler(s.service)) } // API routes @@ -62,63 +81,63 @@ func (s *Server) NewRouter(mw apicore.ClientCommands) *gin.Engine { { // Block // TODO: implement create, update and delete block endpoints - // v1.POST("/spaces/:space_id/objects/:object_id/blocks", s.rateLimit(maxWriteRequestsPerSecond), object.CreateBlockHandler(s.service)) - // v1.PATCH("/spaces/:space_id/objects/:object_id/blocks/:block_id", s.rateLimit(maxWriteRequestsPerSecond), object.UpdateBlockHandler(s.service)) - // v1.DELETE("/spaces/:space_id/objects/:object_id/blocks/:block_id", s.rateLimit(maxWriteRequestsPerSecond), object.DeleteBlockHandler(s.service)) + // v1.POST("/spaces/:space_id/objects/:object_id/blocks", writeRateLimitMW, object.CreateBlockHandler(s.service)) + // v1.PATCH("/spaces/:space_id/objects/:object_id/blocks/:block_id", writeRateLimitMW, object.UpdateBlockHandler(s.service)) + // v1.DELETE("/spaces/:space_id/objects/:object_id/blocks/:block_id", writeRateLimitMW, object.DeleteBlockHandler(s.service)) // List - v1.GET("/spaces/:space_id/lists/:list_id/views", handler.GetListViewsHandler(s.service)) - v1.GET("/spaces/:space_id/lists/:list_id/:view_id/objects", handler.GetObjectsInListHandler(s.service)) - v1.POST("/spaces/:space_id/lists/:list_id/objects", s.rateLimit(maxWriteRequestsPerSecond), handler.AddObjectsToListHandler(s.service)) - v1.DELETE("/spaces/:space_id/lists/:list_id/objects/:object_id", s.rateLimit(maxWriteRequestsPerSecond), handler.RemoveObjectFromListHandler(s.service)) + v1.GET("/spaces/:space_id/lists/:list_id/views", s.ensureAnalyticsEvent("ListGetViews", eventService), handler.GetListViewsHandler(s.service)) + v1.GET("/spaces/:space_id/lists/:list_id/views/:view_id/objects", s.ensureAnalyticsEvent("ListGetObjects", eventService), handler.GetObjectsInListHandler(s.service)) + v1.POST("/spaces/:space_id/lists/:list_id/objects", writeRateLimitMW, s.ensureAnalyticsEvent("ListAddObject", eventService), handler.AddObjectsToListHandler(s.service)) + v1.DELETE("/spaces/:space_id/lists/:list_id/objects/:object_id", writeRateLimitMW, s.ensureAnalyticsEvent("ListRemoveObject", eventService), handler.RemoveObjectFromListHandler(s.service)) // Member - v1.GET("/spaces/:space_id/members", handler.ListMembersHandler(s.service)) - v1.GET("/spaces/:space_id/members/:member_id", handler.GetMemberHandler(s.service)) + v1.GET("/spaces/:space_id/members", s.ensureAnalyticsEvent("MemberList", eventService), handler.ListMembersHandler(s.service)) + v1.GET("/spaces/:space_id/members/:member_id", s.ensureAnalyticsEvent("MemberOpen", eventService), handler.GetMemberHandler(s.service)) // TODO: renable when granular permissions are implementeds - // v1.PATCH("/spaces/:space_id/members/:member_id", s.rateLimit(maxWriteRequestsPerSecond), space.UpdateMemberHandler(s.service)) + // v1.PATCH("/spaces/:space_id/members/:member_id", writeRateLimitMW, space.UpdateMemberHandler(s.service)) // Object - v1.GET("/spaces/:space_id/objects", handler.ListObjectsHandler(s.service)) - v1.GET("/spaces/:space_id/objects/:object_id", handler.GetObjectHandler(s.service)) - v1.POST("/spaces/:space_id/objects", s.rateLimit(maxWriteRequestsPerSecond), handler.CreateObjectHandler(s.service)) - v1.PATCH("/spaces/:space_id/objects/:object_id", s.rateLimit(maxWriteRequestsPerSecond), handler.UpdateObjectHandler(s.service)) - v1.DELETE("/spaces/:space_id/objects/:object_id", s.rateLimit(maxWriteRequestsPerSecond), handler.DeleteObjectHandler(s.service)) + v1.GET("/spaces/:space_id/objects", s.ensureAnalyticsEvent("ObjectList", eventService), handler.ListObjectsHandler(s.service)) + v1.GET("/spaces/:space_id/objects/:object_id", s.ensureAnalyticsEvent("ObjectOpen", eventService), handler.GetObjectHandler(s.service)) + v1.POST("/spaces/:space_id/objects", writeRateLimitMW, s.ensureAnalyticsEvent("ObjectCreate", eventService), handler.CreateObjectHandler(s.service)) + v1.PATCH("/spaces/:space_id/objects/:object_id", writeRateLimitMW, s.ensureAnalyticsEvent("ObjectUpdate", eventService), handler.UpdateObjectHandler(s.service)) + v1.DELETE("/spaces/:space_id/objects/:object_id", writeRateLimitMW, s.ensureAnalyticsEvent("ObjectDelete", eventService), handler.DeleteObjectHandler(s.service)) // Property - v1.GET("/spaces/:space_id/properties", handler.ListPropertiesHandler(s.service)) - v1.GET("/spaces/:space_id/properties/:property_id", handler.GetPropertyHandler(s.service)) - v1.POST("/spaces/:space_id/properties", s.rateLimit(maxWriteRequestsPerSecond), handler.CreatePropertyHandler(s.service)) - v1.PATCH("/spaces/:space_id/properties/:property_id", s.rateLimit(maxWriteRequestsPerSecond), handler.UpdatePropertyHandler(s.service)) - v1.DELETE("/spaces/:space_id/properties/:property_id", s.rateLimit(maxWriteRequestsPerSecond), handler.DeletePropertyHandler(s.service)) + v1.GET("/spaces/:space_id/properties", s.ensureAnalyticsEvent("PropertyList", eventService), handler.ListPropertiesHandler(s.service)) + v1.GET("/spaces/:space_id/properties/:property_id", s.ensureAnalyticsEvent("PropertyOpen", eventService), handler.GetPropertyHandler(s.service)) + v1.POST("/spaces/:space_id/properties", writeRateLimitMW, s.ensureAnalyticsEvent("PropertyCreate", eventService), handler.CreatePropertyHandler(s.service)) + v1.PATCH("/spaces/:space_id/properties/:property_id", writeRateLimitMW, s.ensureAnalyticsEvent("PropertyUpdate", eventService), handler.UpdatePropertyHandler(s.service)) + v1.DELETE("/spaces/:space_id/properties/:property_id", writeRateLimitMW, s.ensureAnalyticsEvent("PropertyDelete", eventService), handler.DeletePropertyHandler(s.service)) // Search - v1.POST("/search", handler.GlobalSearchHandler(s.service)) - v1.POST("/spaces/:space_id/search", handler.SearchHandler(s.service)) + v1.POST("/search", s.ensureAnalyticsEvent("SearchGlobal", eventService), handler.GlobalSearchHandler(s.service)) + v1.POST("/spaces/:space_id/search", s.ensureAnalyticsEvent("SearchSpace", eventService), handler.SearchHandler(s.service)) // Space - v1.GET("/spaces", handler.ListSpacesHandler(s.service)) - v1.GET("/spaces/:space_id", handler.GetSpaceHandler(s.service)) - v1.POST("/spaces", s.rateLimit(maxWriteRequestsPerSecond), handler.CreateSpaceHandler(s.service)) - v1.PATCH("/spaces/:space_id", s.rateLimit(maxWriteRequestsPerSecond), handler.UpdateSpaceHandler(s.service)) + v1.GET("/spaces", s.ensureAnalyticsEvent("SpaceList", eventService), handler.ListSpacesHandler(s.service)) + v1.GET("/spaces/:space_id", s.ensureAnalyticsEvent("SpaceOpen", eventService), handler.GetSpaceHandler(s.service)) + v1.POST("/spaces", writeRateLimitMW, s.ensureAnalyticsEvent("SpaceCreate", eventService), handler.CreateSpaceHandler(s.service)) + v1.PATCH("/spaces/:space_id", writeRateLimitMW, s.ensureAnalyticsEvent("SpaceUpdate", eventService), handler.UpdateSpaceHandler(s.service)) // Tag - v1.GET("/spaces/:space_id/properties/:property_id/tags", handler.ListTagsHandler(s.service)) - v1.GET("/spaces/:space_id/properties/:property_id/tags/:tag_id", handler.GetTagHandler(s.service)) - v1.POST("/spaces/:space_id/properties/:property_id/tags", s.rateLimit(maxWriteRequestsPerSecond), handler.CreateTagHandler(s.service)) - v1.PATCH("/spaces/:space_id/properties/:property_id/tags/:tag_id", s.rateLimit(maxWriteRequestsPerSecond), handler.UpdateTagHandler(s.service)) - v1.DELETE("/spaces/:space_id/properties/:property_id/tags/:tag_id", s.rateLimit(maxWriteRequestsPerSecond), handler.DeleteTagHandler(s.service)) + v1.GET("/spaces/:space_id/properties/:property_id/tags", s.ensureAnalyticsEvent("TagList", eventService), handler.ListTagsHandler(s.service)) + v1.GET("/spaces/:space_id/properties/:property_id/tags/:tag_id", s.ensureAnalyticsEvent("TagOpen", eventService), handler.GetTagHandler(s.service)) + v1.POST("/spaces/:space_id/properties/:property_id/tags", writeRateLimitMW, s.ensureAnalyticsEvent("TagCreate", eventService), handler.CreateTagHandler(s.service)) + v1.PATCH("/spaces/:space_id/properties/:property_id/tags/:tag_id", writeRateLimitMW, s.ensureAnalyticsEvent("TagUpdate", eventService), handler.UpdateTagHandler(s.service)) + v1.DELETE("/spaces/:space_id/properties/:property_id/tags/:tag_id", writeRateLimitMW, s.ensureAnalyticsEvent("TagDelete", eventService), handler.DeleteTagHandler(s.service)) // Template - v1.GET("/spaces/:space_id/types/:type_id/templates", handler.ListTemplatesHandler(s.service)) - v1.GET("/spaces/:space_id/types/:type_id/templates/:template_id", handler.GetTemplateHandler(s.service)) + v1.GET("/spaces/:space_id/types/:type_id/templates", s.ensureAnalyticsEvent("TemplateList", eventService), handler.ListTemplatesHandler(s.service)) + v1.GET("/spaces/:space_id/types/:type_id/templates/:template_id", s.ensureAnalyticsEvent("TemplateOpen", eventService), handler.GetTemplateHandler(s.service)) // Type - v1.GET("/spaces/:space_id/types", handler.ListTypesHandler(s.service)) - v1.GET("/spaces/:space_id/types/:type_id", handler.GetTypeHandler(s.service)) - v1.POST("/spaces/:space_id/types", s.rateLimit(maxWriteRequestsPerSecond), handler.CreateTypeHandler(s.service)) - v1.PATCH("/spaces/:space_id/types/:type_id", s.rateLimit(maxWriteRequestsPerSecond), handler.UpdateTypeHandler(s.service)) - v1.DELETE("/spaces/:space_id/types/:type_id", s.rateLimit(maxWriteRequestsPerSecond), handler.DeleteTypeHandler(s.service)) + v1.GET("/spaces/:space_id/types", s.ensureAnalyticsEvent("TypeList", eventService), handler.ListTypesHandler(s.service)) + v1.GET("/spaces/:space_id/types/:type_id", s.ensureAnalyticsEvent("TypeOpen", eventService), handler.GetTypeHandler(s.service)) + v1.POST("/spaces/:space_id/types", writeRateLimitMW, s.ensureAnalyticsEvent("TypeCreate", eventService), handler.CreateTypeHandler(s.service)) + v1.PATCH("/spaces/:space_id/types/:type_id", writeRateLimitMW, s.ensureAnalyticsEvent("TypeUpdate", eventService), handler.UpdateTypeHandler(s.service)) + v1.DELETE("/spaces/:space_id/types/:type_id", writeRateLimitMW, s.ensureAnalyticsEvent("TypeDelete", eventService), handler.DeleteTypeHandler(s.service)) } return router diff --git a/core/api/server/router_test.go b/core/api/server/router_test.go index cbea76934..427b805c3 100644 --- a/core/api/server/router_test.go +++ b/core/api/server/router_test.go @@ -16,7 +16,7 @@ func TestRouter_Unauthenticated(t *testing.T) { t.Run("GET /v1/spaces without auth returns 401", func(t *testing.T) { // given fx := newFixture(t) - engine := fx.NewRouter(fx.mwMock) + engine := fx.NewRouter(fx.mwMock, &fx.eventService, []byte{}, []byte{}) w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/v1/spaces", nil) @@ -32,7 +32,7 @@ func TestRouter_AuthRoute(t *testing.T) { t.Run("POST /v1/auth/token is accessible without auth", func(t *testing.T) { // given fx := newFixture(t) - engine := fx.NewRouter(fx.mwMock) + engine := fx.NewRouter(fx.mwMock, &fx.eventService, []byte{}, []byte{}) w := httptest.NewRecorder() req := httptest.NewRequest("POST", "/v1/auth/token", nil) @@ -48,13 +48,14 @@ func TestRouter_MetadataHeader(t *testing.T) { t.Run("Response includes Anytype-Version header", func(t *testing.T) { // given fx := newFixture(t) - engine := fx.NewRouter(fx.mwMock) - fx.KeyToToken = map[string]string{"validKey": "dummyToken"} + engine := fx.NewRouter(fx.mwMock, &fx.eventService, []byte{}, []byte{}) + fx.KeyToToken = map[string]ApiSessionEntry{"validKey": {Token: "dummyToken", AppName: "dummyApp"}} fx.mwMock.On("ObjectSearch", mock.Anything, mock.Anything). Return(&pb.RpcObjectSearchResponse{ Records: []*types.Struct{}, Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, }, nil).Once() + fx.eventService.On("Broadcast", mock.Anything).Return(nil).Maybe() w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/v1/spaces", nil) @@ -64,6 +65,6 @@ func TestRouter_MetadataHeader(t *testing.T) { engine.ServeHTTP(w, req) // then - require.Equal(t, "2025-04-22", w.Header().Get("Anytype-Version")) + require.Equal(t, "2025-05-20", w.Header().Get("Anytype-Version")) }) } diff --git a/core/api/server/server.go b/core/api/server/server.go index 8eb3a8b40..e2c1f07a5 100644 --- a/core/api/server/server.go +++ b/core/api/server/server.go @@ -10,25 +10,30 @@ import ( "github.com/anyproto/anytype-heart/core/api/service" ) +type ApiSessionEntry struct { + Token string `json:"token"` + AppName string `json:"appName"` +} + // Server wraps the HTTP server and service logic. type Server struct { engine *gin.Engine service *service.Service mu sync.Mutex - KeyToToken map[string]string // appKey -> token + KeyToToken map[string]ApiSessionEntry // appKey -> token } -// NewServer constructs a new Server with default config and sets up the routes. -func NewServer(mw apicore.ClientCommands, accountService apicore.AccountService, exportService apicore.ExportService) *Server { +// NewServer constructs a new Server with the default config and sets up the routes. +func NewServer(mw apicore.ClientCommands, accountService apicore.AccountService, eventService apicore.EventService, openapiYAML []byte, openapiJSON []byte) *Server { gatewayUrl, techSpaceId, err := getAccountInfo(accountService) if err != nil { panic(err) } - s := &Server{service: service.NewService(mw, exportService, gatewayUrl, techSpaceId)} - s.engine = s.NewRouter(mw) - s.KeyToToken = make(map[string]string) + s := &Server{service: service.NewService(mw, gatewayUrl, techSpaceId)} + s.engine = s.NewRouter(mw, eventService, openapiYAML, openapiJSON) + s.KeyToToken = make(map[string]ApiSessionEntry) return s } diff --git a/core/api/server/server_test.go b/core/api/server/server_test.go index 7f28fdb6f..d6e455e02 100644 --- a/core/api/server/server_test.go +++ b/core/api/server/server_test.go @@ -18,18 +18,19 @@ const ( type fixture struct { *Server - mwMock *mock_apicore.MockClientCommands + eventService mock_apicore.MockEventService + mwMock *mock_apicore.MockClientCommands } func newFixture(t *testing.T) *fixture { mwMock := mock_apicore.NewMockClientCommands(t) accountService := mock_apicore.NewMockAccountService(t) - exportService := mock_apicore.NewMockExportService(t) + eventService := mock_apicore.NewMockEventService(t) accountService.On("GetInfo", mock.Anything).Return(&model.AccountInfo{ GatewayUrl: mockedGatewayUrl, TechSpaceId: mockedTechSpaceId, }, nil).Once() - server := NewServer(mwMock, accountService, exportService) + server := NewServer(mwMock, accountService, eventService, []byte{}, []byte{}) return &fixture{ Server: server, diff --git a/core/api/service.go b/core/api/service.go index 9f43eb7b7..e695124ab 100644 --- a/core/api/service.go +++ b/core/api/service.go @@ -2,6 +2,7 @@ package api import ( "context" + _ "embed" "errors" "fmt" "net/http" @@ -14,7 +15,7 @@ import ( "github.com/anyproto/anytype-heart/core/anytype/config" apicore "github.com/anyproto/anytype-heart/core/api/core" "github.com/anyproto/anytype-heart/core/api/server" - "github.com/anyproto/anytype-heart/core/block/export" + "github.com/anyproto/anytype-heart/core/event" ) const ( @@ -24,6 +25,12 @@ const ( var ( mwSrv apicore.ClientCommands + + //go:embed docs/openapi.yaml + openapiYAML []byte + + //go:embed docs/openapi.json + openapiJSON []byte ) type Service interface { @@ -36,7 +43,7 @@ type apiService struct { httpSrv *http.Server mw apicore.ClientCommands accountService apicore.AccountService - exportService apicore.ExportService + eventService apicore.EventService listenAddr string lock sync.Mutex } @@ -52,8 +59,8 @@ func (s *apiService) Name() (name string) { // Init initializes the API service. // // @title Anytype API -// @version 2025-04-22 -// @description This API empowers seamless interaction with Anytype's resources—spaces, objects, properties, types, templates, and beyond. +// @version 2025-05-20 +// @description This API enables seamless interaction with Anytype's resources - spaces, objects, properties, types, templates, and beyond. // @termsOfService https://anytype.io/terms_of_use // @contact.name Anytype Support // @contact.url https://anytype.io/contact @@ -61,14 +68,13 @@ func (s *apiService) Name() (name string) { // @license.name Any Source Available License 1.0 // @license.url https://github.com/anyproto/anytype-api/blob/main/LICENSE.md // @host http://localhost:31009 -// @BasePath /v1 // @securitydefinitions.bearerauth BearerAuth // @externalDocs.description OpenAPI // @externalDocs.url https://swagger.io/resources/open-api/ func (s *apiService) Init(a *app.App) (err error) { s.listenAddr = a.MustComponent(config.CName).(*config.Config).JsonApiListenAddr s.accountService = a.MustComponent(account.CName).(account.Service) - s.exportService = a.MustComponent(export.CName).(apicore.ExportService) + s.eventService = a.MustComponent(event.CName).(apicore.EventService) return nil } @@ -89,7 +95,8 @@ func (s *apiService) runServer() { return } - s.srv = server.NewServer(s.mw, s.accountService, s.exportService) + s.srv = server.NewServer(s.mw, s.accountService, s.eventService, openapiYAML, openapiJSON) + s.httpSrv = &http.Server{ Addr: s.listenAddr, Handler: s.srv.Engine(), diff --git a/core/api/service/auth.go b/core/api/service/auth.go index 46eb8d48c..fd947142e 100644 --- a/core/api/service/auth.go +++ b/core/api/service/auth.go @@ -4,19 +4,19 @@ import ( "context" "errors" + "github.com/anyproto/anytype-heart/core/api/util" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) var ( - ErrMissingAppName = errors.New("missing app name") - ErrFailedGenerateChallenge = errors.New("failed to generate a new challenge") - ErrInvalidInput = errors.New("invalid input") - ErrFailedAuthenticate = errors.New("failed to authenticate user") + ErrMissingAppName = errors.New("missing app name") + ErrFailedCreateNewChallenge = errors.New("failed to create a new challenge") + ErrFailedAuthenticate = errors.New("failed to authenticate user") ) -// NewChallenge calls AccountLocalLinkNewChallenge and returns the challenge ID, or an error if it fails. -func (s *Service) NewChallenge(ctx context.Context, appName string) (string, error) { +// CreateChallenge calls AccountLocalLinkNewChallenge and returns the challenge ID +func (s *Service) CreateChallenge(ctx context.Context, appName string) (string, error) { if appName == "" { return "", ErrMissingAppName } @@ -27,19 +27,18 @@ func (s *Service) NewChallenge(ctx context.Context, appName string) (string, err }) if resp.Error != nil && resp.Error.Code != pb.RpcAccountLocalLinkNewChallengeResponseError_NULL { - return "", ErrFailedGenerateChallenge + return "", ErrFailedCreateNewChallenge } return resp.ChallengeId, nil } -// SolveChallenge calls AccountLocalLinkSolveChallenge and returns the session token + app key, or an error if it fails. +// SolveChallenge calls AccountLocalLinkSolveChallenge and returns the session token + app key func (s *Service) SolveChallenge(ctx context.Context, challengeId string, code string) (appKey string, err error) { if challengeId == "" || code == "" { - return "", ErrInvalidInput + return "", util.ErrBadInput("challenge_id or code is empty") } - // Call AccountLocalLinkSolveChallenge to retrieve session token and app key resp := s.mw.AccountLocalLinkSolveChallenge(ctx, &pb.RpcAccountLocalLinkSolveChallengeRequest{ ChallengeId: challengeId, Answer: code, diff --git a/core/api/service/auth_test.go b/core/api/service/auth_test.go index 10bbe2a75..0d78d54e0 100644 --- a/core/api/service/auth_test.go +++ b/core/api/service/auth_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/anyproto/anytype-heart/core/api/util" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) @@ -34,7 +35,7 @@ func TestAuthService_GenerateNewChallenge(t *testing.T) { }).Once() // when - challengeId, err := fx.service.NewChallenge(ctx, mockedAppName) + challengeId, err := fx.service.CreateChallenge(ctx, mockedAppName) // then require.NoError(t, err) @@ -47,7 +48,7 @@ func TestAuthService_GenerateNewChallenge(t *testing.T) { fx := newFixture(t) // when - challengeId, err := fx.service.NewChallenge(ctx, "") + challengeId, err := fx.service.CreateChallenge(ctx, "") // then require.Error(t, err) @@ -69,11 +70,11 @@ func TestAuthService_GenerateNewChallenge(t *testing.T) { }).Once() // when - challengeId, err := fx.service.NewChallenge(ctx, mockedAppName) + challengeId, err := fx.service.CreateChallenge(ctx, mockedAppName) // then require.Error(t, err) - require.Equal(t, ErrFailedGenerateChallenge, err) + require.Equal(t, ErrFailedCreateNewChallenge, err) require.Empty(t, challengeId) }) } @@ -112,7 +113,7 @@ func TestAuthService_SolveChallengeForToken(t *testing.T) { // then require.Error(t, err) - require.Equal(t, ErrInvalidInput, err) + require.ErrorIs(t, err, util.ErrBad) require.Empty(t, appKey) }) diff --git a/core/api/service/icon.go b/core/api/service/icon.go new file mode 100644 index 000000000..6118b2c85 --- /dev/null +++ b/core/api/service/icon.go @@ -0,0 +1,47 @@ +package service + +import ( + "fmt" + "unicode" + + apimodel "github.com/anyproto/anytype-heart/core/api/model" +) + +func IsEmoji(s string) bool { + if s == "" { + return false + } + for _, r := range s { + if unicode.Is(unicode.Cf, r) || unicode.Is(unicode.Mn, r) || unicode.Is(unicode.So, r) || unicode.Is(unicode.Sk, r) { + continue + } else { + return false + } + } + return true +} + +// GetIcon returns the appropriate Icon implementation. +func GetIcon(gatewayUrl string, iconEmoji string, iconImage string, iconName string, iconOption float64) apimodel.Icon { + if iconName != "" { + return apimodel.Icon{WrappedIcon: apimodel.NamedIcon{ + Format: apimodel.IconFormatIcon, + Name: apimodel.IconName(iconName), + Color: apimodel.IconOptionToColor[iconOption], + }} + } + if iconEmoji != "" { + return apimodel.Icon{WrappedIcon: apimodel.EmojiIcon{ + Format: apimodel.IconFormatEmoji, + Emoji: iconEmoji, + }} + } + if iconImage != "" { + return apimodel.Icon{WrappedIcon: apimodel.FileIcon{ + Format: apimodel.IconFormatFile, + File: fmt.Sprintf("%s/image/%s", gatewayUrl, iconImage), + }} + } + + return apimodel.Icon{} +} diff --git a/core/api/service/icon_test.go b/core/api/service/icon_test.go new file mode 100644 index 000000000..cb907286b --- /dev/null +++ b/core/api/service/icon_test.go @@ -0,0 +1,47 @@ +package service + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestIsEmoji(t *testing.T) { + tests := []struct { + name string + input string + want bool + }{ + // valid single-code-point emoji + {"GrinningFace", "😀", true}, + // yin-yang with variation selector + {"YinYangWithVS", "☯️", true}, + // emoji + skin tone modifier + {"ThumbsUpMediumSkinTone", "👍🏽", true}, + // ZWJ sequence (couple kissing) + {"CoupleKissingZWJ", "👩‍❤️‍💋‍👨", true}, + // string of emojis + {"MultipleEmojis", "😀😃😄", true}, + + // invalid: letters only + {"Letters", "abc", false}, + // invalid: mixed emoji + letter + {"EmojiPlusLetter", "😀a", false}, + // invalid: digits + {"Digit", "1", false}, + // invalid: punctuation + {"Punctuation", "!", false}, + // invalid: whitespace + {"Whitespace", " ", false}, + // invalid: empty string + {"EmptyString", "", false}, + } + + for _, tc := range tests { + tc := tc + t.Run(tc.name, func(t *testing.T) { + got := IsEmoji(tc.input) + require.Equal(t, tc.want, got, "IsEmoji(%q)", tc.input) + }) + } +} diff --git a/core/api/service/list.go b/core/api/service/list.go index 8f9e40a00..647d53435 100644 --- a/core/api/service/list.go +++ b/core/api/service/list.go @@ -152,7 +152,7 @@ func (s *Service) GetObjectsInList(ctx context.Context, spaceId string, listId s var collectionId string var source []string switch model.ObjectTypeLayout(typeDetail.Fields[bundle.RelationKeyRecommendedLayout.String()].GetNumberValue()) { - case model.ObjectType_set: + case model.ObjectType_set, model.ObjectType_objectType: // for queries, we search within the space for objects of the setOf type setOfValues := resp.ObjectView.Details[0].Details.Fields[bundle.RelationKeySetOf.String()].GetListValue().Values for _, value := range setOfValues { @@ -197,31 +197,31 @@ func (s *Service) GetObjectsInList(ctx context.Context, spaceId string, listId s total := int(searchResp.Counters.Total) hasMore := searchResp.Counters.Total > int64(offset+limit) - propertyMap, err := s.GetPropertyMapFromStore(spaceId) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) if err != nil { return nil, 0, false, err } - typeMap, err := s.GetTypeMapFromStore(spaceId, propertyMap) + typeMap, err := s.getTypeMapFromStore(ctx, spaceId, propertyMap, false) if err != nil { return nil, 0, false, err } - tagMap, err := s.GetTagMapFromStore(spaceId) + tagMap, err := s.getTagMapFromStore(ctx, spaceId) if err != nil { return nil, 0, false, err } objects := make([]apimodel.Object, 0, len(searchResp.Records)) for _, record := range searchResp.Records { - objects = append(objects, s.GetObjectFromStruct(record, propertyMap, typeMap, tagMap)) + objects = append(objects, s.getObjectFromStruct(record, propertyMap, typeMap, tagMap)) } return objects, total, hasMore, nil } // AddObjectsToList adds objects to a list -func (s *Service) AddObjectsToList(ctx context.Context, spaceId string, listId string, objectIds []string) error { +func (s *Service) AddObjectsToList(ctx context.Context, _ string, listId string, request apimodel.AddObjectsToListRequest) error { resp := s.mw.ObjectCollectionAdd(ctx, &pb.RpcObjectCollectionAddRequest{ ContextId: listId, - ObjectIds: objectIds, + ObjectIds: request.Objects, }) if resp.Error != nil && resp.Error.Code != pb.RpcObjectCollectionAddResponseError_NULL { diff --git a/core/api/service/list_test.go b/core/api/service/list_test.go index f441dbaac..89c522750 100644 --- a/core/api/service/list_test.go +++ b/core/api/service/list_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + apimodel "github.com/anyproto/anytype-heart/core/api/model" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pkg/lib/bundle" "github.com/anyproto/anytype-heart/pkg/lib/pb/model" @@ -408,7 +409,7 @@ func TestListService_GetObjectsInList(t *testing.T) { }). Return(&pb.RpcObjectSearchUnsubscribeResponse{}, nil).Once() - // Mock GetPropertyMapsFromStore + // Mock getPropertyMapsFromStore fx.mwMock. On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, @@ -427,6 +428,7 @@ func TestListService_GetObjectsInList(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, @@ -443,7 +445,7 @@ func TestListService_GetObjectsInList(t *testing.T) { }, }, nil).Once() - // Mock GetTypeMapFromStore + // Mock getTypeMapFromStore fx.mwMock. On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, @@ -460,6 +462,7 @@ func TestListService_GetObjectsInList(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyUniqueKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyPluralName.String(), bundle.RelationKeyIconEmoji.String(), @@ -489,7 +492,7 @@ func TestListService_GetObjectsInList(t *testing.T) { }, }, nil).Once() - // Mock GetTagMapFromStore + // Mock getTagMapFromStore fx.mwMock. On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, @@ -653,7 +656,7 @@ func TestListService_GetObjectsInList(t *testing.T) { }). Return(&pb.RpcObjectSearchUnsubscribeResponse{}, nil).Once() - // Mock GetPropertyMapsFromStore + // Mock getPropertyMapsFromStore fx.mwMock. On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, @@ -672,6 +675,7 @@ func TestListService_GetObjectsInList(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, @@ -688,7 +692,7 @@ func TestListService_GetObjectsInList(t *testing.T) { }, }, nil).Once() - // Mock GetTypeMapFromStore + // Mock getTypeMapFromStore fx.mwMock. On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, @@ -705,6 +709,7 @@ func TestListService_GetObjectsInList(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyUniqueKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyPluralName.String(), bundle.RelationKeyIconEmoji.String(), @@ -734,7 +739,7 @@ func TestListService_GetObjectsInList(t *testing.T) { }, }, nil).Once() - // Mock GetTagMapFromStore + // Mock getTagMapFromStore fx.mwMock. On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, @@ -1108,7 +1113,7 @@ func TestListService_GetObjectsInList(t *testing.T) { }). Return(&pb.RpcObjectSearchUnsubscribeResponse{}, nil).Once() - // Mock GetPropertyMapsFromStore to return an error. + // Mock getPropertyMapsFromStore to return an error. fx.mwMock. On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, @@ -1127,6 +1132,7 @@ func TestListService_GetObjectsInList(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, @@ -1149,19 +1155,19 @@ func TestListService_AddObjectsToList(t *testing.T) { // given ctx := context.Background() fx := newFixture(t) - objectIds := []string{"obj-1", "obj-2"} + request := apimodel.AddObjectsToListRequest{Objects: []string{"obj-1", "obj-2"}} fx.mwMock. On("ObjectCollectionAdd", mock.Anything, &pb.RpcObjectCollectionAddRequest{ ContextId: mockedListId, - ObjectIds: objectIds, + ObjectIds: request.Objects, }). Return(&pb.RpcObjectCollectionAddResponse{ Error: &pb.RpcObjectCollectionAddResponseError{Code: pb.RpcObjectCollectionAddResponseError_NULL}, }, nil).Once() // when - err := fx.service.AddObjectsToList(ctx, mockedSpaceId, mockedListId, objectIds) + err := fx.service.AddObjectsToList(ctx, mockedSpaceId, mockedListId, request) // then require.NoError(t, err) @@ -1171,19 +1177,19 @@ func TestListService_AddObjectsToList(t *testing.T) { // given ctx := context.Background() fx := newFixture(t) - objectIds := []string{"obj-1"} + request := apimodel.AddObjectsToListRequest{Objects: []string{"obj-1"}} fx.mwMock. On("ObjectCollectionAdd", mock.Anything, &pb.RpcObjectCollectionAddRequest{ ContextId: mockedListId, - ObjectIds: objectIds, + ObjectIds: request.Objects, }). Return(&pb.RpcObjectCollectionAddResponse{ Error: &pb.RpcObjectCollectionAddResponseError{Code: pb.RpcObjectCollectionAddResponseError_UNKNOWN_ERROR}, }, nil).Once() // when - err := fx.service.AddObjectsToList(ctx, mockedSpaceId, mockedListId, objectIds) + err := fx.service.AddObjectsToList(ctx, mockedSpaceId, mockedListId, request) // then require.ErrorIs(t, err, ErrFailedAddObjectsToList) diff --git a/core/api/service/member.go b/core/api/service/member.go index 15f6b5fdb..2628664ff 100644 --- a/core/api/service/member.go +++ b/core/api/service/member.go @@ -80,7 +80,7 @@ func (s *Service) ListMembers(ctx context.Context, spaceId string, offset int, l members = make([]apimodel.Member, 0, len(paginatedMembers)) for _, record := range paginatedMembers { - icon := apimodel.GetIcon(s.gatewayUrl, record.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), record.Fields[bundle.RelationKeyIconImage.String()].GetStringValue(), "", 0) + icon := GetIcon(s.gatewayUrl, record.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), record.Fields[bundle.RelationKeyIconImage.String()].GetStringValue(), "", 0) member := apimodel.Member{ Object: "member", @@ -107,7 +107,7 @@ func (s *Service) GetMember(ctx context.Context, spaceId string, memberId string relationKey = bundle.RelationKeyIdentity } - resp := s.mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ + resp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ SpaceId: spaceId, Filters: []*model.BlockContentDataviewFilter{ { @@ -127,7 +127,7 @@ func (s *Service) GetMember(ctx context.Context, spaceId string, memberId string return apimodel.Member{}, ErrMemberNotFound } - icon := apimodel.GetIcon(s.gatewayUrl, "", resp.Records[0].Fields[bundle.RelationKeyIconImage.String()].GetStringValue(), "", 0) + icon := GetIcon(s.gatewayUrl, "", resp.Records[0].Fields[bundle.RelationKeyIconImage.String()].GetStringValue(), "", 0) return apimodel.Member{ Object: "member", diff --git a/core/api/service/object.go b/core/api/service/object.go index b930a8063..90036a540 100644 --- a/core/api/service/object.go +++ b/core/api/service/object.go @@ -71,21 +71,21 @@ func (s *Service) ListObjects(ctx context.Context, spaceId string, offset int, l objects = make([]apimodel.Object, 0, len(paginatedObjects)) // pre-fetch properties, types and tags to fill the objects - propertyMap, err := s.GetPropertyMapFromStore(spaceId) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) if err != nil { return nil, 0, false, err } - typeMap, err := s.GetTypeMapFromStore(spaceId, propertyMap) + typeMap, err := s.getTypeMapFromStore(ctx, spaceId, propertyMap, false) if err != nil { return nil, 0, false, err } - tagMap, err := s.GetTagMapFromStore(spaceId) + tagMap, err := s.getTagMapFromStore(ctx, spaceId) if err != nil { return nil, 0, false, err } for _, record := range paginatedObjects { - objects = append(objects, s.GetObjectFromStruct(record, propertyMap, typeMap, tagMap)) + objects = append(objects, s.getObjectFromStruct(record, propertyMap, typeMap, tagMap)) } return objects, total, hasMore, nil } @@ -111,15 +111,15 @@ func (s *Service) GetObject(ctx context.Context, spaceId string, objectId string } } - propertyMap, err := s.GetPropertyMapFromStore(spaceId) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) if err != nil { return apimodel.ObjectWithBody{}, err } - typeMap, err := s.GetTypeMapFromStore(spaceId, propertyMap) + typeMap, err := s.getTypeMapFromStore(ctx, spaceId, propertyMap, false) if err != nil { return apimodel.ObjectWithBody{}, err } - tagMap, err := s.GetTagMapFromStore(spaceId) + tagMap, err := s.getTagMapFromStore(ctx, spaceId) if err != nil { return apimodel.ObjectWithBody{}, err } @@ -129,17 +129,26 @@ func (s *Service) GetObject(ctx context.Context, spaceId string, objectId string return apimodel.ObjectWithBody{}, err } - return s.GetObjectWithBlocksFromStruct(resp.ObjectView.Details[0].Details, markdown, propertyMap, typeMap, tagMap), nil + return s.getObjectWithBlocksFromStruct(resp.ObjectView.Details[0].Details, markdown, propertyMap, typeMap, tagMap), nil } // CreateObject creates a new object in a specific space. func (s *Service) CreateObject(ctx context.Context, spaceId string, request apimodel.CreateObjectRequest) (apimodel.ObjectWithBody, error) { - request.TypeKey = util.FromTypeApiKey(request.TypeKey) details, err := s.buildObjectDetails(ctx, spaceId, request) if err != nil { return apimodel.ObjectWithBody{}, err } + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) + if err != nil { + return apimodel.ObjectWithBody{}, err + } + typeMap, err := s.getTypeMapFromStore(ctx, spaceId, propertyMap, true) + if err != nil { + return apimodel.ObjectWithBody{}, err + } + request.TypeKey = s.ResolveTypeApiKey(typeMap, request.TypeKey) + var objectId string if request.TypeKey == "ot-bookmark" { resp := s.mw.ObjectCreateBookmark(ctx, &pb.RpcObjectCreateBookmarkRequest{ @@ -273,7 +282,7 @@ func (s *Service) buildObjectDetails(ctx context.Context, spaceId string, reques bundle.RelationKeyOrigin.String(): pbtypes.Int64(int64(model.ObjectOrigin_api)), } - iconFields, err := s.processIconFields(ctx, spaceId, request.Icon) + iconFields, err := s.processIconFields(spaceId, request.Icon, false) if err != nil { return nil, err } @@ -300,7 +309,7 @@ func (s *Service) buildUpdatedObjectDetails(ctx context.Context, spaceId string, } if request.Icon != nil { - iconFields, err := s.processIconFields(ctx, spaceId, *request.Icon) + iconFields, err := s.processIconFields(spaceId, *request.Icon, false) if err != nil { return nil, err } @@ -323,13 +332,18 @@ func (s *Service) buildUpdatedObjectDetails(ctx context.Context, spaceId string, } // processIconFields returns the detail fields corresponding to the given icon. -func (s *Service) processIconFields(ctx context.Context, spaceId string, icon apimodel.Icon) (map[string]*types.Value, error) { +func (s *Service) processIconFields(spaceId string, icon apimodel.Icon, isType bool) (map[string]*types.Value, error) { iconFields := make(map[string]*types.Value) switch e := icon.WrappedIcon.(type) { case apimodel.NamedIcon: - return nil, util.ErrBadInput("icon name and color are not supported for object") + if isType { + iconFields[bundle.RelationKeyIconName.String()] = pbtypes.String(string(e.Name)) + iconFields[bundle.RelationKeyIconOption.String()] = pbtypes.Int64(apimodel.ColorToIconOption[e.Color]) + } else { + return nil, util.ErrBadInput("icon name and color are not supported for object") + } case apimodel.EmojiIcon: - if len(e.Emoji) > 0 && !apimodel.IsEmoji(e.Emoji) { + if len(e.Emoji) > 0 && !IsEmoji(e.Emoji) { return nil, util.ErrBadInput("icon emoji is not valid") } iconFields[bundle.RelationKeyIconEmoji.String()] = pbtypes.String(e.Emoji) @@ -361,7 +375,7 @@ func (s *Service) processIconFields(ctx context.Context, spaceId string, icon ap // Style: model.BlockContentTextStyle_name[int32(content.Text.Style)], // Checked: content.Text.Checked, // Color: content.Text.Color, -// Icon: apimodel.GetIcon(s.gatewayUrl, content.Text.IconEmoji, content.Text.IconImage, "", 0), +// Icon: GetIcon(s.gatewayUrl, content.Text.IconEmoji, content.Text.IconImage, "", 0), // } // case *model.BlockContentOfFile: // file = &apimodel.File{ @@ -401,13 +415,13 @@ func (s *Service) processIconFields(ctx context.Context, spaceId string, icon ap // return b // } -// GetObjectFromStruct creates an Object without blocks from the details. -func (s *Service) GetObjectFromStruct(details *types.Struct, propertyMap map[string]apimodel.Property, typeMap map[string]apimodel.Type, tagMap map[string]apimodel.Tag) apimodel.Object { +// getObjectFromStruct creates an Object without blocks from the details. +func (s *Service) getObjectFromStruct(details *types.Struct, propertyMap map[string]*apimodel.Property, typeMap map[string]*apimodel.Type, tagMap map[string]apimodel.Tag) apimodel.Object { return apimodel.Object{ Object: "object", Id: details.Fields[bundle.RelationKeyId.String()].GetStringValue(), Name: details.Fields[bundle.RelationKeyName.String()].GetStringValue(), - Icon: apimodel.GetIcon(s.gatewayUrl, details.GetFields()[bundle.RelationKeyIconEmoji.String()].GetStringValue(), details.GetFields()[bundle.RelationKeyIconImage.String()].GetStringValue(), details.GetFields()[bundle.RelationKeyIconName.String()].GetStringValue(), details.GetFields()[bundle.RelationKeyIconOption.String()].GetNumberValue()), + Icon: GetIcon(s.gatewayUrl, details.GetFields()[bundle.RelationKeyIconEmoji.String()].GetStringValue(), details.GetFields()[bundle.RelationKeyIconImage.String()].GetStringValue(), details.GetFields()[bundle.RelationKeyIconName.String()].GetStringValue(), details.GetFields()[bundle.RelationKeyIconOption.String()].GetNumberValue()), Archived: details.Fields[bundle.RelationKeyIsArchived.String()].GetBoolValue(), SpaceId: details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), Snippet: details.Fields[bundle.RelationKeySnippet.String()].GetStringValue(), @@ -417,13 +431,13 @@ func (s *Service) GetObjectFromStruct(details *types.Struct, propertyMap map[str } } -// GetObjectWithBlocksFromStruct creates an ObjectWithBody from the details. -func (s *Service) GetObjectWithBlocksFromStruct(details *types.Struct, markdown string, propertyMap map[string]apimodel.Property, typeMap map[string]apimodel.Type, tagMap map[string]apimodel.Tag) apimodel.ObjectWithBody { +// getObjectWithBlocksFromStruct creates an ObjectWithBody from the details. +func (s *Service) getObjectWithBlocksFromStruct(details *types.Struct, markdown string, propertyMap map[string]*apimodel.Property, typeMap map[string]*apimodel.Type, tagMap map[string]apimodel.Tag) apimodel.ObjectWithBody { return apimodel.ObjectWithBody{ Object: "object", Id: details.Fields[bundle.RelationKeyId.String()].GetStringValue(), Name: details.Fields[bundle.RelationKeyName.String()].GetStringValue(), - Icon: apimodel.GetIcon(s.gatewayUrl, details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), details.Fields[bundle.RelationKeyIconImage.String()].GetStringValue(), details.Fields[bundle.RelationKeyIconName.String()].GetStringValue(), details.Fields[bundle.RelationKeyIconOption.String()].GetNumberValue()), + Icon: GetIcon(s.gatewayUrl, details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), details.Fields[bundle.RelationKeyIconImage.String()].GetStringValue(), details.Fields[bundle.RelationKeyIconName.String()].GetStringValue(), details.Fields[bundle.RelationKeyIconOption.String()].GetNumberValue()), Archived: details.Fields[bundle.RelationKeyIsArchived.String()].GetBoolValue(), SpaceId: details.Fields[bundle.RelationKeySpaceId.String()].GetStringValue(), Snippet: details.Fields[bundle.RelationKeySnippet.String()].GetStringValue(), @@ -437,11 +451,17 @@ func (s *Service) GetObjectWithBlocksFromStruct(details *types.Struct, markdown // getMarkdownExport retrieves the Markdown export of an object. func (s *Service) getMarkdownExport(ctx context.Context, spaceId string, objectId string, layout model.ObjectTypeLayout) (string, error) { if util.IsObjectLayout(layout) { - md, err := s.exportService.ExportSingleInMemory(ctx, spaceId, objectId, model.Export_Markdown) - if err != nil { + resp := s.mw.ObjectExport(ctx, &pb.RpcObjectExportRequest{ + SpaceId: spaceId, + ObjectId: objectId, + Format: model.Export_Markdown, + }) + + if resp.Error != nil && resp.Error.Code != pb.RpcObjectExportResponseError_NULL { return "", ErrFailedExportMarkdown } - return md, nil + + return resp.Result, nil } return "", nil } diff --git a/core/api/service/object_test.go b/core/api/service/object_test.go index 702f9c85e..1c4de7c84 100644 --- a/core/api/service/object_test.go +++ b/core/api/service/object_test.go @@ -71,7 +71,7 @@ func TestObjectService_ListObjects(t *testing.T) { Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, }).Once() - // Mock GetPropertyMapFromStore + // Mock getPropertyMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -89,6 +89,7 @@ func TestObjectService_ListObjects(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, @@ -138,7 +139,7 @@ func TestObjectService_ListObjects(t *testing.T) { }, }, nil).Once() - // Mock GetTypeMapFromStore + // Mock getTypeMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -154,6 +155,7 @@ func TestObjectService_ListObjects(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyUniqueKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyPluralName.String(), bundle.RelationKeyIconEmoji.String(), @@ -182,7 +184,7 @@ func TestObjectService_ListObjects(t *testing.T) { }, }, nil).Once() - // Mock GetTagMapFromStore + // Mock getTagMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -300,7 +302,7 @@ func TestObjectService_ListObjects(t *testing.T) { Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, }).Once() - // Mock GetPropertyMapFromStore, GetTypeMapFromStore and GetTagMapFromStore + // Mock getPropertyMapFromStore, getTypeMapFromStore and getTagMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, mock.Anything).Return(&pb.RpcObjectSearchResponse{ Records: []*types.Struct{}, Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, @@ -363,7 +365,7 @@ func TestObjectService_GetObject(t *testing.T) { }, }, nil).Once() - // Mock GetPropertyMapsFromStore + // Mock getPropertyMapsFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -381,6 +383,7 @@ func TestObjectService_GetObject(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, @@ -430,7 +433,7 @@ func TestObjectService_GetObject(t *testing.T) { }, }, nil).Once() - // Mock GetTypeMapFromStore + // Mock getTypeMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -446,6 +449,7 @@ func TestObjectService_GetObject(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyUniqueKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyPluralName.String(), bundle.RelationKeyIconEmoji.String(), @@ -474,7 +478,7 @@ func TestObjectService_GetObject(t *testing.T) { }, }, nil).Once() - // Mock GetTagMapFromStore + // Mock getTagMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -501,9 +505,14 @@ func TestObjectService_GetObject(t *testing.T) { }, nil).Once() // Mock ExportMarkdown - fx.exportService. - On("ExportSingleInMemory", mock.Anything, mockedSpaceId, mockedObjectId, model.Export_Markdown). - Return("dummy markdown", nil).Once() + fx.mwMock.On("ObjectExport", mock.Anything, &pb.RpcObjectExportRequest{ + SpaceId: mockedSpaceId, + ObjectId: mockedObjectId, + Format: model.Export_Markdown, + }).Return(&pb.RpcObjectExportResponse{ + Result: "dummy markdown", + Error: &pb.RpcObjectExportResponseError{Code: pb.RpcObjectExportResponseError_NULL}, + }, nil).Once() // when object, err := fx.service.GetObject(ctx, mockedSpaceId, mockedObjectId) @@ -644,16 +653,59 @@ func TestObjectService_CreateObject(t *testing.T) { Error: &pb.RpcObjectShowResponseError{Code: pb.RpcObjectShowResponseError_NULL}, }).Once() - // Mock GetPropertyMapFromStore, GetTypeMapFromStore and GetTagMapFromStore + // Mock getTypeMapFromStore to properly resolve typeKey for creation + fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ + SpaceId: mockedSpaceId, + Filters: []*model.BlockContentDataviewFilter{ + { + RelationKey: bundle.RelationKeyResolvedLayout.String(), + Condition: model.BlockContentDataviewFilter_Equal, + Value: pbtypes.Int64(int64(model.ObjectType_objectType)), + }, + { + RelationKey: bundle.RelationKeyIsDeleted.String(), + }, + }, + Keys: []string{ + bundle.RelationKeyId.String(), + bundle.RelationKeyUniqueKey.String(), + bundle.RelationKeyApiObjectKey.String(), + bundle.RelationKeyName.String(), + bundle.RelationKeyPluralName.String(), + bundle.RelationKeyIconEmoji.String(), + bundle.RelationKeyIconName.String(), + bundle.RelationKeyIconOption.String(), + bundle.RelationKeyRecommendedLayout.String(), + bundle.RelationKeyIsArchived.String(), + bundle.RelationKeyRecommendedFeaturedRelations.String(), + bundle.RelationKeyRecommendedRelations.String(), + }, + }).Return(&pb.RpcObjectSearchResponse{ + Records: []*types.Struct{ + { + Fields: map[string]*types.Value{ + bundle.RelationKeyUniqueKey.String(): pbtypes.String("ot-" + mockedTypeKey), + }, + }, + }, + Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + }).Times(1) + + // Mock getPropertyMapFromStore, getTypeMapFromStore and getTagMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, mock.Anything).Return(&pb.RpcObjectSearchResponse{ Records: []*types.Struct{}, Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, - }).Times(3) + }).Times(4) // Mock ExportMarkdown - fx.exportService. - On("ExportSingleInMemory", mock.Anything, mockedSpaceId, mockedNewObjectId, model.Export_Markdown). - Return("dummy markdown", nil).Once() + fx.mwMock.On("ObjectExport", mock.Anything, &pb.RpcObjectExportRequest{ + SpaceId: mockedSpaceId, + ObjectId: mockedNewObjectId, + Format: model.Export_Markdown, + }).Return(&pb.RpcObjectExportResponse{ + Result: "dummy markdown", + Error: &pb.RpcObjectExportResponseError{Code: pb.RpcObjectExportResponseError_NULL}, + }, nil).Once() // when object, err := fx.service.CreateObject(ctx, mockedSpaceId, apimodel.CreateObjectRequest{ @@ -677,6 +729,12 @@ func TestObjectService_CreateObject(t *testing.T) { ctx := context.Background() fx := newFixture(t) + // Mock getPropertyMapFromStore, getTypeMapFromStore + fx.mwMock.On("ObjectSearch", mock.Anything, mock.Anything).Return(&pb.RpcObjectSearchResponse{ + Records: []*types.Struct{}, + Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, + }).Times(2) + fx.mwMock.On("ObjectCreate", mock.Anything, mock.Anything). Return(&pb.RpcObjectCreateResponse{ Error: &pb.RpcObjectCreateResponseError{Code: pb.RpcObjectCreateResponseError_UNKNOWN_ERROR}, diff --git a/core/api/service/property.go b/core/api/service/property.go index 7dfbcb17e..151bda819 100644 --- a/core/api/service/property.go +++ b/core/api/service/property.go @@ -9,6 +9,7 @@ import ( "time" "github.com/gogo/protobuf/types" + "github.com/iancoleman/strcase" apimodel "github.com/anyproto/anytype-heart/core/api/model" "github.com/anyproto/anytype-heart/core/api/pagination" @@ -106,7 +107,7 @@ var RelationFormatToPropertyFormat = map[model.RelationFormat]apimodel.PropertyF // ListProperties returns a list of properties for a specific space. func (s *Service) ListProperties(ctx context.Context, spaceId string, offset int, limit int) (properties []apimodel.Property, total int, hasMore bool, err error) { - resp := s.mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ + resp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ SpaceId: spaceId, Filters: []*model.BlockContentDataviewFilter{ { @@ -129,6 +130,7 @@ func (s *Service) ListProperties(ctx context.Context, spaceId string, offset int Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, @@ -140,7 +142,7 @@ func (s *Service) ListProperties(ctx context.Context, spaceId string, offset int filteredRecords := make([]*types.Struct, 0, len(resp.Records)) for _, record := range resp.Records { - rk, _ := s.mapPropertyFromRecord(record) + rk, _, _ := s.getPropertyFromStruct(record) if _, isExcluded := excludedSystemProperties[rk]; isExcluded { continue } @@ -152,7 +154,7 @@ func (s *Service) ListProperties(ctx context.Context, spaceId string, offset int properties = make([]apimodel.Property, 0, len(paginatedProperties)) for _, record := range paginatedProperties { - _, property := s.mapPropertyFromRecord(record) + _, _, property := s.getPropertyFromStruct(record) properties = append(properties, property) } @@ -161,7 +163,7 @@ func (s *Service) ListProperties(ctx context.Context, spaceId string, offset int // GetProperty retrieves a single property by its ID in a specific space. func (s *Service) GetProperty(ctx context.Context, spaceId string, propertyId string) (apimodel.Property, error) { - resp := s.mw.ObjectShow(context.Background(), &pb.RpcObjectShowRequest{ + resp := s.mw.ObjectShow(ctx, &pb.RpcObjectShowRequest{ SpaceId: spaceId, ObjectId: propertyId, }) @@ -180,7 +182,7 @@ func (s *Service) GetProperty(ctx context.Context, spaceId string, propertyId st } } - rk, property := s.mapPropertyFromRecord(resp.ObjectView.Details[0].Details) + rk, _, property := s.getPropertyFromStruct(resp.ObjectView.Details[0].Details) if _, isExcluded := excludedSystemProperties[rk]; isExcluded { return apimodel.Property{}, ErrPropertyNotFound } @@ -191,11 +193,24 @@ func (s *Service) GetProperty(ctx context.Context, spaceId string, propertyId st func (s *Service) CreateProperty(ctx context.Context, spaceId string, request apimodel.CreatePropertyRequest) (apimodel.Property, error) { details := &types.Struct{ Fields: map[string]*types.Value{ - bundle.RelationKeyName.String(): pbtypes.String(request.Name), + bundle.RelationKeyName.String(): pbtypes.String(s.sanitizedString(request.Name)), bundle.RelationKeyRelationFormat.String(): pbtypes.Int64(int64(PropertyFormatToRelationFormat[request.Format])), + bundle.RelationKeyOrigin.String(): pbtypes.Int64(int64(model.ObjectOrigin_api)), }, } + if request.Key != "" { + apiKey := strcase.ToSnake(s.sanitizedString(request.Key)) + propMap, err := s.getPropertyMapFromStore(ctx, spaceId, false) + if err != nil { + return apimodel.Property{}, err + } + if _, exists := propMap[apiKey]; exists { + return apimodel.Property{}, util.ErrBadInput(fmt.Sprintf("property key %q already exists", apiKey)) + } + details.Fields[bundle.RelationKeyApiObjectKey.String()] = pbtypes.String(apiKey) + } + resp := s.mw.ObjectCreateRelation(ctx, &pb.RpcObjectCreateRelationRequest{ SpaceId: spaceId, Details: details, @@ -215,21 +230,41 @@ func (s *Service) UpdateProperty(ctx context.Context, spaceId string, propertyId return apimodel.Property{}, err } - if bundle.HasRelation(domain.RelationKey(util.FromPropertyApiKey(prop.Key))) { + rel, err := bundle.PickRelation(domain.RelationKey(prop.RelationKey)) + if err == nil && rel.ReadOnly { return apimodel.Property{}, ErrPropertyCannotBeUpdated } + var detailsToUpdate []*model.Detail if request.Name != nil { - detail := model.Detail{ + detailsToUpdate = append(detailsToUpdate, &model.Detail{ Key: bundle.RelationKeyName.String(), Value: pbtypes.String(s.sanitizedString(*request.Name)), + }) + } + if request.Key != nil { + newKey := strcase.ToSnake(s.sanitizedString(*request.Key)) + propMap, err := s.getPropertyMapFromStore(ctx, spaceId, false) + if err != nil { + return apimodel.Property{}, err } + if existing, exists := propMap[newKey]; exists && existing.Id != propertyId { + return apimodel.Property{}, util.ErrBadInput(fmt.Sprintf("property key %q already exists", newKey)) + } + if bundle.HasRelation(domain.RelationKey(prop.RelationKey)) { + return apimodel.Property{}, util.ErrBadInput("property key of bundled properties cannot be changed") + } + detailsToUpdate = append(detailsToUpdate, &model.Detail{ + Key: bundle.RelationKeyApiObjectKey.String(), + Value: pbtypes.String(newKey), + }) + } + if len(detailsToUpdate) > 0 { resp := s.mw.ObjectSetDetails(ctx, &pb.RpcObjectSetDetailsRequest{ ContextId: propertyId, - Details: []*model.Detail{&detail}, + Details: detailsToUpdate, }) - if resp.Error != nil && resp.Error.Code != pb.RpcObjectSetDetailsResponseError_NULL { return apimodel.Property{}, ErrFailedUpdateProperty } @@ -267,7 +302,7 @@ func (s *Service) processProperties(ctx context.Context, spaceId string, entries if len(entries) == 0 { return fields, nil } - propertyMap, err := s.GetPropertyMapFromStore(spaceId) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, false) if err != nil { return nil, err } @@ -282,14 +317,14 @@ func (s *Service) processProperties(ctx context.Context, spaceId string, entries case apimodel.NumberPropertyLinkValue: key = e.Key if e.Number == nil { - fields[util.FromPropertyApiKey(key)] = pbtypes.ToValue(nil) + fields[s.ResolvePropertyApiKey(propertyMap, key)] = pbtypes.ToValue(nil) continue } raw = *e.Number case apimodel.SelectPropertyLinkValue: key = e.Key if e.Select == nil { - fields[util.FromPropertyApiKey(key)] = pbtypes.ToValue(nil) + fields[s.ResolvePropertyApiKey(propertyMap, key)] = pbtypes.ToValue(nil) continue } raw = *e.Select @@ -303,7 +338,7 @@ func (s *Service) processProperties(ctx context.Context, spaceId string, entries case apimodel.DatePropertyLinkValue: key = e.Key if e.Date == nil { - fields[util.FromPropertyApiKey(key)] = pbtypes.ToValue(nil) + fields[s.ResolvePropertyApiKey(propertyMap, key)] = pbtypes.ToValue(nil) continue } raw = *e.Date @@ -337,7 +372,7 @@ func (s *Service) processProperties(ctx context.Context, spaceId string, entries return nil, util.ErrBadInput("unsupported property link value type " + fmt.Sprintf("%T", e)) } - rk := util.FromPropertyApiKey(key) + rk := s.ResolvePropertyApiKey(propertyMap, key) if _, excluded := excludedSystemProperties[rk]; excluded { continue } @@ -346,10 +381,10 @@ func (s *Service) processProperties(ctx context.Context, spaceId string, entries } prop, ok := propertyMap[rk] if !ok { - return nil, errors.New("unknown property '" + key + "'") + return nil, util.ErrBadInput(fmt.Sprintf("unknown property key: %q", rk)) } - sanitized, err := s.sanitizeAndValidatePropertyValue(ctx, spaceId, key, prop.Format, raw, prop) + sanitized, err := s.sanitizeAndValidatePropertyValue(spaceId, key, prop.Format, raw, prop, propertyMap) if err != nil { return nil, err } @@ -359,7 +394,7 @@ func (s *Service) processProperties(ctx context.Context, spaceId string, entries } // sanitizeAndValidatePropertyValue checks the value for a property according to its format and ensures referenced IDs exist and are valid. -func (s *Service) sanitizeAndValidatePropertyValue(ctx context.Context, spaceId string, key string, format apimodel.PropertyFormat, value interface{}, property apimodel.Property) (interface{}, error) { +func (s *Service) sanitizeAndValidatePropertyValue(spaceId string, key string, format apimodel.PropertyFormat, value interface{}, property *apimodel.Property, propertyMap map[string]*apimodel.Property) (interface{}, error) { switch format { case apimodel.PropertyFormatText, apimodel.PropertyFormatUrl, apimodel.PropertyFormatEmail, apimodel.PropertyFormatPhone: str, ok := value.(string) @@ -379,7 +414,7 @@ func (s *Service) sanitizeAndValidatePropertyValue(ctx context.Context, spaceId if !ok { return nil, util.ErrBadInput("property '" + key + "' must be a string (tag id)") } - if !s.isValidSelectOption(spaceId, property, id) { + if !s.isValidSelectOption(spaceId, property, id, propertyMap) { return nil, util.ErrBadInput("invalid select option for '" + key + "': " + id) } return id, nil @@ -395,7 +430,7 @@ func (s *Service) sanitizeAndValidatePropertyValue(ctx context.Context, spaceId return nil, util.ErrBadInput("property '" + key + "' must be an array of strings (tag ids)") } id = s.sanitizedString(id) - if !s.isValidSelectOption(spaceId, property, id) { + if !s.isValidSelectOption(spaceId, property, id, propertyMap) { return nil, util.ErrBadInput("invalid multi_select option for '" + key + "': " + id) } validIds = append(validIds, id) @@ -444,14 +479,14 @@ func (s *Service) sanitizeAndValidatePropertyValue(ctx context.Context, spaceId } // isValidSelectOption checks if the option id is valid for the given property. -func (s *Service) isValidSelectOption(spaceId string, property apimodel.Property, tagId string) bool { +func (s *Service) isValidSelectOption(spaceId string, property *apimodel.Property, tagId string, propertyMap map[string]*apimodel.Property) bool { fields, err := util.GetFieldsByID(s.mw, spaceId, tagId, []string{bundle.RelationKeyResolvedLayout.String(), bundle.RelationKeyRelationKey.String()}) if err != nil { return false } layout := model.ObjectTypeLayout(fields[bundle.RelationKeyResolvedLayout.String()].GetNumberValue()) - rk := domain.RelationKey(fields[bundle.RelationKeyRelationKey.String()].GetStringValue()) - return util.IsTagLayout(layout) && rk == domain.RelationKey(util.FromPropertyApiKey(property.Key)) + rk := fields[bundle.RelationKeyRelationKey.String()].GetStringValue() + return util.IsTagLayout(layout) && rk == s.ResolvePropertyApiKey(propertyMap, property.Key) } func (s *Service) isValidObjectReference(spaceId string, objectId string) bool { @@ -473,7 +508,7 @@ func (s *Service) isValidFileReference(spaceId string, fileId string) bool { } // getRecommendedPropertiesFromLists combines featured and regular properties into a list of Properties. -func (s *Service) getRecommendedPropertiesFromLists(featured, regular *types.ListValue, propertyMap map[string]apimodel.Property) []apimodel.Property { +func (s *Service) getRecommendedPropertiesFromLists(featured, regular *types.ListValue, propertyMap map[string]*apimodel.Property) []apimodel.Property { var props []apimodel.Property lists := []*types.ListValue{featured, regular} for _, lst := range lists { @@ -489,22 +524,22 @@ func (s *Service) getRecommendedPropertiesFromLists(featured, regular *types.Lis if !ok { continue } - rk := util.FromPropertyApiKey(p.Key) - if _, excluded := excludedSystemProperties[rk]; excluded { + if _, excluded := excludedSystemProperties[p.RelationKey]; excluded { continue } - props = append(props, p) + props = append(props, *p) } } return props } -// GetPropertyMapsFromStore retrieves all properties for all spaces. -func (s *Service) GetPropertyMapsFromStore(spaceIds []string) (map[string]map[string]apimodel.Property, error) { - spacesToProperties := make(map[string]map[string]apimodel.Property, len(spaceIds)) +// getPropertyMapsFromStore retrieves all properties for all spaces. +// Property entries can also be keyed by property id. Required for filling types with properties, as recommended properties are referenced by id and not key. +func (s *Service) getPropertyMapsFromStore(ctx context.Context, spaceIds []string, keyByPropertyId bool) (map[string]map[string]*apimodel.Property, error) { + spacesToProperties := make(map[string]map[string]*apimodel.Property, len(spaceIds)) for _, spaceId := range spaceIds { - propertyMap, err := s.GetPropertyMapFromStore(spaceId) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, keyByPropertyId) if err != nil { return nil, err } @@ -514,10 +549,10 @@ func (s *Service) GetPropertyMapsFromStore(spaceIds []string) (map[string]map[st return spacesToProperties, nil } -// GetPropertyMapFromStore retrieves all properties for a specific space -// Property entries are also keyed by property id. Required for filling types with properties, as recommended properties are referenced by id and not key. -func (s *Service) GetPropertyMapFromStore(spaceId string) (map[string]apimodel.Property, error) { - resp := s.mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ +// getPropertyMapFromStore retrieves all properties for a specific space +// Property entries can also be keyed by property id. Required for filling types with properties, as recommended properties are referenced by id and not key. +func (s *Service) getPropertyMapFromStore(ctx context.Context, spaceId string, keyByPropertyId bool) (map[string]*apimodel.Property, error) { + resp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ SpaceId: spaceId, Filters: []*model.BlockContentDataviewFilter{ { @@ -534,6 +569,7 @@ func (s *Service) GetPropertyMapFromStore(spaceId string) (map[string]apimodel.P Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, @@ -543,30 +579,45 @@ func (s *Service) GetPropertyMapFromStore(spaceId string) (map[string]apimodel.P return nil, ErrFailedRetrievePropertyMap } - propertyMap := make(map[string]apimodel.Property, len(resp.Records)) + propertyMap := make(map[string]*apimodel.Property, len(resp.Records)) for _, record := range resp.Records { - rk, p := s.mapPropertyFromRecord(record) - propertyMap[rk] = p - propertyMap[p.Id] = p // add property under id as key to map as well + rk, key, p := s.getPropertyFromStruct(record) + prop := p + propertyMap[rk] = &prop + propertyMap[key] = &prop // TODO: add under api key as well, double check + if keyByPropertyId { + propertyMap[p.Id] = &prop // add property under id as key to map as well + } } return propertyMap, nil } -// mapPropertyFromRecord maps a single property record into a Property and returns its trimmed relation key. -func (s *Service) mapPropertyFromRecord(record *types.Struct) (string, apimodel.Property) { - rk := record.Fields[bundle.RelationKeyRelationKey.String()].GetStringValue() - return rk, apimodel.Property{ - Object: "property", - Id: record.Fields[bundle.RelationKeyId.String()].GetStringValue(), - Key: util.ToPropertyApiKey(rk), - Name: record.Fields[bundle.RelationKeyName.String()].GetStringValue(), - Format: RelationFormatToPropertyFormat[model.RelationFormat(record.Fields[bundle.RelationKeyRelationFormat.String()].GetNumberValue())], +// getPropertyFromStruct maps a property's details into an apimodel.Property. +// `rk` is what we use internally, `key` is the key being referenced in the API. +func (s *Service) getPropertyFromStruct(details *types.Struct) (string, string, apimodel.Property) { + rk := details.Fields[bundle.RelationKeyRelationKey.String()].GetStringValue() + key := util.ToPropertyApiKey(rk) + + // apiId as key takes precedence over relation key + if apiIDField, exists := details.Fields[bundle.RelationKeyApiObjectKey.String()]; exists { + if apiId := apiIDField.GetStringValue(); apiId != "" { + key = apiId + } + } + + return rk, key, apimodel.Property{ + Object: "property", + Id: details.Fields[bundle.RelationKeyId.String()].GetStringValue(), + Key: key, + Name: details.Fields[bundle.RelationKeyName.String()].GetStringValue(), + Format: RelationFormatToPropertyFormat[model.RelationFormat(details.Fields[bundle.RelationKeyRelationFormat.String()].GetNumberValue())], + RelationKey: rk, // internal-only for simplified lookup } } // getPropertiesFromStruct retrieves the properties from the details. -func (s *Service) getPropertiesFromStruct(details *types.Struct, propertyMap map[string]apimodel.Property, tagMap map[string]apimodel.Tag) []apimodel.PropertyWithValue { +func (s *Service) getPropertiesFromStruct(details *types.Struct, propertyMap map[string]*apimodel.Property, tagMap map[string]apimodel.Tag) []apimodel.PropertyWithValue { properties := make([]apimodel.PropertyWithValue, 0) for rk, value := range details.GetFields() { if _, isExcluded := excludedSystemProperties[rk]; isExcluded { @@ -585,7 +636,9 @@ func (s *Service) getPropertiesFromStruct(details *types.Struct, propertyMap map id := prop.Id name := prop.Name - properties = append(properties, s.buildPropertyWithValue(id, key, name, format, convertedVal)) + if pwv := s.buildPropertyWithValue(id, key, name, format, convertedVal); pwv != nil { + properties = append(properties, *pwv) + } } return properties @@ -657,7 +710,7 @@ func (s *Service) convertPropertyValue(key string, value *types.Value, format ap } // buildPropertyWithValue creates a Property based on the format and converted value. -func (s *Service) buildPropertyWithValue(id string, key string, name string, format apimodel.PropertyFormat, val interface{}) apimodel.PropertyWithValue { +func (s *Service) buildPropertyWithValue(id string, key string, name string, format apimodel.PropertyFormat, val interface{}) *apimodel.PropertyWithValue { base := apimodel.PropertyBase{ Object: "property", Id: id, @@ -666,52 +719,37 @@ func (s *Service) buildPropertyWithValue(id string, key string, name string, for switch format { case apimodel.PropertyFormatText: if str, ok := val.(string); ok { - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.TextPropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - Text: str, + return &apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.TextPropertyValue{ + PropertyBase: base, Key: key, Name: name, Format: format, + Text: str, }} } case apimodel.PropertyFormatNumber: if num, ok := val.(float64); ok { - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.NumberPropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - Number: num, + return &apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.NumberPropertyValue{ + PropertyBase: base, Key: key, Name: name, Format: format, + Number: num, }} } case apimodel.PropertyFormatSelect: if sel, ok := val.(apimodel.Tag); ok { - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.SelectPropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - Select: &sel, + return &apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.SelectPropertyValue{ + PropertyBase: base, Key: key, Name: name, Format: format, + Select: &sel, }} } case apimodel.PropertyFormatMultiSelect: if ms, ok := val.([]apimodel.Tag); ok { - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.MultiSelectPropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - MultiSelect: ms, + return &apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.MultiSelectPropertyValue{ + PropertyBase: base, Key: key, Name: name, Format: format, + MultiSelect: ms, }} } case apimodel.PropertyFormatDate: if dateStr, ok := val.(string); ok { - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.DatePropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - Date: dateStr, + return &apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.DatePropertyValue{ + PropertyBase: base, Key: key, Name: name, Format: format, + Date: dateStr, }} } case apimodel.PropertyFormatFiles: @@ -722,52 +760,37 @@ func (s *Service) buildPropertyWithValue(id string, key string, name string, for files = append(files, str) } } - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.FilesPropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - Files: files, + return &apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.FilesPropertyValue{ + PropertyBase: base, Key: key, Name: name, Format: format, + Files: files, }} } case apimodel.PropertyFormatCheckbox: if cb, ok := val.(bool); ok { - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.CheckboxPropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - Checkbox: cb, + return &apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.CheckboxPropertyValue{ + PropertyBase: base, Key: key, Name: name, Format: format, + Checkbox: cb, }} } case apimodel.PropertyFormatUrl: if urlStr, ok := val.(string); ok { - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.URLPropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - Url: urlStr, + return &apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.URLPropertyValue{ + PropertyBase: base, Key: key, Name: name, Format: format, + Url: urlStr, }} } case apimodel.PropertyFormatEmail: if email, ok := val.(string); ok { - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.EmailPropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - Email: email, + return &apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.EmailPropertyValue{ + PropertyBase: base, Key: key, Name: name, Format: format, + Email: email, }} } case apimodel.PropertyFormatPhone: if phone, ok := val.(string); ok { - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.PhonePropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - Phone: phone, + return &apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.PhonePropertyValue{ + PropertyBase: base, Key: key, Name: name, Format: format, + Phone: phone, }} } case apimodel.PropertyFormatObjects: @@ -782,7 +805,7 @@ func (s *Service) buildPropertyWithValue(id string, key string, name string, for } } } - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.ObjectsPropertyValue{ + return &apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.ObjectsPropertyValue{ PropertyBase: base, Key: key, Name: name, @@ -791,20 +814,16 @@ func (s *Service) buildPropertyWithValue(id string, key string, name string, for }} } - if str, ok := val.(string); ok { - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.TextPropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - Text: str, - }} - } - return apimodel.PropertyWithValue{WrappedPropertyWithValue: apimodel.TextPropertyValue{ - PropertyBase: base, - Key: key, - Name: name, - Format: format, - Text: fmt.Sprintf("%v", val), - }} + return nil +} + +// ResolvePropertyApiKey returns the internal relationKey for a clientKey by looking it up in the propertyMap +// TODO: If not found, this detail shouldn't be set by clients, and strict validation errors +func (s *Service) ResolvePropertyApiKey(propertyMap map[string]*apimodel.Property, clientKey string) string { + if p, ok := propertyMap[clientKey]; ok { + return p.RelationKey + } + return "" + // TODO: enable later for strict validation + // return "", false } diff --git a/core/api/service/search.go b/core/api/service/search.go index 3e80f1f95..7776b8bae 100644 --- a/core/api/service/search.go +++ b/core/api/service/search.go @@ -22,7 +22,7 @@ var ( // GlobalSearch retrieves a paginated list of objects from all spaces that match the search parameters. func (s *Service) GlobalSearch(ctx context.Context, request apimodel.SearchRequest, offset int, limit int) (objects []apimodel.Object, total int, hasMore bool, err error) { - spaceIds, err := s.GetAllSpaceIds() + spaceIds, err := s.GetAllSpaceIds(ctx) if err != nil { return nil, 0, false, err } @@ -31,11 +31,29 @@ func (s *Service) GlobalSearch(ctx context.Context, request apimodel.SearchReque queryFilters := s.prepareQueryFilter(request.Query) sorts, criterionToSortAfter := s.prepareSorts(request.Sort) + // pre-fetch properties, types and tags to fill the objects + propertyMaps, err := s.getPropertyMapsFromStore(ctx, spaceIds, true) + if err != nil { + return nil, 0, false, err + } + typeMaps, err := s.getTypeMapsFromStore(ctx, spaceIds, propertyMaps, true) + if err != nil { + return nil, 0, false, err + } + tagMap, err := s.getTagMapsFromStore(ctx, spaceIds) + if err != nil { + return nil, 0, false, err + } + var combinedRecords []*types.Struct for _, spaceId := range spaceIds { - // Resolve template type and object type IDs per spaceId, as they are unique per spaceId + // Resolve template and type IDs per spaceId, as they are unique per spaceId templateFilter := s.prepareTemplateFilter() - typeFilters := s.prepareObjectTypeFilters(spaceId, request.Types) + typeFilters := s.prepareTypeFilters(request.Types, typeMaps[spaceId]) + if len(request.Types) > 0 && len(typeFilters) == 0 { + // Skip spaces that don’t have any of the requested types + continue + } filters := s.combineFilters(model.BlockContentDataviewFilter_And, baseFilters, templateFilter, queryFilters, typeFilters) objResp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ @@ -76,23 +94,9 @@ func (s *Service) GlobalSearch(ctx context.Context, request apimodel.SearchReque total = len(combinedRecords) paginatedRecords, hasMore := pagination.Paginate(combinedRecords, offset, limit) - // pre-fetch properties, types and tags to fill the objects - propertyMaps, err := s.GetPropertyMapsFromStore(spaceIds) - if err != nil { - return nil, 0, false, err - } - typeMaps, err := s.GetTypeMapsFromStore(spaceIds, propertyMaps) - if err != nil { - return nil, 0, false, err - } - tagMap, err := s.GetTagMapsFromStore(spaceIds) - if err != nil { - return nil, 0, false, err - } - results := make([]apimodel.Object, 0, len(paginatedRecords)) for _, record := range paginatedRecords { - results = append(results, s.GetObjectFromStruct(record, propertyMaps[record.Fields[bundle.RelationKeySpaceId.String()].GetStringValue()], typeMaps[record.Fields[bundle.RelationKeySpaceId.String()].GetStringValue()], tagMap[record.Fields[bundle.RelationKeySpaceId.String()].GetStringValue()])) + results = append(results, s.getObjectFromStruct(record, propertyMaps[record.Fields[bundle.RelationKeySpaceId.String()].GetStringValue()], typeMaps[record.Fields[bundle.RelationKeySpaceId.String()].GetStringValue()], tagMap[record.Fields[bundle.RelationKeySpaceId.String()].GetStringValue()])) } return results, total, hasMore, nil @@ -103,7 +107,26 @@ func (s *Service) Search(ctx context.Context, spaceId string, request apimodel.S baseFilters := s.prepareBaseFilters() templateFilter := s.prepareTemplateFilter() queryFilters := s.prepareQueryFilter(request.Query) - typeFilters := s.prepareObjectTypeFilters(spaceId, request.Types) + + // pre-fetch properties and types to fill the objects + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) + if err != nil { + return nil, 0, false, err + } + typeMap, err := s.getTypeMapFromStore(ctx, spaceId, propertyMap, true) + if err != nil { + return nil, 0, false, err + } + tagMap, err := s.getTagMapFromStore(ctx, spaceId) + if err != nil { + return nil, 0, false, err + } + + typeFilters := s.prepareTypeFilters(request.Types, typeMap) + if len(request.Types) > 0 && len(typeFilters) == 0 { + // No matching types in this space; return empty result + return nil, 0, false, nil + } filters := s.combineFilters(model.BlockContentDataviewFilter_And, baseFilters, templateFilter, queryFilters, typeFilters) sorts, _ := s.prepareSorts(request.Sort) @@ -120,23 +143,9 @@ func (s *Service) Search(ctx context.Context, spaceId string, request apimodel.S total = len(resp.Records) paginatedRecords, hasMore := pagination.Paginate(resp.Records, offset, limit) - // pre-fetch properties and types to fill the objects - propertyMap, err := s.GetPropertyMapFromStore(spaceId) - if err != nil { - return nil, 0, false, err - } - typeMap, err := s.GetTypeMapFromStore(spaceId, propertyMap) - if err != nil { - return nil, 0, false, err - } - tagMap, err := s.GetTagMapFromStore(spaceId) - if err != nil { - return nil, 0, false, err - } - results := make([]apimodel.Object, 0, len(paginatedRecords)) for _, record := range paginatedRecords { - results = append(results, s.GetObjectFromStruct(record, propertyMap, typeMap, tagMap)) + results = append(results, s.getObjectFromStruct(record, propertyMap, typeMap, tagMap)) } return results, total, hasMore, nil @@ -215,26 +224,29 @@ func (s *Service) prepareQueryFilter(searchQuery string) []*model.BlockContentDa } } -// prepareObjectTypeFilters combines object type filters with an OR condition. -func (s *Service) prepareObjectTypeFilters(spaceId string, objectTypes []string) []*model.BlockContentDataviewFilter { - if len(objectTypes) == 0 || objectTypes[0] == "" { +// prepareTypeFilters combines type filters with an OR condition. +func (s *Service) prepareTypeFilters(types []string, typeMap map[string]*apimodel.Type) []*model.BlockContentDataviewFilter { + if len(types) == 0 { return nil } - // Prepare nested filters for each object type - nestedFilters := make([]*model.BlockContentDataviewFilter, 0, len(objectTypes)) - for _, objectType := range objectTypes { - ukOrId := util.FromTypeApiKey(objectType) - typeId, err := util.ResolveUniqueKeyToTypeId(s.mw, spaceId, ukOrId) - if err != nil { - // client passed type id instead of type key - typeId = objectType + // Prepare nested filters for each type + nestedFilters := make([]*model.BlockContentDataviewFilter, 0, len(types)) + for _, key := range types { + if key == "" { + continue + } + + uk := s.ResolveTypeApiKey(typeMap, key) + typeDef, ok := typeMap[uk] + if !ok { + continue } nestedFilters = append(nestedFilters, &model.BlockContentDataviewFilter{ RelationKey: bundle.RelationKeyType.String(), Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(typeId), + Value: pbtypes.String(typeDef.Id), }) } diff --git a/core/api/service/search_test.go b/core/api/service/search_test.go index c65163018..28d2a7941 100644 --- a/core/api/service/search_test.go +++ b/core/api/service/search_test.go @@ -129,7 +129,7 @@ func TestSearchService_GlobalSearch(t *testing.T) { Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, }).Once() - // Mock GetPropertyMapsFromStore + // Mock getPropertyMapsFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -147,6 +147,7 @@ func TestSearchService_GlobalSearch(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, @@ -192,7 +193,7 @@ func TestSearchService_GlobalSearch(t *testing.T) { }, }, nil).Once() - // Mock GetTypeMapsFromStore + // Mock getTypeMapsFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -208,6 +209,7 @@ func TestSearchService_GlobalSearch(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyUniqueKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyPluralName.String(), bundle.RelationKeyIconEmoji.String(), @@ -229,7 +231,7 @@ func TestSearchService_GlobalSearch(t *testing.T) { }, }, nil).Once() - // Mock GetTagMapFromStore + // Mock getTagMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -438,7 +440,7 @@ func TestSearchService_Search(t *testing.T) { Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, }).Once() - // Mock GetPropertyMapsFromStore + // Mock getPropertyMapsFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -456,6 +458,7 @@ func TestSearchService_Search(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, @@ -501,7 +504,7 @@ func TestSearchService_Search(t *testing.T) { }, }, nil).Once() - // Mock GetTypeMapFromStore + // Mock getTypeMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -517,6 +520,7 @@ func TestSearchService_Search(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyUniqueKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyPluralName.String(), bundle.RelationKeyIconEmoji.String(), @@ -538,7 +542,7 @@ func TestSearchService_Search(t *testing.T) { }, }, nil).Once() - // Mock GetTagMapFromStore + // Mock getTagMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ diff --git a/core/api/service/service.go b/core/api/service/service.go index 05f559a8f..8f37aebfa 100644 --- a/core/api/service/service.go +++ b/core/api/service/service.go @@ -5,12 +5,11 @@ import ( ) type Service struct { - mw apicore.ClientCommands - exportService apicore.ExportService - gatewayUrl string - techSpaceId string + mw apicore.ClientCommands + gatewayUrl string + techSpaceId string } -func NewService(mw apicore.ClientCommands, exportService apicore.ExportService, gatewayUrl string, techspaceId string) *Service { - return &Service{mw: mw, exportService: exportService, gatewayUrl: gatewayUrl, techSpaceId: techspaceId} +func NewService(mw apicore.ClientCommands, gatewayUrl string, techspaceId string) *Service { + return &Service{mw: mw, gatewayUrl: gatewayUrl, techSpaceId: techspaceId} } diff --git a/core/api/service/service_test.go b/core/api/service/service_test.go index 9ab3d438b..ee3cfe756 100644 --- a/core/api/service/service_test.go +++ b/core/api/service/service_test.go @@ -28,19 +28,16 @@ const ( ) type fixture struct { - service *Service - mwMock *mock_apicore.MockClientCommands - exportService *mock_apicore.MockExportService + service *Service + mwMock *mock_apicore.MockClientCommands } func newFixture(t *testing.T) *fixture { mwMock := mock_apicore.NewMockClientCommands(t) - exportMock := mock_apicore.NewMockExportService(t) - service := NewService(mwMock, exportMock, gatewayUrl, techSpaceId) + service := NewService(mwMock, gatewayUrl, techSpaceId) return &fixture{ - service: service, - mwMock: mwMock, - exportService: exportMock, + service: service, + mwMock: mwMock, } } diff --git a/core/api/service/space.go b/core/api/service/space.go index 3d8643af7..82b3cb36d 100644 --- a/core/api/service/space.go +++ b/core/api/service/space.go @@ -73,7 +73,7 @@ func (s *Service) ListSpaces(ctx context.Context, offset int, limit int) (spaces spaces = make([]apimodel.Space, 0, len(paginatedRecords)) for _, record := range paginatedRecords { - workspace, err := s.getSpaceInfo(record.Fields[bundle.RelationKeyTargetSpaceId.String()].GetStringValue()) + workspace, err := s.getSpaceInfo(ctx, record.Fields[bundle.RelationKeyTargetSpaceId.String()].GetStringValue()) if err != nil { return nil, 0, false, err } @@ -117,7 +117,7 @@ func (s *Service) GetSpace(ctx context.Context, spaceId string) (apimodel.Space, return apimodel.Space{}, ErrWorkspaceNotFound } - return s.getSpaceInfo(spaceId) + return s.getSpaceInfo(ctx, spaceId) } // CreateSpace creates a new space with the given name and returns the space info. @@ -158,7 +158,7 @@ func (s *Service) CreateSpace(ctx context.Context, request apimodel.CreateSpaceR } } - return s.getSpaceInfo(resp.SpaceId) + return s.getSpaceInfo(ctx, resp.SpaceId) } // UpdateSpace updates the space with the given ID using the provided request. @@ -188,7 +188,7 @@ func (s *Service) UpdateSpace(ctx context.Context, spaceId string, request apimo } } - space, err := s.getSpaceInfo(spaceId) + space, err := s.getSpaceInfo(ctx, spaceId) if err != nil { return apimodel.Space{}, err } @@ -197,8 +197,8 @@ func (s *Service) UpdateSpace(ctx context.Context, spaceId string, request apimo } // getSpaceInfo returns the workspace info for the space with the given ID. -func (s *Service) getSpaceInfo(spaceId string) (space apimodel.Space, err error) { - workspaceResponse := s.mw.WorkspaceOpen(context.Background(), &pb.RpcWorkspaceOpenRequest{ +func (s *Service) getSpaceInfo(ctx context.Context, spaceId string) (space apimodel.Space, err error) { + workspaceResponse := s.mw.WorkspaceOpen(ctx, &pb.RpcWorkspaceOpenRequest{ SpaceId: spaceId, }) @@ -206,7 +206,7 @@ func (s *Service) getSpaceInfo(spaceId string) (space apimodel.Space, err error) return apimodel.Space{}, ErrFailedOpenWorkspace } - spaceResp := s.mw.ObjectShow(context.Background(), &pb.RpcObjectShowRequest{ + spaceResp := s.mw.ObjectShow(ctx, &pb.RpcObjectShowRequest{ SpaceId: spaceId, ObjectId: workspaceResponse.Info.WorkspaceObjectId, }) @@ -216,7 +216,7 @@ func (s *Service) getSpaceInfo(spaceId string) (space apimodel.Space, err error) } name := spaceResp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyName.String()].GetStringValue() - icon := apimodel.GetIcon(s.gatewayUrl, spaceResp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), spaceResp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconImage.String()].GetStringValue(), "", 0) + icon := GetIcon(s.gatewayUrl, spaceResp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), spaceResp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyIconImage.String()].GetStringValue(), "", 0) description := spaceResp.ObjectView.Details[0].Details.Fields[bundle.RelationKeyDescription.String()].GetStringValue() return apimodel.Space{ @@ -231,8 +231,8 @@ func (s *Service) getSpaceInfo(spaceId string) (space apimodel.Space, err error) } // GetAllSpaceIds effectively retrieves all space IDs from the tech space. -func (s *Service) GetAllSpaceIds() ([]string, error) { - resp := s.mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ +func (s *Service) GetAllSpaceIds(ctx context.Context) ([]string, error) { + resp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ SpaceId: s.techSpaceId, Filters: []*model.BlockContentDataviewFilter{ { diff --git a/core/api/service/tag.go b/core/api/service/tag.go index 24dd1cb9b..4440d3a3d 100644 --- a/core/api/service/tag.go +++ b/core/api/service/tag.go @@ -68,7 +68,7 @@ func (s *Service) ListTags(ctx context.Context, spaceId string, propertyId strin tags = make([]apimodel.Tag, 0, len(paginatedTags)) for _, record := range resp.Records { - tags = append(tags, s.mapTagFromRecord(record)) + tags = append(tags, s.getTagFromStruct(record)) } return tags, total, hasMore, nil @@ -95,7 +95,7 @@ func (s *Service) GetTag(ctx context.Context, spaceId string, propertyId string, } } - return s.mapTagFromRecord(resp.ObjectView.Details[0].Details), nil + return s.getTagFromStruct(resp.ObjectView.Details[0].Details), nil } // CreateTag creates a new tag option for a given property ID in a space. @@ -110,6 +110,7 @@ func (s *Service) CreateTag(ctx context.Context, spaceId string, propertyId stri bundle.RelationKeyRelationKey.String(): pbtypes.String(rk), bundle.RelationKeyName.String(): pbtypes.String(s.sanitizedString(request.Name)), bundle.RelationKeyRelationOptionColor.String(): pbtypes.String(apimodel.ColorToColorOption[request.Color]), + bundle.RelationKeyOrigin.String(): pbtypes.Int64(int64(model.ObjectOrigin_api)), }, } @@ -179,11 +180,11 @@ func (s *Service) DeleteTag(ctx context.Context, spaceId string, propertyId stri return tag, nil } -// GetTagMapsFromStore retrieves all tags for all spaces. -func (s *Service) GetTagMapsFromStore(spaceIds []string) (map[string]map[string]apimodel.Tag, error) { +// getTagMapsFromStore retrieves all tags for all spaces. +func (s *Service) getTagMapsFromStore(ctx context.Context, spaceIds []string) (map[string]map[string]apimodel.Tag, error) { spacesToTags := make(map[string]map[string]apimodel.Tag) for _, spaceId := range spaceIds { - tagMap, err := s.GetTagMapFromStore(spaceId) + tagMap, err := s.getTagMapFromStore(ctx, spaceId) if err != nil { return nil, err } @@ -192,9 +193,9 @@ func (s *Service) GetTagMapsFromStore(spaceIds []string) (map[string]map[string] return spacesToTags, nil } -// GetTagMapFromStore retrieves all tags for a specific space. -func (s *Service) GetTagMapFromStore(spaceId string) (map[string]apimodel.Tag, error) { - resp := s.mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ +// getTagMapFromStore retrieves all tags for a specific space. +func (s *Service) getTagMapFromStore(ctx context.Context, spaceId string) (map[string]apimodel.Tag, error) { + resp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ SpaceId: spaceId, Filters: []*model.BlockContentDataviewFilter{ { @@ -222,20 +223,21 @@ func (s *Service) GetTagMapFromStore(spaceId string) (map[string]apimodel.Tag, e tags := make(map[string]apimodel.Tag) for _, record := range resp.Records { - tag := s.mapTagFromRecord(record) + tag := s.getTagFromStruct(record) tags[tag.Id] = tag } return tags, nil } -func (s *Service) mapTagFromRecord(record *types.Struct) apimodel.Tag { +// getTagFromStruct converts a tag's details from a struct to an apimodel.Tag. +func (s *Service) getTagFromStruct(details *types.Struct) apimodel.Tag { return apimodel.Tag{ Object: "tag", - Id: record.Fields[bundle.RelationKeyId.String()].GetStringValue(), - Key: util.ToTagApiKey(record.Fields[bundle.RelationKeyUniqueKey.String()].GetStringValue()), - Name: record.Fields[bundle.RelationKeyName.String()].GetStringValue(), - Color: apimodel.ColorOptionToColor[record.Fields[bundle.RelationKeyRelationOptionColor.String()].GetStringValue()], + Id: details.Fields[bundle.RelationKeyId.String()].GetStringValue(), + Key: util.ToTagApiKey(details.Fields[bundle.RelationKeyUniqueKey.String()].GetStringValue()), + Name: details.Fields[bundle.RelationKeyName.String()].GetStringValue(), + Color: apimodel.ColorOptionToColor[details.Fields[bundle.RelationKeyRelationOptionColor.String()].GetStringValue()], } } diff --git a/core/api/service/template.go b/core/api/service/template.go index b3431039d..61b87ab49 100644 --- a/core/api/service/template.go +++ b/core/api/service/template.go @@ -42,7 +42,7 @@ func (s *Service) ListTemplates(ctx context.Context, spaceId string, typeId stri return nil, 0, false, ErrTemplateTypeNotFound } - // Then, search all objects of the template type and filter by the target object type + // Then, search all objects of the template type and filter by the target type templateTypeId := templateTypeIdResp.Records[0].Fields[bundle.RelationKeyId.String()].GetStringValue() templateObjectsResp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ SpaceId: spaceId, @@ -68,21 +68,21 @@ func (s *Service) ListTemplates(ctx context.Context, spaceId string, typeId stri paginatedTemplates, hasMore := pagination.Paginate(templateObjectsResp.Records, offset, limit) templates = make([]apimodel.Object, 0, len(paginatedTemplates)) - propertyMap, err := s.GetPropertyMapFromStore(spaceId) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) if err != nil { return nil, 0, false, err } - typeMap, err := s.GetTypeMapFromStore(spaceId, propertyMap) + typeMap, err := s.getTypeMapFromStore(ctx, spaceId, propertyMap, false) if err != nil { return nil, 0, false, err } - tagMap, err := s.GetTagMapFromStore(spaceId) + tagMap, err := s.getTagMapFromStore(ctx, spaceId) if err != nil { return nil, 0, false, err } for _, record := range paginatedTemplates { - templates = append(templates, s.GetObjectFromStruct(record, propertyMap, typeMap, tagMap)) + templates = append(templates, s.getObjectFromStruct(record, propertyMap, typeMap, tagMap)) } return templates, total, hasMore, nil @@ -109,15 +109,15 @@ func (s *Service) GetTemplate(ctx context.Context, spaceId string, _ string, tem } } - propertyMap, err := s.GetPropertyMapFromStore(spaceId) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) if err != nil { return apimodel.ObjectWithBody{}, err } - typeMap, err := s.GetTypeMapFromStore(spaceId, propertyMap) + typeMap, err := s.getTypeMapFromStore(ctx, spaceId, propertyMap, false) if err != nil { return apimodel.ObjectWithBody{}, err } - tagMap, err := s.GetTagMapFromStore(spaceId) + tagMap, err := s.getTagMapFromStore(ctx, spaceId) if err != nil { return apimodel.ObjectWithBody{}, err } @@ -127,5 +127,5 @@ func (s *Service) GetTemplate(ctx context.Context, spaceId string, _ string, tem return apimodel.ObjectWithBody{}, err } - return s.GetObjectWithBlocksFromStruct(resp.ObjectView.Details[0].Details, markdown, propertyMap, typeMap, tagMap), nil + return s.getObjectWithBlocksFromStruct(resp.ObjectView.Details[0].Details, markdown, propertyMap, typeMap, tagMap), nil } diff --git a/core/api/service/template_test.go b/core/api/service/template_test.go index ea85d5a81..e93c7d1b8 100644 --- a/core/api/service/template_test.go +++ b/core/api/service/template_test.go @@ -49,7 +49,7 @@ func TestObjectService_ListTemplates(t *testing.T) { Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, }).Once() - // Mock GetPropertyMapFromStore, GetTypeMapFromStore and GetTagMapFromStore + // Mock getPropertyMapFromStore, getTypeMapFromStore and getTagMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, mock.Anything).Return(&pb.RpcObjectSearchResponse{ Records: []*types.Struct{}, Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, @@ -121,16 +121,21 @@ func TestObjectService_GetTemplate(t *testing.T) { }, }).Once() - // Mock GetPropertyMapFromStore, GetTypeMapFromStore and GetTagMapFromStore + // Mock getPropertyMapFromStore, getTypeMapFromStore and getTagMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, mock.Anything).Return(&pb.RpcObjectSearchResponse{ Records: []*types.Struct{}, Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, }).Times(3) // Mock ExportMarkdown - fx.exportService. - On("ExportSingleInMemory", mock.Anything, mockedSpaceId, mockedTemplateId, model.Export_Markdown). - Return("dummy markdown", nil).Once() + fx.mwMock.On("ObjectExport", mock.Anything, &pb.RpcObjectExportRequest{ + SpaceId: mockedSpaceId, + ObjectId: mockedTemplateId, + Format: model.Export_Markdown, + }).Return(&pb.RpcObjectExportResponse{ + Result: "dummy markdown", + Error: &pb.RpcObjectExportResponseError{Code: pb.RpcObjectExportResponseError_NULL}, + }, nil).Once() // when template, err := fx.service.GetTemplate(ctx, mockedSpaceId, mockedTypeId, mockedTemplateId) diff --git a/core/api/service/type.go b/core/api/service/type.go index d1b33fec5..0f1b04cb5 100644 --- a/core/api/service/type.go +++ b/core/api/service/type.go @@ -3,8 +3,10 @@ package service import ( "context" "errors" + "fmt" "github.com/gogo/protobuf/types" + "github.com/iancoleman/strcase" apimodel "github.com/anyproto/anytype-heart/core/api/model" "github.com/anyproto/anytype-heart/core/api/pagination" @@ -53,6 +55,7 @@ func (s *Service) ListTypes(ctx context.Context, spaceId string, offset int, lim Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyUniqueKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyIconEmoji.String(), bundle.RelationKeyIconName.String(), @@ -72,13 +75,14 @@ func (s *Service) ListTypes(ctx context.Context, spaceId string, offset int, lim paginatedTypes, hasMore := pagination.Paginate(resp.Records, offset, limit) types = make([]apimodel.Type, 0, len(paginatedTypes)) - propertyMap, err := s.GetPropertyMapFromStore(spaceId) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) if err != nil { return nil, 0, false, err } for _, record := range paginatedTypes { - types = append(types, s.getTypeFromStruct(record, propertyMap)) + _, _, t := s.getTypeFromStruct(record, propertyMap) + types = append(types, t) } return types, total, hasMore, nil } @@ -105,16 +109,32 @@ func (s *Service) GetType(ctx context.Context, spaceId string, typeId string) (a } // pre-fetch properties to fill the type - propertyMap, err := s.GetPropertyMapFromStore(spaceId) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) if err != nil { return apimodel.Type{}, err } - return s.getTypeFromStruct(resp.ObjectView.Details[0].Details, propertyMap), nil + _, _, t := s.getTypeFromStruct(resp.ObjectView.Details[0].Details, propertyMap) + return t, nil } // CreateType creates a new type in a specific space. func (s *Service) CreateType(ctx context.Context, spaceId string, request apimodel.CreateTypeRequest) (apimodel.Type, error) { + if request.Key != "" { + newKey := strcase.ToSnake(s.sanitizedString(request.Key)) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) + if err != nil { + return apimodel.Type{}, err + } + typeMap, err := s.getTypeMapFromStore(ctx, spaceId, propertyMap, true) + if err != nil { + return apimodel.Type{}, err + } + if _, exists := typeMap[newKey]; exists { + return apimodel.Type{}, util.ErrBadInput(fmt.Sprintf("type key %q already exists", newKey)) + } + } + details, err := s.buildTypeDetails(ctx, spaceId, request) if err != nil { return apimodel.Type{}, err @@ -134,12 +154,12 @@ func (s *Service) CreateType(ctx context.Context, spaceId string, request apimod // UpdateType updates an existing type in a specific space. func (s *Service) UpdateType(ctx context.Context, spaceId string, typeId string, request apimodel.UpdateTypeRequest) (apimodel.Type, error) { - _, err := s.GetType(ctx, spaceId, typeId) + t, err := s.GetType(ctx, spaceId, typeId) if err != nil { return apimodel.Type{}, err } - details, err := s.buildUpdatedTypeDetails(ctx, spaceId, typeId, request) + details, err := s.buildUpdatedTypeDetails(ctx, spaceId, t, request) if err != nil { return apimodel.Type{}, err } @@ -175,12 +195,13 @@ func (s *Service) DeleteType(ctx context.Context, spaceId string, typeId string) return t, nil } -// GetTypeMapsFromStore retrieves all types from all spaces. -func (s *Service) GetTypeMapsFromStore(spaceIds []string, propertyMap map[string]map[string]apimodel.Property) (map[string]map[string]apimodel.Type, error) { - spacesToTypes := make(map[string]map[string]apimodel.Type, len(spaceIds)) +// getTypeMapsFromStore retrieves all types from all spaces. +// Type entries can also be keyed by uniqueKey. Required for resolving type keys to IDs for search filters. +func (s *Service) getTypeMapsFromStore(ctx context.Context, spaceIds []string, propertyMap map[string]map[string]*apimodel.Property, keyByUniqueKey bool) (map[string]map[string]*apimodel.Type, error) { + spacesToTypes := make(map[string]map[string]*apimodel.Type, len(spaceIds)) for _, spaceId := range spaceIds { - typeMap, err := s.GetTypeMapFromStore(spaceId, propertyMap[spaceId]) + typeMap, err := s.getTypeMapFromStore(ctx, spaceId, propertyMap[spaceId], keyByUniqueKey) if err != nil { return nil, err } @@ -190,9 +211,10 @@ func (s *Service) GetTypeMapsFromStore(spaceIds []string, propertyMap map[string return spacesToTypes, nil } -// GetTypeMapFromStore retrieves all types for a specific space. -func (s *Service) GetTypeMapFromStore(spaceId string, propertyMap map[string]apimodel.Property) (map[string]apimodel.Type, error) { - resp := s.mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ +// getTypeMapFromStore retrieves all types for a specific space. +// Type entries can also be keyed by uniqueKey. Required for resolving type keys to IDs for search filters. +func (s *Service) getTypeMapFromStore(ctx context.Context, spaceId string, propertyMap map[string]*apimodel.Property, keyByUniqueKey bool) (map[string]*apimodel.Type, error) { + resp := s.mw.ObjectSearch(ctx, &pb.RpcObjectSearchRequest{ SpaceId: spaceId, Filters: []*model.BlockContentDataviewFilter{ { @@ -208,6 +230,7 @@ func (s *Service) GetTypeMapFromStore(spaceId string, propertyMap map[string]api Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyUniqueKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyPluralName.String(), bundle.RelationKeyIconEmoji.String(), @@ -224,43 +247,68 @@ func (s *Service) GetTypeMapFromStore(spaceId string, propertyMap map[string]api return nil, ErrFailedRetrieveTypes } - typeMap := make(map[string]apimodel.Type, len(resp.Records)) + typeMap := make(map[string]*apimodel.Type, len(resp.Records)) for _, record := range resp.Records { - t := s.getTypeFromStruct(record, propertyMap) - typeMap[t.Id] = t + uk, key, t := s.getTypeFromStruct(record, propertyMap) + ot := t + typeMap[t.Id] = &ot + if keyByUniqueKey { + typeMap[key] = &ot + typeMap[uk] = &ot + } } return typeMap, nil } -// getTypeFromStruct builds an apimodel.Type from the provided fields map and propertyMap. -func (s *Service) getTypeFromStruct(details *types.Struct, propertyMap map[string]apimodel.Property) apimodel.Type { - return apimodel.Type{ +// getTypeFromStruct maps a type's details into an apimodel.Type. +// `uk` is what we use internally, `key` is the key being referenced in the API. +func (s *Service) getTypeFromStruct(details *types.Struct, propertyMap map[string]*apimodel.Property) (string, string, apimodel.Type) { + uk := details.Fields[bundle.RelationKeyUniqueKey.String()].GetStringValue() + key := util.ToTypeApiKey(uk) + + // apiId as key takes precedence over unique key + if apiIDField, exists := details.Fields[bundle.RelationKeyApiObjectKey.String()]; exists { + if apiId := apiIDField.GetStringValue(); apiId != "" { + key = apiId + } + } + + return uk, key, apimodel.Type{ Object: "type", Id: details.Fields[bundle.RelationKeyId.String()].GetStringValue(), - Key: util.ToTypeApiKey(details.Fields[bundle.RelationKeyUniqueKey.String()].GetStringValue()), + Key: key, Name: details.Fields[bundle.RelationKeyName.String()].GetStringValue(), PluralName: details.Fields[bundle.RelationKeyPluralName.String()].GetStringValue(), - Icon: apimodel.GetIcon(s.gatewayUrl, details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), "", details.Fields[bundle.RelationKeyIconName.String()].GetStringValue(), details.Fields[bundle.RelationKeyIconOption.String()].GetNumberValue()), + Icon: GetIcon(s.gatewayUrl, details.Fields[bundle.RelationKeyIconEmoji.String()].GetStringValue(), "", details.Fields[bundle.RelationKeyIconName.String()].GetStringValue(), details.Fields[bundle.RelationKeyIconOption.String()].GetNumberValue()), Archived: details.Fields[bundle.RelationKeyIsArchived.String()].GetBoolValue(), Layout: s.otLayoutToObjectLayout(model.ObjectTypeLayout(details.Fields[bundle.RelationKeyRecommendedLayout.String()].GetNumberValue())), Properties: s.getRecommendedPropertiesFromLists(details.Fields[bundle.RelationKeyRecommendedFeaturedRelations.String()].GetListValue(), details.Fields[bundle.RelationKeyRecommendedRelations.String()].GetListValue(), propertyMap), + UniqueKey: uk, // internal only for simplified lookup } } // getTypeFromMap retrieves the type from the details. -func (s *Service) getTypeFromMap(details *types.Struct, typeMap map[string]apimodel.Type) apimodel.Type { - return typeMap[details.Fields[bundle.RelationKeyType.String()].GetStringValue()] +func (s *Service) getTypeFromMap(details *types.Struct, typeMap map[string]*apimodel.Type) apimodel.Type { + if t, ok := typeMap[details.Fields[bundle.RelationKeyType.String()].GetStringValue()]; ok { + return *t + } + return apimodel.Type{} } // buildTypeDetails builds the type details from the CreateTypeRequest. func (s *Service) buildTypeDetails(ctx context.Context, spaceId string, request apimodel.CreateTypeRequest) (*types.Struct, error) { - fields := make(map[string]*types.Value) + fields := map[string]*types.Value{ + bundle.RelationKeyName.String(): pbtypes.String(s.sanitizedString(request.Name)), + bundle.RelationKeyPluralName.String(): pbtypes.String(s.sanitizedString(request.PluralName)), + bundle.RelationKeyRecommendedLayout.String(): pbtypes.Int64(int64(s.typeLayoutToObjectTypeLayout(request.Layout))), + bundle.RelationKeyOrigin.String(): pbtypes.Int64(int64(model.ObjectOrigin_api)), + } - fields[bundle.RelationKeyName.String()] = pbtypes.String(s.sanitizedString(request.Name)) - fields[bundle.RelationKeyPluralName.String()] = pbtypes.String(s.sanitizedString(request.PluralName)) - fields[bundle.RelationKeyRecommendedLayout.String()] = pbtypes.Int64(int64(s.typeLayoutToObjectTypeLayout(request.Layout))) + if request.Key != "" { + fields[bundle.RelationKeyApiObjectKey.String()] = pbtypes.String(strcase.ToSnake(s.sanitizedString(request.Key))) + } - iconFields, err := s.processIconFields(ctx, spaceId, request.Icon) + iconFields, err := s.processIconFields(spaceId, request.Icon, true) if err != nil { return nil, err } @@ -268,7 +316,7 @@ func (s *Service) buildTypeDetails(ctx context.Context, spaceId string, request fields[k] = v } - propertyMap, err := s.GetPropertyMapFromStore(spaceId) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) if err != nil { return nil, err } @@ -309,7 +357,7 @@ func (s *Service) buildTypeDetails(ctx context.Context, spaceId string, request } // buildUpdatedTypeDetails builds a partial details struct for UpdateTypeRequest. -func (s *Service) buildUpdatedTypeDetails(ctx context.Context, spaceId string, typeId string, request apimodel.UpdateTypeRequest) (*types.Struct, error) { +func (s *Service) buildUpdatedTypeDetails(ctx context.Context, spaceId string, t apimodel.Type, request apimodel.UpdateTypeRequest) (*types.Struct, error) { fields := make(map[string]*types.Value) if request.Name != nil { fields[bundle.RelationKeyName.String()] = pbtypes.String(s.sanitizedString(*request.Name)) @@ -320,9 +368,27 @@ func (s *Service) buildUpdatedTypeDetails(ctx context.Context, spaceId string, t if request.Layout != nil { fields[bundle.RelationKeyRecommendedLayout.String()] = pbtypes.Int64(int64(s.typeLayoutToObjectTypeLayout(*request.Layout))) } + if request.Key != nil { + newKey := strcase.ToSnake(s.sanitizedString(*request.Key)) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) + if err != nil { + return nil, err + } + typeMap, err := s.getTypeMapFromStore(ctx, spaceId, propertyMap, true) + if err != nil { + return nil, err + } + if existing, exists := typeMap[newKey]; exists && existing.Id != t.Id { + return nil, util.ErrBadInput(fmt.Sprintf("type key %q already exists", newKey)) + } + if bundle.HasObjectTypeByKey(domain.TypeKey(util.ToTypeApiKey(t.UniqueKey))) { + return nil, util.ErrBadInput("type key of bundled types cannot be changed") + } + fields[bundle.RelationKeyApiObjectKey.String()] = pbtypes.String(newKey) + } if request.Icon != nil { - iconFields, err := s.processIconFields(ctx, spaceId, *request.Icon) + iconFields, err := s.processIconFields(spaceId, *request.Icon, true) if err != nil { return nil, err } @@ -335,12 +401,12 @@ func (s *Service) buildUpdatedTypeDetails(ctx context.Context, spaceId string, t return &types.Struct{Fields: fields}, nil } - propertyMap, err := s.GetPropertyMapFromStore(spaceId) + propertyMap, err := s.getPropertyMapFromStore(ctx, spaceId, true) if err != nil { return nil, err } - currentFields, err := util.GetFieldsByID(s.mw, spaceId, typeId, []string{bundle.RelationKeyRecommendedFeaturedRelations.String()}) + currentFields, err := util.GetFieldsByID(s.mw, spaceId, t.Id, []string{bundle.RelationKeyRecommendedFeaturedRelations.String()}) if err != nil { return nil, err } @@ -378,10 +444,10 @@ func (s *Service) buildUpdatedTypeDetails(ctx context.Context, spaceId string, t } // buildRelationIds constructs relation IDs for property links, creating new properties if necessary. -func (s *Service) buildRelationIds(ctx context.Context, spaceId string, props []apimodel.PropertyLink, propertyMap map[string]apimodel.Property) ([]string, error) { +func (s *Service) buildRelationIds(ctx context.Context, spaceId string, props []apimodel.PropertyLink, propertyMap map[string]*apimodel.Property) ([]string, error) { relationIds := make([]string, 0, len(props)) for _, propLink := range props { - rk := util.FromPropertyApiKey(propLink.Key) + rk := s.ResolvePropertyApiKey(propertyMap, propLink.Key) if propDef, exists := propertyMap[rk]; exists { relationIds = append(relationIds, propDef.Id) continue @@ -398,27 +464,15 @@ func (s *Service) buildRelationIds(ctx context.Context, spaceId string, props [] return relationIds, nil } -func (s *Service) objectLayoutToObjectTypeLayout(objectLayout apimodel.ObjectLayout) model.ObjectTypeLayout { - switch objectLayout { - case apimodel.ObjectLayoutBasic: - return model.ObjectType_basic - case apimodel.ObjectLayoutProfile: - return model.ObjectType_profile - case apimodel.ObjectLayoutAction: - return model.ObjectType_todo - case apimodel.ObjectLayoutNote: - return model.ObjectType_note - case apimodel.ObjectLayoutBookmark: - return model.ObjectType_bookmark - case apimodel.ObjectLayoutSet: - return model.ObjectType_set - case apimodel.ObjectLayoutCollection: - return model.ObjectType_collection - case apimodel.ObjectLayoutParticipant: - return model.ObjectType_participant - default: - return model.ObjectType_basic +// ResolveTypeApiKey returns the internal uniqueKey for a clientKey by looking it up in the typeMap +// TODO: If not found, this detail shouldn't be set by clients, and strict validation errors +func (s *Service) ResolveTypeApiKey(typeMap map[string]*apimodel.Type, clientKey string) string { + if p, ok := typeMap[clientKey]; ok { + return p.UniqueKey } + return "" + // TODO: enable later for strict validation + // return "", false } func (s *Service) otLayoutToObjectLayout(objectTypeLayout model.ObjectTypeLayout) apimodel.ObjectLayout { @@ -458,18 +512,3 @@ func (s *Service) typeLayoutToObjectTypeLayout(typeLayout apimodel.TypeLayout) m return model.ObjectType_basic } } - -func (s *Service) otLayoutToTypeLayout(objectTypeLayout model.ObjectTypeLayout) apimodel.TypeLayout { - switch objectTypeLayout { - case model.ObjectType_basic: - return apimodel.TypeLayoutBasic - case model.ObjectType_profile: - return apimodel.TypeLayoutProfile - case model.ObjectType_todo: - return apimodel.TypeLayoutAction - case model.ObjectType_note: - return apimodel.TypeLayoutNote - default: - return apimodel.TypeLayoutBasic - } -} diff --git a/core/api/service/type_test.go b/core/api/service/type_test.go index 9ca64887b..5f2ea4e55 100644 --- a/core/api/service/type_test.go +++ b/core/api/service/type_test.go @@ -36,7 +36,7 @@ func TestObjectService_ListTypes(t *testing.T) { Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, }).Once() - // Mock GetPropertyMapFromStore + // Mock getPropertyMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -54,6 +54,7 @@ func TestObjectService_ListTypes(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, @@ -92,7 +93,7 @@ func TestObjectService_ListTypes(t *testing.T) { Error: &pb.RpcObjectSearchResponseError{Code: pb.RpcObjectSearchResponseError_NULL}, }).Once() - // Mock GetPropertyMapFromStore + // Mock getPropertyMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: "empty-space", Filters: []*model.BlockContentDataviewFilter{ @@ -110,6 +111,7 @@ func TestObjectService_ListTypes(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, @@ -157,7 +159,7 @@ func TestObjectService_GetType(t *testing.T) { }, }).Once() - // Mock GetPropertyMapFromStore + // Mock getPropertyMapFromStore fx.mwMock.On("ObjectSearch", mock.Anything, &pb.RpcObjectSearchRequest{ SpaceId: mockedSpaceId, Filters: []*model.BlockContentDataviewFilter{ @@ -175,6 +177,7 @@ func TestObjectService_GetType(t *testing.T) { Keys: []string{ bundle.RelationKeyId.String(), bundle.RelationKeyRelationKey.String(), + bundle.RelationKeyApiObjectKey.String(), bundle.RelationKeyName.String(), bundle.RelationKeyRelationFormat.String(), }, diff --git a/core/api/util/analytics.go b/core/api/util/analytics.go new file mode 100644 index 000000000..f3eb48077 --- /dev/null +++ b/core/api/util/analytics.go @@ -0,0 +1,51 @@ +package util + +import ( + "context" + "encoding/json" + "fmt" +) + +type AnalyticsBroadcastEvent struct { + Type string `json:"type"` + Code string `json:"code"` + Param struct { + Route string `json:"route"` + ApiAppName string `json:"apiAppName"` + Status int `json:"status"` + } `json:"param"` +} + +// ToJSON returns the event as a JSON string +func (e *AnalyticsBroadcastEvent) ToJSON() (string, error) { + eventJSON, err := json.Marshal(e) + if err != nil { + return "", fmt.Errorf("error marshalling analytics event: %w", err) + } + return string(eventJSON), nil +} + +// NewAnalyticsEvent creates a new analytics event with the given code, route and apiAppName +func NewAnalyticsEvent(code, route, apiAppName string, status int) *AnalyticsBroadcastEvent { + return &AnalyticsBroadcastEvent{ + Type: "analyticsEvent", + Code: code, + Param: struct { + Route string `json:"route"` + ApiAppName string `json:"apiAppName"` + Status int `json:"status"` + }{ + Route: route, + ApiAppName: apiAppName, + Status: status, + }, + } +} + +// NewAnalyticsEventForApi creates a new analytics event for api with the app name from the context +func NewAnalyticsEventForApi(ctx context.Context, code string, status int) (string, error) { + // TODO: enable when apiAppName is available in context + // apiAppName := ctx.Value("apiAppName").(string) + apiAppName := "api-app" + return NewAnalyticsEvent(code, "api", apiAppName, status).ToJSON() +} diff --git a/core/api/util/key.go b/core/api/util/key.go index 8a7ded422..feeb0507d 100644 --- a/core/api/util/key.go +++ b/core/api/util/key.go @@ -1,14 +1,15 @@ package util import ( + "regexp" "strings" "github.com/iancoleman/strcase" ) // Internal -> API -// "rel-dueDate" -> "due_date" -// "rel-67b0d3e3cda913b84c1299b1" -> "67b0d3e3cda913b84c1299b1" +// "dueDate" -> "due_date" +// "67b0d3e3cda913b84c1299b1" -> "67b0d3e3cda913b84c1299b1" // "ot-page" -> "page" // "ot-67b0d3e3cda913b84c1299b1" -> "67b0d3e3cda913b84c1299b1" // "opt-67b0d3e3cda913b84c1299b1" -> "67b0d3e3cda913b84c1299b1" @@ -17,61 +18,41 @@ const ( propPrefix = "" typePrefix = "" tagPrefix = "" - internalRelationPrefix = "rel-" + internalRelationPrefix = "" // internally, we're using rk instead of uk when working with relations from api, where no "rel-" prefix exists internalObjectTypePrefix = "ot-" internalRelationOptionPrefix = "opt-" ) +var ( + hex24Pattern = regexp.MustCompile(`^[a-f\d]{24}$`) + digitPattern = regexp.MustCompile(`\d`) +) + func ToPropertyApiKey(internalKey string) string { return toApiKey(propPrefix, internalRelationPrefix, internalKey) } -func FromPropertyApiKey(apiKey string) string { - return fromApiKey(propPrefix, "", apiKey) // interally, we don't prefix relation keys -} - func ToTypeApiKey(internalKey string) string { return toApiKey(typePrefix, internalObjectTypePrefix, internalKey) } -func FromTypeApiKey(apiKey string) string { - return fromApiKey(typePrefix, internalObjectTypePrefix, apiKey) -} - func ToTagApiKey(internalKey string) string { return toApiKey(tagPrefix, internalRelationOptionPrefix, internalKey) } -func FromTagApiKey(apiKey string) string { - return fromApiKey(tagPrefix, internalRelationOptionPrefix, apiKey) -} - -// IsCustomPropertyKey returns true if key is exactly 24 letters and contains at least a digit. -// Non-custom properties never contain a digit. -func IsCustomPropertyKey(key string) bool { - if len(key) != 24 && !strings.ContainsAny(key, "0123456789") { - return false - } - return true +// IsCustomKey returns true if key is exactly 24 letters and contains at least a digit. +func IsCustomKey(key string) bool { + return len(key) == 24 && hex24Pattern.MatchString(key) && digitPattern.MatchString(key) } // toApiKey converts an internal key into API format by stripping any existing internal prefixes and adding the API prefix. func toApiKey(prefix, internalPrefix, internalKey string) string { var k string internalKey = strings.TrimPrefix(internalKey, internalPrefix) - if IsCustomPropertyKey(internalKey) { + if IsCustomKey(internalKey) { k = internalKey } else { k = strcase.ToSnake(internalKey) } return prefix + k } - -// fromApiKey converts an API key back into internal format by stripping the API prefix and re-adding the internal prefix. -func fromApiKey(prefix, internalPrefix, apiKey string) string { - k := strings.TrimPrefix(apiKey, prefix) - if IsCustomPropertyKey(k) { - return internalPrefix + k - } - return internalPrefix + strcase.ToLowerCamel(k) -} diff --git a/core/api/util/util.go b/core/api/util/util.go index b1c955ad2..9fc0394b5 100644 --- a/core/api/util/util.go +++ b/core/api/util/util.go @@ -15,7 +15,6 @@ import ( ) var ( - ErrFailedSearchType = errors.New("failed to search for type") ErrFailedResolveToUniqueKey = errors.New("failed to resolve to unique key") ErrFailedGetById = errors.New("failed to get object by id") ErrFailedGetByIdNotFound = errors.New("failed to find object by id") @@ -23,33 +22,6 @@ var ( ErrRelationKeysNotFound = errors.New("failed to find relation keys") ) -// ResolveUniqueKeyToTypeId resolves the unique key to the type's ID -func ResolveUniqueKeyToTypeId(mw apicore.ClientCommands, spaceId string, uniqueKey string) (typeId string, err error) { - resp := mw.ObjectSearch(context.Background(), &pb.RpcObjectSearchRequest{ - SpaceId: spaceId, - Filters: []*model.BlockContentDataviewFilter{ - { - RelationKey: bundle.RelationKeyUniqueKey.String(), - Condition: model.BlockContentDataviewFilter_Equal, - Value: pbtypes.String(uniqueKey), - }, - }, - Keys: []string{bundle.RelationKeyId.String()}, - }) - - if resp.Error != nil { - if resp.Error != nil && resp.Error.Code != pb.RpcObjectSearchResponseError_NULL { - return "", ErrFailedSearchType - } - - if len(resp.Records) == 0 { - return "", ErrFailedSearchType - } - } - - return resp.Records[0].Fields[bundle.RelationKeyId.String()].GetStringValue(), nil -} - // ResolveIdtoUniqueKeyAndRelationKey resolves the type's ID to the unique key func ResolveIdtoUniqueKeyAndRelationKey(mw apicore.ClientCommands, spaceId string, objectId string) (uk string, rk string, err error) { resp := mw.ObjectShow(context.Background(), &pb.RpcObjectShowRequest{ diff --git a/core/application/application.go b/core/application/application.go index 293ceef8b..63248f91d 100644 --- a/core/application/application.go +++ b/core/application/application.go @@ -8,6 +8,7 @@ import ( "github.com/anyproto/any-sync/app" + "github.com/anyproto/anytype-heart/core/domain" "github.com/anyproto/anytype-heart/core/event" "github.com/anyproto/anytype-heart/core/session" "github.com/anyproto/anytype-heart/pkg/lib/logging" @@ -24,6 +25,7 @@ type Service struct { // memoized private key derived from mnemonic, used for signing session tokens sessionSigningKey []byte + sessionsByAppHash map[string]string rootPath string fulltextPrimaryLanguage string @@ -39,8 +41,9 @@ type Service struct { func New() *Service { s := &Service{ - sessions: session.New(), - traceRecorder: &traceRecorder{}, + sessions: session.New(), + traceRecorder: &traceRecorder{}, + sessionsByAppHash: make(map[string]string), } m := newMigrationManager(s) s.migrationManager = m @@ -70,6 +73,8 @@ func (s *Service) stop() error { defer task.End() if s != nil && s.app != nil { + log.Warnf("stopping app") + s.app.SetDeviceState(int(domain.CompStateAppClosingInitiated)) err := s.app.Close(ctx) if err != nil { log.Warnf("error while stop anytype: %v", err) diff --git a/core/application/sessions.go b/core/application/sessions.go index f9e492108..75210a2a6 100644 --- a/core/application/sessions.go +++ b/core/application/sessions.go @@ -3,7 +3,6 @@ package application import ( "errors" "fmt" - "time" "github.com/anyproto/anytype-heart/core/event" "github.com/anyproto/anytype-heart/core/session" @@ -32,11 +31,14 @@ func (s *Service) CreateSession(req *pb.RpcWalletCreateSessionRequest) (token st return "", "", err } log.Infof("appLink auth %s", appLink.AppName) - token, err := s.sessions.StartSession(s.sessionSigningKey, model.AccountAuthLocalApiScope(appLink.Scope)) // nolint:gosec if err != nil { return "", "", err } + s.lock.Lock() + defer s.lock.Unlock() + s.sessionsByAppHash[appLink.AppHash] = token + return token, w.Account().SignKey.GetPublic().Account(), nil } @@ -94,14 +96,21 @@ func (s *Service) LinkLocalSolveChallenge(req *pb.RpcAccountLocalLinkSolveChalle if err != nil { return "", "", err } - wallet := s.app.Component(walletComp.CName).(walletComp.Wallet) - appKey, err = wallet.PersistAppLink(&walletComp.AppLinkPayload{ - AppName: clientInfo.ProcessName, - AppPath: clientInfo.ProcessPath, - CreatedAt: time.Now().Unix(), - Scope: int(scope), - }) + wallet := s.app.Component(walletComp.CName).(walletComp.Wallet) + name := clientInfo.Name + if name == "" { + name = clientInfo.ProcessName + } + appInfo, err := wallet.PersistAppLink(name, scope) + if err != nil { + return token, appKey, err + } + + s.lock.Lock() + s.sessionsByAppHash[appInfo.AppHash] = token + s.lock.Unlock() + appKey = appInfo.AppKey s.eventSender.Broadcast(event.NewEventSingleMessage("", &pb.EventMessageValueOfAccountLinkChallengeHide{ AccountLinkChallengeHide: &pb.EventAccountLinkChallengeHide{ Challenge: req.Answer, @@ -109,3 +118,70 @@ func (s *Service) LinkLocalSolveChallenge(req *pb.RpcAccountLocalLinkSolveChalle })) return } + +func (s *Service) LinkLocalCreateApp(req *pb.RpcAccountLocalLinkCreateAppRequest) (appKey string, err error) { + if s.app == nil { + return "", ErrApplicationIsNotRunning + } + + wallet := s.app.Component(walletComp.CName).(walletComp.Wallet) + appInfo, err := wallet.PersistAppLink(req.App.AppName, req.App.Scope) + return appInfo.AppKey, err +} + +func (s *Service) LinkLocalListApps() ([]*model.AccountAuthAppInfo, error) { + if s.app == nil { + return nil, ErrApplicationIsNotRunning + } + + wallet := s.app.Component(walletComp.CName).(walletComp.Wallet) + links, err := wallet.ListAppLinks() + if err != nil { + return nil, err + } + appsList := make([]*model.AccountAuthAppInfo, len(links)) + s.lock.RLock() + defer s.lock.RUnlock() + + for i, app := range links { + if app.AppName == "" { + app.AppName = app.AppHash + } + _, isActive := s.sessionsByAppHash[app.AppHash] + appsList[i] = &model.AccountAuthAppInfo{ + AppHash: app.AppHash, + AppName: app.AppName, + AppKey: app.AppKey, + CreatedAt: app.CreatedAt, + ExpireAt: app.ExpireAt, + Scope: model.AccountAuthLocalApiScope(app.Scope), + IsActive: isActive, + } + } + return appsList, nil +} + +func (s *Service) LinkLocalRevokeApp(req *pb.RpcAccountLocalLinkRevokeAppRequest) error { + if s.app == nil { + return ErrApplicationIsNotRunning + } + + wallet := s.app.Component(walletComp.CName).(walletComp.Wallet) + err := wallet.RevokeAppLink(req.AppHash) + if err != nil { + return err + } + + s.lock.Lock() + defer s.lock.Unlock() + if token, ok := s.sessionsByAppHash[req.AppHash]; ok { + delete(s.sessionsByAppHash, req.AppHash) + closeErr := s.sessions.CloseSession(token) + if closeErr != nil { + log.Errorf("error while closing session: %v", err) + } + } + + return err + +} diff --git a/core/block/editor/chatobject/message.go b/core/block/chats/chatmodel/chatmodel.go similarity index 75% rename from core/block/editor/chatobject/message.go rename to core/block/chats/chatmodel/chatmodel.go index e5a6e41de..20f417365 100644 --- a/core/block/editor/chatobject/message.go +++ b/core/block/chats/chatmodel/chatmodel.go @@ -1,4 +1,4 @@ -package chatobject +package chatmodel import ( "context" @@ -9,17 +9,40 @@ import ( "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) +type CounterType int + const ( - creatorKey = "creator" - createdAtKey = "createdAt" - modifiedAtKey = "modifiedAt" - reactionsKey = "reactions" - contentKey = "content" - readKey = "read" - mentionReadKey = "mentionRead" - hasMentionKey = "hasMention" - stateIdKey = "stateId" - orderKey = "_o" + CounterTypeMessage = CounterType(iota) + CounterTypeMention +) + +const ( + DiffManagerMessages = "messages" + DiffManagerMentions = "mentions" +) + +func (t CounterType) DiffManagerName() string { + switch t { + case CounterTypeMessage: + return DiffManagerMessages + case CounterTypeMention: + return DiffManagerMentions + default: + return "unknown" + } +} + +const ( + CreatorKey = "creator" + CreatedAtKey = "createdAt" + ModifiedAtKey = "modifiedAt" + ReactionsKey = "reactions" + ContentKey = "content" + ReadKey = "read" + MentionReadKey = "mentionRead" + HasMentionKey = "hasMention" + StateIdKey = "stateId" + OrderKey = "_o" ) type Message struct { @@ -29,7 +52,11 @@ type Message struct { CurrentUserMentioned bool } -func (m *Message) IsCurrentUserMentioned(ctx context.Context, myParticipantId string, myIdentity string, repo *repository) (bool, error) { +type MessagesGetter interface { + GetMessagesByIds(ctx context.Context, messageIds []string) ([]*Message, error) +} + +func (m *Message) IsCurrentUserMentioned(ctx context.Context, myParticipantId string, myIdentity string, repo MessagesGetter) (bool, error) { for _, mark := range m.Message.Marks { if mark.Type == model.BlockContentTextMark_Mention && mark.Param == myParticipantId { return true, nil @@ -37,7 +64,7 @@ func (m *Message) IsCurrentUserMentioned(ctx context.Context, myParticipantId st } if m.ReplyToMessageId != "" { - msgs, err := repo.getMessagesByIds(ctx, []string{m.ReplyToMessageId}) + msgs, err := repo.GetMessagesByIds(ctx, []string{m.ReplyToMessageId}) if err != nil { return false, fmt.Errorf("get messages by id: %w", err) } @@ -52,7 +79,7 @@ func (m *Message) IsCurrentUserMentioned(ctx context.Context, myParticipantId st return false, nil } -func unmarshalMessage(val *anyenc.Value) (*Message, error) { +func UnmarshalMessage(val *anyenc.Value) (*Message, error) { return newMessageWrapper(val).toModel() } @@ -137,16 +164,16 @@ func (m *Message) MarshalAnyenc(marshalTo *anyenc.Value, arena *anyenc.Arena) { } marshalTo.Set("id", arena.NewString(m.Id)) - marshalTo.Set(creatorKey, arena.NewString(m.Creator)) - marshalTo.Set(createdAtKey, arena.NewNumberInt(int(m.CreatedAt))) - marshalTo.Set(modifiedAtKey, arena.NewNumberInt(int(m.ModifiedAt))) + marshalTo.Set(CreatorKey, arena.NewString(m.Creator)) + marshalTo.Set(CreatedAtKey, arena.NewNumberInt(int(m.CreatedAt))) + marshalTo.Set(ModifiedAtKey, arena.NewNumberInt(int(m.ModifiedAt))) marshalTo.Set("replyToMessageId", arena.NewString(m.ReplyToMessageId)) - marshalTo.Set(contentKey, content) - marshalTo.Set(readKey, arenaNewBool(arena, m.Read)) - marshalTo.Set(mentionReadKey, arenaNewBool(arena, m.MentionRead)) - marshalTo.Set(hasMentionKey, arenaNewBool(arena, m.CurrentUserMentioned)) - marshalTo.Set(stateIdKey, arena.NewString(m.StateId)) - marshalTo.Set(reactionsKey, reactions) + marshalTo.Set(ContentKey, content) + marshalTo.Set(ReadKey, arenaNewBool(arena, m.Read)) + marshalTo.Set(MentionReadKey, arenaNewBool(arena, m.MentionRead)) + marshalTo.Set(HasMentionKey, arenaNewBool(arena, m.CurrentUserMentioned)) + marshalTo.Set(StateIdKey, arena.NewString(m.StateId)) + marshalTo.Set(ReactionsKey, reactions) } func arenaNewBool(a *anyenc.Arena, value bool) *anyenc.Value { @@ -161,24 +188,24 @@ func (m *messageUnmarshaller) toModel() (*Message, error) { return &Message{ ChatMessage: &model.ChatMessage{ Id: string(m.val.GetStringBytes("id")), - Creator: string(m.val.GetStringBytes(creatorKey)), - CreatedAt: int64(m.val.GetInt(createdAtKey)), - ModifiedAt: int64(m.val.GetInt(modifiedAtKey)), - StateId: m.val.GetString(stateIdKey), + Creator: string(m.val.GetStringBytes(CreatorKey)), + CreatedAt: int64(m.val.GetInt(CreatedAtKey)), + ModifiedAt: int64(m.val.GetInt(ModifiedAtKey)), + StateId: m.val.GetString(StateIdKey), OrderId: string(m.val.GetStringBytes("_o", "id")), ReplyToMessageId: string(m.val.GetStringBytes("replyToMessageId")), Message: m.contentToModel(), - Read: m.val.GetBool(readKey), - MentionRead: m.val.GetBool(mentionReadKey), + Read: m.val.GetBool(ReadKey), + MentionRead: m.val.GetBool(MentionReadKey), Attachments: m.attachmentsToModel(), Reactions: m.reactionsToModel(), }, - CurrentUserMentioned: m.val.GetBool(hasMentionKey), + CurrentUserMentioned: m.val.GetBool(HasMentionKey), }, nil } func (m *messageUnmarshaller) contentToModel() *model.ChatMessageMessageContent { - inMarks := m.val.GetArray(contentKey, "message", "marks") + inMarks := m.val.GetArray(ContentKey, "message", "marks") marks := make([]*model.BlockContentTextMark, 0, len(inMarks)) for _, inMark := range inMarks { mark := &model.BlockContentTextMark{ @@ -192,14 +219,14 @@ func (m *messageUnmarshaller) contentToModel() *model.ChatMessageMessageContent marks = append(marks, mark) } return &model.ChatMessageMessageContent{ - Text: string(m.val.GetStringBytes(contentKey, "message", "text")), + Text: string(m.val.GetStringBytes(ContentKey, "message", "text")), Style: model.BlockContentTextStyle(m.val.GetInt("content", "message", "style")), Marks: marks, } } func (m *messageUnmarshaller) attachmentsToModel() []*model.ChatMessageAttachment { - inAttachments := m.val.GetObject(contentKey, "attachments") + inAttachments := m.val.GetObject(ContentKey, "attachments") var attachments []*model.ChatMessageAttachment if inAttachments != nil { attachments = make([]*model.ChatMessageAttachment, 0, inAttachments.Len()) @@ -214,7 +241,7 @@ func (m *messageUnmarshaller) attachmentsToModel() []*model.ChatMessageAttachmen } func (m *messageUnmarshaller) reactionsToModel() *model.ChatMessageReactions { - inReactions := m.val.GetObject(reactionsKey) + inReactions := m.val.GetObject(ReactionsKey) reactions := &model.ChatMessageReactions{ Reactions: map[string]*model.ChatMessageReactionsIdentityList{}, } diff --git a/core/block/chats/chatpush/push.go b/core/block/chats/chatpush/push.go index de7805344..463195f67 100644 --- a/core/block/chats/chatpush/push.go +++ b/core/block/chats/chatpush/push.go @@ -14,9 +14,10 @@ type Payload struct { } type NewMessagePayload struct { - ChatId string `json:"chatId"` - MsgId string `json:"msgId"` - SpaceName string `json:"spaceName"` - SenderName string `json:"senderName"` - Text string `json:"text"` + ChatId string `json:"chatId"` + MsgId string `json:"msgId"` + SpaceName string `json:"spaceName"` + SenderName string `json:"senderName"` + Text string `json:"text"` + HasAttachments bool `json:"hasAttachments"` } diff --git a/core/block/chats/chatrepository/readhandler.go b/core/block/chats/chatrepository/readhandler.go new file mode 100644 index 000000000..590229695 --- /dev/null +++ b/core/block/chats/chatrepository/readhandler.go @@ -0,0 +1,92 @@ +package chatrepository + +import ( + "github.com/anyproto/any-store/anyenc" + "github.com/anyproto/any-store/query" + + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" +) + +type readHandler interface { + getUnreadFilter() query.Filter + getMessagesFilter() query.Filter + getReadKey() string + readModifier(value bool) query.Modifier +} + +type readMessagesHandler struct{} + +func (h readMessagesHandler) getUnreadFilter() query.Filter { + return query.Not{ + Filter: query.Key{Path: []string{chatmodel.ReadKey}, Filter: query.NewComp(query.CompOpEq, true)}, + } +} + +func (h readMessagesHandler) getMessagesFilter() query.Filter { + return nil +} + +func (h readMessagesHandler) getReadKey() string { + return chatmodel.ReadKey +} + +func (h readMessagesHandler) readModifier(value bool) query.Modifier { + return query.ModifyFunc(func(a *anyenc.Arena, v *anyenc.Value) (result *anyenc.Value, modified bool, err error) { + oldValue := v.GetBool(h.getReadKey()) + if oldValue != value { + v.Set(h.getReadKey(), arenaNewBool(a, value)) + return v, true, nil + } + return v, false, nil + }) +} + +type readMentionsHandler struct { +} + +func (h readMentionsHandler) getUnreadFilter() query.Filter { + return query.And{ + query.Key{Path: []string{chatmodel.HasMentionKey}, Filter: query.NewComp(query.CompOpEq, true)}, + query.Key{Path: []string{chatmodel.MentionReadKey}, Filter: query.NewComp(query.CompOpEq, false)}, + } +} + +func (h readMentionsHandler) getMessagesFilter() query.Filter { + return query.Key{Path: []string{chatmodel.HasMentionKey}, Filter: query.NewComp(query.CompOpEq, true)} +} + +func (h readMentionsHandler) getReadKey() string { + return chatmodel.MentionReadKey +} + +func (h readMentionsHandler) readModifier(value bool) query.Modifier { + return query.ModifyFunc(func(a *anyenc.Arena, v *anyenc.Value) (result *anyenc.Value, modified bool, err error) { + if v.GetBool(chatmodel.HasMentionKey) { + oldValue := v.GetBool(h.getReadKey()) + if oldValue != value { + v.Set(h.getReadKey(), arenaNewBool(a, value)) + return v, true, nil + } + } + return v, false, nil + }) +} + +func newReadHandler(counterType chatmodel.CounterType) readHandler { + switch counterType { + case chatmodel.CounterTypeMessage: + return readMessagesHandler{} + case chatmodel.CounterTypeMention: + return readMentionsHandler{} + default: + panic("unknown counter type") + } +} + +func arenaNewBool(a *anyenc.Arena, value bool) *anyenc.Value { + if value { + return a.NewTrue() + } else { + return a.NewFalse() + } +} diff --git a/core/block/chats/chatrepository/repository.go b/core/block/chats/chatrepository/repository.go new file mode 100644 index 000000000..d25bf5558 --- /dev/null +++ b/core/block/chats/chatrepository/repository.go @@ -0,0 +1,474 @@ +package chatrepository + +import ( + "context" + "errors" + "fmt" + "slices" + "sort" + + anystore "github.com/anyproto/any-store" + "github.com/anyproto/any-store/anyenc" + "github.com/anyproto/any-store/query" + "github.com/anyproto/any-sync/app" + "go.uber.org/zap" + + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" + "github.com/anyproto/anytype-heart/core/block/object/idresolver" + "github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore" + "github.com/anyproto/anytype-heart/pkg/lib/logging" + "github.com/anyproto/anytype-heart/pkg/lib/pb/model" +) + +const CName = "chatrepository" + +var log = logging.Logger(CName).Desugar() + +const ( + descOrder = "-_o.id" + ascOrder = "_o.id" + descStateId = "-stateId" +) + +type Service interface { + app.ComponentRunnable + + Repository(chatObjectId string) (Repository, error) +} + +type service struct { + componentCtx context.Context + componentCtxCancel context.CancelFunc + + objectStore objectstore.ObjectStore + spaceIdResolver idresolver.Resolver + arenaPool *anyenc.ArenaPool +} + +func New() Service { + return &service{ + arenaPool: &anyenc.ArenaPool{}, + } +} + +func (s *service) Run(ctx context.Context) error { + return nil +} + +func (s *service) Close(ctx context.Context) error { + if s.componentCtxCancel != nil { + s.componentCtxCancel() + } + return nil +} + +func (s *service) Init(a *app.App) (err error) { + s.componentCtx, s.componentCtxCancel = context.WithCancel(context.Background()) + + s.objectStore = app.MustComponent[objectstore.ObjectStore](a) + s.spaceIdResolver = app.MustComponent[idresolver.Resolver](a) + return nil +} + +func (s *service) Name() (name string) { + return CName +} + +func (s *service) Repository(chatObjectId string) (Repository, error) { + spaceId, err := s.spaceIdResolver.ResolveSpaceID(chatObjectId) + if err != nil { + return nil, fmt.Errorf("resolve space id: %w", err) + } + + crdtDbGetter := s.objectStore.GetCrdtDb(spaceId) + crdtDb, err := crdtDbGetter.Wait() + if err != nil { + return nil, fmt.Errorf("get crdt db: %w", err) + } + + collectionName := chatObjectId + "chats" + collection, err := crdtDb.OpenCollection(s.componentCtx, collectionName) + if errors.Is(err, anystore.ErrCollectionNotFound) { + collection, err = crdtDb.CreateCollection(s.componentCtx, collectionName) + if err != nil { + return nil, fmt.Errorf("create collection: %w", err) + } + } + if err != nil { + return nil, fmt.Errorf("get collection: %w", err) + } + + return &repository{ + collection: collection, + arenaPool: s.arenaPool, + }, nil +} + +type Repository interface { + WriteTx(ctx context.Context) (anystore.WriteTx, error) + ReadTx(ctx context.Context) (anystore.ReadTx, error) + GetLastStateId(ctx context.Context) (string, error) + GetPrevOrderId(ctx context.Context, orderId string) (string, error) + LoadChatState(ctx context.Context) (*model.ChatState, error) + GetOldestOrderId(ctx context.Context, counterType chatmodel.CounterType) (string, error) + GetReadMessagesAfter(ctx context.Context, afterOrderId string, counterType chatmodel.CounterType) ([]string, error) + GetUnreadMessageIdsInRange(ctx context.Context, afterOrderId, beforeOrderId string, lastStateId string, counterType chatmodel.CounterType) ([]string, error) + GetAllUnreadMessages(ctx context.Context, counterType chatmodel.CounterType) ([]string, error) + SetReadFlag(ctx context.Context, chatObjectId string, msgIds []string, counterType chatmodel.CounterType, value bool) []string + GetMessages(ctx context.Context, req GetMessagesRequest) ([]*chatmodel.Message, error) + HasMyReaction(ctx context.Context, myIdentity string, messageId string, emoji string) (bool, error) + GetMessagesByIds(ctx context.Context, messageIds []string) ([]*chatmodel.Message, error) + GetLastMessages(ctx context.Context, limit uint) ([]*chatmodel.Message, error) +} + +type repository struct { + collection anystore.Collection + arenaPool *anyenc.ArenaPool +} + +func (s *repository) WriteTx(ctx context.Context) (anystore.WriteTx, error) { + return s.collection.WriteTx(ctx) +} + +func (s *repository) ReadTx(ctx context.Context) (anystore.ReadTx, error) { + return s.collection.ReadTx(ctx) +} + +func (s *repository) GetLastStateId(ctx context.Context) (string, error) { + lastAddedDate := s.collection.Find(nil).Sort(descStateId).Limit(1) + iter, err := lastAddedDate.Iter(ctx) + if err != nil { + return "", fmt.Errorf("find last added date: %w", err) + } + defer iter.Close() + + for iter.Next() { + doc, err := iter.Doc() + if err != nil { + return "", fmt.Errorf("get doc: %w", err) + } + msg, err := chatmodel.UnmarshalMessage(doc.Value()) + if err != nil { + return "", fmt.Errorf("unmarshal message: %w", err) + } + return msg.StateId, nil + } + return "", nil +} + +func (s *repository) GetPrevOrderId(ctx context.Context, orderId string) (string, error) { + iter, err := s.collection.Find(query.Key{Path: []string{chatmodel.OrderKey, "id"}, Filter: query.NewComp(query.CompOpLt, orderId)}). + Sort(descOrder). + Limit(1). + Iter(ctx) + if err != nil { + return "", fmt.Errorf("init iterator: %w", err) + } + defer iter.Close() + + if iter.Next() { + doc, err := iter.Doc() + if err != nil { + return "", fmt.Errorf("read doc: %w", err) + } + prevOrderId := doc.Value().GetString(chatmodel.OrderKey, "id") + return prevOrderId, nil + } + + return "", nil +} + +// initialChatState returns the initial chat state for the chat object from the DB +func (s *repository) LoadChatState(ctx context.Context) (*model.ChatState, error) { + txn, err := s.ReadTx(ctx) + if err != nil { + return nil, fmt.Errorf("start read tx: %w", err) + } + defer txn.Commit() + + messagesState, err := s.loadChatStateByType(txn.Context(), chatmodel.CounterTypeMessage) + if err != nil { + return nil, fmt.Errorf("get messages state: %w", err) + } + mentionsState, err := s.loadChatStateByType(txn.Context(), chatmodel.CounterTypeMention) + if err != nil { + return nil, fmt.Errorf("get mentions state: %w", err) + } + + lastStateId, err := s.GetLastStateId(txn.Context()) + if err != nil { + return nil, fmt.Errorf("get last added date: %w", err) + } + + return &model.ChatState{ + Messages: messagesState, + Mentions: mentionsState, + LastStateId: lastStateId, + }, nil +} + +func (s *repository) loadChatStateByType(ctx context.Context, counterType chatmodel.CounterType) (*model.ChatStateUnreadState, error) { + handler := newReadHandler(counterType) + + oldestOrderId, err := s.GetOldestOrderId(ctx, counterType) + if err != nil { + return nil, fmt.Errorf("get oldest order id: %w", err) + } + + count, err := s.countUnreadMessages(ctx, handler) + if err != nil { + return nil, fmt.Errorf("update messages: %w", err) + } + + return &model.ChatStateUnreadState{ + OldestOrderId: oldestOrderId, + Counter: int32(count), + }, nil +} + +func (s *repository) GetOldestOrderId(ctx context.Context, counterType chatmodel.CounterType) (string, error) { + handler := newReadHandler(counterType) + unreadQuery := s.collection.Find(handler.getUnreadFilter()).Sort(ascOrder) + + iter, err := unreadQuery.Limit(1).Iter(ctx) + if err != nil { + return "", fmt.Errorf("init iter: %w", err) + } + defer iter.Close() + + for iter.Next() { + doc, err := iter.Doc() + if err != nil { + return "", fmt.Errorf("get doc: %w", err) + } + orders := doc.Value().GetObject(chatmodel.OrderKey) + if orders != nil { + return orders.Get("id").GetString(), nil + } + } + return "", nil +} + +func (s *repository) countUnreadMessages(ctx context.Context, handler readHandler) (int, error) { + unreadQuery := s.collection.Find(handler.getUnreadFilter()) + + return unreadQuery.Count(ctx) +} + +func (s *repository) GetReadMessagesAfter(ctx context.Context, afterOrderId string, counterType chatmodel.CounterType) ([]string, error) { + handler := newReadHandler(counterType) + + filter := query.And{ + query.Key{Path: []string{chatmodel.OrderKey, "id"}, Filter: query.NewComp(query.CompOpGte, afterOrderId)}, + query.Key{Path: []string{handler.getReadKey()}, Filter: query.NewComp(query.CompOpEq, true)}, + } + if handler.getMessagesFilter() != nil { + filter = append(filter, handler.getMessagesFilter()) + } + + iter, err := s.collection.Find(filter).Iter(ctx) + if err != nil { + return nil, fmt.Errorf("init iterator: %w", err) + } + defer iter.Close() + + var msgIds []string + for iter.Next() { + doc, err := iter.Doc() + if err != nil { + return nil, fmt.Errorf("get doc: %w", err) + } + msgIds = append(msgIds, doc.Value().GetString("id")) + } + return msgIds, iter.Err() +} + +func (s *repository) GetUnreadMessageIdsInRange(ctx context.Context, afterOrderId, beforeOrderId string, lastStateId string, counterType chatmodel.CounterType) ([]string, error) { + handler := newReadHandler(counterType) + + qry := query.And{ + query.Key{Path: []string{chatmodel.OrderKey, "id"}, Filter: query.NewComp(query.CompOpGte, afterOrderId)}, + query.Key{Path: []string{chatmodel.OrderKey, "id"}, Filter: query.NewComp(query.CompOpLte, beforeOrderId)}, + query.Or{ + query.Not{Filter: query.Key{Path: []string{chatmodel.StateIdKey}, Filter: query.Exists{}}}, + query.Key{Path: []string{chatmodel.StateIdKey}, Filter: query.NewComp(query.CompOpLte, lastStateId)}, + }, + handler.getUnreadFilter(), + } + iter, err := s.collection.Find(qry).Iter(ctx) + if err != nil { + return nil, fmt.Errorf("find id: %w", err) + } + defer iter.Close() + + var msgIds []string + for iter.Next() { + doc, err := iter.Doc() + if err != nil { + return nil, fmt.Errorf("get doc: %w", err) + } + msgIds = append(msgIds, doc.Value().GetString("id")) + } + return msgIds, iter.Err() +} + +func (s *repository) GetAllUnreadMessages(ctx context.Context, counterType chatmodel.CounterType) ([]string, error) { + handler := newReadHandler(counterType) + + qry := query.And{ + handler.getUnreadFilter(), + } + iter, err := s.collection.Find(qry).Iter(ctx) + if err != nil { + return nil, fmt.Errorf("find id: %w", err) + } + defer iter.Close() + + var msgIds []string + for iter.Next() { + doc, err := iter.Doc() + if err != nil { + return nil, fmt.Errorf("get doc: %w", err) + } + msgIds = append(msgIds, doc.Value().GetString("id")) + } + return msgIds, iter.Err() +} + +func (r *repository) SetReadFlag(ctx context.Context, chatObjectId string, msgIds []string, counterType chatmodel.CounterType, value bool) []string { + handler := newReadHandler(counterType) + + var idsModified []string + for _, id := range msgIds { + if id == chatObjectId { + // skip tree root + continue + } + res, err := r.collection.UpdateId(ctx, id, handler.readModifier(value)) + // Not all changes are messages, skip them + if errors.Is(err, anystore.ErrDocNotFound) { + continue + } + if err != nil { + log.Error("markReadMessages: update message", zap.Error(err), zap.String("changeId", id), zap.String("chatObjectId", chatObjectId)) + continue + } + if res.Modified > 0 { + idsModified = append(idsModified, id) + } + } + return idsModified +} + +type GetMessagesRequest struct { + AfterOrderId string + BeforeOrderId string + Limit int + IncludeBoundary bool +} + +func (s *repository) GetMessages(ctx context.Context, req GetMessagesRequest) ([]*chatmodel.Message, error) { + var qry anystore.Query + if req.AfterOrderId != "" { + operator := query.CompOpGt + if req.IncludeBoundary { + operator = query.CompOpGte + } + qry = s.collection.Find(query.Key{Path: []string{chatmodel.OrderKey, "id"}, Filter: query.NewComp(operator, req.AfterOrderId)}).Sort(ascOrder).Limit(uint(req.Limit)) + } else if req.BeforeOrderId != "" { + operator := query.CompOpLt + if req.IncludeBoundary { + operator = query.CompOpLte + } + qry = s.collection.Find(query.Key{Path: []string{chatmodel.OrderKey, "id"}, Filter: query.NewComp(operator, req.BeforeOrderId)}).Sort(descOrder).Limit(uint(req.Limit)) + } else { + qry = s.collection.Find(nil).Sort(descOrder).Limit(uint(req.Limit)) + } + + msgs, err := s.queryMessages(ctx, qry) + if err != nil { + return nil, fmt.Errorf("query messages: %w", err) + } + return msgs, nil +} + +func (s *repository) queryMessages(ctx context.Context, query anystore.Query) ([]*chatmodel.Message, error) { + arena := s.arenaPool.Get() + defer func() { + arena.Reset() + s.arenaPool.Put(arena) + }() + + iter, err := query.Iter(ctx) + if err != nil { + return nil, fmt.Errorf("find iter: %w", err) + } + defer iter.Close() + + var res []*chatmodel.Message + for iter.Next() { + doc, err := iter.Doc() + if err != nil { + return nil, fmt.Errorf("get doc: %w", err) + } + + msg, err := chatmodel.UnmarshalMessage(doc.Value()) + if err != nil { + return nil, fmt.Errorf("unmarshal message: %w", err) + } + res = append(res, msg) + } + // reverse + sort.Slice(res, func(i, j int) bool { + return res[i].OrderId < res[j].OrderId + }) + return res, nil +} + +func (s *repository) HasMyReaction(ctx context.Context, myIdentity string, messageId string, emoji string) (bool, error) { + doc, err := s.collection.FindId(ctx, messageId) + if err != nil { + return false, fmt.Errorf("find message: %w", err) + } + + msg, err := chatmodel.UnmarshalMessage(doc.Value()) + if err != nil { + return false, fmt.Errorf("unmarshal message: %w", err) + } + if v, ok := msg.GetReactions().GetReactions()[emoji]; ok { + if slices.Contains(v.GetIds(), myIdentity) { + return true, nil + } + } + return false, nil +} + +func (s *repository) GetMessagesByIds(ctx context.Context, messageIds []string) ([]*chatmodel.Message, error) { + txn, err := s.ReadTx(ctx) + if err != nil { + return nil, fmt.Errorf("start read tx: %w", err) + } + defer txn.Commit() + + messages := make([]*chatmodel.Message, 0, len(messageIds)) + for _, messageId := range messageIds { + obj, err := s.collection.FindId(txn.Context(), messageId) + if errors.Is(err, anystore.ErrDocNotFound) { + continue + } + if err != nil { + return nil, errors.Join(txn.Commit(), fmt.Errorf("find id: %w", err)) + } + msg, err := chatmodel.UnmarshalMessage(obj.Value()) + if err != nil { + return nil, errors.Join(txn.Commit(), fmt.Errorf("unmarshal message: %w", err)) + } + messages = append(messages, msg) + } + return messages, nil +} + +func (s *repository) GetLastMessages(ctx context.Context, limit uint) ([]*chatmodel.Message, error) { + qry := s.collection.Find(nil).Sort(descOrder).Limit(limit) + return s.queryMessages(ctx, qry) +} diff --git a/core/block/editor/chatobject/subscription.go b/core/block/chats/chatsubscription/manager.go similarity index 60% rename from core/block/editor/chatobject/subscription.go rename to core/block/chats/chatsubscription/manager.go index 751e65084..326f1f729 100644 --- a/core/block/editor/chatobject/subscription.go +++ b/core/block/chats/chatsubscription/manager.go @@ -1,14 +1,16 @@ -package chatobject +package chatsubscription import ( "context" "slices" "sort" - "time" + "sync" "github.com/hashicorp/golang-lru/v2/expirable" "go.uber.org/zap" + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" + "github.com/anyproto/anytype-heart/core/block/chats/chatrepository" "github.com/anyproto/anytype-heart/core/domain" "github.com/anyproto/anytype-heart/core/event" "github.com/anyproto/anytype-heart/core/session" @@ -18,6 +20,8 @@ import ( ) type subscriptionManager struct { + lock sync.Mutex + componentCtx context.Context spaceId string @@ -38,35 +42,31 @@ type subscriptionManager struct { // Deps spaceIndex spaceindex.Store eventSender event.Sender - repository *repository + repository chatrepository.Repository } type subscription struct { id string withDependencies bool + + onlyLastMessage bool } -func (s *storeObject) newSubscriptionManager(fullId domain.FullID, myIdentity string, myParticipantId string) *subscriptionManager { - return &subscriptionManager{ - componentCtx: s.componentCtx, - spaceId: fullId.SpaceID, - chatId: fullId.ObjectID, - eventSender: s.eventSender, - spaceIndex: s.spaceIndex, - myIdentity: myIdentity, - myParticipantId: myParticipantId, - identityCache: expirable.NewLRU[string, *domain.Details](50, nil, time.Minute), - repository: s.repository, - subscriptions: map[string]*subscription{}, - } +func (s *subscriptionManager) Lock() { + s.lock.Lock() +} + +func (s *subscriptionManager) Unlock() { + s.lock.Unlock() } // subscribe subscribes to messages. It returns true if there was no subscriptionManager with provided id -func (s *subscriptionManager) subscribe(subId string, withDependencies bool) bool { +func (s *subscriptionManager) subscribe(subId string, withDependencies bool, onlyLastMessage bool) bool { if _, ok := s.subscriptions[subId]; !ok { s.subscriptions[subId] = &subscription{ id: subId, withDependencies: withDependencies, + onlyLastMessage: onlyLastMessage, } s.chatStateUpdated = false return true @@ -78,7 +78,7 @@ func (s *subscriptionManager) unsubscribe(subId string) { delete(s.subscriptions, subId) } -func (s *subscriptionManager) isActive() bool { +func (s *subscriptionManager) IsActive() bool { return len(s.subscriptions) > 0 } @@ -100,13 +100,13 @@ func (s *subscriptionManager) listSubIds() []string { return subIds } -// setSessionContext sets the session context for the current operation -func (s *subscriptionManager) setSessionContext(ctx session.Context) { +// SetSessionContext sets the session context for the current operation +func (s *subscriptionManager) SetSessionContext(ctx session.Context) { s.sessionContext = ctx } func (s *subscriptionManager) loadChatState(ctx context.Context) error { - state, err := s.repository.loadChatState(ctx) + state, err := s.repository.LoadChatState(ctx) if err != nil { return err } @@ -114,25 +114,25 @@ func (s *subscriptionManager) loadChatState(ctx context.Context) error { return nil } -func (s *subscriptionManager) getChatState() *model.ChatState { +func (s *subscriptionManager) GetChatState() *model.ChatState { return copyChatState(s.chatState) } -func (s *subscriptionManager) updateChatState(updater func(*model.ChatState) *model.ChatState) { +func (s *subscriptionManager) UpdateChatState(updater func(*model.ChatState) *model.ChatState) { s.chatState = updater(s.chatState) s.chatStateUpdated = true } -// flush is called after commiting changes -func (s *subscriptionManager) flush() { +// Flush is called after committing changes +func (s *subscriptionManager) Flush() { if !s.canSend() { return } // Reload ChatState after commit if s.needReloadState { - s.updateChatState(func(state *model.ChatState) *model.ChatState { - newState, err := s.repository.loadChatState(s.componentCtx) + s.UpdateChatState(func(state *model.ChatState) *model.ChatState { + newState, err := s.repository.LoadChatState(s.componentCtx) if err != nil { log.Error("failed to reload chat state", zap.Error(err)) return state @@ -145,9 +145,34 @@ func (s *subscriptionManager) flush() { events := slices.Clone(s.eventsBuffer) s.eventsBuffer = s.eventsBuffer[:0] + var subIdsOnlyLastMessage []string + subIdsAllMessages := make([]string, 0, len(s.subscriptions)) + for _, sub := range s.subscriptions { + if sub.onlyLastMessage { + subIdsOnlyLastMessage = append(subIdsOnlyLastMessage, sub.id) + } else { + subIdsAllMessages = append(subIdsAllMessages, sub.id) + } + } + + // Corner case when we are subscribed only for the last message + // The idea is to prevent sending a lot of events to message preview subscription on cold recovery or reindex. + if len(subIdsAllMessages) == 0 && len(subIdsOnlyLastMessage) > 0 { + events = s.getEventsOnlyForLastMessage(events, subIdsOnlyLastMessage) + } else { + for _, ev := range events { + if ev := ev.GetChatAdd(); ev != nil { + ev.SubIds = subIdsAllMessages + if s.withDeps() { + s.enrichWithDependencies(ev) + } + } + } + } + if s.chatStateUpdated { events = append(events, event.NewMessage(s.spaceId, &pb.EventMessageValueOfChatStateUpdate{ChatStateUpdate: &pb.EventChatUpdateState{ - State: s.getChatState(), + State: s.GetChatState(), SubIds: s.listSubIds(), }})) s.chatStateUpdated = false @@ -158,14 +183,43 @@ func (s *subscriptionManager) flush() { Messages: events, } if s.sessionContext != nil { - s.sessionContext.SetMessages(s.chatId, events) + s.sessionContext.SetMessages(s.chatId, append(s.sessionContext.GetMessages(), events...)) s.eventSender.BroadcastToOtherSessions(s.sessionContext.ID(), ev) - s.sessionContext = nil - } else if s.isActive() { + } else if s.IsActive() { s.eventSender.Broadcast(ev) } } +func (s *subscriptionManager) getEventsOnlyForLastMessage(events []*pb.EventMessage, subIdsOnlyLastMessage []string) []*pb.EventMessage { + state := newMessagesState() + for _, ev := range events { + state.applyEvent(ev) + } + lastMessage, ok := state.getLastAddedMessage() + if ok { + addEvent := state.addEvents[lastMessage.Id] + addEvent.SubIds = subIdsOnlyLastMessage + if s.withDeps() { + s.enrichWithDependencies(addEvent) + } + + // Just rewrite all events and leave only last message. This message already has all updates applied to it + events = []*pb.EventMessage{ + event.NewMessage(s.spaceId, &pb.EventMessageValueOfChatAdd{ + ChatAdd: addEvent, + }), + } + } + return events +} + +func (s *subscriptionManager) enrichWithDependencies(ev *pb.EventChatAdd) { + deps := s.collectMessageDependencies(ev.Message) + for _, dep := range deps { + ev.Dependencies = append(ev.Dependencies, dep.ToProto()) + } +} + func (s *subscriptionManager) getIdentityDetails(identity string) (*domain.Details, error) { cached, ok := s.identityCache.Get(identity) if ok { @@ -179,7 +233,7 @@ func (s *subscriptionManager) getIdentityDetails(identity string) (*domain.Detai return details, nil } -func (s *subscriptionManager) add(prevOrderId string, message *Message) { +func (s *subscriptionManager) Add(prevOrderId string, message *chatmodel.Message) { if !s.canSend() { return } @@ -189,21 +243,13 @@ func (s *subscriptionManager) add(prevOrderId string, message *Message) { Message: message.ChatMessage, OrderId: message.OrderId, AfterOrderId: prevOrderId, - SubIds: s.listSubIds(), - } - - if s.withDeps() { - deps := s.collectMessageDependencies(message) - for _, dep := range deps { - ev.Dependencies = append(ev.Dependencies, dep.ToProto()) - } } s.eventsBuffer = append(s.eventsBuffer, event.NewMessage(s.spaceId, &pb.EventMessageValueOfChatAdd{ ChatAdd: ev, })) } -func (s *subscriptionManager) collectMessageDependencies(message *Message) []*domain.Details { +func (s *subscriptionManager) collectMessageDependencies(message *model.ChatMessage) []*domain.Details { var result []*domain.Details identityDetails, err := s.getIdentityDetails(message.Creator) @@ -224,7 +270,7 @@ func (s *subscriptionManager) collectMessageDependencies(message *Message) []*do return result } -func (s *subscriptionManager) delete(messageId string) { +func (s *subscriptionManager) Delete(messageId string) { ev := &pb.EventChatDelete{ Id: messageId, SubIds: s.listSubIds(), @@ -237,7 +283,7 @@ func (s *subscriptionManager) delete(messageId string) { s.needReloadState = true } -func (s *subscriptionManager) updateFull(message *Message) { +func (s *subscriptionManager) UpdateFull(message *chatmodel.Message) { if !s.canSend() { return } @@ -251,7 +297,7 @@ func (s *subscriptionManager) updateFull(message *Message) { })) } -func (s *subscriptionManager) updateReactions(message *Message) { +func (s *subscriptionManager) UpdateReactions(message *chatmodel.Message) { if !s.canSend() { return } @@ -268,7 +314,7 @@ func (s *subscriptionManager) updateReactions(message *Message) { // updateMessageRead updates the read status of the messages with the given ids // read ids should ONLY contain ids if they were actually modified in the DB func (s *subscriptionManager) updateMessageRead(ids []string, read bool) { - s.updateChatState(func(state *model.ChatState) *model.ChatState { + s.UpdateChatState(func(state *model.ChatState) *model.ChatState { if read { state.Messages.Counter -= int32(len(ids)) } else { @@ -290,7 +336,7 @@ func (s *subscriptionManager) updateMessageRead(ids []string, read bool) { } func (s *subscriptionManager) updateMentionRead(ids []string, read bool) { - s.updateChatState(func(state *model.ChatState) *model.ChatState { + s.UpdateChatState(func(state *model.ChatState) *model.ChatState { if read { state.Mentions.Counter -= int32(len(ids)) } else { @@ -315,12 +361,46 @@ func (s *subscriptionManager) canSend() bool { if s.sessionContext != nil { return true } - if !s.isActive() { + if !s.IsActive() { return false } return true } +func (s *subscriptionManager) ReadMessages(newOldestOrderId string, idsModified []string, counterType chatmodel.CounterType) { + if counterType == chatmodel.CounterTypeMessage { + s.UpdateChatState(func(state *model.ChatState) *model.ChatState { + state.Messages.OldestOrderId = newOldestOrderId + return state + }) + s.updateMessageRead(idsModified, true) + } else { + s.UpdateChatState(func(state *model.ChatState) *model.ChatState { + state.Mentions.OldestOrderId = newOldestOrderId + return state + }) + s.updateMentionRead(idsModified, true) + } +} + +func (s *subscriptionManager) UnreadMessages(newOldestOrderId string, lastStateId string, msgIds []string, counterType chatmodel.CounterType) { + if counterType == chatmodel.CounterTypeMessage { + s.UpdateChatState(func(state *model.ChatState) *model.ChatState { + state.Messages.OldestOrderId = newOldestOrderId + state.LastStateId = lastStateId + return state + }) + s.updateMessageRead(msgIds, false) + } else { + s.UpdateChatState(func(state *model.ChatState) *model.ChatState { + state.Mentions.OldestOrderId = newOldestOrderId + state.LastStateId = lastStateId + return state + }) + s.updateMentionRead(msgIds, false) + } +} + func copyChatState(state *model.ChatState) *model.ChatState { if state == nil { return nil diff --git a/core/block/chats/chatsubscription/mock_chatsubscription/mock_Service.go b/core/block/chats/chatsubscription/mock_chatsubscription/mock_Service.go new file mode 100644 index 000000000..942abd2f2 --- /dev/null +++ b/core/block/chats/chatsubscription/mock_chatsubscription/mock_Service.go @@ -0,0 +1,386 @@ +// Code generated by mockery. DO NOT EDIT. + +package mock_chatsubscription + +import ( + context "context" + + app "github.com/anyproto/any-sync/app" + chatsubscription "github.com/anyproto/anytype-heart/core/block/chats/chatsubscription" + + mock "github.com/stretchr/testify/mock" +) + +// MockService is an autogenerated mock type for the Service type +type MockService struct { + mock.Mock +} + +type MockService_Expecter struct { + mock *mock.Mock +} + +func (_m *MockService) EXPECT() *MockService_Expecter { + return &MockService_Expecter{mock: &_m.Mock} +} + +// Close provides a mock function with given fields: ctx +func (_m *MockService) Close(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Close") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockService_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close' +type MockService_Close_Call struct { + *mock.Call +} + +// Close is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockService_Expecter) Close(ctx interface{}) *MockService_Close_Call { + return &MockService_Close_Call{Call: _e.mock.On("Close", ctx)} +} + +func (_c *MockService_Close_Call) Run(run func(ctx context.Context)) *MockService_Close_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockService_Close_Call) Return(err error) *MockService_Close_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockService_Close_Call) RunAndReturn(run func(context.Context) error) *MockService_Close_Call { + _c.Call.Return(run) + return _c +} + +// GetManager provides a mock function with given fields: chatObjectId +func (_m *MockService) GetManager(chatObjectId string) (chatsubscription.Manager, error) { + ret := _m.Called(chatObjectId) + + if len(ret) == 0 { + panic("no return value specified for GetManager") + } + + var r0 chatsubscription.Manager + var r1 error + if rf, ok := ret.Get(0).(func(string) (chatsubscription.Manager, error)); ok { + return rf(chatObjectId) + } + if rf, ok := ret.Get(0).(func(string) chatsubscription.Manager); ok { + r0 = rf(chatObjectId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(chatsubscription.Manager) + } + } + + if rf, ok := ret.Get(1).(func(string) error); ok { + r1 = rf(chatObjectId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockService_GetManager_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetManager' +type MockService_GetManager_Call struct { + *mock.Call +} + +// GetManager is a helper method to define mock.On call +// - chatObjectId string +func (_e *MockService_Expecter) GetManager(chatObjectId interface{}) *MockService_GetManager_Call { + return &MockService_GetManager_Call{Call: _e.mock.On("GetManager", chatObjectId)} +} + +func (_c *MockService_GetManager_Call) Run(run func(chatObjectId string)) *MockService_GetManager_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockService_GetManager_Call) Return(_a0 chatsubscription.Manager, _a1 error) *MockService_GetManager_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockService_GetManager_Call) RunAndReturn(run func(string) (chatsubscription.Manager, error)) *MockService_GetManager_Call { + _c.Call.Return(run) + return _c +} + +// Init provides a mock function with given fields: a +func (_m *MockService) Init(a *app.App) error { + ret := _m.Called(a) + + if len(ret) == 0 { + panic("no return value specified for Init") + } + + var r0 error + if rf, ok := ret.Get(0).(func(*app.App) error); ok { + r0 = rf(a) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockService_Init_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Init' +type MockService_Init_Call struct { + *mock.Call +} + +// Init is a helper method to define mock.On call +// - a *app.App +func (_e *MockService_Expecter) Init(a interface{}) *MockService_Init_Call { + return &MockService_Init_Call{Call: _e.mock.On("Init", a)} +} + +func (_c *MockService_Init_Call) Run(run func(a *app.App)) *MockService_Init_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(*app.App)) + }) + return _c +} + +func (_c *MockService_Init_Call) Return(err error) *MockService_Init_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockService_Init_Call) RunAndReturn(run func(*app.App) error) *MockService_Init_Call { + _c.Call.Return(run) + return _c +} + +// Name provides a mock function with given fields: +func (_m *MockService) Name() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for Name") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// MockService_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name' +type MockService_Name_Call struct { + *mock.Call +} + +// Name is a helper method to define mock.On call +func (_e *MockService_Expecter) Name() *MockService_Name_Call { + return &MockService_Name_Call{Call: _e.mock.On("Name")} +} + +func (_c *MockService_Name_Call) Run(run func()) *MockService_Name_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockService_Name_Call) Return(name string) *MockService_Name_Call { + _c.Call.Return(name) + return _c +} + +func (_c *MockService_Name_Call) RunAndReturn(run func() string) *MockService_Name_Call { + _c.Call.Return(run) + return _c +} + +// Run provides a mock function with given fields: ctx +func (_m *MockService) Run(ctx context.Context) error { + ret := _m.Called(ctx) + + if len(ret) == 0 { + panic("no return value specified for Run") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context) error); ok { + r0 = rf(ctx) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockService_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run' +type MockService_Run_Call struct { + *mock.Call +} + +// Run is a helper method to define mock.On call +// - ctx context.Context +func (_e *MockService_Expecter) Run(ctx interface{}) *MockService_Run_Call { + return &MockService_Run_Call{Call: _e.mock.On("Run", ctx)} +} + +func (_c *MockService_Run_Call) Run(run func(ctx context.Context)) *MockService_Run_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context)) + }) + return _c +} + +func (_c *MockService_Run_Call) Return(err error) *MockService_Run_Call { + _c.Call.Return(err) + return _c +} + +func (_c *MockService_Run_Call) RunAndReturn(run func(context.Context) error) *MockService_Run_Call { + _c.Call.Return(run) + return _c +} + +// SubscribeLastMessages provides a mock function with given fields: ctx, req +func (_m *MockService) SubscribeLastMessages(ctx context.Context, req chatsubscription.SubscribeLastMessagesRequest) (*chatsubscription.SubscribeLastMessagesResponse, error) { + ret := _m.Called(ctx, req) + + if len(ret) == 0 { + panic("no return value specified for SubscribeLastMessages") + } + + var r0 *chatsubscription.SubscribeLastMessagesResponse + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, chatsubscription.SubscribeLastMessagesRequest) (*chatsubscription.SubscribeLastMessagesResponse, error)); ok { + return rf(ctx, req) + } + if rf, ok := ret.Get(0).(func(context.Context, chatsubscription.SubscribeLastMessagesRequest) *chatsubscription.SubscribeLastMessagesResponse); ok { + r0 = rf(ctx, req) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*chatsubscription.SubscribeLastMessagesResponse) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, chatsubscription.SubscribeLastMessagesRequest) error); ok { + r1 = rf(ctx, req) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockService_SubscribeLastMessages_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeLastMessages' +type MockService_SubscribeLastMessages_Call struct { + *mock.Call +} + +// SubscribeLastMessages is a helper method to define mock.On call +// - ctx context.Context +// - req chatsubscription.SubscribeLastMessagesRequest +func (_e *MockService_Expecter) SubscribeLastMessages(ctx interface{}, req interface{}) *MockService_SubscribeLastMessages_Call { + return &MockService_SubscribeLastMessages_Call{Call: _e.mock.On("SubscribeLastMessages", ctx, req)} +} + +func (_c *MockService_SubscribeLastMessages_Call) Run(run func(ctx context.Context, req chatsubscription.SubscribeLastMessagesRequest)) *MockService_SubscribeLastMessages_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(chatsubscription.SubscribeLastMessagesRequest)) + }) + return _c +} + +func (_c *MockService_SubscribeLastMessages_Call) Return(_a0 *chatsubscription.SubscribeLastMessagesResponse, _a1 error) *MockService_SubscribeLastMessages_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockService_SubscribeLastMessages_Call) RunAndReturn(run func(context.Context, chatsubscription.SubscribeLastMessagesRequest) (*chatsubscription.SubscribeLastMessagesResponse, error)) *MockService_SubscribeLastMessages_Call { + _c.Call.Return(run) + return _c +} + +// Unsubscribe provides a mock function with given fields: chatObjectId, subId +func (_m *MockService) Unsubscribe(chatObjectId string, subId string) error { + ret := _m.Called(chatObjectId, subId) + + if len(ret) == 0 { + panic("no return value specified for Unsubscribe") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string, string) error); ok { + r0 = rf(chatObjectId, subId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockService_Unsubscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unsubscribe' +type MockService_Unsubscribe_Call struct { + *mock.Call +} + +// Unsubscribe is a helper method to define mock.On call +// - chatObjectId string +// - subId string +func (_e *MockService_Expecter) Unsubscribe(chatObjectId interface{}, subId interface{}) *MockService_Unsubscribe_Call { + return &MockService_Unsubscribe_Call{Call: _e.mock.On("Unsubscribe", chatObjectId, subId)} +} + +func (_c *MockService_Unsubscribe_Call) Run(run func(chatObjectId string, subId string)) *MockService_Unsubscribe_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string), args[1].(string)) + }) + return _c +} + +func (_c *MockService_Unsubscribe_Call) Return(_a0 error) *MockService_Unsubscribe_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockService_Unsubscribe_Call) RunAndReturn(run func(string, string) error) *MockService_Unsubscribe_Call { + _c.Call.Return(run) + return _c +} + +// NewMockService creates a new instance of MockService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewMockService(t interface { + mock.TestingT + Cleanup(func()) +}) *MockService { + mock := &MockService{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/block/chats/chatsubscription/service.go b/core/block/chats/chatsubscription/service.go new file mode 100644 index 000000000..bbf753b1a --- /dev/null +++ b/core/block/chats/chatsubscription/service.go @@ -0,0 +1,251 @@ +package chatsubscription + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/anyproto/any-sync/app" + "github.com/hashicorp/golang-lru/v2/expirable" + + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" + "github.com/anyproto/anytype-heart/core/block/chats/chatrepository" + "github.com/anyproto/anytype-heart/core/block/object/idresolver" + "github.com/anyproto/anytype-heart/core/domain" + "github.com/anyproto/anytype-heart/core/event" + "github.com/anyproto/anytype-heart/core/session" + "github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore" + "github.com/anyproto/anytype-heart/pkg/lib/logging" + "github.com/anyproto/anytype-heart/pkg/lib/pb/model" + "github.com/anyproto/anytype-heart/util/futures" +) + +const CName = "chatsubscription" + +var log = logging.Logger(CName).Desugar() + +type Manager interface { + sync.Locker + + IsActive() bool + GetChatState() *model.ChatState + SetSessionContext(ctx session.Context) + UpdateReactions(message *chatmodel.Message) + UpdateFull(message *chatmodel.Message) + UpdateChatState(updater func(*model.ChatState) *model.ChatState) + Add(prevOrderId string, message *chatmodel.Message) + Delete(messageId string) + Flush() + ReadMessages(newOldestOrderId string, idsModified []string, counterType chatmodel.CounterType) + UnreadMessages(newOldestOrderId string, lastStateId string, msgIds []string, counterType chatmodel.CounterType) +} + +type Service interface { + app.ComponentRunnable + GetManager(chatObjectId string) (Manager, error) + + SubscribeLastMessages(ctx context.Context, req SubscribeLastMessagesRequest) (*SubscribeLastMessagesResponse, error) + Unsubscribe(chatObjectId string, subId string) error +} + +type AccountService interface { + AccountID() string +} + +type service struct { + componentCtx context.Context + componentCtxCancel context.CancelFunc + + spaceIdResolver idresolver.Resolver + objectStore objectstore.ObjectStore + eventSender event.Sender + repositoryService chatrepository.Service + accountService AccountService + + identityCache *expirable.LRU[string, *domain.Details] + lock sync.Mutex + managers map[string]*futures.Future[*subscriptionManager] +} + +func New() Service { + return &service{ + managers: make(map[string]*futures.Future[*subscriptionManager]), + } +} + +func (s *service) Init(a *app.App) (err error) { + s.componentCtx, s.componentCtxCancel = context.WithCancel(context.Background()) + + s.spaceIdResolver = app.MustComponent[idresolver.Resolver](a) + s.objectStore = app.MustComponent[objectstore.ObjectStore](a) + s.eventSender = app.MustComponent[event.Sender](a) + s.repositoryService = app.MustComponent[chatrepository.Service](a) + s.accountService = app.MustComponent[AccountService](a) + s.identityCache = expirable.NewLRU[string, *domain.Details](50, nil, time.Minute) + return nil +} + +func (s *service) Name() (name string) { + return CName +} + +func (s *service) Run(ctx context.Context) (err error) { + return nil +} + +func (s *service) Close(ctx context.Context) (err error) { + if s.componentCtxCancel != nil { + s.componentCtxCancel() + } + return nil +} + +func (s *service) GetManager(chatObjectId string) (Manager, error) { + return s.getManager(chatObjectId) +} + +// getManagerFuture returns a future that should be resolved by the first who called this method. +// The idea behind using futures here is to initialize a manager once without blocking the whole service. +func (s *service) getManagerFuture(chatObjectId string) *futures.Future[*subscriptionManager] { + s.lock.Lock() + mngr, ok := s.managers[chatObjectId] + if ok { + s.lock.Unlock() + return mngr + } + + mngr = futures.New[*subscriptionManager]() + s.managers[chatObjectId] = mngr + s.lock.Unlock() + + mngr.Resolve(s.initManager(chatObjectId)) + + return mngr +} + +func (s *service) getManager(chatObjectId string) (*subscriptionManager, error) { + return s.getManagerFuture(chatObjectId).Wait() +} + +func (s *service) initManager(chatObjectId string) (*subscriptionManager, error) { + spaceId, err := s.spaceIdResolver.ResolveSpaceID(chatObjectId) + if err != nil { + return nil, fmt.Errorf("resolve space id: %w", err) + } + + currentIdentity := s.accountService.AccountID() + currentParticipantId := domain.NewParticipantId(spaceId, currentIdentity) + + repository, err := s.repositoryService.Repository(chatObjectId) + if err != nil { + return nil, fmt.Errorf("get repository: %w", err) + } + mngr := &subscriptionManager{ + componentCtx: s.componentCtx, + spaceId: spaceId, + chatId: chatObjectId, + myIdentity: currentIdentity, + myParticipantId: currentParticipantId, + identityCache: s.identityCache, + subscriptions: make(map[string]*subscription), + spaceIndex: s.objectStore.SpaceIndex(spaceId), + eventSender: s.eventSender, + repository: repository, + } + + err = mngr.loadChatState(s.componentCtx) + if err != nil { + err = fmt.Errorf("init chat state: %w", err) + return nil, err + } + return mngr, nil +} + +type SubscribeLastMessagesRequest struct { + ChatObjectId string + SubId string + Limit int + // If AsyncInit is true, initial messages will be broadcast via events + AsyncInit bool + WithDependencies bool + OnlyLastMessage bool +} + +type SubscribeLastMessagesResponse struct { + Messages []*chatmodel.Message + ChatState *model.ChatState + // Dependencies per message id + Dependencies map[string][]*domain.Details +} + +func (s *service) SubscribeLastMessages(ctx context.Context, req SubscribeLastMessagesRequest) (*SubscribeLastMessagesResponse, error) { + if req.ChatObjectId == "" { + return nil, fmt.Errorf("empty chat object id") + } + + mngr, err := s.getManager(req.ChatObjectId) + if err != nil { + return nil, fmt.Errorf("get manager: %w", err) + } + + mngr.Lock() + defer mngr.Unlock() + + txn, err := mngr.repository.ReadTx(ctx) + if err != nil { + return nil, fmt.Errorf("init read transaction: %w", err) + } + defer txn.Commit() + + messages, err := mngr.repository.GetLastMessages(txn.Context(), uint(req.Limit)) + if err != nil { + return nil, fmt.Errorf("query messages: %w", err) + } + + mngr.subscribe(req.SubId, req.WithDependencies, req.OnlyLastMessage) + + if req.AsyncInit { + var previousOrderId string + if len(messages) > 0 { + previousOrderId, err = mngr.repository.GetPrevOrderId(txn.Context(), messages[0].OrderId) + if err != nil { + return nil, fmt.Errorf("get previous order id: %w", err) + } + } + for _, message := range messages { + mngr.Add(previousOrderId, message) + previousOrderId = message.OrderId + } + + // Force chatState to be sent + mngr.chatStateUpdated = true + mngr.Flush() + return nil, nil + } else { + depsPerMessage := map[string][]*domain.Details{} + if req.WithDependencies { + for _, message := range messages { + deps := mngr.collectMessageDependencies(message.ChatMessage) + depsPerMessage[message.Id] = deps + } + } + return &SubscribeLastMessagesResponse{ + Messages: messages, + ChatState: mngr.GetChatState(), + Dependencies: depsPerMessage, + }, nil + } +} + +func (s *service) Unsubscribe(chatObjectId string, subId string) error { + mngr, err := s.getManager(chatObjectId) + if err != nil { + return fmt.Errorf("get manager: %w", err) + } + mngr.lock.Lock() + defer mngr.lock.Unlock() + + mngr.unsubscribe(subId) + return nil +} diff --git a/core/block/chats/chatsubscription/state.go b/core/block/chats/chatsubscription/state.go new file mode 100644 index 000000000..27fde9e25 --- /dev/null +++ b/core/block/chats/chatsubscription/state.go @@ -0,0 +1,89 @@ +package chatsubscription + +import ( + "github.com/anyproto/anytype-heart/pb" + "github.com/anyproto/anytype-heart/pkg/lib/pb/model" +) + +type messagesState struct { + messages map[string]*model.ChatMessage + + addEvents map[string]*pb.EventChatAdd +} + +func newMessagesState() *messagesState { + return &messagesState{ + messages: map[string]*model.ChatMessage{}, + addEvents: map[string]*pb.EventChatAdd{}, + } +} + +func (s *messagesState) getLastAddedMessage() (*model.ChatMessage, bool) { + var lastMessage *model.ChatMessage + for _, m := range s.messages { + if lastMessage == nil || lastMessage.OrderId < m.OrderId { + lastMessage = m + } + } + + if lastMessage == nil { + return nil, false + } + + _, ok := s.addEvents[lastMessage.Id] + return lastMessage, ok +} + +func (s *messagesState) applyEvent(ev *pb.EventMessage) { + if v := ev.GetChatAdd(); v != nil { + s.applyAdd(v) + } else if v := ev.GetChatDelete(); v != nil { + s.applyDelete(v) + } else if v := ev.GetChatUpdate(); v != nil { + s.applyUpdate(v) + } else if v := ev.GetChatUpdateMentionReadStatus(); v != nil { + s.applyUpdateMentionReadStatus(v) + } else if v := ev.GetChatUpdateMessageReadStatus(); v != nil { + s.applyUpdateMessageReadStatus(v) + } else if v := ev.GetChatUpdateReactions(); v != nil { + s.applyUpdateReactions(v) + } +} + +func (s *messagesState) applyAdd(ev *pb.EventChatAdd) { + s.messages[ev.Id] = ev.Message + s.addEvents[ev.Id] = ev +} + +func (s *messagesState) applyDelete(ev *pb.EventChatDelete) { + delete(s.messages, ev.Id) +} + +func (s *messagesState) applyUpdate(ev *pb.EventChatUpdate) { + s.messages[ev.Id] = ev.Message +} + +func (s *messagesState) applyUpdateMentionReadStatus(ev *pb.EventChatUpdateMentionReadStatus) { + for _, id := range ev.Ids { + msg, ok := s.messages[id] + if ok { + msg.MentionRead = ev.IsRead + } + } +} + +func (s *messagesState) applyUpdateMessageReadStatus(ev *pb.EventChatUpdateMessageReadStatus) { + for _, id := range ev.Ids { + msg, ok := s.messages[id] + if ok { + msg.Read = ev.IsRead + } + } +} + +func (s *messagesState) applyUpdateReactions(ev *pb.EventChatUpdateReactions) { + msg, ok := s.messages[ev.Id] + if ok { + msg.Reactions = ev.Reactions + } +} diff --git a/core/block/chats/service.go b/core/block/chats/service.go index 96a60e138..7cba4a227 100644 --- a/core/block/chats/service.go +++ b/core/block/chats/service.go @@ -14,7 +14,10 @@ import ( "go.uber.org/zap" "github.com/anyproto/anytype-heart/core/block/cache" + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" "github.com/anyproto/anytype-heart/core/block/chats/chatpush" + "github.com/anyproto/anytype-heart/core/block/chats/chatrepository" + "github.com/anyproto/anytype-heart/core/block/chats/chatsubscription" "github.com/anyproto/anytype-heart/core/block/editor/chatobject" "github.com/anyproto/anytype-heart/core/domain" "github.com/anyproto/anytype-heart/core/session" @@ -33,20 +36,22 @@ const CName = "core.block.chats" var log = logging.Logger(CName).Desugar() type Service interface { - AddMessage(ctx context.Context, sessionCtx session.Context, chatObjectId string, message *chatobject.Message) (string, error) - EditMessage(ctx context.Context, chatObjectId string, messageId string, newMessage *chatobject.Message) error + AddMessage(ctx context.Context, sessionCtx session.Context, chatObjectId string, message *chatmodel.Message) (string, error) + EditMessage(ctx context.Context, chatObjectId string, messageId string, newMessage *chatmodel.Message) error ToggleMessageReaction(ctx context.Context, chatObjectId string, messageId string, emoji string) error DeleteMessage(ctx context.Context, chatObjectId string, messageId string) error - GetMessages(ctx context.Context, chatObjectId string, req chatobject.GetMessagesRequest) (*chatobject.GetMessagesResponse, error) - GetMessagesByIds(ctx context.Context, chatObjectId string, messageIds []string) ([]*chatobject.Message, error) - SubscribeLastMessages(ctx context.Context, chatObjectId string, limit int, subId string) (*chatobject.SubscribeLastMessagesResponse, error) + GetMessages(ctx context.Context, chatObjectId string, req chatrepository.GetMessagesRequest) (*chatobject.GetMessagesResponse, error) + GetMessagesByIds(ctx context.Context, chatObjectId string, messageIds []string) ([]*chatmodel.Message, error) + SubscribeLastMessages(ctx context.Context, chatObjectId string, limit int, subId string) (*chatsubscription.SubscribeLastMessagesResponse, error) ReadMessages(ctx context.Context, req ReadMessagesRequest) error - UnreadMessages(ctx context.Context, chatObjectId string, afterOrderId string, counterType chatobject.CounterType) error + UnreadMessages(ctx context.Context, chatObjectId string, afterOrderId string, counterType chatmodel.CounterType) error Unsubscribe(chatObjectId string, subId string) error SubscribeToMessagePreviews(ctx context.Context, subId string) (*SubscribeToMessagePreviewsResponse, error) UnsubscribeFromMessagePreviews(subId string) error + ReadAll(ctx context.Context) error + app.ComponentRunnable } @@ -61,11 +66,12 @@ type accountService interface { } type service struct { - objectGetter cache.ObjectWaitGetter - crossSpaceSubService crossspacesub.Service - pushService pushService - accountService accountService - objectStore objectstore.ObjectStore + objectGetter cache.ObjectWaitGetter + crossSpaceSubService crossspacesub.Service + pushService pushService + accountService accountService + objectStore objectstore.ObjectStore + chatSubscriptionService chatsubscription.Service componentCtx context.Context componentCtxCancel context.CancelFunc @@ -99,6 +105,7 @@ func (s *service) Init(a *app.App) error { s.accountService = app.MustComponent[accountService](a) s.objectStore = app.MustComponent[objectstore.ObjectStore](a) s.objectGetter = app.MustComponent[cache.ObjectWaitGetter](a) + s.chatSubscriptionService = app.MustComponent[chatsubscription.Service](a) return nil } @@ -111,7 +118,7 @@ type ChatPreview struct { SpaceId string ChatObjectId string State *model.ChatState - Message *chatobject.Message + Message *chatmodel.Message Dependencies []*domain.Details } @@ -132,32 +139,43 @@ func (s *service) SubscribeToMessagePreviews(ctx context.Context, subId string) s.subscriptionIds[subId] = struct{}{} + lock := &sync.Mutex{} result := &SubscribeToMessagePreviewsResponse{ Previews: make([]*ChatPreview, 0, len(s.allChatObjectIds)), } - + var wg sync.WaitGroup for chatObjectId, spaceId := range s.allChatObjectIds { - chatAddResp, err := s.onChatAdded(chatObjectId, subId, false) - if err != nil { - log.Error("init lastMessage subscription", zap.Error(err)) - continue - } - var ( - message *chatobject.Message - dependencies []*domain.Details - ) - if len(chatAddResp.Messages) > 0 { - message = chatAddResp.Messages[0] - dependencies = chatAddResp.Dependencies[message.Id] - } - result.Previews = append(result.Previews, &ChatPreview{ - SpaceId: spaceId, - ChatObjectId: chatObjectId, - State: chatAddResp.ChatState, - Message: message, - Dependencies: dependencies, - }) + wg.Add(1) + go func() { + defer wg.Done() + + chatAddResp, err := s.onChatAdded(chatObjectId, subId, false) + if err != nil { + log.Error("init lastMessage subscription", zap.Error(err)) + return + } + var ( + message *chatmodel.Message + dependencies []*domain.Details + ) + if len(chatAddResp.Messages) > 0 { + message = chatAddResp.Messages[0] + dependencies = chatAddResp.Dependencies[message.Id] + } + + lock.Lock() + defer lock.Unlock() + result.Previews = append(result.Previews, &ChatPreview{ + SpaceId: spaceId, + ChatObjectId: chatObjectId, + State: chatAddResp.ChatState, + Message: message, + Dependencies: dependencies, + }) + }() } + wg.Wait() + return result, nil } @@ -260,22 +278,15 @@ func (s *service) monitorMessagePreviews() { } } -func (s *service) onChatAdded(chatObjectId string, subId string, asyncInit bool) (*chatobject.SubscribeLastMessagesResponse, error) { - var resp *chatobject.SubscribeLastMessagesResponse - err := s.chatObjectDo(s.componentCtx, chatObjectId, func(sb chatobject.StoreObject) error { - var err error - resp, err = sb.SubscribeLastMessages(s.componentCtx, chatobject.SubscribeLastMessagesRequest{ - SubId: subId, - Limit: 1, - AsyncInit: asyncInit, - WithDependencies: true, - }) - if err != nil { - return err - } - return nil +func (s *service) onChatAdded(chatObjectId string, subId string, asyncInit bool) (*chatsubscription.SubscribeLastMessagesResponse, error) { + return s.chatSubscriptionService.SubscribeLastMessages(s.componentCtx, chatsubscription.SubscribeLastMessagesRequest{ + ChatObjectId: chatObjectId, + SubId: subId, + Limit: 1, + AsyncInit: asyncInit, + WithDependencies: true, + OnlyLastMessage: true, }) - return resp, err } func (s *service) onChatRemoved(chatObjectId string, subId string) error { @@ -302,7 +313,7 @@ func (s *service) Close(ctx context.Context) error { return err } -func (s *service) AddMessage(ctx context.Context, sessionCtx session.Context, chatObjectId string, message *chatobject.Message) (string, error) { +func (s *service) AddMessage(ctx context.Context, sessionCtx session.Context, chatObjectId string, message *chatmodel.Message) (string, error) { var messageId, spaceId string err := s.chatObjectDo(ctx, chatObjectId, func(sb chatobject.StoreObject) error { var err error @@ -311,18 +322,16 @@ func (s *service) AddMessage(ctx context.Context, sessionCtx session.Context, ch return err }) if err == nil { - go func() { - err := s.sendPushNotification(spaceId, chatObjectId, messageId, message.Message.Text) - if err != nil { - log.Error("sendPushNotification: ", zap.Error(err)) - } - }() + pushErr := s.sendPushNotification(spaceId, chatObjectId, messageId, message.Message.Text, len(message.Attachments) != 0) + if pushErr != nil { + log.Error("sendPushNotification: ", zap.Error(pushErr)) + } } return messageId, err } -func (s *service) sendPushNotification(spaceId, chatObjectId string, messageId string, messageText string) (err error) { +func (s *service) sendPushNotification(spaceId, chatObjectId, messageId, messageText string, hasAttachments bool) (err error) { accountId := s.accountService.AccountID() spaceName := s.objectStore.GetSpaceName(spaceId) details, err := s.objectStore.SpaceIndex(spaceId).GetDetails(domain.NewParticipantId(spaceId, accountId)) @@ -338,11 +347,12 @@ func (s *service) sendPushNotification(spaceId, chatObjectId string, messageId s SenderId: accountId, Type: chatpush.ChatMessage, NewMessagePayload: &chatpush.NewMessagePayload{ - ChatId: chatObjectId, - MsgId: messageId, - SpaceName: spaceName, - SenderName: senderName, - Text: messageText, + ChatId: chatObjectId, + MsgId: messageId, + SpaceName: spaceName, + SenderName: senderName, + Text: messageText, + HasAttachments: hasAttachments, }, } @@ -362,7 +372,7 @@ func (s *service) sendPushNotification(spaceId, chatObjectId string, messageId s return } -func (s *service) EditMessage(ctx context.Context, chatObjectId string, messageId string, newMessage *chatobject.Message) error { +func (s *service) EditMessage(ctx context.Context, chatObjectId string, messageId string, newMessage *chatmodel.Message) error { return s.chatObjectDo(ctx, chatObjectId, func(sb chatobject.StoreObject) error { return sb.EditMessage(ctx, messageId, newMessage) }) @@ -380,7 +390,7 @@ func (s *service) DeleteMessage(ctx context.Context, chatObjectId string, messag }) } -func (s *service) GetMessages(ctx context.Context, chatObjectId string, req chatobject.GetMessagesRequest) (*chatobject.GetMessagesResponse, error) { +func (s *service) GetMessages(ctx context.Context, chatObjectId string, req chatrepository.GetMessagesRequest) (*chatobject.GetMessagesResponse, error) { var resp *chatobject.GetMessagesResponse err := s.chatObjectDo(ctx, chatObjectId, func(sb chatobject.StoreObject) error { var err error @@ -393,8 +403,8 @@ func (s *service) GetMessages(ctx context.Context, chatObjectId string, req chat return resp, err } -func (s *service) GetMessagesByIds(ctx context.Context, chatObjectId string, messageIds []string) ([]*chatobject.Message, error) { - var res []*chatobject.Message +func (s *service) GetMessagesByIds(ctx context.Context, chatObjectId string, messageIds []string) ([]*chatmodel.Message, error) { + var res []*chatmodel.Message err := s.chatObjectDo(ctx, chatObjectId, func(sb chatobject.StoreObject) error { msg, err := sb.GetMessagesByIds(ctx, messageIds) if err != nil { @@ -406,28 +416,18 @@ func (s *service) GetMessagesByIds(ctx context.Context, chatObjectId string, mes return res, err } -func (s *service) SubscribeLastMessages(ctx context.Context, chatObjectId string, limit int, subId string) (*chatobject.SubscribeLastMessagesResponse, error) { - var resp *chatobject.SubscribeLastMessagesResponse - err := s.chatObjectDo(ctx, chatObjectId, func(sb chatobject.StoreObject) error { - var err error - resp, err = sb.SubscribeLastMessages(ctx, chatobject.SubscribeLastMessagesRequest{ - SubId: subId, - Limit: limit, - AsyncInit: false, - WithDependencies: false, - }) - if err != nil { - return err - } - return nil +func (s *service) SubscribeLastMessages(ctx context.Context, chatObjectId string, limit int, subId string) (*chatsubscription.SubscribeLastMessagesResponse, error) { + return s.chatSubscriptionService.SubscribeLastMessages(s.componentCtx, chatsubscription.SubscribeLastMessagesRequest{ + ChatObjectId: chatObjectId, + SubId: subId, + Limit: limit, + AsyncInit: false, + WithDependencies: false, }) - return resp, err } func (s *service) Unsubscribe(chatObjectId string, subId string) error { - return s.chatObjectDo(s.componentCtx, chatObjectId, func(sb chatobject.StoreObject) error { - return sb.Unsubscribe(subId) - }) + return s.chatSubscriptionService.Unsubscribe(chatObjectId, subId) } type ReadMessagesRequest struct { @@ -435,16 +435,21 @@ type ReadMessagesRequest struct { AfterOrderId string BeforeOrderId string LastStateId string - CounterType chatobject.CounterType + CounterType chatmodel.CounterType } func (s *service) ReadMessages(ctx context.Context, req ReadMessagesRequest) error { return s.chatObjectDo(ctx, req.ChatObjectId, func(sb chatobject.StoreObject) error { - return sb.MarkReadMessages(ctx, req.AfterOrderId, req.BeforeOrderId, req.LastStateId, req.CounterType) + return sb.MarkReadMessages(ctx, chatobject.ReadMessagesRequest{ + AfterOrderId: req.AfterOrderId, + BeforeOrderId: req.BeforeOrderId, + LastStateId: req.LastStateId, + CounterType: req.CounterType, + }) }) } -func (s *service) UnreadMessages(ctx context.Context, chatObjectId string, afterOrderId string, counterType chatobject.CounterType) error { +func (s *service) UnreadMessages(ctx context.Context, chatObjectId string, afterOrderId string, counterType chatmodel.CounterType) error { return s.chatObjectDo(ctx, chatObjectId, func(sb chatobject.StoreObject) error { return sb.MarkMessagesAsUnread(ctx, afterOrderId, counterType) }) @@ -455,3 +460,37 @@ func (s *service) chatObjectDo(ctx context.Context, chatObjectId string, proc fu defer cancel() return cache.DoWait(s.objectGetter, waitCtx, chatObjectId, proc) } + +func (s *service) ReadAll(ctx context.Context) error { + s.lock.Lock() + chatIds := make([]string, 0, len(s.allChatObjectIds)) + for id := range s.allChatObjectIds { + chatIds = append(chatIds, id) + } + s.lock.Unlock() + + for _, chatId := range chatIds { + err := s.chatObjectDo(ctx, chatId, func(sb chatobject.StoreObject) error { + err := sb.MarkReadMessages(ctx, chatobject.ReadMessagesRequest{ + All: true, + CounterType: chatmodel.CounterTypeMessage, + }) + if err != nil { + return fmt.Errorf("messages: %w", err) + } + err = sb.MarkReadMessages(ctx, chatobject.ReadMessagesRequest{ + All: true, + CounterType: chatmodel.CounterTypeMention, + }) + if err != nil { + return fmt.Errorf("mentions: %w", err) + } + return nil + }) + if err != nil { + return fmt.Errorf("read: %w", err) + } + } + + return nil +} diff --git a/core/block/chats/service_test.go b/core/block/chats/service_test.go index 1810638ee..6cb558401 100644 --- a/core/block/chats/service_test.go +++ b/core/block/chats/service_test.go @@ -13,9 +13,9 @@ import ( "github.com/stretchr/testify/require" "github.com/anyproto/anytype-heart/core/block/cache/mock_cache" - "github.com/anyproto/anytype-heart/core/block/editor/chatobject" - "github.com/anyproto/anytype-heart/core/block/editor/chatobject/mock_chatobject" - "github.com/anyproto/anytype-heart/core/block/editor/smartblock" + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" + "github.com/anyproto/anytype-heart/core/block/chats/chatsubscription" + "github.com/anyproto/anytype-heart/core/block/chats/chatsubscription/mock_chatsubscription" "github.com/anyproto/anytype-heart/core/domain" "github.com/anyproto/anytype-heart/core/subscription" "github.com/anyproto/anytype-heart/core/subscription/crossspacesub/mock_crossspacesub" @@ -70,6 +70,7 @@ type fixture struct { *service objectGetter *mock_cache.MockObjectWaitGetterComponent + subscriptionService *mock_chatsubscription.MockService app *app.App crossSpaceSubService *mock_crossspacesub.MockService @@ -109,10 +110,12 @@ func newFixture(t *testing.T) *fixture { objectStore := objectstore.NewStoreFixture(t) objectGetter := mock_cache.NewMockObjectWaitGetterComponent(t) crossSpaceSubService := mock_crossspacesub.NewMockService(t) + subscriptionService := mock_chatsubscription.NewMockService(t) fx := &fixture{ service: New().(*service), crossSpaceSubService: crossSpaceSubService, + subscriptionService: subscriptionService, objectGetter: objectGetter, actions: map[string][]recordedAction{}, } @@ -122,12 +125,14 @@ func newFixture(t *testing.T) *fixture { a.Register(objectStore) a.Register(testutil.PrepareMock(ctx, a, objectGetter)) a.Register(testutil.PrepareMock(ctx, a, crossSpaceSubService)) + a.Register(testutil.PrepareMock(ctx, a, subscriptionService)) a.Register(&pushServiceDummy{}) a.Register(&accountServiceDummy{}) a.Register(fx) fx.app = a + fx.expectSubscribe(t) return fx } @@ -136,13 +141,8 @@ func (fx *fixture) start(t *testing.T) { require.NoError(t, err) } -type chatObjectWrapper struct { - smartblock.SmartBlock - chatobject.StoreObject -} - -func givenLastMessages() []*chatobject.Message { - return []*chatobject.Message{ +func givenLastMessages() []*chatmodel.Message { + return []*chatmodel.Message{ { ChatMessage: &model.ChatMessage{ Id: "messageId1", @@ -172,34 +172,26 @@ func givenDependencies() map[string][]*domain.Details { } } -func (fx *fixture) expectChatObject(t *testing.T, chatObjectId string) { - fx.objectGetter.EXPECT().WaitAndGetObject(mock.Anything, chatObjectId).RunAndReturn(func(ctx context.Context, id string) (smartblock.SmartBlock, error) { - sb := mock_chatobject.NewMockStoreObject(t) +func (fx *fixture) expectSubscribe(t *testing.T) { + fx.subscriptionService.EXPECT().SubscribeLastMessages(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, req chatsubscription.SubscribeLastMessagesRequest) (*chatsubscription.SubscribeLastMessagesResponse, error) { + fx.recordAction(req.ChatObjectId, recordedAction{ + actionType: actionTypeSubscribe, + subId: req.SubId, + }) + return &chatsubscription.SubscribeLastMessagesResponse{ + Messages: givenLastMessages(), + ChatState: givenLastState(), + Dependencies: givenDependencies(), + }, nil + }).Maybe() - sb.EXPECT().Lock().Return().Maybe() - sb.EXPECT().Unlock().Return().Maybe() - sb.EXPECT().SubscribeLastMessages(mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, req chatobject.SubscribeLastMessagesRequest) (*chatobject.SubscribeLastMessagesResponse, error) { - fx.recordAction(chatObjectId, recordedAction{ - actionType: actionTypeSubscribe, - subId: req.SubId, - }) - return &chatobject.SubscribeLastMessagesResponse{ - Messages: givenLastMessages(), - ChatState: givenLastState(), - Dependencies: givenDependencies(), - }, nil - }).Maybe() - - sb.EXPECT().Unsubscribe(mock.Anything).RunAndReturn(func(subId string) error { - fx.recordAction(chatObjectId, recordedAction{ - actionType: actionTypeUnsubscribe, - subId: subId, - }) - return nil - }).Maybe() - - return sb, nil - }) + fx.subscriptionService.EXPECT().Unsubscribe(mock.Anything, mock.Anything).RunAndReturn(func(chatObjectId string, subId string) error { + fx.recordAction(chatObjectId, recordedAction{ + actionType: actionTypeUnsubscribe, + subId: subId, + }) + return nil + }).Maybe() } func TestSubscribeToMessagePreviews(t *testing.T) { @@ -220,9 +212,6 @@ func TestSubscribeToMessagePreviews(t *testing.T) { }, }, nil).Maybe() - fx.expectChatObject(t, "chat1") - fx.expectChatObject(t, "chat2") - fx.start(t) resp, err := fx.SubscribeToMessagePreviews(ctx, "previewSub1") @@ -270,9 +259,6 @@ func TestSubscribeToMessagePreviews(t *testing.T) { Records: []*domain.Details{}, }, nil).Maybe() - fx.expectChatObject(t, "chat1") - fx.expectChatObject(t, "chat2") - fx.start(t) fx.chatObjectsSubQueue.Add(ctx, &pb.EventMessage{ @@ -329,9 +315,6 @@ func TestSubscribeToMessagePreviews(t *testing.T) { }, }, nil).Maybe() - fx.expectChatObject(t, "chat1") - fx.expectChatObject(t, "chat2") - fx.start(t) fx.chatObjectsSubQueue.Add(ctx, &pb.EventMessage{ @@ -384,9 +367,6 @@ func TestSubscribeToMessagePreviews(t *testing.T) { }, }, nil).Maybe() - fx.expectChatObject(t, "chat1") - fx.expectChatObject(t, "chat2") - fx.start(t) resp, err := fx.SubscribeToMessagePreviews(ctx, "previewSub1") diff --git a/core/block/editor/accountobject/accountobject.go b/core/block/editor/accountobject/accountobject.go index 32fbd2f67..c95bbb2d6 100644 --- a/core/block/editor/accountobject/accountobject.go +++ b/core/block/editor/accountobject/accountobject.go @@ -136,7 +136,9 @@ func (a *accountObject) Init(ctx *smartblock.InitContext) error { } storeSource.SetPushChangeHook(a.OnPushChange) a.storeSource = storeSource - err = storeSource.ReadStoreDoc(ctx.Ctx, stateStore, a.onUpdate) + err = storeSource.ReadStoreDoc(ctx.Ctx, stateStore, source.ReadStoreDocParams{ + OnUpdateHook: a.onUpdate, + }) if err != nil { return fmt.Errorf("read store doc: %w", err) } diff --git a/core/block/editor/basic/details.go b/core/block/editor/basic/details.go index a7e170e64..27c175a6b 100644 --- a/core/block/editor/basic/details.go +++ b/core/block/editor/basic/details.go @@ -350,6 +350,7 @@ func (bs *basic) SetObjectTypesInState(s *state.State, objectTypeKeys []domain.T s.SetObjectTypeKeys(objectTypeKeys) removeInternalFlags(s) + s.Details().Delete(bundle.RelationKeyLayout) toLayout, err := bs.getLayoutForType(objectTypeKeys[0]) if err != nil { diff --git a/core/block/editor/chatobject/chathandler.go b/core/block/editor/chatobject/chathandler.go index 1dbe96607..249cdc546 100644 --- a/core/block/editor/chatobject/chathandler.go +++ b/core/block/editor/chatobject/chathandler.go @@ -11,14 +11,17 @@ import ( "github.com/anyproto/any-store/query" "github.com/globalsign/mgo/bson" + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" + "github.com/anyproto/anytype-heart/core/block/chats/chatrepository" + "github.com/anyproto/anytype-heart/core/block/chats/chatsubscription" "github.com/anyproto/anytype-heart/core/block/editor/storestate" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) type ChatHandler struct { - repository *repository - subscription *subscriptionManager + repository chatrepository.Repository + subscription chatsubscription.Manager currentIdentity string myParticipantId string // forceNotRead forces handler to mark all messages as not read. It's useful for unit testing @@ -44,7 +47,7 @@ func (d *ChatHandler) Init(ctx context.Context, s *storestate.StoreState) (err e } func (d *ChatHandler) BeforeCreate(ctx context.Context, ch storestate.ChangeOp) error { - msg, err := unmarshalMessage(ch.Value) + msg, err := chatmodel.UnmarshalMessage(ch.Value) if err != nil { return fmt.Errorf("unmarshal message: %w", err) } @@ -72,12 +75,14 @@ func (d *ChatHandler) BeforeCreate(ctx context.Context, ch storestate.ChangeOp) msg.CurrentUserMentioned = isMentioned msg.OrderId = ch.Change.Order - prevOrderId, err := d.repository.getPrevOrderId(ctx, ch.Change.Order) + prevOrderId, err := d.repository.GetPrevOrderId(ctx, ch.Change.Order) if err != nil { return fmt.Errorf("get prev order id: %w", err) } - d.subscription.updateChatState(func(state *model.ChatState) *model.ChatState { + d.subscription.Lock() + defer d.subscription.Unlock() + d.subscription.UpdateChatState(func(state *model.ChatState) *model.ChatState { if !msg.Read { if msg.OrderId < state.Messages.OldestOrderId || state.Messages.OldestOrderId == "" { state.Messages.OldestOrderId = msg.OrderId @@ -98,7 +103,7 @@ func (d *ChatHandler) BeforeCreate(ctx context.Context, ch storestate.ChangeOp) return state }) - d.subscription.add(prevOrderId, msg) + d.subscription.Add(prevOrderId, msg) msg.MarshalAnyenc(ch.Value, ch.Arena) @@ -122,7 +127,7 @@ func (d *ChatHandler) BeforeDelete(ctx context.Context, ch storestate.ChangeOp) return storestate.DeleteModeDelete, fmt.Errorf("get message: %w", err) } - message, err := unmarshalMessage(doc.Value()) + message, err := chatmodel.UnmarshalMessage(doc.Value()) if err != nil { return storestate.DeleteModeDelete, fmt.Errorf("unmarshal message: %w", err) } @@ -130,7 +135,9 @@ func (d *ChatHandler) BeforeDelete(ctx context.Context, ch storestate.ChangeOp) return storestate.DeleteModeDelete, errors.New("can't delete not own message") } - d.subscription.delete(messageId) + d.subscription.Lock() + defer d.subscription.Unlock() + d.subscription.Delete(messageId) return storestate.DeleteModeDelete, nil } @@ -149,13 +156,16 @@ func (d *ChatHandler) UpgradeKeyModifier(ch storestate.ChangeOp, key *pb.KeyModi } if modified { - msg, err := unmarshalMessage(result) + msg, err := chatmodel.UnmarshalMessage(result) if err != nil { return nil, false, fmt.Errorf("unmarshal message: %w", err) } + d.subscription.Lock() + defer d.subscription.Unlock() + switch path { - case reactionsKey: + case chatmodel.ReactionsKey: // Do not parse json, just trim " identity := strings.Trim(key.ModifyValue, `"`) if identity != ch.Change.Creator { @@ -163,15 +173,15 @@ func (d *ChatHandler) UpgradeKeyModifier(ch storestate.ChangeOp, key *pb.KeyModi } // TODO Count validation - d.subscription.updateReactions(msg) - case contentKey: + d.subscription.UpdateReactions(msg) + case chatmodel.ContentKey: creator := msg.Creator if creator != ch.Change.Creator { return v, false, errors.Join(storestate.ErrValidation, fmt.Errorf("can't modify someone else's message")) } msg.ModifiedAt = ch.Change.Timestamp msg.MarshalAnyenc(result, a) - d.subscription.updateFull(msg) + d.subscription.UpdateFull(msg) default: return nil, false, fmt.Errorf("invalid key path %s", key.KeyPath) } diff --git a/core/block/editor/chatobject/chatobject.go b/core/block/editor/chatobject/chatobject.go index 9d9589512..9a698b8e0 100644 --- a/core/block/editor/chatobject/chatobject.go +++ b/core/block/editor/chatobject/chatobject.go @@ -2,26 +2,27 @@ package chatobject import ( "context" - "errors" "fmt" "time" anystore "github.com/anyproto/any-store" "github.com/anyproto/any-store/anyenc" + "github.com/anyproto/any-sync/commonspace/object/accountdata" "github.com/anyproto/any-sync/commonspace/object/tree/objecttree" "github.com/anyproto/any-sync/util/slice" "go.uber.org/zap" "golang.org/x/exp/slices" + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" + "github.com/anyproto/anytype-heart/core/block/chats/chatrepository" + "github.com/anyproto/anytype-heart/core/block/chats/chatsubscription" "github.com/anyproto/anytype-heart/core/block/editor/anystoredebug" "github.com/anyproto/anytype-heart/core/block/editor/smartblock" "github.com/anyproto/anytype-heart/core/block/editor/storestate" "github.com/anyproto/anytype-heart/core/block/source" "github.com/anyproto/anytype-heart/core/domain" - "github.com/anyproto/anytype-heart/core/event" "github.com/anyproto/anytype-heart/core/session" "github.com/anyproto/anytype-heart/pb" - "github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex" "github.com/anyproto/anytype-heart/pkg/lib/logging" "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) @@ -41,27 +42,19 @@ type StoreObject interface { smartblock.SmartBlock anystoredebug.AnystoreDebug - AddMessage(ctx context.Context, sessionCtx session.Context, message *Message) (string, error) - GetMessages(ctx context.Context, req GetMessagesRequest) (*GetMessagesResponse, error) - GetMessagesByIds(ctx context.Context, messageIds []string) ([]*Message, error) - EditMessage(ctx context.Context, messageId string, newMessage *Message) error + AddMessage(ctx context.Context, sessionCtx session.Context, message *chatmodel.Message) (string, error) + GetMessages(ctx context.Context, req chatrepository.GetMessagesRequest) (*GetMessagesResponse, error) + GetMessagesByIds(ctx context.Context, messageIds []string) ([]*chatmodel.Message, error) + EditMessage(ctx context.Context, messageId string, newMessage *chatmodel.Message) error ToggleMessageReaction(ctx context.Context, messageId string, emoji string) error DeleteMessage(ctx context.Context, messageId string) error - SubscribeLastMessages(ctx context.Context, req SubscribeLastMessagesRequest) (*SubscribeLastMessagesResponse, error) - MarkReadMessages(ctx context.Context, afterOrderId string, beforeOrderId string, lastStateId string, counterType CounterType) error - MarkMessagesAsUnread(ctx context.Context, afterOrderId string, counterType CounterType) error - Unsubscribe(subId string) error -} - -type GetMessagesRequest struct { - AfterOrderId string - BeforeOrderId string - Limit int - IncludeBoundary bool + MarkReadMessages(ctx context.Context, req ReadMessagesRequest) error + MarkMessagesAsUnread(ctx context.Context, afterOrderId string, counterType chatmodel.CounterType) error } type AccountService interface { AccountID() string + Keys() *accountdata.AccountKeys } type seenHeadsCollector interface { @@ -73,34 +66,34 @@ type storeObject struct { smartblock.SmartBlock locker smartblock.Locker - seenHeadsCollector seenHeadsCollector - accountService AccountService - storeSource source.Store - store *storestate.StoreState - eventSender event.Sender - subscription *subscriptionManager - crdtDb anystore.DB - spaceIndex spaceindex.Store - chatHandler *ChatHandler - repository *repository + seenHeadsCollector seenHeadsCollector + accountService AccountService + storeSource source.Store + repositoryService chatrepository.Service + store *storestate.StoreState + chatSubscriptionService chatsubscription.Service + subscription chatsubscription.Manager + crdtDb anystore.DB + chatHandler *ChatHandler + repository chatrepository.Repository arenaPool *anyenc.ArenaPool componentCtx context.Context componentCtxCancel context.CancelFunc } -func New(sb smartblock.SmartBlock, accountService AccountService, eventSender event.Sender, crdtDb anystore.DB, spaceIndex spaceindex.Store) StoreObject { +func New(sb smartblock.SmartBlock, accountService AccountService, crdtDb anystore.DB, repositoryService chatrepository.Service, chatSubscriptionService chatsubscription.Service) StoreObject { ctx, cancel := context.WithCancel(context.Background()) return &storeObject{ - SmartBlock: sb, - locker: sb.(smartblock.Locker), - accountService: accountService, - arenaPool: &anyenc.ArenaPool{}, - eventSender: eventSender, - crdtDb: crdtDb, - componentCtx: ctx, - componentCtxCancel: cancel, - spaceIndex: spaceIndex, + SmartBlock: sb, + locker: sb.(smartblock.Locker), + accountService: accountService, + arenaPool: &anyenc.ArenaPool{}, + crdtDb: crdtDb, + repositoryService: repositoryService, + componentCtx: ctx, + componentCtxCancel: cancel, + chatSubscriptionService: chatSubscriptionService, } } @@ -110,42 +103,24 @@ func (s *storeObject) Init(ctx *smartblock.InitContext) error { return fmt.Errorf("source is not a store") } - collectionName := storeSource.Id() + CollectionName - collection, err := s.crdtDb.OpenCollection(ctx.Ctx, collectionName) - if errors.Is(err, anystore.ErrCollectionNotFound) { - collection, err = s.crdtDb.CreateCollection(ctx.Ctx, collectionName) - if err != nil { - return fmt.Errorf("create collection: %w", err) - } - } + var err error + s.repository, err = s.repositoryService.Repository(storeSource.Id()) if err != nil { - return fmt.Errorf("get collection: %w", err) + return fmt.Errorf("get repository: %w", err) } - s.repository = &repository{ - collection: collection, - arenaPool: s.arenaPool, - } // Use Object and Space IDs from source, because object is not initialized yet myParticipantId := domain.NewParticipantId(ctx.Source.SpaceID(), s.accountService.AccountID()) - s.subscription = s.newSubscriptionManager( - domain.FullID{ObjectID: ctx.Source.Id(), SpaceID: ctx.Source.SpaceID()}, - s.accountService.AccountID(), - myParticipantId, - ) - - messagesOpts := newReadHandler(CounterTypeMessage, s.subscription) - mentionsOpts := newReadHandler(CounterTypeMention, s.subscription) // Diff managers should be added before SmartBlock.Init, because they have to be initialized in source.ReadStoreDoc storeSource.RegisterDiffManager(diffManagerMessages, func(removed []string) { - markErr := s.markReadMessages(removed, messagesOpts) + markErr := s.markReadMessages(removed, chatmodel.CounterTypeMessage) if markErr != nil { log.Error("mark read messages", zap.Error(markErr)) } }) storeSource.RegisterDiffManager(diffManagerMentions, func(removed []string) { - markErr := s.markReadMessages(removed, mentionsOpts) + markErr := s.markReadMessages(removed, chatmodel.CounterTypeMention) if markErr != nil { log.Error("mark read mentions", zap.Error(markErr)) } @@ -157,6 +132,11 @@ func (s *storeObject) Init(ctx *smartblock.InitContext) error { } s.storeSource = storeSource + s.subscription, err = s.chatSubscriptionService.GetManager(storeSource.Id()) + if err != nil { + return fmt.Errorf("get subscription manager: %w", err) + } + s.chatHandler = &ChatHandler{ repository: s.repository, subscription: s.subscription, @@ -170,12 +150,13 @@ func (s *storeObject) Init(ctx *smartblock.InitContext) error { } s.store = stateStore - err = s.subscription.loadChatState(s.componentCtx) - if err != nil { - return fmt.Errorf("init chat state: %w", err) - } - - err = storeSource.ReadStoreDoc(ctx.Ctx, stateStore, s.onUpdate) + err = storeSource.ReadStoreDoc(ctx.Ctx, stateStore, source.ReadStoreDocParams{ + OnUpdateHook: s.onUpdate, + ReadStoreTreeHook: &readStoreTreeHook{ + currentIdentity: s.accountService.Keys().SignKey.GetPublic(), + source: s.storeSource, + }, + }) if err != nil { return fmt.Errorf("read store doc: %w", err) } @@ -188,10 +169,12 @@ func (s *storeObject) Init(ctx *smartblock.InitContext) error { } func (s *storeObject) onUpdate() { - s.subscription.flush() + s.subscription.Lock() + defer s.subscription.Unlock() + s.subscription.Flush() } -func (s *storeObject) GetMessageById(ctx context.Context, id string) (*Message, error) { +func (s *storeObject) GetMessageById(ctx context.Context, id string) (*chatmodel.Message, error) { messages, err := s.GetMessagesByIds(ctx, []string{id}) if err != nil { return nil, err @@ -202,27 +185,27 @@ func (s *storeObject) GetMessageById(ctx context.Context, id string) (*Message, return messages[0], nil } -func (s *storeObject) GetMessagesByIds(ctx context.Context, messageIds []string) ([]*Message, error) { - return s.repository.getMessagesByIds(ctx, messageIds) +func (s *storeObject) GetMessagesByIds(ctx context.Context, messageIds []string) ([]*chatmodel.Message, error) { + return s.repository.GetMessagesByIds(ctx, messageIds) } type GetMessagesResponse struct { - Messages []*Message + Messages []*chatmodel.Message ChatState *model.ChatState } -func (s *storeObject) GetMessages(ctx context.Context, req GetMessagesRequest) (*GetMessagesResponse, error) { - msgs, err := s.repository.getMessages(ctx, req) +func (s *storeObject) GetMessages(ctx context.Context, req chatrepository.GetMessagesRequest) (*GetMessagesResponse, error) { + msgs, err := s.repository.GetMessages(ctx, req) if err != nil { return nil, err } return &GetMessagesResponse{ Messages: msgs, - ChatState: s.subscription.getChatState(), + ChatState: s.subscription.GetChatState(), }, nil } -func (s *storeObject) AddMessage(ctx context.Context, sessionCtx session.Context, message *Message) (string, error) { +func (s *storeObject) AddMessage(ctx context.Context, sessionCtx session.Context, message *chatmodel.Message) (string, error) { arena := s.arenaPool.Get() defer func() { arena.Reset() @@ -242,7 +225,14 @@ func (s *storeObject) AddMessage(ctx context.Context, sessionCtx session.Context return "", fmt.Errorf("create chat: %w", err) } - s.subscription.setSessionContext(sessionCtx) + s.subscription.Lock() + s.subscription.SetSessionContext(sessionCtx) + s.subscription.Unlock() + defer func() { + s.subscription.Lock() + s.subscription.SetSessionContext(nil) + s.subscription.Unlock() + }() messageId, err := s.storeSource.PushStoreChange(ctx, source.PushStoreChangeParams{ Changes: builder.ChangeSet, State: s.store, @@ -253,10 +243,8 @@ func (s *storeObject) AddMessage(ctx context.Context, sessionCtx session.Context } if !s.chatHandler.forceNotRead { - for _, counterType := range []CounterType{CounterTypeMessage, CounterTypeMention} { - handler := newReadHandler(counterType, s.subscription) - - err = s.storeSource.MarkSeenHeads(ctx, handler.getDiffManagerName(), []string{messageId}) + for _, counterType := range []chatmodel.CounterType{chatmodel.CounterTypeMessage, chatmodel.CounterTypeMention} { + err = s.storeSource.MarkSeenHeads(ctx, counterType.DiffManagerName(), []string{messageId}) if err != nil { return "", fmt.Errorf("mark read: %w", err) } @@ -280,7 +268,7 @@ func (s *storeObject) DeleteMessage(ctx context.Context, messageId string) error return nil } -func (s *storeObject) EditMessage(ctx context.Context, messageId string, newMessage *Message) error { +func (s *storeObject) EditMessage(ctx context.Context, messageId string, newMessage *chatmodel.Message) error { arena := s.arenaPool.Get() defer func() { arena.Reset() @@ -291,7 +279,7 @@ func (s *storeObject) EditMessage(ctx context.Context, messageId string, newMess newMessage.MarshalAnyenc(obj, arena) builder := storestate.Builder{} - err := builder.Modify(CollectionName, messageId, []string{contentKey}, pb.ModifyOp_Set, obj.Get(contentKey)) + err := builder.Modify(CollectionName, messageId, []string{chatmodel.ContentKey}, pb.ModifyOp_Set, obj.Get(chatmodel.ContentKey)) if err != nil { return fmt.Errorf("modify content: %w", err) } @@ -313,7 +301,7 @@ func (s *storeObject) ToggleMessageReaction(ctx context.Context, messageId strin s.arenaPool.Put(arena) }() - hasReaction, err := s.repository.hasMyReaction(ctx, s.accountService.AccountID(), messageId, emoji) + hasReaction, err := s.repository.HasMyReaction(ctx, s.accountService.AccountID(), messageId, emoji) if err != nil { return fmt.Errorf("check reaction: %w", err) } @@ -321,12 +309,12 @@ func (s *storeObject) ToggleMessageReaction(ctx context.Context, messageId strin builder := storestate.Builder{} if hasReaction { - err = builder.Modify(CollectionName, messageId, []string{reactionsKey, emoji}, pb.ModifyOp_Pull, arena.NewString(s.accountService.AccountID())) + err = builder.Modify(CollectionName, messageId, []string{chatmodel.ReactionsKey, emoji}, pb.ModifyOp_Pull, arena.NewString(s.accountService.AccountID())) if err != nil { return fmt.Errorf("modify content: %w", err) } } else { - err = builder.Modify(CollectionName, messageId, []string{reactionsKey, emoji}, pb.ModifyOp_AddToSet, arena.NewString(s.accountService.AccountID())) + err = builder.Modify(CollectionName, messageId, []string{chatmodel.ReactionsKey, emoji}, pb.ModifyOp_AddToSet, arena.NewString(s.accountService.AccountID())) if err != nil { return fmt.Errorf("modify content: %w", err) } @@ -343,78 +331,13 @@ func (s *storeObject) ToggleMessageReaction(ctx context.Context, messageId strin return nil } -type SubscribeLastMessagesRequest struct { - SubId string - Limit int - // If AsyncInit is true, initial messages will be broadcast via events - AsyncInit bool - WithDependencies bool -} - -type SubscribeLastMessagesResponse struct { - Messages []*Message - ChatState *model.ChatState - // Dependencies per message id - Dependencies map[string][]*domain.Details -} - -func (s *storeObject) SubscribeLastMessages(ctx context.Context, req SubscribeLastMessagesRequest) (*SubscribeLastMessagesResponse, error) { - txn, err := s.repository.readTx(ctx) - if err != nil { - return nil, fmt.Errorf("init read transaction: %w", err) - } - defer txn.Commit() - - messages, err := s.repository.getLastMessages(txn.Context(), uint(req.Limit)) - if err != nil { - return nil, fmt.Errorf("query messages: %w", err) - } - - s.subscription.subscribe(req.SubId, req.WithDependencies) - - if req.AsyncInit { - var previousOrderId string - if len(messages) > 0 { - previousOrderId, err = s.repository.getPrevOrderId(txn.Context(), messages[0].OrderId) - if err != nil { - return nil, fmt.Errorf("get previous order id: %w", err) - } - } - for _, message := range messages { - s.subscription.add(previousOrderId, message) - previousOrderId = message.OrderId - } - - // Force chatState to be sent - s.subscription.chatStateUpdated = true - s.subscription.flush() - return nil, nil - } else { - depsPerMessage := map[string][]*domain.Details{} - if req.WithDependencies { - for _, message := range messages { - deps := s.subscription.collectMessageDependencies(message) - depsPerMessage[message.Id] = deps - } - } - return &SubscribeLastMessagesResponse{ - Messages: messages, - ChatState: s.subscription.getChatState(), - Dependencies: depsPerMessage, - }, nil - } -} - -func (s *storeObject) Unsubscribe(subId string) error { - s.subscription.unsubscribe(subId) - return nil -} - func (s *storeObject) TryClose(objectTTL time.Duration) (res bool, err error) { if !s.locker.TryLock() { return false, nil } - isActive := s.subscription.isActive() + s.subscription.Lock() + defer s.subscription.Unlock() + isActive := s.subscription.IsActive() s.Unlock() if isActive { diff --git a/core/block/editor/chatobject/chatobject_test.go b/core/block/editor/chatobject/chatobject_test.go index d615b7491..e56aa5099 100644 --- a/core/block/editor/chatobject/chatobject_test.go +++ b/core/block/editor/chatobject/chatobject_test.go @@ -4,26 +4,33 @@ import ( "context" "errors" "fmt" - "path/filepath" "testing" - anystore "github.com/anyproto/any-store" + "github.com/anyproto/any-sync/app" + "github.com/anyproto/any-sync/commonspace/object/accountdata" + "github.com/anyproto/any-sync/util/crypto" "github.com/globalsign/mgo/bson" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" + "github.com/anyproto/anytype-heart/core/block/chats/chatrepository" + "github.com/anyproto/anytype-heart/core/block/chats/chatsubscription" "github.com/anyproto/anytype-heart/core/block/editor/smartblock" "github.com/anyproto/anytype-heart/core/block/editor/smartblock/smarttest" "github.com/anyproto/anytype-heart/core/block/editor/storestate" + "github.com/anyproto/anytype-heart/core/block/object/idresolver/mock_idresolver" "github.com/anyproto/anytype-heart/core/block/source" "github.com/anyproto/anytype-heart/core/block/source/mock_source" "github.com/anyproto/anytype-heart/core/domain" "github.com/anyproto/anytype-heart/core/event/mock_event" "github.com/anyproto/anytype-heart/core/session" "github.com/anyproto/anytype-heart/pb" + "github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore" "github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex" "github.com/anyproto/anytype-heart/pkg/lib/pb/model" + "github.com/anyproto/anytype-heart/tests/testutil" ) const ( @@ -32,12 +39,27 @@ const ( type accountServiceStub struct { accountId string + signKey crypto.PrivKey } func (a *accountServiceStub) AccountID() string { return a.accountId } +func (a *accountServiceStub) Keys() *accountdata.AccountKeys { + return &accountdata.AccountKeys{ + SignKey: a.signKey, + } +} + +func (a *accountServiceStub) Name() string { return "accountServiceStub" } + +func (a *accountServiceStub) Init(ap *app.App) error { + signKey, _, _ := crypto.GenerateRandomEd25519KeyPair() + a.signKey = signKey + return nil +} + type stubSeenHeadsCollector struct { heads []string } @@ -53,6 +75,7 @@ type fixture struct { sourceCreator string eventSender *mock_event.MockSender events []*pb.EventMessage + spaceIndex spaceindex.Store generateOrderIdFunc func(tx *storestate.StoreStateTx) string } @@ -61,12 +84,11 @@ const testCreator = "accountId1" func newFixture(t *testing.T) *fixture { ctx := context.Background() - db, err := anystore.Open(ctx, filepath.Join(t.TempDir(), "crdt.db"), nil) - require.NoError(t, err) - t.Cleanup(func() { - err := db.Close() - require.NoError(t, err) - }) + + a := &app.App{} + + idResolver := mock_idresolver.NewMockResolver(t) + idResolver.EXPECT().ResolveSpaceID(mock.Anything).Return(testSpaceId, nil).Maybe() accountService := &accountServiceStub{accountId: testCreator} @@ -74,9 +96,25 @@ func newFixture(t *testing.T) *fixture { sb := smarttest.New("chatId1") - spaceIndex := spaceindex.NewStoreFixture(t) + objectStore := objectstore.NewStoreFixture(t) + spaceIndex := objectStore.SpaceIndex(testSpaceId) - object := New(sb, accountService, eventSender, db, spaceIndex) + repo := chatrepository.New() + subscriptions := chatsubscription.New() + + a.Register(accountService) + a.Register(testutil.PrepareMock(ctx, a, eventSender)) + a.Register(testutil.PrepareMock(ctx, a, idResolver)) + a.Register(objectStore) + a.Register(repo) + a.Register(subscriptions) + + err := a.Start(ctx) + require.NoError(t, err) + db, err := objectStore.GetCrdtDb(testSpaceId).Wait() + require.NoError(t, err) + + object := New(sb, accountService, db, repo, subscriptions) rawObject := object.(*storeObject) fx := &fixture{ @@ -84,6 +122,7 @@ func newFixture(t *testing.T) *fixture { accountServiceStub: accountService, sourceCreator: testCreator, eventSender: eventSender, + spaceIndex: spaceIndex, } eventSender.EXPECT().Broadcast(mock.Anything).Run(func(event *pb.Event) { for _, msg := range event.Messages { @@ -107,7 +146,7 @@ func newFixture(t *testing.T) *fixture { // Imitate diff manager source.EXPECT().MarkSeenHeads(mock.Anything, mock.Anything, mock.Anything).RunAndReturn(func(ctx context.Context, name string, seenHeads []string) error { - allMessagesResp, err := fx.GetMessages(ctx, GetMessagesRequest{ + allMessagesResp, err := fx.GetMessages(ctx, chatrepository.GetMessagesRequest{ AfterOrderId: "", IncludeBoundary: true, }) @@ -158,7 +197,7 @@ func TestAddMessage(t *testing.T) { assert.NotEmpty(t, messageId) assert.NotEmpty(t, sessionCtx.GetMessages()) - messagesResp, err := fx.GetMessages(ctx, GetMessagesRequest{}) + messagesResp, err := fx.GetMessages(ctx, chatrepository.GetMessagesRequest{}) require.NoError(t, err) require.Len(t, messagesResp.Messages, 1) @@ -186,7 +225,7 @@ func TestAddMessage(t *testing.T) { assert.NotEmpty(t, messageId) assert.NotEmpty(t, sessionCtx.GetMessages()) - messagesResp, err := fx.GetMessages(ctx, GetMessagesRequest{}) + messagesResp, err := fx.GetMessages(ctx, chatrepository.GetMessagesRequest{}) require.NoError(t, err) require.Len(t, messagesResp.Messages, 1) assert.Equal(t, messagesResp.ChatState.LastStateId, messagesResp.Messages[0].StateId) @@ -214,7 +253,7 @@ func TestGetMessages(t *testing.T) { assert.NotEmpty(t, messageId) } - messagesResp, err := fx.GetMessages(ctx, GetMessagesRequest{Limit: 5}) + messagesResp, err := fx.GetMessages(ctx, chatrepository.GetMessagesRequest{Limit: 5}) require.NoError(t, err) lastMessage := messagesResp.Messages[4] @@ -227,7 +266,7 @@ func TestGetMessages(t *testing.T) { t.Run("with requested BeforeOrderId", func(t *testing.T) { lastOrderId := messagesResp.Messages[0].OrderId // text 6 - gotMessages, err := fx.GetMessages(ctx, GetMessagesRequest{BeforeOrderId: lastOrderId, Limit: 5}) + gotMessages, err := fx.GetMessages(ctx, chatrepository.GetMessagesRequest{BeforeOrderId: lastOrderId, Limit: 5}) require.NoError(t, err) wantTexts = []string{"text 1", "text 2", "text 3", "text 4", "text 5"} for i, msg := range gotMessages.Messages { @@ -237,7 +276,7 @@ func TestGetMessages(t *testing.T) { t.Run("with requested AfterOrderId", func(t *testing.T) { lastOrderId := messagesResp.Messages[0].OrderId // text 6 - gotMessages, err := fx.GetMessages(ctx, GetMessagesRequest{AfterOrderId: lastOrderId, Limit: 2}) + gotMessages, err := fx.GetMessages(ctx, chatrepository.GetMessagesRequest{AfterOrderId: lastOrderId, Limit: 2}) require.NoError(t, err) wantTexts = []string{"text 7", "text 8"} for i, msg := range gotMessages.Messages { @@ -287,7 +326,7 @@ func TestEditMessage(t *testing.T) { err = fx.EditMessage(ctx, messageId, editedMessage) require.NoError(t, err) - messagesResp, err := fx.GetMessages(ctx, GetMessagesRequest{}) + messagesResp, err := fx.GetMessages(ctx, chatrepository.GetMessagesRequest{}) require.NoError(t, err) require.Len(t, messagesResp.Messages, 1) @@ -322,7 +361,7 @@ func TestEditMessage(t *testing.T) { require.Error(t, err) // Check that nothing is changed - messagesResp, err := fx.GetMessages(ctx, GetMessagesRequest{}) + messagesResp, err := fx.GetMessages(ctx, chatrepository.GetMessagesRequest{}) require.NoError(t, err) require.Len(t, messagesResp.Messages, 1) @@ -378,7 +417,7 @@ func TestToggleReaction(t *testing.T) { require.NoError(t, err) }) - messagesResp, err := fx.GetMessages(ctx, GetMessagesRequest{}) + messagesResp, err := fx.GetMessages(ctx, chatrepository.GetMessagesRequest{}) require.NoError(t, err) require.Len(t, messagesResp.Messages, 1) @@ -398,7 +437,7 @@ func TestToggleReaction(t *testing.T) { } func (fx *fixture) assertReadStatus(t *testing.T, ctx context.Context, afterOrderId string, beforeOrderId string, isRead bool, isMentionRead bool) *GetMessagesResponse { - messageResp, err := fx.GetMessages(ctx, GetMessagesRequest{ + messageResp, err := fx.GetMessages(ctx, chatrepository.GetMessagesRequest{ AfterOrderId: afterOrderId, BeforeOrderId: beforeOrderId, IncludeBoundary: true, @@ -445,8 +484,8 @@ func (fx *fixture) applyToStore(ctx context.Context, params source.PushStoreChan return changeId, nil } -func givenSimpleMessage(text string) *Message { - return &Message{ +func givenSimpleMessage(text string) *chatmodel.Message { + return &chatmodel.Message{ ChatMessage: &model.ChatMessage{ Id: "", OrderId: "", @@ -461,8 +500,8 @@ func givenSimpleMessage(text string) *Message { } } -func givenMessageWithMention(text string) *Message { - return &Message{ +func givenMessageWithMention(text string) *chatmodel.Message { + return &chatmodel.Message{ ChatMessage: &model.ChatMessage{ Id: "", OrderId: "", @@ -484,8 +523,8 @@ func givenMessageWithMention(text string) *Message { } } -func givenComplexMessage() *Message { - return &Message{ +func givenComplexMessage() *chatmodel.Message { + return &chatmodel.Message{ ChatMessage: &model.ChatMessage{ Id: "", OrderId: "", @@ -538,7 +577,7 @@ func givenComplexMessage() *Message { } } -func assertMessagesEqual(t *testing.T, want, got *Message) { +func assertMessagesEqual(t *testing.T, want, got *chatmodel.Message) { // Cleanup order id assert.NotEmpty(t, got.OrderId) got.OrderId = "" diff --git a/core/block/editor/chatobject/mock_chatobject/mock_StoreObject.go b/core/block/editor/chatobject/mock_chatobject/mock_StoreObject.go index 612fe17ce..933c1bbb8 100644 --- a/core/block/editor/chatobject/mock_chatobject/mock_StoreObject.go +++ b/core/block/editor/chatobject/mock_chatobject/mock_StoreObject.go @@ -3,9 +3,13 @@ package mock_chatobject import ( + chatmodel "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" anystoredebug "github.com/anyproto/anytype-heart/core/block/editor/anystoredebug" + chatobject "github.com/anyproto/anytype-heart/core/block/editor/chatobject" + chatrepository "github.com/anyproto/anytype-heart/core/block/chats/chatrepository" + context "context" coresmartblock "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock" @@ -150,7 +154,7 @@ func (_c *MockStoreObject_AddHookOnce_Call) RunAndReturn(run func(string, smartb } // AddMessage provides a mock function with given fields: ctx, sessionCtx, message -func (_m *MockStoreObject) AddMessage(ctx context.Context, sessionCtx session.Context, message *chatobject.Message) (string, error) { +func (_m *MockStoreObject) AddMessage(ctx context.Context, sessionCtx session.Context, message *chatmodel.Message) (string, error) { ret := _m.Called(ctx, sessionCtx, message) if len(ret) == 0 { @@ -159,16 +163,16 @@ func (_m *MockStoreObject) AddMessage(ctx context.Context, sessionCtx session.Co var r0 string var r1 error - if rf, ok := ret.Get(0).(func(context.Context, session.Context, *chatobject.Message) (string, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, session.Context, *chatmodel.Message) (string, error)); ok { return rf(ctx, sessionCtx, message) } - if rf, ok := ret.Get(0).(func(context.Context, session.Context, *chatobject.Message) string); ok { + if rf, ok := ret.Get(0).(func(context.Context, session.Context, *chatmodel.Message) string); ok { r0 = rf(ctx, sessionCtx, message) } else { r0 = ret.Get(0).(string) } - if rf, ok := ret.Get(1).(func(context.Context, session.Context, *chatobject.Message) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, session.Context, *chatmodel.Message) error); ok { r1 = rf(ctx, sessionCtx, message) } else { r1 = ret.Error(1) @@ -185,14 +189,14 @@ type MockStoreObject_AddMessage_Call struct { // AddMessage is a helper method to define mock.On call // - ctx context.Context // - sessionCtx session.Context -// - message *chatobject.Message +// - message *chatmodel.Message func (_e *MockStoreObject_Expecter) AddMessage(ctx interface{}, sessionCtx interface{}, message interface{}) *MockStoreObject_AddMessage_Call { return &MockStoreObject_AddMessage_Call{Call: _e.mock.On("AddMessage", ctx, sessionCtx, message)} } -func (_c *MockStoreObject_AddMessage_Call) Run(run func(ctx context.Context, sessionCtx session.Context, message *chatobject.Message)) *MockStoreObject_AddMessage_Call { +func (_c *MockStoreObject_AddMessage_Call) Run(run func(ctx context.Context, sessionCtx session.Context, message *chatmodel.Message)) *MockStoreObject_AddMessage_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(session.Context), args[2].(*chatobject.Message)) + run(args[0].(context.Context), args[1].(session.Context), args[2].(*chatmodel.Message)) }) return _c } @@ -202,7 +206,7 @@ func (_c *MockStoreObject_AddMessage_Call) Return(_a0 string, _a1 error) *MockSt return _c } -func (_c *MockStoreObject_AddMessage_Call) RunAndReturn(run func(context.Context, session.Context, *chatobject.Message) (string, error)) *MockStoreObject_AddMessage_Call { +func (_c *MockStoreObject_AddMessage_Call) RunAndReturn(run func(context.Context, session.Context, *chatmodel.Message) (string, error)) *MockStoreObject_AddMessage_Call { _c.Call.Return(run) return _c } @@ -744,7 +748,7 @@ func (_c *MockStoreObject_Details_Call) RunAndReturn(run func() *domain.Details) } // EditMessage provides a mock function with given fields: ctx, messageId, newMessage -func (_m *MockStoreObject) EditMessage(ctx context.Context, messageId string, newMessage *chatobject.Message) error { +func (_m *MockStoreObject) EditMessage(ctx context.Context, messageId string, newMessage *chatmodel.Message) error { ret := _m.Called(ctx, messageId, newMessage) if len(ret) == 0 { @@ -752,7 +756,7 @@ func (_m *MockStoreObject) EditMessage(ctx context.Context, messageId string, ne } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, *chatobject.Message) error); ok { + if rf, ok := ret.Get(0).(func(context.Context, string, *chatmodel.Message) error); ok { r0 = rf(ctx, messageId, newMessage) } else { r0 = ret.Error(0) @@ -769,14 +773,14 @@ type MockStoreObject_EditMessage_Call struct { // EditMessage is a helper method to define mock.On call // - ctx context.Context // - messageId string -// - newMessage *chatobject.Message +// - newMessage *chatmodel.Message func (_e *MockStoreObject_Expecter) EditMessage(ctx interface{}, messageId interface{}, newMessage interface{}) *MockStoreObject_EditMessage_Call { return &MockStoreObject_EditMessage_Call{Call: _e.mock.On("EditMessage", ctx, messageId, newMessage)} } -func (_c *MockStoreObject_EditMessage_Call) Run(run func(ctx context.Context, messageId string, newMessage *chatobject.Message)) *MockStoreObject_EditMessage_Call { +func (_c *MockStoreObject_EditMessage_Call) Run(run func(ctx context.Context, messageId string, newMessage *chatmodel.Message)) *MockStoreObject_EditMessage_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(*chatobject.Message)) + run(args[0].(context.Context), args[1].(string), args[2].(*chatmodel.Message)) }) return _c } @@ -786,7 +790,7 @@ func (_c *MockStoreObject_EditMessage_Call) Return(_a0 error) *MockStoreObject_E return _c } -func (_c *MockStoreObject_EditMessage_Call) RunAndReturn(run func(context.Context, string, *chatobject.Message) error) *MockStoreObject_EditMessage_Call { +func (_c *MockStoreObject_EditMessage_Call) RunAndReturn(run func(context.Context, string, *chatmodel.Message) error) *MockStoreObject_EditMessage_Call { _c.Call.Return(run) return _c } @@ -948,7 +952,7 @@ func (_c *MockStoreObject_GetDocInfo_Call) RunAndReturn(run func() smartblock.Do } // GetMessages provides a mock function with given fields: ctx, req -func (_m *MockStoreObject) GetMessages(ctx context.Context, req chatobject.GetMessagesRequest) (*chatobject.GetMessagesResponse, error) { +func (_m *MockStoreObject) GetMessages(ctx context.Context, req chatrepository.GetMessagesRequest) (*chatobject.GetMessagesResponse, error) { ret := _m.Called(ctx, req) if len(ret) == 0 { @@ -957,10 +961,10 @@ func (_m *MockStoreObject) GetMessages(ctx context.Context, req chatobject.GetMe var r0 *chatobject.GetMessagesResponse var r1 error - if rf, ok := ret.Get(0).(func(context.Context, chatobject.GetMessagesRequest) (*chatobject.GetMessagesResponse, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, chatrepository.GetMessagesRequest) (*chatobject.GetMessagesResponse, error)); ok { return rf(ctx, req) } - if rf, ok := ret.Get(0).(func(context.Context, chatobject.GetMessagesRequest) *chatobject.GetMessagesResponse); ok { + if rf, ok := ret.Get(0).(func(context.Context, chatrepository.GetMessagesRequest) *chatobject.GetMessagesResponse); ok { r0 = rf(ctx, req) } else { if ret.Get(0) != nil { @@ -968,7 +972,7 @@ func (_m *MockStoreObject) GetMessages(ctx context.Context, req chatobject.GetMe } } - if rf, ok := ret.Get(1).(func(context.Context, chatobject.GetMessagesRequest) error); ok { + if rf, ok := ret.Get(1).(func(context.Context, chatrepository.GetMessagesRequest) error); ok { r1 = rf(ctx, req) } else { r1 = ret.Error(1) @@ -984,14 +988,14 @@ type MockStoreObject_GetMessages_Call struct { // GetMessages is a helper method to define mock.On call // - ctx context.Context -// - req chatobject.GetMessagesRequest +// - req chatrepository.GetMessagesRequest func (_e *MockStoreObject_Expecter) GetMessages(ctx interface{}, req interface{}) *MockStoreObject_GetMessages_Call { return &MockStoreObject_GetMessages_Call{Call: _e.mock.On("GetMessages", ctx, req)} } -func (_c *MockStoreObject_GetMessages_Call) Run(run func(ctx context.Context, req chatobject.GetMessagesRequest)) *MockStoreObject_GetMessages_Call { +func (_c *MockStoreObject_GetMessages_Call) Run(run func(ctx context.Context, req chatrepository.GetMessagesRequest)) *MockStoreObject_GetMessages_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(chatobject.GetMessagesRequest)) + run(args[0].(context.Context), args[1].(chatrepository.GetMessagesRequest)) }) return _c } @@ -1001,29 +1005,29 @@ func (_c *MockStoreObject_GetMessages_Call) Return(_a0 *chatobject.GetMessagesRe return _c } -func (_c *MockStoreObject_GetMessages_Call) RunAndReturn(run func(context.Context, chatobject.GetMessagesRequest) (*chatobject.GetMessagesResponse, error)) *MockStoreObject_GetMessages_Call { +func (_c *MockStoreObject_GetMessages_Call) RunAndReturn(run func(context.Context, chatrepository.GetMessagesRequest) (*chatobject.GetMessagesResponse, error)) *MockStoreObject_GetMessages_Call { _c.Call.Return(run) return _c } // GetMessagesByIds provides a mock function with given fields: ctx, messageIds -func (_m *MockStoreObject) GetMessagesByIds(ctx context.Context, messageIds []string) ([]*chatobject.Message, error) { +func (_m *MockStoreObject) GetMessagesByIds(ctx context.Context, messageIds []string) ([]*chatmodel.Message, error) { ret := _m.Called(ctx, messageIds) if len(ret) == 0 { panic("no return value specified for GetMessagesByIds") } - var r0 []*chatobject.Message + var r0 []*chatmodel.Message var r1 error - if rf, ok := ret.Get(0).(func(context.Context, []string) ([]*chatobject.Message, error)); ok { + if rf, ok := ret.Get(0).(func(context.Context, []string) ([]*chatmodel.Message, error)); ok { return rf(ctx, messageIds) } - if rf, ok := ret.Get(0).(func(context.Context, []string) []*chatobject.Message); ok { + if rf, ok := ret.Get(0).(func(context.Context, []string) []*chatmodel.Message); ok { r0 = rf(ctx, messageIds) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]*chatobject.Message) + r0 = ret.Get(0).([]*chatmodel.Message) } } @@ -1055,12 +1059,12 @@ func (_c *MockStoreObject_GetMessagesByIds_Call) Run(run func(ctx context.Contex return _c } -func (_c *MockStoreObject_GetMessagesByIds_Call) Return(_a0 []*chatobject.Message, _a1 error) *MockStoreObject_GetMessagesByIds_Call { +func (_c *MockStoreObject_GetMessagesByIds_Call) Return(_a0 []*chatmodel.Message, _a1 error) *MockStoreObject_GetMessagesByIds_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *MockStoreObject_GetMessagesByIds_Call) RunAndReturn(run func(context.Context, []string) ([]*chatobject.Message, error)) *MockStoreObject_GetMessagesByIds_Call { +func (_c *MockStoreObject_GetMessagesByIds_Call) RunAndReturn(run func(context.Context, []string) ([]*chatmodel.Message, error)) *MockStoreObject_GetMessagesByIds_Call { _c.Call.Return(run) return _c } @@ -1568,7 +1572,7 @@ func (_c *MockStoreObject_Lock_Call) RunAndReturn(run func()) *MockStoreObject_L } // MarkMessagesAsUnread provides a mock function with given fields: ctx, afterOrderId, counterType -func (_m *MockStoreObject) MarkMessagesAsUnread(ctx context.Context, afterOrderId string, counterType chatobject.CounterType) error { +func (_m *MockStoreObject) MarkMessagesAsUnread(ctx context.Context, afterOrderId string, counterType chatmodel.CounterType) error { ret := _m.Called(ctx, afterOrderId, counterType) if len(ret) == 0 { @@ -1576,7 +1580,7 @@ func (_m *MockStoreObject) MarkMessagesAsUnread(ctx context.Context, afterOrderI } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, chatobject.CounterType) error); ok { + if rf, ok := ret.Get(0).(func(context.Context, string, chatmodel.CounterType) error); ok { r0 = rf(ctx, afterOrderId, counterType) } else { r0 = ret.Error(0) @@ -1593,14 +1597,14 @@ type MockStoreObject_MarkMessagesAsUnread_Call struct { // MarkMessagesAsUnread is a helper method to define mock.On call // - ctx context.Context // - afterOrderId string -// - counterType chatobject.CounterType +// - counterType chatmodel.CounterType func (_e *MockStoreObject_Expecter) MarkMessagesAsUnread(ctx interface{}, afterOrderId interface{}, counterType interface{}) *MockStoreObject_MarkMessagesAsUnread_Call { return &MockStoreObject_MarkMessagesAsUnread_Call{Call: _e.mock.On("MarkMessagesAsUnread", ctx, afterOrderId, counterType)} } -func (_c *MockStoreObject_MarkMessagesAsUnread_Call) Run(run func(ctx context.Context, afterOrderId string, counterType chatobject.CounterType)) *MockStoreObject_MarkMessagesAsUnread_Call { +func (_c *MockStoreObject_MarkMessagesAsUnread_Call) Run(run func(ctx context.Context, afterOrderId string, counterType chatmodel.CounterType)) *MockStoreObject_MarkMessagesAsUnread_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(chatobject.CounterType)) + run(args[0].(context.Context), args[1].(string), args[2].(chatmodel.CounterType)) }) return _c } @@ -1610,13 +1614,13 @@ func (_c *MockStoreObject_MarkMessagesAsUnread_Call) Return(_a0 error) *MockStor return _c } -func (_c *MockStoreObject_MarkMessagesAsUnread_Call) RunAndReturn(run func(context.Context, string, chatobject.CounterType) error) *MockStoreObject_MarkMessagesAsUnread_Call { +func (_c *MockStoreObject_MarkMessagesAsUnread_Call) RunAndReturn(run func(context.Context, string, chatmodel.CounterType) error) *MockStoreObject_MarkMessagesAsUnread_Call { _c.Call.Return(run) return _c } // MarkReadMessages provides a mock function with given fields: ctx, afterOrderId, beforeOrderId, lastStateId, counterType -func (_m *MockStoreObject) MarkReadMessages(ctx context.Context, afterOrderId string, beforeOrderId string, lastStateId string, counterType chatobject.CounterType) error { +func (_m *MockStoreObject) MarkReadMessages(ctx context.Context, afterOrderId string, beforeOrderId string, lastStateId string, counterType chatmodel.CounterType) error { ret := _m.Called(ctx, afterOrderId, beforeOrderId, lastStateId, counterType) if len(ret) == 0 { @@ -1624,7 +1628,7 @@ func (_m *MockStoreObject) MarkReadMessages(ctx context.Context, afterOrderId st } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, string, string, string, chatobject.CounterType) error); ok { + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, chatmodel.CounterType) error); ok { r0 = rf(ctx, afterOrderId, beforeOrderId, lastStateId, counterType) } else { r0 = ret.Error(0) @@ -1643,14 +1647,14 @@ type MockStoreObject_MarkReadMessages_Call struct { // - afterOrderId string // - beforeOrderId string // - lastStateId string -// - counterType chatobject.CounterType +// - counterType chatmodel.CounterType func (_e *MockStoreObject_Expecter) MarkReadMessages(ctx interface{}, afterOrderId interface{}, beforeOrderId interface{}, lastStateId interface{}, counterType interface{}) *MockStoreObject_MarkReadMessages_Call { return &MockStoreObject_MarkReadMessages_Call{Call: _e.mock.On("MarkReadMessages", ctx, afterOrderId, beforeOrderId, lastStateId, counterType)} } -func (_c *MockStoreObject_MarkReadMessages_Call) Run(run func(ctx context.Context, afterOrderId string, beforeOrderId string, lastStateId string, counterType chatobject.CounterType)) *MockStoreObject_MarkReadMessages_Call { +func (_c *MockStoreObject_MarkReadMessages_Call) Run(run func(ctx context.Context, afterOrderId string, beforeOrderId string, lastStateId string, counterType chatmodel.CounterType)) *MockStoreObject_MarkReadMessages_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(chatobject.CounterType)) + run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(chatmodel.CounterType)) }) return _c } @@ -1660,7 +1664,7 @@ func (_c *MockStoreObject_MarkReadMessages_Call) Return(_a0 error) *MockStoreObj return _c } -func (_c *MockStoreObject_MarkReadMessages_Call) RunAndReturn(run func(context.Context, string, string, string, chatobject.CounterType) error) *MockStoreObject_MarkReadMessages_Call { +func (_c *MockStoreObject_MarkReadMessages_Call) RunAndReturn(run func(context.Context, string, string, string, chatmodel.CounterType) error) *MockStoreObject_MarkReadMessages_Call { _c.Call.Return(run) return _c } @@ -2628,65 +2632,6 @@ func (_c *MockStoreObject_SpaceID_Call) RunAndReturn(run func() string) *MockSto return _c } -// SubscribeLastMessages provides a mock function with given fields: ctx, req -func (_m *MockStoreObject) SubscribeLastMessages(ctx context.Context, req chatobject.SubscribeLastMessagesRequest) (*chatobject.SubscribeLastMessagesResponse, error) { - ret := _m.Called(ctx, req) - - if len(ret) == 0 { - panic("no return value specified for SubscribeLastMessages") - } - - var r0 *chatobject.SubscribeLastMessagesResponse - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, chatobject.SubscribeLastMessagesRequest) (*chatobject.SubscribeLastMessagesResponse, error)); ok { - return rf(ctx, req) - } - if rf, ok := ret.Get(0).(func(context.Context, chatobject.SubscribeLastMessagesRequest) *chatobject.SubscribeLastMessagesResponse); ok { - r0 = rf(ctx, req) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*chatobject.SubscribeLastMessagesResponse) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, chatobject.SubscribeLastMessagesRequest) error); ok { - r1 = rf(ctx, req) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockStoreObject_SubscribeLastMessages_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeLastMessages' -type MockStoreObject_SubscribeLastMessages_Call struct { - *mock.Call -} - -// SubscribeLastMessages is a helper method to define mock.On call -// - ctx context.Context -// - req chatobject.SubscribeLastMessagesRequest -func (_e *MockStoreObject_Expecter) SubscribeLastMessages(ctx interface{}, req interface{}) *MockStoreObject_SubscribeLastMessages_Call { - return &MockStoreObject_SubscribeLastMessages_Call{Call: _e.mock.On("SubscribeLastMessages", ctx, req)} -} - -func (_c *MockStoreObject_SubscribeLastMessages_Call) Run(run func(ctx context.Context, req chatobject.SubscribeLastMessagesRequest)) *MockStoreObject_SubscribeLastMessages_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(chatobject.SubscribeLastMessagesRequest)) - }) - return _c -} - -func (_c *MockStoreObject_SubscribeLastMessages_Call) Return(_a0 *chatobject.SubscribeLastMessagesResponse, _a1 error) *MockStoreObject_SubscribeLastMessages_Call { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *MockStoreObject_SubscribeLastMessages_Call) RunAndReturn(run func(context.Context, chatobject.SubscribeLastMessagesRequest) (*chatobject.SubscribeLastMessagesResponse, error)) *MockStoreObject_SubscribeLastMessages_Call { - _c.Call.Return(run) - return _c -} - // ToggleMessageReaction provides a mock function with given fields: ctx, messageId, emoji func (_m *MockStoreObject) ToggleMessageReaction(ctx context.Context, messageId string, emoji string) error { ret := _m.Called(ctx, messageId, emoji) @@ -3007,52 +2952,6 @@ func (_c *MockStoreObject_Unlock_Call) RunAndReturn(run func()) *MockStoreObject return _c } -// Unsubscribe provides a mock function with given fields: subId -func (_m *MockStoreObject) Unsubscribe(subId string) error { - ret := _m.Called(subId) - - if len(ret) == 0 { - panic("no return value specified for Unsubscribe") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string) error); ok { - r0 = rf(subId) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockStoreObject_Unsubscribe_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Unsubscribe' -type MockStoreObject_Unsubscribe_Call struct { - *mock.Call -} - -// Unsubscribe is a helper method to define mock.On call -// - subId string -func (_e *MockStoreObject_Expecter) Unsubscribe(subId interface{}) *MockStoreObject_Unsubscribe_Call { - return &MockStoreObject_Unsubscribe_Call{Call: _e.mock.On("Unsubscribe", subId)} -} - -func (_c *MockStoreObject_Unsubscribe_Call) Run(run func(subId string)) *MockStoreObject_Unsubscribe_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string)) - }) - return _c -} - -func (_c *MockStoreObject_Unsubscribe_Call) Return(_a0 error) *MockStoreObject_Unsubscribe_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockStoreObject_Unsubscribe_Call) RunAndReturn(run func(string) error) *MockStoreObject_Unsubscribe_Call { - _c.Call.Return(run) - return _c -} - // NewMockStoreObject creates a new instance of MockStoreObject. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. func NewMockStoreObject(t interface { diff --git a/core/block/editor/chatobject/reading.go b/core/block/editor/chatobject/reading.go index 13c2e35aa..3f9450eec 100644 --- a/core/block/editor/chatobject/reading.go +++ b/core/block/editor/chatobject/reading.go @@ -4,162 +4,53 @@ import ( "context" "fmt" - "github.com/anyproto/any-store/anyenc" - "github.com/anyproto/any-store/query" - - "github.com/anyproto/anytype-heart/pkg/lib/pb/model" + "github.com/anyproto/any-sync/commonspace/object/tree/objecttree" + "github.com/anyproto/any-sync/util/crypto" + "github.com/anyproto/any-sync/util/slice" + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" + "github.com/anyproto/anytype-heart/core/block/source" + "golang.org/x/exp/slices" ) -type CounterType int +type ReadMessagesRequest struct { + AfterOrderId string + BeforeOrderId string + LastStateId string -const ( - CounterTypeMessage = CounterType(iota) - CounterTypeMention -) + CounterType chatmodel.CounterType -type readHandler interface { - getUnreadFilter() query.Filter - getMessagesFilter() query.Filter - getDiffManagerName() string - getReadKey() string - readModifier(value bool) query.Modifier - - readMessages(newOldestOrderId string, idsModified []string) - unreadMessages(newOldestOrderId string, lastStateId string, msgIds []string) + // All forces to read all messages + All bool } -type readMessagesHandler struct { - subscription *subscriptionManager -} - -func (h *readMessagesHandler) getUnreadFilter() query.Filter { - return query.Not{ - Filter: query.Key{Path: []string{readKey}, Filter: query.NewComp(query.CompOpEq, true)}, - } -} - -func (h *readMessagesHandler) getMessagesFilter() query.Filter { - return nil -} - -func (h *readMessagesHandler) getDiffManagerName() string { - return diffManagerMessages -} - -func (h *readMessagesHandler) getReadKey() string { - return readKey -} - -func (h *readMessagesHandler) readMessages(newOldestOrderId string, idsModified []string) { - h.subscription.updateChatState(func(state *model.ChatState) *model.ChatState { - state.Messages.OldestOrderId = newOldestOrderId - return state - }) - h.subscription.updateMessageRead(idsModified, true) -} - -func (h *readMessagesHandler) unreadMessages(newOldestOrderId string, lastStateId string, msgIds []string) { - h.subscription.updateChatState(func(state *model.ChatState) *model.ChatState { - state.Messages.OldestOrderId = newOldestOrderId - state.LastStateId = lastStateId - return state - }) - h.subscription.updateMessageRead(msgIds, false) -} - -func (h *readMessagesHandler) readModifier(value bool) query.Modifier { - return query.ModifyFunc(func(a *anyenc.Arena, v *anyenc.Value) (result *anyenc.Value, modified bool, err error) { - oldValue := v.GetBool(h.getReadKey()) - if oldValue != value { - v.Set(h.getReadKey(), arenaNewBool(a, value)) - return v, true, nil - } - return v, false, nil - }) -} - -type readMentionsHandler struct { - subscription *subscriptionManager -} - -func (h *readMentionsHandler) getUnreadFilter() query.Filter { - return query.And{ - query.Key{Path: []string{hasMentionKey}, Filter: query.NewComp(query.CompOpEq, true)}, - query.Key{Path: []string{mentionReadKey}, Filter: query.NewComp(query.CompOpEq, false)}, - } -} - -func (h *readMentionsHandler) getMessagesFilter() query.Filter { - return query.Key{Path: []string{hasMentionKey}, Filter: query.NewComp(query.CompOpEq, true)} -} - -func (h *readMentionsHandler) getDiffManagerName() string { - return diffManagerMentions -} - -func (h *readMentionsHandler) getReadKey() string { - return mentionReadKey -} - -func (h *readMentionsHandler) readMessages(newOldestOrderId string, idsModified []string) { - h.subscription.updateChatState(func(state *model.ChatState) *model.ChatState { - state.Mentions.OldestOrderId = newOldestOrderId - return state - }) - h.subscription.updateMentionRead(idsModified, true) -} - -func (h *readMentionsHandler) unreadMessages(newOldestOrderId string, lastStateId string, msgIds []string) { - h.subscription.updateChatState(func(state *model.ChatState) *model.ChatState { - state.Mentions.OldestOrderId = newOldestOrderId - state.LastStateId = lastStateId - return state - }) - h.subscription.updateMentionRead(msgIds, false) -} - -func (h *readMentionsHandler) readModifier(value bool) query.Modifier { - return query.ModifyFunc(func(a *anyenc.Arena, v *anyenc.Value) (result *anyenc.Value, modified bool, err error) { - if v.GetBool(hasMentionKey) { - oldValue := v.GetBool(h.getReadKey()) - if oldValue != value { - v.Set(h.getReadKey(), arenaNewBool(a, value)) - return v, true, nil - } - } - return v, false, nil - }) -} - -func newReadHandler(counterType CounterType, subscription *subscriptionManager) readHandler { - switch counterType { - case CounterTypeMessage: - return &readMessagesHandler{subscription: subscription} - case CounterTypeMention: - return &readMentionsHandler{subscription: subscription} - default: - panic("unknown counter type") - } -} - -func (s *storeObject) MarkReadMessages(ctx context.Context, afterOrderId, beforeOrderId string, lastStateId string, counterType CounterType) error { - handler := newReadHandler(counterType, s.subscription) +func (s *storeObject) MarkReadMessages(ctx context.Context, req ReadMessagesRequest) error { // 1. select all messages with orderId < beforeOrderId and addedTime < lastDbState // 2. use the last(by orderId) message id as lastHead // 3. update the MarkSeenHeads // 2. mark messages as read in the DB - msgs, err := s.repository.getUnreadMessageIdsInRange(ctx, afterOrderId, beforeOrderId, lastStateId, handler) - if err != nil { - return fmt.Errorf("get message: %w", err) + var msgs []string + + if req.All { + var err error + msgs, err = s.repository.GetAllUnreadMessages(ctx, req.CounterType) + if err != nil { + return fmt.Errorf("get all messages: %w", err) + } + } else { + var err error + msgs, err = s.repository.GetUnreadMessageIdsInRange(ctx, req.AfterOrderId, req.BeforeOrderId, req.LastStateId, req.CounterType) + if err != nil { + return fmt.Errorf("get messages: %w", err) + } } // mark the whole tree as seen from the current message - return s.storeSource.MarkSeenHeads(ctx, handler.getDiffManagerName(), msgs) + return s.storeSource.MarkSeenHeads(ctx, req.CounterType.DiffManagerName(), msgs) } -func (s *storeObject) MarkMessagesAsUnread(ctx context.Context, afterOrderId string, counterType CounterType) error { - txn, err := s.repository.writeTx(ctx) +func (s *storeObject) MarkMessagesAsUnread(ctx context.Context, afterOrderId string, counterType chatmodel.CounterType) error { + txn, err := s.repository.WriteTx(ctx) if err != nil { return fmt.Errorf("create tx: %w", err) } @@ -169,8 +60,7 @@ func (s *storeObject) MarkMessagesAsUnread(ctx context.Context, afterOrderId str _ = txn.Rollback() } }() - handler := newReadHandler(counterType, s.subscription) - messageIds, err := s.repository.getReadMessagesAfter(txn.Context(), afterOrderId, handler) + messageIds, err := s.repository.GetReadMessagesAfter(txn.Context(), afterOrderId, counterType) if err != nil { return fmt.Errorf("get read messages: %w", err) } @@ -179,23 +69,25 @@ func (s *storeObject) MarkMessagesAsUnread(ctx context.Context, afterOrderId str return nil } - idsModified := s.repository.setReadFlag(txn.Context(), s.Id(), messageIds, handler, false) + idsModified := s.repository.SetReadFlag(txn.Context(), s.Id(), messageIds, counterType, false) if len(idsModified) == 0 { return nil } - newOldestOrderId, err := s.repository.getOldestOrderId(txn.Context(), handler) + newOldestOrderId, err := s.repository.GetOldestOrderId(txn.Context(), counterType) if err != nil { return fmt.Errorf("get oldest order id: %w", err) } - lastAdded, err := s.repository.getLastStateId(txn.Context()) + lastAdded, err := s.repository.GetLastStateId(txn.Context()) if err != nil { return fmt.Errorf("get last added date: %w", err) } - handler.unreadMessages(newOldestOrderId, lastAdded, idsModified) - s.subscription.flush() + s.subscription.Lock() + defer s.subscription.Unlock() + s.subscription.UnreadMessages(newOldestOrderId, lastAdded, idsModified, counterType) + s.subscription.Flush() seenHeads, err := s.seenHeadsCollector.collectSeenHeads(ctx, afterOrderId) if err != nil { @@ -214,12 +106,12 @@ func (s *storeObject) MarkMessagesAsUnread(ctx context.Context, afterOrderId str return txn.Commit() } -func (s *storeObject) markReadMessages(changeIds []string, handler readHandler) error { +func (s *storeObject) markReadMessages(changeIds []string, counterType chatmodel.CounterType) error { if len(changeIds) == 0 { return nil } - txn, err := s.repository.writeTx(s.componentCtx) + txn, err := s.repository.WriteTx(s.componentCtx) if err != nil { return fmt.Errorf("start write tx: %w", err) } @@ -230,10 +122,10 @@ func (s *storeObject) markReadMessages(changeIds []string, handler readHandler) } }() - idsModified := s.repository.setReadFlag(txn.Context(), s.Id(), changeIds, handler, true) + idsModified := s.repository.SetReadFlag(txn.Context(), s.Id(), changeIds, counterType, true) if len(idsModified) > 0 { - newOldestOrderId, err := s.repository.getOldestOrderId(txn.Context(), handler) + newOldestOrderId, err := s.repository.GetOldestOrderId(txn.Context(), counterType) if err != nil { return fmt.Errorf("get oldest order id: %w", err) } @@ -244,8 +136,63 @@ func (s *storeObject) markReadMessages(changeIds []string, handler readHandler) return fmt.Errorf("commit: %w", err) } - handler.readMessages(newOldestOrderId, idsModified) - s.subscription.flush() + s.subscription.Lock() + defer s.subscription.Unlock() + s.subscription.ReadMessages(newOldestOrderId, idsModified, counterType) + s.subscription.Flush() + } + return nil +} + +type readStoreTreeHook struct { + joinedAclRecordId string + headsBeforeJoin []string + currentIdentity crypto.PubKey + source source.Store +} + +func (h *readStoreTreeHook) BeforeIteration(ot objecttree.ObjectTree) { + h.joinedAclRecordId = ot.AclList().Head().Id + for _, accState := range ot.AclList().AclState().CurrentAccounts() { + if !accState.PubKey.Equals(h.currentIdentity) { + continue + } + // Find the first record in which the user has got permissions since the last join + // Example: + // We have acl: [ 1:noPermissions, 2:reader, 3:noPermission, 4:reader, 5:writer ] + // Record with id=4 is one that we need + for i := len(accState.PermissionChanges) - 1; i >= 0; i-- { + permChange := accState.PermissionChanges[i] + + if permChange.Permission.NoPermissions() { + break + } else { + h.joinedAclRecordId = permChange.RecordId + } + } + break + } +} + +func (h *readStoreTreeHook) OnIteration(ot objecttree.ObjectTree, change *objecttree.Change) { + if ok, _ := ot.AclList().IsAfter(h.joinedAclRecordId, change.AclHeadId); ok { + h.headsBeforeJoin = slice.DiscardFromSlice(h.headsBeforeJoin, func(s string) bool { + return slices.Contains(change.PreviousIds, s) + }) + if !slices.Contains(h.headsBeforeJoin, change.Id) { + h.headsBeforeJoin = append(h.headsBeforeJoin, change.Id) + } + } +} + +func (h *readStoreTreeHook) AfterDiffManagersInit(ctx context.Context) error { + err := h.source.MarkSeenHeads(ctx, diffManagerMessages, h.headsBeforeJoin) + if err != nil { + return fmt.Errorf("mark read messages: %w", err) + } + err = h.source.MarkSeenHeads(ctx, diffManagerMentions, h.headsBeforeJoin) + if err != nil { + return fmt.Errorf("mark read mentions: %w", err) } return nil } diff --git a/core/block/editor/chatobject/reading_test.go b/core/block/editor/chatobject/reading_test.go index 859c897bf..15495d935 100644 --- a/core/block/editor/chatobject/reading_test.go +++ b/core/block/editor/chatobject/reading_test.go @@ -8,6 +8,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" + "github.com/anyproto/anytype-heart/core/block/chats/chatrepository" "github.com/anyproto/anytype-heart/core/block/editor/storestate" "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) @@ -25,7 +27,12 @@ func TestReadMessages(t *testing.T) { // All messages forced as not read messagesResp := fx.assertReadStatus(t, ctx, "", "", false, false) - err := fx.MarkReadMessages(ctx, "", messagesResp.Messages[2].OrderId, messagesResp.ChatState.LastStateId, CounterTypeMessage) + err := fx.MarkReadMessages(ctx, ReadMessagesRequest{ + AfterOrderId: "", + BeforeOrderId: messagesResp.Messages[2].OrderId, + LastStateId: messagesResp.ChatState.LastStateId, + CounterType: chatmodel.CounterTypeMessage, + }) require.NoError(t, err) fx.assertReadStatus(t, ctx, "", messagesResp.Messages[2].OrderId, true, false) @@ -56,14 +63,18 @@ func TestReadMessagesLoadedInBackground(t *testing.T) { secondMessage, err := fx.GetMessageById(ctx, secondMessageId) require.NoError(t, err) - err = fx.MarkReadMessages(ctx, "", firstMessage.OrderId, firstMessage.StateId, CounterTypeMessage) - require.NoError(t, err) + err = fx.MarkReadMessages(ctx, ReadMessagesRequest{ + AfterOrderId: "", + BeforeOrderId: firstMessage.OrderId, + LastStateId: firstMessage.StateId, + CounterType: chatmodel.CounterTypeMessage, + }) - gotResponse, err := fx.GetMessages(ctx, GetMessagesRequest{}) + gotResponse, err := fx.GetMessages(ctx, chatrepository.GetMessagesRequest{}) require.NoError(t, err) firstMessage.Read = true - wantMessages := []*Message{ + wantMessages := []*chatmodel.Message{ secondMessage, firstMessage, } @@ -95,7 +106,12 @@ func TestReadMentions(t *testing.T) { // All messages forced as not read messagesResp := fx.assertReadStatus(t, ctx, "", "", false, false) - err := fx.MarkReadMessages(ctx, "", messagesResp.Messages[2].OrderId, messagesResp.ChatState.LastStateId, CounterTypeMention) + err := fx.MarkReadMessages(ctx, ReadMessagesRequest{ + AfterOrderId: "", + BeforeOrderId: messagesResp.Messages[2].OrderId, + LastStateId: messagesResp.ChatState.LastStateId, + CounterType: chatmodel.CounterTypeMention, + }) require.NoError(t, err) fx.assertReadStatus(t, ctx, "", messagesResp.Messages[2].OrderId, false, true) @@ -122,7 +138,12 @@ func TestReadMentions(t *testing.T) { // All messages forced as not read messagesResp := fx.assertReadStatus(t, ctx, "", "", false, false) - err = fx.MarkReadMessages(ctx, "", secondMessage.OrderId, messagesResp.ChatState.LastStateId, CounterTypeMention) + err = fx.MarkReadMessages(ctx, ReadMessagesRequest{ + AfterOrderId: "", + BeforeOrderId: secondMessage.OrderId, + LastStateId: messagesResp.ChatState.LastStateId, + CounterType: chatmodel.CounterTypeMention, + }) require.NoError(t, err) fx.assertReadStatus(t, ctx, secondMessage.OrderId, secondMessage.OrderId, false, true) @@ -141,7 +162,7 @@ func TestMarkMessagesAsNotRead(t *testing.T) { // All messages added by myself are read fx.assertReadStatus(t, ctx, "", "", true, true) - err := fx.MarkMessagesAsUnread(ctx, "", CounterTypeMessage) + err := fx.MarkMessagesAsUnread(ctx, "", chatmodel.CounterTypeMessage) require.NoError(t, err) fx.assertReadStatus(t, ctx, "", "", false, true) @@ -159,7 +180,7 @@ func TestMarkMentionsAsNotRead(t *testing.T) { // All messages added by myself are read fx.assertReadStatus(t, ctx, "", "", true, true) - err := fx.MarkMessagesAsUnread(ctx, "", CounterTypeMention) + err := fx.MarkMessagesAsUnread(ctx, "", chatmodel.CounterTypeMention) require.NoError(t, err) fx.assertReadStatus(t, ctx, "", "", true, false) diff --git a/core/block/editor/chatobject/repository.go b/core/block/editor/chatobject/repository.go deleted file mode 100644 index 64e3c67c1..000000000 --- a/core/block/editor/chatobject/repository.go +++ /dev/null @@ -1,331 +0,0 @@ -package chatobject - -import ( - "context" - "errors" - "fmt" - "slices" - "sort" - - anystore "github.com/anyproto/any-store" - "github.com/anyproto/any-store/anyenc" - "github.com/anyproto/any-store/query" - "go.uber.org/zap" - - "github.com/anyproto/anytype-heart/pkg/lib/pb/model" -) - -type repository struct { - collection anystore.Collection - arenaPool *anyenc.ArenaPool -} - -func (s *repository) writeTx(ctx context.Context) (anystore.WriteTx, error) { - return s.collection.WriteTx(ctx) -} - -func (s *repository) readTx(ctx context.Context) (anystore.ReadTx, error) { - return s.collection.ReadTx(ctx) -} - -func (s *repository) getLastStateId(ctx context.Context) (string, error) { - lastAddedDate := s.collection.Find(nil).Sort(descStateId).Limit(1) - iter, err := lastAddedDate.Iter(ctx) - if err != nil { - return "", fmt.Errorf("find last added date: %w", err) - } - defer iter.Close() - - for iter.Next() { - doc, err := iter.Doc() - if err != nil { - return "", fmt.Errorf("get doc: %w", err) - } - msg, err := unmarshalMessage(doc.Value()) - if err != nil { - return "", fmt.Errorf("unmarshal message: %w", err) - } - return msg.StateId, nil - } - return "", nil -} - -func (s *repository) getPrevOrderId(ctx context.Context, orderId string) (string, error) { - iter, err := s.collection.Find(query.Key{Path: []string{orderKey, "id"}, Filter: query.NewComp(query.CompOpLt, orderId)}). - Sort(descOrder). - Limit(1). - Iter(ctx) - if err != nil { - return "", fmt.Errorf("init iterator: %w", err) - } - defer iter.Close() - - if iter.Next() { - doc, err := iter.Doc() - if err != nil { - return "", fmt.Errorf("read doc: %w", err) - } - prevOrderId := doc.Value().GetString(orderKey, "id") - return prevOrderId, nil - } - - return "", nil -} - -// initialChatState returns the initial chat state for the chat object from the DB -func (s *repository) loadChatState(ctx context.Context) (*model.ChatState, error) { - txn, err := s.readTx(ctx) - if err != nil { - return nil, fmt.Errorf("start read tx: %w", err) - } - defer txn.Commit() - - messagesState, err := s.loadChatStateByType(txn.Context(), CounterTypeMessage) - if err != nil { - return nil, fmt.Errorf("get messages state: %w", err) - } - mentionsState, err := s.loadChatStateByType(txn.Context(), CounterTypeMention) - if err != nil { - return nil, fmt.Errorf("get mentions state: %w", err) - } - - lastStateId, err := s.getLastStateId(txn.Context()) - if err != nil { - return nil, fmt.Errorf("get last added date: %w", err) - } - - return &model.ChatState{ - Messages: messagesState, - Mentions: mentionsState, - LastStateId: lastStateId, - }, nil -} - -func (s *repository) loadChatStateByType(ctx context.Context, counterType CounterType) (*model.ChatStateUnreadState, error) { - opts := newReadHandler(counterType, nil) - - oldestOrderId, err := s.getOldestOrderId(ctx, opts) - if err != nil { - return nil, fmt.Errorf("get oldest order id: %w", err) - } - - count, err := s.countUnreadMessages(ctx, opts) - if err != nil { - return nil, fmt.Errorf("update messages: %w", err) - } - - return &model.ChatStateUnreadState{ - OldestOrderId: oldestOrderId, - Counter: int32(count), - }, nil -} - -func (s *repository) getOldestOrderId(ctx context.Context, handler readHandler) (string, error) { - unreadQuery := s.collection.Find(handler.getUnreadFilter()).Sort(ascOrder) - - iter, err := unreadQuery.Limit(1).Iter(ctx) - if err != nil { - return "", fmt.Errorf("init iter: %w", err) - } - defer iter.Close() - - for iter.Next() { - doc, err := iter.Doc() - if err != nil { - return "", fmt.Errorf("get doc: %w", err) - } - orders := doc.Value().GetObject(orderKey) - if orders != nil { - return orders.Get("id").GetString(), nil - } - } - return "", nil -} - -func (s *repository) countUnreadMessages(ctx context.Context, handler readHandler) (int, error) { - unreadQuery := s.collection.Find(handler.getUnreadFilter()) - - return unreadQuery.Count(ctx) -} - -func (s *repository) getReadMessagesAfter(ctx context.Context, afterOrderId string, handler readHandler) ([]string, error) { - filter := query.And{ - query.Key{Path: []string{orderKey, "id"}, Filter: query.NewComp(query.CompOpGte, afterOrderId)}, - query.Key{Path: []string{handler.getReadKey()}, Filter: query.NewComp(query.CompOpEq, true)}, - } - if handler.getMessagesFilter() != nil { - filter = append(filter, handler.getMessagesFilter()) - } - - iter, err := s.collection.Find(filter).Iter(ctx) - if err != nil { - return nil, fmt.Errorf("init iterator: %w", err) - } - defer iter.Close() - - var msgIds []string - for iter.Next() { - doc, err := iter.Doc() - if err != nil { - return nil, fmt.Errorf("get doc: %w", err) - } - msgIds = append(msgIds, doc.Value().GetString("id")) - } - return msgIds, iter.Err() -} - -func (s *repository) getUnreadMessageIdsInRange(ctx context.Context, afterOrderId, beforeOrderId string, lastStateId string, handler readHandler) ([]string, error) { - qry := query.And{ - query.Key{Path: []string{orderKey, "id"}, Filter: query.NewComp(query.CompOpGte, afterOrderId)}, - query.Key{Path: []string{orderKey, "id"}, Filter: query.NewComp(query.CompOpLte, beforeOrderId)}, - query.Or{ - query.Not{query.Key{Path: []string{stateIdKey}, Filter: query.Exists{}}}, - query.Key{Path: []string{stateIdKey}, Filter: query.NewComp(query.CompOpLte, lastStateId)}, - }, - handler.getUnreadFilter(), - } - iter, err := s.collection.Find(qry).Iter(ctx) - if err != nil { - return nil, fmt.Errorf("find id: %w", err) - } - defer iter.Close() - - var msgIds []string - for iter.Next() { - doc, err := iter.Doc() - if err != nil { - return nil, fmt.Errorf("get doc: %w", err) - } - msgIds = append(msgIds, doc.Value().GetString("id")) - } - return msgIds, iter.Err() -} - -func (r *repository) setReadFlag(ctx context.Context, chatObjectId string, msgIds []string, handler readHandler, value bool) []string { - var idsModified []string - for _, id := range msgIds { - if id == chatObjectId { - // skip tree root - continue - } - res, err := r.collection.UpdateId(ctx, id, handler.readModifier(value)) - // Not all changes are messages, skip them - if errors.Is(err, anystore.ErrDocNotFound) { - continue - } - if err != nil { - log.Error("markReadMessages: update message", zap.Error(err), zap.String("changeId", id), zap.String("chatObjectId", chatObjectId)) - continue - } - if res.Modified > 0 { - idsModified = append(idsModified, id) - } - } - return idsModified -} - -func (s *repository) getMessages(ctx context.Context, req GetMessagesRequest) ([]*Message, error) { - var qry anystore.Query - if req.AfterOrderId != "" { - operator := query.CompOpGt - if req.IncludeBoundary { - operator = query.CompOpGte - } - qry = s.collection.Find(query.Key{Path: []string{orderKey, "id"}, Filter: query.NewComp(operator, req.AfterOrderId)}).Sort(ascOrder).Limit(uint(req.Limit)) - } else if req.BeforeOrderId != "" { - operator := query.CompOpLt - if req.IncludeBoundary { - operator = query.CompOpLte - } - qry = s.collection.Find(query.Key{Path: []string{orderKey, "id"}, Filter: query.NewComp(operator, req.BeforeOrderId)}).Sort(descOrder).Limit(uint(req.Limit)) - } else { - qry = s.collection.Find(nil).Sort(descOrder).Limit(uint(req.Limit)) - } - - msgs, err := s.queryMessages(ctx, qry) - if err != nil { - return nil, fmt.Errorf("query messages: %w", err) - } - return msgs, nil -} - -func (s *repository) queryMessages(ctx context.Context, query anystore.Query) ([]*Message, error) { - arena := s.arenaPool.Get() - defer func() { - arena.Reset() - s.arenaPool.Put(arena) - }() - - iter, err := query.Iter(ctx) - if err != nil { - return nil, fmt.Errorf("find iter: %w", err) - } - defer iter.Close() - - var res []*Message - for iter.Next() { - doc, err := iter.Doc() - if err != nil { - return nil, fmt.Errorf("get doc: %w", err) - } - - msg, err := unmarshalMessage(doc.Value()) - if err != nil { - return nil, fmt.Errorf("unmarshal message: %w", err) - } - res = append(res, msg) - } - // reverse - sort.Slice(res, func(i, j int) bool { - return res[i].OrderId < res[j].OrderId - }) - return res, nil -} - -func (s *repository) hasMyReaction(ctx context.Context, myIdentity string, messageId string, emoji string) (bool, error) { - doc, err := s.collection.FindId(ctx, messageId) - if err != nil { - return false, fmt.Errorf("find message: %w", err) - } - - msg, err := unmarshalMessage(doc.Value()) - if err != nil { - return false, fmt.Errorf("unmarshal message: %w", err) - } - if v, ok := msg.GetReactions().GetReactions()[emoji]; ok { - if slices.Contains(v.GetIds(), myIdentity) { - return true, nil - } - } - return false, nil -} - -func (s *repository) getMessagesByIds(ctx context.Context, messageIds []string) ([]*Message, error) { - txn, err := s.readTx(ctx) - if err != nil { - return nil, fmt.Errorf("start read tx: %w", err) - } - defer txn.Commit() - - messages := make([]*Message, 0, len(messageIds)) - for _, messageId := range messageIds { - obj, err := s.collection.FindId(txn.Context(), messageId) - if errors.Is(err, anystore.ErrDocNotFound) { - continue - } - if err != nil { - return nil, errors.Join(txn.Commit(), fmt.Errorf("find id: %w", err)) - } - msg, err := unmarshalMessage(obj.Value()) - if err != nil { - return nil, errors.Join(txn.Commit(), fmt.Errorf("unmarshal message: %w", err)) - } - messages = append(messages, msg) - } - return messages, nil -} - -func (s *repository) getLastMessages(ctx context.Context, limit uint) ([]*Message, error) { - qry := s.collection.Find(nil).Sort(descOrder).Limit(limit) - return s.queryMessages(ctx, qry) -} diff --git a/core/block/editor/chatobject/subscription_test.go b/core/block/editor/chatobject/subscription_test.go index 40ab1829f..4f688cc72 100644 --- a/core/block/editor/chatobject/subscription_test.go +++ b/core/block/editor/chatobject/subscription_test.go @@ -9,6 +9,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" + "github.com/anyproto/anytype-heart/core/block/chats/chatsubscription" "github.com/anyproto/anytype-heart/core/domain" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pkg/lib/bundle" @@ -27,7 +29,9 @@ func TestSubscription(t *testing.T) { assert.NotEmpty(t, messageId) } - resp, err := fx.SubscribeLastMessages(ctx, SubscribeLastMessagesRequest{SubId: "subId", Limit: 5, AsyncInit: false}) + resp, err := fx.chatSubscriptionService.SubscribeLastMessages(ctx, chatsubscription.SubscribeLastMessagesRequest{ + ChatObjectId: fx.Id(), SubId: "subId", Limit: 5, AsyncInit: false, + }) require.NoError(t, err) wantTexts := []string{"text 6", "text 7", "text 8", "text 9", "text 10"} for i, msg := range resp.Messages { @@ -181,7 +185,9 @@ func TestSubscriptionMessageCounters(t *testing.T) { fx := newFixture(t) fx.chatHandler.forceNotRead = true - subscribeResp, err := fx.SubscribeLastMessages(ctx, SubscribeLastMessagesRequest{SubId: "subId", Limit: 10, AsyncInit: false}) + subscribeResp, err := fx.chatSubscriptionService.SubscribeLastMessages(ctx, chatsubscription.SubscribeLastMessagesRequest{ + ChatObjectId: fx.Id(), SubId: "subId", Limit: 10, AsyncInit: false, + }) require.NoError(t, err) assert.Empty(t, subscribeResp.Messages) @@ -275,7 +281,12 @@ func TestSubscriptionMessageCounters(t *testing.T) { fx.events = nil - err = fx.MarkReadMessages(ctx, "", firstMessage.OrderId, secondMessage.StateId, CounterTypeMessage) + err = fx.MarkReadMessages(ctx, ReadMessagesRequest{ + AfterOrderId: "", + BeforeOrderId: firstMessage.OrderId, + LastStateId: secondMessage.StateId, + CounterType: chatmodel.CounterTypeMessage, + }) require.NoError(t, err) wantEvents = []*pb.EventMessage{ @@ -315,7 +326,12 @@ func TestSubscriptionMentionCounters(t *testing.T) { fx := newFixture(t) fx.chatHandler.forceNotRead = true - subscribeResp, err := fx.SubscribeLastMessages(ctx, SubscribeLastMessagesRequest{SubId: "subId", Limit: 10, AsyncInit: false}) + subscribeResp, err := fx.chatSubscriptionService.SubscribeLastMessages(ctx, chatsubscription.SubscribeLastMessagesRequest{ + ChatObjectId: fx.Id(), + SubId: "subId", + Limit: 10, + AsyncInit: false, + }) require.NoError(t, err) assert.Empty(t, subscribeResp.Messages) @@ -415,7 +431,12 @@ func TestSubscriptionMentionCounters(t *testing.T) { fx.events = nil - err = fx.MarkReadMessages(ctx, "", firstMessage.OrderId, secondMessage.StateId, CounterTypeMention) + err = fx.MarkReadMessages(ctx, ReadMessagesRequest{ + AfterOrderId: "", + BeforeOrderId: firstMessage.OrderId, + LastStateId: secondMessage.StateId, + CounterType: chatmodel.CounterTypeMention, + }) require.NoError(t, err) wantEvents = []*pb.EventMessage{ @@ -457,7 +478,13 @@ func TestSubscriptionWithDeps(t *testing.T) { ctx := context.Background() fx := newFixture(t) - _, err := fx.SubscribeLastMessages(ctx, SubscribeLastMessagesRequest{SubId: "subId", Limit: 10, AsyncInit: false, WithDependencies: true}) + _, err := fx.chatSubscriptionService.SubscribeLastMessages(ctx, chatsubscription.SubscribeLastMessagesRequest{ + ChatObjectId: fx.Id(), + SubId: "subId", + Limit: 10, + AsyncInit: false, + WithDependencies: true, + }) require.NoError(t, err) myParticipantId := domain.NewParticipantId(testSpaceId, testCreator) diff --git a/core/block/editor/factory.go b/core/block/editor/factory.go index a65c898c3..42b6a92a3 100644 --- a/core/block/editor/factory.go +++ b/core/block/editor/factory.go @@ -10,6 +10,8 @@ import ( "github.com/anyproto/anytype-heart/core/anytype/config" "github.com/anyproto/anytype-heart/core/block/cache" + "github.com/anyproto/anytype-heart/core/block/chats/chatrepository" + "github.com/anyproto/anytype-heart/core/block/chats/chatsubscription" "github.com/anyproto/anytype-heart/core/block/editor/accountobject" "github.com/anyproto/anytype-heart/core/block/editor/bookmark" "github.com/anyproto/anytype-heart/core/block/editor/chatobject" @@ -52,27 +54,29 @@ type deviceService interface { } type ObjectFactory struct { - bookmarkService bookmark.BookmarkService - fileBlockService file.BlockService - layoutConverter converter.LayoutConverter - objectStore objectstore.ObjectStore - sourceService source.Service - tempDirProvider core.TempDirProvider - fileStore filestore.FileStore - fileService files.Service - config *config.Config - picker cache.ObjectGetter - eventSender event.Sender - indexer smartblock.Indexer - spaceService spaceService - accountService accountService - fileObjectService fileobject.Service - processService process.Service - fileUploaderService fileuploader.Service - fileReconciler reconciler.Reconciler - objectDeleter ObjectDeleter - deviceService deviceService - spaceIdResolver idresolver.Resolver + bookmarkService bookmark.BookmarkService + fileBlockService file.BlockService + layoutConverter converter.LayoutConverter + objectStore objectstore.ObjectStore + sourceService source.Service + tempDirProvider core.TempDirProvider + fileStore filestore.FileStore + fileService files.Service + config *config.Config + picker cache.ObjectGetter + eventSender event.Sender + indexer smartblock.Indexer + spaceService spaceService + accountService accountService + fileObjectService fileobject.Service + processService process.Service + fileUploaderService fileuploader.Service + fileReconciler reconciler.Reconciler + objectDeleter ObjectDeleter + deviceService deviceService + spaceIdResolver idresolver.Resolver + chatRepositoryService chatrepository.Service + chatSubscriptionService chatsubscription.Service } func NewObjectFactory() *ObjectFactory { @@ -104,6 +108,8 @@ func (f *ObjectFactory) Init(a *app.App) (err error) { f.fileReconciler = app.MustComponent[reconciler.Reconciler](a) f.deviceService = app.MustComponent[deviceService](a) f.spaceIdResolver = app.MustComponent[idresolver.Resolver](a) + f.chatRepositoryService = app.MustComponent[chatrepository.Service](a) + f.chatSubscriptionService = app.MustComponent[chatsubscription.Service](a) return nil } @@ -217,9 +223,17 @@ func (f *ObjectFactory) New(space smartblock.Space, sbType coresb.SmartBlockType case coresb.SmartBlockTypeDevicesObject: return NewDevicesObject(sb, f.deviceService), nil case coresb.SmartBlockTypeChatDerivedObject: - return chatobject.New(sb, f.accountService, f.eventSender, f.objectStore.GetCrdtDb(space.Id()), spaceIndex), nil + crdtDb, err := f.objectStore.GetCrdtDb(space.Id()).Wait() + if err != nil { + return nil, fmt.Errorf("get crdt db: %w", err) + } + return chatobject.New(sb, f.accountService, crdtDb, f.chatRepositoryService, f.chatSubscriptionService), nil case coresb.SmartBlockTypeAccountObject: - return accountobject.New(sb, f.accountService.Keys(), spaceIndex, f.layoutConverter, f.fileObjectService, f.objectStore.GetCrdtDb(space.Id()), f.config), nil + crdtDb, err := f.objectStore.GetCrdtDb(space.Id()).Wait() + if err != nil { + return nil, fmt.Errorf("get crdt db: %w", err) + } + return accountobject.New(sb, f.accountService.Keys(), spaceIndex, f.layoutConverter, f.fileObjectService, crdtDb, f.config), nil default: return nil, fmt.Errorf("unexpected smartblock type: %v", sbType) } diff --git a/core/block/editor/objecttype.go b/core/block/editor/objecttype.go index c1de6d519..2f9ef046b 100644 --- a/core/block/editor/objecttype.go +++ b/core/block/editor/objecttype.go @@ -34,6 +34,7 @@ var typeRequiredRelations = append(typeAndRelationRequiredRelations, bundle.RelationKeyIconOption, bundle.RelationKeyIconName, bundle.RelationKeyPluralName, + bundle.RelationKeyHeaderRelationsLayout, ) type ObjectType struct { @@ -99,6 +100,7 @@ func (ot *ObjectType) CreationStateMigration(ctx *smartblock.InitContext) migrat template.WithObjectTypes(ctx.State.ObjectTypeKeys()), template.WithTitle, template.WithLayout(model.ObjectType_objectType), + template.WithDetail(bundle.RelationKeyRecommendedLayout, domain.Int64(model.ObjectType_basic)), } templates = append(templates, ot.dataviewTemplates()...) diff --git a/core/block/editor/page.go b/core/block/editor/page.go index bf9d7e5cd..310ab4437 100644 --- a/core/block/editor/page.go +++ b/core/block/editor/page.go @@ -42,6 +42,7 @@ var typeAndRelationRequiredRelations = []domain.RelationKey{ bundle.RelationKeyLastUsedDate, bundle.RelationKeyRevision, bundle.RelationKeyIsHidden, + bundle.RelationKeyApiObjectKey, } var relationRequiredRelations = append(typeAndRelationRequiredRelations, @@ -50,6 +51,10 @@ var relationRequiredRelations = append(typeAndRelationRequiredRelations, bundle.RelationKeyRelationKey, ) +var relationOptionRequiredRelations = []domain.RelationKey{ + bundle.RelationKeyApiObjectKey, +} + type Page struct { smartblock.SmartBlock basic.AllOperations @@ -136,6 +141,8 @@ func appendRequiredInternalRelations(ctx *smartblock.InitContext) { ctx.RequiredInternalRelationKeys = append(ctx.RequiredInternalRelationKeys, typeRequiredRelations...) case bundle.TypeKeyRelation: ctx.RequiredInternalRelationKeys = append(ctx.RequiredInternalRelationKeys, relationRequiredRelations...) + case bundle.TypeKeyRelationOption: + ctx.RequiredInternalRelationKeys = append(ctx.RequiredInternalRelationKeys, relationOptionRequiredRelations...) } } diff --git a/core/block/editor/smartblock/smartblock.go b/core/block/editor/smartblock/smartblock.go index 099bece0b..27a01f221 100644 --- a/core/block/editor/smartblock/smartblock.go +++ b/core/block/editor/smartblock/smartblock.go @@ -360,6 +360,9 @@ func (sb *smartBlock) Init(ctx *InitContext) (err error) { } } ctx.State.AddBundledRelationLinks(relKeys...) + if ctx.IsNewObject && ctx.State != nil { + source.NewSubObjectsAndProfileLinksMigration(sb.Type(), sb.space, sb.currentParticipantId, sb.spaceIndex).Migrate(ctx.State) + } if err = sb.injectLocalDetails(ctx.State); err != nil { return @@ -848,6 +851,7 @@ func (sb *smartBlock) Apply(s *state.State, flags ...ApplyFlag) (err error) { } func (sb *smartBlock) ResetToVersion(s *state.State) (err error) { + source.NewSubObjectsAndProfileLinksMigration(sb.Type(), sb.space, sb.currentParticipantId, sb.spaceIndex).Migrate(s) s.SetParent(sb.Doc.(*state.State)) sb.storeFileKeys(s) sb.injectLocalDetails(s) diff --git a/core/block/editor/spaceview.go b/core/block/editor/spaceview.go index 72e800db2..bca70235f 100644 --- a/core/block/editor/spaceview.go +++ b/core/block/editor/spaceview.go @@ -32,8 +32,6 @@ var spaceViewRequiredRelations = []domain.RelationKey{ bundle.RelationKeySpaceLocalStatus, bundle.RelationKeySpaceRemoteStatus, bundle.RelationKeyTargetSpaceId, - bundle.RelationKeySpaceInviteFileCid, - bundle.RelationKeySpaceInviteFileKey, bundle.RelationKeyIsAclShared, bundle.RelationKeySharedSpacesLimit, bundle.RelationKeySpaceAccountStatus, @@ -121,28 +119,6 @@ func (s *SpaceView) initTemplate(st *state.State) { ) } -func (s *SpaceView) GetExistingInviteInfo() (fileCid string, fileKey string) { - details := s.CombinedDetails() - fileCid = details.GetString(bundle.RelationKeySpaceInviteFileCid) - fileKey = details.GetString(bundle.RelationKeySpaceInviteFileKey) - return -} - -func (s *SpaceView) RemoveExistingInviteInfo() (fileCid string, err error) { - details := s.Details() - fileCid = details.GetString(bundle.RelationKeySpaceInviteFileCid) - newState := s.NewState() - newState.RemoveDetail(bundle.RelationKeySpaceInviteFileCid, bundle.RelationKeySpaceInviteFileKey) - return fileCid, s.Apply(newState) -} - -func (s *SpaceView) GetGuestUserInviteInfo() (fileCid string, fileKey string) { - details := s.CombinedDetails() - fileCid = details.GetString(bundle.RelationKeySpaceInviteGuestFileCid) - fileKey = details.GetString(bundle.RelationKeySpaceInviteGuestFileKey) - return -} - func (s *SpaceView) TryClose(objectTTL time.Duration) (res bool, err error) { return false, nil } @@ -210,13 +186,6 @@ func (s *SpaceView) GetSharedSpacesLimit() (limit int) { return int(s.CombinedDetails().GetInt64(bundle.RelationKeySharedSpacesLimit)) } -func (s *SpaceView) SetInviteFileInfo(fileCid string, fileKey string) (err error) { - st := s.NewState() - st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileCid, domain.String(fileCid)) - st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileKey, domain.String(fileKey)) - return s.Apply(st) -} - func (s *SpaceView) afterApply(info smartblock.ApplyInfo) (err error) { s.spaceService.OnViewUpdated(s.getSpacePersistentInfo(info.State)) return nil diff --git a/core/block/editor/workspaces.go b/core/block/editor/workspaces.go index 41d4a83ac..783d74f55 100644 --- a/core/block/editor/workspaces.go +++ b/core/block/editor/workspaces.go @@ -1,6 +1,8 @@ package editor import ( + "github.com/anyproto/any-sync/commonspace/object/acl/list" + "github.com/anyproto/anytype-heart/core/anytype/config" "github.com/anyproto/anytype-heart/core/block/editor/basic" "github.com/anyproto/anytype-heart/core/block/editor/dataview" @@ -95,26 +97,37 @@ func (w *Workspaces) CreationStateMigration(ctx *smartblock.InitContext) migrati } } -func (w *Workspaces) SetInviteFileInfo(fileCid string, fileKey string) (err error) { +func (w *Workspaces) SetInviteFileInfo(info domain.InviteInfo) (err error) { st := w.NewState() - st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileCid, domain.String(fileCid)) - st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileKey, domain.String(fileKey)) + st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInvitePermissions, domain.Int64(domain.ConvertAclPermissions(info.Permissions))) + st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteType, domain.Int64(info.InviteType)) + st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileCid, domain.String(info.InviteFileCid)) + st.SetDetailAndBundledRelation(bundle.RelationKeySpaceInviteFileKey, domain.String(info.InviteFileKey)) return w.Apply(st) } -func (w *Workspaces) GetExistingInviteInfo() (fileCid string, fileKey string) { +func (w *Workspaces) GetExistingInviteInfo() (inviteInfo domain.InviteInfo) { details := w.CombinedDetails() - fileCid = details.GetString(bundle.RelationKeySpaceInviteFileCid) - fileKey = details.GetString(bundle.RelationKeySpaceInviteFileKey) + inviteInfo.InviteType = domain.InviteType(details.GetInt64(bundle.RelationKeySpaceInviteType)) + // nolint: gosec + inviteInfo.Permissions = domain.ConvertParticipantPermissions(model.ParticipantPermissions(details.GetInt64(bundle.RelationKeySpaceInvitePermissions))) + inviteInfo.InviteFileCid = details.GetString(bundle.RelationKeySpaceInviteFileCid) + inviteInfo.InviteFileKey = details.GetString(bundle.RelationKeySpaceInviteFileKey) + if inviteInfo.InviteType == domain.InviteTypeDefault { + inviteInfo.Permissions = list.AclPermissionsNone + } return } -func (w *Workspaces) RemoveExistingInviteInfo() (fileCid string, err error) { - details := w.Details() - fileCid = details.GetString(bundle.RelationKeySpaceInviteFileCid) +func (w *Workspaces) RemoveExistingInviteInfo() (info domain.InviteInfo, err error) { + info = w.GetExistingInviteInfo() newState := w.NewState() - newState.RemoveDetail(bundle.RelationKeySpaceInviteFileCid, bundle.RelationKeySpaceInviteFileKey) - return fileCid, w.Apply(newState) + newState.RemoveDetail( + bundle.RelationKeySpaceInviteFileCid, + bundle.RelationKeySpaceInviteFileKey, + bundle.RelationKeySpaceInvitePermissions, + bundle.RelationKeySpaceInviteType) + return info, w.Apply(newState) } func (w *Workspaces) SetGuestInviteFileInfo(fileCid string, fileKey string) (err error) { diff --git a/core/block/editor/workspaces_test.go b/core/block/editor/workspaces_test.go index d26a17f4c..6db93f5e4 100644 --- a/core/block/editor/workspaces_test.go +++ b/core/block/editor/workspaces_test.go @@ -3,6 +3,7 @@ package editor import ( "testing" + "github.com/anyproto/any-sync/commonspace/object/acl/list" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" @@ -11,23 +12,29 @@ import ( "github.com/anyproto/anytype-heart/core/block/editor/smartblock/smarttest" "github.com/anyproto/anytype-heart/core/block/editor/state" "github.com/anyproto/anytype-heart/core/block/migration" + "github.com/anyproto/anytype-heart/core/domain" ) func TestWorkspaces_FileInfo(t *testing.T) { t.Run("file info add remove", func(t *testing.T) { fx := newWorkspacesFixture(t) defer fx.finish() - err := fx.SetInviteFileInfo("fileId", "fileKey") + info := domain.InviteInfo{ + InviteFileCid: "fileId", + InviteFileKey: "fileKey", + InviteType: domain.InviteTypeAnyone, + Permissions: list.AclPermissionsWriter, + } + err := fx.SetInviteFileInfo(info) require.NoError(t, err) - fileId, fileKey := fx.GetExistingInviteInfo() - require.Equal(t, "fileId", fileId) - require.Equal(t, "fileKey", fileKey) - fileId, err = fx.RemoveExistingInviteInfo() + returnedInfo := fx.GetExistingInviteInfo() + require.Equal(t, info, returnedInfo) + returnedInfo, err = fx.RemoveExistingInviteInfo() require.NoError(t, err) - require.Equal(t, "fileId", fileId) - fileId, err = fx.RemoveExistingInviteInfo() + require.Equal(t, info, returnedInfo) + returnedInfo, err = fx.RemoveExistingInviteInfo() require.NoError(t, err) - require.Empty(t, fileId) + require.Empty(t, returnedInfo) }) t.Run("file info empty", func(t *testing.T) { fx := newWorkspacesFixture(t) diff --git a/core/block/export/export.go b/core/block/export/export.go index 0c2b7789e..a206461f0 100644 --- a/core/block/export/export.go +++ b/core/block/export/export.go @@ -273,7 +273,9 @@ func (e *exportContext) exportObject(ctx context.Context, objectId string) (stri if err != nil { return "", err } + // do not allow file export for in-memory writer + // nolint: gosec switch model.ObjectTypeLayout(details.GetInt64(bundle.RelationKeyLayout)) { case model.ObjectType_file, model.ObjectType_image, model.ObjectType_video, model.ObjectType_audio, model.ObjectType_pdf: return "", fmt.Errorf("file export is not allowed for in-memory writer") diff --git a/core/block/import/common/objectcreator/objectcreator.go b/core/block/import/common/objectcreator/objectcreator.go index fef90192a..084ad6ebd 100644 --- a/core/block/import/common/objectcreator/objectcreator.go +++ b/core/block/import/common/objectcreator/objectcreator.go @@ -374,6 +374,9 @@ func (oc *ObjectCreator) resetState(newID string, st *state.State) *domain.Detai // we use revision for bundled objects like relations and object types return nil } + if st.ObjectTypeKey() == bundle.TypeKeyObjectType { + template.InitTemplate(st, template.WithDetail(bundle.RelationKeyRecommendedLayout, domain.Int64(model.ObjectType_basic))) + } err := history.ResetToVersion(b, st) if err != nil { log.With(zap.String("object id", newID)).Errorf("failed to set state %s: %s", newID, err) diff --git a/core/block/object/objectcreator/object_type.go b/core/block/object/objectcreator/object_type.go index 39fd54fe9..968fe2df5 100644 --- a/core/block/object/objectcreator/object_type.go +++ b/core/block/object/objectcreator/object_type.go @@ -20,12 +20,18 @@ func (s *service) createObjectType(ctx context.Context, space clientspace.Space, return "", nil, fmt.Errorf("create object type: no data") } - uniqueKey, err := getUniqueKeyOrGenerate(coresb.SmartBlockTypeObjectType, details) + uniqueKey, wasGenerated, err := getUniqueKeyOrGenerate(coresb.SmartBlockTypeObjectType, details) if err != nil { return "", nil, fmt.Errorf("getUniqueKeyOrGenerate: %w", err) } object := details.Copy() + var objectKey string + if !wasGenerated { + objectKey = uniqueKey.InternalKey() + } + injectApiObjectKey(object, objectKey) + if !object.Has(bundle.RelationKeyRecommendedLayout) { object.SetInt64(bundle.RelationKeyRecommendedLayout, int64(model.ObjectType_basic)) } diff --git a/core/block/object/objectcreator/relation.go b/core/block/object/objectcreator/relation.go index d25e71984..cdeb8bf15 100644 --- a/core/block/object/objectcreator/relation.go +++ b/core/block/object/objectcreator/relation.go @@ -32,12 +32,17 @@ func (s *service) createRelation(ctx context.Context, space clientspace.Space, d if details.GetString(bundle.RelationKeyName) == "" { return "", nil, fmt.Errorf("missing relation name") } + if !details.Has(bundle.RelationKeyCreatedDate) { details.SetInt64(bundle.RelationKeyCreatedDate, time.Now().Unix()) } object = details.Copy() + key := domain.RelationKey(details.GetString(bundle.RelationKeyRelationKey)) + + injectApiObjectKey(object, key.String()) + if key == "" { key = domain.RelationKey(bson.NewObjectId().Hex()) } else if bundle.HasRelation(key) { @@ -50,6 +55,7 @@ func (s *service) createRelation(ctx context.Context, space clientspace.Space, d object.SetString(bundle.RelationKeyUniqueKey, uniqueKey.Marshal()) object.SetString(bundle.RelationKeyId, id) object.SetString(bundle.RelationKeyRelationKey, string(key)) + if details.GetInt64(bundle.RelationKeyRelationFormat) == int64(model.RelationFormat_status) { object.SetInt64(bundle.RelationKeyRelationMaxCount, 1) } diff --git a/core/block/object/objectcreator/relation_option.go b/core/block/object/objectcreator/relation_option.go index c7156594e..80c290bae 100644 --- a/core/block/object/objectcreator/relation_option.go +++ b/core/block/object/objectcreator/relation_option.go @@ -3,10 +3,9 @@ package objectcreator import ( "context" "fmt" + "strings" "time" - "github.com/globalsign/mgo/bson" - "github.com/anyproto/anytype-heart/core/block/editor/state" "github.com/anyproto/anytype-heart/core/domain" "github.com/anyproto/anytype-heart/pkg/lib/bundle" @@ -29,7 +28,7 @@ func (s *service) createRelationOption(ctx context.Context, space clientspace.Sp if !details.Has(bundle.RelationKeyCreatedDate) { details.SetInt64(bundle.RelationKeyCreatedDate, time.Now().Unix()) } - uniqueKey, err := getUniqueKeyOrGenerate(coresb.SmartBlockTypeRelationOption, details) + uniqueKey, wasGenerated, err := getUniqueKeyOrGenerate(coresb.SmartBlockTypeRelationOption, details) if err != nil { return "", nil, fmt.Errorf("getUniqueKeyOrGenerate: %w", err) } @@ -38,21 +37,18 @@ func (s *service) createRelationOption(ctx context.Context, space clientspace.Sp object.SetString(bundle.RelationKeyUniqueKey, uniqueKey.Marshal()) object.SetInt64(bundle.RelationKeyLayout, int64(model.ObjectType_relationOption)) + var objectKey string + if !wasGenerated { + objectKey = uniqueKey.InternalKey() + } + injectApiObjectKey(object, objectKey) + + if strings.TrimSpace(object.GetString(bundle.RelationKeyApiObjectKey)) == "" { + object.SetString(bundle.RelationKeyApiObjectKey, transliterate(object.GetString(bundle.RelationKeyName))) + } + createState := state.NewDocWithUniqueKey("", nil, uniqueKey).(*state.State) createState.SetDetails(object) setOriginalCreatedTimestamp(createState, details) return s.CreateSmartBlockFromStateInSpace(ctx, space, []domain.TypeKey{bundle.TypeKeyRelationOption}, createState) } - -func getUniqueKeyOrGenerate(sbType coresb.SmartBlockType, details *domain.Details) (domain.UniqueKey, error) { - uniqueKey := details.GetString(bundle.RelationKeyUniqueKey) - if uniqueKey == "" { - newUniqueKey, err := domain.NewUniqueKey(sbType, bson.NewObjectId().Hex()) - if err != nil { - return nil, err - } - details.SetString(bundle.RelationKeyUniqueKey, newUniqueKey.Marshal()) - return newUniqueKey, err - } - return domain.UnmarshalUniqueKey(uniqueKey) -} diff --git a/core/block/object/objectcreator/util.go b/core/block/object/objectcreator/util.go new file mode 100644 index 000000000..940b3c41f --- /dev/null +++ b/core/block/object/objectcreator/util.go @@ -0,0 +1,44 @@ +package objectcreator + +import ( + "strings" + + "github.com/anyproto/anytype-heart/core/domain" + "github.com/anyproto/anytype-heart/pkg/lib/bundle" + coresb "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock" + "github.com/globalsign/mgo/bson" + "github.com/gosimple/unidecode" + "github.com/iancoleman/strcase" +) + +// injectApiObjectKey sets a value for ApiObjectKey relation in priority: +// - User-provided ApiObjectKey +// - Key from relationKey/uniqueKey +// - Transliterated Name relation +func injectApiObjectKey(object *domain.Details, key string) { + if strings.TrimSpace(object.GetString(bundle.RelationKeyApiObjectKey)) == "" { + if key == "" { + key = transliterate(object.GetString(bundle.RelationKeyName)) + } + key = strcase.ToSnake(key) + object.SetString(bundle.RelationKeyApiObjectKey, key) + } +} + +func transliterate(in string) string { + return unidecode.Unidecode(strings.TrimSpace(in)) +} + +func getUniqueKeyOrGenerate(sbType coresb.SmartBlockType, details *domain.Details) (uk domain.UniqueKey, wasGenerated bool, err error) { + uniqueKey := details.GetString(bundle.RelationKeyUniqueKey) + if uniqueKey == "" { + newUniqueKey, err := domain.NewUniqueKey(sbType, bson.NewObjectId().Hex()) + if err != nil { + return nil, false, err + } + details.SetString(bundle.RelationKeyUniqueKey, newUniqueKey.Marshal()) + return newUniqueKey, true, err + } + uk, err = domain.UnmarshalUniqueKey(uniqueKey) + return uk, false, err +} diff --git a/core/block/simple/dataview/dataview.go b/core/block/simple/dataview/dataview.go index 04631f88a..0716ead80 100644 --- a/core/block/simple/dataview/dataview.go +++ b/core/block/simple/dataview/dataview.go @@ -187,6 +187,7 @@ func (s *Dataview) SetView(viewID string, view model.BlockContentDataviewView) e v.PageLimit = view.PageLimit v.DefaultTemplateId = view.DefaultTemplateId v.DefaultObjectTypeId = view.DefaultObjectTypeId + v.EndRelationKey = view.EndRelationKey return nil } @@ -209,6 +210,7 @@ func (d *Dataview) SetViewFields(viewID string, view *model.BlockContentDataview v.PageLimit = view.PageLimit v.DefaultTemplateId = view.DefaultTemplateId v.DefaultObjectTypeId = view.DefaultObjectTypeId + v.EndRelationKey = view.EndRelationKey return nil } diff --git a/core/block/simple/dataview/view_changes.go b/core/block/simple/dataview/view_changes.go index 02d683331..542a30fad 100644 --- a/core/block/simple/dataview/view_changes.go +++ b/core/block/simple/dataview/view_changes.go @@ -16,6 +16,7 @@ func diffViewFields(a, b *model.BlockContentDataviewView) *pb.EventBlockDataview a.CardSize == b.CardSize && a.CoverFit == b.CoverFit && a.GroupRelationKey == b.GroupRelationKey && + a.EndRelationKey == b.EndRelationKey && a.GroupBackgroundColors == b.GroupBackgroundColors && a.PageLimit == b.PageLimit && a.DefaultTemplateId == b.DefaultTemplateId && @@ -36,6 +37,7 @@ func diffViewFields(a, b *model.BlockContentDataviewView) *pb.EventBlockDataview PageLimit: b.PageLimit, DefaultTemplateId: b.DefaultTemplateId, DefaultObjectTypeId: b.DefaultObjectTypeId, + EndRelationKey: b.EndRelationKey, } } @@ -237,6 +239,7 @@ func (l *Dataview) ApplyViewUpdate(upd *pb.EventBlockDataviewViewUpdate) { view.PageLimit = f.PageLimit view.DefaultTemplateId = f.DefaultTemplateId view.DefaultObjectTypeId = f.DefaultObjectTypeId + view.EndRelationKey = f.EndRelationKey } { diff --git a/core/block/source/interface.go b/core/block/source/interface.go index 0761ec311..46dbd12c0 100644 --- a/core/block/source/interface.go +++ b/core/block/source/interface.go @@ -58,9 +58,20 @@ type Service interface { app.Component } +type ReadStoreTreeHook interface { + BeforeIteration(ot objecttree.ObjectTree) + OnIteration(ot objecttree.ObjectTree, change *objecttree.Change) + AfterDiffManagersInit(ctx context.Context) error +} + +type ReadStoreDocParams struct { + OnUpdateHook func() + ReadStoreTreeHook ReadStoreTreeHook +} + type Store interface { Source - ReadStoreDoc(ctx context.Context, stateStore *storestate.StoreState, onUpdateHook func()) (err error) + ReadStoreDoc(ctx context.Context, stateStore *storestate.StoreState, params ReadStoreDocParams) (err error) PushStoreChange(ctx context.Context, params PushStoreChangeParams) (changeId string, err error) SetPushChangeHook(onPushChange PushChangeHook) diff --git a/core/block/source/mock_source/mock_Store.go b/core/block/source/mock_source/mock_Store.go index 86bb1ea0b..3055c9a5d 100644 --- a/core/block/source/mock_source/mock_Store.go +++ b/core/block/source/mock_source/mock_Store.go @@ -590,17 +590,17 @@ func (_c *MockStore_ReadOnly_Call) RunAndReturn(run func() bool) *MockStore_Read return _c } -// ReadStoreDoc provides a mock function with given fields: ctx, stateStore, onUpdateHook -func (_m *MockStore) ReadStoreDoc(ctx context.Context, stateStore *storestate.StoreState, onUpdateHook func()) error { - ret := _m.Called(ctx, stateStore, onUpdateHook) +// ReadStoreDoc provides a mock function with given fields: ctx, stateStore, params +func (_m *MockStore) ReadStoreDoc(ctx context.Context, stateStore *storestate.StoreState, params source.ReadStoreDocParams) error { + ret := _m.Called(ctx, stateStore, params) if len(ret) == 0 { panic("no return value specified for ReadStoreDoc") } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, *storestate.StoreState, func()) error); ok { - r0 = rf(ctx, stateStore, onUpdateHook) + if rf, ok := ret.Get(0).(func(context.Context, *storestate.StoreState, source.ReadStoreDocParams) error); ok { + r0 = rf(ctx, stateStore, params) } else { r0 = ret.Error(0) } @@ -616,14 +616,14 @@ type MockStore_ReadStoreDoc_Call struct { // ReadStoreDoc is a helper method to define mock.On call // - ctx context.Context // - stateStore *storestate.StoreState -// - onUpdateHook func() -func (_e *MockStore_Expecter) ReadStoreDoc(ctx interface{}, stateStore interface{}, onUpdateHook interface{}) *MockStore_ReadStoreDoc_Call { - return &MockStore_ReadStoreDoc_Call{Call: _e.mock.On("ReadStoreDoc", ctx, stateStore, onUpdateHook)} +// - params source.ReadStoreDocParams +func (_e *MockStore_Expecter) ReadStoreDoc(ctx interface{}, stateStore interface{}, params interface{}) *MockStore_ReadStoreDoc_Call { + return &MockStore_ReadStoreDoc_Call{Call: _e.mock.On("ReadStoreDoc", ctx, stateStore, params)} } -func (_c *MockStore_ReadStoreDoc_Call) Run(run func(ctx context.Context, stateStore *storestate.StoreState, onUpdateHook func())) *MockStore_ReadStoreDoc_Call { +func (_c *MockStore_ReadStoreDoc_Call) Run(run func(ctx context.Context, stateStore *storestate.StoreState, params source.ReadStoreDocParams)) *MockStore_ReadStoreDoc_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(*storestate.StoreState), args[2].(func())) + run(args[0].(context.Context), args[1].(*storestate.StoreState), args[2].(source.ReadStoreDocParams)) }) return _c } @@ -633,7 +633,7 @@ func (_c *MockStore_ReadStoreDoc_Call) Return(err error) *MockStore_ReadStoreDoc return _c } -func (_c *MockStore_ReadStoreDoc_Call) RunAndReturn(run func(context.Context, *storestate.StoreState, func()) error) *MockStore_ReadStoreDoc_Call { +func (_c *MockStore_ReadStoreDoc_Call) RunAndReturn(run func(context.Context, *storestate.StoreState, source.ReadStoreDocParams) error) *MockStore_ReadStoreDoc_Call { _c.Call.Return(run) return _c } diff --git a/core/block/source/sourceimpl/source.go b/core/block/source/sourceimpl/source.go index 54020eb17..1a34c975b 100644 --- a/core/block/source/sourceimpl/source.go +++ b/core/block/source/sourceimpl/source.go @@ -284,6 +284,16 @@ func (s *treeSource) buildState() (doc state.Doc, err error) { } st.BlocksInit(st) + // This is temporary migration. We will move it to persistent migration later after several releases. + // The reason is to minimize the number of glitches for users of both old and new versions of Anytype. + // For example, if we persist this migration for Dataview block now, user will see "No query selected" + // error in the old version of Anytype. We want to avoid this as much as possible by making this migration + // temporary, though the applying change to this Dataview block will persist this migration, breaking backward + // compatibility. But in many cases we expect that users update object not so often as they just view them. + // TODO: we can skip migration for non-personal spaces + migration := source.NewSubObjectsAndProfileLinksMigration(s.smartblockType, s.space, s.accountService.MyParticipantId(s.spaceID), s.objectStore) + migration.Migrate(st) + // we need to have required internal relations for all objects, including system st.AddBundledRelationLinks(bundle.RequiredInternalRelations...) if s.Type() == smartblock.SmartBlockTypePage || s.Type() == smartblock.SmartBlockTypeProfilePage { @@ -569,7 +579,9 @@ func BuildState(spaceId string, initState *state.State, ot objecttree.ReadableOb lastChange = change // that means that we are starting from tree root if change.Id == ot.Id() { - if uniqueKeyInternalKey != "" { + if st != nil { + st = st.NewState() + } else if uniqueKeyInternalKey != "" { st = newState(st, state.NewDocWithInternalKey(ot.Id(), nil, uniqueKeyInternalKey).(*state.State)) } else { st = newState(st, state.NewDoc(ot.Id(), nil).(*state.State)) diff --git a/core/block/source/sourceimpl/store.go b/core/block/source/sourceimpl/store.go index 4cb0e8b4f..c3fe71ee0 100644 --- a/core/block/source/sourceimpl/store.go +++ b/core/block/source/sourceimpl/store.go @@ -128,6 +128,7 @@ func (s *store) InitDiffManager(ctx context.Context, name string, seenHeads []st if err != nil { return fmt.Errorf("init diff manager: %w", err) } + manager.diffManager.Init() err = s.getTechSpace().KeyValueService().SubscribeForKey(s.seenHeadsKey(name), name, func(key string, val keyvalueservice.Value) { s.ObjectTree.Lock() @@ -182,8 +183,8 @@ func (s *store) PushChange(params source.PushChangeParams) (id string, err error return "", nil } -func (s *store) ReadStoreDoc(ctx context.Context, storeState *storestate.StoreState, onUpdateHook func()) (err error) { - s.onUpdateHook = onUpdateHook +func (s *store) ReadStoreDoc(ctx context.Context, storeState *storestate.StoreState, params source.ReadStoreDocParams) (err error) { + s.onUpdateHook = params.OnUpdateHook s.store = storeState tx, err := s.store.NewTx(ctx) @@ -199,6 +200,7 @@ func (s *store) ReadStoreDoc(ctx context.Context, storeState *storestate.StoreSt tx: tx, allIsNew: allIsNew, ot: s.ObjectTree, + hook: params.ReadStoreTreeHook, } if err = applier.Apply(); err != nil { return errors.Join(tx.Rollback(), err) @@ -212,6 +214,13 @@ func (s *store) ReadStoreDoc(ctx context.Context, storeState *storestate.StoreSt if err != nil { return fmt.Errorf("init diff managers: %w", err) } + + if params.ReadStoreTreeHook != nil { + err = params.ReadStoreTreeHook.AfterDiffManagersInit(ctx) + if err != nil { + return fmt.Errorf("after diff managers init hook: %w", err) + } + } return nil } diff --git a/core/block/source/sourceimpl/store_apply.go b/core/block/source/sourceimpl/store_apply.go index 5cede640b..8bb335a6b 100644 --- a/core/block/source/sourceimpl/store_apply.go +++ b/core/block/source/sourceimpl/store_apply.go @@ -8,6 +8,7 @@ import ( "github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto" "github.com/anyproto/anytype-heart/core/block/editor/storestate" + "github.com/anyproto/anytype-heart/core/block/source" "github.com/anyproto/anytype-heart/pb" ) @@ -17,17 +18,26 @@ type storeApply struct { allIsNew bool needFetchPrevOrderId bool + hook source.ReadStoreTreeHook } func (a *storeApply) Apply() error { var lastErr error + if a.hook != nil { + a.hook.BeforeIteration(a.ot) + } + err := a.ot.IterateRoot(UnmarshalStoreChange, func(change *objecttree.Change) bool { // not a new change - remember and continue if !a.allIsNew && !change.IsNew { return true } + if a.hook != nil { + a.hook.OnIteration(a.ot, change) + } + lastErr = a.applyChange(change) if lastErr != nil { return false diff --git a/core/block/source/sub_object_links_migration.go b/core/block/source/sub_object_links_migration.go new file mode 100644 index 000000000..14d334408 --- /dev/null +++ b/core/block/source/sub_object_links_migration.go @@ -0,0 +1,237 @@ +package source + +import ( + "context" + "fmt" + "strings" + + "github.com/globalsign/mgo/bson" + "github.com/gogo/protobuf/types" + + "github.com/anyproto/anytype-heart/core/block/editor/state" + "github.com/anyproto/anytype-heart/core/block/simple" + dataview2 "github.com/anyproto/anytype-heart/core/block/simple/dataview" + "github.com/anyproto/anytype-heart/core/domain" + "github.com/anyproto/anytype-heart/pkg/lib/bundle" + "github.com/anyproto/anytype-heart/pkg/lib/core/smartblock" + "github.com/anyproto/anytype-heart/pkg/lib/localstore/addr" + "github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex" + "github.com/anyproto/anytype-heart/pkg/lib/logging" + "github.com/anyproto/anytype-heart/pkg/lib/pb/model" + "github.com/anyproto/anytype-heart/util/pbtypes" +) + +var log = logging.Logger("anytype-mw-source-migration") + +// Migrate old relation (rel-name, etc.) and object type (ot-page, etc.) IDs to new ones (just ordinary object IDs) +// Those old ids are ids of sub-objects, legacy system for storing types and relations inside workspace object +type subObjectsAndProfileLinksMigration struct { + profileID string + identityObjectID string + sbType smartblock.SmartBlockType + space Space + objectStore spaceindex.Store +} + +func NewSubObjectsAndProfileLinksMigration(sbType smartblock.SmartBlockType, space Space, identityObjectID string, objectStore spaceindex.Store) *subObjectsAndProfileLinksMigration { + return &subObjectsAndProfileLinksMigration{ + space: space, + identityObjectID: identityObjectID, + sbType: sbType, + objectStore: objectStore, + } +} + +func (m *subObjectsAndProfileLinksMigration) replaceLinksInDetails(s *state.State) { + for _, rel := range s.GetRelationLinks() { + if rel.Key == bundle.RelationKeyFeaturedRelations.String() { + continue + } + if rel.Key == bundle.RelationKeySourceObject.String() { + // migrate broken sourceObject after v0.29.11 + // todo: remove this + if s.UniqueKeyInternal() == "" { + continue + } + + internalKey := s.UniqueKeyInternal() + switch m.sbType { + case smartblock.SmartBlockTypeRelation: + if bundle.HasRelation(domain.RelationKey(internalKey)) { + s.SetDetail(bundle.RelationKeySourceObject, domain.String(domain.RelationKey(internalKey).BundledURL())) + } + case smartblock.SmartBlockTypeObjectType: + if bundle.HasObjectTypeByKey(domain.TypeKey(internalKey)) { + s.SetDetail(bundle.RelationKeySourceObject, domain.String(domain.TypeKey(internalKey).BundledURL())) + } + + } + + continue + } + if m.canRelationContainObjectValues(rel.Format) { + rawValue := s.Details().Get(domain.RelationKey(rel.Key)) + + if oldId := rawValue.String(); oldId != "" { + newId := m.migrateId(oldId) + if oldId != newId { + s.SetDetail(domain.RelationKey(rel.Key), domain.String(newId)) + } + } else if ids := rawValue.StringList(); len(ids) > 0 { + changed := false + for i, oldId := range ids { + newId := m.migrateId(oldId) + if oldId != newId { + ids[i] = newId + changed = true + } + } + if changed { + s.SetDetail(domain.RelationKey(rel.Key), domain.StringList(ids)) + } + } + } + } +} + +// Migrate works only in personal space +func (m *subObjectsAndProfileLinksMigration) Migrate(s *state.State) { + if !m.space.IsPersonal() { + return + } + + uk, err := domain.NewUniqueKey(smartblock.SmartBlockTypeProfilePage, "") + if err != nil { + log.Errorf("migration: failed to create unique key for profile: %s", err) + } else { + // this way we will get incorrect profileID for non-personal spaces, but we are not migrating them + id, err := m.space.DeriveObjectID(context.Background(), uk) + if err != nil { + log.Errorf("migration: failed to derive id for profile: %s", err) + } else { + m.profileID = id + } + } + + m.replaceLinksInDetails(s) + + s.Iterate(func(block simple.Block) bool { + if block.Model().GetDataview() != nil { + // Mark block as mutable + dv := s.Get(block.Model().Id).(dataview2.Block) + m.migrateFilters(dv) + } + + if _, ok := block.(simple.ObjectLinkReplacer); ok { + // Mark block as mutable + b := s.Get(block.Model().Id) + replacer := b.(simple.ObjectLinkReplacer) + replacer.ReplaceLinkIds(m.migrateId) + } + + return true + }) +} + +func (m *subObjectsAndProfileLinksMigration) migrateId(oldId string) (newId string) { + if m.profileID != "" && m.identityObjectID != "" { + // we substitute all links to profile object with space member object + if oldId == m.profileID || + strings.HasPrefix(oldId, "_id_") { // we don't need to check the exact accountID here, because we only have links to our own identity + return m.identityObjectID + } + } + uniqueKey, valid := subObjectIdToUniqueKey(oldId) + if !valid { + return oldId + } + + newId, err := m.space.DeriveObjectID(context.Background(), uniqueKey) + if err != nil { + log.With("uniqueKey", uniqueKey.Marshal()).Errorf("failed to derive id: %s", err) + return oldId + } + return newId +} + +// subObjectIdToUniqueKey converts legacy sub-object id to uniqueKey +// if id is not supported subObjectId, it will return nil, false +// suppose to be used only for migration and almost free to use +func subObjectIdToUniqueKey(id string) (uniqueKey domain.UniqueKey, valid bool) { + // historically, we don't have the prefix for the options, + // so we need to handled it this ugly way + if bson.IsObjectIdHex(id) { + return domain.MustUniqueKey(smartblock.SmartBlockTypeRelationOption, id), true + } + // special case: we don't support bundled relations/types in uniqueKeys (GO-2394). So in case we got it, we need to replace the prefix + if strings.HasPrefix(id, addr.BundledObjectTypeURLPrefix) { + id = addr.ObjectTypeKeyToIdPrefix + strings.TrimPrefix(id, addr.BundledObjectTypeURLPrefix) + } else if strings.HasPrefix(id, addr.BundledRelationURLPrefix) { + id = addr.RelationKeyToIdPrefix + strings.TrimPrefix(id, addr.BundledRelationURLPrefix) + } + uniqueKey, err := domain.UnmarshalUniqueKey(id) + if err != nil { + return nil, false + } + return uniqueKey, true +} + +func (m *subObjectsAndProfileLinksMigration) migrateFilters(dv dataview2.Block) { + for _, view := range dv.Model().GetDataview().GetViews() { + for _, filter := range view.GetFilters() { + err := m.migrateFilter(filter) + if err != nil { + log.Errorf("failed to migrate filter %s: %s", filter.Id, err) + } + } + } +} + +func (m *subObjectsAndProfileLinksMigration) migrateFilter(filter *model.BlockContentDataviewFilter) error { + if filter == nil { + return nil + } + if filter.Value == nil || filter.Value.Kind == nil { + log.With("relationKey", filter.RelationKey).Warnf("empty filter value") + return nil + } + relation, err := m.objectStore.GetRelationByKey(filter.RelationKey) + if err != nil { + log.Warnf("migration: failed to get relation by key %s: %s", filter.RelationKey, err) + } + + // TODO: check this logic + // here we use objectstore to get relation, but it may be not yet available + // In case it is missing, lets try to migrate any string/stringlist: it should ignore invalid strings + if relation == nil || m.canRelationContainObjectValues(relation.Format) { + switch v := filter.Value.Kind.(type) { + case *types.Value_StringValue: + filter.Value = pbtypes.String(m.migrateId(v.StringValue)) + case *types.Value_ListValue: + newIDs := make([]string, 0, len(v.ListValue.Values)) + + for _, oldID := range v.ListValue.Values { + if id, ok := oldID.Kind.(*types.Value_StringValue); ok { + newIDs = append(newIDs, m.migrateId(id.StringValue)) + } else { + return fmt.Errorf("migration: failed to migrate filter: invalid list item value kind %t", oldID.Kind) + } + } + + filter.Value = pbtypes.StringList(newIDs) + } + } + return nil +} + +func (m *subObjectsAndProfileLinksMigration) canRelationContainObjectValues(format model.RelationFormat) bool { + switch format { + case + model.RelationFormat_status, + model.RelationFormat_tag, + model.RelationFormat_object: + return true + default: + return false + } +} diff --git a/core/block/source/sub_object_links_migration_test.go b/core/block/source/sub_object_links_migration_test.go new file mode 100644 index 000000000..baa4fbc12 --- /dev/null +++ b/core/block/source/sub_object_links_migration_test.go @@ -0,0 +1,55 @@ +package source + +import ( + "testing" + + "github.com/anyproto/anytype-heart/core/domain" +) + +func TestSubObjectIdToUniqueKey(t *testing.T) { + type args struct { + id string + } + tests := []struct { + name string + args args + wantUk string + wantValid bool + }{ + {"relation", args{"rel-id"}, "rel-id", true}, + {"type", args{"ot-task"}, "ot-task", true}, + {"opt", args{"650832666293ae9ae67e5f9c"}, "opt-650832666293ae9ae67e5f9c", true}, + {"invalid-prefix", args{"aa-task"}, "", false}, + {"no-key", args{"rel"}, "", false}, + {"no-key2", args{"rel-"}, "", false}, + {"no-key2", args{"rel---gdfgfd--gfdgfd-"}, "", false}, + {"invalid", args{"task"}, "", false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotUk, gotValid := subObjectIdToUniqueKey(tt.args.id) + if gotValid != tt.wantValid { + t.Errorf("SubObjectIdToUniqueKey() gotValid = %v, want %v", gotValid, tt.wantValid) + t.Fail() + } + + if !tt.wantValid { + return + } + + wantUk, err := domain.UnmarshalUniqueKey(tt.wantUk) + if err != nil { + t.Errorf("SubObjectIdToUniqueKey() error = %v", err) + t.Fail() + } + if wantUk.Marshal() != gotUk.Marshal() { + t.Errorf("SubObjectIdToUniqueKey() gotUk = %v, want %v", gotUk, tt.wantUk) + t.Fail() + } + if wantUk.SmartblockType() != gotUk.SmartblockType() { + t.Errorf("SubObjectIdToUniqueKey() gotSmartblockType = %v, want %v", gotUk.SmartblockType(), wantUk.SmartblockType()) + t.Fail() + } + }) + } +} diff --git a/core/chats.go b/core/chats.go index de8329891..368decb14 100644 --- a/core/chats.go +++ b/core/chats.go @@ -8,7 +8,8 @@ import ( "github.com/gogo/protobuf/types" "github.com/anyproto/anytype-heart/core/block/chats" - "github.com/anyproto/anytype-heart/core/block/editor/chatobject" + "github.com/anyproto/anytype-heart/core/block/chats/chatmodel" + "github.com/anyproto/anytype-heart/core/block/chats/chatrepository" "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) @@ -17,7 +18,7 @@ func (mw *Middleware) ChatAddMessage(cctx context.Context, req *pb.RpcChatAddMes ctx := mw.newContext(cctx) chatService := mustService[chats.Service](mw) - messageId, err := chatService.AddMessage(cctx, ctx, req.ChatObjectId, &chatobject.Message{ChatMessage: req.Message}) + messageId, err := chatService.AddMessage(cctx, ctx, req.ChatObjectId, &chatmodel.Message{ChatMessage: req.Message}) if err != nil { code := mapErrorCode[pb.RpcChatAddMessageResponseErrorCode](err) return &pb.RpcChatAddMessageResponse{ @@ -36,7 +37,7 @@ func (mw *Middleware) ChatAddMessage(cctx context.Context, req *pb.RpcChatAddMes func (mw *Middleware) ChatEditMessageContent(cctx context.Context, req *pb.RpcChatEditMessageContentRequest) *pb.RpcChatEditMessageContentResponse { chatService := mustService[chats.Service](mw) - err := chatService.EditMessage(cctx, req.ChatObjectId, req.MessageId, &chatobject.Message{ChatMessage: req.EditedMessage}) + err := chatService.EditMessage(cctx, req.ChatObjectId, req.MessageId, &chatmodel.Message{ChatMessage: req.EditedMessage}) if err != nil { code := mapErrorCode[pb.RpcChatEditMessageContentResponseErrorCode](err) return &pb.RpcChatEditMessageContentResponse{ @@ -84,7 +85,7 @@ func (mw *Middleware) ChatDeleteMessage(cctx context.Context, req *pb.RpcChatDel func (mw *Middleware) ChatGetMessages(cctx context.Context, req *pb.RpcChatGetMessagesRequest) *pb.RpcChatGetMessagesResponse { chatService := mustService[chats.Service](mw) - resp, err := chatService.GetMessages(cctx, req.ChatObjectId, chatobject.GetMessagesRequest{ + resp, err := chatService.GetMessages(cctx, req.ChatObjectId, chatrepository.GetMessagesRequest{ AfterOrderId: req.AfterOrderId, BeforeOrderId: req.BeforeOrderId, Limit: int(req.Limit), @@ -226,7 +227,7 @@ func (mw *Middleware) ChatReadMessages(cctx context.Context, request *pb.RpcChat AfterOrderId: request.AfterOrderId, BeforeOrderId: request.BeforeOrderId, LastStateId: request.LastStateId, - CounterType: chatobject.CounterType(request.Type), + CounterType: chatmodel.CounterType(request.Type), }) if err != nil { code := mapErrorCode(err, @@ -244,7 +245,7 @@ func (mw *Middleware) ChatReadMessages(cctx context.Context, request *pb.RpcChat func (mw *Middleware) ChatUnreadMessages(cctx context.Context, request *pb.RpcChatUnreadRequest) *pb.RpcChatUnreadResponse { chatService := mustService[chats.Service](mw) - err := chatService.UnreadMessages(cctx, request.ChatObjectId, request.AfterOrderId, chatobject.CounterType(request.Type)) + err := chatService.UnreadMessages(cctx, request.ChatObjectId, request.AfterOrderId, chatmodel.CounterType(request.Type)) if err != nil { code := mapErrorCode[pb.RpcChatUnreadResponseErrorCode](err) return &pb.RpcChatUnreadResponse{ @@ -257,10 +258,26 @@ func (mw *Middleware) ChatUnreadMessages(cctx context.Context, request *pb.RpcCh return &pb.RpcChatUnreadResponse{} } -func messagesToProto(msgs []*chatobject.Message) []*model.ChatMessage { +func messagesToProto(msgs []*chatmodel.Message) []*model.ChatMessage { res := make([]*model.ChatMessage, 0, len(msgs)) for _, msg := range msgs { res = append(res, msg.ChatMessage) } return res } + +func (mw *Middleware) ChatReadAll(cctx context.Context, req *pb.RpcChatReadAllRequest) *pb.RpcChatReadAllResponse { + chatService := mustService[chats.Service](mw) + + err := chatService.ReadAll(cctx) + if err != nil { + code := mapErrorCode[pb.RpcChatReadAllResponseErrorCode](err) + return &pb.RpcChatReadAllResponse{ + Error: &pb.RpcChatReadAllResponseError{ + Code: code, + Description: getErrorDescription(err), + }, + } + } + return &pb.RpcChatReadAllResponse{} +} diff --git a/core/debug/exporter/exporter.go b/core/debug/exporter/exporter.go index c4665cb69..6ece646cf 100644 --- a/core/debug/exporter/exporter.go +++ b/core/debug/exporter/exporter.go @@ -5,15 +5,37 @@ import ( "fmt" anystore "github.com/anyproto/any-store" + "github.com/anyproto/any-sync/app" "github.com/anyproto/any-sync/commonspace/headsync/headstorage" "github.com/anyproto/any-sync/commonspace/object/accountdata" "github.com/anyproto/any-sync/commonspace/object/acl/list" + "github.com/anyproto/any-sync/commonspace/object/acl/recordverifier" "github.com/anyproto/any-sync/commonspace/object/tree/objecttree" "github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto" + "github.com/anyproto/any-sync/consensus/consensusproto" "github.com/anyproto/any-sync/util/crypto" "golang.org/x/exp/slices" ) +type recordVerifier struct { +} + +func (r recordVerifier) Init(a *app.App) (err error) { + return nil +} + +func (r recordVerifier) Name() (name string) { + return recordverifier.CName +} + +func (r recordVerifier) VerifyAcceptor(rec *consensusproto.RawRecord) (err error) { + return nil +} + +func (r recordVerifier) ShouldValidate() bool { + return false +} + type DataConverter interface { Unmarshall(dataType string, decrypted []byte) (any, error) Marshall(model any) (data []byte, dataType string, err error) @@ -34,7 +56,7 @@ func prepareExport(ctx context.Context, readable objecttree.ReadableObjectTree, if err != nil { return nil, err } - newAcl, err := list.BuildAclListWithIdentity(keys, listStorage, list.NoOpAcceptorVerifier{}) + newAcl, err := list.BuildAclListWithIdentity(keys, listStorage, recordVerifier{}) if err != nil { return nil, err } diff --git a/core/debug/exporter/importer.go b/core/debug/exporter/importer.go index a01b18a29..d4aeb84a0 100644 --- a/core/debug/exporter/importer.go +++ b/core/debug/exporter/importer.go @@ -80,7 +80,7 @@ func ImportStorage(ctx context.Context, path string) (res ImportResult, err erro if err != nil { return } - acl, err := list.BuildAclListWithIdentity(randomKeys, listStorage, list.NoOpAcceptorVerifier{}) + acl, err := list.BuildAclListWithIdentity(randomKeys, listStorage, recordVerifier{}) if err != nil { return } diff --git a/core/domain/app.go b/core/domain/app.go new file mode 100644 index 000000000..676e46875 --- /dev/null +++ b/core/domain/app.go @@ -0,0 +1,11 @@ +package domain + +import "github.com/anyproto/anytype-heart/pb" + +type CompState int + +const ( + CompStateAppWentBackground CompState = CompState(pb.RpcAppSetDeviceStateRequest_BACKGROUND) // 0 + CompStateAppWentForeground CompState = CompState(pb.RpcAppSetDeviceStateRequest_FOREGROUND) // 1 + CompStateAppClosingInitiated CompState = 2 // triggered by app +) diff --git a/core/domain/invite.go b/core/domain/invite.go index 1b86d061d..6b58dce9c 100644 --- a/core/domain/invite.go +++ b/core/domain/invite.go @@ -1,5 +1,12 @@ package domain +import ( + "github.com/anyproto/any-sync/commonspace/object/acl/aclrecordproto" + "github.com/anyproto/any-sync/commonspace/object/acl/list" + + "github.com/anyproto/anytype-heart/pkg/lib/pb/model" +) + type InviteView struct { SpaceId string SpaceName string @@ -7,6 +14,7 @@ type InviteView struct { CreatorName string AclKey []byte GuestKey []byte + InviteType InviteType } func (i InviteView) IsGuestUserInvite() bool { @@ -16,16 +24,50 @@ func (i InviteView) IsGuestUserInvite() bool { return false } +type InviteType int + +const ( + InviteTypeDefault InviteType = iota + InviteTypeGuest + InviteTypeAnyone +) + type InviteInfo struct { InviteFileCid string InviteFileKey string + InviteType InviteType + Permissions list.AclPermissions } type InviteObject interface { - SetInviteFileInfo(fileCid string, fileKey string) (err error) - GetExistingInviteInfo() (fileCid string, fileKey string) - RemoveExistingInviteInfo() (fileCid string, err error) + SetInviteFileInfo(inviteInfo InviteInfo) (err error) + GetExistingInviteInfo() InviteInfo + RemoveExistingInviteInfo() (InviteInfo, error) SetGuestInviteFileInfo(fileCid string, fileKey string) (err error) GetExistingGuestInviteInfo() (fileCid string, fileKey string) } + +func ConvertParticipantPermissions(permissions model.ParticipantPermissions) list.AclPermissions { + switch permissions { + case model.ParticipantPermissions_Writer: + return list.AclPermissionsWriter + case model.ParticipantPermissions_Reader: + return list.AclPermissionsReader + case model.ParticipantPermissions_Owner: + return list.AclPermissionsOwner + } + return list.AclPermissionsNone +} + +func ConvertAclPermissions(permissions list.AclPermissions) model.ParticipantPermissions { + switch aclrecordproto.AclUserPermissions(permissions) { + case aclrecordproto.AclUserPermissions_Writer: + return model.ParticipantPermissions_Writer + case aclrecordproto.AclUserPermissions_Reader: + return model.ParticipantPermissions_Reader + case aclrecordproto.AclUserPermissions_Owner: + return model.ParticipantPermissions_Owner + } + return model.ParticipantPermissions_NoPermissions +} diff --git a/core/domain/mock_domain/mock_InviteObject.go b/core/domain/mock_domain/mock_InviteObject.go index 623cd8e45..c45eaa009 100644 --- a/core/domain/mock_domain/mock_InviteObject.go +++ b/core/domain/mock_domain/mock_InviteObject.go @@ -2,7 +2,10 @@ package mock_domain -import mock "github.com/stretchr/testify/mock" +import ( + domain "github.com/anyproto/anytype-heart/core/domain" + mock "github.com/stretchr/testify/mock" +) // MockInviteObject is an autogenerated mock type for the InviteObject type type MockInviteObject struct { @@ -73,31 +76,21 @@ func (_c *MockInviteObject_GetExistingGuestInviteInfo_Call) RunAndReturn(run fun } // GetExistingInviteInfo provides a mock function with given fields: -func (_m *MockInviteObject) GetExistingInviteInfo() (string, string) { +func (_m *MockInviteObject) GetExistingInviteInfo() domain.InviteInfo { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for GetExistingInviteInfo") } - var r0 string - var r1 string - if rf, ok := ret.Get(0).(func() (string, string)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { + var r0 domain.InviteInfo + if rf, ok := ret.Get(0).(func() domain.InviteInfo); ok { r0 = rf() } else { - r0 = ret.Get(0).(string) + r0 = ret.Get(0).(domain.InviteInfo) } - if rf, ok := ret.Get(1).(func() string); ok { - r1 = rf() - } else { - r1 = ret.Get(1).(string) - } - - return r0, r1 + return r0 } // MockInviteObject_GetExistingInviteInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExistingInviteInfo' @@ -117,33 +110,33 @@ func (_c *MockInviteObject_GetExistingInviteInfo_Call) Run(run func()) *MockInvi return _c } -func (_c *MockInviteObject_GetExistingInviteInfo_Call) Return(fileCid string, fileKey string) *MockInviteObject_GetExistingInviteInfo_Call { - _c.Call.Return(fileCid, fileKey) +func (_c *MockInviteObject_GetExistingInviteInfo_Call) Return(_a0 domain.InviteInfo) *MockInviteObject_GetExistingInviteInfo_Call { + _c.Call.Return(_a0) return _c } -func (_c *MockInviteObject_GetExistingInviteInfo_Call) RunAndReturn(run func() (string, string)) *MockInviteObject_GetExistingInviteInfo_Call { +func (_c *MockInviteObject_GetExistingInviteInfo_Call) RunAndReturn(run func() domain.InviteInfo) *MockInviteObject_GetExistingInviteInfo_Call { _c.Call.Return(run) return _c } // RemoveExistingInviteInfo provides a mock function with given fields: -func (_m *MockInviteObject) RemoveExistingInviteInfo() (string, error) { +func (_m *MockInviteObject) RemoveExistingInviteInfo() (domain.InviteInfo, error) { ret := _m.Called() if len(ret) == 0 { panic("no return value specified for RemoveExistingInviteInfo") } - var r0 string + var r0 domain.InviteInfo var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { + if rf, ok := ret.Get(0).(func() (domain.InviteInfo, error)); ok { return rf() } - if rf, ok := ret.Get(0).(func() string); ok { + if rf, ok := ret.Get(0).(func() domain.InviteInfo); ok { r0 = rf() } else { - r0 = ret.Get(0).(string) + r0 = ret.Get(0).(domain.InviteInfo) } if rf, ok := ret.Get(1).(func() error); ok { @@ -172,12 +165,12 @@ func (_c *MockInviteObject_RemoveExistingInviteInfo_Call) Run(run func()) *MockI return _c } -func (_c *MockInviteObject_RemoveExistingInviteInfo_Call) Return(fileCid string, err error) *MockInviteObject_RemoveExistingInviteInfo_Call { - _c.Call.Return(fileCid, err) +func (_c *MockInviteObject_RemoveExistingInviteInfo_Call) Return(_a0 domain.InviteInfo, _a1 error) *MockInviteObject_RemoveExistingInviteInfo_Call { + _c.Call.Return(_a0, _a1) return _c } -func (_c *MockInviteObject_RemoveExistingInviteInfo_Call) RunAndReturn(run func() (string, error)) *MockInviteObject_RemoveExistingInviteInfo_Call { +func (_c *MockInviteObject_RemoveExistingInviteInfo_Call) RunAndReturn(run func() (domain.InviteInfo, error)) *MockInviteObject_RemoveExistingInviteInfo_Call { _c.Call.Return(run) return _c } @@ -229,17 +222,17 @@ func (_c *MockInviteObject_SetGuestInviteFileInfo_Call) RunAndReturn(run func(st return _c } -// SetInviteFileInfo provides a mock function with given fields: fileCid, fileKey -func (_m *MockInviteObject) SetInviteFileInfo(fileCid string, fileKey string) error { - ret := _m.Called(fileCid, fileKey) +// SetInviteFileInfo provides a mock function with given fields: inviteInfo +func (_m *MockInviteObject) SetInviteFileInfo(inviteInfo domain.InviteInfo) error { + ret := _m.Called(inviteInfo) if len(ret) == 0 { panic("no return value specified for SetInviteFileInfo") } var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(fileCid, fileKey) + if rf, ok := ret.Get(0).(func(domain.InviteInfo) error); ok { + r0 = rf(inviteInfo) } else { r0 = ret.Error(0) } @@ -253,15 +246,14 @@ type MockInviteObject_SetInviteFileInfo_Call struct { } // SetInviteFileInfo is a helper method to define mock.On call -// - fileCid string -// - fileKey string -func (_e *MockInviteObject_Expecter) SetInviteFileInfo(fileCid interface{}, fileKey interface{}) *MockInviteObject_SetInviteFileInfo_Call { - return &MockInviteObject_SetInviteFileInfo_Call{Call: _e.mock.On("SetInviteFileInfo", fileCid, fileKey)} +// - inviteInfo domain.InviteInfo +func (_e *MockInviteObject_Expecter) SetInviteFileInfo(inviteInfo interface{}) *MockInviteObject_SetInviteFileInfo_Call { + return &MockInviteObject_SetInviteFileInfo_Call{Call: _e.mock.On("SetInviteFileInfo", inviteInfo)} } -func (_c *MockInviteObject_SetInviteFileInfo_Call) Run(run func(fileCid string, fileKey string)) *MockInviteObject_SetInviteFileInfo_Call { +func (_c *MockInviteObject_SetInviteFileInfo_Call) Run(run func(inviteInfo domain.InviteInfo)) *MockInviteObject_SetInviteFileInfo_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) + run(args[0].(domain.InviteInfo)) }) return _c } @@ -271,7 +263,7 @@ func (_c *MockInviteObject_SetInviteFileInfo_Call) Return(err error) *MockInvite return _c } -func (_c *MockInviteObject_SetInviteFileInfo_Call) RunAndReturn(run func(string, string) error) *MockInviteObject_SetInviteFileInfo_Call { +func (_c *MockInviteObject_SetInviteFileInfo_Call) RunAndReturn(run func(domain.InviteInfo) error) *MockInviteObject_SetInviteFileInfo_Call { _c.Call.Return(run) return _c } diff --git a/core/indexer/fulltext.go b/core/indexer/fulltext.go index d5ab72bd9..8ccb0cc80 100644 --- a/core/indexer/fulltext.go +++ b/core/indexer/fulltext.go @@ -45,10 +45,10 @@ func (i *indexer) ForceFTIndex() { // ftLoop runs full-text indexer // MUST NOT be called more than once -func (i *indexer) ftLoopRoutine() { +func (i *indexer) ftLoopRoutine(ctx context.Context) { tickerDuration := ftIndexInterval ticker := time.NewTicker(tickerDuration) - ctx := i.runCtx + prevError := i.runFullTextIndexer(ctx) defer close(i.ftQueueFinished) var lastForceIndex time.Time diff --git a/core/indexer/indexer.go b/core/indexer/indexer.go index 16e9015e5..615532b97 100644 --- a/core/indexer/indexer.go +++ b/core/indexer/indexer.go @@ -32,7 +32,7 @@ const ( var log = logging.Logger("anytype-doc-indexer") func New() Indexer { - return &indexer{} + return new(indexer) } type Indexer interface { @@ -59,6 +59,7 @@ type indexer struct { runCtx context.Context runCtxCancel context.CancelFunc + ftQueueStop context.CancelFunc ftQueueFinished chan struct{} config *config.Config @@ -98,12 +99,20 @@ func (i *indexer) Run(context.Context) (err error) { return i.StartFullTextIndex() } +func (f *indexer) StateChange(state int) { + if state == int(domain.CompStateAppClosingInitiated) && f.ftQueueStop != nil { + f.ftQueueStop() + } +} + func (i *indexer) StartFullTextIndex() (err error) { if ftErr := i.ftInit(); ftErr != nil { log.Errorf("can't init ft: %v", ftErr) } i.ftQueueFinished = make(chan struct{}) - go i.ftLoopRoutine() + var ftCtx context.Context + ftCtx, i.ftQueueStop = context.WithCancel(i.runCtx) + go i.ftLoopRoutine(ftCtx) return } diff --git a/core/indexer/reindex.go b/core/indexer/reindex.go index 5722925b8..7083e275a 100644 --- a/core/indexer/reindex.go +++ b/core/indexer/reindex.go @@ -51,7 +51,7 @@ const ( ForceReindexDeletedObjectsCounter int32 = 1 ForceReindexParticipantsCounter int32 = 1 - ForceReindexChatsCounter int32 = 1 + ForceReindexChatsCounter int32 = 3 ) type allDeletedIdsProvider interface { @@ -242,7 +242,10 @@ func (i *indexer) reindexChats(ctx context.Context, space clientspace.Space) err if len(ids) == 0 { return nil } - db := i.store.GetCrdtDb(space.Id()) + db, err := i.store.GetCrdtDb(space.Id()).Wait() + if err != nil { + return fmt.Errorf("get crdt db: %w", err) + } txn, err := db.WriteTx(ctx) if err != nil { @@ -286,6 +289,8 @@ func (i *indexer) reindexChats(ctx context.Context, space clientspace.Space) err return fmt.Errorf("commit: %w", err) } + i.reindexIdsIgnoreErr(ctx, space, ids...) + return nil } diff --git a/core/inviteservice/inviteservice.go b/core/inviteservice/inviteservice.go index ccd7f6e06..f79de3ce0 100644 --- a/core/inviteservice/inviteservice.go +++ b/core/inviteservice/inviteservice.go @@ -6,6 +6,7 @@ import ( "github.com/anyproto/any-sync/app" "github.com/anyproto/any-sync/app/logger" + "github.com/anyproto/any-sync/commonspace/object/acl/list" "github.com/anyproto/any-sync/util/crypto" "github.com/gogo/protobuf/proto" "github.com/ipfs/go-cid" @@ -32,7 +33,8 @@ type InviteService interface { GetPayload(ctx context.Context, inviteCid cid.Cid, inviteFileKey crypto.SymKey) (*model.InvitePayload, error) View(ctx context.Context, inviteCid cid.Cid, inviteFileKey crypto.SymKey) (domain.InviteView, error) RemoveExisting(ctx context.Context, spaceId string) error - Generate(ctx context.Context, spaceId string, inviteKey crypto.PrivKey, sendInvite func() error) (domain.InviteInfo, error) + Generate(ctx context.Context, params GenerateInviteParams, sendInvite func() error) (domain.InviteInfo, error) + Change(ctx context.Context, spaceId string, permissions list.AclPermissions) error GetCurrent(ctx context.Context, spaceId string) (domain.InviteInfo, error) GetExistingGuestUserInvite(ctx context.Context, spaceId string) (domain.InviteInfo, error) GenerateGuestUserInvite(ctx context.Context, spaceId string, guestKey crypto.PrivKey) (domain.InviteInfo, error) @@ -42,6 +44,13 @@ var _ InviteService = (*inviteService)(nil) var ErrInvalidSpaceType = fmt.Errorf("invalid space type") +type GenerateInviteParams struct { + SpaceId string + Key crypto.PrivKey + InviteType domain.InviteType + Permissions list.AclPermissions +} + type inviteService struct { inviteStore invitestore.Service fileAcl fileacl.Service @@ -85,64 +94,47 @@ func (i *inviteService) View(ctx context.Context, inviteCid cid.Cid, inviteFileK CreatorName: invitePayload.CreatorName, AclKey: invitePayload.AclKey, GuestKey: invitePayload.GuestKey, + InviteType: domain.InviteType(invitePayload.InviteType), }, nil } -func (i *inviteService) GetCurrent(ctx context.Context, spaceId string) (info domain.InviteInfo, err error) { - var ( - fileCid, fileKey string - ) - // this is for migration purposes - err = i.spaceService.TechSpace().DoSpaceView(ctx, spaceId, func(obj techspace.SpaceView) error { - fileCid, fileKey = obj.GetExistingInviteInfo() - if fileCid != "" { - info.InviteFileCid = fileCid - info.InviteFileKey = fileKey - } else { - return nil - } - _, err := obj.RemoveExistingInviteInfo() - if err != nil { - log.Warn("remove existing invite info", zap.Error(err)) - } - return nil +func (i *inviteService) Change(ctx context.Context, spaceId string, permissions list.AclPermissions) error { + return i.doInviteObject(ctx, spaceId, func(obj domain.InviteObject) error { + info := obj.GetExistingInviteInfo() + info.Permissions = permissions + return obj.SetInviteFileInfo(info) }) - if err != nil { - return domain.InviteInfo{}, getInviteError("get existing invite info from space view", err) - } +} + +func (i *inviteService) GetCurrent(ctx context.Context, spaceId string) (info domain.InviteInfo, err error) { err = i.doInviteObject(ctx, spaceId, func(obj domain.InviteObject) error { - if info.InviteFileCid != "" { - return obj.SetInviteFileInfo(info.InviteFileCid, info.InviteFileKey) - } - fileCid, fileKey = obj.GetExistingInviteInfo() + info = obj.GetExistingInviteInfo() return nil }) if err != nil { err = getInviteError("get existing invite info", err) return } - if fileCid == "" { + if info.InviteFileCid == "" { err = ErrInviteNotExists return } - info.InviteFileCid = fileCid - info.InviteFileKey = fileKey return } func (i *inviteService) RemoveExisting(ctx context.Context, spaceId string) (err error) { - var fileCid string + var info domain.InviteInfo err = i.doInviteObject(ctx, spaceId, func(obj domain.InviteObject) error { - fileCid, err = obj.RemoveExistingInviteInfo() + info, err = obj.RemoveExistingInviteInfo() return err }) if err != nil { return removeInviteError("remove existing invite info", err) } - if len(fileCid) == 0 { + if len(info.InviteFileCid) == 0 { return nil } - invCid, err := cid.Decode(fileCid) + invCid, err := cid.Decode(info.InviteFileCid) if err != nil { return removeInviteError("decode invite cid", err) } @@ -171,25 +163,22 @@ func (i *inviteService) GenerateGuestUserInvite(ctx context.Context, spaceId str return i.generateGuestInvite(ctx, spaceId, guestUserKey) } -func (i *inviteService) Generate(ctx context.Context, spaceId string, aclKey crypto.PrivKey, sendInvite func() error) (result domain.InviteInfo, err error) { +func (i *inviteService) Generate(ctx context.Context, params GenerateInviteParams, sendInvite func() error) (result domain.InviteInfo, err error) { + spaceId := params.SpaceId if spaceId == i.accountService.PersonalSpaceID() { return domain.InviteInfo{}, ErrPersonalSpace } - var fileCid, fileKey string err = i.doInviteObject(ctx, spaceId, func(obj domain.InviteObject) error { - fileCid, fileKey = obj.GetExistingInviteInfo() + result = obj.GetExistingInviteInfo() return nil }) if err != nil { return domain.InviteInfo{}, generateInviteError("get existing invite info", err) } - if fileCid != "" { - return domain.InviteInfo{ - InviteFileCid: fileCid, - InviteFileKey: fileKey, - }, nil + if result.InviteFileCid != "" && result.InviteType == params.InviteType { + return result, nil } - invite, err := i.buildInvite(ctx, spaceId, aclKey, nil) + invite, err := i.buildInvite(ctx, params) if err != nil { return domain.InviteInfo{}, generateInviteError("build invite", err) } @@ -208,8 +197,14 @@ func (i *inviteService) Generate(ctx context.Context, spaceId string, aclKey cry removeInviteFile() return domain.InviteInfo{}, generateInviteError("encode invite file key", err) } + inviteInfo := domain.InviteInfo{ + InviteFileCid: inviteFileCid.String(), + InviteFileKey: inviteFileKeyRaw, + InviteType: params.InviteType, + Permissions: params.Permissions, + } err = i.doInviteObject(ctx, spaceId, func(obj domain.InviteObject) error { - return obj.SetInviteFileInfo(inviteFileCid.String(), inviteFileKeyRaw) + return obj.SetInviteFileInfo(inviteInfo) }) if err != nil { removeInviteFile() @@ -223,17 +218,18 @@ func (i *inviteService) Generate(ctx context.Context, spaceId string, aclKey cry } return domain.InviteInfo{}, generateInviteError("send invite", err) } - return domain.InviteInfo{ - InviteFileCid: inviteFileCid.String(), - InviteFileKey: inviteFileKeyRaw, - }, err + return inviteInfo, err } func (i *inviteService) generateGuestInvite(ctx context.Context, spaceId string, guestUserKey crypto.PrivKey) (result domain.InviteInfo, err error) { if spaceId == i.accountService.PersonalSpaceID() { return domain.InviteInfo{}, ErrPersonalSpace } - invite, err := i.buildInvite(ctx, spaceId, nil, guestUserKey) + invite, err := i.buildInvite(ctx, GenerateInviteParams{ + SpaceId: spaceId, + Key: guestUserKey, + InviteType: domain.InviteTypeGuest, + }) if err != nil { return domain.InviteInfo{}, generateInviteError("build invite", err) } @@ -252,6 +248,11 @@ func (i *inviteService) generateGuestInvite(ctx context.Context, spaceId string, removeInviteFile() return domain.InviteInfo{}, generateInviteError("encode invite file key", err) } + inviteInfo := domain.InviteInfo{ + InviteFileCid: inviteFileCid.String(), + InviteFileKey: inviteFileKeyRaw, + InviteType: domain.InviteTypeGuest, + } err = i.doInviteObject(ctx, spaceId, func(obj domain.InviteObject) error { return obj.SetGuestInviteFileInfo(inviteFileCid.String(), inviteFileKeyRaw) }) @@ -260,10 +261,7 @@ func (i *inviteService) generateGuestInvite(ctx context.Context, spaceId string, return domain.InviteInfo{}, generateInviteError("set invite file info", err) } - return domain.InviteInfo{ - InviteFileCid: inviteFileCid.String(), - InviteFileKey: inviteFileKeyRaw, - }, err + return inviteInfo, err } func (i *inviteService) GetPayload(ctx context.Context, inviteCid cid.Cid, inviteFileKey crypto.SymKey) (md *model.InvitePayload, err error) { @@ -294,13 +292,11 @@ func (i *inviteService) GetPayload(ctx context.Context, inviteCid cid.Cid, invit return &invitePayload, nil } -// buildInvite creates invite payload and signs it -// you should provide either aclKey or guestUserKey -func (i *inviteService) buildInvite(ctx context.Context, spaceId string, aclKey, guestUserKey crypto.PrivKey) (*model.Invite, error) { - if aclKey != nil && guestUserKey != nil { +func (i *inviteService) buildInvite(ctx context.Context, params GenerateInviteParams) (*model.Invite, error) { + if params.Key == nil { return nil, fmt.Errorf("you should provide either acl key or guest user key") } - invitePayload, err := i.buildInvitePayload(ctx, spaceId, aclKey, guestUserKey) + invitePayload, err := i.buildInvitePayload(ctx, params) if err != nil { return nil, fmt.Errorf("build invite payload: %w", err) } @@ -318,36 +314,35 @@ func (i *inviteService) buildInvite(ctx context.Context, spaceId string, aclKey, }, nil } -func (i *inviteService) buildInvitePayload(ctx context.Context, spaceId string, aclKey crypto.PrivKey, guestKey crypto.PrivKey) (*model.InvitePayload, error) { +func (i *inviteService) buildInvitePayload(ctx context.Context, params GenerateInviteParams) (*model.InvitePayload, error) { profile, err := i.accountService.ProfileInfo() if err != nil { return nil, fmt.Errorf("get profile info: %w", err) } invitePayload := &model.InvitePayload{ - SpaceId: spaceId, + SpaceId: params.SpaceId, CreatorIdentity: i.accountService.AccountID(), CreatorName: profile.Name, } - if aclKey != nil { - rawAclKey, err := aclKey.Marshall() - if err != nil { - return nil, fmt.Errorf("marshal invite priv key: %w", err) - } - invitePayload.AclKey = rawAclKey - } else if guestKey != nil { - rawGuestKey, err := guestKey.Marshall() - if err != nil { - return nil, fmt.Errorf("marshal invite priv key: %w", err) - } - invitePayload.GuestKey = rawGuestKey - invitePayload.InviteType = model.InvitePayload_JoinAsGuest - } else { - return nil, fmt.Errorf("acl key or guest key should be provided") + rawKey, err := params.Key.Marshall() + if err != nil { + return nil, fmt.Errorf("marshal invite priv key: %w", err) + } + switch params.InviteType { + case domain.InviteTypeGuest: + invitePayload.GuestKey = rawKey + invitePayload.InviteType = model.InviteType_Guest + case domain.InviteTypeAnyone: + invitePayload.AclKey = rawKey + invitePayload.InviteType = model.InviteType_WithoutApprove + case domain.InviteTypeDefault: + invitePayload.AclKey = rawKey + invitePayload.InviteType = model.InviteType_Member } var description spaceinfo.SpaceDescription - err = i.spaceService.TechSpace().DoSpaceView(ctx, spaceId, func(spaceView techspace.SpaceView) error { + err = i.spaceService.TechSpace().DoSpaceView(ctx, params.SpaceId, func(spaceView techspace.SpaceView) error { description = spaceView.GetSpaceDescription() return nil }) @@ -391,6 +386,7 @@ func (i *inviteService) GetExistingGuestUserInvite(ctx context.Context, spaceId return domain.InviteInfo{ InviteFileCid: fileCid, InviteFileKey: fileKey, + InviteType: domain.InviteTypeGuest, }, nil } return domain.InviteInfo{}, ErrInviteNotExists diff --git a/core/inviteservice/inviteservice_test.go b/core/inviteservice/inviteservice_test.go index 6837ede76..05dda66f8 100644 --- a/core/inviteservice/inviteservice_test.go +++ b/core/inviteservice/inviteservice_test.go @@ -2,26 +2,38 @@ package inviteservice import ( "context" + "fmt" "testing" "github.com/anyproto/any-sync/app" + "github.com/anyproto/any-sync/commonspace/object/accountdata" + "github.com/anyproto/any-sync/commonspace/object/acl/list" + "github.com/anyproto/any-sync/util/cidutil" + "github.com/anyproto/any-sync/util/crypto" + "github.com/ipfs/go-cid" + mh "github.com/multiformats/go-multihash" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + "github.com/anyproto/anytype-heart/core/anytype/account" "github.com/anyproto/anytype-heart/core/anytype/account/mock_account" "github.com/anyproto/anytype-heart/core/block/editor/smartblock" "github.com/anyproto/anytype-heart/core/block/editor/smartblock/smarttest" + "github.com/anyproto/anytype-heart/core/domain" "github.com/anyproto/anytype-heart/core/domain/mock_domain" "github.com/anyproto/anytype-heart/core/files/fileacl/mock_fileacl" "github.com/anyproto/anytype-heart/core/invitestore/mock_invitestore" + "github.com/anyproto/anytype-heart/pkg/lib/pb/model" "github.com/anyproto/anytype-heart/pkg/lib/threads" "github.com/anyproto/anytype-heart/space/clientspace" "github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace" "github.com/anyproto/anytype-heart/space/mock_space" + "github.com/anyproto/anytype-heart/space/spaceinfo" "github.com/anyproto/anytype-heart/space/techspace" "github.com/anyproto/anytype-heart/space/techspace/mock_techspace" "github.com/anyproto/anytype-heart/tests/testutil" + "github.com/anyproto/anytype-heart/util/encode" ) type mockInviteObject struct { @@ -29,51 +41,341 @@ type mockInviteObject struct { *mock_domain.MockInviteObject } -func TestInviteService_GetCurrent(t *testing.T) { - t.Run("get current migration", func(t *testing.T) { - fx := newFixture(t) - defer fx.ctrl.Finish() - fx.mockSpaceService.EXPECT().TechSpace().Return(&clientspace.TechSpace{TechSpace: fx.mockTechSpace}) - fx.mockTechSpace.EXPECT().DoSpaceView(ctx, "spaceId", mock.Anything).RunAndReturn( - func(ctx context.Context, spaceId string, f func(view techspace.SpaceView) error) error { - return f(fx.mockSpaceView) - }) - fx.mockSpaceView.EXPECT().GetExistingInviteInfo().Return("fileId", "fileKey") - fx.mockSpaceView.EXPECT().RemoveExistingInviteInfo().Return("fileId", nil) - fx.mockSpaceService.EXPECT().Get(ctx, "spaceId").Return(fx.mockSpace, nil) - fx.mockSpace.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{ - Workspace: "workspaceId", - }) - fx.mockSpace.EXPECT().Do("workspaceId", mock.Anything).RunAndReturn(func(s string, f func(smartblock.SmartBlock) error) error { - return f(mockInviteObject{SmartBlock: smarttest.New("root"), MockInviteObject: fx.mockInviteObject}) - }) - fx.mockInviteObject.EXPECT().SetInviteFileInfo("fileId", "fileKey").Return(nil) - info, err := fx.GetCurrent(ctx, "spaceId") - require.NoError(t, err) - require.Equal(t, "fileKey", info.InviteFileKey) - require.Equal(t, "fileId", info.InviteFileCid) +func (fx *fixture) expectInviteObject() { + fx.mockSpaceService.EXPECT().Get(ctx, "spaceId").Return(fx.mockSpace, nil) + fx.mockSpace.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{ + Workspace: "workspaceId", }) + fx.mockSpace.EXPECT().Do("workspaceId", mock.Anything).RunAndReturn(func(s string, f func(smartblock.SmartBlock) error) error { + return f(mockInviteObject{SmartBlock: smarttest.New("root"), MockInviteObject: fx.mockInviteObject}) + }) +} + +func newCidFromBytes(data []byte) (cid.Cid, error) { + hash, err := mh.Sum(data, mh.SHA2_256, -1) + if err != nil { + return cid.Undef, err + } + return cid.NewCidV1(cid.DagCBOR, hash), nil +} + +func TestInviteService_GetCurrent(t *testing.T) { t.Run("get current no migration", func(t *testing.T) { fx := newFixture(t) defer fx.ctrl.Finish() + fx.expectInviteObject() + returnedInfo := domain.InviteInfo{ + InviteFileCid: "fileCid", + InviteFileKey: "fileKey", + InviteType: domain.InviteTypeAnyone, + Permissions: list.AclPermissionsWriter, + } + fx.mockInviteObject.EXPECT().GetExistingInviteInfo().Return(returnedInfo) + info, err := fx.GetCurrent(ctx, "spaceId") + require.NoError(t, err) + require.Equal(t, returnedInfo, info) + }) +} + +func TestInviteService_RemoveExisting(t *testing.T) { + t.Run("remove ok", func(t *testing.T) { + fx := newFixture(t) + defer fx.ctrl.Finish() + fx.expectInviteObject() + res, err := cidutil.NewCidFromBytes([]byte("fileCid")) + require.NoError(t, err) + returnedInfo := domain.InviteInfo{ + InviteFileCid: res, + InviteFileKey: "fileKey", + InviteType: domain.InviteTypeAnyone, + Permissions: list.AclPermissionsWriter, + } + invCid, err := cid.Decode(returnedInfo.InviteFileCid) + require.NoError(t, err) + fx.mockInviteObject.EXPECT().RemoveExistingInviteInfo().Return(returnedInfo, nil) + fx.mockInviteStore.EXPECT().RemoveInvite(ctx, invCid).Return(nil) + err = fx.RemoveExisting(ctx, "spaceId") + require.NoError(t, err) + }) +} + +func TestInviteService_Generate(t *testing.T) { + t.Run("generate invite anyone, no existing info", func(t *testing.T) { + fx := newFixture(t) + defer fx.ctrl.Finish() + fx.expectInviteObject() + fx.mockInviteObject.EXPECT().GetExistingInviteInfo().Return(domain.InviteInfo{}) + acc, err := accountdata.NewRandom() + require.NoError(t, err) + fx.mockAccountService.EXPECT().AccountID().Return(acc.SignKey.GetPublic().Account()) + profile := account.Profile{ + Id: "profileId", + AccountId: acc.SignKey.GetPublic().Account(), + Name: "Misha", + } + spaceDescription := spaceinfo.SpaceDescription{ + Name: "space", + IconImage: "icon", + } + fx.mockAccountService.EXPECT().PersonalSpaceID().Return("personal") + fx.mockSpaceView.EXPECT().GetSpaceDescription().Return(spaceDescription) + fx.mockFileAcl.EXPECT().GetInfoForFileSharing(spaceDescription.IconImage).Return("iconCid", nil, nil) fx.mockSpaceService.EXPECT().TechSpace().Return(&clientspace.TechSpace{TechSpace: fx.mockTechSpace}) fx.mockTechSpace.EXPECT().DoSpaceView(ctx, "spaceId", mock.Anything).RunAndReturn( func(ctx context.Context, spaceId string, f func(view techspace.SpaceView) error) error { return f(fx.mockSpaceView) }) - fx.mockSpaceView.EXPECT().GetExistingInviteInfo().Return("", "") - fx.mockSpaceService.EXPECT().Get(ctx, "spaceId").Return(fx.mockSpace, nil) - fx.mockSpace.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{ - Workspace: "workspaceId", - }) - fx.mockSpace.EXPECT().Do("workspaceId", mock.Anything).RunAndReturn(func(s string, f func(smartblock.SmartBlock) error) error { - return f(mockInviteObject{SmartBlock: smarttest.New("root"), MockInviteObject: fx.mockInviteObject}) - }) - fx.mockInviteObject.EXPECT().GetExistingInviteInfo().Return("fileId", "fileKey") - info, err := fx.GetCurrent(ctx, "spaceId") + fx.mockAccountService.EXPECT().ProfileInfo().Return(profile, nil) + fx.mockAccountService.EXPECT().SignData(mock.Anything).Return([]byte("signature"), nil) + inviteCid, err := newCidFromBytes([]byte("fileCid")) require.NoError(t, err) - require.Equal(t, "fileKey", info.InviteFileKey) - require.Equal(t, "fileId", info.InviteFileCid) + inviteKey := crypto.NewAES() + fx.mockInviteStore.EXPECT().StoreInvite(ctx, mock.Anything).Return(inviteCid, inviteKey, nil) + inviteFileKeyRaw, err := encode.EncodeKeyToBase58(inviteKey) + require.NoError(t, err) + inviteInfo := domain.InviteInfo{ + InviteFileCid: inviteCid.String(), + InviteFileKey: inviteFileKeyRaw, + InviteType: domain.InviteTypeAnyone, + Permissions: list.AclPermissionsReader, + } + fx.mockInviteObject.EXPECT().SetInviteFileInfo(inviteInfo).Return(nil) + info, err := fx.inviteService.Generate(ctx, GenerateInviteParams{ + SpaceId: "spaceId", + Key: acc.PeerKey, + InviteType: domain.InviteTypeAnyone, + Permissions: list.AclPermissionsReader, + }, func() error { + return nil + }) + require.NoError(t, err) + require.Equal(t, inviteInfo, info) + }) + t.Run("generate invite anyone, invite exists of different type", func(t *testing.T) { + fx := newFixture(t) + defer fx.ctrl.Finish() + fx.expectInviteObject() + returnedInfo := domain.InviteInfo{ + InviteFileCid: "fileCid", + InviteFileKey: "fileKey", + InviteType: domain.InviteTypeDefault, + Permissions: list.AclPermissionsReader, + } + fx.mockInviteObject.EXPECT().GetExistingInviteInfo().Return(returnedInfo) + acc, err := accountdata.NewRandom() + require.NoError(t, err) + fx.mockAccountService.EXPECT().AccountID().Return(acc.SignKey.GetPublic().Account()) + profile := account.Profile{ + Id: "profileId", + AccountId: acc.SignKey.GetPublic().Account(), + Name: "Misha", + } + spaceDescription := spaceinfo.SpaceDescription{ + Name: "space", + IconImage: "icon", + } + fx.mockAccountService.EXPECT().PersonalSpaceID().Return("personal") + fx.mockSpaceView.EXPECT().GetSpaceDescription().Return(spaceDescription) + fx.mockFileAcl.EXPECT().GetInfoForFileSharing(spaceDescription.IconImage).Return("iconCid", nil, nil) + fx.mockSpaceService.EXPECT().TechSpace().Return(&clientspace.TechSpace{TechSpace: fx.mockTechSpace}) + fx.mockTechSpace.EXPECT().DoSpaceView(ctx, "spaceId", mock.Anything).RunAndReturn( + func(ctx context.Context, spaceId string, f func(view techspace.SpaceView) error) error { + return f(fx.mockSpaceView) + }) + fx.mockAccountService.EXPECT().ProfileInfo().Return(profile, nil) + fx.mockAccountService.EXPECT().SignData(mock.Anything).Return([]byte("signature"), nil) + inviteCid, err := newCidFromBytes([]byte("fileCid")) + require.NoError(t, err) + inviteKey := crypto.NewAES() + fx.mockInviteStore.EXPECT().StoreInvite(ctx, mock.Anything).Return(inviteCid, inviteKey, nil) + inviteFileKeyRaw, err := encode.EncodeKeyToBase58(inviteKey) + require.NoError(t, err) + inviteInfo := domain.InviteInfo{ + InviteFileCid: inviteCid.String(), + InviteFileKey: inviteFileKeyRaw, + InviteType: domain.InviteTypeAnyone, + Permissions: list.AclPermissionsReader, + } + fx.mockInviteObject.EXPECT().SetInviteFileInfo(inviteInfo).Return(nil) + info, err := fx.inviteService.Generate(ctx, GenerateInviteParams{ + SpaceId: "spaceId", + Key: acc.PeerKey, + InviteType: domain.InviteTypeAnyone, + Permissions: list.AclPermissionsReader, + }, func() error { + return nil + }) + require.NoError(t, err) + require.Equal(t, inviteInfo, info) + }) + t.Run("generate invite request join, no existing info", func(t *testing.T) { + fx := newFixture(t) + defer fx.ctrl.Finish() + fx.expectInviteObject() + fx.mockInviteObject.EXPECT().GetExistingInviteInfo().Return(domain.InviteInfo{}) + acc, err := accountdata.NewRandom() + require.NoError(t, err) + fx.mockAccountService.EXPECT().AccountID().Return(acc.SignKey.GetPublic().Account()) + profile := account.Profile{ + Id: "profileId", + AccountId: acc.SignKey.GetPublic().Account(), + Name: "Misha", + } + spaceDescription := spaceinfo.SpaceDescription{ + Name: "space", + IconImage: "icon", + } + fx.mockAccountService.EXPECT().PersonalSpaceID().Return("personal") + fx.mockSpaceView.EXPECT().GetSpaceDescription().Return(spaceDescription) + fx.mockFileAcl.EXPECT().GetInfoForFileSharing(spaceDescription.IconImage).Return("iconCid", nil, nil) + fx.mockSpaceService.EXPECT().TechSpace().Return(&clientspace.TechSpace{TechSpace: fx.mockTechSpace}) + fx.mockTechSpace.EXPECT().DoSpaceView(ctx, "spaceId", mock.Anything).RunAndReturn( + func(ctx context.Context, spaceId string, f func(view techspace.SpaceView) error) error { + return f(fx.mockSpaceView) + }) + fx.mockAccountService.EXPECT().ProfileInfo().Return(profile, nil) + fx.mockAccountService.EXPECT().SignData(mock.Anything).Return([]byte("signature"), nil) + inviteCid, err := newCidFromBytes([]byte("fileCid")) + require.NoError(t, err) + inviteKey := crypto.NewAES() + fx.mockInviteStore.EXPECT().StoreInvite(ctx, mock.Anything).Return(inviteCid, inviteKey, nil) + inviteFileKeyRaw, err := encode.EncodeKeyToBase58(inviteKey) + require.NoError(t, err) + inviteInfo := domain.InviteInfo{ + InviteFileCid: inviteCid.String(), + InviteFileKey: inviteFileKeyRaw, + InviteType: domain.InviteTypeDefault, + Permissions: list.AclPermissionsReader, + } + fx.mockInviteObject.EXPECT().SetInviteFileInfo(inviteInfo).Return(nil) + info, err := fx.inviteService.Generate(ctx, GenerateInviteParams{ + SpaceId: "spaceId", + Key: acc.PeerKey, + InviteType: domain.InviteTypeDefault, + Permissions: list.AclPermissionsReader, + }, func() error { + return nil + }) + require.NoError(t, err) + require.Equal(t, inviteInfo, info) + }) + t.Run("generate invite request join, fail to send", func(t *testing.T) { + fx := newFixture(t) + defer fx.ctrl.Finish() + fx.expectInviteObject() + fx.mockInviteObject.EXPECT().GetExistingInviteInfo().Return(domain.InviteInfo{}) + acc, err := accountdata.NewRandom() + require.NoError(t, err) + fx.mockAccountService.EXPECT().AccountID().Return(acc.SignKey.GetPublic().Account()) + profile := account.Profile{ + Id: "profileId", + AccountId: acc.SignKey.GetPublic().Account(), + Name: "Misha", + } + spaceDescription := spaceinfo.SpaceDescription{ + Name: "space", + IconImage: "icon", + } + fx.mockAccountService.EXPECT().PersonalSpaceID().Return("personal") + fx.mockSpaceView.EXPECT().GetSpaceDescription().Return(spaceDescription) + fx.mockFileAcl.EXPECT().GetInfoForFileSharing(spaceDescription.IconImage).Return("iconCid", nil, nil) + fx.mockSpaceService.EXPECT().TechSpace().Return(&clientspace.TechSpace{TechSpace: fx.mockTechSpace}) + fx.mockTechSpace.EXPECT().DoSpaceView(ctx, "spaceId", mock.Anything).RunAndReturn( + func(ctx context.Context, spaceId string, f func(view techspace.SpaceView) error) error { + return f(fx.mockSpaceView) + }) + fx.mockAccountService.EXPECT().ProfileInfo().Return(profile, nil) + fx.mockAccountService.EXPECT().SignData(mock.Anything).Return([]byte("signature"), nil) + inviteCid, err := newCidFromBytes([]byte("fileCid")) + require.NoError(t, err) + inviteKey := crypto.NewAES() + fx.mockInviteStore.EXPECT().StoreInvite(ctx, mock.Anything).Return(inviteCid, inviteKey, nil) + inviteFileKeyRaw, err := encode.EncodeKeyToBase58(inviteKey) + require.NoError(t, err) + inviteInfo := domain.InviteInfo{ + InviteFileCid: inviteCid.String(), + InviteFileKey: inviteFileKeyRaw, + InviteType: domain.InviteTypeDefault, + Permissions: list.AclPermissionsReader, + } + fx.mockInviteObject.EXPECT().SetInviteFileInfo(inviteInfo).Return(nil) + fx.mockInviteObject.EXPECT().RemoveExistingInviteInfo().Return(inviteInfo, nil) + fx.mockInviteStore.EXPECT().RemoveInvite(ctx, inviteCid).Return(nil) + _, err = fx.inviteService.Generate(ctx, GenerateInviteParams{ + SpaceId: "spaceId", + Key: acc.PeerKey, + InviteType: domain.InviteTypeDefault, + Permissions: list.AclPermissionsReader, + }, func() error { + return fmt.Errorf("failed to send") + }) + require.Error(t, err) + }) + t.Run("generate invite anyone, invite exists", func(t *testing.T) { + fx := newFixture(t) + defer fx.ctrl.Finish() + fx.expectInviteObject() + returnedInfo := domain.InviteInfo{ + InviteFileCid: "fileCid", + InviteFileKey: "fileKey", + InviteType: domain.InviteTypeAnyone, + Permissions: list.AclPermissionsWriter, + } + fx.mockAccountService.EXPECT().PersonalSpaceID().Return("personal") + fx.mockInviteObject.EXPECT().GetExistingInviteInfo().Return(returnedInfo) + info, err := fx.inviteService.Generate(ctx, GenerateInviteParams{ + SpaceId: "spaceId", + InviteType: domain.InviteTypeAnyone, + Permissions: list.AclPermissionsReader, + }, func() error { + return nil + }) + require.NoError(t, err) + require.Equal(t, returnedInfo, info) + }) +} + +func TestInviteService_InviteView(t *testing.T) { + t.Run("view ok", func(t *testing.T) { + fx := newFixture(t) + defer fx.ctrl.Finish() + acc, err := accountdata.NewRandom() + require.NoError(t, err) + rawKey, err := acc.PeerKey.Marshall() + require.NoError(t, err) + payload := &model.InvitePayload{ + CreatorIdentity: acc.SignKey.GetPublic().Account(), + CreatorName: "Misha", + SpaceName: "spaceName", + AclKey: rawKey, + SpaceId: "spaceId", + SpaceIconCid: "spaceIconCid", + InviteType: model.InviteType_WithoutApprove, + } + expectedView := domain.InviteView{ + InviteType: domain.InviteTypeAnyone, + SpaceId: "spaceId", + SpaceName: "spaceName", + SpaceIconCid: "spaceIconCid", + CreatorName: "Misha", + AclKey: rawKey, + } + marshaled, err := payload.Marshal() + require.NoError(t, err) + signature, err := acc.SignKey.Sign(marshaled) + require.NoError(t, err) + invite := &model.Invite{ + Payload: marshaled, + Signature: signature, + } + inviteCid, err := newCidFromBytes([]byte("fileCid")) + require.NoError(t, err) + inviteKey := crypto.NewAES() + fx.mockInviteStore.EXPECT().GetInvite(ctx, inviteCid, inviteKey).Return(invite, nil) + fx.mockFileAcl.EXPECT().StoreFileKeys(mock.Anything, mock.Anything).Return(nil) + view, err := fx.inviteService.View(ctx, inviteCid, inviteKey) + require.NoError(t, err) + require.Equal(t, expectedView, view) }) } diff --git a/core/inviteservice/mock_inviteservice/mock_InviteService.go b/core/inviteservice/mock_inviteservice/mock_InviteService.go index fc5caf12f..ea63a2c05 100644 --- a/core/inviteservice/mock_inviteservice/mock_InviteService.go +++ b/core/inviteservice/mock_inviteservice/mock_InviteService.go @@ -12,6 +12,10 @@ import ( domain "github.com/anyproto/anytype-heart/core/domain" + inviteservice "github.com/anyproto/anytype-heart/core/inviteservice" + + list "github.com/anyproto/any-sync/commonspace/object/acl/list" + mock "github.com/stretchr/testify/mock" model "github.com/anyproto/anytype-heart/pkg/lib/pb/model" @@ -30,6 +34,54 @@ func (_m *MockInviteService) EXPECT() *MockInviteService_Expecter { return &MockInviteService_Expecter{mock: &_m.Mock} } +// Change provides a mock function with given fields: ctx, spaceId, permissions +func (_m *MockInviteService) Change(ctx context.Context, spaceId string, permissions list.AclPermissions) error { + ret := _m.Called(ctx, spaceId, permissions) + + if len(ret) == 0 { + panic("no return value specified for Change") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, list.AclPermissions) error); ok { + r0 = rf(ctx, spaceId, permissions) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockInviteService_Change_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Change' +type MockInviteService_Change_Call struct { + *mock.Call +} + +// Change is a helper method to define mock.On call +// - ctx context.Context +// - spaceId string +// - permissions list.AclPermissions +func (_e *MockInviteService_Expecter) Change(ctx interface{}, spaceId interface{}, permissions interface{}) *MockInviteService_Change_Call { + return &MockInviteService_Change_Call{Call: _e.mock.On("Change", ctx, spaceId, permissions)} +} + +func (_c *MockInviteService_Change_Call) Run(run func(ctx context.Context, spaceId string, permissions list.AclPermissions)) *MockInviteService_Change_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(list.AclPermissions)) + }) + return _c +} + +func (_c *MockInviteService_Change_Call) Return(_a0 error) *MockInviteService_Change_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockInviteService_Change_Call) RunAndReturn(run func(context.Context, string, list.AclPermissions) error) *MockInviteService_Change_Call { + _c.Call.Return(run) + return _c +} + // Close provides a mock function with given fields: ctx func (_m *MockInviteService) Close(ctx context.Context) error { ret := _m.Called(ctx) @@ -76,9 +128,9 @@ func (_c *MockInviteService_Close_Call) RunAndReturn(run func(context.Context) e return _c } -// Generate provides a mock function with given fields: ctx, spaceId, inviteKey, sendInvite -func (_m *MockInviteService) Generate(ctx context.Context, spaceId string, inviteKey crypto.PrivKey, sendInvite func() error) (domain.InviteInfo, error) { - ret := _m.Called(ctx, spaceId, inviteKey, sendInvite) +// Generate provides a mock function with given fields: ctx, params, sendInvite +func (_m *MockInviteService) Generate(ctx context.Context, params inviteservice.GenerateInviteParams, sendInvite func() error) (domain.InviteInfo, error) { + ret := _m.Called(ctx, params, sendInvite) if len(ret) == 0 { panic("no return value specified for Generate") @@ -86,17 +138,17 @@ func (_m *MockInviteService) Generate(ctx context.Context, spaceId string, invit var r0 domain.InviteInfo var r1 error - if rf, ok := ret.Get(0).(func(context.Context, string, crypto.PrivKey, func() error) (domain.InviteInfo, error)); ok { - return rf(ctx, spaceId, inviteKey, sendInvite) + if rf, ok := ret.Get(0).(func(context.Context, inviteservice.GenerateInviteParams, func() error) (domain.InviteInfo, error)); ok { + return rf(ctx, params, sendInvite) } - if rf, ok := ret.Get(0).(func(context.Context, string, crypto.PrivKey, func() error) domain.InviteInfo); ok { - r0 = rf(ctx, spaceId, inviteKey, sendInvite) + if rf, ok := ret.Get(0).(func(context.Context, inviteservice.GenerateInviteParams, func() error) domain.InviteInfo); ok { + r0 = rf(ctx, params, sendInvite) } else { r0 = ret.Get(0).(domain.InviteInfo) } - if rf, ok := ret.Get(1).(func(context.Context, string, crypto.PrivKey, func() error) error); ok { - r1 = rf(ctx, spaceId, inviteKey, sendInvite) + if rf, ok := ret.Get(1).(func(context.Context, inviteservice.GenerateInviteParams, func() error) error); ok { + r1 = rf(ctx, params, sendInvite) } else { r1 = ret.Error(1) } @@ -111,16 +163,15 @@ type MockInviteService_Generate_Call struct { // Generate is a helper method to define mock.On call // - ctx context.Context -// - spaceId string -// - inviteKey crypto.PrivKey +// - params inviteservice.GenerateInviteParams // - sendInvite func() error -func (_e *MockInviteService_Expecter) Generate(ctx interface{}, spaceId interface{}, inviteKey interface{}, sendInvite interface{}) *MockInviteService_Generate_Call { - return &MockInviteService_Generate_Call{Call: _e.mock.On("Generate", ctx, spaceId, inviteKey, sendInvite)} +func (_e *MockInviteService_Expecter) Generate(ctx interface{}, params interface{}, sendInvite interface{}) *MockInviteService_Generate_Call { + return &MockInviteService_Generate_Call{Call: _e.mock.On("Generate", ctx, params, sendInvite)} } -func (_c *MockInviteService_Generate_Call) Run(run func(ctx context.Context, spaceId string, inviteKey crypto.PrivKey, sendInvite func() error)) *MockInviteService_Generate_Call { +func (_c *MockInviteService_Generate_Call) Run(run func(ctx context.Context, params inviteservice.GenerateInviteParams, sendInvite func() error)) *MockInviteService_Generate_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(string), args[2].(crypto.PrivKey), args[3].(func() error)) + run(args[0].(context.Context), args[1].(inviteservice.GenerateInviteParams), args[2].(func() error)) }) return _c } @@ -130,7 +181,7 @@ func (_c *MockInviteService_Generate_Call) Return(_a0 domain.InviteInfo, _a1 err return _c } -func (_c *MockInviteService_Generate_Call) RunAndReturn(run func(context.Context, string, crypto.PrivKey, func() error) (domain.InviteInfo, error)) *MockInviteService_Generate_Call { +func (_c *MockInviteService_Generate_Call) RunAndReturn(run func(context.Context, inviteservice.GenerateInviteParams, func() error) (domain.InviteInfo, error)) *MockInviteService_Generate_Call { _c.Call.Return(run) return _c } diff --git a/core/pushnotification/keys.go b/core/pushnotification/keys.go index 3f35728c3..bb15d06de 100644 --- a/core/pushnotification/keys.go +++ b/core/pushnotification/keys.go @@ -1,6 +1,8 @@ package pushnotification import ( + "errors" + "github.com/anyproto/any-sync/util/crypto" "github.com/anyproto/anytype-heart/util/privkey" @@ -20,6 +22,9 @@ func deriveSpaceKey(firstMetadataKey crypto.PrivKey) (crypto.PrivKey, error) { } func deriveSymmetricKey(readKey crypto.SymKey) (crypto.SymKey, error) { + if readKey == nil { + return nil, errors.New("readKey is nil") + } raw, err := readKey.Raw() if err != nil { return nil, err diff --git a/core/pushnotification/service.go b/core/pushnotification/service.go index dc738e6a7..5f229f86f 100644 --- a/core/pushnotification/service.go +++ b/core/pushnotification/service.go @@ -7,6 +7,7 @@ import ( "encoding/hex" "fmt" "sync" + "time" "github.com/anyproto/any-sync/app" "github.com/anyproto/any-sync/commonspace/object/acl/list" @@ -33,6 +34,13 @@ type requestSubscribe struct { topics []string } +type PushMessage struct { + SpaceId string + Topics []string + Payload []byte + Deadline time.Time +} + type Service interface { app.ComponentRunnable RegisterToken(ctx context.Context, req *pb.RpcPushNotificationRegisterTokenRequest) (err error) @@ -59,6 +67,8 @@ type service struct { ctx context.Context cancel context.CancelFunc requestsQueue *mb.MB[requestSubscribe] + notifyQueue *mb.MB[PushMessage] + createSpaceQueue *mb.MB[string] } type spaceKeyType string @@ -74,15 +84,14 @@ func (s *service) SubscribeToTopics(ctx context.Context, spaceId string, topics } func (s *service) Run(ctx context.Context) (err error) { - // TODO Temporarliy disabled - return nil - if s.cfg.IsLocalOnlyMode() { return nil } s.started = true s.ctx, s.cancel = context.WithCancel(context.Background()) go s.run() + go s.notifyLoop() + go s.createSpaceLoop() return nil } @@ -93,6 +102,8 @@ func (s *service) Close(ctx context.Context) (err error) { if s.cancel != nil { s.cancel() } + _ = s.createSpaceQueue.Close() + _ = s.notifyQueue.Close() return s.requestsQueue.Close() } @@ -103,6 +114,8 @@ func (s *service) Init(a *app.App) (err error) { s.requestsQueue = mb.New[requestSubscribe](0) s.spaceService = app.MustComponent[space.Service](a) s.eventSender = app.MustComponent[event.Sender](a) + s.notifyQueue = mb.New[PushMessage](0) + s.createSpaceQueue = mb.New[string](0) return } @@ -148,6 +161,10 @@ func (s *service) CreateSpace(ctx context.Context, spaceId string) (err error) { if !s.started { return nil } + return s.createSpaceQueue.Add(ctx, spaceId) +} + +func (s *service) createSpace(ctx context.Context, spaceId string) (err error) { keys, err := s.getSpaceKeys(spaceId) if err != nil { return fmt.Errorf("get space keys: %w", err) @@ -175,36 +192,12 @@ type spaceKeys struct { } func (s *service) Notify(ctx context.Context, spaceId string, topic []string, payload []byte) (err error) { - if !s.started { - return nil - } - - keys, err := s.getSpaceKeys(spaceId) - if err != nil { - return fmt.Errorf("get space keys: %w", err) - } - topics, err := s.makeTopics(keys.signKey, topic) - if err != nil { - return err - } - encryptedJson, err := keys.encryptionKey.Encrypt(payload) - if err != nil { - return err - } - signature, err := s.wallet.GetAccountPrivkey().Sign(encryptedJson) - if err != nil { - return err - } - p := &pushapi.Message{ - KeyId: keys.encryptionKeyId, - Payload: encryptedJson, - Signature: signature, - } - err = s.pushClient.Notify(ctx, &pushapi.NotifyRequest{ - Topics: &pushapi.Topics{Topics: topics}, - Message: p, + return s.notifyQueue.Add(ctx, PushMessage{ + SpaceId: spaceId, + Topics: topic, + Payload: payload, + Deadline: time.Now().Add(time.Minute * 2), }) - return err } func (s *service) loadSubscriptions(ctx context.Context) (err error) { @@ -309,6 +302,7 @@ func (s *service) run() { keys, err := s.getSpaceKeys(req.spaceId) if err != nil { log.Error("failed to get space keys", zap.Error(err)) + continue } for _, topic := range req.topics { @@ -332,6 +326,72 @@ func (s *service) run() { } } +func (s *service) notifyLoop() { + for { + msg, err := s.notifyQueue.WaitOne(s.ctx) + if err != nil { + return + } + if msg.Deadline.Before(time.Now()) { + continue + } + if err = s.sendNotification(msg); err != nil { + log.Error("failed to send notification", zap.Error(err)) + } + } +} + +func (s *service) sendNotification(msg PushMessage) (err error) { + keys, err := s.getSpaceKeys(msg.SpaceId) + if err != nil { + return fmt.Errorf("get space keys: %w", err) + } + topics, err := s.makeTopics(keys.signKey, msg.Topics) + if err != nil { + return err + } + encryptedJson, err := keys.encryptionKey.Encrypt(msg.Payload) + if err != nil { + return err + } + signature, err := s.wallet.GetAccountPrivkey().Sign(encryptedJson) + if err != nil { + return err + } + p := &pushapi.Message{ + KeyId: keys.encryptionKeyId, + Payload: encryptedJson, + Signature: signature, + } + err = s.pushClient.Notify(s.ctx, &pushapi.NotifyRequest{ + Topics: &pushapi.Topics{Topics: topics}, + Message: p, + }) + return err +} + +func (s *service) createSpaceLoop() { + for { + spaceId, err := s.createSpaceQueue.WaitOne(s.ctx) + if err != nil { + return + } + for { + if err = s.createSpace(s.ctx, spaceId); err != nil { + log.Warn("failed to create space", zap.Error(err)) + select { + case <-time.After(time.Minute): + continue + case <-s.ctx.Done(): + return + } + } else { + break + } + } + } +} + func (s *service) BroadcastKeyUpdate(spaceId string, aclState *list.AclState) error { keys, err := s.getSpaceKeysFromAcl(aclState) if err != nil { diff --git a/core/space.go b/core/space.go index b407f8833..9188f5ba9 100644 --- a/core/space.go +++ b/core/space.go @@ -63,7 +63,7 @@ func (mw *Middleware) SpaceMakeShareable(cctx context.Context, req *pb.RpcSpaceM func (mw *Middleware) SpaceInviteGenerate(cctx context.Context, req *pb.RpcSpaceInviteGenerateRequest) *pb.RpcSpaceInviteGenerateResponse { aclService := mustService[acl.AclService](mw) - inviteInfo, err := aclService.GenerateInvite(cctx, req.SpaceId) + inviteInfo, err := aclService.GenerateInvite(cctx, req.SpaceId, req.InviteType, req.Permissions) if err != nil { code := mapErrorCode(err, errToCode(space.ErrSpaceDeleted, pb.RpcSpaceInviteGenerateResponseError_SPACE_IS_DELETED), @@ -83,9 +83,32 @@ func (mw *Middleware) SpaceInviteGenerate(cctx context.Context, req *pb.RpcSpace return &pb.RpcSpaceInviteGenerateResponse{ InviteCid: inviteInfo.InviteFileCid, InviteFileKey: inviteInfo.InviteFileKey, + // nolint: gosec + InviteType: model.InviteType(inviteInfo.InviteType), + Permissions: domain.ConvertAclPermissions(inviteInfo.Permissions), } } +func (mw *Middleware) SpaceInviteChange(cctx context.Context, req *pb.RpcSpaceInviteChangeRequest) *pb.RpcSpaceInviteChangeResponse { + aclService := mustService[acl.AclService](mw) + err := aclService.ChangeInvite(cctx, req.SpaceId, req.Permissions) + if err != nil { + code := mapErrorCode(err, + errToCode(space.ErrSpaceDeleted, pb.RpcSpaceInviteChangeResponseError_SPACE_IS_DELETED), + errToCode(space.ErrSpaceNotExists, pb.RpcSpaceInviteChangeResponseError_NO_SUCH_SPACE), + errToCode(acl.ErrPersonalSpace, pb.RpcSpaceInviteChangeResponseError_BAD_INPUT), + errToCode(acl.ErrAclRequestFailed, pb.RpcSpaceInviteChangeResponseError_REQUEST_FAILED), + ) + return &pb.RpcSpaceInviteChangeResponse{ + Error: &pb.RpcSpaceInviteChangeResponseError{ + Code: code, + Description: getErrorDescription(err), + }, + } + } + return &pb.RpcSpaceInviteChangeResponse{} +} + func (mw *Middleware) SpaceInviteGetCurrent(cctx context.Context, req *pb.RpcSpaceInviteGetCurrentRequest) *pb.RpcSpaceInviteGetCurrentResponse { aclService := mustService[acl.AclService](mw) inviteInfo, err := aclService.GetCurrentInvite(cctx, req.SpaceId) @@ -104,6 +127,9 @@ func (mw *Middleware) SpaceInviteGetCurrent(cctx context.Context, req *pb.RpcSpa return &pb.RpcSpaceInviteGetCurrentResponse{ InviteCid: inviteInfo.InviteFileCid, InviteFileKey: inviteInfo.InviteFileKey, + // nolint: gosec + InviteType: model.InviteType(inviteInfo.InviteType), + Permissions: domain.ConvertAclPermissions(inviteInfo.Permissions), } } @@ -168,6 +194,8 @@ func (mw *Middleware) SpaceInviteView(cctx context.Context, req *pb.RpcSpaceInvi SpaceName: inviteView.SpaceName, SpaceIconCid: inviteView.SpaceIconCid, IsGuestUserInvite: inviteView.IsGuestUserInvite(), + // nolint: gosec + InviteType: model.InviteType(inviteView.InviteType), } } diff --git a/core/subscription/service.go b/core/subscription/service.go index b664d9ff1..4f261addf 100644 --- a/core/subscription/service.go +++ b/core/subscription/service.go @@ -225,10 +225,14 @@ func (s *service) SubscribeGroups(req SubscribeGroupsRequest) (*pb.RpcObjectGrou func (s *service) Unsubscribe(subIds ...string) (err error) { s.lock.Lock() + subs := make([]*spaceSubscriptions, 0, len(s.spaceSubs)) for _, spaceSub := range s.spaceSubs { - err = errors.Join(spaceSub.Unsubscribe(subIds...)) + subs = append(subs, spaceSub) } s.lock.Unlock() + for _, spaceSub := range subs { + err = errors.Join(spaceSub.Unsubscribe(subIds...)) + } return err } @@ -614,9 +618,6 @@ type SubscribeGroupsRequest struct { func (s *spaceSubscriptions) SubscribeGroups(req SubscribeGroupsRequest) (*pb.RpcObjectGroupsSubscribeResponse, error) { subId := "" - s.m.Lock() - defer s.m.Unlock() - q := database.Query{ Filters: req.Filters, } @@ -678,6 +679,9 @@ func (s *spaceSubscriptions) SubscribeGroups(req SubscribeGroupsRequest) (*pb.Rp subId = bson.NewObjectId().Hex() } + s.m.Lock() + defer s.m.Unlock() + var sub subscription if colObserver != nil { sub = s.newCollectionGroupSub(subId, domain.RelationKey(req.RelationKey), flt, groups, colObserver) diff --git a/core/wallet/applink.go b/core/wallet/applink.go index 2c51e8c27..3edd5fe7f 100644 --- a/core/wallet/applink.go +++ b/core/wallet/applink.go @@ -2,165 +2,344 @@ package wallet import ( "bytes" - "crypto/ed25519" + "crypto/hmac" "crypto/sha256" "encoding/base64" + "encoding/binary" json "encoding/json" + "errors" "fmt" "io" "os" "path/filepath" + "strings" + "time" "github.com/anyproto/any-sync/util/crypto" "github.com/anyproto/anytype-heart/pkg/lib/crypto/symmetric" "github.com/anyproto/anytype-heart/pkg/lib/crypto/symmetric/gcm" + "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) -const appLinkKeysDirectory = "auth" +const ( + appLinkKeysDirectory = "auth" + ver1 = 1 +) var ErrAppLinkNotFound = fmt.Errorf("app link file not found in the account directory") -type AppLinkPayload struct { - AccountPrivateKey []byte `json:"key"` // stored only for the main client app - AppName string `json:"app_name"` - AppPath string `json:"app_path"` // for now, it is not verified - CreatedAt int64 `json:"created_at"` // unix timestamp - ExpireAt int64 `json:"expire_at"` // unix timestamp - Scope int `json:"scope"` +type AppLinkInfo struct { + AppHash string `json:"-"` // filled at read time + AppKey string `json:"app_key"` + AppName string `json:"app_name"` + CreatedAt int64 `json:"created_at"` + ExpireAt int64 `json:"expire_at"` + Scope int `json:"scope"` } -type appLinkFileEncrypted struct { - Payload []byte `json:"payload"` - Signature []byte `json:"signature"` // account signature to check the integrity of the payload -} - -func writeAppLinkFile(accountPk crypto.PrivKey, dir string, payload *AppLinkPayload) (appKey string, err error) { - key, err := symmetric.NewRandom() - if err != nil { - return - } - - b, err := json.Marshal(payload) - if err != nil { - return - } - - encPayloadReader, err := gcm.New(key).EncryptReader(bytes.NewReader(b)) - if err != nil { - return "", err - } - - encPayload, err := io.ReadAll(encPayloadReader) - if err != nil { - return "", err - } - - appKey = base64.StdEncoding.EncodeToString(key.Bytes()) - signature, err := accountPk.Sign(encPayload) - - if err != nil { - return "", err - } - encryptedPayload := appLinkFileEncrypted{ - Payload: encPayload, - Signature: signature, - } - - hash := sha256.Sum256(key.Bytes()) - f, err := os.Create(filepath.Join(dir, fmt.Sprintf("%x", hash)+".json")) - if err != nil { - return "", fmt.Errorf("failed to create app key file in the account: %w", err) - } - // todo: change perms? - - w := json.NewEncoder(f) - err = w.Encode(encryptedPayload) - if err != nil { - return "", err - } - return appKey, nil -} - -func readAppLinkFile(pubKey crypto.PubKey, dir string, appKey string) (*AppLinkPayload, error) { - symKeyBytes, err := base64.StdEncoding.DecodeString(appKey) - - if err != nil { - return nil, err - } - hash := sha256.Sum256(symKeyBytes) - f, err := os.Open(filepath.Join(dir, fmt.Sprintf("%x", hash)+".json")) - if err != nil { - // in case it is not found, we return a special error - if os.IsNotExist(err) { - return nil, ErrAppLinkNotFound - } - return nil, err - } - defer f.Close() - - appKeyFile := appLinkFileEncrypted{} - d := json.NewDecoder(f) - err = d.Decode(&appKeyFile) - - if err != nil { - return nil, err - } - - err = signatureVerify(pubKey, &appKeyFile) - if err != nil { - return nil, err - } - - key, err := symmetric.FromBytes(symKeyBytes) - if err != nil { - return nil, err - } - - r, err := gcm.New(key).DecryptReader(bytes.NewReader(appKeyFile.Payload)) - if err != nil { - return nil, err - } - - d = json.NewDecoder(r) - payload := AppLinkPayload{} - err = d.Decode(&payload) - if err != nil { - return nil, err - } - - return &payload, nil -} - -func signatureVerify(key crypto.PubKey, encrypted *appLinkFileEncrypted) error { - v, err := key.Verify(encrypted.Payload, encrypted.Signature) - if err != nil { - return err - } - if !v { - return fmt.Errorf("signature verification failed") - } - return nil -} - -func (r *wallet) ReadAppLink(appKey string) (*AppLinkPayload, error) { +func (r *wallet) ReadAppLink(appKey string) (*AppLinkInfo, error) { if r.repoPath == "" { return nil, fmt.Errorf("repo path is not set") } - if r.accountKey == nil { return nil, fmt.Errorf("account is not set") } - // readAppLinkFile verifies the signature of the payload to make sure it was not tampered and the account id matches - return readAppLinkFile(r.accountKey.GetPublic(), filepath.Join(r.repoPath, appLinkKeysDirectory), appKey) + return load(filepath.Join(r.repoPath, appLinkKeysDirectory), appKey, r.accountKey) } -func (r *wallet) PersistAppLink(payload *AppLinkPayload) (appKey string, err error) { - return writeAppLinkFile(r.accountKey, filepath.Join(r.repoPath, appLinkKeysDirectory), payload) +func (r *wallet) PersistAppLink(name string, scope model.AccountAuthLocalApiScope) (app *AppLinkInfo, err error) { + return generate(filepath.Join(r.repoPath, appLinkKeysDirectory), r.accountKey, name, scope) } -func DeriveForAccount(seed []byte) (res crypto.DerivationResult, err error) { - res.Identity = crypto.NewEd25519PrivKey(ed25519.NewKeyFromSeed(seed)) - return +// ListAppLinks returns a list of all app links for this repo directory +func (r *wallet) ListAppLinks() ([]*AppLinkInfo, error) { + if r.repoPath == "" { + return nil, fmt.Errorf("repo path is not set") + } + if r.accountKey == nil { + return nil, fmt.Errorf("account is not set") + } + + return list(filepath.Join(r.repoPath, appLinkKeysDirectory), r.accountKey) +} + +// RevokeAppLink removes an app link based on its app hash. +func (r *wallet) RevokeAppLink(appHash string) error { + if r.repoPath == "" { + return fmt.Errorf("repo path is not set") + } + + return revoke(filepath.Join(r.repoPath, appLinkKeysDirectory), appHash) +} + +func generate(dir string, accountPriv crypto.PrivKey, appName string, scope model.AccountAuthLocalApiScope) (info *AppLinkInfo, _ error) { + if err := os.MkdirAll(dir, 0o700); err != nil && !os.IsExist(err) { + return nil, err + } + key, err := crypto.NewRandomAES() + if err != nil { + return nil, err + } + appKey := base64.StdEncoding.EncodeToString(key.Bytes()) + info = &AppLinkInfo{ + AppHash: fmt.Sprintf("%x", sha256.Sum256(key.Bytes())), + AppKey: appKey, + AppName: appName, + CreatedAt: time.Now().Unix(), + Scope: int(scope), + } + file, err := buildV1(key.Bytes(), accountPriv, info) + if err != nil { + return nil, err + } + name := fmt.Sprintf("%s.json", info.AppHash) + fp, err := os.OpenFile(filepath.Join(dir, name), os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600) + if err != nil { + return nil, err + } + defer fp.Close() + return info, json.NewEncoder(fp).Encode(&file) +} + +// load and verify the app link file +func load(dir, appKey string, accountPriv crypto.PrivKey) (*AppLinkInfo, error) { + key, err := base64.StdEncoding.DecodeString(appKey) + if err != nil { + return nil, err + } + path := filepath.Join(dir, fmt.Sprintf("%x.json", sha256.Sum256(key))) + fp, err := os.Open(path) + if errors.Is(err, os.ErrNotExist) { + return nil, ErrAppLinkNotFound + } + if err != nil { + return nil, err + } + defer fp.Close() + + // sniff version + var peek struct { + Version int `json:"ver"` + } + if err = json.NewDecoder(fp).Decode(&peek); err != nil { + return nil, err + } + _, _ = fp.Seek(0, io.SeekStart) + + switch peek.Version { + case 0 /* field missing */ : + var v0 fileV0 + if err = json.NewDecoder(fp).Decode(&v0); err != nil { + return nil, err + } + return verifyAndOpenV0(key, accountPriv, &v0) + + case 1: + var v1 fileV1 + if err = json.NewDecoder(fp).Decode(&v1); err != nil { + return nil, err + } + return verifyAndOpenV1(key, accountPriv, &v1) + + default: + return nil, fmt.Errorf("unsupported version %d", peek.Version) + } +} + +// List reads all app link files in the directory +// For v0 files, only the AppHash field will be populated. +// For v1 files, it will include the whole AppLinkInfo +func list(dir string, accountPriv crypto.PrivKey) ([]*AppLinkInfo, error) { + // Ensure directory exists + if _, err := os.Stat(dir); os.IsNotExist(err) { + return nil, nil // Return empty slice if directory doesn't exist + } + + // Read all .json files in the directory + files, err := filepath.Glob(filepath.Join(dir, "*.json")) + if err != nil { + return nil, err + } + + var result []*AppLinkInfo + for _, path := range files { + // Extract app hash from filename + filename := filepath.Base(path) + appHash := strings.TrimSuffix(filename, ".json") + + // Try to read file to determine version + fp, err := os.Open(path) + if err != nil { + continue // Skip files we can't read + } + + // Attempt to determine version + var peek struct { + Version int `json:"ver"` + } + if err = json.NewDecoder(fp).Decode(&peek); err != nil { + fp.Close() + continue // Skip malformed files + } + + _, _ = fp.Seek(0, io.SeekStart) + + info := &AppLinkInfo{ + AppHash: appHash, + } + + // For v1 files, attempt to decrypt if account private key is provided + if peek.Version == 1 && accountPriv != nil { + var v1 fileV1 + if err = json.NewDecoder(fp).Decode(&v1); err == nil { + // Try to decrypt Info field + if plain, err := accountPriv.Decrypt(v1.Info); err == nil { + _ = json.Unmarshal(plain, info) // Ignore error, partial data is fine + } + } + } + + fp.Close() + result = append(result, info) + } + + return result, nil +} + +// Revoke removes an app link file based on its app hash. +// Returns an error if the file doesn't exist. +func revoke(dir, appHash string) error { + filePath := filepath.Join(dir, appHash+".json") + + // Check if the file exists + if _, err := os.Stat(filePath); os.IsNotExist(err) { + return ErrAppLinkNotFound + } + + // Delete the file + return os.Remove(filePath) +} + +type fileV0 struct { + Payload []byte `json:"payload"` // AES-GCM(appKey, AppLinkInfo) + Signature []byte `json:"signature"` // Ed25519(accountPriv, payload) +} + +func verifyAndOpenV0(appKey []byte, accountPriv crypto.PrivKey, f *fileV0) (*AppLinkInfo, error) { + ok, _ := accountPriv.GetPublic().Verify(f.Payload, f.Signature) + if !ok { + return nil, errors.New("v0 signature invalid") + } + + key, err := symmetric.FromBytes(appKey) + if err != nil { + return nil, err + } + + r, err := gcm.New(key).DecryptReader(bytes.NewReader(f.Payload)) + if err != nil { + return nil, err + } + + var info AppLinkInfo + d := json.NewDecoder(r) + if err = d.Decode(&info); err != nil { + return nil, err + } + + return &info, nil +} + +// fileV1 is the JSON-encoded on-disk structure introduced in format-version 1. +type fileV1 struct { + // Version is the *file-format* version tag and **must be 1** for this layout. + // (Future formats should bump this value and add a new struct.) + Version int `json:"ver"` + + // Info contains the envelope-encrypted AppLinkInfo: + // X25519-SealedBox (accountPub, plaintextJSON(AppLinkInfo)). + // Only the user's account private key can open it, so the payload stays + // confidential even if the file is copied. + Info []byte `json:"info"` + + // Auth is an integrity MAC: + // HMAC-SHA-256(appKey, ver || info) + // It proves that the same per-app symmetric key that named the file + // was also present when the record was created (prevents file swapping). + Auth []byte `json:"auth"` + + // Signature is the wallet owner's attestation: + // Ed25519(accountPriv, ver || info || auth) + // It cryptographically binds the record to the specific wallet account + // and prevents any on-disk modification or replay from another account. + Signature []byte `json:"sig"` +} + +// buildV1 writes the json-ready struct. +func buildV1(appKey []byte, accountPriv crypto.PrivKey, info *AppLinkInfo) (fileV1, error) { + msg, err := json.Marshal(info) + if err != nil { + return fileV1{}, err + } + + // 1. encrypt Info with X25519 sealed-box + sealed, err := accountPriv.GetPublic().Encrypt(msg) + if err != nil { + return fileV1{}, err + } + + // 2. auth = HMAC(appKey, ver||info) + auth := hmacAuth(appKey, ver1, sealed) + + // 3. signature = Ed25519(priv, ver||info||auth) + sig, err := accountPriv.Sign(bytesForSig(ver1, sealed, auth)) + if err != nil { + return fileV1{}, err + } + return fileV1{ + Version: ver1, + Info: sealed, + Auth: auth, + Signature: sig, + }, nil +} + +func verifyAndOpenV1(appKey []byte, accountPriv crypto.PrivKey, f *fileV1) (*AppLinkInfo, error) { + // 1. verify Ed25519 signature + if ok, _ := accountPriv.GetPublic().Verify(bytesForSig(f.Version, f.Info, f.Auth), f.Signature); !ok { + return nil, errors.New("v1 ed25519 signature mismatch") + } + // 2. verify HMAC matches this appKey + want := hmacAuth(appKey, f.Version, f.Info) + if !hmac.Equal(want, f.Auth) { + return nil, errors.New("v1 HMAC mismatch") + } + // 3. decrypt Info with X25519 + plain, err := accountPriv.Decrypt(f.Info) + if err != nil { + return nil, err + } + var info AppLinkInfo + if err := json.Unmarshal(plain, &info); err != nil { + return nil, err + } + return &info, nil +} + +// hmacAuth = HMAC-SHA-256(appKey, ver||info) +func hmacAuth(appKey []byte, ver int, info []byte) []byte { + mac := hmac.New(sha256.New, appKey) + _ = binary.Write(mac, binary.BigEndian, ver) + mac.Write(info) + return mac.Sum(nil) +} + +func bytesForSig(ver int, info, auth []byte) []byte { + var buf bytes.Buffer + binary.Write(&buf, binary.BigEndian, uint32(ver)) + buf.Write(info) + buf.Write(auth) + return buf.Bytes() } diff --git a/core/wallet/applink_test.go b/core/wallet/applink_test.go index 9808de25a..829519e33 100644 --- a/core/wallet/applink_test.go +++ b/core/wallet/applink_test.go @@ -1,71 +1,312 @@ package wallet import ( - "crypto/rand" + "bytes" + "crypto/sha256" + "encoding/base64" "encoding/json" "fmt" - "math" - rand2 "math/rand" + "io" "os" + "path/filepath" + "reflect" "testing" "time" "github.com/anyproto/any-sync/util/crypto" "github.com/stretchr/testify/require" + + "github.com/anyproto/anytype-heart/pkg/lib/crypto/symmetric" + "github.com/anyproto/anytype-heart/pkg/lib/crypto/symmetric/gcm" + "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) -func Test_writeAppLinkFile(t *testing.T) { - // 10 to the 4th power - a := 4 - - fmt.Println(a) - value := fmt.Sprintf("%0*d", a, rand2.Intn(int(math.Pow10(a)))) - fmt.Println(value) - -} -func Test_writeAppLinkFileAndRead(t *testing.T) { - priv, pub, err := crypto.GenerateRandomEd25519KeyPair() - require.NoError(t, err) - - tempDir := os.TempDir() - payload := &AppLinkPayload{ - AppName: "test", - AppPath: "path", - CreatedAt: time.Now().Unix(), - ExpireAt: 0, +// make a reproducible test AppLinkInfo +func testInfo() *AppLinkInfo { + now := time.Now().Unix() + return &AppLinkInfo{ + AppName: "unit-test", + CreatedAt: now, + ExpireAt: now + int64(24*time.Hour/time.Second), + Scope: 42, } - gotAppKey, err := writeAppLinkFile(priv, tempDir, payload) - require.NoError(t, err) - - require.NotEmpty(t, gotAppKey) - - gotPayload, err := readAppLinkFile(pub, tempDir, gotAppKey) - require.NoError(t, err) - require.Equal(t, payload, gotPayload) } -func Test_signatureVerify(t *testing.T) { - priv, pub, err := crypto.GenerateRandomEd25519KeyPair() - require.NoError(t, err) - - data := make([]byte, 100) - _, err = rand.Reader.Read(data) - require.NoError(t, err) - - sign, err := priv.Sign(data) - require.NoError(t, err) - - payload := &appLinkFileEncrypted{Payload: data, Signature: sign} - - err = signatureVerify(pub, payload) - require.NoError(t, err) - - jb, err := json.Marshal(payload) - require.NoError(t, err) - - payload2 := &appLinkFileEncrypted{} - err = json.Unmarshal(jb, payload2) - require.NoError(t, err) - err = signatureVerify(pub, payload2) - require.NoError(t, err) +func equalInfos(a, b *AppLinkInfo) bool { + if a == nil || b == nil { + return a == b + } + // we ignore AppHash because it is filled only on read + return a.AppName == b.AppName && + a.CreatedAt == b.CreatedAt && + a.Scope == b.Scope +} + +func TestGenerateLoad_RoundTrip_V1(t *testing.T) { + // ── arrange keys & temp dir ────────────────────────── + tmp := t.TempDir() + dir := filepath.Join(tmp, appLinkKeysDirectory) + + pk, _, err := crypto.GenerateRandomEd25519KeyPair() + require.NoError(t, err) + + // payload for v1 + want := testInfo() + + info, err := generate(dir, pk, want.AppName, model.AccountAuthLocalApiScope(want.Scope)) + if err != nil { + t.Fatalf("Generate(v1): %v", err) + } + gotV1, err := load(dir, info.AppKey, pk) + if err != nil { + t.Fatalf("Load(v1): %v", err) + } + if !equalInfos(want, gotV1) { + t.Fatalf("v1 payload mismatch.\nwant: %+v\ngot : %+v", want, gotV1) + } +} + +func TestGenerateLoad_RoundTrip_V0(t *testing.T) { + // ── arrange keys & temp dir ────────────────────────── + tmp := t.TempDir() + dir := filepath.Join(tmp, appLinkKeysDirectory) + + // Make sure the directory exists + err := os.MkdirAll(dir, 0o700) + require.NoError(t, err) + + pk, _, err := crypto.GenerateRandomEd25519KeyPair() + require.NoError(t, err) + + // payload for v0 + want := testInfo() + + // ───────────────────────── v0 round-trip ───────────── + appKeyV0, err := writeAppLinkFileV0(pk, dir, want) + if err != nil { + t.Fatalf("writeAppLinkFileV0: %v", err) + } + gotV0, err := load(dir, appKeyV0, pk) + if err != nil { + t.Fatalf("Load(v0): %v", err) + } + if !equalInfos(want, gotV0) { + t.Fatalf("v0 payload mismatch.\nwant: %+v\ngot : %+v", want, gotV0) + } +} + +func TestNoDuplicateKeys_V0_V1(t *testing.T) { + // ── arrange keys & temp dir ────────────────────────── + tmp := t.TempDir() + dir := filepath.Join(tmp, appLinkKeysDirectory) + + // Make sure the directory exists + err := os.MkdirAll(dir, 0o700) + require.NoError(t, err) + + pk, _, err := crypto.GenerateRandomEd25519KeyPair() + require.NoError(t, err) + + // common payload for both versions + want := testInfo() + + // Generate keys for both v0 and v1 + appKeyV1, err := generate(dir, pk, want.AppName, model.AccountAuthLocalApiScope(want.Scope)) + require.NoError(t, err) + + appKeyV0, err := writeAppLinkFileV0(pk, dir, want) + require.NoError(t, err) + + // ───────────────────────── sanity: v0≠v1 keys ──────── + if reflect.DeepEqual(appKeyV0, appKeyV1) { + t.Fatalf("appKey collision between v0 and v1 – should never happen") + } +} + +func TestList(t *testing.T) { + // ── arrange keys & temp dir ────────────────────────── + tmp := t.TempDir() + dir := filepath.Join(tmp, appLinkKeysDirectory) + + // Make sure the directory exists + err := os.MkdirAll(dir, 0o700) + require.NoError(t, err) + + pk, _, err := crypto.GenerateRandomEd25519KeyPair() + require.NoError(t, err) + + // Create v1 entry + info1 := &AppLinkInfo{ + AppName: "app1", + CreatedAt: time.Now().Unix(), + ExpireAt: time.Now().Unix() + 3600, + Scope: 1, + } + info, err := generate(dir, pk, info1.AppName, model.AccountAuthLocalApiScope(info1.Scope)) + require.NoError(t, err) + + // Create v0 entry + info2 := &AppLinkInfo{ + AppName: "app2", + CreatedAt: time.Now().Unix(), + ExpireAt: time.Now().Unix() + 3600, + Scope: 2, + } + appKey2, err := writeAppLinkFileV0(pk, dir, info2) + require.NoError(t, err) + + // List all entries (with account key) + entries, err := list(dir, pk) + require.NoError(t, err) + require.Equal(t, 2, len(entries), "should have found 2 entries") + + // Create maps for easier lookup by AppName + entriesByName := make(map[string]*AppLinkInfo) + for _, entry := range entries { + if entry.AppName != "" { + entriesByName[entry.AppName] = entry + } + } + + // Verify v1 entry has full info + app1Entry, found := entriesByName["app1"] + require.True(t, found, "should have found app1 entry") + require.Equal(t, info1.Scope, app1Entry.Scope) + require.NotEmpty(t, app1Entry.AppHash, "v1 entry should have AppHash") + + // Also verify we can load this entry explicitly with the key + loaded, err := load(dir, info.AppKey, pk) + require.NoError(t, err) + require.Equal(t, info1.AppName, loaded.AppName) + + // Verify v0 entries have AppHash but not other fields + // Since v0 doesn't populate AppName when listing, we need to count entries + // with non-empty AppHash but empty AppName + count := 0 + var v0Entry *AppLinkInfo + for _, entry := range entries { + if entry.AppName == "" && entry.AppHash != "" { + count++ + v0Entry = entry + } + } + require.Equal(t, 1, count, "should have found 1 v0 entry") + require.NotNil(t, v0Entry, "should have a v0 entry") + + // Verify we can load the v0 entry explicitly with the key + loaded, err = load(dir, appKey2, pk) + require.NoError(t, err) + require.Equal(t, info2.AppName, loaded.AppName) + + // Test listing without account key + entriesNoKey, err := list(dir, nil) + require.NoError(t, err) + require.Equal(t, 2, len(entriesNoKey), "should have found 2 entries") + + // All entries should have AppHash but no other fields + for _, entry := range entriesNoKey { + require.NotEmpty(t, entry.AppHash, "entry should have AppHash") + require.Empty(t, entry.AppName, "entry should not have AppName without key") + } +} + +func TestRevoke(t *testing.T) { + // ── arrange keys & temp dir ────────────────────────── + tmp := t.TempDir() + dir := filepath.Join(tmp, appLinkKeysDirectory) + + // Make sure the directory exists + err := os.MkdirAll(dir, 0o700) + require.NoError(t, err) + + pk, _, err := crypto.GenerateRandomEd25519KeyPair() + require.NoError(t, err) + + // Create an app link + info := &AppLinkInfo{ + AppName: "test-app", + CreatedAt: time.Now().Unix(), + ExpireAt: time.Now().Unix() + 3600, + Scope: 1, + } + + // Generate the app link file + _, err = generate(dir, pk, info.AppName, model.AccountAuthLocalApiScope(info.Scope)) + require.NoError(t, err) + + // List entries to get the app hash + entries, err := list(dir, pk) + require.NoError(t, err) + require.Equal(t, 1, len(entries), "should have one entry") + + appHash := entries[0].AppHash + require.NotEmpty(t, appHash, "app hash should not be empty") + + // Verify the file exists + filePath := filepath.Join(dir, appHash+".json") + _, err = os.Stat(filePath) + require.NoError(t, err, "file should exist") + + // Test revoke for existing file + err = revoke(dir, appHash) + require.NoError(t, err, "should successfully revoke existing file") + + // Verify the file no longer exists + _, err = os.Stat(filePath) + require.True(t, os.IsNotExist(err), "file should not exist after revocation") + + // Test revoke for non-existent file + err = revoke(dir, "nonexistent-hash") + require.Equal(t, ErrAppLinkNotFound, err, "should return ErrAppLinkNotFound for non-existent file") + + // Test revoke with empty hash + err = revoke(dir, "") + require.Equal(t, ErrAppLinkNotFound, err, "should return ErrAppLinkNotFound for empty hash") +} + +// writeAppLinkFileV0: legacy support for v0 files. Used for tests +func writeAppLinkFileV0(accountPk crypto.PrivKey, dir string, payload *AppLinkInfo) (appKey string, err error) { + key, err := symmetric.NewRandom() + if err != nil { + return + } + + b, err := json.Marshal(payload) + if err != nil { + return + } + + encPayloadReader, err := gcm.New(key).EncryptReader(bytes.NewReader(b)) + if err != nil { + return "", err + } + + encPayload, err := io.ReadAll(encPayloadReader) + if err != nil { + return "", err + } + + appKey = base64.StdEncoding.EncodeToString(key.Bytes()) + signature, err := accountPk.Sign(encPayload) + + if err != nil { + return "", err + } + encryptedPayload := fileV0{ + Payload: encPayload, + Signature: signature, + } + + hash := sha256.Sum256(key.Bytes()) + f, err := os.Create(filepath.Join(dir, fmt.Sprintf("%x", hash)+".json")) + if err != nil { + return "", fmt.Errorf("failed to create app key file in the account: %w", err) + } + + w := json.NewEncoder(f) + err = w.Encode(encryptedPayload) + if err != nil { + return "", err + } + return appKey, nil } diff --git a/core/wallet/mock_wallet/mock_Wallet.go b/core/wallet/mock_wallet/mock_Wallet.go index 82610f1c8..0f5021870 100644 --- a/core/wallet/mock_wallet/mock_Wallet.go +++ b/core/wallet/mock_wallet/mock_Wallet.go @@ -10,6 +10,8 @@ import ( mock "github.com/stretchr/testify/mock" + model "github.com/anyproto/anytype-heart/pkg/lib/pb/model" + wallet "github.com/anyproto/anytype-heart/core/wallet" ) @@ -446,6 +448,63 @@ func (_c *MockWallet_Init_Call) RunAndReturn(run func(*app.App) error) *MockWall return _c } +// ListAppLinks provides a mock function with given fields: +func (_m *MockWallet) ListAppLinks() ([]*wallet.AppLinkInfo, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ListAppLinks") + } + + var r0 []*wallet.AppLinkInfo + var r1 error + if rf, ok := ret.Get(0).(func() ([]*wallet.AppLinkInfo, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []*wallet.AppLinkInfo); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*wallet.AppLinkInfo) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockWallet_ListAppLinks_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListAppLinks' +type MockWallet_ListAppLinks_Call struct { + *mock.Call +} + +// ListAppLinks is a helper method to define mock.On call +func (_e *MockWallet_Expecter) ListAppLinks() *MockWallet_ListAppLinks_Call { + return &MockWallet_ListAppLinks_Call{Call: _e.mock.On("ListAppLinks")} +} + +func (_c *MockWallet_ListAppLinks_Call) Run(run func()) *MockWallet_ListAppLinks_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *MockWallet_ListAppLinks_Call) Return(_a0 []*wallet.AppLinkInfo, _a1 error) *MockWallet_ListAppLinks_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *MockWallet_ListAppLinks_Call) RunAndReturn(run func() ([]*wallet.AppLinkInfo, error)) *MockWallet_ListAppLinks_Call { + _c.Call.Return(run) + return _c +} + // Name provides a mock function with given fields: func (_m *MockWallet) Name() string { ret := _m.Called() @@ -491,27 +550,29 @@ func (_c *MockWallet_Name_Call) RunAndReturn(run func() string) *MockWallet_Name return _c } -// PersistAppLink provides a mock function with given fields: payload -func (_m *MockWallet) PersistAppLink(payload *wallet.AppLinkPayload) (string, error) { - ret := _m.Called(payload) +// PersistAppLink provides a mock function with given fields: name, scope +func (_m *MockWallet) PersistAppLink(name string, scope model.AccountAuthLocalApiScope) (*wallet.AppLinkInfo, error) { + ret := _m.Called(name, scope) if len(ret) == 0 { panic("no return value specified for PersistAppLink") } - var r0 string + var r0 *wallet.AppLinkInfo var r1 error - if rf, ok := ret.Get(0).(func(*wallet.AppLinkPayload) (string, error)); ok { - return rf(payload) + if rf, ok := ret.Get(0).(func(string, model.AccountAuthLocalApiScope) (*wallet.AppLinkInfo, error)); ok { + return rf(name, scope) } - if rf, ok := ret.Get(0).(func(*wallet.AppLinkPayload) string); ok { - r0 = rf(payload) + if rf, ok := ret.Get(0).(func(string, model.AccountAuthLocalApiScope) *wallet.AppLinkInfo); ok { + r0 = rf(name, scope) } else { - r0 = ret.Get(0).(string) + if ret.Get(0) != nil { + r0 = ret.Get(0).(*wallet.AppLinkInfo) + } } - if rf, ok := ret.Get(1).(func(*wallet.AppLinkPayload) error); ok { - r1 = rf(payload) + if rf, ok := ret.Get(1).(func(string, model.AccountAuthLocalApiScope) error); ok { + r1 = rf(name, scope) } else { r1 = ret.Error(1) } @@ -525,46 +586,47 @@ type MockWallet_PersistAppLink_Call struct { } // PersistAppLink is a helper method to define mock.On call -// - payload *wallet.AppLinkPayload -func (_e *MockWallet_Expecter) PersistAppLink(payload interface{}) *MockWallet_PersistAppLink_Call { - return &MockWallet_PersistAppLink_Call{Call: _e.mock.On("PersistAppLink", payload)} +// - name string +// - scope model.AccountAuthLocalApiScope +func (_e *MockWallet_Expecter) PersistAppLink(name interface{}, scope interface{}) *MockWallet_PersistAppLink_Call { + return &MockWallet_PersistAppLink_Call{Call: _e.mock.On("PersistAppLink", name, scope)} } -func (_c *MockWallet_PersistAppLink_Call) Run(run func(payload *wallet.AppLinkPayload)) *MockWallet_PersistAppLink_Call { +func (_c *MockWallet_PersistAppLink_Call) Run(run func(name string, scope model.AccountAuthLocalApiScope)) *MockWallet_PersistAppLink_Call { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*wallet.AppLinkPayload)) + run(args[0].(string), args[1].(model.AccountAuthLocalApiScope)) }) return _c } -func (_c *MockWallet_PersistAppLink_Call) Return(appKey string, err error) *MockWallet_PersistAppLink_Call { - _c.Call.Return(appKey, err) +func (_c *MockWallet_PersistAppLink_Call) Return(appInfo *wallet.AppLinkInfo, err error) *MockWallet_PersistAppLink_Call { + _c.Call.Return(appInfo, err) return _c } -func (_c *MockWallet_PersistAppLink_Call) RunAndReturn(run func(*wallet.AppLinkPayload) (string, error)) *MockWallet_PersistAppLink_Call { +func (_c *MockWallet_PersistAppLink_Call) RunAndReturn(run func(string, model.AccountAuthLocalApiScope) (*wallet.AppLinkInfo, error)) *MockWallet_PersistAppLink_Call { _c.Call.Return(run) return _c } // ReadAppLink provides a mock function with given fields: appKey -func (_m *MockWallet) ReadAppLink(appKey string) (*wallet.AppLinkPayload, error) { +func (_m *MockWallet) ReadAppLink(appKey string) (*wallet.AppLinkInfo, error) { ret := _m.Called(appKey) if len(ret) == 0 { panic("no return value specified for ReadAppLink") } - var r0 *wallet.AppLinkPayload + var r0 *wallet.AppLinkInfo var r1 error - if rf, ok := ret.Get(0).(func(string) (*wallet.AppLinkPayload, error)); ok { + if rf, ok := ret.Get(0).(func(string) (*wallet.AppLinkInfo, error)); ok { return rf(appKey) } - if rf, ok := ret.Get(0).(func(string) *wallet.AppLinkPayload); ok { + if rf, ok := ret.Get(0).(func(string) *wallet.AppLinkInfo); ok { r0 = rf(appKey) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*wallet.AppLinkPayload) + r0 = ret.Get(0).(*wallet.AppLinkInfo) } } @@ -595,12 +657,12 @@ func (_c *MockWallet_ReadAppLink_Call) Run(run func(appKey string)) *MockWallet_ return _c } -func (_c *MockWallet_ReadAppLink_Call) Return(_a0 *wallet.AppLinkPayload, _a1 error) *MockWallet_ReadAppLink_Call { +func (_c *MockWallet_ReadAppLink_Call) Return(_a0 *wallet.AppLinkInfo, _a1 error) *MockWallet_ReadAppLink_Call { _c.Call.Return(_a0, _a1) return _c } -func (_c *MockWallet_ReadAppLink_Call) RunAndReturn(run func(string) (*wallet.AppLinkPayload, error)) *MockWallet_ReadAppLink_Call { +func (_c *MockWallet_ReadAppLink_Call) RunAndReturn(run func(string) (*wallet.AppLinkInfo, error)) *MockWallet_ReadAppLink_Call { _c.Call.Return(run) return _c } @@ -650,6 +712,52 @@ func (_c *MockWallet_RepoPath_Call) RunAndReturn(run func() string) *MockWallet_ return _c } +// RevokeAppLink provides a mock function with given fields: appHash +func (_m *MockWallet) RevokeAppLink(appHash string) error { + ret := _m.Called(appHash) + + if len(ret) == 0 { + panic("no return value specified for RevokeAppLink") + } + + var r0 error + if rf, ok := ret.Get(0).(func(string) error); ok { + r0 = rf(appHash) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockWallet_RevokeAppLink_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RevokeAppLink' +type MockWallet_RevokeAppLink_Call struct { + *mock.Call +} + +// RevokeAppLink is a helper method to define mock.On call +// - appHash string +func (_e *MockWallet_Expecter) RevokeAppLink(appHash interface{}) *MockWallet_RevokeAppLink_Call { + return &MockWallet_RevokeAppLink_Call{Call: _e.mock.On("RevokeAppLink", appHash)} +} + +func (_c *MockWallet_RevokeAppLink_Call) Run(run func(appHash string)) *MockWallet_RevokeAppLink_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(string)) + }) + return _c +} + +func (_c *MockWallet_RevokeAppLink_Call) Return(_a0 error) *MockWallet_RevokeAppLink_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockWallet_RevokeAppLink_Call) RunAndReturn(run func(string) error) *MockWallet_RevokeAppLink_Call { + _c.Call.Return(run) + return _c +} + // RootPath provides a mock function with given fields: func (_m *MockWallet) RootPath() string { ret := _m.Called() diff --git a/core/wallet/wallet.go b/core/wallet/wallet.go index fa0be7e6c..5d8d0b2d3 100644 --- a/core/wallet/wallet.go +++ b/core/wallet/wallet.go @@ -16,6 +16,7 @@ import ( "github.com/anyproto/anytype-heart/metrics" "github.com/anyproto/anytype-heart/pkg/lib/logging" + "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) const ( @@ -175,8 +176,10 @@ type Wallet interface { GetAccountEthPrivkey() EthPrivateKey GetAccountEthAddress() EthAddress - ReadAppLink(appKey string) (*AppLinkPayload, error) - PersistAppLink(payload *AppLinkPayload) (appKey string, err error) + ReadAppLink(appKey string) (*AppLinkInfo, error) + PersistAppLink(name string, scope model.AccountAuthLocalApiScope) (appInfo *AppLinkInfo, err error) + ListAppLinks() ([]*AppLinkInfo, error) + RevokeAppLink(appHash string) error accountservice.Service app.Component diff --git a/docs/proto.md b/docs/proto.md index 8d6d4d90f..635c225c2 100644 --- a/docs/proto.md +++ b/docs/proto.md @@ -97,10 +97,22 @@ - [Rpc.Account.GetConfig.Get](#anytype-Rpc-Account-GetConfig-Get) - [Rpc.Account.GetConfig.Get.Request](#anytype-Rpc-Account-GetConfig-Get-Request) - [Rpc.Account.LocalLink](#anytype-Rpc-Account-LocalLink) + - [Rpc.Account.LocalLink.CreateApp](#anytype-Rpc-Account-LocalLink-CreateApp) + - [Rpc.Account.LocalLink.CreateApp.Request](#anytype-Rpc-Account-LocalLink-CreateApp-Request) + - [Rpc.Account.LocalLink.CreateApp.Response](#anytype-Rpc-Account-LocalLink-CreateApp-Response) + - [Rpc.Account.LocalLink.CreateApp.Response.Error](#anytype-Rpc-Account-LocalLink-CreateApp-Response-Error) + - [Rpc.Account.LocalLink.ListApps](#anytype-Rpc-Account-LocalLink-ListApps) + - [Rpc.Account.LocalLink.ListApps.Request](#anytype-Rpc-Account-LocalLink-ListApps-Request) + - [Rpc.Account.LocalLink.ListApps.Response](#anytype-Rpc-Account-LocalLink-ListApps-Response) + - [Rpc.Account.LocalLink.ListApps.Response.Error](#anytype-Rpc-Account-LocalLink-ListApps-Response-Error) - [Rpc.Account.LocalLink.NewChallenge](#anytype-Rpc-Account-LocalLink-NewChallenge) - [Rpc.Account.LocalLink.NewChallenge.Request](#anytype-Rpc-Account-LocalLink-NewChallenge-Request) - [Rpc.Account.LocalLink.NewChallenge.Response](#anytype-Rpc-Account-LocalLink-NewChallenge-Response) - [Rpc.Account.LocalLink.NewChallenge.Response.Error](#anytype-Rpc-Account-LocalLink-NewChallenge-Response-Error) + - [Rpc.Account.LocalLink.RevokeApp](#anytype-Rpc-Account-LocalLink-RevokeApp) + - [Rpc.Account.LocalLink.RevokeApp.Request](#anytype-Rpc-Account-LocalLink-RevokeApp-Request) + - [Rpc.Account.LocalLink.RevokeApp.Response](#anytype-Rpc-Account-LocalLink-RevokeApp-Response) + - [Rpc.Account.LocalLink.RevokeApp.Response.Error](#anytype-Rpc-Account-LocalLink-RevokeApp-Response-Error) - [Rpc.Account.LocalLink.SolveChallenge](#anytype-Rpc-Account-LocalLink-SolveChallenge) - [Rpc.Account.LocalLink.SolveChallenge.Request](#anytype-Rpc-Account-LocalLink-SolveChallenge-Request) - [Rpc.Account.LocalLink.SolveChallenge.Response](#anytype-Rpc-Account-LocalLink-SolveChallenge-Response) @@ -582,6 +594,10 @@ - [Rpc.Chat.GetMessagesByIds.Request](#anytype-Rpc-Chat-GetMessagesByIds-Request) - [Rpc.Chat.GetMessagesByIds.Response](#anytype-Rpc-Chat-GetMessagesByIds-Response) - [Rpc.Chat.GetMessagesByIds.Response.Error](#anytype-Rpc-Chat-GetMessagesByIds-Response-Error) + - [Rpc.Chat.ReadAll](#anytype-Rpc-Chat-ReadAll) + - [Rpc.Chat.ReadAll.Request](#anytype-Rpc-Chat-ReadAll-Request) + - [Rpc.Chat.ReadAll.Response](#anytype-Rpc-Chat-ReadAll-Response) + - [Rpc.Chat.ReadAll.Response.Error](#anytype-Rpc-Chat-ReadAll-Response-Error) - [Rpc.Chat.ReadMessages](#anytype-Rpc-Chat-ReadMessages) - [Rpc.Chat.ReadMessages.Request](#anytype-Rpc-Chat-ReadMessages-Request) - [Rpc.Chat.ReadMessages.Response](#anytype-Rpc-Chat-ReadMessages-Response) @@ -1201,6 +1217,10 @@ - [Rpc.Space.Delete.Request](#anytype-Rpc-Space-Delete-Request) - [Rpc.Space.Delete.Response](#anytype-Rpc-Space-Delete-Response) - [Rpc.Space.Delete.Response.Error](#anytype-Rpc-Space-Delete-Response-Error) + - [Rpc.Space.InviteChange](#anytype-Rpc-Space-InviteChange) + - [Rpc.Space.InviteChange.Request](#anytype-Rpc-Space-InviteChange-Request) + - [Rpc.Space.InviteChange.Response](#anytype-Rpc-Space-InviteChange-Response) + - [Rpc.Space.InviteChange.Response.Error](#anytype-Rpc-Space-InviteChange-Response-Error) - [Rpc.Space.InviteGenerate](#anytype-Rpc-Space-InviteGenerate) - [Rpc.Space.InviteGenerate.Request](#anytype-Rpc-Space-InviteGenerate-Request) - [Rpc.Space.InviteGenerate.Response](#anytype-Rpc-Space-InviteGenerate-Response) @@ -1368,7 +1388,10 @@ - [Rpc.Account.Create.Response.Error.Code](#anytype-Rpc-Account-Create-Response-Error-Code) - [Rpc.Account.Delete.Response.Error.Code](#anytype-Rpc-Account-Delete-Response-Error-Code) - [Rpc.Account.EnableLocalNetworkSync.Response.Error.Code](#anytype-Rpc-Account-EnableLocalNetworkSync-Response-Error-Code) + - [Rpc.Account.LocalLink.CreateApp.Response.Error.Code](#anytype-Rpc-Account-LocalLink-CreateApp-Response-Error-Code) + - [Rpc.Account.LocalLink.ListApps.Response.Error.Code](#anytype-Rpc-Account-LocalLink-ListApps-Response-Error-Code) - [Rpc.Account.LocalLink.NewChallenge.Response.Error.Code](#anytype-Rpc-Account-LocalLink-NewChallenge-Response-Error-Code) + - [Rpc.Account.LocalLink.RevokeApp.Response.Error.Code](#anytype-Rpc-Account-LocalLink-RevokeApp-Response-Error-Code) - [Rpc.Account.LocalLink.SolveChallenge.Response.Error.Code](#anytype-Rpc-Account-LocalLink-SolveChallenge-Response-Error-Code) - [Rpc.Account.Migrate.Response.Error.Code](#anytype-Rpc-Account-Migrate-Response-Error-Code) - [Rpc.Account.MigrateCancel.Response.Error.Code](#anytype-Rpc-Account-MigrateCancel-Response-Error-Code) @@ -1485,6 +1508,7 @@ - [Rpc.Chat.EditMessageContent.Response.Error.Code](#anytype-Rpc-Chat-EditMessageContent-Response-Error-Code) - [Rpc.Chat.GetMessages.Response.Error.Code](#anytype-Rpc-Chat-GetMessages-Response-Error-Code) - [Rpc.Chat.GetMessagesByIds.Response.Error.Code](#anytype-Rpc-Chat-GetMessagesByIds-Response-Error-Code) + - [Rpc.Chat.ReadAll.Response.Error.Code](#anytype-Rpc-Chat-ReadAll-Response-Error-Code) - [Rpc.Chat.ReadMessages.ReadType](#anytype-Rpc-Chat-ReadMessages-ReadType) - [Rpc.Chat.ReadMessages.Response.Error.Code](#anytype-Rpc-Chat-ReadMessages-Response-Error-Code) - [Rpc.Chat.SubscribeLastMessages.Response.Error.Code](#anytype-Rpc-Chat-SubscribeLastMessages-Response-Error-Code) @@ -1641,7 +1665,7 @@ - [Rpc.Relation.ListWithValue.Response.Error.Code](#anytype-Rpc-Relation-ListWithValue-Response-Error-Code) - [Rpc.Relation.Options.Response.Error.Code](#anytype-Rpc-Relation-Options-Response-Error-Code) - [Rpc.Space.Delete.Response.Error.Code](#anytype-Rpc-Space-Delete-Response-Error-Code) - - [Rpc.Space.InviteGenerate.Request.InviteType](#anytype-Rpc-Space-InviteGenerate-Request-InviteType) + - [Rpc.Space.InviteChange.Response.Error.Code](#anytype-Rpc-Space-InviteChange-Response-Error-Code) - [Rpc.Space.InviteGenerate.Response.Error.Code](#anytype-Rpc-Space-InviteGenerate-Response-Error-Code) - [Rpc.Space.InviteGetCurrent.Response.Error.Code](#anytype-Rpc-Space-InviteGetCurrent-Response-Error-Code) - [Rpc.Space.InviteGetGuest.Response.Error.Code](#anytype-Rpc-Space-InviteGetGuest-Response-Error-Code) @@ -1923,6 +1947,7 @@ - [pkg/lib/pb/model/protos/models.proto](#pkg_lib_pb_model_protos_models-proto) - [Account](#anytype-model-Account) - [Account.Auth](#anytype-model-Account-Auth) + - [Account.Auth.AppInfo](#anytype-model-Account-Auth-AppInfo) - [Account.Config](#anytype-model-Account-Config) - [Account.Info](#anytype-model-Account-Info) - [Account.Status](#anytype-model-Account-Status) @@ -2060,7 +2085,7 @@ - [Import.ErrorCode](#anytype-model-Import-ErrorCode) - [Import.Type](#anytype-model-Import-Type) - [InternalFlag.Value](#anytype-model-InternalFlag-Value) - - [InvitePayload.InviteType](#anytype-model-InvitePayload-InviteType) + - [InviteType](#anytype-model-InviteType) - [LinkPreview.Type](#anytype-model-LinkPreview-Type) - [Membership.EmailVerificationStatus](#anytype-model-Membership-EmailVerificationStatus) - [Membership.PaymentMethod](#anytype-model-Membership-PaymentMethod) @@ -2117,6 +2142,9 @@ | WalletConvert | [Rpc.Wallet.Convert.Request](#anytype-Rpc-Wallet-Convert-Request) | [Rpc.Wallet.Convert.Response](#anytype-Rpc-Wallet-Convert-Response) | | | AccountLocalLinkNewChallenge | [Rpc.Account.LocalLink.NewChallenge.Request](#anytype-Rpc-Account-LocalLink-NewChallenge-Request) | [Rpc.Account.LocalLink.NewChallenge.Response](#anytype-Rpc-Account-LocalLink-NewChallenge-Response) | | | AccountLocalLinkSolveChallenge | [Rpc.Account.LocalLink.SolveChallenge.Request](#anytype-Rpc-Account-LocalLink-SolveChallenge-Request) | [Rpc.Account.LocalLink.SolveChallenge.Response](#anytype-Rpc-Account-LocalLink-SolveChallenge-Response) | | +| AccountLocalLinkCreateApp | [Rpc.Account.LocalLink.CreateApp.Request](#anytype-Rpc-Account-LocalLink-CreateApp-Request) | [Rpc.Account.LocalLink.CreateApp.Response](#anytype-Rpc-Account-LocalLink-CreateApp-Response) | | +| AccountLocalLinkListApps | [Rpc.Account.LocalLink.ListApps.Request](#anytype-Rpc-Account-LocalLink-ListApps-Request) | [Rpc.Account.LocalLink.ListApps.Response](#anytype-Rpc-Account-LocalLink-ListApps-Response) | | +| AccountLocalLinkRevokeApp | [Rpc.Account.LocalLink.RevokeApp.Request](#anytype-Rpc-Account-LocalLink-RevokeApp-Request) | [Rpc.Account.LocalLink.RevokeApp.Response](#anytype-Rpc-Account-LocalLink-RevokeApp-Response) | | | WalletCreateSession | [Rpc.Wallet.CreateSession.Request](#anytype-Rpc-Wallet-CreateSession-Request) | [Rpc.Wallet.CreateSession.Response](#anytype-Rpc-Wallet-CreateSession-Response) | | | WalletCloseSession | [Rpc.Wallet.CloseSession.Request](#anytype-Rpc-Wallet-CloseSession-Request) | [Rpc.Wallet.CloseSession.Response](#anytype-Rpc-Wallet-CloseSession-Response) | | | WorkspaceCreate | [Rpc.Workspace.Create.Request](#anytype-Rpc-Workspace-Create-Request) | [Rpc.Workspace.Create.Response](#anytype-Rpc-Workspace-Create-Response) | Workspace *** | @@ -2145,6 +2173,7 @@ | AccountChangeNetworkConfigAndRestart | [Rpc.Account.ChangeNetworkConfigAndRestart.Request](#anytype-Rpc-Account-ChangeNetworkConfigAndRestart-Request) | [Rpc.Account.ChangeNetworkConfigAndRestart.Response](#anytype-Rpc-Account-ChangeNetworkConfigAndRestart-Response) | | | SpaceDelete | [Rpc.Space.Delete.Request](#anytype-Rpc-Space-Delete-Request) | [Rpc.Space.Delete.Response](#anytype-Rpc-Space-Delete-Response) | Space *** | | SpaceInviteGenerate | [Rpc.Space.InviteGenerate.Request](#anytype-Rpc-Space-InviteGenerate-Request) | [Rpc.Space.InviteGenerate.Response](#anytype-Rpc-Space-InviteGenerate-Response) | | +| SpaceInviteChange | [Rpc.Space.InviteChange.Request](#anytype-Rpc-Space-InviteChange-Request) | [Rpc.Space.InviteChange.Response](#anytype-Rpc-Space-InviteChange-Response) | | | SpaceInviteGetCurrent | [Rpc.Space.InviteGetCurrent.Request](#anytype-Rpc-Space-InviteGetCurrent-Request) | [Rpc.Space.InviteGetCurrent.Response](#anytype-Rpc-Space-InviteGetCurrent-Response) | | | SpaceInviteGetGuest | [Rpc.Space.InviteGetGuest.Request](#anytype-Rpc-Space-InviteGetGuest-Request) | [Rpc.Space.InviteGetGuest.Response](#anytype-Rpc-Space-InviteGetGuest-Response) | | | SpaceInviteRevoke | [Rpc.Space.InviteRevoke.Request](#anytype-Rpc-Space-InviteRevoke-Request) | [Rpc.Space.InviteRevoke.Response](#anytype-Rpc-Space-InviteRevoke-Response) | | @@ -2398,6 +2427,7 @@ | ChatSubscribeToMessagePreviews | [Rpc.Chat.SubscribeToMessagePreviews.Request](#anytype-Rpc-Chat-SubscribeToMessagePreviews-Request) | [Rpc.Chat.SubscribeToMessagePreviews.Response](#anytype-Rpc-Chat-SubscribeToMessagePreviews-Response) | | | ChatUnsubscribeFromMessagePreviews | [Rpc.Chat.UnsubscribeFromMessagePreviews.Request](#anytype-Rpc-Chat-UnsubscribeFromMessagePreviews-Request) | [Rpc.Chat.UnsubscribeFromMessagePreviews.Response](#anytype-Rpc-Chat-UnsubscribeFromMessagePreviews-Response) | | | ObjectChatAdd | [Rpc.Object.ChatAdd.Request](#anytype-Rpc-Object-ChatAdd-Request) | [Rpc.Object.ChatAdd.Response](#anytype-Rpc-Object-ChatAdd-Response) | | +| ChatReadAll | [Rpc.Chat.ReadAll.Request](#anytype-Rpc-Chat-ReadAll-Request) | [Rpc.Chat.ReadAll.Response](#anytype-Rpc-Chat-ReadAll-Response) | | | AIWritingTools | [Rpc.AI.WritingTools.Request](#anytype-Rpc-AI-WritingTools-Request) | [Rpc.AI.WritingTools.Response](#anytype-Rpc-AI-WritingTools-Response) | mock AI RPCs for compatibility between branches. Not implemented in main | | AIAutofill | [Rpc.AI.Autofill.Request](#anytype-Rpc-AI-Autofill-Request) | [Rpc.AI.Autofill.Response](#anytype-Rpc-AI-Autofill-Response) | | | AIListSummary | [Rpc.AI.ListSummary.Request](#anytype-Rpc-AI-ListSummary-Request) | [Rpc.AI.ListSummary.Response](#anytype-Rpc-AI-ListSummary-Response) | | @@ -3744,6 +3774,115 @@ TODO: Remove this request if we do not need it, GO-1926 + + +### Rpc.Account.LocalLink.CreateApp + + + + + + + + + +### Rpc.Account.LocalLink.CreateApp.Request + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| app | [model.Account.Auth.AppInfo](#anytype-model-Account-Auth-AppInfo) | | | + + + + + + + + +### Rpc.Account.LocalLink.CreateApp.Response + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [Rpc.Account.LocalLink.CreateApp.Response.Error](#anytype-Rpc-Account-LocalLink-CreateApp-Response-Error) | | | +| appKey | [string](#string) | | persistent key, that can be used to restore session via CreateSession or for JSON API | + + + + + + + + +### Rpc.Account.LocalLink.CreateApp.Response.Error + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| code | [Rpc.Account.LocalLink.CreateApp.Response.Error.Code](#anytype-Rpc-Account-LocalLink-CreateApp-Response-Error-Code) | | | +| description | [string](#string) | | | + + + + + + + + +### Rpc.Account.LocalLink.ListApps + + + + + + + + + +### Rpc.Account.LocalLink.ListApps.Request + + + + + + + + + +### Rpc.Account.LocalLink.ListApps.Response + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [Rpc.Account.LocalLink.ListApps.Response.Error](#anytype-Rpc-Account-LocalLink-ListApps-Response-Error) | | | +| app | [model.Account.Auth.AppInfo](#anytype-model-Account-Auth-AppInfo) | repeated | | + + + + + + + + +### Rpc.Account.LocalLink.ListApps.Response.Error + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| code | [Rpc.Account.LocalLink.ListApps.Response.Error.Code](#anytype-Rpc-Account-LocalLink-ListApps-Response-Error-Code) | | | +| description | [string](#string) | | | + + + + + + ### Rpc.Account.LocalLink.NewChallenge @@ -3802,6 +3941,62 @@ TODO: Remove this request if we do not need it, GO-1926 + + +### Rpc.Account.LocalLink.RevokeApp + + + + + + + + + +### Rpc.Account.LocalLink.RevokeApp.Request + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| appHash | [string](#string) | | | + + + + + + + + +### Rpc.Account.LocalLink.RevokeApp.Response + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [Rpc.Account.LocalLink.RevokeApp.Response.Error](#anytype-Rpc-Account-LocalLink-RevokeApp-Response-Error) | | | + + + + + + + + +### Rpc.Account.LocalLink.RevokeApp.Response.Error + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| code | [Rpc.Account.LocalLink.RevokeApp.Response.Error.Code](#anytype-Rpc-Account-LocalLink-RevokeApp-Response-Error-Code) | | | +| description | [string](#string) | | | + + + + + + ### Rpc.Account.LocalLink.SolveChallenge @@ -10855,6 +11050,57 @@ Get marks list in the selected range in text block. + + +### Rpc.Chat.ReadAll + + + + + + + + + +### Rpc.Chat.ReadAll.Request + + + + + + + + + +### Rpc.Chat.ReadAll.Response + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [Rpc.Chat.ReadAll.Response.Error](#anytype-Rpc-Chat-ReadAll-Response-Error) | | | + + + + + + + + +### Rpc.Chat.ReadAll.Response.Error + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| code | [Rpc.Chat.ReadAll.Response.Error.Code](#anytype-Rpc-Chat-ReadAll-Response-Error-Code) | | | +| description | [string](#string) | | | + + + + + + ### Rpc.Chat.ReadMessages @@ -19845,6 +20091,63 @@ Available undo/redo operations + + +### Rpc.Space.InviteChange + + + + + + + + + +### Rpc.Space.InviteChange.Request + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| spaceId | [string](#string) | | | +| permissions | [model.ParticipantPermissions](#anytype-model-ParticipantPermissions) | | | + + + + + + + + +### Rpc.Space.InviteChange.Response + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| error | [Rpc.Space.InviteChange.Response.Error](#anytype-Rpc-Space-InviteChange-Response-Error) | | | + + + + + + + + +### Rpc.Space.InviteChange.Response.Error + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| code | [Rpc.Space.InviteChange.Response.Error.Code](#anytype-Rpc-Space-InviteChange-Response-Error-Code) | | | +| description | [string](#string) | | | + + + + + + ### Rpc.Space.InviteGenerate @@ -19864,7 +20167,8 @@ Available undo/redo operations | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | | spaceId | [string](#string) | | | -| inviteType | [Rpc.Space.InviteGenerate.Request.InviteType](#anytype-Rpc-Space-InviteGenerate-Request-InviteType) | | | +| inviteType | [model.InviteType](#anytype-model-InviteType) | | | +| permissions | [model.ParticipantPermissions](#anytype-model-ParticipantPermissions) | | | @@ -19882,6 +20186,8 @@ Available undo/redo operations | error | [Rpc.Space.InviteGenerate.Response.Error](#anytype-Rpc-Space-InviteGenerate-Response-Error) | | | | inviteCid | [string](#string) | | | | inviteFileKey | [string](#string) | | | +| inviteType | [model.InviteType](#anytype-model-InviteType) | | | +| permissions | [model.ParticipantPermissions](#anytype-model-ParticipantPermissions) | | | @@ -19940,6 +20246,8 @@ Available undo/redo operations | error | [Rpc.Space.InviteGetCurrent.Response.Error](#anytype-Rpc-Space-InviteGetCurrent-Response-Error) | | | | inviteCid | [string](#string) | | | | inviteFileKey | [string](#string) | | | +| inviteType | [model.InviteType](#anytype-model-InviteType) | | | +| permissions | [model.ParticipantPermissions](#anytype-model-ParticipantPermissions) | | | @@ -20115,7 +20423,8 @@ Available undo/redo operations | spaceName | [string](#string) | | | | spaceIconCid | [string](#string) | | | | creatorName | [string](#string) | | | -| isGuestUserInvite | [bool](#bool) | | | +| isGuestUserInvite | [bool](#bool) | | deprecated, use inviteType | +| inviteType | [model.InviteType](#anytype-model-InviteType) | | | @@ -22273,6 +22582,34 @@ Middleware-to-front-end response, that can contain a NULL error or a non-NULL er + + +### Rpc.Account.LocalLink.CreateApp.Response.Error.Code + + +| Name | Number | Description | +| ---- | ------ | ----------- | +| NULL | 0 | | +| UNKNOWN_ERROR | 1 | | +| BAD_INPUT | 2 | | +| ACCOUNT_IS_NOT_RUNNING | 101 | | + + + + + +### Rpc.Account.LocalLink.ListApps.Response.Error.Code + + +| Name | Number | Description | +| ---- | ------ | ----------- | +| NULL | 0 | | +| UNKNOWN_ERROR | 1 | | +| BAD_INPUT | 2 | | +| ACCOUNT_IS_NOT_RUNNING | 101 | | + + + ### Rpc.Account.LocalLink.NewChallenge.Response.Error.Code @@ -22288,6 +22625,21 @@ Middleware-to-front-end response, that can contain a NULL error or a non-NULL er + + +### Rpc.Account.LocalLink.RevokeApp.Response.Error.Code + + +| Name | Number | Description | +| ---- | ------ | ----------- | +| NULL | 0 | | +| UNKNOWN_ERROR | 1 | | +| BAD_INPUT | 2 | | +| NOT_FOUND | 3 | | +| ACCOUNT_IS_NOT_RUNNING | 101 | | + + + ### Rpc.Account.LocalLink.SolveChallenge.Response.Error.Code @@ -23831,6 +24183,19 @@ Middleware-to-front-end response, that can contain a NULL error or a non-NULL er + + +### Rpc.Chat.ReadAll.Response.Error.Code + + +| Name | Number | Description | +| ---- | ------ | ----------- | +| NULL | 0 | | +| UNKNOWN_ERROR | 1 | | +| BAD_INPUT | 2 | ... | + + + ### Rpc.Chat.ReadMessages.ReadType @@ -25985,15 +26350,20 @@ Middleware-to-front-end response, that can contain a NULL error or a non-NULL er - + -### Rpc.Space.InviteGenerate.Request.InviteType +### Rpc.Space.InviteChange.Response.Error.Code | Name | Number | Description | | ---- | ------ | ----------- | -| Member | 0 | | -| Guest | 1 | | +| NULL | 0 | | +| UNKNOWN_ERROR | 1 | | +| BAD_INPUT | 2 | | +| NO_SUCH_SPACE | 101 | | +| SPACE_IS_DELETED | 102 | | +| REQUEST_FAILED | 103 | | +| INCORRECT_PERMISSIONS | 105 | | @@ -26659,6 +27029,7 @@ Event – type of message, that could be sent from a middleware to the correspon | ----- | ---- | ----- | ----------- | | processName | [string](#string) | | | | processPath | [string](#string) | | | +| name | [string](#string) | | | | signatureVerified | [bool](#bool) | | | @@ -27005,6 +27376,7 @@ sent when the view have been changed or added | cardSize | [model.Block.Content.Dataview.View.Size](#anytype-model-Block-Content-Dataview-View-Size) | | Gallery card size | | coverFit | [bool](#bool) | | Image fits container | | groupRelationKey | [string](#string) | | Group view by this relationKey | +| endRelationKey | [string](#string) | | | | groupBackgroundColors | [bool](#bool) | | Enable backgrounds in groups | | pageLimit | [int32](#int32) | | Limit of objects shown in widget | | defaultTemplateId | [string](#string) | | Id of template object set default for the view | @@ -30320,6 +30692,27 @@ Contains basic information about a user account + + +### Account.Auth.AppInfo + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| appHash | [string](#string) | | | +| appName | [string](#string) | | either from process or specified manually when creating | +| appKey | [string](#string) | | | +| createdAt | [int64](#int64) | | | +| expireAt | [int64](#int64) | | | +| scope | [Account.Auth.LocalApiScope](#anytype-model-Account-Auth-LocalApiScope) | | | +| isActive | [bool](#bool) | | | + + + + + + ### Account.Config @@ -30689,6 +31082,7 @@ deprecated | | pageLimit | [int32](#int32) | | Limit of objects shown in widget | | defaultTemplateId | [string](#string) | | Default template that is chosen for new object created within the view | | defaultObjectTypeId | [string](#string) | | Default object type that is chosen for new object created within the view | +| endRelationKey | [string](#string) | | Group view by this relationKey | @@ -31296,7 +31690,7 @@ Used to decode block meta only, without the content itself | spaceName | [string](#string) | | | | spaceIconCid | [string](#string) | | | | spaceIconEncryptionKeys | [FileEncryptionKey](#anytype-model-FileEncryptionKey) | repeated | | -| inviteType | [InvitePayload.InviteType](#anytype-model-InvitePayload-InviteType) | | | +| inviteType | [InviteType](#anytype-model-InviteType) | | | | guestKey | [bytes](#bytes) | | | @@ -32680,15 +33074,16 @@ Look https://github.com/golang/protobuf/issues/1135 for more information. - + -### InvitePayload.InviteType +### InviteType | Name | Number | Description | | ---- | ------ | ----------- | -| JoinAsMember | 0 | aclKey contains the key to sign the ACL record | -| JoinAsGuest | 1 | guestKey contains the privateKey of the guest user | +| Member | 0 | aclKey contains the key to sign the ACL record | +| Guest | 1 | guestKey contains the privateKey of the guest user | +| WithoutApprove | 2 | aclKey contains the key to sign the ACL record, but no approval needed | diff --git a/go.mod b/go.mod index 409fe3818..614dba328 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/PuerkitoBio/goquery v1.10.2 github.com/VividCortex/ewma v1.2.0 github.com/adrium/goheif v0.0.0-20230113233934-ca402e77a786 - github.com/anyproto/any-store v0.1.13 - github.com/anyproto/any-sync v0.7.5 + github.com/anyproto/any-store v0.2.1 + github.com/anyproto/any-sync v0.8.1 github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250131145601-de288583ff2a github.com/anyproto/anytype-push-server/pushclient v0.0.0-20250402124745-6451298047f7 github.com/anyproto/go-chash v0.1.0 @@ -16,7 +16,7 @@ require ( github.com/anyproto/go-slip10 v1.0.0 github.com/anyproto/lexid v0.0.4 github.com/anyproto/protobuf v1.3.3-0.20240814124528-72b8c7e0e0f5 - github.com/anyproto/tantivy-go v1.0.1 + github.com/anyproto/tantivy-go v1.0.2 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de github.com/avast/retry-go/v4 v4.6.1 github.com/chai2010/webp v1.1.2-0.20240612091223-aa1b379218b7 @@ -43,6 +43,7 @@ require ( github.com/golang/snappy v1.0.0 github.com/google/uuid v1.6.0 github.com/gosimple/slug v1.15.0 + github.com/gosimple/unidecode v1.0.1 github.com/grokify/html-strip-tags-go v0.1.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 @@ -94,8 +95,6 @@ require ( github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef github.com/stretchr/testify v1.10.0 - github.com/swaggo/files v1.0.1 - github.com/swaggo/gin-swagger v1.6.0 github.com/swaggo/swag/v2 v2.0.0-rc4 github.com/uber/jaeger-client-go v2.30.0+incompatible github.com/valyala/fastjson v1.6.4 @@ -107,7 +106,7 @@ require ( go.uber.org/mock v0.5.2 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 - golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 + golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 golang.org/x/image v0.27.0 golang.org/x/mobile v0.0.0-20250218173827-cd096645fcd3 golang.org/x/net v0.40.0 @@ -193,7 +192,6 @@ require ( github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e // indirect github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c // indirect github.com/gorilla/css v1.0.1 // indirect - github.com/gosimple/unidecode v1.0.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/holiman/uint256 v1.2.4 // indirect @@ -261,7 +259,6 @@ require ( github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/sv-tools/openapi v0.2.1 // indirect - github.com/swaggo/swag v1.16.4 // indirect github.com/tetratelabs/wazero v1.8.1 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect @@ -292,9 +289,9 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect lukechampine.com/blake3 v1.4.0 // indirect - modernc.org/libc v1.62.1 // indirect + modernc.org/libc v1.65.6 // indirect modernc.org/mathutil v1.7.1 // indirect - modernc.org/memory v1.9.1 // indirect + modernc.org/memory v1.10.0 // indirect modernc.org/sqlite v1.37.0 // indirect nhooyr.io/websocket v1.8.7 // indirect ) diff --git a/go.sum b/go.sum index e1603a425..1e7e0cf46 100644 --- a/go.sum +++ b/go.sum @@ -78,16 +78,10 @@ github.com/alexbrainman/goissue34681 v0.0.0-20191006012335-3fc7a47baff5/go.mod h github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kktS1LM= github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA= -github.com/anyproto/any-store v0.1.13 h1:1wmm0qQIRShaycBLKwcgkQbRKy3WrNPAShTE5fwzfCY= -github.com/anyproto/any-store v0.1.13/go.mod h1:2M0Xf4rmijoKGd+nqqeKG8I1yIokCLEIxrAXEoHjXn4= -github.com/anyproto/any-sync v0.6.15 h1:fxZHjiMcZJzJqzBprBNTYmm0MV8Y7NgIGPfLxlsgnWk= -github.com/anyproto/any-sync v0.6.15/go.mod h1:TSKgCoTV40Bt8AfCh3RxPUUAfYGrhc8Mzh8/AiVlvX4= -github.com/anyproto/any-sync v0.7.2 h1:S1UPzW0iYTLwsMAZ3rN/EJwthTGuadsvXdnGYNiC6cA= -github.com/anyproto/any-sync v0.7.2/go.mod h1:TSKgCoTV40Bt8AfCh3RxPUUAfYGrhc8Mzh8/AiVlvX4= -github.com/anyproto/any-sync v0.7.4 h1:pEkPn1fxJGvSGlsnAOy0lWVaqRgymyddmNy7T9toUQk= -github.com/anyproto/any-sync v0.7.4/go.mod h1:TSKgCoTV40Bt8AfCh3RxPUUAfYGrhc8Mzh8/AiVlvX4= -github.com/anyproto/any-sync v0.7.5 h1:VHayuacVpa2eRu5ubxCwrL3l0f/OSN7p45L8TxnaJEw= -github.com/anyproto/any-sync v0.7.5/go.mod h1:02tMeQ6s/tneWLhoyzvy/ocGswICtvI48kdwTU8hQf8= +github.com/anyproto/any-store v0.2.1 h1:U5UpUNk2U7pjJFgvw+f0f54pJW94YK4Qyd97eRoWSvc= +github.com/anyproto/any-store v0.2.1/go.mod h1:tfmQEKqqtT+zzkTWANTHxWxB1E3OHcn9RHxhdBZ/KSk= +github.com/anyproto/any-sync v0.8.1 h1:uK6o/z9GrFsmnnpWoXj9KSrslRGBTPexsaTuvFrZank= +github.com/anyproto/any-sync v0.8.1/go.mod h1:G6i3PT6pN6lcC5rim5Ed7ppUPuQgU5PyHgiqskrggL0= github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250131145601-de288583ff2a h1:ZZM+0OUCQMWSLSflpkf0ZMVo3V76qEDDIXPpQOClNs0= github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250131145601-de288583ff2a/go.mod h1:4fkueCZcGniSMXkrwESO8zzERrh/L7WHimRNWecfGM0= github.com/anyproto/anytype-push-server/pushclient v0.0.0-20250402124745-6451298047f7 h1:oKkEnxnN1jeB1Ty20CTMH3w4WkCrV8dOQy1Myetg7XA= @@ -118,8 +112,8 @@ github.com/anyproto/protobuf v1.3.3-0.20240814124528-72b8c7e0e0f5 h1:aY7tBzQ+z8H github.com/anyproto/protobuf v1.3.3-0.20240814124528-72b8c7e0e0f5/go.mod h1:5+PHE01DgsDPkralb8MYmGg2sPQahsqEJ9ue7ciDHKg= github.com/anyproto/ristretto v0.1.2-0.20240221153107-2b23839cc50c h1:GicoaTUyB2mtCIl3YMrO0OzysqRT5GA4vuvDsqEkhSM= github.com/anyproto/ristretto v0.1.2-0.20240221153107-2b23839cc50c/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/anyproto/tantivy-go v1.0.1 h1:Uc9WqwGEDsVUEwRgSg4nmhoW20GjMUBKRz5FYw4r+ns= -github.com/anyproto/tantivy-go v1.0.1/go.mod h1:LtipOpRjGtcYMGcop6gQN7rVl1Pc6BlIs9BTMqeWMsk= +github.com/anyproto/tantivy-go v1.0.2 h1:PVr4Tt4QH0JAZDs2Z9T4KJfLL+0mgXizj2Y5LSvEQdU= +github.com/anyproto/tantivy-go v1.0.2/go.mod h1:LtipOpRjGtcYMGcop6gQN7rVl1Pc6BlIs9BTMqeWMsk= github.com/anyproto/zeroconf/v2 v2.2.1-0.20240228113933-f90a5cc4439d h1:5bj7nX/AS8sxGpTIrapE7PC4oPlhkHMwMqXlJbUHBlg= github.com/anyproto/zeroconf/v2 v2.2.1-0.20240228113933-f90a5cc4439d/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= @@ -318,8 +312,6 @@ github.com/gammazero/chanqueue v1.1.0/go.mod h1:fMwpwEiuUgpab0sH4VHiVcEoji1pSi+E github.com/gammazero/deque v1.0.0 h1:LTmimT8H7bXkkCy6gZX7zNLtkbz4NdS2z8LZuor3j34= github.com/gammazero/deque v1.0.0/go.mod h1:iflpYvtGfM3U8S8j+sZEKIak3SAKYpA5/SQewgfXDKo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= -github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= @@ -1058,12 +1050,6 @@ github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8 github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/sv-tools/openapi v0.2.1 h1:ES1tMQMJFGibWndMagvdoo34T1Vllxr1Nlm5wz6b1aA= github.com/sv-tools/openapi v0.2.1/go.mod h1:k5VuZamTw1HuiS9p2Wl5YIDWzYnHG6/FgPOSFXLAhGg= -github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= -github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= -github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= -github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= -github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= -github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= github.com/swaggo/swag/v2 v2.0.0-rc4 h1:SZ8cK68gcV6cslwrJMIOqPkJELRwq4gmjvk77MrvHvY= github.com/swaggo/swag/v2 v2.0.0-rc4/go.mod h1:Ow7Y8gF16BTCDn8YxZbyKn8FkMLRUHekv1kROJZpbvE= github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= @@ -1216,8 +1202,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw= -golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= -golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= +golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -1693,20 +1679,20 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= lukechampine.com/blake3 v1.4.0 h1:xDbKOZCVbnZsfzM6mHSYcGRHZ3YrLDzqz8XnV4uaD5w= lukechampine.com/blake3 v1.4.0/go.mod h1:MQJNQCTnR+kwOP/JEZSxj3MaQjp80FOFSNMMHXcSeX0= -modernc.org/cc/v4 v4.25.2 h1:T2oH7sZdGvTaie0BRNFbIYsabzCxUQg8nLqCdQ2i0ic= -modernc.org/cc/v4 v4.25.2/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.25.1 h1:TFSzPrAGmDsdnhT9X2UrcPMI3N/mJ9/X9ykKXwLhDsU= -modernc.org/ccgo/v4 v4.25.1/go.mod h1:njjuAYiPflywOOrm3B7kCB444ONP5pAVr8PIEoE0uDw= -modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= -modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= +modernc.org/cc/v4 v4.26.1 h1:+X5NtzVBn0KgsBCBe+xkDC7twLb/jNVj9FPgiwSQO3s= +modernc.org/cc/v4 v4.26.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.28.0 h1:rjznn6WWehKq7dG4JtLRKxb52Ecv8OUGah8+Z/SfpNU= +modernc.org/ccgo/v4 v4.28.0/go.mod h1:JygV3+9AV6SmPhDasu4JgquwU81XAKLd3OKTUDNOiKE= +modernc.org/fileutil v1.3.1 h1:8vq5fe7jdtEvoCf3Zf9Nm0Q05sH6kGx0Op2CPx1wTC8= +modernc.org/fileutil v1.3.1/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/libc v1.62.1 h1:s0+fv5E3FymN8eJVmnk0llBe6rOxCu/DEU+XygRbS8s= -modernc.org/libc v1.62.1/go.mod h1:iXhATfJQLjG3NWy56a6WVU73lWOcdYVxsvwCgoPljuo= +modernc.org/libc v1.65.6 h1:OhJUhmuJ6MVZdqL5qmnd0/my46DKGFhSX4WOR7ijfyE= +modernc.org/libc v1.65.6/go.mod h1:MOiGAM9lrMBT9L8xT1nO41qYl5eg9gCp9/kWhz5L7WA= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= -modernc.org/memory v1.9.1 h1:V/Z1solwAVmMW1yttq3nDdZPJqV1rM05Ccq6KMSZ34g= -modernc.org/memory v1.9.1/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= +modernc.org/memory v1.10.0 h1:fzumd51yQ1DxcOxSO+S6X7+QTuVU+n8/Aj7swYjFfC4= +modernc.org/memory v1.10.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw= modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= diff --git a/makefiles/tools.mk b/makefiles/tools.mk index 81ec1c41a..82135c0c8 100644 --- a/makefiles/tools.mk +++ b/makefiles/tools.mk @@ -10,8 +10,11 @@ lint: @echo 'Linting with golint...' @golint `go list ./... | grep -v /vendor/` -swagger: - @echo 'Generating swagger docs...' - @swag init --v3.1 -q -d core/api -g service.go -o core/api/docs - @echo 'Formatting swagger docs...' - @swag fmt -d core/api +openapi: + @echo 'Generating openapi docs...' + @swag init --v3.1 -q -d core/api -g service.go -o $(OPENAPI_DOCS_DIR) + @mv $(OPENAPI_DOCS_DIR)/swagger.yaml $(OPENAPI_DOCS_DIR)/openapi.yaml + @mv $(OPENAPI_DOCS_DIR)/swagger.json $(OPENAPI_DOCS_DIR)/openapi.json + @jq . "$(OPENAPI_DOCS_DIR)/openapi.json" > "$(OPENAPI_DOCS_DIR)/pretty.json" && mv "$(OPENAPI_DOCS_DIR)/pretty.json" "$(OPENAPI_DOCS_DIR)/openapi.json" + @echo 'Formatting openapi docs...' + @swag fmt -d core/api \ No newline at end of file diff --git a/makefiles/vars.mk b/makefiles/vars.mk index d7183e2c0..b5801062b 100644 --- a/makefiles/vars.mk +++ b/makefiles/vars.mk @@ -1,4 +1,5 @@ CUSTOM_NETWORK_FILE ?= ./core/anytype/config/nodes/custom.yml +OPENAPI_DOCS_DIR ?= ./core/api/docs CLIENT_DESKTOP_PATH ?= ../anytype-ts CLIENT_ANDROID_PATH ?= ../anytype-kotlin CLIENT_IOS_PATH ?= ../anytype-swift diff --git a/pb/commands.pb.go b/pb/commands.pb.go index 665687050..c56b15713 100644 --- a/pb/commands.pb.go +++ b/pb/commands.pb.go @@ -221,29 +221,44 @@ func (RpcSpaceMakeShareableResponseErrorCode) EnumDescriptor() ([]byte, []int) { return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 1, 1, 0, 0} } -type RpcSpaceInviteGenerateRequestInviteType int32 +type RpcSpaceInviteChangeResponseErrorCode int32 const ( - RpcSpaceInviteGenerateRequest_Member RpcSpaceInviteGenerateRequestInviteType = 0 - RpcSpaceInviteGenerateRequest_Guest RpcSpaceInviteGenerateRequestInviteType = 1 + RpcSpaceInviteChangeResponseError_NULL RpcSpaceInviteChangeResponseErrorCode = 0 + RpcSpaceInviteChangeResponseError_UNKNOWN_ERROR RpcSpaceInviteChangeResponseErrorCode = 1 + RpcSpaceInviteChangeResponseError_BAD_INPUT RpcSpaceInviteChangeResponseErrorCode = 2 + RpcSpaceInviteChangeResponseError_NO_SUCH_SPACE RpcSpaceInviteChangeResponseErrorCode = 101 + RpcSpaceInviteChangeResponseError_SPACE_IS_DELETED RpcSpaceInviteChangeResponseErrorCode = 102 + RpcSpaceInviteChangeResponseError_REQUEST_FAILED RpcSpaceInviteChangeResponseErrorCode = 103 + RpcSpaceInviteChangeResponseError_INCORRECT_PERMISSIONS RpcSpaceInviteChangeResponseErrorCode = 105 ) -var RpcSpaceInviteGenerateRequestInviteType_name = map[int32]string{ - 0: "Member", - 1: "Guest", +var RpcSpaceInviteChangeResponseErrorCode_name = map[int32]string{ + 0: "NULL", + 1: "UNKNOWN_ERROR", + 2: "BAD_INPUT", + 101: "NO_SUCH_SPACE", + 102: "SPACE_IS_DELETED", + 103: "REQUEST_FAILED", + 105: "INCORRECT_PERMISSIONS", } -var RpcSpaceInviteGenerateRequestInviteType_value = map[string]int32{ - "Member": 0, - "Guest": 1, +var RpcSpaceInviteChangeResponseErrorCode_value = map[string]int32{ + "NULL": 0, + "UNKNOWN_ERROR": 1, + "BAD_INPUT": 2, + "NO_SUCH_SPACE": 101, + "SPACE_IS_DELETED": 102, + "REQUEST_FAILED": 103, + "INCORRECT_PERMISSIONS": 105, } -func (x RpcSpaceInviteGenerateRequestInviteType) String() string { - return proto.EnumName(RpcSpaceInviteGenerateRequestInviteType_name, int32(x)) +func (x RpcSpaceInviteChangeResponseErrorCode) String() string { + return proto.EnumName(RpcSpaceInviteChangeResponseErrorCode_name, int32(x)) } -func (RpcSpaceInviteGenerateRequestInviteType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 2, 0, 0} +func (RpcSpaceInviteChangeResponseErrorCode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 2, 1, 0, 0} } type RpcSpaceInviteGenerateResponseErrorCode int32 @@ -286,7 +301,7 @@ func (x RpcSpaceInviteGenerateResponseErrorCode) String() string { } func (RpcSpaceInviteGenerateResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 2, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 3, 1, 0, 0} } type RpcSpaceStopSharingResponseErrorCode int32 @@ -326,7 +341,7 @@ func (x RpcSpaceStopSharingResponseErrorCode) String() string { } func (RpcSpaceStopSharingResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 3, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 4, 1, 0, 0} } type RpcSpaceInviteGetCurrentResponseErrorCode int32 @@ -357,7 +372,7 @@ func (x RpcSpaceInviteGetCurrentResponseErrorCode) String() string { } func (RpcSpaceInviteGetCurrentResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 4, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 5, 1, 0, 0} } type RpcSpaceInviteGetGuestResponseErrorCode int32 @@ -388,7 +403,7 @@ func (x RpcSpaceInviteGetGuestResponseErrorCode) String() string { } func (RpcSpaceInviteGetGuestResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 5, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 6, 1, 0, 0} } type RpcSpaceInviteRevokeResponseErrorCode int32 @@ -431,7 +446,7 @@ func (x RpcSpaceInviteRevokeResponseErrorCode) String() string { } func (RpcSpaceInviteRevokeResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 6, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 7, 1, 0, 0} } type RpcSpaceInviteViewResponseErrorCode int32 @@ -468,7 +483,7 @@ func (x RpcSpaceInviteViewResponseErrorCode) String() string { } func (RpcSpaceInviteViewResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 7, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 8, 1, 0, 0} } type RpcSpaceJoinResponseErrorCode int32 @@ -520,7 +535,7 @@ func (x RpcSpaceJoinResponseErrorCode) String() string { } func (RpcSpaceJoinResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 8, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 9, 1, 0, 0} } type RpcSpaceJoinCancelResponseErrorCode int32 @@ -566,7 +581,7 @@ func (x RpcSpaceJoinCancelResponseErrorCode) String() string { } func (RpcSpaceJoinCancelResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 9, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 10, 1, 0, 0} } type RpcSpaceRequestApproveResponseErrorCode int32 @@ -615,7 +630,7 @@ func (x RpcSpaceRequestApproveResponseErrorCode) String() string { } func (RpcSpaceRequestApproveResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 10, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 11, 1, 0, 0} } type RpcSpaceRequestDeclineResponseErrorCode int32 @@ -661,7 +676,7 @@ func (x RpcSpaceRequestDeclineResponseErrorCode) String() string { } func (RpcSpaceRequestDeclineResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 11, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 12, 1, 0, 0} } type RpcSpaceParticipantRemoveResponseErrorCode int32 @@ -707,7 +722,7 @@ func (x RpcSpaceParticipantRemoveResponseErrorCode) String() string { } func (RpcSpaceParticipantRemoveResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 12, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 13, 1, 0, 0} } type RpcSpaceParticipantPermissionsChangeResponseErrorCode int32 @@ -756,7 +771,7 @@ func (x RpcSpaceParticipantPermissionsChangeResponseErrorCode) String() string { } func (RpcSpaceParticipantPermissionsChangeResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 13, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 14, 1, 0, 0} } type RpcSpaceDeleteResponseErrorCode int32 @@ -799,7 +814,7 @@ func (x RpcSpaceDeleteResponseErrorCode) String() string { } func (RpcSpaceDeleteResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 14, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 15, 1, 0, 0} } type RpcSpaceSetOrderResponseErrorCode int32 @@ -827,7 +842,7 @@ func (x RpcSpaceSetOrderResponseErrorCode) String() string { } func (RpcSpaceSetOrderResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 15, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 16, 1, 0, 0} } type RpcSpaceUnsetOrderResponseErrorCode int32 @@ -855,7 +870,7 @@ func (x RpcSpaceUnsetOrderResponseErrorCode) String() string { } func (RpcSpaceUnsetOrderResponseErrorCode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 16, 1, 0, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 17, 1, 0, 0} } type RpcWalletCreateResponseErrorCode int32 @@ -1754,6 +1769,102 @@ func (RpcAccountLocalLinkSolveChallengeResponseErrorCode) EnumDescriptor() ([]by return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 1, 1, 0, 0} } +type RpcAccountLocalLinkListAppsResponseErrorCode int32 + +const ( + RpcAccountLocalLinkListAppsResponseError_NULL RpcAccountLocalLinkListAppsResponseErrorCode = 0 + RpcAccountLocalLinkListAppsResponseError_UNKNOWN_ERROR RpcAccountLocalLinkListAppsResponseErrorCode = 1 + RpcAccountLocalLinkListAppsResponseError_BAD_INPUT RpcAccountLocalLinkListAppsResponseErrorCode = 2 + RpcAccountLocalLinkListAppsResponseError_ACCOUNT_IS_NOT_RUNNING RpcAccountLocalLinkListAppsResponseErrorCode = 101 +) + +var RpcAccountLocalLinkListAppsResponseErrorCode_name = map[int32]string{ + 0: "NULL", + 1: "UNKNOWN_ERROR", + 2: "BAD_INPUT", + 101: "ACCOUNT_IS_NOT_RUNNING", +} + +var RpcAccountLocalLinkListAppsResponseErrorCode_value = map[string]int32{ + "NULL": 0, + "UNKNOWN_ERROR": 1, + "BAD_INPUT": 2, + "ACCOUNT_IS_NOT_RUNNING": 101, +} + +func (x RpcAccountLocalLinkListAppsResponseErrorCode) String() string { + return proto.EnumName(RpcAccountLocalLinkListAppsResponseErrorCode_name, int32(x)) +} + +func (RpcAccountLocalLinkListAppsResponseErrorCode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 2, 1, 0, 0} +} + +type RpcAccountLocalLinkCreateAppResponseErrorCode int32 + +const ( + RpcAccountLocalLinkCreateAppResponseError_NULL RpcAccountLocalLinkCreateAppResponseErrorCode = 0 + RpcAccountLocalLinkCreateAppResponseError_UNKNOWN_ERROR RpcAccountLocalLinkCreateAppResponseErrorCode = 1 + RpcAccountLocalLinkCreateAppResponseError_BAD_INPUT RpcAccountLocalLinkCreateAppResponseErrorCode = 2 + RpcAccountLocalLinkCreateAppResponseError_ACCOUNT_IS_NOT_RUNNING RpcAccountLocalLinkCreateAppResponseErrorCode = 101 +) + +var RpcAccountLocalLinkCreateAppResponseErrorCode_name = map[int32]string{ + 0: "NULL", + 1: "UNKNOWN_ERROR", + 2: "BAD_INPUT", + 101: "ACCOUNT_IS_NOT_RUNNING", +} + +var RpcAccountLocalLinkCreateAppResponseErrorCode_value = map[string]int32{ + "NULL": 0, + "UNKNOWN_ERROR": 1, + "BAD_INPUT": 2, + "ACCOUNT_IS_NOT_RUNNING": 101, +} + +func (x RpcAccountLocalLinkCreateAppResponseErrorCode) String() string { + return proto.EnumName(RpcAccountLocalLinkCreateAppResponseErrorCode_name, int32(x)) +} + +func (RpcAccountLocalLinkCreateAppResponseErrorCode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 3, 1, 0, 0} +} + +type RpcAccountLocalLinkRevokeAppResponseErrorCode int32 + +const ( + RpcAccountLocalLinkRevokeAppResponseError_NULL RpcAccountLocalLinkRevokeAppResponseErrorCode = 0 + RpcAccountLocalLinkRevokeAppResponseError_UNKNOWN_ERROR RpcAccountLocalLinkRevokeAppResponseErrorCode = 1 + RpcAccountLocalLinkRevokeAppResponseError_BAD_INPUT RpcAccountLocalLinkRevokeAppResponseErrorCode = 2 + RpcAccountLocalLinkRevokeAppResponseError_NOT_FOUND RpcAccountLocalLinkRevokeAppResponseErrorCode = 3 + RpcAccountLocalLinkRevokeAppResponseError_ACCOUNT_IS_NOT_RUNNING RpcAccountLocalLinkRevokeAppResponseErrorCode = 101 +) + +var RpcAccountLocalLinkRevokeAppResponseErrorCode_name = map[int32]string{ + 0: "NULL", + 1: "UNKNOWN_ERROR", + 2: "BAD_INPUT", + 3: "NOT_FOUND", + 101: "ACCOUNT_IS_NOT_RUNNING", +} + +var RpcAccountLocalLinkRevokeAppResponseErrorCode_value = map[string]int32{ + "NULL": 0, + "UNKNOWN_ERROR": 1, + "BAD_INPUT": 2, + "NOT_FOUND": 3, + "ACCOUNT_IS_NOT_RUNNING": 101, +} + +func (x RpcAccountLocalLinkRevokeAppResponseErrorCode) String() string { + return proto.EnumName(RpcAccountLocalLinkRevokeAppResponseErrorCode_name, int32(x)) +} + +func (RpcAccountLocalLinkRevokeAppResponseErrorCode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 4, 1, 0, 0} +} + type RpcWorkspaceGetCurrentResponseErrorCode int32 const ( @@ -10039,6 +10150,34 @@ func (RpcChatUnreadResponseErrorCode) EnumDescriptor() ([]byte, []int) { return fileDescriptor_8261c968b2e6f45c, []int{0, 42, 11, 1, 0, 0} } +type RpcChatReadAllResponseErrorCode int32 + +const ( + RpcChatReadAllResponseError_NULL RpcChatReadAllResponseErrorCode = 0 + RpcChatReadAllResponseError_UNKNOWN_ERROR RpcChatReadAllResponseErrorCode = 1 + RpcChatReadAllResponseError_BAD_INPUT RpcChatReadAllResponseErrorCode = 2 +) + +var RpcChatReadAllResponseErrorCode_name = map[int32]string{ + 0: "NULL", + 1: "UNKNOWN_ERROR", + 2: "BAD_INPUT", +} + +var RpcChatReadAllResponseErrorCode_value = map[string]int32{ + "NULL": 0, + "UNKNOWN_ERROR": 1, + "BAD_INPUT": 2, +} + +func (x RpcChatReadAllResponseErrorCode) String() string { + return proto.EnumName(RpcChatReadAllResponseErrorCode_name, int32(x)) +} + +func (RpcChatReadAllResponseErrorCode) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 42, 12, 1, 0, 0} +} + type RpcPushNotificationRegisterTokenPlatform int32 const ( @@ -11092,6 +11231,190 @@ func (m *RpcSpaceMakeShareableResponseError) GetDescription() string { return "" } +type RpcSpaceInviteChange struct { +} + +func (m *RpcSpaceInviteChange) Reset() { *m = RpcSpaceInviteChange{} } +func (m *RpcSpaceInviteChange) String() string { return proto.CompactTextString(m) } +func (*RpcSpaceInviteChange) ProtoMessage() {} +func (*RpcSpaceInviteChange) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 2} +} +func (m *RpcSpaceInviteChange) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcSpaceInviteChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcSpaceInviteChange.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcSpaceInviteChange) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcSpaceInviteChange.Merge(m, src) +} +func (m *RpcSpaceInviteChange) XXX_Size() int { + return m.Size() +} +func (m *RpcSpaceInviteChange) XXX_DiscardUnknown() { + xxx_messageInfo_RpcSpaceInviteChange.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcSpaceInviteChange proto.InternalMessageInfo + +type RpcSpaceInviteChangeRequest struct { + SpaceId string `protobuf:"bytes,1,opt,name=spaceId,proto3" json:"spaceId,omitempty"` + Permissions model.ParticipantPermissions `protobuf:"varint,2,opt,name=permissions,proto3,enum=anytype.model.ParticipantPermissions" json:"permissions,omitempty"` +} + +func (m *RpcSpaceInviteChangeRequest) Reset() { *m = RpcSpaceInviteChangeRequest{} } +func (m *RpcSpaceInviteChangeRequest) String() string { return proto.CompactTextString(m) } +func (*RpcSpaceInviteChangeRequest) ProtoMessage() {} +func (*RpcSpaceInviteChangeRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 2, 0} +} +func (m *RpcSpaceInviteChangeRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcSpaceInviteChangeRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcSpaceInviteChangeRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcSpaceInviteChangeRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcSpaceInviteChangeRequest.Merge(m, src) +} +func (m *RpcSpaceInviteChangeRequest) XXX_Size() int { + return m.Size() +} +func (m *RpcSpaceInviteChangeRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RpcSpaceInviteChangeRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcSpaceInviteChangeRequest proto.InternalMessageInfo + +func (m *RpcSpaceInviteChangeRequest) GetSpaceId() string { + if m != nil { + return m.SpaceId + } + return "" +} + +func (m *RpcSpaceInviteChangeRequest) GetPermissions() model.ParticipantPermissions { + if m != nil { + return m.Permissions + } + return model.ParticipantPermissions_Reader +} + +type RpcSpaceInviteChangeResponse struct { + Error *RpcSpaceInviteChangeResponseError `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` +} + +func (m *RpcSpaceInviteChangeResponse) Reset() { *m = RpcSpaceInviteChangeResponse{} } +func (m *RpcSpaceInviteChangeResponse) String() string { return proto.CompactTextString(m) } +func (*RpcSpaceInviteChangeResponse) ProtoMessage() {} +func (*RpcSpaceInviteChangeResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 2, 1} +} +func (m *RpcSpaceInviteChangeResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcSpaceInviteChangeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcSpaceInviteChangeResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcSpaceInviteChangeResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcSpaceInviteChangeResponse.Merge(m, src) +} +func (m *RpcSpaceInviteChangeResponse) XXX_Size() int { + return m.Size() +} +func (m *RpcSpaceInviteChangeResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RpcSpaceInviteChangeResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcSpaceInviteChangeResponse proto.InternalMessageInfo + +func (m *RpcSpaceInviteChangeResponse) GetError() *RpcSpaceInviteChangeResponseError { + if m != nil { + return m.Error + } + return nil +} + +type RpcSpaceInviteChangeResponseError struct { + Code RpcSpaceInviteChangeResponseErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=anytype.RpcSpaceInviteChangeResponseErrorCode" json:"code,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` +} + +func (m *RpcSpaceInviteChangeResponseError) Reset() { *m = RpcSpaceInviteChangeResponseError{} } +func (m *RpcSpaceInviteChangeResponseError) String() string { return proto.CompactTextString(m) } +func (*RpcSpaceInviteChangeResponseError) ProtoMessage() {} +func (*RpcSpaceInviteChangeResponseError) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 2, 1, 0} +} +func (m *RpcSpaceInviteChangeResponseError) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcSpaceInviteChangeResponseError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcSpaceInviteChangeResponseError.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcSpaceInviteChangeResponseError) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcSpaceInviteChangeResponseError.Merge(m, src) +} +func (m *RpcSpaceInviteChangeResponseError) XXX_Size() int { + return m.Size() +} +func (m *RpcSpaceInviteChangeResponseError) XXX_DiscardUnknown() { + xxx_messageInfo_RpcSpaceInviteChangeResponseError.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcSpaceInviteChangeResponseError proto.InternalMessageInfo + +func (m *RpcSpaceInviteChangeResponseError) GetCode() RpcSpaceInviteChangeResponseErrorCode { + if m != nil { + return m.Code + } + return RpcSpaceInviteChangeResponseError_NULL +} + +func (m *RpcSpaceInviteChangeResponseError) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + type RpcSpaceInviteGenerate struct { } @@ -11099,7 +11422,7 @@ func (m *RpcSpaceInviteGenerate) Reset() { *m = RpcSpaceInviteGenerate{} func (m *RpcSpaceInviteGenerate) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGenerate) ProtoMessage() {} func (*RpcSpaceInviteGenerate) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 2} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 3} } func (m *RpcSpaceInviteGenerate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11129,15 +11452,16 @@ func (m *RpcSpaceInviteGenerate) XXX_DiscardUnknown() { var xxx_messageInfo_RpcSpaceInviteGenerate proto.InternalMessageInfo type RpcSpaceInviteGenerateRequest struct { - SpaceId string `protobuf:"bytes,1,opt,name=spaceId,proto3" json:"spaceId,omitempty"` - InviteType RpcSpaceInviteGenerateRequestInviteType `protobuf:"varint,2,opt,name=inviteType,proto3,enum=anytype.RpcSpaceInviteGenerateRequestInviteType" json:"inviteType,omitempty"` + SpaceId string `protobuf:"bytes,1,opt,name=spaceId,proto3" json:"spaceId,omitempty"` + InviteType model.InviteType `protobuf:"varint,2,opt,name=inviteType,proto3,enum=anytype.model.InviteType" json:"inviteType,omitempty"` + Permissions model.ParticipantPermissions `protobuf:"varint,3,opt,name=permissions,proto3,enum=anytype.model.ParticipantPermissions" json:"permissions,omitempty"` } func (m *RpcSpaceInviteGenerateRequest) Reset() { *m = RpcSpaceInviteGenerateRequest{} } func (m *RpcSpaceInviteGenerateRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGenerateRequest) ProtoMessage() {} func (*RpcSpaceInviteGenerateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 2, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 3, 0} } func (m *RpcSpaceInviteGenerateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11173,24 +11497,33 @@ func (m *RpcSpaceInviteGenerateRequest) GetSpaceId() string { return "" } -func (m *RpcSpaceInviteGenerateRequest) GetInviteType() RpcSpaceInviteGenerateRequestInviteType { +func (m *RpcSpaceInviteGenerateRequest) GetInviteType() model.InviteType { if m != nil { return m.InviteType } - return RpcSpaceInviteGenerateRequest_Member + return model.InviteType_Member +} + +func (m *RpcSpaceInviteGenerateRequest) GetPermissions() model.ParticipantPermissions { + if m != nil { + return m.Permissions + } + return model.ParticipantPermissions_Reader } type RpcSpaceInviteGenerateResponse struct { Error *RpcSpaceInviteGenerateResponseError `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` InviteCid string `protobuf:"bytes,2,opt,name=inviteCid,proto3" json:"inviteCid,omitempty"` InviteFileKey string `protobuf:"bytes,3,opt,name=inviteFileKey,proto3" json:"inviteFileKey,omitempty"` + InviteType model.InviteType `protobuf:"varint,4,opt,name=inviteType,proto3,enum=anytype.model.InviteType" json:"inviteType,omitempty"` + Permissions model.ParticipantPermissions `protobuf:"varint,5,opt,name=permissions,proto3,enum=anytype.model.ParticipantPermissions" json:"permissions,omitempty"` } func (m *RpcSpaceInviteGenerateResponse) Reset() { *m = RpcSpaceInviteGenerateResponse{} } func (m *RpcSpaceInviteGenerateResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGenerateResponse) ProtoMessage() {} func (*RpcSpaceInviteGenerateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 2, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 3, 1} } func (m *RpcSpaceInviteGenerateResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11240,6 +11573,20 @@ func (m *RpcSpaceInviteGenerateResponse) GetInviteFileKey() string { return "" } +func (m *RpcSpaceInviteGenerateResponse) GetInviteType() model.InviteType { + if m != nil { + return m.InviteType + } + return model.InviteType_Member +} + +func (m *RpcSpaceInviteGenerateResponse) GetPermissions() model.ParticipantPermissions { + if m != nil { + return m.Permissions + } + return model.ParticipantPermissions_Reader +} + type RpcSpaceInviteGenerateResponseError struct { Code RpcSpaceInviteGenerateResponseErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=anytype.RpcSpaceInviteGenerateResponseErrorCode" json:"code,omitempty"` Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` @@ -11249,7 +11596,7 @@ func (m *RpcSpaceInviteGenerateResponseError) Reset() { *m = RpcSpaceInv func (m *RpcSpaceInviteGenerateResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGenerateResponseError) ProtoMessage() {} func (*RpcSpaceInviteGenerateResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 2, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 3, 1, 0} } func (m *RpcSpaceInviteGenerateResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11299,7 +11646,7 @@ func (m *RpcSpaceStopSharing) Reset() { *m = RpcSpaceStopSharing{} } func (m *RpcSpaceStopSharing) String() string { return proto.CompactTextString(m) } func (*RpcSpaceStopSharing) ProtoMessage() {} func (*RpcSpaceStopSharing) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 3} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 4} } func (m *RpcSpaceStopSharing) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11336,7 +11683,7 @@ func (m *RpcSpaceStopSharingRequest) Reset() { *m = RpcSpaceStopSharingR func (m *RpcSpaceStopSharingRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceStopSharingRequest) ProtoMessage() {} func (*RpcSpaceStopSharingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 3, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 4, 0} } func (m *RpcSpaceStopSharingRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11380,7 +11727,7 @@ func (m *RpcSpaceStopSharingResponse) Reset() { *m = RpcSpaceStopSharing func (m *RpcSpaceStopSharingResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceStopSharingResponse) ProtoMessage() {} func (*RpcSpaceStopSharingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 3, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 4, 1} } func (m *RpcSpaceStopSharingResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11425,7 +11772,7 @@ func (m *RpcSpaceStopSharingResponseError) Reset() { *m = RpcSpaceStopSh func (m *RpcSpaceStopSharingResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceStopSharingResponseError) ProtoMessage() {} func (*RpcSpaceStopSharingResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 3, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 4, 1, 0} } func (m *RpcSpaceStopSharingResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11475,7 +11822,7 @@ func (m *RpcSpaceInviteGetCurrent) Reset() { *m = RpcSpaceInviteGetCurre func (m *RpcSpaceInviteGetCurrent) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGetCurrent) ProtoMessage() {} func (*RpcSpaceInviteGetCurrent) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 4} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 5} } func (m *RpcSpaceInviteGetCurrent) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11512,7 +11859,7 @@ func (m *RpcSpaceInviteGetCurrentRequest) Reset() { *m = RpcSpaceInviteG func (m *RpcSpaceInviteGetCurrentRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGetCurrentRequest) ProtoMessage() {} func (*RpcSpaceInviteGetCurrentRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 4, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 5, 0} } func (m *RpcSpaceInviteGetCurrentRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11552,13 +11899,15 @@ type RpcSpaceInviteGetCurrentResponse struct { Error *RpcSpaceInviteGetCurrentResponseError `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` InviteCid string `protobuf:"bytes,2,opt,name=inviteCid,proto3" json:"inviteCid,omitempty"` InviteFileKey string `protobuf:"bytes,3,opt,name=inviteFileKey,proto3" json:"inviteFileKey,omitempty"` + InviteType model.InviteType `protobuf:"varint,4,opt,name=inviteType,proto3,enum=anytype.model.InviteType" json:"inviteType,omitempty"` + Permissions model.ParticipantPermissions `protobuf:"varint,5,opt,name=permissions,proto3,enum=anytype.model.ParticipantPermissions" json:"permissions,omitempty"` } func (m *RpcSpaceInviteGetCurrentResponse) Reset() { *m = RpcSpaceInviteGetCurrentResponse{} } func (m *RpcSpaceInviteGetCurrentResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGetCurrentResponse) ProtoMessage() {} func (*RpcSpaceInviteGetCurrentResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 4, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 5, 1} } func (m *RpcSpaceInviteGetCurrentResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11608,6 +11957,20 @@ func (m *RpcSpaceInviteGetCurrentResponse) GetInviteFileKey() string { return "" } +func (m *RpcSpaceInviteGetCurrentResponse) GetInviteType() model.InviteType { + if m != nil { + return m.InviteType + } + return model.InviteType_Member +} + +func (m *RpcSpaceInviteGetCurrentResponse) GetPermissions() model.ParticipantPermissions { + if m != nil { + return m.Permissions + } + return model.ParticipantPermissions_Reader +} + type RpcSpaceInviteGetCurrentResponseError struct { Code RpcSpaceInviteGetCurrentResponseErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=anytype.RpcSpaceInviteGetCurrentResponseErrorCode" json:"code,omitempty"` Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` @@ -11617,7 +11980,7 @@ func (m *RpcSpaceInviteGetCurrentResponseError) Reset() { *m = RpcSpaceI func (m *RpcSpaceInviteGetCurrentResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGetCurrentResponseError) ProtoMessage() {} func (*RpcSpaceInviteGetCurrentResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 4, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 5, 1, 0} } func (m *RpcSpaceInviteGetCurrentResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11667,7 +12030,7 @@ func (m *RpcSpaceInviteGetGuest) Reset() { *m = RpcSpaceInviteGetGuest{} func (m *RpcSpaceInviteGetGuest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGetGuest) ProtoMessage() {} func (*RpcSpaceInviteGetGuest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 5} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 6} } func (m *RpcSpaceInviteGetGuest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11704,7 +12067,7 @@ func (m *RpcSpaceInviteGetGuestRequest) Reset() { *m = RpcSpaceInviteGet func (m *RpcSpaceInviteGetGuestRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGetGuestRequest) ProtoMessage() {} func (*RpcSpaceInviteGetGuestRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 5, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 6, 0} } func (m *RpcSpaceInviteGetGuestRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11750,7 +12113,7 @@ func (m *RpcSpaceInviteGetGuestResponse) Reset() { *m = RpcSpaceInviteGe func (m *RpcSpaceInviteGetGuestResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGetGuestResponse) ProtoMessage() {} func (*RpcSpaceInviteGetGuestResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 5, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 6, 1} } func (m *RpcSpaceInviteGetGuestResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11809,7 +12172,7 @@ func (m *RpcSpaceInviteGetGuestResponseError) Reset() { *m = RpcSpaceInv func (m *RpcSpaceInviteGetGuestResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteGetGuestResponseError) ProtoMessage() {} func (*RpcSpaceInviteGetGuestResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 5, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 6, 1, 0} } func (m *RpcSpaceInviteGetGuestResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11859,7 +12222,7 @@ func (m *RpcSpaceInviteRevoke) Reset() { *m = RpcSpaceInviteRevoke{} } func (m *RpcSpaceInviteRevoke) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteRevoke) ProtoMessage() {} func (*RpcSpaceInviteRevoke) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 6} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 7} } func (m *RpcSpaceInviteRevoke) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11896,7 +12259,7 @@ func (m *RpcSpaceInviteRevokeRequest) Reset() { *m = RpcSpaceInviteRevok func (m *RpcSpaceInviteRevokeRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteRevokeRequest) ProtoMessage() {} func (*RpcSpaceInviteRevokeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 6, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 7, 0} } func (m *RpcSpaceInviteRevokeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11940,7 +12303,7 @@ func (m *RpcSpaceInviteRevokeResponse) Reset() { *m = RpcSpaceInviteRevo func (m *RpcSpaceInviteRevokeResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteRevokeResponse) ProtoMessage() {} func (*RpcSpaceInviteRevokeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 6, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 7, 1} } func (m *RpcSpaceInviteRevokeResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -11985,7 +12348,7 @@ func (m *RpcSpaceInviteRevokeResponseError) Reset() { *m = RpcSpaceInvit func (m *RpcSpaceInviteRevokeResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteRevokeResponseError) ProtoMessage() {} func (*RpcSpaceInviteRevokeResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 6, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 7, 1, 0} } func (m *RpcSpaceInviteRevokeResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12035,7 +12398,7 @@ func (m *RpcSpaceInviteView) Reset() { *m = RpcSpaceInviteView{} } func (m *RpcSpaceInviteView) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteView) ProtoMessage() {} func (*RpcSpaceInviteView) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 7} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 8} } func (m *RpcSpaceInviteView) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12073,7 +12436,7 @@ func (m *RpcSpaceInviteViewRequest) Reset() { *m = RpcSpaceInviteViewReq func (m *RpcSpaceInviteViewRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteViewRequest) ProtoMessage() {} func (*RpcSpaceInviteViewRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 7, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 8, 0} } func (m *RpcSpaceInviteViewRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12123,13 +12486,14 @@ type RpcSpaceInviteViewResponse struct { SpaceIconCid string `protobuf:"bytes,4,opt,name=spaceIconCid,proto3" json:"spaceIconCid,omitempty"` CreatorName string `protobuf:"bytes,5,opt,name=creatorName,proto3" json:"creatorName,omitempty"` IsGuestUserInvite bool `protobuf:"varint,6,opt,name=isGuestUserInvite,proto3" json:"isGuestUserInvite,omitempty"` + InviteType model.InviteType `protobuf:"varint,7,opt,name=inviteType,proto3,enum=anytype.model.InviteType" json:"inviteType,omitempty"` } func (m *RpcSpaceInviteViewResponse) Reset() { *m = RpcSpaceInviteViewResponse{} } func (m *RpcSpaceInviteViewResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteViewResponse) ProtoMessage() {} func (*RpcSpaceInviteViewResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 7, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 8, 1} } func (m *RpcSpaceInviteViewResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12200,6 +12564,13 @@ func (m *RpcSpaceInviteViewResponse) GetIsGuestUserInvite() bool { return false } +func (m *RpcSpaceInviteViewResponse) GetInviteType() model.InviteType { + if m != nil { + return m.InviteType + } + return model.InviteType_Member +} + type RpcSpaceInviteViewResponseError struct { Code RpcSpaceInviteViewResponseErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=anytype.RpcSpaceInviteViewResponseErrorCode" json:"code,omitempty"` Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` @@ -12209,7 +12580,7 @@ func (m *RpcSpaceInviteViewResponseError) Reset() { *m = RpcSpaceInviteV func (m *RpcSpaceInviteViewResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceInviteViewResponseError) ProtoMessage() {} func (*RpcSpaceInviteViewResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 7, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 8, 1, 0} } func (m *RpcSpaceInviteViewResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12259,7 +12630,7 @@ func (m *RpcSpaceJoin) Reset() { *m = RpcSpaceJoin{} } func (m *RpcSpaceJoin) String() string { return proto.CompactTextString(m) } func (*RpcSpaceJoin) ProtoMessage() {} func (*RpcSpaceJoin) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 8} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 9} } func (m *RpcSpaceJoin) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12299,7 +12670,7 @@ func (m *RpcSpaceJoinRequest) Reset() { *m = RpcSpaceJoinRequest{} } func (m *RpcSpaceJoinRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceJoinRequest) ProtoMessage() {} func (*RpcSpaceJoinRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 8, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 9, 0} } func (m *RpcSpaceJoinRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12364,7 +12735,7 @@ func (m *RpcSpaceJoinResponse) Reset() { *m = RpcSpaceJoinResponse{} } func (m *RpcSpaceJoinResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceJoinResponse) ProtoMessage() {} func (*RpcSpaceJoinResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 8, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 9, 1} } func (m *RpcSpaceJoinResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12409,7 +12780,7 @@ func (m *RpcSpaceJoinResponseError) Reset() { *m = RpcSpaceJoinResponseE func (m *RpcSpaceJoinResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceJoinResponseError) ProtoMessage() {} func (*RpcSpaceJoinResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 8, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 9, 1, 0} } func (m *RpcSpaceJoinResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12459,7 +12830,7 @@ func (m *RpcSpaceJoinCancel) Reset() { *m = RpcSpaceJoinCancel{} } func (m *RpcSpaceJoinCancel) String() string { return proto.CompactTextString(m) } func (*RpcSpaceJoinCancel) ProtoMessage() {} func (*RpcSpaceJoinCancel) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 9} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 10} } func (m *RpcSpaceJoinCancel) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12496,7 +12867,7 @@ func (m *RpcSpaceJoinCancelRequest) Reset() { *m = RpcSpaceJoinCancelReq func (m *RpcSpaceJoinCancelRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceJoinCancelRequest) ProtoMessage() {} func (*RpcSpaceJoinCancelRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 9, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 10, 0} } func (m *RpcSpaceJoinCancelRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12540,7 +12911,7 @@ func (m *RpcSpaceJoinCancelResponse) Reset() { *m = RpcSpaceJoinCancelRe func (m *RpcSpaceJoinCancelResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceJoinCancelResponse) ProtoMessage() {} func (*RpcSpaceJoinCancelResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 9, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 10, 1} } func (m *RpcSpaceJoinCancelResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12585,7 +12956,7 @@ func (m *RpcSpaceJoinCancelResponseError) Reset() { *m = RpcSpaceJoinCan func (m *RpcSpaceJoinCancelResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceJoinCancelResponseError) ProtoMessage() {} func (*RpcSpaceJoinCancelResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 9, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 10, 1, 0} } func (m *RpcSpaceJoinCancelResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12635,7 +13006,7 @@ func (m *RpcSpaceRequestApprove) Reset() { *m = RpcSpaceRequestApprove{} func (m *RpcSpaceRequestApprove) String() string { return proto.CompactTextString(m) } func (*RpcSpaceRequestApprove) ProtoMessage() {} func (*RpcSpaceRequestApprove) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 10} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 11} } func (m *RpcSpaceRequestApprove) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12674,7 +13045,7 @@ func (m *RpcSpaceRequestApproveRequest) Reset() { *m = RpcSpaceRequestAp func (m *RpcSpaceRequestApproveRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceRequestApproveRequest) ProtoMessage() {} func (*RpcSpaceRequestApproveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 10, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 11, 0} } func (m *RpcSpaceRequestApproveRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12732,7 +13103,7 @@ func (m *RpcSpaceRequestApproveResponse) Reset() { *m = RpcSpaceRequestA func (m *RpcSpaceRequestApproveResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceRequestApproveResponse) ProtoMessage() {} func (*RpcSpaceRequestApproveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 10, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 11, 1} } func (m *RpcSpaceRequestApproveResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12777,7 +13148,7 @@ func (m *RpcSpaceRequestApproveResponseError) Reset() { *m = RpcSpaceReq func (m *RpcSpaceRequestApproveResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceRequestApproveResponseError) ProtoMessage() {} func (*RpcSpaceRequestApproveResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 10, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 11, 1, 0} } func (m *RpcSpaceRequestApproveResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12827,7 +13198,7 @@ func (m *RpcSpaceRequestDecline) Reset() { *m = RpcSpaceRequestDecline{} func (m *RpcSpaceRequestDecline) String() string { return proto.CompactTextString(m) } func (*RpcSpaceRequestDecline) ProtoMessage() {} func (*RpcSpaceRequestDecline) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 11} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 12} } func (m *RpcSpaceRequestDecline) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12865,7 +13236,7 @@ func (m *RpcSpaceRequestDeclineRequest) Reset() { *m = RpcSpaceRequestDe func (m *RpcSpaceRequestDeclineRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceRequestDeclineRequest) ProtoMessage() {} func (*RpcSpaceRequestDeclineRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 11, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 12, 0} } func (m *RpcSpaceRequestDeclineRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12916,7 +13287,7 @@ func (m *RpcSpaceRequestDeclineResponse) Reset() { *m = RpcSpaceRequestD func (m *RpcSpaceRequestDeclineResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceRequestDeclineResponse) ProtoMessage() {} func (*RpcSpaceRequestDeclineResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 11, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 12, 1} } func (m *RpcSpaceRequestDeclineResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -12961,7 +13332,7 @@ func (m *RpcSpaceRequestDeclineResponseError) Reset() { *m = RpcSpaceReq func (m *RpcSpaceRequestDeclineResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceRequestDeclineResponseError) ProtoMessage() {} func (*RpcSpaceRequestDeclineResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 11, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 12, 1, 0} } func (m *RpcSpaceRequestDeclineResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13011,7 +13382,7 @@ func (m *RpcSpaceParticipantRemove) Reset() { *m = RpcSpaceParticipantRe func (m *RpcSpaceParticipantRemove) String() string { return proto.CompactTextString(m) } func (*RpcSpaceParticipantRemove) ProtoMessage() {} func (*RpcSpaceParticipantRemove) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 12} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 13} } func (m *RpcSpaceParticipantRemove) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13049,7 +13420,7 @@ func (m *RpcSpaceParticipantRemoveRequest) Reset() { *m = RpcSpacePartic func (m *RpcSpaceParticipantRemoveRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceParticipantRemoveRequest) ProtoMessage() {} func (*RpcSpaceParticipantRemoveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 12, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 13, 0} } func (m *RpcSpaceParticipantRemoveRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13100,7 +13471,7 @@ func (m *RpcSpaceParticipantRemoveResponse) Reset() { *m = RpcSpaceParti func (m *RpcSpaceParticipantRemoveResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceParticipantRemoveResponse) ProtoMessage() {} func (*RpcSpaceParticipantRemoveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 12, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 13, 1} } func (m *RpcSpaceParticipantRemoveResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13147,7 +13518,7 @@ func (m *RpcSpaceParticipantRemoveResponseError) Reset() { func (m *RpcSpaceParticipantRemoveResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceParticipantRemoveResponseError) ProtoMessage() {} func (*RpcSpaceParticipantRemoveResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 12, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 13, 1, 0} } func (m *RpcSpaceParticipantRemoveResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13197,7 +13568,7 @@ func (m *RpcSpaceParticipantPermissionsChange) Reset() { *m = RpcSpacePa func (m *RpcSpaceParticipantPermissionsChange) String() string { return proto.CompactTextString(m) } func (*RpcSpaceParticipantPermissionsChange) ProtoMessage() {} func (*RpcSpaceParticipantPermissionsChange) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 13} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 14} } func (m *RpcSpaceParticipantPermissionsChange) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13239,7 +13610,7 @@ func (m *RpcSpaceParticipantPermissionsChangeRequest) String() string { } func (*RpcSpaceParticipantPermissionsChangeRequest) ProtoMessage() {} func (*RpcSpaceParticipantPermissionsChangeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 13, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 14, 0} } func (m *RpcSpaceParticipantPermissionsChangeRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13294,7 +13665,7 @@ func (m *RpcSpaceParticipantPermissionsChangeResponse) String() string { } func (*RpcSpaceParticipantPermissionsChangeResponse) ProtoMessage() {} func (*RpcSpaceParticipantPermissionsChangeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 13, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 14, 1} } func (m *RpcSpaceParticipantPermissionsChangeResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13343,7 +13714,7 @@ func (m *RpcSpaceParticipantPermissionsChangeResponseError) String() string { } func (*RpcSpaceParticipantPermissionsChangeResponseError) ProtoMessage() {} func (*RpcSpaceParticipantPermissionsChangeResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 13, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 14, 1, 0} } func (m *RpcSpaceParticipantPermissionsChangeResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13393,7 +13764,7 @@ func (m *RpcSpaceDelete) Reset() { *m = RpcSpaceDelete{} } func (m *RpcSpaceDelete) String() string { return proto.CompactTextString(m) } func (*RpcSpaceDelete) ProtoMessage() {} func (*RpcSpaceDelete) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 14} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 15} } func (m *RpcSpaceDelete) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13430,7 +13801,7 @@ func (m *RpcSpaceDeleteRequest) Reset() { *m = RpcSpaceDeleteRequest{} } func (m *RpcSpaceDeleteRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceDeleteRequest) ProtoMessage() {} func (*RpcSpaceDeleteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 14, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 15, 0} } func (m *RpcSpaceDeleteRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13475,7 +13846,7 @@ func (m *RpcSpaceDeleteResponse) Reset() { *m = RpcSpaceDeleteResponse{} func (m *RpcSpaceDeleteResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceDeleteResponse) ProtoMessage() {} func (*RpcSpaceDeleteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 14, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 15, 1} } func (m *RpcSpaceDeleteResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13527,7 +13898,7 @@ func (m *RpcSpaceDeleteResponseError) Reset() { *m = RpcSpaceDeleteRespo func (m *RpcSpaceDeleteResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceDeleteResponseError) ProtoMessage() {} func (*RpcSpaceDeleteResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 14, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 15, 1, 0} } func (m *RpcSpaceDeleteResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13577,7 +13948,7 @@ func (m *RpcSpaceSetOrder) Reset() { *m = RpcSpaceSetOrder{} } func (m *RpcSpaceSetOrder) String() string { return proto.CompactTextString(m) } func (*RpcSpaceSetOrder) ProtoMessage() {} func (*RpcSpaceSetOrder) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 15} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 16} } func (m *RpcSpaceSetOrder) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13615,7 +13986,7 @@ func (m *RpcSpaceSetOrderRequest) Reset() { *m = RpcSpaceSetOrderRequest func (m *RpcSpaceSetOrderRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceSetOrderRequest) ProtoMessage() {} func (*RpcSpaceSetOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 15, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 16, 0} } func (m *RpcSpaceSetOrderRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13666,7 +14037,7 @@ func (m *RpcSpaceSetOrderResponse) Reset() { *m = RpcSpaceSetOrderRespon func (m *RpcSpaceSetOrderResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceSetOrderResponse) ProtoMessage() {} func (*RpcSpaceSetOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 15, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 16, 1} } func (m *RpcSpaceSetOrderResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13711,7 +14082,7 @@ func (m *RpcSpaceSetOrderResponseError) Reset() { *m = RpcSpaceSetOrderR func (m *RpcSpaceSetOrderResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceSetOrderResponseError) ProtoMessage() {} func (*RpcSpaceSetOrderResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 15, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 16, 1, 0} } func (m *RpcSpaceSetOrderResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13761,7 +14132,7 @@ func (m *RpcSpaceUnsetOrder) Reset() { *m = RpcSpaceUnsetOrder{} } func (m *RpcSpaceUnsetOrder) String() string { return proto.CompactTextString(m) } func (*RpcSpaceUnsetOrder) ProtoMessage() {} func (*RpcSpaceUnsetOrder) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 16} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 17} } func (m *RpcSpaceUnsetOrder) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13798,7 +14169,7 @@ func (m *RpcSpaceUnsetOrderRequest) Reset() { *m = RpcSpaceUnsetOrderReq func (m *RpcSpaceUnsetOrderRequest) String() string { return proto.CompactTextString(m) } func (*RpcSpaceUnsetOrderRequest) ProtoMessage() {} func (*RpcSpaceUnsetOrderRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 16, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 17, 0} } func (m *RpcSpaceUnsetOrderRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13842,7 +14213,7 @@ func (m *RpcSpaceUnsetOrderResponse) Reset() { *m = RpcSpaceUnsetOrderRe func (m *RpcSpaceUnsetOrderResponse) String() string { return proto.CompactTextString(m) } func (*RpcSpaceUnsetOrderResponse) ProtoMessage() {} func (*RpcSpaceUnsetOrderResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 16, 1} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 17, 1} } func (m *RpcSpaceUnsetOrderResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -13887,7 +14258,7 @@ func (m *RpcSpaceUnsetOrderResponseError) Reset() { *m = RpcSpaceUnsetOr func (m *RpcSpaceUnsetOrderResponseError) String() string { return proto.CompactTextString(m) } func (*RpcSpaceUnsetOrderResponseError) ProtoMessage() {} func (*RpcSpaceUnsetOrderResponseError) Descriptor() ([]byte, []int) { - return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 16, 1, 0} + return fileDescriptor_8261c968b2e6f45c, []int{0, 1, 17, 1, 0} } func (m *RpcSpaceUnsetOrderResponseError) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -18413,6 +18784,552 @@ func (m *RpcAccountLocalLinkSolveChallengeResponseError) GetDescription() string return "" } +type RpcAccountLocalLinkListApps struct { +} + +func (m *RpcAccountLocalLinkListApps) Reset() { *m = RpcAccountLocalLinkListApps{} } +func (m *RpcAccountLocalLinkListApps) String() string { return proto.CompactTextString(m) } +func (*RpcAccountLocalLinkListApps) ProtoMessage() {} +func (*RpcAccountLocalLinkListApps) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 2} +} +func (m *RpcAccountLocalLinkListApps) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkListApps) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkListApps.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkListApps) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkListApps.Merge(m, src) +} +func (m *RpcAccountLocalLinkListApps) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkListApps) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkListApps.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkListApps proto.InternalMessageInfo + +type RpcAccountLocalLinkListAppsRequest struct { +} + +func (m *RpcAccountLocalLinkListAppsRequest) Reset() { *m = RpcAccountLocalLinkListAppsRequest{} } +func (m *RpcAccountLocalLinkListAppsRequest) String() string { return proto.CompactTextString(m) } +func (*RpcAccountLocalLinkListAppsRequest) ProtoMessage() {} +func (*RpcAccountLocalLinkListAppsRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 2, 0} +} +func (m *RpcAccountLocalLinkListAppsRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkListAppsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkListAppsRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkListAppsRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkListAppsRequest.Merge(m, src) +} +func (m *RpcAccountLocalLinkListAppsRequest) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkListAppsRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkListAppsRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkListAppsRequest proto.InternalMessageInfo + +type RpcAccountLocalLinkListAppsResponse struct { + Error *RpcAccountLocalLinkListAppsResponseError `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + App []*model.AccountAuthAppInfo `protobuf:"bytes,2,rep,name=app,proto3" json:"app,omitempty"` +} + +func (m *RpcAccountLocalLinkListAppsResponse) Reset() { *m = RpcAccountLocalLinkListAppsResponse{} } +func (m *RpcAccountLocalLinkListAppsResponse) String() string { return proto.CompactTextString(m) } +func (*RpcAccountLocalLinkListAppsResponse) ProtoMessage() {} +func (*RpcAccountLocalLinkListAppsResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 2, 1} +} +func (m *RpcAccountLocalLinkListAppsResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkListAppsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkListAppsResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkListAppsResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkListAppsResponse.Merge(m, src) +} +func (m *RpcAccountLocalLinkListAppsResponse) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkListAppsResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkListAppsResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkListAppsResponse proto.InternalMessageInfo + +func (m *RpcAccountLocalLinkListAppsResponse) GetError() *RpcAccountLocalLinkListAppsResponseError { + if m != nil { + return m.Error + } + return nil +} + +func (m *RpcAccountLocalLinkListAppsResponse) GetApp() []*model.AccountAuthAppInfo { + if m != nil { + return m.App + } + return nil +} + +type RpcAccountLocalLinkListAppsResponseError struct { + Code RpcAccountLocalLinkListAppsResponseErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=anytype.RpcAccountLocalLinkListAppsResponseErrorCode" json:"code,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` +} + +func (m *RpcAccountLocalLinkListAppsResponseError) Reset() { + *m = RpcAccountLocalLinkListAppsResponseError{} +} +func (m *RpcAccountLocalLinkListAppsResponseError) String() string { return proto.CompactTextString(m) } +func (*RpcAccountLocalLinkListAppsResponseError) ProtoMessage() {} +func (*RpcAccountLocalLinkListAppsResponseError) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 2, 1, 0} +} +func (m *RpcAccountLocalLinkListAppsResponseError) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkListAppsResponseError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkListAppsResponseError.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkListAppsResponseError) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkListAppsResponseError.Merge(m, src) +} +func (m *RpcAccountLocalLinkListAppsResponseError) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkListAppsResponseError) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkListAppsResponseError.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkListAppsResponseError proto.InternalMessageInfo + +func (m *RpcAccountLocalLinkListAppsResponseError) GetCode() RpcAccountLocalLinkListAppsResponseErrorCode { + if m != nil { + return m.Code + } + return RpcAccountLocalLinkListAppsResponseError_NULL +} + +func (m *RpcAccountLocalLinkListAppsResponseError) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +type RpcAccountLocalLinkCreateApp struct { +} + +func (m *RpcAccountLocalLinkCreateApp) Reset() { *m = RpcAccountLocalLinkCreateApp{} } +func (m *RpcAccountLocalLinkCreateApp) String() string { return proto.CompactTextString(m) } +func (*RpcAccountLocalLinkCreateApp) ProtoMessage() {} +func (*RpcAccountLocalLinkCreateApp) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 3} +} +func (m *RpcAccountLocalLinkCreateApp) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkCreateApp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkCreateApp.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkCreateApp) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkCreateApp.Merge(m, src) +} +func (m *RpcAccountLocalLinkCreateApp) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkCreateApp) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkCreateApp.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkCreateApp proto.InternalMessageInfo + +type RpcAccountLocalLinkCreateAppRequest struct { + App *model.AccountAuthAppInfo `protobuf:"bytes,1,opt,name=app,proto3" json:"app,omitempty"` +} + +func (m *RpcAccountLocalLinkCreateAppRequest) Reset() { *m = RpcAccountLocalLinkCreateAppRequest{} } +func (m *RpcAccountLocalLinkCreateAppRequest) String() string { return proto.CompactTextString(m) } +func (*RpcAccountLocalLinkCreateAppRequest) ProtoMessage() {} +func (*RpcAccountLocalLinkCreateAppRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 3, 0} +} +func (m *RpcAccountLocalLinkCreateAppRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkCreateAppRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkCreateAppRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkCreateAppRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkCreateAppRequest.Merge(m, src) +} +func (m *RpcAccountLocalLinkCreateAppRequest) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkCreateAppRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkCreateAppRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkCreateAppRequest proto.InternalMessageInfo + +func (m *RpcAccountLocalLinkCreateAppRequest) GetApp() *model.AccountAuthAppInfo { + if m != nil { + return m.App + } + return nil +} + +type RpcAccountLocalLinkCreateAppResponse struct { + Error *RpcAccountLocalLinkCreateAppResponseError `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + AppKey string `protobuf:"bytes,2,opt,name=appKey,proto3" json:"appKey,omitempty"` +} + +func (m *RpcAccountLocalLinkCreateAppResponse) Reset() { *m = RpcAccountLocalLinkCreateAppResponse{} } +func (m *RpcAccountLocalLinkCreateAppResponse) String() string { return proto.CompactTextString(m) } +func (*RpcAccountLocalLinkCreateAppResponse) ProtoMessage() {} +func (*RpcAccountLocalLinkCreateAppResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 3, 1} +} +func (m *RpcAccountLocalLinkCreateAppResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkCreateAppResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkCreateAppResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkCreateAppResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkCreateAppResponse.Merge(m, src) +} +func (m *RpcAccountLocalLinkCreateAppResponse) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkCreateAppResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkCreateAppResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkCreateAppResponse proto.InternalMessageInfo + +func (m *RpcAccountLocalLinkCreateAppResponse) GetError() *RpcAccountLocalLinkCreateAppResponseError { + if m != nil { + return m.Error + } + return nil +} + +func (m *RpcAccountLocalLinkCreateAppResponse) GetAppKey() string { + if m != nil { + return m.AppKey + } + return "" +} + +type RpcAccountLocalLinkCreateAppResponseError struct { + Code RpcAccountLocalLinkCreateAppResponseErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=anytype.RpcAccountLocalLinkCreateAppResponseErrorCode" json:"code,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` +} + +func (m *RpcAccountLocalLinkCreateAppResponseError) Reset() { + *m = RpcAccountLocalLinkCreateAppResponseError{} +} +func (m *RpcAccountLocalLinkCreateAppResponseError) String() string { + return proto.CompactTextString(m) +} +func (*RpcAccountLocalLinkCreateAppResponseError) ProtoMessage() {} +func (*RpcAccountLocalLinkCreateAppResponseError) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 3, 1, 0} +} +func (m *RpcAccountLocalLinkCreateAppResponseError) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkCreateAppResponseError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkCreateAppResponseError.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkCreateAppResponseError) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkCreateAppResponseError.Merge(m, src) +} +func (m *RpcAccountLocalLinkCreateAppResponseError) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkCreateAppResponseError) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkCreateAppResponseError.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkCreateAppResponseError proto.InternalMessageInfo + +func (m *RpcAccountLocalLinkCreateAppResponseError) GetCode() RpcAccountLocalLinkCreateAppResponseErrorCode { + if m != nil { + return m.Code + } + return RpcAccountLocalLinkCreateAppResponseError_NULL +} + +func (m *RpcAccountLocalLinkCreateAppResponseError) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +type RpcAccountLocalLinkRevokeApp struct { +} + +func (m *RpcAccountLocalLinkRevokeApp) Reset() { *m = RpcAccountLocalLinkRevokeApp{} } +func (m *RpcAccountLocalLinkRevokeApp) String() string { return proto.CompactTextString(m) } +func (*RpcAccountLocalLinkRevokeApp) ProtoMessage() {} +func (*RpcAccountLocalLinkRevokeApp) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 4} +} +func (m *RpcAccountLocalLinkRevokeApp) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkRevokeApp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkRevokeApp.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkRevokeApp) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkRevokeApp.Merge(m, src) +} +func (m *RpcAccountLocalLinkRevokeApp) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkRevokeApp) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkRevokeApp.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkRevokeApp proto.InternalMessageInfo + +type RpcAccountLocalLinkRevokeAppRequest struct { + AppHash string `protobuf:"bytes,1,opt,name=appHash,proto3" json:"appHash,omitempty"` +} + +func (m *RpcAccountLocalLinkRevokeAppRequest) Reset() { *m = RpcAccountLocalLinkRevokeAppRequest{} } +func (m *RpcAccountLocalLinkRevokeAppRequest) String() string { return proto.CompactTextString(m) } +func (*RpcAccountLocalLinkRevokeAppRequest) ProtoMessage() {} +func (*RpcAccountLocalLinkRevokeAppRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 4, 0} +} +func (m *RpcAccountLocalLinkRevokeAppRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkRevokeAppRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkRevokeAppRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkRevokeAppRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkRevokeAppRequest.Merge(m, src) +} +func (m *RpcAccountLocalLinkRevokeAppRequest) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkRevokeAppRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkRevokeAppRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkRevokeAppRequest proto.InternalMessageInfo + +func (m *RpcAccountLocalLinkRevokeAppRequest) GetAppHash() string { + if m != nil { + return m.AppHash + } + return "" +} + +type RpcAccountLocalLinkRevokeAppResponse struct { + Error *RpcAccountLocalLinkRevokeAppResponseError `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` +} + +func (m *RpcAccountLocalLinkRevokeAppResponse) Reset() { *m = RpcAccountLocalLinkRevokeAppResponse{} } +func (m *RpcAccountLocalLinkRevokeAppResponse) String() string { return proto.CompactTextString(m) } +func (*RpcAccountLocalLinkRevokeAppResponse) ProtoMessage() {} +func (*RpcAccountLocalLinkRevokeAppResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 4, 1} +} +func (m *RpcAccountLocalLinkRevokeAppResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkRevokeAppResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkRevokeAppResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkRevokeAppResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkRevokeAppResponse.Merge(m, src) +} +func (m *RpcAccountLocalLinkRevokeAppResponse) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkRevokeAppResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkRevokeAppResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkRevokeAppResponse proto.InternalMessageInfo + +func (m *RpcAccountLocalLinkRevokeAppResponse) GetError() *RpcAccountLocalLinkRevokeAppResponseError { + if m != nil { + return m.Error + } + return nil +} + +type RpcAccountLocalLinkRevokeAppResponseError struct { + Code RpcAccountLocalLinkRevokeAppResponseErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=anytype.RpcAccountLocalLinkRevokeAppResponseErrorCode" json:"code,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` +} + +func (m *RpcAccountLocalLinkRevokeAppResponseError) Reset() { + *m = RpcAccountLocalLinkRevokeAppResponseError{} +} +func (m *RpcAccountLocalLinkRevokeAppResponseError) String() string { + return proto.CompactTextString(m) +} +func (*RpcAccountLocalLinkRevokeAppResponseError) ProtoMessage() {} +func (*RpcAccountLocalLinkRevokeAppResponseError) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 3, 16, 4, 1, 0} +} +func (m *RpcAccountLocalLinkRevokeAppResponseError) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcAccountLocalLinkRevokeAppResponseError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcAccountLocalLinkRevokeAppResponseError.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcAccountLocalLinkRevokeAppResponseError) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcAccountLocalLinkRevokeAppResponseError.Merge(m, src) +} +func (m *RpcAccountLocalLinkRevokeAppResponseError) XXX_Size() int { + return m.Size() +} +func (m *RpcAccountLocalLinkRevokeAppResponseError) XXX_DiscardUnknown() { + xxx_messageInfo_RpcAccountLocalLinkRevokeAppResponseError.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcAccountLocalLinkRevokeAppResponseError proto.InternalMessageInfo + +func (m *RpcAccountLocalLinkRevokeAppResponseError) GetCode() RpcAccountLocalLinkRevokeAppResponseErrorCode { + if m != nil { + return m.Code + } + return RpcAccountLocalLinkRevokeAppResponseError_NULL +} + +func (m *RpcAccountLocalLinkRevokeAppResponseError) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + type RpcWorkspace struct { } @@ -75262,6 +76179,174 @@ func (m *RpcChatUnreadResponseError) GetDescription() string { return "" } +type RpcChatReadAll struct { +} + +func (m *RpcChatReadAll) Reset() { *m = RpcChatReadAll{} } +func (m *RpcChatReadAll) String() string { return proto.CompactTextString(m) } +func (*RpcChatReadAll) ProtoMessage() {} +func (*RpcChatReadAll) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 42, 12} +} +func (m *RpcChatReadAll) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcChatReadAll) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcChatReadAll.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcChatReadAll) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcChatReadAll.Merge(m, src) +} +func (m *RpcChatReadAll) XXX_Size() int { + return m.Size() +} +func (m *RpcChatReadAll) XXX_DiscardUnknown() { + xxx_messageInfo_RpcChatReadAll.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcChatReadAll proto.InternalMessageInfo + +type RpcChatReadAllRequest struct { +} + +func (m *RpcChatReadAllRequest) Reset() { *m = RpcChatReadAllRequest{} } +func (m *RpcChatReadAllRequest) String() string { return proto.CompactTextString(m) } +func (*RpcChatReadAllRequest) ProtoMessage() {} +func (*RpcChatReadAllRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 42, 12, 0} +} +func (m *RpcChatReadAllRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcChatReadAllRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcChatReadAllRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcChatReadAllRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcChatReadAllRequest.Merge(m, src) +} +func (m *RpcChatReadAllRequest) XXX_Size() int { + return m.Size() +} +func (m *RpcChatReadAllRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RpcChatReadAllRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcChatReadAllRequest proto.InternalMessageInfo + +type RpcChatReadAllResponse struct { + Error *RpcChatReadAllResponseError `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` +} + +func (m *RpcChatReadAllResponse) Reset() { *m = RpcChatReadAllResponse{} } +func (m *RpcChatReadAllResponse) String() string { return proto.CompactTextString(m) } +func (*RpcChatReadAllResponse) ProtoMessage() {} +func (*RpcChatReadAllResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 42, 12, 1} +} +func (m *RpcChatReadAllResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcChatReadAllResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcChatReadAllResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcChatReadAllResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcChatReadAllResponse.Merge(m, src) +} +func (m *RpcChatReadAllResponse) XXX_Size() int { + return m.Size() +} +func (m *RpcChatReadAllResponse) XXX_DiscardUnknown() { + xxx_messageInfo_RpcChatReadAllResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcChatReadAllResponse proto.InternalMessageInfo + +func (m *RpcChatReadAllResponse) GetError() *RpcChatReadAllResponseError { + if m != nil { + return m.Error + } + return nil +} + +type RpcChatReadAllResponseError struct { + Code RpcChatReadAllResponseErrorCode `protobuf:"varint,1,opt,name=code,proto3,enum=anytype.RpcChatReadAllResponseErrorCode" json:"code,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` +} + +func (m *RpcChatReadAllResponseError) Reset() { *m = RpcChatReadAllResponseError{} } +func (m *RpcChatReadAllResponseError) String() string { return proto.CompactTextString(m) } +func (*RpcChatReadAllResponseError) ProtoMessage() {} +func (*RpcChatReadAllResponseError) Descriptor() ([]byte, []int) { + return fileDescriptor_8261c968b2e6f45c, []int{0, 42, 12, 1, 0} +} +func (m *RpcChatReadAllResponseError) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RpcChatReadAllResponseError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RpcChatReadAllResponseError.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RpcChatReadAllResponseError) XXX_Merge(src proto.Message) { + xxx_messageInfo_RpcChatReadAllResponseError.Merge(m, src) +} +func (m *RpcChatReadAllResponseError) XXX_Size() int { + return m.Size() +} +func (m *RpcChatReadAllResponseError) XXX_DiscardUnknown() { + xxx_messageInfo_RpcChatReadAllResponseError.DiscardUnknown(m) +} + +var xxx_messageInfo_RpcChatReadAllResponseError proto.InternalMessageInfo + +func (m *RpcChatReadAllResponseError) GetCode() RpcChatReadAllResponseErrorCode { + if m != nil { + return m.Code + } + return RpcChatReadAllResponseError_NULL +} + +func (m *RpcChatReadAllResponseError) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + type RpcPushNotification struct { } @@ -75586,7 +76671,7 @@ func init() { proto.RegisterEnum("anytype.RpcAppShutdownResponseErrorCode", RpcAppShutdownResponseErrorCode_name, RpcAppShutdownResponseErrorCode_value) proto.RegisterEnum("anytype.RpcSpaceLeaveApproveResponseErrorCode", RpcSpaceLeaveApproveResponseErrorCode_name, RpcSpaceLeaveApproveResponseErrorCode_value) proto.RegisterEnum("anytype.RpcSpaceMakeShareableResponseErrorCode", RpcSpaceMakeShareableResponseErrorCode_name, RpcSpaceMakeShareableResponseErrorCode_value) - proto.RegisterEnum("anytype.RpcSpaceInviteGenerateRequestInviteType", RpcSpaceInviteGenerateRequestInviteType_name, RpcSpaceInviteGenerateRequestInviteType_value) + proto.RegisterEnum("anytype.RpcSpaceInviteChangeResponseErrorCode", RpcSpaceInviteChangeResponseErrorCode_name, RpcSpaceInviteChangeResponseErrorCode_value) proto.RegisterEnum("anytype.RpcSpaceInviteGenerateResponseErrorCode", RpcSpaceInviteGenerateResponseErrorCode_name, RpcSpaceInviteGenerateResponseErrorCode_value) proto.RegisterEnum("anytype.RpcSpaceStopSharingResponseErrorCode", RpcSpaceStopSharingResponseErrorCode_name, RpcSpaceStopSharingResponseErrorCode_value) proto.RegisterEnum("anytype.RpcSpaceInviteGetCurrentResponseErrorCode", RpcSpaceInviteGetCurrentResponseErrorCode_name, RpcSpaceInviteGetCurrentResponseErrorCode_value) @@ -75625,6 +76710,9 @@ func init() { proto.RegisterEnum("anytype.RpcAccountChangeNetworkConfigAndRestartResponseErrorCode", RpcAccountChangeNetworkConfigAndRestartResponseErrorCode_name, RpcAccountChangeNetworkConfigAndRestartResponseErrorCode_value) proto.RegisterEnum("anytype.RpcAccountLocalLinkNewChallengeResponseErrorCode", RpcAccountLocalLinkNewChallengeResponseErrorCode_name, RpcAccountLocalLinkNewChallengeResponseErrorCode_value) proto.RegisterEnum("anytype.RpcAccountLocalLinkSolveChallengeResponseErrorCode", RpcAccountLocalLinkSolveChallengeResponseErrorCode_name, RpcAccountLocalLinkSolveChallengeResponseErrorCode_value) + proto.RegisterEnum("anytype.RpcAccountLocalLinkListAppsResponseErrorCode", RpcAccountLocalLinkListAppsResponseErrorCode_name, RpcAccountLocalLinkListAppsResponseErrorCode_value) + proto.RegisterEnum("anytype.RpcAccountLocalLinkCreateAppResponseErrorCode", RpcAccountLocalLinkCreateAppResponseErrorCode_name, RpcAccountLocalLinkCreateAppResponseErrorCode_value) + proto.RegisterEnum("anytype.RpcAccountLocalLinkRevokeAppResponseErrorCode", RpcAccountLocalLinkRevokeAppResponseErrorCode_name, RpcAccountLocalLinkRevokeAppResponseErrorCode_value) proto.RegisterEnum("anytype.RpcWorkspaceGetCurrentResponseErrorCode", RpcWorkspaceGetCurrentResponseErrorCode_name, RpcWorkspaceGetCurrentResponseErrorCode_value) proto.RegisterEnum("anytype.RpcWorkspaceGetAllResponseErrorCode", RpcWorkspaceGetAllResponseErrorCode_name, RpcWorkspaceGetAllResponseErrorCode_value) proto.RegisterEnum("anytype.RpcWorkspaceCreateResponseErrorCode", RpcWorkspaceCreateResponseErrorCode_name, RpcWorkspaceCreateResponseErrorCode_value) @@ -75903,6 +76991,7 @@ func init() { proto.RegisterEnum("anytype.RpcChatReadMessagesResponseErrorCode", RpcChatReadMessagesResponseErrorCode_name, RpcChatReadMessagesResponseErrorCode_value) proto.RegisterEnum("anytype.RpcChatUnreadReadType", RpcChatUnreadReadType_name, RpcChatUnreadReadType_value) proto.RegisterEnum("anytype.RpcChatUnreadResponseErrorCode", RpcChatUnreadResponseErrorCode_name, RpcChatUnreadResponseErrorCode_value) + proto.RegisterEnum("anytype.RpcChatReadAllResponseErrorCode", RpcChatReadAllResponseErrorCode_name, RpcChatReadAllResponseErrorCode_value) proto.RegisterEnum("anytype.RpcPushNotificationRegisterTokenPlatform", RpcPushNotificationRegisterTokenPlatform_name, RpcPushNotificationRegisterTokenPlatform_value) proto.RegisterEnum("anytype.RpcPushNotificationRegisterTokenResponseErrorCode", RpcPushNotificationRegisterTokenResponseErrorCode_name, RpcPushNotificationRegisterTokenResponseErrorCode_value) proto.RegisterType((*Rpc)(nil), "anytype.Rpc") @@ -75928,6 +77017,10 @@ func init() { proto.RegisterType((*RpcSpaceMakeShareableRequest)(nil), "anytype.Rpc.Space.MakeShareable.Request") proto.RegisterType((*RpcSpaceMakeShareableResponse)(nil), "anytype.Rpc.Space.MakeShareable.Response") proto.RegisterType((*RpcSpaceMakeShareableResponseError)(nil), "anytype.Rpc.Space.MakeShareable.Response.Error") + proto.RegisterType((*RpcSpaceInviteChange)(nil), "anytype.Rpc.Space.InviteChange") + proto.RegisterType((*RpcSpaceInviteChangeRequest)(nil), "anytype.Rpc.Space.InviteChange.Request") + proto.RegisterType((*RpcSpaceInviteChangeResponse)(nil), "anytype.Rpc.Space.InviteChange.Response") + proto.RegisterType((*RpcSpaceInviteChangeResponseError)(nil), "anytype.Rpc.Space.InviteChange.Response.Error") proto.RegisterType((*RpcSpaceInviteGenerate)(nil), "anytype.Rpc.Space.InviteGenerate") proto.RegisterType((*RpcSpaceInviteGenerateRequest)(nil), "anytype.Rpc.Space.InviteGenerate.Request") proto.RegisterType((*RpcSpaceInviteGenerateResponse)(nil), "anytype.Rpc.Space.InviteGenerate.Response") @@ -76079,6 +77172,18 @@ func init() { proto.RegisterType((*RpcAccountLocalLinkSolveChallengeRequest)(nil), "anytype.Rpc.Account.LocalLink.SolveChallenge.Request") proto.RegisterType((*RpcAccountLocalLinkSolveChallengeResponse)(nil), "anytype.Rpc.Account.LocalLink.SolveChallenge.Response") proto.RegisterType((*RpcAccountLocalLinkSolveChallengeResponseError)(nil), "anytype.Rpc.Account.LocalLink.SolveChallenge.Response.Error") + proto.RegisterType((*RpcAccountLocalLinkListApps)(nil), "anytype.Rpc.Account.LocalLink.ListApps") + proto.RegisterType((*RpcAccountLocalLinkListAppsRequest)(nil), "anytype.Rpc.Account.LocalLink.ListApps.Request") + proto.RegisterType((*RpcAccountLocalLinkListAppsResponse)(nil), "anytype.Rpc.Account.LocalLink.ListApps.Response") + proto.RegisterType((*RpcAccountLocalLinkListAppsResponseError)(nil), "anytype.Rpc.Account.LocalLink.ListApps.Response.Error") + proto.RegisterType((*RpcAccountLocalLinkCreateApp)(nil), "anytype.Rpc.Account.LocalLink.CreateApp") + proto.RegisterType((*RpcAccountLocalLinkCreateAppRequest)(nil), "anytype.Rpc.Account.LocalLink.CreateApp.Request") + proto.RegisterType((*RpcAccountLocalLinkCreateAppResponse)(nil), "anytype.Rpc.Account.LocalLink.CreateApp.Response") + proto.RegisterType((*RpcAccountLocalLinkCreateAppResponseError)(nil), "anytype.Rpc.Account.LocalLink.CreateApp.Response.Error") + proto.RegisterType((*RpcAccountLocalLinkRevokeApp)(nil), "anytype.Rpc.Account.LocalLink.RevokeApp") + proto.RegisterType((*RpcAccountLocalLinkRevokeAppRequest)(nil), "anytype.Rpc.Account.LocalLink.RevokeApp.Request") + proto.RegisterType((*RpcAccountLocalLinkRevokeAppResponse)(nil), "anytype.Rpc.Account.LocalLink.RevokeApp.Response") + proto.RegisterType((*RpcAccountLocalLinkRevokeAppResponseError)(nil), "anytype.Rpc.Account.LocalLink.RevokeApp.Response.Error") proto.RegisterType((*RpcWorkspace)(nil), "anytype.Rpc.Workspace") proto.RegisterType((*RpcWorkspaceGetCurrent)(nil), "anytype.Rpc.Workspace.GetCurrent") proto.RegisterType((*RpcWorkspaceGetCurrentRequest)(nil), "anytype.Rpc.Workspace.GetCurrent.Request") @@ -77203,6 +78308,10 @@ func init() { proto.RegisterType((*RpcChatUnreadRequest)(nil), "anytype.Rpc.Chat.Unread.Request") proto.RegisterType((*RpcChatUnreadResponse)(nil), "anytype.Rpc.Chat.Unread.Response") proto.RegisterType((*RpcChatUnreadResponseError)(nil), "anytype.Rpc.Chat.Unread.Response.Error") + proto.RegisterType((*RpcChatReadAll)(nil), "anytype.Rpc.Chat.ReadAll") + proto.RegisterType((*RpcChatReadAllRequest)(nil), "anytype.Rpc.Chat.ReadAll.Request") + proto.RegisterType((*RpcChatReadAllResponse)(nil), "anytype.Rpc.Chat.ReadAll.Response") + proto.RegisterType((*RpcChatReadAllResponseError)(nil), "anytype.Rpc.Chat.ReadAll.Response.Error") proto.RegisterType((*RpcPushNotification)(nil), "anytype.Rpc.PushNotification") proto.RegisterType((*RpcPushNotificationRegisterToken)(nil), "anytype.Rpc.PushNotification.RegisterToken") proto.RegisterType((*RpcPushNotificationRegisterTokenRequest)(nil), "anytype.Rpc.PushNotification.RegisterToken.Request") @@ -77216,1371 +78325,1385 @@ func init() { func init() { proto.RegisterFile("pb/protos/commands.proto", fileDescriptor_8261c968b2e6f45c) } var fileDescriptor_8261c968b2e6f45c = []byte{ - // 21809 bytes of a gzipped FileDescriptorProto + // 22047 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0xbd, 0x7b, 0x98, 0x24, 0x49, - 0x59, 0x2f, 0x3c, 0x95, 0x59, 0x55, 0x5d, 0x1d, 0x7d, 0x99, 0x9c, 0xdc, 0xd9, 0x61, 0x36, 0x59, - 0x86, 0x65, 0x58, 0x96, 0x75, 0x59, 0x7a, 0x61, 0x41, 0x64, 0x97, 0x5d, 0x96, 0xea, 0xaa, 0xec, - 0xee, 0xda, 0xad, 0xae, 0x6a, 0xb2, 0xaa, 0x67, 0x58, 0xcf, 0xe1, 0xeb, 0x93, 0x53, 0x15, 0xdd, - 0x9d, 0x3b, 0xd5, 0x99, 0x45, 0x66, 0xf6, 0xcc, 0x0e, 0xdf, 0x73, 0xbe, 0x23, 0x07, 0x11, 0x10, - 0x11, 0x51, 0x11, 0x11, 0xb9, 0x0b, 0x08, 0xc8, 0xfd, 0x26, 0x20, 0x17, 0xb9, 0x08, 0x22, 0x2a, - 0x8a, 0xca, 0x45, 0x79, 0x04, 0xf1, 0x82, 0xe7, 0x1c, 0xf5, 0xe0, 0xa7, 0x20, 0x2a, 0xc7, 0xef, - 0x89, 0x4b, 0x66, 0x46, 0x54, 0x57, 0x66, 0x45, 0x56, 0x57, 0x56, 0x2f, 0xfa, 0xfd, 0x55, 0x95, - 0x91, 0x91, 0x6f, 0xbc, 0xf1, 0xfe, 0xde, 0x88, 0x78, 0x23, 0xe2, 0x8d, 0x37, 0xc0, 0xe9, 0xfe, - 0x85, 0x5b, 0xfa, 0xae, 0xe3, 0x3b, 0xde, 0x2d, 0x1d, 0x67, 0x6f, 0xcf, 0xb4, 0xbb, 0xde, 0x12, - 0x7e, 0x56, 0x67, 0x4c, 0xfb, 0x8a, 0x7f, 0xa5, 0x0f, 0xb5, 0xeb, 0xfb, 0x17, 0x77, 0x6e, 0xe9, - 0x59, 0x17, 0x6e, 0xe9, 0x5f, 0xb8, 0x65, 0xcf, 0xe9, 0xc2, 0x5e, 0xf0, 0x01, 0x7e, 0xa0, 0xd9, - 0xb5, 0x1b, 0xe3, 0x72, 0xf5, 0x9c, 0x8e, 0xd9, 0xf3, 0x7c, 0xc7, 0x85, 0x34, 0xe7, 0xa9, 0xa8, - 0x48, 0x78, 0x09, 0xda, 0x7e, 0x40, 0xe1, 0xda, 0x1d, 0xc7, 0xd9, 0xe9, 0x41, 0xf2, 0xee, 0xc2, - 0xfe, 0xf6, 0x2d, 0x9e, 0xef, 0xee, 0x77, 0x7c, 0xfa, 0xf6, 0xba, 0xc1, 0xb7, 0x5d, 0xe8, 0x75, - 0x5c, 0xab, 0xef, 0x3b, 0x2e, 0xc9, 0x71, 0xf6, 0x0d, 0xdf, 0x28, 0x01, 0xd9, 0xe8, 0x77, 0xb4, - 0x6f, 0xcf, 0x00, 0xb9, 0xdc, 0xef, 0x6b, 0x9f, 0x92, 0x00, 0x58, 0x85, 0xfe, 0x39, 0xe8, 0x7a, - 0x96, 0x63, 0x6b, 0xc7, 0xc1, 0x8c, 0x01, 0x9f, 0xb1, 0x0f, 0x3d, 0xff, 0xf6, 0xfc, 0xf3, 0xfe, - 0x52, 0xce, 0x69, 0xaf, 0x97, 0x40, 0xc9, 0x80, 0x5e, 0xdf, 0xb1, 0x3d, 0xa8, 0x3e, 0x05, 0x14, - 0xa0, 0xeb, 0x3a, 0xee, 0xe9, 0xdc, 0x75, 0xb9, 0x1b, 0xe7, 0x6e, 0xbd, 0x69, 0x89, 0x56, 0x7f, - 0xc9, 0xe8, 0x77, 0x96, 0xca, 0xfd, 0xfe, 0x52, 0x44, 0x69, 0x29, 0xf8, 0x68, 0x49, 0x47, 0x5f, - 0x18, 0xe4, 0x43, 0xf5, 0x34, 0x98, 0xb9, 0x44, 0x32, 0x9c, 0x96, 0xae, 0xcb, 0xdd, 0x38, 0x6b, - 0x04, 0x8f, 0xe8, 0x4d, 0x17, 0xfa, 0xa6, 0xd5, 0xf3, 0x4e, 0xcb, 0xe4, 0x0d, 0x7d, 0xd4, 0x5e, - 0x9b, 0x03, 0x05, 0x4c, 0x44, 0xad, 0x80, 0x7c, 0xc7, 0xe9, 0x42, 0x5c, 0xfc, 0xe2, 0xad, 0xb7, - 0x88, 0x17, 0xbf, 0x54, 0x71, 0xba, 0xd0, 0xc0, 0x1f, 0xab, 0xd7, 0x81, 0xb9, 0x40, 0x2c, 0x11, - 0x1b, 0x6c, 0xd2, 0xd9, 0x5b, 0x41, 0x1e, 0xe5, 0x57, 0x4b, 0x20, 0xdf, 0xd8, 0xac, 0xd7, 0x95, - 0x63, 0xea, 0x09, 0xb0, 0xb0, 0xd9, 0xb8, 0xa7, 0xd1, 0x3c, 0xdf, 0xd8, 0xd2, 0x0d, 0xa3, 0x69, - 0x28, 0x39, 0x75, 0x01, 0xcc, 0x2e, 0x97, 0xab, 0x5b, 0xb5, 0xc6, 0xc6, 0x66, 0x5b, 0x91, 0xb4, - 0x57, 0xca, 0x60, 0xb1, 0x05, 0xfd, 0x2a, 0xbc, 0x64, 0x75, 0x60, 0xcb, 0x37, 0x7d, 0xa8, 0xbd, - 0x28, 0x17, 0x0a, 0x53, 0xdd, 0x44, 0x85, 0x86, 0xaf, 0x68, 0x05, 0x1e, 0x77, 0xa0, 0x02, 0x3c, - 0x85, 0x25, 0xfa, 0xf5, 0x12, 0x93, 0x66, 0xb0, 0x74, 0xce, 0x3e, 0x1a, 0xcc, 0x31, 0xef, 0xd4, - 0x45, 0x00, 0x96, 0xcb, 0x95, 0x7b, 0x56, 0x8d, 0xe6, 0x66, 0xa3, 0xaa, 0x1c, 0x43, 0xcf, 0x2b, - 0x4d, 0x43, 0xa7, 0xcf, 0x39, 0xed, 0xbb, 0x39, 0x06, 0xcc, 0x2a, 0x0f, 0xe6, 0xd2, 0x68, 0x66, - 0x86, 0x00, 0xaa, 0xbd, 0x21, 0x04, 0x67, 0x95, 0x03, 0xe7, 0x71, 0xe9, 0xc8, 0x65, 0x0f, 0xd0, - 0x73, 0x24, 0x50, 0x6a, 0xed, 0xee, 0xfb, 0x5d, 0xe7, 0xb2, 0xad, 0xcd, 0x86, 0xc8, 0x68, 0x7f, - 0xc3, 0xca, 0xe4, 0xc9, 0xbc, 0x4c, 0x6e, 0x3c, 0x58, 0x09, 0x4a, 0x21, 0x46, 0x1a, 0xaf, 0x0e, - 0xa5, 0x51, 0xe6, 0xa4, 0xf1, 0x68, 0x51, 0x42, 0xd9, 0xcb, 0xe1, 0x4b, 0x77, 0x80, 0x42, 0xab, - 0x6f, 0x76, 0xa0, 0xf6, 0x39, 0x19, 0xcc, 0xd7, 0xa1, 0x79, 0x09, 0x96, 0xfb, 0x7d, 0xd7, 0xb9, - 0x04, 0xb5, 0x4a, 0xa4, 0xaf, 0xa7, 0xc1, 0x8c, 0x87, 0x32, 0xd5, 0xba, 0xb8, 0x06, 0xb3, 0x46, - 0xf0, 0xa8, 0x9e, 0x01, 0xc0, 0xea, 0x42, 0xdb, 0xb7, 0x7c, 0x0b, 0x7a, 0xa7, 0xa5, 0xeb, 0xe4, - 0x1b, 0x67, 0x0d, 0x26, 0x45, 0xfb, 0xb6, 0x24, 0xaa, 0x63, 0x98, 0x8b, 0x25, 0x96, 0x83, 0x18, - 0xa9, 0xbe, 0x4e, 0x12, 0xd1, 0xb1, 0x91, 0xe4, 0xd2, 0xc9, 0xf6, 0x6d, 0xb9, 0xf4, 0xc2, 0x45, - 0x39, 0x1a, 0xcd, 0xad, 0xd6, 0x66, 0x65, 0x6d, 0xab, 0xb5, 0x51, 0xae, 0xe8, 0x0a, 0x54, 0x4f, - 0x02, 0x05, 0xff, 0xdd, 0xaa, 0xb5, 0xb6, 0xaa, 0x7a, 0x5d, 0x6f, 0xeb, 0x55, 0x65, 0x5b, 0x55, - 0xc1, 0xa2, 0xa1, 0x3f, 0x75, 0x53, 0x6f, 0xb5, 0xb7, 0x56, 0xca, 0xb5, 0xba, 0x5e, 0x55, 0x76, - 0xd0, 0xc7, 0xf5, 0xda, 0x7a, 0xad, 0xbd, 0x65, 0xe8, 0xe5, 0xca, 0x9a, 0x5e, 0x55, 0x76, 0xd5, - 0x07, 0x81, 0xab, 0x1a, 0xcd, 0xad, 0xf2, 0xc6, 0x86, 0xd1, 0x3c, 0xa7, 0x6f, 0xd1, 0x2f, 0x5a, - 0x8a, 0x45, 0x0a, 0x6a, 0x6f, 0xb5, 0xd6, 0xca, 0x86, 0x5e, 0x5e, 0xae, 0xeb, 0xca, 0x7d, 0xda, - 0xb3, 0x65, 0xb0, 0xb0, 0x6e, 0x5e, 0x84, 0xad, 0x5d, 0xd3, 0x85, 0xe6, 0x85, 0x1e, 0xd4, 0x1e, - 0x2e, 0x80, 0xa7, 0xf6, 0x39, 0x16, 0x2f, 0x9d, 0xc7, 0xeb, 0x96, 0x21, 0x02, 0xe6, 0x8a, 0x88, - 0x01, 0xec, 0x9f, 0xc2, 0x66, 0xb0, 0xc6, 0x01, 0xf6, 0xf8, 0x94, 0xf4, 0xd2, 0x21, 0xf6, 0xdf, - 0x1f, 0x00, 0x88, 0x69, 0x5f, 0xce, 0x83, 0xc5, 0x9a, 0x7d, 0xc9, 0xf2, 0xe1, 0x2a, 0xb4, 0xa1, - 0x8b, 0xc6, 0x81, 0x57, 0xe6, 0x44, 0xda, 0x55, 0x1b, 0x00, 0x0b, 0x7f, 0xd7, 0xbe, 0xd2, 0x87, - 0xb8, 0x7a, 0xc3, 0xe5, 0xc5, 0x13, 0x0f, 0x87, 0x88, 0x5a, 0xf8, 0xad, 0xc1, 0xd0, 0x39, 0xfb, - 0x70, 0x00, 0xa2, 0x37, 0x2a, 0x00, 0xc5, 0x75, 0xb8, 0x77, 0x01, 0xba, 0xca, 0x31, 0x75, 0x16, - 0x14, 0x56, 0xd1, 0x97, 0x4a, 0x4e, 0x7b, 0xbd, 0xcc, 0xa8, 0xc0, 0x0a, 0xaf, 0x02, 0x8f, 0x11, - 0x61, 0x61, 0xd8, 0x48, 0x7f, 0x2d, 0x98, 0x25, 0x7c, 0x54, 0xac, 0x2e, 0x45, 0x2b, 0x4a, 0x50, - 0xaf, 0x07, 0x0b, 0xe4, 0x61, 0xc5, 0xea, 0xc1, 0x7b, 0xe0, 0x15, 0x3a, 0xe6, 0xf3, 0x89, 0xda, - 0x4f, 0x84, 0x0d, 0xbf, 0xc6, 0xe9, 0xd1, 0x0f, 0xa6, 0x65, 0x2a, 0x9d, 0x22, 0xbd, 0xe4, 0x81, - 0xd0, 0xf4, 0x0f, 0xb4, 0x70, 0x4b, 0xfb, 0x9e, 0x04, 0xe6, 0x5a, 0xbe, 0xd3, 0x47, 0xcd, 0xc5, - 0xb2, 0x77, 0xc4, 0xda, 0xf7, 0x67, 0xd8, 0xf6, 0x5d, 0xe1, 0xc1, 0x7d, 0xf4, 0x10, 0x39, 0x32, - 0x05, 0xc4, 0xb4, 0xee, 0x6f, 0x87, 0xad, 0x7b, 0x85, 0x43, 0xe5, 0xd6, 0x54, 0xd4, 0xbe, 0x0f, - 0xdb, 0xf6, 0x4b, 0x64, 0xa0, 0x04, 0x6a, 0xe6, 0x57, 0xf6, 0x5d, 0x17, 0xda, 0xbe, 0x18, 0x08, - 0x7f, 0xcc, 0x82, 0xb0, 0xc6, 0x83, 0x70, 0x6b, 0x82, 0x32, 0x07, 0xa5, 0x64, 0xd8, 0xc6, 0x3e, - 0x16, 0xa2, 0x79, 0x0f, 0x87, 0xe6, 0x0f, 0xa5, 0x67, 0x2b, 0x1d, 0xa4, 0x6b, 0x63, 0x20, 0x7a, - 0x12, 0x28, 0x68, 0x3c, 0xac, 0xb4, 0x6b, 0xe7, 0xf4, 0xad, 0x5a, 0xe3, 0x5c, 0xad, 0xad, 0x2b, - 0x50, 0x7b, 0xb1, 0x1c, 0xf5, 0xb9, 0x3e, 0xee, 0xd4, 0xc4, 0x50, 0xf9, 0xb2, 0x34, 0x5e, 0xbf, - 0x47, 0xca, 0x98, 0x0a, 0x26, 0xe2, 0xfd, 0xde, 0x50, 0xa6, 0xd2, 0x21, 0x72, 0xf7, 0x18, 0x88, - 0x9c, 0x02, 0x6a, 0xad, 0x71, 0xae, 0x5c, 0xaf, 0x55, 0x49, 0x1b, 0xdb, 0x6a, 0xdf, 0xbb, 0x81, - 0x30, 0xf9, 0x19, 0x19, 0xcc, 0x13, 0xd6, 0x0c, 0x78, 0xc9, 0xb9, 0x28, 0x68, 0x8c, 0x7c, 0x35, - 0xa5, 0xf1, 0xc8, 0x96, 0x10, 0xd3, 0x5b, 0xfd, 0x78, 0x0a, 0xe3, 0x31, 0x81, 0xdc, 0x03, 0x69, - 0x04, 0x39, 0xd0, 0x35, 0xed, 0x0c, 0xe9, 0xc1, 0x86, 0x8e, 0x20, 0x9f, 0xc8, 0x07, 0xf6, 0xc0, - 0x39, 0x0b, 0x5e, 0xd6, 0xd6, 0x23, 0x4c, 0x38, 0xb5, 0xcd, 0x8d, 0x54, 0x5b, 0x69, 0x98, 0xda, - 0xfe, 0x05, 0x6b, 0x47, 0x2c, 0xf3, 0xe8, 0xdd, 0x1c, 0x2b, 0x6e, 0xc4, 0x49, 0xfc, 0x6a, 0x41, - 0xa0, 0x28, 0x12, 0x6f, 0x2d, 0x5d, 0x0b, 0x66, 0xf1, 0xdf, 0x86, 0xb9, 0x07, 0x69, 0x1b, 0x8a, - 0x12, 0xd4, 0xb3, 0x60, 0x9e, 0x64, 0xec, 0x38, 0x36, 0xaa, 0x4f, 0x1e, 0x67, 0xe0, 0xd2, 0x10, - 0x88, 0x1d, 0x17, 0x9a, 0xbe, 0xe3, 0x62, 0x1a, 0x05, 0x02, 0x22, 0x93, 0xa4, 0xde, 0x0c, 0x4e, - 0x58, 0x1e, 0x6e, 0x55, 0x9b, 0x1e, 0x74, 0x09, 0xb3, 0xa7, 0x8b, 0xd7, 0xe5, 0x6e, 0x2c, 0x19, - 0x07, 0x5f, 0x68, 0xdf, 0x0c, 0xdb, 0xac, 0xce, 0xe9, 0xd9, 0x63, 0xd3, 0x54, 0x3c, 0x9d, 0x96, - 0x5d, 0x1a, 0xaf, 0x07, 0x25, 0xfd, 0xe6, 0x16, 0xd2, 0x8d, 0x15, 0xbc, 0x30, 0x00, 0x69, 0x2b, - 0x46, 0xa9, 0x28, 0x6f, 0xa5, 0xd9, 0x68, 0xeb, 0x8d, 0xb6, 0xb2, 0x3d, 0x54, 0xff, 0x76, 0xb4, - 0xd7, 0xe5, 0x41, 0xfe, 0x6e, 0xc7, 0xb2, 0xb5, 0xe7, 0xe4, 0x38, 0x05, 0xb2, 0xa1, 0x7f, 0xd9, - 0x71, 0x2f, 0x86, 0xcd, 0x3a, 0x4a, 0x48, 0x46, 0x32, 0x52, 0x3c, 0x79, 0xa4, 0xe2, 0xe5, 0x87, - 0x29, 0xde, 0x4f, 0xb3, 0x8a, 0x77, 0x07, 0xaf, 0x78, 0x37, 0x0c, 0x91, 0x3f, 0x62, 0x3e, 0xa6, - 0xbb, 0xf8, 0x74, 0xd8, 0x5d, 0xdc, 0xc5, 0xc1, 0xf8, 0x28, 0x31, 0x32, 0xe9, 0x00, 0xfc, 0x4a, - 0xa6, 0xdd, 0xc4, 0x30, 0xa8, 0x77, 0x62, 0xa0, 0xde, 0x1d, 0xd2, 0x83, 0x58, 0x07, 0x3b, 0x9a, - 0xfb, 0x0e, 0x76, 0x2a, 0x17, 0xd5, 0xab, 0xc1, 0x89, 0x6a, 0x6d, 0x65, 0x45, 0x37, 0xf4, 0x46, - 0x7b, 0xab, 0xa1, 0xb7, 0xcf, 0x37, 0x8d, 0x7b, 0x94, 0x9e, 0xf6, 0x5a, 0x19, 0x00, 0x24, 0xa1, - 0x8a, 0x69, 0x77, 0x60, 0x4f, 0xac, 0xff, 0xff, 0x5b, 0x29, 0x5d, 0x0f, 0x12, 0xd1, 0x8f, 0x81, - 0xf3, 0x15, 0x92, 0x78, 0xab, 0x8c, 0x25, 0x96, 0x0e, 0xd4, 0x37, 0x3f, 0x10, 0x66, 0x0f, 0x57, - 0x81, 0xe3, 0x01, 0x3d, 0x9a, 0x7d, 0xf8, 0xa2, 0xc1, 0xdb, 0xf3, 0x60, 0x91, 0xc2, 0x12, 0xac, - 0x02, 0x3d, 0x4f, 0x68, 0xba, 0xaa, 0x81, 0x12, 0x5d, 0xf4, 0x09, 0x06, 0x83, 0xf0, 0x59, 0x5d, - 0x05, 0x73, 0x7d, 0xe8, 0xee, 0x59, 0x9e, 0x67, 0x39, 0x36, 0x59, 0xce, 0x5d, 0xbc, 0xf5, 0x11, - 0xa1, 0xc4, 0xf1, 0xca, 0xf7, 0xd2, 0x86, 0xe9, 0xfa, 0x56, 0xc7, 0xea, 0x9b, 0xb6, 0xbf, 0x11, - 0x65, 0x36, 0xd8, 0x2f, 0x91, 0x61, 0x97, 0xca, 0x40, 0xe3, 0x6b, 0x12, 0xa3, 0x12, 0xbf, 0x96, - 0x62, 0x52, 0x99, 0x48, 0x30, 0x9d, 0x5a, 0x7c, 0x2a, 0x53, 0xb5, 0x18, 0x82, 0xf7, 0x8e, 0x7a, - 0x0d, 0xb8, 0xba, 0xd6, 0xa8, 0x34, 0x0d, 0x43, 0xaf, 0xb4, 0xb7, 0x36, 0x74, 0x63, 0xbd, 0xd6, - 0x6a, 0xd5, 0x9a, 0x8d, 0xd6, 0x61, 0x5a, 0xbb, 0xf6, 0x59, 0x39, 0xd4, 0x98, 0x2a, 0xec, 0xf4, - 0x2c, 0x1b, 0x6a, 0x77, 0x1d, 0x52, 0x61, 0xf8, 0x35, 0x43, 0x71, 0x9c, 0x69, 0xf9, 0x31, 0x38, - 0xbf, 0x26, 0x3d, 0xce, 0xc3, 0x09, 0xfe, 0x3b, 0x6e, 0xfe, 0x5f, 0x95, 0xc1, 0x09, 0xa6, 0x21, - 0x1a, 0x70, 0x6f, 0x62, 0xeb, 0xc0, 0xff, 0x9d, 0x6d, 0xbb, 0x35, 0x1e, 0xd3, 0x61, 0xb6, 0xf7, - 0x01, 0x36, 0x62, 0x60, 0x7d, 0x73, 0x08, 0x6b, 0x9d, 0x83, 0xf5, 0x89, 0x63, 0xd0, 0x4c, 0x87, - 0xec, 0x3b, 0x32, 0x45, 0xf6, 0x1a, 0x70, 0xf5, 0x46, 0xd9, 0x68, 0xd7, 0x2a, 0xb5, 0x8d, 0x32, - 0x1a, 0x47, 0x99, 0x21, 0x3b, 0xc6, 0xb8, 0xe7, 0x41, 0x1f, 0x8a, 0xef, 0x47, 0xf3, 0xe0, 0xda, - 0xe1, 0x1d, 0x6d, 0x65, 0xd7, 0xb4, 0x77, 0xa0, 0x66, 0x89, 0x40, 0x5d, 0x05, 0x33, 0x1d, 0x9c, - 0x9d, 0xe0, 0xcc, 0x6e, 0xfc, 0x25, 0xf4, 0xe5, 0xa4, 0x04, 0x23, 0xf8, 0x54, 0x7b, 0x37, 0xab, - 0x10, 0x6d, 0x5e, 0x21, 0x9e, 0x9c, 0x0c, 0xde, 0x01, 0xbe, 0x63, 0x74, 0xe3, 0xf3, 0xa1, 0x6e, - 0x9c, 0xe7, 0x74, 0xa3, 0x72, 0x38, 0xf2, 0xe9, 0xd4, 0xe4, 0xb7, 0x1e, 0x08, 0x1d, 0x40, 0xac, - 0x36, 0x59, 0xf1, 0xa3, 0xc2, 0xd0, 0xee, 0xfe, 0x55, 0x32, 0x28, 0x56, 0x61, 0x0f, 0xfa, 0x82, - 0x33, 0xf8, 0xbf, 0x93, 0x44, 0xb7, 0xd3, 0x08, 0x0c, 0x84, 0x76, 0xfc, 0x5a, 0x8a, 0x6f, 0xed, - 0x41, 0xcf, 0x37, 0xf7, 0xfa, 0x58, 0xd4, 0xb2, 0x11, 0x25, 0x68, 0x3f, 0x2a, 0x89, 0x6c, 0xb6, - 0x25, 0x14, 0xf3, 0xef, 0x63, 0x55, 0xf8, 0x0b, 0x12, 0x28, 0xb5, 0xa0, 0xdf, 0x74, 0xbb, 0xd0, - 0xd5, 0x5a, 0x11, 0x46, 0xd7, 0x81, 0x39, 0x0c, 0x0a, 0x9a, 0x66, 0x86, 0x38, 0xb1, 0x49, 0xea, - 0x0d, 0x60, 0x31, 0x7c, 0xc4, 0x9f, 0xd3, 0x6e, 0x7c, 0x20, 0x55, 0xfb, 0x56, 0x4e, 0xd4, 0x07, - 0x80, 0x2e, 0xfa, 0x52, 0x6e, 0x62, 0x5a, 0xa9, 0xd8, 0x7e, 0x7e, 0x22, 0xa9, 0xec, 0xb7, 0x49, - 0xdf, 0x29, 0x01, 0xb0, 0x69, 0x7b, 0x81, 0x5c, 0x1f, 0x95, 0x42, 0xae, 0xda, 0x3f, 0xe6, 0xd2, - 0xcd, 0x62, 0xa2, 0x72, 0x62, 0x24, 0xf6, 0x4b, 0x29, 0xd6, 0x16, 0x62, 0x89, 0x4d, 0x61, 0x6b, - 0xf9, 0x38, 0x28, 0x9e, 0x37, 0x7b, 0x3d, 0xe8, 0x6b, 0xaf, 0x94, 0x41, 0xb1, 0xe2, 0x42, 0xd3, - 0x87, 0x1a, 0x8c, 0x44, 0xa7, 0x81, 0x92, 0xeb, 0x38, 0xfe, 0x86, 0xe9, 0xef, 0x52, 0xb9, 0x85, - 0xcf, 0xea, 0x13, 0xc1, 0x83, 0xb6, 0xf7, 0x7b, 0x3d, 0x1f, 0xde, 0xef, 0x6f, 0xb8, 0xd6, 0x9e, - 0xe9, 0x5e, 0xa9, 0x9b, 0xf6, 0xce, 0xbe, 0xb9, 0x03, 0x29, 0x7b, 0x71, 0xaf, 0xa9, 0xa3, 0xca, - 0xaf, 0xb0, 0x1d, 0xcf, 0x5d, 0xbc, 0xd0, 0x7f, 0x80, 0x93, 0x13, 0x61, 0x71, 0x89, 0xb0, 0x17, - 0xd3, 0xf3, 0x68, 0xa0, 0xb4, 0x67, 0xc3, 0x3d, 0xc7, 0xb6, 0x3a, 0x81, 0xb5, 0x1a, 0x3c, 0x6b, - 0x1f, 0x0f, 0xd1, 0x58, 0xe6, 0xd0, 0x58, 0x12, 0x2e, 0x25, 0x1d, 0x14, 0xad, 0x31, 0xfa, 0x9d, - 0x87, 0x82, 0x07, 0x93, 0x6e, 0x64, 0xab, 0xdd, 0xdc, 0xaa, 0x18, 0x7a, 0xb9, 0xad, 0x6f, 0xd5, - 0x9b, 0x95, 0x72, 0x7d, 0xcb, 0xd0, 0x37, 0x9a, 0x0a, 0x44, 0xb3, 0xf3, 0x19, 0x03, 0x76, 0x9c, - 0x4b, 0xd0, 0xd5, 0x9e, 0x95, 0x13, 0x83, 0x28, 0x41, 0x28, 0x49, 0xf0, 0xc9, 0x22, 0xf0, 0xfd, - 0xb4, 0xb0, 0x9f, 0x11, 0x15, 0x2c, 0x65, 0x3e, 0xa6, 0xc5, 0x7c, 0x42, 0xa8, 0x8f, 0x49, 0x24, - 0xf5, 0x00, 0x00, 0xe9, 0x1f, 0x24, 0x30, 0x53, 0x71, 0xec, 0x4b, 0xd0, 0xf5, 0xd9, 0x49, 0x16, - 0x8b, 0x43, 0x6e, 0x00, 0x87, 0xd3, 0x60, 0x06, 0xda, 0xbe, 0xeb, 0xf4, 0x83, 0x59, 0x56, 0xf0, - 0xa8, 0xbd, 0x31, 0xad, 0x84, 0x69, 0xc9, 0xf1, 0x6b, 0xb3, 0xc3, 0x0b, 0xe2, 0xd8, 0x93, 0x07, - 0xda, 0xce, 0x6b, 0xd3, 0xe0, 0x32, 0x9c, 0x81, 0xec, 0xfb, 0xb1, 0xaf, 0xc9, 0x60, 0x81, 0xb4, - 0xdb, 0x16, 0xc4, 0x66, 0xa1, 0xd6, 0x64, 0xd7, 0x39, 0x07, 0x84, 0xbf, 0x76, 0x8c, 0x13, 0x7f, - 0xd1, 0xec, 0xf7, 0xc3, 0x15, 0xf2, 0xb5, 0x63, 0x06, 0x7d, 0x26, 0x6a, 0xbe, 0x5c, 0x04, 0x79, - 0x73, 0xdf, 0xdf, 0xd5, 0xbe, 0x27, 0x3c, 0xe3, 0xe5, 0xfa, 0x11, 0xca, 0x4f, 0x0c, 0x24, 0x27, - 0x41, 0xc1, 0x77, 0x2e, 0xc2, 0x40, 0x0e, 0xe4, 0x01, 0xc1, 0x61, 0xf6, 0xfb, 0x6d, 0xfc, 0x82, - 0xc2, 0x11, 0x3c, 0x23, 0x03, 0xcb, 0xec, 0x74, 0x9c, 0x7d, 0xdb, 0xaf, 0x05, 0xab, 0xe4, 0x51, - 0x82, 0xf6, 0x25, 0xa1, 0x6d, 0x28, 0x01, 0x06, 0xd3, 0x41, 0x76, 0x61, 0x8c, 0xa6, 0xb4, 0x04, - 0x6e, 0x2a, 0x6f, 0x6c, 0x6c, 0xb5, 0x9b, 0xf7, 0xe8, 0x8d, 0xc8, 0xda, 0xdd, 0xaa, 0x35, 0xb6, - 0xda, 0x6b, 0xfa, 0x56, 0x65, 0xd3, 0xc0, 0x8b, 0x93, 0xe5, 0x4a, 0xa5, 0xb9, 0xd9, 0x68, 0x2b, - 0x50, 0x7b, 0xab, 0x04, 0xe6, 0x2b, 0x3d, 0xc7, 0x0b, 0x11, 0x7e, 0x68, 0x84, 0x70, 0x28, 0xc6, - 0x1c, 0x23, 0x46, 0xed, 0x5f, 0x72, 0xa2, 0x7e, 0x32, 0x81, 0x40, 0x18, 0xf2, 0x31, 0xbd, 0xd4, - 0x1b, 0x85, 0xfc, 0x64, 0x46, 0xd3, 0xcb, 0xbe, 0x49, 0x7c, 0x6e, 0x05, 0xcc, 0x94, 0x89, 0x62, - 0x68, 0x7f, 0x9a, 0x03, 0xc5, 0x8a, 0x63, 0x6f, 0x5b, 0x3b, 0xc8, 0x82, 0x84, 0xb6, 0x79, 0xa1, - 0x07, 0xab, 0xa6, 0x6f, 0x5e, 0xb2, 0xe0, 0x65, 0x5c, 0x81, 0x92, 0x31, 0x90, 0x8a, 0x98, 0xa2, - 0x29, 0xf0, 0xc2, 0xfe, 0x0e, 0x66, 0xaa, 0x64, 0xb0, 0x49, 0x68, 0xfc, 0x20, 0x8f, 0x1b, 0x2e, - 0x74, 0x61, 0x0f, 0x9a, 0x1e, 0x44, 0x73, 0x31, 0x1b, 0xf6, 0xb0, 0xd2, 0x96, 0x8c, 0xb8, 0xd7, - 0xea, 0x59, 0x30, 0x4f, 0x5e, 0x61, 0xfb, 0xc7, 0xc3, 0x6a, 0x5c, 0x32, 0xb8, 0x34, 0xf5, 0xd1, - 0xa0, 0x00, 0xef, 0xf7, 0x5d, 0xf3, 0x74, 0x17, 0xe3, 0xf5, 0xa0, 0x25, 0xe2, 0x28, 0xbb, 0x14, - 0x38, 0xca, 0x2e, 0xb5, 0xb0, 0x1b, 0xad, 0x41, 0x72, 0x69, 0xff, 0xbb, 0x14, 0x5a, 0x2f, 0x5f, - 0x90, 0x23, 0xc5, 0x50, 0x41, 0xde, 0x36, 0xf7, 0x20, 0xd5, 0x0b, 0xfc, 0x5f, 0xbd, 0x09, 0x1c, - 0x37, 0x2f, 0x99, 0xbe, 0xe9, 0xd6, 0x9d, 0x8e, 0xd9, 0xc3, 0xc3, 0x66, 0xd0, 0xf2, 0x07, 0x5f, - 0xe0, 0x4d, 0x2b, 0xdf, 0x71, 0x21, 0xce, 0x15, 0x6c, 0x5a, 0x05, 0x09, 0x88, 0xba, 0xd5, 0x71, - 0x6c, 0xcc, 0xbf, 0x6c, 0xe0, 0xff, 0x48, 0x2a, 0x5d, 0xcb, 0x43, 0x15, 0xc1, 0x54, 0x1a, 0x64, - 0x3f, 0xa5, 0x75, 0xc5, 0xee, 0xe0, 0x0d, 0xab, 0x92, 0x11, 0xf7, 0x5a, 0x5d, 0x06, 0x73, 0x74, - 0xf7, 0x65, 0x1d, 0xe9, 0x55, 0x11, 0xeb, 0xd5, 0x75, 0xbc, 0x1b, 0x22, 0xc1, 0x73, 0xa9, 0x11, - 0xe5, 0x33, 0xd8, 0x8f, 0xd4, 0xa7, 0x80, 0x07, 0xd3, 0xc7, 0xca, 0xbe, 0xe7, 0x3b, 0x7b, 0x04, - 0xf4, 0x15, 0xab, 0x47, 0x6a, 0x30, 0x83, 0x6b, 0x90, 0x94, 0x45, 0xbd, 0x15, 0x9c, 0xec, 0xbb, - 0x70, 0x1b, 0xba, 0xf7, 0x9a, 0x7b, 0xfb, 0xf7, 0xb7, 0x5d, 0xd3, 0xf6, 0xfa, 0x8e, 0xeb, 0x9f, - 0x2e, 0x61, 0xe6, 0x87, 0xbe, 0x53, 0x6f, 0x06, 0x27, 0xee, 0xf3, 0x1c, 0xbb, 0xdc, 0xb7, 0xea, - 0x96, 0xe7, 0x43, 0xbb, 0xdc, 0xed, 0xba, 0xa7, 0x67, 0x71, 0x59, 0x07, 0x5f, 0xa8, 0xd7, 0x83, - 0x85, 0xfb, 0x1c, 0xcb, 0x6e, 0xf9, 0x2e, 0x34, 0xf7, 0x36, 0xdd, 0xde, 0x69, 0x40, 0x36, 0x88, - 0xb8, 0x44, 0xda, 0xf9, 0x96, 0x40, 0x91, 0x40, 0xa2, 0xbd, 0xa8, 0x20, 0xec, 0xd5, 0x4c, 0x85, - 0x94, 0x68, 0x2d, 0x3e, 0x06, 0xcc, 0xd0, 0x5e, 0x13, 0x83, 0x3f, 0x77, 0xeb, 0xa9, 0x81, 0x05, - 0x12, 0x4a, 0xc5, 0x08, 0xb2, 0xa9, 0x8f, 0x03, 0xc5, 0x0e, 0x16, 0x15, 0xd6, 0x83, 0xb9, 0x5b, - 0x1f, 0x3c, 0xbc, 0x50, 0x9c, 0xc5, 0xa0, 0x59, 0xb5, 0x2f, 0xcb, 0x42, 0x8e, 0xd0, 0x49, 0x1c, - 0xa7, 0xeb, 0x29, 0xbe, 0x29, 0x8d, 0xd1, 0x15, 0xdf, 0x0c, 0x6e, 0xa4, 0xfd, 0x2c, 0xb5, 0x69, - 0xaa, 0x5b, 0xcb, 0x9b, 0xc1, 0xac, 0x16, 0x59, 0x3a, 0xad, 0x76, 0xd9, 0x68, 0x6f, 0x35, 0x9a, - 0x55, 0x34, 0x1b, 0xbe, 0x09, 0xdc, 0x30, 0x22, 0xb7, 0xde, 0xde, 0x6a, 0x94, 0xd7, 0x75, 0x65, - 0x9b, 0xb7, 0x97, 0x5a, 0xed, 0xe6, 0xc6, 0x96, 0xb1, 0xd9, 0x68, 0xd4, 0x1a, 0xab, 0x84, 0x18, - 0x32, 0x50, 0x4f, 0x45, 0x19, 0xce, 0x1b, 0xb5, 0xb6, 0xbe, 0x55, 0x69, 0x36, 0x56, 0x6a, 0xab, - 0x8a, 0x35, 0xca, 0xd8, 0xba, 0x4f, 0xbd, 0x0e, 0x5c, 0xcb, 0x71, 0x52, 0x6b, 0x36, 0xd0, 0x14, - 0xbd, 0x52, 0x6e, 0x54, 0x74, 0x34, 0x1f, 0xbf, 0xa8, 0x6a, 0xe0, 0x6a, 0x42, 0x6e, 0x6b, 0xa5, - 0x56, 0x67, 0x77, 0xd5, 0x3e, 0x93, 0x53, 0x4f, 0x83, 0xab, 0xd8, 0x77, 0xd4, 0x27, 0x42, 0xf9, - 0xcd, 0x9c, 0x7a, 0x3d, 0x78, 0x28, 0xf7, 0x15, 0xd9, 0x20, 0xdb, 0xaa, 0x55, 0xb7, 0xd6, 0x6b, - 0xad, 0xf5, 0x72, 0xbb, 0xb2, 0xa6, 0x7c, 0x16, 0x4f, 0x5f, 0x42, 0x7b, 0x9c, 0xf1, 0x4e, 0x7e, - 0x09, 0x6b, 0x27, 0x94, 0x79, 0x45, 0x7d, 0xd4, 0x50, 0xd8, 0x93, 0xed, 0xe2, 0x4f, 0x85, 0x23, - 0x4e, 0x95, 0x53, 0xa1, 0xc7, 0xa4, 0xa0, 0x95, 0x4e, 0x87, 0xda, 0x63, 0xa8, 0xd0, 0x75, 0xe0, - 0xda, 0x86, 0x4e, 0x90, 0x32, 0xf4, 0x4a, 0xf3, 0x9c, 0x6e, 0x6c, 0x9d, 0x2f, 0xd7, 0xeb, 0x7a, - 0x7b, 0x6b, 0xa5, 0x66, 0xb4, 0xda, 0xca, 0xb6, 0xf6, 0x8f, 0x52, 0xb8, 0x2c, 0xc5, 0x48, 0xeb, - 0x4f, 0xa5, 0xb4, 0xcd, 0x3a, 0x71, 0xf9, 0xe9, 0x07, 0x41, 0xd1, 0xf3, 0x4d, 0x7f, 0xdf, 0xa3, - 0xad, 0xfa, 0x21, 0xc3, 0x5b, 0xf5, 0x52, 0x0b, 0x67, 0x32, 0x68, 0x66, 0xed, 0xcb, 0xb9, 0x34, - 0xcd, 0x74, 0x02, 0x2b, 0x53, 0xd6, 0x18, 0x22, 0x3e, 0x03, 0xb4, 0x40, 0xdb, 0x6b, 0xad, 0xad, - 0x72, 0xdd, 0xd0, 0xcb, 0xd5, 0x7b, 0xc3, 0xf5, 0x28, 0xa8, 0x5e, 0x0d, 0x4e, 0x6c, 0x36, 0xca, - 0xcb, 0x75, 0x1d, 0x37, 0x97, 0x66, 0xa3, 0xa1, 0x57, 0x90, 0xdc, 0x7f, 0x14, 0xef, 0xfe, 0x20, - 0xab, 0x1c, 0xf3, 0x8d, 0x2c, 0x27, 0x46, 0xfe, 0x7f, 0x29, 0xec, 0xe6, 0x16, 0x69, 0x18, 0x4b, - 0x6b, 0xb2, 0x38, 0x7c, 0x49, 0xc8, 0xb3, 0x4d, 0x88, 0x93, 0x74, 0x78, 0xfc, 0x97, 0x31, 0xf0, - 0xb8, 0x1a, 0x9c, 0x60, 0xf1, 0xc0, 0x1e, 0x6e, 0xf1, 0x30, 0xfc, 0x89, 0x0c, 0x66, 0xd6, 0xad, - 0x1d, 0xec, 0x5e, 0xbc, 0x1f, 0x19, 0x28, 0x8b, 0x40, 0x0a, 0xbd, 0x77, 0x24, 0xab, 0xcb, 0x4d, - 0xe6, 0x25, 0xf1, 0xf5, 0x16, 0xa1, 0x09, 0xfb, 0x97, 0x53, 0xf7, 0x4c, 0x94, 0xe1, 0x98, 0x9e, - 0xe9, 0xf9, 0x52, 0x9a, 0x9e, 0x69, 0x38, 0xad, 0x54, 0x30, 0x21, 0xd3, 0xc1, 0x85, 0xcf, 0xd8, - 0xb7, 0x5c, 0xd8, 0xc5, 0x66, 0x22, 0xae, 0xb7, 0x6c, 0xf0, 0x89, 0x67, 0xdd, 0xc3, 0x81, 0xc9, - 0x7a, 0xd9, 0xcc, 0x83, 0x52, 0x38, 0x9a, 0xe0, 0x0d, 0x1f, 0xf4, 0x52, 0x6f, 0x34, 0x37, 0x57, - 0xd7, 0xb6, 0x56, 0x0c, 0x5d, 0xa7, 0x4b, 0xc4, 0x3b, 0xda, 0xbb, 0x24, 0xb0, 0x40, 0x6b, 0x48, - 0xbd, 0x27, 0x1e, 0x1a, 0x0b, 0x32, 0x85, 0xe3, 0xdf, 0xd8, 0xe9, 0xc9, 0x2a, 0x0f, 0xc7, 0x63, - 0x93, 0x44, 0x98, 0xe8, 0x3e, 0xf1, 0xa6, 0xb0, 0x09, 0xdd, 0xcd, 0x81, 0xf2, 0x84, 0xd4, 0x14, - 0xb3, 0x9f, 0xa2, 0xbc, 0x08, 0x80, 0x62, 0x0b, 0xf6, 0x60, 0xc7, 0xd7, 0x3e, 0x2c, 0x8f, 0xdd, - 0x26, 0xe2, 0xcc, 0x6d, 0x39, 0x95, 0xb9, 0x9d, 0xcf, 0xc0, 0xdc, 0x2e, 0x8c, 0x6f, 0x6e, 0x17, - 0xd3, 0x9a, 0xdb, 0x33, 0x71, 0xe6, 0x76, 0x42, 0xaf, 0x51, 0x4a, 0xec, 0x35, 0x06, 0x0c, 0x75, - 0xa3, 0x4e, 0x4d, 0x7a, 0x3e, 0x91, 0x2a, 0xf3, 0x27, 0x8b, 0x69, 0xc7, 0x71, 0x02, 0xfc, 0xd1, - 0x9a, 0xe7, 0x3f, 0x59, 0x48, 0x33, 0xee, 0x0f, 0xe5, 0x38, 0x5d, 0x2b, 0x79, 0x45, 0x3e, 0x83, - 0x45, 0x47, 0xf5, 0xe1, 0xe0, 0xa1, 0xd1, 0xf3, 0x96, 0xfe, 0xb4, 0x5a, 0xab, 0xdd, 0xc2, 0x36, - 0x79, 0xa5, 0x69, 0x18, 0x9b, 0x1b, 0x64, 0xbb, 0xea, 0x14, 0x50, 0x23, 0x2a, 0xc6, 0x66, 0x83, - 0x58, 0xe0, 0x3b, 0x3c, 0xf5, 0x95, 0x5a, 0xa3, 0xba, 0x15, 0x8e, 0x6a, 0x8d, 0x95, 0xa6, 0xb2, - 0xab, 0x2e, 0x81, 0x9b, 0x18, 0xea, 0xb8, 0x03, 0x24, 0x25, 0x94, 0x1b, 0xd5, 0xad, 0xf5, 0x86, - 0xbe, 0xde, 0x6c, 0xd4, 0x2a, 0x38, 0xbd, 0xa5, 0xb7, 0x15, 0x0b, 0x99, 0x82, 0x03, 0x36, 0x7f, - 0x4b, 0x2f, 0x1b, 0x95, 0x35, 0xdd, 0x20, 0x45, 0xde, 0xa7, 0xde, 0x00, 0xce, 0x96, 0x1b, 0xcd, - 0x36, 0x4a, 0x29, 0x37, 0xee, 0x6d, 0xdf, 0xbb, 0xa1, 0x6f, 0x6d, 0x18, 0xcd, 0x8a, 0xde, 0x6a, - 0xa1, 0x91, 0x94, 0xce, 0x10, 0x94, 0x9e, 0xfa, 0x64, 0x70, 0x3b, 0xc3, 0x9a, 0xde, 0xc6, 0xbe, - 0x11, 0xeb, 0x4d, 0xec, 0x1e, 0x57, 0xd5, 0xb7, 0xd6, 0xca, 0xad, 0xad, 0x5a, 0xa3, 0xd2, 0x5c, - 0xdf, 0x28, 0xb7, 0x6b, 0x68, 0xc0, 0xdd, 0x30, 0x9a, 0xed, 0xe6, 0xd6, 0x39, 0xdd, 0x68, 0xd5, - 0x9a, 0x0d, 0xc5, 0x46, 0x55, 0x66, 0x46, 0xe8, 0xc0, 0x52, 0x72, 0xd4, 0x6b, 0xc1, 0xe9, 0x20, - 0xbd, 0xde, 0x44, 0x82, 0x66, 0xe6, 0x0c, 0x7d, 0xd6, 0xce, 0x6a, 0xb5, 0x9b, 0x06, 0x99, 0x35, - 0xac, 0xd7, 0x56, 0x0d, 0x34, 0xd5, 0x51, 0x9e, 0x91, 0xe9, 0x9c, 0xe2, 0x9f, 0x25, 0x90, 0x6f, - 0xf9, 0x4e, 0x5f, 0xfb, 0x81, 0xa8, 0x3b, 0x3c, 0x03, 0x80, 0x8b, 0x5d, 0x21, 0xaa, 0xa6, 0x6f, - 0xd2, 0xd5, 0x1a, 0x26, 0x45, 0xfb, 0x0d, 0xe1, 0xfd, 0xdb, 0xc8, 0xea, 0x72, 0xfa, 0x31, 0xc3, - 0xc7, 0x77, 0xc5, 0x8e, 0x43, 0xc6, 0x13, 0x4a, 0xd7, 0x1e, 0x7e, 0x7c, 0x9c, 0x1d, 0x5a, 0x0d, - 0x9c, 0x62, 0x60, 0x45, 0xf2, 0x0f, 0x54, 0x06, 0xaa, 0x0f, 0x02, 0x57, 0x0d, 0x28, 0x1f, 0xd6, - 0xb9, 0x6d, 0xf5, 0x61, 0xe0, 0x21, 0x8c, 0xfa, 0xeb, 0xeb, 0xcd, 0x73, 0x7a, 0xa8, 0xe8, 0xd5, - 0x72, 0xbb, 0xac, 0xec, 0x68, 0x5f, 0x90, 0x41, 0x7e, 0xdd, 0xb9, 0x34, 0xb8, 0x6d, 0x6e, 0xc3, - 0xcb, 0xcc, 0xde, 0x4a, 0xf0, 0xc8, 0x1f, 0xc1, 0x12, 0x12, 0xfb, 0x7a, 0xbc, 0x8b, 0xcc, 0x97, - 0xa4, 0x34, 0x62, 0x5f, 0x3f, 0xac, 0x5f, 0xcc, 0x5f, 0x8f, 0x23, 0xf6, 0x18, 0xd1, 0x42, 0xf5, - 0x2c, 0x38, 0x13, 0xbd, 0xa8, 0x55, 0xf5, 0x46, 0xbb, 0xb6, 0x72, 0x6f, 0x24, 0xdc, 0x9a, 0x21, - 0x24, 0xfe, 0x51, 0xdd, 0x5c, 0xf2, 0x5a, 0xc1, 0x69, 0x70, 0x32, 0x7a, 0xb7, 0xaa, 0xb7, 0x83, - 0x37, 0xf7, 0x69, 0xcf, 0x29, 0x80, 0x79, 0xd2, 0xed, 0x6f, 0xf6, 0xbb, 0xc8, 0xfa, 0x7e, 0x5c, - 0x84, 0xee, 0x8d, 0xe0, 0x78, 0x6d, 0x63, 0xa5, 0xd5, 0xf2, 0x1d, 0xd7, 0xdc, 0x81, 0x78, 0x1c, - 0x25, 0xd2, 0x1a, 0x4c, 0xd6, 0xde, 0x2b, 0xbc, 0xfa, 0xcf, 0x0f, 0x35, 0xa4, 0xcc, 0x18, 0xd4, - 0xbf, 0x26, 0xb4, 0x5a, 0x2f, 0x40, 0x30, 0x1d, 0xfa, 0xf7, 0x4d, 0xb8, 0xcd, 0xc5, 0xe3, 0xb2, - 0x7d, 0xf6, 0xb9, 0x12, 0x98, 0x6d, 0x5b, 0x7b, 0xf0, 0x99, 0x8e, 0x0d, 0x3d, 0x75, 0x06, 0xc8, - 0xab, 0xeb, 0x6d, 0xe5, 0x18, 0xfa, 0x83, 0xa6, 0x45, 0x39, 0xfc, 0x47, 0x47, 0x05, 0xa0, 0x3f, - 0xe5, 0xb6, 0x22, 0xa3, 0x3f, 0xeb, 0x7a, 0x5b, 0xc9, 0xa3, 0x3f, 0x0d, 0xbd, 0xad, 0x14, 0xd0, - 0x9f, 0x8d, 0x7a, 0x5b, 0x29, 0xa2, 0x3f, 0xb5, 0x56, 0x5b, 0x99, 0x41, 0x7f, 0x96, 0x5b, 0x6d, - 0xa5, 0x84, 0xfe, 0x9c, 0x6b, 0xb5, 0x95, 0x59, 0xf4, 0xa7, 0xd2, 0x6e, 0x2b, 0x00, 0xfd, 0xb9, - 0xbb, 0xd5, 0x56, 0xe6, 0xd0, 0x9f, 0x72, 0xa5, 0xad, 0xcc, 0xe3, 0x3f, 0x7a, 0x5b, 0x59, 0x40, - 0x7f, 0x5a, 0xad, 0xb6, 0xb2, 0x88, 0x29, 0xb7, 0xda, 0xca, 0x71, 0x5c, 0x56, 0xad, 0xad, 0x28, - 0xe8, 0xcf, 0x5a, 0xab, 0xad, 0x9c, 0xc0, 0x99, 0x5b, 0x6d, 0x45, 0xc5, 0x85, 0xb6, 0xda, 0xca, - 0x55, 0x38, 0x4f, 0xab, 0xad, 0x9c, 0xc4, 0x45, 0xb4, 0xda, 0xca, 0xd5, 0x98, 0x0d, 0xbd, 0xad, - 0x9c, 0xc2, 0x79, 0x8c, 0xb6, 0xf2, 0x20, 0xfc, 0xaa, 0xd1, 0x56, 0x4e, 0x63, 0xc6, 0xf4, 0xb6, - 0x72, 0x0d, 0xfe, 0x63, 0xb4, 0x15, 0x0d, 0xbf, 0x2a, 0xb7, 0x95, 0x07, 0x6b, 0x0f, 0x01, 0xb3, - 0xab, 0xd0, 0x27, 0x20, 0x6a, 0x0a, 0x90, 0x57, 0xa1, 0xcf, 0x4e, 0xc4, 0x5f, 0x99, 0x07, 0x0f, - 0xa2, 0x8b, 0x37, 0x2b, 0xae, 0xb3, 0x57, 0x87, 0x3b, 0x66, 0xe7, 0x8a, 0x7e, 0x3f, 0x32, 0xf8, - 0xb4, 0x17, 0xe6, 0xb8, 0x15, 0xed, 0x7e, 0xd4, 0x1b, 0xe1, 0xff, 0x89, 0x06, 0x72, 0xb0, 0x46, - 0x2d, 0xf3, 0x6b, 0xd4, 0x71, 0x26, 0x61, 0x5e, 0x64, 0x22, 0xf9, 0xf7, 0x6c, 0x63, 0xe0, 0x36, - 0xa4, 0x72, 0x03, 0x1b, 0x52, 0xa8, 0x85, 0xf5, 0xa1, 0xeb, 0x39, 0xb6, 0xd9, 0x6b, 0x51, 0xf7, - 0x23, 0x32, 0x57, 0x1d, 0x4c, 0x56, 0x9f, 0x1a, 0x34, 0x2a, 0x62, 0xf0, 0x3d, 0x29, 0x69, 0x79, - 0x6b, 0x50, 0x42, 0x31, 0xed, 0xeb, 0xb3, 0x61, 0xfb, 0x6a, 0x73, 0xed, 0xeb, 0x29, 0x87, 0xa0, - 0x9d, 0xae, 0xa9, 0xd5, 0xc6, 0x9b, 0x8a, 0x46, 0xce, 0xf9, 0xc1, 0xfe, 0x97, 0xac, 0x7d, 0x41, - 0x02, 0xa7, 0x74, 0x7b, 0xd8, 0x54, 0x86, 0x55, 0xa3, 0xb7, 0xb2, 0xd0, 0x6c, 0xf0, 0x22, 0xbd, - 0x7d, 0x68, 0xb5, 0x87, 0xd3, 0x8c, 0x91, 0xe8, 0xef, 0x84, 0x12, 0x6d, 0x71, 0x12, 0xbd, 0x6b, - 0x7c, 0xd2, 0xe9, 0x04, 0xda, 0x98, 0x68, 0xdf, 0x95, 0xd7, 0xfe, 0x5c, 0x02, 0x27, 0x88, 0x07, - 0xe1, 0xdd, 0x64, 0xe6, 0x84, 0x7b, 0x7b, 0xde, 0xfa, 0xea, 0x45, 0xb3, 0x2c, 0xa2, 0xdf, 0x4c, - 0x8a, 0xf6, 0x3a, 0x56, 0xe0, 0xf7, 0xf0, 0x02, 0x8f, 0xe9, 0xc7, 0x07, 0x8b, 0x8b, 0x91, 0xf5, - 0x6f, 0x86, 0xb2, 0x6e, 0x70, 0xb2, 0xbe, 0x7d, 0x2c, 0xaa, 0x47, 0x2b, 0xe6, 0x6f, 0xe6, 0xc1, - 0x43, 0x08, 0x87, 0x54, 0x11, 0x48, 0x3f, 0x58, 0xb6, 0xbb, 0x06, 0xf4, 0x7c, 0xd3, 0xf5, 0xb9, - 0xd0, 0x2b, 0x03, 0x53, 0xf3, 0x5c, 0x06, 0x53, 0x73, 0x69, 0xe4, 0xd4, 0x5c, 0x7b, 0x0f, 0x6b, - 0xe0, 0x9d, 0xe7, 0x91, 0x2d, 0x27, 0x60, 0x10, 0x53, 0xc3, 0xb8, 0x16, 0x15, 0x5a, 0x7e, 0x3f, - 0xcc, 0xa1, 0xbc, 0x72, 0xe8, 0x12, 0xd2, 0x21, 0xfe, 0x1b, 0x93, 0xb5, 0xc4, 0xf3, 0xec, 0x3b, - 0xde, 0x6c, 0x54, 0xba, 0x99, 0x4e, 0xa1, 0x5e, 0x5c, 0x02, 0xb3, 0xb8, 0xcb, 0xa9, 0x5b, 0xf6, - 0x45, 0xed, 0x1b, 0x32, 0x98, 0x6f, 0xc0, 0xcb, 0x95, 0x5d, 0xb3, 0xd7, 0x83, 0xf6, 0x0e, 0xd4, - 0xee, 0xe3, 0x6c, 0x7b, 0xb3, 0xdf, 0x6f, 0x44, 0xfb, 0xc3, 0xc1, 0xa3, 0x7a, 0x17, 0x28, 0x78, - 0x1d, 0x27, 0x0c, 0xea, 0xf0, 0x03, 0x31, 0xab, 0xd7, 0xe5, 0x7d, 0x7f, 0x77, 0x09, 0x97, 0x55, - 0xee, 0x5b, 0x2d, 0xf4, 0x81, 0x41, 0xbe, 0xa3, 0xe3, 0xe4, 0x5f, 0x0e, 0xed, 0x8c, 0x73, 0x09, - 0x9d, 0x71, 0xc8, 0xf8, 0x12, 0xcb, 0x74, 0xcc, 0x22, 0xc9, 0x75, 0x60, 0xae, 0x13, 0x64, 0x09, - 0x4f, 0xe9, 0xb1, 0x49, 0xda, 0x5f, 0xa4, 0xea, 0xae, 0x85, 0x0a, 0x4f, 0xa7, 0x55, 0x70, 0xc2, - 0xa6, 0xe6, 0xd5, 0xe0, 0x44, 0xbb, 0xd9, 0xdc, 0x5a, 0x2f, 0x37, 0xee, 0x8d, 0x62, 0xab, 0x6c, - 0x6b, 0xaf, 0xc8, 0x83, 0xc5, 0x96, 0xd3, 0xbb, 0x04, 0x23, 0x9c, 0x6b, 0x9c, 0xfb, 0x27, 0x2b, - 0xa7, 0xdc, 0x01, 0x39, 0xa9, 0xa7, 0x40, 0xd1, 0xb4, 0xbd, 0xcb, 0x30, 0x30, 0xff, 0xe9, 0x13, - 0x85, 0xf1, 0xa3, 0x6c, 0x47, 0x60, 0xf0, 0x30, 0xde, 0x31, 0x42, 0x92, 0x3c, 0x57, 0x31, 0x40, - 0x9e, 0x05, 0xf3, 0x1e, 0xf1, 0x12, 0x69, 0x33, 0xce, 0x40, 0x5c, 0x1a, 0x66, 0x91, 0xb8, 0x29, - 0xc9, 0x94, 0x45, 0xfc, 0xa4, 0xbd, 0x36, 0xec, 0x3f, 0x36, 0x39, 0x88, 0xcb, 0x87, 0x61, 0x2c, - 0x1d, 0xc8, 0xaf, 0x9a, 0xf4, 0x24, 0xfe, 0x34, 0x38, 0x19, 0x9c, 0x50, 0xaf, 0xac, 0x95, 0xeb, - 0x75, 0xbd, 0xb1, 0xaa, 0x6f, 0xd5, 0xaa, 0x64, 0x3f, 0x39, 0x4a, 0x29, 0xb7, 0xdb, 0xfa, 0xfa, - 0x46, 0xbb, 0xb5, 0xa5, 0x3f, 0xad, 0xa2, 0xeb, 0x55, 0xec, 0x80, 0x8d, 0x4f, 0x50, 0x06, 0xae, - 0xf2, 0xe5, 0x46, 0xeb, 0xbc, 0x6e, 0x28, 0xbb, 0x67, 0xcb, 0x60, 0x8e, 0x19, 0x28, 0x10, 0x77, - 0x55, 0xb8, 0x6d, 0xee, 0xf7, 0xa8, 0x39, 0xae, 0x1c, 0x43, 0xdc, 0x61, 0xd9, 0x34, 0xed, 0xde, - 0x15, 0x25, 0xa7, 0x2a, 0x60, 0x9e, 0x1d, 0x13, 0x14, 0x49, 0xfb, 0xd6, 0xb5, 0x60, 0xf6, 0xbc, - 0xe3, 0x5e, 0xc4, 0x5e, 0xc3, 0xda, 0x07, 0x48, 0x0c, 0xb6, 0x20, 0xa2, 0x04, 0x63, 0x80, 0xbd, - 0x4a, 0xdc, 0x4d, 0x2c, 0xa0, 0xb6, 0x34, 0x32, 0x6a, 0xc4, 0x75, 0x60, 0xee, 0x72, 0x90, 0x3b, - 0x6a, 0xe9, 0x4c, 0x92, 0xf6, 0xcb, 0x62, 0x8e, 0x5f, 0xa3, 0x8b, 0xcc, 0x7e, 0xd5, 0xff, 0xed, - 0x12, 0x28, 0xae, 0x42, 0xbf, 0xdc, 0xeb, 0xb1, 0x72, 0x7b, 0x99, 0xf0, 0x39, 0x52, 0xae, 0x12, - 0xe5, 0x5e, 0x2f, 0xbe, 0x51, 0x31, 0x02, 0x0a, 0xce, 0x3b, 0x71, 0x69, 0x82, 0x5e, 0xda, 0x23, - 0x0a, 0xcc, 0x5e, 0x62, 0x7f, 0x1b, 0xb9, 0x66, 0xbf, 0x9e, 0x31, 0x93, 0x1e, 0x1b, 0xc5, 0xdf, - 0xcb, 0x25, 0x3b, 0x49, 0x05, 0xf9, 0xd4, 0x7b, 0xc0, 0xcc, 0xbe, 0x07, 0x2b, 0xa6, 0x17, 0x0c, - 0x6d, 0x7c, 0x4d, 0x9b, 0x17, 0xee, 0x83, 0x1d, 0x7f, 0xa9, 0xb6, 0x87, 0x26, 0x3e, 0x9b, 0x24, - 0x63, 0x18, 0xaf, 0x88, 0x3e, 0x1b, 0x01, 0x05, 0x34, 0xed, 0xbc, 0x6c, 0xf9, 0xbb, 0x95, 0x5d, - 0xd3, 0xa7, 0x9b, 0x2d, 0xe1, 0xb3, 0xf6, 0xa1, 0x31, 0xe0, 0x4c, 0x74, 0xd8, 0x89, 0x3f, 0x8e, - 0x7e, 0x13, 0x50, 0xb0, 0xf9, 0x63, 0xd9, 0x3b, 0x84, 0xff, 0x70, 0x8e, 0x79, 0x20, 0x3d, 0x35, - 0xe0, 0x13, 0xf0, 0xc8, 0x19, 0x07, 0xf0, 0x1f, 0x91, 0x41, 0xbe, 0xd9, 0x87, 0xb6, 0xf0, 0x39, - 0xcd, 0x10, 0x07, 0x69, 0x00, 0x87, 0xf7, 0x89, 0xbb, 0x10, 0x87, 0x95, 0x46, 0x25, 0xc7, 0xa0, - 0x70, 0x0b, 0xc8, 0x5b, 0xf6, 0xb6, 0x43, 0xad, 0xe0, 0x07, 0xc7, 0xd8, 0x45, 0x35, 0x7b, 0xdb, - 0x31, 0x70, 0x46, 0xed, 0x7d, 0x62, 0xde, 0xc3, 0x49, 0x65, 0xa7, 0x13, 0xf7, 0xca, 0x18, 0x63, - 0x91, 0x0a, 0x16, 0x23, 0x13, 0xb5, 0xde, 0x2c, 0x57, 0x95, 0xae, 0xf6, 0x37, 0x25, 0x50, 0x24, - 0x6a, 0xa3, 0xbd, 0x44, 0x06, 0x72, 0xb9, 0xdb, 0x8d, 0x01, 0x43, 0x3a, 0x00, 0x86, 0x13, 0x68, - 0x21, 0xf5, 0xf4, 0x0e, 0x9e, 0xf9, 0xc0, 0x6d, 0x82, 0x63, 0x03, 0x6d, 0x92, 0xe5, 0x6e, 0x37, - 0xfe, 0xdc, 0x43, 0x58, 0xa0, 0xc4, 0x17, 0xc8, 0xf6, 0x10, 0xb2, 0x58, 0x0f, 0x91, 0x7a, 0x20, - 0x89, 0xe5, 0x2f, 0xfb, 0x56, 0xf2, 0xf7, 0x12, 0x98, 0xa9, 0x5b, 0x9e, 0x8f, 0xb0, 0x29, 0x8b, - 0x60, 0x73, 0x2d, 0x98, 0x0d, 0x44, 0x83, 0xba, 0x4c, 0x34, 0x1e, 0x44, 0x09, 0xfc, 0x4c, 0xfe, - 0x6e, 0x1e, 0x9d, 0xc7, 0x27, 0xd7, 0x9e, 0x72, 0x11, 0x7f, 0x26, 0x2e, 0x2a, 0x56, 0x1a, 0x2c, - 0xf6, 0x57, 0x42, 0x81, 0xaf, 0x73, 0x02, 0xbf, 0x6d, 0x9c, 0x22, 0xb3, 0x17, 0xfa, 0x1f, 0x4a, - 0x00, 0xa0, 0xb2, 0xe9, 0xc1, 0xe3, 0x47, 0x72, 0xe1, 0x44, 0x12, 0xa4, 0xfb, 0x0a, 0x56, 0xba, - 0xeb, 0xbc, 0x74, 0x7f, 0x68, 0x74, 0x55, 0x93, 0x0e, 0x18, 0xab, 0x0a, 0x90, 0xad, 0x50, 0xb4, - 0xe8, 0xaf, 0xf6, 0xf6, 0x50, 0xa8, 0x1b, 0x9c, 0x50, 0xef, 0x18, 0xb3, 0xa4, 0xec, 0xe5, 0xfa, - 0xc7, 0x12, 0x98, 0x69, 0x41, 0x1f, 0x75, 0x9d, 0xda, 0x39, 0x91, 0x5e, 0x9f, 0x69, 0xdb, 0x92, - 0x60, 0xdb, 0xfe, 0x4e, 0x4e, 0x34, 0xb0, 0x5c, 0x24, 0x19, 0xca, 0x53, 0xcc, 0xea, 0xc5, 0xeb, - 0x85, 0x02, 0xcb, 0x8d, 0xa2, 0x96, 0xbd, 0x74, 0xdf, 0x2a, 0x85, 0x9e, 0x26, 0xfc, 0xb9, 0x40, - 0xd6, 0xac, 0xce, 0x1d, 0x34, 0xab, 0xc5, 0xcf, 0x05, 0xb2, 0x75, 0x8c, 0x77, 0x6c, 0x48, 0x6d, - 0x80, 0x4c, 0xc0, 0xe7, 0x60, 0x1c, 0x79, 0x3d, 0x5b, 0x06, 0x45, 0xba, 0xf9, 0x70, 0x57, 0xf2, - 0xde, 0xc3, 0xe8, 0xa9, 0xc9, 0xfb, 0xc7, 0x30, 0x05, 0x93, 0x96, 0xf5, 0x43, 0x36, 0x24, 0x86, - 0x8d, 0x9b, 0x41, 0x01, 0x47, 0xdd, 0xa6, 0xe3, 0x5c, 0xe4, 0x2e, 0x12, 0x90, 0xd0, 0xd1, 0x5b, - 0x83, 0x64, 0x4a, 0x8d, 0xc2, 0x04, 0x76, 0x02, 0xc6, 0x41, 0xe1, 0x9b, 0x2a, 0x00, 0x1b, 0xfb, - 0x17, 0x7a, 0x96, 0xb7, 0x6b, 0xd9, 0xd8, 0xc7, 0x6c, 0x9e, 0x3e, 0x92, 0xe0, 0xd1, 0x89, 0x26, - 0x61, 0xac, 0x51, 0xa0, 0x00, 0x79, 0xdf, 0xb5, 0xa8, 0x89, 0x8c, 0xfe, 0xaa, 0x77, 0x86, 0xde, - 0x9a, 0xf9, 0x81, 0xc0, 0x2f, 0x48, 0x0c, 0x11, 0x07, 0x4b, 0x4c, 0xe9, 0x91, 0xd7, 0x26, 0x1b, - 0x21, 0xbc, 0xc0, 0x47, 0x08, 0xe7, 0x4e, 0x83, 0x17, 0x07, 0x4e, 0x83, 0x23, 0x1c, 0x3d, 0xeb, - 0x99, 0x10, 0xbb, 0x2e, 0xc9, 0x06, 0xfe, 0x8f, 0xbe, 0xc0, 0xee, 0x45, 0xd8, 0xbb, 0x8f, 0x9c, - 0x39, 0x88, 0x12, 0xd8, 0x3e, 0x6f, 0x56, 0xb0, 0xcf, 0xfb, 0x58, 0x34, 0x77, 0x72, 0x04, 0x8d, - 0xe9, 0x14, 0x92, 0xe3, 0xd8, 0xcd, 0x0f, 0xb0, 0xab, 0x7d, 0x52, 0x38, 0x90, 0x27, 0x23, 0xe3, - 0xc4, 0x59, 0x10, 0xe5, 0x40, 0x0a, 0x39, 0x60, 0xf6, 0x90, 0x93, 0x7a, 0xe0, 0x51, 0xf4, 0xd3, - 0xe9, 0xf2, 0xde, 0x78, 0x36, 0x76, 0x70, 0xac, 0xbe, 0xb9, 0x7c, 0xb7, 0x5e, 0x69, 0x2b, 0xf0, - 0xe0, 0x51, 0x7b, 0x7c, 0xa8, 0x9e, 0x1c, 0xa0, 0x8f, 0xd6, 0x74, 0xb4, 0xff, 0x21, 0x81, 0x22, - 0x35, 0x37, 0xee, 0x3a, 0x24, 0x84, 0xda, 0x2b, 0xc7, 0x81, 0x24, 0x31, 0xba, 0xc9, 0xe7, 0xd2, - 0x02, 0x30, 0x01, 0x03, 0xe3, 0xde, 0xcc, 0x00, 0xd0, 0xfe, 0x49, 0x02, 0x79, 0x64, 0x06, 0x89, - 0xc5, 0x8e, 0xf8, 0xac, 0xb0, 0x4b, 0x31, 0x23, 0x00, 0x44, 0x3e, 0x46, 0xbf, 0x97, 0xc1, 0x6c, - 0x9f, 0x64, 0x0c, 0x23, 0x97, 0x5c, 0x2f, 0xd0, 0x19, 0x41, 0x23, 0xfa, 0x8c, 0x99, 0x72, 0x26, - 0xb9, 0x25, 0x27, 0xf3, 0x93, 0x0e, 0x0e, 0x7d, 0x12, 0x61, 0x26, 0xb6, 0xb5, 0x7f, 0x95, 0x00, - 0x30, 0xa0, 0xe7, 0xf4, 0x2e, 0xc1, 0x4d, 0xd7, 0xd2, 0x1e, 0x1c, 0x01, 0x40, 0x9b, 0x7d, 0x2e, - 0x6a, 0xf6, 0x9f, 0x97, 0x44, 0x9d, 0x87, 0x39, 0xcd, 0x0b, 0x88, 0xc7, 0x88, 0xff, 0xc9, 0x60, - 0x86, 0xca, 0x91, 0xda, 0x94, 0x62, 0xc2, 0x0f, 0x3e, 0xd2, 0x3e, 0x28, 0xe4, 0x7c, 0x2c, 0xc2, - 0x51, 0x3a, 0x00, 0x2a, 0x63, 0x00, 0x70, 0x1c, 0xcc, 0x05, 0x00, 0x6c, 0x1a, 0x35, 0x05, 0x6a, - 0xef, 0x96, 0xb1, 0x87, 0x06, 0x19, 0xdc, 0x0e, 0xdf, 0xd3, 0xfc, 0xb9, 0xf0, 0x64, 0x9f, 0x91, - 0x47, 0x58, 0x7e, 0x46, 0x00, 0xfd, 0xae, 0xd0, 0xec, 0x5e, 0x80, 0xa1, 0x07, 0x4a, 0x7f, 0x75, - 0x56, 0x07, 0x0b, 0x9c, 0x55, 0xa2, 0x9e, 0x06, 0x27, 0xb9, 0x04, 0x32, 0xde, 0x75, 0x95, 0x63, - 0xaa, 0x06, 0x4e, 0x71, 0x6f, 0xe8, 0x03, 0xec, 0x2a, 0x39, 0xed, 0x5d, 0x7f, 0x92, 0x0b, 0xd7, - 0x7b, 0xde, 0x9f, 0xa7, 0xab, 0x6f, 0x9f, 0xe6, 0x83, 0x65, 0x76, 0x1c, 0xdb, 0x87, 0xf7, 0x33, - 0x6e, 0x2e, 0x61, 0x42, 0xa2, 0xd5, 0x70, 0x1a, 0xcc, 0xf8, 0x2e, 0xeb, 0xfa, 0x12, 0x3c, 0xb2, - 0x8a, 0x55, 0xe0, 0x15, 0xab, 0x01, 0xce, 0x5a, 0x76, 0xa7, 0xb7, 0xdf, 0x85, 0x06, 0xec, 0x99, - 0x48, 0x86, 0x5e, 0xd9, 0xab, 0xc2, 0x3e, 0xb4, 0xbb, 0xd0, 0xf6, 0x09, 0x9f, 0xc1, 0xb9, 0x59, - 0x81, 0x9c, 0xbc, 0x32, 0xde, 0xc9, 0x2b, 0xe3, 0x23, 0x87, 0x2d, 0x01, 0x27, 0xac, 0x01, 0xde, - 0x06, 0x00, 0xa9, 0xdb, 0x39, 0x0b, 0x5e, 0xa6, 0x6a, 0x78, 0xcd, 0xc0, 0x4a, 0x60, 0x33, 0xcc, - 0x60, 0x30, 0x99, 0xb5, 0xaf, 0x86, 0xea, 0xf7, 0x14, 0x4e, 0xfd, 0x6e, 0x16, 0x64, 0x21, 0x9d, - 0xd6, 0xf5, 0xc7, 0xd0, 0xba, 0x05, 0x30, 0x1b, 0xed, 0x46, 0xcb, 0xea, 0x35, 0xe0, 0xea, 0xc0, - 0x43, 0xb9, 0xa1, 0xeb, 0xd5, 0xd6, 0xd6, 0xe6, 0xc6, 0xaa, 0x51, 0xae, 0xea, 0x0a, 0x40, 0xfa, - 0x49, 0xf4, 0x32, 0x74, 0x2c, 0xce, 0x6b, 0x7f, 0x24, 0x81, 0x02, 0x3e, 0xf4, 0xad, 0x3d, 0x7d, - 0x42, 0x9a, 0xe3, 0x71, 0x4e, 0x53, 0xe1, 0xb8, 0x2b, 0x7e, 0x05, 0x0a, 0x15, 0x26, 0xe6, 0xea, - 0x50, 0x57, 0xa0, 0x24, 0x10, 0xca, 0x7e, 0x26, 0x84, 0x9a, 0x64, 0x6b, 0xd7, 0xb9, 0xfc, 0x1f, - 0xb9, 0x49, 0xa2, 0xfa, 0x1f, 0x71, 0x93, 0x1c, 0xc2, 0xc2, 0xd4, 0x9b, 0xe4, 0x90, 0x76, 0x97, - 0xd0, 0x4c, 0xb5, 0x8f, 0x16, 0xc2, 0xf9, 0xdf, 0xa7, 0xa4, 0x43, 0xed, 0x9d, 0x95, 0xc1, 0x82, - 0x65, 0xfb, 0xd0, 0xb5, 0xcd, 0xde, 0x4a, 0xcf, 0xdc, 0x09, 0xec, 0xd3, 0xc1, 0x4d, 0x90, 0x1a, - 0x93, 0xc7, 0xe0, 0xbf, 0x50, 0xcf, 0x00, 0xe0, 0xc3, 0xbd, 0x7e, 0xcf, 0xf4, 0x23, 0xd5, 0x63, - 0x52, 0x58, 0xed, 0xcb, 0xf3, 0xda, 0xf7, 0x18, 0x70, 0x15, 0x01, 0xad, 0x7d, 0xa5, 0x0f, 0x37, - 0x6d, 0xeb, 0x19, 0xfb, 0x38, 0xb6, 0x32, 0xd1, 0xd1, 0x61, 0xaf, 0xb8, 0x5d, 0xa1, 0x22, 0xbf, - 0x2b, 0xa4, 0xde, 0x01, 0xae, 0xc1, 0x61, 0xb3, 0xf1, 0x1d, 0x23, 0xe7, 0xad, 0xee, 0x0e, 0xf4, - 0x6b, 0xdb, 0xeb, 0x96, 0xe7, 0x59, 0xf6, 0x0e, 0x9e, 0x8e, 0x97, 0x8c, 0xf8, 0x0c, 0xda, 0xff, - 0x12, 0x8e, 0xdb, 0x14, 0xf4, 0x19, 0x23, 0xe2, 0x36, 0x39, 0xfc, 0xb6, 0x5d, 0xd4, 0x4e, 0xc3, - 0x55, 0x9d, 0xbc, 0xc0, 0xaa, 0x0e, 0x8b, 0x69, 0x41, 0x70, 0x75, 0xe0, 0x35, 0x42, 0x81, 0xa1, - 0x92, 0xaa, 0x91, 0x7d, 0xdf, 0xf7, 0x6d, 0x19, 0x2c, 0x92, 0xa2, 0x97, 0x1d, 0xe7, 0xe2, 0x9e, - 0xe9, 0x5e, 0xd4, 0x7e, 0xfa, 0x70, 0xbb, 0xc0, 0x89, 0xbb, 0x57, 0x71, 0x5b, 0xba, 0x03, 0xca, - 0x9b, 0x1f, 0x54, 0x5e, 0xed, 0x77, 0x84, 0xa7, 0x24, 0x9c, 0x3c, 0x83, 0x4a, 0x4d, 0x67, 0x7b, - 0x4b, 0xec, 0x78, 0xa4, 0x08, 0x83, 0xd9, 0x03, 0xff, 0x5b, 0x21, 0xf0, 0xc1, 0x38, 0xc2, 0xee, - 0x0c, 0x4c, 0x12, 0x77, 0xed, 0x6b, 0xe3, 0x61, 0x17, 0xf0, 0x35, 0x06, 0x76, 0x0a, 0x90, 0x2f, - 0x86, 0xce, 0x4c, 0xe8, 0x2f, 0x5b, 0xa1, 0x7c, 0x76, 0x68, 0xc6, 0xb0, 0x3c, 0x15, 0x34, 0x4f, - 0xf2, 0x2c, 0x34, 0xfb, 0x99, 0x62, 0xfa, 0x15, 0xe1, 0x1d, 0xb7, 0xa1, 0x02, 0x22, 0xdc, 0x4d, - 0xa7, 0x55, 0x8a, 0x6d, 0xd7, 0x89, 0xb3, 0x99, 0x3d, 0x9a, 0x2f, 0x2c, 0x80, 0xd9, 0x20, 0x7e, - 0x16, 0xbe, 0x91, 0x30, 0xc4, 0xf0, 0x14, 0x28, 0x7a, 0xce, 0xbe, 0xdb, 0x81, 0x74, 0x0f, 0x94, - 0x3e, 0x8d, 0xb1, 0x5f, 0x37, 0xd2, 0x5c, 0x38, 0x60, 0x91, 0xe4, 0x53, 0x5b, 0x24, 0xf1, 0xf6, - 0x6e, 0x82, 0xfd, 0xa0, 0xbd, 0x48, 0xf8, 0xda, 0x10, 0x0e, 0xb3, 0x16, 0xf4, 0x1f, 0x88, 0x46, - 0xc0, 0xaf, 0x0b, 0xed, 0x06, 0x8d, 0xa8, 0x49, 0x3a, 0x95, 0x6b, 0x8e, 0x61, 0x07, 0x3f, 0x18, - 0x3c, 0x28, 0xc8, 0x41, 0x0d, 0x60, 0x6c, 0xf0, 0x6e, 0x1a, 0x75, 0x45, 0xd6, 0x9e, 0x9d, 0x07, - 0x0a, 0x61, 0xad, 0x19, 0xda, 0x82, 0xda, 0xcb, 0x72, 0x47, 0x6d, 0xf0, 0xc6, 0xcf, 0x60, 0x7f, - 0x5f, 0x12, 0x0d, 0x36, 0xce, 0x09, 0x3e, 0xaa, 0x5d, 0x8c, 0x26, 0x8d, 0xd1, 0xcc, 0x12, 0x94, - 0x4f, 0x7b, 0x4b, 0x4e, 0x24, 0x76, 0xb9, 0x18, 0x8b, 0xd9, 0xf7, 0x4a, 0xdf, 0xc9, 0x07, 0x61, - 0x10, 0x57, 0x5c, 0x67, 0x6f, 0xd3, 0xed, 0x69, 0xff, 0x47, 0xe8, 0x6a, 0x88, 0x98, 0xd9, 0x85, - 0x14, 0x3f, 0xbb, 0xc0, 0x2b, 0xd2, 0xbd, 0x68, 0x2b, 0xac, 0x37, 0xc6, 0xf0, 0xad, 0xde, 0x00, - 0x16, 0xcd, 0x6e, 0x77, 0xc3, 0xdc, 0x81, 0x15, 0x34, 0x6d, 0xb7, 0x7d, 0x1a, 0x22, 0x6d, 0x20, - 0x35, 0x71, 0x2a, 0xc3, 0xf7, 0x91, 0x33, 0x07, 0xac, 0x52, 0xf1, 0x65, 0x58, 0x0e, 0x44, 0x2a, - 0xbf, 0xa9, 0x0c, 0x7f, 0x68, 0xc8, 0xe8, 0xec, 0x9a, 0x51, 0x40, 0x47, 0xfa, 0x24, 0xe8, 0x8b, - 0x25, 0xc0, 0x77, 0xf6, 0x9a, 0xf7, 0x6b, 0x12, 0x98, 0x41, 0x78, 0x94, 0xbb, 0x5d, 0xed, 0x11, - 0x5c, 0xdc, 0xd3, 0x58, 0x6f, 0xb8, 0xe7, 0x0b, 0xbb, 0x26, 0x06, 0x35, 0x24, 0xf4, 0x63, 0x30, - 0x89, 0x84, 0x28, 0x71, 0x42, 0x14, 0x8b, 0x5f, 0x9a, 0x58, 0x44, 0xf6, 0xe2, 0xfb, 0xac, 0x04, - 0x16, 0x82, 0x79, 0xc6, 0x0a, 0xf4, 0x3b, 0xbb, 0xda, 0x6d, 0xa2, 0xeb, 0x5c, 0xb4, 0x25, 0x86, - 0x5b, 0xc2, 0x3d, 0xed, 0x7b, 0xb9, 0x94, 0x2a, 0xcf, 0x95, 0x1c, 0xb3, 0x48, 0x98, 0x4a, 0x17, - 0x93, 0x08, 0x66, 0x2f, 0xcc, 0xaf, 0x4a, 0x00, 0xb4, 0x9d, 0x70, 0xb2, 0x7c, 0x08, 0x49, 0xfe, - 0x8c, 0xf0, 0x6e, 0x31, 0xad, 0x78, 0x54, 0x6c, 0xfa, 0x9e, 0x43, 0xd0, 0x99, 0x6a, 0x54, 0x49, - 0x53, 0x69, 0xeb, 0xb3, 0xd5, 0xfd, 0x7e, 0xcf, 0xea, 0x98, 0xfe, 0xa0, 0x07, 0x60, 0xbc, 0x78, - 0xf1, 0x75, 0xde, 0xa9, 0x8c, 0xc6, 0xb0, 0x8c, 0x18, 0x59, 0x92, 0x38, 0x41, 0x52, 0x10, 0x27, - 0x48, 0xd0, 0xab, 0x67, 0x04, 0xf1, 0x29, 0xa8, 0xa7, 0x0c, 0x8e, 0x37, 0xfb, 0xd0, 0x5e, 0x76, - 0xa1, 0xd9, 0xed, 0xb8, 0xfb, 0x7b, 0x17, 0x3c, 0xd6, 0x7d, 0x35, 0x59, 0x47, 0x99, 0x95, 0x6b, - 0x89, 0x5b, 0xb9, 0xd6, 0x7e, 0x4c, 0x16, 0x8d, 0xe4, 0xc6, 0xec, 0xaf, 0x30, 0x3c, 0x8c, 0x31, - 0xd4, 0xa5, 0x72, 0xba, 0x1a, 0x58, 0xa4, 0xce, 0xa7, 0x59, 0xa4, 0x7e, 0xb3, 0x50, 0x5c, 0x38, - 0xa1, 0x7a, 0x4d, 0xc5, 0x77, 0x6e, 0xb1, 0x05, 0xfd, 0x18, 0x78, 0xaf, 0x07, 0x0b, 0x17, 0xa2, - 0x37, 0x21, 0xc4, 0x7c, 0xe2, 0x10, 0x8f, 0xd6, 0xb7, 0xa6, 0x5d, 0xa1, 0xe1, 0x59, 0x88, 0x41, - 0x37, 0x44, 0x50, 0x12, 0x71, 0x9b, 0x4b, 0xb5, 0xdc, 0x92, 0x58, 0x7e, 0xf6, 0x28, 0x7c, 0x52, - 0x02, 0x73, 0xf8, 0x92, 0xf2, 0xe5, 0x2b, 0xf8, 0x20, 0xa8, 0xa0, 0x51, 0xf2, 0x42, 0x56, 0xcc, - 0x2a, 0xc8, 0xf7, 0x2c, 0xfb, 0x62, 0xe0, 0xef, 0x88, 0xfe, 0x47, 0x57, 0x9c, 0x4a, 0x43, 0xae, - 0x38, 0x0d, 0xb7, 0x49, 0xc2, 0x72, 0x63, 0x46, 0xd3, 0x37, 0xe4, 0x44, 0xae, 0x38, 0x1d, 0x49, - 0x2e, 0x7b, 0x31, 0xfe, 0x55, 0x1e, 0x14, 0x5b, 0xd0, 0x74, 0x3b, 0xbb, 0xda, 0xfb, 0xa5, 0xa1, - 0x53, 0x89, 0x12, 0x3f, 0x95, 0x58, 0x01, 0x33, 0xdb, 0x56, 0xcf, 0x87, 0x2e, 0xf1, 0x01, 0x67, - 0xbb, 0x76, 0xd2, 0xc4, 0x97, 0x7b, 0x4e, 0xe7, 0xe2, 0x12, 0x35, 0xed, 0x97, 0x82, 0x78, 0xd3, - 0x4b, 0x2b, 0xf8, 0x23, 0x23, 0xf8, 0x18, 0x19, 0x84, 0x9e, 0xe3, 0xfa, 0x71, 0xf7, 0x17, 0xc5, - 0x50, 0x69, 0x39, 0xae, 0x6f, 0x90, 0x0f, 0x11, 0xcc, 0xdb, 0xfb, 0xbd, 0x5e, 0x1b, 0xde, 0xef, - 0x07, 0xd3, 0xba, 0xe0, 0x19, 0x19, 0x8b, 0xce, 0xf6, 0xb6, 0x07, 0xc9, 0xa2, 0x42, 0xc1, 0xa0, - 0x4f, 0xea, 0x49, 0x50, 0xe8, 0x59, 0x7b, 0x16, 0x99, 0x88, 0x14, 0x0c, 0xf2, 0xa0, 0xde, 0x04, - 0x94, 0x68, 0x0e, 0x44, 0x18, 0x3d, 0x5d, 0xc4, 0x4d, 0xf3, 0x40, 0x3a, 0xd2, 0x99, 0x8b, 0xf0, - 0x8a, 0x77, 0x7a, 0x06, 0xbf, 0xc7, 0xff, 0xb5, 0xd7, 0xa6, 0xdd, 0x30, 0x21, 0x12, 0x8f, 0x9f, - 0xe1, 0xba, 0xb0, 0xe3, 0xb8, 0xdd, 0x40, 0x36, 0xf1, 0x13, 0x0c, 0x9a, 0x2f, 0xdd, 0x36, 0xc7, - 0xd0, 0xc2, 0xb3, 0xd7, 0xb4, 0xf7, 0x14, 0x51, 0xb7, 0x89, 0x8a, 0x3e, 0x6f, 0xf9, 0xbb, 0xeb, - 0xd0, 0x37, 0xb5, 0xbf, 0x92, 0x87, 0x6a, 0xdc, 0xdc, 0xff, 0xaf, 0x71, 0x23, 0x34, 0x8e, 0xc4, - 0x0c, 0xf3, 0xf7, 0x5d, 0x1b, 0xc9, 0x91, 0xfa, 0xd1, 0x32, 0x29, 0xea, 0x1d, 0xe0, 0x9a, 0xe8, - 0x29, 0x58, 0x4a, 0xad, 0x32, 0xae, 0xb5, 0x25, 0x23, 0x3e, 0x83, 0xba, 0x01, 0x1e, 0x4e, 0x5e, - 0xae, 0xb5, 0xd7, 0xeb, 0x6b, 0xd6, 0xce, 0x6e, 0xcf, 0xda, 0xd9, 0xf5, 0xbd, 0x9a, 0xed, 0xf9, - 0xd0, 0xec, 0x36, 0xb7, 0x0d, 0x72, 0xf3, 0x18, 0xc0, 0x74, 0x44, 0xb2, 0xf2, 0x3e, 0xe2, 0x62, - 0xa3, 0x1b, 0xab, 0x29, 0x31, 0x2d, 0xe5, 0x09, 0xa8, 0xa5, 0x78, 0xfb, 0xbd, 0x10, 0xd3, 0x6b, - 0x07, 0x30, 0x8d, 0x54, 0x7d, 0xbf, 0x87, 0x9b, 0x0b, 0xce, 0x9c, 0x76, 0x9c, 0x4b, 0xe0, 0x24, - 0xfb, 0x66, 0xf3, 0x7f, 0x8a, 0xa0, 0xb0, 0xea, 0x9a, 0xfd, 0x5d, 0xed, 0xd9, 0x4c, 0xff, 0x3c, - 0xa9, 0x36, 0x11, 0x6a, 0xa7, 0x34, 0x4a, 0x3b, 0xe5, 0x11, 0xda, 0x99, 0x67, 0xb4, 0x33, 0x7e, - 0xd1, 0xf9, 0x2c, 0x98, 0xef, 0x38, 0xbd, 0x1e, 0xec, 0x20, 0x79, 0xd4, 0xba, 0x78, 0xb5, 0x67, - 0xd6, 0xe0, 0xd2, 0x70, 0x4c, 0x7e, 0xe8, 0xb7, 0xc8, 0x1a, 0x3b, 0x51, 0xfa, 0x28, 0x41, 0x7b, - 0x99, 0x04, 0xf2, 0x7a, 0x77, 0x07, 0x72, 0xeb, 0xf0, 0x39, 0x66, 0x1d, 0xfe, 0x14, 0x28, 0xfa, - 0xa6, 0xbb, 0x03, 0xfd, 0x60, 0x9d, 0x80, 0x3c, 0x85, 0x57, 0x05, 0xc8, 0xcc, 0x55, 0x01, 0x3f, - 0x04, 0xf2, 0x48, 0x66, 0xd4, 0x2d, 0xfe, 0xe1, 0xc3, 0xe0, 0xc7, 0xb2, 0x5f, 0x42, 0x25, 0x2e, - 0xa1, 0x5a, 0x1b, 0xf8, 0x83, 0x41, 0xac, 0x0b, 0x07, 0x43, 0xd9, 0x5e, 0x0b, 0x66, 0xad, 0x8e, - 0x63, 0xd7, 0xf6, 0xcc, 0x1d, 0x48, 0xab, 0x19, 0x25, 0x04, 0x6f, 0xf5, 0x3d, 0xe7, 0x3e, 0x8b, - 0x2e, 0x6a, 0x45, 0x09, 0xa8, 0x0a, 0xbb, 0x56, 0xb7, 0x0b, 0x6d, 0xda, 0xb2, 0xe9, 0xd3, 0xd9, - 0x33, 0x20, 0x8f, 0x78, 0x40, 0xfa, 0x83, 0x8c, 0x05, 0xe5, 0x98, 0x3a, 0x8f, 0x9a, 0x15, 0x69, - 0xbc, 0x4a, 0x8e, 0x5f, 0x73, 0x15, 0xf1, 0x1a, 0x22, 0x95, 0x1b, 0xde, 0xb8, 0x1e, 0x0d, 0x0a, - 0xb6, 0xd3, 0x85, 0x23, 0x07, 0x21, 0x92, 0x4b, 0x7d, 0x3c, 0x28, 0xc0, 0x2e, 0xea, 0x15, 0x64, - 0x9c, 0xfd, 0x4c, 0xb2, 0x2c, 0x0d, 0x92, 0x39, 0x9d, 0x6b, 0xd2, 0x30, 0x6e, 0xb3, 0x6f, 0x80, - 0x3f, 0x31, 0x03, 0x8e, 0x93, 0x3e, 0xa0, 0xb5, 0x7f, 0x01, 0x91, 0xba, 0x00, 0xb5, 0xd7, 0x0f, - 0x1f, 0xb8, 0x8e, 0xf3, 0xca, 0x7e, 0x12, 0x14, 0xbc, 0xfd, 0x0b, 0xa1, 0x11, 0x4a, 0x1e, 0xd8, - 0xa6, 0x2b, 0x4d, 0x64, 0x38, 0x93, 0xc7, 0x1d, 0xce, 0xb8, 0xa1, 0x49, 0x0e, 0x1a, 0x7f, 0x34, - 0x90, 0x91, 0x03, 0x1d, 0xc1, 0x40, 0x36, 0x6c, 0x18, 0x3a, 0x0d, 0x66, 0xcc, 0x6d, 0x1f, 0xba, - 0x91, 0x99, 0x48, 0x1f, 0xd1, 0x50, 0x79, 0x01, 0x6e, 0x3b, 0x2e, 0x12, 0x0b, 0x09, 0x2b, 0x1b, - 0x3e, 0x33, 0x2d, 0x17, 0x70, 0x3b, 0x68, 0x37, 0x83, 0x13, 0xb6, 0x53, 0x85, 0x7d, 0x2a, 0x67, - 0x82, 0xe2, 0x02, 0xb9, 0xdd, 0xfd, 0xc0, 0x8b, 0x03, 0x5d, 0xc9, 0xe2, 0xc1, 0xae, 0x44, 0xfb, - 0x7c, 0xda, 0x39, 0xf3, 0x00, 0xd0, 0x13, 0xb3, 0xd0, 0xd4, 0x27, 0x81, 0xf9, 0x2e, 0xf5, 0x10, - 0xeb, 0x58, 0x61, 0x2b, 0x89, 0xfd, 0x8e, 0xcb, 0x1c, 0x29, 0x52, 0x9e, 0x55, 0xa4, 0x55, 0x50, - 0xc2, 0xc7, 0xb1, 0x91, 0x26, 0x15, 0x06, 0x3c, 0xf2, 0xf1, 0xb4, 0x2e, 0xac, 0x14, 0x23, 0xb6, - 0xa5, 0x0a, 0xfd, 0xc4, 0x08, 0x3f, 0x4e, 0x37, 0xfb, 0x4e, 0x96, 0x50, 0xf6, 0xcd, 0xf1, 0x57, - 0x8a, 0xe0, 0x9a, 0x8a, 0xeb, 0x78, 0x1e, 0x3e, 0x82, 0x33, 0xd8, 0x30, 0xdf, 0x28, 0x71, 0x97, - 0x06, 0x3d, 0xa0, 0x9b, 0xdf, 0xb0, 0x06, 0x35, 0xbd, 0xa6, 0xf1, 0xe7, 0xc2, 0x41, 0x6f, 0xc2, - 0xfd, 0x87, 0x18, 0xa1, 0xff, 0xc7, 0x68, 0x24, 0xef, 0xc9, 0x89, 0xc4, 0xe1, 0x49, 0x29, 0xab, - 0xec, 0x9b, 0xcb, 0x57, 0x24, 0xf0, 0xe0, 0x41, 0x6e, 0x36, 0x6d, 0x2f, 0x6c, 0x30, 0x0f, 0x1d, - 0xd1, 0x5e, 0xf8, 0xb8, 0x2d, 0x89, 0x77, 0x04, 0xc7, 0xd4, 0x9d, 0x29, 0x2d, 0x66, 0xb1, 0x24, - 0x3a, 0xd0, 0x93, 0x74, 0x47, 0x70, 0x6a, 0xf2, 0xd9, 0x0b, 0xf7, 0xf7, 0xf3, 0xe0, 0xf8, 0xaa, - 0xeb, 0xec, 0xf7, 0xbd, 0xa8, 0x07, 0xfa, 0xd3, 0xe1, 0x1b, 0xb2, 0x45, 0x11, 0xd3, 0xe0, 0x3a, - 0x30, 0xe7, 0x52, 0x6b, 0x2e, 0xda, 0x9e, 0x65, 0x93, 0xd8, 0xde, 0x4b, 0x3e, 0x4c, 0xef, 0x15, - 0xf5, 0x33, 0x79, 0xae, 0x9f, 0x19, 0xec, 0x39, 0x0a, 0x43, 0x7a, 0x8e, 0x3f, 0x91, 0x52, 0x0e, - 0xaa, 0x03, 0x22, 0x8a, 0xe9, 0x2f, 0x2a, 0xa0, 0xb8, 0x83, 0x33, 0xd2, 0xee, 0xe2, 0x51, 0x62, - 0x35, 0xc3, 0xc4, 0x0d, 0xfa, 0x69, 0x24, 0x57, 0x99, 0xd5, 0xe1, 0x54, 0x03, 0x5c, 0x32, 0xb7, - 0xd9, 0x2b, 0xd5, 0x6b, 0xf3, 0x60, 0x3e, 0x2c, 0xbd, 0xd6, 0xf5, 0xb8, 0xe8, 0xb0, 0x8c, 0x46, - 0x2d, 0x88, 0x68, 0xd4, 0x81, 0x75, 0xe6, 0x70, 0xd4, 0x91, 0x99, 0x51, 0x67, 0xe8, 0xe8, 0x32, - 0x1f, 0x33, 0xba, 0x68, 0xcf, 0x92, 0x45, 0xaf, 0xdd, 0xe3, 0xbb, 0x56, 0x5c, 0x9b, 0x07, 0xf2, - 0x60, 0x21, 0x78, 0xf9, 0xdf, 0xe8, 0x5a, 0x65, 0xaf, 0x24, 0x1f, 0x91, 0xc0, 0x89, 0x83, 0x9d, - 0xf9, 0xc3, 0x78, 0x2f, 0x35, 0x54, 0x27, 0x2f, 0xf4, 0x52, 0xc3, 0x4f, 0xfc, 0x26, 0x5d, 0x62, - 0x10, 0x14, 0xce, 0xde, 0x1b, 0xdd, 0x89, 0x8b, 0x85, 0x39, 0x11, 0x24, 0x9a, 0xbd, 0x00, 0x7f, - 0x56, 0x06, 0xb3, 0x2d, 0xe8, 0xd7, 0xcd, 0x2b, 0xce, 0xbe, 0xaf, 0x99, 0xa2, 0xdb, 0x73, 0x4f, - 0x04, 0xc5, 0x1e, 0xfe, 0x04, 0x77, 0x30, 0x6c, 0xd0, 0x52, 0x76, 0x7f, 0x0b, 0xfb, 0x06, 0x11, - 0xd2, 0x06, 0xcd, 0xcf, 0x47, 0x9f, 0x11, 0xd9, 0x1d, 0x0d, 0xb9, 0x9b, 0xc8, 0xd6, 0x4e, 0xaa, - 0xbd, 0xd3, 0xb8, 0xa2, 0xb3, 0x87, 0xe5, 0xc7, 0x64, 0xb0, 0xd0, 0x82, 0x7e, 0xcd, 0x5b, 0x31, - 0x2f, 0x39, 0xae, 0xe5, 0x43, 0x6d, 0x55, 0x14, 0x9a, 0x33, 0x00, 0x58, 0xe1, 0x67, 0x34, 0x4e, - 0x16, 0x93, 0xa2, 0xbd, 0x25, 0xad, 0xa3, 0x10, 0xc7, 0xc7, 0x44, 0x40, 0x48, 0xe5, 0x63, 0x91, - 0x54, 0xfc, 0x14, 0x2e, 0x0e, 0x97, 0x28, 0x10, 0x65, 0xb7, 0xb3, 0x6b, 0x5d, 0x82, 0xdd, 0x94, - 0x40, 0x04, 0x9f, 0x45, 0x40, 0x84, 0x84, 0x52, 0xbb, 0xaf, 0x70, 0x7c, 0x4c, 0xc2, 0x7d, 0x25, - 0x89, 0xe0, 0x54, 0xc2, 0x5a, 0xa1, 0xae, 0x87, 0xae, 0x67, 0xde, 0x25, 0x2a, 0xd6, 0xc8, 0x64, - 0x93, 0x58, 0x93, 0x6d, 0xac, 0x8e, 0x85, 0x94, 0x3d, 0x4a, 0xa7, 0xf3, 0x59, 0x74, 0x2c, 0x43, - 0x8b, 0xce, 0x5e, 0xe8, 0xef, 0x93, 0xc1, 0xd5, 0x61, 0xbc, 0x97, 0x16, 0xf4, 0xab, 0xa6, 0xb7, - 0x7b, 0xc1, 0x31, 0xdd, 0xae, 0x56, 0x99, 0xc0, 0x81, 0x43, 0xed, 0x8b, 0x2c, 0x08, 0x0d, 0x1e, - 0x84, 0xa1, 0xae, 0xa4, 0x43, 0x79, 0x99, 0x44, 0x27, 0x93, 0xe8, 0xed, 0xfa, 0x8e, 0x10, 0xac, - 0xa7, 0x72, 0x60, 0xdd, 0x39, 0x2e, 0x8b, 0xd9, 0x03, 0xf7, 0xf3, 0x64, 0x44, 0x60, 0xbc, 0x9e, - 0xef, 0x15, 0x05, 0x2c, 0xc6, 0xeb, 0x55, 0x8e, 0xf5, 0x7a, 0x1d, 0x6b, 0x8c, 0x18, 0xe9, 0xb1, - 0x9c, 0xed, 0x18, 0x71, 0x84, 0xde, 0xc8, 0xef, 0x92, 0x81, 0x82, 0x03, 0x7e, 0x31, 0x1e, 0xe1, - 0x6c, 0xfc, 0xed, 0x64, 0x74, 0x0e, 0x78, 0x9f, 0xcf, 0xa4, 0xf5, 0x3e, 0xd7, 0xde, 0x99, 0xd6, - 0xc7, 0x7c, 0x90, 0xdb, 0x89, 0x20, 0x96, 0xca, 0x85, 0x7c, 0x04, 0x07, 0xd9, 0x83, 0xf6, 0x93, - 0x32, 0x00, 0xa8, 0x41, 0xd3, 0xb3, 0x11, 0x4f, 0x13, 0x85, 0xeb, 0x16, 0xd6, 0xef, 0x1e, 0x01, - 0x75, 0xf5, 0x00, 0x50, 0x84, 0x62, 0x74, 0xea, 0xe2, 0xf5, 0x69, 0x7d, 0x2b, 0x23, 0xae, 0x26, - 0x02, 0x4b, 0x2a, 0x6f, 0xcb, 0xd8, 0xb2, 0xb3, 0x07, 0xe4, 0x57, 0x25, 0x50, 0x68, 0x3b, 0x2d, - 0xe8, 0x1f, 0xde, 0x14, 0x48, 0x1d, 0x35, 0x00, 0x97, 0x3b, 0x89, 0xa8, 0x01, 0xc3, 0x08, 0x65, - 0x2f, 0xba, 0xf7, 0x4a, 0x60, 0xbe, 0xed, 0x54, 0xc2, 0xc5, 0x29, 0x71, 0x5f, 0xd5, 0x7f, 0xc9, - 0xa5, 0x5c, 0xc3, 0x60, 0x8b, 0x89, 0x11, 0x58, 0xaa, 0xd5, 0x83, 0x04, 0x7a, 0xd9, 0xcb, 0xed, - 0x36, 0x70, 0x7c, 0xd3, 0xee, 0x3a, 0x06, 0xec, 0x3a, 0x74, 0xa5, 0x5b, 0x55, 0x41, 0x7e, 0xdf, - 0xee, 0x3a, 0x98, 0xe5, 0x82, 0x81, 0xff, 0xa3, 0x34, 0x17, 0x76, 0x1d, 0xea, 0x1b, 0x80, 0xff, - 0x6b, 0x7f, 0x2e, 0x83, 0x3c, 0xfa, 0x56, 0x5c, 0xd4, 0xef, 0x92, 0x53, 0xc6, 0x41, 0x40, 0xe4, - 0x27, 0x62, 0x09, 0xdd, 0xc5, 0xac, 0xfd, 0x13, 0x0f, 0xd6, 0x87, 0xc7, 0x95, 0xc7, 0x88, 0x22, - 0x5a, 0xf3, 0x57, 0x4f, 0x83, 0x99, 0x0b, 0x3d, 0xa7, 0x73, 0x31, 0x3a, 0xae, 0x4f, 0x1f, 0xd5, - 0x9b, 0x40, 0xc1, 0x35, 0xed, 0x1d, 0x48, 0xf7, 0x14, 0x4e, 0x0e, 0xf4, 0x85, 0xd8, 0xeb, 0xc5, - 0x20, 0x59, 0xb4, 0x77, 0xa6, 0x89, 0xc0, 0x30, 0xa4, 0xf2, 0xe9, 0xf4, 0xa1, 0x3a, 0xc6, 0xc9, - 0x33, 0x05, 0xcc, 0x57, 0xca, 0x0d, 0x72, 0x0f, 0x62, 0xf3, 0x9c, 0xae, 0xc8, 0x18, 0x66, 0x24, - 0x93, 0x0c, 0x61, 0x46, 0xe4, 0xff, 0xc3, 0xc2, 0x3c, 0xa4, 0xf2, 0x47, 0x01, 0xf3, 0x67, 0x25, - 0xb0, 0x50, 0xb7, 0x3c, 0x3f, 0xce, 0xdb, 0x3f, 0x21, 0xde, 0xef, 0x8b, 0xd2, 0x9a, 0xca, 0x5c, - 0x39, 0xc2, 0x81, 0x7e, 0x53, 0x99, 0xc3, 0x49, 0x45, 0x4c, 0xe7, 0x58, 0x0a, 0xe6, 0x80, 0x5c, - 0x82, 0x2f, 0x2c, 0xc9, 0xd4, 0x86, 0x52, 0x54, 0xc8, 0xf4, 0x0d, 0xa5, 0xd8, 0xb2, 0xb3, 0x97, - 0xef, 0x9f, 0x4b, 0xe0, 0x04, 0x2a, 0x3e, 0x69, 0x59, 0x2a, 0x5e, 0xcc, 0x23, 0x97, 0xa5, 0x52, - 0xaf, 0x8c, 0x1f, 0xe0, 0x65, 0x12, 0x2b, 0xe3, 0xa3, 0x88, 0x4e, 0x59, 0xcc, 0x31, 0xcb, 0xb0, - 0xa3, 0xc4, 0x9c, 0xb0, 0x0c, 0x3b, 0xbe, 0x98, 0x93, 0x97, 0x62, 0xc7, 0x14, 0xf3, 0x91, 0x2d, - 0xb0, 0xfe, 0x92, 0x1c, 0x8a, 0x39, 0x76, 0x6d, 0x23, 0x41, 0xcc, 0xa9, 0x4f, 0xf4, 0x6a, 0xef, - 0x1e, 0x53, 0xf0, 0x13, 0x5e, 0xdf, 0x18, 0x07, 0xa6, 0x23, 0x5c, 0xe3, 0xf8, 0x05, 0x19, 0x2c, - 0x52, 0x2e, 0x86, 0x4f, 0x99, 0x13, 0x30, 0x4a, 0x3d, 0x65, 0x4e, 0x7d, 0x06, 0x88, 0xe7, 0x6c, - 0xfa, 0x67, 0x80, 0x12, 0xcb, 0xcf, 0x1e, 0x9c, 0xbf, 0xcc, 0x83, 0x53, 0x88, 0x85, 0x75, 0xa7, - 0x6b, 0x6d, 0x5f, 0x21, 0x5c, 0x9c, 0x33, 0x7b, 0xfb, 0xd0, 0xd3, 0x3e, 0x20, 0x89, 0xa2, 0xf4, - 0x9f, 0x01, 0x70, 0xfa, 0xd0, 0x25, 0x71, 0xdc, 0x28, 0x50, 0x77, 0xc4, 0x55, 0xf6, 0x60, 0x49, - 0xe1, 0xf5, 0x39, 0xcd, 0x80, 0x88, 0xc1, 0xd0, 0x43, 0x56, 0xe1, 0x6c, 0xf8, 0x66, 0xd0, 0xc1, - 0x23, 0x77, 0xd0, 0xc1, 0xe3, 0x46, 0x20, 0x9b, 0xdd, 0x6e, 0x08, 0xd5, 0xe0, 0x66, 0x36, 0x2e, - 0xd3, 0x40, 0x59, 0x50, 0x4e, 0x0f, 0x46, 0x47, 0xf3, 0x62, 0x72, 0x7a, 0xd0, 0x57, 0x97, 0x40, - 0x91, 0x5c, 0x27, 0x1e, 0xae, 0xe8, 0x0f, 0xcf, 0x4c, 0x73, 0xf1, 0xa6, 0x5d, 0x93, 0x57, 0xc3, - 0xdb, 0x52, 0x49, 0x66, 0x58, 0x3f, 0x1d, 0xd9, 0xc9, 0x06, 0xa7, 0x60, 0x4f, 0x1e, 0x9b, 0xf2, - 0x74, 0x76, 0xc3, 0xca, 0xfd, 0x7e, 0xef, 0x4a, 0x9b, 0x06, 0x1e, 0x48, 0xb5, 0x1b, 0xc6, 0xc4, - 0x2f, 0x90, 0x0e, 0xc4, 0x2f, 0x48, 0xbd, 0x1b, 0xc6, 0xf1, 0x31, 0x89, 0xdd, 0xb0, 0x24, 0x82, - 0xd9, 0x8b, 0xf6, 0x6f, 0x4a, 0xc4, 0x6a, 0xa6, 0xb7, 0x11, 0xfc, 0xc3, 0x70, 0xcf, 0x6a, 0xc0, - 0x3b, 0xbb, 0x0c, 0xbb, 0xa8, 0x20, 0xf1, 0x16, 0x16, 0xf5, 0xf1, 0xa0, 0xb8, 0xed, 0xb8, 0x7b, - 0x66, 0xb0, 0x71, 0x3f, 0x78, 0x52, 0x84, 0xde, 0x00, 0xb0, 0x82, 0xf3, 0x18, 0x34, 0x2f, 0x9a, - 0x8f, 0x3c, 0xd3, 0xea, 0xd3, 0xa0, 0x8f, 0xe8, 0xaf, 0x7a, 0x3d, 0x58, 0xa0, 0xb1, 0x1f, 0x1b, - 0xd0, 0xf3, 0x61, 0x97, 0x46, 0xb4, 0xe0, 0x13, 0xd5, 0xb3, 0x60, 0x9e, 0x26, 0xac, 0x58, 0x3d, - 0xe8, 0xd1, 0xa0, 0x16, 0x5c, 0x9a, 0x7a, 0x0a, 0x14, 0x2d, 0xef, 0x6e, 0xcf, 0xb1, 0x69, 0x40, - 0x3e, 0xfa, 0xa4, 0xde, 0x08, 0x8e, 0xd3, 0x7c, 0xa1, 0xb1, 0x4a, 0x0e, 0xec, 0x0c, 0x26, 0x23, - 0xd5, 0xb2, 0x9d, 0x0d, 0xd7, 0xd9, 0x71, 0xa1, 0xe7, 0xe1, 0x53, 0x53, 0x25, 0x83, 0x49, 0x51, - 0xef, 0x05, 0x27, 0x7a, 0x96, 0x7d, 0xd1, 0xc3, 0x31, 0x82, 0x57, 0xa8, 0xdb, 0xd8, 0xfc, 0x90, - 0xd8, 0xdd, 0x4c, 0x63, 0xa3, 0x72, 0x60, 0x3f, 0x31, 0x0e, 0x52, 0x51, 0x6f, 0x02, 0x0a, 0xe5, - 0x66, 0xd9, 0xec, 0x5c, 0xc4, 0xef, 0xa9, 0x3b, 0xea, 0x81, 0x74, 0x46, 0x18, 0x24, 0x8c, 0xfe, - 0x22, 0x27, 0x0c, 0x12, 0x49, 0xff, 0x25, 0x39, 0x30, 0xcf, 0x15, 0x60, 0x02, 0x35, 0xe8, 0x16, - 0xbd, 0xf3, 0xbb, 0x96, 0x0f, 0x11, 0x73, 0xf4, 0xac, 0xcb, 0x63, 0x47, 0x30, 0x6f, 0x1c, 0xf8, - 0xd0, 0x18, 0x42, 0x0c, 0xf1, 0x45, 0x3a, 0x3c, 0xec, 0x59, 0xe6, 0x51, 0x5b, 0x95, 0x4b, 0xd3, - 0x9e, 0x09, 0xd4, 0x83, 0xd4, 0x18, 0x2f, 0x90, 0x5c, 0x3a, 0x2f, 0x10, 0x24, 0x37, 0xb3, 0xd7, - 0x73, 0x2e, 0xc3, 0x6e, 0x48, 0x96, 0xea, 0xea, 0x81, 0x74, 0xed, 0x0b, 0xe3, 0xcc, 0x0b, 0x53, - 0x5f, 0xac, 0x81, 0x1a, 0xd9, 0x7e, 0xa7, 0x03, 0x61, 0x97, 0x1e, 0x5c, 0x0b, 0x1e, 0x53, 0x5e, - 0xb9, 0x91, 0x7a, 0x16, 0x79, 0x44, 0x77, 0x6e, 0xbc, 0x3f, 0xba, 0xf9, 0x64, 0x5f, 0xa4, 0xab, - 0x49, 0x3a, 0x1f, 0x3f, 0x56, 0xa7, 0xa2, 0xbd, 0x37, 0xed, 0x69, 0xd1, 0x44, 0x4c, 0x4f, 0xa1, - 0xc1, 0xdd, 0xdb, 0xef, 0x85, 0xc7, 0x9d, 0xc8, 0x53, 0x4a, 0xf4, 0x52, 0x1d, 0x20, 0x3d, 0x22, - 0xe4, 0x3e, 0x7e, 0x35, 0x28, 0x92, 0x9b, 0x0b, 0xb5, 0x97, 0x2c, 0x0e, 0x85, 0x6e, 0x91, 0x87, - 0x6e, 0x13, 0xcc, 0xdb, 0x0e, 0x2a, 0x6e, 0xc3, 0x74, 0xcd, 0x3d, 0x2f, 0x69, 0x79, 0x9f, 0xd0, - 0x0d, 0x6d, 0xb9, 0x06, 0xf3, 0xd9, 0xda, 0x31, 0x83, 0x23, 0xa3, 0xfe, 0x5f, 0xe0, 0xf8, 0x05, - 0x1a, 0x9a, 0xc3, 0xa3, 0x94, 0xa5, 0x78, 0xe7, 0xd7, 0x01, 0xca, 0xcb, 0xfc, 0x97, 0x6b, 0xc7, - 0x8c, 0x41, 0x62, 0xea, 0x7f, 0x02, 0x8b, 0xe8, 0xb1, 0xeb, 0x5c, 0x0e, 0x18, 0x97, 0xe3, 0x67, - 0x00, 0x03, 0xe4, 0xd7, 0xb9, 0x0f, 0xd7, 0x8e, 0x19, 0x03, 0xa4, 0xd4, 0x26, 0x00, 0xbb, 0xfe, - 0x5e, 0x8f, 0x12, 0xce, 0xc7, 0x77, 0x26, 0x03, 0x84, 0xd7, 0xc2, 0x8f, 0xd6, 0x8e, 0x19, 0x0c, - 0x09, 0xb5, 0x0e, 0x66, 0xfd, 0xfb, 0x7d, 0x4a, 0xaf, 0x10, 0xef, 0x75, 0x32, 0x40, 0xaf, 0x1d, - 0x7c, 0xb3, 0x76, 0xcc, 0x88, 0x08, 0xa8, 0x35, 0x50, 0xea, 0x5f, 0xa0, 0xc4, 0x8a, 0xf1, 0x23, - 0xd5, 0x00, 0xb1, 0x8d, 0x0b, 0x21, 0xad, 0xf0, 0x73, 0xc4, 0x58, 0xc7, 0xbb, 0x44, 0x69, 0xcd, - 0x08, 0x33, 0x56, 0x09, 0xbe, 0x41, 0x8c, 0x85, 0x04, 0xd4, 0x1a, 0x98, 0xf5, 0x6c, 0xb3, 0xef, - 0xed, 0x3a, 0xbe, 0x77, 0xba, 0x34, 0xe0, 0xa0, 0x1c, 0x4f, 0xad, 0x45, 0xbf, 0x31, 0xa2, 0xaf, - 0xd5, 0xc7, 0x83, 0xab, 0xf7, 0xfb, 0x5d, 0xd3, 0x87, 0xfa, 0xfd, 0x96, 0x17, 0xdd, 0x5e, 0x19, - 0x9c, 0xcb, 0x1d, 0xfe, 0x52, 0x5d, 0xa2, 0x47, 0x15, 0x01, 0x6e, 0x97, 0xda, 0xe0, 0x2e, 0x39, - 0x29, 0x96, 0x39, 0xa1, 0xf8, 0x24, 0x90, 0x47, 0xaf, 0xb0, 0x59, 0xb0, 0x38, 0x7c, 0x05, 0x7e, - 0x50, 0x77, 0x70, 0x03, 0x46, 0x1f, 0x0d, 0x58, 0x16, 0xf3, 0x07, 0x2c, 0x8b, 0xeb, 0xc0, 0x9c, - 0xe5, 0xad, 0x5b, 0x3b, 0x64, 0x5a, 0x43, 0x47, 0x7e, 0x36, 0x89, 0x2c, 0x03, 0x35, 0xe0, 0x65, - 0x32, 0xe4, 0x1f, 0x0f, 0x96, 0x81, 0x82, 0x14, 0xed, 0x06, 0x30, 0xcf, 0x36, 0x32, 0x72, 0xfd, - 0xb1, 0x15, 0x4d, 0x8a, 0xe8, 0x93, 0x76, 0x3d, 0x58, 0xe4, 0x75, 0x9a, 0xb1, 0xfd, 0xe4, 0x60, - 0x10, 0xd3, 0x1e, 0x0e, 0x8e, 0x0f, 0x34, 0xac, 0x20, 0xd8, 0x4f, 0x2e, 0x0a, 0xf6, 0x73, 0x1d, - 0x00, 0x91, 0x16, 0x0f, 0x25, 0xf3, 0x50, 0x30, 0x1b, 0xea, 0xe5, 0xd0, 0x0c, 0x5f, 0xcf, 0x81, - 0x52, 0xa0, 0x6c, 0xc3, 0x32, 0x20, 0x9b, 0xc2, 0x66, 0x76, 0xf6, 0x02, 0x9b, 0x82, 0x4d, 0x43, - 0x06, 0x5e, 0xe4, 0x4f, 0xdf, 0xb6, 0xfc, 0x5e, 0x70, 0x26, 0x75, 0x30, 0x59, 0xdd, 0x00, 0xc0, - 0xc2, 0x18, 0xb5, 0xa3, 0x43, 0xaa, 0x8f, 0x49, 0xd1, 0x1e, 0x88, 0x3e, 0x30, 0x34, 0xce, 0x3e, - 0x8c, 0x9e, 0x20, 0x9d, 0x05, 0x05, 0x72, 0xc1, 0xc2, 0x31, 0x75, 0x11, 0x00, 0xfd, 0x69, 0x1b, - 0xba, 0x51, 0xd3, 0x1b, 0x15, 0x5d, 0xc9, 0x69, 0x2f, 0x97, 0xc0, 0x6c, 0xd8, 0x08, 0x86, 0x56, - 0x52, 0xa7, 0xaa, 0x35, 0xf2, 0x86, 0xd9, 0x83, 0x8d, 0x8a, 0x55, 0xb2, 0x27, 0x82, 0x07, 0xed, - 0x7b, 0x70, 0xc5, 0x72, 0x3d, 0xdf, 0x70, 0x2e, 0xaf, 0x38, 0x6e, 0x64, 0x12, 0x91, 0xd0, 0xc4, - 0x71, 0xaf, 0x91, 0xa9, 0xdf, 0x85, 0xf8, 0xb4, 0x22, 0x74, 0xe9, 0x96, 0x4d, 0x94, 0x80, 0xe8, - 0xfa, 0xae, 0x69, 0x7b, 0x7d, 0xc7, 0x83, 0x86, 0x73, 0xd9, 0x2b, 0xdb, 0xdd, 0x8a, 0xd3, 0xdb, - 0xdf, 0xb3, 0x3d, 0x6a, 0xac, 0xc7, 0xbd, 0x46, 0xd2, 0xc1, 0xf7, 0x47, 0x2f, 0x02, 0x50, 0x69, - 0xd6, 0xeb, 0x7a, 0xa5, 0x5d, 0x6b, 0x36, 0x94, 0x63, 0x48, 0x5a, 0xed, 0xf2, 0x72, 0x1d, 0x49, - 0xe7, 0xe9, 0xa0, 0x14, 0xb4, 0x69, 0x1a, 0x9f, 0x28, 0x17, 0xc4, 0x27, 0x52, 0xcb, 0xa0, 0x14, - 0xb4, 0x72, 0x3a, 0x22, 0x3c, 0x62, 0xf0, 0x3c, 0xfa, 0x9e, 0xe9, 0xfa, 0xd8, 0xb4, 0x0c, 0x88, - 0x2c, 0x9b, 0x1e, 0x34, 0xc2, 0xcf, 0xce, 0x3e, 0x9a, 0x72, 0xa0, 0x82, 0xc5, 0x72, 0xbd, 0xbe, - 0xd5, 0x34, 0xb6, 0x1a, 0xcd, 0xf6, 0x5a, 0xad, 0xb1, 0x4a, 0x46, 0xc8, 0xda, 0x6a, 0xa3, 0x69, - 0xe8, 0x64, 0x80, 0x6c, 0x29, 0x39, 0x72, 0x7f, 0xf9, 0x72, 0x09, 0x14, 0xfb, 0x58, 0xba, 0xda, - 0x57, 0xe4, 0x94, 0xa6, 0x45, 0x88, 0x53, 0xcc, 0x0d, 0xcb, 0xdc, 0x61, 0x10, 0x69, 0xc8, 0x61, - 0xed, 0xb3, 0x60, 0x9e, 0x98, 0x43, 0x1e, 0xde, 0x57, 0xc3, 0xc8, 0xc9, 0x06, 0x97, 0xa6, 0x7d, - 0x52, 0x4a, 0x61, 0x5c, 0x0c, 0xe5, 0x28, 0x9d, 0x71, 0xf1, 0x07, 0xb9, 0xf1, 0xae, 0x23, 0xa9, - 0x35, 0xda, 0xba, 0xd1, 0x28, 0xd7, 0x69, 0x16, 0x59, 0x3d, 0x0d, 0x4e, 0x36, 0x9a, 0x34, 0x18, - 0x67, 0x6b, 0xab, 0xdd, 0xdc, 0xaa, 0xad, 0x6f, 0x34, 0x8d, 0xb6, 0x52, 0x50, 0x4f, 0x01, 0x95, - 0xfc, 0xdf, 0xaa, 0xb5, 0xb6, 0x2a, 0xe5, 0x46, 0x45, 0xaf, 0xeb, 0x55, 0xa5, 0xa8, 0x3e, 0x12, - 0x3c, 0x9c, 0x5c, 0x6f, 0xd5, 0x5c, 0xd9, 0x32, 0x9a, 0xe7, 0x5b, 0x08, 0x41, 0x43, 0xaf, 0x97, - 0x91, 0x22, 0x31, 0xf7, 0x98, 0xcf, 0xa8, 0x57, 0x81, 0xe3, 0x2b, 0xb5, 0xba, 0x8e, 0x6f, 0xa3, - 0xa5, 0xe5, 0x95, 0xd4, 0x6b, 0xc1, 0xe9, 0x5a, 0xa3, 0xb5, 0xb9, 0xb2, 0x52, 0xab, 0xd4, 0xf4, - 0x46, 0x7b, 0x6b, 0x43, 0x37, 0xd6, 0x6b, 0xad, 0x16, 0xfa, 0x56, 0x99, 0xd5, 0x3e, 0x2e, 0x83, - 0x22, 0xe9, 0x33, 0x91, 0x11, 0xbb, 0x70, 0xce, 0xec, 0x59, 0x68, 0xa0, 0xc0, 0xd7, 0xc7, 0x0f, - 0x9c, 0xe3, 0xf2, 0xf1, 0x35, 0xf3, 0xf4, 0x24, 0x08, 0x7e, 0xd0, 0x7e, 0x54, 0x4e, 0x79, 0x8e, - 0x8b, 0x02, 0x41, 0x4a, 0x5c, 0xe2, 0x4a, 0x8b, 0x59, 0x75, 0x78, 0x8d, 0x94, 0xe2, 0x1c, 0x97, - 0x38, 0xf9, 0x74, 0xe0, 0xff, 0xe2, 0xa4, 0xc0, 0x57, 0xc0, 0xfc, 0x66, 0xa3, 0xbc, 0xd9, 0x5e, - 0x6b, 0x1a, 0xb5, 0x1f, 0xc6, 0xb7, 0x10, 0x2c, 0x80, 0xd9, 0x95, 0xa6, 0xb1, 0x5c, 0xab, 0x56, - 0xf5, 0x86, 0x52, 0x50, 0x1f, 0x04, 0xae, 0x6a, 0xe9, 0xc6, 0xb9, 0x5a, 0x45, 0xdf, 0xda, 0x6c, - 0x94, 0xcf, 0x95, 0x6b, 0x75, 0xdc, 0x47, 0x14, 0x13, 0xae, 0xbe, 0x9f, 0xd1, 0x7e, 0x24, 0x0f, - 0x00, 0xa9, 0x3a, 0xbe, 0x84, 0x8b, 0xb9, 0x20, 0xfd, 0x8f, 0xd2, 0x4e, 0xf7, 0x22, 0x32, 0x31, - 0xed, 0xb7, 0x06, 0x4a, 0x2e, 0x7d, 0x41, 0xd7, 0x35, 0x47, 0xd1, 0x21, 0x7f, 0x03, 0x6a, 0x46, - 0xf8, 0xb9, 0xf6, 0x81, 0x34, 0xb3, 0xbb, 0x58, 0xc6, 0xa6, 0x72, 0xd3, 0xf3, 0x20, 0x90, 0xda, - 0x0b, 0x73, 0x60, 0x91, 0xaf, 0x18, 0xaa, 0x04, 0x36, 0xa6, 0xc4, 0x2a, 0xc1, 0x7f, 0xcc, 0x18, - 0x59, 0x67, 0x1f, 0x47, 0x87, 0x53, 0x10, 0xb4, 0x4c, 0x12, 0x92, 0x21, 0xb0, 0x58, 0x94, 0x1c, - 0x62, 0x1e, 0x19, 0x1d, 0x8a, 0xa4, 0xce, 0x00, 0xb9, 0x7d, 0xbf, 0xaf, 0xc8, 0xda, 0xa7, 0xf3, - 0x60, 0x81, 0xbb, 0x81, 0x5d, 0xfb, 0xe3, 0x9c, 0xc8, 0xed, 0xc6, 0xcc, 0xdd, 0xee, 0xb9, 0xc3, - 0xde, 0xed, 0x7e, 0xd6, 0x02, 0x33, 0x34, 0x0d, 0xcb, 0xb7, 0xd9, 0x40, 0xa6, 0xc0, 0x71, 0x30, - 0xb7, 0xaa, 0xb7, 0xb7, 0x5a, 0xed, 0xb2, 0xd1, 0xd6, 0xab, 0x4a, 0x0e, 0x0d, 0x7c, 0xfa, 0xfa, - 0x46, 0xfb, 0x5e, 0x45, 0x42, 0x63, 0xe2, 0xea, 0x66, 0xad, 0xaa, 0x6f, 0x35, 0x1b, 0xf5, 0x7b, - 0x15, 0x19, 0xf5, 0x80, 0x4c, 0xde, 0xad, 0xf5, 0xe6, 0x72, 0xad, 0xae, 0x2b, 0x79, 0xd4, 0x6c, - 0xf0, 0x27, 0x41, 0x4a, 0x81, 0xf7, 0x8d, 0x16, 0x59, 0xe1, 0x1c, 0xac, 0xc2, 0xe1, 0x5d, 0x44, - 0xd2, 0x5c, 0x21, 0x9f, 0x6a, 0xed, 0x34, 0x89, 0xd5, 0xec, 0x67, 0xc4, 0x9f, 0x97, 0x81, 0x42, - 0x38, 0xd0, 0xef, 0xef, 0x43, 0xd7, 0x82, 0x76, 0x07, 0x6a, 0x17, 0x45, 0x02, 0x02, 0x1f, 0x08, - 0x85, 0x89, 0x47, 0x0d, 0xc6, 0x16, 0x25, 0x0f, 0x03, 0x66, 0x7c, 0xfe, 0x80, 0x19, 0xff, 0x3b, - 0x69, 0x3d, 0x70, 0x07, 0xd9, 0x9d, 0xc8, 0x9e, 0xd5, 0x67, 0xd2, 0x78, 0xe0, 0x8e, 0xe0, 0x60, - 0x2a, 0x71, 0xbe, 0x63, 0x46, 0x79, 0x45, 0xd6, 0x5e, 0x20, 0x83, 0xe3, 0x55, 0xd3, 0x87, 0xcb, - 0x57, 0xda, 0xc1, 0x3d, 0xaa, 0x31, 0x77, 0x9f, 0xe7, 0x0e, 0xdc, 0x7d, 0x1e, 0x5d, 0xc5, 0x2a, - 0x0d, 0x5c, 0xc5, 0xaa, 0xbd, 0x27, 0xed, 0x99, 0xdd, 0x01, 0x1e, 0x26, 0x16, 0x8c, 0x3b, 0xdd, - 0x59, 0xdc, 0x64, 0x2e, 0xb2, 0x6f, 0x60, 0x6f, 0x9f, 0x05, 0x0a, 0x61, 0x85, 0x71, 0x32, 0xfd, - 0x59, 0x19, 0xc8, 0xe5, 0x6e, 0x57, 0xdb, 0x4a, 0x11, 0xd3, 0x33, 0x88, 0x92, 0x22, 0xf1, 0x51, - 0x52, 0xb8, 0x3d, 0x0b, 0x79, 0xd0, 0x31, 0x28, 0xed, 0x69, 0x04, 0xc6, 0xa3, 0x34, 0x3e, 0x8c, - 0x72, 0x76, 0xa7, 0x11, 0x12, 0x8b, 0x9f, 0xce, 0x95, 0xd6, 0xf4, 0x16, 0x59, 0x5d, 0x14, 0x99, - 0xe4, 0x9b, 0xfb, 0xd3, 0x1e, 0x2f, 0xe0, 0x3c, 0x7a, 0x13, 0xae, 0xb3, 0xcf, 0xee, 0x78, 0xc1, - 0x28, 0x0e, 0xb2, 0x47, 0xe1, 0x7b, 0x12, 0xc8, 0xb7, 0x1c, 0xd7, 0x9f, 0x14, 0x06, 0x69, 0x5d, - 0x22, 0x18, 0x09, 0xb4, 0xe2, 0x67, 0xb6, 0xd9, 0xb9, 0x44, 0x24, 0x97, 0x3f, 0x85, 0xb0, 0xa8, - 0xc7, 0xc1, 0x22, 0xe1, 0x24, 0xbc, 0x53, 0xe8, 0x5f, 0x25, 0xd2, 0x5f, 0xdd, 0x23, 0x8a, 0x08, - 0xde, 0x18, 0x0b, 0x5d, 0x12, 0x02, 0x50, 0xb8, 0x34, 0xed, 0x8d, 0x2c, 0x2e, 0x55, 0x1e, 0x97, - 0x61, 0xf3, 0xfa, 0xf0, 0x5a, 0x9e, 0x49, 0xf5, 0x4c, 0x69, 0x22, 0xac, 0x26, 0x14, 0x9e, 0x3d, - 0x22, 0xcf, 0x91, 0x41, 0x91, 0xba, 0x84, 0x4e, 0x14, 0x81, 0xb4, 0x2d, 0x23, 0x14, 0x82, 0x98, - 0xeb, 0xa8, 0x3c, 0xe9, 0x96, 0x91, 0x5c, 0x7e, 0xf6, 0x38, 0xfc, 0x1b, 0xf5, 0x75, 0x2e, 0x5f, - 0x32, 0xad, 0x9e, 0x79, 0xa1, 0x97, 0x22, 0xb2, 0xf9, 0x27, 0x53, 0x9e, 0xee, 0x0c, 0xab, 0xca, - 0x95, 0x17, 0x23, 0xf1, 0x1f, 0x04, 0xb3, 0x2e, 0xb7, 0x17, 0x8c, 0xac, 0xa8, 0x01, 0x3f, 0x73, - 0xfa, 0xde, 0x88, 0x72, 0xa6, 0x3a, 0xca, 0x29, 0xc4, 0xcf, 0x54, 0x8e, 0x9e, 0xcd, 0x95, 0xbb, - 0xdd, 0x15, 0x68, 0xfa, 0xfb, 0x2e, 0xec, 0xa6, 0x1a, 0x22, 0xdc, 0x81, 0xed, 0x72, 0x46, 0x12, - 0x5c, 0x6c, 0xd1, 0x3a, 0x8f, 0xce, 0x13, 0x46, 0xf4, 0x06, 0x01, 0x2f, 0x13, 0xe9, 0x92, 0xde, - 0x16, 0x42, 0xd2, 0xe4, 0x20, 0x79, 0xd2, 0x78, 0x4c, 0x64, 0x0f, 0xc8, 0x4b, 0x65, 0xb0, 0x48, - 0xec, 0x84, 0x49, 0x63, 0xf2, 0xe1, 0x94, 0x2e, 0x64, 0xcc, 0xad, 0x6d, 0x2c, 0x3b, 0x13, 0x81, - 0x25, 0x8d, 0xc3, 0x99, 0x18, 0x1f, 0xd9, 0x23, 0xf3, 0x3f, 0xaf, 0x02, 0x80, 0x71, 0x0b, 0xfe, - 0x64, 0x31, 0x8a, 0xf3, 0xa9, 0xbd, 0x93, 0xce, 0x3f, 0x5a, 0x5c, 0xd0, 0x79, 0xc6, 0xe5, 0x37, - 0xdc, 0xf6, 0xe2, 0x13, 0x85, 0x46, 0x95, 0x3f, 0x48, 0x69, 0xf3, 0x52, 0xa7, 0xdc, 0x91, 0x83, - 0xfb, 0x98, 0xbd, 0xdc, 0xa7, 0x52, 0x18, 0xbf, 0xa3, 0x58, 0x49, 0x87, 0x5a, 0x7d, 0x8c, 0x99, - 0xfd, 0x69, 0x70, 0xd2, 0xd0, 0xcb, 0xd5, 0x66, 0xa3, 0x7e, 0x2f, 0x7b, 0x85, 0x97, 0x22, 0xb3, - 0x93, 0x93, 0x4c, 0x60, 0x7b, 0x5d, 0xca, 0x3e, 0x90, 0x97, 0x55, 0xd2, 0x6c, 0x85, 0x59, 0x5c, - 0x19, 0xdd, 0xab, 0x09, 0x90, 0x3d, 0x4a, 0x14, 0xbe, 0x55, 0x04, 0x73, 0x06, 0xec, 0x38, 0x7b, - 0x7b, 0xd0, 0xee, 0xc2, 0xae, 0xf6, 0x3a, 0x19, 0xcc, 0x87, 0xbb, 0x8a, 0x2d, 0xe8, 0x6b, 0xff, - 0x29, 0xc2, 0xe6, 0x2c, 0x98, 0x47, 0x95, 0x6b, 0xf2, 0x17, 0x09, 0x70, 0x69, 0xea, 0xcd, 0xe0, - 0x44, 0x80, 0x42, 0x73, 0x60, 0x0a, 0x73, 0xf0, 0x05, 0xef, 0xf7, 0xb3, 0xc9, 0x63, 0x74, 0x57, - 0xbc, 0x30, 0x43, 0x76, 0x97, 0x58, 0x56, 0x63, 0xc0, 0xfa, 0xbd, 0x10, 0xac, 0xa7, 0x71, 0x60, - 0x55, 0x0f, 0x49, 0xff, 0x28, 0x51, 0xfb, 0x90, 0x0c, 0x4e, 0x06, 0x1d, 0xf1, 0xf4, 0xd0, 0xfa, - 0x14, 0x8b, 0xd6, 0xd3, 0x79, 0xb4, 0x56, 0x45, 0xa4, 0x39, 0x8c, 0xe5, 0x18, 0xd4, 0xbe, 0x1c, - 0xa2, 0xf6, 0x5f, 0x38, 0xd4, 0xea, 0x13, 0x2a, 0xe7, 0x28, 0xd1, 0xfb, 0xb0, 0x0c, 0x4e, 0x23, - 0xb3, 0xb3, 0xe2, 0xd8, 0xdb, 0x3d, 0xab, 0xe3, 0x5b, 0xf6, 0x4e, 0xe4, 0xe2, 0xb8, 0x2a, 0xb2, - 0xb2, 0x39, 0x88, 0xad, 0x74, 0x10, 0x5b, 0x7e, 0x8f, 0x41, 0xb4, 0x6d, 0xc5, 0xb1, 0x15, 0x33, - 0x84, 0x31, 0xce, 0xfb, 0x91, 0xe6, 0xb0, 0x49, 0xe9, 0x5b, 0x9f, 0x20, 0x07, 0x47, 0x89, 0xdf, - 0xd7, 0x25, 0x70, 0xca, 0x80, 0x9e, 0xd3, 0xbb, 0x04, 0x89, 0x2f, 0x6b, 0xc0, 0xaf, 0xa7, 0x3d, - 0x3a, 0x55, 0xfb, 0xd3, 0x5e, 0xca, 0x62, 0xd4, 0xe2, 0x31, 0xba, 0x33, 0x5e, 0xd3, 0x87, 0x15, - 0x1d, 0xd3, 0x8e, 0xde, 0x1b, 0xca, 0xff, 0x1c, 0x27, 0xff, 0xe5, 0x43, 0x51, 0x9f, 0xc2, 0x12, - 0x01, 0x60, 0xcc, 0xbb, 0xe7, 0xcb, 0x40, 0xc1, 0x3e, 0xcb, 0x78, 0xf4, 0xa4, 0x77, 0x08, 0x37, - 0xf9, 0xd3, 0x2c, 0xfd, 0x40, 0x09, 0x83, 0xd3, 0x2c, 0x41, 0x82, 0x7a, 0x03, 0x58, 0xec, 0xec, - 0xc2, 0xce, 0xc5, 0x9a, 0x1d, 0x78, 0x95, 0x11, 0x17, 0xa4, 0x81, 0x54, 0xde, 0x60, 0xb8, 0x87, - 0x07, 0x83, 0x5f, 0xdc, 0xe5, 0x26, 0x8f, 0x2c, 0x53, 0x31, 0x20, 0xfc, 0x66, 0x08, 0x42, 0x83, - 0x03, 0xe1, 0xf6, 0xb1, 0xa8, 0xa6, 0x13, 0x7e, 0x63, 0x0c, 0xd5, 0xd7, 0xc0, 0xa9, 0xe6, 0x46, - 0xbb, 0xd6, 0x6c, 0x6c, 0x6d, 0xb6, 0xf4, 0xea, 0xd6, 0x72, 0xd0, 0x00, 0x5a, 0x8a, 0xac, 0x7d, - 0x53, 0x02, 0x33, 0x84, 0x2d, 0x4f, 0x7b, 0x54, 0x04, 0xc1, 0xc8, 0x63, 0x3c, 0xda, 0xdb, 0x85, - 0x83, 0x72, 0x85, 0x82, 0xa0, 0xe5, 0xc4, 0x74, 0x3e, 0x4f, 0x04, 0x33, 0x04, 0xe4, 0x60, 0xa7, - 0xe5, 0x4c, 0x8c, 0xf5, 0x4c, 0xc9, 0x18, 0x41, 0x76, 0xc1, 0x00, 0x5d, 0x23, 0xd8, 0xc8, 0xbe, - 0x0d, 0x3c, 0x2b, 0x4f, 0x96, 0x67, 0xce, 0x5b, 0xfe, 0x2e, 0x3e, 0xe5, 0xa3, 0x3d, 0x55, 0x64, - 0x70, 0xb8, 0x19, 0x14, 0x2e, 0xa1, 0xdc, 0x23, 0x4e, 0x4c, 0x91, 0x4c, 0xda, 0x2f, 0x0a, 0xc7, - 0x83, 0xe7, 0xf4, 0x33, 0xe4, 0x29, 0x06, 0x9c, 0x75, 0x90, 0xef, 0x59, 0x9e, 0x4f, 0xe7, 0x35, - 0xb7, 0xa5, 0x22, 0x14, 0xfc, 0xa9, 0xf9, 0x70, 0xcf, 0xc0, 0x64, 0xb4, 0xbb, 0x91, 0x55, 0x1a, - 0xa5, 0x0a, 0x9c, 0x1a, 0x3b, 0x0d, 0x66, 0x68, 0x34, 0x03, 0xba, 0xf5, 0x17, 0x3c, 0x0a, 0x6e, - 0xb7, 0x09, 0xd5, 0x36, 0x7b, 0x1d, 0xf8, 0x7f, 0x8f, 0x83, 0x99, 0x35, 0xcb, 0xf3, 0x1d, 0xf7, - 0x8a, 0xf6, 0xfa, 0x1c, 0x98, 0x39, 0x07, 0x5d, 0xcf, 0x72, 0xec, 0x03, 0x8e, 0x76, 0xd7, 0x81, - 0xb9, 0xbe, 0x0b, 0x2f, 0x59, 0xce, 0xbe, 0xc7, 0x8c, 0xc4, 0x4c, 0x92, 0xaa, 0x81, 0x92, 0xb9, - 0xef, 0xef, 0x3a, 0x6e, 0x14, 0x04, 0x2d, 0x78, 0x56, 0xcf, 0x00, 0x40, 0xfe, 0x37, 0xcc, 0x3d, - 0x48, 0xdd, 0x07, 0x99, 0x14, 0x55, 0x05, 0x79, 0xdf, 0xda, 0x83, 0xf4, 0x56, 0x04, 0xfc, 0x1f, - 0x09, 0x18, 0x47, 0x18, 0xa6, 0x91, 0x9c, 0x65, 0x23, 0x78, 0xd4, 0xbe, 0x28, 0x83, 0xb9, 0x55, - 0xe8, 0x53, 0x56, 0x3d, 0xed, 0x45, 0x39, 0xa1, 0x8b, 0xc8, 0xd0, 0xdc, 0xaf, 0x67, 0x7a, 0xc1, - 0x77, 0xa1, 0x59, 0xc3, 0x27, 0x46, 0x57, 0x34, 0xc8, 0xec, 0xfd, 0x2c, 0x38, 0x5e, 0xaf, 0x5f, - 0x23, 0x07, 0x68, 0x68, 0x66, 0xba, 0x39, 0x7f, 0xf0, 0x05, 0x3f, 0xef, 0x48, 0x8c, 0x75, 0x43, - 0x65, 0xbf, 0xc4, 0xd4, 0x27, 0xb6, 0x3b, 0x2a, 0x5d, 0xa2, 0x39, 0x0e, 0x5c, 0xbd, 0xc3, 0x52, - 0xa2, 0x64, 0x8c, 0x30, 0xb7, 0x60, 0x94, 0x9c, 0xd1, 0x9c, 0x4c, 0xe1, 0xb2, 0x65, 0x19, 0xcc, - 0xb5, 0x76, 0x9d, 0xcb, 0x81, 0x1c, 0x9f, 0x2e, 0x06, 0xec, 0xb5, 0x60, 0xf6, 0xd2, 0x00, 0xa8, - 0x51, 0x02, 0x7b, 0xbf, 0xa3, 0xcc, 0xdf, 0xef, 0xf8, 0x3c, 0x39, 0x2d, 0x4c, 0x0c, 0x73, 0x31, - 0x30, 0xf1, 0x57, 0x32, 0x4a, 0x29, 0xae, 0x64, 0x54, 0x9f, 0x00, 0x66, 0x28, 0xd7, 0x74, 0x2b, - 0x20, 0x19, 0xe0, 0x20, 0x33, 0x5b, 0xc1, 0x3c, 0x5f, 0xc1, 0x74, 0xc8, 0xc7, 0x57, 0x2e, 0x7b, - 0xe4, 0x7f, 0x5b, 0xc2, 0x31, 0xd2, 0x02, 0xe0, 0x2b, 0x13, 0x00, 0x5e, 0xfb, 0x6e, 0x4e, 0x74, - 0xc3, 0x2c, 0x94, 0x40, 0xc8, 0xc1, 0xa1, 0x2e, 0x19, 0x1c, 0x49, 0x2e, 0x7b, 0x79, 0xbe, 0x3c, - 0x0f, 0xe6, 0xab, 0xd6, 0xf6, 0x76, 0xd8, 0x49, 0xbe, 0x58, 0xb0, 0x93, 0x8c, 0x77, 0x86, 0x43, - 0x76, 0xee, 0xbe, 0xeb, 0x42, 0x3b, 0xa8, 0x14, 0x6d, 0x4e, 0x03, 0xa9, 0xea, 0x8d, 0xe0, 0x78, - 0x30, 0x2e, 0xb0, 0x1d, 0xe5, 0xac, 0x31, 0x98, 0xac, 0x7d, 0x5b, 0xd8, 0xdb, 0x22, 0x90, 0x28, - 0x5b, 0xa5, 0x98, 0x06, 0x78, 0x07, 0x58, 0xd8, 0x25, 0xb9, 0xf1, 0x92, 0x74, 0xd0, 0x59, 0x9e, - 0x1a, 0xb8, 0x83, 0x62, 0x1d, 0x7a, 0x9e, 0xb9, 0x03, 0x0d, 0x3e, 0xf3, 0x40, 0xf3, 0x95, 0xd3, - 0xdc, 0xa8, 0x2a, 0xe6, 0xb8, 0x21, 0x50, 0x93, 0xec, 0xb5, 0xe3, 0xcb, 0x67, 0x41, 0x7e, 0xc5, - 0xea, 0x41, 0xed, 0xc7, 0x25, 0x30, 0x6b, 0xc0, 0x8e, 0x63, 0x77, 0xd0, 0x13, 0xe3, 0x1a, 0xfb, - 0xad, 0x9c, 0xe8, 0x4d, 0xe2, 0x88, 0xce, 0x52, 0x48, 0x23, 0xa6, 0xdd, 0x88, 0xdd, 0x18, 0x9e, - 0x48, 0x6a, 0x0a, 0xf7, 0xbe, 0xa1, 0xa9, 0xc7, 0xf6, 0x76, 0xcf, 0x31, 0xb9, 0x4d, 0x99, 0x41, - 0x53, 0x28, 0x3a, 0x88, 0xdb, 0x70, 0xfc, 0x0d, 0xcb, 0xb6, 0xc3, 0xd8, 0x36, 0x07, 0xd2, 0x79, - 0x7f, 0xa2, 0xc4, 0xf0, 0x80, 0xb8, 0xee, 0xb4, 0xf4, 0x18, 0xcd, 0xbe, 0x01, 0x2c, 0x5e, 0xb8, - 0xe2, 0x43, 0x8f, 0xe6, 0xa2, 0xc5, 0xe6, 0x8d, 0x81, 0x54, 0xe6, 0x72, 0x8f, 0xa4, 0x30, 0x82, - 0x09, 0x05, 0xa6, 0x13, 0xf5, 0xda, 0x18, 0x33, 0xc0, 0x93, 0x40, 0x69, 0x34, 0xab, 0x3a, 0xf6, - 0xd4, 0x0e, 0x7c, 0x5f, 0x77, 0xb4, 0x9f, 0x91, 0xc1, 0x3c, 0x76, 0x72, 0x0c, 0x50, 0x78, 0xb8, - 0xc0, 0x7c, 0x44, 0xfb, 0xaa, 0xb0, 0x17, 0x37, 0xae, 0x32, 0x5b, 0x40, 0xbc, 0xa0, 0xb7, 0xad, - 0xde, 0xa0, 0xa0, 0x0b, 0xc6, 0x40, 0xea, 0x10, 0x40, 0xe4, 0xa1, 0x80, 0x7c, 0x48, 0xc8, 0x95, - 0x7b, 0x14, 0x77, 0x47, 0x85, 0xca, 0xaf, 0xc9, 0x60, 0x0e, 0x4d, 0x52, 0x02, 0x50, 0x9a, 0x1c, - 0x28, 0x8e, 0xdd, 0xbb, 0x12, 0x2d, 0x8b, 0x04, 0x8f, 0xa9, 0x1a, 0xc9, 0x1f, 0x0b, 0xcf, 0xdc, - 0xb1, 0x88, 0x18, 0x5e, 0xa6, 0x84, 0xdf, 0x07, 0x85, 0xe6, 0xf3, 0x23, 0x98, 0x3b, 0x2a, 0xf8, - 0x5e, 0x5b, 0x04, 0xc5, 0xcd, 0x3e, 0x46, 0xee, 0x2b, 0xb2, 0xc8, 0x45, 0x39, 0x07, 0x8e, 0xf1, - 0x21, 0x33, 0xab, 0xe7, 0x74, 0xcc, 0xde, 0x46, 0x74, 0x92, 0x3d, 0x4a, 0x50, 0x6f, 0xa7, 0x9e, - 0xfd, 0xe4, 0x40, 0xf6, 0x0d, 0x89, 0x77, 0xc8, 0x60, 0x19, 0x31, 0x47, 0x26, 0x6f, 0x06, 0x27, - 0xba, 0x96, 0x67, 0x5e, 0xe8, 0x41, 0xdd, 0xee, 0xb8, 0x57, 0x88, 0x38, 0xe8, 0xb4, 0xea, 0xc0, - 0x0b, 0xf5, 0x4e, 0x50, 0xf0, 0xfc, 0x2b, 0x3d, 0x32, 0x4f, 0x64, 0x4f, 0x58, 0xc6, 0x16, 0xd5, - 0x42, 0xd9, 0x0d, 0xf2, 0x15, 0xeb, 0x3a, 0x3b, 0x23, 0xe6, 0x3a, 0xab, 0x3e, 0x0e, 0x14, 0x1d, - 0xd7, 0xda, 0xb1, 0xc8, 0xb5, 0x90, 0x8b, 0x07, 0x42, 0x25, 0x13, 0x53, 0xa0, 0x89, 0xb3, 0x18, - 0x34, 0xab, 0xfa, 0x04, 0x30, 0x6b, 0xed, 0x99, 0x3b, 0xf0, 0x1e, 0xcb, 0x26, 0x81, 0x24, 0x16, - 0x6f, 0x3d, 0x7d, 0xe0, 0xf0, 0x28, 0x7d, 0x6f, 0x44, 0x59, 0xd5, 0x3b, 0xc0, 0x35, 0x1d, 0x17, - 0x9a, 0x3e, 0x44, 0x02, 0x3a, 0x6f, 0x75, 0x77, 0xa0, 0x5f, 0xdb, 0x5e, 0xb7, 0x3c, 0xcf, 0xb2, - 0x77, 0xe8, 0xcd, 0xaf, 0xf1, 0x19, 0xb4, 0x0f, 0x4a, 0xa2, 0xd1, 0x20, 0xb1, 0x64, 0x88, 0x4a, - 0x8c, 0x71, 0x43, 0x3d, 0x23, 0x45, 0x59, 0xd0, 0x01, 0xf9, 0x55, 0x42, 0x71, 0x1a, 0xe3, 0xd9, - 0xca, 0x7e, 0xe8, 0xff, 0x43, 0x09, 0x94, 0xaa, 0xce, 0x65, 0x1b, 0x37, 0x93, 0xdb, 0xc4, 0x2c, - 0xe5, 0x21, 0xa1, 0x1d, 0xf8, 0xbb, 0xce, 0x13, 0x4f, 0x03, 0xe2, 0xda, 0x06, 0x45, 0xc6, 0xc0, - 0x90, 0xd8, 0xee, 0x04, 0x03, 0x08, 0x24, 0x95, 0x93, 0xbd, 0x5c, 0x7f, 0x57, 0x06, 0xf9, 0xaa, - 0xeb, 0xf4, 0xb5, 0xb7, 0xe5, 0x52, 0x38, 0xe2, 0x75, 0x5d, 0xa7, 0xdf, 0xc6, 0x57, 0xc8, 0x46, - 0x7b, 0x4f, 0x6c, 0x9a, 0x7a, 0x1b, 0x28, 0xf5, 0x1d, 0xcf, 0xf2, 0x83, 0x49, 0xc8, 0xe2, 0xad, - 0x0f, 0x19, 0xda, 0x17, 0x6c, 0xd0, 0x4c, 0x46, 0x98, 0x1d, 0xf5, 0xf9, 0x58, 0x84, 0x48, 0x2e, - 0x48, 0x8c, 0xc1, 0x35, 0xba, 0x03, 0xa9, 0xda, 0x4b, 0x58, 0x24, 0x9f, 0xc4, 0x23, 0xf9, 0x88, - 0x21, 0x12, 0x76, 0x9d, 0xfe, 0x44, 0x5c, 0x67, 0x5e, 0x11, 0xa2, 0xfa, 0x64, 0x0e, 0xd5, 0x9b, - 0x84, 0xca, 0xcc, 0x1e, 0xd1, 0x0f, 0xe6, 0x01, 0xc0, 0x46, 0xca, 0x26, 0x9a, 0x3e, 0x89, 0x59, - 0x68, 0x3f, 0x96, 0x67, 0x64, 0x59, 0xe6, 0x65, 0xf9, 0xa8, 0x18, 0x1b, 0x08, 0x93, 0x8f, 0x91, - 0x68, 0x19, 0x14, 0xf6, 0xd1, 0x6b, 0x2a, 0x51, 0x41, 0x12, 0xf8, 0xd1, 0x20, 0x5f, 0x6a, 0xbf, - 0x9d, 0x03, 0x05, 0x9c, 0xa0, 0x9e, 0x01, 0x00, 0x9b, 0x05, 0xe4, 0x30, 0x6d, 0x0e, 0x1b, 0x00, - 0x4c, 0x0a, 0xd6, 0x56, 0xab, 0x4b, 0x5f, 0x13, 0x83, 0x3b, 0x4a, 0x40, 0x5f, 0x63, 0x63, 0x01, - 0xd3, 0xa2, 0xe6, 0x03, 0x93, 0x82, 0xbe, 0xc6, 0x4f, 0x75, 0xb8, 0x4d, 0x6e, 0xf7, 0xc8, 0x1b, - 0x51, 0x42, 0xf8, 0x75, 0x3d, 0xbc, 0x13, 0x36, 0xf8, 0x1a, 0xa7, 0xa0, 0xa9, 0x34, 0x56, 0xcb, - 0xe5, 0xa8, 0x88, 0x22, 0xce, 0x34, 0x98, 0xac, 0xbd, 0x2e, 0x54, 0x9b, 0x2a, 0xa7, 0x36, 0x8f, - 0x49, 0x21, 0xde, 0xec, 0x95, 0xe7, 0xeb, 0x05, 0x30, 0xdb, 0x70, 0xba, 0x54, 0x77, 0x98, 0xe9, - 0xe6, 0x67, 0x0a, 0xa9, 0xa6, 0x9b, 0x21, 0x8d, 0x18, 0x05, 0x79, 0x0a, 0xaf, 0x20, 0x62, 0x14, - 0x58, 0xfd, 0x50, 0x97, 0x41, 0x11, 0x6b, 0xef, 0xc1, 0xcb, 0x46, 0x93, 0x48, 0x60, 0xd1, 0x1a, - 0xf4, 0xcb, 0x7f, 0x77, 0x3a, 0xf6, 0xdf, 0x40, 0x01, 0x57, 0x30, 0x61, 0x6f, 0x88, 0xaf, 0xa8, - 0x94, 0x5c, 0x51, 0x39, 0xb9, 0xa2, 0xf9, 0xc1, 0x8a, 0xa6, 0x59, 0x45, 0x88, 0xd3, 0x90, 0xec, - 0x75, 0xfc, 0x7f, 0xcd, 0x00, 0xd0, 0x30, 0x2f, 0x59, 0x3b, 0x64, 0x6f, 0xf9, 0x8b, 0xc1, 0xec, - 0x89, 0xee, 0x02, 0xff, 0x24, 0x33, 0x10, 0xde, 0x06, 0x66, 0xe8, 0xb8, 0x47, 0x2b, 0xf2, 0x50, - 0xae, 0x22, 0x11, 0x15, 0x62, 0xd4, 0xde, 0xef, 0x1b, 0x41, 0x7e, 0x64, 0x98, 0x6c, 0xef, 0xf7, - 0x7a, 0x6d, 0xf4, 0x2d, 0xb5, 0xd0, 0x82, 0xe7, 0x98, 0x1d, 0x8c, 0xe8, 0x92, 0x69, 0x12, 0x74, - 0x8a, 0x3e, 0x69, 0xef, 0x13, 0x3e, 0xa7, 0xc6, 0xf0, 0xc3, 0xd4, 0x28, 0xa6, 0x09, 0x3e, 0x0e, - 0xcc, 0x38, 0xe1, 0x76, 0xb8, 0x1c, 0xbb, 0x8a, 0x56, 0xb3, 0xb7, 0x1d, 0x23, 0xc8, 0x29, 0xb8, - 0x75, 0x26, 0xc4, 0xc7, 0x54, 0x8e, 0x82, 0x9e, 0x5a, 0x0d, 0x22, 0xa5, 0xa2, 0x7a, 0x9c, 0xb7, - 0xfc, 0xdd, 0xba, 0x65, 0x5f, 0xf4, 0xb4, 0xff, 0x22, 0x66, 0x41, 0x32, 0xf8, 0x4b, 0xe9, 0xf0, - 0xe7, 0x23, 0x95, 0x25, 0x7a, 0x76, 0x30, 0x54, 0x86, 0x73, 0x1b, 0x03, 0xe0, 0xed, 0xa0, 0x48, - 0x18, 0xa5, 0x9d, 0xe8, 0xd9, 0x58, 0xfc, 0x42, 0x4a, 0x06, 0xfd, 0x42, 0xd0, 0x2b, 0x24, 0x2d, - 0x67, 0x99, 0x43, 0x7a, 0xf6, 0xb1, 0x60, 0x86, 0x4a, 0x5a, 0x5d, 0x64, 0x5b, 0xb1, 0x72, 0x4c, - 0x05, 0xa0, 0xb8, 0xee, 0x5c, 0x82, 0x6d, 0x47, 0xc9, 0xa1, 0xff, 0x88, 0xbf, 0xb6, 0xa3, 0x48, - 0xda, 0x2b, 0x4b, 0xa0, 0x14, 0x86, 0xa8, 0xfc, 0x43, 0x09, 0x28, 0x15, 0x3c, 0x43, 0x5b, 0x71, - 0x9d, 0x3d, 0x52, 0x23, 0xf1, 0x33, 0x0f, 0x2f, 0x15, 0x76, 0x10, 0x09, 0x43, 0x47, 0x0e, 0x16, - 0x16, 0x83, 0x25, 0x59, 0xc2, 0x94, 0x82, 0x25, 0x4c, 0xed, 0xad, 0x42, 0x0e, 0x23, 0xa2, 0xa5, - 0x64, 0xdf, 0xd4, 0x7e, 0x47, 0x02, 0x85, 0x4a, 0xcf, 0xb1, 0x21, 0x7b, 0x30, 0x77, 0xe4, 0x09, - 0xd0, 0xe1, 0xfb, 0x18, 0xda, 0xb3, 0x24, 0x51, 0x5b, 0x23, 0x12, 0x00, 0x2a, 0x5b, 0x50, 0xb6, - 0x62, 0x83, 0x54, 0x22, 0xe9, 0xec, 0x05, 0xfa, 0x4d, 0x09, 0xcc, 0x92, 0x98, 0x72, 0xe5, 0x5e, - 0x4f, 0x7b, 0x48, 0x24, 0xd4, 0x21, 0x61, 0x3e, 0xb5, 0x0f, 0x09, 0x1f, 0x3c, 0x0b, 0x6b, 0x15, - 0xd2, 0x4e, 0x11, 0x16, 0x31, 0xdd, 0x39, 0x28, 0xb1, 0x9d, 0xb8, 0x91, 0x0c, 0x65, 0x2f, 0xea, - 0x3f, 0x92, 0x90, 0x01, 0x60, 0x5f, 0xdc, 0x70, 0xe1, 0x25, 0x0b, 0x5e, 0xd6, 0x1e, 0x1c, 0x09, - 0xfb, 0x60, 0xc0, 0xac, 0x37, 0x09, 0x2f, 0xe2, 0x30, 0x24, 0x63, 0x37, 0xc2, 0xe6, 0x7a, 0x51, - 0x26, 0xda, 0x8b, 0x0f, 0x46, 0x31, 0x63, 0xc8, 0x18, 0x6c, 0x76, 0xc1, 0x35, 0x9b, 0x78, 0x2e, - 0xb2, 0x17, 0xec, 0xc7, 0x66, 0x40, 0x69, 0xd3, 0xf6, 0xfa, 0x3d, 0xd3, 0xdb, 0xd5, 0xfe, 0x55, - 0x06, 0x45, 0x72, 0xc5, 0xad, 0xf6, 0x83, 0x5c, 0x5c, 0x9e, 0x67, 0xec, 0x43, 0x37, 0x70, 0xe0, - 0x21, 0x0f, 0x91, 0x7d, 0x24, 0x31, 0xf6, 0x91, 0xf6, 0x41, 0x59, 0x74, 0x92, 0x1a, 0x14, 0x4a, - 0xef, 0xd4, 0x8d, 0x0f, 0x05, 0xd3, 0xb7, 0x3a, 0xfe, 0xbe, 0x0b, 0xbd, 0xa1, 0xa1, 0x60, 0x62, - 0xa9, 0x6c, 0x90, 0xaf, 0x8c, 0xf0, 0x73, 0xcd, 0x04, 0x33, 0x34, 0xf1, 0xc0, 0x66, 0xd4, 0xc1, - 0xa8, 0x12, 0xa7, 0x40, 0xd1, 0x74, 0x7d, 0xcb, 0xf3, 0xe9, 0xf6, 0x2c, 0x7d, 0x42, 0xdd, 0x25, - 0xf9, 0xb7, 0xe9, 0xf6, 0x82, 0x08, 0x5e, 0x61, 0x82, 0xf6, 0x6b, 0x42, 0xf3, 0xc7, 0xe4, 0x9a, - 0xa7, 0x83, 0xfc, 0x9e, 0x31, 0x56, 0xb8, 0x1f, 0x04, 0xae, 0x32, 0xca, 0x6d, 0x7d, 0x8b, 0x04, - 0x7c, 0x0a, 0x63, 0x3b, 0x75, 0xb5, 0xf7, 0xc8, 0xcc, 0xfa, 0xdd, 0x15, 0x6e, 0x8c, 0xa0, 0x52, - 0x8c, 0xc6, 0x88, 0x30, 0x21, 0x61, 0xaf, 0x9b, 0x5b, 0xc2, 0x95, 0x85, 0x97, 0x70, 0xb5, 0x5f, - 0x11, 0xde, 0x8b, 0x0a, 0x45, 0x39, 0x62, 0x0d, 0x30, 0xe9, 0x0a, 0xcc, 0x8f, 0x08, 0xed, 0x2b, - 0x8d, 0x2a, 0xe9, 0x08, 0x61, 0xfb, 0xee, 0x29, 0x20, 0x95, 0x6b, 0xda, 0x4f, 0xcc, 0x80, 0xf9, - 0xf3, 0xae, 0xe5, 0x5b, 0xf6, 0x4e, 0xdb, 0x71, 0x7a, 0x9e, 0xf6, 0x1d, 0x66, 0xa3, 0xe2, 0x09, - 0xa0, 0xd8, 0x71, 0xec, 0x6d, 0x6b, 0x87, 0x8a, 0xf1, 0x0c, 0x57, 0xb9, 0x72, 0x6d, 0x69, 0xc3, - 0x75, 0x2e, 0x59, 0x5d, 0xe8, 0x56, 0x70, 0x2e, 0x83, 0xe6, 0x46, 0x7a, 0xcc, 0x84, 0xcc, 0x7b, - 0xcc, 0xe0, 0x57, 0x6c, 0x79, 0x61, 0xcc, 0x1e, 0x9a, 0xc8, 0x44, 0xcc, 0xab, 0x81, 0x52, 0xcf, - 0xb4, 0x77, 0xf6, 0x83, 0x99, 0xf7, 0xe0, 0x2e, 0x6a, 0x1c, 0xa5, 0x3a, 0xfd, 0xc8, 0x08, 0x3f, - 0xc7, 0x4e, 0x6e, 0xc8, 0xd4, 0x27, 0x6d, 0x0f, 0xff, 0x3f, 0xfb, 0xf1, 0x1c, 0x98, 0x63, 0x0a, - 0x55, 0xe7, 0xc0, 0x4c, 0x55, 0x5f, 0x29, 0x6f, 0xd6, 0xdb, 0xca, 0x31, 0x24, 0xc5, 0xd6, 0xe6, - 0xfa, 0x7a, 0xd9, 0xa8, 0xfd, 0xb0, 0xae, 0xe4, 0xd0, 0xbb, 0x55, 0xa3, 0x8c, 0x9e, 0x15, 0x09, - 0x3d, 0xb4, 0xd6, 0x9a, 0x46, 0x5b, 0x6f, 0x28, 0x32, 0xb2, 0x47, 0xf5, 0xa7, 0x6d, 0x94, 0x1b, - 0x55, 0x25, 0x8f, 0xfe, 0x2f, 0x6f, 0xd6, 0xeb, 0x7a, 0x5b, 0x29, 0x44, 0x41, 0xf4, 0x8a, 0x28, - 0xb9, 0x52, 0x6e, 0x6d, 0x96, 0xeb, 0xca, 0x0c, 0x4a, 0x5e, 0xd9, 0x6c, 0x34, 0xee, 0x55, 0x4a, - 0xa8, 0x88, 0x4a, 0xb3, 0xb1, 0x52, 0xab, 0xea, 0x8d, 0xb6, 0x32, 0xab, 0x5e, 0x05, 0x8e, 0xb7, - 0xda, 0x46, 0xb9, 0xb6, 0xba, 0xd6, 0x5e, 0x69, 0x1a, 0xe7, 0xcb, 0x46, 0x55, 0x01, 0xaa, 0x02, - 0xe6, 0x37, 0x8c, 0xe6, 0x8a, 0x8e, 0xe3, 0xa5, 0x94, 0xeb, 0xca, 0x1c, 0xfa, 0xaa, 0x6d, 0x94, - 0x1b, 0xad, 0x7a, 0xb9, 0xad, 0x2b, 0xf3, 0x67, 0xef, 0x06, 0xa5, 0xa0, 0xba, 0x6a, 0x11, 0x48, - 0x7a, 0x43, 0x39, 0x86, 0x7f, 0x5b, 0x4a, 0x0e, 0xfd, 0xae, 0x20, 0x7e, 0x8b, 0x40, 0xaa, 0xea, - 0x8a, 0x8c, 0x7e, 0x6b, 0x6d, 0x25, 0x8f, 0x7e, 0x37, 0x10, 0x8b, 0x45, 0x20, 0xad, 0xd5, 0x94, - 0x22, 0xfa, 0x6d, 0xaf, 0x29, 0x33, 0xfc, 0x4d, 0xf7, 0x89, 0xbd, 0xf0, 0x41, 0xc9, 0xc7, 0x18, - 0x1a, 0x7e, 0x34, 0x47, 0xc6, 0xff, 0xb5, 0x57, 0x48, 0x22, 0x7d, 0x5d, 0x32, 0xfd, 0x74, 0x8d, - 0xe6, 0x2d, 0xb9, 0x09, 0xb6, 0x1a, 0x55, 0x03, 0xa7, 0xf4, 0x46, 0x75, 0xa3, 0x59, 0x6b, 0xb4, - 0x49, 0xa8, 0x33, 0xbd, 0x5c, 0x59, 0xc3, 0x38, 0x43, 0x84, 0xe0, 0x7a, 0xb3, 0xaa, 0xd7, 0xf1, - 0x8b, 0x95, 0xe6, 0x66, 0xa3, 0xaa, 0x6c, 0xa3, 0xb2, 0xca, 0x9b, 0xed, 0xb5, 0x2d, 0x43, 0x7f, - 0xea, 0x66, 0xcd, 0xd0, 0xab, 0xca, 0x0e, 0xa2, 0x51, 0x2f, 0x37, 0x56, 0x37, 0xcb, 0xab, 0x74, - 0xbf, 0x70, 0x73, 0x63, 0xa3, 0x89, 0x77, 0x0c, 0x77, 0xb5, 0xbf, 0xcf, 0x83, 0x52, 0x79, 0xdf, - 0x77, 0xb6, 0xad, 0x5e, 0x4f, 0x7b, 0x8e, 0x74, 0xf8, 0xa6, 0x58, 0xe6, 0x9a, 0xe2, 0x81, 0x06, - 0x14, 0x94, 0x15, 0x36, 0x9e, 0x20, 0x81, 0x69, 0x87, 0xa7, 0x23, 0x67, 0x6c, 0x99, 0xee, 0x34, - 0x93, 0x47, 0xe2, 0x88, 0x6b, 0xd3, 0x96, 0x85, 0xdf, 0xd0, 0xc7, 0xb3, 0xf7, 0x80, 0x79, 0x96, - 0x12, 0x0e, 0x07, 0x56, 0x5e, 0x25, 0xf1, 0xc2, 0x82, 0x08, 0x81, 0x24, 0x5e, 0x18, 0x3e, 0x78, - 0x21, 0xe1, 0xf6, 0x52, 0x6b, 0xd7, 0x91, 0x9e, 0x1e, 0x07, 0x73, 0x55, 0xbd, 0x55, 0x31, 0x6a, - 0xd8, 0x4f, 0x5d, 0xc9, 0xf3, 0x5e, 0x06, 0x89, 0x96, 0x19, 0x5f, 0x23, 0x51, 0xa5, 0xfc, 0x9e, - 0x90, 0xbd, 0x15, 0x4f, 0x3b, 0x9d, 0x42, 0xbe, 0xe8, 0x81, 0xa6, 0x90, 0xda, 0x8b, 0xf2, 0x64, - 0x9d, 0xac, 0xb5, 0xbf, 0xb7, 0x67, 0xba, 0x57, 0x38, 0x7f, 0xb5, 0x71, 0xf5, 0x2e, 0x7e, 0x7c, - 0x4f, 0x8c, 0x02, 0x84, 0x4c, 0xa8, 0xbe, 0xeb, 0xec, 0xf5, 0x83, 0xbe, 0x9a, 0x3e, 0x69, 0xff, - 0x53, 0x78, 0xe6, 0x58, 0xae, 0x2d, 0x31, 0x95, 0x19, 0x63, 0x68, 0xff, 0x11, 0x49, 0x64, 0x16, - 0x99, 0x58, 0xcc, 0xf7, 0xbb, 0x46, 0xfc, 0x75, 0x1e, 0x5c, 0x45, 0x23, 0xbc, 0x84, 0xeb, 0x0f, - 0xc8, 0x54, 0x7d, 0x75, 0xa6, 0x9a, 0x41, 0x0d, 0x6a, 0x39, 0x32, 0xa8, 0x99, 0x0d, 0xef, 0xbc, - 0xe0, 0x86, 0xf7, 0xdb, 0x84, 0x0f, 0x3d, 0x94, 0x6b, 0x4b, 0x43, 0xea, 0x38, 0x9d, 0x6d, 0xf9, - 0xe7, 0x49, 0x22, 0xab, 0xad, 0x42, 0x1c, 0x7e, 0xbf, 0xeb, 0xda, 0x3b, 0x72, 0x60, 0x91, 0x57, - 0x15, 0xf5, 0xf1, 0xa0, 0xd4, 0xa7, 0x29, 0x54, 0x2e, 0xa7, 0xe3, 0x94, 0xcb, 0x08, 0x73, 0x22, - 0x88, 0xa0, 0xdd, 0xed, 0x3b, 0x96, 0x1d, 0xae, 0xcb, 0x07, 0xcf, 0x68, 0xde, 0x89, 0xa7, 0x0e, - 0x41, 0xbc, 0x3f, 0xfc, 0x10, 0xc5, 0x8e, 0xcd, 0x33, 0xb1, 0x63, 0x91, 0x10, 0x7d, 0xb8, 0x87, - 0x6f, 0x31, 0xda, 0x77, 0x89, 0xc3, 0x8b, 0x64, 0xb0, 0x49, 0x67, 0x9f, 0x0c, 0x4a, 0x41, 0xf9, - 0xc8, 0xba, 0x6b, 0xd6, 0xeb, 0xe5, 0xf5, 0x32, 0x59, 0xa8, 0x6c, 0x6e, 0xe8, 0x8d, 0x72, 0x4d, - 0xc9, 0xa1, 0x81, 0xae, 0xbe, 0xde, 0x6a, 0x6f, 0x56, 0x6b, 0x4d, 0x45, 0xc2, 0x4f, 0x28, 0x53, - 0x65, 0x63, 0x43, 0x91, 0xb5, 0x37, 0xce, 0x80, 0x99, 0x55, 0xb3, 0xd7, 0x83, 0xee, 0x15, 0xed, - 0x9b, 0x12, 0x50, 0x82, 0xd9, 0xc1, 0xba, 0x69, 0x5b, 0xdb, 0xd0, 0xf3, 0x93, 0x17, 0x2a, 0xde, - 0x27, 0x7c, 0xb5, 0x19, 0x2d, 0x63, 0x69, 0x90, 0x7e, 0x8c, 0x8e, 0xdf, 0x02, 0xf2, 0x96, 0xbd, - 0xed, 0xd0, 0xe5, 0x8a, 0x41, 0x7f, 0x9b, 0xe0, 0x63, 0xbc, 0x6d, 0x80, 0x33, 0x0a, 0xde, 0x6e, - 0x26, 0xc8, 0x45, 0xf6, 0xab, 0x16, 0xef, 0xc8, 0x83, 0x85, 0x80, 0x89, 0x9a, 0xdd, 0x85, 0xf7, - 0xb3, 0xdb, 0xa0, 0x3f, 0x93, 0x17, 0x0d, 0x30, 0x34, 0x58, 0x1f, 0x4c, 0x2a, 0x46, 0xa4, 0x6d, - 0x00, 0x3a, 0xa6, 0x0f, 0x77, 0x1c, 0xd7, 0x0a, 0xd7, 0x22, 0x1e, 0x9f, 0x86, 0x5a, 0x85, 0x7c, - 0x7d, 0xc5, 0x60, 0xe8, 0xa8, 0x77, 0x82, 0x39, 0x18, 0x46, 0x74, 0x0c, 0xb6, 0x49, 0x13, 0xf1, - 0x62, 0xf3, 0x6b, 0x7f, 0x24, 0x14, 0xc7, 0x48, 0xa4, 0x9a, 0xe9, 0x30, 0xdb, 0x1a, 0xaf, 0xeb, - 0xd9, 0x6c, 0xac, 0x97, 0x8d, 0xd6, 0x5a, 0xb9, 0x5e, 0xaf, 0x35, 0x56, 0xc3, 0x80, 0xc5, 0x2a, - 0x58, 0xac, 0x36, 0xcf, 0x37, 0x98, 0x88, 0xd2, 0x79, 0x6d, 0x03, 0x94, 0x02, 0x79, 0x0d, 0x3b, - 0x45, 0xc5, 0xca, 0x8c, 0x9e, 0xa2, 0x62, 0x92, 0x90, 0x69, 0x68, 0x75, 0x42, 0xd7, 0x7a, 0xfc, - 0x5f, 0xfb, 0x2d, 0x13, 0x14, 0xb0, 0x3f, 0x8b, 0xf6, 0x2e, 0x3c, 0x2f, 0xee, 0xf7, 0xcc, 0x0e, - 0xd4, 0xf6, 0x52, 0xac, 0x84, 0x07, 0x77, 0xed, 0x4a, 0x07, 0xee, 0xda, 0xc5, 0x7f, 0xe9, 0x88, - 0x71, 0x72, 0x98, 0x0f, 0x8d, 0x41, 0xb2, 0xf0, 0x21, 0x7f, 0x12, 0x3d, 0x9b, 0x88, 0xeb, 0x0d, - 0x65, 0x33, 0x46, 0x25, 0xe3, 0x79, 0xca, 0xe2, 0x12, 0x95, 0x24, 0x8e, 0xb2, 0x6f, 0xf1, 0x5f, - 0xc9, 0x83, 0x42, 0xab, 0xdf, 0xb3, 0x7c, 0xed, 0x17, 0xa4, 0x89, 0x60, 0x46, 0xee, 0x47, 0x96, - 0x47, 0xde, 0x8f, 0x1c, 0xf9, 0x4b, 0xe6, 0x05, 0xfc, 0x25, 0xdb, 0xf0, 0x7e, 0x9f, 0xf7, 0x97, - 0xbc, 0x8d, 0x4e, 0xdb, 0x88, 0xb7, 0xe5, 0x23, 0x86, 0x88, 0x14, 0x57, 0x6b, 0xc8, 0x6d, 0x16, - 0x67, 0x1f, 0x4b, 0x83, 0xea, 0x03, 0x50, 0x5c, 0x6e, 0xb6, 0xdb, 0xcd, 0x75, 0xe5, 0x18, 0x9e, - 0x7e, 0x35, 0x37, 0x48, 0x88, 0xe3, 0x5a, 0xa3, 0xa1, 0x1b, 0xdc, 0x8c, 0x8b, 0xbf, 0x2c, 0x33, - 0x71, 0x82, 0xc5, 0x97, 0x9d, 0xa5, 0x7a, 0x89, 0x2d, 0x82, 0xc7, 0xf3, 0x93, 0xbd, 0x72, 0xfd, - 0x9c, 0x0c, 0x0a, 0xeb, 0xd0, 0xdd, 0x81, 0xda, 0x33, 0x52, 0x38, 0xd8, 0x6d, 0x5b, 0xae, 0x47, - 0x2e, 0x45, 0x88, 0x1c, 0xec, 0xd8, 0x34, 0xf5, 0x7a, 0xb0, 0xe0, 0xc1, 0x8e, 0x63, 0x77, 0x83, - 0x4c, 0xa4, 0x3f, 0xe2, 0x13, 0xb5, 0x97, 0xa5, 0x84, 0x0c, 0x33, 0x3a, 0x11, 0x2f, 0xb9, 0x34, - 0xc0, 0x0c, 0x2b, 0x35, 0x7b, 0x60, 0xbe, 0x2d, 0xa3, 0x8f, 0xfa, 0x57, 0xb4, 0x97, 0x09, 0x7b, - 0x3e, 0xde, 0x0c, 0x8a, 0x17, 0x82, 0x7b, 0xd1, 0xe4, 0xd8, 0xfe, 0x98, 0xe6, 0x51, 0x97, 0xc1, - 0x09, 0x0f, 0xf6, 0x60, 0xc7, 0x87, 0x5d, 0xd4, 0x74, 0x8d, 0x91, 0x9d, 0xc2, 0xc1, 0xec, 0xda, - 0xef, 0xb1, 0x00, 0xde, 0xc1, 0x03, 0x78, 0xc3, 0x10, 0x51, 0xa2, 0x0a, 0xc5, 0xcf, 0x4d, 0x50, - 0x35, 0x5a, 0x3d, 0x27, 0x34, 0x7c, 0x83, 0x67, 0xf4, 0x6e, 0xd7, 0xdf, 0xeb, 0xe1, 0x77, 0xf4, - 0x68, 0x70, 0xf0, 0xac, 0x2e, 0x81, 0x19, 0xd3, 0xbe, 0x82, 0x5f, 0xe5, 0x13, 0x6a, 0x1d, 0x64, - 0xd2, 0x5e, 0x19, 0x22, 0x7f, 0x17, 0x87, 0xfc, 0xa3, 0xc4, 0xd8, 0xcd, 0x1e, 0xf8, 0x1f, 0x9d, - 0x01, 0x85, 0x0d, 0xd3, 0xf3, 0xa1, 0xf6, 0xbf, 0x65, 0x51, 0xe4, 0x6f, 0x00, 0x8b, 0xdb, 0x4e, - 0x67, 0xdf, 0x83, 0x5d, 0xbe, 0x51, 0x0e, 0xa4, 0x4e, 0x02, 0x73, 0x1c, 0x98, 0x9d, 0x26, 0x52, - 0xb2, 0x81, 0x0b, 0xec, 0x81, 0x74, 0x7c, 0xf5, 0xa2, 0xb7, 0x61, 0xba, 0x7e, 0x73, 0x1b, 0xa7, - 0x85, 0x57, 0x2f, 0xb2, 0x89, 0x1c, 0xf4, 0xc5, 0x04, 0xe8, 0x67, 0xe2, 0xa1, 0x2f, 0x09, 0x40, - 0xaf, 0x96, 0x41, 0x69, 0xdb, 0xea, 0x41, 0xfc, 0xc1, 0x2c, 0xfe, 0x60, 0xd8, 0x98, 0x84, 0x65, - 0x1f, 0x8e, 0x49, 0x2b, 0x56, 0x0f, 0x1a, 0xe1, 0x67, 0xc1, 0x44, 0x06, 0x44, 0x13, 0x99, 0x3a, - 0x39, 0x09, 0x87, 0x0c, 0x2f, 0xdb, 0xdc, 0x83, 0xc1, 0xc6, 0xb7, 0x4d, 0x8f, 0xa5, 0x77, 0x4d, - 0xdf, 0xc4, 0x60, 0xcc, 0x1b, 0xf8, 0x3f, 0xef, 0x93, 0x2d, 0x0f, 0xfa, 0x64, 0x3f, 0x57, 0x4e, - 0xd7, 0x23, 0x06, 0xcc, 0xc6, 0xb4, 0xa8, 0x0b, 0x01, 0x40, 0xc4, 0x52, 0x0c, 0x9f, 0x11, 0x30, - 0x1d, 0xd3, 0x85, 0xfe, 0x06, 0xeb, 0x05, 0x5d, 0x30, 0xf8, 0x44, 0x7c, 0x08, 0xc7, 0x6b, 0x99, - 0x7b, 0xe4, 0x6a, 0xc5, 0x0a, 0x7a, 0x47, 0x0f, 0x57, 0x1c, 0x48, 0x8f, 0xfa, 0xdf, 0xc2, 0xa4, - 0xfb, 0xdf, 0x61, 0x75, 0xcc, 0xbe, 0x19, 0xbe, 0x26, 0x0f, 0xe4, 0xca, 0xbe, 0xff, 0x80, 0xee, - 0x7e, 0xbf, 0x27, 0xec, 0x63, 0x4e, 0xfb, 0xb3, 0x7d, 0xff, 0x68, 0x7b, 0xdf, 0x94, 0x5a, 0x22, - 0xe6, 0xcb, 0x1e, 0x57, 0xb7, 0xec, 0x75, 0xe4, 0x6d, 0x72, 0x78, 0x34, 0xea, 0x39, 0xb9, 0xc3, - 0x9b, 0xe6, 0x1a, 0xe9, 0x9f, 0x98, 0x9e, 0x21, 0x7c, 0x0e, 0x3a, 0x9e, 0x3c, 0x77, 0xfb, 0x03, - 0x76, 0x6d, 0xc5, 0xa2, 0x9c, 0x37, 0xc8, 0x83, 0xf6, 0x72, 0xe1, 0x03, 0xa3, 0x44, 0x6c, 0x89, - 0xc7, 0x78, 0xd2, 0xd9, 0x54, 0xaf, 0x16, 0x3a, 0x36, 0x9a, 0x50, 0x6c, 0xf6, 0x80, 0xfd, 0x1d, - 0x7b, 0x4c, 0xa7, 0x7c, 0x68, 0xc4, 0xb4, 0x57, 0x09, 0x2f, 0xe8, 0x93, 0x6a, 0x8f, 0xd8, 0xab, - 0x4f, 0x27, 0x6f, 0x31, 0x47, 0xb1, 0xc4, 0x82, 0xa7, 0x70, 0x57, 0xb4, 0x0c, 0x8a, 0x64, 0xe1, - 0x57, 0x7b, 0xb3, 0x70, 0x13, 0x41, 0xbd, 0x11, 0x7f, 0x7c, 0x27, 0x7c, 0x4e, 0xb3, 0xe6, 0xc0, - 0x1d, 0xf3, 0xc9, 0xa7, 0x3a, 0xe6, 0xc3, 0x47, 0x60, 0x11, 0x68, 0x47, 0xa4, 0x8e, 0x19, 0x4f, - 0x27, 0xd3, 0xb4, 0xb0, 0xa1, 0x0c, 0x65, 0x8f, 0xf7, 0xf3, 0x0b, 0x60, 0x9e, 0x14, 0x4d, 0xce, - 0x17, 0x6a, 0xef, 0x91, 0xbe, 0x7f, 0x50, 0x57, 0x1b, 0x60, 0xfe, 0x32, 0x66, 0x9b, 0x84, 0x97, - 0xa3, 0x2b, 0x17, 0x37, 0x25, 0xae, 0x7b, 0x90, 0x7a, 0x06, 0xb7, 0x46, 0x73, 0xdf, 0x23, 0x19, - 0x93, 0x0d, 0x16, 0x72, 0x78, 0xa2, 0x88, 0x8d, 0x2c, 0x36, 0x49, 0x3d, 0x05, 0x8a, 0x97, 0x2c, - 0x78, 0xb9, 0xd6, 0xa5, 0xd6, 0x2d, 0x7d, 0xd2, 0x7e, 0x5d, 0xd8, 0x67, 0x92, 0x85, 0x9b, 0xf2, - 0x92, 0xad, 0x16, 0x8a, 0x79, 0x4e, 0x8e, 0x64, 0x6b, 0x0a, 0xd1, 0x80, 0x24, 0x72, 0x4f, 0x3d, - 0x0d, 0xe5, 0x5f, 0x49, 0xa1, 0x88, 0x71, 0x86, 0x33, 0x1f, 0x84, 0x2f, 0xf1, 0xac, 0x39, 0x11, - 0x40, 0x54, 0xfe, 0x44, 0xfa, 0x7c, 0xb1, 0xc8, 0x70, 0x23, 0x8a, 0xce, 0x5e, 0xf2, 0xaf, 0x93, - 0xc1, 0x6c, 0x0b, 0xfa, 0x2b, 0x16, 0xec, 0x75, 0x3d, 0xcd, 0x3d, 0xbc, 0x69, 0x74, 0x0b, 0x28, - 0x6e, 0x63, 0x62, 0xa3, 0x36, 0x27, 0x69, 0x36, 0xed, 0x35, 0x92, 0xa8, 0x1f, 0x10, 0x5d, 0x7d, - 0x0b, 0xb8, 0x9d, 0x08, 0x4c, 0x62, 0xa7, 0xe9, 0x92, 0x4b, 0x9e, 0xc2, 0x55, 0x49, 0x32, 0x98, - 0xc7, 0xdb, 0xff, 0xd0, 0x2f, 0xf7, 0xac, 0x1d, 0x9b, 0xbd, 0x5d, 0x7d, 0xec, 0x16, 0xa2, 0x3e, - 0x06, 0x14, 0x4c, 0x44, 0x8d, 0xba, 0xbb, 0x69, 0x43, 0x3b, 0x4f, 0x5c, 0x9e, 0x41, 0x32, 0xa6, - 0xb8, 0x98, 0x24, 0x52, 0xec, 0x80, 0xe7, 0x29, 0x5e, 0x4c, 0x32, 0xb2, 0xf0, 0xec, 0x11, 0xfb, - 0x9a, 0x0c, 0x4e, 0x52, 0x06, 0xce, 0x41, 0xd7, 0xb7, 0x3a, 0x66, 0x8f, 0x20, 0xf7, 0xc2, 0xdc, - 0x24, 0xa0, 0x5b, 0x03, 0x0b, 0x97, 0x58, 0xb2, 0x14, 0xc2, 0xb3, 0x43, 0x21, 0xe4, 0x18, 0x30, - 0xf8, 0x0f, 0x53, 0x5c, 0xf0, 0xc0, 0x49, 0x95, 0xa3, 0x39, 0xc5, 0x0b, 0x1e, 0x84, 0x99, 0xc8, - 0x1e, 0xe2, 0x97, 0xd0, 0xa0, 0x9a, 0x51, 0xf7, 0xf9, 0x45, 0x61, 0x6c, 0x37, 0xc1, 0x1c, 0xc6, - 0x92, 0x7c, 0x48, 0x97, 0x21, 0x12, 0x94, 0x38, 0xec, 0x77, 0xe8, 0x45, 0xf7, 0xe1, 0xb7, 0x06, - 0x4b, 0x47, 0x3b, 0x0f, 0x40, 0xf4, 0x8a, 0xed, 0xa4, 0x73, 0x71, 0x9d, 0xb4, 0x24, 0xd6, 0x49, - 0xbf, 0x49, 0x38, 0xcc, 0xe1, 0x70, 0xb6, 0x0f, 0xaf, 0x1e, 0x62, 0x01, 0xee, 0x46, 0x97, 0x9e, - 0xbd, 0x5e, 0xbc, 0x92, 0xea, 0x45, 0x75, 0xbf, 0xdf, 0xb3, 0x3a, 0x68, 0x3e, 0xf5, 0xc9, 0x89, - 0xcc, 0xa7, 0xd8, 0xfe, 0x40, 0x1e, 0xe8, 0x0f, 0x0e, 0x61, 0x49, 0xdf, 0x08, 0x8e, 0x93, 0x22, - 0x2a, 0x21, 0x5b, 0x05, 0x12, 0xc4, 0x6d, 0x20, 0x99, 0x8f, 0xda, 0x2e, 0xa8, 0x04, 0xa1, 0x10, - 0xc6, 0x58, 0xfa, 0x4c, 0x67, 0xec, 0xa6, 0x55, 0x90, 0x38, 0xce, 0xa6, 0x70, 0x24, 0x2b, 0x4f, - 0xac, 0xdd, 0xcd, 0x7e, 0x17, 0x69, 0xc7, 0x97, 0xf3, 0x93, 0x18, 0x11, 0x9e, 0x42, 0x3d, 0x4d, - 0xe5, 0xd8, 0x25, 0x8d, 0xa8, 0xc8, 0xb0, 0x1f, 0x69, 0xc3, 0xfb, 0xfd, 0xb5, 0x63, 0xc4, 0x2f, - 0x55, 0xbd, 0x09, 0x1c, 0xbf, 0x60, 0x76, 0x2e, 0xee, 0xb8, 0xce, 0x3e, 0xbe, 0xb5, 0xdd, 0xa1, - 0xd7, 0xbf, 0xaf, 0x1d, 0x33, 0x06, 0x5f, 0xa8, 0xb7, 0x06, 0xa6, 0x43, 0x61, 0x94, 0xe9, 0xb0, - 0x76, 0x8c, 0x1a, 0x0f, 0xea, 0x63, 0xc3, 0x4e, 0xa7, 0x98, 0xd8, 0xe9, 0xac, 0x1d, 0x0b, 0xba, - 0x1d, 0xb5, 0x0a, 0x4a, 0x5d, 0xeb, 0x12, 0xde, 0xaa, 0xc6, 0xb3, 0xae, 0x51, 0x41, 0x87, 0xaa, - 0xd6, 0x25, 0xb2, 0xb1, 0xbd, 0x76, 0xcc, 0x08, 0xbf, 0x54, 0x57, 0xc1, 0x2c, 0xde, 0x16, 0xc0, - 0x64, 0x4a, 0xa9, 0x02, 0x0a, 0xad, 0x1d, 0x33, 0xa2, 0x6f, 0x91, 0xf5, 0x91, 0xc7, 0xe7, 0xae, - 0xef, 0x0a, 0xb6, 0xdb, 0x73, 0xa9, 0xb6, 0xdb, 0x91, 0x2c, 0xc8, 0x86, 0xfb, 0x29, 0x50, 0xe8, - 0x60, 0x09, 0x4b, 0x54, 0xc2, 0xe4, 0x51, 0xbd, 0x03, 0xe4, 0xf7, 0x4c, 0x37, 0x98, 0x3c, 0xdf, - 0x30, 0x9a, 0xee, 0xba, 0xe9, 0x5e, 0x44, 0x08, 0xa2, 0xaf, 0x96, 0x67, 0x40, 0x01, 0x0b, 0x2e, - 0xfc, 0xa3, 0xbd, 0x2d, 0x4f, 0xcc, 0x90, 0x8a, 0x63, 0xa3, 0x61, 0xbf, 0xed, 0x04, 0x87, 0xd3, - 0x7f, 0x3d, 0x37, 0x19, 0x0b, 0xf2, 0x2a, 0xe6, 0x3a, 0x15, 0xdb, 0x7a, 0xc6, 0x3e, 0xbc, 0x07, - 0x5e, 0xa1, 0x4b, 0xa2, 0xc3, 0x5e, 0xa9, 0x67, 0x00, 0xf0, 0xe9, 0x49, 0xbd, 0x30, 0x88, 0x29, - 0x93, 0x12, 0x2d, 0x1f, 0x14, 0x46, 0x3b, 0xaa, 0xfc, 0xde, 0x18, 0xa6, 0xcb, 0xa0, 0x20, 0xe2, - 0x67, 0xe0, 0x3d, 0xcb, 0x66, 0xea, 0x1c, 0x3c, 0xa6, 0xec, 0x94, 0xd2, 0x1a, 0x35, 0x23, 0xd8, - 0xcb, 0xbe, 0x6f, 0x7a, 0x4b, 0x9e, 0xdc, 0x28, 0x41, 0x4e, 0x40, 0xeb, 0xf7, 0x5b, 0x5e, 0x74, - 0x7f, 0xb3, 0xf6, 0xb9, 0x89, 0x28, 0xcd, 0x90, 0x01, 0x47, 0x1e, 0x3a, 0xe0, 0x1c, 0x08, 0x10, - 0x94, 0x1f, 0x11, 0x20, 0xa8, 0x90, 0x6e, 0xe5, 0xf0, 0xa3, 0xac, 0xfe, 0x6c, 0xf0, 0xfa, 0x73, - 0x7b, 0x0c, 0x40, 0xc3, 0xe4, 0x32, 0x11, 0xfb, 0xe6, 0x5d, 0xa1, 0xa6, 0xb4, 0x38, 0x4d, 0xb9, - 0x6b, 0x7c, 0x46, 0xb2, 0xd7, 0x96, 0x0f, 0xe7, 0xc1, 0x55, 0x11, 0x33, 0x0d, 0x78, 0x99, 0x2a, - 0xca, 0x1f, 0x4e, 0x44, 0x51, 0xd2, 0x3b, 0x3a, 0x67, 0xad, 0x31, 0xbf, 0x2d, 0x7c, 0x6e, 0x7f, - 0x10, 0xa8, 0x50, 0x36, 0x31, 0xca, 0x72, 0x0a, 0x14, 0x49, 0x0f, 0x43, 0xa1, 0xa1, 0x4f, 0x29, - 0xbb, 0x1b, 0xb1, 0xd3, 0xfe, 0xa2, 0xbc, 0x4d, 0x41, 0x7f, 0xe8, 0xba, 0x46, 0x7b, 0xdf, 0xb5, - 0x6b, 0xb6, 0xef, 0x68, 0xff, 0x7d, 0x22, 0x8a, 0x13, 0x7a, 0xc3, 0xc9, 0xe3, 0x78, 0xc3, 0x8d, - 0xb5, 0xca, 0x11, 0xd4, 0xe0, 0x48, 0x56, 0x39, 0x62, 0x0a, 0xcf, 0x1e, 0xbf, 0x77, 0xca, 0xe0, - 0x14, 0x9d, 0x6c, 0x2d, 0xf3, 0x16, 0xa2, 0x76, 0xef, 0x24, 0x80, 0x3c, 0x19, 0x98, 0x49, 0xd4, - 0x8f, 0x1e, 0x3f, 0xf0, 0x51, 0x0a, 0x12, 0x6f, 0x0c, 0xe5, 0xa6, 0x83, 0x03, 0x1c, 0x4e, 0x04, - 0x29, 0xb1, 0x8b, 0x42, 0x53, 0xb0, 0x91, 0x3d, 0x66, 0x2f, 0x96, 0x41, 0x91, 0xc4, 0x48, 0xd0, - 0x36, 0x33, 0x71, 0x98, 0xe0, 0xef, 0x67, 0x11, 0xd8, 0x91, 0x23, 0xdc, 0x64, 0x16, 0x3f, 0x22, - 0xcd, 0x5e, 0xdc, 0x50, 0x56, 0xa6, 0xe0, 0x42, 0x28, 0x81, 0xb9, 0x16, 0xf4, 0x2b, 0xa6, 0xeb, - 0x5a, 0xe6, 0xce, 0xa4, 0x3c, 0xbe, 0x45, 0xbd, 0x87, 0xb5, 0xef, 0xe4, 0x44, 0xcf, 0xb2, 0x87, - 0x0b, 0xe1, 0x01, 0xab, 0x31, 0x51, 0xc0, 0x5f, 0x2f, 0x74, 0x5e, 0x7d, 0x14, 0xb5, 0x29, 0x78, - 0x6c, 0x4b, 0x60, 0x26, 0x88, 0x83, 0x71, 0x0b, 0x17, 0x1b, 0x65, 0xd7, 0xdf, 0x0b, 0x8e, 0xc1, - 0xe0, 0xff, 0x07, 0xe3, 0x2f, 0x68, 0xaf, 0x48, 0xe9, 0x28, 0x9f, 0x1c, 0xc4, 0x23, 0x5d, 0x1b, - 0x4b, 0xe3, 0x0e, 0x7f, 0x54, 0x61, 0x3b, 0x3e, 0x34, 0x43, 0x97, 0x23, 0xeb, 0xa6, 0x0f, 0xef, - 0xd7, 0xbe, 0x28, 0x83, 0x99, 0x16, 0xf4, 0xd1, 0x78, 0x8b, 0xd8, 0x3f, 0xb4, 0x86, 0xab, 0xcc, - 0x8a, 0x07, 0x3d, 0x5b, 0xab, 0xde, 0x0d, 0x66, 0xfb, 0xae, 0xd3, 0x81, 0x9e, 0x47, 0x57, 0x2f, - 0x58, 0x47, 0xb5, 0x61, 0xa3, 0x3f, 0x66, 0x6d, 0x69, 0x23, 0xf8, 0xc6, 0x88, 0x3e, 0x4f, 0x6b, - 0x06, 0x10, 0x4a, 0xb4, 0x82, 0xd3, 0x36, 0x03, 0x92, 0x0a, 0xcf, 0x1e, 0xe8, 0xdf, 0x97, 0xc1, - 0x7c, 0x0b, 0xfa, 0xa1, 0x14, 0x53, 0x6c, 0x72, 0xc4, 0xc3, 0xcb, 0x41, 0x29, 0x1f, 0x0e, 0xca, - 0x77, 0x0a, 0x5f, 0xbc, 0xcb, 0x4b, 0x33, 0x24, 0x36, 0x11, 0x3c, 0xdf, 0x22, 0x74, 0xdf, 0xae, - 0x18, 0x07, 0x53, 0x38, 0xbe, 0xf6, 0x08, 0x30, 0x8b, 0x79, 0xc1, 0x0d, 0xf6, 0x27, 0xf2, 0x51, - 0xe3, 0xfd, 0x52, 0x46, 0x8d, 0xf7, 0x4e, 0x50, 0xd8, 0x33, 0xdd, 0x8b, 0xc1, 0xe1, 0xdb, 0x47, - 0x8a, 0xad, 0x7e, 0x79, 0x06, 0xf9, 0x6a, 0xb8, 0x9f, 0x66, 0x21, 0x9d, 0x9f, 0xe6, 0xeb, 0xa5, - 0x54, 0x23, 0x21, 0x99, 0x3b, 0x4c, 0xb0, 0xc9, 0xa7, 0x18, 0x37, 0x13, 0xca, 0xce, 0x5e, 0x39, - 0x5e, 0x28, 0x83, 0x12, 0x1a, 0xb7, 0xb1, 0x3d, 0x7e, 0xfe, 0xf0, 0xea, 0x30, 0xdc, 0xd0, 0x4f, - 0xd9, 0x03, 0x07, 0x12, 0x99, 0x9c, 0x79, 0x9f, 0xa2, 0x07, 0x4e, 0x2a, 0x3c, 0x7b, 0x3c, 0xde, - 0x4d, 0xf0, 0xc0, 0xed, 0x41, 0x7b, 0x83, 0x0c, 0xe4, 0x55, 0xe8, 0x4f, 0xdb, 0x8a, 0x7c, 0xbb, - 0x70, 0x78, 0x51, 0x4e, 0x60, 0x98, 0xe7, 0xa5, 0x55, 0x38, 0x99, 0x06, 0x24, 0x16, 0x57, 0x54, - 0x88, 0x81, 0xec, 0x51, 0x7b, 0x3f, 0x41, 0x8d, 0x6c, 0x2e, 0xfc, 0xc8, 0x04, 0x7a, 0xd5, 0xe9, - 0x2e, 0x7c, 0x04, 0x02, 0xc4, 0x34, 0x8e, 0xaa, 0xbd, 0x0d, 0x2b, 0x3c, 0x7b, 0xe4, 0x5e, 0x2a, - 0xe3, 0x4b, 0xcc, 0x2a, 0xbb, 0xb0, 0x73, 0x11, 0x76, 0xd9, 0xcb, 0xb2, 0xc7, 0x85, 0xee, 0x34, - 0x98, 0xe9, 0x10, 0x6a, 0x18, 0xbc, 0x92, 0x11, 0x3c, 0xf2, 0x37, 0x0b, 0x25, 0xde, 0x9d, 0xc5, - 0x77, 0x44, 0xe4, 0xf3, 0x89, 0xe0, 0x22, 0x76, 0xe1, 0x95, 0x40, 0xf1, 0x53, 0x30, 0x5b, 0xc8, - 0x2c, 0xa3, 0xd6, 0x71, 0x6c, 0xed, 0xbf, 0x1e, 0x1e, 0x96, 0x6b, 0xc1, 0xac, 0xd5, 0x71, 0x6c, - 0x1c, 0x02, 0x2e, 0x38, 0x04, 0x14, 0x26, 0x04, 0x6f, 0xf5, 0x3d, 0xe7, 0x3e, 0x8b, 0xee, 0x9a, - 0x47, 0x09, 0xe3, 0x1a, 0x13, 0x88, 0xf5, 0xa3, 0x32, 0x26, 0x86, 0x94, 0x9d, 0x3d, 0x64, 0x9f, - 0x8a, 0xbc, 0xdb, 0x48, 0x57, 0xf8, 0x80, 0x58, 0x05, 0x1e, 0x67, 0x38, 0x63, 0x6b, 0x71, 0x24, - 0xc3, 0x59, 0x02, 0x03, 0x53, 0xb8, 0x89, 0x30, 0xc2, 0x31, 0xf3, 0x35, 0xe0, 0x43, 0xa0, 0x33, - 0x39, 0xf3, 0x70, 0x4c, 0x74, 0x8e, 0xc6, 0x44, 0xfc, 0x08, 0x0d, 0x4f, 0x4f, 0x2d, 0x1e, 0xed, - 0xbf, 0x4d, 0x02, 0x9c, 0xdb, 0xc7, 0xf1, 0x57, 0x20, 0xde, 0x0a, 0xda, 0x5b, 0x25, 0xd1, 0x10, - 0x28, 0x07, 0x24, 0x88, 0xa8, 0x4c, 0x04, 0xc1, 0x37, 0x09, 0xc5, 0x26, 0x11, 0x29, 0x3f, 0x7b, - 0x00, 0x5f, 0x20, 0x83, 0x45, 0xec, 0x23, 0xd0, 0x83, 0xa6, 0x4b, 0x3a, 0xca, 0x89, 0x38, 0xca, - 0xbf, 0x5b, 0x38, 0xc0, 0x0f, 0x2f, 0x87, 0x88, 0x8f, 0x89, 0x40, 0x21, 0x16, 0xdd, 0x47, 0x90, - 0x85, 0xa9, 0x6c, 0xa3, 0x28, 0x21, 0x0b, 0x54, 0xc5, 0x27, 0x83, 0x47, 0x4a, 0x8f, 0x5c, 0x5e, - 0x18, 0x41, 0x63, 0x9b, 0xb2, 0x47, 0xae, 0x08, 0x13, 0xd9, 0x63, 0xf2, 0x86, 0xc7, 0xd0, 0x05, - 0xe7, 0xb6, 0x79, 0xa1, 0x07, 0xb5, 0x57, 0xe5, 0xc3, 0x13, 0x6d, 0xbf, 0x3f, 0x11, 0x0f, 0xcc, - 0x43, 0x5c, 0x46, 0xa5, 0x82, 0xbc, 0xeb, 0x5c, 0x26, 0x4b, 0x5b, 0x0b, 0x06, 0xfe, 0x4f, 0xe2, - 0x59, 0xf6, 0xf6, 0xf7, 0x6c, 0x72, 0x32, 0x74, 0xc1, 0x08, 0x1e, 0xd5, 0xeb, 0xc1, 0xc2, 0x65, - 0xcb, 0xdf, 0x5d, 0x83, 0x66, 0x17, 0xba, 0x86, 0x73, 0x19, 0x7b, 0xcc, 0x95, 0x0c, 0x3e, 0x91, - 0xf7, 0x5f, 0x11, 0xb0, 0x2f, 0x91, 0x50, 0xa6, 0x73, 0xfc, 0x2d, 0x8d, 0xe5, 0x19, 0xcf, 0x55, - 0xf6, 0x0a, 0xf3, 0x01, 0x19, 0xcc, 0x1a, 0xce, 0x65, 0xaa, 0x24, 0xff, 0xcf, 0xd1, 0xea, 0x48, - 0xea, 0x89, 0x1e, 0x96, 0x5c, 0xc8, 0xfe, 0xd4, 0x27, 0x7a, 0x89, 0xc5, 0x4f, 0xe5, 0xe4, 0xd2, - 0xbc, 0xe1, 0x5c, 0x6e, 0x41, 0x9f, 0xb4, 0x08, 0x6d, 0x6b, 0x42, 0x4e, 0xd6, 0x96, 0x47, 0x08, - 0xd2, 0x79, 0x78, 0xf8, 0x9c, 0x76, 0x17, 0x21, 0x14, 0x50, 0xc8, 0xe2, 0xb4, 0x77, 0x11, 0x46, - 0x72, 0x30, 0x85, 0x18, 0x29, 0x32, 0x98, 0x33, 0x9c, 0xcb, 0x68, 0x68, 0x58, 0xb1, 0x7a, 0xbd, - 0xc9, 0x8c, 0x90, 0x69, 0x8d, 0xff, 0x40, 0x0c, 0x01, 0x17, 0x53, 0x37, 0xfe, 0x47, 0x30, 0x90, - 0x3d, 0x0c, 0xcf, 0x25, 0x8d, 0x25, 0x18, 0xa1, 0xed, 0xc9, 0xe0, 0x30, 0x6e, 0x83, 0x08, 0xd9, - 0x38, 0xb2, 0x06, 0x11, 0xc7, 0xc1, 0x54, 0x76, 0x4e, 0x16, 0x2b, 0x78, 0x98, 0x9f, 0x6c, 0x9b, - 0x78, 0x6f, 0x3a, 0xd7, 0x44, 0x3a, 0xec, 0x72, 0x8c, 0x4c, 0x04, 0x8d, 0x14, 0x2e, 0x88, 0x02, - 0x3c, 0x64, 0x8f, 0xc7, 0xc7, 0x65, 0x30, 0x4f, 0x58, 0x78, 0x80, 0x58, 0x01, 0x63, 0x35, 0x2a, - 0xb6, 0x06, 0x47, 0xd3, 0xa8, 0x12, 0x38, 0x98, 0xca, 0x7d, 0xfe, 0xc8, 0x8e, 0x1b, 0xe3, 0xf8, - 0x78, 0x1c, 0x82, 0x63, 0x1b, 0x63, 0x13, 0x3c, 0x42, 0x3e, 0x8e, 0x31, 0x76, 0x44, 0xc7, 0xc8, - 0x9f, 0x1b, 0xb6, 0xa2, 0x49, 0x62, 0x70, 0x88, 0xa6, 0x30, 0x41, 0x18, 0xc6, 0x6c, 0x0a, 0x47, - 0x84, 0xc4, 0xd7, 0x65, 0x00, 0x08, 0x03, 0xeb, 0xce, 0x25, 0x7c, 0x91, 0xe6, 0x04, 0xba, 0xb3, - 0x41, 0xb7, 0x7a, 0x79, 0x84, 0x5b, 0x7d, 0xca, 0x10, 0x2e, 0x69, 0x57, 0x02, 0x19, 0x29, 0xa3, - 0x4a, 0x4e, 0x7d, 0x25, 0x30, 0xb9, 0xfc, 0xec, 0x31, 0xfe, 0x2a, 0xb1, 0xe6, 0xa2, 0x03, 0xa6, - 0x3f, 0x3f, 0x11, 0x94, 0x99, 0xd9, 0xbf, 0xcc, 0xcf, 0xfe, 0x0f, 0x81, 0xed, 0xb8, 0x36, 0xe2, - 0xa8, 0x83, 0xa3, 0xd9, 0xdb, 0x88, 0x47, 0x77, 0x40, 0xf4, 0x47, 0xf2, 0xe0, 0x38, 0xed, 0x44, - 0xbe, 0x1f, 0x20, 0x4e, 0x79, 0x0e, 0x8f, 0xeb, 0x24, 0x47, 0xa0, 0x3c, 0xa9, 0x05, 0xa9, 0x34, - 0x4b, 0x99, 0x02, 0xec, 0x4d, 0x65, 0x75, 0xa3, 0xa8, 0xdf, 0xdf, 0x37, 0xed, 0xae, 0x78, 0xb8, - 0xdf, 0x11, 0xc0, 0x07, 0x6b, 0x8d, 0x32, 0xbf, 0xd6, 0x38, 0x64, 0x65, 0x32, 0xf5, 0xce, 0x35, - 0x16, 0x19, 0x61, 0x77, 0xea, 0x3b, 0xd7, 0xf1, 0x65, 0x67, 0x8f, 0xd2, 0x7b, 0x65, 0x90, 0x6f, - 0x39, 0xae, 0xaf, 0x3d, 0x2f, 0x4d, 0xeb, 0x24, 0x92, 0x8f, 0x40, 0x0a, 0x9e, 0xd5, 0x0a, 0xc8, - 0xa3, 0xca, 0xd1, 0x19, 0xc3, 0x2d, 0xc9, 0x47, 0x9d, 0x4d, 0xdf, 0xc4, 0x5e, 0xdd, 0xa8, 0xfc, - 0xa5, 0xf6, 0x95, 0x3e, 0x34, 0xf0, 0xc7, 0x69, 0xe3, 0xe9, 0x10, 0xf9, 0xb5, 0xe2, 0x0f, 0x60, - 0x64, 0x16, 0x4f, 0x27, 0xb6, 0xe4, 0xec, 0x71, 0x7b, 0xed, 0x71, 0xea, 0xdb, 0xba, 0x62, 0xf5, - 0xa0, 0xf6, 0x3c, 0xe2, 0x32, 0xd2, 0x30, 0xf7, 0xa0, 0xf8, 0x91, 0x98, 0x44, 0xd7, 0x56, 0x1c, - 0x5f, 0x56, 0x8e, 0xe2, 0xcb, 0xa6, 0x6d, 0x50, 0xe4, 0x00, 0x3a, 0x61, 0x69, 0xda, 0x0d, 0x2a, - 0xa1, 0xec, 0xa9, 0xc4, 0xe9, 0x3c, 0xd1, 0x82, 0x3e, 0x31, 0x2a, 0x9b, 0xc1, 0x15, 0x49, 0x4f, - 0x9f, 0x48, 0xc4, 0xce, 0xf0, 0x42, 0x1d, 0x79, 0xe0, 0x06, 0xa6, 0x0f, 0xb0, 0xe0, 0xac, 0xf3, - 0xe0, 0xfc, 0x50, 0xbc, 0x80, 0x78, 0x26, 0x27, 0x02, 0xd3, 0xdb, 0x43, 0x98, 0x36, 0x38, 0x98, - 0xee, 0x18, 0x93, 0x8b, 0xec, 0x01, 0xfb, 0xa9, 0x02, 0x38, 0x4e, 0x26, 0xfd, 0x65, 0xbb, 0x4b, - 0x23, 0xac, 0xbe, 0x59, 0x3a, 0xe2, 0xcd, 0xb6, 0x83, 0x21, 0x58, 0xb9, 0x58, 0xce, 0x85, 0x81, - 0x58, 0xce, 0xea, 0x32, 0x09, 0xe7, 0x8a, 0x3a, 0x51, 0xbc, 0xd3, 0x36, 0x2a, 0xcc, 0x04, 0x96, - 0x3d, 0xee, 0x72, 0xc3, 0xef, 0xf8, 0x7b, 0x44, 0x67, 0xc4, 0xef, 0x11, 0xfd, 0xdd, 0x74, 0xeb, - 0x76, 0xb8, 0xe8, 0x01, 0x81, 0x67, 0x6c, 0x3b, 0xa5, 0x58, 0xd1, 0x13, 0xe0, 0xee, 0x3f, 0x86, - 0x3b, 0x59, 0x14, 0x41, 0x64, 0x4c, 0x77, 0x32, 0x4c, 0xe0, 0x28, 0xdd, 0xc9, 0x46, 0x31, 0x90, - 0x3d, 0x8e, 0xbf, 0x5b, 0xa0, 0xbb, 0xf9, 0xb8, 0xdd, 0x68, 0x7f, 0x22, 0x65, 0x3e, 0x4a, 0x7f, - 0x37, 0x97, 0xca, 0xff, 0x19, 0xf3, 0x95, 0x3c, 0x4c, 0xa7, 0xf1, 0x68, 0x4e, 0x22, 0x37, 0x85, - 0x75, 0x23, 0x09, 0xfb, 0xa2, 0x9f, 0xb7, 0xba, 0xfe, 0xee, 0x84, 0x4e, 0x74, 0x5c, 0x46, 0xb4, - 0x68, 0xbc, 0x7a, 0xf2, 0xa0, 0xfd, 0x4b, 0x2e, 0x55, 0x08, 0xa9, 0x50, 0x24, 0x98, 0xad, 0x18, - 0x11, 0xa7, 0x08, 0xfc, 0x94, 0x48, 0x6f, 0x8a, 0x1a, 0x7d, 0xce, 0xea, 0x42, 0xe7, 0x01, 0xa8, - 0xd1, 0x98, 0xaf, 0xc9, 0x69, 0x74, 0x12, 0xb9, 0xff, 0xa0, 0x1a, 0x1d, 0x8a, 0x64, 0x42, 0x1a, - 0x9d, 0x48, 0x2f, 0x7b, 0x19, 0xbf, 0x62, 0x9e, 0x4e, 0xa4, 0xea, 0x96, 0x7d, 0x51, 0xfb, 0xc7, - 0x22, 0x50, 0x82, 0x38, 0xc2, 0xfe, 0x2e, 0x8d, 0x05, 0xf3, 0x61, 0xe1, 0xbb, 0x51, 0xc6, 0x88, - 0xf7, 0xc2, 0x87, 0x93, 0x2a, 0x1c, 0x08, 0x27, 0x55, 0x06, 0x0b, 0x96, 0xed, 0x43, 0xd7, 0x36, - 0x7b, 0x2b, 0x3d, 0x73, 0xc7, 0x3b, 0x3d, 0x33, 0xf4, 0xf2, 0xba, 0x1a, 0x93, 0xc7, 0xe0, 0xbf, - 0x60, 0x2f, 0x10, 0x2d, 0xf1, 0x17, 0x88, 0xc6, 0x44, 0xbf, 0x9a, 0x8d, 0x8f, 0x7e, 0x15, 0x46, - 0xb7, 0x02, 0xa3, 0x83, 0x63, 0x8b, 0xda, 0xc6, 0x29, 0xc3, 0xfd, 0xdd, 0x22, 0x18, 0x85, 0x2d, - 0x0c, 0xfd, 0xf8, 0x6a, 0x39, 0xd5, 0xea, 0x1e, 0x52, 0x84, 0xa5, 0x41, 0x25, 0x48, 0x6d, 0xa1, - 0xb2, 0x95, 0x97, 0x07, 0x2a, 0x1f, 0x9a, 0x3c, 0x79, 0x01, 0x93, 0x87, 0x55, 0xaa, 0x82, 0xe8, - 0x9d, 0xae, 0xe2, 0x8b, 0x85, 0x22, 0xb5, 0x9d, 0xc2, 0x69, 0xa4, 0x02, 0x38, 0x11, 0x44, 0xbb, - 0xed, 0xf7, 0xa1, 0xe9, 0x9a, 0x76, 0x07, 0x6a, 0x9f, 0x92, 0x26, 0x61, 0xf6, 0xae, 0x80, 0x92, - 0xd5, 0x71, 0xec, 0x96, 0xf5, 0xcc, 0xe0, 0x72, 0xb9, 0xe4, 0x20, 0xeb, 0x58, 0x22, 0x35, 0xfa, - 0x85, 0x11, 0x7e, 0xab, 0xd6, 0xc0, 0x6c, 0xc7, 0x74, 0xbb, 0x24, 0x08, 0x5f, 0x61, 0xe0, 0x22, - 0xa7, 0x58, 0x42, 0x95, 0xe0, 0x13, 0x23, 0xfa, 0x5a, 0x6d, 0xf2, 0x42, 0x2c, 0x0e, 0x44, 0xf3, - 0x88, 0x25, 0x56, 0x8d, 0x3e, 0xe2, 0x64, 0x8e, 0xa4, 0xe3, 0xc2, 0x9e, 0x49, 0x2e, 0x1d, 0x9f, - 0x21, 0x77, 0x44, 0x87, 0x09, 0x69, 0x97, 0x07, 0x70, 0x51, 0x07, 0xd0, 0x98, 0xf6, 0xf2, 0x80, - 0x10, 0x17, 0xd9, 0x6b, 0xe6, 0xbb, 0x8a, 0x60, 0x81, 0xf4, 0x6a, 0x54, 0x9c, 0xda, 0x0b, 0x64, - 0x50, 0x6c, 0x41, 0xff, 0x1e, 0x78, 0x45, 0x6b, 0x1d, 0x7e, 0x4c, 0x56, 0x80, 0x7c, 0x31, 0x0c, - 0x38, 0x88, 0xfe, 0xa6, 0xdd, 0xb7, 0x0f, 0xf8, 0x5a, 0x22, 0x3c, 0x4d, 0x7b, 0xdf, 0x3e, 0xb9, - 0xf8, 0xec, 0xf1, 0xf9, 0x69, 0x19, 0xc8, 0xe5, 0x6e, 0x57, 0xeb, 0x1c, 0x1e, 0x8a, 0xeb, 0xc0, - 0x5c, 0xd0, 0x66, 0xa2, 0x18, 0x90, 0x6c, 0x52, 0xda, 0x45, 0xd0, 0x50, 0x36, 0xe5, 0xee, 0xd4, - 0x77, 0x15, 0x12, 0xca, 0xce, 0x1e, 0x94, 0x2f, 0xcd, 0xd0, 0x46, 0xb3, 0xec, 0x38, 0x17, 0xf1, - 0x51, 0x99, 0x5f, 0x96, 0x41, 0x61, 0x05, 0xfa, 0x9d, 0x5d, 0xcd, 0x9b, 0x48, 0x9b, 0x19, 0xb8, - 0xf7, 0x7c, 0x44, 0x50, 0xce, 0xb4, 0xd1, 0x9f, 0x03, 0xb6, 0x97, 0x30, 0xcb, 0xd3, 0x8e, 0xfe, - 0x9c, 0x58, 0xfa, 0x14, 0x0e, 0xc1, 0xe5, 0xc1, 0x62, 0xb8, 0x02, 0x46, 0x30, 0x7b, 0x47, 0xee, - 0x01, 0xb7, 0x1e, 0x3a, 0xc2, 0x6e, 0xd6, 0xfe, 0x30, 0x5d, 0x88, 0xb5, 0x50, 0xe6, 0x7c, 0xcd, - 0x33, 0x5e, 0x98, 0x4c, 0x11, 0x7c, 0x4d, 0x8c, 0xc1, 0x29, 0xac, 0x00, 0xc8, 0xa0, 0x84, 0x19, - 0xaa, 0x5a, 0x97, 0xb0, 0xeb, 0x21, 0xb7, 0x50, 0xf9, 0xac, 0x89, 0x2c, 0x54, 0xde, 0xc1, 0x2f, - 0x54, 0x0a, 0x46, 0x4c, 0x0e, 0xd6, 0x29, 0x53, 0xfa, 0xe2, 0xa0, 0xef, 0x27, 0xbe, 0x4c, 0x99, - 0xc2, 0x17, 0x67, 0x44, 0xf9, 0xd9, 0x23, 0xfa, 0xc6, 0xff, 0x4c, 0x3b, 0xeb, 0x60, 0x43, 0x56, - 0xfb, 0x1f, 0x27, 0x40, 0xfe, 0x1c, 0xfa, 0xf3, 0x0f, 0xd1, 0x8d, 0x5a, 0x2f, 0x9b, 0x40, 0x70, - 0x87, 0x27, 0x83, 0x3c, 0xa2, 0x4f, 0xa7, 0x3d, 0x37, 0x89, 0xed, 0x0e, 0x23, 0x46, 0x0c, 0xfc, - 0x9d, 0x7a, 0x0a, 0x14, 0x3d, 0x67, 0xdf, 0xed, 0x20, 0xf3, 0x1b, 0x69, 0x0c, 0x7d, 0x4a, 0x1b, - 0xd4, 0x94, 0x23, 0xbd, 0x34, 0x39, 0x97, 0x53, 0xe6, 0x82, 0x25, 0x99, 0xbb, 0x60, 0x29, 0xc5, - 0xfe, 0x83, 0x00, 0x6f, 0xd9, 0x6b, 0xc4, 0x9f, 0xe0, 0xbb, 0x06, 0xbb, 0x93, 0x82, 0x3d, 0x46, - 0x2c, 0x87, 0x55, 0x87, 0xb4, 0x0e, 0xe3, 0xbc, 0x68, 0xc3, 0x38, 0xf2, 0x53, 0x75, 0x18, 0x17, - 0xe0, 0x61, 0x2a, 0xa7, 0xdc, 0x8b, 0xd4, 0xc9, 0xf5, 0xde, 0x49, 0xa2, 0x9b, 0xe7, 0x94, 0xfe, - 0x50, 0xe8, 0x4c, 0xd0, 0xf9, 0x75, 0x6c, 0x74, 0x8e, 0xc8, 0xfd, 0xf5, 0x37, 0x64, 0x1c, 0x49, - 0x33, 0x30, 0x82, 0xc4, 0x2f, 0x4a, 0x4a, 0x0d, 0x11, 0x1a, 0x83, 0xb9, 0x38, 0xd2, 0x0b, 0xe3, - 0x87, 0x16, 0xe7, 0x45, 0xc7, 0xf0, 0x3f, 0xed, 0xd0, 0xe2, 0xa2, 0x8c, 0x64, 0x0f, 0xe4, 0x2f, - 0x91, 0x8b, 0xc9, 0xca, 0x1d, 0xdf, 0xba, 0x34, 0xe1, 0x96, 0xc6, 0x0f, 0x2f, 0x29, 0xa3, 0x09, - 0x1f, 0x90, 0x10, 0xe1, 0x70, 0xda, 0xd1, 0x84, 0xc5, 0xd8, 0xc8, 0x1e, 0xa6, 0x9f, 0x04, 0x48, - 0x7a, 0x74, 0x6d, 0xe7, 0x0d, 0x32, 0x90, 0x5b, 0xd0, 0xd7, 0xe0, 0xe1, 0xd1, 0x3a, 0x0b, 0xe6, - 0x99, 0xa5, 0x83, 0xe0, 0xc2, 0x1b, 0x2e, 0x2d, 0xed, 0x41, 0xf9, 0x50, 0x64, 0xec, 0xa2, 0xcb, - 0xb4, 0x0f, 0xca, 0x8b, 0x30, 0x31, 0x85, 0x83, 0xf2, 0x74, 0xd9, 0xe7, 0xfb, 0x05, 0xa8, 0x49, - 0xad, 0x00, 0x1d, 0x0a, 0xa8, 0xa3, 0x58, 0x0a, 0x7a, 0x7b, 0x64, 0x6c, 0x4c, 0x09, 0xab, 0x0f, - 0xb3, 0x58, 0x35, 0x79, 0xac, 0x6e, 0x13, 0x11, 0x93, 0x98, 0xf1, 0x21, 0x34, 0xc1, 0x7f, 0x67, - 0x08, 0x97, 0xc1, 0xc1, 0xf5, 0xe4, 0xb1, 0xf9, 0xc8, 0x1e, 0xb1, 0x5f, 0x20, 0xe3, 0x56, 0x8b, - 0xcc, 0xad, 0x26, 0x33, 0x6e, 0xd1, 0x69, 0x9b, 0xcc, 0x4d, 0xdb, 0x52, 0x1e, 0xac, 0x88, 0xfc, - 0x85, 0x03, 0xe6, 0x46, 0x41, 0x94, 0x9f, 0xf0, 0xc1, 0x8a, 0x91, 0x1c, 0x64, 0x0f, 0xce, 0xb7, - 0x64, 0x00, 0x56, 0x5d, 0x67, 0xbf, 0xdf, 0x74, 0xbb, 0xd0, 0xd5, 0xfe, 0x2c, 0x9a, 0xa9, 0xfd, - 0xcc, 0x04, 0x66, 0x6a, 0x1b, 0x00, 0xec, 0x84, 0xc4, 0xa9, 0x86, 0x3f, 0x46, 0x6c, 0x5e, 0x16, - 0x31, 0x65, 0x30, 0x34, 0xf8, 0xbb, 0x85, 0x9f, 0xca, 0x63, 0x9c, 0xd4, 0x67, 0x45, 0xe4, 0x26, - 0x39, 0x53, 0x7b, 0x77, 0x88, 0x75, 0x9b, 0xc3, 0xfa, 0x29, 0x87, 0xe0, 0x24, 0x7b, 0xcc, 0xff, - 0x7e, 0x06, 0xcc, 0x91, 0x7d, 0x59, 0x22, 0xd3, 0xbf, 0x8e, 0x40, 0xff, 0xf9, 0x09, 0x80, 0xbe, - 0x09, 0xe6, 0x9d, 0x88, 0x3a, 0xe9, 0x53, 0xd9, 0x95, 0xb2, 0x44, 0xd8, 0x19, 0xbe, 0x0c, 0x8e, - 0x8c, 0xf6, 0x09, 0x16, 0x79, 0x83, 0x47, 0xfe, 0x8e, 0x04, 0x79, 0x33, 0x14, 0x27, 0x09, 0xfd, - 0x7b, 0x42, 0xe8, 0x37, 0x39, 0xe8, 0xcb, 0x87, 0x61, 0x65, 0x0a, 0xf7, 0x2a, 0xc8, 0x20, 0x8f, - 0x8f, 0x41, 0xbe, 0x25, 0xc3, 0x85, 0x98, 0xd3, 0x60, 0x06, 0x37, 0xd9, 0x70, 0x82, 0x18, 0x3c, - 0xa2, 0x37, 0xe6, 0xb6, 0x0f, 0xdd, 0x70, 0x89, 0x3d, 0x78, 0x44, 0x3c, 0x04, 0xee, 0xe7, 0xde, - 0xe9, 0x22, 0xd9, 0x71, 0x0e, 0x13, 0xc6, 0x9e, 0x3d, 0xb2, 0x12, 0x9f, 0xd8, 0xc1, 0xc8, 0x71, - 0x66, 0x8f, 0x23, 0x18, 0xc9, 0x1e, 0xf8, 0x2f, 0xe7, 0xc1, 0x69, 0xb2, 0xfc, 0xb7, 0xe2, 0x3a, - 0x7b, 0x03, 0xd7, 0x98, 0x59, 0x87, 0xd7, 0x85, 0x1b, 0xc0, 0xa2, 0xcf, 0x39, 0xde, 0x53, 0x9d, - 0x18, 0x48, 0xd5, 0x7e, 0x8f, 0x75, 0x9e, 0x79, 0x1a, 0x8f, 0xe4, 0x72, 0x82, 0x00, 0xe3, 0x78, - 0x4f, 0xbd, 0xa3, 0x22, 0xc8, 0x28, 0xb3, 0x9a, 0x28, 0x8f, 0xb5, 0xb8, 0x1c, 0xea, 0x54, 0x41, - 0x44, 0xa7, 0x3e, 0x18, 0xea, 0xd4, 0x7f, 0xe2, 0x74, 0x6a, 0xf5, 0xf0, 0x22, 0x99, 0xc2, 0x12, - 0xd3, 0x22, 0x28, 0xae, 0x58, 0x3d, 0x1f, 0xba, 0xda, 0x57, 0xe9, 0x3c, 0xea, 0x55, 0x19, 0x76, - 0x2f, 0x55, 0x50, 0xdc, 0xc6, 0xa5, 0x51, 0x83, 0xec, 0x66, 0x31, 0x6c, 0x08, 0x87, 0x06, 0xfd, - 0x36, 0x6d, 0x90, 0xbf, 0x01, 0x32, 0x13, 0x9b, 0x80, 0xa5, 0x08, 0xf2, 0x37, 0x9a, 0x85, 0xa9, - 0xdc, 0x6f, 0x55, 0x34, 0xe0, 0x1e, 0x1a, 0x41, 0x2e, 0x66, 0x87, 0xb0, 0x02, 0x64, 0xab, 0xeb, - 0xe1, 0xa6, 0x37, 0x6b, 0xa0, 0xbf, 0x69, 0x5d, 0x8e, 0x06, 0x45, 0x45, 0x58, 0x9e, 0xb6, 0xcb, - 0x91, 0x10, 0x17, 0xd9, 0x63, 0xf6, 0x5d, 0xec, 0x6f, 0xda, 0xef, 0x99, 0x1d, 0x88, 0xb8, 0xcf, - 0x0c, 0xb5, 0x45, 0x20, 0x59, 0xc1, 0x88, 0x2f, 0x59, 0x6c, 0x3b, 0x2d, 0x1c, 0xa2, 0x9d, 0x8e, - 0xbb, 0x1a, 0x19, 0xca, 0x1c, 0x57, 0xfc, 0xc8, 0x56, 0x23, 0x13, 0xd9, 0x98, 0xc2, 0xed, 0xa5, - 0xc1, 0x79, 0xdc, 0xa9, 0xb6, 0xd6, 0x71, 0xf7, 0x6a, 0xa8, 0xb0, 0x26, 0x76, 0xf6, 0x76, 0x9c, - 0xbd, 0x9a, 0x78, 0x1e, 0xa6, 0x80, 0xd6, 0x22, 0x45, 0xeb, 0x0b, 0x74, 0x18, 0xcd, 0x78, 0xbb, - 0xd4, 0x73, 0x5c, 0x3f, 0xdd, 0x76, 0x29, 0xe2, 0xce, 0xc0, 0xdf, 0xa5, 0x3d, 0xbf, 0xc5, 0x1f, - 0xcf, 0x9e, 0xd4, 0xf0, 0x99, 0xe2, 0xfc, 0xd6, 0x28, 0x06, 0xb2, 0x87, 0xf7, 0xad, 0x47, 0x34, - 0x78, 0x8e, 0xdb, 0x1c, 0x69, 0x1b, 0x98, 0xd8, 0xd0, 0x39, 0x4e, 0x73, 0x8c, 0xe7, 0x21, 0x7b, - 0xbc, 0xfe, 0x8e, 0x19, 0x38, 0xdf, 0x34, 0xc5, 0x81, 0x33, 0x68, 0x99, 0x85, 0x31, 0x5b, 0xe6, - 0xb8, 0xbb, 0x0b, 0x54, 0xd6, 0x93, 0x1b, 0x30, 0xc7, 0xd9, 0x5d, 0x48, 0x60, 0x22, 0x7b, 0xc4, - 0xdf, 0x2c, 0x83, 0x42, 0x6b, 0xfa, 0xe3, 0xe5, 0xb8, 0x73, 0x11, 0x2c, 0xab, 0xd6, 0xc4, 0x86, - 0xcb, 0x71, 0xe6, 0x22, 0xb1, 0x2c, 0x4c, 0x21, 0x7e, 0xff, 0x71, 0x30, 0x8f, 0x27, 0xdc, 0xc1, - 0x6e, 0xeb, 0xdf, 0xd1, 0x51, 0xf3, 0xf5, 0x19, 0xb6, 0xd5, 0xbb, 0x41, 0x29, 0xd8, 0x1d, 0xa2, - 0x23, 0xe7, 0x92, 0x58, 0xfb, 0x0c, 0xb8, 0x34, 0xc2, 0xef, 0x0f, 0xe5, 0x13, 0x31, 0xf1, 0x9d, - 0xc0, 0x71, 0x7d, 0x22, 0x8e, 0x74, 0x37, 0xf0, 0x77, 0xa3, 0x11, 0xf5, 0xbf, 0x66, 0x87, 0xf9, - 0xe0, 0x2e, 0x61, 0x7e, 0xc8, 0x2e, 0xe1, 0xa7, 0x58, 0x2c, 0x5b, 0x3c, 0x96, 0x77, 0x8a, 0x8a, - 0x70, 0x82, 0x63, 0xed, 0x7b, 0x43, 0x38, 0xcf, 0x71, 0x70, 0x2e, 0x1f, 0x8a, 0x97, 0x29, 0x9c, - 0x9f, 0xcc, 0x47, 0x63, 0xee, 0xa7, 0x33, 0x6c, 0xc7, 0x03, 0x87, 0x33, 0xf2, 0x07, 0x0e, 0x67, - 0x70, 0x2d, 0xbd, 0x70, 0xc8, 0x96, 0xfe, 0x69, 0x56, 0x3b, 0xda, 0xbc, 0x76, 0x3c, 0x59, 0x1c, - 0x91, 0xc9, 0x8d, 0xcc, 0xef, 0x0b, 0xd5, 0xe3, 0x3c, 0xa7, 0x1e, 0x95, 0xc3, 0x31, 0x93, 0xbd, - 0x7e, 0xfc, 0x66, 0x30, 0xa1, 0x3d, 0xe2, 0xf6, 0x3e, 0xee, 0x46, 0x24, 0x27, 0xc4, 0x89, 0x8d, - 0xdc, 0xe3, 0x6c, 0x44, 0x8e, 0xe2, 0x64, 0x0a, 0x21, 0xdd, 0x16, 0xc0, 0x1c, 0xe6, 0xe9, 0xbc, - 0xd5, 0xdd, 0x81, 0xbe, 0xf6, 0x6a, 0xe2, 0xaa, 0x18, 0x04, 0xd0, 0x9c, 0x50, 0x94, 0xa3, 0xb8, - 0x63, 0xb3, 0x69, 0xfd, 0x05, 0x08, 0x93, 0x4b, 0x0c, 0x83, 0xd3, 0x0e, 0xc4, 0x38, 0x92, 0x83, - 0xec, 0x21, 0xfb, 0x04, 0x71, 0xe6, 0xa8, 0x9b, 0x57, 0x9c, 0x7d, 0x5f, 0x7b, 0xce, 0x04, 0x3a, - 0xe8, 0x65, 0x50, 0xec, 0x61, 0x6a, 0xf4, 0x74, 0x46, 0xf2, 0x74, 0x87, 0x8a, 0x80, 0x94, 0x6f, - 0xd0, 0x2f, 0xd3, 0x1e, 0xd1, 0x88, 0xe4, 0x48, 0xe8, 0x4c, 0xfb, 0x88, 0xc6, 0x88, 0xf2, 0xa7, - 0x72, 0x55, 0x4f, 0x09, 0x95, 0x6e, 0xed, 0x59, 0xfe, 0x84, 0x02, 0x41, 0xf4, 0x10, 0xad, 0x20, - 0x10, 0x04, 0x7e, 0x48, 0x7b, 0xf0, 0x94, 0x91, 0x0a, 0xfa, 0x7c, 0xda, 0x07, 0x4f, 0x93, 0x8b, - 0xcf, 0x1e, 0x93, 0x9f, 0x23, 0x2d, 0xeb, 0x1c, 0xf1, 0xc1, 0xcd, 0xd0, 0xbd, 0x77, 0xec, 0xc6, - 0x42, 0x58, 0x3b, 0xba, 0xc6, 0x32, 0xb4, 0xfc, 0xec, 0x81, 0xf9, 0xe5, 0x1f, 0x00, 0x85, 0x2a, - 0xbc, 0xb0, 0xbf, 0xa3, 0xdd, 0x01, 0x4a, 0x6d, 0x17, 0xc2, 0x9a, 0xbd, 0xed, 0x20, 0xe9, 0xfa, - 0xe8, 0x7f, 0x00, 0x09, 0x7d, 0x42, 0x78, 0xec, 0x42, 0xb3, 0x1b, 0x1d, 0x43, 0x0b, 0x1e, 0xb5, - 0x97, 0x49, 0x20, 0xdf, 0xf2, 0x4d, 0x5f, 0x9b, 0x0d, 0xb1, 0xd5, 0x9e, 0xc3, 0x62, 0x71, 0x07, - 0x8f, 0xc5, 0x0d, 0x9c, 0x2c, 0x30, 0x07, 0x4b, 0xe8, 0xfb, 0x18, 0x00, 0x34, 0x50, 0xba, 0xcf, - 0x73, 0x6c, 0x94, 0x23, 0x38, 0x29, 0x19, 0x3c, 0x6b, 0xaf, 0x0c, 0xc5, 0x7d, 0x17, 0x27, 0xee, - 0x47, 0x89, 0x15, 0x31, 0x85, 0x95, 0x36, 0x09, 0xcc, 0x22, 0xd1, 0xae, 0x41, 0xb3, 0xeb, 0x69, - 0x0f, 0x8b, 0x94, 0x3f, 0x46, 0xcc, 0xda, 0x47, 0x84, 0x63, 0x7a, 0x92, 0x5a, 0x85, 0xc4, 0xe3, - 0xfd, 0x05, 0x82, 0x98, 0x26, 0x12, 0x1f, 0xd3, 0xe4, 0x16, 0x90, 0xb7, 0xec, 0x6d, 0x87, 0x7a, - 0xaf, 0x3d, 0x38, 0x86, 0x36, 0xd2, 0x09, 0x03, 0x67, 0x14, 0x0c, 0xf8, 0x99, 0xcc, 0xd6, 0x54, - 0xee, 0xce, 0xcb, 0xa3, 0xd2, 0xb5, 0xff, 0x7b, 0xa4, 0xb0, 0x55, 0x15, 0xe4, 0xfb, 0xa6, 0xbf, - 0x4b, 0x8b, 0xc6, 0xff, 0x91, 0x8d, 0xbc, 0x6f, 0x9b, 0xb6, 0x63, 0x5f, 0xd9, 0xb3, 0x9e, 0x19, - 0x5e, 0xd1, 0xcb, 0xa5, 0x21, 0xce, 0x77, 0xa0, 0x0d, 0x5d, 0xd3, 0x87, 0xad, 0x4b, 0x3b, 0x78, - 0x8e, 0x55, 0x32, 0xd8, 0xa4, 0xd4, 0xfa, 0x8f, 0x38, 0x8e, 0xd7, 0xff, 0x6d, 0xab, 0x07, 0x71, - 0xc0, 0x27, 0xaa, 0xff, 0xc1, 0x73, 0x2a, 0xfd, 0x1f, 0x52, 0x44, 0xf6, 0x68, 0xfc, 0xab, 0x04, - 0xe6, 0x5b, 0x48, 0xe1, 0x5a, 0xfb, 0x7b, 0x7b, 0xa6, 0x7b, 0x45, 0x7b, 0x78, 0x84, 0x0a, 0xa3, - 0x9a, 0x39, 0x4e, 0x35, 0xb5, 0xdf, 0x10, 0xbe, 0x9d, 0x9a, 0x36, 0x6d, 0xa6, 0x84, 0xd4, 0xed, - 0xe0, 0xb1, 0xa0, 0x80, 0xd4, 0x3b, 0xf0, 0xe7, 0x4b, 0x6c, 0x08, 0x24, 0xa7, 0x60, 0x60, 0xac, - 0x91, 0xbc, 0x4d, 0x21, 0x28, 0x87, 0x04, 0x8e, 0xb7, 0x7c, 0xb3, 0x73, 0x71, 0xd5, 0x71, 0x9d, - 0x7d, 0xdf, 0xb2, 0xa1, 0xa7, 0x3d, 0x24, 0x42, 0x20, 0xd0, 0xff, 0x5c, 0xa4, 0xff, 0xda, 0xbf, - 0xe5, 0x44, 0x47, 0xd1, 0xb0, 0x5b, 0x65, 0xc9, 0xc7, 0xc4, 0xb9, 0x12, 0x1b, 0x17, 0x45, 0x28, - 0x66, 0x2f, 0xb4, 0x37, 0xc9, 0x40, 0xd1, 0xef, 0xef, 0x3b, 0xae, 0x5f, 0x77, 0x3a, 0x66, 0xcf, - 0xf3, 0x1d, 0x17, 0x6a, 0xcd, 0x44, 0xa9, 0xa1, 0x1e, 0xa6, 0xeb, 0x74, 0xa2, 0xc1, 0x91, 0x3e, - 0xb1, 0x6a, 0x27, 0xf3, 0x3a, 0xfe, 0x09, 0xe1, 0x5d, 0x46, 0x22, 0x95, 0x41, 0x8e, 0x62, 0xf4, - 0x7c, 0x58, 0x97, 0x96, 0xce, 0x15, 0x5f, 0x6c, 0xe7, 0x51, 0x88, 0xa9, 0x29, 0x2c, 0x95, 0x4b, - 0x60, 0xa1, 0xb5, 0x7f, 0x21, 0x24, 0xe2, 0xb1, 0x46, 0xc8, 0x6b, 0x84, 0x83, 0x59, 0x50, 0xc5, - 0x63, 0x09, 0xc5, 0xc8, 0xf7, 0x7a, 0xb0, 0xe0, 0xb1, 0xd9, 0x28, 0xde, 0x7c, 0xa2, 0x60, 0x10, - 0x8b, 0xd1, 0xa5, 0x66, 0x2f, 0xc0, 0xf7, 0x49, 0x60, 0xa1, 0xd9, 0x87, 0x36, 0xec, 0x12, 0x1f, - 0x3b, 0x4e, 0x80, 0x2f, 0x4b, 0x29, 0x40, 0x8e, 0x50, 0x8c, 0x00, 0x23, 0x7f, 0xd8, 0x6a, 0x20, - 0xbc, 0x28, 0x21, 0x95, 0xe0, 0x92, 0x4a, 0xcb, 0x5e, 0x70, 0x5f, 0x91, 0xc0, 0x9c, 0xb1, 0x6f, - 0x6f, 0xb8, 0x0e, 0x1a, 0x8d, 0x5d, 0xed, 0xce, 0xa8, 0x83, 0xb8, 0x19, 0x9c, 0xe8, 0xee, 0xbb, - 0x78, 0xfd, 0xa9, 0x66, 0xb7, 0x60, 0xc7, 0xb1, 0xbb, 0x1e, 0xae, 0x47, 0xc1, 0x38, 0xf8, 0xe2, - 0xf6, 0xfc, 0xf3, 0xfe, 0x52, 0xce, 0x69, 0x2f, 0x10, 0x8e, 0x98, 0x43, 0x2a, 0xcf, 0x14, 0x2d, - 0xde, 0x13, 0x08, 0xc6, 0xc5, 0x19, 0x55, 0x42, 0xf6, 0xc2, 0xfd, 0x82, 0x04, 0xd4, 0x72, 0xa7, - 0xe3, 0xec, 0xdb, 0x7e, 0x0b, 0xf6, 0x60, 0xc7, 0x6f, 0xbb, 0x66, 0x07, 0xb2, 0xf6, 0xb3, 0x02, - 0xe4, 0xae, 0xe5, 0xd2, 0x3e, 0x18, 0xfd, 0xa5, 0x72, 0x7c, 0x99, 0xf0, 0x8e, 0x23, 0xa9, 0xe5, - 0xc1, 0x52, 0x52, 0x88, 0x53, 0x6c, 0x5f, 0x51, 0xb0, 0xa0, 0xec, 0xa5, 0xfa, 0x69, 0x09, 0xcc, - 0x06, 0x3d, 0xf6, 0x8e, 0x88, 0x30, 0x7f, 0x2e, 0xe5, 0x64, 0x24, 0x24, 0x9e, 0x42, 0x86, 0xef, - 0x4a, 0x31, 0xab, 0x88, 0xa3, 0x9f, 0x4e, 0x74, 0xe5, 0xf4, 0xa2, 0x43, 0x8f, 0x8d, 0xe6, 0xd6, - 0x4a, 0xb3, 0x5e, 0xd5, 0x0d, 0x45, 0xd6, 0xbe, 0x2a, 0x81, 0xfc, 0x86, 0x65, 0xef, 0xb0, 0x81, - 0xcd, 0x4e, 0x22, 0x3b, 0xb2, 0x0b, 0xef, 0xa7, 0x2d, 0x9d, 0x3c, 0xa8, 0xb7, 0x82, 0x93, 0xf6, - 0xfe, 0xde, 0x05, 0xe8, 0x36, 0xb7, 0xf1, 0x28, 0xeb, 0xb5, 0x9d, 0x16, 0xb4, 0x89, 0x11, 0x5a, - 0x30, 0x86, 0xbe, 0xe3, 0x4d, 0x30, 0x81, 0xc9, 0x03, 0xe2, 0x24, 0x46, 0xe2, 0x21, 0x53, 0x12, - 0xc3, 0x54, 0xaa, 0x69, 0xc3, 0x10, 0xe2, 0xd9, 0x6b, 0xea, 0x6f, 0x15, 0xc0, 0xd5, 0x65, 0xfb, - 0x0a, 0xb6, 0x29, 0x48, 0x07, 0x5f, 0xd9, 0x35, 0xed, 0x1d, 0x88, 0x07, 0x88, 0x50, 0xe2, 0x6c, - 0xa4, 0xff, 0x1c, 0x1f, 0xe9, 0x5f, 0x35, 0xc0, 0x8c, 0xe3, 0x76, 0xa1, 0xbb, 0x7c, 0x05, 0xf3, - 0x34, 0xb8, 0xec, 0x4c, 0xdb, 0xe4, 0xb0, 0x22, 0x96, 0x28, 0xf9, 0xa5, 0x26, 0xf9, 0xde, 0x08, - 0x08, 0x9d, 0xbd, 0x19, 0xcc, 0xd0, 0x34, 0x75, 0x1e, 0x94, 0x9a, 0x46, 0x55, 0x37, 0xb6, 0x6a, - 0x55, 0xe5, 0x98, 0x7a, 0x15, 0x38, 0x5e, 0x6b, 0xeb, 0x46, 0xb9, 0x5d, 0x6b, 0x36, 0xb6, 0x70, - 0xba, 0x92, 0xd3, 0x9e, 0x9b, 0x17, 0xf5, 0xec, 0x4d, 0x66, 0x66, 0x18, 0xac, 0x06, 0x98, 0xe9, - 0x90, 0x0c, 0x78, 0x08, 0x9d, 0x4b, 0x55, 0x3b, 0x4a, 0x90, 0x24, 0x18, 0x01, 0x21, 0xf5, 0x0c, - 0x00, 0x97, 0x5d, 0xc7, 0xde, 0x89, 0xce, 0xb4, 0x95, 0x0c, 0x26, 0x45, 0x7b, 0x4e, 0x0e, 0x14, - 0xc9, 0x37, 0xf8, 0x66, 0x13, 0xfc, 0x2f, 0x12, 0x7c, 0xf0, 0x8c, 0x2c, 0x5e, 0x2c, 0xaf, 0x68, - 0xa2, 0x45, 0x1f, 0x91, 0x2e, 0x12, 0x19, 0x10, 0x4b, 0x98, 0x56, 0xe5, 0x16, 0x50, 0x24, 0xdf, - 0x52, 0xaf, 0x83, 0xf8, 0x28, 0xa5, 0x24, 0x9b, 0xa0, 0x9f, 0xb2, 0xb8, 0x4c, 0xb3, 0xd7, 0xe6, - 0x8f, 0x4a, 0xa0, 0xd4, 0x80, 0x7e, 0x65, 0x17, 0x76, 0x2e, 0x6a, 0x8f, 0xe4, 0x17, 0x40, 0x7b, - 0x16, 0xb4, 0xfd, 0x7b, 0xf7, 0x7a, 0xe1, 0x02, 0x68, 0x90, 0xa0, 0x3d, 0x9f, 0xed, 0x7c, 0x9f, - 0xc2, 0xeb, 0xcf, 0x4d, 0x43, 0xea, 0x1a, 0x94, 0x10, 0xa3, 0x32, 0xa7, 0x40, 0xd1, 0x85, 0xde, - 0x7e, 0x2f, 0x58, 0x44, 0xa3, 0x4f, 0xda, 0x6b, 0x43, 0x71, 0x56, 0x38, 0x71, 0xde, 0x22, 0x5e, - 0xc4, 0x14, 0xc2, 0x9e, 0xe6, 0xc1, 0x4c, 0xcd, 0xb6, 0x7c, 0xcb, 0xec, 0x69, 0x2f, 0xc8, 0x83, - 0x85, 0x16, 0xf4, 0x37, 0x4c, 0xd7, 0xdc, 0x83, 0x3e, 0x74, 0x3d, 0xed, 0x3b, 0x7c, 0x9f, 0xd0, - 0xef, 0x99, 0xfe, 0xb6, 0xe3, 0xee, 0x05, 0xaa, 0x19, 0x3c, 0x23, 0xd5, 0xbc, 0x04, 0x5d, 0x2f, - 0xe2, 0x2b, 0x78, 0x44, 0x6f, 0x2e, 0x3b, 0xee, 0x45, 0x34, 0x08, 0xd2, 0x69, 0x1a, 0x7d, 0x44, - 0xf4, 0x7a, 0xce, 0x4e, 0x1d, 0x5e, 0x82, 0x41, 0x54, 0xb5, 0xf0, 0x19, 0xcd, 0x05, 0xba, 0x4e, - 0xc3, 0xf1, 0x51, 0xa7, 0x5d, 0x77, 0x76, 0x48, 0xd8, 0xd9, 0x92, 0xc1, 0x27, 0x46, 0xb9, 0xcc, - 0x4b, 0x10, 0xe7, 0x2a, 0xb2, 0xb9, 0x68, 0xa2, 0xba, 0x04, 0xd4, 0xf0, 0xb3, 0x36, 0xec, 0xc1, - 0x3d, 0xe8, 0xbb, 0x57, 0xf0, 0xed, 0x12, 0x25, 0x63, 0xc8, 0x1b, 0x3a, 0x40, 0x8b, 0x4f, 0xd6, - 0xa9, 0xf4, 0x96, 0x38, 0xc9, 0x1d, 0x6a, 0xb2, 0x2e, 0x42, 0x71, 0x2a, 0xb7, 0x67, 0xc9, 0xc8, - 0x9a, 0x79, 0xb9, 0x0c, 0xf2, 0x78, 0xf0, 0x7c, 0x73, 0x8e, 0x5b, 0x61, 0xda, 0x83, 0x9e, 0x67, - 0xee, 0xc0, 0x60, 0x85, 0x89, 0x3e, 0xaa, 0xb7, 0x81, 0x42, 0x0f, 0x63, 0x4a, 0x06, 0x87, 0x87, - 0x73, 0x35, 0x43, 0x06, 0x06, 0xa2, 0x15, 0x8e, 0x04, 0x18, 0x6e, 0x83, 0x7c, 0x71, 0xf6, 0x6e, - 0x50, 0x20, 0xf0, 0xcf, 0x82, 0x42, 0x55, 0x5f, 0xde, 0x5c, 0x55, 0x8e, 0xa1, 0xbf, 0x01, 0x7f, - 0xb3, 0xa0, 0xb0, 0x52, 0x6e, 0x97, 0xeb, 0x8a, 0x84, 0xea, 0x51, 0x6b, 0xac, 0x34, 0x15, 0x19, - 0x25, 0x6e, 0x94, 0x1b, 0xb5, 0x8a, 0x92, 0x57, 0xe7, 0xc0, 0xcc, 0xf9, 0xb2, 0xd1, 0xa8, 0x35, - 0x56, 0x95, 0x82, 0xf6, 0x17, 0x2c, 0x7e, 0xb7, 0xf3, 0xf8, 0x5d, 0x1f, 0xc7, 0xd3, 0x30, 0xc8, - 0x7e, 0x31, 0x84, 0xec, 0x4e, 0x0e, 0xb2, 0x1f, 0x10, 0x21, 0x32, 0x05, 0x77, 0xa6, 0x22, 0x98, - 0xd9, 0x70, 0x9d, 0x0e, 0xf4, 0x3c, 0xed, 0xa5, 0x12, 0x28, 0x56, 0x4c, 0xbb, 0x03, 0x7b, 0xda, - 0x35, 0x11, 0x54, 0xc4, 0x55, 0x34, 0x17, 0xb8, 0x8a, 0x6a, 0xdf, 0xca, 0x89, 0xf6, 0x7e, 0x94, - 0xee, 0x12, 0xa1, 0x19, 0x23, 0x1f, 0xb1, 0x5e, 0x2e, 0x91, 0xd4, 0x14, 0x6e, 0xd8, 0x91, 0xc0, - 0x2c, 0x5d, 0x0d, 0xb8, 0x00, 0xd9, 0x79, 0xf8, 0x77, 0x72, 0xa2, 0x93, 0xc3, 0xa0, 0x06, 0x21, - 0x99, 0x18, 0x79, 0x88, 0x4d, 0x04, 0x47, 0x51, 0x9b, 0xc2, 0xe6, 0xa1, 0x04, 0xe6, 0x36, 0x6d, - 0x6f, 0x98, 0x50, 0xc4, 0xc3, 0xf1, 0x07, 0xd5, 0x60, 0x08, 0x1d, 0x2a, 0x1c, 0xff, 0x68, 0x7a, - 0xd9, 0x0b, 0xe6, 0x3b, 0x39, 0x70, 0x72, 0x15, 0xda, 0xd0, 0xb5, 0x3a, 0xa4, 0x06, 0x81, 0x24, - 0xee, 0xe4, 0x25, 0xf1, 0x48, 0x8e, 0xf3, 0x61, 0x5f, 0xf0, 0x12, 0x78, 0x55, 0x28, 0x81, 0xa7, - 0x70, 0x12, 0xb8, 0x59, 0x90, 0xce, 0x14, 0xae, 0x55, 0x9f, 0x05, 0xf3, 0x0d, 0xc7, 0xb7, 0xb6, - 0xad, 0x0e, 0xf1, 0x41, 0xfb, 0x05, 0x19, 0xe4, 0xeb, 0x96, 0xe7, 0x6b, 0xe5, 0xa8, 0x3b, 0xb9, - 0x0e, 0xcc, 0x59, 0x76, 0xa7, 0xb7, 0xdf, 0x85, 0x06, 0x34, 0x49, 0xbf, 0x52, 0x32, 0xd8, 0xa4, - 0x68, 0x6b, 0x1f, 0xb1, 0x25, 0x07, 0x5b, 0xfb, 0xbf, 0x23, 0xbc, 0x0c, 0xc3, 0xb2, 0x80, 0xe3, - 0x52, 0xc6, 0xd8, 0x5d, 0x65, 0xb0, 0x60, 0x33, 0x59, 0x03, 0x83, 0x7d, 0xf0, 0x5e, 0x02, 0x96, - 0x9c, 0xc1, 0x7f, 0xa1, 0x7d, 0x40, 0xa8, 0xb1, 0x8e, 0x62, 0x28, 0x1d, 0x32, 0x2b, 0x63, 0x4c, - 0x92, 0x55, 0xb0, 0x58, 0x6b, 0xb4, 0x75, 0xa3, 0x51, 0xae, 0xd3, 0x2c, 0xb2, 0xf6, 0xaf, 0x12, - 0x28, 0x18, 0xb0, 0xdf, 0xbb, 0xc2, 0x06, 0x9e, 0xa6, 0x8e, 0xe2, 0xb9, 0xd0, 0x51, 0x5c, 0x5d, - 0x01, 0xc0, 0xec, 0xa0, 0x82, 0xf1, 0xcd, 0x5c, 0xd2, 0xd0, 0x70, 0xa6, 0x5c, 0x05, 0xcb, 0x61, - 0x6e, 0x83, 0xf9, 0x52, 0x7b, 0xa1, 0xf0, 0xce, 0x11, 0x47, 0x0d, 0x73, 0x18, 0xd3, 0x27, 0x7c, - 0x50, 0x68, 0xb3, 0x67, 0x24, 0xb9, 0xa3, 0x11, 0xff, 0xd7, 0x24, 0x90, 0x6f, 0xa3, 0xde, 0x92, - 0xe9, 0x38, 0x3f, 0x37, 0x9e, 0x8e, 0x23, 0x32, 0x31, 0x3a, 0x7e, 0x17, 0x98, 0x67, 0x35, 0x96, - 0xba, 0x4a, 0x24, 0xaa, 0x38, 0xf7, 0xc1, 0x38, 0x1a, 0x3e, 0x84, 0x9d, 0xa3, 0x11, 0xf1, 0x67, - 0x1e, 0x05, 0xc0, 0x3a, 0xdc, 0xbb, 0x00, 0x5d, 0x6f, 0xd7, 0xea, 0x6b, 0x7f, 0x25, 0x83, 0xd9, - 0x55, 0xe8, 0xb7, 0x7c, 0xd3, 0xdf, 0xf7, 0x06, 0xb6, 0x3b, 0x6d, 0xa7, 0x62, 0x76, 0x76, 0x21, - 0xed, 0x8e, 0x82, 0x47, 0xed, 0x3d, 0xb2, 0xa8, 0x3f, 0x51, 0x54, 0xce, 0x52, 0x58, 0x46, 0x0c, - 0x26, 0x8f, 0x06, 0xf9, 0xae, 0xe9, 0x9b, 0x14, 0x8b, 0x6b, 0x06, 0xb0, 0x88, 0x08, 0x19, 0x38, - 0x9b, 0xf6, 0x0e, 0x49, 0xc4, 0xa1, 0x48, 0xa0, 0xfc, 0x74, 0x20, 0x7c, 0x20, 0x37, 0x06, 0x0a, - 0x27, 0xc0, 0x42, 0xa3, 0xd9, 0xde, 0xaa, 0x37, 0x57, 0x57, 0x75, 0x94, 0xaa, 0xc8, 0xea, 0x29, - 0xa0, 0x6e, 0x94, 0xef, 0x5d, 0xd7, 0x1b, 0xed, 0xad, 0x46, 0xb3, 0xaa, 0xd3, 0x2f, 0xf3, 0xea, - 0x71, 0x30, 0x57, 0x29, 0x57, 0xd6, 0x82, 0x84, 0x82, 0x7a, 0x1a, 0x9c, 0x5c, 0xd7, 0xd7, 0x97, - 0x75, 0xa3, 0xb5, 0x56, 0xdb, 0xd8, 0x42, 0x64, 0x56, 0x9a, 0x9b, 0x8d, 0xaa, 0x52, 0x54, 0x35, - 0x70, 0x8a, 0x79, 0x73, 0xde, 0x68, 0x36, 0x56, 0xb7, 0x5a, 0xed, 0x72, 0x5b, 0x57, 0x66, 0xd4, - 0xab, 0xc0, 0xf1, 0x4a, 0xb9, 0x81, 0xb3, 0x57, 0x9a, 0x8d, 0x86, 0x5e, 0x69, 0x2b, 0x25, 0xed, - 0xdf, 0xf2, 0x60, 0xae, 0xe6, 0x35, 0xcc, 0x3d, 0x78, 0xce, 0xec, 0x59, 0x5d, 0xed, 0x05, 0xcc, - 0xcc, 0xe3, 0x7a, 0xb0, 0xe0, 0x92, 0xbf, 0xb0, 0xdb, 0xb6, 0x20, 0x41, 0x73, 0xc1, 0xe0, 0x13, - 0xd1, 0x9c, 0xdc, 0xc6, 0x04, 0x82, 0x39, 0x39, 0x79, 0x52, 0x97, 0x01, 0x20, 0xff, 0xda, 0xd1, - 0x1d, 0xb1, 0x67, 0x07, 0x5b, 0x93, 0xb9, 0x07, 0x3d, 0xe8, 0x5e, 0xb2, 0x3a, 0x30, 0xc8, 0x69, - 0x30, 0x5f, 0x69, 0x5f, 0x97, 0x45, 0xf7, 0x17, 0x19, 0x50, 0x99, 0xea, 0xc4, 0xf4, 0x86, 0x3f, - 0x2e, 0x8b, 0xec, 0x0e, 0x0a, 0x91, 0x4c, 0xa7, 0x29, 0x2f, 0x96, 0xc6, 0x5b, 0xb6, 0x6d, 0x37, - 0x9b, 0x5b, 0xad, 0xb5, 0xa6, 0xd1, 0x56, 0x64, 0x75, 0x1e, 0x94, 0xd0, 0x63, 0xbd, 0xd9, 0x58, - 0x55, 0xf2, 0xea, 0xd5, 0xe0, 0xc4, 0x5a, 0xb9, 0xb5, 0x55, 0x6b, 0x9c, 0x2b, 0xd7, 0x6b, 0xd5, - 0xad, 0xca, 0x5a, 0xd9, 0x68, 0x29, 0x05, 0xf5, 0x1a, 0x70, 0x75, 0xbb, 0xa6, 0x1b, 0x5b, 0x2b, - 0x7a, 0xb9, 0xbd, 0x69, 0xe8, 0xad, 0xad, 0x46, 0x73, 0xab, 0x51, 0x5e, 0xd7, 0x95, 0x22, 0x6a, - 0xfe, 0xf8, 0x55, 0xa4, 0x36, 0x33, 0x07, 0x95, 0xb1, 0x14, 0xa3, 0x8c, 0xb3, 0x83, 0xca, 0x08, - 0x58, 0xb5, 0x32, 0xf4, 0x96, 0x6e, 0x9c, 0xd3, 0x95, 0xb9, 0x61, 0xba, 0x36, 0xaf, 0x9e, 0x04, - 0x0a, 0xe2, 0x61, 0xab, 0xd6, 0x0a, 0x72, 0x56, 0x95, 0x05, 0xed, 0xd3, 0x45, 0x70, 0xca, 0x80, - 0x3b, 0x96, 0xe7, 0x43, 0x77, 0xc3, 0xbc, 0xb2, 0x07, 0x6d, 0x3f, 0xe8, 0xe4, 0xff, 0x29, 0xb5, - 0x32, 0xae, 0x83, 0x85, 0x3e, 0xa1, 0xb1, 0x0e, 0xfd, 0x5d, 0xa7, 0x4b, 0x47, 0xe1, 0x47, 0xc6, - 0xf6, 0x1c, 0x4b, 0x1b, 0x6c, 0x76, 0x83, 0xff, 0x9a, 0xd1, 0x6d, 0x39, 0x41, 0xb7, 0xf3, 0xe3, - 0xe8, 0xb6, 0x7a, 0x2d, 0x98, 0xdd, 0xf7, 0xa0, 0xab, 0xef, 0x99, 0x56, 0x2f, 0xb8, 0xe3, 0x33, - 0x4c, 0xd0, 0xde, 0x99, 0x17, 0x3d, 0xb1, 0xc2, 0xd4, 0x65, 0xb8, 0x18, 0x63, 0xfa, 0xd6, 0x33, - 0x00, 0xd0, 0xca, 0x6e, 0xba, 0x3d, 0xaa, 0xac, 0x4c, 0x0a, 0xe2, 0xef, 0x82, 0xd5, 0xeb, 0x59, - 0xf6, 0x4e, 0xb8, 0xef, 0x1f, 0x25, 0x68, 0x2f, 0x96, 0x45, 0x4e, 0xb0, 0xa4, 0xe5, 0x2d, 0x5d, - 0x6b, 0x7a, 0xa1, 0x34, 0xe5, 0x7e, 0xf7, 0x60, 0xd3, 0x29, 0xaa, 0x0a, 0x98, 0xc7, 0x69, 0xb4, - 0x05, 0x2a, 0x33, 0xa8, 0x0f, 0x0e, 0xc8, 0xad, 0xeb, 0xed, 0xb5, 0x66, 0x35, 0x7c, 0x57, 0x42, - 0x24, 0x11, 0x33, 0xe5, 0xc6, 0xbd, 0xb8, 0x35, 0xce, 0xaa, 0x0f, 0x01, 0xd7, 0x30, 0x1d, 0x76, - 0xb9, 0x6e, 0xe8, 0xe5, 0xea, 0xbd, 0x5b, 0xfa, 0xd3, 0x6a, 0xad, 0x76, 0x8b, 0x6f, 0x5c, 0x41, - 0x3b, 0x9a, 0x43, 0xfc, 0xea, 0xeb, 0xe5, 0x5a, 0x9d, 0xf6, 0xef, 0x2b, 0x4d, 0x63, 0xbd, 0xdc, - 0x56, 0xe6, 0xb5, 0x97, 0xcb, 0x40, 0x59, 0x85, 0xfe, 0x86, 0xe3, 0xfa, 0x66, 0xaf, 0x6e, 0xd9, - 0x17, 0x37, 0xdd, 0x1e, 0x37, 0xd9, 0x14, 0x0e, 0xd3, 0xc1, 0x0f, 0x91, 0x1c, 0xc1, 0xf8, 0x1d, - 0xf1, 0x3e, 0xce, 0x16, 0x29, 0x53, 0x94, 0xa0, 0x3d, 0x4b, 0x12, 0x59, 0xee, 0x16, 0x2f, 0x35, - 0x9d, 0x9e, 0x3c, 0x7b, 0xda, 0xe3, 0xf3, 0x10, 0xd4, 0x8a, 0xda, 0xf3, 0xf2, 0xa0, 0xb4, 0x62, - 0xd9, 0x66, 0xcf, 0x7a, 0x26, 0x17, 0x1d, 0x33, 0xea, 0x63, 0x72, 0x09, 0x7d, 0x8c, 0x34, 0xd6, - 0xf8, 0xf9, 0xb3, 0xb2, 0xe8, 0xf2, 0x02, 0x23, 0xfb, 0x80, 0xc9, 0x98, 0xc1, 0xf3, 0x63, 0x92, - 0xc8, 0xf2, 0xc2, 0x68, 0x7a, 0xe9, 0x30, 0xfc, 0xec, 0xf7, 0x87, 0x8d, 0x35, 0xd0, 0xbe, 0x4b, - 0xc3, 0x54, 0x61, 0x56, 0xfb, 0x03, 0x19, 0x68, 0xab, 0xd0, 0x3f, 0x07, 0xdd, 0x70, 0x2a, 0x80, - 0x7b, 0x7d, 0x6a, 0x6f, 0x33, 0x4d, 0xf6, 0xcd, 0x2c, 0x80, 0xe7, 0x79, 0x00, 0xcb, 0x09, 0x8d, - 0x27, 0x86, 0x74, 0x4c, 0xe3, 0xad, 0x81, 0xa2, 0x87, 0xdf, 0x53, 0x35, 0x7b, 0x6c, 0xfc, 0x70, - 0x89, 0x89, 0xb1, 0xd4, 0x09, 0x61, 0x83, 0x12, 0xd0, 0xbe, 0x1b, 0x4e, 0x82, 0x7e, 0x98, 0xd3, - 0x8e, 0x95, 0x43, 0x33, 0x9b, 0x4e, 0x5f, 0xdc, 0x6c, 0xd5, 0x65, 0x98, 0x7d, 0xa3, 0x7d, 0xac, - 0x00, 0x4e, 0x0e, 0xab, 0x8e, 0xf6, 0xa1, 0x1c, 0xb7, 0xc3, 0x0e, 0xf1, 0x90, 0x9f, 0xa3, 0x1b, - 0x88, 0xe8, 0x41, 0x7d, 0x3c, 0xb8, 0x3a, 0x5c, 0x86, 0x6b, 0x3b, 0x0d, 0x78, 0xd9, 0xeb, 0x41, - 0xdf, 0x87, 0x2e, 0xae, 0x5a, 0xc9, 0x18, 0xfe, 0x52, 0x7d, 0x22, 0x78, 0x90, 0x65, 0x7b, 0x56, - 0x17, 0xba, 0x6d, 0xab, 0xef, 0x95, 0xed, 0x6e, 0x7b, 0xdf, 0x77, 0x5c, 0xcb, 0xa4, 0x37, 0x52, - 0x96, 0x8c, 0xb8, 0xd7, 0xea, 0x4d, 0x40, 0xb1, 0xbc, 0xa6, 0x7d, 0xc1, 0x31, 0xdd, 0xae, 0x65, - 0xef, 0xd4, 0x2d, 0xcf, 0xa7, 0x1e, 0xc0, 0x07, 0xd2, 0xb5, 0xbf, 0x96, 0x45, 0x0f, 0xd3, 0x8d, - 0x80, 0x35, 0xa6, 0x43, 0x79, 0xbe, 0x2c, 0x72, 0x3c, 0x2e, 0x1d, 0xed, 0x74, 0xca, 0xf2, 0xdc, - 0x69, 0x1b, 0x12, 0xc3, 0x47, 0x70, 0xdc, 0xb5, 0x90, 0xf4, 0xc0, 0x10, 0x38, 0xa7, 0x1b, 0xb5, - 0x95, 0x9a, 0x8e, 0xcc, 0x8a, 0xab, 0xc1, 0x89, 0xe8, 0x5d, 0xf5, 0xde, 0xad, 0x96, 0xde, 0x68, - 0x2b, 0x25, 0xd4, 0x4f, 0x91, 0xe4, 0x95, 0x72, 0xad, 0xae, 0x57, 0xb7, 0xda, 0x4d, 0xf4, 0xa6, - 0x3a, 0x9e, 0x69, 0xa1, 0x3d, 0x27, 0x0f, 0x8e, 0x63, 0xd9, 0x5e, 0xc1, 0x52, 0x45, 0x42, 0x19, - 0xf0, 0xb5, 0x0d, 0x01, 0x9a, 0x25, 0xe2, 0xd5, 0x7e, 0x5f, 0xf8, 0xc2, 0x4d, 0x06, 0xc2, 0x81, - 0x32, 0x62, 0x34, 0xe3, 0x3b, 0x92, 0x48, 0x84, 0x0a, 0x61, 0xb2, 0xe9, 0x94, 0xe2, 0x9f, 0xa7, - 0x3d, 0xe2, 0xc4, 0x83, 0x8f, 0xad, 0xcc, 0x0a, 0xfe, 0xf8, 0x69, 0x1b, 0x35, 0x03, 0xab, 0xc3, - 0x22, 0x00, 0x38, 0x05, 0x6b, 0x10, 0xd1, 0x83, 0xa1, 0xe3, 0x55, 0x9c, 0x1e, 0x94, 0x2b, 0xed, - 0xda, 0x39, 0x3d, 0x4e, 0x0f, 0x3e, 0x2f, 0x83, 0xd2, 0x2a, 0xf4, 0xd1, 0x9c, 0xca, 0xd3, 0x9e, - 0x24, 0xb0, 0xfe, 0x83, 0xcc, 0x98, 0x9e, 0xd3, 0x31, 0x7b, 0xe1, 0x32, 0x00, 0x79, 0xd2, 0x7e, - 0x6c, 0x1c, 0x13, 0x24, 0x28, 0x3a, 0x66, 0xbc, 0xfa, 0x21, 0x50, 0xf0, 0xd1, 0x6b, 0xba, 0x0c, - 0xfd, 0xb0, 0xd8, 0xe1, 0x0a, 0x11, 0xa9, 0x9a, 0xbe, 0x69, 0x90, 0xfc, 0xcc, 0xe8, 0x24, 0x68, - 0xbb, 0xc4, 0x30, 0xf2, 0xfd, 0x68, 0x7f, 0xfe, 0x85, 0x0c, 0xae, 0x26, 0xed, 0xa3, 0xdc, 0xef, - 0xb7, 0x7c, 0xc7, 0x85, 0x06, 0xec, 0x40, 0xab, 0xef, 0x0f, 0xac, 0xef, 0xb9, 0x24, 0x35, 0xd8, - 0x6c, 0xa6, 0x8f, 0xda, 0x1b, 0x64, 0xd1, 0x08, 0xbf, 0x07, 0xda, 0xe3, 0x40, 0x79, 0x31, 0x8d, - 0xfd, 0x53, 0x92, 0x48, 0xcc, 0xde, 0x94, 0xc4, 0xd3, 0x01, 0xf5, 0xf1, 0x23, 0x00, 0x2a, 0x58, - 0xb9, 0x31, 0xf4, 0x8a, 0x5e, 0xdb, 0x40, 0x83, 0xc0, 0x43, 0xc1, 0x83, 0x37, 0x36, 0x8d, 0xca, - 0x5a, 0xb9, 0xa5, 0x6f, 0x19, 0xfa, 0x6a, 0xad, 0xd5, 0xa6, 0x4e, 0x59, 0xe4, 0xab, 0x19, 0xf5, - 0x5a, 0x70, 0xba, 0xb5, 0xb9, 0xdc, 0xaa, 0x18, 0xb5, 0x0d, 0x9c, 0x6e, 0xe8, 0x0d, 0xfd, 0x3c, - 0x7d, 0x5b, 0xd2, 0x3e, 0xa2, 0x80, 0x39, 0x34, 0x01, 0x68, 0x91, 0x79, 0x81, 0xf6, 0x37, 0x79, - 0x30, 0x67, 0x40, 0xcf, 0xe9, 0x5d, 0xc2, 0x73, 0x84, 0x69, 0x4d, 0x3d, 0xbe, 0x2d, 0x8b, 0x9e, - 0xdf, 0x66, 0x98, 0x5d, 0x62, 0x18, 0x8d, 0x9f, 0x68, 0x9a, 0x97, 0x4c, 0xab, 0x67, 0x5e, 0xa0, - 0x5d, 0x4d, 0xc9, 0x88, 0x12, 0xd4, 0x25, 0xa0, 0x3a, 0x97, 0x6d, 0xe8, 0xb6, 0x3a, 0x97, 0x75, - 0x7f, 0xb7, 0xdc, 0xed, 0xba, 0xd0, 0xf3, 0xe8, 0xea, 0xc5, 0x90, 0x37, 0xea, 0x8d, 0xe0, 0x38, - 0x4e, 0x65, 0x32, 0x13, 0x07, 0x99, 0xc1, 0xe4, 0x30, 0x67, 0xd9, 0xbe, 0x12, 0xe4, 0x2c, 0x30, - 0x39, 0xa3, 0x64, 0xf6, 0xb8, 0x44, 0x91, 0x3f, 0xa5, 0x73, 0x1d, 0x98, 0xb3, 0xcd, 0x3d, 0xa8, - 0xdf, 0xdf, 0xb7, 0x5c, 0xe8, 0x61, 0xc7, 0x18, 0xd9, 0x60, 0x93, 0xb4, 0x8f, 0x09, 0x9d, 0x37, - 0x17, 0x93, 0x58, 0x3a, 0xdd, 0x5f, 0x1d, 0x43, 0xf5, 0x87, 0xf4, 0x33, 0xb2, 0xf6, 0x11, 0x19, - 0xcc, 0x53, 0xa6, 0xca, 0xf6, 0x95, 0x5a, 0x57, 0x7b, 0x28, 0x67, 0xfc, 0x9a, 0x28, 0x2d, 0x30, - 0x7e, 0xf1, 0x83, 0xf6, 0x13, 0xb2, 0xa8, 0xbb, 0xf3, 0x90, 0x8a, 0xe3, 0x32, 0xe2, 0x1d, 0x47, - 0xb7, 0x9d, 0x7d, 0xea, 0xa8, 0x5a, 0x32, 0xc8, 0x43, 0x96, 0x8b, 0x7a, 0xda, 0xaf, 0x0b, 0x39, - 0x53, 0x0b, 0x56, 0xe3, 0x88, 0x00, 0xfc, 0x8c, 0x0c, 0x16, 0x29, 0x57, 0x2d, 0x7a, 0xce, 0x47, - 0xe8, 0xc0, 0xdb, 0x4f, 0x09, 0x1b, 0x82, 0x43, 0xea, 0x4f, 0x4b, 0x7a, 0xc0, 0x00, 0xf9, 0x09, - 0xa1, 0xe0, 0x68, 0xc2, 0x15, 0x39, 0x22, 0x28, 0xdf, 0x95, 0x07, 0x73, 0x9b, 0x1e, 0x74, 0xa9, - 0xdf, 0xbe, 0xf6, 0xda, 0x3c, 0x90, 0x57, 0x21, 0xb7, 0x91, 0xfa, 0x22, 0x61, 0x0f, 0x5f, 0xb6, - 0xb2, 0x0c, 0x51, 0x64, 0x23, 0xc5, 0xc0, 0x76, 0x03, 0x58, 0x24, 0x22, 0x2d, 0xfb, 0x3e, 0x32, - 0x12, 0x03, 0x6f, 0xda, 0x81, 0xd4, 0x49, 0x6c, 0x15, 0xe1, 0xb2, 0x50, 0x96, 0x0a, 0xe2, 0xa9, - 0x0e, 0xb7, 0xc9, 0x7c, 0x36, 0x6f, 0x0c, 0xa4, 0xaa, 0x8f, 0x01, 0x57, 0x39, 0x7d, 0x48, 0xce, - 0xaf, 0x30, 0x99, 0x0b, 0x38, 0xf3, 0xb0, 0x57, 0xda, 0xdf, 0x08, 0xf9, 0xea, 0x8a, 0x4b, 0x27, - 0x9d, 0x2e, 0xf4, 0x27, 0x63, 0x92, 0x9c, 0x04, 0x0a, 0xca, 0x81, 0xf7, 0x5f, 0x0c, 0xbd, 0xd5, - 0xac, 0x9f, 0xd3, 0x87, 0x2f, 0x63, 0x14, 0xb4, 0xe7, 0xca, 0x60, 0x76, 0xd9, 0x75, 0xcc, 0x6e, - 0xc7, 0xf4, 0x7c, 0xed, 0xbb, 0x12, 0x98, 0xdf, 0x30, 0xaf, 0xf4, 0x1c, 0xb3, 0x8b, 0xfd, 0xfb, - 0x07, 0xfa, 0x82, 0x3e, 0x79, 0x15, 0xf4, 0x05, 0xf4, 0x91, 0x3f, 0x18, 0x18, 0x1e, 0xdd, 0xcb, - 0x89, 0xdc, 0xab, 0x19, 0x6e, 0xf3, 0x49, 0xc3, 0x82, 0x95, 0x06, 0x7c, 0x2d, 0xb1, 0x3c, 0xc5, - 0x58, 0x94, 0x1f, 0x11, 0x0b, 0x3f, 0x2a, 0x42, 0xf2, 0x68, 0x76, 0xe5, 0x9f, 0x57, 0x02, 0xc5, - 0x2a, 0xc4, 0x56, 0xdc, 0xaf, 0x4a, 0x60, 0xa6, 0x05, 0x7d, 0x6c, 0xc1, 0xdd, 0xc6, 0x79, 0x0a, - 0x77, 0x71, 0x86, 0xc8, 0x89, 0x3d, 0x78, 0x46, 0x93, 0x75, 0xe6, 0xbc, 0x35, 0xfe, 0x9f, 0xc2, - 0x23, 0x91, 0x94, 0xbb, 0x44, 0xcb, 0x3c, 0x94, 0x47, 0x62, 0x22, 0xa9, 0xec, 0x7d, 0xad, 0xde, - 0x23, 0x51, 0xd7, 0x2a, 0xa6, 0xd7, 0x7b, 0x35, 0xab, 0x9f, 0x89, 0xde, 0x66, 0x94, 0xf9, 0x04, - 0xe7, 0xa8, 0xc7, 0x81, 0x19, 0x22, 0xf3, 0x60, 0x3e, 0x3a, 0xe8, 0xa7, 0x40, 0x48, 0xe0, 0xb3, - 0xd7, 0x41, 0x4e, 0x41, 0x17, 0xb5, 0xf8, 0xc2, 0xa7, 0x12, 0x83, 0x60, 0xbe, 0x01, 0xfd, 0xcb, - 0x8e, 0x7b, 0xb1, 0xe5, 0x9b, 0x3e, 0xd4, 0xfe, 0x59, 0x22, 0xd7, 0xe5, 0x31, 0xd1, 0x4f, 0x1a, - 0xe0, 0x04, 0xa9, 0x10, 0xcd, 0x88, 0xfb, 0x6f, 0x52, 0x91, 0xeb, 0x86, 0x0a, 0x81, 0xc9, 0x67, - 0x1c, 0xfc, 0x54, 0x7b, 0xe9, 0xd0, 0xa0, 0x4f, 0xd2, 0x90, 0x49, 0x03, 0x95, 0x0c, 0xcb, 0x60, - 0xfc, 0xfd, 0x78, 0xda, 0x47, 0x85, 0xcc, 0x6a, 0x31, 0x9a, 0x47, 0xd3, 0x15, 0x7c, 0xf8, 0x51, - 0x20, 0x5f, 0xd9, 0x35, 0x7d, 0xed, 0xdd, 0x32, 0x00, 0xe5, 0x6e, 0x77, 0x9d, 0xf8, 0x80, 0xb3, - 0x0e, 0x69, 0x67, 0xc1, 0x7c, 0x67, 0xd7, 0x8c, 0x6e, 0xce, 0x20, 0xfd, 0x01, 0x97, 0xa6, 0x3e, - 0x3e, 0x72, 0x26, 0x27, 0x52, 0xd5, 0x06, 0x60, 0x42, 0x65, 0x50, 0xda, 0xa1, 0xa3, 0x39, 0x1f, - 0x0a, 0x33, 0xf1, 0x08, 0x1d, 0xfa, 0x7c, 0x29, 0x62, 0x2f, 0x7e, 0x0e, 0x47, 0x49, 0x87, 0x07, - 0x6c, 0xa2, 0x84, 0x94, 0x27, 0xbd, 0xc5, 0x02, 0x7a, 0x24, 0xf3, 0x35, 0x95, 0xd0, 0xb5, 0xaa, - 0xde, 0xb5, 0x02, 0xd1, 0xd2, 0x80, 0x59, 0xda, 0x0b, 0x73, 0xe9, 0xe0, 0x4b, 0x16, 0xdc, 0x53, - 0xc0, 0x02, 0xec, 0x5a, 0x3e, 0x0c, 0x6a, 0x49, 0x05, 0x98, 0x04, 0x31, 0xff, 0x81, 0xf6, 0x6c, - 0xe1, 0xa0, 0x6b, 0x58, 0xa0, 0x07, 0x6b, 0x14, 0xd3, 0xfe, 0xc4, 0xc2, 0xa8, 0x89, 0xd1, 0xcc, - 0x1e, 0xac, 0x1f, 0x93, 0xc1, 0xd5, 0x6d, 0x67, 0x67, 0xa7, 0x07, 0x03, 0x31, 0x41, 0xe2, 0x9d, - 0xa9, 0x99, 0x93, 0x84, 0x0b, 0xef, 0x04, 0x39, 0xf7, 0x59, 0xe1, 0x51, 0x32, 0xf4, 0xc0, 0x9f, - 0x98, 0x4a, 0x9c, 0x45, 0x61, 0x71, 0x0d, 0xe5, 0x33, 0x06, 0x05, 0xb1, 0x80, 0xcf, 0xc2, 0x64, - 0xb3, 0x07, 0xe2, 0x4b, 0x12, 0x58, 0x20, 0xf7, 0x22, 0x06, 0x0a, 0x7a, 0xcf, 0x04, 0x01, 0xd0, - 0xbe, 0x9b, 0x13, 0xf5, 0xb3, 0xc5, 0x32, 0xe1, 0x38, 0x89, 0x11, 0xb1, 0x58, 0x50, 0x95, 0x91, - 0xe4, 0xa6, 0x70, 0x53, 0x67, 0x1e, 0xcc, 0xad, 0xc2, 0xa0, 0xa5, 0x79, 0xda, 0xfb, 0x53, 0xf6, - 0x44, 0x67, 0xc1, 0x3c, 0xbe, 0x1c, 0xac, 0x49, 0x8f, 0x49, 0x92, 0x55, 0x33, 0x2e, 0x4d, 0xbd, - 0x1e, 0x2c, 0x5c, 0x80, 0xdb, 0x8e, 0x0b, 0x9b, 0xdc, 0x59, 0x4a, 0x3e, 0x71, 0x78, 0x78, 0x3a, - 0xf5, 0x46, 0x70, 0x9c, 0x3a, 0xba, 0x2f, 0xa3, 0xb9, 0xbe, 0xe9, 0x5e, 0xa1, 0x07, 0xd3, 0x06, - 0x93, 0xb5, 0xbf, 0x60, 0x1b, 0xcc, 0x32, 0x8f, 0xe2, 0xcd, 0x07, 0xc5, 0xce, 0x54, 0x3a, 0x66, - 0x74, 0x7a, 0x02, 0x28, 0x51, 0x1d, 0x09, 0x0c, 0xba, 0xa4, 0x1e, 0x34, 0xcc, 0xab, 0x3e, 0x01, - 0xcc, 0x22, 0x11, 0x61, 0xbb, 0x81, 0x76, 0xbd, 0xa7, 0x87, 0x7c, 0x88, 0xdf, 0x1b, 0x51, 0x56, - 0xed, 0x97, 0x42, 0x9d, 0xd1, 0x39, 0x9d, 0x79, 0x6c, 0x1a, 0xe6, 0xa7, 0x72, 0x91, 0xbc, 0xc2, - 0x94, 0xbf, 0x7c, 0xa5, 0xd6, 0xf5, 0xb4, 0xf5, 0x74, 0x5a, 0x73, 0x06, 0x80, 0xb0, 0xf9, 0x05, - 0x81, 0x33, 0x98, 0x14, 0x3e, 0x36, 0x7e, 0xe2, 0x51, 0xc0, 0x41, 0x71, 0x60, 0x76, 0x26, 0x0b, - 0xa8, 0xe0, 0x11, 0x42, 0x11, 0x4e, 0xb2, 0x47, 0xe7, 0x17, 0xf3, 0xe0, 0xea, 0xf0, 0x84, 0x53, - 0xdd, 0xf4, 0xa2, 0x96, 0x7d, 0x6f, 0x3a, 0x88, 0xb8, 0x23, 0x25, 0x61, 0x73, 0x3c, 0x09, 0x0a, - 0xde, 0xfe, 0x85, 0xd0, 0x11, 0x90, 0x3c, 0x68, 0x6f, 0x94, 0x53, 0x8d, 0x55, 0x43, 0xf9, 0x9b, - 0x70, 0x23, 0xbc, 0x19, 0x9c, 0xb0, 0xf7, 0xf7, 0x42, 0x2c, 0x70, 0x4f, 0x43, 0x7b, 0x96, 0x83, - 0x2f, 0xf8, 0x26, 0x9b, 0x17, 0x6f, 0xb2, 0x29, 0x46, 0x52, 0x91, 0x4a, 0x67, 0xaf, 0x1e, 0x9f, - 0x1d, 0x38, 0x82, 0x56, 0x49, 0xad, 0x14, 0x04, 0x7e, 0x89, 0x85, 0xff, 0x1f, 0x73, 0xa9, 0x7a, - 0xde, 0xd1, 0x27, 0xd7, 0x52, 0xf4, 0x84, 0x47, 0x79, 0x6c, 0xed, 0x75, 0x05, 0xa0, 0xb5, 0x22, - 0x87, 0x1c, 0x0a, 0xea, 0x86, 0x0b, 0x2f, 0x59, 0xf0, 0xb2, 0x37, 0xb0, 0xdf, 0x41, 0xe4, 0x96, - 0x63, 0xe5, 0xf6, 0x8d, 0xbc, 0xa8, 0x43, 0x0d, 0xaf, 0x41, 0x07, 0x8a, 0x8a, 0x69, 0x3b, 0x4f, - 0x07, 0xa5, 0x3e, 0xcd, 0x41, 0xdb, 0x4e, 0x79, 0x3c, 0xaa, 0x28, 0x23, 0x4d, 0x35, 0x42, 0x92, - 0xda, 0xdf, 0xe6, 0xc0, 0x1c, 0xf3, 0x26, 0x7e, 0x47, 0xe0, 0x80, 0x6a, 0x49, 0xc9, 0x33, 0x52, - 0x59, 0x78, 0x46, 0xaa, 0x2e, 0x81, 0x82, 0x27, 0xd4, 0x68, 0x49, 0x36, 0xf5, 0x49, 0x60, 0xbe, - 0x0b, 0xfb, 0xd0, 0xee, 0x42, 0xbb, 0x63, 0x41, 0xef, 0x74, 0x01, 0x8b, 0x25, 0x36, 0x4c, 0x03, - 0x97, 0x59, 0x30, 0x7e, 0x77, 0x3a, 0xac, 0xb2, 0xd7, 0xd2, 0x3f, 0x95, 0xc0, 0x19, 0xa6, 0x95, - 0xac, 0xb8, 0xce, 0x5e, 0x6a, 0x4d, 0x7d, 0x39, 0x3b, 0x1e, 0x6f, 0xf2, 0x9a, 0x7a, 0x57, 0x62, - 0xa3, 0x1c, 0x52, 0x5c, 0x4c, 0xa3, 0x7f, 0x7f, 0x28, 0xdd, 0xa7, 0x71, 0xd2, 0xad, 0x1e, 0x92, - 0xfe, 0x14, 0x0e, 0x84, 0xe7, 0xc1, 0xbc, 0x01, 0xcd, 0x6e, 0x38, 0xd4, 0xfe, 0x11, 0x63, 0x44, - 0x3f, 0x09, 0xe4, 0xfd, 0x68, 0x35, 0xec, 0x91, 0x07, 0x2b, 0xc3, 0x7e, 0x89, 0x1f, 0xf0, 0xa2, - 0x18, 0xfe, 0x48, 0xa8, 0xe1, 0x0c, 0x5a, 0xe0, 0xb2, 0x88, 0x05, 0x9e, 0x1f, 0x66, 0x81, 0x5f, - 0x07, 0xe6, 0x7a, 0xa6, 0x47, 0x1a, 0x4c, 0x78, 0xf7, 0x2f, 0x9b, 0xc4, 0xdf, 0xb2, 0x9f, 0x78, - 0xda, 0x6e, 0x58, 0xd5, 0x0e, 0x1f, 0x91, 0xf8, 0xc3, 0x42, 0x47, 0xeb, 0x46, 0x95, 0x9d, 0x4e, - 0x23, 0xee, 0x1e, 0x63, 0xe5, 0xee, 0x14, 0x50, 0xd7, 0xf5, 0x56, 0xab, 0xbc, 0x8a, 0x4f, 0xdc, - 0x04, 0x2e, 0x58, 0xdd, 0xb3, 0x37, 0x20, 0xf1, 0x11, 0x84, 0xd5, 0x79, 0x50, 0x0a, 0xf8, 0x53, - 0x8e, 0x91, 0x27, 0x1b, 0xef, 0x38, 0x29, 0x39, 0xed, 0x8b, 0x32, 0x28, 0x6e, 0xda, 0x2e, 0x34, - 0xbb, 0xda, 0xf3, 0x18, 0x5d, 0xfa, 0x41, 0x4e, 0x97, 0x1e, 0x36, 0xac, 0x61, 0xa0, 0x6f, 0x32, - 0xd2, 0x22, 0x3e, 0x1c, 0x59, 0xe2, 0x62, 0x39, 0xcf, 0xcc, 0xe1, 0x71, 0x17, 0x5b, 0x25, 0x8f, - 0x2f, 0x35, 0xf3, 0x3e, 0x40, 0x18, 0xd9, 0xdf, 0x96, 0x81, 0xb2, 0xb1, 0xef, 0xed, 0x72, 0x87, - 0xbe, 0x7f, 0x55, 0x06, 0x0b, 0xc1, 0xb9, 0x98, 0xb6, 0x73, 0x11, 0xda, 0xda, 0x33, 0xb8, 0x1e, - 0xd9, 0x47, 0x69, 0x41, 0x8f, 0x8c, 0x1f, 0xd4, 0x0d, 0x26, 0x34, 0x8c, 0x34, 0xec, 0x58, 0xff, - 0x40, 0x19, 0x4b, 0x1c, 0xfd, 0xa5, 0x0d, 0xfa, 0x6d, 0x14, 0x50, 0x46, 0x7b, 0xb1, 0xf0, 0x3d, - 0x47, 0x23, 0x68, 0x0f, 0xef, 0xde, 0xc5, 0x6e, 0x2e, 0x4a, 0x45, 0x3a, 0x7b, 0x54, 0xaf, 0x03, - 0xa5, 0x40, 0x52, 0xea, 0x0c, 0x90, 0x6b, 0xcd, 0x96, 0x72, 0x4c, 0x9d, 0x03, 0x33, 0x65, 0xbb, - 0xeb, 0x3a, 0x56, 0x57, 0xc9, 0x9d, 0x9d, 0x01, 0x05, 0x7d, 0xaf, 0xef, 0x5f, 0x39, 0xfb, 0x08, - 0xb0, 0xd0, 0xf2, 0x5d, 0x68, 0xee, 0x25, 0xe2, 0x76, 0xfb, 0x6d, 0x60, 0xc6, 0x76, 0xb6, 0xcc, - 0x7d, 0x7f, 0x57, 0x7d, 0xe8, 0x01, 0xab, 0x83, 0x6a, 0x4d, 0x93, 0x46, 0xe3, 0xfc, 0xfa, 0x1d, - 0x78, 0xa5, 0xa3, 0x68, 0x3b, 0xe5, 0x7d, 0x7f, 0x77, 0xf9, 0xda, 0xcf, 0xfc, 0xd9, 0x99, 0xdc, - 0xe7, 0xff, 0xec, 0x4c, 0xee, 0x6b, 0x7f, 0x76, 0x26, 0xf7, 0x53, 0xdf, 0x38, 0x73, 0xec, 0xf3, - 0xdf, 0x38, 0x73, 0xec, 0x4b, 0xdf, 0x38, 0x73, 0xec, 0x87, 0xa5, 0xfe, 0x85, 0x0b, 0x45, 0x4c, - 0xe5, 0x71, 0xff, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4f, 0xb0, 0xbc, 0xab, 0x06, 0x33, 0x02, - 0x00, + 0x59, 0x2f, 0x3c, 0x95, 0x59, 0x55, 0x5d, 0x1d, 0x7d, 0x99, 0x9a, 0xdc, 0xd9, 0x61, 0x36, 0x76, + 0x19, 0x96, 0x61, 0x59, 0xd6, 0x65, 0xe9, 0x85, 0x05, 0x91, 0x5d, 0x16, 0x96, 0xea, 0xea, 0xea, + 0xee, 0xda, 0xad, 0xae, 0x6a, 0xb2, 0xaa, 0x67, 0x18, 0xcf, 0xe1, 0xeb, 0x93, 0x53, 0x15, 0xdd, + 0x9d, 0x3b, 0xd5, 0x99, 0x45, 0x66, 0xf6, 0xcc, 0x36, 0xdf, 0x73, 0xbe, 0x23, 0x22, 0xb0, 0x88, + 0x88, 0xa8, 0x88, 0x88, 0xdc, 0x05, 0x04, 0xe4, 0x7e, 0x13, 0x90, 0x8b, 0x08, 0x82, 0x78, 0x43, + 0x51, 0xb9, 0x08, 0x8f, 0xe0, 0x05, 0xf1, 0x9c, 0x83, 0x1e, 0xfc, 0x14, 0x44, 0x45, 0xbf, 0x27, + 0x2e, 0x99, 0x19, 0x51, 0x5d, 0x99, 0x15, 0x59, 0x5d, 0x59, 0xbd, 0xe8, 0xf7, 0x57, 0x55, 0x46, + 0x46, 0xbe, 0xf1, 0xc6, 0xfb, 0x7b, 0x23, 0xe2, 0x8d, 0x88, 0x37, 0xde, 0x00, 0xa7, 0x7b, 0x17, + 0x6f, 0xed, 0x39, 0xb6, 0x67, 0xbb, 0xb7, 0xb6, 0xed, 0xdd, 0x5d, 0xc3, 0xea, 0xb8, 0x0b, 0xe4, + 0x59, 0x9b, 0x32, 0xac, 0x7d, 0x6f, 0xbf, 0x87, 0xe0, 0x0d, 0xbd, 0x4b, 0xdb, 0xb7, 0x76, 0xcd, + 0x8b, 0xb7, 0xf6, 0x2e, 0xde, 0xba, 0x6b, 0x77, 0x50, 0xd7, 0xff, 0x80, 0x3c, 0xb0, 0xec, 0xf0, + 0xa6, 0xa8, 0x5c, 0x5d, 0xbb, 0x6d, 0x74, 0x5d, 0xcf, 0x76, 0x10, 0xcb, 0x79, 0x2a, 0x2c, 0x12, + 0x5d, 0x46, 0x96, 0xe7, 0x53, 0xb8, 0x6e, 0xdb, 0xb6, 0xb7, 0xbb, 0x88, 0xbe, 0xbb, 0xb8, 0xb7, + 0x75, 0xab, 0xeb, 0x39, 0x7b, 0x6d, 0x8f, 0xbd, 0xbd, 0xbe, 0xff, 0x6d, 0x07, 0xb9, 0x6d, 0xc7, + 0xec, 0x79, 0xb6, 0x43, 0x73, 0x9c, 0xfd, 0xf8, 0x3f, 0x14, 0x80, 0xaa, 0xf7, 0xda, 0xf0, 0xdb, + 0x53, 0x40, 0x2d, 0xf5, 0x7a, 0xf0, 0x93, 0x0a, 0x00, 0x2b, 0xc8, 0x3b, 0x87, 0x1c, 0xd7, 0xb4, + 0x2d, 0x78, 0x1c, 0x4c, 0xe9, 0xe8, 0x19, 0x7b, 0xc8, 0xf5, 0xee, 0xc8, 0xde, 0xff, 0x75, 0x35, + 0x03, 0x5f, 0xaf, 0x80, 0x82, 0x8e, 0xdc, 0x9e, 0x6d, 0xb9, 0x48, 0x7b, 0x0a, 0xc8, 0x21, 0xc7, + 0xb1, 0x9d, 0xd3, 0x99, 0xeb, 0x33, 0x37, 0xcd, 0xdc, 0x76, 0xf3, 0x02, 0xab, 0xfe, 0x82, 0xde, + 0x6b, 0x2f, 0x94, 0x7a, 0xbd, 0x85, 0x90, 0xd2, 0x82, 0xff, 0xd1, 0x42, 0x05, 0x7f, 0xa1, 0xd3, + 0x0f, 0xb5, 0xd3, 0x60, 0xea, 0x32, 0xcd, 0x70, 0x5a, 0xb9, 0x3e, 0x73, 0xd3, 0xb4, 0xee, 0x3f, + 0xe2, 0x37, 0x1d, 0xe4, 0x19, 0x66, 0xd7, 0x3d, 0xad, 0xd2, 0x37, 0xec, 0x11, 0xbe, 0x36, 0x03, + 0x72, 0x84, 0x88, 0x56, 0x06, 0xd9, 0xb6, 0xdd, 0x41, 0xa4, 0xf8, 0xf9, 0xdb, 0x6e, 0x95, 0x2f, + 0x7e, 0xa1, 0x6c, 0x77, 0x90, 0x4e, 0x3e, 0xd6, 0xae, 0x07, 0x33, 0xbe, 0x58, 0x42, 0x36, 0xf8, + 0xa4, 0xb3, 0xb7, 0x81, 0x2c, 0xce, 0xaf, 0x15, 0x40, 0xb6, 0xbe, 0x51, 0xab, 0x15, 0x8f, 0x69, + 0x27, 0xc0, 0xdc, 0x46, 0xfd, 0x9e, 0x7a, 0xe3, 0x7c, 0x7d, 0xb3, 0xa2, 0xeb, 0x0d, 0xbd, 0x98, + 0xd1, 0xe6, 0xc0, 0xf4, 0x62, 0x69, 0x69, 0xb3, 0x5a, 0x5f, 0xdf, 0x68, 0x15, 0x15, 0xf8, 0x4a, + 0x15, 0xcc, 0x37, 0x91, 0xb7, 0x84, 0x2e, 0x9b, 0x6d, 0xd4, 0xf4, 0x0c, 0x0f, 0xc1, 0x17, 0x65, + 0x02, 0x61, 0x6a, 0x1b, 0xb8, 0xd0, 0xe0, 0x15, 0xab, 0xc0, 0x63, 0x0f, 0x54, 0x40, 0xa4, 0xb0, + 0xc0, 0xbe, 0x5e, 0xe0, 0xd2, 0x74, 0x9e, 0xce, 0xd9, 0x47, 0x81, 0x19, 0xee, 0x9d, 0x36, 0x0f, + 0xc0, 0x62, 0xa9, 0x7c, 0xcf, 0x8a, 0xde, 0xd8, 0xa8, 0x2f, 0x15, 0x8f, 0xe1, 0xe7, 0xe5, 0x86, + 0x5e, 0x61, 0xcf, 0x19, 0xf8, 0xdd, 0x0c, 0x07, 0xe6, 0x92, 0x08, 0xe6, 0xc2, 0x70, 0x66, 0x06, + 0x00, 0x0a, 0xdf, 0x10, 0x80, 0xb3, 0x22, 0x80, 0xf3, 0xd8, 0x64, 0xe4, 0xd2, 0x07, 0xe8, 0x39, + 0x0a, 0x28, 0x34, 0x77, 0xf6, 0xbc, 0x8e, 0x7d, 0xc5, 0x82, 0xd3, 0x01, 0x32, 0xf0, 0x9b, 0xbc, + 0x4c, 0x9e, 0x2c, 0xca, 0xe4, 0xa6, 0x83, 0x95, 0x60, 0x14, 0x22, 0xa4, 0xf1, 0xea, 0x40, 0x1a, + 0x25, 0x41, 0x1a, 0x8f, 0x92, 0x25, 0x94, 0xbe, 0x1c, 0xfe, 0x69, 0x11, 0xe4, 0x9a, 0x3d, 0xa3, + 0x8d, 0xe0, 0xef, 0xa8, 0x60, 0xb6, 0x86, 0x8c, 0xcb, 0xa8, 0xd4, 0xeb, 0x39, 0xf6, 0x65, 0x04, + 0xcb, 0xa1, 0xbe, 0x9e, 0x06, 0x53, 0x2e, 0xce, 0x54, 0xed, 0x90, 0x1a, 0x4c, 0xeb, 0xfe, 0xa3, + 0x76, 0x06, 0x00, 0xb3, 0x83, 0x2c, 0xcf, 0xf4, 0x4c, 0xe4, 0x9e, 0x56, 0xae, 0x57, 0x6f, 0x9a, + 0xd6, 0xb9, 0x14, 0xf8, 0x6d, 0x45, 0x56, 0xc7, 0x08, 0x17, 0x0b, 0x3c, 0x07, 0x11, 0x52, 0x7d, + 0x9d, 0x22, 0xa3, 0x63, 0x43, 0xc9, 0x25, 0x93, 0xed, 0xdb, 0x32, 0xc9, 0x85, 0x8b, 0x73, 0xd4, + 0x1b, 0x9b, 0xcd, 0x8d, 0xf2, 0xea, 0x66, 0x73, 0xbd, 0x54, 0xae, 0x14, 0x91, 0x76, 0x12, 0x14, + 0xc9, 0xdf, 0xcd, 0x6a, 0x73, 0x73, 0xa9, 0x52, 0xab, 0xb4, 0x2a, 0x4b, 0xc5, 0x2d, 0x4d, 0x03, + 0xf3, 0x7a, 0xe5, 0xa9, 0x1b, 0x95, 0x66, 0x6b, 0x73, 0xb9, 0x54, 0xad, 0x55, 0x96, 0x8a, 0xdb, + 0xf8, 0xe3, 0x5a, 0x75, 0xad, 0xda, 0xda, 0xd4, 0x2b, 0xa5, 0xf2, 0x6a, 0x65, 0xa9, 0xb8, 0xa3, + 0x3d, 0x08, 0x5c, 0x55, 0x6f, 0x6c, 0x96, 0xd6, 0xd7, 0xf5, 0xc6, 0xb9, 0xca, 0x26, 0xfb, 0xa2, + 0x59, 0x34, 0x69, 0x41, 0xad, 0xcd, 0xe6, 0x6a, 0x49, 0xaf, 0x94, 0x16, 0x6b, 0x95, 0xe2, 0xbd, + 0xf0, 0xd9, 0x2a, 0x98, 0x5b, 0x33, 0x2e, 0xa1, 0xe6, 0x8e, 0xe1, 0x20, 0xe3, 0x62, 0x17, 0xc1, + 0x87, 0x49, 0xe0, 0x09, 0x7f, 0x87, 0xc7, 0xab, 0x22, 0xe2, 0x75, 0xeb, 0x00, 0x01, 0x0b, 0x45, + 0x44, 0x00, 0xf6, 0x4f, 0x41, 0x33, 0x58, 0x15, 0x00, 0x7b, 0x5c, 0x42, 0x7a, 0xc9, 0x10, 0xfb, + 0xd1, 0x07, 0x00, 0x62, 0xf0, 0x0f, 0x54, 0x30, 0x5b, 0xb5, 0x2e, 0x9b, 0x1e, 0x2a, 0xef, 0x18, + 0xd6, 0x36, 0x82, 0x5d, 0x99, 0x46, 0xb5, 0x02, 0x66, 0x7a, 0xc8, 0xd9, 0x35, 0x5d, 0x3c, 0x76, + 0xb9, 0xa4, 0x72, 0xf3, 0xb7, 0x3d, 0x3c, 0x90, 0x16, 0xb1, 0x15, 0x16, 0xd6, 0x0d, 0xc7, 0x33, + 0xdb, 0x66, 0xcf, 0xb0, 0xbc, 0xf5, 0x30, 0xb3, 0xce, 0x7f, 0x09, 0xff, 0x30, 0x61, 0xeb, 0xe3, + 0x59, 0x8d, 0x00, 0xf3, 0xdf, 0x33, 0xf2, 0xad, 0x2f, 0x86, 0x5c, 0x32, 0x2c, 0x7f, 0x7c, 0xe2, + 0x58, 0x5e, 0x03, 0xae, 0xae, 0xd6, 0xcb, 0x0d, 0x5d, 0xaf, 0x94, 0x5b, 0x9b, 0xeb, 0x15, 0x7d, + 0xad, 0xda, 0x6c, 0x56, 0x1b, 0xf5, 0x66, 0xd1, 0x84, 0x5f, 0xcf, 0x81, 0x79, 0x5a, 0xb3, 0x15, + 0x64, 0x21, 0x07, 0x8f, 0xed, 0x6f, 0xcc, 0xc8, 0xc0, 0x7a, 0x3b, 0x00, 0x26, 0xf9, 0xae, 0xb5, + 0xdf, 0x43, 0x0c, 0xd5, 0x6b, 0xfa, 0x50, 0xad, 0x06, 0x19, 0x74, 0x2e, 0x73, 0xbf, 0x46, 0xa8, + 0x23, 0x6b, 0xc4, 0x9b, 0xb2, 0x9c, 0x46, 0x2c, 0x8b, 0x1a, 0xf1, 0xe8, 0x48, 0x08, 0xfd, 0x8a, + 0x46, 0x98, 0x71, 0xd7, 0x81, 0x69, 0xca, 0x6b, 0xd9, 0xec, 0x30, 0xf8, 0xc2, 0x04, 0xed, 0x06, + 0x30, 0x47, 0x1f, 0x96, 0xcd, 0x2e, 0xba, 0x07, 0xed, 0x33, 0x83, 0x4e, 0x4c, 0xec, 0x13, 0x4e, + 0xf6, 0x10, 0xc2, 0xc9, 0x8d, 0x2c, 0x9c, 0x9f, 0x08, 0x46, 0x96, 0xaa, 0xa0, 0xdb, 0x3f, 0x98, + 0x54, 0x30, 0xc9, 0xb4, 0xfb, 0x25, 0x0f, 0x84, 0xb1, 0xe5, 0xc0, 0x10, 0x62, 0xc2, 0xef, 0x29, + 0x60, 0xa6, 0xe9, 0xd9, 0x3d, 0xdc, 0x1f, 0x9b, 0xd6, 0xb6, 0xdc, 0x00, 0xf2, 0x69, 0xbe, 0xcb, + 0x29, 0x8b, 0x0a, 0xf6, 0xa8, 0x01, 0x72, 0xe4, 0x0a, 0x88, 0xe8, 0x71, 0xbe, 0x1d, 0xf4, 0x38, + 0xcb, 0x02, 0x2a, 0xb7, 0x25, 0xa2, 0xf6, 0x7d, 0x38, 0x78, 0xbc, 0x2c, 0x0b, 0x8a, 0xbe, 0x9a, + 0x79, 0xe5, 0x3d, 0xc7, 0x41, 0x96, 0x27, 0x07, 0xc2, 0x9f, 0xa9, 0x1c, 0x08, 0xab, 0x22, 0x08, + 0xb7, 0xc5, 0x28, 0xb3, 0x5f, 0xca, 0x7f, 0xf0, 0x76, 0xfe, 0xb1, 0x40, 0xa3, 0xee, 0x11, 0x34, + 0xea, 0x87, 0x92, 0x8b, 0x26, 0x99, 0x5a, 0xad, 0x8e, 0xa0, 0x55, 0x27, 0x41, 0x11, 0x1b, 0x7d, + 0xe5, 0x56, 0xf5, 0x5c, 0x65, 0xb3, 0x5a, 0x3f, 0x57, 0x6d, 0x55, 0x8a, 0x08, 0xbe, 0x58, 0x0d, + 0x07, 0x21, 0x6f, 0x85, 0x4c, 0x5d, 0xa4, 0x34, 0xe3, 0x8b, 0xca, 0x68, 0xfd, 0x3f, 0x2d, 0x23, + 0x3d, 0xbd, 0xe0, 0x30, 0x91, 0xef, 0x7b, 0x07, 0x32, 0x95, 0x0c, 0x91, 0xbb, 0x47, 0x40, 0xe4, + 0x14, 0xd0, 0xaa, 0xf5, 0x73, 0xa5, 0x5a, 0x75, 0x89, 0xb6, 0xf3, 0xcd, 0xd6, 0x85, 0x75, 0x8c, + 0xc9, 0xcf, 0x04, 0xc6, 0x9e, 0x8e, 0x2e, 0xdb, 0x97, 0x24, 0x2d, 0xee, 0xaf, 0x8c, 0x64, 0xa3, + 0xd1, 0x12, 0x22, 0x7a, 0xcc, 0x1f, 0x57, 0x92, 0xda, 0x68, 0x03, 0xc9, 0x3d, 0x90, 0x46, 0xb1, + 0x03, 0xdd, 0xe3, 0xf6, 0x80, 0x5e, 0x74, 0xe0, 0x28, 0xf6, 0x6f, 0x59, 0x00, 0x68, 0x25, 0xcf, + 0x99, 0xe8, 0x0a, 0x5c, 0x0b, 0x31, 0x11, 0xd4, 0x36, 0x33, 0x54, 0x6d, 0x95, 0x41, 0x6a, 0xfb, + 0x6a, 0xde, 0x9e, 0x5a, 0x14, 0xd1, 0xbb, 0x25, 0x52, 0xdc, 0x98, 0x93, 0xe8, 0x25, 0x31, 0x5f, + 0x51, 0x14, 0xd1, 0x7c, 0xbc, 0x0e, 0x4c, 0x93, 0xbf, 0x75, 0x63, 0x17, 0xb1, 0x36, 0x14, 0x26, + 0x68, 0x67, 0xc1, 0x2c, 0xcd, 0xd8, 0xb6, 0x2d, 0x5c, 0x9f, 0x2c, 0xc9, 0x20, 0xa4, 0x61, 0x10, + 0xdb, 0x0e, 0x32, 0x3c, 0xdb, 0x21, 0x34, 0x72, 0x14, 0x44, 0x2e, 0x49, 0xbb, 0x05, 0x9c, 0x30, + 0x5d, 0xd2, 0xaa, 0x36, 0x5c, 0xe4, 0x50, 0x66, 0x4f, 0xe7, 0xaf, 0xcf, 0xdc, 0x54, 0xd0, 0x0f, + 0xbe, 0xe8, 0xeb, 0xcb, 0xa7, 0x12, 0xf4, 0xe5, 0xf0, 0x1b, 0x41, 0x73, 0xaf, 0x08, 0x2a, 0xfa, + 0x98, 0x24, 0x32, 0x4b, 0xa6, 0xa0, 0x97, 0x47, 0xeb, 0x7c, 0x69, 0x97, 0xbb, 0x89, 0xd5, 0x6a, + 0x99, 0x2c, 0x9c, 0x21, 0xd6, 0x01, 0xe0, 0x54, 0x9c, 0xb7, 0xdc, 0xa8, 0xb7, 0x2a, 0xf5, 0x56, + 0x71, 0x6b, 0xa0, 0xea, 0x6e, 0xc3, 0xd7, 0x65, 0x41, 0xf6, 0x6e, 0xdb, 0xb4, 0xe0, 0x73, 0x32, + 0x82, 0xee, 0x59, 0xc8, 0xbb, 0x62, 0x3b, 0x97, 0x82, 0x1e, 0x21, 0x4c, 0x88, 0x57, 0x82, 0x50, + 0x67, 0xd5, 0xa1, 0x3a, 0x9b, 0x1d, 0xa4, 0xb3, 0x3f, 0xcd, 0x5b, 0x07, 0x77, 0x8a, 0x3a, 0x7b, + 0xe3, 0x00, 0xf9, 0x63, 0xe6, 0x23, 0x7a, 0x9a, 0x4f, 0x05, 0x3d, 0xcd, 0x5d, 0x02, 0x8c, 0x8f, + 0x94, 0x23, 0x93, 0x0c, 0xc0, 0x2f, 0xa5, 0xda, 0xc3, 0x0c, 0x82, 0x7a, 0x3b, 0x02, 0xea, 0x9d, + 0x01, 0x9d, 0x8f, 0x79, 0xb0, 0x8f, 0xba, 0xf7, 0x60, 0x7f, 0x74, 0x49, 0xbb, 0x1a, 0x9c, 0x58, + 0xaa, 0x2e, 0x2f, 0x57, 0xf4, 0x4a, 0xbd, 0xb5, 0x59, 0xaf, 0xb4, 0xce, 0x37, 0xf4, 0x7b, 0x8a, + 0x5d, 0xf8, 0x5a, 0x15, 0x00, 0x2c, 0xa1, 0xb2, 0x61, 0xb5, 0x51, 0x57, 0x6e, 0xe8, 0xf8, 0x5b, + 0x25, 0x59, 0xe7, 0x13, 0xd2, 0x8f, 0x80, 0xf3, 0x15, 0x8a, 0x7c, 0xab, 0x8c, 0x24, 0x96, 0x0c, + 0xd4, 0x37, 0x3f, 0x10, 0x26, 0x3f, 0x57, 0x81, 0xe3, 0x3e, 0x3d, 0x96, 0x7d, 0xf0, 0xa2, 0xda, + 0xdb, 0xb3, 0x60, 0x9e, 0xc1, 0xe2, 0xaf, 0x92, 0xde, 0x2f, 0x35, 0xf5, 0x87, 0xa0, 0xc0, 0x16, + 0x45, 0xfd, 0x71, 0x24, 0x78, 0x1e, 0xdf, 0xdc, 0xfe, 0xc5, 0x6a, 0x32, 0xdb, 0x4e, 0xac, 0x49, + 0x84, 0x4a, 0xfc, 0x5a, 0x82, 0x39, 0x71, 0x2c, 0xc1, 0x64, 0x6a, 0xf1, 0xc9, 0x54, 0xd5, 0x62, + 0x00, 0xde, 0x31, 0x4b, 0x3e, 0x87, 0x68, 0xed, 0xf0, 0x33, 0x6a, 0xa0, 0x31, 0x4b, 0xa8, 0xdd, + 0x35, 0x2d, 0x04, 0xef, 0x3a, 0xa4, 0xc2, 0x88, 0x6b, 0xea, 0xf2, 0x38, 0xb3, 0xf2, 0x23, 0x70, + 0x7e, 0x4d, 0x72, 0x9c, 0x07, 0x13, 0xfc, 0x0f, 0xdc, 0xfc, 0xbf, 0xa2, 0x82, 0x13, 0x5c, 0x43, + 0xd4, 0xd1, 0xee, 0xd8, 0xf6, 0x49, 0x7e, 0x94, 0x6f, 0xbb, 0x55, 0x11, 0xd3, 0x41, 0x66, 0xfb, + 0x01, 0x36, 0x22, 0x60, 0x7d, 0x73, 0x00, 0x6b, 0x4d, 0x80, 0xf5, 0x09, 0x23, 0xd0, 0x4c, 0x86, + 0xec, 0x3b, 0x52, 0x45, 0xf6, 0x1a, 0x70, 0xf5, 0x7a, 0x49, 0x6f, 0x55, 0xcb, 0xd5, 0xf5, 0x12, + 0x1e, 0x47, 0xb9, 0x21, 0x3b, 0x62, 0x5e, 0x20, 0x82, 0x3e, 0x10, 0xdf, 0x8f, 0x66, 0xc1, 0x75, + 0x83, 0x3b, 0x5a, 0xb6, 0x7a, 0x6f, 0xca, 0x40, 0xbd, 0x04, 0xa6, 0xda, 0x24, 0x3b, 0xc5, 0x99, + 0xdf, 0x18, 0x8f, 0xe9, 0xcb, 0x69, 0x09, 0xba, 0xff, 0x29, 0x7c, 0x37, 0xaf, 0x10, 0x2d, 0x51, + 0x21, 0x9e, 0x1c, 0x0f, 0xde, 0x01, 0xbe, 0x23, 0x74, 0xe3, 0xb3, 0x81, 0x6e, 0x9c, 0x17, 0x74, + 0xa3, 0x7c, 0x38, 0xf2, 0xc9, 0xd4, 0xe4, 0xb7, 0x1f, 0x08, 0x1d, 0x40, 0xa4, 0x36, 0x99, 0xd1, + 0xa3, 0xc2, 0xc0, 0xee, 0xfe, 0x55, 0x2a, 0xc8, 0x2f, 0xa1, 0x2e, 0xf2, 0x24, 0x27, 0xff, 0x7f, + 0xa7, 0xc8, 0x6e, 0x37, 0x53, 0x18, 0x28, 0xed, 0xe8, 0x65, 0x18, 0xcf, 0xdc, 0x45, 0xae, 0x67, + 0xec, 0xf6, 0x88, 0xa8, 0x55, 0x3d, 0x4c, 0x80, 0x3f, 0xa6, 0xc8, 0x6c, 0x46, 0xc7, 0x14, 0xf3, + 0x1f, 0x63, 0x51, 0xfb, 0x73, 0x0a, 0x28, 0x34, 0x91, 0xd7, 0x70, 0x3a, 0xc8, 0x81, 0xcd, 0x10, + 0xa3, 0xeb, 0xc1, 0x0c, 0x01, 0x05, 0x4f, 0x33, 0x03, 0x9c, 0xf8, 0x24, 0xed, 0x46, 0x30, 0x1f, + 0x3c, 0x92, 0xcf, 0x59, 0x37, 0xde, 0x97, 0x0a, 0xbf, 0x95, 0x91, 0xf5, 0x91, 0x61, 0x6b, 0xd6, + 0x8c, 0x9b, 0x88, 0x56, 0x2a, 0xe7, 0xef, 0x12, 0x4b, 0x2a, 0x7d, 0x37, 0x82, 0x77, 0x2a, 0x00, + 0x6c, 0x58, 0xae, 0x2f, 0xd7, 0x47, 0x26, 0x90, 0x2b, 0xfc, 0xc7, 0x4c, 0xb2, 0x59, 0x4c, 0x58, + 0x4e, 0x84, 0xc4, 0x7e, 0x29, 0xc1, 0xda, 0x42, 0x24, 0xb1, 0xf4, 0x65, 0xf6, 0x85, 0xe3, 0x20, + 0x7f, 0xde, 0xe8, 0x76, 0x91, 0x07, 0x5f, 0xa9, 0x82, 0x7c, 0xd9, 0x41, 0x86, 0x87, 0x20, 0x0a, + 0x45, 0x07, 0x41, 0xc1, 0xb1, 0x6d, 0x6f, 0xdd, 0xf0, 0x76, 0x98, 0xdc, 0x82, 0x67, 0xed, 0x09, + 0xe0, 0x41, 0x5b, 0x7b, 0xdd, 0xae, 0x87, 0xee, 0xf3, 0xd6, 0x1d, 0x73, 0xd7, 0x70, 0xf6, 0x6b, + 0x86, 0xb5, 0xbd, 0x67, 0x6c, 0x23, 0xc6, 0x5e, 0xd4, 0x6b, 0xe6, 0xc8, 0xf5, 0x2b, 0x7c, 0xc7, + 0x73, 0x97, 0x28, 0xf4, 0x1f, 0x10, 0xe4, 0x44, 0x59, 0x5c, 0xa0, 0xec, 0x45, 0xf4, 0x3c, 0x10, + 0x14, 0x76, 0x2d, 0xb4, 0x6b, 0x5b, 0x66, 0xdb, 0xb7, 0x56, 0xfd, 0x67, 0xf8, 0xf1, 0x00, 0x8d, + 0x45, 0x01, 0x8d, 0x05, 0xe9, 0x52, 0x92, 0x41, 0xd1, 0x1c, 0xa1, 0xdf, 0x79, 0x08, 0xb8, 0x96, + 0x76, 0x23, 0x9b, 0xad, 0xc6, 0x66, 0x59, 0xaf, 0x94, 0x5a, 0x95, 0xcd, 0x5a, 0xa3, 0x5c, 0xaa, + 0x6d, 0xea, 0x95, 0xf5, 0x46, 0x11, 0xe1, 0xd9, 0xf9, 0x94, 0x8e, 0xda, 0xf6, 0x65, 0xe4, 0xc0, + 0x67, 0x65, 0xe4, 0x20, 0x8a, 0x11, 0x4a, 0x1c, 0x7c, 0xaa, 0x0c, 0x7c, 0x3f, 0x2d, 0xed, 0x87, + 0xc7, 0x04, 0xcb, 0x98, 0x8f, 0x68, 0x31, 0xbf, 0x21, 0xd5, 0xc7, 0xc4, 0x92, 0x7a, 0x00, 0x80, + 0xf4, 0x0f, 0x0a, 0x98, 0x2a, 0xdb, 0xd6, 0x65, 0xe4, 0x78, 0xfc, 0x24, 0x8b, 0xc7, 0x21, 0xd3, + 0x87, 0xc3, 0x69, 0x30, 0x85, 0x2c, 0xcf, 0xb1, 0x7b, 0xfe, 0x2c, 0xcb, 0x7f, 0x84, 0x6f, 0x4c, + 0x2a, 0x61, 0x56, 0x72, 0xf4, 0xb2, 0xee, 0xe0, 0x82, 0x04, 0xf6, 0xd4, 0xbe, 0xb6, 0xf3, 0xda, + 0x24, 0xb8, 0x0c, 0x66, 0x20, 0xfd, 0x7e, 0xec, 0xab, 0x2a, 0x98, 0xa3, 0xed, 0xb6, 0x89, 0x88, + 0x59, 0x08, 0x1b, 0xfc, 0x3a, 0x67, 0x9f, 0xf0, 0x57, 0x8f, 0x09, 0xe2, 0xcf, 0x1b, 0xbd, 0x5e, + 0xb0, 0xb8, 0xbe, 0x7a, 0x4c, 0x67, 0xcf, 0x54, 0xcd, 0x17, 0xf3, 0x20, 0x6b, 0xec, 0x79, 0x3b, + 0xf0, 0x7b, 0xd2, 0x33, 0x5e, 0xa1, 0x1f, 0x61, 0xfc, 0x44, 0x40, 0x72, 0x12, 0xe4, 0x3c, 0xfb, + 0x12, 0xf2, 0xe5, 0x40, 0x1f, 0x30, 0x1c, 0x46, 0xaf, 0xd7, 0x22, 0x2f, 0x18, 0x1c, 0xfe, 0x33, + 0x36, 0xb0, 0x8c, 0x76, 0xdb, 0xde, 0xb3, 0xbc, 0xaa, 0xbf, 0xc0, 0x1e, 0x26, 0xc0, 0x2f, 0x48, + 0xed, 0x60, 0x49, 0x30, 0x98, 0x0c, 0xb2, 0x8b, 0x23, 0x34, 0xa5, 0x05, 0x70, 0x73, 0x69, 0x7d, + 0x7d, 0xb3, 0xd5, 0xb8, 0xa7, 0x52, 0x0f, 0xad, 0xdd, 0xcd, 0x6a, 0x7d, 0xb3, 0xb5, 0x5a, 0xd9, + 0x2c, 0x6f, 0xe8, 0x64, 0x71, 0xb2, 0x54, 0x2e, 0x37, 0x36, 0xea, 0xad, 0x22, 0x82, 0x6f, 0x55, + 0xc0, 0x6c, 0xb9, 0x6b, 0xbb, 0x01, 0xc2, 0x0f, 0x09, 0x11, 0x0e, 0xc4, 0x98, 0xe1, 0xc4, 0x08, + 0xff, 0x25, 0x23, 0xeb, 0x47, 0xe6, 0x0b, 0x84, 0x23, 0x1f, 0xd1, 0x4b, 0xbd, 0x51, 0xca, 0x8f, + 0x6c, 0x38, 0xbd, 0xf4, 0x9b, 0xc4, 0xaf, 0x37, 0xc0, 0x54, 0x89, 0x2a, 0x06, 0xfc, 0xb3, 0x0c, + 0xc8, 0x97, 0x6d, 0x6b, 0xcb, 0xdc, 0xc6, 0x16, 0x24, 0xb2, 0x8c, 0x8b, 0x5d, 0xb4, 0x64, 0x78, + 0xc6, 0x65, 0x13, 0x5d, 0x21, 0x15, 0x28, 0xe8, 0x7d, 0xa9, 0x98, 0x29, 0x96, 0x82, 0x2e, 0xee, + 0x6d, 0x13, 0xa6, 0x0a, 0x3a, 0x9f, 0x84, 0xc7, 0x0f, 0xfa, 0xb8, 0xee, 0x20, 0x07, 0x75, 0x91, + 0xe1, 0x12, 0x37, 0x2b, 0x0b, 0x75, 0x89, 0xd2, 0x16, 0xf4, 0xa8, 0xd7, 0xda, 0x59, 0x30, 0x4b, + 0x5f, 0x11, 0xfb, 0xc7, 0x25, 0x6a, 0x5c, 0xd0, 0x85, 0x34, 0xed, 0x51, 0x20, 0x87, 0xee, 0xf3, + 0x1c, 0xe3, 0x74, 0x87, 0xe0, 0xf5, 0xa0, 0x05, 0xea, 0x48, 0xbe, 0xe0, 0x3b, 0x92, 0x2f, 0x34, + 0x89, 0x9b, 0xb9, 0x4e, 0x73, 0xc1, 0xff, 0x53, 0x08, 0xac, 0x97, 0xcf, 0xa9, 0xa1, 0x62, 0x68, + 0x20, 0x6b, 0x19, 0xbb, 0x88, 0xe9, 0x05, 0xf9, 0xaf, 0xdd, 0x0c, 0x8e, 0x1b, 0x97, 0x0d, 0xcf, + 0x70, 0x6a, 0x76, 0xdb, 0xe8, 0x92, 0x61, 0xd3, 0x6f, 0xf9, 0xfd, 0x2f, 0xc8, 0x7e, 0x97, 0x67, + 0x3b, 0x88, 0xe4, 0xf2, 0xf7, 0xbb, 0xfc, 0x04, 0x4c, 0xdd, 0x6c, 0xdb, 0x16, 0xe1, 0x5f, 0xd5, + 0xc9, 0x7f, 0x2c, 0x95, 0x8e, 0xe9, 0xe2, 0x8a, 0x10, 0x2a, 0x75, 0xba, 0x9f, 0xd2, 0xdc, 0xb7, + 0xda, 0x64, 0xaf, 0xab, 0xa0, 0x47, 0xbd, 0xd6, 0x16, 0xc1, 0x0c, 0xdb, 0x7d, 0x59, 0xc3, 0x7a, + 0x95, 0x27, 0x7a, 0x75, 0xbd, 0xe8, 0xa6, 0x4b, 0xf1, 0x5c, 0xa8, 0x87, 0xf9, 0x74, 0xfe, 0x23, + 0xed, 0x29, 0xe0, 0x5a, 0xf6, 0x58, 0xde, 0x73, 0x3d, 0x7b, 0x97, 0x82, 0xbe, 0x6c, 0x76, 0x69, + 0x0d, 0xa6, 0x48, 0x0d, 0xe2, 0xb2, 0x68, 0xb7, 0x81, 0x93, 0x3d, 0x07, 0x6d, 0x21, 0xe7, 0x82, + 0xb1, 0xbb, 0x77, 0x5f, 0xcb, 0x31, 0x2c, 0xb7, 0x67, 0x3b, 0xde, 0xe9, 0x02, 0x61, 0x7e, 0xe0, + 0x3b, 0xed, 0x16, 0x70, 0xe2, 0x5e, 0xd7, 0xb6, 0x4a, 0x3d, 0xb3, 0x66, 0xba, 0x1e, 0xb2, 0x4a, + 0x9d, 0x8e, 0x73, 0x7a, 0x9a, 0x94, 0x75, 0xf0, 0x85, 0x76, 0x03, 0x98, 0xbb, 0xd7, 0x36, 0xad, + 0xa6, 0xe7, 0x20, 0x63, 0x77, 0xc3, 0xe9, 0x9e, 0x06, 0x74, 0x83, 0x48, 0x48, 0x64, 0x9d, 0x6f, + 0x01, 0xe4, 0x29, 0x24, 0xf0, 0x45, 0x39, 0x69, 0xaf, 0x7f, 0x26, 0xa4, 0x58, 0x6b, 0xf1, 0xd1, + 0x60, 0x8a, 0xf5, 0x9a, 0x04, 0xfc, 0x99, 0xdb, 0x4e, 0xf5, 0x2d, 0x90, 0x30, 0x2a, 0xba, 0x9f, + 0x4d, 0x7b, 0x2c, 0xc8, 0xb7, 0x89, 0xa8, 0x88, 0x1e, 0xcc, 0xdc, 0x76, 0xed, 0xe0, 0x42, 0x49, + 0x16, 0x9d, 0x65, 0x85, 0x5f, 0x54, 0xa5, 0x0e, 0x0a, 0xc4, 0x71, 0x9c, 0xac, 0xa7, 0xf8, 0x86, + 0x32, 0x42, 0x57, 0x7c, 0x0b, 0xb8, 0x89, 0xf5, 0xb3, 0xcc, 0xa6, 0x59, 0xda, 0x5c, 0xdc, 0xf0, + 0x67, 0xb5, 0xd8, 0xd2, 0x69, 0xb6, 0x4a, 0x7a, 0x6b, 0xb3, 0xde, 0x58, 0xc2, 0xb3, 0xe1, 0x9b, + 0xc1, 0x8d, 0x43, 0x72, 0x57, 0x5a, 0x9b, 0xf5, 0xd2, 0x5a, 0xa5, 0xb8, 0x25, 0xda, 0x4b, 0xcd, + 0x56, 0x63, 0x7d, 0x53, 0xdf, 0xa8, 0xd7, 0xab, 0xf5, 0x15, 0x4a, 0x0c, 0x1b, 0xa8, 0xa7, 0xc2, + 0x0c, 0xe7, 0xf5, 0x6a, 0xab, 0xb2, 0x59, 0x6e, 0xd4, 0x97, 0xab, 0x2b, 0x45, 0x73, 0x98, 0xb1, + 0x75, 0xaf, 0x76, 0x3d, 0xb8, 0x4e, 0xe0, 0xa4, 0xda, 0xa8, 0xe3, 0x29, 0x7a, 0xb9, 0x54, 0x2f, + 0x57, 0xf0, 0x7c, 0xfc, 0x92, 0x06, 0xc1, 0xd5, 0x94, 0xdc, 0xe6, 0x72, 0xb5, 0xc6, 0xef, 0xaa, + 0x7d, 0x3a, 0xa3, 0x9d, 0x06, 0x57, 0xf1, 0xef, 0x98, 0x3b, 0x45, 0xf1, 0xb7, 0x32, 0xda, 0x0d, + 0xe0, 0x21, 0xc2, 0x57, 0x74, 0x83, 0x6c, 0xb3, 0xba, 0xb4, 0xb9, 0x56, 0x6d, 0xae, 0x95, 0x5a, + 0xe5, 0xd5, 0xe2, 0x67, 0xc8, 0xf4, 0x25, 0xb0, 0xc7, 0x39, 0xef, 0xfd, 0x97, 0xf0, 0x76, 0x42, + 0x49, 0x54, 0xd4, 0x47, 0x0e, 0x84, 0x3d, 0xde, 0x2e, 0xfe, 0x64, 0x30, 0xe2, 0x2c, 0x09, 0x2a, + 0xf4, 0xe8, 0x04, 0xb4, 0x92, 0xe9, 0x50, 0x6b, 0x04, 0x15, 0xba, 0x1e, 0x5c, 0x57, 0xaf, 0x50, + 0xa4, 0xf4, 0x4a, 0xb9, 0x71, 0xae, 0xa2, 0x6f, 0x9e, 0x2f, 0xd5, 0x6a, 0x95, 0xd6, 0xe6, 0x72, + 0x55, 0x6f, 0xb6, 0x8a, 0x5b, 0xf0, 0x1f, 0x95, 0x60, 0x59, 0x8a, 0x93, 0xd6, 0x9f, 0x29, 0x49, + 0x9b, 0x75, 0xec, 0xf2, 0xd3, 0x0f, 0x82, 0xbc, 0xeb, 0x19, 0xde, 0x9e, 0xcb, 0x5a, 0xf5, 0x83, + 0x07, 0xb7, 0xea, 0x85, 0x26, 0xc9, 0xa4, 0xb3, 0xcc, 0xf0, 0x8b, 0x99, 0x24, 0xcd, 0x74, 0x0c, + 0x2b, 0x53, 0xe6, 0x08, 0x22, 0x3e, 0x03, 0xa0, 0xaf, 0xed, 0xd5, 0xe6, 0x66, 0xa9, 0xa6, 0x57, + 0x4a, 0x4b, 0x17, 0x82, 0xf5, 0x28, 0xa4, 0x5d, 0x0d, 0x4e, 0x6c, 0xd4, 0x4b, 0x8b, 0xb5, 0x0a, + 0x69, 0x2e, 0x8d, 0x7a, 0xbd, 0x52, 0xc6, 0x72, 0xff, 0x31, 0xb2, 0xfb, 0x83, 0xad, 0x72, 0xc2, + 0x37, 0xb6, 0x9c, 0x38, 0xf9, 0x7f, 0x5d, 0x91, 0xf5, 0xd2, 0x0b, 0x35, 0x8c, 0xa7, 0x35, 0x5e, + 0x1c, 0xbe, 0x20, 0xe5, 0x14, 0x27, 0xc5, 0x49, 0x32, 0x3c, 0xfe, 0xdb, 0x08, 0x78, 0x5c, 0x0d, + 0x4e, 0xf0, 0x78, 0x10, 0xe7, 0xb8, 0x68, 0x18, 0xbe, 0xac, 0x82, 0xa9, 0x35, 0x73, 0x9b, 0xb8, + 0x6a, 0xef, 0x85, 0x06, 0xca, 0x3c, 0x50, 0x02, 0xc7, 0x1f, 0xc5, 0xec, 0x08, 0x93, 0x79, 0x45, + 0x7e, 0xbd, 0x45, 0x6a, 0xc2, 0xfe, 0xc5, 0xc4, 0x3d, 0x13, 0x63, 0x38, 0xa2, 0x67, 0x7a, 0xbe, + 0x92, 0xa4, 0x67, 0x1a, 0x4c, 0x2b, 0x11, 0x4c, 0xd8, 0x74, 0x70, 0xd0, 0x33, 0xf6, 0x4c, 0x07, + 0x75, 0x88, 0x99, 0x48, 0xea, 0xad, 0xea, 0x62, 0xe2, 0x59, 0xe7, 0x70, 0x60, 0xf2, 0x5e, 0x36, + 0xb3, 0xa0, 0x10, 0x8c, 0x26, 0x64, 0xc3, 0x07, 0xbf, 0xac, 0xd4, 0x1b, 0x1b, 0x2b, 0xab, 0x9b, + 0xcb, 0x7a, 0xa5, 0xc2, 0x96, 0x88, 0xb7, 0xe1, 0xbb, 0x14, 0x30, 0xc7, 0x6a, 0xc8, 0xbc, 0x27, + 0x1e, 0x12, 0x09, 0x32, 0x83, 0xe3, 0xdf, 0xf9, 0xe9, 0xc9, 0x8a, 0x08, 0xc7, 0x63, 0xe2, 0x44, + 0x18, 0xeb, 0x3e, 0xf1, 0xa6, 0xa0, 0x09, 0xdd, 0x2d, 0x80, 0xf2, 0xf8, 0xc4, 0x14, 0xd3, 0x9f, + 0xa2, 0xbc, 0x08, 0x80, 0x7c, 0x13, 0x75, 0x51, 0xdb, 0x83, 0x1f, 0x56, 0x47, 0x6e, 0x13, 0x51, + 0xe6, 0xb6, 0x9a, 0xc8, 0xdc, 0xce, 0xa6, 0x60, 0x6e, 0xe7, 0x46, 0x37, 0xb7, 0xf3, 0x49, 0xcd, + 0xed, 0xa9, 0x28, 0x73, 0x3b, 0xa6, 0xd7, 0x28, 0xc4, 0xf6, 0x1a, 0x7d, 0x86, 0xba, 0x5e, 0x63, + 0x26, 0xbd, 0x98, 0xc8, 0x94, 0xf9, 0x13, 0xf9, 0xa4, 0xe3, 0x38, 0x05, 0xfe, 0x68, 0xcd, 0xf3, + 0x9f, 0xcc, 0x25, 0x19, 0xf7, 0x07, 0x72, 0x9c, 0xac, 0x95, 0xbc, 0x22, 0x9b, 0xc2, 0xa2, 0xa3, + 0xf6, 0x30, 0xf0, 0x90, 0xf0, 0x79, 0xb3, 0xf2, 0xb4, 0x6a, 0xb3, 0xd5, 0x24, 0x36, 0x79, 0xb9, + 0xa1, 0xeb, 0x1b, 0xeb, 0x74, 0xbb, 0xea, 0x14, 0xd0, 0x42, 0x2a, 0xfa, 0x46, 0x9d, 0x5a, 0xe0, + 0xdb, 0x22, 0xf5, 0xe5, 0x6a, 0x7d, 0x69, 0x33, 0x18, 0xd5, 0xea, 0xcb, 0x8d, 0xe2, 0x8e, 0xb6, + 0x00, 0x6e, 0xe6, 0xa8, 0x93, 0x0e, 0x90, 0x96, 0x50, 0xaa, 0x2f, 0x6d, 0xae, 0xd5, 0x2b, 0x6b, + 0x8d, 0x7a, 0xb5, 0x4c, 0xd2, 0x9b, 0x95, 0x56, 0xd1, 0xc4, 0xa6, 0x60, 0x9f, 0xcd, 0xdf, 0xac, + 0x94, 0xf4, 0xf2, 0x6a, 0x45, 0xa7, 0x45, 0xde, 0xab, 0xdd, 0x08, 0xce, 0x96, 0xea, 0x8d, 0x16, + 0x4e, 0x29, 0xd5, 0x2f, 0xb4, 0x2e, 0xac, 0x57, 0x36, 0xd7, 0xf5, 0x46, 0xb9, 0xd2, 0x6c, 0xe2, + 0x91, 0x94, 0xcd, 0x10, 0x8a, 0x5d, 0xed, 0xc9, 0xe0, 0x0e, 0x8e, 0xb5, 0x4a, 0x8b, 0xf8, 0x46, + 0xac, 0x35, 0x88, 0x7b, 0xdc, 0x52, 0x65, 0x73, 0xb5, 0xd4, 0xdc, 0xac, 0xd6, 0xcb, 0x8d, 0xb5, + 0xf5, 0x52, 0xab, 0x8a, 0x07, 0xdc, 0x75, 0xbd, 0xd1, 0x6a, 0x6c, 0x9e, 0xab, 0xe8, 0xcd, 0x6a, + 0xa3, 0x5e, 0xb4, 0x70, 0x95, 0xb9, 0x11, 0xda, 0xb7, 0x94, 0x6c, 0xed, 0x3a, 0x70, 0xda, 0x4f, + 0xaf, 0x35, 0xb0, 0xa0, 0xb9, 0x39, 0x43, 0x8f, 0xb7, 0xb3, 0x9a, 0xad, 0x86, 0x4e, 0x67, 0x0d, + 0x6b, 0xd5, 0x15, 0x1d, 0x4f, 0x75, 0x8a, 0xcf, 0x48, 0x75, 0x4e, 0xf1, 0xcf, 0x0a, 0xc8, 0x36, + 0x3d, 0xbb, 0x07, 0x7f, 0x20, 0xec, 0x0e, 0xcf, 0x00, 0xe0, 0x10, 0x57, 0x88, 0x25, 0xc3, 0x33, + 0xd8, 0x6a, 0x0d, 0x97, 0x02, 0x7f, 0x53, 0x7a, 0xff, 0x36, 0xb4, 0xba, 0xec, 0x5e, 0xc4, 0xf0, + 0xf1, 0x5d, 0xb9, 0xe3, 0xc2, 0xd1, 0x84, 0x26, 0x70, 0xa8, 0x0e, 0x82, 0x53, 0x1c, 0xac, 0x58, + 0xfe, 0xbe, 0xca, 0x20, 0xed, 0x41, 0xe0, 0xaa, 0x3e, 0xe5, 0x23, 0x3a, 0xb7, 0xa5, 0x3d, 0x14, + 0x3c, 0x98, 0x53, 0xff, 0xca, 0x5a, 0xe3, 0x5c, 0x25, 0x50, 0xf4, 0xa5, 0x52, 0xab, 0x54, 0xdc, + 0x86, 0x9f, 0x53, 0x41, 0x76, 0xcd, 0xbe, 0xdc, 0xbf, 0x6d, 0x6e, 0xa1, 0x2b, 0xdc, 0xde, 0x8a, + 0xff, 0x08, 0x5f, 0xaf, 0x26, 0x15, 0xfb, 0x5a, 0xb4, 0x8b, 0xcc, 0x17, 0x94, 0x24, 0x62, 0x5f, + 0x3b, 0xac, 0x5f, 0xcc, 0xdf, 0x8c, 0x22, 0xf6, 0x08, 0xd1, 0x22, 0xed, 0x2c, 0x38, 0x13, 0xbe, + 0xa8, 0x2e, 0x55, 0xea, 0xad, 0xea, 0xf2, 0x85, 0x50, 0xb8, 0x55, 0x5d, 0x4a, 0xfc, 0xc3, 0xba, + 0xb9, 0xf8, 0xb5, 0x82, 0xd3, 0xe0, 0x64, 0xf8, 0x6e, 0xa5, 0xd2, 0xf2, 0xdf, 0xdc, 0x0b, 0x9f, + 0x93, 0x03, 0xb3, 0xb4, 0xdb, 0xdf, 0xe8, 0x75, 0xb0, 0xf5, 0xfd, 0xd8, 0x10, 0xdd, 0x9b, 0xc0, + 0xf1, 0xea, 0xfa, 0x72, 0xb3, 0xe9, 0xd9, 0x8e, 0xb1, 0x8d, 0xc8, 0x38, 0x4a, 0xa5, 0xd5, 0x9f, + 0x0c, 0xdf, 0x2b, 0xbd, 0xfa, 0x2f, 0x0e, 0x35, 0xb4, 0xcc, 0x08, 0xd4, 0xbf, 0x2a, 0xb5, 0x5a, + 0x2f, 0x41, 0x30, 0x19, 0xfa, 0xf7, 0x8e, 0xb9, 0xcd, 0x45, 0xe3, 0xb2, 0x75, 0xf6, 0x79, 0x0a, + 0x98, 0x6e, 0x99, 0xbb, 0xe8, 0x99, 0xb6, 0x85, 0x5c, 0x6d, 0x0a, 0xa8, 0x2b, 0x6b, 0xad, 0xe2, + 0x31, 0xfc, 0x07, 0x4f, 0x8b, 0x32, 0xe4, 0x4f, 0x05, 0x17, 0x80, 0xff, 0x94, 0x5a, 0x45, 0x15, + 0xff, 0x59, 0xab, 0xb4, 0x8a, 0x59, 0xfc, 0xa7, 0x5e, 0x69, 0x15, 0x73, 0xf8, 0xcf, 0x7a, 0xad, + 0x55, 0xcc, 0xe3, 0x3f, 0xd5, 0x66, 0xab, 0x38, 0x85, 0xff, 0x2c, 0x36, 0x5b, 0xc5, 0x02, 0xfe, + 0x73, 0xae, 0xd9, 0x2a, 0x4e, 0xe3, 0x3f, 0xe5, 0x56, 0xab, 0x08, 0xf0, 0x9f, 0xbb, 0x9b, 0xad, + 0xe2, 0x0c, 0xfe, 0x53, 0x2a, 0xb7, 0x8a, 0xb3, 0xe4, 0x4f, 0xa5, 0x55, 0x9c, 0xc3, 0x7f, 0x9a, + 0xcd, 0x56, 0x71, 0x9e, 0x50, 0x6e, 0xb6, 0x8a, 0xc7, 0x49, 0x59, 0xd5, 0x56, 0xb1, 0x88, 0xff, + 0xac, 0x36, 0x5b, 0xc5, 0x13, 0x24, 0x73, 0xb3, 0x55, 0xd4, 0x48, 0xa1, 0xcd, 0x56, 0xf1, 0x2a, + 0x92, 0xa7, 0xd9, 0x2a, 0x9e, 0x24, 0x45, 0x34, 0x5b, 0xc5, 0xab, 0x09, 0x1b, 0x95, 0x56, 0xf1, + 0x14, 0xc9, 0xa3, 0xb7, 0x8a, 0x0f, 0x22, 0xaf, 0xea, 0xad, 0xe2, 0x69, 0xc2, 0x58, 0xa5, 0x55, + 0xbc, 0x86, 0xfc, 0xd1, 0x5b, 0x45, 0x48, 0x5e, 0x95, 0x5a, 0xc5, 0x6b, 0xe1, 0x83, 0xc1, 0xf4, + 0x0a, 0xf2, 0x28, 0x88, 0xb0, 0x08, 0xd4, 0x15, 0xe4, 0xf1, 0x13, 0xf1, 0x57, 0x66, 0xc1, 0x83, + 0xd8, 0xe2, 0xcd, 0xb2, 0x63, 0xef, 0xd6, 0xd0, 0xb6, 0xd1, 0xde, 0xaf, 0xdc, 0x87, 0x0d, 0x3e, + 0xf8, 0xc2, 0x8c, 0xb0, 0xa2, 0xdd, 0x0b, 0x7b, 0x23, 0xf2, 0x3f, 0xd6, 0x40, 0xf6, 0xd7, 0xa8, + 0x55, 0x71, 0x8d, 0x3a, 0xca, 0x24, 0xcc, 0xca, 0x4c, 0x24, 0xff, 0x9e, 0x6f, 0x0c, 0xc2, 0x86, + 0x54, 0xa6, 0x6f, 0x43, 0x0a, 0xb7, 0xb0, 0x1e, 0x72, 0x5c, 0xdb, 0x32, 0xba, 0x4d, 0xe6, 0x7e, + 0x44, 0xe7, 0xaa, 0xfd, 0xc9, 0xda, 0x53, 0xfd, 0x46, 0x45, 0x0d, 0xbe, 0x27, 0xc6, 0x2d, 0x6f, + 0xf5, 0x4b, 0x28, 0xa2, 0x7d, 0x7d, 0x26, 0x68, 0x5f, 0x2d, 0xa1, 0x7d, 0x3d, 0xe5, 0x10, 0xb4, + 0x93, 0x35, 0xb5, 0xea, 0x68, 0x53, 0xd1, 0xd0, 0x39, 0xdf, 0xdf, 0xff, 0x52, 0xe1, 0xe7, 0x14, + 0x70, 0xaa, 0x62, 0x0d, 0x9a, 0xca, 0xf0, 0x6a, 0xf4, 0x56, 0x1e, 0x9a, 0x75, 0x51, 0xa4, 0x77, + 0x0c, 0xac, 0xf6, 0x60, 0x9a, 0x11, 0x12, 0xfd, 0xbd, 0x40, 0xa2, 0x4d, 0x41, 0xa2, 0x77, 0x8d, + 0x4e, 0x3a, 0x99, 0x40, 0xeb, 0x63, 0xed, 0xbb, 0xb2, 0xf0, 0x2f, 0x15, 0x70, 0x82, 0x7a, 0x10, + 0xde, 0x4d, 0x67, 0x4e, 0xa4, 0xb7, 0x17, 0xad, 0xaf, 0x6e, 0x38, 0xcb, 0xa2, 0xfa, 0xcd, 0xa5, + 0xc0, 0xd7, 0xf1, 0x02, 0xbf, 0x47, 0x14, 0x78, 0x44, 0x3f, 0xde, 0x5f, 0x5c, 0x84, 0xac, 0x7f, + 0x2b, 0x90, 0x75, 0x5d, 0x90, 0xf5, 0x1d, 0x23, 0x51, 0x3d, 0x5a, 0x31, 0x7f, 0x23, 0x0b, 0x1e, + 0x4c, 0x39, 0x64, 0x8a, 0x40, 0xfb, 0xc1, 0x92, 0xd5, 0xd1, 0x91, 0xeb, 0x19, 0x8e, 0x27, 0x84, + 0x26, 0xea, 0x9b, 0x9a, 0x67, 0x52, 0x98, 0x9a, 0x2b, 0x43, 0xa7, 0xe6, 0xf0, 0x3d, 0xbc, 0x81, + 0x77, 0x5e, 0x44, 0xb6, 0x14, 0x83, 0x41, 0x44, 0x0d, 0xa3, 0x5a, 0x54, 0x60, 0xf9, 0xfd, 0xb0, + 0x80, 0xf2, 0xf2, 0xa1, 0x4b, 0x48, 0x86, 0xf8, 0x6f, 0x8e, 0xd7, 0x12, 0xcf, 0xf2, 0xef, 0x44, + 0xb3, 0xb1, 0xd8, 0x49, 0x75, 0x0a, 0xf5, 0xdc, 0x13, 0x60, 0x9a, 0x74, 0x39, 0x35, 0xd3, 0xba, + 0x04, 0xff, 0x42, 0x05, 0xb3, 0x75, 0x74, 0xa5, 0xbc, 0x63, 0x74, 0xbb, 0xc8, 0xda, 0x46, 0xf0, + 0x5e, 0xc1, 0xb6, 0x37, 0x7a, 0xbd, 0x7a, 0xb8, 0x3f, 0xec, 0x3f, 0x6a, 0x77, 0x81, 0x9c, 0xdb, + 0xb6, 0x83, 0x00, 0x19, 0x3f, 0x10, 0xb1, 0x7a, 0x5d, 0xda, 0xf3, 0x76, 0x16, 0x48, 0x59, 0xa5, + 0x9e, 0xd9, 0xc4, 0x1f, 0xe8, 0xf4, 0x3b, 0x36, 0x4e, 0x7e, 0x7d, 0x60, 0x67, 0x9c, 0x89, 0xe9, + 0x8c, 0x03, 0xc6, 0x17, 0x78, 0xa6, 0x23, 0x16, 0x49, 0xae, 0x07, 0x33, 0x6d, 0x3f, 0x4b, 0x70, + 0x4a, 0x8f, 0x4f, 0x82, 0x7f, 0x95, 0xa8, 0xbb, 0x96, 0x2a, 0x3c, 0x99, 0x56, 0xa1, 0x31, 0x9b, + 0x9a, 0x57, 0x83, 0x13, 0xad, 0x46, 0x63, 0x73, 0xad, 0x54, 0xbf, 0x10, 0xc6, 0x1e, 0xda, 0x82, + 0xaf, 0xc8, 0x82, 0xf9, 0xa6, 0xdd, 0xbd, 0x8c, 0x42, 0x9c, 0xab, 0x82, 0xfb, 0x27, 0x2f, 0xa7, + 0xcc, 0x01, 0x39, 0x69, 0xa7, 0x40, 0xde, 0xb0, 0xdc, 0x2b, 0xc8, 0x37, 0xff, 0xd9, 0x13, 0x83, + 0xf1, 0xa3, 0x7c, 0x47, 0xa0, 0x8b, 0x30, 0xde, 0x39, 0x44, 0x92, 0x22, 0x57, 0x11, 0x40, 0x9e, + 0x05, 0xb3, 0x2e, 0xf5, 0x12, 0x69, 0x71, 0xce, 0x40, 0x42, 0x1a, 0x61, 0x91, 0xba, 0x29, 0xa9, + 0x8c, 0x45, 0xf2, 0x04, 0x5f, 0x1b, 0xf4, 0x1f, 0x1b, 0x02, 0xc4, 0xa5, 0xc3, 0x30, 0x96, 0x0c, + 0xe4, 0x57, 0x8d, 0x7b, 0x12, 0x7f, 0x1a, 0x9c, 0xf4, 0x0f, 0xb7, 0x97, 0x57, 0x4b, 0xb5, 0x5a, + 0xa5, 0xbe, 0x52, 0xd9, 0xac, 0x2e, 0xd1, 0xfd, 0xe4, 0x30, 0xa5, 0xd4, 0x6a, 0x55, 0xd6, 0xd6, + 0x5b, 0xcd, 0xcd, 0xca, 0xd3, 0xca, 0x95, 0xca, 0x12, 0x71, 0xc0, 0x26, 0x27, 0x28, 0x7d, 0x57, + 0xf9, 0x52, 0xbd, 0x79, 0xbe, 0xa2, 0x17, 0x77, 0xe0, 0x3f, 0x28, 0xa0, 0x50, 0x33, 0xc9, 0xa9, + 0x30, 0x97, 0xb7, 0x96, 0xbe, 0xcc, 0x37, 0xd0, 0x9a, 0x88, 0xec, 0xe3, 0x87, 0x08, 0xd0, 0xa7, + 0x17, 0xb9, 0x03, 0xa6, 0x1a, 0xbd, 0x1e, 0x3b, 0x7d, 0xf1, 0xb0, 0xb8, 0x0e, 0xa4, 0xd4, 0xeb, + 0x55, 0xad, 0x2d, 0x5b, 0xc7, 0xf9, 0x39, 0x93, 0xb5, 0x21, 0xc0, 0xf9, 0xc4, 0xd1, 0xb8, 0x39, + 0xca, 0x51, 0x1f, 0xc1, 0x17, 0xa9, 0x60, 0x9a, 0xfa, 0x34, 0x94, 0x7a, 0x3d, 0xf8, 0x94, 0xb0, + 0x45, 0x32, 0xe1, 0x50, 0x41, 0xcb, 0x0b, 0xe7, 0xa3, 0x3c, 0x5c, 0x6b, 0x22, 0x5c, 0x3f, 0x34, + 0x44, 0x40, 0x01, 0x1f, 0x11, 0x78, 0x9d, 0x12, 0xdd, 0x00, 0x83, 0xf6, 0xf5, 0xdb, 0x01, 0x20, + 0xeb, 0x02, 0x20, 0x77, 0x8e, 0x58, 0xde, 0xd1, 0x22, 0xf2, 0x37, 0x0a, 0x98, 0xa6, 0x71, 0x16, + 0x30, 0x22, 0x0f, 0xeb, 0x1f, 0x0b, 0x57, 0x0d, 0x77, 0x87, 0x1b, 0x0b, 0xf1, 0x23, 0x7c, 0xdf, + 0x21, 0x84, 0x1e, 0x14, 0x15, 0x61, 0xfc, 0x7c, 0x69, 0x44, 0xe1, 0x46, 0xd1, 0x4d, 0x26, 0xdc, + 0xa7, 0x8f, 0x20, 0xdc, 0x39, 0x30, 0x1d, 0x5a, 0x2b, 0x6a, 0x9c, 0xac, 0xcf, 0x96, 0xc0, 0x0c, + 0x67, 0x9d, 0x62, 0xda, 0x4b, 0x68, 0xcb, 0xd8, 0xeb, 0xb2, 0x35, 0x80, 0xe2, 0x31, 0x4c, 0x8c, + 0xd4, 0xa9, 0x61, 0x75, 0xf7, 0x8b, 0x19, 0xad, 0x08, 0x66, 0x79, 0x43, 0xb4, 0xa8, 0xc0, 0x6f, + 0x5d, 0x07, 0xa6, 0xcf, 0xdb, 0xce, 0x25, 0x72, 0x54, 0x01, 0x7e, 0x80, 0x06, 0x46, 0xf5, 0xa3, + 0xf0, 0x70, 0xfd, 0xd8, 0xab, 0xe4, 0x7d, 0x53, 0x7d, 0x6a, 0x0b, 0x43, 0x23, 0xed, 0x5c, 0x0f, + 0x66, 0xae, 0xf8, 0xb9, 0x43, 0xf3, 0x82, 0x4b, 0x82, 0xbf, 0x2c, 0xe7, 0x6d, 0x3a, 0xbc, 0xc8, + 0xf4, 0xb7, 0x1a, 0xdf, 0xae, 0x80, 0xfc, 0x0a, 0xf2, 0x4a, 0xdd, 0x2e, 0x2f, 0xb7, 0x97, 0x49, + 0x1f, 0x5e, 0x17, 0x2a, 0x51, 0xea, 0x76, 0xa3, 0x47, 0x72, 0x4e, 0x40, 0xfe, 0x21, 0x4b, 0x21, + 0x4d, 0xf2, 0x68, 0xc8, 0x90, 0x02, 0xd3, 0x97, 0xd8, 0xdf, 0x86, 0xe7, 0x41, 0x5e, 0xcf, 0xcd, + 0xcd, 0x1e, 0x13, 0x06, 0xc5, 0xcd, 0xc4, 0x7b, 0x66, 0xfa, 0xf9, 0xb4, 0x7b, 0xc0, 0xd4, 0x9e, + 0x8b, 0xca, 0x86, 0xeb, 0xdb, 0xd3, 0x62, 0x4d, 0x1b, 0x17, 0xef, 0x45, 0x6d, 0x6f, 0xa1, 0xba, + 0xdb, 0xb3, 0x1d, 0x6f, 0x83, 0x66, 0x0c, 0xe2, 0xcc, 0xb2, 0x67, 0xdd, 0xa7, 0xa0, 0x41, 0x50, + 0xb8, 0x62, 0x7a, 0x3b, 0xe5, 0x1d, 0xc3, 0x63, 0x3b, 0xbc, 0xc1, 0x33, 0xfc, 0xd0, 0x08, 0x70, + 0xc6, 0x7a, 0x09, 0x46, 0xc7, 0xc0, 0xb8, 0x19, 0x14, 0xc9, 0x9c, 0xcb, 0xb4, 0xb6, 0x29, 0xff, + 0xc1, 0xc2, 0xd6, 0x81, 0xf4, 0xc4, 0x80, 0x8f, 0xc1, 0x0d, 0x70, 0x14, 0xc0, 0x7f, 0x44, 0x05, + 0xd9, 0x46, 0x0f, 0x59, 0xd2, 0x87, 0xc3, 0x03, 0x1c, 0x94, 0x3e, 0x1c, 0xde, 0x27, 0x7f, 0x6e, + 0x21, 0xa8, 0x34, 0x2e, 0x39, 0x02, 0x85, 0x5b, 0x41, 0xd6, 0xb4, 0xb6, 0x6c, 0x36, 0xf5, 0xbe, + 0x36, 0xc2, 0x5c, 0x20, 0x66, 0x02, 0xc9, 0x08, 0xdf, 0x27, 0x77, 0x64, 0x21, 0xae, 0xec, 0x64, + 0xe2, 0x5e, 0x1e, 0x61, 0x24, 0xd1, 0xc0, 0x7c, 0x38, 0x2f, 0xae, 0x35, 0x4a, 0x4b, 0xc5, 0x0e, + 0xfc, 0x66, 0x01, 0xe4, 0xa9, 0xda, 0xc0, 0x97, 0xa8, 0x40, 0x2d, 0x75, 0x3a, 0x11, 0x60, 0x28, + 0x07, 0xc0, 0xb0, 0x7d, 0x2d, 0x64, 0xc7, 0x4b, 0xfc, 0x67, 0x31, 0x9a, 0xaa, 0xe4, 0xd8, 0xc0, + 0x9a, 0x64, 0xa9, 0xd3, 0x89, 0x3e, 0x6c, 0x15, 0x14, 0xa8, 0x88, 0x05, 0xf2, 0x3d, 0x84, 0x2a, + 0xd7, 0x43, 0x24, 0x1e, 0x48, 0x22, 0xf9, 0x4b, 0xbf, 0x95, 0xfc, 0xbd, 0x02, 0xa6, 0x88, 0xb1, + 0xdd, 0xe9, 0xc0, 0x92, 0x0c, 0x36, 0xd7, 0x81, 0x69, 0x5f, 0x34, 0xb8, 0xcb, 0xc4, 0xe3, 0x41, + 0x98, 0x20, 0x2e, 0x1f, 0xde, 0x2d, 0xa2, 0xf3, 0xb8, 0xf8, 0xda, 0x33, 0x2e, 0xa2, 0x0f, 0xe2, + 0x86, 0xc5, 0x2a, 0xfd, 0xc5, 0xfe, 0x4a, 0x20, 0xf0, 0x35, 0x41, 0xe0, 0xb7, 0x8f, 0x52, 0x64, + 0xfa, 0x42, 0xff, 0x63, 0x05, 0x00, 0x5c, 0x36, 0x8b, 0x76, 0xf0, 0x08, 0x21, 0x86, 0x51, 0x8c, + 0x74, 0x5f, 0x21, 0x6d, 0xbb, 0x0e, 0xac, 0x6a, 0x5c, 0x54, 0x03, 0xad, 0x08, 0x54, 0x33, 0x10, + 0x2d, 0xfe, 0x0b, 0xdf, 0x2e, 0x65, 0xcd, 0xca, 0x97, 0x94, 0xbe, 0x5c, 0xff, 0x54, 0x01, 0x53, + 0x4d, 0xe4, 0xe1, 0xae, 0x13, 0x9e, 0x93, 0xe9, 0xf5, 0xb9, 0xb6, 0xad, 0x48, 0xb6, 0xed, 0xef, + 0x64, 0x64, 0x83, 0x71, 0x86, 0x92, 0x61, 0x3c, 0x45, 0xcc, 0x1a, 0x5e, 0x2f, 0x15, 0x8c, 0x73, + 0x18, 0xb5, 0xf4, 0xa5, 0xfb, 0x56, 0x25, 0x70, 0x6f, 0x13, 0x0f, 0x23, 0xf3, 0x66, 0x75, 0xe6, + 0xa0, 0x59, 0x2d, 0x7f, 0x18, 0x99, 0xaf, 0x63, 0xb4, 0x37, 0x55, 0x62, 0x03, 0x64, 0x0c, 0x8e, + 0x4e, 0xa3, 0xc8, 0xeb, 0xd9, 0x2a, 0xc8, 0xb3, 0x1d, 0xcf, 0xbb, 0xe2, 0x37, 0x3c, 0x87, 0x4f, + 0x4d, 0xde, 0x3f, 0x82, 0x29, 0x18, 0xb7, 0x97, 0x18, 0xb0, 0xa1, 0x70, 0x6c, 0xdc, 0x02, 0x72, + 0xe4, 0x2a, 0x0c, 0x36, 0xce, 0x85, 0x3e, 0x6a, 0x3e, 0x89, 0x0a, 0x7e, 0xab, 0xd3, 0x4c, 0x89, + 0x51, 0x18, 0xc3, 0xf6, 0xe3, 0x28, 0x28, 0x7c, 0x43, 0x03, 0x60, 0x7d, 0xef, 0x62, 0xd7, 0x74, + 0x77, 0x4c, 0x8b, 0x38, 0xb6, 0xce, 0xb2, 0x47, 0x7a, 0xa3, 0x43, 0xac, 0x49, 0x18, 0x69, 0x14, + 0x14, 0x81, 0xba, 0xe7, 0x98, 0xcc, 0x44, 0xc6, 0x7f, 0xb5, 0x27, 0x05, 0x2e, 0xe2, 0xd9, 0xbe, + 0x68, 0x53, 0x58, 0x0c, 0x21, 0x07, 0x0b, 0x5c, 0xe9, 0xa1, 0xab, 0x38, 0x7f, 0x6d, 0x47, 0x4e, + 0xbc, 0xb6, 0x43, 0x08, 0x41, 0x91, 0xef, 0x0b, 0x41, 0x81, 0x71, 0x74, 0xcd, 0x67, 0xd2, 0x48, + 0x81, 0xaa, 0x4e, 0xfe, 0xe3, 0x2f, 0x88, 0x4f, 0x23, 0x71, 0x29, 0xa6, 0x07, 0x9d, 0xc2, 0x04, + 0xbe, 0xcf, 0x9b, 0x96, 0xec, 0xf3, 0x3e, 0x16, 0xce, 0x9d, 0x6c, 0x49, 0x63, 0x3a, 0x81, 0xe4, + 0x04, 0x76, 0xb3, 0x7d, 0xec, 0xc2, 0x4f, 0x48, 0x07, 0x3f, 0xe6, 0x64, 0x1c, 0x3b, 0x0b, 0x62, + 0x1c, 0x28, 0x01, 0x07, 0x9c, 0xe3, 0x4a, 0x5c, 0x0f, 0x3c, 0x8c, 0x7e, 0x32, 0x5d, 0xde, 0x1d, + 0xcd, 0xc6, 0xf6, 0x63, 0x79, 0x34, 0x16, 0xef, 0xae, 0x94, 0x5b, 0x45, 0x74, 0x30, 0xbe, 0x07, + 0x89, 0xe4, 0x41, 0xa3, 0x76, 0x84, 0x0b, 0xc9, 0xf0, 0x7f, 0x2a, 0x20, 0xcf, 0xcc, 0x8d, 0xbb, + 0x0e, 0x09, 0x21, 0x7c, 0xe5, 0x28, 0x90, 0xc4, 0x86, 0x54, 0xfa, 0x9d, 0xa4, 0x00, 0x8c, 0xc1, + 0xc0, 0xb8, 0x90, 0x1a, 0x00, 0xf0, 0x9f, 0x14, 0x90, 0xc5, 0x66, 0x90, 0x5c, 0xc0, 0x9a, 0xcf, + 0x48, 0x9f, 0x63, 0xe0, 0x04, 0x80, 0xc9, 0x47, 0xe8, 0xf7, 0x22, 0x98, 0xee, 0xd1, 0x8c, 0x41, + 0xb8, 0xa4, 0x1b, 0x24, 0x3a, 0x23, 0xa4, 0x87, 0x9f, 0x71, 0x53, 0xce, 0xb8, 0xb3, 0x10, 0xf1, + 0xfc, 0x24, 0x83, 0xa3, 0x32, 0x8e, 0xd8, 0x36, 0x5b, 0xf0, 0x5f, 0x15, 0x00, 0x74, 0xe4, 0xda, + 0xdd, 0xcb, 0x68, 0xc3, 0x31, 0xe1, 0xb5, 0x21, 0x00, 0xac, 0xd9, 0x67, 0xc2, 0x66, 0xff, 0x59, + 0x45, 0xf6, 0xc4, 0x82, 0xa0, 0x79, 0x3e, 0xf1, 0x08, 0xf1, 0x3f, 0x19, 0x4c, 0x31, 0x39, 0x32, + 0x9b, 0x52, 0x4e, 0xf8, 0xfe, 0x47, 0xf0, 0x83, 0x52, 0x27, 0x1e, 0x64, 0x38, 0x4a, 0x06, 0x40, + 0x79, 0x04, 0x00, 0x8e, 0x83, 0x19, 0x1f, 0x80, 0x0d, 0xbd, 0x5a, 0x44, 0xf0, 0xdd, 0x2a, 0x71, + 0x0b, 0xa3, 0x83, 0xdb, 0xe1, 0x7b, 0x9a, 0xbf, 0x94, 0x9e, 0xec, 0x73, 0xf2, 0x08, 0xca, 0x4f, + 0x09, 0xa0, 0xdf, 0x97, 0x9a, 0xdd, 0x4b, 0x30, 0xf4, 0x40, 0xe9, 0xaf, 0xce, 0x56, 0xc0, 0x9c, + 0x60, 0x95, 0x68, 0xa7, 0xc1, 0x49, 0x21, 0x81, 0x8e, 0x77, 0x9d, 0xe2, 0x31, 0x0d, 0x82, 0x53, + 0xc2, 0x1b, 0xf6, 0x80, 0x3a, 0xc5, 0x0c, 0x7c, 0xd7, 0x97, 0x33, 0xc1, 0x7a, 0xcf, 0xfb, 0xb3, + 0x6c, 0xf5, 0xed, 0x53, 0x62, 0x84, 0xde, 0xb6, 0x6d, 0x79, 0xe8, 0x3e, 0xce, 0xb7, 0x2e, 0x48, + 0x88, 0xb5, 0x1a, 0x4e, 0x83, 0x29, 0xcf, 0xe1, 0xfd, 0xed, 0xfc, 0x47, 0x5e, 0xb1, 0x72, 0xa2, + 0x62, 0xd5, 0xc1, 0x59, 0xd3, 0x6a, 0x77, 0xf7, 0x3a, 0x48, 0x47, 0x5d, 0x03, 0xcb, 0xd0, 0x2d, + 0xb9, 0x4b, 0xa8, 0x87, 0xac, 0x0e, 0xb2, 0x3c, 0xca, 0xa7, 0x7f, 0x58, 0x5f, 0x22, 0xa7, 0xa8, + 0x8c, 0x4f, 0x12, 0x95, 0xf1, 0x11, 0x83, 0x96, 0x80, 0x63, 0xd6, 0x00, 0x6f, 0x07, 0x80, 0xd6, + 0xed, 0x9c, 0x89, 0xae, 0x30, 0x35, 0xec, 0x0f, 0xf3, 0xdc, 0x08, 0x32, 0xe8, 0x5c, 0x66, 0xf8, + 0x95, 0x40, 0xfd, 0x9e, 0x22, 0xa8, 0xdf, 0x2d, 0x92, 0x2c, 0x24, 0xd3, 0xba, 0xde, 0xe1, 0x37, + 0x95, 0xae, 0x01, 0x57, 0xfb, 0xc7, 0x22, 0xea, 0x95, 0xca, 0x52, 0x73, 0x73, 0x63, 0x7d, 0x45, + 0x2f, 0x2d, 0x55, 0x8a, 0x00, 0xeb, 0x27, 0xd5, 0xcb, 0xe0, 0x34, 0x43, 0x16, 0xfe, 0x89, 0x02, + 0x72, 0x24, 0xd2, 0x04, 0x7c, 0xfa, 0x98, 0x34, 0xc7, 0x15, 0x3c, 0x35, 0x83, 0x71, 0x57, 0xfe, + 0x5e, 0x32, 0x26, 0x4c, 0xc2, 0xd5, 0xa1, 0xee, 0x25, 0x8b, 0x21, 0x94, 0xfe, 0x4c, 0x08, 0x37, + 0xc9, 0xe6, 0x8e, 0x7d, 0xe5, 0x3f, 0x73, 0x93, 0xc4, 0xf5, 0x3f, 0xe2, 0x26, 0x39, 0x80, 0x85, + 0x89, 0x37, 0xc9, 0x01, 0xed, 0x2e, 0xa6, 0x99, 0xc2, 0x8f, 0xe6, 0x82, 0xf9, 0xdf, 0x27, 0x95, + 0x43, 0xed, 0x9d, 0x95, 0xc0, 0x9c, 0x69, 0x79, 0xc8, 0xb1, 0x8c, 0xee, 0x72, 0xd7, 0xd8, 0xf6, + 0xed, 0xd3, 0x6b, 0x0f, 0x44, 0xb8, 0x0f, 0xf3, 0xe8, 0xe2, 0x17, 0xda, 0x19, 0x00, 0x3c, 0xb4, + 0xdb, 0xeb, 0x1a, 0x5e, 0xa8, 0x7a, 0x5c, 0x0a, 0xaf, 0x7d, 0x59, 0x51, 0xfb, 0x1e, 0x0d, 0xae, + 0xa2, 0xa0, 0xb5, 0xf6, 0x7b, 0x68, 0xc3, 0x32, 0x9f, 0xb1, 0x47, 0x02, 0xba, 0x53, 0x1d, 0x1d, + 0xf4, 0x4a, 0xd8, 0x15, 0xca, 0x8b, 0xbb, 0x42, 0xda, 0x9d, 0xe0, 0x1a, 0x12, 0xe6, 0x9f, 0x04, + 0xdf, 0x3f, 0x6f, 0x76, 0xb6, 0x91, 0x57, 0xdd, 0x5a, 0x33, 0x5d, 0xd7, 0xb4, 0xb6, 0xc9, 0x74, + 0xbc, 0xa0, 0x47, 0x67, 0x80, 0xff, 0x5b, 0x3a, 0x58, 0x9c, 0xdf, 0x67, 0x0c, 0x09, 0x16, 0x67, + 0x8b, 0xdb, 0x76, 0x61, 0x3b, 0x0d, 0x56, 0x75, 0xb2, 0x12, 0xab, 0x3a, 0x3c, 0xa6, 0x39, 0xc9, + 0xd5, 0x81, 0xd7, 0x48, 0x45, 0xa3, 0x8b, 0xab, 0x46, 0xfa, 0x7d, 0xdf, 0xb7, 0x55, 0x30, 0x4f, + 0x8b, 0x5e, 0xb4, 0xed, 0x4b, 0xbb, 0x86, 0x73, 0x09, 0xfe, 0xf4, 0xe1, 0x76, 0x81, 0x63, 0x77, + 0xaf, 0xa2, 0xb6, 0x74, 0xfb, 0x94, 0x37, 0xdb, 0xaf, 0xbc, 0xf0, 0xf7, 0xa4, 0xa7, 0x24, 0x82, + 0x3c, 0xfd, 0x4a, 0x4d, 0x66, 0x7b, 0x4b, 0xee, 0x4c, 0xb6, 0x0c, 0x83, 0xe9, 0x03, 0xff, 0xdb, + 0x01, 0xf0, 0xfe, 0x38, 0xc2, 0xef, 0x0c, 0x8c, 0x13, 0x77, 0xf8, 0xd5, 0xd1, 0xb0, 0xf3, 0xf9, + 0x1a, 0x01, 0xbb, 0x22, 0x50, 0x2f, 0x05, 0x1e, 0x94, 0xf8, 0x2f, 0x5f, 0xa1, 0x6c, 0x7a, 0x68, + 0x46, 0xb0, 0x3c, 0x11, 0x34, 0x4f, 0x8a, 0x2c, 0x34, 0x7a, 0xa9, 0x62, 0xfa, 0x25, 0xe9, 0x1d, + 0xb7, 0x81, 0x02, 0xa2, 0xdc, 0x4d, 0xa6, 0x55, 0xca, 0x6d, 0xd7, 0xc9, 0xb3, 0x99, 0x3e, 0x9a, + 0x2f, 0xcc, 0xf9, 0xfe, 0x94, 0x4d, 0x44, 0xae, 0x09, 0x0e, 0x30, 0x3c, 0x05, 0xf2, 0xae, 0xbd, + 0xe7, 0xb4, 0x11, 0xdb, 0x03, 0x65, 0x4f, 0x23, 0xec, 0xd7, 0x0d, 0x35, 0x17, 0x0e, 0x58, 0x24, + 0xd9, 0xc4, 0x16, 0x49, 0xb4, 0xbd, 0x1b, 0x63, 0x3f, 0xc0, 0x17, 0xa9, 0xb2, 0x5b, 0x3a, 0x02, + 0x66, 0x4d, 0xe4, 0x3d, 0x10, 0x8d, 0x80, 0x5f, 0x97, 0xda, 0x0d, 0x1a, 0x52, 0x93, 0x64, 0x2a, + 0xd7, 0x18, 0xc1, 0x0e, 0xbe, 0x16, 0x3c, 0xc8, 0xcf, 0xc1, 0x0c, 0x60, 0x62, 0xf0, 0x6e, 0xe8, + 0xb5, 0xa2, 0x0a, 0x9f, 0x9d, 0x05, 0x45, 0xca, 0x5a, 0x23, 0xb0, 0x05, 0xe1, 0xcb, 0x32, 0x47, + 0x6d, 0xf0, 0x46, 0xcf, 0x60, 0x85, 0xbb, 0x68, 0x63, 0x6f, 0x38, 0x10, 0x04, 0x1f, 0xd6, 0x2e, + 0x42, 0x93, 0x46, 0x68, 0x66, 0x31, 0xca, 0x07, 0xdf, 0x92, 0x91, 0xb9, 0x30, 0x41, 0x8e, 0xc5, + 0xf4, 0x7b, 0xa5, 0xef, 0x64, 0xfd, 0xd8, 0xab, 0xcb, 0x8e, 0xbd, 0xbb, 0xe1, 0x74, 0xe1, 0xbf, + 0x49, 0xdd, 0x47, 0x13, 0x31, 0xbb, 0x50, 0xa2, 0x67, 0x17, 0x64, 0x45, 0xba, 0x1b, 0x6e, 0x85, + 0x75, 0x47, 0x18, 0xbe, 0xb5, 0x1b, 0xc1, 0xbc, 0xd1, 0xe9, 0xac, 0x1b, 0xdb, 0xa8, 0x8c, 0xa7, + 0xed, 0x96, 0xc7, 0xe2, 0x32, 0xf6, 0xa5, 0xc6, 0x4e, 0x65, 0xc4, 0x3e, 0x72, 0xea, 0x80, 0x55, + 0x2a, 0xbf, 0x0c, 0x2b, 0x80, 0xc8, 0xe4, 0x37, 0x91, 0xe1, 0x0f, 0x0f, 0x19, 0xed, 0x1d, 0x23, + 0x8c, 0x22, 0xcb, 0x9e, 0x24, 0x7d, 0xb1, 0x24, 0xf8, 0x4e, 0x5f, 0xf3, 0x7e, 0x4d, 0x01, 0x53, + 0x18, 0x8f, 0x52, 0xa7, 0x03, 0x1f, 0x2e, 0x04, 0x5b, 0x8e, 0xf4, 0x86, 0x7b, 0xbe, 0xb4, 0x6b, + 0xa2, 0x5f, 0x43, 0x4a, 0x3f, 0xfa, 0xd4, 0x00, 0x13, 0xa2, 0x22, 0x08, 0x51, 0x2e, 0x68, 0x72, + 0x6c, 0x11, 0xe9, 0x8b, 0xef, 0x33, 0x0a, 0x98, 0xf3, 0xe7, 0x19, 0xcb, 0xc8, 0x6b, 0xef, 0xc0, + 0xdb, 0x65, 0xd7, 0xb9, 0x58, 0x4b, 0x0c, 0xb6, 0x84, 0xbb, 0xf0, 0x7b, 0x99, 0x84, 0x2a, 0x2f, + 0x94, 0x1c, 0xb1, 0x48, 0x98, 0x48, 0x17, 0xe3, 0x08, 0xa6, 0x2f, 0xcc, 0xaf, 0x28, 0x00, 0xb4, + 0xec, 0x60, 0xb2, 0x7c, 0x08, 0x49, 0xfe, 0x8c, 0xf4, 0x6e, 0x31, 0xab, 0x78, 0x58, 0x6c, 0xf2, + 0x9e, 0x43, 0xd2, 0x99, 0x6a, 0x58, 0x49, 0x13, 0x69, 0xeb, 0xd3, 0x4b, 0x7b, 0xbd, 0xae, 0xd9, + 0x36, 0xbc, 0x7e, 0x0f, 0xc0, 0x68, 0xf1, 0xc2, 0xe7, 0x28, 0x09, 0x8d, 0xc6, 0xa0, 0x8c, 0x08, + 0x59, 0xd2, 0xe0, 0x64, 0x8a, 0x1f, 0x9c, 0x4c, 0xd2, 0xab, 0x67, 0x08, 0xf1, 0x09, 0xa8, 0xa7, + 0x0a, 0x8e, 0x37, 0x7a, 0xc8, 0x5a, 0x74, 0x90, 0xd1, 0x69, 0x3b, 0x7b, 0xbb, 0x17, 0x5d, 0xde, + 0x7d, 0x35, 0x5e, 0x47, 0xb9, 0x95, 0x6b, 0x45, 0x58, 0xb9, 0x86, 0xcf, 0x95, 0xbe, 0xe4, 0x99, + 0xdb, 0x5f, 0xe1, 0x78, 0x18, 0x61, 0xa8, 0x4b, 0xe4, 0x74, 0xd5, 0xb7, 0x48, 0x9d, 0x4d, 0xb2, + 0x48, 0xfd, 0x66, 0xa9, 0x60, 0x94, 0x52, 0xf5, 0x9a, 0x88, 0xef, 0xdc, 0x7c, 0x13, 0x79, 0x11, + 0xf0, 0xde, 0x00, 0xe6, 0x2e, 0x86, 0x6f, 0x02, 0x88, 0xc5, 0xc4, 0x01, 0x1e, 0xad, 0x6f, 0x4d, + 0xba, 0x42, 0x23, 0xb2, 0x10, 0x81, 0x6e, 0x80, 0xa0, 0x22, 0xe3, 0x36, 0x97, 0x68, 0xb9, 0x25, + 0xb6, 0xfc, 0xf4, 0x51, 0xf8, 0x84, 0x02, 0x66, 0x9a, 0x3b, 0x86, 0x83, 0x16, 0xf7, 0xc9, 0xe9, + 0x73, 0x49, 0xa3, 0xe4, 0x85, 0xbc, 0x98, 0x35, 0x90, 0xed, 0x9a, 0xd6, 0x25, 0xdf, 0xdf, 0x11, + 0xff, 0x0f, 0xaf, 0x64, 0x56, 0x06, 0x5c, 0xc9, 0x1c, 0x6c, 0x93, 0x04, 0xe5, 0x46, 0x8c, 0xa6, + 0x6f, 0xc8, 0xc8, 0x5c, 0xc9, 0x3c, 0x94, 0x5c, 0xfa, 0x62, 0xfc, 0xeb, 0x2c, 0xc8, 0x37, 0x91, + 0xe1, 0xb4, 0x77, 0xe0, 0xfb, 0x95, 0x81, 0x53, 0x89, 0x82, 0x38, 0x95, 0x58, 0x06, 0x53, 0x5b, + 0x66, 0xd7, 0x43, 0x0e, 0xf5, 0x01, 0xe7, 0xbb, 0x76, 0xda, 0xc4, 0x17, 0xbb, 0x76, 0xfb, 0xd2, + 0x02, 0x33, 0xed, 0x17, 0xfc, 0x20, 0xf7, 0x0b, 0xcb, 0xe4, 0x23, 0xdd, 0xff, 0x18, 0x1b, 0x84, + 0xae, 0xed, 0x78, 0x51, 0x97, 0xa6, 0x45, 0x50, 0x69, 0xda, 0x8e, 0xa7, 0xd3, 0x0f, 0x31, 0xcc, + 0x5b, 0x7b, 0xdd, 0x6e, 0x0b, 0xdd, 0xe7, 0xf9, 0xd3, 0x3a, 0xff, 0x19, 0x1b, 0x8b, 0xf6, 0xd6, + 0x96, 0x8b, 0xe8, 0xa2, 0x42, 0x4e, 0x67, 0x4f, 0xda, 0x49, 0x90, 0xeb, 0x9a, 0xbb, 0x26, 0x9d, + 0x88, 0xe4, 0x74, 0xfa, 0xa0, 0xdd, 0x0c, 0x8a, 0xe1, 0x1c, 0x88, 0x32, 0x7a, 0x3a, 0x4f, 0x9a, + 0xe6, 0x81, 0x74, 0xac, 0x33, 0x97, 0xd0, 0xbe, 0x7b, 0x7a, 0x8a, 0xbc, 0x27, 0xff, 0xe1, 0x6b, + 0x93, 0x6e, 0x98, 0x50, 0x89, 0x47, 0xcf, 0x70, 0x1d, 0xd4, 0xb6, 0x9d, 0x8e, 0x2f, 0x9b, 0xe8, + 0x09, 0x06, 0xcb, 0x97, 0x6c, 0x9b, 0x63, 0x60, 0xe1, 0xe9, 0x6b, 0xda, 0x7b, 0xf2, 0xb8, 0xdb, + 0xc4, 0x45, 0x9f, 0x37, 0xbd, 0x9d, 0x35, 0xe4, 0x19, 0xf0, 0xaf, 0xd5, 0x81, 0x1a, 0x37, 0xf3, + 0xff, 0x6b, 0xdc, 0x10, 0x8d, 0xa3, 0x81, 0x0a, 0xbd, 0x3d, 0xc7, 0xc2, 0x72, 0x64, 0x7e, 0xb4, + 0x5c, 0x8a, 0x76, 0x27, 0xb8, 0x26, 0x7c, 0xf2, 0x97, 0x52, 0x97, 0x38, 0xd7, 0xda, 0x82, 0x1e, + 0x9d, 0x41, 0x5b, 0x07, 0x0f, 0xa3, 0x2f, 0x57, 0x5b, 0x6b, 0xb5, 0x55, 0x73, 0x7b, 0xa7, 0x6b, + 0x6e, 0xef, 0x78, 0x6e, 0xd5, 0x72, 0x3d, 0x64, 0x74, 0x1a, 0x5b, 0x3a, 0xbd, 0xee, 0x10, 0x10, + 0x3a, 0x32, 0x59, 0x45, 0x1f, 0x71, 0xb9, 0xd1, 0x8d, 0xd7, 0x94, 0x88, 0x96, 0xf2, 0x78, 0xdc, + 0x52, 0xdc, 0xbd, 0x6e, 0x80, 0xe9, 0x75, 0x7d, 0x98, 0x86, 0xaa, 0xbe, 0xd7, 0x25, 0xcd, 0x85, + 0x64, 0x4e, 0x3a, 0xce, 0xc5, 0x70, 0x92, 0x7e, 0xb3, 0xf9, 0xb7, 0x3c, 0xc8, 0xad, 0x38, 0x46, + 0x6f, 0x07, 0x3e, 0x9b, 0xeb, 0x9f, 0xc7, 0xd5, 0x26, 0x02, 0xed, 0x54, 0x86, 0x69, 0xa7, 0x3a, + 0x44, 0x3b, 0xb3, 0x9c, 0x76, 0x46, 0x2f, 0x3a, 0x9f, 0x05, 0xb3, 0x6d, 0xbb, 0xdb, 0x45, 0x6d, + 0x2c, 0x8f, 0x6a, 0x87, 0xac, 0xf6, 0x4c, 0xeb, 0x42, 0x1a, 0xb9, 0x08, 0x04, 0x79, 0x4d, 0xba, + 0xc6, 0x4e, 0x95, 0x3e, 0x4c, 0x80, 0x2f, 0x53, 0x40, 0xb6, 0xd2, 0xd9, 0x46, 0xc2, 0x3a, 0x7c, + 0x86, 0x5b, 0x87, 0x3f, 0x05, 0xf2, 0x9e, 0xe1, 0x6c, 0x23, 0xcf, 0x5f, 0x27, 0xa0, 0x4f, 0xc1, + 0xfd, 0x24, 0x2a, 0x77, 0x3f, 0xc9, 0x0f, 0x81, 0x2c, 0x96, 0x19, 0x73, 0x8b, 0x7f, 0xd8, 0x20, + 0xf8, 0x89, 0xec, 0x17, 0x70, 0x89, 0x0b, 0xe4, 0x56, 0x7b, 0xf2, 0x41, 0x3f, 0xd6, 0xb9, 0x83, + 0xf1, 0xb3, 0xaf, 0x03, 0xd3, 0x66, 0xdb, 0xb6, 0xaa, 0xbb, 0xc6, 0x36, 0x62, 0xd5, 0x0c, 0x13, + 0xfc, 0xb7, 0x95, 0x5d, 0xfb, 0x5e, 0x93, 0x2d, 0x6a, 0x85, 0x09, 0xb8, 0x0a, 0x3b, 0x66, 0xa7, + 0x83, 0x2c, 0xd6, 0xb2, 0xd9, 0xd3, 0xd9, 0x33, 0x20, 0x8b, 0x79, 0xc0, 0xfa, 0x83, 0x8d, 0x85, + 0xe2, 0x31, 0x6d, 0x16, 0x37, 0x2b, 0xda, 0x78, 0x8b, 0x19, 0x71, 0xcd, 0x55, 0xc6, 0x6b, 0x88, + 0x56, 0x6e, 0x70, 0xe3, 0x7a, 0x14, 0xc8, 0x59, 0x76, 0x07, 0x0d, 0x1d, 0x84, 0x68, 0x2e, 0xed, + 0x71, 0x20, 0x87, 0x3a, 0xb8, 0x57, 0x50, 0x49, 0xf6, 0x33, 0xf1, 0xb2, 0xd4, 0x69, 0xe6, 0x64, + 0xae, 0x49, 0x83, 0xb8, 0x4d, 0xbf, 0x01, 0xfe, 0xc4, 0x14, 0x38, 0x4e, 0xfb, 0x80, 0xe6, 0xde, + 0x45, 0x4c, 0xea, 0x22, 0x82, 0xaf, 0x1f, 0x3c, 0x70, 0x1d, 0x17, 0x95, 0xfd, 0x24, 0xc8, 0xb9, + 0x7b, 0x17, 0x03, 0x23, 0x94, 0x3e, 0xf0, 0x4d, 0x57, 0x19, 0xcb, 0x70, 0xa6, 0x8e, 0x3a, 0x9c, + 0x09, 0x43, 0x93, 0xea, 0x37, 0xfe, 0x70, 0x20, 0xa3, 0x07, 0x3a, 0xfc, 0x81, 0x6c, 0xd0, 0x30, + 0x74, 0x1a, 0x4c, 0x19, 0x5b, 0x1e, 0x72, 0x42, 0x33, 0x91, 0x3d, 0xe2, 0xa1, 0xf2, 0x22, 0xda, + 0xb2, 0x1d, 0x2c, 0x16, 0x1a, 0xcb, 0x3a, 0x78, 0xe6, 0x5a, 0x2e, 0x10, 0x76, 0xd0, 0x6e, 0x01, + 0x27, 0x2c, 0x7b, 0x09, 0xf5, 0x98, 0x9c, 0x29, 0x8a, 0x73, 0xa4, 0x05, 0x1c, 0x7c, 0x71, 0xa0, + 0x2b, 0x99, 0x3f, 0xd8, 0x95, 0xc0, 0xcf, 0x26, 0x9d, 0x33, 0xf7, 0x01, 0x3d, 0x36, 0x0b, 0x4d, + 0x7b, 0x22, 0x98, 0xed, 0x30, 0x0f, 0xb1, 0xb6, 0x19, 0xb4, 0x92, 0xc8, 0xef, 0x84, 0xcc, 0xa1, + 0x22, 0x65, 0x79, 0x45, 0x5a, 0x01, 0x05, 0x72, 0x1c, 0x1b, 0x6b, 0x52, 0xae, 0xcf, 0x23, 0x9f, + 0x4c, 0xeb, 0x82, 0x4a, 0x71, 0x62, 0x5b, 0x28, 0xb3, 0x4f, 0xf4, 0xe0, 0xe3, 0x64, 0xb3, 0xef, + 0x78, 0x09, 0xa5, 0xdf, 0x1c, 0x7f, 0x25, 0x0f, 0xae, 0x29, 0x3b, 0xb6, 0xeb, 0x92, 0x23, 0x38, + 0xfd, 0x0d, 0xf3, 0x8d, 0x8a, 0x70, 0x53, 0xd9, 0x03, 0xba, 0xf9, 0x0d, 0x6a, 0x50, 0x93, 0x6b, + 0x1a, 0x7f, 0x29, 0x1d, 0x69, 0x2b, 0xd8, 0x7f, 0x88, 0x10, 0xfa, 0x7f, 0x8e, 0x46, 0xf2, 0x9e, + 0x8c, 0x4c, 0xf0, 0xaf, 0x84, 0xb2, 0x4a, 0xbf, 0xb9, 0x7c, 0x49, 0x01, 0xd7, 0xf6, 0x73, 0xb3, + 0x61, 0xb9, 0x41, 0x83, 0x79, 0xc8, 0x90, 0xf6, 0x22, 0xc6, 0x6d, 0x89, 0xbd, 0x98, 0x3c, 0xa2, + 0xee, 0x5c, 0x69, 0x11, 0x8b, 0x25, 0xe1, 0x81, 0x9e, 0xb8, 0x8b, 0xc9, 0x13, 0x93, 0x4f, 0x5f, + 0xb8, 0x7f, 0x98, 0x05, 0xc7, 0x57, 0x1c, 0x7b, 0xaf, 0xe7, 0x86, 0x3d, 0xd0, 0x9f, 0x0d, 0xde, + 0x90, 0xcd, 0xcb, 0x98, 0x06, 0xd7, 0x83, 0x19, 0x87, 0x59, 0x73, 0xe1, 0xf6, 0x2c, 0x9f, 0xc4, + 0xf7, 0x5e, 0xea, 0x61, 0x7a, 0xaf, 0xb0, 0x9f, 0xc9, 0x0a, 0xfd, 0x4c, 0x7f, 0xcf, 0x91, 0x1b, + 0xd0, 0x73, 0x7c, 0x59, 0x49, 0x38, 0xa8, 0xf6, 0x89, 0x28, 0xa2, 0xbf, 0x28, 0x83, 0xfc, 0x36, + 0xc9, 0xc8, 0xba, 0x8b, 0x47, 0xca, 0xd5, 0x8c, 0x10, 0xd7, 0xd9, 0xa7, 0xa1, 0x5c, 0x55, 0x5e, + 0x87, 0x13, 0x0d, 0x70, 0xf1, 0xdc, 0xa6, 0xaf, 0x54, 0xaf, 0xcd, 0x82, 0xd9, 0xa0, 0xf4, 0x6a, + 0xc7, 0x15, 0x42, 0x52, 0x73, 0x1a, 0x35, 0x27, 0xa3, 0x51, 0x07, 0xd6, 0x99, 0x83, 0x51, 0x47, + 0xe5, 0x46, 0x9d, 0x81, 0xa3, 0xcb, 0x6c, 0xc4, 0xe8, 0x02, 0x9f, 0xa5, 0xca, 0xde, 0xf5, 0x29, + 0x76, 0xad, 0xa4, 0x36, 0x0f, 0xe4, 0xc1, 0x42, 0xf2, 0xc6, 0xd1, 0xe1, 0xb5, 0x4a, 0x5f, 0x49, + 0x3e, 0xa2, 0x80, 0x13, 0x07, 0x3b, 0xf3, 0x87, 0x8a, 0x5e, 0x6a, 0xb8, 0x4e, 0x6e, 0xe0, 0xa5, + 0x46, 0x9e, 0xc4, 0x4d, 0xba, 0xd8, 0x20, 0x28, 0x82, 0xbd, 0x37, 0xbc, 0x13, 0x97, 0x0b, 0x73, + 0x22, 0x49, 0x34, 0x7d, 0x01, 0xfe, 0xac, 0x0a, 0xa6, 0x9b, 0xc8, 0xab, 0x19, 0xfb, 0xf6, 0x9e, + 0x07, 0x0d, 0xd9, 0xed, 0xb9, 0x27, 0x80, 0x7c, 0x97, 0x7c, 0x42, 0x3a, 0x18, 0x3e, 0x52, 0x32, + 0xbf, 0xbf, 0x45, 0x7c, 0x83, 0x28, 0x69, 0x9d, 0xe5, 0x17, 0xa3, 0xcf, 0xc8, 0xec, 0x8e, 0x06, + 0xdc, 0x8d, 0x65, 0x6b, 0x27, 0xd1, 0xde, 0x69, 0x54, 0xd1, 0xe9, 0xc3, 0xf2, 0x5c, 0x15, 0xcc, + 0x35, 0x91, 0x57, 0x75, 0x97, 0x8d, 0xcb, 0xb6, 0x63, 0x7a, 0x08, 0xae, 0xc8, 0x42, 0x73, 0x06, + 0x00, 0x33, 0xf8, 0x8c, 0xc5, 0xc9, 0xe2, 0x52, 0xe0, 0x5b, 0x92, 0x3a, 0x0a, 0x09, 0x7c, 0x8c, + 0x05, 0x84, 0x44, 0x3e, 0x16, 0x71, 0xc5, 0xa7, 0x0f, 0xc4, 0x17, 0x14, 0x06, 0x44, 0xc9, 0x69, + 0xef, 0x98, 0x97, 0x51, 0x27, 0x21, 0x10, 0xfe, 0x67, 0x21, 0x10, 0x01, 0xa1, 0xc4, 0xee, 0x2b, + 0x02, 0x1f, 0xe3, 0x70, 0x5f, 0x89, 0x23, 0x38, 0x91, 0xb0, 0x56, 0xb8, 0xeb, 0x61, 0xeb, 0x99, + 0x77, 0xc9, 0x8a, 0x35, 0x34, 0xd9, 0x14, 0xde, 0x64, 0x1b, 0xa9, 0x63, 0xa1, 0x65, 0x0f, 0xd3, + 0xe9, 0x6c, 0x1a, 0x1d, 0xcb, 0xc0, 0xa2, 0xd3, 0x17, 0xfa, 0xfb, 0x54, 0x70, 0x75, 0x10, 0xef, + 0xa5, 0x89, 0xbc, 0x25, 0xc3, 0xdd, 0xb9, 0x68, 0x1b, 0x4e, 0x07, 0x96, 0xc7, 0x70, 0xe0, 0x10, + 0x7e, 0x9e, 0x07, 0xa1, 0x2e, 0x82, 0x30, 0xd0, 0x95, 0x74, 0x20, 0x2f, 0xe3, 0xe8, 0x64, 0x62, + 0xbd, 0x5d, 0xdf, 0x11, 0x80, 0xf5, 0x54, 0x01, 0xac, 0x27, 0x8d, 0xca, 0x62, 0xfa, 0xc0, 0xfd, + 0x3c, 0x1d, 0x11, 0x38, 0xaf, 0xe7, 0x0b, 0xb2, 0x80, 0x45, 0x78, 0xbd, 0xaa, 0x91, 0x5e, 0xaf, + 0x23, 0x8d, 0x11, 0x43, 0x3d, 0x96, 0xd3, 0x1d, 0x23, 0x8e, 0xd0, 0x1b, 0xf9, 0x5d, 0x2a, 0x28, + 0x92, 0x80, 0x5f, 0x9c, 0x47, 0x38, 0x1f, 0xf4, 0x3f, 0x1e, 0x9d, 0x03, 0xde, 0xe7, 0x53, 0x49, + 0xbd, 0xcf, 0xe1, 0x3b, 0x93, 0xfa, 0x98, 0xf7, 0x73, 0x3b, 0x16, 0xc4, 0x12, 0xb9, 0x90, 0x0f, + 0xe1, 0x20, 0x7d, 0xd0, 0x7e, 0x52, 0x05, 0x00, 0x37, 0x68, 0x76, 0x36, 0xe2, 0x69, 0xb2, 0x70, + 0xdd, 0xca, 0xfb, 0xdd, 0x63, 0xa0, 0xae, 0xee, 0x03, 0x8a, 0x52, 0x0c, 0x4f, 0x5d, 0xbc, 0x3e, + 0xa9, 0x6f, 0x65, 0xc8, 0xd5, 0x58, 0x60, 0x49, 0xe4, 0x6d, 0x19, 0x59, 0x76, 0xfa, 0x80, 0xfc, + 0xaa, 0x02, 0x72, 0x2d, 0xbb, 0x89, 0xbc, 0xc3, 0x9b, 0x02, 0x89, 0xa3, 0x06, 0x90, 0x72, 0xc7, + 0x11, 0x35, 0x60, 0x10, 0xa1, 0xf4, 0x45, 0xf7, 0x5e, 0x05, 0xcc, 0xb6, 0xec, 0x72, 0xb0, 0x38, + 0x25, 0xef, 0xab, 0xfa, 0x2f, 0x99, 0x84, 0x6b, 0x18, 0x7c, 0x31, 0x11, 0x02, 0x4b, 0xb4, 0x7a, + 0x10, 0x43, 0x2f, 0x7d, 0xb9, 0xdd, 0x0e, 0x8e, 0x6f, 0x58, 0x1d, 0x5b, 0x47, 0x1d, 0x9b, 0xad, + 0x74, 0x6b, 0x1a, 0xc8, 0xee, 0x59, 0x1d, 0x9b, 0xb0, 0x9c, 0xd3, 0xc9, 0x7f, 0x9c, 0xe6, 0xa0, + 0x8e, 0xcd, 0x7c, 0x03, 0xc8, 0x7f, 0xf8, 0x97, 0x2a, 0xc8, 0xe2, 0x6f, 0xe5, 0x45, 0xfd, 0x2e, + 0x35, 0x61, 0x1c, 0x04, 0x4c, 0x7e, 0x2c, 0x96, 0xd0, 0x5d, 0xdc, 0xda, 0xbf, 0xda, 0x77, 0xff, + 0x41, 0x5f, 0x79, 0x9c, 0x28, 0xc2, 0x35, 0x7f, 0xed, 0x34, 0x98, 0xba, 0xd8, 0xb5, 0xdb, 0x97, + 0xc2, 0xe3, 0xfa, 0xec, 0x51, 0xbb, 0x19, 0xe4, 0x1c, 0xc3, 0xda, 0x46, 0x6c, 0x4f, 0xe1, 0x64, + 0x5f, 0x5f, 0x48, 0xbc, 0x5e, 0x74, 0x9a, 0x05, 0xbe, 0x33, 0x49, 0x04, 0x86, 0x01, 0x95, 0x4f, + 0xa6, 0x0f, 0x4b, 0x23, 0x9c, 0x3c, 0x2b, 0x82, 0xd9, 0x72, 0xa9, 0x4e, 0x2f, 0x5f, 0x6d, 0x9c, + 0xab, 0x14, 0x55, 0x02, 0x33, 0x96, 0x49, 0x8a, 0x30, 0x63, 0xf2, 0xff, 0x69, 0x61, 0x1e, 0x50, + 0xf9, 0xa3, 0x80, 0xf9, 0x33, 0x0a, 0x98, 0xab, 0x99, 0xae, 0x17, 0xe5, 0xed, 0x1f, 0x13, 0xef, + 0xf7, 0x45, 0x49, 0x4d, 0x65, 0xa1, 0x1c, 0xe9, 0x40, 0xbf, 0x89, 0xcc, 0xe1, 0xb8, 0x22, 0x26, + 0x73, 0x2c, 0x85, 0x70, 0x80, 0xba, 0x28, 0x89, 0x24, 0x13, 0x1b, 0x4a, 0x61, 0x21, 0x93, 0x37, + 0x94, 0x22, 0xcb, 0x4e, 0x5f, 0xbe, 0x7f, 0xa9, 0x80, 0x13, 0xb8, 0xf8, 0xb8, 0x65, 0xa9, 0x68, + 0x31, 0x0f, 0x5d, 0x96, 0x4a, 0xbc, 0x32, 0x7e, 0x80, 0x97, 0x71, 0xac, 0x8c, 0x0f, 0x23, 0x3a, + 0x61, 0x31, 0x47, 0x2c, 0xc3, 0x0e, 0x13, 0x73, 0xcc, 0x32, 0xec, 0xe8, 0x62, 0x8e, 0x5f, 0x8a, + 0x1d, 0x51, 0xcc, 0x47, 0xb6, 0xc0, 0xfa, 0x4b, 0x6a, 0x20, 0xe6, 0xc8, 0xb5, 0x8d, 0x18, 0x31, + 0x27, 0x3e, 0xd1, 0x0b, 0xdf, 0x3d, 0xa2, 0xe0, 0xc7, 0xbc, 0xbe, 0x31, 0x0a, 0x4c, 0x47, 0xb8, + 0xc6, 0xf1, 0x0b, 0x2a, 0x98, 0x67, 0x5c, 0x0c, 0x9e, 0x32, 0xc7, 0x60, 0x94, 0x78, 0xca, 0x9c, + 0xf8, 0x0c, 0x90, 0xc8, 0xd9, 0xe4, 0xcf, 0x00, 0xc5, 0x96, 0x9f, 0x3e, 0x38, 0x5f, 0xcf, 0x82, + 0x53, 0x98, 0x85, 0x35, 0xbb, 0x63, 0x6e, 0xed, 0x53, 0x2e, 0xce, 0x19, 0xdd, 0x3d, 0xe4, 0xc2, + 0x0f, 0x28, 0xb2, 0x28, 0xfd, 0x57, 0x00, 0xec, 0x1e, 0x72, 0x68, 0x1c, 0x37, 0x06, 0xd4, 0x9d, + 0x51, 0x95, 0x3d, 0x58, 0x52, 0x70, 0x7d, 0x4e, 0xc3, 0x27, 0xa2, 0x73, 0xf4, 0xb0, 0x55, 0x38, + 0x1d, 0xbc, 0xe9, 0x77, 0xf0, 0xc8, 0x1c, 0x74, 0xf0, 0xb8, 0x09, 0xa8, 0x46, 0xa7, 0x13, 0x40, + 0xd5, 0xbf, 0x99, 0x4d, 0xca, 0xd4, 0x71, 0x16, 0x9c, 0xd3, 0x45, 0xe1, 0xd1, 0xbc, 0x88, 0x9c, + 0x2e, 0xf2, 0xb4, 0x05, 0x90, 0x77, 0x48, 0x4c, 0xe2, 0x60, 0x45, 0x7f, 0x70, 0x66, 0x96, 0x4b, + 0x34, 0xed, 0x1a, 0xa2, 0x1a, 0xde, 0x9e, 0x48, 0x32, 0x83, 0xfa, 0xe9, 0xd0, 0x4e, 0xd6, 0x05, + 0x05, 0x7b, 0xf2, 0xc8, 0x94, 0x27, 0xb3, 0x1b, 0x56, 0xea, 0xf5, 0xba, 0xfb, 0x2d, 0x16, 0x78, + 0x20, 0xd1, 0x6e, 0x18, 0x17, 0xbf, 0x40, 0x39, 0x10, 0xbf, 0x20, 0xf1, 0x6e, 0x98, 0xc0, 0xc7, + 0x38, 0x76, 0xc3, 0xe2, 0x08, 0xa6, 0x2f, 0xda, 0x6f, 0x16, 0xa8, 0xd5, 0xcc, 0x6e, 0x23, 0xf8, + 0x87, 0xc1, 0x9e, 0xd5, 0x40, 0x74, 0x76, 0x19, 0x74, 0x51, 0x41, 0xec, 0x2d, 0x2c, 0xda, 0xe3, + 0x40, 0x7e, 0xcb, 0x76, 0x76, 0x0d, 0x7f, 0xe3, 0xbe, 0xff, 0xa4, 0x08, 0xbb, 0x01, 0x60, 0x99, + 0xe4, 0xd1, 0x59, 0x5e, 0x3c, 0x1f, 0x79, 0xa6, 0xd9, 0x63, 0x41, 0x1f, 0xf1, 0x5f, 0xed, 0x06, + 0x30, 0xc7, 0x62, 0x3f, 0xd6, 0x91, 0xeb, 0xa1, 0x0e, 0x8b, 0x68, 0x21, 0x26, 0x6a, 0x67, 0xc1, + 0x2c, 0x4b, 0x58, 0x36, 0xbb, 0xc8, 0x65, 0x41, 0x2d, 0x84, 0x34, 0xed, 0x14, 0xc8, 0x9b, 0xee, + 0xdd, 0xae, 0x6d, 0xb1, 0x80, 0x7c, 0xec, 0x49, 0xbb, 0x09, 0x1c, 0x67, 0xf9, 0x02, 0x63, 0x95, + 0x1e, 0xd8, 0xe9, 0x4f, 0xc6, 0xaa, 0x65, 0xd9, 0xeb, 0x8e, 0xbd, 0xed, 0x20, 0xd7, 0x25, 0xa7, + 0xa6, 0x0a, 0x3a, 0x97, 0xa2, 0x5d, 0x00, 0x27, 0xba, 0xa6, 0x75, 0xc9, 0x25, 0x31, 0x82, 0x97, + 0x99, 0xdb, 0xd8, 0xec, 0x80, 0xd8, 0xdd, 0x5c, 0x63, 0x63, 0x72, 0xe0, 0x3f, 0xd1, 0x0f, 0x52, + 0xd1, 0x6e, 0x06, 0x45, 0xc6, 0xcd, 0xa2, 0xd1, 0xbe, 0x44, 0xde, 0x33, 0x77, 0xd4, 0x03, 0xe9, + 0x9c, 0x30, 0x68, 0x18, 0xfd, 0x79, 0x41, 0x18, 0x34, 0x92, 0xfe, 0x4b, 0x32, 0x60, 0x56, 0x28, + 0xc0, 0x00, 0x9a, 0xdf, 0x2d, 0xba, 0xe7, 0x77, 0x4c, 0x0f, 0x61, 0xe6, 0xd8, 0x59, 0x97, 0xc7, + 0x0c, 0x61, 0x5e, 0x3f, 0xf0, 0xa1, 0x3e, 0x80, 0x18, 0xe6, 0x8b, 0x76, 0x78, 0xc4, 0xb3, 0xcc, + 0x65, 0xb6, 0xaa, 0x90, 0x06, 0x9f, 0x09, 0xb4, 0x83, 0xd4, 0x38, 0x2f, 0x90, 0x4c, 0x32, 0x2f, + 0x10, 0x2c, 0x37, 0xa3, 0xdb, 0xb5, 0xaf, 0xa0, 0x4e, 0x40, 0x96, 0xe9, 0xea, 0x81, 0x74, 0xf8, + 0xb9, 0x51, 0xe6, 0x85, 0x89, 0x2f, 0xd6, 0xc0, 0x8d, 0x6c, 0xaf, 0xdd, 0x46, 0xa8, 0xc3, 0x0e, + 0xae, 0xf9, 0x8f, 0x09, 0xaf, 0xdc, 0x48, 0x3c, 0x8b, 0x3c, 0xa2, 0x3b, 0x37, 0xde, 0x1f, 0xde, + 0x7c, 0xb2, 0x27, 0xd3, 0xd5, 0xc4, 0x9d, 0x8f, 0x1f, 0xa9, 0x53, 0x81, 0xef, 0x4d, 0x7a, 0x5a, + 0x34, 0x16, 0xd3, 0x53, 0x78, 0x70, 0x77, 0xf7, 0xba, 0xc1, 0x71, 0x27, 0xfa, 0x94, 0x10, 0xbd, + 0x44, 0x07, 0x48, 0x8f, 0x08, 0xb9, 0x8f, 0x5f, 0x0d, 0xf2, 0xf4, 0xe6, 0x42, 0xf8, 0x92, 0xf9, + 0x81, 0xd0, 0xcd, 0x8b, 0xd0, 0x6d, 0x80, 0x59, 0xcb, 0xc6, 0xc5, 0xad, 0x1b, 0x8e, 0xb1, 0xeb, + 0xc6, 0x2d, 0xef, 0x53, 0xba, 0x81, 0x2d, 0x57, 0xe7, 0x3e, 0x5b, 0x3d, 0xa6, 0x0b, 0x64, 0xb4, + 0xff, 0x0b, 0x1c, 0xbf, 0xc8, 0x42, 0x73, 0xb8, 0x8c, 0xb2, 0x12, 0xed, 0xfc, 0xda, 0x47, 0x79, + 0x51, 0xfc, 0x72, 0xf5, 0x98, 0xde, 0x4f, 0x4c, 0xfb, 0x2f, 0x60, 0x1e, 0x3f, 0x76, 0xec, 0x2b, + 0x3e, 0xe3, 0x6a, 0xf4, 0x0c, 0xa0, 0x8f, 0xfc, 0x9a, 0xf0, 0xe1, 0xea, 0x31, 0xbd, 0x8f, 0x94, + 0xd6, 0x00, 0x60, 0xc7, 0xdb, 0xed, 0x32, 0xc2, 0xd9, 0xe8, 0xce, 0xa4, 0x8f, 0xf0, 0x6a, 0xf0, + 0xd1, 0xea, 0x31, 0x9d, 0x23, 0xa1, 0xd5, 0xc0, 0xb4, 0x77, 0x9f, 0xc7, 0xe8, 0xe5, 0xa2, 0xbd, + 0x4e, 0xfa, 0xe8, 0xb5, 0xfc, 0x6f, 0x56, 0x8f, 0xe9, 0x21, 0x01, 0xad, 0x0a, 0x0a, 0xbd, 0x8b, + 0x8c, 0x58, 0x3e, 0x7a, 0xa4, 0xea, 0x23, 0xb6, 0x7e, 0x31, 0xa0, 0x15, 0x7c, 0x8e, 0x19, 0x6b, + 0xbb, 0x97, 0x19, 0xad, 0x29, 0x69, 0xc6, 0xca, 0xfe, 0x37, 0x98, 0xb1, 0x80, 0x80, 0x56, 0x05, + 0xd3, 0xae, 0x65, 0xf4, 0xdc, 0x1d, 0xdb, 0x73, 0x4f, 0x17, 0xfa, 0x1c, 0x94, 0xa3, 0xa9, 0x35, + 0xd9, 0x37, 0x7a, 0xf8, 0xb5, 0xf6, 0x38, 0x70, 0xf5, 0x5e, 0xaf, 0x63, 0x78, 0xa8, 0x72, 0x9f, + 0xe9, 0x86, 0xb7, 0x57, 0xfa, 0xe7, 0x72, 0x07, 0xbf, 0xd4, 0x16, 0xd8, 0x51, 0x45, 0x40, 0xda, + 0x25, 0xec, 0xdf, 0x25, 0xa7, 0xc5, 0x72, 0x27, 0x14, 0x9f, 0x08, 0xb2, 0xf8, 0x15, 0x31, 0x0b, + 0xe6, 0x07, 0xaf, 0xc0, 0xf7, 0xeb, 0x0e, 0x69, 0xc0, 0xf8, 0xa3, 0x3e, 0xcb, 0x62, 0xf6, 0x80, + 0x65, 0x71, 0x3d, 0x98, 0x31, 0xdd, 0x35, 0x73, 0x9b, 0x4e, 0x6b, 0xd8, 0xc8, 0xcf, 0x27, 0xd1, + 0x65, 0xa0, 0x3a, 0xba, 0x42, 0x87, 0xfc, 0xe3, 0xfe, 0x32, 0x90, 0x9f, 0x02, 0x6f, 0x04, 0xb3, + 0x7c, 0x23, 0xa3, 0x77, 0x42, 0x9b, 0xe1, 0xa4, 0x88, 0x3d, 0xc1, 0x1b, 0xc0, 0xbc, 0xa8, 0xd3, + 0x9c, 0xed, 0xa7, 0xfa, 0x83, 0x18, 0x7c, 0x18, 0x38, 0xde, 0xd7, 0xb0, 0xfc, 0x60, 0x3f, 0x99, + 0x30, 0xd8, 0xcf, 0xf5, 0x00, 0x84, 0x5a, 0x3c, 0x90, 0xcc, 0x43, 0xc0, 0x74, 0xa0, 0x97, 0x03, + 0x33, 0x7c, 0x2d, 0x03, 0x0a, 0xbe, 0xb2, 0x0d, 0xca, 0x80, 0x6d, 0x0a, 0x8b, 0xdb, 0xd9, 0xf3, + 0x6d, 0x0a, 0x3e, 0x0d, 0x1b, 0x78, 0xa1, 0x3f, 0x7d, 0xcb, 0xf4, 0xba, 0xfe, 0x99, 0xd4, 0xfe, + 0x64, 0x6d, 0x1d, 0x00, 0x93, 0x60, 0xd4, 0x0a, 0x0f, 0xa9, 0x3e, 0x3a, 0x41, 0x7b, 0xa0, 0xfa, + 0xc0, 0xd1, 0x38, 0xfb, 0x50, 0x76, 0x82, 0x74, 0x1a, 0xe4, 0xe8, 0x05, 0x0b, 0xc7, 0xb4, 0x79, + 0x00, 0x2a, 0x4f, 0x5b, 0xaf, 0xe8, 0xd5, 0x4a, 0xbd, 0x5c, 0x29, 0x66, 0xe0, 0xcb, 0x15, 0x30, + 0x1d, 0x34, 0x82, 0x81, 0x95, 0xac, 0x30, 0xd5, 0x1a, 0x7a, 0xc3, 0xec, 0xc1, 0x46, 0xc5, 0x2b, + 0xd9, 0x13, 0xc0, 0x83, 0xf6, 0x5c, 0xb4, 0x6c, 0x3a, 0xae, 0xa7, 0xdb, 0x57, 0x96, 0x6d, 0x27, + 0x34, 0x89, 0x68, 0x68, 0xe2, 0xa8, 0xd7, 0xd8, 0xd4, 0xef, 0x20, 0x72, 0x5a, 0x11, 0x39, 0x6c, + 0xcb, 0x26, 0x4c, 0xc0, 0x74, 0x3d, 0xc7, 0xb0, 0xdc, 0x9e, 0xed, 0x22, 0xdd, 0xbe, 0xe2, 0x96, + 0xac, 0x4e, 0xd9, 0xee, 0xee, 0xed, 0x5a, 0x2e, 0x33, 0xd6, 0xa3, 0x5e, 0x63, 0xe9, 0x90, 0xfb, + 0xa3, 0xe7, 0x01, 0x28, 0x37, 0x6a, 0xb5, 0x4a, 0xb9, 0x55, 0x6d, 0xd4, 0x8b, 0xc7, 0xb0, 0xb4, + 0x5a, 0xa5, 0xc5, 0x1a, 0x96, 0xce, 0xd3, 0x41, 0xc1, 0x6f, 0xd3, 0x2c, 0x3e, 0x51, 0xc6, 0x8f, + 0x4f, 0xa4, 0x95, 0x40, 0xc1, 0x6f, 0xe5, 0x6c, 0x44, 0x78, 0x78, 0xff, 0x79, 0xf4, 0x5d, 0xc3, + 0xf1, 0x88, 0x69, 0xe9, 0x13, 0x59, 0x34, 0x5c, 0xa4, 0x07, 0x9f, 0x9d, 0x7d, 0x14, 0xe3, 0x40, + 0x03, 0xf3, 0xa5, 0x5a, 0x6d, 0xb3, 0xa1, 0x6f, 0xd6, 0x1b, 0xad, 0xd5, 0x6a, 0x7d, 0x85, 0x8e, + 0x90, 0xd5, 0x95, 0x7a, 0x43, 0xaf, 0xd0, 0x01, 0xb2, 0x59, 0xcc, 0xdc, 0x91, 0xbd, 0xff, 0xeb, + 0x6a, 0x66, 0xb1, 0x00, 0xf2, 0x3d, 0x22, 0x5d, 0xf8, 0x25, 0x35, 0xa1, 0x69, 0x11, 0xe0, 0x14, + 0x71, 0xc3, 0xb2, 0x70, 0x18, 0x44, 0x19, 0x70, 0x58, 0xfb, 0x2c, 0x98, 0xa5, 0xe6, 0x90, 0x4b, + 0xf6, 0xd5, 0x08, 0x72, 0xaa, 0x2e, 0xa4, 0xc1, 0x4f, 0x28, 0x09, 0x8c, 0x8b, 0x81, 0x1c, 0x25, + 0x33, 0x2e, 0xfe, 0x28, 0x33, 0xda, 0x75, 0x24, 0xd5, 0x7a, 0xab, 0xa2, 0xd7, 0x4b, 0x35, 0x96, + 0x45, 0xd5, 0x4e, 0x83, 0x93, 0xf5, 0x06, 0x0b, 0xc6, 0xd9, 0xdc, 0x6c, 0x35, 0x36, 0xab, 0x6b, + 0xeb, 0x0d, 0xbd, 0x55, 0xcc, 0x69, 0xa7, 0x80, 0x46, 0xff, 0x6f, 0x56, 0x9b, 0x9b, 0xe5, 0x52, + 0xbd, 0x5c, 0xa9, 0x55, 0x96, 0x8a, 0x79, 0xed, 0x11, 0xe0, 0x61, 0xf4, 0x7a, 0xab, 0xc6, 0xf2, + 0xa6, 0xde, 0x38, 0xdf, 0xc4, 0x08, 0xea, 0x95, 0x5a, 0x09, 0x2b, 0x52, 0x33, 0xbc, 0xf3, 0x6a, + 0x4a, 0xbb, 0x0a, 0x1c, 0x5f, 0xae, 0xd6, 0x2a, 0xe4, 0x36, 0x5a, 0x56, 0x5e, 0x41, 0xbb, 0x0e, + 0x9c, 0xae, 0xd6, 0x9b, 0x1b, 0xcb, 0xcb, 0xd5, 0x72, 0xb5, 0x52, 0x6f, 0x6d, 0xae, 0x57, 0xf4, + 0xb5, 0x6a, 0xb3, 0x89, 0xbf, 0x2d, 0x4e, 0xc3, 0x8f, 0xab, 0x20, 0x4f, 0xfb, 0x4c, 0x6c, 0xc4, + 0xce, 0x9d, 0x33, 0xba, 0x26, 0x1e, 0x28, 0x5a, 0xf6, 0x25, 0x64, 0xf5, 0x9d, 0xe3, 0xf2, 0x70, + 0x9a, 0x7f, 0x12, 0x84, 0x3c, 0xc0, 0x1f, 0x53, 0x13, 0x9e, 0xe3, 0x62, 0x40, 0xd0, 0x12, 0x17, + 0x84, 0xd2, 0x22, 0x56, 0x1d, 0x5e, 0xa3, 0x24, 0x38, 0xc7, 0x25, 0x4f, 0x3e, 0x19, 0xf8, 0xbf, + 0x38, 0x2e, 0xf0, 0x8b, 0x60, 0x76, 0xa3, 0x5e, 0xda, 0x68, 0xad, 0x36, 0xf4, 0xea, 0x0f, 0x93, + 0x5b, 0x08, 0xe6, 0xc0, 0xf4, 0x72, 0x43, 0x5f, 0xac, 0x2e, 0x2d, 0x55, 0xea, 0xc5, 0x9c, 0xf6, + 0x20, 0x70, 0x55, 0xb3, 0xa2, 0x9f, 0xab, 0x96, 0x2b, 0x9b, 0x1b, 0xf5, 0xd2, 0xb9, 0x52, 0xb5, + 0x46, 0xfa, 0x88, 0x7c, 0xcc, 0x4d, 0xf5, 0x53, 0xf0, 0x47, 0xb2, 0x00, 0xd0, 0xaa, 0x93, 0x4b, + 0xb8, 0xb8, 0x0b, 0xd2, 0xff, 0x24, 0xe9, 0x74, 0x2f, 0x24, 0x13, 0xd1, 0x7e, 0xab, 0xa0, 0xe0, + 0xb0, 0x17, 0x6c, 0x5d, 0x73, 0x18, 0x1d, 0xfa, 0xd7, 0xa7, 0xa6, 0x07, 0x9f, 0xc3, 0x0f, 0x24, + 0x99, 0xdd, 0x45, 0x32, 0x36, 0x91, 0x9b, 0x9e, 0xfb, 0x81, 0x84, 0x2f, 0xcc, 0x80, 0x79, 0xb1, + 0x62, 0xb8, 0x12, 0xc4, 0x98, 0x92, 0xab, 0x84, 0xf8, 0x31, 0x67, 0x64, 0x9d, 0x7d, 0x2c, 0x1b, + 0x4e, 0x81, 0xdf, 0x32, 0x69, 0x48, 0x06, 0xdf, 0x62, 0x29, 0x66, 0x30, 0xf3, 0xd8, 0xe8, 0x28, + 0x2a, 0xda, 0x14, 0x50, 0x5b, 0xf7, 0x79, 0x45, 0x15, 0x7e, 0x2a, 0x0b, 0xe6, 0x84, 0x1b, 0xd8, + 0xe1, 0x9f, 0x66, 0x64, 0x6e, 0x37, 0xe6, 0xee, 0x76, 0xcf, 0x1c, 0xf6, 0x6e, 0xf7, 0xb3, 0x26, + 0x98, 0x62, 0x69, 0x44, 0xbe, 0x8d, 0x3a, 0x36, 0x05, 0x8e, 0x83, 0x99, 0x95, 0x4a, 0x6b, 0xb3, + 0xd9, 0x2a, 0xe9, 0xad, 0xca, 0x52, 0x31, 0x83, 0x07, 0xbe, 0xca, 0xda, 0x7a, 0xeb, 0x42, 0x51, + 0xc1, 0x63, 0xe2, 0xca, 0x46, 0x75, 0xa9, 0xb2, 0xd9, 0xa8, 0xd7, 0x2e, 0x14, 0x55, 0xdc, 0x03, + 0x72, 0x79, 0x37, 0xd7, 0x1a, 0x8b, 0xd5, 0x5a, 0xa5, 0x98, 0xc5, 0xcd, 0x86, 0x7c, 0xe2, 0xa7, + 0xe4, 0x44, 0xdf, 0x68, 0x99, 0x15, 0xce, 0xfe, 0x2a, 0x1c, 0xde, 0x45, 0x24, 0xc9, 0x15, 0xf2, + 0x89, 0xd6, 0x4e, 0xe3, 0x58, 0x4d, 0x7f, 0x46, 0xfc, 0x59, 0x15, 0x14, 0x29, 0x07, 0x95, 0xfb, + 0x7a, 0xc8, 0x31, 0x91, 0xd5, 0x46, 0xf0, 0x92, 0x4c, 0x40, 0xe0, 0x03, 0xa1, 0x30, 0xc9, 0xa8, + 0xc1, 0xd9, 0xa2, 0xf4, 0xa1, 0xcf, 0x8c, 0xcf, 0x1e, 0x30, 0xe3, 0x7f, 0x2f, 0xa9, 0x07, 0x6e, + 0x3f, 0xbb, 0x63, 0xd9, 0xb3, 0xfa, 0x74, 0x12, 0x0f, 0xdc, 0x21, 0x1c, 0x4c, 0x24, 0xce, 0x77, + 0xc4, 0x28, 0x5f, 0x54, 0xe1, 0x0b, 0x54, 0x70, 0x7c, 0xc9, 0xf0, 0xd0, 0xe2, 0x7e, 0xcb, 0xbf, + 0x47, 0x35, 0xe2, 0xee, 0xf3, 0xcc, 0x81, 0xbb, 0xcf, 0xc3, 0xab, 0x58, 0x95, 0xbe, 0xab, 0x58, + 0xe1, 0x7b, 0x92, 0x9e, 0xd9, 0xed, 0xe3, 0x61, 0x6c, 0xc1, 0xb8, 0x93, 0x9d, 0xc5, 0x8d, 0xe7, + 0x22, 0xfd, 0x06, 0xf6, 0xf6, 0x69, 0x50, 0xa4, 0xac, 0x70, 0x4e, 0xa6, 0x3f, 0xab, 0x02, 0xb5, + 0xd4, 0xe9, 0xc0, 0xcd, 0x04, 0x31, 0x3d, 0xfd, 0x28, 0x29, 0x8a, 0x18, 0x25, 0x45, 0xd8, 0xb3, + 0x50, 0xfb, 0x1d, 0x83, 0x92, 0x9e, 0x46, 0xe0, 0x3c, 0x4a, 0xa3, 0xc3, 0x28, 0xa7, 0x77, 0x1a, + 0x21, 0xb6, 0xf8, 0xc9, 0x5c, 0x69, 0xcd, 0x6e, 0x91, 0xad, 0xc8, 0x22, 0x13, 0x7f, 0x73, 0x7f, + 0xd2, 0xe3, 0x05, 0x82, 0x47, 0x6f, 0xcc, 0x75, 0xf6, 0xe9, 0x1d, 0x2f, 0x18, 0xc6, 0x41, 0xfa, + 0x28, 0x7c, 0x4f, 0x01, 0xd9, 0xa6, 0xed, 0x78, 0xe3, 0xc2, 0x20, 0xa9, 0x4b, 0x04, 0x27, 0x81, + 0x66, 0xf4, 0xcc, 0x36, 0x3d, 0x97, 0x88, 0xf8, 0xf2, 0x27, 0x10, 0x16, 0xf5, 0x38, 0x98, 0xa7, + 0x9c, 0x04, 0x77, 0x0a, 0xfd, 0xab, 0x42, 0xfb, 0xab, 0x7b, 0x64, 0x11, 0x21, 0x1b, 0x63, 0x81, + 0x4b, 0x82, 0x0f, 0x8a, 0x90, 0x06, 0xdf, 0xc8, 0xe3, 0xb2, 0x24, 0xe2, 0x32, 0x68, 0x5e, 0x1f, + 0x5c, 0xcb, 0x33, 0xae, 0x9e, 0x29, 0x49, 0x84, 0xd5, 0x98, 0xc2, 0xd3, 0x47, 0xe4, 0x39, 0x2a, + 0xc8, 0x33, 0x97, 0xd0, 0xb1, 0x22, 0x90, 0xb4, 0x65, 0x04, 0x42, 0x90, 0x73, 0x1d, 0x55, 0xc7, + 0xdd, 0x32, 0xe2, 0xcb, 0x4f, 0x1f, 0x87, 0x7f, 0x67, 0xbe, 0xce, 0xa5, 0xcb, 0x86, 0xd9, 0x35, + 0x2e, 0x76, 0x13, 0x44, 0x36, 0xff, 0x44, 0xc2, 0xd3, 0x9d, 0x41, 0x55, 0x85, 0xf2, 0x22, 0x24, + 0xfe, 0x83, 0x60, 0xda, 0x11, 0xf6, 0x82, 0xb1, 0x15, 0xd5, 0xe7, 0x67, 0xce, 0xde, 0xeb, 0x61, + 0xce, 0x44, 0x47, 0x39, 0xa5, 0xf8, 0x99, 0xc8, 0xd1, 0xb3, 0x99, 0x52, 0xa7, 0xb3, 0x8c, 0x0c, + 0x6f, 0xcf, 0x41, 0x9d, 0x44, 0x43, 0x84, 0xd3, 0xb7, 0x5d, 0xce, 0x49, 0x42, 0x88, 0x2d, 0x5a, + 0x13, 0xd1, 0x79, 0xfc, 0x90, 0xde, 0xc0, 0xe7, 0x65, 0x2c, 0x5d, 0xd2, 0xdb, 0x02, 0x48, 0x1a, + 0x02, 0x24, 0x4f, 0x1c, 0x8d, 0x89, 0xf4, 0x01, 0x79, 0xa9, 0x0a, 0xe6, 0xa9, 0x9d, 0x30, 0x6e, + 0x4c, 0x3e, 0x9c, 0xd0, 0x85, 0x8c, 0xbb, 0xb5, 0x8d, 0x67, 0x67, 0x2c, 0xb0, 0x24, 0x71, 0x38, + 0x93, 0xe3, 0x23, 0x7d, 0x64, 0xfe, 0xd7, 0x55, 0x00, 0x70, 0x6e, 0xc1, 0x9f, 0xc8, 0x87, 0x71, + 0x3e, 0xe1, 0x3b, 0xd9, 0xfc, 0xa3, 0x29, 0x04, 0x9d, 0xe7, 0x5c, 0x7e, 0x83, 0x6d, 0x2f, 0x31, + 0x51, 0x6a, 0x54, 0xf9, 0xa3, 0x84, 0x36, 0x2f, 0x73, 0xca, 0x1d, 0x3a, 0xb8, 0x8f, 0xd8, 0xcb, + 0x7d, 0x32, 0x81, 0xf1, 0x3b, 0x8c, 0x95, 0x64, 0xa8, 0xd5, 0x46, 0x98, 0xd9, 0x9f, 0x06, 0x27, + 0xf5, 0x4a, 0x69, 0xa9, 0x51, 0xaf, 0x5d, 0xe0, 0xaf, 0xf0, 0x2a, 0xaa, 0xfc, 0xe4, 0x24, 0x15, + 0xd8, 0x5e, 0x97, 0xb0, 0x0f, 0x14, 0x65, 0x15, 0x37, 0x5b, 0xe1, 0x16, 0x57, 0x86, 0xf7, 0x6a, + 0x12, 0x64, 0x8f, 0x12, 0x85, 0x6f, 0xe5, 0xc1, 0x8c, 0x8e, 0xda, 0xf6, 0xee, 0x2e, 0xb2, 0x3a, + 0xa8, 0x03, 0x5f, 0xa7, 0x82, 0xd9, 0x60, 0x57, 0xb1, 0x89, 0x3c, 0xf8, 0x5f, 0x42, 0x6c, 0xce, + 0x82, 0x59, 0x5c, 0xb9, 0x86, 0x78, 0x91, 0x80, 0x90, 0xa6, 0xdd, 0x02, 0x4e, 0xf8, 0x28, 0x34, + 0xfa, 0xa6, 0x30, 0x07, 0x5f, 0x88, 0x7e, 0x3f, 0x1b, 0x22, 0x46, 0x77, 0x45, 0x0b, 0x33, 0x60, + 0x77, 0x81, 0x67, 0x35, 0x02, 0xac, 0x3f, 0x08, 0xc0, 0x7a, 0x9a, 0x00, 0xd6, 0xd2, 0x21, 0xe9, + 0x1f, 0x25, 0x6a, 0x1f, 0x52, 0xc1, 0x49, 0xbf, 0x23, 0x9e, 0x1c, 0x5a, 0x9f, 0xe4, 0xd1, 0x7a, + 0xba, 0x88, 0xd6, 0x8a, 0x8c, 0x34, 0x07, 0xb1, 0x1c, 0x81, 0xda, 0x17, 0x03, 0xd4, 0xfe, 0x9b, + 0x80, 0x5a, 0x6d, 0x4c, 0xe5, 0x1c, 0x25, 0x7a, 0x1f, 0x56, 0xc1, 0x69, 0x6c, 0x76, 0x96, 0x6d, + 0x6b, 0xab, 0x6b, 0xb6, 0x3d, 0xd3, 0xda, 0x0e, 0x5d, 0x1c, 0x57, 0x64, 0x56, 0x36, 0xfb, 0xb1, + 0x55, 0x0e, 0x62, 0x2b, 0xee, 0x31, 0xc8, 0xb6, 0xad, 0x28, 0xb6, 0x22, 0x86, 0x30, 0xce, 0x79, + 0x3f, 0xd4, 0x1c, 0x3e, 0x29, 0x79, 0xeb, 0x93, 0xe4, 0xe0, 0x28, 0xf1, 0xfb, 0x9a, 0x02, 0x4e, + 0xe9, 0xc8, 0xb5, 0xbb, 0x97, 0x11, 0xf5, 0x65, 0xf5, 0xf9, 0x75, 0xe1, 0xa3, 0x12, 0xb5, 0x3f, + 0xf8, 0x52, 0x1e, 0xa3, 0xa6, 0x88, 0xd1, 0x93, 0xa2, 0x35, 0x7d, 0x50, 0xd1, 0x11, 0xed, 0xe8, + 0xbd, 0x81, 0xfc, 0xcf, 0x09, 0xf2, 0x5f, 0x3c, 0x14, 0xf5, 0x09, 0x2c, 0x11, 0x00, 0xce, 0xbc, + 0x7b, 0xbe, 0x0a, 0x8a, 0xc4, 0x67, 0x99, 0x8c, 0x9e, 0xec, 0x0e, 0xe1, 0x86, 0x78, 0x9a, 0xa5, + 0xe7, 0x2b, 0xa1, 0x7f, 0x9a, 0xc5, 0x4f, 0xd0, 0x6e, 0x04, 0xf3, 0xed, 0x1d, 0xd4, 0xbe, 0x54, + 0xb5, 0x7c, 0xaf, 0x32, 0xea, 0x82, 0xd4, 0x97, 0x2a, 0x1a, 0x0c, 0xf7, 0x88, 0x60, 0x88, 0x8b, + 0xbb, 0xc2, 0xe4, 0x91, 0x67, 0x2a, 0x02, 0x84, 0xdf, 0x0a, 0x40, 0xa8, 0x0b, 0x20, 0xdc, 0x31, + 0x12, 0xd5, 0x64, 0xc2, 0xaf, 0x8f, 0xa0, 0xfa, 0x10, 0x9c, 0x6a, 0xac, 0xb7, 0xaa, 0x8d, 0xfa, + 0xe6, 0x46, 0xb3, 0xb2, 0xb4, 0xb9, 0xe8, 0x37, 0x80, 0x66, 0x51, 0x85, 0xdf, 0x50, 0xc0, 0x14, + 0x65, 0xcb, 0x85, 0x8f, 0x0c, 0x21, 0x18, 0x7a, 0x8c, 0x07, 0xbe, 0x5d, 0x3a, 0x28, 0x57, 0x20, + 0x08, 0x56, 0x4e, 0x44, 0xe7, 0xf3, 0x04, 0x30, 0x45, 0x41, 0xf6, 0x77, 0x5a, 0xce, 0x44, 0x58, + 0xcf, 0x8c, 0x8c, 0xee, 0x67, 0x97, 0x0c, 0xd0, 0x35, 0x84, 0x8d, 0xf4, 0xdb, 0xc0, 0xb3, 0xb2, + 0x74, 0x79, 0xe6, 0xbc, 0xe9, 0xed, 0x90, 0x53, 0x3e, 0xf0, 0xa9, 0x32, 0x83, 0xc3, 0x2d, 0x20, + 0x77, 0x19, 0xe7, 0x1e, 0x72, 0x62, 0x8a, 0x66, 0x82, 0xbf, 0x28, 0x1d, 0x0f, 0x5e, 0xd0, 0xcf, + 0x80, 0xa7, 0x08, 0x70, 0xd6, 0x40, 0xb6, 0x6b, 0xba, 0x1e, 0x9b, 0xd7, 0xdc, 0x9e, 0x88, 0x90, + 0xff, 0xa7, 0xea, 0xa1, 0x5d, 0x9d, 0x90, 0x81, 0x77, 0x63, 0xab, 0x34, 0x4c, 0x95, 0x38, 0x35, + 0x76, 0x1a, 0x4c, 0xb1, 0x68, 0x06, 0x6c, 0xeb, 0xcf, 0x7f, 0x94, 0xdc, 0x6e, 0x93, 0xaa, 0x6d, + 0xfa, 0x3a, 0xf0, 0xff, 0x1e, 0x07, 0x53, 0xab, 0xa6, 0xeb, 0xd9, 0xce, 0x3e, 0x7c, 0x7d, 0x06, + 0x4c, 0x9d, 0x43, 0x8e, 0x6b, 0xda, 0xd6, 0x01, 0x47, 0xbb, 0xeb, 0xc1, 0x4c, 0xcf, 0x41, 0x97, + 0x4d, 0x7b, 0xcf, 0xe5, 0x46, 0x62, 0x2e, 0x49, 0x83, 0xa0, 0x60, 0xec, 0x79, 0x3b, 0xb6, 0x13, + 0x06, 0x41, 0xf3, 0x9f, 0xb5, 0x33, 0x00, 0xd0, 0xff, 0x75, 0x63, 0x17, 0x31, 0xf7, 0x41, 0x2e, + 0x45, 0xd3, 0x40, 0xd6, 0x33, 0x77, 0x11, 0xbb, 0x15, 0x81, 0xfc, 0xc7, 0x02, 0x26, 0x11, 0x86, + 0x59, 0x24, 0x67, 0x55, 0xf7, 0x1f, 0xe1, 0xe7, 0x55, 0x30, 0xb3, 0x82, 0x3c, 0xc6, 0xaa, 0x0b, + 0x5f, 0x94, 0x91, 0xba, 0x88, 0x0c, 0xcf, 0xfd, 0xba, 0x86, 0xeb, 0x7f, 0x17, 0x98, 0x35, 0x62, + 0x62, 0x78, 0x45, 0x83, 0xca, 0xdf, 0xcf, 0x42, 0xe2, 0xf5, 0x7a, 0x55, 0x7a, 0x80, 0x86, 0x65, + 0x66, 0x9b, 0xf3, 0x07, 0x5f, 0x88, 0xf3, 0x8e, 0xd8, 0x58, 0x37, 0x4c, 0xf6, 0x0b, 0x5c, 0x7d, + 0x22, 0xbb, 0xa3, 0xc2, 0x65, 0x96, 0xe3, 0xc0, 0xd5, 0x3b, 0x3c, 0x25, 0x46, 0x46, 0x0f, 0x72, + 0x4b, 0x46, 0xc9, 0x19, 0xce, 0xc9, 0x04, 0x2e, 0x5b, 0x56, 0xc1, 0x4c, 0x73, 0xc7, 0xbe, 0xe2, + 0xcb, 0xf1, 0xe9, 0x72, 0xc0, 0x5e, 0x07, 0xa6, 0x2f, 0xf7, 0x81, 0x1a, 0x26, 0xf0, 0xf7, 0x3b, + 0xaa, 0xe2, 0xfd, 0x8e, 0xf7, 0xab, 0x49, 0x61, 0xe2, 0x98, 0x8b, 0x80, 0x49, 0xbc, 0x92, 0x51, + 0x49, 0x70, 0x25, 0xa3, 0xf6, 0x78, 0x30, 0xc5, 0xb8, 0x66, 0x5b, 0x01, 0xf1, 0x00, 0xfb, 0x99, + 0xf9, 0x0a, 0x66, 0xc5, 0x0a, 0x26, 0x43, 0x3e, 0xba, 0x72, 0xe9, 0x23, 0xff, 0xbb, 0x0a, 0x89, + 0x91, 0xe6, 0x03, 0x5f, 0x1e, 0x03, 0xf0, 0xf0, 0xbb, 0x19, 0xd9, 0x0d, 0xb3, 0x40, 0x02, 0x01, + 0x07, 0x87, 0xba, 0x64, 0x70, 0x28, 0xb9, 0xf4, 0xe5, 0xf9, 0xf2, 0x2c, 0x98, 0x5d, 0x32, 0xb7, + 0xb6, 0x82, 0x4e, 0xf2, 0xc5, 0x92, 0x9d, 0x64, 0xb4, 0x33, 0x1c, 0xb6, 0x73, 0xf7, 0x1c, 0x07, + 0x59, 0x7e, 0xa5, 0x58, 0x73, 0xea, 0x4b, 0xd5, 0x6e, 0x02, 0xc7, 0xfd, 0x71, 0x81, 0xef, 0x28, + 0xa7, 0xf5, 0xfe, 0x64, 0xf8, 0x6d, 0x69, 0x6f, 0x0b, 0x5f, 0xa2, 0x7c, 0x95, 0x22, 0x1a, 0xe0, + 0x9d, 0x60, 0x6e, 0x87, 0xe6, 0x26, 0x4b, 0xd2, 0x7e, 0x67, 0x79, 0xaa, 0xef, 0x0e, 0x8a, 0x35, + 0xe4, 0xba, 0xc6, 0x36, 0xd2, 0xc5, 0xcc, 0x7d, 0xcd, 0x57, 0x4d, 0x72, 0xa3, 0xaa, 0x9c, 0xe3, + 0x86, 0x44, 0x4d, 0xd2, 0xd7, 0x8e, 0x2f, 0x9e, 0x05, 0xd9, 0x65, 0xb3, 0x8b, 0xe0, 0x8f, 0x2b, + 0x60, 0x5a, 0x47, 0x6d, 0xdb, 0x6a, 0xe3, 0x27, 0xce, 0x35, 0xf6, 0x5b, 0x19, 0xd9, 0x9b, 0xc4, + 0x31, 0x9d, 0x85, 0x80, 0x46, 0x44, 0xbb, 0x91, 0xbb, 0x31, 0x3c, 0x96, 0xd4, 0x04, 0xee, 0x7d, + 0xc3, 0x53, 0x8f, 0xad, 0xad, 0xae, 0x6d, 0x08, 0x9b, 0x32, 0xfd, 0xa6, 0x50, 0x78, 0x10, 0xb7, + 0x6e, 0x7b, 0xeb, 0xa6, 0x65, 0x05, 0xb1, 0x6d, 0x0e, 0xa4, 0x8b, 0xfe, 0x44, 0xb1, 0xe1, 0x01, + 0x49, 0xdd, 0x59, 0xe9, 0x11, 0x9a, 0x7d, 0x23, 0x98, 0xbf, 0xb8, 0xef, 0x21, 0x97, 0xe5, 0x62, + 0xc5, 0x66, 0xf5, 0xbe, 0x54, 0xee, 0x72, 0x8f, 0xb8, 0x30, 0x82, 0x31, 0x05, 0x26, 0x13, 0xf5, + 0xea, 0x08, 0x33, 0xc0, 0x93, 0xa0, 0x58, 0x6f, 0x2c, 0x55, 0x88, 0xa7, 0xb6, 0xef, 0xfb, 0xba, + 0x0d, 0x7f, 0x46, 0x05, 0xb3, 0xc4, 0xc9, 0xd1, 0x47, 0xe1, 0x61, 0x12, 0xf3, 0x11, 0xf8, 0x15, + 0x69, 0x2f, 0x6e, 0x52, 0x65, 0xbe, 0x80, 0x68, 0x41, 0x6f, 0x99, 0xdd, 0x7e, 0x41, 0xe7, 0xf4, + 0xbe, 0xd4, 0x01, 0x80, 0xa8, 0x03, 0x01, 0xf9, 0x90, 0x94, 0x2b, 0xf7, 0x30, 0xee, 0x8e, 0x0a, + 0x95, 0x5f, 0x53, 0xc1, 0x0c, 0x9e, 0xa4, 0xf8, 0xa0, 0x34, 0x04, 0x50, 0x6c, 0xab, 0xbb, 0x1f, + 0x2e, 0x8b, 0xf8, 0x8f, 0x89, 0x1a, 0xc9, 0x9f, 0x4a, 0xcf, 0xdc, 0x89, 0x88, 0x38, 0x5e, 0x26, + 0x84, 0xdf, 0x07, 0xa5, 0xe6, 0xf3, 0x43, 0x98, 0x3b, 0x2a, 0xf8, 0x5e, 0x9b, 0x07, 0xf9, 0x8d, + 0x1e, 0x41, 0xee, 0x4b, 0xaa, 0xcc, 0x45, 0x39, 0x07, 0x8e, 0xf1, 0x61, 0x33, 0xab, 0x6b, 0xb7, + 0x8d, 0xee, 0x7a, 0x78, 0x92, 0x3d, 0x4c, 0xd0, 0xee, 0x60, 0x9e, 0xfd, 0xf4, 0x40, 0xf6, 0x8d, + 0xb1, 0x77, 0xc8, 0x10, 0x19, 0x71, 0x47, 0x26, 0x6f, 0x01, 0x27, 0x3a, 0xa6, 0x6b, 0x5c, 0xec, + 0xa2, 0x8a, 0xd5, 0x76, 0xf6, 0xa9, 0x38, 0xd8, 0xb4, 0xea, 0xc0, 0x0b, 0xed, 0x49, 0x20, 0xe7, + 0x7a, 0xfb, 0x5d, 0x3a, 0x4f, 0xe4, 0x4f, 0x58, 0x46, 0x16, 0xd5, 0xc4, 0xd9, 0x75, 0xfa, 0x15, + 0xef, 0x3a, 0x3b, 0x25, 0xe7, 0x3a, 0xab, 0x3d, 0x16, 0xe4, 0x6d, 0xc7, 0xdc, 0x36, 0xe9, 0xb5, + 0x90, 0xf3, 0x07, 0x42, 0x25, 0x53, 0x53, 0xa0, 0x41, 0xb2, 0xe8, 0x2c, 0xab, 0xf6, 0x78, 0x30, + 0x6d, 0xee, 0x1a, 0xdb, 0xe8, 0x1e, 0xd3, 0xa2, 0x81, 0x24, 0xe6, 0x6f, 0x3b, 0x7d, 0xe0, 0xf0, + 0x28, 0x7b, 0xaf, 0x87, 0x59, 0xb5, 0x3b, 0xc1, 0x35, 0x6d, 0x07, 0x19, 0x1e, 0xc2, 0x02, 0x3a, + 0x6f, 0x76, 0xb6, 0x91, 0x57, 0xdd, 0x5a, 0x33, 0x5d, 0xd7, 0xb4, 0xb6, 0xd9, 0xcd, 0xaf, 0xd1, + 0x19, 0xe0, 0x07, 0x15, 0xd9, 0x68, 0x90, 0x44, 0x32, 0x54, 0x25, 0x46, 0xb8, 0xa1, 0x9e, 0x93, + 0xa2, 0x2a, 0xe9, 0x80, 0xfc, 0x2a, 0xa9, 0x38, 0x8d, 0xd1, 0x6c, 0xa5, 0x3f, 0xf4, 0xff, 0xb1, + 0x02, 0x0a, 0x4b, 0xf6, 0x15, 0x8b, 0x34, 0x93, 0xdb, 0xe5, 0x2c, 0xe5, 0x01, 0xa1, 0x1d, 0xc4, + 0xbb, 0xce, 0x63, 0x4f, 0x03, 0x92, 0xda, 0xfa, 0x45, 0x46, 0xc0, 0x10, 0xdb, 0xee, 0x24, 0x03, + 0x08, 0xc4, 0x95, 0x93, 0xbe, 0x5c, 0x7f, 0x5f, 0x05, 0xd9, 0x25, 0xc7, 0xee, 0xc1, 0xb7, 0x65, + 0x12, 0x38, 0xe2, 0x75, 0x1c, 0xbb, 0xd7, 0x22, 0x57, 0xc8, 0x86, 0x7b, 0x4f, 0x7c, 0x9a, 0x76, + 0x3b, 0x28, 0xf4, 0x6c, 0xd7, 0xf4, 0xfc, 0x49, 0xc8, 0xfc, 0x6d, 0x0f, 0x1e, 0xd8, 0x17, 0xac, + 0xb3, 0x4c, 0x7a, 0x90, 0x1d, 0xf7, 0xf9, 0x44, 0x84, 0x58, 0x2e, 0x58, 0x8c, 0xfe, 0x35, 0xba, + 0x7d, 0xa9, 0xf0, 0x25, 0x3c, 0x92, 0x4f, 0x14, 0x91, 0x7c, 0xf8, 0x00, 0x09, 0x3b, 0x76, 0x6f, + 0x2c, 0xae, 0x33, 0xaf, 0x08, 0x50, 0x7d, 0xb2, 0x80, 0xea, 0xcd, 0x52, 0x65, 0xa6, 0x8f, 0xe8, + 0x07, 0xb3, 0x00, 0x10, 0x23, 0x65, 0x03, 0x4f, 0x9f, 0xe4, 0x2c, 0xb4, 0xe7, 0x66, 0x39, 0x59, + 0x96, 0x44, 0x59, 0x3e, 0x32, 0xc2, 0x06, 0x22, 0xe4, 0x23, 0x24, 0x5a, 0x02, 0xb9, 0x3d, 0xfc, + 0x9a, 0x49, 0x54, 0x92, 0x04, 0x79, 0xd4, 0xe9, 0x97, 0xf0, 0x77, 0x33, 0x20, 0x47, 0x12, 0xb4, + 0x33, 0x00, 0x10, 0xb3, 0x80, 0x1e, 0xa6, 0xcd, 0x10, 0x03, 0x80, 0x4b, 0x21, 0xda, 0x6a, 0x76, + 0xd8, 0x6b, 0x6a, 0x70, 0x87, 0x09, 0xf8, 0x6b, 0x62, 0x2c, 0x10, 0x5a, 0xcc, 0x7c, 0xe0, 0x52, + 0xf0, 0xd7, 0xe4, 0xa9, 0x86, 0xb6, 0xe8, 0xed, 0x1e, 0x59, 0x3d, 0x4c, 0x08, 0xbe, 0xae, 0x05, + 0x77, 0xc2, 0xfa, 0x5f, 0x93, 0x14, 0x3c, 0x95, 0x26, 0x6a, 0xb9, 0x18, 0x16, 0x91, 0x27, 0x99, + 0xfa, 0x93, 0xe1, 0xeb, 0x02, 0xb5, 0x59, 0x12, 0xd4, 0xe6, 0xd1, 0x09, 0xc4, 0x9b, 0xbe, 0xf2, + 0x7c, 0x2d, 0x07, 0xa6, 0xeb, 0x76, 0x87, 0xe9, 0x0e, 0x37, 0xdd, 0xfc, 0x74, 0x2e, 0xd1, 0x74, + 0x33, 0xa0, 0x11, 0xa1, 0x20, 0x4f, 0x11, 0x15, 0x44, 0x8e, 0x02, 0xaf, 0x1f, 0xda, 0x22, 0xc8, + 0x13, 0xed, 0x3d, 0x78, 0xd9, 0x68, 0x1c, 0x09, 0x22, 0x5a, 0x9d, 0x7d, 0xf9, 0x1f, 0x4e, 0xc7, + 0xfe, 0x07, 0xc8, 0x91, 0x0a, 0xc6, 0xec, 0x0d, 0x89, 0x15, 0x55, 0xe2, 0x2b, 0xaa, 0xc6, 0x57, + 0x34, 0xdb, 0x5f, 0xd1, 0x24, 0xab, 0x08, 0x51, 0x1a, 0x92, 0xbe, 0x8e, 0xff, 0xef, 0x29, 0x00, + 0xea, 0xc6, 0x65, 0x73, 0x9b, 0xee, 0x2d, 0x7f, 0xde, 0x9f, 0x3d, 0xb1, 0x5d, 0xe0, 0x9f, 0xe4, + 0x06, 0xc2, 0xdb, 0xc1, 0x14, 0x1b, 0xf7, 0x58, 0x45, 0x1e, 0x22, 0x54, 0x24, 0xa4, 0x42, 0x8d, + 0xda, 0xfb, 0x3c, 0xdd, 0xcf, 0x8f, 0x0d, 0x93, 0xad, 0xbd, 0x6e, 0xb7, 0x85, 0xbf, 0x65, 0x16, + 0x9a, 0xff, 0x1c, 0xb1, 0x83, 0x11, 0x5e, 0x32, 0x4d, 0x83, 0x4e, 0xb1, 0x27, 0xf8, 0x3e, 0xe9, + 0x73, 0x6a, 0x1c, 0x3f, 0x5c, 0x8d, 0x22, 0x9a, 0xe0, 0x63, 0xc1, 0x94, 0x1d, 0x6c, 0x87, 0xab, + 0x91, 0xab, 0x68, 0x55, 0x6b, 0xcb, 0xd6, 0xfd, 0x9c, 0x92, 0x5b, 0x67, 0x52, 0x7c, 0x4c, 0xe4, + 0x28, 0xe8, 0xa9, 0x15, 0x3f, 0x52, 0x2a, 0xae, 0xc7, 0x79, 0xd3, 0xdb, 0xa9, 0x99, 0xd6, 0x25, + 0x17, 0xfe, 0x37, 0x39, 0x0b, 0x92, 0xc3, 0x5f, 0x49, 0x86, 0xbf, 0x18, 0xa9, 0x2c, 0xd6, 0xb3, + 0x83, 0xa3, 0x32, 0x98, 0xdb, 0x08, 0x00, 0xef, 0x00, 0x79, 0xca, 0x28, 0xeb, 0x44, 0xcf, 0x46, + 0xe2, 0x17, 0x50, 0xd2, 0xd9, 0x17, 0x92, 0x5e, 0x21, 0x49, 0x39, 0x4b, 0x1d, 0xd2, 0xb3, 0x8f, + 0x01, 0x53, 0x4c, 0xd2, 0xda, 0x3c, 0xdf, 0x8a, 0x8b, 0xc7, 0x34, 0x00, 0xf2, 0x6b, 0xf6, 0x65, + 0xd4, 0xb2, 0x8b, 0x19, 0xfc, 0x1f, 0xf3, 0xd7, 0xb2, 0x8b, 0x0a, 0x7c, 0x65, 0x01, 0x14, 0x82, + 0x10, 0x95, 0x7f, 0xac, 0x80, 0x62, 0x99, 0xcc, 0xd0, 0x96, 0x1d, 0x7b, 0x97, 0xd6, 0x48, 0xfe, + 0xcc, 0xc3, 0x4b, 0xa5, 0x1d, 0x44, 0x82, 0xd0, 0x91, 0xfd, 0x85, 0x45, 0x60, 0x49, 0x97, 0x30, + 0x15, 0x7f, 0x09, 0x13, 0xbe, 0x55, 0xca, 0x61, 0x44, 0xb6, 0x94, 0xf4, 0x9b, 0xda, 0xef, 0x29, + 0x20, 0x57, 0xee, 0xda, 0x16, 0xe2, 0x0f, 0xe6, 0x0e, 0x3d, 0x01, 0x3a, 0x78, 0x1f, 0x03, 0x3e, + 0x4b, 0x91, 0xb5, 0x35, 0x42, 0x01, 0xe0, 0xb2, 0x25, 0x65, 0x2b, 0x37, 0x48, 0xc5, 0x92, 0x4e, + 0x5f, 0xa0, 0xdf, 0x50, 0xc0, 0x34, 0x8d, 0x29, 0x57, 0xea, 0x76, 0xe1, 0x83, 0x43, 0xa1, 0x0e, + 0x08, 0xf3, 0x09, 0x3f, 0x24, 0x7d, 0xf0, 0x2c, 0xa8, 0x55, 0x40, 0x3b, 0x41, 0x58, 0xc4, 0x64, + 0xe7, 0xa0, 0xe4, 0x76, 0xe2, 0x86, 0x32, 0x94, 0xbe, 0xa8, 0xff, 0x44, 0xc1, 0x06, 0x80, 0x75, + 0x69, 0xdd, 0x41, 0x97, 0x4d, 0x74, 0x05, 0x5e, 0x1b, 0x0a, 0xfb, 0x60, 0xc0, 0xac, 0x37, 0x49, + 0x2f, 0xe2, 0x70, 0x24, 0x23, 0x37, 0xc2, 0x66, 0xba, 0x61, 0x26, 0xd6, 0x8b, 0xf7, 0x47, 0x31, + 0xe3, 0xc8, 0xe8, 0x7c, 0x76, 0xc9, 0x35, 0x9b, 0x68, 0x2e, 0xd2, 0x17, 0xec, 0xc7, 0xa6, 0x40, + 0x61, 0xc3, 0x72, 0x7b, 0x5d, 0xc3, 0xdd, 0x81, 0xff, 0xaa, 0x82, 0x3c, 0xbd, 0xe2, 0x16, 0xfe, + 0xa0, 0x10, 0x97, 0xe7, 0x19, 0x7b, 0xc8, 0xf1, 0x1d, 0x78, 0xe8, 0x43, 0x68, 0x1f, 0x29, 0x9c, + 0x7d, 0x04, 0x3f, 0xa8, 0xca, 0x4e, 0x52, 0xfd, 0x42, 0xd9, 0x9d, 0xba, 0xd1, 0xa1, 0x60, 0x7a, + 0x66, 0xdb, 0xdb, 0x73, 0x90, 0x3b, 0x30, 0x14, 0x4c, 0x24, 0x95, 0x75, 0xfa, 0x95, 0x1e, 0x7c, + 0x0e, 0x0d, 0x30, 0xc5, 0x12, 0x0f, 0x6c, 0x46, 0x1d, 0x8c, 0x2a, 0x71, 0x0a, 0xe4, 0x0d, 0xc7, + 0x33, 0x5d, 0x8f, 0x6d, 0xcf, 0xb2, 0x27, 0xdc, 0x5d, 0xd2, 0x7f, 0x1b, 0x4e, 0xd7, 0x8f, 0xe0, + 0x15, 0x24, 0xc0, 0x5f, 0x93, 0x9a, 0x3f, 0xc6, 0xd7, 0x3c, 0x19, 0xe4, 0xf7, 0x8c, 0xb0, 0xc2, + 0xfd, 0x20, 0x70, 0x95, 0x5e, 0x6a, 0x55, 0x36, 0x69, 0xc0, 0xa7, 0x20, 0xb6, 0x53, 0x07, 0xbe, + 0x47, 0xe5, 0xd6, 0xef, 0xf6, 0x85, 0x31, 0x82, 0x49, 0x31, 0x1c, 0x23, 0x82, 0x84, 0x98, 0xbd, + 0x6e, 0x61, 0x09, 0x57, 0x95, 0x5e, 0xc2, 0x85, 0xbf, 0x22, 0xbd, 0x17, 0x15, 0x88, 0x72, 0xc8, + 0x1a, 0x60, 0xdc, 0x15, 0x98, 0x1f, 0x91, 0xda, 0x57, 0x1a, 0x56, 0xd2, 0x11, 0xc2, 0xf6, 0xdd, + 0x53, 0x40, 0x29, 0x55, 0xe1, 0x4f, 0x4c, 0x81, 0xd9, 0xf3, 0x8e, 0xe9, 0x99, 0xd6, 0x76, 0xcb, + 0xb6, 0xbb, 0x2e, 0xfc, 0x0e, 0xb7, 0x51, 0xf1, 0x78, 0x90, 0x6f, 0xdb, 0xd6, 0x96, 0xb9, 0xcd, + 0xc4, 0x78, 0x46, 0xa8, 0x5c, 0xa9, 0xba, 0xb0, 0xee, 0xd8, 0x97, 0xcd, 0x0e, 0x72, 0xca, 0x24, + 0x97, 0xce, 0x72, 0x63, 0x3d, 0xe6, 0x42, 0xe6, 0x3d, 0xba, 0xff, 0x2b, 0xbe, 0xbc, 0x20, 0x66, + 0x0f, 0x4b, 0xe4, 0x22, 0xe6, 0x55, 0x41, 0xa1, 0x6b, 0x58, 0xdb, 0x7b, 0xfe, 0xcc, 0xbb, 0x7f, + 0x17, 0x35, 0x8a, 0x52, 0x8d, 0x7d, 0xa4, 0x07, 0x9f, 0x13, 0x27, 0x37, 0x6c, 0xea, 0xd3, 0xb6, + 0x47, 0xfe, 0x9f, 0xfd, 0x78, 0x06, 0xcc, 0x70, 0x85, 0x6a, 0x33, 0x60, 0x6a, 0xa9, 0xb2, 0x5c, + 0xda, 0xa8, 0xb5, 0x8a, 0xc7, 0xb0, 0x14, 0x9b, 0x1b, 0x6b, 0x6b, 0x25, 0xbd, 0xfa, 0xc3, 0x95, + 0x62, 0x06, 0xbf, 0x5b, 0xd1, 0x4b, 0xf8, 0xb9, 0xa8, 0xe0, 0x87, 0xe6, 0x6a, 0x43, 0x6f, 0x55, + 0xea, 0x45, 0x15, 0xdb, 0xa3, 0x95, 0xa7, 0xad, 0x97, 0xea, 0x4b, 0xc5, 0x2c, 0xfe, 0xbf, 0xb8, + 0x51, 0xab, 0x55, 0x5a, 0xc5, 0x5c, 0x18, 0x44, 0x2f, 0x8f, 0x93, 0xcb, 0xa5, 0xe6, 0x46, 0xa9, + 0x56, 0x9c, 0xc2, 0xc9, 0xcb, 0x1b, 0xf5, 0xfa, 0x85, 0x62, 0x01, 0x17, 0x51, 0x6e, 0xd4, 0x97, + 0xab, 0x4b, 0x95, 0x7a, 0xab, 0x38, 0xad, 0x5d, 0x05, 0x8e, 0x37, 0x5b, 0x7a, 0xa9, 0xba, 0xb2, + 0xda, 0x5a, 0x6e, 0xe8, 0xe7, 0x4b, 0xfa, 0x52, 0x11, 0x68, 0x45, 0x30, 0xbb, 0xae, 0x37, 0x96, + 0x2b, 0x24, 0x5e, 0x4a, 0xa9, 0x56, 0x9c, 0xc1, 0x5f, 0xb5, 0xf4, 0x52, 0xbd, 0x59, 0x2b, 0xb5, + 0x2a, 0xc5, 0xd9, 0xb3, 0x77, 0x83, 0x82, 0x5f, 0x5d, 0x2d, 0x0f, 0x94, 0x4a, 0xbd, 0x78, 0x8c, + 0xfc, 0x36, 0x8b, 0x19, 0xfc, 0xbb, 0x8c, 0xf9, 0xcd, 0x03, 0x65, 0xa9, 0x52, 0x54, 0xf1, 0x6f, + 0xb5, 0x55, 0xcc, 0xe2, 0xdf, 0x75, 0xcc, 0x62, 0x1e, 0x28, 0xab, 0xd5, 0x62, 0x1e, 0xff, 0xb6, + 0x56, 0x8b, 0x53, 0xe2, 0x4d, 0xf7, 0xb1, 0xbd, 0xf0, 0x41, 0xc9, 0x47, 0x18, 0x1a, 0x5e, 0x38, + 0x47, 0x26, 0xff, 0xe1, 0x2b, 0x14, 0x99, 0xbe, 0x2e, 0x9e, 0x7e, 0xb2, 0x46, 0xf3, 0x96, 0xcc, + 0x18, 0x5b, 0x8d, 0x06, 0xc1, 0xa9, 0x4a, 0x7d, 0x69, 0xbd, 0x51, 0xad, 0xb7, 0x68, 0xa8, 0xb3, + 0x4a, 0xa9, 0xbc, 0x4a, 0x70, 0x46, 0x18, 0xc1, 0xb5, 0xc6, 0x52, 0xa5, 0x46, 0x5e, 0x2c, 0x37, + 0x36, 0xea, 0x4b, 0xc5, 0x2d, 0x5c, 0x56, 0x69, 0xa3, 0xb5, 0xba, 0xa9, 0x57, 0x9e, 0xba, 0x51, + 0xd5, 0x2b, 0x4b, 0xc5, 0x6d, 0x4c, 0xa3, 0x56, 0xaa, 0xaf, 0x6c, 0x94, 0x56, 0xd8, 0x7e, 0xe1, + 0xc6, 0xfa, 0x7a, 0x83, 0xec, 0x18, 0xee, 0xc0, 0xbf, 0xcf, 0x82, 0x42, 0x69, 0xcf, 0xb3, 0xb7, + 0xcc, 0x6e, 0x17, 0x3e, 0x47, 0x39, 0x7c, 0x53, 0x2c, 0x09, 0x4d, 0xf1, 0x40, 0x03, 0xf2, 0xcb, + 0x0a, 0x1a, 0x8f, 0x9f, 0xc0, 0xb5, 0xc3, 0xd3, 0xa1, 0x33, 0xb6, 0xca, 0x76, 0x9a, 0xe9, 0x23, + 0x75, 0xc4, 0xb5, 0x58, 0xcb, 0x22, 0x6f, 0xd8, 0xe3, 0xd9, 0x7b, 0xc0, 0x2c, 0x4f, 0x89, 0x84, + 0x03, 0x2b, 0xad, 0xd0, 0x78, 0x61, 0x7e, 0x84, 0x40, 0x1a, 0x2f, 0x8c, 0x1c, 0xbc, 0x50, 0x48, + 0x7b, 0xa9, 0xb6, 0x6a, 0x58, 0x4f, 0x8f, 0x83, 0x99, 0xa5, 0x4a, 0xb3, 0xac, 0x57, 0x89, 0x9f, + 0x7a, 0x31, 0x2b, 0x7a, 0x19, 0xc4, 0x5a, 0x66, 0x62, 0x8d, 0x64, 0x95, 0xf2, 0x7b, 0x52, 0xf6, + 0x56, 0x34, 0xed, 0x64, 0x0a, 0xf9, 0xa2, 0x07, 0x9a, 0x42, 0xc2, 0x17, 0x65, 0xe9, 0x3a, 0x59, + 0x73, 0x6f, 0x77, 0xd7, 0x70, 0xf6, 0x05, 0x7f, 0xb5, 0x51, 0xf5, 0x2e, 0x7a, 0x7c, 0x8f, 0x8d, + 0x02, 0x84, 0x4d, 0xa8, 0x9e, 0x63, 0xef, 0xf6, 0xfc, 0xbe, 0x9a, 0x3d, 0xc1, 0xff, 0x25, 0x3d, + 0x73, 0x2c, 0x55, 0x17, 0xb8, 0xca, 0x8c, 0x30, 0xb4, 0xff, 0x88, 0x22, 0x33, 0x8b, 0x8c, 0x2d, + 0xe6, 0xfb, 0x5d, 0x23, 0xfe, 0x26, 0x0b, 0xae, 0x62, 0x11, 0x5e, 0x82, 0xf5, 0x07, 0x6c, 0xaa, + 0xbe, 0x3a, 0x55, 0xcd, 0x60, 0x06, 0xb5, 0x1a, 0x1a, 0xd4, 0xdc, 0x86, 0x77, 0x56, 0x72, 0xc3, + 0xfb, 0x6d, 0xd2, 0x87, 0x1e, 0x4a, 0xd5, 0x85, 0x01, 0x75, 0x9c, 0xcc, 0xb6, 0xfc, 0xfd, 0x8a, + 0xcc, 0x6a, 0xab, 0x14, 0x87, 0xdf, 0xef, 0xba, 0xf6, 0x8e, 0x0c, 0x98, 0x17, 0x55, 0x45, 0x7b, + 0x1c, 0x28, 0xf4, 0x58, 0x0a, 0x93, 0xcb, 0xe9, 0x28, 0xe5, 0xd2, 0x83, 0x9c, 0x18, 0x22, 0x64, + 0x75, 0x7a, 0xb6, 0x69, 0x05, 0xeb, 0xf2, 0xfe, 0x33, 0x9e, 0x77, 0x92, 0xa9, 0x83, 0x1f, 0xef, + 0x8f, 0x3c, 0x84, 0xb1, 0x63, 0xb3, 0x5c, 0xec, 0x58, 0x2c, 0x44, 0x0f, 0xed, 0x92, 0x5b, 0x8c, + 0xf6, 0x1c, 0xea, 0xf0, 0xa2, 0xe8, 0x7c, 0xd2, 0xd9, 0x27, 0x83, 0x82, 0x5f, 0x3e, 0xb6, 0xee, + 0x1a, 0xb5, 0x5a, 0x69, 0xad, 0x44, 0x17, 0x2a, 0x1b, 0xeb, 0x95, 0x7a, 0xa9, 0x5a, 0xcc, 0xe0, + 0x81, 0xae, 0xb6, 0xd6, 0x6c, 0x6d, 0x2c, 0x55, 0x1b, 0x45, 0x85, 0x3c, 0xe1, 0x4c, 0xe5, 0xf5, + 0xf5, 0xa2, 0x0a, 0xdf, 0x38, 0x05, 0xa6, 0x56, 0x8c, 0x6e, 0x17, 0x39, 0xfb, 0xf0, 0x1b, 0x0a, + 0x28, 0xfa, 0xb3, 0x83, 0x35, 0xc3, 0x32, 0xb7, 0x90, 0xeb, 0xc5, 0x2f, 0x54, 0xbc, 0x4f, 0xfa, + 0x6a, 0x33, 0x56, 0xc6, 0x42, 0x3f, 0xfd, 0x08, 0x1d, 0xbf, 0x15, 0x64, 0x4d, 0x6b, 0xcb, 0x66, + 0xcb, 0x15, 0xfd, 0xfe, 0x36, 0xfe, 0xc7, 0x64, 0xdb, 0x80, 0x64, 0x94, 0xbc, 0xdd, 0x4c, 0x92, + 0x8b, 0xf4, 0x57, 0x2d, 0xde, 0x91, 0x05, 0x73, 0x3e, 0x13, 0x55, 0xab, 0x83, 0xee, 0xe3, 0xb7, + 0x41, 0x7f, 0x26, 0x2b, 0x1b, 0x60, 0xa8, 0xbf, 0x3e, 0x84, 0x54, 0x84, 0x48, 0x5b, 0x00, 0xb4, + 0x0d, 0x0f, 0x6d, 0xdb, 0x8e, 0x19, 0xac, 0x45, 0x3c, 0x2e, 0x09, 0xb5, 0x32, 0xfd, 0x7a, 0x5f, + 0xe7, 0xe8, 0x68, 0x4f, 0x02, 0x33, 0x28, 0x88, 0xe8, 0xe8, 0x6f, 0x93, 0xc6, 0xe2, 0xc5, 0xe7, + 0x87, 0x7f, 0x22, 0x15, 0xc7, 0x48, 0xa6, 0x9a, 0xc9, 0x30, 0xdb, 0x1c, 0xad, 0xeb, 0xd9, 0xa8, + 0xaf, 0x95, 0xf4, 0xe6, 0x6a, 0xa9, 0x56, 0xab, 0xd6, 0x57, 0x82, 0x80, 0xc5, 0x1a, 0x98, 0x5f, + 0x6a, 0x9c, 0xaf, 0x73, 0x11, 0xa5, 0xb3, 0x70, 0x1d, 0x14, 0x7c, 0x79, 0x0d, 0x3a, 0x45, 0xc5, + 0xcb, 0x8c, 0x9d, 0xa2, 0xe2, 0x92, 0xb0, 0x69, 0x68, 0xb6, 0x03, 0xd7, 0x7a, 0xf2, 0x1f, 0xfe, + 0xb6, 0x01, 0x72, 0xc4, 0x9f, 0x05, 0xbe, 0x8b, 0xcc, 0x8b, 0x7b, 0x5d, 0xa3, 0x8d, 0xe0, 0x6e, + 0x82, 0x95, 0x70, 0xff, 0xae, 0x5d, 0xe5, 0xc0, 0x5d, 0xbb, 0xe4, 0x2f, 0x1b, 0x31, 0x4e, 0x0e, + 0xf2, 0xa1, 0xd1, 0x69, 0x16, 0x31, 0xe4, 0x4f, 0xac, 0x67, 0x13, 0x75, 0xbd, 0x61, 0x6c, 0x46, + 0xa8, 0x64, 0x34, 0x4f, 0x69, 0x5c, 0xa2, 0x12, 0xc7, 0x51, 0xfa, 0x2d, 0xfe, 0x4b, 0x59, 0x90, + 0x6b, 0xf6, 0xba, 0xa6, 0x07, 0x7f, 0x41, 0x19, 0x0b, 0x66, 0xf4, 0x7e, 0x64, 0x75, 0xe8, 0xfd, + 0xc8, 0xa1, 0xbf, 0x64, 0x56, 0xc2, 0x5f, 0xb2, 0x85, 0xee, 0xf3, 0x44, 0x7f, 0xc9, 0xdb, 0xd9, + 0xb4, 0x8d, 0x7a, 0x5b, 0x3e, 0x7c, 0x80, 0x48, 0x49, 0xb5, 0x06, 0xdc, 0x66, 0x71, 0xf6, 0x31, + 0x2c, 0xa8, 0x3e, 0x00, 0xf9, 0xc5, 0x46, 0xab, 0xd5, 0x58, 0x2b, 0x1e, 0x23, 0xd3, 0xaf, 0xc6, + 0x3a, 0x0d, 0x71, 0x5c, 0xad, 0xd7, 0x2b, 0xba, 0x30, 0xe3, 0x12, 0x2f, 0xcb, 0x8c, 0x9d, 0x60, + 0x89, 0x65, 0xa7, 0xa9, 0x5e, 0x72, 0x8b, 0xe0, 0xd1, 0xfc, 0xa4, 0xaf, 0x5c, 0x3f, 0xa7, 0x82, + 0xdc, 0x1a, 0x72, 0xb6, 0x11, 0x7c, 0x46, 0x02, 0x07, 0xbb, 0x2d, 0xd3, 0x71, 0xe9, 0xa5, 0x08, + 0xa1, 0x83, 0x1d, 0x9f, 0xa6, 0xdd, 0x00, 0xe6, 0x5c, 0xd4, 0xb6, 0xad, 0x8e, 0x9f, 0x89, 0xf6, + 0x47, 0x62, 0x22, 0x7c, 0x59, 0x42, 0xc8, 0x08, 0xa3, 0x63, 0xf1, 0x92, 0x4b, 0x02, 0xcc, 0xa0, + 0x52, 0xd3, 0x07, 0xe6, 0xdb, 0x2a, 0xfe, 0xa8, 0xb7, 0x0f, 0x5f, 0x26, 0xed, 0xf9, 0x78, 0x0b, + 0xc8, 0x5f, 0xf4, 0xef, 0x45, 0x53, 0x23, 0xfb, 0x63, 0x96, 0x47, 0x5b, 0x04, 0x27, 0x5c, 0xd4, + 0x45, 0x6d, 0x0f, 0x75, 0x70, 0xd3, 0xd5, 0x87, 0x76, 0x0a, 0x07, 0xb3, 0xc3, 0x3f, 0xe0, 0x01, + 0xbc, 0x53, 0x04, 0xf0, 0xc6, 0x01, 0xa2, 0xc4, 0x15, 0x8a, 0x9e, 0x9b, 0xe0, 0x6a, 0x34, 0xbb, + 0x76, 0x60, 0xf8, 0xfa, 0xcf, 0xf8, 0xdd, 0x8e, 0xb7, 0xdb, 0x25, 0xef, 0xd8, 0xd1, 0x60, 0xff, + 0x59, 0x5b, 0x00, 0x53, 0x86, 0xb5, 0x4f, 0x5e, 0x65, 0x63, 0x6a, 0xed, 0x67, 0x82, 0xaf, 0x0c, + 0x90, 0xbf, 0x4b, 0x40, 0xfe, 0x91, 0x72, 0xec, 0xa6, 0x0f, 0xfc, 0x8f, 0x4d, 0x81, 0xdc, 0xba, + 0xe1, 0x7a, 0x08, 0xfe, 0x1f, 0x55, 0x16, 0xf9, 0x1b, 0xc1, 0xfc, 0x96, 0xdd, 0xde, 0x73, 0x51, + 0x47, 0x6c, 0x94, 0x7d, 0xa9, 0xe3, 0xc0, 0x9c, 0x04, 0x66, 0x67, 0x89, 0x8c, 0xac, 0xef, 0x02, + 0x7b, 0x20, 0x9d, 0x5c, 0xbd, 0xe8, 0xae, 0x1b, 0x8e, 0xd7, 0xd8, 0x22, 0x69, 0xc1, 0xd5, 0x8b, + 0x7c, 0xa2, 0x00, 0x7d, 0x3e, 0x06, 0xfa, 0xa9, 0x68, 0xe8, 0x0b, 0x12, 0xd0, 0x6b, 0x25, 0x50, + 0xd8, 0x32, 0xbb, 0x88, 0x7c, 0x30, 0x4d, 0x3e, 0x18, 0x34, 0x26, 0x11, 0xd9, 0x07, 0x63, 0xd2, + 0xb2, 0xd9, 0x45, 0x7a, 0xf0, 0x99, 0x3f, 0x91, 0x01, 0xe1, 0x44, 0xa6, 0x46, 0x4f, 0xc2, 0x61, + 0xc3, 0xcb, 0x32, 0x76, 0x91, 0xbf, 0xf1, 0x6d, 0xb1, 0x63, 0xe9, 0x1d, 0xc3, 0x33, 0x08, 0x18, + 0xb3, 0x3a, 0xf9, 0x2f, 0xfa, 0x64, 0xab, 0xfd, 0x3e, 0xd9, 0xcf, 0x53, 0x93, 0xf5, 0x88, 0x3e, + 0xb3, 0x11, 0x2d, 0xea, 0xa2, 0x0f, 0x10, 0xb5, 0x14, 0x83, 0x67, 0x0c, 0x4c, 0xdb, 0x70, 0x90, + 0xb7, 0xce, 0x7b, 0x41, 0xe7, 0x74, 0x31, 0x91, 0x1c, 0xc2, 0x71, 0x9b, 0xc6, 0x2e, 0xbd, 0x5a, + 0xb1, 0x8c, 0xdf, 0xb1, 0xc3, 0x15, 0x07, 0xd2, 0xc3, 0xfe, 0x37, 0x37, 0xee, 0xfe, 0x77, 0x50, + 0x1d, 0xd3, 0x6f, 0x86, 0xaf, 0xc9, 0x02, 0xb5, 0xbc, 0xe7, 0x3d, 0xa0, 0xbb, 0xdf, 0xef, 0x49, + 0xfb, 0x98, 0xb3, 0xfe, 0x6c, 0xcf, 0x3b, 0xda, 0xde, 0x37, 0xa1, 0x96, 0xc8, 0xf9, 0xb2, 0x47, + 0xd5, 0x2d, 0x7d, 0x1d, 0x79, 0x9b, 0x1a, 0x1c, 0x8d, 0x7a, 0x4e, 0xe6, 0xf0, 0xa6, 0x39, 0xa4, + 0xfd, 0x13, 0xd7, 0x33, 0x04, 0xcf, 0x7e, 0xc7, 0x93, 0x15, 0x6e, 0x7f, 0x20, 0xae, 0xad, 0x44, + 0x94, 0xb3, 0x3a, 0x7d, 0x80, 0x2f, 0x97, 0x3e, 0x30, 0x4a, 0xc5, 0x16, 0x7b, 0x8c, 0x27, 0x99, + 0x4d, 0xf5, 0x6a, 0xa9, 0x63, 0xa3, 0x31, 0xc5, 0xa6, 0x0f, 0xd8, 0xdf, 0xf1, 0xc7, 0x74, 0x4a, + 0x87, 0x46, 0x0c, 0xbe, 0x4a, 0x7a, 0x41, 0x9f, 0x56, 0x7b, 0xc8, 0x5e, 0x7d, 0x32, 0x79, 0xcb, + 0x39, 0x8a, 0xc5, 0x16, 0x3c, 0x81, 0xbb, 0xa2, 0x55, 0x90, 0xa7, 0x0b, 0xbf, 0xf0, 0xcd, 0xd2, + 0x4d, 0x04, 0xf7, 0x46, 0xe2, 0xf1, 0x9d, 0xe0, 0x39, 0xc9, 0x9a, 0x83, 0x70, 0xcc, 0x27, 0x9b, + 0xe8, 0x98, 0x8f, 0x18, 0x81, 0x45, 0xa2, 0x1d, 0xd1, 0x3a, 0xa6, 0x3c, 0x9d, 0x4c, 0xd2, 0xc2, + 0x06, 0x32, 0x94, 0x3e, 0xde, 0xcf, 0xcf, 0x81, 0x59, 0x5a, 0x34, 0x3d, 0x5f, 0x08, 0xdf, 0xa3, + 0x7c, 0xff, 0xa0, 0xae, 0xd5, 0xc1, 0xec, 0x15, 0xc2, 0x36, 0x0d, 0x2f, 0xc7, 0x56, 0x2e, 0x6e, + 0x8e, 0x5d, 0xf7, 0xa0, 0xf5, 0xf4, 0x6f, 0x8d, 0x16, 0xbe, 0xc7, 0x32, 0xa6, 0x1b, 0x2c, 0xf4, + 0xf0, 0x44, 0x9e, 0x18, 0x59, 0x7c, 0x92, 0x76, 0x0a, 0xe4, 0x2f, 0x9b, 0xe8, 0x4a, 0xb5, 0xc3, + 0xac, 0x5b, 0xf6, 0x04, 0x7f, 0x5d, 0xda, 0x67, 0x92, 0x87, 0x9b, 0xf1, 0x92, 0xae, 0x16, 0xca, + 0x79, 0x4e, 0x0e, 0x65, 0x6b, 0x02, 0xd1, 0x80, 0x14, 0x7a, 0x4f, 0x3d, 0x0b, 0xe5, 0x5f, 0x4e, + 0xa0, 0x88, 0x51, 0x86, 0xb3, 0x18, 0x84, 0x2f, 0xf6, 0xac, 0x39, 0x15, 0x40, 0x58, 0xfe, 0x58, + 0xfa, 0x7c, 0xb9, 0xc8, 0x70, 0x43, 0x8a, 0x4e, 0x5f, 0xf2, 0xaf, 0x53, 0xc1, 0x74, 0x13, 0x79, + 0xcb, 0x26, 0xea, 0x76, 0x5c, 0xe8, 0x1c, 0xde, 0x34, 0xba, 0x15, 0xe4, 0xb7, 0x08, 0xb1, 0x61, + 0x9b, 0x93, 0x2c, 0x1b, 0x7c, 0x8d, 0x22, 0xeb, 0x07, 0xc4, 0x56, 0xdf, 0x7c, 0x6e, 0xc7, 0x02, + 0x93, 0xdc, 0x69, 0xba, 0xf8, 0x92, 0x27, 0x70, 0x55, 0x92, 0x0a, 0x66, 0xc9, 0xf6, 0x3f, 0xf2, + 0x4a, 0x5d, 0x73, 0xdb, 0xe2, 0x6f, 0x57, 0x1f, 0xb9, 0x85, 0x68, 0x8f, 0x06, 0x39, 0x03, 0x53, + 0x63, 0xee, 0x6e, 0x70, 0x60, 0xe7, 0x49, 0xca, 0xd3, 0x69, 0xc6, 0x04, 0x17, 0x93, 0x84, 0x8a, + 0xed, 0xf3, 0x3c, 0xc1, 0x8b, 0x49, 0x86, 0x16, 0x9e, 0x3e, 0x62, 0x5f, 0x55, 0xc1, 0x49, 0xc6, + 0xc0, 0x39, 0xe4, 0x78, 0x66, 0xdb, 0xe8, 0x52, 0xe4, 0x5e, 0x98, 0x19, 0x07, 0x74, 0xab, 0x60, + 0xee, 0x32, 0x4f, 0x96, 0x41, 0x78, 0x76, 0x20, 0x84, 0x02, 0x03, 0xba, 0xf8, 0x61, 0x82, 0x0b, + 0x1e, 0x04, 0xa9, 0x0a, 0x34, 0x27, 0x78, 0xc1, 0x83, 0x34, 0x13, 0xe9, 0x43, 0xfc, 0x12, 0x16, + 0x54, 0x33, 0xec, 0x3e, 0x3f, 0x2f, 0x8d, 0xed, 0x06, 0x98, 0x21, 0x58, 0xd2, 0x0f, 0xd9, 0x32, + 0x44, 0x8c, 0x12, 0x07, 0xfd, 0x0e, 0xbb, 0xe8, 0x3e, 0xf8, 0x56, 0xe7, 0xe9, 0xc0, 0xf3, 0x00, + 0x84, 0xaf, 0xf8, 0x4e, 0x3a, 0x13, 0xd5, 0x49, 0x2b, 0x72, 0x9d, 0xf4, 0x9b, 0xa4, 0xc3, 0x1c, + 0x0e, 0x66, 0xfb, 0xf0, 0xea, 0x21, 0x17, 0xe0, 0x6e, 0x78, 0xe9, 0xe9, 0xeb, 0xc5, 0x2b, 0x99, + 0x5e, 0x2c, 0xed, 0xf5, 0xba, 0x66, 0x1b, 0xcf, 0xa7, 0x3e, 0x31, 0x96, 0xf9, 0x14, 0xdf, 0x1f, + 0xa8, 0x7d, 0xfd, 0xc1, 0x21, 0x2c, 0xe9, 0x9b, 0xc0, 0x71, 0x5a, 0x44, 0x39, 0x60, 0x2b, 0x47, + 0x83, 0xb8, 0xf5, 0x25, 0x8b, 0x51, 0xdb, 0x25, 0x95, 0x20, 0x10, 0xc2, 0x08, 0x4b, 0x9f, 0xc9, + 0x8c, 0xdd, 0xa4, 0x0a, 0x12, 0xc5, 0xd9, 0x04, 0x8e, 0x64, 0x65, 0xa9, 0xb5, 0xbb, 0xd1, 0xeb, + 0x60, 0xed, 0xf8, 0x62, 0x76, 0x1c, 0x23, 0xc2, 0x53, 0x98, 0xa7, 0xa9, 0x1a, 0xb9, 0xa4, 0x11, + 0x16, 0x19, 0xf4, 0x23, 0x2d, 0x74, 0x9f, 0xb7, 0x7a, 0x8c, 0xfa, 0xa5, 0x6a, 0x37, 0x83, 0xe3, + 0x17, 0x8d, 0xf6, 0xa5, 0x6d, 0xc7, 0xde, 0x23, 0xb7, 0xb6, 0xdb, 0xec, 0xfa, 0xf7, 0xd5, 0x63, + 0x7a, 0xff, 0x0b, 0xed, 0x36, 0xdf, 0x74, 0xc8, 0x0d, 0x33, 0x1d, 0x56, 0x8f, 0x31, 0xe3, 0x41, + 0x7b, 0x4c, 0xd0, 0xe9, 0xe4, 0x63, 0x3b, 0x9d, 0xd5, 0x63, 0x7e, 0xb7, 0xa3, 0x2d, 0x81, 0x42, + 0xc7, 0xbc, 0x4c, 0xb6, 0xaa, 0xc9, 0xac, 0x6b, 0x58, 0xd0, 0xa1, 0x25, 0xf3, 0x32, 0xdd, 0xd8, + 0x5e, 0x3d, 0xa6, 0x07, 0x5f, 0x6a, 0x2b, 0x60, 0x9a, 0x6c, 0x0b, 0x10, 0x32, 0x85, 0x44, 0x01, + 0x85, 0x56, 0x8f, 0xe9, 0xe1, 0xb7, 0xd8, 0xfa, 0xc8, 0x92, 0x73, 0xd7, 0x77, 0xf9, 0xdb, 0xed, + 0x99, 0x44, 0xdb, 0xed, 0x58, 0x16, 0x74, 0xc3, 0xfd, 0x14, 0xc8, 0xb5, 0x89, 0x84, 0x15, 0x26, + 0x61, 0xfa, 0xa8, 0xdd, 0x09, 0xb2, 0xbb, 0x86, 0xe3, 0x4f, 0x9e, 0x6f, 0x1c, 0x4e, 0x77, 0xcd, + 0x70, 0x2e, 0x61, 0x04, 0xf1, 0x57, 0x8b, 0x53, 0x20, 0x47, 0x04, 0x17, 0xfc, 0x81, 0x6f, 0xcb, + 0x52, 0x33, 0xa4, 0x6c, 0x5b, 0x78, 0xd8, 0x6f, 0xd9, 0xfe, 0xe1, 0xf4, 0x5f, 0xcf, 0x8c, 0xc7, + 0x82, 0xbc, 0x8a, 0xbb, 0x4e, 0xc5, 0x32, 0x9f, 0xb1, 0x87, 0xee, 0x41, 0xfb, 0x6c, 0x49, 0x74, + 0xd0, 0x2b, 0xed, 0x0c, 0x00, 0x1e, 0x3b, 0xa9, 0x17, 0x04, 0x31, 0xe5, 0x52, 0xc2, 0xe5, 0x83, + 0xdc, 0x70, 0x47, 0x95, 0x3f, 0x18, 0xc1, 0x74, 0xe9, 0x17, 0x44, 0xf4, 0x0c, 0xbc, 0x6b, 0x5a, + 0x5c, 0x9d, 0xfd, 0xc7, 0x84, 0x9d, 0x52, 0x52, 0xa3, 0x66, 0x08, 0x7b, 0xe9, 0xf7, 0x4d, 0x6f, + 0xc9, 0xd2, 0x1b, 0x25, 0xe8, 0x09, 0xe8, 0xca, 0x7d, 0xa6, 0x1b, 0xde, 0xdf, 0x0c, 0x7f, 0x67, + 0x2c, 0x4a, 0x33, 0x60, 0xc0, 0x51, 0x07, 0x0e, 0x38, 0x07, 0x02, 0x04, 0x65, 0x87, 0x04, 0x08, + 0xca, 0x25, 0x5b, 0x39, 0xfc, 0x28, 0xaf, 0x3f, 0xeb, 0xa2, 0xfe, 0xdc, 0x11, 0x01, 0xd0, 0x20, + 0xb9, 0x8c, 0xc5, 0xbe, 0x79, 0x57, 0xa0, 0x29, 0x4d, 0x41, 0x53, 0xee, 0x1a, 0x9d, 0x91, 0xf4, + 0xb5, 0xe5, 0xc3, 0x59, 0x70, 0x55, 0xc8, 0x4c, 0x1d, 0x5d, 0x61, 0x8a, 0xf2, 0xc7, 0x63, 0x51, + 0x94, 0xe4, 0x8e, 0xce, 0x69, 0x6b, 0xcc, 0xef, 0x4a, 0x9f, 0xdb, 0xef, 0x07, 0x2a, 0x90, 0x4d, + 0x84, 0xb2, 0x9c, 0x02, 0x79, 0xda, 0xc3, 0x30, 0x68, 0xd8, 0x53, 0xc2, 0xee, 0x46, 0xee, 0xb4, + 0xbf, 0x2c, 0x6f, 0x13, 0xd0, 0x1f, 0xb6, 0xae, 0xd1, 0xda, 0x73, 0xac, 0xaa, 0xe5, 0xd9, 0xf0, + 0x47, 0xc7, 0xa2, 0x38, 0x81, 0x37, 0x9c, 0x3a, 0x8a, 0x37, 0xdc, 0x48, 0xab, 0x1c, 0x7e, 0x0d, + 0x8e, 0x64, 0x95, 0x23, 0xa2, 0xf0, 0xf4, 0xf1, 0x7b, 0xa7, 0x0a, 0x4e, 0xb1, 0xc9, 0xd6, 0xa2, + 0x68, 0x21, 0xc2, 0x0b, 0xe3, 0x00, 0xf2, 0xa4, 0x6f, 0x26, 0x31, 0x3f, 0x7a, 0xf2, 0x20, 0x46, + 0x29, 0x88, 0xbd, 0x31, 0x54, 0x98, 0x0e, 0xf6, 0x71, 0x38, 0x16, 0xa4, 0xe4, 0x2e, 0x0a, 0x4d, + 0xc0, 0x46, 0xfa, 0x98, 0xbd, 0x58, 0x05, 0x79, 0x1a, 0x23, 0x01, 0x6e, 0xa4, 0xe2, 0x30, 0x21, + 0xde, 0xcf, 0x22, 0xb1, 0x23, 0x47, 0xb9, 0x49, 0x2d, 0x7e, 0x44, 0x92, 0xbd, 0xb8, 0x81, 0xac, + 0x4c, 0xc0, 0x85, 0x50, 0x01, 0x33, 0x4d, 0xe4, 0x95, 0x0d, 0xc7, 0x31, 0x8d, 0xed, 0x71, 0x79, + 0x7c, 0xcb, 0x7a, 0x0f, 0xc3, 0xef, 0x64, 0x64, 0xcf, 0xb2, 0x07, 0x0b, 0xe1, 0x3e, 0xab, 0x11, + 0x51, 0xc0, 0x5f, 0x2f, 0x75, 0x5e, 0x7d, 0x18, 0xb5, 0x09, 0x78, 0x6c, 0x2b, 0x60, 0xca, 0x8f, + 0x83, 0x71, 0xab, 0x10, 0x1b, 0x65, 0xc7, 0xdb, 0xf5, 0x8f, 0xc1, 0x90, 0xff, 0x07, 0xe3, 0x2f, + 0xc0, 0x57, 0x24, 0x74, 0x94, 0x8f, 0x0f, 0xe2, 0x91, 0xac, 0x8d, 0x25, 0x71, 0x87, 0x3f, 0xaa, + 0xb0, 0x1d, 0x1f, 0x9a, 0x62, 0xcb, 0x91, 0x35, 0xc3, 0x43, 0xf7, 0xc1, 0xcf, 0xab, 0x60, 0xaa, + 0x89, 0x3c, 0x3c, 0xde, 0x62, 0xf6, 0x0f, 0xad, 0xe1, 0x1a, 0xb7, 0xe2, 0xc1, 0xce, 0xd6, 0x6a, + 0x77, 0x83, 0xe9, 0x9e, 0x63, 0xb7, 0x91, 0xeb, 0xb2, 0xd5, 0x0b, 0xde, 0x51, 0x6d, 0xd0, 0xe8, + 0x4f, 0x58, 0x5b, 0x58, 0xf7, 0xbf, 0xd1, 0xc3, 0xcf, 0x93, 0x9a, 0x01, 0x94, 0x12, 0xab, 0xe0, + 0xa4, 0xcd, 0x80, 0xb8, 0xc2, 0xd3, 0x07, 0xfa, 0x0f, 0x55, 0x30, 0xdb, 0x44, 0x5e, 0x20, 0xc5, + 0x04, 0x9b, 0x1c, 0xd1, 0xf0, 0x0a, 0x50, 0xaa, 0x87, 0x83, 0xf2, 0x9d, 0xd2, 0x17, 0xef, 0x8a, + 0xd2, 0x0c, 0x88, 0x8d, 0x05, 0xcf, 0xb7, 0x48, 0xdd, 0xb7, 0x2b, 0xc7, 0xc1, 0x04, 0x8e, 0xaf, + 0x3d, 0x1c, 0x4c, 0x13, 0x5e, 0x48, 0x83, 0xfd, 0x89, 0x6c, 0xd8, 0x78, 0xbf, 0x90, 0x52, 0xe3, + 0x7d, 0x12, 0xc8, 0xed, 0x1a, 0xce, 0x25, 0xff, 0xf0, 0xed, 0x23, 0xe4, 0x56, 0xbf, 0x5c, 0x9d, + 0x7e, 0x35, 0xd8, 0x4f, 0x33, 0x97, 0xcc, 0x4f, 0xf3, 0xf5, 0x4a, 0xa2, 0x91, 0x90, 0xce, 0x1d, + 0xc6, 0xd8, 0xe4, 0x13, 0x8c, 0x9b, 0x31, 0x65, 0xa7, 0xaf, 0x1c, 0x2f, 0x54, 0x41, 0x01, 0x8f, + 0xdb, 0xc4, 0x1e, 0x3f, 0x7f, 0x78, 0x75, 0x18, 0x6c, 0xe8, 0x27, 0xec, 0x81, 0x7d, 0x89, 0x8c, + 0xcf, 0xbc, 0x4f, 0xd0, 0x03, 0xc7, 0x15, 0x9e, 0x3e, 0x1e, 0xef, 0xa6, 0x78, 0x90, 0xf6, 0x00, + 0xdf, 0xa0, 0x02, 0x75, 0x05, 0x79, 0x93, 0xb6, 0x22, 0xdf, 0x2e, 0x1d, 0x5e, 0x54, 0x10, 0x18, + 0xe1, 0x79, 0x61, 0x05, 0x8d, 0xa7, 0x01, 0xc9, 0xc5, 0x15, 0x95, 0x62, 0x20, 0x7d, 0xd4, 0xde, + 0x4f, 0x51, 0xa3, 0x9b, 0x0b, 0x3f, 0x32, 0x86, 0x5e, 0x75, 0xb2, 0x0b, 0x1f, 0xbe, 0x00, 0x09, + 0x8d, 0xa3, 0x6a, 0x6f, 0x83, 0x0a, 0x4f, 0x1f, 0xb9, 0x97, 0xaa, 0xe4, 0x12, 0xb3, 0xf2, 0x0e, + 0x6a, 0x5f, 0x42, 0x1d, 0xfe, 0xb2, 0xec, 0x51, 0xa1, 0x3b, 0x0d, 0xa6, 0xda, 0x94, 0x1a, 0x01, + 0xaf, 0xa0, 0xfb, 0x8f, 0xe2, 0xcd, 0x42, 0xb1, 0x77, 0x67, 0x89, 0x1d, 0x11, 0xfd, 0x7c, 0x2c, + 0xb8, 0xc8, 0x5d, 0x78, 0x25, 0x51, 0xfc, 0x04, 0xcc, 0x16, 0x3a, 0xcb, 0xa8, 0xb6, 0x6d, 0x0b, + 0xfe, 0xf7, 0xc3, 0xc3, 0x72, 0x1d, 0x98, 0x36, 0xdb, 0xb6, 0x45, 0x42, 0xc0, 0xf9, 0x87, 0x80, + 0x82, 0x04, 0xff, 0x6d, 0x65, 0xd7, 0xbe, 0xd7, 0x64, 0xbb, 0xe6, 0x61, 0xc2, 0xa8, 0xc6, 0x04, + 0x66, 0xfd, 0xa8, 0x8c, 0x89, 0x01, 0x65, 0xa7, 0x0f, 0xd9, 0x27, 0x43, 0xef, 0x36, 0xda, 0x15, + 0x3e, 0x20, 0x56, 0x81, 0x47, 0x19, 0xce, 0xf8, 0x5a, 0x1c, 0xc9, 0x70, 0x16, 0xc3, 0xc0, 0x04, + 0x6e, 0x22, 0x0c, 0x71, 0x4c, 0x7d, 0x0d, 0xf8, 0x10, 0xe8, 0x8c, 0xcf, 0x3c, 0x1c, 0x11, 0x9d, + 0xa3, 0x31, 0x11, 0x3f, 0xc2, 0xc2, 0xd3, 0x33, 0x8b, 0x07, 0xfe, 0x8f, 0x71, 0x80, 0x73, 0xc7, + 0x28, 0xfe, 0x0a, 0xd4, 0x5b, 0x01, 0xbe, 0x55, 0x91, 0x0d, 0x81, 0x72, 0x40, 0x82, 0x98, 0xca, + 0x58, 0x10, 0x7c, 0x93, 0x54, 0x6c, 0x12, 0x99, 0xf2, 0xd3, 0x07, 0xf0, 0x05, 0x2a, 0x98, 0x27, + 0x3e, 0x02, 0x5d, 0x64, 0x38, 0xb4, 0xa3, 0x1c, 0x8b, 0xa3, 0xfc, 0xbb, 0xa5, 0x03, 0xfc, 0x88, + 0x72, 0x08, 0xf9, 0x18, 0x0b, 0x14, 0x72, 0xd1, 0x7d, 0x24, 0x59, 0x98, 0xc8, 0x36, 0x4a, 0x31, + 0x60, 0x81, 0xa9, 0xf8, 0x78, 0xf0, 0x48, 0xe8, 0x91, 0x2b, 0x0a, 0xc3, 0x6f, 0x6c, 0x13, 0xf6, + 0xc8, 0x95, 0x61, 0x22, 0x7d, 0x4c, 0xde, 0xf0, 0x68, 0xb6, 0xe0, 0xdc, 0x32, 0x2e, 0x76, 0x11, + 0x7c, 0x55, 0x36, 0x38, 0xd1, 0xf6, 0x87, 0x63, 0xf1, 0xc0, 0x3c, 0xc4, 0x65, 0x54, 0x1a, 0xc8, + 0x3a, 0xf6, 0x15, 0xba, 0xb4, 0x35, 0xa7, 0x93, 0xff, 0x34, 0x9e, 0x65, 0x77, 0x6f, 0xd7, 0xa2, + 0x27, 0x43, 0xe7, 0x74, 0xff, 0x51, 0xbb, 0x01, 0xcc, 0x5d, 0x31, 0xbd, 0x9d, 0x55, 0x64, 0x74, + 0x90, 0xa3, 0xdb, 0x57, 0x88, 0xc7, 0x5c, 0x41, 0x17, 0x13, 0x45, 0xff, 0x15, 0x09, 0xfb, 0x12, + 0x0b, 0x65, 0x32, 0xc7, 0xdf, 0x92, 0x58, 0x9e, 0xd1, 0x5c, 0xa5, 0xaf, 0x30, 0x1f, 0x50, 0xc1, + 0xb4, 0x6e, 0x5f, 0x61, 0x4a, 0xf2, 0xff, 0x1c, 0xad, 0x8e, 0x24, 0x9e, 0xe8, 0x11, 0xc9, 0x05, + 0xec, 0x4f, 0x7c, 0xa2, 0x17, 0x5b, 0xfc, 0x44, 0x4e, 0x2e, 0xcd, 0xea, 0xf6, 0x95, 0x26, 0xf2, + 0x68, 0x8b, 0x80, 0x9b, 0x63, 0x72, 0xb2, 0x36, 0x5d, 0x4a, 0x90, 0xcd, 0xc3, 0x83, 0xe7, 0xa4, + 0xbb, 0x08, 0x81, 0x80, 0x02, 0x16, 0x27, 0xbd, 0x8b, 0x30, 0x94, 0x83, 0x09, 0xc4, 0x48, 0x51, + 0xc1, 0x8c, 0x6e, 0x5f, 0xc1, 0x43, 0xc3, 0xb2, 0xd9, 0xed, 0x8e, 0x67, 0x84, 0x4c, 0x6a, 0xfc, + 0xfb, 0x62, 0xf0, 0xb9, 0x98, 0xb8, 0xf1, 0x3f, 0x84, 0x81, 0xf4, 0x61, 0x78, 0x1e, 0x6d, 0x2c, + 0xfe, 0x08, 0x6d, 0x8d, 0x07, 0x87, 0x51, 0x1b, 0x44, 0xc0, 0xc6, 0x91, 0x35, 0x88, 0x28, 0x0e, + 0x26, 0xb2, 0x73, 0x32, 0x5f, 0x26, 0xc3, 0xfc, 0x78, 0xdb, 0xc4, 0x7b, 0x93, 0xb9, 0x26, 0xb2, + 0x61, 0x57, 0x60, 0x64, 0x2c, 0x68, 0x24, 0x70, 0x41, 0x94, 0xe0, 0x21, 0x7d, 0x3c, 0x3e, 0xae, + 0x82, 0x59, 0xca, 0xc2, 0x03, 0xc4, 0x0a, 0x18, 0xa9, 0x51, 0xf1, 0x35, 0x38, 0x9a, 0x46, 0x15, + 0xc3, 0xc1, 0x44, 0xee, 0xf3, 0xc7, 0x76, 0xdc, 0x08, 0xc7, 0xc7, 0xa3, 0x10, 0x1c, 0xd9, 0x18, + 0x1b, 0xe3, 0x11, 0xf2, 0x51, 0x8c, 0xb1, 0x23, 0x3a, 0x46, 0xfe, 0xbc, 0xa0, 0x15, 0x8d, 0x13, + 0x83, 0x43, 0x34, 0x85, 0x31, 0xc2, 0x30, 0x62, 0x53, 0x38, 0x22, 0x24, 0xbe, 0xa6, 0x02, 0x40, + 0x19, 0x58, 0xb3, 0x2f, 0x93, 0x8b, 0x34, 0xc7, 0xd0, 0x9d, 0xf5, 0xbb, 0xd5, 0xab, 0x43, 0xdc, + 0xea, 0x13, 0x86, 0x70, 0x49, 0xba, 0x12, 0xc8, 0x49, 0x19, 0x57, 0x72, 0xe2, 0x2b, 0x81, 0xf1, + 0xe5, 0xa7, 0x8f, 0xf1, 0x57, 0xa8, 0x35, 0x17, 0x1e, 0x30, 0xfd, 0xf9, 0xb1, 0xa0, 0xcc, 0xcd, + 0xfe, 0x55, 0x71, 0xf6, 0x7f, 0x08, 0x6c, 0x47, 0xb5, 0x11, 0x87, 0x1d, 0x1c, 0x4d, 0xdf, 0x46, + 0x3c, 0xba, 0x03, 0xa2, 0x3f, 0x92, 0x05, 0xc7, 0x59, 0x27, 0xf2, 0xfd, 0x00, 0x71, 0xc2, 0x73, + 0x78, 0x42, 0x27, 0x39, 0x04, 0xe5, 0x71, 0x2d, 0x48, 0x25, 0x59, 0xca, 0x94, 0x60, 0x6f, 0x22, + 0xab, 0x1b, 0xf9, 0xca, 0x7d, 0x3d, 0xc3, 0xea, 0xc8, 0x87, 0xfb, 0x1d, 0x02, 0xbc, 0xbf, 0xd6, + 0xa8, 0x8a, 0x6b, 0x8d, 0x03, 0x56, 0x26, 0x13, 0xef, 0x5c, 0x13, 0x91, 0x51, 0x76, 0x27, 0xbe, + 0x73, 0x1d, 0x5d, 0x76, 0xfa, 0x28, 0xbd, 0x57, 0x05, 0xd9, 0xa6, 0xed, 0x78, 0xf0, 0xfe, 0x24, + 0xad, 0x93, 0x4a, 0x3e, 0x04, 0xc9, 0x7f, 0xd6, 0xca, 0x20, 0x8b, 0x2b, 0xc7, 0x66, 0x0c, 0xb7, + 0xc6, 0x1f, 0x75, 0x36, 0x3c, 0x83, 0x78, 0x75, 0xe3, 0xf2, 0x17, 0x5a, 0xfb, 0x3d, 0xa4, 0x93, + 0x8f, 0x93, 0xc6, 0xd3, 0xa1, 0xf2, 0x6b, 0x46, 0x1f, 0xc0, 0x48, 0x2d, 0x9e, 0x4e, 0x64, 0xc9, + 0xe9, 0xe3, 0xf6, 0xda, 0xe3, 0xcc, 0xb7, 0x75, 0xd9, 0xec, 0x22, 0x78, 0x3f, 0x75, 0x19, 0xa9, + 0x1b, 0xbb, 0x48, 0xfe, 0x48, 0x4c, 0xac, 0x6b, 0x2b, 0x89, 0x2f, 0xab, 0x86, 0xf1, 0x65, 0x93, + 0x36, 0x28, 0x7a, 0x00, 0x9d, 0xb2, 0x34, 0xe9, 0x06, 0x15, 0x53, 0xf6, 0x44, 0xe2, 0x74, 0x9e, + 0x68, 0x22, 0x8f, 0x1a, 0x95, 0x0d, 0xff, 0x8a, 0xa4, 0xa7, 0x8f, 0x25, 0x62, 0x67, 0x70, 0xa1, + 0x8e, 0xda, 0x77, 0x03, 0xd3, 0x07, 0x78, 0x70, 0xd6, 0x44, 0x70, 0x7e, 0x28, 0x5a, 0x40, 0x22, + 0x93, 0x63, 0x81, 0xe9, 0xed, 0x01, 0x4c, 0xeb, 0x02, 0x4c, 0x77, 0x8e, 0xc8, 0x45, 0xfa, 0x80, + 0xfd, 0x54, 0x0e, 0x1c, 0xa7, 0x93, 0xfe, 0x92, 0xd5, 0x61, 0x11, 0x56, 0xdf, 0xac, 0x1c, 0xf1, + 0x66, 0xdb, 0xc1, 0x10, 0xac, 0x42, 0x2c, 0xe7, 0x5c, 0x5f, 0x2c, 0x67, 0x6d, 0x91, 0x86, 0x73, + 0xc5, 0x9d, 0x28, 0xd9, 0x69, 0x1b, 0x16, 0x66, 0x82, 0xc8, 0x9e, 0x74, 0xb9, 0xc1, 0x77, 0xe2, + 0x3d, 0xa2, 0x53, 0xf2, 0xf7, 0x88, 0xfe, 0x7e, 0xb2, 0x75, 0x3b, 0x52, 0x74, 0x9f, 0xc0, 0x53, + 0xb6, 0x9d, 0x12, 0xac, 0xe8, 0x49, 0x70, 0xf7, 0x9f, 0xc3, 0x9d, 0x2c, 0x8c, 0x20, 0x32, 0xa2, + 0x3b, 0x19, 0x21, 0x70, 0x94, 0xee, 0x64, 0xc3, 0x18, 0x48, 0x1f, 0xc7, 0xdf, 0xcf, 0xb1, 0xdd, + 0x7c, 0xd2, 0x6e, 0xe0, 0x97, 0x95, 0xd4, 0x47, 0xe9, 0xef, 0x66, 0x12, 0xf9, 0x3f, 0x13, 0xbe, + 0xe2, 0x87, 0xe9, 0x24, 0x1e, 0xcd, 0x71, 0xe4, 0x26, 0xb0, 0x6e, 0xa4, 0x10, 0x5f, 0xf4, 0xf3, + 0x66, 0xc7, 0xdb, 0x19, 0xd3, 0x89, 0x8e, 0x2b, 0x98, 0x16, 0x8b, 0x57, 0x4f, 0x1f, 0xe0, 0xbf, + 0x64, 0x12, 0x85, 0x90, 0x0a, 0x44, 0x42, 0xd8, 0x8a, 0x10, 0x71, 0x82, 0xc0, 0x4f, 0xb1, 0xf4, + 0x26, 0xa8, 0xd1, 0xe7, 0xcc, 0x0e, 0xb2, 0x1f, 0x80, 0x1a, 0x4d, 0xf8, 0x1a, 0x9f, 0x46, 0xc7, + 0x91, 0xfb, 0x4f, 0xaa, 0xd1, 0x81, 0x48, 0xc6, 0xa4, 0xd1, 0xb1, 0xf4, 0xd2, 0x97, 0xf1, 0x2b, + 0x66, 0xd9, 0x44, 0xaa, 0x66, 0x5a, 0x97, 0xe0, 0x3f, 0xe6, 0x41, 0xd1, 0x8f, 0x23, 0xec, 0xed, + 0xb0, 0x58, 0x30, 0x1f, 0x96, 0xbe, 0x1b, 0x65, 0x84, 0x78, 0x2f, 0x62, 0x38, 0xa9, 0xdc, 0x81, + 0x70, 0x52, 0x25, 0x30, 0x67, 0x5a, 0x1e, 0x72, 0x2c, 0xa3, 0xbb, 0xdc, 0x35, 0xb6, 0xdd, 0xd3, + 0x53, 0x03, 0x2f, 0xaf, 0xab, 0x72, 0x79, 0x74, 0xf1, 0x0b, 0xfe, 0x02, 0xd1, 0x82, 0x78, 0x81, + 0x68, 0x44, 0xf4, 0xab, 0xe9, 0xe8, 0xe8, 0x57, 0x41, 0x74, 0x2b, 0x30, 0x3c, 0x38, 0xb6, 0xac, + 0x6d, 0x9c, 0x30, 0xdc, 0xdf, 0xad, 0x92, 0x51, 0xd8, 0x82, 0xd0, 0x8f, 0xaf, 0x56, 0x13, 0xad, + 0xee, 0x61, 0x45, 0x58, 0xe8, 0x57, 0x82, 0xc4, 0x16, 0x2a, 0x5f, 0x79, 0xb5, 0xaf, 0xf2, 0x81, + 0xc9, 0x93, 0x95, 0x30, 0x79, 0x78, 0xa5, 0xca, 0xc9, 0xde, 0xe9, 0x2a, 0xbf, 0x58, 0x28, 0x53, + 0xdb, 0x09, 0x9c, 0x46, 0xca, 0x81, 0x13, 0x7e, 0xb4, 0xdb, 0x5e, 0x0f, 0x19, 0x8e, 0x61, 0xb5, + 0x11, 0xfc, 0xa4, 0x32, 0x0e, 0xb3, 0x77, 0x19, 0x14, 0xcc, 0xb6, 0x6d, 0x35, 0xcd, 0x67, 0xfa, + 0x97, 0xcb, 0xc5, 0x07, 0x59, 0x27, 0x12, 0xa9, 0xb2, 0x2f, 0xf4, 0xe0, 0x5b, 0xad, 0x0a, 0xa6, + 0xdb, 0x86, 0xd3, 0xa1, 0x41, 0xf8, 0x72, 0x7d, 0x17, 0x39, 0x45, 0x12, 0x2a, 0xfb, 0x9f, 0xe8, + 0xe1, 0xd7, 0x5a, 0x43, 0x14, 0x62, 0xbe, 0x2f, 0x9a, 0x47, 0x24, 0xb1, 0xa5, 0xf0, 0x23, 0x41, + 0xe6, 0x58, 0x3a, 0x0e, 0xea, 0x1a, 0xf4, 0xd2, 0xf1, 0x29, 0x7a, 0x47, 0x74, 0x90, 0x90, 0x74, + 0x79, 0x80, 0x14, 0x75, 0x00, 0x8d, 0x49, 0x2f, 0x0f, 0x48, 0x71, 0x91, 0xbe, 0x66, 0xbe, 0x2b, + 0x0f, 0xe6, 0x68, 0xaf, 0xc6, 0xc4, 0x09, 0x5f, 0xa0, 0x82, 0x7c, 0x13, 0x79, 0xf7, 0xa0, 0x7d, + 0xd8, 0x3c, 0xfc, 0x98, 0x5c, 0x04, 0xea, 0xa5, 0x20, 0xe0, 0x20, 0xfe, 0x9b, 0x74, 0xdf, 0xde, + 0xe7, 0x6b, 0x81, 0xf2, 0x34, 0xe9, 0x7d, 0xfb, 0xf8, 0xe2, 0xd3, 0xc7, 0xe7, 0xa7, 0x55, 0xa0, + 0x96, 0x3a, 0x1d, 0xd8, 0x3e, 0x3c, 0x14, 0xd7, 0x83, 0x19, 0xbf, 0xcd, 0x84, 0x31, 0x20, 0xf9, + 0xa4, 0xa4, 0x8b, 0xa0, 0x81, 0x6c, 0x4a, 0x9d, 0x89, 0xef, 0x2a, 0xc4, 0x94, 0x9d, 0x3e, 0x28, + 0x5f, 0x98, 0x62, 0x8d, 0x66, 0xd1, 0xb6, 0x2f, 0x91, 0xa3, 0x32, 0xbf, 0xac, 0x82, 0xdc, 0x32, + 0xf2, 0xda, 0x3b, 0xd0, 0x1d, 0x4b, 0x9b, 0xe9, 0xbb, 0xf7, 0x7c, 0x48, 0x50, 0xce, 0xa4, 0xd1, + 0x9f, 0x7d, 0xb6, 0x17, 0x08, 0xcb, 0x93, 0x8e, 0xfe, 0x1c, 0x5b, 0xfa, 0x04, 0x0e, 0xc1, 0x65, + 0xc1, 0x7c, 0xb0, 0x02, 0x46, 0x31, 0x7b, 0x47, 0xe6, 0x01, 0xb7, 0x1e, 0x3a, 0xc4, 0x6e, 0x86, + 0x7f, 0x9c, 0x2c, 0xc4, 0x5a, 0x20, 0x73, 0xb1, 0xe6, 0x29, 0x2f, 0x4c, 0x26, 0x08, 0xbe, 0x26, + 0xc7, 0xe0, 0x04, 0x56, 0x00, 0x54, 0x50, 0x20, 0x0c, 0x2d, 0x99, 0x97, 0x89, 0xeb, 0xa1, 0xb0, + 0x50, 0xf9, 0xac, 0xb1, 0x2c, 0x54, 0xde, 0x29, 0x2e, 0x54, 0x4a, 0x46, 0x4c, 0xf6, 0xd7, 0x29, + 0x13, 0xfa, 0xe2, 0xe0, 0xef, 0xc7, 0xbe, 0x4c, 0x99, 0xc0, 0x17, 0x67, 0x48, 0xf9, 0xe9, 0x23, + 0xfa, 0xc6, 0xff, 0xca, 0x3a, 0x6b, 0x7f, 0x43, 0x16, 0xfe, 0xcf, 0x13, 0x20, 0x7b, 0x0e, 0xff, + 0xf9, 0x87, 0xf0, 0x46, 0xad, 0x97, 0x8d, 0x21, 0xb8, 0xc3, 0x93, 0x41, 0x16, 0xd3, 0x67, 0xd3, + 0x9e, 0x9b, 0xe5, 0x76, 0x87, 0x31, 0x23, 0x3a, 0xf9, 0x4e, 0x3b, 0x05, 0xf2, 0xae, 0xbd, 0xe7, + 0xb4, 0xb1, 0xf9, 0x8d, 0x35, 0x86, 0x3d, 0x25, 0x0d, 0x6a, 0x2a, 0x90, 0x5e, 0x18, 0x9f, 0xcb, + 0x29, 0x77, 0xc1, 0x92, 0x2a, 0x5c, 0xb0, 0x94, 0x60, 0xff, 0x41, 0x82, 0xb7, 0xf4, 0x35, 0xe2, + 0xcb, 0xe4, 0xae, 0xc1, 0xce, 0xb8, 0x60, 0x8f, 0x10, 0xcb, 0x61, 0xd5, 0x21, 0xa9, 0xc3, 0xb8, + 0x28, 0xda, 0x20, 0x8e, 0xfc, 0x44, 0x1d, 0xc6, 0x25, 0x78, 0x98, 0xc8, 0x29, 0xf7, 0x3c, 0x73, + 0x72, 0xbd, 0x30, 0x4e, 0x74, 0xb3, 0x82, 0xd2, 0x1f, 0x0a, 0x9d, 0x31, 0x3a, 0xbf, 0x8e, 0x8c, + 0xce, 0x11, 0xb9, 0xbf, 0xfe, 0xa6, 0x4a, 0x22, 0x69, 0xfa, 0x46, 0x90, 0xfc, 0x45, 0x49, 0x89, + 0x21, 0xc2, 0x63, 0xb0, 0x10, 0x47, 0x7a, 0x6e, 0xf4, 0xd0, 0xe2, 0xa2, 0xe8, 0x38, 0xfe, 0x27, + 0x1d, 0x5a, 0x5c, 0x96, 0x91, 0xf4, 0x81, 0xfc, 0x25, 0x7a, 0x31, 0x59, 0xa9, 0xed, 0x99, 0x97, + 0xc7, 0xdc, 0xd2, 0xc4, 0xe1, 0x25, 0x61, 0x34, 0xe1, 0x03, 0x12, 0xa2, 0x1c, 0x4e, 0x3a, 0x9a, + 0xb0, 0x1c, 0x1b, 0xe9, 0xc3, 0xf4, 0x93, 0x00, 0x4b, 0x8f, 0xad, 0xed, 0xbc, 0x41, 0x05, 0x6a, + 0x13, 0x79, 0x10, 0x1d, 0x1e, 0xad, 0xb3, 0x60, 0x96, 0x5b, 0x3a, 0xf0, 0x2f, 0xbc, 0x11, 0xd2, + 0x92, 0x1e, 0x94, 0x0f, 0x44, 0xc6, 0x2f, 0xba, 0x4c, 0xfa, 0xa0, 0xbc, 0x0c, 0x13, 0x13, 0x38, + 0x28, 0xcf, 0x96, 0x7d, 0xbe, 0x5f, 0x80, 0x1a, 0xd7, 0x0a, 0xd0, 0xa1, 0x80, 0x3a, 0x8a, 0xa5, + 0xa0, 0xb7, 0x87, 0xc6, 0xc6, 0x84, 0xb0, 0xfa, 0x30, 0x8f, 0x55, 0x43, 0xc4, 0xea, 0x76, 0x19, + 0x31, 0xc9, 0x19, 0x1f, 0x52, 0x13, 0xfc, 0x77, 0x06, 0x70, 0xe9, 0x02, 0x5c, 0x4f, 0x1e, 0x99, + 0x8f, 0xf4, 0x11, 0xfb, 0x05, 0x3a, 0x6e, 0x35, 0xe9, 0xdc, 0x6a, 0x3c, 0xe3, 0x16, 0x9b, 0xb6, + 0xa9, 0xc2, 0xb4, 0x2d, 0xe1, 0xc1, 0x8a, 0xd0, 0x5f, 0xd8, 0x67, 0x6e, 0x18, 0x44, 0xd9, 0x31, + 0x1f, 0xac, 0x18, 0xca, 0x41, 0xfa, 0xe0, 0x7c, 0x4b, 0x05, 0x60, 0xc5, 0xb1, 0xf7, 0x7a, 0x0d, + 0xa7, 0x83, 0x1c, 0xf8, 0xe7, 0xe1, 0x4c, 0xed, 0x67, 0xc6, 0x30, 0x53, 0x5b, 0x07, 0x60, 0x3b, + 0x20, 0xce, 0x34, 0xfc, 0xd1, 0x72, 0xf3, 0xb2, 0x90, 0x29, 0x9d, 0xa3, 0x21, 0xde, 0x2d, 0xfc, + 0x54, 0x11, 0xe3, 0xb8, 0x3e, 0x2b, 0x24, 0x37, 0xce, 0x99, 0xda, 0xbb, 0x03, 0xac, 0x5b, 0x02, + 0xd6, 0x4f, 0x39, 0x04, 0x27, 0xe9, 0x63, 0xfe, 0xf7, 0x53, 0x60, 0x86, 0xee, 0xcb, 0x52, 0x99, + 0xfe, 0x4d, 0x08, 0xfa, 0xcf, 0x8f, 0x01, 0xf4, 0x0d, 0x30, 0x6b, 0x87, 0xd4, 0x69, 0x9f, 0xca, + 0xaf, 0x94, 0xc5, 0xc2, 0xce, 0xf1, 0xa5, 0x0b, 0x64, 0xe0, 0x6f, 0xf0, 0xc8, 0xeb, 0x22, 0xf2, + 0x77, 0xc6, 0xc8, 0x9b, 0xa3, 0x38, 0x4e, 0xe8, 0xdf, 0x13, 0x40, 0xbf, 0x21, 0x40, 0x5f, 0x3a, + 0x0c, 0x2b, 0x13, 0xb8, 0x57, 0x41, 0x05, 0x59, 0x72, 0x0c, 0xf2, 0x2d, 0x29, 0x2e, 0xc4, 0x9c, + 0x06, 0x53, 0xa4, 0xc9, 0x06, 0x13, 0x44, 0xff, 0x11, 0xbf, 0x31, 0xb6, 0x3c, 0xe4, 0x04, 0x4b, + 0xec, 0xfe, 0x23, 0xe6, 0xc1, 0x77, 0x3f, 0x77, 0x4f, 0xe7, 0xe9, 0x8e, 0x73, 0x90, 0x30, 0xf2, + 0xec, 0x91, 0x97, 0xf8, 0xd8, 0x0e, 0x46, 0x8e, 0x32, 0x7b, 0x1c, 0xc2, 0x48, 0xfa, 0xc0, 0x7f, + 0x31, 0x0b, 0x4e, 0xd3, 0xe5, 0xbf, 0x65, 0xc7, 0xde, 0xed, 0xbb, 0xc6, 0xcc, 0x3c, 0xbc, 0x2e, + 0xdc, 0x08, 0xe6, 0x3d, 0xc1, 0xf1, 0x9e, 0xe9, 0x44, 0x5f, 0x2a, 0xfc, 0x03, 0xde, 0x79, 0xe6, + 0x69, 0x22, 0x92, 0x8b, 0x31, 0x02, 0x8c, 0xe2, 0x3d, 0xf1, 0x8e, 0x8a, 0x24, 0xa3, 0xdc, 0x6a, + 0xa2, 0x3a, 0xd2, 0xe2, 0x72, 0xa0, 0x53, 0x39, 0x19, 0x9d, 0xfa, 0x60, 0xa0, 0x53, 0xff, 0x45, + 0xd0, 0xa9, 0x95, 0xc3, 0x8b, 0x64, 0x02, 0x4b, 0x4c, 0xf3, 0x20, 0xbf, 0x6c, 0x76, 0x3d, 0xe4, + 0xc0, 0xaf, 0xb0, 0x79, 0xd4, 0xab, 0x52, 0xec, 0x5e, 0x96, 0x40, 0x7e, 0x8b, 0x94, 0xc6, 0x0c, + 0xb2, 0x5b, 0xe4, 0xb0, 0xa1, 0x1c, 0xea, 0xec, 0xdb, 0xa4, 0x41, 0xfe, 0xfa, 0xc8, 0x8c, 0x6d, + 0x02, 0x96, 0x20, 0xc8, 0xdf, 0x70, 0x16, 0x26, 0x72, 0xbf, 0x55, 0x5e, 0x47, 0xbb, 0x78, 0x04, + 0xb9, 0x94, 0x1e, 0xc2, 0x45, 0xa0, 0x9a, 0x1d, 0x97, 0x34, 0xbd, 0x69, 0x1d, 0xff, 0x4d, 0xea, + 0x72, 0xd4, 0x2f, 0x2a, 0xca, 0xf2, 0xa4, 0x5d, 0x8e, 0xa4, 0xb8, 0x48, 0x1f, 0xb3, 0xef, 0x12, + 0x7f, 0xd3, 0x5e, 0xd7, 0x68, 0x23, 0xcc, 0x7d, 0x6a, 0xa8, 0xcd, 0x03, 0xc5, 0xf4, 0x47, 0x7c, + 0xc5, 0xe4, 0xdb, 0x69, 0xee, 0x10, 0xed, 0x74, 0xd4, 0xd5, 0xc8, 0x40, 0xe6, 0xa4, 0xe2, 0x47, + 0xb6, 0x1a, 0x19, 0xcb, 0xc6, 0x04, 0x6e, 0x2f, 0xf5, 0xcf, 0xe3, 0x4e, 0xb4, 0xb5, 0x8e, 0xba, + 0x57, 0xc3, 0x84, 0x35, 0xb6, 0xb3, 0xb7, 0xa3, 0xec, 0xd5, 0x44, 0xf3, 0x30, 0x01, 0xb4, 0xe6, + 0x19, 0x5a, 0x9f, 0x63, 0xc3, 0x68, 0xca, 0xdb, 0xa5, 0xae, 0xed, 0x78, 0xc9, 0xb6, 0x4b, 0x31, + 0x77, 0x3a, 0xf9, 0x2e, 0xe9, 0xf9, 0x2d, 0xf1, 0x78, 0xf6, 0xb8, 0x86, 0xcf, 0x04, 0xe7, 0xb7, + 0x86, 0x31, 0x90, 0x3e, 0xbc, 0x6f, 0x3d, 0xa2, 0xc1, 0x73, 0xd4, 0xe6, 0xc8, 0xda, 0xc0, 0xd8, + 0x86, 0xce, 0x51, 0x9a, 0x63, 0x34, 0x0f, 0xe9, 0xe3, 0xf5, 0x77, 0xdc, 0xc0, 0xf9, 0xa6, 0x09, + 0x0e, 0x9c, 0x7e, 0xcb, 0xcc, 0x8d, 0xd8, 0x32, 0x47, 0xdd, 0x5d, 0x60, 0xb2, 0x1e, 0xdf, 0x80, + 0x39, 0xca, 0xee, 0x42, 0x0c, 0x13, 0xe9, 0x23, 0xfe, 0x66, 0x15, 0xe4, 0x9a, 0x93, 0x1f, 0x2f, + 0x47, 0x9d, 0x8b, 0x10, 0x59, 0x35, 0xc7, 0x36, 0x5c, 0x8e, 0x32, 0x17, 0x89, 0x64, 0x61, 0x02, + 0xf1, 0xfb, 0x8f, 0x83, 0x59, 0x32, 0xe1, 0xf6, 0x77, 0x5b, 0xff, 0x8e, 0x8d, 0x9a, 0xaf, 0x4f, + 0xb1, 0xad, 0xde, 0x0d, 0x0a, 0xfe, 0xee, 0x10, 0x1b, 0x39, 0x17, 0xe4, 0xda, 0xa7, 0xcf, 0xa5, + 0x1e, 0x7c, 0x7f, 0x28, 0x9f, 0x88, 0xb1, 0xef, 0x04, 0x8e, 0xea, 0x13, 0x71, 0xa4, 0xbb, 0x81, + 0xbf, 0x1f, 0x8e, 0xa8, 0xff, 0x3d, 0x3d, 0xcc, 0xfb, 0x77, 0x09, 0xb3, 0x03, 0x76, 0x09, 0x3f, + 0xc9, 0x63, 0xd9, 0x14, 0xb1, 0x7c, 0x92, 0xac, 0x08, 0xc7, 0x38, 0xd6, 0xbe, 0x37, 0x80, 0xf3, + 0x9c, 0x00, 0xe7, 0xe2, 0xa1, 0x78, 0x99, 0xc0, 0xf9, 0xc9, 0x6c, 0x38, 0xe6, 0x7e, 0x2a, 0xc5, + 0x76, 0xdc, 0x77, 0x38, 0x23, 0x7b, 0xe0, 0x70, 0x86, 0xd0, 0xd2, 0x73, 0x87, 0x6c, 0xe9, 0x9f, + 0xe2, 0xb5, 0xa3, 0x25, 0x6a, 0xc7, 0x93, 0xe5, 0x11, 0x19, 0xdf, 0xc8, 0xfc, 0xbe, 0x40, 0x3d, + 0xce, 0x0b, 0xea, 0x51, 0x3e, 0x1c, 0x33, 0xe9, 0xeb, 0xc7, 0x6f, 0xf9, 0x13, 0xda, 0x23, 0x6e, + 0xef, 0xa3, 0x6e, 0x44, 0x0a, 0x42, 0x1c, 0xdb, 0xc8, 0x3d, 0xca, 0x46, 0xe4, 0x30, 0x4e, 0x26, + 0x10, 0xd2, 0x6d, 0x0e, 0xcc, 0x10, 0x9e, 0xce, 0x9b, 0x9d, 0x6d, 0xe4, 0xc1, 0x57, 0x53, 0x57, + 0x45, 0x3f, 0x80, 0xe6, 0x98, 0xa2, 0x1c, 0x45, 0x1d, 0x9b, 0x4d, 0xea, 0x2f, 0x40, 0x99, 0x5c, + 0xe0, 0x18, 0x9c, 0x74, 0x20, 0xc6, 0xa1, 0x1c, 0xa4, 0x0f, 0xd9, 0x6f, 0x50, 0x67, 0x8e, 0x9a, + 0xb1, 0x6f, 0xef, 0x79, 0xf0, 0x39, 0x63, 0xe8, 0xa0, 0x17, 0x41, 0xbe, 0x4b, 0xa8, 0xb1, 0xd3, + 0x19, 0xf1, 0xd3, 0x1d, 0x26, 0x02, 0x5a, 0xbe, 0xce, 0xbe, 0x4c, 0x7a, 0x44, 0x23, 0x94, 0x23, + 0xa5, 0x33, 0xe9, 0x23, 0x1a, 0x43, 0xca, 0x9f, 0xc8, 0x55, 0x3d, 0x05, 0x5c, 0xba, 0xb9, 0x6b, + 0x7a, 0x63, 0x0a, 0x04, 0xd1, 0xc5, 0xb4, 0xfc, 0x40, 0x10, 0xe4, 0x21, 0xe9, 0xc1, 0x53, 0x4e, + 0x2a, 0xf8, 0xf3, 0x49, 0x1f, 0x3c, 0x8d, 0x2f, 0x3e, 0x7d, 0x4c, 0x7e, 0x8e, 0xb6, 0xac, 0x73, + 0xd4, 0x07, 0x37, 0x45, 0xf7, 0xde, 0x91, 0x1b, 0x0b, 0x65, 0xed, 0xe8, 0x1a, 0xcb, 0xc0, 0xf2, + 0xd3, 0x07, 0xe6, 0x97, 0x7f, 0x00, 0xe4, 0x96, 0xd0, 0xc5, 0xbd, 0x6d, 0x78, 0x27, 0x28, 0xb4, + 0x1c, 0x84, 0xaa, 0xd6, 0x96, 0x8d, 0xa5, 0xeb, 0xe1, 0xff, 0x3e, 0x24, 0xec, 0x09, 0xe3, 0xb1, + 0x83, 0x8c, 0x4e, 0x78, 0x0c, 0xcd, 0x7f, 0x84, 0x2f, 0x53, 0x40, 0xb6, 0xe9, 0x19, 0x1e, 0x9c, + 0x0e, 0xb0, 0x85, 0xcf, 0xe1, 0xb1, 0xb8, 0x53, 0xc4, 0xe2, 0x46, 0x41, 0x16, 0x84, 0x83, 0x05, + 0xfc, 0x7d, 0x04, 0x00, 0x10, 0x14, 0xee, 0x75, 0x6d, 0x0b, 0xe7, 0xf0, 0x4f, 0x4a, 0xfa, 0xcf, + 0xf0, 0x95, 0x81, 0xb8, 0xef, 0x12, 0xc4, 0xfd, 0x48, 0xb9, 0x22, 0x26, 0xb0, 0xd2, 0xa6, 0x80, + 0x69, 0x2c, 0xda, 0x55, 0x64, 0x74, 0x5c, 0xf8, 0xd0, 0x50, 0xf9, 0x23, 0xc4, 0x0c, 0x3f, 0x22, + 0x1d, 0xd3, 0x93, 0xd6, 0x2a, 0x20, 0x1e, 0xed, 0x2f, 0xe0, 0xc7, 0x34, 0x51, 0xc4, 0x98, 0x26, + 0xb7, 0x82, 0xac, 0x69, 0x6d, 0xd9, 0xcc, 0x7b, 0xed, 0xda, 0x08, 0xda, 0x58, 0x27, 0x74, 0x92, + 0x51, 0x32, 0xe0, 0x67, 0x3c, 0x5b, 0x13, 0xb9, 0x3b, 0x2f, 0x8b, 0x4b, 0x87, 0xff, 0xf7, 0x50, + 0x61, 0x6b, 0x1a, 0xc8, 0xf6, 0x0c, 0x6f, 0x87, 0x15, 0x4d, 0xfe, 0x63, 0x1b, 0x79, 0xcf, 0x32, + 0x2c, 0xdb, 0xda, 0xdf, 0x35, 0x9f, 0x19, 0x5c, 0xd1, 0x2b, 0xa4, 0x61, 0xce, 0xb7, 0x91, 0x85, + 0x1c, 0xc3, 0x43, 0xcd, 0xcb, 0xdb, 0x64, 0x8e, 0x55, 0xd0, 0xf9, 0xa4, 0xc4, 0xfa, 0x8f, 0x39, + 0x8e, 0xd6, 0xff, 0x2d, 0xb3, 0x8b, 0x48, 0xc0, 0x27, 0xa6, 0xff, 0xfe, 0x73, 0x22, 0xfd, 0x1f, + 0x50, 0x44, 0xfa, 0x68, 0xfc, 0xab, 0x02, 0x66, 0x9b, 0x58, 0xe1, 0x9a, 0x7b, 0xbb, 0xbb, 0x86, + 0xb3, 0x0f, 0x1f, 0x16, 0xa2, 0xc2, 0xa9, 0x66, 0x46, 0x50, 0x4d, 0xf8, 0x9b, 0xd2, 0xb7, 0x53, + 0xb3, 0xa6, 0xcd, 0x95, 0x90, 0xb8, 0x1d, 0x3c, 0x06, 0xe4, 0xb0, 0x7a, 0xfb, 0xfe, 0x7c, 0xb1, + 0x0d, 0x81, 0xe6, 0x94, 0x0c, 0x8c, 0x35, 0x94, 0xb7, 0x09, 0x04, 0xe5, 0x50, 0xc0, 0xf1, 0xa6, + 0x67, 0xb4, 0x2f, 0xad, 0xd8, 0x8e, 0xbd, 0xe7, 0x99, 0x16, 0x72, 0xe1, 0x83, 0x43, 0x04, 0x7c, + 0xfd, 0xcf, 0x84, 0xfa, 0x0f, 0xff, 0x3d, 0x23, 0x3b, 0x8a, 0x06, 0xdd, 0x2a, 0x4f, 0x3e, 0x22, + 0xce, 0x95, 0xdc, 0xb8, 0x28, 0x43, 0x31, 0x7d, 0xa1, 0xbd, 0x49, 0x05, 0xc5, 0xca, 0x7d, 0x3d, + 0xdb, 0xf1, 0x6a, 0x76, 0xdb, 0xe8, 0xba, 0x9e, 0xed, 0x20, 0xd8, 0x88, 0x95, 0x1a, 0xee, 0x61, + 0x3a, 0x76, 0x3b, 0x1c, 0x1c, 0xd9, 0x13, 0xaf, 0x76, 0xaa, 0xa8, 0xe3, 0xbf, 0x21, 0xbd, 0xcb, + 0x48, 0xa5, 0xd2, 0xcf, 0x51, 0x84, 0x9e, 0x0f, 0xea, 0xd2, 0x92, 0xb9, 0xe2, 0xcb, 0xed, 0x3c, + 0x4a, 0x31, 0x35, 0x81, 0xa5, 0x72, 0x05, 0xcc, 0x35, 0xf7, 0x2e, 0x06, 0x44, 0x5c, 0xde, 0x08, + 0x79, 0x8d, 0x74, 0x30, 0x0b, 0xa6, 0x78, 0x3c, 0xa1, 0x08, 0xf9, 0xde, 0x00, 0xe6, 0x5c, 0x3e, + 0x1b, 0xc3, 0x5b, 0x4c, 0x94, 0x0c, 0x62, 0x31, 0xbc, 0xd4, 0xf4, 0x05, 0xf8, 0x3e, 0x05, 0xcc, + 0x35, 0x7a, 0xc8, 0x42, 0x1d, 0xea, 0x63, 0x27, 0x08, 0xf0, 0x65, 0x09, 0x05, 0x28, 0x10, 0x8a, + 0x10, 0x60, 0xe8, 0x0f, 0xbb, 0xe4, 0x0b, 0x2f, 0x4c, 0x48, 0x24, 0xb8, 0xb8, 0xd2, 0xd2, 0x17, + 0xdc, 0x97, 0x14, 0x30, 0xa3, 0xef, 0x59, 0xeb, 0x8e, 0x8d, 0x47, 0x63, 0x07, 0x3e, 0x29, 0xec, + 0x20, 0x6e, 0x01, 0x27, 0x3a, 0x7b, 0x0e, 0x59, 0x7f, 0xaa, 0x5a, 0x4d, 0xd4, 0xb6, 0xad, 0x8e, + 0x4b, 0xea, 0x91, 0xd3, 0x0f, 0xbe, 0xb8, 0x23, 0x7b, 0xff, 0xd7, 0xd5, 0x0c, 0x7c, 0x81, 0x74, + 0xc4, 0x1c, 0x5a, 0x79, 0xae, 0x68, 0xf9, 0x9e, 0x40, 0x32, 0x2e, 0xce, 0xb0, 0x12, 0xd2, 0x17, + 0xee, 0xe7, 0x14, 0xa0, 0x95, 0xda, 0x6d, 0x7b, 0xcf, 0xf2, 0x9a, 0xa8, 0x8b, 0xda, 0x5e, 0xcb, + 0x31, 0xda, 0x88, 0xb7, 0x9f, 0x8b, 0x40, 0xed, 0x98, 0x0e, 0xeb, 0x83, 0xf1, 0x5f, 0x26, 0xc7, + 0x97, 0x49, 0xef, 0x38, 0xd2, 0x5a, 0x1e, 0x2c, 0x25, 0x81, 0x38, 0xe5, 0xf6, 0x15, 0x25, 0x0b, + 0x4a, 0x5f, 0xaa, 0x9f, 0x52, 0xc0, 0xb4, 0xdf, 0x63, 0x6f, 0xcb, 0x08, 0xf3, 0xe7, 0x12, 0x4e, + 0x46, 0x02, 0xe2, 0x09, 0x64, 0xf8, 0xae, 0x04, 0xb3, 0x8a, 0x28, 0xfa, 0xc9, 0x44, 0x57, 0x4a, + 0x2e, 0x3a, 0xfc, 0x58, 0x6f, 0x6c, 0x2e, 0x37, 0x6a, 0x4b, 0x15, 0xbd, 0xa8, 0xc2, 0xaf, 0x28, + 0x20, 0xbb, 0x6e, 0x5a, 0xdb, 0x7c, 0x60, 0xb3, 0x93, 0xd8, 0x8e, 0xec, 0xa0, 0xfb, 0x58, 0x4b, + 0xa7, 0x0f, 0xda, 0x6d, 0xe0, 0xa4, 0xb5, 0xb7, 0x7b, 0x11, 0x39, 0x8d, 0x2d, 0x32, 0xca, 0xba, + 0x2d, 0xbb, 0x89, 0x2c, 0x6a, 0x84, 0xe6, 0xf4, 0x81, 0xef, 0x44, 0x13, 0x4c, 0x62, 0xf2, 0x80, + 0x39, 0x89, 0x90, 0x78, 0xc0, 0x94, 0xc2, 0x31, 0x95, 0x68, 0xda, 0x30, 0x80, 0x78, 0xfa, 0x9a, + 0xfa, 0xdb, 0x39, 0x70, 0x75, 0xc9, 0xda, 0x27, 0x36, 0x05, 0xed, 0xe0, 0xcb, 0x3b, 0x86, 0xb5, + 0x8d, 0xc8, 0x00, 0x11, 0x48, 0x9c, 0x8f, 0xf4, 0x9f, 0x11, 0x23, 0xfd, 0x6b, 0x3a, 0x98, 0xb2, + 0x9d, 0x0e, 0x72, 0x16, 0xf7, 0x09, 0x4f, 0xfd, 0xcb, 0xce, 0xac, 0x4d, 0x0e, 0x2a, 0x62, 0x81, + 0x91, 0x5f, 0x68, 0xd0, 0xef, 0x75, 0x9f, 0xd0, 0xd9, 0x5b, 0xc0, 0x14, 0x4b, 0xd3, 0x66, 0x41, + 0xa1, 0xa1, 0x2f, 0x55, 0xf4, 0xcd, 0xea, 0x52, 0xf1, 0x98, 0x76, 0x15, 0x38, 0x5e, 0x6d, 0x55, + 0xf4, 0x52, 0xab, 0xda, 0xa8, 0x6f, 0x92, 0xf4, 0x62, 0x06, 0x3e, 0x2f, 0x2b, 0xeb, 0xd9, 0x1b, + 0xcf, 0xcc, 0x20, 0x58, 0x75, 0x30, 0xd5, 0xa6, 0x19, 0xc8, 0x10, 0x3a, 0x93, 0xa8, 0x76, 0x8c, + 0x20, 0x4d, 0xd0, 0x7d, 0x42, 0xda, 0x19, 0x00, 0xae, 0x38, 0xb6, 0xb5, 0x1d, 0x9e, 0x69, 0x2b, + 0xe8, 0x5c, 0x0a, 0x7c, 0x4e, 0x06, 0xe4, 0xe9, 0x37, 0xe4, 0x66, 0x13, 0xf2, 0x2f, 0x14, 0xbc, + 0xff, 0x8c, 0x2d, 0x5e, 0x22, 0xaf, 0x70, 0xa2, 0xc5, 0x1e, 0xb1, 0x2e, 0x52, 0x19, 0x50, 0x4b, + 0x98, 0x55, 0xe5, 0x56, 0x90, 0xa7, 0xdf, 0x32, 0xaf, 0x83, 0xe8, 0x28, 0xa5, 0x34, 0x9b, 0xa4, + 0x9f, 0xb2, 0xbc, 0x4c, 0xd3, 0xd7, 0xe6, 0x8f, 0x2a, 0xa0, 0x50, 0x47, 0x5e, 0x79, 0x07, 0xb5, + 0x2f, 0xc1, 0x47, 0x88, 0x0b, 0xa0, 0x5d, 0x13, 0x59, 0xde, 0x85, 0xdd, 0x6e, 0xb0, 0x00, 0xea, + 0x27, 0xc0, 0xe7, 0xf3, 0x9d, 0xef, 0x53, 0x44, 0xfd, 0xb9, 0x79, 0x40, 0x5d, 0xfd, 0x12, 0x22, + 0x54, 0xe6, 0x14, 0xc8, 0x3b, 0xc8, 0xdd, 0xeb, 0xfa, 0x8b, 0x68, 0xec, 0x09, 0xbe, 0x36, 0x10, + 0x67, 0x59, 0x10, 0xe7, 0xad, 0xf2, 0x45, 0x4c, 0x20, 0xec, 0x69, 0x16, 0x4c, 0x55, 0x2d, 0xd3, + 0x33, 0x8d, 0x2e, 0x7c, 0x41, 0x16, 0xcc, 0x35, 0x91, 0xb7, 0x6e, 0x38, 0xc6, 0x2e, 0xf2, 0x90, + 0xe3, 0xc2, 0xef, 0x88, 0x7d, 0x42, 0xaf, 0x6b, 0x78, 0x5b, 0xb6, 0xb3, 0xeb, 0xab, 0xa6, 0xff, + 0x8c, 0x55, 0xf3, 0x32, 0x72, 0xdc, 0x90, 0x2f, 0xff, 0x11, 0xbf, 0xb9, 0x62, 0x3b, 0x97, 0xf0, + 0x20, 0xc8, 0xa6, 0x69, 0xec, 0x11, 0xd3, 0xeb, 0xda, 0xdb, 0x35, 0x74, 0x19, 0xf9, 0x51, 0xd5, + 0x82, 0x67, 0x3c, 0x17, 0xe8, 0xd8, 0x75, 0xdb, 0xc3, 0x9d, 0x76, 0xcd, 0xde, 0xa6, 0x61, 0x67, + 0x0b, 0xba, 0x98, 0x18, 0xe6, 0x32, 0x2e, 0x23, 0x92, 0x2b, 0xcf, 0xe7, 0x62, 0x89, 0xda, 0x02, + 0xd0, 0x82, 0xcf, 0x5a, 0xa8, 0x8b, 0x76, 0x91, 0xe7, 0xec, 0x93, 0xdb, 0x25, 0x0a, 0xfa, 0x80, + 0x37, 0x6c, 0x80, 0x96, 0x9f, 0xac, 0x33, 0xe9, 0x2d, 0x08, 0x92, 0x3b, 0xd4, 0x64, 0x5d, 0x86, + 0xe2, 0x44, 0x6e, 0xcf, 0x52, 0xb1, 0x35, 0xf3, 0x72, 0x15, 0x64, 0xc9, 0xe0, 0xf9, 0xe6, 0x8c, + 0xb0, 0xc2, 0xb4, 0x8b, 0x5c, 0xd7, 0xd8, 0x46, 0xfe, 0x0a, 0x13, 0x7b, 0xd4, 0x6e, 0x07, 0xb9, + 0x2e, 0xc1, 0x94, 0x0e, 0x0e, 0x0f, 0x13, 0x6a, 0x86, 0x0d, 0x0c, 0x4c, 0x2b, 0x18, 0x09, 0x08, + 0xdc, 0x3a, 0xfd, 0xe2, 0xec, 0xdd, 0x20, 0x47, 0xe1, 0x9f, 0x06, 0xb9, 0xa5, 0xca, 0xe2, 0xc6, + 0x4a, 0xf1, 0x18, 0xfe, 0xeb, 0xf3, 0x37, 0x0d, 0x72, 0xcb, 0xa5, 0x56, 0xa9, 0x56, 0x54, 0x70, + 0x3d, 0xaa, 0xf5, 0xe5, 0x46, 0x51, 0xc5, 0x89, 0xeb, 0xa5, 0x7a, 0xb5, 0x5c, 0xcc, 0x6a, 0x33, + 0x60, 0xea, 0x7c, 0x49, 0xaf, 0x57, 0xeb, 0x2b, 0xc5, 0x1c, 0xfc, 0x2b, 0x1e, 0xbf, 0x3b, 0x44, + 0xfc, 0x6e, 0x88, 0xe2, 0x69, 0x10, 0x64, 0xbf, 0x18, 0x40, 0xf6, 0x24, 0x01, 0xb2, 0x1f, 0x90, + 0x21, 0x32, 0x01, 0x77, 0xa6, 0x3c, 0x98, 0x5a, 0x77, 0xec, 0x36, 0x72, 0x5d, 0xf8, 0x52, 0x05, + 0xe4, 0xcb, 0x86, 0xd5, 0x46, 0x5d, 0x78, 0x4d, 0x08, 0x15, 0x75, 0x15, 0xcd, 0xf8, 0xae, 0xa2, + 0xf0, 0x5b, 0x19, 0xd9, 0xde, 0x8f, 0xd1, 0x5d, 0xa0, 0x34, 0x23, 0xe4, 0x23, 0xd7, 0xcb, 0xc5, + 0x92, 0x9a, 0xc0, 0x0d, 0x3b, 0x0a, 0x98, 0x66, 0xab, 0x01, 0x17, 0x11, 0x3f, 0x0f, 0xff, 0x4e, + 0x46, 0x76, 0x72, 0xe8, 0xd7, 0x20, 0x20, 0x13, 0x21, 0x0f, 0xb9, 0x89, 0xe0, 0x30, 0x6a, 0x13, + 0xd8, 0x3c, 0x54, 0xc0, 0xcc, 0x86, 0xe5, 0x0e, 0x12, 0x8a, 0x7c, 0x38, 0x7e, 0xbf, 0x1a, 0x1c, + 0xa1, 0x43, 0x85, 0xe3, 0x1f, 0x4e, 0x2f, 0x7d, 0xc1, 0x7c, 0x27, 0x03, 0x4e, 0xae, 0x20, 0x0b, + 0x39, 0x66, 0x9b, 0xd6, 0xc0, 0x97, 0xc4, 0x93, 0x44, 0x49, 0x3c, 0x42, 0xe0, 0x7c, 0xd0, 0x17, + 0xa2, 0x04, 0x5e, 0x15, 0x48, 0xe0, 0x29, 0x82, 0x04, 0x6e, 0x91, 0xa4, 0x33, 0x81, 0x6b, 0xd5, + 0xa7, 0xc1, 0x6c, 0xdd, 0xf6, 0xcc, 0x2d, 0xb3, 0x4d, 0x7d, 0xd0, 0x7e, 0x41, 0x05, 0xd9, 0x9a, + 0xe9, 0x7a, 0xb0, 0x14, 0x76, 0x27, 0xd7, 0x83, 0x19, 0xd3, 0x6a, 0x77, 0xf7, 0x3a, 0x48, 0x47, + 0x06, 0xed, 0x57, 0x0a, 0x3a, 0x9f, 0x14, 0x6e, 0xed, 0x63, 0xb6, 0x54, 0x7f, 0x6b, 0xff, 0xf7, + 0xa4, 0x97, 0x61, 0x78, 0x16, 0x48, 0x5c, 0xca, 0x08, 0xbb, 0xab, 0x04, 0xe6, 0x2c, 0x2e, 0xab, + 0x6f, 0xb0, 0xf7, 0xdf, 0x4b, 0xc0, 0x93, 0xd3, 0xc5, 0x2f, 0xe0, 0x07, 0xa4, 0x1a, 0xeb, 0x30, + 0x86, 0x92, 0x21, 0xb3, 0x3c, 0xc2, 0x24, 0x59, 0x03, 0xf3, 0xd5, 0x7a, 0xab, 0xa2, 0xd7, 0x4b, + 0x35, 0x96, 0x45, 0x85, 0xff, 0xaa, 0x80, 0x9c, 0x8e, 0x7a, 0xdd, 0x7d, 0x3e, 0xf0, 0x34, 0x73, + 0x14, 0xcf, 0x04, 0x8e, 0xe2, 0xda, 0x32, 0x00, 0x46, 0x1b, 0x17, 0x4c, 0x6e, 0xe6, 0x52, 0x06, + 0x86, 0x33, 0x15, 0x2a, 0x58, 0x0a, 0x72, 0xeb, 0xdc, 0x97, 0xf0, 0x85, 0xd2, 0x3b, 0x47, 0x02, + 0x35, 0xc2, 0x61, 0x44, 0x9f, 0xf0, 0x41, 0xa9, 0xcd, 0x9e, 0xa1, 0xe4, 0x8e, 0x46, 0xfc, 0x5f, + 0x55, 0x40, 0xb6, 0x85, 0x7b, 0x4b, 0xae, 0xe3, 0xfc, 0x9d, 0xd1, 0x74, 0x1c, 0x93, 0x89, 0xd0, + 0xf1, 0xbb, 0xc0, 0x2c, 0xaf, 0xb1, 0xcc, 0x55, 0x22, 0x56, 0xc5, 0x85, 0x0f, 0x46, 0xd1, 0xf0, + 0x01, 0xec, 0x1c, 0x8d, 0x88, 0x3f, 0xfd, 0x48, 0x00, 0xd6, 0xd0, 0xee, 0x45, 0xe4, 0xb8, 0x3b, + 0x66, 0x0f, 0xfe, 0xb5, 0x0a, 0xa6, 0x57, 0x90, 0xd7, 0xf4, 0x0c, 0x6f, 0xcf, 0xed, 0xdb, 0xee, + 0xb4, 0xec, 0xb2, 0xd1, 0xde, 0x41, 0xac, 0x3b, 0xf2, 0x1f, 0xe1, 0x7b, 0x54, 0x59, 0x7f, 0xa2, + 0xb0, 0x9c, 0x85, 0xa0, 0x8c, 0x08, 0x4c, 0x1e, 0x05, 0xb2, 0x1d, 0xc3, 0x33, 0x18, 0x16, 0xd7, + 0xf4, 0x61, 0x11, 0x12, 0xd2, 0x49, 0x36, 0xf8, 0x0e, 0x45, 0xc6, 0xa1, 0x48, 0xa2, 0xfc, 0x64, + 0x20, 0x7c, 0x20, 0x33, 0x02, 0x0a, 0x27, 0xc0, 0x5c, 0xbd, 0xd1, 0xda, 0xac, 0x35, 0x56, 0x56, + 0x2a, 0x38, 0xb5, 0xa8, 0x6a, 0xa7, 0x80, 0xb6, 0x5e, 0xba, 0xb0, 0x56, 0xa9, 0xb7, 0x36, 0xeb, + 0x8d, 0xa5, 0x0a, 0xfb, 0x32, 0xab, 0x1d, 0x07, 0x33, 0xe5, 0x52, 0x79, 0xd5, 0x4f, 0xc8, 0x69, + 0xa7, 0xc1, 0xc9, 0xb5, 0xca, 0xda, 0x62, 0x45, 0x6f, 0xae, 0x56, 0xd7, 0x37, 0x31, 0x99, 0xe5, + 0xc6, 0x46, 0x7d, 0xa9, 0x98, 0xd7, 0x20, 0x38, 0xc5, 0xbd, 0x39, 0xaf, 0x37, 0xea, 0x2b, 0x9b, + 0xcd, 0x56, 0xa9, 0x55, 0x29, 0x4e, 0x69, 0x57, 0x81, 0xe3, 0xe5, 0x52, 0x9d, 0x64, 0x2f, 0x37, + 0xea, 0xf5, 0x4a, 0xb9, 0x55, 0x2c, 0xc0, 0x7f, 0xcf, 0x82, 0x99, 0xaa, 0x5b, 0x37, 0x76, 0xd1, + 0x39, 0xa3, 0x6b, 0x76, 0xe0, 0x0b, 0xb8, 0x99, 0xc7, 0x0d, 0x60, 0xce, 0xa1, 0x7f, 0x51, 0xa7, + 0x65, 0x22, 0x8a, 0xe6, 0x9c, 0x2e, 0x26, 0xe2, 0x39, 0xb9, 0x45, 0x08, 0xf8, 0x73, 0x72, 0xfa, + 0xa4, 0x2d, 0x02, 0x40, 0xff, 0xb5, 0xc2, 0x3b, 0x62, 0xcf, 0xf6, 0xb7, 0x26, 0x63, 0x17, 0xb9, + 0xc8, 0xb9, 0x6c, 0xb6, 0x91, 0x9f, 0x53, 0xe7, 0xbe, 0x82, 0x5f, 0x53, 0x65, 0xf7, 0x17, 0x39, + 0x50, 0xb9, 0xea, 0x44, 0xf4, 0x86, 0x3f, 0xae, 0xca, 0xec, 0x0e, 0x4a, 0x91, 0x4c, 0xa6, 0x29, + 0x2f, 0x56, 0x46, 0x5b, 0xb6, 0x6d, 0x35, 0x1a, 0x9b, 0xcd, 0xd5, 0x86, 0xde, 0x2a, 0xaa, 0xda, + 0x2c, 0x28, 0xe0, 0xc7, 0x5a, 0xa3, 0xbe, 0x52, 0xcc, 0x6a, 0x57, 0x83, 0x13, 0xab, 0xa5, 0xe6, + 0x66, 0xb5, 0x7e, 0xae, 0x54, 0xab, 0x2e, 0x6d, 0x96, 0x57, 0x4b, 0x7a, 0xb3, 0x98, 0xd3, 0xae, + 0x01, 0x57, 0xb7, 0xaa, 0x15, 0x7d, 0x73, 0xb9, 0x52, 0x6a, 0x6d, 0xe8, 0x95, 0xe6, 0x66, 0xbd, + 0xb1, 0x59, 0x2f, 0xad, 0x55, 0x8a, 0x79, 0xdc, 0xfc, 0xc9, 0xab, 0x50, 0x6d, 0xa6, 0x0e, 0x2a, + 0x63, 0x21, 0x42, 0x19, 0xa7, 0xfb, 0x95, 0x11, 0xf0, 0x6a, 0xa5, 0x57, 0x9a, 0x15, 0xfd, 0x5c, + 0xa5, 0x38, 0x33, 0x48, 0xd7, 0x66, 0xb5, 0x93, 0xa0, 0x88, 0x79, 0xd8, 0xac, 0x36, 0xfd, 0x9c, + 0x4b, 0xc5, 0x39, 0xf8, 0xa9, 0x3c, 0x38, 0xa5, 0xa3, 0x6d, 0xd3, 0xf5, 0x90, 0xb3, 0x6e, 0xec, + 0xef, 0x22, 0xcb, 0xf3, 0x3b, 0xf9, 0x7f, 0x4a, 0xac, 0x8c, 0x6b, 0x60, 0xae, 0x47, 0x69, 0xac, + 0x21, 0x6f, 0xc7, 0xee, 0xb0, 0x51, 0xf8, 0x11, 0x91, 0x3d, 0xc7, 0xc2, 0x3a, 0x9f, 0x5d, 0x17, + 0xbf, 0xe6, 0x74, 0x5b, 0x8d, 0xd1, 0xed, 0xec, 0x28, 0xba, 0xad, 0x5d, 0x07, 0xa6, 0xf7, 0x5c, + 0xe4, 0x54, 0x76, 0x0d, 0xb3, 0xeb, 0xdf, 0xf1, 0x19, 0x24, 0xc0, 0x77, 0x66, 0x65, 0x4f, 0xac, + 0x70, 0x75, 0x19, 0x2c, 0xc6, 0x88, 0xbe, 0xf5, 0x0c, 0x00, 0xac, 0xb2, 0x1b, 0x4e, 0x97, 0x29, + 0x2b, 0x97, 0x82, 0xf9, 0xbb, 0x68, 0x76, 0xbb, 0xa6, 0xb5, 0x1d, 0xec, 0xfb, 0x87, 0x09, 0xf0, + 0xc5, 0xaa, 0xcc, 0x09, 0x96, 0xa4, 0xbc, 0x25, 0x6b, 0x4d, 0x2f, 0x54, 0x26, 0xdc, 0xef, 0x1e, + 0x6c, 0x3a, 0x79, 0xad, 0x08, 0x66, 0x49, 0x1a, 0x6b, 0x81, 0xc5, 0x29, 0xdc, 0x07, 0xfb, 0xe4, + 0xd6, 0x2a, 0xad, 0xd5, 0xc6, 0x52, 0xf0, 0xae, 0x80, 0x49, 0x62, 0x66, 0x4a, 0xf5, 0x0b, 0xa4, + 0x35, 0x4e, 0x6b, 0x0f, 0x06, 0xd7, 0x70, 0x1d, 0x76, 0xa9, 0xa6, 0x57, 0x4a, 0x4b, 0x17, 0x36, + 0x2b, 0x4f, 0xab, 0x36, 0x5b, 0x4d, 0xb1, 0x71, 0xf9, 0xed, 0x68, 0x06, 0xf3, 0x5b, 0x59, 0x2b, + 0x55, 0x6b, 0xac, 0x7f, 0x5f, 0x6e, 0xe8, 0x6b, 0xa5, 0x56, 0x71, 0x16, 0xbe, 0x5c, 0x05, 0xc5, + 0x15, 0xe4, 0xad, 0xdb, 0x8e, 0x67, 0x74, 0x6b, 0xa6, 0x75, 0x69, 0xc3, 0xe9, 0x0a, 0x93, 0x4d, + 0xe9, 0x30, 0x1d, 0xe2, 0x10, 0x29, 0x10, 0x8c, 0xde, 0x11, 0xef, 0x91, 0x6c, 0xa1, 0x32, 0x85, + 0x09, 0xf0, 0x59, 0x8a, 0xcc, 0x72, 0xb7, 0x7c, 0xa9, 0xc9, 0xf4, 0xe4, 0xd9, 0x93, 0x1e, 0x9f, + 0x07, 0xa0, 0x96, 0x87, 0xf7, 0x67, 0x41, 0x61, 0xd9, 0xb4, 0x8c, 0xae, 0xf9, 0x4c, 0x21, 0x3a, + 0x66, 0xd8, 0xc7, 0x64, 0x62, 0xfa, 0x18, 0x65, 0xa4, 0xf1, 0xf3, 0x67, 0x55, 0xd9, 0xe5, 0x05, + 0x4e, 0xf6, 0x3e, 0x93, 0x11, 0x83, 0xe7, 0xc7, 0x14, 0x99, 0xe5, 0x85, 0xe1, 0xf4, 0x92, 0x61, + 0xf8, 0x99, 0xef, 0x0f, 0x1b, 0xab, 0xaf, 0x7d, 0x17, 0x06, 0xa9, 0xc2, 0x34, 0xfc, 0x23, 0x15, + 0xc0, 0x15, 0xe4, 0x9d, 0x43, 0x4e, 0x30, 0x15, 0x20, 0xbd, 0x3e, 0xb3, 0xb7, 0xb9, 0x26, 0xfb, + 0x66, 0x1e, 0xc0, 0xf3, 0x22, 0x80, 0xa5, 0x98, 0xc6, 0x13, 0x41, 0x3a, 0xa2, 0xf1, 0x56, 0x41, + 0xde, 0x25, 0xef, 0x99, 0x9a, 0x3d, 0x26, 0x7a, 0xb8, 0x24, 0xc4, 0x78, 0xea, 0x94, 0xb0, 0xce, + 0x08, 0xc0, 0xef, 0x06, 0x93, 0xa0, 0x1f, 0x16, 0xb4, 0x63, 0xf9, 0xd0, 0xcc, 0x26, 0xd3, 0x17, + 0x27, 0x5d, 0x75, 0x19, 0x64, 0xdf, 0xc0, 0x8f, 0xe5, 0xc0, 0xc9, 0x41, 0xd5, 0x81, 0x1f, 0xca, + 0x08, 0x3b, 0xec, 0x88, 0x0c, 0xf9, 0x19, 0xb6, 0x81, 0x88, 0x1f, 0xb4, 0xc7, 0x81, 0xab, 0x83, + 0x65, 0xb8, 0x96, 0x5d, 0x47, 0x57, 0xdc, 0x2e, 0xf2, 0x3c, 0xe4, 0x90, 0xaa, 0x15, 0xf4, 0xc1, + 0x2f, 0xb5, 0x27, 0x80, 0x07, 0x99, 0x96, 0x6b, 0x76, 0x90, 0xd3, 0x32, 0x7b, 0x6e, 0xc9, 0xea, + 0xb4, 0xf6, 0x3c, 0xdb, 0x31, 0x0d, 0x76, 0x23, 0x65, 0x41, 0x8f, 0x7a, 0xad, 0xdd, 0x0c, 0x8a, + 0xa6, 0xdb, 0xb0, 0x2e, 0xda, 0x86, 0xd3, 0x31, 0xad, 0xed, 0x9a, 0xe9, 0x7a, 0xcc, 0x03, 0xf8, + 0x40, 0x3a, 0xfc, 0x1b, 0x55, 0xf6, 0x30, 0xdd, 0x10, 0x58, 0x23, 0x3a, 0x94, 0xe7, 0xab, 0x32, + 0xc7, 0xe3, 0x92, 0xd1, 0x4e, 0xa6, 0x2c, 0xcf, 0x9b, 0xb4, 0x21, 0x31, 0x78, 0x04, 0x27, 0x5d, + 0x0b, 0x4d, 0xf7, 0x0d, 0x81, 0x73, 0x15, 0xbd, 0xba, 0x5c, 0xad, 0x60, 0xb3, 0xe2, 0x6a, 0x70, + 0x22, 0x7c, 0xb7, 0x74, 0x61, 0xb3, 0x59, 0xa9, 0xb7, 0x8a, 0x05, 0xdc, 0x4f, 0xd1, 0xe4, 0xe5, + 0x52, 0xb5, 0x56, 0x59, 0xda, 0x6c, 0x35, 0xf0, 0x9b, 0xa5, 0xd1, 0x4c, 0x0b, 0xf8, 0x9c, 0x2c, + 0x38, 0x4e, 0x64, 0xbb, 0x4f, 0xa4, 0x8a, 0x85, 0xd2, 0xe7, 0x6b, 0x1b, 0x00, 0x34, 0x4d, 0xc5, + 0x0b, 0xff, 0x50, 0xfa, 0xc2, 0x4d, 0x0e, 0xc2, 0xbe, 0x32, 0x22, 0x34, 0xe3, 0x3b, 0x8a, 0x4c, + 0x84, 0x0a, 0x69, 0xb2, 0xc9, 0x94, 0xe2, 0x9f, 0x27, 0x3d, 0xe2, 0x44, 0x83, 0x4f, 0xac, 0xcc, + 0x32, 0xf9, 0xf8, 0x69, 0xeb, 0x55, 0x9d, 0xa8, 0xc3, 0x3c, 0x00, 0x24, 0x85, 0x68, 0x10, 0xd5, + 0x83, 0x81, 0xe3, 0x55, 0x94, 0x1e, 0x94, 0xca, 0xad, 0xea, 0xb9, 0x4a, 0x94, 0x1e, 0x7c, 0x56, + 0x05, 0x85, 0x15, 0xe4, 0xe1, 0x39, 0x95, 0x0b, 0x9f, 0x28, 0xb1, 0xfe, 0x83, 0xcd, 0x98, 0xae, + 0xdd, 0x36, 0xba, 0xc1, 0x32, 0x00, 0x7d, 0x82, 0xcf, 0x1d, 0xc5, 0x04, 0xf1, 0x8b, 0x8e, 0x18, + 0xaf, 0x7e, 0x08, 0xe4, 0x3c, 0xfc, 0x9a, 0x2d, 0x43, 0x3f, 0x34, 0x72, 0xb8, 0xc2, 0x44, 0x96, + 0x0c, 0xcf, 0xd0, 0x69, 0x7e, 0x6e, 0x74, 0x92, 0xb4, 0x5d, 0x22, 0x18, 0xf9, 0x7e, 0xb4, 0x3f, + 0xff, 0x4a, 0x05, 0x57, 0xd3, 0xf6, 0x51, 0xea, 0xf5, 0x9a, 0x9e, 0xed, 0x20, 0x1d, 0xb5, 0x91, + 0xd9, 0xf3, 0xfa, 0xd6, 0xf7, 0x1c, 0x9a, 0xea, 0x6f, 0x36, 0xb3, 0x47, 0xf8, 0x06, 0x55, 0x36, + 0xc2, 0xef, 0x81, 0xf6, 0xd8, 0x57, 0x5e, 0x44, 0x63, 0xff, 0xa4, 0x22, 0x13, 0xb3, 0x37, 0x21, + 0xf1, 0x64, 0x40, 0x7d, 0xfc, 0x08, 0x80, 0xf2, 0x57, 0x6e, 0xf4, 0x4a, 0xb9, 0x52, 0x5d, 0xc7, + 0x83, 0xc0, 0x43, 0xc0, 0xb5, 0xeb, 0x1b, 0x7a, 0x79, 0xb5, 0xd4, 0xac, 0x6c, 0xea, 0x95, 0x95, + 0x6a, 0xb3, 0xc5, 0x9c, 0xb2, 0xe8, 0x57, 0x53, 0xda, 0x75, 0xe0, 0x74, 0x73, 0x63, 0xb1, 0x59, + 0xd6, 0xab, 0xeb, 0x24, 0x5d, 0xaf, 0xd4, 0x2b, 0xe7, 0xd9, 0xdb, 0x02, 0xfc, 0x48, 0x11, 0xcc, + 0xe0, 0x09, 0x40, 0x93, 0xce, 0x0b, 0xe0, 0x37, 0xb3, 0x60, 0x46, 0x47, 0xae, 0xdd, 0xbd, 0x4c, + 0xe6, 0x08, 0x93, 0x9a, 0x7a, 0x7c, 0x5b, 0x95, 0x3d, 0xbf, 0xcd, 0x31, 0xbb, 0xc0, 0x31, 0x1a, + 0x3d, 0xd1, 0x34, 0x2e, 0x1b, 0x66, 0xd7, 0xb8, 0xc8, 0xba, 0x9a, 0x82, 0x1e, 0x26, 0x68, 0x0b, + 0x40, 0xb3, 0xaf, 0x58, 0xc8, 0x69, 0xb6, 0xaf, 0x54, 0xbc, 0x9d, 0x52, 0xa7, 0xe3, 0x20, 0xd7, + 0x65, 0xab, 0x17, 0x03, 0xde, 0x68, 0x37, 0x81, 0xe3, 0x24, 0x95, 0xcb, 0x4c, 0x1d, 0x64, 0xfa, + 0x93, 0x83, 0x9c, 0x25, 0x6b, 0xdf, 0xcf, 0x99, 0xe3, 0x72, 0x86, 0xc9, 0xfc, 0x71, 0x89, 0xbc, + 0x78, 0x4a, 0xe7, 0x7a, 0x30, 0x63, 0x19, 0xbb, 0xa8, 0x72, 0x5f, 0xcf, 0x74, 0x90, 0x4b, 0x1c, + 0x63, 0x54, 0x9d, 0x4f, 0x82, 0x1f, 0x93, 0x3a, 0x6f, 0x2e, 0x27, 0xb1, 0x64, 0xba, 0xbf, 0x32, + 0x82, 0xea, 0x0f, 0xe8, 0x67, 0x54, 0xf8, 0x11, 0x15, 0xcc, 0x32, 0xa6, 0x4a, 0xd6, 0x7e, 0xb5, + 0x03, 0x1f, 0x22, 0x18, 0xbf, 0x06, 0x4e, 0xf3, 0x8d, 0x5f, 0xf2, 0x00, 0x7f, 0x42, 0x95, 0x75, + 0x77, 0x1e, 0x50, 0x71, 0x52, 0x46, 0xb4, 0xe3, 0xe8, 0x96, 0xbd, 0xc7, 0x1c, 0x55, 0x0b, 0x3a, + 0x7d, 0x48, 0x73, 0x51, 0x0f, 0xfe, 0xba, 0x94, 0x33, 0xb5, 0x64, 0x35, 0x8e, 0x08, 0xc0, 0x4f, + 0xab, 0x60, 0x9e, 0x71, 0xd5, 0x64, 0xe7, 0x7c, 0xa4, 0x0e, 0xbc, 0xfd, 0x94, 0xb4, 0x21, 0x38, + 0xa0, 0xfe, 0xac, 0xa4, 0x07, 0x0c, 0x90, 0xbf, 0x21, 0x15, 0x1c, 0x4d, 0xba, 0x22, 0x47, 0x04, + 0xe5, 0xbb, 0xb2, 0x60, 0x66, 0xc3, 0x45, 0x0e, 0xf3, 0xdb, 0x87, 0xaf, 0xcd, 0x02, 0x75, 0x05, + 0x09, 0x1b, 0xa9, 0x2f, 0x92, 0xf6, 0xf0, 0xe5, 0x2b, 0xcb, 0x11, 0xc5, 0x36, 0x52, 0x04, 0x6c, + 0x37, 0x82, 0x79, 0x2a, 0xd2, 0x92, 0xe7, 0x61, 0x23, 0xd1, 0xf7, 0xa6, 0xed, 0x4b, 0x1d, 0xc7, + 0x56, 0x11, 0x29, 0x0b, 0x67, 0x29, 0x63, 0x9e, 0x6a, 0x68, 0x8b, 0xce, 0x67, 0xb3, 0x7a, 0x5f, + 0xaa, 0xf6, 0x68, 0x70, 0x95, 0xdd, 0x43, 0xf4, 0xfc, 0x0a, 0x97, 0x39, 0x47, 0x32, 0x0f, 0x7a, + 0x05, 0xbf, 0x29, 0xe5, 0xab, 0x2b, 0x2f, 0x9d, 0x64, 0xba, 0xd0, 0x1b, 0x8f, 0x49, 0x72, 0x12, + 0x14, 0x71, 0x0e, 0xb2, 0xff, 0xa2, 0x57, 0x9a, 0x8d, 0xda, 0xb9, 0xca, 0xe0, 0x65, 0x8c, 0x1c, + 0x7c, 0x9e, 0x0a, 0xa6, 0x17, 0x1d, 0xdb, 0xe8, 0xb4, 0x0d, 0xd7, 0x83, 0xdf, 0x55, 0xc0, 0xec, + 0xba, 0xb1, 0xdf, 0xb5, 0x8d, 0x0e, 0xf1, 0xef, 0xef, 0xeb, 0x0b, 0x7a, 0xf4, 0x95, 0xdf, 0x17, + 0xb0, 0x47, 0xf1, 0x60, 0x60, 0x70, 0x74, 0x2f, 0x23, 0x73, 0xaf, 0x66, 0xb0, 0xcd, 0xa7, 0x0c, + 0x0a, 0x56, 0xea, 0xf3, 0xb5, 0xc0, 0xf3, 0x14, 0x61, 0x51, 0x7e, 0x44, 0x2e, 0xfc, 0xa8, 0x0c, + 0xc9, 0xa3, 0xd9, 0x95, 0xbf, 0xbf, 0x00, 0xf2, 0x4b, 0x88, 0x58, 0x71, 0xbf, 0xaa, 0x80, 0xa9, + 0x26, 0xf2, 0x88, 0x05, 0x77, 0xbb, 0xe0, 0x29, 0xdc, 0x21, 0x19, 0x42, 0x27, 0x76, 0xff, 0x19, + 0x4f, 0xd6, 0xb9, 0xf3, 0xd6, 0xe4, 0x7f, 0x02, 0x8f, 0x44, 0x5a, 0xee, 0x02, 0x2b, 0xf3, 0x50, + 0x1e, 0x89, 0xb1, 0xa4, 0xd2, 0xf7, 0xb5, 0x7a, 0x8f, 0xc2, 0x5c, 0xab, 0xb8, 0x5e, 0xef, 0xd5, + 0xbc, 0x7e, 0xc6, 0x7a, 0x9b, 0x31, 0xe6, 0x63, 0x9c, 0xa3, 0x1e, 0x0b, 0xa6, 0xa8, 0xcc, 0xfd, + 0xf9, 0x68, 0xbf, 0x9f, 0x02, 0x25, 0x41, 0xce, 0x5e, 0xfb, 0x39, 0x25, 0x5d, 0xd4, 0xa2, 0x0b, + 0x9f, 0x48, 0x0c, 0x82, 0xd9, 0x3a, 0xf2, 0xae, 0xd8, 0xce, 0xa5, 0xa6, 0x67, 0x78, 0x08, 0xfe, + 0xb3, 0x42, 0xaf, 0xcb, 0xe3, 0xa2, 0x9f, 0xd4, 0xc1, 0x09, 0x5a, 0x21, 0x96, 0x91, 0xf4, 0xdf, + 0xb4, 0x22, 0xd7, 0x0f, 0x14, 0x02, 0x97, 0x4f, 0x3f, 0xf8, 0x29, 0x7c, 0xe9, 0xc0, 0xa0, 0x4f, + 0xca, 0x80, 0x49, 0x03, 0x93, 0x0c, 0xcf, 0x60, 0xf4, 0xfd, 0x78, 0xf0, 0xa3, 0x52, 0x66, 0xb5, + 0x1c, 0xcd, 0xa3, 0xe9, 0x0a, 0x3e, 0xf1, 0x28, 0x90, 0x2d, 0xef, 0x18, 0x1e, 0x7c, 0xb7, 0x0a, + 0x40, 0xa9, 0xd3, 0x59, 0xa3, 0x3e, 0xe0, 0xbc, 0x43, 0xda, 0x59, 0x30, 0xdb, 0xde, 0x31, 0xc2, + 0x9b, 0x33, 0x68, 0x7f, 0x20, 0xa4, 0x69, 0x8f, 0x0b, 0x9d, 0xc9, 0xa9, 0x54, 0x61, 0x1f, 0x4c, + 0xb8, 0x0c, 0x46, 0x3b, 0x70, 0x34, 0x17, 0x43, 0x61, 0xc6, 0x1e, 0xa1, 0xc3, 0x9f, 0x2f, 0x84, + 0xec, 0x45, 0xcf, 0xe1, 0x18, 0xe9, 0xe0, 0x80, 0x4d, 0x98, 0x90, 0xf0, 0xa4, 0xb7, 0x5c, 0x40, + 0x8f, 0x78, 0xbe, 0x26, 0x12, 0xba, 0x56, 0xab, 0x74, 0x4c, 0x5f, 0xb4, 0x2c, 0x60, 0x16, 0x7c, + 0x61, 0x26, 0x19, 0x7c, 0xf1, 0x82, 0x7b, 0x0a, 0x98, 0x43, 0x1d, 0xd3, 0x43, 0x7e, 0x2d, 0x99, + 0x00, 0xe3, 0x20, 0x16, 0x3f, 0x80, 0xcf, 0x96, 0x0e, 0xba, 0x46, 0x04, 0x7a, 0xb0, 0x46, 0x11, + 0xed, 0x4f, 0x2e, 0x8c, 0x9a, 0x1c, 0xcd, 0xf4, 0xc1, 0x7a, 0xae, 0x0a, 0xae, 0x6e, 0xd9, 0xdb, + 0xdb, 0x5d, 0xe4, 0x8b, 0x09, 0x51, 0xef, 0x4c, 0x68, 0x8c, 0x13, 0x2e, 0xb2, 0x13, 0x64, 0xdf, + 0x6b, 0x06, 0x47, 0xc9, 0xf0, 0x83, 0x78, 0x62, 0x2a, 0x76, 0x16, 0x45, 0xc4, 0x35, 0x90, 0xcf, + 0x08, 0x14, 0xe4, 0x02, 0x3e, 0x4b, 0x93, 0x4d, 0x1f, 0x88, 0x2f, 0x28, 0x60, 0x8e, 0xde, 0x8b, + 0xe8, 0x2b, 0xe8, 0x3d, 0x63, 0x04, 0x00, 0x7e, 0x37, 0x23, 0xeb, 0x67, 0x4b, 0x64, 0x22, 0x70, + 0x12, 0x21, 0x62, 0xb9, 0xa0, 0x2a, 0x43, 0xc9, 0x4d, 0xe0, 0xa6, 0xce, 0x2c, 0x98, 0x59, 0x41, + 0x7e, 0x4b, 0x73, 0xe1, 0xfb, 0x13, 0xf6, 0x44, 0x67, 0xc1, 0x2c, 0xb9, 0x1c, 0xac, 0xc1, 0x8e, + 0x49, 0xd2, 0x55, 0x33, 0x21, 0x4d, 0xbb, 0x01, 0xcc, 0x5d, 0x44, 0x5b, 0xb6, 0x83, 0x1a, 0xc2, + 0x59, 0x4a, 0x31, 0x71, 0x70, 0x78, 0x3a, 0xed, 0x26, 0x70, 0x9c, 0x39, 0xba, 0x2f, 0xe2, 0xb9, + 0xbe, 0xe1, 0xec, 0xb3, 0x83, 0x69, 0xfd, 0xc9, 0xf0, 0xaf, 0xf8, 0x06, 0xb3, 0x28, 0xa2, 0x78, + 0xcb, 0x41, 0xb1, 0x73, 0x95, 0x8e, 0x18, 0x9d, 0x1e, 0x0f, 0x0a, 0x4c, 0x47, 0x7c, 0x83, 0x2e, + 0xae, 0x07, 0x0d, 0xf2, 0x6a, 0x8f, 0x07, 0xd3, 0x58, 0x44, 0xc4, 0x6e, 0x60, 0x5d, 0xef, 0xe9, + 0x01, 0x1f, 0x92, 0xf7, 0x7a, 0x98, 0x15, 0xfe, 0x52, 0xa0, 0x33, 0x15, 0x41, 0x67, 0x1e, 0x93, + 0x84, 0xf9, 0x89, 0x5c, 0x24, 0x5f, 0xe4, 0xca, 0x5f, 0xdc, 0xaf, 0x76, 0x5c, 0xb8, 0x96, 0x4c, + 0x6b, 0xce, 0x00, 0x10, 0x34, 0x3f, 0x3f, 0x70, 0x06, 0x97, 0x22, 0xc6, 0xc6, 0x8f, 0x3d, 0x0a, + 0xd8, 0x2f, 0x0e, 0xc2, 0xce, 0x78, 0x01, 0x95, 0x3c, 0x42, 0x28, 0xc3, 0x49, 0xfa, 0xe8, 0xfc, + 0x62, 0x16, 0x5c, 0x1d, 0x9c, 0x70, 0xaa, 0x19, 0x6e, 0xd8, 0xb2, 0x2f, 0x24, 0x83, 0x48, 0x38, + 0x52, 0x12, 0x34, 0xc7, 0x93, 0x20, 0xe7, 0xee, 0x5d, 0x0c, 0x1c, 0x01, 0xe9, 0x03, 0x7c, 0xa3, + 0x9a, 0x68, 0xac, 0x1a, 0xc8, 0xdf, 0x98, 0x1b, 0xe1, 0x2d, 0xe0, 0x84, 0xb5, 0xb7, 0x1b, 0x60, + 0x41, 0x7a, 0x1a, 0xd6, 0xb3, 0x1c, 0x7c, 0x21, 0x36, 0xd9, 0xac, 0x7c, 0x93, 0x4d, 0x30, 0x92, + 0xca, 0x54, 0x3a, 0x7d, 0xf5, 0xf8, 0x4c, 0xdf, 0x11, 0xb4, 0x72, 0x62, 0xa5, 0xa0, 0xf0, 0x2b, + 0x3c, 0xfc, 0xff, 0x98, 0x49, 0xd4, 0xf3, 0x0e, 0x3f, 0xb9, 0x96, 0xa0, 0x27, 0x3c, 0xca, 0x63, + 0x6b, 0xaf, 0xcb, 0x01, 0xd8, 0x0c, 0x1d, 0x72, 0x18, 0xa8, 0xeb, 0x0e, 0xba, 0x6c, 0xa2, 0x2b, + 0x6e, 0xdf, 0x7e, 0x07, 0x95, 0x5b, 0x86, 0x97, 0xdb, 0x5f, 0x64, 0x65, 0x1d, 0x6a, 0x44, 0x0d, + 0x3a, 0x50, 0x54, 0x44, 0xdb, 0x79, 0x3a, 0x28, 0xf4, 0x58, 0x0e, 0xd6, 0x76, 0x4a, 0xa3, 0x51, + 0xc5, 0x19, 0x59, 0xaa, 0x1e, 0x90, 0x84, 0x7f, 0x9b, 0x01, 0x33, 0xdc, 0x9b, 0xe8, 0x1d, 0x81, + 0x03, 0xaa, 0xa5, 0xc4, 0xcf, 0x48, 0x55, 0xe9, 0x19, 0xa9, 0xb6, 0x00, 0x72, 0xae, 0x54, 0xa3, + 0xa5, 0xd9, 0xb4, 0x27, 0x82, 0xd9, 0x0e, 0xea, 0x21, 0xab, 0x83, 0xac, 0xb6, 0x89, 0xdc, 0xd3, + 0x39, 0x22, 0x96, 0xc8, 0x30, 0x0d, 0x42, 0x66, 0xc9, 0xf8, 0xdd, 0xc9, 0xb0, 0x4a, 0x5f, 0x4b, + 0xff, 0x4c, 0x01, 0x67, 0xb8, 0x56, 0xb2, 0xec, 0xd8, 0xbb, 0x89, 0x35, 0xf5, 0xe5, 0xfc, 0x78, + 0xbc, 0x21, 0x6a, 0xea, 0x5d, 0xb1, 0x8d, 0x72, 0x40, 0x71, 0x11, 0x8d, 0xfe, 0xfd, 0x81, 0x74, + 0x9f, 0x26, 0x48, 0x77, 0xe9, 0x90, 0xf4, 0x27, 0x70, 0x20, 0x3c, 0x0b, 0x66, 0x75, 0x64, 0x74, + 0x82, 0xa1, 0xf6, 0x4f, 0x38, 0x23, 0xfa, 0x89, 0x20, 0xeb, 0x85, 0xab, 0x61, 0x8f, 0x38, 0x58, + 0x19, 0xfe, 0x4b, 0xf2, 0x40, 0x16, 0xc5, 0xc8, 0x47, 0x52, 0x0d, 0xa7, 0xdf, 0x02, 0x57, 0x65, + 0x2c, 0xf0, 0xec, 0x20, 0x0b, 0xfc, 0x7a, 0x30, 0xd3, 0x35, 0x5c, 0xda, 0x60, 0x82, 0xbb, 0x7f, + 0xf9, 0x24, 0xf1, 0x96, 0xfd, 0xd8, 0xd3, 0x76, 0x83, 0xaa, 0x76, 0xf8, 0x88, 0xc4, 0x1f, 0x96, + 0x3a, 0x5a, 0x37, 0xac, 0xec, 0x64, 0x1a, 0x71, 0xf7, 0x08, 0x2b, 0x77, 0xa7, 0x80, 0xb6, 0x56, + 0x69, 0x36, 0x4b, 0x2b, 0xe4, 0xc4, 0x8d, 0xef, 0x82, 0xd5, 0x39, 0x7b, 0x23, 0x16, 0x1f, 0x45, + 0x58, 0x9b, 0x05, 0x05, 0x9f, 0xbf, 0xe2, 0x31, 0xfa, 0x64, 0x91, 0x1d, 0xa7, 0x62, 0x06, 0x7e, + 0x5e, 0x05, 0xf9, 0x0d, 0xcb, 0x41, 0x46, 0x07, 0xde, 0xcf, 0xe9, 0xd2, 0x0f, 0x0a, 0xba, 0xf4, + 0xd0, 0x41, 0x0d, 0x03, 0x7f, 0x93, 0x92, 0x16, 0x89, 0xe1, 0xc8, 0x62, 0x17, 0xcb, 0x45, 0x66, + 0x0e, 0x8f, 0xbb, 0xdc, 0x2a, 0x79, 0x74, 0xa9, 0xa9, 0xf7, 0x01, 0xd2, 0xc8, 0xfe, 0x98, 0x82, + 0xe1, 0x34, 0x3a, 0xa5, 0xae, 0x70, 0x24, 0xe3, 0x9b, 0xbc, 0x09, 0xf5, 0x64, 0x51, 0xb4, 0x37, + 0x0d, 0x56, 0xee, 0x52, 0x37, 0xca, 0x91, 0xf6, 0xd5, 0x81, 0xb4, 0x4a, 0x82, 0xb4, 0x1e, 0x25, + 0x4b, 0x28, 0xfd, 0x2e, 0xf3, 0x77, 0x55, 0x50, 0x5c, 0xdf, 0x73, 0x77, 0x84, 0xb3, 0xef, 0xbf, + 0xaa, 0x82, 0x39, 0xff, 0x78, 0x50, 0xcb, 0xbe, 0x84, 0x2c, 0xf8, 0x0c, 0x61, 0x60, 0xf2, 0x70, + 0x9a, 0x3f, 0x30, 0x91, 0x07, 0x6d, 0x9d, 0x8b, 0x90, 0xa3, 0x0c, 0x8a, 0x6e, 0xd0, 0x57, 0xc6, + 0x82, 0x40, 0x7f, 0x61, 0x9d, 0x7d, 0x1b, 0xc6, 0xd5, 0x81, 0x2f, 0x96, 0xbe, 0xee, 0x69, 0x08, + 0xed, 0xc1, 0xd8, 0xc8, 0x5d, 0xe0, 0x94, 0x88, 0x74, 0xfa, 0xca, 0x7d, 0x3d, 0x28, 0xf8, 0x92, + 0xd2, 0xa6, 0x80, 0x5a, 0x6d, 0x34, 0x8b, 0xc7, 0xb4, 0x19, 0x30, 0x55, 0xb2, 0x3a, 0x8e, 0x6d, + 0x76, 0x8a, 0x99, 0xb3, 0x53, 0x20, 0x57, 0xd9, 0xed, 0x79, 0xfb, 0x67, 0x1f, 0x0e, 0xe6, 0x9a, + 0x9e, 0x83, 0x8c, 0xdd, 0x58, 0xdc, 0xee, 0xb8, 0x1d, 0x4c, 0x59, 0xf6, 0xa6, 0xb1, 0xe7, 0xed, + 0x68, 0x0f, 0x39, 0x60, 0x7c, 0xb1, 0xc6, 0xd3, 0x60, 0x41, 0x49, 0xbf, 0x76, 0x27, 0x59, 0xf0, + 0xc9, 0x5b, 0x76, 0x69, 0xcf, 0xdb, 0x59, 0xbc, 0xee, 0xd3, 0x7f, 0x7e, 0x26, 0xf3, 0xd9, 0x3f, + 0x3f, 0x93, 0xf9, 0xea, 0x9f, 0x9f, 0xc9, 0xfc, 0xd4, 0x5f, 0x9c, 0x39, 0xf6, 0xd9, 0xbf, 0x38, + 0x73, 0xec, 0x0b, 0x7f, 0x71, 0xe6, 0xd8, 0x0f, 0x2b, 0xbd, 0x8b, 0x17, 0xf3, 0x84, 0xca, 0x63, + 0xff, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x87, 0x1a, 0x01, 0x1f, 0xa2, 0x3b, 0x02, 0x00, } func (m *Rpc) Marshal() (dAtA []byte, err error) { @@ -79274,6 +80397,134 @@ func (m *RpcSpaceMakeShareableResponseError) MarshalToSizedBuffer(dAtA []byte) ( return len(dAtA) - i, nil } +func (m *RpcSpaceInviteChange) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcSpaceInviteChange) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcSpaceInviteChange) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *RpcSpaceInviteChangeRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcSpaceInviteChangeRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcSpaceInviteChangeRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Permissions != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.Permissions)) + i-- + dAtA[i] = 0x10 + } + if len(m.SpaceId) > 0 { + i -= len(m.SpaceId) + copy(dAtA[i:], m.SpaceId) + i = encodeVarintCommands(dAtA, i, uint64(len(m.SpaceId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RpcSpaceInviteChangeResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcSpaceInviteChangeResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcSpaceInviteChangeResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Error != nil { + { + size, err := m.Error.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommands(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RpcSpaceInviteChangeResponseError) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcSpaceInviteChangeResponseError) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcSpaceInviteChangeResponseError) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintCommands(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if m.Code != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.Code)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *RpcSpaceInviteGenerate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -79317,6 +80568,11 @@ func (m *RpcSpaceInviteGenerateRequest) MarshalToSizedBuffer(dAtA []byte) (int, _ = i var l int _ = l + if m.Permissions != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.Permissions)) + i-- + dAtA[i] = 0x18 + } if m.InviteType != 0 { i = encodeVarintCommands(dAtA, i, uint64(m.InviteType)) i-- @@ -79352,6 +80608,16 @@ func (m *RpcSpaceInviteGenerateResponse) MarshalToSizedBuffer(dAtA []byte) (int, _ = i var l int _ = l + if m.Permissions != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.Permissions)) + i-- + dAtA[i] = 0x28 + } + if m.InviteType != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.InviteType)) + i-- + dAtA[i] = 0x20 + } if len(m.InviteFileKey) > 0 { i -= len(m.InviteFileKey) copy(dAtA[i:], m.InviteFileKey) @@ -79612,6 +80878,16 @@ func (m *RpcSpaceInviteGetCurrentResponse) MarshalToSizedBuffer(dAtA []byte) (in _ = i var l int _ = l + if m.Permissions != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.Permissions)) + i-- + dAtA[i] = 0x28 + } + if m.InviteType != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.InviteType)) + i-- + dAtA[i] = 0x20 + } if len(m.InviteFileKey) > 0 { i -= len(m.InviteFileKey) copy(dAtA[i:], m.InviteFileKey) @@ -80016,6 +81292,11 @@ func (m *RpcSpaceInviteViewResponse) MarshalToSizedBuffer(dAtA []byte) (int, err _ = i var l int _ = l + if m.InviteType != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.InviteType)) + i-- + dAtA[i] = 0x38 + } if m.IsGuestUserInvite { i-- if m.IsGuestUserInvite { @@ -84464,6 +85745,394 @@ func (m *RpcAccountLocalLinkSolveChallengeResponseError) MarshalToSizedBuffer(dA return len(dAtA) - i, nil } +func (m *RpcAccountLocalLinkListApps) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkListApps) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkListApps) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *RpcAccountLocalLinkListAppsRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkListAppsRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkListAppsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *RpcAccountLocalLinkListAppsResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkListAppsResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkListAppsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.App) > 0 { + for iNdEx := len(m.App) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.App[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommands(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } + } + if m.Error != nil { + { + size, err := m.Error.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommands(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RpcAccountLocalLinkListAppsResponseError) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkListAppsResponseError) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkListAppsResponseError) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintCommands(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if m.Code != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.Code)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *RpcAccountLocalLinkCreateApp) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkCreateApp) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkCreateApp) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *RpcAccountLocalLinkCreateAppRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkCreateAppRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkCreateAppRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.App != nil { + { + size, err := m.App.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommands(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RpcAccountLocalLinkCreateAppResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkCreateAppResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkCreateAppResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AppKey) > 0 { + i -= len(m.AppKey) + copy(dAtA[i:], m.AppKey) + i = encodeVarintCommands(dAtA, i, uint64(len(m.AppKey))) + i-- + dAtA[i] = 0x12 + } + if m.Error != nil { + { + size, err := m.Error.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommands(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RpcAccountLocalLinkCreateAppResponseError) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkCreateAppResponseError) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkCreateAppResponseError) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintCommands(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if m.Code != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.Code)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + +func (m *RpcAccountLocalLinkRevokeApp) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkRevokeApp) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkRevokeApp) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *RpcAccountLocalLinkRevokeAppRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkRevokeAppRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkRevokeAppRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.AppHash) > 0 { + i -= len(m.AppHash) + copy(dAtA[i:], m.AppHash) + i = encodeVarintCommands(dAtA, i, uint64(len(m.AppHash))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RpcAccountLocalLinkRevokeAppResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkRevokeAppResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkRevokeAppResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Error != nil { + { + size, err := m.Error.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommands(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RpcAccountLocalLinkRevokeAppResponseError) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcAccountLocalLinkRevokeAppResponseError) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcAccountLocalLinkRevokeAppResponseError) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintCommands(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if m.Code != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.Code)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *RpcWorkspace) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -126610,6 +128279,122 @@ func (m *RpcChatUnreadResponseError) MarshalToSizedBuffer(dAtA []byte) (int, err return len(dAtA) - i, nil } +func (m *RpcChatReadAll) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcChatReadAll) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcChatReadAll) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *RpcChatReadAllRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcChatReadAllRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcChatReadAllRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func (m *RpcChatReadAllResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcChatReadAllResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcChatReadAllResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.Error != nil { + { + size, err := m.Error.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintCommands(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *RpcChatReadAllResponseError) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RpcChatReadAllResponseError) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RpcChatReadAllResponseError) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintCommands(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if m.Code != 0 { + i = encodeVarintCommands(dAtA, i, uint64(m.Code)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *RpcPushNotification) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -127112,6 +128897,60 @@ func (m *RpcSpaceMakeShareableResponseError) Size() (n int) { return n } +func (m *RpcSpaceInviteChange) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *RpcSpaceInviteChangeRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.SpaceId) + if l > 0 { + n += 1 + l + sovCommands(uint64(l)) + } + if m.Permissions != 0 { + n += 1 + sovCommands(uint64(m.Permissions)) + } + return n +} + +func (m *RpcSpaceInviteChangeResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Error != nil { + l = m.Error.Size() + n += 1 + l + sovCommands(uint64(l)) + } + return n +} + +func (m *RpcSpaceInviteChangeResponseError) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Code != 0 { + n += 1 + sovCommands(uint64(m.Code)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovCommands(uint64(l)) + } + return n +} + func (m *RpcSpaceInviteGenerate) Size() (n int) { if m == nil { return 0 @@ -127134,6 +128973,9 @@ func (m *RpcSpaceInviteGenerateRequest) Size() (n int) { if m.InviteType != 0 { n += 1 + sovCommands(uint64(m.InviteType)) } + if m.Permissions != 0 { + n += 1 + sovCommands(uint64(m.Permissions)) + } return n } @@ -127155,6 +128997,12 @@ func (m *RpcSpaceInviteGenerateResponse) Size() (n int) { if l > 0 { n += 1 + l + sovCommands(uint64(l)) } + if m.InviteType != 0 { + n += 1 + sovCommands(uint64(m.InviteType)) + } + if m.Permissions != 0 { + n += 1 + sovCommands(uint64(m.Permissions)) + } return n } @@ -127265,6 +129113,12 @@ func (m *RpcSpaceInviteGetCurrentResponse) Size() (n int) { if l > 0 { n += 1 + l + sovCommands(uint64(l)) } + if m.InviteType != 0 { + n += 1 + sovCommands(uint64(m.InviteType)) + } + if m.Permissions != 0 { + n += 1 + sovCommands(uint64(m.Permissions)) + } return n } @@ -127449,6 +129303,9 @@ func (m *RpcSpaceInviteViewResponse) Size() (n int) { if m.IsGuestUserInvite { n += 2 } + if m.InviteType != 0 { + n += 1 + sovCommands(uint64(m.InviteType)) + } return n } @@ -129309,6 +131166,165 @@ func (m *RpcAccountLocalLinkSolveChallengeResponseError) Size() (n int) { return n } +func (m *RpcAccountLocalLinkListApps) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *RpcAccountLocalLinkListAppsRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *RpcAccountLocalLinkListAppsResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Error != nil { + l = m.Error.Size() + n += 1 + l + sovCommands(uint64(l)) + } + if len(m.App) > 0 { + for _, e := range m.App { + l = e.Size() + n += 1 + l + sovCommands(uint64(l)) + } + } + return n +} + +func (m *RpcAccountLocalLinkListAppsResponseError) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Code != 0 { + n += 1 + sovCommands(uint64(m.Code)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovCommands(uint64(l)) + } + return n +} + +func (m *RpcAccountLocalLinkCreateApp) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *RpcAccountLocalLinkCreateAppRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.App != nil { + l = m.App.Size() + n += 1 + l + sovCommands(uint64(l)) + } + return n +} + +func (m *RpcAccountLocalLinkCreateAppResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Error != nil { + l = m.Error.Size() + n += 1 + l + sovCommands(uint64(l)) + } + l = len(m.AppKey) + if l > 0 { + n += 1 + l + sovCommands(uint64(l)) + } + return n +} + +func (m *RpcAccountLocalLinkCreateAppResponseError) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Code != 0 { + n += 1 + sovCommands(uint64(m.Code)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovCommands(uint64(l)) + } + return n +} + +func (m *RpcAccountLocalLinkRevokeApp) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *RpcAccountLocalLinkRevokeAppRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.AppHash) + if l > 0 { + n += 1 + l + sovCommands(uint64(l)) + } + return n +} + +func (m *RpcAccountLocalLinkRevokeAppResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Error != nil { + l = m.Error.Size() + n += 1 + l + sovCommands(uint64(l)) + } + return n +} + +func (m *RpcAccountLocalLinkRevokeAppResponseError) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Code != 0 { + n += 1 + sovCommands(uint64(m.Code)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovCommands(uint64(l)) + } + return n +} + func (m *RpcWorkspace) Size() (n int) { if m == nil { return 0 @@ -147214,6 +149230,53 @@ func (m *RpcChatUnreadResponseError) Size() (n int) { return n } +func (m *RpcChatReadAll) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *RpcChatReadAllRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func (m *RpcChatReadAllResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Error != nil { + l = m.Error.Size() + n += 1 + l + sovCommands(uint64(l)) + } + return n +} + +func (m *RpcChatReadAllResponseError) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Code != 0 { + n += 1 + sovCommands(uint64(m.Code)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovCommands(uint64(l)) + } + return n +} + func (m *RpcPushNotification) Size() (n int) { if m == nil { return 0 @@ -149069,6 +151132,344 @@ func (m *RpcSpaceMakeShareableResponseError) Unmarshal(dAtA []byte) error { } return nil } +func (m *RpcSpaceInviteChange) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: InviteChange: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: InviteChange: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcSpaceInviteChangeRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Request: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SpaceId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SpaceId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Permissions", wireType) + } + m.Permissions = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Permissions |= model.ParticipantPermissions(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcSpaceInviteChangeResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Response: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Response: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Error == nil { + m.Error = &RpcSpaceInviteChangeResponseError{} + } + if err := m.Error.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcSpaceInviteChangeResponseError) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Error: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Error: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType) + } + m.Code = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Code |= RpcSpaceInviteChangeResponseErrorCode(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *RpcSpaceInviteGenerate) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -149194,7 +151595,26 @@ func (m *RpcSpaceInviteGenerateRequest) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.InviteType |= RpcSpaceInviteGenerateRequestInviteType(b&0x7F) << shift + m.InviteType |= model.InviteType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Permissions", wireType) + } + m.Permissions = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Permissions |= model.ParticipantPermissions(b&0x7F) << shift if b < 0x80 { break } @@ -149349,6 +151769,44 @@ func (m *RpcSpaceInviteGenerateResponse) Unmarshal(dAtA []byte) error { } m.InviteFileKey = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InviteType", wireType) + } + m.InviteType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InviteType |= model.InviteType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Permissions", wireType) + } + m.Permissions = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Permissions |= model.ParticipantPermissions(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipCommands(dAtA[iNdEx:]) @@ -150051,6 +152509,44 @@ func (m *RpcSpaceInviteGetCurrentResponse) Unmarshal(dAtA []byte) error { } m.InviteFileKey = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InviteType", wireType) + } + m.InviteType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InviteType |= model.InviteType(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Permissions", wireType) + } + m.Permissions = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Permissions |= model.ParticipantPermissions(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipCommands(dAtA[iNdEx:]) @@ -151252,6 +153748,25 @@ func (m *RpcSpaceInviteViewResponse) Unmarshal(dAtA []byte) error { } } m.IsGuestUserInvite = bool(v != 0) + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field InviteType", wireType) + } + m.InviteType = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.InviteType |= model.InviteType(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipCommands(dAtA[iNdEx:]) @@ -162987,6 +165502,1001 @@ func (m *RpcAccountLocalLinkSolveChallengeResponseError) Unmarshal(dAtA []byte) } return nil } +func (m *RpcAccountLocalLinkListApps) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ListApps: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ListApps: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcAccountLocalLinkListAppsRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Request: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcAccountLocalLinkListAppsResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Response: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Response: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Error == nil { + m.Error = &RpcAccountLocalLinkListAppsResponseError{} + } + if err := m.Error.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field App", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.App = append(m.App, &model.AccountAuthAppInfo{}) + if err := m.App[len(m.App)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcAccountLocalLinkListAppsResponseError) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Error: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Error: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType) + } + m.Code = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Code |= RpcAccountLocalLinkListAppsResponseErrorCode(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcAccountLocalLinkCreateApp) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: CreateApp: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: CreateApp: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcAccountLocalLinkCreateAppRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Request: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field App", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.App == nil { + m.App = &model.AccountAuthAppInfo{} + } + if err := m.App.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcAccountLocalLinkCreateAppResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Response: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Response: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Error == nil { + m.Error = &RpcAccountLocalLinkCreateAppResponseError{} + } + if err := m.Error.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcAccountLocalLinkCreateAppResponseError) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Error: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Error: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType) + } + m.Code = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Code |= RpcAccountLocalLinkCreateAppResponseErrorCode(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcAccountLocalLinkRevokeApp) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RevokeApp: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RevokeApp: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcAccountLocalLinkRevokeAppRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Request: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcAccountLocalLinkRevokeAppResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Response: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Response: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Error == nil { + m.Error = &RpcAccountLocalLinkRevokeAppResponseError{} + } + if err := m.Error.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcAccountLocalLinkRevokeAppResponseError) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Error: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Error: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType) + } + m.Code = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Code |= RpcAccountLocalLinkRevokeAppResponseErrorCode(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *RpcWorkspace) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -277610,6 +281120,293 @@ func (m *RpcChatUnreadResponseError) Unmarshal(dAtA []byte) error { } return nil } +func (m *RpcChatReadAll) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ReadAll: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ReadAll: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcChatReadAllRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Request: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Request: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcChatReadAllResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Response: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Response: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Error == nil { + m.Error = &RpcChatReadAllResponseError{} + } + if err := m.Error.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *RpcChatReadAllResponseError) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Error: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Error: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType) + } + m.Code = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Code |= RpcChatReadAllResponseErrorCode(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowCommands + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthCommands + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthCommands + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipCommands(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthCommands + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *RpcPushNotification) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/pb/events.pb.go b/pb/events.pb.go index 6966d8e69..7b424ab6c 100644 --- a/pb/events.pb.go +++ b/pb/events.pb.go @@ -2241,6 +2241,7 @@ func (m *EventAccountLinkChallenge) GetScope() model.AccountAuthLocalApiScope { type EventAccountLinkChallengeClientInfo struct { ProcessName string `protobuf:"bytes,1,opt,name=processName,proto3" json:"processName,omitempty"` ProcessPath string `protobuf:"bytes,2,opt,name=processPath,proto3" json:"processPath,omitempty"` + Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"` SignatureVerified bool `protobuf:"varint,3,opt,name=signatureVerified,proto3" json:"signatureVerified,omitempty"` } @@ -2291,6 +2292,13 @@ func (m *EventAccountLinkChallengeClientInfo) GetProcessPath() string { return "" } +func (m *EventAccountLinkChallengeClientInfo) GetName() string { + if m != nil { + return m.Name + } + return "" +} + func (m *EventAccountLinkChallengeClientInfo) GetSignatureVerified() bool { if m != nil { return m.SignatureVerified @@ -8356,6 +8364,7 @@ type EventBlockDataviewViewUpdateFields struct { CardSize model.BlockContentDataviewViewSize `protobuf:"varint,5,opt,name=cardSize,proto3,enum=anytype.model.BlockContentDataviewViewSize" json:"cardSize,omitempty"` CoverFit bool `protobuf:"varint,6,opt,name=coverFit,proto3" json:"coverFit,omitempty"` GroupRelationKey string `protobuf:"bytes,7,opt,name=groupRelationKey,proto3" json:"groupRelationKey,omitempty"` + EndRelationKey string `protobuf:"bytes,16,opt,name=endRelationKey,proto3" json:"endRelationKey,omitempty"` GroupBackgroundColors bool `protobuf:"varint,8,opt,name=groupBackgroundColors,proto3" json:"groupBackgroundColors,omitempty"` PageLimit int32 `protobuf:"varint,9,opt,name=pageLimit,proto3" json:"pageLimit,omitempty"` DefaultTemplateId string `protobuf:"bytes,10,opt,name=defaultTemplateId,proto3" json:"defaultTemplateId,omitempty"` @@ -8444,6 +8453,13 @@ func (m *EventBlockDataviewViewUpdateFields) GetGroupRelationKey() string { return "" } +func (m *EventBlockDataviewViewUpdateFields) GetEndRelationKey() string { + if m != nil { + return m.EndRelationKey + } + return "" +} + func (m *EventBlockDataviewViewUpdateFields) GetGroupBackgroundColors() bool { if m != nil { return m.GroupBackgroundColors @@ -12773,413 +12789,414 @@ func init() { func init() { proto.RegisterFile("pb/protos/events.proto", fileDescriptor_a966342d378ae5f5) } var fileDescriptor_a966342d378ae5f5 = []byte{ - // 6491 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x49, 0x8c, 0x1c, 0xc9, - 0x75, 0x76, 0xed, 0xcb, 0xeb, 0x66, 0xb3, 0x18, 0xe4, 0x90, 0x39, 0x39, 0x3d, 0x1c, 0x4e, 0x0f, - 0xc9, 0xa1, 0x66, 0x38, 0x45, 0x0e, 0xd7, 0x11, 0x67, 0xb8, 0xf4, 0xc6, 0xa9, 0xe2, 0xd2, 0x6c, - 0x45, 0x93, 0xd4, 0x68, 0x24, 0xfc, 0x50, 0x76, 0x65, 0x74, 0x77, 0x8a, 0xd5, 0x99, 0xa5, 0xcc, - 0xec, 0x26, 0x5b, 0xdb, 0xaf, 0x5f, 0xcb, 0xaf, 0xff, 0x07, 0x6c, 0xd8, 0x06, 0x0c, 0xdb, 0xf0, - 0xc5, 0x80, 0x61, 0x01, 0x3e, 0x18, 0x86, 0x01, 0x5f, 0xec, 0x83, 0x17, 0xc0, 0x10, 0x6c, 0x79, - 0x01, 0xa4, 0x9b, 0x2f, 0xb6, 0xe4, 0xd1, 0xc5, 0x17, 0x1f, 0x64, 0x03, 0x86, 0x8f, 0x46, 0x2c, - 0x19, 0x19, 0x91, 0x4b, 0x65, 0xb5, 0x66, 0xe4, 0x05, 0xd6, 0xa9, 0x2b, 0x22, 0xde, 0xfb, 0x5e, - 0x2c, 0xef, 0xbd, 0x88, 0x78, 0x11, 0x19, 0x0d, 0x47, 0x47, 0xeb, 0xe7, 0x46, 0xbe, 0x17, 0x7a, - 0xc1, 0x39, 0xb2, 0x4b, 0xdc, 0x30, 0xe8, 0xb2, 0x14, 0x6a, 0x5a, 0xee, 0x5e, 0xb8, 0x37, 0x22, - 0xe6, 0xc9, 0xd1, 0x93, 0xcd, 0x73, 0x43, 0x67, 0xfd, 0xdc, 0x68, 0xfd, 0xdc, 0xb6, 0x67, 0x93, - 0x61, 0x44, 0xce, 0x12, 0x82, 0xdc, 0x9c, 0xdd, 0xf4, 0xbc, 0xcd, 0x21, 0xe1, 0x65, 0xeb, 0x3b, - 0x1b, 0xe7, 0x82, 0xd0, 0xdf, 0x19, 0x84, 0xbc, 0x74, 0xee, 0x3b, 0xdf, 0x2d, 0x43, 0x7d, 0x99, - 0xc2, 0xa3, 0x0b, 0xd0, 0xda, 0x26, 0x41, 0x60, 0x6d, 0x92, 0xc0, 0x28, 0x9f, 0xa8, 0x9e, 0x99, - 0xba, 0x70, 0xb4, 0x2b, 0x44, 0x75, 0x19, 0x45, 0xf7, 0x3e, 0x2f, 0xc6, 0x92, 0x0e, 0xcd, 0x42, - 0x7b, 0xe0, 0xb9, 0x21, 0x79, 0x16, 0xf6, 0x6d, 0xa3, 0x72, 0xa2, 0x7c, 0xa6, 0x8d, 0xe3, 0x0c, - 0x74, 0x09, 0xda, 0x8e, 0xeb, 0x84, 0x8e, 0x15, 0x7a, 0xbe, 0x51, 0x3d, 0x51, 0xd6, 0x20, 0x59, - 0x25, 0xbb, 0xf3, 0x83, 0x81, 0xb7, 0xe3, 0x86, 0x38, 0x26, 0x44, 0x06, 0x34, 0x43, 0xdf, 0x1a, - 0x90, 0xbe, 0x6d, 0xd4, 0x18, 0x62, 0x94, 0x34, 0xff, 0xe8, 0x32, 0x34, 0x45, 0x1d, 0xd0, 0xf3, - 0xd0, 0x0c, 0x46, 0x9c, 0xea, 0x1b, 0x65, 0x4e, 0x26, 0xd2, 0xe8, 0x26, 0x4c, 0x59, 0x1c, 0x76, - 0x6d, 0xcb, 0x7b, 0x6a, 0x94, 0x99, 0xe0, 0x17, 0x12, 0x6d, 0x11, 0x82, 0xbb, 0x94, 0xa4, 0x57, - 0xc2, 0x2a, 0x07, 0xea, 0xc3, 0x8c, 0x48, 0x2e, 0x91, 0xd0, 0x72, 0x86, 0x81, 0xf1, 0x5d, 0x0e, - 0x72, 0x3c, 0x07, 0x44, 0x90, 0xf5, 0x4a, 0x38, 0xc1, 0x88, 0x3e, 0x05, 0x87, 0x45, 0xce, 0xa2, - 0xe7, 0x6e, 0x38, 0x9b, 0x8f, 0x46, 0xb6, 0x15, 0x12, 0xe3, 0x2f, 0x39, 0xde, 0xc9, 0x1c, 0x3c, - 0x4e, 0xdb, 0xe5, 0xc4, 0xbd, 0x12, 0xce, 0xc2, 0x40, 0xb7, 0xe1, 0x80, 0xc8, 0x16, 0xa0, 0x7f, - 0xc5, 0x41, 0x5f, 0xcc, 0x01, 0x95, 0x68, 0x3a, 0x1b, 0xfa, 0x34, 0x1c, 0x11, 0x19, 0xf7, 0x1c, - 0xf7, 0xc9, 0xe2, 0x96, 0x35, 0x1c, 0x12, 0x77, 0x93, 0x18, 0x7f, 0x3d, 0xbe, 0x8e, 0x1a, 0x71, - 0xaf, 0x84, 0x33, 0x41, 0xd0, 0x26, 0x18, 0x59, 0xf9, 0x3d, 0xc7, 0x26, 0xc6, 0xdf, 0x70, 0x01, - 0x67, 0x26, 0x12, 0xe0, 0xd8, 0x54, 0x48, 0x2e, 0x18, 0x7a, 0x00, 0x1d, 0x6f, 0xfd, 0x73, 0x64, - 0x10, 0xf5, 0xfc, 0x1a, 0x09, 0x8d, 0x0e, 0xc3, 0x7f, 0x39, 0x81, 0xff, 0x80, 0x91, 0x45, 0x63, - 0xd6, 0x5d, 0x23, 0x61, 0xaf, 0x84, 0x53, 0xcc, 0xe8, 0x11, 0x20, 0x2d, 0x6f, 0x7e, 0x9b, 0xb8, - 0xb6, 0x71, 0x81, 0x41, 0xbe, 0x32, 0x1e, 0x92, 0x91, 0xf6, 0x4a, 0x38, 0x03, 0x20, 0x05, 0xfb, - 0xc8, 0x0d, 0x48, 0x68, 0x5c, 0x9c, 0x04, 0x96, 0x91, 0xa6, 0x60, 0x59, 0x2e, 0x1d, 0x44, 0x9e, - 0x8b, 0xc9, 0xd0, 0x0a, 0x1d, 0xcf, 0x15, 0xf5, 0xbd, 0xc4, 0x80, 0x4f, 0x65, 0x03, 0x4b, 0x5a, - 0x59, 0xe3, 0x4c, 0x10, 0xf4, 0xbf, 0xe0, 0xb9, 0x44, 0x3e, 0x26, 0xdb, 0xde, 0x2e, 0x31, 0x2e, - 0x33, 0xf4, 0xd3, 0x45, 0xe8, 0x9c, 0xba, 0x57, 0xc2, 0xd9, 0x30, 0x68, 0x01, 0xa6, 0xa3, 0x02, - 0x06, 0x7b, 0x85, 0xc1, 0xce, 0xe6, 0xc1, 0x0a, 0x30, 0x8d, 0x87, 0x1a, 0x3d, 0x4f, 0x2f, 0x0e, - 0xbd, 0x80, 0x18, 0xf3, 0x99, 0x46, 0x2f, 0x20, 0x18, 0x09, 0x35, 0x7a, 0x85, 0x43, 0x6d, 0x64, - 0x10, 0xfa, 0xce, 0x80, 0x55, 0x90, 0x6a, 0xd1, 0xd5, 0xf1, 0x8d, 0x8c, 0x89, 0x85, 0x2a, 0x65, - 0xc3, 0x20, 0x0c, 0x07, 0x83, 0x9d, 0xf5, 0x60, 0xe0, 0x3b, 0x23, 0x9a, 0x37, 0x6f, 0xdb, 0xc6, - 0x3b, 0xe3, 0x90, 0xd7, 0x14, 0xe2, 0xee, 0xbc, 0x4d, 0x47, 0x27, 0x09, 0x80, 0x3e, 0x0d, 0x48, - 0xcd, 0x12, 0xdd, 0x77, 0x9d, 0xc1, 0x7e, 0x6c, 0x02, 0x58, 0xd9, 0x97, 0x19, 0x30, 0xc8, 0x82, - 0x23, 0x6a, 0xee, 0xaa, 0x17, 0x38, 0xf4, 0xaf, 0x71, 0x83, 0xc1, 0xbf, 0x3e, 0x01, 0x7c, 0xc4, - 0x42, 0x15, 0x2b, 0x0b, 0x2a, 0x29, 0x62, 0x91, 0x9a, 0x36, 0xf1, 0x03, 0xe3, 0xe6, 0xc4, 0x22, - 0x22, 0x96, 0xa4, 0x88, 0x28, 0x3f, 0xd9, 0x45, 0xef, 0xfa, 0xde, 0xce, 0x28, 0x30, 0x6e, 0x4d, - 0xdc, 0x45, 0x9c, 0x21, 0xd9, 0x45, 0x3c, 0x17, 0x5d, 0x81, 0xd6, 0xfa, 0xd0, 0x1b, 0x3c, 0xa1, - 0x83, 0x59, 0x61, 0x90, 0x46, 0x02, 0x72, 0x81, 0x16, 0x8b, 0xe1, 0x93, 0xb4, 0x54, 0x59, 0xd9, - 0xef, 0x25, 0x32, 0x24, 0x21, 0x11, 0x53, 0xe3, 0x0b, 0x99, 0xac, 0x9c, 0x84, 0x2a, 0xab, 0xc2, - 0x81, 0x96, 0x60, 0x6a, 0xc3, 0x19, 0x92, 0xe0, 0xd1, 0x68, 0xe8, 0x59, 0x7c, 0x9e, 0x9c, 0xba, - 0x70, 0x22, 0x13, 0xe0, 0x76, 0x4c, 0x47, 0x51, 0x14, 0x36, 0x74, 0x03, 0xda, 0xdb, 0x96, 0xff, - 0x24, 0xe8, 0xbb, 0x1b, 0x9e, 0x51, 0xcf, 0x9c, 0xe1, 0x38, 0xc6, 0xfd, 0x88, 0xaa, 0x57, 0xc2, - 0x31, 0x0b, 0x9d, 0x27, 0x59, 0xa5, 0xd6, 0x48, 0x78, 0xdb, 0x21, 0x43, 0x3b, 0x30, 0x1a, 0x0c, - 0xe4, 0xa5, 0x4c, 0x90, 0x35, 0x12, 0x76, 0x39, 0x19, 0x9d, 0x27, 0x75, 0x46, 0xf4, 0x1e, 0x1c, - 0x8e, 0x72, 0x16, 0xb7, 0x9c, 0xa1, 0xed, 0x13, 0xb7, 0x6f, 0x07, 0x46, 0x33, 0x73, 0x0a, 0x8a, - 0xf1, 0x14, 0x5a, 0x3a, 0x4d, 0x66, 0x40, 0x50, 0xcf, 0x18, 0x65, 0xab, 0x26, 0x69, 0xb4, 0x32, - 0x3d, 0x63, 0x0c, 0xad, 0x12, 0x53, 0xed, 0xca, 0x02, 0x41, 0x36, 0x1c, 0x8b, 0xf2, 0x17, 0xac, - 0xc1, 0x93, 0x4d, 0xdf, 0xdb, 0x71, 0xed, 0x45, 0x6f, 0xe8, 0xf9, 0x46, 0x3b, 0x73, 0x72, 0x8b, - 0xf1, 0x13, 0xf4, 0xbd, 0x12, 0xce, 0x83, 0x42, 0x8b, 0x30, 0x1d, 0x15, 0x3d, 0x24, 0xcf, 0x42, - 0x03, 0x32, 0xe7, 0xf9, 0x18, 0x9a, 0x12, 0x51, 0x07, 0xa9, 0x32, 0xa9, 0x20, 0x54, 0x25, 0x8c, - 0xa9, 0x02, 0x10, 0x4a, 0xa4, 0x82, 0xd0, 0xb4, 0x0a, 0x42, 0xa7, 0x60, 0xe3, 0x40, 0x01, 0x08, - 0x25, 0x52, 0x41, 0x68, 0x9a, 0x4e, 0xd5, 0xb2, 0xa5, 0x9e, 0xf7, 0x84, 0xea, 0x93, 0x31, 0x93, - 0x39, 0x55, 0x2b, 0xbd, 0x25, 0x08, 0xe9, 0x54, 0x9d, 0x64, 0xa6, 0x2b, 0xa1, 0x28, 0x6f, 0x7e, - 0xe8, 0x6c, 0xba, 0xc6, 0xc1, 0x31, 0xba, 0x4c, 0xd1, 0x18, 0x15, 0x5d, 0x09, 0x69, 0x6c, 0xe8, - 0x96, 0x30, 0xcb, 0x35, 0x12, 0x2e, 0x39, 0xbb, 0xc6, 0xa1, 0xcc, 0x69, 0x28, 0x46, 0x59, 0x72, - 0x76, 0xa5, 0x5d, 0x72, 0x16, 0xb5, 0x69, 0xd1, 0x24, 0x67, 0x3c, 0x57, 0xd0, 0xb4, 0x88, 0x50, - 0x6d, 0x5a, 0x94, 0xa7, 0x36, 0xed, 0x9e, 0x15, 0x92, 0x67, 0xc6, 0xf3, 0x05, 0x4d, 0x63, 0x54, - 0x6a, 0xd3, 0x58, 0x06, 0x9d, 0xdd, 0xa2, 0x8c, 0xc7, 0xc4, 0x0f, 0x9d, 0x81, 0x35, 0xe4, 0x5d, - 0x75, 0x32, 0x73, 0x0e, 0x8a, 0xf1, 0x34, 0x6a, 0x3a, 0xbb, 0x65, 0xc2, 0xa8, 0x0d, 0x7f, 0x68, - 0xad, 0x0f, 0x09, 0xf6, 0x9e, 0x1a, 0xa7, 0x0a, 0x1a, 0x1e, 0x11, 0xaa, 0x0d, 0x8f, 0xf2, 0x54, - 0xdf, 0xf2, 0x49, 0xc7, 0xde, 0x24, 0xa1, 0x71, 0xa6, 0xc0, 0xb7, 0x70, 0x32, 0xd5, 0xb7, 0xf0, - 0x1c, 0xe9, 0x01, 0x96, 0xac, 0xd0, 0xda, 0x75, 0xc8, 0xd3, 0xc7, 0x0e, 0x79, 0x4a, 0x27, 0xf6, - 0xc3, 0x63, 0x3c, 0x40, 0x44, 0xdb, 0x15, 0xc4, 0xd2, 0x03, 0x24, 0x40, 0xa4, 0x07, 0x50, 0xf3, - 0x85, 0x5b, 0x3f, 0x32, 0xc6, 0x03, 0x68, 0xf8, 0xd2, 0xc7, 0xe7, 0x41, 0x21, 0x0b, 0x8e, 0xa6, - 0x8a, 0x1e, 0xf8, 0x36, 0xf1, 0x8d, 0x17, 0x99, 0x90, 0x57, 0x8b, 0x85, 0x30, 0xf2, 0x5e, 0x09, - 0xe7, 0x00, 0xa5, 0x44, 0xac, 0x79, 0x3b, 0xfe, 0x80, 0xd0, 0x7e, 0x7a, 0x65, 0x12, 0x11, 0x92, - 0x3c, 0x25, 0x42, 0x96, 0xa0, 0x5d, 0x78, 0x51, 0x96, 0x50, 0xc1, 0x6c, 0x16, 0x65, 0xd2, 0xc5, - 0x0e, 0xe6, 0x34, 0x93, 0xd4, 0x1d, 0x2f, 0x29, 0xc9, 0xd5, 0x2b, 0xe1, 0xf1, 0xb0, 0x68, 0x0f, - 0x8e, 0x6b, 0x04, 0x7c, 0x9e, 0x57, 0x05, 0xbf, 0xca, 0x04, 0x9f, 0x1b, 0x2f, 0x38, 0xc5, 0xd6, - 0x2b, 0xe1, 0x02, 0x60, 0x34, 0x82, 0x17, 0xb4, 0xce, 0x88, 0x0c, 0x5b, 0xa8, 0xc8, 0x97, 0x98, - 0xdc, 0xb3, 0xe3, 0xe5, 0xea, 0x3c, 0xbd, 0x12, 0x1e, 0x07, 0x49, 0x77, 0x5c, 0x99, 0xc5, 0x74, - 0x24, 0xbf, 0x98, 0xb9, 0xec, 0xc9, 0x11, 0xc7, 0xc7, 0x32, 0x17, 0x2c, 0x53, 0xf3, 0x45, 0x77, - 0x7e, 0x79, 0x52, 0xcd, 0x97, 0xfd, 0x98, 0x07, 0xa5, 0x8d, 0x1d, 0x2d, 0x7a, 0x68, 0xf9, 0x9b, - 0x24, 0xe4, 0x1d, 0xdd, 0xb7, 0x69, 0xa3, 0xbe, 0x32, 0xc9, 0xd8, 0xa5, 0xd8, 0xb4, 0xb1, 0xcb, - 0x04, 0x46, 0x01, 0xcc, 0x6a, 0x14, 0xfd, 0x60, 0xd1, 0x1b, 0x0e, 0xc9, 0x20, 0xea, 0xcd, 0xff, - 0xcd, 0x04, 0xbf, 0x31, 0x5e, 0x70, 0x82, 0xa9, 0x57, 0xc2, 0x63, 0x41, 0x53, 0xed, 0x7d, 0x30, - 0xb4, 0x13, 0x3a, 0x63, 0x4c, 0xa4, 0xab, 0x49, 0xb6, 0x54, 0x7b, 0x53, 0x14, 0x29, 0x5d, 0x55, - 0x28, 0x68, 0x73, 0x8f, 0x4d, 0xa2, 0xab, 0x3a, 0x4f, 0x4a, 0x57, 0xf5, 0x62, 0x3a, 0xbb, 0xed, - 0x04, 0xc4, 0x67, 0x18, 0x77, 0x3c, 0xc7, 0x35, 0x5e, 0xca, 0x9c, 0xdd, 0x1e, 0x05, 0xc4, 0x17, - 0x82, 0x28, 0x15, 0x9d, 0xdd, 0x34, 0x36, 0x0d, 0xe7, 0x1e, 0xd9, 0x08, 0x8d, 0x13, 0x45, 0x38, - 0x94, 0x4a, 0xc3, 0xa1, 0x19, 0x74, 0xa6, 0x90, 0x19, 0x6b, 0x84, 0x8e, 0x0a, 0xb6, 0xdc, 0x4d, - 0x62, 0xbc, 0x9c, 0x39, 0x53, 0x28, 0x70, 0x0a, 0x31, 0x9d, 0x29, 0xb2, 0x40, 0xe8, 0xce, 0x5f, - 0xe6, 0xd3, 0x15, 0x19, 0x87, 0x9e, 0xcb, 0xdc, 0xf9, 0x2b, 0xd0, 0x92, 0x94, 0xee, 0x41, 0xd2, - 0x00, 0xe8, 0x63, 0x50, 0x1b, 0x39, 0xee, 0xa6, 0x61, 0x33, 0xa0, 0xc3, 0x09, 0xa0, 0x55, 0xc7, - 0xdd, 0xec, 0x95, 0x30, 0x23, 0x41, 0xef, 0x00, 0x8c, 0x7c, 0x6f, 0x40, 0x82, 0x60, 0x85, 0x3c, - 0x35, 0x08, 0x63, 0x30, 0x93, 0x0c, 0x9c, 0xa0, 0xbb, 0x42, 0xe8, 0xbc, 0xac, 0xd0, 0xa3, 0x65, - 0x38, 0x20, 0x52, 0xc2, 0xca, 0x37, 0x32, 0x17, 0x7f, 0x11, 0x40, 0x1c, 0x6e, 0xd2, 0xb8, 0xe8, - 0xde, 0x47, 0x64, 0x2c, 0x79, 0x2e, 0x31, 0x36, 0x33, 0xf7, 0x3e, 0x11, 0x08, 0x25, 0xa1, 0x6b, - 0x2c, 0x85, 0x03, 0x2d, 0xc0, 0x74, 0xb8, 0xe5, 0x13, 0xcb, 0x5e, 0x0b, 0xad, 0x70, 0x27, 0x30, - 0xdc, 0xcc, 0x65, 0x1a, 0x2f, 0xec, 0x3e, 0x64, 0x94, 0x74, 0x09, 0xaa, 0xf2, 0xa0, 0x15, 0xe8, - 0xd0, 0x8d, 0xd0, 0x3d, 0x67, 0xdb, 0x09, 0x31, 0xb1, 0x06, 0x5b, 0xc4, 0x36, 0xbc, 0xcc, 0x4d, - 0x14, 0x5d, 0xf6, 0x76, 0x55, 0x3a, 0xba, 0x5a, 0x49, 0xf2, 0xa2, 0x1e, 0xcc, 0xd0, 0xbc, 0xb5, - 0x91, 0x35, 0x20, 0x8f, 0x02, 0x6b, 0x93, 0x18, 0xa3, 0x4c, 0x0d, 0x64, 0x68, 0x31, 0x15, 0x5d, - 0xac, 0xe8, 0x7c, 0x11, 0xd2, 0x3d, 0x6f, 0x60, 0x0d, 0x39, 0xd2, 0xe7, 0xf3, 0x91, 0x62, 0xaa, - 0x08, 0x29, 0xce, 0xd1, 0xda, 0xc8, 0xfb, 0xde, 0x36, 0x76, 0x0b, 0xda, 0x28, 0xe8, 0xb4, 0x36, - 0x8a, 0x3c, 0x8a, 0xe7, 0x7a, 0xa1, 0xb3, 0xe1, 0x0c, 0x84, 0xfd, 0xba, 0xb6, 0xe1, 0x67, 0xe2, - 0xad, 0x28, 0x64, 0xdd, 0x35, 0x1e, 0x59, 0x4a, 0xf1, 0xa2, 0x87, 0x80, 0xd4, 0x3c, 0xa1, 0x54, - 0x01, 0x43, 0x9c, 0x1b, 0x87, 0x28, 0x35, 0x2b, 0x83, 0x9f, 0xd6, 0x72, 0x64, 0xed, 0xd1, 0xed, - 0xed, 0x82, 0xef, 0x59, 0xf6, 0xc0, 0x0a, 0x42, 0x23, 0xcc, 0xac, 0xe5, 0x2a, 0x27, 0xeb, 0x4a, - 0x3a, 0x5a, 0xcb, 0x24, 0x2f, 0xc5, 0xdb, 0x26, 0xdb, 0xeb, 0xc4, 0x0f, 0xb6, 0x9c, 0x91, 0xa8, - 0xe3, 0x4e, 0x26, 0xde, 0x7d, 0x49, 0x16, 0xd7, 0x30, 0xc5, 0x4b, 0x17, 0xe2, 0x2c, 0x4e, 0xbd, - 0xb6, 0xe7, 0x0e, 0xb8, 0x32, 0x0a, 0xd0, 0xa7, 0x99, 0x0b, 0x71, 0xa6, 0x19, 0xdd, 0x98, 0x38, - 0x86, 0xce, 0x86, 0x41, 0xef, 0xc3, 0x11, 0x56, 0x30, 0xbf, 0x13, 0x7a, 0x7c, 0xfd, 0x3b, 0x6f, - 0xdb, 0xc4, 0x36, 0xbe, 0x90, 0xb9, 0x93, 0xe6, 0xf0, 0x09, 0x5a, 0x16, 0x4b, 0xc9, 0xc0, 0x40, - 0x77, 0xe1, 0xe0, 0xe8, 0xc2, 0x48, 0xab, 0xf5, 0xb3, 0xcc, 0x45, 0xf9, 0xea, 0x85, 0xd5, 0x64, - 0x75, 0x93, 0x9c, 0xd4, 0x8c, 0x9d, 0xed, 0x91, 0xe7, 0x87, 0xb7, 0x1d, 0xd7, 0x09, 0xb6, 0x8c, - 0xbd, 0x4c, 0x33, 0xee, 0x33, 0x92, 0x2e, 0xa7, 0xa1, 0x66, 0xac, 0xf2, 0xa0, 0x4b, 0xd0, 0x1c, - 0x6c, 0x59, 0xb4, 0x76, 0xc6, 0x57, 0x79, 0x30, 0xf9, 0x58, 0x82, 0x7f, 0x71, 0xcb, 0x0a, 0x45, - 0xf8, 0x25, 0x22, 0x45, 0xd7, 0x01, 0xe8, 0x4f, 0xd1, 0x82, 0xff, 0x53, 0xce, 0xf4, 0x83, 0x8c, - 0x51, 0xd6, 0x5e, 0x61, 0x40, 0xef, 0xc1, 0xe1, 0x38, 0x45, 0x1d, 0x00, 0x8f, 0x27, 0x7c, 0xad, - 0x9c, 0xe9, 0xc9, 0x15, 0x1c, 0x49, 0xdb, 0x2b, 0xe1, 0x2c, 0x08, 0x3a, 0x01, 0xc7, 0xd9, 0xd1, - 0x61, 0x4b, 0xec, 0xe8, 0xfe, 0x6f, 0x39, 0x33, 0x2c, 0xa6, 0x48, 0x48, 0xf1, 0xd0, 0x09, 0x78, - 0x0c, 0x64, 0x52, 0xa2, 0xcb, 0xc3, 0x7f, 0x52, 0xe2, 0xb7, 0x26, 0x90, 0x98, 0xe0, 0x49, 0x4a, - 0x4c, 0x14, 0x47, 0x9d, 0x2f, 0xd6, 0x32, 0x5f, 0x1f, 0xd3, 0xf9, 0x72, 0xdd, 0xa2, 0x30, 0xa0, - 0x7b, 0x70, 0x90, 0xa6, 0x28, 0x18, 0x11, 0x03, 0xf8, 0xcd, 0x72, 0xa6, 0x0e, 0x2a, 0x95, 0x64, - 0xd4, 0x54, 0x07, 0x13, 0xac, 0x74, 0x09, 0x3b, 0xda, 0x09, 0xb6, 0x96, 0xdd, 0x81, 0xbf, 0xc7, - 0xe2, 0x7a, 0x77, 0xc9, 0x9e, 0x40, 0xfd, 0x7f, 0xe5, 0xcc, 0x5d, 0xcf, 0x6a, 0x92, 0x3c, 0xd6, - 0x91, 0x3c, 0xa8, 0x85, 0x26, 0xd4, 0x77, 0xad, 0xe1, 0x0e, 0x31, 0x7f, 0xa9, 0x01, 0x35, 0x5a, - 0x2d, 0xf3, 0xef, 0xcb, 0x50, 0xa5, 0x9a, 0x38, 0x03, 0x15, 0xc7, 0x36, 0xf8, 0xf1, 0x55, 0xc5, - 0xb1, 0x91, 0x01, 0x4d, 0x8f, 0x6e, 0x1e, 0xe4, 0x61, 0x5a, 0x94, 0x44, 0x73, 0x30, 0x6d, 0x6d, - 0x84, 0xc4, 0x7f, 0x20, 0x8a, 0x1b, 0xac, 0x58, 0xcb, 0xa3, 0xd6, 0x20, 0x0e, 0xe6, 0x44, 0x44, - 0xd1, 0x4c, 0x1c, 0xb6, 0x51, 0xd9, 0x91, 0x0e, 0x44, 0xa4, 0xe8, 0x28, 0x34, 0x82, 0x9d, 0xf5, - 0xbe, 0x1d, 0x18, 0xb5, 0x13, 0xd5, 0x33, 0x6d, 0x2c, 0x52, 0xe8, 0x6d, 0x98, 0xb6, 0xc9, 0x88, - 0xb8, 0x36, 0x71, 0x07, 0x0e, 0x09, 0x8c, 0x3a, 0x3b, 0x12, 0x3c, 0xd6, 0xe5, 0xc7, 0x89, 0xdd, - 0xe8, 0x38, 0xb1, 0xbb, 0xc6, 0x8e, 0x13, 0xb1, 0x46, 0x6c, 0x9e, 0x87, 0x86, 0x18, 0xb0, 0x64, - 0x13, 0x63, 0x71, 0x15, 0x55, 0x9c, 0xb9, 0x01, 0x0d, 0x31, 0x28, 0x49, 0x0e, 0xa5, 0x59, 0x95, - 0x9f, 0xa4, 0x59, 0x55, 0x4d, 0xce, 0x97, 0xe1, 0x60, 0xd2, 0xec, 0x92, 0x02, 0x17, 0xa0, 0xed, - 0x4b, 0xb3, 0xae, 0x24, 0xfc, 0x66, 0x4a, 0x64, 0x57, 0x02, 0xe1, 0x98, 0x2d, 0x57, 0xfc, 0xa7, - 0xe1, 0x58, 0x9e, 0x2d, 0x76, 0xa0, 0xea, 0xd8, 0xfc, 0xe8, 0xb5, 0x8d, 0xe9, 0x4f, 0x0a, 0xe2, - 0x04, 0x94, 0x82, 0xd5, 0xa2, 0x85, 0x45, 0x6a, 0x12, 0xf0, 0xa4, 0xd9, 0x7d, 0x78, 0xf0, 0x47, - 0x30, 0xa5, 0x58, 0x13, 0xea, 0x42, 0x3d, 0xa0, 0x3f, 0xc4, 0xf1, 0xaa, 0x91, 0xd1, 0x41, 0x8c, - 0x10, 0x73, 0xb2, 0xdc, 0x71, 0xff, 0x76, 0x03, 0x9a, 0xe2, 0xc4, 0xcf, 0x5c, 0x81, 0x1a, 0x3b, - 0x7f, 0x3d, 0x02, 0x75, 0xc7, 0xb5, 0xc9, 0x33, 0x86, 0x5d, 0xc7, 0x3c, 0x81, 0xce, 0x43, 0x53, - 0x9c, 0xfe, 0x89, 0x41, 0xc9, 0x3b, 0x4b, 0x8e, 0xc8, 0xcc, 0xf7, 0xa1, 0x19, 0x9d, 0xc3, 0xce, - 0x42, 0x7b, 0xe4, 0x7b, 0x74, 0x4d, 0xd3, 0x8f, 0x86, 0x3a, 0xce, 0x40, 0x6f, 0x42, 0xd3, 0x16, - 0x27, 0xbd, 0x15, 0x31, 0x8d, 0xe4, 0xa8, 0x79, 0x44, 0x67, 0x7e, 0xb5, 0x0c, 0x0d, 0x7e, 0x1c, - 0x6b, 0xee, 0x4a, 0xd5, 0xbd, 0x0c, 0x8d, 0x01, 0xcb, 0x33, 0x92, 0x47, 0xb1, 0x5a, 0x0d, 0xc5, - 0xf9, 0x2e, 0x16, 0xc4, 0x94, 0x2d, 0xe0, 0x0e, 0xb7, 0x32, 0x96, 0x8d, 0x8f, 0x25, 0x16, 0xc4, - 0xff, 0x69, 0x72, 0xff, 0xa4, 0x02, 0x07, 0xf4, 0x53, 0xde, 0x59, 0x68, 0x0f, 0xe4, 0xb9, 0xb1, - 0xe8, 0x5d, 0x99, 0x81, 0x1e, 0x00, 0x0c, 0x86, 0x0e, 0x71, 0x43, 0x76, 0xce, 0x50, 0xc9, 0xdc, - 0xbe, 0x66, 0x1e, 0xfa, 0x76, 0x17, 0x25, 0x1b, 0x56, 0x20, 0xd0, 0x4d, 0xa8, 0x07, 0x03, 0x6f, - 0xc4, 0xdd, 0xdc, 0x8c, 0x12, 0xcf, 0xd0, 0xab, 0x3d, 0xbf, 0x13, 0x6e, 0xf1, 0x25, 0xf2, 0xfc, - 0xc8, 0x59, 0xa3, 0x0c, 0x98, 0xf3, 0x99, 0x5f, 0x01, 0x88, 0xa1, 0xd1, 0x09, 0xb9, 0x23, 0x59, - 0xb1, 0xb6, 0xa3, 0xfa, 0xab, 0x59, 0x0a, 0xc5, 0xaa, 0x15, 0x6e, 0x09, 0xdf, 0xac, 0x66, 0xa1, - 0xb3, 0x70, 0x28, 0x70, 0x36, 0x5d, 0x2b, 0xdc, 0xf1, 0xc9, 0x63, 0xe2, 0x3b, 0x1b, 0x0e, 0xb1, - 0x59, 0xf5, 0x5a, 0x38, 0x5d, 0x60, 0xbe, 0x09, 0x87, 0xd2, 0x27, 0xd8, 0x63, 0x3b, 0xd1, 0xfc, - 0xff, 0x6d, 0x68, 0xf0, 0xe0, 0x84, 0xf9, 0xaf, 0x15, 0xa9, 0xd7, 0xe6, 0x9f, 0x95, 0xa1, 0xce, - 0x0f, 0x69, 0x93, 0x5e, 0xec, 0xb6, 0xaa, 0xd3, 0xd5, 0x8c, 0x9d, 0x7b, 0xd6, 0xa1, 0x75, 0xf7, - 0x2e, 0xd9, 0x7b, 0x4c, 0xe7, 0x2a, 0xa9, 0xe8, 0xb9, 0xfe, 0xe0, 0x0e, 0xb4, 0x22, 0x62, 0xea, - 0x5d, 0x9e, 0x90, 0x3d, 0x21, 0x9c, 0xfe, 0x44, 0x67, 0xc5, 0x9c, 0x27, 0x4d, 0x35, 0x69, 0x4f, - 0x5c, 0x8a, 0x98, 0x18, 0x3f, 0x0b, 0xd5, 0x35, 0x12, 0xa6, 0x9a, 0xb0, 0x7f, 0xb3, 0xcc, 0xad, - 0xed, 0x22, 0xd4, 0xf9, 0x41, 0x79, 0x52, 0x06, 0x82, 0xda, 0x13, 0xb2, 0x17, 0x79, 0x25, 0xf6, - 0x3b, 0x17, 0xe4, 0x4f, 0xab, 0x30, 0xad, 0x1e, 0x0e, 0x9a, 0xcb, 0xb9, 0xd3, 0x38, 0x9b, 0x98, - 0xe3, 0x69, 0x5c, 0x24, 0xa9, 0x67, 0x63, 0x58, 0x4c, 0x35, 0xda, 0x98, 0x27, 0xcc, 0x2e, 0x34, - 0xc4, 0x99, 0x6b, 0x12, 0x49, 0xd2, 0x57, 0x54, 0xfa, 0x3b, 0xd0, 0x92, 0x47, 0xa8, 0x1f, 0x56, - 0xb6, 0x0f, 0x2d, 0x79, 0x56, 0x7a, 0x04, 0xea, 0xa1, 0x17, 0x5a, 0x43, 0x06, 0x57, 0xc5, 0x3c, - 0x41, 0xf5, 0xd2, 0x25, 0xcf, 0xc2, 0x45, 0xe9, 0x79, 0xab, 0x38, 0xce, 0xe0, 0x8e, 0x95, 0xec, - 0xf2, 0xd2, 0x2a, 0x2f, 0x95, 0x19, 0xb1, 0xcc, 0x9a, 0x2a, 0x73, 0x0f, 0x1a, 0xe2, 0x00, 0x55, - 0x96, 0x97, 0x95, 0x72, 0x34, 0x0f, 0xf5, 0x4d, 0x5a, 0x2e, 0x46, 0xfd, 0xf5, 0x84, 0x7d, 0xf3, - 0xb8, 0xc8, 0xa2, 0xe7, 0x86, 0x54, 0x8d, 0xf5, 0xb8, 0x30, 0xe6, 0x9c, 0x74, 0x08, 0x7d, 0x7e, - 0x1a, 0xce, 0x8d, 0x50, 0xa4, 0xcc, 0x6f, 0x97, 0xa1, 0x2d, 0xaf, 0x1f, 0x98, 0xef, 0xe7, 0x19, - 0xcf, 0x3c, 0x1c, 0xf0, 0x05, 0x15, 0x35, 0xd4, 0xc8, 0x84, 0x5e, 0x48, 0xd4, 0x04, 0x2b, 0x34, - 0x58, 0xe7, 0x30, 0xdf, 0xc9, 0x1d, 0xd4, 0x39, 0x98, 0x8e, 0x48, 0xef, 0xc6, 0xaa, 0xa7, 0xe5, - 0x99, 0xa6, 0xe4, 0x4e, 0xcd, 0xdc, 0xe6, 0x06, 0x4c, 0xab, 0x87, 0x90, 0xe6, 0xe3, 0x6c, 0xeb, - 0xb9, 0x49, 0xc5, 0x28, 0x07, 0x9e, 0x95, 0x44, 0xa4, 0x25, 0x6a, 0x42, 0x4c, 0x82, 0x35, 0x06, - 0xf3, 0x18, 0xd4, 0xf9, 0xd5, 0x88, 0x04, 0xb2, 0xf9, 0xeb, 0x03, 0xa8, 0xb3, 0x41, 0x30, 0x2f, - 0x72, 0x03, 0x38, 0x0b, 0x0d, 0x16, 0xe6, 0x8b, 0x2e, 0x8e, 0x1d, 0xc9, 0x1a, 0x31, 0x2c, 0x68, - 0xcc, 0x45, 0x98, 0x52, 0x0e, 0xa5, 0xa9, 0xc6, 0xb2, 0x02, 0xa9, 0x05, 0x51, 0x12, 0x99, 0xd0, - 0xa2, 0x13, 0xb4, 0xf0, 0xb9, 0xb4, 0xfd, 0x32, 0x6d, 0x9e, 0x94, 0x2b, 0x4c, 0x53, 0x1c, 0xc2, - 0xf7, 0x65, 0x2f, 0xc9, 0xb4, 0xf9, 0x19, 0x68, 0xcb, 0xb3, 0x6b, 0xf4, 0x00, 0xa6, 0xc5, 0xd9, - 0x35, 0x0f, 0xbd, 0x51, 0xe2, 0x99, 0x02, 0xed, 0x7a, 0x48, 0x9e, 0x85, 0xec, 0xf8, 0xbb, 0xfb, - 0x70, 0x6f, 0x44, 0xb0, 0x06, 0x60, 0x7e, 0xf3, 0x0c, 0xeb, 0x79, 0x73, 0x04, 0x2d, 0x79, 0x60, - 0x97, 0x1c, 0x85, 0xab, 0xdc, 0x35, 0x56, 0x0a, 0x4f, 0x9b, 0x39, 0x3f, 0x75, 0xc0, 0xcc, 0x83, - 0x9a, 0x2f, 0x40, 0xf5, 0x2e, 0xd9, 0xa3, 0x16, 0xc2, 0x1d, 0xa9, 0xb0, 0x10, 0xee, 0x30, 0xfb, - 0xd0, 0x10, 0x07, 0xe7, 0x49, 0x79, 0xe7, 0xa0, 0xb1, 0xc1, 0xcf, 0xe2, 0x0b, 0x5c, 0xa6, 0x20, - 0x33, 0x6f, 0xc2, 0x94, 0x7a, 0x5c, 0x9e, 0xc4, 0x3b, 0x01, 0x53, 0x03, 0xe5, 0x40, 0x9e, 0x0f, - 0x83, 0x9a, 0x65, 0x12, 0x5d, 0x1d, 0x53, 0x08, 0xcb, 0x99, 0x7a, 0xf8, 0x72, 0x66, 0xb7, 0x8f, - 0xd1, 0xc6, 0xbb, 0x70, 0x30, 0x79, 0x2e, 0x9e, 0x94, 0x74, 0x06, 0x0e, 0xae, 0x27, 0x4e, 0xe1, - 0xb9, 0x0f, 0x4c, 0x66, 0x9b, 0x7d, 0xa8, 0xf3, 0x73, 0xcb, 0x24, 0xc4, 0x79, 0xa8, 0x5b, 0xec, - 0x5c, 0xb4, 0xc2, 0x96, 0x16, 0x66, 0x66, 0x2d, 0x19, 0x2b, 0xe6, 0x84, 0xa6, 0x03, 0x07, 0xf4, - 0xa3, 0xd0, 0x24, 0x64, 0x0f, 0x0e, 0xec, 0x6a, 0x47, 0xae, 0x1c, 0x7a, 0x2e, 0x13, 0x5a, 0x83, - 0xc2, 0x3a, 0xa3, 0xf9, 0xb5, 0x06, 0xd4, 0xd8, 0x59, 0x7e, 0x52, 0xc4, 0x15, 0xa8, 0x85, 0xe4, - 0x59, 0xb4, 0x2e, 0x9e, 0x1b, 0x7b, 0x31, 0x80, 0x07, 0x94, 0x19, 0x3d, 0xfa, 0x38, 0x5d, 0xc4, - 0xef, 0x0d, 0xa3, 0xfd, 0xe2, 0x2b, 0xe3, 0x19, 0xd7, 0x28, 0x29, 0xe6, 0x1c, 0x94, 0x95, 0xd9, - 0x82, 0xb8, 0x7b, 0x52, 0xc0, 0xca, 0x8c, 0x10, 0x73, 0x0e, 0x74, 0x13, 0x9a, 0x83, 0x2d, 0x32, - 0x78, 0x42, 0x6c, 0x71, 0xe9, 0xe4, 0xd4, 0x78, 0xe6, 0x45, 0x4e, 0x8c, 0x23, 0x2e, 0x2a, 0x7b, - 0xc0, 0x46, 0xb7, 0x31, 0x89, 0x6c, 0x36, 0xe2, 0x98, 0x73, 0xa0, 0x65, 0x68, 0x3b, 0x03, 0xcf, - 0x5d, 0xde, 0xf6, 0x3e, 0xe7, 0x88, 0xdb, 0x25, 0xaf, 0x8e, 0x67, 0xef, 0x47, 0xe4, 0x38, 0xe6, - 0x8c, 0x60, 0xfa, 0xdb, 0x74, 0x57, 0xda, 0x9a, 0x14, 0x86, 0x91, 0xe3, 0x98, 0xd3, 0x9c, 0x15, - 0xe3, 0x99, 0x6d, 0xe4, 0xb7, 0xa1, 0xce, 0xba, 0x1c, 0x5d, 0x57, 0x8b, 0x67, 0x14, 0x49, 0xb9, - 0x1e, 0x4b, 0x0c, 0x95, 0xc4, 0x61, 0xfd, 0xaf, 0xe3, 0x4c, 0x4d, 0x82, 0x23, 0xc6, 0x8d, 0xe3, - 0xbc, 0x04, 0x4d, 0x31, 0x14, 0x7a, 0x85, 0x5b, 0x11, 0xc1, 0x8b, 0x50, 0xe7, 0x86, 0x99, 0xdd, - 0x9e, 0x97, 0xa1, 0x2d, 0x3b, 0x73, 0x3c, 0x09, 0xeb, 0x9d, 0x1c, 0x92, 0x6f, 0x55, 0xa0, 0xce, - 0xef, 0x34, 0xa4, 0x5d, 0xad, 0x6a, 0x05, 0xaf, 0x8c, 0xbf, 0x22, 0xa1, 0x9a, 0xc1, 0x6d, 0xb6, - 0x39, 0xa4, 0x6b, 0x79, 0x79, 0x4f, 0xf9, 0x4c, 0x01, 0xf7, 0x6a, 0x44, 0x8f, 0x63, 0xd6, 0x82, - 0xe1, 0x7c, 0x00, 0x6d, 0xc9, 0x85, 0x16, 0xf4, 0x21, 0x3d, 0x3b, 0x76, 0x28, 0x92, 0x22, 0x05, - 0xe0, 0xaf, 0x94, 0xa1, 0xba, 0xe4, 0xec, 0xa6, 0xfa, 0xe1, 0xad, 0xc8, 0xaa, 0x8b, 0xdc, 0xc1, - 0x92, 0xb3, 0xab, 0x19, 0xb5, 0xb9, 0x1c, 0x69, 0xdc, 0x3b, 0x7a, 0xf5, 0x4e, 0x8f, 0x5f, 0x81, - 0xc5, 0x30, 0xbc, 0x62, 0xbf, 0xd0, 0x84, 0x1a, 0xbb, 0x2e, 0x94, 0xe5, 0xa7, 0xf6, 0x46, 0xc5, - 0x15, 0x63, 0x07, 0x12, 0x6c, 0xc2, 0x65, 0xf4, 0xdc, 0x4f, 0x59, 0x61, 0xb1, 0x9f, 0xe2, 0xe7, - 0x2b, 0x6a, 0xdc, 0xe1, 0x0a, 0xd4, 0xb6, 0x9d, 0x6d, 0x22, 0xdc, 0x54, 0x81, 0xc8, 0xfb, 0xce, - 0x36, 0xc1, 0x8c, 0x9e, 0xf2, 0x6d, 0x59, 0xc1, 0x96, 0xf0, 0x50, 0x05, 0x7c, 0x3d, 0x2b, 0xd8, - 0xc2, 0x8c, 0x9e, 0xf2, 0xb9, 0x74, 0x17, 0xd9, 0x98, 0x84, 0x8f, 0x6e, 0x2e, 0x31, 0xa3, 0xa7, - 0x7c, 0x81, 0xf3, 0x05, 0x22, 0x7c, 0x52, 0x01, 0xdf, 0x9a, 0xf3, 0x05, 0x82, 0x19, 0x7d, 0xec, - 0xc2, 0x5b, 0x93, 0x75, 0x8d, 0xe2, 0xc2, 0x1f, 0xc2, 0x4c, 0xa8, 0x1d, 0x7a, 0x8b, 0x3b, 0x6b, - 0x67, 0x0b, 0xc6, 0x45, 0xe3, 0xc1, 0x09, 0x0c, 0x6a, 0x04, 0x6c, 0xcf, 0x9c, 0x6d, 0x04, 0x2f, - 0x42, 0xfd, 0x93, 0x8e, 0x1d, 0x6e, 0xe9, 0xc5, 0x75, 0xcd, 0xe5, 0xd1, 0x61, 0xdb, 0x97, 0xcb, - 0x53, 0x47, 0x9d, 0xe3, 0x2c, 0x41, 0x8d, 0xaa, 0xcf, 0xfe, 0xf4, 0x38, 0xd6, 0xba, 0x0f, 0xe5, - 0x80, 0xd5, 0x8e, 0xe6, 0x38, 0xb3, 0x50, 0xa3, 0x1a, 0x92, 0xd3, 0x25, 0xb3, 0x50, 0xa3, 0x7a, - 0x97, 0x5f, 0x4a, 0x47, 0x5b, 0x2f, 0xad, 0x46, 0xa5, 0xa7, 0x61, 0x46, 0x1f, 0x8e, 0x1c, 0x94, - 0x3f, 0x6e, 0x42, 0x8d, 0xdd, 0xbd, 0x4b, 0x5a, 0xe4, 0x27, 0xe0, 0x00, 0x1f, 0xbf, 0x05, 0xb1, - 0x04, 0xaf, 0x64, 0x46, 0xfc, 0xf5, 0x1b, 0x7d, 0x42, 0x05, 0x04, 0x0b, 0xd6, 0x11, 0x26, 0x5f, - 0x54, 0x30, 0x28, 0x4d, 0x23, 0xdf, 0x91, 0x8b, 0xd7, 0x5a, 0xc1, 0xc5, 0x4f, 0xc6, 0xcb, 0x97, - 0xc0, 0xd1, 0x4a, 0x16, 0x2d, 0x40, 0x8b, 0x4e, 0xad, 0xb4, 0xbb, 0x84, 0xd9, 0x9e, 0x1e, 0xcf, - 0xdf, 0x17, 0xd4, 0x58, 0xf2, 0xd1, 0x89, 0x7d, 0x60, 0xf9, 0x36, 0xab, 0x95, 0xb0, 0xe1, 0x57, - 0xc7, 0x83, 0x2c, 0x46, 0xe4, 0x38, 0xe6, 0x44, 0x77, 0x61, 0xca, 0x26, 0x32, 0x4e, 0x20, 0x8c, - 0xfa, 0x63, 0xe3, 0x81, 0x96, 0x62, 0x06, 0xac, 0x72, 0xd3, 0x3a, 0x45, 0x7b, 0xc3, 0xa0, 0x70, - 0xb1, 0xc1, 0xa0, 0xe2, 0x0b, 0xf6, 0x31, 0xa7, 0x79, 0x0a, 0x0e, 0x68, 0xe3, 0xf6, 0x91, 0xae, - 0x3a, 0xd4, 0xb1, 0xe4, 0x38, 0x57, 0xe5, 0x16, 0xe5, 0x0d, 0x7d, 0xd9, 0x91, 0xbb, 0x23, 0x11, - 0x8c, 0xf7, 0xa0, 0x15, 0x0d, 0x0c, 0xba, 0xa5, 0xd7, 0xe1, 0xb5, 0xe2, 0x3a, 0xc8, 0x31, 0x15, - 0x68, 0x2b, 0xd0, 0x96, 0x23, 0x84, 0xe6, 0x75, 0xb8, 0xd7, 0x8b, 0xe1, 0xe2, 0xd1, 0x15, 0x78, - 0x18, 0xa6, 0x94, 0x81, 0x42, 0x8b, 0x3a, 0xe2, 0x1b, 0xc5, 0x88, 0xea, 0x30, 0xc7, 0xab, 0x1e, - 0x39, 0x62, 0xea, 0xa8, 0x54, 0xe3, 0x51, 0xf9, 0xbd, 0x26, 0xb4, 0xe4, 0x7d, 0xd7, 0x8c, 0x3d, - 0xe6, 0x8e, 0x3f, 0x2c, 0xdc, 0x63, 0x46, 0xfc, 0xdd, 0x47, 0xfe, 0x10, 0x53, 0x0e, 0x3a, 0xc4, - 0xa1, 0x13, 0x4a, 0x53, 0x7d, 0xb5, 0x98, 0xf5, 0x21, 0x25, 0xc7, 0x9c, 0x0b, 0x3d, 0xd0, 0xb5, - 0xbc, 0x36, 0xe6, 0x3e, 0x94, 0x06, 0x92, 0xab, 0xe9, 0x7d, 0x68, 0x3b, 0x74, 0xe9, 0xd7, 0x8b, - 0x67, 0xde, 0xd7, 0x8b, 0xe1, 0xfa, 0x11, 0x0b, 0x8e, 0xb9, 0x69, 0xdd, 0x36, 0xac, 0x5d, 0x6a, - 0xd7, 0x0c, 0xac, 0x31, 0x69, 0xdd, 0x6e, 0xc7, 0x4c, 0x58, 0x45, 0x40, 0xd7, 0xc4, 0xda, 0xa5, - 0x59, 0xe0, 0x59, 0xe2, 0xae, 0x8a, 0xd7, 0x2f, 0xef, 0xa5, 0x66, 0x5a, 0x6e, 0xc6, 0xe7, 0x27, - 0x40, 0x19, 0x3b, 0xdb, 0xd2, 0x11, 0xe4, 0x2b, 0xa3, 0xf6, 0xa4, 0x23, 0xa8, 0xae, 0x8e, 0xcc, - 0x17, 0xa0, 0xfa, 0xc8, 0x1f, 0xe6, 0xcf, 0xd5, 0x6c, 0xb8, 0x73, 0x8a, 0x5f, 0xd1, 0x2d, 0x21, - 0x7f, 0x41, 0x2f, 0xc7, 0x24, 0x17, 0x47, 0xe9, 0xf4, 0x1c, 0xa2, 0xeb, 0x62, 0x42, 0xbf, 0xac, - 0xdb, 0xdb, 0x4b, 0x09, 0x7b, 0xa3, 0x16, 0xb6, 0xea, 0x13, 0x7e, 0xe5, 0x4f, 0x99, 0xc9, 0x27, - 0x9d, 0x27, 0xef, 0x44, 0xeb, 0x8f, 0x7d, 0x79, 0x8a, 0x64, 0xdf, 0x72, 0xac, 0x6f, 0x94, 0xa1, - 0x25, 0xaf, 0x33, 0xa7, 0xa3, 0xf3, 0x2d, 0x27, 0xe8, 0x11, 0xcb, 0x26, 0xbe, 0xb0, 0xdb, 0xd7, - 0x0a, 0xef, 0x49, 0x77, 0xfb, 0x82, 0x03, 0x4b, 0x5e, 0xf3, 0x04, 0xb4, 0xa2, 0xdc, 0x9c, 0x4d, - 0xd9, 0x0f, 0x2b, 0xd0, 0x10, 0x17, 0xa1, 0x93, 0x95, 0xb8, 0x01, 0x8d, 0xa1, 0xb5, 0xe7, 0xed, - 0x44, 0x5b, 0xa6, 0xd3, 0x05, 0x77, 0xab, 0xbb, 0xf7, 0x18, 0x35, 0x16, 0x5c, 0xe8, 0x6d, 0xa8, - 0x0f, 0x9d, 0x6d, 0x27, 0x14, 0xee, 0xe3, 0x54, 0x21, 0x3b, 0xbb, 0x32, 0xc5, 0x79, 0xa8, 0x70, - 0x76, 0xff, 0x31, 0xfa, 0x7a, 0xa5, 0x50, 0xf8, 0x63, 0x46, 0x8d, 0x05, 0x97, 0x79, 0x07, 0x1a, - 0xbc, 0x3a, 0xfb, 0x9b, 0x24, 0xf4, 0x96, 0xc4, 0x9a, 0xce, 0xea, 0x96, 0xb3, 0x2a, 0x3d, 0x0e, - 0x0d, 0x2e, 0x3c, 0x47, 0x6b, 0x7e, 0xf0, 0x3c, 0xdb, 0xef, 0x0c, 0xcd, 0x7b, 0xf1, 0x81, 0xe3, - 0x87, 0x3f, 0xcb, 0x30, 0x1f, 0xc2, 0xc1, 0x25, 0x2b, 0xb4, 0xd6, 0xad, 0x80, 0x60, 0x32, 0xf0, - 0x7c, 0x3b, 0x13, 0xd5, 0xe7, 0x45, 0x22, 0x42, 0x9d, 0x8f, 0x2a, 0xe8, 0x7e, 0x16, 0x3a, 0xfc, - 0xaf, 0x13, 0x3a, 0xfc, 0xfd, 0x5a, 0x4e, 0x3c, 0x6f, 0x92, 0x48, 0x06, 0x55, 0xb8, 0x54, 0x40, - 0xef, 0x9a, 0xbe, 0xf6, 0x3e, 0x59, 0xc0, 0xa9, 0x2d, 0xbe, 0xaf, 0xe9, 0x11, 0xbd, 0x22, 0x5e, - 0x2d, 0xa4, 0x77, 0x2b, 0x19, 0xd2, 0x3b, 0x5d, 0xc0, 0x9d, 0x8a, 0xe9, 0x5d, 0xd3, 0x63, 0x7a, - 0x45, 0xd2, 0xd5, 0xa0, 0xde, 0xff, 0xb0, 0x30, 0xda, 0xaf, 0xe6, 0x84, 0x7d, 0x3e, 0xae, 0x87, - 0x7d, 0xc6, 0x68, 0xcd, 0x4f, 0x2b, 0xee, 0xf3, 0x6b, 0x8d, 0x9c, 0xb8, 0xcf, 0x55, 0x2d, 0xee, - 0x33, 0xa6, 0x66, 0xc9, 0xc0, 0xcf, 0x35, 0x3d, 0xf0, 0x73, 0xb2, 0x80, 0x53, 0x8b, 0xfc, 0x5c, - 0xd5, 0x22, 0x3f, 0x45, 0x42, 0x95, 0xd0, 0xcf, 0x55, 0x2d, 0xf4, 0x53, 0xc4, 0xa8, 0xc4, 0x7e, - 0xae, 0x6a, 0xb1, 0x9f, 0x22, 0x46, 0x25, 0xf8, 0x73, 0x55, 0x0b, 0xfe, 0x14, 0x31, 0x2a, 0xd1, - 0x9f, 0x6b, 0x7a, 0xf4, 0xa7, 0xb8, 0x7f, 0x94, 0x41, 0xff, 0x59, 0xa0, 0xe6, 0x3f, 0x30, 0x50, - 0xf3, 0xf3, 0xd5, 0x9c, 0x00, 0x0c, 0xce, 0x0e, 0xc0, 0x9c, 0xcd, 0x1f, 0xc9, 0xe2, 0x08, 0xcc, - 0xe4, 0xb3, 0x40, 0x3a, 0x04, 0x73, 0x3d, 0x11, 0x82, 0x39, 0x55, 0xc0, 0xac, 0xc7, 0x60, 0xfe, - 0xdb, 0x04, 0x19, 0x7e, 0xa7, 0x31, 0x66, 0x3f, 0xfd, 0x96, 0xba, 0x9f, 0x1e, 0x33, 0x93, 0xa5, - 0x37, 0xd4, 0x37, 0xf4, 0x0d, 0xf5, 0x99, 0x09, 0x78, 0xb5, 0x1d, 0xf5, 0x6a, 0xd6, 0x8e, 0xba, - 0x3b, 0x01, 0x4a, 0xee, 0x96, 0xfa, 0x4e, 0x7a, 0x4b, 0x7d, 0x76, 0x02, 0xbc, 0xcc, 0x3d, 0xf5, - 0x6a, 0xd6, 0x9e, 0x7a, 0x92, 0xda, 0xe5, 0x6e, 0xaa, 0xdf, 0xd6, 0x36, 0xd5, 0xaf, 0x4e, 0xd2, - 0x5d, 0xf1, 0xe4, 0xf0, 0xa9, 0x9c, 0x5d, 0xf5, 0x9b, 0x93, 0xc0, 0x8c, 0x0f, 0x62, 0xff, 0x6c, - 0x5f, 0xac, 0x8b, 0xf9, 0xed, 0x97, 0xa0, 0x15, 0x5d, 0xb4, 0x31, 0x3f, 0x0f, 0xcd, 0xe8, 0xeb, - 0xd7, 0x8c, 0xdb, 0xbd, 0x62, 0x53, 0xc7, 0x57, 0xcf, 0x22, 0x85, 0x6e, 0x40, 0x8d, 0xfe, 0x12, - 0x66, 0xf1, 0xda, 0x64, 0x17, 0x7a, 0xa8, 0x10, 0xcc, 0xf8, 0xcc, 0x7f, 0x39, 0x02, 0xa0, 0x7c, - 0x14, 0x38, 0xa9, 0xd8, 0x77, 0xa9, 0x33, 0x1b, 0x86, 0xc4, 0x67, 0x17, 0xb9, 0x0a, 0x3f, 0x9a, - 0x8b, 0x25, 0x50, 0x6d, 0x09, 0x89, 0x8f, 0x05, 0x3b, 0xba, 0x0f, 0xad, 0x28, 0x90, 0xca, 0xae, - 0x49, 0xe7, 0x29, 0x59, 0x16, 0x54, 0x14, 0xda, 0xc3, 0x12, 0x02, 0xcd, 0x43, 0x2d, 0xf0, 0xfc, - 0x50, 0xdc, 0xa9, 0x7e, 0x63, 0x62, 0xa8, 0x35, 0xcf, 0x0f, 0x31, 0x63, 0xe5, 0x4d, 0x53, 0xde, - 0x5c, 0xd8, 0x4f, 0xd3, 0x34, 0x8f, 0xfd, 0xcf, 0x55, 0xe9, 0x43, 0x17, 0x85, 0x35, 0x72, 0x1d, - 0x3a, 0x37, 0xf9, 0x28, 0xa9, 0x56, 0x89, 0xc4, 0x22, 0x88, 0x8f, 0x04, 0x5f, 0xdf, 0xbc, 0x06, - 0x9d, 0x81, 0xb7, 0x4b, 0x7c, 0x1c, 0x5f, 0x71, 0x12, 0xb7, 0xd0, 0x52, 0xf9, 0xc8, 0x84, 0xd6, - 0x96, 0x63, 0x93, 0xfe, 0x40, 0xf8, 0xbf, 0x16, 0x96, 0x69, 0x74, 0x17, 0x5a, 0x2c, 0xc6, 0x1e, - 0x45, 0xf8, 0xf7, 0x57, 0x49, 0x1e, 0xea, 0x8f, 0x00, 0xa8, 0x20, 0x26, 0xfc, 0xb6, 0x13, 0xb2, - 0x3e, 0x6c, 0x61, 0x99, 0xa6, 0x15, 0x66, 0xf7, 0xc8, 0xd4, 0x0a, 0x37, 0x79, 0x85, 0x93, 0xf9, - 0xe8, 0x12, 0x3c, 0xc7, 0xf2, 0x12, 0x5b, 0x4c, 0x1e, 0xaa, 0x6f, 0xe1, 0xec, 0x42, 0x76, 0x6f, - 0xce, 0xda, 0xe4, 0x5f, 0x58, 0xb1, 0xe0, 0x5d, 0x1d, 0xc7, 0x19, 0xe8, 0x2c, 0x1c, 0xb2, 0xc9, - 0x86, 0xb5, 0x33, 0x0c, 0x1f, 0x92, 0xed, 0xd1, 0xd0, 0x0a, 0x49, 0xdf, 0x66, 0xcf, 0x3e, 0xb4, - 0x71, 0xba, 0x00, 0x9d, 0x87, 0xc3, 0x22, 0x93, 0x9b, 0x31, 0x1d, 0x8d, 0xbe, 0xcd, 0x5e, 0x41, - 0x68, 0xe3, 0xac, 0x22, 0xf3, 0x07, 0x35, 0x3a, 0xe8, 0x4c, 0xb5, 0xdf, 0x85, 0xaa, 0x65, 0xdb, - 0x62, 0xda, 0xbc, 0xb8, 0x4f, 0x03, 0x11, 0x9f, 0xd6, 0x50, 0x04, 0xb4, 0x2a, 0xaf, 0xdc, 0xf1, - 0x89, 0xf3, 0xca, 0x7e, 0xb1, 0xe4, 0x6b, 0x34, 0x02, 0x87, 0x22, 0xee, 0xf0, 0xaf, 0x31, 0xaa, - 0x3f, 0x19, 0xa2, 0xfc, 0x36, 0x43, 0xe0, 0xa0, 0x3b, 0x50, 0x63, 0x35, 0xe4, 0x13, 0xeb, 0xa5, - 0xfd, 0xe2, 0xdd, 0xe7, 0xf5, 0x63, 0x18, 0xe6, 0x80, 0xdf, 0x7d, 0x53, 0x2e, 0x5c, 0x96, 0xf5, - 0x0b, 0x97, 0x0b, 0x50, 0x77, 0x42, 0xb2, 0x9d, 0xbe, 0x7f, 0x3b, 0x56, 0x55, 0x85, 0xe7, 0xe1, - 0xac, 0x63, 0xef, 0x01, 0xbe, 0x9f, 0xfb, 0xc9, 0xc4, 0x2d, 0xa8, 0x51, 0xf6, 0xd4, 0x5a, 0x72, - 0x12, 0xc1, 0x8c, 0xd3, 0xbc, 0x00, 0x35, 0xda, 0xd8, 0x31, 0xad, 0x13, 0xf5, 0xa9, 0xc8, 0xfa, - 0x2c, 0x4c, 0x41, 0xdb, 0x1b, 0x11, 0x9f, 0x19, 0x86, 0xf9, 0x4f, 0x35, 0xe5, 0x52, 0x5c, 0x5f, - 0xd5, 0xb1, 0xcb, 0xfb, 0xf6, 0x9c, 0xaa, 0x96, 0xe1, 0x84, 0x96, 0xbd, 0xb5, 0x7f, 0xb4, 0x94, - 0x9e, 0xe1, 0x84, 0x9e, 0xfd, 0x04, 0x98, 0x29, 0x4d, 0xbb, 0xa7, 0x69, 0xda, 0x95, 0xfd, 0x23, - 0x6a, 0xba, 0x46, 0x8a, 0x74, 0x6d, 0x49, 0xd7, 0xb5, 0xee, 0x64, 0x43, 0x2e, 0xa7, 0xa6, 0x09, - 0xb4, 0xed, 0x33, 0xb9, 0xda, 0xb6, 0xa0, 0x69, 0xdb, 0x7e, 0x45, 0x7f, 0x44, 0xfa, 0xf6, 0xfd, - 0x1a, 0xd4, 0xe8, 0xf4, 0x88, 0x96, 0x55, 0x5d, 0x7b, 0x73, 0x5f, 0x53, 0xab, 0xaa, 0x67, 0x2b, - 0x09, 0x3d, 0xbb, 0xb4, 0x3f, 0xa4, 0x94, 0x8e, 0xad, 0x24, 0x74, 0x6c, 0x9f, 0x78, 0x29, 0xfd, - 0xea, 0x69, 0xfa, 0x75, 0x61, 0x7f, 0x68, 0x9a, 0x6e, 0x59, 0x45, 0xba, 0x75, 0x4b, 0xd7, 0xad, - 0x09, 0x57, 0x6f, 0x6c, 0xad, 0x32, 0x81, 0x5e, 0xbd, 0x97, 0xab, 0x57, 0x37, 0x34, 0xbd, 0xda, - 0x8f, 0xd8, 0x8f, 0x48, 0xa7, 0x2e, 0xf1, 0x45, 0x67, 0xfe, 0x97, 0x6c, 0x59, 0x8b, 0x4e, 0xf3, - 0x32, 0xb4, 0xe3, 0x57, 0x55, 0x32, 0xae, 0xe7, 0x73, 0xb2, 0x48, 0x6a, 0x94, 0x34, 0x2f, 0x42, - 0x3b, 0x7e, 0x29, 0x25, 0xeb, 0xab, 0x39, 0x56, 0x28, 0xbf, 0x9e, 0x62, 0x29, 0x73, 0x19, 0x0e, - 0xa5, 0xdf, 0x71, 0xc8, 0x88, 0xc3, 0x2b, 0x77, 0xcb, 0xa3, 0xaf, 0x57, 0x94, 0x2c, 0xf3, 0x29, - 0xcc, 0x24, 0x5e, 0x66, 0xd8, 0x37, 0x06, 0xba, 0xa8, 0x2c, 0x91, 0xab, 0x89, 0x6f, 0x71, 0xf5, - 0xdb, 0xf2, 0xf1, 0x42, 0xd8, 0x5c, 0x82, 0x99, 0x82, 0xca, 0x4f, 0x72, 0x59, 0xfe, 0xb3, 0x30, - 0x35, 0xae, 0xee, 0x1f, 0xc1, 0x65, 0xfe, 0x10, 0x3a, 0xa9, 0x57, 0x65, 0x92, 0x62, 0x56, 0x01, - 0x36, 0x25, 0x8d, 0x50, 0xda, 0xf3, 0xfb, 0xf8, 0x74, 0x81, 0xf1, 0x61, 0x05, 0xc3, 0xfc, 0xad, - 0x32, 0x1c, 0x4a, 0x3f, 0x29, 0x33, 0xe9, 0xe6, 0xc7, 0x80, 0x26, 0xc3, 0x92, 0x5f, 0x7c, 0x44, - 0x49, 0x74, 0x1f, 0xa6, 0x83, 0xa1, 0x33, 0x20, 0x8b, 0x5b, 0x96, 0xbb, 0x49, 0x02, 0xb1, 0xa3, - 0x29, 0x78, 0x16, 0x66, 0x2d, 0xe6, 0xc0, 0x1a, 0xbb, 0xf9, 0x14, 0xa6, 0x94, 0x42, 0xf4, 0x0e, - 0x54, 0xbc, 0x51, 0xea, 0x5e, 0x63, 0x3e, 0xe6, 0x83, 0xc8, 0xde, 0x70, 0xc5, 0x1b, 0xa5, 0x4d, - 0x52, 0x35, 0xdf, 0xaa, 0x66, 0xbe, 0xe6, 0x5d, 0x38, 0x94, 0x7e, 0xb5, 0x25, 0xd9, 0x3d, 0xa7, - 0x53, 0x51, 0x02, 0xde, 0x4d, 0xc9, 0x2d, 0xff, 0x55, 0x38, 0x98, 0x7c, 0x8b, 0x25, 0xe3, 0x6b, - 0x9c, 0xf8, 0xa3, 0xa6, 0x28, 0x5c, 0x3f, 0xf7, 0x73, 0x65, 0x98, 0xd1, 0x1b, 0x82, 0x8e, 0x02, - 0xd2, 0x73, 0x56, 0x3c, 0x97, 0x74, 0x4a, 0xe8, 0x39, 0x38, 0xa4, 0xe7, 0xcf, 0xdb, 0x76, 0xa7, - 0x9c, 0x26, 0xa7, 0x6e, 0xab, 0x53, 0x41, 0x06, 0x1c, 0x49, 0xf4, 0x10, 0x73, 0xa2, 0x9d, 0x2a, - 0x7a, 0x1e, 0x9e, 0x4b, 0x96, 0x8c, 0x86, 0xd6, 0x80, 0x74, 0x6a, 0xe6, 0x8f, 0x2b, 0x50, 0x7b, - 0x14, 0x10, 0xdf, 0xfc, 0xc7, 0x4a, 0xf4, 0x95, 0xc6, 0x5b, 0x50, 0x63, 0xcf, 0xa4, 0x28, 0x5f, - 0x50, 0x96, 0x13, 0x5f, 0x50, 0x6a, 0x5f, 0xe1, 0xc5, 0x5f, 0x50, 0xbe, 0x05, 0x35, 0xf6, 0x30, - 0xca, 0xfe, 0x39, 0xbf, 0x5e, 0x86, 0x76, 0xfc, 0x48, 0xc9, 0xbe, 0xf9, 0xd5, 0xaf, 0x42, 0x2a, - 0xfa, 0x57, 0x21, 0xaf, 0x41, 0xdd, 0x67, 0xdf, 0x6f, 0x70, 0x2f, 0x93, 0xfc, 0xd6, 0x84, 0x09, - 0xc4, 0x9c, 0xc4, 0x24, 0x30, 0xa5, 0x3e, 0xc1, 0xb2, 0xff, 0x6a, 0x9c, 0x14, 0xef, 0xaf, 0xf5, - 0xed, 0x60, 0xde, 0xf7, 0xad, 0x3d, 0xa1, 0x98, 0x7a, 0xa6, 0x39, 0x0b, 0xb5, 0x55, 0xc7, 0xdd, - 0xcc, 0xfe, 0x70, 0xd5, 0xfc, 0x83, 0x32, 0x34, 0xc5, 0xe5, 0x5d, 0xf3, 0x2a, 0x54, 0x57, 0xc8, - 0x53, 0x5a, 0x11, 0x71, 0x6d, 0x38, 0x55, 0x91, 0xfb, 0xac, 0x15, 0x82, 0x1e, 0x47, 0x64, 0xe6, - 0x35, 0x39, 0x4d, 0xee, 0x9f, 0xf7, 0x2d, 0xa8, 0xb1, 0x97, 0x53, 0xf6, 0xcf, 0xf9, 0x87, 0x2d, - 0x68, 0xf0, 0xaf, 0x3f, 0xcd, 0xdf, 0x6d, 0x41, 0x83, 0xbf, 0xa6, 0x82, 0x6e, 0x40, 0x33, 0xd8, - 0xd9, 0xde, 0xb6, 0xfc, 0x3d, 0x23, 0xfb, 0x8d, 0x60, 0xed, 0xf1, 0x95, 0xee, 0x1a, 0xa7, 0xc5, - 0x11, 0x13, 0xba, 0x0c, 0xb5, 0x81, 0xb5, 0x41, 0x52, 0xc7, 0xb9, 0x59, 0xcc, 0x8b, 0xd6, 0x06, - 0xc1, 0x8c, 0x1c, 0xdd, 0x82, 0x96, 0x18, 0x96, 0x40, 0xc4, 0x73, 0xc6, 0xcb, 0x8d, 0x06, 0x53, - 0x72, 0x99, 0x77, 0xa0, 0x29, 0x2a, 0x83, 0x6e, 0xca, 0x6f, 0x5f, 0x93, 0x91, 0xe7, 0xcc, 0x26, - 0xc8, 0x67, 0x36, 0xe4, 0x57, 0xb0, 0xdf, 0xa9, 0x40, 0x8d, 0x56, 0xee, 0x43, 0x23, 0xa1, 0xe3, - 0x00, 0x43, 0x2b, 0x08, 0x57, 0x77, 0x86, 0x43, 0x62, 0x8b, 0x2f, 0xec, 0x94, 0x1c, 0x74, 0x06, - 0x0e, 0xf2, 0x54, 0xb0, 0xb5, 0xb6, 0x33, 0x18, 0x10, 0xf9, 0x65, 0x69, 0x32, 0x1b, 0xcd, 0x43, - 0x9d, 0xbd, 0xef, 0x29, 0x56, 0x85, 0xaf, 0x17, 0xf6, 0x6c, 0x77, 0xd5, 0x71, 0x45, 0x6d, 0x38, - 0xa7, 0xe9, 0x41, 0x5b, 0xe6, 0x51, 0x23, 0x1c, 0x39, 0xae, 0xeb, 0xb8, 0x9b, 0x42, 0xa3, 0xa3, - 0x24, 0x9d, 0x74, 0xe8, 0x4f, 0x51, 0xdf, 0x3a, 0x16, 0x29, 0x9a, 0xbf, 0x61, 0x39, 0x43, 0x51, - 0xc5, 0x3a, 0x16, 0x29, 0x8a, 0xb4, 0x23, 0xde, 0xa0, 0xa9, 0xb1, 0x06, 0x46, 0x49, 0xf3, 0x83, - 0xb2, 0xfc, 0x00, 0x3c, 0xeb, 0xe3, 0xcc, 0x54, 0x2c, 0x69, 0x56, 0x0d, 0x68, 0xf3, 0x09, 0x41, - 0x09, 0x51, 0x1f, 0x85, 0x86, 0xe7, 0x0e, 0x1d, 0x97, 0x88, 0xd8, 0x91, 0x48, 0x25, 0xfa, 0xb8, - 0x9e, 0xea, 0x63, 0x51, 0xbe, 0x6c, 0x3b, 0xb4, 0x8a, 0x8d, 0xb8, 0x9c, 0xe7, 0xa0, 0xeb, 0xd0, - 0xb4, 0xc9, 0xae, 0x33, 0x20, 0x81, 0xd1, 0x64, 0xaa, 0xf7, 0xca, 0xd8, 0xbe, 0x5d, 0x62, 0xb4, - 0x38, 0xe2, 0x31, 0x43, 0x68, 0xf0, 0x2c, 0xd9, 0xa4, 0xb2, 0xd2, 0xa4, 0xb8, 0xd2, 0x95, 0x31, - 0x95, 0xae, 0x16, 0x54, 0xba, 0x96, 0xac, 0xf4, 0xdc, 0x97, 0x00, 0x62, 0x75, 0x43, 0x53, 0xd0, - 0x7c, 0xe4, 0x3e, 0x71, 0xbd, 0xa7, 0x6e, 0xa7, 0x44, 0x13, 0x0f, 0x36, 0x36, 0xa8, 0x94, 0x4e, - 0x99, 0x26, 0x28, 0x9d, 0xe3, 0x6e, 0x76, 0x2a, 0x08, 0xa0, 0x41, 0x13, 0xc4, 0xee, 0x54, 0xe9, - 0xef, 0xdb, 0x6c, 0xfc, 0x3a, 0x35, 0x74, 0x0c, 0x0e, 0xf7, 0xdd, 0x81, 0xb7, 0x3d, 0xb2, 0x42, - 0x67, 0x7d, 0x48, 0x1e, 0x13, 0x3f, 0x70, 0x3c, 0xb7, 0x53, 0xa7, 0xb3, 0xd7, 0x0a, 0x09, 0x9f, - 0x7a, 0xfe, 0x93, 0x15, 0x42, 0x6c, 0xf1, 0xbc, 0x4b, 0xa7, 0x61, 0xfe, 0x5b, 0x99, 0x9f, 0x06, - 0x9b, 0xb7, 0x60, 0x5a, 0x7b, 0x2c, 0xc9, 0x88, 0x9f, 0x6e, 0x4f, 0xbc, 0xdc, 0x7e, 0x94, 0xc5, - 0x6b, 0x49, 0xbc, 0x94, 0xe1, 0x29, 0xf3, 0x36, 0x80, 0xf2, 0x44, 0xd2, 0x71, 0x80, 0xf5, 0xbd, - 0x90, 0x04, 0xfc, 0x79, 0x24, 0x0a, 0x51, 0xc3, 0x4a, 0x8e, 0x8a, 0x5f, 0xd1, 0xf0, 0xcd, 0x2b, - 0x00, 0xca, 0x03, 0x49, 0xd4, 0xae, 0x68, 0x6a, 0x21, 0x09, 0x96, 0xcc, 0x36, 0xbb, 0xa2, 0x05, - 0xd1, 0x53, 0x48, 0x51, 0x0d, 0x78, 0xf4, 0x4e, 0xad, 0x01, 0xcb, 0x31, 0x97, 0x01, 0xe2, 0xd7, - 0x80, 0xcc, 0xab, 0xd2, 0x75, 0xbf, 0x01, 0x35, 0xdb, 0x0a, 0x2d, 0xe1, 0x35, 0x9f, 0x4f, 0xcc, - 0x5c, 0x31, 0x0b, 0x66, 0x64, 0xe6, 0x6f, 0x96, 0x61, 0x5a, 0x7d, 0xf9, 0xc8, 0x7c, 0x17, 0x6a, - 0xec, 0xe9, 0xa4, 0x9b, 0x30, 0xad, 0x3e, 0x7d, 0x94, 0x7a, 0xe2, 0x9e, 0xe3, 0xa9, 0xac, 0x58, - 0x63, 0x30, 0xfb, 0xb2, 0x4a, 0x1f, 0x1a, 0xea, 0x3c, 0x34, 0xc5, 0x4b, 0x4a, 0xe6, 0x29, 0x68, - 0xc7, 0x0f, 0x27, 0x51, 0xdf, 0xc1, 0xf3, 0xa3, 0x51, 0x16, 0x49, 0xf3, 0x1f, 0x6a, 0x50, 0x67, - 0xc3, 0x69, 0x7e, 0xb5, 0xa2, 0x6a, 0xa8, 0xf9, 0xe3, 0x72, 0xee, 0x5e, 0xf0, 0xa2, 0xf6, 0x54, - 0xc1, 0x4c, 0xea, 0xc1, 0x30, 0xf1, 0x4e, 0x92, 0xee, 0x58, 0xaf, 0x40, 0xd3, 0xe5, 0x9a, 0x29, - 0x5e, 0x0a, 0x98, 0xcd, 0xe4, 0x12, 0xda, 0x8b, 0x23, 0x62, 0x74, 0x09, 0xea, 0xc4, 0xf7, 0x3d, - 0x9f, 0x99, 0xd4, 0x4c, 0xea, 0xe9, 0xad, 0xf8, 0x4d, 0xa6, 0x65, 0x4a, 0x85, 0x39, 0x31, 0xba, - 0x04, 0xcf, 0x05, 0xdc, 0x8a, 0xf8, 0x9a, 0x32, 0x10, 0xdf, 0x55, 0x0b, 0x6f, 0x93, 0x5d, 0x68, - 0x06, 0x70, 0x30, 0xf9, 0xcc, 0x92, 0x09, 0x2d, 0xbe, 0x36, 0x95, 0x06, 0x22, 0xd3, 0x54, 0xf3, - 0xf8, 0xef, 0x95, 0xd8, 0x2f, 0x2a, 0x39, 0x74, 0xbd, 0xf2, 0x94, 0x41, 0x45, 0xc7, 0xc9, 0xdc, - 0x43, 0xea, 0x99, 0x73, 0x9f, 0x88, 0x66, 0x75, 0xc5, 0xda, 0x4b, 0xaa, 0x1b, 0x28, 0xa3, 0x36, - 0xd4, 0x59, 0xeb, 0x3a, 0x15, 0xd5, 0x57, 0x54, 0x73, 0xac, 0xbd, 0x36, 0x77, 0x11, 0x9a, 0x22, - 0x9f, 0xd2, 0xcf, 0xf3, 0x0e, 0xeb, 0x94, 0xd0, 0x34, 0xb4, 0xd6, 0xc8, 0x70, 0xa3, 0xe7, 0x05, - 0x61, 0xa7, 0x8c, 0x0e, 0x40, 0x9b, 0x19, 0xe0, 0x03, 0x77, 0xb8, 0xd7, 0xa9, 0xcc, 0xbd, 0x07, - 0x6d, 0xd9, 0x8d, 0xa8, 0x05, 0xb5, 0x95, 0x9d, 0xe1, 0xb0, 0x53, 0x62, 0xeb, 0xe1, 0xd0, 0xf3, - 0xa3, 0x68, 0xf8, 0xf2, 0x33, 0x3a, 0xb9, 0x75, 0xca, 0x79, 0x2e, 0xa8, 0x82, 0x3a, 0x30, 0x2d, - 0x84, 0xf3, 0x3a, 0x57, 0xcd, 0xbf, 0x2b, 0x43, 0x5b, 0xbe, 0x42, 0x45, 0x17, 0xa3, 0x91, 0x62, - 0xe5, 0x3b, 0x9f, 0xab, 0x09, 0x15, 0xcb, 0x7f, 0xd4, 0x2a, 0xa1, 0x66, 0xa7, 0x61, 0x46, 0xf8, - 0xf9, 0x68, 0xc4, 0xb9, 0xab, 0x4e, 0xe4, 0xce, 0xdd, 0x91, 0xbd, 0xde, 0x61, 0x76, 0xbd, 0xe8, - 0xb9, 0x2e, 0x19, 0x84, 0xac, 0xef, 0x0f, 0xc2, 0xd4, 0x8a, 0x17, 0xae, 0x7a, 0x41, 0x40, 0x5b, - 0xc6, 0x7b, 0x2a, 0x2e, 0xaf, 0xa0, 0x19, 0x80, 0xe8, 0x82, 0x1b, 0xf5, 0xcc, 0xe6, 0x6f, 0x94, - 0xa1, 0xc1, 0xdf, 0xc6, 0x32, 0x7f, 0xb9, 0x0c, 0x0d, 0xf1, 0x1e, 0xd6, 0x6b, 0xd0, 0xf1, 0x3d, - 0x0a, 0x1c, 0xed, 0x62, 0xfa, 0x4b, 0xa2, 0x95, 0xa9, 0x7c, 0xba, 0xb1, 0xf6, 0x14, 0x55, 0x14, - 0xeb, 0x0e, 0x2d, 0x0f, 0x5d, 0x03, 0xe0, 0xef, 0x6d, 0x3d, 0xdc, 0x93, 0xaf, 0x6d, 0x24, 0xef, - 0xb5, 0x89, 0x17, 0xba, 0xd8, 0x09, 0x90, 0x42, 0x6d, 0x6e, 0xc3, 0xa1, 0xd4, 0x63, 0x49, 0x4a, - 0xb0, 0xe7, 0x0c, 0x1c, 0x24, 0x6a, 0x91, 0x1c, 0x8f, 0x64, 0x36, 0x55, 0x69, 0x2d, 0x4b, 0x68, - 0xbd, 0x9e, 0x39, 0xf7, 0x45, 0x38, 0x80, 0x49, 0x30, 0xf2, 0xdc, 0x80, 0xfc, 0xb4, 0xfe, 0x9d, - 0x49, 0xee, 0x3f, 0x26, 0x99, 0xfb, 0x7e, 0x1d, 0xea, 0x6c, 0x05, 0x6d, 0xfe, 0x79, 0x5d, 0xae, - 0xf5, 0x53, 0x3e, 0xec, 0x82, 0x7a, 0x99, 0x49, 0x75, 0x46, 0xda, 0xe2, 0x5b, 0xbf, 0xc4, 0xf4, - 0x36, 0xb4, 0x46, 0xbe, 0xb7, 0xe9, 0xd3, 0x35, 0x7b, 0x2d, 0xf1, 0xce, 0x95, 0xce, 0xb6, 0x2a, - 0xc8, 0xb0, 0x64, 0x50, 0x75, 0xbd, 0xae, 0xeb, 0xfa, 0x2d, 0x68, 0xdb, 0xbe, 0x37, 0x62, 0x9f, - 0xe1, 0x8b, 0x03, 0xc4, 0x13, 0x39, 0xb8, 0x4b, 0x11, 0x5d, 0xaf, 0x84, 0x63, 0x26, 0x6a, 0x2d, - 0x7c, 0xb0, 0xc5, 0xd9, 0xfd, 0x8b, 0x39, 0xec, 0x5c, 0x3d, 0x7a, 0x25, 0x2c, 0xc8, 0x29, 0x23, - 0x79, 0xc6, 0x18, 0x5b, 0x63, 0x19, 0x97, 0x9f, 0x45, 0x8c, 0x9c, 0x1c, 0x5d, 0x87, 0x56, 0x60, - 0xed, 0x12, 0xf6, 0x78, 0x79, 0x7b, 0x6c, 0x57, 0xac, 0x09, 0xb2, 0x5e, 0x09, 0x4b, 0x16, 0xda, - 0xe4, 0x6d, 0x67, 0x93, 0xef, 0x96, 0xc5, 0x0b, 0xea, 0x79, 0x4d, 0xbe, 0x1f, 0xd1, 0xb1, 0xe7, - 0xee, 0xa3, 0x04, 0xdd, 0xdd, 0xf1, 0x69, 0x61, 0x8a, 0x1f, 0x8d, 0xb3, 0x84, 0x39, 0x05, 0x6d, - 0xd9, 0x45, 0x66, 0x4b, 0x5a, 0x65, 0x0b, 0x1a, 0xbc, 0x05, 0x26, 0x40, 0x2b, 0xaa, 0x10, 0x25, - 0x96, 0xe0, 0xe6, 0x0a, 0xb4, 0xa2, 0x41, 0xcb, 0x79, 0x7a, 0x03, 0x41, 0xcd, 0xf6, 0xc4, 0xb2, - 0xb0, 0x8a, 0xd9, 0x6f, 0x3a, 0xa8, 0xea, 0x2b, 0x5f, 0x6d, 0xf9, 0xe4, 0xd5, 0xdc, 0x7c, 0x74, - 0x27, 0x8b, 0x7a, 0x52, 0x1e, 0x70, 0x98, 0x82, 0x26, 0xde, 0x61, 0x2b, 0xf6, 0x4e, 0x99, 0x66, - 0xd3, 0x6d, 0x60, 0xa7, 0x42, 0x9d, 0xf2, 0xa2, 0xe5, 0x0e, 0xc8, 0x90, 0xad, 0xf2, 0xa4, 0xab, - 0xaf, 0x2d, 0xb4, 0x25, 0xf8, 0xc2, 0xec, 0x5f, 0x7c, 0x70, 0xbc, 0xfc, 0xbd, 0x0f, 0x8e, 0x97, - 0x7f, 0xf8, 0xc1, 0xf1, 0xf2, 0x2f, 0xfe, 0xe8, 0x78, 0xe9, 0x7b, 0x3f, 0x3a, 0x5e, 0xfa, 0xdb, - 0x1f, 0x1d, 0x2f, 0xbd, 0x5f, 0x19, 0xad, 0xaf, 0x37, 0xd8, 0xbd, 0x9a, 0x8b, 0xff, 0x1e, 0x00, - 0x00, 0xff, 0xff, 0x32, 0x1a, 0xcc, 0xe1, 0xa5, 0x68, 0x00, 0x00, + // 6509 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x49, 0x8c, 0x1d, 0x49, + 0x5a, 0xff, 0xdb, 0x97, 0xaf, 0xca, 0xe5, 0xe7, 0x68, 0x2f, 0xd9, 0xd9, 0xd5, 0x6e, 0x77, 0xb5, + 0xed, 0xf6, 0x74, 0xbb, 0x9f, 0xdd, 0x5e, 0x7b, 0xdc, 0xed, 0xa5, 0x36, 0xf7, 0x7b, 0x5e, 0xca, + 0x35, 0x51, 0xb6, 0xa7, 0xa7, 0x67, 0xf4, 0xd7, 0x64, 0xbd, 0x8c, 0xaa, 0xca, 0xf1, 0xab, 0xcc, + 0x37, 0x99, 0x59, 0x65, 0xd7, 0x2c, 0x7f, 0x86, 0x59, 0x18, 0x90, 0x40, 0x2c, 0x42, 0x80, 0xe0, + 0x80, 0x84, 0xe0, 0x86, 0x10, 0x12, 0x17, 0x40, 0x02, 0x21, 0x10, 0x02, 0x06, 0x90, 0x66, 0x24, + 0x0e, 0x5c, 0x60, 0x86, 0x9e, 0x0b, 0x17, 0x0e, 0x73, 0x41, 0x1c, 0x51, 0x2c, 0x19, 0x19, 0x91, + 0xcb, 0xcb, 0x57, 0xd3, 0x3d, 0x2c, 0x62, 0x4e, 0xf5, 0x22, 0xe2, 0xfb, 0x7e, 0x5f, 0x2c, 0xdf, + 0xf7, 0x45, 0xc4, 0x17, 0x91, 0x51, 0x70, 0x74, 0xb4, 0x7e, 0x6e, 0xe4, 0x7b, 0xa1, 0x17, 0x9c, + 0x23, 0xbb, 0xc4, 0x0d, 0x83, 0x2e, 0x4b, 0xa1, 0xa6, 0xe5, 0xee, 0x85, 0x7b, 0x23, 0x62, 0x9e, + 0x1c, 0x3d, 0xd9, 0x3c, 0x37, 0x74, 0xd6, 0xcf, 0x8d, 0xd6, 0xcf, 0x6d, 0x7b, 0x36, 0x19, 0x46, + 0xe4, 0x2c, 0x21, 0xc8, 0xcd, 0xd9, 0x4d, 0xcf, 0xdb, 0x1c, 0x12, 0x5e, 0xb6, 0xbe, 0xb3, 0x71, + 0x2e, 0x08, 0xfd, 0x9d, 0x41, 0xc8, 0x4b, 0xe7, 0xbe, 0xfa, 0xad, 0x32, 0xd4, 0x97, 0x29, 0x3c, + 0xba, 0x00, 0xad, 0x6d, 0x12, 0x04, 0xd6, 0x26, 0x09, 0x8c, 0xf2, 0x89, 0xea, 0x99, 0xa9, 0x0b, + 0x47, 0xbb, 0x42, 0x54, 0x97, 0x51, 0x74, 0xef, 0xf3, 0x62, 0x2c, 0xe9, 0xd0, 0x2c, 0xb4, 0x07, + 0x9e, 0x1b, 0x92, 0x67, 0x61, 0xdf, 0x36, 0x2a, 0x27, 0xca, 0x67, 0xda, 0x38, 0xce, 0x40, 0x97, + 0xa0, 0xed, 0xb8, 0x4e, 0xe8, 0x58, 0xa1, 0xe7, 0x1b, 0xd5, 0x13, 0x65, 0x0d, 0x92, 0x55, 0xb2, + 0x3b, 0x3f, 0x18, 0x78, 0x3b, 0x6e, 0x88, 0x63, 0x42, 0x64, 0x40, 0x33, 0xf4, 0xad, 0x01, 0xe9, + 0xdb, 0x46, 0x8d, 0x21, 0x46, 0x49, 0xf3, 0x4f, 0x2e, 0x43, 0x53, 0xd4, 0x01, 0x3d, 0x0f, 0xcd, + 0x60, 0xc4, 0xa9, 0xbe, 0x5e, 0xe6, 0x64, 0x22, 0x8d, 0x6e, 0xc2, 0x94, 0xc5, 0x61, 0xd7, 0xb6, + 0xbc, 0xa7, 0x46, 0x99, 0x09, 0x7e, 0x21, 0xd1, 0x16, 0x21, 0xb8, 0x4b, 0x49, 0x7a, 0x25, 0xac, + 0x72, 0xa0, 0x3e, 0xcc, 0x88, 0xe4, 0x12, 0x09, 0x2d, 0x67, 0x18, 0x18, 0x7f, 0xc3, 0x41, 0x8e, + 0xe7, 0x80, 0x08, 0xb2, 0x5e, 0x09, 0x27, 0x18, 0xd1, 0xa7, 0xe0, 0x39, 0x91, 0xb3, 0xe8, 0xb9, + 0x1b, 0xce, 0xe6, 0xa3, 0x91, 0x6d, 0x85, 0xc4, 0xf8, 0x16, 0xc7, 0x3b, 0x99, 0x83, 0xc7, 0x69, + 0xbb, 0x9c, 0xb8, 0x57, 0xc2, 0x59, 0x18, 0xe8, 0x36, 0x1c, 0x10, 0xd9, 0x02, 0xf4, 0x6f, 0x39, + 0xe8, 0x8b, 0x39, 0xa0, 0x12, 0x4d, 0x67, 0x43, 0x9f, 0x86, 0xc3, 0x22, 0xe3, 0x9e, 0xe3, 0x3e, + 0x59, 0xdc, 0xb2, 0x86, 0x43, 0xe2, 0x6e, 0x12, 0xe3, 0xef, 0xc6, 0xd7, 0x51, 0x23, 0xee, 0x95, + 0x70, 0x26, 0x08, 0xda, 0x04, 0x23, 0x2b, 0xbf, 0xe7, 0xd8, 0xc4, 0xf8, 0x7b, 0x2e, 0xe0, 0xcc, + 0x44, 0x02, 0x1c, 0x9b, 0x0a, 0xc9, 0x05, 0x43, 0x0f, 0xa0, 0xe3, 0xad, 0x7f, 0x8e, 0x0c, 0xa2, + 0x9e, 0x5f, 0x23, 0xa1, 0xd1, 0x61, 0xf8, 0x2f, 0x27, 0xf0, 0x1f, 0x30, 0xb2, 0x68, 0xcc, 0xba, + 0x6b, 0x24, 0xec, 0x95, 0x70, 0x8a, 0x19, 0x3d, 0x02, 0xa4, 0xe5, 0xcd, 0x6f, 0x13, 0xd7, 0x36, + 0x2e, 0x30, 0xc8, 0x57, 0xc6, 0x43, 0x32, 0xd2, 0x5e, 0x09, 0x67, 0x00, 0xa4, 0x60, 0x1f, 0xb9, + 0x01, 0x09, 0x8d, 0x8b, 0x93, 0xc0, 0x32, 0xd2, 0x14, 0x2c, 0xcb, 0xa5, 0x83, 0xc8, 0x73, 0x31, + 0x19, 0x5a, 0xa1, 0xe3, 0xb9, 0xa2, 0xbe, 0x97, 0x18, 0xf0, 0xa9, 0x6c, 0x60, 0x49, 0x2b, 0x6b, + 0x9c, 0x09, 0x82, 0xfe, 0x1f, 0x1c, 0x49, 0xe4, 0x63, 0xb2, 0xed, 0xed, 0x12, 0xe3, 0x32, 0x43, + 0x3f, 0x5d, 0x84, 0xce, 0xa9, 0x7b, 0x25, 0x9c, 0x0d, 0x83, 0x16, 0x60, 0x3a, 0x2a, 0x60, 0xb0, + 0x57, 0x18, 0xec, 0x6c, 0x1e, 0xac, 0x00, 0xd3, 0x78, 0xa8, 0xd1, 0xf3, 0xf4, 0xe2, 0xd0, 0x0b, + 0x88, 0x31, 0x9f, 0x69, 0xf4, 0x02, 0x82, 0x91, 0x50, 0xa3, 0x57, 0x38, 0xd4, 0x46, 0x06, 0xa1, + 0xef, 0x0c, 0x58, 0x05, 0xa9, 0x16, 0x5d, 0x1d, 0xdf, 0xc8, 0x98, 0x58, 0xa8, 0x52, 0x36, 0x0c, + 0xc2, 0x70, 0x30, 0xd8, 0x59, 0x0f, 0x06, 0xbe, 0x33, 0xa2, 0x79, 0xf3, 0xb6, 0x6d, 0xbc, 0x33, + 0x0e, 0x79, 0x4d, 0x21, 0xee, 0xce, 0xdb, 0x74, 0x74, 0x92, 0x00, 0xe8, 0xd3, 0x80, 0xd4, 0x2c, + 0xd1, 0x7d, 0xd7, 0x19, 0xec, 0xc7, 0x26, 0x80, 0x95, 0x7d, 0x99, 0x01, 0x83, 0x2c, 0x38, 0xac, + 0xe6, 0xae, 0x7a, 0x81, 0x43, 0xff, 0x1a, 0x37, 0x18, 0xfc, 0xeb, 0x13, 0xc0, 0x47, 0x2c, 0x54, + 0xb1, 0xb2, 0xa0, 0x92, 0x22, 0x16, 0xa9, 0x69, 0x13, 0x3f, 0x30, 0x6e, 0x4e, 0x2c, 0x22, 0x62, + 0x49, 0x8a, 0x88, 0xf2, 0x93, 0x5d, 0xf4, 0xae, 0xef, 0xed, 0x8c, 0x02, 0xe3, 0xd6, 0xc4, 0x5d, + 0xc4, 0x19, 0x92, 0x5d, 0xc4, 0x73, 0xd1, 0x15, 0x68, 0xad, 0x0f, 0xbd, 0xc1, 0x13, 0x3a, 0x98, + 0x15, 0x06, 0x69, 0x24, 0x20, 0x17, 0x68, 0xb1, 0x18, 0x3e, 0x49, 0x4b, 0x95, 0x95, 0xfd, 0x5e, + 0x22, 0x43, 0x12, 0x12, 0x31, 0x35, 0xbe, 0x90, 0xc9, 0xca, 0x49, 0xa8, 0xb2, 0x2a, 0x1c, 0x68, + 0x09, 0xa6, 0x36, 0x9c, 0x21, 0x09, 0x1e, 0x8d, 0x86, 0x9e, 0xc5, 0xe7, 0xc9, 0xa9, 0x0b, 0x27, + 0x32, 0x01, 0x6e, 0xc7, 0x74, 0x14, 0x45, 0x61, 0x43, 0x37, 0xa0, 0xbd, 0x6d, 0xf9, 0x4f, 0x82, + 0xbe, 0xbb, 0xe1, 0x19, 0xf5, 0xcc, 0x19, 0x8e, 0x63, 0xdc, 0x8f, 0xa8, 0x7a, 0x25, 0x1c, 0xb3, + 0xd0, 0x79, 0x92, 0x55, 0x6a, 0x8d, 0x84, 0xb7, 0x1d, 0x32, 0xb4, 0x03, 0xa3, 0xc1, 0x40, 0x5e, + 0xca, 0x04, 0x59, 0x23, 0x61, 0x97, 0x93, 0xd1, 0x79, 0x52, 0x67, 0x44, 0xef, 0xc1, 0x73, 0x51, + 0xce, 0xe2, 0x96, 0x33, 0xb4, 0x7d, 0xe2, 0xf6, 0xed, 0xc0, 0x68, 0x66, 0x4e, 0x41, 0x31, 0x9e, + 0x42, 0x4b, 0xa7, 0xc9, 0x0c, 0x08, 0xea, 0x19, 0xa3, 0x6c, 0xd5, 0x24, 0x8d, 0x56, 0xa6, 0x67, + 0x8c, 0xa1, 0x55, 0x62, 0xaa, 0x5d, 0x59, 0x20, 0xc8, 0x86, 0x63, 0x51, 0xfe, 0x82, 0x35, 0x78, + 0xb2, 0xe9, 0x7b, 0x3b, 0xae, 0xbd, 0xe8, 0x0d, 0x3d, 0xdf, 0x68, 0x67, 0x4e, 0x6e, 0x31, 0x7e, + 0x82, 0xbe, 0x57, 0xc2, 0x79, 0x50, 0x68, 0x11, 0xa6, 0xa3, 0xa2, 0x87, 0xe4, 0x59, 0x68, 0x40, + 0xe6, 0x3c, 0x1f, 0x43, 0x53, 0x22, 0xea, 0x20, 0x55, 0x26, 0x15, 0x84, 0xaa, 0x84, 0x31, 0x55, + 0x00, 0x42, 0x89, 0x54, 0x10, 0x9a, 0x56, 0x41, 0xe8, 0x14, 0x6c, 0x1c, 0x28, 0x00, 0xa1, 0x44, + 0x2a, 0x08, 0x4d, 0xd3, 0xa9, 0x5a, 0xb6, 0xd4, 0xf3, 0x9e, 0x50, 0x7d, 0x32, 0x66, 0x32, 0xa7, + 0x6a, 0xa5, 0xb7, 0x04, 0x21, 0x9d, 0xaa, 0x93, 0xcc, 0x74, 0x25, 0x14, 0xe5, 0xcd, 0x0f, 0x9d, + 0x4d, 0xd7, 0x38, 0x38, 0x46, 0x97, 0x29, 0x1a, 0xa3, 0xa2, 0x2b, 0x21, 0x8d, 0x0d, 0xdd, 0x12, + 0x66, 0xb9, 0x46, 0xc2, 0x25, 0x67, 0xd7, 0x38, 0x94, 0x39, 0x0d, 0xc5, 0x28, 0x4b, 0xce, 0xae, + 0xb4, 0x4b, 0xce, 0xa2, 0x36, 0x2d, 0x9a, 0xe4, 0x8c, 0x23, 0x05, 0x4d, 0x8b, 0x08, 0xd5, 0xa6, + 0x45, 0x79, 0x6a, 0xd3, 0xee, 0x59, 0x21, 0x79, 0x66, 0x3c, 0x5f, 0xd0, 0x34, 0x46, 0xa5, 0x36, + 0x8d, 0x65, 0xd0, 0xd9, 0x2d, 0xca, 0x78, 0x4c, 0xfc, 0xd0, 0x19, 0x58, 0x43, 0xde, 0x55, 0x27, + 0x33, 0xe7, 0xa0, 0x18, 0x4f, 0xa3, 0xa6, 0xb3, 0x5b, 0x26, 0x8c, 0xda, 0xf0, 0x87, 0xd6, 0xfa, + 0x90, 0x60, 0xef, 0xa9, 0x71, 0xaa, 0xa0, 0xe1, 0x11, 0xa1, 0xda, 0xf0, 0x28, 0x4f, 0xf5, 0x2d, + 0x9f, 0x74, 0xec, 0x4d, 0x12, 0x1a, 0x67, 0x0a, 0x7c, 0x0b, 0x27, 0x53, 0x7d, 0x0b, 0xcf, 0x91, + 0x1e, 0x60, 0xc9, 0x0a, 0xad, 0x5d, 0x87, 0x3c, 0x7d, 0xec, 0x90, 0xa7, 0x74, 0x62, 0x7f, 0x6e, + 0x8c, 0x07, 0x88, 0x68, 0xbb, 0x82, 0x58, 0x7a, 0x80, 0x04, 0x88, 0xf4, 0x00, 0x6a, 0xbe, 0x70, + 0xeb, 0x87, 0xc7, 0x78, 0x00, 0x0d, 0x5f, 0xfa, 0xf8, 0x3c, 0x28, 0x64, 0xc1, 0xd1, 0x54, 0xd1, + 0x03, 0xdf, 0x26, 0xbe, 0xf1, 0x22, 0x13, 0xf2, 0x6a, 0xb1, 0x10, 0x46, 0xde, 0x2b, 0xe1, 0x1c, + 0xa0, 0x94, 0x88, 0x35, 0x6f, 0xc7, 0x1f, 0x10, 0xda, 0x4f, 0xaf, 0x4c, 0x22, 0x42, 0x92, 0xa7, + 0x44, 0xc8, 0x12, 0xb4, 0x0b, 0x2f, 0xca, 0x12, 0x2a, 0x98, 0xcd, 0xa2, 0x4c, 0xba, 0xd8, 0xc1, + 0x9c, 0x66, 0x92, 0xba, 0xe3, 0x25, 0x25, 0xb9, 0x7a, 0x25, 0x3c, 0x1e, 0x16, 0xed, 0xc1, 0x71, + 0x8d, 0x80, 0xcf, 0xf3, 0xaa, 0xe0, 0x57, 0x99, 0xe0, 0x73, 0xe3, 0x05, 0xa7, 0xd8, 0x7a, 0x25, + 0x5c, 0x00, 0x8c, 0x46, 0xf0, 0x82, 0xd6, 0x19, 0x91, 0x61, 0x0b, 0x15, 0xf9, 0x12, 0x93, 0x7b, + 0x76, 0xbc, 0x5c, 0x9d, 0xa7, 0x57, 0xc2, 0xe3, 0x20, 0xe9, 0x8e, 0x2b, 0xb3, 0x98, 0x8e, 0xe4, + 0x17, 0x33, 0x97, 0x3d, 0x39, 0xe2, 0xf8, 0x58, 0xe6, 0x82, 0x65, 0x6a, 0xbe, 0xe8, 0xce, 0x2f, + 0x4f, 0xaa, 0xf9, 0xb2, 0x1f, 0xf3, 0xa0, 0xb4, 0xb1, 0xa3, 0x45, 0x0f, 0x2d, 0x7f, 0x93, 0x84, + 0xbc, 0xa3, 0xfb, 0x36, 0x6d, 0xd4, 0xff, 0x9f, 0x64, 0xec, 0x52, 0x6c, 0xda, 0xd8, 0x65, 0x02, + 0xa3, 0x00, 0x66, 0x35, 0x8a, 0x7e, 0xb0, 0xe8, 0x0d, 0x87, 0x64, 0x10, 0xf5, 0xe6, 0x4f, 0x30, + 0xc1, 0x6f, 0x8c, 0x17, 0x9c, 0x60, 0xea, 0x95, 0xf0, 0x58, 0xd0, 0x54, 0x7b, 0x1f, 0x0c, 0xed, + 0x84, 0xce, 0x18, 0x13, 0xe9, 0x6a, 0x92, 0x2d, 0xd5, 0xde, 0x14, 0x45, 0x4a, 0x57, 0x15, 0x0a, + 0xda, 0xdc, 0x63, 0x93, 0xe8, 0xaa, 0xce, 0x93, 0xd2, 0x55, 0xbd, 0x98, 0xce, 0x6e, 0x3b, 0x01, + 0xf1, 0x19, 0xc6, 0x1d, 0xcf, 0x71, 0x8d, 0x97, 0x32, 0x67, 0xb7, 0x47, 0x01, 0xf1, 0x85, 0x20, + 0x4a, 0x45, 0x67, 0x37, 0x8d, 0x4d, 0xc3, 0xb9, 0x47, 0x36, 0x42, 0xe3, 0x44, 0x11, 0x0e, 0xa5, + 0xd2, 0x70, 0x68, 0x06, 0x9d, 0x29, 0x64, 0xc6, 0x1a, 0xa1, 0xa3, 0x82, 0x2d, 0x77, 0x93, 0x18, + 0x2f, 0x67, 0xce, 0x14, 0x0a, 0x9c, 0x42, 0x4c, 0x67, 0x8a, 0x2c, 0x10, 0xba, 0xf3, 0x97, 0xf9, + 0x74, 0x45, 0xc6, 0xa1, 0xe7, 0x32, 0x77, 0xfe, 0x0a, 0xb4, 0x24, 0xa5, 0x7b, 0x90, 0x34, 0x00, + 0xfa, 0x18, 0xd4, 0x46, 0x8e, 0xbb, 0x69, 0xd8, 0x0c, 0xe8, 0xb9, 0x04, 0xd0, 0xaa, 0xe3, 0x6e, + 0xf6, 0x4a, 0x98, 0x91, 0xa0, 0x77, 0x00, 0x46, 0xbe, 0x37, 0x20, 0x41, 0xb0, 0x42, 0x9e, 0x1a, + 0x84, 0x31, 0x98, 0x49, 0x06, 0x4e, 0xd0, 0x5d, 0x21, 0x74, 0x5e, 0x56, 0xe8, 0xd1, 0x32, 0x1c, + 0x10, 0x29, 0x61, 0xe5, 0x1b, 0x99, 0x8b, 0xbf, 0x08, 0x20, 0x0e, 0x37, 0x69, 0x5c, 0x74, 0xef, + 0x23, 0x32, 0x96, 0x3c, 0x97, 0x18, 0x9b, 0x99, 0x7b, 0x9f, 0x08, 0x84, 0x92, 0xd0, 0x35, 0x96, + 0xc2, 0x81, 0x16, 0x60, 0x3a, 0xdc, 0xf2, 0x89, 0x65, 0xaf, 0x85, 0x56, 0xb8, 0x13, 0x18, 0x6e, + 0xe6, 0x32, 0x8d, 0x17, 0x76, 0x1f, 0x32, 0x4a, 0xba, 0x04, 0x55, 0x79, 0xd0, 0x0a, 0x74, 0xe8, + 0x46, 0xe8, 0x9e, 0xb3, 0xed, 0x84, 0x98, 0x58, 0x83, 0x2d, 0x62, 0x1b, 0x5e, 0xe6, 0x26, 0x8a, + 0x2e, 0x7b, 0xbb, 0x2a, 0x1d, 0x5d, 0xad, 0x24, 0x79, 0x51, 0x0f, 0x66, 0x68, 0xde, 0xda, 0xc8, + 0x1a, 0x90, 0x47, 0x81, 0xb5, 0x49, 0x8c, 0x51, 0xa6, 0x06, 0x32, 0xb4, 0x98, 0x8a, 0x2e, 0x56, + 0x74, 0xbe, 0x08, 0xe9, 0x9e, 0x37, 0xb0, 0x86, 0x1c, 0xe9, 0xf3, 0xf9, 0x48, 0x31, 0x55, 0x84, + 0x14, 0xe7, 0x68, 0x6d, 0xe4, 0x7d, 0x6f, 0x1b, 0xbb, 0x05, 0x6d, 0x14, 0x74, 0x5a, 0x1b, 0x45, + 0x1e, 0xc5, 0x73, 0xbd, 0xd0, 0xd9, 0x70, 0x06, 0xc2, 0x7e, 0x5d, 0xdb, 0xf0, 0x33, 0xf1, 0x56, + 0x14, 0xb2, 0xee, 0x1a, 0x8f, 0x2c, 0xa5, 0x78, 0xd1, 0x43, 0x40, 0x6a, 0x9e, 0x50, 0xaa, 0x80, + 0x21, 0xce, 0x8d, 0x43, 0x94, 0x9a, 0x95, 0xc1, 0x4f, 0x6b, 0x39, 0xb2, 0xf6, 0xe8, 0xf6, 0x76, + 0xc1, 0xf7, 0x2c, 0x7b, 0x60, 0x05, 0xa1, 0x11, 0x66, 0xd6, 0x72, 0x95, 0x93, 0x75, 0x25, 0x1d, + 0xad, 0x65, 0x92, 0x97, 0xe2, 0x6d, 0x93, 0xed, 0x75, 0xe2, 0x07, 0x5b, 0xce, 0x48, 0xd4, 0x71, + 0x27, 0x13, 0xef, 0xbe, 0x24, 0x8b, 0x6b, 0x98, 0xe2, 0xa5, 0x0b, 0x71, 0x16, 0xa7, 0x5e, 0xdb, + 0x73, 0x07, 0x5c, 0x19, 0x05, 0xe8, 0xd3, 0xcc, 0x85, 0x38, 0xd3, 0x8c, 0x6e, 0x4c, 0x1c, 0x43, + 0x67, 0xc3, 0xa0, 0xf7, 0xe1, 0x30, 0x2b, 0x98, 0xdf, 0x09, 0x3d, 0xbe, 0xfe, 0x9d, 0xb7, 0x6d, + 0x62, 0x1b, 0x5f, 0xc8, 0xdc, 0x49, 0x73, 0xf8, 0x04, 0x2d, 0x8b, 0xa5, 0x64, 0x60, 0xa0, 0xbb, + 0x70, 0x70, 0x74, 0x61, 0xa4, 0xd5, 0xfa, 0x59, 0xe6, 0xa2, 0x7c, 0xf5, 0xc2, 0x6a, 0xb2, 0xba, + 0x49, 0x4e, 0x6a, 0xc6, 0xce, 0xf6, 0xc8, 0xf3, 0xc3, 0xdb, 0x8e, 0xeb, 0x04, 0x5b, 0xc6, 0x5e, + 0xa6, 0x19, 0xf7, 0x19, 0x49, 0x97, 0xd3, 0x50, 0x33, 0x56, 0x79, 0xd0, 0x25, 0x68, 0x0e, 0xb6, + 0x2c, 0x5a, 0x3b, 0xe3, 0x2b, 0x3c, 0x98, 0x7c, 0x2c, 0xc1, 0xbf, 0xb8, 0x65, 0x85, 0x22, 0xfc, + 0x12, 0x91, 0xa2, 0xeb, 0x00, 0xf4, 0xa7, 0x68, 0xc1, 0x4f, 0x96, 0x33, 0xfd, 0x20, 0x63, 0x94, + 0xb5, 0x57, 0x18, 0xd0, 0x7b, 0xf0, 0x5c, 0x9c, 0xa2, 0x0e, 0x80, 0xc7, 0x13, 0xbe, 0x5a, 0xce, + 0xf4, 0xe4, 0x0a, 0x8e, 0xa4, 0xed, 0x95, 0x70, 0x16, 0x04, 0x9d, 0x80, 0xe3, 0xec, 0xe8, 0xb0, + 0x25, 0x76, 0x74, 0x3f, 0x55, 0xce, 0x0c, 0x8b, 0x29, 0x12, 0x52, 0x3c, 0x74, 0x02, 0x1e, 0x03, + 0x99, 0x94, 0xe8, 0xf2, 0xf0, 0x9f, 0x94, 0xf8, 0xcd, 0x09, 0x24, 0x26, 0x78, 0x92, 0x12, 0x13, + 0xc5, 0x51, 0xe7, 0x8b, 0xb5, 0xcc, 0xd7, 0xc6, 0x74, 0xbe, 0x5c, 0xb7, 0x28, 0x0c, 0xe8, 0x1e, + 0x1c, 0xa4, 0x29, 0x0a, 0x46, 0xc4, 0x00, 0x7e, 0xa3, 0x9c, 0xa9, 0x83, 0x4a, 0x25, 0x19, 0x35, + 0xd5, 0xc1, 0x04, 0x2b, 0x5d, 0xc2, 0x8e, 0x76, 0x82, 0xad, 0x65, 0x77, 0xe0, 0xef, 0xb1, 0xb8, + 0xde, 0x5d, 0xb2, 0x27, 0x50, 0x7f, 0xba, 0x9c, 0xb9, 0xeb, 0x59, 0x4d, 0x92, 0xc7, 0x3a, 0x92, + 0x07, 0xb5, 0xd0, 0x84, 0xfa, 0xae, 0x35, 0xdc, 0x21, 0xe6, 0x2f, 0x36, 0xa0, 0x46, 0xab, 0x65, + 0xfe, 0x73, 0x19, 0xaa, 0x54, 0x13, 0x67, 0xa0, 0xe2, 0xd8, 0x06, 0x3f, 0xbe, 0xaa, 0x38, 0x36, + 0x32, 0xa0, 0xe9, 0xd1, 0xcd, 0x83, 0x3c, 0x4c, 0x8b, 0x92, 0x68, 0x0e, 0xa6, 0xad, 0x8d, 0x90, + 0xf8, 0x0f, 0x44, 0x71, 0x83, 0x15, 0x6b, 0x79, 0xd4, 0x1a, 0xc4, 0xc1, 0x9c, 0x88, 0x28, 0x9a, + 0x89, 0xc3, 0x36, 0x2a, 0x3b, 0xd2, 0x81, 0x88, 0x14, 0x1d, 0x85, 0x46, 0xb0, 0xb3, 0xde, 0xb7, + 0x03, 0xa3, 0x76, 0xa2, 0x7a, 0xa6, 0x8d, 0x45, 0x0a, 0xbd, 0x0d, 0xd3, 0x36, 0x19, 0x11, 0xd7, + 0x26, 0xee, 0xc0, 0x21, 0x81, 0x51, 0x67, 0x47, 0x82, 0xc7, 0xba, 0xfc, 0x38, 0xb1, 0x1b, 0x1d, + 0x27, 0x76, 0xd7, 0xd8, 0x71, 0x22, 0xd6, 0x88, 0xcd, 0xf3, 0xd0, 0x10, 0x03, 0x96, 0x6c, 0x62, + 0x2c, 0xae, 0xa2, 0x8a, 0x33, 0x37, 0xa0, 0x21, 0x06, 0x25, 0xc9, 0xa1, 0x34, 0xab, 0xf2, 0xc3, + 0x34, 0xab, 0xaa, 0xc9, 0xf9, 0x32, 0x1c, 0x4c, 0x9a, 0x5d, 0x52, 0xe0, 0x02, 0xb4, 0x7d, 0x69, + 0xd6, 0x95, 0x84, 0xdf, 0x4c, 0x89, 0xec, 0x4a, 0x20, 0x1c, 0xb3, 0xe5, 0x8a, 0xff, 0x34, 0x1c, + 0xcb, 0xb3, 0xc5, 0x0e, 0x54, 0x1d, 0x9b, 0x1f, 0xbd, 0xb6, 0x31, 0xfd, 0x49, 0x41, 0x9c, 0x80, + 0x52, 0xb0, 0x5a, 0xb4, 0xb0, 0x48, 0x4d, 0x02, 0x9e, 0x34, 0xbb, 0x0f, 0x0f, 0xfe, 0x08, 0xa6, + 0x14, 0x6b, 0x42, 0x5d, 0xa8, 0x07, 0xf4, 0x87, 0x38, 0x5e, 0x35, 0x32, 0x3a, 0x88, 0x11, 0x62, + 0x4e, 0x96, 0x3b, 0xee, 0x7f, 0xdc, 0x80, 0xa6, 0x38, 0xf1, 0x33, 0x57, 0xa0, 0xc6, 0xce, 0x5f, + 0x0f, 0x43, 0xdd, 0x71, 0x6d, 0xf2, 0x8c, 0x61, 0xd7, 0x31, 0x4f, 0xa0, 0xf3, 0xd0, 0x14, 0xa7, + 0x7f, 0x62, 0x50, 0xf2, 0xce, 0x92, 0x23, 0x32, 0xf3, 0x7d, 0x68, 0x46, 0xe7, 0xb0, 0xb3, 0xd0, + 0x1e, 0xf9, 0x1e, 0x5d, 0xd3, 0xf4, 0xa3, 0xa1, 0x8e, 0x33, 0xd0, 0x9b, 0xd0, 0xb4, 0xc5, 0x49, + 0x6f, 0x45, 0x4c, 0x23, 0x39, 0x6a, 0x1e, 0xd1, 0x99, 0x5f, 0x29, 0x43, 0x83, 0x1f, 0xc7, 0x9a, + 0xbb, 0x52, 0x75, 0x2f, 0x43, 0x63, 0xc0, 0xf2, 0x8c, 0xe4, 0x51, 0xac, 0x56, 0x43, 0x71, 0xbe, + 0x8b, 0x05, 0x31, 0x65, 0x0b, 0xb8, 0xc3, 0xad, 0x8c, 0x65, 0xe3, 0x63, 0x89, 0x05, 0xf1, 0x7f, + 0x9b, 0xdc, 0x7f, 0xa8, 0xc0, 0x01, 0xfd, 0x94, 0x77, 0x16, 0xda, 0x03, 0x79, 0x6e, 0x2c, 0x7a, + 0x57, 0x66, 0xa0, 0x07, 0x00, 0x83, 0xa1, 0x43, 0xdc, 0x90, 0x9d, 0x33, 0x54, 0x32, 0xb7, 0xaf, + 0x99, 0x87, 0xbe, 0xdd, 0x45, 0xc9, 0x86, 0x15, 0x08, 0x74, 0x13, 0xea, 0xc1, 0xc0, 0x1b, 0x71, + 0x37, 0x37, 0xa3, 0xc4, 0x33, 0xf4, 0x6a, 0xcf, 0xef, 0x84, 0x5b, 0x7c, 0x89, 0x3c, 0x3f, 0x72, + 0xd6, 0x28, 0x03, 0xe6, 0x7c, 0xe6, 0x2f, 0x95, 0x01, 0x62, 0x6c, 0x74, 0x42, 0x6e, 0x49, 0x56, + 0xac, 0xed, 0xa8, 0x01, 0x6a, 0x96, 0x42, 0xb1, 0x6a, 0x85, 0x5b, 0xc2, 0x39, 0xab, 0x59, 0x08, + 0x41, 0xcd, 0xa5, 0xcc, 0xfc, 0xca, 0x02, 0xfb, 0x8d, 0xce, 0xc2, 0xa1, 0xc0, 0xd9, 0x74, 0xad, + 0x70, 0xc7, 0x27, 0x8f, 0x89, 0xef, 0x6c, 0x38, 0xc4, 0x66, 0x75, 0x6e, 0xe1, 0x74, 0x81, 0xf9, + 0x26, 0x1c, 0x4a, 0x1f, 0x6b, 0x8f, 0xed, 0x59, 0xf3, 0x67, 0xda, 0xd0, 0xe0, 0x11, 0x0b, 0xf3, + 0xdf, 0x2b, 0x52, 0xd9, 0xcd, 0xbf, 0x28, 0x43, 0x9d, 0x9f, 0xdc, 0x26, 0x5d, 0xdb, 0x6d, 0x55, + 0xd1, 0xab, 0x19, 0xdb, 0xf9, 0xac, 0x93, 0xec, 0xee, 0x5d, 0xb2, 0xf7, 0x98, 0x4e, 0x60, 0x52, + 0xfb, 0x73, 0x9d, 0xc4, 0x1d, 0x68, 0x45, 0xc4, 0xd4, 0xe5, 0x3c, 0x21, 0x7b, 0x42, 0x38, 0xfd, + 0x89, 0xce, 0x8a, 0x89, 0x50, 0xda, 0x6f, 0xd2, 0xc8, 0xb8, 0x14, 0x31, 0x5b, 0x7e, 0x16, 0xaa, + 0x6b, 0x24, 0x4c, 0x35, 0x61, 0xff, 0xb6, 0x9a, 0x5b, 0xdb, 0x45, 0xa8, 0xf3, 0xd3, 0xf3, 0xa4, + 0x0c, 0x04, 0xb5, 0x27, 0x64, 0x2f, 0x72, 0x55, 0xec, 0x77, 0x2e, 0xc8, 0x9f, 0x55, 0x61, 0x5a, + 0x3d, 0x31, 0x34, 0x97, 0x73, 0xe7, 0x76, 0x36, 0x5b, 0xc7, 0x73, 0xbb, 0x48, 0x52, 0x77, 0xc7, + 0xb0, 0x98, 0x6a, 0xb4, 0x31, 0x4f, 0x98, 0x5d, 0x68, 0x88, 0x83, 0xd8, 0x24, 0x92, 0xa4, 0xaf, + 0xa8, 0xf4, 0x77, 0xa0, 0x25, 0xcf, 0x55, 0x3f, 0xac, 0x6c, 0x1f, 0x5a, 0xf2, 0x00, 0xf5, 0x30, + 0xd4, 0x43, 0x2f, 0xb4, 0x86, 0x0c, 0xae, 0x8a, 0x79, 0x82, 0xea, 0xa5, 0x4b, 0x9e, 0x85, 0x8b, + 0xd2, 0x1d, 0x57, 0x71, 0x9c, 0xc1, 0xbd, 0x2d, 0xd9, 0xe5, 0xa5, 0x55, 0x5e, 0x2a, 0x33, 0x62, + 0x99, 0x35, 0x55, 0xe6, 0x1e, 0x34, 0xc4, 0xa9, 0xaa, 0x2c, 0x2f, 0x2b, 0xe5, 0x68, 0x1e, 0xea, + 0x9b, 0xb4, 0x5c, 0x8c, 0xfa, 0xeb, 0x09, 0xa3, 0xe7, 0xc1, 0x92, 0x45, 0xcf, 0x0d, 0xa9, 0x1a, + 0xeb, 0xc1, 0x62, 0xcc, 0x39, 0xe9, 0x10, 0xfa, 0xfc, 0x88, 0x9c, 0x1b, 0xa1, 0x48, 0x99, 0xbf, + 0x53, 0x86, 0xb6, 0xbc, 0x93, 0x60, 0xbe, 0x9f, 0x67, 0x3c, 0xf3, 0x70, 0xc0, 0x17, 0x54, 0xd4, + 0x50, 0x23, 0x13, 0x7a, 0x21, 0x51, 0x13, 0xac, 0xd0, 0x60, 0x9d, 0xc3, 0x7c, 0x27, 0x77, 0x50, + 0xe7, 0x60, 0x3a, 0x22, 0xbd, 0x1b, 0xab, 0x9e, 0x96, 0x67, 0x9a, 0x92, 0x3b, 0x35, 0x9d, 0x9b, + 0x1b, 0x30, 0xad, 0x9e, 0x4c, 0x9a, 0x8f, 0xb3, 0xad, 0xe7, 0x26, 0x15, 0xa3, 0x9c, 0x82, 0x56, + 0x12, 0xe1, 0x97, 0xa8, 0x09, 0x31, 0x09, 0xd6, 0x18, 0xcc, 0x63, 0x50, 0xe7, 0xf7, 0x25, 0x12, + 0xc8, 0xe6, 0x9f, 0x0f, 0xa0, 0xce, 0x06, 0xc1, 0xbc, 0xc8, 0x0d, 0xe0, 0x2c, 0x34, 0x58, 0xec, + 0x2f, 0xba, 0x4d, 0x76, 0x38, 0x6b, 0xc4, 0xb0, 0xa0, 0x31, 0x17, 0x61, 0x4a, 0x39, 0xa9, 0xa6, + 0x1a, 0xcb, 0x0a, 0xa4, 0x16, 0x44, 0x49, 0x64, 0x42, 0x8b, 0xce, 0xda, 0xc2, 0x0f, 0xd3, 0xf6, + 0xcb, 0xb4, 0x79, 0x52, 0x2e, 0x3b, 0x4d, 0x71, 0x32, 0xdf, 0x97, 0xbd, 0x24, 0xd3, 0xe6, 0x67, + 0xa0, 0x2d, 0x0f, 0xb4, 0xd1, 0x03, 0x98, 0x16, 0x07, 0xda, 0x3c, 0x1e, 0x47, 0x89, 0x67, 0x0a, + 0xb4, 0xeb, 0x21, 0x79, 0x16, 0xb2, 0x33, 0xf1, 0xee, 0xc3, 0xbd, 0x11, 0xc1, 0x1a, 0x80, 0xf9, + 0x8d, 0x33, 0xac, 0xe7, 0xcd, 0x11, 0xb4, 0xe4, 0x29, 0x5e, 0x72, 0x14, 0xae, 0x72, 0xd7, 0x58, + 0x29, 0x3c, 0x82, 0xe6, 0xfc, 0xd4, 0x01, 0x33, 0x0f, 0x6a, 0xbe, 0x00, 0xd5, 0xbb, 0x64, 0x8f, + 0x5a, 0x08, 0x77, 0xa4, 0xc2, 0x42, 0xb8, 0xc3, 0xec, 0x43, 0x43, 0x9c, 0xa6, 0x27, 0xe5, 0x9d, + 0x83, 0xc6, 0x06, 0x3f, 0xa0, 0x2f, 0x70, 0x99, 0x82, 0xcc, 0xbc, 0x09, 0x53, 0xea, 0x19, 0x7a, + 0x12, 0xef, 0x04, 0x4c, 0x0d, 0x94, 0x53, 0x7a, 0x3e, 0x0c, 0x6a, 0x96, 0x49, 0x74, 0x75, 0x4c, + 0x21, 0x2c, 0x67, 0xea, 0xe1, 0xcb, 0x99, 0xdd, 0x3e, 0x46, 0x1b, 0xef, 0xc2, 0xc1, 0xe4, 0x61, + 0x79, 0x52, 0xd2, 0x19, 0x38, 0xb8, 0x9e, 0x38, 0x9a, 0xe7, 0x3e, 0x30, 0x99, 0x6d, 0xf6, 0xa1, + 0xce, 0x0f, 0x33, 0x93, 0x10, 0xe7, 0xa1, 0x6e, 0xb1, 0xc3, 0xd2, 0x0a, 0x5b, 0x6f, 0x98, 0x99, + 0xb5, 0x64, 0xac, 0x98, 0x13, 0x9a, 0x0e, 0x1c, 0xd0, 0xcf, 0x47, 0x93, 0x90, 0x3d, 0x38, 0xb0, + 0xab, 0x9d, 0xc3, 0x72, 0xe8, 0xb9, 0x4c, 0x68, 0x0d, 0x0a, 0xeb, 0x8c, 0xe6, 0x57, 0x1b, 0x50, + 0x63, 0x07, 0xfc, 0x49, 0x11, 0x57, 0xa0, 0x16, 0x92, 0x67, 0xd1, 0x62, 0x79, 0x6e, 0xec, 0x6d, + 0x01, 0x1e, 0x65, 0x66, 0xf4, 0xe8, 0xe3, 0x74, 0x65, 0xbf, 0x37, 0x8c, 0x36, 0x91, 0xaf, 0x8c, + 0x67, 0x5c, 0xa3, 0xa4, 0x98, 0x73, 0x50, 0x56, 0x66, 0x0b, 0xe2, 0x42, 0x4a, 0x01, 0x2b, 0x33, + 0x42, 0xcc, 0x39, 0xd0, 0x4d, 0x68, 0x0e, 0xb6, 0xc8, 0xe0, 0x09, 0xb1, 0xc5, 0x4d, 0x94, 0x53, + 0xe3, 0x99, 0x17, 0x39, 0x31, 0x8e, 0xb8, 0xa8, 0xec, 0x01, 0x1b, 0xdd, 0xc6, 0x24, 0xb2, 0xd9, + 0x88, 0x63, 0xce, 0x81, 0x96, 0xa1, 0xed, 0x0c, 0x3c, 0x77, 0x79, 0xdb, 0xfb, 0x9c, 0x23, 0xae, + 0x9c, 0xbc, 0x3a, 0x9e, 0xbd, 0x1f, 0x91, 0xe3, 0x98, 0x33, 0x82, 0xe9, 0x6f, 0xd3, 0xad, 0x6a, + 0x6b, 0x52, 0x18, 0x46, 0x8e, 0x63, 0x4e, 0x73, 0x56, 0x8c, 0x67, 0xb6, 0x91, 0xdf, 0x86, 0x3a, + 0xeb, 0x72, 0x74, 0x5d, 0x2d, 0x9e, 0x51, 0x24, 0xe5, 0x7a, 0x2c, 0x31, 0x54, 0x12, 0x87, 0xf5, + 0xbf, 0x8e, 0x33, 0x35, 0x09, 0x8e, 0x18, 0x37, 0x8e, 0xf3, 0x12, 0x34, 0xc5, 0x50, 0xe8, 0x15, + 0x6e, 0x45, 0x04, 0x2f, 0x42, 0x9d, 0x1b, 0x66, 0x76, 0x7b, 0x5e, 0x86, 0xb6, 0xec, 0xcc, 0xf1, + 0x24, 0xac, 0x77, 0x72, 0x48, 0xbe, 0x59, 0x81, 0x3a, 0xbf, 0xe8, 0x90, 0x76, 0xb5, 0xaa, 0x15, + 0xbc, 0x32, 0xfe, 0xde, 0x84, 0x6a, 0x06, 0xb7, 0xd9, 0x8e, 0x91, 0xae, 0xef, 0xe5, 0xe5, 0xe5, + 0x33, 0x05, 0xdc, 0xab, 0x11, 0x3d, 0x8e, 0x59, 0x0b, 0x86, 0xf3, 0x01, 0xb4, 0x25, 0x17, 0x5a, + 0xd0, 0x87, 0xf4, 0xec, 0xd8, 0xa1, 0x48, 0x8a, 0x14, 0x80, 0xbf, 0x52, 0x86, 0xea, 0x92, 0xb3, + 0x9b, 0xea, 0x87, 0xb7, 0x22, 0xab, 0x2e, 0x72, 0x07, 0x4b, 0xce, 0xae, 0x66, 0xd4, 0xe6, 0x72, + 0xa4, 0x71, 0xef, 0xe8, 0xd5, 0x3b, 0x3d, 0x7e, 0x05, 0x16, 0xc3, 0xf0, 0x8a, 0xfd, 0x7c, 0x13, + 0x6a, 0xec, 0x0e, 0x51, 0x96, 0x9f, 0xda, 0x1b, 0x15, 0x57, 0x8c, 0x9d, 0x52, 0xb0, 0x09, 0x97, + 0xd1, 0x73, 0x3f, 0x65, 0x85, 0xc5, 0x7e, 0x8a, 0x1f, 0xba, 0xa8, 0xc1, 0x88, 0x2b, 0x50, 0xdb, + 0x76, 0xc4, 0x66, 0xad, 0x50, 0xe4, 0x7d, 0x67, 0x9b, 0x60, 0x46, 0x4f, 0xf9, 0xb6, 0xac, 0x60, + 0x4b, 0x78, 0xa8, 0x02, 0xbe, 0x9e, 0x15, 0x6c, 0x61, 0x46, 0x4f, 0xf9, 0xd8, 0xe6, 0xb0, 0x31, + 0x09, 0x1f, 0xdd, 0x70, 0x8a, 0x0d, 0xe4, 0x15, 0xa8, 0x05, 0xce, 0x17, 0x88, 0xf0, 0x49, 0x05, + 0x7c, 0x6b, 0xce, 0x17, 0x08, 0x66, 0xf4, 0xb1, 0x0b, 0x6f, 0x4d, 0xd6, 0x35, 0x8a, 0x0b, 0x7f, + 0x08, 0x33, 0xa1, 0x76, 0x12, 0x2e, 0x2e, 0xb2, 0x9d, 0x2d, 0x18, 0x17, 0x8d, 0x07, 0x27, 0x30, + 0xa8, 0x11, 0xb0, 0x7d, 0x74, 0xb6, 0x11, 0xbc, 0x08, 0xf5, 0x4f, 0x3a, 0x76, 0xb8, 0xa5, 0x17, + 0xd7, 0x35, 0x97, 0x47, 0x87, 0x6d, 0x5f, 0x2e, 0x4f, 0x1d, 0x75, 0x8e, 0xb3, 0x04, 0x35, 0xaa, + 0x3e, 0xfb, 0xd3, 0xe3, 0x58, 0xeb, 0x3e, 0x94, 0x03, 0x56, 0x3b, 0x9a, 0xe3, 0xcc, 0x42, 0x8d, + 0x6a, 0x48, 0x4e, 0x97, 0xcc, 0x42, 0x8d, 0xea, 0x5d, 0x7e, 0x29, 0x1d, 0x6d, 0xbd, 0xb4, 0x1a, + 0x95, 0x9e, 0x86, 0x19, 0x7d, 0x38, 0x72, 0x50, 0xfe, 0xb4, 0x09, 0x35, 0x76, 0x21, 0x2f, 0x69, + 0x91, 0x9f, 0x80, 0x03, 0x7c, 0xfc, 0x16, 0xc4, 0x12, 0xbc, 0x92, 0x79, 0x0c, 0xa0, 0x5f, 0xf3, + 0x13, 0x2a, 0x20, 0x58, 0xb0, 0x8e, 0x30, 0xf9, 0xa2, 0x82, 0x41, 0x69, 0x1a, 0xf9, 0x8e, 0x5c, + 0xbc, 0xd6, 0x0a, 0x6e, 0x83, 0x32, 0x5e, 0xbe, 0x04, 0x8e, 0x56, 0xb2, 0x68, 0x01, 0x5a, 0x74, + 0x6a, 0xa5, 0xdd, 0x25, 0xcc, 0xf6, 0xf4, 0x78, 0xfe, 0xbe, 0xa0, 0xc6, 0x92, 0x8f, 0x4e, 0xec, + 0x03, 0xcb, 0xb7, 0x59, 0xad, 0x84, 0x0d, 0xbf, 0x3a, 0x1e, 0x64, 0x31, 0x22, 0xc7, 0x31, 0x27, + 0xba, 0x0b, 0x53, 0x36, 0x91, 0x71, 0x02, 0x61, 0xd4, 0x1f, 0x1b, 0x0f, 0xb4, 0x14, 0x33, 0x60, + 0x95, 0x9b, 0xd6, 0x29, 0xda, 0x1b, 0x06, 0x85, 0x8b, 0x0d, 0x06, 0x15, 0xdf, 0xba, 0x8f, 0x39, + 0xcd, 0x53, 0x70, 0x40, 0x1b, 0xb7, 0x8f, 0x74, 0xd5, 0xa1, 0x8e, 0x25, 0xc7, 0xb9, 0x2a, 0xb7, + 0x28, 0x6f, 0xe8, 0xcb, 0x8e, 0xdc, 0x1d, 0x89, 0x60, 0xbc, 0x07, 0xad, 0x68, 0x60, 0xd0, 0x2d, + 0xbd, 0x0e, 0xaf, 0x15, 0xd7, 0x41, 0x8e, 0xa9, 0x40, 0x5b, 0x81, 0xb6, 0x1c, 0x21, 0x34, 0xaf, + 0xc3, 0xbd, 0x5e, 0x0c, 0x17, 0x8f, 0xae, 0xc0, 0xc3, 0x30, 0xa5, 0x0c, 0x14, 0x5a, 0xd4, 0x11, + 0xdf, 0x28, 0x46, 0x54, 0x87, 0x39, 0x5e, 0xf5, 0xc8, 0x11, 0x53, 0x47, 0xa5, 0x1a, 0x8f, 0xca, + 0xef, 0x37, 0xa1, 0x25, 0x2f, 0xc1, 0x66, 0xec, 0x31, 0x77, 0xfc, 0x61, 0xe1, 0x1e, 0x33, 0xe2, + 0xef, 0x3e, 0xf2, 0x87, 0x98, 0x72, 0xd0, 0x21, 0x0e, 0x9d, 0x50, 0x9a, 0xea, 0xab, 0xc5, 0xac, + 0x0f, 0x29, 0x39, 0xe6, 0x5c, 0xe8, 0x81, 0xae, 0xe5, 0xb5, 0x31, 0x97, 0xa4, 0x34, 0x90, 0x5c, + 0x4d, 0xef, 0x43, 0xdb, 0xa1, 0x4b, 0xbf, 0x5e, 0x3c, 0xf3, 0xbe, 0x5e, 0x0c, 0xd7, 0x8f, 0x58, + 0x70, 0xcc, 0x4d, 0xeb, 0xb6, 0x61, 0xed, 0x52, 0xbb, 0x66, 0x60, 0x8d, 0x49, 0xeb, 0x76, 0x3b, + 0x66, 0xc2, 0x2a, 0x02, 0xba, 0x26, 0xd6, 0x2e, 0xcd, 0x02, 0xcf, 0x12, 0x77, 0x55, 0xbc, 0x7e, + 0x79, 0x2f, 0x35, 0xd3, 0x72, 0x33, 0x3e, 0x3f, 0x01, 0xca, 0xd8, 0xd9, 0x96, 0x8e, 0x20, 0x5f, + 0x19, 0xb5, 0x27, 0x1d, 0x41, 0x75, 0x75, 0x64, 0xbe, 0x00, 0xd5, 0x47, 0xfe, 0x30, 0x7f, 0xae, + 0x66, 0xc3, 0x9d, 0x53, 0xfc, 0x8a, 0x6e, 0x09, 0xf9, 0x0b, 0x7a, 0x39, 0x26, 0xb9, 0x38, 0x4a, + 0xa7, 0xe7, 0x10, 0x5d, 0x17, 0x13, 0xfa, 0x65, 0xdd, 0xde, 0x5e, 0x4a, 0xd8, 0x1b, 0xb5, 0xb0, + 0x55, 0x9f, 0xf0, 0x7b, 0x80, 0xca, 0x4c, 0x3e, 0xe9, 0x3c, 0x79, 0x27, 0x5a, 0x7f, 0xec, 0xcb, + 0x53, 0x24, 0xfb, 0x96, 0x63, 0x7d, 0xbd, 0x0c, 0x2d, 0x79, 0xc7, 0x39, 0x1d, 0x9d, 0x6f, 0x39, + 0x41, 0x8f, 0x58, 0x36, 0xf1, 0x85, 0xdd, 0xbe, 0x56, 0x78, 0x79, 0xba, 0xdb, 0x17, 0x1c, 0x58, + 0xf2, 0x9a, 0x27, 0xa0, 0x15, 0xe5, 0xe6, 0x6c, 0xca, 0xbe, 0x57, 0x81, 0x86, 0xb8, 0x1d, 0x9d, + 0xac, 0xc4, 0x0d, 0x68, 0x0c, 0xad, 0x3d, 0x6f, 0x27, 0xda, 0x32, 0x9d, 0x2e, 0xb8, 0x70, 0xdd, + 0xbd, 0xc7, 0xa8, 0xb1, 0xe0, 0x42, 0x6f, 0x43, 0x7d, 0xe8, 0x6c, 0x3b, 0xa1, 0x70, 0x1f, 0xa7, + 0x0a, 0xd9, 0xd9, 0x3d, 0x2a, 0xce, 0x43, 0x85, 0xb3, 0x4b, 0x91, 0xd1, 0x27, 0x2d, 0x85, 0xc2, + 0x1f, 0x33, 0x6a, 0x2c, 0xb8, 0xcc, 0x3b, 0xd0, 0xe0, 0xd5, 0xd9, 0xdf, 0x24, 0xa1, 0xb7, 0x24, + 0xd6, 0x74, 0x56, 0xb7, 0x9c, 0x55, 0xe9, 0x71, 0x68, 0x70, 0xe1, 0x39, 0x5a, 0xf3, 0xdd, 0xe7, + 0xd9, 0x7e, 0x67, 0x68, 0xde, 0x8b, 0x4f, 0x21, 0x3f, 0xfc, 0x59, 0x86, 0xf9, 0x10, 0x0e, 0x2e, + 0x59, 0xa1, 0xb5, 0x6e, 0x05, 0x04, 0x93, 0x81, 0xe7, 0xdb, 0x99, 0xa8, 0x3e, 0x2f, 0x12, 0x11, + 0xea, 0x7c, 0x54, 0x41, 0xf7, 0xe3, 0xd0, 0xe1, 0xff, 0x9c, 0xd0, 0xe1, 0x1f, 0xd4, 0x72, 0xe2, + 0x79, 0x93, 0x44, 0x32, 0xa8, 0xc2, 0xa5, 0x02, 0x7a, 0xd7, 0xf4, 0xb5, 0xf7, 0xc9, 0x02, 0x4e, + 0x6d, 0xf1, 0x7d, 0x4d, 0x8f, 0xe8, 0x15, 0xf1, 0x6a, 0x21, 0xbd, 0x5b, 0xc9, 0x90, 0xde, 0xe9, + 0x02, 0xee, 0x54, 0x4c, 0xef, 0x9a, 0x1e, 0xd3, 0x2b, 0x92, 0xae, 0x06, 0xf5, 0xfe, 0x8f, 0x85, + 0xd1, 0x7e, 0x35, 0x27, 0xec, 0xf3, 0x71, 0x3d, 0xec, 0x33, 0x46, 0x6b, 0x7e, 0x54, 0x71, 0x9f, + 0x5f, 0x6b, 0xe4, 0xc4, 0x7d, 0xae, 0x6a, 0x71, 0x9f, 0x31, 0x35, 0x4b, 0x06, 0x7e, 0xae, 0xe9, + 0x81, 0x9f, 0x93, 0x05, 0x9c, 0x5a, 0xe4, 0xe7, 0xaa, 0x16, 0xf9, 0x29, 0x12, 0xaa, 0x84, 0x7e, + 0xae, 0x6a, 0xa1, 0x9f, 0x22, 0x46, 0x25, 0xf6, 0x73, 0x55, 0x8b, 0xfd, 0x14, 0x31, 0x2a, 0xc1, + 0x9f, 0xab, 0x5a, 0xf0, 0xa7, 0x88, 0x51, 0x89, 0xfe, 0x5c, 0xd3, 0xa3, 0x3f, 0xc5, 0xfd, 0xa3, + 0x0c, 0xfa, 0x8f, 0x03, 0x35, 0xff, 0x85, 0x81, 0x9a, 0x9f, 0xab, 0xe6, 0x04, 0x60, 0x70, 0x76, + 0x00, 0xe6, 0x6c, 0xfe, 0x48, 0x16, 0x47, 0x60, 0x26, 0x9f, 0x05, 0xd2, 0x21, 0x98, 0xeb, 0x89, + 0x10, 0xcc, 0xa9, 0x02, 0x66, 0x3d, 0x06, 0xf3, 0xbf, 0x26, 0xc8, 0xf0, 0xbb, 0x8d, 0x31, 0xfb, + 0xe9, 0xb7, 0xd4, 0xfd, 0xf4, 0x98, 0x99, 0x2c, 0xbd, 0xa1, 0xbe, 0xa1, 0x6f, 0xa8, 0xcf, 0x4c, + 0xc0, 0xab, 0xed, 0xa8, 0x57, 0xb3, 0x76, 0xd4, 0xdd, 0x09, 0x50, 0x72, 0xb7, 0xd4, 0x77, 0xd2, + 0x5b, 0xea, 0xb3, 0x13, 0xe0, 0x65, 0xee, 0xa9, 0x57, 0xb3, 0xf6, 0xd4, 0x93, 0xd4, 0x2e, 0x77, + 0x53, 0xfd, 0xb6, 0xb6, 0xa9, 0x7e, 0x75, 0x92, 0xee, 0x8a, 0x27, 0x87, 0x4f, 0xe5, 0xec, 0xaa, + 0xdf, 0x9c, 0x04, 0x66, 0x7c, 0x10, 0xfb, 0xc7, 0xfb, 0x62, 0x5d, 0xcc, 0xb7, 0x5f, 0x82, 0x56, + 0x74, 0xd1, 0xc6, 0xfc, 0x3c, 0x34, 0xa3, 0x4f, 0x62, 0x33, 0xae, 0xfc, 0x8a, 0x4d, 0x1d, 0x5f, + 0x3d, 0x8b, 0x14, 0xba, 0x01, 0x35, 0xfa, 0x4b, 0x98, 0xc5, 0x6b, 0x93, 0x5d, 0xe8, 0xa1, 0x42, + 0x30, 0xe3, 0x33, 0x7f, 0xe3, 0x08, 0x80, 0xf2, 0xa5, 0xe0, 0xa4, 0x62, 0xdf, 0xa5, 0xce, 0x6c, + 0x18, 0x12, 0x9f, 0x5d, 0xe4, 0x2a, 0xfc, 0x92, 0x2e, 0x96, 0x40, 0xb5, 0x25, 0x24, 0x3e, 0x16, + 0xec, 0xe8, 0x3e, 0xb4, 0xa2, 0x40, 0x2a, 0xbb, 0x3b, 0x9d, 0xa7, 0x64, 0x59, 0x50, 0x51, 0x68, + 0x0f, 0x4b, 0x08, 0x34, 0x0f, 0xb5, 0xc0, 0xf3, 0x43, 0x71, 0xd1, 0xfa, 0x8d, 0x89, 0xa1, 0xd6, + 0x3c, 0x3f, 0xc4, 0x8c, 0x95, 0x37, 0x4d, 0x79, 0x88, 0x61, 0x3f, 0x4d, 0xd3, 0x3c, 0xf6, 0xaf, + 0xd7, 0xa4, 0x0f, 0x5d, 0x14, 0xd6, 0xc8, 0x75, 0xe8, 0xdc, 0xe4, 0xa3, 0xa4, 0x5a, 0x65, 0x74, + 0x3b, 0xb2, 0xa2, 0xdc, 0x8e, 0x7c, 0x0d, 0x3a, 0x03, 0x6f, 0x97, 0xf8, 0x38, 0xbe, 0xe2, 0x24, + 0x6e, 0xa1, 0xa5, 0xf2, 0x91, 0x09, 0xad, 0x2d, 0xc7, 0x26, 0xfd, 0x81, 0xf0, 0x7f, 0x2d, 0x2c, + 0xd3, 0xe8, 0x2e, 0xb4, 0x58, 0x8c, 0x3d, 0x8a, 0xf0, 0xef, 0xaf, 0x92, 0x3c, 0xd4, 0x1f, 0x01, + 0x50, 0x41, 0x4c, 0xf8, 0x6d, 0x27, 0x64, 0x7d, 0xd8, 0xc2, 0x32, 0x4d, 0x2b, 0xcc, 0xee, 0x91, + 0xa9, 0x15, 0x6e, 0xf2, 0x0a, 0x27, 0xf3, 0xd1, 0x69, 0x98, 0x21, 0xae, 0xad, 0x52, 0x76, 0x18, + 0x65, 0x22, 0x17, 0x5d, 0x82, 0x23, 0x8c, 0x37, 0xb1, 0x15, 0xe5, 0x21, 0xfd, 0x16, 0xce, 0x2e, + 0x64, 0xf7, 0xeb, 0xac, 0x4d, 0xfe, 0x79, 0x16, 0x0b, 0xf2, 0xd5, 0x71, 0x9c, 0x81, 0xce, 0xc2, + 0x21, 0x9b, 0x6c, 0x58, 0x3b, 0xc3, 0xf0, 0x21, 0xd9, 0x1e, 0x0d, 0xad, 0x90, 0xf4, 0x6d, 0xf6, + 0x66, 0x44, 0x1b, 0xa7, 0x0b, 0xd0, 0x79, 0x78, 0x4e, 0x64, 0x72, 0x73, 0xa7, 0xa3, 0xd6, 0xb7, + 0xd9, 0x13, 0x0a, 0x6d, 0x9c, 0x55, 0x64, 0x7e, 0x97, 0x29, 0x07, 0x33, 0x81, 0x77, 0xa1, 0x6a, + 0xd9, 0xb6, 0x98, 0x5e, 0x2f, 0xee, 0xd3, 0x90, 0xc4, 0x77, 0x39, 0x14, 0x01, 0xad, 0xca, 0xab, + 0x79, 0x7c, 0x82, 0xbd, 0xb2, 0x5f, 0x2c, 0xf9, 0x94, 0x8d, 0xc0, 0xa1, 0x88, 0x3b, 0xfc, 0x53, + 0x8e, 0xea, 0x0f, 0x87, 0x28, 0x3f, 0xec, 0x10, 0x38, 0xe8, 0x0e, 0xd4, 0x58, 0x0d, 0xf9, 0x04, + 0x7c, 0x69, 0xbf, 0x78, 0xf7, 0x79, 0xfd, 0x18, 0x86, 0x39, 0xe0, 0x77, 0xe4, 0x94, 0x8b, 0x99, + 0x65, 0xfd, 0x62, 0xe6, 0x02, 0xd4, 0x9d, 0x90, 0x6c, 0xa7, 0xef, 0xe9, 0x8e, 0x55, 0x69, 0xe1, + 0xa1, 0x38, 0xeb, 0xd8, 0xfb, 0x82, 0xef, 0xe7, 0x7e, 0x6f, 0x71, 0x0b, 0x6a, 0x94, 0x3d, 0xb5, + 0xe6, 0x9c, 0x44, 0x30, 0xe3, 0x34, 0x2f, 0x40, 0x8d, 0x36, 0x76, 0x4c, 0xeb, 0x44, 0x7d, 0x2a, + 0xb2, 0x3e, 0x0b, 0x53, 0xd0, 0xf6, 0x46, 0xc4, 0x67, 0x86, 0x61, 0xfe, 0x5b, 0x4d, 0xb9, 0x3c, + 0xd7, 0x57, 0x75, 0xec, 0xf2, 0xbe, 0x3d, 0xac, 0xaa, 0x65, 0x38, 0xa1, 0x65, 0x6f, 0xed, 0x1f, + 0x2d, 0xa5, 0x67, 0x38, 0xa1, 0x67, 0x3f, 0x04, 0x66, 0x4a, 0xd3, 0xee, 0x69, 0x9a, 0x76, 0x65, + 0xff, 0x88, 0x9a, 0xae, 0x91, 0x22, 0x5d, 0x5b, 0xd2, 0x75, 0xad, 0x3b, 0xd9, 0x90, 0xcb, 0x29, + 0x6c, 0x02, 0x6d, 0xfb, 0x4c, 0xae, 0xb6, 0x2d, 0x68, 0xda, 0xb6, 0x5f, 0xd1, 0x1f, 0x91, 0xbe, + 0x7d, 0xa7, 0x06, 0x35, 0x3a, 0x8d, 0xa2, 0x65, 0x55, 0xd7, 0xde, 0xdc, 0xd7, 0x14, 0xac, 0xea, + 0xd9, 0x4a, 0x42, 0xcf, 0x2e, 0xed, 0x0f, 0x29, 0xa5, 0x63, 0x2b, 0x09, 0x1d, 0xdb, 0x27, 0x5e, + 0x4a, 0xbf, 0x7a, 0x9a, 0x7e, 0x5d, 0xd8, 0x1f, 0x9a, 0xa6, 0x5b, 0x56, 0x91, 0x6e, 0xdd, 0xd2, + 0x75, 0x6b, 0xc2, 0x55, 0x1e, 0x5b, 0xd3, 0x4c, 0xa0, 0x57, 0xef, 0xe5, 0xea, 0xd5, 0x0d, 0x4d, + 0xaf, 0xf6, 0x23, 0xf6, 0x23, 0xd2, 0xa9, 0x4b, 0x7c, 0x71, 0x9a, 0xff, 0x19, 0x5c, 0xd6, 0xe2, + 0xd4, 0xbc, 0x0c, 0xed, 0xf8, 0x49, 0x96, 0x8c, 0x6b, 0xfc, 0x9c, 0x2c, 0x92, 0x1a, 0x25, 0xcd, + 0x8b, 0xd0, 0x8e, 0x9f, 0x59, 0xc9, 0xfa, 0xe4, 0x8e, 0x15, 0xca, 0x4f, 0xaf, 0x58, 0xca, 0x5c, + 0x86, 0x43, 0xe9, 0x47, 0x20, 0x32, 0xe2, 0xf5, 0xca, 0x1d, 0xf4, 0xe8, 0xcb, 0x17, 0x25, 0xcb, + 0x7c, 0x0a, 0x33, 0x89, 0x67, 0x1d, 0xf6, 0x8d, 0x81, 0x2e, 0x2a, 0x4b, 0xe9, 0x6a, 0xe2, 0x43, + 0x5e, 0xfd, 0x56, 0x7d, 0xbc, 0x60, 0x36, 0x97, 0x60, 0xa6, 0xa0, 0xf2, 0x93, 0x5c, 0xaa, 0xff, + 0x2c, 0x4c, 0x8d, 0xab, 0xfb, 0x47, 0x70, 0xe9, 0x3f, 0x84, 0x4e, 0xea, 0x49, 0x9a, 0xa4, 0x98, + 0x55, 0x80, 0x4d, 0x49, 0x23, 0x94, 0xf6, 0xfc, 0x3e, 0x3e, 0x71, 0x60, 0x7c, 0x58, 0xc1, 0x30, + 0x7f, 0xbb, 0x0c, 0x87, 0xd2, 0xef, 0xd1, 0x4c, 0xba, 0x49, 0x32, 0xa0, 0xc9, 0xb0, 0xe4, 0x97, + 0x21, 0x51, 0x12, 0xdd, 0x87, 0xe9, 0x60, 0xe8, 0x0c, 0xc8, 0xe2, 0x96, 0xe5, 0x6e, 0x92, 0x40, + 0xec, 0x7c, 0x0a, 0xde, 0x94, 0x59, 0x8b, 0x39, 0xb0, 0xc6, 0x6e, 0x3e, 0x85, 0x29, 0xa5, 0x10, + 0xbd, 0x03, 0x15, 0x6f, 0x94, 0xba, 0xff, 0x98, 0x8f, 0xf9, 0x20, 0xb2, 0x37, 0x5c, 0xf1, 0x46, + 0x69, 0x93, 0x54, 0xcd, 0xb7, 0xaa, 0x99, 0xaf, 0x79, 0x17, 0x0e, 0xa5, 0x9f, 0x7c, 0x49, 0x76, + 0xcf, 0xe9, 0x54, 0x34, 0x81, 0x77, 0x53, 0x32, 0x34, 0x70, 0x15, 0x0e, 0x26, 0x1f, 0x72, 0xc9, + 0xf8, 0x6a, 0x27, 0xfe, 0xf8, 0x29, 0x0a, 0xeb, 0xcf, 0xfd, 0x6c, 0x19, 0x66, 0xf4, 0x86, 0xa0, + 0xa3, 0x80, 0xf4, 0x9c, 0x15, 0xcf, 0x25, 0x9d, 0x12, 0x3a, 0x02, 0x87, 0xf4, 0xfc, 0x79, 0xdb, + 0xee, 0x94, 0xd3, 0xe4, 0xd4, 0x6d, 0x75, 0x2a, 0xc8, 0x80, 0xc3, 0x89, 0x1e, 0x62, 0x4e, 0xb4, + 0x53, 0x45, 0xcf, 0xc3, 0x91, 0x64, 0xc9, 0x68, 0x68, 0x0d, 0x48, 0xa7, 0x66, 0xfe, 0xa0, 0x02, + 0xb5, 0x47, 0x01, 0xf1, 0xcd, 0x7f, 0xad, 0x44, 0x5f, 0x73, 0xbc, 0x05, 0x35, 0xf6, 0xc6, 0x8a, + 0xf2, 0xf9, 0x65, 0x39, 0xf1, 0xf9, 0xa5, 0xf6, 0x09, 0x5f, 0xfc, 0xf9, 0xe5, 0x5b, 0x50, 0x63, + 0xaf, 0xaa, 0xec, 0x9f, 0xf3, 0x6b, 0x65, 0x68, 0xc7, 0x2f, 0x9c, 0xec, 0x9b, 0x5f, 0xfd, 0x7a, + 0xa4, 0xa2, 0x7f, 0x3d, 0xf2, 0x1a, 0xd4, 0x7d, 0xf6, 0x9d, 0x07, 0xf7, 0x32, 0xc9, 0x6f, 0x52, + 0x98, 0x40, 0xcc, 0x49, 0x4c, 0x02, 0x53, 0xea, 0xfb, 0x2d, 0xfb, 0xaf, 0xc6, 0x49, 0xf1, 0x78, + 0x5b, 0xdf, 0x0e, 0xe6, 0x7d, 0xdf, 0xda, 0x13, 0x8a, 0xa9, 0x67, 0x9a, 0xb3, 0x50, 0x5b, 0x75, + 0xdc, 0xcd, 0xec, 0xaf, 0x5e, 0xcd, 0x3f, 0x2c, 0x43, 0x53, 0x5c, 0xf2, 0x35, 0xaf, 0x42, 0x75, + 0x85, 0x3c, 0xa5, 0x15, 0x11, 0xd7, 0x8b, 0x53, 0x15, 0xb9, 0xcf, 0x5a, 0x21, 0xe8, 0x71, 0x44, + 0x66, 0x5e, 0x93, 0xd3, 0xe4, 0xfe, 0x79, 0xdf, 0x82, 0x1a, 0x7b, 0x76, 0x65, 0xff, 0x9c, 0x7f, + 0xd4, 0x82, 0x06, 0xff, 0x74, 0xd4, 0xfc, 0xbd, 0x16, 0x34, 0xf8, 0x53, 0x2c, 0xe8, 0x06, 0x34, + 0x83, 0x9d, 0xed, 0x6d, 0xcb, 0xdf, 0x33, 0xb2, 0x1f, 0x18, 0xd6, 0x5e, 0x6e, 0xe9, 0xae, 0x71, + 0x5a, 0x1c, 0x31, 0xa1, 0xcb, 0x50, 0x1b, 0x58, 0x1b, 0x24, 0x75, 0xec, 0x9b, 0xc5, 0xbc, 0x68, + 0x6d, 0x10, 0xcc, 0xc8, 0xd1, 0x2d, 0x68, 0x89, 0x61, 0x09, 0x44, 0xdc, 0x67, 0xbc, 0xdc, 0x68, + 0x30, 0x25, 0x97, 0x79, 0x07, 0x9a, 0xa2, 0x32, 0xe8, 0xa6, 0xfc, 0x70, 0x36, 0x19, 0xa1, 0xce, + 0x6c, 0x82, 0x7c, 0xa3, 0x43, 0x7e, 0x42, 0xfb, 0x97, 0x15, 0xa8, 0xd1, 0xca, 0x7d, 0x68, 0x24, + 0x74, 0x1c, 0x60, 0x68, 0x05, 0xe1, 0xea, 0xce, 0x70, 0x48, 0x6c, 0xf1, 0x25, 0x9e, 0x92, 0x83, + 0xce, 0xc0, 0x41, 0x9e, 0x0a, 0xb6, 0xd6, 0x76, 0x06, 0x03, 0x22, 0xbf, 0x40, 0x4d, 0x66, 0xa3, + 0x79, 0xa8, 0xb3, 0xc7, 0x41, 0xc5, 0xaa, 0xf0, 0xf5, 0xc2, 0x9e, 0xed, 0xae, 0x3a, 0xae, 0xa8, + 0x0d, 0xe7, 0x34, 0x3d, 0x68, 0xcb, 0x3c, 0x6a, 0x84, 0x23, 0xc7, 0x75, 0x1d, 0x77, 0x53, 0x68, + 0x74, 0x94, 0xa4, 0x93, 0x0e, 0xfd, 0x29, 0xea, 0x5b, 0xc7, 0x22, 0x45, 0xf3, 0x37, 0x2c, 0x67, + 0x28, 0xaa, 0x58, 0xc7, 0x22, 0x45, 0x91, 0x76, 0xc4, 0x03, 0x36, 0x35, 0xd6, 0xc0, 0x28, 0x69, + 0x7e, 0x50, 0x96, 0x5f, 0x8f, 0x67, 0x7d, 0xc4, 0x99, 0x8a, 0x39, 0xcd, 0xaa, 0x81, 0x6f, 0x3e, + 0x21, 0x28, 0xa1, 0xec, 0xa3, 0xd0, 0xf0, 0xdc, 0xa1, 0xe3, 0x12, 0x11, 0x63, 0x12, 0xa9, 0x44, + 0x1f, 0xd7, 0x53, 0x7d, 0x2c, 0xca, 0x97, 0x6d, 0x87, 0x56, 0xb1, 0x11, 0x97, 0xf3, 0x1c, 0x74, + 0x1d, 0x9a, 0x36, 0xd9, 0x75, 0x06, 0x24, 0x30, 0x9a, 0x4c, 0xf5, 0x5e, 0x19, 0xdb, 0xb7, 0x4b, + 0x8c, 0x16, 0x47, 0x3c, 0x66, 0x08, 0x0d, 0x9e, 0x25, 0x9b, 0x54, 0x56, 0x9a, 0x14, 0x57, 0xba, + 0x32, 0xa6, 0xd2, 0xd5, 0x82, 0x4a, 0xd7, 0x92, 0x95, 0x9e, 0xfb, 0x12, 0x40, 0xac, 0x6e, 0x68, + 0x0a, 0x9a, 0x8f, 0xdc, 0x27, 0xae, 0xf7, 0xd4, 0xed, 0x94, 0x68, 0xe2, 0xc1, 0xc6, 0x06, 0x95, + 0xd2, 0x29, 0xd3, 0x04, 0xa5, 0x73, 0xdc, 0xcd, 0x4e, 0x05, 0x01, 0x34, 0x68, 0x82, 0xd8, 0x9d, + 0x2a, 0xfd, 0x7d, 0x9b, 0x8d, 0x5f, 0xa7, 0x86, 0x8e, 0xc1, 0x73, 0x7d, 0x77, 0xe0, 0x6d, 0x8f, + 0xac, 0xd0, 0x59, 0x1f, 0x92, 0xc7, 0xc4, 0x0f, 0x1c, 0xcf, 0xed, 0xd4, 0xe9, 0xec, 0xb5, 0x42, + 0xc2, 0xa7, 0x9e, 0xff, 0x64, 0x85, 0x10, 0x5b, 0xbc, 0x0d, 0xd3, 0x69, 0x98, 0xff, 0x51, 0xe6, + 0xa7, 0xc6, 0xe6, 0x2d, 0x98, 0xd6, 0x5e, 0x5a, 0x32, 0xe2, 0x77, 0xdf, 0x13, 0xcf, 0xbe, 0x1f, + 0x65, 0x71, 0x5d, 0x12, 0x2f, 0x65, 0x78, 0xca, 0xbc, 0x0d, 0xa0, 0xbc, 0xaf, 0x74, 0x1c, 0x60, + 0x7d, 0x2f, 0x24, 0x01, 0x7f, 0x5b, 0x89, 0x42, 0xd4, 0xb0, 0x92, 0xa3, 0xe2, 0x57, 0x34, 0x7c, + 0xf3, 0x0a, 0x80, 0xf2, 0xba, 0x12, 0xb5, 0x2b, 0x9a, 0x5a, 0x48, 0x82, 0x25, 0xb3, 0xcd, 0xae, + 0x68, 0x41, 0xf4, 0x8e, 0x52, 0x54, 0x03, 0x1e, 0xbd, 0x53, 0x6b, 0xc0, 0x72, 0xcc, 0x65, 0x80, + 0xf8, 0x29, 0x21, 0xf3, 0xaa, 0x74, 0xdd, 0x6f, 0x40, 0xcd, 0xb6, 0x42, 0x4b, 0x78, 0xcd, 0xe7, + 0x13, 0x33, 0x57, 0xcc, 0x82, 0x19, 0x99, 0xf9, 0x5b, 0x65, 0x98, 0x56, 0x9f, 0x4d, 0x32, 0xdf, + 0x85, 0x1a, 0x7b, 0x77, 0xe9, 0x26, 0x4c, 0xab, 0xef, 0x26, 0xa5, 0xde, 0xc7, 0xe7, 0x78, 0x2a, + 0x2b, 0xd6, 0x18, 0xcc, 0xbe, 0xac, 0xd2, 0x87, 0x86, 0x3a, 0x0f, 0x4d, 0xf1, 0x0c, 0x93, 0x79, + 0x0a, 0xda, 0xf1, 0xab, 0x4b, 0xd4, 0x77, 0xf0, 0xfc, 0x68, 0x94, 0x45, 0xd2, 0xfc, 0x97, 0x1a, + 0xd4, 0xd9, 0x70, 0x9a, 0x5f, 0xa9, 0xa8, 0x1a, 0x6a, 0xfe, 0xa0, 0x9c, 0xbb, 0x17, 0xbc, 0xa8, + 0xbd, 0x73, 0x30, 0x93, 0x7a, 0x6d, 0x4c, 0x3c, 0xb2, 0xa4, 0x3b, 0xd6, 0x2b, 0xd0, 0x74, 0xb9, + 0x66, 0x8a, 0x67, 0x06, 0x66, 0x33, 0xb9, 0x84, 0xf6, 0xe2, 0x88, 0x18, 0x5d, 0x82, 0x3a, 0xf1, + 0x7d, 0xcf, 0x67, 0x26, 0x35, 0x93, 0x7a, 0xb7, 0x2b, 0x7e, 0xd0, 0x69, 0x99, 0x52, 0x61, 0x4e, + 0x8c, 0x2e, 0xc1, 0x91, 0x80, 0x5b, 0x11, 0x5f, 0x53, 0x06, 0xe2, 0xfb, 0x6b, 0xe1, 0x6d, 0xb2, + 0x0b, 0xcd, 0x00, 0x0e, 0x26, 0xdf, 0x68, 0x32, 0xa1, 0xc5, 0xd7, 0xa6, 0xd2, 0x40, 0x64, 0x9a, + 0x6a, 0x1e, 0xff, 0xbd, 0x12, 0xfb, 0x45, 0x25, 0x87, 0xae, 0x57, 0x9e, 0x32, 0xa8, 0xe8, 0xd8, + 0x99, 0x7b, 0x48, 0x3d, 0x73, 0xee, 0x13, 0xd1, 0xac, 0xae, 0x58, 0x7b, 0x49, 0x75, 0x03, 0x65, + 0xd4, 0x86, 0x3a, 0x6b, 0x5d, 0xa7, 0xa2, 0xfa, 0x8a, 0x6a, 0x8e, 0xb5, 0xd7, 0xe6, 0x2e, 0x42, + 0x53, 0xe4, 0x53, 0xfa, 0x79, 0xde, 0x61, 0x9d, 0x12, 0x9a, 0x86, 0xd6, 0x1a, 0x19, 0x6e, 0xf4, + 0xbc, 0x20, 0xec, 0x94, 0xd1, 0x01, 0x68, 0x33, 0x03, 0x7c, 0xe0, 0x0e, 0xf7, 0x3a, 0x95, 0xb9, + 0xf7, 0xa0, 0x2d, 0xbb, 0x11, 0xb5, 0xa0, 0xb6, 0xb2, 0x33, 0x1c, 0x76, 0x4a, 0x6c, 0x3d, 0x1c, + 0x7a, 0x7e, 0x14, 0x0d, 0x5f, 0x7e, 0x46, 0x27, 0xb7, 0x4e, 0x39, 0xcf, 0x05, 0x55, 0x50, 0x07, + 0xa6, 0x85, 0x70, 0x5e, 0xe7, 0xaa, 0xf9, 0x4f, 0x65, 0x68, 0xcb, 0x27, 0xac, 0xe8, 0x62, 0x34, + 0x52, 0xac, 0x7c, 0xe7, 0x73, 0x35, 0xa1, 0x62, 0xf9, 0x2f, 0x62, 0x25, 0xd4, 0xec, 0x34, 0xcc, + 0x08, 0x3f, 0x1f, 0x8d, 0x38, 0x77, 0xd5, 0x89, 0xdc, 0xb9, 0x3b, 0xb2, 0xd7, 0x3b, 0xcc, 0xae, + 0x17, 0x3d, 0xd7, 0x25, 0x83, 0x90, 0xf5, 0xfd, 0x41, 0x98, 0x5a, 0xf1, 0xc2, 0x55, 0x2f, 0x08, + 0x68, 0xcb, 0x78, 0x4f, 0xc5, 0xe5, 0x15, 0x34, 0x03, 0x10, 0x5d, 0x84, 0xa3, 0x9e, 0xd9, 0xfc, + 0xcd, 0x32, 0x34, 0xf8, 0xc3, 0x5a, 0xe6, 0x2f, 0x97, 0xa1, 0x21, 0x1e, 0xd3, 0x7a, 0x0d, 0x3a, + 0xbe, 0x47, 0x81, 0xa3, 0x5d, 0x4c, 0x7f, 0x49, 0xb4, 0x32, 0x95, 0x4f, 0x37, 0xd6, 0x9e, 0xa2, + 0x8a, 0x62, 0xdd, 0xa1, 0xe5, 0xa1, 0x6b, 0x00, 0xfc, 0xb1, 0xae, 0x87, 0x7b, 0xf2, 0xa9, 0x8e, + 0xe4, 0xfd, 0x37, 0xf1, 0xbc, 0x17, 0x3b, 0x29, 0x52, 0xa8, 0xcd, 0x6d, 0x38, 0x94, 0x7a, 0x69, + 0x49, 0x09, 0xf6, 0x9c, 0x81, 0x83, 0x44, 0x2d, 0x92, 0xe3, 0x91, 0xcc, 0xa6, 0x2a, 0xad, 0x65, + 0x09, 0xad, 0xd7, 0x33, 0xe7, 0xbe, 0x08, 0x07, 0x30, 0x09, 0x46, 0x9e, 0x1b, 0x90, 0x1f, 0xd5, + 0xff, 0x42, 0xc9, 0xfd, 0xaf, 0x26, 0x73, 0xdf, 0xa9, 0x43, 0x9d, 0xad, 0xa0, 0xcd, 0xbf, 0xaa, + 0xcb, 0xb5, 0x7e, 0xca, 0x87, 0x5d, 0x50, 0x2f, 0x3d, 0xa9, 0xce, 0x48, 0x5b, 0x7c, 0xeb, 0x97, + 0x9d, 0xde, 0x86, 0xd6, 0xc8, 0xf7, 0x36, 0x7d, 0xba, 0x66, 0xaf, 0x25, 0x1e, 0xc9, 0xd2, 0xd9, + 0x56, 0x05, 0x19, 0x96, 0x0c, 0xaa, 0xae, 0xd7, 0x75, 0x5d, 0xbf, 0x05, 0x6d, 0xdb, 0xf7, 0x46, + 0xec, 0x73, 0x7d, 0x71, 0xd0, 0x78, 0x22, 0x07, 0x77, 0x29, 0xa2, 0xeb, 0x95, 0x70, 0xcc, 0x44, + 0xad, 0x85, 0x0f, 0xb6, 0x38, 0xe3, 0x7f, 0x31, 0x87, 0x9d, 0xab, 0x47, 0xaf, 0x84, 0x05, 0x39, + 0x65, 0x24, 0xcf, 0x18, 0x63, 0x6b, 0x2c, 0xe3, 0xf2, 0xb3, 0x88, 0x91, 0x93, 0xa3, 0xeb, 0xd0, + 0x0a, 0xac, 0x5d, 0xc2, 0x5e, 0x3e, 0x6f, 0x8f, 0xed, 0x8a, 0x35, 0x41, 0xd6, 0x2b, 0x61, 0xc9, + 0x42, 0x9b, 0xbc, 0xed, 0x6c, 0xf2, 0xdd, 0xb2, 0x78, 0x7e, 0x3d, 0xaf, 0xc9, 0xf7, 0x23, 0x3a, + 0xf6, 0x56, 0x7e, 0x94, 0xa0, 0xbb, 0x3b, 0x3e, 0x2d, 0x4c, 0xf1, 0x23, 0x74, 0x96, 0x30, 0xa7, + 0xa0, 0x2d, 0xbb, 0xc8, 0x6c, 0x49, 0xab, 0x6c, 0x41, 0x83, 0xb7, 0xc0, 0x04, 0x68, 0x45, 0x15, + 0xa2, 0xc4, 0x12, 0xdc, 0x5c, 0x81, 0x56, 0x34, 0x68, 0x39, 0x4f, 0x74, 0x20, 0xa8, 0xd9, 0x9e, + 0x58, 0x16, 0x56, 0x31, 0xfb, 0x4d, 0x07, 0x55, 0x7d, 0x22, 0xac, 0x2d, 0xdf, 0xcb, 0x9a, 0x9b, + 0x8f, 0xee, 0x6e, 0x51, 0x4f, 0xca, 0x03, 0x0e, 0x53, 0xd0, 0xc4, 0x3b, 0x6c, 0xc5, 0xde, 0x29, + 0xd3, 0x6c, 0xba, 0x0d, 0xec, 0x54, 0xa8, 0x53, 0x5e, 0xb4, 0xdc, 0x01, 0x19, 0xb2, 0x55, 0x9e, + 0x74, 0xf5, 0xb5, 0x85, 0xb6, 0x04, 0x5f, 0x98, 0xfd, 0xeb, 0x0f, 0x8e, 0x97, 0xbf, 0xfd, 0xc1, + 0xf1, 0xf2, 0xf7, 0x3e, 0x38, 0x5e, 0xfe, 0x85, 0xef, 0x1f, 0x2f, 0x7d, 0xfb, 0xfb, 0xc7, 0x4b, + 0xff, 0xf8, 0xfd, 0xe3, 0xa5, 0xf7, 0x2b, 0xa3, 0xf5, 0xf5, 0x06, 0xbb, 0x7f, 0x73, 0xf1, 0x3f, + 0x03, 0x00, 0x00, 0xff, 0xff, 0xe2, 0x96, 0x7f, 0xf9, 0xe2, 0x68, 0x00, 0x00, } func (m *Event) Marshal() (dAtA []byte, err error) { @@ -15776,6 +15793,13 @@ func (m *EventAccountLinkChallengeClientInfo) MarshalToSizedBuffer(dAtA []byte) _ = i var l int _ = l + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintEvents(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x22 + } if m.SignatureVerified { i-- if m.SignatureVerified { @@ -20486,6 +20510,15 @@ func (m *EventBlockDataviewViewUpdateFields) MarshalToSizedBuffer(dAtA []byte) ( _ = i var l int _ = l + if len(m.EndRelationKey) > 0 { + i -= len(m.EndRelationKey) + copy(dAtA[i:], m.EndRelationKey) + i = encodeVarintEvents(dAtA, i, uint64(len(m.EndRelationKey))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } if len(m.DefaultObjectTypeId) > 0 { i -= len(m.DefaultObjectTypeId) copy(dAtA[i:], m.DefaultObjectTypeId) @@ -25000,6 +25033,10 @@ func (m *EventAccountLinkChallengeClientInfo) Size() (n int) { if m.SignatureVerified { n += 2 } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovEvents(uint64(l)) + } return n } @@ -26983,6 +27020,10 @@ func (m *EventBlockDataviewViewUpdateFields) Size() (n int) { if l > 0 { n += 1 + l + sovEvents(uint64(l)) } + l = len(m.EndRelationKey) + if l > 0 { + n += 2 + l + sovEvents(uint64(l)) + } return n } @@ -33360,6 +33401,38 @@ func (m *EventAccountLinkChallengeClientInfo) Unmarshal(dAtA []byte) error { } } m.SignatureVerified = bool(v != 0) + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) @@ -46407,6 +46480,38 @@ func (m *EventBlockDataviewViewUpdateFields) Unmarshal(dAtA []byte) error { } m.DefaultObjectTypeId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndRelationKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowEvents + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthEvents + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthEvents + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EndRelationKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipEvents(dAtA[iNdEx:]) diff --git a/pb/protos/commands.proto b/pb/protos/commands.proto index 4c8f0a804..8c1b4b1e6 100644 --- a/pb/protos/commands.proto +++ b/pb/protos/commands.proto @@ -148,20 +148,46 @@ message Rpc { } } + message InviteChange { + message Request { + string spaceId = 1; + model.ParticipantPermissions permissions = 2; + } + + message Response { + Error error = 1; + + message Error { + Code code = 1; + string description = 2; + + enum Code { + NULL = 0; + UNKNOWN_ERROR = 1; + BAD_INPUT = 2; + + NO_SUCH_SPACE = 101; + SPACE_IS_DELETED = 102; + REQUEST_FAILED = 103; + INCORRECT_PERMISSIONS = 105; + } + } + } + } + message InviteGenerate { message Request { string spaceId = 1; - InviteType inviteType = 2; - enum InviteType { - Member = 0; - Guest = 1; - } + model.InviteType inviteType = 2; + model.ParticipantPermissions permissions = 3; } message Response { Error error = 1; string inviteCid = 2; string inviteFileKey = 3; + model.InviteType inviteType = 4; + model.ParticipantPermissions permissions = 5; message Error { Code code = 1; @@ -217,6 +243,8 @@ message Rpc { Error error = 1; string inviteCid = 2; string inviteFileKey = 3; + model.InviteType inviteType = 4; + model.ParticipantPermissions permissions = 5; message Error { Code code = 1; @@ -298,7 +326,8 @@ message Rpc { string spaceName = 3; string spaceIconCid = 4; string creatorName = 5; - bool isGuestUserInvite = 6; + bool isGuestUserInvite = 6; // deprecated, use inviteType + model.InviteType inviteType = 7; message Error { Code code = 1; @@ -1236,7 +1265,77 @@ message Rpc { } } } + message ListApps { + message Request { + } + + message Response { + Error error = 1; + repeated model.Account.Auth.AppInfo app = 2; + + message Error { + Code code = 1; + string description = 2; + + enum Code { + NULL = 0; + UNKNOWN_ERROR = 1; + BAD_INPUT = 2; + + ACCOUNT_IS_NOT_RUNNING = 101; + } + } + } + } + message CreateApp { + message Request { + model.Account.Auth.AppInfo app = 1; + } + + message Response { + Error error = 1; + string appKey = 2; // persistent key, that can be used to restore session via CreateSession or for JSON API + + message Error { + Code code = 1; + string description = 2; + + enum Code { + NULL = 0; + UNKNOWN_ERROR = 1; + BAD_INPUT = 2; + + ACCOUNT_IS_NOT_RUNNING = 101; + } + } + } + } + message RevokeApp { + message Request { + string appHash = 1; + } + + message Response { + Error error = 1; + + message Error { + Code code = 1; + string description = 2; + + enum Code { + NULL = 0; + UNKNOWN_ERROR = 1; + BAD_INPUT = 2; + NOT_FOUND = 3; + + ACCOUNT_IS_NOT_RUNNING = 101; + } + } + } + } + } + } message Workspace { message GetCurrent { @@ -8409,6 +8508,28 @@ message Rpc { } } } + + + message ReadAll { + message Request {} + + message Response { + Error error = 1; + + message Error { + Code code = 1; + string description = 2; + + enum Code { + NULL = 0; + UNKNOWN_ERROR = 1; + BAD_INPUT = 2; + // ... + } + } + } + } + } message PushNotification { message RegisterToken { diff --git a/pb/protos/events.proto b/pb/protos/events.proto index a88ebfde2..60fdd6de5 100644 --- a/pb/protos/events.proto +++ b/pb/protos/events.proto @@ -197,6 +197,7 @@ message Event { message ClientInfo { string processName = 1; string processPath = 2; + string name = 4; bool signatureVerified = 3; } string challenge = 1; @@ -816,6 +817,7 @@ message Event { anytype.model.Block.Content.Dataview.View.Size cardSize = 5; // Gallery card size bool coverFit = 6; // Image fits container string groupRelationKey = 7; // Group view by this relationKey + string endRelationKey = 16; bool groupBackgroundColors = 8; // Enable backgrounds in groups int32 pageLimit = 9; // Limit of objects shown in widget string defaultTemplateId = 10; // Id of template object set default for the view diff --git a/pb/protos/service/service.proto b/pb/protos/service/service.proto index ad2bf3540..d9e920b12 100644 --- a/pb/protos/service/service.proto +++ b/pb/protos/service/service.proto @@ -17,6 +17,10 @@ service ClientCommands { rpc WalletConvert (anytype.Rpc.Wallet.Convert.Request) returns (anytype.Rpc.Wallet.Convert.Response); rpc AccountLocalLinkNewChallenge (anytype.Rpc.Account.LocalLink.NewChallenge.Request) returns (anytype.Rpc.Account.LocalLink.NewChallenge.Response); rpc AccountLocalLinkSolveChallenge (anytype.Rpc.Account.LocalLink.SolveChallenge.Request) returns (anytype.Rpc.Account.LocalLink.SolveChallenge.Response); + rpc AccountLocalLinkCreateApp (anytype.Rpc.Account.LocalLink.CreateApp.Request) returns (anytype.Rpc.Account.LocalLink.CreateApp.Response); + rpc AccountLocalLinkListApps (anytype.Rpc.Account.LocalLink.ListApps.Request) returns (anytype.Rpc.Account.LocalLink.ListApps.Response); + rpc AccountLocalLinkRevokeApp (anytype.Rpc.Account.LocalLink.RevokeApp.Request) returns (anytype.Rpc.Account.LocalLink.RevokeApp.Response); + rpc WalletCreateSession (anytype.Rpc.Wallet.CreateSession.Request) returns (anytype.Rpc.Wallet.CreateSession.Response); rpc WalletCloseSession (anytype.Rpc.Wallet.CloseSession.Request) returns (anytype.Rpc.Wallet.CloseSession.Response); // Workspace @@ -55,6 +59,7 @@ service ClientCommands { // *** rpc SpaceDelete (anytype.Rpc.Space.Delete.Request) returns (anytype.Rpc.Space.Delete.Response); rpc SpaceInviteGenerate (anytype.Rpc.Space.InviteGenerate.Request) returns (anytype.Rpc.Space.InviteGenerate.Response); + rpc SpaceInviteChange (anytype.Rpc.Space.InviteChange.Request) returns (anytype.Rpc.Space.InviteChange.Response); rpc SpaceInviteGetCurrent (anytype.Rpc.Space.InviteGetCurrent.Request) returns (anytype.Rpc.Space.InviteGetCurrent.Response); rpc SpaceInviteGetGuest (anytype.Rpc.Space.InviteGetGuest.Request) returns (anytype.Rpc.Space.InviteGetGuest.Response); rpc SpaceInviteRevoke(anytype.Rpc.Space.InviteRevoke.Request) returns (anytype.Rpc.Space.InviteRevoke.Response); @@ -403,6 +408,7 @@ service ClientCommands { rpc ChatSubscribeToMessagePreviews (anytype.Rpc.Chat.SubscribeToMessagePreviews.Request) returns (anytype.Rpc.Chat.SubscribeToMessagePreviews.Response); rpc ChatUnsubscribeFromMessagePreviews (anytype.Rpc.Chat.UnsubscribeFromMessagePreviews.Request) returns (anytype.Rpc.Chat.UnsubscribeFromMessagePreviews.Response); rpc ObjectChatAdd (anytype.Rpc.Object.ChatAdd.Request) returns (anytype.Rpc.Object.ChatAdd.Response); + rpc ChatReadAll (anytype.Rpc.Chat.ReadAll.Request) returns (anytype.Rpc.Chat.ReadAll.Response); // mock AI RPCs for compatibility between branches. Not implemented in main rpc AIWritingTools (anytype.Rpc.AI.WritingTools.Request) returns (anytype.Rpc.AI.WritingTools.Response); diff --git a/pb/service/service.pb.go b/pb/service/service.pb.go index 0cf2cd505..19ed0f912 100644 --- a/pb/service/service.pb.go +++ b/pb/service/service.pb.go @@ -26,368 +26,373 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package func init() { proto.RegisterFile("pb/protos/service/service.proto", fileDescriptor_93a29dc403579097) } var fileDescriptor_93a29dc403579097 = []byte{ - // 5766 bytes of a gzipped FileDescriptorProto + // 5854 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x9d, 0xdd, 0x6f, 0x24, 0x49, - 0x52, 0xc0, 0xd7, 0x2f, 0x2c, 0xd4, 0x71, 0x0b, 0xf4, 0xc2, 0xb2, 0xb7, 0xdc, 0xcd, 0xcc, 0xce, - 0x87, 0x3d, 0x33, 0x1e, 0xb7, 0x67, 0x67, 0xf6, 0x8b, 0x3b, 0x24, 0xe8, 0xb1, 0xc7, 0xde, 0xbe, - 0xb5, 0xbd, 0xc6, 0xdd, 0x9e, 0x11, 0x2b, 0x21, 0x51, 0xee, 0x4a, 0xb7, 0x0b, 0x57, 0x57, 0xd6, - 0x55, 0x65, 0x7b, 0xa6, 0x0f, 0x81, 0x40, 0x20, 0x10, 0x08, 0xc4, 0x89, 0x2f, 0xc1, 0x13, 0x12, - 0x7f, 0x01, 0x7f, 0x06, 0x8f, 0xf7, 0xc8, 0x23, 0xda, 0xfd, 0x33, 0x78, 0x00, 0x55, 0x66, 0x56, - 0x7e, 0x44, 0x45, 0x64, 0x95, 0xf7, 0x9e, 0x66, 0xe4, 0xf8, 0x45, 0x44, 0x7e, 0x44, 0x66, 0x46, - 0x66, 0x65, 0x55, 0x47, 0x37, 0x8b, 0xb3, 0xed, 0xa2, 0xe4, 0x82, 0x57, 0xdb, 0x15, 0x2b, 0xaf, - 0xd2, 0x19, 0x6b, 0xfe, 0x1d, 0xca, 0x3f, 0x0f, 0xde, 0x8c, 0xf3, 0x95, 0x58, 0x15, 0xec, 0xbd, - 0x77, 0x2d, 0x39, 0xe3, 0x8b, 0x45, 0x9c, 0x27, 0x95, 0x42, 0xde, 0x7b, 0xc7, 0x4a, 0xd8, 0x15, - 0xcb, 0x85, 0xfe, 0xfb, 0x93, 0xff, 0xfd, 0xbf, 0xb5, 0xe8, 0xad, 0x9d, 0x2c, 0x65, 0xb9, 0xd8, - 0xd1, 0x1a, 0x83, 0x2f, 0xa3, 0x6f, 0x8f, 0x8a, 0x62, 0x9f, 0x89, 0x17, 0xac, 0xac, 0x52, 0x9e, - 0x0f, 0xee, 0x0c, 0xb5, 0x83, 0xe1, 0x49, 0x31, 0x1b, 0x8e, 0x8a, 0x62, 0x68, 0x85, 0xc3, 0x13, - 0xf6, 0xa3, 0x25, 0xab, 0xc4, 0x7b, 0x77, 0xc3, 0x50, 0x55, 0xf0, 0xbc, 0x62, 0x83, 0xf3, 0xe8, - 0x57, 0x46, 0x45, 0x31, 0x61, 0x62, 0x97, 0xd5, 0x15, 0x98, 0x88, 0x58, 0xb0, 0xc1, 0x46, 0x4b, - 0xd5, 0x07, 0x8c, 0x8f, 0xfb, 0xdd, 0xa0, 0xf6, 0x33, 0x8d, 0xbe, 0x55, 0xfb, 0xb9, 0x58, 0x8a, - 0x84, 0xbf, 0xca, 0x07, 0xef, 0xb7, 0x15, 0xb5, 0xc8, 0xd8, 0xbe, 0x1d, 0x42, 0xb4, 0xd5, 0x97, - 0xd1, 0x2f, 0xbe, 0x8c, 0xb3, 0x8c, 0x89, 0x9d, 0x92, 0xd5, 0x05, 0xf7, 0x75, 0x94, 0x68, 0xa8, - 0x64, 0xc6, 0xee, 0x9d, 0x20, 0xa3, 0x0d, 0x7f, 0x19, 0x7d, 0x5b, 0x49, 0x4e, 0xd8, 0x8c, 0x5f, - 0xb1, 0x72, 0x80, 0x6a, 0x69, 0x21, 0xd1, 0xe4, 0x2d, 0x08, 0xda, 0xde, 0xe1, 0xf9, 0x15, 0x2b, - 0x05, 0x6e, 0x5b, 0x0b, 0xc3, 0xb6, 0x2d, 0xa4, 0x6d, 0xff, 0xf5, 0x5a, 0xf4, 0xdd, 0xd1, 0x6c, - 0xc6, 0x97, 0xb9, 0x38, 0xe0, 0xb3, 0x38, 0x3b, 0x48, 0xf3, 0xcb, 0x23, 0xf6, 0x6a, 0xe7, 0xa2, - 0xe6, 0xf3, 0x39, 0x1b, 0x3c, 0xf5, 0x5b, 0x55, 0xa1, 0x43, 0xc3, 0x0e, 0x5d, 0xd8, 0xf8, 0xfe, - 0xf0, 0x7a, 0x4a, 0xba, 0x2c, 0x7f, 0xbf, 0x16, 0xdd, 0x80, 0x65, 0x99, 0xf0, 0xec, 0x8a, 0xd9, - 0xd2, 0x7c, 0xd4, 0x61, 0xd8, 0xc7, 0x4d, 0x79, 0x3e, 0xbe, 0xae, 0x9a, 0x2e, 0x51, 0x16, 0xbd, - 0xed, 0x86, 0xcb, 0x84, 0x55, 0x72, 0x38, 0x3d, 0xa0, 0x23, 0x42, 0x23, 0xc6, 0xf3, 0xc3, 0x3e, - 0xa8, 0xf6, 0x96, 0x46, 0x03, 0xed, 0x2d, 0xe3, 0x95, 0x71, 0x76, 0x1f, 0xb5, 0xe0, 0x10, 0xc6, - 0xd7, 0x83, 0x1e, 0xa4, 0x76, 0xf5, 0x07, 0xd1, 0x2f, 0xbd, 0xe4, 0xe5, 0x65, 0x55, 0xc4, 0x33, - 0xa6, 0x87, 0xc2, 0x3d, 0x5f, 0xbb, 0x91, 0xc2, 0xd1, 0xb0, 0xde, 0x85, 0x39, 0x41, 0xdb, 0x08, - 0xbf, 0x28, 0x18, 0x9c, 0x83, 0xac, 0x62, 0x2d, 0xa4, 0x82, 0x16, 0x42, 0xda, 0xf6, 0x65, 0x34, - 0xb0, 0xb6, 0xcf, 0xfe, 0x90, 0xcd, 0xc4, 0x28, 0x49, 0x60, 0xaf, 0x58, 0x5d, 0x49, 0x0c, 0x47, - 0x49, 0x42, 0xf5, 0x0a, 0x8e, 0x6a, 0x67, 0xaf, 0xa2, 0x77, 0x80, 0xb3, 0x83, 0xb4, 0x92, 0x0e, - 0xb7, 0xc2, 0x56, 0x34, 0x66, 0x9c, 0x0e, 0xfb, 0xe2, 0xda, 0xf1, 0x9f, 0xae, 0x45, 0xdf, 0x41, - 0x3c, 0x9f, 0xb0, 0x05, 0xbf, 0x62, 0x83, 0xc7, 0xdd, 0xd6, 0x14, 0x69, 0xfc, 0x7f, 0x70, 0x0d, - 0x0d, 0x24, 0x4c, 0x26, 0x2c, 0x63, 0x33, 0x41, 0x86, 0x89, 0x12, 0x77, 0x86, 0x89, 0xc1, 0x9c, - 0x11, 0xd6, 0x08, 0xf7, 0x99, 0xd8, 0x59, 0x96, 0x25, 0xcb, 0x05, 0xd9, 0x97, 0x16, 0xe9, 0xec, - 0x4b, 0x0f, 0x45, 0xea, 0xb3, 0xcf, 0xc4, 0x28, 0xcb, 0xc8, 0xfa, 0x28, 0x71, 0x67, 0x7d, 0x0c, - 0xa6, 0x3d, 0xcc, 0xa2, 0x5f, 0x76, 0x5a, 0x4c, 0x8c, 0xf3, 0x73, 0x3e, 0xa0, 0xdb, 0x42, 0xca, - 0x8d, 0x8f, 0x8d, 0x4e, 0x0e, 0xa9, 0xc6, 0xf3, 0xd7, 0x05, 0x2f, 0xe9, 0x6e, 0x51, 0xe2, 0xce, - 0x6a, 0x18, 0x4c, 0x7b, 0xf8, 0xfd, 0xe8, 0x2d, 0x3d, 0x4b, 0x36, 0xeb, 0xd9, 0x5d, 0x74, 0x0a, - 0x85, 0x0b, 0xda, 0xbd, 0x0e, 0xaa, 0x65, 0xfe, 0x30, 0x9d, 0x97, 0xf5, 0xec, 0x83, 0x9b, 0xd7, - 0xd2, 0x0e, 0xf3, 0x96, 0xd2, 0xe6, 0x79, 0xf4, 0xab, 0xbe, 0xf9, 0x9d, 0x38, 0x9f, 0xb1, 0x6c, - 0xf0, 0x30, 0xa4, 0xae, 0x18, 0xe3, 0x6a, 0xb3, 0x17, 0x6b, 0x27, 0x3b, 0x4d, 0xe8, 0xc9, 0xf4, - 0x0e, 0xaa, 0x0d, 0xa6, 0xd2, 0xbb, 0x61, 0xa8, 0x65, 0x7b, 0x97, 0x65, 0x8c, 0xb4, 0xad, 0x84, - 0x1d, 0xb6, 0x0d, 0xa4, 0x6d, 0x97, 0xd1, 0xaf, 0x99, 0x6e, 0xae, 0xf3, 0x02, 0x29, 0xaf, 0x17, - 0x9d, 0x4d, 0xa2, 0x1f, 0x5d, 0xc8, 0xf8, 0x7a, 0xd4, 0x0f, 0x6e, 0xd5, 0x47, 0xcf, 0x28, 0x78, - 0x7d, 0xc0, 0x7c, 0x72, 0x37, 0x0c, 0x69, 0xdb, 0x7f, 0xb3, 0x16, 0x7d, 0x4f, 0xcb, 0x9e, 0xe7, - 0xf1, 0x59, 0xc6, 0xe4, 0x12, 0x7f, 0xc4, 0xc4, 0x2b, 0x5e, 0x5e, 0x4e, 0x56, 0xf9, 0x8c, 0x48, - 0x67, 0x70, 0xb8, 0x23, 0x9d, 0x21, 0x95, 0x74, 0x61, 0xfe, 0x28, 0x7a, 0xb7, 0x09, 0x8a, 0x8b, - 0x38, 0x9f, 0xb3, 0x1f, 0x56, 0x3c, 0x1f, 0x15, 0xe9, 0x28, 0x49, 0xca, 0xc1, 0x10, 0xef, 0x7a, - 0xc8, 0x99, 0x12, 0x6c, 0xf7, 0xe6, 0x9d, 0xf4, 0x59, 0xb7, 0xb2, 0xe0, 0x05, 0x4c, 0x9f, 0x9b, - 0xe6, 0x13, 0xbc, 0xa0, 0xd2, 0x67, 0x1f, 0x69, 0x59, 0x3d, 0xac, 0xd7, 0x20, 0xdc, 0xea, 0xa1, - 0xbb, 0xe8, 0xdc, 0x0e, 0x21, 0x76, 0x0d, 0x68, 0x1a, 0x8a, 0xe7, 0xe7, 0xe9, 0xfc, 0xb4, 0x48, - 0xea, 0x31, 0xf4, 0x00, 0xaf, 0xb3, 0x83, 0x10, 0x6b, 0x00, 0x81, 0x6a, 0x6f, 0x7f, 0x67, 0xb3, - 0x4c, 0x3d, 0x2f, 0xed, 0x95, 0x7c, 0x71, 0xc0, 0xe6, 0xf1, 0x6c, 0xa5, 0x27, 0xd3, 0x0f, 0x43, - 0xb3, 0x18, 0xa4, 0x4d, 0x21, 0x3e, 0xba, 0xa6, 0x96, 0x2e, 0xcf, 0xbf, 0xaf, 0x45, 0x77, 0xbd, - 0x38, 0xd1, 0xc1, 0xa4, 0x4a, 0x3f, 0xca, 0x93, 0x13, 0x56, 0x89, 0xb8, 0x14, 0x83, 0xef, 0x07, - 0x62, 0x80, 0xd0, 0x31, 0x65, 0xfb, 0xc1, 0x37, 0xd2, 0xb5, 0xbd, 0x3e, 0xa9, 0x57, 0x09, 0x3d, - 0xff, 0xf8, 0xbd, 0x2e, 0x25, 0x70, 0xf6, 0xb9, 0x1d, 0x42, 0x6c, 0xaf, 0x4b, 0xc1, 0x38, 0xbf, - 0x4a, 0x05, 0xdb, 0x67, 0x39, 0x2b, 0xdb, 0xbd, 0xae, 0x54, 0x7d, 0x84, 0xe8, 0x75, 0x02, 0xb5, - 0x33, 0x9d, 0xe7, 0xcd, 0x64, 0x1a, 0x9b, 0x01, 0x23, 0xad, 0x5c, 0xe3, 0x51, 0x3f, 0x98, 0xa8, - 0xa1, 0xd8, 0xaf, 0x8d, 0x04, 0x6b, 0xa8, 0x90, 0x5e, 0x35, 0x34, 0xa8, 0xdd, 0x98, 0x3b, 0xde, - 0x4e, 0xd8, 0x15, 0xbf, 0x84, 0x1b, 0x73, 0xd7, 0x80, 0x02, 0x88, 0x8d, 0x39, 0x0a, 0xda, 0xe4, - 0xc3, 0xf1, 0xf3, 0x22, 0x65, 0xaf, 0x40, 0xf2, 0xe1, 0x2a, 0xd7, 0x62, 0x22, 0xf9, 0x40, 0x30, - 0xed, 0xe1, 0x28, 0xfa, 0x05, 0x29, 0xfc, 0x21, 0x4f, 0xf3, 0xc1, 0x4d, 0x44, 0xa9, 0x16, 0x18, - 0xab, 0xb7, 0x68, 0x00, 0x94, 0xb8, 0xfe, 0xab, 0xce, 0x04, 0xee, 0x11, 0x4a, 0x20, 0x09, 0x58, - 0xef, 0xc2, 0x6c, 0xd6, 0x27, 0x85, 0xf5, 0x6c, 0x39, 0xb9, 0x88, 0xcb, 0x34, 0x9f, 0x0f, 0x30, - 0x5d, 0x47, 0x4e, 0x64, 0x7d, 0x18, 0x07, 0xc2, 0x49, 0x2b, 0x8e, 0x8a, 0xa2, 0xac, 0x27, 0x61, - 0x2c, 0x9c, 0x7c, 0x24, 0x18, 0x4e, 0x2d, 0x14, 0xf7, 0xb6, 0xcb, 0x66, 0x59, 0x9a, 0x07, 0xbd, - 0x69, 0xa4, 0x8f, 0x37, 0x8b, 0x82, 0xe0, 0x3d, 0x60, 0xf1, 0x15, 0x6b, 0x6a, 0x86, 0xb5, 0x8c, - 0x0b, 0x04, 0x83, 0x17, 0x80, 0x76, 0x8b, 0x2d, 0xc5, 0x87, 0xf1, 0x25, 0xab, 0x1b, 0x98, 0xd5, - 0x4b, 0xf8, 0x00, 0xd3, 0xf7, 0x08, 0x62, 0x8b, 0x8d, 0x93, 0xda, 0xd5, 0x32, 0x7a, 0x47, 0xca, - 0x8f, 0xe3, 0x52, 0xa4, 0xb3, 0xb4, 0x88, 0xf3, 0x66, 0xeb, 0x86, 0xcd, 0x22, 0x2d, 0xca, 0xb8, - 0xdc, 0xea, 0x49, 0x6b, 0xb7, 0xff, 0xb2, 0x16, 0xbd, 0x0f, 0xfd, 0x1e, 0xb3, 0x72, 0x91, 0xca, - 0x13, 0x80, 0x4a, 0x4d, 0xf9, 0x83, 0x4f, 0xc2, 0x46, 0x5b, 0x0a, 0xa6, 0x34, 0x9f, 0x5e, 0x5f, - 0xd1, 0xe6, 0x7d, 0x13, 0xbd, 0x2b, 0xfa, 0xa2, 0x4c, 0x5a, 0x27, 0x64, 0x93, 0x66, 0xab, 0x23, - 0x85, 0x44, 0xde, 0xd7, 0x82, 0xc0, 0x08, 0x3f, 0xcd, 0xab, 0xc6, 0x3a, 0x36, 0xc2, 0xad, 0x38, - 0x38, 0xc2, 0x3d, 0xcc, 0x8e, 0xf0, 0xe3, 0xe5, 0x59, 0x96, 0x56, 0x17, 0x69, 0x3e, 0xd7, 0x49, - 0xbe, 0xaf, 0x6b, 0xc5, 0x30, 0xcf, 0xdf, 0xe8, 0xe4, 0x30, 0x27, 0x3a, 0x58, 0x48, 0x27, 0x20, - 0x4c, 0x36, 0x3a, 0x39, 0xbb, 0xf7, 0xb2, 0xd2, 0x7a, 0xd3, 0x0f, 0xf6, 0x5e, 0x8e, 0x6a, 0x2d, - 0x25, 0xf6, 0x5e, 0x6d, 0xca, 0xee, 0xbd, 0xdc, 0x3a, 0x54, 0x3c, 0xbb, 0x62, 0xa7, 0x65, 0x0a, - 0xf6, 0x5e, 0x5e, 0xf9, 0x1a, 0x86, 0xd8, 0x7b, 0x51, 0xac, 0x9d, 0xa8, 0x2c, 0xb1, 0xcf, 0xc4, - 0x44, 0xc4, 0x62, 0x59, 0x81, 0x89, 0xca, 0xb1, 0x61, 0x10, 0x62, 0xa2, 0x22, 0x50, 0xed, 0xed, - 0x77, 0xa3, 0x48, 0x9d, 0x97, 0xc8, 0x33, 0x2d, 0x7f, 0xed, 0xd1, 0x07, 0x29, 0xde, 0x81, 0xd6, - 0xfb, 0x01, 0xc2, 0xa6, 0x57, 0xea, 0xef, 0xf2, 0xa8, 0x6e, 0x80, 0x6a, 0x48, 0x11, 0x91, 0x5e, - 0x01, 0x04, 0x16, 0x74, 0x72, 0xc1, 0x5f, 0xe1, 0x05, 0xad, 0x25, 0xe1, 0x82, 0x6a, 0xc2, 0x1e, - 0x9e, 0xeb, 0x82, 0x62, 0x87, 0xe7, 0x4d, 0x31, 0x42, 0x87, 0xe7, 0x90, 0xb1, 0x31, 0xe3, 0x1a, - 0x7e, 0xc6, 0xf9, 0xe5, 0x22, 0x2e, 0x2f, 0x41, 0xcc, 0x78, 0xca, 0x0d, 0x43, 0xc4, 0x0c, 0xc5, - 0xda, 0x98, 0x71, 0x1d, 0xd6, 0xc9, 0xf9, 0x69, 0x99, 0x81, 0x98, 0xf1, 0x6c, 0x68, 0x84, 0x88, - 0x19, 0x02, 0xb5, 0xb3, 0x93, 0xeb, 0x6d, 0xc2, 0xe0, 0x71, 0x8d, 0xa7, 0x3e, 0x61, 0xd4, 0x71, - 0x0d, 0x82, 0xc1, 0x10, 0xda, 0x2f, 0xe3, 0xe2, 0x02, 0x0f, 0x21, 0x29, 0x0a, 0x87, 0x50, 0x83, - 0xc0, 0xfe, 0x9e, 0xb0, 0xb8, 0x9c, 0x5d, 0xe0, 0xfd, 0xad, 0x64, 0xe1, 0xfe, 0x36, 0x0c, 0xec, - 0x6f, 0x25, 0x78, 0x99, 0x8a, 0x8b, 0x43, 0x26, 0x62, 0xbc, 0xbf, 0x7d, 0x26, 0xdc, 0xdf, 0x2d, - 0xd6, 0x66, 0xff, 0xae, 0xc3, 0xc9, 0xf2, 0xac, 0x9a, 0x95, 0xe9, 0x19, 0x1b, 0x04, 0xac, 0x18, - 0x88, 0xc8, 0xfe, 0x49, 0x58, 0xfb, 0xfc, 0xc9, 0x5a, 0x74, 0xb3, 0xe9, 0x76, 0x5e, 0x55, 0x7a, - 0xed, 0xf3, 0xdd, 0x7f, 0x84, 0xf7, 0x2f, 0x81, 0x13, 0x8f, 0x33, 0x7a, 0xa8, 0x39, 0xb9, 0x01, - 0x5e, 0xa4, 0xd3, 0xbc, 0x32, 0x85, 0xfa, 0xa4, 0x8f, 0x75, 0x47, 0x81, 0xc8, 0x0d, 0x7a, 0x29, - 0xda, 0xb4, 0x4c, 0xf7, 0x4f, 0x23, 0x1b, 0x27, 0x15, 0x48, 0xcb, 0x9a, 0xf6, 0x76, 0x08, 0x22, - 0x2d, 0xc3, 0x49, 0x18, 0x0a, 0xfb, 0x25, 0x5f, 0x16, 0x55, 0x47, 0x28, 0x00, 0x28, 0x1c, 0x0a, - 0x6d, 0x58, 0xfb, 0x7c, 0x1d, 0xfd, 0xba, 0x1b, 0x7e, 0x6e, 0x63, 0x6f, 0xd1, 0x31, 0x85, 0x35, - 0xf1, 0xb0, 0x2f, 0x6e, 0x33, 0x8a, 0xc6, 0xb3, 0xd8, 0x65, 0x22, 0x4e, 0xb3, 0x6a, 0xb0, 0x8e, - 0xdb, 0x68, 0xe4, 0x44, 0x46, 0x81, 0x71, 0x70, 0x7e, 0xdb, 0x5d, 0x16, 0x59, 0x3a, 0x6b, 0x3f, - 0x4c, 0xd2, 0xba, 0x46, 0x1c, 0x9e, 0xdf, 0x5c, 0x0c, 0xce, 0xd7, 0x75, 0xea, 0x27, 0xff, 0x33, - 0x5d, 0x15, 0x0c, 0x9f, 0xaf, 0x3d, 0x24, 0x3c, 0x5f, 0x43, 0x14, 0xd6, 0x67, 0xc2, 0xc4, 0x41, - 0xbc, 0xe2, 0x4b, 0x62, 0xbe, 0x36, 0xe2, 0x70, 0x7d, 0x5c, 0xcc, 0xee, 0x0d, 0x8c, 0x87, 0x71, - 0x2e, 0x58, 0x99, 0xc7, 0xd9, 0x5e, 0x16, 0xcf, 0xab, 0x01, 0x31, 0xc7, 0xf8, 0x14, 0xb1, 0x37, - 0xa0, 0x69, 0xa4, 0x19, 0xc7, 0xd5, 0x5e, 0x7c, 0xc5, 0xcb, 0x54, 0xd0, 0xcd, 0x68, 0x91, 0xce, - 0x66, 0xf4, 0x50, 0xd4, 0xdb, 0xa8, 0x9c, 0x5d, 0xa4, 0x57, 0x2c, 0x09, 0x78, 0x6b, 0x90, 0x1e, - 0xde, 0x1c, 0x14, 0xe9, 0xb4, 0x09, 0x5f, 0x96, 0x33, 0x46, 0x76, 0x9a, 0x12, 0x77, 0x76, 0x9a, - 0xc1, 0xb4, 0x87, 0xbf, 0x58, 0x8b, 0x7e, 0x43, 0x49, 0xdd, 0x27, 0x3c, 0xbb, 0x71, 0x75, 0x71, - 0xc6, 0xe3, 0x32, 0x19, 0x7c, 0x80, 0xd9, 0x41, 0x51, 0xe3, 0xfa, 0xc9, 0x75, 0x54, 0x60, 0xb3, - 0xd6, 0x79, 0xb7, 0x1d, 0x71, 0x68, 0xb3, 0x7a, 0x48, 0xb8, 0x59, 0x21, 0x0a, 0x27, 0x10, 0x29, - 0x57, 0x07, 0x80, 0xeb, 0xa4, 0xbe, 0x7f, 0x0a, 0xb8, 0xd1, 0xc9, 0xc1, 0xf9, 0xb1, 0x16, 0xfa, - 0xd1, 0xb2, 0x45, 0xd9, 0xc0, 0x23, 0x66, 0xd8, 0x17, 0x27, 0x3d, 0x9b, 0x51, 0x11, 0xf6, 0xdc, - 0x1a, 0x19, 0xc3, 0xbe, 0x38, 0xe1, 0xd9, 0x99, 0xd6, 0x42, 0x9e, 0x91, 0xa9, 0x6d, 0xd8, 0x17, - 0x87, 0xd9, 0x97, 0x66, 0x9a, 0x75, 0xe1, 0x61, 0xc0, 0x0e, 0x5c, 0x1b, 0x36, 0x7b, 0xb1, 0xda, - 0xe1, 0x5f, 0xad, 0x45, 0xdf, 0xb5, 0x1e, 0x0f, 0x79, 0x92, 0x9e, 0xaf, 0x14, 0xf4, 0x22, 0xce, - 0x96, 0xac, 0x1a, 0x3c, 0xa1, 0xac, 0xb5, 0x59, 0x53, 0x82, 0xa7, 0xd7, 0xd2, 0x81, 0x63, 0x67, - 0x54, 0x14, 0xd9, 0x6a, 0xca, 0x16, 0x45, 0x46, 0x8e, 0x1d, 0x0f, 0x09, 0x8f, 0x1d, 0x88, 0xc2, - 0xac, 0x7c, 0xca, 0xeb, 0x9c, 0x1f, 0xcd, 0xca, 0xa5, 0x28, 0x9c, 0x95, 0x37, 0x08, 0xcc, 0x95, - 0xa6, 0x7c, 0x87, 0x67, 0x19, 0x9b, 0x89, 0xf6, 0x2d, 0x11, 0xa3, 0x69, 0x89, 0x70, 0xae, 0x04, - 0x48, 0x7b, 0x2a, 0xd7, 0xec, 0x21, 0xe3, 0x92, 0x3d, 0x5b, 0x1d, 0xa4, 0xf9, 0xe5, 0x00, 0x4f, - 0x0b, 0x2c, 0x40, 0x9c, 0xca, 0xa1, 0x20, 0xdc, 0xab, 0x9e, 0xe6, 0x09, 0xc7, 0xf7, 0xaa, 0xb5, - 0x24, 0xbc, 0x57, 0xd5, 0x04, 0x34, 0x79, 0xc2, 0x28, 0x93, 0xb5, 0x24, 0x6c, 0x52, 0x13, 0xd8, - 0x54, 0xa8, 0x9f, 0x14, 0x91, 0x53, 0x21, 0x78, 0x36, 0xb4, 0xd1, 0xc9, 0xc1, 0x3d, 0x97, 0x76, - 0x80, 0x46, 0x04, 0x30, 0x7e, 0x27, 0xc8, 0xc0, 0xd0, 0x6f, 0x76, 0xc3, 0x7b, 0x4c, 0xcc, 0x2e, - 0xf0, 0xd0, 0xf7, 0x90, 0x70, 0xe8, 0x43, 0x14, 0xb6, 0xd5, 0x94, 0x9b, 0xdd, 0xfc, 0x3a, 0x1e, - 0x78, 0xad, 0x9d, 0xfc, 0x46, 0x27, 0x07, 0xdb, 0x6a, 0xbc, 0xa0, 0xdb, 0x4a, 0xc9, 0xc2, 0x6d, - 0x65, 0x18, 0x58, 0x7a, 0x25, 0x90, 0x87, 0x64, 0xeb, 0xb4, 0xa2, 0x77, 0x4c, 0xb6, 0xd1, 0xc9, - 0x69, 0x27, 0xff, 0x64, 0xf6, 0x87, 0x4a, 0x7a, 0xc4, 0xeb, 0xc1, 0xf7, 0x22, 0xce, 0xd2, 0x24, - 0x16, 0x6c, 0xca, 0x2f, 0x59, 0x8e, 0x6f, 0xc5, 0x74, 0x69, 0x15, 0x3f, 0xf4, 0x14, 0xc2, 0x5b, - 0xb1, 0xb0, 0x22, 0x8c, 0x13, 0x45, 0x9f, 0x56, 0x6c, 0x27, 0xae, 0x88, 0x29, 0xd2, 0x43, 0xc2, - 0x71, 0x02, 0x51, 0x98, 0x08, 0x2b, 0xf9, 0xf3, 0xd7, 0x05, 0x2b, 0x53, 0x96, 0xcf, 0x18, 0x9e, - 0x08, 0x43, 0x2a, 0x9c, 0x08, 0x23, 0x34, 0xdc, 0x04, 0xee, 0xc6, 0x82, 0x3d, 0x5b, 0x4d, 0xd3, - 0x05, 0xab, 0x44, 0xbc, 0x28, 0xf0, 0x4d, 0x20, 0x80, 0xc2, 0x9b, 0xc0, 0x36, 0xdc, 0x3a, 0x73, - 0x32, 0x33, 0x6d, 0xfb, 0xd6, 0x1a, 0x24, 0x02, 0xb7, 0xd6, 0x08, 0x14, 0x36, 0xac, 0x05, 0xd0, - 0xa7, 0x0f, 0x2d, 0x2b, 0xc1, 0xa7, 0x0f, 0x34, 0xdd, 0x3a, 0xc9, 0x33, 0xcc, 0xa4, 0x1e, 0x9a, - 0x1d, 0x45, 0x9f, 0xb8, 0x43, 0x74, 0xb3, 0x17, 0x8b, 0x1f, 0x1d, 0x9e, 0xb0, 0x2c, 0x96, 0xeb, - 0x61, 0xe0, 0x7c, 0xae, 0x61, 0xfa, 0x1c, 0x1d, 0x3a, 0xac, 0x76, 0xf8, 0x67, 0x6b, 0xd1, 0x7b, - 0x98, 0xc7, 0x2f, 0x0a, 0xe9, 0xf7, 0x71, 0xb7, 0x2d, 0x45, 0x12, 0xd7, 0xf2, 0xc2, 0x1a, 0xf6, - 0x66, 0x49, 0x23, 0xb2, 0xb7, 0xf6, 0x74, 0x01, 0xfc, 0x6c, 0xd0, 0x94, 0x1f, 0x72, 0xc4, 0xcd, - 0x92, 0x10, 0x6f, 0x37, 0x5a, 0x7e, 0xb9, 0x2a, 0xb0, 0xd1, 0x32, 0x36, 0xb4, 0x98, 0xd8, 0x68, - 0x21, 0x98, 0x1d, 0x9d, 0x6e, 0xf5, 0x5e, 0xa6, 0xe2, 0x42, 0x26, 0x72, 0x60, 0x74, 0x7a, 0x65, - 0x35, 0x10, 0x31, 0x3a, 0x49, 0x18, 0xa6, 0x3a, 0x0d, 0x58, 0x8f, 0x4d, 0x6c, 0x2e, 0x37, 0x86, - 0xdc, 0x91, 0x79, 0xbf, 0x1b, 0x84, 0xf1, 0xda, 0x88, 0xf5, 0x9e, 0xea, 0x61, 0xc8, 0x02, 0xd8, - 0x57, 0x6d, 0xf6, 0x62, 0xb5, 0xc3, 0x3f, 0x89, 0xbe, 0xd3, 0xaa, 0xd8, 0x1e, 0x8b, 0xc5, 0xb2, - 0x64, 0xc9, 0x60, 0xbb, 0xa3, 0xdc, 0x0d, 0x68, 0x5c, 0x3f, 0xee, 0xaf, 0xd0, 0x4a, 0xfe, 0x1b, - 0x4e, 0x85, 0x95, 0x29, 0xc3, 0x93, 0x90, 0x49, 0x9f, 0x0d, 0x26, 0xff, 0xb4, 0x4e, 0x6b, 0xff, - 0xee, 0x46, 0xd7, 0xe8, 0x2a, 0x4e, 0x33, 0xf9, 0x14, 0xf8, 0x83, 0x90, 0x51, 0x0f, 0x0d, 0xee, - 0xdf, 0x49, 0x95, 0xd6, 0xcc, 0x2c, 0xc7, 0xb8, 0xb3, 0xef, 0x7b, 0x44, 0xcf, 0x04, 0xc8, 0xb6, - 0x6f, 0xab, 0x27, 0xad, 0xdd, 0x8a, 0x66, 0xc9, 0xab, 0xff, 0xec, 0x06, 0x39, 0xe6, 0x55, 0xab, - 0x22, 0x91, 0xbe, 0xd5, 0x93, 0xd6, 0x5e, 0xff, 0x38, 0x7a, 0xb7, 0xed, 0x55, 0x2f, 0x44, 0xdb, - 0x9d, 0xa6, 0xc0, 0x5a, 0xf4, 0xb8, 0xbf, 0x82, 0x76, 0xff, 0xaf, 0xe6, 0xc0, 0x5b, 0xf9, 0x9f, - 0xf1, 0xc5, 0x82, 0xe5, 0x09, 0x4b, 0x1a, 0x8d, 0xaa, 0xde, 0x98, 0x7d, 0x4a, 0xdb, 0x35, 0x0a, - 0x43, 0x57, 0xc3, 0x94, 0xe8, 0x37, 0xbf, 0x81, 0xa6, 0x2e, 0xda, 0x7f, 0xae, 0x45, 0x0f, 0xd0, - 0xa2, 0x35, 0x81, 0xeb, 0x15, 0xf1, 0x77, 0xfa, 0x38, 0xc2, 0x34, 0x4d, 0x51, 0x47, 0x3f, 0x83, - 0x05, 0x5d, 0xe4, 0x7f, 0x5b, 0x8b, 0x6e, 0x5b, 0xc5, 0x3a, 0xbc, 0x77, 0x78, 0x7e, 0x9e, 0xa5, - 0x33, 0x21, 0x1f, 0xf5, 0x6a, 0x15, 0xba, 0x39, 0x29, 0x8d, 0xee, 0xe6, 0x0c, 0x68, 0xea, 0xb2, - 0xfd, 0xe3, 0x5a, 0x74, 0xcb, 0x6d, 0x4e, 0xf9, 0x9c, 0x58, 0x1d, 0xbb, 0x36, 0x8a, 0xd5, 0xe0, - 0x63, 0xba, 0x0d, 0x30, 0xde, 0x94, 0xeb, 0x93, 0x6b, 0xeb, 0xd9, 0xbd, 0xfa, 0x67, 0x69, 0x25, - 0x78, 0xb9, 0x9a, 0x5c, 0xf0, 0x57, 0xcd, 0xdb, 0x58, 0xfe, 0x6a, 0xa1, 0x81, 0xa1, 0x43, 0x10, - 0x7b, 0x75, 0x9c, 0x6c, 0xb9, 0xb2, 0x6f, 0x6d, 0x55, 0x84, 0x2b, 0x87, 0xe8, 0x70, 0xe5, 0x93, - 0x76, 0xad, 0x6c, 0x6a, 0x65, 0x5f, 0x31, 0xdb, 0xc0, 0x8b, 0xda, 0x7e, 0xcd, 0xec, 0x7e, 0x37, - 0x68, 0x33, 0x66, 0x2d, 0xde, 0x4d, 0xcf, 0xcf, 0x4d, 0x9d, 0xf0, 0x92, 0xba, 0x08, 0x91, 0x31, - 0x13, 0xa8, 0xdd, 0xf4, 0xed, 0xa5, 0x19, 0x93, 0x8f, 0xaa, 0xbe, 0x38, 0x3f, 0xcf, 0x78, 0x9c, - 0x80, 0x4d, 0x5f, 0x2d, 0x1e, 0xba, 0x72, 0x62, 0xd3, 0x87, 0x71, 0xf6, 0x12, 0x4c, 0x2d, 0xad, - 0xc7, 0x5c, 0x3e, 0x4b, 0x33, 0x78, 0x99, 0x5b, 0x6a, 0x1a, 0x21, 0x71, 0x09, 0xa6, 0x05, 0xd9, - 0xc4, 0xac, 0x16, 0xd5, 0x63, 0xa5, 0x29, 0xff, 0xbd, 0xb6, 0xa2, 0x23, 0x26, 0x12, 0x33, 0x04, - 0xb3, 0x87, 0x2a, 0xb5, 0xf0, 0xb4, 0x90, 0xc6, 0x6f, 0xb5, 0xb5, 0x94, 0x84, 0x38, 0x54, 0xf1, - 0x09, 0xbb, 0x87, 0xaf, 0xff, 0xbe, 0xcb, 0x5f, 0xe5, 0xd2, 0xe8, 0xed, 0xb6, 0x4a, 0x23, 0x23, - 0xf6, 0xf0, 0x90, 0xd1, 0x86, 0x3f, 0x8f, 0x7e, 0x5e, 0x1a, 0x2e, 0x79, 0x31, 0xb8, 0x81, 0x28, - 0x94, 0xce, 0xd5, 0xe7, 0x9b, 0xa4, 0xdc, 0xde, 0x99, 0x31, 0xb1, 0x71, 0x5a, 0xc5, 0x73, 0xf8, - 0xbe, 0x82, 0xed, 0x71, 0x29, 0x25, 0xee, 0xcc, 0xb4, 0x29, 0x3f, 0x2a, 0x8e, 0x78, 0xa2, 0xad, - 0x23, 0x35, 0x34, 0xc2, 0x50, 0x54, 0xb8, 0x90, 0x4d, 0xa6, 0x8f, 0xe2, 0xab, 0x74, 0x6e, 0x12, - 0x1e, 0x35, 0x7d, 0x55, 0x20, 0x99, 0xb6, 0xcc, 0xd0, 0x81, 0x88, 0x64, 0x9a, 0x84, 0x9d, 0xc9, - 0xd8, 0x32, 0xfb, 0xcd, 0x31, 0xf4, 0x38, 0x3f, 0xe7, 0x75, 0xea, 0x7d, 0x90, 0xe6, 0x97, 0x70, - 0x32, 0x76, 0x4c, 0xe2, 0x3c, 0x31, 0x19, 0xf7, 0xd1, 0xb3, 0xbb, 0xa6, 0xe6, 0x8c, 0xd6, 0x5e, - 0xd4, 0x50, 0x1a, 0x60, 0xd7, 0x64, 0x8e, 0x72, 0x21, 0x47, 0xec, 0x9a, 0x42, 0xbc, 0xed, 0x62, - 0xe3, 0x3c, 0xe3, 0x39, 0xec, 0x62, 0x6b, 0xa1, 0x16, 0x12, 0x5d, 0xdc, 0x82, 0xec, 0x7c, 0xdc, - 0x88, 0xd4, 0xa9, 0xdf, 0x28, 0xcb, 0xc0, 0x7c, 0x6c, 0x54, 0x0d, 0x40, 0xcc, 0xc7, 0x28, 0xa8, - 0xfd, 0x9c, 0x44, 0xdf, 0xaa, 0x9b, 0xf4, 0xb8, 0x64, 0x57, 0x29, 0x83, 0x77, 0x8a, 0x1c, 0x09, - 0x31, 0xfe, 0x7d, 0xc2, 0x8e, 0xac, 0xd3, 0xbc, 0x2a, 0xb2, 0xb8, 0xba, 0xd0, 0xb7, 0x4c, 0xfc, - 0x3a, 0x37, 0x42, 0x78, 0xcf, 0xe4, 0x5e, 0x07, 0x65, 0x27, 0xf5, 0x46, 0x66, 0xa6, 0x98, 0x75, - 0x5c, 0xb5, 0x35, 0xcd, 0x6c, 0x74, 0x72, 0xf6, 0x51, 0xce, 0x7e, 0x9c, 0x65, 0xac, 0x5c, 0x35, - 0xb2, 0xc3, 0x38, 0x4f, 0xcf, 0x59, 0x25, 0xc0, 0xa3, 0x1c, 0x4d, 0x0d, 0x21, 0x46, 0x3c, 0xca, - 0x09, 0xe0, 0x76, 0x37, 0x09, 0x3c, 0x8f, 0xf3, 0x84, 0xbd, 0x06, 0xbb, 0x49, 0x68, 0x47, 0x32, - 0xc4, 0x6e, 0x92, 0x62, 0xed, 0x23, 0x8d, 0x67, 0x19, 0x9f, 0x5d, 0xea, 0x25, 0xc0, 0xef, 0x60, - 0x29, 0x81, 0x6b, 0xc0, 0xed, 0x10, 0x62, 0x17, 0x01, 0x29, 0x38, 0x61, 0x45, 0x16, 0xcf, 0xe0, - 0xc5, 0x32, 0xa5, 0xa3, 0x65, 0xc4, 0x22, 0x00, 0x19, 0x50, 0x5c, 0x7d, 0x61, 0x0d, 0x2b, 0x2e, - 0xb8, 0xaf, 0x76, 0x3b, 0x84, 0xd8, 0x65, 0x50, 0x0a, 0x26, 0x45, 0x96, 0x0a, 0x30, 0x0c, 0x94, - 0x86, 0x94, 0x10, 0xc3, 0xc0, 0x27, 0x80, 0xc9, 0x43, 0x56, 0xce, 0x19, 0x6a, 0x52, 0x4a, 0x82, - 0x26, 0x1b, 0xc2, 0xde, 0xa2, 0x57, 0x75, 0xe7, 0xc5, 0x0a, 0xdc, 0xa2, 0xd7, 0xd5, 0xe2, 0xc5, - 0x8a, 0xb8, 0x45, 0xef, 0x01, 0xa0, 0x88, 0xc7, 0x71, 0x25, 0xf0, 0x22, 0x4a, 0x49, 0xb0, 0x88, - 0x0d, 0x61, 0xd7, 0x68, 0x55, 0xc4, 0xa5, 0x00, 0x6b, 0xb4, 0x2e, 0x80, 0x73, 0xb5, 0xe2, 0x26, - 0x29, 0xb7, 0x33, 0x89, 0xea, 0x15, 0x26, 0xf6, 0x52, 0x96, 0x25, 0x15, 0x98, 0x49, 0x74, 0xbb, - 0x37, 0x52, 0x62, 0x26, 0x69, 0x53, 0x20, 0x94, 0xf4, 0x73, 0x19, 0xac, 0x76, 0xe0, 0xb1, 0xcc, - 0xed, 0x10, 0x62, 0xe7, 0xa7, 0xa6, 0xd0, 0x3b, 0x71, 0x59, 0xa6, 0xf5, 0xe2, 0xbf, 0x8e, 0x17, - 0xa8, 0x91, 0x13, 0xf3, 0x13, 0xc6, 0x81, 0xe1, 0xd5, 0x4c, 0xdc, 0x58, 0xc1, 0xe0, 0xd4, 0x7d, - 0x27, 0xc8, 0xd8, 0x8c, 0x53, 0x4a, 0x9c, 0xbb, 0x01, 0x58, 0x6b, 0x22, 0x57, 0x03, 0xd6, 0xbb, - 0x30, 0xe7, 0x85, 0x3e, 0xe3, 0xe2, 0x90, 0x5f, 0xb1, 0x29, 0x7f, 0xfe, 0x3a, 0xad, 0xea, 0x4d, - 0xa0, 0x5e, 0xb9, 0x9f, 0x12, 0x96, 0x30, 0x98, 0x78, 0xa1, 0xaf, 0x53, 0xc9, 0x26, 0x10, 0xa0, - 0x2c, 0x47, 0xec, 0x15, 0x9a, 0x40, 0x40, 0x8b, 0x86, 0x23, 0x12, 0x88, 0x10, 0x6f, 0xcf, 0xf1, - 0x8c, 0x73, 0xfd, 0x15, 0x87, 0x29, 0x6f, 0x72, 0x39, 0xca, 0x1a, 0x04, 0x89, 0xa3, 0x94, 0xa0, - 0x82, 0xdd, 0x5f, 0x1a, 0xff, 0x76, 0x88, 0xdd, 0x27, 0xec, 0xb4, 0x87, 0xd9, 0x83, 0x1e, 0x24, - 0xe2, 0xca, 0x5e, 0x70, 0xa1, 0x5c, 0xb5, 0xef, 0xb7, 0x3c, 0xe8, 0x41, 0x3a, 0x67, 0x82, 0x6e, - 0xb5, 0x9e, 0xc5, 0xb3, 0xcb, 0x79, 0xc9, 0x97, 0x79, 0xb2, 0xc3, 0x33, 0x5e, 0x82, 0x33, 0x41, - 0xaf, 0xd4, 0x00, 0x25, 0xce, 0x04, 0x3b, 0x54, 0x6c, 0x06, 0xe7, 0x96, 0x62, 0x94, 0xa5, 0x73, - 0xb8, 0xa3, 0xf6, 0x0c, 0x49, 0x80, 0xc8, 0xe0, 0x50, 0x10, 0x09, 0x22, 0xb5, 0xe3, 0x16, 0xe9, - 0x2c, 0xce, 0x94, 0xbf, 0x6d, 0xda, 0x8c, 0x07, 0x76, 0x06, 0x11, 0xa2, 0x80, 0xd4, 0x73, 0xba, - 0x2c, 0xf3, 0x71, 0x2e, 0x38, 0x59, 0xcf, 0x06, 0xe8, 0xac, 0xa7, 0x03, 0x82, 0x69, 0x75, 0xca, - 0x5e, 0xd7, 0xa5, 0xa9, 0xff, 0xc1, 0xa6, 0xd5, 0xfa, 0xef, 0x43, 0x2d, 0x0f, 0x4d, 0xab, 0x80, - 0x03, 0x95, 0xd1, 0x4e, 0x54, 0xc0, 0x04, 0xb4, 0xfd, 0x30, 0xb9, 0xdf, 0x0d, 0xe2, 0x7e, 0x26, - 0x62, 0x95, 0xb1, 0x90, 0x1f, 0x09, 0xf4, 0xf1, 0xd3, 0x80, 0xf6, 0xb8, 0xc5, 0xab, 0xcf, 0x05, - 0x9b, 0x5d, 0xb6, 0xee, 0xeb, 0xf9, 0x05, 0x55, 0x08, 0x71, 0xdc, 0x42, 0xa0, 0x78, 0x17, 0x8d, - 0x67, 0x3c, 0x0f, 0x75, 0x51, 0x2d, 0xef, 0xd3, 0x45, 0x9a, 0xb3, 0x9b, 0x5f, 0x23, 0xd5, 0x91, - 0xa9, 0xba, 0x69, 0x93, 0xb0, 0xe0, 0x42, 0xc4, 0xe6, 0x97, 0x84, 0x6d, 0x4e, 0x0e, 0x7d, 0x1e, - 0xb6, 0x5f, 0x66, 0x68, 0x59, 0x39, 0xa4, 0x5f, 0x66, 0xa0, 0x58, 0xba, 0x92, 0x2a, 0x46, 0x3a, - 0xac, 0xf8, 0x71, 0xf2, 0xa8, 0x1f, 0x6c, 0xb7, 0x3c, 0x9e, 0xcf, 0x9d, 0x8c, 0xc5, 0xa5, 0xf2, - 0xba, 0x15, 0x30, 0x64, 0x31, 0x62, 0xcb, 0x13, 0xc0, 0xc1, 0x14, 0xe6, 0x79, 0xde, 0xe1, 0xb9, - 0x60, 0xb9, 0xc0, 0xa6, 0x30, 0xdf, 0x98, 0x06, 0x43, 0x53, 0x18, 0xa5, 0x00, 0xe2, 0x56, 0x9e, - 0x07, 0x31, 0x71, 0x14, 0x2f, 0xd0, 0x8c, 0x4d, 0x9d, 0xf5, 0x28, 0x79, 0x28, 0x6e, 0x01, 0xe7, - 0x3c, 0x64, 0x76, 0xbd, 0x4c, 0xe3, 0x72, 0x6e, 0x4e, 0x37, 0x92, 0xc1, 0x63, 0xda, 0x8e, 0x4f, - 0x12, 0x0f, 0x99, 0xc3, 0x1a, 0x60, 0xda, 0x19, 0x2f, 0xe2, 0xb9, 0xa9, 0x29, 0x52, 0x03, 0x29, - 0x6f, 0x55, 0xf5, 0x7e, 0x37, 0x08, 0xfc, 0xbc, 0x48, 0x13, 0xc6, 0x03, 0x7e, 0xa4, 0xbc, 0x8f, - 0x1f, 0x08, 0x82, 0xec, 0xad, 0xae, 0xb7, 0xda, 0xd1, 0x8d, 0xf2, 0x44, 0xef, 0x63, 0x87, 0x44, - 0xf3, 0x00, 0x2e, 0x94, 0xbd, 0x11, 0x3c, 0x18, 0xa3, 0xcd, 0x01, 0x6d, 0x68, 0x8c, 0x9a, 0xf3, - 0xd7, 0x3e, 0x63, 0x14, 0x83, 0xb5, 0xcf, 0x1f, 0xeb, 0x31, 0xba, 0x1b, 0x8b, 0xb8, 0xce, 0xdb, - 0x5f, 0xa4, 0xec, 0x95, 0xde, 0x08, 0x23, 0xf5, 0x6d, 0xa8, 0xa1, 0x7c, 0x17, 0x1b, 0xec, 0x8a, - 0xb7, 0x7b, 0xf3, 0x01, 0xdf, 0x7a, 0x87, 0xd0, 0xe9, 0x1b, 0x6c, 0x15, 0xb6, 0x7b, 0xf3, 0x01, - 0xdf, 0xfa, 0x93, 0x12, 0x9d, 0xbe, 0xc1, 0x77, 0x25, 0xb6, 0x7b, 0xf3, 0xda, 0xf7, 0x9f, 0x37, - 0x03, 0xd7, 0x75, 0x5e, 0xe7, 0x61, 0x33, 0x91, 0x5e, 0x31, 0x2c, 0x9d, 0xf4, 0xed, 0x19, 0x34, - 0x94, 0x4e, 0xd2, 0x2a, 0xce, 0x47, 0xdd, 0xb0, 0x52, 0x1c, 0xf3, 0x2a, 0x95, 0x97, 0x44, 0x9e, - 0xf6, 0x30, 0xda, 0xc0, 0xa1, 0x4d, 0x53, 0x48, 0xc9, 0x3e, 0xee, 0xf6, 0x50, 0x7b, 0x3d, 0xff, - 0x51, 0xc0, 0x5e, 0xfb, 0x96, 0xfe, 0x56, 0x4f, 0xda, 0x3e, 0x78, 0xf6, 0x98, 0xe6, 0x91, 0xe1, - 0x84, 0xa1, 0xab, 0x84, 0x31, 0x65, 0x1e, 0x25, 0xbb, 0xcf, 0x4e, 0x1f, 0xf7, 0x57, 0xe8, 0x70, - 0x3f, 0x4a, 0x92, 0x7e, 0xee, 0xdd, 0x67, 0xee, 0x8f, 0xfb, 0x2b, 0x68, 0xf7, 0x7f, 0xd9, 0x6c, - 0x6b, 0xa0, 0x7f, 0x3d, 0x06, 0x9f, 0xf4, 0xb1, 0x08, 0xc6, 0xe1, 0xd3, 0x6b, 0xe9, 0xe8, 0x82, - 0xfc, 0x6d, 0xb3, 0x7f, 0x6f, 0x50, 0xf9, 0x8e, 0x94, 0x7c, 0xb7, 0x5a, 0x0f, 0xc9, 0x50, 0x54, - 0x59, 0x18, 0x0e, 0xcc, 0x8f, 0xae, 0xa9, 0xe5, 0x7c, 0x61, 0xd0, 0x83, 0xf5, 0xbb, 0xbc, 0x4e, - 0x79, 0x42, 0x96, 0x1d, 0x1a, 0x16, 0xe8, 0xe3, 0xeb, 0xaa, 0x51, 0x43, 0xd5, 0x81, 0xe5, 0x37, - 0x76, 0x9e, 0xf6, 0x34, 0xec, 0x7d, 0x75, 0xe7, 0xc3, 0xeb, 0x29, 0xe9, 0xb2, 0xfc, 0xc7, 0x5a, - 0x74, 0xcf, 0x63, 0xed, 0xe3, 0x0c, 0x70, 0xe8, 0xf2, 0x83, 0x80, 0x7d, 0x4a, 0xc9, 0x14, 0xee, - 0xb7, 0xbe, 0x99, 0xb2, 0xfd, 0x1c, 0x9f, 0xa7, 0xb2, 0x97, 0x66, 0x82, 0x95, 0xed, 0xcf, 0xf1, - 0xf9, 0x76, 0x15, 0x35, 0xa4, 0x3f, 0xc7, 0x17, 0xc0, 0x9d, 0xcf, 0xf1, 0x21, 0x9e, 0xd1, 0xcf, - 0xf1, 0xa1, 0xd6, 0x82, 0x9f, 0xe3, 0x0b, 0x6b, 0x50, 0xab, 0x4b, 0x53, 0x04, 0x75, 0x6c, 0xde, - 0xcb, 0xa2, 0x7f, 0x8a, 0xfe, 0xe4, 0x3a, 0x2a, 0xc4, 0xfa, 0xaa, 0x38, 0x79, 0xcd, 0xb3, 0x47, - 0x9b, 0x7a, 0x57, 0x3d, 0xb7, 0x7b, 0xf3, 0xda, 0xf7, 0x8f, 0xf4, 0xe6, 0xca, 0xac, 0x26, 0xbc, - 0x94, 0x9f, 0x62, 0xdc, 0x0c, 0xad, 0x0e, 0xb5, 0x05, 0xb7, 0xe7, 0x1f, 0xf5, 0x83, 0x89, 0xea, - 0xd6, 0x84, 0xee, 0xf4, 0x61, 0x97, 0x21, 0xd0, 0xe5, 0xdb, 0xbd, 0x79, 0x62, 0x19, 0x51, 0xbe, - 0x55, 0x6f, 0xf7, 0x30, 0xe6, 0xf7, 0xf5, 0xe3, 0xfe, 0x0a, 0xda, 0xfd, 0x95, 0xce, 0x5a, 0x5d, - 0xf7, 0xb2, 0x9f, 0xb7, 0xba, 0x4c, 0x4d, 0xbc, 0x6e, 0x1e, 0xf6, 0xc5, 0x43, 0xf9, 0x8b, 0xbb, - 0x84, 0x76, 0xe5, 0x2f, 0xe8, 0x32, 0xfa, 0xe1, 0xf5, 0x94, 0x74, 0x59, 0xfe, 0x61, 0x2d, 0xba, - 0x49, 0x96, 0x45, 0xc7, 0xc1, 0xc7, 0x7d, 0x2d, 0x83, 0x78, 0xf8, 0xe4, 0xda, 0x7a, 0xba, 0x50, - 0xff, 0xbc, 0x16, 0xdd, 0x0a, 0x14, 0x4a, 0x05, 0xc8, 0x35, 0xac, 0xfb, 0x81, 0xf2, 0xe9, 0xf5, - 0x15, 0xa9, 0xe5, 0xde, 0xc5, 0x27, 0xed, 0x4f, 0xab, 0x05, 0x6c, 0x4f, 0xe8, 0x4f, 0xab, 0x75, - 0x6b, 0xc1, 0x33, 0xa6, 0xf8, 0xac, 0xd9, 0xf3, 0xa1, 0x67, 0x4c, 0xf2, 0x82, 0x66, 0xf0, 0xa3, - 0x2d, 0x18, 0x87, 0x39, 0x79, 0xfe, 0xba, 0x88, 0xf3, 0x84, 0x76, 0xa2, 0xe4, 0xdd, 0x4e, 0x0c, - 0x07, 0xcf, 0xe6, 0x6a, 0xe9, 0x09, 0x6f, 0xf6, 0x71, 0x0f, 0x28, 0x7d, 0x83, 0x04, 0xcf, 0xe6, - 0x5a, 0x28, 0xe1, 0x4d, 0x67, 0x8d, 0x21, 0x6f, 0x20, 0x59, 0x7c, 0xd8, 0x07, 0x05, 0x3b, 0x04, - 0xe3, 0xcd, 0x1c, 0xf9, 0x3f, 0x0a, 0x59, 0x69, 0x1d, 0xfb, 0x6f, 0xf5, 0xa4, 0x09, 0xb7, 0x13, - 0x26, 0x3e, 0x63, 0x71, 0xc2, 0xca, 0xa0, 0x5b, 0x43, 0xf5, 0x72, 0xeb, 0xd2, 0x98, 0xdb, 0x1d, - 0x9e, 0x2d, 0x17, 0xb9, 0xee, 0x4c, 0xd2, 0xad, 0x4b, 0x75, 0xbb, 0x05, 0x34, 0x3c, 0x95, 0xb4, - 0x6e, 0x65, 0x7a, 0xf9, 0x30, 0x6c, 0xc6, 0xcb, 0x2a, 0x37, 0x7b, 0xb1, 0x74, 0x3d, 0x75, 0x18, - 0x75, 0xd4, 0x13, 0x44, 0xd2, 0x56, 0x4f, 0x1a, 0x1e, 0x0f, 0x3a, 0x6e, 0x4d, 0x3c, 0x6d, 0x77, - 0xd8, 0x6a, 0x85, 0xd4, 0xe3, 0xfe, 0x0a, 0xf0, 0x30, 0x56, 0x47, 0xd5, 0x41, 0x5a, 0x89, 0xbd, - 0x34, 0xcb, 0x06, 0x9b, 0x81, 0x30, 0x69, 0xa0, 0xe0, 0x61, 0x2c, 0x02, 0x13, 0x91, 0xdc, 0x1c, - 0x5e, 0xe6, 0x83, 0x2e, 0x3b, 0x92, 0xea, 0x15, 0xc9, 0x2e, 0x0d, 0x0e, 0xd4, 0x9c, 0xa6, 0x36, - 0xb5, 0x1d, 0x86, 0x1b, 0xae, 0x55, 0xe1, 0xed, 0xde, 0x3c, 0x78, 0xda, 0x2f, 0x29, 0xb9, 0xb2, - 0xdc, 0xa5, 0x4c, 0x78, 0x2b, 0xc9, 0xbd, 0x0e, 0x0a, 0x1c, 0x4a, 0xaa, 0x61, 0xf4, 0x32, 0x4d, - 0xe6, 0x4c, 0xa0, 0x0f, 0xaa, 0x5c, 0x20, 0xf8, 0xa0, 0x0a, 0x80, 0xa0, 0xeb, 0xd4, 0xdf, 0xcd, - 0x69, 0xec, 0x38, 0xc1, 0xba, 0x4e, 0x2b, 0x3b, 0x54, 0xa8, 0xeb, 0x50, 0x1a, 0xcc, 0x06, 0xc6, - 0xad, 0xfe, 0xcc, 0xc5, 0xc3, 0x90, 0x19, 0xf0, 0xad, 0x8b, 0xcd, 0x5e, 0x2c, 0x58, 0x51, 0xac, - 0xc3, 0x74, 0x91, 0x0a, 0x6c, 0x45, 0x71, 0x6c, 0xd4, 0x48, 0x68, 0x45, 0x69, 0xa3, 0x54, 0xf5, - 0xea, 0x1c, 0x61, 0x9c, 0x84, 0xab, 0xa7, 0x98, 0x7e, 0xd5, 0x33, 0x6c, 0xeb, 0xb9, 0x6a, 0x6e, - 0x42, 0x46, 0x5c, 0xe8, 0xcd, 0x32, 0x12, 0xdb, 0xf2, 0xf5, 0x67, 0x08, 0x86, 0x66, 0x1d, 0x4a, - 0x01, 0x3e, 0x2f, 0xa8, 0xb9, 0xe6, 0xd1, 0x6f, 0x51, 0xb0, 0xb8, 0x8c, 0xf3, 0x19, 0xba, 0x39, - 0x95, 0x06, 0x5b, 0x64, 0x68, 0x73, 0x4a, 0x6a, 0x80, 0xa7, 0xf6, 0xfe, 0xfb, 0xc5, 0xc8, 0x50, - 0x30, 0x2f, 0xf2, 0xfa, 0xaf, 0x17, 0x3f, 0xe8, 0x41, 0xc2, 0xa7, 0xf6, 0x0d, 0x60, 0xce, 0xdd, - 0x95, 0xd3, 0x0f, 0x02, 0xa6, 0x7c, 0x34, 0xb4, 0x11, 0xa6, 0x55, 0x40, 0x50, 0x3b, 0x67, 0x8b, - 0x9f, 0xb3, 0x15, 0x16, 0xd4, 0xee, 0x21, 0xe1, 0xe7, 0x6c, 0x15, 0x0a, 0xea, 0x36, 0x0a, 0xf2, - 0x4c, 0x77, 0x1f, 0xb4, 0x1e, 0xd0, 0x77, 0xb7, 0x3e, 0x1b, 0x9d, 0x1c, 0x18, 0x39, 0xbb, 0xe9, - 0x95, 0xf7, 0x98, 0x02, 0x29, 0xe8, 0x6e, 0x7a, 0x85, 0x3f, 0xa5, 0xd8, 0xec, 0xc5, 0xc2, 0x1b, - 0x01, 0xb1, 0x60, 0xaf, 0x9b, 0x47, 0xf5, 0x48, 0x71, 0xa5, 0xbc, 0xf5, 0xac, 0xfe, 0x7e, 0x37, - 0x68, 0xef, 0xdf, 0x1e, 0x97, 0x7c, 0xc6, 0xaa, 0x4a, 0x7f, 0x01, 0xd6, 0xbf, 0xe0, 0xa4, 0x65, - 0x43, 0xf0, 0xfd, 0xd7, 0xbb, 0x61, 0xc8, 0xf9, 0x6c, 0xa3, 0x12, 0xd9, 0xaf, 0x49, 0xad, 0xa3, - 0x9a, 0xed, 0x0f, 0x49, 0x6d, 0x74, 0x72, 0x76, 0x78, 0x69, 0xa9, 0xfb, 0xf9, 0xa8, 0xfb, 0xa8, - 0x3a, 0xf6, 0xe5, 0xa8, 0x07, 0x3d, 0x48, 0xed, 0xea, 0xb3, 0xe8, 0xcd, 0x03, 0x3e, 0x9f, 0xb0, - 0x3c, 0x19, 0x7c, 0xcf, 0xbf, 0xc1, 0xcb, 0xe7, 0xc3, 0xfa, 0xcf, 0xc6, 0xe8, 0x0d, 0x4a, 0x6c, - 0xef, 0x20, 0xee, 0xb2, 0xb3, 0xe5, 0x7c, 0x22, 0x62, 0x01, 0xee, 0x20, 0xca, 0xbf, 0x0f, 0x6b, - 0x01, 0x71, 0x07, 0xd1, 0x03, 0x80, 0xbd, 0x69, 0xc9, 0x18, 0x6a, 0xaf, 0x16, 0x04, 0xed, 0x69, - 0xc0, 0x66, 0x11, 0xc6, 0x5e, 0x9d, 0xa8, 0xc3, 0x3b, 0x83, 0x56, 0x47, 0x4a, 0x89, 0x2c, 0xa2, - 0x4d, 0xd9, 0xe0, 0x56, 0xd5, 0x97, 0x5f, 0xf3, 0x59, 0x2e, 0x16, 0x71, 0xb9, 0x02, 0xc1, 0xad, - 0x6b, 0xe9, 0x00, 0x44, 0x70, 0xa3, 0xa0, 0x1d, 0xb5, 0x4d, 0x33, 0xcf, 0x2e, 0xf7, 0x79, 0xc9, - 0x97, 0x22, 0xcd, 0x19, 0xfc, 0xa2, 0x8b, 0x69, 0x50, 0x97, 0x21, 0x46, 0x2d, 0xc5, 0xda, 0x2c, - 0x57, 0x12, 0xea, 0x3a, 0xa3, 0xfc, 0x04, 0x7e, 0x25, 0x78, 0x09, 0x1f, 0x67, 0x2a, 0x2b, 0x10, - 0x22, 0xb2, 0x5c, 0x12, 0x06, 0x7d, 0x7f, 0x9c, 0xe6, 0x73, 0xb4, 0xef, 0x8f, 0xdd, 0xaf, 0x2a, - 0xdf, 0xa2, 0x01, 0x3b, 0xa0, 0x54, 0xa3, 0xa9, 0x01, 0xa0, 0x5f, 0x65, 0x46, 0x1b, 0xdd, 0x25, - 0x88, 0x01, 0x85, 0x93, 0xc0, 0xd5, 0x17, 0x05, 0xcb, 0x59, 0xd2, 0x5c, 0xda, 0xc3, 0x5c, 0x79, - 0x44, 0xd0, 0x15, 0x24, 0xed, 0x5c, 0x24, 0xe5, 0x27, 0xcb, 0xfc, 0xb8, 0xe4, 0xe7, 0x69, 0xc6, - 0x4a, 0x30, 0x17, 0x29, 0x75, 0x47, 0x4e, 0xcc, 0x45, 0x18, 0x67, 0x6f, 0x7f, 0x48, 0xa9, 0xf7, - 0x3b, 0x0e, 0xd3, 0x32, 0x9e, 0xc1, 0xdb, 0x1f, 0xca, 0x46, 0x1b, 0x23, 0x4e, 0x06, 0x03, 0xb8, - 0x93, 0xe8, 0x28, 0xd7, 0xf9, 0x4a, 0xc6, 0x87, 0x7e, 0x95, 0x56, 0x7e, 0x6b, 0xb8, 0x02, 0x89, - 0x8e, 0x36, 0x87, 0x91, 0x44, 0xa2, 0x13, 0xd6, 0xb0, 0x4b, 0x89, 0xe4, 0x8e, 0xf4, 0xad, 0x26, - 0xb0, 0x94, 0x28, 0x1b, 0x8d, 0x90, 0x58, 0x4a, 0x5a, 0x10, 0x98, 0x90, 0x9a, 0x61, 0x30, 0x47, - 0x27, 0x24, 0x23, 0x0d, 0x4e, 0x48, 0x2e, 0x65, 0x27, 0x8a, 0x71, 0x9e, 0x8a, 0x34, 0xce, 0x26, - 0x4c, 0x1c, 0xc7, 0x65, 0xbc, 0x60, 0x82, 0x95, 0x70, 0xa2, 0xd0, 0xc8, 0xd0, 0x63, 0x88, 0x89, - 0x82, 0x62, 0xb5, 0xc3, 0xdf, 0x8e, 0xde, 0xae, 0xd7, 0x7d, 0x96, 0xeb, 0x5f, 0xa0, 0x7a, 0x2e, - 0x7f, 0xba, 0x6e, 0xf0, 0x8e, 0xb1, 0x31, 0x11, 0x25, 0x8b, 0x17, 0x8d, 0xed, 0xb7, 0xcc, 0xdf, - 0x25, 0xf8, 0x78, 0xad, 0x8e, 0xe7, 0x23, 0x2e, 0xd2, 0xf3, 0x7a, 0x9b, 0xad, 0x5f, 0x60, 0x02, - 0xf1, 0xec, 0x8a, 0x87, 0x81, 0x4f, 0xb1, 0x60, 0x9c, 0x9d, 0xa7, 0x5d, 0xe9, 0x09, 0x2b, 0x32, - 0x38, 0x4f, 0x7b, 0xda, 0x12, 0x20, 0xe6, 0x69, 0x14, 0xb4, 0x83, 0xd3, 0x15, 0x4f, 0x59, 0xb8, - 0x32, 0x53, 0xd6, 0xaf, 0x32, 0x53, 0xef, 0x9d, 0x90, 0x2c, 0x7a, 0xfb, 0x90, 0x2d, 0xce, 0x58, - 0x59, 0x5d, 0xa4, 0x05, 0xf5, 0x3d, 0x64, 0x4b, 0x74, 0x7e, 0x0f, 0x99, 0x40, 0xed, 0x4a, 0x60, - 0x81, 0x71, 0x75, 0x14, 0x2f, 0x98, 0xfc, 0xb0, 0x0c, 0x58, 0x09, 0x1c, 0x23, 0x0e, 0x44, 0xac, - 0x04, 0x24, 0xec, 0xbc, 0x5e, 0x66, 0x99, 0x13, 0x36, 0xaf, 0x23, 0xac, 0x3c, 0x8e, 0x57, 0x0b, - 0x96, 0x0b, 0x6d, 0x12, 0x9c, 0xc9, 0x3b, 0x26, 0x71, 0x9e, 0x38, 0x93, 0xef, 0xa3, 0xe7, 0x4c, - 0x4d, 0x5e, 0xc3, 0x1f, 0xf3, 0x52, 0xa8, 0xdf, 0x97, 0x3b, 0x2d, 0x33, 0x30, 0x35, 0xf9, 0x8d, - 0xea, 0x91, 0xc4, 0xd4, 0x14, 0xd6, 0x70, 0x7e, 0x4b, 0xc4, 0x2b, 0xc3, 0x0b, 0x56, 0x9a, 0x38, - 0x79, 0xbe, 0x88, 0xd3, 0x4c, 0x47, 0xc3, 0xf7, 0x03, 0xb6, 0x09, 0x1d, 0xe2, 0xb7, 0x44, 0xfa, - 0xea, 0x3a, 0xbf, 0xbe, 0x12, 0x2e, 0x21, 0x78, 0x44, 0xd0, 0x61, 0x9f, 0x78, 0x44, 0xd0, 0xad, - 0x65, 0x77, 0xee, 0x96, 0x95, 0xdc, 0x4a, 0x12, 0x3b, 0x3c, 0x81, 0xe7, 0x85, 0x8e, 0x4d, 0x00, - 0x12, 0x3b, 0xf7, 0xa0, 0x82, 0x4d, 0x0d, 0x2c, 0xb6, 0x97, 0xe6, 0x71, 0x96, 0xfe, 0x18, 0xa6, - 0xf5, 0x8e, 0x9d, 0x86, 0x20, 0x52, 0x03, 0x9c, 0xc4, 0x5c, 0xed, 0x33, 0x31, 0x4d, 0xeb, 0xa9, - 0xff, 0x7e, 0xa0, 0xdd, 0x24, 0xd1, 0xed, 0xca, 0x21, 0x9d, 0x6f, 0x1f, 0xc3, 0x66, 0x1d, 0x15, - 0xc5, 0xa4, 0x5e, 0x55, 0x4f, 0xd8, 0x8c, 0xa5, 0x85, 0x18, 0x7c, 0x14, 0x6e, 0x2b, 0x80, 0x13, - 0x17, 0x2d, 0x7a, 0xa8, 0x39, 0x8f, 0xef, 0xeb, 0xb9, 0x64, 0xa2, 0x7e, 0x78, 0xf5, 0xb4, 0x62, - 0xa5, 0x4e, 0x34, 0xf6, 0x99, 0x00, 0xa3, 0xd3, 0xe1, 0x86, 0x0e, 0x58, 0x57, 0x94, 0x18, 0x9d, - 0x61, 0x0d, 0x7b, 0xd8, 0xe7, 0x70, 0xfa, 0xdb, 0x01, 0xf2, 0xba, 0xe3, 0x23, 0xd2, 0x98, 0x43, - 0x11, 0x87, 0x7d, 0x34, 0x6d, 0xb3, 0xb5, 0xb6, 0xdb, 0x51, 0xbe, 0x1a, 0xc3, 0x2b, 0x13, 0x88, - 0x25, 0x89, 0x11, 0xd9, 0x5a, 0x00, 0x77, 0x0e, 0xc3, 0x4b, 0x1e, 0x27, 0xb3, 0xb8, 0x12, 0xc7, - 0xf1, 0x2a, 0xe3, 0x71, 0x22, 0xd7, 0x75, 0x78, 0x18, 0xde, 0x30, 0x43, 0x17, 0xa2, 0x0e, 0xc3, - 0x29, 0xd8, 0xcd, 0xce, 0xe4, 0xef, 0xc9, 0xea, 0xab, 0xa4, 0x30, 0x3b, 0x93, 0xe5, 0x85, 0xd7, - 0x48, 0xef, 0x86, 0x21, 0xfb, 0x0a, 0x9c, 0x12, 0xc9, 0x34, 0xe4, 0x16, 0xa6, 0xe3, 0x25, 0x20, - 0xef, 0x07, 0x08, 0xfb, 0x59, 0x16, 0xf5, 0xf7, 0xe6, 0x27, 0xc4, 0x84, 0xfe, 0x42, 0xfc, 0x23, - 0x4c, 0xd7, 0x85, 0xbc, 0x1b, 0x6a, 0x5b, 0x3d, 0x69, 0x9b, 0x66, 0xee, 0x5c, 0xc4, 0x62, 0x94, - 0x24, 0x87, 0xac, 0x42, 0xde, 0x67, 0xaf, 0x85, 0x43, 0x2b, 0x25, 0xd2, 0xcc, 0x36, 0x65, 0x03, - 0xbd, 0x96, 0x3d, 0x4f, 0x52, 0xa1, 0x65, 0xcd, 0x05, 0xed, 0x47, 0x6d, 0x03, 0x6d, 0x8a, 0xa8, - 0x15, 0x4d, 0xdb, 0xb9, 0xbc, 0x66, 0xa6, 0x7c, 0x3e, 0xcf, 0x98, 0x86, 0x4e, 0x58, 0xac, 0x3e, - 0x90, 0xb9, 0xdd, 0xb6, 0x85, 0x82, 0xc4, 0x5c, 0x1e, 0x54, 0xb0, 0x69, 0x64, 0x8d, 0xa9, 0x47, - 0x52, 0x4d, 0xc3, 0x6e, 0xb4, 0xcd, 0x78, 0x00, 0x91, 0x46, 0xa2, 0xa0, 0x7d, 0xed, 0xae, 0x16, - 0xef, 0xb3, 0xa6, 0x25, 0xe0, 0x17, 0xb8, 0xa4, 0xb2, 0x23, 0x26, 0x5e, 0xbb, 0x43, 0x30, 0xbb, - 0x4f, 0x00, 0x1e, 0x9e, 0xad, 0xc6, 0x09, 0xdc, 0x27, 0x40, 0x7d, 0xc9, 0x10, 0xfb, 0x04, 0x8a, - 0xf5, 0xbb, 0xce, 0x9c, 0x7b, 0x1d, 0xc4, 0x95, 0xad, 0x1c, 0xd2, 0x75, 0x28, 0x18, 0xea, 0x3a, - 0x4a, 0xc1, 0x6f, 0x52, 0xf7, 0x68, 0x0d, 0x69, 0x52, 0xec, 0x5c, 0x6d, 0xbd, 0x0b, 0xb3, 0xb9, - 0x7f, 0x2d, 0x3c, 0x61, 0x71, 0x62, 0x2a, 0x86, 0xe8, 0xba, 0x72, 0x22, 0xf7, 0xc7, 0x38, 0xed, - 0xe4, 0xf7, 0xa2, 0x81, 0xaa, 0x46, 0xe9, 0xba, 0xb9, 0x85, 0x15, 0xb1, 0x26, 0x88, 0x89, 0xca, - 0x27, 0x9c, 0xc4, 0xcd, 0xeb, 0xa2, 0x29, 0xd7, 0x0e, 0xf4, 0x6b, 0xa1, 0x15, 0x48, 0xdc, 0xfc, - 0x66, 0x6f, 0xd1, 0x44, 0xe2, 0xd6, 0xad, 0xe5, 0x7c, 0x8c, 0x08, 0x74, 0xd9, 0x5e, 0xc9, 0x17, - 0xb0, 0x4c, 0x9f, 0x06, 0xbb, 0x07, 0xd1, 0x20, 0x3e, 0x46, 0xd4, 0x4f, 0xd3, 0xae, 0x41, 0xe6, - 0xec, 0x40, 0x5e, 0x4f, 0xc3, 0x7f, 0x05, 0x45, 0x09, 0x89, 0x35, 0xa8, 0x05, 0x39, 0x3f, 0x9d, - 0x3a, 0x7e, 0x59, 0xa6, 0x22, 0xcd, 0xe7, 0x53, 0xce, 0x33, 0x78, 0x64, 0x39, 0x1a, 0x0f, 0x5d, - 0x29, 0xf5, 0xd3, 0xa9, 0x2d, 0xca, 0x2e, 0x71, 0xa3, 0xf1, 0x68, 0x29, 0xf8, 0x79, 0x9a, 0x65, - 0x20, 0x72, 0x46, 0xe3, 0x61, 0x23, 0x21, 0x22, 0xc7, 0x27, 0x9c, 0x1f, 0xfc, 0x1c, 0xcb, 0xd3, - 0x7f, 0x7d, 0x02, 0x7a, 0x07, 0xea, 0x38, 0x42, 0xea, 0x07, 0x3f, 0x21, 0xe4, 0xfc, 0x80, 0xe9, - 0x18, 0xfb, 0x29, 0x97, 0x4d, 0xa8, 0x8e, 0x40, 0xd4, 0x0f, 0x98, 0x52, 0xb0, 0xf3, 0x4e, 0xf2, - 0xf1, 0xb2, 0xba, 0xf0, 0x8f, 0x0c, 0xd4, 0xe6, 0x50, 0x7d, 0xb6, 0xf5, 0x29, 0xf8, 0x41, 0x21, - 0x9f, 0x1d, 0x7a, 0x30, 0x71, 0x3d, 0xad, 0x53, 0x49, 0x15, 0xe6, 0xd9, 0xfb, 0xff, 0xf5, 0xd5, - 0x8d, 0xb5, 0x9f, 0x7e, 0x75, 0x63, 0xed, 0x7f, 0xbe, 0xba, 0xb1, 0xf6, 0x93, 0xaf, 0x6f, 0xbc, - 0xf1, 0xd3, 0xaf, 0x6f, 0xbc, 0xf1, 0xdf, 0x5f, 0xdf, 0x78, 0xe3, 0xcb, 0x37, 0x2b, 0x95, 0x9b, - 0x9d, 0xfd, 0x5c, 0x51, 0x72, 0xc1, 0x9f, 0xfe, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xc7, 0xe9, - 0x8b, 0xe6, 0x86, 0x80, 0x00, 0x00, + 0x52, 0xc0, 0xcf, 0x3c, 0xb0, 0x50, 0xc7, 0x2d, 0xd0, 0x0b, 0xcb, 0xdd, 0x72, 0x37, 0xdf, 0x63, + 0xcf, 0x8c, 0xc7, 0xed, 0xd9, 0x99, 0xfd, 0xe2, 0x0e, 0x09, 0x7a, 0xec, 0xb1, 0xb7, 0x6f, 0x6d, + 0xaf, 0x71, 0xb7, 0x67, 0xc4, 0x4a, 0x48, 0x94, 0xbb, 0xd2, 0xed, 0xc2, 0xd5, 0x95, 0x75, 0x55, + 0xd9, 0x9e, 0xe9, 0x43, 0x20, 0x10, 0x27, 0x10, 0x08, 0xc4, 0x89, 0x2f, 0xc1, 0x13, 0x12, 0x7f, + 0x01, 0x7f, 0x01, 0xcf, 0x3c, 0xde, 0x23, 0x8f, 0x68, 0xf7, 0x1f, 0x41, 0x95, 0x99, 0x95, 0x1f, + 0x51, 0x11, 0x59, 0xe5, 0xe5, 0x69, 0x46, 0x8e, 0x5f, 0x44, 0xe4, 0x47, 0x64, 0x66, 0x64, 0x56, + 0x56, 0x75, 0x74, 0xb3, 0x38, 0xdb, 0x2e, 0x4a, 0x2e, 0x78, 0xb5, 0x5d, 0xb1, 0xf2, 0x2a, 0x9d, + 0xb1, 0xe6, 0xdf, 0xa1, 0xfc, 0xf3, 0xe0, 0xad, 0x38, 0x5f, 0x89, 0x55, 0xc1, 0xde, 0xfb, 0xb6, + 0x25, 0x67, 0x7c, 0xb1, 0x88, 0xf3, 0xa4, 0x52, 0xc8, 0x7b, 0xef, 0x5a, 0x09, 0xbb, 0x62, 0xb9, + 0xd0, 0x7f, 0x7f, 0xfa, 0x5f, 0x3f, 0xf9, 0xb9, 0xe8, 0xed, 0x9d, 0x2c, 0x65, 0xb9, 0xd8, 0xd1, + 0x1a, 0x83, 0x2f, 0xa2, 0x6f, 0x8d, 0x8a, 0x62, 0x9f, 0x89, 0x97, 0xac, 0xac, 0x52, 0x9e, 0x0f, + 0xee, 0x0e, 0xb5, 0x83, 0xe1, 0x49, 0x31, 0x1b, 0x8e, 0x8a, 0x62, 0x68, 0x85, 0xc3, 0x13, 0xf6, + 0xa3, 0x25, 0xab, 0xc4, 0x7b, 0xf7, 0xc2, 0x50, 0x55, 0xf0, 0xbc, 0x62, 0x83, 0xf3, 0xe8, 0x57, + 0x47, 0x45, 0x31, 0x61, 0x62, 0x97, 0xd5, 0x15, 0x98, 0x88, 0x58, 0xb0, 0xc1, 0x46, 0x4b, 0xd5, + 0x07, 0x8c, 0x8f, 0x07, 0xdd, 0xa0, 0xf6, 0x33, 0x8d, 0xbe, 0x59, 0xfb, 0xb9, 0x58, 0x8a, 0x84, + 0xbf, 0xce, 0x07, 0xb7, 0xdb, 0x8a, 0x5a, 0x64, 0x6c, 0xdf, 0x09, 0x21, 0xda, 0xea, 0xab, 0xe8, + 0x97, 0x5e, 0xc5, 0x59, 0xc6, 0xc4, 0x4e, 0xc9, 0xea, 0x82, 0xfb, 0x3a, 0x4a, 0x34, 0x54, 0x32, + 0x63, 0xf7, 0x6e, 0x90, 0xd1, 0x86, 0xbf, 0x88, 0xbe, 0xa5, 0x24, 0x27, 0x6c, 0xc6, 0xaf, 0x58, + 0x39, 0x40, 0xb5, 0xb4, 0x90, 0x68, 0xf2, 0x16, 0x04, 0x6d, 0xef, 0xf0, 0xfc, 0x8a, 0x95, 0x02, + 0xb7, 0xad, 0x85, 0x61, 0xdb, 0x16, 0xd2, 0xb6, 0xff, 0x7a, 0x2d, 0xfa, 0xee, 0x68, 0x36, 0xe3, + 0xcb, 0x5c, 0x1c, 0xf0, 0x59, 0x9c, 0x1d, 0xa4, 0xf9, 0xe5, 0x11, 0x7b, 0xbd, 0x73, 0x51, 0xf3, + 0xf9, 0x9c, 0x0d, 0x9e, 0xf9, 0xad, 0xaa, 0xd0, 0xa1, 0x61, 0x87, 0x2e, 0x6c, 0x7c, 0x7f, 0x70, + 0x3d, 0x25, 0x5d, 0x96, 0xbf, 0x5f, 0x8b, 0x6e, 0xc0, 0xb2, 0x4c, 0x78, 0x76, 0xc5, 0x6c, 0x69, + 0x3e, 0xec, 0x30, 0xec, 0xe3, 0xa6, 0x3c, 0x1f, 0x5d, 0x57, 0x4d, 0x97, 0xe8, 0xcf, 0xd6, 0xa2, + 0xef, 0xc0, 0x12, 0xa9, 0x9e, 0x1f, 0x15, 0xc5, 0xe0, 0x49, 0x87, 0x55, 0x43, 0x9a, 0x72, 0xbc, + 0x7f, 0x0d, 0x0d, 0x5d, 0x84, 0x3f, 0x89, 0xbe, 0x0d, 0x4b, 0x70, 0x90, 0x56, 0x62, 0x54, 0x14, + 0xd5, 0x60, 0xbb, 0xc3, 0x5c, 0x03, 0x1a, 0xff, 0x4f, 0xfa, 0x2b, 0x04, 0x5a, 0xe0, 0x84, 0x5d, + 0xf1, 0xcb, 0x5e, 0x2d, 0x60, 0xc8, 0xde, 0x2d, 0xe0, 0x6a, 0xe8, 0x22, 0x64, 0xd1, 0x3b, 0xee, + 0x98, 0x9d, 0xb0, 0x4a, 0xce, 0x69, 0x0f, 0xe9, 0x61, 0xa9, 0x11, 0xe3, 0xf4, 0x51, 0x1f, 0x54, + 0x7b, 0x4b, 0xa3, 0x81, 0xf6, 0x96, 0xf1, 0xca, 0x38, 0x7b, 0x80, 0x5a, 0x70, 0x08, 0xe3, 0xeb, + 0x61, 0x0f, 0x52, 0xbb, 0xfa, 0xc3, 0xe8, 0x97, 0x5f, 0xf1, 0xf2, 0xb2, 0x2a, 0xe2, 0x19, 0xd3, + 0xf3, 0xd1, 0x7d, 0x5f, 0xbb, 0x91, 0xc2, 0x29, 0x69, 0xbd, 0x0b, 0x73, 0x66, 0x8e, 0x46, 0xf8, + 0x79, 0xc1, 0xe0, 0x42, 0x60, 0x15, 0x6b, 0x21, 0x35, 0x73, 0x40, 0x48, 0xdb, 0xbe, 0x8c, 0x06, + 0xd6, 0xf6, 0xd9, 0x1f, 0xb1, 0x99, 0x18, 0x25, 0x09, 0xec, 0x15, 0xab, 0x2b, 0x89, 0xe1, 0x28, + 0x49, 0xa8, 0x5e, 0xc1, 0x51, 0xed, 0xec, 0x75, 0xf4, 0x2e, 0x70, 0x26, 0x43, 0x35, 0x49, 0x06, + 0x5b, 0x61, 0x2b, 0x1a, 0x33, 0x4e, 0x87, 0x7d, 0x71, 0x27, 0xfe, 0x11, 0xcf, 0x27, 0x6c, 0xc1, + 0xaf, 0x18, 0x88, 0x7f, 0xd4, 0x9a, 0x22, 0x89, 0xf8, 0x0f, 0x6b, 0x20, 0x61, 0x32, 0x61, 0x19, + 0x9b, 0x09, 0x32, 0x4c, 0x94, 0xb8, 0x33, 0x4c, 0x0c, 0xe6, 0x8c, 0xb0, 0x46, 0xb8, 0xcf, 0xc4, + 0xce, 0xb2, 0x2c, 0x59, 0x2e, 0xc8, 0xbe, 0xb4, 0x48, 0x67, 0x5f, 0x7a, 0x28, 0x52, 0x9f, 0x7d, + 0x26, 0x46, 0x59, 0x46, 0xd6, 0x47, 0x89, 0x3b, 0xeb, 0x63, 0x30, 0xed, 0x61, 0x16, 0xfd, 0x8a, + 0xd3, 0x62, 0x62, 0x9c, 0x9f, 0xf3, 0x01, 0xdd, 0x16, 0x52, 0x6e, 0x7c, 0x6c, 0x74, 0x72, 0x48, + 0x35, 0x5e, 0xbc, 0x29, 0x78, 0x49, 0x77, 0x8b, 0x12, 0x77, 0x56, 0xc3, 0x60, 0xda, 0xc3, 0x1f, + 0x44, 0x6f, 0xeb, 0x09, 0xb2, 0x49, 0x2a, 0xee, 0xa1, 0xb3, 0x27, 0xcc, 0x2a, 0xee, 0x77, 0x50, + 0x2d, 0xf3, 0x87, 0xe9, 0xbc, 0xac, 0x67, 0x1f, 0xdc, 0xbc, 0x96, 0x76, 0x98, 0xb7, 0x94, 0x36, + 0xcf, 0xa3, 0x5f, 0xf3, 0xcd, 0xef, 0xc4, 0xf9, 0x8c, 0x65, 0x83, 0x47, 0x21, 0x75, 0xc5, 0x18, + 0x57, 0x9b, 0xbd, 0x58, 0x3b, 0xd9, 0x69, 0x42, 0x4f, 0xa6, 0x77, 0x51, 0x6d, 0x30, 0x95, 0xde, + 0x0b, 0x43, 0x2d, 0xdb, 0xbb, 0x2c, 0x63, 0xa4, 0x6d, 0x25, 0xec, 0xb0, 0x6d, 0x20, 0x6d, 0xbb, + 0x8c, 0x7e, 0xdd, 0x74, 0x73, 0x9d, 0x9c, 0x49, 0x79, 0xbd, 0xe8, 0x6c, 0x12, 0xfd, 0xe8, 0x42, + 0xc6, 0xd7, 0xe3, 0x7e, 0x70, 0xab, 0x3e, 0x7a, 0x46, 0xc1, 0xeb, 0x03, 0xe6, 0x93, 0x7b, 0x61, + 0x48, 0xdb, 0xfe, 0x9b, 0xb5, 0xe8, 0x7b, 0x5a, 0xf6, 0x22, 0x8f, 0xcf, 0x32, 0x26, 0x57, 0xf7, + 0x23, 0x26, 0x5e, 0xf3, 0xf2, 0x72, 0xb2, 0xca, 0x67, 0x44, 0x4e, 0x89, 0xc3, 0x1d, 0x39, 0x25, + 0xa9, 0xa4, 0x0b, 0xf3, 0xc7, 0x26, 0x7d, 0xda, 0xb9, 0x88, 0xf3, 0x39, 0xfb, 0x61, 0xc5, 0xf3, + 0x51, 0x91, 0x8e, 0x92, 0xa4, 0x1c, 0x0c, 0xf1, 0xae, 0x87, 0x9c, 0x29, 0xc1, 0x76, 0x6f, 0xde, + 0xd9, 0xc3, 0xe8, 0x56, 0x16, 0xbc, 0x80, 0x7b, 0x98, 0xa6, 0xf9, 0x04, 0x2f, 0xa8, 0x3d, 0x8c, + 0x8f, 0xb4, 0xac, 0x1e, 0xd6, 0x6b, 0x10, 0x6e, 0xf5, 0xd0, 0x5d, 0x74, 0xee, 0x84, 0x10, 0xbb, + 0x06, 0x34, 0x0d, 0xc5, 0xf3, 0xf3, 0x74, 0x7e, 0x5a, 0x24, 0xf5, 0x18, 0x7a, 0x88, 0xd7, 0xd9, + 0x41, 0x88, 0x35, 0x80, 0x40, 0xb5, 0xb7, 0xbf, 0xb3, 0xa9, 0xbe, 0x9e, 0x97, 0xf6, 0x4a, 0xbe, + 0x38, 0x60, 0xf3, 0x78, 0xb6, 0xd2, 0x93, 0xe9, 0x07, 0xa1, 0x59, 0x0c, 0xd2, 0xa6, 0x10, 0x1f, + 0x5e, 0x53, 0x4b, 0x97, 0xe7, 0xdf, 0xd7, 0xa2, 0x7b, 0x5e, 0x9c, 0xe8, 0x60, 0x52, 0xa5, 0x1f, + 0xe5, 0xc9, 0x09, 0xab, 0x44, 0x5c, 0x8a, 0xc1, 0xf7, 0x03, 0x31, 0x40, 0xe8, 0x98, 0xb2, 0xfd, + 0xe0, 0x6b, 0xe9, 0xda, 0x5e, 0x9f, 0xd4, 0xab, 0x84, 0x9e, 0x7f, 0xfc, 0x5e, 0x97, 0x12, 0x38, + 0xfb, 0xdc, 0x09, 0x21, 0xb6, 0xd7, 0xa5, 0x60, 0x9c, 0x5f, 0xa5, 0x82, 0xed, 0xb3, 0x9c, 0x95, + 0xed, 0x5e, 0x57, 0xaa, 0x3e, 0x42, 0xf4, 0x3a, 0x81, 0xda, 0xb3, 0x03, 0xc7, 0x9b, 0xaa, 0x38, + 0x38, 0x3b, 0x70, 0x0d, 0x28, 0x80, 0x38, 0x3b, 0x40, 0x41, 0x3b, 0xa3, 0x7a, 0xb5, 0x32, 0x19, + 0xcd, 0x66, 0xa0, 0xb0, 0xad, 0x9c, 0xe6, 0x71, 0x3f, 0x98, 0x68, 0x49, 0xb1, 0x5f, 0x1b, 0x09, + 0xb6, 0xa4, 0x42, 0x7a, 0xb5, 0xa4, 0x41, 0xd1, 0x96, 0x54, 0x9b, 0xa6, 0x40, 0x4b, 0x2a, 0xa0, + 0x47, 0x4b, 0x1a, 0xd0, 0x26, 0x39, 0x8e, 0x9f, 0x97, 0x29, 0x7b, 0x0d, 0x92, 0x1c, 0x57, 0xb9, + 0x16, 0x13, 0x49, 0x0e, 0x82, 0x69, 0x0f, 0x47, 0xd1, 0x2f, 0x4a, 0xe1, 0x0f, 0x79, 0x9a, 0x0f, + 0x6e, 0x22, 0x4a, 0xb5, 0xc0, 0x58, 0xbd, 0x45, 0x03, 0xa0, 0xc4, 0xf5, 0x5f, 0x75, 0xc6, 0x71, + 0x9f, 0x50, 0x02, 0xc9, 0xc6, 0x7a, 0x17, 0x66, 0xb3, 0x4b, 0x29, 0xac, 0x67, 0xe5, 0xc9, 0x45, + 0x5c, 0xa6, 0xf9, 0x7c, 0x80, 0xe9, 0x3a, 0x72, 0x22, 0xbb, 0xc4, 0x38, 0x10, 0x4e, 0x5a, 0x71, + 0x54, 0x14, 0x65, 0x3d, 0xd9, 0x63, 0xe1, 0xe4, 0x23, 0xc1, 0x70, 0x6a, 0xa1, 0xb8, 0xb7, 0x5d, + 0x36, 0xcb, 0xd2, 0x3c, 0xe8, 0x4d, 0x23, 0x7d, 0xbc, 0x59, 0x14, 0x04, 0xef, 0x01, 0x8b, 0xaf, + 0x58, 0x53, 0x33, 0xac, 0x65, 0x5c, 0x20, 0x18, 0xbc, 0x00, 0xb4, 0x5b, 0x79, 0x29, 0x3e, 0x8c, + 0x2f, 0x59, 0xdd, 0xc0, 0xac, 0x4e, 0x15, 0x06, 0x98, 0xbe, 0x47, 0x10, 0x5b, 0x79, 0x9c, 0xd4, + 0xae, 0x96, 0xd1, 0xbb, 0x52, 0x7e, 0x1c, 0x97, 0x22, 0x9d, 0xa5, 0x45, 0x9c, 0x37, 0x5b, 0x44, + 0x6c, 0x16, 0x69, 0x51, 0xc6, 0xe5, 0x56, 0x4f, 0x5a, 0xbb, 0xfd, 0x97, 0xb5, 0xe8, 0x36, 0xf4, + 0x7b, 0xcc, 0xca, 0x45, 0x2a, 0x4f, 0x1a, 0x2a, 0x3d, 0xc3, 0x7e, 0x1c, 0x36, 0xda, 0x52, 0x30, + 0xa5, 0xf9, 0xe4, 0xfa, 0x8a, 0x36, 0xbf, 0x9c, 0xe8, 0xdd, 0xd7, 0xe7, 0x65, 0xd2, 0x3a, 0x0e, + 0x9d, 0x34, 0x5b, 0x2a, 0x29, 0x24, 0xf2, 0xcb, 0x16, 0x04, 0x46, 0xf8, 0x69, 0x5e, 0x35, 0xd6, + 0xb1, 0x11, 0x6e, 0xc5, 0xc1, 0x11, 0xee, 0x61, 0x76, 0x84, 0x1f, 0x2f, 0xcf, 0xb2, 0xb4, 0xba, + 0x48, 0xf3, 0xb9, 0xde, 0x4c, 0xf8, 0xba, 0x56, 0x0c, 0xf7, 0x13, 0x1b, 0x9d, 0x1c, 0xe6, 0x44, + 0x07, 0x0b, 0xe9, 0x04, 0x84, 0xc9, 0x46, 0x27, 0x67, 0xf7, 0x78, 0x56, 0x7a, 0x90, 0x56, 0x02, + 0xec, 0xf1, 0x1c, 0xd5, 0x5a, 0x4a, 0xec, 0xf1, 0xda, 0x94, 0xdd, 0xe3, 0xb9, 0x75, 0xa8, 0x78, + 0x76, 0xc5, 0x4e, 0xcb, 0x14, 0xec, 0xf1, 0xbc, 0xf2, 0x35, 0x0c, 0xb1, 0xc7, 0xa3, 0x58, 0x3b, + 0x51, 0x59, 0x62, 0x9f, 0x89, 0x89, 0x88, 0xc5, 0xb2, 0x02, 0x13, 0x95, 0x63, 0xc3, 0x20, 0xc4, + 0x44, 0x45, 0xa0, 0xda, 0xdb, 0xef, 0x45, 0x91, 0x3a, 0x97, 0x91, 0x67, 0x67, 0xfe, 0xda, 0xa3, + 0x0f, 0x6c, 0xbc, 0x83, 0xb3, 0xdb, 0x01, 0xc2, 0xa6, 0x71, 0xea, 0xef, 0xf2, 0x48, 0x70, 0x80, + 0x6a, 0x48, 0x11, 0x91, 0xc6, 0x01, 0x04, 0x16, 0x74, 0x72, 0xc1, 0x5f, 0xe3, 0x05, 0xad, 0x25, + 0xe1, 0x82, 0x6a, 0xc2, 0x3e, 0x29, 0xd1, 0x05, 0xc5, 0x9e, 0x94, 0x34, 0xc5, 0x08, 0x3d, 0x29, + 0x81, 0x8c, 0x8d, 0x19, 0xd7, 0xf0, 0x73, 0xce, 0x2f, 0x17, 0x71, 0x79, 0x09, 0x62, 0xc6, 0x53, + 0x6e, 0x18, 0x22, 0x66, 0x28, 0xd6, 0xc6, 0x8c, 0xeb, 0xb0, 0xde, 0x04, 0x9c, 0x96, 0x19, 0x88, + 0x19, 0xcf, 0x86, 0x46, 0x88, 0x98, 0x21, 0x50, 0x3b, 0x3b, 0xb9, 0xde, 0x26, 0x0c, 0x1e, 0x0b, + 0x79, 0xea, 0x13, 0x46, 0x1d, 0x0b, 0x21, 0x18, 0x0c, 0xa1, 0xfd, 0x32, 0x2e, 0x2e, 0xf0, 0x10, + 0x92, 0xa2, 0x70, 0x08, 0x35, 0x08, 0xec, 0xef, 0x09, 0x8b, 0xcb, 0xd9, 0x05, 0xde, 0xdf, 0x4a, + 0x16, 0xee, 0x6f, 0xc3, 0xc0, 0xfe, 0x56, 0x82, 0x57, 0xa9, 0xb8, 0x38, 0x64, 0x22, 0xc6, 0xfb, + 0xdb, 0x67, 0xc2, 0xfd, 0xdd, 0x62, 0x6d, 0xf6, 0xef, 0x3a, 0x9c, 0x2c, 0xcf, 0xaa, 0x59, 0x99, + 0x9e, 0xb1, 0x41, 0xc0, 0x8a, 0x81, 0x88, 0xec, 0x9f, 0x84, 0xb5, 0xcf, 0x9f, 0xae, 0x45, 0x37, + 0x9b, 0x6e, 0xe7, 0x55, 0xa5, 0xd7, 0x3e, 0xdf, 0xfd, 0x87, 0x78, 0xff, 0x12, 0x38, 0xf1, 0xec, + 0xaa, 0x87, 0x9a, 0x93, 0x1b, 0xe0, 0x45, 0x3a, 0xcd, 0x2b, 0x53, 0xa8, 0x8f, 0xfb, 0x58, 0x77, + 0x14, 0x88, 0xdc, 0xa0, 0x97, 0xa2, 0x4d, 0xcb, 0x74, 0xff, 0x34, 0xb2, 0x71, 0x52, 0x81, 0xb4, + 0xac, 0x69, 0x6f, 0x87, 0x20, 0xd2, 0x32, 0x9c, 0x84, 0xa1, 0xb0, 0x5f, 0xf2, 0x65, 0x51, 0x75, + 0x84, 0x02, 0x80, 0xc2, 0xa1, 0xd0, 0x86, 0xb5, 0xcf, 0x37, 0xd1, 0x6f, 0xb8, 0xe1, 0xe7, 0x36, + 0xf6, 0x16, 0x1d, 0x53, 0x58, 0x13, 0x0f, 0xfb, 0xe2, 0x36, 0xa3, 0x68, 0x3c, 0x8b, 0x5d, 0x26, + 0xe2, 0x34, 0xab, 0x06, 0xeb, 0xb8, 0x8d, 0x46, 0x4e, 0x64, 0x14, 0x18, 0x07, 0xe7, 0xb7, 0xdd, + 0x65, 0x91, 0xa5, 0xb3, 0xf6, 0x43, 0x2b, 0xad, 0x6b, 0xc4, 0xe1, 0xf9, 0xcd, 0xc5, 0xe0, 0x7c, + 0x5d, 0xa7, 0x7e, 0xf2, 0x3f, 0xd3, 0x55, 0xc1, 0xf0, 0xf9, 0xda, 0x43, 0xc2, 0xf3, 0x35, 0x44, + 0x61, 0x7d, 0x26, 0x4c, 0x1c, 0xc4, 0x2b, 0xbe, 0x24, 0xe6, 0x6b, 0x23, 0x0e, 0xd7, 0xc7, 0xc5, + 0xec, 0xde, 0xc0, 0x78, 0x18, 0xe7, 0x82, 0x95, 0x79, 0x9c, 0xed, 0x65, 0xf1, 0xbc, 0x1a, 0x10, + 0x73, 0x8c, 0x4f, 0x11, 0x7b, 0x03, 0x9a, 0x46, 0x9a, 0x71, 0x5c, 0xed, 0xc5, 0x57, 0xbc, 0x4c, + 0x05, 0xdd, 0x8c, 0x16, 0xe9, 0x6c, 0x46, 0x0f, 0x45, 0xbd, 0x8d, 0xca, 0xd9, 0x45, 0x7a, 0xc5, + 0x92, 0x80, 0xb7, 0x06, 0xe9, 0xe1, 0xcd, 0x41, 0x91, 0x4e, 0x9b, 0xf0, 0x65, 0x39, 0x63, 0x64, + 0xa7, 0x29, 0x71, 0x67, 0xa7, 0x19, 0x4c, 0x7b, 0xf8, 0xc9, 0x5a, 0xf4, 0x9b, 0x4a, 0xea, 0x3e, + 0x49, 0xda, 0x8d, 0xab, 0x8b, 0x33, 0x1e, 0x97, 0xc9, 0xe0, 0x7d, 0xcc, 0x0e, 0x8a, 0x1a, 0xd7, + 0x4f, 0xaf, 0xa3, 0x02, 0x9b, 0xb5, 0xce, 0xbb, 0xed, 0x88, 0x43, 0x9b, 0xd5, 0x43, 0xc2, 0xcd, + 0x0a, 0x51, 0x38, 0x81, 0x48, 0xb9, 0x3a, 0x68, 0x5c, 0x27, 0xf5, 0xfd, 0xd3, 0xc6, 0x8d, 0x4e, + 0x0e, 0xce, 0x8f, 0xb5, 0xd0, 0x8f, 0x96, 0x2d, 0xca, 0x06, 0x1e, 0x31, 0xc3, 0xbe, 0x38, 0xe9, + 0xd9, 0x8c, 0x8a, 0xb0, 0xe7, 0xd6, 0xc8, 0x18, 0xf6, 0xc5, 0x09, 0xcf, 0xce, 0xb4, 0x16, 0xf2, + 0x8c, 0x4c, 0x6d, 0xc3, 0xbe, 0x38, 0xcc, 0xbe, 0x34, 0xd3, 0xac, 0x0b, 0x8f, 0x02, 0x76, 0xe0, + 0xda, 0xb0, 0xd9, 0x8b, 0xd5, 0x0e, 0xff, 0x6a, 0x2d, 0xfa, 0xae, 0xf5, 0x78, 0xc8, 0x93, 0xf4, + 0x7c, 0xa5, 0xa0, 0x97, 0x71, 0xb6, 0x64, 0xd5, 0xe0, 0x29, 0x65, 0xad, 0xcd, 0x9a, 0x12, 0x3c, + 0xbb, 0x96, 0x0e, 0x1c, 0x3b, 0xa3, 0xa2, 0xc8, 0x56, 0x53, 0xb6, 0x28, 0x32, 0x72, 0xec, 0x78, + 0x48, 0x78, 0xec, 0x40, 0x14, 0x66, 0xe5, 0x53, 0x5e, 0xe7, 0xfc, 0x68, 0x56, 0x2e, 0x45, 0xe1, + 0xac, 0xbc, 0x41, 0x60, 0xae, 0x34, 0xe5, 0x3b, 0x3c, 0xcb, 0xd8, 0x4c, 0xb4, 0x6f, 0xa3, 0x18, + 0x4d, 0x4b, 0x84, 0x73, 0x25, 0x40, 0xda, 0x53, 0xb9, 0x66, 0x0f, 0x19, 0x97, 0xec, 0xf9, 0xea, + 0x20, 0xcd, 0x2f, 0x07, 0x78, 0x5a, 0x60, 0x01, 0xe2, 0x54, 0x0e, 0x05, 0xe1, 0x5e, 0xf5, 0x34, + 0x4f, 0x38, 0xbe, 0x57, 0xad, 0x25, 0xe1, 0xbd, 0xaa, 0x26, 0xa0, 0xc9, 0x13, 0x46, 0x99, 0xac, + 0x25, 0x61, 0x93, 0x9a, 0xc0, 0xa6, 0x42, 0xfd, 0x44, 0x8a, 0x9c, 0x0a, 0xc1, 0x33, 0xa8, 0x8d, + 0x4e, 0x0e, 0xee, 0xb9, 0xb4, 0x03, 0x34, 0x22, 0x80, 0xf1, 0xbb, 0x41, 0x06, 0x86, 0x7e, 0xb3, + 0x1b, 0xde, 0x63, 0x62, 0x76, 0x81, 0x87, 0xbe, 0x87, 0x84, 0x43, 0x1f, 0xa2, 0xb0, 0xad, 0xa6, + 0xdc, 0xec, 0xe6, 0xd7, 0xf1, 0xc0, 0x6b, 0xed, 0xe4, 0x37, 0x3a, 0x39, 0xd8, 0x56, 0xe3, 0x05, + 0xdd, 0x56, 0x4a, 0x16, 0x6e, 0x2b, 0xc3, 0xc0, 0xd2, 0x2b, 0x81, 0x3c, 0x24, 0x5b, 0xa7, 0x15, + 0xbd, 0x63, 0xb2, 0x8d, 0x4e, 0x4e, 0x3b, 0xf9, 0x27, 0xb3, 0x3f, 0x54, 0xd2, 0x23, 0x5e, 0x0f, + 0xbe, 0x97, 0x71, 0x96, 0x26, 0xb1, 0x60, 0x53, 0x7e, 0xc9, 0x72, 0x7c, 0x2b, 0xa6, 0x4b, 0xab, + 0xf8, 0xa1, 0xa7, 0x10, 0xde, 0x8a, 0x85, 0x15, 0x61, 0x9c, 0x28, 0xfa, 0xb4, 0x62, 0x3b, 0x71, + 0x45, 0x4c, 0x91, 0x1e, 0x12, 0x8e, 0x13, 0x88, 0xc2, 0x44, 0x58, 0xc9, 0x5f, 0xbc, 0x29, 0x58, + 0x99, 0xb2, 0x7c, 0xc6, 0xf0, 0x44, 0x18, 0x52, 0xe1, 0x44, 0x18, 0xa1, 0xe1, 0x26, 0x70, 0x37, + 0x16, 0xec, 0xf9, 0x6a, 0x9a, 0x2e, 0x58, 0x25, 0xe2, 0x45, 0x81, 0x6f, 0x02, 0x01, 0x14, 0xde, + 0x04, 0xb6, 0xe1, 0xd6, 0x99, 0x93, 0x99, 0x69, 0xdb, 0xb7, 0xe3, 0x20, 0x11, 0xb8, 0x1d, 0x47, + 0xa0, 0xb0, 0x61, 0x2d, 0x80, 0x3e, 0x7d, 0x68, 0x59, 0x09, 0x3e, 0x7d, 0xa0, 0xe9, 0xd6, 0x49, + 0x9e, 0x61, 0x26, 0xf5, 0xd0, 0xec, 0x28, 0xfa, 0xc4, 0x1d, 0xa2, 0x9b, 0xbd, 0x58, 0xfc, 0xe8, + 0xf0, 0x84, 0x65, 0xb1, 0x5c, 0x0f, 0x03, 0xe7, 0x73, 0x0d, 0xd3, 0xe7, 0xe8, 0xd0, 0x61, 0xb5, + 0xc3, 0x3f, 0x5f, 0x8b, 0xde, 0xc3, 0x3c, 0x7e, 0x5e, 0x48, 0xbf, 0x4f, 0xba, 0x6d, 0x29, 0x92, + 0xb8, 0xfe, 0x17, 0xd6, 0xb0, 0x37, 0x58, 0x1a, 0x91, 0xbd, 0x1d, 0xa8, 0x0b, 0xe0, 0x67, 0x83, + 0xa6, 0xfc, 0x90, 0x23, 0x6e, 0xb0, 0x84, 0x78, 0xbb, 0xd1, 0xf2, 0xcb, 0x55, 0x81, 0x8d, 0x96, + 0xb1, 0xa1, 0xc5, 0xc4, 0x46, 0x0b, 0xc1, 0xec, 0xe8, 0x74, 0xab, 0xf7, 0x2a, 0x15, 0x17, 0x32, + 0x91, 0x03, 0xa3, 0xd3, 0x2b, 0xab, 0x81, 0x88, 0xd1, 0x49, 0xc2, 0x30, 0xd5, 0x69, 0xc0, 0x7a, + 0x6c, 0x62, 0x73, 0xb9, 0x31, 0xe4, 0x8e, 0xcc, 0x07, 0xdd, 0x20, 0x8c, 0xd7, 0x46, 0xac, 0xf7, + 0x54, 0x8f, 0x42, 0x16, 0xc0, 0xbe, 0x6a, 0xb3, 0x17, 0xab, 0x1d, 0xfe, 0x69, 0xf4, 0x9d, 0x56, + 0xc5, 0xf6, 0x58, 0x2c, 0x96, 0x25, 0x4b, 0xc0, 0x6d, 0xf1, 0x76, 0xb9, 0x1b, 0x90, 0xb8, 0x2d, + 0x1e, 0x54, 0x68, 0x25, 0xff, 0x0d, 0xa7, 0xc2, 0xca, 0x94, 0xe1, 0x69, 0xc8, 0xa4, 0xcf, 0x06, + 0x93, 0x7f, 0x5a, 0xa7, 0xb5, 0x7f, 0x77, 0xa3, 0x6b, 0x74, 0x15, 0xa7, 0x99, 0x7c, 0x0a, 0xfc, + 0x7e, 0xc8, 0xa8, 0x87, 0x06, 0xf7, 0xef, 0xa4, 0x4a, 0x6b, 0x66, 0x96, 0x63, 0xdc, 0xd9, 0xf7, + 0x3d, 0xa6, 0x67, 0x02, 0x64, 0xdb, 0xb7, 0xd5, 0x93, 0xd6, 0x6e, 0x45, 0xb3, 0xe4, 0xd5, 0x7f, + 0x76, 0x83, 0x1c, 0xf3, 0xaa, 0x55, 0x91, 0x48, 0xdf, 0xea, 0x49, 0xdb, 0x57, 0x15, 0xda, 0x5e, + 0xf5, 0x42, 0xb4, 0xdd, 0x69, 0x0a, 0xac, 0x45, 0x4f, 0xfa, 0x2b, 0x68, 0xf7, 0xff, 0x6a, 0x0e, + 0xbc, 0x95, 0xff, 0x19, 0x5f, 0x2c, 0x58, 0x9e, 0xb0, 0xa4, 0xd1, 0xa8, 0xea, 0x8d, 0xd9, 0x27, + 0xb4, 0x5d, 0xa3, 0x30, 0x74, 0x35, 0x4c, 0x89, 0x7e, 0xeb, 0x6b, 0x68, 0xea, 0xa2, 0xfd, 0xe7, + 0x5a, 0xf4, 0x10, 0x2d, 0x5a, 0x13, 0xb8, 0x5e, 0x11, 0x7f, 0xb7, 0x8f, 0x23, 0x4c, 0xd3, 0x14, + 0x75, 0xf4, 0xff, 0xb0, 0xa0, 0x8b, 0xfc, 0x6f, 0x6b, 0xd1, 0x1d, 0xab, 0x58, 0x87, 0xf7, 0x0e, + 0xcf, 0xcf, 0xb3, 0x74, 0x26, 0xe4, 0xa3, 0x5e, 0xad, 0x42, 0x37, 0x27, 0xa5, 0xd1, 0xdd, 0x9c, + 0x01, 0x4d, 0x5d, 0xb6, 0x7f, 0x5c, 0x8b, 0x6e, 0xb9, 0xcd, 0x29, 0x9f, 0x13, 0xab, 0x63, 0xd7, + 0x46, 0xb1, 0x1a, 0x7c, 0x44, 0xb7, 0x01, 0xc6, 0x9b, 0x72, 0x7d, 0x7c, 0x6d, 0x3d, 0xbb, 0x57, + 0xff, 0x34, 0xad, 0x04, 0x2f, 0x57, 0x93, 0x0b, 0xfe, 0xba, 0x79, 0xf5, 0xce, 0x5f, 0x2d, 0x34, + 0x30, 0x74, 0x08, 0x62, 0xaf, 0x8e, 0x93, 0x2d, 0x57, 0xf6, 0x15, 0xbd, 0x8a, 0x70, 0xe5, 0x10, + 0x1d, 0xae, 0x7c, 0xd2, 0xae, 0x95, 0x4d, 0xad, 0xec, 0xfb, 0x84, 0x1b, 0x78, 0x51, 0xdb, 0xef, + 0x14, 0x3e, 0xe8, 0x06, 0x6d, 0xc6, 0xac, 0xc5, 0xbb, 0xe9, 0xf9, 0xb9, 0xa9, 0x13, 0x5e, 0x52, + 0x17, 0x21, 0x32, 0x66, 0x02, 0xb5, 0x9b, 0xbe, 0xbd, 0x34, 0x63, 0xf2, 0x51, 0xd5, 0xe7, 0xe7, + 0xe7, 0x19, 0x8f, 0x13, 0xb0, 0xe9, 0xab, 0xc5, 0x43, 0x57, 0x4e, 0x6c, 0xfa, 0x30, 0xce, 0x5e, + 0x82, 0xa9, 0xa5, 0xf5, 0x98, 0xcb, 0x67, 0x69, 0x06, 0x2f, 0x8d, 0x4b, 0x4d, 0x23, 0x24, 0x2e, + 0xc1, 0xb4, 0x20, 0x9b, 0x98, 0xd5, 0xa2, 0x7a, 0xac, 0x34, 0xe5, 0xbf, 0xdf, 0x56, 0x74, 0xc4, + 0x44, 0x62, 0x86, 0x60, 0xf6, 0x50, 0xa5, 0x16, 0x9e, 0x16, 0xd2, 0xf8, 0xad, 0xb6, 0x96, 0x92, + 0x10, 0x87, 0x2a, 0x3e, 0x61, 0xf7, 0xf0, 0xf5, 0xdf, 0x77, 0xf9, 0xeb, 0x5c, 0x1a, 0xbd, 0xd3, + 0x56, 0x69, 0x64, 0xc4, 0x1e, 0x1e, 0x32, 0xda, 0xf0, 0x67, 0xd1, 0x2f, 0x48, 0xc3, 0x25, 0x2f, + 0x06, 0x37, 0x10, 0x85, 0xd2, 0xb9, 0x62, 0x7d, 0x93, 0x94, 0xdb, 0x3b, 0x33, 0x26, 0x36, 0x4e, + 0xab, 0x78, 0x0e, 0xdf, 0x8b, 0xb0, 0x3d, 0x2e, 0xa5, 0xc4, 0x9d, 0x99, 0x36, 0xe5, 0x47, 0xc5, + 0x11, 0x4f, 0xb4, 0x75, 0xa4, 0x86, 0x46, 0x18, 0x8a, 0x0a, 0x17, 0xb2, 0xc9, 0xf4, 0x51, 0x7c, + 0x95, 0xce, 0x4d, 0xc2, 0xa3, 0xa6, 0xaf, 0x0a, 0x24, 0xd3, 0x96, 0x19, 0x3a, 0x10, 0x91, 0x4c, + 0x93, 0xb0, 0x33, 0x19, 0x5b, 0x66, 0xbf, 0x39, 0x86, 0x1e, 0xe7, 0xe7, 0xbc, 0x4e, 0xbd, 0x0f, + 0xd2, 0xfc, 0x12, 0x4e, 0xc6, 0x8e, 0x49, 0x9c, 0x27, 0x26, 0xe3, 0x3e, 0x7a, 0x76, 0xd7, 0xd4, + 0x9c, 0xd1, 0xda, 0x8b, 0x1a, 0x4a, 0x03, 0xec, 0x9a, 0xcc, 0x51, 0x2e, 0xe4, 0x88, 0x5d, 0x53, + 0x88, 0xb7, 0x5d, 0x6c, 0x9c, 0x67, 0x3c, 0x87, 0x5d, 0x6c, 0x2d, 0xd4, 0x42, 0xa2, 0x8b, 0x5b, + 0x90, 0x9d, 0x8f, 0x1b, 0x91, 0x3a, 0xf5, 0x1b, 0x65, 0x19, 0x98, 0x8f, 0x8d, 0xaa, 0x01, 0x88, + 0xf9, 0x18, 0x05, 0xb5, 0x9f, 0x93, 0xe8, 0x9b, 0x75, 0x93, 0x1e, 0x97, 0xec, 0x2a, 0x65, 0xf0, + 0x4e, 0x91, 0x23, 0x21, 0xc6, 0xbf, 0x4f, 0xd8, 0x91, 0x75, 0x9a, 0x57, 0x45, 0x16, 0x57, 0x17, + 0xfa, 0x96, 0x89, 0x5f, 0xe7, 0x46, 0x08, 0xef, 0x99, 0xdc, 0xef, 0xa0, 0xec, 0xa4, 0xde, 0xc8, + 0xcc, 0x14, 0xb3, 0x8e, 0xab, 0xb6, 0xa6, 0x99, 0x8d, 0x4e, 0xce, 0x3e, 0xca, 0xd9, 0x8f, 0xb3, + 0x8c, 0x95, 0xab, 0x46, 0x76, 0x18, 0xe7, 0xe9, 0x39, 0xab, 0x04, 0x78, 0x94, 0xa3, 0xa9, 0x21, + 0xc4, 0x88, 0x47, 0x39, 0x01, 0xdc, 0xee, 0x26, 0x81, 0xe7, 0x71, 0x9e, 0xb0, 0x37, 0x60, 0x37, + 0x09, 0xed, 0x48, 0x86, 0xd8, 0x4d, 0x52, 0xac, 0x7d, 0xa4, 0xf1, 0x3c, 0xe3, 0xb3, 0x4b, 0xbd, + 0x04, 0xf8, 0x1d, 0x2c, 0x25, 0x70, 0x0d, 0xb8, 0x13, 0x42, 0xec, 0x22, 0x20, 0x05, 0x27, 0xac, + 0xc8, 0xe2, 0x19, 0xbc, 0x58, 0xa6, 0x74, 0xb4, 0x8c, 0x58, 0x04, 0x20, 0x03, 0x8a, 0xab, 0x2f, + 0xac, 0x61, 0xc5, 0x05, 0xf7, 0xd5, 0xee, 0x84, 0x10, 0xbb, 0x0c, 0x4a, 0xc1, 0xa4, 0xc8, 0x52, + 0x01, 0x86, 0x81, 0xd2, 0x90, 0x12, 0x62, 0x18, 0xf8, 0x04, 0x30, 0x79, 0xc8, 0xca, 0x39, 0x43, + 0x4d, 0x4a, 0x49, 0xd0, 0x64, 0x43, 0xd8, 0x5b, 0xf4, 0xaa, 0xee, 0xbc, 0x58, 0x81, 0x5b, 0xf4, + 0xba, 0x5a, 0xbc, 0x58, 0x11, 0xb7, 0xe8, 0x3d, 0x00, 0x14, 0xf1, 0x38, 0xae, 0x04, 0x5e, 0x44, + 0x29, 0x09, 0x16, 0xb1, 0x21, 0xec, 0x1a, 0xad, 0x8a, 0xb8, 0x14, 0x60, 0x8d, 0xd6, 0x05, 0x70, + 0xae, 0x56, 0xdc, 0x24, 0xe5, 0x76, 0x26, 0x51, 0xbd, 0xc2, 0xc4, 0x5e, 0xca, 0xb2, 0xa4, 0x02, + 0x33, 0x89, 0x6e, 0xf7, 0x46, 0x4a, 0xcc, 0x24, 0x6d, 0x0a, 0x84, 0x92, 0x7e, 0x2e, 0x83, 0xd5, + 0x0e, 0x3c, 0x96, 0xb9, 0x13, 0x42, 0xec, 0xfc, 0xd4, 0x14, 0x7a, 0x27, 0x2e, 0xcb, 0xb4, 0x5e, + 0xfc, 0xd7, 0xf1, 0x02, 0x35, 0x72, 0x62, 0x7e, 0xc2, 0x38, 0x30, 0xbc, 0x9a, 0x89, 0x1b, 0x2b, + 0x18, 0x9c, 0xba, 0xef, 0x06, 0x19, 0x9b, 0x71, 0x4a, 0x89, 0x73, 0x37, 0x00, 0x6b, 0x4d, 0xe4, + 0x6a, 0xc0, 0x7a, 0x17, 0xe6, 0xbc, 0x38, 0x68, 0x5c, 0x1c, 0xf2, 0x2b, 0x36, 0xe5, 0x2f, 0xde, + 0xa4, 0x55, 0xbd, 0x09, 0xd4, 0x2b, 0xf7, 0x33, 0xc2, 0x12, 0x06, 0x13, 0x2f, 0x0e, 0x76, 0x2a, + 0xd9, 0x04, 0x02, 0x94, 0xe5, 0x88, 0xbd, 0x46, 0x13, 0x08, 0x68, 0xd1, 0x70, 0x44, 0x02, 0x11, + 0xe2, 0xed, 0x39, 0x9e, 0x71, 0xae, 0x3f, 0xd9, 0x31, 0xe5, 0x4d, 0x2e, 0x47, 0x59, 0x83, 0x20, + 0x71, 0x94, 0x12, 0x54, 0xb0, 0xfb, 0x4b, 0xe3, 0xdf, 0x0e, 0xb1, 0x07, 0x84, 0x9d, 0xf6, 0x30, + 0x7b, 0xd8, 0x83, 0x44, 0x5c, 0xd9, 0x0b, 0x2e, 0x94, 0xab, 0xf6, 0xfd, 0x96, 0x87, 0x3d, 0x48, + 0xe7, 0x4c, 0xd0, 0xad, 0xd6, 0xf3, 0x78, 0x76, 0x39, 0x2f, 0xf9, 0x32, 0x4f, 0x76, 0x78, 0xc6, + 0x4b, 0x70, 0x26, 0xe8, 0x95, 0x1a, 0xa0, 0xc4, 0x99, 0x60, 0x87, 0x8a, 0xcd, 0xe0, 0xdc, 0x52, + 0x8c, 0xb2, 0x74, 0x0e, 0x77, 0xd4, 0x9e, 0x21, 0x09, 0x10, 0x19, 0x1c, 0x0a, 0x22, 0x41, 0xa4, + 0x76, 0xdc, 0x22, 0x9d, 0xc5, 0x99, 0xf2, 0xb7, 0x4d, 0x9b, 0xf1, 0xc0, 0xce, 0x20, 0x42, 0x14, + 0x90, 0x7a, 0x4e, 0x97, 0x65, 0x3e, 0xce, 0x05, 0x27, 0xeb, 0xd9, 0x00, 0x9d, 0xf5, 0x74, 0x40, + 0x30, 0xad, 0x4e, 0xd9, 0x9b, 0xba, 0x34, 0xf5, 0x3f, 0xd8, 0xb4, 0x5a, 0xff, 0x7d, 0xa8, 0xe5, + 0xa1, 0x69, 0x15, 0x70, 0xa0, 0x32, 0xda, 0x89, 0x0a, 0x98, 0x80, 0xb6, 0x1f, 0x26, 0x0f, 0xba, + 0x41, 0xdc, 0xcf, 0x44, 0xac, 0x32, 0x16, 0xf2, 0x23, 0x81, 0x3e, 0x7e, 0x1a, 0xd0, 0x1e, 0xb7, + 0x78, 0xf5, 0xb9, 0x60, 0xb3, 0xcb, 0xd6, 0x7d, 0x3d, 0xbf, 0xa0, 0x0a, 0x21, 0x8e, 0x5b, 0x08, + 0x14, 0xef, 0xa2, 0xf1, 0x8c, 0xe7, 0xa1, 0x2e, 0xaa, 0xe5, 0x7d, 0xba, 0x48, 0x73, 0x76, 0xf3, + 0x6b, 0xa4, 0x3a, 0x32, 0x55, 0x37, 0x6d, 0x12, 0x16, 0x5c, 0x88, 0xd8, 0xfc, 0x92, 0xb0, 0xcd, + 0xc9, 0xa1, 0xcf, 0xc3, 0xf6, 0xcb, 0x0c, 0x2d, 0x2b, 0x87, 0xf4, 0xcb, 0x0c, 0x14, 0x4b, 0x57, + 0x52, 0xc5, 0x48, 0x87, 0x15, 0x3f, 0x4e, 0x1e, 0xf7, 0x83, 0xed, 0x96, 0xc7, 0xf3, 0xb9, 0x93, + 0xb1, 0xb8, 0x54, 0x5e, 0xb7, 0x02, 0x86, 0x2c, 0x46, 0x6c, 0x79, 0x02, 0x38, 0x98, 0xc2, 0x3c, + 0xcf, 0x3b, 0x3c, 0x17, 0x2c, 0x17, 0xd8, 0x14, 0xe6, 0x1b, 0xd3, 0x60, 0x68, 0x0a, 0xa3, 0x14, + 0x40, 0xdc, 0xca, 0xf3, 0x20, 0x26, 0x8e, 0xe2, 0x05, 0x9a, 0xb1, 0xa9, 0xb3, 0x1e, 0x25, 0x0f, + 0xc5, 0x2d, 0xe0, 0x9c, 0x87, 0xcc, 0xae, 0x97, 0x69, 0x5c, 0xce, 0xcd, 0xe9, 0x46, 0x32, 0x78, + 0x42, 0xdb, 0xf1, 0x49, 0xe2, 0x21, 0x73, 0x58, 0x03, 0x4c, 0x3b, 0xe3, 0x45, 0x3c, 0x37, 0x35, + 0x45, 0x6a, 0x20, 0xe5, 0xad, 0xaa, 0x3e, 0xe8, 0x06, 0x81, 0x9f, 0x97, 0x69, 0xc2, 0x78, 0xc0, + 0x8f, 0x94, 0xf7, 0xf1, 0x03, 0x41, 0x90, 0xbd, 0xd5, 0xf5, 0xd6, 0x1f, 0xd5, 0xca, 0x13, 0xbd, + 0x8f, 0x1d, 0x12, 0xcd, 0x03, 0xb8, 0x50, 0xf6, 0x46, 0xf0, 0x60, 0x8c, 0x36, 0x07, 0xb4, 0xa1, + 0x31, 0x6a, 0xce, 0x5f, 0xfb, 0x8c, 0x51, 0x0c, 0xd6, 0x3e, 0x7f, 0xac, 0xc7, 0xe8, 0x6e, 0x2c, + 0xe2, 0x3a, 0x6f, 0x7f, 0x99, 0xb2, 0xd7, 0x7a, 0x23, 0x8c, 0xd4, 0xb7, 0xa1, 0x86, 0xf2, 0x5d, + 0x6c, 0xb0, 0x2b, 0xde, 0xee, 0xcd, 0x07, 0x7c, 0xeb, 0x1d, 0x42, 0xa7, 0x6f, 0xb0, 0x55, 0xd8, + 0xee, 0xcd, 0x07, 0x7c, 0xeb, 0x4f, 0x57, 0x74, 0xfa, 0x06, 0xdf, 0xaf, 0xd8, 0xee, 0xcd, 0x6b, + 0xdf, 0x7f, 0xd1, 0x0c, 0x5c, 0xd7, 0x79, 0x9d, 0x87, 0xcd, 0x44, 0x7a, 0xc5, 0xb0, 0x74, 0xd2, + 0xb7, 0x67, 0xd0, 0x50, 0x3a, 0x49, 0xab, 0x38, 0x5f, 0xf0, 0xc3, 0x4a, 0x71, 0xcc, 0xab, 0x54, + 0x5e, 0x12, 0x79, 0xd6, 0xc3, 0x68, 0x03, 0x87, 0x36, 0x4d, 0x21, 0x25, 0xfb, 0xb8, 0xdb, 0x43, + 0xed, 0xf5, 0xfc, 0xc7, 0x01, 0x7b, 0xed, 0x5b, 0xfa, 0x5b, 0x3d, 0x69, 0xfb, 0xe0, 0xd9, 0x63, + 0x9a, 0x47, 0x86, 0x13, 0x86, 0xae, 0x12, 0xc6, 0x94, 0x79, 0x94, 0xec, 0x3e, 0x3b, 0x7d, 0xd2, + 0x5f, 0xa1, 0xc3, 0xfd, 0x28, 0x49, 0xfa, 0xb9, 0x77, 0x9f, 0xb9, 0x3f, 0xe9, 0xaf, 0xa0, 0xdd, + 0xff, 0x65, 0xb3, 0xad, 0x81, 0xfe, 0xf5, 0x18, 0x7c, 0xda, 0xc7, 0x22, 0x18, 0x87, 0xcf, 0xae, + 0xa5, 0xa3, 0x0b, 0xf2, 0xb7, 0xcd, 0xfe, 0xbd, 0x41, 0xe5, 0x3b, 0x52, 0xf2, 0xdd, 0x6a, 0x3d, + 0x24, 0x43, 0x51, 0x65, 0x61, 0x38, 0x30, 0x3f, 0xbc, 0xa6, 0x96, 0xf3, 0x39, 0x49, 0x0f, 0xd6, + 0xef, 0xf2, 0x3a, 0xe5, 0x09, 0x59, 0x76, 0x68, 0x58, 0xa0, 0x8f, 0xae, 0xab, 0x46, 0x0d, 0x55, + 0x07, 0x96, 0xdf, 0xf2, 0x79, 0xd6, 0xd3, 0xb0, 0xf7, 0x75, 0x9f, 0x0f, 0xae, 0xa7, 0xa4, 0xcb, + 0xf2, 0x1f, 0x6b, 0xd1, 0x7d, 0x8f, 0xb5, 0x8f, 0x33, 0xc0, 0xa1, 0xcb, 0x0f, 0x02, 0xf6, 0x29, + 0x25, 0x53, 0xb8, 0xdf, 0xfe, 0x7a, 0xca, 0xf6, 0xb3, 0x7f, 0x9e, 0xca, 0x5e, 0x9a, 0x09, 0x56, + 0xb6, 0x3f, 0xfb, 0xe7, 0xdb, 0x55, 0xd4, 0x90, 0xfe, 0xec, 0x5f, 0x00, 0x77, 0x3e, 0xfb, 0x87, + 0x78, 0x46, 0x3f, 0xfb, 0x87, 0x5a, 0x0b, 0x7e, 0xf6, 0x2f, 0xac, 0x41, 0xad, 0x2e, 0x4d, 0x11, + 0xd4, 0xb1, 0x79, 0x2f, 0x8b, 0xfe, 0x29, 0xfa, 0xd3, 0xeb, 0xa8, 0x10, 0xeb, 0xab, 0xe2, 0xe4, + 0x35, 0xcf, 0x1e, 0x6d, 0xea, 0x5d, 0xf5, 0xdc, 0xee, 0xcd, 0x6b, 0xdf, 0x3f, 0xd2, 0x9b, 0x2b, + 0xb3, 0x9a, 0xf0, 0x52, 0x7e, 0xf2, 0x71, 0x33, 0xb4, 0x3a, 0xd4, 0x16, 0xdc, 0x9e, 0x7f, 0xdc, + 0x0f, 0x26, 0xaa, 0x5b, 0x13, 0xba, 0xd3, 0x87, 0x5d, 0x86, 0x40, 0x97, 0x6f, 0xf7, 0xe6, 0x89, + 0x65, 0x44, 0xf9, 0x56, 0xbd, 0xdd, 0xc3, 0x98, 0xdf, 0xd7, 0x4f, 0xfa, 0x2b, 0x68, 0xf7, 0x57, + 0x3a, 0x6b, 0x75, 0xdd, 0xcb, 0x7e, 0xde, 0xea, 0x32, 0x35, 0xf1, 0xba, 0x79, 0xd8, 0x17, 0x0f, + 0xe5, 0x2f, 0xee, 0x12, 0xda, 0x95, 0xbf, 0xa0, 0xcb, 0xe8, 0x07, 0xd7, 0x53, 0xd2, 0x65, 0xf9, + 0x87, 0xb5, 0xe8, 0x26, 0x59, 0x16, 0x1d, 0x07, 0x1f, 0xf5, 0xb5, 0x0c, 0xe2, 0xe1, 0xe3, 0x6b, + 0xeb, 0xe9, 0x42, 0xfd, 0xf3, 0x5a, 0x74, 0x2b, 0x50, 0x28, 0x15, 0x20, 0xd7, 0xb0, 0xee, 0x07, + 0xca, 0x27, 0xd7, 0x57, 0xa4, 0x96, 0x7b, 0x17, 0x9f, 0xb4, 0x3f, 0xe1, 0x16, 0xb0, 0x3d, 0xa1, + 0x3f, 0xe1, 0xd6, 0xad, 0x05, 0xcf, 0x98, 0xe2, 0xb3, 0x66, 0xcf, 0x87, 0x9e, 0x31, 0xc9, 0x0b, + 0x9a, 0xc1, 0x8f, 0xb6, 0x60, 0x1c, 0xe6, 0xe4, 0xc5, 0x9b, 0x22, 0xce, 0x13, 0xda, 0x89, 0x92, + 0x77, 0x3b, 0x31, 0x1c, 0x3c, 0x9b, 0xab, 0xa5, 0x27, 0xbc, 0xd9, 0xc7, 0x3d, 0xa4, 0xf4, 0x0d, + 0x12, 0x3c, 0x9b, 0x6b, 0xa1, 0x84, 0x37, 0x9d, 0x35, 0x86, 0xbc, 0x81, 0x64, 0xf1, 0x51, 0x1f, + 0x14, 0xec, 0x10, 0x8c, 0x37, 0x73, 0xe4, 0xff, 0x38, 0x64, 0xa5, 0x75, 0xec, 0xbf, 0xd5, 0x93, + 0x26, 0xdc, 0x4e, 0x98, 0xf8, 0x94, 0xc5, 0x09, 0x2b, 0x83, 0x6e, 0x0d, 0xd5, 0xcb, 0xad, 0x4b, + 0x63, 0x6e, 0x77, 0x78, 0xb6, 0x5c, 0xe4, 0xba, 0x33, 0x49, 0xb7, 0x2e, 0xd5, 0xed, 0x16, 0xd0, + 0xf0, 0x54, 0xd2, 0xba, 0x95, 0xe9, 0xe5, 0xa3, 0xb0, 0x19, 0x2f, 0xab, 0xdc, 0xec, 0xc5, 0xd2, + 0xf5, 0xd4, 0x61, 0xd4, 0x51, 0x4f, 0x10, 0x49, 0x5b, 0x3d, 0x69, 0x78, 0x3c, 0xe8, 0xb8, 0x35, + 0xf1, 0xb4, 0xdd, 0x61, 0xab, 0x15, 0x52, 0x4f, 0xfa, 0x2b, 0xc0, 0xc3, 0x58, 0x1d, 0x55, 0x07, + 0x69, 0x25, 0xf6, 0xd2, 0x2c, 0x1b, 0x6c, 0x06, 0xc2, 0xa4, 0x81, 0x82, 0x87, 0xb1, 0x08, 0x4c, + 0x44, 0x72, 0x73, 0x78, 0x99, 0x0f, 0xba, 0xec, 0x48, 0xaa, 0x57, 0x24, 0xbb, 0x34, 0x38, 0x50, + 0x73, 0x9a, 0xda, 0xd4, 0x76, 0x18, 0x6e, 0xb8, 0x56, 0x85, 0xb7, 0x7b, 0xf3, 0xe0, 0x69, 0xbf, + 0xa4, 0xe4, 0xca, 0x72, 0x8f, 0x32, 0xe1, 0xad, 0x24, 0xf7, 0x3b, 0x28, 0x70, 0x28, 0xa9, 0x86, + 0xd1, 0xab, 0x34, 0x99, 0x33, 0x81, 0x3e, 0xa8, 0x72, 0x81, 0xe0, 0x83, 0x2a, 0x00, 0x82, 0xae, + 0x53, 0x7f, 0x37, 0xa7, 0xb1, 0xe3, 0x04, 0xeb, 0x3a, 0xad, 0xec, 0x50, 0xa1, 0xae, 0x43, 0x69, + 0x30, 0x1b, 0x18, 0xb7, 0xfa, 0x33, 0x17, 0x8f, 0x42, 0x66, 0xc0, 0xb7, 0x2e, 0x36, 0x7b, 0xb1, + 0x60, 0x45, 0xb1, 0x0e, 0xd3, 0x45, 0x2a, 0xb0, 0x15, 0xc5, 0xb1, 0x51, 0x23, 0xa1, 0x15, 0xa5, + 0x8d, 0x52, 0xd5, 0xab, 0x73, 0x84, 0x71, 0x12, 0xae, 0x9e, 0x62, 0xfa, 0x55, 0xcf, 0xb0, 0xad, + 0xe7, 0xaa, 0xb9, 0x09, 0x19, 0x71, 0xa1, 0x37, 0xcb, 0x48, 0x6c, 0x3b, 0xbf, 0xec, 0x60, 0xc1, + 0xd0, 0xac, 0x43, 0x29, 0xc0, 0xe7, 0x05, 0xcd, 0x6f, 0x41, 0x4c, 0x98, 0x18, 0x15, 0x05, 0x8b, + 0xcb, 0x38, 0x9f, 0xa1, 0x9b, 0x53, 0xf3, 0xdb, 0x0e, 0x1e, 0x19, 0xda, 0x9c, 0x92, 0x1a, 0xe0, + 0xa9, 0xbd, 0xff, 0x7e, 0x31, 0x32, 0x14, 0xcc, 0x8b, 0xbc, 0xfe, 0xeb, 0xc5, 0x0f, 0x7b, 0x90, + 0xf0, 0xa9, 0x7d, 0x03, 0x98, 0x73, 0x77, 0xe5, 0xf4, 0xfd, 0x80, 0x29, 0x1f, 0x0d, 0x6d, 0x84, + 0x69, 0x15, 0x10, 0xd4, 0xce, 0xd9, 0xe2, 0x67, 0x6c, 0x85, 0x05, 0xb5, 0x7b, 0x48, 0xf8, 0x19, + 0x5b, 0x85, 0x82, 0xba, 0x8d, 0x82, 0x3c, 0xd3, 0xdd, 0x07, 0xad, 0x07, 0xf4, 0xdd, 0xad, 0xcf, + 0x46, 0x27, 0x07, 0x46, 0xce, 0x6e, 0x7a, 0xe5, 0x3d, 0xa6, 0x40, 0x0a, 0xba, 0x9b, 0x5e, 0xe1, + 0x4f, 0x29, 0x36, 0x7b, 0xb1, 0xf0, 0x46, 0x40, 0x2c, 0xd8, 0x9b, 0xe6, 0x51, 0x3d, 0x52, 0x5c, + 0x29, 0x6f, 0x3d, 0xab, 0x7f, 0xd0, 0x0d, 0xda, 0xfb, 0xb7, 0xc7, 0x25, 0x9f, 0xb1, 0xaa, 0xd2, + 0x5f, 0x80, 0xf5, 0x2f, 0x38, 0x69, 0xd9, 0x10, 0x7c, 0xff, 0xf5, 0x5e, 0x18, 0x72, 0x3e, 0xdb, + 0xa8, 0x44, 0xf6, 0x6b, 0x52, 0xeb, 0xa8, 0x66, 0xfb, 0x43, 0x52, 0x1b, 0x9d, 0x9c, 0x1d, 0x5e, + 0x5a, 0xea, 0x7e, 0x3e, 0xea, 0x01, 0xaa, 0x8e, 0x7d, 0x39, 0xea, 0x61, 0x0f, 0x52, 0xbb, 0xfa, + 0x34, 0x7a, 0xeb, 0x80, 0xcf, 0x27, 0x2c, 0x4f, 0x06, 0xdf, 0xf3, 0x6f, 0xf0, 0xf2, 0xf9, 0xb0, + 0xfe, 0xb3, 0x31, 0x7a, 0x83, 0x12, 0xdb, 0x3b, 0x88, 0xbb, 0xec, 0x6c, 0x39, 0x9f, 0x88, 0x58, + 0x80, 0x3b, 0x88, 0xf2, 0xef, 0xc3, 0x5a, 0x40, 0xdc, 0x41, 0xf4, 0x00, 0x60, 0x6f, 0x5a, 0x32, + 0x86, 0xda, 0xab, 0x05, 0x41, 0x7b, 0x1a, 0xb0, 0x59, 0x84, 0xb1, 0x57, 0x27, 0xea, 0xf0, 0xce, + 0xa0, 0xd5, 0x91, 0x52, 0x22, 0x8b, 0x68, 0x53, 0x36, 0xb8, 0x55, 0xf5, 0xe5, 0xd7, 0x7c, 0x96, + 0x8b, 0x45, 0x5c, 0xae, 0x40, 0x70, 0xeb, 0x5a, 0x3a, 0x00, 0x11, 0xdc, 0x28, 0x68, 0x47, 0x6d, + 0xd3, 0xcc, 0xb3, 0xcb, 0x7d, 0x5e, 0xf2, 0xa5, 0x48, 0x73, 0x06, 0xbf, 0xe8, 0x62, 0x1a, 0xd4, + 0x65, 0x88, 0x51, 0x4b, 0xb1, 0x36, 0xcb, 0x95, 0x84, 0xba, 0xce, 0x28, 0x3f, 0xb5, 0x5f, 0x09, + 0x5e, 0xc2, 0xc7, 0x99, 0xca, 0x0a, 0x84, 0x88, 0x2c, 0x97, 0x84, 0x41, 0xdf, 0x1f, 0xa7, 0xf9, + 0x1c, 0xed, 0xfb, 0x63, 0xf7, 0xab, 0xca, 0xb7, 0x68, 0xc0, 0x0e, 0x28, 0xd5, 0x68, 0x6a, 0x00, + 0xe8, 0x57, 0x99, 0xd1, 0x46, 0x77, 0x09, 0x62, 0x40, 0xe1, 0x24, 0x70, 0xf5, 0x79, 0xc1, 0x72, + 0x96, 0x34, 0x97, 0xf6, 0x30, 0x57, 0x1e, 0x11, 0x74, 0x05, 0x49, 0x3b, 0x17, 0x49, 0xf9, 0xc9, + 0x32, 0x3f, 0x2e, 0xf9, 0x79, 0x9a, 0xb1, 0x12, 0xcc, 0x45, 0x4a, 0xdd, 0x91, 0x13, 0x73, 0x11, + 0xc6, 0xd9, 0xdb, 0x1f, 0x52, 0xea, 0xfd, 0x5e, 0xc4, 0xb4, 0x8c, 0x67, 0xf0, 0xf6, 0x87, 0xb2, + 0xd1, 0xc6, 0x88, 0x93, 0xc1, 0x00, 0xee, 0x24, 0x3a, 0xca, 0x75, 0xbe, 0x92, 0xf1, 0xa1, 0x5f, + 0xa5, 0x95, 0xdf, 0x1a, 0xae, 0x40, 0xa2, 0xa3, 0xcd, 0x61, 0x24, 0x91, 0xe8, 0x84, 0x35, 0xec, + 0x52, 0x22, 0xb9, 0x23, 0x7d, 0xab, 0x09, 0x2c, 0x25, 0xca, 0x46, 0x23, 0x24, 0x96, 0x92, 0x16, + 0x04, 0x26, 0xa4, 0x66, 0x18, 0xcc, 0xd1, 0x09, 0xc9, 0x48, 0x83, 0x13, 0x92, 0x4b, 0xd9, 0x89, + 0x62, 0x9c, 0xa7, 0x22, 0x8d, 0xb3, 0x09, 0x13, 0xc7, 0x71, 0x19, 0x2f, 0x98, 0x60, 0x25, 0x9c, + 0x28, 0x34, 0x32, 0xf4, 0x18, 0x62, 0xa2, 0xa0, 0x58, 0xed, 0xf0, 0x77, 0xa2, 0x77, 0xea, 0x75, + 0x9f, 0xe5, 0xfa, 0x97, 0xae, 0x5e, 0xc8, 0xdf, 0x29, 0x1c, 0xbc, 0x6b, 0x6c, 0x4c, 0x44, 0xc9, + 0xe2, 0x45, 0x63, 0xfb, 0x6d, 0xf3, 0x77, 0x09, 0x3e, 0x59, 0xab, 0xe3, 0xf9, 0x88, 0x8b, 0xf4, + 0xbc, 0xde, 0x66, 0xeb, 0x17, 0x98, 0x40, 0x3c, 0xbb, 0xe2, 0x61, 0xe0, 0x53, 0x2c, 0x18, 0x67, + 0xe7, 0x69, 0x57, 0x7a, 0xc2, 0x8a, 0x0c, 0xce, 0xd3, 0x9e, 0xb6, 0x04, 0x88, 0x79, 0x1a, 0x05, + 0xed, 0xe0, 0x74, 0xc5, 0x53, 0x16, 0xae, 0xcc, 0x94, 0xf5, 0xab, 0xcc, 0xd4, 0x7b, 0x27, 0x24, + 0x8b, 0xde, 0x39, 0x64, 0x8b, 0x33, 0x56, 0x56, 0x17, 0x69, 0x41, 0x7d, 0x0f, 0xd9, 0x12, 0x9d, + 0xdf, 0x43, 0x26, 0x50, 0xbb, 0x12, 0x58, 0x60, 0x5c, 0x1d, 0xc5, 0x0b, 0x26, 0x3f, 0x2c, 0x03, + 0x56, 0x02, 0xc7, 0x88, 0x03, 0x11, 0x2b, 0x01, 0x09, 0x3b, 0xaf, 0x97, 0x59, 0xe6, 0x84, 0xcd, + 0xeb, 0x08, 0x2b, 0x8f, 0xe3, 0xd5, 0x82, 0xe5, 0x42, 0x9b, 0x04, 0x67, 0xf2, 0x8e, 0x49, 0x9c, + 0x27, 0xce, 0xe4, 0xfb, 0xe8, 0x39, 0x53, 0x93, 0xd7, 0xf0, 0xc7, 0xbc, 0x14, 0xea, 0x27, 0xec, + 0x4e, 0xcb, 0x0c, 0x4c, 0x4d, 0x7e, 0xa3, 0x7a, 0x24, 0x31, 0x35, 0x85, 0x35, 0x9c, 0xdf, 0x2c, + 0xf1, 0xca, 0xf0, 0x92, 0x95, 0x26, 0x4e, 0x5e, 0x2c, 0xe2, 0x34, 0xd3, 0xd1, 0xf0, 0xfd, 0x80, + 0x6d, 0x42, 0x87, 0xf8, 0xcd, 0x92, 0xbe, 0xba, 0xce, 0xaf, 0xbc, 0x84, 0x4b, 0x08, 0x1e, 0x11, + 0x74, 0xd8, 0x27, 0x1e, 0x11, 0x74, 0x6b, 0xd9, 0x9d, 0xbb, 0x65, 0x25, 0xb7, 0x92, 0xc4, 0x0e, + 0x4f, 0xe0, 0x79, 0xa1, 0x63, 0x13, 0x80, 0xc4, 0xce, 0x3d, 0xa8, 0x60, 0x53, 0x03, 0x8b, 0xed, + 0xa5, 0x79, 0x9c, 0xa5, 0x3f, 0x86, 0x69, 0xbd, 0x63, 0xa7, 0x21, 0x88, 0xd4, 0x00, 0x27, 0x31, + 0x57, 0xfb, 0x4c, 0x4c, 0xd3, 0x7a, 0xea, 0x7f, 0x10, 0x68, 0x37, 0x49, 0x74, 0xbb, 0x72, 0x48, + 0xe7, 0xdb, 0xc7, 0xb0, 0x59, 0x47, 0x45, 0x31, 0xa9, 0x57, 0xd5, 0x13, 0x36, 0x63, 0x69, 0x21, + 0x06, 0x1f, 0x86, 0xdb, 0x0a, 0xe0, 0xc4, 0x45, 0x8b, 0x1e, 0x6a, 0xce, 0xe3, 0xfb, 0x7a, 0x2e, + 0x99, 0xa8, 0x5f, 0xd9, 0x3d, 0xad, 0x58, 0xa9, 0x13, 0x8d, 0x7d, 0x26, 0xc0, 0xe8, 0x74, 0xb8, + 0xa1, 0x03, 0xd6, 0x15, 0x25, 0x46, 0x67, 0x58, 0xc3, 0x1e, 0xf6, 0x39, 0x9c, 0xfe, 0x76, 0x80, + 0xbc, 0xee, 0xf8, 0x98, 0x34, 0xe6, 0x50, 0xc4, 0x61, 0x1f, 0x4d, 0xdb, 0x6c, 0xad, 0xed, 0x76, + 0x94, 0xaf, 0xc6, 0xf0, 0xca, 0x04, 0x62, 0x49, 0x62, 0x44, 0xb6, 0x16, 0xc0, 0x9d, 0xc3, 0xf0, + 0x92, 0xc7, 0xc9, 0x2c, 0xae, 0xc4, 0x71, 0xbc, 0xca, 0x78, 0x9c, 0xc8, 0x75, 0x1d, 0x1e, 0x86, + 0x37, 0xcc, 0xd0, 0x85, 0xa8, 0xc3, 0x70, 0x0a, 0x76, 0xb3, 0x33, 0xf9, 0xe3, 0xc1, 0xfa, 0x2a, + 0x29, 0xcc, 0xce, 0x64, 0x79, 0xe1, 0x35, 0xd2, 0x7b, 0x61, 0xc8, 0xbe, 0x02, 0xa7, 0x44, 0x32, + 0x0d, 0xb9, 0x85, 0xe9, 0x78, 0x09, 0xc8, 0xed, 0x00, 0x61, 0x3f, 0xcb, 0xa2, 0xfe, 0xde, 0xfc, + 0x54, 0x99, 0xd0, 0x5f, 0x88, 0x7f, 0x8c, 0xe9, 0xba, 0x90, 0x77, 0x43, 0x6d, 0xab, 0x27, 0x6d, + 0xd3, 0xcc, 0x9d, 0x8b, 0x58, 0x8c, 0x92, 0xe4, 0x90, 0x55, 0xc8, 0xfb, 0xec, 0xb5, 0x70, 0x68, + 0xa5, 0x44, 0x9a, 0xd9, 0xa6, 0x6c, 0xa0, 0xd7, 0xb2, 0x17, 0x49, 0x2a, 0xb4, 0xac, 0xb9, 0xa0, + 0xfd, 0xb8, 0x6d, 0xa0, 0x4d, 0x11, 0xb5, 0xa2, 0x69, 0x3b, 0x97, 0xd7, 0xcc, 0x94, 0xcf, 0xe7, + 0x19, 0xd3, 0xd0, 0x09, 0x8b, 0xd5, 0x07, 0x32, 0xb7, 0xdb, 0xb6, 0x50, 0x90, 0x98, 0xcb, 0x83, + 0x0a, 0x36, 0x8d, 0xac, 0x31, 0xf5, 0x48, 0xaa, 0x69, 0xd8, 0x8d, 0xb6, 0x19, 0x0f, 0x20, 0xd2, + 0x48, 0x14, 0xb4, 0xaf, 0xdd, 0xd5, 0xe2, 0x7d, 0xd6, 0xb4, 0x04, 0xfc, 0x02, 0x97, 0x54, 0x76, + 0xc4, 0xc4, 0x6b, 0x77, 0x08, 0x66, 0xf7, 0x09, 0xc0, 0xc3, 0xf3, 0xd5, 0x38, 0x81, 0xfb, 0x04, + 0xa8, 0x2f, 0x19, 0x62, 0x9f, 0x40, 0xb1, 0x7e, 0xd7, 0x99, 0x73, 0xaf, 0x83, 0xb8, 0xb2, 0x95, + 0x43, 0xba, 0x0e, 0x05, 0x43, 0x5d, 0x47, 0x29, 0xf8, 0x4d, 0xea, 0x1e, 0xad, 0x21, 0x4d, 0x8a, + 0x9d, 0xab, 0xad, 0x77, 0x61, 0x36, 0xf7, 0xaf, 0x85, 0x27, 0x2c, 0x4e, 0x4c, 0xc5, 0x10, 0x5d, + 0x57, 0x4e, 0xe4, 0xfe, 0x18, 0xa7, 0x9d, 0xfc, 0x7e, 0x34, 0x50, 0xd5, 0x28, 0x5d, 0x37, 0xb7, + 0xb0, 0x22, 0xd6, 0x04, 0x31, 0x51, 0xf9, 0x84, 0x93, 0xb8, 0x79, 0x5d, 0x34, 0xe5, 0xda, 0x81, + 0x7e, 0x2d, 0xb4, 0x02, 0x89, 0x9b, 0xdf, 0xec, 0x2d, 0x9a, 0x48, 0xdc, 0xba, 0xb5, 0x9c, 0x8f, + 0x11, 0x81, 0x2e, 0xdb, 0x2b, 0xf9, 0x02, 0x96, 0xe9, 0x93, 0x60, 0xf7, 0x20, 0x1a, 0xc4, 0xc7, + 0x88, 0xfa, 0x69, 0xda, 0x35, 0xc8, 0x9c, 0x1d, 0xc8, 0xeb, 0x69, 0xf8, 0xaf, 0xa0, 0x28, 0x21, + 0xb1, 0x06, 0xb5, 0x20, 0xfb, 0x1e, 0x72, 0x13, 0x47, 0xa3, 0x2c, 0x1b, 0xdc, 0xc6, 0x43, 0xc3, + 0xfd, 0xc0, 0xc3, 0x9d, 0x10, 0xe2, 0xfc, 0xf0, 0xeb, 0xf8, 0x55, 0x99, 0x8a, 0x34, 0x9f, 0x4f, + 0x39, 0xcf, 0xe0, 0x41, 0xe8, 0x68, 0x3c, 0x74, 0xa5, 0xd4, 0x0f, 0xbf, 0xb6, 0x28, 0xbb, 0x70, + 0x8e, 0xc6, 0xa3, 0xa5, 0xe0, 0xe7, 0x69, 0x96, 0x81, 0x78, 0x1c, 0x8d, 0x87, 0x8d, 0x84, 0x88, + 0x47, 0x9f, 0x70, 0x7e, 0xae, 0x74, 0x2c, 0x9f, 0x29, 0xe8, 0x73, 0xd5, 0xbb, 0x50, 0xc7, 0x11, + 0x52, 0x3f, 0x57, 0x0a, 0x21, 0xe7, 0xe7, 0x57, 0xc7, 0xd8, 0x0f, 0xc4, 0x6c, 0x42, 0x75, 0x04, + 0xa2, 0x7e, 0x7e, 0x95, 0x82, 0x9d, 0x37, 0x9d, 0x8f, 0x97, 0xd5, 0x85, 0x7f, 0x10, 0xa1, 0xb6, + 0x9c, 0xea, 0x63, 0xb0, 0xcf, 0xc0, 0xcf, 0x14, 0xf9, 0xec, 0xd0, 0x83, 0x89, 0x4b, 0x6f, 0x9d, + 0x4a, 0xaa, 0x30, 0xcf, 0x6f, 0xff, 0xf7, 0x97, 0x37, 0xd6, 0x7e, 0xf6, 0xe5, 0x8d, 0xb5, 0xff, + 0xfd, 0xf2, 0xc6, 0xda, 0x4f, 0xbf, 0xba, 0xf1, 0x8d, 0x9f, 0x7d, 0x75, 0xe3, 0x1b, 0xff, 0xf3, + 0xd5, 0x8d, 0x6f, 0x7c, 0xf1, 0x56, 0xa5, 0x32, 0xbe, 0xb3, 0x9f, 0x2f, 0x4a, 0x2e, 0xf8, 0xb3, + 0xff, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xf4, 0x6f, 0x9e, 0xb4, 0xc9, 0x82, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -412,6 +417,9 @@ type ClientCommandsClient interface { WalletConvert(ctx context.Context, in *pb.RpcWalletConvertRequest, opts ...grpc.CallOption) (*pb.RpcWalletConvertResponse, error) AccountLocalLinkNewChallenge(ctx context.Context, in *pb.RpcAccountLocalLinkNewChallengeRequest, opts ...grpc.CallOption) (*pb.RpcAccountLocalLinkNewChallengeResponse, error) AccountLocalLinkSolveChallenge(ctx context.Context, in *pb.RpcAccountLocalLinkSolveChallengeRequest, opts ...grpc.CallOption) (*pb.RpcAccountLocalLinkSolveChallengeResponse, error) + AccountLocalLinkCreateApp(ctx context.Context, in *pb.RpcAccountLocalLinkCreateAppRequest, opts ...grpc.CallOption) (*pb.RpcAccountLocalLinkCreateAppResponse, error) + AccountLocalLinkListApps(ctx context.Context, in *pb.RpcAccountLocalLinkListAppsRequest, opts ...grpc.CallOption) (*pb.RpcAccountLocalLinkListAppsResponse, error) + AccountLocalLinkRevokeApp(ctx context.Context, in *pb.RpcAccountLocalLinkRevokeAppRequest, opts ...grpc.CallOption) (*pb.RpcAccountLocalLinkRevokeAppResponse, error) WalletCreateSession(ctx context.Context, in *pb.RpcWalletCreateSessionRequest, opts ...grpc.CallOption) (*pb.RpcWalletCreateSessionResponse, error) WalletCloseSession(ctx context.Context, in *pb.RpcWalletCloseSessionRequest, opts ...grpc.CallOption) (*pb.RpcWalletCloseSessionResponse, error) // Workspace @@ -446,6 +454,7 @@ type ClientCommandsClient interface { // *** SpaceDelete(ctx context.Context, in *pb.RpcSpaceDeleteRequest, opts ...grpc.CallOption) (*pb.RpcSpaceDeleteResponse, error) SpaceInviteGenerate(ctx context.Context, in *pb.RpcSpaceInviteGenerateRequest, opts ...grpc.CallOption) (*pb.RpcSpaceInviteGenerateResponse, error) + SpaceInviteChange(ctx context.Context, in *pb.RpcSpaceInviteChangeRequest, opts ...grpc.CallOption) (*pb.RpcSpaceInviteChangeResponse, error) SpaceInviteGetCurrent(ctx context.Context, in *pb.RpcSpaceInviteGetCurrentRequest, opts ...grpc.CallOption) (*pb.RpcSpaceInviteGetCurrentResponse, error) SpaceInviteGetGuest(ctx context.Context, in *pb.RpcSpaceInviteGetGuestRequest, opts ...grpc.CallOption) (*pb.RpcSpaceInviteGetGuestResponse, error) SpaceInviteRevoke(ctx context.Context, in *pb.RpcSpaceInviteRevokeRequest, opts ...grpc.CallOption) (*pb.RpcSpaceInviteRevokeResponse, error) @@ -754,6 +763,7 @@ type ClientCommandsClient interface { ChatSubscribeToMessagePreviews(ctx context.Context, in *pb.RpcChatSubscribeToMessagePreviewsRequest, opts ...grpc.CallOption) (*pb.RpcChatSubscribeToMessagePreviewsResponse, error) ChatUnsubscribeFromMessagePreviews(ctx context.Context, in *pb.RpcChatUnsubscribeFromMessagePreviewsRequest, opts ...grpc.CallOption) (*pb.RpcChatUnsubscribeFromMessagePreviewsResponse, error) ObjectChatAdd(ctx context.Context, in *pb.RpcObjectChatAddRequest, opts ...grpc.CallOption) (*pb.RpcObjectChatAddResponse, error) + ChatReadAll(ctx context.Context, in *pb.RpcChatReadAllRequest, opts ...grpc.CallOption) (*pb.RpcChatReadAllResponse, error) // mock AI RPCs for compatibility between branches. Not implemented in main AIWritingTools(ctx context.Context, in *pb.RpcAIWritingToolsRequest, opts ...grpc.CallOption) (*pb.RpcAIWritingToolsResponse, error) AIAutofill(ctx context.Context, in *pb.RpcAIAutofillRequest, opts ...grpc.CallOption) (*pb.RpcAIAutofillResponse, error) @@ -843,6 +853,33 @@ func (c *clientCommandsClient) AccountLocalLinkSolveChallenge(ctx context.Contex return out, nil } +func (c *clientCommandsClient) AccountLocalLinkCreateApp(ctx context.Context, in *pb.RpcAccountLocalLinkCreateAppRequest, opts ...grpc.CallOption) (*pb.RpcAccountLocalLinkCreateAppResponse, error) { + out := new(pb.RpcAccountLocalLinkCreateAppResponse) + err := c.cc.Invoke(ctx, "/anytype.ClientCommands/AccountLocalLinkCreateApp", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *clientCommandsClient) AccountLocalLinkListApps(ctx context.Context, in *pb.RpcAccountLocalLinkListAppsRequest, opts ...grpc.CallOption) (*pb.RpcAccountLocalLinkListAppsResponse, error) { + out := new(pb.RpcAccountLocalLinkListAppsResponse) + err := c.cc.Invoke(ctx, "/anytype.ClientCommands/AccountLocalLinkListApps", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *clientCommandsClient) AccountLocalLinkRevokeApp(ctx context.Context, in *pb.RpcAccountLocalLinkRevokeAppRequest, opts ...grpc.CallOption) (*pb.RpcAccountLocalLinkRevokeAppResponse, error) { + out := new(pb.RpcAccountLocalLinkRevokeAppResponse) + err := c.cc.Invoke(ctx, "/anytype.ClientCommands/AccountLocalLinkRevokeApp", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *clientCommandsClient) WalletCreateSession(ctx context.Context, in *pb.RpcWalletCreateSessionRequest, opts ...grpc.CallOption) (*pb.RpcWalletCreateSessionResponse, error) { out := new(pb.RpcWalletCreateSessionResponse) err := c.cc.Invoke(ctx, "/anytype.ClientCommands/WalletCreateSession", in, out, opts...) @@ -1095,6 +1132,15 @@ func (c *clientCommandsClient) SpaceInviteGenerate(ctx context.Context, in *pb.R return out, nil } +func (c *clientCommandsClient) SpaceInviteChange(ctx context.Context, in *pb.RpcSpaceInviteChangeRequest, opts ...grpc.CallOption) (*pb.RpcSpaceInviteChangeResponse, error) { + out := new(pb.RpcSpaceInviteChangeResponse) + err := c.cc.Invoke(ctx, "/anytype.ClientCommands/SpaceInviteChange", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *clientCommandsClient) SpaceInviteGetCurrent(ctx context.Context, in *pb.RpcSpaceInviteGetCurrentRequest, opts ...grpc.CallOption) (*pb.RpcSpaceInviteGetCurrentResponse, error) { out := new(pb.RpcSpaceInviteGetCurrentResponse) err := c.cc.Invoke(ctx, "/anytype.ClientCommands/SpaceInviteGetCurrent", in, out, opts...) @@ -3395,6 +3441,15 @@ func (c *clientCommandsClient) ObjectChatAdd(ctx context.Context, in *pb.RpcObje return out, nil } +func (c *clientCommandsClient) ChatReadAll(ctx context.Context, in *pb.RpcChatReadAllRequest, opts ...grpc.CallOption) (*pb.RpcChatReadAllResponse, error) { + out := new(pb.RpcChatReadAllResponse) + err := c.cc.Invoke(ctx, "/anytype.ClientCommands/ChatReadAll", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *clientCommandsClient) AIWritingTools(ctx context.Context, in *pb.RpcAIWritingToolsRequest, opts ...grpc.CallOption) (*pb.RpcAIWritingToolsResponse, error) { out := new(pb.RpcAIWritingToolsResponse) err := c.cc.Invoke(ctx, "/anytype.ClientCommands/AIWritingTools", in, out, opts...) @@ -3452,6 +3507,9 @@ type ClientCommandsServer interface { WalletConvert(context.Context, *pb.RpcWalletConvertRequest) *pb.RpcWalletConvertResponse AccountLocalLinkNewChallenge(context.Context, *pb.RpcAccountLocalLinkNewChallengeRequest) *pb.RpcAccountLocalLinkNewChallengeResponse AccountLocalLinkSolveChallenge(context.Context, *pb.RpcAccountLocalLinkSolveChallengeRequest) *pb.RpcAccountLocalLinkSolveChallengeResponse + AccountLocalLinkCreateApp(context.Context, *pb.RpcAccountLocalLinkCreateAppRequest) *pb.RpcAccountLocalLinkCreateAppResponse + AccountLocalLinkListApps(context.Context, *pb.RpcAccountLocalLinkListAppsRequest) *pb.RpcAccountLocalLinkListAppsResponse + AccountLocalLinkRevokeApp(context.Context, *pb.RpcAccountLocalLinkRevokeAppRequest) *pb.RpcAccountLocalLinkRevokeAppResponse WalletCreateSession(context.Context, *pb.RpcWalletCreateSessionRequest) *pb.RpcWalletCreateSessionResponse WalletCloseSession(context.Context, *pb.RpcWalletCloseSessionRequest) *pb.RpcWalletCloseSessionResponse // Workspace @@ -3486,6 +3544,7 @@ type ClientCommandsServer interface { // *** SpaceDelete(context.Context, *pb.RpcSpaceDeleteRequest) *pb.RpcSpaceDeleteResponse SpaceInviteGenerate(context.Context, *pb.RpcSpaceInviteGenerateRequest) *pb.RpcSpaceInviteGenerateResponse + SpaceInviteChange(context.Context, *pb.RpcSpaceInviteChangeRequest) *pb.RpcSpaceInviteChangeResponse SpaceInviteGetCurrent(context.Context, *pb.RpcSpaceInviteGetCurrentRequest) *pb.RpcSpaceInviteGetCurrentResponse SpaceInviteGetGuest(context.Context, *pb.RpcSpaceInviteGetGuestRequest) *pb.RpcSpaceInviteGetGuestResponse SpaceInviteRevoke(context.Context, *pb.RpcSpaceInviteRevokeRequest) *pb.RpcSpaceInviteRevokeResponse @@ -3794,6 +3853,7 @@ type ClientCommandsServer interface { ChatSubscribeToMessagePreviews(context.Context, *pb.RpcChatSubscribeToMessagePreviewsRequest) *pb.RpcChatSubscribeToMessagePreviewsResponse ChatUnsubscribeFromMessagePreviews(context.Context, *pb.RpcChatUnsubscribeFromMessagePreviewsRequest) *pb.RpcChatUnsubscribeFromMessagePreviewsResponse ObjectChatAdd(context.Context, *pb.RpcObjectChatAddRequest) *pb.RpcObjectChatAddResponse + ChatReadAll(context.Context, *pb.RpcChatReadAllRequest) *pb.RpcChatReadAllResponse // mock AI RPCs for compatibility between branches. Not implemented in main AIWritingTools(context.Context, *pb.RpcAIWritingToolsRequest) *pb.RpcAIWritingToolsResponse AIAutofill(context.Context, *pb.RpcAIAutofillRequest) *pb.RpcAIAutofillResponse @@ -3831,6 +3891,15 @@ func (*UnimplementedClientCommandsServer) AccountLocalLinkNewChallenge(ctx conte func (*UnimplementedClientCommandsServer) AccountLocalLinkSolveChallenge(ctx context.Context, req *pb.RpcAccountLocalLinkSolveChallengeRequest) *pb.RpcAccountLocalLinkSolveChallengeResponse { return nil } +func (*UnimplementedClientCommandsServer) AccountLocalLinkCreateApp(ctx context.Context, req *pb.RpcAccountLocalLinkCreateAppRequest) *pb.RpcAccountLocalLinkCreateAppResponse { + return nil +} +func (*UnimplementedClientCommandsServer) AccountLocalLinkListApps(ctx context.Context, req *pb.RpcAccountLocalLinkListAppsRequest) *pb.RpcAccountLocalLinkListAppsResponse { + return nil +} +func (*UnimplementedClientCommandsServer) AccountLocalLinkRevokeApp(ctx context.Context, req *pb.RpcAccountLocalLinkRevokeAppRequest) *pb.RpcAccountLocalLinkRevokeAppResponse { + return nil +} func (*UnimplementedClientCommandsServer) WalletCreateSession(ctx context.Context, req *pb.RpcWalletCreateSessionRequest) *pb.RpcWalletCreateSessionResponse { return nil } @@ -3915,6 +3984,9 @@ func (*UnimplementedClientCommandsServer) SpaceDelete(ctx context.Context, req * func (*UnimplementedClientCommandsServer) SpaceInviteGenerate(ctx context.Context, req *pb.RpcSpaceInviteGenerateRequest) *pb.RpcSpaceInviteGenerateResponse { return nil } +func (*UnimplementedClientCommandsServer) SpaceInviteChange(ctx context.Context, req *pb.RpcSpaceInviteChangeRequest) *pb.RpcSpaceInviteChangeResponse { + return nil +} func (*UnimplementedClientCommandsServer) SpaceInviteGetCurrent(ctx context.Context, req *pb.RpcSpaceInviteGetCurrentRequest) *pb.RpcSpaceInviteGetCurrentResponse { return nil } @@ -4674,6 +4746,9 @@ func (*UnimplementedClientCommandsServer) ChatUnsubscribeFromMessagePreviews(ctx func (*UnimplementedClientCommandsServer) ObjectChatAdd(ctx context.Context, req *pb.RpcObjectChatAddRequest) *pb.RpcObjectChatAddResponse { return nil } +func (*UnimplementedClientCommandsServer) ChatReadAll(ctx context.Context, req *pb.RpcChatReadAllRequest) *pb.RpcChatReadAllResponse { + return nil +} func (*UnimplementedClientCommandsServer) AIWritingTools(ctx context.Context, req *pb.RpcAIWritingToolsRequest) *pb.RpcAIWritingToolsResponse { return nil } @@ -4838,6 +4913,60 @@ func _ClientCommands_AccountLocalLinkSolveChallenge_Handler(srv interface{}, ctx return interceptor(ctx, in, info, handler) } +func _ClientCommands_AccountLocalLinkCreateApp_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(pb.RpcAccountLocalLinkCreateAppRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ClientCommandsServer).AccountLocalLinkCreateApp(ctx, in), nil + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/anytype.ClientCommands/AccountLocalLinkCreateApp", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ClientCommandsServer).AccountLocalLinkCreateApp(ctx, req.(*pb.RpcAccountLocalLinkCreateAppRequest)), nil + } + return interceptor(ctx, in, info, handler) +} + +func _ClientCommands_AccountLocalLinkListApps_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(pb.RpcAccountLocalLinkListAppsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ClientCommandsServer).AccountLocalLinkListApps(ctx, in), nil + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/anytype.ClientCommands/AccountLocalLinkListApps", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ClientCommandsServer).AccountLocalLinkListApps(ctx, req.(*pb.RpcAccountLocalLinkListAppsRequest)), nil + } + return interceptor(ctx, in, info, handler) +} + +func _ClientCommands_AccountLocalLinkRevokeApp_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(pb.RpcAccountLocalLinkRevokeAppRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ClientCommandsServer).AccountLocalLinkRevokeApp(ctx, in), nil + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/anytype.ClientCommands/AccountLocalLinkRevokeApp", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ClientCommandsServer).AccountLocalLinkRevokeApp(ctx, req.(*pb.RpcAccountLocalLinkRevokeAppRequest)), nil + } + return interceptor(ctx, in, info, handler) +} + func _ClientCommands_WalletCreateSession_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(pb.RpcWalletCreateSessionRequest) if err := dec(in); err != nil { @@ -5342,6 +5471,24 @@ func _ClientCommands_SpaceInviteGenerate_Handler(srv interface{}, ctx context.Co return interceptor(ctx, in, info, handler) } +func _ClientCommands_SpaceInviteChange_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(pb.RpcSpaceInviteChangeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ClientCommandsServer).SpaceInviteChange(ctx, in), nil + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/anytype.ClientCommands/SpaceInviteChange", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ClientCommandsServer).SpaceInviteChange(ctx, req.(*pb.RpcSpaceInviteChangeRequest)), nil + } + return interceptor(ctx, in, info, handler) +} + func _ClientCommands_SpaceInviteGetCurrent_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(pb.RpcSpaceInviteGetCurrentRequest) if err := dec(in); err != nil { @@ -9900,6 +10047,24 @@ func _ClientCommands_ObjectChatAdd_Handler(srv interface{}, ctx context.Context, return interceptor(ctx, in, info, handler) } +func _ClientCommands_ChatReadAll_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(pb.RpcChatReadAllRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ClientCommandsServer).ChatReadAll(ctx, in), nil + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/anytype.ClientCommands/ChatReadAll", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ClientCommandsServer).ChatReadAll(ctx, req.(*pb.RpcChatReadAllRequest)), nil + } + return interceptor(ctx, in, info, handler) +} + func _ClientCommands_AIWritingTools_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(pb.RpcAIWritingToolsRequest) if err := dec(in); err != nil { @@ -10026,6 +10191,18 @@ var _ClientCommands_serviceDesc = grpc.ServiceDesc{ MethodName: "AccountLocalLinkSolveChallenge", Handler: _ClientCommands_AccountLocalLinkSolveChallenge_Handler, }, + { + MethodName: "AccountLocalLinkCreateApp", + Handler: _ClientCommands_AccountLocalLinkCreateApp_Handler, + }, + { + MethodName: "AccountLocalLinkListApps", + Handler: _ClientCommands_AccountLocalLinkListApps_Handler, + }, + { + MethodName: "AccountLocalLinkRevokeApp", + Handler: _ClientCommands_AccountLocalLinkRevokeApp_Handler, + }, { MethodName: "WalletCreateSession", Handler: _ClientCommands_WalletCreateSession_Handler, @@ -10138,6 +10315,10 @@ var _ClientCommands_serviceDesc = grpc.ServiceDesc{ MethodName: "SpaceInviteGenerate", Handler: _ClientCommands_SpaceInviteGenerate_Handler, }, + { + MethodName: "SpaceInviteChange", + Handler: _ClientCommands_SpaceInviteChange_Handler, + }, { MethodName: "SpaceInviteGetCurrent", Handler: _ClientCommands_SpaceInviteGetCurrent_Handler, @@ -11146,6 +11327,10 @@ var _ClientCommands_serviceDesc = grpc.ServiceDesc{ MethodName: "ObjectChatAdd", Handler: _ClientCommands_ObjectChatAdd_Handler, }, + { + MethodName: "ChatReadAll", + Handler: _ClientCommands_ChatReadAll_Handler, + }, { MethodName: "AIWritingTools", Handler: _ClientCommands_AIWritingTools_Handler, diff --git a/pkg/lib/bundle/relation.gen.go b/pkg/lib/bundle/relation.gen.go index 5df8b895d..34200bd42 100644 --- a/pkg/lib/bundle/relation.gen.go +++ b/pkg/lib/bundle/relation.gen.go @@ -9,7 +9,7 @@ import ( "github.com/anyproto/anytype-heart/pkg/lib/pb/model" ) -const RelationChecksum = "d48a3d0b09921529f922f42d214a6b5c00b5ce939bb5056b4aa80b9a1e4cd0e0" +const RelationChecksum = "5dcb32d8a24ade95642a2e7258eb1bc12645f31f875d8eb7dcdfdf01e4062dc4" const ( RelationKeyTag domain.RelationKey = "tag" RelationKeyCamera domain.RelationKey = "camera" @@ -126,10 +126,12 @@ const ( RelationKeySpaceAccountStatus domain.RelationKey = "spaceAccountStatus" RelationKeySpaceInviteFileCid domain.RelationKey = "spaceInviteFileCid" RelationKeySpaceInviteFileKey domain.RelationKey = "spaceInviteFileKey" + RelationKeySpaceInviteType domain.RelationKey = "spaceInviteType" RelationKeySpaceInviteGuestFileCid domain.RelationKey = "spaceInviteGuestFileCid" RelationKeySpaceInviteGuestFileKey domain.RelationKey = "spaceInviteGuestFileKey" RelationKeyGuestKey domain.RelationKey = "guestKey" RelationKeyParticipantPermissions domain.RelationKey = "participantPermissions" + RelationKeySpaceInvitePermissions domain.RelationKey = "spaceInvitePermissions" RelationKeyIdentity domain.RelationKey = "identity" RelationKeyParticipantStatus domain.RelationKey = "participantStatus" RelationKeyIdentityProfileLink domain.RelationKey = "identityProfileLink" @@ -160,6 +162,8 @@ const ( RelationKeyAutoWidgetTargets domain.RelationKey = "autoWidgetTargets" RelationKeyAutoWidgetDisabled domain.RelationKey = "autoWidgetDisabled" RelationKeyPluralName domain.RelationKey = "pluralName" + RelationKeyHeaderRelationsLayout domain.RelationKey = "headerRelationsLayout" + RelationKeyApiObjectKey domain.RelationKey = "apiObjectKey" RelationKeyIncludeTime domain.RelationKey = "includeTime" ) @@ -193,6 +197,20 @@ var ( ReadOnlyRelation: true, Scope: model.Relation_type, }, + RelationKeyApiObjectKey: { + + DataSource: model.Relation_details, + Description: "Identifier to use in intergrations with Anytype API", + Format: model.RelationFormat_longtext, + Hidden: true, + Id: "_brapiObjectKey", + Key: "apiObjectKey", + MaxCount: 1, + Name: "API Object Key", + ReadOnly: false, + ReadOnlyRelation: true, + Scope: model.Relation_type, + }, RelationKeyArtist: { DataSource: model.Relation_details, @@ -766,6 +784,20 @@ var ( ReadOnlyRelation: true, Scope: model.Relation_type, }, + RelationKeyHeaderRelationsLayout: { + + DataSource: model.Relation_details, + Description: "Layout of header relations. Line or column", + Format: model.RelationFormat_number, + Hidden: true, + Id: "_brheaderRelationsLayout", + Key: "headerRelationsLayout", + MaxCount: 1, + Name: "Header relations layout", + ReadOnly: false, + ReadOnlyRelation: true, + Scope: model.Relation_type, + }, RelationKeyHeightInPixels: { DataSource: model.Relation_details, @@ -1905,6 +1937,34 @@ var ( ReadOnlyRelation: true, Scope: model.Relation_type, }, + RelationKeySpaceInvitePermissions: { + + DataSource: model.Relation_details, + Description: "Invite permissions. Possible values: models.ParticipantPermissions", + Format: model.RelationFormat_number, + Hidden: true, + Id: "_brspaceInvitePermissions", + Key: "spaceInvitePermissions", + MaxCount: 1, + Name: "Invite permissions", + ReadOnly: true, + ReadOnlyRelation: true, + Scope: model.Relation_type, + }, + RelationKeySpaceInviteType: { + + DataSource: model.Relation_details, + Description: "Encoded encryption key of invite file for current space. It stored in SpaceView", + Format: model.RelationFormat_number, + Hidden: true, + Id: "_brspaceInviteType", + Key: "spaceInviteType", + MaxCount: 1, + Name: "Invite type of space", + ReadOnly: true, + ReadOnlyRelation: true, + Scope: model.Relation_type, + }, RelationKeySpaceLocalStatus: { DataSource: model.Relation_derived, diff --git a/pkg/lib/bundle/relations.json b/pkg/lib/bundle/relations.json index 72b706ada..ddef9444b 100644 --- a/pkg/lib/bundle/relations.json +++ b/pkg/lib/bundle/relations.json @@ -1198,6 +1198,16 @@ "readonly": true, "source": "details" }, + { + "description": "Encoded encryption key of invite file for current space. It stored in SpaceView", + "format": "number", + "hidden": true, + "key": "spaceInviteType", + "maxCount": 1, + "name": "Invite type of space", + "readonly": true, + "source": "details" + }, { "description": "CID of invite file for for guest user in the current space. It's stored in SpaceView", "format": "shorttext", @@ -1238,6 +1248,16 @@ "readonly": true, "source": "details" }, + { + "description": "Invite permissions. Possible values: models.ParticipantPermissions", + "format": "number", + "hidden": true, + "key": "spaceInvitePermissions", + "maxCount": 1, + "name": "Invite permissions", + "readonly": true, + "source": "details" + }, { "description": "Identity", "format": "longtext", @@ -1553,6 +1573,26 @@ "readonly": false, "source": "details" }, + { + "description": "Layout of header relations. Line or column", + "format": "number", + "hidden": true, + "key": "headerRelationsLayout", + "maxCount": 1, + "name": "Header relations layout", + "readonly": false, + "source": "details" + }, + { + "description": "Identifier to use in intergrations with Anytype API", + "format": "longtext", + "hidden": true, + "key": "apiObjectKey", + "maxCount": 1, + "name": "API Object Key", + "readonly": false, + "source": "details" + }, { "description": "Should time be shown for relation values with date format", "format": "checkbox", diff --git a/pkg/lib/bundle/systemRelations.gen.go b/pkg/lib/bundle/systemRelations.gen.go index 0d39d3299..49760d9aa 100644 --- a/pkg/lib/bundle/systemRelations.gen.go +++ b/pkg/lib/bundle/systemRelations.gen.go @@ -6,7 +6,7 @@ package bundle import domain "github.com/anyproto/anytype-heart/core/domain" -const SystemRelationsChecksum = "b4130174711023e6d6e5a235a0a2e89b6d266753029ee41b9767b2c4fbb7d124" +const SystemRelationsChecksum = "af284797af811e6407b681c954b49703ced09dc457560f7717b1bece1894e97f" // SystemRelations contains relations that have some special biz logic depends on them in some objects // in case EVERY object depend on the relation please add it to RequiredInternalRelations @@ -70,6 +70,8 @@ var SystemRelations = append(RequiredInternalRelations, []domain.RelationKey{ RelationKeySpaceAccessType, RelationKeySpaceInviteFileCid, RelationKeySpaceInviteFileKey, + RelationKeySpaceInviteType, + RelationKeySpaceInvitePermissions, RelationKeyReadersLimit, RelationKeyWritersLimit, RelationKeySharedSpacesLimit, diff --git a/pkg/lib/bundle/systemRelations.json b/pkg/lib/bundle/systemRelations.json index 947784ee7..fed17e523 100644 --- a/pkg/lib/bundle/systemRelations.json +++ b/pkg/lib/bundle/systemRelations.json @@ -75,6 +75,8 @@ "spaceAccessType", "spaceInviteFileCid", "spaceInviteFileKey", + "spaceInviteType", + "spaceInvitePermissions", "readersLimit", "writersLimit", "sharedSpacesLimit", diff --git a/pkg/lib/gateway/gateway.go b/pkg/lib/gateway/gateway.go index b1ba13762..daf47cc35 100644 --- a/pkg/lib/gateway/gateway.go +++ b/pkg/lib/gateway/gateway.go @@ -21,7 +21,6 @@ import ( "github.com/anyproto/anytype-heart/core/domain" "github.com/anyproto/anytype-heart/core/files" "github.com/anyproto/anytype-heart/core/files/fileobject" - "github.com/anyproto/anytype-heart/pb" "github.com/anyproto/anytype-heart/pkg/lib/logging" "github.com/anyproto/anytype-heart/util/constant" "github.com/anyproto/anytype-heart/util/svg" @@ -130,10 +129,10 @@ func (g *gateway) Addr() string { } func (g *gateway) StateChange(state int) { - switch pb.RpcAppSetDeviceStateRequestDeviceState(state) { - case pb.RpcAppSetDeviceStateRequest_FOREGROUND: + switch domain.CompState(state) { + case domain.CompStateAppWentForeground: g.startServer() - case pb.RpcAppSetDeviceStateRequest_BACKGROUND: + case domain.CompStateAppWentBackground, domain.CompStateAppClosingInitiated: if err := g.stopServer(); err != nil { log.Errorf("err gateway close: %+v", err) } diff --git a/pkg/lib/localstore/ftsearch/ftsearch.go b/pkg/lib/localstore/ftsearch/ftsearch.go index c2e86d67d..39d7d82f0 100644 --- a/pkg/lib/localstore/ftsearch/ftsearch.go +++ b/pkg/lib/localstore/ftsearch/ftsearch.go @@ -16,11 +16,13 @@ package ftsearch import "C" import ( "context" + "errors" "fmt" "os" "path/filepath" "strings" "sync" + "sync/atomic" "time" "unicode" @@ -29,9 +31,11 @@ import ( tantivy "github.com/anyproto/tantivy-go" "github.com/valyala/fastjson" + "github.com/anyproto/anytype-heart/core/domain" "github.com/anyproto/anytype-heart/core/wallet" "github.com/anyproto/anytype-heart/metrics" "github.com/anyproto/anytype-heart/pkg/lib/bundle" + "github.com/anyproto/anytype-heart/pkg/lib/localstore/ftsearch/tantivycheck" "github.com/anyproto/anytype-heart/pkg/lib/logging" "github.com/anyproto/anytype-heart/util/text" ) @@ -40,7 +44,7 @@ const ( CName = "fts" ftsDir = "fts" ftsDir2 = "fts_tantivy" - ftsVer = "13" + ftsVer = "14" docLimit = 10000 fieldTitle = "Title" @@ -57,7 +61,10 @@ const ( tokenizerId = "SimpleIdTokenizer" ) -var log = logging.Logger("ftsearch") +var ( + log = logging.Logger("ftsearch") + ErrAppClosingInitiated = errors.New("app closing initiated") +) type FTSearch interface { app.ComponentRunnable @@ -93,14 +100,15 @@ type DocumentMatch struct { } type ftSearch struct { - rootPath string - ftsPath string - builderId string - index *tantivy.TantivyContext - parserPool *fastjson.ParserPool - mu sync.Mutex - blevePath string - lang tantivy.Language + rootPath string + ftsPath string + builderId string + index *tantivy.TantivyContext + parserPool *fastjson.ParserPool + mu sync.Mutex + blevePath string + lang tantivy.Language + appClosingInitiated atomic.Bool } func (f *ftSearch) ProvideStat() any { @@ -126,6 +134,9 @@ func (f *ftSearch) BatchDeleteObjects(ids []string) error { } f.mu.Lock() defer f.mu.Unlock() + if f.appClosingInitiated.Load() { + return ErrAppClosingInitiated + } start := time.Now() defer func() { spentMs := time.Since(start).Milliseconds() @@ -147,6 +158,9 @@ func (f *ftSearch) BatchDeleteObjects(ids []string) error { func (f *ftSearch) DeleteObject(objectId string) error { f.mu.Lock() defer f.mu.Unlock() + if f.appClosingInitiated.Load() { + return ErrAppClosingInitiated + } return f.index.DeleteDocuments(fieldIdRaw, objectId) } @@ -182,6 +196,24 @@ func (f *ftSearch) Name() (name string) { } func (f *ftSearch) Run(context.Context) error { + report, err := tantivycheck.Check(f.ftsPath) + if err != nil { + if !errors.Is(err, os.ErrNotExist) { + log.Warnf("tantivy index checking failed: %v", err) + } + } + if !report.IsOk() { + log.With("missingSegments", len(report.MissingSegments)). + With("missingDelFiles", len(report.MissingDelFiles)). + With("extraSegments", len(report.ExtraSegments)). + With("extraDelFiles", len(report.ExtraDelFiles)). + With("writerLockPresent", report.WriterLockPresent). + With("metaLockPresent", report.MetaLockPresent). + With("totalSegmentsInMeta", report.TotalSegmentsInMeta). + With("uniqueSegmentPrefixesOnDisk", report.UniqueSegmentPrefixesOnDisk). + Warnf("tantivy index is inconsistent state, dry run") + } + builder, err := tantivy.NewSchemaBuilder() if err != nil { return err @@ -328,6 +360,9 @@ func (f *ftSearch) tryToBuildSchema(schema *tantivy.Schema) (*tantivy.TantivyCon func (f *ftSearch) Index(doc SearchDoc) error { f.mu.Lock() defer f.mu.Unlock() + if f.appClosingInitiated.Load() { + return ErrAppClosingInitiated + } metrics.ObjectFTUpdatedCounter.Inc() tantivyDoc, err := f.convertDoc(doc) if err != nil { @@ -375,6 +410,9 @@ func (f *ftSearch) BatchIndex(ctx context.Context, docs []SearchDoc, deletedDocs } }() f.mu.Lock() + if f.appClosingInitiated.Load() { + return ErrAppClosingInitiated + } err = f.index.DeleteDocuments(fieldIdRaw, deletedDocs...) f.mu.Unlock() if err != nil { @@ -390,6 +428,9 @@ func (f *ftSearch) BatchIndex(ctx context.Context, docs []SearchDoc, deletedDocs } f.mu.Lock() defer f.mu.Unlock() + if f.appClosingInitiated.Load() { + return ErrAppClosingInitiated + } return f.index.AddAndConsumeDocuments(tantivyDocs...) } @@ -572,8 +613,10 @@ func (f *ftSearch) DocCount() (uint64, error) { func (f *ftSearch) Close(ctx context.Context) error { if f.index != nil { - f.index.Free() - f.index = nil + err := f.index.Close() + if err != nil { + log.Errorf("failed to close tantivy index: %v", err) + } } return nil } @@ -582,6 +625,12 @@ func (f *ftSearch) cleanupBleve() { _ = os.RemoveAll(f.blevePath) } +func (f *ftSearch) StateChange(state int) { + if state == int(domain.CompStateAppClosingInitiated) { + f.appClosingInitiated.Store(true) + } +} + func prepareQuery(query string) string { query = text.Truncate(query, 100, "") query = strings.ToLower(query) diff --git a/pkg/lib/localstore/ftsearch/tantivycheck/tantivycheck.go b/pkg/lib/localstore/ftsearch/tantivycheck/tantivycheck.go new file mode 100644 index 000000000..97fa3825d --- /dev/null +++ b/pkg/lib/localstore/ftsearch/tantivycheck/tantivycheck.go @@ -0,0 +1,230 @@ +// Package tantivycheck provides a DRY-RUN consistency check for Tantivy index +// directories. +// +// It verifies that +// +// - every segment listed in meta.json has files on disk +// - every expected ..del file exists +// - there are no extra segment prefixes on disk +// - there are no extra .del files on disk +// - the special lock files INDEX_WRITER_LOCK and META_LOCK are noted +// +// Nothing is modified on disk; you simply get a ConsistencyReport back. +package tantivycheck + +import ( + "encoding/json" + "fmt" + "io/fs" + "os" + "path/filepath" + "regexp" + "strconv" +) + +// ----------------------------------------------------------------------------- +// Package-level helpers (compiled once) +// ----------------------------------------------------------------------------- + +var ( + segPrefixRe = regexp.MustCompile(`^([0-9a-f]{32})(?:\..+)?$`) + delFileRe = regexp.MustCompile(`^([0-9a-f]{32})\.(\d+)\.del$`) +) + +// ----------------------------------------------------------------------------- +// Public API +// ----------------------------------------------------------------------------- + +// ConsistencyReport gathers all findings of the dry-run. +type ConsistencyReport struct { + // Segments present in meta.json but with no files on disk. + MissingSegments []string + // ..del files that meta.json expects but are absent. + MissingDelFiles []string + // Segment prefixes that exist on disk but are not referenced in meta.json. + ExtraSegments []string + // .del files on disk that are not referenced (wrong opstamp or orphan). + ExtraDelFiles []string + + // Lock-file information + WriterLockPresent bool // true if INDEX_WRITER_LOCK exists + MetaLockPresent bool // true if META_LOCK exists + + // Informational counters + TotalSegmentsInMeta int + UniqueSegmentPrefixesOnDisk int +} + +// Check runs the consistency test against dir and returns a report. +// +// It fails with an error if meta.json is absent or can’t be decoded. +func Check(dir string) (ConsistencyReport, error) { + // --------------------------------------------------------------------- + // 1) Parse meta.json + // --------------------------------------------------------------------- + meta, err := readMeta(filepath.Join(dir, "meta.json")) + if err != nil { + return ConsistencyReport{}, err + } + + // Build metaSegments: 32-hex-id (no dashes) → expected opstamp (nil if none) + metaSegments := make(map[string]*uint64, len(meta.Segments)) + for _, s := range meta.Segments { + id := stripDashes(s.SegmentID) + if s.Deletes != nil { + metaSegments[id] = &s.Deletes.Opstamp + } else { + metaSegments[id] = nil + } + } + + // --------------------------------------------------------------------- + // 2) Walk directory once + // --------------------------------------------------------------------- + segmentPrefixesDisk := map[string]struct{}{} + delFilesDisk := map[[2]string]struct{}{} // key = [segPrefix, opstamp] + + var writerLockPresent, metaLockPresent bool + + err = filepath.WalkDir(dir, func(path string, d fs.DirEntry, walkErr error) error { + if walkErr != nil { + return walkErr + } + if d.IsDir() { + return nil + } + + name := d.Name() + + switch name { + case "INDEX_WRITER_LOCK": + writerLockPresent = true + case "META_LOCK": + metaLockPresent = true + } + + if m := segPrefixRe.FindStringSubmatch(name); m != nil { + segmentPrefixesDisk[m[1]] = struct{}{} + } + if m := delFileRe.FindStringSubmatch(name); m != nil { + delFilesDisk[[2]string{m[1], m[2]}] = struct{}{} + } + return nil + }) + if err != nil { + return ConsistencyReport{}, fmt.Errorf("scanning directory: %w", err) + } + + // --------------------------------------------------------------------- + // 3) Compare sets + // --------------------------------------------------------------------- + var ( + missingSegments []string + extraSegments []string + missingDelFiles []string + extraDelFiles []string + ) + + // missing segments + for id := range metaSegments { + if _, ok := segmentPrefixesDisk[id]; !ok { + missingSegments = append(missingSegments, id) + } + } + + // extra segments + for id := range segmentPrefixesDisk { + if _, ok := metaSegments[id]; !ok { + extraSegments = append(extraSegments, id) + } + } + + // missing del files + for id, opPtr := range metaSegments { + if opPtr == nil { + continue // no deletes expected + } + opStr := strconv.FormatUint(*opPtr, 10) + if _, ok := delFilesDisk[[2]string{id, opStr}]; !ok { + missingDelFiles = append(missingDelFiles, fmt.Sprintf("%s.%s.del", id, opStr)) + } + } + + // extra del files + for key := range delFilesDisk { + id, opStr := key[0], key[1] + expectedOpPtr, segKnown := metaSegments[id] + if !segKnown || expectedOpPtr == nil || strconv.FormatUint(*expectedOpPtr, 10) != opStr { + extraDelFiles = append(extraDelFiles, fmt.Sprintf("%s.%s.del", id, opStr)) + } + } + + // --------------------------------------------------------------------- + // 4) Return aggregated report + // --------------------------------------------------------------------- + return ConsistencyReport{ + MissingSegments: missingSegments, + MissingDelFiles: missingDelFiles, + ExtraSegments: extraSegments, + ExtraDelFiles: extraDelFiles, + WriterLockPresent: writerLockPresent, + MetaLockPresent: metaLockPresent, + TotalSegmentsInMeta: len(metaSegments), + UniqueSegmentPrefixesOnDisk: len(segmentPrefixesDisk), + }, nil +} + +// IsOk returns true when the report is free of inconsistencies: +// +// - no segments are missing +// - no .del files are missing +// - no extra segments are present +// - no extra .del files are present +// +// The presence of INDEX_WRITER_LOCK or META_LOCK is *not* considered +// an inconsistency—these files are expected during normal operation and +// merely reported for information. +func (r *ConsistencyReport) IsOk() bool { + return len(r.MissingSegments) == 0 && + len(r.MissingDelFiles) == 0 && + len(r.ExtraSegments) == 0 && + len(r.ExtraDelFiles) == 0 && + !r.WriterLockPresent && + !r.MetaLockPresent +} + +// ----------------------------------------------------------------------------- +// Internal helpers +// ----------------------------------------------------------------------------- + +// metaFile mirrors only the parts of meta.json we need. +type metaFile struct { + Segments []struct { + SegmentID string `json:"segment_id"` + Deletes *struct { + Opstamp uint64 `json:"opstamp"` + } `json:"deletes"` + } `json:"segments"` +} + +func readMeta(path string) (*metaFile, error) { + b, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("reading %s: %w", path, err) + } + var m metaFile + if err := json.Unmarshal(b, &m); err != nil { + return nil, fmt.Errorf("decoding meta.json: %w", err) + } + return &m, nil +} + +func stripDashes(s string) string { + out := make([]byte, 0, len(s)) + for i := 0; i < len(s); i++ { + if s[i] != '-' { + out = append(out, s[i]) + } + } + return string(out) +} diff --git a/pkg/lib/localstore/objectstore/fixture.go b/pkg/lib/localstore/objectstore/fixture.go index 7cab5efe6..703a924dd 100644 --- a/pkg/lib/localstore/objectstore/fixture.go +++ b/pkg/lib/localstore/objectstore/fixture.go @@ -107,6 +107,7 @@ func NewStoreFixture(t testing.TB) *StoreFixture { spaceIndexes: map[string]spaceindex.Store{}, techSpaceIdProvider: &stubTechSpaceIdProvider{}, subManager: &spaceindex.SubscriptionManager{}, + crdtDbs: map[string]*AnystoreGetter{}, } t.Cleanup(func() { diff --git a/pkg/lib/localstore/objectstore/service.go b/pkg/lib/localstore/objectstore/service.go index 7af388932..020eada23 100644 --- a/pkg/lib/localstore/objectstore/service.go +++ b/pkg/lib/localstore/objectstore/service.go @@ -54,7 +54,7 @@ type ObjectStore interface { IterateSpaceIndex(func(store spaceindex.Store) error) error SpaceIndex(spaceId string) spaceindex.Store - GetCrdtDb(spaceId string) anystore.DB + GetCrdtDb(spaceId string) *AnystoreGetter SpaceNameGetter spaceresolverstore.Store @@ -120,7 +120,7 @@ type dsObjectStore struct { spaceStoreDirsCheck sync.Once crtdStoreLock sync.Mutex - crdtDbs map[string]anystore.DB + crdtDbs map[string]*AnystoreGetter componentCtx context.Context componentCtxCancel context.CancelFunc @@ -161,7 +161,7 @@ func New() ObjectStore { componentCtxCancel: cancel, subManager: &spaceindex.SubscriptionManager{}, spaceIndexes: map[string]spaceindex.Store{}, - crdtDbs: map[string]anystore.DB{}, + crdtDbs: map[string]*AnystoreGetter{}, } } @@ -328,15 +328,17 @@ func (s *dsObjectStore) Close(_ context.Context) (err error) { s.crtdStoreLock.Lock() closeChan = make(chan error, len(s.crdtDbs)) - for spaceId, store := range s.crdtDbs { + for spaceId, storeGetter := range s.crdtDbs { go func(spaceId string, store anystore.DB) { - closeChan <- store.Close() - }(spaceId, store) + if store != nil { + closeChan <- store.Close() + } + }(spaceId, storeGetter.Get()) } for i := 0; i < len(s.crdtDbs); i++ { err = errors.Join(err, <-closeChan) } - s.crdtDbs = map[string]anystore.DB{} + s.crdtDbs = map[string]*AnystoreGetter{} s.crtdStoreLock.Unlock() return err @@ -389,28 +391,66 @@ func (s *dsObjectStore) getAnyStoreConfig() *anystore.Config { } } -func (s *dsObjectStore) GetCrdtDb(spaceId string) anystore.DB { +type AnystoreGetter struct { + ctx context.Context + config *anystore.Config + objectStorePath string + spaceId string + + lock sync.Mutex + db anystore.DB +} + +func (g *AnystoreGetter) Get() anystore.DB { + g.lock.Lock() + defer g.lock.Unlock() + + return g.db +} + +func (g *AnystoreGetter) Wait() (anystore.DB, error) { + g.lock.Lock() + defer g.lock.Unlock() + + if g.db != nil { + return g.db, nil + } + + dir := filepath.Join(g.objectStorePath, g.spaceId) + err := ensureDirExists(dir) + if err != nil { + return nil, fmt.Errorf("ensure dir exists: %w", err) + } + path := filepath.Join(dir, "crdt.db") + db, err := anystore.Open(g.ctx, path, g.config) + if errors.Is(err, anystore.ErrIncompatibleVersion) { + _ = os.RemoveAll(path) + db, err = anystore.Open(g.ctx, path, g.config) + } + if err != nil { + return nil, fmt.Errorf("open: %w", err) + } + g.db = db + + return db, nil +} + +func (s *dsObjectStore) GetCrdtDb(spaceId string) *AnystoreGetter { s.crtdStoreLock.Lock() defer s.crtdStoreLock.Unlock() db, ok := s.crdtDbs[spaceId] - if !ok { - dir := filepath.Join(s.objectStorePath, spaceId) - err := ensureDirExists(dir) - if err != nil { - return nil - } - path := filepath.Join(dir, "crdt.db") - db, err = anystore.Open(s.componentCtx, path, s.getAnyStoreConfig()) - if errors.Is(err, anystore.ErrIncompatibleVersion) { - _ = os.RemoveAll(path) - db, err = anystore.Open(s.componentCtx, path, s.getAnyStoreConfig()) - } - if err != nil { - return nil - } - s.crdtDbs[spaceId] = db + if ok { + return db } + + db = &AnystoreGetter{ + spaceId: spaceId, + ctx: s.componentCtx, + config: s.getAnyStoreConfig(), + objectStorePath: s.objectStorePath, + } + s.crdtDbs[spaceId] = db return db } diff --git a/pkg/lib/pb/model/models.pb.go b/pkg/lib/pb/model/models.pb.go index 794c45201..436f2949c 100644 --- a/pkg/lib/pb/model/models.pb.go +++ b/pkg/lib/pb/model/models.pb.go @@ -331,6 +331,34 @@ func (ParticipantPermissions) EnumDescriptor() ([]byte, []int) { return fileDescriptor_98a910b73321e591, []int{4} } +type InviteType int32 + +const ( + InviteType_Member InviteType = 0 + InviteType_Guest InviteType = 1 + InviteType_WithoutApprove InviteType = 2 +) + +var InviteType_name = map[int32]string{ + 0: "Member", + 1: "Guest", + 2: "WithoutApprove", +} + +var InviteType_value = map[string]int32{ + "Member": 0, + "Guest": 1, + "WithoutApprove": 2, +} + +func (x InviteType) String() string { + return proto.EnumName(InviteType_name, int32(x)) +} + +func (InviteType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_98a910b73321e591, []int{5} +} + type ParticipantStatus int32 const ( @@ -365,7 +393,7 @@ func (x ParticipantStatus) String() string { } func (ParticipantStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_98a910b73321e591, []int{5} + return fileDescriptor_98a910b73321e591, []int{6} } type SpaceAccessType int32 @@ -393,7 +421,7 @@ func (x SpaceAccessType) String() string { } func (SpaceAccessType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_98a910b73321e591, []int{6} + return fileDescriptor_98a910b73321e591, []int{7} } type SpaceUxType int32 @@ -421,7 +449,7 @@ func (x SpaceUxType) String() string { } func (SpaceUxType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_98a910b73321e591, []int{7} + return fileDescriptor_98a910b73321e591, []int{8} } type ImageKind int32 @@ -452,7 +480,7 @@ func (x ImageKind) String() string { } func (ImageKind) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_98a910b73321e591, []int{8} + return fileDescriptor_98a910b73321e591, []int{9} } type FileIndexingStatus int32 @@ -480,7 +508,7 @@ func (x FileIndexingStatus) String() string { } func (FileIndexingStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_98a910b73321e591, []int{9} + return fileDescriptor_98a910b73321e591, []int{10} } type SpaceShareableStatus int32 @@ -508,7 +536,7 @@ func (x SpaceShareableStatus) String() string { } func (SpaceShareableStatus) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_98a910b73321e591, []int{10} + return fileDescriptor_98a910b73321e591, []int{11} } type NameserviceNameType int32 @@ -531,7 +559,7 @@ func (x NameserviceNameType) String() string { } func (NameserviceNameType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_98a910b73321e591, []int{11} + return fileDescriptor_98a910b73321e591, []int{12} } type DeviceNetworkType int32 @@ -559,7 +587,7 @@ func (x DeviceNetworkType) String() string { } func (DeviceNetworkType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_98a910b73321e591, []int{12} + return fileDescriptor_98a910b73321e591, []int{13} } type BlockPosition int32 @@ -2201,31 +2229,6 @@ func (ImportErrorCode) EnumDescriptor() ([]byte, []int) { return fileDescriptor_98a910b73321e591, []int{23, 1} } -type InvitePayloadInviteType int32 - -const ( - InvitePayload_JoinAsMember InvitePayloadInviteType = 0 - InvitePayload_JoinAsGuest InvitePayloadInviteType = 1 -) - -var InvitePayloadInviteType_name = map[int32]string{ - 0: "JoinAsMember", - 1: "JoinAsGuest", -} - -var InvitePayloadInviteType_value = map[string]int32{ - "JoinAsMember": 0, - "JoinAsGuest": 1, -} - -func (x InvitePayloadInviteType) String() string { - return proto.EnumName(InvitePayloadInviteType_name, int32(x)) -} - -func (InvitePayloadInviteType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_98a910b73321e591, []int{25, 0} -} - type MembershipStatus int32 const ( @@ -3993,6 +3996,7 @@ type BlockContentDataviewView struct { PageLimit int32 `protobuf:"varint,13,opt,name=pageLimit,proto3" json:"pageLimit,omitempty"` DefaultTemplateId string `protobuf:"bytes,14,opt,name=defaultTemplateId,proto3" json:"defaultTemplateId,omitempty"` DefaultObjectTypeId string `protobuf:"bytes,15,opt,name=defaultObjectTypeId,proto3" json:"defaultObjectTypeId,omitempty"` + EndRelationKey string `protobuf:"bytes,16,opt,name=endRelationKey,proto3" json:"endRelationKey,omitempty"` } func (m *BlockContentDataviewView) Reset() { *m = BlockContentDataviewView{} } @@ -4133,6 +4137,13 @@ func (m *BlockContentDataviewView) GetDefaultObjectTypeId() string { return "" } +func (m *BlockContentDataviewView) GetEndRelationKey() string { + if m != nil { + return m.EndRelationKey + } + return "" +} + type BlockContentDataviewRelation struct { Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` IsVisible bool `protobuf:"varint,2,opt,name=isVisible,proto3" json:"isVisible,omitempty"` @@ -5774,6 +5785,98 @@ func (m *AccountAuth) XXX_DiscardUnknown() { var xxx_messageInfo_AccountAuth proto.InternalMessageInfo +type AccountAuthAppInfo struct { + AppHash string `protobuf:"bytes,1,opt,name=appHash,proto3" json:"appHash,omitempty"` + AppName string `protobuf:"bytes,2,opt,name=appName,proto3" json:"appName,omitempty"` + AppKey string `protobuf:"bytes,4,opt,name=appKey,proto3" json:"appKey,omitempty"` + CreatedAt int64 `protobuf:"varint,5,opt,name=createdAt,proto3" json:"createdAt,omitempty"` + ExpireAt int64 `protobuf:"varint,6,opt,name=expireAt,proto3" json:"expireAt,omitempty"` + Scope AccountAuthLocalApiScope `protobuf:"varint,7,opt,name=scope,proto3,enum=anytype.model.AccountAuthLocalApiScope" json:"scope,omitempty"` + IsActive bool `protobuf:"varint,8,opt,name=isActive,proto3" json:"isActive,omitempty"` +} + +func (m *AccountAuthAppInfo) Reset() { *m = AccountAuthAppInfo{} } +func (m *AccountAuthAppInfo) String() string { return proto.CompactTextString(m) } +func (*AccountAuthAppInfo) ProtoMessage() {} +func (*AccountAuthAppInfo) Descriptor() ([]byte, []int) { + return fileDescriptor_98a910b73321e591, []int{5, 3, 0} +} +func (m *AccountAuthAppInfo) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AccountAuthAppInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AccountAuthAppInfo.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AccountAuthAppInfo) XXX_Merge(src proto.Message) { + xxx_messageInfo_AccountAuthAppInfo.Merge(m, src) +} +func (m *AccountAuthAppInfo) XXX_Size() int { + return m.Size() +} +func (m *AccountAuthAppInfo) XXX_DiscardUnknown() { + xxx_messageInfo_AccountAuthAppInfo.DiscardUnknown(m) +} + +var xxx_messageInfo_AccountAuthAppInfo proto.InternalMessageInfo + +func (m *AccountAuthAppInfo) GetAppHash() string { + if m != nil { + return m.AppHash + } + return "" +} + +func (m *AccountAuthAppInfo) GetAppName() string { + if m != nil { + return m.AppName + } + return "" +} + +func (m *AccountAuthAppInfo) GetAppKey() string { + if m != nil { + return m.AppKey + } + return "" +} + +func (m *AccountAuthAppInfo) GetCreatedAt() int64 { + if m != nil { + return m.CreatedAt + } + return 0 +} + +func (m *AccountAuthAppInfo) GetExpireAt() int64 { + if m != nil { + return m.ExpireAt + } + return 0 +} + +func (m *AccountAuthAppInfo) GetScope() AccountAuthLocalApiScope { + if m != nil { + return m.Scope + } + return AccountAuth_Limited +} + +func (m *AccountAuthAppInfo) GetIsActive() bool { + if m != nil { + return m.IsActive + } + return false +} + type LinkPreview struct { Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"` Title string `protobuf:"bytes,2,opt,name=title,proto3" json:"title,omitempty"` @@ -8370,15 +8473,15 @@ func (m *Invite) GetSignature() []byte { } type InvitePayload struct { - CreatorIdentity string `protobuf:"bytes,1,opt,name=creatorIdentity,proto3" json:"creatorIdentity,omitempty"` - CreatorName string `protobuf:"bytes,2,opt,name=creatorName,proto3" json:"creatorName,omitempty"` - AclKey []byte `protobuf:"bytes,3,opt,name=aclKey,proto3" json:"aclKey,omitempty"` - SpaceId string `protobuf:"bytes,4,opt,name=spaceId,proto3" json:"spaceId,omitempty"` - SpaceName string `protobuf:"bytes,5,opt,name=spaceName,proto3" json:"spaceName,omitempty"` - SpaceIconCid string `protobuf:"bytes,6,opt,name=spaceIconCid,proto3" json:"spaceIconCid,omitempty"` - SpaceIconEncryptionKeys []*FileEncryptionKey `protobuf:"bytes,7,rep,name=spaceIconEncryptionKeys,proto3" json:"spaceIconEncryptionKeys,omitempty"` - InviteType InvitePayloadInviteType `protobuf:"varint,8,opt,name=inviteType,proto3,enum=anytype.model.InvitePayloadInviteType" json:"inviteType,omitempty"` - GuestKey []byte `protobuf:"bytes,9,opt,name=guestKey,proto3" json:"guestKey,omitempty"` + CreatorIdentity string `protobuf:"bytes,1,opt,name=creatorIdentity,proto3" json:"creatorIdentity,omitempty"` + CreatorName string `protobuf:"bytes,2,opt,name=creatorName,proto3" json:"creatorName,omitempty"` + AclKey []byte `protobuf:"bytes,3,opt,name=aclKey,proto3" json:"aclKey,omitempty"` + SpaceId string `protobuf:"bytes,4,opt,name=spaceId,proto3" json:"spaceId,omitempty"` + SpaceName string `protobuf:"bytes,5,opt,name=spaceName,proto3" json:"spaceName,omitempty"` + SpaceIconCid string `protobuf:"bytes,6,opt,name=spaceIconCid,proto3" json:"spaceIconCid,omitempty"` + SpaceIconEncryptionKeys []*FileEncryptionKey `protobuf:"bytes,7,rep,name=spaceIconEncryptionKeys,proto3" json:"spaceIconEncryptionKeys,omitempty"` + InviteType InviteType `protobuf:"varint,8,opt,name=inviteType,proto3,enum=anytype.model.InviteType" json:"inviteType,omitempty"` + GuestKey []byte `protobuf:"bytes,9,opt,name=guestKey,proto3" json:"guestKey,omitempty"` } func (m *InvitePayload) Reset() { *m = InvitePayload{} } @@ -8463,11 +8566,11 @@ func (m *InvitePayload) GetSpaceIconEncryptionKeys() []*FileEncryptionKey { return nil } -func (m *InvitePayload) GetInviteType() InvitePayloadInviteType { +func (m *InvitePayload) GetInviteType() InviteType { if m != nil { return m.InviteType } - return InvitePayload_JoinAsMember + return InviteType_Member } func (m *InvitePayload) GetGuestKey() []byte { @@ -9692,6 +9795,7 @@ func init() { proto.RegisterEnum("anytype.model.ObjectOrigin", ObjectOrigin_name, ObjectOrigin_value) proto.RegisterEnum("anytype.model.SpaceStatus", SpaceStatus_name, SpaceStatus_value) proto.RegisterEnum("anytype.model.ParticipantPermissions", ParticipantPermissions_name, ParticipantPermissions_value) + proto.RegisterEnum("anytype.model.InviteType", InviteType_name, InviteType_value) proto.RegisterEnum("anytype.model.ParticipantStatus", ParticipantStatus_name, ParticipantStatus_value) proto.RegisterEnum("anytype.model.SpaceAccessType", SpaceAccessType_name, SpaceAccessType_value) proto.RegisterEnum("anytype.model.SpaceUxType", SpaceUxType_name, SpaceUxType_value) @@ -9742,7 +9846,6 @@ func init() { proto.RegisterEnum("anytype.model.ExportFormat", ExportFormat_name, ExportFormat_value) proto.RegisterEnum("anytype.model.ImportType", ImportType_name, ImportType_value) proto.RegisterEnum("anytype.model.ImportErrorCode", ImportErrorCode_name, ImportErrorCode_value) - proto.RegisterEnum("anytype.model.InvitePayloadInviteType", InvitePayloadInviteType_name, InvitePayloadInviteType_value) proto.RegisterEnum("anytype.model.MembershipStatus", MembershipStatus_name, MembershipStatus_value) proto.RegisterEnum("anytype.model.MembershipPaymentMethod", MembershipPaymentMethod_name, MembershipPaymentMethod_value) proto.RegisterEnum("anytype.model.MembershipEmailVerificationStatus", MembershipEmailVerificationStatus_name, MembershipEmailVerificationStatus_value) @@ -9794,6 +9897,7 @@ func init() { proto.RegisterType((*AccountStatus)(nil), "anytype.model.Account.Status") proto.RegisterType((*AccountInfo)(nil), "anytype.model.Account.Info") proto.RegisterType((*AccountAuth)(nil), "anytype.model.Account.Auth") + proto.RegisterType((*AccountAuthAppInfo)(nil), "anytype.model.Account.Auth.AppInfo") proto.RegisterType((*LinkPreview)(nil), "anytype.model.LinkPreview") proto.RegisterType((*Restrictions)(nil), "anytype.model.Restrictions") proto.RegisterType((*RestrictionsDataviewRestrictions)(nil), "anytype.model.Restrictions.DataviewRestrictions") @@ -9856,586 +9960,592 @@ func init() { } var fileDescriptor_98a910b73321e591 = []byte{ - // 9261 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x7d, 0x4b, 0x6c, 0x24, 0xd9, - 0x91, 0x18, 0xeb, 0x5f, 0x15, 0xc5, 0x22, 0x1f, 0x5f, 0xff, 0x4a, 0xa5, 0x56, 0xbb, 0x95, 0x1a, - 0xcd, 0xb4, 0x5a, 0x23, 0xf6, 0x4c, 0xcf, 0x8c, 0x66, 0x34, 0xd2, 0x8c, 0x54, 0x24, 0x8b, 0xcd, - 0x9a, 0xe6, 0x4f, 0x59, 0xd5, 0xdd, 0x9a, 0xc1, 0xae, 0xe9, 0x64, 0xe5, 0x63, 0x55, 0x8a, 0x59, - 0x99, 0xa5, 0xcc, 0x57, 0x6c, 0x52, 0xb0, 0x0d, 0xf9, 0xb7, 0xeb, 0xbd, 0xc9, 0x86, 0xd7, 0xeb, - 0x85, 0x6d, 0xac, 0x74, 0x30, 0x60, 0x78, 0xd7, 0xf0, 0x69, 0x61, 0xaf, 0x3f, 0x80, 0x77, 0x4f, - 0x06, 0xf6, 0x22, 0xfb, 0x64, 0xc0, 0x06, 0x6c, 0x68, 0x00, 0x5f, 0x0c, 0x7b, 0xb1, 0x3e, 0xe9, - 0xe0, 0x83, 0x11, 0xf1, 0x5e, 0x7e, 0xea, 0x43, 0x76, 0xf5, 0xec, 0xae, 0xb1, 0x27, 0x56, 0x44, - 0x46, 0x44, 0xbe, 0x4f, 0xbc, 0x78, 0x11, 0xf1, 0xe2, 0x25, 0xe1, 0x95, 0xd1, 0x69, 0xff, 0x81, - 0xeb, 0x1c, 0x3f, 0x18, 0x1d, 0x3f, 0x18, 0xfa, 0xb6, 0x70, 0x1f, 0x8c, 0x02, 0x5f, 0xfa, 0xa1, - 0x02, 0xc2, 0x75, 0x82, 0x78, 0xcd, 0xf2, 0x2e, 0xe4, 0xc5, 0x48, 0xac, 0x13, 0xb6, 0x71, 0xbb, - 0xef, 0xfb, 0x7d, 0x57, 0x28, 0xd2, 0xe3, 0xf1, 0xc9, 0x83, 0x50, 0x06, 0xe3, 0x9e, 0x54, 0xc4, - 0xc6, 0xcf, 0xf2, 0x70, 0xb3, 0x33, 0xb4, 0x02, 0xb9, 0xe1, 0xfa, 0xbd, 0xd3, 0x8e, 0x67, 0x8d, - 0xc2, 0x81, 0x2f, 0x37, 0xac, 0x50, 0xf0, 0xd7, 0xa1, 0x78, 0x8c, 0xc8, 0xb0, 0x9e, 0xb9, 0x9b, - 0xbb, 0x57, 0x7d, 0x78, 0x7d, 0x7d, 0x42, 0xf0, 0x3a, 0x71, 0x98, 0x9a, 0x86, 0xbf, 0x09, 0x25, - 0x5b, 0x48, 0xcb, 0x71, 0xc3, 0x7a, 0xf6, 0x6e, 0xe6, 0x5e, 0xf5, 0xe1, 0xad, 0x75, 0xf5, 0xe2, - 0xf5, 0xe8, 0xc5, 0xeb, 0x1d, 0x7a, 0xb1, 0x19, 0xd1, 0xf1, 0x77, 0xa1, 0x7c, 0xe2, 0xb8, 0xe2, - 0xb1, 0xb8, 0x08, 0xeb, 0xb9, 0x2b, 0x79, 0x36, 0xb2, 0xf5, 0x8c, 0x19, 0x13, 0xf3, 0x4d, 0x58, - 0x11, 0xe7, 0x32, 0xb0, 0x4c, 0xe1, 0x5a, 0xd2, 0xf1, 0xbd, 0xb0, 0x9e, 0xa7, 0x16, 0xde, 0x9a, - 0x6a, 0x61, 0xf4, 0x9c, 0xd8, 0xa7, 0x58, 0xf8, 0x5d, 0xa8, 0xfa, 0xc7, 0xdf, 0x17, 0x3d, 0xd9, - 0xbd, 0x18, 0x89, 0xb0, 0x5e, 0xb8, 0x9b, 0xbb, 0x57, 0x31, 0xd3, 0x28, 0xfe, 0x0d, 0xa8, 0xf6, - 0x7c, 0xd7, 0x15, 0x3d, 0xf5, 0x8e, 0xe2, 0xd5, 0xdd, 0x4a, 0xd3, 0xf2, 0xb7, 0xe1, 0x46, 0x20, - 0x86, 0xfe, 0x99, 0xb0, 0x37, 0x63, 0x2c, 0xf5, 0xb3, 0x4c, 0xaf, 0x99, 0xff, 0x90, 0x37, 0xa1, - 0x16, 0xe8, 0xf6, 0xed, 0x3a, 0xde, 0x69, 0x58, 0x2f, 0x51, 0xb7, 0x3e, 0x7f, 0x49, 0xb7, 0x90, - 0xc6, 0x9c, 0xe4, 0xe0, 0x0c, 0x72, 0xa7, 0xe2, 0xa2, 0x5e, 0xb9, 0x9b, 0xb9, 0x57, 0x31, 0xf1, - 0x27, 0x7f, 0x1f, 0xea, 0x7e, 0xe0, 0xf4, 0x1d, 0xcf, 0x72, 0x37, 0x03, 0x61, 0x49, 0x61, 0x77, - 0x9d, 0xa1, 0x08, 0xa5, 0x35, 0x1c, 0xd5, 0xe1, 0x6e, 0xe6, 0x5e, 0xce, 0xbc, 0xf4, 0x39, 0x7f, - 0x4b, 0xcd, 0x50, 0xdb, 0x3b, 0xf1, 0xeb, 0x55, 0xdd, 0xfd, 0xc9, 0xb6, 0x6c, 0xeb, 0xc7, 0x66, - 0x4c, 0x68, 0xfc, 0x22, 0x0b, 0xc5, 0x8e, 0xb0, 0x82, 0xde, 0xa0, 0xf1, 0xab, 0x19, 0x28, 0x9a, - 0x22, 0x1c, 0xbb, 0x92, 0x37, 0xa0, 0xac, 0xc6, 0xb6, 0x6d, 0xd7, 0x33, 0xd4, 0xba, 0x18, 0xfe, - 0x2c, 0xba, 0xb3, 0x0e, 0xf9, 0xa1, 0x90, 0x56, 0x3d, 0x47, 0x23, 0xd4, 0x98, 0x6a, 0x95, 0x7a, - 0xfd, 0xfa, 0x9e, 0x90, 0x96, 0x49, 0x74, 0x8d, 0x4f, 0x33, 0x90, 0x47, 0x90, 0xdf, 0x86, 0xca, - 0xc0, 0xe9, 0x0f, 0x5c, 0xa7, 0x3f, 0x90, 0xba, 0x21, 0x09, 0x82, 0x7f, 0x08, 0xab, 0x31, 0x60, - 0x5a, 0x5e, 0x5f, 0x60, 0x8b, 0xe6, 0x29, 0x3f, 0x3d, 0x34, 0xa7, 0x89, 0x79, 0x1d, 0x4a, 0xb4, - 0x1e, 0xda, 0x36, 0x69, 0x74, 0xc5, 0x8c, 0x40, 0x54, 0xb7, 0x68, 0xa6, 0x1e, 0x8b, 0x8b, 0x7a, - 0x9e, 0x9e, 0xa6, 0x51, 0xbc, 0x09, 0xab, 0x11, 0xb8, 0xa5, 0x47, 0xa3, 0x70, 0xf5, 0x68, 0x4c, - 0xd3, 0x1b, 0x3f, 0xda, 0x83, 0x02, 0x2d, 0x4b, 0xbe, 0x02, 0x59, 0x27, 0x1a, 0xe8, 0xac, 0x63, - 0xf3, 0x07, 0x50, 0x3c, 0x71, 0x84, 0x6b, 0xbf, 0x70, 0x84, 0x35, 0x19, 0x6f, 0xc1, 0x72, 0x20, - 0x42, 0x19, 0x38, 0x5a, 0xfb, 0xd5, 0x02, 0xfd, 0xe2, 0x3c, 0x1b, 0xb0, 0x6e, 0xa6, 0x08, 0xcd, - 0x09, 0x36, 0xec, 0x76, 0x6f, 0xe0, 0xb8, 0x76, 0x20, 0xbc, 0xb6, 0xad, 0xd6, 0x69, 0xc5, 0x4c, - 0xa3, 0xf8, 0x3d, 0x58, 0x3d, 0xb6, 0x7a, 0xa7, 0xfd, 0xc0, 0x1f, 0x7b, 0xb8, 0x20, 0xfc, 0x80, - 0xba, 0x5d, 0x31, 0xa7, 0xd1, 0xfc, 0x0d, 0x28, 0x58, 0xae, 0xd3, 0xf7, 0x68, 0x25, 0xae, 0xcc, - 0x4c, 0xba, 0x6a, 0x4b, 0x13, 0x29, 0x4c, 0x45, 0xc8, 0x77, 0xa0, 0x76, 0x26, 0x02, 0xe9, 0xf4, - 0x2c, 0x97, 0xf0, 0xf5, 0x12, 0x71, 0x1a, 0x73, 0x39, 0x9f, 0xa6, 0x29, 0xcd, 0x49, 0x46, 0xde, - 0x06, 0x08, 0xd1, 0x4c, 0xd2, 0x74, 0xea, 0xb5, 0xf0, 0xda, 0x5c, 0x31, 0x9b, 0xbe, 0x27, 0x85, - 0x27, 0xd7, 0x3b, 0x31, 0xf9, 0xce, 0x92, 0x99, 0x62, 0xe6, 0xef, 0x42, 0x5e, 0x8a, 0x73, 0x59, - 0x5f, 0xb9, 0x62, 0x44, 0x23, 0x21, 0x5d, 0x71, 0x2e, 0x77, 0x96, 0x4c, 0x62, 0x40, 0x46, 0x5c, - 0x64, 0xf5, 0xd5, 0x05, 0x18, 0x71, 0x5d, 0x22, 0x23, 0x32, 0xf0, 0x0f, 0xa0, 0xe8, 0x5a, 0x17, - 0xfe, 0x58, 0xd6, 0x19, 0xb1, 0x7e, 0xe9, 0x4a, 0xd6, 0x5d, 0x22, 0xdd, 0x59, 0x32, 0x35, 0x13, - 0x7f, 0x1b, 0x72, 0xb6, 0x73, 0x56, 0x5f, 0x23, 0xde, 0xbb, 0x57, 0xf2, 0x6e, 0x39, 0x67, 0x3b, - 0x4b, 0x26, 0x92, 0xf3, 0x4d, 0x28, 0x1f, 0xfb, 0xfe, 0xe9, 0xd0, 0x0a, 0x4e, 0xeb, 0x9c, 0x58, - 0xbf, 0x7c, 0x25, 0xeb, 0x86, 0x26, 0xde, 0x59, 0x32, 0x63, 0x46, 0xec, 0xb2, 0xd3, 0xf3, 0xbd, - 0xfa, 0xb5, 0x05, 0xba, 0xdc, 0xee, 0xf9, 0x1e, 0x76, 0x19, 0x19, 0x90, 0xd1, 0x75, 0xbc, 0xd3, - 0xfa, 0xf5, 0x05, 0x18, 0xd1, 0x72, 0x22, 0x23, 0x32, 0x60, 0xb3, 0x6d, 0x4b, 0x5a, 0x67, 0x8e, - 0x78, 0x5e, 0xbf, 0xb1, 0x40, 0xb3, 0xb7, 0x34, 0x31, 0x36, 0x3b, 0x62, 0x44, 0x21, 0xd1, 0xd2, - 0xac, 0xdf, 0x5c, 0x40, 0x48, 0x64, 0xd1, 0x51, 0x48, 0xc4, 0xc8, 0xff, 0x22, 0xac, 0x9d, 0x08, - 0x4b, 0x8e, 0x03, 0x61, 0x27, 0x1b, 0xdd, 0x2d, 0x92, 0xb6, 0x7e, 0xf5, 0xdc, 0x4f, 0x73, 0xed, - 0x2c, 0x99, 0xb3, 0xa2, 0xf8, 0xfb, 0x50, 0x70, 0x2d, 0x29, 0xce, 0xeb, 0x75, 0x92, 0x69, 0xbc, - 0x40, 0x29, 0xa4, 0x38, 0xdf, 0x59, 0x32, 0x15, 0x0b, 0xff, 0x1e, 0xac, 0x4a, 0xeb, 0xd8, 0x15, - 0x07, 0x27, 0x9a, 0x20, 0xac, 0x7f, 0x8e, 0xa4, 0xbc, 0x7e, 0xb5, 0x3a, 0x4f, 0xf2, 0xec, 0x2c, - 0x99, 0xd3, 0x62, 0xb0, 0x55, 0x84, 0xaa, 0x37, 0x16, 0x68, 0x15, 0xc9, 0xc3, 0x56, 0x11, 0x0b, - 0xdf, 0x85, 0x2a, 0xfd, 0xd8, 0xf4, 0xdd, 0xf1, 0xd0, 0xab, 0x7f, 0x9e, 0x24, 0xdc, 0x7b, 0xb1, - 0x04, 0x45, 0xbf, 0xb3, 0x64, 0xa6, 0xd9, 0x71, 0x12, 0x09, 0x34, 0xfd, 0xe7, 0xf5, 0xdb, 0x0b, - 0x4c, 0x62, 0x57, 0x13, 0xe3, 0x24, 0x46, 0x8c, 0xb8, 0xf4, 0x9e, 0x3b, 0x76, 0x5f, 0xc8, 0xfa, - 0x17, 0x16, 0x58, 0x7a, 0xcf, 0x88, 0x14, 0x97, 0x9e, 0x62, 0x42, 0x35, 0xee, 0x0d, 0x2c, 0x59, - 0xbf, 0xb3, 0x80, 0x1a, 0x6f, 0x0e, 0x2c, 0xb2, 0x15, 0xc8, 0xd0, 0xf8, 0x21, 0x2c, 0xa7, 0xad, - 0x32, 0xe7, 0x90, 0x0f, 0x84, 0xa5, 0x76, 0x84, 0xb2, 0x49, 0xbf, 0x11, 0x27, 0x6c, 0x47, 0xd2, - 0x8e, 0x50, 0x36, 0xe9, 0x37, 0xbf, 0x09, 0x45, 0xe5, 0x9b, 0x90, 0xc1, 0x2f, 0x9b, 0x1a, 0x42, - 0x5a, 0x3b, 0xb0, 0xfa, 0xb4, 0x6f, 0x95, 0x4d, 0xfa, 0x8d, 0xb4, 0x76, 0xe0, 0x8f, 0x0e, 0x3c, - 0x32, 0xd8, 0x65, 0x53, 0x43, 0x8d, 0x4f, 0x3f, 0x80, 0x92, 0x6e, 0x54, 0xe3, 0x1f, 0x67, 0xa0, - 0xa8, 0x0c, 0x0a, 0xff, 0x36, 0x14, 0x42, 0x79, 0xe1, 0x0a, 0x6a, 0xc3, 0xca, 0xc3, 0xaf, 0x2c, - 0x60, 0x84, 0xd6, 0x3b, 0xc8, 0x60, 0x2a, 0x3e, 0xc3, 0x84, 0x02, 0xc1, 0xbc, 0x04, 0x39, 0xd3, - 0x7f, 0xce, 0x96, 0x38, 0x40, 0x51, 0x4d, 0x16, 0xcb, 0x20, 0x72, 0xcb, 0x39, 0x63, 0x59, 0x44, - 0xee, 0x08, 0xcb, 0x16, 0x01, 0xcb, 0xf1, 0x1a, 0x54, 0xa2, 0x69, 0x09, 0x59, 0x9e, 0x33, 0x58, - 0x4e, 0x4d, 0x78, 0xc8, 0x0a, 0x8d, 0xff, 0x93, 0x87, 0x3c, 0xae, 0x7f, 0xfe, 0x0a, 0xd4, 0xa4, - 0x15, 0xf4, 0x85, 0x72, 0x84, 0x63, 0x27, 0x65, 0x12, 0xc9, 0x3f, 0x88, 0xfa, 0x90, 0xa5, 0x3e, - 0xbc, 0xf6, 0x42, 0xbb, 0x32, 0xd1, 0x83, 0xd4, 0x2e, 0x9c, 0x5b, 0x6c, 0x17, 0xde, 0x86, 0x32, - 0x9a, 0xb3, 0x8e, 0xf3, 0x43, 0x41, 0x43, 0xbf, 0xf2, 0xf0, 0xfe, 0x8b, 0x5f, 0xd9, 0xd6, 0x1c, - 0x66, 0xcc, 0xcb, 0xdb, 0x50, 0xe9, 0x59, 0x81, 0x4d, 0x8d, 0xa1, 0xd9, 0x5a, 0x79, 0xf8, 0xd5, - 0x17, 0x0b, 0xda, 0x8c, 0x58, 0xcc, 0x84, 0x9b, 0x1f, 0x40, 0xd5, 0x16, 0x61, 0x2f, 0x70, 0x46, - 0x64, 0xde, 0xd4, 0x5e, 0xfc, 0xb5, 0x17, 0x0b, 0xdb, 0x4a, 0x98, 0xcc, 0xb4, 0x04, 0xf4, 0xc8, - 0x82, 0xd8, 0xbe, 0x95, 0xc8, 0x41, 0x48, 0x10, 0xc6, 0xbb, 0x50, 0x8e, 0xfa, 0xc3, 0x97, 0xa1, - 0x8c, 0x7f, 0xf7, 0x7d, 0x4f, 0xb0, 0x25, 0x9c, 0x5b, 0x84, 0x3a, 0x43, 0xcb, 0x75, 0x59, 0x86, - 0xaf, 0x00, 0x20, 0xb8, 0x27, 0x6c, 0x67, 0x3c, 0x64, 0x59, 0xe3, 0x9b, 0x91, 0xb6, 0x94, 0x21, - 0x7f, 0x68, 0xf5, 0x91, 0x63, 0x19, 0xca, 0x91, 0xb9, 0x66, 0x19, 0xe4, 0xdf, 0xb2, 0xc2, 0xc1, - 0xb1, 0x6f, 0x05, 0x36, 0xcb, 0xf2, 0x2a, 0x94, 0x9a, 0x41, 0x6f, 0xe0, 0x9c, 0x09, 0x96, 0x33, - 0x1e, 0x40, 0x35, 0xd5, 0x5e, 0x14, 0xa1, 0x5f, 0x5a, 0x81, 0x42, 0xd3, 0xb6, 0x85, 0xcd, 0x32, - 0xc8, 0xa0, 0x3b, 0xc8, 0xb2, 0xc6, 0x57, 0xa1, 0x12, 0x8f, 0x16, 0x92, 0xe3, 0xc6, 0xcd, 0x96, - 0xf0, 0x17, 0xa2, 0x59, 0x06, 0xb5, 0xb2, 0xed, 0xb9, 0x8e, 0x27, 0x58, 0xb6, 0xf1, 0x97, 0x48, - 0x55, 0xf9, 0xb7, 0x26, 0x17, 0xc4, 0xab, 0x2f, 0xda, 0x59, 0x27, 0x57, 0xc3, 0xe7, 0x53, 0xfd, - 0xdb, 0x75, 0xa8, 0x71, 0x65, 0xc8, 0x6f, 0xf9, 0x32, 0x64, 0x99, 0xc6, 0xff, 0xcc, 0x42, 0x39, - 0xda, 0x50, 0x31, 0x26, 0x18, 0x07, 0xae, 0x56, 0x68, 0xfc, 0xc9, 0xaf, 0x43, 0x41, 0x3a, 0x52, - 0xab, 0x71, 0xc5, 0x54, 0x00, 0xfa, 0x6a, 0xe9, 0x99, 0x55, 0x0e, 0xec, 0xf4, 0x54, 0x39, 0x43, - 0xab, 0x2f, 0x76, 0xac, 0x70, 0xa0, 0x5d, 0xd8, 0x04, 0x81, 0xfc, 0x27, 0xd6, 0x19, 0xea, 0x1c, - 0x3d, 0x57, 0x5e, 0x5c, 0x1a, 0xc5, 0xdf, 0x82, 0x3c, 0x76, 0x50, 0x2b, 0xcd, 0x5f, 0x98, 0xea, - 0x30, 0xaa, 0xc9, 0x61, 0x20, 0x70, 0x7a, 0xd6, 0x31, 0x02, 0x33, 0x89, 0x98, 0xbf, 0x0a, 0x2b, - 0x6a, 0x11, 0x1e, 0x44, 0xf1, 0x43, 0x89, 0x24, 0x4f, 0x61, 0x79, 0x13, 0x87, 0xd3, 0x92, 0xa2, - 0x5e, 0x5e, 0x40, 0xbf, 0xa3, 0xc1, 0x59, 0xef, 0x20, 0x8b, 0xa9, 0x38, 0x8d, 0x77, 0x70, 0x4c, - 0x2d, 0x29, 0x70, 0x9a, 0x5b, 0xc3, 0x91, 0xbc, 0x50, 0x4a, 0xb3, 0x2d, 0x64, 0x6f, 0xe0, 0x78, - 0x7d, 0x96, 0x51, 0x43, 0x8c, 0x93, 0x48, 0x24, 0x41, 0xe0, 0x07, 0x2c, 0xd7, 0x68, 0x40, 0x1e, - 0x75, 0x14, 0x8d, 0xa4, 0x67, 0x0d, 0x85, 0x1e, 0x69, 0xfa, 0xdd, 0xb8, 0x06, 0x6b, 0x33, 0xfb, - 0x71, 0xe3, 0xf7, 0x8a, 0x4a, 0x43, 0x90, 0x83, 0x7c, 0x41, 0xcd, 0x41, 0x6e, 0xde, 0x4b, 0xd9, - 0x18, 0x94, 0x32, 0x69, 0x63, 0x3e, 0x80, 0x02, 0x76, 0x2c, 0x32, 0x31, 0x0b, 0xb0, 0xef, 0x21, - 0xb9, 0xa9, 0xb8, 0x30, 0x82, 0xe9, 0x0d, 0x44, 0xef, 0x54, 0xd8, 0xda, 0xd6, 0x47, 0x20, 0x2a, - 0x4d, 0x2f, 0xe5, 0x9e, 0x2b, 0x80, 0x54, 0xa2, 0xe7, 0x7b, 0xad, 0xa1, 0xff, 0x7d, 0x87, 0xe6, - 0x15, 0x55, 0x22, 0x42, 0x44, 0x4f, 0xdb, 0xa8, 0x23, 0x7a, 0xda, 0x12, 0x44, 0xa3, 0x05, 0x05, - 0x7a, 0x37, 0xae, 0x04, 0xd5, 0x66, 0x95, 0x69, 0x78, 0x75, 0xb1, 0x36, 0xeb, 0x26, 0x37, 0x7e, - 0x27, 0x0b, 0x79, 0x84, 0xf9, 0x7d, 0x28, 0x04, 0x18, 0x87, 0xd1, 0x70, 0x5e, 0x16, 0xb3, 0x29, - 0x12, 0xfe, 0x6d, 0xad, 0x8a, 0xd9, 0x05, 0x94, 0x25, 0x7e, 0x63, 0x5a, 0x2d, 0xaf, 0x43, 0x61, - 0x64, 0x05, 0xd6, 0x50, 0xaf, 0x13, 0x05, 0x18, 0x3f, 0xc9, 0x40, 0x1e, 0x89, 0xf8, 0x1a, 0xd4, - 0x3a, 0x32, 0x70, 0x4e, 0x85, 0x1c, 0x04, 0xfe, 0xb8, 0x3f, 0x50, 0x9a, 0xf4, 0x58, 0x5c, 0x28, - 0x7b, 0xa3, 0x0c, 0x82, 0xb4, 0x5c, 0xa7, 0xc7, 0xb2, 0xa8, 0x55, 0x1b, 0xbe, 0x6b, 0xb3, 0x1c, - 0x5f, 0x85, 0xea, 0x13, 0xcf, 0x16, 0x41, 0xd8, 0xf3, 0x03, 0x61, 0xb3, 0xbc, 0x5e, 0xdd, 0xa7, - 0xac, 0x40, 0x7b, 0x99, 0x38, 0x97, 0x14, 0x0b, 0xb1, 0x22, 0xbf, 0x06, 0xab, 0x1b, 0x93, 0x01, - 0x12, 0x2b, 0xa1, 0x4d, 0xda, 0x13, 0x1e, 0x2a, 0x19, 0x2b, 0x2b, 0x25, 0xf6, 0xbf, 0xef, 0xb0, - 0x0a, 0xbe, 0x4c, 0xad, 0x13, 0x06, 0xc6, 0xbf, 0xcd, 0x44, 0x96, 0xa3, 0x06, 0x95, 0x43, 0x2b, - 0xb0, 0xfa, 0x81, 0x35, 0xc2, 0xf6, 0x55, 0xa1, 0xa4, 0x36, 0xce, 0x37, 0x95, 0x75, 0x53, 0xc0, - 0x43, 0x65, 0x1b, 0x15, 0xf0, 0x16, 0xcb, 0x25, 0xc0, 0xdb, 0x2c, 0x8f, 0xef, 0xf8, 0xee, 0xd8, - 0x97, 0x82, 0x15, 0xc8, 0xd6, 0xf9, 0xb6, 0x60, 0x45, 0x44, 0x76, 0xd1, 0xa2, 0xb0, 0x12, 0xf6, - 0x79, 0x13, 0xf5, 0xe7, 0xd8, 0x3f, 0x67, 0x65, 0x6c, 0x06, 0x0e, 0xa3, 0xb0, 0x59, 0x05, 0x9f, - 0xec, 0x8f, 0x87, 0xc7, 0x02, 0xbb, 0x09, 0xf8, 0xa4, 0xeb, 0xf7, 0xfb, 0xae, 0x60, 0x55, 0x1c, - 0x83, 0x94, 0xf1, 0x65, 0xcb, 0x64, 0x69, 0x2d, 0xd7, 0xf5, 0xc7, 0x92, 0xd5, 0x1a, 0xbf, 0xc8, - 0x41, 0x1e, 0xa3, 0x1b, 0x5c, 0x3b, 0x03, 0xb4, 0x33, 0x7a, 0xed, 0xe0, 0xef, 0x78, 0x05, 0x66, - 0x93, 0x15, 0xc8, 0xdf, 0xd7, 0x33, 0x9d, 0x5b, 0xc0, 0xca, 0xa2, 0xe0, 0xf4, 0x24, 0x73, 0xc8, - 0x0f, 0x9d, 0xa1, 0xd0, 0xb6, 0x8e, 0x7e, 0x23, 0x2e, 0xc4, 0xfd, 0xb8, 0x40, 0xc9, 0x13, 0xfa, - 0x8d, 0xab, 0xc6, 0xc2, 0x6d, 0xa1, 0x29, 0x69, 0x0d, 0xe4, 0xcc, 0x08, 0x9c, 0x63, 0xbd, 0x2a, - 0x73, 0xad, 0xd7, 0x07, 0x91, 0xf5, 0x2a, 0x2d, 0xb0, 0xea, 0xa9, 0x99, 0x69, 0xcb, 0x95, 0x18, - 0x8d, 0xf2, 0xe2, 0xec, 0xa9, 0xcd, 0x64, 0x4b, 0x6b, 0x6d, 0xb2, 0xd1, 0x95, 0xd5, 0x28, 0xb3, - 0x0c, 0xce, 0x26, 0x2d, 0x57, 0x65, 0xf3, 0x9e, 0x3a, 0xb6, 0xf0, 0x59, 0x8e, 0x36, 0xc2, 0xb1, - 0xed, 0xf8, 0x2c, 0x8f, 0x9e, 0xd7, 0xe1, 0xd6, 0x36, 0x2b, 0x18, 0xaf, 0xa6, 0xb6, 0xa4, 0xe6, - 0x58, 0xfa, 0x4a, 0x0c, 0xa9, 0x6f, 0x46, 0x69, 0xe3, 0xb1, 0xb0, 0x59, 0xd6, 0xf8, 0xfa, 0x1c, - 0x33, 0x5b, 0x83, 0xca, 0x93, 0x91, 0xeb, 0x5b, 0xf6, 0x15, 0x76, 0x76, 0x19, 0x20, 0x89, 0xaa, - 0x1b, 0xbf, 0x30, 0x92, 0xed, 0x1c, 0x7d, 0xd1, 0xd0, 0x1f, 0x07, 0x3d, 0x41, 0x26, 0xa4, 0x62, - 0x6a, 0x88, 0x7f, 0x07, 0x0a, 0xf8, 0x3c, 0x4a, 0xe3, 0xdc, 0x5f, 0x28, 0x96, 0x5b, 0x7f, 0xea, - 0x88, 0xe7, 0xa6, 0x62, 0xe4, 0x77, 0x00, 0xac, 0x9e, 0x74, 0xce, 0x04, 0x22, 0xf5, 0x62, 0x4f, - 0x61, 0xf8, 0x3b, 0x69, 0xf7, 0xe5, 0xea, 0x3c, 0x64, 0xca, 0xaf, 0xe1, 0x26, 0x54, 0x71, 0xe9, - 0x8e, 0x0e, 0x02, 0x5c, 0xed, 0xf5, 0x65, 0x62, 0x7c, 0x63, 0xb1, 0xe6, 0x3d, 0x8a, 0x19, 0xcd, - 0xb4, 0x10, 0xfe, 0x04, 0x96, 0x55, 0x4e, 0x4d, 0x0b, 0xad, 0x91, 0xd0, 0x37, 0x17, 0x13, 0x7a, - 0x90, 0x70, 0x9a, 0x13, 0x62, 0x66, 0xd3, 0x92, 0x85, 0x97, 0x4e, 0x4b, 0xbe, 0x0a, 0x2b, 0xdd, - 0xc9, 0x55, 0xa0, 0xb6, 0x8a, 0x29, 0x2c, 0x37, 0x60, 0xd9, 0x09, 0x93, 0xac, 0x28, 0xe5, 0x48, - 0xca, 0xe6, 0x04, 0xae, 0xf1, 0x1f, 0x8b, 0x90, 0xa7, 0x91, 0x9f, 0xce, 0x71, 0x6d, 0x4e, 0x98, - 0xf4, 0x07, 0x8b, 0x4f, 0xf5, 0xd4, 0x8a, 0x27, 0x0b, 0x92, 0x4b, 0x59, 0x90, 0xef, 0x40, 0x21, - 0xf4, 0x03, 0x19, 0x4d, 0xef, 0x82, 0x4a, 0xd4, 0xf1, 0x03, 0x69, 0x2a, 0x46, 0xbe, 0x0d, 0xa5, - 0x13, 0xc7, 0x95, 0x38, 0x29, 0x6a, 0xf0, 0x5e, 0x5f, 0x4c, 0xc6, 0x36, 0x31, 0x99, 0x11, 0x33, - 0xdf, 0x4d, 0x2b, 0x5b, 0x91, 0x24, 0xad, 0x2f, 0x26, 0x69, 0x9e, 0x0e, 0xde, 0x07, 0xd6, 0xf3, - 0xcf, 0x44, 0x60, 0xa6, 0x12, 0x93, 0x6a, 0x93, 0x9e, 0xc1, 0xf3, 0x06, 0x94, 0x07, 0x8e, 0x2d, - 0xd0, 0xcf, 0x21, 0x1b, 0x53, 0x36, 0x63, 0x98, 0x3f, 0x86, 0x32, 0xc5, 0x07, 0x68, 0x15, 0x2b, - 0x2f, 0x3d, 0xf8, 0x2a, 0x54, 0x89, 0x04, 0xe0, 0x8b, 0xe8, 0xe5, 0xdb, 0x8e, 0xa4, 0xfc, 0x74, - 0xd9, 0x8c, 0x61, 0x6c, 0x30, 0xe9, 0x7b, 0xba, 0xc1, 0x55, 0xd5, 0xe0, 0x69, 0x3c, 0x7f, 0x1b, - 0x6e, 0x10, 0x6e, 0x6a, 0x93, 0xc4, 0xa5, 0x86, 0x42, 0xe7, 0x3f, 0x44, 0x87, 0x65, 0x64, 0xf5, - 0xc5, 0xae, 0x33, 0x74, 0x64, 0xbd, 0x76, 0x37, 0x73, 0xaf, 0x60, 0x26, 0x08, 0xfe, 0x3a, 0xac, - 0xd9, 0xe2, 0xc4, 0x1a, 0xbb, 0xb2, 0x2b, 0x86, 0x23, 0xd7, 0x92, 0xa2, 0x6d, 0x93, 0x8e, 0x56, - 0xcc, 0xd9, 0x07, 0xfc, 0x0d, 0xb8, 0xa6, 0x91, 0x07, 0xf1, 0xa9, 0x42, 0xdb, 0xa6, 0xf4, 0x5d, - 0xc5, 0x9c, 0xf7, 0xc8, 0xd8, 0xd3, 0x66, 0x18, 0x37, 0x50, 0x8c, 0x53, 0x23, 0x03, 0x1a, 0x4a, - 0xb5, 0x23, 0x3f, 0xb2, 0x5c, 0x57, 0x04, 0x17, 0x2a, 0xc8, 0x7d, 0x6c, 0x79, 0xc7, 0x96, 0xc7, - 0x72, 0xb4, 0xc7, 0x5a, 0xae, 0xf0, 0x6c, 0x2b, 0x50, 0x3b, 0xf2, 0x23, 0xda, 0xd0, 0x0b, 0xc6, - 0x3d, 0xc8, 0xd3, 0x90, 0x56, 0xa0, 0xa0, 0xa2, 0x24, 0x8a, 0x98, 0x75, 0x84, 0x44, 0x16, 0x79, - 0x17, 0x97, 0x1f, 0xcb, 0x36, 0xfe, 0x49, 0x11, 0xca, 0xd1, 0xe0, 0x45, 0x67, 0x08, 0x99, 0xe4, - 0x0c, 0x01, 0xdd, 0xb8, 0xf0, 0xa9, 0x13, 0x3a, 0xc7, 0xda, 0x2d, 0x2d, 0x9b, 0x09, 0x02, 0x3d, - 0xa1, 0xe7, 0x8e, 0x2d, 0x07, 0xb4, 0x66, 0x0a, 0xa6, 0x02, 0xf8, 0x3d, 0x58, 0xb5, 0x71, 0x1c, - 0xbc, 0x9e, 0x3b, 0xb6, 0x45, 0x17, 0x77, 0x51, 0x95, 0x26, 0x98, 0x46, 0xf3, 0x8f, 0x01, 0xa4, - 0x33, 0x14, 0xdb, 0x7e, 0x30, 0xb4, 0xa4, 0x8e, 0x0d, 0xbe, 0xf1, 0x72, 0x5a, 0xbd, 0xde, 0x8d, - 0x05, 0x98, 0x29, 0x61, 0x28, 0x1a, 0xdf, 0xa6, 0x45, 0x97, 0x3e, 0x93, 0xe8, 0xad, 0x58, 0x80, - 0x99, 0x12, 0xc6, 0xbb, 0x50, 0x3a, 0xf1, 0x83, 0xe1, 0xd8, 0xb5, 0xf4, 0x9e, 0xfb, 0xfe, 0x4b, - 0xca, 0xdd, 0x56, 0xdc, 0x64, 0x7b, 0x22, 0x51, 0x49, 0x8e, 0xbb, 0xb2, 0x60, 0x8e, 0xdb, 0xf8, - 0x25, 0x80, 0xa4, 0x85, 0xfc, 0x26, 0xf0, 0x3d, 0xdf, 0x93, 0x83, 0xe6, 0xf1, 0x71, 0xb0, 0x21, - 0x4e, 0xfc, 0x40, 0x6c, 0x59, 0xb8, 0xbd, 0xde, 0x80, 0xb5, 0x18, 0xdf, 0x3c, 0x91, 0x22, 0x40, - 0x34, 0xa9, 0x40, 0x67, 0xe0, 0x07, 0x52, 0xf9, 0x78, 0xf4, 0xf3, 0x49, 0x87, 0xe5, 0x70, 0x4b, - 0x6f, 0x77, 0x0e, 0x58, 0xde, 0xb8, 0x07, 0x90, 0x0c, 0x2d, 0xc5, 0x42, 0xf4, 0xeb, 0xcd, 0x87, - 0x3a, 0x32, 0x22, 0xe8, 0xe1, 0xdb, 0x2c, 0x63, 0xfc, 0x3c, 0x03, 0xd5, 0x54, 0x97, 0x26, 0x63, - 0xe6, 0x4d, 0x7f, 0xec, 0x49, 0x15, 0xa4, 0xd3, 0xcf, 0xa7, 0x96, 0x3b, 0xc6, 0xcd, 0x7d, 0x0d, - 0x6a, 0x04, 0x6f, 0x39, 0xa1, 0x74, 0xbc, 0x9e, 0x64, 0xb9, 0x98, 0x44, 0x39, 0x06, 0xf9, 0x98, - 0x64, 0xdf, 0xd7, 0xa8, 0x02, 0x67, 0xb0, 0x7c, 0x28, 0x82, 0x9e, 0x88, 0x88, 0xc8, 0x19, 0xd6, - 0x98, 0x98, 0x4c, 0x39, 0xc3, 0x96, 0x1c, 0x74, 0xc6, 0x43, 0x56, 0x46, 0xa7, 0x12, 0x81, 0xe6, - 0x99, 0x08, 0xd0, 0x97, 0xa9, 0xe0, 0x7b, 0x10, 0x81, 0xab, 0xc1, 0xf2, 0x18, 0x44, 0xd4, 0x7b, - 0x8e, 0xc7, 0xaa, 0x31, 0x60, 0x9d, 0xb3, 0x65, 0x6c, 0x3f, 0x85, 0x0e, 0xac, 0xd6, 0xf8, 0x1f, - 0x39, 0xc8, 0xa3, 0x5d, 0xc7, 0x58, 0x37, 0x6d, 0x84, 0xd4, 0x5a, 0x49, 0xa3, 0x3e, 0xdb, 0x6e, - 0x84, 0xb2, 0xd3, 0xbb, 0xd1, 0x7b, 0x50, 0xed, 0x8d, 0x43, 0xe9, 0x0f, 0x69, 0x2b, 0xd6, 0xa7, - 0x5d, 0x37, 0x67, 0xb2, 0x46, 0x34, 0x9c, 0x66, 0x9a, 0x94, 0xbf, 0x03, 0xc5, 0x13, 0xa5, 0xf5, - 0x2a, 0x6f, 0xf4, 0x85, 0x4b, 0x76, 0x6b, 0xad, 0xd9, 0x9a, 0x18, 0xfb, 0xe5, 0xcc, 0xac, 0xd8, - 0x34, 0x4a, 0xef, 0xba, 0xc5, 0x78, 0xd7, 0xfd, 0x25, 0x58, 0x11, 0x38, 0xe0, 0x87, 0xae, 0xd5, - 0x13, 0x43, 0xe1, 0x45, 0xcb, 0xec, 0xed, 0x97, 0xe8, 0x31, 0xcd, 0x18, 0x75, 0x7b, 0x4a, 0x16, - 0x5a, 0x1e, 0xcf, 0xc7, 0xcd, 0x3f, 0x0a, 0xec, 0xcb, 0x66, 0x82, 0x30, 0xbe, 0xac, 0xed, 0x65, - 0x09, 0x72, 0xcd, 0xb0, 0xa7, 0x33, 0x20, 0x22, 0xec, 0xa9, 0xf0, 0x6a, 0x93, 0x86, 0x83, 0x65, - 0x8d, 0x37, 0xa1, 0x12, 0xbf, 0x01, 0x95, 0x67, 0xdf, 0x97, 0x9d, 0x91, 0xe8, 0x39, 0x27, 0x8e, - 0xb0, 0x95, 0x7e, 0x76, 0xa4, 0x15, 0x48, 0x95, 0x44, 0x6c, 0x79, 0x36, 0xcb, 0x36, 0x7e, 0xbb, - 0x0c, 0x45, 0xb5, 0xf9, 0xea, 0x0e, 0x57, 0xe2, 0x0e, 0x7f, 0x17, 0xca, 0xfe, 0x48, 0x04, 0x96, - 0xf4, 0x03, 0x9d, 0xb9, 0x79, 0xe7, 0x65, 0x36, 0xf3, 0xf5, 0x03, 0xcd, 0x6c, 0xc6, 0x62, 0xa6, - 0xb5, 0x29, 0x3b, 0xab, 0x4d, 0xf7, 0x81, 0x45, 0xfb, 0xf6, 0x61, 0x80, 0x7c, 0xf2, 0x42, 0xc7, - 0xe1, 0x33, 0x78, 0xde, 0x85, 0x4a, 0xcf, 0xf7, 0x6c, 0x27, 0xce, 0xe2, 0xac, 0x3c, 0xfc, 0xfa, - 0x4b, 0xb5, 0x70, 0x33, 0xe2, 0x36, 0x13, 0x41, 0xfc, 0x75, 0x28, 0x9c, 0xa1, 0x9a, 0x91, 0x3e, - 0x5d, 0xae, 0x84, 0x8a, 0x88, 0x7f, 0x02, 0xd5, 0x1f, 0x8c, 0x9d, 0xde, 0xe9, 0x41, 0x3a, 0x4b, - 0xf8, 0xde, 0x4b, 0xb5, 0xe2, 0xbb, 0x09, 0xbf, 0x99, 0x16, 0x96, 0x52, 0xed, 0xd2, 0x9f, 0x40, - 0xb5, 0xcb, 0xb3, 0xaa, 0x6d, 0x42, 0xcd, 0x13, 0xa1, 0x14, 0xf6, 0xb6, 0xf6, 0xd5, 0xe0, 0x33, - 0xf8, 0x6a, 0x93, 0x22, 0x8c, 0x2f, 0x41, 0x39, 0x9a, 0x70, 0x5e, 0x84, 0xec, 0x3e, 0x06, 0x45, - 0x45, 0xc8, 0x1e, 0x04, 0x4a, 0xdb, 0x9a, 0xa8, 0x6d, 0xc6, 0x1f, 0x65, 0xa0, 0x12, 0x0f, 0xfa, - 0xa4, 0xe5, 0x6c, 0xfd, 0x60, 0x6c, 0xb9, 0x2c, 0x43, 0xe1, 0xb2, 0x2f, 0x15, 0x44, 0xc6, 0xfa, - 0x11, 0x1d, 0xd6, 0x07, 0x2c, 0x47, 0x2e, 0x82, 0x08, 0x43, 0x96, 0xe7, 0x1c, 0x56, 0x34, 0xfa, - 0x20, 0x50, 0xa4, 0x05, 0x34, 0x7c, 0xf8, 0x34, 0x42, 0x14, 0x95, 0x47, 0x71, 0x2a, 0x94, 0x81, - 0xdc, 0xf7, 0x25, 0x01, 0x65, 0x6c, 0x54, 0xdb, 0x63, 0x15, 0x7c, 0xe7, 0xbe, 0x2f, 0xdb, 0x68, - 0x12, 0xe3, 0xf0, 0xac, 0x1a, 0xbd, 0x9e, 0x20, 0xb2, 0x88, 0x4d, 0xd7, 0x6d, 0x7b, 0xac, 0xa6, - 0x1f, 0x28, 0x68, 0x05, 0x25, 0xb6, 0xce, 0xad, 0x1e, 0xb2, 0xaf, 0xa2, 0x85, 0x45, 0x1e, 0x0d, - 0x33, 0x5c, 0x92, 0xad, 0x73, 0x27, 0x94, 0x21, 0x5b, 0x33, 0xfe, 0x30, 0x03, 0xd5, 0xd4, 0x04, - 0x63, 0xf8, 0x47, 0x84, 0xb8, 0x95, 0xa9, 0x68, 0xf0, 0x63, 0x1c, 0xc6, 0xc0, 0x8e, 0xb6, 0xa9, - 0xae, 0x8f, 0x3f, 0xb3, 0xf8, 0xbe, 0xae, 0x3f, 0xf4, 0x83, 0xc0, 0x7f, 0xae, 0x5c, 0x9f, 0x5d, - 0x2b, 0x94, 0xcf, 0x84, 0x38, 0x65, 0x79, 0xec, 0xea, 0xe6, 0x38, 0x08, 0x84, 0xa7, 0x10, 0x05, - 0x6a, 0x9c, 0x38, 0x57, 0x50, 0x11, 0x85, 0x22, 0x31, 0xed, 0x83, 0xac, 0x84, 0x86, 0x40, 0x53, - 0x2b, 0x4c, 0x19, 0x09, 0x90, 0x5c, 0x81, 0x15, 0xdc, 0x54, 0x54, 0x86, 0xe2, 0xe0, 0x64, 0xcb, - 0xba, 0x08, 0x9b, 0x7d, 0x9f, 0xc1, 0x34, 0x72, 0xdf, 0x7f, 0xce, 0xaa, 0x8d, 0x31, 0x40, 0x12, - 0x93, 0x61, 0x2c, 0x8a, 0x0a, 0x11, 0x9f, 0x21, 0x68, 0x88, 0x1f, 0x00, 0xe0, 0x2f, 0xa2, 0x8c, - 0x02, 0xd2, 0x97, 0x70, 0x94, 0x89, 0xcf, 0x4c, 0x89, 0x68, 0xfc, 0x15, 0xa8, 0xc4, 0x0f, 0x78, - 0x1d, 0x4a, 0xe4, 0xd2, 0xc6, 0xaf, 0x8d, 0x40, 0xf4, 0xcf, 0x1c, 0xcf, 0x16, 0xe7, 0x64, 0x57, - 0x0a, 0xa6, 0x02, 0xb0, 0x95, 0x03, 0xc7, 0xb6, 0x85, 0x17, 0x9d, 0xf4, 0x28, 0x68, 0xde, 0x79, - 0x7c, 0x7e, 0xee, 0x79, 0x7c, 0xe3, 0x97, 0xa1, 0x9a, 0x0a, 0x1a, 0x2f, 0xed, 0x76, 0xaa, 0x61, - 0xd9, 0xc9, 0x86, 0xdd, 0x86, 0x4a, 0x54, 0x03, 0x12, 0xd2, 0xde, 0x56, 0x31, 0x13, 0x44, 0xe3, - 0x5f, 0x66, 0xd1, 0x93, 0xc5, 0xae, 0x4d, 0x07, 0x7a, 0xdb, 0x50, 0x0c, 0xa5, 0x25, 0xc7, 0x51, - 0x31, 0xc3, 0x82, 0x0b, 0xb4, 0x43, 0x3c, 0x3b, 0x4b, 0xa6, 0xe6, 0xe6, 0x1f, 0x40, 0x4e, 0x5a, - 0x7d, 0x9d, 0x28, 0xfd, 0xca, 0x62, 0x42, 0xba, 0x56, 0x7f, 0x67, 0xc9, 0x44, 0x3e, 0xbe, 0x0b, - 0xe5, 0x9e, 0xce, 0x6d, 0x69, 0xa3, 0xb8, 0x60, 0x2c, 0x16, 0x65, 0xc4, 0x76, 0x96, 0xcc, 0x58, - 0x02, 0xff, 0x0e, 0xe4, 0xd1, 0xbb, 0xd4, 0x35, 0x1f, 0x0b, 0xc6, 0x98, 0xb8, 0x5c, 0x76, 0x96, - 0x4c, 0xe2, 0xdc, 0x28, 0x41, 0x81, 0x6c, 0x70, 0xa3, 0x0e, 0x45, 0xd5, 0xd7, 0xe9, 0x91, 0x6b, - 0xdc, 0x82, 0x5c, 0xd7, 0xea, 0xa3, 0x87, 0xef, 0xd8, 0xa1, 0x4e, 0x95, 0xe0, 0xcf, 0xc6, 0x2b, - 0x49, 0x9e, 0x2e, 0x9d, 0x02, 0xce, 0x4c, 0xa4, 0x80, 0x1b, 0x45, 0xc8, 0xe3, 0x1b, 0x1b, 0xb7, - 0xaf, 0x8a, 0x16, 0x1a, 0xff, 0x2c, 0x87, 0x81, 0x85, 0x14, 0xe7, 0x73, 0xd3, 0xdb, 0x1f, 0x41, - 0x65, 0x14, 0xf8, 0x3d, 0x11, 0x86, 0x7e, 0xa0, 0x9d, 0xa3, 0xd7, 0x5f, 0x7c, 0xf4, 0xbc, 0x7e, - 0x18, 0xf1, 0x98, 0x09, 0xbb, 0xf1, 0xef, 0xb3, 0x50, 0x89, 0x1f, 0xa8, 0x78, 0x46, 0x8a, 0x73, - 0x95, 0xca, 0xdc, 0x13, 0xc1, 0xd0, 0x72, 0x6c, 0x65, 0x3d, 0x36, 0x07, 0x56, 0xe4, 0xe4, 0x7e, - 0xec, 0x8f, 0xe5, 0xf8, 0x58, 0xa8, 0x14, 0xd6, 0x53, 0x67, 0x28, 0x7c, 0x96, 0xa7, 0xc3, 0x23, - 0x54, 0xec, 0x9e, 0xeb, 0x8f, 0x6d, 0x56, 0x40, 0xf8, 0x11, 0x6d, 0x6f, 0x7b, 0xd6, 0x28, 0x54, - 0x36, 0x73, 0xcf, 0x09, 0x7c, 0x56, 0x42, 0xa6, 0x6d, 0xa7, 0x3f, 0xb4, 0x58, 0x19, 0x85, 0x75, - 0x9f, 0x3b, 0x12, 0x8d, 0x70, 0x05, 0xdd, 0xd4, 0x83, 0x91, 0xf0, 0x3a, 0x32, 0x10, 0x42, 0xee, - 0x59, 0x23, 0x95, 0xd3, 0x34, 0x85, 0x6d, 0x3b, 0x52, 0xd9, 0xcf, 0x6d, 0xab, 0x27, 0x8e, 0x7d, - 0xff, 0x94, 0x2d, 0xa3, 0xa1, 0x69, 0x7b, 0xa1, 0xb4, 0xfa, 0x81, 0x35, 0x54, 0x36, 0xb4, 0x2b, - 0x5c, 0x41, 0xd0, 0x0a, 0xbd, 0xdb, 0x91, 0x83, 0xf1, 0xf1, 0x23, 0x8c, 0xfb, 0x56, 0xd5, 0x39, - 0x93, 0x2d, 0x46, 0x02, 0x6d, 0xe8, 0x32, 0x94, 0x37, 0x1c, 0xd7, 0x39, 0x76, 0x5c, 0x87, 0xad, - 0x21, 0x69, 0xeb, 0xbc, 0x67, 0xb9, 0x8e, 0x1d, 0x58, 0xcf, 0x19, 0xc7, 0xc6, 0x3d, 0x0e, 0xfc, - 0x53, 0x87, 0x5d, 0x43, 0x42, 0x0a, 0x03, 0xcf, 0x9c, 0x1f, 0xb2, 0xeb, 0x74, 0x56, 0x76, 0x2a, - 0x64, 0x6f, 0x70, 0x62, 0x1d, 0xb3, 0x1b, 0x49, 0x4a, 0xef, 0x66, 0x63, 0x0d, 0x56, 0xa7, 0x4e, - 0xe5, 0x1b, 0x25, 0x1d, 0x7d, 0x36, 0x6a, 0x50, 0x4d, 0x1d, 0x97, 0x36, 0x5e, 0x85, 0x72, 0x74, - 0x98, 0x8a, 0x51, 0xba, 0x13, 0xaa, 0x34, 0xb0, 0x56, 0x92, 0x18, 0x6e, 0xfc, 0x97, 0x0c, 0x14, - 0xd5, 0x49, 0x36, 0xdf, 0x88, 0x2b, 0x4f, 0x32, 0x0b, 0x9c, 0x5e, 0x2a, 0x26, 0x7d, 0xf6, 0x1b, - 0x97, 0x9f, 0x5c, 0x87, 0x82, 0x4b, 0xe1, 0xb8, 0x36, 0x5f, 0x04, 0xa4, 0xac, 0x4d, 0x6e, 0xc2, - 0xda, 0xdc, 0x86, 0x8a, 0x35, 0x96, 0x3e, 0x1d, 0xd2, 0xe9, 0x13, 0x8c, 0x04, 0x61, 0x34, 0xe3, - 0xd3, 0xe8, 0x28, 0x31, 0x49, 0x3e, 0x63, 0x37, 0x10, 0x42, 0x25, 0x1d, 0x29, 0xd6, 0xce, 0xd2, - 0x4e, 0xe2, 0x0f, 0x47, 0x56, 0x4f, 0x12, 0x82, 0xf6, 0x58, 0x34, 0xb5, 0x2c, 0x8f, 0x6b, 0x60, - 0x73, 0x60, 0x49, 0xe3, 0x04, 0xca, 0x87, 0x7e, 0x38, 0xbd, 0x63, 0x97, 0x20, 0xd7, 0xf5, 0x47, - 0xca, 0xff, 0xdc, 0xf0, 0x25, 0xf9, 0x9f, 0x6a, 0x83, 0x3e, 0x91, 0x4a, 0xe5, 0x4c, 0xa7, 0x3f, - 0x90, 0x2a, 0x4e, 0x6f, 0x7b, 0x9e, 0x08, 0x58, 0x01, 0x67, 0xd8, 0x14, 0x23, 0xf4, 0x79, 0x59, - 0x11, 0xe7, 0x94, 0xf0, 0xdb, 0x4e, 0x10, 0x4a, 0x56, 0x32, 0xda, 0xb8, 0xd7, 0x3a, 0x7d, 0xda, - 0x22, 0xe9, 0x07, 0x89, 0x5a, 0xc2, 0x26, 0x12, 0xb8, 0x29, 0x3c, 0xd4, 0x40, 0x8a, 0xad, 0x54, - 0x60, 0x48, 0x2f, 0xc8, 0xe2, 0xfe, 0x46, 0xf0, 0x47, 0xe3, 0x50, 0x3a, 0x27, 0x17, 0x2c, 0x67, - 0x3c, 0x83, 0xda, 0x44, 0x91, 0x13, 0xbf, 0x0e, 0x6c, 0x02, 0x81, 0x4d, 0x5f, 0xe2, 0xb7, 0xe0, - 0xda, 0x04, 0x76, 0xcf, 0xb1, 0x6d, 0xca, 0x04, 0x4f, 0x3f, 0x88, 0x3a, 0xb8, 0x51, 0x81, 0x52, - 0x4f, 0xcd, 0xa1, 0x71, 0x08, 0x35, 0x9a, 0xd4, 0x3d, 0x21, 0xad, 0x03, 0xcf, 0xbd, 0xf8, 0x13, - 0x57, 0xa2, 0x19, 0x5f, 0xd5, 0xe1, 0x17, 0x5a, 0x93, 0x93, 0xc0, 0x1f, 0x92, 0xac, 0x82, 0x49, - 0xbf, 0x51, 0xba, 0xf4, 0xb5, 0x66, 0x64, 0xa5, 0x6f, 0xfc, 0xa2, 0x02, 0xa5, 0x66, 0xaf, 0x87, - 0x01, 0xe3, 0xcc, 0x9b, 0xdf, 0x81, 0x62, 0xcf, 0xf7, 0x4e, 0x9c, 0xbe, 0xb6, 0xd6, 0xd3, 0x7e, - 0xa3, 0xe6, 0x43, 0x75, 0x3c, 0x71, 0xfa, 0xa6, 0x26, 0x46, 0x36, 0xbd, 0xdb, 0x14, 0xae, 0x64, - 0x53, 0x26, 0x37, 0xde, 0x5c, 0x1e, 0x40, 0xde, 0xf1, 0x4e, 0x7c, 0x5d, 0x36, 0xfa, 0xf9, 0x4b, - 0x98, 0xa8, 0x76, 0x92, 0x08, 0x1b, 0xff, 0x2d, 0x03, 0x45, 0xf5, 0x6a, 0xfe, 0x2a, 0xac, 0x08, - 0x0f, 0x97, 0x5a, 0x64, 0xe8, 0xf5, 0x1a, 0x9b, 0xc2, 0xa2, 0x4b, 0xab, 0x31, 0xe2, 0x78, 0xdc, - 0xd7, 0x99, 0x99, 0x34, 0x8a, 0xbf, 0x07, 0xb7, 0x14, 0x78, 0x18, 0x88, 0x40, 0xb8, 0xc2, 0x0a, - 0xc5, 0xe6, 0xc0, 0xf2, 0x3c, 0xe1, 0xea, 0x6d, 0xff, 0xb2, 0xc7, 0xdc, 0x80, 0x65, 0xf5, 0xa8, - 0x33, 0xb2, 0x7a, 0x22, 0xd4, 0x6b, 0x69, 0x02, 0xc7, 0xbf, 0x06, 0x05, 0xaa, 0xaa, 0xad, 0xdb, - 0x57, 0x4f, 0xa5, 0xa2, 0x6a, 0xf8, 0xf1, 0xbe, 0xd4, 0x04, 0x50, 0xc3, 0x84, 0x21, 0x99, 0xb6, - 0x0d, 0x5f, 0xbc, 0x72, 0x5c, 0x29, 0x3a, 0x4c, 0x31, 0x61, 0xfb, 0x6c, 0xe1, 0x0a, 0x2a, 0x7f, - 0xc4, 0x7d, 0x33, 0x4b, 0xe7, 0x2e, 0x13, 0xb8, 0xc6, 0x7f, 0xcd, 0x43, 0x1e, 0x47, 0x18, 0x89, - 0x07, 0xfe, 0x50, 0xc4, 0xd9, 0x67, 0xe5, 0x88, 0x4c, 0xe0, 0xd0, 0xf1, 0xb1, 0x54, 0x01, 0x40, - 0x4c, 0xa6, 0x4c, 0xcb, 0x34, 0x1a, 0x29, 0x47, 0x81, 0x7f, 0xe2, 0xb8, 0x09, 0xa5, 0x76, 0x91, - 0xa6, 0xd0, 0xfc, 0xeb, 0x70, 0x73, 0x68, 0x05, 0xa7, 0x42, 0xd2, 0xea, 0x7e, 0xe6, 0x07, 0xa7, - 0x21, 0x8e, 0x5c, 0xdb, 0xd6, 0x69, 0xcb, 0x4b, 0x9e, 0xf2, 0xd7, 0x61, 0xed, 0x79, 0x04, 0xc6, - 0xef, 0x50, 0x89, 0xc3, 0xd9, 0x07, 0x68, 0x8c, 0x6d, 0x71, 0xe6, 0x90, 0xdc, 0xb2, 0xaa, 0xad, - 0x8d, 0x60, 0x54, 0x25, 0x4b, 0x0d, 0x64, 0x47, 0xbf, 0x59, 0x9f, 0x3f, 0x4d, 0x62, 0xd1, 0x6e, - 0xaa, 0x9a, 0xa3, 0xb0, 0x6d, 0x53, 0xde, 0xb5, 0x62, 0x26, 0x08, 0x54, 0x34, 0x7a, 0xe5, 0x53, - 0x65, 0x72, 0x6b, 0x2a, 0x40, 0x4d, 0xa1, 0x90, 0x42, 0x8a, 0xde, 0x20, 0x7a, 0x89, 0x4a, 0x8a, - 0xa6, 0x51, 0xfc, 0x0e, 0x40, 0xdf, 0x92, 0xe2, 0xb9, 0x75, 0xf1, 0x24, 0x70, 0xeb, 0x42, 0x1d, - 0xa4, 0x24, 0x18, 0x0c, 0x71, 0x5d, 0xbf, 0x67, 0xb9, 0x1d, 0xe9, 0x07, 0x56, 0x5f, 0x1c, 0x5a, - 0x72, 0x50, 0xef, 0xab, 0x10, 0x77, 0x1a, 0x8f, 0x3d, 0x96, 0xce, 0x50, 0x7c, 0xe2, 0x7b, 0xa2, - 0x3e, 0x50, 0x3d, 0x8e, 0x60, 0x6c, 0x89, 0xe5, 0x59, 0xee, 0x85, 0x74, 0x7a, 0xd8, 0x17, 0x47, - 0xb5, 0x24, 0x85, 0xa2, 0xa4, 0x82, 0x90, 0x38, 0x8e, 0x6d, 0xbb, 0xfe, 0x7d, 0xd5, 0xd7, 0x18, - 0x81, 0xb3, 0x2b, 0xe4, 0x40, 0x04, 0x62, 0x3c, 0x6c, 0xda, 0x76, 0x20, 0xc2, 0xb0, 0x7e, 0xaa, - 0x66, 0x77, 0x0a, 0xdd, 0xf8, 0x26, 0x1d, 0x73, 0x0d, 0x8c, 0xb7, 0xa0, 0xb6, 0x8b, 0x2d, 0x6c, - 0x8e, 0x9c, 0x4e, 0xcf, 0x1f, 0x09, 0x34, 0xe8, 0x94, 0x30, 0xa6, 0xf4, 0x42, 0x15, 0x4a, 0x1f, - 0x85, 0xbe, 0xd7, 0x3c, 0x6c, 0xab, 0x2d, 0x66, 0x7b, 0xec, 0xba, 0x2c, 0x6b, 0x1c, 0x00, 0x24, - 0x9a, 0x8d, 0xdb, 0x45, 0x93, 0xce, 0x94, 0xd8, 0x92, 0x4a, 0x66, 0x79, 0xb6, 0xe3, 0xf5, 0xb7, - 0xb4, 0x32, 0xb3, 0x0c, 0x22, 0x29, 0x49, 0x21, 0xec, 0x18, 0x49, 0xee, 0x0c, 0x41, 0xc2, 0x66, - 0x39, 0xe3, 0xff, 0x66, 0xa0, 0x9a, 0x2a, 0xa1, 0xf8, 0x53, 0x2c, 0xfb, 0xc0, 0xcd, 0x1e, 0xdd, - 0x05, 0x9c, 0x37, 0xa5, 0xe8, 0x31, 0x8c, 0xb3, 0xaa, 0x2b, 0x3c, 0xf0, 0xa9, 0x4a, 0x49, 0xa4, - 0x30, 0x9f, 0xa9, 0xe4, 0xc3, 0x78, 0xa8, 0xf3, 0x3a, 0x55, 0x28, 0x3d, 0xf1, 0x4e, 0x3d, 0xff, - 0xb9, 0xa7, 0xf6, 0x69, 0xaa, 0xe3, 0x99, 0x38, 0x91, 0x8c, 0x4a, 0x6d, 0x72, 0xc6, 0xbf, 0xc9, - 0x4f, 0x95, 0xbc, 0xb5, 0xa0, 0xa8, 0x82, 0x09, 0xf2, 0x73, 0x67, 0x6b, 0x94, 0xd2, 0xc4, 0xfa, - 0xf4, 0x2b, 0x85, 0x32, 0x35, 0x33, 0x7a, 0xf9, 0x71, 0x41, 0x68, 0x76, 0xee, 0x29, 0xdd, 0x84, - 0xa0, 0xc8, 0x36, 0x4f, 0xd4, 0x44, 0xc7, 0x12, 0x1a, 0x7f, 0x2b, 0x03, 0xd7, 0xe7, 0x91, 0xa4, - 0x2b, 0xc7, 0x33, 0x93, 0x95, 0xe3, 0x9d, 0xa9, 0x4a, 0xec, 0x2c, 0xf5, 0xe6, 0xc1, 0x4b, 0x36, - 0x62, 0xb2, 0x2e, 0xdb, 0xf8, 0xbd, 0x0c, 0xac, 0xcd, 0xf4, 0x39, 0xe5, 0xc7, 0x00, 0x14, 0x95, - 0x66, 0xa9, 0x42, 0xa9, 0xb8, 0x74, 0x45, 0x1d, 0x3d, 0xd0, 0x0e, 0x1f, 0xaa, 0x5a, 0x00, 0x5d, - 0x7b, 0xae, 0x9c, 0x68, 0x9c, 0x35, 0xdc, 0x40, 0xfa, 0x42, 0xa5, 0x69, 0x95, 0xb3, 0xa5, 0x31, - 0x45, 0xe5, 0xe8, 0xaa, 0xf3, 0x11, 0x56, 0xa2, 0x02, 0xac, 0xf1, 0xc8, 0x75, 0x7a, 0x08, 0x96, - 0x79, 0x03, 0x6e, 0xaa, 0x0b, 0x08, 0x3a, 0xa8, 0x3c, 0xe9, 0x0e, 0x1c, 0x5a, 0x1c, 0xac, 0x82, - 0xef, 0x39, 0x1c, 0x1f, 0xbb, 0x4e, 0x38, 0x60, 0x60, 0x98, 0x70, 0x6d, 0x4e, 0x07, 0xa9, 0xc9, - 0x4f, 0x75, 0xf3, 0x57, 0x00, 0xb6, 0x9e, 0x46, 0x8d, 0x66, 0x19, 0xce, 0x61, 0x65, 0xeb, 0x69, - 0x5a, 0xba, 0x5e, 0x3c, 0x4f, 0xd1, 0x7a, 0x85, 0x2c, 0x67, 0xfc, 0x4a, 0x26, 0xaa, 0x90, 0x68, - 0xfc, 0x65, 0xa8, 0xa9, 0x06, 0x1f, 0x5a, 0x17, 0xae, 0x6f, 0xd9, 0xbc, 0x05, 0x2b, 0x61, 0x7c, - 0x45, 0x26, 0xb5, 0x61, 0x4d, 0x3b, 0x02, 0x9d, 0x09, 0x22, 0x73, 0x8a, 0x29, 0x0a, 0x94, 0xb2, - 0xc9, 0xb1, 0x0a, 0xa7, 0x90, 0xcf, 0xa2, 0x25, 0xb7, 0x4c, 0x41, 0x9c, 0x65, 0x7c, 0x0d, 0xd6, - 0x3a, 0x89, 0x71, 0x57, 0x1e, 0x35, 0x2a, 0x87, 0xda, 0x19, 0xb6, 0x22, 0xe5, 0xd0, 0xa0, 0xf1, - 0xcf, 0x4b, 0x00, 0xc9, 0x11, 0xd2, 0x9c, 0x35, 0x3f, 0xaf, 0x22, 0x62, 0xe6, 0x40, 0x37, 0xf7, - 0xd2, 0x07, 0xba, 0xef, 0xc5, 0x8e, 0xbd, 0x4a, 0x2f, 0x4f, 0x97, 0x85, 0x27, 0x6d, 0x9a, 0x76, - 0xe7, 0x27, 0x0a, 0x86, 0x0a, 0xd3, 0x05, 0x43, 0x77, 0x67, 0xab, 0x0b, 0xa7, 0x8c, 0x51, 0x92, - 0xb7, 0x28, 0x4d, 0xe4, 0x2d, 0x1a, 0x50, 0x0e, 0x84, 0x65, 0xfb, 0x9e, 0x7b, 0x11, 0x9d, 0x1b, - 0x46, 0x30, 0x7f, 0x0b, 0x0a, 0x92, 0x6e, 0xf9, 0x94, 0x69, 0xed, 0xbc, 0x60, 0xe2, 0x14, 0x2d, - 0x5a, 0x36, 0x27, 0xd4, 0x25, 0x81, 0x6a, 0xd7, 0x2c, 0x9b, 0x29, 0x0c, 0x5f, 0x07, 0xee, 0x60, - 0x10, 0xe7, 0xba, 0xc2, 0xde, 0xb8, 0xd8, 0x52, 0xc7, 0x79, 0xb4, 0xaf, 0x97, 0xcd, 0x39, 0x4f, - 0xa2, 0xf9, 0x5f, 0x4e, 0xe6, 0x9f, 0x9a, 0x7c, 0xe6, 0x84, 0xd8, 0xd3, 0x1a, 0xb9, 0x2f, 0x31, - 0x8c, 0x9e, 0x43, 0xb4, 0x60, 0xd5, 0x58, 0x92, 0xf6, 0x26, 0x67, 0xe2, 0x97, 0x3c, 0x8d, 0x86, - 0x57, 0x25, 0x6e, 0x56, 0x49, 0x68, 0x82, 0x20, 0x4b, 0xde, 0xf3, 0xbd, 0x7d, 0xd4, 0x08, 0xa6, - 0x2d, 0xb9, 0x86, 0xb1, 0xbf, 0x23, 0x77, 0x1c, 0x58, 0x2e, 0x3d, 0x5d, 0x53, 0x96, 0x3c, 0xc1, - 0x18, 0x7f, 0x90, 0x8d, 0x83, 0xa7, 0x0a, 0x14, 0x8e, 0xad, 0xd0, 0xe9, 0xa9, 0xdd, 0x4d, 0x3b, - 0x3d, 0x6a, 0x77, 0x93, 0xbe, 0xed, 0xb3, 0x2c, 0xc6, 0x41, 0xa1, 0xd0, 0xc7, 0x39, 0xc9, 0x9d, - 0x2a, 0x96, 0x47, 0x13, 0x10, 0x69, 0x92, 0xaa, 0x19, 0x22, 0x56, 0x4a, 0xce, 0xd9, 0x71, 0x35, - 0x26, 0x85, 0xd9, 0xb4, 0xc5, 0xb0, 0x32, 0xd2, 0x78, 0xbe, 0x14, 0x2a, 0x35, 0x49, 0x7a, 0xcf, - 0x00, 0xc5, 0x44, 0x97, 0x04, 0x58, 0x15, 0x03, 0x93, 0x48, 0xa8, 0xca, 0x27, 0x86, 0x14, 0xb6, - 0x2d, 0xe3, 0xba, 0x9f, 0x7c, 0xc0, 0x6a, 0xd8, 0xa2, 0xe4, 0xaa, 0x16, 0x5b, 0x41, 0xa9, 0x16, - 0x55, 0xb2, 0xac, 0xe2, 0xcf, 0x33, 0xaa, 0x6f, 0x61, 0xf8, 0x56, 0x1b, 0xed, 0xd2, 0x1a, 0xb6, - 0x2c, 0x76, 0x74, 0x18, 0xc7, 0xb8, 0x6b, 0x64, 0x61, 0x10, 0xe4, 0x8c, 0x2c, 0x4f, 0xb2, 0x6b, - 0xd8, 0xd5, 0x91, 0x7d, 0xc2, 0xae, 0x23, 0x4b, 0x6f, 0x60, 0x49, 0x76, 0x03, 0x69, 0xf0, 0xd7, - 0x96, 0x08, 0x50, 0x53, 0xd8, 0x4d, 0xa4, 0x91, 0x56, 0x9f, 0xdd, 0x32, 0x7e, 0x3d, 0xa9, 0x87, - 0x7e, 0x23, 0x0e, 0x4f, 0x16, 0x59, 0x3e, 0x18, 0xc0, 0xcc, 0x5b, 0xcb, 0x2d, 0x58, 0x0b, 0xc4, - 0x0f, 0xc6, 0xce, 0xc4, 0x2d, 0x81, 0xdc, 0xd5, 0x65, 0x28, 0xb3, 0x1c, 0xc6, 0x19, 0xac, 0x45, - 0xc0, 0x33, 0x47, 0x0e, 0x28, 0x8f, 0xc4, 0xdf, 0x4a, 0x5d, 0x63, 0xc8, 0xcc, 0xbd, 0xfe, 0x15, - 0x8b, 0x4c, 0xae, 0x2d, 0xc4, 0xe7, 0x04, 0xd9, 0x05, 0xce, 0x09, 0x8c, 0x7f, 0x54, 0x4a, 0xa5, - 0x92, 0x54, 0xc0, 0x66, 0xc7, 0x01, 0xdb, 0xec, 0x41, 0x74, 0x92, 0xfa, 0xcf, 0xbe, 0x4c, 0xea, - 0x7f, 0x5e, 0x51, 0xc7, 0xfb, 0x18, 0x3f, 0xd0, 0xca, 0x7c, 0xba, 0xc0, 0xb1, 0xc6, 0x04, 0x2d, - 0xdf, 0xa0, 0x63, 0x65, 0xab, 0xa3, 0x2a, 0x8e, 0x0a, 0x73, 0x2f, 0x15, 0xa5, 0xcf, 0x8f, 0x35, - 0xa5, 0x99, 0xe2, 0x4a, 0xd9, 0xb1, 0xe2, 0x3c, 0x3b, 0x86, 0xb1, 0xb3, 0xb6, 0x70, 0x31, 0xac, - 0x4e, 0x81, 0xd4, 0xef, 0x48, 0x3c, 0xad, 0xf1, 0xb2, 0x39, 0x83, 0x47, 0x67, 0x6f, 0x38, 0x76, - 0xa5, 0xa3, 0x0f, 0x3a, 0x14, 0x30, 0x7d, 0xeb, 0xb1, 0x32, 0x7b, 0xeb, 0xf1, 0x43, 0x80, 0x50, - 0xe0, 0xea, 0xd8, 0x72, 0x7a, 0x52, 0xd7, 0x25, 0xdd, 0xb9, 0xac, 0x6f, 0xfa, 0x78, 0x26, 0xc5, - 0x81, 0xed, 0x1f, 0x5a, 0xe7, 0x74, 0x64, 0xab, 0x0b, 0x28, 0x62, 0x78, 0xda, 0xba, 0xaf, 0xcc, - 0x5a, 0xf7, 0xb7, 0xa0, 0x10, 0xa2, 0x0b, 0x4d, 0x17, 0x77, 0x2e, 0x9f, 0xdf, 0x75, 0xf2, 0xb3, - 0x4d, 0x45, 0x4b, 0x09, 0x4b, 0xb4, 0x7f, 0x7e, 0x40, 0x57, 0x76, 0x2a, 0x66, 0x04, 0x4e, 0x58, - 0xd8, 0x9b, 0x53, 0x16, 0x76, 0xea, 0x3c, 0xe8, 0xd6, 0xcc, 0x79, 0x50, 0xc3, 0x86, 0xa2, 0x3e, - 0x9e, 0x98, 0x4e, 0x25, 0x44, 0x89, 0xcd, 0x6c, 0x2a, 0xb1, 0x19, 0xd7, 0xc7, 0xe6, 0xd2, 0xf5, - 0xb1, 0x53, 0xf7, 0xfe, 0x0a, 0x33, 0xf7, 0xfe, 0x8c, 0x4f, 0xa0, 0xa0, 0xa2, 0x06, 0x88, 0x1c, - 0x56, 0xe5, 0xec, 0x62, 0xb7, 0x59, 0x86, 0x5f, 0x07, 0x16, 0x0a, 0xf2, 0x86, 0x44, 0xc7, 0x1a, - 0x0a, 0x32, 0xa3, 0x59, 0x5e, 0x87, 0xeb, 0x8a, 0x36, 0x9c, 0x7c, 0x42, 0x2e, 0x99, 0xeb, 0x1c, - 0x07, 0x56, 0x70, 0xc1, 0xf2, 0xc6, 0x87, 0x54, 0x1c, 0x10, 0xa9, 0x5c, 0x35, 0xbe, 0x67, 0xa9, - 0x0c, 0xb7, 0xad, 0xed, 0x13, 0xd5, 0x96, 0xe8, 0x78, 0x50, 0x55, 0xdc, 0x51, 0xc0, 0x45, 0x19, - 0xa3, 0xe5, 0xb4, 0x17, 0xf0, 0xa7, 0xb6, 0x22, 0x8d, 0x8d, 0x94, 0x4f, 0x39, 0x59, 0x42, 0x97, - 0x59, 0xb4, 0x84, 0xce, 0x78, 0x0c, 0xab, 0xe6, 0xa4, 0xd5, 0xe7, 0xef, 0x41, 0xc9, 0x1f, 0xa5, - 0xe5, 0xbc, 0x48, 0x73, 0x23, 0x72, 0xe3, 0x77, 0x33, 0xb0, 0xdc, 0xf6, 0xa4, 0x08, 0x3c, 0xcb, - 0xdd, 0x76, 0xad, 0x3e, 0x7f, 0x37, 0xb2, 0x63, 0xf3, 0xb3, 0x13, 0x69, 0xda, 0x49, 0x93, 0xe6, - 0xea, 0x34, 0x3c, 0xbf, 0x01, 0x6b, 0xc2, 0x76, 0xa4, 0x1f, 0x28, 0x4f, 0x3a, 0xaa, 0x74, 0xbc, - 0x0e, 0x4c, 0xa1, 0x3b, 0xb4, 0x68, 0xba, 0x6a, 0x9a, 0xeb, 0x70, 0x7d, 0x02, 0x1b, 0xb9, 0xc9, - 0x59, 0x7e, 0x1b, 0xea, 0xc9, 0x7e, 0xb5, 0xe5, 0x7b, 0xb2, 0xed, 0xd9, 0xe2, 0x9c, 0xdc, 0x30, - 0x96, 0x33, 0x7e, 0x2d, 0x76, 0x00, 0x9f, 0xea, 0x3a, 0xc8, 0xc0, 0xf7, 0x93, 0x4b, 0xb6, 0x1a, - 0x4a, 0x5d, 0xe6, 0xce, 0x2e, 0x70, 0x99, 0xfb, 0xc3, 0xe4, 0x42, 0xae, 0xda, 0x4a, 0x5e, 0x99, - 0xbb, 0x3f, 0x51, 0xf9, 0x96, 0xf6, 0xff, 0x3b, 0x22, 0x75, 0x3b, 0xf7, 0x4d, 0x1d, 0xf4, 0xe5, - 0x17, 0xf1, 0x93, 0x55, 0xa5, 0xc3, 0x3b, 0xd3, 0xb7, 0x40, 0x16, 0x2b, 0xa3, 0x9c, 0x71, 0x65, - 0xe1, 0xa5, 0x5d, 0xd9, 0x6f, 0x4f, 0xc5, 0x57, 0xe5, 0xb9, 0x09, 0xbb, 0x2b, 0xee, 0xb8, 0x7e, - 0x1b, 0x4a, 0x03, 0x27, 0x94, 0x7e, 0xa0, 0xee, 0x5d, 0xcf, 0xde, 0x13, 0x4b, 0x8d, 0xd6, 0x8e, - 0x22, 0xa4, 0x9a, 0xb7, 0x88, 0x8b, 0x7f, 0x0f, 0xd6, 0x68, 0xe0, 0x0f, 0x13, 0xbf, 0x22, 0xac, - 0x57, 0xe7, 0xd6, 0x1a, 0xa6, 0x44, 0x6d, 0x4c, 0xb1, 0x98, 0xb3, 0x42, 0x1a, 0x7d, 0x80, 0x64, - 0x7e, 0x66, 0xac, 0xd8, 0x67, 0xb8, 0x77, 0x7d, 0x13, 0x8a, 0xe1, 0xf8, 0x38, 0x39, 0xaf, 0xd3, - 0x50, 0xe3, 0x1c, 0x1a, 0x33, 0xfe, 0xc3, 0xa1, 0x08, 0x54, 0x73, 0xaf, 0xbc, 0xfc, 0xfd, 0x61, - 0x7a, 0xe2, 0x95, 0x72, 0xde, 0xbd, 0x64, 0xf6, 0x62, 0xc9, 0x29, 0x0d, 0x68, 0xbc, 0x03, 0xd5, - 0xd4, 0xa0, 0xa2, 0x65, 0x1e, 0x7b, 0xb6, 0x1f, 0x25, 0x89, 0xf1, 0xb7, 0xba, 0xfc, 0x66, 0x47, - 0x69, 0x62, 0xfa, 0xdd, 0x30, 0x81, 0x4d, 0x0f, 0xe0, 0x15, 0x31, 0xf8, 0x2b, 0x50, 0x4b, 0x39, - 0x7d, 0x71, 0x02, 0x71, 0x12, 0x69, 0x9c, 0xc1, 0xe7, 0x53, 0xe2, 0x0e, 0x45, 0x30, 0x74, 0x42, - 0xdc, 0x6a, 0x54, 0x38, 0x49, 0xce, 0xb7, 0x2d, 0x3c, 0xe9, 0xc8, 0xc8, 0x82, 0xc6, 0x30, 0xff, - 0x26, 0x14, 0x46, 0x22, 0x18, 0x86, 0xda, 0x8a, 0x4e, 0x6b, 0xd0, 0x5c, 0xb1, 0xa1, 0xa9, 0x78, - 0x8c, 0x7f, 0x9a, 0x81, 0xf2, 0x9e, 0x90, 0x16, 0x7a, 0x17, 0x7c, 0x6f, 0xea, 0x2d, 0xb3, 0x67, - 0xcc, 0x11, 0xe9, 0xba, 0x0e, 0x70, 0xd7, 0xdb, 0x9a, 0x5e, 0xc3, 0x3b, 0x4b, 0x49, 0xc3, 0x1a, - 0x1b, 0x50, 0xd2, 0xe8, 0xc6, 0xbb, 0xb0, 0x3a, 0x45, 0x49, 0xe3, 0xa2, 0xbc, 0xff, 0xce, 0xc5, - 0x30, 0x2a, 0x84, 0x5a, 0x36, 0x27, 0x91, 0x1b, 0x15, 0x28, 0x8d, 0x14, 0x83, 0xf1, 0x07, 0x37, - 0xa8, 0xfc, 0xc6, 0x39, 0xc1, 0xa8, 0x7f, 0xde, 0xce, 0x7a, 0x07, 0x80, 0x36, 0x6f, 0xb5, 0x29, - 0xab, 0xa4, 0x6e, 0x0a, 0xc3, 0xdf, 0x8f, 0xb3, 0xf1, 0xf9, 0xb9, 0x6e, 0x57, 0x5a, 0xf8, 0x74, - 0x4a, 0xbe, 0x0e, 0x25, 0x27, 0xa4, 0x4c, 0x9d, 0x2e, 0x6c, 0x8a, 0x40, 0xfe, 0x2d, 0x28, 0x3a, - 0xc3, 0x91, 0x1f, 0x48, 0x9d, 0xae, 0xbf, 0x52, 0x6a, 0x9b, 0x28, 0x77, 0x96, 0x4c, 0xcd, 0x83, - 0xdc, 0xe2, 0x9c, 0xb8, 0xcb, 0x2f, 0xe6, 0x6e, 0x9d, 0x47, 0xdc, 0x8a, 0x87, 0x7f, 0x17, 0x6a, - 0x7d, 0x55, 0xd7, 0xa9, 0x04, 0x6b, 0x23, 0xf2, 0x95, 0xab, 0x84, 0x3c, 0x4a, 0x33, 0xec, 0x2c, - 0x99, 0x93, 0x12, 0x50, 0x24, 0xba, 0xf8, 0x22, 0x94, 0x5d, 0xff, 0x23, 0xdf, 0xf1, 0x28, 0x20, - 0x7e, 0x81, 0x48, 0x33, 0xcd, 0x80, 0x22, 0x27, 0x24, 0xf0, 0xaf, 0xa3, 0xc7, 0x13, 0x4a, 0x7d, - 0xf5, 0xfd, 0xee, 0x55, 0x92, 0xba, 0x22, 0xd4, 0x97, 0xd6, 0x43, 0xc9, 0xcf, 0xa1, 0x91, 0x5a, - 0x24, 0xfa, 0x25, 0xcd, 0xd1, 0x28, 0xf0, 0x31, 0xaa, 0xae, 0x91, 0xb4, 0xaf, 0x5f, 0x25, 0xed, - 0xf0, 0x52, 0xee, 0x9d, 0x25, 0xf3, 0x0a, 0xd9, 0xbc, 0x8b, 0xb1, 0x9f, 0xee, 0xc2, 0xae, 0xb0, - 0xce, 0xa2, 0x8b, 0xf3, 0xf7, 0x17, 0x1a, 0x05, 0xe2, 0xd8, 0x59, 0x32, 0xa7, 0x64, 0xf0, 0x5f, - 0x86, 0xb5, 0x89, 0x77, 0xd2, 0x5d, 0x59, 0x75, 0xad, 0xfe, 0x6b, 0x0b, 0x77, 0x03, 0x99, 0x76, - 0x96, 0xcc, 0x59, 0x49, 0x7c, 0x0c, 0x9f, 0x9b, 0xed, 0xd2, 0x96, 0xe8, 0xb9, 0x8e, 0x27, 0xf4, - 0x0d, 0xfc, 0x77, 0x5e, 0x6e, 0xb4, 0x34, 0xf3, 0xce, 0x92, 0x79, 0xb9, 0x64, 0xfe, 0x57, 0xe1, - 0xf6, 0x68, 0xae, 0x89, 0x51, 0xa6, 0x4b, 0x5f, 0xe0, 0x7f, 0x6f, 0xc1, 0x37, 0xcf, 0xf0, 0xef, - 0x2c, 0x99, 0x57, 0xca, 0x47, 0xdf, 0x99, 0x62, 0x6c, 0x5d, 0x7e, 0xae, 0x00, 0x3a, 0xcb, 0xed, - 0xb9, 0x3b, 0xc2, 0xb2, 0xe3, 0x13, 0x85, 0x04, 0xd1, 0xf8, 0x5f, 0x19, 0x28, 0x6a, 0x7d, 0xbf, - 0x1d, 0xd7, 0x14, 0xc4, 0xa6, 0x3b, 0x41, 0xf0, 0x0f, 0xa0, 0x22, 0x82, 0xc0, 0x0f, 0x36, 0x7d, - 0x3b, 0x2a, 0xc7, 0x9c, 0xce, 0x43, 0x2b, 0x39, 0xeb, 0xad, 0x88, 0xcc, 0x4c, 0x38, 0xf8, 0xfb, - 0x00, 0x6a, 0x9d, 0x77, 0x93, 0x5b, 0x44, 0x8d, 0xf9, 0xfc, 0xea, 0x90, 0x2a, 0xa1, 0x4e, 0x12, - 0x77, 0xd1, 0x09, 0x51, 0x04, 0xc6, 0x21, 0x69, 0x21, 0x15, 0x92, 0xde, 0xd6, 0x99, 0x06, 0x4a, - 0xc0, 0xe8, 0xbb, 0x74, 0x31, 0xa2, 0xf1, 0xfb, 0x19, 0x28, 0x2a, 0xe3, 0xc1, 0x5b, 0xb3, 0x3d, - 0x7a, 0xed, 0xc5, 0x36, 0x67, 0x7d, 0xba, 0x67, 0xdf, 0x02, 0x50, 0x36, 0x28, 0xd5, 0xb3, 0xdb, - 0x53, 0x72, 0x34, 0x6b, 0x54, 0x00, 0x9d, 0xd0, 0x1b, 0x0f, 0xd5, 0x7d, 0x2f, 0x4a, 0x1a, 0x3f, - 0xd9, 0xdd, 0x65, 0x4b, 0x7c, 0x0d, 0x6a, 0x4f, 0xf6, 0x1f, 0xef, 0x1f, 0x3c, 0xdb, 0x3f, 0x6a, - 0x99, 0xe6, 0x81, 0xa9, 0x72, 0xc7, 0x1b, 0xcd, 0xad, 0xa3, 0xf6, 0xfe, 0xe1, 0x93, 0x2e, 0xcb, - 0x36, 0xfe, 0x55, 0x06, 0x6a, 0x13, 0xb6, 0xeb, 0xcf, 0x76, 0xea, 0x52, 0xc3, 0x9f, 0x9b, 0x3f, - 0xfc, 0xf9, 0xcb, 0x86, 0xbf, 0x30, 0x3d, 0xfc, 0xbf, 0x9d, 0x81, 0xda, 0x84, 0x8d, 0x4c, 0x4b, - 0xcf, 0x4c, 0x4a, 0x4f, 0xef, 0xf4, 0xd9, 0xa9, 0x9d, 0xde, 0x80, 0xe5, 0xe8, 0xf7, 0x7e, 0x92, - 0x93, 0x98, 0xc0, 0xa5, 0x69, 0xe8, 0xc2, 0x45, 0x7e, 0x92, 0x86, 0x2e, 0x5d, 0x5c, 0xdd, 0x5a, - 0xba, 0x60, 0x1a, 0xd2, 0xfd, 0xfb, 0xc6, 0xe5, 0x16, 0xf4, 0x8a, 0x2e, 0x3c, 0x82, 0xea, 0x28, - 0x59, 0xa6, 0x2f, 0xe7, 0x96, 0xa4, 0x39, 0x5f, 0xd0, 0xce, 0xdf, 0xc9, 0xc0, 0xca, 0xa4, 0xcd, - 0xfd, 0x73, 0x3d, 0xac, 0xff, 0x22, 0x03, 0x6b, 0x33, 0x96, 0xfc, 0x4a, 0xc7, 0x6e, 0xba, 0x5d, - 0xd9, 0x05, 0xda, 0x95, 0x9b, 0xd3, 0xae, 0xcb, 0x2d, 0xc9, 0xd5, 0x2d, 0xee, 0xc0, 0xe7, 0x2e, - 0xdd, 0x13, 0xae, 0x18, 0xea, 0x09, 0xa1, 0xb9, 0x69, 0xa1, 0xbf, 0x95, 0x81, 0xdb, 0x57, 0xd9, - 0xfb, 0xff, 0xef, 0x7a, 0x35, 0xdd, 0x42, 0xe3, 0xdd, 0xb8, 0xd4, 0xa0, 0x0a, 0x25, 0xfd, 0x5d, - 0x2b, 0x5d, 0xea, 0x3d, 0xf0, 0x9f, 0x7b, 0x2a, 0x57, 0x6d, 0x0a, 0x4b, 0xdf, 0xfc, 0x37, 0xc5, - 0xc8, 0x75, 0xe8, 0x14, 0xf5, 0x16, 0x40, 0x93, 0xe2, 0xba, 0xe8, 0x22, 0xce, 0xe6, 0xee, 0x41, - 0xa7, 0xc5, 0x96, 0xd2, 0x4e, 0xec, 0x27, 0x91, 0x21, 0x36, 0x0e, 0xa1, 0x98, 0x5c, 0x8d, 0xd8, - 0xb3, 0x82, 0x53, 0x5b, 0x9d, 0x55, 0x2e, 0x43, 0xf9, 0x50, 0x87, 0x50, 0xea, 0x55, 0x1f, 0x75, - 0x0e, 0xf6, 0x55, 0x5a, 0x7c, 0xeb, 0xa0, 0xab, 0x2e, 0x58, 0x74, 0x9e, 0x3e, 0x52, 0x87, 0x66, - 0x8f, 0xcc, 0xe6, 0xe1, 0xce, 0x11, 0x51, 0x14, 0x8c, 0xdf, 0xcc, 0x47, 0xbb, 0x9a, 0x61, 0xea, - 0x53, 0x50, 0x80, 0x22, 0x5a, 0x73, 0x5f, 0x0b, 0x8e, 0x5f, 0x43, 0x45, 0xc1, 0xad, 0x73, 0x95, - 0x87, 0x60, 0x59, 0x5e, 0x84, 0xec, 0xe1, 0xb1, 0xaa, 0x55, 0xda, 0x91, 0x43, 0x57, 0xdd, 0xcc, - 0xec, 0x9e, 0x4b, 0x56, 0xc0, 0x1f, 0x9b, 0xe1, 0x19, 0x2b, 0x1a, 0xff, 0x3a, 0x07, 0x95, 0xd8, - 0x54, 0xbe, 0x8c, 0xe9, 0xe6, 0x1c, 0x56, 0xda, 0xfb, 0xdd, 0x96, 0xb9, 0xdf, 0xdc, 0xd5, 0x24, - 0x39, 0x7e, 0x0d, 0x56, 0xb7, 0xdb, 0xbb, 0xad, 0xa3, 0xdd, 0x83, 0xe6, 0x96, 0x46, 0x96, 0xf9, - 0x4d, 0xe0, 0xed, 0xbd, 0xc3, 0x03, 0xb3, 0x7b, 0xd4, 0xee, 0x1c, 0x6d, 0x36, 0xf7, 0x37, 0x5b, - 0xbb, 0xad, 0x2d, 0x56, 0xe4, 0xaf, 0xc0, 0xdd, 0xfd, 0x83, 0x6e, 0xfb, 0x60, 0xff, 0x68, 0xff, - 0xe0, 0xe8, 0x60, 0xe3, 0xa3, 0xd6, 0x66, 0xb7, 0x73, 0xd4, 0xde, 0x3f, 0x42, 0xa9, 0x8f, 0xcc, - 0x26, 0x3e, 0x61, 0x05, 0x7e, 0x17, 0x6e, 0x6b, 0xaa, 0x4e, 0xcb, 0x7c, 0xda, 0x32, 0x51, 0xc8, - 0x93, 0xfd, 0xe6, 0xd3, 0x66, 0x7b, 0xb7, 0xb9, 0xb1, 0xdb, 0x62, 0xcb, 0xfc, 0x0e, 0x34, 0x34, - 0x85, 0xd9, 0xec, 0xb6, 0x8e, 0x76, 0xdb, 0x7b, 0xed, 0xee, 0x51, 0xeb, 0x7b, 0x9b, 0xad, 0xd6, - 0x56, 0x6b, 0x8b, 0xd5, 0xf8, 0x57, 0xe0, 0xcb, 0xd4, 0x28, 0xdd, 0x88, 0xc9, 0x97, 0x7d, 0xd2, - 0x3e, 0x3c, 0x6a, 0x9a, 0x9b, 0x3b, 0xed, 0xa7, 0x2d, 0xb6, 0xc2, 0x5f, 0x83, 0x2f, 0x5d, 0x4e, - 0xba, 0xd5, 0x36, 0x5b, 0x9b, 0xdd, 0x03, 0xf3, 0x63, 0xb6, 0xc6, 0xbf, 0x00, 0x9f, 0xdb, 0xe9, - 0xee, 0xed, 0x1e, 0x3d, 0x33, 0x0f, 0xf6, 0x1f, 0x1d, 0xd1, 0xcf, 0x4e, 0xd7, 0x7c, 0xb2, 0xd9, - 0x7d, 0x62, 0xb6, 0x18, 0xf0, 0x06, 0xdc, 0x3c, 0xdc, 0x38, 0xda, 0x3f, 0xe8, 0x1e, 0x35, 0xf7, - 0x3f, 0xde, 0xd8, 0x3d, 0xd8, 0x7c, 0x7c, 0xb4, 0x7d, 0x60, 0xee, 0x35, 0xbb, 0xac, 0xca, 0xbf, - 0x0a, 0xaf, 0x6d, 0x76, 0x9e, 0xea, 0x66, 0x1e, 0x6c, 0x1f, 0x99, 0x07, 0xcf, 0x3a, 0x47, 0x07, - 0xe6, 0x91, 0xd9, 0xda, 0xa5, 0x3e, 0x77, 0x92, 0xb6, 0x97, 0xf8, 0x6d, 0xa8, 0xb7, 0xf7, 0x3b, - 0x4f, 0xb6, 0xb7, 0xdb, 0x9b, 0xed, 0xd6, 0x7e, 0xf7, 0xe8, 0xb0, 0x65, 0xee, 0xb5, 0x3b, 0x1d, - 0x24, 0x63, 0x15, 0xe3, 0x3b, 0x50, 0x6c, 0x7b, 0x67, 0x8e, 0xa4, 0xf5, 0xa5, 0x95, 0x51, 0x47, - 0x5c, 0x11, 0x48, 0xcb, 0xc2, 0xe9, 0x7b, 0xf4, 0xc5, 0x01, 0x5a, 0x5d, 0xcb, 0x66, 0x82, 0x30, - 0x7e, 0x3f, 0x07, 0x35, 0x25, 0x22, 0x8a, 0xe0, 0xee, 0xc1, 0xaa, 0x4e, 0x96, 0xb6, 0x27, 0x4d, - 0xd8, 0x34, 0x9a, 0x3e, 0xe5, 0xa5, 0x50, 0x29, 0x43, 0x96, 0x46, 0xf1, 0x9b, 0x50, 0xb4, 0x7a, - 0x2e, 0x86, 0x81, 0xea, 0x44, 0x53, 0x43, 0x9f, 0xd5, 0x76, 0xa1, 0x5d, 0x54, 0x84, 0x3d, 0xdf, - 0xdb, 0x8c, 0x2f, 0x9d, 0x4c, 0xe0, 0xf8, 0x27, 0x70, 0x2b, 0x86, 0x5b, 0x5e, 0x2f, 0xb8, 0x18, - 0xc5, 0xdf, 0xda, 0x2b, 0xcd, 0x4d, 0x26, 0x6c, 0x3b, 0xae, 0x98, 0x20, 0x34, 0x2f, 0x13, 0xc0, - 0x1f, 0x01, 0x38, 0x34, 0x58, 0xe4, 0x1f, 0xcd, 0xbf, 0x59, 0x3d, 0x31, 0x9a, 0x1a, 0xd2, 0x6e, - 0x60, 0xfc, 0x1b, 0x37, 0x88, 0x3e, 0xda, 0xdd, 0xc7, 0xfa, 0xd3, 0x7c, 0xcb, 0x66, 0x0c, 0x1b, - 0x0f, 0x00, 0x12, 0x2e, 0xce, 0x60, 0x19, 0x7d, 0x8b, 0x66, 0xb8, 0x27, 0x86, 0xc7, 0x22, 0x50, - 0x75, 0x7e, 0x0a, 0xf3, 0x08, 0x39, 0x58, 0xc6, 0xf8, 0xa3, 0x4c, 0x2a, 0x0e, 0x57, 0x71, 0xf6, - 0x95, 0x3b, 0xd0, 0xbc, 0x53, 0x23, 0x8c, 0x84, 0xf5, 0xa0, 0x6a, 0xc7, 0x48, 0x83, 0xfc, 0x10, - 0xb8, 0x33, 0x3b, 0x94, 0xf9, 0x05, 0x87, 0x72, 0x0e, 0xef, 0x74, 0xd2, 0xbf, 0x30, 0x9b, 0xf4, - 0xbf, 0x03, 0xd0, 0x77, 0xfd, 0x63, 0x7d, 0xf2, 0x58, 0xd4, 0x95, 0x41, 0x31, 0xc6, 0x70, 0xa1, - 0x1c, 0x7d, 0x67, 0x10, 0x75, 0x8c, 0xbe, 0x34, 0x18, 0x27, 0x38, 0x15, 0xc4, 0x77, 0x60, 0x45, - 0x4c, 0xb6, 0x39, 0xbb, 0x60, 0x9b, 0xa7, 0xf8, 0x8c, 0x6f, 0xc0, 0xda, 0x0c, 0x11, 0x0e, 0xe2, - 0xc8, 0x92, 0xf1, 0xc7, 0x06, 0xf0, 0xf7, 0xec, 0x81, 0xbe, 0xf1, 0x9f, 0xb2, 0xb0, 0xbc, 0x67, - 0x79, 0xce, 0x89, 0x08, 0x65, 0xd4, 0xda, 0xb0, 0x37, 0x10, 0x43, 0x2b, 0x6a, 0xad, 0x82, 0x74, - 0xd6, 0x23, 0x9b, 0x3e, 0x4f, 0x98, 0x39, 0xa0, 0xc2, 0xd5, 0x34, 0x96, 0x83, 0xb8, 0xfe, 0x5e, - 0x43, 0x38, 0x77, 0xae, 0xd3, 0x13, 0x5e, 0x18, 0xad, 0x98, 0x08, 0x4c, 0xea, 0x7b, 0x8a, 0x57, - 0xd4, 0xf7, 0x94, 0x66, 0xc7, 0xff, 0x2e, 0x54, 0xc3, 0x5e, 0x20, 0x84, 0x17, 0x0e, 0x7c, 0x19, - 0x7d, 0xa3, 0x32, 0x8d, 0xa2, 0x62, 0x3b, 0xff, 0xb9, 0x87, 0x3a, 0xbe, 0xeb, 0x78, 0xa7, 0xba, - 0x86, 0x6c, 0x02, 0x87, 0x3a, 0x48, 0x39, 0x1f, 0xe7, 0x87, 0x82, 0xf2, 0x0d, 0x05, 0x33, 0x86, - 0x29, 0xab, 0x63, 0x49, 0xd1, 0xf7, 0x03, 0x47, 0xa8, 0xd4, 0x66, 0xc5, 0x4c, 0x61, 0x90, 0xd7, - 0xb5, 0xbc, 0xfe, 0xd8, 0xea, 0x0b, 0x7d, 0x40, 0x1e, 0xc3, 0xc6, 0xff, 0x2e, 0x00, 0xa8, 0xd5, - 0x10, 0x0e, 0x9c, 0x11, 0x1d, 0xbd, 0x38, 0xba, 0xea, 0xb8, 0x66, 0xd2, 0x6f, 0xfe, 0xde, 0xc4, - 0x85, 0x80, 0xd9, 0xe3, 0xd4, 0x84, 0x7d, 0x3a, 0x25, 0x84, 0x83, 0x63, 0x49, 0xa1, 0x4b, 0xab, - 0x68, 0xfc, 0xf3, 0x66, 0x1a, 0x45, 0xc5, 0x75, 0x96, 0x14, 0x2d, 0xcf, 0x56, 0x29, 0xa7, 0xbc, - 0x19, 0xc3, 0x74, 0x84, 0x14, 0x36, 0xc7, 0xd2, 0x37, 0x85, 0x27, 0x9e, 0xc7, 0xb7, 0xe5, 0x12, - 0x14, 0xdf, 0x83, 0xda, 0xc8, 0xba, 0x18, 0x0a, 0x4f, 0xee, 0x09, 0x39, 0xf0, 0x6d, 0x5d, 0x07, - 0xf5, 0xda, 0xe5, 0x0d, 0x3c, 0x4c, 0x93, 0x9b, 0x93, 0xdc, 0xa8, 0x13, 0x5e, 0x48, 0xab, 0x44, - 0x4d, 0xa3, 0x86, 0xf8, 0x06, 0x80, 0xfa, 0x95, 0xb2, 0x54, 0x33, 0x59, 0x28, 0x6b, 0x28, 0x42, - 0x11, 0x9c, 0x39, 0xca, 0xba, 0x2a, 0x23, 0x95, 0x70, 0xa1, 0x2d, 0x1e, 0x87, 0x22, 0x68, 0x0d, - 0x2d, 0xc7, 0xd5, 0x13, 0x9c, 0x20, 0xf8, 0xdb, 0x70, 0x23, 0x1c, 0x1f, 0xa3, 0xce, 0x1c, 0x8b, - 0xae, 0xbf, 0x2f, 0x9e, 0x87, 0xae, 0x90, 0x52, 0x04, 0xba, 0xd6, 0x62, 0xfe, 0x43, 0xa3, 0x1f, - 0xbb, 0x61, 0xf4, 0x3d, 0x14, 0xfc, 0x95, 0x14, 0x74, 0xc5, 0x28, 0x5d, 0xed, 0xc6, 0x32, 0x68, - 0xfe, 0x14, 0x4a, 0x17, 0xc3, 0x65, 0xf9, 0x97, 0xe1, 0x8b, 0x13, 0x44, 0xa6, 0x3a, 0xba, 0x0e, - 0xb7, 0x1d, 0xcf, 0x72, 0x9d, 0x1f, 0xaa, 0x42, 0x82, 0x9c, 0x31, 0x82, 0xda, 0xc4, 0xc0, 0xd1, - 0xf5, 0x4e, 0xfa, 0xa5, 0x2b, 0x82, 0x18, 0x2c, 0x2b, 0xb8, 0x23, 0x03, 0x87, 0x4e, 0x5c, 0x62, - 0xcc, 0x26, 0xae, 0x73, 0x9f, 0x65, 0xf9, 0x75, 0x60, 0x0a, 0xd3, 0xf6, 0xac, 0xd1, 0xa8, 0x39, - 0x1a, 0xb9, 0x82, 0xe5, 0xe8, 0xea, 0x6c, 0x82, 0x55, 0xd7, 0x02, 0x58, 0xde, 0xf8, 0x1e, 0xdc, - 0xa2, 0x91, 0x79, 0x2a, 0x82, 0x38, 0xd0, 0xd6, 0x7d, 0xbd, 0x01, 0x6b, 0xea, 0xd7, 0xbe, 0x2f, - 0xd5, 0x63, 0x72, 0x3e, 0x39, 0xac, 0x28, 0x34, 0xfa, 0x5e, 0x1d, 0x41, 0x17, 0x62, 0x63, 0x5c, - 0x4c, 0x97, 0x35, 0xfe, 0xb0, 0x08, 0x3c, 0x51, 0x88, 0xae, 0x23, 0x82, 0x2d, 0x4b, 0x5a, 0xa9, - 0x4c, 0x69, 0xed, 0xd2, 0x6a, 0x80, 0x17, 0xd7, 0xf2, 0xdd, 0x84, 0xa2, 0x13, 0x62, 0x68, 0xa8, - 0x0b, 0x7a, 0x35, 0xc4, 0x77, 0x01, 0x46, 0x22, 0x70, 0x7c, 0x9b, 0x34, 0xa8, 0x30, 0xf7, 0x5e, - 0xc6, 0x6c, 0xa3, 0xd6, 0x0f, 0x63, 0x1e, 0x33, 0xc5, 0x8f, 0xed, 0x50, 0x90, 0x3a, 0x5b, 0x2f, - 0x52, 0xa3, 0xd3, 0x28, 0xfe, 0x06, 0x5c, 0x1b, 0x05, 0x4e, 0x4f, 0xa8, 0xe9, 0x78, 0x12, 0xda, - 0x9b, 0xf4, 0x15, 0xc1, 0x12, 0x51, 0xce, 0x7b, 0x84, 0x1a, 0x68, 0x79, 0x14, 0x30, 0x85, 0x74, - 0x9a, 0xac, 0xaf, 0x90, 0xab, 0x92, 0xd7, 0x9a, 0x39, 0xff, 0x21, 0xbf, 0x0f, 0x4c, 0x3f, 0xd8, - 0x73, 0xbc, 0x5d, 0xe1, 0xf5, 0xe5, 0x80, 0x94, 0xbb, 0x66, 0xce, 0xe0, 0xc9, 0x82, 0xa9, 0x6f, - 0x35, 0xa9, 0x73, 0xa4, 0x8a, 0x19, 0xc3, 0xea, 0xb3, 0x04, 0xae, 0x1f, 0x74, 0x64, 0xa0, 0x6b, - 0x77, 0x63, 0x18, 0x7d, 0xa8, 0x90, 0xda, 0x7a, 0x18, 0xf8, 0xf6, 0x98, 0x4e, 0x39, 0x94, 0x11, - 0x9b, 0x46, 0x27, 0x94, 0x7b, 0x96, 0xa7, 0x0b, 0x2a, 0x6b, 0x69, 0xca, 0x18, 0x4d, 0x31, 0xa1, - 0x1f, 0x26, 0x02, 0x57, 0x75, 0x4c, 0x98, 0xc2, 0x69, 0x9a, 0x44, 0x14, 0x8b, 0x69, 0x12, 0x39, - 0xd4, 0x7f, 0x3b, 0xf0, 0x1d, 0x3b, 0x91, 0xa5, 0x6a, 0x7b, 0x66, 0xf0, 0x29, 0xda, 0x44, 0x26, - 0x9f, 0xa0, 0x4d, 0xe4, 0x5e, 0x87, 0x82, 0x7f, 0x72, 0x22, 0x02, 0xfa, 0x34, 0x67, 0xc5, 0x54, - 0x80, 0xf1, 0xe3, 0x0c, 0x40, 0xa2, 0x12, 0xb8, 0x10, 0x12, 0x28, 0x59, 0xf8, 0xb7, 0xe0, 0x5a, - 0x1a, 0xed, 0xea, 0x52, 0x59, 0x5a, 0x0d, 0xc9, 0x83, 0x2d, 0xeb, 0x22, 0x64, 0x59, 0x7d, 0xb5, - 0x5b, 0xe3, 0x9e, 0x09, 0x41, 0x75, 0x87, 0xd7, 0x81, 0x25, 0x48, 0xba, 0xaf, 0x17, 0xb2, 0xfc, - 0x24, 0xe9, 0xc7, 0xc2, 0x0a, 0x42, 0x56, 0x30, 0x76, 0xa0, 0xa8, 0x8e, 0xc0, 0xe6, 0x1c, 0x5e, - 0xbf, 0x5c, 0xad, 0xca, 0xdf, 0xce, 0x00, 0x6c, 0xa9, 0xba, 0x6a, 0xdc, 0xdb, 0xe7, 0xd4, 0x04, - 0xcc, 0xf3, 0xb3, 0x2c, 0xdb, 0xa6, 0xfa, 0xf4, 0x5c, 0xfc, 0x5d, 0x20, 0x04, 0x51, 0x9f, 0xac, - 0xa8, 0xb6, 0x4c, 0xad, 0xc4, 0x18, 0x56, 0xdb, 0xca, 0xa6, 0xef, 0x79, 0xa2, 0x87, 0x9b, 0x52, - 0xbc, 0xad, 0xc4, 0x28, 0xe3, 0x47, 0x59, 0xa8, 0x6c, 0x0e, 0x2c, 0xa9, 0x3e, 0xa3, 0xf3, 0x1d, - 0x28, 0x0f, 0x45, 0x18, 0x5a, 0x7d, 0x11, 0xea, 0x23, 0x9f, 0xe9, 0xf3, 0xda, 0x98, 0x76, 0xfd, - 0x89, 0x17, 0x08, 0xcb, 0x56, 0xdf, 0x0e, 0x8a, 0xb9, 0x94, 0x04, 0x4f, 0xc6, 0x21, 0xf9, 0x4b, - 0x48, 0xf0, 0xe2, 0x0f, 0xfd, 0xba, 0x56, 0xa8, 0x48, 0xe2, 0x74, 0x5b, 0x1a, 0xd5, 0xd8, 0x83, - 0x6a, 0x8a, 0x95, 0xbf, 0x02, 0x35, 0xdf, 0xb5, 0x45, 0xa8, 0x6e, 0x0f, 0x26, 0x1f, 0x5c, 0x9c, - 0x40, 0x52, 0x69, 0x07, 0xae, 0x67, 0x11, 0xe8, 0xd3, 0xbb, 0x08, 0x34, 0x7e, 0xa3, 0x0c, 0x55, - 0x6c, 0xd4, 0x9e, 0xea, 0xc3, 0xcc, 0x74, 0xd4, 0xa1, 0xe4, 0x6b, 0xc9, 0xfa, 0xda, 0xa1, 0x9f, - 0x92, 0xa9, 0xcb, 0x45, 0x72, 0x93, 0xe5, 0x22, 0xb7, 0xa1, 0xa2, 0x8e, 0x9a, 0xec, 0xa6, 0xb2, - 0x8f, 0x39, 0x33, 0x41, 0xa0, 0x13, 0x33, 0xf4, 0x6d, 0xb2, 0xd2, 0x4d, 0x75, 0x4a, 0x93, 0x33, - 0x53, 0x18, 0x0a, 0x73, 0x74, 0xf7, 0xab, 0x3a, 0xcc, 0x51, 0xa0, 0xaa, 0xdb, 0x19, 0xb9, 0x17, - 0x5d, 0x5f, 0xb7, 0xb6, 0x6d, 0x27, 0xb7, 0xb7, 0x27, 0xf1, 0x7c, 0x13, 0x4a, 0x7a, 0x5a, 0xf4, - 0x59, 0xd4, 0x57, 0xe6, 0xcc, 0x84, 0x26, 0x5f, 0xd7, 0x7f, 0xf5, 0x05, 0x2a, 0x33, 0xe2, 0xe4, - 0x8f, 0xa0, 0x6a, 0x49, 0x69, 0xf5, 0x06, 0x43, 0x6d, 0x55, 0x73, 0x73, 0x8e, 0xa5, 0xd3, 0x82, - 0x9a, 0x31, 0xb5, 0x99, 0xe6, 0xe4, 0x1b, 0x50, 0x09, 0x84, 0x35, 0x71, 0x32, 0xfe, 0xca, 0x15, - 0x62, 0xcc, 0x88, 0xd6, 0x4c, 0xd8, 0xe2, 0x6f, 0x8f, 0x42, 0xea, 0xdb, 0xa3, 0x77, 0xa1, 0xaa, - 0x55, 0xc7, 0xc4, 0x47, 0xea, 0x9b, 0x2c, 0x69, 0x54, 0xe3, 0xa7, 0x19, 0x58, 0x99, 0xec, 0xde, - 0x9f, 0xc5, 0xd7, 0xf2, 0xbe, 0x95, 0x7c, 0x2d, 0xef, 0x33, 0x7c, 0x79, 0xee, 0xb7, 0x32, 0x00, - 0xc9, 0xc8, 0xe1, 0xde, 0xaa, 0xbe, 0xea, 0x15, 0x79, 0xfb, 0x0a, 0xe2, 0x3b, 0x13, 0x9f, 0x82, - 0x78, 0x7b, 0xa1, 0x69, 0x48, 0xfd, 0x4c, 0x15, 0xc6, 0x3f, 0x80, 0x95, 0x49, 0x3c, 0x5d, 0x28, - 0x68, 0xef, 0xb6, 0x54, 0x6e, 0xab, 0xbd, 0xd7, 0x7c, 0xd4, 0xd2, 0x17, 0xd9, 0xda, 0xfb, 0x8f, - 0x59, 0xb6, 0xf1, 0xc7, 0x19, 0xa8, 0xc4, 0x93, 0xc2, 0xbf, 0x9b, 0x9e, 0x4d, 0x55, 0x20, 0xf3, - 0xd6, 0x22, 0xb3, 0x99, 0xfc, 0x6a, 0x79, 0x32, 0xb8, 0x48, 0x4d, 0x6e, 0xc3, 0x87, 0x95, 0xc9, - 0x87, 0x73, 0xcc, 0xec, 0xa3, 0x49, 0x33, 0xfb, 0xe6, 0x42, 0xaf, 0x8c, 0x42, 0xdc, 0x5d, 0x27, - 0x94, 0xda, 0x02, 0xbf, 0x9f, 0x7d, 0x2f, 0xd3, 0xb8, 0x0b, 0xcb, 0xe9, 0x47, 0xb3, 0x77, 0x59, - 0xef, 0xff, 0x71, 0x0e, 0x56, 0x26, 0x6b, 0x4c, 0xe8, 0x6e, 0x9c, 0xaa, 0x6f, 0x3a, 0x70, 0xed, - 0xd4, 0x5d, 0x02, 0x86, 0xe1, 0xb5, 0x0e, 0xa2, 0x09, 0xb1, 0x46, 0xd9, 0x33, 0x7f, 0x28, 0xd8, - 0xdd, 0xf4, 0x17, 0x41, 0xdf, 0xe0, 0x10, 0xdd, 0x69, 0x64, 0x23, 0x5e, 0xd1, 0xdf, 0x46, 0xfb, - 0x51, 0x96, 0xd7, 0x52, 0x15, 0xed, 0x3f, 0x41, 0x0f, 0x72, 0x75, 0x63, 0xec, 0xd9, 0xae, 0xb0, - 0x63, 0xec, 0x4f, 0xd3, 0xd8, 0xb8, 0x24, 0xfd, 0x47, 0x79, 0xbe, 0x02, 0x95, 0xce, 0xf8, 0x58, - 0x97, 0xa3, 0xff, 0xb5, 0x3c, 0xbf, 0x09, 0x6b, 0x9a, 0x2a, 0xa9, 0xfe, 0x64, 0x7f, 0x1d, 0x77, - 0xb5, 0x95, 0xa6, 0x1a, 0x2f, 0xdd, 0x50, 0xf6, 0x37, 0xf2, 0xd8, 0x04, 0xba, 0x2a, 0xff, 0x37, - 0x49, 0x4e, 0x7c, 0x75, 0x88, 0xfd, 0x4a, 0x9e, 0xaf, 0x02, 0x74, 0xba, 0xf1, 0x8b, 0x7e, 0x2d, - 0xcf, 0xab, 0x50, 0xec, 0x74, 0x49, 0xda, 0x8f, 0xf3, 0xfc, 0x06, 0xb0, 0xe4, 0xa9, 0xae, 0x89, - 0xfd, 0x3b, 0xaa, 0x31, 0x71, 0x91, 0xeb, 0xdf, 0xcd, 0x63, 0xbf, 0xa2, 0x51, 0x66, 0x7f, 0x2f, - 0xcf, 0x19, 0x54, 0x53, 0x39, 0x59, 0xf6, 0xf7, 0xf3, 0x9c, 0x43, 0x6d, 0xcf, 0x09, 0x43, 0xc7, - 0xeb, 0xeb, 0x1e, 0xfc, 0x2a, 0xbd, 0x79, 0x3b, 0xbe, 0xfd, 0xc4, 0x7e, 0x3d, 0xcf, 0x6f, 0x01, - 0x4f, 0x9f, 0x43, 0xe9, 0x07, 0xbf, 0x41, 0xdc, 0x6a, 0x27, 0x0d, 0x35, 0xee, 0x1f, 0x10, 0x37, - 0x6a, 0x82, 0x46, 0xfc, 0x26, 0x0d, 0xc8, 0x66, 0x52, 0x45, 0xab, 0xf1, 0x3f, 0x21, 0xe6, 0x68, - 0x32, 0x15, 0xee, 0xa7, 0xf9, 0xfb, 0xbf, 0x4b, 0xe7, 0x08, 0xe9, 0x52, 0x33, 0xbe, 0x0c, 0x65, - 0xd7, 0xf7, 0xfa, 0x52, 0x7d, 0x89, 0xb5, 0x06, 0x95, 0x70, 0xe0, 0x07, 0x92, 0x40, 0xba, 0x9e, - 0xe9, 0xd1, 0x35, 0x7e, 0x75, 0xa1, 0x41, 0x45, 0x83, 0x2a, 0x2f, 0x2b, 0xad, 0x3e, 0xab, 0xc6, - 0xf5, 0xbf, 0xf9, 0xb8, 0x46, 0x99, 0x3e, 0x27, 0x10, 0x5d, 0xd7, 0x66, 0x45, 0x24, 0x1d, 0x07, - 0xae, 0xaa, 0x55, 0x16, 0x18, 0x09, 0xa8, 0x4f, 0x2e, 0x8e, 0x06, 0x18, 0x70, 0x54, 0x14, 0xd6, - 0xff, 0xbe, 0xa3, 0x2e, 0x02, 0xeb, 0xc2, 0x3e, 0x1b, 0xdb, 0x11, 0xd7, 0xae, 0x30, 0x71, 0xff, - 0x1f, 0x66, 0x60, 0x39, 0xba, 0x44, 0xef, 0xf4, 0x1d, 0x4f, 0x55, 0x3b, 0x47, 0xdf, 0xb7, 0xed, - 0xb9, 0xce, 0x28, 0xfa, 0x5e, 0xe4, 0x2a, 0x54, 0xed, 0xc0, 0xea, 0x37, 0x3d, 0x7b, 0x2b, 0xf0, - 0x47, 0xaa, 0xd9, 0xea, 0xa4, 0x51, 0x55, 0x59, 0x3f, 0x17, 0xc7, 0x48, 0x3e, 0x12, 0x01, 0xcb, - 0x53, 0xd1, 0xe0, 0xc0, 0x0a, 0x1c, 0xaf, 0xdf, 0x3a, 0x97, 0xc2, 0x0b, 0x55, 0xb5, 0x75, 0x15, - 0x4a, 0xe3, 0x50, 0xf4, 0xac, 0x50, 0xb0, 0x22, 0x02, 0xc7, 0x63, 0xc7, 0x95, 0x8e, 0xa7, 0x3e, - 0xd3, 0x18, 0x97, 0x53, 0x97, 0xb1, 0x67, 0xd6, 0xc8, 0x61, 0x95, 0xfb, 0xff, 0x2e, 0x03, 0x55, - 0x52, 0x8b, 0x24, 0x97, 0x9e, 0x78, 0x71, 0x55, 0x28, 0xed, 0xc6, 0xdf, 0xeb, 0x2b, 0x42, 0xf6, - 0xe0, 0x54, 0xe5, 0xd2, 0xb5, 0x5a, 0xa8, 0xdb, 0xae, 0xea, 0xd3, 0x7d, 0x79, 0xfe, 0x39, 0xb8, - 0x61, 0x8a, 0xa1, 0x2f, 0xc5, 0x33, 0xcb, 0x91, 0xe9, 0x9b, 0x4d, 0x05, 0x0c, 0x03, 0xd5, 0xa3, - 0xe8, 0x2a, 0x53, 0x91, 0xc2, 0x40, 0x7c, 0x6d, 0x84, 0x29, 0x61, 0xef, 0x09, 0xa3, 0xe3, 0xc2, - 0x72, 0x4c, 0xf2, 0x91, 0xef, 0x78, 0xf8, 0x36, 0xba, 0x81, 0x4d, 0x18, 0x3a, 0x94, 0x41, 0x14, - 0xdc, 0xdf, 0x87, 0x9b, 0xf3, 0x8f, 0x12, 0xd4, 0xdd, 0x6c, 0xfa, 0x48, 0x34, 0xdd, 0x75, 0x79, - 0x16, 0x38, 0xea, 0x12, 0x6d, 0x05, 0x0a, 0x07, 0xcf, 0x3d, 0x52, 0x8b, 0x35, 0xa8, 0xed, 0xfb, - 0x29, 0x1e, 0x96, 0xbb, 0xdf, 0x9b, 0x38, 0xfd, 0x49, 0x06, 0x25, 0x6a, 0xc4, 0x52, 0xea, 0x1e, - 0x57, 0x46, 0x9d, 0x2b, 0xd0, 0xff, 0xf9, 0x50, 0xdf, 0xad, 0xd0, 0xa7, 0x2e, 0xb6, 0xfa, 0x6e, - 0x45, 0xdc, 0xcc, 0xbc, 0xfa, 0x80, 0x97, 0xd7, 0x13, 0xae, 0xb0, 0x59, 0xe1, 0xfe, 0x7b, 0xb0, - 0xaa, 0xbb, 0xda, 0x13, 0x61, 0x18, 0xdd, 0x83, 0x3a, 0x0c, 0x9c, 0x33, 0xf5, 0x6d, 0x8c, 0x65, - 0x28, 0x1f, 0x8a, 0x20, 0xf4, 0x3d, 0xfa, 0x2e, 0x08, 0x40, 0xb1, 0x33, 0xb0, 0x02, 0x7c, 0xc7, - 0xfd, 0xaf, 0xe9, 0x41, 0x7a, 0x72, 0x1e, 0x6d, 0x0d, 0xb8, 0x7e, 0xf4, 0x67, 0x71, 0x2c, 0x69, - 0x69, 0x72, 0x19, 0x08, 0x6b, 0xc8, 0xb2, 0xf7, 0x37, 0xa1, 0x42, 0xd7, 0xa8, 0x1e, 0x3b, 0x9e, - 0x8d, 0x1d, 0xdf, 0xd0, 0x25, 0xfd, 0xf4, 0xbd, 0xa6, 0x33, 0x1a, 0x8e, 0xb2, 0xfa, 0xb2, 0x2d, - 0xcb, 0xf2, 0x9b, 0xc0, 0x9b, 0x63, 0xe9, 0x0f, 0x2d, 0xba, 0xfe, 0xeb, 0x5e, 0xa8, 0xaf, 0x20, - 0xe7, 0xee, 0x7f, 0x1b, 0xb8, 0xca, 0xcd, 0xd9, 0xe2, 0xdc, 0xf1, 0xfa, 0xf1, 0x77, 0x07, 0x80, - 0x3e, 0x22, 0x62, 0x8b, 0xf3, 0xe8, 0x0e, 0x5c, 0x04, 0x44, 0x9f, 0x32, 0xd9, 0xf6, 0xc7, 0x1e, - 0x36, 0xfa, 0x29, 0x5c, 0x57, 0x2a, 0x86, 0xbd, 0xa0, 0xbb, 0xa5, 0x97, 0x26, 0x0c, 0xd4, 0x1d, - 0x38, 0x39, 0x0e, 0x63, 0x5a, 0x96, 0xc1, 0x86, 0xc5, 0xc1, 0x76, 0x82, 0xcf, 0xde, 0x37, 0xe0, - 0xda, 0x9c, 0x8c, 0x07, 0x19, 0x75, 0x15, 0xf7, 0xb1, 0xa5, 0xfb, 0x1f, 0xc2, 0x9a, 0x32, 0x43, - 0xfb, 0xea, 0xf6, 0x5f, 0x34, 0x6c, 0xcf, 0xda, 0xdb, 0x6d, 0x35, 0xd2, 0x9b, 0xad, 0xdd, 0xdd, - 0x27, 0xbb, 0x4d, 0x93, 0x65, 0x48, 0x1f, 0x0e, 0xba, 0x47, 0x9b, 0x07, 0xfb, 0xfb, 0xad, 0xcd, - 0x6e, 0x6b, 0x8b, 0x65, 0x37, 0xee, 0xff, 0x87, 0x9f, 0xdf, 0xc9, 0xfc, 0xec, 0xe7, 0x77, 0x32, - 0xff, 0xfd, 0xe7, 0x77, 0x32, 0x3f, 0xfe, 0xf4, 0xce, 0xd2, 0xcf, 0x3e, 0xbd, 0xb3, 0xf4, 0x9f, - 0x3f, 0xbd, 0xb3, 0xf4, 0x09, 0x9b, 0xfe, 0x57, 0x3d, 0xc7, 0x45, 0x0a, 0x2a, 0xde, 0xfa, 0x7f, - 0x01, 0x00, 0x00, 0xff, 0xff, 0x4f, 0x8e, 0xd9, 0xf9, 0xc5, 0x67, 0x00, 0x00, + // 9355 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x7d, 0x5b, 0x6c, 0x23, 0x59, + 0x76, 0x98, 0xf8, 0x26, 0x0f, 0x45, 0xe9, 0xea, 0xf6, 0x8b, 0xc3, 0x6d, 0x77, 0xda, 0xdc, 0xd9, + 0x99, 0x9e, 0xde, 0x59, 0xf5, 0x4c, 0xcf, 0xcc, 0xce, 0xec, 0x78, 0x67, 0x76, 0x29, 0x89, 0x6a, + 0x71, 0x5a, 0xaf, 0x2d, 0xb2, 0xbb, 0x77, 0x06, 0x76, 0x94, 0x12, 0xeb, 0x8a, 0xac, 0x55, 0xb1, + 0x8a, 0x5b, 0x75, 0xa9, 0x96, 0x16, 0x49, 0xb0, 0x71, 0x12, 0x3b, 0x46, 0x7e, 0x36, 0x41, 0x1c, + 0xc7, 0x48, 0x02, 0xef, 0x7e, 0x04, 0x30, 0x6c, 0x07, 0xf9, 0x32, 0x12, 0xe7, 0x01, 0x24, 0xfe, + 0x0a, 0xe0, 0x9f, 0x45, 0xbe, 0x02, 0x24, 0x40, 0x82, 0x5d, 0x20, 0x08, 0x90, 0x87, 0xe1, 0x7c, + 0x39, 0x40, 0x3e, 0x82, 0x73, 0xee, 0xad, 0x17, 0x49, 0xa9, 0xd9, 0x63, 0x3b, 0xc8, 0x97, 0x78, + 0x4f, 0x9d, 0x73, 0xee, 0xfb, 0xdc, 0xf3, 0xba, 0x57, 0xf0, 0xea, 0xf8, 0x74, 0xf0, 0xc0, 0xb1, + 0x8f, 0x1f, 0x8c, 0x8f, 0x1f, 0x8c, 0x3c, 0x4b, 0x38, 0x0f, 0xc6, 0xbe, 0x27, 0xbd, 0x40, 0x15, + 0x82, 0x75, 0x2a, 0xf1, 0x9a, 0xe9, 0x5e, 0xc8, 0x8b, 0xb1, 0x58, 0x27, 0x68, 0xe3, 0xf6, 0xc0, + 0xf3, 0x06, 0x8e, 0x50, 0xa8, 0xc7, 0x93, 0x93, 0x07, 0x81, 0xf4, 0x27, 0x7d, 0xa9, 0x90, 0x9b, + 0x3f, 0xce, 0xc3, 0xcd, 0xee, 0xc8, 0xf4, 0xe5, 0x86, 0xe3, 0xf5, 0x4f, 0xbb, 0xae, 0x39, 0x0e, + 0x86, 0x9e, 0xdc, 0x30, 0x03, 0xc1, 0xdf, 0x84, 0xe2, 0x31, 0x02, 0x83, 0x7a, 0xe6, 0x6e, 0xee, + 0x5e, 0xf5, 0xe1, 0xf5, 0xf5, 0x14, 0xe3, 0x75, 0xa2, 0x30, 0x34, 0x0e, 0x7f, 0x1b, 0x4a, 0x96, + 0x90, 0xa6, 0xed, 0x04, 0xf5, 0xec, 0xdd, 0xcc, 0xbd, 0xea, 0xc3, 0x5b, 0xeb, 0xaa, 0xe2, 0xf5, + 0xb0, 0xe2, 0xf5, 0x2e, 0x55, 0x6c, 0x84, 0x78, 0xfc, 0x7d, 0x28, 0x9f, 0xd8, 0x8e, 0x78, 0x2c, + 0x2e, 0x82, 0x7a, 0xee, 0x4a, 0x9a, 0x8d, 0x6c, 0x3d, 0x63, 0x44, 0xc8, 0x7c, 0x13, 0x56, 0xc4, + 0xb9, 0xf4, 0x4d, 0x43, 0x38, 0xa6, 0xb4, 0x3d, 0x37, 0xa8, 0xe7, 0xa9, 0x85, 0xb7, 0xa6, 0x5a, + 0x18, 0x7e, 0x27, 0xf2, 0x29, 0x12, 0x7e, 0x17, 0xaa, 0xde, 0xf1, 0x77, 0x44, 0x5f, 0xf6, 0x2e, + 0xc6, 0x22, 0xa8, 0x17, 0xee, 0xe6, 0xee, 0x55, 0x8c, 0x24, 0x88, 0x7f, 0x0d, 0xaa, 0x7d, 0xcf, + 0x71, 0x44, 0x5f, 0xd5, 0x51, 0xbc, 0xba, 0x5b, 0x49, 0x5c, 0xfe, 0x2e, 0xdc, 0xf0, 0xc5, 0xc8, + 0x3b, 0x13, 0xd6, 0x66, 0x04, 0xa5, 0x7e, 0x96, 0xa9, 0x9a, 0xf9, 0x1f, 0x79, 0x0b, 0x6a, 0xbe, + 0x6e, 0xdf, 0xae, 0xed, 0x9e, 0x06, 0xf5, 0x12, 0x75, 0xeb, 0x0b, 0x97, 0x74, 0x0b, 0x71, 0x8c, + 0x34, 0x05, 0x67, 0x90, 0x3b, 0x15, 0x17, 0xf5, 0xca, 0xdd, 0xcc, 0xbd, 0x8a, 0x81, 0x3f, 0xf9, + 0x87, 0x50, 0xf7, 0x7c, 0x7b, 0x60, 0xbb, 0xa6, 0xb3, 0xe9, 0x0b, 0x53, 0x0a, 0xab, 0x67, 0x8f, + 0x44, 0x20, 0xcd, 0xd1, 0xb8, 0x0e, 0x77, 0x33, 0xf7, 0x72, 0xc6, 0xa5, 0xdf, 0xf9, 0x3b, 0x6a, + 0x86, 0x3a, 0xee, 0x89, 0x57, 0xaf, 0xea, 0xee, 0xa7, 0xdb, 0xb2, 0xad, 0x3f, 0x1b, 0x11, 0x62, + 0xf3, 0x8f, 0xb3, 0x50, 0xec, 0x0a, 0xd3, 0xef, 0x0f, 0x1b, 0xbf, 0x9c, 0x81, 0xa2, 0x21, 0x82, + 0x89, 0x23, 0x79, 0x03, 0xca, 0x6a, 0x6c, 0x3b, 0x56, 0x3d, 0x43, 0xad, 0x8b, 0xca, 0x9f, 0x67, + 0xed, 0xac, 0x43, 0x7e, 0x24, 0xa4, 0x59, 0xcf, 0xd1, 0x08, 0x35, 0xa6, 0x5a, 0xa5, 0xaa, 0x5f, + 0xdf, 0x13, 0xd2, 0x34, 0x08, 0xaf, 0xf1, 0xd3, 0x0c, 0xe4, 0xb1, 0xc8, 0x6f, 0x43, 0x65, 0x68, + 0x0f, 0x86, 0x8e, 0x3d, 0x18, 0x4a, 0xdd, 0x90, 0x18, 0xc0, 0x3f, 0x86, 0xd5, 0xa8, 0x60, 0x98, + 0xee, 0x40, 0x60, 0x8b, 0xe6, 0x2d, 0x7e, 0xfa, 0x68, 0x4c, 0x23, 0xf3, 0x3a, 0x94, 0x68, 0x3f, + 0x74, 0x2c, 0x5a, 0xd1, 0x15, 0x23, 0x2c, 0xe2, 0x72, 0x0b, 0x67, 0xea, 0xb1, 0xb8, 0xa8, 0xe7, + 0xe9, 0x6b, 0x12, 0xc4, 0x5b, 0xb0, 0x1a, 0x16, 0xb7, 0xf4, 0x68, 0x14, 0xae, 0x1e, 0x8d, 0x69, + 0xfc, 0xe6, 0x6f, 0xee, 0x41, 0x81, 0xb6, 0x25, 0x5f, 0x81, 0xac, 0x1d, 0x0e, 0x74, 0xd6, 0xb6, + 0xf8, 0x03, 0x28, 0x9e, 0xd8, 0xc2, 0xb1, 0x5e, 0x38, 0xc2, 0x1a, 0x8d, 0xb7, 0x61, 0xd9, 0x17, + 0x81, 0xf4, 0x6d, 0xbd, 0xfa, 0xd5, 0x06, 0xfd, 0xd9, 0x79, 0x32, 0x60, 0xdd, 0x48, 0x20, 0x1a, + 0x29, 0x32, 0xec, 0x76, 0x7f, 0x68, 0x3b, 0x96, 0x2f, 0xdc, 0x8e, 0xa5, 0xf6, 0x69, 0xc5, 0x48, + 0x82, 0xf8, 0x3d, 0x58, 0x3d, 0x36, 0xfb, 0xa7, 0x03, 0xdf, 0x9b, 0xb8, 0xb8, 0x21, 0x3c, 0x9f, + 0xba, 0x5d, 0x31, 0xa6, 0xc1, 0xfc, 0x2d, 0x28, 0x98, 0x8e, 0x3d, 0x70, 0x69, 0x27, 0xae, 0xcc, + 0x4c, 0xba, 0x6a, 0x4b, 0x0b, 0x31, 0x0c, 0x85, 0xc8, 0x77, 0xa0, 0x76, 0x26, 0x7c, 0x69, 0xf7, + 0x4d, 0x87, 0xe0, 0xf5, 0x12, 0x51, 0x36, 0xe7, 0x52, 0x3e, 0x4d, 0x62, 0x1a, 0x69, 0x42, 0xde, + 0x01, 0x08, 0x50, 0x4c, 0xd2, 0x74, 0xea, 0xbd, 0xf0, 0xfa, 0x5c, 0x36, 0x9b, 0x9e, 0x2b, 0x85, + 0x2b, 0xd7, 0xbb, 0x11, 0xfa, 0xce, 0x92, 0x91, 0x20, 0xe6, 0xef, 0x43, 0x5e, 0x8a, 0x73, 0x59, + 0x5f, 0xb9, 0x62, 0x44, 0x43, 0x26, 0x3d, 0x71, 0x2e, 0x77, 0x96, 0x0c, 0x22, 0x40, 0x42, 0xdc, + 0x64, 0xf5, 0xd5, 0x05, 0x08, 0x71, 0x5f, 0x22, 0x21, 0x12, 0xf0, 0x8f, 0xa0, 0xe8, 0x98, 0x17, + 0xde, 0x44, 0xd6, 0x19, 0x91, 0x7e, 0xf1, 0x4a, 0xd2, 0x5d, 0x42, 0xdd, 0x59, 0x32, 0x34, 0x11, + 0x7f, 0x17, 0x72, 0x96, 0x7d, 0x56, 0x5f, 0x23, 0xda, 0xbb, 0x57, 0xd2, 0x6e, 0xd9, 0x67, 0x3b, + 0x4b, 0x06, 0xa2, 0xf3, 0x4d, 0x28, 0x1f, 0x7b, 0xde, 0xe9, 0xc8, 0xf4, 0x4f, 0xeb, 0x9c, 0x48, + 0xbf, 0x74, 0x25, 0xe9, 0x86, 0x46, 0xde, 0x59, 0x32, 0x22, 0x42, 0xec, 0xb2, 0xdd, 0xf7, 0xdc, + 0xfa, 0xb5, 0x05, 0xba, 0xdc, 0xe9, 0x7b, 0x2e, 0x76, 0x19, 0x09, 0x90, 0xd0, 0xb1, 0xdd, 0xd3, + 0xfa, 0xf5, 0x05, 0x08, 0x51, 0x72, 0x22, 0x21, 0x12, 0x60, 0xb3, 0x2d, 0x53, 0x9a, 0x67, 0xb6, + 0x78, 0x5e, 0xbf, 0xb1, 0x40, 0xb3, 0xb7, 0x34, 0x32, 0x36, 0x3b, 0x24, 0x44, 0x26, 0xe1, 0xd6, + 0xac, 0xdf, 0x5c, 0x80, 0x49, 0x28, 0xd1, 0x91, 0x49, 0x48, 0xc8, 0xff, 0x3c, 0xac, 0x9d, 0x08, + 0x53, 0x4e, 0x7c, 0x61, 0xc5, 0x07, 0xdd, 0x2d, 0xe2, 0xb6, 0x7e, 0xf5, 0xdc, 0x4f, 0x53, 0xed, + 0x2c, 0x19, 0xb3, 0xac, 0xf8, 0x87, 0x50, 0x70, 0x4c, 0x29, 0xce, 0xeb, 0x75, 0xe2, 0xd9, 0x7c, + 0xc1, 0xa2, 0x90, 0xe2, 0x7c, 0x67, 0xc9, 0x50, 0x24, 0xfc, 0xdb, 0xb0, 0x2a, 0xcd, 0x63, 0x47, + 0x1c, 0x9c, 0x68, 0x84, 0xa0, 0xfe, 0x0a, 0x71, 0x79, 0xf3, 0xea, 0xe5, 0x9c, 0xa6, 0xd9, 0x59, + 0x32, 0xa6, 0xd9, 0x60, 0xab, 0x08, 0x54, 0x6f, 0x2c, 0xd0, 0x2a, 0xe2, 0x87, 0xad, 0x22, 0x12, + 0xbe, 0x0b, 0x55, 0xfa, 0xb1, 0xe9, 0x39, 0x93, 0x91, 0x5b, 0xff, 0x02, 0x71, 0xb8, 0xf7, 0x62, + 0x0e, 0x0a, 0x7f, 0x67, 0xc9, 0x48, 0x92, 0xe3, 0x24, 0x52, 0xd1, 0xf0, 0x9e, 0xd7, 0x6f, 0x2f, + 0x30, 0x89, 0x3d, 0x8d, 0x8c, 0x93, 0x18, 0x12, 0xe2, 0xd6, 0x7b, 0x6e, 0x5b, 0x03, 0x21, 0xeb, + 0x3f, 0xb3, 0xc0, 0xd6, 0x7b, 0x46, 0xa8, 0xb8, 0xf5, 0x14, 0x11, 0x2e, 0xe3, 0xfe, 0xd0, 0x94, + 0xf5, 0x3b, 0x0b, 0x2c, 0xe3, 0xcd, 0xa1, 0x49, 0xb2, 0x02, 0x09, 0x1a, 0xdf, 0x83, 0xe5, 0xa4, + 0x54, 0xe6, 0x1c, 0xf2, 0xbe, 0x30, 0xd5, 0x89, 0x50, 0x36, 0xe8, 0x37, 0xc2, 0x84, 0x65, 0x4b, + 0x3a, 0x11, 0xca, 0x06, 0xfd, 0xe6, 0x37, 0xa1, 0xa8, 0x74, 0x13, 0x12, 0xf8, 0x65, 0x43, 0x97, + 0x10, 0xd7, 0xf2, 0xcd, 0x01, 0x9d, 0x5b, 0x65, 0x83, 0x7e, 0x23, 0xae, 0xe5, 0x7b, 0xe3, 0x03, + 0x97, 0x04, 0x76, 0xd9, 0xd0, 0xa5, 0xc6, 0xdf, 0xfc, 0x18, 0x4a, 0xba, 0x51, 0x8d, 0x7f, 0x98, + 0x81, 0xa2, 0x12, 0x28, 0xfc, 0x1b, 0x50, 0x08, 0xe4, 0x85, 0x23, 0xa8, 0x0d, 0x2b, 0x0f, 0xdf, + 0x58, 0x40, 0x08, 0xad, 0x77, 0x91, 0xc0, 0x50, 0x74, 0x4d, 0x03, 0x0a, 0x54, 0xe6, 0x25, 0xc8, + 0x19, 0xde, 0x73, 0xb6, 0xc4, 0x01, 0x8a, 0x6a, 0xb2, 0x58, 0x06, 0x81, 0x5b, 0xf6, 0x19, 0xcb, + 0x22, 0x70, 0x47, 0x98, 0x96, 0xf0, 0x59, 0x8e, 0xd7, 0xa0, 0x12, 0x4e, 0x4b, 0xc0, 0xf2, 0x9c, + 0xc1, 0x72, 0x62, 0xc2, 0x03, 0x56, 0x68, 0xfc, 0xaf, 0x3c, 0xe4, 0x71, 0xff, 0xf3, 0x57, 0xa1, + 0x26, 0x4d, 0x7f, 0x20, 0x94, 0x22, 0x1c, 0x29, 0x29, 0x69, 0x20, 0xff, 0x28, 0xec, 0x43, 0x96, + 0xfa, 0xf0, 0xfa, 0x0b, 0xe5, 0x4a, 0xaa, 0x07, 0x89, 0x53, 0x38, 0xb7, 0xd8, 0x29, 0xbc, 0x0d, + 0x65, 0x14, 0x67, 0x5d, 0xfb, 0x7b, 0x82, 0x86, 0x7e, 0xe5, 0xe1, 0xfd, 0x17, 0x57, 0xd9, 0xd1, + 0x14, 0x46, 0x44, 0xcb, 0x3b, 0x50, 0xe9, 0x9b, 0xbe, 0x45, 0x8d, 0xa1, 0xd9, 0x5a, 0x79, 0xf8, + 0xe5, 0x17, 0x33, 0xda, 0x0c, 0x49, 0x8c, 0x98, 0x9a, 0x1f, 0x40, 0xd5, 0x12, 0x41, 0xdf, 0xb7, + 0xc7, 0x24, 0xde, 0xd4, 0x59, 0xfc, 0x95, 0x17, 0x33, 0xdb, 0x8a, 0x89, 0x8c, 0x24, 0x07, 0xd4, + 0xc8, 0xfc, 0x48, 0xbe, 0x95, 0x48, 0x41, 0x88, 0x01, 0xcd, 0xf7, 0xa1, 0x1c, 0xf6, 0x87, 0x2f, + 0x43, 0x19, 0xff, 0xee, 0x7b, 0xae, 0x60, 0x4b, 0x38, 0xb7, 0x58, 0xea, 0x8e, 0x4c, 0xc7, 0x61, + 0x19, 0xbe, 0x02, 0x80, 0xc5, 0x3d, 0x61, 0xd9, 0x93, 0x11, 0xcb, 0x36, 0x7f, 0x2e, 0x5c, 0x2d, + 0x65, 0xc8, 0x1f, 0x9a, 0x03, 0xa4, 0x58, 0x86, 0x72, 0x28, 0xae, 0x59, 0x06, 0xe9, 0xb7, 0xcc, + 0x60, 0x78, 0xec, 0x99, 0xbe, 0xc5, 0xb2, 0xbc, 0x0a, 0xa5, 0x96, 0xdf, 0x1f, 0xda, 0x67, 0x82, + 0xe5, 0x9a, 0x0f, 0xa0, 0x9a, 0x68, 0x2f, 0xb2, 0xd0, 0x95, 0x56, 0xa0, 0xd0, 0xb2, 0x2c, 0x61, + 0xb1, 0x0c, 0x12, 0xe8, 0x0e, 0xb2, 0x6c, 0xf3, 0xcb, 0x50, 0x89, 0x46, 0x0b, 0xd1, 0xf1, 0xe0, + 0x66, 0x4b, 0xf8, 0x0b, 0xc1, 0x2c, 0x83, 0xab, 0xb2, 0xe3, 0x3a, 0xb6, 0x2b, 0x58, 0xb6, 0xf1, + 0x17, 0x68, 0xa9, 0xf2, 0xaf, 0xa7, 0x37, 0xc4, 0x6b, 0x2f, 0x3a, 0x59, 0xd3, 0xbb, 0xe1, 0x0b, + 0x89, 0xfe, 0xed, 0xda, 0xd4, 0xb8, 0x32, 0xe4, 0xb7, 0x3c, 0x19, 0xb0, 0x4c, 0xe3, 0xbf, 0x65, + 0xa1, 0x1c, 0x1e, 0xa8, 0x68, 0x13, 0x4c, 0x7c, 0x47, 0x2f, 0x68, 0xfc, 0xc9, 0xaf, 0x43, 0x41, + 0xda, 0x52, 0x2f, 0xe3, 0x8a, 0xa1, 0x0a, 0xa8, 0xab, 0x25, 0x67, 0x56, 0x29, 0xb0, 0xd3, 0x53, + 0x65, 0x8f, 0xcc, 0x81, 0xd8, 0x31, 0x83, 0xa1, 0x56, 0x61, 0x63, 0x00, 0xd2, 0x9f, 0x98, 0x67, + 0xb8, 0xe6, 0xe8, 0xbb, 0xd2, 0xe2, 0x92, 0x20, 0xfe, 0x0e, 0xe4, 0xb1, 0x83, 0x7a, 0xd1, 0xfc, + 0xb9, 0xa9, 0x0e, 0xe3, 0x32, 0x39, 0xf4, 0x05, 0x4e, 0xcf, 0x3a, 0x5a, 0x60, 0x06, 0x21, 0xf3, + 0xd7, 0x60, 0x45, 0x6d, 0xc2, 0x83, 0xd0, 0x7e, 0x28, 0x11, 0xe7, 0x29, 0x28, 0x6f, 0xe1, 0x70, + 0x9a, 0x52, 0xd4, 0xcb, 0x0b, 0xac, 0xef, 0x70, 0x70, 0xd6, 0xbb, 0x48, 0x62, 0x28, 0xca, 0xe6, + 0x7b, 0x38, 0xa6, 0xa6, 0x14, 0x38, 0xcd, 0xed, 0xd1, 0x58, 0x5e, 0xa8, 0x45, 0xb3, 0x2d, 0x64, + 0x7f, 0x68, 0xbb, 0x03, 0x96, 0x51, 0x43, 0x8c, 0x93, 0x48, 0x28, 0xbe, 0xef, 0xf9, 0x2c, 0xd7, + 0x68, 0x40, 0x1e, 0xd7, 0x28, 0x0a, 0x49, 0xd7, 0x1c, 0x09, 0x3d, 0xd2, 0xf4, 0xbb, 0x71, 0x0d, + 0xd6, 0x66, 0xce, 0xe3, 0xc6, 0xef, 0x15, 0xd5, 0x0a, 0x41, 0x0a, 0xd2, 0x05, 0x35, 0x05, 0xa9, + 0x79, 0x2f, 0x25, 0x63, 0x90, 0x4b, 0x5a, 0xc6, 0x7c, 0x04, 0x05, 0xec, 0x58, 0x28, 0x62, 0x16, + 0x20, 0xdf, 0x43, 0x74, 0x43, 0x51, 0xa1, 0x05, 0xd3, 0x1f, 0x8a, 0xfe, 0xa9, 0xb0, 0xb4, 0xac, + 0x0f, 0x8b, 0xb8, 0x68, 0xfa, 0x09, 0xf5, 0x5c, 0x15, 0x68, 0x49, 0xf4, 0x3d, 0xb7, 0x3d, 0xf2, + 0xbe, 0x63, 0xd3, 0xbc, 0xe2, 0x92, 0x08, 0x01, 0xe1, 0xd7, 0x0e, 0xae, 0x11, 0x3d, 0x6d, 0x31, + 0xa0, 0xd1, 0x86, 0x02, 0xd5, 0x8d, 0x3b, 0x41, 0xb5, 0x59, 0x79, 0x1a, 0x5e, 0x5b, 0xac, 0xcd, + 0xba, 0xc9, 0x8d, 0xdf, 0xc9, 0x42, 0x1e, 0xcb, 0xfc, 0x3e, 0x14, 0x7c, 0xb4, 0xc3, 0x68, 0x38, + 0x2f, 0xb3, 0xd9, 0x14, 0x0a, 0xff, 0x86, 0x5e, 0x8a, 0xd9, 0x05, 0x16, 0x4b, 0x54, 0x63, 0x72, + 0x59, 0x5e, 0x87, 0xc2, 0xd8, 0xf4, 0xcd, 0x91, 0xde, 0x27, 0xaa, 0xd0, 0xfc, 0x61, 0x06, 0xf2, + 0x88, 0xc4, 0xd7, 0xa0, 0xd6, 0x95, 0xbe, 0x7d, 0x2a, 0xe4, 0xd0, 0xf7, 0x26, 0x83, 0xa1, 0x5a, + 0x49, 0x8f, 0xc5, 0x85, 0x92, 0x37, 0x4a, 0x20, 0x48, 0xd3, 0xb1, 0xfb, 0x2c, 0x8b, 0xab, 0x6a, + 0xc3, 0x73, 0x2c, 0x96, 0xe3, 0xab, 0x50, 0x7d, 0xe2, 0x5a, 0xc2, 0x0f, 0xfa, 0x9e, 0x2f, 0x2c, + 0x96, 0xd7, 0xbb, 0xfb, 0x94, 0x15, 0xe8, 0x2c, 0x13, 0xe7, 0x92, 0x6c, 0x21, 0x56, 0xe4, 0xd7, + 0x60, 0x75, 0x23, 0x6d, 0x20, 0xb1, 0x12, 0xca, 0xa4, 0x3d, 0xe1, 0xe2, 0x22, 0x63, 0x65, 0xb5, + 0x88, 0xbd, 0xef, 0xd8, 0xac, 0x82, 0x95, 0xa9, 0x7d, 0xc2, 0xa0, 0xf9, 0x2f, 0x33, 0xa1, 0xe4, + 0xa8, 0x41, 0xe5, 0xd0, 0xf4, 0xcd, 0x81, 0x6f, 0x8e, 0xb1, 0x7d, 0x55, 0x28, 0xa9, 0x83, 0xf3, + 0x6d, 0x25, 0xdd, 0x54, 0xe1, 0xa1, 0x92, 0x8d, 0xaa, 0xf0, 0x0e, 0xcb, 0xc5, 0x85, 0x77, 0x59, + 0x1e, 0xeb, 0xf8, 0xd6, 0xc4, 0x93, 0x82, 0x15, 0x48, 0xd6, 0x79, 0x96, 0x60, 0x45, 0x04, 0xf6, + 0x50, 0xa2, 0xb0, 0x12, 0xf6, 0x79, 0x13, 0xd7, 0xcf, 0xb1, 0x77, 0xce, 0xca, 0xd8, 0x0c, 0x1c, + 0x46, 0x61, 0xb1, 0x0a, 0x7e, 0xd9, 0x9f, 0x8c, 0x8e, 0x05, 0x76, 0x13, 0xf0, 0x4b, 0xcf, 0x1b, + 0x0c, 0x1c, 0xc1, 0xaa, 0x38, 0x06, 0x09, 0xe1, 0xcb, 0x96, 0x49, 0xd2, 0x9a, 0x8e, 0xe3, 0x4d, + 0x24, 0xab, 0x35, 0xfe, 0x38, 0x07, 0x79, 0xb4, 0x6e, 0x70, 0xef, 0x0c, 0x51, 0xce, 0xe8, 0xbd, + 0x83, 0xbf, 0xa3, 0x1d, 0x98, 0x8d, 0x77, 0x20, 0xff, 0x50, 0xcf, 0x74, 0x6e, 0x01, 0x29, 0x8b, + 0x8c, 0x93, 0x93, 0xcc, 0x21, 0x3f, 0xb2, 0x47, 0x42, 0xcb, 0x3a, 0xfa, 0x8d, 0xb0, 0x00, 0xcf, + 0xe3, 0x02, 0x39, 0x4f, 0xe8, 0x37, 0xee, 0x1a, 0x13, 0x8f, 0x85, 0x96, 0xa4, 0x3d, 0x90, 0x33, + 0xc2, 0xe2, 0x1c, 0xe9, 0x55, 0x99, 0x2b, 0xbd, 0x3e, 0x0a, 0xa5, 0x57, 0x69, 0x81, 0x5d, 0x4f, + 0xcd, 0x4c, 0x4a, 0xae, 0x58, 0x68, 0x94, 0x17, 0x27, 0x4f, 0x1c, 0x26, 0x5b, 0x7a, 0xd5, 0xc6, + 0x07, 0x5d, 0x59, 0x8d, 0x32, 0xcb, 0xe0, 0x6c, 0xd2, 0x76, 0x55, 0x32, 0xef, 0xa9, 0x6d, 0x09, + 0x8f, 0xe5, 0xe8, 0x20, 0x9c, 0x58, 0xb6, 0xc7, 0xf2, 0xa8, 0x79, 0x1d, 0x6e, 0x6d, 0xb3, 0x42, + 0xf3, 0xb5, 0xc4, 0x91, 0xd4, 0x9a, 0x48, 0x4f, 0xb1, 0xa1, 0xe5, 0x9b, 0x51, 0xab, 0xf1, 0x58, + 0x58, 0x2c, 0xdb, 0xfc, 0xea, 0x1c, 0x31, 0x5b, 0x83, 0xca, 0x93, 0xb1, 0xe3, 0x99, 0xd6, 0x15, + 0x72, 0x76, 0x19, 0x20, 0xb6, 0xaa, 0x1b, 0x3f, 0xfc, 0x62, 0x7c, 0x9c, 0xa3, 0x2e, 0x1a, 0x78, + 0x13, 0xbf, 0x2f, 0x48, 0x84, 0x54, 0x0c, 0x5d, 0xe2, 0xdf, 0x84, 0x02, 0x7e, 0x0f, 0xdd, 0x38, + 0xf7, 0x17, 0xb2, 0xe5, 0xd6, 0x9f, 0xda, 0xe2, 0xb9, 0xa1, 0x08, 0xf9, 0x1d, 0x00, 0xb3, 0x2f, + 0xed, 0x33, 0x81, 0x40, 0xbd, 0xd9, 0x13, 0x10, 0xfe, 0x5e, 0x52, 0x7d, 0xb9, 0xda, 0x0f, 0x99, + 0xd0, 0x6b, 0xb8, 0x01, 0x55, 0xdc, 0xba, 0xe3, 0x03, 0x1f, 0x77, 0x7b, 0x7d, 0x99, 0x08, 0xdf, + 0x5a, 0xac, 0x79, 0x8f, 0x22, 0x42, 0x23, 0xc9, 0x84, 0x3f, 0x81, 0x65, 0xe5, 0x53, 0xd3, 0x4c, + 0x6b, 0xc4, 0xf4, 0xed, 0xc5, 0x98, 0x1e, 0xc4, 0x94, 0x46, 0x8a, 0xcd, 0xac, 0x5b, 0xb2, 0xf0, + 0xd2, 0x6e, 0xc9, 0xd7, 0x60, 0xa5, 0x97, 0xde, 0x05, 0xea, 0xa8, 0x98, 0x82, 0xf2, 0x26, 0x2c, + 0xdb, 0x41, 0xec, 0x15, 0x25, 0x1f, 0x49, 0xd9, 0x48, 0xc1, 0x1a, 0xff, 0xbb, 0x08, 0x79, 0x1a, + 0xf9, 0x69, 0x1f, 0xd7, 0x66, 0x4a, 0xa4, 0x3f, 0x58, 0x7c, 0xaa, 0xa7, 0x76, 0x3c, 0x49, 0x90, + 0x5c, 0x42, 0x82, 0x7c, 0x13, 0x0a, 0x81, 0xe7, 0xcb, 0x70, 0x7a, 0x17, 0x5c, 0x44, 0x5d, 0xcf, + 0x97, 0x86, 0x22, 0xe4, 0xdb, 0x50, 0x3a, 0xb1, 0x1d, 0x89, 0x93, 0xa2, 0x06, 0xef, 0xcd, 0xc5, + 0x78, 0x6c, 0x13, 0x91, 0x11, 0x12, 0xf3, 0xdd, 0xe4, 0x62, 0x2b, 0x12, 0xa7, 0xf5, 0xc5, 0x38, + 0xcd, 0x5b, 0x83, 0xf7, 0x81, 0xf5, 0xbd, 0x33, 0xe1, 0x1b, 0x09, 0xc7, 0xa4, 0x3a, 0xa4, 0x67, + 0xe0, 0xbc, 0x01, 0xe5, 0xa1, 0x6d, 0x09, 0xd4, 0x73, 0x48, 0xc6, 0x94, 0x8d, 0xa8, 0xcc, 0x1f, + 0x43, 0x99, 0xec, 0x03, 0x94, 0x8a, 0x95, 0x97, 0x1e, 0x7c, 0x65, 0xaa, 0x84, 0x0c, 0xb0, 0x22, + 0xaa, 0x7c, 0xdb, 0x96, 0xe4, 0x9f, 0x2e, 0x1b, 0x51, 0x19, 0x1b, 0x4c, 0xeb, 0x3d, 0xd9, 0xe0, + 0xaa, 0x6a, 0xf0, 0x34, 0x9c, 0xbf, 0x0b, 0x37, 0x08, 0x36, 0x75, 0x48, 0xe2, 0x56, 0x43, 0xa6, + 0xf3, 0x3f, 0xa2, 0xc2, 0x32, 0x36, 0x07, 0x62, 0xd7, 0x1e, 0xd9, 0xb2, 0x5e, 0xbb, 0x9b, 0xb9, + 0x57, 0x30, 0x62, 0x00, 0x7f, 0x13, 0xd6, 0x2c, 0x71, 0x62, 0x4e, 0x1c, 0xd9, 0x13, 0xa3, 0xb1, + 0x63, 0x4a, 0xd1, 0xb1, 0x68, 0x8d, 0x56, 0x8c, 0xd9, 0x0f, 0xfc, 0x2d, 0xb8, 0xa6, 0x81, 0x07, + 0x51, 0x54, 0xa1, 0x63, 0x91, 0xfb, 0xae, 0x62, 0xcc, 0xfb, 0x84, 0xdb, 0x44, 0xb8, 0x56, 0xb2, + 0x77, 0x4c, 0x6d, 0x93, 0x34, 0xb4, 0xb9, 0xa7, 0xc5, 0x35, 0x1e, 0xb4, 0x68, 0xcf, 0x86, 0x82, + 0x36, 0x90, 0xea, 0xe4, 0x7e, 0x64, 0x3a, 0x8e, 0xf0, 0x2f, 0x94, 0x31, 0xfc, 0xd8, 0x74, 0x8f, + 0x4d, 0x97, 0xe5, 0xe8, 0x2c, 0x36, 0x1d, 0xe1, 0x5a, 0xa6, 0xaf, 0x4e, 0xee, 0x47, 0x74, 0xf0, + 0x17, 0x9a, 0xf7, 0x20, 0x4f, 0x43, 0x5f, 0x81, 0x82, 0xb2, 0xa6, 0xc8, 0xb2, 0xd6, 0x96, 0x14, + 0x49, 0xee, 0x5d, 0xdc, 0xa6, 0x2c, 0xdb, 0xf8, 0x47, 0x45, 0x28, 0x87, 0x0d, 0x09, 0x63, 0x0d, + 0x99, 0x38, 0xd6, 0x80, 0xea, 0x5e, 0xf0, 0xd4, 0x0e, 0xec, 0x63, 0xad, 0xbe, 0x96, 0x8d, 0x18, + 0x80, 0x1a, 0xd3, 0x73, 0xdb, 0x92, 0x43, 0xda, 0x5b, 0x05, 0x43, 0x15, 0xf8, 0x3d, 0x58, 0xb5, + 0x70, 0xbc, 0xdc, 0xbe, 0x33, 0xb1, 0x44, 0x0f, 0x4f, 0x5b, 0xe5, 0x4e, 0x98, 0x06, 0xf3, 0x4f, + 0x01, 0xa4, 0x3d, 0x12, 0xdb, 0x9e, 0x3f, 0x32, 0xa5, 0xb6, 0x21, 0xbe, 0xf6, 0x72, 0xab, 0x7f, + 0xbd, 0x17, 0x31, 0x30, 0x12, 0xcc, 0x90, 0x35, 0xd6, 0xa6, 0x59, 0x97, 0x3e, 0x17, 0xeb, 0xad, + 0x88, 0x81, 0x91, 0x60, 0xc6, 0x7b, 0x50, 0x3a, 0xf1, 0xfc, 0xd1, 0xc4, 0x31, 0xf5, 0xd9, 0xfc, + 0xe1, 0x4b, 0xf2, 0xdd, 0x56, 0xd4, 0x24, 0xa3, 0x42, 0x56, 0xb1, 0x2f, 0xbc, 0xb2, 0xa0, 0x2f, + 0xbc, 0xf9, 0xf3, 0x00, 0x71, 0x0b, 0xf9, 0x4d, 0xe0, 0x7b, 0x9e, 0x2b, 0x87, 0xad, 0xe3, 0x63, + 0x7f, 0x43, 0x9c, 0x78, 0xbe, 0xd8, 0x32, 0xf1, 0x18, 0xbe, 0x01, 0x6b, 0x11, 0xbc, 0x75, 0x22, + 0x85, 0x8f, 0x60, 0x5a, 0x02, 0xdd, 0xa1, 0xe7, 0x4b, 0xa5, 0x0b, 0xd2, 0xcf, 0x27, 0x5d, 0x96, + 0xc3, 0xa3, 0xbf, 0xd3, 0x3d, 0x60, 0xf9, 0xe6, 0x3d, 0x80, 0x78, 0x68, 0xc9, 0x66, 0xa2, 0x5f, + 0x6f, 0x3f, 0xd4, 0x16, 0x14, 0x95, 0x1e, 0xbe, 0xcb, 0x32, 0xcd, 0x9f, 0x64, 0xa0, 0x9a, 0xe8, + 0x52, 0xda, 0xb6, 0xde, 0xf4, 0x26, 0xae, 0x54, 0xc6, 0x3c, 0xfd, 0x7c, 0x6a, 0x3a, 0x13, 0x54, + 0x02, 0xd6, 0xa0, 0x46, 0xe5, 0x2d, 0x3b, 0x90, 0xb6, 0xdb, 0x97, 0x2c, 0x17, 0xa1, 0x28, 0x05, + 0x22, 0x1f, 0xa1, 0xec, 0x7b, 0x1a, 0x54, 0xe0, 0x0c, 0x96, 0x0f, 0x85, 0xdf, 0x17, 0x21, 0x12, + 0x29, 0xcd, 0x1a, 0x12, 0xa1, 0x29, 0xa5, 0xd9, 0x94, 0xc3, 0xee, 0x64, 0xc4, 0xca, 0xa8, 0x7c, + 0x62, 0xa1, 0x75, 0x26, 0x7c, 0xd4, 0x79, 0x2a, 0x58, 0x0f, 0x02, 0x70, 0x37, 0x98, 0x2e, 0x83, + 0x10, 0x7b, 0xcf, 0x76, 0x59, 0x35, 0x2a, 0x98, 0xe7, 0x6c, 0x19, 0xdb, 0x4f, 0x26, 0x06, 0xab, + 0x35, 0xfe, 0x4b, 0x0e, 0xf2, 0x28, 0xff, 0xd1, 0x26, 0x4e, 0x6e, 0x67, 0xb5, 0x57, 0x92, 0xa0, + 0xcf, 0x77, 0x6a, 0x21, 0xef, 0xe4, 0xa9, 0xf5, 0x01, 0x54, 0xfb, 0x93, 0x40, 0x7a, 0x23, 0x3a, + 0xb2, 0x75, 0x54, 0xec, 0xe6, 0x8c, 0x77, 0x89, 0x86, 0xd3, 0x48, 0xa2, 0xf2, 0xf7, 0xa0, 0x78, + 0xa2, 0x56, 0xbd, 0xf2, 0x2f, 0xfd, 0xcc, 0x25, 0xa7, 0xba, 0x5e, 0xd9, 0x1a, 0x19, 0xfb, 0x65, + 0xcf, 0xec, 0xd8, 0x24, 0x48, 0x9f, 0xce, 0xc5, 0xe8, 0x74, 0xfe, 0x79, 0x58, 0x11, 0x38, 0xe0, + 0x87, 0x8e, 0xd9, 0x17, 0x23, 0xe1, 0x86, 0xdb, 0xec, 0xdd, 0x97, 0xe8, 0x31, 0xcd, 0x18, 0x75, + 0x7b, 0x8a, 0x17, 0x4a, 0x1e, 0xd7, 0x43, 0x25, 0x21, 0x74, 0x00, 0x94, 0x8d, 0x18, 0xd0, 0xfc, + 0x92, 0x96, 0x97, 0x25, 0xc8, 0xb5, 0x82, 0xbe, 0xf6, 0x94, 0x88, 0xa0, 0xaf, 0xcc, 0xb0, 0x4d, + 0x1a, 0x0e, 0x96, 0x6d, 0xbe, 0x0d, 0x95, 0xa8, 0x06, 0x5c, 0x3c, 0xfb, 0x9e, 0xec, 0x8e, 0x45, + 0xdf, 0x3e, 0xb1, 0x85, 0xa5, 0xd6, 0x67, 0x57, 0x9a, 0xbe, 0x54, 0xce, 0xc6, 0xb6, 0x6b, 0xb1, + 0x6c, 0xe3, 0xb7, 0xcb, 0x50, 0x54, 0x87, 0xb4, 0xee, 0x70, 0x25, 0xea, 0xf0, 0xb7, 0xa0, 0xec, + 0x8d, 0x85, 0x6f, 0x4a, 0xcf, 0xd7, 0x1e, 0x9e, 0xf7, 0x5e, 0xe6, 0xd0, 0x5f, 0x3f, 0xd0, 0xc4, + 0x46, 0xc4, 0x66, 0x7a, 0x35, 0x65, 0x67, 0x57, 0xd3, 0x7d, 0x60, 0xe1, 0xf9, 0x7e, 0xe8, 0x23, + 0x9d, 0xbc, 0xd0, 0xf6, 0xfa, 0x0c, 0x9c, 0xf7, 0xa0, 0xd2, 0xf7, 0x5c, 0xcb, 0x8e, 0xbc, 0x3d, + 0x2b, 0x0f, 0xbf, 0xfa, 0x52, 0x2d, 0xdc, 0x0c, 0xa9, 0x8d, 0x98, 0x11, 0x7f, 0x13, 0x0a, 0x67, + 0xb8, 0xcc, 0x68, 0x3d, 0x5d, 0xbe, 0x08, 0x15, 0x12, 0xff, 0x0c, 0xaa, 0xdf, 0x9d, 0xd8, 0xfd, + 0xd3, 0x83, 0xa4, 0x37, 0xf1, 0x83, 0x97, 0x6a, 0xc5, 0xb7, 0x62, 0x7a, 0x23, 0xc9, 0x2c, 0xb1, + 0xb4, 0x4b, 0x7f, 0x82, 0xa5, 0x5d, 0x9e, 0x5d, 0xda, 0x06, 0xd4, 0x5c, 0x11, 0x48, 0x61, 0x6d, + 0x6b, 0x9d, 0x0e, 0x3e, 0x87, 0x4e, 0x97, 0x66, 0xd1, 0xfc, 0x22, 0x94, 0xc3, 0x09, 0xe7, 0x45, + 0xc8, 0xee, 0xa3, 0xf1, 0x54, 0x84, 0xec, 0x81, 0xaf, 0x56, 0x5b, 0x0b, 0x57, 0x5b, 0xf3, 0x0f, + 0x33, 0x50, 0x89, 0x06, 0x3d, 0x2d, 0x39, 0xdb, 0xdf, 0x9d, 0x98, 0x0e, 0xcb, 0x90, 0x59, 0xed, + 0x49, 0x55, 0x22, 0x61, 0xfd, 0x88, 0x82, 0xfa, 0x3e, 0xcb, 0x91, 0x8a, 0x20, 0x82, 0x80, 0xe5, + 0x39, 0x87, 0x15, 0x0d, 0x3e, 0xf0, 0x15, 0x6a, 0x01, 0x05, 0x1f, 0x7e, 0x0d, 0x01, 0x45, 0xa5, + 0x51, 0x9c, 0x0a, 0x25, 0x20, 0xf7, 0x3d, 0x49, 0x85, 0x32, 0x36, 0xaa, 0xe3, 0xb2, 0x0a, 0xd6, + 0xb9, 0xef, 0xc9, 0x0e, 0x8a, 0xc4, 0xc8, 0x8c, 0xab, 0x86, 0xd5, 0x53, 0x89, 0x24, 0x62, 0xcb, + 0x71, 0x3a, 0x2e, 0xab, 0xe9, 0x0f, 0xaa, 0xb4, 0x82, 0x1c, 0xdb, 0xe7, 0x66, 0x1f, 0xc9, 0x57, + 0x51, 0xc2, 0x22, 0x8d, 0x2e, 0x33, 0xdc, 0x92, 0xed, 0x73, 0x3b, 0x90, 0x01, 0x5b, 0x6b, 0xfe, + 0x41, 0x06, 0xaa, 0x89, 0x09, 0x46, 0x33, 0x91, 0x10, 0xf1, 0x28, 0x53, 0x56, 0xe3, 0xa7, 0x38, + 0x8c, 0xbe, 0x15, 0x1e, 0x53, 0x3d, 0x0f, 0x7f, 0x66, 0xb1, 0xbe, 0x9e, 0x37, 0xf2, 0x7c, 0xdf, + 0x7b, 0xae, 0x54, 0x9f, 0x5d, 0x33, 0x90, 0xcf, 0x84, 0x38, 0x65, 0x79, 0xec, 0xea, 0xe6, 0xc4, + 0xf7, 0x85, 0xab, 0x00, 0x05, 0x6a, 0x9c, 0x38, 0x57, 0xa5, 0x22, 0x32, 0x45, 0x64, 0x3a, 0x07, + 0x59, 0x09, 0x05, 0x81, 0xc6, 0x56, 0x90, 0x32, 0x22, 0x20, 0xba, 0x2a, 0x56, 0xf0, 0x50, 0x51, + 0x9e, 0x8c, 0x83, 0x93, 0x2d, 0xf3, 0x22, 0x68, 0x0d, 0x3c, 0x06, 0xd3, 0xc0, 0x7d, 0xef, 0x39, + 0xab, 0x36, 0x26, 0x00, 0xb1, 0xed, 0x86, 0x36, 0x2b, 0x2e, 0x88, 0x28, 0xd6, 0xa0, 0x4b, 0xfc, + 0x00, 0x00, 0x7f, 0x11, 0x66, 0x68, 0xb8, 0xbe, 0x84, 0x42, 0x4d, 0x74, 0x46, 0x82, 0x45, 0xe3, + 0x2f, 0x41, 0x25, 0xfa, 0xc0, 0xeb, 0x50, 0x22, 0xd5, 0x37, 0xaa, 0x36, 0x2c, 0xa2, 0x7e, 0x66, + 0xbb, 0x96, 0x38, 0x27, 0xb9, 0x52, 0x30, 0x54, 0x01, 0x5b, 0x39, 0xb4, 0x2d, 0x4b, 0xb8, 0x61, + 0x44, 0x48, 0x95, 0xe6, 0xc5, 0xed, 0xf3, 0x73, 0xe3, 0xf6, 0x8d, 0x5f, 0x80, 0x6a, 0xc2, 0xb8, + 0xbc, 0xb4, 0xdb, 0x89, 0x86, 0x65, 0xd3, 0x0d, 0xbb, 0x0d, 0x95, 0x30, 0x57, 0x24, 0xa0, 0xb3, + 0xad, 0x62, 0xc4, 0x80, 0xc6, 0x3f, 0xcd, 0xa2, 0x26, 0x8b, 0x5d, 0x9b, 0x36, 0x08, 0xb7, 0xa1, + 0x18, 0x48, 0x53, 0x4e, 0xc2, 0xa4, 0x87, 0x05, 0x37, 0x68, 0x97, 0x68, 0x76, 0x96, 0x0c, 0x4d, + 0xcd, 0x3f, 0x82, 0x9c, 0x34, 0x07, 0xda, 0xa1, 0xfa, 0xc6, 0x62, 0x4c, 0x7a, 0xe6, 0x60, 0x67, + 0xc9, 0x40, 0x3a, 0xbe, 0x0b, 0xe5, 0xbe, 0xf6, 0x81, 0x69, 0xa1, 0xb8, 0xa0, 0xcd, 0x16, 0x7a, + 0xce, 0x76, 0x96, 0x8c, 0x88, 0x03, 0xff, 0x26, 0xe4, 0x51, 0xbb, 0xd4, 0xb9, 0x21, 0x0b, 0xda, + 0xa2, 0xb8, 0x5d, 0x76, 0x96, 0x0c, 0xa2, 0xdc, 0x28, 0x41, 0x81, 0x64, 0x70, 0xa3, 0x0e, 0x45, + 0xd5, 0xd7, 0xe9, 0x91, 0x6b, 0xdc, 0x82, 0x5c, 0xcf, 0x1c, 0xa0, 0x86, 0x6f, 0x5b, 0x81, 0x76, + 0xa9, 0xe0, 0xcf, 0xc6, 0xab, 0xb1, 0x3f, 0x2f, 0xe9, 0x2a, 0xce, 0xa4, 0x5c, 0xc5, 0x8d, 0x22, + 0xe4, 0xb1, 0xc6, 0xc6, 0xed, 0xab, 0xac, 0x85, 0xc6, 0x6f, 0xe5, 0xd0, 0xb0, 0x90, 0xe2, 0x7c, + 0xae, 0x1b, 0xfc, 0x13, 0xa8, 0x8c, 0x7d, 0xaf, 0x2f, 0x82, 0xc0, 0xf3, 0xb5, 0x72, 0xf4, 0xe6, + 0x8b, 0x43, 0xd4, 0xeb, 0x87, 0x21, 0x8d, 0x11, 0x93, 0x37, 0xff, 0x75, 0x16, 0x2a, 0xd1, 0x07, + 0x65, 0xcf, 0x48, 0x71, 0xae, 0x5c, 0x9e, 0x7b, 0xc2, 0x1f, 0x99, 0xb6, 0xa5, 0xa4, 0xc7, 0xe6, + 0xd0, 0x0c, 0x95, 0xdc, 0x4f, 0xbd, 0x89, 0x9c, 0x1c, 0x0b, 0xe5, 0xea, 0x7a, 0x6a, 0x8f, 0x84, + 0xc7, 0xf2, 0x14, 0x64, 0xc2, 0x85, 0xdd, 0x77, 0xbc, 0x89, 0xc5, 0x0a, 0x58, 0x7e, 0x44, 0xc7, + 0xdb, 0x9e, 0x39, 0x0e, 0x94, 0xcc, 0xdc, 0xb3, 0x7d, 0x8f, 0x95, 0x90, 0x68, 0xdb, 0x1e, 0x8c, + 0x4c, 0x56, 0x46, 0x66, 0xbd, 0xe7, 0xb6, 0x44, 0x21, 0x5c, 0x41, 0x35, 0xf5, 0x60, 0x2c, 0xdc, + 0xae, 0xf4, 0x85, 0x90, 0x7b, 0xe6, 0x58, 0xf9, 0x3e, 0x0d, 0x61, 0x59, 0xb6, 0x54, 0xf2, 0x73, + 0xdb, 0xec, 0x8b, 0x63, 0xcf, 0x3b, 0x65, 0xcb, 0x28, 0x68, 0x3a, 0x6e, 0x20, 0xcd, 0x81, 0x6f, + 0x8e, 0x94, 0x0c, 0xed, 0x09, 0x47, 0x50, 0x69, 0x85, 0xea, 0xb6, 0xe5, 0x70, 0x72, 0xfc, 0x08, + 0xed, 0xbe, 0x55, 0x15, 0x8f, 0xb2, 0xc4, 0x58, 0xa0, 0x0c, 0x5d, 0x86, 0xf2, 0x86, 0xed, 0xd8, + 0xc7, 0xb6, 0x63, 0xb3, 0x35, 0x44, 0x6d, 0x9f, 0xf7, 0x4d, 0xc7, 0xb6, 0x7c, 0xf3, 0x39, 0xe3, + 0xd8, 0xb8, 0xc7, 0xbe, 0x77, 0x6a, 0xb3, 0x6b, 0x88, 0x48, 0x66, 0xe0, 0x99, 0xfd, 0x3d, 0x76, + 0x9d, 0x62, 0x6a, 0xa7, 0x42, 0xf6, 0x87, 0x27, 0xe6, 0x31, 0xbb, 0x11, 0xbb, 0xfe, 0x6e, 0x36, + 0xd6, 0x60, 0x75, 0x2a, 0x7a, 0xdf, 0x28, 0x69, 0xeb, 0xb3, 0x51, 0x83, 0x6a, 0x22, 0xac, 0xda, + 0x78, 0x0d, 0xca, 0x61, 0xd0, 0x15, 0xad, 0x79, 0x3b, 0x50, 0xee, 0x62, 0xbd, 0x48, 0xa2, 0x72, + 0xe3, 0x3f, 0x64, 0xa0, 0xa8, 0x22, 0xde, 0x7c, 0x23, 0xca, 0x50, 0xc9, 0x2c, 0x10, 0xe5, 0x54, + 0x44, 0x3a, 0x46, 0x1c, 0xa5, 0xa9, 0x5c, 0x87, 0x82, 0x43, 0x66, 0xbb, 0x16, 0x5f, 0x54, 0x48, + 0x48, 0x9b, 0x5c, 0x4a, 0xda, 0xdc, 0x86, 0x8a, 0x39, 0x91, 0x1e, 0x05, 0xf3, 0x74, 0xa4, 0x23, + 0x06, 0x34, 0x5b, 0x51, 0xd4, 0x3a, 0x74, 0x60, 0x92, 0xce, 0xd8, 0xf3, 0x85, 0x50, 0xce, 0x49, + 0xb2, 0xb5, 0xb3, 0x74, 0x92, 0x78, 0xa3, 0xb1, 0xd9, 0x97, 0x04, 0xa0, 0x33, 0x16, 0x45, 0x2d, + 0xcb, 0xe3, 0x1e, 0xd8, 0x1c, 0x9a, 0xb2, 0x79, 0x02, 0xe5, 0x43, 0x2f, 0x98, 0x3e, 0xb1, 0x4b, + 0x90, 0xeb, 0x79, 0x63, 0xa5, 0x7f, 0x6e, 0x78, 0x92, 0xf4, 0x4f, 0x75, 0x40, 0x9f, 0x48, 0xb5, + 0xe4, 0x0c, 0x7b, 0x30, 0x94, 0xca, 0x4e, 0xef, 0xb8, 0xae, 0xf0, 0x59, 0x01, 0x67, 0xd8, 0x10, + 0x63, 0xd4, 0x79, 0x59, 0x11, 0xe7, 0x94, 0xe0, 0xdb, 0xb6, 0x1f, 0x48, 0x56, 0x6a, 0x76, 0xf0, + 0xac, 0xb5, 0x07, 0x74, 0x44, 0xd2, 0x0f, 0x62, 0xb5, 0x84, 0x4d, 0xa4, 0xe2, 0xa6, 0x70, 0x71, + 0x05, 0x92, 0x6d, 0xa5, 0x0c, 0x43, 0xaa, 0x20, 0x8b, 0xe7, 0x1b, 0x95, 0x3f, 0x99, 0x04, 0xd2, + 0x3e, 0xb9, 0x60, 0xb9, 0xe6, 0x33, 0xa8, 0xa5, 0x92, 0xa1, 0xf8, 0x75, 0x60, 0x29, 0x00, 0x36, + 0x7d, 0x89, 0xdf, 0x82, 0x6b, 0x29, 0xe8, 0x9e, 0x6d, 0x59, 0xe4, 0x31, 0x9e, 0xfe, 0x10, 0x76, + 0x70, 0xa3, 0x02, 0xa5, 0xbe, 0x9a, 0xc3, 0xe6, 0x21, 0xd4, 0x68, 0x52, 0xf7, 0x84, 0x34, 0x0f, + 0x5c, 0xe7, 0xe2, 0x4f, 0x9c, 0xb1, 0xd6, 0xfc, 0xb2, 0x36, 0xbf, 0x50, 0x9a, 0x9c, 0xf8, 0xde, + 0x88, 0x78, 0x15, 0x0c, 0xfa, 0x8d, 0xdc, 0xa5, 0xa7, 0x57, 0x46, 0x56, 0x7a, 0xcd, 0xff, 0x5a, + 0x85, 0x52, 0xab, 0xdf, 0x47, 0x83, 0x71, 0xa6, 0xe6, 0xf7, 0xa0, 0xd8, 0xf7, 0xdc, 0x13, 0x7b, + 0xa0, 0xa5, 0xf5, 0xb4, 0xde, 0xa8, 0xe9, 0x70, 0x39, 0x9e, 0xd8, 0x03, 0x43, 0x23, 0x23, 0x99, + 0x3e, 0x6d, 0x0a, 0x57, 0x92, 0x29, 0x91, 0x1b, 0x1d, 0x2e, 0x0f, 0x20, 0x6f, 0xbb, 0x27, 0x9e, + 0x4e, 0x2f, 0xfd, 0xc2, 0x25, 0x44, 0x94, 0x63, 0x49, 0x88, 0x8d, 0xff, 0x94, 0x81, 0xa2, 0xaa, + 0x5a, 0xf9, 0x8b, 0x70, 0xab, 0x85, 0x82, 0x5e, 0xef, 0xb1, 0x29, 0x28, 0xaa, 0xb4, 0x1a, 0x22, + 0x8e, 0x27, 0x03, 0xed, 0x99, 0x49, 0x82, 0xf8, 0x07, 0x70, 0x4b, 0x15, 0x0f, 0x7d, 0xe1, 0x0b, + 0x47, 0x98, 0x81, 0xd8, 0x1c, 0x9a, 0xae, 0x2b, 0x1c, 0x7d, 0xec, 0x5f, 0xf6, 0x99, 0x37, 0x61, + 0x59, 0x7d, 0xea, 0x8e, 0xcd, 0xbe, 0x08, 0xf4, 0x5e, 0x4a, 0xc1, 0xf8, 0x57, 0xa0, 0x40, 0xd9, + 0xb7, 0x75, 0xeb, 0xea, 0xa9, 0x54, 0x58, 0x0d, 0x2f, 0x3a, 0x97, 0x5a, 0x00, 0x6a, 0x98, 0xd0, + 0x24, 0xd3, 0xb2, 0xe1, 0x67, 0xaf, 0x1c, 0x57, 0xb2, 0x0e, 0x13, 0x44, 0xd8, 0x3e, 0x4b, 0x38, + 0x82, 0xd2, 0x24, 0xf1, 0xdc, 0xcc, 0x52, 0x7c, 0x26, 0x05, 0x6b, 0xfc, 0xc7, 0x3c, 0xe4, 0x71, + 0x84, 0x11, 0x79, 0xe8, 0x8d, 0x44, 0xe4, 0xa5, 0x56, 0x8a, 0x48, 0x0a, 0x86, 0x8a, 0x8f, 0xa9, + 0x12, 0x05, 0x22, 0x34, 0x25, 0x5a, 0xa6, 0xc1, 0x88, 0x39, 0xf6, 0xbd, 0x13, 0xdb, 0x89, 0x31, + 0xb5, 0x8a, 0x34, 0x05, 0xe6, 0x5f, 0x85, 0x9b, 0x23, 0xd3, 0x3f, 0x15, 0x92, 0x76, 0xf7, 0x33, + 0xcf, 0x3f, 0x0d, 0x70, 0xe4, 0x3a, 0x96, 0x76, 0x6f, 0x5e, 0xf2, 0x95, 0xbf, 0x09, 0x6b, 0xcf, + 0xc3, 0x62, 0x54, 0x87, 0x72, 0x30, 0xce, 0x7e, 0x40, 0x61, 0x6c, 0x89, 0x33, 0x9b, 0xf8, 0x96, + 0x55, 0x0e, 0x6e, 0x58, 0xc6, 0xa5, 0x64, 0xaa, 0x81, 0xec, 0xea, 0x9a, 0x75, 0x9c, 0x2a, 0x0d, + 0x45, 0xb9, 0xa9, 0x72, 0x93, 0x82, 0x8e, 0x45, 0xfe, 0xd9, 0x8a, 0x11, 0x03, 0x70, 0xa1, 0x51, + 0x95, 0x4f, 0x95, 0xc8, 0xad, 0x29, 0x03, 0x35, 0x01, 0x42, 0x0c, 0x29, 0xfa, 0xc3, 0xb0, 0x12, + 0xe5, 0x3c, 0x4d, 0x82, 0xf8, 0x1d, 0x80, 0x81, 0x29, 0xc5, 0x73, 0xf3, 0xe2, 0x89, 0xef, 0xd4, + 0x85, 0x0a, 0xb8, 0xc4, 0x10, 0x34, 0x71, 0x1d, 0xaf, 0x6f, 0x3a, 0x5d, 0xe9, 0xf9, 0xe6, 0x40, + 0x1c, 0x9a, 0x72, 0x58, 0x1f, 0x28, 0x13, 0x77, 0x1a, 0x8e, 0x3d, 0x96, 0xf6, 0x48, 0x7c, 0xe6, + 0xb9, 0xa2, 0x3e, 0x54, 0x3d, 0x0e, 0xcb, 0xd8, 0x12, 0xd3, 0x35, 0x9d, 0x0b, 0x69, 0xf7, 0xb1, + 0x2f, 0xb6, 0x6a, 0x49, 0x02, 0x44, 0x4e, 0x05, 0x21, 0x71, 0x1c, 0x3b, 0x56, 0xfd, 0x3b, 0xaa, + 0xaf, 0x11, 0x00, 0x67, 0x57, 0xc8, 0xa1, 0xf0, 0xc5, 0x64, 0xd4, 0xb2, 0x2c, 0x5f, 0x04, 0x41, + 0xfd, 0x54, 0xcd, 0xee, 0x14, 0xb8, 0xf1, 0x5b, 0x59, 0x8a, 0x87, 0x0d, 0x1b, 0xff, 0x3d, 0x03, + 0xa5, 0xd6, 0x78, 0x4c, 0x4b, 0xad, 0x0e, 0x25, 0x73, 0x3c, 0xde, 0x89, 0x23, 0x98, 0x61, 0x51, + 0x7f, 0xd9, 0x8f, 0xe3, 0x98, 0x61, 0x11, 0x0f, 0x33, 0x73, 0x3c, 0x8e, 0xf3, 0x87, 0x75, 0x09, + 0x1b, 0xda, 0x57, 0xb9, 0xdb, 0x2d, 0xa9, 0xe3, 0x92, 0x31, 0x00, 0x07, 0x41, 0x9c, 0x8f, 0x6d, + 0x5f, 0x44, 0xd1, 0xc9, 0xa8, 0x4c, 0x49, 0x59, 0x7d, 0x6f, 0x1c, 0x86, 0x1d, 0xdf, 0xb8, 0x64, + 0x6f, 0x61, 0xeb, 0xd7, 0x77, 0x71, 0x74, 0x5b, 0x63, 0xbb, 0x8b, 0x04, 0x86, 0xa2, 0x53, 0x07, + 0x7c, 0x8b, 0xc2, 0x61, 0x61, 0x5c, 0x20, 0x2c, 0x37, 0xdf, 0x81, 0x5a, 0x8a, 0x06, 0x0f, 0x30, + 0x72, 0xa4, 0x93, 0x3b, 0xa5, 0x0a, 0xa5, 0x4f, 0x02, 0xcf, 0x6d, 0x1d, 0x76, 0xd4, 0x91, 0xba, + 0x3d, 0x71, 0x1c, 0x96, 0x6d, 0x1e, 0x00, 0xc4, 0x3b, 0x19, 0x8f, 0x47, 0xc5, 0x8c, 0x2d, 0x29, + 0xe7, 0x9d, 0x6b, 0xd9, 0xee, 0x60, 0x4b, 0x6f, 0x5e, 0x96, 0x41, 0x20, 0x39, 0x65, 0x84, 0x15, + 0x01, 0x49, 0x7d, 0xa3, 0x92, 0xb0, 0x58, 0xae, 0xf9, 0x7f, 0x32, 0x50, 0x4d, 0xa4, 0x96, 0xfc, + 0x29, 0xa6, 0xc3, 0x60, 0xdf, 0x51, 0x3d, 0xc2, 0x75, 0xaa, 0x26, 0x24, 0x2a, 0xe3, 0x2a, 0xd6, + 0x99, 0x2f, 0xf8, 0x55, 0xb9, 0x60, 0x12, 0x90, 0xcf, 0x95, 0x0a, 0xd3, 0x7c, 0xa8, 0xfd, 0x58, + 0x55, 0x28, 0x3d, 0x71, 0x4f, 0x5d, 0xef, 0xb9, 0xab, 0xf4, 0x12, 0xca, 0x6f, 0x4a, 0x45, 0x6a, + 0xc3, 0x14, 0xa4, 0x5c, 0xf3, 0x5f, 0xe4, 0xa7, 0x52, 0x01, 0xdb, 0x50, 0x54, 0xc6, 0x13, 0xe9, + 0xf5, 0xb3, 0xb9, 0x5b, 0x49, 0x64, 0x1d, 0x15, 0x4c, 0x80, 0x0c, 0x4d, 0x8c, 0x56, 0x4d, 0x94, + 0x28, 0x9b, 0x9d, 0x1b, 0xbd, 0x4c, 0x31, 0x0a, 0xcf, 0xa2, 0x54, 0xae, 0x78, 0xc4, 0xa1, 0xf1, + 0xd7, 0x33, 0x70, 0x7d, 0x1e, 0x4a, 0x32, 0xa3, 0x3e, 0x93, 0xce, 0xa8, 0xef, 0x4e, 0x65, 0xa8, + 0x67, 0xa9, 0x37, 0x0f, 0x5e, 0xb2, 0x11, 0xe9, 0x7c, 0xf5, 0xe6, 0xef, 0x65, 0x60, 0x6d, 0xa6, + 0xcf, 0x09, 0xbd, 0x0d, 0xa0, 0xa8, 0x56, 0x96, 0x4a, 0x20, 0x8b, 0x52, 0x7a, 0x54, 0xa8, 0x85, + 0x34, 0x9a, 0x40, 0xe5, 0x48, 0xe8, 0x9c, 0x7c, 0x65, 0x34, 0xe0, 0xac, 0xe1, 0x81, 0x39, 0x10, + 0xca, 0x2d, 0xad, 0x94, 0x4b, 0x0d, 0x29, 0x2a, 0xc5, 0x5e, 0xc5, 0x8d, 0x58, 0x89, 0x12, 0xd3, + 0x26, 0x63, 0xc7, 0xee, 0x63, 0xb1, 0xcc, 0x1b, 0x70, 0x53, 0x5d, 0xcc, 0xd0, 0x46, 0xf4, 0x49, + 0x6f, 0x68, 0xd3, 0xe6, 0x60, 0x15, 0xac, 0xe7, 0x70, 0x72, 0xec, 0xd8, 0xc1, 0x90, 0x41, 0xd3, + 0x80, 0x6b, 0x73, 0x3a, 0x48, 0x4d, 0x7e, 0xaa, 0x9b, 0xbf, 0x02, 0xb0, 0xf5, 0x34, 0x6c, 0x34, + 0xcb, 0x70, 0x0e, 0x2b, 0x5b, 0x4f, 0x93, 0xdc, 0xf5, 0xe6, 0x79, 0x8a, 0xd2, 0x3a, 0x60, 0xb9, + 0xe6, 0x2f, 0x65, 0xc2, 0xcc, 0x91, 0xc6, 0x5f, 0x84, 0x9a, 0x6a, 0xf0, 0xa1, 0x79, 0xe1, 0x78, + 0xa6, 0xc5, 0xdb, 0xb0, 0x12, 0x44, 0x57, 0x87, 0x12, 0x07, 0xf4, 0xb4, 0xe2, 0xd3, 0x4d, 0x21, + 0x19, 0x53, 0x44, 0xa1, 0x61, 0x98, 0x8d, 0xc3, 0x48, 0x9c, 0x4c, 0x5c, 0x93, 0xb6, 0xdc, 0x32, + 0x19, 0xad, 0x66, 0xf3, 0x2b, 0xb0, 0xd6, 0x8d, 0x0f, 0x33, 0x65, 0x41, 0xe0, 0xe2, 0x50, 0x27, + 0xe1, 0x56, 0xb8, 0x38, 0x74, 0xb1, 0xf9, 0x8f, 0x4b, 0x00, 0x71, 0x68, 0x6d, 0xce, 0x9e, 0x9f, + 0x97, 0x29, 0x32, 0x13, 0xe8, 0xce, 0xbd, 0x74, 0xa0, 0xfb, 0x83, 0xc8, 0x90, 0x51, 0xee, 0xf4, + 0xe9, 0x74, 0xf9, 0xb8, 0x4d, 0xd3, 0xe6, 0x4b, 0x2a, 0x91, 0xaa, 0x30, 0x9d, 0x48, 0x75, 0x77, + 0x36, 0xeb, 0x72, 0x4a, 0x18, 0xc5, 0x7e, 0x9a, 0x52, 0xca, 0x4f, 0xd3, 0x80, 0xb2, 0x2f, 0x4c, + 0xcb, 0x73, 0x9d, 0x8b, 0x30, 0x9e, 0x1a, 0x96, 0xf9, 0x3b, 0x50, 0x90, 0x74, 0xfb, 0xa9, 0x4c, + 0x7b, 0xe7, 0x05, 0x13, 0xa7, 0x70, 0x51, 0xb2, 0xd9, 0x81, 0x4e, 0x95, 0x54, 0x5a, 0x42, 0xd9, + 0x48, 0x40, 0xf8, 0x3a, 0x70, 0x1b, 0x8d, 0x56, 0xc7, 0x11, 0xd6, 0xc6, 0xc5, 0x96, 0x0a, 0x73, + 0x92, 0x1e, 0x53, 0x36, 0xe6, 0x7c, 0x09, 0xe7, 0x7f, 0x39, 0x9e, 0x7f, 0x6a, 0xf2, 0x99, 0x1d, + 0x60, 0x4f, 0x6b, 0xea, 0xc0, 0x0a, 0xcb, 0xa8, 0x29, 0x85, 0x1b, 0x56, 0x8d, 0x25, 0xad, 0xde, + 0x38, 0x57, 0xe0, 0x92, 0xaf, 0xe1, 0xf0, 0x2a, 0x47, 0xd5, 0xaa, 0x3a, 0x22, 0x23, 0x00, 0x49, + 0xf2, 0xbe, 0xe7, 0xd2, 0x99, 0xcb, 0xb4, 0x24, 0xd7, 0x65, 0xec, 0xef, 0xd8, 0x99, 0xf8, 0xa6, + 0x43, 0x5f, 0xd7, 0x94, 0x24, 0x8f, 0x21, 0xcd, 0xdf, 0xcf, 0x46, 0xc6, 0x62, 0x05, 0x0a, 0xc7, + 0x66, 0x60, 0xf7, 0xd5, 0xe9, 0xa6, 0x95, 0x3c, 0x75, 0xba, 0x49, 0xcf, 0xf2, 0x58, 0x16, 0xed, + 0xbe, 0x40, 0xe8, 0xf0, 0x55, 0x7c, 0xd7, 0x8c, 0xe5, 0x51, 0x04, 0x84, 0x2b, 0x49, 0xe5, 0x52, + 0x11, 0x29, 0x39, 0x23, 0xad, 0x28, 0x4b, 0x95, 0xdc, 0x0a, 0x74, 0xc4, 0xb0, 0x32, 0xe2, 0xb8, + 0x9e, 0x14, 0xca, 0x15, 0x4b, 0xeb, 0x9e, 0x01, 0xb2, 0x09, 0x2f, 0x4f, 0xb0, 0x2a, 0x1a, 0x62, + 0x21, 0x53, 0xe5, 0x3f, 0x0d, 0xc8, 0x4c, 0x5d, 0xc6, 0x7d, 0x9f, 0xfe, 0xc0, 0x6a, 0xd8, 0xa2, + 0xf8, 0x0a, 0x1b, 0x5b, 0x41, 0xae, 0x26, 0x65, 0xf8, 0xac, 0xe2, 0xcf, 0x33, 0xca, 0xfb, 0x61, + 0x58, 0xab, 0x85, 0x72, 0x69, 0x0d, 0x5b, 0x16, 0x29, 0x76, 0x8c, 0xa3, 0x9d, 0x39, 0x36, 0xd1, + 0xe8, 0xb3, 0xc7, 0xa6, 0x2b, 0xd9, 0x35, 0xec, 0xea, 0xd8, 0x3a, 0x61, 0xd7, 0x91, 0xa4, 0x3f, + 0x34, 0x25, 0xbb, 0x81, 0x38, 0xf8, 0x6b, 0x4b, 0xf8, 0xb8, 0x52, 0xd8, 0x4d, 0xc4, 0x91, 0xe6, + 0x80, 0xdd, 0x6a, 0xfe, 0x6a, 0x9c, 0x27, 0xfe, 0x56, 0x64, 0x8e, 0x2d, 0xb2, 0x7d, 0xd0, 0x60, + 0x9b, 0xb7, 0x97, 0xdb, 0xb0, 0xe6, 0x8b, 0xef, 0x4e, 0xec, 0xd4, 0xed, 0x89, 0xdc, 0xd5, 0xe9, + 0x39, 0xb3, 0x14, 0xcd, 0x33, 0x58, 0x0b, 0x0b, 0xcf, 0x6c, 0x39, 0x24, 0xbf, 0x19, 0x7f, 0x27, + 0x71, 0xbd, 0x23, 0x33, 0xf7, 0x5a, 0x5c, 0xc4, 0x32, 0xbe, 0xce, 0x11, 0xc5, 0x45, 0xb2, 0x0b, + 0xc4, 0x45, 0x9a, 0xff, 0xa0, 0x94, 0x70, 0x9d, 0x29, 0x03, 0xd5, 0x8a, 0x0c, 0xd4, 0xd9, 0xc0, + 0x7b, 0x1c, 0xea, 0xc8, 0xbe, 0x4c, 0xa8, 0x63, 0x5e, 0xb2, 0xcb, 0x87, 0x68, 0x2f, 0xd1, 0xce, + 0x7c, 0xba, 0x40, 0x18, 0x27, 0x85, 0xcb, 0x37, 0x28, 0x8c, 0x6e, 0x76, 0x55, 0x26, 0x56, 0x61, + 0xee, 0x65, 0xab, 0x64, 0xbc, 0x5c, 0x63, 0x1a, 0x09, 0xaa, 0x84, 0x1c, 0x2b, 0xce, 0x93, 0x63, + 0x07, 0x28, 0xc7, 0x4a, 0xb1, 0x1c, 0x23, 0xdf, 0x01, 0x45, 0xbd, 0xd4, 0xef, 0x90, 0x3d, 0xed, + 0xf1, 0xb2, 0x31, 0x03, 0x47, 0x65, 0x6f, 0x34, 0x71, 0xa4, 0xad, 0xb5, 0x55, 0x55, 0x98, 0xbe, + 0x0d, 0x5a, 0x99, 0xbd, 0x0d, 0xfa, 0x31, 0x40, 0x20, 0x70, 0x77, 0x6c, 0xd9, 0x7d, 0xa9, 0xf3, + 0xb5, 0xee, 0x5c, 0xd6, 0x37, 0x1d, 0x8e, 0x4a, 0x50, 0x60, 0xfb, 0x47, 0xe6, 0x39, 0x85, 0xa8, + 0x75, 0x62, 0x49, 0x54, 0x9e, 0x96, 0xee, 0x2b, 0xb3, 0xd2, 0xfd, 0x9d, 0x50, 0x4f, 0xbf, 0x7e, + 0xe5, 0xfc, 0xae, 0xa7, 0x74, 0xf3, 0x3a, 0x94, 0xc8, 0x0a, 0xf0, 0x7c, 0xba, 0xca, 0x54, 0x31, + 0xc2, 0x62, 0x4a, 0xc2, 0xde, 0x9c, 0x92, 0xb0, 0x53, 0xf1, 0xaf, 0x5b, 0x33, 0xf1, 0xaf, 0x86, + 0x05, 0x45, 0x1d, 0x8e, 0x99, 0x76, 0x9d, 0x84, 0x8e, 0xdc, 0x6c, 0xc2, 0x91, 0x1b, 0xe5, 0x0d, + 0xe7, 0x92, 0x79, 0xc3, 0x53, 0xf7, 0x21, 0x0b, 0x33, 0xf7, 0x21, 0x9b, 0x9f, 0x41, 0x41, 0x59, + 0x0d, 0x10, 0x2a, 0xac, 0x4a, 0xd9, 0xc5, 0x6e, 0xb3, 0x0c, 0xbf, 0x0e, 0x2c, 0x10, 0xa4, 0x0d, + 0x89, 0xae, 0x39, 0x12, 0x24, 0x46, 0xb3, 0xbc, 0x0e, 0xd7, 0x15, 0x6e, 0x90, 0xfe, 0x42, 0x2a, + 0x99, 0x63, 0x1f, 0xfb, 0xa6, 0x7f, 0xc1, 0xf2, 0xcd, 0x8f, 0x29, 0x19, 0x22, 0x5c, 0x72, 0xd5, + 0xe8, 0xfe, 0xa9, 0x12, 0xdc, 0x96, 0x96, 0x4f, 0x94, 0x4b, 0xa3, 0xed, 0x5f, 0x95, 0x89, 0x48, + 0x06, 0x26, 0x79, 0xc8, 0x96, 0x93, 0x5a, 0xc0, 0x9f, 0xda, 0x8e, 0x6c, 0x6e, 0x24, 0x74, 0xca, + 0x74, 0x6a, 0x61, 0x66, 0xd1, 0xd4, 0xc2, 0xe6, 0x63, 0x58, 0x35, 0xd2, 0x52, 0x9f, 0x7f, 0x00, + 0x25, 0x6f, 0x9c, 0xe4, 0xf3, 0xa2, 0x95, 0x1b, 0xa2, 0x37, 0x7f, 0x37, 0x03, 0xcb, 0x1d, 0x57, + 0x0a, 0xdf, 0x35, 0x9d, 0x6d, 0xc7, 0x1c, 0xf0, 0xf7, 0x43, 0x39, 0x36, 0xdf, 0x1b, 0x93, 0xc4, + 0x4d, 0x8b, 0x34, 0x47, 0x87, 0x1d, 0xf8, 0x0d, 0x58, 0x13, 0x96, 0x2d, 0x3d, 0x5f, 0x69, 0xd2, + 0x61, 0x06, 0xe8, 0x75, 0x60, 0x0a, 0xdc, 0xa5, 0x4d, 0xd3, 0x53, 0xd3, 0x5c, 0x87, 0xeb, 0x29, + 0x68, 0xa8, 0x26, 0x67, 0xf9, 0x6d, 0xa8, 0xc7, 0xe7, 0xd5, 0x96, 0xe7, 0xca, 0x8e, 0x6b, 0x89, + 0x73, 0x52, 0xc3, 0x58, 0xae, 0xf9, 0x2b, 0x91, 0x02, 0xf8, 0x54, 0xe7, 0x87, 0xfa, 0x9e, 0x17, + 0x5f, 0x3e, 0xd6, 0xa5, 0xc4, 0x25, 0xf7, 0xec, 0x02, 0x97, 0xdc, 0x3f, 0x8e, 0x2f, 0x2a, 0xab, + 0xa3, 0xe4, 0xd5, 0xb9, 0xe7, 0x13, 0xa5, 0xb5, 0x69, 0xfd, 0xbf, 0x2b, 0x12, 0xb7, 0x96, 0xdf, + 0xd6, 0x46, 0x5f, 0x7e, 0x11, 0x3d, 0x59, 0x65, 0x76, 0xbc, 0x37, 0x7d, 0x3b, 0x66, 0xb1, 0xf4, + 0xd2, 0x19, 0x55, 0x16, 0x5e, 0x5a, 0x95, 0xfd, 0xc6, 0x94, 0x7d, 0x55, 0x9e, 0xeb, 0xa0, 0xbc, + 0xe2, 0xee, 0xef, 0x37, 0xa0, 0x34, 0xb4, 0x03, 0xe9, 0xf9, 0xea, 0x3e, 0xfa, 0xec, 0xfd, 0xb9, + 0xc4, 0x68, 0xed, 0x28, 0x44, 0xca, 0x05, 0x0c, 0xa9, 0xf8, 0xb7, 0x61, 0x8d, 0x06, 0xfe, 0x30, + 0xd6, 0x2b, 0x82, 0x7a, 0x75, 0x6e, 0x0e, 0x66, 0x82, 0xd5, 0xc6, 0x14, 0x89, 0x31, 0xcb, 0xa4, + 0x31, 0x00, 0x88, 0xe7, 0x67, 0x46, 0x8a, 0x7d, 0x8e, 0xfb, 0xe8, 0x37, 0xa1, 0x18, 0x4c, 0x8e, + 0xe3, 0xf8, 0xa4, 0x2e, 0x35, 0xce, 0xa1, 0x31, 0xa3, 0x3f, 0x1c, 0x0a, 0x5f, 0x35, 0xf7, 0xca, + 0x4b, 0xf1, 0x1f, 0x27, 0x27, 0x5e, 0x2d, 0xce, 0xbb, 0x97, 0xcc, 0x5e, 0xc4, 0x39, 0xb1, 0x02, + 0x1a, 0xef, 0x41, 0x35, 0x31, 0xa8, 0x28, 0x99, 0x27, 0xae, 0xe5, 0x85, 0x4e, 0x71, 0xfc, 0xad, + 0x2e, 0x05, 0x5a, 0xa1, 0x5b, 0x9c, 0x7e, 0x37, 0x0c, 0x60, 0xd3, 0x03, 0x78, 0x85, 0x0d, 0xfe, + 0x2a, 0xd4, 0x12, 0x4a, 0x5f, 0xe4, 0x30, 0x4d, 0x03, 0x9b, 0x67, 0xf0, 0x85, 0x04, 0xbb, 0x43, + 0xe1, 0x8f, 0xec, 0x00, 0x8f, 0x1a, 0x65, 0x4e, 0x92, 0xf2, 0x6d, 0x09, 0x57, 0xda, 0x32, 0x94, + 0xa0, 0x51, 0x99, 0xff, 0x1c, 0x14, 0xc6, 0xc2, 0x1f, 0x05, 0x5a, 0x8a, 0x4e, 0xaf, 0xa0, 0xb9, + 0x6c, 0x03, 0x43, 0xd1, 0x34, 0x7f, 0x33, 0x03, 0xe5, 0x3d, 0x21, 0x4d, 0xd4, 0x2e, 0xf8, 0xde, + 0x54, 0x2d, 0xb3, 0x31, 0xf5, 0x10, 0x75, 0x5d, 0x1b, 0xb8, 0xeb, 0x1d, 0x8d, 0xaf, 0xcb, 0x3b, + 0x4b, 0x71, 0xc3, 0x1a, 0x1b, 0x50, 0xd2, 0xe0, 0xc6, 0xfb, 0xb0, 0x3a, 0x85, 0x49, 0xe3, 0xa2, + 0xb4, 0xff, 0xee, 0xc5, 0x28, 0x4c, 0xfc, 0x5a, 0x36, 0xd2, 0xc0, 0x8d, 0x0a, 0x94, 0xc6, 0x8a, + 0xa0, 0xf9, 0xfb, 0x37, 0x28, 0xdd, 0xc8, 0x3e, 0x41, 0xab, 0x7f, 0xde, 0xc9, 0x7a, 0x07, 0x40, + 0x79, 0xf4, 0xe8, 0x50, 0x56, 0x4e, 0xec, 0x04, 0x84, 0x7f, 0x18, 0x45, 0x1f, 0xf2, 0x73, 0xd5, + 0xae, 0x24, 0xf3, 0xe9, 0x10, 0x44, 0x1d, 0x4a, 0x76, 0x40, 0x9e, 0x3a, 0x9d, 0xc8, 0x15, 0x16, + 0xf9, 0xd7, 0xa1, 0x68, 0x8f, 0xc6, 0x9e, 0x2f, 0x75, 0x78, 0xe2, 0x4a, 0xae, 0x1d, 0xc2, 0xdc, + 0x59, 0x32, 0x34, 0x0d, 0x52, 0x8b, 0x73, 0xa2, 0x2e, 0xbf, 0x98, 0xba, 0x7d, 0x1e, 0x52, 0x2b, + 0x1a, 0xfe, 0x2d, 0xa8, 0x0d, 0x54, 0x1e, 0xab, 0x62, 0xac, 0x85, 0xc8, 0x1b, 0x57, 0x31, 0x79, + 0x94, 0x24, 0xd8, 0x59, 0x32, 0xd2, 0x1c, 0x90, 0x25, 0xaa, 0xf8, 0x22, 0x90, 0x3d, 0xef, 0x13, + 0xcf, 0x76, 0xc9, 0x20, 0x7e, 0x01, 0x4b, 0x23, 0x49, 0x80, 0x2c, 0x53, 0x1c, 0xf8, 0x57, 0x51, + 0xe3, 0x09, 0xa4, 0x7e, 0x12, 0xe0, 0xee, 0x55, 0x9c, 0x7a, 0x22, 0xd0, 0x97, 0xf9, 0x03, 0xc9, + 0xcf, 0xa1, 0x91, 0xd8, 0x24, 0xba, 0x92, 0xd6, 0x78, 0xec, 0x7b, 0x68, 0x55, 0xd7, 0x88, 0xdb, + 0x57, 0xaf, 0xe2, 0x76, 0x78, 0x29, 0xf5, 0xce, 0x92, 0x71, 0x05, 0x6f, 0xde, 0x43, 0xdb, 0x4f, + 0x77, 0x61, 0x57, 0x98, 0x67, 0xe1, 0x83, 0x02, 0xf7, 0x17, 0x1a, 0x05, 0xa2, 0xd8, 0x59, 0x32, + 0xa6, 0x78, 0xf0, 0x5f, 0x80, 0xb5, 0x54, 0x9d, 0x74, 0x87, 0x58, 0x3d, 0x37, 0xf0, 0x95, 0x85, + 0xbb, 0x81, 0x44, 0x3b, 0x4b, 0xc6, 0x2c, 0x27, 0x3e, 0x81, 0x57, 0x66, 0xbb, 0xb4, 0x25, 0xfa, + 0x8e, 0xed, 0x0a, 0xfd, 0x32, 0xc1, 0x7b, 0x2f, 0x37, 0x5a, 0x9a, 0x78, 0x67, 0xc9, 0xb8, 0x9c, + 0x33, 0xff, 0xcb, 0x70, 0x7b, 0x3c, 0x57, 0xc4, 0x28, 0xd1, 0xa5, 0x1f, 0x36, 0xf8, 0x60, 0xc1, + 0x9a, 0x67, 0xe8, 0x77, 0x96, 0x8c, 0x2b, 0xf9, 0xa3, 0xee, 0x4c, 0x36, 0xb6, 0x4e, 0xcb, 0x57, + 0x05, 0x8a, 0x5d, 0xf7, 0x9d, 0x1d, 0x61, 0x5a, 0x51, 0x04, 0x25, 0x06, 0x34, 0xfe, 0x47, 0x06, + 0x8a, 0x7a, 0xbd, 0xdf, 0x8e, 0x72, 0x28, 0x22, 0xd1, 0x1d, 0x03, 0xf8, 0x47, 0x50, 0x11, 0xbe, + 0xef, 0xf9, 0x9b, 0x9e, 0x15, 0xa6, 0x9f, 0x4e, 0xfb, 0xa1, 0x15, 0x9f, 0xf5, 0x76, 0x88, 0x66, + 0xc4, 0x14, 0xfc, 0x43, 0x00, 0xb5, 0xcf, 0x7b, 0xf1, 0xed, 0xaa, 0xc6, 0x7c, 0x7a, 0x15, 0x94, + 0x8b, 0xb1, 0x63, 0xc7, 0x5d, 0x18, 0x11, 0x0b, 0x8b, 0x91, 0x49, 0x5a, 0x48, 0x98, 0xa4, 0xb7, + 0xb5, 0xa7, 0x81, 0x1c, 0x30, 0xfa, 0x8e, 0x61, 0x04, 0x68, 0xfc, 0x9b, 0x0c, 0x14, 0x95, 0xf0, + 0xe0, 0xed, 0xd9, 0x1e, 0xbd, 0xfe, 0x62, 0x99, 0xb3, 0x3e, 0xdd, 0xb3, 0xaf, 0x03, 0x28, 0x19, + 0x94, 0xe8, 0xd9, 0xed, 0x29, 0x3e, 0x9a, 0x34, 0x4c, 0xf8, 0x8e, 0xf1, 0x9b, 0x0f, 0xd5, 0x3d, + 0x38, 0x72, 0x1a, 0x3f, 0xd9, 0xdd, 0x65, 0x4b, 0x7c, 0x0d, 0x6a, 0x4f, 0xf6, 0x1f, 0xef, 0x1f, + 0x3c, 0xdb, 0x3f, 0x6a, 0x1b, 0xc6, 0x81, 0xa1, 0x7c, 0xc7, 0x1b, 0xad, 0xad, 0xa3, 0xce, 0xfe, + 0xe1, 0x93, 0x1e, 0xcb, 0x36, 0xfe, 0x59, 0x06, 0x6a, 0x29, 0xd9, 0xf5, 0x67, 0x3b, 0x75, 0x89, + 0xe1, 0xcf, 0xcd, 0x1f, 0xfe, 0xfc, 0x65, 0xc3, 0x5f, 0x98, 0x1e, 0xfe, 0xdf, 0xce, 0x40, 0x2d, + 0x25, 0x23, 0x93, 0xdc, 0x33, 0x69, 0xee, 0xc9, 0x93, 0x3e, 0x3b, 0x75, 0xd2, 0x37, 0x61, 0x39, + 0xfc, 0xbd, 0x1f, 0xfb, 0x24, 0x52, 0xb0, 0x24, 0x0e, 0x5d, 0x44, 0xc9, 0xa7, 0x71, 0xe8, 0x32, + 0xca, 0xd5, 0xad, 0xa5, 0x8b, 0xb7, 0x01, 0xbd, 0x4b, 0xd0, 0xb8, 0x5c, 0x82, 0x5e, 0xd1, 0x85, + 0x47, 0x50, 0x1d, 0xc7, 0xdb, 0xf4, 0xe5, 0xd4, 0x92, 0x24, 0xe5, 0x0b, 0xda, 0xf9, 0x3b, 0x19, + 0x58, 0x49, 0xcb, 0xdc, 0xff, 0xaf, 0x87, 0xf5, 0x9f, 0x64, 0x60, 0x6d, 0x46, 0x92, 0x5f, 0xa9, + 0xd8, 0x4d, 0xb7, 0x2b, 0xbb, 0x40, 0xbb, 0x72, 0x73, 0xda, 0x75, 0xb9, 0x24, 0xb9, 0xba, 0xc5, + 0x5d, 0x78, 0xe5, 0xd2, 0x33, 0xe1, 0x8a, 0xa1, 0x4e, 0x31, 0xcd, 0x4d, 0x33, 0xfd, 0x8d, 0x0c, + 0xdc, 0xbe, 0x4a, 0xde, 0xff, 0x3f, 0x5f, 0x57, 0xd3, 0x2d, 0x6c, 0xbe, 0x1f, 0xa5, 0x56, 0x54, + 0xa1, 0xa4, 0xdf, 0xfb, 0xd2, 0xa9, 0xed, 0x43, 0xef, 0xb9, 0xab, 0x7c, 0xd5, 0x86, 0x30, 0xf5, + 0x8b, 0x08, 0x86, 0x18, 0x3b, 0x36, 0x45, 0x51, 0x6f, 0x01, 0xb4, 0xc8, 0xae, 0x0b, 0x2f, 0x1e, + 0x6d, 0xee, 0x1e, 0x74, 0xdb, 0x6c, 0x29, 0xa9, 0xc4, 0x7e, 0x16, 0x0a, 0xe2, 0xe6, 0x21, 0x14, + 0xe3, 0xab, 0x20, 0x7b, 0xa6, 0x7f, 0x6a, 0xa9, 0x58, 0xe5, 0x32, 0x94, 0x0f, 0xb5, 0x09, 0xa5, + 0xaa, 0xfa, 0xa4, 0x7b, 0xb0, 0xaf, 0xdc, 0xe2, 0x5b, 0x07, 0x3d, 0x75, 0xa1, 0xa4, 0xfb, 0xf4, + 0x91, 0x0a, 0x9a, 0x3d, 0x32, 0x5a, 0x87, 0x3b, 0x47, 0x84, 0x51, 0x68, 0xfe, 0x7a, 0x3e, 0x3c, + 0xd5, 0x9a, 0x86, 0x8e, 0x82, 0x02, 0x14, 0x51, 0x9a, 0x7b, 0x9a, 0x71, 0x54, 0x0d, 0x25, 0x41, + 0xb7, 0xcf, 0x95, 0x1f, 0x82, 0x65, 0x79, 0x11, 0xb2, 0x87, 0xc7, 0x2a, 0x37, 0x6b, 0x47, 0x8e, + 0x1c, 0x75, 0x63, 0xb5, 0x77, 0x2e, 0x59, 0x01, 0x7f, 0x6c, 0x06, 0x67, 0xac, 0xd8, 0xfc, 0xe7, + 0x39, 0xa8, 0x44, 0xa2, 0xf2, 0x65, 0x44, 0x37, 0xe7, 0xb0, 0xd2, 0xd9, 0xef, 0xb5, 0x8d, 0xfd, + 0xd6, 0xae, 0x46, 0xc9, 0xf1, 0x6b, 0xb0, 0xba, 0xdd, 0xd9, 0x6d, 0x1f, 0xed, 0x1e, 0xb4, 0xb6, + 0x34, 0xb0, 0xcc, 0x6f, 0x02, 0xef, 0xec, 0x1d, 0x1e, 0x18, 0xbd, 0xa3, 0x4e, 0xf7, 0x68, 0xb3, + 0xb5, 0xbf, 0xd9, 0xde, 0x6d, 0x6f, 0xb1, 0x22, 0x7f, 0x15, 0xee, 0xee, 0x1f, 0xf4, 0x3a, 0x07, + 0xfb, 0x47, 0xfb, 0x07, 0x47, 0x07, 0x1b, 0x9f, 0xb4, 0x37, 0x7b, 0xdd, 0xa3, 0xce, 0xfe, 0x11, + 0x72, 0x7d, 0x64, 0xb4, 0xf0, 0x0b, 0x2b, 0xf0, 0xbb, 0x70, 0x5b, 0x63, 0x75, 0xdb, 0xc6, 0xd3, + 0xb6, 0x81, 0x4c, 0x9e, 0xec, 0xb7, 0x9e, 0xb6, 0x3a, 0xbb, 0xad, 0x8d, 0xdd, 0x36, 0x5b, 0xe6, + 0x77, 0xa0, 0xa1, 0x31, 0x8c, 0x56, 0xaf, 0x7d, 0xb4, 0xdb, 0xd9, 0xeb, 0xf4, 0x8e, 0xda, 0xdf, + 0xde, 0x6c, 0xb7, 0xb7, 0xda, 0x5b, 0xac, 0xc6, 0xdf, 0x80, 0x2f, 0x51, 0xa3, 0x74, 0x23, 0xd2, + 0x95, 0x7d, 0xd6, 0x39, 0x3c, 0x6a, 0x19, 0x9b, 0x3b, 0x9d, 0xa7, 0x6d, 0xb6, 0xc2, 0x5f, 0x87, + 0x2f, 0x5e, 0x8e, 0xba, 0xd5, 0x31, 0xda, 0x9b, 0xbd, 0x03, 0xe3, 0x53, 0xb6, 0xc6, 0x7f, 0x06, + 0x5e, 0xd9, 0xe9, 0xed, 0xed, 0x1e, 0x3d, 0x33, 0x0e, 0xf6, 0x1f, 0x1d, 0xd1, 0xcf, 0x6e, 0xcf, + 0x78, 0xb2, 0xd9, 0x7b, 0x62, 0xb4, 0x19, 0xf0, 0x06, 0xdc, 0x3c, 0xdc, 0x38, 0xda, 0x3f, 0xe8, + 0x1d, 0xb5, 0xf6, 0x3f, 0xdd, 0xd8, 0x3d, 0xd8, 0x7c, 0x7c, 0xb4, 0x7d, 0x60, 0xec, 0xb5, 0x7a, + 0xac, 0xca, 0xbf, 0x0c, 0xaf, 0x6f, 0x76, 0x9f, 0xea, 0x66, 0x1e, 0x6c, 0x1f, 0x19, 0x07, 0xcf, + 0xba, 0x47, 0x07, 0xc6, 0x91, 0xd1, 0xde, 0xa5, 0x3e, 0x77, 0xe3, 0xb6, 0x97, 0xf8, 0x6d, 0xa8, + 0x77, 0xf6, 0xbb, 0x4f, 0xb6, 0xb7, 0x3b, 0x9b, 0x9d, 0xf6, 0x7e, 0xef, 0xe8, 0xb0, 0x6d, 0xec, + 0x75, 0xba, 0x5d, 0x44, 0x63, 0x95, 0xe6, 0x37, 0xa1, 0xd8, 0x71, 0xcf, 0x6c, 0x49, 0xfb, 0x4b, + 0x2f, 0x46, 0x6d, 0x71, 0x85, 0x45, 0xda, 0x16, 0xf6, 0xc0, 0xa5, 0x97, 0x18, 0x68, 0x77, 0x2d, + 0x1b, 0x31, 0xa0, 0xf9, 0x8b, 0x39, 0xa8, 0x29, 0x16, 0xa1, 0x05, 0x77, 0x0f, 0x56, 0xb5, 0xb3, + 0xb4, 0x93, 0x16, 0x61, 0xd3, 0x60, 0x7a, 0xe2, 0x4c, 0x81, 0x12, 0x82, 0x2c, 0x09, 0xa2, 0xb4, + 0x8d, 0xbe, 0x83, 0x66, 0xa0, 0x8a, 0x68, 0xea, 0xd2, 0xe7, 0x95, 0x5d, 0x28, 0x17, 0x15, 0x62, + 0xdf, 0x73, 0x37, 0xa3, 0x4b, 0x36, 0x29, 0x18, 0xff, 0x0c, 0x6e, 0x45, 0xe5, 0xb6, 0xdb, 0xf7, + 0x2f, 0xc6, 0xd1, 0x1b, 0x84, 0xa5, 0xb9, 0xce, 0x84, 0x6d, 0xdb, 0x11, 0x29, 0x44, 0xe3, 0x32, + 0x06, 0xfc, 0x6b, 0x00, 0x36, 0x0d, 0x16, 0xe9, 0x47, 0xea, 0x56, 0xdb, 0x2b, 0x33, 0x7e, 0xc0, + 0x10, 0xc1, 0x48, 0x20, 0xe3, 0x91, 0x30, 0x40, 0x49, 0xfb, 0x58, 0x3f, 0x52, 0xb8, 0x6c, 0x44, + 0xe5, 0xe6, 0x1f, 0x66, 0x12, 0x86, 0xb4, 0x32, 0x94, 0xaf, 0x3c, 0x42, 0xe6, 0x85, 0x7d, 0xd0, + 0x94, 0xd5, 0xa3, 0xa2, 0x35, 0x1b, 0x5d, 0xe4, 0x87, 0xc0, 0xed, 0xd9, 0xb1, 0xc8, 0x2f, 0x38, + 0x16, 0x73, 0x68, 0xa7, 0xbd, 0xf6, 0x85, 0x59, 0xaf, 0xfd, 0x1d, 0x80, 0x81, 0xe3, 0x1d, 0xeb, + 0xd0, 0x61, 0x51, 0xa7, 0x32, 0x45, 0x90, 0xa6, 0x03, 0xe5, 0xf0, 0x01, 0x45, 0x5c, 0x24, 0xf4, + 0x84, 0x62, 0xe4, 0xa1, 0x54, 0x25, 0xbe, 0x03, 0x2b, 0x22, 0xdd, 0xe6, 0xec, 0x82, 0x6d, 0x9e, + 0xa2, 0x6b, 0x7e, 0x0d, 0xd6, 0x66, 0x90, 0x70, 0x10, 0xc7, 0xa6, 0x8c, 0x5e, 0x51, 0xc0, 0xdf, + 0xb3, 0x11, 0xf9, 0xe6, 0xbf, 0xcb, 0xc2, 0xf2, 0x9e, 0xe9, 0xda, 0x27, 0x22, 0x90, 0x61, 0x6b, + 0x83, 0xfe, 0x50, 0x8c, 0xcc, 0xb0, 0xb5, 0xaa, 0xa4, 0xdd, 0x16, 0xd9, 0x64, 0x40, 0x60, 0x26, + 0xc2, 0x84, 0xdb, 0x61, 0x22, 0x87, 0xd1, 0x85, 0x01, 0x5d, 0xc2, 0xb9, 0x73, 0xec, 0xbe, 0x70, + 0x83, 0x70, 0xc9, 0x87, 0xc5, 0x38, 0x41, 0xa7, 0x78, 0x45, 0x82, 0x4e, 0x69, 0x76, 0xfc, 0xef, + 0x42, 0x35, 0xe8, 0xfb, 0x42, 0xb8, 0xc1, 0xd0, 0x93, 0xe1, 0xe3, 0x9b, 0x49, 0x10, 0x65, 0x07, + 0x7a, 0xcf, 0x5d, 0xdc, 0xf2, 0xbb, 0xb6, 0x7b, 0xaa, 0x93, 0xde, 0x52, 0x30, 0x5c, 0x83, 0xe4, + 0xb4, 0xb1, 0xbf, 0x27, 0xc8, 0x61, 0x50, 0x30, 0xa2, 0x32, 0xb9, 0x65, 0x4c, 0x29, 0x06, 0x9e, + 0x6f, 0x0b, 0xe5, 0x9b, 0xac, 0x18, 0x09, 0x08, 0xd2, 0x3a, 0xa6, 0x3b, 0x98, 0x98, 0x03, 0xa1, + 0x23, 0xdc, 0x51, 0xb9, 0xf9, 0x3f, 0x0b, 0x00, 0x7b, 0x62, 0x74, 0x2c, 0xfc, 0x60, 0x68, 0x8f, + 0x29, 0x76, 0x62, 0xeb, 0x34, 0xe9, 0x9a, 0x41, 0xbf, 0xf9, 0x07, 0xa9, 0x1b, 0x0c, 0xb3, 0xf1, + 0xd0, 0x98, 0x7c, 0xda, 0xa7, 0x83, 0x83, 0x63, 0x4a, 0xa1, 0x73, 0xa3, 0x68, 0xfc, 0xf3, 0x46, + 0x12, 0x44, 0xd9, 0x80, 0xa6, 0x14, 0x6d, 0xd7, 0x52, 0x3e, 0xa3, 0xbc, 0x11, 0x95, 0x29, 0x06, + 0x14, 0xb4, 0x26, 0xd2, 0x33, 0x84, 0x2b, 0x9e, 0x47, 0xd7, 0xfb, 0x62, 0x10, 0xdf, 0x83, 0xda, + 0xd8, 0xbc, 0x18, 0x09, 0x57, 0xee, 0x09, 0x39, 0xf4, 0x2c, 0x9d, 0xc8, 0xf4, 0xfa, 0xe5, 0x0d, + 0x3c, 0x4c, 0xa2, 0x1b, 0x69, 0x6a, 0x5c, 0x13, 0x6e, 0x40, 0xbb, 0x44, 0x4d, 0xa3, 0x2e, 0xf1, + 0x0d, 0x00, 0xf5, 0x2b, 0x21, 0x6a, 0x66, 0xdc, 0x48, 0xe6, 0x48, 0x04, 0xc2, 0x3f, 0xb3, 0x95, + 0x78, 0x54, 0x32, 0x27, 0xa6, 0x42, 0x61, 0x3a, 0x09, 0x84, 0xdf, 0x1e, 0x99, 0xb6, 0xa3, 0x27, + 0x38, 0x06, 0xf0, 0x77, 0xe1, 0x46, 0x30, 0x39, 0xc6, 0x35, 0x73, 0x2c, 0x7a, 0xde, 0xbe, 0x78, + 0x1e, 0x38, 0x42, 0x4a, 0xe1, 0xeb, 0x64, 0x89, 0xf9, 0x1f, 0x9b, 0x83, 0x48, 0x8f, 0xa2, 0x87, + 0x5e, 0xf0, 0x57, 0x9c, 0x91, 0x15, 0x81, 0x74, 0xba, 0x1a, 0xcb, 0x70, 0x06, 0xcb, 0x0a, 0xa4, + 0xb3, 0xd9, 0xb2, 0xfc, 0x4b, 0xf0, 0xb3, 0x29, 0x24, 0x43, 0xc5, 0x9e, 0x83, 0x6d, 0xdb, 0x35, + 0x1d, 0xfb, 0x7b, 0x2a, 0x13, 0x20, 0xd7, 0x1c, 0x43, 0x2d, 0x35, 0x70, 0x74, 0x1f, 0x95, 0x7e, + 0xe9, 0x94, 0x1e, 0x06, 0xcb, 0xaa, 0xdc, 0x95, 0xbe, 0x4d, 0x21, 0x93, 0x08, 0xb2, 0x89, 0xfb, + 0xdc, 0x63, 0x59, 0x7e, 0x1d, 0x98, 0x82, 0x74, 0x5c, 0x73, 0x3c, 0x6e, 0x8d, 0xc7, 0x8e, 0x60, + 0x39, 0xba, 0xeb, 0x1b, 0x43, 0xd5, 0x3d, 0x06, 0x96, 0x6f, 0x7e, 0x1b, 0x6e, 0xd1, 0xc8, 0x3c, + 0x15, 0x7e, 0x64, 0x29, 0xeb, 0xbe, 0xde, 0x80, 0x35, 0xf5, 0x6b, 0xdf, 0x93, 0xea, 0x33, 0x69, + 0x8f, 0x1c, 0x56, 0x14, 0x18, 0x95, 0xa7, 0xae, 0xa0, 0x1b, 0xbc, 0x11, 0x2c, 0xc2, 0xcb, 0x36, + 0xff, 0xa0, 0x08, 0x3c, 0x5e, 0x10, 0x3d, 0x5b, 0xf8, 0x5b, 0xa6, 0x34, 0x13, 0xae, 0xce, 0xda, + 0xa5, 0xe1, 0xfc, 0x17, 0x27, 0xe3, 0xdd, 0x84, 0xa2, 0x1d, 0xa0, 0x6d, 0xa7, 0x33, 0x90, 0x75, + 0x89, 0xef, 0x02, 0x8c, 0x85, 0x6f, 0x7b, 0x16, 0xad, 0xa0, 0xc2, 0xdc, 0x8b, 0x24, 0xb3, 0x8d, + 0x5a, 0x3f, 0x8c, 0x68, 0x8c, 0x04, 0x3d, 0xb6, 0x43, 0x95, 0x54, 0x70, 0xbc, 0x48, 0x8d, 0x4e, + 0x82, 0xf8, 0x5b, 0x70, 0x6d, 0xec, 0xdb, 0x7d, 0xa1, 0xa6, 0xe3, 0x49, 0x60, 0x6d, 0xd2, 0xf3, + 0x88, 0x25, 0xc2, 0x9c, 0xf7, 0x09, 0x57, 0xa0, 0xe9, 0x92, 0xc5, 0x13, 0x50, 0x38, 0x58, 0xdf, + 0x79, 0x57, 0x39, 0xba, 0x35, 0x63, 0xfe, 0x47, 0x7e, 0x1f, 0x98, 0xfe, 0xb0, 0x67, 0xbb, 0xbb, + 0xc2, 0x1d, 0xc8, 0x21, 0x2d, 0xee, 0x9a, 0x31, 0x03, 0x27, 0x09, 0xa6, 0x1e, 0xa1, 0x52, 0x81, + 0xa0, 0x8a, 0x11, 0x95, 0xd5, 0x7b, 0x0b, 0x8e, 0xe7, 0x77, 0xa5, 0xaf, 0x93, 0x8d, 0xa3, 0x32, + 0x2a, 0x41, 0x01, 0xb5, 0xf5, 0xd0, 0xf7, 0xac, 0x09, 0x85, 0x29, 0x94, 0x10, 0x9b, 0x06, 0xc7, + 0x98, 0x7b, 0xa6, 0xab, 0x33, 0x22, 0x6b, 0x49, 0xcc, 0x08, 0x4c, 0x46, 0x9d, 0x17, 0xc4, 0x0c, + 0x57, 0xb5, 0x51, 0x97, 0x80, 0x69, 0x9c, 0x98, 0x15, 0x8b, 0x70, 0x62, 0x3e, 0xd4, 0x7f, 0xcb, + 0xf7, 0x6c, 0x2b, 0xe6, 0xa5, 0x92, 0x73, 0x66, 0xe0, 0x09, 0xdc, 0x98, 0x27, 0x4f, 0xe1, 0xc6, + 0x7c, 0xaf, 0x43, 0xc1, 0x3b, 0x39, 0x11, 0x3e, 0xbd, 0x39, 0x5a, 0x31, 0x54, 0xa1, 0xf9, 0x83, + 0x0c, 0x40, 0xbc, 0x24, 0x70, 0x23, 0xc4, 0xa5, 0x78, 0xe3, 0xdf, 0x82, 0x6b, 0x49, 0xb0, 0xa3, + 0x73, 0x5d, 0x69, 0x37, 0xc4, 0x1f, 0xb6, 0xcc, 0x8b, 0x80, 0x65, 0xf5, 0x5d, 0x74, 0x0d, 0x7b, + 0x26, 0x04, 0x25, 0x0e, 0x5e, 0x07, 0x16, 0x03, 0xe9, 0x82, 0x61, 0xc0, 0xf2, 0x69, 0xd4, 0x4f, + 0x85, 0xe9, 0x07, 0xac, 0xd0, 0xdc, 0x81, 0xa2, 0x8a, 0x61, 0xcd, 0x89, 0x3e, 0xbf, 0x5c, 0xb2, + 0xc9, 0xdf, 0xc8, 0x00, 0x6c, 0xa9, 0x44, 0x70, 0x3c, 0xdb, 0xe7, 0x04, 0xf5, 0xe7, 0xe9, 0x59, + 0xa6, 0x65, 0x51, 0x42, 0x7d, 0x2e, 0x7a, 0xf0, 0x08, 0x8b, 0xb8, 0x9e, 0xcc, 0x30, 0x39, 0x4c, + 0xed, 0xc4, 0xa8, 0xac, 0x8e, 0x95, 0x4d, 0xcf, 0x75, 0x45, 0x1f, 0x0f, 0xa5, 0xe8, 0x58, 0x89, + 0x40, 0xcd, 0xef, 0x67, 0xa1, 0xb2, 0x39, 0x34, 0xa5, 0x7a, 0x1f, 0xe8, 0x9b, 0x50, 0x1e, 0x89, + 0x20, 0x30, 0x07, 0x22, 0xd0, 0x31, 0x9b, 0xe9, 0x80, 0x6b, 0x84, 0xbb, 0xfe, 0xc4, 0xf5, 0x85, + 0x69, 0xa9, 0x47, 0x91, 0x22, 0x2a, 0xc5, 0xc1, 0x95, 0x91, 0x4d, 0xfd, 0x12, 0x1c, 0xdc, 0xe8, + 0x05, 0x63, 0xc7, 0x0c, 0x14, 0x4a, 0xe4, 0x2f, 0x4b, 0x82, 0x1a, 0x7b, 0x50, 0x4d, 0x90, 0xf2, + 0x57, 0xa1, 0xe6, 0x39, 0x96, 0x08, 0xd4, 0x75, 0xc7, 0xf8, 0x25, 0xc9, 0x14, 0x90, 0x72, 0x33, + 0x70, 0x3f, 0x0b, 0x5f, 0x87, 0xdf, 0xc2, 0x62, 0xf3, 0xd7, 0xca, 0x50, 0xc5, 0x46, 0xed, 0xa9, + 0x3e, 0xcc, 0x4c, 0x47, 0x1d, 0x4a, 0x9e, 0xe6, 0xac, 0xd3, 0xc3, 0xbd, 0x04, 0x4f, 0x9d, 0xef, + 0x91, 0x4b, 0xe7, 0x7b, 0xa4, 0x12, 0xc4, 0xf3, 0xd3, 0x09, 0xe2, 0x77, 0x00, 0x46, 0x9e, 0x45, + 0x52, 0xba, 0xa5, 0xc2, 0x2c, 0x39, 0x23, 0x01, 0x21, 0x3b, 0x45, 0x77, 0xbf, 0xaa, 0xed, 0x14, + 0x55, 0x54, 0x89, 0x37, 0x63, 0xe7, 0xa2, 0xe7, 0xe9, 0xd6, 0x76, 0xac, 0xf8, 0xba, 0x79, 0x1a, + 0xce, 0x37, 0xa1, 0xa4, 0xa7, 0x45, 0x07, 0x93, 0xde, 0x98, 0x33, 0x13, 0x1a, 0x7d, 0x5d, 0xff, + 0xd5, 0x37, 0xbe, 0x8c, 0x90, 0x92, 0x3f, 0x82, 0xaa, 0x29, 0xa5, 0xd9, 0x1f, 0x8e, 0xb4, 0x54, + 0xcd, 0xcd, 0x89, 0x2b, 0x27, 0x19, 0xb5, 0x22, 0x6c, 0x23, 0x49, 0xc9, 0x37, 0xa0, 0xe2, 0x0b, + 0x33, 0x15, 0xda, 0x7e, 0xf5, 0x0a, 0x36, 0x46, 0x88, 0x6b, 0xc4, 0x64, 0xd1, 0xa3, 0xaa, 0x90, + 0x78, 0x54, 0xf5, 0x2e, 0x54, 0xf5, 0xd2, 0x31, 0xf0, 0x93, 0x7a, 0x6c, 0x26, 0x09, 0x6a, 0xfc, + 0x28, 0x03, 0x2b, 0xe9, 0xee, 0xfd, 0x59, 0x3c, 0x03, 0xf8, 0xf5, 0xf8, 0x19, 0xc0, 0xcf, 0xf1, + 0xa4, 0xde, 0x6f, 0x64, 0x00, 0xe2, 0x91, 0xc3, 0xb3, 0x55, 0x3d, 0x57, 0x16, 0x6a, 0xfb, 0xaa, + 0xc4, 0x77, 0x52, 0x6f, 0x57, 0xbc, 0xbb, 0xd0, 0x34, 0x24, 0x7e, 0x26, 0x32, 0xdb, 0x1f, 0xc0, + 0x4a, 0x1a, 0x4e, 0x37, 0x02, 0x3a, 0xbb, 0x6d, 0xe5, 0x9c, 0xea, 0xec, 0xb5, 0x1e, 0xb5, 0xf5, + 0xcd, 0xbb, 0xce, 0xfe, 0x63, 0x96, 0x6d, 0xfc, 0x51, 0x06, 0x2a, 0xd1, 0xa4, 0xf0, 0x6f, 0x25, + 0x67, 0x53, 0x65, 0xb8, 0xbc, 0xb3, 0xc8, 0x6c, 0xc6, 0xbf, 0xda, 0xae, 0xf4, 0x2f, 0x12, 0x93, + 0xdb, 0xf0, 0x60, 0x25, 0xfd, 0x71, 0x8e, 0x98, 0x7d, 0x94, 0x16, 0xb3, 0x6f, 0x2f, 0x54, 0x65, + 0x68, 0xe2, 0xee, 0xda, 0x81, 0xd4, 0x12, 0xf8, 0xc3, 0xec, 0x07, 0x99, 0xc6, 0x5d, 0x58, 0x4e, + 0x7e, 0x9a, 0xbd, 0x7c, 0x7b, 0xff, 0x8f, 0x72, 0xb0, 0x92, 0x4e, 0x12, 0xa1, 0xcb, 0x7c, 0x2a, + 0x41, 0xe9, 0xc0, 0xb1, 0x12, 0x97, 0x01, 0x18, 0x5f, 0x85, 0xaa, 0x36, 0xa2, 0x09, 0xb0, 0x46, + 0xee, 0x2f, 0x6f, 0x24, 0xd8, 0xdd, 0xe4, 0x53, 0xa7, 0x6f, 0x71, 0x08, 0x2f, 0x61, 0xb2, 0x31, + 0xaf, 0xe8, 0x47, 0xdf, 0xbe, 0x9f, 0xe5, 0xb5, 0x44, 0x4a, 0xfa, 0x0f, 0x51, 0x83, 0x5c, 0xdd, + 0x98, 0xb8, 0x96, 0x23, 0xac, 0x08, 0xfa, 0xa3, 0x24, 0x34, 0xca, 0x29, 0xff, 0x7e, 0x9e, 0xaf, + 0x40, 0xa5, 0x3b, 0x39, 0xd6, 0xf9, 0xe4, 0x7f, 0x25, 0xcf, 0x6f, 0xc2, 0x9a, 0xc6, 0x8a, 0xd3, + 0x37, 0xd9, 0x2f, 0xe2, 0xa9, 0xb6, 0xd2, 0x52, 0xe3, 0xa5, 0x1b, 0xca, 0xfe, 0x6a, 0x1e, 0x9b, + 0x40, 0x77, 0xfb, 0xff, 0x1a, 0xf1, 0x89, 0xee, 0x3a, 0xb1, 0x5f, 0xca, 0xf3, 0x55, 0x80, 0x6e, + 0x2f, 0xaa, 0xe8, 0x57, 0xf2, 0xbc, 0x0a, 0xc5, 0x6e, 0x8f, 0xb8, 0xfd, 0x20, 0xcf, 0x6f, 0x00, + 0x8b, 0xbf, 0xea, 0xa4, 0xd6, 0xbf, 0xa5, 0x1a, 0x13, 0x65, 0xa9, 0xfe, 0xed, 0x3c, 0xf6, 0x2b, + 0x1c, 0x65, 0xf6, 0x77, 0xf2, 0x9c, 0x41, 0x35, 0xe1, 0x54, 0x65, 0x7f, 0x37, 0xcf, 0x39, 0xd4, + 0xf6, 0xec, 0x20, 0xb0, 0xdd, 0x81, 0xee, 0xc1, 0x2f, 0x53, 0xcd, 0xdb, 0xd1, 0x75, 0x2d, 0xf6, + 0xab, 0x79, 0x7e, 0x0b, 0x78, 0x32, 0x90, 0xa4, 0x3f, 0xfc, 0x1a, 0x51, 0xab, 0x93, 0x34, 0xd0, + 0xb0, 0xbf, 0x47, 0xd4, 0xb8, 0x12, 0x34, 0xe0, 0xd7, 0x69, 0x40, 0x36, 0xe3, 0x34, 0x58, 0x0d, + 0xff, 0x21, 0x11, 0x87, 0x93, 0xa9, 0x60, 0x3f, 0xca, 0xdf, 0xff, 0x5d, 0x0a, 0x04, 0x24, 0x73, + 0xc5, 0xf8, 0x32, 0x94, 0x1d, 0xcf, 0x1d, 0x48, 0xf5, 0xc4, 0x6c, 0x0d, 0x2a, 0xc1, 0xd0, 0xf3, + 0x25, 0x15, 0xe9, 0x3e, 0xa9, 0x4b, 0xef, 0x0e, 0xa8, 0x1b, 0x09, 0xca, 0x1a, 0x54, 0x8e, 0x55, + 0x69, 0x0e, 0x58, 0x35, 0x4a, 0xe0, 0xcd, 0x47, 0x49, 0xc6, 0xf4, 0xfe, 0x41, 0x78, 0xbf, 0x9c, + 0x15, 0x11, 0x75, 0xe2, 0x3b, 0x2a, 0xd9, 0x58, 0xa0, 0x25, 0xa0, 0xde, 0x92, 0x1c, 0x0f, 0xd1, + 0xe0, 0xa8, 0x28, 0xa8, 0xf7, 0x1d, 0x5b, 0xdd, 0x5c, 0xd6, 0x99, 0x79, 0x16, 0xb6, 0x23, 0x4a, + 0x3e, 0x61, 0xe2, 0xfe, 0xdf, 0xcf, 0xc0, 0x72, 0x78, 0xeb, 0xdf, 0x1e, 0xd8, 0xae, 0x4a, 0x57, + 0x0e, 0x1f, 0xee, 0xed, 0x3b, 0xf6, 0x38, 0x7c, 0x08, 0x73, 0x15, 0xaa, 0x96, 0x6f, 0x0e, 0x5a, + 0xae, 0xb5, 0xe5, 0x7b, 0x63, 0xd5, 0x6c, 0x15, 0x2a, 0x54, 0x69, 0xd2, 0xcf, 0xc5, 0x31, 0xa2, + 0x8f, 0x85, 0xcf, 0xf2, 0x94, 0xf5, 0x37, 0x34, 0x7d, 0xdb, 0x1d, 0xb4, 0xcf, 0xa5, 0x70, 0x03, + 0x95, 0x2e, 0x5d, 0x85, 0xd2, 0x24, 0x10, 0x7d, 0x33, 0x10, 0xac, 0x88, 0x85, 0xe3, 0x89, 0xed, + 0x48, 0xdb, 0x55, 0xef, 0x4f, 0x46, 0xf9, 0xd0, 0x65, 0xec, 0x99, 0x39, 0xb6, 0x59, 0xe5, 0xfe, + 0xbf, 0xca, 0x40, 0x95, 0x96, 0x45, 0xec, 0x0c, 0x8f, 0xb5, 0xb8, 0x2a, 0x94, 0x76, 0xa3, 0x87, + 0x08, 0x8b, 0x90, 0x3d, 0x38, 0x55, 0xce, 0x70, 0xbd, 0x2c, 0xd4, 0xf5, 0x5c, 0xf5, 0x26, 0x61, + 0x9e, 0xbf, 0x02, 0x37, 0x0c, 0x31, 0xf2, 0xa4, 0x78, 0x66, 0xda, 0x32, 0x79, 0x35, 0xa9, 0x80, + 0x66, 0xa0, 0xfa, 0x14, 0xde, 0x45, 0x2a, 0x92, 0x19, 0x88, 0xd5, 0x86, 0x90, 0x12, 0xf6, 0x9e, + 0x20, 0xda, 0x2e, 0x2c, 0x47, 0x28, 0x9f, 0x78, 0xb6, 0x8b, 0xb5, 0xd1, 0x95, 0x71, 0x82, 0x50, + 0x54, 0x05, 0x41, 0x70, 0x7f, 0x1f, 0x6e, 0xce, 0x8f, 0x05, 0xa8, 0xcb, 0xe4, 0xf4, 0xfa, 0x35, + 0x5d, 0x56, 0x79, 0xe6, 0xdb, 0xea, 0xd6, 0x6f, 0x05, 0x0a, 0x07, 0xcf, 0x5d, 0x5a, 0x16, 0x6b, + 0x50, 0xdb, 0xf7, 0x12, 0x34, 0x2c, 0x77, 0xff, 0x7d, 0x80, 0xd8, 0x61, 0xa7, 0x1e, 0xff, 0xa2, + 0x35, 0x44, 0xc2, 0xf7, 0xd1, 0x44, 0x04, 0xda, 0xa4, 0x7b, 0x66, 0xcb, 0xa1, 0x37, 0x09, 0xe3, + 0x64, 0x2c, 0x7b, 0xbf, 0x9f, 0x8a, 0xfb, 0xc4, 0xa3, 0x19, 0xb6, 0x7e, 0x29, 0x71, 0x83, 0x2b, + 0xa3, 0x22, 0x0a, 0xf4, 0x9f, 0x4f, 0xd4, 0x0b, 0x1d, 0x3a, 0xde, 0x62, 0xa9, 0x17, 0x3a, 0xa2, + 0xfe, 0xe5, 0xd5, 0x53, 0x65, 0x6e, 0x5f, 0x38, 0xc2, 0x62, 0x85, 0xfb, 0x1f, 0xc0, 0xaa, 0x1e, + 0xa3, 0xbe, 0x08, 0x82, 0xf0, 0x06, 0xd4, 0xa1, 0x6f, 0x9f, 0xa9, 0x57, 0x40, 0x96, 0xa1, 0x7c, + 0x28, 0xfc, 0xc0, 0x73, 0xe9, 0x05, 0x14, 0x80, 0x62, 0x77, 0x68, 0xfa, 0x58, 0xc7, 0xfd, 0xaf, + 0xe8, 0xd1, 0x7d, 0x72, 0x1e, 0x9e, 0x29, 0xb8, 0xf1, 0xf4, 0x03, 0x40, 0xa6, 0x34, 0x35, 0xba, + 0xf4, 0x85, 0x39, 0x62, 0xd9, 0xfb, 0x9b, 0x50, 0xa1, 0x0b, 0x54, 0x8f, 0x6d, 0xd7, 0xc2, 0x9e, + 0x6f, 0xe8, 0x64, 0x7e, 0x7a, 0x99, 0xea, 0x8c, 0xc6, 0xb1, 0xac, 0xde, 0xfa, 0x65, 0x59, 0x7e, + 0x13, 0x78, 0x6b, 0x22, 0xbd, 0x91, 0x49, 0x17, 0x9d, 0x9d, 0x0b, 0xf5, 0x2e, 0x74, 0xee, 0xfe, + 0x37, 0x80, 0x2b, 0xa7, 0x9e, 0x25, 0xce, 0x6d, 0x77, 0x10, 0xbd, 0xb0, 0x00, 0xf4, 0x5c, 0x8a, + 0x25, 0xce, 0xc3, 0xdb, 0x6f, 0x61, 0x21, 0x7c, 0xb4, 0x65, 0xdb, 0x9b, 0xb8, 0xd8, 0xe8, 0xa7, + 0x70, 0x5d, 0xad, 0x4d, 0xec, 0x05, 0xdd, 0xa2, 0xbd, 0xd4, 0xd3, 0xa0, 0x6e, 0xbf, 0xc9, 0x49, + 0x10, 0xe1, 0xb2, 0x0c, 0x36, 0x2c, 0xb2, 0xd2, 0x63, 0x78, 0xf6, 0x7e, 0x13, 0xae, 0xcd, 0x71, + 0x95, 0xd0, 0x69, 0xa0, 0x0c, 0x46, 0xb6, 0x74, 0xff, 0x63, 0x58, 0x53, 0xf2, 0x6b, 0x5f, 0xdd, + 0x73, 0x0c, 0x87, 0xed, 0x59, 0x67, 0xbb, 0xa3, 0x46, 0x7a, 0xb3, 0xbd, 0xbb, 0xfb, 0x64, 0xb7, + 0x65, 0xb0, 0x0c, 0x2d, 0xa4, 0x83, 0xde, 0xd1, 0xe6, 0xc1, 0xfe, 0x7e, 0x7b, 0xb3, 0xd7, 0xde, + 0x62, 0xd9, 0x8d, 0xfb, 0xff, 0xf6, 0x27, 0x77, 0x32, 0x3f, 0xfe, 0xc9, 0x9d, 0xcc, 0x7f, 0xfe, + 0xc9, 0x9d, 0xcc, 0x0f, 0x7e, 0x7a, 0x67, 0xe9, 0xc7, 0x3f, 0xbd, 0xb3, 0xf4, 0xef, 0x7f, 0x7a, + 0x67, 0xe9, 0x33, 0x36, 0xfd, 0xcf, 0x8b, 0x8e, 0x8b, 0x64, 0x8d, 0xbc, 0xf3, 0x7f, 0x03, 0x00, + 0x00, 0xff, 0xff, 0x44, 0x1c, 0x74, 0x2e, 0xd7, 0x68, 0x00, 0x00, } func (m *SmartBlockSnapshotBase) Marshal() (dAtA []byte, err error) { @@ -11985,6 +12095,15 @@ func (m *BlockContentDataviewView) MarshalToSizedBuffer(dAtA []byte) (int, error _ = i var l int _ = l + if len(m.EndRelationKey) > 0 { + i -= len(m.EndRelationKey) + copy(dAtA[i:], m.EndRelationKey) + i = encodeVarintModels(dAtA, i, uint64(len(m.EndRelationKey))) + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0x82 + } if len(m.DefaultObjectTypeId) > 0 { i -= len(m.DefaultObjectTypeId) copy(dAtA[i:], m.DefaultObjectTypeId) @@ -13422,6 +13541,75 @@ func (m *AccountAuth) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *AccountAuthAppInfo) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AccountAuthAppInfo) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AccountAuthAppInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.IsActive { + i-- + if m.IsActive { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x40 + } + if m.Scope != 0 { + i = encodeVarintModels(dAtA, i, uint64(m.Scope)) + i-- + dAtA[i] = 0x38 + } + if m.ExpireAt != 0 { + i = encodeVarintModels(dAtA, i, uint64(m.ExpireAt)) + i-- + dAtA[i] = 0x30 + } + if m.CreatedAt != 0 { + i = encodeVarintModels(dAtA, i, uint64(m.CreatedAt)) + i-- + dAtA[i] = 0x28 + } + if len(m.AppKey) > 0 { + i -= len(m.AppKey) + copy(dAtA[i:], m.AppKey) + i = encodeVarintModels(dAtA, i, uint64(len(m.AppKey))) + i-- + dAtA[i] = 0x22 + } + if len(m.AppName) > 0 { + i -= len(m.AppName) + copy(dAtA[i:], m.AppName) + i = encodeVarintModels(dAtA, i, uint64(len(m.AppName))) + i-- + dAtA[i] = 0x12 + } + if len(m.AppHash) > 0 { + i -= len(m.AppHash) + copy(dAtA[i:], m.AppHash) + i = encodeVarintModels(dAtA, i, uint64(len(m.AppHash))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *LinkPreview) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -17453,6 +17641,10 @@ func (m *BlockContentDataviewView) Size() (n int) { if l > 0 { n += 1 + l + sovModels(uint64(l)) } + l = len(m.EndRelationKey) + if l > 0 { + n += 2 + l + sovModels(uint64(l)) + } return n } @@ -18030,6 +18222,39 @@ func (m *AccountAuth) Size() (n int) { return n } +func (m *AccountAuthAppInfo) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.AppHash) + if l > 0 { + n += 1 + l + sovModels(uint64(l)) + } + l = len(m.AppName) + if l > 0 { + n += 1 + l + sovModels(uint64(l)) + } + l = len(m.AppKey) + if l > 0 { + n += 1 + l + sovModels(uint64(l)) + } + if m.CreatedAt != 0 { + n += 1 + sovModels(uint64(m.CreatedAt)) + } + if m.ExpireAt != 0 { + n += 1 + sovModels(uint64(m.ExpireAt)) + } + if m.Scope != 0 { + n += 1 + sovModels(uint64(m.Scope)) + } + if m.IsActive { + n += 2 + } + return n +} + func (m *LinkPreview) Size() (n int) { if m == nil { return 0 @@ -23796,6 +24021,38 @@ func (m *BlockContentDataviewView) Unmarshal(dAtA []byte) error { } m.DefaultObjectTypeId = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 16: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field EndRelationKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.EndRelationKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipModels(dAtA[iNdEx:]) @@ -27367,6 +27624,229 @@ func (m *AccountAuth) Unmarshal(dAtA []byte) error { } return nil } +func (m *AccountAuthAppInfo) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AppInfo: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AppInfo: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppHash", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppHash = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppName", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppName = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field AppKey", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthModels + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthModels + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.AppKey = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CreatedAt", wireType) + } + m.CreatedAt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CreatedAt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field ExpireAt", wireType) + } + m.ExpireAt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.ExpireAt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Scope", wireType) + } + m.Scope = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Scope |= AccountAuthLocalApiScope(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field IsActive", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowModels + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.IsActive = bool(v != 0) + default: + iNdEx = preIndex + skippy, err := skipModels(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthModels + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *LinkPreview) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -33716,7 +34196,7 @@ func (m *InvitePayload) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.InviteType |= InvitePayloadInviteType(b&0x7F) << shift + m.InviteType |= InviteType(b&0x7F) << shift if b < 0x80 { break } diff --git a/pkg/lib/pb/model/protos/models.proto b/pkg/lib/pb/model/protos/models.proto index a7cbe2313..da0c60f5e 100644 --- a/pkg/lib/pb/model/protos/models.proto +++ b/pkg/lib/pb/model/protos/models.proto @@ -363,6 +363,7 @@ message Block { int32 pageLimit = 13; // Limit of objects shown in widget string defaultTemplateId = 14; // Default template that is chosen for new object created within the view string defaultObjectTypeId = 15; // Default object type that is chosen for new object created within the view + string endRelationKey = 16; // Group view by this relationKey enum Type { Table = 0; @@ -676,6 +677,15 @@ message Account { } message Auth { + message AppInfo { + string appHash = 1; + string appName = 2; // either from process or specified manually when creating + string appKey = 4; + int64 createdAt = 5; + int64 expireAt = 6; + LocalApiScope scope = 7; + bool isActive = 8; + } enum LocalApiScope { Limited = 0; // Used in WebClipper; AccountSelect(to be deprecated), ObjectSearch, ObjectShow, ObjectCreate, ObjectCreateFromURL, BlockPreview, BlockPaste, BroadcastPayloadEvent JsonAPI = 1; // JSON API only, no direct grpc api calls allowed @@ -1006,6 +1016,12 @@ enum ParticipantPermissions { NoPermissions = 3; } +enum InviteType { + Member = 0; // aclKey contains the key to sign the ACL record + Guest = 1; // guestKey contains the privateKey of the guest user + WithoutApprove = 2; // aclKey contains the key to sign the ACL record, but no approval needed +} + enum ParticipantStatus { Joining = 0; Active = 1; @@ -1204,10 +1220,6 @@ message InvitePayload { InviteType inviteType = 8; bytes guestKey = 9; - enum InviteType { - JoinAsMember = 0; // aclKey contains the key to sign the ACL record - JoinAsGuest = 1; // guestKey contains the privateKey of the guest user - } } message IdentityProfile { diff --git a/space/internal/components/aclobjectmanager/aclobjectmanager.go b/space/internal/components/aclobjectmanager/aclobjectmanager.go index 91fc5df02..9703bb5ef 100644 --- a/space/internal/components/aclobjectmanager/aclobjectmanager.go +++ b/space/internal/components/aclobjectmanager/aclobjectmanager.go @@ -19,7 +19,6 @@ import ( "github.com/anyproto/anytype-heart/core/block/chats/chatpush" "github.com/anyproto/anytype-heart/space/clientspace" "github.com/anyproto/anytype-heart/space/internal/components/aclnotifications" - "github.com/anyproto/anytype-heart/space/internal/components/invitemigrator" "github.com/anyproto/anytype-heart/space/internal/components/participantwatcher" "github.com/anyproto/anytype-heart/space/internal/components/spaceloader" "github.com/anyproto/anytype-heart/space/internal/components/spacestatus" @@ -61,7 +60,6 @@ type aclObjectManager struct { notificationService aclnotifications.AclNotification spaceLoaderListener SpaceLoaderListener participantWatcher participantwatcher.ParticipantWatcher - inviteMigrator invitemigrator.InviteMigrator accountService accountservice.Service pushNotificationService pushNotificationService @@ -114,7 +112,6 @@ func (a *aclObjectManager) Init(ap *app.App) (err error) { if a.statService == nil { a.statService = debugstat.NewNoOp() } - a.inviteMigrator = app.MustComponent[invitemigrator.InviteMigrator](ap) a.statService.AddProvider(a) a.waitLoad = make(chan struct{}) a.wait = make(chan struct{}) @@ -157,11 +154,7 @@ func (a *aclObjectManager) process() { return } a.spaceLoaderListener.OnSpaceLoad(a.sp.Id()) - err := a.inviteMigrator.MigrateExistingInvites(a.sp) - if err != nil { - log.Warn("migrate existing invites", zap.Error(err)) - } - err = a.participantWatcher.UpdateAccountParticipantFromProfile(a.ctx, a.sp) + err := a.participantWatcher.UpdateAccountParticipantFromProfile(a.ctx, a.sp) if err != nil { log.Error("init my identity", zap.Error(err)) } diff --git a/space/internal/components/aclobjectmanager/aclobjectmananger_test.go b/space/internal/components/aclobjectmanager/aclobjectmananger_test.go index 30693b0d9..4df21bb10 100644 --- a/space/internal/components/aclobjectmanager/aclobjectmananger_test.go +++ b/space/internal/components/aclobjectmanager/aclobjectmananger_test.go @@ -25,7 +25,6 @@ import ( "github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace" "github.com/anyproto/anytype-heart/space/internal/components/aclnotifications/mock_aclnotifications" "github.com/anyproto/anytype-heart/space/internal/components/dependencies/mock_dependencies" - "github.com/anyproto/anytype-heart/space/internal/components/invitemigrator/mock_invitemigrator" "github.com/anyproto/anytype-heart/space/internal/components/participantwatcher/mock_participantwatcher" "github.com/anyproto/anytype-heart/space/internal/components/spaceloader/mock_spaceloader" "github.com/anyproto/anytype-heart/space/internal/components/spacestatus/mock_spacestatus" @@ -70,7 +69,6 @@ func TestAclObjectManager(t *testing.T) { fx := newFixture(t) defer fx.finish(t) fx.mockLoader.EXPECT().WaitLoad(mock.Anything).Return(fx.mockSpace, nil) - fx.mockInviteMigrator.EXPECT().MigrateExistingInvites(fx.mockSpace).Return(nil) fx.mockParticipantWatcher.EXPECT().UpdateAccountParticipantFromProfile(mock.Anything, fx.mockSpace).Return(nil) fx.mockSpace.EXPECT().CommonSpace().Return(fx.mockCommonSpace) fx.mockSpace.EXPECT().Id().Return("spaceId") @@ -111,7 +109,6 @@ func TestAclObjectManager(t *testing.T) { fx := newFixture(t) defer fx.finish(t) fx.mockLoader.EXPECT().WaitLoad(mock.Anything).Return(fx.mockSpace, nil) - fx.mockInviteMigrator.EXPECT().MigrateExistingInvites(fx.mockSpace).Return(nil) fx.mockParticipantWatcher.EXPECT().UpdateAccountParticipantFromProfile(mock.Anything, fx.mockSpace).Return(nil) fx.mockSpace.EXPECT().CommonSpace().Return(fx.mockCommonSpace) fx.mockSpace.EXPECT().Id().Return("spaceId") @@ -158,7 +155,6 @@ func TestAclObjectManager(t *testing.T) { fx := newFixture(t) defer fx.finish(t) fx.mockLoader.EXPECT().WaitLoad(mock.Anything).Return(fx.mockSpace, nil) - fx.mockInviteMigrator.EXPECT().MigrateExistingInvites(fx.mockSpace).Return(nil) fx.mockStatus.EXPECT().SetOwner(a.ActualAccounts()["a"].Acl.AclState().Identity().Account(), mock.Anything).Return(nil) fx.mockParticipantWatcher.EXPECT().UpdateAccountParticipantFromProfile(mock.Anything, fx.mockSpace).Return(nil) fx.mockSpace.EXPECT().CommonSpace().Return(fx.mockCommonSpace) @@ -198,7 +194,6 @@ type fixture struct { mockCommonSpace *mock_commonspace.MockSpace mockParticipantWatcher *mock_participantwatcher.MockParticipantWatcher mockAclNotification *mock_aclnotifications.MockAclNotification - mockInviteMigrator *mock_invitemigrator.MockInviteMigrator mockAccountService *mock_accountservice.MockService spaceLoaderListener *testSpaceLoaderListener } @@ -216,12 +211,10 @@ func newFixture(t *testing.T) *fixture { mockCommonSpace: mock_commonspace.NewMockSpace(ctrl), mockParticipantWatcher: mock_participantwatcher.NewMockParticipantWatcher(t), mockAclNotification: mock_aclnotifications.NewMockAclNotification(t), - mockInviteMigrator: mock_invitemigrator.NewMockInviteMigrator(t), mockAccountService: mock_accountservice.NewMockService(ctrl), spaceLoaderListener: &testSpaceLoaderListener{}, } fx.a.Register(testutil.PrepareMock(ctx, fx.a, fx.mockStatus)). - Register(testutil.PrepareMock(ctx, fx.a, fx.mockInviteMigrator)). Register(testutil.PrepareMock(ctx, fx.a, fx.mockIndexer)). Register(testutil.PrepareMock(ctx, fx.a, fx.mockLoader)). Register(testutil.PrepareMock(ctx, fx.a, fx.mockParticipantWatcher)). diff --git a/space/internal/components/invitemigrator/invitemigrator.go b/space/internal/components/invitemigrator/invitemigrator.go deleted file mode 100644 index a17bf76ff..000000000 --- a/space/internal/components/invitemigrator/invitemigrator.go +++ /dev/null @@ -1,62 +0,0 @@ -package invitemigrator - -import ( - "fmt" - - "github.com/anyproto/any-sync/app" - "github.com/anyproto/any-sync/app/logger" - "go.uber.org/zap" - - "github.com/anyproto/anytype-heart/core/block/editor/smartblock" - "github.com/anyproto/anytype-heart/core/domain" - "github.com/anyproto/anytype-heart/space/clientspace" - "github.com/anyproto/anytype-heart/space/internal/components/spacestatus" -) - -const CName = "client.components.invitemigrator" - -var log = logger.NewNamed(CName) - -func New() InviteMigrator { - return &inviteMigrator{} -} - -type InviteMigrator interface { - app.Component - MigrateExistingInvites(space clientspace.Space) error -} - -type inviteMigrator struct { - status spacestatus.SpaceStatus -} - -func (i *inviteMigrator) Init(a *app.App) (err error) { - i.status = app.MustComponent[spacestatus.SpaceStatus](a) - return nil -} - -func (i *inviteMigrator) Name() (name string) { - return CName -} - -func (i *inviteMigrator) MigrateExistingInvites(space clientspace.Space) error { - spaceView := i.status.GetSpaceView() - spaceView.Lock() - fileCid, fileKey := spaceView.GetExistingInviteInfo() - if fileCid == "" { - spaceView.Unlock() - return nil - } - _, err := spaceView.RemoveExistingInviteInfo() - if err != nil { - log.Warn("remove existing invite info", zap.Error(err)) - } - spaceView.Unlock() - return space.Do(space.DerivedIDs().Workspace, func(sb smartblock.SmartBlock) error { - invObject, ok := sb.(domain.InviteObject) - if !ok { - return fmt.Errorf("space is not invite object") - } - return invObject.SetInviteFileInfo(fileCid, fileKey) - }) -} diff --git a/space/internal/components/invitemigrator/invitemigrator_test.go b/space/internal/components/invitemigrator/invitemigrator_test.go deleted file mode 100644 index 2c0da2992..000000000 --- a/space/internal/components/invitemigrator/invitemigrator_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package invitemigrator - -import ( - "context" - "testing" - - "github.com/anyproto/any-sync/app" - "github.com/stretchr/testify/mock" - "github.com/stretchr/testify/require" - - "github.com/anyproto/anytype-heart/core/block/editor/smartblock" - "github.com/anyproto/anytype-heart/core/block/editor/smartblock/smarttest" - "github.com/anyproto/anytype-heart/core/domain/mock_domain" - "github.com/anyproto/anytype-heart/pkg/lib/threads" - "github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace" - "github.com/anyproto/anytype-heart/space/internal/components/spacestatus/mock_spacestatus" - "github.com/anyproto/anytype-heart/space/techspace/mock_techspace" - "github.com/anyproto/anytype-heart/tests/testutil" -) - -type mockInviteObject struct { - smartblock.SmartBlock - *mock_domain.MockInviteObject -} - -func TestInviteMigrator(t *testing.T) { - t.Run("migrate existing invites", func(t *testing.T) { - fx := newFixture(t) - fx.mockStatus.EXPECT().GetSpaceView().Return(fx.mockSpaceView) - fx.mockSpaceView.EXPECT().Lock() - fx.mockSpaceView.EXPECT().Unlock() - fx.mockSpaceView.EXPECT().GetExistingInviteInfo().Return("fileCid", "fileKey") - fx.mockSpaceView.EXPECT().RemoveExistingInviteInfo().Return("fileCid", nil) - fx.mockSpaceObject.EXPECT().DerivedIDs().Return(threads.DerivedSmartblockIds{ - Workspace: "workspaceId", - }) - fx.mockSpaceObject.EXPECT().Do("workspaceId", mock.Anything).RunAndReturn(func(s string, f func(smartblock.SmartBlock) error) error { - return f(mockInviteObject{SmartBlock: smarttest.New("root"), MockInviteObject: fx.mockInviteObject}) - }) - fx.mockInviteObject.EXPECT().SetInviteFileInfo("fileCid", "fileKey").Return(nil) - err := fx.MigrateExistingInvites(fx.mockSpaceObject) - require.NoError(t, err) - }) - t.Run("migrate existing invites empty spaceview", func(t *testing.T) { - fx := newFixture(t) - fx.mockStatus.EXPECT().GetSpaceView().Return(fx.mockSpaceView) - fx.mockSpaceView.EXPECT().Lock() - fx.mockSpaceView.EXPECT().Unlock() - fx.mockSpaceView.EXPECT().GetExistingInviteInfo().Return("", "") - err := fx.MigrateExistingInvites(fx.mockSpaceObject) - require.NoError(t, err) - }) -} - -var ctx = context.Background() - -type fixture struct { - *inviteMigrator - a *app.App - mockStatus *mock_spacestatus.MockSpaceStatus - mockSpaceView *mock_techspace.MockSpaceView - mockInviteObject *mock_domain.MockInviteObject - mockSpaceObject *mock_clientspace.MockSpace -} - -func newFixture(t *testing.T) *fixture { - fx := &fixture{ - inviteMigrator: New().(*inviteMigrator), - a: new(app.App), - mockStatus: mock_spacestatus.NewMockSpaceStatus(t), - mockSpaceView: mock_techspace.NewMockSpaceView(t), - mockInviteObject: mock_domain.NewMockInviteObject(t), - mockSpaceObject: mock_clientspace.NewMockSpace(t), - } - fx.a.Register(testutil.PrepareMock(ctx, fx.a, fx.mockStatus)). - Register(fx) - - require.NoError(t, fx.a.Start(ctx)) - return fx -} diff --git a/space/internal/components/invitemigrator/mock_invitemigrator/mock_InviteMigrator.go b/space/internal/components/invitemigrator/mock_invitemigrator/mock_InviteMigrator.go deleted file mode 100644 index 12be9ef2d..000000000 --- a/space/internal/components/invitemigrator/mock_invitemigrator/mock_InviteMigrator.go +++ /dev/null @@ -1,174 +0,0 @@ -// Code generated by mockery. DO NOT EDIT. - -package mock_invitemigrator - -import ( - app "github.com/anyproto/any-sync/app" - clientspace "github.com/anyproto/anytype-heart/space/clientspace" - - mock "github.com/stretchr/testify/mock" -) - -// MockInviteMigrator is an autogenerated mock type for the InviteMigrator type -type MockInviteMigrator struct { - mock.Mock -} - -type MockInviteMigrator_Expecter struct { - mock *mock.Mock -} - -func (_m *MockInviteMigrator) EXPECT() *MockInviteMigrator_Expecter { - return &MockInviteMigrator_Expecter{mock: &_m.Mock} -} - -// Init provides a mock function with given fields: a -func (_m *MockInviteMigrator) Init(a *app.App) error { - ret := _m.Called(a) - - if len(ret) == 0 { - panic("no return value specified for Init") - } - - var r0 error - if rf, ok := ret.Get(0).(func(*app.App) error); ok { - r0 = rf(a) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockInviteMigrator_Init_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Init' -type MockInviteMigrator_Init_Call struct { - *mock.Call -} - -// Init is a helper method to define mock.On call -// - a *app.App -func (_e *MockInviteMigrator_Expecter) Init(a interface{}) *MockInviteMigrator_Init_Call { - return &MockInviteMigrator_Init_Call{Call: _e.mock.On("Init", a)} -} - -func (_c *MockInviteMigrator_Init_Call) Run(run func(a *app.App)) *MockInviteMigrator_Init_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(*app.App)) - }) - return _c -} - -func (_c *MockInviteMigrator_Init_Call) Return(err error) *MockInviteMigrator_Init_Call { - _c.Call.Return(err) - return _c -} - -func (_c *MockInviteMigrator_Init_Call) RunAndReturn(run func(*app.App) error) *MockInviteMigrator_Init_Call { - _c.Call.Return(run) - return _c -} - -// MigrateExistingInvites provides a mock function with given fields: space -func (_m *MockInviteMigrator) MigrateExistingInvites(space clientspace.Space) error { - ret := _m.Called(space) - - if len(ret) == 0 { - panic("no return value specified for MigrateExistingInvites") - } - - var r0 error - if rf, ok := ret.Get(0).(func(clientspace.Space) error); ok { - r0 = rf(space) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockInviteMigrator_MigrateExistingInvites_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MigrateExistingInvites' -type MockInviteMigrator_MigrateExistingInvites_Call struct { - *mock.Call -} - -// MigrateExistingInvites is a helper method to define mock.On call -// - space clientspace.Space -func (_e *MockInviteMigrator_Expecter) MigrateExistingInvites(space interface{}) *MockInviteMigrator_MigrateExistingInvites_Call { - return &MockInviteMigrator_MigrateExistingInvites_Call{Call: _e.mock.On("MigrateExistingInvites", space)} -} - -func (_c *MockInviteMigrator_MigrateExistingInvites_Call) Run(run func(space clientspace.Space)) *MockInviteMigrator_MigrateExistingInvites_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(clientspace.Space)) - }) - return _c -} - -func (_c *MockInviteMigrator_MigrateExistingInvites_Call) Return(_a0 error) *MockInviteMigrator_MigrateExistingInvites_Call { - _c.Call.Return(_a0) - return _c -} - -func (_c *MockInviteMigrator_MigrateExistingInvites_Call) RunAndReturn(run func(clientspace.Space) error) *MockInviteMigrator_MigrateExistingInvites_Call { - _c.Call.Return(run) - return _c -} - -// Name provides a mock function with given fields: -func (_m *MockInviteMigrator) Name() string { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for Name") - } - - var r0 string - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - return r0 -} - -// MockInviteMigrator_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name' -type MockInviteMigrator_Name_Call struct { - *mock.Call -} - -// Name is a helper method to define mock.On call -func (_e *MockInviteMigrator_Expecter) Name() *MockInviteMigrator_Name_Call { - return &MockInviteMigrator_Name_Call{Call: _e.mock.On("Name")} -} - -func (_c *MockInviteMigrator_Name_Call) Run(run func()) *MockInviteMigrator_Name_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockInviteMigrator_Name_Call) Return(name string) *MockInviteMigrator_Name_Call { - _c.Call.Return(name) - return _c -} - -func (_c *MockInviteMigrator_Name_Call) RunAndReturn(run func() string) *MockInviteMigrator_Name_Call { - _c.Call.Return(run) - return _c -} - -// NewMockInviteMigrator creates a new instance of MockInviteMigrator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. -// The first argument is typically a *testing.T value. -func NewMockInviteMigrator(t interface { - mock.TestingT - Cleanup(func()) -}) *MockInviteMigrator { - mock := &MockInviteMigrator{} - mock.Mock.Test(t) - - t.Cleanup(func() { mock.AssertExpectations(t) }) - - return mock -} diff --git a/space/internal/components/migration/systemobjectreviser/systemobjectreviser.go b/space/internal/components/migration/systemobjectreviser/systemobjectreviser.go index 07fca4ac5..73421fe9e 100644 --- a/space/internal/components/migration/systemobjectreviser/systemobjectreviser.go +++ b/space/internal/components/migration/systemobjectreviser/systemobjectreviser.go @@ -43,6 +43,7 @@ var ( } customObjectFilterKeys = []domain.RelationKey{ + bundle.RelationKeyRevision, bundle.RelationKeyIconOption, bundle.RelationKeyIconName, bundle.RelationKeyPluralName, diff --git a/space/internal/components/spaceloader/loadingspace.go b/space/internal/components/spaceloader/loadingspace.go index 03dc8bcb5..b3fec787e 100644 --- a/space/internal/components/spaceloader/loadingspace.go +++ b/space/internal/components/spaceloader/loadingspace.go @@ -8,7 +8,6 @@ import ( "github.com/anyproto/any-sync/app/logger" "github.com/anyproto/any-sync/commonspace/object/tree/objecttree" - "github.com/anyproto/any-sync/commonspace/spacesyncproto" "go.uber.org/zap" "github.com/anyproto/anytype-heart/space/clientspace" @@ -73,11 +72,13 @@ func (ls *loadingSpace) setLoadErr(err error) { func (ls *loadingSpace) loadRetry(ctx context.Context) { defer func() { if err := ls.spaceServiceProvider.onLoad(ls.space, ls.getLoadErr()); err != nil { - log.WarnCtx(ctx, "space onLoad error", zap.Error(err)) + log.WarnCtx(ctx, "space onLoad error", zap.Error(err), zap.Error(ls.getLoadErr())) } close(ls.loadCh) }() - if ls.load(ctx) { + shouldReturn, err := ls.load(ctx) + if shouldReturn { + ls.setLoadErr(err) return } timeout := 1 * time.Second @@ -87,7 +88,9 @@ func (ls *loadingSpace) loadRetry(ctx context.Context) { ls.setLoadErr(ctx.Err()) return case <-time.After(timeout): - if ls.load(ctx) { + shouldReturn, err := ls.load(ctx) + if shouldReturn { + ls.setLoadErr(err) return } } @@ -98,47 +101,44 @@ func (ls *loadingSpace) loadRetry(ctx context.Context) { } } -func (ls *loadingSpace) load(ctx context.Context) (notRetryable bool) { - sp, err := ls.spaceServiceProvider.open(ctx) - if errors.Is(err, spacesyncproto.ErrSpaceMissing) { - log.WarnCtx(ctx, "space load: space is missing", zap.String("spaceId", ls.ID), zap.Bool("notRetryable", ls.disableRemoteLoad), zap.Error(err)) - return ls.disableRemoteLoad - } - if err == nil { - err = sp.WaitMandatoryObjects(ctx) - if err != nil { - notRetryable = errors.Is(err, objecttree.ErrHasInvalidChanges) - log.WarnCtx(ctx, "space load: mandatory objects error", zap.String("spaceId", ls.ID), zap.Error(err), zap.Bool("notRetryable", ls.disableRemoteLoad || notRetryable)) - return ls.disableRemoteLoad || notRetryable - } - } - if err != nil { - if sp != nil { - closeErr := sp.Close(ctx) - if closeErr != nil { - log.WarnCtx(ctx, "space close error", zap.Error(closeErr)) - } - } - ls.setLoadErr(err) +func (ls *loadingSpace) logErrors(ctx context.Context, err error, mandatoryObjects bool, notRetryable bool) { + log := log.With(zap.String("spaceId", ls.ID), zap.Error(err), zap.Bool("notRetryable", notRetryable)) + if mandatoryObjects { + log.WarnCtx(ctx, "space load: mandatory objects error") if errors.Is(err, context.Canceled) { - log.WarnCtx(ctx, "space load: error: context bug", zap.String("spaceId", ls.ID), zap.Error(err), zap.Bool("notRetryable", ls.disableRemoteLoad)) - // hotfix for drpc bug - // todo: remove after https://github.com/anyproto/any-sync/pull/448 got integrated - return ls.disableRemoteLoad + log.WarnCtx(ctx, "space load: error: context bug") } - log.WarnCtx(ctx, "space load: error", zap.String("spaceId", ls.ID), zap.Error(err), zap.Bool("notRetryable", true)) } else { - if ls.latestAclHeadId != "" && !ls.disableRemoteLoad { - acl := sp.CommonSpace().Acl() - acl.RLock() - defer acl.RUnlock() - _, err := acl.Get(ls.latestAclHeadId) - if err != nil { - log.WarnCtx(ctx, "space load: acl head not found", zap.String("spaceId", ls.ID), zap.String("aclHeadId", ls.latestAclHeadId), zap.Error(err), zap.Bool("notRetryable", false)) - return false - } - } - ls.space = sp + log.WarnCtx(ctx, "space load: build space error") } - return true +} + +func (ls *loadingSpace) isNotRetryable(err error) bool { + return errors.Is(err, objecttree.ErrHasInvalidChanges) || ls.disableRemoteLoad +} + +func (ls *loadingSpace) load(ctx context.Context) (ok bool, err error) { + sp, err := ls.spaceServiceProvider.open(ctx) + if err != nil { + notRetryable := ls.isNotRetryable(err) + ls.logErrors(ctx, err, false, notRetryable) + return notRetryable, err + } + err = sp.WaitMandatoryObjects(ctx) + if err != nil { + notRetryable := ls.isNotRetryable(err) + ls.logErrors(ctx, err, true, notRetryable) + return notRetryable, err + } + if ls.latestAclHeadId != "" && !ls.disableRemoteLoad { + acl := sp.CommonSpace().Acl() + acl.RLock() + defer acl.RUnlock() + _, err := acl.Get(ls.latestAclHeadId) + if err != nil { + return false, err + } + } + ls.space = sp + return true, nil } diff --git a/space/internal/spaceprocess/loader/loader.go b/space/internal/spaceprocess/loader/loader.go index 2435c16c6..109b5365d 100644 --- a/space/internal/spaceprocess/loader/loader.go +++ b/space/internal/spaceprocess/loader/loader.go @@ -10,7 +10,6 @@ import ( "github.com/anyproto/anytype-heart/space/internal/components/aclnotifications" "github.com/anyproto/anytype-heart/space/internal/components/aclobjectmanager" "github.com/anyproto/anytype-heart/space/internal/components/builder" - "github.com/anyproto/anytype-heart/space/internal/components/invitemigrator" "github.com/anyproto/anytype-heart/space/internal/components/migration" "github.com/anyproto/anytype-heart/space/internal/components/participantwatcher" "github.com/anyproto/anytype-heart/space/internal/components/spaceloader" @@ -44,7 +43,6 @@ func New(app *app.App, params Params) Loader { Register(spaceloader.New(params.IsPersonal, false)). Register(aclnotifications.NewAclNotificationSender()). Register(aclobjectmanager.New(params.OwnerMetadata, params.GuestKey)). - Register(invitemigrator.New()). Register(participantwatcher.New()). Register(migration.New()) for _, comp := range params.AdditionalComps { diff --git a/space/join.go b/space/join.go index 124ca8c6d..4e3e004ed 100644 --- a/space/join.go +++ b/space/join.go @@ -49,6 +49,48 @@ func (s *service) Join(ctx context.Context, id, aclHeadId string) error { return nil } +func (s *service) InviteJoin(ctx context.Context, id, aclHeadId string) error { + s.mu.Lock() + waiter, exists := s.waiting[id] + if exists { + s.mu.Unlock() + <-waiter.wait + if waiter.err != nil { + return waiter.err + } + s.mu.Lock() + ctrl := s.spaceControllers[id] + s.mu.Unlock() + if ctrl.Mode() != mode.ModeLoading { + info := spaceinfo.NewSpacePersistentInfo(id) + info.SetAclHeadId(aclHeadId).SetAccountStatus(spaceinfo.AccountStatusActive) + return ctrl.SetPersistentInfo(ctx, info) + } + return nil + } + wait := make(chan struct{}) + s.waiting[id] = controllerWaiter{ + wait: wait, + } + s.mu.Unlock() + ctrl, err := s.factory.CreateActiveSpace(ctx, id, aclHeadId) + if err != nil { + s.mu.Lock() + close(wait) + s.waiting[id] = controllerWaiter{ + wait: wait, + err: err, + } + s.mu.Unlock() + return err + } + s.mu.Lock() + close(wait) + s.spaceControllers[ctrl.SpaceId()] = ctrl + s.mu.Unlock() + return nil +} + func (s *service) CancelLeave(ctx context.Context, id string) error { info := spaceinfo.NewSpacePersistentInfo(id) info.SetAccountStatus(spaceinfo.AccountStatusActive) diff --git a/space/mock_space/mock_Service.go b/space/mock_space/mock_Service.go index c98769e69..d932488e8 100644 --- a/space/mock_space/mock_Service.go +++ b/space/mock_space/mock_Service.go @@ -632,6 +632,54 @@ func (_c *MockService_Init_Call) RunAndReturn(run func(*app.App) error) *MockSer return _c } +// InviteJoin provides a mock function with given fields: ctx, id, aclHeadId +func (_m *MockService) InviteJoin(ctx context.Context, id string, aclHeadId string) error { + ret := _m.Called(ctx, id, aclHeadId) + + if len(ret) == 0 { + panic("no return value specified for InviteJoin") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok { + r0 = rf(ctx, id, aclHeadId) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// MockService_InviteJoin_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'InviteJoin' +type MockService_InviteJoin_Call struct { + *mock.Call +} + +// InviteJoin is a helper method to define mock.On call +// - ctx context.Context +// - id string +// - aclHeadId string +func (_e *MockService_Expecter) InviteJoin(ctx interface{}, id interface{}, aclHeadId interface{}) *MockService_InviteJoin_Call { + return &MockService_InviteJoin_Call{Call: _e.mock.On("InviteJoin", ctx, id, aclHeadId)} +} + +func (_c *MockService_InviteJoin_Call) Run(run func(ctx context.Context, id string, aclHeadId string)) *MockService_InviteJoin_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string)) + }) + return _c +} + +func (_c *MockService_InviteJoin_Call) Return(_a0 error) *MockService_InviteJoin_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *MockService_InviteJoin_Call) RunAndReturn(run func(context.Context, string, string) error) *MockService_InviteJoin_Call { + _c.Call.Return(run) + return _c +} + // Join provides a mock function with given fields: ctx, id, aclHeadId func (_m *MockService) Join(ctx context.Context, id string, aclHeadId string) error { ret := _m.Called(ctx, id, aclHeadId) diff --git a/space/service.go b/space/service.go index afb4983be..2e2db021f 100644 --- a/space/service.go +++ b/space/service.go @@ -61,6 +61,7 @@ type Service interface { Create(ctx context.Context) (space clientspace.Space, err error) Join(ctx context.Context, id, aclHeadId string) error + InviteJoin(ctx context.Context, id, aclHeadId string) error CancelLeave(ctx context.Context, id string) (err error) Get(ctx context.Context, id string) (space clientspace.Space, err error) Wait(ctx context.Context, spaceId string) (sp clientspace.Space, err error) diff --git a/space/spacefactory/mock_spacefactory/mock_SpaceFactory.go b/space/spacefactory/mock_spacefactory/mock_SpaceFactory.go index a29b6b1a7..7e4c6fe52 100644 --- a/space/spacefactory/mock_spacefactory/mock_SpaceFactory.go +++ b/space/spacefactory/mock_spacefactory/mock_SpaceFactory.go @@ -30,6 +30,66 @@ func (_m *MockSpaceFactory) EXPECT() *MockSpaceFactory_Expecter { return &MockSpaceFactory_Expecter{mock: &_m.Mock} } +// CreateActiveSpace provides a mock function with given fields: ctx, id, aclHeadId +func (_m *MockSpaceFactory) CreateActiveSpace(ctx context.Context, id string, aclHeadId string) (spacecontroller.SpaceController, error) { + ret := _m.Called(ctx, id, aclHeadId) + + if len(ret) == 0 { + panic("no return value specified for CreateActiveSpace") + } + + var r0 spacecontroller.SpaceController + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string, string) (spacecontroller.SpaceController, error)); ok { + return rf(ctx, id, aclHeadId) + } + if rf, ok := ret.Get(0).(func(context.Context, string, string) spacecontroller.SpaceController); ok { + r0 = rf(ctx, id, aclHeadId) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(spacecontroller.SpaceController) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok { + r1 = rf(ctx, id, aclHeadId) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MockSpaceFactory_CreateActiveSpace_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateActiveSpace' +type MockSpaceFactory_CreateActiveSpace_Call struct { + *mock.Call +} + +// CreateActiveSpace is a helper method to define mock.On call +// - ctx context.Context +// - id string +// - aclHeadId string +func (_e *MockSpaceFactory_Expecter) CreateActiveSpace(ctx interface{}, id interface{}, aclHeadId interface{}) *MockSpaceFactory_CreateActiveSpace_Call { + return &MockSpaceFactory_CreateActiveSpace_Call{Call: _e.mock.On("CreateActiveSpace", ctx, id, aclHeadId)} +} + +func (_c *MockSpaceFactory_CreateActiveSpace_Call) Run(run func(ctx context.Context, id string, aclHeadId string)) *MockSpaceFactory_CreateActiveSpace_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(string)) + }) + return _c +} + +func (_c *MockSpaceFactory_CreateActiveSpace_Call) Return(sp spacecontroller.SpaceController, err error) *MockSpaceFactory_CreateActiveSpace_Call { + _c.Call.Return(sp, err) + return _c +} + +func (_c *MockSpaceFactory_CreateActiveSpace_Call) RunAndReturn(run func(context.Context, string, string) (spacecontroller.SpaceController, error)) *MockSpaceFactory_CreateActiveSpace_Call { + _c.Call.Return(run) + return _c +} + // CreateAndSetTechSpace provides a mock function with given fields: ctx func (_m *MockSpaceFactory) CreateAndSetTechSpace(ctx context.Context) (*clientspace.TechSpace, error) { ret := _m.Called(ctx) diff --git a/space/spacefactory/spacefactory.go b/space/spacefactory/spacefactory.go index 65dcf5d9f..04548282e 100644 --- a/space/spacefactory/spacefactory.go +++ b/space/spacefactory/spacefactory.go @@ -32,6 +32,7 @@ type SpaceFactory interface { NewShareableSpace(ctx context.Context, id string, info spaceinfo.SpacePersistentInfo) (spacecontroller.SpaceController, error) CreateStreamableSpace(ctx context.Context, privKey crypto.PrivKey, id string, metadata []byte) (spacecontroller.SpaceController, error) NewStreamableSpace(ctx context.Context, id string, info spaceinfo.SpacePersistentInfo, metadata []byte) (spacecontroller.SpaceController, error) + CreateActiveSpace(ctx context.Context, id, aclHeadId string) (sp spacecontroller.SpaceController, err error) CreateMarketplaceSpace(ctx context.Context) (sp spacecontroller.SpaceController, err error) CreateAndSetTechSpace(ctx context.Context) (*clientspace.TechSpace, error) LoadAndSetTechSpace(ctx context.Context) (*clientspace.TechSpace, error) @@ -208,6 +209,26 @@ func (s *spaceFactory) CreateInvitingSpace(ctx context.Context, id, aclHeadId st return ctrl, err } +func (s *spaceFactory) CreateActiveSpace(ctx context.Context, id, aclHeadId string) (sp spacecontroller.SpaceController, err error) { + exists, err := s.techSpace.SpaceViewExists(ctx, id) + if err != nil { + return + } + info := spaceinfo.NewSpacePersistentInfo(id) + info.SetAclHeadId(aclHeadId).SetAccountStatus(spaceinfo.AccountStatusActive) + if !exists { + if err := s.techSpace.SpaceViewCreate(ctx, id, true, info); err != nil { + return nil, err + } + } + ctrl, err := shareablespace.NewSpaceController(id, info, s.app) + if err != nil { + return nil, err + } + err = ctrl.Start(ctx) + return ctrl, err +} + func (s *spaceFactory) CreateShareableSpace(ctx context.Context, id string) (sp spacecontroller.SpaceController, err error) { coreSpace, err := s.spaceCore.Get(ctx, id) if err != nil { diff --git a/space/techspace/mock_techspace/mock_SpaceView.go b/space/techspace/mock_techspace/mock_SpaceView.go index 595e0f0a7..e43365afa 100644 --- a/space/techspace/mock_techspace/mock_SpaceView.go +++ b/space/techspace/mock_techspace/mock_SpaceView.go @@ -22,61 +22,6 @@ func (_m *MockSpaceView) EXPECT() *MockSpaceView_Expecter { return &MockSpaceView_Expecter{mock: &_m.Mock} } -// GetExistingInviteInfo provides a mock function with given fields: -func (_m *MockSpaceView) GetExistingInviteInfo() (string, string) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for GetExistingInviteInfo") - } - - var r0 string - var r1 string - if rf, ok := ret.Get(0).(func() (string, string)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() string); ok { - r1 = rf() - } else { - r1 = ret.Get(1).(string) - } - - return r0, r1 -} - -// MockSpaceView_GetExistingInviteInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetExistingInviteInfo' -type MockSpaceView_GetExistingInviteInfo_Call struct { - *mock.Call -} - -// GetExistingInviteInfo is a helper method to define mock.On call -func (_e *MockSpaceView_Expecter) GetExistingInviteInfo() *MockSpaceView_GetExistingInviteInfo_Call { - return &MockSpaceView_GetExistingInviteInfo_Call{Call: _e.mock.On("GetExistingInviteInfo")} -} - -func (_c *MockSpaceView_GetExistingInviteInfo_Call) Run(run func()) *MockSpaceView_GetExistingInviteInfo_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockSpaceView_GetExistingInviteInfo_Call) Return(fileCid string, fileKey string) *MockSpaceView_GetExistingInviteInfo_Call { - _c.Call.Return(fileCid, fileKey) - return _c -} - -func (_c *MockSpaceView_GetExistingInviteInfo_Call) RunAndReturn(run func() (string, string)) *MockSpaceView_GetExistingInviteInfo_Call { - _c.Call.Return(run) - return _c -} - // GetLocalInfo provides a mock function with given fields: func (_m *MockSpaceView) GetLocalInfo() spaceinfo.SpaceLocalInfo { ret := _m.Called() @@ -289,61 +234,6 @@ func (_c *MockSpaceView_Lock_Call) RunAndReturn(run func()) *MockSpaceView_Lock_ return _c } -// RemoveExistingInviteInfo provides a mock function with given fields: -func (_m *MockSpaceView) RemoveExistingInviteInfo() (string, error) { - ret := _m.Called() - - if len(ret) == 0 { - panic("no return value specified for RemoveExistingInviteInfo") - } - - var r0 string - var r1 error - if rf, ok := ret.Get(0).(func() (string, error)); ok { - return rf() - } - if rf, ok := ret.Get(0).(func() string); ok { - r0 = rf() - } else { - r0 = ret.Get(0).(string) - } - - if rf, ok := ret.Get(1).(func() error); ok { - r1 = rf() - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// MockSpaceView_RemoveExistingInviteInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'RemoveExistingInviteInfo' -type MockSpaceView_RemoveExistingInviteInfo_Call struct { - *mock.Call -} - -// RemoveExistingInviteInfo is a helper method to define mock.On call -func (_e *MockSpaceView_Expecter) RemoveExistingInviteInfo() *MockSpaceView_RemoveExistingInviteInfo_Call { - return &MockSpaceView_RemoveExistingInviteInfo_Call{Call: _e.mock.On("RemoveExistingInviteInfo")} -} - -func (_c *MockSpaceView_RemoveExistingInviteInfo_Call) Run(run func()) *MockSpaceView_RemoveExistingInviteInfo_Call { - _c.Call.Run(func(args mock.Arguments) { - run() - }) - return _c -} - -func (_c *MockSpaceView_RemoveExistingInviteInfo_Call) Return(fileCid string, err error) *MockSpaceView_RemoveExistingInviteInfo_Call { - _c.Call.Return(fileCid, err) - return _c -} - -func (_c *MockSpaceView_RemoveExistingInviteInfo_Call) RunAndReturn(run func() (string, error)) *MockSpaceView_RemoveExistingInviteInfo_Call { - _c.Call.Return(run) - return _c -} - // SetAccessType provides a mock function with given fields: acc func (_m *MockSpaceView) SetAccessType(acc spaceinfo.AccessType) error { ret := _m.Called(acc) @@ -436,53 +326,6 @@ func (_c *MockSpaceView_SetAclIsEmpty_Call) RunAndReturn(run func(bool) error) * return _c } -// SetInviteFileInfo provides a mock function with given fields: fileCid, fileKey -func (_m *MockSpaceView) SetInviteFileInfo(fileCid string, fileKey string) error { - ret := _m.Called(fileCid, fileKey) - - if len(ret) == 0 { - panic("no return value specified for SetInviteFileInfo") - } - - var r0 error - if rf, ok := ret.Get(0).(func(string, string) error); ok { - r0 = rf(fileCid, fileKey) - } else { - r0 = ret.Error(0) - } - - return r0 -} - -// MockSpaceView_SetInviteFileInfo_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetInviteFileInfo' -type MockSpaceView_SetInviteFileInfo_Call struct { - *mock.Call -} - -// SetInviteFileInfo is a helper method to define mock.On call -// - fileCid string -// - fileKey string -func (_e *MockSpaceView_Expecter) SetInviteFileInfo(fileCid interface{}, fileKey interface{}) *MockSpaceView_SetInviteFileInfo_Call { - return &MockSpaceView_SetInviteFileInfo_Call{Call: _e.mock.On("SetInviteFileInfo", fileCid, fileKey)} -} - -func (_c *MockSpaceView_SetInviteFileInfo_Call) Run(run func(fileCid string, fileKey string)) *MockSpaceView_SetInviteFileInfo_Call { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(string), args[1].(string)) - }) - return _c -} - -func (_c *MockSpaceView_SetInviteFileInfo_Call) Return(err error) *MockSpaceView_SetInviteFileInfo_Call { - _c.Call.Return(err) - return _c -} - -func (_c *MockSpaceView_SetInviteFileInfo_Call) RunAndReturn(run func(string, string) error) *MockSpaceView_SetInviteFileInfo_Call { - _c.Call.Return(run) - return _c -} - // SetOwner provides a mock function with given fields: ownerId, createdDate func (_m *MockSpaceView) SetOwner(ownerId string, createdDate int64) error { ret := _m.Called(ownerId, createdDate) diff --git a/space/techspace/techspace.go b/space/techspace/techspace.go index c95fdf1ca..132d86715 100644 --- a/space/techspace/techspace.go +++ b/space/techspace/techspace.go @@ -75,14 +75,11 @@ type SpaceView interface { GetLocalInfo() spaceinfo.SpaceLocalInfo SetSpaceData(details *domain.Details) error SetSpaceLocalInfo(info spaceinfo.SpaceLocalInfo) error - SetInviteFileInfo(fileCid string, fileKey string) (err error) SetAccessType(acc spaceinfo.AccessType) error SetAclIsEmpty(isEmpty bool) (err error) SetOwner(ownerId string, createdDate int64) (err error) SetSpacePersistentInfo(info spaceinfo.SpacePersistentInfo) error - RemoveExistingInviteInfo() (fileCid string, err error) GetSpaceDescription() (data spaceinfo.SpaceDescription) - GetExistingInviteInfo() (fileCid string, fileKey string) SetSharedSpacesLimit(limits int) (err error) GetSharedSpacesLimit() (limits int) } diff --git a/tantivity_sha256.txt b/tantivity_sha256.txt index 2456d1167..c969cec02 100644 --- a/tantivity_sha256.txt +++ b/tantivity_sha256.txt @@ -1,12 +1,12 @@ -565dd299ef61edff535b20ec166f34f2399529b8254eed5d137a771a7b2b7c04 deps/libs/android-386.tar.gz -34d9c7d4a400653ddbcf28e64a5c8e055c08ab675df6b921cebedb4c5e667254 deps/libs/android-amd64.tar.gz -d90b501033763687f1ae136d69e284033594870c7143e50624799ff474e12f41 deps/libs/android-arm.tar.gz -3939f7ad6a1d08a0a559566d0ae5195739317a0023381bcb719603a7e2cac10d deps/libs/android-arm64.tar.gz -b7f7c3e82b1054a4c0755e7cd32f98d1dbe2ec55dab49f07e6620c8e2cd3ff83 deps/libs/darwin-amd64.tar.gz -40cdb051d2e063eb374e1a911ca7926beb4586c41a0347e430dc18fe5c216790 deps/libs/darwin-arm64.tar.gz -2dc93d6cb9356df9b5c330a6c566e1da1a4dfb32a17f1262080f2c1a875a5775 deps/libs/ios-amd64.tar.gz -2a949a364f29c5801c3c18607dbc14b5edefdcd002746ce94c89f297bb4f620c deps/libs/ios-arm64.tar.gz -b09afc40d37a37377579ec4096511fd88cc22cdd387518225a77f205c226130a deps/libs/ios-arm64-sim.tar.gz -122010a6f287a3d3b169a64c26918bd5745a1190c99638e7e91a664172781cf7 deps/libs/linux-amd64-musl.tar.gz -2b86930fcd938fe41413f4f915c90a2093d703179c61153ec4a007cdd2ed4a9c deps/libs/linux-arm64-musl.tar.gz -2cdefb8975651849f6c5f41c5a934035d959e797c6fdef9a5a946ec9052e3bee deps/libs/windows-amd64.tar.gz +bbde99ff75d9c20a7eefeea4ca6c5c77a75c1d1114ee7d53d77b78a49741f2e3 deps/libs/android-386.tar.gz +5c4599d29230f689ed2cfb21185548cb2fc3e8e61fd31e856c969fd4bdd7abc3 deps/libs/android-amd64.tar.gz +e4d16d8fce08b5de22d475c8e9be02473c07786b298601d6b96768f0fc7ecbd6 deps/libs/android-arm.tar.gz +8c67e2b0e8cf701ea6fecbe074f19ee48fb4321d02bc8a8b3fb11055397eb853 deps/libs/android-arm64.tar.gz +1278ecd5b7d73e36163e48c6b98b88a6e7c96a663ddba31eb168224a6921fd92 deps/libs/darwin-amd64.tar.gz +209429e1ffb2cdd55cedb90c74617d87aced121bc905802430f71b48b0ea6a43 deps/libs/darwin-arm64.tar.gz +101f9afde0a06339d81060f1bb77be63055d9674878cea5f7b142fcc3ca9658e deps/libs/ios-amd64.tar.gz +8b0f568bbf09e0ada76c9b331eab59ad9ed409aa37dec3b3d0538480babfeb5e deps/libs/ios-arm64.tar.gz +f3a90aff6eab8aa0e3e89a2866f0dbbd9c5ffb0d8a47d5aa4ad3d28afbd3416b deps/libs/ios-arm64-sim.tar.gz +74c3585022a962794c49f8f15606d3093684cad5543868e90d91d3ca876c45a8 deps/libs/linux-amd64-musl.tar.gz +2e1a052e7c12b3a0fa845c53c151228243ab6483c9fa3d83b97f34f40550fa6b deps/libs/linux-arm64-musl.tar.gz +5357ae4522bd826a8c53cb39d8c63b77e4cbc1683154c54b6f71542a25b1dcd1 deps/libs/windows-amd64.tar.gz diff --git a/util/builtinobjects/data/empty.zip b/util/builtinobjects/data/empty.zip index 40a3fa6c9..da2d1aa7f 100644 Binary files a/util/builtinobjects/data/empty.zip and b/util/builtinobjects/data/empty.zip differ diff --git a/util/futures/future.go b/util/futures/future.go new file mode 100644 index 000000000..7fbee9410 --- /dev/null +++ b/util/futures/future.go @@ -0,0 +1,59 @@ +package futures + +import ( + "sync" +) + +type Future[T any] struct { + cond *sync.Cond + + ok bool + value T + err error +} + +// New creates a value that should be resolved later. It's necessary to resolve a future eventually, otherwise there is +// a possibility of deadlock, when someone waits for never-resolving future. +func New[T any]() *Future[T] { + return &Future[T]{ + cond: &sync.Cond{ + L: &sync.Mutex{}, + }, + } +} + +func (f *Future[T]) Wait() (T, error) { + f.cond.L.Lock() + for !f.ok { + f.cond.Wait() + } + f.cond.L.Unlock() + + return f.value, f.err +} + +// Resolve sets value or error for future only once, all consequent calls to Resolve have no effect +func (f *Future[T]) Resolve(val T, err error) { + f.cond.L.Lock() + defer f.cond.L.Unlock() + + // Resolve once + if f.ok { + return + } + + f.ok = true + f.value = val + f.err = err + + f.cond.Broadcast() +} + +func (f *Future[T]) ResolveValue(val T) { + f.Resolve(val, nil) +} + +func (f *Future[T]) ResolveErr(err error) { + var defaultValue T + f.Resolve(defaultValue, err) +} diff --git a/util/futures/future_test.go b/util/futures/future_test.go new file mode 100644 index 000000000..7d94ed8e0 --- /dev/null +++ b/util/futures/future_test.go @@ -0,0 +1,88 @@ +package futures + +import ( + "fmt" + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestFutures(t *testing.T) { + t.Run("synchronously in linear order: has value", func(t *testing.T) { + f := New[int]() + f.ResolveValue(42) + + got, err := f.Wait() + require.NoError(t, err) + assert.Equal(t, 42, got) + }) + + t.Run("synchronously in linear order: has error", func(t *testing.T) { + f := New[int]() + f.ResolveErr(fmt.Errorf("test error")) + + got, err := f.Wait() + require.Error(t, err) + assert.Equal(t, 0, got) + }) + + t.Run("one producer, multiple consumers: has value", func(t *testing.T) { + f := New[int]() + + var wg sync.WaitGroup + for range 10 { + wg.Add(1) + go func() { + defer wg.Done() + got, err := f.Wait() + require.NoError(t, err) + assert.Equal(t, 42, got) + }() + } + + f.ResolveValue(42) + + wg.Wait() + }) + + t.Run("one producer, multiple consumers: has error", func(t *testing.T) { + f := New[int]() + + var wg sync.WaitGroup + for range 10 { + wg.Add(1) + go func() { + defer wg.Done() + got, err := f.Wait() + require.Error(t, err) + assert.Equal(t, 0, got) + }() + } + + f.ResolveErr(fmt.Errorf("test error")) + + wg.Wait() + }) + + t.Run("multiple producers: has first resolved value", func(t *testing.T) { + f := New[int]() + + var wg sync.WaitGroup + for i := range 10 { + wg.Add(1) + go func() { + defer wg.Done() + + f.ResolveValue(i + 1) + }() + } + wg.Wait() + + got, err := f.Wait() + require.NoError(t, err) + + assert.True(t, got >= 1 && got <= 11) + }) +} diff --git a/util/grpcprocess/grpcprocess.go b/util/grpcprocess/grpcprocess.go new file mode 100644 index 000000000..cbda054c7 --- /dev/null +++ b/util/grpcprocess/grpcprocess.go @@ -0,0 +1,94 @@ +//go:build !gomobile + +package grpcprocess + +import ( + "context" + "fmt" + "net" + "os" + + gnet "github.com/shirou/gopsutil/v3/net" + gproc "github.com/shirou/gopsutil/v3/process" + "google.golang.org/grpc" + "google.golang.org/grpc/peer" +) + +// ProcessInfo holds details about the client process. +type ProcessInfo struct { + PID int32 + Name string + Path string +} + +// FromContext retrieves the ProcessInfo stored by the interceptor. +func FromContext(ctx context.Context) (*ProcessInfo, bool) { + pi, ok := ctx.Value(processInfoKey).(*ProcessInfo) + return pi, ok +} + +// ProcessInfoInterceptor returns an interceptor that *only* runs for the +// gRPC methods listed in allowedMethods (exact match on info.FullMethod). +func ProcessInfoInterceptor(allowedMethods ...string) grpc.UnaryServerInterceptor { + allow := make(map[string]struct{}, len(allowedMethods)) + for _, m := range allowedMethods { + allow[m] = struct{}{} + } + + return func( + ctx context.Context, + req interface{}, + info *grpc.UnaryServerInfo, + handler grpc.UnaryHandler, + ) (interface{}, error) { + if _, ok := allow[info.FullMethod]; !ok { + return handler(ctx, req) + } + if _, ok := ctx.Value(processInfoKey).(*ProcessInfo); ok { + // already set + return handler(ctx, req) + } + if p, ok := peer.FromContext(ctx); ok { + if host, port, err := net.SplitHostPort(p.Addr.String()); err == nil { + ip := net.ParseIP(host) + if ip.IsLoopback() { + if pi, err := ResolveProcess(host, port); err == nil { + ctx = context.WithValue(ctx, processInfoKey, pi) + } + } + } + } + return handler(ctx, req) + } +} + +type ctxKey string + +const processInfoKey ctxKey = "processInfo" + +func ResolveProcess(remoteIP, remotePort string) (*ProcessInfo, error) { + conns, err := gnet.Connections("tcp") + if err != nil { + return nil, err + } + + self := int32(os.Getpid()) + for _, c := range conns { + if c.Pid == self || c.Status != "ESTABLISHED" { + continue + } + + if fmt.Sprint(c.Laddr.IP) == remoteIP && + fmt.Sprint(c.Laddr.Port) == remotePort { + + proc, err := gproc.NewProcess(c.Pid) + if err != nil { + return nil, err + } + name, _ := proc.Name() + exe, _ := proc.Exe() + return &ProcessInfo{PID: c.Pid, Name: name, Path: exe}, nil + } + } + return nil, fmt.Errorf("process for %s:%s not found", remoteIP, remotePort) +} diff --git a/util/grpcprocess/grpcprocess_mobile.go b/util/grpcprocess/grpcprocess_mobile.go new file mode 100644 index 000000000..35a0d91cd --- /dev/null +++ b/util/grpcprocess/grpcprocess_mobile.go @@ -0,0 +1,38 @@ +//go:build gomobile + +package grpcprocess + +import ( + "context" + "fmt" + + "google.golang.org/grpc" +) + +// ProcessInfo holds details about the client process. +type ProcessInfo struct { + PID int32 + Name string + Path string +} + +// FromContext retrieves the ProcessInfo stored by the interceptor. +func FromContext(ctx context.Context) (*ProcessInfo, bool) { + return nil, false +} + +// ProcessInfoInterceptor returns an interceptor that *only* runs for the +// gRPC methods listed in allowedMethods (exact match on info.FullMethod). +func ProcessInfoInterceptor(allowedMethods ...string) grpc.UnaryServerInterceptor { + return func( + ctx context.Context, + req interface{}, + info *grpc.UnaryServerInfo, + handler grpc.UnaryHandler, + ) (interface{}, error) { + return handler(ctx, req) + } +} +func ResolveProcess(remoteIP, remotePort string) (*ProcessInfo, error) { + return nil, fmt.Errorf("not supported in gomobile") +}