1
0
Fork 0
mirror of https://github.com/anyproto/anytype-heart.git synced 2025-06-10 18:10:49 +09:00

GO-4780 Merge branch 'GO-4146-new-spacestore' of github.com:anyproto/anytype-heart into go-4780-change-orderid-to-afterorderid-in-subscriptiongo

This commit is contained in:
Sergey 2025-01-31 10:00:44 +01:00
commit e717173909
No known key found for this signature in database
GPG key ID: 3B6BEF79160221C6
92 changed files with 6532 additions and 2997 deletions

View file

@ -25,346 +25,348 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
func init() { proto.RegisterFile("pb/protos/service/service.proto", fileDescriptor_93a29dc403579097) }
var fileDescriptor_93a29dc403579097 = []byte{
// 5412 bytes of a gzipped FileDescriptorProto
// 5445 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x9d, 0xdd, 0x6f, 0x24, 0x49,
0x52, 0xc0, 0xcf, 0x2f, 0x2c, 0xd4, 0x71, 0x0b, 0xf4, 0xc2, 0xb2, 0xb7, 0xdc, 0xcd, 0xcc, 0xce,
0xce, 0xd8, 0x33, 0x63, 0xbb, 0x3d, 0x3b, 0xb3, 0x1f, 0xa7, 0x3b, 0x24, 0xd4, 0x63, 0x8f, 0xbd,
0xbe, 0xb3, 0x3d, 0xc6, 0xdd, 0x9e, 0x91, 0x56, 0x42, 0x22, 0xdd, 0x95, 0x6e, 0x17, 0xae, 0xae,
0xbe, 0xb3, 0x3d, 0xc6, 0xdd, 0x9e, 0x91, 0x56, 0x42, 0xa2, 0xdc, 0x95, 0x6e, 0x17, 0xae, 0xae,
0xac, 0xab, 0xca, 0x6e, 0x4f, 0x1f, 0x02, 0x81, 0x40, 0x20, 0x10, 0x88, 0x13, 0x5f, 0xaf, 0x48,
0xfc, 0x35, 0x3c, 0xde, 0x23, 0x8f, 0x68, 0xf7, 0x0f, 0xe0, 0x9d, 0x27, 0x54, 0x59, 0x59, 0xf9,
0x11, 0x15, 0x91, 0x55, 0xbe, 0xa7, 0x19, 0x39, 0x7e, 0x11, 0x91, 0x9f, 0x91, 0x91, 0x59, 0x59,
0xd5, 0xd1, 0xdd, 0xfc, 0x62, 0x27, 0x2f, 0x84, 0x14, 0xe5, 0x4e, 0xc9, 0x8b, 0x65, 0x32, 0xe5,
0xcd, 0xbf, 0x43, 0xf5, 0xe7, 0xc1, 0x3b, 0x2c, 0x5b, 0xc9, 0x55, 0xce, 0x3f, 0xfc, 0xc0, 0x92,
0x53, 0x31, 0x9f, 0xb3, 0x2c, 0x2e, 0x6b, 0xe4, 0xc3, 0xf7, 0xad, 0x84, 0x2f, 0x79, 0x26, 0xf5,
0xdf, 0x9f, 0xfd, 0xdf, 0xff, 0xae, 0x45, 0xef, 0xee, 0xa6, 0x09, 0xcf, 0xe4, 0xae, 0xd6, 0x18,
0x7c, 0x15, 0x7d, 0x67, 0x94, 0xe7, 0x07, 0x5c, 0xbe, 0xe6, 0x45, 0x99, 0x88, 0x6c, 0xf0, 0xf1,
0x50, 0x3b, 0x18, 0x9e, 0xe5, 0xd3, 0xe1, 0x28, 0xcf, 0x87, 0x56, 0x38, 0x3c, 0xe3, 0x3f, 0x5d,
0xf0, 0x52, 0x7e, 0xf8, 0x20, 0x0c, 0x95, 0xb9, 0xc8, 0x4a, 0x3e, 0xb8, 0x8c, 0x7e, 0x6b, 0x94,
0xe7, 0x63, 0x2e, 0xf7, 0x78, 0x55, 0x81, 0xb1, 0x64, 0x92, 0x0f, 0x36, 0x5a, 0xaa, 0x3e, 0x60,
0x7c, 0x3c, 0xea, 0x06, 0xb5, 0x9f, 0x49, 0xf4, 0xed, 0xca, 0xcf, 0xd5, 0x42, 0xc6, 0xe2, 0x26,
0x1b, 0x7c, 0xd4, 0x56, 0xd4, 0x22, 0x63, 0xfb, 0x7e, 0x08, 0xd1, 0x56, 0xdf, 0x44, 0xbf, 0xfe,
0x86, 0xa5, 0x29, 0x97, 0xbb, 0x05, 0xaf, 0x0a, 0xee, 0xeb, 0xd4, 0xa2, 0x61, 0x2d, 0x33, 0x76,
0x3f, 0x0e, 0x32, 0xda, 0xf0, 0x57, 0xd1, 0x77, 0x6a, 0xc9, 0x19, 0x9f, 0x8a, 0x25, 0x2f, 0x06,
0xa8, 0x96, 0x16, 0x12, 0x4d, 0xde, 0x82, 0xa0, 0xed, 0x5d, 0x91, 0x2d, 0x79, 0x21, 0x71, 0xdb,
0x5a, 0x18, 0xb6, 0x6d, 0x21, 0x6d, 0xfb, 0xef, 0xd6, 0xa2, 0xef, 0x8d, 0xa6, 0x53, 0xb1, 0xc8,
0xe4, 0x91, 0x98, 0xb2, 0xf4, 0x28, 0xc9, 0xae, 0x4f, 0xf8, 0xcd, 0xee, 0x55, 0xc5, 0x67, 0x33,
0x3e, 0x78, 0xee, 0xb7, 0x6a, 0x8d, 0x0e, 0x0d, 0x3b, 0x74, 0x61, 0xe3, 0xfb, 0xd3, 0xdb, 0x29,
0xe9, 0xb2, 0xfc, 0xd3, 0x5a, 0x74, 0x07, 0x96, 0x65, 0x2c, 0xd2, 0x25, 0xb7, 0xa5, 0xf9, 0xac,
0xc3, 0xb0, 0x8f, 0x9b, 0xf2, 0x7c, 0x7e, 0x5b, 0x35, 0x5d, 0xa2, 0x34, 0x7a, 0xcf, 0x1d, 0x2e,
0x63, 0x5e, 0xaa, 0xe9, 0xf4, 0x98, 0x1e, 0x11, 0x1a, 0x31, 0x9e, 0x9f, 0xf4, 0x41, 0xb5, 0xb7,
0x24, 0x1a, 0x68, 0x6f, 0xa9, 0x28, 0x8d, 0xb3, 0x47, 0xa8, 0x05, 0x87, 0x30, 0xbe, 0x1e, 0xf7,
0x20, 0xb5, 0xab, 0x3f, 0x8e, 0x7e, 0xe3, 0x8d, 0x28, 0xae, 0xcb, 0x9c, 0x4d, 0xb9, 0x9e, 0x0a,
0x0f, 0x7d, 0xed, 0x46, 0x0a, 0x67, 0xc3, 0x7a, 0x17, 0xe6, 0x0c, 0xda, 0x46, 0xf8, 0x2a, 0xe7,
0x30, 0x06, 0x59, 0xc5, 0x4a, 0x48, 0x0d, 0x5a, 0x08, 0x69, 0xdb, 0xd7, 0xd1, 0xc0, 0xda, 0xbe,
0xf8, 0x13, 0x3e, 0x95, 0xa3, 0x38, 0x86, 0xbd, 0x62, 0x75, 0x15, 0x31, 0x1c, 0xc5, 0x31, 0xd5,
0x2b, 0x38, 0xaa, 0x9d, 0xdd, 0x44, 0xef, 0x03, 0x67, 0x47, 0x49, 0xa9, 0x1c, 0x6e, 0x87, 0xad,
0x68, 0xcc, 0x38, 0x1d, 0xf6, 0xc5, 0xb5, 0xe3, 0xbf, 0x58, 0x8b, 0xbe, 0x8b, 0x78, 0x3e, 0xe3,
0x73, 0xb1, 0xe4, 0x83, 0xa7, 0xdd, 0xd6, 0x6a, 0xd2, 0xf8, 0xff, 0xe4, 0x16, 0x1a, 0xc8, 0x30,
0x19, 0xf3, 0x94, 0x4f, 0x25, 0x39, 0x4c, 0x6a, 0x71, 0xe7, 0x30, 0x31, 0x98, 0x33, 0xc3, 0x1a,
0xe1, 0x01, 0x97, 0xbb, 0x8b, 0xa2, 0xe0, 0x99, 0x24, 0xfb, 0xd2, 0x22, 0x9d, 0x7d, 0xe9, 0xa1,
0x48, 0x7d, 0x0e, 0xb8, 0x1c, 0xa5, 0x29, 0x59, 0x9f, 0x5a, 0xdc, 0x59, 0x1f, 0x83, 0x69, 0x0f,
0xd3, 0xe8, 0x37, 0x9d, 0x16, 0x93, 0x87, 0xd9, 0xa5, 0x18, 0xd0, 0x6d, 0xa1, 0xe4, 0xc6, 0xc7,
0x46, 0x27, 0x87, 0x54, 0xe3, 0xe5, 0xdb, 0x5c, 0x14, 0x74, 0xb7, 0xd4, 0xe2, 0xce, 0x6a, 0x18,
0x4c, 0x7b, 0xf8, 0xa3, 0xe8, 0x5d, 0x1d, 0x25, 0x9b, 0xf5, 0xec, 0x01, 0x1a, 0x42, 0xe1, 0x82,
0xf6, 0xb0, 0x83, 0xb2, 0xc1, 0x41, 0xcb, 0x74, 0xf0, 0xf9, 0x18, 0xd5, 0x03, 0xa1, 0xe7, 0x41,
0x18, 0x6a, 0xd9, 0xde, 0xe3, 0x29, 0x27, 0x6d, 0xd7, 0xc2, 0x0e, 0xdb, 0x06, 0xd2, 0xb6, 0x8b,
0xe8, 0x77, 0x4c, 0xb3, 0x54, 0xeb, 0xa8, 0x92, 0x57, 0x41, 0x7a, 0x93, 0xa8, 0xb7, 0x0b, 0x19,
0x5f, 0x5b, 0xfd, 0xe0, 0x56, 0x7d, 0xf4, 0x0c, 0xc4, 0xeb, 0x03, 0xe6, 0xdf, 0x83, 0x30, 0xa4,
0x6d, 0xff, 0xfd, 0x5a, 0xf4, 0x7d, 0x2d, 0x7b, 0x99, 0xb1, 0x8b, 0x94, 0xab, 0x25, 0xf1, 0x84,
0xcb, 0x1b, 0x51, 0x5c, 0x8f, 0x57, 0xd9, 0x94, 0x58, 0xfe, 0x71, 0xb8, 0x63, 0xf9, 0x27, 0x95,
0x74, 0x61, 0xfe, 0x34, 0xfa, 0xa0, 0x19, 0x14, 0x57, 0x2c, 0x9b, 0xf1, 0x1f, 0x97, 0x22, 0x1b,
0xe5, 0xc9, 0x28, 0x8e, 0x8b, 0xc1, 0x10, 0xef, 0x7a, 0xc8, 0x99, 0x12, 0xec, 0xf4, 0xe6, 0x9d,
0x74, 0x53, 0xb7, 0xb2, 0x14, 0x39, 0x4c, 0x37, 0x9b, 0xe6, 0x93, 0x22, 0xa7, 0xd2, 0x4d, 0x1f,
0x69, 0x59, 0x3d, 0xae, 0x62, 0x36, 0x6e, 0xf5, 0xd8, 0x0d, 0xd2, 0xf7, 0x43, 0x88, 0x8d, 0x99,
0x4d, 0x43, 0x89, 0xec, 0x32, 0x99, 0x9d, 0xe7, 0x71, 0x35, 0x87, 0x1e, 0xe3, 0x75, 0x76, 0x10,
0x22, 0x66, 0x12, 0xa8, 0xf6, 0xf6, 0x8f, 0x36, 0x2b, 0xd3, 0xf3, 0x78, 0xbf, 0x10, 0xf3, 0x23,
0x3e, 0x63, 0xd3, 0x95, 0x0e, 0x3e, 0x9f, 0x86, 0x66, 0x3d, 0xa4, 0x4d, 0x21, 0x3e, 0xbb, 0xa5,
0x96, 0x2e, 0xcf, 0x7f, 0xac, 0x45, 0x0f, 0xbc, 0x71, 0xa2, 0x07, 0x53, 0x5d, 0xfa, 0x51, 0x16,
0x9f, 0xf1, 0x52, 0xb2, 0x42, 0x0e, 0x7e, 0x18, 0x18, 0x03, 0x84, 0x8e, 0x29, 0xdb, 0x8f, 0x7e,
0x29, 0x5d, 0xdb, 0xeb, 0xe3, 0x2a, 0xaa, 0xea, 0xf8, 0xe3, 0xf7, 0xba, 0x92, 0xc0, 0xe8, 0x73,
0x3f, 0x84, 0xd8, 0x5e, 0x57, 0x82, 0xc3, 0x6c, 0x99, 0x48, 0x7e, 0xc0, 0x33, 0x5e, 0xb4, 0x7b,
0xbd, 0x56, 0xf5, 0x11, 0xa2, 0xd7, 0x09, 0xd4, 0x46, 0x3a, 0xcf, 0x9b, 0x59, 0x99, 0x37, 0x03,
0x46, 0x5a, 0x6b, 0xf3, 0x56, 0x3f, 0xd8, 0x6e, 0x2d, 0x1d, 0x9f, 0x67, 0x7c, 0x29, 0xae, 0xe1,
0xd6, 0xd2, 0x35, 0x51, 0x03, 0xc4, 0xd6, 0x12, 0x05, 0xed, 0xf2, 0xe9, 0xf8, 0x79, 0x9d, 0xf0,
0x1b, 0xb0, 0x7c, 0xba, 0xca, 0x95, 0x98, 0x58, 0x3e, 0x11, 0x4c, 0x7b, 0x38, 0x89, 0x7e, 0x4d,
0x09, 0x7f, 0x2c, 0x92, 0x6c, 0x70, 0x17, 0x51, 0xaa, 0x04, 0xc6, 0xea, 0x3d, 0x1a, 0x00, 0x25,
0xae, 0xfe, 0xba, 0xcb, 0xb2, 0x29, 0x4f, 0xd1, 0x12, 0x5b, 0x71, 0xb0, 0xc4, 0x1e, 0x66, 0xf3,
0x16, 0x25, 0xac, 0xe2, 0xd7, 0xf8, 0x8a, 0x15, 0x49, 0x36, 0x1b, 0x60, 0xba, 0x8e, 0x9c, 0xc8,
0x5b, 0x30, 0x0e, 0x0c, 0x61, 0xad, 0x38, 0xca, 0xf3, 0xa2, 0x0a, 0x8b, 0xd8, 0x10, 0xf6, 0x91,
0xe0, 0x10, 0x6e, 0xa1, 0xb8, 0xb7, 0x3d, 0x3e, 0x4d, 0x93, 0x2c, 0xe8, 0x4d, 0x23, 0x7d, 0xbc,
0x59, 0x14, 0x0c, 0xde, 0x23, 0xce, 0x96, 0xbc, 0xa9, 0x19, 0xd6, 0x32, 0x2e, 0x10, 0x1c, 0xbc,
0x00, 0xb4, 0x9b, 0x44, 0x25, 0x3e, 0x66, 0xd7, 0xbc, 0x6a, 0x60, 0x5e, 0x2d, 0xaa, 0x03, 0x4c,
0xdf, 0x23, 0x88, 0x4d, 0x22, 0x4e, 0x6a, 0x57, 0x8b, 0xe8, 0x7d, 0x25, 0x3f, 0x65, 0x85, 0x4c,
0xa6, 0x49, 0xce, 0xb2, 0x66, 0xf3, 0x81, 0xcd, 0xeb, 0x16, 0x65, 0x5c, 0x6e, 0xf7, 0xa4, 0xb5,
0xdb, 0x7f, 0x5f, 0x8b, 0x3e, 0x82, 0x7e, 0x4f, 0x79, 0x31, 0x4f, 0xd4, 0x1e, 0xb6, 0xac, 0x83,
0xf0, 0xe0, 0x8b, 0xb0, 0xd1, 0x96, 0x82, 0x29, 0xcd, 0x0f, 0x6e, 0xaf, 0x68, 0x33, 0xb1, 0xb1,
0xce, 0xeb, 0x5f, 0x15, 0x71, 0xeb, 0x8c, 0x67, 0xdc, 0x24, 0xeb, 0x4a, 0x48, 0x64, 0x62, 0x2d,
0x08, 0xcc, 0xf0, 0xf3, 0xac, 0x6c, 0xac, 0x63, 0x33, 0xdc, 0x8a, 0x83, 0x33, 0xdc, 0xc3, 0xec,
0x0c, 0x3f, 0x5d, 0x5c, 0xa4, 0x49, 0x79, 0x95, 0x64, 0x33, 0x9d, 0x76, 0xfb, 0xba, 0x56, 0x0c,
0x33, 0xef, 0x8d, 0x4e, 0x0e, 0x73, 0xa2, 0x07, 0x0b, 0xe9, 0x04, 0x0c, 0x93, 0x8d, 0x4e, 0xce,
0x6e, 0x4e, 0xac, 0xb4, 0xda, 0xb6, 0x82, 0xcd, 0x89, 0xa3, 0x5a, 0x49, 0x89, 0xcd, 0x49, 0x9b,
0xd2, 0xe6, 0x45, 0xf4, 0xdb, 0x6e, 0x1d, 0x4a, 0x91, 0x2e, 0xf9, 0x79, 0x91, 0x0c, 0x9e, 0xd0,
0xe5, 0x6b, 0x18, 0xe3, 0x6a, 0xb3, 0x17, 0x6b, 0x03, 0x95, 0x25, 0x0e, 0xb8, 0x1c, 0x4b, 0x26,
0x17, 0x25, 0x08, 0x54, 0x8e, 0x0d, 0x83, 0x10, 0x81, 0x8a, 0x40, 0xb5, 0xb7, 0x3f, 0x8c, 0xa2,
0x7a, 0xc7, 0xaf, 0x4e, 0x65, 0xfc, 0xb5, 0x47, 0x1f, 0x05, 0x78, 0x47, 0x32, 0x1f, 0x05, 0x08,
0x9b, 0xf0, 0xd4, 0x7f, 0x57, 0x87, 0x4d, 0x03, 0x54, 0x43, 0x89, 0x88, 0x84, 0x07, 0x20, 0xb0,
0xa0, 0xe3, 0x2b, 0x71, 0x83, 0x17, 0xb4, 0x92, 0x84, 0x0b, 0xaa, 0x09, 0x7b, 0xfc, 0xab, 0x0b,
0x8a, 0x1d, 0xff, 0x36, 0xc5, 0x08, 0x1d, 0xff, 0x42, 0xc6, 0x8e, 0x19, 0xd7, 0xf0, 0x0b, 0x21,
0xae, 0xe7, 0xac, 0xb8, 0x06, 0x63, 0xc6, 0x53, 0x6e, 0x18, 0x62, 0xcc, 0x50, 0xac, 0x1d, 0x33,
0xae, 0xc3, 0x2a, 0x5d, 0x3e, 0x2f, 0x52, 0x30, 0x66, 0x3c, 0x1b, 0x1a, 0x21, 0xc6, 0x0c, 0x81,
0xda, 0xe8, 0xe4, 0x7a, 0x1b, 0x73, 0x78, 0xe0, 0xe0, 0xa9, 0x8f, 0x39, 0x75, 0xe0, 0x80, 0x60,
0x70, 0x08, 0x1d, 0x14, 0x2c, 0xbf, 0xc2, 0x87, 0x90, 0x12, 0x85, 0x87, 0x50, 0x83, 0xc0, 0xfe,
0x1e, 0x73, 0x56, 0x4c, 0xaf, 0xf0, 0xfe, 0xae, 0x65, 0xe1, 0xfe, 0x36, 0x0c, 0xec, 0xef, 0x5a,
0xf0, 0x26, 0x91, 0x57, 0xc7, 0x5c, 0x32, 0xbc, 0xbf, 0x7d, 0x26, 0xdc, 0xdf, 0x2d, 0xd6, 0xe6,
0xe3, 0xae, 0xc3, 0xf1, 0xe2, 0xa2, 0x9c, 0x16, 0xc9, 0x05, 0x1f, 0x04, 0xac, 0x18, 0x88, 0xc8,
0xc7, 0x49, 0x58, 0xfb, 0xfc, 0xf9, 0x5a, 0x74, 0xb7, 0xe9, 0x76, 0x51, 0x96, 0x7a, 0xed, 0xf3,
0xdd, 0x7f, 0x86, 0xf7, 0x2f, 0x81, 0x13, 0x07, 0xf2, 0x3d, 0xd4, 0x9c, 0xdc, 0x00, 0x2f, 0xd2,
0x79, 0x56, 0x9a, 0x42, 0x7d, 0xd1, 0xc7, 0xba, 0xa3, 0x40, 0xe4, 0x06, 0xbd, 0x14, 0x6d, 0x5a,
0xa6, 0xfb, 0xa7, 0x91, 0x1d, 0xc6, 0x25, 0x48, 0xcb, 0x9a, 0xf6, 0x76, 0x08, 0x22, 0x2d, 0xc3,
0x49, 0x38, 0x14, 0x0e, 0x0a, 0xb1, 0xc8, 0xcb, 0x8e, 0xa1, 0x00, 0xa0, 0xf0, 0x50, 0x68, 0xc3,
0xda, 0xe7, 0xdb, 0xe8, 0x77, 0xdd, 0xe1, 0xe7, 0x36, 0xf6, 0x36, 0x3d, 0xa6, 0xb0, 0x26, 0x1e,
0xf6, 0xc5, 0x6d, 0x46, 0xd1, 0x78, 0x96, 0x7b, 0x5c, 0xb2, 0x24, 0x2d, 0x07, 0xeb, 0xb8, 0x8d,
0x46, 0x4e, 0x64, 0x14, 0x18, 0x07, 0xe3, 0xdb, 0xde, 0x22, 0x4f, 0x93, 0x69, 0xfb, 0x71, 0x88,
0xd6, 0x35, 0xe2, 0x70, 0x7c, 0x73, 0x31, 0x18, 0xaf, 0xab, 0xd4, 0x4f, 0xfd, 0x67, 0xb2, 0xca,
0x39, 0x1e, 0xaf, 0x3d, 0x24, 0x1c, 0xaf, 0x21, 0x0a, 0xeb, 0x33, 0xe6, 0xf2, 0x88, 0xad, 0xc4,
0x82, 0x88, 0xd7, 0x46, 0x1c, 0xae, 0x8f, 0x8b, 0xd9, 0xbd, 0x81, 0xf1, 0x70, 0x98, 0x49, 0x5e,
0x64, 0x2c, 0xdd, 0x4f, 0xd9, 0xac, 0x1c, 0x10, 0x31, 0xc6, 0xa7, 0x88, 0xbd, 0x01, 0x4d, 0x23,
0xcd, 0x78, 0x58, 0xee, 0xb3, 0xa5, 0x28, 0x12, 0x49, 0x37, 0xa3, 0x45, 0x3a, 0x9b, 0xd1, 0x43,
0x51, 0x6f, 0xa3, 0x62, 0x7a, 0x95, 0x2c, 0x79, 0x1c, 0xf0, 0xd6, 0x20, 0x3d, 0xbc, 0x39, 0x28,
0xd2, 0x69, 0x63, 0xb1, 0x28, 0xa6, 0x9c, 0xec, 0xb4, 0x5a, 0xdc, 0xd9, 0x69, 0x06, 0xd3, 0x1e,
0xfe, 0x7a, 0x2d, 0xfa, 0xbd, 0x5a, 0xea, 0x3e, 0xa3, 0xd8, 0x63, 0xe5, 0xd5, 0x85, 0x60, 0x45,
0x3c, 0xf8, 0x04, 0xb3, 0x83, 0xa2, 0xc6, 0xf5, 0xb3, 0xdb, 0xa8, 0xc0, 0x66, 0xad, 0xf2, 0x6e,
0x3b, 0xe3, 0xd0, 0x66, 0xf5, 0x90, 0x70, 0xb3, 0x42, 0x14, 0x06, 0x10, 0x25, 0xaf, 0x8f, 0xe4,
0xd6, 0x49, 0x7d, 0xff, 0x5c, 0x6e, 0xa3, 0x93, 0x83, 0xf1, 0xb1, 0x12, 0xfa, 0xa3, 0x65, 0x9b,
0xb2, 0x81, 0x8f, 0x98, 0x61, 0x5f, 0x9c, 0xf4, 0x6c, 0x66, 0x45, 0xd8, 0x73, 0x6b, 0x66, 0x0c,
0xfb, 0xe2, 0x84, 0x67, 0x27, 0xac, 0x85, 0x3c, 0x23, 0xa1, 0x6d, 0xd8, 0x17, 0x87, 0xd9, 0x97,
0x66, 0x9a, 0x75, 0xe1, 0x49, 0xc0, 0x0e, 0x5c, 0x1b, 0x36, 0x7b, 0xb1, 0xda, 0xe1, 0xdf, 0xae,
0x45, 0xdf, 0xb3, 0x1e, 0x8f, 0x45, 0x9c, 0x5c, 0xae, 0x6a, 0xe8, 0x35, 0x4b, 0x17, 0xbc, 0x1c,
0x3c, 0xa3, 0xac, 0xb5, 0x59, 0x53, 0x82, 0xe7, 0xb7, 0xd2, 0x81, 0x73, 0x67, 0x94, 0xe7, 0xe9,
0x6a, 0xc2, 0xe7, 0x79, 0x4a, 0xce, 0x1d, 0x0f, 0x09, 0xcf, 0x1d, 0x88, 0xc2, 0xac, 0x7c, 0x22,
0xaa, 0x9c, 0x1f, 0xcd, 0xca, 0x95, 0x28, 0x9c, 0x95, 0x37, 0x08, 0xcc, 0x95, 0x26, 0x62, 0x57,
0xa4, 0x29, 0x9f, 0xca, 0xf6, 0x3d, 0x07, 0xa3, 0x69, 0x89, 0x70, 0xae, 0x04, 0x48, 0x7b, 0x2a,
0xd7, 0xec, 0x21, 0x59, 0xc1, 0x5f, 0xac, 0x8e, 0x92, 0xec, 0x7a, 0x80, 0xa7, 0x05, 0x16, 0x20,
0x4e, 0xe5, 0x50, 0x10, 0xee, 0x55, 0xcf, 0xb3, 0x58, 0xe0, 0x7b, 0xd5, 0x4a, 0x12, 0xde, 0xab,
0x6a, 0x02, 0x9a, 0x3c, 0xe3, 0x94, 0xc9, 0x4a, 0x12, 0x36, 0xa9, 0x09, 0x2c, 0x14, 0xea, 0x67,
0x37, 0x64, 0x28, 0x04, 0x4f, 0x6b, 0x36, 0x3a, 0x39, 0x38, 0x42, 0x9b, 0x4d, 0xeb, 0x3e, 0x97,
0xd3, 0x2b, 0x7c, 0x84, 0x7a, 0x48, 0x78, 0x84, 0x42, 0x14, 0x56, 0x69, 0x22, 0xcc, 0xa6, 0x7b,
0x1d, 0x1f, 0x1f, 0xad, 0x0d, 0xf7, 0x46, 0x27, 0x07, 0xb7, 0x91, 0x87, 0x73, 0xd5, 0x66, 0xe8,
0x20, 0xaf, 0x65, 0xe1, 0x6d, 0xa4, 0x61, 0x60, 0xe9, 0x6b, 0x81, 0x3a, 0xcb, 0x5a, 0xa7, 0x15,
0xbd, 0xd3, 0xac, 0x8d, 0x4e, 0x4e, 0x3b, 0xf9, 0x57, 0xb3, 0x8d, 0xab, 0xa5, 0x27, 0xa2, 0x9a,
0x23, 0xaf, 0x59, 0x9a, 0xc4, 0x4c, 0xf2, 0x89, 0xb8, 0xe6, 0x19, 0xbe, 0x63, 0xd2, 0xa5, 0xad,
0xf9, 0xa1, 0xa7, 0x10, 0xde, 0x31, 0x85, 0x15, 0xe1, 0x38, 0xa9, 0xe9, 0xf3, 0x92, 0xef, 0xb2,
0x92, 0x88, 0x64, 0x1e, 0x12, 0x1e, 0x27, 0x10, 0x85, 0xf9, 0x6a, 0x2d, 0x7f, 0xf9, 0x36, 0xe7,
0x45, 0xc2, 0xb3, 0x29, 0xc7, 0xf3, 0x55, 0x48, 0x85, 0xf3, 0x55, 0x84, 0x86, 0x7b, 0xb5, 0x3d,
0x26, 0xf9, 0x8b, 0xd5, 0x24, 0x99, 0xf3, 0x52, 0xb2, 0x79, 0x8e, 0xef, 0xd5, 0x00, 0x14, 0xde,
0xab, 0xb5, 0xe1, 0xd6, 0xd1, 0x90, 0x09, 0x88, 0xed, 0xeb, 0x51, 0x90, 0x08, 0x5c, 0x8f, 0x22,
0x50, 0xd8, 0xb0, 0x16, 0x40, 0x1f, 0x12, 0xb4, 0xac, 0x04, 0x1f, 0x12, 0xd0, 0x74, 0xeb, 0xc0,
0xcd, 0x30, 0xe3, 0x6a, 0x6a, 0x76, 0x14, 0x7d, 0xec, 0x4e, 0xd1, 0xcd, 0x5e, 0x2c, 0x7e, 0xc2,
0x77, 0xc6, 0x53, 0xa6, 0x96, 0xad, 0xc0, 0x31, 0x5a, 0xc3, 0xf4, 0x39, 0xe1, 0x73, 0x58, 0xed,
0xf0, 0x2f, 0xd7, 0xa2, 0x0f, 0x31, 0x8f, 0xaf, 0x72, 0xe5, 0xf7, 0x69, 0xb7, 0xad, 0x9a, 0x24,
0xee, 0x7f, 0x85, 0x35, 0xec, 0x95, 0x8c, 0x46, 0x64, 0xaf, 0x87, 0xe9, 0x02, 0xf8, 0x49, 0x9b,
0x29, 0x3f, 0xe4, 0x88, 0x2b, 0x19, 0x21, 0xde, 0xee, 0x87, 0xfc, 0x72, 0x95, 0x60, 0x3f, 0x64,
0x6c, 0x68, 0x31, 0xb1, 0x1f, 0x42, 0x30, 0x3b, 0x3b, 0xdd, 0xea, 0xbd, 0x49, 0xe4, 0x95, 0xca,
0xb7, 0xc0, 0xec, 0xf4, 0xca, 0x6a, 0x20, 0x62, 0x76, 0x92, 0x30, 0xcc, 0x48, 0x1a, 0xb0, 0x9a,
0x9b, 0x58, 0x2c, 0x37, 0x86, 0xdc, 0x99, 0xf9, 0xa8, 0x1b, 0x84, 0xe3, 0xb5, 0x11, 0xeb, 0xad,
0xcf, 0x93, 0x90, 0x05, 0xb0, 0xfd, 0xd9, 0xec, 0xc5, 0x6a, 0x87, 0x7f, 0x1e, 0x7d, 0xb7, 0x55,
0xb1, 0x7d, 0xce, 0xe4, 0xa2, 0xe0, 0xf1, 0x60, 0xa7, 0xa3, 0xdc, 0x0d, 0x68, 0x5c, 0x3f, 0xed,
0xaf, 0xd0, 0xca, 0xd1, 0x1b, 0xae, 0x1e, 0x56, 0xa6, 0x0c, 0xcf, 0x42, 0x26, 0x7d, 0x36, 0x98,
0xa3, 0xd3, 0x3a, 0xad, 0x6d, 0xb6, 0x3b, 0xba, 0x46, 0x4b, 0x96, 0xa4, 0xea, 0x61, 0xed, 0x27,
0x21, 0xa3, 0x1e, 0x1a, 0xdc, 0x66, 0x93, 0x2a, 0xad, 0xc8, 0xac, 0xe6, 0xb8, 0xb3, 0x3d, 0xdb,
0xa2, 0x23, 0x01, 0xb2, 0x3b, 0xdb, 0xee, 0x49, 0x6b, 0xb7, 0xb2, 0x59, 0xf2, 0xaa, 0x3f, 0xbb,
0x83, 0x1c, 0xf3, 0xaa, 0x55, 0x91, 0x91, 0xbe, 0xdd, 0x93, 0xd6, 0x5e, 0xff, 0x2c, 0xfa, 0xa0,
0xed, 0x55, 0x2f, 0x44, 0x3b, 0x9d, 0xa6, 0xc0, 0x5a, 0xf4, 0xb4, 0xbf, 0x82, 0xdd, 0xd2, 0x7c,
0x99, 0x94, 0x52, 0x14, 0xab, 0xf1, 0x95, 0xb8, 0x69, 0x5e, 0xbb, 0xf0, 0x67, 0xab, 0x06, 0x86,
0x0e, 0x41, 0x6c, 0x69, 0x70, 0xb2, 0xe5, 0xca, 0xbe, 0x9e, 0x51, 0x12, 0xae, 0x1c, 0xa2, 0xc3,
0x95, 0x4f, 0xda, 0x58, 0xd5, 0xd4, 0xca, 0xbe, 0x4b, 0xb2, 0x81, 0x17, 0xb5, 0xfd, 0x3e, 0xc9,
0xa3, 0x6e, 0xd0, 0x66, 0x2c, 0x5a, 0xbc, 0x97, 0x5c, 0x5e, 0x9a, 0x3a, 0xe1, 0x25, 0x75, 0x11,
0x22, 0x63, 0x21, 0x50, 0x9b, 0x74, 0xef, 0x27, 0x29, 0x57, 0x27, 0xfa, 0xaf, 0x2e, 0x2f, 0x53,
0xc1, 0x62, 0x90, 0x74, 0x57, 0xe2, 0xa1, 0x2b, 0x27, 0x92, 0x6e, 0x8c, 0xb3, 0x77, 0x05, 0x2a,
0xe9, 0x19, 0x9f, 0x8a, 0x6c, 0x9a, 0xa4, 0xf0, 0x16, 0xaa, 0xd2, 0x34, 0x42, 0xe2, 0xae, 0x40,
0x0b, 0xb2, 0x0b, 0x63, 0x25, 0xaa, 0xa6, 0x7d, 0x53, 0xfe, 0x87, 0x6d, 0x45, 0x47, 0x4c, 0x2c,
0x8c, 0x08, 0x66, 0xf7, 0x9e, 0x95, 0xf0, 0x3c, 0x57, 0xc6, 0xef, 0xb5, 0xb5, 0x6a, 0x09, 0xb1,
0xf7, 0xf4, 0x09, 0xbb, 0x87, 0xaa, 0xfe, 0xbe, 0x27, 0x6e, 0x32, 0x65, 0xf4, 0x7e, 0x5b, 0xa5,
0x91, 0x11, 0x7b, 0x28, 0xc8, 0x68, 0xc3, 0x3f, 0x89, 0x7e, 0x55, 0x19, 0x2e, 0x44, 0x3e, 0xb8,
0x83, 0x28, 0x14, 0xce, 0x9d, 0xcd, 0xbb, 0xa4, 0xdc, 0x5e, 0x2d, 0x30, 0x63, 0xe3, 0xbc, 0x64,
0x33, 0x3e, 0x78, 0x40, 0xf4, 0xb8, 0x92, 0x12, 0x57, 0x0b, 0xda, 0x94, 0x3f, 0x2a, 0x4e, 0x44,
0xac, 0xad, 0x23, 0x35, 0x34, 0xc2, 0xd0, 0xa8, 0x70, 0x21, 0x9b, 0xcc, 0x9c, 0xb0, 0x65, 0x32,
0x33, 0x0b, 0x4e, 0x1d, 0xb7, 0x4a, 0x90, 0xcc, 0x58, 0x66, 0xe8, 0x40, 0x44, 0x32, 0x43, 0xc2,
0xda, 0xe7, 0xbf, 0xac, 0x45, 0xf7, 0x2c, 0x73, 0xd0, 0x9c, 0xd6, 0x1d, 0x66, 0x97, 0xa2, 0x4a,
0x7d, 0x8e, 0x92, 0xec, 0xba, 0x1c, 0x7c, 0x4e, 0x99, 0xc4, 0x79, 0x53, 0x94, 0x2f, 0x6e, 0xad,
0x67, 0xb3, 0xd6, 0xe6, 0x28, 0xcb, 0x3e, 0xcf, 0xae, 0x35, 0x40, 0xd6, 0x6a, 0x4e, 0xbc, 0x20,
0x47, 0x64, 0xad, 0x21, 0xde, 0x76, 0xb1, 0x71, 0x9e, 0x8a, 0x0c, 0x76, 0xb1, 0xb5, 0x50, 0x09,
0x89, 0x2e, 0x6e, 0x41, 0x36, 0x1e, 0x37, 0xa2, 0xfa, 0xd4, 0x65, 0x94, 0xa6, 0x20, 0x1e, 0x1b,
0x55, 0x03, 0x10, 0xf1, 0x18, 0x05, 0xb5, 0x9f, 0xb3, 0xe8, 0xdb, 0x55, 0x93, 0x9e, 0x16, 0x7c,
0x99, 0x70, 0x78, 0xf5, 0xc2, 0x91, 0x10, 0xf3, 0xdf, 0x27, 0xec, 0xcc, 0x3a, 0xcf, 0xca, 0x3c,
0x65, 0xe5, 0x95, 0x7e, 0x18, 0xef, 0xd7, 0xb9, 0x11, 0xc2, 0xc7, 0xf1, 0x0f, 0x3b, 0x28, 0x1b,
0xd4, 0x1b, 0x99, 0x09, 0x31, 0xeb, 0xb8, 0x6a, 0x2b, 0xcc, 0x6c, 0x74, 0x72, 0xf6, 0xc4, 0xfb,
0x80, 0xa5, 0x29, 0x2f, 0x56, 0x8d, 0xec, 0x98, 0x65, 0xc9, 0x25, 0x2f, 0x25, 0x38, 0xf1, 0xd6,
0xd4, 0x10, 0x62, 0xc4, 0x89, 0x77, 0x00, 0xb7, 0xd9, 0x3c, 0xf0, 0x7c, 0x98, 0xc5, 0xfc, 0x2d,
0xc8, 0xe6, 0xa1, 0x1d, 0xc5, 0x10, 0xd9, 0x3c, 0xc5, 0xda, 0x93, 0xdf, 0x17, 0xa9, 0x98, 0x5e,
0xeb, 0x25, 0xc0, 0xef, 0x60, 0x25, 0x81, 0x6b, 0xc0, 0xfd, 0x10, 0x62, 0x17, 0x01, 0x25, 0x38,
0xe3, 0x79, 0xca, 0xa6, 0xf0, 0xfe, 0x4d, 0xad, 0xa3, 0x65, 0xc4, 0x22, 0x00, 0x19, 0x50, 0x5c,
0x7d, 0xaf, 0x07, 0x2b, 0x2e, 0xb8, 0xd6, 0x73, 0x3f, 0x84, 0xd8, 0x65, 0x50, 0x09, 0xc6, 0x79,
0x9a, 0x48, 0x30, 0x0d, 0x6a, 0x0d, 0x25, 0x21, 0xa6, 0x81, 0x4f, 0x00, 0x93, 0xc7, 0xbc, 0x98,
0x71, 0xd4, 0xa4, 0x92, 0x04, 0x4d, 0x36, 0x84, 0xbd, 0x6c, 0x5c, 0xd7, 0x5d, 0xe4, 0x2b, 0x70,
0xd9, 0x58, 0x57, 0x4b, 0xe4, 0x2b, 0xe2, 0xb2, 0xb1, 0x07, 0x80, 0x22, 0x9e, 0xb2, 0x52, 0xe2,
0x45, 0x54, 0x92, 0x60, 0x11, 0x1b, 0xc2, 0xae, 0xd1, 0x75, 0x11, 0x17, 0x12, 0xac, 0xd1, 0xba,
0x00, 0xce, 0x13, 0xe8, 0xbb, 0xa4, 0xdc, 0x46, 0x92, 0xba, 0x57, 0xb8, 0xdc, 0x4f, 0x78, 0x1a,
0x97, 0x20, 0x92, 0xe8, 0x76, 0x6f, 0xa4, 0x44, 0x24, 0x69, 0x53, 0x60, 0x28, 0xe9, 0xf3, 0x71,
0xac, 0x76, 0xe0, 0x68, 0xfc, 0x7e, 0x08, 0xb1, 0xf1, 0xa9, 0x29, 0xf4, 0x2e, 0x2b, 0x8a, 0xa4,
0x5a, 0xfc, 0xd7, 0xf1, 0x02, 0x35, 0x72, 0x22, 0x3e, 0x61, 0x1c, 0x98, 0x5e, 0x4d, 0xe0, 0xc6,
0x0a, 0x06, 0x43, 0xf7, 0xc7, 0x41, 0xc6, 0x66, 0x9c, 0x4a, 0xe2, 0x3c, 0x42, 0xc5, 0x5a, 0x13,
0x79, 0x82, 0xba, 0xde, 0x85, 0x39, 0x6f, 0x22, 0x19, 0x17, 0xc7, 0x62, 0xc9, 0x27, 0xe2, 0xe5,
0xdb, 0xa4, 0x94, 0x49, 0x36, 0xd3, 0x2b, 0xf7, 0x73, 0xc2, 0x12, 0x06, 0x13, 0x6f, 0x22, 0x75,
0x2a, 0xd9, 0x04, 0x02, 0x94, 0xe5, 0x84, 0xdf, 0xa0, 0x09, 0x04, 0xb4, 0x68, 0x38, 0x22, 0x81,
0x08, 0xf1, 0xf6, 0x1c, 0xc5, 0x38, 0xd7, 0xaf, 0x6b, 0x4f, 0x44, 0x93, 0xcb, 0x51, 0xd6, 0x20,
0x48, 0x6c, 0x65, 0x83, 0x0a, 0x76, 0x7f, 0x69, 0xfc, 0xdb, 0x29, 0xf6, 0x88, 0xb0, 0xd3, 0x9e,
0x66, 0x8f, 0x7b, 0x90, 0x88, 0x2b, 0x7b, 0x0f, 0x80, 0x72, 0xd5, 0xbe, 0x06, 0xf0, 0xb8, 0x07,
0xe9, 0x9c, 0xc9, 0xb8, 0xd5, 0x7a, 0xc1, 0xa6, 0xd7, 0xb3, 0x42, 0x2c, 0xb2, 0x78, 0x57, 0xa4,
0xa2, 0x00, 0x67, 0x32, 0x5e, 0xa9, 0x01, 0x4a, 0x9c, 0xc9, 0x74, 0xa8, 0xd8, 0x0c, 0xce, 0x2d,
0xc5, 0x28, 0x4d, 0x66, 0x70, 0x47, 0xed, 0x19, 0x52, 0x00, 0x91, 0xc1, 0xa1, 0x20, 0x32, 0x88,
0xea, 0x1d, 0xb7, 0x4c, 0xa6, 0x2c, 0xad, 0xfd, 0xed, 0xd0, 0x66, 0x3c, 0xb0, 0x73, 0x10, 0x21,
0x0a, 0x48, 0x3d, 0x27, 0x8b, 0x22, 0x3b, 0xcc, 0xa4, 0x20, 0xeb, 0xd9, 0x00, 0x9d, 0xf5, 0x74,
0x40, 0x10, 0x56, 0x27, 0xfc, 0x6d, 0x55, 0x9a, 0xea, 0x1f, 0x2c, 0xac, 0x56, 0x7f, 0x1f, 0x6a,
0x79, 0x28, 0xac, 0x02, 0x0e, 0x54, 0x46, 0x3b, 0xa9, 0x07, 0x4c, 0x40, 0xdb, 0x1f, 0x26, 0x8f,
0xba, 0x41, 0xdc, 0xcf, 0x58, 0xae, 0x52, 0x1e, 0xf2, 0xa3, 0x80, 0x3e, 0x7e, 0x1a, 0xd0, 0x1e,
0xb7, 0x78, 0xf5, 0xb9, 0xe2, 0xd3, 0xeb, 0xd6, 0xb5, 0x26, 0xbf, 0xa0, 0x35, 0x42, 0x1c, 0xb7,
0x10, 0x28, 0xde, 0x45, 0x87, 0x53, 0x91, 0x85, 0xba, 0xa8, 0x92, 0xf7, 0xe9, 0x22, 0xcd, 0xd9,
0xcd, 0xaf, 0x91, 0xea, 0x91, 0x59, 0x77, 0xd3, 0x26, 0x61, 0xc1, 0x85, 0x88, 0xcd, 0x2f, 0x09,
0xdb, 0x9c, 0x1c, 0xfa, 0x3c, 0x6e, 0xdf, 0xf9, 0x6e, 0x59, 0x39, 0xa6, 0xef, 0x7c, 0x53, 0x2c,
0x5d, 0xc9, 0x7a, 0x8c, 0x74, 0x58, 0xf1, 0xc7, 0xc9, 0x56, 0x3f, 0xd8, 0x6e, 0x79, 0x3c, 0x9f,
0xbb, 0x29, 0x67, 0x45, 0xed, 0x75, 0x3b, 0x60, 0xc8, 0x62, 0xc4, 0x96, 0x27, 0x80, 0x83, 0x10,
0xe6, 0x79, 0xde, 0x15, 0x99, 0xe4, 0x99, 0xc4, 0x42, 0x98, 0x6f, 0x4c, 0x83, 0xa1, 0x10, 0x46,
0x29, 0x80, 0x71, 0xab, 0xce, 0x83, 0xb8, 0x3c, 0x61, 0x73, 0x34, 0x63, 0xab, 0xcf, 0x7a, 0x6a,
0x79, 0x68, 0xdc, 0x02, 0xce, 0x79, 0xc8, 0xe7, 0x7a, 0x99, 0xb0, 0x62, 0x66, 0x4e, 0x37, 0xe2,
0xc1, 0x53, 0xda, 0x8e, 0x4f, 0x12, 0x0f, 0xf9, 0xc2, 0x1a, 0x20, 0xec, 0x1c, 0xce, 0xd9, 0xcc,
0xd4, 0x14, 0xa9, 0x81, 0x92, 0xb7, 0xaa, 0xfa, 0xa8, 0x1b, 0x04, 0x7e, 0x5e, 0x27, 0x31, 0x17,
0x01, 0x3f, 0x4a, 0xde, 0xc7, 0x0f, 0x04, 0x41, 0xf6, 0x56, 0xd5, 0xbb, 0xde, 0xd1, 0x8d, 0xb2,
0x58, 0xef, 0x63, 0x87, 0x44, 0xf3, 0x00, 0x2e, 0x94, 0xbd, 0x11, 0x3c, 0x98, 0xa3, 0xcd, 0x01,
0x6d, 0x68, 0x8e, 0x9a, 0xf3, 0xd7, 0x3e, 0x73, 0x14, 0x83, 0xb5, 0xcf, 0x9f, 0xe9, 0x39, 0xba,
0xc7, 0x24, 0xab, 0xf2, 0xf6, 0xd7, 0x09, 0xbf, 0xd1, 0x1b, 0x61, 0xa4, 0xbe, 0x0d, 0x35, 0x54,
0xaf, 0xac, 0x82, 0x5d, 0xf1, 0x4e, 0x6f, 0x3e, 0xe0, 0x5b, 0xef, 0x10, 0x3a, 0x7d, 0x83, 0xad,
0xc2, 0x4e, 0x6f, 0x3e, 0xe0, 0x5b, 0xbf, 0x0b, 0xdf, 0xe9, 0x1b, 0xbc, 0x10, 0xbf, 0xd3, 0x9b,
0xd7, 0xbe, 0xff, 0xaa, 0x99, 0xb8, 0xae, 0xf3, 0x2a, 0x0f, 0x9b, 0xca, 0x64, 0xc9, 0xb1, 0x74,
0xd2, 0xb7, 0x67, 0xd0, 0x50, 0x3a, 0x49, 0xab, 0x38, 0x5f, 0x6f, 0xc2, 0x4a, 0x71, 0x2a, 0xca,
0x44, 0x3d, 0xa4, 0x7f, 0xde, 0xc3, 0x68, 0x03, 0x87, 0x36, 0x4d, 0x21, 0x25, 0xfb, 0xb8, 0xd1,
0x43, 0xed, 0x2d, 0xe6, 0xad, 0x80, 0xbd, 0xf6, 0x65, 0xe6, 0xed, 0x9e, 0xb4, 0x7d, 0xf0, 0xe7,
0x31, 0xee, 0x13, 0xc7, 0x50, 0xaf, 0xa2, 0x0f, 0x1d, 0x9f, 0xf6, 0x57, 0xd0, 0xee, 0xff, 0xa6,
0xd9, 0x57, 0x40, 0xff, 0x7a, 0x12, 0x3c, 0xeb, 0x63, 0x11, 0x4c, 0x84, 0xe7, 0xb7, 0xd2, 0xd1,
0x05, 0xf9, 0x87, 0x66, 0x03, 0xdd, 0xa0, 0xea, 0x5d, 0x0e, 0xf5, 0x0e, 0xa8, 0x9e, 0x13, 0xa1,
0x6e, 0xb5, 0x30, 0x9c, 0x19, 0x9f, 0xdd, 0x52, 0xcb, 0xf9, 0x96, 0x97, 0x07, 0xeb, 0x77, 0x0e,
0x9d, 0xf2, 0x84, 0x2c, 0x3b, 0x34, 0x2c, 0xd0, 0xe7, 0xb7, 0x55, 0xa3, 0xe6, 0x8a, 0x03, 0xab,
0xaf, 0x73, 0x3c, 0xef, 0x69, 0xd8, 0xfb, 0x5e, 0xc7, 0xa7, 0xb7, 0x53, 0xd2, 0x65, 0xf9, 0xcf,
0xb5, 0xe8, 0xa1, 0xc7, 0xda, 0xe7, 0x09, 0xe0, 0xd4, 0xe3, 0x47, 0x01, 0xfb, 0x94, 0x92, 0x29,
0xdc, 0xef, 0xff, 0x72, 0xca, 0xf6, 0xc3, 0x57, 0x9e, 0xca, 0x7e, 0x92, 0x4a, 0x5e, 0xb4, 0x3f,
0x7c, 0xe5, 0xdb, 0xad, 0xa9, 0x21, 0xfd, 0xe1, 0xab, 0x00, 0xee, 0x7c, 0xf8, 0x0a, 0xf1, 0x8c,
0x7e, 0xf8, 0x0a, 0xb5, 0x16, 0xfc, 0xf0, 0x55, 0x58, 0x83, 0x0a, 0xef, 0x4d, 0x11, 0xea, 0x73,
0xeb, 0x5e, 0x16, 0xfd, 0x63, 0xec, 0x67, 0xb7, 0x51, 0x21, 0x16, 0xb8, 0x9a, 0x53, 0xf7, 0xdc,
0x7a, 0xb4, 0xa9, 0x77, 0xd7, 0x6d, 0xa7, 0x37, 0xaf, 0x7d, 0xff, 0x54, 0xef, 0x6e, 0x4c, 0x38,
0x17, 0x85, 0xfa, 0xe8, 0xd9, 0x66, 0x28, 0x3c, 0x57, 0x16, 0xdc, 0x9e, 0xdf, 0xea, 0x07, 0x13,
0xd5, 0xad, 0x08, 0xdd, 0xe9, 0xc3, 0x2e, 0x43, 0xa0, 0xcb, 0x77, 0x7a, 0xf3, 0xc4, 0x32, 0x52,
0xfb, 0xae, 0x7b, 0xbb, 0x87, 0x31, 0xbf, 0xaf, 0x9f, 0xf6, 0x57, 0xd0, 0xee, 0x97, 0x3a, 0x6d,
0x74, 0xdd, 0xab, 0x7e, 0xde, 0xee, 0x32, 0x35, 0xf6, 0xba, 0x79, 0xd8, 0x17, 0x0f, 0x25, 0x10,
0xee, 0x12, 0xda, 0x95, 0x40, 0xa0, 0xcb, 0xe8, 0xa7, 0xb7, 0x53, 0xd2, 0x65, 0xf9, 0xe7, 0xb5,
0xe8, 0x2e, 0x59, 0x16, 0x3d, 0x0e, 0x3e, 0xef, 0x6b, 0x19, 0x8c, 0x87, 0x2f, 0x6e, 0xad, 0xa7,
0x0b, 0xf5, 0x6f, 0x6b, 0xd1, 0xbd, 0x40, 0xa1, 0xea, 0x01, 0x72, 0x0b, 0xeb, 0xfe, 0x40, 0xf9,
0xc1, 0xed, 0x15, 0xa9, 0xe5, 0xde, 0xc5, 0xc7, 0xed, 0x8f, 0x32, 0x05, 0x6c, 0x8f, 0xe9, 0x8f,
0x32, 0x75, 0x6b, 0xc1, 0x43, 0x1e, 0x76, 0xd1, 0x6c, 0xba, 0xd0, 0x43, 0x1e, 0x75, 0x43, 0x2d,
0xf8, 0x71, 0x09, 0x8c, 0xc3, 0x9c, 0xbc, 0x7c, 0x9b, 0xb3, 0x2c, 0xa6, 0x9d, 0xd4, 0xf2, 0x6e,
0x27, 0x86, 0x83, 0x87, 0x63, 0x95, 0xf4, 0x4c, 0x34, 0x1b, 0xa9, 0xc7, 0x94, 0xbe, 0x41, 0x82,
0x87, 0x63, 0x2d, 0x94, 0xf0, 0xa6, 0xb3, 0xc6, 0x90, 0x37, 0x90, 0x2c, 0x3e, 0xe9, 0x83, 0x82,
0x14, 0xdd, 0x78, 0x33, 0x67, 0xee, 0x5b, 0x21, 0x2b, 0xad, 0x73, 0xf7, 0xed, 0x9e, 0x34, 0xe1,
0x76, 0xcc, 0xe5, 0x97, 0x9c, 0xc5, 0xbc, 0x08, 0xba, 0x35, 0x54, 0x2f, 0xb7, 0x2e, 0x8d, 0xb9,
0xdd, 0x15, 0xe9, 0x62, 0x9e, 0xe9, 0xce, 0x24, 0xdd, 0xba, 0x54, 0xb7, 0x5b, 0x40, 0xc3, 0x63,
0x41, 0xeb, 0x56, 0xa5, 0x97, 0x4f, 0xc2, 0x66, 0xbc, 0xac, 0x72, 0xb3, 0x17, 0x4b, 0xd7, 0x53,
0x0f, 0xa3, 0x8e, 0x7a, 0x82, 0x91, 0xb4, 0xdd, 0x93, 0x86, 0xe7, 0x73, 0x8e, 0x5b, 0x33, 0x9e,
0x76, 0x3a, 0x6c, 0xb5, 0x86, 0xd4, 0xd3, 0xfe, 0x0a, 0xf0, 0x34, 0x54, 0x8f, 0xaa, 0xa3, 0xa4,
0x94, 0xfb, 0x49, 0x9a, 0x0e, 0x36, 0x03, 0xc3, 0xa4, 0x81, 0x82, 0xa7, 0xa1, 0x08, 0x4c, 0x8c,
0xe4, 0xe6, 0xf4, 0x30, 0x1b, 0x74, 0xd9, 0x51, 0x54, 0xaf, 0x91, 0xec, 0xd2, 0xe0, 0x44, 0xcb,
0x69, 0x6a, 0x53, 0xdb, 0x61, 0xb8, 0xe1, 0x5a, 0x15, 0xde, 0xe9, 0xcd, 0x83, 0xc7, 0xed, 0x8a,
0x52, 0x2b, 0xcb, 0x03, 0xca, 0x84, 0xb7, 0x92, 0x3c, 0xec, 0xa0, 0xc0, 0xa9, 0x60, 0x3d, 0x8d,
0xde, 0x24, 0xf1, 0x8c, 0x4b, 0xf4, 0x49, 0x91, 0x0b, 0x04, 0x9f, 0x14, 0x01, 0x10, 0x74, 0x5d,
0xfd, 0x77, 0x73, 0x1c, 0x7a, 0x18, 0x63, 0x5d, 0xa7, 0x95, 0x1d, 0x2a, 0xd4, 0x75, 0x28, 0x0d,
0xa2, 0x81, 0x71, 0xab, 0x5f, 0xc7, 0x7f, 0x12, 0x32, 0x03, 0xde, 0xc9, 0xdf, 0xec, 0xc5, 0x82,
0x15, 0xc5, 0x3a, 0x4c, 0xe6, 0x89, 0xc4, 0x56, 0x14, 0xc7, 0x46, 0x85, 0x84, 0x56, 0x94, 0x36,
0x4a, 0x55, 0xaf, 0xca, 0x11, 0x0e, 0xe3, 0x70, 0xf5, 0x6a, 0xa6, 0x5f, 0xf5, 0x0c, 0xdb, 0x7a,
0xb0, 0x99, 0x99, 0x21, 0x23, 0xaf, 0xf4, 0x66, 0x19, 0x19, 0xdb, 0xea, 0x35, 0x4d, 0x08, 0x86,
0xa2, 0x0e, 0xa5, 0x00, 0x0f, 0xec, 0x2b, 0xae, 0x79, 0xf6, 0x9a, 0xe7, 0x9c, 0x15, 0x2c, 0x9b,
0xa2, 0x9b, 0x53, 0x65, 0xb0, 0x45, 0x86, 0x36, 0xa7, 0xa4, 0x06, 0x78, 0x6c, 0xee, 0xbf, 0x60,
0x89, 0x4c, 0x05, 0xf3, 0x26, 0xa3, 0xff, 0x7e, 0xe5, 0xe3, 0x1e, 0x24, 0x7c, 0x6c, 0xde, 0x00,
0xe6, 0xe0, 0xbb, 0x76, 0xfa, 0x49, 0xc0, 0x94, 0x8f, 0x86, 0x36, 0xc2, 0xb4, 0x0a, 0x18, 0xd4,
0x26, 0xc1, 0xe5, 0xf2, 0x27, 0x7c, 0x85, 0x0d, 0x6a, 0x9b, 0x9f, 0x2a, 0x24, 0x34, 0xa8, 0xdb,
0x28, 0xc8, 0x33, 0xdd, 0x7d, 0xd0, 0x7a, 0x40, 0xdf, 0xdd, 0xfa, 0x6c, 0x74, 0x72, 0x60, 0xe6,
0xec, 0x25, 0x4b, 0xef, 0x39, 0x01, 0x52, 0xd0, 0xbd, 0x64, 0x89, 0x3f, 0x26, 0xd8, 0xec, 0xc5,
0xc2, 0x47, 0xf2, 0x4c, 0xf2, 0xb7, 0xcd, 0xb3, 0x72, 0xa4, 0xb8, 0x4a, 0xde, 0x7a, 0x58, 0xfe,
0xa8, 0x1b, 0xb4, 0x17, 0x60, 0x4f, 0x0b, 0x31, 0xe5, 0x65, 0xa9, 0xbf, 0x54, 0xe9, 0xdf, 0x30,
0xd2, 0xb2, 0x21, 0xf8, 0x4e, 0xe5, 0x83, 0x30, 0xe4, 0x7c, 0x5e, 0xae, 0x16, 0xd9, 0xaf, 0xde,
0xac, 0xa3, 0x9a, 0xed, 0x0f, 0xde, 0x6c, 0x74, 0x72, 0x76, 0x7a, 0x69, 0xa9, 0xfb, 0x99, 0x9b,
0x47, 0xa8, 0x3a, 0xf6, 0x85, 0x9b, 0xc7, 0x3d, 0x48, 0xed, 0xea, 0xcb, 0xe8, 0x9d, 0x23, 0x31,
0x1b, 0xf3, 0x2c, 0x1e, 0x7c, 0xdf, 0xbf, 0x42, 0x2b, 0x66, 0xc3, 0xea, 0xcf, 0xc6, 0xe8, 0x1d,
0x4a, 0x6c, 0x2f, 0x01, 0xee, 0xf1, 0x8b, 0xc5, 0x6c, 0x2c, 0x99, 0x04, 0x97, 0x00, 0xd5, 0xdf,
0x87, 0x95, 0x80, 0xb8, 0x04, 0xe8, 0x01, 0xc0, 0xde, 0xa4, 0xe0, 0x1c, 0xb5, 0x57, 0x09, 0x82,
0xf6, 0x34, 0x60, 0xb3, 0x08, 0x63, 0xaf, 0x4a, 0xd4, 0xe1, 0xa5, 0x3d, 0xab, 0xa3, 0xa4, 0x44,
0x16, 0xd1, 0xa6, 0xec, 0xe0, 0xae, 0xab, 0xaf, 0xbe, 0x3a, 0xb2, 0x98, 0xcf, 0x59, 0xb1, 0x02,
0x83, 0x5b, 0xd7, 0xd2, 0x01, 0x88, 0xc1, 0x8d, 0x82, 0x76, 0xd6, 0x36, 0xcd, 0x3c, 0xbd, 0x3e,
0x10, 0x85, 0x58, 0xc8, 0x24, 0xe3, 0xf0, 0xcb, 0x13, 0xa6, 0x41, 0x5d, 0x86, 0x98, 0xb5, 0x14,
0x6b, 0xb3, 0x5c, 0x45, 0xd4, 0xf7, 0x09, 0xd5, 0xc7, 0xb3, 0x4b, 0x29, 0x0a, 0xf8, 0x3c, 0xb1,
0xb6, 0x02, 0x21, 0x22, 0xcb, 0x25, 0x61, 0xd0, 0xf7, 0xa7, 0x49, 0x36, 0x43, 0xfb, 0xfe, 0xd4,
0xfd, 0xfa, 0xeb, 0x3d, 0x1a, 0xb0, 0x13, 0xaa, 0x6e, 0xb4, 0x7a, 0x02, 0xe8, 0x77, 0x39, 0xd1,
0x46, 0x77, 0x09, 0x62, 0x42, 0xe1, 0x24, 0x70, 0xf5, 0x2a, 0xe7, 0x19, 0x8f, 0x9b, 0x5b, 0x73,
0x98, 0x2b, 0x8f, 0x08, 0xba, 0x82, 0xa4, 0x8d, 0x45, 0x4a, 0x7e, 0xb6, 0xc8, 0x4e, 0x0b, 0x71,
0x99, 0xa4, 0xbc, 0x00, 0xb1, 0xa8, 0x56, 0x77, 0xe4, 0x44, 0x2c, 0xc2, 0x38, 0x7b, 0xfd, 0x42,
0x49, 0xbd, 0x2f, 0xc0, 0x4f, 0x0a, 0x36, 0x85, 0xd7, 0x2f, 0x6a, 0x1b, 0x6d, 0x8c, 0x38, 0x19,
0x0c, 0xe0, 0x4e, 0xa2, 0x53, 0xbb, 0xce, 0x56, 0x6a, 0x7c, 0xe8, 0x77, 0x09, 0xd5, 0x37, 0x51,
0x4b, 0x90, 0xe8, 0x68, 0x73, 0x18, 0x49, 0x24, 0x3a, 0x61, 0x0d, 0xbb, 0x94, 0x28, 0xee, 0x44,
0x5f, 0x2b, 0x02, 0x4b, 0x49, 0x6d, 0xa3, 0x11, 0x12, 0x4b, 0x49, 0x0b, 0x02, 0x01, 0xa9, 0x99,
0x06, 0x33, 0x34, 0x20, 0x19, 0x69, 0x30, 0x20, 0xb9, 0x94, 0x0d, 0x14, 0x87, 0x59, 0x22, 0x13,
0x96, 0x8e, 0xb9, 0x3c, 0x65, 0x05, 0x9b, 0x73, 0xc9, 0x0b, 0x18, 0x28, 0x34, 0x32, 0xf4, 0x18,
0x22, 0x50, 0x50, 0xac, 0x76, 0xf8, 0x07, 0xd1, 0x7b, 0xd5, 0xba, 0xcf, 0x33, 0xfd, 0x5b, 0x2f,
0x2f, 0xd5, 0x8f, 0x44, 0x0d, 0xde, 0x37, 0x36, 0xc6, 0xb2, 0xe0, 0x6c, 0xde, 0xd8, 0x7e, 0xd7,
0xfc, 0x5d, 0x81, 0x4f, 0xd7, 0xaa, 0xf1, 0x7c, 0x22, 0x64, 0x72, 0x59, 0x6d, 0xb3, 0xf5, 0x1b,
0x44, 0x60, 0x3c, 0xbb, 0xe2, 0x61, 0xe0, 0x5b, 0x14, 0x18, 0x67, 0xe3, 0xb4, 0x2b, 0x3d, 0xe3,
0x79, 0x0a, 0xe3, 0xb4, 0xa7, 0xad, 0x00, 0x22, 0x4e, 0xa3, 0xa0, 0x9d, 0x9c, 0xae, 0x78, 0xc2,
0xc3, 0x95, 0x99, 0xf0, 0x7e, 0x95, 0x99, 0x78, 0x2f, 0x65, 0xa4, 0xd1, 0x7b, 0xc7, 0x7c, 0x7e,
0xc1, 0x8b, 0xf2, 0x2a, 0xc9, 0xa9, 0xef, 0xb6, 0x5a, 0xa2, 0xf3, 0xbb, 0xad, 0x04, 0x6a, 0x57,
0x02, 0x0b, 0x1c, 0x96, 0x27, 0x6c, 0xce, 0xd5, 0x97, 0x35, 0xc0, 0x4a, 0xe0, 0x18, 0x71, 0x20,
0x62, 0x25, 0x20, 0x61, 0xe7, 0xfd, 0x2e, 0xcb, 0x9c, 0xf1, 0x59, 0x35, 0xc2, 0x8a, 0x53, 0xb6,
0x9a, 0xf3, 0x4c, 0x6a, 0x93, 0xe0, 0x4c, 0xde, 0x31, 0x89, 0xf3, 0xc4, 0x99, 0x7c, 0x1f, 0x3d,
0x27, 0x34, 0x79, 0x0d, 0x7f, 0x2a, 0x0a, 0x59, 0xff, 0x92, 0xd3, 0x79, 0x91, 0x82, 0xd0, 0xe4,
0x37, 0xaa, 0x47, 0x12, 0xa1, 0x29, 0xac, 0xe1, 0xfc, 0x0a, 0x81, 0x57, 0x86, 0xd7, 0xbc, 0x30,
0xe3, 0xe4, 0xe5, 0x9c, 0x25, 0xa9, 0x1e, 0x0d, 0x3f, 0x0c, 0xd8, 0x26, 0x74, 0x88, 0x5f, 0x21,
0xe8, 0xab, 0xeb, 0xfc, 0x6e, 0x43, 0xb8, 0x84, 0xe0, 0x11, 0x41, 0x87, 0x7d, 0xe2, 0x11, 0x41,
0xb7, 0x96, 0xdd, 0xb9, 0x5b, 0x56, 0x71, 0x2b, 0x45, 0xec, 0x8a, 0x18, 0x9e, 0x17, 0x3a, 0x36,
0x01, 0x48, 0xec, 0xdc, 0x83, 0x0a, 0x36, 0x35, 0xb0, 0xd8, 0x7e, 0x92, 0xb1, 0x34, 0xf9, 0x19,
0x4c, 0xeb, 0x1d, 0x3b, 0x0d, 0x41, 0xa4, 0x06, 0x38, 0x89, 0xb9, 0x3a, 0xe0, 0x72, 0x92, 0x54,
0xa1, 0xff, 0x51, 0xa0, 0xdd, 0x14, 0xd1, 0xed, 0xca, 0x21, 0x9d, 0x6f, 0xb4, 0xc2, 0x66, 0x1d,
0xe5, 0xf9, 0xb8, 0x5a, 0x55, 0xcf, 0xf8, 0x94, 0x27, 0xb9, 0x1c, 0x7c, 0x16, 0x6e, 0x2b, 0x80,
0x13, 0x17, 0x2d, 0x7a, 0xa8, 0x39, 0x8f, 0xef, 0xab, 0x58, 0x32, 0xae, 0x7f, 0xe2, 0xf0, 0xbc,
0xe4, 0x85, 0x4e, 0x34, 0x0e, 0xb8, 0x04, 0xb3, 0xd3, 0xe1, 0x86, 0x0e, 0x58, 0x55, 0x94, 0x98,
0x9d, 0x61, 0x0d, 0x7b, 0xd8, 0xe7, 0x70, 0xfa, 0x9b, 0xdb, 0xea, 0xbe, 0xe1, 0x16, 0x69, 0xcc,
0xa1, 0x88, 0xc3, 0x3e, 0x9a, 0xb6, 0xd9, 0x5a, 0xdb, 0xed, 0x28, 0x5b, 0x1d, 0xc2, 0x2b, 0x13,
0x88, 0x25, 0x85, 0x11, 0xd9, 0x5a, 0x00, 0x77, 0x0e, 0xc3, 0x0b, 0xc1, 0xe2, 0x29, 0x2b, 0xe5,
0x29, 0x5b, 0xa5, 0x82, 0xc5, 0x6a, 0x5d, 0x87, 0x87, 0xe1, 0x0d, 0x33, 0x74, 0x21, 0xea, 0x30,
0x9c, 0x82, 0xdd, 0xec, 0x4c, 0xfd, 0x72, 0xa3, 0xbe, 0xcb, 0x09, 0xb3, 0x33, 0x55, 0x5e, 0x78,
0x8f, 0xf3, 0x41, 0x18, 0xb2, 0xef, 0xa0, 0xd5, 0x22, 0x95, 0x86, 0xdc, 0xc3, 0x74, 0xbc, 0x04,
0xe4, 0xa3, 0x00, 0x61, 0xbf, 0x4b, 0x51, 0xff, 0xbd, 0xf9, 0xf1, 0x21, 0xa9, 0xbf, 0x64, 0xbd,
0x85, 0xe9, 0xba, 0xd0, 0xd0, 0xfd, 0xc0, 0xdd, 0x76, 0x4f, 0xda, 0xa6, 0x99, 0xbb, 0x57, 0x4c,
0x8e, 0xe2, 0xf8, 0x98, 0x97, 0xc8, 0x0b, 0xe5, 0x95, 0x70, 0x68, 0xa5, 0x44, 0x9a, 0xd9, 0xa6,
0xec, 0x40, 0xaf, 0x64, 0x2f, 0xe3, 0x44, 0x6a, 0x59, 0x73, 0x43, 0x7a, 0xab, 0x6d, 0xa0, 0x4d,
0x11, 0xb5, 0xa2, 0x69, 0x1b, 0xcb, 0x2b, 0x66, 0x22, 0x66, 0xb3, 0x94, 0x6b, 0xe8, 0x8c, 0xb3,
0xfa, 0x43, 0x7e, 0x3b, 0x6d, 0x5b, 0x28, 0x48, 0xc4, 0xf2, 0xa0, 0x82, 0x4d, 0x23, 0x2b, 0xac,
0x7e, 0x24, 0xd5, 0x34, 0xec, 0x46, 0xdb, 0x8c, 0x07, 0x10, 0x69, 0x24, 0x0a, 0xda, 0xf7, 0xde,
0x2a, 0xf1, 0x01, 0x6f, 0x5a, 0x02, 0x7e, 0x82, 0x48, 0x29, 0x3b, 0x62, 0xe2, 0xbd, 0x37, 0x04,
0xb3, 0xfb, 0x04, 0xe0, 0xe1, 0xc5, 0xea, 0x30, 0x86, 0xfb, 0x04, 0xa8, 0xaf, 0x18, 0x62, 0x9f,
0x40, 0xb1, 0x7e, 0xd7, 0x99, 0x73, 0xaf, 0x23, 0x56, 0xda, 0xca, 0x21, 0x5d, 0x87, 0x82, 0xa1,
0xae, 0xa3, 0x14, 0xfc, 0x26, 0x75, 0x8f, 0xd6, 0x90, 0x26, 0xc5, 0xce, 0xd5, 0xd6, 0xbb, 0x30,
0x27, 0xf1, 0xf1, 0xaa, 0x38, 0x11, 0xba, 0x18, 0xfa, 0xbd, 0xc6, 0x12, 0x24, 0x3e, 0x7e, 0xb1,
0x5b, 0x34, 0x91, 0xf8, 0x74, 0x6b, 0xd9, 0x38, 0x69, 0xf6, 0xb7, 0xea, 0x0a, 0x15, 0xfe, 0x8b,
0x02, 0xb5, 0x90, 0x88, 0x93, 0x2d, 0xa8, 0xb6, 0xfd, 0xe2, 0xa3, 0xff, 0xfa, 0xfa, 0xce, 0xda,
0x2f, 0xbe, 0xbe, 0xb3, 0xf6, 0x3f, 0x5f, 0xdf, 0x59, 0xfb, 0xf9, 0x37, 0x77, 0xbe, 0xf5, 0x8b,
0x6f, 0xee, 0x7c, 0xeb, 0xbf, 0xbf, 0xb9, 0xf3, 0xad, 0xaf, 0xde, 0xd1, 0xbf, 0x30, 0x7c, 0xf1,
0x2b, 0xea, 0x77, 0x82, 0x9f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x92, 0xd1, 0x67, 0x07,
0x85, 0x78, 0x00, 0x00,
0xfc, 0x35, 0x88, 0xa7, 0x7b, 0xe4, 0x11, 0xed, 0xfe, 0x05, 0xfc, 0x07, 0xa8, 0x32, 0xb3, 0xf2,
0x23, 0x2a, 0x22, 0xab, 0x7c, 0x4f, 0x33, 0x72, 0xfc, 0x22, 0x22, 0x3f, 0x23, 0x23, 0xb3, 0xb2,
0xaa, 0xa3, 0xbb, 0xc5, 0xc5, 0x4e, 0x51, 0x72, 0xc1, 0xab, 0x9d, 0x8a, 0x95, 0xcb, 0x74, 0xca,
0x9a, 0x7f, 0x87, 0xf2, 0xcf, 0x83, 0x77, 0xe2, 0x7c, 0x25, 0x56, 0x05, 0xfb, 0xf0, 0x03, 0x4b,
0x4e, 0xf9, 0x7c, 0x1e, 0xe7, 0x49, 0xa5, 0x90, 0x0f, 0xdf, 0xb7, 0x12, 0xb6, 0x64, 0xb9, 0xd0,
0x7f, 0x7f, 0xf6, 0xdf, 0xff, 0xb7, 0x16, 0xbd, 0xbb, 0x9b, 0xa5, 0x2c, 0x17, 0xbb, 0x5a, 0x63,
0xf0, 0x55, 0xf4, 0x9d, 0x51, 0x51, 0x1c, 0x30, 0xf1, 0x9a, 0x95, 0x55, 0xca, 0xf3, 0xc1, 0xc7,
0x43, 0xed, 0x60, 0x78, 0x56, 0x4c, 0x87, 0xa3, 0xa2, 0x18, 0x5a, 0xe1, 0xf0, 0x8c, 0xfd, 0x74,
0xc1, 0x2a, 0xf1, 0xe1, 0x83, 0x30, 0x54, 0x15, 0x3c, 0xaf, 0xd8, 0xe0, 0x32, 0xfa, 0xad, 0x51,
0x51, 0x8c, 0x99, 0xd8, 0x63, 0x75, 0x05, 0xc6, 0x22, 0x16, 0x6c, 0xb0, 0xd1, 0x52, 0xf5, 0x01,
0xe3, 0xe3, 0x51, 0x37, 0xa8, 0xfd, 0x4c, 0xa2, 0x6f, 0xd7, 0x7e, 0xae, 0x16, 0x22, 0xe1, 0x37,
0xf9, 0xe0, 0xa3, 0xb6, 0xa2, 0x16, 0x19, 0xdb, 0xf7, 0x43, 0x88, 0xb6, 0xfa, 0x26, 0xfa, 0xf5,
0x37, 0x71, 0x96, 0x31, 0xb1, 0x5b, 0xb2, 0xba, 0xe0, 0xbe, 0x8e, 0x12, 0x0d, 0x95, 0xcc, 0xd8,
0xfd, 0x38, 0xc8, 0x68, 0xc3, 0x5f, 0x45, 0xdf, 0x51, 0x92, 0x33, 0x36, 0xe5, 0x4b, 0x56, 0x0e,
0x50, 0x2d, 0x2d, 0x24, 0x9a, 0xbc, 0x05, 0x41, 0xdb, 0xbb, 0x3c, 0x5f, 0xb2, 0x52, 0xe0, 0xb6,
0xb5, 0x30, 0x6c, 0xdb, 0x42, 0xda, 0xf6, 0xdf, 0xad, 0x45, 0xdf, 0x1b, 0x4d, 0xa7, 0x7c, 0x91,
0x8b, 0x23, 0x3e, 0x8d, 0xb3, 0xa3, 0x34, 0xbf, 0x3e, 0x61, 0x37, 0xbb, 0x57, 0x35, 0x9f, 0xcf,
0xd8, 0xe0, 0xb9, 0xdf, 0xaa, 0x0a, 0x1d, 0x1a, 0x76, 0xe8, 0xc2, 0xc6, 0xf7, 0xa7, 0xb7, 0x53,
0xd2, 0x65, 0xf9, 0xa7, 0xb5, 0xe8, 0x0e, 0x2c, 0xcb, 0x98, 0x67, 0x4b, 0x66, 0x4b, 0xf3, 0x59,
0x87, 0x61, 0x1f, 0x37, 0xe5, 0xf9, 0xfc, 0xb6, 0x6a, 0xba, 0x44, 0x59, 0xf4, 0x9e, 0x3b, 0x5c,
0xc6, 0xac, 0x92, 0xd3, 0xe9, 0x31, 0x3d, 0x22, 0x34, 0x62, 0x3c, 0x3f, 0xe9, 0x83, 0x6a, 0x6f,
0x69, 0x34, 0xd0, 0xde, 0x32, 0x5e, 0x19, 0x67, 0x8f, 0x50, 0x0b, 0x0e, 0x61, 0x7c, 0x3d, 0xee,
0x41, 0x6a, 0x57, 0x7f, 0x1c, 0xfd, 0xc6, 0x1b, 0x5e, 0x5e, 0x57, 0x45, 0x3c, 0x65, 0x7a, 0x2a,
0x3c, 0xf4, 0xb5, 0x1b, 0x29, 0x9c, 0x0d, 0xeb, 0x5d, 0x98, 0x33, 0x68, 0x1b, 0xe1, 0xab, 0x82,
0xc1, 0x18, 0x64, 0x15, 0x6b, 0x21, 0x35, 0x68, 0x21, 0xa4, 0x6d, 0x5f, 0x47, 0x03, 0x6b, 0xfb,
0xe2, 0x4f, 0xd8, 0x54, 0x8c, 0x92, 0x04, 0xf6, 0x8a, 0xd5, 0x95, 0xc4, 0x70, 0x94, 0x24, 0x54,
0xaf, 0xe0, 0xa8, 0x76, 0x76, 0x13, 0xbd, 0x0f, 0x9c, 0x1d, 0xa5, 0x95, 0x74, 0xb8, 0x1d, 0xb6,
0xa2, 0x31, 0xe3, 0x74, 0xd8, 0x17, 0xd7, 0x8e, 0xff, 0x62, 0x2d, 0xfa, 0x2e, 0xe2, 0xf9, 0x8c,
0xcd, 0xf9, 0x92, 0x0d, 0x9e, 0x76, 0x5b, 0x53, 0xa4, 0xf1, 0xff, 0xc9, 0x2d, 0x34, 0x90, 0x61,
0x32, 0x66, 0x19, 0x9b, 0x0a, 0x72, 0x98, 0x28, 0x71, 0xe7, 0x30, 0x31, 0x98, 0x33, 0xc3, 0x1a,
0xe1, 0x01, 0x13, 0xbb, 0x8b, 0xb2, 0x64, 0xb9, 0x20, 0xfb, 0xd2, 0x22, 0x9d, 0x7d, 0xe9, 0xa1,
0x48, 0x7d, 0x0e, 0x98, 0x18, 0x65, 0x19, 0x59, 0x1f, 0x25, 0xee, 0xac, 0x8f, 0xc1, 0xb4, 0x87,
0x69, 0xf4, 0x9b, 0x4e, 0x8b, 0x89, 0xc3, 0xfc, 0x92, 0x0f, 0xe8, 0xb6, 0x90, 0x72, 0xe3, 0x63,
0xa3, 0x93, 0x43, 0xaa, 0xf1, 0xf2, 0x6d, 0xc1, 0x4b, 0xba, 0x5b, 0x94, 0xb8, 0xb3, 0x1a, 0x06,
0xd3, 0x1e, 0xfe, 0x28, 0x7a, 0x57, 0x47, 0xc9, 0x66, 0x3d, 0x7b, 0x80, 0x86, 0x50, 0xb8, 0xa0,
0x3d, 0xec, 0xa0, 0x5a, 0xe6, 0x8f, 0xd3, 0x59, 0x59, 0x47, 0x1f, 0xdc, 0xbc, 0x96, 0x76, 0x98,
0xb7, 0x94, 0x36, 0xcf, 0xa3, 0xdf, 0xf6, 0xcd, 0xef, 0xc6, 0xf9, 0x94, 0x65, 0x83, 0x27, 0x21,
0x75, 0xc5, 0x18, 0x57, 0x9b, 0xbd, 0x58, 0x1b, 0xec, 0x34, 0xa1, 0x83, 0xe9, 0xc7, 0xa8, 0x36,
0x08, 0xa5, 0x0f, 0xc2, 0x50, 0xcb, 0xf6, 0x1e, 0xcb, 0x18, 0x69, 0x5b, 0x09, 0x3b, 0x6c, 0x1b,
0x48, 0xdb, 0x2e, 0xa3, 0xdf, 0x31, 0xdd, 0x5c, 0xe7, 0x05, 0x52, 0x5e, 0x2f, 0x3a, 0x9b, 0x44,
0x3f, 0xba, 0x90, 0xf1, 0xb5, 0xd5, 0x0f, 0x6e, 0xd5, 0x47, 0x47, 0x14, 0xbc, 0x3e, 0x20, 0x9e,
0x3c, 0x08, 0x43, 0xda, 0xf6, 0xdf, 0xaf, 0x45, 0xdf, 0xd7, 0xb2, 0x97, 0x79, 0x7c, 0x91, 0x31,
0xb9, 0xc4, 0x9f, 0x30, 0x71, 0xc3, 0xcb, 0xeb, 0xf1, 0x2a, 0x9f, 0x12, 0xe9, 0x0c, 0x0e, 0x77,
0xa4, 0x33, 0xa4, 0x92, 0x2e, 0xcc, 0x9f, 0x46, 0x1f, 0x34, 0x83, 0xe2, 0x2a, 0xce, 0x67, 0xec,
0xc7, 0x15, 0xcf, 0x47, 0x45, 0x3a, 0x4a, 0x92, 0x72, 0x30, 0xc4, 0xbb, 0x1e, 0x72, 0xa6, 0x04,
0x3b, 0xbd, 0x79, 0x27, 0x7d, 0xd6, 0xad, 0x2c, 0x78, 0x01, 0xd3, 0xe7, 0xa6, 0xf9, 0x04, 0x2f,
0xa8, 0xf4, 0xd9, 0x47, 0x5a, 0x56, 0x8f, 0xeb, 0x35, 0x08, 0xb7, 0x7a, 0xec, 0x2e, 0x3a, 0xf7,
0x43, 0x88, 0x5d, 0x03, 0x9a, 0x86, 0xe2, 0xf9, 0x65, 0x3a, 0x3b, 0x2f, 0x92, 0x7a, 0x0e, 0x3d,
0xc6, 0xeb, 0xec, 0x20, 0xc4, 0x1a, 0x40, 0xa0, 0xda, 0xdb, 0x3f, 0xda, 0x2c, 0x53, 0xc7, 0xa5,
0xfd, 0x92, 0xcf, 0x8f, 0xd8, 0x2c, 0x9e, 0xae, 0x74, 0x30, 0xfd, 0x34, 0x14, 0xc5, 0x20, 0x6d,
0x0a, 0xf1, 0xd9, 0x2d, 0xb5, 0x74, 0x79, 0xfe, 0x63, 0x2d, 0x7a, 0xe0, 0x8d, 0x13, 0x3d, 0x98,
0x54, 0xe9, 0x47, 0x79, 0x72, 0xc6, 0x2a, 0x11, 0x97, 0x62, 0xf0, 0xc3, 0xc0, 0x18, 0x20, 0x74,
0x4c, 0xd9, 0x7e, 0xf4, 0x4b, 0xe9, 0xda, 0x5e, 0x1f, 0xd7, 0xab, 0x84, 0x8e, 0x3f, 0x7e, 0xaf,
0x4b, 0x09, 0x8c, 0x3e, 0xf7, 0x43, 0x88, 0xed, 0x75, 0x29, 0x38, 0xcc, 0x97, 0xa9, 0x60, 0x07,
0x2c, 0x67, 0x65, 0xbb, 0xd7, 0x95, 0xaa, 0x8f, 0x10, 0xbd, 0x4e, 0xa0, 0x36, 0xd2, 0x79, 0xde,
0x4c, 0xa6, 0xb1, 0x19, 0x30, 0xd2, 0xca, 0x35, 0xb6, 0xfa, 0xc1, 0x76, 0xab, 0xec, 0xf8, 0x3c,
0x63, 0x4b, 0x7e, 0x0d, 0xb7, 0xca, 0xae, 0x09, 0x05, 0x10, 0x5b, 0x65, 0x14, 0xb4, 0xe9, 0x80,
0xe3, 0xe7, 0x75, 0xca, 0x6e, 0x40, 0x3a, 0xe0, 0x2a, 0xd7, 0x62, 0x22, 0x1d, 0x40, 0x30, 0xed,
0xe1, 0x24, 0xfa, 0x35, 0x29, 0xfc, 0x31, 0x4f, 0xf3, 0xc1, 0x5d, 0x44, 0xa9, 0x16, 0x18, 0xab,
0xf7, 0x68, 0x00, 0x94, 0xb8, 0xfe, 0xab, 0x5e, 0x9b, 0x1f, 0x12, 0x4a, 0x60, 0x59, 0x5e, 0xef,
0xc2, 0x6c, 0x1e, 0x26, 0x85, 0x75, 0xfc, 0x1a, 0x5f, 0xc5, 0x65, 0x9a, 0xcf, 0x06, 0x98, 0xae,
0x23, 0x27, 0xf2, 0x30, 0x8c, 0x03, 0x43, 0x58, 0x2b, 0x8e, 0x8a, 0xa2, 0xac, 0xc3, 0x22, 0x36,
0x84, 0x7d, 0x24, 0x38, 0x84, 0x5b, 0x28, 0xee, 0x6d, 0x8f, 0x4d, 0xb3, 0x34, 0x0f, 0x7a, 0xd3,
0x48, 0x1f, 0x6f, 0x16, 0x05, 0x83, 0xf7, 0x88, 0xc5, 0x4b, 0xd6, 0xd4, 0x0c, 0x6b, 0x19, 0x17,
0x08, 0x0e, 0x5e, 0x00, 0xda, 0x4d, 0xaf, 0x14, 0x1f, 0xc7, 0xd7, 0xac, 0x6e, 0x60, 0x56, 0x2f,
0xaa, 0x03, 0x4c, 0xdf, 0x23, 0x88, 0x4d, 0x2f, 0x4e, 0x6a, 0x57, 0x8b, 0xe8, 0x7d, 0x29, 0x3f,
0x8d, 0x4b, 0x91, 0x4e, 0xd3, 0x22, 0xce, 0x9b, 0xcd, 0x14, 0x36, 0xaf, 0x5b, 0x94, 0x71, 0xb9,
0xdd, 0x93, 0xd6, 0x6e, 0xff, 0x7d, 0x2d, 0xfa, 0x08, 0xfa, 0x3d, 0x65, 0xe5, 0x3c, 0x95, 0x7b,
0xf2, 0x4a, 0x05, 0xe1, 0xc1, 0x17, 0x61, 0xa3, 0x2d, 0x05, 0x53, 0x9a, 0x1f, 0xdc, 0x5e, 0xd1,
0x66, 0x62, 0x63, 0xbd, 0x4f, 0x79, 0x55, 0x26, 0xad, 0x33, 0xab, 0x71, 0xb3, 0xf9, 0x90, 0x42,
0x22, 0x13, 0x6b, 0x41, 0x60, 0x86, 0x9f, 0xe7, 0x55, 0x63, 0x1d, 0x9b, 0xe1, 0x56, 0x1c, 0x9c,
0xe1, 0x1e, 0x66, 0x67, 0xf8, 0xe9, 0xe2, 0x22, 0x4b, 0xab, 0xab, 0x34, 0x9f, 0xe9, 0xb4, 0xdb,
0xd7, 0xb5, 0x62, 0x98, 0x79, 0x6f, 0x74, 0x72, 0x98, 0x13, 0x3d, 0x58, 0x48, 0x27, 0x60, 0x98,
0x6c, 0x74, 0x72, 0x76, 0x37, 0x64, 0xa5, 0xf5, 0x36, 0x1c, 0xec, 0x86, 0x1c, 0xd5, 0x5a, 0x4a,
0xec, 0x86, 0xda, 0x94, 0xdd, 0x0d, 0xb9, 0x75, 0xa8, 0x78, 0xb6, 0x64, 0xe7, 0x65, 0x0a, 0x76,
0x43, 0x5e, 0xf9, 0x1a, 0x86, 0xd8, 0x0d, 0x51, 0xac, 0x0d, 0x54, 0x96, 0x38, 0x60, 0x62, 0x2c,
0x62, 0xb1, 0xa8, 0x40, 0xa0, 0x72, 0x6c, 0x18, 0x84, 0x08, 0x54, 0x04, 0xaa, 0xbd, 0xfd, 0x61,
0x14, 0xa9, 0x13, 0x0c, 0x79, 0xca, 0xe4, 0xaf, 0x3d, 0xfa, 0x68, 0xc3, 0x3b, 0x62, 0xfa, 0x28,
0x40, 0xd8, 0x84, 0x47, 0xfd, 0x5d, 0x1e, 0x9e, 0x0d, 0x50, 0x0d, 0x29, 0x22, 0x12, 0x1e, 0x80,
0xc0, 0x82, 0x8e, 0xaf, 0xf8, 0x0d, 0x5e, 0xd0, 0x5a, 0x12, 0x2e, 0xa8, 0x26, 0xec, 0x71, 0xb6,
0x2e, 0x28, 0x76, 0x9c, 0xdd, 0x14, 0x23, 0x74, 0x9c, 0x0d, 0x19, 0x3b, 0x66, 0x5c, 0xc3, 0x2f,
0x38, 0xbf, 0x9e, 0xc7, 0xe5, 0x35, 0x18, 0x33, 0x9e, 0x72, 0xc3, 0x10, 0x63, 0x86, 0x62, 0xed,
0x98, 0x71, 0x1d, 0xd6, 0xe9, 0xf2, 0x79, 0x99, 0x81, 0x31, 0xe3, 0xd9, 0xd0, 0x08, 0x31, 0x66,
0x08, 0xd4, 0x46, 0x27, 0xd7, 0xdb, 0x98, 0xc1, 0x03, 0x14, 0x4f, 0x7d, 0xcc, 0xa8, 0x03, 0x14,
0x04, 0x83, 0x43, 0xe8, 0xa0, 0x8c, 0x8b, 0x2b, 0x7c, 0x08, 0x49, 0x51, 0x78, 0x08, 0x35, 0x08,
0xec, 0xef, 0x31, 0x8b, 0xcb, 0xe9, 0x15, 0xde, 0xdf, 0x4a, 0x16, 0xee, 0x6f, 0xc3, 0xc0, 0xfe,
0x56, 0x82, 0x37, 0xa9, 0xb8, 0x3a, 0x66, 0x22, 0xc6, 0xfb, 0xdb, 0x67, 0xc2, 0xfd, 0xdd, 0x62,
0x6d, 0x3e, 0xee, 0x3a, 0x1c, 0x2f, 0x2e, 0xaa, 0x69, 0x99, 0x5e, 0xb0, 0x41, 0xc0, 0x8a, 0x81,
0x88, 0x7c, 0x9c, 0x84, 0xb5, 0xcf, 0x9f, 0xaf, 0x45, 0x77, 0x9b, 0x6e, 0xe7, 0x55, 0xa5, 0xd7,
0x3e, 0xdf, 0xfd, 0x67, 0x78, 0xff, 0x12, 0x38, 0xf1, 0x80, 0xa1, 0x87, 0x9a, 0x93, 0x1b, 0xe0,
0x45, 0x3a, 0xcf, 0x2b, 0x53, 0xa8, 0x2f, 0xfa, 0x58, 0x77, 0x14, 0x88, 0xdc, 0xa0, 0x97, 0xa2,
0x4d, 0xcb, 0x74, 0xff, 0x34, 0xb2, 0xc3, 0xa4, 0x02, 0x69, 0x59, 0xd3, 0xde, 0x0e, 0x41, 0xa4,
0x65, 0x38, 0x09, 0x87, 0xc2, 0x41, 0xc9, 0x17, 0x45, 0xd5, 0x31, 0x14, 0x00, 0x14, 0x1e, 0x0a,
0x6d, 0x58, 0xfb, 0x7c, 0x1b, 0xfd, 0xae, 0x3b, 0xfc, 0xdc, 0xc6, 0xde, 0xa6, 0xc7, 0x14, 0xd6,
0xc4, 0xc3, 0xbe, 0xb8, 0xcd, 0x28, 0x1a, 0xcf, 0x62, 0x8f, 0x89, 0x38, 0xcd, 0xaa, 0xc1, 0x3a,
0x6e, 0xa3, 0x91, 0x13, 0x19, 0x05, 0xc6, 0xc1, 0xf8, 0xb6, 0xb7, 0x28, 0xb2, 0x74, 0xda, 0x7e,
0xbc, 0xa3, 0x75, 0x8d, 0x38, 0x1c, 0xdf, 0x5c, 0x0c, 0xc6, 0xeb, 0x3a, 0xf5, 0x93, 0xff, 0x99,
0xac, 0x0a, 0x86, 0xc7, 0x6b, 0x0f, 0x09, 0xc7, 0x6b, 0x88, 0xc2, 0xfa, 0x8c, 0x99, 0x38, 0x8a,
0x57, 0x7c, 0x41, 0xc4, 0x6b, 0x23, 0x0e, 0xd7, 0xc7, 0xc5, 0xec, 0xde, 0xc0, 0x78, 0x38, 0xcc,
0x05, 0x2b, 0xf3, 0x38, 0xdb, 0xcf, 0xe2, 0x59, 0x35, 0x20, 0x62, 0x8c, 0x4f, 0x11, 0x7b, 0x03,
0x9a, 0x46, 0x9a, 0xf1, 0xb0, 0xda, 0x8f, 0x97, 0xbc, 0x4c, 0x05, 0xdd, 0x8c, 0x16, 0xe9, 0x6c,
0x46, 0x0f, 0x45, 0xbd, 0x8d, 0xca, 0xe9, 0x55, 0xba, 0x64, 0x49, 0xc0, 0x5b, 0x83, 0xf4, 0xf0,
0xe6, 0xa0, 0x48, 0xa7, 0x8d, 0xf9, 0xa2, 0x9c, 0x32, 0xb2, 0xd3, 0x94, 0xb8, 0xb3, 0xd3, 0x0c,
0xa6, 0x3d, 0xfc, 0xf5, 0x5a, 0xf4, 0x7b, 0x4a, 0xea, 0x3e, 0x73, 0xd9, 0x8b, 0xab, 0xab, 0x0b,
0x1e, 0x97, 0xc9, 0xe0, 0x13, 0xcc, 0x0e, 0x8a, 0x1a, 0xd7, 0xcf, 0x6e, 0xa3, 0x02, 0x9b, 0xb5,
0xce, 0xbb, 0xed, 0x8c, 0x43, 0x9b, 0xd5, 0x43, 0xc2, 0xcd, 0x0a, 0x51, 0x18, 0x40, 0xa4, 0x5c,
0x1d, 0xc9, 0xad, 0x93, 0xfa, 0xfe, 0xb9, 0xdc, 0x46, 0x27, 0x07, 0xe3, 0x63, 0x2d, 0xf4, 0x47,
0xcb, 0x36, 0x65, 0x03, 0x1f, 0x31, 0xc3, 0xbe, 0x38, 0xe9, 0xd9, 0xcc, 0x8a, 0xb0, 0xe7, 0xd6,
0xcc, 0x18, 0xf6, 0xc5, 0x09, 0xcf, 0x4e, 0x58, 0x0b, 0x79, 0x46, 0x42, 0xdb, 0xb0, 0x2f, 0x0e,
0xb3, 0x2f, 0xcd, 0x34, 0xeb, 0xc2, 0x93, 0x80, 0x1d, 0xb8, 0x36, 0x6c, 0xf6, 0x62, 0xb5, 0xc3,
0xbf, 0x5d, 0x8b, 0xbe, 0x67, 0x3d, 0x1e, 0xf3, 0x24, 0xbd, 0x5c, 0x29, 0xe8, 0x75, 0x9c, 0x2d,
0x58, 0x35, 0x78, 0x46, 0x59, 0x6b, 0xb3, 0xa6, 0x04, 0xcf, 0x6f, 0xa5, 0x03, 0xe7, 0xce, 0xa8,
0x28, 0xb2, 0xd5, 0x84, 0xcd, 0x8b, 0x8c, 0x9c, 0x3b, 0x1e, 0x12, 0x9e, 0x3b, 0x10, 0x85, 0x59,
0xf9, 0x84, 0xd7, 0x39, 0x3f, 0x9a, 0x95, 0x4b, 0x51, 0x38, 0x2b, 0x6f, 0x10, 0x98, 0x2b, 0x4d,
0xf8, 0x2e, 0xcf, 0x32, 0x36, 0x15, 0xed, 0x7b, 0x1b, 0x46, 0xd3, 0x12, 0xe1, 0x5c, 0x09, 0x90,
0xf6, 0x54, 0xae, 0xd9, 0x43, 0xc6, 0x25, 0x7b, 0xb1, 0x3a, 0x4a, 0xf3, 0xeb, 0x01, 0x9e, 0x16,
0x58, 0x80, 0x38, 0x95, 0x43, 0x41, 0xb8, 0x57, 0x3d, 0xcf, 0x13, 0x8e, 0xef, 0x55, 0x6b, 0x49,
0x78, 0xaf, 0xaa, 0x09, 0x68, 0xf2, 0x8c, 0x51, 0x26, 0x6b, 0x49, 0xd8, 0xa4, 0x26, 0xb0, 0x50,
0xa8, 0x9f, 0xdd, 0x90, 0xa1, 0x10, 0x3c, 0xad, 0xd9, 0xe8, 0xe4, 0xe0, 0x08, 0x6d, 0x36, 0xad,
0xfb, 0x4c, 0x4c, 0xaf, 0xf0, 0x11, 0xea, 0x21, 0xe1, 0x11, 0x0a, 0x51, 0x58, 0xa5, 0x09, 0x37,
0x9b, 0xee, 0x75, 0x7c, 0x7c, 0xb4, 0x36, 0xdc, 0x1b, 0x9d, 0x1c, 0xdc, 0x46, 0x1e, 0xce, 0x65,
0x9b, 0xa1, 0x83, 0x5c, 0xc9, 0xc2, 0xdb, 0x48, 0xc3, 0xc0, 0xd2, 0x2b, 0x81, 0x3c, 0xcb, 0x5a,
0xa7, 0x15, 0xbd, 0xd3, 0xac, 0x8d, 0x4e, 0x4e, 0x3b, 0xf9, 0x57, 0xb3, 0x8d, 0x53, 0xd2, 0x13,
0x5e, 0xcf, 0x91, 0xd7, 0x71, 0x96, 0x26, 0xb1, 0x60, 0x13, 0x7e, 0xcd, 0x72, 0x7c, 0xc7, 0xa4,
0x4b, 0xab, 0xf8, 0xa1, 0xa7, 0x10, 0xde, 0x31, 0x85, 0x15, 0xe1, 0x38, 0x51, 0xf4, 0x79, 0xc5,
0x76, 0xe3, 0x8a, 0x88, 0x64, 0x1e, 0x12, 0x1e, 0x27, 0x10, 0x85, 0xf9, 0xaa, 0x92, 0xbf, 0x7c,
0x5b, 0xb0, 0x32, 0x65, 0xf9, 0x94, 0xe1, 0xf9, 0x2a, 0xa4, 0xc2, 0xf9, 0x2a, 0x42, 0xc3, 0xbd,
0xda, 0x5e, 0x2c, 0xd8, 0x8b, 0xd5, 0x24, 0x9d, 0xb3, 0x4a, 0xc4, 0xf3, 0x02, 0xdf, 0xab, 0x01,
0x28, 0xbc, 0x57, 0x6b, 0xc3, 0xad, 0xa3, 0x21, 0x13, 0x10, 0xdb, 0xd7, 0xbd, 0x20, 0x11, 0xb8,
0xee, 0x45, 0xa0, 0xb0, 0x61, 0x2d, 0x80, 0x3e, 0x24, 0x68, 0x59, 0x09, 0x3e, 0x24, 0xa0, 0xe9,
0xd6, 0x81, 0x9b, 0x61, 0xc6, 0xf5, 0xd4, 0xec, 0x28, 0xfa, 0xd8, 0x9d, 0xa2, 0x9b, 0xbd, 0x58,
0xfc, 0x84, 0xef, 0x8c, 0x65, 0xb1, 0x5c, 0xb6, 0x02, 0xc7, 0x68, 0x0d, 0xd3, 0xe7, 0x84, 0xcf,
0x61, 0xb5, 0xc3, 0xbf, 0x5c, 0x8b, 0x3e, 0xc4, 0x3c, 0xbe, 0x2a, 0xa4, 0xdf, 0xa7, 0xdd, 0xb6,
0x14, 0x49, 0xdc, 0x67, 0x0b, 0x6b, 0xd8, 0x2b, 0x19, 0x8d, 0xc8, 0x5e, 0x77, 0xd3, 0x05, 0xf0,
0x93, 0x36, 0x53, 0x7e, 0xc8, 0x11, 0x57, 0x32, 0x42, 0xbc, 0xdd, 0x0f, 0xf9, 0xe5, 0xaa, 0xc0,
0x7e, 0xc8, 0xd8, 0xd0, 0x62, 0x62, 0x3f, 0x84, 0x60, 0x76, 0x76, 0xba, 0xd5, 0x7b, 0x93, 0x8a,
0x2b, 0x99, 0x6f, 0x81, 0xd9, 0xe9, 0x95, 0xd5, 0x40, 0xc4, 0xec, 0x24, 0x61, 0x98, 0x91, 0x34,
0x60, 0x3d, 0x37, 0xb1, 0x58, 0x6e, 0x0c, 0xb9, 0x33, 0xf3, 0x51, 0x37, 0x08, 0xc7, 0x6b, 0x23,
0xd6, 0x5b, 0x9f, 0x27, 0x21, 0x0b, 0x60, 0xfb, 0xb3, 0xd9, 0x8b, 0xd5, 0x0e, 0xff, 0x3c, 0xfa,
0x6e, 0xab, 0x62, 0xfb, 0x2c, 0x16, 0x8b, 0x92, 0x25, 0x83, 0x9d, 0x8e, 0x72, 0x37, 0xa0, 0x71,
0xfd, 0xb4, 0xbf, 0x42, 0x2b, 0x47, 0x6f, 0x38, 0x35, 0xac, 0x4c, 0x19, 0x9e, 0x85, 0x4c, 0xfa,
0x6c, 0x30, 0x47, 0xa7, 0x75, 0x5a, 0xdb, 0x6c, 0x77, 0x74, 0x8d, 0x96, 0x71, 0x9a, 0xc9, 0x87,
0xb5, 0x9f, 0x84, 0x8c, 0x7a, 0x68, 0x70, 0x9b, 0x4d, 0xaa, 0xb4, 0x22, 0xb3, 0x9c, 0xe3, 0xce,
0xf6, 0x6c, 0x8b, 0x8e, 0x04, 0xc8, 0xee, 0x6c, 0xbb, 0x27, 0xad, 0xdd, 0x8a, 0x66, 0xc9, 0xab,
0xff, 0xec, 0x0e, 0x72, 0xcc, 0xab, 0x56, 0x45, 0x46, 0xfa, 0x76, 0x4f, 0x5a, 0x7b, 0xfd, 0xb3,
0xe8, 0x83, 0xb6, 0x57, 0xbd, 0x10, 0xed, 0x74, 0x9a, 0x02, 0x6b, 0xd1, 0xd3, 0xfe, 0x0a, 0x76,
0x4b, 0xf3, 0x65, 0x5a, 0x09, 0x5e, 0xae, 0xc6, 0x57, 0xfc, 0xa6, 0x79, 0x8d, 0xc4, 0x9f, 0xad,
0x1a, 0x18, 0x3a, 0x04, 0xb1, 0xa5, 0xc1, 0xc9, 0x96, 0x2b, 0xfb, 0xba, 0x49, 0x45, 0xb8, 0x72,
0x88, 0x0e, 0x57, 0x3e, 0x69, 0x63, 0x55, 0x53, 0x2b, 0xfb, 0x6e, 0xcc, 0x06, 0x5e, 0xd4, 0xf6,
0xfb, 0x31, 0x8f, 0xba, 0x41, 0x9b, 0xb1, 0x68, 0xf1, 0x5e, 0x7a, 0x79, 0x69, 0xea, 0x84, 0x97,
0xd4, 0x45, 0x88, 0x8c, 0x85, 0x40, 0x6d, 0xd2, 0xbd, 0x9f, 0x66, 0x4c, 0x9e, 0xe8, 0xbf, 0xba,
0xbc, 0xcc, 0x78, 0x9c, 0x80, 0xa4, 0xbb, 0x16, 0x0f, 0x5d, 0x39, 0x91, 0x74, 0x63, 0x9c, 0xbd,
0x2b, 0x50, 0x4b, 0xcf, 0xd8, 0x94, 0xe7, 0xd3, 0x34, 0x83, 0xb7, 0x50, 0xa5, 0xa6, 0x11, 0x12,
0x77, 0x05, 0x5a, 0x90, 0x5d, 0x18, 0x6b, 0x51, 0x3d, 0xed, 0x9b, 0xf2, 0x3f, 0x6c, 0x2b, 0x3a,
0x62, 0x62, 0x61, 0x44, 0x30, 0xbb, 0xf7, 0xac, 0x85, 0xe7, 0x85, 0x34, 0x7e, 0xaf, 0xad, 0xa5,
0x24, 0xc4, 0xde, 0xd3, 0x27, 0xec, 0x1e, 0xaa, 0xfe, 0xfb, 0x1e, 0xbf, 0xc9, 0xa5, 0xd1, 0xfb,
0x6d, 0x95, 0x46, 0x46, 0xec, 0xa1, 0x20, 0xa3, 0x0d, 0xff, 0x24, 0xfa, 0x55, 0x69, 0xb8, 0xe4,
0xc5, 0xe0, 0x0e, 0xa2, 0x50, 0x3a, 0x77, 0x36, 0xef, 0x92, 0x72, 0x7b, 0xb5, 0xc0, 0x8c, 0x8d,
0xf3, 0x2a, 0x9e, 0xc1, 0x8b, 0xd6, 0xb6, 0xc7, 0xa5, 0x94, 0xb8, 0x5a, 0xd0, 0xa6, 0xfc, 0x51,
0x71, 0xc2, 0x13, 0x6d, 0x1d, 0xa9, 0xa1, 0x11, 0x86, 0x46, 0x85, 0x0b, 0xd9, 0x64, 0xe6, 0x24,
0x5e, 0xa6, 0x33, 0xb3, 0xe0, 0xa8, 0xb8, 0x55, 0x81, 0x64, 0xc6, 0x32, 0x43, 0x07, 0x22, 0x92,
0x19, 0x12, 0xd6, 0x3e, 0xff, 0x65, 0x2d, 0xba, 0x67, 0x99, 0x83, 0xe6, 0xb4, 0xee, 0x30, 0xbf,
0xe4, 0x75, 0xea, 0x73, 0x94, 0xe6, 0xd7, 0xd5, 0xe0, 0x73, 0xca, 0x24, 0xce, 0x9b, 0xa2, 0x7c,
0x71, 0x6b, 0x3d, 0x9b, 0xb5, 0x36, 0x47, 0x59, 0xf6, 0x79, 0xb6, 0xd2, 0x00, 0x59, 0xab, 0x39,
0xf1, 0x82, 0x1c, 0x91, 0xb5, 0x86, 0x78, 0xdb, 0xc5, 0xc6, 0x79, 0xc6, 0x73, 0xd8, 0xc5, 0xd6,
0x42, 0x2d, 0x24, 0xba, 0xb8, 0x05, 0xd9, 0x78, 0xdc, 0x88, 0xd4, 0xa9, 0xcb, 0x28, 0xcb, 0x40,
0x3c, 0x36, 0xaa, 0x06, 0x20, 0xe2, 0x31, 0x0a, 0x6a, 0x3f, 0x67, 0xd1, 0xb7, 0xeb, 0x26, 0x3d,
0x2d, 0xd9, 0x32, 0x65, 0xf0, 0xea, 0x85, 0x23, 0x21, 0xe6, 0xbf, 0x4f, 0xd8, 0x99, 0x75, 0x9e,
0x57, 0x45, 0x16, 0x57, 0x57, 0xfa, 0x61, 0xbc, 0x5f, 0xe7, 0x46, 0x08, 0x1f, 0xc7, 0x3f, 0xec,
0xa0, 0x6c, 0x50, 0x6f, 0x64, 0x26, 0xc4, 0xac, 0xe3, 0xaa, 0xad, 0x30, 0xb3, 0xd1, 0xc9, 0xd9,
0x13, 0xef, 0x83, 0x38, 0xcb, 0x58, 0xb9, 0x6a, 0x64, 0xc7, 0x71, 0x9e, 0x5e, 0xb2, 0x4a, 0x80,
0x13, 0x6f, 0x4d, 0x0d, 0x21, 0x46, 0x9c, 0x78, 0x07, 0x70, 0x9b, 0xcd, 0x03, 0xcf, 0x87, 0x79,
0xc2, 0xde, 0x82, 0x6c, 0x1e, 0xda, 0x91, 0x0c, 0x91, 0xcd, 0x53, 0xac, 0x3d, 0xf9, 0x7d, 0x91,
0xf1, 0xe9, 0xb5, 0x5e, 0x02, 0xfc, 0x0e, 0x96, 0x12, 0xb8, 0x06, 0xdc, 0x0f, 0x21, 0x76, 0x11,
0x90, 0x82, 0x33, 0x56, 0x64, 0xf1, 0x14, 0xde, 0xbf, 0x51, 0x3a, 0x5a, 0x46, 0x2c, 0x02, 0x90,
0x01, 0xc5, 0xd5, 0xf7, 0x7a, 0xb0, 0xe2, 0x82, 0x6b, 0x3d, 0xf7, 0x43, 0x88, 0x5d, 0x06, 0xa5,
0x60, 0x5c, 0x64, 0xa9, 0x00, 0xd3, 0x40, 0x69, 0x48, 0x09, 0x31, 0x0d, 0x7c, 0x02, 0x98, 0x3c,
0x66, 0xe5, 0x8c, 0xa1, 0x26, 0xa5, 0x24, 0x68, 0xb2, 0x21, 0xec, 0x65, 0x63, 0x55, 0x77, 0x5e,
0xac, 0xc0, 0x65, 0x63, 0x5d, 0x2d, 0x5e, 0xac, 0x88, 0xcb, 0xc6, 0x1e, 0x00, 0x8a, 0x78, 0x1a,
0x57, 0x02, 0x2f, 0xa2, 0x94, 0x04, 0x8b, 0xd8, 0x10, 0x76, 0x8d, 0x56, 0x45, 0x5c, 0x08, 0xb0,
0x46, 0xeb, 0x02, 0x38, 0x4f, 0xa0, 0xef, 0x92, 0x72, 0x1b, 0x49, 0x54, 0xaf, 0x30, 0xb1, 0x9f,
0xb2, 0x2c, 0xa9, 0x40, 0x24, 0xd1, 0xed, 0xde, 0x48, 0x89, 0x48, 0xd2, 0xa6, 0xc0, 0x50, 0xd2,
0xe7, 0xe3, 0x58, 0xed, 0xc0, 0xd1, 0xf8, 0xfd, 0x10, 0x62, 0xe3, 0x53, 0x53, 0xe8, 0xdd, 0xb8,
0x2c, 0xd3, 0x7a, 0xf1, 0x5f, 0xc7, 0x0b, 0xd4, 0xc8, 0x89, 0xf8, 0x84, 0x71, 0x60, 0x7a, 0x35,
0x81, 0x1b, 0x2b, 0x18, 0x0c, 0xdd, 0x1f, 0x07, 0x19, 0x9b, 0x71, 0x4a, 0x89, 0xf3, 0x08, 0x15,
0x6b, 0x4d, 0xe4, 0x09, 0xea, 0x7a, 0x17, 0xe6, 0xbc, 0x89, 0x64, 0x5c, 0x1c, 0xf3, 0x25, 0x9b,
0xf0, 0x97, 0x6f, 0xd3, 0x4a, 0xa4, 0xf9, 0x4c, 0xaf, 0xdc, 0xcf, 0x09, 0x4b, 0x18, 0x4c, 0xbc,
0x89, 0xd4, 0xa9, 0x64, 0x13, 0x08, 0x50, 0x96, 0x13, 0x76, 0x83, 0x26, 0x10, 0xd0, 0xa2, 0xe1,
0x88, 0x04, 0x22, 0xc4, 0xdb, 0x73, 0x14, 0xe3, 0x5c, 0xbf, 0x7e, 0x3e, 0xe1, 0x4d, 0x2e, 0x47,
0x59, 0x83, 0x20, 0xb1, 0x95, 0x0d, 0x2a, 0xd8, 0xfd, 0xa5, 0xf1, 0x6f, 0xa7, 0xd8, 0x23, 0xc2,
0x4e, 0x7b, 0x9a, 0x3d, 0xee, 0x41, 0x22, 0xae, 0xec, 0x3d, 0x00, 0xca, 0x55, 0xfb, 0x1a, 0xc0,
0xe3, 0x1e, 0xa4, 0x73, 0x26, 0xe3, 0x56, 0xeb, 0x45, 0x3c, 0xbd, 0x9e, 0x95, 0x7c, 0x91, 0x27,
0xbb, 0x3c, 0xe3, 0x25, 0x38, 0x93, 0xf1, 0x4a, 0x0d, 0x50, 0xe2, 0x4c, 0xa6, 0x43, 0xc5, 0x66,
0x70, 0x6e, 0x29, 0x46, 0x59, 0x3a, 0x83, 0x3b, 0x6a, 0xcf, 0x90, 0x04, 0x88, 0x0c, 0x0e, 0x05,
0x91, 0x41, 0xa4, 0x76, 0xdc, 0x22, 0x9d, 0xc6, 0x99, 0xf2, 0xb7, 0x43, 0x9b, 0xf1, 0xc0, 0xce,
0x41, 0x84, 0x28, 0x20, 0xf5, 0x9c, 0x2c, 0xca, 0xfc, 0x30, 0x17, 0x9c, 0xac, 0x67, 0x03, 0x74,
0xd6, 0xd3, 0x01, 0x41, 0x58, 0x9d, 0xb0, 0xb7, 0x75, 0x69, 0xea, 0x7f, 0xb0, 0xb0, 0x5a, 0xff,
0x7d, 0xa8, 0xe5, 0xa1, 0xb0, 0x0a, 0x38, 0x50, 0x19, 0xed, 0x44, 0x0d, 0x98, 0x80, 0xb6, 0x3f,
0x4c, 0x1e, 0x75, 0x83, 0xb8, 0x9f, 0xb1, 0x58, 0x65, 0x2c, 0xe4, 0x47, 0x02, 0x7d, 0xfc, 0x34,
0xa0, 0x3d, 0x6e, 0xf1, 0xea, 0x73, 0xc5, 0xa6, 0xd7, 0xad, 0x6b, 0x4d, 0x7e, 0x41, 0x15, 0x42,
0x1c, 0xb7, 0x10, 0x28, 0xde, 0x45, 0x87, 0x53, 0x9e, 0x87, 0xba, 0xa8, 0x96, 0xf7, 0xe9, 0x22,
0xcd, 0xd9, 0xcd, 0xaf, 0x91, 0xea, 0x91, 0xa9, 0xba, 0x69, 0x93, 0xb0, 0xe0, 0x42, 0xc4, 0xe6,
0x97, 0x84, 0x6d, 0x4e, 0x0e, 0x7d, 0x1e, 0xb7, 0xef, 0x7c, 0xb7, 0xac, 0x1c, 0xd3, 0x77, 0xbe,
0x29, 0x96, 0xae, 0xa4, 0x1a, 0x23, 0x1d, 0x56, 0xfc, 0x71, 0xb2, 0xd5, 0x0f, 0xb6, 0x5b, 0x1e,
0xcf, 0xe7, 0x6e, 0xc6, 0xe2, 0x52, 0x79, 0xdd, 0x0e, 0x18, 0xb2, 0x18, 0xb1, 0xe5, 0x09, 0xe0,
0x20, 0x84, 0x79, 0x9e, 0x77, 0x79, 0x2e, 0x58, 0x2e, 0xb0, 0x10, 0xe6, 0x1b, 0xd3, 0x60, 0x28,
0x84, 0x51, 0x0a, 0x60, 0xdc, 0xca, 0xf3, 0x20, 0x26, 0x4e, 0xe2, 0x39, 0x9a, 0xb1, 0xa9, 0xb3,
0x1e, 0x25, 0x0f, 0x8d, 0x5b, 0xc0, 0x39, 0x0f, 0xf9, 0x5c, 0x2f, 0x93, 0xb8, 0x9c, 0x99, 0xd3,
0x8d, 0x64, 0xf0, 0x94, 0xb6, 0xe3, 0x93, 0xc4, 0x43, 0xbe, 0xb0, 0x06, 0x08, 0x3b, 0x87, 0xf3,
0x78, 0x66, 0x6a, 0x8a, 0xd4, 0x40, 0xca, 0x5b, 0x55, 0x7d, 0xd4, 0x0d, 0x02, 0x3f, 0xaf, 0xd3,
0x84, 0xf1, 0x80, 0x1f, 0x29, 0xef, 0xe3, 0x07, 0x82, 0x20, 0x7b, 0xab, 0xeb, 0xad, 0x76, 0x74,
0xa3, 0x3c, 0xd1, 0xfb, 0xd8, 0x21, 0xd1, 0x3c, 0x80, 0x0b, 0x65, 0x6f, 0x04, 0x0f, 0xe6, 0x68,
0x73, 0x40, 0x1b, 0x9a, 0xa3, 0xe6, 0xfc, 0xb5, 0xcf, 0x1c, 0xc5, 0x60, 0xed, 0xf3, 0x67, 0x7a,
0x8e, 0xee, 0xc5, 0x22, 0xae, 0xf3, 0xf6, 0xd7, 0x29, 0xbb, 0xd1, 0x1b, 0x61, 0xa4, 0xbe, 0x0d,
0x35, 0x94, 0xaf, 0xac, 0x82, 0x5d, 0xf1, 0x4e, 0x6f, 0x3e, 0xe0, 0x5b, 0xef, 0x10, 0x3a, 0x7d,
0x83, 0xad, 0xc2, 0x4e, 0x6f, 0x3e, 0xe0, 0x5b, 0xbf, 0x0b, 0xdf, 0xe9, 0x1b, 0xbc, 0x10, 0xbf,
0xd3, 0x9b, 0xd7, 0xbe, 0xff, 0xaa, 0x99, 0xb8, 0xae, 0xf3, 0x3a, 0x0f, 0x9b, 0x8a, 0x74, 0xc9,
0xb0, 0x74, 0xd2, 0xb7, 0x67, 0xd0, 0x50, 0x3a, 0x49, 0xab, 0x38, 0x5f, 0xa3, 0xc2, 0x4a, 0x71,
0xca, 0xab, 0x54, 0x3e, 0xa4, 0x7f, 0xde, 0xc3, 0x68, 0x03, 0x87, 0x36, 0x4d, 0x21, 0x25, 0xfb,
0xb8, 0xd1, 0x43, 0xed, 0x2d, 0xe6, 0xad, 0x80, 0xbd, 0xf6, 0x65, 0xe6, 0xed, 0x9e, 0xb4, 0x7d,
0xf0, 0xe7, 0x31, 0xee, 0x13, 0xc7, 0x50, 0xaf, 0xa2, 0x0f, 0x1d, 0x9f, 0xf6, 0x57, 0xd0, 0xee,
0xff, 0xa6, 0xd9, 0x57, 0x40, 0xff, 0x7a, 0x12, 0x3c, 0xeb, 0x63, 0x11, 0x4c, 0x84, 0xe7, 0xb7,
0xd2, 0xd1, 0x05, 0xf9, 0x87, 0x66, 0x03, 0xdd, 0xa0, 0xf2, 0x5d, 0x0e, 0xf9, 0x0e, 0xa8, 0x9e,
0x13, 0xa1, 0x6e, 0xb5, 0x30, 0x9c, 0x19, 0x9f, 0xdd, 0x52, 0xcb, 0xf9, 0x36, 0x99, 0x07, 0xeb,
0x77, 0x0e, 0x9d, 0xf2, 0x84, 0x2c, 0x3b, 0x34, 0x2c, 0xd0, 0xe7, 0xb7, 0x55, 0xa3, 0xe6, 0x8a,
0x03, 0xcb, 0xaf, 0x73, 0x3c, 0xef, 0x69, 0xd8, 0xfb, 0x5e, 0xc7, 0xa7, 0xb7, 0x53, 0xd2, 0x65,
0xf9, 0xcf, 0xb5, 0xe8, 0xa1, 0xc7, 0xda, 0xe7, 0x09, 0xe0, 0xd4, 0xe3, 0x47, 0x01, 0xfb, 0x94,
0x92, 0x29, 0xdc, 0xef, 0xff, 0x72, 0xca, 0xf6, 0x43, 0x5e, 0x9e, 0xca, 0x7e, 0x9a, 0x09, 0x56,
0xb6, 0x3f, 0xe4, 0xe5, 0xdb, 0x55, 0xd4, 0x90, 0xfe, 0x90, 0x57, 0x00, 0x77, 0x3e, 0xe4, 0x85,
0x78, 0x46, 0x3f, 0xe4, 0x85, 0x5a, 0x0b, 0x7e, 0xc8, 0x2b, 0xac, 0x41, 0x85, 0xf7, 0xa6, 0x08,
0xea, 0xdc, 0xba, 0x97, 0x45, 0xff, 0x18, 0xfb, 0xd9, 0x6d, 0x54, 0x88, 0x05, 0x4e, 0x71, 0xf2,
0x9e, 0x5b, 0x8f, 0x36, 0xf5, 0xee, 0xba, 0xed, 0xf4, 0xe6, 0xb5, 0xef, 0x9f, 0xea, 0xdd, 0x8d,
0x09, 0xe7, 0xbc, 0x94, 0x1f, 0x71, 0xdb, 0x0c, 0x85, 0xe7, 0xda, 0x82, 0xdb, 0xf3, 0x5b, 0xfd,
0x60, 0xa2, 0xba, 0x35, 0xa1, 0x3b, 0x7d, 0xd8, 0x65, 0x08, 0x74, 0xf9, 0x4e, 0x6f, 0x9e, 0x58,
0x46, 0x94, 0x6f, 0xd5, 0xdb, 0x3d, 0x8c, 0xf9, 0x7d, 0xfd, 0xb4, 0xbf, 0x82, 0x76, 0xbf, 0xd4,
0x69, 0xa3, 0xeb, 0x5e, 0xf6, 0xf3, 0x76, 0x97, 0xa9, 0xb1, 0xd7, 0xcd, 0xc3, 0xbe, 0x78, 0x28,
0x81, 0x70, 0x97, 0xd0, 0xae, 0x04, 0x02, 0x5d, 0x46, 0x3f, 0xbd, 0x9d, 0x92, 0x2e, 0xcb, 0x3f,
0xaf, 0x45, 0x77, 0xc9, 0xb2, 0xe8, 0x71, 0xf0, 0x79, 0x5f, 0xcb, 0x60, 0x3c, 0x7c, 0x71, 0x6b,
0x3d, 0x5d, 0xa8, 0x7f, 0x5b, 0x8b, 0xee, 0x05, 0x0a, 0xa5, 0x06, 0xc8, 0x2d, 0xac, 0xfb, 0x03,
0xe5, 0x07, 0xb7, 0x57, 0xa4, 0x96, 0x7b, 0x17, 0x1f, 0xb7, 0x3f, 0xca, 0x14, 0xb0, 0x3d, 0xa6,
0x3f, 0xca, 0xd4, 0xad, 0x05, 0x0f, 0x79, 0xe2, 0x8b, 0x66, 0xd3, 0x85, 0x1e, 0xf2, 0xc8, 0x1b,
0x6a, 0xc1, 0x8f, 0x4b, 0x60, 0x1c, 0xe6, 0xe4, 0xe5, 0xdb, 0x22, 0xce, 0x13, 0xda, 0x89, 0x92,
0x77, 0x3b, 0x31, 0x1c, 0x3c, 0x1c, 0xab, 0xa5, 0x67, 0xbc, 0xd9, 0x48, 0x3d, 0xa6, 0xf4, 0x0d,
0x12, 0x3c, 0x1c, 0x6b, 0xa1, 0x84, 0x37, 0x9d, 0x35, 0x86, 0xbc, 0x81, 0x64, 0xf1, 0x49, 0x1f,
0x14, 0xa4, 0xe8, 0xc6, 0x9b, 0x39, 0x73, 0xdf, 0x0a, 0x59, 0x69, 0x9d, 0xbb, 0x6f, 0xf7, 0xa4,
0x09, 0xb7, 0x63, 0x26, 0xbe, 0x64, 0x71, 0xc2, 0xca, 0xa0, 0x5b, 0x43, 0xf5, 0x72, 0xeb, 0xd2,
0x98, 0xdb, 0x5d, 0x9e, 0x2d, 0xe6, 0xb9, 0xee, 0x4c, 0xd2, 0xad, 0x4b, 0x75, 0xbb, 0x05, 0x34,
0x3c, 0x16, 0xb4, 0x6e, 0x65, 0x7a, 0xf9, 0x24, 0x6c, 0xc6, 0xcb, 0x2a, 0x37, 0x7b, 0xb1, 0x74,
0x3d, 0xf5, 0x30, 0xea, 0xa8, 0x27, 0x18, 0x49, 0xdb, 0x3d, 0x69, 0x78, 0x3e, 0xe7, 0xb8, 0x35,
0xe3, 0x69, 0xa7, 0xc3, 0x56, 0x6b, 0x48, 0x3d, 0xed, 0xaf, 0x00, 0x4f, 0x43, 0xf5, 0xa8, 0x3a,
0x4a, 0x2b, 0xb1, 0x9f, 0x66, 0xd9, 0x60, 0x33, 0x30, 0x4c, 0x1a, 0x28, 0x78, 0x1a, 0x8a, 0xc0,
0xc4, 0x48, 0x6e, 0x4e, 0x0f, 0xf3, 0x41, 0x97, 0x1d, 0x49, 0xf5, 0x1a, 0xc9, 0x2e, 0x0d, 0x4e,
0xb4, 0x9c, 0xa6, 0x36, 0xb5, 0x1d, 0x86, 0x1b, 0xae, 0x55, 0xe1, 0x9d, 0xde, 0x3c, 0x78, 0xdc,
0x2e, 0x29, 0xb9, 0xb2, 0x3c, 0xa0, 0x4c, 0x78, 0x2b, 0xc9, 0xc3, 0x0e, 0x0a, 0x9c, 0x0a, 0xaa,
0x69, 0xf4, 0x26, 0x4d, 0x66, 0x4c, 0xa0, 0x4f, 0x8a, 0x5c, 0x20, 0xf8, 0xa4, 0x08, 0x80, 0xa0,
0xeb, 0xd4, 0xdf, 0xcd, 0x71, 0xe8, 0x61, 0x82, 0x75, 0x9d, 0x56, 0x76, 0xa8, 0x50, 0xd7, 0xa1,
0x34, 0x88, 0x06, 0xc6, 0xad, 0x7e, 0x1d, 0xff, 0x49, 0xc8, 0x0c, 0x78, 0x27, 0x7f, 0xb3, 0x17,
0x0b, 0x56, 0x14, 0xeb, 0x30, 0x9d, 0xa7, 0x02, 0x5b, 0x51, 0x1c, 0x1b, 0x35, 0x12, 0x5a, 0x51,
0xda, 0x28, 0x55, 0xbd, 0x3a, 0x47, 0x38, 0x4c, 0xc2, 0xd5, 0x53, 0x4c, 0xbf, 0xea, 0x19, 0xb6,
0xf5, 0x60, 0x33, 0x37, 0x43, 0x46, 0x5c, 0xe9, 0xcd, 0x32, 0x32, 0xb6, 0xe5, 0x6b, 0x9a, 0x10,
0x0c, 0x45, 0x1d, 0x4a, 0x01, 0x1e, 0xd8, 0xd7, 0x5c, 0xf3, 0xec, 0xb5, 0x28, 0x58, 0x5c, 0xc6,
0xf9, 0x14, 0xdd, 0x9c, 0x4a, 0x83, 0x2d, 0x32, 0xb4, 0x39, 0x25, 0x35, 0xc0, 0x63, 0x73, 0xff,
0x05, 0x4b, 0x64, 0x2a, 0x98, 0x37, 0x19, 0xfd, 0xf7, 0x2b, 0x1f, 0xf7, 0x20, 0xe1, 0x63, 0xf3,
0x06, 0x30, 0x07, 0xdf, 0xca, 0xe9, 0x27, 0x01, 0x53, 0x3e, 0x1a, 0xda, 0x08, 0xd3, 0x2a, 0x60,
0x50, 0x9b, 0x04, 0x97, 0x89, 0x9f, 0xb0, 0x15, 0x36, 0xa8, 0x6d, 0x7e, 0x2a, 0x91, 0xd0, 0xa0,
0x6e, 0xa3, 0x20, 0xcf, 0x74, 0xf7, 0x41, 0xeb, 0x01, 0x7d, 0x77, 0xeb, 0xb3, 0xd1, 0xc9, 0x81,
0x99, 0xb3, 0x97, 0x2e, 0xbd, 0xe7, 0x04, 0x48, 0x41, 0xf7, 0xd2, 0x25, 0xfe, 0x98, 0x60, 0xb3,
0x17, 0x0b, 0x1f, 0xc9, 0xc7, 0x82, 0xbd, 0x6d, 0x9e, 0x95, 0x23, 0xc5, 0x95, 0xf2, 0xd6, 0xc3,
0xf2, 0x47, 0xdd, 0xa0, 0xbd, 0x00, 0x7b, 0x5a, 0xf2, 0x29, 0xab, 0x2a, 0xfd, 0xa5, 0x4a, 0xff,
0x86, 0x91, 0x96, 0x0d, 0xc1, 0x77, 0x2a, 0x1f, 0x84, 0x21, 0xe7, 0xf3, 0x72, 0x4a, 0x64, 0xbf,
0x7a, 0xb3, 0x8e, 0x6a, 0xb6, 0x3f, 0x78, 0xb3, 0xd1, 0xc9, 0xd9, 0xe9, 0xa5, 0xa5, 0xee, 0x67,
0x6e, 0x1e, 0xa1, 0xea, 0xd8, 0x17, 0x6e, 0x1e, 0xf7, 0x20, 0xb5, 0xab, 0x2f, 0xa3, 0x77, 0x8e,
0xf8, 0x6c, 0xcc, 0xf2, 0x64, 0xf0, 0x7d, 0xff, 0x0a, 0x2d, 0x9f, 0x0d, 0xeb, 0x3f, 0x1b, 0xa3,
0x77, 0x28, 0xb1, 0xbd, 0x04, 0xb8, 0xc7, 0x2e, 0x16, 0xb3, 0xb1, 0x88, 0x05, 0xb8, 0x04, 0x28,
0xff, 0x3e, 0xac, 0x05, 0xc4, 0x25, 0x40, 0x0f, 0x00, 0xf6, 0x26, 0x25, 0x63, 0xa8, 0xbd, 0x5a,
0x10, 0xb4, 0xa7, 0x01, 0x9b, 0x45, 0x18, 0x7b, 0x75, 0xa2, 0x0e, 0x2f, 0xed, 0x59, 0x1d, 0x29,
0x25, 0xb2, 0x88, 0x36, 0x65, 0x07, 0xb7, 0xaa, 0xbe, 0xfc, 0xea, 0xc8, 0x62, 0x3e, 0x8f, 0xcb,
0x15, 0x18, 0xdc, 0xba, 0x96, 0x0e, 0x40, 0x0c, 0x6e, 0x14, 0xb4, 0xb3, 0xb6, 0x69, 0xe6, 0xe9,
0xf5, 0x01, 0x2f, 0xf9, 0x42, 0xa4, 0x39, 0x83, 0x5f, 0x9e, 0x30, 0x0d, 0xea, 0x32, 0xc4, 0xac,
0xa5, 0x58, 0x9b, 0xe5, 0x4a, 0x42, 0xdd, 0x27, 0x94, 0x1f, 0xcf, 0xae, 0x04, 0x2f, 0xe1, 0xf3,
0x44, 0x65, 0x05, 0x42, 0x44, 0x96, 0x4b, 0xc2, 0xa0, 0xef, 0x4f, 0xd3, 0x7c, 0x86, 0xf6, 0xfd,
0xa9, 0xfb, 0xf5, 0xd7, 0x7b, 0x34, 0x60, 0x27, 0x94, 0x6a, 0x34, 0x35, 0x01, 0xf4, 0xbb, 0x9c,
0x68, 0xa3, 0xbb, 0x04, 0x31, 0xa1, 0x70, 0x12, 0xb8, 0x7a, 0x55, 0xb0, 0x9c, 0x25, 0xcd, 0xad,
0x39, 0xcc, 0x95, 0x47, 0x04, 0x5d, 0x41, 0xd2, 0xc6, 0x22, 0x29, 0x3f, 0x5b, 0xe4, 0xa7, 0x25,
0xbf, 0x4c, 0x33, 0x56, 0x82, 0x58, 0xa4, 0xd4, 0x1d, 0x39, 0x11, 0x8b, 0x30, 0xce, 0x5e, 0xbf,
0x90, 0x52, 0xef, 0x0b, 0xf0, 0x93, 0x32, 0x9e, 0xc2, 0xeb, 0x17, 0xca, 0x46, 0x1b, 0x23, 0x4e,
0x06, 0x03, 0xb8, 0x93, 0xe8, 0x28, 0xd7, 0xf9, 0x4a, 0x8e, 0x0f, 0xfd, 0x2e, 0xa1, 0xfc, 0x26,
0x6a, 0x05, 0x12, 0x1d, 0x6d, 0x0e, 0x23, 0x89, 0x44, 0x27, 0xac, 0x61, 0x97, 0x12, 0xc9, 0x9d,
0xe8, 0x6b, 0x45, 0x60, 0x29, 0x51, 0x36, 0x1a, 0x21, 0xb1, 0x94, 0xb4, 0x20, 0x10, 0x90, 0x9a,
0x69, 0x30, 0x43, 0x03, 0x92, 0x91, 0x06, 0x03, 0x92, 0x4b, 0xd9, 0x40, 0x71, 0x98, 0xa7, 0x22,
0x8d, 0xb3, 0x31, 0x13, 0xa7, 0x71, 0x19, 0xcf, 0x99, 0x60, 0x25, 0x0c, 0x14, 0x1a, 0x19, 0x7a,
0x0c, 0x11, 0x28, 0x28, 0x56, 0x3b, 0xfc, 0x83, 0xe8, 0xbd, 0x7a, 0xdd, 0x67, 0xb9, 0xfe, 0xed,
0x9a, 0x97, 0xf2, 0x47, 0xaf, 0x06, 0xef, 0x1b, 0x1b, 0x63, 0x51, 0xb2, 0x78, 0xde, 0xd8, 0x7e,
0xd7, 0xfc, 0x5d, 0x82, 0x4f, 0xd7, 0xea, 0xf1, 0x7c, 0xc2, 0x45, 0x7a, 0x59, 0x6f, 0xb3, 0xf5,
0x1b, 0x44, 0x60, 0x3c, 0xbb, 0xe2, 0x61, 0xe0, 0x5b, 0x14, 0x18, 0x67, 0xe3, 0xb4, 0x2b, 0x3d,
0x63, 0x45, 0x06, 0xe3, 0xb4, 0xa7, 0x2d, 0x01, 0x22, 0x4e, 0xa3, 0xa0, 0x9d, 0x9c, 0xae, 0x78,
0xc2, 0xc2, 0x95, 0x99, 0xb0, 0x7e, 0x95, 0x99, 0x78, 0x2f, 0x65, 0x64, 0xd1, 0x7b, 0xc7, 0x6c,
0x7e, 0xc1, 0xca, 0xea, 0x2a, 0x2d, 0xa8, 0xef, 0xb6, 0x5a, 0xa2, 0xf3, 0xbb, 0xad, 0x04, 0x6a,
0x57, 0x02, 0x0b, 0x1c, 0x56, 0x27, 0xf1, 0x9c, 0xc9, 0x2f, 0x6b, 0x80, 0x95, 0xc0, 0x31, 0xe2,
0x40, 0xc4, 0x4a, 0x40, 0xc2, 0xce, 0xfb, 0x5d, 0x96, 0x39, 0x63, 0xb3, 0x7a, 0x84, 0x95, 0xa7,
0xf1, 0x6a, 0xce, 0x72, 0xa1, 0x4d, 0x82, 0x33, 0x79, 0xc7, 0x24, 0xce, 0x13, 0x67, 0xf2, 0x7d,
0xf4, 0x9c, 0xd0, 0xe4, 0x35, 0xfc, 0x29, 0x2f, 0x85, 0xfa, 0x65, 0xaa, 0xf3, 0x32, 0x03, 0xa1,
0xc9, 0x6f, 0x54, 0x8f, 0x24, 0x42, 0x53, 0x58, 0xc3, 0xf9, 0x15, 0x02, 0xaf, 0x0c, 0xaf, 0x59,
0x69, 0xc6, 0xc9, 0xcb, 0x79, 0x9c, 0x66, 0x7a, 0x34, 0xfc, 0x30, 0x60, 0x9b, 0xd0, 0x21, 0x7e,
0x85, 0xa0, 0xaf, 0xae, 0xf3, 0xbb, 0x0d, 0xe1, 0x12, 0x82, 0x47, 0x04, 0x1d, 0xf6, 0x89, 0x47,
0x04, 0xdd, 0x5a, 0x76, 0xe7, 0x6e, 0x59, 0xc9, 0xad, 0x24, 0xb1, 0xcb, 0x13, 0x78, 0x5e, 0xe8,
0xd8, 0x04, 0x20, 0xb1, 0x73, 0x0f, 0x2a, 0xd8, 0xd4, 0xc0, 0x62, 0xfb, 0x69, 0x1e, 0x67, 0xe9,
0xcf, 0x60, 0x5a, 0xef, 0xd8, 0x69, 0x08, 0x22, 0x35, 0xc0, 0x49, 0xcc, 0xd5, 0x01, 0x13, 0x93,
0xb4, 0x0e, 0xfd, 0x8f, 0x02, 0xed, 0x26, 0x89, 0x6e, 0x57, 0x0e, 0xe9, 0x7c, 0xa3, 0x15, 0x36,
0xeb, 0xa8, 0x28, 0xc6, 0xf5, 0xaa, 0x7a, 0xc6, 0xa6, 0x2c, 0x2d, 0xc4, 0xe0, 0xb3, 0x70, 0x5b,
0x01, 0x9c, 0xb8, 0x68, 0xd1, 0x43, 0xcd, 0x79, 0x7c, 0x5f, 0xc7, 0x92, 0xb1, 0xfa, 0xc9, 0xc6,
0xf3, 0x8a, 0x95, 0x3a, 0xd1, 0x38, 0x60, 0x02, 0xcc, 0x4e, 0x87, 0x1b, 0x3a, 0x60, 0x5d, 0x51,
0x62, 0x76, 0x86, 0x35, 0xec, 0x61, 0x9f, 0xc3, 0xe9, 0x6f, 0x6e, 0xcb, 0xfb, 0x86, 0x5b, 0xa4,
0x31, 0x87, 0x22, 0x0e, 0xfb, 0x68, 0xda, 0x66, 0x6b, 0x6d, 0xb7, 0xa3, 0x7c, 0x75, 0x08, 0xaf,
0x4c, 0x20, 0x96, 0x24, 0x46, 0x64, 0x6b, 0x01, 0xdc, 0x39, 0x0c, 0x2f, 0x79, 0x9c, 0x4c, 0xe3,
0x4a, 0x9c, 0xc6, 0xab, 0x8c, 0xc7, 0x89, 0x5c, 0xd7, 0xe1, 0x61, 0x78, 0xc3, 0x0c, 0x5d, 0x88,
0x3a, 0x0c, 0xa7, 0x60, 0x37, 0x3b, 0x93, 0xbf, 0x44, 0xa9, 0xef, 0x72, 0xc2, 0xec, 0x4c, 0x96,
0x17, 0xde, 0xe3, 0x7c, 0x10, 0x86, 0xec, 0x3b, 0x68, 0x4a, 0x24, 0xd3, 0x90, 0x7b, 0x98, 0x8e,
0x97, 0x80, 0x7c, 0x14, 0x20, 0xec, 0x77, 0x29, 0xd4, 0xdf, 0x9b, 0x1f, 0x1f, 0x12, 0xfa, 0x4b,
0xd6, 0x5b, 0x98, 0xae, 0x0b, 0x0d, 0xdd, 0x0f, 0xdc, 0x6d, 0xf7, 0xa4, 0x6d, 0x9a, 0xb9, 0x7b,
0x15, 0x8b, 0x51, 0x92, 0x1c, 0xb3, 0x0a, 0x79, 0xa1, 0xbc, 0x16, 0x0e, 0xad, 0x94, 0x48, 0x33,
0xdb, 0x94, 0x1d, 0xe8, 0xb5, 0xec, 0x65, 0x92, 0x0a, 0x2d, 0x6b, 0x6e, 0x48, 0x6f, 0xb5, 0x0d,
0xb4, 0x29, 0xa2, 0x56, 0x34, 0x6d, 0x63, 0x79, 0xcd, 0x4c, 0xf8, 0x6c, 0x96, 0x31, 0x0d, 0x9d,
0xb1, 0x58, 0x7d, 0xc8, 0x6f, 0xa7, 0x6d, 0x0b, 0x05, 0x89, 0x58, 0x1e, 0x54, 0xb0, 0x69, 0x64,
0x8d, 0xa9, 0x47, 0x52, 0x4d, 0xc3, 0x6e, 0xb4, 0xcd, 0x78, 0x00, 0x91, 0x46, 0xa2, 0xa0, 0x7d,
0xef, 0xad, 0x16, 0x1f, 0xb0, 0xa6, 0x25, 0xe0, 0x27, 0x88, 0xa4, 0xb2, 0x23, 0x26, 0xde, 0x7b,
0x43, 0x30, 0xbb, 0x4f, 0x00, 0x1e, 0x5e, 0xac, 0x0e, 0x13, 0xb8, 0x4f, 0x80, 0xfa, 0x92, 0x21,
0xf6, 0x09, 0x14, 0xeb, 0x77, 0x9d, 0x39, 0xf7, 0x3a, 0x8a, 0x2b, 0x5b, 0x39, 0xa4, 0xeb, 0x50,
0x30, 0xd4, 0x75, 0x94, 0x82, 0xdf, 0xa4, 0xee, 0xd1, 0x1a, 0xd2, 0xa4, 0xd8, 0xb9, 0xda, 0x7a,
0x17, 0xe6, 0x24, 0x3e, 0x5e, 0x15, 0x27, 0x5c, 0x17, 0x43, 0xbf, 0xd7, 0x58, 0x81, 0xc4, 0xc7,
0x2f, 0x76, 0x8b, 0x26, 0x12, 0x9f, 0x6e, 0x2d, 0x1b, 0x27, 0xcd, 0xfe, 0x56, 0x5e, 0xa1, 0xc2,
0x7f, 0x51, 0x40, 0x09, 0x89, 0x38, 0xd9, 0x82, 0x94, 0xed, 0x17, 0x1f, 0xfd, 0xd7, 0xd7, 0x77,
0xd6, 0x7e, 0xf1, 0xf5, 0x9d, 0xb5, 0xff, 0xfd, 0xfa, 0xce, 0xda, 0xcf, 0xbf, 0xb9, 0xf3, 0xad,
0x5f, 0x7c, 0x73, 0xe7, 0x5b, 0xff, 0xf3, 0xcd, 0x9d, 0x6f, 0x7d, 0xf5, 0x8e, 0xfe, 0xc5, 0xe4,
0x8b, 0x5f, 0x91, 0xbf, 0x7b, 0xfc, 0xfc, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x5a, 0x7a, 0x62,
0x93, 0x55, 0x79, 0x00, 0x00,
}
// This is a compile-time assertion to ensure that this generated file
@ -401,6 +403,8 @@ 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
@ -1140,6 +1144,46 @@ 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 {
@ -6288,6 +6332,10 @@ 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":
@ -7114,6 +7162,34 @@ 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,16 +9,19 @@ 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/treearchive"
"github.com/anyproto/anytype-heart/core/debug/exporter"
"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"
@ -42,22 +45,20 @@ func main() {
return
}
fmt.Println("opening file...")
st := time.Now()
archive, err := treearchive.Open(*file)
var (
st = time.Now()
ctx = context.Background()
)
res, err := exporter.ImportStorage(ctx, *file)
if err != nil {
log.Fatal("can't open debug file:", err)
log.Fatal("can't import the tree:", err)
}
objectTree, err := res.CreateReadableTree(*fromRoot, "")
if err != nil {
log.Fatal("can't create readable tree:", err)
}
defer archive.Close()
fmt.Printf("open archive done in %.1fs\n", time.Since(st).Seconds())
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())
importer := exporter.NewTreeImporter(objectTree)
if *makeJson {
treeJson, err := importer.Json()
if err != nil {
@ -83,10 +84,11 @@ func main() {
}
fmt.Println("Change:")
fmt.Println(pbtypes.Sprint(ch.Model))
err = importer.Import(*fromRoot, ch.Id)
objectTree, err = res.CreateReadableTree(*fromRoot, ch.Id)
if err != nil {
log.Fatal("can't import the tree before", ch.Id, err)
log.Fatal("can't create readable tree:", err)
}
importer = exporter.NewTreeImporter(objectTree)
}
ot := importer.ObjectTree()
di, err := ot.Debug(state.ChangeParser{})
@ -126,12 +128,16 @@ func main() {
if *objectStore {
fmt.Println("fetch object store info..")
ls, err := archive.LocalStore()
f, err := os.Open(filepath.Join(res.FolderPath, "localstore.json"))
if err != nil {
fmt.Println("can't open objectStore info:", err)
} else {
fmt.Println(pbtypes.Sprint(ls))
log.Fatal("can't open objectStore info:", err)
}
defer f.Close()
info := &model.ObjectInfo{}
if err = jsonpb.Unmarshal(f, info); err != nil {
log.Fatal("can't unmarshal objectStore info:", err)
}
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.GetSpaceStorePath())
db, err := sql.Open("sqlite3", cfg.GetSqliteStorePath())
if err != nil {
fmt.Println("Error opening database:", err)
return

View file

@ -10,6 +10,7 @@ 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 {
@ -49,6 +50,35 @@ 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,
@ -64,6 +94,7 @@ 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,7 +10,6 @@ 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"
@ -392,7 +391,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 := liststorage.NewInMemoryAclListStorage(recs[0].Id, recs)
store, err := list.NewInMemoryStorage(recs[0].Id, recs)
if err != nil {
return domain.InviteView{}, convertedOrAclRequestError(err)
}

View file

@ -110,9 +110,12 @@ 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"
@ -208,6 +211,18 @@ 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,6 +43,7 @@ const (
const (
SpaceStoreBadgerPath = "spacestore"
SpaceStoreSqlitePath = "spaceStore.db"
SpaceStoreNewPath = "spaceStoreNew"
)
var (
@ -69,6 +70,7 @@ 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
@ -293,12 +295,27 @@ 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) GetSpaceStorePath() string {
return filepath.Join(c.RepoPath, "spaceStore.db")
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) GetTempDirPath() string {
@ -391,7 +408,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.NetworkId != "" && c.NetworkId != conf.NetworkId {
if !c.DisableNetworkIdCheck && 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,15 +31,23 @@ 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")
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")
)
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

@ -0,0 +1,218 @@
package application
import (
"context"
"errors"
"os"
"path/filepath"
"sync"
"github.com/anyproto/any-sync/app"
"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()
_ = m.wait()
}
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,16 +30,20 @@ type Service struct {
eventSender event.Sender
sessions session.Service
traceRecorder *traceRecorder
migrationManager *migrationManager
appAccountStartInProcessCancel context.CancelFunc
appAccountStartInProcessCancelMutex sync.Mutex
}
func New() *Service {
return &Service{
s := &Service{
sessions: session.New(),
traceRecorder: &traceRecorder{},
}
m := newMigrationManager(s)
s.migrationManager = m
return s
}
func (s *Service) GetApp() *app.App {

View file

@ -1,6 +1,7 @@
package block
import (
"context"
"encoding/json"
"fmt"
"net/http"
@ -22,6 +23,7 @@ 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))
}
@ -122,6 +124,44 @@ 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

@ -43,6 +43,7 @@ type StoreObject interface {
ToggleMessageReaction(ctx context.Context, messageId string, emoji string) error
DeleteMessage(ctx context.Context, messageId string) error
SubscribeLastMessages(ctx context.Context, subId string, limit int, asyncInit bool) ([]*model.ChatMessage, int, error)
MarkSeenHeads(heads []string)
Unsubscribe(subId string) error
}
@ -118,6 +119,10 @@ 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,72 +1,60 @@
package debug
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)
}
}
// 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)
// }
//
// }

View file

@ -135,6 +135,7 @@ func (ss *StoreState) Collection(ctx context.Context, name string) (anystore.Col
func (ss *StoreState) applyChangeSet(ctx context.Context, set ChangeSet) (err error) {
fmt.Println("PREV=", ss.id, " -- ", set.PrevOrderId)
fmt.Println("CURR derived=", ss.id, " -- ", lexId.Next(set.PrevOrderId))
fmt.Println("CURR=", ss.id, " -- ", set.Order)
for _, ch := range set.Changes {
applyErr := ss.applyChange(ctx, Change{

View file

@ -47,10 +47,6 @@ 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,9 +4,8 @@ import (
"sync"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/commonspace/spacestorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
"github.com/anyproto/anytype-heart/pkg/lib/localstore/objectstore"
)
const CName = "block.object.resolver"
@ -21,12 +20,12 @@ func New() Resolver {
}
type resolver struct {
storage storage.ClientStorage
objectStore objectstore.ObjectStore
sync.Mutex
}
func (r *resolver) Init(a *app.App) (err error) {
r.storage = a.MustComponent(spacestorage.CName).(storage.ClientStorage)
r.objectStore = a.MustComponent(objectstore.CName).(objectstore.ObjectStore)
return
}
@ -35,5 +34,5 @@ func (r *resolver) Name() (name string) {
}
func (r *resolver) ResolveSpaceID(objectID string) (string, error) {
return r.storage.GetSpaceID(objectID)
return r.objectStore.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.NewTestDerivedAcl("spaceId", keys)
aclList, err := list.NewInMemoryDerivedAcl("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.SpaceSettingsId()
t.spaceSettingsId = spaceStorage.StateStorage().SettingsId()
t.treeManager = app.MustComponent[treemanager.TreeManager](a)
t.nodeConf = app.MustComponent[nodeconf.NodeConf](a)
t.syncedTreeRemover = app.MustComponent[SyncedTreeRemover](a)

View file

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

View file

@ -11,7 +11,6 @@ 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"
@ -100,7 +99,7 @@ type BuildOptions struct {
func (b *BuildOptions) BuildTreeOpts() objecttreebuilder.BuildTreeOpts {
return objecttreebuilder.BuildTreeOpts{
Listener: b.Listener,
TreeBuilder: func(treeStorage treestorage.TreeStorage, aclList list.AclList) (objecttree.ObjectTree, error) {
TreeBuilder: func(treeStorage objecttree.Storage, aclList list.AclList) (objecttree.ObjectTree, error) {
ot, err := objecttree.BuildKeyFilterableObjectTree(treeStorage, aclList)
if err != nil {
return nil, err
@ -123,7 +122,7 @@ func (s *service) NewSource(ctx context.Context, space Space, id string, buildOp
if err != nil {
return nil, err
}
err = s.storageService.BindSpaceID(src.SpaceID(), src.Id())
err = s.objectStore.BindSpaceId(src.SpaceID(), src.Id())
if err != nil {
return nil, fmt.Errorf("store space id for object: %w", err)
}
@ -239,7 +238,7 @@ func (s *service) RegisterStaticSource(src Source) error {
s.mu.Lock()
defer s.mu.Unlock()
s.staticIds[src.Id()] = src
err := s.storageService.BindSpaceID(src.SpaceID(), src.Id())
err := s.objectStore.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/object/tree/treechangeproto"
"github.com/anyproto/any-sync/commonspace/objecttreebuilder"
"github.com/gogo/protobuf/proto"
"github.com/golang/snappy"
@ -32,6 +32,7 @@ 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 {
@ -50,6 +51,7 @@ type store struct {
store *storestate.StoreState
onUpdateHook func()
onPushChange PushChangeHook
diffManager *objecttree.DiffManager
}
func (s *store) GetFileKeysSnapshot() []*pb.ChangeFileKeys {
@ -60,6 +62,22 @@ 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,
})
}
onRemove := func(removed []string) {
for _, rem := range removed {
fmt.Println("[x]: removed", rem)
}
}
s.diffManager, err = objecttree.NewDiffManager(seenHeads, curTreeHeads, buildTree, onRemove)
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)
@ -89,7 +107,10 @@ 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
@ -135,12 +156,14 @@ func (s *store) PushStoreChange(ctx context.Context, params PushStoreChangeParam
IsEncrypted: true,
DataType: dataType,
Timestamp: params.Time.Unix(),
}, func(change *treechangeproto.RawTreeChangeWithId) error {
}, func(change objecttree.StorageChange) error {
order := tx.NextOrder(prevOrder)
fmt.Println("VALIDATE ", prevOrder, " ", change.OrderId, " ", order)
err = tx.ApplyChangeSet(storestate.ChangeSet{
Id: change.Id,
PrevOrderId: prevOrder,
Order: order,
Order: change.OrderId,
Changes: params.Changes,
Creator: s.accountService.AccountID(),
Timestamp: params.Time.Unix(),
@ -162,6 +185,14 @@ 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
}
@ -178,12 +209,17 @@ 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,62 +24,16 @@ type storeApply struct {
}
func (a *storeApply) Apply() (err error) {
maxOrder := a.tx.GetMaxOrder()
isEmpty := maxOrder == ""
prevOrderId := a.tx.GetMaxOrder()
iterErr := a.ot.IterateRoot(UnmarshalStoreChange, func(change *objecttree.Change) bool {
// not a new change - remember and continue
if !a.allIsNew && !change.IsNew && !isEmpty {
a.prevChange = change
a.prevOrder = ""
if !a.allIsNew && !change.IsNew {
return true
}
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, prevOrder, currOrder); err != nil {
if err = a.applyChange(prevOrderId, change); err != nil {
return false
}
a.prevOrder = currOrder
a.prevChange = change
prevOrderId = change.OrderId
return true
})
if err == nil && iterErr != nil {
@ -88,19 +42,19 @@ func (a *storeApply) Apply() (err error) {
return
}
func (a *storeApply) applyChange(change *objecttree.Change, prevOrder string, order string) (err error) {
func (a *storeApply) applyChange(prevOrderId string, change *objecttree.Change) (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, order)
return a.tx.SetOrder(change.Id, change.OrderId)
}
return fmt.Errorf("unexpected change content type: %T", change.Model)
}
set := storestate.ChangeSet{
Id: change.Id,
PrevOrderId: prevOrder,
Order: order,
PrevOrderId: prevOrderId,
Order: change.OrderId,
Changes: storeChange.ChangeSet,
Creator: change.Identity.Account(),
Timestamp: change.Timestamp,
@ -112,56 +66,3 @@ func (a *storeApply) applyChange(change *objecttree.Change, prevOrder string, or
}
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

@ -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) {
header, sErr := techSpace.Storage().SpaceHeader()
state, sErr := techSpace.Storage().StateStorage().GetState(ctx)
if sErr != nil {
return sErr
}
payload := coordinatorclient.SpaceSignPayload{
SpaceId: header.Id,
SpaceHeader: header.RawHeader,
SpaceId: techSpace.Id(),
SpaceHeader: state.SpaceHeader,
OldAccount: c.wallet.GetOldAccountKey(),
Identity: c.wallet.GetAccountPrivkey(),
}

View file

@ -0,0 +1,111 @@
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

@ -0,0 +1,96 @@
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

@ -1,13 +1,10 @@
package treearchive
package exporter
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"
@ -43,22 +40,18 @@ func (m MarshalledJsonChange) MarshalJSON() ([]byte, error) {
type TreeImporter interface {
ObjectTree() objecttree.ReadableObjectTree
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
State() (*state.State, error)
Json() (TreeJson, error)
ChangeAt(idx int) (IdChange, error)
}
type treeImporter struct {
listStorage liststorage.ListStorage
treeStorage treestorage.TreeStorage
objectTree objecttree.ReadableObjectTree
objectTree objecttree.ReadableObjectTree
}
func NewTreeImporter(listStorage liststorage.ListStorage, treeStorage treestorage.TreeStorage) TreeImporter {
func NewTreeImporter(objectTree objecttree.ReadableObjectTree) TreeImporter {
return &treeImporter{
listStorage: listStorage,
treeStorage: treeStorage,
objectTree: objectTree,
}
}
@ -83,25 +76,6 @@ 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

@ -1,99 +0,0 @@
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

@ -1,91 +0,0 @@
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,77 +0,0 @@
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

@ -1,59 +0,0 @@
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

@ -1,116 +0,0 @@
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

@ -1,110 +0,0 @@
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,7 +1,6 @@
package debug
import (
"archive/zip"
"bytes"
"context"
"fmt"
@ -11,14 +10,15 @@ import (
"path/filepath"
"time"
"github.com/anyproto/any-sync/commonspace/object/tree/exporter"
anystore "github.com/anyproto/any-store"
"github.com/anyproto/any-sync/commonspace/object/tree/objecttree"
"github.com/anyproto/anytype-heart/core/debug/treearchive"
"github.com/anyproto/anytype-heart/core/debug/exporter"
"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,66 +26,78 @@ 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) {
filename = filepath.Join(path, fmt.Sprintf("at.dbg.%s.%s.zip", e.id, time.Now().Format("20060102.150405.99")))
archiveWriter, err := treearchive.NewArchiveWriter(filename)
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)
if err != nil {
return
}
defer archiveWriter.Close()
e.zw = archiveWriter.ZipWriter()
params := exporter.TreeExporterParams{
ListStorageExporter: archiveWriter,
TreeStorageExporter: archiveWriter,
DataConverter: &changeDataConverter{anonymize: e.anonymized},
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},
}
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)
err = exporter.ExportTree(ctx, exportParams)
if err != nil {
e.log.Printf("export tree in zip error: %v", err)
return
}
err = anyStore.Checkpoint(ctx, true)
if err != nil {
return
}
logBuf := bytes.NewBuffer(nil)
e.log = stdlog.New(io.MultiWriter(logBuf, os.Stderr), "", stdlog.LstdFlags)
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 {
data[0].Details = transform(data[0].Details, e.anonymized, anonymize.Details)
// TODO: [storage] fix details, take from main
// data[0].Details = transform(data[0].Details, e.anonymized, anonymize.Struct)
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())
lsWr, er := e.zw.Create("localstore.json")
er := os.WriteFile(localStorePath, []byte(osData), 0644)
if er != nil {
e.log.Printf("create file in zip error: %v", er)
e.log.Printf("localstore.json write error: %v", err)
} else {
if _, err := lsWr.Write([]byte(osData)); err != nil {
e.log.Printf("localstore.json write error: %v", err)
} else {
e.log.Printf("localstore.json wrote")
}
e.log.Printf("localstore.json wrote")
}
} else {
e.log.Printf("not data in objectstore")
e.log.Printf("no data in objectstore")
}
}
logW, err := e.zw.Create("creation.log")
err = os.WriteFile(logPath, logBuf.Bytes(), 0644)
if err != nil {
return
}
io.Copy(logW, logBuf)
err = ziputil.ZipFolder(exportDirPath, filename)
return
}

View file

@ -140,7 +140,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, i.storageService)
spaceInd = newSpaceIndexer(i.runCtx, i.store.SpaceIndex(info.Space.Id()), i.store)
i.spaceIndexers[info.Space.Id()] = spaceInd
}
i.lock.Unlock()

View file

@ -7,6 +7,7 @@ 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"
@ -49,7 +50,7 @@ const (
)
type allDeletedIdsProvider interface {
AllDeletedTreeIds() (ids []string, err error)
AllDeletedTreeIds(ctx context.Context) (ids []string, err error)
}
func (i *indexer) buildFlags(spaceID string) (reindexFlags, error) {
@ -234,14 +235,11 @@ func (i *indexer) addSyncDetails(space clientspace.Space) {
func (i *indexer) reindexDeletedObjects(space clientspace.Space) error {
store := i.store.SpaceIndex(space.Id())
storage, ok := space.Storage().(allDeletedIdsProvider)
if !ok {
return fmt.Errorf("space storage doesn't implement allDeletedIdsProvider")
}
allIds, err := storage.AllDeletedTreeIds()
allIds, err := space.Storage().AllDeletedTreeIds(i.runCtx)
if err != nil {
return fmt.Errorf("get deleted tree ids: %w", err)
}
fmt.Println("[x]: deletedIds", len(allIds))
for _, objectId := range allIds {
err = store.DeleteObject(objectId)
if err != nil {
@ -425,35 +423,31 @@ 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())
tids := space.StoredIds()
var entries []headstorage.HeadsEntry
err = space.Storage().HeadStorage().IterateEntries(ctx, headstorage.IterOpts{}, func(entry headstorage.HeadsEntry) (bool, error) {
entries = append(entries, entry)
return true, nil
})
if err != nil {
return
}
var idsToReindex []string
for _, tid := range tids {
for _, entry := range entries {
id := entry.Id
logErr := func(err error) {
log.With("tree", tid).Errorf("reindexOutdatedObjects failed to get tree to reindex: %s", err)
log.With("tree", entry.Id).Errorf("reindexOutdatedObjects failed to get tree to reindex: %s", err)
}
lastHash, err := store.GetLastIndexedHeadsHash(ctx, tid)
lastHash, err := store.GetLastIndexedHeadsHash(ctx, id)
if err != nil {
logErr(err)
continue
}
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)
hh := headsHash(entry.Heads)
if lastHash != hh {
if lastHash != "" {
log.With("tree", tid).Warnf("not equal indexed heads hash: %s!=%s (%d logs)", lastHash, hh, len(heads))
log.With("tree", id).Warnf("not equal indexed heads hash: %s!=%s (%d logs)", lastHash, hh, len(entry.Heads))
}
idsToReindex = append(idsToReindex, tid)
idsToReindex = append(idsToReindex, id)
}
}

View file

@ -15,24 +15,21 @@ 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
storageService storage.ClientStorage
batcher *mb.MB[indexTask]
runCtx context.Context
spaceIndex spaceindex.Store
objectStore objectstore.ObjectStore
batcher *mb.MB[indexTask]
}
func newSpaceIndexer(runCtx context.Context, spaceIndex spaceindex.Store, objectStore objectstore.ObjectStore, storageService storage.ClientStorage) *spaceIndexer {
func newSpaceIndexer(runCtx context.Context, spaceIndex spaceindex.Store, objectStore objectstore.ObjectStore) *spaceIndexer {
ind := &spaceIndexer{
runCtx: runCtx,
spaceIndex: spaceIndex,
objectStore: objectStore,
storageService: storageService,
batcher: mb.New[indexTask](100),
runCtx: runCtx,
spaceIndex: spaceIndex,
objectStore: objectStore,
batcher: mb.New[indexTask](100),
}
go ind.indexBatchLoop()
return ind
@ -125,7 +122,7 @@ func (i *spaceIndexer) index(ctx context.Context, info smartblock.DocInfo, optio
for _, o := range options {
o(opts)
}
err := i.storageService.BindSpaceID(info.Space.Id(), info.Id)
err := i.objectStore.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

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

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.SpaceSettingsId()
s.spaceSettingsId = spaceStorage.StateStorage().SettingsId()
s.periodicSync = periodicsync.NewPeriodicSync(
s.updateIntervalSecs,
s.updateTimeout,

View file

@ -24,10 +24,16 @@ 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, code}
return errToCodeTuple[T]{err: err, code: code}
}
func errTypeToCode[T ~int32](errTypeProto any, code T) errToCodeTuple[T] {
return errToCodeTuple[T]{code: code, checkErrorType: errTypeProto}
}
func mapErrorCode[T ~int32](err error, mappings ...errToCodeTuple[T]) T {
@ -35,8 +41,15 @@ func mapErrorCode[T ~int32](err error, mappings ...errToCodeTuple[T]) T {
return 0
}
for _, m := range mappings {
if errors.Is(err, m.err) {
return m.code
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
}
}
}
// Unknown error

View file

@ -8,12 +8,20 @@ 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)
@ -23,12 +31,14 @@ func TestErrorCodeMapping(t *testing.T) {
errToCode(err1, testCode(2)),
errToCode(err2, testCode(3)),
errToCode(err3, testCode(4)),
errTypeToCode(&testErrorType{}, testCode(5)),
)
}
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))
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))
}

View file

@ -87,6 +87,14 @@
- [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)
@ -1293,6 +1301,8 @@
- [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)
@ -2027,6 +2037,8 @@
| 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) | |
@ -3470,6 +3482,119 @@ 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
@ -21018,6 +21143,35 @@ 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
@ -21113,6 +21267,7 @@ 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 | |

4
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.6
github.com/anyproto/any-sync v0.5.26
github.com/anyproto/any-sync v0.6.0-alpha.11
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20241223184559-a5cacfe0950a
github.com/anyproto/go-chash v0.1.0
github.com/anyproto/go-naturaldate/v2 v2.0.2-0.20230524105841-9829cfd13438
@ -109,6 +109,7 @@ require (
golang.org/x/mobile v0.0.0-20241108191957-fa514ef75a0f
golang.org/x/net v0.34.0
golang.org/x/oauth2 v0.25.0
golang.org/x/sys v0.29.0
golang.org/x/text v0.21.0
google.golang.org/grpc v1.70.0
gopkg.in/Graylog2/go-gelf.v2 v2.0.0-20180125164251-1832d8546a9f
@ -285,7 +286,6 @@ require (
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/time v0.9.0 // indirect
golang.org/x/tools v0.29.0 // indirect

4
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.6 h1:CmxIH2JhgHH2s7dnv1SNKAQ3spvX2amG/5RbrTZkLaQ=
github.com/anyproto/any-store v0.1.6/go.mod h1:nbyRoJYOlvSWU1xDOrmgPP96UeoTf4eYZ9k+qqLK9k8=
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/any-sync v0.6.0-alpha.11 h1:TwLkPTPaNmp78K7pmsb1X9CPR8oD5dWahjOGOxV50kY=
github.com/anyproto/any-sync v0.6.0-alpha.11/go.mod h1:JmjcChDSqgt6+G697YI3Yr57SZswxPJNX1arN//UYig=
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20241223184559-a5cacfe0950a h1:kSNyLHsZ40JxlRAglr85YXH2ik2LH3AH5Hd3JL42KGo=
github.com/anyproto/anytype-publish-server/publishclient v0.0.0-20241223184559-a5cacfe0950a/go.mod h1:4fkueCZcGniSMXkrwESO8zzERrh/L7WHimRNWecfGM0=
github.com/anyproto/badger/v4 v4.2.1-0.20240110160636-80743fa3d580 h1:Ba80IlCCxkZ9H1GF+7vFu/TSpPvbpDCxXJ5ogc4euYc=

File diff suppressed because it is too large Load diff

View file

@ -812,6 +812,54 @@ 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
@ -854,6 +902,7 @@ 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

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

View file

@ -36,6 +36,8 @@ 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

@ -26,346 +26,348 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
func init() { proto.RegisterFile("pb/protos/service/service.proto", fileDescriptor_93a29dc403579097) }
var fileDescriptor_93a29dc403579097 = []byte{
// 5412 bytes of a gzipped FileDescriptorProto
// 5445 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x9d, 0xdd, 0x6f, 0x24, 0x49,
0x52, 0xc0, 0xcf, 0x2f, 0x2c, 0xd4, 0x71, 0x0b, 0xf4, 0xc2, 0xb2, 0xb7, 0xdc, 0xcd, 0xcc, 0xce,
0xce, 0xd8, 0x33, 0x63, 0xbb, 0x3d, 0x3b, 0xb3, 0x1f, 0xa7, 0x3b, 0x24, 0xd4, 0x63, 0x8f, 0xbd,
0xbe, 0xb3, 0x3d, 0xc6, 0xdd, 0x9e, 0x91, 0x56, 0x42, 0x22, 0xdd, 0x95, 0x6e, 0x17, 0xae, 0xae,
0xbe, 0xb3, 0x3d, 0xc6, 0xdd, 0x9e, 0x91, 0x56, 0x42, 0xa2, 0xdc, 0x95, 0x6e, 0x17, 0xae, 0xae,
0xac, 0xab, 0xca, 0x6e, 0x4f, 0x1f, 0x02, 0x81, 0x40, 0x20, 0x10, 0x88, 0x13, 0x5f, 0xaf, 0x48,
0xfc, 0x35, 0x3c, 0xde, 0x23, 0x8f, 0x68, 0xf7, 0x0f, 0xe0, 0x9d, 0x27, 0x54, 0x59, 0x59, 0xf9,
0x11, 0x15, 0x91, 0x55, 0xbe, 0xa7, 0x19, 0x39, 0x7e, 0x11, 0x91, 0x9f, 0x91, 0x91, 0x59, 0x59,
0xd5, 0xd1, 0xdd, 0xfc, 0x62, 0x27, 0x2f, 0x84, 0x14, 0xe5, 0x4e, 0xc9, 0x8b, 0x65, 0x32, 0xe5,
0xcd, 0xbf, 0x43, 0xf5, 0xe7, 0xc1, 0x3b, 0x2c, 0x5b, 0xc9, 0x55, 0xce, 0x3f, 0xfc, 0xc0, 0x92,
0x53, 0x31, 0x9f, 0xb3, 0x2c, 0x2e, 0x6b, 0xe4, 0xc3, 0xf7, 0xad, 0x84, 0x2f, 0x79, 0x26, 0xf5,
0xdf, 0x9f, 0xfd, 0xdf, 0xff, 0xae, 0x45, 0xef, 0xee, 0xa6, 0x09, 0xcf, 0xe4, 0xae, 0xd6, 0x18,
0x7c, 0x15, 0x7d, 0x67, 0x94, 0xe7, 0x07, 0x5c, 0xbe, 0xe6, 0x45, 0x99, 0x88, 0x6c, 0xf0, 0xf1,
0x50, 0x3b, 0x18, 0x9e, 0xe5, 0xd3, 0xe1, 0x28, 0xcf, 0x87, 0x56, 0x38, 0x3c, 0xe3, 0x3f, 0x5d,
0xf0, 0x52, 0x7e, 0xf8, 0x20, 0x0c, 0x95, 0xb9, 0xc8, 0x4a, 0x3e, 0xb8, 0x8c, 0x7e, 0x6b, 0x94,
0xe7, 0x63, 0x2e, 0xf7, 0x78, 0x55, 0x81, 0xb1, 0x64, 0x92, 0x0f, 0x36, 0x5a, 0xaa, 0x3e, 0x60,
0x7c, 0x3c, 0xea, 0x06, 0xb5, 0x9f, 0x49, 0xf4, 0xed, 0xca, 0xcf, 0xd5, 0x42, 0xc6, 0xe2, 0x26,
0x1b, 0x7c, 0xd4, 0x56, 0xd4, 0x22, 0x63, 0xfb, 0x7e, 0x08, 0xd1, 0x56, 0xdf, 0x44, 0xbf, 0xfe,
0x86, 0xa5, 0x29, 0x97, 0xbb, 0x05, 0xaf, 0x0a, 0xee, 0xeb, 0xd4, 0xa2, 0x61, 0x2d, 0x33, 0x76,
0x3f, 0x0e, 0x32, 0xda, 0xf0, 0x57, 0xd1, 0x77, 0x6a, 0xc9, 0x19, 0x9f, 0x8a, 0x25, 0x2f, 0x06,
0xa8, 0x96, 0x16, 0x12, 0x4d, 0xde, 0x82, 0xa0, 0xed, 0x5d, 0x91, 0x2d, 0x79, 0x21, 0x71, 0xdb,
0x5a, 0x18, 0xb6, 0x6d, 0x21, 0x6d, 0xfb, 0xef, 0xd6, 0xa2, 0xef, 0x8d, 0xa6, 0x53, 0xb1, 0xc8,
0xe4, 0x91, 0x98, 0xb2, 0xf4, 0x28, 0xc9, 0xae, 0x4f, 0xf8, 0xcd, 0xee, 0x55, 0xc5, 0x67, 0x33,
0x3e, 0x78, 0xee, 0xb7, 0x6a, 0x8d, 0x0e, 0x0d, 0x3b, 0x74, 0x61, 0xe3, 0xfb, 0xd3, 0xdb, 0x29,
0xe9, 0xb2, 0xfc, 0xd3, 0x5a, 0x74, 0x07, 0x96, 0x65, 0x2c, 0xd2, 0x25, 0xb7, 0xa5, 0xf9, 0xac,
0xc3, 0xb0, 0x8f, 0x9b, 0xf2, 0x7c, 0x7e, 0x5b, 0x35, 0x5d, 0xa2, 0x34, 0x7a, 0xcf, 0x1d, 0x2e,
0x63, 0x5e, 0xaa, 0xe9, 0xf4, 0x98, 0x1e, 0x11, 0x1a, 0x31, 0x9e, 0x9f, 0xf4, 0x41, 0xb5, 0xb7,
0x24, 0x1a, 0x68, 0x6f, 0xa9, 0x28, 0x8d, 0xb3, 0x47, 0xa8, 0x05, 0x87, 0x30, 0xbe, 0x1e, 0xf7,
0x20, 0xb5, 0xab, 0x3f, 0x8e, 0x7e, 0xe3, 0x8d, 0x28, 0xae, 0xcb, 0x9c, 0x4d, 0xb9, 0x9e, 0x0a,
0x0f, 0x7d, 0xed, 0x46, 0x0a, 0x67, 0xc3, 0x7a, 0x17, 0xe6, 0x0c, 0xda, 0x46, 0xf8, 0x2a, 0xe7,
0x30, 0x06, 0x59, 0xc5, 0x4a, 0x48, 0x0d, 0x5a, 0x08, 0x69, 0xdb, 0xd7, 0xd1, 0xc0, 0xda, 0xbe,
0xf8, 0x13, 0x3e, 0x95, 0xa3, 0x38, 0x86, 0xbd, 0x62, 0x75, 0x15, 0x31, 0x1c, 0xc5, 0x31, 0xd5,
0x2b, 0x38, 0xaa, 0x9d, 0xdd, 0x44, 0xef, 0x03, 0x67, 0x47, 0x49, 0xa9, 0x1c, 0x6e, 0x87, 0xad,
0x68, 0xcc, 0x38, 0x1d, 0xf6, 0xc5, 0xb5, 0xe3, 0xbf, 0x58, 0x8b, 0xbe, 0x8b, 0x78, 0x3e, 0xe3,
0x73, 0xb1, 0xe4, 0x83, 0xa7, 0xdd, 0xd6, 0x6a, 0xd2, 0xf8, 0xff, 0xe4, 0x16, 0x1a, 0xc8, 0x30,
0x19, 0xf3, 0x94, 0x4f, 0x25, 0x39, 0x4c, 0x6a, 0x71, 0xe7, 0x30, 0x31, 0x98, 0x33, 0xc3, 0x1a,
0xe1, 0x01, 0x97, 0xbb, 0x8b, 0xa2, 0xe0, 0x99, 0x24, 0xfb, 0xd2, 0x22, 0x9d, 0x7d, 0xe9, 0xa1,
0x48, 0x7d, 0x0e, 0xb8, 0x1c, 0xa5, 0x29, 0x59, 0x9f, 0x5a, 0xdc, 0x59, 0x1f, 0x83, 0x69, 0x0f,
0xd3, 0xe8, 0x37, 0x9d, 0x16, 0x93, 0x87, 0xd9, 0xa5, 0x18, 0xd0, 0x6d, 0xa1, 0xe4, 0xc6, 0xc7,
0x46, 0x27, 0x87, 0x54, 0xe3, 0xe5, 0xdb, 0x5c, 0x14, 0x74, 0xb7, 0xd4, 0xe2, 0xce, 0x6a, 0x18,
0x4c, 0x7b, 0xf8, 0xa3, 0xe8, 0x5d, 0x1d, 0x25, 0x9b, 0xf5, 0xec, 0x01, 0x1a, 0x42, 0xe1, 0x82,
0xf6, 0xb0, 0x83, 0xb2, 0xc1, 0x41, 0xcb, 0x74, 0xf0, 0xf9, 0x18, 0xd5, 0x03, 0xa1, 0xe7, 0x41,
0x18, 0x6a, 0xd9, 0xde, 0xe3, 0x29, 0x27, 0x6d, 0xd7, 0xc2, 0x0e, 0xdb, 0x06, 0xd2, 0xb6, 0x8b,
0xe8, 0x77, 0x4c, 0xb3, 0x54, 0xeb, 0xa8, 0x92, 0x57, 0x41, 0x7a, 0x93, 0xa8, 0xb7, 0x0b, 0x19,
0x5f, 0x5b, 0xfd, 0xe0, 0x56, 0x7d, 0xf4, 0x0c, 0xc4, 0xeb, 0x03, 0xe6, 0xdf, 0x83, 0x30, 0xa4,
0x6d, 0xff, 0xfd, 0x5a, 0xf4, 0x7d, 0x2d, 0x7b, 0x99, 0xb1, 0x8b, 0x94, 0xab, 0x25, 0xf1, 0x84,
0xcb, 0x1b, 0x51, 0x5c, 0x8f, 0x57, 0xd9, 0x94, 0x58, 0xfe, 0x71, 0xb8, 0x63, 0xf9, 0x27, 0x95,
0x74, 0x61, 0xfe, 0x34, 0xfa, 0xa0, 0x19, 0x14, 0x57, 0x2c, 0x9b, 0xf1, 0x1f, 0x97, 0x22, 0x1b,
0xe5, 0xc9, 0x28, 0x8e, 0x8b, 0xc1, 0x10, 0xef, 0x7a, 0xc8, 0x99, 0x12, 0xec, 0xf4, 0xe6, 0x9d,
0x74, 0x53, 0xb7, 0xb2, 0x14, 0x39, 0x4c, 0x37, 0x9b, 0xe6, 0x93, 0x22, 0xa7, 0xd2, 0x4d, 0x1f,
0x69, 0x59, 0x3d, 0xae, 0x62, 0x36, 0x6e, 0xf5, 0xd8, 0x0d, 0xd2, 0xf7, 0x43, 0x88, 0x8d, 0x99,
0x4d, 0x43, 0x89, 0xec, 0x32, 0x99, 0x9d, 0xe7, 0x71, 0x35, 0x87, 0x1e, 0xe3, 0x75, 0x76, 0x10,
0x22, 0x66, 0x12, 0xa8, 0xf6, 0xf6, 0x8f, 0x36, 0x2b, 0xd3, 0xf3, 0x78, 0xbf, 0x10, 0xf3, 0x23,
0x3e, 0x63, 0xd3, 0x95, 0x0e, 0x3e, 0x9f, 0x86, 0x66, 0x3d, 0xa4, 0x4d, 0x21, 0x3e, 0xbb, 0xa5,
0x96, 0x2e, 0xcf, 0x7f, 0xac, 0x45, 0x0f, 0xbc, 0x71, 0xa2, 0x07, 0x53, 0x5d, 0xfa, 0x51, 0x16,
0x9f, 0xf1, 0x52, 0xb2, 0x42, 0x0e, 0x7e, 0x18, 0x18, 0x03, 0x84, 0x8e, 0x29, 0xdb, 0x8f, 0x7e,
0x29, 0x5d, 0xdb, 0xeb, 0xe3, 0x2a, 0xaa, 0xea, 0xf8, 0xe3, 0xf7, 0xba, 0x92, 0xc0, 0xe8, 0x73,
0x3f, 0x84, 0xd8, 0x5e, 0x57, 0x82, 0xc3, 0x6c, 0x99, 0x48, 0x7e, 0xc0, 0x33, 0x5e, 0xb4, 0x7b,
0xbd, 0x56, 0xf5, 0x11, 0xa2, 0xd7, 0x09, 0xd4, 0x46, 0x3a, 0xcf, 0x9b, 0x59, 0x99, 0x37, 0x03,
0x46, 0x5a, 0x6b, 0xf3, 0x56, 0x3f, 0xd8, 0x6e, 0x2d, 0x1d, 0x9f, 0x67, 0x7c, 0x29, 0xae, 0xe1,
0xd6, 0xd2, 0x35, 0x51, 0x03, 0xc4, 0xd6, 0x12, 0x05, 0xed, 0xf2, 0xe9, 0xf8, 0x79, 0x9d, 0xf0,
0x1b, 0xb0, 0x7c, 0xba, 0xca, 0x95, 0x98, 0x58, 0x3e, 0x11, 0x4c, 0x7b, 0x38, 0x89, 0x7e, 0x4d,
0x09, 0x7f, 0x2c, 0x92, 0x6c, 0x70, 0x17, 0x51, 0xaa, 0x04, 0xc6, 0xea, 0x3d, 0x1a, 0x00, 0x25,
0xae, 0xfe, 0xba, 0xcb, 0xb2, 0x29, 0x4f, 0xd1, 0x12, 0x5b, 0x71, 0xb0, 0xc4, 0x1e, 0x66, 0xf3,
0x16, 0x25, 0xac, 0xe2, 0xd7, 0xf8, 0x8a, 0x15, 0x49, 0x36, 0x1b, 0x60, 0xba, 0x8e, 0x9c, 0xc8,
0x5b, 0x30, 0x0e, 0x0c, 0x61, 0xad, 0x38, 0xca, 0xf3, 0xa2, 0x0a, 0x8b, 0xd8, 0x10, 0xf6, 0x91,
0xe0, 0x10, 0x6e, 0xa1, 0xb8, 0xb7, 0x3d, 0x3e, 0x4d, 0x93, 0x2c, 0xe8, 0x4d, 0x23, 0x7d, 0xbc,
0x59, 0x14, 0x0c, 0xde, 0x23, 0xce, 0x96, 0xbc, 0xa9, 0x19, 0xd6, 0x32, 0x2e, 0x10, 0x1c, 0xbc,
0x00, 0xb4, 0x9b, 0x44, 0x25, 0x3e, 0x66, 0xd7, 0xbc, 0x6a, 0x60, 0x5e, 0x2d, 0xaa, 0x03, 0x4c,
0xdf, 0x23, 0x88, 0x4d, 0x22, 0x4e, 0x6a, 0x57, 0x8b, 0xe8, 0x7d, 0x25, 0x3f, 0x65, 0x85, 0x4c,
0xa6, 0x49, 0xce, 0xb2, 0x66, 0xf3, 0x81, 0xcd, 0xeb, 0x16, 0x65, 0x5c, 0x6e, 0xf7, 0xa4, 0xb5,
0xdb, 0x7f, 0x5f, 0x8b, 0x3e, 0x82, 0x7e, 0x4f, 0x79, 0x31, 0x4f, 0xd4, 0x1e, 0xb6, 0xac, 0x83,
0xf0, 0xe0, 0x8b, 0xb0, 0xd1, 0x96, 0x82, 0x29, 0xcd, 0x0f, 0x6e, 0xaf, 0x68, 0x33, 0xb1, 0xb1,
0xce, 0xeb, 0x5f, 0x15, 0x71, 0xeb, 0x8c, 0x67, 0xdc, 0x24, 0xeb, 0x4a, 0x48, 0x64, 0x62, 0x2d,
0x08, 0xcc, 0xf0, 0xf3, 0xac, 0x6c, 0xac, 0x63, 0x33, 0xdc, 0x8a, 0x83, 0x33, 0xdc, 0xc3, 0xec,
0x0c, 0x3f, 0x5d, 0x5c, 0xa4, 0x49, 0x79, 0x95, 0x64, 0x33, 0x9d, 0x76, 0xfb, 0xba, 0x56, 0x0c,
0x33, 0xef, 0x8d, 0x4e, 0x0e, 0x73, 0xa2, 0x07, 0x0b, 0xe9, 0x04, 0x0c, 0x93, 0x8d, 0x4e, 0xce,
0x6e, 0x4e, 0xac, 0xb4, 0xda, 0xb6, 0x82, 0xcd, 0x89, 0xa3, 0x5a, 0x49, 0x89, 0xcd, 0x49, 0x9b,
0xd2, 0xe6, 0x45, 0xf4, 0xdb, 0x6e, 0x1d, 0x4a, 0x91, 0x2e, 0xf9, 0x79, 0x91, 0x0c, 0x9e, 0xd0,
0xe5, 0x6b, 0x18, 0xe3, 0x6a, 0xb3, 0x17, 0x6b, 0x03, 0x95, 0x25, 0x0e, 0xb8, 0x1c, 0x4b, 0x26,
0x17, 0x25, 0x08, 0x54, 0x8e, 0x0d, 0x83, 0x10, 0x81, 0x8a, 0x40, 0xb5, 0xb7, 0x3f, 0x8c, 0xa2,
0x7a, 0xc7, 0xaf, 0x4e, 0x65, 0xfc, 0xb5, 0x47, 0x1f, 0x05, 0x78, 0x47, 0x32, 0x1f, 0x05, 0x08,
0x9b, 0xf0, 0xd4, 0x7f, 0x57, 0x87, 0x4d, 0x03, 0x54, 0x43, 0x89, 0x88, 0x84, 0x07, 0x20, 0xb0,
0xa0, 0xe3, 0x2b, 0x71, 0x83, 0x17, 0xb4, 0x92, 0x84, 0x0b, 0xaa, 0x09, 0x7b, 0xfc, 0xab, 0x0b,
0x8a, 0x1d, 0xff, 0x36, 0xc5, 0x08, 0x1d, 0xff, 0x42, 0xc6, 0x8e, 0x19, 0xd7, 0xf0, 0x0b, 0x21,
0xae, 0xe7, 0xac, 0xb8, 0x06, 0x63, 0xc6, 0x53, 0x6e, 0x18, 0x62, 0xcc, 0x50, 0xac, 0x1d, 0x33,
0xae, 0xc3, 0x2a, 0x5d, 0x3e, 0x2f, 0x52, 0x30, 0x66, 0x3c, 0x1b, 0x1a, 0x21, 0xc6, 0x0c, 0x81,
0xda, 0xe8, 0xe4, 0x7a, 0x1b, 0x73, 0x78, 0xe0, 0xe0, 0xa9, 0x8f, 0x39, 0x75, 0xe0, 0x80, 0x60,
0x70, 0x08, 0x1d, 0x14, 0x2c, 0xbf, 0xc2, 0x87, 0x90, 0x12, 0x85, 0x87, 0x50, 0x83, 0xc0, 0xfe,
0x1e, 0x73, 0x56, 0x4c, 0xaf, 0xf0, 0xfe, 0xae, 0x65, 0xe1, 0xfe, 0x36, 0x0c, 0xec, 0xef, 0x5a,
0xf0, 0x26, 0x91, 0x57, 0xc7, 0x5c, 0x32, 0xbc, 0xbf, 0x7d, 0x26, 0xdc, 0xdf, 0x2d, 0xd6, 0xe6,
0xe3, 0xae, 0xc3, 0xf1, 0xe2, 0xa2, 0x9c, 0x16, 0xc9, 0x05, 0x1f, 0x04, 0xac, 0x18, 0x88, 0xc8,
0xc7, 0x49, 0x58, 0xfb, 0xfc, 0xf9, 0x5a, 0x74, 0xb7, 0xe9, 0x76, 0x51, 0x96, 0x7a, 0xed, 0xf3,
0xdd, 0x7f, 0x86, 0xf7, 0x2f, 0x81, 0x13, 0x07, 0xf2, 0x3d, 0xd4, 0x9c, 0xdc, 0x00, 0x2f, 0xd2,
0x79, 0x56, 0x9a, 0x42, 0x7d, 0xd1, 0xc7, 0xba, 0xa3, 0x40, 0xe4, 0x06, 0xbd, 0x14, 0x6d, 0x5a,
0xa6, 0xfb, 0xa7, 0x91, 0x1d, 0xc6, 0x25, 0x48, 0xcb, 0x9a, 0xf6, 0x76, 0x08, 0x22, 0x2d, 0xc3,
0x49, 0x38, 0x14, 0x0e, 0x0a, 0xb1, 0xc8, 0xcb, 0x8e, 0xa1, 0x00, 0xa0, 0xf0, 0x50, 0x68, 0xc3,
0xda, 0xe7, 0xdb, 0xe8, 0x77, 0xdd, 0xe1, 0xe7, 0x36, 0xf6, 0x36, 0x3d, 0xa6, 0xb0, 0x26, 0x1e,
0xf6, 0xc5, 0x6d, 0x46, 0xd1, 0x78, 0x96, 0x7b, 0x5c, 0xb2, 0x24, 0x2d, 0x07, 0xeb, 0xb8, 0x8d,
0x46, 0x4e, 0x64, 0x14, 0x18, 0x07, 0xe3, 0xdb, 0xde, 0x22, 0x4f, 0x93, 0x69, 0xfb, 0x71, 0x88,
0xd6, 0x35, 0xe2, 0x70, 0x7c, 0x73, 0x31, 0x18, 0xaf, 0xab, 0xd4, 0x4f, 0xfd, 0x67, 0xb2, 0xca,
0x39, 0x1e, 0xaf, 0x3d, 0x24, 0x1c, 0xaf, 0x21, 0x0a, 0xeb, 0x33, 0xe6, 0xf2, 0x88, 0xad, 0xc4,
0x82, 0x88, 0xd7, 0x46, 0x1c, 0xae, 0x8f, 0x8b, 0xd9, 0xbd, 0x81, 0xf1, 0x70, 0x98, 0x49, 0x5e,
0x64, 0x2c, 0xdd, 0x4f, 0xd9, 0xac, 0x1c, 0x10, 0x31, 0xc6, 0xa7, 0x88, 0xbd, 0x01, 0x4d, 0x23,
0xcd, 0x78, 0x58, 0xee, 0xb3, 0xa5, 0x28, 0x12, 0x49, 0x37, 0xa3, 0x45, 0x3a, 0x9b, 0xd1, 0x43,
0x51, 0x6f, 0xa3, 0x62, 0x7a, 0x95, 0x2c, 0x79, 0x1c, 0xf0, 0xd6, 0x20, 0x3d, 0xbc, 0x39, 0x28,
0xd2, 0x69, 0x63, 0xb1, 0x28, 0xa6, 0x9c, 0xec, 0xb4, 0x5a, 0xdc, 0xd9, 0x69, 0x06, 0xd3, 0x1e,
0xfe, 0x7a, 0x2d, 0xfa, 0xbd, 0x5a, 0xea, 0x3e, 0xa3, 0xd8, 0x63, 0xe5, 0xd5, 0x85, 0x60, 0x45,
0x3c, 0xf8, 0x04, 0xb3, 0x83, 0xa2, 0xc6, 0xf5, 0xb3, 0xdb, 0xa8, 0xc0, 0x66, 0xad, 0xf2, 0x6e,
0x3b, 0xe3, 0xd0, 0x66, 0xf5, 0x90, 0x70, 0xb3, 0x42, 0x14, 0x06, 0x10, 0x25, 0xaf, 0x8f, 0xe4,
0xd6, 0x49, 0x7d, 0xff, 0x5c, 0x6e, 0xa3, 0x93, 0x83, 0xf1, 0xb1, 0x12, 0xfa, 0xa3, 0x65, 0x9b,
0xb2, 0x81, 0x8f, 0x98, 0x61, 0x5f, 0x9c, 0xf4, 0x6c, 0x66, 0x45, 0xd8, 0x73, 0x6b, 0x66, 0x0c,
0xfb, 0xe2, 0x84, 0x67, 0x27, 0xac, 0x85, 0x3c, 0x23, 0xa1, 0x6d, 0xd8, 0x17, 0x87, 0xd9, 0x97,
0x66, 0x9a, 0x75, 0xe1, 0x49, 0xc0, 0x0e, 0x5c, 0x1b, 0x36, 0x7b, 0xb1, 0xda, 0xe1, 0xdf, 0xae,
0x45, 0xdf, 0xb3, 0x1e, 0x8f, 0x45, 0x9c, 0x5c, 0xae, 0x6a, 0xe8, 0x35, 0x4b, 0x17, 0xbc, 0x1c,
0x3c, 0xa3, 0xac, 0xb5, 0x59, 0x53, 0x82, 0xe7, 0xb7, 0xd2, 0x81, 0x73, 0x67, 0x94, 0xe7, 0xe9,
0x6a, 0xc2, 0xe7, 0x79, 0x4a, 0xce, 0x1d, 0x0f, 0x09, 0xcf, 0x1d, 0x88, 0xc2, 0xac, 0x7c, 0x22,
0xaa, 0x9c, 0x1f, 0xcd, 0xca, 0x95, 0x28, 0x9c, 0x95, 0x37, 0x08, 0xcc, 0x95, 0x26, 0x62, 0x57,
0xa4, 0x29, 0x9f, 0xca, 0xf6, 0x3d, 0x07, 0xa3, 0x69, 0x89, 0x70, 0xae, 0x04, 0x48, 0x7b, 0x2a,
0xd7, 0xec, 0x21, 0x59, 0xc1, 0x5f, 0xac, 0x8e, 0x92, 0xec, 0x7a, 0x80, 0xa7, 0x05, 0x16, 0x20,
0x4e, 0xe5, 0x50, 0x10, 0xee, 0x55, 0xcf, 0xb3, 0x58, 0xe0, 0x7b, 0xd5, 0x4a, 0x12, 0xde, 0xab,
0x6a, 0x02, 0x9a, 0x3c, 0xe3, 0x94, 0xc9, 0x4a, 0x12, 0x36, 0xa9, 0x09, 0x2c, 0x14, 0xea, 0x67,
0x37, 0x64, 0x28, 0x04, 0x4f, 0x6b, 0x36, 0x3a, 0x39, 0x38, 0x42, 0x9b, 0x4d, 0xeb, 0x3e, 0x97,
0xd3, 0x2b, 0x7c, 0x84, 0x7a, 0x48, 0x78, 0x84, 0x42, 0x14, 0x56, 0x69, 0x22, 0xcc, 0xa6, 0x7b,
0x1d, 0x1f, 0x1f, 0xad, 0x0d, 0xf7, 0x46, 0x27, 0x07, 0xb7, 0x91, 0x87, 0x73, 0xd5, 0x66, 0xe8,
0x20, 0xaf, 0x65, 0xe1, 0x6d, 0xa4, 0x61, 0x60, 0xe9, 0x6b, 0x81, 0x3a, 0xcb, 0x5a, 0xa7, 0x15,
0xbd, 0xd3, 0xac, 0x8d, 0x4e, 0x4e, 0x3b, 0xf9, 0x57, 0xb3, 0x8d, 0xab, 0xa5, 0x27, 0xa2, 0x9a,
0x23, 0xaf, 0x59, 0x9a, 0xc4, 0x4c, 0xf2, 0x89, 0xb8, 0xe6, 0x19, 0xbe, 0x63, 0xd2, 0xa5, 0xad,
0xf9, 0xa1, 0xa7, 0x10, 0xde, 0x31, 0x85, 0x15, 0xe1, 0x38, 0xa9, 0xe9, 0xf3, 0x92, 0xef, 0xb2,
0x92, 0x88, 0x64, 0x1e, 0x12, 0x1e, 0x27, 0x10, 0x85, 0xf9, 0x6a, 0x2d, 0x7f, 0xf9, 0x36, 0xe7,
0x45, 0xc2, 0xb3, 0x29, 0xc7, 0xf3, 0x55, 0x48, 0x85, 0xf3, 0x55, 0x84, 0x86, 0x7b, 0xb5, 0x3d,
0x26, 0xf9, 0x8b, 0xd5, 0x24, 0x99, 0xf3, 0x52, 0xb2, 0x79, 0x8e, 0xef, 0xd5, 0x00, 0x14, 0xde,
0xab, 0xb5, 0xe1, 0xd6, 0xd1, 0x90, 0x09, 0x88, 0xed, 0xeb, 0x51, 0x90, 0x08, 0x5c, 0x8f, 0x22,
0x50, 0xd8, 0xb0, 0x16, 0x40, 0x1f, 0x12, 0xb4, 0xac, 0x04, 0x1f, 0x12, 0xd0, 0x74, 0xeb, 0xc0,
0xcd, 0x30, 0xe3, 0x6a, 0x6a, 0x76, 0x14, 0x7d, 0xec, 0x4e, 0xd1, 0xcd, 0x5e, 0x2c, 0x7e, 0xc2,
0x77, 0xc6, 0x53, 0xa6, 0x96, 0xad, 0xc0, 0x31, 0x5a, 0xc3, 0xf4, 0x39, 0xe1, 0x73, 0x58, 0xed,
0xf0, 0x2f, 0xd7, 0xa2, 0x0f, 0x31, 0x8f, 0xaf, 0x72, 0xe5, 0xf7, 0x69, 0xb7, 0xad, 0x9a, 0x24,
0xee, 0x7f, 0x85, 0x35, 0xec, 0x95, 0x8c, 0x46, 0x64, 0xaf, 0x87, 0xe9, 0x02, 0xf8, 0x49, 0x9b,
0x29, 0x3f, 0xe4, 0x88, 0x2b, 0x19, 0x21, 0xde, 0xee, 0x87, 0xfc, 0x72, 0x95, 0x60, 0x3f, 0x64,
0x6c, 0x68, 0x31, 0xb1, 0x1f, 0x42, 0x30, 0x3b, 0x3b, 0xdd, 0xea, 0xbd, 0x49, 0xe4, 0x95, 0xca,
0xb7, 0xc0, 0xec, 0xf4, 0xca, 0x6a, 0x20, 0x62, 0x76, 0x92, 0x30, 0xcc, 0x48, 0x1a, 0xb0, 0x9a,
0x9b, 0x58, 0x2c, 0x37, 0x86, 0xdc, 0x99, 0xf9, 0xa8, 0x1b, 0x84, 0xe3, 0xb5, 0x11, 0xeb, 0xad,
0xcf, 0x93, 0x90, 0x05, 0xb0, 0xfd, 0xd9, 0xec, 0xc5, 0x6a, 0x87, 0x7f, 0x1e, 0x7d, 0xb7, 0x55,
0xb1, 0x7d, 0xce, 0xe4, 0xa2, 0xe0, 0xf1, 0x60, 0xa7, 0xa3, 0xdc, 0x0d, 0x68, 0x5c, 0x3f, 0xed,
0xaf, 0xd0, 0xca, 0xd1, 0x1b, 0xae, 0x1e, 0x56, 0xa6, 0x0c, 0xcf, 0x42, 0x26, 0x7d, 0x36, 0x98,
0xa3, 0xd3, 0x3a, 0xad, 0x6d, 0xb6, 0x3b, 0xba, 0x46, 0x4b, 0x96, 0xa4, 0xea, 0x61, 0xed, 0x27,
0x21, 0xa3, 0x1e, 0x1a, 0xdc, 0x66, 0x93, 0x2a, 0xad, 0xc8, 0xac, 0xe6, 0xb8, 0xb3, 0x3d, 0xdb,
0xa2, 0x23, 0x01, 0xb2, 0x3b, 0xdb, 0xee, 0x49, 0x6b, 0xb7, 0xb2, 0x59, 0xf2, 0xaa, 0x3f, 0xbb,
0x83, 0x1c, 0xf3, 0xaa, 0x55, 0x91, 0x91, 0xbe, 0xdd, 0x93, 0xd6, 0x5e, 0xff, 0x2c, 0xfa, 0xa0,
0xed, 0x55, 0x2f, 0x44, 0x3b, 0x9d, 0xa6, 0xc0, 0x5a, 0xf4, 0xb4, 0xbf, 0x82, 0xdd, 0xd2, 0x7c,
0x99, 0x94, 0x52, 0x14, 0xab, 0xf1, 0x95, 0xb8, 0x69, 0x5e, 0xbb, 0xf0, 0x67, 0xab, 0x06, 0x86,
0x0e, 0x41, 0x6c, 0x69, 0x70, 0xb2, 0xe5, 0xca, 0xbe, 0x9e, 0x51, 0x12, 0xae, 0x1c, 0xa2, 0xc3,
0x95, 0x4f, 0xda, 0x58, 0xd5, 0xd4, 0xca, 0xbe, 0x4b, 0xb2, 0x81, 0x17, 0xb5, 0xfd, 0x3e, 0xc9,
0xa3, 0x6e, 0xd0, 0x66, 0x2c, 0x5a, 0xbc, 0x97, 0x5c, 0x5e, 0x9a, 0x3a, 0xe1, 0x25, 0x75, 0x11,
0x22, 0x63, 0x21, 0x50, 0x9b, 0x74, 0xef, 0x27, 0x29, 0x57, 0x27, 0xfa, 0xaf, 0x2e, 0x2f, 0x53,
0xc1, 0x62, 0x90, 0x74, 0x57, 0xe2, 0xa1, 0x2b, 0x27, 0x92, 0x6e, 0x8c, 0xb3, 0x77, 0x05, 0x2a,
0xe9, 0x19, 0x9f, 0x8a, 0x6c, 0x9a, 0xa4, 0xf0, 0x16, 0xaa, 0xd2, 0x34, 0x42, 0xe2, 0xae, 0x40,
0x0b, 0xb2, 0x0b, 0x63, 0x25, 0xaa, 0xa6, 0x7d, 0x53, 0xfe, 0x87, 0x6d, 0x45, 0x47, 0x4c, 0x2c,
0x8c, 0x08, 0x66, 0xf7, 0x9e, 0x95, 0xf0, 0x3c, 0x57, 0xc6, 0xef, 0xb5, 0xb5, 0x6a, 0x09, 0xb1,
0xf7, 0xf4, 0x09, 0xbb, 0x87, 0xaa, 0xfe, 0xbe, 0x27, 0x6e, 0x32, 0x65, 0xf4, 0x7e, 0x5b, 0xa5,
0x91, 0x11, 0x7b, 0x28, 0xc8, 0x68, 0xc3, 0x3f, 0x89, 0x7e, 0x55, 0x19, 0x2e, 0x44, 0x3e, 0xb8,
0x83, 0x28, 0x14, 0xce, 0x9d, 0xcd, 0xbb, 0xa4, 0xdc, 0x5e, 0x2d, 0x30, 0x63, 0xe3, 0xbc, 0x64,
0x33, 0x3e, 0x78, 0x40, 0xf4, 0xb8, 0x92, 0x12, 0x57, 0x0b, 0xda, 0x94, 0x3f, 0x2a, 0x4e, 0x44,
0xac, 0xad, 0x23, 0x35, 0x34, 0xc2, 0xd0, 0xa8, 0x70, 0x21, 0x9b, 0xcc, 0x9c, 0xb0, 0x65, 0x32,
0x33, 0x0b, 0x4e, 0x1d, 0xb7, 0x4a, 0x90, 0xcc, 0x58, 0x66, 0xe8, 0x40, 0x44, 0x32, 0x43, 0xc2,
0xda, 0xe7, 0xbf, 0xac, 0x45, 0xf7, 0x2c, 0x73, 0xd0, 0x9c, 0xd6, 0x1d, 0x66, 0x97, 0xa2, 0x4a,
0x7d, 0x8e, 0x92, 0xec, 0xba, 0x1c, 0x7c, 0x4e, 0x99, 0xc4, 0x79, 0x53, 0x94, 0x2f, 0x6e, 0xad,
0x67, 0xb3, 0xd6, 0xe6, 0x28, 0xcb, 0x3e, 0xcf, 0xae, 0x35, 0x40, 0xd6, 0x6a, 0x4e, 0xbc, 0x20,
0x47, 0x64, 0xad, 0x21, 0xde, 0x76, 0xb1, 0x71, 0x9e, 0x8a, 0x0c, 0x76, 0xb1, 0xb5, 0x50, 0x09,
0x89, 0x2e, 0x6e, 0x41, 0x36, 0x1e, 0x37, 0xa2, 0xfa, 0xd4, 0x65, 0x94, 0xa6, 0x20, 0x1e, 0x1b,
0x55, 0x03, 0x10, 0xf1, 0x18, 0x05, 0xb5, 0x9f, 0xb3, 0xe8, 0xdb, 0x55, 0x93, 0x9e, 0x16, 0x7c,
0x99, 0x70, 0x78, 0xf5, 0xc2, 0x91, 0x10, 0xf3, 0xdf, 0x27, 0xec, 0xcc, 0x3a, 0xcf, 0xca, 0x3c,
0x65, 0xe5, 0x95, 0x7e, 0x18, 0xef, 0xd7, 0xb9, 0x11, 0xc2, 0xc7, 0xf1, 0x0f, 0x3b, 0x28, 0x1b,
0xd4, 0x1b, 0x99, 0x09, 0x31, 0xeb, 0xb8, 0x6a, 0x2b, 0xcc, 0x6c, 0x74, 0x72, 0xf6, 0xc4, 0xfb,
0x80, 0xa5, 0x29, 0x2f, 0x56, 0x8d, 0xec, 0x98, 0x65, 0xc9, 0x25, 0x2f, 0x25, 0x38, 0xf1, 0xd6,
0xd4, 0x10, 0x62, 0xc4, 0x89, 0x77, 0x00, 0xb7, 0xd9, 0x3c, 0xf0, 0x7c, 0x98, 0xc5, 0xfc, 0x2d,
0xc8, 0xe6, 0xa1, 0x1d, 0xc5, 0x10, 0xd9, 0x3c, 0xc5, 0xda, 0x93, 0xdf, 0x17, 0xa9, 0x98, 0x5e,
0xeb, 0x25, 0xc0, 0xef, 0x60, 0x25, 0x81, 0x6b, 0xc0, 0xfd, 0x10, 0x62, 0x17, 0x01, 0x25, 0x38,
0xe3, 0x79, 0xca, 0xa6, 0xf0, 0xfe, 0x4d, 0xad, 0xa3, 0x65, 0xc4, 0x22, 0x00, 0x19, 0x50, 0x5c,
0x7d, 0xaf, 0x07, 0x2b, 0x2e, 0xb8, 0xd6, 0x73, 0x3f, 0x84, 0xd8, 0x65, 0x50, 0x09, 0xc6, 0x79,
0x9a, 0x48, 0x30, 0x0d, 0x6a, 0x0d, 0x25, 0x21, 0xa6, 0x81, 0x4f, 0x00, 0x93, 0xc7, 0xbc, 0x98,
0x71, 0xd4, 0xa4, 0x92, 0x04, 0x4d, 0x36, 0x84, 0xbd, 0x6c, 0x5c, 0xd7, 0x5d, 0xe4, 0x2b, 0x70,
0xd9, 0x58, 0x57, 0x4b, 0xe4, 0x2b, 0xe2, 0xb2, 0xb1, 0x07, 0x80, 0x22, 0x9e, 0xb2, 0x52, 0xe2,
0x45, 0x54, 0x92, 0x60, 0x11, 0x1b, 0xc2, 0xae, 0xd1, 0x75, 0x11, 0x17, 0x12, 0xac, 0xd1, 0xba,
0x00, 0xce, 0x13, 0xe8, 0xbb, 0xa4, 0xdc, 0x46, 0x92, 0xba, 0x57, 0xb8, 0xdc, 0x4f, 0x78, 0x1a,
0x97, 0x20, 0x92, 0xe8, 0x76, 0x6f, 0xa4, 0x44, 0x24, 0x69, 0x53, 0x60, 0x28, 0xe9, 0xf3, 0x71,
0xac, 0x76, 0xe0, 0x68, 0xfc, 0x7e, 0x08, 0xb1, 0xf1, 0xa9, 0x29, 0xf4, 0x2e, 0x2b, 0x8a, 0xa4,
0x5a, 0xfc, 0xd7, 0xf1, 0x02, 0x35, 0x72, 0x22, 0x3e, 0x61, 0x1c, 0x98, 0x5e, 0x4d, 0xe0, 0xc6,
0x0a, 0x06, 0x43, 0xf7, 0xc7, 0x41, 0xc6, 0x66, 0x9c, 0x4a, 0xe2, 0x3c, 0x42, 0xc5, 0x5a, 0x13,
0x79, 0x82, 0xba, 0xde, 0x85, 0x39, 0x6f, 0x22, 0x19, 0x17, 0xc7, 0x62, 0xc9, 0x27, 0xe2, 0xe5,
0xdb, 0xa4, 0x94, 0x49, 0x36, 0xd3, 0x2b, 0xf7, 0x73, 0xc2, 0x12, 0x06, 0x13, 0x6f, 0x22, 0x75,
0x2a, 0xd9, 0x04, 0x02, 0x94, 0xe5, 0x84, 0xdf, 0xa0, 0x09, 0x04, 0xb4, 0x68, 0x38, 0x22, 0x81,
0x08, 0xf1, 0xf6, 0x1c, 0xc5, 0x38, 0xd7, 0xaf, 0x6b, 0x4f, 0x44, 0x93, 0xcb, 0x51, 0xd6, 0x20,
0x48, 0x6c, 0x65, 0x83, 0x0a, 0x76, 0x7f, 0x69, 0xfc, 0xdb, 0x29, 0xf6, 0x88, 0xb0, 0xd3, 0x9e,
0x66, 0x8f, 0x7b, 0x90, 0x88, 0x2b, 0x7b, 0x0f, 0x80, 0x72, 0xd5, 0xbe, 0x06, 0xf0, 0xb8, 0x07,
0xe9, 0x9c, 0xc9, 0xb8, 0xd5, 0x7a, 0xc1, 0xa6, 0xd7, 0xb3, 0x42, 0x2c, 0xb2, 0x78, 0x57, 0xa4,
0xa2, 0x00, 0x67, 0x32, 0x5e, 0xa9, 0x01, 0x4a, 0x9c, 0xc9, 0x74, 0xa8, 0xd8, 0x0c, 0xce, 0x2d,
0xc5, 0x28, 0x4d, 0x66, 0x70, 0x47, 0xed, 0x19, 0x52, 0x00, 0x91, 0xc1, 0xa1, 0x20, 0x32, 0x88,
0xea, 0x1d, 0xb7, 0x4c, 0xa6, 0x2c, 0xad, 0xfd, 0xed, 0xd0, 0x66, 0x3c, 0xb0, 0x73, 0x10, 0x21,
0x0a, 0x48, 0x3d, 0x27, 0x8b, 0x22, 0x3b, 0xcc, 0xa4, 0x20, 0xeb, 0xd9, 0x00, 0x9d, 0xf5, 0x74,
0x40, 0x10, 0x56, 0x27, 0xfc, 0x6d, 0x55, 0x9a, 0xea, 0x1f, 0x2c, 0xac, 0x56, 0x7f, 0x1f, 0x6a,
0x79, 0x28, 0xac, 0x02, 0x0e, 0x54, 0x46, 0x3b, 0xa9, 0x07, 0x4c, 0x40, 0xdb, 0x1f, 0x26, 0x8f,
0xba, 0x41, 0xdc, 0xcf, 0x58, 0xae, 0x52, 0x1e, 0xf2, 0xa3, 0x80, 0x3e, 0x7e, 0x1a, 0xd0, 0x1e,
0xb7, 0x78, 0xf5, 0xb9, 0xe2, 0xd3, 0xeb, 0xd6, 0xb5, 0x26, 0xbf, 0xa0, 0x35, 0x42, 0x1c, 0xb7,
0x10, 0x28, 0xde, 0x45, 0x87, 0x53, 0x91, 0x85, 0xba, 0xa8, 0x92, 0xf7, 0xe9, 0x22, 0xcd, 0xd9,
0xcd, 0xaf, 0x91, 0xea, 0x91, 0x59, 0x77, 0xd3, 0x26, 0x61, 0xc1, 0x85, 0x88, 0xcd, 0x2f, 0x09,
0xdb, 0x9c, 0x1c, 0xfa, 0x3c, 0x6e, 0xdf, 0xf9, 0x6e, 0x59, 0x39, 0xa6, 0xef, 0x7c, 0x53, 0x2c,
0x5d, 0xc9, 0x7a, 0x8c, 0x74, 0x58, 0xf1, 0xc7, 0xc9, 0x56, 0x3f, 0xd8, 0x6e, 0x79, 0x3c, 0x9f,
0xbb, 0x29, 0x67, 0x45, 0xed, 0x75, 0x3b, 0x60, 0xc8, 0x62, 0xc4, 0x96, 0x27, 0x80, 0x83, 0x10,
0xe6, 0x79, 0xde, 0x15, 0x99, 0xe4, 0x99, 0xc4, 0x42, 0x98, 0x6f, 0x4c, 0x83, 0xa1, 0x10, 0x46,
0x29, 0x80, 0x71, 0xab, 0xce, 0x83, 0xb8, 0x3c, 0x61, 0x73, 0x34, 0x63, 0xab, 0xcf, 0x7a, 0x6a,
0x79, 0x68, 0xdc, 0x02, 0xce, 0x79, 0xc8, 0xe7, 0x7a, 0x99, 0xb0, 0x62, 0x66, 0x4e, 0x37, 0xe2,
0xc1, 0x53, 0xda, 0x8e, 0x4f, 0x12, 0x0f, 0xf9, 0xc2, 0x1a, 0x20, 0xec, 0x1c, 0xce, 0xd9, 0xcc,
0xd4, 0x14, 0xa9, 0x81, 0x92, 0xb7, 0xaa, 0xfa, 0xa8, 0x1b, 0x04, 0x7e, 0x5e, 0x27, 0x31, 0x17,
0x01, 0x3f, 0x4a, 0xde, 0xc7, 0x0f, 0x04, 0x41, 0xf6, 0x56, 0xd5, 0xbb, 0xde, 0xd1, 0x8d, 0xb2,
0x58, 0xef, 0x63, 0x87, 0x44, 0xf3, 0x00, 0x2e, 0x94, 0xbd, 0x11, 0x3c, 0x98, 0xa3, 0xcd, 0x01,
0x6d, 0x68, 0x8e, 0x9a, 0xf3, 0xd7, 0x3e, 0x73, 0x14, 0x83, 0xb5, 0xcf, 0x9f, 0xe9, 0x39, 0xba,
0xc7, 0x24, 0xab, 0xf2, 0xf6, 0xd7, 0x09, 0xbf, 0xd1, 0x1b, 0x61, 0xa4, 0xbe, 0x0d, 0x35, 0x54,
0xaf, 0xac, 0x82, 0x5d, 0xf1, 0x4e, 0x6f, 0x3e, 0xe0, 0x5b, 0xef, 0x10, 0x3a, 0x7d, 0x83, 0xad,
0xc2, 0x4e, 0x6f, 0x3e, 0xe0, 0x5b, 0xbf, 0x0b, 0xdf, 0xe9, 0x1b, 0xbc, 0x10, 0xbf, 0xd3, 0x9b,
0xd7, 0xbe, 0xff, 0xaa, 0x99, 0xb8, 0xae, 0xf3, 0x2a, 0x0f, 0x9b, 0xca, 0x64, 0xc9, 0xb1, 0x74,
0xd2, 0xb7, 0x67, 0xd0, 0x50, 0x3a, 0x49, 0xab, 0x38, 0x5f, 0x6f, 0xc2, 0x4a, 0x71, 0x2a, 0xca,
0x44, 0x3d, 0xa4, 0x7f, 0xde, 0xc3, 0x68, 0x03, 0x87, 0x36, 0x4d, 0x21, 0x25, 0xfb, 0xb8, 0xd1,
0x43, 0xed, 0x2d, 0xe6, 0xad, 0x80, 0xbd, 0xf6, 0x65, 0xe6, 0xed, 0x9e, 0xb4, 0x7d, 0xf0, 0xe7,
0x31, 0xee, 0x13, 0xc7, 0x50, 0xaf, 0xa2, 0x0f, 0x1d, 0x9f, 0xf6, 0x57, 0xd0, 0xee, 0xff, 0xa6,
0xd9, 0x57, 0x40, 0xff, 0x7a, 0x12, 0x3c, 0xeb, 0x63, 0x11, 0x4c, 0x84, 0xe7, 0xb7, 0xd2, 0xd1,
0x05, 0xf9, 0x87, 0x66, 0x03, 0xdd, 0xa0, 0xea, 0x5d, 0x0e, 0xf5, 0x0e, 0xa8, 0x9e, 0x13, 0xa1,
0x6e, 0xb5, 0x30, 0x9c, 0x19, 0x9f, 0xdd, 0x52, 0xcb, 0xf9, 0x96, 0x97, 0x07, 0xeb, 0x77, 0x0e,
0x9d, 0xf2, 0x84, 0x2c, 0x3b, 0x34, 0x2c, 0xd0, 0xe7, 0xb7, 0x55, 0xa3, 0xe6, 0x8a, 0x03, 0xab,
0xaf, 0x73, 0x3c, 0xef, 0x69, 0xd8, 0xfb, 0x5e, 0xc7, 0xa7, 0xb7, 0x53, 0xd2, 0x65, 0xf9, 0xcf,
0xb5, 0xe8, 0xa1, 0xc7, 0xda, 0xe7, 0x09, 0xe0, 0xd4, 0xe3, 0x47, 0x01, 0xfb, 0x94, 0x92, 0x29,
0xdc, 0xef, 0xff, 0x72, 0xca, 0xf6, 0xc3, 0x57, 0x9e, 0xca, 0x7e, 0x92, 0x4a, 0x5e, 0xb4, 0x3f,
0x7c, 0xe5, 0xdb, 0xad, 0xa9, 0x21, 0xfd, 0xe1, 0xab, 0x00, 0xee, 0x7c, 0xf8, 0x0a, 0xf1, 0x8c,
0x7e, 0xf8, 0x0a, 0xb5, 0x16, 0xfc, 0xf0, 0x55, 0x58, 0x83, 0x0a, 0xef, 0x4d, 0x11, 0xea, 0x73,
0xeb, 0x5e, 0x16, 0xfd, 0x63, 0xec, 0x67, 0xb7, 0x51, 0x21, 0x16, 0xb8, 0x9a, 0x53, 0xf7, 0xdc,
0x7a, 0xb4, 0xa9, 0x77, 0xd7, 0x6d, 0xa7, 0x37, 0xaf, 0x7d, 0xff, 0x54, 0xef, 0x6e, 0x4c, 0x38,
0x17, 0x85, 0xfa, 0xe8, 0xd9, 0x66, 0x28, 0x3c, 0x57, 0x16, 0xdc, 0x9e, 0xdf, 0xea, 0x07, 0x13,
0xd5, 0xad, 0x08, 0xdd, 0xe9, 0xc3, 0x2e, 0x43, 0xa0, 0xcb, 0x77, 0x7a, 0xf3, 0xc4, 0x32, 0x52,
0xfb, 0xae, 0x7b, 0xbb, 0x87, 0x31, 0xbf, 0xaf, 0x9f, 0xf6, 0x57, 0xd0, 0xee, 0x97, 0x3a, 0x6d,
0x74, 0xdd, 0xab, 0x7e, 0xde, 0xee, 0x32, 0x35, 0xf6, 0xba, 0x79, 0xd8, 0x17, 0x0f, 0x25, 0x10,
0xee, 0x12, 0xda, 0x95, 0x40, 0xa0, 0xcb, 0xe8, 0xa7, 0xb7, 0x53, 0xd2, 0x65, 0xf9, 0xe7, 0xb5,
0xe8, 0x2e, 0x59, 0x16, 0x3d, 0x0e, 0x3e, 0xef, 0x6b, 0x19, 0x8c, 0x87, 0x2f, 0x6e, 0xad, 0xa7,
0x0b, 0xf5, 0x6f, 0x6b, 0xd1, 0xbd, 0x40, 0xa1, 0xea, 0x01, 0x72, 0x0b, 0xeb, 0xfe, 0x40, 0xf9,
0xc1, 0xed, 0x15, 0xa9, 0xe5, 0xde, 0xc5, 0xc7, 0xed, 0x8f, 0x32, 0x05, 0x6c, 0x8f, 0xe9, 0x8f,
0x32, 0x75, 0x6b, 0xc1, 0x43, 0x1e, 0x76, 0xd1, 0x6c, 0xba, 0xd0, 0x43, 0x1e, 0x75, 0x43, 0x2d,
0xf8, 0x71, 0x09, 0x8c, 0xc3, 0x9c, 0xbc, 0x7c, 0x9b, 0xb3, 0x2c, 0xa6, 0x9d, 0xd4, 0xf2, 0x6e,
0x27, 0x86, 0x83, 0x87, 0x63, 0x95, 0xf4, 0x4c, 0x34, 0x1b, 0xa9, 0xc7, 0x94, 0xbe, 0x41, 0x82,
0x87, 0x63, 0x2d, 0x94, 0xf0, 0xa6, 0xb3, 0xc6, 0x90, 0x37, 0x90, 0x2c, 0x3e, 0xe9, 0x83, 0x82,
0x14, 0xdd, 0x78, 0x33, 0x67, 0xee, 0x5b, 0x21, 0x2b, 0xad, 0x73, 0xf7, 0xed, 0x9e, 0x34, 0xe1,
0x76, 0xcc, 0xe5, 0x97, 0x9c, 0xc5, 0xbc, 0x08, 0xba, 0x35, 0x54, 0x2f, 0xb7, 0x2e, 0x8d, 0xb9,
0xdd, 0x15, 0xe9, 0x62, 0x9e, 0xe9, 0xce, 0x24, 0xdd, 0xba, 0x54, 0xb7, 0x5b, 0x40, 0xc3, 0x63,
0x41, 0xeb, 0x56, 0xa5, 0x97, 0x4f, 0xc2, 0x66, 0xbc, 0xac, 0x72, 0xb3, 0x17, 0x4b, 0xd7, 0x53,
0x0f, 0xa3, 0x8e, 0x7a, 0x82, 0x91, 0xb4, 0xdd, 0x93, 0x86, 0xe7, 0x73, 0x8e, 0x5b, 0x33, 0x9e,
0x76, 0x3a, 0x6c, 0xb5, 0x86, 0xd4, 0xd3, 0xfe, 0x0a, 0xf0, 0x34, 0x54, 0x8f, 0xaa, 0xa3, 0xa4,
0x94, 0xfb, 0x49, 0x9a, 0x0e, 0x36, 0x03, 0xc3, 0xa4, 0x81, 0x82, 0xa7, 0xa1, 0x08, 0x4c, 0x8c,
0xe4, 0xe6, 0xf4, 0x30, 0x1b, 0x74, 0xd9, 0x51, 0x54, 0xaf, 0x91, 0xec, 0xd2, 0xe0, 0x44, 0xcb,
0x69, 0x6a, 0x53, 0xdb, 0x61, 0xb8, 0xe1, 0x5a, 0x15, 0xde, 0xe9, 0xcd, 0x83, 0xc7, 0xed, 0x8a,
0x52, 0x2b, 0xcb, 0x03, 0xca, 0x84, 0xb7, 0x92, 0x3c, 0xec, 0xa0, 0xc0, 0xa9, 0x60, 0x3d, 0x8d,
0xde, 0x24, 0xf1, 0x8c, 0x4b, 0xf4, 0x49, 0x91, 0x0b, 0x04, 0x9f, 0x14, 0x01, 0x10, 0x74, 0x5d,
0xfd, 0x77, 0x73, 0x1c, 0x7a, 0x18, 0x63, 0x5d, 0xa7, 0x95, 0x1d, 0x2a, 0xd4, 0x75, 0x28, 0x0d,
0xa2, 0x81, 0x71, 0xab, 0x5f, 0xc7, 0x7f, 0x12, 0x32, 0x03, 0xde, 0xc9, 0xdf, 0xec, 0xc5, 0x82,
0x15, 0xc5, 0x3a, 0x4c, 0xe6, 0x89, 0xc4, 0x56, 0x14, 0xc7, 0x46, 0x85, 0x84, 0x56, 0x94, 0x36,
0x4a, 0x55, 0xaf, 0xca, 0x11, 0x0e, 0xe3, 0x70, 0xf5, 0x6a, 0xa6, 0x5f, 0xf5, 0x0c, 0xdb, 0x7a,
0xb0, 0x99, 0x99, 0x21, 0x23, 0xaf, 0xf4, 0x66, 0x19, 0x19, 0xdb, 0xea, 0x35, 0x4d, 0x08, 0x86,
0xa2, 0x0e, 0xa5, 0x00, 0x0f, 0xec, 0x2b, 0xae, 0x79, 0xf6, 0x9a, 0xe7, 0x9c, 0x15, 0x2c, 0x9b,
0xa2, 0x9b, 0x53, 0x65, 0xb0, 0x45, 0x86, 0x36, 0xa7, 0xa4, 0x06, 0x78, 0x6c, 0xee, 0xbf, 0x60,
0x89, 0x4c, 0x05, 0xf3, 0x26, 0xa3, 0xff, 0x7e, 0xe5, 0xe3, 0x1e, 0x24, 0x7c, 0x6c, 0xde, 0x00,
0xe6, 0xe0, 0xbb, 0x76, 0xfa, 0x49, 0xc0, 0x94, 0x8f, 0x86, 0x36, 0xc2, 0xb4, 0x0a, 0x18, 0xd4,
0x26, 0xc1, 0xe5, 0xf2, 0x27, 0x7c, 0x85, 0x0d, 0x6a, 0x9b, 0x9f, 0x2a, 0x24, 0x34, 0xa8, 0xdb,
0x28, 0xc8, 0x33, 0xdd, 0x7d, 0xd0, 0x7a, 0x40, 0xdf, 0xdd, 0xfa, 0x6c, 0x74, 0x72, 0x60, 0xe6,
0xec, 0x25, 0x4b, 0xef, 0x39, 0x01, 0x52, 0xd0, 0xbd, 0x64, 0x89, 0x3f, 0x26, 0xd8, 0xec, 0xc5,
0xc2, 0x47, 0xf2, 0x4c, 0xf2, 0xb7, 0xcd, 0xb3, 0x72, 0xa4, 0xb8, 0x4a, 0xde, 0x7a, 0x58, 0xfe,
0xa8, 0x1b, 0xb4, 0x17, 0x60, 0x4f, 0x0b, 0x31, 0xe5, 0x65, 0xa9, 0xbf, 0x54, 0xe9, 0xdf, 0x30,
0xd2, 0xb2, 0x21, 0xf8, 0x4e, 0xe5, 0x83, 0x30, 0xe4, 0x7c, 0x5e, 0xae, 0x16, 0xd9, 0xaf, 0xde,
0xac, 0xa3, 0x9a, 0xed, 0x0f, 0xde, 0x6c, 0x74, 0x72, 0x76, 0x7a, 0x69, 0xa9, 0xfb, 0x99, 0x9b,
0x47, 0xa8, 0x3a, 0xf6, 0x85, 0x9b, 0xc7, 0x3d, 0x48, 0xed, 0xea, 0xcb, 0xe8, 0x9d, 0x23, 0x31,
0x1b, 0xf3, 0x2c, 0x1e, 0x7c, 0xdf, 0xbf, 0x42, 0x2b, 0x66, 0xc3, 0xea, 0xcf, 0xc6, 0xe8, 0x1d,
0x4a, 0x6c, 0x2f, 0x01, 0xee, 0xf1, 0x8b, 0xc5, 0x6c, 0x2c, 0x99, 0x04, 0x97, 0x00, 0xd5, 0xdf,
0x87, 0x95, 0x80, 0xb8, 0x04, 0xe8, 0x01, 0xc0, 0xde, 0xa4, 0xe0, 0x1c, 0xb5, 0x57, 0x09, 0x82,
0xf6, 0x34, 0x60, 0xb3, 0x08, 0x63, 0xaf, 0x4a, 0xd4, 0xe1, 0xa5, 0x3d, 0xab, 0xa3, 0xa4, 0x44,
0x16, 0xd1, 0xa6, 0xec, 0xe0, 0xae, 0xab, 0xaf, 0xbe, 0x3a, 0xb2, 0x98, 0xcf, 0x59, 0xb1, 0x02,
0x83, 0x5b, 0xd7, 0xd2, 0x01, 0x88, 0xc1, 0x8d, 0x82, 0x76, 0xd6, 0x36, 0xcd, 0x3c, 0xbd, 0x3e,
0x10, 0x85, 0x58, 0xc8, 0x24, 0xe3, 0xf0, 0xcb, 0x13, 0xa6, 0x41, 0x5d, 0x86, 0x98, 0xb5, 0x14,
0x6b, 0xb3, 0x5c, 0x45, 0xd4, 0xf7, 0x09, 0xd5, 0xc7, 0xb3, 0x4b, 0x29, 0x0a, 0xf8, 0x3c, 0xb1,
0xb6, 0x02, 0x21, 0x22, 0xcb, 0x25, 0x61, 0xd0, 0xf7, 0xa7, 0x49, 0x36, 0x43, 0xfb, 0xfe, 0xd4,
0xfd, 0xfa, 0xeb, 0x3d, 0x1a, 0xb0, 0x13, 0xaa, 0x6e, 0xb4, 0x7a, 0x02, 0xe8, 0x77, 0x39, 0xd1,
0x46, 0x77, 0x09, 0x62, 0x42, 0xe1, 0x24, 0x70, 0xf5, 0x2a, 0xe7, 0x19, 0x8f, 0x9b, 0x5b, 0x73,
0x98, 0x2b, 0x8f, 0x08, 0xba, 0x82, 0xa4, 0x8d, 0x45, 0x4a, 0x7e, 0xb6, 0xc8, 0x4e, 0x0b, 0x71,
0x99, 0xa4, 0xbc, 0x00, 0xb1, 0xa8, 0x56, 0x77, 0xe4, 0x44, 0x2c, 0xc2, 0x38, 0x7b, 0xfd, 0x42,
0x49, 0xbd, 0x2f, 0xc0, 0x4f, 0x0a, 0x36, 0x85, 0xd7, 0x2f, 0x6a, 0x1b, 0x6d, 0x8c, 0x38, 0x19,
0x0c, 0xe0, 0x4e, 0xa2, 0x53, 0xbb, 0xce, 0x56, 0x6a, 0x7c, 0xe8, 0x77, 0x09, 0xd5, 0x37, 0x51,
0x4b, 0x90, 0xe8, 0x68, 0x73, 0x18, 0x49, 0x24, 0x3a, 0x61, 0x0d, 0xbb, 0x94, 0x28, 0xee, 0x44,
0x5f, 0x2b, 0x02, 0x4b, 0x49, 0x6d, 0xa3, 0x11, 0x12, 0x4b, 0x49, 0x0b, 0x02, 0x01, 0xa9, 0x99,
0x06, 0x33, 0x34, 0x20, 0x19, 0x69, 0x30, 0x20, 0xb9, 0x94, 0x0d, 0x14, 0x87, 0x59, 0x22, 0x13,
0x96, 0x8e, 0xb9, 0x3c, 0x65, 0x05, 0x9b, 0x73, 0xc9, 0x0b, 0x18, 0x28, 0x34, 0x32, 0xf4, 0x18,
0x22, 0x50, 0x50, 0xac, 0x76, 0xf8, 0x07, 0xd1, 0x7b, 0xd5, 0xba, 0xcf, 0x33, 0xfd, 0x5b, 0x2f,
0x2f, 0xd5, 0x8f, 0x44, 0x0d, 0xde, 0x37, 0x36, 0xc6, 0xb2, 0xe0, 0x6c, 0xde, 0xd8, 0x7e, 0xd7,
0xfc, 0x5d, 0x81, 0x4f, 0xd7, 0xaa, 0xf1, 0x7c, 0x22, 0x64, 0x72, 0x59, 0x6d, 0xb3, 0xf5, 0x1b,
0x44, 0x60, 0x3c, 0xbb, 0xe2, 0x61, 0xe0, 0x5b, 0x14, 0x18, 0x67, 0xe3, 0xb4, 0x2b, 0x3d, 0xe3,
0x79, 0x0a, 0xe3, 0xb4, 0xa7, 0xad, 0x00, 0x22, 0x4e, 0xa3, 0xa0, 0x9d, 0x9c, 0xae, 0x78, 0xc2,
0xc3, 0x95, 0x99, 0xf0, 0x7e, 0x95, 0x99, 0x78, 0x2f, 0x65, 0xa4, 0xd1, 0x7b, 0xc7, 0x7c, 0x7e,
0xc1, 0x8b, 0xf2, 0x2a, 0xc9, 0xa9, 0xef, 0xb6, 0x5a, 0xa2, 0xf3, 0xbb, 0xad, 0x04, 0x6a, 0x57,
0x02, 0x0b, 0x1c, 0x96, 0x27, 0x6c, 0xce, 0xd5, 0x97, 0x35, 0xc0, 0x4a, 0xe0, 0x18, 0x71, 0x20,
0x62, 0x25, 0x20, 0x61, 0xe7, 0xfd, 0x2e, 0xcb, 0x9c, 0xf1, 0x59, 0x35, 0xc2, 0x8a, 0x53, 0xb6,
0x9a, 0xf3, 0x4c, 0x6a, 0x93, 0xe0, 0x4c, 0xde, 0x31, 0x89, 0xf3, 0xc4, 0x99, 0x7c, 0x1f, 0x3d,
0x27, 0x34, 0x79, 0x0d, 0x7f, 0x2a, 0x0a, 0x59, 0xff, 0x92, 0xd3, 0x79, 0x91, 0x82, 0xd0, 0xe4,
0x37, 0xaa, 0x47, 0x12, 0xa1, 0x29, 0xac, 0xe1, 0xfc, 0x0a, 0x81, 0x57, 0x86, 0xd7, 0xbc, 0x30,
0xe3, 0xe4, 0xe5, 0x9c, 0x25, 0xa9, 0x1e, 0x0d, 0x3f, 0x0c, 0xd8, 0x26, 0x74, 0x88, 0x5f, 0x21,
0xe8, 0xab, 0xeb, 0xfc, 0x6e, 0x43, 0xb8, 0x84, 0xe0, 0x11, 0x41, 0x87, 0x7d, 0xe2, 0x11, 0x41,
0xb7, 0x96, 0xdd, 0xb9, 0x5b, 0x56, 0x71, 0x2b, 0x45, 0xec, 0x8a, 0x18, 0x9e, 0x17, 0x3a, 0x36,
0x01, 0x48, 0xec, 0xdc, 0x83, 0x0a, 0x36, 0x35, 0xb0, 0xd8, 0x7e, 0x92, 0xb1, 0x34, 0xf9, 0x19,
0x4c, 0xeb, 0x1d, 0x3b, 0x0d, 0x41, 0xa4, 0x06, 0x38, 0x89, 0xb9, 0x3a, 0xe0, 0x72, 0x92, 0x54,
0xa1, 0xff, 0x51, 0xa0, 0xdd, 0x14, 0xd1, 0xed, 0xca, 0x21, 0x9d, 0x6f, 0xb4, 0xc2, 0x66, 0x1d,
0xe5, 0xf9, 0xb8, 0x5a, 0x55, 0xcf, 0xf8, 0x94, 0x27, 0xb9, 0x1c, 0x7c, 0x16, 0x6e, 0x2b, 0x80,
0x13, 0x17, 0x2d, 0x7a, 0xa8, 0x39, 0x8f, 0xef, 0xab, 0x58, 0x32, 0xae, 0x7f, 0xe2, 0xf0, 0xbc,
0xe4, 0x85, 0x4e, 0x34, 0x0e, 0xb8, 0x04, 0xb3, 0xd3, 0xe1, 0x86, 0x0e, 0x58, 0x55, 0x94, 0x98,
0x9d, 0x61, 0x0d, 0x7b, 0xd8, 0xe7, 0x70, 0xfa, 0x9b, 0xdb, 0xea, 0xbe, 0xe1, 0x16, 0x69, 0xcc,
0xa1, 0x88, 0xc3, 0x3e, 0x9a, 0xb6, 0xd9, 0x5a, 0xdb, 0xed, 0x28, 0x5b, 0x1d, 0xc2, 0x2b, 0x13,
0x88, 0x25, 0x85, 0x11, 0xd9, 0x5a, 0x00, 0x77, 0x0e, 0xc3, 0x0b, 0xc1, 0xe2, 0x29, 0x2b, 0xe5,
0x29, 0x5b, 0xa5, 0x82, 0xc5, 0x6a, 0x5d, 0x87, 0x87, 0xe1, 0x0d, 0x33, 0x74, 0x21, 0xea, 0x30,
0x9c, 0x82, 0xdd, 0xec, 0x4c, 0xfd, 0x72, 0xa3, 0xbe, 0xcb, 0x09, 0xb3, 0x33, 0x55, 0x5e, 0x78,
0x8f, 0xf3, 0x41, 0x18, 0xb2, 0xef, 0xa0, 0xd5, 0x22, 0x95, 0x86, 0xdc, 0xc3, 0x74, 0xbc, 0x04,
0xe4, 0xa3, 0x00, 0x61, 0xbf, 0x4b, 0x51, 0xff, 0xbd, 0xf9, 0xf1, 0x21, 0xa9, 0xbf, 0x64, 0xbd,
0x85, 0xe9, 0xba, 0xd0, 0xd0, 0xfd, 0xc0, 0xdd, 0x76, 0x4f, 0xda, 0xa6, 0x99, 0xbb, 0x57, 0x4c,
0x8e, 0xe2, 0xf8, 0x98, 0x97, 0xc8, 0x0b, 0xe5, 0x95, 0x70, 0x68, 0xa5, 0x44, 0x9a, 0xd9, 0xa6,
0xec, 0x40, 0xaf, 0x64, 0x2f, 0xe3, 0x44, 0x6a, 0x59, 0x73, 0x43, 0x7a, 0xab, 0x6d, 0xa0, 0x4d,
0x11, 0xb5, 0xa2, 0x69, 0x1b, 0xcb, 0x2b, 0x66, 0x22, 0x66, 0xb3, 0x94, 0x6b, 0xe8, 0x8c, 0xb3,
0xfa, 0x43, 0x7e, 0x3b, 0x6d, 0x5b, 0x28, 0x48, 0xc4, 0xf2, 0xa0, 0x82, 0x4d, 0x23, 0x2b, 0xac,
0x7e, 0x24, 0xd5, 0x34, 0xec, 0x46, 0xdb, 0x8c, 0x07, 0x10, 0x69, 0x24, 0x0a, 0xda, 0xf7, 0xde,
0x2a, 0xf1, 0x01, 0x6f, 0x5a, 0x02, 0x7e, 0x82, 0x48, 0x29, 0x3b, 0x62, 0xe2, 0xbd, 0x37, 0x04,
0xb3, 0xfb, 0x04, 0xe0, 0xe1, 0xc5, 0xea, 0x30, 0x86, 0xfb, 0x04, 0xa8, 0xaf, 0x18, 0x62, 0x9f,
0x40, 0xb1, 0x7e, 0xd7, 0x99, 0x73, 0xaf, 0x23, 0x56, 0xda, 0xca, 0x21, 0x5d, 0x87, 0x82, 0xa1,
0xae, 0xa3, 0x14, 0xfc, 0x26, 0x75, 0x8f, 0xd6, 0x90, 0x26, 0xc5, 0xce, 0xd5, 0xd6, 0xbb, 0x30,
0x27, 0xf1, 0xf1, 0xaa, 0x38, 0x11, 0xba, 0x18, 0xfa, 0xbd, 0xc6, 0x12, 0x24, 0x3e, 0x7e, 0xb1,
0x5b, 0x34, 0x91, 0xf8, 0x74, 0x6b, 0xd9, 0x38, 0x69, 0xf6, 0xb7, 0xea, 0x0a, 0x15, 0xfe, 0x8b,
0x02, 0xb5, 0x90, 0x88, 0x93, 0x2d, 0xa8, 0xb6, 0xfd, 0xe2, 0xa3, 0xff, 0xfa, 0xfa, 0xce, 0xda,
0x2f, 0xbe, 0xbe, 0xb3, 0xf6, 0x3f, 0x5f, 0xdf, 0x59, 0xfb, 0xf9, 0x37, 0x77, 0xbe, 0xf5, 0x8b,
0x6f, 0xee, 0x7c, 0xeb, 0xbf, 0xbf, 0xb9, 0xf3, 0xad, 0xaf, 0xde, 0xd1, 0xbf, 0x30, 0x7c, 0xf1,
0x2b, 0xea, 0x77, 0x82, 0x9f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x92, 0xd1, 0x67, 0x07,
0x85, 0x78, 0x00, 0x00,
0xfc, 0x35, 0x88, 0xa7, 0x7b, 0xe4, 0x11, 0xed, 0xfe, 0x05, 0xfc, 0x07, 0xa8, 0x32, 0xb3, 0xf2,
0x23, 0x2a, 0x22, 0xab, 0x7c, 0x4f, 0x33, 0x72, 0xfc, 0x22, 0x22, 0x3f, 0x23, 0x23, 0xb3, 0xb2,
0xaa, 0xa3, 0xbb, 0xc5, 0xc5, 0x4e, 0x51, 0x72, 0xc1, 0xab, 0x9d, 0x8a, 0x95, 0xcb, 0x74, 0xca,
0x9a, 0x7f, 0x87, 0xf2, 0xcf, 0x83, 0x77, 0xe2, 0x7c, 0x25, 0x56, 0x05, 0xfb, 0xf0, 0x03, 0x4b,
0x4e, 0xf9, 0x7c, 0x1e, 0xe7, 0x49, 0xa5, 0x90, 0x0f, 0xdf, 0xb7, 0x12, 0xb6, 0x64, 0xb9, 0xd0,
0x7f, 0x7f, 0xf6, 0xdf, 0xff, 0xb7, 0x16, 0xbd, 0xbb, 0x9b, 0xa5, 0x2c, 0x17, 0xbb, 0x5a, 0x63,
0xf0, 0x55, 0xf4, 0x9d, 0x51, 0x51, 0x1c, 0x30, 0xf1, 0x9a, 0x95, 0x55, 0xca, 0xf3, 0xc1, 0xc7,
0x43, 0xed, 0x60, 0x78, 0x56, 0x4c, 0x87, 0xa3, 0xa2, 0x18, 0x5a, 0xe1, 0xf0, 0x8c, 0xfd, 0x74,
0xc1, 0x2a, 0xf1, 0xe1, 0x83, 0x30, 0x54, 0x15, 0x3c, 0xaf, 0xd8, 0xe0, 0x32, 0xfa, 0xad, 0x51,
0x51, 0x8c, 0x99, 0xd8, 0x63, 0x75, 0x05, 0xc6, 0x22, 0x16, 0x6c, 0xb0, 0xd1, 0x52, 0xf5, 0x01,
0xe3, 0xe3, 0x51, 0x37, 0xa8, 0xfd, 0x4c, 0xa2, 0x6f, 0xd7, 0x7e, 0xae, 0x16, 0x22, 0xe1, 0x37,
0xf9, 0xe0, 0xa3, 0xb6, 0xa2, 0x16, 0x19, 0xdb, 0xf7, 0x43, 0x88, 0xb6, 0xfa, 0x26, 0xfa, 0xf5,
0x37, 0x71, 0x96, 0x31, 0xb1, 0x5b, 0xb2, 0xba, 0xe0, 0xbe, 0x8e, 0x12, 0x0d, 0x95, 0xcc, 0xd8,
0xfd, 0x38, 0xc8, 0x68, 0xc3, 0x5f, 0x45, 0xdf, 0x51, 0x92, 0x33, 0x36, 0xe5, 0x4b, 0x56, 0x0e,
0x50, 0x2d, 0x2d, 0x24, 0x9a, 0xbc, 0x05, 0x41, 0xdb, 0xbb, 0x3c, 0x5f, 0xb2, 0x52, 0xe0, 0xb6,
0xb5, 0x30, 0x6c, 0xdb, 0x42, 0xda, 0xf6, 0xdf, 0xad, 0x45, 0xdf, 0x1b, 0x4d, 0xa7, 0x7c, 0x91,
0x8b, 0x23, 0x3e, 0x8d, 0xb3, 0xa3, 0x34, 0xbf, 0x3e, 0x61, 0x37, 0xbb, 0x57, 0x35, 0x9f, 0xcf,
0xd8, 0xe0, 0xb9, 0xdf, 0xaa, 0x0a, 0x1d, 0x1a, 0x76, 0xe8, 0xc2, 0xc6, 0xf7, 0xa7, 0xb7, 0x53,
0xd2, 0x65, 0xf9, 0xa7, 0xb5, 0xe8, 0x0e, 0x2c, 0xcb, 0x98, 0x67, 0x4b, 0x66, 0x4b, 0xf3, 0x59,
0x87, 0x61, 0x1f, 0x37, 0xe5, 0xf9, 0xfc, 0xb6, 0x6a, 0xba, 0x44, 0x59, 0xf4, 0x9e, 0x3b, 0x5c,
0xc6, 0xac, 0x92, 0xd3, 0xe9, 0x31, 0x3d, 0x22, 0x34, 0x62, 0x3c, 0x3f, 0xe9, 0x83, 0x6a, 0x6f,
0x69, 0x34, 0xd0, 0xde, 0x32, 0x5e, 0x19, 0x67, 0x8f, 0x50, 0x0b, 0x0e, 0x61, 0x7c, 0x3d, 0xee,
0x41, 0x6a, 0x57, 0x7f, 0x1c, 0xfd, 0xc6, 0x1b, 0x5e, 0x5e, 0x57, 0x45, 0x3c, 0x65, 0x7a, 0x2a,
0x3c, 0xf4, 0xb5, 0x1b, 0x29, 0x9c, 0x0d, 0xeb, 0x5d, 0x98, 0x33, 0x68, 0x1b, 0xe1, 0xab, 0x82,
0xc1, 0x18, 0x64, 0x15, 0x6b, 0x21, 0x35, 0x68, 0x21, 0xa4, 0x6d, 0x5f, 0x47, 0x03, 0x6b, 0xfb,
0xe2, 0x4f, 0xd8, 0x54, 0x8c, 0x92, 0x04, 0xf6, 0x8a, 0xd5, 0x95, 0xc4, 0x70, 0x94, 0x24, 0x54,
0xaf, 0xe0, 0xa8, 0x76, 0x76, 0x13, 0xbd, 0x0f, 0x9c, 0x1d, 0xa5, 0x95, 0x74, 0xb8, 0x1d, 0xb6,
0xa2, 0x31, 0xe3, 0x74, 0xd8, 0x17, 0xd7, 0x8e, 0xff, 0x62, 0x2d, 0xfa, 0x2e, 0xe2, 0xf9, 0x8c,
0xcd, 0xf9, 0x92, 0x0d, 0x9e, 0x76, 0x5b, 0x53, 0xa4, 0xf1, 0xff, 0xc9, 0x2d, 0x34, 0x90, 0x61,
0x32, 0x66, 0x19, 0x9b, 0x0a, 0x72, 0x98, 0x28, 0x71, 0xe7, 0x30, 0x31, 0x98, 0x33, 0xc3, 0x1a,
0xe1, 0x01, 0x13, 0xbb, 0x8b, 0xb2, 0x64, 0xb9, 0x20, 0xfb, 0xd2, 0x22, 0x9d, 0x7d, 0xe9, 0xa1,
0x48, 0x7d, 0x0e, 0x98, 0x18, 0x65, 0x19, 0x59, 0x1f, 0x25, 0xee, 0xac, 0x8f, 0xc1, 0xb4, 0x87,
0x69, 0xf4, 0x9b, 0x4e, 0x8b, 0x89, 0xc3, 0xfc, 0x92, 0x0f, 0xe8, 0xb6, 0x90, 0x72, 0xe3, 0x63,
0xa3, 0x93, 0x43, 0xaa, 0xf1, 0xf2, 0x6d, 0xc1, 0x4b, 0xba, 0x5b, 0x94, 0xb8, 0xb3, 0x1a, 0x06,
0xd3, 0x1e, 0xfe, 0x28, 0x7a, 0x57, 0x47, 0xc9, 0x66, 0x3d, 0x7b, 0x80, 0x86, 0x50, 0xb8, 0xa0,
0x3d, 0xec, 0xa0, 0x5a, 0xe6, 0x8f, 0xd3, 0x59, 0x59, 0x47, 0x1f, 0xdc, 0xbc, 0x96, 0x76, 0x98,
0xb7, 0x94, 0x36, 0xcf, 0xa3, 0xdf, 0xf6, 0xcd, 0xef, 0xc6, 0xf9, 0x94, 0x65, 0x83, 0x27, 0x21,
0x75, 0xc5, 0x18, 0x57, 0x9b, 0xbd, 0x58, 0x1b, 0xec, 0x34, 0xa1, 0x83, 0xe9, 0xc7, 0xa8, 0x36,
0x08, 0xa5, 0x0f, 0xc2, 0x50, 0xcb, 0xf6, 0x1e, 0xcb, 0x18, 0x69, 0x5b, 0x09, 0x3b, 0x6c, 0x1b,
0x48, 0xdb, 0x2e, 0xa3, 0xdf, 0x31, 0xdd, 0x5c, 0xe7, 0x05, 0x52, 0x5e, 0x2f, 0x3a, 0x9b, 0x44,
0x3f, 0xba, 0x90, 0xf1, 0xb5, 0xd5, 0x0f, 0x6e, 0xd5, 0x47, 0x47, 0x14, 0xbc, 0x3e, 0x20, 0x9e,
0x3c, 0x08, 0x43, 0xda, 0xf6, 0xdf, 0xaf, 0x45, 0xdf, 0xd7, 0xb2, 0x97, 0x79, 0x7c, 0x91, 0x31,
0xb9, 0xc4, 0x9f, 0x30, 0x71, 0xc3, 0xcb, 0xeb, 0xf1, 0x2a, 0x9f, 0x12, 0xe9, 0x0c, 0x0e, 0x77,
0xa4, 0x33, 0xa4, 0x92, 0x2e, 0xcc, 0x9f, 0x46, 0x1f, 0x34, 0x83, 0xe2, 0x2a, 0xce, 0x67, 0xec,
0xc7, 0x15, 0xcf, 0x47, 0x45, 0x3a, 0x4a, 0x92, 0x72, 0x30, 0xc4, 0xbb, 0x1e, 0x72, 0xa6, 0x04,
0x3b, 0xbd, 0x79, 0x27, 0x7d, 0xd6, 0xad, 0x2c, 0x78, 0x01, 0xd3, 0xe7, 0xa6, 0xf9, 0x04, 0x2f,
0xa8, 0xf4, 0xd9, 0x47, 0x5a, 0x56, 0x8f, 0xeb, 0x35, 0x08, 0xb7, 0x7a, 0xec, 0x2e, 0x3a, 0xf7,
0x43, 0x88, 0x5d, 0x03, 0x9a, 0x86, 0xe2, 0xf9, 0x65, 0x3a, 0x3b, 0x2f, 0x92, 0x7a, 0x0e, 0x3d,
0xc6, 0xeb, 0xec, 0x20, 0xc4, 0x1a, 0x40, 0xa0, 0xda, 0xdb, 0x3f, 0xda, 0x2c, 0x53, 0xc7, 0xa5,
0xfd, 0x92, 0xcf, 0x8f, 0xd8, 0x2c, 0x9e, 0xae, 0x74, 0x30, 0xfd, 0x34, 0x14, 0xc5, 0x20, 0x6d,
0x0a, 0xf1, 0xd9, 0x2d, 0xb5, 0x74, 0x79, 0xfe, 0x63, 0x2d, 0x7a, 0xe0, 0x8d, 0x13, 0x3d, 0x98,
0x54, 0xe9, 0x47, 0x79, 0x72, 0xc6, 0x2a, 0x11, 0x97, 0x62, 0xf0, 0xc3, 0xc0, 0x18, 0x20, 0x74,
0x4c, 0xd9, 0x7e, 0xf4, 0x4b, 0xe9, 0xda, 0x5e, 0x1f, 0xd7, 0xab, 0x84, 0x8e, 0x3f, 0x7e, 0xaf,
0x4b, 0x09, 0x8c, 0x3e, 0xf7, 0x43, 0x88, 0xed, 0x75, 0x29, 0x38, 0xcc, 0x97, 0xa9, 0x60, 0x07,
0x2c, 0x67, 0x65, 0xbb, 0xd7, 0x95, 0xaa, 0x8f, 0x10, 0xbd, 0x4e, 0xa0, 0x36, 0xd2, 0x79, 0xde,
0x4c, 0xa6, 0xb1, 0x19, 0x30, 0xd2, 0xca, 0x35, 0xb6, 0xfa, 0xc1, 0x76, 0xab, 0xec, 0xf8, 0x3c,
0x63, 0x4b, 0x7e, 0x0d, 0xb7, 0xca, 0xae, 0x09, 0x05, 0x10, 0x5b, 0x65, 0x14, 0xb4, 0xe9, 0x80,
0xe3, 0xe7, 0x75, 0xca, 0x6e, 0x40, 0x3a, 0xe0, 0x2a, 0xd7, 0x62, 0x22, 0x1d, 0x40, 0x30, 0xed,
0xe1, 0x24, 0xfa, 0x35, 0x29, 0xfc, 0x31, 0x4f, 0xf3, 0xc1, 0x5d, 0x44, 0xa9, 0x16, 0x18, 0xab,
0xf7, 0x68, 0x00, 0x94, 0xb8, 0xfe, 0xab, 0x5e, 0x9b, 0x1f, 0x12, 0x4a, 0x60, 0x59, 0x5e, 0xef,
0xc2, 0x6c, 0x1e, 0x26, 0x85, 0x75, 0xfc, 0x1a, 0x5f, 0xc5, 0x65, 0x9a, 0xcf, 0x06, 0x98, 0xae,
0x23, 0x27, 0xf2, 0x30, 0x8c, 0x03, 0x43, 0x58, 0x2b, 0x8e, 0x8a, 0xa2, 0xac, 0xc3, 0x22, 0x36,
0x84, 0x7d, 0x24, 0x38, 0x84, 0x5b, 0x28, 0xee, 0x6d, 0x8f, 0x4d, 0xb3, 0x34, 0x0f, 0x7a, 0xd3,
0x48, 0x1f, 0x6f, 0x16, 0x05, 0x83, 0xf7, 0x88, 0xc5, 0x4b, 0xd6, 0xd4, 0x0c, 0x6b, 0x19, 0x17,
0x08, 0x0e, 0x5e, 0x00, 0xda, 0x4d, 0xaf, 0x14, 0x1f, 0xc7, 0xd7, 0xac, 0x6e, 0x60, 0x56, 0x2f,
0xaa, 0x03, 0x4c, 0xdf, 0x23, 0x88, 0x4d, 0x2f, 0x4e, 0x6a, 0x57, 0x8b, 0xe8, 0x7d, 0x29, 0x3f,
0x8d, 0x4b, 0x91, 0x4e, 0xd3, 0x22, 0xce, 0x9b, 0xcd, 0x14, 0x36, 0xaf, 0x5b, 0x94, 0x71, 0xb9,
0xdd, 0x93, 0xd6, 0x6e, 0xff, 0x7d, 0x2d, 0xfa, 0x08, 0xfa, 0x3d, 0x65, 0xe5, 0x3c, 0x95, 0x7b,
0xf2, 0x4a, 0x05, 0xe1, 0xc1, 0x17, 0x61, 0xa3, 0x2d, 0x05, 0x53, 0x9a, 0x1f, 0xdc, 0x5e, 0xd1,
0x66, 0x62, 0x63, 0xbd, 0x4f, 0x79, 0x55, 0x26, 0xad, 0x33, 0xab, 0x71, 0xb3, 0xf9, 0x90, 0x42,
0x22, 0x13, 0x6b, 0x41, 0x60, 0x86, 0x9f, 0xe7, 0x55, 0x63, 0x1d, 0x9b, 0xe1, 0x56, 0x1c, 0x9c,
0xe1, 0x1e, 0x66, 0x67, 0xf8, 0xe9, 0xe2, 0x22, 0x4b, 0xab, 0xab, 0x34, 0x9f, 0xe9, 0xb4, 0xdb,
0xd7, 0xb5, 0x62, 0x98, 0x79, 0x6f, 0x74, 0x72, 0x98, 0x13, 0x3d, 0x58, 0x48, 0x27, 0x60, 0x98,
0x6c, 0x74, 0x72, 0x76, 0x37, 0x64, 0xa5, 0xf5, 0x36, 0x1c, 0xec, 0x86, 0x1c, 0xd5, 0x5a, 0x4a,
0xec, 0x86, 0xda, 0x94, 0xdd, 0x0d, 0xb9, 0x75, 0xa8, 0x78, 0xb6, 0x64, 0xe7, 0x65, 0x0a, 0x76,
0x43, 0x5e, 0xf9, 0x1a, 0x86, 0xd8, 0x0d, 0x51, 0xac, 0x0d, 0x54, 0x96, 0x38, 0x60, 0x62, 0x2c,
0x62, 0xb1, 0xa8, 0x40, 0xa0, 0x72, 0x6c, 0x18, 0x84, 0x08, 0x54, 0x04, 0xaa, 0xbd, 0xfd, 0x61,
0x14, 0xa9, 0x13, 0x0c, 0x79, 0xca, 0xe4, 0xaf, 0x3d, 0xfa, 0x68, 0xc3, 0x3b, 0x62, 0xfa, 0x28,
0x40, 0xd8, 0x84, 0x47, 0xfd, 0x5d, 0x1e, 0x9e, 0x0d, 0x50, 0x0d, 0x29, 0x22, 0x12, 0x1e, 0x80,
0xc0, 0x82, 0x8e, 0xaf, 0xf8, 0x0d, 0x5e, 0xd0, 0x5a, 0x12, 0x2e, 0xa8, 0x26, 0xec, 0x71, 0xb6,
0x2e, 0x28, 0x76, 0x9c, 0xdd, 0x14, 0x23, 0x74, 0x9c, 0x0d, 0x19, 0x3b, 0x66, 0x5c, 0xc3, 0x2f,
0x38, 0xbf, 0x9e, 0xc7, 0xe5, 0x35, 0x18, 0x33, 0x9e, 0x72, 0xc3, 0x10, 0x63, 0x86, 0x62, 0xed,
0x98, 0x71, 0x1d, 0xd6, 0xe9, 0xf2, 0x79, 0x99, 0x81, 0x31, 0xe3, 0xd9, 0xd0, 0x08, 0x31, 0x66,
0x08, 0xd4, 0x46, 0x27, 0xd7, 0xdb, 0x98, 0xc1, 0x03, 0x14, 0x4f, 0x7d, 0xcc, 0xa8, 0x03, 0x14,
0x04, 0x83, 0x43, 0xe8, 0xa0, 0x8c, 0x8b, 0x2b, 0x7c, 0x08, 0x49, 0x51, 0x78, 0x08, 0x35, 0x08,
0xec, 0xef, 0x31, 0x8b, 0xcb, 0xe9, 0x15, 0xde, 0xdf, 0x4a, 0x16, 0xee, 0x6f, 0xc3, 0xc0, 0xfe,
0x56, 0x82, 0x37, 0xa9, 0xb8, 0x3a, 0x66, 0x22, 0xc6, 0xfb, 0xdb, 0x67, 0xc2, 0xfd, 0xdd, 0x62,
0x6d, 0x3e, 0xee, 0x3a, 0x1c, 0x2f, 0x2e, 0xaa, 0x69, 0x99, 0x5e, 0xb0, 0x41, 0xc0, 0x8a, 0x81,
0x88, 0x7c, 0x9c, 0x84, 0xb5, 0xcf, 0x9f, 0xaf, 0x45, 0x77, 0x9b, 0x6e, 0xe7, 0x55, 0xa5, 0xd7,
0x3e, 0xdf, 0xfd, 0x67, 0x78, 0xff, 0x12, 0x38, 0xf1, 0x80, 0xa1, 0x87, 0x9a, 0x93, 0x1b, 0xe0,
0x45, 0x3a, 0xcf, 0x2b, 0x53, 0xa8, 0x2f, 0xfa, 0x58, 0x77, 0x14, 0x88, 0xdc, 0xa0, 0x97, 0xa2,
0x4d, 0xcb, 0x74, 0xff, 0x34, 0xb2, 0xc3, 0xa4, 0x02, 0x69, 0x59, 0xd3, 0xde, 0x0e, 0x41, 0xa4,
0x65, 0x38, 0x09, 0x87, 0xc2, 0x41, 0xc9, 0x17, 0x45, 0xd5, 0x31, 0x14, 0x00, 0x14, 0x1e, 0x0a,
0x6d, 0x58, 0xfb, 0x7c, 0x1b, 0xfd, 0xae, 0x3b, 0xfc, 0xdc, 0xc6, 0xde, 0xa6, 0xc7, 0x14, 0xd6,
0xc4, 0xc3, 0xbe, 0xb8, 0xcd, 0x28, 0x1a, 0xcf, 0x62, 0x8f, 0x89, 0x38, 0xcd, 0xaa, 0xc1, 0x3a,
0x6e, 0xa3, 0x91, 0x13, 0x19, 0x05, 0xc6, 0xc1, 0xf8, 0xb6, 0xb7, 0x28, 0xb2, 0x74, 0xda, 0x7e,
0xbc, 0xa3, 0x75, 0x8d, 0x38, 0x1c, 0xdf, 0x5c, 0x0c, 0xc6, 0xeb, 0x3a, 0xf5, 0x93, 0xff, 0x99,
0xac, 0x0a, 0x86, 0xc7, 0x6b, 0x0f, 0x09, 0xc7, 0x6b, 0x88, 0xc2, 0xfa, 0x8c, 0x99, 0x38, 0x8a,
0x57, 0x7c, 0x41, 0xc4, 0x6b, 0x23, 0x0e, 0xd7, 0xc7, 0xc5, 0xec, 0xde, 0xc0, 0x78, 0x38, 0xcc,
0x05, 0x2b, 0xf3, 0x38, 0xdb, 0xcf, 0xe2, 0x59, 0x35, 0x20, 0x62, 0x8c, 0x4f, 0x11, 0x7b, 0x03,
0x9a, 0x46, 0x9a, 0xf1, 0xb0, 0xda, 0x8f, 0x97, 0xbc, 0x4c, 0x05, 0xdd, 0x8c, 0x16, 0xe9, 0x6c,
0x46, 0x0f, 0x45, 0xbd, 0x8d, 0xca, 0xe9, 0x55, 0xba, 0x64, 0x49, 0xc0, 0x5b, 0x83, 0xf4, 0xf0,
0xe6, 0xa0, 0x48, 0xa7, 0x8d, 0xf9, 0xa2, 0x9c, 0x32, 0xb2, 0xd3, 0x94, 0xb8, 0xb3, 0xd3, 0x0c,
0xa6, 0x3d, 0xfc, 0xf5, 0x5a, 0xf4, 0x7b, 0x4a, 0xea, 0x3e, 0x73, 0xd9, 0x8b, 0xab, 0xab, 0x0b,
0x1e, 0x97, 0xc9, 0xe0, 0x13, 0xcc, 0x0e, 0x8a, 0x1a, 0xd7, 0xcf, 0x6e, 0xa3, 0x02, 0x9b, 0xb5,
0xce, 0xbb, 0xed, 0x8c, 0x43, 0x9b, 0xd5, 0x43, 0xc2, 0xcd, 0x0a, 0x51, 0x18, 0x40, 0xa4, 0x5c,
0x1d, 0xc9, 0xad, 0x93, 0xfa, 0xfe, 0xb9, 0xdc, 0x46, 0x27, 0x07, 0xe3, 0x63, 0x2d, 0xf4, 0x47,
0xcb, 0x36, 0x65, 0x03, 0x1f, 0x31, 0xc3, 0xbe, 0x38, 0xe9, 0xd9, 0xcc, 0x8a, 0xb0, 0xe7, 0xd6,
0xcc, 0x18, 0xf6, 0xc5, 0x09, 0xcf, 0x4e, 0x58, 0x0b, 0x79, 0x46, 0x42, 0xdb, 0xb0, 0x2f, 0x0e,
0xb3, 0x2f, 0xcd, 0x34, 0xeb, 0xc2, 0x93, 0x80, 0x1d, 0xb8, 0x36, 0x6c, 0xf6, 0x62, 0xb5, 0xc3,
0xbf, 0x5d, 0x8b, 0xbe, 0x67, 0x3d, 0x1e, 0xf3, 0x24, 0xbd, 0x5c, 0x29, 0xe8, 0x75, 0x9c, 0x2d,
0x58, 0x35, 0x78, 0x46, 0x59, 0x6b, 0xb3, 0xa6, 0x04, 0xcf, 0x6f, 0xa5, 0x03, 0xe7, 0xce, 0xa8,
0x28, 0xb2, 0xd5, 0x84, 0xcd, 0x8b, 0x8c, 0x9c, 0x3b, 0x1e, 0x12, 0x9e, 0x3b, 0x10, 0x85, 0x59,
0xf9, 0x84, 0xd7, 0x39, 0x3f, 0x9a, 0x95, 0x4b, 0x51, 0x38, 0x2b, 0x6f, 0x10, 0x98, 0x2b, 0x4d,
0xf8, 0x2e, 0xcf, 0x32, 0x36, 0x15, 0xed, 0x7b, 0x1b, 0x46, 0xd3, 0x12, 0xe1, 0x5c, 0x09, 0x90,
0xf6, 0x54, 0xae, 0xd9, 0x43, 0xc6, 0x25, 0x7b, 0xb1, 0x3a, 0x4a, 0xf3, 0xeb, 0x01, 0x9e, 0x16,
0x58, 0x80, 0x38, 0x95, 0x43, 0x41, 0xb8, 0x57, 0x3d, 0xcf, 0x13, 0x8e, 0xef, 0x55, 0x6b, 0x49,
0x78, 0xaf, 0xaa, 0x09, 0x68, 0xf2, 0x8c, 0x51, 0x26, 0x6b, 0x49, 0xd8, 0xa4, 0x26, 0xb0, 0x50,
0xa8, 0x9f, 0xdd, 0x90, 0xa1, 0x10, 0x3c, 0xad, 0xd9, 0xe8, 0xe4, 0xe0, 0x08, 0x6d, 0x36, 0xad,
0xfb, 0x4c, 0x4c, 0xaf, 0xf0, 0x11, 0xea, 0x21, 0xe1, 0x11, 0x0a, 0x51, 0x58, 0xa5, 0x09, 0x37,
0x9b, 0xee, 0x75, 0x7c, 0x7c, 0xb4, 0x36, 0xdc, 0x1b, 0x9d, 0x1c, 0xdc, 0x46, 0x1e, 0xce, 0x65,
0x9b, 0xa1, 0x83, 0x5c, 0xc9, 0xc2, 0xdb, 0x48, 0xc3, 0xc0, 0xd2, 0x2b, 0x81, 0x3c, 0xcb, 0x5a,
0xa7, 0x15, 0xbd, 0xd3, 0xac, 0x8d, 0x4e, 0x4e, 0x3b, 0xf9, 0x57, 0xb3, 0x8d, 0x53, 0xd2, 0x13,
0x5e, 0xcf, 0x91, 0xd7, 0x71, 0x96, 0x26, 0xb1, 0x60, 0x13, 0x7e, 0xcd, 0x72, 0x7c, 0xc7, 0xa4,
0x4b, 0xab, 0xf8, 0xa1, 0xa7, 0x10, 0xde, 0x31, 0x85, 0x15, 0xe1, 0x38, 0x51, 0xf4, 0x79, 0xc5,
0x76, 0xe3, 0x8a, 0x88, 0x64, 0x1e, 0x12, 0x1e, 0x27, 0x10, 0x85, 0xf9, 0xaa, 0x92, 0xbf, 0x7c,
0x5b, 0xb0, 0x32, 0x65, 0xf9, 0x94, 0xe1, 0xf9, 0x2a, 0xa4, 0xc2, 0xf9, 0x2a, 0x42, 0xc3, 0xbd,
0xda, 0x5e, 0x2c, 0xd8, 0x8b, 0xd5, 0x24, 0x9d, 0xb3, 0x4a, 0xc4, 0xf3, 0x02, 0xdf, 0xab, 0x01,
0x28, 0xbc, 0x57, 0x6b, 0xc3, 0xad, 0xa3, 0x21, 0x13, 0x10, 0xdb, 0xd7, 0xbd, 0x20, 0x11, 0xb8,
0xee, 0x45, 0xa0, 0xb0, 0x61, 0x2d, 0x80, 0x3e, 0x24, 0x68, 0x59, 0x09, 0x3e, 0x24, 0xa0, 0xe9,
0xd6, 0x81, 0x9b, 0x61, 0xc6, 0xf5, 0xd4, 0xec, 0x28, 0xfa, 0xd8, 0x9d, 0xa2, 0x9b, 0xbd, 0x58,
0xfc, 0x84, 0xef, 0x8c, 0x65, 0xb1, 0x5c, 0xb6, 0x02, 0xc7, 0x68, 0x0d, 0xd3, 0xe7, 0x84, 0xcf,
0x61, 0xb5, 0xc3, 0xbf, 0x5c, 0x8b, 0x3e, 0xc4, 0x3c, 0xbe, 0x2a, 0xa4, 0xdf, 0xa7, 0xdd, 0xb6,
0x14, 0x49, 0xdc, 0x67, 0x0b, 0x6b, 0xd8, 0x2b, 0x19, 0x8d, 0xc8, 0x5e, 0x77, 0xd3, 0x05, 0xf0,
0x93, 0x36, 0x53, 0x7e, 0xc8, 0x11, 0x57, 0x32, 0x42, 0xbc, 0xdd, 0x0f, 0xf9, 0xe5, 0xaa, 0xc0,
0x7e, 0xc8, 0xd8, 0xd0, 0x62, 0x62, 0x3f, 0x84, 0x60, 0x76, 0x76, 0xba, 0xd5, 0x7b, 0x93, 0x8a,
0x2b, 0x99, 0x6f, 0x81, 0xd9, 0xe9, 0x95, 0xd5, 0x40, 0xc4, 0xec, 0x24, 0x61, 0x98, 0x91, 0x34,
0x60, 0x3d, 0x37, 0xb1, 0x58, 0x6e, 0x0c, 0xb9, 0x33, 0xf3, 0x51, 0x37, 0x08, 0xc7, 0x6b, 0x23,
0xd6, 0x5b, 0x9f, 0x27, 0x21, 0x0b, 0x60, 0xfb, 0xb3, 0xd9, 0x8b, 0xd5, 0x0e, 0xff, 0x3c, 0xfa,
0x6e, 0xab, 0x62, 0xfb, 0x2c, 0x16, 0x8b, 0x92, 0x25, 0x83, 0x9d, 0x8e, 0x72, 0x37, 0xa0, 0x71,
0xfd, 0xb4, 0xbf, 0x42, 0x2b, 0x47, 0x6f, 0x38, 0x35, 0xac, 0x4c, 0x19, 0x9e, 0x85, 0x4c, 0xfa,
0x6c, 0x30, 0x47, 0xa7, 0x75, 0x5a, 0xdb, 0x6c, 0x77, 0x74, 0x8d, 0x96, 0x71, 0x9a, 0xc9, 0x87,
0xb5, 0x9f, 0x84, 0x8c, 0x7a, 0x68, 0x70, 0x9b, 0x4d, 0xaa, 0xb4, 0x22, 0xb3, 0x9c, 0xe3, 0xce,
0xf6, 0x6c, 0x8b, 0x8e, 0x04, 0xc8, 0xee, 0x6c, 0xbb, 0x27, 0xad, 0xdd, 0x8a, 0x66, 0xc9, 0xab,
0xff, 0xec, 0x0e, 0x72, 0xcc, 0xab, 0x56, 0x45, 0x46, 0xfa, 0x76, 0x4f, 0x5a, 0x7b, 0xfd, 0xb3,
0xe8, 0x83, 0xb6, 0x57, 0xbd, 0x10, 0xed, 0x74, 0x9a, 0x02, 0x6b, 0xd1, 0xd3, 0xfe, 0x0a, 0x76,
0x4b, 0xf3, 0x65, 0x5a, 0x09, 0x5e, 0xae, 0xc6, 0x57, 0xfc, 0xa6, 0x79, 0x8d, 0xc4, 0x9f, 0xad,
0x1a, 0x18, 0x3a, 0x04, 0xb1, 0xa5, 0xc1, 0xc9, 0x96, 0x2b, 0xfb, 0xba, 0x49, 0x45, 0xb8, 0x72,
0x88, 0x0e, 0x57, 0x3e, 0x69, 0x63, 0x55, 0x53, 0x2b, 0xfb, 0x6e, 0xcc, 0x06, 0x5e, 0xd4, 0xf6,
0xfb, 0x31, 0x8f, 0xba, 0x41, 0x9b, 0xb1, 0x68, 0xf1, 0x5e, 0x7a, 0x79, 0x69, 0xea, 0x84, 0x97,
0xd4, 0x45, 0x88, 0x8c, 0x85, 0x40, 0x6d, 0xd2, 0xbd, 0x9f, 0x66, 0x4c, 0x9e, 0xe8, 0xbf, 0xba,
0xbc, 0xcc, 0x78, 0x9c, 0x80, 0xa4, 0xbb, 0x16, 0x0f, 0x5d, 0x39, 0x91, 0x74, 0x63, 0x9c, 0xbd,
0x2b, 0x50, 0x4b, 0xcf, 0xd8, 0x94, 0xe7, 0xd3, 0x34, 0x83, 0xb7, 0x50, 0xa5, 0xa6, 0x11, 0x12,
0x77, 0x05, 0x5a, 0x90, 0x5d, 0x18, 0x6b, 0x51, 0x3d, 0xed, 0x9b, 0xf2, 0x3f, 0x6c, 0x2b, 0x3a,
0x62, 0x62, 0x61, 0x44, 0x30, 0xbb, 0xf7, 0xac, 0x85, 0xe7, 0x85, 0x34, 0x7e, 0xaf, 0xad, 0xa5,
0x24, 0xc4, 0xde, 0xd3, 0x27, 0xec, 0x1e, 0xaa, 0xfe, 0xfb, 0x1e, 0xbf, 0xc9, 0xa5, 0xd1, 0xfb,
0x6d, 0x95, 0x46, 0x46, 0xec, 0xa1, 0x20, 0xa3, 0x0d, 0xff, 0x24, 0xfa, 0x55, 0x69, 0xb8, 0xe4,
0xc5, 0xe0, 0x0e, 0xa2, 0x50, 0x3a, 0x77, 0x36, 0xef, 0x92, 0x72, 0x7b, 0xb5, 0xc0, 0x8c, 0x8d,
0xf3, 0x2a, 0x9e, 0xc1, 0x8b, 0xd6, 0xb6, 0xc7, 0xa5, 0x94, 0xb8, 0x5a, 0xd0, 0xa6, 0xfc, 0x51,
0x71, 0xc2, 0x13, 0x6d, 0x1d, 0xa9, 0xa1, 0x11, 0x86, 0x46, 0x85, 0x0b, 0xd9, 0x64, 0xe6, 0x24,
0x5e, 0xa6, 0x33, 0xb3, 0xe0, 0xa8, 0xb8, 0x55, 0x81, 0x64, 0xc6, 0x32, 0x43, 0x07, 0x22, 0x92,
0x19, 0x12, 0xd6, 0x3e, 0xff, 0x65, 0x2d, 0xba, 0x67, 0x99, 0x83, 0xe6, 0xb4, 0xee, 0x30, 0xbf,
0xe4, 0x75, 0xea, 0x73, 0x94, 0xe6, 0xd7, 0xd5, 0xe0, 0x73, 0xca, 0x24, 0xce, 0x9b, 0xa2, 0x7c,
0x71, 0x6b, 0x3d, 0x9b, 0xb5, 0x36, 0x47, 0x59, 0xf6, 0x79, 0xb6, 0xd2, 0x00, 0x59, 0xab, 0x39,
0xf1, 0x82, 0x1c, 0x91, 0xb5, 0x86, 0x78, 0xdb, 0xc5, 0xc6, 0x79, 0xc6, 0x73, 0xd8, 0xc5, 0xd6,
0x42, 0x2d, 0x24, 0xba, 0xb8, 0x05, 0xd9, 0x78, 0xdc, 0x88, 0xd4, 0xa9, 0xcb, 0x28, 0xcb, 0x40,
0x3c, 0x36, 0xaa, 0x06, 0x20, 0xe2, 0x31, 0x0a, 0x6a, 0x3f, 0x67, 0xd1, 0xb7, 0xeb, 0x26, 0x3d,
0x2d, 0xd9, 0x32, 0x65, 0xf0, 0xea, 0x85, 0x23, 0x21, 0xe6, 0xbf, 0x4f, 0xd8, 0x99, 0x75, 0x9e,
0x57, 0x45, 0x16, 0x57, 0x57, 0xfa, 0x61, 0xbc, 0x5f, 0xe7, 0x46, 0x08, 0x1f, 0xc7, 0x3f, 0xec,
0xa0, 0x6c, 0x50, 0x6f, 0x64, 0x26, 0xc4, 0xac, 0xe3, 0xaa, 0xad, 0x30, 0xb3, 0xd1, 0xc9, 0xd9,
0x13, 0xef, 0x83, 0x38, 0xcb, 0x58, 0xb9, 0x6a, 0x64, 0xc7, 0x71, 0x9e, 0x5e, 0xb2, 0x4a, 0x80,
0x13, 0x6f, 0x4d, 0x0d, 0x21, 0x46, 0x9c, 0x78, 0x07, 0x70, 0x9b, 0xcd, 0x03, 0xcf, 0x87, 0x79,
0xc2, 0xde, 0x82, 0x6c, 0x1e, 0xda, 0x91, 0x0c, 0x91, 0xcd, 0x53, 0xac, 0x3d, 0xf9, 0x7d, 0x91,
0xf1, 0xe9, 0xb5, 0x5e, 0x02, 0xfc, 0x0e, 0x96, 0x12, 0xb8, 0x06, 0xdc, 0x0f, 0x21, 0x76, 0x11,
0x90, 0x82, 0x33, 0x56, 0x64, 0xf1, 0x14, 0xde, 0xbf, 0x51, 0x3a, 0x5a, 0x46, 0x2c, 0x02, 0x90,
0x01, 0xc5, 0xd5, 0xf7, 0x7a, 0xb0, 0xe2, 0x82, 0x6b, 0x3d, 0xf7, 0x43, 0x88, 0x5d, 0x06, 0xa5,
0x60, 0x5c, 0x64, 0xa9, 0x00, 0xd3, 0x40, 0x69, 0x48, 0x09, 0x31, 0x0d, 0x7c, 0x02, 0x98, 0x3c,
0x66, 0xe5, 0x8c, 0xa1, 0x26, 0xa5, 0x24, 0x68, 0xb2, 0x21, 0xec, 0x65, 0x63, 0x55, 0x77, 0x5e,
0xac, 0xc0, 0x65, 0x63, 0x5d, 0x2d, 0x5e, 0xac, 0x88, 0xcb, 0xc6, 0x1e, 0x00, 0x8a, 0x78, 0x1a,
0x57, 0x02, 0x2f, 0xa2, 0x94, 0x04, 0x8b, 0xd8, 0x10, 0x76, 0x8d, 0x56, 0x45, 0x5c, 0x08, 0xb0,
0x46, 0xeb, 0x02, 0x38, 0x4f, 0xa0, 0xef, 0x92, 0x72, 0x1b, 0x49, 0x54, 0xaf, 0x30, 0xb1, 0x9f,
0xb2, 0x2c, 0xa9, 0x40, 0x24, 0xd1, 0xed, 0xde, 0x48, 0x89, 0x48, 0xd2, 0xa6, 0xc0, 0x50, 0xd2,
0xe7, 0xe3, 0x58, 0xed, 0xc0, 0xd1, 0xf8, 0xfd, 0x10, 0x62, 0xe3, 0x53, 0x53, 0xe8, 0xdd, 0xb8,
0x2c, 0xd3, 0x7a, 0xf1, 0x5f, 0xc7, 0x0b, 0xd4, 0xc8, 0x89, 0xf8, 0x84, 0x71, 0x60, 0x7a, 0x35,
0x81, 0x1b, 0x2b, 0x18, 0x0c, 0xdd, 0x1f, 0x07, 0x19, 0x9b, 0x71, 0x4a, 0x89, 0xf3, 0x08, 0x15,
0x6b, 0x4d, 0xe4, 0x09, 0xea, 0x7a, 0x17, 0xe6, 0xbc, 0x89, 0x64, 0x5c, 0x1c, 0xf3, 0x25, 0x9b,
0xf0, 0x97, 0x6f, 0xd3, 0x4a, 0xa4, 0xf9, 0x4c, 0xaf, 0xdc, 0xcf, 0x09, 0x4b, 0x18, 0x4c, 0xbc,
0x89, 0xd4, 0xa9, 0x64, 0x13, 0x08, 0x50, 0x96, 0x13, 0x76, 0x83, 0x26, 0x10, 0xd0, 0xa2, 0xe1,
0x88, 0x04, 0x22, 0xc4, 0xdb, 0x73, 0x14, 0xe3, 0x5c, 0xbf, 0x7e, 0x3e, 0xe1, 0x4d, 0x2e, 0x47,
0x59, 0x83, 0x20, 0xb1, 0x95, 0x0d, 0x2a, 0xd8, 0xfd, 0xa5, 0xf1, 0x6f, 0xa7, 0xd8, 0x23, 0xc2,
0x4e, 0x7b, 0x9a, 0x3d, 0xee, 0x41, 0x22, 0xae, 0xec, 0x3d, 0x00, 0xca, 0x55, 0xfb, 0x1a, 0xc0,
0xe3, 0x1e, 0xa4, 0x73, 0x26, 0xe3, 0x56, 0xeb, 0x45, 0x3c, 0xbd, 0x9e, 0x95, 0x7c, 0x91, 0x27,
0xbb, 0x3c, 0xe3, 0x25, 0x38, 0x93, 0xf1, 0x4a, 0x0d, 0x50, 0xe2, 0x4c, 0xa6, 0x43, 0xc5, 0x66,
0x70, 0x6e, 0x29, 0x46, 0x59, 0x3a, 0x83, 0x3b, 0x6a, 0xcf, 0x90, 0x04, 0x88, 0x0c, 0x0e, 0x05,
0x91, 0x41, 0xa4, 0x76, 0xdc, 0x22, 0x9d, 0xc6, 0x99, 0xf2, 0xb7, 0x43, 0x9b, 0xf1, 0xc0, 0xce,
0x41, 0x84, 0x28, 0x20, 0xf5, 0x9c, 0x2c, 0xca, 0xfc, 0x30, 0x17, 0x9c, 0xac, 0x67, 0x03, 0x74,
0xd6, 0xd3, 0x01, 0x41, 0x58, 0x9d, 0xb0, 0xb7, 0x75, 0x69, 0xea, 0x7f, 0xb0, 0xb0, 0x5a, 0xff,
0x7d, 0xa8, 0xe5, 0xa1, 0xb0, 0x0a, 0x38, 0x50, 0x19, 0xed, 0x44, 0x0d, 0x98, 0x80, 0xb6, 0x3f,
0x4c, 0x1e, 0x75, 0x83, 0xb8, 0x9f, 0xb1, 0x58, 0x65, 0x2c, 0xe4, 0x47, 0x02, 0x7d, 0xfc, 0x34,
0xa0, 0x3d, 0x6e, 0xf1, 0xea, 0x73, 0xc5, 0xa6, 0xd7, 0xad, 0x6b, 0x4d, 0x7e, 0x41, 0x15, 0x42,
0x1c, 0xb7, 0x10, 0x28, 0xde, 0x45, 0x87, 0x53, 0x9e, 0x87, 0xba, 0xa8, 0x96, 0xf7, 0xe9, 0x22,
0xcd, 0xd9, 0xcd, 0xaf, 0x91, 0xea, 0x91, 0xa9, 0xba, 0x69, 0x93, 0xb0, 0xe0, 0x42, 0xc4, 0xe6,
0x97, 0x84, 0x6d, 0x4e, 0x0e, 0x7d, 0x1e, 0xb7, 0xef, 0x7c, 0xb7, 0xac, 0x1c, 0xd3, 0x77, 0xbe,
0x29, 0x96, 0xae, 0xa4, 0x1a, 0x23, 0x1d, 0x56, 0xfc, 0x71, 0xb2, 0xd5, 0x0f, 0xb6, 0x5b, 0x1e,
0xcf, 0xe7, 0x6e, 0xc6, 0xe2, 0x52, 0x79, 0xdd, 0x0e, 0x18, 0xb2, 0x18, 0xb1, 0xe5, 0x09, 0xe0,
0x20, 0x84, 0x79, 0x9e, 0x77, 0x79, 0x2e, 0x58, 0x2e, 0xb0, 0x10, 0xe6, 0x1b, 0xd3, 0x60, 0x28,
0x84, 0x51, 0x0a, 0x60, 0xdc, 0xca, 0xf3, 0x20, 0x26, 0x4e, 0xe2, 0x39, 0x9a, 0xb1, 0xa9, 0xb3,
0x1e, 0x25, 0x0f, 0x8d, 0x5b, 0xc0, 0x39, 0x0f, 0xf9, 0x5c, 0x2f, 0x93, 0xb8, 0x9c, 0x99, 0xd3,
0x8d, 0x64, 0xf0, 0x94, 0xb6, 0xe3, 0x93, 0xc4, 0x43, 0xbe, 0xb0, 0x06, 0x08, 0x3b, 0x87, 0xf3,
0x78, 0x66, 0x6a, 0x8a, 0xd4, 0x40, 0xca, 0x5b, 0x55, 0x7d, 0xd4, 0x0d, 0x02, 0x3f, 0xaf, 0xd3,
0x84, 0xf1, 0x80, 0x1f, 0x29, 0xef, 0xe3, 0x07, 0x82, 0x20, 0x7b, 0xab, 0xeb, 0xad, 0x76, 0x74,
0xa3, 0x3c, 0xd1, 0xfb, 0xd8, 0x21, 0xd1, 0x3c, 0x80, 0x0b, 0x65, 0x6f, 0x04, 0x0f, 0xe6, 0x68,
0x73, 0x40, 0x1b, 0x9a, 0xa3, 0xe6, 0xfc, 0xb5, 0xcf, 0x1c, 0xc5, 0x60, 0xed, 0xf3, 0x67, 0x7a,
0x8e, 0xee, 0xc5, 0x22, 0xae, 0xf3, 0xf6, 0xd7, 0x29, 0xbb, 0xd1, 0x1b, 0x61, 0xa4, 0xbe, 0x0d,
0x35, 0x94, 0xaf, 0xac, 0x82, 0x5d, 0xf1, 0x4e, 0x6f, 0x3e, 0xe0, 0x5b, 0xef, 0x10, 0x3a, 0x7d,
0x83, 0xad, 0xc2, 0x4e, 0x6f, 0x3e, 0xe0, 0x5b, 0xbf, 0x0b, 0xdf, 0xe9, 0x1b, 0xbc, 0x10, 0xbf,
0xd3, 0x9b, 0xd7, 0xbe, 0xff, 0xaa, 0x99, 0xb8, 0xae, 0xf3, 0x3a, 0x0f, 0x9b, 0x8a, 0x74, 0xc9,
0xb0, 0x74, 0xd2, 0xb7, 0x67, 0xd0, 0x50, 0x3a, 0x49, 0xab, 0x38, 0x5f, 0xa3, 0xc2, 0x4a, 0x71,
0xca, 0xab, 0x54, 0x3e, 0xa4, 0x7f, 0xde, 0xc3, 0x68, 0x03, 0x87, 0x36, 0x4d, 0x21, 0x25, 0xfb,
0xb8, 0xd1, 0x43, 0xed, 0x2d, 0xe6, 0xad, 0x80, 0xbd, 0xf6, 0x65, 0xe6, 0xed, 0x9e, 0xb4, 0x7d,
0xf0, 0xe7, 0x31, 0xee, 0x13, 0xc7, 0x50, 0xaf, 0xa2, 0x0f, 0x1d, 0x9f, 0xf6, 0x57, 0xd0, 0xee,
0xff, 0xa6, 0xd9, 0x57, 0x40, 0xff, 0x7a, 0x12, 0x3c, 0xeb, 0x63, 0x11, 0x4c, 0x84, 0xe7, 0xb7,
0xd2, 0xd1, 0x05, 0xf9, 0x87, 0x66, 0x03, 0xdd, 0xa0, 0xf2, 0x5d, 0x0e, 0xf9, 0x0e, 0xa8, 0x9e,
0x13, 0xa1, 0x6e, 0xb5, 0x30, 0x9c, 0x19, 0x9f, 0xdd, 0x52, 0xcb, 0xf9, 0x36, 0x99, 0x07, 0xeb,
0x77, 0x0e, 0x9d, 0xf2, 0x84, 0x2c, 0x3b, 0x34, 0x2c, 0xd0, 0xe7, 0xb7, 0x55, 0xa3, 0xe6, 0x8a,
0x03, 0xcb, 0xaf, 0x73, 0x3c, 0xef, 0x69, 0xd8, 0xfb, 0x5e, 0xc7, 0xa7, 0xb7, 0x53, 0xd2, 0x65,
0xf9, 0xcf, 0xb5, 0xe8, 0xa1, 0xc7, 0xda, 0xe7, 0x09, 0xe0, 0xd4, 0xe3, 0x47, 0x01, 0xfb, 0x94,
0x92, 0x29, 0xdc, 0xef, 0xff, 0x72, 0xca, 0xf6, 0x43, 0x5e, 0x9e, 0xca, 0x7e, 0x9a, 0x09, 0x56,
0xb6, 0x3f, 0xe4, 0xe5, 0xdb, 0x55, 0xd4, 0x90, 0xfe, 0x90, 0x57, 0x00, 0x77, 0x3e, 0xe4, 0x85,
0x78, 0x46, 0x3f, 0xe4, 0x85, 0x5a, 0x0b, 0x7e, 0xc8, 0x2b, 0xac, 0x41, 0x85, 0xf7, 0xa6, 0x08,
0xea, 0xdc, 0xba, 0x97, 0x45, 0xff, 0x18, 0xfb, 0xd9, 0x6d, 0x54, 0x88, 0x05, 0x4e, 0x71, 0xf2,
0x9e, 0x5b, 0x8f, 0x36, 0xf5, 0xee, 0xba, 0xed, 0xf4, 0xe6, 0xb5, 0xef, 0x9f, 0xea, 0xdd, 0x8d,
0x09, 0xe7, 0xbc, 0x94, 0x1f, 0x71, 0xdb, 0x0c, 0x85, 0xe7, 0xda, 0x82, 0xdb, 0xf3, 0x5b, 0xfd,
0x60, 0xa2, 0xba, 0x35, 0xa1, 0x3b, 0x7d, 0xd8, 0x65, 0x08, 0x74, 0xf9, 0x4e, 0x6f, 0x9e, 0x58,
0x46, 0x94, 0x6f, 0xd5, 0xdb, 0x3d, 0x8c, 0xf9, 0x7d, 0xfd, 0xb4, 0xbf, 0x82, 0x76, 0xbf, 0xd4,
0x69, 0xa3, 0xeb, 0x5e, 0xf6, 0xf3, 0x76, 0x97, 0xa9, 0xb1, 0xd7, 0xcd, 0xc3, 0xbe, 0x78, 0x28,
0x81, 0x70, 0x97, 0xd0, 0xae, 0x04, 0x02, 0x5d, 0x46, 0x3f, 0xbd, 0x9d, 0x92, 0x2e, 0xcb, 0x3f,
0xaf, 0x45, 0x77, 0xc9, 0xb2, 0xe8, 0x71, 0xf0, 0x79, 0x5f, 0xcb, 0x60, 0x3c, 0x7c, 0x71, 0x6b,
0x3d, 0x5d, 0xa8, 0x7f, 0x5b, 0x8b, 0xee, 0x05, 0x0a, 0xa5, 0x06, 0xc8, 0x2d, 0xac, 0xfb, 0x03,
0xe5, 0x07, 0xb7, 0x57, 0xa4, 0x96, 0x7b, 0x17, 0x1f, 0xb7, 0x3f, 0xca, 0x14, 0xb0, 0x3d, 0xa6,
0x3f, 0xca, 0xd4, 0xad, 0x05, 0x0f, 0x79, 0xe2, 0x8b, 0x66, 0xd3, 0x85, 0x1e, 0xf2, 0xc8, 0x1b,
0x6a, 0xc1, 0x8f, 0x4b, 0x60, 0x1c, 0xe6, 0xe4, 0xe5, 0xdb, 0x22, 0xce, 0x13, 0xda, 0x89, 0x92,
0x77, 0x3b, 0x31, 0x1c, 0x3c, 0x1c, 0xab, 0xa5, 0x67, 0xbc, 0xd9, 0x48, 0x3d, 0xa6, 0xf4, 0x0d,
0x12, 0x3c, 0x1c, 0x6b, 0xa1, 0x84, 0x37, 0x9d, 0x35, 0x86, 0xbc, 0x81, 0x64, 0xf1, 0x49, 0x1f,
0x14, 0xa4, 0xe8, 0xc6, 0x9b, 0x39, 0x73, 0xdf, 0x0a, 0x59, 0x69, 0x9d, 0xbb, 0x6f, 0xf7, 0xa4,
0x09, 0xb7, 0x63, 0x26, 0xbe, 0x64, 0x71, 0xc2, 0xca, 0xa0, 0x5b, 0x43, 0xf5, 0x72, 0xeb, 0xd2,
0x98, 0xdb, 0x5d, 0x9e, 0x2d, 0xe6, 0xb9, 0xee, 0x4c, 0xd2, 0xad, 0x4b, 0x75, 0xbb, 0x05, 0x34,
0x3c, 0x16, 0xb4, 0x6e, 0x65, 0x7a, 0xf9, 0x24, 0x6c, 0xc6, 0xcb, 0x2a, 0x37, 0x7b, 0xb1, 0x74,
0x3d, 0xf5, 0x30, 0xea, 0xa8, 0x27, 0x18, 0x49, 0xdb, 0x3d, 0x69, 0x78, 0x3e, 0xe7, 0xb8, 0x35,
0xe3, 0x69, 0xa7, 0xc3, 0x56, 0x6b, 0x48, 0x3d, 0xed, 0xaf, 0x00, 0x4f, 0x43, 0xf5, 0xa8, 0x3a,
0x4a, 0x2b, 0xb1, 0x9f, 0x66, 0xd9, 0x60, 0x33, 0x30, 0x4c, 0x1a, 0x28, 0x78, 0x1a, 0x8a, 0xc0,
0xc4, 0x48, 0x6e, 0x4e, 0x0f, 0xf3, 0x41, 0x97, 0x1d, 0x49, 0xf5, 0x1a, 0xc9, 0x2e, 0x0d, 0x4e,
0xb4, 0x9c, 0xa6, 0x36, 0xb5, 0x1d, 0x86, 0x1b, 0xae, 0x55, 0xe1, 0x9d, 0xde, 0x3c, 0x78, 0xdc,
0x2e, 0x29, 0xb9, 0xb2, 0x3c, 0xa0, 0x4c, 0x78, 0x2b, 0xc9, 0xc3, 0x0e, 0x0a, 0x9c, 0x0a, 0xaa,
0x69, 0xf4, 0x26, 0x4d, 0x66, 0x4c, 0xa0, 0x4f, 0x8a, 0x5c, 0x20, 0xf8, 0xa4, 0x08, 0x80, 0xa0,
0xeb, 0xd4, 0xdf, 0xcd, 0x71, 0xe8, 0x61, 0x82, 0x75, 0x9d, 0x56, 0x76, 0xa8, 0x50, 0xd7, 0xa1,
0x34, 0x88, 0x06, 0xc6, 0xad, 0x7e, 0x1d, 0xff, 0x49, 0xc8, 0x0c, 0x78, 0x27, 0x7f, 0xb3, 0x17,
0x0b, 0x56, 0x14, 0xeb, 0x30, 0x9d, 0xa7, 0x02, 0x5b, 0x51, 0x1c, 0x1b, 0x35, 0x12, 0x5a, 0x51,
0xda, 0x28, 0x55, 0xbd, 0x3a, 0x47, 0x38, 0x4c, 0xc2, 0xd5, 0x53, 0x4c, 0xbf, 0xea, 0x19, 0xb6,
0xf5, 0x60, 0x33, 0x37, 0x43, 0x46, 0x5c, 0xe9, 0xcd, 0x32, 0x32, 0xb6, 0xe5, 0x6b, 0x9a, 0x10,
0x0c, 0x45, 0x1d, 0x4a, 0x01, 0x1e, 0xd8, 0xd7, 0x5c, 0xf3, 0xec, 0xb5, 0x28, 0x58, 0x5c, 0xc6,
0xf9, 0x14, 0xdd, 0x9c, 0x4a, 0x83, 0x2d, 0x32, 0xb4, 0x39, 0x25, 0x35, 0xc0, 0x63, 0x73, 0xff,
0x05, 0x4b, 0x64, 0x2a, 0x98, 0x37, 0x19, 0xfd, 0xf7, 0x2b, 0x1f, 0xf7, 0x20, 0xe1, 0x63, 0xf3,
0x06, 0x30, 0x07, 0xdf, 0xca, 0xe9, 0x27, 0x01, 0x53, 0x3e, 0x1a, 0xda, 0x08, 0xd3, 0x2a, 0x60,
0x50, 0x9b, 0x04, 0x97, 0x89, 0x9f, 0xb0, 0x15, 0x36, 0xa8, 0x6d, 0x7e, 0x2a, 0x91, 0xd0, 0xa0,
0x6e, 0xa3, 0x20, 0xcf, 0x74, 0xf7, 0x41, 0xeb, 0x01, 0x7d, 0x77, 0xeb, 0xb3, 0xd1, 0xc9, 0x81,
0x99, 0xb3, 0x97, 0x2e, 0xbd, 0xe7, 0x04, 0x48, 0x41, 0xf7, 0xd2, 0x25, 0xfe, 0x98, 0x60, 0xb3,
0x17, 0x0b, 0x1f, 0xc9, 0xc7, 0x82, 0xbd, 0x6d, 0x9e, 0x95, 0x23, 0xc5, 0x95, 0xf2, 0xd6, 0xc3,
0xf2, 0x47, 0xdd, 0xa0, 0xbd, 0x00, 0x7b, 0x5a, 0xf2, 0x29, 0xab, 0x2a, 0xfd, 0xa5, 0x4a, 0xff,
0x86, 0x91, 0x96, 0x0d, 0xc1, 0x77, 0x2a, 0x1f, 0x84, 0x21, 0xe7, 0xf3, 0x72, 0x4a, 0x64, 0xbf,
0x7a, 0xb3, 0x8e, 0x6a, 0xb6, 0x3f, 0x78, 0xb3, 0xd1, 0xc9, 0xd9, 0xe9, 0xa5, 0xa5, 0xee, 0x67,
0x6e, 0x1e, 0xa1, 0xea, 0xd8, 0x17, 0x6e, 0x1e, 0xf7, 0x20, 0xb5, 0xab, 0x2f, 0xa3, 0x77, 0x8e,
0xf8, 0x6c, 0xcc, 0xf2, 0x64, 0xf0, 0x7d, 0xff, 0x0a, 0x2d, 0x9f, 0x0d, 0xeb, 0x3f, 0x1b, 0xa3,
0x77, 0x28, 0xb1, 0xbd, 0x04, 0xb8, 0xc7, 0x2e, 0x16, 0xb3, 0xb1, 0x88, 0x05, 0xb8, 0x04, 0x28,
0xff, 0x3e, 0xac, 0x05, 0xc4, 0x25, 0x40, 0x0f, 0x00, 0xf6, 0x26, 0x25, 0x63, 0xa8, 0xbd, 0x5a,
0x10, 0xb4, 0xa7, 0x01, 0x9b, 0x45, 0x18, 0x7b, 0x75, 0xa2, 0x0e, 0x2f, 0xed, 0x59, 0x1d, 0x29,
0x25, 0xb2, 0x88, 0x36, 0x65, 0x07, 0xb7, 0xaa, 0xbe, 0xfc, 0xea, 0xc8, 0x62, 0x3e, 0x8f, 0xcb,
0x15, 0x18, 0xdc, 0xba, 0x96, 0x0e, 0x40, 0x0c, 0x6e, 0x14, 0xb4, 0xb3, 0xb6, 0x69, 0xe6, 0xe9,
0xf5, 0x01, 0x2f, 0xf9, 0x42, 0xa4, 0x39, 0x83, 0x5f, 0x9e, 0x30, 0x0d, 0xea, 0x32, 0xc4, 0xac,
0xa5, 0x58, 0x9b, 0xe5, 0x4a, 0x42, 0xdd, 0x27, 0x94, 0x1f, 0xcf, 0xae, 0x04, 0x2f, 0xe1, 0xf3,
0x44, 0x65, 0x05, 0x42, 0x44, 0x96, 0x4b, 0xc2, 0xa0, 0xef, 0x4f, 0xd3, 0x7c, 0x86, 0xf6, 0xfd,
0xa9, 0xfb, 0xf5, 0xd7, 0x7b, 0x34, 0x60, 0x27, 0x94, 0x6a, 0x34, 0x35, 0x01, 0xf4, 0xbb, 0x9c,
0x68, 0xa3, 0xbb, 0x04, 0x31, 0xa1, 0x70, 0x12, 0xb8, 0x7a, 0x55, 0xb0, 0x9c, 0x25, 0xcd, 0xad,
0x39, 0xcc, 0x95, 0x47, 0x04, 0x5d, 0x41, 0xd2, 0xc6, 0x22, 0x29, 0x3f, 0x5b, 0xe4, 0xa7, 0x25,
0xbf, 0x4c, 0x33, 0x56, 0x82, 0x58, 0xa4, 0xd4, 0x1d, 0x39, 0x11, 0x8b, 0x30, 0xce, 0x5e, 0xbf,
0x90, 0x52, 0xef, 0x0b, 0xf0, 0x93, 0x32, 0x9e, 0xc2, 0xeb, 0x17, 0xca, 0x46, 0x1b, 0x23, 0x4e,
0x06, 0x03, 0xb8, 0x93, 0xe8, 0x28, 0xd7, 0xf9, 0x4a, 0x8e, 0x0f, 0xfd, 0x2e, 0xa1, 0xfc, 0x26,
0x6a, 0x05, 0x12, 0x1d, 0x6d, 0x0e, 0x23, 0x89, 0x44, 0x27, 0xac, 0x61, 0x97, 0x12, 0xc9, 0x9d,
0xe8, 0x6b, 0x45, 0x60, 0x29, 0x51, 0x36, 0x1a, 0x21, 0xb1, 0x94, 0xb4, 0x20, 0x10, 0x90, 0x9a,
0x69, 0x30, 0x43, 0x03, 0x92, 0x91, 0x06, 0x03, 0x92, 0x4b, 0xd9, 0x40, 0x71, 0x98, 0xa7, 0x22,
0x8d, 0xb3, 0x31, 0x13, 0xa7, 0x71, 0x19, 0xcf, 0x99, 0x60, 0x25, 0x0c, 0x14, 0x1a, 0x19, 0x7a,
0x0c, 0x11, 0x28, 0x28, 0x56, 0x3b, 0xfc, 0x83, 0xe8, 0xbd, 0x7a, 0xdd, 0x67, 0xb9, 0xfe, 0xed,
0x9a, 0x97, 0xf2, 0x47, 0xaf, 0x06, 0xef, 0x1b, 0x1b, 0x63, 0x51, 0xb2, 0x78, 0xde, 0xd8, 0x7e,
0xd7, 0xfc, 0x5d, 0x82, 0x4f, 0xd7, 0xea, 0xf1, 0x7c, 0xc2, 0x45, 0x7a, 0x59, 0x6f, 0xb3, 0xf5,
0x1b, 0x44, 0x60, 0x3c, 0xbb, 0xe2, 0x61, 0xe0, 0x5b, 0x14, 0x18, 0x67, 0xe3, 0xb4, 0x2b, 0x3d,
0x63, 0x45, 0x06, 0xe3, 0xb4, 0xa7, 0x2d, 0x01, 0x22, 0x4e, 0xa3, 0xa0, 0x9d, 0x9c, 0xae, 0x78,
0xc2, 0xc2, 0x95, 0x99, 0xb0, 0x7e, 0x95, 0x99, 0x78, 0x2f, 0x65, 0x64, 0xd1, 0x7b, 0xc7, 0x6c,
0x7e, 0xc1, 0xca, 0xea, 0x2a, 0x2d, 0xa8, 0xef, 0xb6, 0x5a, 0xa2, 0xf3, 0xbb, 0xad, 0x04, 0x6a,
0x57, 0x02, 0x0b, 0x1c, 0x56, 0x27, 0xf1, 0x9c, 0xc9, 0x2f, 0x6b, 0x80, 0x95, 0xc0, 0x31, 0xe2,
0x40, 0xc4, 0x4a, 0x40, 0xc2, 0xce, 0xfb, 0x5d, 0x96, 0x39, 0x63, 0xb3, 0x7a, 0x84, 0x95, 0xa7,
0xf1, 0x6a, 0xce, 0x72, 0xa1, 0x4d, 0x82, 0x33, 0x79, 0xc7, 0x24, 0xce, 0x13, 0x67, 0xf2, 0x7d,
0xf4, 0x9c, 0xd0, 0xe4, 0x35, 0xfc, 0x29, 0x2f, 0x85, 0xfa, 0x65, 0xaa, 0xf3, 0x32, 0x03, 0xa1,
0xc9, 0x6f, 0x54, 0x8f, 0x24, 0x42, 0x53, 0x58, 0xc3, 0xf9, 0x15, 0x02, 0xaf, 0x0c, 0xaf, 0x59,
0x69, 0xc6, 0xc9, 0xcb, 0x79, 0x9c, 0x66, 0x7a, 0x34, 0xfc, 0x30, 0x60, 0x9b, 0xd0, 0x21, 0x7e,
0x85, 0xa0, 0xaf, 0xae, 0xf3, 0xbb, 0x0d, 0xe1, 0x12, 0x82, 0x47, 0x04, 0x1d, 0xf6, 0x89, 0x47,
0x04, 0xdd, 0x5a, 0x76, 0xe7, 0x6e, 0x59, 0xc9, 0xad, 0x24, 0xb1, 0xcb, 0x13, 0x78, 0x5e, 0xe8,
0xd8, 0x04, 0x20, 0xb1, 0x73, 0x0f, 0x2a, 0xd8, 0xd4, 0xc0, 0x62, 0xfb, 0x69, 0x1e, 0x67, 0xe9,
0xcf, 0x60, 0x5a, 0xef, 0xd8, 0x69, 0x08, 0x22, 0x35, 0xc0, 0x49, 0xcc, 0xd5, 0x01, 0x13, 0x93,
0xb4, 0x0e, 0xfd, 0x8f, 0x02, 0xed, 0x26, 0x89, 0x6e, 0x57, 0x0e, 0xe9, 0x7c, 0xa3, 0x15, 0x36,
0xeb, 0xa8, 0x28, 0xc6, 0xf5, 0xaa, 0x7a, 0xc6, 0xa6, 0x2c, 0x2d, 0xc4, 0xe0, 0xb3, 0x70, 0x5b,
0x01, 0x9c, 0xb8, 0x68, 0xd1, 0x43, 0xcd, 0x79, 0x7c, 0x5f, 0xc7, 0x92, 0xb1, 0xfa, 0xc9, 0xc6,
0xf3, 0x8a, 0x95, 0x3a, 0xd1, 0x38, 0x60, 0x02, 0xcc, 0x4e, 0x87, 0x1b, 0x3a, 0x60, 0x5d, 0x51,
0x62, 0x76, 0x86, 0x35, 0xec, 0x61, 0x9f, 0xc3, 0xe9, 0x6f, 0x6e, 0xcb, 0xfb, 0x86, 0x5b, 0xa4,
0x31, 0x87, 0x22, 0x0e, 0xfb, 0x68, 0xda, 0x66, 0x6b, 0x6d, 0xb7, 0xa3, 0x7c, 0x75, 0x08, 0xaf,
0x4c, 0x20, 0x96, 0x24, 0x46, 0x64, 0x6b, 0x01, 0xdc, 0x39, 0x0c, 0x2f, 0x79, 0x9c, 0x4c, 0xe3,
0x4a, 0x9c, 0xc6, 0xab, 0x8c, 0xc7, 0x89, 0x5c, 0xd7, 0xe1, 0x61, 0x78, 0xc3, 0x0c, 0x5d, 0x88,
0x3a, 0x0c, 0xa7, 0x60, 0x37, 0x3b, 0x93, 0xbf, 0x44, 0xa9, 0xef, 0x72, 0xc2, 0xec, 0x4c, 0x96,
0x17, 0xde, 0xe3, 0x7c, 0x10, 0x86, 0xec, 0x3b, 0x68, 0x4a, 0x24, 0xd3, 0x90, 0x7b, 0x98, 0x8e,
0x97, 0x80, 0x7c, 0x14, 0x20, 0xec, 0x77, 0x29, 0xd4, 0xdf, 0x9b, 0x1f, 0x1f, 0x12, 0xfa, 0x4b,
0xd6, 0x5b, 0x98, 0xae, 0x0b, 0x0d, 0xdd, 0x0f, 0xdc, 0x6d, 0xf7, 0xa4, 0x6d, 0x9a, 0xb9, 0x7b,
0x15, 0x8b, 0x51, 0x92, 0x1c, 0xb3, 0x0a, 0x79, 0xa1, 0xbc, 0x16, 0x0e, 0xad, 0x94, 0x48, 0x33,
0xdb, 0x94, 0x1d, 0xe8, 0xb5, 0xec, 0x65, 0x92, 0x0a, 0x2d, 0x6b, 0x6e, 0x48, 0x6f, 0xb5, 0x0d,
0xb4, 0x29, 0xa2, 0x56, 0x34, 0x6d, 0x63, 0x79, 0xcd, 0x4c, 0xf8, 0x6c, 0x96, 0x31, 0x0d, 0x9d,
0xb1, 0x58, 0x7d, 0xc8, 0x6f, 0xa7, 0x6d, 0x0b, 0x05, 0x89, 0x58, 0x1e, 0x54, 0xb0, 0x69, 0x64,
0x8d, 0xa9, 0x47, 0x52, 0x4d, 0xc3, 0x6e, 0xb4, 0xcd, 0x78, 0x00, 0x91, 0x46, 0xa2, 0xa0, 0x7d,
0xef, 0xad, 0x16, 0x1f, 0xb0, 0xa6, 0x25, 0xe0, 0x27, 0x88, 0xa4, 0xb2, 0x23, 0x26, 0xde, 0x7b,
0x43, 0x30, 0xbb, 0x4f, 0x00, 0x1e, 0x5e, 0xac, 0x0e, 0x13, 0xb8, 0x4f, 0x80, 0xfa, 0x92, 0x21,
0xf6, 0x09, 0x14, 0xeb, 0x77, 0x9d, 0x39, 0xf7, 0x3a, 0x8a, 0x2b, 0x5b, 0x39, 0xa4, 0xeb, 0x50,
0x30, 0xd4, 0x75, 0x94, 0x82, 0xdf, 0xa4, 0xee, 0xd1, 0x1a, 0xd2, 0xa4, 0xd8, 0xb9, 0xda, 0x7a,
0x17, 0xe6, 0x24, 0x3e, 0x5e, 0x15, 0x27, 0x5c, 0x17, 0x43, 0xbf, 0xd7, 0x58, 0x81, 0xc4, 0xc7,
0x2f, 0x76, 0x8b, 0x26, 0x12, 0x9f, 0x6e, 0x2d, 0x1b, 0x27, 0xcd, 0xfe, 0x56, 0x5e, 0xa1, 0xc2,
0x7f, 0x51, 0x40, 0x09, 0x89, 0x38, 0xd9, 0x82, 0x94, 0xed, 0x17, 0x1f, 0xfd, 0xd7, 0xd7, 0x77,
0xd6, 0x7e, 0xf1, 0xf5, 0x9d, 0xb5, 0xff, 0xfd, 0xfa, 0xce, 0xda, 0xcf, 0xbf, 0xb9, 0xf3, 0xad,
0x5f, 0x7c, 0x73, 0xe7, 0x5b, 0xff, 0xf3, 0xcd, 0x9d, 0x6f, 0x7d, 0xf5, 0x8e, 0xfe, 0xc5, 0xe4,
0x8b, 0x5f, 0x91, 0xbf, 0x7b, 0xfc, 0xfc, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x5a, 0x7a, 0x62,
0x93, 0x55, 0x79, 0x00, 0x00,
}
// Reference imports to suppress errors if they are not otherwise used.
@ -407,6 +409,8 @@ 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)
@ -919,6 +923,24 @@ 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...)
@ -3275,6 +3297,8 @@ 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
@ -3657,6 +3681,12 @@ 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
}
@ -4808,6 +4838,42 @@ 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 {
@ -9508,6 +9574,14 @@ 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,10 +170,13 @@ 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, filepath.Join(opts.Dir, "-corrupted"))
log.Errorf("failed to rename corrupted localstore: %s", err2)
err2 := os.Rename(opts.Dir, opts.Dir+"-corrupted")
if err2 != nil {
log.Errorf("failed to rename corrupted localstore: %s", err2)
}
var errAfterRemove error
r.localstoreDS, errAfterRemove = openBadgerWithRecover(opts)
errAfterRemove = anyerror.CleanupError(errAfterRemove)

View file

@ -75,16 +75,14 @@ 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())
@ -100,7 +98,7 @@ func NewStoreFixture(t testing.TB) *StoreFixture {
fts: fullText,
sourceService: &detailsFromId{},
arenaPool: &anyenc.ArenaPool{},
repoPath: walletService.RepoPath(),
objectStorePath: t.TempDir(),
oldStore: oldStore,
spaceIndexes: map[string]spaceindex.Store{},
techSpaceIdProvider: &stubTechSpaceIdProvider{},

View file

@ -20,6 +20,7 @@ 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"
)
@ -52,6 +53,7 @@ type ObjectStore interface {
GetCrdtDb(spaceId string) anystore.DB
SpaceNameGetter
spaceresolverstore.Store
CrossSpace
}
@ -86,9 +88,11 @@ type TechSpaceIdProvider interface {
}
type dsObjectStore struct {
repoPath string
techSpaceId string
anyStoreConfig anystore.Config
spaceresolverstore.Store
objectStorePath string
techSpaceId string
anyStoreConfig anystore.Config
anyStore anystore.DB
anyStoreLockRemove func() error
@ -145,6 +149,9 @@ 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")
@ -152,8 +159,10 @@ func (s *dsObjectStore) Init(a *app.App) (err error) {
s.fts = fts.(ftsearch.FTSearch)
}
s.arenaPool = &anyenc.ArenaPool{}
s.repoPath = app.MustComponent[wallet.Wallet](a).RepoPath()
s.anyStoreConfig = *app.MustComponent[configProvider](a).GetAnyStoreConfig()
cfg := app.MustComponent[configProvider](a)
s.objectStorePath = filepath.Join(repoPath, "objectstore")
s.anyStoreConfig = *cfg.GetAnyStoreConfig()
s.setDefaultConfig()
s.oldStore = app.MustComponent[oldstore.Service](a)
s.techSpaceIdProvider = app.MustComponent[TechSpaceIdProvider](a)
@ -168,12 +177,23 @@ func (s *dsObjectStore) Name() (name string) {
func (s *dsObjectStore) Run(ctx context.Context) error {
s.techSpaceId = s.techSpaceIdProvider.TechSpaceId()
dbDir := s.storeRootDir()
err := ensureDirExists(dbDir)
err := ensureDirExists(s.objectStorePath)
if err != nil {
return err
}
return s.openDatabase(ctx, filepath.Join(dbDir, "objects.db"))
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
}
func (s *dsObjectStore) setDefaultConfig() {
@ -184,10 +204,6 @@ 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) {
@ -238,7 +254,7 @@ func (s *dsObjectStore) preloadExistingObjectStores() error {
var err error
s.spaceStoreDirsCheck.Do(func() {
var entries []os.DirEntry
entries, err = os.ReadDir(s.storeRootDir())
entries, err = os.ReadDir(s.objectStorePath)
s.Lock()
defer s.Unlock()
for _, entry := range entries {
@ -300,7 +316,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.storeRootDir(), spaceId)
dir := filepath.Join(s.objectStorePath, spaceId)
err := ensureDirExists(dir)
if err != nil {
return spaceindex.NewInvalidStore(err)
@ -334,7 +350,7 @@ func (s *dsObjectStore) GetCrdtDb(spaceId string) anystore.DB {
db, ok := s.crdtDbs[spaceId]
if !ok {
dir := filepath.Join(s.storeRootDir(), spaceId)
dir := filepath.Join(s.objectStorePath, spaceId)
err := ensureDirExists(dir)
if err != nil {
return nil

View file

@ -0,0 +1,71 @@
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

@ -11,7 +11,6 @@ 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"
@ -29,6 +28,7 @@ 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() spacestorage.SpaceStorage
Storage() anystorage.ClientSpaceStorage
DerivedIDs() threads.DerivedSmartblockIds
@ -124,12 +124,16 @@ func BuildSpace(ctx context.Context, deps SpaceDeps) (Space, error) {
if err != nil {
return nil, fmt.Errorf("derive object ids: %w", err)
}
if deps.StorageService.IsSpaceCreated(deps.CommonSpace.Id()) {
isSpaceCreated, err := sp.Storage().IsSpaceCreated(ctx)
if err != nil {
return nil, fmt.Errorf("is space created: %w", err)
}
if isSpaceCreated {
err = sp.ObjectProvider.CreateMandatoryObjects(ctx, sp)
if err != nil {
return nil, fmt.Errorf("create mandatory objects: %w", err)
}
err = deps.StorageService.UnmarkSpaceCreated(deps.CommonSpace.Id())
err = sp.Storage().UnmarkSpaceCreated(ctx)
if err != nil {
return nil, fmt.Errorf("unmark space created: %w", err)
}
@ -207,8 +211,8 @@ func (s *space) StoredIds() []string {
return s.common.StoredIds()
}
func (s *space) Storage() spacestorage.SpaceStorage {
return s.common.Storage()
func (s *space) Storage() anystorage.ClientSpaceStorage {
return s.common.Storage().(anystorage.ClientSpaceStorage)
}
func (s *space) DerivedIDs() threads.DerivedSmartblockIds {
@ -305,10 +309,7 @@ func (s *space) TryLoadBundledObjects(ctx context.Context) (missingSourceIds []s
if err != nil {
return nil, err
}
storedIds, err := s.Storage().StoredIds()
if err != nil {
return nil, err
}
storedIds := s.StoredIds()
missingIds := bundledObjectIds.Filter(func(bo domain.BundledObjectId) bool {
return !slices.Contains(storedIds, bo.DerivedObjectId)
@ -318,11 +319,7 @@ func (s *space) TryLoadBundledObjects(ctx context.Context) (missingSourceIds []s
s.LoadObjectsIgnoreErrs(ctx, missingIds.DerivedObjectIds())
// todo: make LoadObjectsIgnoreErrs return list of loaded ids
storedIds, err = s.Storage().StoredIds()
if err != nil {
return nil, err
}
storedIds = s.StoredIds()
missingIds = bundledObjectIds.Filter(func(bo domain.BundledObjectId) bool {
return !slices.Contains(storedIds, bo.DerivedObjectId)
})
@ -348,7 +345,7 @@ func (s *space) migrationProfileObject(ctx context.Context) error {
return err
}
extractedProfileExists, _ := s.Storage().HasTree(extractedProfileId)
extractedProfileExists, _ := s.Storage().HasTree(ctx, extractedProfileId)
if extractedProfileExists {
return nil
}

View file

@ -77,10 +77,6 @@ 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
}
@ -113,7 +109,7 @@ func (c *virtualCommonSpace) DebugAllHeads() []headsync.TreeHeads {
return nil
}
func (c *virtualCommonSpace) Description() (desc commonspace.SpaceDescription, err error) {
func (c *virtualCommonSpace) Description(ctx context.Context) (desc commonspace.SpaceDescription, err error) {
return
}

View file

@ -0,0 +1,65 @@
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()
spaceDesc, err := sp.Description(ctx)
if err != nil {
err = spacesyncproto.ErrUnexpected
return

View file

@ -0,0 +1,139 @@
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"
)
// TODO: [storage] add mark space created etc
// add tree root
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"
// TODO: [storage] make it more obvious
rawChangeKey = "r"
)
type clientStorage struct {
spacestorage.SpaceStorage
clientColl anystore.Collection
arena *anyenc.Arena
}
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,
arena: &anyenc.Arena{},
}
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
}
// TODO: [storage] change to arena pool or use mutexes
val := r.arena.NewTrue()
if !isCreated {
val = r.arena.NewFalse()
}
defer r.arena.Reset()
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 {
tx.Rollback()
return err
}
return tx.Commit()
}

View file

@ -0,0 +1,134 @@
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/app/ocache"
"github.com/anyproto/any-sync/commonspace/spacestorage"
)
var log = logger.NewNamed(spacestorage.CName)
func New(rootPath string) *storageService {
return &storageService{
rootPath: rootPath,
}
}
type storageService struct {
rootPath string
cache ocache.OCache
}
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': %v", 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) {
// TODO: [storage] set anystore config from config
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)
}
var anyStoreConfig *anystore.Config = &anystore.Config{
ReadConnections: 4,
SQLiteConnectionOptions: map[string]string{
"synchronous": "off",
},
}

View file

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

View file

@ -4,13 +4,13 @@ import (
"context"
"testing"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"github.com/anyproto/any-sync/consensus/consensusproto"
"github.com/dgraph-io/badger/v4"
"github.com/stretchr/testify/require"
)
func testList(t *testing.T, store liststorage.ListStorage, root *consensusproto.RawRecordWithId, head string) {
func testList(t *testing.T, store oldstorage.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 liststorage.ListStorage
var listStore oldstorage.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 liststorage.ListStorage
aclStorage oldstorage.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 spacestorage.SpaceStorage, err error) {
func newSpaceStorage(objDb *badger.DB, spaceId string, service *storageService) (store oldstorage.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 spacestorage.SpaceStorage, err error) {
func createSpaceStorage(db *badger.DB, payload spacestorage.SpaceStorageCreatePayload, service *storageService) (store oldstorage.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) (treestorage.TreeStorage, error) {
func (s *spaceStorage) TreeStorage(id string) (oldstorage.TreeStorage, error) {
return newTreeStorage(s.objDb, s.spaceId, id)
}
func (s *spaceStorage) CreateTreeStorage(payload treestorage.TreeStorageCreatePayload) (ts treestorage.TreeStorage, err error) {
func (s *spaceStorage) CreateTreeStorage(payload treestorage.TreeStorageCreatePayload) (ts oldstorage.TreeStorage, err error) {
return createTreeStorage(s.objDb, s.spaceId, payload)
}
func (s *spaceStorage) AclStorage() (liststorage.ListStorage, error) {
func (s *spaceStorage) AclStorage() (oldstorage.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(spacestorage.TreeDeletedStatusDeleted)) {
if bytes.Equal(val, []byte(oldstorage.TreeDeletedStatusDeleted)) {
isDeleted = true
}
return nil

View file

@ -7,7 +7,8 @@ import (
"testing"
"github.com/anyproto/any-sync/commonspace/object/tree/treechangeproto"
spacestorage "github.com/anyproto/any-sync/commonspace/spacestorage"
"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"
@ -36,7 +37,7 @@ func spaceTestPayload() spacestorage.SpaceStorageCreatePayload {
}
}
func testSpace(t *testing.T, store spacestorage.SpaceStorage, payload spacestorage.SpaceStorageCreatePayload) {
func testSpace(t *testing.T, store oldstorage.SpaceStorage, payload spacestorage.SpaceStorageCreatePayload) {
header, err := store.SpaceHeader()
require.NoError(t, err)
require.Equal(t, payload.SpaceHeaderWithId, header)
@ -139,3 +140,58 @@ 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,12 +1,15 @@
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"
@ -46,11 +49,11 @@ func (s *storageService) Name() (name string) {
return spacestorage.CName
}
func (s *storageService) SpaceStorage(id string) (spacestorage.SpaceStorage, error) {
func (s *storageService) SpaceStorage(id string) (oldstorage.SpaceStorage, error) {
return newSpaceStorage(s.db, id, s)
}
func (s *storageService) WaitSpaceStorage(ctx context.Context, id string) (store spacestorage.SpaceStorage, err error) {
func (s *storageService) WaitSpaceStorage(ctx context.Context, id string) (store oldstorage.SpaceStorage, err error) {
var ls *lockSpace
ls, err = s.checkLock(id, func() error {
store, err = newSpaceStorage(s.db, id, s)
@ -152,7 +155,7 @@ func (s *storageService) unlockSpaceStorage(id string) {
}
}
func (s *storageService) CreateSpaceStorage(payload spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error) {
func (s *storageService) CreateSpaceStorage(payload spacestorage.SpaceStorageCreatePayload) (oldstorage.SpaceStorage, error) {
return createSpaceStorage(s.db, payload, s)
}
@ -166,6 +169,37 @@ 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))
}
@ -193,6 +227,11 @@ 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,11 +1,13 @@
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"
)
@ -16,7 +18,7 @@ type treeStorage struct {
root *treechangeproto.RawTreeChangeWithId
}
func newTreeStorage(db *badger.DB, spaceId, treeId string) (ts treestorage.TreeStorage, err error) {
func newTreeStorage(db *badger.DB, spaceId, treeId string) (ts oldstorage.TreeStorage, err error) {
keys := newTreeKeys(spaceId, treeId)
err = db.View(func(txn *badger.Txn) error {
_, err := txn.Get(keys.RootIdKey())
@ -48,7 +50,7 @@ func newTreeStorage(db *badger.DB, spaceId, treeId string) (ts treestorage.TreeS
return
}
func createTreeStorage(db *badger.DB, spaceId string, payload treestorage.TreeStorageCreatePayload) (ts treestorage.TreeStorage, err error) {
func createTreeStorage(db *badger.DB, spaceId string, payload treestorage.TreeStorageCreatePayload) (ts oldstorage.TreeStorage, err error) {
keys := newTreeKeys(spaceId, payload.RootRawChange.Id)
if hasDB(db, keys.RootIdKey()) {
err = treestorage.ErrTreeExists
@ -57,7 +59,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 treestorage.TreeStorage, err error) {
func forceCreateTreeStorage(db *badger.DB, spaceId string, payload treestorage.TreeStorageCreatePayload) (ts oldstorage.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())
@ -108,7 +110,74 @@ func (t *treeStorage) Heads() (heads []string, err error) {
}
func (t *treeStorage) GetAllChangeIds() (chs []string, err error) {
return nil, fmt.Errorf("get all change ids should not be called")
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
})
}
func (t *treeStorage) SetHeads(heads []string) (err error) {

View file

@ -1,13 +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"
)
@ -27,7 +30,7 @@ type fixture struct {
db *badger.DB
}
func testTreePayload(t *testing.T, store treestorage.TreeStorage, payload treestorage.TreeStorageCreatePayload) {
func testTreePayload(t *testing.T, store oldstorage.TreeStorage, payload treestorage.TreeStorageCreatePayload) {
require.Equal(t, payload.RootRawChange.Id, store.Id())
root, err := store.Root()
@ -139,7 +142,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: "newId"}
newChange := &treechangeproto.RawTreeChangeWithId{RawChange: []byte("ab"), Id: "id10"}
require.NoError(t, store.AddRawChange(newChange))
rawCh, err := store.GetRawChange(context.Background(), newChange.Id)
require.NoError(t, err)
@ -157,6 +160,50 @@ 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

@ -0,0 +1,248 @@
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
oldPath 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.oldPath = cfg.GetOldSpaceStorePath()
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
}
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

@ -0,0 +1,203 @@
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
}

Binary file not shown.

View file

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

Binary file not shown.

View file

@ -0,0 +1,223 @@
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

@ -0,0 +1,96 @@
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

@ -6,12 +6,14 @@ 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"
)
func newListStorage(ss *spaceStorage, treeId string) (liststorage.ListStorage, error) {
var ErrUnknownRecord = errors.New("record does not exist")
func newListStorage(ss *spaceStorage, treeId string) (oldstorage.ListStorage, error) {
ts := &listStorage{
listId: treeId,
spaceStorage: ss,
@ -38,7 +40,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, liststorage.ErrUnknownRecord)
return nil, replaceNoRowsErr(err, ErrUnknownRecord)
}
return &consensusproto.RawRecordWithId{
Payload: tch.RawChange,
@ -66,7 +68,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, liststorage.ErrUnknownRecord)
return nil, replaceNoRowsErr(err, ErrUnknownRecord)
}
return &consensusproto.RawRecordWithId{
Payload: tch.RawChange,

View file

@ -3,7 +3,7 @@ package sqlitestorage
import (
"testing"
"github.com/anyproto/any-sync/commonspace/object/acl/liststorage"
"github.com/anyproto/any-sync/commonspace/spacestorage/oldstorage"
"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 liststorage.ListStorage, root *consensusproto.RawRecordWithId, head string) {
func testList(t *testing.T, store oldstorage.ListStorage, root *consensusproto.RawRecordWithId, head string) {
require.Equal(t, store.Id(), root.Id)
aclRoot, err := store.Root()

View file

@ -5,6 +5,7 @@ import (
"database/sql"
"errors"
"net/url"
"os"
"sync"
"time"
@ -12,6 +13,7 @@ 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"
@ -30,7 +32,7 @@ var (
)
type configGetter interface {
GetSpaceStorePath() string
GetSqliteStorePath() string
GetTempDirPath() string
}
@ -51,6 +53,8 @@ type storageService struct {
allTreeDelStatus,
change,
hasTree,
listChanges,
iterateChanges,
hasChange,
updateTreeHeads,
deleteTree,
@ -60,6 +64,7 @@ type storageService struct {
spaceIds,
spaceIsCreated,
upsertBind,
getAllBinds,
deleteSpace,
deleteTreesBySpace,
deleteChangesBySpace,
@ -91,7 +96,7 @@ func New() *storageService {
}
func (s *storageService) Init(a *app.App) (err error) {
s.dbPath = a.MustComponent("config").(configGetter).GetSpaceStorePath()
s.dbPath = a.MustComponent("config").(configGetter).GetSqliteStorePath()
s.dbTempPath = a.MustComponent("config").(configGetter).GetTempDirPath()
s.lockedSpaces = map[string]*lockSpace{}
if s.checkpointAfterWrite == 0 {
@ -159,7 +164,7 @@ func (s *storageService) Name() (name string) {
return spacestorage.CName
}
func (s *storageService) WaitSpaceStorage(ctx context.Context, id string) (store spacestorage.SpaceStorage, err error) {
func (s *storageService) WaitSpaceStorage(ctx context.Context, id string) (store oldstorage.SpaceStorage, err error) {
var ls *lockSpace
ls, err = s.checkLock(id, func() error {
store, err = newSpaceStorage(s, id)
@ -277,7 +282,7 @@ func (s *storageService) unlockSpaceStorage(id string) {
}
}
func (s *storageService) CreateSpaceStorage(payload spacestorage.SpaceStorageCreatePayload) (ss spacestorage.SpaceStorage, err error) {
func (s *storageService) CreateSpaceStorage(payload spacestorage.SpaceStorageCreatePayload) (ss oldstorage.SpaceStorage, err error) {
_, err = s.checkLock(payload.SpaceHeaderWithId.Id, func() error {
ss, err = createSpaceStorage(s, payload)
return err
@ -291,6 +296,25 @@ 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
@ -352,6 +376,14 @@ 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
}
return uint64(stat.Size()), nil
}
func (s *storageService) Close(ctx context.Context) (err error) {
if s.ctxCancel != nil {
s.ctxCancel()

View file

@ -28,6 +28,34 @@ 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)
@ -192,7 +220,7 @@ type testConfig struct {
tmpDir string
}
func (t *testConfig) GetSpaceStorePath() string {
func (t *testConfig) GetSqliteStorePath() 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 liststorage.ListStorage
aclStorage oldstorage.ListStorage
header *spacesyncproto.RawSpaceHeaderWithId
}
func newSpaceStorage(s *storageService, spaceId string) (spacestorage.SpaceStorage, error) {
func newSpaceStorage(s *storageService, spaceId string) (oldstorage.SpaceStorage, error) {
ss := &spaceStorage{
spaceId: spaceId,
service: s,
@ -64,7 +64,7 @@ func newSpaceStorage(s *storageService, spaceId string) (spacestorage.SpaceStora
return ss, nil
}
func createSpaceStorage(s *storageService, payload spacestorage.SpaceStorageCreatePayload) (spacestorage.SpaceStorage, error) {
func createSpaceStorage(s *storageService, payload spacestorage.SpaceStorageCreatePayload) (oldstorage.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, spacestorage.TreeDeletedStatusDeleted)
rows, err := s.service.stmt.allTreeDelStatus.Query(s.spaceId, oldstorage.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() (liststorage.ListStorage, error) {
func (s *spaceStorage) AclStorage() (oldstorage.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) (treestorage.TreeStorage, error) {
func (s *spaceStorage) TreeStorage(id string) (oldstorage.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) (treestorage.TreeStorage, error) {
func (s *spaceStorage) CreateTreeStorage(payload treestorage.TreeStorageCreatePayload) (oldstorage.TreeStorage, error) {
return createTreeStorage(s, payload)
}

View file

@ -6,6 +6,7 @@ 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"
@ -90,7 +91,7 @@ func TestSpaceStorage_NewAndCreateTree(t *testing.T) {
treeIds, err := store.StoredIds()
require.NoError(t, err)
assert.Equal(t, []string{payload.SpaceSettingsWithId.Id, otherStore.Id()}, treeIds)
assert.Equal(t, []string{payload.SpaceSettingsWithId.Id}, treeIds)
deletedIds, err := store.(*spaceStorage).AllDeletedTreeIds()
require.NoError(t, err)
@ -106,11 +107,11 @@ func TestSpaceStorage_AllDeletedTreeIds(t *testing.T) {
store, err := createSpaceStorage(fx.storageService, payload)
require.NoError(t, err)
err = store.SetTreeDeletedStatus("id1", spacestorage.TreeDeletedStatusDeleted)
err = store.SetTreeDeletedStatus("id1", oldstorage.TreeDeletedStatusDeleted)
require.NoError(t, err)
err = store.SetTreeDeletedStatus("id2", spacestorage.TreeDeletedStatusQueued)
err = store.SetTreeDeletedStatus("id2", oldstorage.TreeDeletedStatusQueued)
require.NoError(t, err)
err = store.SetTreeDeletedStatus("id3", spacestorage.TreeDeletedStatusDeleted)
err = store.SetTreeDeletedStatus("id3", oldstorage.TreeDeletedStatusDeleted)
require.NoError(t, err)
deletedIds, err := store.(*spaceStorage).AllDeletedTreeIds()
@ -127,12 +128,12 @@ func TestSpaceStorage_SetTreeDeletedStatus(t *testing.T) {
store, err := createSpaceStorage(fx.storageService, payload)
require.NoError(t, err)
err = store.SetTreeDeletedStatus("treeId", spacestorage.TreeDeletedStatusDeleted)
err = store.SetTreeDeletedStatus("treeId", oldstorage.TreeDeletedStatusDeleted)
require.NoError(t, err)
status, err := store.TreeDeletedStatus("treeId")
require.NoError(t, err)
require.Equal(t, spacestorage.TreeDeletedStatusDeleted, status)
require.Equal(t, oldstorage.TreeDeletedStatusDeleted, status)
_, err = store.TreeStorage("treeId")
require.ErrorIs(t, err, treestorage.ErrUnknownTreeId)
@ -202,7 +203,7 @@ func TestSpaceStorage_ReadSpaceHash(t *testing.T) {
require.NoError(t, ss.WriteSpaceHash("hash"))
var checkHashes = func(ss spacestorage.SpaceStorage) {
var checkHashes = func(ss oldstorage.SpaceStorage) {
hash, err = ss.ReadSpaceHash()
require.NoError(t, err)
assert.Equal(t, "hash", hash)
@ -238,7 +239,7 @@ func spaceTestPayload() spacestorage.SpaceStorageCreatePayload {
}
}
func testSpace(t *testing.T, store spacestorage.SpaceStorage, payload spacestorage.SpaceStorageCreatePayload) {
func testSpace(t *testing.T, store oldstorage.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`); err != nil {
if s.stmt.treeIdsBySpace, err = s.readDb.Prepare(`SELECT id FROM trees WHERE spaceId = ? AND type != 1 AND deleteStatus IS NULL`); err != nil {
return
}
if s.stmt.deleteTree, err = s.writeDb.Prepare(`
@ -88,6 +88,12 @@ 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
}
@ -112,6 +118,9 @@ 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,15 +1,19 @@
package sqlitestorage
import (
"bytes"
"context"
"errors"
"fmt"
"sync"
"sync/atomic"
"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) (treestorage.TreeStorage, error) {
func newTreeStorage(ss *spaceStorage, treeId string) (oldstorage.TreeStorage, error) {
ts := &treeStorage{
treeId: treeId,
spaceStorage: ss,
@ -23,7 +27,7 @@ func newTreeStorage(ss *spaceStorage, treeId string) (treestorage.TreeStorage, e
return ts, nil
}
func createTreeStorage(ss *spaceStorage, payload treestorage.TreeStorageCreatePayload) (ts treestorage.TreeStorage, err error) {
func createTreeStorage(ss *spaceStorage, payload treestorage.TreeStorageCreatePayload) (ts oldstorage.TreeStorage, err error) {
ts = &treeStorage{
treeId: payload.RootRawChange.Id,
spaceStorage: ss,
@ -99,7 +103,54 @@ func (t *treeStorage) Heads() ([]string, error) {
}
func (t *treeStorage) GetAllChangeIds() (chs []string, err error) {
return nil, fmt.Errorf("get all change ids should not be called")
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()
}
func (t *treeStorage) SetHeads(heads []string) error {
@ -154,8 +205,14 @@ func (t *treeStorage) AddRawChangesSetHeads(changes []*treechangeproto.RawTreeCh
return nil
}
var totalCalls atomic.Int32
func (t *treeStorage) GetRawChange(ctx context.Context, id string) (*treechangeproto.RawTreeChangeWithId, error) {
ch, err := t.spaceStorage.TreeRoot(id)
// totalCalls.Store(totalCalls.Load() + 1)
// if totalCalls.Load()%10 == 0 {
// fmt.Println("totalCalls", totalCalls.Load())
// }
if err != nil {
return nil, replaceNoRowsErr(err, treestorage.ErrUnknownChange)
}

View file

@ -1,13 +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"
)
@ -54,7 +58,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: "newId"}
newChange := &treechangeproto.RawTreeChangeWithId{RawChange: []byte("ab"), Id: "id10"}
require.NoError(t, store.AddRawChange(newChange))
rawCh, err := store.GetRawChange(ctx, newChange.Id)
require.NoError(t, err)
@ -72,6 +76,55 @@ 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) {
@ -190,7 +243,7 @@ func treeTestPayload() treestorage.TreeStorageCreatePayload {
}
}
func testTreePayload(t *testing.T, store treestorage.TreeStorage, payload treestorage.TreeStorageCreatePayload) {
func testTreePayload(t *testing.T, store oldstorage.TreeStorage, payload treestorage.TreeStorageCreatePayload) {
require.Equal(t, payload.RootRawChange.Id, store.Id())
root, err := store.Root()

View file

@ -2,13 +2,11 @@ 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/badgerstorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/sqlitestorage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/anystorage"
)
type SpaceStorageMode int
@ -22,12 +20,7 @@ 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
@ -40,7 +33,7 @@ func New() ClientStorage {
}
type configGetter interface {
GetSpaceStorageMode() SpaceStorageMode
GetNewSpaceStorePath() string
}
func (s *storageService) Name() (name string) {
@ -48,16 +41,7 @@ func (s *storageService) Name() (name string) {
}
func (s *storageService) Init(a *app.App) (err error) {
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)
}
rootPath := a.MustComponent("config").(configGetter).GetNewSpaceStorePath()
s.ClientStorage = anystorage.New(rootPath)
return s.ClientStorage.Init(a)
}

View file

@ -25,6 +25,7 @@ import (
"github.com/anyproto/anytype-heart/pkg/lib/logging"
"github.com/anyproto/anytype-heart/pkg/lib/pb/model"
"github.com/anyproto/anytype-heart/space/spacecore"
"github.com/anyproto/anytype-heart/space/spacecore/storage/anystorage"
)
const CName = "space.typeprovider"
@ -196,17 +197,15 @@ func (p *provider) objectTypeFromSpace(spaceID string, id string) (tp smartblock
return
}
p.RUnlock()
sp, err := p.spaceService.Get(context.Background(), spaceID)
ctx := context.Background()
sp, err := p.spaceService.Get(ctx, spaceID)
if err != nil {
return
}
store := sp.Storage()
rawRoot, err := store.TreeRoot(id)
rawRoot, err := sp.Storage().(anystorage.ClientSpaceStorage).TreeRoot(ctx, id)
if err != nil {
return
}
tp, _, err = GetTypeAndKeyFromRoot(rawRoot)
if err != nil {
return

View file

@ -17,6 +17,7 @@ import (
"github.com/anyproto/anytype-heart/space/internal/spacecontroller"
"github.com/anyproto/anytype-heart/space/spacecore"
"github.com/anyproto/anytype-heart/space/spacecore/storage"
"github.com/anyproto/anytype-heart/space/spacecore/storage/anystorage"
"github.com/anyproto/anytype-heart/space/spaceinfo"
"github.com/anyproto/anytype-heart/space/techspace"
)
@ -71,7 +72,7 @@ func (s *spaceFactory) CreatePersonalSpace(ctx context.Context, metadata []byte)
if err != nil {
return
}
err = s.storageService.MarkSpaceCreated(coreSpace.Id())
err = coreSpace.Storage().(anystorage.ClientSpaceStorage).MarkSpaceCreated(ctx)
if err != nil {
return
}
@ -192,7 +193,11 @@ func (s *spaceFactory) CreateInvitingSpace(ctx context.Context, id, aclHeadId st
}
func (s *spaceFactory) CreateShareableSpace(ctx context.Context, id string) (sp spacecontroller.SpaceController, err error) {
err = s.storageService.MarkSpaceCreated(id)
coreSpace, err := s.spaceCore.Get(ctx, id)
if err != nil {
return
}
err = coreSpace.Storage().(anystorage.ClientSpaceStorage).MarkSpaceCreated(ctx)
if err != nil {
return
}

View file

@ -0,0 +1,15 @@
//go:build !windows
package freespace
import "golang.org/x/sys/unix"
func GetFreeDiskSpace(path string) (freeSpace uint64, err error) {
var stat unix.Statfs_t
err = unix.Statfs(path, &stat)
if err != nil {
return 0, err
}
freeSpace = stat.Bavail * uint64(stat.Bsize)
return freeSpace, nil
}

View file

@ -0,0 +1,15 @@
//go:build windows
package freespace
import "golang.org/x/sys/windows"
func GetFreeDiskSpace(path string) (uint64, error) {
var freeBytesAvailable, totalNumberOfBytes, totalNumberOfFreeBytes uint64
lpDirectoryName := windows.StringToUTF16Ptr(path)
err := windows.GetDiskFreeSpaceEx(lpDirectoryName, &freeBytesAvailable, &totalNumberOfBytes, &totalNumberOfFreeBytes)
if err != nil {
return 0, err
}
return freeBytesAvailable, nil
}

87
util/ziputil/ziputil.go Normal file
View file

@ -0,0 +1,87 @@
package ziputil
import (
"archive/zip"
"io"
"os"
"path/filepath"
"strings"
)
func ZipFolder(source, targetZip string) error {
zipFile, err := os.Create(targetZip)
if err != nil {
return err
}
defer zipFile.Close()
writer := zip.NewWriter(zipFile)
defer writer.Close()
return filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
relPath, err := filepath.Rel(source, path)
if err != nil {
return err
}
if relPath == "." {
return nil
}
if info.IsDir() {
_, err := writer.Create(strings.ReplaceAll(relPath, "\\", "/") + "/")
return err
}
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
zipWriter, err := writer.Create(strings.ReplaceAll(relPath, "\\", "/"))
if err != nil {
return err
}
_, err = io.Copy(zipWriter, f)
return err
})
}
func UnzipFolder(sourceZip, targetDir string) error {
r, err := zip.OpenReader(sourceZip)
if err != nil {
return err
}
defer r.Close()
if err := os.MkdirAll(targetDir, 0755); err != nil {
return err
}
for _, file := range r.File {
extractedPath := filepath.Join(targetDir, file.Name)
if file.FileInfo().IsDir() {
if err := os.MkdirAll(extractedPath, 0700); err != nil {
return err
}
continue
}
if err := extractFile(file, extractedPath); err != nil {
return err
}
}
return nil
}
func extractFile(file *zip.File, outputPath string) error {
rc, err := file.Open()
if err != nil {
return err
}
defer rc.Close()
outputFile, err := os.OpenFile(outputPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
if err != nil {
return err
}
defer outputFile.Close()
_, err = io.Copy(outputFile, rc)
return err
}

View file

@ -0,0 +1,92 @@
package ziputil
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
)
func TestZipAndUnzipFolder(t *testing.T) {
var (
sourceDir = t.TempDir()
tmpZipDir = t.TempDir()
unzipDir = t.TempDir()
)
zipPath := filepath.Join(tmpZipDir, "test_archive.zip")
err := createFolders(sourceDir)
require.NoError(t, err)
err = ZipFolder(sourceDir, zipPath)
require.NoError(t, err)
err = UnzipFolder(zipPath, unzipDir)
require.NoError(t, err)
err = compareDirectories(sourceDir, unzipDir)
require.NoError(t, err)
}
func createFolders(baseDir string) error {
subDir, err := os.MkdirTemp(baseDir, "subfolder")
if err != nil {
return err
}
file1 := filepath.Join(baseDir, "file1.txt")
if err := os.WriteFile(file1, []byte("Hello, World!"), 0700); err != nil {
return err
}
file2 := filepath.Join(subDir, "file2.txt")
if err := os.WriteFile(file2, []byte("Nested file content"), 0700); err != nil {
return err
}
return nil
}
func compareDirectories(dir1, dir2 string) error {
return filepath.Walk(dir1, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
relPath, err := filepath.Rel(dir1, path)
if err != nil {
return err
}
if relPath == "." {
return nil
}
pathInDir2 := filepath.Join(dir2, relPath)
info2, err := os.Stat(pathInDir2)
if err != nil {
return err
}
if info.IsDir() {
if !info2.IsDir() {
return &mismatchError{path, pathInDir2, "dir vs file"}
}
} else {
if info2.IsDir() {
return &mismatchError{path, pathInDir2, "file vs dir"}
}
content1, err := ioutil.ReadFile(path)
if err != nil {
return err
}
content2, err := ioutil.ReadFile(pathInDir2)
if err != nil {
return err
}
if string(content1) != string(content2) {
return &mismatchError{path, pathInDir2, "file content mismatch"}
}
}
return nil
})
}
type mismatchError struct {
path1, path2, reason string
}
func (m *mismatchError) Error() string {
return "Mismatch between " + m.path1 + " and " + m.path2 + ": " + m.reason
}