1
0
Fork 0
mirror of https://github.com/anyproto/anytype-heart.git synced 2025-06-07 21:37:04 +09:00

GO-5171 Revert "Merge pull request #2052 from anyproto/GO-4146-new-spacestore"

This reverts commit 862fd01621, reversing
changes made to ea41c4784d.

# Conflicts:
#	clientlibrary/service/service.pb.go
#	core/block/source/store.go
#	go.mod
#	go.sum
#	pb/commands.pb.go
#	pb/service/service.pb.go

# Conflicts:
#	clientlibrary/service/service.pb.go
#	go.mod
#	go.sum
#	pb/commands.pb.go
#	pb/service/service.pb.go
This commit is contained in:
Roman Khafizianov 2025-02-19 12:14:33 +01:00
parent 48fe32e6e0
commit 5222f44f83
No known key found for this signature in database
GPG key ID: F07A7D55A2684852
106 changed files with 3515 additions and 7791 deletions

View file

@ -97,9 +97,6 @@ packages:
github.com/anyproto/anytype-heart/space/spacecore/storage:
interfaces:
ClientStorage:
github.com/anyproto/anytype-heart/space/spacecore/storage/anystorage:
interfaces:
ClientSpaceStorage:
github.com/anyproto/anytype-heart/space/techspace:
interfaces:
TechSpace:

View file

@ -25,352 +25,350 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
func init() { proto.RegisterFile("pb/protos/service/service.proto", fileDescriptor_93a29dc403579097) }
var fileDescriptor_93a29dc403579097 = []byte{
// 5514 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x9d, 0x5f, 0x6f, 0x24, 0x49,
0x52, 0xc0, 0xb7, 0x5f, 0x58, 0xa8, 0xe3, 0x16, 0xe8, 0x85, 0x65, 0x6f, 0xb9, 0x9b, 0x99, 0x9d,
0x9d, 0xb1, 0x3d, 0x63, 0xbb, 0x3d, 0x3b, 0xb3, 0xff, 0xb8, 0x43, 0x82, 0x1e, 0x7b, 0xec, 0xf5,
0x9d, 0xed, 0x35, 0xee, 0xf6, 0x8c, 0xb4, 0x12, 0x12, 0xe5, 0xaa, 0x74, 0xbb, 0x70, 0x75, 0x65,
0x5d, 0x55, 0x76, 0x7b, 0xfa, 0x10, 0x08, 0x04, 0x02, 0x81, 0x40, 0x9c, 0xf8, 0x27, 0x78, 0x42,
0x42, 0x7c, 0x00, 0x3e, 0x06, 0x8f, 0xf7, 0xc8, 0x23, 0xda, 0xfd, 0x0a, 0x7c, 0x00, 0x54, 0xf9,
0x3f, 0xa3, 0x32, 0xb2, 0xca, 0xcb, 0xd3, 0x8c, 0x1c, 0xbf, 0x88, 0xc8, 0xac, 0x8c, 0xcc, 0x8c,
0xcc, 0xca, 0xca, 0x8e, 0xee, 0x96, 0x17, 0x3b, 0x65, 0x45, 0x19, 0xad, 0x77, 0x6a, 0x52, 0x2d,
0xb3, 0x84, 0xa8, 0x7f, 0x47, 0xfc, 0xcf, 0xc3, 0x37, 0xe3, 0x62, 0xc5, 0x56, 0x25, 0x79, 0xef,
0x5d, 0x43, 0x26, 0x74, 0x3e, 0x8f, 0x8b, 0xb4, 0x16, 0xc8, 0x7b, 0xef, 0x18, 0x09, 0x59, 0x92,
0x82, 0xc9, 0xbf, 0x3f, 0xfd, 0x8f, 0xff, 0x1d, 0x44, 0x6f, 0xed, 0xe6, 0x19, 0x29, 0xd8, 0xae,
0xd4, 0x18, 0x7e, 0x19, 0x7d, 0x7b, 0x5c, 0x96, 0x07, 0x84, 0xbd, 0x24, 0x55, 0x9d, 0xd1, 0x62,
0xf8, 0xc1, 0x48, 0x3a, 0x18, 0x9d, 0x95, 0xc9, 0x68, 0x5c, 0x96, 0x23, 0x23, 0x1c, 0x9d, 0x91,
0x1f, 0x2f, 0x48, 0xcd, 0xde, 0x7b, 0x10, 0x86, 0xea, 0x92, 0x16, 0x35, 0x19, 0x5e, 0x46, 0xbf,
0x32, 0x2e, 0xcb, 0x09, 0x61, 0x7b, 0xa4, 0xa9, 0xc0, 0x84, 0xc5, 0x8c, 0x0c, 0xd7, 0x5b, 0xaa,
0x2e, 0xa0, 0x7d, 0x6c, 0x74, 0x83, 0xd2, 0xcf, 0x34, 0xfa, 0x56, 0xe3, 0xe7, 0x6a, 0xc1, 0x52,
0x7a, 0x53, 0x0c, 0xdf, 0x6f, 0x2b, 0x4a, 0x91, 0xb6, 0x7d, 0x3f, 0x84, 0x48, 0xab, 0xaf, 0xa2,
0x5f, 0x7c, 0x15, 0xe7, 0x39, 0x61, 0xbb, 0x15, 0x69, 0x0a, 0xee, 0xea, 0x08, 0xd1, 0x48, 0xc8,
0xb4, 0xdd, 0x0f, 0x82, 0x8c, 0x34, 0xfc, 0x65, 0xf4, 0x6d, 0x21, 0x39, 0x23, 0x09, 0x5d, 0x92,
0x6a, 0xe8, 0xd5, 0x92, 0x42, 0xe4, 0x91, 0xb7, 0x20, 0x68, 0x7b, 0x97, 0x16, 0x4b, 0x52, 0x31,
0xbf, 0x6d, 0x29, 0x0c, 0xdb, 0x36, 0x90, 0xb4, 0xfd, 0x57, 0x83, 0xe8, 0xbb, 0xe3, 0x24, 0xa1,
0x8b, 0x82, 0x1d, 0xd1, 0x24, 0xce, 0x8f, 0xb2, 0xe2, 0xfa, 0x84, 0xdc, 0xec, 0x5e, 0x35, 0x7c,
0x31, 0x23, 0xc3, 0x67, 0xee, 0x53, 0x15, 0xe8, 0x48, 0xb3, 0x23, 0x1b, 0xd6, 0xbe, 0x3f, 0xba,
0x9d, 0x92, 0x2c, 0xcb, 0xdf, 0x0d, 0xa2, 0x3b, 0xb0, 0x2c, 0x13, 0x9a, 0x2f, 0x89, 0x29, 0xcd,
0xc7, 0x1d, 0x86, 0x5d, 0x5c, 0x97, 0xe7, 0x93, 0xdb, 0xaa, 0xc9, 0x12, 0xe5, 0xd1, 0xdb, 0x76,
0xb8, 0x4c, 0x48, 0xcd, 0xbb, 0xd3, 0x23, 0x3c, 0x22, 0x24, 0xa2, 0x3d, 0x3f, 0xee, 0x83, 0x4a,
0x6f, 0x59, 0x34, 0x94, 0xde, 0x72, 0x5a, 0x6b, 0x67, 0x1b, 0x5e, 0x0b, 0x16, 0xa1, 0x7d, 0x3d,
0xea, 0x41, 0x4a, 0x57, 0xbf, 0x1f, 0xfd, 0xd2, 0x2b, 0x5a, 0x5d, 0xd7, 0x65, 0x9c, 0x10, 0xd9,
0x15, 0x1e, 0xba, 0xda, 0x4a, 0x0a, 0x7b, 0xc3, 0x5a, 0x17, 0x66, 0x05, 0xad, 0x12, 0x7e, 0x51,
0x12, 0x38, 0x06, 0x19, 0xc5, 0x46, 0x88, 0x05, 0x2d, 0x84, 0xa4, 0xed, 0xeb, 0x68, 0x68, 0x6c,
0x5f, 0xfc, 0x01, 0x49, 0xd8, 0x38, 0x4d, 0x61, 0xab, 0x18, 0x5d, 0x4e, 0x8c, 0xc6, 0x69, 0x8a,
0xb5, 0x8a, 0x1f, 0x95, 0xce, 0x6e, 0xa2, 0x77, 0x80, 0xb3, 0xa3, 0xac, 0xe6, 0x0e, 0xb7, 0xc3,
0x56, 0x24, 0xa6, 0x9d, 0x8e, 0xfa, 0xe2, 0xd2, 0xf1, 0x9f, 0x0c, 0xa2, 0xef, 0x78, 0x3c, 0x9f,
0x91, 0x39, 0x5d, 0x92, 0xe1, 0x93, 0x6e, 0x6b, 0x82, 0xd4, 0xfe, 0x3f, 0xbc, 0x85, 0x86, 0x27,
0x4c, 0x26, 0x24, 0x27, 0x09, 0x43, 0xc3, 0x44, 0x88, 0x3b, 0xc3, 0x44, 0x63, 0x56, 0x0f, 0x53,
0xc2, 0x03, 0xc2, 0x76, 0x17, 0x55, 0x45, 0x0a, 0x86, 0xb6, 0xa5, 0x41, 0x3a, 0xdb, 0xd2, 0x41,
0x3d, 0xf5, 0x39, 0x20, 0x6c, 0x9c, 0xe7, 0x68, 0x7d, 0x84, 0xb8, 0xb3, 0x3e, 0x1a, 0x93, 0x1e,
0x92, 0xe8, 0x97, 0xad, 0x27, 0xc6, 0x0e, 0x8b, 0x4b, 0x3a, 0xc4, 0x9f, 0x05, 0x97, 0x6b, 0x1f,
0xeb, 0x9d, 0x9c, 0xa7, 0x1a, 0x2f, 0x5e, 0x97, 0xb4, 0xc2, 0x9b, 0x45, 0x88, 0x3b, 0xab, 0xa1,
0x31, 0xe9, 0xe1, 0xf7, 0xa2, 0xb7, 0xe4, 0x28, 0xa9, 0xe6, 0xb3, 0x07, 0xde, 0x21, 0x14, 0x4e,
0x68, 0x0f, 0x3b, 0xa8, 0x96, 0xf9, 0xe3, 0x6c, 0x56, 0x35, 0xa3, 0x8f, 0xdf, 0xbc, 0x94, 0x76,
0x98, 0x37, 0x94, 0x34, 0x4f, 0xa3, 0x5f, 0x75, 0xcd, 0xef, 0xc6, 0x45, 0x42, 0xf2, 0xe1, 0xe3,
0x90, 0xba, 0x60, 0xb4, 0xab, 0xcd, 0x5e, 0xac, 0x19, 0xec, 0x24, 0x21, 0x07, 0xd3, 0x0f, 0xbc,
0xda, 0x60, 0x28, 0x7d, 0x10, 0x86, 0x5a, 0xb6, 0xf7, 0x48, 0x4e, 0x50, 0xdb, 0x42, 0xd8, 0x61,
0x5b, 0x43, 0xd2, 0x76, 0x15, 0xfd, 0x9a, 0x6e, 0xe6, 0x26, 0x2f, 0xe0, 0xf2, 0x66, 0xd2, 0xd9,
0x44, 0xda, 0xd1, 0x86, 0xb4, 0xaf, 0xad, 0x7e, 0x70, 0xab, 0x3e, 0x72, 0x44, 0xf1, 0xd7, 0x07,
0x8c, 0x27, 0x0f, 0xc2, 0x90, 0xb4, 0xfd, 0xd7, 0x83, 0xe8, 0x7b, 0x52, 0xf6, 0xa2, 0x88, 0x2f,
0x72, 0xc2, 0xa7, 0xf8, 0x13, 0xc2, 0x6e, 0x68, 0x75, 0x3d, 0x59, 0x15, 0x09, 0x92, 0xce, 0xf8,
0xe1, 0x8e, 0x74, 0x06, 0x55, 0x92, 0x85, 0xf9, 0xc3, 0xe8, 0x5d, 0x15, 0x14, 0x57, 0x71, 0x31,
0x23, 0x3f, 0xac, 0x69, 0x31, 0x2e, 0xb3, 0x71, 0x9a, 0x56, 0xc3, 0x91, 0xbf, 0xe9, 0x21, 0xa7,
0x4b, 0xb0, 0xd3, 0x9b, 0xb7, 0xd2, 0x67, 0xf9, 0x94, 0x19, 0x2d, 0x61, 0xfa, 0xac, 0x1e, 0x1f,
0xa3, 0x25, 0x96, 0x3e, 0xbb, 0x48, 0xcb, 0xea, 0x71, 0x33, 0x07, 0xf9, 0xad, 0x1e, 0xdb, 0x93,
0xce, 0xfd, 0x10, 0x62, 0xe6, 0x00, 0xf5, 0xa0, 0x68, 0x71, 0x99, 0xcd, 0xce, 0xcb, 0xb4, 0xe9,
0x43, 0x8f, 0xfc, 0x75, 0xb6, 0x10, 0x64, 0x0e, 0x40, 0x50, 0xe9, 0xed, 0x6f, 0x4d, 0x96, 0x29,
0xc7, 0xa5, 0xfd, 0x8a, 0xce, 0x8f, 0xc8, 0x2c, 0x4e, 0x56, 0x72, 0x30, 0xfd, 0x28, 0x34, 0x8a,
0x41, 0x5a, 0x17, 0xe2, 0xe3, 0x5b, 0x6a, 0xc9, 0xf2, 0xfc, 0xdb, 0x20, 0x7a, 0xe0, 0xc4, 0x89,
0x0c, 0x26, 0x51, 0xfa, 0x71, 0x91, 0x9e, 0x91, 0x9a, 0xc5, 0x15, 0x1b, 0x7e, 0x3f, 0x10, 0x03,
0x88, 0x8e, 0x2e, 0xdb, 0x0f, 0xbe, 0x91, 0xae, 0x69, 0xf5, 0x49, 0x33, 0x4b, 0xc8, 0xf1, 0xc7,
0x6d, 0x75, 0x2e, 0x81, 0xa3, 0xcf, 0xfd, 0x10, 0x62, 0x5a, 0x9d, 0x0b, 0x0e, 0x8b, 0x65, 0xc6,
0xc8, 0x01, 0x29, 0x48, 0xd5, 0x6e, 0x75, 0xa1, 0xea, 0x22, 0x48, 0xab, 0x23, 0xa8, 0x19, 0xe9,
0x1c, 0x6f, 0x3a, 0xd3, 0xd8, 0x0c, 0x18, 0x69, 0xe5, 0x1a, 0x5b, 0xfd, 0x60, 0xb3, 0x54, 0xb6,
0x7c, 0x9e, 0x91, 0x25, 0xbd, 0x86, 0x4b, 0x65, 0xdb, 0x84, 0x00, 0x90, 0xa5, 0xb2, 0x17, 0x34,
0xe9, 0x80, 0xe5, 0xe7, 0x65, 0x46, 0x6e, 0x40, 0x3a, 0x60, 0x2b, 0x37, 0x62, 0x24, 0x1d, 0xf0,
0x60, 0xd2, 0xc3, 0x49, 0xf4, 0x0b, 0x5c, 0xf8, 0x43, 0x9a, 0x15, 0xc3, 0xbb, 0x1e, 0xa5, 0x46,
0xa0, 0xad, 0xde, 0xc3, 0x01, 0x50, 0xe2, 0xe6, 0xaf, 0x72, 0x6e, 0x7e, 0x88, 0x28, 0x81, 0x69,
0x79, 0xad, 0x0b, 0x33, 0x79, 0x18, 0x17, 0x36, 0xe3, 0xd7, 0xe4, 0x2a, 0xae, 0xb2, 0x62, 0x36,
0xf4, 0xe9, 0x5a, 0x72, 0x24, 0x0f, 0xf3, 0x71, 0x20, 0x84, 0xa5, 0xe2, 0xb8, 0x2c, 0xab, 0x66,
0x58, 0xf4, 0x85, 0xb0, 0x8b, 0x04, 0x43, 0xb8, 0x85, 0xfa, 0xbd, 0xed, 0x91, 0x24, 0xcf, 0x8a,
0xa0, 0x37, 0x89, 0xf4, 0xf1, 0x66, 0x50, 0x10, 0xbc, 0x47, 0x24, 0x5e, 0x12, 0x55, 0x33, 0xdf,
0x93, 0xb1, 0x81, 0x60, 0xf0, 0x02, 0xd0, 0x2c, 0x7a, 0xb9, 0xf8, 0x38, 0xbe, 0x26, 0xcd, 0x03,
0x26, 0xcd, 0xa4, 0x3a, 0xf4, 0xe9, 0x3b, 0x04, 0xb2, 0xe8, 0xf5, 0x93, 0xd2, 0xd5, 0x22, 0x7a,
0x87, 0xcb, 0x4f, 0xe3, 0x8a, 0x65, 0x49, 0x56, 0xc6, 0x85, 0x5a, 0x4c, 0xf9, 0xfa, 0x75, 0x8b,
0xd2, 0x2e, 0xb7, 0x7b, 0xd2, 0xd2, 0xed, 0x3f, 0x0f, 0xa2, 0xf7, 0xa1, 0xdf, 0x53, 0x52, 0xcd,
0x33, 0xbe, 0x26, 0xaf, 0xc5, 0x20, 0x3c, 0xfc, 0x34, 0x6c, 0xb4, 0xa5, 0xa0, 0x4b, 0xf3, 0xd9,
0xed, 0x15, 0x4d, 0x26, 0x36, 0x91, 0xeb, 0x94, 0x2f, 0xaa, 0xb4, 0xb5, 0x67, 0x35, 0x51, 0x8b,
0x0f, 0x2e, 0x44, 0x32, 0xb1, 0x16, 0x04, 0x7a, 0xf8, 0x79, 0x51, 0x2b, 0xeb, 0xbe, 0x1e, 0x6e,
0xc4, 0xc1, 0x1e, 0xee, 0x60, 0xa6, 0x87, 0x9f, 0x2e, 0x2e, 0xf2, 0xac, 0xbe, 0xca, 0x8a, 0x99,
0x4c, 0xbb, 0x5d, 0x5d, 0x23, 0x86, 0x99, 0xf7, 0x7a, 0x27, 0xe7, 0x73, 0x22, 0x83, 0x05, 0x75,
0x02, 0xc2, 0x64, 0xbd, 0x93, 0x33, 0xab, 0x21, 0x23, 0x6d, 0x96, 0xe1, 0x60, 0x35, 0x64, 0xa9,
0x36, 0x52, 0x64, 0x35, 0xd4, 0xa6, 0xcc, 0x6a, 0xc8, 0xae, 0x43, 0x4d, 0xf3, 0x25, 0x39, 0xaf,
0x32, 0xb0, 0x1a, 0x72, 0xca, 0xa7, 0x18, 0x64, 0x35, 0x84, 0xb1, 0x66, 0xa0, 0x32, 0xc4, 0x01,
0x61, 0x13, 0x16, 0xb3, 0x45, 0x0d, 0x06, 0x2a, 0xcb, 0x86, 0x46, 0x90, 0x81, 0x0a, 0x41, 0xa5,
0xb7, 0xdf, 0x8d, 0x22, 0xb1, 0x83, 0xc1, 0x77, 0x99, 0xdc, 0xb9, 0x47, 0x6e, 0x6d, 0x38, 0x5b,
0x4c, 0xef, 0x07, 0x08, 0x93, 0xf0, 0x88, 0xbf, 0xf3, 0xcd, 0xb3, 0xa1, 0x57, 0x83, 0x8b, 0x90,
0x84, 0x07, 0x20, 0xb0, 0xa0, 0x93, 0x2b, 0x7a, 0xe3, 0x2f, 0x68, 0x23, 0x09, 0x17, 0x54, 0x12,
0x66, 0x3b, 0x5b, 0x16, 0xd4, 0xb7, 0x9d, 0xad, 0x8a, 0x11, 0xda, 0xce, 0x86, 0x8c, 0x89, 0x19,
0xdb, 0xf0, 0x73, 0x4a, 0xaf, 0xe7, 0x71, 0x75, 0x0d, 0x62, 0xc6, 0x51, 0x56, 0x0c, 0x12, 0x33,
0x18, 0x6b, 0x62, 0xc6, 0x76, 0xd8, 0xa4, 0xcb, 0xe7, 0x55, 0x0e, 0x62, 0xc6, 0xb1, 0x21, 0x11,
0x24, 0x66, 0x10, 0xd4, 0x8c, 0x4e, 0xb6, 0xb7, 0x09, 0x81, 0x1b, 0x28, 0x8e, 0xfa, 0x84, 0x60,
0x1b, 0x28, 0x1e, 0x0c, 0x86, 0xd0, 0x41, 0x15, 0x97, 0x57, 0xfe, 0x10, 0xe2, 0xa2, 0x70, 0x08,
0x29, 0x04, 0xb6, 0xf7, 0x84, 0xc4, 0x55, 0x72, 0xe5, 0x6f, 0x6f, 0x21, 0x0b, 0xb7, 0xb7, 0x66,
0x60, 0x7b, 0x0b, 0xc1, 0xab, 0x8c, 0x5d, 0x1d, 0x13, 0x16, 0xfb, 0xdb, 0xdb, 0x65, 0xc2, 0xed,
0xdd, 0x62, 0x4d, 0x3e, 0x6e, 0x3b, 0x9c, 0x2c, 0x2e, 0xea, 0xa4, 0xca, 0x2e, 0xc8, 0x30, 0x60,
0x45, 0x43, 0x48, 0x3e, 0x8e, 0xc2, 0xd2, 0xe7, 0x4f, 0x07, 0xd1, 0x5d, 0xd5, 0xec, 0xb4, 0xae,
0xe5, 0xdc, 0xe7, 0xba, 0xff, 0xd8, 0xdf, 0xbe, 0x08, 0x8e, 0xbc, 0x60, 0xe8, 0xa1, 0x66, 0xe5,
0x06, 0xfe, 0x22, 0x9d, 0x17, 0xb5, 0x2e, 0xd4, 0xa7, 0x7d, 0xac, 0x5b, 0x0a, 0x48, 0x6e, 0xd0,
0x4b, 0xd1, 0xa4, 0x65, 0xb2, 0x7d, 0x94, 0xec, 0x30, 0xad, 0x41, 0x5a, 0xa6, 0x9e, 0xb7, 0x45,
0x20, 0x69, 0x99, 0x9f, 0x84, 0xa1, 0x70, 0x50, 0xd1, 0x45, 0x59, 0x77, 0x84, 0x02, 0x80, 0xc2,
0xa1, 0xd0, 0x86, 0xa5, 0xcf, 0xd7, 0xd1, 0xaf, 0xdb, 0xe1, 0x67, 0x3f, 0xec, 0x6d, 0x3c, 0xa6,
0x7c, 0x8f, 0x78, 0xd4, 0x17, 0x37, 0x19, 0x85, 0xf2, 0xcc, 0xf6, 0x08, 0x8b, 0xb3, 0xbc, 0x1e,
0xae, 0xf9, 0x6d, 0x28, 0x39, 0x92, 0x51, 0xf8, 0x38, 0x38, 0xbe, 0xed, 0x2d, 0xca, 0x3c, 0x4b,
0xda, 0xaf, 0x77, 0xa4, 0xae, 0x16, 0x87, 0xc7, 0x37, 0x1b, 0x83, 0xe3, 0x75, 0x93, 0xfa, 0xf1,
0xff, 0x4c, 0x57, 0x25, 0xf1, 0x8f, 0xd7, 0x0e, 0x12, 0x1e, 0xaf, 0x21, 0x0a, 0xeb, 0x33, 0x21,
0xec, 0x28, 0x5e, 0xd1, 0x05, 0x32, 0x5e, 0x6b, 0x71, 0xb8, 0x3e, 0x36, 0x66, 0xd6, 0x06, 0xda,
0xc3, 0x61, 0xc1, 0x48, 0x55, 0xc4, 0xf9, 0x7e, 0x1e, 0xcf, 0xea, 0x21, 0x32, 0xc6, 0xb8, 0x14,
0xb2, 0x36, 0xc0, 0x69, 0xcf, 0x63, 0x3c, 0xac, 0xf7, 0xe3, 0x25, 0xad, 0x32, 0x86, 0x3f, 0x46,
0x83, 0x74, 0x3e, 0x46, 0x07, 0xf5, 0x7a, 0x1b, 0x57, 0xc9, 0x55, 0xb6, 0x24, 0x69, 0xc0, 0x9b,
0x42, 0x7a, 0x78, 0xb3, 0x50, 0x4f, 0xa3, 0x4d, 0xe8, 0xa2, 0x4a, 0x08, 0xda, 0x68, 0x42, 0xdc,
0xd9, 0x68, 0x1a, 0x93, 0x1e, 0xfe, 0x7c, 0x10, 0xfd, 0x86, 0x90, 0xda, 0xef, 0x5c, 0xf6, 0xe2,
0xfa, 0xea, 0x82, 0xc6, 0x55, 0x3a, 0xfc, 0xd0, 0x67, 0xc7, 0x8b, 0x6a, 0xd7, 0x4f, 0x6f, 0xa3,
0x02, 0x1f, 0x6b, 0x93, 0x77, 0x9b, 0x1e, 0xe7, 0x7d, 0xac, 0x0e, 0x12, 0x7e, 0xac, 0x10, 0x85,
0x03, 0x08, 0x97, 0x8b, 0x2d, 0xb9, 0x35, 0x54, 0xdf, 0xdd, 0x97, 0x5b, 0xef, 0xe4, 0xe0, 0xf8,
0xd8, 0x08, 0xdd, 0x68, 0xd9, 0xc6, 0x6c, 0xf8, 0x23, 0x66, 0xd4, 0x17, 0x47, 0x3d, 0xeb, 0x5e,
0x11, 0xf6, 0xdc, 0xea, 0x19, 0xa3, 0xbe, 0x38, 0xe2, 0xd9, 0x1a, 0xd6, 0x42, 0x9e, 0x3d, 0x43,
0xdb, 0xa8, 0x2f, 0x0e, 0xb3, 0x2f, 0xc9, 0xa8, 0x79, 0xe1, 0x71, 0xc0, 0x0e, 0x9c, 0x1b, 0x36,
0x7b, 0xb1, 0xd2, 0xe1, 0x5f, 0x0e, 0xa2, 0xef, 0x1a, 0x8f, 0xc7, 0x34, 0xcd, 0x2e, 0x57, 0x02,
0x7a, 0x19, 0xe7, 0x0b, 0x52, 0x0f, 0x9f, 0x62, 0xd6, 0xda, 0xac, 0x2e, 0xc1, 0xb3, 0x5b, 0xe9,
0xc0, 0xbe, 0x33, 0x2e, 0xcb, 0x7c, 0x35, 0x25, 0xf3, 0x32, 0x47, 0xfb, 0x8e, 0x83, 0x84, 0xfb,
0x0e, 0x44, 0x61, 0x56, 0x3e, 0xa5, 0x4d, 0xce, 0xef, 0xcd, 0xca, 0xb9, 0x28, 0x9c, 0x95, 0x2b,
0x04, 0xe6, 0x4a, 0x53, 0xba, 0x4b, 0xf3, 0x9c, 0x24, 0xac, 0x7d, 0x6e, 0x43, 0x6b, 0x1a, 0x22,
0x9c, 0x2b, 0x01, 0xd2, 0xec, 0xca, 0xa9, 0x35, 0x64, 0x5c, 0x91, 0xe7, 0xab, 0xa3, 0xac, 0xb8,
0x1e, 0xfa, 0xd3, 0x02, 0x03, 0x20, 0xbb, 0x72, 0x5e, 0x10, 0xae, 0x55, 0xcf, 0x8b, 0x94, 0xfa,
0xd7, 0xaa, 0x8d, 0x24, 0xbc, 0x56, 0x95, 0x04, 0x34, 0x79, 0x46, 0x30, 0x93, 0x8d, 0x24, 0x6c,
0x52, 0x12, 0xbe, 0xa1, 0x50, 0xbe, 0xbb, 0x41, 0x87, 0x42, 0xf0, 0xb6, 0x66, 0xbd, 0x93, 0x83,
0x11, 0xaa, 0x16, 0xad, 0xfb, 0x84, 0x25, 0x57, 0xfe, 0x08, 0x75, 0x90, 0x70, 0x84, 0x42, 0x14,
0x56, 0x69, 0x4a, 0xf5, 0xa2, 0x7b, 0xcd, 0x1f, 0x1f, 0xad, 0x05, 0xf7, 0x7a, 0x27, 0x07, 0x97,
0x91, 0x87, 0x73, 0xfe, 0xcc, 0xbc, 0x41, 0x2e, 0x64, 0xe1, 0x65, 0xa4, 0x66, 0x60, 0xe9, 0x85,
0x80, 0xef, 0x65, 0xad, 0xe1, 0x8a, 0xce, 0x6e, 0xd6, 0x7a, 0x27, 0x27, 0x9d, 0xfc, 0xa3, 0x5e,
0xc6, 0x09, 0xe9, 0x09, 0x6d, 0xfa, 0xc8, 0xcb, 0x38, 0xcf, 0xd2, 0x98, 0x91, 0x29, 0xbd, 0x26,
0x85, 0x7f, 0xc5, 0x24, 0x4b, 0x2b, 0xf8, 0x91, 0xa3, 0x10, 0x5e, 0x31, 0x85, 0x15, 0x61, 0x9c,
0x08, 0xfa, 0xbc, 0x26, 0xbb, 0x71, 0x8d, 0x8c, 0x64, 0x0e, 0x12, 0x8e, 0x13, 0x88, 0xc2, 0x7c,
0x55, 0xc8, 0x5f, 0xbc, 0x2e, 0x49, 0x95, 0x91, 0x22, 0x21, 0xfe, 0x7c, 0x15, 0x52, 0xe1, 0x7c,
0xd5, 0x43, 0xc3, 0xb5, 0xda, 0x5e, 0xcc, 0xc8, 0xf3, 0xd5, 0x34, 0x9b, 0x93, 0x9a, 0xc5, 0xf3,
0xd2, 0xbf, 0x56, 0x03, 0x50, 0x78, 0xad, 0xd6, 0x86, 0x5b, 0x5b, 0x43, 0x7a, 0x40, 0x6c, 0x1f,
0xf7, 0x82, 0x44, 0xe0, 0xb8, 0x17, 0x82, 0xc2, 0x07, 0x6b, 0x00, 0xef, 0x4b, 0x82, 0x96, 0x95,
0xe0, 0x4b, 0x02, 0x9c, 0x6e, 0x6d, 0xb8, 0x69, 0x66, 0xd2, 0x74, 0xcd, 0x8e, 0xa2, 0x4f, 0xec,
0x2e, 0xba, 0xd9, 0x8b, 0xf5, 0xef, 0xf0, 0x9d, 0x91, 0x3c, 0xe6, 0xd3, 0x56, 0x60, 0x1b, 0x4d,
0x31, 0x7d, 0x76, 0xf8, 0x2c, 0x56, 0x3a, 0xfc, 0xd3, 0x41, 0xf4, 0x9e, 0xcf, 0xe3, 0x17, 0x25,
0xf7, 0xfb, 0xa4, 0xdb, 0x96, 0x20, 0x91, 0xf3, 0x6c, 0x61, 0x0d, 0x73, 0x24, 0x43, 0x89, 0xcc,
0x71, 0x37, 0x59, 0x00, 0x37, 0x69, 0xd3, 0xe5, 0x87, 0x1c, 0x72, 0x24, 0x23, 0xc4, 0x9b, 0xf5,
0x90, 0x5b, 0xae, 0x1a, 0xac, 0x87, 0xb4, 0x0d, 0x29, 0x46, 0xd6, 0x43, 0x1e, 0xcc, 0xf4, 0x4e,
0xbb, 0x7a, 0xaf, 0x32, 0x76, 0xc5, 0xf3, 0x2d, 0xd0, 0x3b, 0x9d, 0xb2, 0x6a, 0x08, 0xe9, 0x9d,
0x28, 0x0c, 0x33, 0x12, 0x05, 0x36, 0x7d, 0xd3, 0x37, 0x96, 0x6b, 0x43, 0x76, 0xcf, 0xdc, 0xe8,
0x06, 0x61, 0xbc, 0x2a, 0xb1, 0x5c, 0xfa, 0x3c, 0x0e, 0x59, 0x00, 0xcb, 0x9f, 0xcd, 0x5e, 0xac,
0x74, 0xf8, 0xc7, 0xd1, 0x77, 0x5a, 0x15, 0xdb, 0x27, 0x31, 0x5b, 0x54, 0x24, 0x1d, 0xee, 0x74,
0x94, 0x5b, 0x81, 0xda, 0xf5, 0x93, 0xfe, 0x0a, 0xad, 0x1c, 0x5d, 0x71, 0x22, 0xac, 0x74, 0x19,
0x9e, 0x86, 0x4c, 0xba, 0x6c, 0x30, 0x47, 0xc7, 0x75, 0x5a, 0xcb, 0x6c, 0x3b, 0xba, 0xc6, 0xcb,
0x38, 0xcb, 0xf9, 0xcb, 0xda, 0x0f, 0x43, 0x46, 0x1d, 0x34, 0xb8, 0xcc, 0x46, 0x55, 0x5a, 0x23,
0x33, 0xef, 0xe3, 0xd6, 0xf2, 0x6c, 0x0b, 0x1f, 0x09, 0x3c, 0xab, 0xb3, 0xed, 0x9e, 0xb4, 0x74,
0xcb, 0xd4, 0x94, 0xd7, 0xfc, 0xd9, 0x0e, 0x72, 0x9f, 0x57, 0xa9, 0xea, 0x89, 0xf4, 0xed, 0x9e,
0xb4, 0xf4, 0xfa, 0x47, 0xd1, 0xbb, 0x6d, 0xaf, 0x72, 0x22, 0xda, 0xe9, 0x34, 0x05, 0xe6, 0xa2,
0x27, 0xfd, 0x15, 0xa4, 0xfb, 0x7f, 0xd1, 0xfb, 0xd2, 0xc2, 0x7f, 0x42, 0xe7, 0x73, 0x52, 0xa4,
0x24, 0x55, 0x1a, 0x75, 0xb3, 0x7e, 0xfa, 0x0c, 0xb7, 0xab, 0x15, 0x46, 0xb6, 0x86, 0x2e, 0xd1,
0x6f, 0x7e, 0x03, 0x4d, 0x59, 0xb4, 0xff, 0x1c, 0x44, 0x8f, 0xbc, 0x45, 0x53, 0x81, 0xeb, 0x14,
0xf1, 0x77, 0xfa, 0x38, 0xf2, 0x69, 0xea, 0xa2, 0x8e, 0xff, 0x1f, 0x16, 0x64, 0x91, 0xff, 0x75,
0x10, 0xdd, 0x37, 0x8a, 0x4d, 0x78, 0xef, 0xd2, 0xe2, 0x32, 0xcf, 0x12, 0xc6, 0xdf, 0xc8, 0x4a,
0x15, 0xfc, 0x71, 0x62, 0x1a, 0xdd, 0x8f, 0x33, 0xa0, 0x69, 0x16, 0xaf, 0x9f, 0x67, 0x35, 0xa3,
0xd5, 0x6a, 0x72, 0x45, 0x6f, 0xd4, 0x07, 0x43, 0xee, 0xb8, 0x2c, 0x81, 0x91, 0x45, 0x20, 0x8b,
0x57, 0x3f, 0xd9, 0x72, 0x65, 0x3e, 0x2c, 0xaa, 0x11, 0x57, 0x16, 0xd1, 0xe1, 0xca, 0x25, 0xcd,
0xac, 0xa4, 0x6a, 0x65, 0xbe, 0x82, 0x5a, 0xf7, 0x17, 0xb5, 0xfd, 0x25, 0xd4, 0x46, 0x37, 0x68,
0x72, 0x53, 0x29, 0xde, 0xcb, 0x2e, 0x2f, 0x75, 0x9d, 0xfc, 0x25, 0xb5, 0x11, 0x24, 0x37, 0x45,
0x50, 0xb3, 0xbc, 0xda, 0xcf, 0x72, 0xc2, 0xdf, 0xdd, 0x7c, 0x71, 0x79, 0x99, 0xd3, 0x38, 0x05,
0xcb, 0xab, 0x46, 0x3c, 0xb2, 0xe5, 0xc8, 0xf2, 0xca, 0xc7, 0x99, 0x53, 0x21, 0x8d, 0xb4, 0x89,
0xee, 0x22, 0xc9, 0x72, 0x78, 0xde, 0x98, 0x6b, 0x6a, 0x21, 0x72, 0x2a, 0xa4, 0x05, 0x99, 0x14,
0xa8, 0x11, 0x35, 0x51, 0xa9, 0xca, 0xff, 0xb0, 0xad, 0x68, 0x89, 0x91, 0x14, 0xc8, 0x83, 0x99,
0x5d, 0x86, 0x46, 0x78, 0x5e, 0x72, 0xe3, 0xf7, 0xda, 0x5a, 0x42, 0x82, 0xec, 0x32, 0xb8, 0x84,
0x59, 0x2d, 0x37, 0x7f, 0xdf, 0xa3, 0x37, 0x05, 0x37, 0x7a, 0xbf, 0xad, 0xa2, 0x64, 0xc8, 0x6a,
0x19, 0x32, 0xd2, 0xf0, 0x8f, 0xa2, 0x9f, 0xe7, 0x86, 0x2b, 0x5a, 0x0e, 0xef, 0x78, 0x14, 0x2a,
0xeb, 0x74, 0xee, 0x5d, 0x54, 0x6e, 0x0e, 0x91, 0xe8, 0xd8, 0x38, 0xaf, 0xe3, 0x19, 0x3c, 0x52,
0x6f, 0x5a, 0x9c, 0x4b, 0x91, 0x43, 0x24, 0x6d, 0xca, 0x8d, 0x8a, 0x13, 0x9a, 0x4a, 0xeb, 0x9e,
0x1a, 0x6a, 0x61, 0x28, 0x2a, 0x6c, 0xc8, 0xa4, 0xad, 0x27, 0xf1, 0x32, 0x9b, 0xe9, 0xd4, 0x42,
0x0c, 0x60, 0x35, 0x48, 0x5b, 0x0d, 0x33, 0xb2, 0x20, 0x24, 0x6d, 0x45, 0x61, 0xe9, 0xf3, 0x1f,
0x06, 0xd1, 0x3d, 0xc3, 0x1c, 0xa8, 0x7d, 0xd9, 0xc3, 0xe2, 0x92, 0x36, 0x49, 0xee, 0x51, 0x56,
0x5c, 0xd7, 0xc3, 0x4f, 0x30, 0x93, 0x7e, 0x5e, 0x17, 0xe5, 0xd3, 0x5b, 0xeb, 0x99, 0xf5, 0x89,
0xda, 0xb4, 0x34, 0x27, 0x17, 0x84, 0x06, 0x58, 0x9f, 0xe8, 0xbd, 0x4d, 0xc8, 0x21, 0xeb, 0x93,
0x10, 0x6f, 0x9a, 0x58, 0x3b, 0xcf, 0x69, 0x01, 0x9b, 0xd8, 0x58, 0x68, 0x84, 0x48, 0x13, 0xb7,
0x20, 0x33, 0x1e, 0x2b, 0x91, 0xd8, 0x5f, 0x1b, 0xe7, 0x39, 0x18, 0x8f, 0xb5, 0xaa, 0x06, 0x90,
0xf1, 0xd8, 0x0b, 0x4a, 0x3f, 0x67, 0xd1, 0xb7, 0x9a, 0x47, 0x7a, 0x5a, 0x91, 0x65, 0x46, 0xe0,
0x21, 0x1b, 0x4b, 0x82, 0xf4, 0x7f, 0x97, 0x30, 0x3d, 0xeb, 0xbc, 0xa8, 0xcb, 0x3c, 0xae, 0xaf,
0xe4, 0xb1, 0x0b, 0xb7, 0xce, 0x4a, 0x08, 0x0f, 0x5e, 0x3c, 0xec, 0xa0, 0xcc, 0xa0, 0xae, 0x64,
0x7a, 0x88, 0x59, 0xf3, 0xab, 0xb6, 0x86, 0x99, 0xf5, 0x4e, 0xce, 0xbc, 0xdb, 0x38, 0x88, 0xf3,
0x9c, 0x54, 0x2b, 0x25, 0x3b, 0x8e, 0x8b, 0xec, 0x92, 0xd4, 0x0c, 0xbc, 0xdb, 0x90, 0xd4, 0x08,
0x62, 0xc8, 0xbb, 0x8d, 0x00, 0x6e, 0xd6, 0x6d, 0xc0, 0xf3, 0x61, 0x91, 0x92, 0xd7, 0x60, 0xdd,
0x06, 0xed, 0x70, 0x06, 0x59, 0xb7, 0x61, 0xac, 0xd9, 0xe3, 0x7f, 0x9e, 0xd3, 0xe4, 0x5a, 0x4e,
0x01, 0x6e, 0x03, 0x73, 0x09, 0x9c, 0x03, 0xee, 0x87, 0x10, 0x33, 0x09, 0x70, 0xc1, 0x19, 0x29,
0xf3, 0x38, 0x81, 0x27, 0xad, 0x84, 0x8e, 0x94, 0x21, 0x93, 0x00, 0x64, 0x40, 0x71, 0xe5, 0x09,
0x2e, 0x5f, 0x71, 0xc1, 0x01, 0xae, 0xfb, 0x21, 0xc4, 0x4c, 0x83, 0x5c, 0x30, 0x29, 0xf3, 0x8c,
0x81, 0x6e, 0x20, 0x34, 0xb8, 0x04, 0xe9, 0x06, 0x2e, 0x01, 0x4c, 0x1e, 0x93, 0x6a, 0x46, 0xbc,
0x26, 0xb9, 0x24, 0x68, 0x52, 0x11, 0xe6, 0x58, 0xb9, 0xa8, 0x3b, 0x2d, 0x57, 0xe0, 0x58, 0xb9,
0xac, 0x16, 0x2d, 0x57, 0xc8, 0xb1, 0x72, 0x07, 0x00, 0x45, 0x3c, 0x8d, 0x6b, 0xe6, 0x2f, 0x22,
0x97, 0x04, 0x8b, 0xa8, 0x08, 0x33, 0x47, 0x8b, 0x22, 0x2e, 0x18, 0x98, 0xa3, 0x65, 0x01, 0xac,
0xb3, 0x06, 0x77, 0x51, 0xb9, 0x19, 0x49, 0x44, 0xab, 0x10, 0xb6, 0x9f, 0x91, 0x3c, 0xad, 0xc1,
0x48, 0x22, 0x9f, 0xbb, 0x92, 0x22, 0x23, 0x49, 0x9b, 0x02, 0xa1, 0x24, 0xdf, 0x84, 0xf8, 0x6a,
0x07, 0x5e, 0x82, 0xdc, 0x0f, 0x21, 0x66, 0x7c, 0x52, 0x85, 0xde, 0x8d, 0xab, 0x2a, 0x6b, 0x26,
0xff, 0x35, 0x7f, 0x81, 0x94, 0x1c, 0x19, 0x9f, 0x7c, 0x1c, 0xe8, 0x5e, 0x6a, 0xe0, 0xf6, 0x15,
0x0c, 0x0e, 0xdd, 0x1f, 0x04, 0x19, 0x93, 0x71, 0x72, 0x89, 0xf5, 0xb2, 0xdc, 0xf7, 0x34, 0x3d,
0xef, 0xca, 0xd7, 0xba, 0x30, 0xeb, 0x9b, 0x33, 0xed, 0xe2, 0x98, 0x2e, 0xc9, 0x94, 0xbe, 0x78,
0x9d, 0xd5, 0xcd, 0x72, 0x4b, 0xce, 0xdc, 0xcf, 0x10, 0x4b, 0x3e, 0x18, 0xf9, 0xe6, 0xac, 0x53,
0xc9, 0x24, 0x10, 0xa0, 0x2c, 0x27, 0xe4, 0xc6, 0x9b, 0x40, 0x40, 0x8b, 0x9a, 0x43, 0x12, 0x88,
0x10, 0x6f, 0x76, 0xcc, 0xb4, 0x73, 0x79, 0xd1, 0xc0, 0x94, 0xaa, 0x5c, 0x0e, 0xb3, 0x06, 0x41,
0x64, 0xd3, 0x22, 0xa8, 0x60, 0xd6, 0x97, 0xda, 0xbf, 0xe9, 0x62, 0x1b, 0x88, 0x9d, 0x76, 0x37,
0x7b, 0xd4, 0x83, 0xf4, 0xb8, 0x32, 0x27, 0x3e, 0x30, 0x57, 0xed, 0x03, 0x1f, 0x8f, 0x7a, 0x90,
0xd6, 0xee, 0x9b, 0x5d, 0xad, 0xe7, 0x71, 0x72, 0x3d, 0xab, 0xe8, 0xa2, 0x48, 0x77, 0x69, 0x4e,
0x2b, 0xb0, 0xfb, 0xe6, 0x94, 0x1a, 0xa0, 0xc8, 0xee, 0x5b, 0x87, 0x8a, 0xc9, 0xe0, 0xec, 0x52,
0x8c, 0xf3, 0x6c, 0x06, 0x57, 0xd4, 0x8e, 0x21, 0x0e, 0x20, 0x19, 0x9c, 0x17, 0xf4, 0x04, 0x91,
0x58, 0x71, 0xb3, 0x2c, 0x89, 0x73, 0xe1, 0x6f, 0x07, 0x37, 0xe3, 0x80, 0x9d, 0x41, 0xe4, 0x51,
0xf0, 0xd4, 0x73, 0xba, 0xa8, 0x8a, 0xc3, 0x82, 0x51, 0xb4, 0x9e, 0x0a, 0xe8, 0xac, 0xa7, 0x05,
0x82, 0x61, 0x75, 0x4a, 0x5e, 0x37, 0xa5, 0x69, 0xfe, 0xf1, 0x0d, 0xab, 0xcd, 0xdf, 0x47, 0x52,
0x1e, 0x1a, 0x56, 0x01, 0x07, 0x2a, 0x23, 0x9d, 0x88, 0x80, 0x09, 0x68, 0xbb, 0x61, 0xb2, 0xd1,
0x0d, 0xfa, 0xfd, 0x4c, 0xd8, 0x2a, 0x27, 0x21, 0x3f, 0x1c, 0xe8, 0xe3, 0x47, 0x81, 0x66, 0xbb,
0xc5, 0xa9, 0xcf, 0x15, 0x49, 0xae, 0x5b, 0x07, 0xd8, 0xdc, 0x82, 0x0a, 0x04, 0xd9, 0x6e, 0x41,
0x50, 0x7f, 0x13, 0x1d, 0x26, 0xb4, 0x08, 0x35, 0x51, 0x23, 0xef, 0xd3, 0x44, 0x92, 0x33, 0x8b,
0x5f, 0x2d, 0x95, 0x91, 0x29, 0x9a, 0x69, 0x13, 0xb1, 0x60, 0x43, 0xc8, 0xe2, 0x17, 0x85, 0x4d,
0x4e, 0x0e, 0x7d, 0x1e, 0xb7, 0x4f, 0xf7, 0xb7, 0xac, 0x1c, 0xe3, 0xa7, 0xfb, 0x31, 0x16, 0xaf,
0xa4, 0x88, 0x91, 0x0e, 0x2b, 0x6e, 0x9c, 0x6c, 0xf5, 0x83, 0xcd, 0x92, 0xc7, 0xf1, 0xb9, 0x9b,
0x93, 0xb8, 0x12, 0x5e, 0xb7, 0x03, 0x86, 0x0c, 0x86, 0x2c, 0x79, 0x02, 0x38, 0x18, 0xc2, 0x1c,
0xcf, 0xbb, 0xb4, 0x60, 0xa4, 0x60, 0xbe, 0x21, 0xcc, 0x35, 0x26, 0xc1, 0xd0, 0x10, 0x86, 0x29,
0x80, 0xb8, 0xe5, 0xfb, 0x41, 0x84, 0x9d, 0xc4, 0x73, 0x6f, 0xc6, 0x26, 0xf6, 0x7a, 0x84, 0x3c,
0x14, 0xb7, 0x80, 0xb3, 0x5e, 0xe7, 0xda, 0x5e, 0xa6, 0x71, 0x35, 0xd3, 0xbb, 0x1b, 0xe9, 0xf0,
0x09, 0x6e, 0xc7, 0x25, 0x91, 0xd7, 0xb9, 0x61, 0x0d, 0x30, 0xec, 0x1c, 0xce, 0xe3, 0x99, 0xae,
0xa9, 0xa7, 0x06, 0x5c, 0xde, 0xaa, 0xea, 0x46, 0x37, 0x08, 0xfc, 0xbc, 0xcc, 0x52, 0x42, 0x03,
0x7e, 0xb8, 0xbc, 0x8f, 0x1f, 0x08, 0x82, 0xec, 0xad, 0xa9, 0xb7, 0x58, 0xd1, 0x8d, 0x8b, 0x54,
0xae, 0x63, 0x47, 0xc8, 0xe3, 0x01, 0x5c, 0x28, 0x7b, 0x43, 0x78, 0xd0, 0x47, 0xd5, 0x06, 0x6d,
0xa8, 0x8f, 0xea, 0xfd, 0xd7, 0x3e, 0x7d, 0xd4, 0x07, 0x4b, 0x9f, 0x3f, 0x91, 0x7d, 0x74, 0x2f,
0x66, 0x71, 0x93, 0xb7, 0xbf, 0xcc, 0xc8, 0x8d, 0x5c, 0x08, 0x7b, 0xea, 0xab, 0xa8, 0x11, 0xff,
0x38, 0x19, 0xac, 0x8a, 0x77, 0x7a, 0xf3, 0x01, 0xdf, 0x72, 0x85, 0xd0, 0xe9, 0x1b, 0x2c, 0x15,
0x76, 0x7a, 0xf3, 0x01, 0xdf, 0xf2, 0xd6, 0x83, 0x4e, 0xdf, 0xe0, 0xea, 0x83, 0x9d, 0xde, 0xbc,
0xf4, 0xfd, 0x67, 0xaa, 0xe3, 0xda, 0xce, 0x9b, 0x3c, 0x2c, 0x61, 0xd9, 0x92, 0xf8, 0xd2, 0x49,
0xd7, 0x9e, 0x46, 0x43, 0xe9, 0x24, 0xae, 0x62, 0xdd, 0x3b, 0xe6, 0x2b, 0xc5, 0x29, 0xad, 0x33,
0x7e, 0x1c, 0xe3, 0x59, 0x0f, 0xa3, 0x0a, 0x0e, 0x2d, 0x9a, 0x42, 0x4a, 0xe6, 0xc5, 0xb2, 0x83,
0x9a, 0xf3, 0xea, 0x5b, 0x01, 0x7b, 0xed, 0x63, 0xeb, 0xdb, 0x3d, 0x69, 0xf3, 0x8a, 0xd7, 0x61,
0xec, 0x77, 0xcb, 0xa1, 0x56, 0xf5, 0xbe, 0x5e, 0x7e, 0xd2, 0x5f, 0x41, 0xba, 0xff, 0x0b, 0xb5,
0xae, 0x80, 0xfe, 0x65, 0x27, 0x78, 0xda, 0xc7, 0x22, 0xe8, 0x08, 0xcf, 0x6e, 0xa5, 0x23, 0x0b,
0xf2, 0x37, 0x6a, 0x01, 0xad, 0x50, 0xfe, 0xd5, 0x0e, 0xff, 0xda, 0x57, 0xf6, 0x89, 0x50, 0xb3,
0x1a, 0x18, 0xf6, 0x8c, 0x8f, 0x6f, 0xa9, 0x65, 0xdd, 0x42, 0xe7, 0xc0, 0xf2, 0xeb, 0x52, 0xab,
0x3c, 0x21, 0xcb, 0x16, 0x0d, 0x0b, 0xf4, 0xc9, 0x6d, 0xd5, 0xb0, 0xbe, 0x62, 0xc1, 0xfc, 0x1e,
0x96, 0x67, 0x3d, 0x0d, 0x3b, 0x37, 0xb3, 0x7c, 0x74, 0x3b, 0x25, 0x59, 0x96, 0x7f, 0x1f, 0x44,
0x0f, 0x1d, 0xd6, 0xbc, 0x4f, 0x00, 0xbb, 0x1e, 0x3f, 0x08, 0xd8, 0xc7, 0x94, 0x74, 0xe1, 0x7e,
0xeb, 0x9b, 0x29, 0x9b, 0x2b, 0xdb, 0x1c, 0x95, 0xfd, 0x2c, 0x67, 0xa4, 0x6a, 0x5f, 0xd9, 0xe6,
0xda, 0x15, 0xd4, 0x08, 0xbf, 0xb2, 0x2d, 0x80, 0x5b, 0x57, 0xb6, 0x79, 0x3c, 0x7b, 0xaf, 0x6c,
0xf3, 0x5a, 0x0b, 0x5e, 0xd9, 0x16, 0xd6, 0xc0, 0x86, 0x77, 0x55, 0x04, 0xb1, 0x6f, 0xdd, 0xcb,
0xa2, 0xbb, 0x8d, 0xfd, 0xf4, 0x36, 0x2a, 0xc8, 0x04, 0x27, 0x38, 0x7e, 0xa2, 0xb1, 0xc7, 0x33,
0x75, 0x4e, 0x35, 0xee, 0xf4, 0xe6, 0xa5, 0xef, 0x1f, 0xcb, 0xd5, 0x8d, 0x1e, 0xce, 0x69, 0xc5,
0xaf, 0xeb, 0xdb, 0x0c, 0x0d, 0xcf, 0x8d, 0x05, 0xbb, 0xe5, 0xb7, 0xfa, 0xc1, 0x48, 0x75, 0x1b,
0x42, 0x36, 0xfa, 0xa8, 0xcb, 0x10, 0x68, 0xf2, 0x9d, 0xde, 0x3c, 0x32, 0x8d, 0x08, 0xdf, 0xa2,
0xb5, 0x7b, 0x18, 0x73, 0xdb, 0xfa, 0x49, 0x7f, 0x05, 0xe9, 0x7e, 0x29, 0xd3, 0x46, 0xdb, 0x3d,
0x6f, 0xe7, 0xed, 0x2e, 0x53, 0x13, 0xa7, 0x99, 0x47, 0x7d, 0xf1, 0x50, 0x02, 0x61, 0x4f, 0xa1,
0x5d, 0x09, 0x84, 0x77, 0x1a, 0xfd, 0xe8, 0x76, 0x4a, 0xb2, 0x2c, 0x7f, 0x3f, 0x88, 0xee, 0xa2,
0x65, 0x91, 0x71, 0xf0, 0x49, 0x5f, 0xcb, 0x20, 0x1e, 0x3e, 0xbd, 0xb5, 0x9e, 0x2c, 0xd4, 0x3f,
0x0d, 0xa2, 0x7b, 0x81, 0x42, 0x89, 0x00, 0xb9, 0x85, 0x75, 0x37, 0x50, 0x3e, 0xbb, 0xbd, 0x22,
0x36, 0xdd, 0xdb, 0xf8, 0xa4, 0x7d, 0xfd, 0x56, 0xc0, 0xf6, 0x04, 0xbf, 0x7e, 0xab, 0x5b, 0x0b,
0x6e, 0xf2, 0xc4, 0x17, 0x6a, 0xd1, 0xe5, 0xdd, 0xe4, 0xe1, 0x67, 0x11, 0x83, 0xd7, 0x88, 0xf8,
0x38, 0x9f, 0x93, 0x17, 0xaf, 0xcb, 0xb8, 0x48, 0x71, 0x27, 0x42, 0xde, 0xed, 0x44, 0x73, 0x70,
0x73, 0xac, 0x91, 0x9e, 0x51, 0xb5, 0x90, 0x7a, 0x84, 0xe9, 0x6b, 0x24, 0xb8, 0x39, 0xd6, 0x42,
0x11, 0x6f, 0x32, 0x6b, 0x0c, 0x79, 0x03, 0xc9, 0xe2, 0xe3, 0x3e, 0x28, 0x48, 0xd1, 0xb5, 0x37,
0xbd, 0xe7, 0xbe, 0x15, 0xb2, 0xd2, 0xda, 0x77, 0xdf, 0xee, 0x49, 0x23, 0x6e, 0x27, 0x84, 0x7d,
0x4e, 0xe2, 0x94, 0x54, 0x41, 0xb7, 0x9a, 0xea, 0xe5, 0xd6, 0xa6, 0x7d, 0x6e, 0x77, 0x69, 0xbe,
0x98, 0x17, 0xb2, 0x31, 0x51, 0xb7, 0x36, 0xd5, 0xed, 0x16, 0xd0, 0x70, 0x5b, 0xd0, 0xb8, 0xe5,
0xe9, 0xe5, 0xe3, 0xb0, 0x19, 0x27, 0xab, 0xdc, 0xec, 0xc5, 0xe2, 0xf5, 0x94, 0x61, 0xd4, 0x51,
0x4f, 0x10, 0x49, 0xdb, 0x3d, 0x69, 0xb8, 0x3f, 0x67, 0xb9, 0xd5, 0xf1, 0xb4, 0xd3, 0x61, 0xab,
0x15, 0x52, 0x4f, 0xfa, 0x2b, 0xc0, 0xdd, 0x50, 0x19, 0x55, 0x47, 0x59, 0xcd, 0xf6, 0xb3, 0x3c,
0x1f, 0x6e, 0x06, 0xc2, 0x44, 0x41, 0xc1, 0xdd, 0x50, 0x0f, 0x8c, 0x44, 0xb2, 0xda, 0x3d, 0x2c,
0x86, 0x5d, 0x76, 0x38, 0xd5, 0x2b, 0x92, 0x6d, 0x1a, 0xec, 0x68, 0x59, 0x8f, 0x5a, 0xd7, 0x76,
0x14, 0x7e, 0x70, 0xad, 0x0a, 0xef, 0xf4, 0xe6, 0xc1, 0xeb, 0x76, 0x4e, 0xf1, 0x99, 0xe5, 0x01,
0x66, 0xc2, 0x99, 0x49, 0x1e, 0x76, 0x50, 0x60, 0x57, 0x50, 0x74, 0xa3, 0x57, 0x59, 0x3a, 0x23,
0xcc, 0xfb, 0xa6, 0xc8, 0x06, 0x82, 0x6f, 0x8a, 0x00, 0x08, 0x9a, 0x4e, 0xfc, 0x5d, 0x6f, 0x87,
0x1e, 0xa6, 0xbe, 0xa6, 0x93, 0xca, 0x16, 0x15, 0x6a, 0x3a, 0x2f, 0x0d, 0x46, 0x03, 0xed, 0x56,
0x5e, 0xbc, 0xf0, 0x38, 0x64, 0x06, 0xdc, 0xbe, 0xb0, 0xd9, 0x8b, 0x05, 0x33, 0x8a, 0x71, 0x98,
0xcd, 0x33, 0xe6, 0x9b, 0x51, 0x2c, 0x1b, 0x0d, 0x12, 0x9a, 0x51, 0xda, 0x28, 0x56, 0xbd, 0x26,
0x47, 0x38, 0x4c, 0xc3, 0xd5, 0x13, 0x4c, 0xbf, 0xea, 0x69, 0xb6, 0xf5, 0x62, 0xb3, 0xd0, 0x21,
0xc3, 0xae, 0xe4, 0x62, 0xd9, 0x13, 0xdb, 0xfc, 0x83, 0x5c, 0x08, 0x86, 0x46, 0x1d, 0x4c, 0x01,
0x6e, 0xd8, 0x37, 0x9c, 0x7a, 0xf7, 0x5a, 0x96, 0x24, 0xae, 0xe2, 0x22, 0xf1, 0x2e, 0x4e, 0xb9,
0xc1, 0x16, 0x19, 0x5a, 0x9c, 0xa2, 0x1a, 0xe0, 0xb5, 0xb9, 0xfb, 0x29, 0xad, 0xa7, 0x2b, 0xe8,
0x6f, 0x56, 0xdd, 0x2f, 0x69, 0x1f, 0xf5, 0x20, 0xe1, 0x6b, 0x73, 0x05, 0xe8, 0x8d, 0x6f, 0xe1,
0xf4, 0xc3, 0x80, 0x29, 0x17, 0x0d, 0x2d, 0x84, 0x71, 0x15, 0x10, 0xd4, 0x3a, 0xc1, 0x25, 0xec,
0x47, 0x64, 0xe5, 0x0b, 0x6a, 0x93, 0x9f, 0x72, 0x24, 0x14, 0xd4, 0x6d, 0x14, 0xe4, 0x99, 0xf6,
0x3a, 0x68, 0x2d, 0xa0, 0x6f, 0x2f, 0x7d, 0xd6, 0x3b, 0x39, 0xd0, 0x73, 0xf6, 0xb2, 0xa5, 0xf3,
0x9e, 0xc0, 0x53, 0xd0, 0xbd, 0x6c, 0xe9, 0x7f, 0x4d, 0xb0, 0xd9, 0x8b, 0x85, 0xaf, 0xe4, 0x63,
0x46, 0x5e, 0xab, 0x77, 0xe5, 0x9e, 0xe2, 0x72, 0x79, 0xeb, 0x65, 0xf9, 0x46, 0x37, 0x68, 0x0e,
0xc0, 0x9e, 0x56, 0x34, 0x21, 0x75, 0x2d, 0xef, 0x24, 0x75, 0x4f, 0x18, 0x49, 0xd9, 0x08, 0xdc,
0x48, 0xfa, 0x20, 0x0c, 0x59, 0x17, 0x09, 0x0a, 0x91, 0xb9, 0xdf, 0x68, 0xcd, 0xab, 0xd9, 0xbe,
0xda, 0x68, 0xbd, 0x93, 0x33, 0xdd, 0x4b, 0x4a, 0xed, 0x0b, 0x8d, 0x36, 0xbc, 0xea, 0xbe, 0xbb,
0x8c, 0x1e, 0xf5, 0x20, 0xa5, 0xab, 0xcf, 0xa3, 0x37, 0x8f, 0xe8, 0x6c, 0x42, 0x8a, 0x74, 0xf8,
0x3d, 0xf7, 0x08, 0x2d, 0x9d, 0x8d, 0x9a, 0x3f, 0x6b, 0xa3, 0x77, 0x30, 0xb1, 0x39, 0x04, 0xb8,
0x47, 0x2e, 0x16, 0xb3, 0x09, 0x8b, 0x19, 0x38, 0x04, 0xc8, 0xff, 0x3e, 0x6a, 0x04, 0xc8, 0x21,
0x40, 0x07, 0x00, 0xf6, 0xa6, 0x15, 0x21, 0x5e, 0x7b, 0x8d, 0x20, 0x68, 0x4f, 0x02, 0x26, 0x8b,
0xd0, 0xf6, 0x9a, 0x44, 0x1d, 0x1e, 0xda, 0x33, 0x3a, 0x5c, 0x8a, 0x64, 0x11, 0x6d, 0xca, 0x04,
0xb7, 0xa8, 0x3e, 0xbf, 0x5f, 0x66, 0x31, 0x9f, 0xc7, 0xd5, 0x0a, 0x04, 0xb7, 0xac, 0xa5, 0x05,
0x20, 0xc1, 0xed, 0x05, 0x4d, 0xaf, 0x55, 0x8f, 0x39, 0xb9, 0x3e, 0xa0, 0x15, 0x5d, 0xb0, 0xac,
0x20, 0xf0, 0x8e, 0x11, 0xfd, 0x40, 0x6d, 0x06, 0xe9, 0xb5, 0x18, 0x6b, 0xb2, 0x5c, 0x4e, 0x88,
0xf3, 0x84, 0xfc, 0x9a, 0xf4, 0x9a, 0xd1, 0x0a, 0xbe, 0x4f, 0x14, 0x56, 0x20, 0x84, 0x64, 0xb9,
0x28, 0x0c, 0xda, 0xfe, 0x34, 0x2b, 0x66, 0xde, 0xb6, 0x3f, 0xb5, 0xef, 0xf9, 0xbd, 0x87, 0x03,
0xa6, 0x43, 0x89, 0x87, 0x26, 0x3a, 0x80, 0xfc, 0x6a, 0xd7, 0xfb, 0xd0, 0x6d, 0x02, 0xe9, 0x50,
0x7e, 0x12, 0xb8, 0xfa, 0xa2, 0x24, 0x05, 0x49, 0xd5, 0xa9, 0x39, 0x9f, 0x2b, 0x87, 0x08, 0xba,
0x82, 0xa4, 0x19, 0x8b, 0xb8, 0xfc, 0x6c, 0x51, 0x9c, 0x56, 0xf4, 0x32, 0xcb, 0x49, 0x05, 0xc6,
0x22, 0xa1, 0x6e, 0xc9, 0x91, 0xb1, 0xc8, 0xc7, 0x99, 0xe3, 0x17, 0x5c, 0xea, 0xdc, 0xf5, 0x3f,
0xad, 0xe2, 0x04, 0x1e, 0xbf, 0x10, 0x36, 0xda, 0x18, 0xb2, 0x33, 0x18, 0xc0, 0xad, 0x44, 0x47,
0xb8, 0x2e, 0x56, 0x3c, 0x3e, 0xe4, 0x57, 0xa3, 0xfc, 0xf6, 0xdb, 0x1a, 0x24, 0x3a, 0xd2, 0x9c,
0x8f, 0x44, 0x12, 0x9d, 0xb0, 0x86, 0x99, 0x4a, 0x38, 0x77, 0x22, 0x8f, 0x15, 0x81, 0xa9, 0x44,
0xd8, 0x50, 0x42, 0x64, 0x2a, 0x69, 0x41, 0x60, 0x40, 0x52, 0xdd, 0x60, 0xe6, 0x1d, 0x90, 0xb4,
0x34, 0x38, 0x20, 0xd9, 0x94, 0x19, 0x28, 0x0e, 0x8b, 0x8c, 0x65, 0x71, 0x3e, 0x21, 0xec, 0x34,
0xae, 0xe2, 0x39, 0x61, 0xa4, 0x82, 0x03, 0x85, 0x44, 0x46, 0x0e, 0x83, 0x0c, 0x14, 0x18, 0x2b,
0x1d, 0xfe, 0x76, 0xf4, 0x76, 0x33, 0xef, 0x93, 0x42, 0xfe, 0x4a, 0xd1, 0x0b, 0xfe, 0xf3, 0x66,
0xc3, 0x77, 0xb4, 0x8d, 0x09, 0xab, 0x48, 0x3c, 0x57, 0xb6, 0xdf, 0xd2, 0x7f, 0xe7, 0xe0, 0x93,
0x41, 0x13, 0xcf, 0x27, 0x94, 0x65, 0x97, 0xcd, 0x32, 0x5b, 0x7e, 0x41, 0x04, 0xe2, 0xd9, 0x16,
0x8f, 0x02, 0xb7, 0x8e, 0xf8, 0x38, 0x33, 0x4e, 0xdb, 0xd2, 0x33, 0x52, 0xe6, 0x70, 0x9c, 0x76,
0xb4, 0x39, 0x80, 0x8c, 0xd3, 0x5e, 0xd0, 0x74, 0x4e, 0x5b, 0x3c, 0x25, 0xe1, 0xca, 0x4c, 0x49,
0xbf, 0xca, 0x4c, 0x9d, 0x8f, 0x32, 0xf2, 0xe8, 0xed, 0x63, 0x32, 0xbf, 0x20, 0x55, 0x7d, 0x95,
0x95, 0xd8, 0x0d, 0xbd, 0x86, 0xe8, 0xbc, 0xa1, 0x17, 0x41, 0xcd, 0x4c, 0x60, 0x80, 0xc3, 0xfa,
0x24, 0x9e, 0x13, 0x7e, 0x87, 0x0a, 0x98, 0x09, 0x2c, 0x23, 0x16, 0x84, 0xcc, 0x04, 0x28, 0x6c,
0x7d, 0xdf, 0x65, 0x98, 0x33, 0x32, 0x6b, 0x22, 0xac, 0x3a, 0x8d, 0x57, 0x73, 0x52, 0x30, 0x69,
0x12, 0xec, 0xc9, 0x5b, 0x26, 0xfd, 0x3c, 0xb2, 0x27, 0xdf, 0x47, 0xcf, 0x1a, 0x9a, 0x9c, 0x07,
0x7f, 0x4a, 0x2b, 0x26, 0x7e, 0x83, 0xec, 0xbc, 0xca, 0xc1, 0xd0, 0xe4, 0x3e, 0x54, 0x87, 0x44,
0x86, 0xa6, 0xb0, 0x86, 0xf5, 0x7b, 0x13, 0x4e, 0x19, 0x5e, 0x92, 0x4a, 0xc7, 0xc9, 0x8b, 0x79,
0x9c, 0xe5, 0x32, 0x1a, 0xbe, 0x1f, 0xb0, 0x8d, 0xe8, 0x20, 0xbf, 0x37, 0xd1, 0x57, 0xd7, 0xfa,
0x85, 0x8e, 0x70, 0x09, 0xc1, 0x2b, 0x82, 0x0e, 0xfb, 0xc8, 0x2b, 0x82, 0x6e, 0x2d, 0xb3, 0x72,
0x37, 0x2c, 0xe7, 0x56, 0x9c, 0xd8, 0xa5, 0x29, 0xdc, 0x2f, 0xb4, 0x6c, 0x02, 0x10, 0x59, 0xb9,
0x07, 0x15, 0x4c, 0x6a, 0x60, 0xb0, 0xfd, 0xac, 0x88, 0xf3, 0xec, 0x27, 0x30, 0xad, 0xb7, 0xec,
0x28, 0x02, 0x49, 0x0d, 0xfc, 0xa4, 0xcf, 0xd5, 0x01, 0x61, 0xd3, 0xac, 0x19, 0xfa, 0x37, 0x02,
0xcf, 0x8d, 0x13, 0xdd, 0xae, 0x2c, 0xd2, 0xba, 0x8d, 0x17, 0x3e, 0xd6, 0x71, 0x59, 0x4e, 0x9a,
0x59, 0xf5, 0x8c, 0x24, 0x24, 0x2b, 0xd9, 0xf0, 0xe3, 0xf0, 0xb3, 0x02, 0x38, 0x72, 0xd0, 0xa2,
0x87, 0x9a, 0xf5, 0xfa, 0xbe, 0x19, 0x4b, 0x26, 0xe2, 0xc7, 0x39, 0xcf, 0x6b, 0x52, 0xc9, 0x44,
0xe3, 0x80, 0x30, 0xd0, 0x3b, 0x2d, 0x6e, 0x64, 0x81, 0x4d, 0x45, 0x91, 0xde, 0x19, 0xd6, 0x30,
0x9b, 0x7d, 0x16, 0x27, 0x6f, 0x57, 0xe7, 0xe7, 0x0d, 0xb7, 0x50, 0x63, 0x16, 0x85, 0x6c, 0xf6,
0xe1, 0xb4, 0xc9, 0xd6, 0xda, 0x6e, 0xc7, 0xc5, 0xea, 0x10, 0x1e, 0x99, 0xf0, 0x58, 0xe2, 0x18,
0x92, 0xad, 0x05, 0x70, 0x6b, 0x33, 0xbc, 0xa2, 0x71, 0x9a, 0xc4, 0x35, 0x3b, 0x8d, 0x57, 0x39,
0x8d, 0x53, 0x3e, 0xaf, 0xc3, 0xcd, 0x70, 0xc5, 0x8c, 0x6c, 0x08, 0xdb, 0x0c, 0xc7, 0x60, 0x3b,
0x3b, 0xe3, 0xbf, 0x39, 0x2a, 0xcf, 0x72, 0xc2, 0xec, 0x8c, 0x97, 0x17, 0x9e, 0xe3, 0x7c, 0x10,
0x86, 0xcc, 0x37, 0x68, 0x42, 0xc4, 0xd3, 0x90, 0x7b, 0x3e, 0x1d, 0x27, 0x01, 0x79, 0x3f, 0x40,
0x98, 0x1b, 0x48, 0xc4, 0xdf, 0xd5, 0xcf, 0x4c, 0x31, 0x79, 0x67, 0xf9, 0x96, 0x4f, 0xd7, 0x86,
0x46, 0xf6, 0x45, 0x16, 0xdb, 0x3d, 0x69, 0x93, 0x66, 0xee, 0x5e, 0xc5, 0x6c, 0x9c, 0xa6, 0xc7,
0xa4, 0xf6, 0x7c, 0x50, 0xde, 0x08, 0x47, 0x46, 0x8a, 0xa4, 0x99, 0x6d, 0xca, 0x04, 0x7a, 0x23,
0x7b, 0x91, 0x66, 0x4c, 0xca, 0xd4, 0x09, 0xe9, 0xad, 0xb6, 0x81, 0x36, 0x85, 0xd4, 0x0a, 0xa7,
0xcd, 0x58, 0xde, 0x30, 0x53, 0x3a, 0x9b, 0xe5, 0x44, 0x42, 0x67, 0x24, 0x16, 0x57, 0x36, 0xee,
0xb4, 0x6d, 0x79, 0x41, 0x64, 0x2c, 0x0f, 0x2a, 0x98, 0x34, 0xb2, 0xc1, 0xc4, 0x2b, 0x29, 0xf5,
0x60, 0xd7, 0xdb, 0x66, 0x1c, 0x00, 0x49, 0x23, 0xbd, 0xa0, 0xf9, 0xee, 0xad, 0x11, 0x1f, 0x10,
0xf5, 0x24, 0xe0, 0x65, 0x53, 0x5c, 0xd9, 0x12, 0x23, 0xdf, 0xbd, 0x79, 0x30, 0xb3, 0x4e, 0x00,
0x1e, 0x9e, 0xaf, 0x0e, 0x53, 0xb8, 0x4e, 0x80, 0xfa, 0x9c, 0x41, 0xd6, 0x09, 0x18, 0xeb, 0x36,
0x9d, 0xde, 0xf7, 0x3a, 0x8a, 0x6b, 0x53, 0x39, 0x4f, 0xd3, 0x79, 0xc1, 0x50, 0xd3, 0x61, 0x0a,
0xee, 0x23, 0xb5, 0xb7, 0xd6, 0x3c, 0x8f, 0xd4, 0xb7, 0xaf, 0xb6, 0xd6, 0x85, 0x99, 0x71, 0x49,
0xaf, 0x27, 0xf9, 0x91, 0x25, 0xff, 0x6f, 0x35, 0x08, 0x21, 0x32, 0x2e, 0xb5, 0x20, 0x61, 0xfb,
0xf9, 0xfb, 0xff, 0xf5, 0xd5, 0x9d, 0xc1, 0xcf, 0xbe, 0xba, 0x33, 0xf8, 0x9f, 0xaf, 0xee, 0x0c,
0x7e, 0xfa, 0xf5, 0x9d, 0x37, 0x7e, 0xf6, 0xf5, 0x9d, 0x37, 0xfe, 0xfb, 0xeb, 0x3b, 0x6f, 0x7c,
0xf9, 0xa6, 0xfc, 0x2d, 0xea, 0x8b, 0x9f, 0xe3, 0xbf, 0x28, 0xfd, 0xec, 0xff, 0x02, 0x00, 0x00,
0xff, 0xff, 0xc9, 0x60, 0xbd, 0x6d, 0xaf, 0x7a, 0x00, 0x00,
// 5482 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x9d, 0x5f, 0x6f, 0x1d, 0x49,
0x56, 0xc0, 0xe7, 0xbe, 0x30, 0xd0, 0xcb, 0x0e, 0x70, 0x07, 0x86, 0xd9, 0x61, 0x37, 0xc9, 0x64,
0x12, 0x3b, 0x89, 0xe3, 0xeb, 0x4c, 0x32, 0xff, 0xd8, 0x45, 0x82, 0x1b, 0x3b, 0xf1, 0x78, 0xd7,
0xf6, 0x18, 0x5f, 0x3b, 0x91, 0x46, 0x42, 0xa2, 0xdd, 0x5d, 0xbe, 0x6e, 0xdc, 0xb7, 0xab, 0xb7,
0xbb, 0xae, 0x93, 0xbb, 0x08, 0x04, 0x02, 0x81, 0x40, 0x20, 0x56, 0xfc, 0x13, 0x3c, 0x21, 0xf1,
0x09, 0xf8, 0x18, 0x3c, 0xee, 0x03, 0x0f, 0x3c, 0xa2, 0x99, 0x6f, 0xc0, 0x27, 0x40, 0x5d, 0x5d,
0x7f, 0x4f, 0x9f, 0x53, 0xdd, 0x1e, 0x9e, 0x12, 0xf9, 0xfc, 0xce, 0x39, 0xf5, 0xe7, 0x54, 0xd5,
0xa9, 0xea, 0xea, 0xbe, 0xd1, 0xcd, 0xf2, 0x6c, 0xab, 0xac, 0xb8, 0xe0, 0xf5, 0x56, 0xcd, 0xaa,
0xab, 0x2c, 0x61, 0xfa, 0xdf, 0x89, 0xfc, 0xf3, 0xf8, 0xcd, 0xb8, 0x58, 0x89, 0x55, 0xc9, 0xde,
0x7b, 0xd7, 0x92, 0x09, 0x5f, 0x2c, 0xe2, 0x22, 0xad, 0x5b, 0xe4, 0xbd, 0x77, 0xac, 0x84, 0x5d,
0xb1, 0x42, 0xa8, 0xbf, 0x3f, 0xfe, 0xaf, 0xff, 0x1d, 0x45, 0x6f, 0x6d, 0xe7, 0x19, 0x2b, 0xc4,
0xb6, 0xd2, 0x18, 0x7f, 0x19, 0x7d, 0x7b, 0x5a, 0x96, 0xbb, 0x4c, 0xbc, 0x60, 0x55, 0x9d, 0xf1,
0x62, 0xfc, 0xc1, 0x44, 0x39, 0x98, 0x1c, 0x97, 0xc9, 0x64, 0x5a, 0x96, 0x13, 0x2b, 0x9c, 0x1c,
0xb3, 0x1f, 0x2f, 0x59, 0x2d, 0xde, 0xbb, 0x13, 0x86, 0xea, 0x92, 0x17, 0x35, 0x1b, 0x9f, 0x47,
0xbf, 0x32, 0x2d, 0xcb, 0x19, 0x13, 0x3b, 0xac, 0xa9, 0xc0, 0x4c, 0xc4, 0x82, 0x8d, 0xd7, 0x3b,
0xaa, 0x3e, 0x60, 0x7c, 0xdc, 0xeb, 0x07, 0x95, 0x9f, 0x93, 0xe8, 0x5b, 0x8d, 0x9f, 0x8b, 0xa5,
0x48, 0xf9, 0xab, 0x62, 0xfc, 0x7e, 0x57, 0x51, 0x89, 0x8c, 0xed, 0xdb, 0x21, 0x44, 0x59, 0x7d,
0x19, 0xfd, 0xe2, 0xcb, 0x38, 0xcf, 0x99, 0xd8, 0xae, 0x58, 0x53, 0x70, 0x5f, 0xa7, 0x15, 0x4d,
0x5a, 0x99, 0xb1, 0xfb, 0x41, 0x90, 0x51, 0x86, 0xbf, 0x8c, 0xbe, 0xdd, 0x4a, 0x8e, 0x59, 0xc2,
0xaf, 0x58, 0x35, 0x46, 0xb5, 0x94, 0x90, 0x68, 0xf2, 0x0e, 0x04, 0x6d, 0x6f, 0xf3, 0xe2, 0x8a,
0x55, 0x02, 0xb7, 0xad, 0x84, 0x61, 0xdb, 0x16, 0x52, 0xb6, 0xff, 0x6a, 0x14, 0x7d, 0x77, 0x9a,
0x24, 0x7c, 0x59, 0x88, 0x7d, 0x9e, 0xc4, 0xf9, 0x7e, 0x56, 0x5c, 0x1e, 0xb2, 0x57, 0xdb, 0x17,
0x0d, 0x5f, 0xcc, 0xd9, 0xf8, 0x89, 0xdf, 0xaa, 0x2d, 0x3a, 0x31, 0xec, 0xc4, 0x85, 0x8d, 0xef,
0x8f, 0xae, 0xa7, 0xa4, 0xca, 0xf2, 0x77, 0xa3, 0xe8, 0x06, 0x2c, 0xcb, 0x8c, 0xe7, 0x57, 0xcc,
0x96, 0xe6, 0xe3, 0x1e, 0xc3, 0x3e, 0x6e, 0xca, 0xf3, 0xc9, 0x75, 0xd5, 0x54, 0x89, 0xf2, 0xe8,
0x6d, 0x37, 0x5c, 0x66, 0xac, 0x96, 0xc3, 0xe9, 0x3e, 0x1d, 0x11, 0x0a, 0x31, 0x9e, 0x1f, 0x0c,
0x41, 0x95, 0xb7, 0x2c, 0x1a, 0x2b, 0x6f, 0x39, 0xaf, 0x8d, 0xb3, 0x7b, 0xa8, 0x05, 0x87, 0x30,
0xbe, 0xee, 0x0f, 0x20, 0x95, 0xab, 0xdf, 0x8f, 0x7e, 0xe9, 0x25, 0xaf, 0x2e, 0xeb, 0x32, 0x4e,
0x98, 0x1a, 0x0a, 0x77, 0x7d, 0x6d, 0x2d, 0x85, 0xa3, 0x61, 0xad, 0x0f, 0x73, 0x82, 0x56, 0x0b,
0xbf, 0x28, 0x19, 0x9c, 0x83, 0xac, 0x62, 0x23, 0xa4, 0x82, 0x16, 0x42, 0xca, 0xf6, 0x65, 0x34,
0xb6, 0xb6, 0xcf, 0xfe, 0x80, 0x25, 0x62, 0x9a, 0xa6, 0xb0, 0x57, 0xac, 0xae, 0x24, 0x26, 0xd3,
0x34, 0xa5, 0x7a, 0x05, 0x47, 0x95, 0xb3, 0x57, 0xd1, 0x3b, 0xc0, 0xd9, 0x7e, 0x56, 0x4b, 0x87,
0x9b, 0x61, 0x2b, 0x0a, 0x33, 0x4e, 0x27, 0x43, 0x71, 0xe5, 0xf8, 0x4f, 0x46, 0xd1, 0x77, 0x10,
0xcf, 0xc7, 0x6c, 0xc1, 0xaf, 0xd8, 0xf8, 0x51, 0xbf, 0xb5, 0x96, 0x34, 0xfe, 0x3f, 0xbc, 0x86,
0x06, 0x12, 0x26, 0x33, 0x96, 0xb3, 0x44, 0x90, 0x61, 0xd2, 0x8a, 0x7b, 0xc3, 0xc4, 0x60, 0xce,
0x08, 0xd3, 0xc2, 0x5d, 0x26, 0xb6, 0x97, 0x55, 0xc5, 0x0a, 0x41, 0xf6, 0xa5, 0x45, 0x7a, 0xfb,
0xd2, 0x43, 0x91, 0xfa, 0xec, 0x32, 0x31, 0xcd, 0x73, 0xb2, 0x3e, 0xad, 0xb8, 0xb7, 0x3e, 0x06,
0x53, 0x1e, 0x92, 0xe8, 0x97, 0x9d, 0x16, 0x13, 0x7b, 0xc5, 0x39, 0x1f, 0xd3, 0x6d, 0x21, 0xe5,
0xc6, 0xc7, 0x7a, 0x2f, 0x87, 0x54, 0xe3, 0xd9, 0xeb, 0x92, 0x57, 0x74, 0xb7, 0xb4, 0xe2, 0xde,
0x6a, 0x18, 0x4c, 0x79, 0xf8, 0xbd, 0xe8, 0x2d, 0x35, 0x4b, 0xea, 0xf5, 0xec, 0x0e, 0x3a, 0x85,
0xc2, 0x05, 0xed, 0x6e, 0x0f, 0x65, 0x27, 0x07, 0x25, 0x53, 0x93, 0xcf, 0x07, 0xa8, 0x1e, 0x98,
0x7a, 0xee, 0x84, 0xa1, 0x8e, 0xed, 0x1d, 0x96, 0x33, 0xd2, 0x76, 0x2b, 0xec, 0xb1, 0x6d, 0x20,
0x65, 0xbb, 0x8a, 0x7e, 0xcd, 0x34, 0x4b, 0xb3, 0x8e, 0x4a, 0x79, 0x33, 0x49, 0x6f, 0x10, 0xf5,
0x76, 0x21, 0xe3, 0xeb, 0xe1, 0x30, 0xb8, 0x53, 0x1f, 0x35, 0x02, 0xf1, 0xfa, 0x80, 0xf1, 0x77,
0x27, 0x0c, 0x29, 0xdb, 0x7f, 0x3d, 0x8a, 0xbe, 0xa7, 0x64, 0xcf, 0x8a, 0xf8, 0x2c, 0x67, 0x72,
0x49, 0x3c, 0x64, 0xe2, 0x15, 0xaf, 0x2e, 0x67, 0xab, 0x22, 0x21, 0x96, 0x7f, 0x1c, 0xee, 0x59,
0xfe, 0x49, 0x25, 0x55, 0x98, 0x3f, 0x8c, 0xde, 0xd5, 0x41, 0x71, 0x11, 0x17, 0x73, 0xf6, 0xc3,
0x9a, 0x17, 0xd3, 0x32, 0x9b, 0xa6, 0x69, 0x35, 0x9e, 0xe0, 0x5d, 0x0f, 0x39, 0x53, 0x82, 0xad,
0xc1, 0xbc, 0x93, 0x6e, 0xaa, 0x56, 0x16, 0xbc, 0x84, 0xe9, 0xa6, 0x6e, 0x3e, 0xc1, 0x4b, 0x2a,
0xdd, 0xf4, 0x91, 0x8e, 0xd5, 0x83, 0x66, 0xce, 0xc6, 0xad, 0x1e, 0xb8, 0x93, 0xf4, 0xed, 0x10,
0x62, 0xe7, 0x4c, 0xdd, 0x50, 0xbc, 0x38, 0xcf, 0xe6, 0xa7, 0x65, 0xda, 0x8c, 0xa1, 0xfb, 0x78,
0x9d, 0x1d, 0x84, 0x98, 0x33, 0x09, 0x54, 0x79, 0xfb, 0x5b, 0x9b, 0x95, 0xa9, 0x71, 0xfc, 0xbc,
0xe2, 0x8b, 0x7d, 0x36, 0x8f, 0x93, 0x95, 0x9a, 0x7c, 0x3e, 0x0a, 0x8d, 0x7a, 0x48, 0x9b, 0x42,
0x7c, 0x7c, 0x4d, 0x2d, 0x55, 0x9e, 0x7f, 0x1b, 0x45, 0x77, 0xbc, 0x38, 0x51, 0xc1, 0xd4, 0x96,
0x7e, 0x5a, 0xa4, 0xc7, 0xac, 0x16, 0x71, 0x25, 0xc6, 0xdf, 0x0f, 0xc4, 0x00, 0xa1, 0x63, 0xca,
0xf6, 0x83, 0x6f, 0xa4, 0x6b, 0x7b, 0x7d, 0xd6, 0xcc, 0xaa, 0x6a, 0xfe, 0xf1, 0x7b, 0x5d, 0x4a,
0xe0, 0xec, 0x73, 0x3b, 0x84, 0xd8, 0x5e, 0x97, 0x82, 0xbd, 0xe2, 0x2a, 0x13, 0x6c, 0x97, 0x15,
0xac, 0xea, 0xf6, 0x7a, 0xab, 0xea, 0x23, 0x44, 0xaf, 0x13, 0xa8, 0x9d, 0xe9, 0x3c, 0x6f, 0x66,
0x65, 0xde, 0x08, 0x18, 0xe9, 0xac, 0xcd, 0x0f, 0x87, 0xc1, 0x76, 0x6b, 0xe9, 0xf8, 0x3c, 0x66,
0x57, 0xfc, 0x12, 0x6e, 0x2d, 0x5d, 0x13, 0x2d, 0x40, 0x6c, 0x2d, 0x51, 0xd0, 0x2e, 0x9f, 0x8e,
0x9f, 0x17, 0x19, 0x7b, 0x05, 0x96, 0x4f, 0x57, 0xb9, 0x11, 0x13, 0xcb, 0x27, 0x82, 0x29, 0x0f,
0x87, 0xd1, 0x2f, 0x48, 0xe1, 0x0f, 0x79, 0x56, 0x8c, 0x6f, 0x22, 0x4a, 0x8d, 0xc0, 0x58, 0xbd,
0x45, 0x03, 0xa0, 0xc4, 0xcd, 0x5f, 0xb7, 0xe3, 0x22, 0x61, 0x39, 0x5a, 0x62, 0x2b, 0x0e, 0x96,
0xd8, 0xc3, 0x6c, 0xde, 0x22, 0x85, 0xcd, 0xfc, 0x35, 0xbb, 0x88, 0xab, 0xac, 0x98, 0x8f, 0x31,
0x5d, 0x47, 0x4e, 0xe4, 0x2d, 0x18, 0x07, 0x42, 0x58, 0x29, 0x4e, 0xcb, 0xb2, 0x6a, 0xa6, 0x45,
0x2c, 0x84, 0x7d, 0x24, 0x18, 0xc2, 0x1d, 0x14, 0xf7, 0xb6, 0xc3, 0x92, 0x3c, 0x2b, 0x82, 0xde,
0x14, 0x32, 0xc4, 0x9b, 0x45, 0x41, 0xf0, 0xee, 0xb3, 0xf8, 0x8a, 0xe9, 0x9a, 0x61, 0x2d, 0xe3,
0x02, 0xc1, 0xe0, 0x05, 0xa0, 0xdd, 0x24, 0x4a, 0xf1, 0x41, 0x7c, 0xc9, 0x9a, 0x06, 0x66, 0xcd,
0xa2, 0x3a, 0xc6, 0xf4, 0x3d, 0x82, 0xd8, 0x24, 0xe2, 0xa4, 0x72, 0xb5, 0x8c, 0xde, 0x91, 0xf2,
0xa3, 0xb8, 0x12, 0x59, 0x92, 0x95, 0x71, 0xa1, 0x37, 0x1f, 0xd8, 0xb8, 0xee, 0x50, 0xc6, 0xe5,
0xe6, 0x40, 0x5a, 0xb9, 0xfd, 0xe7, 0x51, 0xf4, 0x3e, 0xf4, 0x7b, 0xc4, 0xaa, 0x45, 0x26, 0xf7,
0xb0, 0x75, 0x3b, 0x09, 0x8f, 0x3f, 0x0d, 0x1b, 0xed, 0x28, 0x98, 0xd2, 0x7c, 0x76, 0x7d, 0x45,
0x9b, 0x89, 0xcd, 0x54, 0x5e, 0xff, 0x45, 0x95, 0x76, 0xce, 0x78, 0x66, 0x3a, 0x59, 0x97, 0x42,
0x22, 0x13, 0xeb, 0x40, 0x60, 0x84, 0x9f, 0x16, 0xb5, 0xb6, 0x8e, 0x8d, 0x70, 0x2b, 0x0e, 0x8e,
0x70, 0x0f, 0xb3, 0x23, 0xfc, 0x68, 0x79, 0x96, 0x67, 0xf5, 0x45, 0x56, 0xcc, 0x55, 0xda, 0xed,
0xeb, 0x5a, 0x31, 0xcc, 0xbc, 0xd7, 0x7b, 0x39, 0xcc, 0x89, 0x0a, 0x16, 0xd2, 0x09, 0x08, 0x93,
0xf5, 0x5e, 0xce, 0x6e, 0x4e, 0xac, 0xb4, 0xd9, 0xb6, 0x82, 0xcd, 0x89, 0xa3, 0xda, 0x48, 0x89,
0xcd, 0x49, 0x97, 0x52, 0xe6, 0x79, 0xf4, 0xab, 0x6e, 0x1d, 0x6a, 0x9e, 0x5f, 0xb1, 0xd3, 0x2a,
0x1b, 0x3f, 0xa0, 0xcb, 0xa7, 0x19, 0xe3, 0x6a, 0x63, 0x10, 0x6b, 0x27, 0x2a, 0x4b, 0xec, 0x32,
0x31, 0x13, 0xb1, 0x58, 0xd6, 0x60, 0xa2, 0x72, 0x6c, 0x18, 0x84, 0x98, 0xa8, 0x08, 0x54, 0x79,
0xfb, 0xdd, 0x28, 0x6a, 0x77, 0xfc, 0xf2, 0x54, 0xc6, 0x5f, 0x7b, 0xd4, 0x51, 0x80, 0x77, 0x24,
0xf3, 0x7e, 0x80, 0xb0, 0x09, 0x4f, 0xfb, 0x77, 0x79, 0xd8, 0x34, 0x46, 0x35, 0xa4, 0x88, 0x48,
0x78, 0x00, 0x02, 0x0b, 0x3a, 0xbb, 0xe0, 0xaf, 0xf0, 0x82, 0x36, 0x92, 0x70, 0x41, 0x15, 0x61,
0x8f, 0x7f, 0x55, 0x41, 0xb1, 0xe3, 0x5f, 0x5d, 0x8c, 0xd0, 0xf1, 0x2f, 0x64, 0x6c, 0xcc, 0xb8,
0x86, 0x9f, 0x72, 0x7e, 0xb9, 0x88, 0xab, 0x4b, 0x10, 0x33, 0x9e, 0xb2, 0x66, 0x88, 0x98, 0xa1,
0x58, 0x1b, 0x33, 0xae, 0xc3, 0x26, 0x5d, 0x3e, 0xad, 0x72, 0x10, 0x33, 0x9e, 0x0d, 0x85, 0x10,
0x31, 0x43, 0xa0, 0x76, 0x76, 0x72, 0xbd, 0xcd, 0x18, 0x3c, 0x70, 0xf0, 0xd4, 0x67, 0x8c, 0x3a,
0x70, 0x40, 0x30, 0x18, 0x42, 0xbb, 0x55, 0x5c, 0x5e, 0xe0, 0x21, 0x24, 0x45, 0xe1, 0x10, 0xd2,
0x08, 0xec, 0xef, 0x19, 0x8b, 0xab, 0xe4, 0x02, 0xef, 0xef, 0x56, 0x16, 0xee, 0x6f, 0xc3, 0xc0,
0xfe, 0x6e, 0x05, 0x2f, 0x33, 0x71, 0x71, 0xc0, 0x44, 0x8c, 0xf7, 0xb7, 0xcf, 0x84, 0xfb, 0xbb,
0xc3, 0xda, 0x7c, 0xdc, 0x75, 0x38, 0x5b, 0x9e, 0xd5, 0x49, 0x95, 0x9d, 0xb1, 0x71, 0xc0, 0x8a,
0x81, 0x88, 0x7c, 0x9c, 0x84, 0x95, 0xcf, 0x9f, 0x8e, 0xa2, 0x9b, 0xba, 0xdb, 0x79, 0x5d, 0xab,
0xb5, 0xcf, 0x77, 0xff, 0x31, 0xde, 0xbf, 0x04, 0x4e, 0x1c, 0xc8, 0x0f, 0x50, 0x73, 0x72, 0x03,
0xbc, 0x48, 0xa7, 0x45, 0x6d, 0x0a, 0xf5, 0xe9, 0x10, 0xeb, 0x8e, 0x02, 0x91, 0x1b, 0x0c, 0x52,
0xb4, 0x69, 0x99, 0xea, 0x1f, 0x2d, 0xdb, 0x4b, 0x6b, 0x90, 0x96, 0xe9, 0xf6, 0x76, 0x08, 0x22,
0x2d, 0xc3, 0x49, 0x18, 0x0a, 0xbb, 0x15, 0x5f, 0x96, 0x75, 0x4f, 0x28, 0x00, 0x28, 0x1c, 0x0a,
0x5d, 0x58, 0xf9, 0x7c, 0x1d, 0xfd, 0xba, 0x1b, 0x7e, 0x6e, 0x63, 0x6f, 0xd2, 0x31, 0x85, 0x35,
0xf1, 0x64, 0x28, 0x6e, 0x33, 0x0a, 0xed, 0x59, 0xec, 0x30, 0x11, 0x67, 0x79, 0x3d, 0x5e, 0xc3,
0x6d, 0x68, 0x39, 0x91, 0x51, 0x60, 0x1c, 0x9c, 0xdf, 0x76, 0x96, 0x65, 0x9e, 0x25, 0xdd, 0xc7,
0x21, 0x4a, 0xd7, 0x88, 0xc3, 0xf3, 0x9b, 0x8b, 0xc1, 0xf9, 0xba, 0x49, 0xfd, 0xe4, 0x7f, 0x4e,
0x56, 0x25, 0xc3, 0xe7, 0x6b, 0x0f, 0x09, 0xcf, 0xd7, 0x10, 0x85, 0xf5, 0x99, 0x31, 0xb1, 0x1f,
0xaf, 0xf8, 0x92, 0x98, 0xaf, 0x8d, 0x38, 0x5c, 0x1f, 0x17, 0xb3, 0x7b, 0x03, 0xe3, 0x61, 0xaf,
0x10, 0xac, 0x2a, 0xe2, 0xfc, 0x79, 0x1e, 0xcf, 0xeb, 0x31, 0x31, 0xc7, 0xf8, 0x14, 0xb1, 0x37,
0xa0, 0x69, 0xa4, 0x19, 0xf7, 0xea, 0xe7, 0xf1, 0x15, 0xaf, 0x32, 0x41, 0x37, 0xa3, 0x45, 0x7a,
0x9b, 0xd1, 0x43, 0x51, 0x6f, 0xd3, 0x2a, 0xb9, 0xc8, 0xae, 0x58, 0x1a, 0xf0, 0xa6, 0x91, 0x01,
0xde, 0x1c, 0x14, 0xe9, 0xb4, 0x19, 0x5f, 0x56, 0x09, 0x23, 0x3b, 0xad, 0x15, 0xf7, 0x76, 0x9a,
0xc1, 0x94, 0x87, 0x3f, 0x1f, 0x45, 0xbf, 0xd1, 0x4a, 0xdd, 0x67, 0x14, 0x3b, 0x71, 0x7d, 0x71,
0xc6, 0xe3, 0x2a, 0x1d, 0x7f, 0x88, 0xd9, 0x41, 0x51, 0xe3, 0xfa, 0xf1, 0x75, 0x54, 0x60, 0xb3,
0x36, 0x79, 0xb7, 0x1d, 0x71, 0x68, 0xb3, 0x7a, 0x48, 0xb8, 0x59, 0x21, 0x0a, 0x27, 0x10, 0x29,
0x6f, 0x8f, 0xe4, 0xd6, 0x48, 0x7d, 0xff, 0x5c, 0x6e, 0xbd, 0x97, 0x83, 0xf3, 0x63, 0x23, 0xf4,
0xa3, 0x65, 0x93, 0xb2, 0x81, 0x47, 0xcc, 0x64, 0x28, 0x4e, 0x7a, 0x36, 0xa3, 0x22, 0xec, 0xb9,
0x33, 0x32, 0x26, 0x43, 0x71, 0xc2, 0xb3, 0x33, 0xad, 0x85, 0x3c, 0x23, 0x53, 0xdb, 0x64, 0x28,
0x0e, 0xb3, 0x2f, 0xc5, 0xe8, 0x75, 0xe1, 0x41, 0xc0, 0x0e, 0x5c, 0x1b, 0x36, 0x06, 0xb1, 0xca,
0xe1, 0x5f, 0x8e, 0xa2, 0xef, 0x5a, 0x8f, 0x07, 0x3c, 0xcd, 0xce, 0x57, 0x2d, 0xf4, 0x22, 0xce,
0x97, 0xac, 0x1e, 0x3f, 0xa6, 0xac, 0x75, 0x59, 0x53, 0x82, 0x27, 0xd7, 0xd2, 0x81, 0x63, 0x67,
0x5a, 0x96, 0xf9, 0xea, 0x84, 0x2d, 0xca, 0x9c, 0x1c, 0x3b, 0x1e, 0x12, 0x1e, 0x3b, 0x10, 0x85,
0x59, 0xf9, 0x09, 0x6f, 0x72, 0x7e, 0x34, 0x2b, 0x97, 0xa2, 0x70, 0x56, 0xae, 0x11, 0x98, 0x2b,
0x9d, 0xf0, 0x6d, 0x9e, 0xe7, 0x2c, 0x11, 0xdd, 0x7b, 0x0e, 0x46, 0xd3, 0x12, 0xe1, 0x5c, 0x09,
0x90, 0xf6, 0x54, 0x4e, 0xef, 0x21, 0xe3, 0x8a, 0x3d, 0x5d, 0xed, 0x67, 0xc5, 0xe5, 0x18, 0x4f,
0x0b, 0x2c, 0x40, 0x9c, 0xca, 0xa1, 0x20, 0xdc, 0xab, 0x9e, 0x16, 0x29, 0xc7, 0xf7, 0xaa, 0x8d,
0x24, 0xbc, 0x57, 0x55, 0x04, 0x34, 0x79, 0xcc, 0x28, 0x93, 0x8d, 0x24, 0x6c, 0x52, 0x11, 0xd8,
0x54, 0xa8, 0x9e, 0xdd, 0x90, 0x53, 0x21, 0x78, 0x5a, 0xb3, 0xde, 0xcb, 0xc1, 0x08, 0xd5, 0x9b,
0xd6, 0xe7, 0x4c, 0x24, 0x17, 0x78, 0x84, 0x7a, 0x48, 0x38, 0x42, 0x21, 0x0a, 0xab, 0x74, 0xc2,
0xcd, 0xa6, 0x7b, 0x0d, 0x8f, 0x8f, 0xce, 0x86, 0x7b, 0xbd, 0x97, 0x83, 0xdb, 0xc8, 0xbd, 0x85,
0x6c, 0x33, 0x34, 0xc8, 0x5b, 0x59, 0x78, 0x1b, 0x69, 0x18, 0x58, 0xfa, 0x56, 0x20, 0xcf, 0xb2,
0xd6, 0x68, 0x45, 0xef, 0x34, 0x6b, 0xbd, 0x97, 0x53, 0x4e, 0xfe, 0xd1, 0x6c, 0xe3, 0x5a, 0xe9,
0x21, 0x6f, 0xc6, 0xc8, 0x8b, 0x38, 0xcf, 0xd2, 0x58, 0xb0, 0x13, 0x7e, 0xc9, 0x0a, 0x7c, 0xc7,
0xa4, 0x4a, 0xdb, 0xf2, 0x13, 0x4f, 0x21, 0xbc, 0x63, 0x0a, 0x2b, 0xc2, 0x38, 0x69, 0xe9, 0xd3,
0x9a, 0x6d, 0xc7, 0x35, 0x31, 0x93, 0x79, 0x48, 0x38, 0x4e, 0x20, 0x0a, 0xf3, 0xd5, 0x56, 0xfe,
0xec, 0x75, 0xc9, 0xaa, 0x8c, 0x15, 0x09, 0xc3, 0xf3, 0x55, 0x48, 0x85, 0xf3, 0x55, 0x84, 0x86,
0x7b, 0xb5, 0x9d, 0x58, 0xb0, 0xa7, 0xab, 0x93, 0x6c, 0xc1, 0x6a, 0x11, 0x2f, 0x4a, 0x7c, 0xaf,
0x06, 0xa0, 0xf0, 0x5e, 0xad, 0x0b, 0x77, 0x8e, 0x86, 0xcc, 0x84, 0xd8, 0xbd, 0x1e, 0x05, 0x89,
0xc0, 0xf5, 0x28, 0x02, 0x85, 0x0d, 0x6b, 0x01, 0xf4, 0x21, 0x41, 0xc7, 0x4a, 0xf0, 0x21, 0x01,
0x4d, 0x77, 0x0e, 0xdc, 0x0c, 0x33, 0x6b, 0x86, 0x66, 0x4f, 0xd1, 0x67, 0xee, 0x10, 0xdd, 0x18,
0xc4, 0xe2, 0x27, 0x7c, 0xc7, 0x2c, 0x8f, 0xe5, 0xb2, 0x15, 0x38, 0x46, 0xd3, 0xcc, 0x90, 0x13,
0x3e, 0x87, 0x55, 0x0e, 0xff, 0x74, 0x14, 0xbd, 0x87, 0x79, 0xfc, 0xa2, 0x94, 0x7e, 0x1f, 0xf5,
0xdb, 0x6a, 0x49, 0xe2, 0xfe, 0x57, 0x58, 0xc3, 0x5e, 0xc9, 0xd0, 0x22, 0x7b, 0x3d, 0x4c, 0x15,
0xc0, 0x4f, 0xda, 0x4c, 0xf9, 0x21, 0x47, 0x5c, 0xc9, 0x08, 0xf1, 0x76, 0x3f, 0xe4, 0x97, 0xab,
0x06, 0xfb, 0x21, 0x63, 0x43, 0x89, 0x89, 0xfd, 0x10, 0x82, 0xd9, 0xd1, 0xe9, 0x56, 0xef, 0x65,
0x26, 0x2e, 0x64, 0xbe, 0x05, 0x46, 0xa7, 0x57, 0x56, 0x03, 0x11, 0xa3, 0x93, 0x84, 0x61, 0x46,
0xa2, 0xc1, 0x66, 0x6c, 0x62, 0x73, 0xb9, 0x31, 0xe4, 0x8e, 0xcc, 0x7b, 0xfd, 0x20, 0x8c, 0x57,
0x2d, 0x56, 0x5b, 0x9f, 0x07, 0x21, 0x0b, 0x60, 0xfb, 0xb3, 0x31, 0x88, 0x55, 0x0e, 0xff, 0x38,
0xfa, 0x4e, 0xa7, 0x62, 0xcf, 0x59, 0x2c, 0x96, 0x15, 0x4b, 0xc7, 0x5b, 0x3d, 0xe5, 0xd6, 0xa0,
0x71, 0xfd, 0x68, 0xb8, 0x42, 0x27, 0x47, 0xd7, 0x5c, 0x1b, 0x56, 0xa6, 0x0c, 0x8f, 0x43, 0x26,
0x7d, 0x36, 0x98, 0xa3, 0xd3, 0x3a, 0x9d, 0x6d, 0xb6, 0x1b, 0x5d, 0xd3, 0xab, 0x38, 0xcb, 0xe5,
0xc3, 0xda, 0x0f, 0x43, 0x46, 0x3d, 0x34, 0xb8, 0xcd, 0x26, 0x55, 0x3a, 0x33, 0xb3, 0x1c, 0xe3,
0xce, 0xf6, 0xec, 0x21, 0x3d, 0x13, 0x20, 0xbb, 0xb3, 0xcd, 0x81, 0xb4, 0x72, 0x2b, 0xf4, 0x92,
0xd7, 0xfc, 0xd9, 0x0d, 0x72, 0xcc, 0xab, 0x52, 0x45, 0x22, 0x7d, 0x73, 0x20, 0xad, 0xbc, 0xfe,
0x51, 0xf4, 0x6e, 0xd7, 0xab, 0x5a, 0x88, 0xb6, 0x7a, 0x4d, 0x81, 0xb5, 0xe8, 0xd1, 0x70, 0x05,
0xe5, 0xfe, 0x5f, 0xcc, 0xb9, 0x74, 0xeb, 0x3f, 0xe1, 0x8b, 0x05, 0x2b, 0x52, 0x96, 0x6a, 0x8d,
0xba, 0xd9, 0x3f, 0x7d, 0x46, 0xdb, 0x35, 0x0a, 0x13, 0x57, 0xc3, 0x94, 0xe8, 0x37, 0xbf, 0x81,
0xa6, 0x2a, 0xda, 0x7f, 0x8c, 0xa2, 0xfb, 0x68, 0xd1, 0x74, 0xe0, 0x7a, 0x45, 0xfc, 0x9d, 0x21,
0x8e, 0x30, 0x4d, 0x53, 0xd4, 0xe9, 0xff, 0xc3, 0x82, 0x2a, 0xf2, 0xbf, 0x8e, 0xa2, 0xdb, 0x56,
0xb1, 0x09, 0xef, 0x6d, 0x5e, 0x9c, 0xe7, 0x59, 0x22, 0xe4, 0x13, 0x59, 0xa5, 0x42, 0x37, 0x27,
0xa5, 0xd1, 0xdf, 0x9c, 0x01, 0x4d, 0xbb, 0x79, 0xfd, 0x3c, 0xab, 0x05, 0xaf, 0x56, 0xb3, 0x0b,
0xfe, 0x4a, 0xbf, 0x60, 0xe3, 0xcf, 0xcb, 0x0a, 0x98, 0x38, 0x04, 0xb1, 0x79, 0xc5, 0xc9, 0x8e,
0x2b, 0xfb, 0x22, 0x4e, 0x4d, 0xb8, 0x72, 0x88, 0x1e, 0x57, 0x3e, 0x69, 0x57, 0x25, 0x5d, 0x2b,
0xfb, 0xd6, 0xd0, 0x3a, 0x5e, 0xd4, 0xee, 0x9b, 0x43, 0xf7, 0xfa, 0x41, 0x9b, 0x9b, 0x2a, 0xf1,
0x4e, 0x76, 0x7e, 0x6e, 0xea, 0x84, 0x97, 0xd4, 0x45, 0x88, 0xdc, 0x94, 0x40, 0xed, 0xf6, 0xea,
0x79, 0x96, 0x33, 0xf9, 0xec, 0xe6, 0x8b, 0xf3, 0xf3, 0x9c, 0xc7, 0x29, 0xd8, 0x5e, 0x35, 0xe2,
0x89, 0x2b, 0x27, 0xb6, 0x57, 0x18, 0x67, 0x6f, 0x85, 0x34, 0xd2, 0x26, 0xba, 0x8b, 0x24, 0xcb,
0xe1, 0x7d, 0x63, 0xa9, 0x69, 0x84, 0xc4, 0xad, 0x90, 0x0e, 0x64, 0x53, 0xa0, 0x46, 0xd4, 0x44,
0xa5, 0x2e, 0xff, 0xdd, 0xae, 0xa2, 0x23, 0x26, 0x52, 0x20, 0x04, 0xb3, 0xa7, 0x0c, 0x8d, 0xf0,
0xb4, 0x94, 0xc6, 0x6f, 0x75, 0xb5, 0x5a, 0x09, 0x71, 0xca, 0xe0, 0x13, 0x76, 0xb7, 0xdc, 0xfc,
0x7d, 0x87, 0xbf, 0x2a, 0xa4, 0xd1, 0xdb, 0x5d, 0x15, 0x2d, 0x23, 0x76, 0xcb, 0x90, 0x51, 0x86,
0x7f, 0x14, 0xfd, 0xbc, 0x34, 0x5c, 0xf1, 0x72, 0x7c, 0x03, 0x51, 0xa8, 0x9c, 0xdb, 0xb9, 0x37,
0x49, 0xb9, 0xbd, 0x44, 0x62, 0x62, 0xe3, 0xb4, 0x8e, 0xe7, 0x6c, 0x7c, 0x87, 0xe8, 0x71, 0x29,
0x25, 0x2e, 0x91, 0x74, 0x29, 0x3f, 0x2a, 0x0e, 0x79, 0xaa, 0xac, 0x23, 0x35, 0x34, 0xc2, 0x50,
0x54, 0xb8, 0x90, 0x4d, 0x5b, 0x0f, 0xe3, 0xab, 0x6c, 0x6e, 0x52, 0x8b, 0x76, 0x02, 0xab, 0x41,
0xda, 0x6a, 0x99, 0x89, 0x03, 0x11, 0x69, 0x2b, 0x09, 0x2b, 0x9f, 0xff, 0x30, 0x8a, 0x6e, 0x59,
0x66, 0x57, 0x9f, 0xcb, 0xee, 0x15, 0xe7, 0xbc, 0x49, 0x72, 0xf7, 0xb3, 0xe2, 0xb2, 0x1e, 0x7f,
0x42, 0x99, 0xc4, 0x79, 0x53, 0x94, 0x4f, 0xaf, 0xad, 0x67, 0xf7, 0x27, 0xfa, 0xd0, 0xd2, 0xde,
0x5c, 0x68, 0x35, 0xc0, 0xfe, 0xc4, 0x9c, 0x6d, 0x42, 0x8e, 0xd8, 0x9f, 0x84, 0x78, 0xdb, 0xc5,
0xc6, 0x79, 0xce, 0x0b, 0xd8, 0xc5, 0xd6, 0x42, 0x23, 0x24, 0xba, 0xb8, 0x03, 0xd9, 0xf9, 0x58,
0x8b, 0xda, 0xf3, 0xb5, 0x69, 0x9e, 0x83, 0xf9, 0xd8, 0xa8, 0x1a, 0x80, 0x98, 0x8f, 0x51, 0x50,
0xf9, 0x39, 0x8e, 0xbe, 0xd5, 0x34, 0xe9, 0x51, 0xc5, 0xae, 0x32, 0x06, 0x2f, 0xd9, 0x38, 0x12,
0x62, 0xfc, 0xfb, 0x84, 0x1d, 0x59, 0xa7, 0x45, 0x5d, 0xe6, 0x71, 0x7d, 0xa1, 0xae, 0x5d, 0xf8,
0x75, 0xd6, 0x42, 0x78, 0xf1, 0xe2, 0x6e, 0x0f, 0x65, 0x27, 0x75, 0x2d, 0x33, 0x53, 0xcc, 0x1a,
0xae, 0xda, 0x99, 0x66, 0xd6, 0x7b, 0x39, 0xfb, 0x6c, 0x63, 0x37, 0xce, 0x73, 0x56, 0xad, 0xb4,
0xec, 0x20, 0x2e, 0xb2, 0x73, 0x56, 0x0b, 0xf0, 0x6c, 0x43, 0x51, 0x13, 0x88, 0x11, 0xcf, 0x36,
0x02, 0xb8, 0xdd, 0xb7, 0x01, 0xcf, 0x7b, 0x45, 0xca, 0x5e, 0x83, 0x7d, 0x1b, 0xb4, 0x23, 0x19,
0x62, 0xdf, 0x46, 0xb1, 0xf6, 0x8c, 0xff, 0x69, 0xce, 0x93, 0x4b, 0xb5, 0x04, 0xf8, 0x1d, 0x2c,
0x25, 0x70, 0x0d, 0xb8, 0x1d, 0x42, 0xec, 0x22, 0x20, 0x05, 0xc7, 0xac, 0xcc, 0xe3, 0x04, 0xde,
0xb4, 0x6a, 0x75, 0x94, 0x8c, 0x58, 0x04, 0x20, 0x03, 0x8a, 0xab, 0x6e, 0x70, 0x61, 0xc5, 0x05,
0x17, 0xb8, 0x6e, 0x87, 0x10, 0xbb, 0x0c, 0x4a, 0xc1, 0xac, 0xcc, 0x33, 0x01, 0x86, 0x41, 0xab,
0x21, 0x25, 0xc4, 0x30, 0xf0, 0x09, 0x60, 0xf2, 0x80, 0x55, 0x73, 0x86, 0x9a, 0x94, 0x92, 0xa0,
0x49, 0x4d, 0xd8, 0x6b, 0xe5, 0x6d, 0xdd, 0x79, 0xb9, 0x02, 0xd7, 0xca, 0x55, 0xb5, 0x78, 0xb9,
0x22, 0xae, 0x95, 0x7b, 0x00, 0x28, 0xe2, 0x51, 0x5c, 0x0b, 0xbc, 0x88, 0x52, 0x12, 0x2c, 0xa2,
0x26, 0xec, 0x1a, 0xdd, 0x16, 0x71, 0x29, 0xc0, 0x1a, 0xad, 0x0a, 0xe0, 0xdc, 0x35, 0xb8, 0x49,
0xca, 0xed, 0x4c, 0xd2, 0xf6, 0x0a, 0x13, 0xcf, 0x33, 0x96, 0xa7, 0x35, 0x98, 0x49, 0x54, 0xbb,
0x6b, 0x29, 0x31, 0x93, 0x74, 0x29, 0x10, 0x4a, 0xea, 0x49, 0x08, 0x56, 0x3b, 0xf0, 0x10, 0xe4,
0x76, 0x08, 0xb1, 0xf3, 0x93, 0x2e, 0xf4, 0x76, 0x5c, 0x55, 0x59, 0xb3, 0xf8, 0xaf, 0xe1, 0x05,
0xd2, 0x72, 0x62, 0x7e, 0xc2, 0x38, 0x30, 0xbc, 0xf4, 0xc4, 0x8d, 0x15, 0x0c, 0x4e, 0xdd, 0x1f,
0x04, 0x19, 0x9b, 0x71, 0x4a, 0x89, 0xf3, 0xb0, 0x1c, 0x6b, 0x4d, 0xe4, 0x59, 0xf9, 0x5a, 0x1f,
0xe6, 0xbc, 0x73, 0x66, 0x5c, 0x1c, 0xf0, 0x2b, 0x76, 0xc2, 0x9f, 0xbd, 0xce, 0xea, 0x66, 0xbb,
0xa5, 0x56, 0xee, 0x27, 0x84, 0x25, 0x0c, 0x26, 0xde, 0x39, 0xeb, 0x55, 0xb2, 0x09, 0x04, 0x28,
0xcb, 0x21, 0x7b, 0x85, 0x26, 0x10, 0xd0, 0xa2, 0xe1, 0x88, 0x04, 0x22, 0xc4, 0xdb, 0x13, 0x33,
0xe3, 0x5c, 0xbd, 0x98, 0x7f, 0xc2, 0x75, 0x2e, 0x47, 0x59, 0x83, 0x20, 0x71, 0x68, 0x11, 0x54,
0xb0, 0xfb, 0x4b, 0xe3, 0xdf, 0x0e, 0xb1, 0x7b, 0x84, 0x9d, 0xee, 0x30, 0xbb, 0x3f, 0x80, 0x44,
0x5c, 0xd9, 0x1b, 0x1f, 0x94, 0xab, 0xee, 0x85, 0x8f, 0xfb, 0x03, 0x48, 0xe7, 0xf4, 0xcd, 0xad,
0xd6, 0xd3, 0x38, 0xb9, 0x9c, 0x57, 0x7c, 0x59, 0xa4, 0xdb, 0x3c, 0xe7, 0x15, 0x38, 0x7d, 0xf3,
0x4a, 0x0d, 0x50, 0xe2, 0xf4, 0xad, 0x47, 0xc5, 0x66, 0x70, 0x6e, 0x29, 0xa6, 0x79, 0x36, 0x87,
0x3b, 0x6a, 0xcf, 0x90, 0x04, 0x88, 0x0c, 0x0e, 0x05, 0x91, 0x20, 0x6a, 0x77, 0xdc, 0x22, 0x4b,
0xe2, 0xbc, 0xf5, 0xb7, 0x45, 0x9b, 0xf1, 0xc0, 0xde, 0x20, 0x42, 0x14, 0x90, 0x7a, 0x9e, 0x2c,
0xab, 0x62, 0xaf, 0x10, 0x9c, 0xac, 0xa7, 0x06, 0x7a, 0xeb, 0xe9, 0x80, 0x60, 0x5a, 0x3d, 0x61,
0xaf, 0x9b, 0xd2, 0x34, 0xff, 0x60, 0xd3, 0x6a, 0xf3, 0xf7, 0x89, 0x92, 0x87, 0xa6, 0x55, 0xc0,
0x81, 0xca, 0x28, 0x27, 0x6d, 0xc0, 0x04, 0xb4, 0xfd, 0x30, 0xb9, 0xd7, 0x0f, 0xe2, 0x7e, 0x66,
0x62, 0x95, 0xb3, 0x90, 0x1f, 0x09, 0x0c, 0xf1, 0xa3, 0x41, 0x7b, 0xdc, 0xe2, 0xd5, 0xe7, 0x82,
0x25, 0x97, 0x9d, 0x0b, 0x6c, 0x7e, 0x41, 0x5b, 0x84, 0x38, 0x6e, 0x21, 0x50, 0xbc, 0x8b, 0xf6,
0x12, 0x5e, 0x84, 0xba, 0xa8, 0x91, 0x0f, 0xe9, 0x22, 0xc5, 0xd9, 0xcd, 0xaf, 0x91, 0xaa, 0xc8,
0x6c, 0xbb, 0x69, 0x83, 0xb0, 0xe0, 0x42, 0xc4, 0xe6, 0x97, 0x84, 0x6d, 0x4e, 0x0e, 0x7d, 0x1e,
0x74, 0x6f, 0xf7, 0x77, 0xac, 0x1c, 0xd0, 0xb7, 0xfb, 0x29, 0x96, 0xae, 0x64, 0x1b, 0x23, 0x3d,
0x56, 0xfc, 0x38, 0x79, 0x38, 0x0c, 0xb6, 0x5b, 0x1e, 0xcf, 0xe7, 0x76, 0xce, 0xe2, 0xaa, 0xf5,
0xba, 0x19, 0x30, 0x64, 0x31, 0x62, 0xcb, 0x13, 0xc0, 0xc1, 0x14, 0xe6, 0x79, 0xde, 0xe6, 0x85,
0x60, 0x85, 0xc0, 0xa6, 0x30, 0xdf, 0x98, 0x02, 0x43, 0x53, 0x18, 0xa5, 0x00, 0xe2, 0x56, 0x9e,
0x07, 0x31, 0x71, 0x18, 0x2f, 0xd0, 0x8c, 0xad, 0x3d, 0xeb, 0x69, 0xe5, 0xa1, 0xb8, 0x05, 0x9c,
0xf3, 0x38, 0xd7, 0xf5, 0x72, 0x12, 0x57, 0x73, 0x73, 0xba, 0x91, 0x8e, 0x1f, 0xd1, 0x76, 0x7c,
0x92, 0x78, 0x9c, 0x1b, 0xd6, 0x00, 0xd3, 0xce, 0xde, 0x22, 0x9e, 0x9b, 0x9a, 0x22, 0x35, 0x90,
0xf2, 0x4e, 0x55, 0xef, 0xf5, 0x83, 0xc0, 0xcf, 0x8b, 0x2c, 0x65, 0x3c, 0xe0, 0x47, 0xca, 0x87,
0xf8, 0x81, 0x20, 0xc8, 0xde, 0x9a, 0x7a, 0xb7, 0x3b, 0xba, 0x69, 0x91, 0xaa, 0x7d, 0xec, 0x84,
0x68, 0x1e, 0xc0, 0x85, 0xb2, 0x37, 0x82, 0x07, 0x63, 0x54, 0x1f, 0xd0, 0x86, 0xc6, 0xa8, 0x39,
0x7f, 0x1d, 0x32, 0x46, 0x31, 0x58, 0xf9, 0xfc, 0x89, 0x1a, 0xa3, 0x3b, 0xb1, 0x88, 0x9b, 0xbc,
0xfd, 0x45, 0xc6, 0x5e, 0xa9, 0x8d, 0x30, 0x52, 0x5f, 0x4d, 0x4d, 0xe4, 0xcb, 0xc9, 0x60, 0x57,
0xbc, 0x35, 0x98, 0x0f, 0xf8, 0x56, 0x3b, 0x84, 0x5e, 0xdf, 0x60, 0xab, 0xb0, 0x35, 0x98, 0x0f,
0xf8, 0x56, 0x5f, 0x3d, 0xe8, 0xf5, 0x0d, 0x3e, 0x7d, 0xb0, 0x35, 0x98, 0x57, 0xbe, 0xff, 0x4c,
0x0f, 0x5c, 0xd7, 0x79, 0x93, 0x87, 0x25, 0x22, 0xbb, 0x62, 0x58, 0x3a, 0xe9, 0xdb, 0x33, 0x68,
0x28, 0x9d, 0xa4, 0x55, 0x9c, 0xef, 0x74, 0x61, 0xa5, 0x38, 0xe2, 0x75, 0x26, 0xaf, 0x63, 0x3c,
0x19, 0x60, 0x54, 0xc3, 0xa1, 0x4d, 0x53, 0x48, 0xc9, 0x3e, 0x58, 0xf6, 0x50, 0x7b, 0x5f, 0xfd,
0x61, 0xc0, 0x5e, 0xf7, 0xda, 0xfa, 0xe6, 0x40, 0xda, 0x3e, 0xe2, 0xf5, 0x18, 0xf7, 0xd9, 0x72,
0xa8, 0x57, 0xd1, 0xc7, 0xcb, 0x8f, 0x86, 0x2b, 0x28, 0xf7, 0x7f, 0xa1, 0xf7, 0x15, 0xd0, 0xbf,
0x1a, 0x04, 0x8f, 0x87, 0x58, 0x04, 0x03, 0xe1, 0xc9, 0xb5, 0x74, 0x54, 0x41, 0xfe, 0x46, 0x6f,
0xa0, 0x35, 0x2a, 0xdf, 0xda, 0x91, 0x6f, 0xfb, 0xaa, 0x31, 0x11, 0xea, 0x56, 0x0b, 0xc3, 0x91,
0xf1, 0xf1, 0x35, 0xb5, 0x9c, 0xaf, 0xb6, 0x79, 0xb0, 0x7a, 0xbb, 0xd4, 0x29, 0x4f, 0xc8, 0xb2,
0x43, 0xc3, 0x02, 0x7d, 0x72, 0x5d, 0x35, 0x6a, 0xac, 0x38, 0xb0, 0xfc, 0x0e, 0xcb, 0x93, 0x81,
0x86, 0xbd, 0x2f, 0xb3, 0x7c, 0x74, 0x3d, 0x25, 0x55, 0x96, 0x7f, 0x1f, 0x45, 0x77, 0x3d, 0xd6,
0x3e, 0x4f, 0x00, 0xa7, 0x1e, 0x3f, 0x08, 0xd8, 0xa7, 0x94, 0x4c, 0xe1, 0x7e, 0xeb, 0x9b, 0x29,
0xdb, 0x4f, 0x9c, 0x79, 0x2a, 0xcf, 0xb3, 0x5c, 0xb0, 0xaa, 0xfb, 0x89, 0x33, 0xdf, 0x6e, 0x4b,
0x4d, 0xe8, 0x4f, 0x9c, 0x05, 0x70, 0xe7, 0x13, 0x67, 0x88, 0x67, 0xf4, 0x13, 0x67, 0xa8, 0xb5,
0xe0, 0x27, 0xce, 0xc2, 0x1a, 0xd4, 0xf4, 0xae, 0x8b, 0xd0, 0x9e, 0x5b, 0x0f, 0xb2, 0xe8, 0x1f,
0x63, 0x3f, 0xbe, 0x8e, 0x0a, 0xb1, 0xc0, 0xb5, 0x9c, 0xbc, 0xd1, 0x38, 0xa0, 0x4d, 0xbd, 0x5b,
0x8d, 0x5b, 0x83, 0x79, 0xe5, 0xfb, 0xc7, 0x6a, 0x77, 0x63, 0xa6, 0x73, 0x5e, 0xc9, 0xcf, 0xdb,
0x6d, 0x84, 0xa6, 0xe7, 0xc6, 0x82, 0xdb, 0xf3, 0x0f, 0x87, 0xc1, 0x44, 0x75, 0x1b, 0x42, 0x75,
0xfa, 0xa4, 0xcf, 0x10, 0xe8, 0xf2, 0xad, 0xc1, 0x3c, 0xb1, 0x8c, 0xb4, 0xbe, 0xdb, 0xde, 0x1e,
0x60, 0xcc, 0xef, 0xeb, 0x47, 0xc3, 0x15, 0x94, 0xfb, 0x2b, 0x95, 0x36, 0xba, 0xee, 0x65, 0x3f,
0x6f, 0xf6, 0x99, 0x9a, 0x79, 0xdd, 0x3c, 0x19, 0x8a, 0x87, 0x12, 0x08, 0x77, 0x09, 0xed, 0x4b,
0x20, 0xd0, 0x65, 0xf4, 0xa3, 0xeb, 0x29, 0xa9, 0xb2, 0xfc, 0xfd, 0x28, 0xba, 0x49, 0x96, 0x45,
0xc5, 0xc1, 0x27, 0x43, 0x2d, 0x83, 0x78, 0xf8, 0xf4, 0xda, 0x7a, 0xaa, 0x50, 0xff, 0x34, 0x8a,
0x6e, 0x05, 0x0a, 0xd5, 0x06, 0xc8, 0x35, 0xac, 0xfb, 0x81, 0xf2, 0xd9, 0xf5, 0x15, 0xa9, 0xe5,
0xde, 0xc5, 0x67, 0xdd, 0xcf, 0x6f, 0x05, 0x6c, 0xcf, 0xe8, 0xcf, 0x6f, 0xf5, 0x6b, 0xc1, 0x43,
0x9e, 0xf8, 0x4c, 0x6f, 0xba, 0xd0, 0x43, 0x1e, 0x79, 0x17, 0x31, 0xf8, 0x19, 0x11, 0x8c, 0xc3,
0x9c, 0x3c, 0x7b, 0x5d, 0xc6, 0x45, 0x4a, 0x3b, 0x69, 0xe5, 0xfd, 0x4e, 0x0c, 0x07, 0x0f, 0xc7,
0x1a, 0xe9, 0x31, 0xd7, 0x1b, 0xa9, 0xfb, 0x94, 0xbe, 0x41, 0x82, 0x87, 0x63, 0x1d, 0x94, 0xf0,
0xa6, 0xb2, 0xc6, 0x90, 0x37, 0x90, 0x2c, 0x3e, 0x18, 0x82, 0x82, 0x14, 0xdd, 0x78, 0x33, 0x67,
0xee, 0x0f, 0x43, 0x56, 0x3a, 0xe7, 0xee, 0x9b, 0x03, 0x69, 0xc2, 0xed, 0x8c, 0x89, 0xcf, 0x59,
0x9c, 0xb2, 0x2a, 0xe8, 0xd6, 0x50, 0x83, 0xdc, 0xba, 0x34, 0xe6, 0x76, 0x9b, 0xe7, 0xcb, 0x45,
0xa1, 0x3a, 0x93, 0x74, 0xeb, 0x52, 0xfd, 0x6e, 0x01, 0x0d, 0x8f, 0x05, 0xad, 0x5b, 0x99, 0x5e,
0x3e, 0x08, 0x9b, 0xf1, 0xb2, 0xca, 0x8d, 0x41, 0x2c, 0x5d, 0x4f, 0x15, 0x46, 0x3d, 0xf5, 0x04,
0x91, 0xb4, 0x39, 0x90, 0x86, 0xe7, 0x73, 0x8e, 0x5b, 0x13, 0x4f, 0x5b, 0x3d, 0xb6, 0x3a, 0x21,
0xf5, 0x68, 0xb8, 0x02, 0x3c, 0x0d, 0x55, 0x51, 0xb5, 0x9f, 0xd5, 0xe2, 0x79, 0x96, 0xe7, 0xe3,
0x8d, 0x40, 0x98, 0x68, 0x28, 0x78, 0x1a, 0x8a, 0xc0, 0x44, 0x24, 0xeb, 0xd3, 0xc3, 0x62, 0xdc,
0x67, 0x47, 0x52, 0x83, 0x22, 0xd9, 0xa5, 0xc1, 0x89, 0x96, 0xd3, 0xd4, 0xa6, 0xb6, 0x93, 0x70,
0xc3, 0x75, 0x2a, 0xbc, 0x35, 0x98, 0x07, 0x8f, 0xdb, 0x25, 0x25, 0x57, 0x96, 0x3b, 0x94, 0x09,
0x6f, 0x25, 0xb9, 0xdb, 0x43, 0x81, 0x53, 0xc1, 0x76, 0x18, 0xbd, 0xcc, 0xd2, 0x39, 0x13, 0xe8,
0x93, 0x22, 0x17, 0x08, 0x3e, 0x29, 0x02, 0x20, 0xe8, 0xba, 0xf6, 0xef, 0xe6, 0x38, 0x74, 0x2f,
0xc5, 0xba, 0x4e, 0x29, 0x3b, 0x54, 0xa8, 0xeb, 0x50, 0x1a, 0xcc, 0x06, 0xc6, 0xad, 0xfa, 0xf0,
0xc2, 0x83, 0x90, 0x19, 0xf0, 0xf5, 0x85, 0x8d, 0x41, 0x2c, 0x58, 0x51, 0xac, 0xc3, 0x6c, 0x91,
0x09, 0x6c, 0x45, 0x71, 0x6c, 0x34, 0x48, 0x68, 0x45, 0xe9, 0xa2, 0x54, 0xf5, 0x9a, 0x1c, 0x61,
0x2f, 0x0d, 0x57, 0xaf, 0x65, 0x86, 0x55, 0xcf, 0xb0, 0x9d, 0x07, 0x9b, 0x85, 0x09, 0x19, 0x71,
0xa1, 0x36, 0xcb, 0x48, 0x6c, 0xcb, 0x17, 0x72, 0x21, 0x18, 0x9a, 0x75, 0x28, 0x05, 0x78, 0x60,
0xdf, 0x70, 0xfa, 0xd9, 0x6b, 0x59, 0xb2, 0xb8, 0x8a, 0x8b, 0x04, 0xdd, 0x9c, 0x4a, 0x83, 0x1d,
0x32, 0xb4, 0x39, 0x25, 0x35, 0xc0, 0x63, 0x73, 0xff, 0x55, 0x5a, 0x64, 0x28, 0x98, 0x77, 0x56,
0xfd, 0x37, 0x69, 0xef, 0x0f, 0x20, 0xe1, 0x63, 0x73, 0x0d, 0x98, 0x83, 0xef, 0xd6, 0xe9, 0x87,
0x01, 0x53, 0x3e, 0x1a, 0xda, 0x08, 0xd3, 0x2a, 0x20, 0xa8, 0x4d, 0x82, 0xcb, 0xc4, 0x8f, 0xd8,
0x0a, 0x0b, 0x6a, 0x9b, 0x9f, 0x4a, 0x24, 0x14, 0xd4, 0x5d, 0x14, 0xe4, 0x99, 0xee, 0x3e, 0x68,
0x2d, 0xa0, 0xef, 0x6e, 0x7d, 0xd6, 0x7b, 0x39, 0x30, 0x72, 0x76, 0xb2, 0x2b, 0xef, 0x39, 0x01,
0x52, 0xd0, 0x9d, 0xec, 0x0a, 0x7f, 0x4c, 0xb0, 0x31, 0x88, 0x85, 0x8f, 0xe4, 0x63, 0xc1, 0x5e,
0xeb, 0x67, 0xe5, 0x48, 0x71, 0xa5, 0xbc, 0xf3, 0xb0, 0xfc, 0x5e, 0x3f, 0x68, 0x2f, 0xc0, 0x1e,
0x55, 0x3c, 0x61, 0x75, 0xad, 0xbe, 0x49, 0xea, 0xdf, 0x30, 0x52, 0xb2, 0x09, 0xf8, 0x22, 0xe9,
0x9d, 0x30, 0xe4, 0x7c, 0x48, 0xb0, 0x15, 0xd9, 0xef, 0x1b, 0xad, 0xa1, 0x9a, 0xdd, 0x4f, 0x1b,
0xad, 0xf7, 0x72, 0x76, 0x78, 0x29, 0xa9, 0xfb, 0x41, 0xa3, 0x7b, 0xa8, 0x3a, 0xf6, 0x2d, 0xa3,
0xfb, 0x03, 0x48, 0xe5, 0xea, 0xf3, 0xe8, 0xcd, 0x7d, 0x3e, 0x9f, 0xb1, 0x22, 0x1d, 0x7f, 0xcf,
0xbf, 0x42, 0xcb, 0xe7, 0x93, 0xe6, 0xcf, 0xc6, 0xe8, 0x0d, 0x4a, 0x6c, 0x2f, 0x01, 0xee, 0xb0,
0xb3, 0xe5, 0x7c, 0x26, 0x62, 0x01, 0x2e, 0x01, 0xca, 0xbf, 0x4f, 0x1a, 0x01, 0x71, 0x09, 0xd0,
0x03, 0x80, 0xbd, 0x93, 0x8a, 0x31, 0xd4, 0x5e, 0x23, 0x08, 0xda, 0x53, 0x80, 0xcd, 0x22, 0x8c,
0xbd, 0x26, 0x51, 0x87, 0x97, 0xf6, 0xac, 0x8e, 0x94, 0x12, 0x59, 0x44, 0x97, 0xb2, 0xc1, 0xdd,
0x56, 0x5f, 0x7e, 0x5f, 0x66, 0xb9, 0x58, 0xc4, 0xd5, 0x0a, 0x04, 0xb7, 0xaa, 0xa5, 0x03, 0x10,
0xc1, 0x8d, 0x82, 0x76, 0xd4, 0xea, 0x66, 0x4e, 0x2e, 0x77, 0x79, 0xc5, 0x97, 0x22, 0x2b, 0x18,
0xfc, 0xc6, 0x88, 0x69, 0x50, 0x97, 0x21, 0x46, 0x2d, 0xc5, 0xda, 0x2c, 0x57, 0x12, 0xed, 0x7d,
0x42, 0xf9, 0x99, 0xf4, 0x5a, 0xf0, 0x0a, 0x3e, 0x4f, 0x6c, 0xad, 0x40, 0x88, 0xc8, 0x72, 0x49,
0x18, 0xf4, 0xfd, 0x51, 0x56, 0xcc, 0xd1, 0xbe, 0x3f, 0x72, 0xbf, 0xf3, 0x7b, 0x8b, 0x06, 0xec,
0x80, 0x6a, 0x1b, 0xad, 0x1d, 0x00, 0xea, 0xad, 0x5d, 0xb4, 0xd1, 0x5d, 0x82, 0x18, 0x50, 0x38,
0x09, 0x5c, 0x7d, 0x51, 0xb2, 0x82, 0xa5, 0xfa, 0xd6, 0x1c, 0xe6, 0xca, 0x23, 0x82, 0xae, 0x20,
0x69, 0xe7, 0x22, 0x29, 0x3f, 0x5e, 0x16, 0x47, 0x15, 0x3f, 0xcf, 0x72, 0x56, 0x81, 0xb9, 0xa8,
0x55, 0x77, 0xe4, 0xc4, 0x5c, 0x84, 0x71, 0xf6, 0xfa, 0x85, 0x94, 0x7a, 0xdf, 0xfa, 0x3f, 0xa9,
0xe2, 0x04, 0x5e, 0xbf, 0x68, 0x6d, 0x74, 0x31, 0xe2, 0x64, 0x30, 0x80, 0x3b, 0x89, 0x4e, 0xeb,
0xba, 0x58, 0xc9, 0xf8, 0x50, 0x6f, 0x8d, 0xca, 0xaf, 0xdf, 0xd6, 0x20, 0xd1, 0x51, 0xe6, 0x30,
0x92, 0x48, 0x74, 0xc2, 0x1a, 0x76, 0x29, 0x91, 0xdc, 0xa1, 0xba, 0x56, 0x04, 0x96, 0x92, 0xd6,
0x86, 0x16, 0x12, 0x4b, 0x49, 0x07, 0x02, 0x13, 0x92, 0x1e, 0x06, 0x73, 0x74, 0x42, 0x32, 0xd2,
0xe0, 0x84, 0xe4, 0x52, 0x76, 0xa2, 0xd8, 0x2b, 0x32, 0x91, 0xc5, 0xf9, 0x8c, 0x89, 0xa3, 0xb8,
0x8a, 0x17, 0x4c, 0xb0, 0x0a, 0x4e, 0x14, 0x0a, 0x99, 0x78, 0x0c, 0x31, 0x51, 0x50, 0xac, 0x72,
0xf8, 0xdb, 0xd1, 0xdb, 0xcd, 0xba, 0xcf, 0x0a, 0xf5, 0xab, 0x3e, 0xcf, 0xe4, 0xcf, 0x81, 0x8d,
0xdf, 0x31, 0x36, 0x66, 0xa2, 0x62, 0xf1, 0x42, 0xdb, 0x7e, 0xcb, 0xfc, 0x5d, 0x82, 0x8f, 0x46,
0x4d, 0x3c, 0x1f, 0x72, 0x91, 0x9d, 0x37, 0xdb, 0x6c, 0xf5, 0x06, 0x11, 0x88, 0x67, 0x57, 0x3c,
0x09, 0x7c, 0x75, 0x04, 0xe3, 0xec, 0x3c, 0xed, 0x4a, 0x8f, 0x59, 0x99, 0xc3, 0x79, 0xda, 0xd3,
0x96, 0x00, 0x31, 0x4f, 0xa3, 0xa0, 0x1d, 0x9c, 0xae, 0xf8, 0x84, 0x85, 0x2b, 0x73, 0xc2, 0x86,
0x55, 0xe6, 0xc4, 0x7b, 0x29, 0x23, 0x8f, 0xde, 0x3e, 0x60, 0x8b, 0x33, 0x56, 0xd5, 0x17, 0x59,
0x49, 0x7d, 0xa1, 0xd7, 0x12, 0xbd, 0x5f, 0xe8, 0x25, 0x50, 0xbb, 0x12, 0x58, 0x60, 0xaf, 0x3e,
0x8c, 0x17, 0x4c, 0x7e, 0x43, 0x05, 0xac, 0x04, 0x8e, 0x11, 0x07, 0x22, 0x56, 0x02, 0x12, 0x76,
0xde, 0xef, 0xb2, 0xcc, 0x31, 0x9b, 0x37, 0x11, 0x56, 0x1d, 0xc5, 0xab, 0x05, 0x2b, 0x84, 0x32,
0x09, 0xce, 0xe4, 0x1d, 0x93, 0x38, 0x4f, 0x9c, 0xc9, 0x0f, 0xd1, 0x73, 0xa6, 0x26, 0xaf, 0xe1,
0x8f, 0x78, 0x25, 0xda, 0xdf, 0xec, 0x3a, 0xad, 0x72, 0x30, 0x35, 0xf9, 0x8d, 0xea, 0x91, 0xc4,
0xd4, 0x14, 0xd6, 0x70, 0x7e, 0x6f, 0xc2, 0x2b, 0xc3, 0x0b, 0x56, 0x99, 0x38, 0x79, 0xb6, 0x88,
0xb3, 0x5c, 0x45, 0xc3, 0xf7, 0x03, 0xb6, 0x09, 0x1d, 0xe2, 0xf7, 0x26, 0x86, 0xea, 0x3a, 0xbf,
0xd0, 0x11, 0x2e, 0x21, 0x78, 0x44, 0xd0, 0x63, 0x9f, 0x78, 0x44, 0xd0, 0xaf, 0x65, 0x77, 0xee,
0x96, 0x95, 0xdc, 0x4a, 0x12, 0xdb, 0x3c, 0x85, 0xe7, 0x85, 0x8e, 0x4d, 0x00, 0x12, 0x3b, 0xf7,
0xa0, 0x82, 0x4d, 0x0d, 0x2c, 0xf6, 0x3c, 0x2b, 0xe2, 0x3c, 0xfb, 0x09, 0x4c, 0xeb, 0x1d, 0x3b,
0x9a, 0x20, 0x52, 0x03, 0x9c, 0xc4, 0x5c, 0xed, 0x32, 0x71, 0x92, 0x35, 0x53, 0xff, 0xbd, 0x40,
0xbb, 0x49, 0xa2, 0xdf, 0x95, 0x43, 0x3a, 0x5f, 0xe3, 0x85, 0xcd, 0x3a, 0x2d, 0xcb, 0x59, 0xb3,
0xaa, 0x1e, 0xb3, 0x84, 0x65, 0xa5, 0x18, 0x7f, 0x1c, 0x6e, 0x2b, 0x80, 0x13, 0x17, 0x2d, 0x06,
0xa8, 0x39, 0x8f, 0xef, 0x9b, 0xb9, 0x64, 0xd6, 0xfe, 0x98, 0xe5, 0x69, 0xcd, 0x2a, 0x95, 0x68,
0xec, 0x32, 0x01, 0x46, 0xa7, 0xc3, 0x4d, 0x1c, 0xb0, 0xa9, 0x28, 0x31, 0x3a, 0xc3, 0x1a, 0xf6,
0xb0, 0xcf, 0xe1, 0xd4, 0xd7, 0xd5, 0xe5, 0x7d, 0xc3, 0x87, 0xa4, 0x31, 0x87, 0x22, 0x0e, 0xfb,
0x68, 0xda, 0x66, 0x6b, 0x5d, 0xb7, 0xd3, 0x62, 0xb5, 0x07, 0xaf, 0x4c, 0x20, 0x96, 0x24, 0x46,
0x64, 0x6b, 0x01, 0xdc, 0x39, 0x0c, 0xaf, 0x78, 0x9c, 0x26, 0x71, 0x2d, 0x8e, 0xe2, 0x55, 0xce,
0xe3, 0x54, 0xae, 0xeb, 0xf0, 0x30, 0x5c, 0x33, 0x13, 0x17, 0xa2, 0x0e, 0xc3, 0x29, 0xd8, 0xcd,
0xce, 0xe4, 0x6f, 0x74, 0xaa, 0xbb, 0x9c, 0x30, 0x3b, 0x93, 0xe5, 0x85, 0xf7, 0x38, 0xef, 0x84,
0x21, 0xfb, 0x0e, 0x5a, 0x2b, 0x92, 0x69, 0xc8, 0x2d, 0x4c, 0xc7, 0x4b, 0x40, 0xde, 0x0f, 0x10,
0xf6, 0x0b, 0x24, 0xed, 0xdf, 0xf5, 0xcf, 0x4c, 0x09, 0xf5, 0xcd, 0xf2, 0x87, 0x98, 0xae, 0x0b,
0x4d, 0xdc, 0x0f, 0x59, 0x6c, 0x0e, 0xa4, 0x6d, 0x9a, 0xb9, 0x7d, 0x11, 0x8b, 0x69, 0x9a, 0x1e,
0xb0, 0x1a, 0x79, 0xa1, 0xbc, 0x11, 0x4e, 0xac, 0x94, 0x48, 0x33, 0xbb, 0x94, 0x0d, 0xf4, 0x46,
0xf6, 0x2c, 0xcd, 0x84, 0x92, 0xe9, 0x1b, 0xd2, 0x0f, 0xbb, 0x06, 0xba, 0x14, 0x51, 0x2b, 0x9a,
0xb6, 0x73, 0x79, 0xc3, 0x9c, 0xf0, 0xf9, 0x3c, 0x67, 0x0a, 0x3a, 0x66, 0x71, 0xfb, 0xc9, 0xc6,
0xad, 0xae, 0x2d, 0x14, 0x24, 0xe6, 0xf2, 0xa0, 0x82, 0x4d, 0x23, 0x1b, 0xac, 0x7d, 0x24, 0xa5,
0x1b, 0x76, 0xbd, 0x6b, 0xc6, 0x03, 0x88, 0x34, 0x12, 0x05, 0xed, 0x7b, 0x6f, 0x8d, 0x78, 0x97,
0xe9, 0x96, 0x80, 0x1f, 0x9b, 0x92, 0xca, 0x8e, 0x98, 0x78, 0xef, 0x0d, 0xc1, 0xec, 0x3e, 0x01,
0x78, 0x78, 0xba, 0xda, 0x4b, 0xe1, 0x3e, 0x01, 0xea, 0x4b, 0x86, 0xd8, 0x27, 0x50, 0xac, 0xdf,
0x75, 0xe6, 0xdc, 0x6b, 0x3f, 0xae, 0x6d, 0xe5, 0x90, 0xae, 0x43, 0xc1, 0x50, 0xd7, 0x51, 0x0a,
0x7e, 0x93, 0xba, 0x47, 0x6b, 0x48, 0x93, 0x62, 0xe7, 0x6a, 0x6b, 0x7d, 0x98, 0x9d, 0x97, 0xcc,
0x7e, 0x52, 0x5e, 0x59, 0xc2, 0x7f, 0xab, 0xa1, 0x15, 0x12, 0xf3, 0x52, 0x07, 0x6a, 0x6d, 0x3f,
0x7d, 0xff, 0x3f, 0xbf, 0xba, 0x31, 0xfa, 0xd9, 0x57, 0x37, 0x46, 0xff, 0xf3, 0xd5, 0x8d, 0xd1,
0x4f, 0xbf, 0xbe, 0xf1, 0xc6, 0xcf, 0xbe, 0xbe, 0xf1, 0xc6, 0x7f, 0x7f, 0x7d, 0xe3, 0x8d, 0x2f,
0xdf, 0x54, 0xbf, 0xdd, 0x7c, 0xf6, 0x73, 0xf2, 0x17, 0x98, 0x9f, 0xfc, 0x5f, 0x00, 0x00, 0x00,
0xff, 0xff, 0x95, 0x51, 0xdf, 0xf9, 0xdf, 0x79, 0x00, 0x00,
}
// This is a compile-time assertion to ensure that this generated file
@ -407,8 +405,6 @@ type ClientCommandsHandler interface {
// Account
// ***
AccountRecover(context.Context, *pb.RpcAccountRecoverRequest) *pb.RpcAccountRecoverResponse
AccountMigrate(context.Context, *pb.RpcAccountMigrateRequest) *pb.RpcAccountMigrateResponse
AccountMigrateCancel(context.Context, *pb.RpcAccountMigrateCancelRequest) *pb.RpcAccountMigrateCancelResponse
AccountCreate(context.Context, *pb.RpcAccountCreateRequest) *pb.RpcAccountCreateResponse
AccountDelete(context.Context, *pb.RpcAccountDeleteRequest) *pb.RpcAccountDeleteResponse
AccountRevertDeletion(context.Context, *pb.RpcAccountRevertDeletionRequest) *pb.RpcAccountRevertDeletionResponse
@ -1150,46 +1146,6 @@ func AccountRecover(b []byte) (resp []byte) {
return resp
}
func AccountMigrate(b []byte) (resp []byte) {
defer func() {
if PanicHandler != nil {
if r := recover(); r != nil {
resp, _ = (&pb.RpcAccountMigrateResponse{Error: &pb.RpcAccountMigrateResponseError{Code: pb.RpcAccountMigrateResponseError_UNKNOWN_ERROR, Description: "panic recovered"}}).Marshal()
PanicHandler(r)
}
}
}()
in := new(pb.RpcAccountMigrateRequest)
if err := in.Unmarshal(b); err != nil {
resp, _ = (&pb.RpcAccountMigrateResponse{Error: &pb.RpcAccountMigrateResponseError{Code: pb.RpcAccountMigrateResponseError_BAD_INPUT, Description: err.Error()}}).Marshal()
return resp
}
resp, _ = clientCommandsHandler.AccountMigrate(context.Background(), in).Marshal()
return resp
}
func AccountMigrateCancel(b []byte) (resp []byte) {
defer func() {
if PanicHandler != nil {
if r := recover(); r != nil {
resp, _ = (&pb.RpcAccountMigrateCancelResponse{Error: &pb.RpcAccountMigrateCancelResponseError{Code: pb.RpcAccountMigrateCancelResponseError_UNKNOWN_ERROR, Description: "panic recovered"}}).Marshal()
PanicHandler(r)
}
}
}()
in := new(pb.RpcAccountMigrateCancelRequest)
if err := in.Unmarshal(b); err != nil {
resp, _ = (&pb.RpcAccountMigrateCancelResponse{Error: &pb.RpcAccountMigrateCancelResponseError{Code: pb.RpcAccountMigrateCancelResponseError_BAD_INPUT, Description: err.Error()}}).Marshal()
return resp
}
resp, _ = clientCommandsHandler.AccountMigrateCancel(context.Background(), in).Marshal()
return resp
}
func AccountCreate(b []byte) (resp []byte) {
defer func() {
if PanicHandler != nil {
@ -6378,10 +6334,6 @@ func CommandAsync(cmd string, data []byte, callback func(data []byte)) {
cd = WorkspaceExport(data)
case "AccountRecover":
cd = AccountRecover(data)
case "AccountMigrate":
cd = AccountMigrate(data)
case "AccountMigrateCancel":
cd = AccountMigrateCancel(data)
case "AccountCreate":
cd = AccountCreate(data)
case "AccountDelete":
@ -7212,34 +7164,6 @@ func (h *ClientCommandsHandlerProxy) AccountRecover(ctx context.Context, req *pb
call, _ := actualCall(ctx, req)
return call.(*pb.RpcAccountRecoverResponse)
}
func (h *ClientCommandsHandlerProxy) AccountMigrate(ctx context.Context, req *pb.RpcAccountMigrateRequest) *pb.RpcAccountMigrateResponse {
actualCall := func(ctx context.Context, req any) (any, error) {
return h.client.AccountMigrate(ctx, req.(*pb.RpcAccountMigrateRequest)), nil
}
for _, interceptor := range h.interceptors {
toCall := actualCall
currentInterceptor := interceptor
actualCall = func(ctx context.Context, req any) (any, error) {
return currentInterceptor(ctx, req, "AccountMigrate", toCall)
}
}
call, _ := actualCall(ctx, req)
return call.(*pb.RpcAccountMigrateResponse)
}
func (h *ClientCommandsHandlerProxy) AccountMigrateCancel(ctx context.Context, req *pb.RpcAccountMigrateCancelRequest) *pb.RpcAccountMigrateCancelResponse {
actualCall := func(ctx context.Context, req any) (any, error) {
return h.client.AccountMigrateCancel(ctx, req.(*pb.RpcAccountMigrateCancelRequest)), nil
}
for _, interceptor := range h.interceptors {
toCall := actualCall
currentInterceptor := interceptor
actualCall = func(ctx context.Context, req any) (any, error) {
return currentInterceptor(ctx, req, "AccountMigrateCancel", toCall)
}
}
call, _ := actualCall(ctx, req)
return call.(*pb.RpcAccountMigrateCancelResponse)
}
func (h *ClientCommandsHandlerProxy) AccountCreate(ctx context.Context, req *pb.RpcAccountCreateRequest) *pb.RpcAccountCreateResponse {
actualCall := func(ctx context.Context, req any) (any, error) {
return h.client.AccountCreate(ctx, req.(*pb.RpcAccountCreateRequest)), nil

View file

@ -9,19 +9,16 @@ import (
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/goccy/go-graphviz"
"github.com/gogo/protobuf/jsonpb"
"github.com/gogo/protobuf/proto"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/debug/exporter"
"github.com/anyproto/anytype-heart/core/debug/treearchive"
"github.com/anyproto/anytype-heart/pkg/lib/core/smartblock"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/util/pbtypes"
@ -45,20 +42,22 @@ func main() {
return
}
fmt.Println("opening file...")
var (
st = time.Now()
ctx = context.Background()
)
res, err := exporter.ImportStorage(ctx, *file)
st := time.Now()
archive, err := treearchive.Open(*file)
if err != nil {
log.Fatal("can't import the tree:", err)
}
objectTree, err := res.CreateReadableTree(*fromRoot, "")
if err != nil {
log.Fatal("can't create readable tree:", err)
log.Fatal("can't open debug file:", err)
}
defer archive.Close()
fmt.Printf("open archive done in %.1fs\n", time.Since(st).Seconds())
importer := exporter.NewTreeImporter(objectTree)
importer := treearchive.NewTreeImporter(archive.ListStorage(), archive.TreeStorage())
st = time.Now()
err = importer.Import(*fromRoot, "")
if err != nil {
log.Fatal("can't import the tree", err)
}
fmt.Printf("import tree done in %.1fs\n", time.Since(st).Seconds())
if *makeJson {
treeJson, err := importer.Json()
if err != nil {
@ -84,11 +83,10 @@ func main() {
}
fmt.Println("Change:")
fmt.Println(pbtypes.Sprint(ch.Model))
objectTree, err = res.CreateReadableTree(*fromRoot, ch.Id)
err = importer.Import(*fromRoot, ch.Id)
if err != nil {
log.Fatal("can't create readable tree:", err)
log.Fatal("can't import the tree before", ch.Id, err)
}
importer = exporter.NewTreeImporter(objectTree)
}
ot := importer.ObjectTree()
di, err := ot.Debug(state.ChangeParser{})
@ -128,16 +126,12 @@ func main() {
if *objectStore {
fmt.Println("fetch object store info..")
f, err := os.Open(filepath.Join(res.FolderPath, "localstore.json"))
ls, err := archive.LocalStore()
if err != nil {
log.Fatal("can't open objectStore info:", err)
fmt.Println("can't open objectStore info:", err)
} else {
fmt.Println(pbtypes.Sprint(ls))
}
info := &model.ObjectInfo{}
if err = jsonpb.Unmarshal(f, info); err != nil {
log.Fatal("can't unmarshal objectStore info:", err)
}
defer f.Close()
fmt.Println(pbtypes.Sprint(info))
}
if *makeTree {

View file

@ -306,7 +306,7 @@ func getTableSizes(mw *core.Middleware) (tables map[string]uint64) {
tables = make(map[string]uint64)
cfg := mw.GetApp().MustComponent(config.CName).(*config.Config)
db, err := sql.Open("sqlite3", cfg.GetSqliteStorePath())
db, err := sql.Open("sqlite3", cfg.GetSpaceStorePath())
if err != nil {
fmt.Println("Error opening database:", err)
return

View file

@ -10,7 +10,6 @@ import (
"github.com/anyproto/anytype-heart/core/application"
"github.com/anyproto/anytype-heart/core/session"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/space/spacecore/storage/migrator"
)
func (mw *Middleware) AccountCreate(cctx context.Context, req *pb.RpcAccountCreateRequest) *pb.RpcAccountCreateResponse {
@ -50,35 +49,6 @@ func (mw *Middleware) AccountRecover(cctx context.Context, _ *pb.RpcAccountRecov
}
}
func (mw *Middleware) AccountMigrate(cctx context.Context, req *pb.RpcAccountMigrateRequest) *pb.RpcAccountMigrateResponse {
err := mw.applicationService.AccountMigrate(cctx, req)
code := mapErrorCode(err,
errToCode(application.ErrBadInput, pb.RpcAccountMigrateResponseError_BAD_INPUT),
errToCode(application.ErrAccountNotFound, pb.RpcAccountMigrateResponseError_ACCOUNT_NOT_FOUND),
errToCode(context.Canceled, pb.RpcAccountMigrateResponseError_CANCELED),
errTypeToCode(&migrator.NotEnoughFreeSpaceError{}, pb.RpcAccountMigrateResponseError_NOT_ENOUGH_FREE_SPACE),
)
return &pb.RpcAccountMigrateResponse{
Error: &pb.RpcAccountMigrateResponseError{
Code: code,
Description: getErrorDescription(err),
},
}
}
func (mw *Middleware) AccountMigrateCancel(cctx context.Context, req *pb.RpcAccountMigrateCancelRequest) *pb.RpcAccountMigrateCancelResponse {
err := mw.applicationService.AccountMigrateCancel(cctx, req)
code := mapErrorCode(err,
errToCode(application.ErrBadInput, pb.RpcAccountMigrateCancelResponseError_BAD_INPUT),
)
return &pb.RpcAccountMigrateCancelResponse{
Error: &pb.RpcAccountMigrateCancelResponseError{
Code: code,
Description: getErrorDescription(err),
},
}
}
func (mw *Middleware) AccountSelect(cctx context.Context, req *pb.RpcAccountSelectRequest) *pb.RpcAccountSelectResponse {
account, err := mw.applicationService.AccountSelect(cctx, req)
code := mapErrorCode(err,
@ -94,7 +64,6 @@ func (mw *Middleware) AccountSelect(cctx context.Context, req *pb.RpcAccountSele
errToCode(application.ErrAnotherProcessIsRunning, pb.RpcAccountSelectResponseError_ANOTHER_ANYTYPE_PROCESS_IS_RUNNING),
errToCode(application.ErrIncompatibleVersion, pb.RpcAccountSelectResponseError_FAILED_TO_FETCH_REMOTE_NODE_HAS_INCOMPATIBLE_PROTO_VERSION),
errToCode(application.ErrFailedToStartApplication, pb.RpcAccountSelectResponseError_FAILED_TO_RUN_NODE),
errToCode(application.ErrAccountStoreIsNotMigrated, pb.RpcAccountSelectResponseError_ACCOUNT_STORE_NOT_MIGRATED),
)
return &pb.RpcAccountSelectResponse{
Config: nil,

View file

@ -10,6 +10,7 @@ import (
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/acl/aclclient"
"github.com/anyproto/any-sync/commonspace/object/acl/list"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/coordinator/coordinatorclient"
"github.com/anyproto/any-sync/coordinator/coordinatorproto"
"github.com/anyproto/any-sync/nodeconf"
@ -391,7 +392,7 @@ func (a *aclService) ViewInvite(ctx context.Context, inviteCid cid.Cid, inviteFi
if len(recs) == 0 {
return domain.InviteView{}, fmt.Errorf("no acl records found for space: %s, %w", res.SpaceId, ErrAclRequestFailed)
}
store, err := list.NewInMemoryStorage(recs[0].Id, recs)
store, err := liststorage.NewInMemoryAclListStorage(recs[0].Id, recs)
if err != nil {
return domain.InviteView{}, convertedOrAclRequestError(err)
}

View file

@ -143,6 +143,9 @@ func (m mockSyncAcl) HandleRequest(ctx context.Context, senderId string, request
return nil, nil
}
func (m mockSyncAcl) SetHeadUpdater(updater headupdater.HeadUpdater) {
}
func (m mockSyncAcl) SetAclUpdater(updater headupdater.AclUpdater) {
}
@ -323,7 +326,7 @@ func TestService_ViewInvite(t *testing.T) {
keys, err := accountdata.NewRandom()
require.NoError(t, err)
fx.mockAccountService.EXPECT().Keys().Return(keys)
aclList, err := list.NewInMemoryDerivedAcl("spaceId", keys)
aclList, err := list.NewTestDerivedAcl("spaceId", keys)
require.NoError(t, err)
inv, err := aclList.RecordBuilder().BuildInvite()
require.NoError(t, err)
@ -354,7 +357,7 @@ func TestService_ViewInvite(t *testing.T) {
keys, err := accountdata.NewRandom()
require.NoError(t, err)
fx.mockAccountService.EXPECT().Keys().Return(keys)
aclList, err := list.NewInMemoryDerivedAcl("spaceId", keys)
aclList, err := list.NewTestDerivedAcl("spaceId", keys)
require.NoError(t, err)
inv, err := aclList.RecordBuilder().BuildInvite()
require.NoError(t, err)

View file

@ -108,12 +108,9 @@ import (
"github.com/anyproto/anytype-heart/space/spacecore/clientserver"
"github.com/anyproto/anytype-heart/space/spacecore/credentialprovider"
"github.com/anyproto/anytype-heart/space/spacecore/localdiscovery"
"github.com/anyproto/anytype-heart/space/spacecore/oldstorage"
"github.com/anyproto/anytype-heart/space/spacecore/peermanager"
"github.com/anyproto/anytype-heart/space/spacecore/peerstore"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/migrator"
"github.com/anyproto/anytype-heart/space/spacecore/storage/migratorfinisher"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider"
"github.com/anyproto/anytype-heart/space/spacefactory"
"github.com/anyproto/anytype-heart/space/virtualspaceservice"
@ -209,18 +206,6 @@ func appVersion(a *app.App, clientWithVersion string) string {
return clientWithVersion + "/middle:" + middleVersion + "/any-sync:" + anySyncVersion
}
func BootstrapMigration(a *app.App, components ...app.Component) {
for _, c := range components {
a.Register(c)
}
a.Register(migratorfinisher.New()).
Register(clientds.New()).
Register(oldstorage.New()).
Register(storage.New()).
Register(process.New()).
Register(migrator.New())
}
func Bootstrap(a *app.App, components ...app.Component) {
for _, c := range components {
a.Register(c)

View file

@ -43,7 +43,6 @@ const (
const (
SpaceStoreBadgerPath = "spacestore"
SpaceStoreSqlitePath = "spaceStore.db"
SpaceStoreNewPath = "spaceStoreNew"
)
var (
@ -70,7 +69,6 @@ type Config struct {
DisableThreadsSyncEvents bool
DontStartLocalNetworkSyncAutomatically bool
PeferYamuxTransport bool
DisableNetworkIdCheck bool
SpaceStorageMode storage.SpaceStorageMode
NetworkMode pb.RpcAccountNetworkMode
NetworkCustomConfigFilePath string `json:",omitempty"` // not saved to config
@ -295,27 +293,12 @@ func (c *Config) FSConfig() (FSConfig, error) {
return FSConfig{IPFSStorageAddr: res.CustomFileStorePath}, nil
}
func (c *Config) GetRepoPath() string {
return c.RepoPath
}
func (c *Config) GetConfigPath() string {
return filepath.Join(c.RepoPath, ConfigFileName)
}
func (c *Config) GetSqliteStorePath() string {
return filepath.Join(c.RepoPath, SpaceStoreSqlitePath)
}
func (c *Config) GetOldSpaceStorePath() string {
if c.GetSpaceStorageMode() == storage.SpaceStorageModeBadger {
return filepath.Join(c.RepoPath, SpaceStoreBadgerPath)
}
return c.GetSqliteStorePath()
}
func (c *Config) GetNewSpaceStorePath() string {
return filepath.Join(c.RepoPath, SpaceStoreNewPath)
func (c *Config) GetSpaceStorePath() string {
return filepath.Join(c.RepoPath, "spaceStore.db")
}
func (c *Config) GetTempDirPath() string {
@ -408,7 +391,7 @@ func (c *Config) GetNodeConfWithError() (conf nodeconf.Configuration, err error)
if err := yaml.Unmarshal(confBytes, &conf); err != nil {
return nodeconf.Configuration{}, errors.Join(ErrNetworkFileFailedToRead, err)
}
if !c.DisableNetworkIdCheck && c.NetworkId != "" && c.NetworkId != conf.NetworkId {
if c.NetworkId != "" && c.NetworkId != conf.NetworkId {
log.Warnf("Network id mismatch: %s != %s", c.NetworkId, conf.NetworkId)
return nodeconf.Configuration{}, errors.Join(ErrNetworkIdMismatch, fmt.Errorf("network id mismatch: %s != %s", c.NetworkId, conf.NetworkId))
}

View file

@ -31,23 +31,15 @@ var (
ErrNoMnemonicProvided = errors.New("no mnemonic provided")
ErrIncompatibleVersion = errors.New("can't fetch account's data because remote nodes have incompatible protocol version. Please update anytype to the latest version")
ErrAnotherProcessIsRunning = errors.New("another anytype process is running")
ErrFailedToFindAccountInfo = errors.New("failed to find account info")
ErrAccountIsDeleted = errors.New("account is deleted")
ErrAccountStoreIsNotMigrated = errors.New("account store is not migrated")
ErrAnotherProcessIsRunning = errors.New("another anytype process is running")
ErrFailedToFindAccountInfo = errors.New("failed to find account info")
ErrAccountIsDeleted = errors.New("account is deleted")
)
func (s *Service) AccountSelect(ctx context.Context, req *pb.RpcAccountSelectRequest) (*model.Account, error) {
if req.Id == "" {
return nil, ErrEmptyAccountID
}
curMigration := s.migrationManager.getOrCreateMigration(req.RootPath, req.Id)
if !curMigration.successful() {
return nil, ErrAccountStoreIsNotMigrated
}
if s.migrationManager.isRunning() {
return nil, ErrMigrationRunning
}
if runtime.GOOS != "android" && runtime.GOOS != "ios" {
s.traceRecorder.start()

View file

@ -1,222 +0,0 @@
package application
import (
"context"
"errors"
"os"
"path/filepath"
"sync"
"github.com/anyproto/any-sync/app"
"go.uber.org/zap"
"github.com/anyproto/anytype-heart/core/anytype"
"github.com/anyproto/anytype-heart/core/anytype/config"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/core"
)
var (
ErrAccountNotFound = errors.New("account not found")
ErrMigrationRunning = errors.New("migration is running")
)
func (s *Service) AccountMigrate(ctx context.Context, req *pb.RpcAccountMigrateRequest) error {
if s.rootPath == "" {
s.rootPath = req.RootPath
}
return s.migrationManager.getOrCreateMigration(req.RootPath, req.Id).wait()
}
func (s *Service) AccountMigrateCancel(ctx context.Context, req *pb.RpcAccountMigrateCancelRequest) error {
m := s.migrationManager.getMigration(req.Id)
if m == nil {
return nil
}
m.cancelMigration()
return nil
}
func (s *Service) migrate(ctx context.Context, id string) error {
res, err := core.WalletAccountAt(s.mnemonic, 0)
if err != nil {
return err
}
if _, err := os.Stat(filepath.Join(s.rootPath, id)); err != nil {
if os.IsNotExist(err) {
return ErrAccountNotFound
}
return err
}
cfg := anytype.BootstrapConfig(false, os.Getenv("ANYTYPE_STAGING") == "1")
cfg.PeferYamuxTransport = true
cfg.DisableNetworkIdCheck = true
comps := []app.Component{
cfg,
anytype.BootstrapWallet(s.rootPath, res),
s.eventSender,
}
a := &app.App{}
anytype.BootstrapMigration(a, comps...)
err = a.Start(ctx)
if err != nil {
return err
}
return a.Close(ctx)
}
type migration struct {
mx sync.Mutex
isStarted bool
isFinished bool
ctx context.Context
cancel context.CancelFunc
manager *migrationManager
err error
id string
done chan struct{}
}
func newMigration(m *migrationManager, id string) *migration {
ctx, cancel := context.WithCancel(context.Background())
return &migration{
ctx: ctx,
cancel: cancel,
done: make(chan struct{}),
id: id,
manager: m,
}
}
func newSuccessfulMigration(manager *migrationManager, id string) *migration {
m := newMigration(manager, id)
m.setFinished(nil, false)
return m
}
func (m *migration) setFinished(err error, notify bool) {
m.mx.Lock()
defer m.mx.Unlock()
m.isFinished = true
m.err = err
close(m.done)
if notify {
m.manager.setMigrationRunning(m.id, false)
}
}
func (m *migration) cancelMigration() {
m.cancel()
err := m.wait()
if err != nil {
log.Warn("failed to wait for migration to finish", zap.Error(err))
}
}
func (m *migration) wait() error {
m.mx.Lock()
if !m.manager.setMigrationRunning(m.id, true) {
m.mx.Unlock()
return ErrMigrationRunning
}
if !m.isStarted {
m.isStarted = true
} else {
m.mx.Unlock()
<-m.done
return m.err
}
m.mx.Unlock()
err := m.manager.service.migrate(m.ctx, m.id)
if err != nil {
m.setFinished(err, true)
return err
}
m.setFinished(nil, true)
return nil
}
func (m *migration) successful() bool {
m.mx.Lock()
defer m.mx.Unlock()
return m.isFinished && m.err == nil
}
func (m *migration) finished() bool {
m.mx.Lock()
defer m.mx.Unlock()
return m.isFinished
}
type migrationManager struct {
migrations map[string]*migration
service *Service
runningMigration string
sync.Mutex
}
func newMigrationManager(s *Service) *migrationManager {
return &migrationManager{
service: s,
}
}
func (m *migrationManager) setMigrationRunning(id string, isRunning bool) bool {
m.Lock()
defer m.Unlock()
if (m.runningMigration != "" && m.runningMigration != id) && isRunning {
return false
}
if m.runningMigration == "" && !isRunning {
panic("migration is not running")
}
if isRunning {
m.runningMigration = id
} else {
m.runningMigration = ""
}
return true
}
func (m *migrationManager) isRunning() bool {
m.Lock()
defer m.Unlock()
return m.runningMigration != ""
}
func (m *migrationManager) getOrCreateMigration(rootPath, id string) *migration {
m.Lock()
defer m.Unlock()
if m.migrations == nil {
m.migrations = make(map[string]*migration)
}
if m.migrations[id] == nil {
sqlitePath := filepath.Join(rootPath, id, config.SpaceStoreSqlitePath)
baderPath := filepath.Join(rootPath, id, config.SpaceStoreBadgerPath)
if anyPathExists([]string{sqlitePath, baderPath}) {
m.migrations[id] = newMigration(m, id)
} else {
m.migrations[id] = newSuccessfulMigration(m, id)
}
}
if m.migrations[id].finished() && !m.migrations[id].successful() {
// resetting migration
m.migrations[id] = newMigration(m, id)
}
return m.migrations[id]
}
func (m *migrationManager) getMigration(id string) *migration {
m.Lock()
defer m.Unlock()
return m.migrations[id]
}
func anyPathExists(paths []string) bool {
for _, path := range paths {
if _, err := os.Stat(path); err == nil {
return true
}
}
return false
}

View file

@ -30,20 +30,16 @@ type Service struct {
eventSender event.Sender
sessions session.Service
traceRecorder *traceRecorder
migrationManager *migrationManager
appAccountStartInProcessCancel context.CancelFunc
appAccountStartInProcessCancelMutex sync.Mutex
}
func New() *Service {
s := &Service{
return &Service{
sessions: session.New(),
traceRecorder: &traceRecorder{},
}
m := newMigrationManager(s)
s.migrationManager = m
return s
}
func (s *Service) GetApp() *app.App {

View file

@ -1,7 +1,6 @@
package block
import (
"context"
"encoding/json"
"fmt"
"net/http"
@ -23,7 +22,6 @@ import (
func (s *Service) DebugRouter(r chi.Router) {
r.Get("/objects", debug.JSONHandler(s.debugListObjects))
r.Get("/tree/{id}", debug.JSONHandler(s.debugTree))
r.Get("/tree_in_space/{spaceId}/{id}", debug.JSONHandler(s.debugTreeInSpace))
r.Get("/objects_per_space/{spaceId}", debug.JSONHandler(s.debugListObjectsPerSpace))
r.Get("/objects/{id}", debug.JSONHandler(s.debugGetObject))
}
@ -124,44 +122,6 @@ func (s *Service) debugTree(req *http.Request) (debugTree, error) {
return result, err
}
// TODO Refactor
func (s *Service) debugTreeInSpace(req *http.Request) (debugTree, error) {
spaceId := chi.URLParam(req, "spaceId")
id := chi.URLParam(req, "id")
result := debugTree{
Id: id,
}
spc, err := s.spaceService.Get(context.Background(), spaceId)
if err != nil {
return result, fmt.Errorf("get space: %w", err)
}
err = spc.Do(id, func(sb smartblock.SmartBlock) error {
ot := sb.Tree()
return ot.IterateRoot(source.UnmarshalChange, func(change *objecttree.Change) bool {
change.Next = nil
raw, err := json.Marshal(change)
if err != nil {
log.Error("debug tree: marshal change", zap.Error(err))
return false
}
ts := time.Unix(change.Timestamp, 0)
ch := debugChange{
Change: raw,
Timestamp: ts.Format(time.RFC3339),
}
if change.Identity != nil {
ch.Identity = change.Identity.Account()
}
result.Changes = append(result.Changes, ch)
return true
})
})
return result, err
}
func (s *Service) getDebugObject(id string) (debugObject, error) {
var obj debugObject
err := cache.Do(s, id, func(sb smartblock.SmartBlock) error {

View file

@ -39,7 +39,6 @@ type StoreObject interface {
ToggleMessageReaction(ctx context.Context, messageId string, emoji string) error
DeleteMessage(ctx context.Context, messageId string) error
SubscribeLastMessages(ctx context.Context, limit int) ([]*model.ChatMessage, int, error)
MarkSeenHeads(heads []string)
Unsubscribe() error
}
@ -113,10 +112,6 @@ func (s *storeObject) onUpdate() {
s.subscription.flush()
}
func (s *storeObject) MarkSeenHeads(heads []string) {
s.storeSource.MarkSeenHeads(heads)
}
func (s *storeObject) GetMessagesByIds(ctx context.Context, messageIds []string) ([]*model.ChatMessage, error) {
coll, err := s.store.Collection(ctx, collectionName)
if err != nil {

View file

@ -1,60 +1,72 @@
package debug
// TODO: revive at some point
// func TestBuildFast(t *testing.T) {
// // Specify the directory you want to iterate
// dir := "./testdata"
//
// // Read the directory
// files, err := ioutil.ReadDir(dir)
// if err != nil {
// t.Fatalf("Failed to read dir: %s", err)
// }
//
// // Iterate over the files
// for _, file := range files {
// t.Run(file.Name(), func(t *testing.T) {
// filePath := filepath.Join(dir, file.Name())
//
// // open the file
// f, err := os.Open(filePath)
// if err != nil {
// t.Fatalf("Failed to open file: %s", err)
// }
// defer f.Close()
//
// testBuildFast(t, filePath)
// })
// }
// }
//
// func testBuildFast(b *testing.T, filepath string) {
// // todo: replace with less heavy tree
// archive, err := treearchive.Open(filepath)
// if err != nil {
// require.NoError(b, err)
// }
// defer archive.Close()
//
// importer := exporter.NewTreeImporter(archive.ListStorage(), archive.TreeStorage())
//
// err = importer.Import(false, "")
// if err != nil {
// log.Fatal("can't import the tree", err)
// }
//
// start := time.Now()
// _, err = importer.State()
// if err != nil {
// log.Fatal("can't build state:", err)
// }
// b.Logf("fast build took %s", time.Since(start))
//
// importer2 := exporter.NewTreeImporter(archive.ListStorage(), archive.TreeStorage())
//
// err = importer2.Import(false, "")
// if err != nil {
// log.Fatal("can't import the tree", err)
// }
//
// }
import (
"io/ioutil"
"log"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/anyproto/anytype-heart/core/debug/treearchive"
)
func TestBuildFast(t *testing.T) {
// Specify the directory you want to iterate
dir := "./testdata"
// Read the directory
files, err := ioutil.ReadDir(dir)
if err != nil {
t.Fatalf("Failed to read dir: %s", err)
}
// Iterate over the files
for _, file := range files {
t.Run(file.Name(), func(t *testing.T) {
filePath := filepath.Join(dir, file.Name())
// open the file
f, err := os.Open(filePath)
if err != nil {
t.Fatalf("Failed to open file: %s", err)
}
defer f.Close()
testBuildFast(t, filePath)
})
}
}
func testBuildFast(b *testing.T, filepath string) {
// todo: replace with less heavy tree
archive, err := treearchive.Open(filepath)
if err != nil {
require.NoError(b, err)
}
defer archive.Close()
importer := treearchive.NewTreeImporter(archive.ListStorage(), archive.TreeStorage())
err = importer.Import(false, "")
if err != nil {
log.Fatal("can't import the tree", err)
}
start := time.Now()
_, err = importer.State()
if err != nil {
log.Fatal("can't build state:", err)
}
b.Logf("fast build took %s", time.Since(start))
importer2 := treearchive.NewTreeImporter(archive.ListStorage(), archive.TreeStorage())
err = importer2.Import(false, "")
if err != nil {
log.Fatal("can't import the tree", err)
}
}

View file

@ -47,6 +47,10 @@ func (stx *StoreStateTx) NextOrder(prev string) string {
return lexId.Next(prev)
}
func (stx *StoreStateTx) NextBeforeOrder(prev string, before string) (string, error) {
return lexId.NextBefore(prev, before)
}
func (stx *StoreStateTx) SetOrder(changeId, order string) (err error) {
stx.arena.Reset()
obj := stx.arena.NewObject()

View file

@ -4,8 +4,9 @@ import (
"sync"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
)
const CName = "block.object.resolver"
@ -20,12 +21,12 @@ func New() Resolver {
}
type resolver struct {
objectStore objectstore.ObjectStore
storage storage.ClientStorage
sync.Mutex
}
func (r *resolver) Init(a *app.App) (err error) {
r.objectStore = a.MustComponent(objectstore.CName).(objectstore.ObjectStore)
r.storage = a.MustComponent(spacestorage.CName).(storage.ClientStorage)
return
}
@ -34,5 +35,5 @@ func (r *resolver) Name() (name string) {
}
func (r *resolver) ResolveSpaceID(objectID string) (string, error) {
return r.objectStore.GetSpaceId(objectID)
return r.storage.GetSpaceID(objectID)
}

View file

@ -20,7 +20,7 @@ func Test_Payloads(t *testing.T) {
changePayload := []byte("some")
keys, err := accountdata.NewRandom()
require.NoError(t, err)
aclList, err := list.NewInMemoryDerivedAcl("spaceId", keys)
aclList, err := list.NewTestDerivedAcl("spaceId", keys)
require.NoError(t, err)
timestamp := time.Now().Add(time.Hour).Unix()

View file

@ -102,7 +102,7 @@ func NewTreeSyncer(spaceId string) treesyncer.TreeSyncer {
func (t *treeSyncer) Init(a *app.App) (err error) {
t.isSyncing = true
spaceStorage := app.MustComponent[spacestorage.SpaceStorage](a)
t.spaceSettingsId = spaceStorage.StateStorage().SettingsId()
t.spaceSettingsId = spaceStorage.SpaceSettingsId()
t.treeManager = app.MustComponent[treemanager.TreeManager](a)
t.nodeConf = app.MustComponent[nodeconf.NodeConf](a)
t.syncedTreeRemover = app.MustComponent[SyncedTreeRemover](a)

View file

@ -8,7 +8,6 @@ import (
"time"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/headsync/statestorage/mock_statestorage"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/mock_synctree"
"github.com/anyproto/any-sync/commonspace/object/treemanager/mock_treemanager"
@ -33,7 +32,6 @@ type fixture struct {
nodeConf *mock_nodeconf.MockService
syncStatus *mock_treesyncer.MockSyncedTreeRemover
syncDetailsUpdater *mock_treesyncer.MockSyncDetailsUpdater
stateStorage *mock_statestorage.MockStateStorage
}
func newFixture(t *testing.T, spaceId string) *fixture {
@ -46,9 +44,7 @@ func newFixture(t *testing.T, spaceId string) *fixture {
syncStatus := mock_treesyncer.NewMockSyncedTreeRemover(t)
syncDetailsUpdater := mock_treesyncer.NewMockSyncDetailsUpdater(t)
spaceStorage := mock_spacestorage.NewMockSpaceStorage(ctrl)
stateStorage := mock_statestorage.NewMockStateStorage(ctrl)
spaceStorage.EXPECT().StateStorage().AnyTimes().Return(stateStorage)
stateStorage.EXPECT().SettingsId().AnyTimes().Return("settingsId")
spaceStorage.EXPECT().SpaceSettingsId().Return("spaceSettingsId").AnyTimes()
a := new(app.App)
a.Register(testutil.PrepareMock(context.Background(), a, treeManager)).
@ -68,7 +64,6 @@ func newFixture(t *testing.T, spaceId string) *fixture {
nodeConf: nodeConf,
syncStatus: syncStatus,
syncDetailsUpdater: syncDetailsUpdater,
stateStorage: stateStorage,
}
}

View file

@ -358,7 +358,7 @@ func (s *Service) SpaceInitChat(ctx context.Context, spaceId string) error {
return err
}
if spaceChatExists, err := spc.Storage().HasTree(ctx, chatId); err != nil {
if spaceChatExists, err := spc.Storage().HasTree(chatId); err != nil {
return err
} else if !spaceChatExists {
_, err = s.objectCreator.AddChatDerivedObject(ctx, spc, workspaceId)

View file

@ -276,39 +276,6 @@ func (_c *MockStore_Id_Call) RunAndReturn(run func() string) *MockStore_Id_Call
return _c
}
// MarkSeenHeads provides a mock function with given fields: heads
func (_m *MockStore) MarkSeenHeads(heads []string) {
_m.Called(heads)
}
// MockStore_MarkSeenHeads_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarkSeenHeads'
type MockStore_MarkSeenHeads_Call struct {
*mock.Call
}
// MarkSeenHeads is a helper method to define mock.On call
// - heads []string
func (_e *MockStore_Expecter) MarkSeenHeads(heads interface{}) *MockStore_MarkSeenHeads_Call {
return &MockStore_MarkSeenHeads_Call{Call: _e.mock.On("MarkSeenHeads", heads)}
}
func (_c *MockStore_MarkSeenHeads_Call) Run(run func(heads []string)) *MockStore_MarkSeenHeads_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].([]string))
})
return _c
}
func (_c *MockStore_MarkSeenHeads_Call) Return() *MockStore_MarkSeenHeads_Call {
_c.Call.Return()
return _c
}
func (_c *MockStore_MarkSeenHeads_Call) RunAndReturn(run func([]string)) *MockStore_MarkSeenHeads_Call {
_c.Call.Return(run)
return _c
}
// PushChange provides a mock function with given fields: params
func (_m *MockStore) PushChange(params source.PushChangeParams) (string, error) {
ret := _m.Called(params)

View file

@ -11,6 +11,7 @@ import (
"github.com/anyproto/any-sync/commonspace/object/acl/list"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/updatelistener"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
"github.com/anyproto/any-sync/commonspace/spacestorage"
@ -99,7 +100,7 @@ type BuildOptions struct {
func (b *BuildOptions) BuildTreeOpts() objecttreebuilder.BuildTreeOpts {
return objecttreebuilder.BuildTreeOpts{
Listener: b.Listener,
TreeBuilder: func(treeStorage objecttree.Storage, aclList list.AclList) (objecttree.ObjectTree, error) {
TreeBuilder: func(treeStorage treestorage.TreeStorage, aclList list.AclList) (objecttree.ObjectTree, error) {
ot, err := objecttree.BuildKeyFilterableObjectTree(treeStorage, aclList)
if err != nil {
return nil, err
@ -122,7 +123,7 @@ func (s *service) NewSource(ctx context.Context, space Space, id string, buildOp
if err != nil {
return nil, err
}
err = s.objectStore.BindSpaceId(src.SpaceID(), src.Id())
err = s.storageService.BindSpaceID(src.SpaceID(), src.Id())
if err != nil {
return nil, fmt.Errorf("store space id for object: %w", err)
}
@ -245,7 +246,7 @@ func (s *service) RegisterStaticSource(src Source) error {
s.mu.Lock()
defer s.mu.Unlock()
s.staticIds[src.Id()] = src
err := s.objectStore.BindSpaceId(src.SpaceID(), src.Id())
err := s.storageService.BindSpaceID(src.SpaceID(), src.Id())
if err != nil {
return fmt.Errorf("store space id for object: %w", err)
}

View file

@ -11,7 +11,7 @@ import (
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/synctree"
"github.com/anyproto/any-sync/commonspace/object/tree/synctree/updatelistener"
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/gogo/protobuf/proto"
"github.com/golang/snappy"
@ -33,7 +33,6 @@ type Store interface {
ReadStoreDoc(ctx context.Context, stateStore *storestate.StoreState, onUpdateHook func()) (err error)
PushStoreChange(ctx context.Context, params PushStoreChangeParams) (changeId string, err error)
SetPushChangeHook(onPushChange PushChangeHook)
MarkSeenHeads(heads []string)
}
type PushStoreChangeParams struct {
@ -52,8 +51,6 @@ type store struct {
store *storestate.StoreState
onUpdateHook func()
onPushChange PushChangeHook
diffManager *objecttree.DiffManager
sbType smartblock.SmartBlockType
}
func (s *store) GetFileKeysSnapshot() []*pb.ChangeFileKeys {
@ -64,17 +61,6 @@ func (s *store) SetPushChangeHook(onPushChange PushChangeHook) {
s.onPushChange = onPushChange
}
func (s *store) createDiffManager(ctx context.Context, curTreeHeads, seenHeads []string) (err error) {
buildTree := func(heads []string) (objecttree.ReadableObjectTree, error) {
return s.space.TreeBuilder().BuildHistoryTree(ctx, s.Id(), objecttreebuilder.HistoryTreeOpts{
Heads: heads,
Include: true,
})
}
s.diffManager, err = objecttree.NewDiffManager(seenHeads, curTreeHeads, buildTree, func(ids []string) {})
return
}
func (s *store) ReadDoc(ctx context.Context, receiver ChangeReceiver, empty bool) (doc state.Doc, err error) {
s.receiver = receiver
setter, ok := s.ObjectTree.(synctree.ListenerSetter)
@ -115,10 +101,7 @@ func (s *store) PushChange(params PushChangeParams) (id string, err error) {
func (s *store) ReadStoreDoc(ctx context.Context, storeState *storestate.StoreState, onUpdateHook func()) (err error) {
s.onUpdateHook = onUpdateHook
s.store = storeState
err = s.createDiffManager(ctx, s.source.Tree().Heads(), nil)
if err != nil {
return err
}
tx, err := s.store.NewTx(ctx)
if err != nil {
return
@ -161,11 +144,11 @@ func (s *store) PushStoreChange(ctx context.Context, params PushStoreChangeParam
IsEncrypted: true,
DataType: dataType,
Timestamp: params.Time.Unix(),
}, func(change objecttree.StorageChange) error {
// TODO: get order here
}, func(change *treechangeproto.RawTreeChangeWithId) error {
order := tx.NextOrder(tx.GetMaxOrder())
err = tx.ApplyChangeSet(storestate.ChangeSet{
Id: change.Id,
Order: change.OrderId,
Order: order,
Changes: params.Changes,
Creator: s.accountService.AccountID(),
Timestamp: params.Time.Unix(),
@ -187,14 +170,6 @@ func (s *store) PushStoreChange(ctx context.Context, params PushStoreChangeParam
if err == nil {
s.onUpdateHook()
}
ch, err := s.ObjectTree.GetChange(changeId)
if err != nil {
return "", err
}
s.diffManager.Add(&objecttree.Change{
Id: changeId,
PreviousIds: ch.PreviousIds,
})
return changeId, err
}
@ -211,17 +186,12 @@ func (s *store) update(ctx context.Context, tree objecttree.ObjectTree) error {
return errors.Join(tx.Rollback(), err)
}
err = tx.Commit()
s.diffManager.Update(tree)
if err == nil {
s.onUpdateHook()
}
return err
}
func (s *store) MarkSeenHeads(heads []string) {
s.diffManager.Remove(heads)
}
func (s *store) Update(tree objecttree.ObjectTree) error {
err := s.update(context.Background(), tree)
if err != nil {

View file

@ -24,14 +24,62 @@ type storeApply struct {
}
func (a *storeApply) Apply() (err error) {
maxOrder := a.tx.GetMaxOrder()
isEmpty := maxOrder == ""
iterErr := a.ot.IterateRoot(UnmarshalStoreChange, func(change *objecttree.Change) bool {
// not a new change - remember and continue
if !a.allIsNew && !change.IsNew {
if !a.allIsNew && !change.IsNew && !isEmpty {
a.prevChange = change
a.prevOrder = ""
return true
}
if err = a.applyChange(change); err != nil {
currOrder, curOrdErr := a.tx.GetOrder(change.Id)
if curOrdErr != nil {
if !errors.Is(curOrdErr, storestate.ErrOrderNotFound) {
err = curOrdErr
return false
}
} else {
// change has been handled before
a.prevChange = change
a.prevOrder = currOrder
return true
}
prevOrder, prevOrdErr := a.getPrevOrder()
if prevOrdErr != nil {
if !errors.Is(prevOrdErr, storestate.ErrOrderNotFound) {
err = prevOrdErr
return false
}
if !isEmpty {
// it should not happen, consistency with tree and store broken
err = fmt.Errorf("unable to find previous order")
return false
}
}
if prevOrder == a.tx.GetMaxOrder() {
// insert on top - just create next id
currOrder = a.tx.NextOrder(prevOrder)
} else {
// insert in the middle - find next order and create id between
nextOrder, nextOrdErr := a.findNextOrder(change.Id)
if nextOrdErr != nil {
// it should not happen, consistency with tree and store broken
err = errors.Join(nextOrdErr, fmt.Errorf("unable to find next order"))
return false
}
if currOrder, err = a.tx.NextBeforeOrder(prevOrder, nextOrder); err != nil {
return false
}
}
if err = a.applyChange(change, currOrder); err != nil {
return false
}
a.prevOrder = currOrder
a.prevChange = change
return true
})
if err == nil && iterErr != nil {
@ -40,18 +88,18 @@ func (a *storeApply) Apply() (err error) {
return
}
func (a *storeApply) applyChange(change *objecttree.Change) (err error) {
func (a *storeApply) applyChange(change *objecttree.Change, order string) (err error) {
storeChange, ok := change.Model.(*pb.StoreChange)
if !ok {
// if it is root
if _, ok := change.Model.(*treechangeproto.TreeChangeInfo); ok {
return a.tx.SetOrder(change.Id, change.OrderId)
return a.tx.SetOrder(change.Id, order)
}
return fmt.Errorf("unexpected change content type: %T", change.Model)
}
set := storestate.ChangeSet{
Id: change.Id,
Order: change.OrderId,
Order: order,
Changes: storeChange.ChangeSet,
Creator: change.Identity.Account(),
Timestamp: change.Timestamp,
@ -63,3 +111,56 @@ func (a *storeApply) applyChange(change *objecttree.Change) (err error) {
}
return err
}
func (a *storeApply) getPrevOrder() (order string, err error) {
if a.prevOrder != "" {
return a.prevOrder, nil
}
if a.prevChange == nil {
return "", nil
}
if order, err = a.tx.GetOrder(a.prevChange.Id); err != nil {
return
}
a.prevOrder = order
return
}
func (a *storeApply) findNextOrder(changeId string) (order string, err error) {
if order = a.findNextInCache(changeId); order != "" {
return
}
a.nextCacheChange = map[string]struct{}{}
iterErr := a.ot.IterateFrom(changeId, UnmarshalStoreChange, func(change *objecttree.Change) bool {
order, err = a.tx.GetOrder(change.Id)
if err != nil {
if errors.Is(err, storestate.ErrOrderNotFound) {
// no order - remember id and move forward
a.nextCacheChange[change.Id] = struct{}{}
return true
} else {
return false
}
}
// order found
a.nextCachedOrder = order
return false
})
if err == nil && iterErr != nil {
return "", iterErr
}
return
}
func (a *storeApply) findNextInCache(changeId string) (order string) {
if a.nextCacheChange == nil {
return ""
}
if _, ok := a.nextCacheChange[changeId]; ok {
return a.nextCachedOrder
}
a.nextCachedOrder = ""
a.nextCacheChange = nil
return ""
}

View file

@ -2,10 +2,12 @@ package source
import (
"context"
"fmt"
"os"
"path/filepath"
"sort"
"testing"
"time"
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-sync/commonspace/object/accountdata"
@ -17,7 +19,6 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"golang.org/x/sys/unix"
"github.com/anyproto/anytype-heart/core/block/editor/storestate"
"github.com/anyproto/anytype-heart/pb"
@ -97,6 +98,90 @@ func TestStoreApply_RealTree(t *testing.T) {
})
}
func TestStoreApply_Apply(t *testing.T) {
t.Run("new tree", func(t *testing.T) {
fx := newMockTreeStoreFx(t)
tx := fx.RequireTx(t)
changes := []*objecttree.Change{
testChange("1", false),
testChange("2", false),
testChange("3", false),
}
fx.ApplyChanges(t, tx, changes...)
require.NoError(t, tx.Commit())
})
t.Run("insert middle", func(t *testing.T) {
fx := newMockTreeStoreFx(t)
tx := fx.RequireTx(t)
changes := []*objecttree.Change{
testChange("1", false),
testChange("2", false),
testChange("3", false),
}
fx.ApplyChanges(t, tx, changes...)
require.NoError(t, tx.Commit())
tx = fx.RequireTx(t)
changes = []*objecttree.Change{
testChange("1", false),
testChange("1.1", true),
testChange("1.2", true),
testChange("1.3", true),
testChange("2", false),
testChange("2.2", true),
testChange("3", false),
}
fx.ExpectTreeFrom("1.1", changes[1:]...)
fx.ExpectTreeFrom("2.2", changes[6:]...)
fx.ApplyChanges(t, tx, changes...)
require.NoError(t, tx.Commit())
})
t.Run("append", func(t *testing.T) {
fx := newMockTreeStoreFx(t)
tx := fx.RequireTx(t)
changes := []*objecttree.Change{
testChange("1", false),
testChange("2", false),
testChange("3", false),
}
fx.ApplyChanges(t, tx, changes...)
require.NoError(t, tx.Commit())
tx = fx.RequireTx(t)
changes = []*objecttree.Change{
testChange("1", false),
testChange("2", false),
testChange("3", false),
testChange("4", true),
testChange("5", true),
testChange("6", true),
}
fx.ApplyChanges(t, tx, changes...)
require.NoError(t, tx.Commit())
})
}
func TestStoreApply_Apply10000(t *testing.T) {
fx := newMockTreeStoreFx(t)
tx := fx.RequireTx(t)
changes := make([]*objecttree.Change, 100000)
for i := range changes {
changes[i] = testChange(fmt.Sprint(i), false)
}
st := time.Now()
applier := &storeApply{
tx: tx,
ot: fx.mockTree,
}
fx.ExpectTree(changes...)
require.NoError(t, applier.Apply())
t.Logf("apply dur: %v;", time.Since(st))
st = time.Now()
require.NoError(t, tx.Commit())
t.Logf("commit dur: %v;", time.Since(st))
}
type storeFx struct {
state *storestate.StoreState
mockTree *mock_objecttree.MockObjectTree
@ -158,6 +243,37 @@ func (fx *storeFx) ApplyChanges(t *testing.T, tx *storestate.StoreStateTx, chang
fx.AssertOrder(t, tx, changes...)
}
func newMockTreeStoreFx(t testing.TB) *storeFx {
tmpDir, err := os.MkdirTemp("", "source_store_*")
require.NoError(t, err)
db, err := anystore.Open(ctx, filepath.Join(tmpDir, "test.db"), nil)
require.NoError(t, err)
ctrl := gomock.NewController(t)
t.Cleanup(func() {
if db != nil {
_ = db.Close()
}
ctrl.Finish()
if tmpDir != "" {
_ = os.RemoveAll(tmpDir)
}
})
state, err := storestate.New(ctx, "source_test", db, storestate.DefaultHandler{Name: "default"})
require.NoError(t, err)
tree := mock_objecttree.NewMockObjectTree(ctrl)
tree.EXPECT().Id().Return("root").AnyTimes()
return &storeFx{
state: state,
mockTree: tree,
db: db,
}
}
func newRealTreeStoreFx(t testing.TB) *storeFx {
tmpDir, err := os.MkdirTemp("", "source_store_*")
require.NoError(t, err)
@ -179,16 +295,14 @@ func newRealTreeStoreFx(t testing.TB) *storeFx {
state, err := storestate.New(ctx, "source_test", db, storestate.DefaultHandler{Name: "default"})
require.NoError(t, err)
aclList, _ := prepareAclList(t)
objTree, err := buildTree(t, aclList)
objTree, err := buildTree(aclList)
require.NoError(t, err)
fx := &storeFx{
state: state,
realTree: objTree,
aclList: aclList,
changeCreator: objecttree.NewMockChangeCreator(func() anystore.DB {
return createStore(ctx, t)
}),
db: db,
state: state,
realTree: objTree,
aclList: aclList,
changeCreator: objecttree.NewMockChangeCreator(),
db: db,
}
tx := fx.RequireTx(t)
defer tx.Rollback()
@ -207,7 +321,6 @@ func testChange(id string, isNew bool) *objecttree.Change {
return &objecttree.Change{
Id: id,
OrderId: id,
IsNew: isNew,
Model: &pb.StoreChange{},
Identity: pub,
@ -217,17 +330,15 @@ func testChange(id string, isNew bool) *objecttree.Change {
func prepareAclList(t testing.TB) (list.AclList, *accountdata.AccountKeys) {
randKeys, err := accountdata.NewRandom()
require.NoError(t, err)
aclList, err := list.NewInMemoryDerivedAcl("spaceId", randKeys)
aclList, err := list.NewTestDerivedAcl("spaceId", randKeys)
require.NoError(t, err, "building acl list should be without error")
return aclList, randKeys
}
func buildTree(t testing.TB, aclList list.AclList) (objecttree.ObjectTree, error) {
changeCreator := objecttree.NewMockChangeCreator(func() anystore.DB {
return createStore(ctx, t)
})
treeStorage := changeCreator.CreateNewTreeStorage(t.(*testing.T), "0", aclList.Head().Id, false)
func buildTree(aclList list.AclList) (objecttree.ObjectTree, error) {
changeCreator := objecttree.NewMockChangeCreator()
treeStorage := changeCreator.CreateNewTreeStorage("0", aclList.Head().Id, false)
tree, err := objecttree.BuildTestableTree(treeStorage, aclList)
if err != nil {
return nil, err
@ -235,22 +346,3 @@ func buildTree(t testing.TB, aclList list.AclList) (objecttree.ObjectTree, error
tree.SetFlusher(objecttree.MarkNewChangeFlusher())
return tree, nil
}
func createStore(ctx context.Context, t testing.TB) anystore.DB {
return createNamedStore(ctx, t, "changes.db")
}
func createNamedStore(ctx context.Context, t testing.TB, name string) anystore.DB {
path := filepath.Join(t.TempDir(), name)
db, err := anystore.Open(ctx, path, nil)
require.NoError(t, err)
t.Cleanup(func() {
err := db.Close()
require.NoError(t, err)
unix.Rmdir(path)
})
return objecttree.TestStore{
DB: db,
Path: path,
}
}

View file

@ -83,13 +83,13 @@ func (c *configFetcher) updateStatus(ctx context.Context) (err error) {
techSpace := c.getter.TechSpace()
res, err := c.client.StatusCheck(ctx, techSpace.Id())
if errors.Is(err, coordinatorproto.ErrSpaceNotExists) {
state, sErr := techSpace.Storage().StateStorage().GetState(ctx)
header, sErr := techSpace.Storage().SpaceHeader()
if sErr != nil {
return sErr
}
payload := coordinatorclient.SpaceSignPayload{
SpaceId: techSpace.Id(),
SpaceHeader: state.SpaceHeader,
SpaceId: header.Id,
SpaceHeader: header.RawHeader,
OldAccount: c.wallet.GetOldAccountKey(),
Identity: c.wallet.GetAccountPrivkey(),
}

View file

@ -1,111 +0,0 @@
package exporter
import (
"context"
"fmt"
anystore "github.com/anyproto/any-store"
"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/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/util/crypto"
"golang.org/x/exp/slices"
)
type DataConverter interface {
Unmarshall(dataType string, decrypted []byte) (any, error)
Marshall(model any) (data []byte, dataType string, err error)
}
func prepareExport(ctx context.Context, readable objecttree.ReadableObjectTree, store anystore.DB) (objecttree.ObjectTree, error) {
headStorage, err := headstorage.New(ctx, store)
if err != nil {
return nil, err
}
acl := readable.AclList()
root := acl.Root()
listStorage, err := list.CreateStorage(ctx, root, headStorage, store)
if err != nil {
return nil, err
}
keys, err := accountdata.NewRandom()
if err != nil {
return nil, err
}
newAcl, err := list.BuildAclListWithIdentity(keys, listStorage, list.NoOpAcceptorVerifier{})
if err != nil {
return nil, err
}
treeStorage, err := objecttree.CreateStorage(ctx, readable.Header(), headStorage, store)
if err != nil {
return nil, err
}
writeTree, err := objecttree.BuildTestableTree(treeStorage, newAcl)
if err != nil {
return nil, err
}
return writeTree, nil
}
type ExportParams struct {
Readable objecttree.ReadableObjectTree
Store anystore.DB
Converter DataConverter
}
func ExportTree(ctx context.Context, params ExportParams) error {
writeTree, err := prepareExport(ctx, params.Readable, params.Store)
if err != nil {
return err
}
var (
changeBuilder = objecttree.NewChangeBuilder(crypto.NewKeyStorage(), writeTree.Header())
converter = params.Converter
changes []*treechangeproto.RawTreeChangeWithId
)
err = writeTree.IterateRoot(
func(change *objecttree.Change, decrypted []byte) (any, error) {
return converter.Unmarshall(change.DataType, decrypted)
},
func(change *objecttree.Change) bool {
if change.Id == writeTree.Id() {
return true
}
var (
data []byte
dataType string
)
data, dataType, err = converter.Marshall(change.Model)
if err != nil {
return false
}
// that means that change is unencrypted
change.ReadKeyId = ""
change.Data = data
change.DataType = dataType
var raw *treechangeproto.RawTreeChangeWithId
raw, err = changeBuilder.Marshall(change)
if err != nil {
return false
}
changes = append(changes, raw)
return true
})
if err != nil {
return err
}
payload := objecttree.RawChangesPayload{
NewHeads: writeTree.Heads(),
RawChanges: changes,
}
res, err := writeTree.AddRawChanges(ctx, payload)
if err != nil {
return err
}
if !slices.Equal(res.Heads, writeTree.Heads()) {
return fmt.Errorf("heads mismatch: %v != %v", res.Heads, writeTree.Heads())
}
return nil
}

View file

@ -1,96 +0,0 @@
package exporter
import (
"context"
"os"
"path/filepath"
"strings"
anystore "github.com/anyproto/any-store"
"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/tree/objecttree"
"github.com/anyproto/anytype-heart/util/ziputil"
)
type ImportResult struct {
List list.AclList
Storage objecttree.Storage
FolderPath string
}
func (i ImportResult) CreateReadableTree(fullTree bool, beforeId string) (objecttree.ReadableObjectTree, error) {
return objecttree.BuildNonVerifiableHistoryTree(objecttree.HistoryTreeParams{
Storage: i.Storage,
AclList: i.List,
Heads: i.Heads(fullTree, beforeId),
IncludeBeforeId: true,
})
}
func (i ImportResult) Heads(fullTree bool, beforeId string) []string {
if fullTree {
return nil
}
return []string{beforeId}
}
func ImportStorage(ctx context.Context, path string) (res ImportResult, err error) {
targetDir := strings.TrimSuffix(path, filepath.Ext(path))
if _, err = os.Stat(targetDir); err == nil {
err = os.RemoveAll(targetDir)
if err != nil {
return
}
}
if err = ziputil.UnzipFolder(path, targetDir); err != nil {
return
}
anyStore, err := anystore.Open(ctx, targetDir, nil)
if err != nil {
return
}
defer anyStore.Close()
var (
aclId string
treeId string
)
headStorage, err := headstorage.New(ctx, anyStore)
if err != nil {
return
}
err = headStorage.IterateEntries(ctx, headstorage.IterOpts{}, func(entry headstorage.HeadsEntry) (bool, error) {
if entry.CommonSnapshot == "" {
aclId = entry.Id
return true, nil
}
treeId = entry.Id
return true, nil
})
if err != nil {
return
}
listStorage, err := list.NewStorage(ctx, aclId, headStorage, anyStore)
if err != nil {
return
}
randomKeys, err := accountdata.NewRandom()
if err != nil {
return
}
acl, err := list.BuildAclListWithIdentity(randomKeys, listStorage, list.NoOpAcceptorVerifier{})
if err != nil {
return
}
treeStorage, err := objecttree.NewStorage(ctx, treeId, headStorage, anyStore)
if err != nil {
return
}
return ImportResult{
List: acl,
Storage: treeStorage,
FolderPath: targetDir,
}, nil
}

View file

@ -0,0 +1,99 @@
package treearchive
import (
"archive/zip"
"encoding/json"
"io/fs"
"os"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/consensus/consensusproto"
"github.com/anyproto/anytype-heart/core/debug/treearchive/zipaclstorage"
"github.com/anyproto/anytype-heart/core/debug/treearchive/ziptreestorage"
)
type ExportedObjectsJson struct {
AclId string `json:"aclId"`
TreeId string `json:"treeId"`
}
type ArchiveWriter struct {
zw *zip.Writer
zf fs.File
treeId string
aclId string
storages []flushableStorage
}
type flushableStorage interface {
FlushStorage() error
}
func NewArchiveWriter(path string) (*ArchiveWriter, error) {
zf, err := os.Create(path)
if err != nil {
return nil, err
}
zw := zip.NewWriter(zf)
return &ArchiveWriter{
zw: zw,
zf: zf,
}, nil
}
func (e *ArchiveWriter) ZipWriter() *zip.Writer {
return e.zw
}
func (e *ArchiveWriter) TreeStorage(root *treechangeproto.RawTreeChangeWithId) (treestorage.TreeStorage, error) {
e.treeId = root.Id
st, err := ziptreestorage.NewZipTreeWriteStorage(root, e.zw)
if err != nil {
return nil, err
}
e.storages = append(e.storages, st.(flushableStorage))
return st, nil
}
func (e *ArchiveWriter) ListStorage(root *consensusproto.RawRecordWithId) (liststorage.ListStorage, error) {
e.aclId = root.Id
st, err := zipaclstorage.NewACLWriteStorage(root, e.zw)
if err != nil {
return nil, err
}
e.storages = append(e.storages, st.(flushableStorage))
return st, nil
}
func (e *ArchiveWriter) Close() (err error) {
for _, st := range e.storages {
err = st.FlushStorage()
if err != nil {
return
}
}
exportedHeader, err := e.zw.CreateHeader(&zip.FileHeader{
Name: "exported.json",
Method: zip.Deflate,
})
if err != nil {
return
}
enc := json.NewEncoder(exportedHeader)
enc.SetIndent("", "\t")
err = enc.Encode(ExportedObjectsJson{
TreeId: e.treeId,
AclId: e.aclId,
})
if err != nil {
return
}
err = e.zw.Close()
if err != nil {
return
}
return e.zf.Close()
}

View file

@ -0,0 +1,91 @@
package treearchive
import (
"archive/zip"
"encoding/json"
"fmt"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/gogo/protobuf/jsonpb"
"github.com/anyproto/anytype-heart/core/debug/treearchive/zipaclstorage"
"github.com/anyproto/anytype-heart/core/debug/treearchive/ziptreestorage"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
)
type TreeArchive interface {
ListStorage() liststorage.ListStorage
TreeStorage() treestorage.TreeStorage
LocalStore() (*model.ObjectInfo, error)
Close() error
}
type treeArchive struct {
listStorage liststorage.ListStorage
treeStorage treestorage.TreeStorage
zr *zip.ReadCloser
}
// Open expects debug tree zip file
// returns TreeArchive that has ListStorage and TreeStorage
func Open(filename string) (tr TreeArchive, err error) {
zr, err := zip.OpenReader(filename)
if err != nil {
return nil, err
}
exported, err := zr.Open("exported.json")
if err != nil {
return
}
defer exported.Close()
expJson := &ExportedObjectsJson{}
if err = json.NewDecoder(exported).Decode(expJson); err != nil {
return
}
listStorage, err := zipaclstorage.NewZipAclReadStorage(expJson.AclId, zr)
if err != nil {
return
}
treeStorage, err := ziptreestorage.NewZipTreeReadStorage(expJson.TreeId, zr)
if err != nil {
return
}
return &treeArchive{
listStorage: listStorage,
treeStorage: treeStorage,
zr: zr,
}, nil
}
func (a *treeArchive) ListStorage() liststorage.ListStorage {
return a.listStorage
}
func (a *treeArchive) TreeStorage() treestorage.TreeStorage {
return a.treeStorage
}
func (a *treeArchive) LocalStore() (*model.ObjectInfo, error) {
for _, f := range a.zr.File {
if f.Name == "localstore.json" {
rd, err := f.Open()
if err != nil {
return nil, err
}
defer rd.Close()
var oi = &model.ObjectInfo{}
if err = jsonpb.Unmarshal(rd, oi); err != nil {
return nil, err
}
return oi, nil
}
}
return nil, fmt.Errorf("block logs file not found")
}
func (a *treeArchive) Close() (err error) {
return a.zr.Close()
}

View file

@ -1,10 +1,13 @@
package exporter
package treearchive
import (
"errors"
"fmt"
"github.com/anyproto/any-sync/commonspace/object/acl/list"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/anytype-heart/core/block/editor/state"
"github.com/anyproto/anytype-heart/core/block/source"
@ -40,18 +43,22 @@ func (m MarshalledJsonChange) MarshalJSON() ([]byte, error) {
type TreeImporter interface {
ObjectTree() objecttree.ReadableObjectTree
State() (*state.State, error)
State() (*state.State, error) // set fullStateChain to true to get full state chain, otherwise only the last state will be returned
Import(fromRoot bool, beforeId string) error
Json() (TreeJson, error)
ChangeAt(idx int) (IdChange, error)
}
type treeImporter struct {
objectTree objecttree.ReadableObjectTree
listStorage liststorage.ListStorage
treeStorage treestorage.TreeStorage
objectTree objecttree.ReadableObjectTree
}
func NewTreeImporter(objectTree objecttree.ReadableObjectTree) TreeImporter {
func NewTreeImporter(listStorage liststorage.ListStorage, treeStorage treestorage.TreeStorage) TreeImporter {
return &treeImporter{
objectTree: objectTree,
listStorage: listStorage,
treeStorage: treeStorage,
}
}
@ -76,6 +83,25 @@ func (t *treeImporter) State() (*state.State, error) {
return st, nil
}
func (t *treeImporter) Import(fullTree bool, beforeId string) (err error) {
aclList, err := list.BuildAclList(t.listStorage, list.NoOpAcceptorVerifier{})
if err != nil {
return
}
var heads []string
if !fullTree {
heads = []string{beforeId}
}
t.objectTree, err = objecttree.BuildNonVerifiableHistoryTree(objecttree.HistoryTreeParams{
TreeStorage: t.treeStorage,
AclList: aclList,
Heads: heads,
IncludeBeforeId: true,
})
return
}
func (t *treeImporter) Json() (treeJson TreeJson, err error) {
treeJson = TreeJson{
Id: t.objectTree.Id(),

View file

@ -0,0 +1,77 @@
package zipaclstorage
import (
"archive/zip"
"context"
"fmt"
"io"
"strings"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/consensus/consensusproto"
)
type zipAclReadStorage struct {
id string
files map[string]*zip.File
}
func NewZipAclReadStorage(id string, zr *zip.ReadCloser) (ls liststorage.ListStorage, err error) {
aclStorage := &zipAclReadStorage{
id: id,
files: map[string]*zip.File{},
}
for _, f := range zr.Reader.File {
if len(f.Name) > len(id) && strings.Contains(f.Name, id) {
split := strings.SplitAfter(id, "/")
last := split[len(split)-1]
aclStorage.files[last] = f
}
}
ls = aclStorage
return
}
func (z *zipAclReadStorage) Id() string {
return z.id
}
func (z *zipAclReadStorage) Root() (*consensusproto.RawRecordWithId, error) {
return z.readRecord(z.id)
}
func (z *zipAclReadStorage) Head() (string, error) {
return z.id, nil
}
func (z *zipAclReadStorage) SetHead(headId string) error {
panic("should not be called")
}
func (z *zipAclReadStorage) GetRawRecord(_ context.Context, id string) (*consensusproto.RawRecordWithId, error) {
return z.readRecord(id)
}
func (z *zipAclReadStorage) AddRawRecord(_ context.Context, _ *consensusproto.RawRecordWithId) (err error) {
panic("should not be called")
}
func (z *zipAclReadStorage) readRecord(id string) (rec *consensusproto.RawRecordWithId, err error) {
file, ok := z.files[id]
if !ok {
err = fmt.Errorf("object not found in storage")
return
}
opened, err := file.Open()
if err != nil {
return
}
defer opened.Close()
buf, err := io.ReadAll(opened)
if err != nil {
return
}
rec = &consensusproto.RawRecordWithId{Payload: buf, Id: id}
return
}

View file

@ -0,0 +1,59 @@
package zipaclstorage
import (
"archive/zip"
"context"
"strings"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/consensus/consensusproto"
)
type zipACLWriteStorage struct {
id string
zw *zip.Writer
}
func NewACLWriteStorage(root *consensusproto.RawRecordWithId, zw *zip.Writer) (ls liststorage.ListStorage, err error) {
ls = &zipACLWriteStorage{
id: root.Id,
zw: zw,
}
err = ls.AddRawRecord(context.Background(), root)
return
}
// nolint:revive
func (z *zipACLWriteStorage) Id() string {
return z.id
}
func (z *zipACLWriteStorage) Root() (*consensusproto.RawRecordWithId, error) {
panic("should not be called")
}
func (z *zipACLWriteStorage) Head() (string, error) {
return z.id, nil
}
func (z *zipACLWriteStorage) SetHead(_ string) error {
// TODO: As soon as our acls are writeable, this should be implemented
panic("should not be called")
}
func (z *zipACLWriteStorage) GetRawRecord(_ context.Context, _ string) (*consensusproto.RawRecordWithId, error) {
panic("should not be called")
}
func (z *zipACLWriteStorage) AddRawRecord(_ context.Context, rec *consensusproto.RawRecordWithId) (err error) {
wr, err := z.zw.Create(strings.Join([]string{z.id, rec.Id}, "/"))
if err != nil {
return
}
_, err = wr.Write(rec.Payload)
return
}
func (z *zipACLWriteStorage) FlushStorage() error {
return nil
}

View file

@ -0,0 +1,116 @@
package ziptreestorage
import (
"archive/zip"
"context"
"encoding/json"
"fmt"
"io"
"strings"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
)
type zipTreeReadStorage struct {
id string
heads []string
files map[string]*zip.File
}
func NewZipTreeReadStorage(id string, zr *zip.ReadCloser) (st treestorage.TreeStorage, err error) {
zrs := &zipTreeReadStorage{
id: id,
heads: nil,
files: map[string]*zip.File{},
}
for _, f := range zr.Reader.File {
if len(f.Name) > len(id) && strings.Contains(f.Name, id) {
split := strings.Split(f.Name, "/")
last := split[len(split)-1]
zrs.files[last] = f
}
}
data, ok := zrs.files["data.json"]
if !ok {
err = fmt.Errorf("no data.json in archive")
return
}
dataOpened, err := data.Open()
if err != nil {
return
}
defer dataOpened.Close()
headsEntry := &HeadsJsonEntry{}
if err = json.NewDecoder(dataOpened).Decode(headsEntry); err != nil {
return
}
zrs.heads = headsEntry.Heads
st = zrs
return
}
func (t *zipTreeReadStorage) GetAllChangeIds() (chs []string, err error) {
return nil, fmt.Errorf("get all change ids should not be called")
}
func (z *zipTreeReadStorage) Id() string {
return z.id
}
func (z *zipTreeReadStorage) Root() (root *treechangeproto.RawTreeChangeWithId, err error) {
return z.readChange(z.id)
}
func (z *zipTreeReadStorage) Heads() ([]string, error) {
return z.heads, nil
}
func (z *zipTreeReadStorage) SetHeads(heads []string) (err error) {
panic("should not be called")
}
func (z *zipTreeReadStorage) AddRawChange(change *treechangeproto.RawTreeChangeWithId) (err error) {
panic("should not be called")
}
func (z *zipTreeReadStorage) AddRawChangesSetHeads(changes []*treechangeproto.RawTreeChangeWithId, heads []string) (err error) {
panic("should not be called")
}
func (z *zipTreeReadStorage) GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error) {
return z.readChange(id)
}
func (z *zipTreeReadStorage) GetAppendRawChange(ctx context.Context, buf []byte, id string) (*treechangeproto.RawTreeChangeWithId, error) {
return z.readChange(id)
}
func (z *zipTreeReadStorage) HasChange(ctx context.Context, id string) (ok bool, err error) {
_, ok = z.files[id]
return
}
func (z *zipTreeReadStorage) Delete() error {
panic("should not be called")
}
func (z *zipTreeReadStorage) readChange(id string) (change *treechangeproto.RawTreeChangeWithId, err error) {
file, ok := z.files[id]
if !ok {
err = fmt.Errorf("object not found in storage")
return
}
opened, err := file.Open()
if err != nil {
return
}
defer opened.Close()
buf, err := io.ReadAll(opened)
if err != nil {
return
}
change = &treechangeproto.RawTreeChangeWithId{RawChange: buf, Id: id}
return
}

View file

@ -0,0 +1,110 @@
package ziptreestorage
import (
"archive/zip"
"context"
"encoding/json"
"fmt"
"strings"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
)
type HeadsJsonEntry struct {
Heads []string `json:"heads"`
RootId string `json:"rootId"`
}
type zipTreeWriteStorage struct {
id string
heads []string
zw *zip.Writer
}
func NewZipTreeWriteStorage(root *treechangeproto.RawTreeChangeWithId, zw *zip.Writer) (st treestorage.TreeStorage, err error) {
z := &zipTreeWriteStorage{
id: root.Id,
zw: zw,
}
err = z.SetHeads([]string{root.Id})
if err != nil {
return
}
err = z.AddRawChange(root)
if err != nil {
return
}
st = z
return
}
func (z *zipTreeWriteStorage) Id() string {
return z.id
}
func (t *zipTreeWriteStorage) GetAllChangeIds() (chs []string, err error) {
return nil, fmt.Errorf("get all change ids should not be called")
}
func (z *zipTreeWriteStorage) Root() (*treechangeproto.RawTreeChangeWithId, error) {
panic("should not be implemented")
}
func (z *zipTreeWriteStorage) Heads() ([]string, error) {
return z.heads, nil
}
func (z *zipTreeWriteStorage) SetHeads(heads []string) (err error) {
z.heads = heads
return
}
func (z *zipTreeWriteStorage) AddRawChange(change *treechangeproto.RawTreeChangeWithId) (err error) {
wr, err := z.zw.Create(strings.Join([]string{z.id, change.Id}, "/"))
if err != nil {
return
}
_, err = wr.Write(change.RawChange)
return
}
func (z *zipTreeWriteStorage) AddRawChangesSetHeads(changes []*treechangeproto.RawTreeChangeWithId, heads []string) (err error) {
for _, ch := range changes {
err = z.AddRawChange(ch)
if err != nil {
return
}
}
return z.SetHeads(heads)
}
func (z *zipTreeWriteStorage) GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error) {
panic("should not be called")
}
func (z *zipTreeWriteStorage) GetAppendRawChange(ctx context.Context, buf []byte, id string) (*treechangeproto.RawTreeChangeWithId, error) {
panic("should not be called")
}
func (z *zipTreeWriteStorage) HasChange(ctx context.Context, id string) (ok bool, err error) {
panic("should not be called")
}
func (z *zipTreeWriteStorage) Delete() error {
panic("should not be called")
}
func (z *zipTreeWriteStorage) FlushStorage() (err error) {
chw, err := z.zw.CreateHeader(&zip.FileHeader{
Name: strings.Join([]string{z.id, "data.json"}, "/"),
Method: zip.Deflate,
})
enc := json.NewEncoder(chw)
enc.SetIndent("", "\t")
err = enc.Encode(HeadsJsonEntry{
Heads: z.heads,
RootId: z.id,
})
return
}

View file

@ -1,6 +1,7 @@
package debug
import (
"archive/zip"
"bytes"
"context"
"fmt"
@ -10,15 +11,14 @@ import (
"path/filepath"
"time"
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-sync/commonspace/object/tree/exporter"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/anytype-heart/core/debug/exporter"
"github.com/anyproto/anytype-heart/core/debug/treearchive"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/util/anonymize"
"github.com/anyproto/anytype-heart/util/pbtypes"
"github.com/anyproto/anytype-heart/util/ziputil"
)
type treeExporter struct {
@ -26,78 +26,66 @@ type treeExporter struct {
s objectstore.ObjectStore
anonymized bool
id domain.FullID
zw *zip.Writer
}
func (e *treeExporter) Export(ctx context.Context, path string, tree objecttree.ReadableObjectTree) (filename string, err error) {
var (
exportDirPath = filepath.Join(path, fmt.Sprintf("at.dbg.%s.%s", e.id, time.Now().Format("20060102.150405.99")))
dbPath = filepath.Join(exportDirPath, "db")
localStorePath = filepath.Join(exportDirPath, "localstore.json")
logPath = filepath.Join(exportDirPath, "creation.log")
)
filename = exportDirPath + ".zip"
err = os.MkdirAll(exportDirPath, 0755)
filename = filepath.Join(path, fmt.Sprintf("at.dbg.%s.%s.zip", e.id, time.Now().Format("20060102.150405.99")))
archiveWriter, err := treearchive.NewArchiveWriter(filename)
if err != nil {
return
}
defer func() {
_ = os.RemoveAll(exportDirPath)
}()
err = os.Mkdir(dbPath, 0755)
if err != nil {
return
}
anyStore, err := anystore.Open(ctx, dbPath, nil)
if err != nil {
return
}
defer func() {
_ = anyStore.Close()
}()
exportParams := exporter.ExportParams{
Readable: tree,
Store: anyStore,
Converter: &changeDataConverter{anonymize: e.anonymized},
}
st := time.Now()
err = exporter.ExportTree(ctx, exportParams)
if err != nil {
return
}
err = anyStore.Checkpoint(ctx, true)
if err != nil {
return
defer archiveWriter.Close()
e.zw = archiveWriter.ZipWriter()
params := exporter.TreeExporterParams{
ListStorageExporter: archiveWriter,
TreeStorageExporter: archiveWriter,
DataConverter: &changeDataConverter{anonymize: e.anonymized},
}
anySyncExporter := exporter.NewTreeExporter(params)
logBuf := bytes.NewBuffer(nil)
e.log = stdlog.New(io.MultiWriter(logBuf, os.Stderr), "", stdlog.LstdFlags)
e.log.Printf("exporting tree and acl")
st := time.Now()
err = anySyncExporter.ExportUnencrypted(tree)
if err != nil {
e.log.Printf("export tree in zip error: %v", err)
return
}
e.log.Printf("exported tree for a %v", time.Since(st))
data, err := e.s.SpaceIndex(e.id.SpaceID).GetInfosByIds([]string{e.id.ObjectID})
if err != nil {
e.log.Printf("can't fetch localstore info: %v", err)
} else {
if len(data) > 0 {
// TODO: [storage] fix details, take from main
// data[0].Details = transform(data[0].Details, e.anonymized, anonymize.Struct)
data[0].Details = transform(data[0].Details, e.anonymized, anonymize.Details)
data[0].Snippet = transform(data[0].Snippet, e.anonymized, anonymize.Text)
for i, r := range data[0].Relations {
data[0].Relations[i] = transform(r, e.anonymized, anonymize.Relation)
}
osData := pbtypes.Sprint(data[0].ToProto())
er := os.WriteFile(localStorePath, []byte(osData), 0600)
lsWr, er := e.zw.Create("localstore.json")
if er != nil {
e.log.Printf("localstore.json write error: %v", err)
e.log.Printf("create file in zip error: %v", er)
} else {
e.log.Printf("localstore.json wrote")
if _, err := lsWr.Write([]byte(osData)); err != nil {
e.log.Printf("localstore.json write error: %v", err)
} else {
e.log.Printf("localstore.json wrote")
}
}
} else {
e.log.Printf("no data in objectstore")
e.log.Printf("not data in objectstore")
}
}
err = os.WriteFile(logPath, logBuf.Bytes(), 0600)
logW, err := e.zw.Create("creation.log")
if err != nil {
return
}
err = ziputil.ZipFolder(exportDirPath, filename)
io.Copy(logW, logBuf)
return
}

View file

@ -45,6 +45,7 @@ func NewIndexerFixture(t *testing.T) *IndexerFixture {
walletService := mock_wallet.NewMockWallet(t)
walletService.EXPECT().Name().Return(wallet.CName)
objectStore := objectstore.NewStoreFixture(t)
clientStorage := mock_storage.NewMockClientStorage(t)

View file

@ -143,7 +143,7 @@ func (i *indexer) Index(info smartblock.DocInfo, options ...smartblock.IndexOpti
i.lock.Lock()
spaceInd, ok := i.spaceIndexers[info.Space.Id()]
if !ok {
spaceInd = newSpaceIndexer(i.runCtx, i.store.SpaceIndex(info.Space.Id()), i.store)
spaceInd = newSpaceIndexer(i.runCtx, i.store.SpaceIndex(info.Space.Id()), i.store, i.storageService)
i.spaceIndexers[info.Space.Id()] = spaceInd
}
i.lock.Unlock()

View file

@ -5,6 +5,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock/smarttest"
@ -49,6 +50,7 @@ func TestIndexer(t *testing.T) {
)))
smartTest.SetType(coresb.SmartBlockTypePage)
indexerFx.storageServiceFx.EXPECT().BindSpaceID(mock.Anything, mock.Anything).Return(nil)
indexerFx.store.SpaceIndex("spaceId1").SaveLastIndexedHeadsHash(ctx, "objectId1", "7f40bc2814f5297818461f889780a870ea033fe64c5a261117f2b662515a3dba")
// when
@ -76,6 +78,7 @@ func TestIndexer(t *testing.T) {
)))
smartTest.SetType(coresb.SmartBlockTypePage)
indexerFx.storageServiceFx.EXPECT().BindSpaceID(mock.Anything, mock.Anything).Return(nil)
indexerFx.store.SpaceIndex("spaceId1").SaveLastIndexedHeadsHash(ctx, "objectId1", "randomHash")
// when
@ -104,6 +107,7 @@ func TestIndexer(t *testing.T) {
)))
smartTest.SetType(coresb.SmartBlockTypePage)
indexerFx.storageServiceFx.EXPECT().BindSpaceID(mock.Anything, mock.Anything).Return(nil)
indexerFx.store.SpaceIndex("spaceId1").SaveLastIndexedHeadsHash(ctx, "objectId1", "7f40bc2814f5297818461f889780a870ea033fe64c5a261117f2b662515a3dba")
// when

View file

@ -7,7 +7,6 @@ import (
"time"
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-sync/commonspace/headsync/headstorage"
"go.uber.org/zap"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock"
@ -52,7 +51,7 @@ const (
)
type allDeletedIdsProvider interface {
AllDeletedTreeIds(ctx context.Context) (ids []string, err error)
AllDeletedTreeIds() (ids []string, err error)
}
func (i *indexer) buildFlags(spaceID string) (reindexFlags, error) {
@ -248,7 +247,11 @@ func (i *indexer) addSyncDetails(space clientspace.Space) {
func (i *indexer) reindexDeletedObjects(space clientspace.Space) error {
store := i.store.SpaceIndex(space.Id())
allIds, err := space.Storage().AllDeletedTreeIds(i.runCtx)
storage, ok := space.Storage().(allDeletedIdsProvider)
if !ok {
return fmt.Errorf("space storage doesn't implement allDeletedIdsProvider")
}
allIds, err := storage.AllDeletedTreeIds()
if err != nil {
return fmt.Errorf("get deleted tree ids: %w", err)
}
@ -437,34 +440,35 @@ func (i *indexer) reindexIDs(ctx context.Context, space smartblock.Space, reinde
func (i *indexer) reindexOutdatedObjects(ctx context.Context, space clientspace.Space) (toReindex, success int, err error) {
store := i.store.SpaceIndex(space.Id())
var entries []headstorage.HeadsEntry
err = space.Storage().HeadStorage().IterateEntries(ctx, headstorage.IterOpts{}, func(entry headstorage.HeadsEntry) (bool, error) {
// skipping Acl
if entry.CommonSnapshot != "" {
entries = append(entries, entry)
}
return true, nil
})
if err != nil {
return
}
tids := space.StoredIds()
var idsToReindex []string
for _, entry := range entries {
id := entry.Id
for _, tid := range tids {
logErr := func(err error) {
log.With("tree", entry.Id).Errorf("reindexOutdatedObjects failed to get tree to reindex: %s", err)
log.With("tree", tid).Errorf("reindexOutdatedObjects failed to get tree to reindex: %s", err)
}
lastHash, err := store.GetLastIndexedHeadsHash(ctx, id)
lastHash, err := store.GetLastIndexedHeadsHash(ctx, tid)
if err != nil {
logErr(err)
continue
}
hh := headsHash(entry.Heads)
info, err := space.Storage().TreeStorage(tid)
if err != nil {
logErr(err)
continue
}
heads, err := info.Heads()
if err != nil {
logErr(err)
continue
}
hh := headsHash(heads)
if lastHash != hh {
if lastHash != "" {
log.With("tree", id).Warnf("not equal indexed heads hash: %s!=%s (%d logs)", lastHash, hh, len(entry.Heads))
log.With("tree", tid).Warnf("not equal indexed heads hash: %s!=%s (%d logs)", lastHash, hh, len(heads))
}
idsToReindex = append(idsToReindex, id)
idsToReindex = append(idsToReindex, tid)
}
}

View file

@ -4,12 +4,9 @@ import (
"context"
"testing"
"github.com/anyproto/any-sync/commonspace/headsync/headstorage"
"github.com/anyproto/any-sync/commonspace/headsync/headstorage/mock_headstorage"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"github.com/anyproto/anytype-heart/core/block/editor"
"github.com/anyproto/anytype-heart/core/block/editor/smartblock/smarttest"
@ -25,7 +22,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/clientspace"
mock_space "github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace"
"github.com/anyproto/anytype-heart/space/spacecore/storage/anystorage/mock_anystorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/mock_storage"
)
@ -58,6 +54,7 @@ func TestReindexMarketplaceSpace(t *testing.T) {
virtualSpace := getMockSpace(indexerFx)
storage := mock_storage.NewMockClientStorage(t)
storage.EXPECT().BindSpaceID(mock.Anything, mock.Anything).Return(nil)
indexerFx.storageService = storage
// when
@ -95,6 +92,7 @@ func TestReindexMarketplaceSpace(t *testing.T) {
require.NoError(t, err)
storage := mock_storage.NewMockClientStorage(t)
storage.EXPECT().BindSpaceID(mock.Anything, mock.Anything).Return(nil)
fx.storageService = storage
// when
@ -130,6 +128,7 @@ func TestReindexMarketplaceSpace(t *testing.T) {
require.NoError(t, err)
storage := mock_storage.NewMockClientStorage(t)
storage.EXPECT().BindSpaceID(mock.Anything, mock.Anything).Return(nil)
fx.storageService = storage
fx.sourceFx.EXPECT().IDsListerBySmartblockType(mock.Anything, mock.Anything).Return(idsLister{Ids: []string{}}, nil).Maybe()
@ -190,15 +189,6 @@ func TestIndexer_ReindexSpace_RemoveParticipants(t *testing.T) {
err = fx.objectStore.SaveChecksums(spaceId2, &checksums)
require.NoError(t, err)
ctrl := gomock.NewController(t)
headStorage := mock_headstorage.NewMockHeadStorage(ctrl)
storage := mock_anystorage.NewMockClientSpaceStorage(t)
storage.EXPECT().HeadStorage().Return(headStorage)
headStorage.EXPECT().IterateEntries(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().
DoAndReturn(func(ctx context.Context, opts headstorage.IterOpts, entryIter headstorage.EntryIterator) error {
return nil
})
for _, space := range []string{spaceId1, spaceId2} {
t.Run("reindex - participants deleted - when flag doesn't match", func(t *testing.T) {
// given
@ -206,7 +196,7 @@ func TestIndexer_ReindexSpace_RemoveParticipants(t *testing.T) {
spc := mock_space.NewMockSpace(t)
spc.EXPECT().Id().Return(space)
spc.EXPECT().Storage().Return(storage)
spc.EXPECT().StoredIds().Return([]string{}).Maybe()
fx.sourceFx.EXPECT().IDsListerBySmartblockType(mock.Anything, mock.Anything).Return(idsLister{Ids: []string{}}, nil).Maybe()
// when
@ -285,21 +275,12 @@ func TestIndexer_ReindexSpace_EraseLinks(t *testing.T) {
require.NoError(t, err)
err = fx.objectStore.SaveChecksums(spaceId2, &checksums)
require.NoError(t, err)
ctrl := gomock.NewController(t)
headStorage := mock_headstorage.NewMockHeadStorage(ctrl)
storage := mock_anystorage.NewMockClientSpaceStorage(t)
storage.EXPECT().HeadStorage().Return(headStorage)
headStorage.EXPECT().IterateEntries(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().
DoAndReturn(func(ctx context.Context, opts headstorage.IterOpts, entryIter headstorage.EntryIterator) error {
return nil
})
t.Run("links from archive and home are deleted", func(t *testing.T) {
// given
favs := []string{"fav1", "fav2"}
trash := []string{"trash1", "trash2"}
store := fx.store.SpaceIndex("space1")
err = store.UpdateObjectLinks(ctx, "home", favs)
require.NoError(t, err)
err = store.UpdateObjectLinks(ctx, "bin", trash)
@ -313,7 +294,7 @@ func TestIndexer_ReindexSpace_EraseLinks(t *testing.T) {
space1 := mock_space.NewMockSpace(t)
space1.EXPECT().Id().Return(spaceId1)
space1.EXPECT().Storage().Return(storage)
space1.EXPECT().StoredIds().Return([]string{}).Maybe()
// when
err = fx.ReindexSpace(space1)
@ -354,7 +335,8 @@ func TestIndexer_ReindexSpace_EraseLinks(t *testing.T) {
space1 := mock_space.NewMockSpace(t)
space1.EXPECT().Id().Return(spaceId2)
space1.EXPECT().Storage().Return(storage)
space1.EXPECT().StoredIds().Return([]string{}).Maybe()
// when
err = fx.ReindexSpace(space1)
assert.NoError(t, err)

View file

@ -15,21 +15,24 @@ import (
"github.com/anyproto/anytype-heart/metrics"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
)
type spaceIndexer struct {
runCtx context.Context
spaceIndex spaceindex.Store
objectStore objectstore.ObjectStore
batcher *mb.MB[indexTask]
runCtx context.Context
spaceIndex spaceindex.Store
objectStore objectstore.ObjectStore
storageService storage.ClientStorage
batcher *mb.MB[indexTask]
}
func newSpaceIndexer(runCtx context.Context, spaceIndex spaceindex.Store, objectStore objectstore.ObjectStore) *spaceIndexer {
func newSpaceIndexer(runCtx context.Context, spaceIndex spaceindex.Store, objectStore objectstore.ObjectStore, storageService storage.ClientStorage) *spaceIndexer {
ind := &spaceIndexer{
runCtx: runCtx,
spaceIndex: spaceIndex,
objectStore: objectStore,
batcher: mb.New[indexTask](100),
runCtx: runCtx,
spaceIndex: spaceIndex,
objectStore: objectStore,
storageService: storageService,
batcher: mb.New[indexTask](100),
}
go ind.indexBatchLoop()
return ind
@ -122,7 +125,7 @@ func (i *spaceIndexer) index(ctx context.Context, info smartblock.DocInfo, optio
for _, o := range options {
o(opts)
}
err := i.objectStore.BindSpaceId(info.Space.Id(), info.Id)
err := i.storageService.BindSpaceID(info.Space.Id(), info.Id)
if err != nil {
log.Error("failed to bind space id", zap.Error(err), zap.String("id", info.Id))
return err

View file

@ -189,7 +189,7 @@ func (s *service) publishToPublishServer(ctx context.Context, spaceId, pageId, u
return err
}
version, err := s.evaluateDocumentVersion(ctx, spc, pageId, joinSpace)
version, err := s.evaluateDocumentVersion(spc, pageId, joinSpace)
if err != nil {
return err
}
@ -380,12 +380,12 @@ func (s *service) extractInviteLink(ctx context.Context, spaceId string, joinSpa
return inviteLink, nil
}
func (s *service) evaluateDocumentVersion(ctx context.Context, spc clientspace.Space, pageId string, joinSpace bool) (string, error) {
treeStorage, err := spc.Storage().TreeStorage(ctx, pageId)
func (s *service) evaluateDocumentVersion(spc clientspace.Space, pageId string, joinSpace bool) (string, error) {
treeStorage, err := spc.Storage().TreeStorage(pageId)
if err != nil {
return "", err
}
heads, err := treeStorage.Heads(ctx)
heads, err := treeStorage.Heads()
if err != nil {
return "", err
}

View file

@ -11,17 +11,15 @@ import (
"path/filepath"
"testing"
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree/mock_objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
"github.com/anyproto/any-sync/consensus/consensusproto"
"github.com/anyproto/anytype-publish-server/publishclient/publishapi"
"github.com/gogo/protobuf/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"golang.org/x/sys/unix"
"github.com/anyproto/anytype-heart/core/anytype/account/mock_account"
"github.com/anyproto/anytype-heart/core/block/cache/mock_cache"
@ -48,7 +46,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/threads"
"github.com/anyproto/anytype-heart/space/clientspace/mock_clientspace"
"github.com/anyproto/anytype-heart/space/mock_space"
"github.com/anyproto/anytype-heart/space/spacecore/storage/anystorage/mock_anystorage"
"github.com/anyproto/anytype-heart/space/spacecore/typeprovider/mock_typeprovider"
"github.com/anyproto/anytype-heart/tests/testutil"
"github.com/anyproto/anytype-heart/util/pbtypes"
@ -138,7 +135,7 @@ func TestPublish(t *testing.T) {
t.Run("success", func(t *testing.T) {
// given
isPersonal := true
spaceService, err := prepareSpaceService(t, isPersonal)
spaceService, err := prepaeSpaceService(t, isPersonal)
objectTypeId := "customObjectType"
expectedUri := "test"
@ -181,7 +178,7 @@ func TestPublish(t *testing.T) {
t.Run("success with space sharing", func(t *testing.T) {
// given
isPersonal := false
spaceService, err := prepareSpaceService(t, isPersonal)
spaceService, err := prepaeSpaceService(t, isPersonal)
objectTypeId := "customObjectType"
expectedUri := "test"
@ -234,7 +231,7 @@ func TestPublish(t *testing.T) {
})
t.Run("success with space sharing - invite not exists", func(t *testing.T) {
isPersonal := false
spaceService, err := prepareSpaceService(t, isPersonal)
spaceService, err := prepaeSpaceService(t, isPersonal)
objectTypeId := "customObjectType"
expectedUri := "test"
@ -282,7 +279,7 @@ func TestPublish(t *testing.T) {
t.Run("success for member", func(t *testing.T) {
// given
isPersonal := false
spaceService, err := prepareSpaceService(t, isPersonal)
spaceService, err := prepaeSpaceService(t, isPersonal)
objectTypeId := "customObjectType"
expectedUri := "test"
@ -340,7 +337,7 @@ func TestPublish(t *testing.T) {
t.Run("internal error", func(t *testing.T) {
// given
isPersonal := true
spaceService, err := prepareSpaceService(t, isPersonal)
spaceService, err := prepaeSpaceService(t, isPersonal)
objectTypeId := "customObjectType"
expectedUri := "test"
@ -663,22 +660,28 @@ func TestService_PublishingList(t *testing.T) {
})
}
var ctx = context.Background()
func prepareSpaceService(t *testing.T, isPersonal bool) (*mock_space.MockService, error) {
func prepaeSpaceService(t *testing.T, isPersonal bool) (*mock_space.MockService, error) {
spaceService := mock_space.NewMockService(t)
space := mock_clientspace.NewMockSpace(t)
ctrl := gomock.NewController(t)
space.EXPECT().IsPersonal().Return(isPersonal)
space.EXPECT().Id().Return(spaceId)
st := mock_anystorage.NewMockClientSpaceStorage(t)
mockSt := mock_objecttree.NewMockStorage(ctrl)
st.EXPECT().TreeStorage(mock.Anything, mock.Anything).Return(mockSt, nil)
mockSt.EXPECT().Heads(gomock.Any()).Return([]string{"heads"}, nil)
space.EXPECT().Storage().Return(st)
storage, err := spacestorage.NewInMemorySpaceStorage(spacestorage.SpaceStorageCreatePayload{
AclWithId: &consensusproto.RawRecordWithId{Id: "aclId"},
SpaceHeaderWithId: &spacesyncproto.RawSpaceHeaderWithId{Id: spaceId},
SpaceSettingsWithId: &treechangeproto.RawTreeChangeWithId{Id: "settingsId"},
},
)
assert.NoError(t, err)
objectHeads := []string{"heads"}
_, err = storage.CreateTreeStorage(treestorage.TreeStorageCreatePayload{
RootRawChange: &treechangeproto.RawTreeChangeWithId{Id: objectId},
Heads: objectHeads,
})
assert.NoError(t, err)
space.EXPECT().Storage().Return(storage)
spaceService.EXPECT().Get(context.Background(), spaceId).Return(space, nil)
return spaceService, nil
return spaceService, err
}
func prepareExporter(t *testing.T, objectTypeId string, spaceService *mock_space.MockService) export.Export {
@ -892,22 +895,3 @@ func createTestFile(fileName string, size int64) error {
file.Close()
return nil
}
func createStore(ctx context.Context, t testing.TB) anystore.DB {
return createNamedStore(ctx, t, "changes.db")
}
func createNamedStore(ctx context.Context, t testing.TB, name string) anystore.DB {
path := filepath.Join(t.TempDir(), name)
db, err := anystore.Open(ctx, path, nil)
require.NoError(t, err)
t.Cleanup(func() {
err := db.Close()
require.NoError(t, err)
unix.Rmdir(path)
})
return objecttree.TestStore{
DB: db,
Path: path,
}
}

View file

@ -94,7 +94,7 @@ func (s *syncStatusService) Init(a *app.App) (err error) {
s.updateIntervalSecs = syncUpdateInterval
s.updateTimeout = syncTimeout
s.spaceId = sharedState.SpaceId
s.spaceSettingsId = spaceStorage.StateStorage().SettingsId()
s.spaceSettingsId = spaceStorage.SpaceSettingsId()
s.periodicSync = periodicsync.NewPeriodicSync(
s.updateIntervalSecs,
s.updateTimeout,

View file

@ -5,7 +5,6 @@ import (
"testing"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/headsync/statestorage/mock_statestorage"
"github.com/anyproto/any-sync/commonspace/spacestate"
"github.com/anyproto/any-sync/commonspace/spacestorage/mock_spacestorage"
"github.com/anyproto/any-sync/nodeconf/mock_nodeconf"
@ -175,9 +174,7 @@ func newFixture(t *testing.T, spaceId string) *fixture {
ctrl := gomock.NewController(t)
service := mock_nodeconf.NewMockService(ctrl)
storage := mock_spacestorage.NewMockSpaceStorage(ctrl)
stateStorage := mock_statestorage.NewMockStateStorage(ctrl)
storage.EXPECT().StateStorage().AnyTimes().Return(stateStorage)
stateStorage.EXPECT().SettingsId().AnyTimes().Return(testSpaceSettingsId)
storage.EXPECT().SpaceSettingsId().Return(testSpaceSettingsId)
spaceState := &spacestate.SpaceState{SpaceId: spaceId}
config := &config.Config{}

View file

@ -24,16 +24,10 @@ func (mw *Middleware) getResponseEvent(ctx session.Context) *pb.ResponseEvent {
type errToCodeTuple[T ~int32] struct {
err error
code T
checkErrorType any
}
func errToCode[T ~int32](err error, code T) errToCodeTuple[T] {
return errToCodeTuple[T]{err: err, code: code}
}
func errTypeToCode[T ~int32](errTypeProto any, code T) errToCodeTuple[T] {
return errToCodeTuple[T]{code: code, checkErrorType: errTypeProto}
return errToCodeTuple[T]{err, code}
}
func mapErrorCode[T ~int32](err error, mappings ...errToCodeTuple[T]) T {
@ -41,15 +35,8 @@ func mapErrorCode[T ~int32](err error, mappings ...errToCodeTuple[T]) T {
return 0
}
for _, m := range mappings {
if m.err != nil {
if errors.Is(err, m.err) {
return m.code
}
}
if m.checkErrorType != nil {
if errors.As(err, m.checkErrorType) {
return m.code
}
if errors.Is(err, m.err) {
return m.code
}
}
// Unknown error

View file

@ -8,20 +8,12 @@ import (
"github.com/stretchr/testify/assert"
)
type testErrorType struct {
}
func (t testErrorType) Error() string {
return "error type!"
}
type testCode int32
func TestErrorCodeMapping(t *testing.T) {
err1 := errors.New("err1")
err2 := errors.New("err2")
err3 := errors.New("err3")
err4 := testErrorType{}
wrapped1 := errors.Join(err1, fmt.Errorf("description of error"))
wrapped2 := fmt.Errorf("description of error: %w", err2)
@ -31,14 +23,12 @@ func TestErrorCodeMapping(t *testing.T) {
errToCode(err1, testCode(2)),
errToCode(err2, testCode(3)),
errToCode(err3, testCode(4)),
errTypeToCode(&testErrorType{}, testCode(5)),
)
}
assert.Equal(t, testCode(0), mapper(nil))
assert.Equal(t, testCode(1), mapper(errors.New("unknown error")))
assert.Equal(t, testCode(2), mapper(wrapped1))
assert.Equal(t, testCode(3), mapper(wrapped2))
assert.Equal(t, testCode(4), mapper(err3))
assert.Equal(t, testCode(5), mapper(err4))
assert.True(t, 0 == mapper(nil))
assert.True(t, 1 == mapper(errors.New("unknown error")))
assert.True(t, 2 == mapper(wrapped1))
assert.True(t, 3 == mapper(wrapped2))
assert.True(t, 4 == mapper(err3))
}

View file

@ -87,14 +87,6 @@
- [Rpc.Account.LocalLink.SolveChallenge.Request](#anytype-Rpc-Account-LocalLink-SolveChallenge-Request)
- [Rpc.Account.LocalLink.SolveChallenge.Response](#anytype-Rpc-Account-LocalLink-SolveChallenge-Response)
- [Rpc.Account.LocalLink.SolveChallenge.Response.Error](#anytype-Rpc-Account-LocalLink-SolveChallenge-Response-Error)
- [Rpc.Account.Migrate](#anytype-Rpc-Account-Migrate)
- [Rpc.Account.Migrate.Request](#anytype-Rpc-Account-Migrate-Request)
- [Rpc.Account.Migrate.Response](#anytype-Rpc-Account-Migrate-Response)
- [Rpc.Account.Migrate.Response.Error](#anytype-Rpc-Account-Migrate-Response-Error)
- [Rpc.Account.MigrateCancel](#anytype-Rpc-Account-MigrateCancel)
- [Rpc.Account.MigrateCancel.Request](#anytype-Rpc-Account-MigrateCancel-Request)
- [Rpc.Account.MigrateCancel.Response](#anytype-Rpc-Account-MigrateCancel-Response)
- [Rpc.Account.MigrateCancel.Response.Error](#anytype-Rpc-Account-MigrateCancel-Response-Error)
- [Rpc.Account.Move](#anytype-Rpc-Account-Move)
- [Rpc.Account.Move.Request](#anytype-Rpc-Account-Move-Request)
- [Rpc.Account.Move.Response](#anytype-Rpc-Account-Move-Response)
@ -1306,8 +1298,6 @@
- [Rpc.Account.EnableLocalNetworkSync.Response.Error.Code](#anytype-Rpc-Account-EnableLocalNetworkSync-Response-Error-Code)
- [Rpc.Account.LocalLink.NewChallenge.Response.Error.Code](#anytype-Rpc-Account-LocalLink-NewChallenge-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)
- [Rpc.Account.Move.Response.Error.Code](#anytype-Rpc-Account-Move-Response-Error-Code)
- [Rpc.Account.NetworkMode](#anytype-Rpc-Account-NetworkMode)
- [Rpc.Account.Recover.Response.Error.Code](#anytype-Rpc-Account-Recover-Response-Error-Code)
@ -2043,8 +2033,6 @@
| WorkspaceSetInfo | [Rpc.Workspace.SetInfo.Request](#anytype-Rpc-Workspace-SetInfo-Request) | [Rpc.Workspace.SetInfo.Response](#anytype-Rpc-Workspace-SetInfo-Response) | |
| WorkspaceExport | [Rpc.Workspace.Export.Request](#anytype-Rpc-Workspace-Export-Request) | [Rpc.Workspace.Export.Response](#anytype-Rpc-Workspace-Export-Response) | |
| AccountRecover | [Rpc.Account.Recover.Request](#anytype-Rpc-Account-Recover-Request) | [Rpc.Account.Recover.Response](#anytype-Rpc-Account-Recover-Response) | Account *** |
| AccountMigrate | [Rpc.Account.Migrate.Request](#anytype-Rpc-Account-Migrate-Request) | [Rpc.Account.Migrate.Response](#anytype-Rpc-Account-Migrate-Response) | |
| AccountMigrateCancel | [Rpc.Account.MigrateCancel.Request](#anytype-Rpc-Account-MigrateCancel-Request) | [Rpc.Account.MigrateCancel.Response](#anytype-Rpc-Account-MigrateCancel-Response) | |
| AccountCreate | [Rpc.Account.Create.Request](#anytype-Rpc-Account-Create-Request) | [Rpc.Account.Create.Response](#anytype-Rpc-Account-Create-Response) | |
| AccountDelete | [Rpc.Account.Delete.Request](#anytype-Rpc-Account-Delete-Request) | [Rpc.Account.Delete.Response](#anytype-Rpc-Account-Delete-Response) | |
| AccountRevertDeletion | [Rpc.Account.RevertDeletion.Request](#anytype-Rpc-Account-RevertDeletion-Request) | [Rpc.Account.RevertDeletion.Response](#anytype-Rpc-Account-RevertDeletion-Response) | |
@ -3490,119 +3478,6 @@ TODO: Remove this request if we do not need it, GO-1926
<a name="anytype-Rpc-Account-Migrate"></a>
### Rpc.Account.Migrate
<a name="anytype-Rpc-Account-Migrate-Request"></a>
### Rpc.Account.Migrate.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [string](#string) | | Id of a selected account |
| rootPath | [string](#string) | | |
<a name="anytype-Rpc-Account-Migrate-Response"></a>
### Rpc.Account.Migrate.Response
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| error | [Rpc.Account.Migrate.Response.Error](#anytype-Rpc-Account-Migrate-Response-Error) | | |
<a name="anytype-Rpc-Account-Migrate-Response-Error"></a>
### Rpc.Account.Migrate.Response.Error
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| code | [Rpc.Account.Migrate.Response.Error.Code](#anytype-Rpc-Account-Migrate-Response-Error-Code) | | |
| description | [string](#string) | | |
<a name="anytype-Rpc-Account-MigrateCancel"></a>
### Rpc.Account.MigrateCancel
<a name="anytype-Rpc-Account-MigrateCancel-Request"></a>
### Rpc.Account.MigrateCancel.Request
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| id | [string](#string) | | Id of a selected account |
<a name="anytype-Rpc-Account-MigrateCancel-Response"></a>
### Rpc.Account.MigrateCancel.Response
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| error | [Rpc.Account.MigrateCancel.Response.Error](#anytype-Rpc-Account-MigrateCancel-Response-Error) | | |
<a name="anytype-Rpc-Account-MigrateCancel-Response-Error"></a>
### Rpc.Account.MigrateCancel.Response.Error
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| code | [Rpc.Account.MigrateCancel.Response.Error.Code](#anytype-Rpc-Account-MigrateCancel-Response-Error-Code) | | |
| description | [string](#string) | | |
<a name="anytype-Rpc-Account-Move"></a>
### Rpc.Account.Move
@ -21224,35 +21099,6 @@ Middleware-to-front-end response, that can contain a NULL error or a non-NULL er
<a name="anytype-Rpc-Account-Migrate-Response-Error-Code"></a>
### Rpc.Account.Migrate.Response.Error.Code
| Name | Number | Description |
| ---- | ------ | ----------- |
| NULL | 0 | No error |
| UNKNOWN_ERROR | 1 | Any other errors |
| BAD_INPUT | 2 | Id or root path is wrong |
| ACCOUNT_NOT_FOUND | 101 | |
| CANCELED | 102 | |
| NOT_ENOUGH_FREE_SPACE | 103 | TODO: [storage] Add specific error codes for migration problems |
<a name="anytype-Rpc-Account-MigrateCancel-Response-Error-Code"></a>
### Rpc.Account.MigrateCancel.Response.Error.Code
| Name | Number | Description |
| ---- | ------ | ----------- |
| NULL | 0 | No error |
| UNKNOWN_ERROR | 1 | Any other errors |
| BAD_INPUT | 2 | Id or root path is wrong |
<a name="anytype-Rpc-Account-Move-Response-Error-Code"></a>
### Rpc.Account.Move.Response.Error.Code
@ -21348,7 +21194,6 @@ Middleware-to-front-end response, that can contain a NULL error or a non-NULL er
| FAILED_TO_FETCH_REMOTE_NODE_HAS_INCOMPATIBLE_PROTO_VERSION | 110 | |
| ACCOUNT_IS_DELETED | 111 | |
| ACCOUNT_LOAD_IS_CANCELED | 112 | |
| ACCOUNT_STORE_NOT_MIGRATED | 113 | |
| CONFIG_FILE_NOT_FOUND | 200 | |
| CONFIG_FILE_INVALID | 201 | |
| CONFIG_FILE_NETWORK_ID_MISMATCH | 202 | |

17
go.mod
View file

@ -8,7 +8,7 @@ require (
github.com/VividCortex/ewma v1.2.0
github.com/adrium/goheif v0.0.0-20230113233934-ca402e77a786
github.com/anyproto/any-store v0.1.7
github.com/anyproto/any-sync v0.6.0
github.com/anyproto/any-sync v0.5.26
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20250131145601-de288583ff2a
github.com/anyproto/go-chash v0.1.0
github.com/anyproto/go-naturaldate/v2 v2.0.2-0.20230524105841-9829cfd13438
@ -103,12 +103,11 @@ require (
go.uber.org/mock v0.5.0
go.uber.org/multierr v1.11.0
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c
golang.org/x/image v0.24.0
golang.org/x/mobile v0.0.0-20241108191957-fa514ef75a0f
golang.org/x/net v0.35.0
golang.org/x/oauth2 v0.26.0
golang.org/x/sys v0.30.0
golang.org/x/text v0.22.0
google.golang.org/grpc v1.70.0
gopkg.in/Graylog2/go-gelf.v2 v2.0.0-20180125164251-1832d8546a9f
@ -116,6 +115,7 @@ require (
gopkg.in/yaml.v3 v3.0.1
storj.io/drpc v0.0.34
zombiezen.com/go/sqlite v1.4.0
)
require (
@ -189,7 +189,7 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/flatbuffers v1.12.1 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/google/pprof v0.0.0-20250202011525-fc3143867406 // 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
@ -217,12 +217,12 @@ require (
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
github.com/libp2p/go-libp2p v0.38.2 // indirect
github.com/libp2p/go-libp2p v0.39.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/miekg/dns v1.1.62 // indirect
github.com/miekg/dns v1.1.63 // indirect
github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
@ -282,14 +282,15 @@ require (
go.opentelemetry.io/otel/trace v1.32.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.33.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/mod v0.23.0 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/term v0.29.0 // indirect
golang.org/x/time v0.10.0 // indirect
golang.org/x/tools v0.29.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241202173237-19429a94021a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect
google.golang.org/protobuf v1.36.2 // indirect
google.golang.org/protobuf v1.36.4 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
lukechampine.com/blake3 v1.3.0 // indirect

66
go.sum
View file

@ -84,8 +84,8 @@ github.com/andybalholm/cascadia v1.3.3 h1:AG2YHrzJIm4BZ19iwJ/DAua6Btl3IwJX+VI4kk
github.com/andybalholm/cascadia v1.3.3/go.mod h1:xNd9bqTn98Ln4DwST8/nG+H0yuB8Hmgu1YHNnWw0GeA=
github.com/anyproto/any-store v0.1.7 h1:E3DntI+JXo3h7v0WTUJWH+nm7G4MV0PNOXZ6SFzQ2OU=
github.com/anyproto/any-store v0.1.7/go.mod h1:nbyRoJYOlvSWU1xDOrmgPP96UeoTf4eYZ9k+qqLK9k8=
github.com/anyproto/any-sync v0.6.0 h1:JDxOTUuzGCHaeyid64tVIahYySCuonOK8Gwpf8s8lJ0=
github.com/anyproto/any-sync v0.6.0/go.mod h1:GrVtVp1VWqWRyYErJVsJVUhb6yzcvelQ+HWOXZ4f0tc=
github.com/anyproto/any-sync v0.5.26 h1:JWcR/RFGQ22CYWrdh2Ain6uEWNePtYHCLs+LXsm8hhU=
github.com/anyproto/any-sync v0.5.26/go.mod h1:Ljftoz6/mCM/2wP2tK9H1/jtVAxfgqzYplBA4MbiUs0=
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/badger/v4 v4.2.1-0.20240110160636-80743fa3d580 h1:Ba80IlCCxkZ9H1GF+7vFu/TSpPvbpDCxXJ5ogc4euYc=
@ -483,8 +483,8 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/pprof v0.0.0-20250202011525-fc3143867406 h1:wlQI2cYY0BsWmmPPAnxfQ8SDW0S3Jasn+4B8kXFxprg=
github.com/google/pprof v0.0.0-20250202011525-fc3143867406/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -673,8 +673,8 @@ github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0=
github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk=
github.com/koron/go-ssdp v0.0.5 h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk=
github.com/koron/go-ssdp v0.0.5/go.mod h1:Qm59B7hpKpDqfyRNWRNr00jGwLdXjDyZh6y7rH6VS0w=
github.com/kovidgoyal/imaging v1.6.4 h1:K0idhRPXnRrJBKnBYcTfI1HTWSNDeAn7hYDvf9I0dCk=
github.com/kovidgoyal/imaging v1.6.4/go.mod h1:bEIgsaZmXlvFfkv/CUxr9rJook6AQkJnpB5EPosRfRY=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
@ -696,8 +696,8 @@ github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6
github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg=
github.com/libp2p/go-flow-metrics v0.2.0 h1:EIZzjmeOE6c8Dav0sNv35vhZxATIXWZg6j/C08XmmDw=
github.com/libp2p/go-flow-metrics v0.2.0/go.mod h1:st3qqfu8+pMfh+9Mzqb2GTiwrAGjIPszEjZmtksN8Jc=
github.com/libp2p/go-libp2p v0.38.2 h1:9SZQDOCi82A25An4kx30lEtr6kGTxrtoaDkbs5xrK5k=
github.com/libp2p/go-libp2p v0.38.2/go.mod h1:QWV4zGL3O9nXKdHirIC59DoRcZ446dfkjbOJ55NEWFo=
github.com/libp2p/go-libp2p v0.39.0 h1:LmrhDRud4eDkQCSB4l5NfoIFDqvDwAyANmfeYkgnKgs=
github.com/libp2p/go-libp2p v0.39.0/go.mod h1:3zicI8Lp7Isun+Afo/JOACUbbJqqR2owK6RQWFsVAbI=
github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0=
@ -710,8 +710,8 @@ github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk=
github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk=
github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8=
github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE=
github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ=
github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4=
github.com/libp2p/go-yamux/v4 v4.0.2 h1:nrLh89LN/LEiqcFiqdKDRHjGstN300C1269K/EX0CPU=
github.com/libp2p/go-yamux/v4 v4.0.2/go.mod h1:C808cCRgOs1iBwY4S71T5oxgMxgLmqUw56qh4AeBW2o=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
@ -751,8 +751,8 @@ github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwX
github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
github.com/miekg/dns v1.1.62 h1:cN8OuEF1/x5Rq6Np+h1epln8OiyPWV+lROx9LxcGgIQ=
github.com/miekg/dns v1.1.62/go.mod h1:mvDlcItzm+br7MToIKqkglaGhlFMHJ9DTNNWONWXbNQ=
github.com/miekg/dns v1.1.63 h1:8M5aAw6OMZfFXTT7K5V0Eu5YiiL8l7nUAkyN6C9YwaY=
github.com/miekg/dns v1.1.63/go.mod h1:6NGHfjhpmr5lt3XPLuyfDJi5AXbNIPM9PY6H6sF1Nfs=
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
github.com/miolini/datacounter v1.0.3 h1:tanOZPVblGXQl7/bSZWoEM8l4KK83q24qwQLMrO/HOA=
@ -874,36 +874,46 @@ github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk
github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M=
github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk=
github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE=
github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U=
github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg=
github.com/pion/ice/v2 v2.3.37 h1:ObIdaNDu1rCo7hObhs34YSBcO7fjslJMZV0ux+uZWh0=
github.com/pion/ice/v2 v2.3.37/go.mod h1:mBF7lnigdqgtB+YHkaY/Y6s6tsyRyo4u4rPGRuOjUBQ=
github.com/pion/ice/v4 v4.0.6 h1:jmM9HwI9lfetQV/39uD0nY4y++XZNPhvzIPCb8EwxUM=
github.com/pion/ice/v4 v4.0.6/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw=
github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI=
github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y=
github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI=
github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90=
github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8=
github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk=
github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0=
github.com/pion/rtp v1.8.10 h1:puphjdbjPB+L+NFaVuZ5h6bt1g5q4kFIoI+r5q/g0CU=
github.com/pion/rtp v1.8.10/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4=
github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk=
github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4=
github.com/pion/sctp v1.8.35 h1:qwtKvNK1Wc5tHMIYgTDJhfZk7vATGVHhXbUDfHbYwzA=
github.com/pion/sctp v1.8.35/go.mod h1:EcXP8zCYVTRy3W9xtOF7wJm1L1aXfKRQzaM33SjQlzg=
github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY=
github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M=
github.com/pion/srtp/v2 v2.0.20 h1:HNNny4s+OUmG280ETrCdgFndp4ufx3/uy85EawYEhTk=
github.com/pion/srtp/v2 v2.0.20/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA=
github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA=
github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E=
github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M=
github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ=
github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4=
github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8=
github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=
github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU=
github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q=
github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E=
github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0=
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc=
github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY=
github.com/pion/webrtc/v3 v3.3.5 h1:ZsSzaMz/i9nblPdiAkZoP+E6Kmjw+jnyq3bEmU3EtRg=
github.com/pion/webrtc/v3 v3.3.5/go.mod h1:liNa+E1iwyzyXqNUwvoMRNQ10x8h8FOeJKL8RkIbamE=
github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=
github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA=
github.com/pion/webrtc/v4 v4.0.8 h1:T1ZmnT9qxIJIt4d8XoiMOBrTClGHDDXNg9e/fh018Qc=
github.com/pion/webrtc/v4 v4.0.8/go.mod h1:HHBeUVBAC+j4ZFnYhovEFStF02Arb1EyD4G7e7HBTJw=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -1207,8 +1217,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-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
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=
@ -1244,8 +1254,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1641,8 +1651,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

File diff suppressed because it is too large Load diff

View file

@ -812,54 +812,6 @@ message Rpc {
}
}
message Migrate {
message Request {
option (no_auth) = true;
string id = 1; // Id of a selected account
string rootPath = 2;
}
message Response {
Error error = 1;
message Error {
Code code = 1;
string description = 2;
enum Code {
NULL = 0; // No error
UNKNOWN_ERROR = 1; // Any other errors
BAD_INPUT = 2; // Id or root path is wrong
ACCOUNT_NOT_FOUND = 101;
CANCELED = 102;
NOT_ENOUGH_FREE_SPACE = 103;
// TODO: [storage] Add specific error codes for migration problems
}
}
}
}
message MigrateCancel {
message Request {
option (no_auth) = true;
string id = 1; // Id of a selected account
}
message Response {
Error error = 1;
message Error {
Code code = 1;
string description = 2;
enum Code {
NULL = 0; // No error
UNKNOWN_ERROR = 1; // Any other errors
BAD_INPUT = 2; // Id or root path is wrong
}
}
}
}
message Select {
/**
* Front end to middleware request-to-launch-a specific account using account id and a root path
@ -902,7 +854,6 @@ message Rpc {
FAILED_TO_FETCH_REMOTE_NODE_HAS_INCOMPATIBLE_PROTO_VERSION = 110;
ACCOUNT_IS_DELETED = 111;
ACCOUNT_LOAD_IS_CANCELED = 112;
ACCOUNT_STORE_NOT_MIGRATED = 113;
CONFIG_FILE_NOT_FOUND = 200;
CONFIG_FILE_INVALID = 201;

View file

@ -732,7 +732,7 @@ message Event {
FaviconHash faviconHash = 6;
Type type = 7;
TargetObjectId targetObjectId = 8;
message Url {
string value = 1;

View file

@ -36,8 +36,6 @@ service ClientCommands {
// Account
// ***
rpc AccountRecover (anytype.Rpc.Account.Recover.Request) returns (anytype.Rpc.Account.Recover.Response);
rpc AccountMigrate (anytype.Rpc.Account.Migrate.Request) returns (anytype.Rpc.Account.Migrate.Response);
rpc AccountMigrateCancel (anytype.Rpc.Account.MigrateCancel.Request) returns (anytype.Rpc.Account.MigrateCancel.Response);
rpc AccountCreate (anytype.Rpc.Account.Create.Request) returns (anytype.Rpc.Account.Create.Response);
rpc AccountDelete (anytype.Rpc.Account.Delete.Request) returns (anytype.Rpc.Account.Delete.Response);
rpc AccountRevertDeletion (anytype.Rpc.Account.RevertDeletion.Request) returns (anytype.Rpc.Account.RevertDeletion.Response);

View file

@ -416,104 +416,6 @@ func (_c *MockClientCommandsServer_AccountLocalLinkSolveChallenge_Call) RunAndRe
return _c
}
// AccountMigrate provides a mock function with given fields: _a0, _a1
func (_m *MockClientCommandsServer) AccountMigrate(_a0 context.Context, _a1 *pb.RpcAccountMigrateRequest) *pb.RpcAccountMigrateResponse {
ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for AccountMigrate")
}
var r0 *pb.RpcAccountMigrateResponse
if rf, ok := ret.Get(0).(func(context.Context, *pb.RpcAccountMigrateRequest) *pb.RpcAccountMigrateResponse); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*pb.RpcAccountMigrateResponse)
}
}
return r0
}
// MockClientCommandsServer_AccountMigrate_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AccountMigrate'
type MockClientCommandsServer_AccountMigrate_Call struct {
*mock.Call
}
// AccountMigrate is a helper method to define mock.On call
// - _a0 context.Context
// - _a1 *pb.RpcAccountMigrateRequest
func (_e *MockClientCommandsServer_Expecter) AccountMigrate(_a0 interface{}, _a1 interface{}) *MockClientCommandsServer_AccountMigrate_Call {
return &MockClientCommandsServer_AccountMigrate_Call{Call: _e.mock.On("AccountMigrate", _a0, _a1)}
}
func (_c *MockClientCommandsServer_AccountMigrate_Call) Run(run func(_a0 context.Context, _a1 *pb.RpcAccountMigrateRequest)) *MockClientCommandsServer_AccountMigrate_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(*pb.RpcAccountMigrateRequest))
})
return _c
}
func (_c *MockClientCommandsServer_AccountMigrate_Call) Return(_a0 *pb.RpcAccountMigrateResponse) *MockClientCommandsServer_AccountMigrate_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockClientCommandsServer_AccountMigrate_Call) RunAndReturn(run func(context.Context, *pb.RpcAccountMigrateRequest) *pb.RpcAccountMigrateResponse) *MockClientCommandsServer_AccountMigrate_Call {
_c.Call.Return(run)
return _c
}
// AccountMigrateCancel provides a mock function with given fields: _a0, _a1
func (_m *MockClientCommandsServer) AccountMigrateCancel(_a0 context.Context, _a1 *pb.RpcAccountMigrateCancelRequest) *pb.RpcAccountMigrateCancelResponse {
ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for AccountMigrateCancel")
}
var r0 *pb.RpcAccountMigrateCancelResponse
if rf, ok := ret.Get(0).(func(context.Context, *pb.RpcAccountMigrateCancelRequest) *pb.RpcAccountMigrateCancelResponse); ok {
r0 = rf(_a0, _a1)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*pb.RpcAccountMigrateCancelResponse)
}
}
return r0
}
// MockClientCommandsServer_AccountMigrateCancel_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AccountMigrateCancel'
type MockClientCommandsServer_AccountMigrateCancel_Call struct {
*mock.Call
}
// AccountMigrateCancel is a helper method to define mock.On call
// - _a0 context.Context
// - _a1 *pb.RpcAccountMigrateCancelRequest
func (_e *MockClientCommandsServer_Expecter) AccountMigrateCancel(_a0 interface{}, _a1 interface{}) *MockClientCommandsServer_AccountMigrateCancel_Call {
return &MockClientCommandsServer_AccountMigrateCancel_Call{Call: _e.mock.On("AccountMigrateCancel", _a0, _a1)}
}
func (_c *MockClientCommandsServer_AccountMigrateCancel_Call) Run(run func(_a0 context.Context, _a1 *pb.RpcAccountMigrateCancelRequest)) *MockClientCommandsServer_AccountMigrateCancel_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(*pb.RpcAccountMigrateCancelRequest))
})
return _c
}
func (_c *MockClientCommandsServer_AccountMigrateCancel_Call) Return(_a0 *pb.RpcAccountMigrateCancelResponse) *MockClientCommandsServer_AccountMigrateCancel_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockClientCommandsServer_AccountMigrateCancel_Call) RunAndReturn(run func(context.Context, *pb.RpcAccountMigrateCancelRequest) *pb.RpcAccountMigrateCancelResponse) *MockClientCommandsServer_AccountMigrateCancel_Call {
_c.Call.Return(run)
return _c
}
// AccountMove provides a mock function with given fields: _a0, _a1
func (_m *MockClientCommandsServer) AccountMove(_a0 context.Context, _a1 *pb.RpcAccountMoveRequest) *pb.RpcAccountMoveResponse {
ret := _m.Called(_a0, _a1)

View file

@ -26,352 +26,350 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
func init() { proto.RegisterFile("pb/protos/service/service.proto", fileDescriptor_93a29dc403579097) }
var fileDescriptor_93a29dc403579097 = []byte{
// 5514 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x9d, 0x5f, 0x6f, 0x24, 0x49,
0x52, 0xc0, 0xb7, 0x5f, 0x58, 0xa8, 0xe3, 0x16, 0xe8, 0x85, 0x65, 0x6f, 0xb9, 0x9b, 0x99, 0x9d,
0x9d, 0xb1, 0x3d, 0x63, 0xbb, 0x3d, 0x3b, 0xb3, 0xff, 0xb8, 0x43, 0x82, 0x1e, 0x7b, 0xec, 0xf5,
0x9d, 0xed, 0x35, 0xee, 0xf6, 0x8c, 0xb4, 0x12, 0x12, 0xe5, 0xaa, 0x74, 0xbb, 0x70, 0x75, 0x65,
0x5d, 0x55, 0x76, 0x7b, 0xfa, 0x10, 0x08, 0x04, 0x02, 0x81, 0x40, 0x9c, 0xf8, 0x27, 0x78, 0x42,
0x42, 0x7c, 0x00, 0x3e, 0x06, 0x8f, 0xf7, 0xc8, 0x23, 0xda, 0xfd, 0x0a, 0x7c, 0x00, 0x54, 0xf9,
0x3f, 0xa3, 0x32, 0xb2, 0xca, 0xcb, 0xd3, 0x8c, 0x1c, 0xbf, 0x88, 0xc8, 0xac, 0x8c, 0xcc, 0x8c,
0xcc, 0xca, 0xca, 0x8e, 0xee, 0x96, 0x17, 0x3b, 0x65, 0x45, 0x19, 0xad, 0x77, 0x6a, 0x52, 0x2d,
0xb3, 0x84, 0xa8, 0x7f, 0x47, 0xfc, 0xcf, 0xc3, 0x37, 0xe3, 0x62, 0xc5, 0x56, 0x25, 0x79, 0xef,
0x5d, 0x43, 0x26, 0x74, 0x3e, 0x8f, 0x8b, 0xb4, 0x16, 0xc8, 0x7b, 0xef, 0x18, 0x09, 0x59, 0x92,
0x82, 0xc9, 0xbf, 0x3f, 0xfd, 0x8f, 0xff, 0x1d, 0x44, 0x6f, 0xed, 0xe6, 0x19, 0x29, 0xd8, 0xae,
0xd4, 0x18, 0x7e, 0x19, 0x7d, 0x7b, 0x5c, 0x96, 0x07, 0x84, 0xbd, 0x24, 0x55, 0x9d, 0xd1, 0x62,
0xf8, 0xc1, 0x48, 0x3a, 0x18, 0x9d, 0x95, 0xc9, 0x68, 0x5c, 0x96, 0x23, 0x23, 0x1c, 0x9d, 0x91,
0x1f, 0x2f, 0x48, 0xcd, 0xde, 0x7b, 0x10, 0x86, 0xea, 0x92, 0x16, 0x35, 0x19, 0x5e, 0x46, 0xbf,
0x32, 0x2e, 0xcb, 0x09, 0x61, 0x7b, 0xa4, 0xa9, 0xc0, 0x84, 0xc5, 0x8c, 0x0c, 0xd7, 0x5b, 0xaa,
0x2e, 0xa0, 0x7d, 0x6c, 0x74, 0x83, 0xd2, 0xcf, 0x34, 0xfa, 0x56, 0xe3, 0xe7, 0x6a, 0xc1, 0x52,
0x7a, 0x53, 0x0c, 0xdf, 0x6f, 0x2b, 0x4a, 0x91, 0xb6, 0x7d, 0x3f, 0x84, 0x48, 0xab, 0xaf, 0xa2,
0x5f, 0x7c, 0x15, 0xe7, 0x39, 0x61, 0xbb, 0x15, 0x69, 0x0a, 0xee, 0xea, 0x08, 0xd1, 0x48, 0xc8,
0xb4, 0xdd, 0x0f, 0x82, 0x8c, 0x34, 0xfc, 0x65, 0xf4, 0x6d, 0x21, 0x39, 0x23, 0x09, 0x5d, 0x92,
0x6a, 0xe8, 0xd5, 0x92, 0x42, 0xe4, 0x91, 0xb7, 0x20, 0x68, 0x7b, 0x97, 0x16, 0x4b, 0x52, 0x31,
0xbf, 0x6d, 0x29, 0x0c, 0xdb, 0x36, 0x90, 0xb4, 0xfd, 0x57, 0x83, 0xe8, 0xbb, 0xe3, 0x24, 0xa1,
0x8b, 0x82, 0x1d, 0xd1, 0x24, 0xce, 0x8f, 0xb2, 0xe2, 0xfa, 0x84, 0xdc, 0xec, 0x5e, 0x35, 0x7c,
0x31, 0x23, 0xc3, 0x67, 0xee, 0x53, 0x15, 0xe8, 0x48, 0xb3, 0x23, 0x1b, 0xd6, 0xbe, 0x3f, 0xba,
0x9d, 0x92, 0x2c, 0xcb, 0xdf, 0x0d, 0xa2, 0x3b, 0xb0, 0x2c, 0x13, 0x9a, 0x2f, 0x89, 0x29, 0xcd,
0xc7, 0x1d, 0x86, 0x5d, 0x5c, 0x97, 0xe7, 0x93, 0xdb, 0xaa, 0xc9, 0x12, 0xe5, 0xd1, 0xdb, 0x76,
0xb8, 0x4c, 0x48, 0xcd, 0xbb, 0xd3, 0x23, 0x3c, 0x22, 0x24, 0xa2, 0x3d, 0x3f, 0xee, 0x83, 0x4a,
0x6f, 0x59, 0x34, 0x94, 0xde, 0x72, 0x5a, 0x6b, 0x67, 0x1b, 0x5e, 0x0b, 0x16, 0xa1, 0x7d, 0x3d,
0xea, 0x41, 0x4a, 0x57, 0xbf, 0x1f, 0xfd, 0xd2, 0x2b, 0x5a, 0x5d, 0xd7, 0x65, 0x9c, 0x10, 0xd9,
0x15, 0x1e, 0xba, 0xda, 0x4a, 0x0a, 0x7b, 0xc3, 0x5a, 0x17, 0x66, 0x05, 0xad, 0x12, 0x7e, 0x51,
0x12, 0x38, 0x06, 0x19, 0xc5, 0x46, 0x88, 0x05, 0x2d, 0x84, 0xa4, 0xed, 0xeb, 0x68, 0x68, 0x6c,
0x5f, 0xfc, 0x01, 0x49, 0xd8, 0x38, 0x4d, 0x61, 0xab, 0x18, 0x5d, 0x4e, 0x8c, 0xc6, 0x69, 0x8a,
0xb5, 0x8a, 0x1f, 0x95, 0xce, 0x6e, 0xa2, 0x77, 0x80, 0xb3, 0xa3, 0xac, 0xe6, 0x0e, 0xb7, 0xc3,
0x56, 0x24, 0xa6, 0x9d, 0x8e, 0xfa, 0xe2, 0xd2, 0xf1, 0x9f, 0x0c, 0xa2, 0xef, 0x78, 0x3c, 0x9f,
0x91, 0x39, 0x5d, 0x92, 0xe1, 0x93, 0x6e, 0x6b, 0x82, 0xd4, 0xfe, 0x3f, 0xbc, 0x85, 0x86, 0x27,
0x4c, 0x26, 0x24, 0x27, 0x09, 0x43, 0xc3, 0x44, 0x88, 0x3b, 0xc3, 0x44, 0x63, 0x56, 0x0f, 0x53,
0xc2, 0x03, 0xc2, 0x76, 0x17, 0x55, 0x45, 0x0a, 0x86, 0xb6, 0xa5, 0x41, 0x3a, 0xdb, 0xd2, 0x41,
0x3d, 0xf5, 0x39, 0x20, 0x6c, 0x9c, 0xe7, 0x68, 0x7d, 0x84, 0xb8, 0xb3, 0x3e, 0x1a, 0x93, 0x1e,
0x92, 0xe8, 0x97, 0xad, 0x27, 0xc6, 0x0e, 0x8b, 0x4b, 0x3a, 0xc4, 0x9f, 0x05, 0x97, 0x6b, 0x1f,
0xeb, 0x9d, 0x9c, 0xa7, 0x1a, 0x2f, 0x5e, 0x97, 0xb4, 0xc2, 0x9b, 0x45, 0x88, 0x3b, 0xab, 0xa1,
0x31, 0xe9, 0xe1, 0xf7, 0xa2, 0xb7, 0xe4, 0x28, 0xa9, 0xe6, 0xb3, 0x07, 0xde, 0x21, 0x14, 0x4e,
0x68, 0x0f, 0x3b, 0xa8, 0x96, 0xf9, 0xe3, 0x6c, 0x56, 0x35, 0xa3, 0x8f, 0xdf, 0xbc, 0x94, 0x76,
0x98, 0x37, 0x94, 0x34, 0x4f, 0xa3, 0x5f, 0x75, 0xcd, 0xef, 0xc6, 0x45, 0x42, 0xf2, 0xe1, 0xe3,
0x90, 0xba, 0x60, 0xb4, 0xab, 0xcd, 0x5e, 0xac, 0x19, 0xec, 0x24, 0x21, 0x07, 0xd3, 0x0f, 0xbc,
0xda, 0x60, 0x28, 0x7d, 0x10, 0x86, 0x5a, 0xb6, 0xf7, 0x48, 0x4e, 0x50, 0xdb, 0x42, 0xd8, 0x61,
0x5b, 0x43, 0xd2, 0x76, 0x15, 0xfd, 0x9a, 0x6e, 0xe6, 0x26, 0x2f, 0xe0, 0xf2, 0x66, 0xd2, 0xd9,
0x44, 0xda, 0xd1, 0x86, 0xb4, 0xaf, 0xad, 0x7e, 0x70, 0xab, 0x3e, 0x72, 0x44, 0xf1, 0xd7, 0x07,
0x8c, 0x27, 0x0f, 0xc2, 0x90, 0xb4, 0xfd, 0xd7, 0x83, 0xe8, 0x7b, 0x52, 0xf6, 0xa2, 0x88, 0x2f,
0x72, 0xc2, 0xa7, 0xf8, 0x13, 0xc2, 0x6e, 0x68, 0x75, 0x3d, 0x59, 0x15, 0x09, 0x92, 0xce, 0xf8,
0xe1, 0x8e, 0x74, 0x06, 0x55, 0x92, 0x85, 0xf9, 0xc3, 0xe8, 0x5d, 0x15, 0x14, 0x57, 0x71, 0x31,
0x23, 0x3f, 0xac, 0x69, 0x31, 0x2e, 0xb3, 0x71, 0x9a, 0x56, 0xc3, 0x91, 0xbf, 0xe9, 0x21, 0xa7,
0x4b, 0xb0, 0xd3, 0x9b, 0xb7, 0xd2, 0x67, 0xf9, 0x94, 0x19, 0x2d, 0x61, 0xfa, 0xac, 0x1e, 0x1f,
0xa3, 0x25, 0x96, 0x3e, 0xbb, 0x48, 0xcb, 0xea, 0x71, 0x33, 0x07, 0xf9, 0xad, 0x1e, 0xdb, 0x93,
0xce, 0xfd, 0x10, 0x62, 0xe6, 0x00, 0xf5, 0xa0, 0x68, 0x71, 0x99, 0xcd, 0xce, 0xcb, 0xb4, 0xe9,
0x43, 0x8f, 0xfc, 0x75, 0xb6, 0x10, 0x64, 0x0e, 0x40, 0x50, 0xe9, 0xed, 0x6f, 0x4d, 0x96, 0x29,
0xc7, 0xa5, 0xfd, 0x8a, 0xce, 0x8f, 0xc8, 0x2c, 0x4e, 0x56, 0x72, 0x30, 0xfd, 0x28, 0x34, 0x8a,
0x41, 0x5a, 0x17, 0xe2, 0xe3, 0x5b, 0x6a, 0xc9, 0xf2, 0xfc, 0xdb, 0x20, 0x7a, 0xe0, 0xc4, 0x89,
0x0c, 0x26, 0x51, 0xfa, 0x71, 0x91, 0x9e, 0x91, 0x9a, 0xc5, 0x15, 0x1b, 0x7e, 0x3f, 0x10, 0x03,
0x88, 0x8e, 0x2e, 0xdb, 0x0f, 0xbe, 0x91, 0xae, 0x69, 0xf5, 0x49, 0x33, 0x4b, 0xc8, 0xf1, 0xc7,
0x6d, 0x75, 0x2e, 0x81, 0xa3, 0xcf, 0xfd, 0x10, 0x62, 0x5a, 0x9d, 0x0b, 0x0e, 0x8b, 0x65, 0xc6,
0xc8, 0x01, 0x29, 0x48, 0xd5, 0x6e, 0x75, 0xa1, 0xea, 0x22, 0x48, 0xab, 0x23, 0xa8, 0x19, 0xe9,
0x1c, 0x6f, 0x3a, 0xd3, 0xd8, 0x0c, 0x18, 0x69, 0xe5, 0x1a, 0x5b, 0xfd, 0x60, 0xb3, 0x54, 0xb6,
0x7c, 0x9e, 0x91, 0x25, 0xbd, 0x86, 0x4b, 0x65, 0xdb, 0x84, 0x00, 0x90, 0xa5, 0xb2, 0x17, 0x34,
0xe9, 0x80, 0xe5, 0xe7, 0x65, 0x46, 0x6e, 0x40, 0x3a, 0x60, 0x2b, 0x37, 0x62, 0x24, 0x1d, 0xf0,
0x60, 0xd2, 0xc3, 0x49, 0xf4, 0x0b, 0x5c, 0xf8, 0x43, 0x9a, 0x15, 0xc3, 0xbb, 0x1e, 0xa5, 0x46,
0xa0, 0xad, 0xde, 0xc3, 0x01, 0x50, 0xe2, 0xe6, 0xaf, 0x72, 0x6e, 0x7e, 0x88, 0x28, 0x81, 0x69,
0x79, 0xad, 0x0b, 0x33, 0x79, 0x18, 0x17, 0x36, 0xe3, 0xd7, 0xe4, 0x2a, 0xae, 0xb2, 0x62, 0x36,
0xf4, 0xe9, 0x5a, 0x72, 0x24, 0x0f, 0xf3, 0x71, 0x20, 0x84, 0xa5, 0xe2, 0xb8, 0x2c, 0xab, 0x66,
0x58, 0xf4, 0x85, 0xb0, 0x8b, 0x04, 0x43, 0xb8, 0x85, 0xfa, 0xbd, 0xed, 0x91, 0x24, 0xcf, 0x8a,
0xa0, 0x37, 0x89, 0xf4, 0xf1, 0x66, 0x50, 0x10, 0xbc, 0x47, 0x24, 0x5e, 0x12, 0x55, 0x33, 0xdf,
0x93, 0xb1, 0x81, 0x60, 0xf0, 0x02, 0xd0, 0x2c, 0x7a, 0xb9, 0xf8, 0x38, 0xbe, 0x26, 0xcd, 0x03,
0x26, 0xcd, 0xa4, 0x3a, 0xf4, 0xe9, 0x3b, 0x04, 0xb2, 0xe8, 0xf5, 0x93, 0xd2, 0xd5, 0x22, 0x7a,
0x87, 0xcb, 0x4f, 0xe3, 0x8a, 0x65, 0x49, 0x56, 0xc6, 0x85, 0x5a, 0x4c, 0xf9, 0xfa, 0x75, 0x8b,
0xd2, 0x2e, 0xb7, 0x7b, 0xd2, 0xd2, 0xed, 0x3f, 0x0f, 0xa2, 0xf7, 0xa1, 0xdf, 0x53, 0x52, 0xcd,
0x33, 0xbe, 0x26, 0xaf, 0xc5, 0x20, 0x3c, 0xfc, 0x34, 0x6c, 0xb4, 0xa5, 0xa0, 0x4b, 0xf3, 0xd9,
0xed, 0x15, 0x4d, 0x26, 0x36, 0x91, 0xeb, 0x94, 0x2f, 0xaa, 0xb4, 0xb5, 0x67, 0x35, 0x51, 0x8b,
0x0f, 0x2e, 0x44, 0x32, 0xb1, 0x16, 0x04, 0x7a, 0xf8, 0x79, 0x51, 0x2b, 0xeb, 0xbe, 0x1e, 0x6e,
0xc4, 0xc1, 0x1e, 0xee, 0x60, 0xa6, 0x87, 0x9f, 0x2e, 0x2e, 0xf2, 0xac, 0xbe, 0xca, 0x8a, 0x99,
0x4c, 0xbb, 0x5d, 0x5d, 0x23, 0x86, 0x99, 0xf7, 0x7a, 0x27, 0xe7, 0x73, 0x22, 0x83, 0x05, 0x75,
0x02, 0xc2, 0x64, 0xbd, 0x93, 0x33, 0xab, 0x21, 0x23, 0x6d, 0x96, 0xe1, 0x60, 0x35, 0x64, 0xa9,
0x36, 0x52, 0x64, 0x35, 0xd4, 0xa6, 0xcc, 0x6a, 0xc8, 0xae, 0x43, 0x4d, 0xf3, 0x25, 0x39, 0xaf,
0x32, 0xb0, 0x1a, 0x72, 0xca, 0xa7, 0x18, 0x64, 0x35, 0x84, 0xb1, 0x66, 0xa0, 0x32, 0xc4, 0x01,
0x61, 0x13, 0x16, 0xb3, 0x45, 0x0d, 0x06, 0x2a, 0xcb, 0x86, 0x46, 0x90, 0x81, 0x0a, 0x41, 0xa5,
0xb7, 0xdf, 0x8d, 0x22, 0xb1, 0x83, 0xc1, 0x77, 0x99, 0xdc, 0xb9, 0x47, 0x6e, 0x6d, 0x38, 0x5b,
0x4c, 0xef, 0x07, 0x08, 0x93, 0xf0, 0x88, 0xbf, 0xf3, 0xcd, 0xb3, 0xa1, 0x57, 0x83, 0x8b, 0x90,
0x84, 0x07, 0x20, 0xb0, 0xa0, 0x93, 0x2b, 0x7a, 0xe3, 0x2f, 0x68, 0x23, 0x09, 0x17, 0x54, 0x12,
0x66, 0x3b, 0x5b, 0x16, 0xd4, 0xb7, 0x9d, 0xad, 0x8a, 0x11, 0xda, 0xce, 0x86, 0x8c, 0x89, 0x19,
0xdb, 0xf0, 0x73, 0x4a, 0xaf, 0xe7, 0x71, 0x75, 0x0d, 0x62, 0xc6, 0x51, 0x56, 0x0c, 0x12, 0x33,
0x18, 0x6b, 0x62, 0xc6, 0x76, 0xd8, 0xa4, 0xcb, 0xe7, 0x55, 0x0e, 0x62, 0xc6, 0xb1, 0x21, 0x11,
0x24, 0x66, 0x10, 0xd4, 0x8c, 0x4e, 0xb6, 0xb7, 0x09, 0x81, 0x1b, 0x28, 0x8e, 0xfa, 0x84, 0x60,
0x1b, 0x28, 0x1e, 0x0c, 0x86, 0xd0, 0x41, 0x15, 0x97, 0x57, 0xfe, 0x10, 0xe2, 0xa2, 0x70, 0x08,
0x29, 0x04, 0xb6, 0xf7, 0x84, 0xc4, 0x55, 0x72, 0xe5, 0x6f, 0x6f, 0x21, 0x0b, 0xb7, 0xb7, 0x66,
0x60, 0x7b, 0x0b, 0xc1, 0xab, 0x8c, 0x5d, 0x1d, 0x13, 0x16, 0xfb, 0xdb, 0xdb, 0x65, 0xc2, 0xed,
0xdd, 0x62, 0x4d, 0x3e, 0x6e, 0x3b, 0x9c, 0x2c, 0x2e, 0xea, 0xa4, 0xca, 0x2e, 0xc8, 0x30, 0x60,
0x45, 0x43, 0x48, 0x3e, 0x8e, 0xc2, 0xd2, 0xe7, 0x4f, 0x07, 0xd1, 0x5d, 0xd5, 0xec, 0xb4, 0xae,
0xe5, 0xdc, 0xe7, 0xba, 0xff, 0xd8, 0xdf, 0xbe, 0x08, 0x8e, 0xbc, 0x60, 0xe8, 0xa1, 0x66, 0xe5,
0x06, 0xfe, 0x22, 0x9d, 0x17, 0xb5, 0x2e, 0xd4, 0xa7, 0x7d, 0xac, 0x5b, 0x0a, 0x48, 0x6e, 0xd0,
0x4b, 0xd1, 0xa4, 0x65, 0xb2, 0x7d, 0x94, 0xec, 0x30, 0xad, 0x41, 0x5a, 0xa6, 0x9e, 0xb7, 0x45,
0x20, 0x69, 0x99, 0x9f, 0x84, 0xa1, 0x70, 0x50, 0xd1, 0x45, 0x59, 0x77, 0x84, 0x02, 0x80, 0xc2,
0xa1, 0xd0, 0x86, 0xa5, 0xcf, 0xd7, 0xd1, 0xaf, 0xdb, 0xe1, 0x67, 0x3f, 0xec, 0x6d, 0x3c, 0xa6,
0x7c, 0x8f, 0x78, 0xd4, 0x17, 0x37, 0x19, 0x85, 0xf2, 0xcc, 0xf6, 0x08, 0x8b, 0xb3, 0xbc, 0x1e,
0xae, 0xf9, 0x6d, 0x28, 0x39, 0x92, 0x51, 0xf8, 0x38, 0x38, 0xbe, 0xed, 0x2d, 0xca, 0x3c, 0x4b,
0xda, 0xaf, 0x77, 0xa4, 0xae, 0x16, 0x87, 0xc7, 0x37, 0x1b, 0x83, 0xe3, 0x75, 0x93, 0xfa, 0xf1,
0xff, 0x4c, 0x57, 0x25, 0xf1, 0x8f, 0xd7, 0x0e, 0x12, 0x1e, 0xaf, 0x21, 0x0a, 0xeb, 0x33, 0x21,
0xec, 0x28, 0x5e, 0xd1, 0x05, 0x32, 0x5e, 0x6b, 0x71, 0xb8, 0x3e, 0x36, 0x66, 0xd6, 0x06, 0xda,
0xc3, 0x61, 0xc1, 0x48, 0x55, 0xc4, 0xf9, 0x7e, 0x1e, 0xcf, 0xea, 0x21, 0x32, 0xc6, 0xb8, 0x14,
0xb2, 0x36, 0xc0, 0x69, 0xcf, 0x63, 0x3c, 0xac, 0xf7, 0xe3, 0x25, 0xad, 0x32, 0x86, 0x3f, 0x46,
0x83, 0x74, 0x3e, 0x46, 0x07, 0xf5, 0x7a, 0x1b, 0x57, 0xc9, 0x55, 0xb6, 0x24, 0x69, 0xc0, 0x9b,
0x42, 0x7a, 0x78, 0xb3, 0x50, 0x4f, 0xa3, 0x4d, 0xe8, 0xa2, 0x4a, 0x08, 0xda, 0x68, 0x42, 0xdc,
0xd9, 0x68, 0x1a, 0x93, 0x1e, 0xfe, 0x7c, 0x10, 0xfd, 0x86, 0x90, 0xda, 0xef, 0x5c, 0xf6, 0xe2,
0xfa, 0xea, 0x82, 0xc6, 0x55, 0x3a, 0xfc, 0xd0, 0x67, 0xc7, 0x8b, 0x6a, 0xd7, 0x4f, 0x6f, 0xa3,
0x02, 0x1f, 0x6b, 0x93, 0x77, 0x9b, 0x1e, 0xe7, 0x7d, 0xac, 0x0e, 0x12, 0x7e, 0xac, 0x10, 0x85,
0x03, 0x08, 0x97, 0x8b, 0x2d, 0xb9, 0x35, 0x54, 0xdf, 0xdd, 0x97, 0x5b, 0xef, 0xe4, 0xe0, 0xf8,
0xd8, 0x08, 0xdd, 0x68, 0xd9, 0xc6, 0x6c, 0xf8, 0x23, 0x66, 0xd4, 0x17, 0x47, 0x3d, 0xeb, 0x5e,
0x11, 0xf6, 0xdc, 0xea, 0x19, 0xa3, 0xbe, 0x38, 0xe2, 0xd9, 0x1a, 0xd6, 0x42, 0x9e, 0x3d, 0x43,
0xdb, 0xa8, 0x2f, 0x0e, 0xb3, 0x2f, 0xc9, 0xa8, 0x79, 0xe1, 0x71, 0xc0, 0x0e, 0x9c, 0x1b, 0x36,
0x7b, 0xb1, 0xd2, 0xe1, 0x5f, 0x0e, 0xa2, 0xef, 0x1a, 0x8f, 0xc7, 0x34, 0xcd, 0x2e, 0x57, 0x02,
0x7a, 0x19, 0xe7, 0x0b, 0x52, 0x0f, 0x9f, 0x62, 0xd6, 0xda, 0xac, 0x2e, 0xc1, 0xb3, 0x5b, 0xe9,
0xc0, 0xbe, 0x33, 0x2e, 0xcb, 0x7c, 0x35, 0x25, 0xf3, 0x32, 0x47, 0xfb, 0x8e, 0x83, 0x84, 0xfb,
0x0e, 0x44, 0x61, 0x56, 0x3e, 0xa5, 0x4d, 0xce, 0xef, 0xcd, 0xca, 0xb9, 0x28, 0x9c, 0x95, 0x2b,
0x04, 0xe6, 0x4a, 0x53, 0xba, 0x4b, 0xf3, 0x9c, 0x24, 0xac, 0x7d, 0x6e, 0x43, 0x6b, 0x1a, 0x22,
0x9c, 0x2b, 0x01, 0xd2, 0xec, 0xca, 0xa9, 0x35, 0x64, 0x5c, 0x91, 0xe7, 0xab, 0xa3, 0xac, 0xb8,
0x1e, 0xfa, 0xd3, 0x02, 0x03, 0x20, 0xbb, 0x72, 0x5e, 0x10, 0xae, 0x55, 0xcf, 0x8b, 0x94, 0xfa,
0xd7, 0xaa, 0x8d, 0x24, 0xbc, 0x56, 0x95, 0x04, 0x34, 0x79, 0x46, 0x30, 0x93, 0x8d, 0x24, 0x6c,
0x52, 0x12, 0xbe, 0xa1, 0x50, 0xbe, 0xbb, 0x41, 0x87, 0x42, 0xf0, 0xb6, 0x66, 0xbd, 0x93, 0x83,
0x11, 0xaa, 0x16, 0xad, 0xfb, 0x84, 0x25, 0x57, 0xfe, 0x08, 0x75, 0x90, 0x70, 0x84, 0x42, 0x14,
0x56, 0x69, 0x4a, 0xf5, 0xa2, 0x7b, 0xcd, 0x1f, 0x1f, 0xad, 0x05, 0xf7, 0x7a, 0x27, 0x07, 0x97,
0x91, 0x87, 0x73, 0xfe, 0xcc, 0xbc, 0x41, 0x2e, 0x64, 0xe1, 0x65, 0xa4, 0x66, 0x60, 0xe9, 0x85,
0x80, 0xef, 0x65, 0xad, 0xe1, 0x8a, 0xce, 0x6e, 0xd6, 0x7a, 0x27, 0x27, 0x9d, 0xfc, 0xa3, 0x5e,
0xc6, 0x09, 0xe9, 0x09, 0x6d, 0xfa, 0xc8, 0xcb, 0x38, 0xcf, 0xd2, 0x98, 0x91, 0x29, 0xbd, 0x26,
0x85, 0x7f, 0xc5, 0x24, 0x4b, 0x2b, 0xf8, 0x91, 0xa3, 0x10, 0x5e, 0x31, 0x85, 0x15, 0x61, 0x9c,
0x08, 0xfa, 0xbc, 0x26, 0xbb, 0x71, 0x8d, 0x8c, 0x64, 0x0e, 0x12, 0x8e, 0x13, 0x88, 0xc2, 0x7c,
0x55, 0xc8, 0x5f, 0xbc, 0x2e, 0x49, 0x95, 0x91, 0x22, 0x21, 0xfe, 0x7c, 0x15, 0x52, 0xe1, 0x7c,
0xd5, 0x43, 0xc3, 0xb5, 0xda, 0x5e, 0xcc, 0xc8, 0xf3, 0xd5, 0x34, 0x9b, 0x93, 0x9a, 0xc5, 0xf3,
0xd2, 0xbf, 0x56, 0x03, 0x50, 0x78, 0xad, 0xd6, 0x86, 0x5b, 0x5b, 0x43, 0x7a, 0x40, 0x6c, 0x1f,
0xf7, 0x82, 0x44, 0xe0, 0xb8, 0x17, 0x82, 0xc2, 0x07, 0x6b, 0x00, 0xef, 0x4b, 0x82, 0x96, 0x95,
0xe0, 0x4b, 0x02, 0x9c, 0x6e, 0x6d, 0xb8, 0x69, 0x66, 0xd2, 0x74, 0xcd, 0x8e, 0xa2, 0x4f, 0xec,
0x2e, 0xba, 0xd9, 0x8b, 0xf5, 0xef, 0xf0, 0x9d, 0x91, 0x3c, 0xe6, 0xd3, 0x56, 0x60, 0x1b, 0x4d,
0x31, 0x7d, 0x76, 0xf8, 0x2c, 0x56, 0x3a, 0xfc, 0xd3, 0x41, 0xf4, 0x9e, 0xcf, 0xe3, 0x17, 0x25,
0xf7, 0xfb, 0xa4, 0xdb, 0x96, 0x20, 0x91, 0xf3, 0x6c, 0x61, 0x0d, 0x73, 0x24, 0x43, 0x89, 0xcc,
0x71, 0x37, 0x59, 0x00, 0x37, 0x69, 0xd3, 0xe5, 0x87, 0x1c, 0x72, 0x24, 0x23, 0xc4, 0x9b, 0xf5,
0x90, 0x5b, 0xae, 0x1a, 0xac, 0x87, 0xb4, 0x0d, 0x29, 0x46, 0xd6, 0x43, 0x1e, 0xcc, 0xf4, 0x4e,
0xbb, 0x7a, 0xaf, 0x32, 0x76, 0xc5, 0xf3, 0x2d, 0xd0, 0x3b, 0x9d, 0xb2, 0x6a, 0x08, 0xe9, 0x9d,
0x28, 0x0c, 0x33, 0x12, 0x05, 0x36, 0x7d, 0xd3, 0x37, 0x96, 0x6b, 0x43, 0x76, 0xcf, 0xdc, 0xe8,
0x06, 0x61, 0xbc, 0x2a, 0xb1, 0x5c, 0xfa, 0x3c, 0x0e, 0x59, 0x00, 0xcb, 0x9f, 0xcd, 0x5e, 0xac,
0x74, 0xf8, 0xc7, 0xd1, 0x77, 0x5a, 0x15, 0xdb, 0x27, 0x31, 0x5b, 0x54, 0x24, 0x1d, 0xee, 0x74,
0x94, 0x5b, 0x81, 0xda, 0xf5, 0x93, 0xfe, 0x0a, 0xad, 0x1c, 0x5d, 0x71, 0x22, 0xac, 0x74, 0x19,
0x9e, 0x86, 0x4c, 0xba, 0x6c, 0x30, 0x47, 0xc7, 0x75, 0x5a, 0xcb, 0x6c, 0x3b, 0xba, 0xc6, 0xcb,
0x38, 0xcb, 0xf9, 0xcb, 0xda, 0x0f, 0x43, 0x46, 0x1d, 0x34, 0xb8, 0xcc, 0x46, 0x55, 0x5a, 0x23,
0x33, 0xef, 0xe3, 0xd6, 0xf2, 0x6c, 0x0b, 0x1f, 0x09, 0x3c, 0xab, 0xb3, 0xed, 0x9e, 0xb4, 0x74,
0xcb, 0xd4, 0x94, 0xd7, 0xfc, 0xd9, 0x0e, 0x72, 0x9f, 0x57, 0xa9, 0xea, 0x89, 0xf4, 0xed, 0x9e,
0xb4, 0xf4, 0xfa, 0x47, 0xd1, 0xbb, 0x6d, 0xaf, 0x72, 0x22, 0xda, 0xe9, 0x34, 0x05, 0xe6, 0xa2,
0x27, 0xfd, 0x15, 0xa4, 0xfb, 0x7f, 0xd1, 0xfb, 0xd2, 0xc2, 0x7f, 0x42, 0xe7, 0x73, 0x52, 0xa4,
0x24, 0x55, 0x1a, 0x75, 0xb3, 0x7e, 0xfa, 0x0c, 0xb7, 0xab, 0x15, 0x46, 0xb6, 0x86, 0x2e, 0xd1,
0x6f, 0x7e, 0x03, 0x4d, 0x59, 0xb4, 0xff, 0x1c, 0x44, 0x8f, 0xbc, 0x45, 0x53, 0x81, 0xeb, 0x14,
0xf1, 0x77, 0xfa, 0x38, 0xf2, 0x69, 0xea, 0xa2, 0x8e, 0xff, 0x1f, 0x16, 0x64, 0x91, 0xff, 0x75,
0x10, 0xdd, 0x37, 0x8a, 0x4d, 0x78, 0xef, 0xd2, 0xe2, 0x32, 0xcf, 0x12, 0xc6, 0xdf, 0xc8, 0x4a,
0x15, 0xfc, 0x71, 0x62, 0x1a, 0xdd, 0x8f, 0x33, 0xa0, 0x69, 0x16, 0xaf, 0x9f, 0x67, 0x35, 0xa3,
0xd5, 0x6a, 0x72, 0x45, 0x6f, 0xd4, 0x07, 0x43, 0xee, 0xb8, 0x2c, 0x81, 0x91, 0x45, 0x20, 0x8b,
0x57, 0x3f, 0xd9, 0x72, 0x65, 0x3e, 0x2c, 0xaa, 0x11, 0x57, 0x16, 0xd1, 0xe1, 0xca, 0x25, 0xcd,
0xac, 0xa4, 0x6a, 0x65, 0xbe, 0x82, 0x5a, 0xf7, 0x17, 0xb5, 0xfd, 0x25, 0xd4, 0x46, 0x37, 0x68,
0x72, 0x53, 0x29, 0xde, 0xcb, 0x2e, 0x2f, 0x75, 0x9d, 0xfc, 0x25, 0xb5, 0x11, 0x24, 0x37, 0x45,
0x50, 0xb3, 0xbc, 0xda, 0xcf, 0x72, 0xc2, 0xdf, 0xdd, 0x7c, 0x71, 0x79, 0x99, 0xd3, 0x38, 0x05,
0xcb, 0xab, 0x46, 0x3c, 0xb2, 0xe5, 0xc8, 0xf2, 0xca, 0xc7, 0x99, 0x53, 0x21, 0x8d, 0xb4, 0x89,
0xee, 0x22, 0xc9, 0x72, 0x78, 0xde, 0x98, 0x6b, 0x6a, 0x21, 0x72, 0x2a, 0xa4, 0x05, 0x99, 0x14,
0xa8, 0x11, 0x35, 0x51, 0xa9, 0xca, 0xff, 0xb0, 0xad, 0x68, 0x89, 0x91, 0x14, 0xc8, 0x83, 0x99,
0x5d, 0x86, 0x46, 0x78, 0x5e, 0x72, 0xe3, 0xf7, 0xda, 0x5a, 0x42, 0x82, 0xec, 0x32, 0xb8, 0x84,
0x59, 0x2d, 0x37, 0x7f, 0xdf, 0xa3, 0x37, 0x05, 0x37, 0x7a, 0xbf, 0xad, 0xa2, 0x64, 0xc8, 0x6a,
0x19, 0x32, 0xd2, 0xf0, 0x8f, 0xa2, 0x9f, 0xe7, 0x86, 0x2b, 0x5a, 0x0e, 0xef, 0x78, 0x14, 0x2a,
0xeb, 0x74, 0xee, 0x5d, 0x54, 0x6e, 0x0e, 0x91, 0xe8, 0xd8, 0x38, 0xaf, 0xe3, 0x19, 0x3c, 0x52,
0x6f, 0x5a, 0x9c, 0x4b, 0x91, 0x43, 0x24, 0x6d, 0xca, 0x8d, 0x8a, 0x13, 0x9a, 0x4a, 0xeb, 0x9e,
0x1a, 0x6a, 0x61, 0x28, 0x2a, 0x6c, 0xc8, 0xa4, 0xad, 0x27, 0xf1, 0x32, 0x9b, 0xe9, 0xd4, 0x42,
0x0c, 0x60, 0x35, 0x48, 0x5b, 0x0d, 0x33, 0xb2, 0x20, 0x24, 0x6d, 0x45, 0x61, 0xe9, 0xf3, 0x1f,
0x06, 0xd1, 0x3d, 0xc3, 0x1c, 0xa8, 0x7d, 0xd9, 0xc3, 0xe2, 0x92, 0x36, 0x49, 0xee, 0x51, 0x56,
0x5c, 0xd7, 0xc3, 0x4f, 0x30, 0x93, 0x7e, 0x5e, 0x17, 0xe5, 0xd3, 0x5b, 0xeb, 0x99, 0xf5, 0x89,
0xda, 0xb4, 0x34, 0x27, 0x17, 0x84, 0x06, 0x58, 0x9f, 0xe8, 0xbd, 0x4d, 0xc8, 0x21, 0xeb, 0x93,
0x10, 0x6f, 0x9a, 0x58, 0x3b, 0xcf, 0x69, 0x01, 0x9b, 0xd8, 0x58, 0x68, 0x84, 0x48, 0x13, 0xb7,
0x20, 0x33, 0x1e, 0x2b, 0x91, 0xd8, 0x5f, 0x1b, 0xe7, 0x39, 0x18, 0x8f, 0xb5, 0xaa, 0x06, 0x90,
0xf1, 0xd8, 0x0b, 0x4a, 0x3f, 0x67, 0xd1, 0xb7, 0x9a, 0x47, 0x7a, 0x5a, 0x91, 0x65, 0x46, 0xe0,
0x21, 0x1b, 0x4b, 0x82, 0xf4, 0x7f, 0x97, 0x30, 0x3d, 0xeb, 0xbc, 0xa8, 0xcb, 0x3c, 0xae, 0xaf,
0xe4, 0xb1, 0x0b, 0xb7, 0xce, 0x4a, 0x08, 0x0f, 0x5e, 0x3c, 0xec, 0xa0, 0xcc, 0xa0, 0xae, 0x64,
0x7a, 0x88, 0x59, 0xf3, 0xab, 0xb6, 0x86, 0x99, 0xf5, 0x4e, 0xce, 0xbc, 0xdb, 0x38, 0x88, 0xf3,
0x9c, 0x54, 0x2b, 0x25, 0x3b, 0x8e, 0x8b, 0xec, 0x92, 0xd4, 0x0c, 0xbc, 0xdb, 0x90, 0xd4, 0x08,
0x62, 0xc8, 0xbb, 0x8d, 0x00, 0x6e, 0xd6, 0x6d, 0xc0, 0xf3, 0x61, 0x91, 0x92, 0xd7, 0x60, 0xdd,
0x06, 0xed, 0x70, 0x06, 0x59, 0xb7, 0x61, 0xac, 0xd9, 0xe3, 0x7f, 0x9e, 0xd3, 0xe4, 0x5a, 0x4e,
0x01, 0x6e, 0x03, 0x73, 0x09, 0x9c, 0x03, 0xee, 0x87, 0x10, 0x33, 0x09, 0x70, 0xc1, 0x19, 0x29,
0xf3, 0x38, 0x81, 0x27, 0xad, 0x84, 0x8e, 0x94, 0x21, 0x93, 0x00, 0x64, 0x40, 0x71, 0xe5, 0x09,
0x2e, 0x5f, 0x71, 0xc1, 0x01, 0xae, 0xfb, 0x21, 0xc4, 0x4c, 0x83, 0x5c, 0x30, 0x29, 0xf3, 0x8c,
0x81, 0x6e, 0x20, 0x34, 0xb8, 0x04, 0xe9, 0x06, 0x2e, 0x01, 0x4c, 0x1e, 0x93, 0x6a, 0x46, 0xbc,
0x26, 0xb9, 0x24, 0x68, 0x52, 0x11, 0xe6, 0x58, 0xb9, 0xa8, 0x3b, 0x2d, 0x57, 0xe0, 0x58, 0xb9,
0xac, 0x16, 0x2d, 0x57, 0xc8, 0xb1, 0x72, 0x07, 0x00, 0x45, 0x3c, 0x8d, 0x6b, 0xe6, 0x2f, 0x22,
0x97, 0x04, 0x8b, 0xa8, 0x08, 0x33, 0x47, 0x8b, 0x22, 0x2e, 0x18, 0x98, 0xa3, 0x65, 0x01, 0xac,
0xb3, 0x06, 0x77, 0x51, 0xb9, 0x19, 0x49, 0x44, 0xab, 0x10, 0xb6, 0x9f, 0x91, 0x3c, 0xad, 0xc1,
0x48, 0x22, 0x9f, 0xbb, 0x92, 0x22, 0x23, 0x49, 0x9b, 0x02, 0xa1, 0x24, 0xdf, 0x84, 0xf8, 0x6a,
0x07, 0x5e, 0x82, 0xdc, 0x0f, 0x21, 0x66, 0x7c, 0x52, 0x85, 0xde, 0x8d, 0xab, 0x2a, 0x6b, 0x26,
0xff, 0x35, 0x7f, 0x81, 0x94, 0x1c, 0x19, 0x9f, 0x7c, 0x1c, 0xe8, 0x5e, 0x6a, 0xe0, 0xf6, 0x15,
0x0c, 0x0e, 0xdd, 0x1f, 0x04, 0x19, 0x93, 0x71, 0x72, 0x89, 0xf5, 0xb2, 0xdc, 0xf7, 0x34, 0x3d,
0xef, 0xca, 0xd7, 0xba, 0x30, 0xeb, 0x9b, 0x33, 0xed, 0xe2, 0x98, 0x2e, 0xc9, 0x94, 0xbe, 0x78,
0x9d, 0xd5, 0xcd, 0x72, 0x4b, 0xce, 0xdc, 0xcf, 0x10, 0x4b, 0x3e, 0x18, 0xf9, 0xe6, 0xac, 0x53,
0xc9, 0x24, 0x10, 0xa0, 0x2c, 0x27, 0xe4, 0xc6, 0x9b, 0x40, 0x40, 0x8b, 0x9a, 0x43, 0x12, 0x88,
0x10, 0x6f, 0x76, 0xcc, 0xb4, 0x73, 0x79, 0xd1, 0xc0, 0x94, 0xaa, 0x5c, 0x0e, 0xb3, 0x06, 0x41,
0x64, 0xd3, 0x22, 0xa8, 0x60, 0xd6, 0x97, 0xda, 0xbf, 0xe9, 0x62, 0x1b, 0x88, 0x9d, 0x76, 0x37,
0x7b, 0xd4, 0x83, 0xf4, 0xb8, 0x32, 0x27, 0x3e, 0x30, 0x57, 0xed, 0x03, 0x1f, 0x8f, 0x7a, 0x90,
0xd6, 0xee, 0x9b, 0x5d, 0xad, 0xe7, 0x71, 0x72, 0x3d, 0xab, 0xe8, 0xa2, 0x48, 0x77, 0x69, 0x4e,
0x2b, 0xb0, 0xfb, 0xe6, 0x94, 0x1a, 0xa0, 0xc8, 0xee, 0x5b, 0x87, 0x8a, 0xc9, 0xe0, 0xec, 0x52,
0x8c, 0xf3, 0x6c, 0x06, 0x57, 0xd4, 0x8e, 0x21, 0x0e, 0x20, 0x19, 0x9c, 0x17, 0xf4, 0x04, 0x91,
0x58, 0x71, 0xb3, 0x2c, 0x89, 0x73, 0xe1, 0x6f, 0x07, 0x37, 0xe3, 0x80, 0x9d, 0x41, 0xe4, 0x51,
0xf0, 0xd4, 0x73, 0xba, 0xa8, 0x8a, 0xc3, 0x82, 0x51, 0xb4, 0x9e, 0x0a, 0xe8, 0xac, 0xa7, 0x05,
0x82, 0x61, 0x75, 0x4a, 0x5e, 0x37, 0xa5, 0x69, 0xfe, 0xf1, 0x0d, 0xab, 0xcd, 0xdf, 0x47, 0x52,
0x1e, 0x1a, 0x56, 0x01, 0x07, 0x2a, 0x23, 0x9d, 0x88, 0x80, 0x09, 0x68, 0xbb, 0x61, 0xb2, 0xd1,
0x0d, 0xfa, 0xfd, 0x4c, 0xd8, 0x2a, 0x27, 0x21, 0x3f, 0x1c, 0xe8, 0xe3, 0x47, 0x81, 0x66, 0xbb,
0xc5, 0xa9, 0xcf, 0x15, 0x49, 0xae, 0x5b, 0x07, 0xd8, 0xdc, 0x82, 0x0a, 0x04, 0xd9, 0x6e, 0x41,
0x50, 0x7f, 0x13, 0x1d, 0x26, 0xb4, 0x08, 0x35, 0x51, 0x23, 0xef, 0xd3, 0x44, 0x92, 0x33, 0x8b,
0x5f, 0x2d, 0x95, 0x91, 0x29, 0x9a, 0x69, 0x13, 0xb1, 0x60, 0x43, 0xc8, 0xe2, 0x17, 0x85, 0x4d,
0x4e, 0x0e, 0x7d, 0x1e, 0xb7, 0x4f, 0xf7, 0xb7, 0xac, 0x1c, 0xe3, 0xa7, 0xfb, 0x31, 0x16, 0xaf,
0xa4, 0x88, 0x91, 0x0e, 0x2b, 0x6e, 0x9c, 0x6c, 0xf5, 0x83, 0xcd, 0x92, 0xc7, 0xf1, 0xb9, 0x9b,
0x93, 0xb8, 0x12, 0x5e, 0xb7, 0x03, 0x86, 0x0c, 0x86, 0x2c, 0x79, 0x02, 0x38, 0x18, 0xc2, 0x1c,
0xcf, 0xbb, 0xb4, 0x60, 0xa4, 0x60, 0xbe, 0x21, 0xcc, 0x35, 0x26, 0xc1, 0xd0, 0x10, 0x86, 0x29,
0x80, 0xb8, 0xe5, 0xfb, 0x41, 0x84, 0x9d, 0xc4, 0x73, 0x6f, 0xc6, 0x26, 0xf6, 0x7a, 0x84, 0x3c,
0x14, 0xb7, 0x80, 0xb3, 0x5e, 0xe7, 0xda, 0x5e, 0xa6, 0x71, 0x35, 0xd3, 0xbb, 0x1b, 0xe9, 0xf0,
0x09, 0x6e, 0xc7, 0x25, 0x91, 0xd7, 0xb9, 0x61, 0x0d, 0x30, 0xec, 0x1c, 0xce, 0xe3, 0x99, 0xae,
0xa9, 0xa7, 0x06, 0x5c, 0xde, 0xaa, 0xea, 0x46, 0x37, 0x08, 0xfc, 0xbc, 0xcc, 0x52, 0x42, 0x03,
0x7e, 0xb8, 0xbc, 0x8f, 0x1f, 0x08, 0x82, 0xec, 0xad, 0xa9, 0xb7, 0x58, 0xd1, 0x8d, 0x8b, 0x54,
0xae, 0x63, 0x47, 0xc8, 0xe3, 0x01, 0x5c, 0x28, 0x7b, 0x43, 0x78, 0xd0, 0x47, 0xd5, 0x06, 0x6d,
0xa8, 0x8f, 0xea, 0xfd, 0xd7, 0x3e, 0x7d, 0xd4, 0x07, 0x4b, 0x9f, 0x3f, 0x91, 0x7d, 0x74, 0x2f,
0x66, 0x71, 0x93, 0xb7, 0xbf, 0xcc, 0xc8, 0x8d, 0x5c, 0x08, 0x7b, 0xea, 0xab, 0xa8, 0x11, 0xff,
0x38, 0x19, 0xac, 0x8a, 0x77, 0x7a, 0xf3, 0x01, 0xdf, 0x72, 0x85, 0xd0, 0xe9, 0x1b, 0x2c, 0x15,
0x76, 0x7a, 0xf3, 0x01, 0xdf, 0xf2, 0xd6, 0x83, 0x4e, 0xdf, 0xe0, 0xea, 0x83, 0x9d, 0xde, 0xbc,
0xf4, 0xfd, 0x67, 0xaa, 0xe3, 0xda, 0xce, 0x9b, 0x3c, 0x2c, 0x61, 0xd9, 0x92, 0xf8, 0xd2, 0x49,
0xd7, 0x9e, 0x46, 0x43, 0xe9, 0x24, 0xae, 0x62, 0xdd, 0x3b, 0xe6, 0x2b, 0xc5, 0x29, 0xad, 0x33,
0x7e, 0x1c, 0xe3, 0x59, 0x0f, 0xa3, 0x0a, 0x0e, 0x2d, 0x9a, 0x42, 0x4a, 0xe6, 0xc5, 0xb2, 0x83,
0x9a, 0xf3, 0xea, 0x5b, 0x01, 0x7b, 0xed, 0x63, 0xeb, 0xdb, 0x3d, 0x69, 0xf3, 0x8a, 0xd7, 0x61,
0xec, 0x77, 0xcb, 0xa1, 0x56, 0xf5, 0xbe, 0x5e, 0x7e, 0xd2, 0x5f, 0x41, 0xba, 0xff, 0x0b, 0xb5,
0xae, 0x80, 0xfe, 0x65, 0x27, 0x78, 0xda, 0xc7, 0x22, 0xe8, 0x08, 0xcf, 0x6e, 0xa5, 0x23, 0x0b,
0xf2, 0x37, 0x6a, 0x01, 0xad, 0x50, 0xfe, 0xd5, 0x0e, 0xff, 0xda, 0x57, 0xf6, 0x89, 0x50, 0xb3,
0x1a, 0x18, 0xf6, 0x8c, 0x8f, 0x6f, 0xa9, 0x65, 0xdd, 0x42, 0xe7, 0xc0, 0xf2, 0xeb, 0x52, 0xab,
0x3c, 0x21, 0xcb, 0x16, 0x0d, 0x0b, 0xf4, 0xc9, 0x6d, 0xd5, 0xb0, 0xbe, 0x62, 0xc1, 0xfc, 0x1e,
0x96, 0x67, 0x3d, 0x0d, 0x3b, 0x37, 0xb3, 0x7c, 0x74, 0x3b, 0x25, 0x59, 0x96, 0x7f, 0x1f, 0x44,
0x0f, 0x1d, 0xd6, 0xbc, 0x4f, 0x00, 0xbb, 0x1e, 0x3f, 0x08, 0xd8, 0xc7, 0x94, 0x74, 0xe1, 0x7e,
0xeb, 0x9b, 0x29, 0x9b, 0x2b, 0xdb, 0x1c, 0x95, 0xfd, 0x2c, 0x67, 0xa4, 0x6a, 0x5f, 0xd9, 0xe6,
0xda, 0x15, 0xd4, 0x08, 0xbf, 0xb2, 0x2d, 0x80, 0x5b, 0x57, 0xb6, 0x79, 0x3c, 0x7b, 0xaf, 0x6c,
0xf3, 0x5a, 0x0b, 0x5e, 0xd9, 0x16, 0xd6, 0xc0, 0x86, 0x77, 0x55, 0x04, 0xb1, 0x6f, 0xdd, 0xcb,
0xa2, 0xbb, 0x8d, 0xfd, 0xf4, 0x36, 0x2a, 0xc8, 0x04, 0x27, 0x38, 0x7e, 0xa2, 0xb1, 0xc7, 0x33,
0x75, 0x4e, 0x35, 0xee, 0xf4, 0xe6, 0xa5, 0xef, 0x1f, 0xcb, 0xd5, 0x8d, 0x1e, 0xce, 0x69, 0xc5,
0xaf, 0xeb, 0xdb, 0x0c, 0x0d, 0xcf, 0x8d, 0x05, 0xbb, 0xe5, 0xb7, 0xfa, 0xc1, 0x48, 0x75, 0x1b,
0x42, 0x36, 0xfa, 0xa8, 0xcb, 0x10, 0x68, 0xf2, 0x9d, 0xde, 0x3c, 0x32, 0x8d, 0x08, 0xdf, 0xa2,
0xb5, 0x7b, 0x18, 0x73, 0xdb, 0xfa, 0x49, 0x7f, 0x05, 0xe9, 0x7e, 0x29, 0xd3, 0x46, 0xdb, 0x3d,
0x6f, 0xe7, 0xed, 0x2e, 0x53, 0x13, 0xa7, 0x99, 0x47, 0x7d, 0xf1, 0x50, 0x02, 0x61, 0x4f, 0xa1,
0x5d, 0x09, 0x84, 0x77, 0x1a, 0xfd, 0xe8, 0x76, 0x4a, 0xb2, 0x2c, 0x7f, 0x3f, 0x88, 0xee, 0xa2,
0x65, 0x91, 0x71, 0xf0, 0x49, 0x5f, 0xcb, 0x20, 0x1e, 0x3e, 0xbd, 0xb5, 0x9e, 0x2c, 0xd4, 0x3f,
0x0d, 0xa2, 0x7b, 0x81, 0x42, 0x89, 0x00, 0xb9, 0x85, 0x75, 0x37, 0x50, 0x3e, 0xbb, 0xbd, 0x22,
0x36, 0xdd, 0xdb, 0xf8, 0xa4, 0x7d, 0xfd, 0x56, 0xc0, 0xf6, 0x04, 0xbf, 0x7e, 0xab, 0x5b, 0x0b,
0x6e, 0xf2, 0xc4, 0x17, 0x6a, 0xd1, 0xe5, 0xdd, 0xe4, 0xe1, 0x67, 0x11, 0x83, 0xd7, 0x88, 0xf8,
0x38, 0x9f, 0x93, 0x17, 0xaf, 0xcb, 0xb8, 0x48, 0x71, 0x27, 0x42, 0xde, 0xed, 0x44, 0x73, 0x70,
0x73, 0xac, 0x91, 0x9e, 0x51, 0xb5, 0x90, 0x7a, 0x84, 0xe9, 0x6b, 0x24, 0xb8, 0x39, 0xd6, 0x42,
0x11, 0x6f, 0x32, 0x6b, 0x0c, 0x79, 0x03, 0xc9, 0xe2, 0xe3, 0x3e, 0x28, 0x48, 0xd1, 0xb5, 0x37,
0xbd, 0xe7, 0xbe, 0x15, 0xb2, 0xd2, 0xda, 0x77, 0xdf, 0xee, 0x49, 0x23, 0x6e, 0x27, 0x84, 0x7d,
0x4e, 0xe2, 0x94, 0x54, 0x41, 0xb7, 0x9a, 0xea, 0xe5, 0xd6, 0xa6, 0x7d, 0x6e, 0x77, 0x69, 0xbe,
0x98, 0x17, 0xb2, 0x31, 0x51, 0xb7, 0x36, 0xd5, 0xed, 0x16, 0xd0, 0x70, 0x5b, 0xd0, 0xb8, 0xe5,
0xe9, 0xe5, 0xe3, 0xb0, 0x19, 0x27, 0xab, 0xdc, 0xec, 0xc5, 0xe2, 0xf5, 0x94, 0x61, 0xd4, 0x51,
0x4f, 0x10, 0x49, 0xdb, 0x3d, 0x69, 0xb8, 0x3f, 0x67, 0xb9, 0xd5, 0xf1, 0xb4, 0xd3, 0x61, 0xab,
0x15, 0x52, 0x4f, 0xfa, 0x2b, 0xc0, 0xdd, 0x50, 0x19, 0x55, 0x47, 0x59, 0xcd, 0xf6, 0xb3, 0x3c,
0x1f, 0x6e, 0x06, 0xc2, 0x44, 0x41, 0xc1, 0xdd, 0x50, 0x0f, 0x8c, 0x44, 0xb2, 0xda, 0x3d, 0x2c,
0x86, 0x5d, 0x76, 0x38, 0xd5, 0x2b, 0x92, 0x6d, 0x1a, 0xec, 0x68, 0x59, 0x8f, 0x5a, 0xd7, 0x76,
0x14, 0x7e, 0x70, 0xad, 0x0a, 0xef, 0xf4, 0xe6, 0xc1, 0xeb, 0x76, 0x4e, 0xf1, 0x99, 0xe5, 0x01,
0x66, 0xc2, 0x99, 0x49, 0x1e, 0x76, 0x50, 0x60, 0x57, 0x50, 0x74, 0xa3, 0x57, 0x59, 0x3a, 0x23,
0xcc, 0xfb, 0xa6, 0xc8, 0x06, 0x82, 0x6f, 0x8a, 0x00, 0x08, 0x9a, 0x4e, 0xfc, 0x5d, 0x6f, 0x87,
0x1e, 0xa6, 0xbe, 0xa6, 0x93, 0xca, 0x16, 0x15, 0x6a, 0x3a, 0x2f, 0x0d, 0x46, 0x03, 0xed, 0x56,
0x5e, 0xbc, 0xf0, 0x38, 0x64, 0x06, 0xdc, 0xbe, 0xb0, 0xd9, 0x8b, 0x05, 0x33, 0x8a, 0x71, 0x98,
0xcd, 0x33, 0xe6, 0x9b, 0x51, 0x2c, 0x1b, 0x0d, 0x12, 0x9a, 0x51, 0xda, 0x28, 0x56, 0xbd, 0x26,
0x47, 0x38, 0x4c, 0xc3, 0xd5, 0x13, 0x4c, 0xbf, 0xea, 0x69, 0xb6, 0xf5, 0x62, 0xb3, 0xd0, 0x21,
0xc3, 0xae, 0xe4, 0x62, 0xd9, 0x13, 0xdb, 0xfc, 0x83, 0x5c, 0x08, 0x86, 0x46, 0x1d, 0x4c, 0x01,
0x6e, 0xd8, 0x37, 0x9c, 0x7a, 0xf7, 0x5a, 0x96, 0x24, 0xae, 0xe2, 0x22, 0xf1, 0x2e, 0x4e, 0xb9,
0xc1, 0x16, 0x19, 0x5a, 0x9c, 0xa2, 0x1a, 0xe0, 0xb5, 0xb9, 0xfb, 0x29, 0xad, 0xa7, 0x2b, 0xe8,
0x6f, 0x56, 0xdd, 0x2f, 0x69, 0x1f, 0xf5, 0x20, 0xe1, 0x6b, 0x73, 0x05, 0xe8, 0x8d, 0x6f, 0xe1,
0xf4, 0xc3, 0x80, 0x29, 0x17, 0x0d, 0x2d, 0x84, 0x71, 0x15, 0x10, 0xd4, 0x3a, 0xc1, 0x25, 0xec,
0x47, 0x64, 0xe5, 0x0b, 0x6a, 0x93, 0x9f, 0x72, 0x24, 0x14, 0xd4, 0x6d, 0x14, 0xe4, 0x99, 0xf6,
0x3a, 0x68, 0x2d, 0xa0, 0x6f, 0x2f, 0x7d, 0xd6, 0x3b, 0x39, 0xd0, 0x73, 0xf6, 0xb2, 0xa5, 0xf3,
0x9e, 0xc0, 0x53, 0xd0, 0xbd, 0x6c, 0xe9, 0x7f, 0x4d, 0xb0, 0xd9, 0x8b, 0x85, 0xaf, 0xe4, 0x63,
0x46, 0x5e, 0xab, 0x77, 0xe5, 0x9e, 0xe2, 0x72, 0x79, 0xeb, 0x65, 0xf9, 0x46, 0x37, 0x68, 0x0e,
0xc0, 0x9e, 0x56, 0x34, 0x21, 0x75, 0x2d, 0xef, 0x24, 0x75, 0x4f, 0x18, 0x49, 0xd9, 0x08, 0xdc,
0x48, 0xfa, 0x20, 0x0c, 0x59, 0x17, 0x09, 0x0a, 0x91, 0xb9, 0xdf, 0x68, 0xcd, 0xab, 0xd9, 0xbe,
0xda, 0x68, 0xbd, 0x93, 0x33, 0xdd, 0x4b, 0x4a, 0xed, 0x0b, 0x8d, 0x36, 0xbc, 0xea, 0xbe, 0xbb,
0x8c, 0x1e, 0xf5, 0x20, 0xa5, 0xab, 0xcf, 0xa3, 0x37, 0x8f, 0xe8, 0x6c, 0x42, 0x8a, 0x74, 0xf8,
0x3d, 0xf7, 0x08, 0x2d, 0x9d, 0x8d, 0x9a, 0x3f, 0x6b, 0xa3, 0x77, 0x30, 0xb1, 0x39, 0x04, 0xb8,
0x47, 0x2e, 0x16, 0xb3, 0x09, 0x8b, 0x19, 0x38, 0x04, 0xc8, 0xff, 0x3e, 0x6a, 0x04, 0xc8, 0x21,
0x40, 0x07, 0x00, 0xf6, 0xa6, 0x15, 0x21, 0x5e, 0x7b, 0x8d, 0x20, 0x68, 0x4f, 0x02, 0x26, 0x8b,
0xd0, 0xf6, 0x9a, 0x44, 0x1d, 0x1e, 0xda, 0x33, 0x3a, 0x5c, 0x8a, 0x64, 0x11, 0x6d, 0xca, 0x04,
0xb7, 0xa8, 0x3e, 0xbf, 0x5f, 0x66, 0x31, 0x9f, 0xc7, 0xd5, 0x0a, 0x04, 0xb7, 0xac, 0xa5, 0x05,
0x20, 0xc1, 0xed, 0x05, 0x4d, 0xaf, 0x55, 0x8f, 0x39, 0xb9, 0x3e, 0xa0, 0x15, 0x5d, 0xb0, 0xac,
0x20, 0xf0, 0x8e, 0x11, 0xfd, 0x40, 0x6d, 0x06, 0xe9, 0xb5, 0x18, 0x6b, 0xb2, 0x5c, 0x4e, 0x88,
0xf3, 0x84, 0xfc, 0x9a, 0xf4, 0x9a, 0xd1, 0x0a, 0xbe, 0x4f, 0x14, 0x56, 0x20, 0x84, 0x64, 0xb9,
0x28, 0x0c, 0xda, 0xfe, 0x34, 0x2b, 0x66, 0xde, 0xb6, 0x3f, 0xb5, 0xef, 0xf9, 0xbd, 0x87, 0x03,
0xa6, 0x43, 0x89, 0x87, 0x26, 0x3a, 0x80, 0xfc, 0x6a, 0xd7, 0xfb, 0xd0, 0x6d, 0x02, 0xe9, 0x50,
0x7e, 0x12, 0xb8, 0xfa, 0xa2, 0x24, 0x05, 0x49, 0xd5, 0xa9, 0x39, 0x9f, 0x2b, 0x87, 0x08, 0xba,
0x82, 0xa4, 0x19, 0x8b, 0xb8, 0xfc, 0x6c, 0x51, 0x9c, 0x56, 0xf4, 0x32, 0xcb, 0x49, 0x05, 0xc6,
0x22, 0xa1, 0x6e, 0xc9, 0x91, 0xb1, 0xc8, 0xc7, 0x99, 0xe3, 0x17, 0x5c, 0xea, 0xdc, 0xf5, 0x3f,
0xad, 0xe2, 0x04, 0x1e, 0xbf, 0x10, 0x36, 0xda, 0x18, 0xb2, 0x33, 0x18, 0xc0, 0xad, 0x44, 0x47,
0xb8, 0x2e, 0x56, 0x3c, 0x3e, 0xe4, 0x57, 0xa3, 0xfc, 0xf6, 0xdb, 0x1a, 0x24, 0x3a, 0xd2, 0x9c,
0x8f, 0x44, 0x12, 0x9d, 0xb0, 0x86, 0x99, 0x4a, 0x38, 0x77, 0x22, 0x8f, 0x15, 0x81, 0xa9, 0x44,
0xd8, 0x50, 0x42, 0x64, 0x2a, 0x69, 0x41, 0x60, 0x40, 0x52, 0xdd, 0x60, 0xe6, 0x1d, 0x90, 0xb4,
0x34, 0x38, 0x20, 0xd9, 0x94, 0x19, 0x28, 0x0e, 0x8b, 0x8c, 0x65, 0x71, 0x3e, 0x21, 0xec, 0x34,
0xae, 0xe2, 0x39, 0x61, 0xa4, 0x82, 0x03, 0x85, 0x44, 0x46, 0x0e, 0x83, 0x0c, 0x14, 0x18, 0x2b,
0x1d, 0xfe, 0x76, 0xf4, 0x76, 0x33, 0xef, 0x93, 0x42, 0xfe, 0x4a, 0xd1, 0x0b, 0xfe, 0xf3, 0x66,
0xc3, 0x77, 0xb4, 0x8d, 0x09, 0xab, 0x48, 0x3c, 0x57, 0xb6, 0xdf, 0xd2, 0x7f, 0xe7, 0xe0, 0x93,
0x41, 0x13, 0xcf, 0x27, 0x94, 0x65, 0x97, 0xcd, 0x32, 0x5b, 0x7e, 0x41, 0x04, 0xe2, 0xd9, 0x16,
0x8f, 0x02, 0xb7, 0x8e, 0xf8, 0x38, 0x33, 0x4e, 0xdb, 0xd2, 0x33, 0x52, 0xe6, 0x70, 0x9c, 0x76,
0xb4, 0x39, 0x80, 0x8c, 0xd3, 0x5e, 0xd0, 0x74, 0x4e, 0x5b, 0x3c, 0x25, 0xe1, 0xca, 0x4c, 0x49,
0xbf, 0xca, 0x4c, 0x9d, 0x8f, 0x32, 0xf2, 0xe8, 0xed, 0x63, 0x32, 0xbf, 0x20, 0x55, 0x7d, 0x95,
0x95, 0xd8, 0x0d, 0xbd, 0x86, 0xe8, 0xbc, 0xa1, 0x17, 0x41, 0xcd, 0x4c, 0x60, 0x80, 0xc3, 0xfa,
0x24, 0x9e, 0x13, 0x7e, 0x87, 0x0a, 0x98, 0x09, 0x2c, 0x23, 0x16, 0x84, 0xcc, 0x04, 0x28, 0x6c,
0x7d, 0xdf, 0x65, 0x98, 0x33, 0x32, 0x6b, 0x22, 0xac, 0x3a, 0x8d, 0x57, 0x73, 0x52, 0x30, 0x69,
0x12, 0xec, 0xc9, 0x5b, 0x26, 0xfd, 0x3c, 0xb2, 0x27, 0xdf, 0x47, 0xcf, 0x1a, 0x9a, 0x9c, 0x07,
0x7f, 0x4a, 0x2b, 0x26, 0x7e, 0x83, 0xec, 0xbc, 0xca, 0xc1, 0xd0, 0xe4, 0x3e, 0x54, 0x87, 0x44,
0x86, 0xa6, 0xb0, 0x86, 0xf5, 0x7b, 0x13, 0x4e, 0x19, 0x5e, 0x92, 0x4a, 0xc7, 0xc9, 0x8b, 0x79,
0x9c, 0xe5, 0x32, 0x1a, 0xbe, 0x1f, 0xb0, 0x8d, 0xe8, 0x20, 0xbf, 0x37, 0xd1, 0x57, 0xd7, 0xfa,
0x85, 0x8e, 0x70, 0x09, 0xc1, 0x2b, 0x82, 0x0e, 0xfb, 0xc8, 0x2b, 0x82, 0x6e, 0x2d, 0xb3, 0x72,
0x37, 0x2c, 0xe7, 0x56, 0x9c, 0xd8, 0xa5, 0x29, 0xdc, 0x2f, 0xb4, 0x6c, 0x02, 0x10, 0x59, 0xb9,
0x07, 0x15, 0x4c, 0x6a, 0x60, 0xb0, 0xfd, 0xac, 0x88, 0xf3, 0xec, 0x27, 0x30, 0xad, 0xb7, 0xec,
0x28, 0x02, 0x49, 0x0d, 0xfc, 0xa4, 0xcf, 0xd5, 0x01, 0x61, 0xd3, 0xac, 0x19, 0xfa, 0x37, 0x02,
0xcf, 0x8d, 0x13, 0xdd, 0xae, 0x2c, 0xd2, 0xba, 0x8d, 0x17, 0x3e, 0xd6, 0x71, 0x59, 0x4e, 0x9a,
0x59, 0xf5, 0x8c, 0x24, 0x24, 0x2b, 0xd9, 0xf0, 0xe3, 0xf0, 0xb3, 0x02, 0x38, 0x72, 0xd0, 0xa2,
0x87, 0x9a, 0xf5, 0xfa, 0xbe, 0x19, 0x4b, 0x26, 0xe2, 0xc7, 0x39, 0xcf, 0x6b, 0x52, 0xc9, 0x44,
0xe3, 0x80, 0x30, 0xd0, 0x3b, 0x2d, 0x6e, 0x64, 0x81, 0x4d, 0x45, 0x91, 0xde, 0x19, 0xd6, 0x30,
0x9b, 0x7d, 0x16, 0x27, 0x6f, 0x57, 0xe7, 0xe7, 0x0d, 0xb7, 0x50, 0x63, 0x16, 0x85, 0x6c, 0xf6,
0xe1, 0xb4, 0xc9, 0xd6, 0xda, 0x6e, 0xc7, 0xc5, 0xea, 0x10, 0x1e, 0x99, 0xf0, 0x58, 0xe2, 0x18,
0x92, 0xad, 0x05, 0x70, 0x6b, 0x33, 0xbc, 0xa2, 0x71, 0x9a, 0xc4, 0x35, 0x3b, 0x8d, 0x57, 0x39,
0x8d, 0x53, 0x3e, 0xaf, 0xc3, 0xcd, 0x70, 0xc5, 0x8c, 0x6c, 0x08, 0xdb, 0x0c, 0xc7, 0x60, 0x3b,
0x3b, 0xe3, 0xbf, 0x39, 0x2a, 0xcf, 0x72, 0xc2, 0xec, 0x8c, 0x97, 0x17, 0x9e, 0xe3, 0x7c, 0x10,
0x86, 0xcc, 0x37, 0x68, 0x42, 0xc4, 0xd3, 0x90, 0x7b, 0x3e, 0x1d, 0x27, 0x01, 0x79, 0x3f, 0x40,
0x98, 0x1b, 0x48, 0xc4, 0xdf, 0xd5, 0xcf, 0x4c, 0x31, 0x79, 0x67, 0xf9, 0x96, 0x4f, 0xd7, 0x86,
0x46, 0xf6, 0x45, 0x16, 0xdb, 0x3d, 0x69, 0x93, 0x66, 0xee, 0x5e, 0xc5, 0x6c, 0x9c, 0xa6, 0xc7,
0xa4, 0xf6, 0x7c, 0x50, 0xde, 0x08, 0x47, 0x46, 0x8a, 0xa4, 0x99, 0x6d, 0xca, 0x04, 0x7a, 0x23,
0x7b, 0x91, 0x66, 0x4c, 0xca, 0xd4, 0x09, 0xe9, 0xad, 0xb6, 0x81, 0x36, 0x85, 0xd4, 0x0a, 0xa7,
0xcd, 0x58, 0xde, 0x30, 0x53, 0x3a, 0x9b, 0xe5, 0x44, 0x42, 0x67, 0x24, 0x16, 0x57, 0x36, 0xee,
0xb4, 0x6d, 0x79, 0x41, 0x64, 0x2c, 0x0f, 0x2a, 0x98, 0x34, 0xb2, 0xc1, 0xc4, 0x2b, 0x29, 0xf5,
0x60, 0xd7, 0xdb, 0x66, 0x1c, 0x00, 0x49, 0x23, 0xbd, 0xa0, 0xf9, 0xee, 0xad, 0x11, 0x1f, 0x10,
0xf5, 0x24, 0xe0, 0x65, 0x53, 0x5c, 0xd9, 0x12, 0x23, 0xdf, 0xbd, 0x79, 0x30, 0xb3, 0x4e, 0x00,
0x1e, 0x9e, 0xaf, 0x0e, 0x53, 0xb8, 0x4e, 0x80, 0xfa, 0x9c, 0x41, 0xd6, 0x09, 0x18, 0xeb, 0x36,
0x9d, 0xde, 0xf7, 0x3a, 0x8a, 0x6b, 0x53, 0x39, 0x4f, 0xd3, 0x79, 0xc1, 0x50, 0xd3, 0x61, 0x0a,
0xee, 0x23, 0xb5, 0xb7, 0xd6, 0x3c, 0x8f, 0xd4, 0xb7, 0xaf, 0xb6, 0xd6, 0x85, 0x99, 0x71, 0x49,
0xaf, 0x27, 0xf9, 0x91, 0x25, 0xff, 0x6f, 0x35, 0x08, 0x21, 0x32, 0x2e, 0xb5, 0x20, 0x61, 0xfb,
0xf9, 0xfb, 0xff, 0xf5, 0xd5, 0x9d, 0xc1, 0xcf, 0xbe, 0xba, 0x33, 0xf8, 0x9f, 0xaf, 0xee, 0x0c,
0x7e, 0xfa, 0xf5, 0x9d, 0x37, 0x7e, 0xf6, 0xf5, 0x9d, 0x37, 0xfe, 0xfb, 0xeb, 0x3b, 0x6f, 0x7c,
0xf9, 0xa6, 0xfc, 0x2d, 0xea, 0x8b, 0x9f, 0xe3, 0xbf, 0x28, 0xfd, 0xec, 0xff, 0x02, 0x00, 0x00,
0xff, 0xff, 0xc9, 0x60, 0xbd, 0x6d, 0xaf, 0x7a, 0x00, 0x00,
// 5482 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x9d, 0x5f, 0x6f, 0x1d, 0x49,
0x56, 0xc0, 0xe7, 0xbe, 0x30, 0xd0, 0xcb, 0x0e, 0x70, 0x07, 0x86, 0xd9, 0x61, 0x37, 0xc9, 0x64,
0x12, 0x3b, 0x89, 0xe3, 0xeb, 0x4c, 0x32, 0xff, 0xd8, 0x45, 0x82, 0x1b, 0x3b, 0xf1, 0x78, 0xd7,
0xf6, 0x18, 0x5f, 0x3b, 0x91, 0x46, 0x42, 0xa2, 0xdd, 0x5d, 0xbe, 0x6e, 0xdc, 0xb7, 0xab, 0xb7,
0xbb, 0xae, 0x93, 0xbb, 0x08, 0x04, 0x02, 0x81, 0x40, 0x20, 0x56, 0xfc, 0x13, 0x3c, 0x21, 0xf1,
0x09, 0xf8, 0x18, 0x3c, 0xee, 0x03, 0x0f, 0x3c, 0xa2, 0x99, 0x6f, 0xc0, 0x27, 0x40, 0x5d, 0x5d,
0x7f, 0x4f, 0x9f, 0x53, 0xdd, 0x1e, 0x9e, 0x12, 0xf9, 0xfc, 0xce, 0x39, 0xf5, 0xe7, 0x54, 0xd5,
0xa9, 0xea, 0xea, 0xbe, 0xd1, 0xcd, 0xf2, 0x6c, 0xab, 0xac, 0xb8, 0xe0, 0xf5, 0x56, 0xcd, 0xaa,
0xab, 0x2c, 0x61, 0xfa, 0xdf, 0x89, 0xfc, 0xf3, 0xf8, 0xcd, 0xb8, 0x58, 0x89, 0x55, 0xc9, 0xde,
0x7b, 0xd7, 0x92, 0x09, 0x5f, 0x2c, 0xe2, 0x22, 0xad, 0x5b, 0xe4, 0xbd, 0x77, 0xac, 0x84, 0x5d,
0xb1, 0x42, 0xa8, 0xbf, 0x3f, 0xfe, 0xaf, 0xff, 0x1d, 0x45, 0x6f, 0x6d, 0xe7, 0x19, 0x2b, 0xc4,
0xb6, 0xd2, 0x18, 0x7f, 0x19, 0x7d, 0x7b, 0x5a, 0x96, 0xbb, 0x4c, 0xbc, 0x60, 0x55, 0x9d, 0xf1,
0x62, 0xfc, 0xc1, 0x44, 0x39, 0x98, 0x1c, 0x97, 0xc9, 0x64, 0x5a, 0x96, 0x13, 0x2b, 0x9c, 0x1c,
0xb3, 0x1f, 0x2f, 0x59, 0x2d, 0xde, 0xbb, 0x13, 0x86, 0xea, 0x92, 0x17, 0x35, 0x1b, 0x9f, 0x47,
0xbf, 0x32, 0x2d, 0xcb, 0x19, 0x13, 0x3b, 0xac, 0xa9, 0xc0, 0x4c, 0xc4, 0x82, 0x8d, 0xd7, 0x3b,
0xaa, 0x3e, 0x60, 0x7c, 0xdc, 0xeb, 0x07, 0x95, 0x9f, 0x93, 0xe8, 0x5b, 0x8d, 0x9f, 0x8b, 0xa5,
0x48, 0xf9, 0xab, 0x62, 0xfc, 0x7e, 0x57, 0x51, 0x89, 0x8c, 0xed, 0xdb, 0x21, 0x44, 0x59, 0x7d,
0x19, 0xfd, 0xe2, 0xcb, 0x38, 0xcf, 0x99, 0xd8, 0xae, 0x58, 0x53, 0x70, 0x5f, 0xa7, 0x15, 0x4d,
0x5a, 0x99, 0xb1, 0xfb, 0x41, 0x90, 0x51, 0x86, 0xbf, 0x8c, 0xbe, 0xdd, 0x4a, 0x8e, 0x59, 0xc2,
0xaf, 0x58, 0x35, 0x46, 0xb5, 0x94, 0x90, 0x68, 0xf2, 0x0e, 0x04, 0x6d, 0x6f, 0xf3, 0xe2, 0x8a,
0x55, 0x02, 0xb7, 0xad, 0x84, 0x61, 0xdb, 0x16, 0x52, 0xb6, 0xff, 0x6a, 0x14, 0x7d, 0x77, 0x9a,
0x24, 0x7c, 0x59, 0x88, 0x7d, 0x9e, 0xc4, 0xf9, 0x7e, 0x56, 0x5c, 0x1e, 0xb2, 0x57, 0xdb, 0x17,
0x0d, 0x5f, 0xcc, 0xd9, 0xf8, 0x89, 0xdf, 0xaa, 0x2d, 0x3a, 0x31, 0xec, 0xc4, 0x85, 0x8d, 0xef,
0x8f, 0xae, 0xa7, 0xa4, 0xca, 0xf2, 0x77, 0xa3, 0xe8, 0x06, 0x2c, 0xcb, 0x8c, 0xe7, 0x57, 0xcc,
0x96, 0xe6, 0xe3, 0x1e, 0xc3, 0x3e, 0x6e, 0xca, 0xf3, 0xc9, 0x75, 0xd5, 0x54, 0x89, 0xf2, 0xe8,
0x6d, 0x37, 0x5c, 0x66, 0xac, 0x96, 0xc3, 0xe9, 0x3e, 0x1d, 0x11, 0x0a, 0x31, 0x9e, 0x1f, 0x0c,
0x41, 0x95, 0xb7, 0x2c, 0x1a, 0x2b, 0x6f, 0x39, 0xaf, 0x8d, 0xb3, 0x7b, 0xa8, 0x05, 0x87, 0x30,
0xbe, 0xee, 0x0f, 0x20, 0x95, 0xab, 0xdf, 0x8f, 0x7e, 0xe9, 0x25, 0xaf, 0x2e, 0xeb, 0x32, 0x4e,
0x98, 0x1a, 0x0a, 0x77, 0x7d, 0x6d, 0x2d, 0x85, 0xa3, 0x61, 0xad, 0x0f, 0x73, 0x82, 0x56, 0x0b,
0xbf, 0x28, 0x19, 0x9c, 0x83, 0xac, 0x62, 0x23, 0xa4, 0x82, 0x16, 0x42, 0xca, 0xf6, 0x65, 0x34,
0xb6, 0xb6, 0xcf, 0xfe, 0x80, 0x25, 0x62, 0x9a, 0xa6, 0xb0, 0x57, 0xac, 0xae, 0x24, 0x26, 0xd3,
0x34, 0xa5, 0x7a, 0x05, 0x47, 0x95, 0xb3, 0x57, 0xd1, 0x3b, 0xc0, 0xd9, 0x7e, 0x56, 0x4b, 0x87,
0x9b, 0x61, 0x2b, 0x0a, 0x33, 0x4e, 0x27, 0x43, 0x71, 0xe5, 0xf8, 0x4f, 0x46, 0xd1, 0x77, 0x10,
0xcf, 0xc7, 0x6c, 0xc1, 0xaf, 0xd8, 0xf8, 0x51, 0xbf, 0xb5, 0x96, 0x34, 0xfe, 0x3f, 0xbc, 0x86,
0x06, 0x12, 0x26, 0x33, 0x96, 0xb3, 0x44, 0x90, 0x61, 0xd2, 0x8a, 0x7b, 0xc3, 0xc4, 0x60, 0xce,
0x08, 0xd3, 0xc2, 0x5d, 0x26, 0xb6, 0x97, 0x55, 0xc5, 0x0a, 0x41, 0xf6, 0xa5, 0x45, 0x7a, 0xfb,
0xd2, 0x43, 0x91, 0xfa, 0xec, 0x32, 0x31, 0xcd, 0x73, 0xb2, 0x3e, 0xad, 0xb8, 0xb7, 0x3e, 0x06,
0x53, 0x1e, 0x92, 0xe8, 0x97, 0x9d, 0x16, 0x13, 0x7b, 0xc5, 0x39, 0x1f, 0xd3, 0x6d, 0x21, 0xe5,
0xc6, 0xc7, 0x7a, 0x2f, 0x87, 0x54, 0xe3, 0xd9, 0xeb, 0x92, 0x57, 0x74, 0xb7, 0xb4, 0xe2, 0xde,
0x6a, 0x18, 0x4c, 0x79, 0xf8, 0xbd, 0xe8, 0x2d, 0x35, 0x4b, 0xea, 0xf5, 0xec, 0x0e, 0x3a, 0x85,
0xc2, 0x05, 0xed, 0x6e, 0x0f, 0x65, 0x27, 0x07, 0x25, 0x53, 0x93, 0xcf, 0x07, 0xa8, 0x1e, 0x98,
0x7a, 0xee, 0x84, 0xa1, 0x8e, 0xed, 0x1d, 0x96, 0x33, 0xd2, 0x76, 0x2b, 0xec, 0xb1, 0x6d, 0x20,
0x65, 0xbb, 0x8a, 0x7e, 0xcd, 0x34, 0x4b, 0xb3, 0x8e, 0x4a, 0x79, 0x33, 0x49, 0x6f, 0x10, 0xf5,
0x76, 0x21, 0xe3, 0xeb, 0xe1, 0x30, 0xb8, 0x53, 0x1f, 0x35, 0x02, 0xf1, 0xfa, 0x80, 0xf1, 0x77,
0x27, 0x0c, 0x29, 0xdb, 0x7f, 0x3d, 0x8a, 0xbe, 0xa7, 0x64, 0xcf, 0x8a, 0xf8, 0x2c, 0x67, 0x72,
0x49, 0x3c, 0x64, 0xe2, 0x15, 0xaf, 0x2e, 0x67, 0xab, 0x22, 0x21, 0x96, 0x7f, 0x1c, 0xee, 0x59,
0xfe, 0x49, 0x25, 0x55, 0x98, 0x3f, 0x8c, 0xde, 0xd5, 0x41, 0x71, 0x11, 0x17, 0x73, 0xf6, 0xc3,
0x9a, 0x17, 0xd3, 0x32, 0x9b, 0xa6, 0x69, 0x35, 0x9e, 0xe0, 0x5d, 0x0f, 0x39, 0x53, 0x82, 0xad,
0xc1, 0xbc, 0x93, 0x6e, 0xaa, 0x56, 0x16, 0xbc, 0x84, 0xe9, 0xa6, 0x6e, 0x3e, 0xc1, 0x4b, 0x2a,
0xdd, 0xf4, 0x91, 0x8e, 0xd5, 0x83, 0x66, 0xce, 0xc6, 0xad, 0x1e, 0xb8, 0x93, 0xf4, 0xed, 0x10,
0x62, 0xe7, 0x4c, 0xdd, 0x50, 0xbc, 0x38, 0xcf, 0xe6, 0xa7, 0x65, 0xda, 0x8c, 0xa1, 0xfb, 0x78,
0x9d, 0x1d, 0x84, 0x98, 0x33, 0x09, 0x54, 0x79, 0xfb, 0x5b, 0x9b, 0x95, 0xa9, 0x71, 0xfc, 0xbc,
0xe2, 0x8b, 0x7d, 0x36, 0x8f, 0x93, 0x95, 0x9a, 0x7c, 0x3e, 0x0a, 0x8d, 0x7a, 0x48, 0x9b, 0x42,
0x7c, 0x7c, 0x4d, 0x2d, 0x55, 0x9e, 0x7f, 0x1b, 0x45, 0x77, 0xbc, 0x38, 0x51, 0xc1, 0xd4, 0x96,
0x7e, 0x5a, 0xa4, 0xc7, 0xac, 0x16, 0x71, 0x25, 0xc6, 0xdf, 0x0f, 0xc4, 0x00, 0xa1, 0x63, 0xca,
0xf6, 0x83, 0x6f, 0xa4, 0x6b, 0x7b, 0x7d, 0xd6, 0xcc, 0xaa, 0x6a, 0xfe, 0xf1, 0x7b, 0x5d, 0x4a,
0xe0, 0xec, 0x73, 0x3b, 0x84, 0xd8, 0x5e, 0x97, 0x82, 0xbd, 0xe2, 0x2a, 0x13, 0x6c, 0x97, 0x15,
0xac, 0xea, 0xf6, 0x7a, 0xab, 0xea, 0x23, 0x44, 0xaf, 0x13, 0xa8, 0x9d, 0xe9, 0x3c, 0x6f, 0x66,
0x65, 0xde, 0x08, 0x18, 0xe9, 0xac, 0xcd, 0x0f, 0x87, 0xc1, 0x76, 0x6b, 0xe9, 0xf8, 0x3c, 0x66,
0x57, 0xfc, 0x12, 0x6e, 0x2d, 0x5d, 0x13, 0x2d, 0x40, 0x6c, 0x2d, 0x51, 0xd0, 0x2e, 0x9f, 0x8e,
0x9f, 0x17, 0x19, 0x7b, 0x05, 0x96, 0x4f, 0x57, 0xb9, 0x11, 0x13, 0xcb, 0x27, 0x82, 0x29, 0x0f,
0x87, 0xd1, 0x2f, 0x48, 0xe1, 0x0f, 0x79, 0x56, 0x8c, 0x6f, 0x22, 0x4a, 0x8d, 0xc0, 0x58, 0xbd,
0x45, 0x03, 0xa0, 0xc4, 0xcd, 0x5f, 0xb7, 0xe3, 0x22, 0x61, 0x39, 0x5a, 0x62, 0x2b, 0x0e, 0x96,
0xd8, 0xc3, 0x6c, 0xde, 0x22, 0x85, 0xcd, 0xfc, 0x35, 0xbb, 0x88, 0xab, 0xac, 0x98, 0x8f, 0x31,
0x5d, 0x47, 0x4e, 0xe4, 0x2d, 0x18, 0x07, 0x42, 0x58, 0x29, 0x4e, 0xcb, 0xb2, 0x6a, 0xa6, 0x45,
0x2c, 0x84, 0x7d, 0x24, 0x18, 0xc2, 0x1d, 0x14, 0xf7, 0xb6, 0xc3, 0x92, 0x3c, 0x2b, 0x82, 0xde,
0x14, 0x32, 0xc4, 0x9b, 0x45, 0x41, 0xf0, 0xee, 0xb3, 0xf8, 0x8a, 0xe9, 0x9a, 0x61, 0x2d, 0xe3,
0x02, 0xc1, 0xe0, 0x05, 0xa0, 0xdd, 0x24, 0x4a, 0xf1, 0x41, 0x7c, 0xc9, 0x9a, 0x06, 0x66, 0xcd,
0xa2, 0x3a, 0xc6, 0xf4, 0x3d, 0x82, 0xd8, 0x24, 0xe2, 0xa4, 0x72, 0xb5, 0x8c, 0xde, 0x91, 0xf2,
0xa3, 0xb8, 0x12, 0x59, 0x92, 0x95, 0x71, 0xa1, 0x37, 0x1f, 0xd8, 0xb8, 0xee, 0x50, 0xc6, 0xe5,
0xe6, 0x40, 0x5a, 0xb9, 0xfd, 0xe7, 0x51, 0xf4, 0x3e, 0xf4, 0x7b, 0xc4, 0xaa, 0x45, 0x26, 0xf7,
0xb0, 0x75, 0x3b, 0x09, 0x8f, 0x3f, 0x0d, 0x1b, 0xed, 0x28, 0x98, 0xd2, 0x7c, 0x76, 0x7d, 0x45,
0x9b, 0x89, 0xcd, 0x54, 0x5e, 0xff, 0x45, 0x95, 0x76, 0xce, 0x78, 0x66, 0x3a, 0x59, 0x97, 0x42,
0x22, 0x13, 0xeb, 0x40, 0x60, 0x84, 0x9f, 0x16, 0xb5, 0xb6, 0x8e, 0x8d, 0x70, 0x2b, 0x0e, 0x8e,
0x70, 0x0f, 0xb3, 0x23, 0xfc, 0x68, 0x79, 0x96, 0x67, 0xf5, 0x45, 0x56, 0xcc, 0x55, 0xda, 0xed,
0xeb, 0x5a, 0x31, 0xcc, 0xbc, 0xd7, 0x7b, 0x39, 0xcc, 0x89, 0x0a, 0x16, 0xd2, 0x09, 0x08, 0x93,
0xf5, 0x5e, 0xce, 0x6e, 0x4e, 0xac, 0xb4, 0xd9, 0xb6, 0x82, 0xcd, 0x89, 0xa3, 0xda, 0x48, 0x89,
0xcd, 0x49, 0x97, 0x52, 0xe6, 0x79, 0xf4, 0xab, 0x6e, 0x1d, 0x6a, 0x9e, 0x5f, 0xb1, 0xd3, 0x2a,
0x1b, 0x3f, 0xa0, 0xcb, 0xa7, 0x19, 0xe3, 0x6a, 0x63, 0x10, 0x6b, 0x27, 0x2a, 0x4b, 0xec, 0x32,
0x31, 0x13, 0xb1, 0x58, 0xd6, 0x60, 0xa2, 0x72, 0x6c, 0x18, 0x84, 0x98, 0xa8, 0x08, 0x54, 0x79,
0xfb, 0xdd, 0x28, 0x6a, 0x77, 0xfc, 0xf2, 0x54, 0xc6, 0x5f, 0x7b, 0xd4, 0x51, 0x80, 0x77, 0x24,
0xf3, 0x7e, 0x80, 0xb0, 0x09, 0x4f, 0xfb, 0x77, 0x79, 0xd8, 0x34, 0x46, 0x35, 0xa4, 0x88, 0x48,
0x78, 0x00, 0x02, 0x0b, 0x3a, 0xbb, 0xe0, 0xaf, 0xf0, 0x82, 0x36, 0x92, 0x70, 0x41, 0x15, 0x61,
0x8f, 0x7f, 0x55, 0x41, 0xb1, 0xe3, 0x5f, 0x5d, 0x8c, 0xd0, 0xf1, 0x2f, 0x64, 0x6c, 0xcc, 0xb8,
0x86, 0x9f, 0x72, 0x7e, 0xb9, 0x88, 0xab, 0x4b, 0x10, 0x33, 0x9e, 0xb2, 0x66, 0x88, 0x98, 0xa1,
0x58, 0x1b, 0x33, 0xae, 0xc3, 0x26, 0x5d, 0x3e, 0xad, 0x72, 0x10, 0x33, 0x9e, 0x0d, 0x85, 0x10,
0x31, 0x43, 0xa0, 0x76, 0x76, 0x72, 0xbd, 0xcd, 0x18, 0x3c, 0x70, 0xf0, 0xd4, 0x67, 0x8c, 0x3a,
0x70, 0x40, 0x30, 0x18, 0x42, 0xbb, 0x55, 0x5c, 0x5e, 0xe0, 0x21, 0x24, 0x45, 0xe1, 0x10, 0xd2,
0x08, 0xec, 0xef, 0x19, 0x8b, 0xab, 0xe4, 0x02, 0xef, 0xef, 0x56, 0x16, 0xee, 0x6f, 0xc3, 0xc0,
0xfe, 0x6e, 0x05, 0x2f, 0x33, 0x71, 0x71, 0xc0, 0x44, 0x8c, 0xf7, 0xb7, 0xcf, 0x84, 0xfb, 0xbb,
0xc3, 0xda, 0x7c, 0xdc, 0x75, 0x38, 0x5b, 0x9e, 0xd5, 0x49, 0x95, 0x9d, 0xb1, 0x71, 0xc0, 0x8a,
0x81, 0x88, 0x7c, 0x9c, 0x84, 0x95, 0xcf, 0x9f, 0x8e, 0xa2, 0x9b, 0xba, 0xdb, 0x79, 0x5d, 0xab,
0xb5, 0xcf, 0x77, 0xff, 0x31, 0xde, 0xbf, 0x04, 0x4e, 0x1c, 0xc8, 0x0f, 0x50, 0x73, 0x72, 0x03,
0xbc, 0x48, 0xa7, 0x45, 0x6d, 0x0a, 0xf5, 0xe9, 0x10, 0xeb, 0x8e, 0x02, 0x91, 0x1b, 0x0c, 0x52,
0xb4, 0x69, 0x99, 0xea, 0x1f, 0x2d, 0xdb, 0x4b, 0x6b, 0x90, 0x96, 0xe9, 0xf6, 0x76, 0x08, 0x22,
0x2d, 0xc3, 0x49, 0x18, 0x0a, 0xbb, 0x15, 0x5f, 0x96, 0x75, 0x4f, 0x28, 0x00, 0x28, 0x1c, 0x0a,
0x5d, 0x58, 0xf9, 0x7c, 0x1d, 0xfd, 0xba, 0x1b, 0x7e, 0x6e, 0x63, 0x6f, 0xd2, 0x31, 0x85, 0x35,
0xf1, 0x64, 0x28, 0x6e, 0x33, 0x0a, 0xed, 0x59, 0xec, 0x30, 0x11, 0x67, 0x79, 0x3d, 0x5e, 0xc3,
0x6d, 0x68, 0x39, 0x91, 0x51, 0x60, 0x1c, 0x9c, 0xdf, 0x76, 0x96, 0x65, 0x9e, 0x25, 0xdd, 0xc7,
0x21, 0x4a, 0xd7, 0x88, 0xc3, 0xf3, 0x9b, 0x8b, 0xc1, 0xf9, 0xba, 0x49, 0xfd, 0xe4, 0x7f, 0x4e,
0x56, 0x25, 0xc3, 0xe7, 0x6b, 0x0f, 0x09, 0xcf, 0xd7, 0x10, 0x85, 0xf5, 0x99, 0x31, 0xb1, 0x1f,
0xaf, 0xf8, 0x92, 0x98, 0xaf, 0x8d, 0x38, 0x5c, 0x1f, 0x17, 0xb3, 0x7b, 0x03, 0xe3, 0x61, 0xaf,
0x10, 0xac, 0x2a, 0xe2, 0xfc, 0x79, 0x1e, 0xcf, 0xeb, 0x31, 0x31, 0xc7, 0xf8, 0x14, 0xb1, 0x37,
0xa0, 0x69, 0xa4, 0x19, 0xf7, 0xea, 0xe7, 0xf1, 0x15, 0xaf, 0x32, 0x41, 0x37, 0xa3, 0x45, 0x7a,
0x9b, 0xd1, 0x43, 0x51, 0x6f, 0xd3, 0x2a, 0xb9, 0xc8, 0xae, 0x58, 0x1a, 0xf0, 0xa6, 0x91, 0x01,
0xde, 0x1c, 0x14, 0xe9, 0xb4, 0x19, 0x5f, 0x56, 0x09, 0x23, 0x3b, 0xad, 0x15, 0xf7, 0x76, 0x9a,
0xc1, 0x94, 0x87, 0x3f, 0x1f, 0x45, 0xbf, 0xd1, 0x4a, 0xdd, 0x67, 0x14, 0x3b, 0x71, 0x7d, 0x71,
0xc6, 0xe3, 0x2a, 0x1d, 0x7f, 0x88, 0xd9, 0x41, 0x51, 0xe3, 0xfa, 0xf1, 0x75, 0x54, 0x60, 0xb3,
0x36, 0x79, 0xb7, 0x1d, 0x71, 0x68, 0xb3, 0x7a, 0x48, 0xb8, 0x59, 0x21, 0x0a, 0x27, 0x10, 0x29,
0x6f, 0x8f, 0xe4, 0xd6, 0x48, 0x7d, 0xff, 0x5c, 0x6e, 0xbd, 0x97, 0x83, 0xf3, 0x63, 0x23, 0xf4,
0xa3, 0x65, 0x93, 0xb2, 0x81, 0x47, 0xcc, 0x64, 0x28, 0x4e, 0x7a, 0x36, 0xa3, 0x22, 0xec, 0xb9,
0x33, 0x32, 0x26, 0x43, 0x71, 0xc2, 0xb3, 0x33, 0xad, 0x85, 0x3c, 0x23, 0x53, 0xdb, 0x64, 0x28,
0x0e, 0xb3, 0x2f, 0xc5, 0xe8, 0x75, 0xe1, 0x41, 0xc0, 0x0e, 0x5c, 0x1b, 0x36, 0x06, 0xb1, 0xca,
0xe1, 0x5f, 0x8e, 0xa2, 0xef, 0x5a, 0x8f, 0x07, 0x3c, 0xcd, 0xce, 0x57, 0x2d, 0xf4, 0x22, 0xce,
0x97, 0xac, 0x1e, 0x3f, 0xa6, 0xac, 0x75, 0x59, 0x53, 0x82, 0x27, 0xd7, 0xd2, 0x81, 0x63, 0x67,
0x5a, 0x96, 0xf9, 0xea, 0x84, 0x2d, 0xca, 0x9c, 0x1c, 0x3b, 0x1e, 0x12, 0x1e, 0x3b, 0x10, 0x85,
0x59, 0xf9, 0x09, 0x6f, 0x72, 0x7e, 0x34, 0x2b, 0x97, 0xa2, 0x70, 0x56, 0xae, 0x11, 0x98, 0x2b,
0x9d, 0xf0, 0x6d, 0x9e, 0xe7, 0x2c, 0x11, 0xdd, 0x7b, 0x0e, 0x46, 0xd3, 0x12, 0xe1, 0x5c, 0x09,
0x90, 0xf6, 0x54, 0x4e, 0xef, 0x21, 0xe3, 0x8a, 0x3d, 0x5d, 0xed, 0x67, 0xc5, 0xe5, 0x18, 0x4f,
0x0b, 0x2c, 0x40, 0x9c, 0xca, 0xa1, 0x20, 0xdc, 0xab, 0x9e, 0x16, 0x29, 0xc7, 0xf7, 0xaa, 0x8d,
0x24, 0xbc, 0x57, 0x55, 0x04, 0x34, 0x79, 0xcc, 0x28, 0x93, 0x8d, 0x24, 0x6c, 0x52, 0x11, 0xd8,
0x54, 0xa8, 0x9e, 0xdd, 0x90, 0x53, 0x21, 0x78, 0x5a, 0xb3, 0xde, 0xcb, 0xc1, 0x08, 0xd5, 0x9b,
0xd6, 0xe7, 0x4c, 0x24, 0x17, 0x78, 0x84, 0x7a, 0x48, 0x38, 0x42, 0x21, 0x0a, 0xab, 0x74, 0xc2,
0xcd, 0xa6, 0x7b, 0x0d, 0x8f, 0x8f, 0xce, 0x86, 0x7b, 0xbd, 0x97, 0x83, 0xdb, 0xc8, 0xbd, 0x85,
0x6c, 0x33, 0x34, 0xc8, 0x5b, 0x59, 0x78, 0x1b, 0x69, 0x18, 0x58, 0xfa, 0x56, 0x20, 0xcf, 0xb2,
0xd6, 0x68, 0x45, 0xef, 0x34, 0x6b, 0xbd, 0x97, 0x53, 0x4e, 0xfe, 0xd1, 0x6c, 0xe3, 0x5a, 0xe9,
0x21, 0x6f, 0xc6, 0xc8, 0x8b, 0x38, 0xcf, 0xd2, 0x58, 0xb0, 0x13, 0x7e, 0xc9, 0x0a, 0x7c, 0xc7,
0xa4, 0x4a, 0xdb, 0xf2, 0x13, 0x4f, 0x21, 0xbc, 0x63, 0x0a, 0x2b, 0xc2, 0x38, 0x69, 0xe9, 0xd3,
0x9a, 0x6d, 0xc7, 0x35, 0x31, 0x93, 0x79, 0x48, 0x38, 0x4e, 0x20, 0x0a, 0xf3, 0xd5, 0x56, 0xfe,
0xec, 0x75, 0xc9, 0xaa, 0x8c, 0x15, 0x09, 0xc3, 0xf3, 0x55, 0x48, 0x85, 0xf3, 0x55, 0x84, 0x86,
0x7b, 0xb5, 0x9d, 0x58, 0xb0, 0xa7, 0xab, 0x93, 0x6c, 0xc1, 0x6a, 0x11, 0x2f, 0x4a, 0x7c, 0xaf,
0x06, 0xa0, 0xf0, 0x5e, 0xad, 0x0b, 0x77, 0x8e, 0x86, 0xcc, 0x84, 0xd8, 0xbd, 0x1e, 0x05, 0x89,
0xc0, 0xf5, 0x28, 0x02, 0x85, 0x0d, 0x6b, 0x01, 0xf4, 0x21, 0x41, 0xc7, 0x4a, 0xf0, 0x21, 0x01,
0x4d, 0x77, 0x0e, 0xdc, 0x0c, 0x33, 0x6b, 0x86, 0x66, 0x4f, 0xd1, 0x67, 0xee, 0x10, 0xdd, 0x18,
0xc4, 0xe2, 0x27, 0x7c, 0xc7, 0x2c, 0x8f, 0xe5, 0xb2, 0x15, 0x38, 0x46, 0xd3, 0xcc, 0x90, 0x13,
0x3e, 0x87, 0x55, 0x0e, 0xff, 0x74, 0x14, 0xbd, 0x87, 0x79, 0xfc, 0xa2, 0x94, 0x7e, 0x1f, 0xf5,
0xdb, 0x6a, 0x49, 0xe2, 0xfe, 0x57, 0x58, 0xc3, 0x5e, 0xc9, 0xd0, 0x22, 0x7b, 0x3d, 0x4c, 0x15,
0xc0, 0x4f, 0xda, 0x4c, 0xf9, 0x21, 0x47, 0x5c, 0xc9, 0x08, 0xf1, 0x76, 0x3f, 0xe4, 0x97, 0xab,
0x06, 0xfb, 0x21, 0x63, 0x43, 0x89, 0x89, 0xfd, 0x10, 0x82, 0xd9, 0xd1, 0xe9, 0x56, 0xef, 0x65,
0x26, 0x2e, 0x64, 0xbe, 0x05, 0x46, 0xa7, 0x57, 0x56, 0x03, 0x11, 0xa3, 0x93, 0x84, 0x61, 0x46,
0xa2, 0xc1, 0x66, 0x6c, 0x62, 0x73, 0xb9, 0x31, 0xe4, 0x8e, 0xcc, 0x7b, 0xfd, 0x20, 0x8c, 0x57,
0x2d, 0x56, 0x5b, 0x9f, 0x07, 0x21, 0x0b, 0x60, 0xfb, 0xb3, 0x31, 0x88, 0x55, 0x0e, 0xff, 0x38,
0xfa, 0x4e, 0xa7, 0x62, 0xcf, 0x59, 0x2c, 0x96, 0x15, 0x4b, 0xc7, 0x5b, 0x3d, 0xe5, 0xd6, 0xa0,
0x71, 0xfd, 0x68, 0xb8, 0x42, 0x27, 0x47, 0xd7, 0x5c, 0x1b, 0x56, 0xa6, 0x0c, 0x8f, 0x43, 0x26,
0x7d, 0x36, 0x98, 0xa3, 0xd3, 0x3a, 0x9d, 0x6d, 0xb6, 0x1b, 0x5d, 0xd3, 0xab, 0x38, 0xcb, 0xe5,
0xc3, 0xda, 0x0f, 0x43, 0x46, 0x3d, 0x34, 0xb8, 0xcd, 0x26, 0x55, 0x3a, 0x33, 0xb3, 0x1c, 0xe3,
0xce, 0xf6, 0xec, 0x21, 0x3d, 0x13, 0x20, 0xbb, 0xb3, 0xcd, 0x81, 0xb4, 0x72, 0x2b, 0xf4, 0x92,
0xd7, 0xfc, 0xd9, 0x0d, 0x72, 0xcc, 0xab, 0x52, 0x45, 0x22, 0x7d, 0x73, 0x20, 0xad, 0xbc, 0xfe,
0x51, 0xf4, 0x6e, 0xd7, 0xab, 0x5a, 0x88, 0xb6, 0x7a, 0x4d, 0x81, 0xb5, 0xe8, 0xd1, 0x70, 0x05,
0xe5, 0xfe, 0x5f, 0xcc, 0xb9, 0x74, 0xeb, 0x3f, 0xe1, 0x8b, 0x05, 0x2b, 0x52, 0x96, 0x6a, 0x8d,
0xba, 0xd9, 0x3f, 0x7d, 0x46, 0xdb, 0x35, 0x0a, 0x13, 0x57, 0xc3, 0x94, 0xe8, 0x37, 0xbf, 0x81,
0xa6, 0x2a, 0xda, 0x7f, 0x8c, 0xa2, 0xfb, 0x68, 0xd1, 0x74, 0xe0, 0x7a, 0x45, 0xfc, 0x9d, 0x21,
0x8e, 0x30, 0x4d, 0x53, 0xd4, 0xe9, 0xff, 0xc3, 0x82, 0x2a, 0xf2, 0xbf, 0x8e, 0xa2, 0xdb, 0x56,
0xb1, 0x09, 0xef, 0x6d, 0x5e, 0x9c, 0xe7, 0x59, 0x22, 0xe4, 0x13, 0x59, 0xa5, 0x42, 0x37, 0x27,
0xa5, 0xd1, 0xdf, 0x9c, 0x01, 0x4d, 0xbb, 0x79, 0xfd, 0x3c, 0xab, 0x05, 0xaf, 0x56, 0xb3, 0x0b,
0xfe, 0x4a, 0xbf, 0x60, 0xe3, 0xcf, 0xcb, 0x0a, 0x98, 0x38, 0x04, 0xb1, 0x79, 0xc5, 0xc9, 0x8e,
0x2b, 0xfb, 0x22, 0x4e, 0x4d, 0xb8, 0x72, 0x88, 0x1e, 0x57, 0x3e, 0x69, 0x57, 0x25, 0x5d, 0x2b,
0xfb, 0xd6, 0xd0, 0x3a, 0x5e, 0xd4, 0xee, 0x9b, 0x43, 0xf7, 0xfa, 0x41, 0x9b, 0x9b, 0x2a, 0xf1,
0x4e, 0x76, 0x7e, 0x6e, 0xea, 0x84, 0x97, 0xd4, 0x45, 0x88, 0xdc, 0x94, 0x40, 0xed, 0xf6, 0xea,
0x79, 0x96, 0x33, 0xf9, 0xec, 0xe6, 0x8b, 0xf3, 0xf3, 0x9c, 0xc7, 0x29, 0xd8, 0x5e, 0x35, 0xe2,
0x89, 0x2b, 0x27, 0xb6, 0x57, 0x18, 0x67, 0x6f, 0x85, 0x34, 0xd2, 0x26, 0xba, 0x8b, 0x24, 0xcb,
0xe1, 0x7d, 0x63, 0xa9, 0x69, 0x84, 0xc4, 0xad, 0x90, 0x0e, 0x64, 0x53, 0xa0, 0x46, 0xd4, 0x44,
0xa5, 0x2e, 0xff, 0xdd, 0xae, 0xa2, 0x23, 0x26, 0x52, 0x20, 0x04, 0xb3, 0xa7, 0x0c, 0x8d, 0xf0,
0xb4, 0x94, 0xc6, 0x6f, 0x75, 0xb5, 0x5a, 0x09, 0x71, 0xca, 0xe0, 0x13, 0x76, 0xb7, 0xdc, 0xfc,
0x7d, 0x87, 0xbf, 0x2a, 0xa4, 0xd1, 0xdb, 0x5d, 0x15, 0x2d, 0x23, 0x76, 0xcb, 0x90, 0x51, 0x86,
0x7f, 0x14, 0xfd, 0xbc, 0x34, 0x5c, 0xf1, 0x72, 0x7c, 0x03, 0x51, 0xa8, 0x9c, 0xdb, 0xb9, 0x37,
0x49, 0xb9, 0xbd, 0x44, 0x62, 0x62, 0xe3, 0xb4, 0x8e, 0xe7, 0x6c, 0x7c, 0x87, 0xe8, 0x71, 0x29,
0x25, 0x2e, 0x91, 0x74, 0x29, 0x3f, 0x2a, 0x0e, 0x79, 0xaa, 0xac, 0x23, 0x35, 0x34, 0xc2, 0x50,
0x54, 0xb8, 0x90, 0x4d, 0x5b, 0x0f, 0xe3, 0xab, 0x6c, 0x6e, 0x52, 0x8b, 0x76, 0x02, 0xab, 0x41,
0xda, 0x6a, 0x99, 0x89, 0x03, 0x11, 0x69, 0x2b, 0x09, 0x2b, 0x9f, 0xff, 0x30, 0x8a, 0x6e, 0x59,
0x66, 0x57, 0x9f, 0xcb, 0xee, 0x15, 0xe7, 0xbc, 0x49, 0x72, 0xf7, 0xb3, 0xe2, 0xb2, 0x1e, 0x7f,
0x42, 0x99, 0xc4, 0x79, 0x53, 0x94, 0x4f, 0xaf, 0xad, 0x67, 0xf7, 0x27, 0xfa, 0xd0, 0xd2, 0xde,
0x5c, 0x68, 0x35, 0xc0, 0xfe, 0xc4, 0x9c, 0x6d, 0x42, 0x8e, 0xd8, 0x9f, 0x84, 0x78, 0xdb, 0xc5,
0xc6, 0x79, 0xce, 0x0b, 0xd8, 0xc5, 0xd6, 0x42, 0x23, 0x24, 0xba, 0xb8, 0x03, 0xd9, 0xf9, 0x58,
0x8b, 0xda, 0xf3, 0xb5, 0x69, 0x9e, 0x83, 0xf9, 0xd8, 0xa8, 0x1a, 0x80, 0x98, 0x8f, 0x51, 0x50,
0xf9, 0x39, 0x8e, 0xbe, 0xd5, 0x34, 0xe9, 0x51, 0xc5, 0xae, 0x32, 0x06, 0x2f, 0xd9, 0x38, 0x12,
0x62, 0xfc, 0xfb, 0x84, 0x1d, 0x59, 0xa7, 0x45, 0x5d, 0xe6, 0x71, 0x7d, 0xa1, 0xae, 0x5d, 0xf8,
0x75, 0xd6, 0x42, 0x78, 0xf1, 0xe2, 0x6e, 0x0f, 0x65, 0x27, 0x75, 0x2d, 0x33, 0x53, 0xcc, 0x1a,
0xae, 0xda, 0x99, 0x66, 0xd6, 0x7b, 0x39, 0xfb, 0x6c, 0x63, 0x37, 0xce, 0x73, 0x56, 0xad, 0xb4,
0xec, 0x20, 0x2e, 0xb2, 0x73, 0x56, 0x0b, 0xf0, 0x6c, 0x43, 0x51, 0x13, 0x88, 0x11, 0xcf, 0x36,
0x02, 0xb8, 0xdd, 0xb7, 0x01, 0xcf, 0x7b, 0x45, 0xca, 0x5e, 0x83, 0x7d, 0x1b, 0xb4, 0x23, 0x19,
0x62, 0xdf, 0x46, 0xb1, 0xf6, 0x8c, 0xff, 0x69, 0xce, 0x93, 0x4b, 0xb5, 0x04, 0xf8, 0x1d, 0x2c,
0x25, 0x70, 0x0d, 0xb8, 0x1d, 0x42, 0xec, 0x22, 0x20, 0x05, 0xc7, 0xac, 0xcc, 0xe3, 0x04, 0xde,
0xb4, 0x6a, 0x75, 0x94, 0x8c, 0x58, 0x04, 0x20, 0x03, 0x8a, 0xab, 0x6e, 0x70, 0x61, 0xc5, 0x05,
0x17, 0xb8, 0x6e, 0x87, 0x10, 0xbb, 0x0c, 0x4a, 0xc1, 0xac, 0xcc, 0x33, 0x01, 0x86, 0x41, 0xab,
0x21, 0x25, 0xc4, 0x30, 0xf0, 0x09, 0x60, 0xf2, 0x80, 0x55, 0x73, 0x86, 0x9a, 0x94, 0x92, 0xa0,
0x49, 0x4d, 0xd8, 0x6b, 0xe5, 0x6d, 0xdd, 0x79, 0xb9, 0x02, 0xd7, 0xca, 0x55, 0xb5, 0x78, 0xb9,
0x22, 0xae, 0x95, 0x7b, 0x00, 0x28, 0xe2, 0x51, 0x5c, 0x0b, 0xbc, 0x88, 0x52, 0x12, 0x2c, 0xa2,
0x26, 0xec, 0x1a, 0xdd, 0x16, 0x71, 0x29, 0xc0, 0x1a, 0xad, 0x0a, 0xe0, 0xdc, 0x35, 0xb8, 0x49,
0xca, 0xed, 0x4c, 0xd2, 0xf6, 0x0a, 0x13, 0xcf, 0x33, 0x96, 0xa7, 0x35, 0x98, 0x49, 0x54, 0xbb,
0x6b, 0x29, 0x31, 0x93, 0x74, 0x29, 0x10, 0x4a, 0xea, 0x49, 0x08, 0x56, 0x3b, 0xf0, 0x10, 0xe4,
0x76, 0x08, 0xb1, 0xf3, 0x93, 0x2e, 0xf4, 0x76, 0x5c, 0x55, 0x59, 0xb3, 0xf8, 0xaf, 0xe1, 0x05,
0xd2, 0x72, 0x62, 0x7e, 0xc2, 0x38, 0x30, 0xbc, 0xf4, 0xc4, 0x8d, 0x15, 0x0c, 0x4e, 0xdd, 0x1f,
0x04, 0x19, 0x9b, 0x71, 0x4a, 0x89, 0xf3, 0xb0, 0x1c, 0x6b, 0x4d, 0xe4, 0x59, 0xf9, 0x5a, 0x1f,
0xe6, 0xbc, 0x73, 0x66, 0x5c, 0x1c, 0xf0, 0x2b, 0x76, 0xc2, 0x9f, 0xbd, 0xce, 0xea, 0x66, 0xbb,
0xa5, 0x56, 0xee, 0x27, 0x84, 0x25, 0x0c, 0x26, 0xde, 0x39, 0xeb, 0x55, 0xb2, 0x09, 0x04, 0x28,
0xcb, 0x21, 0x7b, 0x85, 0x26, 0x10, 0xd0, 0xa2, 0xe1, 0x88, 0x04, 0x22, 0xc4, 0xdb, 0x13, 0x33,
0xe3, 0x5c, 0xbd, 0x98, 0x7f, 0xc2, 0x75, 0x2e, 0x47, 0x59, 0x83, 0x20, 0x71, 0x68, 0x11, 0x54,
0xb0, 0xfb, 0x4b, 0xe3, 0xdf, 0x0e, 0xb1, 0x7b, 0x84, 0x9d, 0xee, 0x30, 0xbb, 0x3f, 0x80, 0x44,
0x5c, 0xd9, 0x1b, 0x1f, 0x94, 0xab, 0xee, 0x85, 0x8f, 0xfb, 0x03, 0x48, 0xe7, 0xf4, 0xcd, 0xad,
0xd6, 0xd3, 0x38, 0xb9, 0x9c, 0x57, 0x7c, 0x59, 0xa4, 0xdb, 0x3c, 0xe7, 0x15, 0x38, 0x7d, 0xf3,
0x4a, 0x0d, 0x50, 0xe2, 0xf4, 0xad, 0x47, 0xc5, 0x66, 0x70, 0x6e, 0x29, 0xa6, 0x79, 0x36, 0x87,
0x3b, 0x6a, 0xcf, 0x90, 0x04, 0x88, 0x0c, 0x0e, 0x05, 0x91, 0x20, 0x6a, 0x77, 0xdc, 0x22, 0x4b,
0xe2, 0xbc, 0xf5, 0xb7, 0x45, 0x9b, 0xf1, 0xc0, 0xde, 0x20, 0x42, 0x14, 0x90, 0x7a, 0x9e, 0x2c,
0xab, 0x62, 0xaf, 0x10, 0x9c, 0xac, 0xa7, 0x06, 0x7a, 0xeb, 0xe9, 0x80, 0x60, 0x5a, 0x3d, 0x61,
0xaf, 0x9b, 0xd2, 0x34, 0xff, 0x60, 0xd3, 0x6a, 0xf3, 0xf7, 0x89, 0x92, 0x87, 0xa6, 0x55, 0xc0,
0x81, 0xca, 0x28, 0x27, 0x6d, 0xc0, 0x04, 0xb4, 0xfd, 0x30, 0xb9, 0xd7, 0x0f, 0xe2, 0x7e, 0x66,
0x62, 0x95, 0xb3, 0x90, 0x1f, 0x09, 0x0c, 0xf1, 0xa3, 0x41, 0x7b, 0xdc, 0xe2, 0xd5, 0xe7, 0x82,
0x25, 0x97, 0x9d, 0x0b, 0x6c, 0x7e, 0x41, 0x5b, 0x84, 0x38, 0x6e, 0x21, 0x50, 0xbc, 0x8b, 0xf6,
0x12, 0x5e, 0x84, 0xba, 0xa8, 0x91, 0x0f, 0xe9, 0x22, 0xc5, 0xd9, 0xcd, 0xaf, 0x91, 0xaa, 0xc8,
0x6c, 0xbb, 0x69, 0x83, 0xb0, 0xe0, 0x42, 0xc4, 0xe6, 0x97, 0x84, 0x6d, 0x4e, 0x0e, 0x7d, 0x1e,
0x74, 0x6f, 0xf7, 0x77, 0xac, 0x1c, 0xd0, 0xb7, 0xfb, 0x29, 0x96, 0xae, 0x64, 0x1b, 0x23, 0x3d,
0x56, 0xfc, 0x38, 0x79, 0x38, 0x0c, 0xb6, 0x5b, 0x1e, 0xcf, 0xe7, 0x76, 0xce, 0xe2, 0xaa, 0xf5,
0xba, 0x19, 0x30, 0x64, 0x31, 0x62, 0xcb, 0x13, 0xc0, 0xc1, 0x14, 0xe6, 0x79, 0xde, 0xe6, 0x85,
0x60, 0x85, 0xc0, 0xa6, 0x30, 0xdf, 0x98, 0x02, 0x43, 0x53, 0x18, 0xa5, 0x00, 0xe2, 0x56, 0x9e,
0x07, 0x31, 0x71, 0x18, 0x2f, 0xd0, 0x8c, 0xad, 0x3d, 0xeb, 0x69, 0xe5, 0xa1, 0xb8, 0x05, 0x9c,
0xf3, 0x38, 0xd7, 0xf5, 0x72, 0x12, 0x57, 0x73, 0x73, 0xba, 0x91, 0x8e, 0x1f, 0xd1, 0x76, 0x7c,
0x92, 0x78, 0x9c, 0x1b, 0xd6, 0x00, 0xd3, 0xce, 0xde, 0x22, 0x9e, 0x9b, 0x9a, 0x22, 0x35, 0x90,
0xf2, 0x4e, 0x55, 0xef, 0xf5, 0x83, 0xc0, 0xcf, 0x8b, 0x2c, 0x65, 0x3c, 0xe0, 0x47, 0xca, 0x87,
0xf8, 0x81, 0x20, 0xc8, 0xde, 0x9a, 0x7a, 0xb7, 0x3b, 0xba, 0x69, 0x91, 0xaa, 0x7d, 0xec, 0x84,
0x68, 0x1e, 0xc0, 0x85, 0xb2, 0x37, 0x82, 0x07, 0x63, 0x54, 0x1f, 0xd0, 0x86, 0xc6, 0xa8, 0x39,
0x7f, 0x1d, 0x32, 0x46, 0x31, 0x58, 0xf9, 0xfc, 0x89, 0x1a, 0xa3, 0x3b, 0xb1, 0x88, 0x9b, 0xbc,
0xfd, 0x45, 0xc6, 0x5e, 0xa9, 0x8d, 0x30, 0x52, 0x5f, 0x4d, 0x4d, 0xe4, 0xcb, 0xc9, 0x60, 0x57,
0xbc, 0x35, 0x98, 0x0f, 0xf8, 0x56, 0x3b, 0x84, 0x5e, 0xdf, 0x60, 0xab, 0xb0, 0x35, 0x98, 0x0f,
0xf8, 0x56, 0x5f, 0x3d, 0xe8, 0xf5, 0x0d, 0x3e, 0x7d, 0xb0, 0x35, 0x98, 0x57, 0xbe, 0xff, 0x4c,
0x0f, 0x5c, 0xd7, 0x79, 0x93, 0x87, 0x25, 0x22, 0xbb, 0x62, 0x58, 0x3a, 0xe9, 0xdb, 0x33, 0x68,
0x28, 0x9d, 0xa4, 0x55, 0x9c, 0xef, 0x74, 0x61, 0xa5, 0x38, 0xe2, 0x75, 0x26, 0xaf, 0x63, 0x3c,
0x19, 0x60, 0x54, 0xc3, 0xa1, 0x4d, 0x53, 0x48, 0xc9, 0x3e, 0x58, 0xf6, 0x50, 0x7b, 0x5f, 0xfd,
0x61, 0xc0, 0x5e, 0xf7, 0xda, 0xfa, 0xe6, 0x40, 0xda, 0x3e, 0xe2, 0xf5, 0x18, 0xf7, 0xd9, 0x72,
0xa8, 0x57, 0xd1, 0xc7, 0xcb, 0x8f, 0x86, 0x2b, 0x28, 0xf7, 0x7f, 0xa1, 0xf7, 0x15, 0xd0, 0xbf,
0x1a, 0x04, 0x8f, 0x87, 0x58, 0x04, 0x03, 0xe1, 0xc9, 0xb5, 0x74, 0x54, 0x41, 0xfe, 0x46, 0x6f,
0xa0, 0x35, 0x2a, 0xdf, 0xda, 0x91, 0x6f, 0xfb, 0xaa, 0x31, 0x11, 0xea, 0x56, 0x0b, 0xc3, 0x91,
0xf1, 0xf1, 0x35, 0xb5, 0x9c, 0xaf, 0xb6, 0x79, 0xb0, 0x7a, 0xbb, 0xd4, 0x29, 0x4f, 0xc8, 0xb2,
0x43, 0xc3, 0x02, 0x7d, 0x72, 0x5d, 0x35, 0x6a, 0xac, 0x38, 0xb0, 0xfc, 0x0e, 0xcb, 0x93, 0x81,
0x86, 0xbd, 0x2f, 0xb3, 0x7c, 0x74, 0x3d, 0x25, 0x55, 0x96, 0x7f, 0x1f, 0x45, 0x77, 0x3d, 0xd6,
0x3e, 0x4f, 0x00, 0xa7, 0x1e, 0x3f, 0x08, 0xd8, 0xa7, 0x94, 0x4c, 0xe1, 0x7e, 0xeb, 0x9b, 0x29,
0xdb, 0x4f, 0x9c, 0x79, 0x2a, 0xcf, 0xb3, 0x5c, 0xb0, 0xaa, 0xfb, 0x89, 0x33, 0xdf, 0x6e, 0x4b,
0x4d, 0xe8, 0x4f, 0x9c, 0x05, 0x70, 0xe7, 0x13, 0x67, 0x88, 0x67, 0xf4, 0x13, 0x67, 0xa8, 0xb5,
0xe0, 0x27, 0xce, 0xc2, 0x1a, 0xd4, 0xf4, 0xae, 0x8b, 0xd0, 0x9e, 0x5b, 0x0f, 0xb2, 0xe8, 0x1f,
0x63, 0x3f, 0xbe, 0x8e, 0x0a, 0xb1, 0xc0, 0xb5, 0x9c, 0xbc, 0xd1, 0x38, 0xa0, 0x4d, 0xbd, 0x5b,
0x8d, 0x5b, 0x83, 0x79, 0xe5, 0xfb, 0xc7, 0x6a, 0x77, 0x63, 0xa6, 0x73, 0x5e, 0xc9, 0xcf, 0xdb,
0x6d, 0x84, 0xa6, 0xe7, 0xc6, 0x82, 0xdb, 0xf3, 0x0f, 0x87, 0xc1, 0x44, 0x75, 0x1b, 0x42, 0x75,
0xfa, 0xa4, 0xcf, 0x10, 0xe8, 0xf2, 0xad, 0xc1, 0x3c, 0xb1, 0x8c, 0xb4, 0xbe, 0xdb, 0xde, 0x1e,
0x60, 0xcc, 0xef, 0xeb, 0x47, 0xc3, 0x15, 0x94, 0xfb, 0x2b, 0x95, 0x36, 0xba, 0xee, 0x65, 0x3f,
0x6f, 0xf6, 0x99, 0x9a, 0x79, 0xdd, 0x3c, 0x19, 0x8a, 0x87, 0x12, 0x08, 0x77, 0x09, 0xed, 0x4b,
0x20, 0xd0, 0x65, 0xf4, 0xa3, 0xeb, 0x29, 0xa9, 0xb2, 0xfc, 0xfd, 0x28, 0xba, 0x49, 0x96, 0x45,
0xc5, 0xc1, 0x27, 0x43, 0x2d, 0x83, 0x78, 0xf8, 0xf4, 0xda, 0x7a, 0xaa, 0x50, 0xff, 0x34, 0x8a,
0x6e, 0x05, 0x0a, 0xd5, 0x06, 0xc8, 0x35, 0xac, 0xfb, 0x81, 0xf2, 0xd9, 0xf5, 0x15, 0xa9, 0xe5,
0xde, 0xc5, 0x67, 0xdd, 0xcf, 0x6f, 0x05, 0x6c, 0xcf, 0xe8, 0xcf, 0x6f, 0xf5, 0x6b, 0xc1, 0x43,
0x9e, 0xf8, 0x4c, 0x6f, 0xba, 0xd0, 0x43, 0x1e, 0x79, 0x17, 0x31, 0xf8, 0x19, 0x11, 0x8c, 0xc3,
0x9c, 0x3c, 0x7b, 0x5d, 0xc6, 0x45, 0x4a, 0x3b, 0x69, 0xe5, 0xfd, 0x4e, 0x0c, 0x07, 0x0f, 0xc7,
0x1a, 0xe9, 0x31, 0xd7, 0x1b, 0xa9, 0xfb, 0x94, 0xbe, 0x41, 0x82, 0x87, 0x63, 0x1d, 0x94, 0xf0,
0xa6, 0xb2, 0xc6, 0x90, 0x37, 0x90, 0x2c, 0x3e, 0x18, 0x82, 0x82, 0x14, 0xdd, 0x78, 0x33, 0x67,
0xee, 0x0f, 0x43, 0x56, 0x3a, 0xe7, 0xee, 0x9b, 0x03, 0x69, 0xc2, 0xed, 0x8c, 0x89, 0xcf, 0x59,
0x9c, 0xb2, 0x2a, 0xe8, 0xd6, 0x50, 0x83, 0xdc, 0xba, 0x34, 0xe6, 0x76, 0x9b, 0xe7, 0xcb, 0x45,
0xa1, 0x3a, 0x93, 0x74, 0xeb, 0x52, 0xfd, 0x6e, 0x01, 0x0d, 0x8f, 0x05, 0xad, 0x5b, 0x99, 0x5e,
0x3e, 0x08, 0x9b, 0xf1, 0xb2, 0xca, 0x8d, 0x41, 0x2c, 0x5d, 0x4f, 0x15, 0x46, 0x3d, 0xf5, 0x04,
0x91, 0xb4, 0x39, 0x90, 0x86, 0xe7, 0x73, 0x8e, 0x5b, 0x13, 0x4f, 0x5b, 0x3d, 0xb6, 0x3a, 0x21,
0xf5, 0x68, 0xb8, 0x02, 0x3c, 0x0d, 0x55, 0x51, 0xb5, 0x9f, 0xd5, 0xe2, 0x79, 0x96, 0xe7, 0xe3,
0x8d, 0x40, 0x98, 0x68, 0x28, 0x78, 0x1a, 0x8a, 0xc0, 0x44, 0x24, 0xeb, 0xd3, 0xc3, 0x62, 0xdc,
0x67, 0x47, 0x52, 0x83, 0x22, 0xd9, 0xa5, 0xc1, 0x89, 0x96, 0xd3, 0xd4, 0xa6, 0xb6, 0x93, 0x70,
0xc3, 0x75, 0x2a, 0xbc, 0x35, 0x98, 0x07, 0x8f, 0xdb, 0x25, 0x25, 0x57, 0x96, 0x3b, 0x94, 0x09,
0x6f, 0x25, 0xb9, 0xdb, 0x43, 0x81, 0x53, 0xc1, 0x76, 0x18, 0xbd, 0xcc, 0xd2, 0x39, 0x13, 0xe8,
0x93, 0x22, 0x17, 0x08, 0x3e, 0x29, 0x02, 0x20, 0xe8, 0xba, 0xf6, 0xef, 0xe6, 0x38, 0x74, 0x2f,
0xc5, 0xba, 0x4e, 0x29, 0x3b, 0x54, 0xa8, 0xeb, 0x50, 0x1a, 0xcc, 0x06, 0xc6, 0xad, 0xfa, 0xf0,
0xc2, 0x83, 0x90, 0x19, 0xf0, 0xf5, 0x85, 0x8d, 0x41, 0x2c, 0x58, 0x51, 0xac, 0xc3, 0x6c, 0x91,
0x09, 0x6c, 0x45, 0x71, 0x6c, 0x34, 0x48, 0x68, 0x45, 0xe9, 0xa2, 0x54, 0xf5, 0x9a, 0x1c, 0x61,
0x2f, 0x0d, 0x57, 0xaf, 0x65, 0x86, 0x55, 0xcf, 0xb0, 0x9d, 0x07, 0x9b, 0x85, 0x09, 0x19, 0x71,
0xa1, 0x36, 0xcb, 0x48, 0x6c, 0xcb, 0x17, 0x72, 0x21, 0x18, 0x9a, 0x75, 0x28, 0x05, 0x78, 0x60,
0xdf, 0x70, 0xfa, 0xd9, 0x6b, 0x59, 0xb2, 0xb8, 0x8a, 0x8b, 0x04, 0xdd, 0x9c, 0x4a, 0x83, 0x1d,
0x32, 0xb4, 0x39, 0x25, 0x35, 0xc0, 0x63, 0x73, 0xff, 0x55, 0x5a, 0x64, 0x28, 0x98, 0x77, 0x56,
0xfd, 0x37, 0x69, 0xef, 0x0f, 0x20, 0xe1, 0x63, 0x73, 0x0d, 0x98, 0x83, 0xef, 0xd6, 0xe9, 0x87,
0x01, 0x53, 0x3e, 0x1a, 0xda, 0x08, 0xd3, 0x2a, 0x20, 0xa8, 0x4d, 0x82, 0xcb, 0xc4, 0x8f, 0xd8,
0x0a, 0x0b, 0x6a, 0x9b, 0x9f, 0x4a, 0x24, 0x14, 0xd4, 0x5d, 0x14, 0xe4, 0x99, 0xee, 0x3e, 0x68,
0x2d, 0xa0, 0xef, 0x6e, 0x7d, 0xd6, 0x7b, 0x39, 0x30, 0x72, 0x76, 0xb2, 0x2b, 0xef, 0x39, 0x01,
0x52, 0xd0, 0x9d, 0xec, 0x0a, 0x7f, 0x4c, 0xb0, 0x31, 0x88, 0x85, 0x8f, 0xe4, 0x63, 0xc1, 0x5e,
0xeb, 0x67, 0xe5, 0x48, 0x71, 0xa5, 0xbc, 0xf3, 0xb0, 0xfc, 0x5e, 0x3f, 0x68, 0x2f, 0xc0, 0x1e,
0x55, 0x3c, 0x61, 0x75, 0xad, 0xbe, 0x49, 0xea, 0xdf, 0x30, 0x52, 0xb2, 0x09, 0xf8, 0x22, 0xe9,
0x9d, 0x30, 0xe4, 0x7c, 0x48, 0xb0, 0x15, 0xd9, 0xef, 0x1b, 0xad, 0xa1, 0x9a, 0xdd, 0x4f, 0x1b,
0xad, 0xf7, 0x72, 0x76, 0x78, 0x29, 0xa9, 0xfb, 0x41, 0xa3, 0x7b, 0xa8, 0x3a, 0xf6, 0x2d, 0xa3,
0xfb, 0x03, 0x48, 0xe5, 0xea, 0xf3, 0xe8, 0xcd, 0x7d, 0x3e, 0x9f, 0xb1, 0x22, 0x1d, 0x7f, 0xcf,
0xbf, 0x42, 0xcb, 0xe7, 0x93, 0xe6, 0xcf, 0xc6, 0xe8, 0x0d, 0x4a, 0x6c, 0x2f, 0x01, 0xee, 0xb0,
0xb3, 0xe5, 0x7c, 0x26, 0x62, 0x01, 0x2e, 0x01, 0xca, 0xbf, 0x4f, 0x1a, 0x01, 0x71, 0x09, 0xd0,
0x03, 0x80, 0xbd, 0x93, 0x8a, 0x31, 0xd4, 0x5e, 0x23, 0x08, 0xda, 0x53, 0x80, 0xcd, 0x22, 0x8c,
0xbd, 0x26, 0x51, 0x87, 0x97, 0xf6, 0xac, 0x8e, 0x94, 0x12, 0x59, 0x44, 0x97, 0xb2, 0xc1, 0xdd,
0x56, 0x5f, 0x7e, 0x5f, 0x66, 0xb9, 0x58, 0xc4, 0xd5, 0x0a, 0x04, 0xb7, 0xaa, 0xa5, 0x03, 0x10,
0xc1, 0x8d, 0x82, 0x76, 0xd4, 0xea, 0x66, 0x4e, 0x2e, 0x77, 0x79, 0xc5, 0x97, 0x22, 0x2b, 0x18,
0xfc, 0xc6, 0x88, 0x69, 0x50, 0x97, 0x21, 0x46, 0x2d, 0xc5, 0xda, 0x2c, 0x57, 0x12, 0xed, 0x7d,
0x42, 0xf9, 0x99, 0xf4, 0x5a, 0xf0, 0x0a, 0x3e, 0x4f, 0x6c, 0xad, 0x40, 0x88, 0xc8, 0x72, 0x49,
0x18, 0xf4, 0xfd, 0x51, 0x56, 0xcc, 0xd1, 0xbe, 0x3f, 0x72, 0xbf, 0xf3, 0x7b, 0x8b, 0x06, 0xec,
0x80, 0x6a, 0x1b, 0xad, 0x1d, 0x00, 0xea, 0xad, 0x5d, 0xb4, 0xd1, 0x5d, 0x82, 0x18, 0x50, 0x38,
0x09, 0x5c, 0x7d, 0x51, 0xb2, 0x82, 0xa5, 0xfa, 0xd6, 0x1c, 0xe6, 0xca, 0x23, 0x82, 0xae, 0x20,
0x69, 0xe7, 0x22, 0x29, 0x3f, 0x5e, 0x16, 0x47, 0x15, 0x3f, 0xcf, 0x72, 0x56, 0x81, 0xb9, 0xa8,
0x55, 0x77, 0xe4, 0xc4, 0x5c, 0x84, 0x71, 0xf6, 0xfa, 0x85, 0x94, 0x7a, 0xdf, 0xfa, 0x3f, 0xa9,
0xe2, 0x04, 0x5e, 0xbf, 0x68, 0x6d, 0x74, 0x31, 0xe2, 0x64, 0x30, 0x80, 0x3b, 0x89, 0x4e, 0xeb,
0xba, 0x58, 0xc9, 0xf8, 0x50, 0x6f, 0x8d, 0xca, 0xaf, 0xdf, 0xd6, 0x20, 0xd1, 0x51, 0xe6, 0x30,
0x92, 0x48, 0x74, 0xc2, 0x1a, 0x76, 0x29, 0x91, 0xdc, 0xa1, 0xba, 0x56, 0x04, 0x96, 0x92, 0xd6,
0x86, 0x16, 0x12, 0x4b, 0x49, 0x07, 0x02, 0x13, 0x92, 0x1e, 0x06, 0x73, 0x74, 0x42, 0x32, 0xd2,
0xe0, 0x84, 0xe4, 0x52, 0x76, 0xa2, 0xd8, 0x2b, 0x32, 0x91, 0xc5, 0xf9, 0x8c, 0x89, 0xa3, 0xb8,
0x8a, 0x17, 0x4c, 0xb0, 0x0a, 0x4e, 0x14, 0x0a, 0x99, 0x78, 0x0c, 0x31, 0x51, 0x50, 0xac, 0x72,
0xf8, 0xdb, 0xd1, 0xdb, 0xcd, 0xba, 0xcf, 0x0a, 0xf5, 0xab, 0x3e, 0xcf, 0xe4, 0xcf, 0x81, 0x8d,
0xdf, 0x31, 0x36, 0x66, 0xa2, 0x62, 0xf1, 0x42, 0xdb, 0x7e, 0xcb, 0xfc, 0x5d, 0x82, 0x8f, 0x46,
0x4d, 0x3c, 0x1f, 0x72, 0x91, 0x9d, 0x37, 0xdb, 0x6c, 0xf5, 0x06, 0x11, 0x88, 0x67, 0x57, 0x3c,
0x09, 0x7c, 0x75, 0x04, 0xe3, 0xec, 0x3c, 0xed, 0x4a, 0x8f, 0x59, 0x99, 0xc3, 0x79, 0xda, 0xd3,
0x96, 0x00, 0x31, 0x4f, 0xa3, 0xa0, 0x1d, 0x9c, 0xae, 0xf8, 0x84, 0x85, 0x2b, 0x73, 0xc2, 0x86,
0x55, 0xe6, 0xc4, 0x7b, 0x29, 0x23, 0x8f, 0xde, 0x3e, 0x60, 0x8b, 0x33, 0x56, 0xd5, 0x17, 0x59,
0x49, 0x7d, 0xa1, 0xd7, 0x12, 0xbd, 0x5f, 0xe8, 0x25, 0x50, 0xbb, 0x12, 0x58, 0x60, 0xaf, 0x3e,
0x8c, 0x17, 0x4c, 0x7e, 0x43, 0x05, 0xac, 0x04, 0x8e, 0x11, 0x07, 0x22, 0x56, 0x02, 0x12, 0x76,
0xde, 0xef, 0xb2, 0xcc, 0x31, 0x9b, 0x37, 0x11, 0x56, 0x1d, 0xc5, 0xab, 0x05, 0x2b, 0x84, 0x32,
0x09, 0xce, 0xe4, 0x1d, 0x93, 0x38, 0x4f, 0x9c, 0xc9, 0x0f, 0xd1, 0x73, 0xa6, 0x26, 0xaf, 0xe1,
0x8f, 0x78, 0x25, 0xda, 0xdf, 0xec, 0x3a, 0xad, 0x72, 0x30, 0x35, 0xf9, 0x8d, 0xea, 0x91, 0xc4,
0xd4, 0x14, 0xd6, 0x70, 0x7e, 0x6f, 0xc2, 0x2b, 0xc3, 0x0b, 0x56, 0x99, 0x38, 0x79, 0xb6, 0x88,
0xb3, 0x5c, 0x45, 0xc3, 0xf7, 0x03, 0xb6, 0x09, 0x1d, 0xe2, 0xf7, 0x26, 0x86, 0xea, 0x3a, 0xbf,
0xd0, 0x11, 0x2e, 0x21, 0x78, 0x44, 0xd0, 0x63, 0x9f, 0x78, 0x44, 0xd0, 0xaf, 0x65, 0x77, 0xee,
0x96, 0x95, 0xdc, 0x4a, 0x12, 0xdb, 0x3c, 0x85, 0xe7, 0x85, 0x8e, 0x4d, 0x00, 0x12, 0x3b, 0xf7,
0xa0, 0x82, 0x4d, 0x0d, 0x2c, 0xf6, 0x3c, 0x2b, 0xe2, 0x3c, 0xfb, 0x09, 0x4c, 0xeb, 0x1d, 0x3b,
0x9a, 0x20, 0x52, 0x03, 0x9c, 0xc4, 0x5c, 0xed, 0x32, 0x71, 0x92, 0x35, 0x53, 0xff, 0xbd, 0x40,
0xbb, 0x49, 0xa2, 0xdf, 0x95, 0x43, 0x3a, 0x5f, 0xe3, 0x85, 0xcd, 0x3a, 0x2d, 0xcb, 0x59, 0xb3,
0xaa, 0x1e, 0xb3, 0x84, 0x65, 0xa5, 0x18, 0x7f, 0x1c, 0x6e, 0x2b, 0x80, 0x13, 0x17, 0x2d, 0x06,
0xa8, 0x39, 0x8f, 0xef, 0x9b, 0xb9, 0x64, 0xd6, 0xfe, 0x98, 0xe5, 0x69, 0xcd, 0x2a, 0x95, 0x68,
0xec, 0x32, 0x01, 0x46, 0xa7, 0xc3, 0x4d, 0x1c, 0xb0, 0xa9, 0x28, 0x31, 0x3a, 0xc3, 0x1a, 0xf6,
0xb0, 0xcf, 0xe1, 0xd4, 0xd7, 0xd5, 0xe5, 0x7d, 0xc3, 0x87, 0xa4, 0x31, 0x87, 0x22, 0x0e, 0xfb,
0x68, 0xda, 0x66, 0x6b, 0x5d, 0xb7, 0xd3, 0x62, 0xb5, 0x07, 0xaf, 0x4c, 0x20, 0x96, 0x24, 0x46,
0x64, 0x6b, 0x01, 0xdc, 0x39, 0x0c, 0xaf, 0x78, 0x9c, 0x26, 0x71, 0x2d, 0x8e, 0xe2, 0x55, 0xce,
0xe3, 0x54, 0xae, 0xeb, 0xf0, 0x30, 0x5c, 0x33, 0x13, 0x17, 0xa2, 0x0e, 0xc3, 0x29, 0xd8, 0xcd,
0xce, 0xe4, 0x6f, 0x74, 0xaa, 0xbb, 0x9c, 0x30, 0x3b, 0x93, 0xe5, 0x85, 0xf7, 0x38, 0xef, 0x84,
0x21, 0xfb, 0x0e, 0x5a, 0x2b, 0x92, 0x69, 0xc8, 0x2d, 0x4c, 0xc7, 0x4b, 0x40, 0xde, 0x0f, 0x10,
0xf6, 0x0b, 0x24, 0xed, 0xdf, 0xf5, 0xcf, 0x4c, 0x09, 0xf5, 0xcd, 0xf2, 0x87, 0x98, 0xae, 0x0b,
0x4d, 0xdc, 0x0f, 0x59, 0x6c, 0x0e, 0xa4, 0x6d, 0x9a, 0xb9, 0x7d, 0x11, 0x8b, 0x69, 0x9a, 0x1e,
0xb0, 0x1a, 0x79, 0xa1, 0xbc, 0x11, 0x4e, 0xac, 0x94, 0x48, 0x33, 0xbb, 0x94, 0x0d, 0xf4, 0x46,
0xf6, 0x2c, 0xcd, 0x84, 0x92, 0xe9, 0x1b, 0xd2, 0x0f, 0xbb, 0x06, 0xba, 0x14, 0x51, 0x2b, 0x9a,
0xb6, 0x73, 0x79, 0xc3, 0x9c, 0xf0, 0xf9, 0x3c, 0x67, 0x0a, 0x3a, 0x66, 0x71, 0xfb, 0xc9, 0xc6,
0xad, 0xae, 0x2d, 0x14, 0x24, 0xe6, 0xf2, 0xa0, 0x82, 0x4d, 0x23, 0x1b, 0xac, 0x7d, 0x24, 0xa5,
0x1b, 0x76, 0xbd, 0x6b, 0xc6, 0x03, 0x88, 0x34, 0x12, 0x05, 0xed, 0x7b, 0x6f, 0x8d, 0x78, 0x97,
0xe9, 0x96, 0x80, 0x1f, 0x9b, 0x92, 0xca, 0x8e, 0x98, 0x78, 0xef, 0x0d, 0xc1, 0xec, 0x3e, 0x01,
0x78, 0x78, 0xba, 0xda, 0x4b, 0xe1, 0x3e, 0x01, 0xea, 0x4b, 0x86, 0xd8, 0x27, 0x50, 0xac, 0xdf,
0x75, 0xe6, 0xdc, 0x6b, 0x3f, 0xae, 0x6d, 0xe5, 0x90, 0xae, 0x43, 0xc1, 0x50, 0xd7, 0x51, 0x0a,
0x7e, 0x93, 0xba, 0x47, 0x6b, 0x48, 0x93, 0x62, 0xe7, 0x6a, 0x6b, 0x7d, 0x98, 0x9d, 0x97, 0xcc,
0x7e, 0x52, 0x5e, 0x59, 0xc2, 0x7f, 0xab, 0xa1, 0x15, 0x12, 0xf3, 0x52, 0x07, 0x6a, 0x6d, 0x3f,
0x7d, 0xff, 0x3f, 0xbf, 0xba, 0x31, 0xfa, 0xd9, 0x57, 0x37, 0x46, 0xff, 0xf3, 0xd5, 0x8d, 0xd1,
0x4f, 0xbf, 0xbe, 0xf1, 0xc6, 0xcf, 0xbe, 0xbe, 0xf1, 0xc6, 0x7f, 0x7f, 0x7d, 0xe3, 0x8d, 0x2f,
0xdf, 0x54, 0xbf, 0xdd, 0x7c, 0xf6, 0x73, 0xf2, 0x17, 0x98, 0x9f, 0xfc, 0x5f, 0x00, 0x00, 0x00,
0xff, 0xff, 0x95, 0x51, 0xdf, 0xf9, 0xdf, 0x79, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -413,8 +411,6 @@ type ClientCommandsClient interface {
// Account
// ***
AccountRecover(ctx context.Context, in *pb.RpcAccountRecoverRequest, opts ...grpc.CallOption) (*pb.RpcAccountRecoverResponse, error)
AccountMigrate(ctx context.Context, in *pb.RpcAccountMigrateRequest, opts ...grpc.CallOption) (*pb.RpcAccountMigrateResponse, error)
AccountMigrateCancel(ctx context.Context, in *pb.RpcAccountMigrateCancelRequest, opts ...grpc.CallOption) (*pb.RpcAccountMigrateCancelResponse, error)
AccountCreate(ctx context.Context, in *pb.RpcAccountCreateRequest, opts ...grpc.CallOption) (*pb.RpcAccountCreateResponse, error)
AccountDelete(ctx context.Context, in *pb.RpcAccountDeleteRequest, opts ...grpc.CallOption) (*pb.RpcAccountDeleteResponse, error)
AccountRevertDeletion(ctx context.Context, in *pb.RpcAccountRevertDeletionRequest, opts ...grpc.CallOption) (*pb.RpcAccountRevertDeletionResponse, error)
@ -929,24 +925,6 @@ func (c *clientCommandsClient) AccountRecover(ctx context.Context, in *pb.RpcAcc
return out, nil
}
func (c *clientCommandsClient) AccountMigrate(ctx context.Context, in *pb.RpcAccountMigrateRequest, opts ...grpc.CallOption) (*pb.RpcAccountMigrateResponse, error) {
out := new(pb.RpcAccountMigrateResponse)
err := c.cc.Invoke(ctx, "/anytype.ClientCommands/AccountMigrate", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *clientCommandsClient) AccountMigrateCancel(ctx context.Context, in *pb.RpcAccountMigrateCancelRequest, opts ...grpc.CallOption) (*pb.RpcAccountMigrateCancelResponse, error) {
out := new(pb.RpcAccountMigrateCancelResponse)
err := c.cc.Invoke(ctx, "/anytype.ClientCommands/AccountMigrateCancel", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *clientCommandsClient) AccountCreate(ctx context.Context, in *pb.RpcAccountCreateRequest, opts ...grpc.CallOption) (*pb.RpcAccountCreateResponse, error) {
out := new(pb.RpcAccountCreateResponse)
err := c.cc.Invoke(ctx, "/anytype.ClientCommands/AccountCreate", in, out, opts...)
@ -3321,8 +3299,6 @@ type ClientCommandsServer interface {
// Account
// ***
AccountRecover(context.Context, *pb.RpcAccountRecoverRequest) *pb.RpcAccountRecoverResponse
AccountMigrate(context.Context, *pb.RpcAccountMigrateRequest) *pb.RpcAccountMigrateResponse
AccountMigrateCancel(context.Context, *pb.RpcAccountMigrateCancelRequest) *pb.RpcAccountMigrateCancelResponse
AccountCreate(context.Context, *pb.RpcAccountCreateRequest) *pb.RpcAccountCreateResponse
AccountDelete(context.Context, *pb.RpcAccountDeleteRequest) *pb.RpcAccountDeleteResponse
AccountRevertDeletion(context.Context, *pb.RpcAccountRevertDeletionRequest) *pb.RpcAccountRevertDeletionResponse
@ -3707,12 +3683,6 @@ func (*UnimplementedClientCommandsServer) WorkspaceExport(ctx context.Context, r
func (*UnimplementedClientCommandsServer) AccountRecover(ctx context.Context, req *pb.RpcAccountRecoverRequest) *pb.RpcAccountRecoverResponse {
return nil
}
func (*UnimplementedClientCommandsServer) AccountMigrate(ctx context.Context, req *pb.RpcAccountMigrateRequest) *pb.RpcAccountMigrateResponse {
return nil
}
func (*UnimplementedClientCommandsServer) AccountMigrateCancel(ctx context.Context, req *pb.RpcAccountMigrateCancelRequest) *pb.RpcAccountMigrateCancelResponse {
return nil
}
func (*UnimplementedClientCommandsServer) AccountCreate(ctx context.Context, req *pb.RpcAccountCreateRequest) *pb.RpcAccountCreateResponse {
return nil
}
@ -4870,42 +4840,6 @@ func _ClientCommands_AccountRecover_Handler(srv interface{}, ctx context.Context
return interceptor(ctx, in, info, handler)
}
func _ClientCommands_AccountMigrate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(pb.RpcAccountMigrateRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ClientCommandsServer).AccountMigrate(ctx, in), nil
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/anytype.ClientCommands/AccountMigrate",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ClientCommandsServer).AccountMigrate(ctx, req.(*pb.RpcAccountMigrateRequest)), nil
}
return interceptor(ctx, in, info, handler)
}
func _ClientCommands_AccountMigrateCancel_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(pb.RpcAccountMigrateCancelRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ClientCommandsServer).AccountMigrateCancel(ctx, in), nil
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/anytype.ClientCommands/AccountMigrateCancel",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ClientCommandsServer).AccountMigrateCancel(ctx, req.(*pb.RpcAccountMigrateCancelRequest)), nil
}
return interceptor(ctx, in, info, handler)
}
func _ClientCommands_AccountCreate_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(pb.RpcAccountCreateRequest)
if err := dec(in); err != nil {
@ -9642,14 +9576,6 @@ var _ClientCommands_serviceDesc = grpc.ServiceDesc{
MethodName: "AccountRecover",
Handler: _ClientCommands_AccountRecover_Handler,
},
{
MethodName: "AccountMigrate",
Handler: _ClientCommands_AccountMigrate_Handler,
},
{
MethodName: "AccountMigrateCancel",
Handler: _ClientCommands_AccountMigrateCancel_Handler,
},
{
MethodName: "AccountCreate",
Handler: _ClientCommands_AccountCreate_Handler,

View file

@ -170,13 +170,10 @@ func (r *clientds) Init(a *app.App) (err error) {
r.localstoreDS, err = openBadgerWithRecover(opts)
err = anyerror.CleanupError(err)
if err != nil && isBadgerCorrupted(err) {
log.With("error", err).Error("badger db is corrupted")
// because localstore contains mostly recoverable info (with th only exception of objects' lastOpenedDate)
// we can just remove and recreate it
err2 := os.Rename(opts.Dir, opts.Dir+"-corrupted")
if err2 != nil {
log.Errorf("failed to rename corrupted localstore: %s", err2)
}
err2 := os.Rename(opts.Dir, filepath.Join(opts.Dir, "-corrupted"))
log.Errorf("failed to rename corrupted localstore: %s", err2)
var errAfterRemove error
r.localstoreDS, errAfterRemove = openBadgerWithRecover(opts)
errAfterRemove = anyerror.CleanupError(errAfterRemove)

View file

@ -75,14 +75,16 @@ func (w *walletStub) Name() string { return wallet.CName }
func NewStoreFixture(t testing.TB) *StoreFixture {
ctx, cancel := context.WithCancel(context.Background())
walletService := newWalletStub(t)
fullText := ftsearch.TantivyNew()
testApp := &app.App{}
dataStore, err := datastore.NewInMemory()
require.NoError(t, err)
testApp.Register(newWalletStub(t))
testApp.Register(dataStore)
testApp.Register(walletService)
err = fullText.Init(testApp)
require.NoError(t, err)
err = fullText.Run(context.Background())
@ -98,7 +100,7 @@ func NewStoreFixture(t testing.TB) *StoreFixture {
fts: fullText,
sourceService: &detailsFromId{},
arenaPool: &anyenc.ArenaPool{},
objectStorePath: t.TempDir(),
repoPath: walletService.RepoPath(),
oldStore: oldStore,
spaceIndexes: map[string]spaceindex.Store{},
techSpaceIdProvider: &stubTechSpaceIdProvider{},

View file

@ -20,7 +20,6 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/anystorehelper"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/oldstore"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceindex"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceresolverstore"
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
)
@ -53,7 +52,6 @@ type ObjectStore interface {
GetCrdtDb(spaceId string) anystore.DB
SpaceNameGetter
spaceresolverstore.Store
CrossSpace
}
@ -88,11 +86,9 @@ type TechSpaceIdProvider interface {
}
type dsObjectStore struct {
spaceresolverstore.Store
objectStorePath string
techSpaceId string
anyStoreConfig anystore.Config
repoPath string
techSpaceId string
anyStoreConfig anystore.Config
anyStore anystore.DB
anyStoreLockRemove func() error
@ -149,9 +145,6 @@ func New() ObjectStore {
func (s *dsObjectStore) Init(a *app.App) (err error) {
s.sourceService = app.MustComponent[spaceindex.SourceDetailsFromID](a)
repoPath := app.MustComponent[wallet.Wallet](a).RepoPath()
fts := a.Component(ftsearch.CName)
if fts == nil {
log.Warnf("init objectstore without fulltext")
@ -159,10 +152,8 @@ func (s *dsObjectStore) Init(a *app.App) (err error) {
s.fts = fts.(ftsearch.FTSearch)
}
s.arenaPool = &anyenc.ArenaPool{}
cfg := app.MustComponent[configProvider](a)
s.objectStorePath = filepath.Join(repoPath, "objectstore")
s.anyStoreConfig = *cfg.GetAnyStoreConfig()
s.repoPath = app.MustComponent[wallet.Wallet](a).RepoPath()
s.anyStoreConfig = *app.MustComponent[configProvider](a).GetAnyStoreConfig()
s.setDefaultConfig()
s.oldStore = app.MustComponent[oldstore.Service](a)
s.techSpaceIdProvider = app.MustComponent[TechSpaceIdProvider](a)
@ -177,23 +168,12 @@ func (s *dsObjectStore) Name() (name string) {
func (s *dsObjectStore) Run(ctx context.Context) error {
s.techSpaceId = s.techSpaceIdProvider.TechSpaceId()
err := ensureDirExists(s.objectStorePath)
dbDir := s.storeRootDir()
err := ensureDirExists(dbDir)
if err != nil {
return err
}
err = s.openDatabase(ctx, filepath.Join(s.objectStorePath, "objects.db"))
if err != nil {
return fmt.Errorf("open db: %w", err)
}
store, err := spaceresolverstore.New(s.componentCtx, s.anyStore)
if err != nil {
return fmt.Errorf("new space resolver store: %w", err)
}
s.Store = store
return err
return s.openDatabase(ctx, filepath.Join(dbDir, "objects.db"))
}
func (s *dsObjectStore) setDefaultConfig() {
@ -204,6 +184,10 @@ func (s *dsObjectStore) setDefaultConfig() {
s.anyStoreConfig.SQLiteConnectionOptions["synchronous"] = "off"
}
func (s *dsObjectStore) storeRootDir() string {
return filepath.Join(s.repoPath, "objectstore")
}
func ensureDirExists(dir string) error {
_, err := os.Stat(dir)
if errors.Is(err, os.ErrNotExist) {
@ -254,7 +238,7 @@ func (s *dsObjectStore) preloadExistingObjectStores() error {
var err error
s.spaceStoreDirsCheck.Do(func() {
var entries []os.DirEntry
entries, err = os.ReadDir(s.objectStorePath)
entries, err = os.ReadDir(s.storeRootDir())
s.Lock()
defer s.Unlock()
for _, entry := range entries {
@ -316,7 +300,7 @@ func (s *dsObjectStore) SpaceIndex(spaceId string) spaceindex.Store {
func (s *dsObjectStore) getOrInitSpaceIndex(spaceId string) spaceindex.Store {
store, ok := s.spaceIndexes[spaceId]
if !ok {
dir := filepath.Join(s.objectStorePath, spaceId)
dir := filepath.Join(s.storeRootDir(), spaceId)
err := ensureDirExists(dir)
if err != nil {
return spaceindex.NewInvalidStore(err)
@ -350,7 +334,7 @@ func (s *dsObjectStore) GetCrdtDb(spaceId string) anystore.DB {
db, ok := s.crdtDbs[spaceId]
if !ok {
dir := filepath.Join(s.objectStorePath, spaceId)
dir := filepath.Join(s.storeRootDir(), spaceId)
err := ensureDirExists(dir)
if err != nil {
return nil

View file

@ -1,71 +0,0 @@
package spaceresolverstore
import (
"context"
"errors"
"fmt"
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-store/anyenc"
"github.com/anyproto/any-store/query"
"github.com/anyproto/anytype-heart/core/domain"
)
const bindKey = "b"
type Store interface {
BindSpaceId(spaceId, objectId string) error
GetSpaceId(objectId string) (spaceId string, err error)
}
type dsObjectStore struct {
componentCtx context.Context
collection anystore.Collection
arenaPool *anyenc.ArenaPool
}
func New(componentCtx context.Context, db anystore.DB) (Store, error) {
collection, err := db.Collection(componentCtx, "bindId")
if err != nil {
return nil, fmt.Errorf("open bindId collection: %w", err)
}
return &dsObjectStore{
componentCtx: componentCtx,
arenaPool: &anyenc.ArenaPool{},
collection: collection,
}, nil
}
func (d *dsObjectStore) BindSpaceId(spaceId, objectId string) error {
return d.modifyBind(d.componentCtx, objectId, spaceId)
}
func (d *dsObjectStore) GetSpaceId(objectId string) (spaceId string, err error) {
doc, err := d.collection.FindId(d.componentCtx, objectId)
if err != nil {
if errors.Is(err, anystore.ErrDocNotFound) {
return "", domain.ErrObjectNotFound
}
return "", err
}
return doc.Value().GetString(bindKey), nil
}
func (d *dsObjectStore) modifyBind(ctx context.Context, objectId, spaceId string) error {
tx, err := d.collection.WriteTx(ctx)
if err != nil {
return err
}
arena := d.arenaPool.Get()
defer d.arenaPool.Put(arena)
mod := query.ModifyFunc(func(a *anyenc.Arena, v *anyenc.Value) (result *anyenc.Value, modified bool, err error) {
v.Set(bindKey, arena.NewString(spaceId))
return v, true, nil
})
_, err = d.collection.UpsertId(tx.Context(), objectId, mod)
if err != nil {
return errors.Join(err, tx.Rollback())
}
return tx.Commit()
}

View file

@ -3,12 +3,10 @@
package mock_clientspace
import (
anystorage "github.com/anyproto/anytype-heart/space/spacecore/storage/anystorage"
context "context"
commonspace "github.com/anyproto/any-sync/commonspace"
context "context"
domain "github.com/anyproto/anytype-heart/core/domain"
headsync "github.com/anyproto/any-sync/commonspace/headsync"
@ -23,6 +21,8 @@ import (
smartblock "github.com/anyproto/anytype-heart/core/block/editor/smartblock"
spacestorage "github.com/anyproto/any-sync/commonspace/spacestorage"
threads "github.com/anyproto/anytype-heart/pkg/lib/threads"
treestorage "github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
@ -1511,19 +1511,19 @@ func (_c *MockSpace_Remove_Call) RunAndReturn(run func(context.Context, string)
}
// Storage provides a mock function with given fields:
func (_m *MockSpace) Storage() anystorage.ClientSpaceStorage {
func (_m *MockSpace) Storage() spacestorage.SpaceStorage {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for Storage")
}
var r0 anystorage.ClientSpaceStorage
if rf, ok := ret.Get(0).(func() anystorage.ClientSpaceStorage); ok {
var r0 spacestorage.SpaceStorage
if rf, ok := ret.Get(0).(func() spacestorage.SpaceStorage); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(anystorage.ClientSpaceStorage)
r0 = ret.Get(0).(spacestorage.SpaceStorage)
}
}
@ -1547,12 +1547,12 @@ func (_c *MockSpace_Storage_Call) Run(run func()) *MockSpace_Storage_Call {
return _c
}
func (_c *MockSpace_Storage_Call) Return(_a0 anystorage.ClientSpaceStorage) *MockSpace_Storage_Call {
func (_c *MockSpace_Storage_Call) Return(_a0 spacestorage.SpaceStorage) *MockSpace_Storage_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockSpace_Storage_Call) RunAndReturn(run func() anystorage.ClientSpaceStorage) *MockSpace_Storage_Call {
func (_c *MockSpace_Storage_Call) RunAndReturn(run func() spacestorage.SpaceStorage) *MockSpace_Storage_Call {
_c.Call.Return(run)
return _c
}

View file

@ -11,6 +11,7 @@ import (
"github.com/anyproto/any-sync/commonspace"
"github.com/anyproto/any-sync/commonspace/headsync"
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/any-sync/net/peer"
"github.com/anyproto/any-sync/util/crypto"
"go.uber.org/zap"
@ -28,7 +29,6 @@ import (
"github.com/anyproto/anytype-heart/space/spacecore"
"github.com/anyproto/anytype-heart/space/spacecore/peermanager"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/anystorage"
)
type Space interface {
@ -40,7 +40,7 @@ type Space interface {
DebugAllHeads() []headsync.TreeHeads
DeleteTree(ctx context.Context, id string) (err error)
StoredIds() []string
Storage() anystorage.ClientSpaceStorage
Storage() spacestorage.SpaceStorage
DerivedIDs() threads.DerivedSmartblockIds
@ -124,16 +124,12 @@ func BuildSpace(ctx context.Context, deps SpaceDeps) (Space, error) {
if err != nil {
return nil, fmt.Errorf("derive object ids: %w", err)
}
isSpaceCreated, err := sp.Storage().IsSpaceCreated(ctx)
if err != nil {
return nil, fmt.Errorf("is space created: %w", err)
}
if isSpaceCreated {
if deps.StorageService.IsSpaceCreated(deps.CommonSpace.Id()) {
err = sp.ObjectProvider.CreateMandatoryObjects(ctx, sp)
if err != nil {
return nil, fmt.Errorf("create mandatory objects: %w", err)
}
err = sp.Storage().UnmarkSpaceCreated(ctx)
err = deps.StorageService.UnmarkSpaceCreated(deps.CommonSpace.Id())
if err != nil {
return nil, fmt.Errorf("unmark space created: %w", err)
}
@ -211,8 +207,8 @@ func (s *space) StoredIds() []string {
return s.common.StoredIds()
}
func (s *space) Storage() anystorage.ClientSpaceStorage {
return s.common.Storage().(anystorage.ClientSpaceStorage)
func (s *space) Storage() spacestorage.SpaceStorage {
return s.common.Storage()
}
func (s *space) DerivedIDs() threads.DerivedSmartblockIds {
@ -309,7 +305,10 @@ func (s *space) TryLoadBundledObjects(ctx context.Context) (missingSourceIds []s
if err != nil {
return nil, err
}
storedIds := s.StoredIds()
storedIds, err := s.Storage().StoredIds()
if err != nil {
return nil, err
}
missingIds := bundledObjectIds.Filter(func(bo domain.BundledObjectId) bool {
return !slices.Contains(storedIds, bo.DerivedObjectId)
@ -319,7 +318,11 @@ func (s *space) TryLoadBundledObjects(ctx context.Context) (missingSourceIds []s
s.LoadObjectsIgnoreErrs(ctx, missingIds.DerivedObjectIds())
// todo: make LoadObjectsIgnoreErrs return list of loaded ids
storedIds = s.StoredIds()
storedIds, err = s.Storage().StoredIds()
if err != nil {
return nil, err
}
missingIds = bundledObjectIds.Filter(func(bo domain.BundledObjectId) bool {
return !slices.Contains(storedIds, bo.DerivedObjectId)
})
@ -345,10 +348,7 @@ func (s *space) migrationProfileObject(ctx context.Context) error {
return err
}
extractedProfileExists, err := s.Storage().HasTree(ctx, extractedProfileId)
if err != nil {
return err
}
extractedProfileExists, _ := s.Storage().HasTree(extractedProfileId)
if extractedProfileExists {
return nil
}

View file

@ -77,6 +77,10 @@ func (c *virtualCommonSpace) HandleStreamSyncRequest(ctx context.Context, req *s
return nil
}
func (c *virtualCommonSpace) HandleDeprecatedObjectSyncRequest(ctx context.Context, req *spacesyncproto.ObjectSyncMessage) (resp *spacesyncproto.ObjectSyncMessage, err error) {
return
}
func (c *virtualCommonSpace) HandleStream(stream spacesyncproto.DRPCSpaceSync_ObjectSyncStreamStream) error {
return nil
}
@ -109,7 +113,7 @@ func (c *virtualCommonSpace) DebugAllHeads() []headsync.TreeHeads {
return nil
}
func (c *virtualCommonSpace) Description(ctx context.Context) (desc commonspace.SpaceDescription, err error) {
func (c *virtualCommonSpace) Description() (desc commonspace.SpaceDescription, err error) {
return
}

View file

@ -238,6 +238,10 @@ func (s *syncAclStub) HandleRequest(ctx context.Context, senderId string, reques
return
}
func (s *syncAclStub) SetHeadUpdater(updater headupdater.HeadUpdater) {
return
}
func (s *syncAclStub) SetAclUpdater(updater headupdater.AclUpdater) {
s.updater = updater
return

View file

@ -1,65 +0,0 @@
package oldstorage
import (
"context"
"fmt"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/badgerstorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/sqlitestorage"
)
type SpaceStorageMode int
const CName = "client.spacecore.oldstorage"
const (
SpaceStorageModeSqlite SpaceStorageMode = iota // used for new account repos
SpaceStorageModeBadger // used for existing account repos
)
type ClientStorage interface {
oldstorage.SpaceStorageProvider
app.ComponentRunnable
// GetBoundObjectIds returns list of object ids bound (mapped) to space id
GetBoundObjectIds(spaceId string) ([]string, error)
AllSpaceIds() (ids []string, err error)
DeleteSpaceStorage(ctx context.Context, spaceId string) error
GetSpaceID(objectID string) (spaceID string, err error)
EstimateSize() (uint64, error)
}
// storageService is a proxy for the actual storage implementation
type storageService struct {
ClientStorage
}
func New() ClientStorage {
return &storageService{}
}
type configGetter interface {
GetSpaceStorageMode() storage.SpaceStorageMode
}
func (s *storageService) Name() (name string) {
return CName
}
func (s *storageService) Init(a *app.App) (err error) {
mode := a.MustComponent("config").(configGetter).GetSpaceStorageMode()
if mode == storage.SpaceStorageModeBadger {
// for already existing account repos
s.ClientStorage = badgerstorage.New()
} else if mode == storage.SpaceStorageModeSqlite {
// sqlite used for new account repos
s.ClientStorage = sqlitestorage.New()
} else {
return fmt.Errorf("unknown storage mode %d", mode)
}
return s.ClientStorage.Init(a)
}

View file

@ -85,7 +85,7 @@ func (r *rpcHandler) SpacePull(ctx context.Context, request *spacesyncproto.Spac
return
}
spaceDesc, err := sp.Description(ctx)
spaceDesc, err := sp.Description()
if err != nil {
err = spacesyncproto.ErrUnexpected
return

View file

@ -1,132 +0,0 @@
package anystorage
import (
"context"
"errors"
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-store/anyenc"
"github.com/anyproto/any-store/query"
"github.com/anyproto/any-sync/commonspace/headsync/headstorage"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/spacestorage"
)
type ClientSpaceStorage interface {
spacestorage.SpaceStorage
HasTree(ctx context.Context, id string) (has bool, err error)
TreeRoot(ctx context.Context, id string) (root *treechangeproto.RawTreeChangeWithId, err error)
MarkSpaceCreated(ctx context.Context) error
IsSpaceCreated(ctx context.Context) (created bool, err error)
UnmarkSpaceCreated(ctx context.Context) error
AllDeletedTreeIds(ctx context.Context) (ids []string, err error)
}
var _ ClientSpaceStorage = (*clientStorage)(nil)
const (
clientCollectionKey = "_client"
clientDocumentKey = "space"
createdKey = "created"
rawChangeKey = "r"
)
type clientStorage struct {
spacestorage.SpaceStorage
clientColl anystore.Collection
}
func (r *clientStorage) AllDeletedTreeIds(ctx context.Context) (ids []string, err error) {
err = r.SpaceStorage.HeadStorage().IterateEntries(ctx, headstorage.IterOpts{Deleted: true}, func(entry headstorage.HeadsEntry) (bool, error) {
ids = append(ids, entry.Id)
return true, nil
})
return
}
func NewClientStorage(ctx context.Context, spaceStorage spacestorage.SpaceStorage) (*clientStorage, error) {
storage := &clientStorage{
SpaceStorage: spaceStorage,
}
anyStore := storage.AnyStore()
client, err := anyStore.Collection(ctx, clientCollectionKey)
if err != nil {
return nil, err
}
storage.clientColl = client
return storage, nil
}
func (r *clientStorage) Close(ctx context.Context) (err error) {
spaceStorageErr := r.SpaceStorage.Close(ctx)
anyStoreErr := r.SpaceStorage.AnyStore().Close()
return errors.Join(spaceStorageErr, anyStoreErr)
}
func (r *clientStorage) HasTree(ctx context.Context, id string) (has bool, err error) {
_, err = r.SpaceStorage.HeadStorage().GetEntry(ctx, id)
isNotFound := errors.Is(err, anystore.ErrDocNotFound)
if err != nil && !isNotFound {
return false, err
}
return !isNotFound, nil
}
func (r *clientStorage) TreeRoot(ctx context.Context, id string) (root *treechangeproto.RawTreeChangeWithId, err error) {
// it should be faster to do it that way, instead of calling TreeStorage
coll, err := r.SpaceStorage.AnyStore().OpenCollection(ctx, objecttree.CollName)
if err != nil {
return nil, err
}
doc, err := coll.FindId(ctx, id)
if err != nil {
return nil, err
}
return &treechangeproto.RawTreeChangeWithId{
Id: id,
RawChange: doc.Value().GetBytes(rawChangeKey),
}, nil
}
func (r *clientStorage) MarkSpaceCreated(ctx context.Context) error {
return r.modifyState(ctx, true)
}
func (r *clientStorage) IsSpaceCreated(ctx context.Context) (isCreated bool, err error) {
doc, err := r.clientColl.FindId(ctx, clientDocumentKey)
isNotFound := errors.Is(err, anystore.ErrDocNotFound)
if err != nil && !isNotFound {
return false, err
}
if isNotFound {
return false, nil
}
return doc.Value().GetBool(createdKey), nil
}
func (r *clientStorage) UnmarkSpaceCreated(ctx context.Context) error {
return r.modifyState(ctx, false)
}
func (r *clientStorage) modifyState(ctx context.Context, isCreated bool) error {
tx, err := r.clientColl.WriteTx(ctx)
if err != nil {
return err
}
arena := &anyenc.Arena{}
val := arena.NewTrue()
if !isCreated {
val = arena.NewFalse()
}
mod := query.ModifyFunc(func(a *anyenc.Arena, v *anyenc.Value) (result *anyenc.Value, modified bool, err error) {
v.Set(createdKey, val)
return v, true, nil
})
_, err = r.clientColl.UpsertId(tx.Context(), clientDocumentKey, mod)
if err != nil {
rollErr := tx.Rollback()
return errors.Join(err, rollErr)
}
return tx.Commit()
}

View file

@ -1,917 +0,0 @@
// Code generated by mockery. DO NOT EDIT.
package mock_anystorage
import (
anystore "github.com/anyproto/any-store"
app "github.com/anyproto/any-sync/app"
context "context"
headstorage "github.com/anyproto/any-sync/commonspace/headsync/headstorage"
list "github.com/anyproto/any-sync/commonspace/object/acl/list"
mock "github.com/stretchr/testify/mock"
objecttree "github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
statestorage "github.com/anyproto/any-sync/commonspace/headsync/statestorage"
treechangeproto "github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
treestorage "github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
)
// MockClientSpaceStorage is an autogenerated mock type for the ClientSpaceStorage type
type MockClientSpaceStorage struct {
mock.Mock
}
type MockClientSpaceStorage_Expecter struct {
mock *mock.Mock
}
func (_m *MockClientSpaceStorage) EXPECT() *MockClientSpaceStorage_Expecter {
return &MockClientSpaceStorage_Expecter{mock: &_m.Mock}
}
// AclStorage provides a mock function with given fields:
func (_m *MockClientSpaceStorage) AclStorage() (list.Storage, error) {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for AclStorage")
}
var r0 list.Storage
var r1 error
if rf, ok := ret.Get(0).(func() (list.Storage, error)); ok {
return rf()
}
if rf, ok := ret.Get(0).(func() list.Storage); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(list.Storage)
}
}
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockClientSpaceStorage_AclStorage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AclStorage'
type MockClientSpaceStorage_AclStorage_Call struct {
*mock.Call
}
// AclStorage is a helper method to define mock.On call
func (_e *MockClientSpaceStorage_Expecter) AclStorage() *MockClientSpaceStorage_AclStorage_Call {
return &MockClientSpaceStorage_AclStorage_Call{Call: _e.mock.On("AclStorage")}
}
func (_c *MockClientSpaceStorage_AclStorage_Call) Run(run func()) *MockClientSpaceStorage_AclStorage_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockClientSpaceStorage_AclStorage_Call) Return(_a0 list.Storage, _a1 error) *MockClientSpaceStorage_AclStorage_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockClientSpaceStorage_AclStorage_Call) RunAndReturn(run func() (list.Storage, error)) *MockClientSpaceStorage_AclStorage_Call {
_c.Call.Return(run)
return _c
}
// AllDeletedTreeIds provides a mock function with given fields: ctx
func (_m *MockClientSpaceStorage) AllDeletedTreeIds(ctx context.Context) ([]string, error) {
ret := _m.Called(ctx)
if len(ret) == 0 {
panic("no return value specified for AllDeletedTreeIds")
}
var r0 []string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context) ([]string, error)); ok {
return rf(ctx)
}
if rf, ok := ret.Get(0).(func(context.Context) []string); ok {
r0 = rf(ctx)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]string)
}
}
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockClientSpaceStorage_AllDeletedTreeIds_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AllDeletedTreeIds'
type MockClientSpaceStorage_AllDeletedTreeIds_Call struct {
*mock.Call
}
// AllDeletedTreeIds is a helper method to define mock.On call
// - ctx context.Context
func (_e *MockClientSpaceStorage_Expecter) AllDeletedTreeIds(ctx interface{}) *MockClientSpaceStorage_AllDeletedTreeIds_Call {
return &MockClientSpaceStorage_AllDeletedTreeIds_Call{Call: _e.mock.On("AllDeletedTreeIds", ctx)}
}
func (_c *MockClientSpaceStorage_AllDeletedTreeIds_Call) Run(run func(ctx context.Context)) *MockClientSpaceStorage_AllDeletedTreeIds_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context))
})
return _c
}
func (_c *MockClientSpaceStorage_AllDeletedTreeIds_Call) Return(ids []string, err error) *MockClientSpaceStorage_AllDeletedTreeIds_Call {
_c.Call.Return(ids, err)
return _c
}
func (_c *MockClientSpaceStorage_AllDeletedTreeIds_Call) RunAndReturn(run func(context.Context) ([]string, error)) *MockClientSpaceStorage_AllDeletedTreeIds_Call {
_c.Call.Return(run)
return _c
}
// AnyStore provides a mock function with given fields:
func (_m *MockClientSpaceStorage) AnyStore() anystore.DB {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for AnyStore")
}
var r0 anystore.DB
if rf, ok := ret.Get(0).(func() anystore.DB); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(anystore.DB)
}
}
return r0
}
// MockClientSpaceStorage_AnyStore_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AnyStore'
type MockClientSpaceStorage_AnyStore_Call struct {
*mock.Call
}
// AnyStore is a helper method to define mock.On call
func (_e *MockClientSpaceStorage_Expecter) AnyStore() *MockClientSpaceStorage_AnyStore_Call {
return &MockClientSpaceStorage_AnyStore_Call{Call: _e.mock.On("AnyStore")}
}
func (_c *MockClientSpaceStorage_AnyStore_Call) Run(run func()) *MockClientSpaceStorage_AnyStore_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockClientSpaceStorage_AnyStore_Call) Return(_a0 anystore.DB) *MockClientSpaceStorage_AnyStore_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockClientSpaceStorage_AnyStore_Call) RunAndReturn(run func() anystore.DB) *MockClientSpaceStorage_AnyStore_Call {
_c.Call.Return(run)
return _c
}
// Close provides a mock function with given fields: ctx
func (_m *MockClientSpaceStorage) 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
}
// MockClientSpaceStorage_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
type MockClientSpaceStorage_Close_Call struct {
*mock.Call
}
// Close is a helper method to define mock.On call
// - ctx context.Context
func (_e *MockClientSpaceStorage_Expecter) Close(ctx interface{}) *MockClientSpaceStorage_Close_Call {
return &MockClientSpaceStorage_Close_Call{Call: _e.mock.On("Close", ctx)}
}
func (_c *MockClientSpaceStorage_Close_Call) Run(run func(ctx context.Context)) *MockClientSpaceStorage_Close_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context))
})
return _c
}
func (_c *MockClientSpaceStorage_Close_Call) Return(err error) *MockClientSpaceStorage_Close_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockClientSpaceStorage_Close_Call) RunAndReturn(run func(context.Context) error) *MockClientSpaceStorage_Close_Call {
_c.Call.Return(run)
return _c
}
// CreateTreeStorage provides a mock function with given fields: ctx, payload
func (_m *MockClientSpaceStorage) CreateTreeStorage(ctx context.Context, payload treestorage.TreeStorageCreatePayload) (objecttree.Storage, error) {
ret := _m.Called(ctx, payload)
if len(ret) == 0 {
panic("no return value specified for CreateTreeStorage")
}
var r0 objecttree.Storage
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, treestorage.TreeStorageCreatePayload) (objecttree.Storage, error)); ok {
return rf(ctx, payload)
}
if rf, ok := ret.Get(0).(func(context.Context, treestorage.TreeStorageCreatePayload) objecttree.Storage); ok {
r0 = rf(ctx, payload)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(objecttree.Storage)
}
}
if rf, ok := ret.Get(1).(func(context.Context, treestorage.TreeStorageCreatePayload) error); ok {
r1 = rf(ctx, payload)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockClientSpaceStorage_CreateTreeStorage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CreateTreeStorage'
type MockClientSpaceStorage_CreateTreeStorage_Call struct {
*mock.Call
}
// CreateTreeStorage is a helper method to define mock.On call
// - ctx context.Context
// - payload treestorage.TreeStorageCreatePayload
func (_e *MockClientSpaceStorage_Expecter) CreateTreeStorage(ctx interface{}, payload interface{}) *MockClientSpaceStorage_CreateTreeStorage_Call {
return &MockClientSpaceStorage_CreateTreeStorage_Call{Call: _e.mock.On("CreateTreeStorage", ctx, payload)}
}
func (_c *MockClientSpaceStorage_CreateTreeStorage_Call) Run(run func(ctx context.Context, payload treestorage.TreeStorageCreatePayload)) *MockClientSpaceStorage_CreateTreeStorage_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(treestorage.TreeStorageCreatePayload))
})
return _c
}
func (_c *MockClientSpaceStorage_CreateTreeStorage_Call) Return(_a0 objecttree.Storage, _a1 error) *MockClientSpaceStorage_CreateTreeStorage_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockClientSpaceStorage_CreateTreeStorage_Call) RunAndReturn(run func(context.Context, treestorage.TreeStorageCreatePayload) (objecttree.Storage, error)) *MockClientSpaceStorage_CreateTreeStorage_Call {
_c.Call.Return(run)
return _c
}
// HasTree provides a mock function with given fields: ctx, id
func (_m *MockClientSpaceStorage) HasTree(ctx context.Context, id string) (bool, error) {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for HasTree")
}
var r0 bool
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, string) bool); ok {
r0 = rf(ctx, id)
} else {
r0 = ret.Get(0).(bool)
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockClientSpaceStorage_HasTree_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HasTree'
type MockClientSpaceStorage_HasTree_Call struct {
*mock.Call
}
// HasTree is a helper method to define mock.On call
// - ctx context.Context
// - id string
func (_e *MockClientSpaceStorage_Expecter) HasTree(ctx interface{}, id interface{}) *MockClientSpaceStorage_HasTree_Call {
return &MockClientSpaceStorage_HasTree_Call{Call: _e.mock.On("HasTree", ctx, id)}
}
func (_c *MockClientSpaceStorage_HasTree_Call) Run(run func(ctx context.Context, id string)) *MockClientSpaceStorage_HasTree_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string))
})
return _c
}
func (_c *MockClientSpaceStorage_HasTree_Call) Return(has bool, err error) *MockClientSpaceStorage_HasTree_Call {
_c.Call.Return(has, err)
return _c
}
func (_c *MockClientSpaceStorage_HasTree_Call) RunAndReturn(run func(context.Context, string) (bool, error)) *MockClientSpaceStorage_HasTree_Call {
_c.Call.Return(run)
return _c
}
// HeadStorage provides a mock function with given fields:
func (_m *MockClientSpaceStorage) HeadStorage() headstorage.HeadStorage {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for HeadStorage")
}
var r0 headstorage.HeadStorage
if rf, ok := ret.Get(0).(func() headstorage.HeadStorage); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(headstorage.HeadStorage)
}
}
return r0
}
// MockClientSpaceStorage_HeadStorage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'HeadStorage'
type MockClientSpaceStorage_HeadStorage_Call struct {
*mock.Call
}
// HeadStorage is a helper method to define mock.On call
func (_e *MockClientSpaceStorage_Expecter) HeadStorage() *MockClientSpaceStorage_HeadStorage_Call {
return &MockClientSpaceStorage_HeadStorage_Call{Call: _e.mock.On("HeadStorage")}
}
func (_c *MockClientSpaceStorage_HeadStorage_Call) Run(run func()) *MockClientSpaceStorage_HeadStorage_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockClientSpaceStorage_HeadStorage_Call) Return(_a0 headstorage.HeadStorage) *MockClientSpaceStorage_HeadStorage_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockClientSpaceStorage_HeadStorage_Call) RunAndReturn(run func() headstorage.HeadStorage) *MockClientSpaceStorage_HeadStorage_Call {
_c.Call.Return(run)
return _c
}
// Id provides a mock function with given fields:
func (_m *MockClientSpaceStorage) Id() string {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for Id")
}
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
// MockClientSpaceStorage_Id_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Id'
type MockClientSpaceStorage_Id_Call struct {
*mock.Call
}
// Id is a helper method to define mock.On call
func (_e *MockClientSpaceStorage_Expecter) Id() *MockClientSpaceStorage_Id_Call {
return &MockClientSpaceStorage_Id_Call{Call: _e.mock.On("Id")}
}
func (_c *MockClientSpaceStorage_Id_Call) Run(run func()) *MockClientSpaceStorage_Id_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockClientSpaceStorage_Id_Call) Return(_a0 string) *MockClientSpaceStorage_Id_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockClientSpaceStorage_Id_Call) RunAndReturn(run func() string) *MockClientSpaceStorage_Id_Call {
_c.Call.Return(run)
return _c
}
// Init provides a mock function with given fields: a
func (_m *MockClientSpaceStorage) 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
}
// MockClientSpaceStorage_Init_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Init'
type MockClientSpaceStorage_Init_Call struct {
*mock.Call
}
// Init is a helper method to define mock.On call
// - a *app.App
func (_e *MockClientSpaceStorage_Expecter) Init(a interface{}) *MockClientSpaceStorage_Init_Call {
return &MockClientSpaceStorage_Init_Call{Call: _e.mock.On("Init", a)}
}
func (_c *MockClientSpaceStorage_Init_Call) Run(run func(a *app.App)) *MockClientSpaceStorage_Init_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(*app.App))
})
return _c
}
func (_c *MockClientSpaceStorage_Init_Call) Return(err error) *MockClientSpaceStorage_Init_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockClientSpaceStorage_Init_Call) RunAndReturn(run func(*app.App) error) *MockClientSpaceStorage_Init_Call {
_c.Call.Return(run)
return _c
}
// IsSpaceCreated provides a mock function with given fields: ctx
func (_m *MockClientSpaceStorage) IsSpaceCreated(ctx context.Context) (bool, error) {
ret := _m.Called(ctx)
if len(ret) == 0 {
panic("no return value specified for IsSpaceCreated")
}
var r0 bool
var r1 error
if rf, ok := ret.Get(0).(func(context.Context) (bool, error)); ok {
return rf(ctx)
}
if rf, ok := ret.Get(0).(func(context.Context) bool); ok {
r0 = rf(ctx)
} else {
r0 = ret.Get(0).(bool)
}
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockClientSpaceStorage_IsSpaceCreated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsSpaceCreated'
type MockClientSpaceStorage_IsSpaceCreated_Call struct {
*mock.Call
}
// IsSpaceCreated is a helper method to define mock.On call
// - ctx context.Context
func (_e *MockClientSpaceStorage_Expecter) IsSpaceCreated(ctx interface{}) *MockClientSpaceStorage_IsSpaceCreated_Call {
return &MockClientSpaceStorage_IsSpaceCreated_Call{Call: _e.mock.On("IsSpaceCreated", ctx)}
}
func (_c *MockClientSpaceStorage_IsSpaceCreated_Call) Run(run func(ctx context.Context)) *MockClientSpaceStorage_IsSpaceCreated_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context))
})
return _c
}
func (_c *MockClientSpaceStorage_IsSpaceCreated_Call) Return(created bool, err error) *MockClientSpaceStorage_IsSpaceCreated_Call {
_c.Call.Return(created, err)
return _c
}
func (_c *MockClientSpaceStorage_IsSpaceCreated_Call) RunAndReturn(run func(context.Context) (bool, error)) *MockClientSpaceStorage_IsSpaceCreated_Call {
_c.Call.Return(run)
return _c
}
// MarkSpaceCreated provides a mock function with given fields: ctx
func (_m *MockClientSpaceStorage) MarkSpaceCreated(ctx context.Context) error {
ret := _m.Called(ctx)
if len(ret) == 0 {
panic("no return value specified for MarkSpaceCreated")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockClientSpaceStorage_MarkSpaceCreated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarkSpaceCreated'
type MockClientSpaceStorage_MarkSpaceCreated_Call struct {
*mock.Call
}
// MarkSpaceCreated is a helper method to define mock.On call
// - ctx context.Context
func (_e *MockClientSpaceStorage_Expecter) MarkSpaceCreated(ctx interface{}) *MockClientSpaceStorage_MarkSpaceCreated_Call {
return &MockClientSpaceStorage_MarkSpaceCreated_Call{Call: _e.mock.On("MarkSpaceCreated", ctx)}
}
func (_c *MockClientSpaceStorage_MarkSpaceCreated_Call) Run(run func(ctx context.Context)) *MockClientSpaceStorage_MarkSpaceCreated_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context))
})
return _c
}
func (_c *MockClientSpaceStorage_MarkSpaceCreated_Call) Return(_a0 error) *MockClientSpaceStorage_MarkSpaceCreated_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockClientSpaceStorage_MarkSpaceCreated_Call) RunAndReturn(run func(context.Context) error) *MockClientSpaceStorage_MarkSpaceCreated_Call {
_c.Call.Return(run)
return _c
}
// Name provides a mock function with given fields:
func (_m *MockClientSpaceStorage) 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
}
// MockClientSpaceStorage_Name_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Name'
type MockClientSpaceStorage_Name_Call struct {
*mock.Call
}
// Name is a helper method to define mock.On call
func (_e *MockClientSpaceStorage_Expecter) Name() *MockClientSpaceStorage_Name_Call {
return &MockClientSpaceStorage_Name_Call{Call: _e.mock.On("Name")}
}
func (_c *MockClientSpaceStorage_Name_Call) Run(run func()) *MockClientSpaceStorage_Name_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockClientSpaceStorage_Name_Call) Return(name string) *MockClientSpaceStorage_Name_Call {
_c.Call.Return(name)
return _c
}
func (_c *MockClientSpaceStorage_Name_Call) RunAndReturn(run func() string) *MockClientSpaceStorage_Name_Call {
_c.Call.Return(run)
return _c
}
// Run provides a mock function with given fields: ctx
func (_m *MockClientSpaceStorage) 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
}
// MockClientSpaceStorage_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run'
type MockClientSpaceStorage_Run_Call struct {
*mock.Call
}
// Run is a helper method to define mock.On call
// - ctx context.Context
func (_e *MockClientSpaceStorage_Expecter) Run(ctx interface{}) *MockClientSpaceStorage_Run_Call {
return &MockClientSpaceStorage_Run_Call{Call: _e.mock.On("Run", ctx)}
}
func (_c *MockClientSpaceStorage_Run_Call) Run(run func(ctx context.Context)) *MockClientSpaceStorage_Run_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context))
})
return _c
}
func (_c *MockClientSpaceStorage_Run_Call) Return(err error) *MockClientSpaceStorage_Run_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockClientSpaceStorage_Run_Call) RunAndReturn(run func(context.Context) error) *MockClientSpaceStorage_Run_Call {
_c.Call.Return(run)
return _c
}
// StateStorage provides a mock function with given fields:
func (_m *MockClientSpaceStorage) StateStorage() statestorage.StateStorage {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for StateStorage")
}
var r0 statestorage.StateStorage
if rf, ok := ret.Get(0).(func() statestorage.StateStorage); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(statestorage.StateStorage)
}
}
return r0
}
// MockClientSpaceStorage_StateStorage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'StateStorage'
type MockClientSpaceStorage_StateStorage_Call struct {
*mock.Call
}
// StateStorage is a helper method to define mock.On call
func (_e *MockClientSpaceStorage_Expecter) StateStorage() *MockClientSpaceStorage_StateStorage_Call {
return &MockClientSpaceStorage_StateStorage_Call{Call: _e.mock.On("StateStorage")}
}
func (_c *MockClientSpaceStorage_StateStorage_Call) Run(run func()) *MockClientSpaceStorage_StateStorage_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockClientSpaceStorage_StateStorage_Call) Return(_a0 statestorage.StateStorage) *MockClientSpaceStorage_StateStorage_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockClientSpaceStorage_StateStorage_Call) RunAndReturn(run func() statestorage.StateStorage) *MockClientSpaceStorage_StateStorage_Call {
_c.Call.Return(run)
return _c
}
// TreeRoot provides a mock function with given fields: ctx, id
func (_m *MockClientSpaceStorage) TreeRoot(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error) {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for TreeRoot")
}
var r0 *treechangeproto.RawTreeChangeWithId
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (*treechangeproto.RawTreeChangeWithId, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, string) *treechangeproto.RawTreeChangeWithId); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*treechangeproto.RawTreeChangeWithId)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockClientSpaceStorage_TreeRoot_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TreeRoot'
type MockClientSpaceStorage_TreeRoot_Call struct {
*mock.Call
}
// TreeRoot is a helper method to define mock.On call
// - ctx context.Context
// - id string
func (_e *MockClientSpaceStorage_Expecter) TreeRoot(ctx interface{}, id interface{}) *MockClientSpaceStorage_TreeRoot_Call {
return &MockClientSpaceStorage_TreeRoot_Call{Call: _e.mock.On("TreeRoot", ctx, id)}
}
func (_c *MockClientSpaceStorage_TreeRoot_Call) Run(run func(ctx context.Context, id string)) *MockClientSpaceStorage_TreeRoot_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string))
})
return _c
}
func (_c *MockClientSpaceStorage_TreeRoot_Call) Return(root *treechangeproto.RawTreeChangeWithId, err error) *MockClientSpaceStorage_TreeRoot_Call {
_c.Call.Return(root, err)
return _c
}
func (_c *MockClientSpaceStorage_TreeRoot_Call) RunAndReturn(run func(context.Context, string) (*treechangeproto.RawTreeChangeWithId, error)) *MockClientSpaceStorage_TreeRoot_Call {
_c.Call.Return(run)
return _c
}
// TreeStorage provides a mock function with given fields: ctx, id
func (_m *MockClientSpaceStorage) TreeStorage(ctx context.Context, id string) (objecttree.Storage, error) {
ret := _m.Called(ctx, id)
if len(ret) == 0 {
panic("no return value specified for TreeStorage")
}
var r0 objecttree.Storage
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (objecttree.Storage, error)); ok {
return rf(ctx, id)
}
if rf, ok := ret.Get(0).(func(context.Context, string) objecttree.Storage); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(objecttree.Storage)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockClientSpaceStorage_TreeStorage_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'TreeStorage'
type MockClientSpaceStorage_TreeStorage_Call struct {
*mock.Call
}
// TreeStorage is a helper method to define mock.On call
// - ctx context.Context
// - id string
func (_e *MockClientSpaceStorage_Expecter) TreeStorage(ctx interface{}, id interface{}) *MockClientSpaceStorage_TreeStorage_Call {
return &MockClientSpaceStorage_TreeStorage_Call{Call: _e.mock.On("TreeStorage", ctx, id)}
}
func (_c *MockClientSpaceStorage_TreeStorage_Call) Run(run func(ctx context.Context, id string)) *MockClientSpaceStorage_TreeStorage_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string))
})
return _c
}
func (_c *MockClientSpaceStorage_TreeStorage_Call) Return(_a0 objecttree.Storage, _a1 error) *MockClientSpaceStorage_TreeStorage_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockClientSpaceStorage_TreeStorage_Call) RunAndReturn(run func(context.Context, string) (objecttree.Storage, error)) *MockClientSpaceStorage_TreeStorage_Call {
_c.Call.Return(run)
return _c
}
// UnmarkSpaceCreated provides a mock function with given fields: ctx
func (_m *MockClientSpaceStorage) UnmarkSpaceCreated(ctx context.Context) error {
ret := _m.Called(ctx)
if len(ret) == 0 {
panic("no return value specified for UnmarkSpaceCreated")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context) error); ok {
r0 = rf(ctx)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockClientSpaceStorage_UnmarkSpaceCreated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UnmarkSpaceCreated'
type MockClientSpaceStorage_UnmarkSpaceCreated_Call struct {
*mock.Call
}
// UnmarkSpaceCreated is a helper method to define mock.On call
// - ctx context.Context
func (_e *MockClientSpaceStorage_Expecter) UnmarkSpaceCreated(ctx interface{}) *MockClientSpaceStorage_UnmarkSpaceCreated_Call {
return &MockClientSpaceStorage_UnmarkSpaceCreated_Call{Call: _e.mock.On("UnmarkSpaceCreated", ctx)}
}
func (_c *MockClientSpaceStorage_UnmarkSpaceCreated_Call) Run(run func(ctx context.Context)) *MockClientSpaceStorage_UnmarkSpaceCreated_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context))
})
return _c
}
func (_c *MockClientSpaceStorage_UnmarkSpaceCreated_Call) Return(_a0 error) *MockClientSpaceStorage_UnmarkSpaceCreated_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockClientSpaceStorage_UnmarkSpaceCreated_Call) RunAndReturn(run func(context.Context) error) *MockClientSpaceStorage_UnmarkSpaceCreated_Call {
_c.Call.Return(run)
return _c
}
// NewMockClientSpaceStorage creates a new instance of MockClientSpaceStorage. 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 NewMockClientSpaceStorage(t interface {
mock.TestingT
Cleanup(func())
}) *MockClientSpaceStorage {
mock := &MockClientSpaceStorage{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View file

@ -1,134 +0,0 @@
package anystorage
import (
"context"
"errors"
"fmt"
"os"
"path"
"strings"
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/app/logger"
"github.com/anyproto/any-sync/commonspace/spacestorage"
)
// nolint: unused
var log = logger.NewNamed(spacestorage.CName)
func New(rootPath string) *storageService {
return &storageService{
rootPath: rootPath,
}
}
type storageService struct {
rootPath string
}
func (s *storageService) AllSpaceIds() (ids []string, err error) {
var files []string
fileInfo, err := os.ReadDir(s.rootPath)
if err != nil {
return files, fmt.Errorf("can't read datadir '%v': %w", s.rootPath, err)
}
for _, file := range fileInfo {
if !strings.HasPrefix(file.Name(), ".") {
files = append(files, file.Name())
}
}
return files, nil
}
func (s *storageService) Run(ctx context.Context) (err error) {
return nil
}
func (s *storageService) openDb(ctx context.Context, id string) (db anystore.DB, err error) {
dbPath := path.Join(s.rootPath, id, "store.db")
if _, err := os.Stat(dbPath); err != nil {
if errors.Is(err, os.ErrNotExist) {
return nil, spacestorage.ErrSpaceStorageMissing
}
return nil, err
}
return anystore.Open(ctx, dbPath, anyStoreConfig())
}
func (s *storageService) createDb(ctx context.Context, id string) (db anystore.DB, err error) {
dirPath := path.Join(s.rootPath, id)
err = os.MkdirAll(dirPath, 0755)
if err != nil {
return nil, err
}
dbPath := path.Join(dirPath, "store.db")
return anystore.Open(ctx, dbPath, anyStoreConfig())
}
func (s *storageService) Close(ctx context.Context) (err error) {
return nil
}
func (s *storageService) Init(a *app.App) (err error) {
if _, err = os.Stat(s.rootPath); err != nil {
err = os.MkdirAll(s.rootPath, 0755)
if err != nil {
return err
}
}
return nil
}
func (s *storageService) Name() (name string) {
return spacestorage.CName
}
func (s *storageService) WaitSpaceStorage(ctx context.Context, id string) (spacestorage.SpaceStorage, error) {
db, err := s.openDb(ctx, id)
if err != nil {
return nil, err
}
st, err := spacestorage.New(ctx, id, db)
if err != nil {
return nil, err
}
return NewClientStorage(ctx, st)
}
func (s *storageService) SpaceExists(id string) bool {
if id == "" {
return false
}
dbPath := path.Join(s.rootPath, id)
if _, err := os.Stat(dbPath); err != nil {
return false
}
return true
}
func (s *storageService) CreateSpaceStorage(ctx context.Context, payload spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error) {
db, err := s.createDb(ctx, payload.SpaceHeaderWithId.Id)
if err != nil {
return nil, err
}
st, err := spacestorage.Create(ctx, db, payload)
if err != nil {
return nil, err
}
return NewClientStorage(ctx, st)
}
func (s *storageService) DeleteSpaceStorage(ctx context.Context, spaceId string) error {
dbPath := path.Join(s.rootPath, spaceId)
return os.RemoveAll(dbPath)
}
func anyStoreConfig() *anystore.Config {
return &anystore.Config{
ReadConnections: 4,
SQLiteConnectionOptions: map[string]string{
"synchronous": "off",
},
}
}

View file

@ -60,10 +60,6 @@ func (t treeKeys) RawChangeKey(id string) []byte {
return treestorage.JoinStringsToBytes("space", t.spaceId, "t", t.id, id)
}
func (t treeKeys) RawChangesPrefix() []byte {
return treestorage.JoinStringsToBytes("space", t.spaceId, "t", t.id)
}
func (t treeKeys) RawChangePrefix() []byte {
return t.rawChangePrefix
}

View file

@ -4,15 +4,12 @@ import (
"context"
"errors"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/consensus/consensusproto"
"github.com/dgraph-io/badger/v4"
)
var (
ErrIncorrectKey = errors.New("key format is incorrect")
ErrUnknownRecord = errors.New("record does not exist")
)
var ErrIncorrectKey = errors.New("key format is incorrect")
type listStorage struct {
db *badger.DB
@ -21,7 +18,7 @@ type listStorage struct {
root *consensusproto.RawRecordWithId
}
func newListStorage(spaceId string, db *badger.DB, txn *badger.Txn) (ls oldstorage.ListStorage, err error) {
func newListStorage(spaceId string, db *badger.DB, txn *badger.Txn) (ls liststorage.ListStorage, err error) {
keys := newAclKeys(spaceId)
rootId, err := getTxn(txn, keys.RootIdKey())
if err != nil {
@ -48,7 +45,7 @@ func newListStorage(spaceId string, db *badger.DB, txn *badger.Txn) (ls oldstora
return
}
func createListStorage(spaceID string, db *badger.DB, txn *badger.Txn, root *consensusproto.RawRecordWithId) (ls oldstorage.ListStorage, err error) {
func createListStorage(spaceID string, db *badger.DB, txn *badger.Txn, root *consensusproto.RawRecordWithId) (ls liststorage.ListStorage, err error) {
keys := newAclKeys(spaceID)
_, err = getTxn(txn, keys.RootIdKey())
if err != badger.ErrKeyNotFound {
@ -102,7 +99,7 @@ func (l *listStorage) GetRawRecord(_ context.Context, id string) (raw *consensus
res, err := getDB(l.db, l.keys.RawRecordKey(id))
if err != nil {
if err == badger.ErrKeyNotFound {
err = ErrUnknownRecord
err = liststorage.ErrUnknownRecord
}
return
}

View file

@ -4,13 +4,13 @@ import (
"context"
"testing"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/consensus/consensusproto"
"github.com/dgraph-io/badger/v4"
"github.com/stretchr/testify/require"
)
func testList(t *testing.T, store oldstorage.ListStorage, root *consensusproto.RawRecordWithId, head string) {
func testList(t *testing.T, store liststorage.ListStorage, root *consensusproto.RawRecordWithId, head string) {
require.Equal(t, store.Id(), root.Id)
aclRoot, err := store.Root()
@ -35,7 +35,7 @@ func TestListStorage(t *testing.T) {
return nil
})
var listStore oldstorage.ListStorage
var listStore liststorage.ListStorage
fx.db.View(func(txn *badger.Txn) (err error) {
listStore, err = newListStorage(spaceId, fx.db, txn)
require.NoError(t, err)

View file

@ -7,10 +7,10 @@ import (
"fmt"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
"github.com/dgraph-io/badger/v4"
"golang.org/x/exp/slices"
@ -21,7 +21,7 @@ type spaceStorage struct {
spaceSettingsId string
objDb *badger.DB
keys spaceKeys
aclStorage oldstorage.ListStorage
aclStorage liststorage.ListStorage
header *spacesyncproto.RawSpaceHeaderWithId
service *storageService
}
@ -38,7 +38,7 @@ func (s *spaceStorage) Name() (name string) {
return spacestorage.CName
}
func newSpaceStorage(objDb *badger.DB, spaceId string, service *storageService) (store oldstorage.SpaceStorage, err error) {
func newSpaceStorage(objDb *badger.DB, spaceId string, service *storageService) (store spacestorage.SpaceStorage, err error) {
keys := newSpaceKeys(spaceId)
err = objDb.View(func(txn *badger.Txn) error {
header, err := getTxn(txn, keys.HeaderKey())
@ -75,7 +75,7 @@ func newSpaceStorage(objDb *badger.DB, spaceId string, service *storageService)
return
}
func createSpaceStorage(db *badger.DB, payload spacestorage.SpaceStorageCreatePayload, service *storageService) (store oldstorage.SpaceStorage, err error) {
func createSpaceStorage(db *badger.DB, payload spacestorage.SpaceStorageCreatePayload, service *storageService) (store spacestorage.SpaceStorage, err error) {
keys := newSpaceKeys(payload.SpaceHeaderWithId.Id)
if hasDB(db, keys.HeaderKey()) {
err = spacestorage.ErrSpaceStorageExists
@ -133,15 +133,15 @@ func (s *spaceStorage) HasTree(id string) (bool, error) {
return hasDB(s.objDb, keys.RootIdKey()), nil
}
func (s *spaceStorage) TreeStorage(id string) (oldstorage.TreeStorage, error) {
func (s *spaceStorage) TreeStorage(id string) (treestorage.TreeStorage, error) {
return newTreeStorage(s.objDb, s.spaceId, id)
}
func (s *spaceStorage) CreateTreeStorage(payload treestorage.TreeStorageCreatePayload) (ts oldstorage.TreeStorage, err error) {
func (s *spaceStorage) CreateTreeStorage(payload treestorage.TreeStorageCreatePayload) (ts treestorage.TreeStorage, err error) {
return createTreeStorage(s.objDb, s.spaceId, payload)
}
func (s *spaceStorage) AclStorage() (oldstorage.ListStorage, error) {
func (s *spaceStorage) AclStorage() (liststorage.ListStorage, error) {
return s.aclStorage, nil
}
@ -186,7 +186,7 @@ func (s *spaceStorage) AllDeletedTreeIds() (ids []string, err error) {
var isDeleted bool
err = item.Value(func(val []byte) error {
if bytes.Equal(val, []byte(oldstorage.TreeDeletedStatusDeleted)) {
if bytes.Equal(val, []byte(spacestorage.TreeDeletedStatusDeleted)) {
isDeleted = true
}
return nil

View file

@ -7,8 +7,7 @@ import (
"testing"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
spacestorage "github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
"github.com/anyproto/any-sync/consensus/consensusproto"
"github.com/stretchr/testify/assert"
@ -37,7 +36,7 @@ func spaceTestPayload() spacestorage.SpaceStorageCreatePayload {
}
}
func testSpace(t *testing.T, store oldstorage.SpaceStorage, payload spacestorage.SpaceStorageCreatePayload) {
func testSpace(t *testing.T, store spacestorage.SpaceStorage, payload spacestorage.SpaceStorageCreatePayload) {
header, err := store.SpaceHeader()
require.NoError(t, err)
require.Equal(t, payload.SpaceHeaderWithId, header)
@ -140,58 +139,3 @@ func TestSpaceStorage_StoredIds_BigTxn(t *testing.T) {
require.NoError(t, err)
require.Len(t, storedIds, 0)
}
func newServiceFixture(t *testing.T) *storageService {
fx := newFixture(t)
fx.open(t)
t.Cleanup(func() {
fx.stop(t)
})
s := &storageService{
db: fx.db,
keys: newStorageServiceKeys(),
lockedSpaces: map[string]*lockSpace{},
}
return s
}
func TestStorageService_BindSpaceID(t *testing.T) {
fx := newServiceFixture(t)
err := fx.BindSpaceID("spaceId1", "objectId1")
require.NoError(t, err)
spaceId, err := fx.GetSpaceID("objectId1")
require.NoError(t, err)
require.Equal(t, spaceId, "spaceId1")
}
func TestStorageService_GetBoundObjectIds(t *testing.T) {
t.Run("with no bindings", func(t *testing.T) {
fx := newServiceFixture(t)
ids, err := fx.GetBoundObjectIds("spaceId")
require.NoError(t, err)
assert.Empty(t, ids)
})
t.Run("ok", func(t *testing.T) {
fx := newServiceFixture(t)
spaceId := "spaceId1"
err := fx.BindSpaceID(spaceId, "objectId1")
require.NoError(t, err)
err = fx.BindSpaceID(spaceId, "objectId2")
require.NoError(t, err)
ids, err := fx.GetBoundObjectIds(spaceId)
require.NoError(t, err)
assert.ElementsMatch(t, []string{"objectId1", "objectId2"}, ids)
})
}

View file

@ -1,15 +1,12 @@
package badgerstorage
import (
"bytes"
"context"
"errors"
"fmt"
"sync"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/dgraph-io/badger/v4"
"github.com/anyproto/anytype-heart/core/domain"
@ -49,11 +46,11 @@ func (s *storageService) Name() (name string) {
return spacestorage.CName
}
func (s *storageService) SpaceStorage(id string) (oldstorage.SpaceStorage, error) {
func (s *storageService) SpaceStorage(id string) (spacestorage.SpaceStorage, error) {
return newSpaceStorage(s.db, id, s)
}
func (s *storageService) WaitSpaceStorage(ctx context.Context, id string) (store oldstorage.SpaceStorage, err error) {
func (s *storageService) WaitSpaceStorage(ctx context.Context, id string) (store spacestorage.SpaceStorage, err error) {
var ls *lockSpace
ls, err = s.checkLock(id, func() error {
store, err = newSpaceStorage(s.db, id, s)
@ -155,7 +152,7 @@ func (s *storageService) unlockSpaceStorage(id string) {
}
}
func (s *storageService) CreateSpaceStorage(payload spacestorage.SpaceStorageCreatePayload) (oldstorage.SpaceStorage, error) {
func (s *storageService) CreateSpaceStorage(payload spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error) {
return createSpaceStorage(s.db, payload, s)
}
@ -169,37 +166,6 @@ func (s *storageService) GetSpaceID(objectID string) (spaceID string, err error)
return spaceID, err
}
func (s *storageService) GetBoundObjectIds(spaceId string) (ids []string, err error) {
prefix := []byte("bind/")
spaceIdBytes := []byte(spaceId)
err = s.db.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.PrefetchValues = false
opts.Prefix = prefix
it := txn.NewIterator(opts)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
id := item.Key()
err = item.Value(func(val []byte) error {
if bytes.Equal(spaceIdBytes, val) {
idStr := string(id)
ids = append(ids, idStr[len(prefix):])
}
return nil
})
if err != nil {
return fmt.Errorf("read value: %w", err)
}
}
return nil
})
return
}
func (s *storageService) BindSpaceID(spaceID, objectID string) (err error) {
return badgerhelper.SetValue(s.db, s.keys.BindObjectIDKey(objectID), []byte(spaceID))
}
@ -227,11 +193,6 @@ func (s *storageService) AllSpaceIds() (ids []string, err error) {
return
}
func (s *storageService) EstimateSize() (uint64, error) {
onDiskSize, _ := s.db.EstimateSize(nil)
return onDiskSize, nil
}
func (s *storageService) Run(ctx context.Context) (err error) {
s.db, err = s.provider.SpaceStorage()
if err != nil {

View file

@ -1,13 +1,11 @@
package badgerstorage
import (
"bytes"
"context"
"fmt"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/dgraph-io/badger/v4"
)
@ -18,7 +16,7 @@ type treeStorage struct {
root *treechangeproto.RawTreeChangeWithId
}
func newTreeStorage(db *badger.DB, spaceId, treeId string) (ts oldstorage.TreeStorage, err error) {
func newTreeStorage(db *badger.DB, spaceId, treeId string) (ts treestorage.TreeStorage, err error) {
keys := newTreeKeys(spaceId, treeId)
err = db.View(func(txn *badger.Txn) error {
_, err := txn.Get(keys.RootIdKey())
@ -50,7 +48,7 @@ func newTreeStorage(db *badger.DB, spaceId, treeId string) (ts oldstorage.TreeSt
return
}
func createTreeStorage(db *badger.DB, spaceId string, payload treestorage.TreeStorageCreatePayload) (ts oldstorage.TreeStorage, err error) {
func createTreeStorage(db *badger.DB, spaceId string, payload treestorage.TreeStorageCreatePayload) (ts treestorage.TreeStorage, err error) {
keys := newTreeKeys(spaceId, payload.RootRawChange.Id)
if hasDB(db, keys.RootIdKey()) {
err = treestorage.ErrTreeExists
@ -59,7 +57,7 @@ func createTreeStorage(db *badger.DB, spaceId string, payload treestorage.TreeSt
return forceCreateTreeStorage(db, spaceId, payload)
}
func forceCreateTreeStorage(db *badger.DB, spaceId string, payload treestorage.TreeStorageCreatePayload) (ts oldstorage.TreeStorage, err error) {
func forceCreateTreeStorage(db *badger.DB, spaceId string, payload treestorage.TreeStorageCreatePayload) (ts treestorage.TreeStorage, err error) {
keys := newTreeKeys(spaceId, payload.RootRawChange.Id)
err = db.Update(func(txn *badger.Txn) error {
err = txn.Set(keys.RawChangeKey(payload.RootRawChange.Id), payload.RootRawChange.GetRawChange())
@ -110,74 +108,7 @@ func (t *treeStorage) Heads() (heads []string, err error) {
}
func (t *treeStorage) GetAllChangeIds() (chs []string, err error) {
prefix := t.keys.RawChangesPrefix()
err = t.db.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.PrefetchValues = false
opts.Prefix = prefix
it := txn.NewIterator(opts)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
id := item.Key()
changeId := string(id[len(prefix)+1:])
// Special case
if changeId == "heads" {
continue
}
chs = append(chs, changeId)
if err != nil {
return fmt.Errorf("read value: %w", err)
}
}
return nil
})
return chs, err
}
func (t *treeStorage) GetAllChanges() ([]*treechangeproto.RawTreeChangeWithId, error) {
var changes []*treechangeproto.RawTreeChangeWithId
err := t.IterateChanges(func(id string, rawChange []byte) error {
changes = append(changes, &treechangeproto.RawTreeChangeWithId{
Id: id,
RawChange: bytes.Clone(rawChange),
})
return nil
})
return changes, err
}
func (t *treeStorage) IterateChanges(proc func(id string, rawChange []byte) error) error {
prefix := t.keys.RawChangesPrefix()
return t.db.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.PrefetchValues = false
opts.Prefix = prefix
it := txn.NewIterator(opts)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
id := item.Key()
changeId := string(id[len(prefix)+1:])
// Special case
if changeId == "heads" {
continue
}
err := item.Value(func(val []byte) error {
return proc(changeId, val)
})
if err != nil {
return fmt.Errorf("read value: %w", err)
}
}
return nil
})
return nil, fmt.Errorf("get all change ids should not be called")
}
func (t *treeStorage) SetHeads(heads []string) (err error) {

View file

@ -1,24 +1,16 @@
package badgerstorage
import (
"bytes"
"context"
"os"
"testing"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/dgraph-io/badger/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type oldTreeStorage interface {
oldstorage.ChangesIterator
oldstorage.TreeStorage
}
func treeTestPayload() treestorage.TreeStorageCreatePayload {
rootRawChange := &treechangeproto.RawTreeChangeWithId{RawChange: []byte("some"), Id: "someRootId"}
otherChange := &treechangeproto.RawTreeChangeWithId{RawChange: []byte("some other"), Id: "otherId"}
@ -35,7 +27,7 @@ type fixture struct {
db *badger.DB
}
func testTreePayload(t *testing.T, store oldstorage.TreeStorage, payload treestorage.TreeStorageCreatePayload) {
func testTreePayload(t *testing.T, store treestorage.TreeStorage, payload treestorage.TreeStorageCreatePayload) {
require.Equal(t, payload.RootRawChange.Id, store.Id())
root, err := store.Root()
@ -134,9 +126,8 @@ func TestTreeStorage_Methods(t *testing.T) {
fx.open(t)
defer fx.stop(t)
treeStore, err := newTreeStorage(fx.db, spaceId, payload.RootRawChange.Id)
store, err := newTreeStorage(fx.db, spaceId, payload.RootRawChange.Id)
require.NoError(t, err)
store := treeStore.(oldTreeStorage)
testTreePayload(t, store, payload)
t.Run("update heads", func(t *testing.T) {
@ -148,7 +139,7 @@ func TestTreeStorage_Methods(t *testing.T) {
})
t.Run("add raw change, get change and has change", func(t *testing.T) {
newChange := &treechangeproto.RawTreeChangeWithId{RawChange: []byte("ab"), Id: "id10"}
newChange := &treechangeproto.RawTreeChangeWithId{RawChange: []byte("ab"), Id: "newId"}
require.NoError(t, store.AddRawChange(newChange))
rawCh, err := store.GetRawChange(context.Background(), newChange.Id)
require.NoError(t, err)
@ -166,50 +157,6 @@ func TestTreeStorage_Methods(t *testing.T) {
require.NoError(t, err)
require.False(t, has)
})
t.Run("iterate changes", func(t *testing.T) {
newChange := &treechangeproto.RawTreeChangeWithId{RawChange: []byte("foo"), Id: "id01"}
require.NoError(t, store.AddRawChange(newChange))
newChange = &treechangeproto.RawTreeChangeWithId{RawChange: []byte("bar"), Id: "id20"}
require.NoError(t, store.AddRawChange(newChange))
var collected []*treechangeproto.RawTreeChangeWithId
require.NoError(t, store.IterateChanges(func(id string, rawChange []byte) error {
collected = append(collected, &treechangeproto.RawTreeChangeWithId{
Id: id,
RawChange: bytes.Clone(rawChange),
})
return nil
}))
want := []*treechangeproto.RawTreeChangeWithId{
{Id: "id01", RawChange: []byte("foo")},
{Id: "id10", RawChange: []byte("ab")},
{Id: "id20", RawChange: []byte("bar")},
{Id: "otherId", RawChange: []byte("some other")},
{Id: "someRootId", RawChange: []byte("some")},
}
assert.Equal(t, want, collected)
got, err := store.GetAllChanges()
require.NoError(t, err)
assert.Equal(t, want, got)
})
t.Run("get all change ids", func(t *testing.T) {
got, err := store.GetAllChangeIds()
require.NoError(t, err)
want := []string{"id01",
"id10",
"id20",
"otherId",
"someRootId",
}
assert.Equal(t, want, got)
})
}
func TestTreeStorage_Delete(t *testing.T) {

View file

@ -1,247 +0,0 @@
package migrator
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/spacestorage/migration"
"github.com/anyproto/anytype-heart/core/block/process"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/anystorehelper"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceresolverstore"
"github.com/anyproto/anytype-heart/space/spacecore/oldstorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/migratorfinisher"
"github.com/anyproto/anytype-heart/util/freespace"
)
type NotEnoughFreeSpaceError struct {
Free uint64
Required uint64
}
func (e NotEnoughFreeSpaceError) Error() string {
if e.Required == 0 {
return fmt.Sprintf("not enough free space: %d", e.Free)
}
return fmt.Sprintf("Not enough free space: %d, required: %d", e.Free, e.Required)
}
const CName = "client.storage.migration"
type migrator struct {
oldStorage oldstorage.ClientStorage
newStorage storage.ClientStorage
process process.Service
path string
objectStorePath string
finisher migratorfinisher.Service
anyStoreConfig *anystore.Config
}
type pathProvider interface {
GetNewSpaceStorePath() string
GetOldSpaceStorePath() string
GetRepoPath() string
GetAnyStoreConfig() *anystore.Config
}
func New() app.ComponentRunnable {
return &migrator{}
}
func (m *migrator) Init(a *app.App) (err error) {
cfg := a.MustComponent("config").(pathProvider)
m.path = cfg.GetNewSpaceStorePath()
m.objectStorePath = filepath.Join(cfg.GetRepoPath(), "objectstore")
m.oldStorage = app.MustComponent[oldstorage.ClientStorage](a)
m.newStorage = app.MustComponent[storage.ClientStorage](a)
m.process = app.MustComponent[process.Service](a)
m.finisher = app.MustComponent[migratorfinisher.Service](a)
m.anyStoreConfig = cfg.GetAnyStoreConfig()
return nil
}
func (m *migrator) Name() (name string) {
return CName
}
func (m *migrator) Run(ctx context.Context) (err error) {
oldSize, err := m.oldStorage.EstimateSize()
if err != nil {
return fmt.Errorf("estimate size: %w", err)
}
free, err := freespace.GetFreeDiskSpace(m.path)
if err != nil {
return fmt.Errorf("get free disk space: %w", err)
}
requiredDiskSpace := oldSize * 15 / 10
if requiredDiskSpace > free {
return NotEnoughFreeSpaceError{
Free: free,
Required: requiredDiskSpace,
}
}
err = m.run(ctx)
if err != nil {
if strings.Contains(err.Error(), "disk is full") {
return NotEnoughFreeSpaceError{
Free: free,
}
}
return err
}
return nil
}
func (m *migrator) run(ctx context.Context) (err error) {
progress := process.NewProgress(&pb.ModelProcessMessageOfMigration{Migration: &pb.ModelProcessMigration{}})
progress.SetProgressMessage("Migrating spaces")
err = m.process.Add(progress)
if err != nil {
return err
}
defer func() {
progress.Finish(err)
}()
migrator := migration.NewSpaceMigrator(m.oldStorage, m.newStorage, 40, m.path)
allIds, err := m.oldStorage.AllSpaceIds()
if err != nil {
return err
}
var (
total int64
totalMap = make(map[string]int64)
)
for _, id := range allIds {
store, err := m.oldStorage.WaitSpaceStorage(ctx, id)
if err != nil {
return err
}
storedIds, err := store.StoredIds()
if err != nil {
return err
}
total += int64(len(storedIds))
totalMap[id] = int64(len(storedIds))
err = store.Close(ctx)
if err != nil {
return err
}
select {
case <-ctx.Done():
return ctx.Err()
default:
}
}
progress.SetTotal(total)
for _, id := range allIds {
err := migrator.MigrateId(ctx, id, progress)
if err != nil {
if errors.Is(err, migration.ErrAlreadyMigrated) {
progress.AddDone(totalMap[id])
continue
}
return err
}
select {
case <-ctx.Done():
return ctx.Err()
default:
}
}
err = m.doObjectStoreDb(ctx, func(db anystore.DB) error {
resolverStore, err := spaceresolverstore.New(ctx, db)
if err != nil {
return fmt.Errorf("new resolver store: %w", err)
}
for _, spaceId := range allIds {
objectIds, err := m.oldStorage.GetBoundObjectIds(spaceId)
if err != nil {
return fmt.Errorf("get bound object ids: %w", err)
}
for _, objectId := range objectIds {
err = resolverStore.BindSpaceId(spaceId, objectId)
if err != nil {
return fmt.Errorf("bind space id: %w", err)
}
}
}
return nil
})
if err != nil {
return fmt.Errorf("migrate space id bindings: %w", err)
}
// TODO Maybe add some condition?
m.finisher.SetMigrationDone()
return nil
}
// nolint:unused
func (m *migrator) verify(ctx context.Context, fast bool) ([]*verificationReport, error) {
var reports []*verificationReport
err := m.doObjectStoreDb(ctx, func(db anystore.DB) error {
resolverStore, err := spaceresolverstore.New(ctx, db)
if err != nil {
return fmt.Errorf("new resolver store: %w", err)
}
v := &verifier{
fast: fast,
oldStorage: m.oldStorage,
newStorage: m.newStorage,
resolverStore: resolverStore,
}
reports, err = v.verify(ctx)
return err
})
if err != nil {
return nil, err
}
return reports, nil
}
func (m *migrator) doObjectStoreDb(ctx context.Context, proc func(db anystore.DB) error) error {
err := ensureDirExists(m.objectStorePath)
if err != nil {
return fmt.Errorf("ensure dir exists: %w", err)
}
store, lockRemove, err := anystorehelper.OpenDatabaseWithLockCheck(ctx, filepath.Join(m.objectStorePath, "objects.db"), m.anyStoreConfig)
if err != nil {
return fmt.Errorf("open database: %w", err)
}
err = proc(store)
return errors.Join(err, store.Close(), lockRemove())
}
func ensureDirExists(dir string) error {
_, err := os.Stat(dir)
if errors.Is(err, os.ErrNotExist) {
err = os.MkdirAll(dir, 0700)
if err != nil {
return fmt.Errorf("create db dir: %w", err)
}
}
return nil
}
func (m *migrator) Close(ctx context.Context) (err error) {
return nil
}

View file

@ -1,203 +0,0 @@
package migrator
import (
"context"
"io"
"os"
"path/filepath"
"testing"
"github.com/anyproto/any-sync/app"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/anyproto/anytype-heart/core/anytype/config"
"github.com/anyproto/anytype-heart/core/block/process"
"github.com/anyproto/anytype-heart/core/event/mock_event"
"github.com/anyproto/anytype-heart/core/wallet"
"github.com/anyproto/anytype-heart/pb"
"github.com/anyproto/anytype-heart/pkg/lib/datastore/clientds"
"github.com/anyproto/anytype-heart/space/spacecore/oldstorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/migratorfinisher"
"github.com/anyproto/anytype-heart/tests/testutil"
)
type fixture struct {
migrator *migrator
app *app.App
cfg *config.Config
}
type quicPreferenceSetterStub struct {
}
func (q *quicPreferenceSetterStub) Init(a *app.App) (err error) {
return nil
}
func (q *quicPreferenceSetterStub) Name() (name string) {
return "quicPreferenceSetterStub"
}
func (q *quicPreferenceSetterStub) PreferQuic(b bool) {
}
func newFixture(t *testing.T, mode storage.SpaceStorageMode) *fixture {
cfg := config.New()
cfg.SpaceStorageMode = mode
cfg.RepoPath = t.TempDir()
fx := &fixture{
cfg: cfg,
}
return fx
}
func (fx *fixture) start(t *testing.T) {
walletService := wallet.NewWithRepoDirAndRandomKeys(fx.cfg.RepoPath)
oldStorage := oldstorage.New()
newStorage := storage.New()
processService := process.New()
eventSender := mock_event.NewMockSender(t)
eventSender.EXPECT().Broadcast(mock.Anything).Run(func(ev *pb.Event) {
}).Maybe()
eventSender.EXPECT().BroadcastExceptSessions(mock.Anything, mock.Anything).Run(func(ev *pb.Event, exceptSessions []string) {
t.Log(ev)
}).Maybe()
migrator := New().(*migrator)
ctx := context.Background()
testApp := &app.App{}
testApp.Register(migratorfinisher.New())
testApp.Register(clientds.New())
testApp.Register(testutil.PrepareMock(ctx, testApp, eventSender))
testApp.Register(&quicPreferenceSetterStub{})
testApp.Register(walletService)
testApp.Register(fx.cfg)
testApp.Register(oldStorage)
testApp.Register(newStorage)
testApp.Register(processService)
testApp.Register(migrator)
fx.app = testApp
fx.migrator = migrator
err := testApp.Start(ctx)
require.NoError(t, err)
}
func assertReports(t *testing.T, reports []*verificationReport) {
for _, report := range reports {
for _, err := range report.errors {
assert.NoError(t, err.err, err.id)
}
}
}
func TestMigration(t *testing.T) {
t.Run("no old storage", func(t *testing.T) {
fx := newFixture(t, storage.SpaceStorageModeSqlite)
fx.start(t)
})
t.Run("with sqlite, fast verification", func(t *testing.T) {
fx := newFixture(t, storage.SpaceStorageModeSqlite)
err := copyFile("testdata/spaceStore.db", fx.cfg.GetOldSpaceStorePath())
require.NoError(t, err)
// TODO Test object->space bindings were populated
fx.start(t)
reports, err := fx.migrator.verify(context.Background(), true)
require.NoError(t, err)
assertReports(t, reports)
})
t.Run("with sqlite, full verification", func(t *testing.T) {
fx := newFixture(t, storage.SpaceStorageModeSqlite)
err := copyFile("testdata/spaceStore.db", fx.cfg.GetOldSpaceStorePath())
require.NoError(t, err)
// TODO Test object->space bindings were populated
fx.start(t)
reports, err := fx.migrator.verify(context.Background(), false)
require.NoError(t, err)
assertReports(t, reports)
})
t.Run("with badger, fast verification", func(t *testing.T) {
fx := newFixture(t, storage.SpaceStorageModeBadger)
err := copyDir("testdata/badger_spacestore", fx.cfg.GetOldSpaceStorePath())
require.NoError(t, err)
// TODO Test object->space bindings were populated
fx.start(t)
reports, err := fx.migrator.verify(context.Background(), true)
require.NoError(t, err)
assertReports(t, reports)
})
t.Run("with badger, full verification", func(t *testing.T) {
fx := newFixture(t, storage.SpaceStorageModeBadger)
err := copyDir("testdata/badger_spacestore", fx.cfg.GetOldSpaceStorePath())
require.NoError(t, err)
// TODO Test object->space bindings were populated
fx.start(t)
reports, err := fx.migrator.verify(context.Background(), false)
require.NoError(t, err)
assertReports(t, reports)
})
}
func copyFile(srcPath string, destPath string) error {
src, err := os.Open(srcPath)
if err != nil {
return err
}
defer src.Close()
dest, err := os.Create(destPath)
if err != nil {
return err
}
defer dest.Close()
_, err = io.Copy(dest, src)
return err
}
func copyDir(srcPath string, destPath string) error {
dir, err := os.ReadDir(srcPath)
if err != nil {
return err
}
err = os.MkdirAll(destPath, os.ModePerm)
if err != nil {
return err
}
for _, entry := range dir {
src := filepath.Join(srcPath, entry.Name())
dst := filepath.Join(destPath, entry.Name())
err := copyFile(src, dst)
if err != nil {
return err
}
}
return nil
}

View file

@ -1 +0,0 @@
/À‰µ 7¤¼¯…püHello Badger

View file

@ -1,224 +0,0 @@
// nolint:unused
package migrator
import (
"bytes"
"context"
"errors"
"fmt"
"slices"
"time"
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-store/query"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/any-sync/commonspace/spacestorage"
oldstorage2 "github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/anyproto/anytype-heart/core/domain"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore/spaceresolverstore"
"github.com/anyproto/anytype-heart/space/spacecore/oldstorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
)
type verifier struct {
fast bool
oldStorage oldstorage.ClientStorage
newStorage storage.ClientStorage
resolverStore spaceresolverstore.Store
}
type errorEntry struct {
id string
err error
}
type verificationReport struct {
spaceId string
treesCompared int
errors []errorEntry
totalBytesCompared int
duration time.Duration
}
func (v *verifier) verify(ctx context.Context) ([]*verificationReport, error) {
allSpaceIds, err := v.oldStorage.AllSpaceIds()
if err != nil {
return nil, fmt.Errorf("list all space ids: %w", err)
}
reports := make([]*verificationReport, 0, len(allSpaceIds))
for _, spaceId := range allSpaceIds {
report, err := v.verifySpace(ctx, spaceId)
if err != nil {
return nil, fmt.Errorf("verify space: %w", err)
}
report.spaceId = spaceId
reports = append(reports, report)
}
return reports, nil
}
func (v *verifier) verifySpace(ctx context.Context, spaceId string) (*verificationReport, error) {
oldStore, err := v.oldStorage.WaitSpaceStorage(ctx, spaceId)
if err != nil {
return nil, fmt.Errorf("open old store: %w", err)
}
newStore, err := v.newStorage.WaitSpaceStorage(ctx, spaceId)
if err != nil {
return nil, fmt.Errorf("open new store: %w", err)
}
storedIds, err := oldStore.StoredIds()
if err != nil {
return nil, err
}
newStoreCollection, err := newStore.AnyStore().Collection(ctx, "changes")
if err != nil {
return nil, fmt.Errorf("get new store collection: %w", err)
}
report := &verificationReport{}
now := time.Now()
for _, treeId := range storedIds {
bytesCompared, err := v.verifyTree(ctx, oldStore, newStore, newStoreCollection, treeId)
if err != nil {
report.errors = append(report.errors, errorEntry{id: treeId, err: err})
}
report.treesCompared++
report.totalBytesCompared += bytesCompared
}
report.duration = time.Since(now)
err = oldStore.Close(ctx)
if err != nil {
return nil, err
}
return report, nil
}
func (v *verifier) verifyTree(ctx context.Context, oldStore oldstorage2.SpaceStorage, newStore spacestorage.SpaceStorage, newStoreCollection anystore.Collection, treeId string) (int, error) {
newHeadStorage := newStore.HeadStorage()
entry, err := newHeadStorage.GetEntry(ctx, treeId)
if err != nil {
return 0, fmt.Errorf("get heads entry: %w", err)
}
oldTreeStorage, err := oldStore.TreeStorage(treeId)
if err != nil {
return 0, fmt.Errorf("open old tree storage: %w", err)
}
oldHeads, err := oldTreeStorage.Heads()
if err != nil {
return 0, fmt.Errorf("open old heads storage: %w", err)
}
if !slices.Equal(oldHeads, entry.Heads) {
return 0, fmt.Errorf("old heads doesn't match tree storage")
}
err = v.verifySpaceBindings(oldStore, treeId)
if err != nil {
return 0, fmt.Errorf("verify space: %w", err)
}
newTreeStorage, err := newStore.TreeStorage(ctx, treeId)
if err != nil {
return 0, fmt.Errorf("open new tree storage: %w", err)
}
var bytesCompared int
if v.fast {
err = v.verifyChangesFast(ctx, oldTreeStorage, newTreeStorage)
if err != nil {
return 0, fmt.Errorf("verify tree fast: %w", err)
}
} else {
bytesCompared, err = v.verifyChangesFull(ctx, newStoreCollection, oldTreeStorage)
if err != nil {
return 0, fmt.Errorf("verify tree fast: %w", err)
}
}
return bytesCompared, nil
}
func (v *verifier) verifySpaceBindings(oldStore oldstorage2.SpaceStorage, treeId string) error {
gotSpaceId, err := v.resolverStore.GetSpaceId(treeId)
// If it's not found in new store, check that it's not found in old store either
if errors.Is(err, domain.ErrObjectNotFound) {
_, err = v.oldStorage.GetSpaceID(treeId)
if errors.Is(err, domain.ErrObjectNotFound) {
return nil
}
if err == nil {
return fmt.Errorf("binding is not found in new store")
}
return fmt.Errorf("check binding in old store: %w", err)
} else if err != nil {
return fmt.Errorf("resolve space id for object: %w", err)
}
if gotSpaceId != oldStore.Id() {
return fmt.Errorf("resolved spaced id mismatch")
}
return nil
}
// verifyChangesFast checks only existence of changes
func (v *verifier) verifyChangesFast(ctx context.Context, oldTreeStorage oldstorage2.TreeStorage, newTreeStorage objecttree.Storage) error {
oldChangeIds, err := oldTreeStorage.GetAllChangeIds()
if err != nil {
return fmt.Errorf("get old change ids: %w", err)
}
if len(oldChangeIds) == 0 {
return fmt.Errorf("old change ids is empty")
}
for _, oldChangeId := range oldChangeIds {
ok, err := newTreeStorage.Has(ctx, oldChangeId)
if err != nil {
return fmt.Errorf("get old change id: %w", err)
}
if !ok {
return fmt.Errorf("old change id doesn't exist")
}
}
return nil
}
// verifyChangesFull checks byte contents of changes
func (v *verifier) verifyChangesFull(ctx context.Context, newStoreCollection anystore.Collection, oldTreeStorage oldstorage2.TreeStorage) (int, error) {
iterator, ok := oldTreeStorage.(oldstorage2.ChangesIterator)
if !ok {
return 0, fmt.Errorf("old tree storage doesn't implement ChangesIterator")
}
var bytesCompared int
iter, err := newStoreCollection.Find(query.Key{Path: []string{"t"}, Filter: query.NewComp(query.CompOpEq, oldTreeStorage.Id())}).Sort("id").Iter(ctx)
if err != nil {
return 0, fmt.Errorf("new store: changes iterator: %w", err)
}
defer iter.Close()
err = iterator.IterateChanges(func(id string, oldChange []byte) error {
if !iter.Next() {
return fmt.Errorf("new store iterator: no more changes")
}
doc, err := iter.Doc()
if err != nil {
return fmt.Errorf("new store iterator: read doc: %w", err)
}
newId := doc.Value().GetString("id")
if newId != id {
return fmt.Errorf("new store iterator: id doesn't match")
}
bytesCompared += len(oldChange)
if !bytes.Equal(oldChange, doc.Value().GetBytes("r")) {
return fmt.Errorf("old tree change doesn't match tree storage")
}
return nil
})
return bytesCompared, err
}

View file

@ -1,96 +0,0 @@
package migratorfinisher
import (
"context"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/anyproto/any-sync/app"
)
const (
migratedName = "space_store_migrated"
objectStoreFolder = "objectstore"
crdtDb = "crdt"
)
const CName = "space.spacecore.storage.migratorfinisher"
type finisher struct {
isMigrationDone bool
newStorePath string
oldPath string
}
type Service interface {
app.ComponentRunnable
SetMigrationDone()
}
func New() Service {
return &finisher{}
}
type pathProvider interface {
GetNewSpaceStorePath() string
GetOldSpaceStorePath() string
}
func (f *finisher) Init(a *app.App) (err error) {
cfg := a.MustComponent("config").(pathProvider)
f.newStorePath = cfg.GetNewSpaceStorePath()
f.oldPath = cfg.GetOldSpaceStorePath()
return nil
}
func (f *finisher) Name() (name string) {
return CName
}
func (f *finisher) Run(ctx context.Context) (err error) {
return nil
}
func (f *finisher) SetMigrationDone() {
f.isMigrationDone = true
}
func (f *finisher) Close(ctx context.Context) error {
if !f.isMigrationDone {
return nil
}
err := f.removeCrdtIndexes()
if err != nil {
return nil
}
return f.renameOldStore()
}
func (f *finisher) renameOldStore() error {
newName := migratedName
newPath := filepath.Join(filepath.Dir(f.oldPath), newName+filepath.Ext(f.oldPath))
err := os.Rename(f.oldPath, newPath)
if err != nil {
return fmt.Errorf("failed to rename: %w", err)
}
return nil
}
func (f *finisher) removeCrdtIndexes() error {
rootDir := filepath.Join(filepath.Dir(f.newStorePath), objectStoreFolder)
prefix := crdtDb
return filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() && strings.HasPrefix(info.Name(), prefix) {
if removeErr := os.Remove(path); removeErr != nil {
return removeErr
}
}
return nil
})
}

View file

@ -82,6 +82,53 @@ func (_c *MockClientStorage_AllSpaceIds_Call) RunAndReturn(run func() ([]string,
return _c
}
// BindSpaceID provides a mock function with given fields: spaceID, objectID
func (_m *MockClientStorage) BindSpaceID(spaceID string, objectID string) error {
ret := _m.Called(spaceID, objectID)
if len(ret) == 0 {
panic("no return value specified for BindSpaceID")
}
var r0 error
if rf, ok := ret.Get(0).(func(string, string) error); ok {
r0 = rf(spaceID, objectID)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockClientStorage_BindSpaceID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'BindSpaceID'
type MockClientStorage_BindSpaceID_Call struct {
*mock.Call
}
// BindSpaceID is a helper method to define mock.On call
// - spaceID string
// - objectID string
func (_e *MockClientStorage_Expecter) BindSpaceID(spaceID interface{}, objectID interface{}) *MockClientStorage_BindSpaceID_Call {
return &MockClientStorage_BindSpaceID_Call{Call: _e.mock.On("BindSpaceID", spaceID, objectID)}
}
func (_c *MockClientStorage_BindSpaceID_Call) Run(run func(spaceID string, objectID string)) *MockClientStorage_BindSpaceID_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(string))
})
return _c
}
func (_c *MockClientStorage_BindSpaceID_Call) Return(err error) *MockClientStorage_BindSpaceID_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockClientStorage_BindSpaceID_Call) RunAndReturn(run func(string, string) error) *MockClientStorage_BindSpaceID_Call {
_c.Call.Return(run)
return _c
}
// Close provides a mock function with given fields: ctx
func (_m *MockClientStorage) Close(ctx context.Context) error {
ret := _m.Called(ctx)
@ -128,9 +175,9 @@ func (_c *MockClientStorage_Close_Call) RunAndReturn(run func(context.Context) e
return _c
}
// CreateSpaceStorage provides a mock function with given fields: ctx, payload
func (_m *MockClientStorage) CreateSpaceStorage(ctx context.Context, payload spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error) {
ret := _m.Called(ctx, payload)
// CreateSpaceStorage provides a mock function with given fields: payload
func (_m *MockClientStorage) CreateSpaceStorage(payload spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error) {
ret := _m.Called(payload)
if len(ret) == 0 {
panic("no return value specified for CreateSpaceStorage")
@ -138,19 +185,19 @@ func (_m *MockClientStorage) CreateSpaceStorage(ctx context.Context, payload spa
var r0 spacestorage.SpaceStorage
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error)); ok {
return rf(ctx, payload)
if rf, ok := ret.Get(0).(func(spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error)); ok {
return rf(payload)
}
if rf, ok := ret.Get(0).(func(context.Context, spacestorage.SpaceStorageCreatePayload) spacestorage.SpaceStorage); ok {
r0 = rf(ctx, payload)
if rf, ok := ret.Get(0).(func(spacestorage.SpaceStorageCreatePayload) spacestorage.SpaceStorage); ok {
r0 = rf(payload)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(spacestorage.SpaceStorage)
}
}
if rf, ok := ret.Get(1).(func(context.Context, spacestorage.SpaceStorageCreatePayload) error); ok {
r1 = rf(ctx, payload)
if rf, ok := ret.Get(1).(func(spacestorage.SpaceStorageCreatePayload) error); ok {
r1 = rf(payload)
} else {
r1 = ret.Error(1)
}
@ -164,15 +211,14 @@ type MockClientStorage_CreateSpaceStorage_Call struct {
}
// CreateSpaceStorage is a helper method to define mock.On call
// - ctx context.Context
// - payload spacestorage.SpaceStorageCreatePayload
func (_e *MockClientStorage_Expecter) CreateSpaceStorage(ctx interface{}, payload interface{}) *MockClientStorage_CreateSpaceStorage_Call {
return &MockClientStorage_CreateSpaceStorage_Call{Call: _e.mock.On("CreateSpaceStorage", ctx, payload)}
func (_e *MockClientStorage_Expecter) CreateSpaceStorage(payload interface{}) *MockClientStorage_CreateSpaceStorage_Call {
return &MockClientStorage_CreateSpaceStorage_Call{Call: _e.mock.On("CreateSpaceStorage", payload)}
}
func (_c *MockClientStorage_CreateSpaceStorage_Call) Run(run func(ctx context.Context, payload spacestorage.SpaceStorageCreatePayload)) *MockClientStorage_CreateSpaceStorage_Call {
func (_c *MockClientStorage_CreateSpaceStorage_Call) Run(run func(payload spacestorage.SpaceStorageCreatePayload)) *MockClientStorage_CreateSpaceStorage_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(spacestorage.SpaceStorageCreatePayload))
run(args[0].(spacestorage.SpaceStorageCreatePayload))
})
return _c
}
@ -182,7 +228,7 @@ func (_c *MockClientStorage_CreateSpaceStorage_Call) Return(_a0 spacestorage.Spa
return _c
}
func (_c *MockClientStorage_CreateSpaceStorage_Call) RunAndReturn(run func(context.Context, spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error)) *MockClientStorage_CreateSpaceStorage_Call {
func (_c *MockClientStorage_CreateSpaceStorage_Call) RunAndReturn(run func(spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error)) *MockClientStorage_CreateSpaceStorage_Call {
_c.Call.Return(run)
return _c
}
@ -234,6 +280,62 @@ func (_c *MockClientStorage_DeleteSpaceStorage_Call) RunAndReturn(run func(conte
return _c
}
// GetSpaceID provides a mock function with given fields: objectID
func (_m *MockClientStorage) GetSpaceID(objectID string) (string, error) {
ret := _m.Called(objectID)
if len(ret) == 0 {
panic("no return value specified for GetSpaceID")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
return rf(objectID)
}
if rf, ok := ret.Get(0).(func(string) string); ok {
r0 = rf(objectID)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(objectID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockClientStorage_GetSpaceID_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetSpaceID'
type MockClientStorage_GetSpaceID_Call struct {
*mock.Call
}
// GetSpaceID is a helper method to define mock.On call
// - objectID string
func (_e *MockClientStorage_Expecter) GetSpaceID(objectID interface{}) *MockClientStorage_GetSpaceID_Call {
return &MockClientStorage_GetSpaceID_Call{Call: _e.mock.On("GetSpaceID", objectID)}
}
func (_c *MockClientStorage_GetSpaceID_Call) Run(run func(objectID string)) *MockClientStorage_GetSpaceID_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}
func (_c *MockClientStorage_GetSpaceID_Call) Return(spaceID string, err error) *MockClientStorage_GetSpaceID_Call {
_c.Call.Return(spaceID, err)
return _c
}
func (_c *MockClientStorage_GetSpaceID_Call) RunAndReturn(run func(string) (string, error)) *MockClientStorage_GetSpaceID_Call {
_c.Call.Return(run)
return _c
}
// Init provides a mock function with given fields: a
func (_m *MockClientStorage) Init(a *app.App) error {
ret := _m.Called(a)
@ -280,6 +382,98 @@ func (_c *MockClientStorage_Init_Call) RunAndReturn(run func(*app.App) error) *M
return _c
}
// IsSpaceCreated provides a mock function with given fields: id
func (_m *MockClientStorage) IsSpaceCreated(id string) bool {
ret := _m.Called(id)
if len(ret) == 0 {
panic("no return value specified for IsSpaceCreated")
}
var r0 bool
if rf, ok := ret.Get(0).(func(string) bool); ok {
r0 = rf(id)
} else {
r0 = ret.Get(0).(bool)
}
return r0
}
// MockClientStorage_IsSpaceCreated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IsSpaceCreated'
type MockClientStorage_IsSpaceCreated_Call struct {
*mock.Call
}
// IsSpaceCreated is a helper method to define mock.On call
// - id string
func (_e *MockClientStorage_Expecter) IsSpaceCreated(id interface{}) *MockClientStorage_IsSpaceCreated_Call {
return &MockClientStorage_IsSpaceCreated_Call{Call: _e.mock.On("IsSpaceCreated", id)}
}
func (_c *MockClientStorage_IsSpaceCreated_Call) Run(run func(id string)) *MockClientStorage_IsSpaceCreated_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}
func (_c *MockClientStorage_IsSpaceCreated_Call) Return(created bool) *MockClientStorage_IsSpaceCreated_Call {
_c.Call.Return(created)
return _c
}
func (_c *MockClientStorage_IsSpaceCreated_Call) RunAndReturn(run func(string) bool) *MockClientStorage_IsSpaceCreated_Call {
_c.Call.Return(run)
return _c
}
// MarkSpaceCreated provides a mock function with given fields: id
func (_m *MockClientStorage) MarkSpaceCreated(id string) error {
ret := _m.Called(id)
if len(ret) == 0 {
panic("no return value specified for MarkSpaceCreated")
}
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(id)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockClientStorage_MarkSpaceCreated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'MarkSpaceCreated'
type MockClientStorage_MarkSpaceCreated_Call struct {
*mock.Call
}
// MarkSpaceCreated is a helper method to define mock.On call
// - id string
func (_e *MockClientStorage_Expecter) MarkSpaceCreated(id interface{}) *MockClientStorage_MarkSpaceCreated_Call {
return &MockClientStorage_MarkSpaceCreated_Call{Call: _e.mock.On("MarkSpaceCreated", id)}
}
func (_c *MockClientStorage_MarkSpaceCreated_Call) Run(run func(id string)) *MockClientStorage_MarkSpaceCreated_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}
func (_c *MockClientStorage_MarkSpaceCreated_Call) Return(err error) *MockClientStorage_MarkSpaceCreated_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockClientStorage_MarkSpaceCreated_Call) RunAndReturn(run func(string) error) *MockClientStorage_MarkSpaceCreated_Call {
_c.Call.Return(run)
return _c
}
// Name provides a mock function with given fields:
func (_m *MockClientStorage) Name() string {
ret := _m.Called()
@ -417,6 +611,52 @@ func (_c *MockClientStorage_SpaceExists_Call) RunAndReturn(run func(string) bool
return _c
}
// UnmarkSpaceCreated provides a mock function with given fields: id
func (_m *MockClientStorage) UnmarkSpaceCreated(id string) error {
ret := _m.Called(id)
if len(ret) == 0 {
panic("no return value specified for UnmarkSpaceCreated")
}
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(id)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockClientStorage_UnmarkSpaceCreated_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UnmarkSpaceCreated'
type MockClientStorage_UnmarkSpaceCreated_Call struct {
*mock.Call
}
// UnmarkSpaceCreated is a helper method to define mock.On call
// - id string
func (_e *MockClientStorage_Expecter) UnmarkSpaceCreated(id interface{}) *MockClientStorage_UnmarkSpaceCreated_Call {
return &MockClientStorage_UnmarkSpaceCreated_Call{Call: _e.mock.On("UnmarkSpaceCreated", id)}
}
func (_c *MockClientStorage_UnmarkSpaceCreated_Call) Run(run func(id string)) *MockClientStorage_UnmarkSpaceCreated_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}
func (_c *MockClientStorage_UnmarkSpaceCreated_Call) Return(err error) *MockClientStorage_UnmarkSpaceCreated_Call {
_c.Call.Return(err)
return _c
}
func (_c *MockClientStorage_UnmarkSpaceCreated_Call) RunAndReturn(run func(string) error) *MockClientStorage_UnmarkSpaceCreated_Call {
_c.Call.Return(run)
return _c
}
// WaitSpaceStorage provides a mock function with given fields: ctx, id
func (_m *MockClientStorage) WaitSpaceStorage(ctx context.Context, id string) (spacestorage.SpaceStorage, error) {
ret := _m.Called(ctx, id)

View file

@ -6,14 +6,12 @@ import (
"errors"
"sync"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/anyproto/any-sync/consensus/consensusproto"
)
var ErrUnknownRecord = errors.New("record does not exist")
func newListStorage(ss *spaceStorage, treeId string) (oldstorage.ListStorage, error) {
func newListStorage(ss *spaceStorage, treeId string) (liststorage.ListStorage, error) {
ts := &listStorage{
listId: treeId,
spaceStorage: ss,
@ -40,7 +38,7 @@ type listStorage struct {
func (t *listStorage) Root() (*consensusproto.RawRecordWithId, error) {
tch, err := t.spaceStorage.TreeRoot(t.listId)
if err != nil {
return nil, replaceNoRowsErr(err, ErrUnknownRecord)
return nil, replaceNoRowsErr(err, liststorage.ErrUnknownRecord)
}
return &consensusproto.RawRecordWithId{
Payload: tch.RawChange,
@ -68,7 +66,7 @@ func (t *listStorage) SetHead(headId string) error {
func (t *listStorage) GetRawRecord(ctx context.Context, id string) (*consensusproto.RawRecordWithId, error) {
tch, err := t.spaceStorage.TreeRoot(id)
if err != nil {
return nil, replaceNoRowsErr(err, ErrUnknownRecord)
return nil, replaceNoRowsErr(err, liststorage.ErrUnknownRecord)
}
return &consensusproto.RawRecordWithId{
Payload: tch.RawChange,

View file

@ -3,7 +3,7 @@ package sqlitestorage
import (
"testing"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/consensus/consensusproto"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -56,7 +56,7 @@ func TestListStorage_SetHead(t *testing.T) {
}
func testList(t *testing.T, store oldstorage.ListStorage, root *consensusproto.RawRecordWithId, head string) {
func testList(t *testing.T, store liststorage.ListStorage, root *consensusproto.RawRecordWithId, head string) {
require.Equal(t, store.Id(), root.Id)
aclRoot, err := store.Root()

View file

@ -5,7 +5,6 @@ import (
"database/sql"
"errors"
"net/url"
"os"
"sync"
"time"
@ -13,7 +12,6 @@ import (
"github.com/anyproto/any-sync/app/logger"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/globalsign/mgo/bson"
"github.com/mattn/go-sqlite3"
"go.uber.org/atomic"
@ -32,7 +30,7 @@ var (
)
type configGetter interface {
GetSqliteStorePath() string
GetSpaceStorePath() string
GetTempDirPath() string
}
@ -53,8 +51,6 @@ type storageService struct {
allTreeDelStatus,
change,
hasTree,
listChanges,
iterateChanges,
hasChange,
updateTreeHeads,
deleteTree,
@ -64,7 +60,6 @@ type storageService struct {
spaceIds,
spaceIsCreated,
upsertBind,
getAllBinds,
deleteSpace,
deleteTreesBySpace,
deleteChangesBySpace,
@ -96,7 +91,7 @@ func New() *storageService {
}
func (s *storageService) Init(a *app.App) (err error) {
s.dbPath = a.MustComponent("config").(configGetter).GetSqliteStorePath()
s.dbPath = a.MustComponent("config").(configGetter).GetSpaceStorePath()
s.dbTempPath = a.MustComponent("config").(configGetter).GetTempDirPath()
s.lockedSpaces = map[string]*lockSpace{}
if s.checkpointAfterWrite == 0 {
@ -164,7 +159,7 @@ func (s *storageService) Name() (name string) {
return spacestorage.CName
}
func (s *storageService) WaitSpaceStorage(ctx context.Context, id string) (store oldstorage.SpaceStorage, err error) {
func (s *storageService) WaitSpaceStorage(ctx context.Context, id string) (store spacestorage.SpaceStorage, err error) {
var ls *lockSpace
ls, err = s.checkLock(id, func() error {
store, err = newSpaceStorage(s, id)
@ -282,7 +277,7 @@ func (s *storageService) unlockSpaceStorage(id string) {
}
}
func (s *storageService) CreateSpaceStorage(payload spacestorage.SpaceStorageCreatePayload) (ss oldstorage.SpaceStorage, err error) {
func (s *storageService) CreateSpaceStorage(payload spacestorage.SpaceStorageCreatePayload) (ss spacestorage.SpaceStorage, err error) {
_, err = s.checkLock(payload.SpaceHeaderWithId.Id, func() error {
ss, err = createSpaceStorage(s, payload)
return err
@ -296,25 +291,6 @@ func (s *storageService) GetSpaceID(objectID string) (spaceID string, err error)
return
}
func (s *storageService) GetBoundObjectIds(spaceId string) ([]string, error) {
rows, err := s.stmt.getAllBinds.Query(spaceId)
if err != nil {
return nil, err
}
defer func() {
err = errors.Join(rows.Close())
}()
var ids []string
for rows.Next() {
var id string
if err = rows.Scan(&id); err != nil {
return nil, err
}
ids = append(ids, id)
}
return ids, nil
}
func (s *storageService) BindSpaceID(spaceID, objectID string) (err error) {
_, err = s.stmt.upsertBind.Exec(objectID, spaceID, spaceID)
return
@ -376,15 +352,6 @@ func (s *storageService) checkpoint() (err error) {
return err
}
func (s *storageService) EstimateSize() (uint64, error) {
stat, err := os.Stat(s.dbPath)
if err != nil {
return 0, err
}
// nolint: gosec
return uint64(stat.Size()), nil
}
func (s *storageService) Close(ctx context.Context) (err error) {
if s.ctxCancel != nil {
s.ctxCancel()

View file

@ -28,34 +28,6 @@ func TestStorageService_BindSpaceID(t *testing.T) {
assert.Equal(t, "spaceId2", spaceId)
}
func TestStorageService_GetBoundObjectIds(t *testing.T) {
t.Run("no bindings", func(t *testing.T) {
fx := newFixture(t)
defer fx.finish(t)
spaceId := "spaceId"
ids, err := fx.GetBoundObjectIds(spaceId)
require.NoError(t, err)
assert.Empty(t, ids)
})
t.Run("ok", func(t *testing.T) {
fx := newFixture(t)
defer fx.finish(t)
spaceId := "spaceId"
require.NoError(t, fx.BindSpaceID(spaceId, "objectId1"))
require.NoError(t, fx.BindSpaceID(spaceId, "objectId2"))
ids, err := fx.GetBoundObjectIds(spaceId)
require.NoError(t, err)
assert.ElementsMatch(t, []string{"objectId1", "objectId2"}, ids)
})
}
func TestStorageService_DeleteSpaceStorage(t *testing.T) {
fx := newFixture(t)
defer fx.finish(t)
@ -220,7 +192,7 @@ type testConfig struct {
tmpDir string
}
func (t *testConfig) GetSqliteStorePath() string {
func (t *testConfig) GetSpaceStorePath() string {
return filepath.Join(t.tmpDir, "spaceStore.db")
}
func (t *testConfig) GetTempDirPath() string {

View file

@ -7,10 +7,10 @@ import (
"sync"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
_ "github.com/mattn/go-sqlite3"
)
@ -34,12 +34,12 @@ type spaceStorage struct {
isDeleted bool
aclStorage oldstorage.ListStorage
aclStorage liststorage.ListStorage
header *spacesyncproto.RawSpaceHeaderWithId
}
func newSpaceStorage(s *storageService, spaceId string) (oldstorage.SpaceStorage, error) {
func newSpaceStorage(s *storageService, spaceId string) (spacestorage.SpaceStorage, error) {
ss := &spaceStorage{
spaceId: spaceId,
service: s,
@ -64,7 +64,7 @@ func newSpaceStorage(s *storageService, spaceId string) (oldstorage.SpaceStorage
return ss, nil
}
func createSpaceStorage(s *storageService, payload spacestorage.SpaceStorageCreatePayload) (oldstorage.SpaceStorage, error) {
func createSpaceStorage(s *storageService, payload spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error) {
tx, err := s.writeDb.Begin()
if err != nil {
return nil, err
@ -194,7 +194,7 @@ func (s *spaceStorage) TreeDeletedStatus(id string) (status string, err error) {
}
func (s *spaceStorage) AllDeletedTreeIds() (ids []string, err error) {
rows, err := s.service.stmt.allTreeDelStatus.Query(s.spaceId, oldstorage.TreeDeletedStatusDeleted)
rows, err := s.service.stmt.allTreeDelStatus.Query(s.spaceId, spacestorage.TreeDeletedStatusDeleted)
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
@ -218,7 +218,7 @@ func (s *spaceStorage) SpaceSettingsId() string {
return s.spaceSettingsId
}
func (s *spaceStorage) AclStorage() (oldstorage.ListStorage, error) {
func (s *spaceStorage) AclStorage() (liststorage.ListStorage, error) {
return s.aclStorage, nil
}
@ -258,7 +258,7 @@ func (s *spaceStorage) TreeRoot(id string) (*treechangeproto.RawTreeChangeWithId
}, nil
}
func (s *spaceStorage) TreeStorage(id string) (oldstorage.TreeStorage, error) {
func (s *spaceStorage) TreeStorage(id string) (treestorage.TreeStorage, error) {
return newTreeStorage(s, id)
}
@ -271,7 +271,7 @@ func (s *spaceStorage) HasTree(id string) (bool, error) {
return res > 0, nil
}
func (s *spaceStorage) CreateTreeStorage(payload treestorage.TreeStorageCreatePayload) (oldstorage.TreeStorage, error) {
func (s *spaceStorage) CreateTreeStorage(payload treestorage.TreeStorageCreatePayload) (treestorage.TreeStorage, error) {
return createTreeStorage(s, payload)
}

View file

@ -6,7 +6,6 @@ import (
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/anyproto/any-sync/commonspace/spacesyncproto"
"github.com/anyproto/any-sync/consensus/consensusproto"
"github.com/stretchr/testify/assert"
@ -91,7 +90,7 @@ func TestSpaceStorage_NewAndCreateTree(t *testing.T) {
treeIds, err := store.StoredIds()
require.NoError(t, err)
assert.Equal(t, []string{payload.SpaceSettingsWithId.Id}, treeIds)
assert.Equal(t, []string{payload.SpaceSettingsWithId.Id, otherStore.Id()}, treeIds)
deletedIds, err := store.(*spaceStorage).AllDeletedTreeIds()
require.NoError(t, err)
@ -107,11 +106,11 @@ func TestSpaceStorage_AllDeletedTreeIds(t *testing.T) {
store, err := createSpaceStorage(fx.storageService, payload)
require.NoError(t, err)
err = store.SetTreeDeletedStatus("id1", oldstorage.TreeDeletedStatusDeleted)
err = store.SetTreeDeletedStatus("id1", spacestorage.TreeDeletedStatusDeleted)
require.NoError(t, err)
err = store.SetTreeDeletedStatus("id2", oldstorage.TreeDeletedStatusQueued)
err = store.SetTreeDeletedStatus("id2", spacestorage.TreeDeletedStatusQueued)
require.NoError(t, err)
err = store.SetTreeDeletedStatus("id3", oldstorage.TreeDeletedStatusDeleted)
err = store.SetTreeDeletedStatus("id3", spacestorage.TreeDeletedStatusDeleted)
require.NoError(t, err)
deletedIds, err := store.(*spaceStorage).AllDeletedTreeIds()
@ -128,12 +127,12 @@ func TestSpaceStorage_SetTreeDeletedStatus(t *testing.T) {
store, err := createSpaceStorage(fx.storageService, payload)
require.NoError(t, err)
err = store.SetTreeDeletedStatus("treeId", oldstorage.TreeDeletedStatusDeleted)
err = store.SetTreeDeletedStatus("treeId", spacestorage.TreeDeletedStatusDeleted)
require.NoError(t, err)
status, err := store.TreeDeletedStatus("treeId")
require.NoError(t, err)
require.Equal(t, oldstorage.TreeDeletedStatusDeleted, status)
require.Equal(t, spacestorage.TreeDeletedStatusDeleted, status)
_, err = store.TreeStorage("treeId")
require.ErrorIs(t, err, treestorage.ErrUnknownTreeId)
@ -203,7 +202,7 @@ func TestSpaceStorage_ReadSpaceHash(t *testing.T) {
require.NoError(t, ss.WriteSpaceHash("hash"))
var checkHashes = func(ss oldstorage.SpaceStorage) {
var checkHashes = func(ss spacestorage.SpaceStorage) {
hash, err = ss.ReadSpaceHash()
require.NoError(t, err)
assert.Equal(t, "hash", hash)
@ -239,7 +238,7 @@ func spaceTestPayload() spacestorage.SpaceStorageCreatePayload {
}
}
func testSpace(t *testing.T, store oldstorage.SpaceStorage, payload spacestorage.SpaceStorageCreatePayload) {
func testSpace(t *testing.T, store spacestorage.SpaceStorage, payload spacestorage.SpaceStorageCreatePayload) {
header, err := store.SpaceHeader()
require.NoError(t, err)
require.Equal(t, payload.SpaceHeaderWithId, header)

View file

@ -58,7 +58,7 @@ func initStmts(s *storageService) (err error) {
if s.stmt.updateSpaceIsDeleted, err = s.writeDb.Prepare(`UPDATE spaces SET isDeleted = ? WHERE id = ?`); err != nil {
return
}
if s.stmt.treeIdsBySpace, err = s.readDb.Prepare(`SELECT id FROM trees WHERE spaceId = ? AND type != 1 AND deleteStatus IS NULL`); err != nil {
if s.stmt.treeIdsBySpace, err = s.readDb.Prepare(`SELECT id FROM trees WHERE spaceId = ? AND type != 1`); err != nil {
return
}
if s.stmt.deleteTree, err = s.writeDb.Prepare(`
@ -88,12 +88,6 @@ func initStmts(s *storageService) (err error) {
if s.stmt.hasChange, err = s.readDb.Prepare(`SELECT COUNT(*) FROM changes WHERE id = ? AND treeId = ?`); err != nil {
return
}
if s.stmt.listChanges, err = s.readDb.Prepare(`SELECT id FROM changes WHERE treeId = ? ORDER BY id`); err != nil {
return
}
if s.stmt.iterateChanges, err = s.readDb.Prepare(`SELECT id, data FROM changes WHERE treeId = ? ORDER BY id`); err != nil {
return
}
if s.stmt.updateTreeHeads, err = s.writeDb.Prepare(`UPDATE trees SET heads = ? WHERE id = ?`); err != nil {
return
}
@ -118,9 +112,6 @@ func initStmts(s *storageService) (err error) {
if s.stmt.upsertBind, err = s.writeDb.Prepare(`INSERT INTO binds (objectId, spaceId) VALUES (?, ?) ON CONFLICT (objectId) DO UPDATE SET spaceId = ?`); err != nil {
return
}
if s.stmt.getAllBinds, err = s.writeDb.Prepare(`SELECT objectId FROM binds WHERE spaceId = ?`); err != nil {
return
}
if s.stmt.deleteSpace, err = s.writeDb.Prepare(`DELETE FROM spaces WHERE id = ?`); err != nil {
return
}

View file

@ -1,18 +1,15 @@
package sqlitestorage
import (
"bytes"
"context"
"errors"
"fmt"
"sync"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
)
func newTreeStorage(ss *spaceStorage, treeId string) (oldstorage.TreeStorage, error) {
func newTreeStorage(ss *spaceStorage, treeId string) (treestorage.TreeStorage, error) {
ts := &treeStorage{
treeId: treeId,
spaceStorage: ss,
@ -26,7 +23,7 @@ func newTreeStorage(ss *spaceStorage, treeId string) (oldstorage.TreeStorage, er
return ts, nil
}
func createTreeStorage(ss *spaceStorage, payload treestorage.TreeStorageCreatePayload) (ts oldstorage.TreeStorage, err error) {
func createTreeStorage(ss *spaceStorage, payload treestorage.TreeStorageCreatePayload) (ts treestorage.TreeStorage, err error) {
ts = &treeStorage{
treeId: payload.RootRawChange.Id,
spaceStorage: ss,
@ -102,54 +99,7 @@ func (t *treeStorage) Heads() ([]string, error) {
}
func (t *treeStorage) GetAllChangeIds() (chs []string, err error) {
rows, err := t.service.stmt.listChanges.Query(t.treeId)
if err != nil {
return nil, replaceNoRowsErr(err, nil)
}
for rows.Next() {
var id string
err = rows.Scan(&id)
if err != nil {
return nil, errors.Join(rows.Close(), err)
}
chs = append(chs, id)
}
return chs, rows.Close()
}
func (t *treeStorage) GetAllChanges() ([]*treechangeproto.RawTreeChangeWithId, error) {
var changes []*treechangeproto.RawTreeChangeWithId
err := t.IterateChanges(func(id string, rawChange []byte) error {
changes = append(changes, &treechangeproto.RawTreeChangeWithId{
Id: id,
RawChange: bytes.Clone(rawChange),
})
return nil
})
return changes, err
}
func (t *treeStorage) IterateChanges(proc func(id string, rawChange []byte) error) error {
rows, err := t.service.stmt.iterateChanges.Query(t.treeId)
if err != nil {
return replaceNoRowsErr(err, nil)
}
buf := make([]byte, 0, 1024)
for rows.Next() {
var id string
err = rows.Scan(&id, &buf)
if err != nil {
return errors.Join(rows.Close(), err)
}
err = proc(id, buf)
if err != nil {
return errors.Join(rows.Close(), err)
}
buf = buf[:0]
}
return rows.Close()
return nil, fmt.Errorf("get all change ids should not be called")
}
func (t *treeStorage) SetHeads(heads []string) error {

View file

@ -1,26 +1,17 @@
package sqlitestorage
import (
"bytes"
"crypto/rand"
"database/sql"
"encoding/hex"
"slices"
"sort"
"testing"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/object/tree/treestorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type oldTreeStorage interface {
oldstorage.ChangesIterator
oldstorage.TreeStorage
}
func TestTreeStorage_Create(t *testing.T) {
fx := newFixture(t)
defer fx.finish(t)
@ -47,13 +38,11 @@ func TestTreeStorage_Methods(t *testing.T) {
ss, err := createSpaceStorage(fx.storageService, spacePayload)
require.NoError(t, err)
payload := treeTestPayload()
var store oldTreeStorage
treeStore, err := ss.CreateTreeStorage(payload)
store, err := ss.CreateTreeStorage(payload)
require.NoError(t, err)
treeStore, err = ss.TreeStorage(payload.RootRawChange.Id)
store, err = ss.TreeStorage(payload.RootRawChange.Id)
require.NoError(t, err)
store = treeStore.(oldTreeStorage)
testTreePayload(t, store, payload)
t.Run("update heads", func(t *testing.T) {
@ -65,7 +54,7 @@ func TestTreeStorage_Methods(t *testing.T) {
})
t.Run("add raw change, get change and has change", func(t *testing.T) {
newChange := &treechangeproto.RawTreeChangeWithId{RawChange: []byte("ab"), Id: "id10"}
newChange := &treechangeproto.RawTreeChangeWithId{RawChange: []byte("ab"), Id: "newId"}
require.NoError(t, store.AddRawChange(newChange))
rawCh, err := store.GetRawChange(ctx, newChange.Id)
require.NoError(t, err)
@ -83,55 +72,6 @@ func TestTreeStorage_Methods(t *testing.T) {
require.NoError(t, err)
require.False(t, has)
})
t.Run("iterate changes", func(t *testing.T) {
newChange := &treechangeproto.RawTreeChangeWithId{RawChange: []byte("foo"), Id: "id01"}
require.NoError(t, store.AddRawChange(newChange))
newChange = &treechangeproto.RawTreeChangeWithId{RawChange: []byte("bar"), Id: "id20"}
require.NoError(t, store.AddRawChange(newChange))
var collected []*treechangeproto.RawTreeChangeWithId
require.NoError(t, store.IterateChanges(func(id string, rawChange []byte) error {
collected = append(collected, &treechangeproto.RawTreeChangeWithId{
Id: id,
RawChange: bytes.Clone(rawChange),
})
return nil
}))
want := slices.Clone(payload.Changes)
want = append(want, []*treechangeproto.RawTreeChangeWithId{
{Id: "id01", RawChange: []byte("foo")},
{Id: "id10", RawChange: []byte("ab")},
{Id: "id20", RawChange: []byte("bar")},
}...)
sort.Slice(want, func(i, j int) bool {
return want[i].Id < want[j].Id
})
assert.Equal(t, want, collected)
got, err := store.GetAllChanges()
require.NoError(t, err)
assert.Equal(t, want, got)
})
t.Run("get all change ids", func(t *testing.T) {
got, err := store.GetAllChangeIds()
require.NoError(t, err)
want := []string{
payload.Changes[0].Id,
payload.Changes[1].Id,
"id01",
"id10",
"id20",
}
sort.Strings(want)
assert.Equal(t, want, got)
})
}
func TestTreeStorage_AddRawChangesSetHeads(t *testing.T) {
@ -250,7 +190,7 @@ func treeTestPayload() treestorage.TreeStorageCreatePayload {
}
}
func testTreePayload(t *testing.T, store oldstorage.TreeStorage, payload treestorage.TreeStorageCreatePayload) {
func testTreePayload(t *testing.T, store treestorage.TreeStorage, payload treestorage.TreeStorageCreatePayload) {
require.Equal(t, payload.RootRawChange.Id, store.Id())
root, err := store.Root()

View file

@ -2,11 +2,13 @@ package storage
import (
"context"
"fmt"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/anystorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/badgerstorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/sqlitestorage"
)
type SpaceStorageMode int
@ -20,7 +22,12 @@ type ClientStorage interface {
spacestorage.SpaceStorageProvider
app.ComponentRunnable
AllSpaceIds() (ids []string, err error)
GetSpaceID(objectID string) (spaceID string, err error)
BindSpaceID(spaceID, objectID string) (err error)
DeleteSpaceStorage(ctx context.Context, spaceId string) error
MarkSpaceCreated(id string) (err error)
UnmarkSpaceCreated(id string) (err error)
IsSpaceCreated(id string) (created bool)
}
// storageService is a proxy for the actual storage implementation
@ -33,7 +40,7 @@ func New() ClientStorage {
}
type configGetter interface {
GetNewSpaceStorePath() string
GetSpaceStorageMode() SpaceStorageMode
}
func (s *storageService) Name() (name string) {
@ -41,7 +48,16 @@ func (s *storageService) Name() (name string) {
}
func (s *storageService) Init(a *app.App) (err error) {
rootPath := a.MustComponent("config").(configGetter).GetNewSpaceStorePath()
s.ClientStorage = anystorage.New(rootPath)
mode := a.MustComponent("config").(configGetter).GetSpaceStorageMode()
if mode == SpaceStorageModeBadger {
// for already existing account repos
s.ClientStorage = badgerstorage.New()
} else if mode == SpaceStorageModeSqlite {
// sqlite used for new account repos
s.ClientStorage = sqlitestorage.New()
} else {
return fmt.Errorf("unknown storage mode %d", mode)
}
return s.ClientStorage.Init(a)
}

Some files were not shown because too many files have changed in this diff Show more