From 0c025fa93720edafd33cf39c027c3091f5a54aea Mon Sep 17 00:00:00 2001 From: paul cannon Date: Wed, 25 Sep 2019 16:30:41 -0500 Subject: [PATCH] storage/: remove reverse-key-listing feature We don't use reverse listing in any of our code, outside of tests, and it is only exposed through libuplink in the lib/uplink.(*Project).ListBuckets() API. We also don't know of any users who might have a need for reverse listing through ListBuckets(). Since one of our prospective pointerdb backends can not support backwards iteration, and because of the above considerations, we are going to remove the reverse listing feature. Change-Id: I8d2a1f33d01ee70b79918d584b8c671f57eef2a0 --- internal/testplanet/uplink_test.go | 4 +- pkg/pb/metainfo.pb.go | 469 +++++++++++---------- pkg/pb/metainfo.proto | 2 +- pkg/storj/metainfo.go | 45 +- proto.lock | 8 +- satellite/metainfo/metainfo.go | 7 +- satellite/metainfo/service.go | 3 +- satellite/repair/repair_test.go | 4 +- storage/boltdb/client.go | 47 +-- storage/common.go | 2 - storage/iterator.go | 20 - storage/listv2.go | 26 +- storage/postgreskv/alternateclient.go | 31 +- storage/postgreskv/client.go | 21 +- storage/redis/client.go | 10 +- storage/storelogger/logger.go | 1 - storage/teststore/store.go | 8 +- storage/testsuite/long_bench.go | 193 +-------- storage/testsuite/test_iterate.go | 29 -- storage/testsuite/test_iterate_all.go | 69 --- storage/testsuite/test_listv2.go | 43 -- storage/testsuite/test_prefix.go | 18 - uplink/metainfo/client_old.go | 3 +- uplink/metainfo/kvmetainfo/objects.go | 15 +- uplink/metainfo/kvmetainfo/objects_test.go | 285 ++----------- uplink/metainfo/kvmetainfo/prefixed.go | 4 +- uplink/storage/objects/store.go | 6 +- uplink/storage/streams/shim.go | 6 +- uplink/storage/streams/store.go | 10 +- uplink/storage/streams/store_test.go | 18 +- 30 files changed, 326 insertions(+), 1081 deletions(-) diff --git a/internal/testplanet/uplink_test.go b/internal/testplanet/uplink_test.go index 19087c384..62d990ff7 100644 --- a/internal/testplanet/uplink_test.go +++ b/internal/testplanet/uplink_test.go @@ -91,7 +91,7 @@ func TestDownloadWithSomeNodesOffline(t *testing.T) { // get a remote segment from pointerdb pdb := satellite.Metainfo.Service - listResponse, _, err := pdb.List(ctx, "", "", "", true, 0, 0) + listResponse, _, err := pdb.List(ctx, "", "", true, 0, 0) require.NoError(t, err) var path string @@ -195,7 +195,7 @@ func TestDownloadFromUnresponsiveNode(t *testing.T) { // get a remote segment from pointerdb pdb := planet.Satellites[0].Metainfo.Service - listResponse, _, err := pdb.List(ctx, "", "", "", true, 0, 0) + listResponse, _, err := pdb.List(ctx, "", "", true, 0, 0) require.NoError(t, err) var path string diff --git a/pkg/pb/metainfo.pb.go b/pkg/pb/metainfo.pb.go index 33e921d4a..a7eeb48c2 100644 --- a/pkg/pb/metainfo.pb.go +++ b/pkg/pb/metainfo.pb.go @@ -1310,7 +1310,7 @@ type ListSegmentsRequestOld struct { Bucket []byte `protobuf:"bytes,1,opt,name=bucket,proto3" json:"bucket,omitempty"` Prefix []byte `protobuf:"bytes,2,opt,name=prefix,proto3" json:"prefix,omitempty"` StartAfter []byte `protobuf:"bytes,3,opt,name=start_after,json=startAfter,proto3" json:"start_after,omitempty"` - EndBefore []byte `protobuf:"bytes,4,opt,name=end_before,json=endBefore,proto3" json:"end_before,omitempty"` + EndBefore []byte `protobuf:"bytes,4,opt,name=end_before,json=endBefore,proto3" json:"end_before,omitempty"` // Deprecated: Do not use. Recursive bool `protobuf:"varint,5,opt,name=recursive,proto3" json:"recursive,omitempty"` Limit int32 `protobuf:"varint,6,opt,name=limit,proto3" json:"limit,omitempty"` MetaFlags uint32 `protobuf:"fixed32,7,opt,name=meta_flags,json=metaFlags,proto3" json:"meta_flags,omitempty"` @@ -1371,6 +1371,7 @@ func (m *ListSegmentsRequestOld) GetStartAfter() []byte { return nil } +// Deprecated: Do not use. func (m *ListSegmentsRequestOld) GetEndBefore() []byte { if m != nil { return m.EndBefore @@ -5133,239 +5134,239 @@ func init() { func init() { proto.RegisterFile("metainfo.proto", fileDescriptor_631e2f30a93cd64e) } var fileDescriptor_631e2f30a93cd64e = []byte{ - // 3709 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0x4b, 0x6c, 0x1c, 0x59, - 0xd5, 0x76, 0xbf, 0xbb, 0x4f, 0xb7, 0xdd, 0xdd, 0xd7, 0x8e, 0xdd, 0x29, 0xc7, 0x71, 0x52, 0x49, - 0x66, 0xfc, 0xeb, 0x9f, 0x71, 0x46, 0x9e, 0xff, 0x47, 0x83, 0x92, 0x61, 0xb0, 0xd3, 0x9e, 0x74, - 0x4f, 0x62, 0xc7, 0x53, 0x4e, 0x26, 0x21, 0x0c, 0xb4, 0xca, 0x5d, 0xd7, 0x76, 0x91, 0xee, 0xae, - 0xa6, 0xaa, 0x7a, 0xc6, 0x19, 0x56, 0x48, 0x23, 0x21, 0x04, 0x42, 0x23, 0xd6, 0x88, 0xd5, 0xec, - 0x58, 0xc1, 0x0e, 0x09, 0xd8, 0x02, 0x12, 0x1a, 0xa4, 0x11, 0x62, 0xc1, 0x62, 0x60, 0xc5, 0x0e, - 0x36, 0xec, 0x40, 0x48, 0xe8, 0xbe, 0xea, 0x5d, 0xfd, 0xf0, 0x23, 0x61, 0x76, 0x55, 0xe7, 0x9e, - 0x7b, 0xea, 0xde, 0xf3, 0xf8, 0xce, 0xa9, 0x73, 0xab, 0x60, 0xa6, 0x8b, 0x6d, 0x55, 0xef, 0xed, - 0x1b, 0xab, 0x7d, 0xd3, 0xb0, 0x0d, 0x94, 0x17, 0xf7, 0x52, 0x05, 0xf7, 0xda, 0xe6, 0xd3, 0xbe, - 0xad, 0x1b, 0x3d, 0x36, 0x26, 0xc1, 0x81, 0x71, 0xc0, 0xf9, 0xa4, 0xe5, 0x03, 0xc3, 0x38, 0xe8, - 0xe0, 0xeb, 0xf4, 0x6e, 0x6f, 0xb0, 0x7f, 0xdd, 0xd6, 0xbb, 0xd8, 0xb2, 0xd5, 0x6e, 0x5f, 0x30, - 0xf7, 0x0c, 0x0d, 0xf3, 0xeb, 0x72, 0xdf, 0xd0, 0x7b, 0x36, 0x36, 0xb5, 0x3d, 0x4e, 0x28, 0x19, - 0xa6, 0x86, 0x4d, 0x8b, 0xdd, 0xc9, 0x2b, 0x30, 0xad, 0xe0, 0x6f, 0x0e, 0xb0, 0x65, 0x37, 0xb0, - 0xaa, 0x61, 0x13, 0x2d, 0x40, 0x4e, 0xed, 0xeb, 0xad, 0x27, 0xf8, 0x69, 0x2d, 0x71, 0x29, 0xb1, - 0x52, 0x52, 0xb2, 0x6a, 0x5f, 0xbf, 0x83, 0x9f, 0xca, 0x3f, 0x49, 0x41, 0x76, 0x63, 0xd0, 0x7e, - 0x82, 0x6d, 0x84, 0x20, 0xdd, 0x53, 0xbb, 0x98, 0x33, 0xd0, 0x6b, 0xf4, 0x1a, 0x14, 0xfb, 0xaa, - 0x7d, 0xd8, 0x6a, 0xeb, 0xfd, 0x43, 0x6c, 0xd6, 0x92, 0x97, 0x12, 0x2b, 0x33, 0x6b, 0x0b, 0xab, - 0x9e, 0x8d, 0xdc, 0xa2, 0x23, 0xbb, 0x03, 0xdd, 0xc6, 0x0a, 0x10, 0x5e, 0x46, 0x40, 0xb7, 0x00, - 0xda, 0x26, 0x56, 0x6d, 0xac, 0xb5, 0x54, 0xbb, 0x96, 0xba, 0x94, 0x58, 0x29, 0xae, 0x49, 0xab, - 0x6c, 0x8f, 0xab, 0x62, 0x8f, 0xab, 0xf7, 0xc5, 0x1e, 0x37, 0xf2, 0xbf, 0xf9, 0x6c, 0x79, 0xea, - 0xa3, 0x3f, 0x2f, 0x27, 0x94, 0x02, 0x9f, 0xb7, 0x6e, 0xa3, 0x57, 0x60, 0x4e, 0xc3, 0xfb, 0xea, - 0xa0, 0x63, 0xb7, 0x2c, 0x7c, 0xd0, 0xc5, 0x3d, 0xbb, 0x65, 0xe9, 0x1f, 0xe0, 0x5a, 0xfa, 0x52, - 0x62, 0x25, 0xa5, 0x20, 0x3e, 0xb6, 0xcb, 0x86, 0x76, 0xf5, 0x0f, 0x30, 0x7a, 0x08, 0xe7, 0xc5, - 0x0c, 0x13, 0x6b, 0x83, 0x9e, 0xa6, 0xf6, 0xda, 0x4f, 0x5b, 0x56, 0xfb, 0x10, 0x77, 0x71, 0x2d, - 0x43, 0x57, 0xb1, 0xb8, 0xea, 0x2a, 0x4f, 0x71, 0x78, 0x76, 0x29, 0x8b, 0xb2, 0xc0, 0x67, 0x07, - 0x07, 0x90, 0x06, 0x4b, 0x42, 0xb0, 0xbb, 0xfb, 0x56, 0x5f, 0x35, 0xd5, 0x2e, 0xb6, 0xb1, 0x69, - 0xd5, 0xb2, 0x54, 0xf8, 0x25, 0xaf, 0x6e, 0x36, 0x9d, 0xcb, 0x1d, 0x87, 0x4f, 0x59, 0xe4, 0x62, - 0xa2, 0x06, 0xd1, 0x12, 0x40, 0x5f, 0x35, 0xed, 0x1e, 0x36, 0x5b, 0xba, 0x56, 0xcb, 0x51, 0x4b, - 0x14, 0x38, 0xa5, 0xa9, 0xc9, 0x3a, 0xcc, 0x30, 0x63, 0xdd, 0xd5, 0x2d, 0xbb, 0x69, 0xe3, 0x6e, - 0xa4, 0xd1, 0xfc, 0xaa, 0x4f, 0x1e, 0x4b, 0xf5, 0xf2, 0xc7, 0x29, 0x98, 0x65, 0xcf, 0xba, 0x45, - 0x69, 0xdc, 0x9f, 0xd0, 0x75, 0xc8, 0x1e, 0x52, 0x9f, 0xaa, 0x95, 0xa9, 0xe0, 0x85, 0x55, 0xc7, - 0xdf, 0x7d, 0x2e, 0xa7, 0x70, 0xb6, 0x53, 0x76, 0xab, 0x38, 0x8f, 0x48, 0x1d, 0xcf, 0x23, 0xd2, - 0x67, 0xe9, 0x11, 0x99, 0xd3, 0xf7, 0x88, 0x6c, 0xd0, 0x23, 0xbe, 0x0c, 0x73, 0x7e, 0x2b, 0x59, - 0x7d, 0xa3, 0x67, 0x61, 0xb4, 0x02, 0xd9, 0x3d, 0x4a, 0xa7, 0x7a, 0x2f, 0xae, 0x55, 0x5c, 0x33, - 0x31, 0x7e, 0x85, 0x8f, 0xcb, 0x0f, 0xa1, 0xc2, 0x28, 0xb7, 0xb1, 0x7d, 0x9a, 0x46, 0x96, 0x5f, - 0x87, 0xaa, 0x47, 0xf0, 0xc4, 0xeb, 0x7a, 0x2c, 0xfc, 0xaf, 0x8e, 0x3b, 0xf8, 0x74, 0xfd, 0x4f, - 0x9e, 0x17, 0x5a, 0x13, 0xb2, 0xd9, 0xea, 0xe4, 0x8f, 0x12, 0x62, 0xcd, 0x24, 0xc0, 0x8e, 0xfd, - 0xc8, 0x79, 0xc8, 0xb6, 0x07, 0xa6, 0x65, 0x98, 0x02, 0x6c, 0xd9, 0x1d, 0x9a, 0x83, 0x4c, 0x47, - 0xef, 0xea, 0x2c, 0x26, 0x33, 0x0a, 0xbb, 0x41, 0x17, 0xa0, 0xa0, 0xe9, 0x26, 0x6e, 0x13, 0xc3, - 0x53, 0x3f, 0xce, 0x28, 0x2e, 0x41, 0x7e, 0x04, 0xc8, 0xbb, 0x22, 0xae, 0xc6, 0x55, 0xc8, 0xe8, - 0x36, 0xee, 0x5a, 0xb5, 0xc4, 0xa5, 0xd4, 0x4a, 0x71, 0xad, 0x16, 0xd4, 0xa2, 0xc0, 0x07, 0x85, - 0xb1, 0x11, 0x25, 0x74, 0x0d, 0x13, 0xd3, 0x07, 0xe7, 0x15, 0x7a, 0x2d, 0x7f, 0x3b, 0x01, 0x8b, - 0x8c, 0x7b, 0x17, 0xdb, 0xeb, 0xb6, 0x6d, 0xea, 0x7b, 0x03, 0xf2, 0xc8, 0x53, 0x8d, 0x74, 0xbf, - 0xfb, 0x26, 0x83, 0xee, 0x7b, 0x11, 0x2e, 0x44, 0x2f, 0x81, 0x1b, 0xe4, 0xc3, 0x04, 0xcc, 0xae, - 0x6b, 0x9a, 0x89, 0x2d, 0x0b, 0x6b, 0xf7, 0x48, 0x8a, 0xbb, 0x4b, 0x75, 0xb6, 0x22, 0x34, 0xc9, - 0xbc, 0x08, 0xad, 0xf2, 0xf4, 0xe7, 0xb2, 0x08, 0xed, 0xde, 0x82, 0x39, 0xcb, 0x36, 0x4c, 0xf5, - 0x00, 0xb7, 0x48, 0xfe, 0x6c, 0xa9, 0x4c, 0x1a, 0x87, 0xc5, 0xea, 0x2a, 0x4d, 0xaa, 0xdb, 0x86, - 0x86, 0xf9, 0x63, 0x14, 0xc4, 0xd9, 0x3d, 0x34, 0xf9, 0xf7, 0x49, 0x98, 0xe7, 0x98, 0xf2, 0xd0, - 0xd4, 0x1d, 0x67, 0xbc, 0xd7, 0xd1, 0x8e, 0xe5, 0x1c, 0x9e, 0x08, 0x28, 0x09, 0x7f, 0x27, 0xda, - 0x23, 0x38, 0xc7, 0x75, 0x44, 0xaf, 0x51, 0x0d, 0x72, 0x1c, 0xe5, 0x38, 0xc0, 0x89, 0x5b, 0x74, - 0x03, 0xc0, 0x45, 0xb3, 0x71, 0x60, 0xcc, 0xc3, 0x8e, 0x6e, 0x80, 0xd4, 0x55, 0x8f, 0x04, 0x6a, - 0x61, 0xcd, 0x0f, 0xa5, 0x19, 0xfa, 0xa4, 0x85, 0xae, 0x7a, 0xb4, 0x29, 0x18, 0xbc, 0x78, 0x5a, - 0x07, 0xc0, 0x47, 0x7d, 0xdd, 0x54, 0xa9, 0xbf, 0x66, 0x27, 0xc8, 0x2e, 0x9e, 0x79, 0xf2, 0xa7, - 0x09, 0x58, 0xf0, 0x6b, 0x94, 0x59, 0x9c, 0xa8, 0xb4, 0x01, 0x15, 0x55, 0xd8, 0xbc, 0x45, 0xad, - 0x28, 0xfc, 0x7c, 0xc9, 0x55, 0x6e, 0x84, 0x57, 0x28, 0x65, 0x67, 0x1a, 0xbd, 0xb7, 0xd0, 0xab, - 0x30, 0x6d, 0x1a, 0x86, 0xdd, 0xea, 0xeb, 0xb8, 0x8d, 0x1d, 0x07, 0xdc, 0x28, 0x93, 0x25, 0xfd, - 0xe9, 0xb3, 0xe5, 0xdc, 0x0e, 0xa1, 0x37, 0xeb, 0x4a, 0x91, 0x70, 0xb1, 0x1b, 0x8d, 0x26, 0x27, - 0x53, 0x7f, 0x4f, 0xb5, 0x31, 0xad, 0x97, 0x52, 0x74, 0xca, 0x02, 0x9f, 0x52, 0xa6, 0x5c, 0x3b, - 0x6c, 0xfc, 0x0e, 0x7e, 0xaa, 0x40, 0xdf, 0xb9, 0x96, 0xff, 0xe5, 0x6e, 0xea, 0x96, 0xd1, 0x25, - 0x2b, 0x7a, 0xee, 0x7e, 0xf2, 0x12, 0xe4, 0xb8, 0x53, 0x70, 0x27, 0x41, 0x1e, 0x27, 0xd9, 0x61, - 0x57, 0x8a, 0x60, 0x41, 0x37, 0xa0, 0x6c, 0x98, 0xfa, 0x81, 0xde, 0x53, 0x3b, 0x42, 0xf1, 0x19, - 0xaa, 0xf8, 0xa8, 0x00, 0x9b, 0x11, 0xac, 0x4c, 0xd9, 0x72, 0x03, 0x6a, 0x81, 0xcd, 0xbb, 0x26, - 0xf5, 0x2c, 0x23, 0x31, 0x72, 0x19, 0xf2, 0x0f, 0x13, 0x70, 0x9e, 0x8b, 0xaa, 0x1b, 0xef, 0xf7, - 0x3a, 0x86, 0xaa, 0x3d, 0x77, 0x4d, 0xca, 0x9f, 0x24, 0x40, 0x0a, 0x2d, 0xea, 0x2c, 0x9c, 0xd6, - 0xa3, 0xab, 0xe4, 0x68, 0x93, 0x1d, 0xdf, 0x5b, 0x7f, 0x90, 0x80, 0x73, 0x7c, 0x43, 0xcd, 0xde, - 0xbe, 0xf1, 0xfc, 0x35, 0xfc, 0xa6, 0x03, 0xb2, 0x6c, 0x3d, 0x91, 0xee, 0x33, 0x5a, 0x25, 0x24, - 0x8b, 0x8b, 0x30, 0xf4, 0xd5, 0x0e, 0xcf, 0x71, 0x6b, 0x3f, 0x4e, 0x38, 0xc1, 0xe1, 0x2f, 0x39, - 0x4e, 0xd7, 0x75, 0x02, 0xce, 0x90, 0x1c, 0xdf, 0x19, 0xbe, 0x9f, 0x84, 0x79, 0x52, 0x34, 0xf0, - 0x45, 0x5a, 0x67, 0xa1, 0xb2, 0x79, 0xc8, 0xf6, 0x4d, 0xbc, 0xaf, 0x1f, 0x71, 0xa5, 0xf1, 0x3b, - 0xb4, 0x0c, 0x45, 0xcb, 0x56, 0x4d, 0xbb, 0xa5, 0xee, 0x13, 0x0b, 0x53, 0x17, 0x56, 0x80, 0x92, - 0xd6, 0x09, 0x85, 0x14, 0x11, 0xb8, 0xa7, 0xb5, 0xf6, 0xf0, 0x3e, 0xa9, 0x61, 0xd2, 0xac, 0x88, - 0xc0, 0x3d, 0x6d, 0x83, 0x12, 0x48, 0x01, 0x65, 0x62, 0x52, 0x62, 0xe9, 0xef, 0xb1, 0xec, 0x95, - 0x57, 0x5c, 0x82, 0x5b, 0x74, 0x65, 0xbd, 0x45, 0xd7, 0x12, 0x00, 0xd9, 0x45, 0x6b, 0xbf, 0xa3, - 0x1e, 0x58, 0xf4, 0x45, 0x2b, 0xa7, 0x14, 0x08, 0xe5, 0x4d, 0x42, 0xa0, 0xe9, 0xc9, 0xaf, 0x0e, - 0xd7, 0x5c, 0x37, 0xfd, 0xb5, 0xd7, 0x0b, 0xae, 0x3a, 0x62, 0x66, 0xac, 0x8e, 0xa8, 0xc4, 0x24, - 0x0c, 0x69, 0xf1, 0x32, 0x47, 0x7d, 0x2a, 0xe1, 0xf1, 0xa9, 0xc9, 0xd0, 0x60, 0x11, 0x0a, 0xba, - 0xd5, 0xe2, 0x5a, 0x4e, 0xd1, 0x47, 0xe4, 0x75, 0x6b, 0x87, 0xde, 0xcb, 0xdf, 0xa3, 0x4e, 0x18, - 0x51, 0xea, 0x1d, 0xcb, 0xca, 0xcb, 0x50, 0x64, 0x76, 0x6d, 0x79, 0x8a, 0x3e, 0x60, 0xa4, 0xed, - 0x31, 0x4a, 0xbf, 0x45, 0x82, 0xf1, 0x51, 0x45, 0xdf, 0xbd, 0x8e, 0x26, 0x6f, 0x02, 0xda, 0x31, - 0x8d, 0x6f, 0xe0, 0xb6, 0x17, 0x9a, 0x26, 0x5e, 0xa3, 0xfc, 0x1a, 0xcc, 0xfa, 0xc4, 0xf0, 0xea, - 0xf9, 0x32, 0x94, 0xfa, 0x8c, 0xdc, 0xb2, 0xd4, 0x8e, 0x70, 0xd3, 0x22, 0xa7, 0xed, 0xaa, 0x1d, - 0x5b, 0xfe, 0x6e, 0x0e, 0xb2, 0xf7, 0xf6, 0xc8, 0x6d, 0xac, 0x3b, 0x5f, 0x83, 0x19, 0xb7, 0x82, - 0xf2, 0x60, 0xc1, 0xb4, 0x43, 0xdd, 0xe1, 0xa0, 0xf0, 0x1e, 0x36, 0x2d, 0xb7, 0xb8, 0x17, 0xb7, - 0x64, 0x3b, 0x96, 0xad, 0xda, 0x03, 0x8b, 0xba, 0xf4, 0x8c, 0x77, 0x3b, 0xec, 0xd1, 0xab, 0xbb, - 0x74, 0x58, 0xe1, 0x6c, 0xe8, 0x65, 0x28, 0x58, 0xb6, 0x89, 0xd5, 0x2e, 0x51, 0x68, 0x86, 0x06, - 0x77, 0x85, 0x07, 0x77, 0x7e, 0x97, 0x0e, 0x34, 0xeb, 0x4a, 0x9e, 0xb1, 0x34, 0xb5, 0x40, 0x1f, - 0x20, 0x7b, 0xbc, 0x16, 0xcc, 0x3a, 0x79, 0x26, 0x79, 0x3a, 0x91, 0x91, 0x9b, 0x40, 0x46, 0x9e, - 0x4d, 0x5b, 0x27, 0x25, 0x38, 0xab, 0xfc, 0x30, 0x95, 0x91, 0x9f, 0x64, 0x1d, 0x7c, 0xde, 0xba, - 0x8d, 0x6e, 0x43, 0xcd, 0xd5, 0x36, 0xd1, 0x93, 0xa6, 0xda, 0x6a, 0xab, 0x67, 0xf4, 0xda, 0xb8, - 0x56, 0xa0, 0xaa, 0x98, 0xe6, 0xaa, 0xc8, 0x6c, 0x13, 0xa2, 0x32, 0xef, 0xb0, 0x6f, 0x71, 0x6e, - 0x4a, 0x47, 0x2f, 0x03, 0x0a, 0x0b, 0xaa, 0x01, 0x35, 0x5d, 0x35, 0x34, 0x07, 0xbd, 0x04, 0x68, - 0x5f, 0x3f, 0x0a, 0xd6, 0xc8, 0x45, 0x0a, 0xef, 0x15, 0x3a, 0xe2, 0x2d, 0x8e, 0x1b, 0x50, 0x0d, - 0x37, 0x19, 0x4a, 0xa3, 0xab, 0xf3, 0x8a, 0x19, 0xec, 0x2e, 0x3c, 0x80, 0x73, 0xd1, 0x5d, 0x85, - 0xe9, 0x31, 0xbb, 0x0a, 0x73, 0x38, 0xa6, 0x9d, 0x60, 0x1b, 0xb6, 0xda, 0x61, 0xdb, 0x98, 0xa1, - 0xdb, 0x28, 0x50, 0x0a, 0x5d, 0xff, 0x32, 0x14, 0xf5, 0x5e, 0x47, 0xef, 0x61, 0x36, 0x5e, 0xa6, - 0xe3, 0xc0, 0x48, 0x82, 0xc1, 0xc4, 0x5d, 0xc3, 0xe6, 0x0c, 0x15, 0xc6, 0xc0, 0x48, 0x84, 0x41, - 0x7e, 0x1b, 0xb2, 0xcc, 0x6b, 0x51, 0x11, 0x72, 0xcd, 0xed, 0x77, 0xd6, 0xef, 0x36, 0xeb, 0x95, - 0x29, 0x34, 0x0d, 0x85, 0x07, 0x3b, 0x77, 0xef, 0xad, 0xd7, 0x9b, 0xdb, 0xb7, 0x2b, 0x09, 0x34, - 0x03, 0x70, 0xeb, 0xde, 0xd6, 0x56, 0xf3, 0xfe, 0x7d, 0x72, 0x9f, 0x24, 0xc3, 0xfc, 0x7e, 0xb3, - 0x5e, 0x49, 0xa1, 0x12, 0xe4, 0xeb, 0x9b, 0x77, 0x37, 0xe9, 0x60, 0x5a, 0xfe, 0x30, 0x05, 0x88, - 0x05, 0xc4, 0x06, 0x3e, 0xd0, 0x7b, 0x27, 0x79, 0x2d, 0x3f, 0x9b, 0x40, 0xf6, 0x3b, 0x78, 0xfa, - 0x78, 0x0e, 0x1e, 0xe9, 0x3a, 0xb9, 0x53, 0x75, 0x9d, 0xfc, 0x49, 0x5c, 0x47, 0xfe, 0x55, 0x12, - 0x66, 0x7d, 0x66, 0xe0, 0x68, 0x7a, 0x66, 0x6a, 0xf5, 0xc1, 0x5d, 0x7a, 0x24, 0xdc, 0x45, 0x2a, - 0x30, 0x73, 0xaa, 0x0a, 0xcc, 0x9e, 0x48, 0x81, 0x7f, 0x4b, 0x08, 0x05, 0xfa, 0xde, 0x0e, 0x27, - 0x77, 0x64, 0x9f, 0x62, 0x12, 0x23, 0x15, 0x33, 0x0c, 0x3a, 0x93, 0x27, 0x87, 0xce, 0x54, 0x0c, - 0x74, 0xca, 0xf3, 0x30, 0xe7, 0xdf, 0x2e, 0x6f, 0xea, 0xfc, 0x28, 0x01, 0x15, 0x36, 0x70, 0x92, - 0x96, 0xe3, 0x59, 0xb9, 0x9d, 0xfc, 0x3a, 0x54, 0x3d, 0xab, 0x73, 0xfb, 0x96, 0x06, 0x25, 0x86, - 0xfb, 0x96, 0x8c, 0x59, 0xe1, 0xe3, 0xf2, 0x4f, 0x93, 0x62, 0xfe, 0x49, 0x7b, 0x88, 0x91, 0xdb, - 0xfb, 0x1f, 0xa8, 0x78, 0xb6, 0xe7, 0x2d, 0xa7, 0xcb, 0xee, 0x06, 0x59, 0x5d, 0xed, 0x63, 0xe5, - 0x0d, 0xc9, 0x54, 0x80, 0xf5, 0x16, 0xeb, 0x4c, 0xfa, 0x4a, 0xe8, 0x74, 0x6c, 0x09, 0x9d, 0xf1, - 0x96, 0xd0, 0x4d, 0x28, 0xb3, 0x2d, 0xb7, 0xf4, 0x5e, 0xbb, 0x33, 0xd0, 0xb0, 0x1b, 0x1f, 0x01, - 0xdd, 0x88, 0x6e, 0x64, 0x93, 0xf3, 0x29, 0x33, 0x6c, 0xa2, 0xb8, 0x97, 0x1f, 0x09, 0x80, 0x1f, - 0xb3, 0xc9, 0xe9, 0x17, 0x3b, 0xac, 0xc9, 0xf9, 0xeb, 0x14, 0xcc, 0xf8, 0xb9, 0x23, 0x1c, 0x24, - 0x31, 0xc2, 0x41, 0x92, 0x71, 0x75, 0x5b, 0x6a, 0xbc, 0xba, 0xcd, 0x5f, 0x88, 0xa5, 0x4f, 0xa1, - 0x10, 0xcb, 0x9c, 0x42, 0x21, 0x96, 0x3d, 0xfd, 0x42, 0x2c, 0x77, 0x72, 0x34, 0xc9, 0xc7, 0xa1, - 0xc9, 0xff, 0xc1, 0x7c, 0xb4, 0x37, 0x21, 0x09, 0xf2, 0xce, 0xf4, 0x04, 0x7b, 0xe7, 0x11, 0xf7, - 0xf2, 0xc7, 0x09, 0xa8, 0x79, 0x92, 0xd6, 0x09, 0xcf, 0x12, 0xce, 0x0c, 0x73, 0xde, 0x82, 0xf3, - 0x11, 0xab, 0xe4, 0x71, 0x30, 0x19, 0xdc, 0xcb, 0xdf, 0x12, 0xb2, 0xde, 0xd4, 0x7b, 0xba, 0x75, - 0x78, 0xc2, 0x2d, 0x4f, 0xf8, 0xf0, 0x0b, 0x20, 0x45, 0x3d, 0x9c, 0x23, 0xff, 0xdf, 0x93, 0x50, - 0xdc, 0x55, 0x6d, 0x31, 0xef, 0xec, 0x4a, 0x87, 0x13, 0xb5, 0xc7, 0x9b, 0x30, 0x4d, 0xc3, 0x8e, - 0x24, 0x7f, 0x4d, 0xb5, 0xf1, 0x44, 0xd1, 0x56, 0x12, 0x53, 0xeb, 0xaa, 0x8d, 0xd1, 0x16, 0x94, - 0xdd, 0xa6, 0x37, 0x13, 0x36, 0x49, 0xd8, 0xcd, 0xb8, 0x93, 0xa9, 0xb8, 0xeb, 0x30, 0x6b, 0xa9, - 0x36, 0xee, 0x74, 0x74, 0x5a, 0x80, 0x1f, 0xf4, 0x54, 0x7b, 0x60, 0xf2, 0xf7, 0x1f, 0x05, 0x39, - 0x43, 0xbb, 0x62, 0x44, 0xfe, 0x4b, 0x12, 0x72, 0xfc, 0xfd, 0x64, 0xd2, 0xaa, 0xe1, 0xff, 0x21, - 0xdf, 0x37, 0x2c, 0xdd, 0x16, 0x00, 0x58, 0x5c, 0x3b, 0xef, 0xfa, 0x0a, 0x97, 0xb9, 0xc3, 0x19, - 0x14, 0x87, 0x15, 0xbd, 0x0e, 0xb3, 0xae, 0xe9, 0x9e, 0xe0, 0xa7, 0x1c, 0x19, 0x52, 0x51, 0xc8, - 0xe0, 0x46, 0xf9, 0x1d, 0xfc, 0x94, 0x81, 0xc2, 0x15, 0x98, 0xf6, 0x4d, 0xe7, 0xdd, 0x9e, 0x92, - 0x97, 0x13, 0xad, 0xc2, 0x2c, 0x79, 0xfb, 0xf0, 0x1c, 0x60, 0xd0, 0xd8, 0x67, 0x07, 0x17, 0x55, - 0x32, 0xe4, 0x9c, 0x5c, 0xd4, 0xc9, 0x3b, 0xdc, 0x9a, 0x53, 0xcf, 0x61, 0xad, 0xc5, 0xdf, 0x6f, - 0xe8, 0x0c, 0x76, 0x9c, 0xea, 0x2e, 0xb8, 0x49, 0xc7, 0xe8, 0x9c, 0x17, 0x21, 0x4b, 0x4f, 0x0d, - 0xac, 0x5a, 0x8e, 0x66, 0x9f, 0xb2, 0xbb, 0x79, 0xda, 0x47, 0x53, 0xf8, 0xb0, 0xdc, 0x80, 0x0c, - 0x25, 0xa0, 0x45, 0x28, 0xb0, 0x73, 0x86, 0xde, 0xa0, 0x4b, 0xf5, 0x9b, 0x51, 0xf2, 0x94, 0xb0, - 0x3d, 0xe8, 0x22, 0x19, 0xd2, 0x3d, 0x43, 0x13, 0xf5, 0xd6, 0x0c, 0xd7, 0x43, 0x76, 0xdb, 0xd0, - 0x70, 0xb3, 0xae, 0xd0, 0x31, 0xb9, 0x01, 0xe5, 0x80, 0x5e, 0xc9, 0xeb, 0x56, 0x5f, 0x35, 0x6d, - 0x22, 0x72, 0x8f, 0xf7, 0xce, 0x33, 0x0a, 0x6d, 0xab, 0x6c, 0x53, 0x0a, 0x49, 0xcd, 0x7a, 0x4f, - 0xc3, 0x47, 0xe2, 0x48, 0x91, 0xde, 0xc8, 0x7f, 0x48, 0xc0, 0x2c, 0x17, 0x75, 0xb2, 0x57, 0xa6, - 0x67, 0xe3, 0x33, 0x2f, 0x40, 0xb9, 0xab, 0x1e, 0xb5, 0xe8, 0x11, 0x03, 0x6b, 0x80, 0xf2, 0xfe, - 0xe9, 0x74, 0x57, 0x3d, 0x72, 0xfb, 0x9d, 0xf2, 0xef, 0x12, 0x30, 0xe7, 0xdf, 0x16, 0x47, 0xc8, - 0x57, 0x00, 0xc4, 0xeb, 0xb9, 0xb3, 0xce, 0x2a, 0x5f, 0x67, 0x41, 0xf4, 0x94, 0xeb, 0x4a, 0x81, - 0x33, 0x35, 0xa3, 0x7b, 0xae, 0xc9, 0xd3, 0xe8, 0xb9, 0x4e, 0xd0, 0x80, 0xff, 0x63, 0xd2, 0xd9, - 0xce, 0x09, 0x5f, 0x08, 0x26, 0xdf, 0x7f, 0x4c, 0x98, 0x26, 0x8f, 0x1b, 0xa6, 0xa9, 0xf1, 0xc3, - 0x34, 0x1d, 0x17, 0xa6, 0xb7, 0x61, 0x7a, 0xd0, 0xef, 0x18, 0xaa, 0xd6, 0x32, 0xb1, 0x35, 0xe8, - 0xd8, 0xfc, 0xec, 0x49, 0x0e, 0xbb, 0x10, 0x51, 0xea, 0x83, 0x3e, 0x3f, 0x82, 0x19, 0x74, 0x6c, - 0xa5, 0x34, 0xf0, 0xdc, 0xc9, 0xdf, 0x71, 0xbb, 0xed, 0x21, 0xd6, 0xe1, 0x61, 0xfa, 0x22, 0xe4, - 0xe8, 0x29, 0xb1, 0x73, 0x54, 0x18, 0x8c, 0xd4, 0x2c, 0x19, 0x6e, 0x6a, 0xe8, 0x1a, 0xa4, 0x0f, - 0x55, 0xeb, 0x90, 0x7f, 0xd8, 0x54, 0x15, 0xc7, 0x63, 0xf4, 0x71, 0x0d, 0xd5, 0x3a, 0x54, 0xe8, - 0xb0, 0xfc, 0xef, 0x24, 0x94, 0x48, 0xc2, 0x13, 0x26, 0x40, 0x6b, 0xc1, 0x80, 0x2a, 0xae, 0x9d, - 0xf3, 0xec, 0xcf, 0xcd, 0x8d, 0x9e, 0xa8, 0x0a, 0x80, 0x40, 0x32, 0x1e, 0x04, 0x52, 0x1e, 0x10, - 0x08, 0x1f, 0x7e, 0x66, 0xc6, 0x38, 0xfc, 0x7c, 0x1b, 0xce, 0x39, 0x27, 0x80, 0x9e, 0x78, 0x24, - 0xa5, 0xfd, 0x18, 0xc1, 0x31, 0x2b, 0xe6, 0xba, 0x34, 0x2b, 0x9c, 0x4e, 0x73, 0xc7, 0x4e, 0xa7, - 0x31, 0xf9, 0x2f, 0x1f, 0x9b, 0xff, 0xea, 0xce, 0x11, 0x97, 0xff, 0x1d, 0x14, 0xfd, 0x2f, 0x54, - 0xad, 0x41, 0xbb, 0x8d, 0x2d, 0x6b, 0x7f, 0xd0, 0x69, 0x71, 0xa4, 0x67, 0xde, 0x50, 0x71, 0x07, - 0x76, 0x18, 0xc4, 0xff, 0x36, 0xe9, 0xf8, 0xd3, 0x96, 0xfa, 0x04, 0xb3, 0x2c, 0xf1, 0x5f, 0x8e, - 0xa9, 0xcf, 0x22, 0x0f, 0xc7, 0xe6, 0xd5, 0x4c, 0x6c, 0x5e, 0x65, 0x6d, 0xff, 0x90, 0x2a, 0x79, - 0x7d, 0xf8, 0x33, 0xf7, 0xe0, 0xf7, 0x34, 0xca, 0xf5, 0x67, 0xa2, 0x69, 0xf9, 0x53, 0xf7, 0x60, - 0x38, 0xaa, 0x7a, 0xff, 0x7c, 0xe6, 0xa6, 0x5f, 0xba, 0x9b, 0x3a, 0x95, 0xd7, 0x88, 0xc9, 0xb5, - 0x70, 0x13, 0x72, 0x2c, 0x0d, 0x88, 0xcd, 0xc7, 0xe4, 0x01, 0x47, 0xdd, 0x24, 0x0f, 0x88, 0x29, - 0xa1, 0x14, 0xe0, 0xe5, 0x7a, 0xb6, 0x29, 0x60, 0x09, 0x16, 0x23, 0x15, 0xc9, 0x5d, 0xfe, 0x93, - 0x04, 0x20, 0x3e, 0x7e, 0xa2, 0x7e, 0xd1, 0x84, 0xbe, 0xbe, 0x01, 0x65, 0xd6, 0x11, 0x6a, 0x8d, - 0xef, 0xf2, 0x33, 0x6c, 0x86, 0x53, 0x9c, 0x3a, 0x6d, 0xa1, 0x94, 0xa7, 0x2d, 0x24, 0x3f, 0x76, - 0x4a, 0x4f, 0x5f, 0x33, 0xe7, 0xba, 0xbf, 0x99, 0x13, 0x7e, 0xcc, 0x38, 0xdd, 0x1c, 0xb7, 0x42, - 0x76, 0xba, 0x39, 0xde, 0xa0, 0x4d, 0x8c, 0x1f, 0xb4, 0xbf, 0x48, 0x38, 0x1f, 0x1b, 0x04, 0x3e, - 0x31, 0xf9, 0x3c, 0xa8, 0x5e, 0xfe, 0x79, 0xca, 0xfd, 0xc4, 0x21, 0xf0, 0x31, 0xca, 0xe7, 0x13, - 0x70, 0xe2, 0x73, 0x49, 0x3a, 0xfe, 0x1d, 0xed, 0x32, 0x94, 0x22, 0xbe, 0x5c, 0x2b, 0x5a, 0x9e, - 0x03, 0xb9, 0x98, 0x34, 0x98, 0x3d, 0x6e, 0x1a, 0xcc, 0x45, 0xa4, 0xc1, 0x97, 0x21, 0xdd, 0xc3, - 0x47, 0xe2, 0x64, 0x73, 0x88, 0x15, 0x29, 0x9b, 0xfc, 0x3e, 0x94, 0x36, 0x54, 0xbb, 0x7d, 0x78, - 0x6c, 0x7f, 0xfb, 0x02, 0xe4, 0x4d, 0x36, 0x20, 0xa2, 0x49, 0xf2, 0x7c, 0xff, 0xe9, 0x11, 0x4d, - 0xc3, 0xc9, 0xe1, 0x95, 0xff, 0x0a, 0x50, 0x09, 0x0e, 0xa3, 0x3a, 0x4c, 0xf3, 0x63, 0x7c, 0xd6, - 0x6a, 0xe4, 0x41, 0xb4, 0x14, 0xfc, 0xa2, 0xd4, 0xf7, 0x15, 0x78, 0x63, 0x4a, 0x29, 0xed, 0x79, - 0xc8, 0xe8, 0x06, 0xf0, 0x93, 0xff, 0xd6, 0x01, 0x76, 0x3f, 0x39, 0x0f, 0x88, 0x70, 0xbb, 0xfd, - 0x8d, 0x29, 0xa5, 0xb0, 0x27, 0x68, 0x9e, 0x25, 0x68, 0x14, 0x1b, 0x39, 0xa2, 0x86, 0x96, 0xe0, - 0x4b, 0x41, 0xee, 0x12, 0x18, 0x19, 0x7d, 0xc9, 0xf9, 0x1e, 0xa1, 0xa3, 0x5b, 0xb6, 0xd3, 0xf3, - 0x89, 0xf8, 0x30, 0xd6, 0x95, 0xc0, 0x17, 0x4d, 0x88, 0xe8, 0x6b, 0x30, 0xcf, 0xe7, 0x5b, 0xd8, - 0x6e, 0xa9, 0xee, 0x77, 0x09, 0xbc, 0xfd, 0x73, 0x2d, 0x28, 0x2a, 0xf2, 0x53, 0x8a, 0xc6, 0x94, - 0x32, 0xb7, 0x17, 0x31, 0x8c, 0xd6, 0xa1, 0xc4, 0xbb, 0xe5, 0x7b, 0xa4, 0x48, 0xe0, 0x6d, 0xa0, - 0x0b, 0xc1, 0xd6, 0xb1, 0xf7, 0x75, 0xbd, 0x31, 0xa5, 0x14, 0x0d, 0x97, 0x4a, 0xf4, 0xc4, 0x45, - 0xb4, 0x69, 0x31, 0xcb, 0x0b, 0xe9, 0xa5, 0xa0, 0x0c, 0xdf, 0xcb, 0x24, 0xd1, 0x93, 0xe1, 0x21, - 0x13, 0x53, 0x71, 0x29, 0xc4, 0x54, 0xf9, 0xa0, 0xa9, 0x82, 0x07, 0x33, 0xc4, 0x54, 0x86, 0xa0, - 0x11, 0x25, 0xf3, 0xc9, 0x54, 0xc9, 0x85, 0xa0, 0x92, 0x43, 0x07, 0x1f, 0x44, 0xc9, 0x86, 0x43, - 0x44, 0xf7, 0x61, 0xd6, 0xab, 0x05, 0x61, 0x70, 0xa0, 0x72, 0xe4, 0x48, 0x65, 0x04, 0xad, 0x5e, - 0x35, 0x82, 0x63, 0xe8, 0x21, 0xcc, 0x71, 0xa9, 0xfb, 0x34, 0xc5, 0x0a, 0xb1, 0x45, 0x2a, 0xf6, - 0x4a, 0x50, 0x6c, 0x44, 0x41, 0xd3, 0x98, 0x52, 0x90, 0x11, 0x1a, 0x24, 0x1a, 0x17, 0x00, 0xc3, - 0xac, 0x56, 0x0a, 0x6a, 0x3c, 0xa2, 0xcb, 0x42, 0x34, 0x6e, 0x79, 0xc8, 0xe8, 0x36, 0xcc, 0x08, - 0x29, 0xdc, 0x70, 0xec, 0x0c, 0xff, 0x62, 0x48, 0x4c, 0xd0, 0x72, 0xe2, 0xe9, 0xdc, 0x74, 0xf7, - 0x61, 0x56, 0x08, 0xea, 0xaa, 0x4f, 0x30, 0x87, 0x49, 0x7a, 0x8a, 0x1f, 0x55, 0x1e, 0x85, 0xde, - 0x55, 0x88, 0xf6, 0xac, 0xe0, 0x18, 0xd1, 0x9e, 0x6f, 0x93, 0x42, 0x7b, 0xe5, 0xa0, 0xf6, 0x62, - 0x2b, 0x73, 0xa2, 0x3d, 0x2b, 0x34, 0x88, 0x1e, 0xc3, 0x39, 0x21, 0xd8, 0x6f, 0x97, 0x0a, 0x95, - 0x7c, 0x35, 0x24, 0x39, 0xda, 0x30, 0x62, 0xcf, 0x3e, 0xcb, 0xac, 0xbb, 0xd0, 0x4f, 0x3d, 0xb1, - 0x1a, 0x0c, 0xa7, 0x70, 0x4d, 0x45, 0xc2, 0xc9, 0x72, 0xa9, 0x68, 0x0b, 0x2a, 0x42, 0x84, 0xc6, - 0x73, 0x68, 0x0d, 0x05, 0x0f, 0xb0, 0xa2, 0x6b, 0x84, 0xc6, 0x94, 0x52, 0xb6, 0xfc, 0x23, 0x1b, - 0x05, 0xc8, 0xf1, 0x51, 0xf9, 0x2d, 0x98, 0xe6, 0x38, 0xcb, 0x53, 0xf2, 0x17, 0xa1, 0x60, 0xf2, - 0x6b, 0x01, 0xd9, 0x8b, 0x21, 0xc8, 0x66, 0xe3, 0x14, 0xb3, 0x5d, 0x6e, 0xf9, 0x9f, 0x00, 0xd5, - 0x10, 0x03, 0xda, 0x8c, 0x46, 0xed, 0x8b, 0x71, 0xa8, 0xcd, 0xa6, 0x86, 0x60, 0xfb, 0x66, 0x04, - 0x6c, 0x2f, 0x46, 0xc2, 0xb6, 0x23, 0xc0, 0x83, 0xdb, 0x9b, 0xd1, 0xb8, 0x7d, 0x31, 0x0e, 0xb7, - 0x83, 0x8b, 0xe0, 0xa6, 0x7c, 0x23, 0x0a, 0xb8, 0x2f, 0x44, 0x03, 0xb7, 0x23, 0xc2, 0x8b, 0xdc, - 0x5f, 0x1f, 0x81, 0xdc, 0x2f, 0x8c, 0x42, 0x6e, 0x47, 0x6a, 0x34, 0x74, 0x6f, 0x44, 0x42, 0xf7, - 0x52, 0x0c, 0x74, 0x3b, 0xc2, 0x7c, 0xd8, 0xbd, 0x19, 0x8d, 0xdd, 0x17, 0xe3, 0xb0, 0xdb, 0xd5, - 0x95, 0x0f, 0xbc, 0x6f, 0x46, 0x80, 0xf7, 0x62, 0x24, 0x78, 0xbb, 0x06, 0x73, 0xd1, 0xfb, 0x8d, - 0x28, 0xf4, 0xbe, 0x10, 0x8d, 0xde, 0xae, 0xa6, 0x3d, 0xf0, 0xfd, 0x60, 0x18, 0x7c, 0x5f, 0x19, - 0x0a, 0xdf, 0x8e, 0xbc, 0x08, 0xfc, 0x7e, 0x34, 0x14, 0xbf, 0xaf, 0x0e, 0xc7, 0x6f, 0x47, 0x70, - 0x14, 0x80, 0x6f, 0x46, 0x03, 0xf8, 0xc5, 0x38, 0x00, 0x77, 0xd5, 0xee, 0x43, 0xf0, 0x46, 0x0c, - 0x82, 0x2f, 0xc7, 0x22, 0xb8, 0x23, 0x28, 0x00, 0xe1, 0x0f, 0x86, 0x41, 0xf8, 0x95, 0xa1, 0x10, - 0xee, 0x6a, 0x30, 0x8c, 0xe1, 0x8f, 0x86, 0x62, 0xf8, 0xd5, 0xe1, 0x18, 0xee, 0x6a, 0x30, 0x02, - 0xc4, 0xbf, 0x3a, 0x1c, 0xc4, 0xaf, 0x8d, 0x00, 0x71, 0x47, 0x76, 0x24, 0x8a, 0x6f, 0x44, 0xa2, - 0xf8, 0x52, 0x0c, 0x8a, 0xbb, 0x91, 0xe5, 0x85, 0xf1, 0xed, 0x58, 0x18, 0xbf, 0x3c, 0x04, 0xc6, - 0x1d, 0x59, 0x21, 0x1c, 0x07, 0xc8, 0x8b, 0xe1, 0xb5, 0x7f, 0x54, 0x21, 0xbf, 0xc5, 0x65, 0xa0, - 0x2d, 0x28, 0x31, 0xd8, 0xe4, 0xff, 0xcb, 0x0e, 0x2f, 0x91, 0xa5, 0x11, 0x58, 0x8c, 0xea, 0x50, - 0xb8, 0x8d, 0x6d, 0x2e, 0x6b, 0x48, 0xad, 0x2c, 0x0d, 0x03, 0x64, 0xb2, 0x28, 0xa6, 0xcb, 0xb8, - 0x45, 0xf9, 0xb2, 0xa9, 0x34, 0x02, 0x9b, 0x51, 0x03, 0x8a, 0x44, 0xa9, 0x6c, 0xcc, 0x42, 0xc3, - 0xca, 0x67, 0x69, 0x28, 0x44, 0x23, 0x0c, 0x73, 0xbb, 0x62, 0x7b, 0x5e, 0x30, 0x1d, 0xaf, 0x8c, - 0x96, 0xc6, 0xc4, 0x6c, 0xf4, 0x16, 0x14, 0xa9, 0xb7, 0xf2, 0x6f, 0x75, 0x87, 0xd6, 0xd3, 0xd2, - 0x70, 0xc8, 0xa6, 0x06, 0xa6, 0x51, 0xca, 0x85, 0x0d, 0x2f, 0xac, 0xa5, 0x11, 0xd8, 0xcd, 0x0d, - 0xcc, 0x65, 0x0d, 0xa9, 0xb0, 0xa5, 0x61, 0x00, 0x2e, 0x2c, 0xc2, 0x06, 0x7c, 0x16, 0x09, 0xd5, - 0xda, 0xd2, 0x50, 0x28, 0x47, 0xef, 0x42, 0xd5, 0x13, 0xd8, 0x7c, 0x5d, 0x63, 0xd4, 0xdc, 0xd2, - 0x38, 0xc0, 0x8e, 0x5a, 0x80, 0xbc, 0xa1, 0xcd, 0xc5, 0x8f, 0x53, 0x7b, 0x4b, 0x63, 0x01, 0x3c, - 0xb1, 0x0e, 0x7d, 0xae, 0x38, 0xce, 0x1e, 0x5e, 0x84, 0x4b, 0x23, 0x20, 0x1e, 0xed, 0xc0, 0x34, - 0xb3, 0x97, 0x90, 0x37, 0xa2, 0x1a, 0x97, 0x46, 0x61, 0x3d, 0xd1, 0xaf, 0x8b, 0xc8, 0x42, 0xea, - 0x18, 0x55, 0xb9, 0x34, 0x0e, 0xec, 0x13, 0xfd, 0x7a, 0xd4, 0x2e, 0xc4, 0x8f, 0x53, 0x9d, 0x4b, - 0x63, 0xc1, 0x3f, 0xda, 0x83, 0x59, 0xaf, 0xde, 0xc5, 0x13, 0xc6, 0xaa, 0xd2, 0xa5, 0xf1, 0xd2, - 0x00, 0xba, 0x03, 0x25, 0xef, 0x3f, 0x12, 0x68, 0x68, 0xbd, 0x2e, 0x0d, 0xcf, 0x03, 0xe8, 0x1d, - 0x28, 0x0b, 0xd0, 0x16, 0x8b, 0x1d, 0x59, 0xb8, 0x4b, 0xa3, 0x73, 0x02, 0x7a, 0x0d, 0x32, 0xb4, - 0xe0, 0x46, 0xf3, 0xd1, 0x5d, 0x15, 0x69, 0x21, 0xa6, 0x74, 0x47, 0x0f, 0xa1, 0xc2, 0x40, 0x9e, - 0x8b, 0xbe, 0xd7, 0xd1, 0x22, 0x96, 0x14, 0xf8, 0x83, 0x34, 0x62, 0x49, 0xa1, 0x3f, 0x22, 0xbf, - 0x02, 0x15, 0x9f, 0xb3, 0x12, 0xda, 0xe5, 0xe1, 0xfe, 0x4a, 0x24, 0xcb, 0x23, 0x5c, 0x96, 0x88, - 0xd9, 0x85, 0x19, 0xcf, 0x4f, 0x57, 0x84, 0x12, 0x76, 0x74, 0xff, 0xef, 0x61, 0xd2, 0xa5, 0x18, - 0x06, 0x57, 0x68, 0x0b, 0x50, 0xc0, 0x34, 0x84, 0x7a, 0x65, 0x94, 0x75, 0x88, 0xf0, 0xab, 0x23, - 0x0d, 0xc4, 0x15, 0xe2, 0x73, 0xd3, 0x68, 0x85, 0x04, 0xff, 0xfe, 0x8a, 0x50, 0x48, 0xf8, 0x6f, - 0xac, 0x77, 0xa0, 0xec, 0xf5, 0xd1, 0x80, 0x0d, 0xa3, 0xff, 0x91, 0xf2, 0xda, 0x30, 0xee, 0xb7, - 0xa1, 0x77, 0xa1, 0xea, 0xcf, 0x61, 0x84, 0xe8, 0x5b, 0x50, 0xf4, 0x9f, 0x39, 0x7e, 0x78, 0x88, - 0xf9, 0x61, 0x86, 0xe4, 0x41, 0xcf, 0x9f, 0x2e, 0xde, 0xc0, 0x0a, 0xff, 0x47, 0xe3, 0x0d, 0xac, - 0x88, 0xdf, 0x63, 0x36, 0xd2, 0x8f, 0x93, 0xfd, 0xbd, 0xbd, 0x2c, 0x3d, 0x97, 0x7d, 0xf5, 0x3f, - 0x01, 0x00, 0x00, 0xff, 0xff, 0x48, 0x9e, 0xe0, 0x05, 0xd0, 0x44, 0x00, 0x00, + // 3712 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0x5d, 0x6c, 0x1c, 0x57, + 0xf5, 0xf7, 0xec, 0xf7, 0x9e, 0x5d, 0x7b, 0xd7, 0xd7, 0x8e, 0xbd, 0x19, 0xc7, 0x71, 0x32, 0x49, + 0x5a, 0xff, 0xf5, 0x6f, 0x9d, 0xca, 0x05, 0x54, 0x94, 0x94, 0x62, 0x67, 0xdd, 0x78, 0x9b, 0xd8, + 0x71, 0xc7, 0x49, 0x13, 0x42, 0x61, 0x35, 0xde, 0xb9, 0xb6, 0x87, 0xec, 0xee, 0x2c, 0x33, 0xb3, + 0xad, 0x53, 0x9e, 0x90, 0x2a, 0x21, 0x84, 0x84, 0x2a, 0x9e, 0x11, 0x4f, 0x7d, 0xe3, 0x09, 0xde, + 0x90, 0x80, 0x57, 0x40, 0x42, 0x45, 0xaa, 0x10, 0x0f, 0x3c, 0x14, 0x9e, 0x78, 0x83, 0x17, 0xde, + 0x40, 0x48, 0xe8, 0x7e, 0xcd, 0xf7, 0xec, 0x87, 0x3f, 0x12, 0xfa, 0x36, 0x73, 0xee, 0xb9, 0x67, + 0xee, 0x3d, 0x1f, 0xbf, 0x73, 0xe6, 0xdc, 0x19, 0x98, 0xea, 0x60, 0x47, 0x33, 0xba, 0xfb, 0xe6, + 0x4a, 0xcf, 0x32, 0x1d, 0x13, 0x15, 0xc4, 0xbd, 0x5c, 0xc5, 0xdd, 0x96, 0xf5, 0xb4, 0xe7, 0x18, + 0x66, 0x97, 0x8d, 0xc9, 0x70, 0x60, 0x1e, 0x70, 0x3e, 0x79, 0xe9, 0xc0, 0x34, 0x0f, 0xda, 0xf8, + 0x3a, 0xbd, 0xdb, 0xeb, 0xef, 0x5f, 0x77, 0x8c, 0x0e, 0xb6, 0x1d, 0xad, 0xd3, 0x13, 0xcc, 0x5d, + 0x53, 0xc7, 0xfc, 0xba, 0xd2, 0x33, 0x8d, 0xae, 0x83, 0x2d, 0x7d, 0x8f, 0x13, 0xca, 0xa6, 0xa5, + 0x63, 0xcb, 0x66, 0x77, 0xca, 0x32, 0x4c, 0xaa, 0xf8, 0xdb, 0x7d, 0x6c, 0x3b, 0x9b, 0x58, 0xd3, + 0xb1, 0x85, 0xe6, 0x21, 0xaf, 0xf5, 0x8c, 0xe6, 0x13, 0xfc, 0xb4, 0x26, 0x5d, 0x92, 0x96, 0xcb, + 0x6a, 0x4e, 0xeb, 0x19, 0x77, 0xf0, 0x53, 0xe5, 0xa7, 0x69, 0xc8, 0xad, 0xf7, 0x5b, 0x4f, 0xb0, + 0x83, 0x10, 0x64, 0xba, 0x5a, 0x07, 0x73, 0x06, 0x7a, 0x8d, 0x5e, 0x83, 0x52, 0x4f, 0x73, 0x0e, + 0x9b, 0x2d, 0xa3, 0x77, 0x88, 0xad, 0x5a, 0xea, 0x92, 0xb4, 0x3c, 0xb5, 0x3a, 0xbf, 0xe2, 0xdb, + 0xc8, 0x2d, 0x3a, 0xb2, 0xdb, 0x37, 0x1c, 0xac, 0x02, 0xe1, 0x65, 0x04, 0x74, 0x0b, 0xa0, 0x65, + 0x61, 0xcd, 0xc1, 0x7a, 0x53, 0x73, 0x6a, 0xe9, 0x4b, 0xd2, 0x72, 0x69, 0x55, 0x5e, 0x61, 0x7b, + 0x5c, 0x11, 0x7b, 0x5c, 0xb9, 0x2f, 0xf6, 0xb8, 0x5e, 0xf8, 0xed, 0x67, 0x4b, 0x13, 0x1f, 0xfd, + 0x65, 0x49, 0x52, 0x8b, 0x7c, 0xde, 0x9a, 0x83, 0x5e, 0x81, 0x59, 0x1d, 0xef, 0x6b, 0xfd, 0xb6, + 0xd3, 0xb4, 0xf1, 0x41, 0x07, 0x77, 0x9d, 0xa6, 0x6d, 0x7c, 0x80, 0x6b, 0x99, 0x4b, 0xd2, 0x72, + 0x5a, 0x45, 0x7c, 0x6c, 0x97, 0x0d, 0xed, 0x1a, 0x1f, 0x60, 0xf4, 0x10, 0xce, 0x8b, 0x19, 0x16, + 0xd6, 0xfb, 0x5d, 0x5d, 0xeb, 0xb6, 0x9e, 0x36, 0xed, 0xd6, 0x21, 0xee, 0xe0, 0x5a, 0x96, 0xae, + 0x62, 0x61, 0xc5, 0x53, 0x9e, 0xea, 0xf2, 0xec, 0x52, 0x16, 0x75, 0x9e, 0xcf, 0x0e, 0x0f, 0x20, + 0x1d, 0x16, 0x85, 0x60, 0x6f, 0xf7, 0xcd, 0x9e, 0x66, 0x69, 0x1d, 0xec, 0x60, 0xcb, 0xae, 0xe5, + 0xa8, 0xf0, 0x4b, 0x7e, 0xdd, 0x6c, 0xb8, 0x97, 0x3b, 0x2e, 0x9f, 0xba, 0xc0, 0xc5, 0xc4, 0x0d, + 0xa2, 0x45, 0x80, 0x9e, 0x66, 0x39, 0x5d, 0x6c, 0x35, 0x0d, 0xbd, 0x96, 0xa7, 0x96, 0x28, 0x72, + 0x4a, 0x43, 0x57, 0x0c, 0x98, 0x62, 0xc6, 0xba, 0x6b, 0xd8, 0x4e, 0xc3, 0xc1, 0x9d, 0x58, 0xa3, + 0x05, 0x55, 0x9f, 0x3a, 0x96, 0xea, 0x95, 0x8f, 0xd3, 0x30, 0xc3, 0x9e, 0x75, 0x8b, 0xd2, 0xb8, + 0x3f, 0xa1, 0xeb, 0x90, 0x3b, 0xa4, 0x3e, 0x55, 0xab, 0x50, 0xc1, 0xf3, 0x2b, 0xae, 0xbf, 0x07, + 0x5c, 0x4e, 0xe5, 0x6c, 0xa7, 0xec, 0x56, 0x49, 0x1e, 0x91, 0x3e, 0x9e, 0x47, 0x64, 0xce, 0xd2, + 0x23, 0xb2, 0xa7, 0xef, 0x11, 0xb9, 0xb0, 0x47, 0x7c, 0x15, 0x66, 0x83, 0x56, 0xb2, 0x7b, 0x66, + 0xd7, 0xc6, 0x68, 0x19, 0x72, 0x7b, 0x94, 0x4e, 0xf5, 0x5e, 0x5a, 0xad, 0x7a, 0x66, 0x62, 0xfc, + 0x2a, 0x1f, 0x57, 0x1e, 0x42, 0x95, 0x51, 0x6e, 0x63, 0xe7, 0x34, 0x8d, 0xac, 0xbc, 0x0e, 0xd3, + 0x3e, 0xc1, 0x63, 0xaf, 0xeb, 0xb1, 0xf0, 0xbf, 0x3a, 0x6e, 0xe3, 0xd3, 0xf5, 0x3f, 0x65, 0x4e, + 0x68, 0x4d, 0xc8, 0x66, 0xab, 0x53, 0x3e, 0x92, 0xc4, 0x9a, 0x49, 0x80, 0x1d, 0xfb, 0x91, 0x73, + 0x90, 0x6b, 0xf5, 0x2d, 0xdb, 0xb4, 0x04, 0xd8, 0xb2, 0x3b, 0x34, 0x0b, 0xd9, 0xb6, 0xd1, 0x31, + 0x58, 0x4c, 0x66, 0x55, 0x76, 0x83, 0x2e, 0x40, 0x51, 0x37, 0x2c, 0xdc, 0x22, 0x86, 0xa7, 0x7e, + 0x9c, 0x55, 0x3d, 0x82, 0xf2, 0x08, 0x90, 0x7f, 0x45, 0x5c, 0x8d, 0x2b, 0x90, 0x35, 0x1c, 0xdc, + 0xb1, 0x6b, 0xd2, 0xa5, 0xf4, 0x72, 0x69, 0xb5, 0x16, 0xd6, 0xa2, 0xc0, 0x07, 0x95, 0xb1, 0x11, + 0x25, 0x74, 0x4c, 0x0b, 0xd3, 0x07, 0x17, 0x54, 0x7a, 0xad, 0x7c, 0x57, 0x82, 0x05, 0xc6, 0xbd, + 0x8b, 0x9d, 0x35, 0xc7, 0xb1, 0x8c, 0xbd, 0x3e, 0x79, 0xe4, 0xa9, 0x46, 0x7a, 0xd0, 0x7d, 0x53, + 0x61, 0xf7, 0xbd, 0x08, 0x17, 0xe2, 0x97, 0xc0, 0x0d, 0xf2, 0xa1, 0x04, 0x33, 0x6b, 0xba, 0x6e, + 0x61, 0xdb, 0xc6, 0xfa, 0x3d, 0x92, 0xe2, 0xee, 0x52, 0x9d, 0x2d, 0x0b, 0x4d, 0x32, 0x2f, 0x42, + 0x2b, 0x3c, 0xfd, 0x79, 0x2c, 0x42, 0xbb, 0xb7, 0x60, 0xd6, 0x76, 0x4c, 0x4b, 0x3b, 0xc0, 0x4d, + 0x92, 0x3f, 0x9b, 0x1a, 0x93, 0xc6, 0x61, 0x71, 0x7a, 0x85, 0x26, 0xd5, 0x6d, 0x53, 0xc7, 0xfc, + 0x31, 0x2a, 0xe2, 0xec, 0x3e, 0x9a, 0xf2, 0x87, 0x14, 0xcc, 0x71, 0x4c, 0x79, 0x68, 0x19, 0xae, + 0x33, 0xde, 0x6b, 0xeb, 0xc7, 0x72, 0x0e, 0x5f, 0x04, 0x94, 0x85, 0xbf, 0x13, 0xed, 0x11, 0x9c, + 0xe3, 0x3a, 0xa2, 0xd7, 0xa8, 0x06, 0x79, 0x8e, 0x72, 0x1c, 0xe0, 0xc4, 0x2d, 0xba, 0x01, 0xe0, + 0xa1, 0xd9, 0x28, 0x30, 0xe6, 0x63, 0x47, 0x37, 0x40, 0xee, 0x68, 0x47, 0x02, 0xb5, 0xb0, 0x1e, + 0x84, 0xd2, 0x2c, 0x7d, 0xd2, 0x7c, 0x47, 0x3b, 0xda, 0x10, 0x0c, 0x7e, 0x3c, 0xad, 0x03, 0xe0, + 0xa3, 0x9e, 0x61, 0x69, 0xd4, 0x5f, 0x73, 0x63, 0x64, 0x17, 0xdf, 0x3c, 0xe5, 0x53, 0x09, 0xe6, + 0x83, 0x1a, 0x65, 0x16, 0x27, 0x2a, 0xdd, 0x84, 0xaa, 0x26, 0x6c, 0xde, 0xa4, 0x56, 0x14, 0x7e, + 0xbe, 0xe8, 0x29, 0x37, 0xc6, 0x2b, 0xd4, 0x8a, 0x3b, 0x8d, 0xde, 0xdb, 0xe8, 0x55, 0x98, 0xb4, + 0x4c, 0xd3, 0x69, 0xf6, 0x0c, 0xdc, 0xc2, 0xae, 0x03, 0xae, 0x57, 0xc8, 0x92, 0xfe, 0xfc, 0xd9, + 0x52, 0x7e, 0x87, 0xd0, 0x1b, 0x75, 0xb5, 0x44, 0xb8, 0xd8, 0x8d, 0x4e, 0x93, 0x93, 0x65, 0xbc, + 0xa7, 0x39, 0x98, 0xd6, 0x4b, 0x69, 0x3a, 0x65, 0x9e, 0x4f, 0xa9, 0x50, 0xae, 0x1d, 0x36, 0x7e, + 0x07, 0x3f, 0x55, 0xa1, 0xe7, 0x5e, 0x2b, 0xff, 0xf6, 0x36, 0x75, 0xcb, 0xec, 0x90, 0x15, 0x3d, + 0x77, 0x3f, 0x79, 0x09, 0xf2, 0xdc, 0x29, 0xb8, 0x93, 0x20, 0x9f, 0x93, 0xec, 0xb0, 0x2b, 0x55, + 0xb0, 0xa0, 0x1b, 0x50, 0x31, 0x2d, 0xe3, 0xc0, 0xe8, 0x6a, 0x6d, 0xa1, 0xf8, 0x2c, 0x55, 0x7c, + 0x5c, 0x80, 0x4d, 0x09, 0x56, 0xa6, 0x6c, 0x65, 0x13, 0x6a, 0xa1, 0xcd, 0x7b, 0x26, 0xf5, 0x2d, + 0x43, 0x1a, 0xba, 0x0c, 0xe5, 0x47, 0x12, 0x9c, 0xe7, 0xa2, 0xea, 0xe6, 0xfb, 0xdd, 0xb6, 0xa9, + 0xe9, 0xcf, 0x5d, 0x93, 0xca, 0x27, 0x12, 0xc8, 0x91, 0x45, 0x9d, 0x85, 0xd3, 0xfa, 0x74, 0x95, + 0x1a, 0x6e, 0xb2, 0xe3, 0x7b, 0xeb, 0x0f, 0x25, 0x38, 0xc7, 0x37, 0xd4, 0xe8, 0xee, 0x9b, 0xcf, + 0x5f, 0xc3, 0x6f, 0xba, 0x20, 0xcb, 0xd6, 0x13, 0xeb, 0x3e, 0xc3, 0x55, 0x42, 0xb2, 0xb8, 0x08, + 0xc3, 0x40, 0xed, 0xf0, 0x1c, 0xb7, 0xf6, 0x13, 0xc9, 0x0d, 0x8e, 0x60, 0xc9, 0x71, 0xba, 0xae, + 0x13, 0x72, 0x86, 0xd4, 0xe8, 0xce, 0xf0, 0x51, 0x0a, 0xe6, 0x48, 0xd1, 0xc0, 0x17, 0x69, 0x9f, + 0x85, 0xca, 0xe6, 0x20, 0xd7, 0xb3, 0xf0, 0xbe, 0x71, 0xc4, 0x95, 0xc6, 0xef, 0xd0, 0x12, 0x94, + 0x6c, 0x47, 0xb3, 0x9c, 0xa6, 0xb6, 0x4f, 0x2c, 0x4c, 0x5d, 0x58, 0x05, 0x4a, 0x5a, 0x23, 0x14, + 0x74, 0x19, 0x00, 0x77, 0xf5, 0xe6, 0x1e, 0xde, 0x27, 0x35, 0x4c, 0x86, 0xee, 0x2a, 0x55, 0x93, + 0xd4, 0x22, 0xee, 0xea, 0xeb, 0x94, 0x48, 0x8a, 0x28, 0x0b, 0x93, 0x32, 0xcb, 0x78, 0x8f, 0x65, + 0xb0, 0x82, 0xea, 0x11, 0xbc, 0xc2, 0x2b, 0xe7, 0x2f, 0xbc, 0x16, 0x01, 0xc8, 0x4e, 0x9a, 0xfb, + 0x6d, 0xed, 0xc0, 0xa6, 0x2f, 0x5b, 0x79, 0xb5, 0x48, 0x28, 0x6f, 0x12, 0x02, 0x4d, 0x51, 0x41, + 0x95, 0x78, 0x26, 0xbb, 0x19, 0xac, 0xbf, 0x5e, 0xf0, 0x54, 0x92, 0x30, 0x63, 0x65, 0x48, 0x35, + 0x26, 0x63, 0xc8, 0x88, 0x17, 0x3a, 0xea, 0x57, 0x92, 0xcf, 0xaf, 0xc6, 0x43, 0x84, 0x05, 0x28, + 0x1a, 0x76, 0x93, 0x6b, 0x3a, 0x4d, 0x1f, 0x51, 0x30, 0xec, 0x1d, 0x7a, 0xaf, 0xfc, 0x80, 0x3a, + 0x62, 0x4c, 0xb9, 0x77, 0x2c, 0x4b, 0x2f, 0x41, 0x89, 0xd9, 0xb6, 0xe9, 0x2b, 0xfc, 0x80, 0x91, + 0xb6, 0x47, 0x28, 0xff, 0x16, 0x08, 0xce, 0xc7, 0x15, 0x7e, 0xf7, 0xda, 0xba, 0xb2, 0x01, 0x68, + 0xc7, 0x32, 0xbf, 0x85, 0x5b, 0x7e, 0x78, 0x1a, 0x7b, 0x8d, 0xca, 0x6b, 0x30, 0x13, 0x10, 0xc3, + 0x2b, 0xe8, 0xcb, 0x50, 0xee, 0x31, 0x72, 0xd3, 0xd6, 0xda, 0xc2, 0x55, 0x4b, 0x9c, 0xb6, 0xab, + 0xb5, 0x1d, 0xe5, 0xfb, 0x79, 0xc8, 0xdd, 0xdb, 0x23, 0xb7, 0x89, 0x2e, 0x7d, 0x0d, 0xa6, 0xbc, + 0x2a, 0xca, 0x87, 0x07, 0x93, 0x2e, 0x75, 0x87, 0x03, 0xc3, 0x7b, 0xd8, 0xb2, 0xbd, 0x02, 0x5f, + 0xdc, 0x92, 0xed, 0xd8, 0x8e, 0xe6, 0xf4, 0x6d, 0xea, 0xd6, 0x53, 0xfe, 0xed, 0xb0, 0x47, 0xaf, + 0xec, 0xd2, 0x61, 0x95, 0xb3, 0xa1, 0x97, 0xa1, 0x68, 0x3b, 0x16, 0xd6, 0x3a, 0x44, 0xa1, 0x59, + 0x1a, 0x0a, 0x55, 0x1e, 0xe0, 0x85, 0x5d, 0x3a, 0xd0, 0xa8, 0xab, 0x05, 0xc6, 0xd2, 0xd0, 0x43, + 0xbd, 0x80, 0xdc, 0xf1, 0xda, 0x30, 0x6b, 0xe4, 0x99, 0xe4, 0xe9, 0x44, 0x46, 0x7e, 0x0c, 0x19, + 0x05, 0x36, 0x6d, 0x8d, 0x94, 0xe1, 0xac, 0xfa, 0xc3, 0x54, 0x46, 0x61, 0x9c, 0x75, 0xf0, 0x79, + 0x6b, 0x0e, 0xba, 0x0d, 0x35, 0x4f, 0xdb, 0x44, 0x4f, 0xba, 0xe6, 0x68, 0xcd, 0xae, 0xd9, 0x6d, + 0xe1, 0x5a, 0x91, 0xaa, 0x62, 0x92, 0xab, 0x22, 0xbb, 0x4d, 0x88, 0xea, 0x9c, 0xcb, 0xbe, 0xc5, + 0xb9, 0x29, 0x1d, 0xbd, 0x0c, 0x28, 0x2a, 0xa8, 0x06, 0xd4, 0x74, 0xd3, 0x91, 0x39, 0xe8, 0x25, + 0x40, 0xfb, 0xc6, 0x51, 0xb8, 0x4e, 0x2e, 0x51, 0x88, 0xaf, 0xd2, 0x11, 0x7f, 0x81, 0xbc, 0x09, + 0xd3, 0xd1, 0x46, 0x43, 0x79, 0x78, 0x85, 0x5e, 0xb5, 0xc2, 0x1d, 0x86, 0x07, 0x70, 0x2e, 0xbe, + 0xb3, 0x30, 0x39, 0x62, 0x67, 0x61, 0x16, 0x27, 0xb4, 0x14, 0x1c, 0xd3, 0xd1, 0xda, 0x6c, 0x1b, + 0x53, 0x74, 0x1b, 0x45, 0x4a, 0xa1, 0xeb, 0x5f, 0x82, 0x92, 0xd1, 0x6d, 0x1b, 0x5d, 0xcc, 0xc6, + 0x2b, 0x74, 0x1c, 0x18, 0x49, 0x30, 0x58, 0xb8, 0x63, 0x3a, 0x9c, 0xa1, 0xca, 0x18, 0x18, 0x89, + 0x30, 0x28, 0x6f, 0x43, 0x8e, 0x79, 0x2d, 0x2a, 0x41, 0xbe, 0xb1, 0xfd, 0xce, 0xda, 0xdd, 0x46, + 0xbd, 0x3a, 0x81, 0x26, 0xa1, 0xf8, 0x60, 0xe7, 0xee, 0xbd, 0xb5, 0x7a, 0x63, 0xfb, 0x76, 0x55, + 0x42, 0x53, 0x00, 0xb7, 0xee, 0x6d, 0x6d, 0x35, 0xee, 0xdf, 0x27, 0xf7, 0x29, 0x32, 0xcc, 0xef, + 0x37, 0xea, 0xd5, 0x34, 0x2a, 0x43, 0xa1, 0xbe, 0x71, 0x77, 0x83, 0x0e, 0x66, 0x94, 0x0f, 0xd3, + 0x80, 0x58, 0x40, 0xac, 0xe3, 0x03, 0xa3, 0x7b, 0x92, 0x57, 0xf3, 0xb3, 0x09, 0xe4, 0xa0, 0x83, + 0x67, 0x8e, 0xe7, 0xe0, 0xb1, 0xae, 0x93, 0x3f, 0x55, 0xd7, 0x29, 0x9c, 0xc4, 0x75, 0x94, 0x5f, + 0xa7, 0x60, 0x26, 0x60, 0x06, 0x8e, 0xa6, 0x67, 0xa6, 0xd6, 0x00, 0xdc, 0x65, 0x86, 0xc2, 0x5d, + 0xac, 0x02, 0xb3, 0xa7, 0xaa, 0xc0, 0xdc, 0x89, 0x14, 0xf8, 0x77, 0x49, 0x28, 0x30, 0xf0, 0x86, + 0x38, 0xbe, 0x23, 0x07, 0x14, 0x23, 0x0d, 0x55, 0xcc, 0x20, 0xe8, 0x4c, 0x9d, 0x1c, 0x3a, 0xd3, + 0x09, 0xd0, 0xa9, 0xcc, 0xc1, 0x6c, 0x70, 0xbb, 0xbc, 0xb1, 0xf3, 0x63, 0x09, 0xaa, 0x6c, 0xe0, + 0x24, 0x6d, 0xc7, 0xb3, 0x72, 0x3b, 0xe5, 0x75, 0x98, 0xf6, 0xad, 0xce, 0xeb, 0x5d, 0x9a, 0x94, + 0x18, 0xed, 0x5d, 0x32, 0x66, 0x95, 0x8f, 0x2b, 0x3f, 0x4b, 0x89, 0xf9, 0x27, 0xed, 0x23, 0xc6, + 0x6e, 0xef, 0xff, 0xa0, 0xea, 0xdb, 0x9e, 0xbf, 0xa4, 0xae, 0x78, 0x1b, 0x64, 0xb5, 0x75, 0x80, + 0x95, 0x37, 0x25, 0xd3, 0x21, 0xd6, 0x5b, 0xac, 0x3b, 0x19, 0x28, 0xa1, 0x33, 0x89, 0x25, 0x74, + 0xd6, 0x5f, 0x42, 0x37, 0xa0, 0xc2, 0xb6, 0xdc, 0x34, 0xba, 0xad, 0x76, 0x5f, 0xc7, 0x5e, 0x7c, + 0x84, 0x74, 0x23, 0x3a, 0x92, 0x0d, 0xce, 0xa7, 0x4e, 0xb1, 0x89, 0xe2, 0x5e, 0x79, 0x24, 0x00, + 0x7e, 0xc4, 0x46, 0x67, 0x50, 0xec, 0xa0, 0x46, 0xe7, 0x6f, 0xd2, 0x30, 0x15, 0xe4, 0x8e, 0x71, + 0x10, 0x69, 0x88, 0x83, 0xa4, 0x92, 0xea, 0xb6, 0xf4, 0x68, 0x75, 0x5b, 0xb0, 0x10, 0xcb, 0x9c, + 0x42, 0x21, 0x96, 0x3d, 0x85, 0x42, 0x2c, 0x77, 0xfa, 0x85, 0x58, 0xfe, 0xe4, 0x68, 0x52, 0x48, + 0x42, 0x93, 0x2f, 0xc0, 0x5c, 0xbc, 0x37, 0x21, 0x19, 0x0a, 0xee, 0x74, 0x89, 0xbd, 0xf3, 0x88, + 0x7b, 0xe5, 0x63, 0x09, 0x6a, 0xbe, 0xa4, 0x75, 0xc2, 0xf3, 0x84, 0x33, 0xc3, 0x9c, 0xb7, 0xe0, + 0x7c, 0xcc, 0x2a, 0x79, 0x1c, 0x8c, 0x07, 0xf7, 0xca, 0x77, 0x84, 0xac, 0x37, 0x8d, 0xae, 0x61, + 0x1f, 0x9e, 0x70, 0xcb, 0x63, 0x3e, 0xfc, 0x02, 0xc8, 0x71, 0x0f, 0xe7, 0xc8, 0xff, 0x8f, 0x14, + 0x94, 0x76, 0x35, 0x47, 0xcc, 0x3b, 0xbb, 0xd2, 0xe1, 0x44, 0x2d, 0xf2, 0x06, 0x4c, 0xd2, 0xb0, + 0x23, 0xc9, 0x5f, 0xd7, 0x1c, 0x3c, 0x56, 0xb4, 0x95, 0xc5, 0xd4, 0xba, 0xe6, 0x60, 0xb4, 0x05, + 0x15, 0xaf, 0xf1, 0xcd, 0x84, 0x8d, 0x13, 0x76, 0x53, 0xde, 0x64, 0x2a, 0xee, 0x3a, 0xcc, 0xd8, + 0x9a, 0x83, 0xdb, 0x6d, 0x83, 0x16, 0xe0, 0x07, 0x5d, 0xcd, 0xe9, 0x5b, 0xfc, 0xfd, 0x47, 0x45, + 0xee, 0xd0, 0xae, 0x18, 0x51, 0xfe, 0x9a, 0x82, 0x3c, 0x7f, 0x3f, 0x19, 0xb7, 0x6a, 0xf8, 0x22, + 0x14, 0x7a, 0xa6, 0x6d, 0x38, 0x02, 0x00, 0x4b, 0xab, 0xe7, 0x3d, 0x5f, 0xe1, 0x32, 0x77, 0x38, + 0x83, 0xea, 0xb2, 0xa2, 0xd7, 0x61, 0xc6, 0x33, 0xdd, 0x13, 0xfc, 0x94, 0x23, 0x43, 0x3a, 0x0e, + 0x19, 0xbc, 0x28, 0xbf, 0x83, 0x9f, 0x32, 0x50, 0xb8, 0x02, 0x93, 0x81, 0xe9, 0xac, 0xee, 0x53, + 0xcb, 0x7e, 0x4e, 0xb4, 0x02, 0x33, 0xe4, 0xed, 0xc3, 0x77, 0x88, 0x41, 0x63, 0x9f, 0x1d, 0x5e, + 0x4c, 0x93, 0x21, 0xf7, 0xf4, 0xa2, 0x4e, 0xde, 0xe1, 0x56, 0xdd, 0x7a, 0x0e, 0xeb, 0x4d, 0xfe, + 0x7e, 0x43, 0x67, 0xb0, 0x23, 0x55, 0x6f, 0xc1, 0x0d, 0x3a, 0x46, 0xe7, 0xbc, 0x08, 0x39, 0x7a, + 0x72, 0x60, 0xd7, 0xf2, 0x34, 0xfb, 0x54, 0xbc, 0xcd, 0xd3, 0x5e, 0x9a, 0xca, 0x87, 0x95, 0x4d, + 0xc8, 0x52, 0x02, 0x5a, 0x80, 0x22, 0x3b, 0x6b, 0xe8, 0xf6, 0x3b, 0x54, 0xbf, 0x59, 0xb5, 0x40, + 0x09, 0xdb, 0xfd, 0x0e, 0x52, 0x20, 0xd3, 0x35, 0x75, 0x51, 0x6f, 0x4d, 0x71, 0x3d, 0xe4, 0xb6, + 0x4d, 0x1d, 0x37, 0xea, 0x2a, 0x1d, 0x53, 0x36, 0xa1, 0x12, 0xd2, 0x2b, 0x79, 0xdd, 0xea, 0x69, + 0x96, 0x43, 0x44, 0xee, 0xf1, 0xfe, 0x79, 0x56, 0xa5, 0x6d, 0x95, 0x6d, 0x4a, 0x21, 0xa9, 0xd9, + 0xe8, 0xea, 0xf8, 0x48, 0x1c, 0x2b, 0xd2, 0x1b, 0xe5, 0x8f, 0x12, 0xcc, 0x70, 0x51, 0x27, 0x7b, + 0x65, 0x7a, 0x36, 0x3e, 0xf3, 0x02, 0x54, 0x3a, 0xda, 0x51, 0x93, 0x1e, 0x33, 0xb0, 0x26, 0x28, + 0xef, 0xa1, 0x4e, 0x76, 0xb4, 0x23, 0xaf, 0xe7, 0xa9, 0xfc, 0x5e, 0x82, 0xd9, 0xe0, 0xb6, 0x38, + 0x42, 0xbe, 0x02, 0x20, 0x5e, 0xcf, 0xdd, 0x75, 0x4e, 0xf3, 0x75, 0x16, 0x45, 0x5f, 0xb9, 0xae, + 0x16, 0x39, 0x53, 0x23, 0xbe, 0xef, 0x9a, 0x3a, 0x8d, 0xbe, 0xeb, 0x18, 0x4d, 0xf8, 0x3f, 0xa5, + 0xdc, 0xed, 0x9c, 0xf0, 0x85, 0x60, 0xfc, 0xfd, 0x27, 0x84, 0x69, 0xea, 0xb8, 0x61, 0x9a, 0x1e, + 0x3d, 0x4c, 0x33, 0x49, 0x61, 0x7a, 0x1b, 0x26, 0xfb, 0xbd, 0xb6, 0xa9, 0xe9, 0x4d, 0x0b, 0xdb, + 0xfd, 0xb6, 0xc3, 0xcf, 0x9f, 0x94, 0xa8, 0x0b, 0x11, 0xa5, 0x3e, 0xe8, 0xf1, 0x63, 0x98, 0x7e, + 0xdb, 0x51, 0xcb, 0x7d, 0xdf, 0x9d, 0xf2, 0x3d, 0xaf, 0xe3, 0x1e, 0x61, 0x1d, 0x1c, 0xa6, 0x2f, + 0x42, 0x9e, 0x9e, 0x14, 0xbb, 0xc7, 0x85, 0xe1, 0x48, 0xcd, 0x91, 0xe1, 0x86, 0x8e, 0xae, 0x41, + 0xe6, 0x50, 0xb3, 0x0f, 0xf9, 0xc7, 0x4d, 0xd3, 0xe2, 0x88, 0x8c, 0x3e, 0x6e, 0x53, 0xb3, 0x0f, + 0x55, 0x3a, 0xac, 0xfc, 0x27, 0x05, 0x65, 0x92, 0xf0, 0x84, 0x09, 0xd0, 0x6a, 0x38, 0xa0, 0x4a, + 0xab, 0xe7, 0x7c, 0xfb, 0xf3, 0x72, 0xa3, 0x2f, 0xaa, 0x42, 0x20, 0x90, 0x4a, 0x06, 0x81, 0xb4, + 0x0f, 0x04, 0xa2, 0x07, 0xa0, 0xd9, 0x11, 0x0e, 0x40, 0xdf, 0x86, 0x73, 0xee, 0x29, 0xa0, 0x2f, + 0x1e, 0x49, 0x69, 0x3f, 0x42, 0x70, 0xcc, 0x88, 0xb9, 0x1e, 0xcd, 0x8e, 0xa6, 0xd3, 0xfc, 0xb1, + 0xd3, 0x69, 0x42, 0xfe, 0x2b, 0x24, 0xe6, 0xbf, 0xba, 0x7b, 0xcc, 0x15, 0x7c, 0x07, 0x45, 0xff, + 0x0f, 0xd3, 0x76, 0xbf, 0xd5, 0xc2, 0xb6, 0xbd, 0xdf, 0x6f, 0x37, 0x39, 0xd2, 0x33, 0x6f, 0xa8, + 0x7a, 0x03, 0x3b, 0x0c, 0xe2, 0x7f, 0x97, 0x72, 0xfd, 0x69, 0x4b, 0x7b, 0x82, 0x59, 0x96, 0xf8, + 0x1f, 0xc7, 0xd4, 0x67, 0x91, 0x87, 0x13, 0xf3, 0x6a, 0x36, 0x31, 0xaf, 0xb2, 0xb6, 0x7f, 0x44, + 0x95, 0xbc, 0x3e, 0xfc, 0xb9, 0x77, 0xf8, 0x7b, 0x1a, 0xe5, 0xfa, 0x33, 0xd1, 0xb4, 0xf2, 0xa9, + 0x77, 0x38, 0x1c, 0x57, 0xbd, 0x7f, 0x3e, 0x73, 0xd3, 0xaf, 0xbc, 0x4d, 0x9d, 0xca, 0x6b, 0xc4, + 0xf8, 0x5a, 0xb8, 0x09, 0x79, 0x96, 0x06, 0xc4, 0xe6, 0x13, 0xf2, 0x80, 0xab, 0x6e, 0x92, 0x07, + 0xc4, 0x94, 0x48, 0x0a, 0xf0, 0x73, 0x3d, 0xdb, 0x14, 0xb0, 0x08, 0x0b, 0xb1, 0x8a, 0xe4, 0x2e, + 0xff, 0x89, 0x04, 0x88, 0x8f, 0x9f, 0xa8, 0x5f, 0x34, 0xa6, 0xaf, 0xaf, 0x43, 0x85, 0x75, 0x84, + 0x9a, 0xa3, 0xbb, 0xfc, 0x14, 0x9b, 0xe1, 0x16, 0xa7, 0x6e, 0x5b, 0x28, 0xed, 0x6b, 0x0b, 0x29, + 0x8f, 0xdd, 0xd2, 0x33, 0xd0, 0xcc, 0xb9, 0x1e, 0x6c, 0xe6, 0x44, 0x1f, 0x33, 0x4a, 0x37, 0xc7, + 0xab, 0x90, 0xdd, 0x6e, 0x8e, 0x3f, 0x68, 0xa5, 0xd1, 0x83, 0xf6, 0x97, 0x92, 0xfb, 0xc1, 0x41, + 0xe8, 0x33, 0x93, 0xcf, 0x83, 0xea, 0x95, 0x5f, 0xa4, 0xbd, 0xcf, 0x1c, 0x42, 0x1f, 0xa4, 0x7c, + 0x3e, 0x01, 0x27, 0x39, 0x97, 0x64, 0x92, 0xdf, 0xd1, 0x2e, 0x43, 0x39, 0xe6, 0xeb, 0xb5, 0x92, + 0xed, 0x3b, 0x90, 0x4b, 0x48, 0x83, 0xb9, 0xe3, 0xa6, 0xc1, 0x7c, 0x4c, 0x1a, 0x7c, 0x19, 0x32, + 0x5d, 0x7c, 0x24, 0x4e, 0x36, 0x07, 0x58, 0x91, 0xb2, 0x29, 0xef, 0x43, 0x79, 0x5d, 0x73, 0x5a, + 0x87, 0xc7, 0xf6, 0xb7, 0x2f, 0x41, 0xc1, 0x62, 0x03, 0x22, 0x9a, 0x64, 0xdf, 0x37, 0xa0, 0x3e, + 0xd1, 0x34, 0x9c, 0x5c, 0x5e, 0xe5, 0x6f, 0x00, 0xd5, 0xf0, 0x30, 0xaa, 0xc3, 0x24, 0x3f, 0xc6, + 0x67, 0xad, 0x46, 0x1e, 0x44, 0x8b, 0xe1, 0xaf, 0x4a, 0x03, 0x5f, 0x82, 0x6f, 0x4e, 0xa8, 0xe5, + 0x3d, 0x1f, 0x19, 0xdd, 0x00, 0x7e, 0xf2, 0xdf, 0x3c, 0xc0, 0xde, 0x67, 0xe7, 0x21, 0x11, 0x5e, + 0xb7, 0x7f, 0x73, 0x42, 0x2d, 0xee, 0x09, 0x9a, 0x6f, 0x09, 0x3a, 0xc5, 0x46, 0x8e, 0xa8, 0x91, + 0x25, 0x04, 0x52, 0x90, 0xb7, 0x04, 0x46, 0x46, 0x5f, 0x71, 0xbf, 0x47, 0x68, 0x1b, 0xb6, 0xe3, + 0xf6, 0x7c, 0x62, 0x3e, 0x8e, 0xf5, 0x24, 0xf0, 0x45, 0x13, 0x22, 0xfa, 0x06, 0xcc, 0xf1, 0xf9, + 0x36, 0x76, 0x9a, 0x9a, 0xf7, 0x5d, 0x02, 0x6f, 0xff, 0x5c, 0x0b, 0x8b, 0x8a, 0xfd, 0x94, 0x62, + 0x73, 0x42, 0x9d, 0xdd, 0x8b, 0x19, 0x46, 0x6b, 0x50, 0xe6, 0xdd, 0xf2, 0x3d, 0x52, 0x24, 0xf0, + 0x36, 0xd0, 0x85, 0x70, 0xeb, 0xd8, 0xff, 0xba, 0xbe, 0x39, 0xa1, 0x96, 0x4c, 0x8f, 0x4a, 0xf4, + 0xc4, 0x45, 0xb4, 0x68, 0x31, 0xcb, 0x0b, 0xe9, 0xc5, 0xb0, 0x8c, 0xc0, 0xcb, 0x24, 0xd1, 0x93, + 0xe9, 0x23, 0x13, 0x53, 0x71, 0x29, 0xc4, 0x54, 0x85, 0xb0, 0xa9, 0xc2, 0x07, 0x33, 0xc4, 0x54, + 0xa6, 0xa0, 0x11, 0x25, 0xf3, 0xc9, 0x54, 0xc9, 0xc5, 0xb0, 0x92, 0x23, 0x07, 0x1f, 0x44, 0xc9, + 0xa6, 0x4b, 0x44, 0xf7, 0x61, 0xc6, 0xaf, 0x05, 0x61, 0x70, 0xa0, 0x72, 0x94, 0x58, 0x65, 0x84, + 0xad, 0x3e, 0x6d, 0x86, 0xc7, 0xd0, 0x43, 0x98, 0xe5, 0x52, 0xf7, 0x69, 0x8a, 0x15, 0x62, 0x4b, + 0x54, 0xec, 0x95, 0xb0, 0xd8, 0x98, 0x82, 0x66, 0x73, 0x42, 0x45, 0x66, 0x64, 0x90, 0x68, 0x5c, + 0x00, 0x0c, 0xb3, 0x5a, 0x39, 0xac, 0xf1, 0x98, 0x2e, 0x0b, 0xd1, 0xb8, 0xed, 0x23, 0xa3, 0xdb, + 0x30, 0x25, 0xa4, 0x70, 0xc3, 0xb1, 0x33, 0xfc, 0x8b, 0x11, 0x31, 0x61, 0xcb, 0x89, 0xa7, 0x73, + 0xd3, 0xdd, 0x87, 0x19, 0x21, 0xa8, 0xa3, 0x3d, 0xc1, 0x1c, 0x26, 0xe9, 0x29, 0x7e, 0x5c, 0x79, + 0x14, 0x79, 0x57, 0x21, 0xda, 0xb3, 0xc3, 0x63, 0x44, 0x7b, 0x81, 0x4d, 0x0a, 0xed, 0x55, 0xc2, + 0xda, 0x4b, 0xac, 0xcc, 0x89, 0xf6, 0xec, 0xc8, 0x20, 0x7a, 0x0c, 0xe7, 0x84, 0xe0, 0xa0, 0x5d, + 0xaa, 0x54, 0xf2, 0xd5, 0x88, 0xe4, 0x78, 0xc3, 0x88, 0x3d, 0x07, 0x2c, 0xb3, 0xe6, 0x41, 0x3f, + 0xf5, 0xc4, 0xe9, 0x70, 0x38, 0x45, 0x6b, 0x2a, 0x12, 0x4e, 0xb6, 0x47, 0x45, 0x5b, 0x50, 0x15, + 0x22, 0x74, 0x9e, 0x43, 0x6b, 0x28, 0x7c, 0x80, 0x15, 0x5f, 0x23, 0x6c, 0x4e, 0xa8, 0x15, 0x3b, + 0x38, 0xb2, 0x5e, 0x84, 0x3c, 0x1f, 0x55, 0xde, 0x82, 0x49, 0x8e, 0xb3, 0x3c, 0x25, 0x7f, 0x19, + 0x8a, 0x16, 0xbf, 0x16, 0x90, 0xbd, 0x10, 0x81, 0x6c, 0x36, 0x4e, 0x31, 0xdb, 0xe3, 0x56, 0xfe, + 0x05, 0x30, 0x1d, 0x61, 0x40, 0x1b, 0xf1, 0xa8, 0x7d, 0x31, 0x09, 0xb5, 0xd9, 0xd4, 0x08, 0x6c, + 0xdf, 0x8c, 0x81, 0xed, 0x85, 0x58, 0xd8, 0x76, 0x05, 0xf8, 0x70, 0x7b, 0x23, 0x1e, 0xb7, 0x2f, + 0x26, 0xe1, 0x76, 0x78, 0x11, 0xdc, 0x94, 0x6f, 0xc4, 0x01, 0xf7, 0x85, 0x78, 0xe0, 0x76, 0x45, + 0xf8, 0x91, 0xfb, 0x9b, 0x43, 0x90, 0xfb, 0x85, 0x61, 0xc8, 0xed, 0x4a, 0x8d, 0x87, 0xee, 0xf5, + 0x58, 0xe8, 0x5e, 0x4c, 0x80, 0x6e, 0x57, 0x58, 0x00, 0xbb, 0x37, 0xe2, 0xb1, 0xfb, 0x62, 0x12, + 0x76, 0x7b, 0xba, 0x0a, 0x80, 0xf7, 0xcd, 0x18, 0xf0, 0x5e, 0x88, 0x05, 0x6f, 0xcf, 0x60, 0x1e, + 0x7a, 0xbf, 0x11, 0x87, 0xde, 0x17, 0xe2, 0xd1, 0xdb, 0xd3, 0xb4, 0x0f, 0xbe, 0x1f, 0x0c, 0x82, + 0xef, 0x2b, 0x03, 0xe1, 0xdb, 0x95, 0x17, 0x83, 0xdf, 0x8f, 0x06, 0xe2, 0xf7, 0xd5, 0xc1, 0xf8, + 0xed, 0x0a, 0x8e, 0x03, 0xf0, 0x8d, 0x78, 0x00, 0xbf, 0x98, 0x04, 0xe0, 0x9e, 0xda, 0x03, 0x08, + 0xbe, 0x99, 0x80, 0xe0, 0x4b, 0x89, 0x08, 0xee, 0x0a, 0x0a, 0x41, 0xf8, 0x83, 0x41, 0x10, 0x7e, + 0x65, 0x20, 0x84, 0x7b, 0x1a, 0x8c, 0x62, 0xf8, 0xa3, 0x81, 0x18, 0x7e, 0x75, 0x30, 0x86, 0x7b, + 0x1a, 0x8c, 0x01, 0xf1, 0xaf, 0x0f, 0x06, 0xf1, 0x6b, 0x43, 0x40, 0xdc, 0x95, 0x1d, 0x8b, 0xe2, + 0xeb, 0xb1, 0x28, 0xbe, 0x98, 0x80, 0xe2, 0x5e, 0x64, 0xf9, 0x61, 0x7c, 0x3b, 0x11, 0xc6, 0x2f, + 0x0f, 0x80, 0x71, 0x57, 0x56, 0x04, 0xc7, 0x01, 0x0a, 0x62, 0x78, 0xf5, 0x9f, 0xd3, 0x50, 0xd8, + 0xe2, 0x32, 0xd0, 0x16, 0x94, 0x19, 0x6c, 0xf2, 0x7f, 0x66, 0x07, 0x97, 0xc8, 0xf2, 0x10, 0x2c, + 0x46, 0x75, 0x28, 0xde, 0xc6, 0x0e, 0x97, 0x35, 0xa0, 0x56, 0x96, 0x07, 0x01, 0x32, 0x59, 0x14, + 0xd3, 0x65, 0xd2, 0xa2, 0x02, 0xd9, 0x54, 0x1e, 0x82, 0xcd, 0x68, 0x13, 0x4a, 0x44, 0xa9, 0x6c, + 0xcc, 0x46, 0x83, 0xca, 0x67, 0x79, 0x20, 0x44, 0x23, 0x0c, 0xb3, 0xbb, 0x62, 0x7b, 0x7e, 0x30, + 0x1d, 0xad, 0x8c, 0x96, 0x47, 0xc4, 0x6c, 0xf4, 0x16, 0x94, 0xa8, 0xb7, 0xf2, 0x6f, 0x75, 0x07, + 0xd6, 0xd3, 0xf2, 0x60, 0xc8, 0xa6, 0x06, 0xa6, 0x51, 0xca, 0x85, 0x0d, 0x2e, 0xac, 0xe5, 0x21, + 0xd8, 0xcd, 0x0d, 0xcc, 0x65, 0x0d, 0xa8, 0xb0, 0xe5, 0x41, 0x00, 0x2e, 0x2c, 0xc2, 0x06, 0x02, + 0x16, 0x89, 0xd4, 0xda, 0xf2, 0x40, 0x28, 0x47, 0xef, 0xc2, 0xb4, 0x2f, 0xb0, 0xf9, 0xba, 0x46, + 0xa8, 0xb9, 0xe5, 0x51, 0x80, 0x1d, 0x35, 0x01, 0xf9, 0x43, 0x9b, 0x8b, 0x1f, 0xa5, 0xf6, 0x96, + 0x47, 0x02, 0x78, 0x62, 0x1d, 0xfa, 0x5c, 0x71, 0x9c, 0x3d, 0xb8, 0x08, 0x97, 0x87, 0x40, 0x3c, + 0xda, 0x81, 0x49, 0x66, 0x2f, 0x21, 0x6f, 0x48, 0x35, 0x2e, 0x0f, 0xc3, 0x7a, 0xa2, 0x5f, 0x0f, + 0x91, 0x85, 0xd4, 0x11, 0xaa, 0x72, 0x79, 0x14, 0xd8, 0x27, 0xfa, 0xf5, 0xa9, 0x5d, 0x88, 0x1f, + 0xa5, 0x3a, 0x97, 0x47, 0x82, 0x7f, 0xb4, 0x07, 0x33, 0x7e, 0xbd, 0x8b, 0x27, 0x8c, 0x54, 0xa5, + 0xcb, 0xa3, 0xa5, 0x01, 0x74, 0x07, 0xca, 0xfe, 0x7f, 0x24, 0xd0, 0xc0, 0x7a, 0x5d, 0x1e, 0x9c, + 0x07, 0xd0, 0x3b, 0x50, 0x11, 0xa0, 0x2d, 0x16, 0x3b, 0xb4, 0x70, 0x97, 0x87, 0xe7, 0x04, 0xf4, + 0x1a, 0x64, 0x69, 0xc1, 0x8d, 0xe6, 0xe2, 0xbb, 0x2a, 0xf2, 0x7c, 0x42, 0xe9, 0x8e, 0x1e, 0x42, + 0x95, 0x81, 0x3c, 0x17, 0x7d, 0xaf, 0xad, 0xc7, 0x2c, 0x29, 0xf4, 0x17, 0x69, 0xcc, 0x92, 0x22, + 0x7f, 0x45, 0x7e, 0x0d, 0xaa, 0x01, 0x67, 0x25, 0xb4, 0xcb, 0x83, 0xfd, 0x95, 0x48, 0x56, 0x86, + 0xb8, 0x2c, 0x11, 0xb3, 0x0b, 0x53, 0xbe, 0x1f, 0xaf, 0x08, 0x25, 0xea, 0xe8, 0xc1, 0x5f, 0xc4, + 0xe4, 0x4b, 0x09, 0x0c, 0x9e, 0xd0, 0x26, 0xa0, 0x90, 0x69, 0x08, 0xf5, 0xca, 0x30, 0xeb, 0x10, + 0xe1, 0x57, 0x87, 0x1a, 0x88, 0x2b, 0x24, 0xe0, 0xa6, 0xf1, 0x0a, 0x09, 0xff, 0x01, 0x16, 0xa3, + 0x90, 0xe8, 0x1f, 0x59, 0xef, 0x40, 0xc5, 0xef, 0xa3, 0x21, 0x1b, 0xc6, 0xff, 0x27, 0xe5, 0xb7, + 0x61, 0xd2, 0x6f, 0x43, 0xef, 0xc2, 0x74, 0x30, 0x87, 0x11, 0x62, 0x60, 0x41, 0xf1, 0x7f, 0xe6, + 0x04, 0xe1, 0x21, 0xe1, 0x87, 0x19, 0x92, 0x07, 0x7d, 0x7f, 0xba, 0xf8, 0x03, 0x2b, 0xfa, 0x1f, + 0x8d, 0x3f, 0xb0, 0x62, 0x7e, 0x8f, 0x59, 0xcf, 0x3c, 0x4e, 0xf5, 0xf6, 0xf6, 0x72, 0xf4, 0x5c, + 0xf6, 0xd5, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x70, 0x7c, 0x53, 0x8c, 0xd4, 0x44, 0x00, 0x00, } type DRPCMetainfoClient interface { diff --git a/pkg/pb/metainfo.proto b/pkg/pb/metainfo.proto index 16011cd8f..51f7b02ed 100644 --- a/pkg/pb/metainfo.proto +++ b/pkg/pb/metainfo.proto @@ -215,7 +215,7 @@ message ListSegmentsRequestOld { bytes bucket = 1; bytes prefix = 2; bytes start_after = 3; - bytes end_before = 4; + bytes end_before = 4 [deprecated=true]; bool recursive = 5; int32 limit = 6; fixed32 meta_flags = 7; diff --git a/pkg/storj/metainfo.go b/pkg/storj/metainfo.go index 690468455..693fe52ca 100644 --- a/pkg/storj/metainfo.go +++ b/pkg/storj/metainfo.go @@ -77,9 +77,9 @@ func (create CreateObject) Object(bucket Bucket, path Path) Object { type ListDirection int8 const ( - // Before lists backwards from cursor, without cursor + // Before lists backwards from cursor, without cursor [NOT SUPPORTED] Before = ListDirection(-2) - // Backward lists backwards from cursor, including cursor + // Backward lists backwards from cursor, including cursor [NOT SUPPORTED] Backward = ListDirection(-1) // Forward lists forwards from cursor, including cursor Forward = ListDirection(1) @@ -114,24 +114,12 @@ func (opts ListOptions) NextPage(list ObjectList) ListOptions { return ListOptions{} } - switch opts.Direction { - case Before, Backward: - return ListOptions{ - Prefix: opts.Prefix, - Cursor: list.Items[0].Path, - Direction: Before, - Limit: opts.Limit, - } - case After, Forward: - return ListOptions{ - Prefix: opts.Prefix, - Cursor: list.Items[len(list.Items)-1].Path, - Direction: After, - Limit: opts.Limit, - } + return ListOptions{ + Prefix: opts.Prefix, + Cursor: list.Items[len(list.Items)-1].Path, + Direction: After, + Limit: opts.Limit, } - - return ListOptions{} } // BucketListOptions lists objects @@ -153,22 +141,11 @@ func (opts BucketListOptions) NextPage(list BucketList) BucketListOptions { return BucketListOptions{} } - switch opts.Direction { - case Before, Backward: - return BucketListOptions{ - Cursor: list.Items[0].Name, - Direction: Before, - Limit: opts.Limit, - } - case After, Forward: - return BucketListOptions{ - Cursor: list.Items[len(list.Items)-1].Name, - Direction: After, - Limit: opts.Limit, - } + return BucketListOptions{ + Cursor: list.Items[len(list.Items)-1].Name, + Direction: After, + Limit: opts.Limit, } - - return BucketListOptions{} } // MetainfoLimits lists limits specified for the Metainfo database diff --git a/proto.lock b/proto.lock index 0f3d32db9..eb3436aec 100644 --- a/proto.lock +++ b/proto.lock @@ -2431,7 +2431,13 @@ { "id": 4, "name": "end_before", - "type": "bytes" + "type": "bytes", + "options": [ + { + "name": "deprecated", + "value": "true" + } + ] }, { "id": 5, diff --git a/satellite/metainfo/metainfo.go b/satellite/metainfo/metainfo.go index a5e6bc654..4c35dfecc 100644 --- a/satellite/metainfo/metainfo.go +++ b/satellite/metainfo/metainfo.go @@ -438,7 +438,7 @@ func (endpoint *Endpoint) ListSegmentsOld(ctx context.Context, req *pb.ListSegme return nil, rpcstatus.Error(rpcstatus.InvalidArgument, err.Error()) } - items, more, err := endpoint.metainfo.List(ctx, prefix, string(req.StartAfter), string(req.EndBefore), req.Recursive, req.Limit, req.MetaFlags) + items, more, err := endpoint.metainfo.List(ctx, prefix, string(req.StartAfter), req.Recursive, req.Limit, req.MetaFlags) if err != nil { return nil, rpcstatus.Error(rpcstatus.Internal, err.Error()) } @@ -924,7 +924,7 @@ func (endpoint *Endpoint) setBucketAttribution(ctx context.Context, header *pb.R return rpcstatus.Error(rpcstatus.InvalidArgument, err.Error()) } - items, _, err := endpoint.metainfo.List(ctx, prefix, "", "", true, 1, 0) + items, _, err := endpoint.metainfo.List(ctx, prefix, "", true, 1, 0) if err != nil { endpoint.log.Error("error while listing segments", zap.Error(err)) return rpcstatus.Error(rpcstatus.Internal, err.Error()) @@ -1292,8 +1292,7 @@ func (endpoint *Endpoint) ListObjects(ctx context.Context, req *pb.ObjectListReq metaflags := meta.All // TODO use flags - // TODO find out how EncryptedCursor -> startAfter/endAfter - segments, more, err := endpoint.metainfo.List(ctx, prefix, string(req.EncryptedCursor), "", req.Recursive, req.Limit, metaflags) + segments, more, err := endpoint.metainfo.List(ctx, prefix, string(req.EncryptedCursor), req.Recursive, req.Limit, metaflags) if err != nil { return nil, rpcstatus.Error(rpcstatus.Internal, err.Error()) } diff --git a/satellite/metainfo/service.go b/satellite/metainfo/service.go index fc6503856..037e76578 100644 --- a/satellite/metainfo/service.go +++ b/satellite/metainfo/service.go @@ -196,7 +196,7 @@ func (s *Service) GetWithBytes(ctx context.Context, path string) (pointerBytes [ } // List returns all Path keys in the pointers bucket -func (s *Service) List(ctx context.Context, prefix string, startAfter string, endBefore string, recursive bool, limit int32, +func (s *Service) List(ctx context.Context, prefix string, startAfter string, recursive bool, limit int32, metaFlags uint32) (items []*pb.ListResponse_Item, more bool, err error) { defer mon.Task()(&ctx)(&err) @@ -211,7 +211,6 @@ func (s *Service) List(ctx context.Context, prefix string, startAfter string, en rawItems, more, err := storage.ListV2(ctx, s.db, storage.ListOptions{ Prefix: prefixKey, StartAfter: storage.Key(startAfter), - EndBefore: storage.Key(endBefore), Recursive: recursive, Limit: int(limit), IncludeValue: metaFlags != meta.None, diff --git a/satellite/repair/repair_test.go b/satellite/repair/repair_test.go index 0d245fc48..2b62ab766 100644 --- a/satellite/repair/repair_test.go +++ b/satellite/repair/repair_test.go @@ -597,7 +597,7 @@ func TestRepairMultipleDisqualified(t *testing.T) { // get a remote segment from metainfo metainfo := satellite.Metainfo.Service - listResponse, _, err := metainfo.List(ctx, "", "", "", true, 0, 0) + listResponse, _, err := metainfo.List(ctx, "", "", true, 0, 0) require.NoError(t, err) var path string @@ -1036,7 +1036,7 @@ func getRemoteSegment( // get a remote segment from metainfo metainfo := satellite.Metainfo.Service - listResponse, _, err := metainfo.List(ctx, "", "", "", true, 0, 0) + listResponse, _, err := metainfo.List(ctx, "", "", true, 0, 0) require.NoError(t, err) for _, v := range listResponse { diff --git a/storage/boltdb/client.go b/storage/boltdb/client.go index 2289f5c6a..e2c449166 100644 --- a/storage/boltdb/client.go +++ b/storage/boltdb/client.go @@ -226,12 +226,7 @@ func (client *Client) GetAll(ctx context.Context, keys storage.Keys) (_ storage. func (client *Client) Iterate(ctx context.Context, opts storage.IterateOptions, fn func(context.Context, storage.Iterator) error) (err error) { defer mon.Task()(&ctx)(&err) return client.view(func(bucket *bolt.Bucket) error { - var cursor advancer - if !opts.Reverse { - cursor = forward{bucket.Cursor()} - } else { - cursor = backward{bucket.Cursor()} - } + var cursor advancer = forward{bucket.Cursor()} start := true lastPrefix := []byte{} @@ -307,46 +302,6 @@ func (cursor forward) Advance() (key, value []byte) { return cursor.Next() } -type backward struct { - *bolt.Cursor -} - -func (cursor backward) PositionToFirst(prefix, first storage.Key) (key, value []byte) { - if prefix.IsZero() { - // there's no prefix - if first.IsZero() { - // and no first item, so start from the end - return cursor.Last() - } - } else { - // there's a prefix - if first.IsZero() || storage.AfterPrefix(prefix).Less(first) { - // there's no first, or it's after our prefix - // storage.AfterPrefix("axxx/") is the next item after prefixes - // so we position to the item before - nextkey := storage.AfterPrefix(prefix) - _, _ = cursor.Seek(nextkey) - return cursor.Prev() - } - } - - // otherwise try to position on first or one before that - key, value = cursor.Seek(first) - if !bytes.Equal(key, first) { - key, value = cursor.Prev() - } - return key, value -} - -func (cursor backward) SkipPrefix(prefix storage.Key) (key, value []byte) { - _, _ = cursor.Seek(prefix) - return cursor.Prev() -} - -func (cursor backward) Advance() (key, value []byte) { - return cursor.Prev() -} - // CompareAndSwap atomically compares and swaps oldValue with newValue func (client *Client) CompareAndSwap(ctx context.Context, key storage.Key, oldValue, newValue storage.Value) (err error) { defer mon.Task()(&ctx)(&err) diff --git a/storage/common.go b/storage/common.go index afdb70d8a..74a2b47ab 100644 --- a/storage/common.go +++ b/storage/common.go @@ -85,8 +85,6 @@ type IterateOptions struct { First Key // Recurse, do not collapse items based on Delimiter Recurse bool - // Reverse iterates in reverse order - Reverse bool } // Iterator iterates over a sequence of ListItems diff --git a/storage/iterator.go b/storage/iterator.go index 76ebfa96b..0cbd91009 100644 --- a/storage/iterator.go +++ b/storage/iterator.go @@ -60,26 +60,6 @@ func SortAndCollapse(items Items, prefix []byte) Items { return result } -// ReverseItems reverses items in the list -// items will be reused and modified -// TODO: remove this -func ReverseItems(items Items) Items { - for i := len(items)/2 - 1; i >= 0; i-- { - k := len(items) - 1 - i - items[i], items[k] = items[k], items[i] - } - return items -} - -// ReverseKeys reverses the list of keys -func ReverseKeys(keys Keys) Keys { - for i := len(keys)/2 - 1; i >= 0; i-- { - k := len(keys) - 1 - i - keys[i], keys[k] = keys[k], keys[i] - } - return keys -} - // StaticIterator implements an iterator over list of items type StaticIterator struct { Items Items diff --git a/storage/listv2.go b/storage/listv2.go index 12496ac6a..ac2a499fa 100644 --- a/storage/listv2.go +++ b/storage/listv2.go @@ -5,14 +5,12 @@ package storage import ( "context" - "errors" ) // ListOptions are items that are optional for the LIST method type ListOptions struct { Prefix Key StartAfter Key // StartAfter is relative to Prefix - EndBefore Key // EndBefore is relative to Prefix Recursive bool IncludeValue bool Limit int @@ -24,12 +22,9 @@ type ListOptions struct { // more indicates if the result was truncated. If false // then the result []ListItem includes all requested keys. // If true then the caller must call List again to get more -// results by setting `StartAfter` or `EndBefore` appropriately. +// results by setting `StartAfter` appropriately. func ListV2(ctx context.Context, store KeyValueStore, opts ListOptions) (result Items, more bool, err error) { defer mon.Task()(&ctx)(&err) - if !opts.StartAfter.IsZero() && !opts.EndBefore.IsZero() { - return nil, false, errors.New("start-after and end-before cannot be combined") - } limit := opts.Limit if limit <= 0 || limit > LookupLimit { @@ -37,15 +32,8 @@ func ListV2(ctx context.Context, store KeyValueStore, opts ListOptions) (result } more = true - reverse := !opts.EndBefore.IsZero() - - var first Key - if !reverse { - first = opts.StartAfter - } else { - first = opts.EndBefore - } + first := opts.StartAfter iterate := func(ctx context.Context, it Iterator) error { var item ListItem skipFirst := true @@ -86,23 +74,15 @@ func ListV2(ctx context.Context, store KeyValueStore, opts ListOptions) (result } var firstFull Key - if !reverse && !opts.StartAfter.IsZero() { + if !opts.StartAfter.IsZero() { firstFull = joinKey(opts.Prefix, opts.StartAfter) } - if reverse && !opts.EndBefore.IsZero() { - firstFull = joinKey(opts.Prefix, opts.EndBefore) - } err = store.Iterate(ctx, IterateOptions{ Prefix: opts.Prefix, First: firstFull, - Reverse: reverse, Recurse: opts.Recursive, }, iterate) - if reverse { - result = ReverseItems(result) - } - return result, more, err } diff --git a/storage/postgreskv/alternateclient.go b/storage/postgreskv/alternateclient.go index 1395b13b0..03d79dc30 100644 --- a/storage/postgreskv/alternateclient.go +++ b/storage/postgreskv/alternateclient.go @@ -57,29 +57,6 @@ FROM ( ) x ORDER BY p LIMIT $4 -` - - alternateReverseQuery = ` -SELECT DISTINCT - $2::BYTEA || x.localpath AS p, - first_value(x.metadata) OVER (PARTITION BY x.localpath ORDER BY x.fullpath) AS m -FROM ( - SELECT - pd.fullpath, - local_path(pd.fullpath, $2::BYTEA, set_byte(' '::BYTEA, 0, b.delim)) AS localpath, - pd.metadata - FROM - pathdata pd, - buckets b - WHERE - b.bucketname = $1::BYTEA - AND pd.bucket = b.bucketname - AND pd.fullpath >= $2::BYTEA - AND ($2::BYTEA = ''::BYTEA OR pd.fullpath < bytea_increment($2::BYTEA)) - AND ($3::BYTEA = ''::BYTEA OR pd.fullpath <= $3::BYTEA) -) x -ORDER BY p DESC -LIMIT $4 ` ) @@ -120,13 +97,7 @@ func (opi *alternateOrderedPostgresIterator) doNextQuery(ctx context.Context) (_ if start == nil { start = opi.opts.First } - var query string - if opi.opts.Reverse { - query = alternateReverseQuery - } else { - query = alternateForwardQuery - } - return opi.client.pgConn.Query(query, []byte(opi.bucket), []byte(opi.opts.Prefix), []byte(start), opi.batchSize+1) + return opi.client.pgConn.Query(alternateForwardQuery, []byte(opi.bucket), []byte(opi.opts.Prefix), []byte(start), opi.batchSize+1) } func newAlternateOrderedPostgresIterator(ctx context.Context, altClient *AlternateClient, opts storage.IterateOptions, batchSize int) (_ *alternateOrderedPostgresIterator, err error) { diff --git a/storage/postgreskv/client.go b/storage/postgreskv/client.go index 0f062c096..fd7909be7 100644 --- a/storage/postgreskv/client.go +++ b/storage/postgreskv/client.go @@ -6,7 +6,6 @@ package postgreskv import ( "context" "database/sql" - "fmt" "github.com/lib/pq" "github.com/zeebo/errs" @@ -254,28 +253,18 @@ func (opi *orderedPostgresIterator) doNextQuery(ctx context.Context) (_ *sql.Row } var query string if !opi.opts.Recurse { - if opi.opts.Reverse { - query = "SELECT p, m FROM list_directory_reverse($1::BYTEA, $2::BYTEA, $3::BYTEA, $4) ld(p, m)" - } else { - query = "SELECT p, m FROM list_directory($1::BYTEA, $2::BYTEA, $3::BYTEA, $4) ld(p, m)" - } + query = "SELECT p, m FROM list_directory($1::BYTEA, $2::BYTEA, $3::BYTEA, $4) ld(p, m)" } else { - startCmp := ">=" - orderDir := "" - if opi.opts.Reverse { - startCmp = "<=" - orderDir = " DESC" - } - query = fmt.Sprintf(` + query = ` SELECT fullpath, metadata FROM pathdata WHERE bucket = $1::BYTEA AND ($2::BYTEA = ''::BYTEA OR fullpath >= $2::BYTEA) AND ($2::BYTEA = ''::BYTEA OR fullpath < bytea_increment($2::BYTEA)) - AND ($3::BYTEA = ''::BYTEA OR fullpath %s $3::BYTEA) - ORDER BY fullpath%s + AND ($3::BYTEA = ''::BYTEA OR fullpath >= $3::BYTEA) + ORDER BY fullpath LIMIT $4 - `, startCmp, orderDir) + ` } return opi.client.pgConn.Query(query, []byte(opi.bucket), []byte(opi.opts.Prefix), []byte(start), opi.batchSize+1) } diff --git a/storage/redis/client.go b/storage/redis/client.go index 40f392219..aa4e5d58e 100644 --- a/storage/redis/client.go +++ b/storage/redis/client.go @@ -164,21 +164,13 @@ func (client *Client) GetAll(ctx context.Context, keys storage.Keys) (_ storage. // Iterate iterates over items based on opts func (client *Client) Iterate(ctx context.Context, opts storage.IterateOptions, fn func(context.Context, storage.Iterator) error) (err error) { defer mon.Task()(&ctx)(&err) - var all storage.Items - if !opts.Reverse { - all, err = client.allPrefixedItems(opts.Prefix, opts.First, nil) - } else { - all, err = client.allPrefixedItems(opts.Prefix, nil, opts.First) - } + all, err := client.allPrefixedItems(opts.Prefix, opts.First, nil) if err != nil { return err } if !opts.Recurse { all = storage.SortAndCollapse(all, opts.Prefix) } - if opts.Reverse { - all = storage.ReverseItems(all) - } return fn(ctx, &storage.StaticIterator{ Items: all, }) diff --git a/storage/storelogger/logger.go b/storage/storelogger/logger.go index 3172dcec6..08a6c1e6b 100644 --- a/storage/storelogger/logger.go +++ b/storage/storelogger/logger.go @@ -74,7 +74,6 @@ func (store *Logger) Iterate(ctx context.Context, opts storage.IterateOptions, f zap.ByteString("prefix", opts.Prefix), zap.ByteString("first", opts.First), zap.Bool("recurse", opts.Recurse), - zap.Bool("reverse", opts.Reverse), ) return store.store.Iterate(ctx, opts, func(ctx context.Context, it storage.Iterator) error { return fn(ctx, storage.IteratorFunc(func(ctx context.Context, item *storage.ListItem) bool { diff --git a/storage/teststore/store.go b/storage/teststore/store.go index 70becb4c7..01f205298 100644 --- a/storage/teststore/store.go +++ b/storage/teststore/store.go @@ -30,7 +30,6 @@ type Client struct { Put int List int GetAll int - ReverseList int Delete int Close int Iterate int @@ -202,12 +201,7 @@ func (store *Client) Iterate(ctx context.Context, opts storage.IterateOptions, f return errInternal } - var cursor advancer - if !opts.Reverse { - cursor = &forward{newCursor(store)} - } else { - cursor = &backward{newCursor(store)} - } + var cursor advancer = &forward{newCursor(store)} cursor.PositionToFirst(opts.Prefix, opts.First) var lastPrefix storage.Key diff --git a/storage/testsuite/long_bench.go b/storage/testsuite/long_bench.go index 4a2d90713..09da28255 100644 --- a/storage/testsuite/long_bench.go +++ b/storage/testsuite/long_bench.go @@ -194,19 +194,12 @@ func BenchmarkPathOperationsInLargeDb(b *testing.B, store storage.KeyValueStore) } doTest("DeepRecursive", deepRecursive) - doTest("DeepRecursiveReverse", deepRecursiveReverse) doTest("DeepNonRecursive", deepNonRecursive) - doTest("DeepNonRecursiveReverse", deepNonRecursiveReverse) doTest("ShallowRecursive", shallowRecursive) - doTest("ShallowRecursiveReverse", shallowRecursiveReverse) doTest("ShallowNonRecursive", shallowNonRecursive) - doTest("ShallowNonRecursiveReverse", shallowNonRecursiveReverse) doTest("TopRecursiveLimit", topRecursiveLimit) - doTest("TopRecursiveLimitReverse", topRecursiveLimitReverse) doTest("TopRecursiveStartAt", topRecursiveStartAt) - doTest("TopRecursiveStartAtReverse", topRecursiveStartAtReverse) doTest("TopNonRecursive", topNonRecursive) - doTest("TopNonRecursiveReverse", topNonRecursiveReverse) cleanupStore(b, store) } @@ -347,10 +340,7 @@ func benchAndVerifyIteration(b *testing.B, store storage.KeyValueStore, opts *ve if result.Key.Equal(lastKey) { errorf("got the same key (%q) twice in a row, not on a lookup boundary!", lastKey) } - if opts.iterateOpts.Reverse && !lastKey.IsZero() && lastKey.Less(result.Key) { - errorf("KeyValueStore returned items out of order! %q > %q", result.Key, lastKey) - } - if !opts.iterateOpts.Reverse && result.Key.Less(lastKey) { + if result.Key.Less(lastKey) { errorf("KeyValueStore returned items out of order! %q < %q", result.Key, lastKey) } if result.IsPrefix { @@ -410,31 +400,6 @@ func deepRecursive(b *testing.B, store storage.KeyValueStore) { benchAndVerifyIteration(b, store, opts) } -func deepRecursiveReverse(b *testing.B, store storage.KeyValueStore) { - opts := &verifyOpts{ - iterateOpts: storage.IterateOptions{ - Prefix: storage.Key(largestLevel2Directory), - Recurse: true, - Reverse: true, - }, - } - - // these are not expected to exhaust all available items - opts.doIterations = 500 - opts.batchSize = storage.LookupLimit - opts.expectCount = opts.doIterations * opts.batchSize - - // verify with: - // select encode(fullpath, 'escape') from ( - // select rank() over (order by fullpath desc), fullpath from pathdata - // where fullpath < bytea_increment($1::bytea) - // ) x where rank = ($2 * $3); - // where $1 = largestLevel2Directory, $2 = doIterations, and $3 = batchSize - opts.expectLastKey = storage.Key("Peronosporales/hateless/apetaly/poikilocythemia/capped/abrash/dugout/notodontid/jasponyx/cassican/brunelliaceous") - - benchAndVerifyIteration(b, store, opts) -} - func deepNonRecursive(b *testing.B, store storage.KeyValueStore) { opts := &verifyOpts{ iterateOpts: storage.IterateOptions{ @@ -460,32 +425,6 @@ func deepNonRecursive(b *testing.B, store storage.KeyValueStore) { benchAndVerifyIteration(b, store, opts) } -func deepNonRecursiveReverse(b *testing.B, store storage.KeyValueStore) { - opts := &verifyOpts{ - iterateOpts: storage.IterateOptions{ - Prefix: storage.Key(largestLevel2Directory), - Recurse: false, - Reverse: true, - }, - doIterations: 1, - batchSize: 10000, - } - - // verify with: - // select count(*) from list_directory(''::bytea, $1::bytea) ld(fp, md); - // where $1 is largestLevel2Directory - opts.expectCount = 119 - - // verify with: - // select encode(fp, 'escape') from ( - // select * from list_directory(''::bytea, $1::bytea) ld(fp, md) - // ) x order by fp limit 1; - // where $1 is largestLevel2Directory - opts.expectLastKey = storage.Key("Peronosporales/hateless/Absyrtus") - - benchAndVerifyIteration(b, store, opts) -} - func shallowRecursive(b *testing.B, store storage.KeyValueStore) { opts := &verifyOpts{ iterateOpts: storage.IterateOptions{ @@ -515,36 +454,6 @@ func shallowRecursive(b *testing.B, store storage.KeyValueStore) { benchAndVerifyIteration(b, store, opts) } -func shallowRecursiveReverse(b *testing.B, store storage.KeyValueStore) { - opts := &verifyOpts{ - iterateOpts: storage.IterateOptions{ - Prefix: storage.Key(largestSingleDirectory), - Recurse: true, - Reverse: true, - }, - } - - // verify with: - // select count(*) from pathdata - // where fullpath > $1::bytea and fullpath < bytea_increment($1::bytea); - // where $1 = largestSingleDirectory - opts.expectCount = 18574 - - // verify with: - // select convert_from(fullpath, 'UTF8') from pathdata - // where fullpath > $1::bytea and fullpath < bytea_increment($1::bytea) - // order by fullpath limit 1; - // where $1 = largestSingleDirectory - opts.expectLastKey = storage.Key("Peronosporales/hateless/tod/unricht/sniveling/Puyallup/Aaronite") - - // i didn't plan it this way, but expectedCount happens to have some nicely-sized factors for - // our purposes with no messy remainder. 74 * 251 = 18574 - opts.doIterations = 74 - opts.batchSize = 251 - - benchAndVerifyIteration(b, store, opts) -} - func shallowNonRecursive(b *testing.B, store storage.KeyValueStore) { opts := &verifyOpts{ iterateOpts: storage.IterateOptions{ @@ -570,32 +479,6 @@ func shallowNonRecursive(b *testing.B, store storage.KeyValueStore) { benchAndVerifyIteration(b, store, opts) } -func shallowNonRecursiveReverse(b *testing.B, store storage.KeyValueStore) { - opts := &verifyOpts{ - iterateOpts: storage.IterateOptions{ - Prefix: storage.Key(largestSingleDirectory), - Recurse: false, - Reverse: true, - }, - doIterations: 2, - batchSize: 10000, - } - - // verify with: - // select count(*) from list_directory(''::bytea, $1::bytea) ld(fp, md); - // where $1 is largestSingleDirectory - opts.expectCount = 18574 - - // verify with: - // select encode(fp, 'escape') from ( - // select * from list_directory(''::bytea, $1::bytea) ld(fp, md) - // ) x order by fp limit 1; - // where $1 = largestSingleDirectory - opts.expectLastKey = storage.Key("Peronosporales/hateless/tod/unricht/sniveling/Puyallup/Aaronite") - - benchAndVerifyIteration(b, store, opts) -} - func topRecursiveLimit(b *testing.B, store storage.KeyValueStore) { opts := &verifyOpts{ iterateOpts: storage.IterateOptions{ @@ -618,29 +501,6 @@ func topRecursiveLimit(b *testing.B, store storage.KeyValueStore) { benchAndVerifyIteration(b, store, opts) } -func topRecursiveLimitReverse(b *testing.B, store storage.KeyValueStore) { - opts := &verifyOpts{ - iterateOpts: storage.IterateOptions{ - Recurse: true, - Reverse: true, - }, - doIterations: 100, - batchSize: 10000, - } - - // not expected to exhaust items - opts.expectCount = opts.doIterations * opts.batchSize - - // verify with: - // select encode(fullpath, 'escape') from ( - // select rank() over (order by fullpath desc), fullpath from pathdata - // ) x where rank = $1; - // where $1 = expectCount - opts.expectLastKey = storage.Key("nonresuscitation/synchronically/cabook/homeozoic/inclinatorium/iguanodont/thiophenol/congeliturbation/Alaric") - - benchAndVerifyIteration(b, store, opts) -} - func topRecursiveStartAt(b *testing.B, store storage.KeyValueStore) { opts := &verifyOpts{ iterateOpts: storage.IterateOptions{ @@ -666,36 +526,6 @@ func topRecursiveStartAt(b *testing.B, store storage.KeyValueStore) { benchAndVerifyIteration(b, store, opts) } -func topRecursiveStartAtReverse(b *testing.B, store storage.KeyValueStore) { - opts := &verifyOpts{ - iterateOpts: storage.IterateOptions{ - Recurse: true, - Reverse: true, - }, - doIterations: 61, - batchSize: 10000, - } - - // this is pretty arbitrary. just the key 100 positions before the end of the Peronosporales/hateless/ dir. - opts.iterateOpts.First = storage.Key("Peronosporales/hateless/warrener/anthropomancy/geisotherm/wickerwork") - - // we *do* expect to exhaust the available items this time. - // verify with: - // select count(*) from ( - // select fullpath from pathdata where fullpath <= $1::bytea order by fullpath desc limit $2 - // ) x; - // where $1 = iterateOpts.First and $2 = (doIterations * batchSize) - opts.expectCount = 608405 - - // since expectCount < (doIterations * batchSize), and we're going in reverse, the last key read - // should be the first one lexicographically. - // verify with: - // select encode(fullpath, 'escape') from pathdata order by fullpath limit 1; - opts.expectLastKey = storage.Key("Lissamphibia") - - benchAndVerifyIteration(b, store, opts) -} - func topNonRecursive(b *testing.B, store storage.KeyValueStore) { opts := &verifyOpts{ iterateOpts: storage.IterateOptions{ @@ -718,27 +548,6 @@ func topNonRecursive(b *testing.B, store storage.KeyValueStore) { benchAndVerifyIteration(b, store, opts) } -func topNonRecursiveReverse(b *testing.B, store storage.KeyValueStore) { - opts := &verifyOpts{ - iterateOpts: storage.IterateOptions{ - Recurse: false, - Reverse: true, - }, - doIterations: 1, - batchSize: 10000, - } - - // verify with: - // select count(*) from list_directory(''::bytea, ''::bytea); - opts.expectCount = 21 - - // verify with: - // select encode(fullpath, 'escape') from pathdata order by fullpath limit 1; - opts.expectLastKey = storage.Key("Lissamphibia") - - benchAndVerifyIteration(b, store, opts) -} - func cleanupBigPathset(tb testing.TB, store storage.KeyValueStore) { if *noCleanDb { tb.Skip("Instructed not to clean up this KeyValueStore after long benchmarks are complete.") diff --git a/storage/testsuite/test_iterate.go b/storage/testsuite/test_iterate.go index 492d3a012..fd2929840 100644 --- a/storage/testsuite/test_iterate.go +++ b/storage/testsuite/test_iterate.go @@ -42,17 +42,6 @@ func testIterate(t *testing.T, store storage.KeyValueStore) { newItem("g", "g", false), newItem("h", "h", false), }}, - {"no limits reverse", - storage.IterateOptions{ - Reverse: true, - }, storage.Items{ - newItem("h", "h", false), - newItem("g", "g", false), - newItem("c/", "", true), - newItem("c", "c", false), - newItem("b/", "", true), - newItem("a", "a", false), - }}, {"at a", storage.IterateOptions{ @@ -66,14 +55,6 @@ func testIterate(t *testing.T, store storage.KeyValueStore) { newItem("h", "h", false), }}, - {"reverse at a", - storage.IterateOptions{ - First: storage.Key("a"), - Reverse: true, - }, storage.Items{ - newItem("a", "a", false), - }}, - {"after a", storage.IterateOptions{ First: storage.NextKey(storage.Key("a")), @@ -126,16 +107,6 @@ func testIterate(t *testing.T, store storage.KeyValueStore) { newItem("g", "g", false), newItem("h", "h", false), }}, - {"reverse after e", - storage.IterateOptions{ - First: storage.NextKey(storage.Key("e")), - Reverse: true, - }, storage.Items{ - newItem("c/", "", true), - newItem("c", "c", false), - newItem("b/", "", true), - newItem("a", "a", false), - }}, {"prefix b slash", storage.IterateOptions{ Prefix: storage.Key("b/"), diff --git a/storage/testsuite/test_iterate_all.go b/storage/testsuite/test_iterate_all.go index b862f6ac9..976708f7c 100644 --- a/storage/testsuite/test_iterate_all.go +++ b/storage/testsuite/test_iterate_all.go @@ -61,21 +61,6 @@ func testIterateAll(t *testing.T, store storage.KeyValueStore) { newItem("g", "g", false), newItem("h", "h", false), }}, - {"no limits reverse", - storage.IterateOptions{ - Recurse: true, Reverse: true, - }, storage.Items{ - newItem("h", "h", false), - newItem("g", "g", false), - newItem("c/1", "c/1", false), - newItem("c//", "c//", false), - newItem("c/", "c/", false), - newItem("c", "c", false), - newItem("b/3", "b/3", false), - newItem("b/2", "b/2", false), - newItem("b/1", "b/1", false), - newItem("a", "a", false), - }}, {"at a", storage.IterateOptions{ @@ -93,13 +78,6 @@ func testIterateAll(t *testing.T, store storage.KeyValueStore) { newItem("g", "g", false), newItem("h", "h", false), }}, - {"at a reverse", - storage.IterateOptions{ - First: storage.Key("a"), - Recurse: true, Reverse: true, - }, storage.Items{ - newItem("a", "a", false), - }}, {"after a", storage.IterateOptions{ @@ -180,20 +158,6 @@ func testIterateAll(t *testing.T, store storage.KeyValueStore) { newItem("g", "g", false), newItem("h", "h", false), }}, - {"at e reverse", - storage.IterateOptions{ - First: storage.Key("e"), - Recurse: true, Reverse: true, - }, storage.Items{ - newItem("c/1", "c/1", false), - newItem("c//", "c//", false), - newItem("c/", "c/", false), - newItem("c", "c", false), - newItem("b/3", "b/3", false), - newItem("b/2", "b/2", false), - newItem("b/1", "b/1", false), - newItem("a", "a", false), - }}, {"prefix b slash", storage.IterateOptions{ @@ -221,23 +185,6 @@ func testIterateAll(t *testing.T, store storage.KeyValueStore) { newItem("b/2", "b/2", false), newItem("b/3", "b/3", false), }}, - {"reverse prefix b slash", - storage.IterateOptions{ - Prefix: storage.Key("b/"), - Recurse: true, Reverse: true, - }, storage.Items{ - newItem("b/3", "b/3", false), - newItem("b/2", "b/2", false), - newItem("b/1", "b/1", false), - }}, - {"reverse prefix b slash at b slash 2", - storage.IterateOptions{ - Prefix: storage.Key("b/"), First: storage.Key("b/2"), - Recurse: true, Reverse: true, - }, storage.Items{ - newItem("b/2", "b/2", false), - newItem("b/1", "b/1", false), - }}, {"prefix c slash", storage.IterateOptions{ @@ -248,15 +195,6 @@ func testIterateAll(t *testing.T, store storage.KeyValueStore) { newItem("c//", "c//", false), newItem("c/1", "c/1", false), }}, - {"reverse prefix c slash", - storage.IterateOptions{ - Prefix: storage.Key("c/"), - Recurse: true, Reverse: true, - }, storage.Items{ - newItem("c/1", "c/1", false), - newItem("c//", "c//", false), - newItem("c/", "c/", false), - }}, {"prefix c slash slash", storage.IterateOptions{ @@ -265,12 +203,5 @@ func testIterateAll(t *testing.T, store storage.KeyValueStore) { }, storage.Items{ newItem("c//", "c//", false), }}, - {"reverse prefix c slash slash", - storage.IterateOptions{ - Prefix: storage.Key("c//"), - Recurse: true, Reverse: true, - }, storage.Items{ - newItem("c//", "c//", false), - }}, }) } diff --git a/storage/testsuite/test_listv2.go b/storage/testsuite/test_listv2.go index f26741ff3..0d2e89273 100644 --- a/storage/testsuite/test_listv2.go +++ b/storage/testsuite/test_listv2.go @@ -122,49 +122,6 @@ func testListV2(t *testing.T, store storage.KeyValueStore) { newItem("my-album/", "", true), }, }, - {"end before 2 recursive", - storage.ListOptions{ - Recursive: true, - EndBefore: storage.Key("music/z-song5.mp3"), - Limit: 2, - }, - true, storage.Items{ - newItem("music/my-album/song3.mp3", "", false), - newItem("music/my-album/song4.mp3", "", false), - }, - }, - {"end before non-existing 2 recursive", - storage.ListOptions{ - Recursive: true, - EndBefore: storage.Key("music/my-album/song5.mp3"), - Limit: 2, - }, - true, storage.Items{ - newItem("music/my-album/song3.mp3", "", false), - newItem("music/my-album/song4.mp3", "", false), - }, - }, - {"end before 2", - storage.ListOptions{ - Prefix: storage.Key("music/"), - EndBefore: storage.Key("z-song5.mp3"), - Limit: 2, - }, - true, storage.Items{ - newItem("a-song2.mp3", "", false), - newItem("my-album/", "", true), - }, - }, - {"end before 2 prefixed", - storage.ListOptions{ - Prefix: storage.Key("music/my-album/"), - EndBefore: storage.Key("song4.mp3"), - Limit: 2, - }, - false, storage.Items{ - newItem("song3.mp3", "", false), - }, - }, } for _, test := range tests { diff --git a/storage/testsuite/test_prefix.go b/storage/testsuite/test_prefix.go index 971a0efbf..1584d42bc 100644 --- a/storage/testsuite/test_prefix.go +++ b/storage/testsuite/test_prefix.go @@ -39,30 +39,12 @@ func testPrefix(t *testing.T, store storage.KeyValueStore) { newItem("x-b/2", "b/2", false), newItem("x-b/3", "b/3", false), }}, - {"reverse prefix x dash b slash", - storage.IterateOptions{ - Prefix: storage.Key("x-"), First: storage.Key("x-b/3"), - Recurse: true, Reverse: true, - }, storage.Items{ - newItem("x-b/3", "b/3", false), - newItem("x-b/2", "b/2", false), - newItem("x-b/1", "b/1", false), - newItem("x-a", "a", false), - }}, {"prefix x dash b slash", storage.IterateOptions{ Prefix: storage.Key("x-"), First: storage.Key("x-b"), }, storage.Items{ newItem("x-b/", "", true), }}, - {"reverse x dash b slash", - storage.IterateOptions{ - Prefix: storage.Key("x-"), First: storage.Key("x-b/2"), - Reverse: true, - }, storage.Items{ - newItem("x-b/", "", true), - newItem("x-a", "a", false), - }}, {"prefix y- slash", storage.IterateOptions{ Prefix: storage.Key("y-"), diff --git a/uplink/metainfo/client_old.go b/uplink/metainfo/client_old.go index bd071f6ad..831d547e6 100644 --- a/uplink/metainfo/client_old.go +++ b/uplink/metainfo/client_old.go @@ -134,7 +134,7 @@ func (client *Client) DeleteSegmentOld(ctx context.Context, bucket string, path } // ListSegmentsOld lists the available segments -func (client *Client) ListSegmentsOld(ctx context.Context, bucket string, prefix, startAfter, endBefore storj.Path, recursive bool, limit int32, metaFlags uint32) (items []ListItem, more bool, err error) { +func (client *Client) ListSegmentsOld(ctx context.Context, bucket string, prefix, startAfter, ignoredEndBefore storj.Path, recursive bool, limit int32, metaFlags uint32) (items []ListItem, more bool, err error) { defer mon.Task()(&ctx)(&err) response, err := client.client.ListSegmentsOld(ctx, &pb.ListSegmentsRequestOld{ @@ -142,7 +142,6 @@ func (client *Client) ListSegmentsOld(ctx context.Context, bucket string, prefix Bucket: []byte(bucket), Prefix: []byte(prefix), StartAfter: []byte(startAfter), - EndBefore: []byte(endBefore), Recursive: recursive, Limit: limit, MetaFlags: metaFlags, diff --git a/uplink/metainfo/kvmetainfo/objects.go b/uplink/metainfo/kvmetainfo/objects.go index ed578707d..6fc14c019 100644 --- a/uplink/metainfo/kvmetainfo/objects.go +++ b/uplink/metainfo/kvmetainfo/objects.go @@ -169,15 +169,9 @@ func (db *DB) ListObjects(ctx context.Context, bucket string, options storj.List prefix: bucket, } - var startAfter, endBefore string + var startAfter string switch options.Direction { // TODO for now we are supporting only storj.After - // case storj.Before: - // // before lists backwards from cursor, without cursor - // endBefore = options.Cursor - // case storj.Backward: - // // backward lists backwards from cursor, including cursor - // endBefore = keyAfter(options.Cursor) // case storj.Forward: // // forward lists forwards from cursor, including cursor // startAfter = keyBefore(options.Cursor) @@ -188,12 +182,7 @@ func (db *DB) ListObjects(ctx context.Context, bucket string, options storj.List return storj.ObjectList{}, errClass.New("invalid direction %d", options.Direction) } - // TODO: remove this hack-fix of specifying the last key - if options.Cursor == "" && (options.Direction == storj.Before || options.Direction == storj.Backward) { - endBefore = "\x7f\x7f\x7f\x7f\x7f\x7f\x7f" - } - - items, more, err := objects.List(ctx, options.Prefix, startAfter, endBefore, options.Recursive, options.Limit, meta.All) + items, more, err := objects.List(ctx, options.Prefix, startAfter, options.Recursive, options.Limit, meta.All) if err != nil { return storj.ObjectList{}, err } diff --git a/uplink/metainfo/kvmetainfo/objects_test.go b/uplink/metainfo/kvmetainfo/objects_test.go index acbf70f7d..a0f3a1030 100644 --- a/uplink/metainfo/kvmetainfo/objects_test.go +++ b/uplink/metainfo/kvmetainfo/objects_test.go @@ -294,8 +294,6 @@ func TestListObjectsEmpty(t *testing.T) { // TODO for now we are supporting only storj.After for _, direction := range []storj.ListDirection{ - // storj.Before, - // storj.Backward, // storj.Forward, storj.After, } { @@ -334,311 +332,80 @@ func TestListObjects(t *testing.T) { result []string }{ { - options: options("", "", storj.After, 0), + options: options("", "", 0), result: []string{"a", "a/", "aa", "b", "b/", "bb", "c"}, }, { - options: options("", "`", storj.After, 0), + options: options("", "`", 0), result: []string{"a", "a/", "aa", "b", "b/", "bb", "c"}, }, { - options: options("", "b", storj.After, 0), + options: options("", "b", 0), result: []string{"b/", "bb", "c"}, }, { - options: options("", "c", storj.After, 0), + options: options("", "c", 0), result: []string{}, }, { - options: options("", "ca", storj.After, 0), + options: options("", "ca", 0), result: []string{}, }, { - options: options("", "", storj.After, 1), + options: options("", "", 1), more: true, result: []string{"a"}, }, { - options: options("", "`", storj.After, 1), + options: options("", "`", 1), more: true, result: []string{"a"}, }, { - options: options("", "aa", storj.After, 1), + options: options("", "aa", 1), more: true, result: []string{"b"}, }, { - options: options("", "c", storj.After, 1), + options: options("", "c", 1), result: []string{}, }, { - options: options("", "ca", storj.After, 1), + options: options("", "ca", 1), result: []string{}, }, { - options: options("", "", storj.After, 2), + options: options("", "", 2), more: true, result: []string{"a", "a/"}, }, { - options: options("", "`", storj.After, 2), + options: options("", "`", 2), more: true, result: []string{"a", "a/"}, }, { - options: options("", "aa", storj.After, 2), + options: options("", "aa", 2), more: true, result: []string{"b", "b/"}, }, { - options: options("", "bb", storj.After, 2), + options: options("", "bb", 2), result: []string{"c"}, }, { - options: options("", "c", storj.After, 2), + options: options("", "c", 2), result: []string{}, }, { - options: options("", "ca", storj.After, 2), + options: options("", "ca", 2), result: []string{}, }, { - options: optionsRecursive("", "", storj.After, 0), + options: optionsRecursive("", "", 0), result: []string{"a", "a/xa", "a/xaa", "a/xb", "a/xbb", "a/xc", "aa", "b", "b/ya", "b/yaa", "b/yb", "b/ybb", "b/yc", "bb", "c"}, }, { - options: options("a", "", storj.After, 0), + options: options("a", "", 0), result: []string{"xa", "xaa", "xb", "xbb", "xc"}, }, { - options: options("a/", "", storj.After, 0), + options: options("a/", "", 0), result: []string{"xa", "xaa", "xb", "xbb", "xc"}, }, { - options: options("a/", "xb", storj.After, 0), + options: options("a/", "xb", 0), result: []string{"xbb", "xc"}, }, { - options: optionsRecursive("", "a/xbb", storj.After, 5), + options: optionsRecursive("", "a/xbb", 5), more: true, result: []string{"a/xc", "aa", "b", "b/ya", "b/yaa"}, }, { - options: options("a/", "xaa", storj.After, 2), + options: options("a/", "xaa", 2), more: true, result: []string{"xb", "xbb"}, }, - // TODO commented until we will decide if we will support direction for object listing - // - // { - // options: options("", "", storj.Forward, 0), - // result: []string{"a", "a/", "aa", "b", "b/", "bb", "c"}, - // }, { - // options: options("", "`", storj.Forward, 0), - // result: []string{"a", "a/", "aa", "b", "b/", "bb", "c"}, - // }, { - // options: options("", "b", storj.Forward, 0), - // result: []string{"b", "b/", "bb", "c"}, - // }, { - // options: options("", "c", storj.Forward, 0), - // result: []string{"c"}, - // }, { - // options: options("", "ca", storj.Forward, 0), - // result: []string{}, - // }, { - // options: options("", "", storj.Forward, 1), - // more: true, - // result: []string{"a"}, - // }, { - // options: options("", "`", storj.Forward, 1), - // more: true, - // result: []string{"a"}, - // }, { - // options: options("", "aa", storj.Forward, 1), - // more: true, - // result: []string{"aa"}, - // }, { - // options: options("", "c", storj.Forward, 1), - // result: []string{"c"}, - // }, { - // options: options("", "ca", storj.Forward, 1), - // result: []string{}, - // }, { - // options: options("", "", storj.Forward, 2), - // more: true, - // result: []string{"a", "a/"}, - // }, { - // options: options("", "`", storj.Forward, 2), - // more: true, - // result: []string{"a", "a/"}, - // }, { - // options: options("", "aa", storj.Forward, 2), - // more: true, - // result: []string{"aa", "b"}, - // }, { - // options: options("", "bb", storj.Forward, 2), - // result: []string{"bb", "c"}, - // }, { - // options: options("", "c", storj.Forward, 2), - // result: []string{"c"}, - // }, { - // options: options("", "ca", storj.Forward, 2), - // result: []string{}, - // }, { - // options: optionsRecursive("", "", storj.Forward, 0), - // result: []string{"a", "a/xa", "a/xaa", "a/xb", "a/xbb", "a/xc", "aa", "b", "b/ya", "b/yaa", "b/yb", "b/ybb", "b/yc", "bb", "c"}, - // }, { - // options: options("a", "", storj.Forward, 0), - // result: []string{"xa", "xaa", "xb", "xbb", "xc"}, - // }, { - // options: options("a/", "", storj.Forward, 0), - // result: []string{"xa", "xaa", "xb", "xbb", "xc"}, - // }, { - // options: options("a/", "xb", storj.Forward, 0), - // result: []string{"xb", "xbb", "xc"}, - // }, { - // options: optionsRecursive("", "a/xbb", storj.Forward, 5), - // more: true, - // result: []string{"a/xbb", "a/xc", "aa", "b", "b/ya"}, - // }, { - // options: options("a/", "xaa", storj.Forward, 2), - // more: true, - // result: []string{"xaa", "xb"}, - // }, { - // options: options("", "", storj.Backward, 0), - // result: []string{"a", "a/", "aa", "b", "b/", "bb", "c"}, - // }, { - // options: options("", "`", storj.Backward, 0), - // result: []string{}, - // }, { - // options: options("", "b", storj.Backward, 0), - // result: []string{"a", "a/", "aa", "b"}, - // }, { - // options: options("", "c", storj.Backward, 0), - // result: []string{"a", "a/", "aa", "b", "b/", "bb", "c"}, - // }, { - // options: options("", "ca", storj.Backward, 0), - // result: []string{"a", "a/", "aa", "b", "b/", "bb", "c"}, - // }, { - // options: options("", "", storj.Backward, 1), - // more: true, - // result: []string{"c"}, - // }, { - // options: options("", "`", storj.Backward, 1), - // result: []string{}, - // }, { - // options: options("", "aa", storj.Backward, 1), - // more: true, - // result: []string{"aa"}, - // }, { - // options: options("", "c", storj.Backward, 1), - // more: true, - // result: []string{"c"}, - // }, { - // options: options("", "ca", storj.Backward, 1), - // more: true, - // result: []string{"c"}, - // }, { - // options: options("", "", storj.Backward, 2), - // more: true, - // result: []string{"bb", "c"}, - // }, { - // options: options("", "`", storj.Backward, 2), - // result: []string{}, - // }, { - // options: options("", "a/", storj.Backward, 2), - // result: []string{"a"}, - // }, { - // options: options("", "bb", storj.Backward, 2), - // more: true, - // result: []string{"b/", "bb"}, - // }, { - // options: options("", "c", storj.Backward, 2), - // more: true, - // result: []string{"bb", "c"}, - // }, { - // options: options("", "ca", storj.Backward, 2), - // more: true, - // result: []string{"bb", "c"}, - // }, { - // options: optionsRecursive("", "", storj.Backward, 0), - // result: []string{"a", "a/xa", "a/xaa", "a/xb", "a/xbb", "a/xc", "aa", "b", "b/ya", "b/yaa", "b/yb", "b/ybb", "b/yc", "bb", "c"}, - // }, { - // options: options("a", "", storj.Backward, 0), - // result: []string{"xa", "xaa", "xb", "xbb", "xc"}, - // }, { - // options: options("a/", "", storj.Backward, 0), - // result: []string{"xa", "xaa", "xb", "xbb", "xc"}, - // }, { - // options: options("a/", "xb", storj.Backward, 0), - // result: []string{"xa", "xaa", "xb"}, - // }, { - // options: optionsRecursive("", "b/yaa", storj.Backward, 5), - // more: true, - // result: []string{"a/xc", "aa", "b", "b/ya", "b/yaa"}, - // }, { - // options: options("a/", "xbb", storj.Backward, 2), - // more: true, - // result: []string{"xb", "xbb"}, - // }, { - // options: options("", "", storj.Before, 0), - // result: []string{"a", "a/", "aa", "b", "b/", "bb", "c"}, - // }, { - // options: options("", "`", storj.Before, 0), - // result: []string{}, - // }, { - // options: options("", "a", storj.Before, 0), - // result: []string{}, - // }, { - // options: options("", "b", storj.Before, 0), - // result: []string{"a", "a/", "aa"}, - // }, { - // options: options("", "c", storj.Before, 0), - // result: []string{"a", "a/", "aa", "b", "b/", "bb"}, - // }, { - // options: options("", "ca", storj.Before, 0), - // result: []string{"a", "a/", "aa", "b", "b/", "bb", "c"}, - // }, { - // options: options("", "", storj.Before, 1), - // more: true, - // result: []string{"c"}, - // }, { - // options: options("", "`", storj.Before, 1), - // result: []string{}, - // }, { - // options: options("", "a/", storj.Before, 1), - // result: []string{"a"}, - // }, { - // options: options("", "c", storj.Before, 1), - // more: true, - // result: []string{"bb"}, - // }, { - // options: options("", "ca", storj.Before, 1), - // more: true, - // result: []string{"c"}, - // }, { - // options: options("", "", storj.Before, 2), - // more: true, - // result: []string{"bb", "c"}, - // }, { - // options: options("", "`", storj.Before, 2), - // result: []string{}, - // }, { - // options: options("", "a/", storj.Before, 2), - // result: []string{"a"}, - // }, { - // options: options("", "bb", storj.Before, 2), - // more: true, - // result: []string{"b", "b/"}, - // }, { - // options: options("", "c", storj.Before, 2), - // more: true, - // result: []string{"b/", "bb"}, - // }, { - // options: options("", "ca", storj.Before, 2), - // more: true, - // result: []string{"bb", "c"}, - // }, { - // options: optionsRecursive("", "", storj.Before, 0), - // result: []string{"a", "a/xa", "a/xaa", "a/xb", "a/xbb", "a/xc", "aa", "b", "b/ya", "b/yaa", "b/yb", "b/ybb", "b/yc", "bb", "c"}, - // }, { - // options: options("a", "", storj.Before, 0), - // result: []string{"xa", "xaa", "xb", "xbb", "xc"}, - // }, { - // options: options("a/", "", storj.Before, 0), - // result: []string{"xa", "xaa", "xb", "xbb", "xc"}, - // }, { - // options: options("a/", "xb", storj.Before, 0), - // result: []string{"xa", "xaa"}, - // }, { - // options: optionsRecursive("", "b/yaa", storj.Before, 5), - // more: true, - // result: []string{"a/xbb", "a/xc", "aa", "b", "b/ya"}, - // }, { - // options: options("a/", "xbb", storj.Before, 2), - // more: true, - // result: []string{"xaa", "xb"}, - // }, } { errTag := fmt.Sprintf("%d. %+v", i, tt) @@ -655,20 +422,20 @@ func TestListObjects(t *testing.T) { } }) } -func options(prefix, cursor string, direction storj.ListDirection, limit int) storj.ListOptions { +func options(prefix, cursor string, limit int) storj.ListOptions { return storj.ListOptions{ Prefix: prefix, Cursor: cursor, - Direction: direction, + Direction: storj.After, Limit: limit, } } -func optionsRecursive(prefix, cursor string, direction storj.ListDirection, limit int) storj.ListOptions { +func optionsRecursive(prefix, cursor string, limit int) storj.ListOptions { return storj.ListOptions{ Prefix: prefix, Cursor: cursor, - Direction: direction, + Direction: storj.After, Limit: limit, Recursive: true, } diff --git a/uplink/metainfo/kvmetainfo/prefixed.go b/uplink/metainfo/kvmetainfo/prefixed.go index f4861a3a6..caacc69cb 100644 --- a/uplink/metainfo/kvmetainfo/prefixed.go +++ b/uplink/metainfo/kvmetainfo/prefixed.go @@ -59,8 +59,8 @@ func (o *prefixedObjStore) Delete(ctx context.Context, path storj.Path) (err err return o.store.Delete(ctx, storj.JoinPaths(o.prefix, path)) } -func (o *prefixedObjStore) List(ctx context.Context, prefix, startAfter, endBefore storj.Path, recursive bool, limit int, metaFlags uint32) (items []objects.ListItem, more bool, err error) { +func (o *prefixedObjStore) List(ctx context.Context, prefix, startAfter storj.Path, recursive bool, limit int, metaFlags uint32) (items []objects.ListItem, more bool, err error) { defer mon.Task()(&ctx)(&err) - return o.store.List(ctx, storj.JoinPaths(o.prefix, prefix), startAfter, endBefore, recursive, limit, metaFlags) + return o.store.List(ctx, storj.JoinPaths(o.prefix, prefix), startAfter, recursive, limit, metaFlags) } diff --git a/uplink/storage/objects/store.go b/uplink/storage/objects/store.go index 83c697759..79a928cc8 100644 --- a/uplink/storage/objects/store.go +++ b/uplink/storage/objects/store.go @@ -43,7 +43,7 @@ type Store interface { Get(ctx context.Context, path storj.Path) (rr ranger.Ranger, meta Meta, err error) Put(ctx context.Context, path storj.Path, data io.Reader, metadata pb.SerializableMeta, expiration time.Time) (meta Meta, err error) Delete(ctx context.Context, path storj.Path) (err error) - List(ctx context.Context, prefix, startAfter, endBefore storj.Path, recursive bool, limit int, metaFlags uint32) (items []ListItem, more bool, err error) + List(ctx context.Context, prefix, startAfter storj.Path, recursive bool, limit int, metaFlags uint32) (items []ListItem, more bool, err error) } type objStore struct { @@ -123,11 +123,11 @@ func (o *objStore) Delete(ctx context.Context, path storj.Path) (err error) { return err } -func (o *objStore) List(ctx context.Context, prefix, startAfter, endBefore storj.Path, recursive bool, limit int, metaFlags uint32) ( +func (o *objStore) List(ctx context.Context, prefix, startAfter storj.Path, recursive bool, limit int, metaFlags uint32) ( items []ListItem, more bool, err error) { defer mon.Task()(&ctx)(&err) - strItems, more, err := o.store.List(ctx, prefix, startAfter, endBefore, o.pathCipher, recursive, limit, metaFlags) + strItems, more, err := o.store.List(ctx, prefix, startAfter, o.pathCipher, recursive, limit, metaFlags) if err != nil { return nil, false, err } diff --git a/uplink/storage/streams/shim.go b/uplink/storage/streams/shim.go index 668794e49..c2b784005 100644 --- a/uplink/storage/streams/shim.go +++ b/uplink/storage/streams/shim.go @@ -21,7 +21,7 @@ type Store interface { Get(ctx context.Context, path storj.Path, pathCipher storj.CipherSuite) (ranger.Ranger, Meta, error) Put(ctx context.Context, path storj.Path, pathCipher storj.CipherSuite, data io.Reader, metadata []byte, expiration time.Time) (Meta, error) Delete(ctx context.Context, path storj.Path, pathCipher storj.CipherSuite) error - List(ctx context.Context, prefix, startAfter, endBefore storj.Path, pathCipher storj.CipherSuite, recursive bool, limit int, metaFlags uint32) (items []ListItem, more bool, err error) + List(ctx context.Context, prefix, startAfter storj.Path, pathCipher storj.CipherSuite, recursive bool, limit int, metaFlags uint32) (items []ListItem, more bool, err error) } type shimStore struct { @@ -66,8 +66,8 @@ func (s *shimStore) Delete(ctx context.Context, path storj.Path, pathCipher stor } // List parses the passed in path and dispatches to the typed store. -func (s *shimStore) List(ctx context.Context, prefix storj.Path, startAfter storj.Path, endBefore storj.Path, pathCipher storj.CipherSuite, recursive bool, limit int, metaFlags uint32) (items []ListItem, more bool, err error) { +func (s *shimStore) List(ctx context.Context, prefix storj.Path, startAfter storj.Path, pathCipher storj.CipherSuite, recursive bool, limit int, metaFlags uint32) (items []ListItem, more bool, err error) { defer mon.Task()(&ctx)(&err) - return s.store.List(ctx, ParsePath(prefix), startAfter, endBefore, pathCipher, recursive, limit, metaFlags) + return s.store.List(ctx, ParsePath(prefix), startAfter, pathCipher, recursive, limit, metaFlags) } diff --git a/uplink/storage/streams/store.go b/uplink/storage/streams/store.go index f67793a91..938d8a1c5 100644 --- a/uplink/storage/streams/store.go +++ b/uplink/storage/streams/store.go @@ -59,7 +59,7 @@ type typedStore interface { Get(ctx context.Context, path Path, pathCipher storj.CipherSuite) (ranger.Ranger, Meta, error) Put(ctx context.Context, path Path, pathCipher storj.CipherSuite, data io.Reader, metadata []byte, expiration time.Time) (Meta, error) Delete(ctx context.Context, path Path, pathCipher storj.CipherSuite) error - List(ctx context.Context, prefix Path, startAfter, endBefore string, pathCipher storj.CipherSuite, recursive bool, limit int, metaFlags uint32) (items []ListItem, more bool, err error) + List(ctx context.Context, prefix Path, startAfter string, pathCipher storj.CipherSuite, recursive bool, limit int, metaFlags uint32) (items []ListItem, more bool, err error) } // streamStore is a store for streams. It implements typedStore as part of an ongoing migration @@ -582,7 +582,7 @@ func pathForKey(raw string) paths.Unencrypted { } // List all the paths inside l/, stripping off the l/ prefix -func (s *streamStore) List(ctx context.Context, prefix Path, startAfter, endBefore string, pathCipher storj.CipherSuite, recursive bool, limit int, metaFlags uint32) (items []ListItem, more bool, err error) { +func (s *streamStore) List(ctx context.Context, prefix Path, startAfter string, pathCipher storj.CipherSuite, recursive bool, limit int, metaFlags uint32) (items []ListItem, more bool, err error) { defer mon.Task()(&ctx)(&err) // TODO use flags with listing @@ -611,9 +611,9 @@ func (s *streamStore) List(ctx context.Context, prefix Path, startAfter, endBefo encPrefix = paths.NewEncrypted(encPrefix.Raw()[:lastSlashIdx]) } - // We have to encrypt startAfter and endBefore but only if they don't contain a bucket. - // They contain a bucket if and only if the prefix has no bucket. This is why they are raw - // strings instead of a typed string: it's either a bucket or an unencrypted path component + // We have to encrypt startAfter but only if it doesn't contain a bucket. + // It contains a bucket if and only if the prefix has no bucket. This is why it is a raw + // string instead of a typed string: it's either a bucket or an unencrypted path component // and that isn't known at compile time. needsEncryption := prefix.Bucket() != "" if needsEncryption { diff --git a/uplink/storage/streams/store_test.go b/uplink/storage/streams/store_test.go index 517fda20b..c8fc559a5 100644 --- a/uplink/storage/streams/store_test.go +++ b/uplink/storage/streams/store_test.go @@ -132,7 +132,7 @@ func TestStreamsInterruptedDelete(t *testing.T) { require.NoError(t, err) // Ensure the item shows when we list - listItems, _, err := streamStore.List(ctx, bucketName, "", "", storj.EncNull, true, 10, meta.None) + listItems, _, err := streamStore.List(ctx, bucketName, "", storj.EncNull, true, 10, meta.None) require.NoError(t, err) require.True(t, len(listItems) == 1) @@ -158,7 +158,7 @@ func TestStreamsInterruptedDelete(t *testing.T) { // It should *still* show when we list, as we've only deleted one // segment - listItems, _, err = streamStore.List(ctx, bucketName, "", "", storj.EncNull, true, 10, meta.None) + listItems, _, err = streamStore.List(ctx, bucketName, "", storj.EncNull, true, 10, meta.None) require.NoError(t, err) require.True(t, len(listItems) == 1) @@ -168,7 +168,7 @@ func TestStreamsInterruptedDelete(t *testing.T) { _ = streamStore.Delete(ctx, fullPath, storj.EncNull) // Now it should have 0 list items - listItems, _, err = streamStore.List(ctx, bucketName, "", "", storj.EncNull, true, 10, meta.None) + listItems, _, err = streamStore.List(ctx, bucketName, "", storj.EncNull, true, 10, meta.None) require.NoError(t, err) require.True(t, len(listItems) == 0) }) @@ -203,39 +203,39 @@ func TestStreamStoreList(t *testing.T) { prefix := bucketName // should list all - items, more, err := streamStore.List(ctx, prefix, "", "", storj.EncNull, true, 10, meta.None) + items, more, err := streamStore.List(ctx, prefix, "", storj.EncNull, true, 10, meta.None) require.NoError(t, err) require.False(t, more) require.Equal(t, len(objects), len(items)) // should list first two and more = true - items, more, err = streamStore.List(ctx, prefix, "", "", storj.EncNull, true, 2, meta.None) + items, more, err = streamStore.List(ctx, prefix, "", storj.EncNull, true, 2, meta.None) require.NoError(t, err) require.True(t, more) require.Equal(t, 2, len(items)) // should list only prefixes - items, more, err = streamStore.List(ctx, prefix, "", "", storj.EncNull, false, 10, meta.None) + items, more, err = streamStore.List(ctx, prefix, "", storj.EncNull, false, 10, meta.None) require.NoError(t, err) require.False(t, more) require.Equal(t, 2, len(items)) // should list only BBBB bucket prefix = storj.JoinPaths(bucketName, "bbbb") - items, more, err = streamStore.List(ctx, prefix, "", "", storj.EncNull, false, 10, meta.None) + items, more, err = streamStore.List(ctx, prefix, "", storj.EncNull, false, 10, meta.None) require.NoError(t, err) require.False(t, more) require.Equal(t, 3, len(items)) // should list only BBBB bucket after afile - items, more, err = streamStore.List(ctx, prefix, "afile1", "", storj.EncNull, false, 10, meta.None) + items, more, err = streamStore.List(ctx, prefix, "afile1", storj.EncNull, false, 10, meta.None) require.NoError(t, err) require.False(t, more) require.Equal(t, 2, len(items)) // should list nothing prefix = storj.JoinPaths(bucketName, "cccc") - items, more, err = streamStore.List(ctx, prefix, "", "", storj.EncNull, true, 10, meta.None) + items, more, err = streamStore.List(ctx, prefix, "", storj.EncNull, true, 10, meta.None) require.NoError(t, err) require.False(t, more) require.Equal(t, 0, len(items))