From 22f9d46b3fc30a322e72c59edc521d65041b9597 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Mon, 2 Nov 2020 15:17:33 +0000 Subject: [PATCH 1/3] Add a FetchRemoteWithStatus streaming RPC Repository mirroring is interested in the list of new tags; having Gitaly report that directly will allow us to eliminate two FetchAllTags RPC calls per repository mirroring operation. This commit adds the new RPC to the proto only. --- .../unreleased/fetch-remote-with-status.yml | 5 ++++ proto/repository-service.proto | 28 +++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 changelogs/unreleased/fetch-remote-with-status.yml diff --git a/changelogs/unreleased/fetch-remote-with-status.yml b/changelogs/unreleased/fetch-remote-with-status.yml new file mode 100644 index 00000000000..3b8dba86659 --- /dev/null +++ b/changelogs/unreleased/fetch-remote-with-status.yml @@ -0,0 +1,5 @@ +--- +title: Add ref status updates to the FetchRemote RPC +merge_request: 2739 +author: +type: changed diff --git a/proto/repository-service.proto b/proto/repository-service.proto index 24c3ea7fa0c..dff68d4f118 100644 --- a/proto/repository-service.proto +++ b/proto/repository-service.proto @@ -219,6 +219,11 @@ service RepositoryService { op: MUTATOR }; } + rpc FetchRemoteWithStatus(FetchRemoteRequest) returns (stream FetchRemoteWithStatusResponse) { + option(op_type) = { + op: MUTATOR + }; + } } message RepositoryExistsRequest { @@ -646,3 +651,26 @@ message OptimizeRepositoryRequest { } message OptimizeRepositoryResponse{} + +message FetchRemoteWithStatusResponse { + // Per `git fetch` manpage, OUTPUT section + enum UpdateType { + FAST_FORWARD_UPDATE = 0; // ' ' + FORCED_UPDATE = 1; // '+' + PRUNED = 2; // '-' + TAG_UPDATE = 3; // 't' + FETCHED = 4; // '*' + UPDATE_FAILED = 5; // '!' + UNCHANGED = 6; // '=' + } + + message Update { + UpdateType update_type = 1; + string summary = 2; + string from_ref = 3; + string to_ref = 4; + string reason = 5; + } + + repeated Update ref_updates = 1; +} -- GitLab From 08dc6b04bd1fe8a9c96432f6993453660a63e277 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 3 Nov 2020 14:24:16 +0000 Subject: [PATCH 2/3] Autogenerated proto changes --- proto/go/gitalypb/repository-service.pb.go | 617 ++++++++++++------ ruby/proto/gitaly/repository-service_pb.rb | 22 + .../gitaly/repository-service_services_pb.rb | 1 + 3 files changed, 447 insertions(+), 193 deletions(-) diff --git a/proto/go/gitalypb/repository-service.pb.go b/proto/go/gitalypb/repository-service.pb.go index 02f3a323b69..536e6e36c0c 100644 --- a/proto/go/gitalypb/repository-service.pb.go +++ b/proto/go/gitalypb/repository-service.pb.go @@ -95,6 +95,47 @@ func (GetRawChangesResponse_RawChange_Operation) EnumDescriptor() ([]byte, []int return fileDescriptor_e9b1768cf174c79b, []int{65, 0, 0} } +// Per `git fetch` manpage, OUTPUT section +type FetchRemoteWithStatusResponse_UpdateType int32 + +const ( + FetchRemoteWithStatusResponse_FAST_FORWARD_UPDATE FetchRemoteWithStatusResponse_UpdateType = 0 + FetchRemoteWithStatusResponse_FORCED_UPDATE FetchRemoteWithStatusResponse_UpdateType = 1 + FetchRemoteWithStatusResponse_PRUNED FetchRemoteWithStatusResponse_UpdateType = 2 + FetchRemoteWithStatusResponse_TAG_UPDATE FetchRemoteWithStatusResponse_UpdateType = 3 + FetchRemoteWithStatusResponse_FETCHED FetchRemoteWithStatusResponse_UpdateType = 4 + FetchRemoteWithStatusResponse_UPDATE_FAILED FetchRemoteWithStatusResponse_UpdateType = 5 + FetchRemoteWithStatusResponse_UNCHANGED FetchRemoteWithStatusResponse_UpdateType = 6 +) + +var FetchRemoteWithStatusResponse_UpdateType_name = map[int32]string{ + 0: "FAST_FORWARD_UPDATE", + 1: "FORCED_UPDATE", + 2: "PRUNED", + 3: "TAG_UPDATE", + 4: "FETCHED", + 5: "UPDATE_FAILED", + 6: "UNCHANGED", +} + +var FetchRemoteWithStatusResponse_UpdateType_value = map[string]int32{ + "FAST_FORWARD_UPDATE": 0, + "FORCED_UPDATE": 1, + "PRUNED": 2, + "TAG_UPDATE": 3, + "FETCHED": 4, + "UPDATE_FAILED": 5, + "UNCHANGED": 6, +} + +func (x FetchRemoteWithStatusResponse_UpdateType) String() string { + return proto.EnumName(FetchRemoteWithStatusResponse_UpdateType_name, int32(x)) +} + +func (FetchRemoteWithStatusResponse_UpdateType) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_e9b1768cf174c79b, []int{85, 0} +} + type RepositoryExistsRequest struct { Repository *Repository `protobuf:"bytes,1,opt,name=repository,proto3" json:"repository,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -3914,9 +3955,120 @@ func (m *OptimizeRepositoryResponse) XXX_DiscardUnknown() { var xxx_messageInfo_OptimizeRepositoryResponse proto.InternalMessageInfo +type FetchRemoteWithStatusResponse struct { + RefUpdates []*FetchRemoteWithStatusResponse_Update `protobuf:"bytes,1,rep,name=ref_updates,json=refUpdates,proto3" json:"ref_updates,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FetchRemoteWithStatusResponse) Reset() { *m = FetchRemoteWithStatusResponse{} } +func (m *FetchRemoteWithStatusResponse) String() string { return proto.CompactTextString(m) } +func (*FetchRemoteWithStatusResponse) ProtoMessage() {} +func (*FetchRemoteWithStatusResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_e9b1768cf174c79b, []int{85} +} + +func (m *FetchRemoteWithStatusResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FetchRemoteWithStatusResponse.Unmarshal(m, b) +} +func (m *FetchRemoteWithStatusResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FetchRemoteWithStatusResponse.Marshal(b, m, deterministic) +} +func (m *FetchRemoteWithStatusResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_FetchRemoteWithStatusResponse.Merge(m, src) +} +func (m *FetchRemoteWithStatusResponse) XXX_Size() int { + return xxx_messageInfo_FetchRemoteWithStatusResponse.Size(m) +} +func (m *FetchRemoteWithStatusResponse) XXX_DiscardUnknown() { + xxx_messageInfo_FetchRemoteWithStatusResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_FetchRemoteWithStatusResponse proto.InternalMessageInfo + +func (m *FetchRemoteWithStatusResponse) GetRefUpdates() []*FetchRemoteWithStatusResponse_Update { + if m != nil { + return m.RefUpdates + } + return nil +} + +type FetchRemoteWithStatusResponse_Update struct { + UpdateType FetchRemoteWithStatusResponse_UpdateType `protobuf:"varint,1,opt,name=update_type,json=updateType,proto3,enum=gitaly.FetchRemoteWithStatusResponse_UpdateType" json:"update_type,omitempty"` + Summary string `protobuf:"bytes,2,opt,name=summary,proto3" json:"summary,omitempty"` + FromRef string `protobuf:"bytes,3,opt,name=from_ref,json=fromRef,proto3" json:"from_ref,omitempty"` + ToRef string `protobuf:"bytes,4,opt,name=to_ref,json=toRef,proto3" json:"to_ref,omitempty"` + Reason string `protobuf:"bytes,5,opt,name=reason,proto3" json:"reason,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *FetchRemoteWithStatusResponse_Update) Reset() { *m = FetchRemoteWithStatusResponse_Update{} } +func (m *FetchRemoteWithStatusResponse_Update) String() string { return proto.CompactTextString(m) } +func (*FetchRemoteWithStatusResponse_Update) ProtoMessage() {} +func (*FetchRemoteWithStatusResponse_Update) Descriptor() ([]byte, []int) { + return fileDescriptor_e9b1768cf174c79b, []int{85, 0} +} + +func (m *FetchRemoteWithStatusResponse_Update) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_FetchRemoteWithStatusResponse_Update.Unmarshal(m, b) +} +func (m *FetchRemoteWithStatusResponse_Update) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_FetchRemoteWithStatusResponse_Update.Marshal(b, m, deterministic) +} +func (m *FetchRemoteWithStatusResponse_Update) XXX_Merge(src proto.Message) { + xxx_messageInfo_FetchRemoteWithStatusResponse_Update.Merge(m, src) +} +func (m *FetchRemoteWithStatusResponse_Update) XXX_Size() int { + return xxx_messageInfo_FetchRemoteWithStatusResponse_Update.Size(m) +} +func (m *FetchRemoteWithStatusResponse_Update) XXX_DiscardUnknown() { + xxx_messageInfo_FetchRemoteWithStatusResponse_Update.DiscardUnknown(m) +} + +var xxx_messageInfo_FetchRemoteWithStatusResponse_Update proto.InternalMessageInfo + +func (m *FetchRemoteWithStatusResponse_Update) GetUpdateType() FetchRemoteWithStatusResponse_UpdateType { + if m != nil { + return m.UpdateType + } + return FetchRemoteWithStatusResponse_FAST_FORWARD_UPDATE +} + +func (m *FetchRemoteWithStatusResponse_Update) GetSummary() string { + if m != nil { + return m.Summary + } + return "" +} + +func (m *FetchRemoteWithStatusResponse_Update) GetFromRef() string { + if m != nil { + return m.FromRef + } + return "" +} + +func (m *FetchRemoteWithStatusResponse_Update) GetToRef() string { + if m != nil { + return m.ToRef + } + return "" +} + +func (m *FetchRemoteWithStatusResponse_Update) GetReason() string { + if m != nil { + return m.Reason + } + return "" +} + func init() { proto.RegisterEnum("gitaly.GetArchiveRequest_Format", GetArchiveRequest_Format_name, GetArchiveRequest_Format_value) proto.RegisterEnum("gitaly.GetRawChangesResponse_RawChange_Operation", GetRawChangesResponse_RawChange_Operation_name, GetRawChangesResponse_RawChange_Operation_value) + proto.RegisterEnum("gitaly.FetchRemoteWithStatusResponse_UpdateType", FetchRemoteWithStatusResponse_UpdateType_name, FetchRemoteWithStatusResponse_UpdateType_value) proto.RegisterType((*RepositoryExistsRequest)(nil), "gitaly.RepositoryExistsRequest") proto.RegisterType((*RepositoryExistsResponse)(nil), "gitaly.RepositoryExistsResponse") proto.RegisterType((*RepackIncrementalRequest)(nil), "gitaly.RepackIncrementalRequest") @@ -4004,204 +4156,220 @@ func init() { proto.RegisterType((*ReplicateRepositoryResponse)(nil), "gitaly.ReplicateRepositoryResponse") proto.RegisterType((*OptimizeRepositoryRequest)(nil), "gitaly.OptimizeRepositoryRequest") proto.RegisterType((*OptimizeRepositoryResponse)(nil), "gitaly.OptimizeRepositoryResponse") + proto.RegisterType((*FetchRemoteWithStatusResponse)(nil), "gitaly.FetchRemoteWithStatusResponse") + proto.RegisterType((*FetchRemoteWithStatusResponse_Update)(nil), "gitaly.FetchRemoteWithStatusResponse.Update") } func init() { proto.RegisterFile("repository-service.proto", fileDescriptor_e9b1768cf174c79b) } var fileDescriptor_e9b1768cf174c79b = []byte{ - // 3057 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x5a, 0x5b, 0x6f, 0xdc, 0xc6, - 0xf5, 0xf7, 0xea, 0xb6, 0xbb, 0x47, 0x6b, 0x7b, 0x35, 0x92, 0xad, 0x15, 0x2d, 0xf9, 0x42, 0x3b, - 0x8e, 0xe3, 0x38, 0x72, 0x62, 0xff, 0x81, 0x7f, 0xda, 0xa2, 0x28, 0xb4, 0xba, 0xdb, 0xd6, 0x25, - 0x94, 0xdc, 0x20, 0x06, 0x02, 0x86, 0xcb, 0x9d, 0xd5, 0xb2, 0xe2, 0x72, 0xd6, 0xc3, 0x59, 0xcb, - 0x0a, 0xd0, 0x87, 0x16, 0xe8, 0x5b, 0x11, 0xa0, 0x40, 0xd1, 0xf4, 0xb1, 0xcf, 0xfd, 0x04, 0x7d, - 0x29, 0x8a, 0xbe, 0xf4, 0x3b, 0x04, 0xfd, 0x06, 0xfd, 0x08, 0x7d, 0x2a, 0xe6, 0x42, 0x0e, 0xb9, - 0x24, 0x37, 0x2e, 0xb4, 0x48, 0xdf, 0x38, 0x67, 0x66, 0xce, 0x39, 0x73, 0xe6, 0x9c, 0x99, 0x39, - 0xbf, 0x43, 0x68, 0x50, 0xdc, 0x27, 0xa1, 0xc7, 0x08, 0x3d, 0xff, 0x28, 0xc4, 0xf4, 0x8d, 0xe7, - 0xe2, 0xd5, 0x3e, 0x25, 0x8c, 0xa0, 0x99, 0x13, 0x8f, 0x39, 0xfe, 0xb9, 0x01, 0xbe, 0x17, 0x30, - 0x49, 0x33, 0x6a, 0x61, 0xd7, 0xa1, 0xb8, 0x2d, 0x5b, 0xe6, 0x11, 0x2c, 0x5a, 0xf1, 0xec, 0xcd, - 0xb7, 0x5e, 0xc8, 0x42, 0x0b, 0xbf, 0x1e, 0xe0, 0x90, 0xa1, 0x4f, 0x01, 0x34, 0xe3, 0x46, 0xe9, - 0x76, 0xe9, 0xc1, 0xec, 0x13, 0xb4, 0x2a, 0x39, 0xae, 0xea, 0x49, 0xcd, 0xa9, 0x3f, 0xfe, 0xe3, - 0x51, 0xc9, 0x4a, 0x8c, 0x35, 0x9f, 0x40, 0x23, 0xcb, 0x34, 0xec, 0x93, 0x20, 0xc4, 0xe8, 0x3a, - 0xcc, 0x60, 0x41, 0x11, 0x1c, 0x2b, 0x96, 0x6a, 0x99, 0xc7, 0x62, 0x8e, 0xe3, 0x9e, 0xee, 0x06, - 0x2e, 0xc5, 0x3d, 0x1c, 0x30, 0xc7, 0xbf, 0xb8, 0x26, 0x37, 0x60, 0x29, 0x87, 0xab, 0x54, 0xc5, - 0xa4, 0x30, 0x27, 0x3b, 0xb7, 0x06, 0xfe, 0xc5, 0x65, 0xa1, 0xbb, 0x70, 0xd9, 0xa5, 0xd8, 0x61, - 0xd8, 0x6e, 0x79, 0xac, 0xe7, 0xf4, 0x1b, 0x13, 0x62, 0x81, 0x35, 0x49, 0x6c, 0x0a, 0x9a, 0xb9, - 0x00, 0x28, 0x29, 0x53, 0x69, 0xb2, 0x07, 0x73, 0x7b, 0x5e, 0xfb, 0xad, 0xec, 0xb9, 0xf8, 0xaa, - 0x17, 0x00, 0x25, 0xd9, 0x29, 0x21, 0xbf, 0x2d, 0xc1, 0xb5, 0x6d, 0x87, 0xb6, 0x9c, 0x13, 0xbc, - 0x4e, 0x7c, 0x1f, 0xbb, 0xec, 0x87, 0x59, 0x33, 0x5a, 0x80, 0xe9, 0x3e, 0x1d, 0x04, 0xb8, 0x31, - 0x29, 0x3a, 0x65, 0xc3, 0x6c, 0xc0, 0xf5, 0x61, 0x6d, 0x94, 0xa2, 0x47, 0xb0, 0xf8, 0x39, 0xf5, - 0x18, 0x5e, 0x27, 0xbd, 0x9e, 0xc7, 0xb6, 0xa9, 0xd3, 0xef, 0x5e, 0xdc, 0x26, 0x06, 0x34, 0xb2, - 0x4c, 0x95, 0xc0, 0x67, 0x70, 0x65, 0xdd, 0xc7, 0x4e, 0x30, 0xe8, 0x5f, 0x5c, 0xce, 0x1c, 0x5c, - 0x8d, 0x79, 0x29, 0xf6, 0x9f, 0xc1, 0x35, 0x3d, 0xe5, 0xc8, 0xfb, 0x1a, 0x5f, 0x5c, 0xca, 0x23, - 0xb8, 0x3e, 0xcc, 0x52, 0xc5, 0x17, 0x82, 0xa9, 0xd0, 0xfb, 0x1a, 0x0b, 0x6e, 0x93, 0x96, 0xf8, - 0x36, 0x5f, 0xc3, 0xd2, 0x5a, 0xbf, 0xef, 0x9f, 0x6f, 0x7b, 0xcc, 0x61, 0x8c, 0x7a, 0xad, 0x01, - 0xc3, 0x17, 0x0f, 0x73, 0x64, 0x40, 0x85, 0xe2, 0x37, 0x5e, 0xe8, 0x91, 0x40, 0xec, 0x7b, 0xcd, - 0x8a, 0xdb, 0xe6, 0x32, 0x18, 0x79, 0x22, 0x95, 0x45, 0xfe, 0x36, 0x01, 0x68, 0x0b, 0x33, 0xb7, - 0x6b, 0xe1, 0x1e, 0x61, 0x17, 0xb7, 0x07, 0x3f, 0x55, 0xa8, 0x60, 0x25, 0x14, 0xa9, 0x5a, 0xaa, - 0xc5, 0x5d, 0xaf, 0x43, 0xa8, 0x1b, 0xbb, 0x9e, 0x68, 0xa0, 0x45, 0x28, 0x07, 0xc4, 0x66, 0xce, - 0x49, 0xd8, 0x98, 0x92, 0x87, 0x50, 0x40, 0x8e, 0x9d, 0x93, 0x10, 0x35, 0xa0, 0xcc, 0xbc, 0x1e, - 0x26, 0x03, 0xd6, 0x98, 0xbe, 0x5d, 0x7a, 0x30, 0x6d, 0x45, 0x4d, 0x3e, 0x25, 0x0c, 0xbb, 0xf6, - 0x29, 0x3e, 0x6f, 0xcc, 0x48, 0x09, 0x61, 0xd8, 0x7d, 0x8e, 0xcf, 0xd1, 0x2d, 0x98, 0x3d, 0x0d, - 0xc8, 0x59, 0x60, 0x77, 0x09, 0x3f, 0xd4, 0xca, 0xa2, 0x13, 0x04, 0x69, 0x87, 0x53, 0xd0, 0x12, - 0x54, 0x02, 0x62, 0xcb, 0x00, 0xa8, 0x0a, 0x69, 0xe5, 0x80, 0x1c, 0xf2, 0x26, 0x7a, 0x0a, 0x97, - 0xa5, 0x9e, 0x76, 0xdf, 0xa1, 0x4e, 0x2f, 0x6c, 0x80, 0x58, 0xf2, 0x15, 0xbd, 0x64, 0x61, 0x9d, - 0x9a, 0x1c, 0x74, 0x28, 0xc6, 0x3c, 0x9b, 0xaa, 0x54, 0xea, 0x55, 0xf3, 0x1a, 0xcc, 0xa7, 0x0c, - 0xa8, 0x43, 0x67, 0x5d, 0x84, 0x9e, 0xb6, 0xd6, 0x58, 0x42, 0x27, 0xcb, 0x54, 0x09, 0xfc, 0xd7, - 0x04, 0xcc, 0x6d, 0x63, 0xb6, 0x46, 0xdd, 0xae, 0xf7, 0x66, 0x0c, 0x1b, 0x79, 0x03, 0xaa, 0xae, - 0x88, 0x50, 0xdb, 0x6b, 0xab, 0xbd, 0xac, 0x48, 0xc2, 0x6e, 0x9b, 0xef, 0x72, 0x9f, 0xe2, 0x8e, - 0xf7, 0x56, 0x6c, 0x67, 0xd5, 0x52, 0x2d, 0xf4, 0x29, 0xcc, 0x74, 0x08, 0xed, 0x39, 0x4c, 0x6c, - 0xe7, 0x95, 0x27, 0xb7, 0x23, 0x51, 0x19, 0xcd, 0x56, 0xb7, 0xc4, 0x38, 0x4b, 0x8d, 0xe7, 0xd1, - 0xd2, 0x77, 0x58, 0x57, 0xec, 0x76, 0xcd, 0x12, 0xdf, 0xdc, 0x09, 0xf0, 0x5b, 0xd7, 0x1f, 0xb4, - 0x71, 0x63, 0xe6, 0xf6, 0xe4, 0x83, 0x9a, 0x15, 0x35, 0xd1, 0x0a, 0x00, 0xf6, 0xbd, 0x36, 0xdf, - 0x2e, 0xd6, 0x15, 0x5b, 0x5d, 0xb1, 0xaa, 0x82, 0x72, 0xc8, 0x27, 0x3e, 0x84, 0x39, 0x2f, 0x10, - 0x23, 0x6d, 0xbf, 0x13, 0xda, 0x2d, 0x9f, 0xb4, 0xc2, 0x46, 0x45, 0x8c, 0xba, 0xaa, 0x3a, 0x5e, - 0x74, 0xc2, 0x26, 0x27, 0x9b, 0x4f, 0x61, 0x46, 0xaa, 0x82, 0xca, 0x30, 0xf9, 0x6a, 0xf7, 0xb0, - 0x7e, 0x89, 0x7f, 0x1c, 0xaf, 0x59, 0xf5, 0x12, 0x02, 0x98, 0x39, 0x5e, 0xb3, 0xec, 0xed, 0x57, - 0xf5, 0x09, 0x34, 0x0b, 0x65, 0xfe, 0xdd, 0x7c, 0xf5, 0xa4, 0x3e, 0x69, 0x3e, 0x00, 0x94, 0x5c, - 0x91, 0x8e, 0xf8, 0xb6, 0xc3, 0x1c, 0x61, 0xe6, 0x9a, 0x25, 0xbe, 0xb9, 0x1f, 0xec, 0x38, 0xe1, - 0x0b, 0xe2, 0x3a, 0x7e, 0x93, 0x3a, 0x81, 0xdb, 0x1d, 0x43, 0xbc, 0x9b, 0x1f, 0x43, 0x23, 0xcb, - 0x54, 0x29, 0xb1, 0x00, 0xd3, 0x6f, 0x1c, 0x7f, 0x80, 0xd5, 0xad, 0x2e, 0x1b, 0xe6, 0x77, 0x25, - 0x68, 0x08, 0x37, 0x3d, 0x22, 0x03, 0xea, 0x62, 0x39, 0xeb, 0xe2, 0x4e, 0xf2, 0x33, 0x98, 0x0b, - 0x05, 0x43, 0x3b, 0xc1, 0x60, 0xa2, 0x88, 0x81, 0x55, 0x97, 0x83, 0xad, 0xd4, 0xb5, 0xa5, 0x18, - 0xb4, 0x84, 0x4a, 0xc2, 0x9f, 0x6a, 0x56, 0x2d, 0x4c, 0xa8, 0xc9, 0x77, 0x9b, 0x39, 0xf4, 0x04, - 0x33, 0x9b, 0xe2, 0x8e, 0xf0, 0xac, 0x9a, 0x55, 0x95, 0x14, 0x0b, 0x77, 0xcc, 0xa7, 0xb0, 0x94, - 0xb3, 0x34, 0xfd, 0xca, 0xa1, 0x38, 0x1c, 0xf8, 0x2c, 0x7a, 0xe5, 0xc8, 0x96, 0xb9, 0x0d, 0xb3, - 0x5b, 0xe1, 0x38, 0xae, 0xf8, 0x7b, 0x50, 0x93, 0x8c, 0xb4, 0xfd, 0x31, 0xa5, 0x84, 0x2a, 0x2f, - 0x90, 0x0d, 0xf3, 0x2f, 0x25, 0xb8, 0x2a, 0x6e, 0x3d, 0x0b, 0x77, 0x2e, 0x6e, 0xf6, 0x3a, 0x4c, - 0x72, 0x4b, 0xc8, 0xa3, 0x9e, 0x7f, 0xa6, 0x6e, 0x80, 0xc9, 0xf4, 0x0d, 0x80, 0xee, 0x40, 0x8d, - 0xf8, 0x6d, 0x3b, 0xee, 0x97, 0x06, 0x9c, 0x25, 0x7e, 0xdb, 0x8a, 0x86, 0xc4, 0xa7, 0xf3, 0x74, - 0xe2, 0x74, 0x7e, 0x36, 0x55, 0x99, 0xa9, 0x97, 0xcd, 0x06, 0xd4, 0xb5, 0xe6, 0x72, 0x91, 0xcf, - 0xa6, 0x2a, 0xa5, 0xfa, 0x84, 0x19, 0xc0, 0xc2, 0x96, 0x17, 0xb4, 0xf7, 0x30, 0x3d, 0xc1, 0x4d, - 0x27, 0x1c, 0xc3, 0xa1, 0xb3, 0x0c, 0xd5, 0x48, 0xcd, 0xb0, 0x31, 0x21, 0x62, 0x5e, 0x13, 0xcc, - 0x0f, 0xe1, 0xda, 0x90, 0x3c, 0x1d, 0x78, 0x2d, 0x27, 0x94, 0x2e, 0x5f, 0xb5, 0xc4, 0xb7, 0xf9, - 0x4d, 0x09, 0xe6, 0xe4, 0x61, 0xb9, 0x45, 0xe8, 0xe9, 0xff, 0xde, 0xd5, 0xf9, 0x5b, 0x30, 0xa9, - 0x4f, 0xfc, 0xf4, 0x5d, 0xda, 0x0d, 0x2d, 0xcc, 0x55, 0xde, 0x0d, 0x0e, 0x29, 0x39, 0xa1, 0x38, - 0x0c, 0xc7, 0x72, 0x7a, 0x53, 0xc1, 0x34, 0x71, 0x7a, 0x4b, 0xc2, 0x6e, 0xdb, 0xfc, 0x29, 0x18, - 0x79, 0x32, 0x95, 0x31, 0x6f, 0xc1, 0xac, 0x17, 0xd8, 0x7d, 0x45, 0x56, 0x61, 0x03, 0x5e, 0x3c, - 0x50, 0xaa, 0x7c, 0xf4, 0x7a, 0xe0, 0x84, 0xdd, 0x31, 0xab, 0x1c, 0x0a, 0xa6, 0x09, 0x95, 0x25, - 0x21, 0x52, 0x39, 0x2b, 0xf3, 0x5d, 0x55, 0xf6, 0xe1, 0xe6, 0xf0, 0xc5, 0xb9, 0x45, 0x49, 0xef, - 0xa5, 0xf5, 0x62, 0x2c, 0xc1, 0x38, 0xa0, 0xbe, 0xd2, 0x98, 0x7f, 0x9a, 0x77, 0xe0, 0x56, 0xa1, - 0x34, 0xb5, 0xed, 0x07, 0x30, 0x2f, 0x87, 0x34, 0x07, 0x41, 0xdb, 0x1f, 0xc3, 0x3b, 0xf4, 0x21, - 0x2c, 0xa4, 0x19, 0x8e, 0xb8, 0x93, 0xbe, 0x99, 0x80, 0xfa, 0x11, 0x66, 0xeb, 0x24, 0xe8, 0x78, - 0x27, 0x17, 0x37, 0xc0, 0xa7, 0x50, 0xc6, 0x01, 0xa3, 0x1e, 0x96, 0x21, 0x3b, 0xfb, 0xe4, 0x66, - 0x34, 0x6d, 0x58, 0xc8, 0xea, 0x66, 0xc0, 0xe8, 0xb9, 0x15, 0x0d, 0x37, 0x7e, 0x53, 0x82, 0x69, - 0x41, 0xe2, 0x46, 0xe4, 0x2f, 0x3a, 0x19, 0xc0, 0xfc, 0x13, 0xad, 0x40, 0x55, 0x5c, 0x5d, 0x76, - 0xc8, 0xa8, 0x34, 0xee, 0xce, 0x25, 0xab, 0x22, 0x48, 0x47, 0x8c, 0xa2, 0x3b, 0x30, 0x2b, 0xbb, - 0xbd, 0x80, 0x3d, 0x7d, 0x22, 0xce, 0xbc, 0xe9, 0x9d, 0x4b, 0x16, 0x08, 0xe2, 0x2e, 0xa7, 0xa1, - 0x5b, 0x20, 0x5b, 0x76, 0x8b, 0x10, 0x5f, 0xbe, 0x2f, 0x77, 0x2e, 0x59, 0x92, 0x6b, 0x93, 0x10, - 0xbf, 0x59, 0x56, 0x57, 0xa5, 0x39, 0x0f, 0x73, 0x09, 0x55, 0xd5, 0x16, 0xb9, 0x30, 0xbf, 0x81, - 0x7d, 0xcc, 0x13, 0x95, 0xf1, 0xd8, 0x09, 0xc1, 0xd4, 0x29, 0x3e, 0x97, 0x46, 0xaa, 0x5a, 0xe2, - 0xdb, 0xbc, 0x0e, 0x0b, 0x69, 0x21, 0x4a, 0xb8, 0xc7, 0xd3, 0xe5, 0x90, 0x11, 0x8a, 0xd7, 0x07, - 0x21, 0x23, 0xbd, 0x1d, 0x42, 0x4e, 0xc3, 0xb1, 0xa8, 0x20, 0xbc, 0x61, 0x22, 0xe1, 0x0d, 0xcb, - 0x60, 0xe4, 0x89, 0x52, 0x8a, 0x1c, 0x43, 0xa3, 0xe9, 0xb8, 0xa7, 0x83, 0xfe, 0x38, 0xf5, 0x30, - 0x1f, 0xc3, 0x52, 0x0e, 0xd7, 0x11, 0x2e, 0xfb, 0x1a, 0xee, 0xe4, 0x85, 0xd4, 0x98, 0xa2, 0x27, - 0xd7, 0x2e, 0xf7, 0xc0, 0x1c, 0x25, 0x52, 0xd9, 0x67, 0x1f, 0x10, 0xbf, 0x93, 0x5e, 0x78, 0x2e, - 0x0e, 0xc6, 0x70, 0x03, 0x9a, 0xeb, 0x30, 0x9f, 0xe2, 0xa7, 0x6c, 0xf2, 0x08, 0x90, 0x2f, 0x49, - 0x76, 0xd8, 0x25, 0x94, 0xd9, 0x81, 0xd3, 0x8b, 0xee, 0xbb, 0xba, 0xea, 0x39, 0xe2, 0x1d, 0xfb, - 0x4e, 0x4f, 0x6c, 0xda, 0x36, 0x66, 0xbb, 0x41, 0x87, 0xac, 0x8d, 0x2f, 0xcb, 0x34, 0x7f, 0x02, - 0x4b, 0x39, 0x5c, 0x95, 0x82, 0x37, 0x01, 0x74, 0x7a, 0xa9, 0xb6, 0x2e, 0x41, 0xe1, 0x2a, 0xad, - 0x3b, 0xbe, 0x3b, 0xf0, 0x1d, 0x86, 0xd7, 0xbb, 0xd8, 0x3d, 0x0d, 0x07, 0xbd, 0x8b, 0xab, 0xf4, - 0xff, 0xb0, 0x94, 0xc3, 0x55, 0xa9, 0x64, 0x40, 0xc5, 0x55, 0x34, 0x65, 0xa9, 0xb8, 0xcd, 0xb7, - 0x6d, 0x1b, 0xb3, 0xa3, 0xc0, 0xe9, 0x87, 0x5d, 0x72, 0x71, 0xf8, 0xc5, 0xfc, 0x00, 0xe6, 0x53, - 0xfc, 0x46, 0xb8, 0xf2, 0xb7, 0x25, 0xb8, 0x9b, 0xe7, 0x58, 0x63, 0x53, 0x86, 0x27, 0xba, 0x5d, - 0xc6, 0xfa, 0xb6, 0xbe, 0x96, 0xca, 0xbc, 0xfd, 0x92, 0xfa, 0xfc, 0x92, 0x15, 0x5d, 0xce, 0x80, - 0x75, 0x55, 0xee, 0x26, 0xc6, 0xae, 0x0d, 0x58, 0xd7, 0xbc, 0x0f, 0xf7, 0x46, 0x2b, 0xa6, 0x7c, - 0xfe, 0x0f, 0x25, 0x58, 0xd8, 0xc6, 0xcc, 0x72, 0xce, 0xd6, 0xbb, 0x4e, 0x70, 0x32, 0x0e, 0x04, - 0xe3, 0x2e, 0x5c, 0xee, 0x50, 0xd2, 0xb3, 0x53, 0x30, 0x46, 0xd5, 0xaa, 0x71, 0x62, 0xfc, 0x4a, - 0xbd, 0x05, 0xb3, 0x8c, 0xd8, 0xa9, 0x77, 0x6e, 0xd5, 0x02, 0x46, 0xa2, 0x01, 0xe6, 0x5f, 0xa7, - 0xe0, 0xda, 0x90, 0x62, 0x6a, 0x23, 0x76, 0x60, 0x96, 0x3a, 0x67, 0xb6, 0x2b, 0xc9, 0x8d, 0x92, - 0xb8, 0xa7, 0xde, 0x4f, 0x64, 0xa7, 0xd9, 0x39, 0xab, 0x31, 0xc9, 0x02, 0x1a, 0xf7, 0x1a, 0xdf, - 0x4d, 0x42, 0x35, 0xee, 0x41, 0x8b, 0x50, 0xe6, 0xd9, 0x25, 0x7f, 0xb2, 0x48, 0x17, 0x9b, 0xe1, - 0xcd, 0xdd, 0x76, 0x8c, 0xfe, 0x4c, 0x68, 0xf4, 0x07, 0xad, 0x40, 0x25, 0xc0, 0x67, 0x32, 0x67, - 0x15, 0xca, 0x37, 0x27, 0x1a, 0x25, 0xab, 0x1c, 0xe0, 0x33, 0x91, 0xb5, 0xae, 0x40, 0x85, 0xbf, - 0xd3, 0x45, 0xf7, 0x94, 0xee, 0x26, 0x7e, 0x5b, 0x74, 0x1f, 0x40, 0x95, 0xf4, 0x31, 0x75, 0x18, - 0x5f, 0xfb, 0xb4, 0x48, 0xaf, 0x3f, 0x79, 0xc7, 0x05, 0xac, 0x1e, 0x44, 0x13, 0x2d, 0xcd, 0x83, - 0xdb, 0x9c, 0xdb, 0x44, 0x33, 0x95, 0x78, 0x4a, 0x8d, 0x3a, 0x67, 0xf1, 0x78, 0xee, 0x4b, 0x5c, - 0xa9, 0x1e, 0x69, 0x63, 0x91, 0x67, 0x4f, 0x0b, 0x85, 0xf6, 0x48, 0x1b, 0x0b, 0x3c, 0x05, 0x9f, - 0xc9, 0xae, 0x8a, 0xec, 0x0a, 0xf0, 0x99, 0xe8, 0xba, 0x07, 0x57, 0xa2, 0x95, 0xda, 0xad, 0x73, - 0x7e, 0x22, 0x54, 0x65, 0x5e, 0xa7, 0xd6, 0xda, 0xe4, 0x34, 0x3e, 0x2a, 0x5a, 0xb0, 0x1a, 0x05, - 0x72, 0x94, 0x5a, 0xb2, 0x18, 0x65, 0x7a, 0x50, 0xd5, 0xea, 0xcc, 0x42, 0xf9, 0xe5, 0xfe, 0xf3, - 0xfd, 0x83, 0xcf, 0xf7, 0xeb, 0x97, 0x50, 0x15, 0xa6, 0xd7, 0x36, 0x36, 0x36, 0x37, 0x64, 0xa6, - 0xbe, 0x7e, 0x70, 0xb8, 0xbb, 0xb9, 0x21, 0x33, 0xf5, 0x8d, 0xcd, 0x17, 0x9b, 0xc7, 0x9b, 0x1b, - 0xf5, 0x49, 0x54, 0x83, 0xca, 0xde, 0xc1, 0xc6, 0xee, 0x16, 0xef, 0x9a, 0xe2, 0x5d, 0xd6, 0xe6, - 0xfe, 0xda, 0xde, 0xe6, 0x46, 0x7d, 0x1a, 0xd5, 0xa1, 0x76, 0xfc, 0xc5, 0xe1, 0xa6, 0xbd, 0xbe, - 0xb3, 0xb6, 0xbf, 0xbd, 0xb9, 0x51, 0x9f, 0x31, 0x7f, 0x5f, 0x82, 0xc6, 0x11, 0x76, 0xa8, 0xdb, - 0xdd, 0xf2, 0x7c, 0x1c, 0x36, 0xcf, 0xf9, 0x69, 0x7a, 0x71, 0xe7, 0x5e, 0x80, 0xe9, 0xd7, 0x03, - 0xac, 0xd2, 0x85, 0xaa, 0x25, 0x1b, 0x51, 0x12, 0x37, 0xa9, 0x93, 0xb8, 0xeb, 0x30, 0xd3, 0xf1, - 0x7c, 0x86, 0xa9, 0xdc, 0x7e, 0x4b, 0xb5, 0xcc, 0x4f, 0x60, 0x29, 0x47, 0x2b, 0x9d, 0x6f, 0x76, - 0x38, 0x59, 0xf8, 0x74, 0xcd, 0x92, 0x0d, 0xf3, 0xcf, 0x25, 0xb8, 0x91, 0x9a, 0xb3, 0x4e, 0x02, - 0x86, 0x03, 0xf6, 0xc3, 0x2d, 0xe6, 0x03, 0xa8, 0xbb, 0xdd, 0x41, 0x70, 0x8a, 0x79, 0xe6, 0x29, - 0x75, 0x55, 0x18, 0xdf, 0x55, 0x45, 0x8f, 0xcf, 0x93, 0x73, 0x58, 0xce, 0xd7, 0x55, 0x2d, 0xb1, - 0x01, 0xe5, 0x9e, 0xc3, 0xdc, 0x6e, 0xbc, 0xc8, 0xa8, 0x89, 0x56, 0x00, 0xc4, 0xa7, 0x9d, 0xb8, - 0xbd, 0xab, 0x82, 0xb2, 0xe1, 0x30, 0x07, 0xdd, 0x86, 0x1a, 0x0e, 0xda, 0x36, 0xe9, 0xd8, 0x82, - 0xa6, 0xb0, 0x47, 0xc0, 0x41, 0xfb, 0xa0, 0xb3, 0xc7, 0x29, 0xe6, 0xef, 0x4a, 0x30, 0x23, 0x91, - 0xbb, 0xe8, 0x1d, 0x5f, 0x8a, 0xdf, 0xf1, 0x3c, 0x86, 0xc5, 0x35, 0x2b, 0x57, 0x2a, 0xbe, 0xd1, - 0x8f, 0x61, 0x29, 0x3e, 0x40, 0x09, 0xf5, 0xbe, 0x16, 0x6e, 0x69, 0x77, 0xb1, 0xd3, 0xc6, 0x54, - 0x9d, 0x48, 0x8b, 0xd1, 0x81, 0x1a, 0xf7, 0xef, 0x88, 0x6e, 0xf4, 0x1e, 0x5c, 0xe9, 0x79, 0x94, - 0x12, 0x6a, 0x53, 0xdc, 0xe9, 0x39, 0xfd, 0xb0, 0x31, 0x25, 0x9e, 0x82, 0x97, 0x25, 0xd5, 0x92, - 0x44, 0xf3, 0x0b, 0x58, 0xd9, 0xc6, 0xec, 0xa0, 0xf5, 0x0b, 0xec, 0xb2, 0x0d, 0x8f, 0x62, 0x77, - 0x7c, 0x68, 0xf5, 0xff, 0xc1, 0xcd, 0x22, 0xd6, 0x23, 0x50, 0xeb, 0x3f, 0x95, 0x60, 0x61, 0xdd, - 0x27, 0x01, 0xe6, 0xb7, 0xc1, 0x21, 0x21, 0x63, 0x28, 0xd1, 0xdc, 0x87, 0xa9, 0x3e, 0x7f, 0x95, - 0x0f, 0x25, 0xd0, 0x52, 0x33, 0x21, 0x42, 0xf4, 0xa3, 0xfb, 0x31, 0x9c, 0x3c, 0x99, 0x8b, 0xc8, - 0xaa, 0x5e, 0x73, 0x11, 0xae, 0x0d, 0x69, 0xa8, 0x7c, 0xeb, 0xef, 0x25, 0x58, 0x4e, 0xf5, 0xec, - 0x06, 0x0c, 0xd3, 0xc0, 0xf9, 0x01, 0xd7, 0x90, 0x8b, 0x1c, 0x4c, 0xfe, 0x17, 0xc8, 0xc1, 0x2d, - 0x58, 0x29, 0x58, 0x82, 0x06, 0x9b, 0xb9, 0x3d, 0xde, 0x8c, 0x1b, 0x6c, 0xce, 0x32, 0x55, 0x02, - 0xdf, 0x72, 0x81, 0x81, 0x38, 0x86, 0xc6, 0x26, 0x50, 0xdc, 0x47, 0xd8, 0x77, 0x98, 0xf7, 0x46, - 0xe1, 0xba, 0xea, 0x0d, 0x10, 0x11, 0xf9, 0x95, 0x20, 0xb5, 0x1a, 0x96, 0xac, 0xb4, 0xfa, 0x75, - 0x89, 0xa7, 0x32, 0x7d, 0xdf, 0x73, 0xc7, 0x8b, 0xbb, 0xa3, 0x87, 0x30, 0x23, 0x37, 0x65, 0x04, - 0xe0, 0xa3, 0x46, 0x98, 0x2b, 0x70, 0x23, 0x57, 0x07, 0xa5, 0xe3, 0x4b, 0x58, 0x3a, 0xe8, 0x33, - 0xaf, 0x27, 0x62, 0x6e, 0x7c, 0x9b, 0xb5, 0x0c, 0x46, 0x1e, 0x5b, 0x29, 0xf4, 0xc9, 0x3f, 0x6f, - 0x8a, 0x02, 0x6b, 0x54, 0xa5, 0x92, 0x95, 0x69, 0xf4, 0x25, 0xd4, 0x87, 0x8b, 0xc3, 0xe8, 0x56, - 0x56, 0x5a, 0xaa, 0x16, 0x6d, 0xdc, 0x2e, 0x1e, 0xa0, 0x56, 0x38, 0xf3, 0xef, 0x6f, 0x1f, 0x4c, - 0x54, 0x26, 0xd0, 0x57, 0x51, 0x51, 0x37, 0x51, 0xf1, 0x45, 0xc9, 0xe9, 0xb9, 0x25, 0x66, 0xe3, - 0xce, 0x88, 0x11, 0x29, 0x09, 0x25, 0xf4, 0x1c, 0x40, 0x97, 0x70, 0xd1, 0x52, 0x7a, 0x62, 0xa2, - 0x94, 0x6c, 0x18, 0x79, 0x5d, 0x59, 0x66, 0xba, 0x54, 0xab, 0x99, 0x65, 0xaa, 0xc1, 0x9a, 0x59, - 0x4e, 0x65, 0x37, 0x62, 0xf6, 0x39, 0x5c, 0x49, 0x97, 0x54, 0xd1, 0x4a, 0xfc, 0x54, 0xcb, 0x2b, - 0xfc, 0x1a, 0x37, 0x8b, 0xba, 0x87, 0x18, 0x7f, 0xa9, 0xc0, 0xd8, 0x44, 0xf1, 0x54, 0xef, 0x59, - 0x41, 0xad, 0x56, 0xef, 0x59, 0x61, 0xdd, 0x35, 0xa1, 0x77, 0xba, 0x9a, 0xa9, 0xf5, 0xce, 0x2d, - 0x9c, 0x6a, 0xbd, 0xf3, 0x8b, 0xa0, 0xb1, 0x33, 0xb8, 0x80, 0xb2, 0x55, 0x48, 0x14, 0xef, 0x75, - 0x61, 0x51, 0xd4, 0x30, 0x47, 0x0d, 0x19, 0xd2, 0x7e, 0x1f, 0x66, 0x13, 0xa5, 0x38, 0x14, 0x6f, - 0x54, 0xb6, 0xc0, 0x69, 0xdc, 0xc8, 0xed, 0xcb, 0x1a, 0x7b, 0x38, 0x1f, 0xd2, 0xc6, 0x2e, 0xa8, - 0xee, 0x69, 0x63, 0x17, 0x56, 0xea, 0x22, 0xf6, 0x7b, 0x00, 0xba, 0x88, 0xa4, 0x3d, 0x2e, 0x53, - 0x2a, 0xd3, 0x1e, 0x97, 0xad, 0x39, 0x45, 0x06, 0xfe, 0x58, 0x68, 0x3b, 0x5c, 0x14, 0xd2, 0xda, - 0x16, 0xd4, 0xa0, 0xb4, 0xb6, 0x45, 0xf5, 0xa4, 0x64, 0x38, 0x67, 0xaa, 0x2c, 0x3a, 0x9c, 0x8b, - 0x6a, 0x4b, 0x3a, 0x9c, 0x0b, 0x4b, 0x34, 0xb1, 0x3d, 0x7e, 0x04, 0x53, 0x5b, 0xa1, 0x7b, 0x8a, - 0xe6, 0xe3, 0x29, 0xba, 0x40, 0x63, 0x2c, 0xa4, 0x89, 0x43, 0x53, 0x37, 0xa1, 0x12, 0xd5, 0x28, - 0xd0, 0x62, 0xca, 0xdb, 0x75, 0xbd, 0xc5, 0x68, 0x64, 0x3b, 0x86, 0xd8, 0x1c, 0xc3, 0xe5, 0x54, - 0x81, 0x01, 0x2d, 0xc7, 0x52, 0x73, 0xea, 0x1c, 0xc6, 0x4a, 0x41, 0xef, 0x90, 0xe5, 0x9e, 0x03, - 0x68, 0xe0, 0x5f, 0xef, 0x73, 0xa6, 0x38, 0xa1, 0xf7, 0x39, 0xa7, 0x4e, 0x10, 0xa9, 0xe8, 0x02, - 0xca, 0x62, 0xf7, 0x3a, 0x90, 0x0a, 0x6b, 0x09, 0x3a, 0x90, 0x8a, 0xa1, 0xff, 0x64, 0xb4, 0x66, - 0xd1, 0xf6, 0xa4, 0x90, 0x02, 0xf4, 0x3f, 0x29, 0xa4, 0x08, 0xac, 0x8f, 0x85, 0xd0, 0x6c, 0x85, - 0x5c, 0xa1, 0xe4, 0xe8, 0x7e, 0x51, 0x0c, 0xa5, 0x41, 0x7b, 0xe3, 0xfd, 0xef, 0x1d, 0x37, 0x64, - 0xbd, 0x23, 0xa8, 0x25, 0x51, 0x72, 0x74, 0x23, 0xcd, 0x20, 0x05, 0x27, 0x1a, 0xcb, 0xf9, 0x9d, - 0x99, 0xc0, 0xfb, 0x25, 0x18, 0xc5, 0x40, 0x21, 0xfa, 0x60, 0x94, 0x8e, 0x69, 0x81, 0x0f, 0xdf, - 0x65, 0x68, 0x7a, 0x45, 0x0f, 0x4a, 0x68, 0x07, 0xaa, 0x31, 0x78, 0x8d, 0x1a, 0x45, 0xd0, 0xbb, - 0xb1, 0x94, 0xd3, 0x33, 0x64, 0x9d, 0xcf, 0xa0, 0x96, 0x04, 0xa3, 0xb5, 0x75, 0x72, 0x70, 0x70, - 0x6d, 0x9d, 0x5c, 0xfc, 0x3a, 0x79, 0x24, 0x6b, 0x38, 0x33, 0x71, 0x24, 0x67, 0x30, 0xd3, 0xc4, - 0x91, 0x9c, 0xc5, 0x3f, 0x63, 0xa7, 0x69, 0x89, 0x9f, 0x1c, 0xd2, 0x18, 0x24, 0x4a, 0xfe, 0x65, - 0x90, 0x0b, 0x7a, 0xea, 0x53, 0xa8, 0x10, 0xc0, 0x4c, 0xec, 0xe7, 0x57, 0x30, 0x97, 0x01, 0x15, - 0xb5, 0x8c, 0x22, 0x14, 0x53, 0xcb, 0x28, 0x44, 0x24, 0xe3, 0x55, 0x34, 0xa1, 0xac, 0x7e, 0x4d, - 0x42, 0xd7, 0xe3, 0x59, 0xa9, 0xff, 0x9e, 0x8c, 0xc5, 0x0c, 0x7d, 0xc8, 0xb2, 0x87, 0x30, 0x9b, - 0x40, 0x1c, 0x51, 0xf2, 0x8e, 0x18, 0x42, 0x12, 0xb5, 0x65, 0x73, 0x20, 0xca, 0xc4, 0xba, 0x7f, - 0xc5, 0x53, 0xa5, 0x11, 0xf8, 0x1f, 0xfa, 0x70, 0x94, 0x7f, 0x0e, 0x0b, 0x7d, 0xf4, 0x6e, 0x83, - 0x87, 0x56, 0xf5, 0x73, 0xb8, 0x9c, 0xc2, 0xb2, 0xf4, 0x09, 0x9c, 0x07, 0x38, 0xea, 0x13, 0x38, - 0x17, 0x00, 0x4b, 0xac, 0xed, 0x14, 0x16, 0xf2, 0x20, 0x06, 0x74, 0x57, 0x47, 0x45, 0x21, 0x58, - 0x62, 0xdc, 0x1b, 0x3d, 0x28, 0x23, 0xac, 0x05, 0x73, 0x19, 0xbc, 0x46, 0x3b, 0x50, 0x11, 0xc0, - 0xa4, 0x1d, 0xa8, 0x10, 0xec, 0x49, 0xc8, 0xc0, 0x80, 0xb2, 0x55, 0x1b, 0x94, 0x78, 0x3c, 0x17, - 0x14, 0x8f, 0xf4, 0x11, 0x3d, 0xa2, 0xe8, 0xa3, 0x0f, 0x97, 0x16, 0xcc, 0x65, 0x0a, 0x35, 0x7a, - 0x29, 0x45, 0x95, 0x21, 0xbd, 0x94, 0xc2, 0x2a, 0x4f, 0x62, 0x29, 0x04, 0xae, 0xe7, 0x83, 0x12, - 0xe8, 0xbd, 0xc4, 0xf6, 0x16, 0xe3, 0x21, 0xc6, 0xfd, 0xef, 0x1b, 0x36, 0x14, 0x7e, 0xc7, 0x70, - 0x39, 0x95, 0x4f, 0x6b, 0x27, 0xcb, 0x43, 0x39, 0xb4, 0x93, 0xe5, 0x23, 0x0c, 0x91, 0xeb, 0xfa, - 0x43, 0x10, 0x44, 0x94, 0xa5, 0xa3, 0x7b, 0xb9, 0xf3, 0x87, 0x70, 0x08, 0xe3, 0xbd, 0xef, 0x19, - 0x95, 0x7d, 0x9b, 0x0e, 0x67, 0xe7, 0xc9, 0xe4, 0x2d, 0x17, 0x0c, 0x48, 0x26, 0x6f, 0x05, 0x89, - 0x7d, 0x8a, 0x7d, 0x3a, 0xcd, 0x4e, 0xb2, 0xcf, 0x4d, 0xfd, 0x93, 0xec, 0x0b, 0x32, 0xf4, 0x88, - 0x7d, 0x07, 0xe6, 0x73, 0x92, 0x64, 0x94, 0xf0, 0xcd, 0xa2, 0x2c, 0xde, 0xb8, 0x3b, 0x72, 0x4c, - 0xf6, 0xb5, 0x94, 0x4d, 0x8b, 0x75, 0x94, 0x14, 0x66, 0xe2, 0x3a, 0x4a, 0x8a, 0xb3, 0xea, 0x48, - 0x48, 0xf3, 0xe3, 0x57, 0x7c, 0xb0, 0xef, 0xb4, 0x56, 0x5d, 0xd2, 0x7b, 0x2c, 0x3f, 0x3f, 0x22, - 0xf4, 0xe4, 0xb1, 0x64, 0xf1, 0x58, 0xfc, 0xdf, 0xfd, 0xf8, 0x84, 0xa8, 0x76, 0xbf, 0xd5, 0x9a, - 0x11, 0xa4, 0xa7, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0xe5, 0x4f, 0xb9, 0xf5, 0x30, 0x2e, 0x00, - 0x00, + // 3283 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x5a, 0x5b, 0x6f, 0x1c, 0xc7, + 0xb1, 0xd6, 0xf2, 0xb2, 0x97, 0xe2, 0x92, 0x5a, 0x36, 0x49, 0x71, 0x39, 0x22, 0x45, 0x69, 0x74, + 0xb1, 0x2c, 0xcb, 0x94, 0x4c, 0x1d, 0xe0, 0xf8, 0x9c, 0x83, 0x83, 0x80, 0x5c, 0x72, 0x49, 0x4a, + 0xe2, 0xc5, 0x43, 0x32, 0x82, 0x05, 0x18, 0xe3, 0xd9, 0xdd, 0x5e, 0xee, 0x84, 0xb3, 0x33, 0xab, + 0x9e, 0x5e, 0x51, 0x34, 0x90, 0x87, 0x24, 0xc8, 0x5b, 0x60, 0x20, 0x40, 0x10, 0xe7, 0x31, 0xcf, + 0xf9, 0x01, 0x41, 0x5e, 0x02, 0xc3, 0x2f, 0xf9, 0x0f, 0xfe, 0x0b, 0xf9, 0x09, 0x79, 0x0a, 0xfa, + 0x32, 0xd3, 0x33, 0x3b, 0x33, 0x6b, 0x19, 0x5c, 0x38, 0x6f, 0xd3, 0x55, 0xdd, 0x55, 0xd5, 0xd5, + 0xd5, 0xdd, 0xd5, 0x5f, 0x0d, 0x54, 0x09, 0xee, 0x79, 0xbe, 0x4d, 0x3d, 0x72, 0xf9, 0xb1, 0x8f, + 0xc9, 0x5b, 0xbb, 0x89, 0xd7, 0x7a, 0xc4, 0xa3, 0x1e, 0xca, 0x9f, 0xd9, 0xd4, 0x72, 0x2e, 0x35, + 0x70, 0x6c, 0x97, 0x0a, 0x9a, 0x56, 0xf6, 0x3b, 0x16, 0xc1, 0x2d, 0xd1, 0xd2, 0x8f, 0x61, 0xd1, + 0x08, 0x47, 0x6f, 0xbf, 0xb3, 0x7d, 0xea, 0x1b, 0xf8, 0x4d, 0x1f, 0xfb, 0x14, 0x7d, 0x0a, 0xa0, + 0x04, 0x57, 0x73, 0xb7, 0x73, 0x0f, 0xa7, 0xd6, 0xd1, 0x9a, 0x90, 0xb8, 0xa6, 0x06, 0x6d, 0x4e, + 0xfc, 0xe9, 0x1f, 0x8f, 0x73, 0x46, 0xa4, 0xaf, 0xbe, 0x0e, 0xd5, 0xa4, 0x50, 0xbf, 0xe7, 0xb9, + 0x3e, 0x46, 0x37, 0x20, 0x8f, 0x39, 0x85, 0x4b, 0x2c, 0x1a, 0xb2, 0xa5, 0x9f, 0xf0, 0x31, 0x56, + 0xf3, 0x7c, 0xcf, 0x6d, 0x12, 0xdc, 0xc5, 0x2e, 0xb5, 0x9c, 0xab, 0x5b, 0x72, 0x13, 0x96, 0x52, + 0xa4, 0x0a, 0x53, 0x74, 0x02, 0xb3, 0x82, 0x59, 0xef, 0x3b, 0x57, 0xd7, 0x85, 0xee, 0xc2, 0x74, + 0x93, 0x60, 0x8b, 0x62, 0xb3, 0x61, 0xd3, 0xae, 0xd5, 0xab, 0x8e, 0xf1, 0x09, 0x96, 0x05, 0x71, + 0x93, 0xd3, 0xf4, 0x79, 0x40, 0x51, 0x9d, 0xd2, 0x92, 0x7d, 0x98, 0xdd, 0xb7, 0x5b, 0xef, 0x04, + 0xe7, 0xea, 0xb3, 0x9e, 0x07, 0x14, 0x15, 0x27, 0x95, 0xfc, 0x2e, 0x07, 0x0b, 0x3b, 0x16, 0x69, + 0x58, 0x67, 0xb8, 0xe6, 0x39, 0x0e, 0x6e, 0xd2, 0x9f, 0x66, 0xce, 0x68, 0x1e, 0x26, 0x7b, 0xa4, + 0xef, 0xe2, 0xea, 0x38, 0x67, 0x8a, 0x86, 0x5e, 0x85, 0x1b, 0x83, 0xd6, 0x48, 0x43, 0x8f, 0x61, + 0xf1, 0x15, 0xb1, 0x29, 0xae, 0x79, 0xdd, 0xae, 0x4d, 0x77, 0x88, 0xd5, 0xeb, 0x5c, 0xdd, 0x27, + 0x1a, 0x54, 0x93, 0x42, 0xa5, 0xc2, 0xe7, 0x30, 0x53, 0x73, 0xb0, 0xe5, 0xf6, 0x7b, 0x57, 0xd7, + 0x33, 0x0b, 0xd7, 0x43, 0x59, 0x52, 0xfc, 0x67, 0xb0, 0xa0, 0x86, 0x1c, 0xdb, 0x5f, 0xe1, 0xab, + 0x6b, 0x79, 0x0c, 0x37, 0x06, 0x45, 0xca, 0xfd, 0x85, 0x60, 0xc2, 0xb7, 0xbf, 0xc2, 0x5c, 0xda, + 0xb8, 0xc1, 0xbf, 0xf5, 0x37, 0xb0, 0xb4, 0xd1, 0xeb, 0x39, 0x97, 0x3b, 0x36, 0xb5, 0x28, 0x25, + 0x76, 0xa3, 0x4f, 0xf1, 0xd5, 0xb7, 0x39, 0xd2, 0xa0, 0x48, 0xf0, 0x5b, 0xdb, 0xb7, 0x3d, 0x97, + 0xaf, 0x7b, 0xd9, 0x08, 0xdb, 0xfa, 0x32, 0x68, 0x69, 0x2a, 0xa5, 0x47, 0xbe, 0x1d, 0x03, 0x54, + 0xc7, 0xb4, 0xd9, 0x31, 0x70, 0xd7, 0xa3, 0x57, 0xf7, 0x07, 0x3b, 0x55, 0x08, 0x17, 0xc5, 0x0d, + 0x29, 0x19, 0xb2, 0xc5, 0x42, 0xaf, 0xed, 0x91, 0x66, 0x18, 0x7a, 0xbc, 0x81, 0x16, 0xa1, 0xe0, + 0x7a, 0x26, 0xb5, 0xce, 0xfc, 0xea, 0x84, 0x38, 0x84, 0x5c, 0xef, 0xc4, 0x3a, 0xf3, 0x51, 0x15, + 0x0a, 0xd4, 0xee, 0x62, 0xaf, 0x4f, 0xab, 0x93, 0xb7, 0x73, 0x0f, 0x27, 0x8d, 0xa0, 0xc9, 0x86, + 0xf8, 0x7e, 0xc7, 0x3c, 0xc7, 0x97, 0xd5, 0xbc, 0xd0, 0xe0, 0xfb, 0x9d, 0x17, 0xf8, 0x12, 0xad, + 0xc2, 0xd4, 0xb9, 0xeb, 0x5d, 0xb8, 0x66, 0xc7, 0x63, 0x87, 0x5a, 0x81, 0x33, 0x81, 0x93, 0x76, + 0x19, 0x05, 0x2d, 0x41, 0xd1, 0xf5, 0x4c, 0xb1, 0x01, 0x4a, 0x5c, 0x5b, 0xc1, 0xf5, 0x8e, 0x58, + 0x13, 0x3d, 0x83, 0x69, 0x61, 0xa7, 0xd9, 0xb3, 0x88, 0xd5, 0xf5, 0xab, 0xc0, 0xa7, 0x3c, 0xa3, + 0xa6, 0xcc, 0xbd, 0x53, 0x16, 0x9d, 0x8e, 0x78, 0x9f, 0xe7, 0x13, 0xc5, 0x62, 0xa5, 0xa4, 0x2f, + 0xc0, 0x5c, 0xcc, 0x81, 0x6a, 0xeb, 0xd4, 0xf8, 0xd6, 0x53, 0xde, 0x1a, 0xc9, 0xd6, 0x49, 0x0a, + 0x95, 0x0a, 0xff, 0x39, 0x06, 0xb3, 0x3b, 0x98, 0x6e, 0x90, 0x66, 0xc7, 0x7e, 0x3b, 0x82, 0x85, + 0xbc, 0x09, 0xa5, 0x26, 0xdf, 0xa1, 0xa6, 0xdd, 0x92, 0x6b, 0x59, 0x14, 0x84, 0xbd, 0x16, 0x5b, + 0xe5, 0x1e, 0xc1, 0x6d, 0xfb, 0x1d, 0x5f, 0xce, 0x92, 0x21, 0x5b, 0xe8, 0x53, 0xc8, 0xb7, 0x3d, + 0xd2, 0xb5, 0x28, 0x5f, 0xce, 0x99, 0xf5, 0xdb, 0x81, 0xaa, 0x84, 0x65, 0x6b, 0x75, 0xde, 0xcf, + 0x90, 0xfd, 0xd9, 0x6e, 0xe9, 0x59, 0xb4, 0xc3, 0x57, 0xbb, 0x6c, 0xf0, 0x6f, 0x16, 0x04, 0xf8, + 0x5d, 0xd3, 0xe9, 0xb7, 0x70, 0x35, 0x7f, 0x7b, 0xfc, 0x61, 0xd9, 0x08, 0x9a, 0x68, 0x05, 0x00, + 0x3b, 0x76, 0x8b, 0x2d, 0x17, 0xed, 0xf0, 0xa5, 0x2e, 0x1a, 0x25, 0x4e, 0x39, 0x62, 0x03, 0x1f, + 0xc1, 0xac, 0xed, 0xf2, 0x9e, 0xa6, 0xd3, 0xf6, 0xcd, 0x86, 0xe3, 0x35, 0xfc, 0x6a, 0x91, 0xf7, + 0xba, 0x2e, 0x19, 0x2f, 0xdb, 0xfe, 0x26, 0x23, 0xeb, 0xcf, 0x20, 0x2f, 0x4c, 0x41, 0x05, 0x18, + 0x7f, 0xbd, 0x77, 0x54, 0xb9, 0xc6, 0x3e, 0x4e, 0x36, 0x8c, 0x4a, 0x0e, 0x01, 0xe4, 0x4f, 0x36, + 0x0c, 0x73, 0xe7, 0x75, 0x65, 0x0c, 0x4d, 0x41, 0x81, 0x7d, 0x6f, 0xbe, 0x5e, 0xaf, 0x8c, 0xeb, + 0x0f, 0x01, 0x45, 0x67, 0xa4, 0x76, 0x7c, 0xcb, 0xa2, 0x16, 0x77, 0x73, 0xd9, 0xe0, 0xdf, 0x2c, + 0x0e, 0x76, 0x2d, 0xff, 0xa5, 0xd7, 0xb4, 0x9c, 0x4d, 0x62, 0xb9, 0xcd, 0xce, 0x08, 0xf6, 0xbb, + 0xfe, 0x14, 0xaa, 0x49, 0xa1, 0xd2, 0x88, 0x79, 0x98, 0x7c, 0x6b, 0x39, 0x7d, 0x2c, 0x6f, 0x75, + 0xd1, 0xd0, 0xbf, 0xcf, 0x41, 0x95, 0x87, 0xe9, 0xb1, 0xd7, 0x27, 0x4d, 0x2c, 0x46, 0x5d, 0x3d, + 0x48, 0x7e, 0x06, 0xb3, 0x3e, 0x17, 0x68, 0x46, 0x04, 0x8c, 0x65, 0x09, 0x30, 0x2a, 0xa2, 0xb3, + 0x11, 0xbb, 0xb6, 0xa4, 0x80, 0x06, 0x37, 0x89, 0xc7, 0x53, 0xd9, 0x28, 0xfb, 0x11, 0x33, 0xd9, + 0x6a, 0x53, 0x8b, 0x9c, 0x61, 0x6a, 0x12, 0xdc, 0xe6, 0x91, 0x55, 0x36, 0x4a, 0x82, 0x62, 0xe0, + 0xb6, 0xfe, 0x0c, 0x96, 0x52, 0xa6, 0xa6, 0xb2, 0x1c, 0x82, 0xfd, 0xbe, 0x43, 0x83, 0x2c, 0x47, + 0xb4, 0xf4, 0x1d, 0x98, 0xaa, 0xfb, 0xa3, 0xb8, 0xe2, 0xef, 0x41, 0x59, 0x08, 0x52, 0xfe, 0xc7, + 0x84, 0x78, 0x44, 0x46, 0x81, 0x68, 0xe8, 0x7f, 0xcb, 0xc1, 0x75, 0x7e, 0xeb, 0x19, 0xb8, 0x7d, + 0x75, 0xb7, 0x57, 0x60, 0x9c, 0x79, 0x42, 0x1c, 0xf5, 0xec, 0x33, 0x76, 0x03, 0x8c, 0xc7, 0x6f, + 0x00, 0x74, 0x07, 0xca, 0x9e, 0xd3, 0x32, 0x43, 0xbe, 0x70, 0xe0, 0x94, 0xe7, 0xb4, 0x8c, 0xa0, + 0x4b, 0x78, 0x3a, 0x4f, 0x46, 0x4e, 0xe7, 0xe7, 0x13, 0xc5, 0x7c, 0xa5, 0xa0, 0x57, 0xa1, 0xa2, + 0x2c, 0x17, 0x93, 0x7c, 0x3e, 0x51, 0xcc, 0x55, 0xc6, 0x74, 0x17, 0xe6, 0xeb, 0xb6, 0xdb, 0xda, + 0xc7, 0xe4, 0x0c, 0x6f, 0x5a, 0xfe, 0x08, 0x0e, 0x9d, 0x65, 0x28, 0x05, 0x66, 0xfa, 0xd5, 0x31, + 0xbe, 0xe7, 0x15, 0x41, 0xff, 0x08, 0x16, 0x06, 0xf4, 0xa9, 0x8d, 0xd7, 0xb0, 0x7c, 0x11, 0xf2, + 0x25, 0x83, 0x7f, 0xeb, 0x5f, 0xe7, 0x60, 0x56, 0x1c, 0x96, 0x75, 0x8f, 0x9c, 0xff, 0xe7, 0x43, + 0x9d, 0xe5, 0x82, 0x51, 0x7b, 0xc2, 0xd4, 0x77, 0x69, 0xcf, 0x37, 0x30, 0x33, 0x79, 0xcf, 0x3d, + 0x22, 0xde, 0x19, 0xc1, 0xbe, 0x3f, 0x92, 0xd3, 0x9b, 0x70, 0xa1, 0x91, 0xd3, 0x5b, 0x10, 0xf6, + 0x5a, 0xfa, 0xff, 0x83, 0x96, 0xa6, 0x53, 0x3a, 0x73, 0x15, 0xa6, 0x6c, 0xd7, 0xec, 0x49, 0xb2, + 0xdc, 0x36, 0x60, 0x87, 0x1d, 0x85, 0xc9, 0xc7, 0x6f, 0xfa, 0x96, 0xdf, 0x19, 0xb1, 0xc9, 0x3e, + 0x17, 0x1a, 0x31, 0x59, 0x10, 0x02, 0x93, 0x93, 0x3a, 0xdf, 0xd7, 0x64, 0x07, 0x6e, 0x0d, 0x5e, + 0x9c, 0x75, 0xe2, 0x75, 0x4f, 0x8d, 0x97, 0x23, 0xd9, 0x8c, 0x7d, 0xe2, 0x48, 0x8b, 0xd9, 0xa7, + 0x7e, 0x07, 0x56, 0x33, 0xb5, 0xc9, 0x65, 0x3f, 0x84, 0x39, 0xd1, 0x65, 0xb3, 0xef, 0xb6, 0x9c, + 0x11, 0xe4, 0xa1, 0x8f, 0x60, 0x3e, 0x2e, 0x70, 0xc8, 0x9d, 0xf4, 0xf5, 0x18, 0x54, 0x8e, 0x31, + 0xad, 0x79, 0x6e, 0xdb, 0x3e, 0xbb, 0xba, 0x03, 0x3e, 0x85, 0x02, 0x76, 0x29, 0xb1, 0xb1, 0xd8, + 0xb2, 0x53, 0xeb, 0xb7, 0x82, 0x61, 0x83, 0x4a, 0xd6, 0xb6, 0x5d, 0x4a, 0x2e, 0x8d, 0xa0, 0xbb, + 0xf6, 0xdb, 0x1c, 0x4c, 0x72, 0x12, 0x73, 0x22, 0xcb, 0xe8, 0xc4, 0x06, 0x66, 0x9f, 0x68, 0x05, + 0x4a, 0xfc, 0xea, 0x32, 0x7d, 0x4a, 0x84, 0x73, 0x77, 0xaf, 0x19, 0x45, 0x4e, 0x3a, 0xa6, 0x04, + 0xdd, 0x81, 0x29, 0xc1, 0xb6, 0x5d, 0xfa, 0x6c, 0x9d, 0x9f, 0x79, 0x93, 0xbb, 0xd7, 0x0c, 0xe0, + 0xc4, 0x3d, 0x46, 0x43, 0xab, 0x20, 0x5a, 0x66, 0xc3, 0xf3, 0x1c, 0x91, 0x5f, 0xee, 0x5e, 0x33, + 0x84, 0xd4, 0x4d, 0xcf, 0x73, 0x36, 0x0b, 0xf2, 0xaa, 0xd4, 0xe7, 0x60, 0x36, 0x62, 0xaa, 0x5c, + 0xa2, 0x26, 0xcc, 0x6d, 0x61, 0x07, 0xb3, 0x87, 0xca, 0x68, 0xfc, 0x84, 0x60, 0xe2, 0x1c, 0x5f, + 0x0a, 0x27, 0x95, 0x0c, 0xfe, 0xad, 0xdf, 0x80, 0xf9, 0xb8, 0x12, 0xa9, 0xdc, 0x66, 0xcf, 0x65, + 0x9f, 0x7a, 0x04, 0xd7, 0xfa, 0x3e, 0xf5, 0xba, 0xbb, 0x9e, 0x77, 0xee, 0x8f, 0xc4, 0x04, 0x1e, + 0x0d, 0x63, 0x91, 0x68, 0x58, 0x06, 0x2d, 0x4d, 0x95, 0x34, 0xe4, 0x04, 0xaa, 0x9b, 0x56, 0xf3, + 0xbc, 0xdf, 0x1b, 0xa5, 0x1d, 0xfa, 0x13, 0x58, 0x4a, 0x91, 0x3a, 0x24, 0x64, 0xdf, 0xc0, 0x9d, + 0xb4, 0x2d, 0x35, 0xa2, 0xdd, 0x93, 0xea, 0x97, 0x7b, 0xa0, 0x0f, 0x53, 0x29, 0xfd, 0x73, 0x00, + 0x88, 0xdd, 0x49, 0x2f, 0xed, 0x26, 0x76, 0x47, 0x70, 0x03, 0xea, 0x35, 0x98, 0x8b, 0xc9, 0x93, + 0x3e, 0x79, 0x0c, 0xc8, 0x11, 0x24, 0xd3, 0xef, 0x78, 0x84, 0x9a, 0xae, 0xd5, 0x0d, 0xee, 0xbb, + 0x8a, 0xe4, 0x1c, 0x33, 0xc6, 0x81, 0xd5, 0xe5, 0x8b, 0xb6, 0x83, 0xe9, 0x9e, 0xdb, 0xf6, 0x36, + 0x46, 0xf7, 0xca, 0xd4, 0xff, 0x0f, 0x96, 0x52, 0xa4, 0x4a, 0x03, 0x6f, 0x01, 0xa8, 0xe7, 0xa5, + 0x5c, 0xba, 0x08, 0x85, 0x99, 0x54, 0xb3, 0x9c, 0x66, 0xdf, 0xb1, 0x28, 0xae, 0x75, 0x70, 0xf3, + 0xdc, 0xef, 0x77, 0xaf, 0x6e, 0xd2, 0x7f, 0xc3, 0x52, 0x8a, 0x54, 0x69, 0x92, 0x06, 0xc5, 0xa6, + 0xa4, 0x49, 0x4f, 0x85, 0x6d, 0xb6, 0x6c, 0x3b, 0x98, 0x1e, 0xbb, 0x56, 0xcf, 0xef, 0x78, 0x57, + 0x87, 0x5f, 0xf4, 0x0f, 0x61, 0x2e, 0x26, 0x6f, 0x48, 0x28, 0x7f, 0x93, 0x83, 0xbb, 0x69, 0x81, + 0x35, 0x32, 0x63, 0xd8, 0x43, 0xb7, 0x43, 0x69, 0xcf, 0x54, 0xd7, 0x52, 0x81, 0xb5, 0x4f, 0x89, + 0xc3, 0x2e, 0x59, 0xce, 0xb2, 0xfa, 0xb4, 0x23, 0xdf, 0x6e, 0xbc, 0xef, 0x46, 0x9f, 0x76, 0xf4, + 0x07, 0x70, 0x6f, 0xb8, 0x61, 0x32, 0xe6, 0xff, 0x98, 0x83, 0xf9, 0x1d, 0x4c, 0x0d, 0xeb, 0xa2, + 0xd6, 0xb1, 0xdc, 0xb3, 0x51, 0x20, 0x18, 0x77, 0x61, 0xba, 0x4d, 0xbc, 0xae, 0x19, 0x83, 0x31, + 0x4a, 0x46, 0x99, 0x11, 0xc3, 0x2c, 0x75, 0x15, 0xa6, 0xa8, 0x67, 0xc6, 0xf2, 0xdc, 0x92, 0x01, + 0xd4, 0x0b, 0x3a, 0xe8, 0x7f, 0x9f, 0x80, 0x85, 0x01, 0xc3, 0xe4, 0x42, 0xec, 0xc2, 0x14, 0xb1, + 0x2e, 0xcc, 0xa6, 0x20, 0x57, 0x73, 0xfc, 0x9e, 0xfa, 0x20, 0xf2, 0x3a, 0x4d, 0x8e, 0x59, 0x0b, + 0x49, 0x06, 0x90, 0x90, 0xab, 0x7d, 0x3f, 0x0e, 0xa5, 0x90, 0x83, 0x16, 0xa1, 0xc0, 0x5e, 0x97, + 0x2c, 0x65, 0x11, 0x21, 0x96, 0x67, 0xcd, 0xbd, 0x56, 0x88, 0xfe, 0x8c, 0x29, 0xf4, 0x07, 0xad, + 0x40, 0xd1, 0xc5, 0x17, 0xe2, 0xcd, 0xca, 0x8d, 0xdf, 0x1c, 0xab, 0xe6, 0x8c, 0x82, 0x8b, 0x2f, + 0xf8, 0xab, 0x75, 0x05, 0x8a, 0x2c, 0x4f, 0xe7, 0xec, 0x09, 0xc5, 0xf6, 0x9c, 0x16, 0x67, 0x1f, + 0x42, 0xc9, 0xeb, 0x61, 0x62, 0x51, 0x36, 0xf7, 0x49, 0xfe, 0xbc, 0xfe, 0xe4, 0x3d, 0x27, 0xb0, + 0x76, 0x18, 0x0c, 0x34, 0x94, 0x0c, 0xe6, 0x73, 0xe6, 0x13, 0x25, 0x54, 0xe0, 0x29, 0x65, 0x62, + 0x5d, 0x84, 0xfd, 0x59, 0x2c, 0x31, 0xa3, 0xba, 0x5e, 0x0b, 0xf3, 0x77, 0xf6, 0x24, 0x37, 0x68, + 0xdf, 0x6b, 0x61, 0x8e, 0xa7, 0xe0, 0x0b, 0xc1, 0x2a, 0x0a, 0x96, 0x8b, 0x2f, 0x38, 0xeb, 0x1e, + 0xcc, 0x04, 0x33, 0x35, 0x1b, 0x97, 0xec, 0x44, 0x28, 0x89, 0x77, 0x9d, 0x9c, 0xeb, 0x26, 0xa3, + 0xb1, 0x5e, 0xc1, 0x84, 0x65, 0x2f, 0x10, 0xbd, 0xe4, 0x94, 0x79, 0x2f, 0xdd, 0x86, 0x92, 0x32, + 0x67, 0x0a, 0x0a, 0xa7, 0x07, 0x2f, 0x0e, 0x0e, 0x5f, 0x1d, 0x54, 0xae, 0xa1, 0x12, 0x4c, 0x6e, + 0x6c, 0x6d, 0x6d, 0x6f, 0x89, 0x97, 0x7a, 0xed, 0xf0, 0x68, 0x6f, 0x7b, 0x4b, 0xbc, 0xd4, 0xb7, + 0xb6, 0x5f, 0x6e, 0x9f, 0x6c, 0x6f, 0x55, 0xc6, 0x51, 0x19, 0x8a, 0xfb, 0x87, 0x5b, 0x7b, 0x75, + 0xc6, 0x9a, 0x60, 0x2c, 0x63, 0xfb, 0x60, 0x63, 0x7f, 0x7b, 0xab, 0x32, 0x89, 0x2a, 0x50, 0x3e, + 0xf9, 0xfc, 0x68, 0xdb, 0xac, 0xed, 0x6e, 0x1c, 0xec, 0x6c, 0x6f, 0x55, 0xf2, 0xfa, 0x1f, 0x72, + 0x50, 0x3d, 0xc6, 0x16, 0x69, 0x76, 0xea, 0xb6, 0x83, 0xfd, 0xcd, 0x4b, 0x76, 0x9a, 0x5e, 0x3d, + 0xb8, 0xe7, 0x61, 0xf2, 0x4d, 0x1f, 0xcb, 0xe7, 0x42, 0xc9, 0x10, 0x8d, 0xe0, 0x11, 0x37, 0xae, + 0x1e, 0x71, 0x37, 0x20, 0xdf, 0xb6, 0x1d, 0x8a, 0x89, 0x58, 0x7e, 0x43, 0xb6, 0xf4, 0x4f, 0x60, + 0x29, 0xc5, 0x2a, 0xf5, 0xde, 0x6c, 0x33, 0x32, 0x8f, 0xe9, 0xb2, 0x21, 0x1a, 0xfa, 0x5f, 0x72, + 0x70, 0x33, 0x36, 0xa6, 0xe6, 0xb9, 0x14, 0xbb, 0xf4, 0xa7, 0x9b, 0xcc, 0x87, 0x50, 0x69, 0x76, + 0xfa, 0xee, 0x39, 0x66, 0x2f, 0x4f, 0x61, 0xab, 0xc4, 0xf8, 0xae, 0x4b, 0x7a, 0x78, 0x9e, 0x5c, + 0xc2, 0x72, 0xba, 0xad, 0x72, 0x8a, 0x55, 0x28, 0x74, 0x2d, 0xda, 0xec, 0x84, 0x93, 0x0c, 0x9a, + 0x68, 0x05, 0x80, 0x7f, 0x9a, 0x91, 0xdb, 0xbb, 0xc4, 0x29, 0x5b, 0x16, 0xb5, 0xd0, 0x6d, 0x28, + 0x63, 0xb7, 0x65, 0x7a, 0x6d, 0x93, 0xd3, 0x24, 0xf6, 0x08, 0xd8, 0x6d, 0x1d, 0xb6, 0xf7, 0x19, + 0x45, 0xff, 0x7d, 0x0e, 0xf2, 0x02, 0xb9, 0x0b, 0xf2, 0xf8, 0x5c, 0x98, 0xc7, 0xb3, 0x3d, 0xcc, + 0xaf, 0x59, 0x31, 0x53, 0xfe, 0x8d, 0xfe, 0x17, 0x96, 0xc2, 0x03, 0xd4, 0x23, 0xf6, 0x57, 0x3c, + 0x2c, 0xcd, 0x0e, 0xb6, 0x5a, 0x98, 0xc8, 0x13, 0x69, 0x31, 0x38, 0x50, 0x43, 0xfe, 0x2e, 0x67, + 0xa3, 0xfb, 0x30, 0xd3, 0xb5, 0x09, 0xf1, 0x88, 0x49, 0x70, 0xbb, 0x6b, 0xf5, 0xfc, 0xea, 0x04, + 0x4f, 0x05, 0xa7, 0x05, 0xd5, 0x10, 0x44, 0xfd, 0x73, 0x58, 0xd9, 0xc1, 0xf4, 0xb0, 0xf1, 0x0b, + 0xdc, 0xa4, 0x5b, 0x36, 0xc1, 0xcd, 0xd1, 0xa1, 0xd5, 0xff, 0x05, 0xb7, 0xb2, 0x44, 0x0f, 0x41, + 0xad, 0xff, 0x9c, 0x83, 0xf9, 0x9a, 0xe3, 0xb9, 0x98, 0xdd, 0x06, 0x47, 0x9e, 0x37, 0x82, 0x12, + 0xcd, 0x03, 0x98, 0xe8, 0xb1, 0xac, 0x7c, 0xe0, 0x01, 0x2d, 0x2c, 0xe3, 0x2a, 0x38, 0x1f, 0x3d, + 0x08, 0xe1, 0xe4, 0xf1, 0x54, 0x44, 0x56, 0x72, 0xf5, 0x45, 0x58, 0x18, 0xb0, 0x50, 0xc6, 0xd6, + 0x77, 0x39, 0x58, 0x8e, 0x71, 0xf6, 0x5c, 0x8a, 0x89, 0x6b, 0xfd, 0x84, 0x73, 0x48, 0x45, 0x0e, + 0xc6, 0x7f, 0x04, 0x72, 0xb0, 0x0a, 0x2b, 0x19, 0x53, 0x50, 0x60, 0x33, 0xf3, 0xc7, 0xdb, 0x51, + 0x83, 0xcd, 0x49, 0xa1, 0x52, 0xe1, 0x3b, 0xa6, 0xd0, 0xe5, 0xc7, 0xd0, 0xc8, 0x14, 0xf2, 0xfb, + 0x08, 0x3b, 0x16, 0xb5, 0xdf, 0x4a, 0x5c, 0x57, 0xe6, 0x00, 0x01, 0x91, 0x5d, 0x09, 0xc2, 0xaa, + 0x41, 0xcd, 0xd2, 0xaa, 0x5f, 0xe7, 0xd8, 0x53, 0xa6, 0xe7, 0xd8, 0xcd, 0xd1, 0xe2, 0xee, 0xe8, + 0x11, 0xe4, 0xc5, 0xa2, 0x0c, 0x01, 0x7c, 0x64, 0x0f, 0x7d, 0x05, 0x6e, 0xa6, 0xda, 0x20, 0x6d, + 0x3c, 0x85, 0xa5, 0xc3, 0x1e, 0xb5, 0xbb, 0x7c, 0xcf, 0x8d, 0x6e, 0xb1, 0x96, 0x41, 0x4b, 0x13, + 0x2b, 0x95, 0xfe, 0x75, 0x1c, 0x56, 0x22, 0x45, 0x8a, 0x57, 0x36, 0xed, 0x1c, 0x53, 0x8b, 0xf6, + 0x55, 0x7e, 0xb4, 0x0f, 0x53, 0x04, 0xb7, 0xcd, 0x7e, 0xaf, 0x65, 0xd1, 0x30, 0x3f, 0x7a, 0x1c, + 0xa8, 0x1e, 0x3a, 0x76, 0xed, 0x94, 0x0f, 0x62, 0xe6, 0xb4, 0xc5, 0xa7, 0xaf, 0x7d, 0x9b, 0x83, + 0xbc, 0xf8, 0x46, 0x9f, 0xc1, 0x94, 0x90, 0x6a, 0xd2, 0xcb, 0x9e, 0x38, 0x57, 0x66, 0xd6, 0x9f, + 0xfe, 0x18, 0xc9, 0x27, 0x97, 0x3d, 0x6c, 0x40, 0x3f, 0xfc, 0x66, 0xf7, 0x81, 0xdf, 0xef, 0x76, + 0xad, 0xf0, 0x12, 0x0a, 0x9a, 0x2c, 0x25, 0x91, 0x69, 0x64, 0x5b, 0x1e, 0xc6, 0x05, 0x91, 0x41, + 0xb6, 0xd1, 0x02, 0xe4, 0x79, 0xf2, 0xd8, 0x96, 0x97, 0xeb, 0x24, 0xcb, 0x1b, 0xdb, 0x02, 0x1f, + 0xb6, 0x7c, 0x99, 0x52, 0xf1, 0x7a, 0x15, 0x6b, 0xe9, 0xbf, 0xc9, 0x01, 0x28, 0xf5, 0x68, 0x11, + 0xe6, 0xea, 0x1b, 0xc7, 0x27, 0x66, 0xfd, 0xd0, 0x78, 0xb5, 0x61, 0x6c, 0x99, 0xa7, 0x47, 0x5b, + 0x1b, 0x27, 0xdb, 0x95, 0x6b, 0x68, 0x16, 0xa6, 0xeb, 0x87, 0x46, 0x6d, 0x3b, 0x24, 0xf1, 0x5c, + 0xe4, 0xc8, 0x38, 0x3d, 0xe0, 0xb9, 0xc8, 0x0c, 0xc0, 0xc9, 0xc6, 0x4e, 0xc0, 0x1b, 0x67, 0x09, + 0x48, 0x7d, 0xfb, 0xa4, 0xb6, 0xcb, 0xb3, 0x91, 0x59, 0x98, 0x16, 0x0c, 0xb3, 0xbe, 0xb1, 0xf7, + 0x92, 0xe7, 0x24, 0xd3, 0x50, 0x3a, 0x3d, 0x08, 0x13, 0x92, 0xf5, 0xef, 0x56, 0x79, 0x65, 0x3c, + 0x28, 0x2f, 0x8a, 0x5f, 0x0a, 0xd0, 0x17, 0x50, 0x19, 0xac, 0xea, 0xa3, 0xd5, 0x64, 0x98, 0xc4, + 0x7e, 0x22, 0xd0, 0x6e, 0x67, 0x77, 0x90, 0x51, 0x92, 0xff, 0xd7, 0x37, 0x0f, 0xc7, 0x8a, 0x63, + 0xe8, 0xcb, 0xa0, 0x1a, 0x1f, 0x29, 0xd5, 0xa3, 0xe8, 0xf0, 0xd4, 0x7f, 0x03, 0xb4, 0x3b, 0x43, + 0x7a, 0xc4, 0x34, 0xe4, 0xd0, 0x0b, 0x00, 0x55, 0x7b, 0x47, 0x4b, 0xf1, 0x81, 0x91, 0x7f, 0x00, + 0x34, 0x2d, 0x8d, 0x95, 0x14, 0xa6, 0x6a, 0xec, 0x4a, 0x58, 0xa2, 0x8c, 0xaf, 0x84, 0xa5, 0x94, + 0xe4, 0x03, 0x61, 0xaf, 0x60, 0x26, 0x5e, 0x0b, 0x47, 0x2b, 0x61, 0x8e, 0x9d, 0x56, 0xb1, 0xd7, + 0x6e, 0x65, 0xb1, 0x07, 0x04, 0x7f, 0x21, 0x51, 0xf4, 0x48, 0xd5, 0x5b, 0xad, 0x59, 0x46, 0x91, + 0x5d, 0xad, 0x59, 0x66, 0xc1, 0x3c, 0x62, 0x77, 0xbc, 0x0c, 0xad, 0xec, 0x4e, 0xad, 0x78, 0x2b, + 0xbb, 0xd3, 0xab, 0xd7, 0x61, 0x30, 0x34, 0x01, 0x25, 0xcb, 0xc7, 0x28, 0x5c, 0xeb, 0xcc, 0x6a, + 0xb6, 0xa6, 0x0f, 0xeb, 0x32, 0x60, 0xfd, 0x01, 0x4c, 0x45, 0x0e, 0x02, 0xa4, 0xa5, 0x9c, 0x0e, + 0x81, 0xd8, 0x9b, 0xa9, 0xbc, 0xa4, 0xb3, 0x07, 0x1f, 0xb2, 0xca, 0xd9, 0x19, 0x65, 0x59, 0xe5, + 0xec, 0xcc, 0x12, 0x6b, 0x20, 0x7e, 0x1f, 0x40, 0x55, 0xff, 0x54, 0xc4, 0x25, 0x6a, 0x9c, 0x2a, + 0xe2, 0x92, 0xc5, 0xc2, 0xc0, 0xc1, 0x4f, 0xb9, 0xb5, 0x83, 0xd5, 0x3c, 0x65, 0x6d, 0x46, 0xf1, + 0x50, 0x59, 0x9b, 0x55, 0x08, 0x8c, 0x6e, 0xe7, 0x44, 0x79, 0x4c, 0x6d, 0xe7, 0xac, 0xa2, 0xa0, + 0xda, 0xce, 0x99, 0xb5, 0xb5, 0xd0, 0x1f, 0xff, 0x03, 0x13, 0x75, 0xbf, 0x79, 0x8e, 0xe6, 0xc2, + 0x21, 0xaa, 0xb2, 0xa6, 0xcd, 0xc7, 0x89, 0x03, 0x43, 0xb7, 0xa1, 0x18, 0x14, 0x97, 0xd0, 0x62, + 0x2c, 0xda, 0x55, 0xa1, 0x4c, 0xab, 0x26, 0x19, 0x03, 0x62, 0x4e, 0x60, 0x3a, 0x56, 0x19, 0x42, + 0xcb, 0xa1, 0xd6, 0x94, 0x02, 0x95, 0xb6, 0x92, 0xc1, 0x1d, 0xf0, 0xdc, 0x0b, 0x00, 0x55, 0xb1, + 0x51, 0xeb, 0x9c, 0xa8, 0x2a, 0xa9, 0x75, 0x4e, 0x29, 0xf0, 0x04, 0x26, 0x36, 0x01, 0x25, 0x8b, + 0x2e, 0x6a, 0x23, 0x65, 0x16, 0x81, 0xd4, 0x46, 0xca, 0xae, 0xd9, 0x44, 0x77, 0x6b, 0xb2, 0x4c, + 0x12, 0x55, 0x92, 0x51, 0xb6, 0x89, 0x2a, 0xc9, 0xaa, 0xb2, 0x84, 0x4a, 0x48, 0xf2, 0xd7, 0x06, + 0x59, 0xde, 0x40, 0x0f, 0xb2, 0xf6, 0x50, 0xbc, 0xda, 0xa2, 0x7d, 0xf0, 0x83, 0xfd, 0x06, 0xbc, + 0x77, 0x0c, 0xe5, 0x68, 0x79, 0x03, 0xdd, 0x8c, 0x0b, 0x88, 0xe1, 0xc0, 0xda, 0x72, 0x3a, 0x33, + 0xb1, 0xf1, 0x7e, 0x09, 0x5a, 0x36, 0xc2, 0x8b, 0x3e, 0x1c, 0x66, 0x63, 0x5c, 0xe1, 0xa3, 0xf7, + 0xe9, 0x1a, 0x9f, 0xd1, 0xc3, 0x1c, 0xda, 0x85, 0x52, 0x58, 0x75, 0x40, 0xd5, 0xac, 0x9a, 0x89, + 0xb6, 0x94, 0xc2, 0x19, 0xf0, 0xce, 0x67, 0x50, 0x8e, 0x56, 0x11, 0x94, 0x77, 0x52, 0x0a, 0x18, + 0xca, 0x3b, 0xa9, 0x85, 0x87, 0xe8, 0x91, 0xac, 0x70, 0xe8, 0xc8, 0x91, 0x9c, 0x00, 0xbb, 0x23, + 0x47, 0x72, 0x12, 0xb8, 0x0e, 0x83, 0xa6, 0xc1, 0xff, 0x4e, 0x89, 0x83, 0xc7, 0x28, 0xfa, 0x7b, + 0x48, 0x2a, 0x5a, 0xad, 0x4e, 0xa1, 0x4c, 0xe4, 0x39, 0xb2, 0x9e, 0x5f, 0xc2, 0x6c, 0x02, 0x0d, + 0x56, 0x3a, 0xb2, 0xe0, 0x67, 0xa5, 0x23, 0x13, 0x4a, 0x0e, 0x67, 0xb1, 0x09, 0x05, 0xf9, 0x4f, + 0x19, 0xba, 0x11, 0x8e, 0x8a, 0xfd, 0xb0, 0xa6, 0x2d, 0x26, 0xe8, 0x03, 0x9e, 0x3d, 0x82, 0xa9, + 0x08, 0x54, 0x8c, 0xa2, 0x77, 0xc4, 0x00, 0x04, 0xac, 0x3c, 0x9b, 0x82, 0x2d, 0x47, 0xe6, 0xfd, + 0x2b, 0xf6, 0xc6, 0x1d, 0x02, 0xdc, 0xa2, 0x8f, 0x86, 0xc5, 0xe7, 0xa0, 0xd2, 0xc7, 0xef, 0xd7, + 0x79, 0x60, 0x56, 0x3f, 0x87, 0xe9, 0x18, 0x08, 0xa9, 0x4e, 0xe0, 0x34, 0xa4, 0x58, 0x9d, 0xc0, + 0xa9, 0xc8, 0x65, 0x64, 0x6e, 0xe7, 0x30, 0x9f, 0x86, 0x0d, 0xa1, 0xbb, 0x6a, 0x57, 0x64, 0xa2, + 0x5c, 0xda, 0xbd, 0xe1, 0x9d, 0x12, 0xca, 0x1a, 0x30, 0x9b, 0x00, 0xda, 0x54, 0x00, 0x65, 0x21, + 0x83, 0x2a, 0x80, 0x32, 0x51, 0xba, 0x88, 0x0e, 0x0c, 0x28, 0x59, 0x6e, 0x43, 0x91, 0xe4, 0x39, + 0xa3, 0xea, 0xa7, 0x8e, 0xe8, 0x21, 0xd5, 0x3a, 0x75, 0xb8, 0x34, 0x60, 0x36, 0x51, 0x61, 0x53, + 0x53, 0xc9, 0x2a, 0xe9, 0xa9, 0xa9, 0x64, 0x96, 0xe7, 0x22, 0x53, 0xf1, 0xe0, 0x46, 0x3a, 0x9a, + 0x84, 0xee, 0x47, 0x96, 0x37, 0x1b, 0xc8, 0xd2, 0x1e, 0xfc, 0x50, 0xb7, 0x81, 0xed, 0x77, 0x02, + 0xd3, 0x31, 0x20, 0x44, 0x05, 0x59, 0x1a, 0x3c, 0xa5, 0x82, 0x2c, 0x1d, 0x1a, 0x0a, 0x42, 0xd7, + 0x19, 0xc0, 0x8e, 0x02, 0x78, 0x05, 0xdd, 0x4b, 0x1d, 0x3f, 0x00, 0x20, 0x69, 0xf7, 0x7f, 0xa0, + 0x57, 0x32, 0x37, 0x1d, 0x84, 0x55, 0xa2, 0x8f, 0xb7, 0x54, 0x14, 0x27, 0xfa, 0x78, 0xcb, 0x40, + 0x64, 0x62, 0xe2, 0xe3, 0xf8, 0x48, 0x54, 0x7c, 0x2a, 0x66, 0x13, 0x15, 0x9f, 0x01, 0xad, 0x04, + 0xe2, 0xdb, 0x30, 0x97, 0x82, 0x6e, 0xa0, 0x48, 0x6c, 0x66, 0xc1, 0x2f, 0xda, 0xdd, 0xa1, 0x7d, + 0x92, 0xd9, 0x52, 0x12, 0xcf, 0x50, 0xbb, 0x24, 0x13, 0x42, 0x51, 0xbb, 0x64, 0x08, 0x1c, 0x12, + 0x28, 0x69, 0xc1, 0x42, 0x2a, 0xfe, 0x30, 0xf4, 0x01, 0x72, 0xff, 0xbd, 0xa0, 0x8b, 0x40, 0xc7, + 0xd3, 0xdc, 0xe6, 0xd3, 0xd7, 0x6c, 0x84, 0x63, 0x35, 0xd6, 0x9a, 0x5e, 0xf7, 0x89, 0xf8, 0xfc, + 0xd8, 0x23, 0x67, 0x4f, 0x84, 0x9c, 0x27, 0xfc, 0xf7, 0xff, 0x27, 0x67, 0x9e, 0x6c, 0xf7, 0x1a, + 0x8d, 0x3c, 0x27, 0x3d, 0xfb, 0x77, 0x00, 0x00, 0x00, 0xff, 0xff, 0x9b, 0x6f, 0x83, 0x54, 0x4f, + 0x30, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -4258,6 +4426,7 @@ type RepositoryServiceClient interface { RenameRepository(ctx context.Context, in *RenameRepositoryRequest, opts ...grpc.CallOption) (*RenameRepositoryResponse, error) ReplicateRepository(ctx context.Context, in *ReplicateRepositoryRequest, opts ...grpc.CallOption) (*ReplicateRepositoryResponse, error) OptimizeRepository(ctx context.Context, in *OptimizeRepositoryRequest, opts ...grpc.CallOption) (*OptimizeRepositoryResponse, error) + FetchRemoteWithStatus(ctx context.Context, in *FetchRemoteRequest, opts ...grpc.CallOption) (RepositoryService_FetchRemoteWithStatusClient, error) } type repositoryServiceClient struct { @@ -4880,6 +5049,38 @@ func (c *repositoryServiceClient) OptimizeRepository(ctx context.Context, in *Op return out, nil } +func (c *repositoryServiceClient) FetchRemoteWithStatus(ctx context.Context, in *FetchRemoteRequest, opts ...grpc.CallOption) (RepositoryService_FetchRemoteWithStatusClient, error) { + stream, err := c.cc.NewStream(ctx, &_RepositoryService_serviceDesc.Streams[10], "/gitaly.RepositoryService/FetchRemoteWithStatus", opts...) + if err != nil { + return nil, err + } + x := &repositoryServiceFetchRemoteWithStatusClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type RepositoryService_FetchRemoteWithStatusClient interface { + Recv() (*FetchRemoteWithStatusResponse, error) + grpc.ClientStream +} + +type repositoryServiceFetchRemoteWithStatusClient struct { + grpc.ClientStream +} + +func (x *repositoryServiceFetchRemoteWithStatusClient) Recv() (*FetchRemoteWithStatusResponse, error) { + m := new(FetchRemoteWithStatusResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + // RepositoryServiceServer is the server API for RepositoryService service. type RepositoryServiceServer interface { RepositoryExists(context.Context, *RepositoryExistsRequest) (*RepositoryExistsResponse, error) @@ -4924,6 +5125,7 @@ type RepositoryServiceServer interface { RenameRepository(context.Context, *RenameRepositoryRequest) (*RenameRepositoryResponse, error) ReplicateRepository(context.Context, *ReplicateRepositoryRequest) (*ReplicateRepositoryResponse, error) OptimizeRepository(context.Context, *OptimizeRepositoryRequest) (*OptimizeRepositoryResponse, error) + FetchRemoteWithStatus(*FetchRemoteRequest, RepositoryService_FetchRemoteWithStatusServer) error } // UnimplementedRepositoryServiceServer can be embedded to have forward compatible implementations. @@ -5056,6 +5258,9 @@ func (*UnimplementedRepositoryServiceServer) ReplicateRepository(ctx context.Con func (*UnimplementedRepositoryServiceServer) OptimizeRepository(ctx context.Context, req *OptimizeRepositoryRequest) (*OptimizeRepositoryResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method OptimizeRepository not implemented") } +func (*UnimplementedRepositoryServiceServer) FetchRemoteWithStatus(req *FetchRemoteRequest, srv RepositoryService_FetchRemoteWithStatusServer) error { + return status.Errorf(codes.Unimplemented, "method FetchRemoteWithStatus not implemented") +} func RegisterRepositoryServiceServer(s *grpc.Server, srv RepositoryServiceServer) { s.RegisterService(&_RepositoryService_serviceDesc, srv) @@ -5857,6 +6062,27 @@ func _RepositoryService_OptimizeRepository_Handler(srv interface{}, ctx context. return interceptor(ctx, in, info, handler) } +func _RepositoryService_FetchRemoteWithStatus_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(FetchRemoteRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(RepositoryServiceServer).FetchRemoteWithStatus(m, &repositoryServiceFetchRemoteWithStatusServer{stream}) +} + +type RepositoryService_FetchRemoteWithStatusServer interface { + Send(*FetchRemoteWithStatusResponse) error + grpc.ServerStream +} + +type repositoryServiceFetchRemoteWithStatusServer struct { + grpc.ServerStream +} + +func (x *repositoryServiceFetchRemoteWithStatusServer) Send(m *FetchRemoteWithStatusResponse) error { + return x.ServerStream.SendMsg(m) +} + var _RepositoryService_serviceDesc = grpc.ServiceDesc{ ServiceName: "gitaly.RepositoryService", HandlerType: (*RepositoryServiceServer)(nil), @@ -6041,6 +6267,11 @@ var _RepositoryService_serviceDesc = grpc.ServiceDesc{ Handler: _RepositoryService_BackupCustomHooks_Handler, ServerStreams: true, }, + { + StreamName: "FetchRemoteWithStatus", + Handler: _RepositoryService_FetchRemoteWithStatus_Handler, + ServerStreams: true, + }, }, Metadata: "repository-service.proto", } diff --git a/ruby/proto/gitaly/repository-service_pb.rb b/ruby/proto/gitaly/repository-service_pb.rb index c73dd9516ae..a7ee7a1d5f1 100644 --- a/ruby/proto/gitaly/repository-service_pb.rb +++ b/ruby/proto/gitaly/repository-service_pb.rb @@ -330,6 +330,25 @@ Google::Protobuf::DescriptorPool.generated_pool.build do end add_message "gitaly.OptimizeRepositoryResponse" do end + add_message "gitaly.FetchRemoteWithStatusResponse" do + repeated :ref_updates, :message, 1, "gitaly.FetchRemoteWithStatusResponse.Update" + end + add_message "gitaly.FetchRemoteWithStatusResponse.Update" do + optional :update_type, :enum, 1, "gitaly.FetchRemoteWithStatusResponse.UpdateType" + optional :summary, :string, 2 + optional :from_ref, :string, 3 + optional :to_ref, :string, 4 + optional :reason, :string, 5 + end + add_enum "gitaly.FetchRemoteWithStatusResponse.UpdateType" do + value :FAST_FORWARD_UPDATE, 0 + value :FORCED_UPDATE, 1 + value :PRUNED, 2 + value :TAG_UPDATE, 3 + value :FETCHED, 4 + value :UPDATE_FAILED, 5 + value :UNCHANGED, 6 + end end end @@ -423,4 +442,7 @@ module Gitaly ReplicateRepositoryResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.ReplicateRepositoryResponse").msgclass OptimizeRepositoryRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.OptimizeRepositoryRequest").msgclass OptimizeRepositoryResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.OptimizeRepositoryResponse").msgclass + FetchRemoteWithStatusResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.FetchRemoteWithStatusResponse").msgclass + FetchRemoteWithStatusResponse::Update = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.FetchRemoteWithStatusResponse.Update").msgclass + FetchRemoteWithStatusResponse::UpdateType = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.FetchRemoteWithStatusResponse.UpdateType").enummodule end diff --git a/ruby/proto/gitaly/repository-service_services_pb.rb b/ruby/proto/gitaly/repository-service_services_pb.rb index c5a28529b24..f9cb75b2ba7 100644 --- a/ruby/proto/gitaly/repository-service_services_pb.rb +++ b/ruby/proto/gitaly/repository-service_services_pb.rb @@ -56,6 +56,7 @@ module Gitaly rpc :RenameRepository, Gitaly::RenameRepositoryRequest, Gitaly::RenameRepositoryResponse rpc :ReplicateRepository, Gitaly::ReplicateRepositoryRequest, Gitaly::ReplicateRepositoryResponse rpc :OptimizeRepository, Gitaly::OptimizeRepositoryRequest, Gitaly::OptimizeRepositoryResponse + rpc :FetchRemoteWithStatus, Gitaly::FetchRemoteRequest, stream(Gitaly::FetchRemoteWithStatusResponse) end Stub = Service.rpc_stub_class -- GitLab From 1b6e7628d32bd5bf135efa97040f6ca671450fa6 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 3 Nov 2020 14:54:12 +0000 Subject: [PATCH 3/3] Implement RepositoryService.FetchRemoteWithStatus This RPC is identical to FetchRemote, but returns the list of updated references in a response stream. Useful if you want to know what was updated, and what was left alone, by the RPC. --- internal/git/fetch_scanner.go | 159 ++++++++++++++++++ internal/git/fetch_scanner_test.go | 81 +++++++++ internal/git/repository.go | 8 + .../gitaly/service/repository/fetch_remote.go | 114 ++++++++++++- .../service/repository/fetch_remote_test.go | 105 +++++++++++- internal/praefect/coordinator.go | 1 + .../protoregistry/protoregistry_test.go | 1 + 7 files changed, 462 insertions(+), 7 deletions(-) create mode 100644 internal/git/fetch_scanner.go create mode 100644 internal/git/fetch_scanner_test.go diff --git a/internal/git/fetch_scanner.go b/internal/git/fetch_scanner.go new file mode 100644 index 00000000000..c3bfd980fba --- /dev/null +++ b/internal/git/fetch_scanner.go @@ -0,0 +1,159 @@ +package git + +import ( + "bufio" + "bytes" + "io" + "strings" +) + +type RefUpdateType byte + +// type FetchStatusLine represents a line of status output from `git fetch`, as +// documented here: https://git-scm.com/docs/git-fetch/2.11.4#_output +// +// Note that the content of the `from` and `to` lines may be affected by the +// refspecs given to the `git fetch` command +type FetchStatusLine struct { + Type RefUpdateType + Summary string + From string + To string + Reason string +} + +const ( + RefUpdateTypeFastForwardUpdate RefUpdateType = ' ' + RefUpdateTypeForcedUpdate RefUpdateType = '+' + RefUpdateTypePruned RefUpdateType = '-' + RefUpdateTypeTagUpdate RefUpdateType = 't' + RefUpdateTypeFetched RefUpdateType = '*' + RefUpdateTypeUpdateFailed RefUpdateType = '!' + RefUpdateTypeUnchanged RefUpdateType = '=' +) + +var ( + validRefUpdateTypes = []RefUpdateType{ + RefUpdateTypeFastForwardUpdate, + RefUpdateTypeForcedUpdate, + RefUpdateTypePruned, + RefUpdateTypeTagUpdate, + RefUpdateTypeFetched, + RefUpdateTypeUpdateFailed, + RefUpdateTypeUnchanged, + } +) + +func (t RefUpdateType) Valid() bool { + for _, cmp := range validRefUpdateTypes { + if t == cmp { + return true + } + } + + return false +} + +// type FetchScanner scans the output of `git fetch`, allowing information about +// the updated refs to be gathered +type FetchScanner struct { + scanner *bufio.Scanner + lastErr error + lastLine FetchStatusLine +} + +func NewFetchScanner(r io.Reader) *FetchScanner { + return &FetchScanner{scanner: bufio.NewScanner(r)} +} + +func (f *FetchScanner) Scan() bool { + if f.lastErr != nil { + return false + } + + for f.scanner.Scan() { + // Silently ignore non-matching lines + line, ok := parseFetchStatusLine(f.scanner.Bytes()) + if !ok { + continue + } + + f.lastLine = line + return true + } + + f.lastErr = f.scanner.Err() + return false +} + +func (f *FetchScanner) Err() error { + return f.lastErr +} + +func (f *FetchScanner) StatusLine() FetchStatusLine { + return f.lastLine +} + +// line has this format: " -> []" +func parseFetchStatusLine(line []byte) (FetchStatusLine, bool) { + var blank FetchStatusLine + var out FetchStatusLine + + // Handle the flag very strictly, since status and non-status text mingle + if len(line) < 4 || line[0] != ' ' || line[2] != ' ' { + return blank, false + } + + out.Type, line = RefUpdateType(line[1]), line[3:] + if !out.Type.Valid() { + return blank, false + } + + // Get the summary, which may be composed of multiple words + if line[0] == '[' { + end := bytes.IndexByte(line, ']') + if end < 0 || len(line) <= end+2 { + return blank, false + } + + out.Summary, line = string(line[0:end+1]), line[end+1:] + } else { + end := bytes.IndexByte(line, ' ') + if end < 0 || len(line) <= end+1 { + return blank, false + } + + out.Summary, line = string(line[0:end]), line[end:] + } + + // Now we can scan by word for a bit + scanner := bufio.NewScanner(bytes.NewReader(line)) + scanner.Split(bufio.ScanWords) + + // From field + if !scanner.Scan() { + return blank, false + } + out.From = scanner.Text() + + // Hardcoded -> delimeter + if !scanner.Scan() || !bytes.Equal(scanner.Bytes(), []byte("->")) { + return blank, false + } + + // To field + if !scanner.Scan() { + return blank, false + } + out.To = scanner.Text() + + // Reason field - optional, the rest of the line. This implementation will + // squeeze multiple spaces into one, but that shouldn't be a big problem + var reason []string + for scanner.Scan() { + reason = append(reason, scanner.Text()) + } + out.Reason = strings.Join(reason, " ") + + return out, true +} diff --git a/internal/git/fetch_scanner_test.go b/internal/git/fetch_scanner_test.go new file mode 100644 index 00000000000..e1bc15e345b --- /dev/null +++ b/internal/git/fetch_scanner_test.go @@ -0,0 +1,81 @@ +package git + +import ( + "strconv" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestFetchScannerScan(t *testing.T) { + blank := FetchStatusLine{} + + for i, tc := range []struct { + data string + expected FetchStatusLine + success bool + }{ + {"", blank, false}, + {" ", blank, false}, + {"****", blank, false}, + {"* [new branch] foo -> upstream/foo", blank, false}, + {" * [new branch] foo -> upstream/foo", blank, false}, + {" * [new branch foo -> upstream/foo", blank, false}, + {" * new branch foo -> upstream/foo", blank, false}, + {" * [new branch] foo upstream/foo", blank, false}, + {" * [new branch] foo upstream/foo (some reason)", blank, false}, + { + " * [new branch] foo -> upstream/foo", + FetchStatusLine{RefUpdateTypeFetched, "[new branch]", "foo", "upstream/foo", ""}, + true, + }, + { + " * [new branch] 面 -> upstream/面", + FetchStatusLine{RefUpdateTypeFetched, "[new branch]", "面", "upstream/面", ""}, + true, + }, + { + " + d8b96a36c...d2a598d09 cgroups-impl -> upstream/cgroups-impl (forced update)", + FetchStatusLine{RefUpdateTypeForcedUpdate, "d8b96a36c...d2a598d09", "cgroups-impl", "upstream/cgroups-impl", "(forced update)"}, + true, + }, + { + " * [new tag] v13.7.0-rc1 -> v13.7.0-rc1", + FetchStatusLine{RefUpdateTypeFetched, "[new tag]", "v13.7.0-rc1", "v13.7.0-rc1", ""}, + true, + }, + { + " 87daf9d2e..1504b30e1 master -> upstream/master", + FetchStatusLine{RefUpdateTypeFastForwardUpdate, "87daf9d2e..1504b30e1", "master", "upstream/master", ""}, + true, + }, + { + " - [deleted] (none) -> upstream/foo", + FetchStatusLine{RefUpdateTypePruned, "[deleted]", "(none)", "upstream/foo", ""}, + true, + }, + { + " t d8b96a36c...d2a598d09 v1.2.3 -> v1.2.3", + FetchStatusLine{RefUpdateTypeTagUpdate, "d8b96a36c...d2a598d09", "v1.2.3", "v1.2.3", ""}, + true, + }, + { + " ! d8b96a36c...d2a598d09 foo -> upstream/foo (update hook failed)", + FetchStatusLine{RefUpdateTypeUpdateFailed, "d8b96a36c...d2a598d09", "foo", "upstream/foo", "(update hook failed)"}, + true, + }, + { + " = [up to date] foo -> upstream/foo", + FetchStatusLine{RefUpdateTypeUnchanged, "[up to date]", "foo", "upstream/foo", ""}, + true, + }, + } { + t.Run(strconv.Itoa(i), func(t *testing.T) { + // Regular run + scanner := NewFetchScanner(strings.NewReader(tc.data)) + require.Equal(t, tc.success, scanner.Scan()) + require.Equal(t, tc.expected, scanner.StatusLine()) + }) + } +} diff --git a/internal/git/repository.go b/internal/git/repository.go index e72f2e69d8f..b9bcd360fa7 100644 --- a/internal/git/repository.go +++ b/internal/git/repository.go @@ -64,6 +64,10 @@ type FetchOpts struct { // doesn't have the previous commit as an ancestor. // https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---force Force bool + // Verbose controls how much information is written to stderr. The list of + // refs updated by the fetch will only be listed if verbose is true. + // https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---verbose + Verbose bool // Tags controls whether tags will be fetched as part of the remote or not. // https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---tags // https://git-scm.com/docs/git-fetch#Documentation/git-fetch.txt---no-tags @@ -83,6 +87,10 @@ func (opts FetchOpts) buildFlags() []Option { flags = append(flags, Flag{Name: "--force"}) } + if opts.Verbose { + flags = append(flags, Flag{Name: "--verbose"}) + } + if opts.Tags != FetchOptsTagsDefault { flags = append(flags, Flag{Name: opts.Tags.String()}) } diff --git a/internal/gitaly/service/repository/fetch_remote.go b/internal/gitaly/service/repository/fetch_remote.go index 47f24072def..995fa518aa6 100644 --- a/internal/gitaly/service/repository/fetch_remote.go +++ b/internal/gitaly/service/repository/fetch_remote.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "io" "io/ioutil" "net/url" "os" @@ -11,6 +12,7 @@ import ( "strings" "time" + "github.com/golang/protobuf/proto" "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus/ctxlogrus" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" @@ -19,6 +21,7 @@ import ( "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/gitaly/rubyserver" "gitlab.com/gitlab-org/gitaly/internal/helper" + "gitlab.com/gitlab-org/gitaly/internal/helper/chunk" "gitlab.com/gitlab-org/gitaly/internal/metadata/featureflag" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" "google.golang.org/grpc/status" @@ -38,8 +41,55 @@ func init() { prometheus.MustRegister(fetchRemoteImplCounter) } +func (s *server) FetchRemoteWithStatus(in *gitalypb.FetchRemoteRequest, stream gitalypb.RepositoryService_FetchRemoteWithStatusServer) error { + ctx, cancel := context.WithCancel(stream.Context()) + defer cancel() + + sender := chunk.New(&fetchRemoteWithStatusSender{stream: stream}) + _, err := s.fetchRemote(ctx, in, func(line git.FetchStatusLine) { + updateType, ok := convertRefUpdateType(line.Type) + if !ok { + // FIXME: log an error here + cancel() + return + } + + // Only report refs that have changed for now + if updateType == gitalypb.FetchRemoteWithStatusResponse_UNCHANGED { + return + } + + update := &gitalypb.FetchRemoteWithStatusResponse_Update{ + UpdateType: updateType, + Summary: line.Summary, + FromRef: line.From, + ToRef: line.To, + Reason: line.Reason, + } + + if err := sender.Send(&gitalypb.FetchRemoteWithStatusResponse{RefUpdates: []*gitalypb.FetchRemoteWithStatusResponse_Update{update}}); err != nil { + // FIXME: log an error here + cancel() + } + }) + + if err != nil { + return err + } + + return sender.Flush() +} + func (s *server) FetchRemote(ctx context.Context, req *gitalypb.FetchRemoteRequest) (*gitalypb.FetchRemoteResponse, error) { + return s.fetchRemote(ctx, req, nil) +} + +func (s *server) fetchRemote(ctx context.Context, req *gitalypb.FetchRemoteRequest, refUpdatesFunc func(git.FetchStatusLine)) (*gitalypb.FetchRemoteResponse, error) { if featureflag.IsDisabled(ctx, featureflag.GoFetchRemote) { + if refUpdatesFunc != nil { + return nil, helper.Unimplemented + } + fetchRemoteImplCounter.WithLabelValues("ruby").Inc() client, err := s.ruby.RepositoryServiceClient(ctx) @@ -62,7 +112,33 @@ func (s *server) FetchRemote(ctx context.Context, req *gitalypb.FetchRemoteReque } var stderr bytes.Buffer - opts := git.FetchOpts{Stderr: &stderr, Force: req.Force, Prune: true, Tags: git.FetchOptsTagsAll} + opts := git.FetchOpts{ + Stderr: &stderr, + Force: req.Force, + Prune: true, + Tags: git.FetchOptsTagsAll, + } + + if refUpdatesFunc != nil { + pr, pw := io.Pipe() + + opts.Stderr = io.MultiWriter(&stderr, pw) + opts.Verbose = true + + go func() { + defer pr.Close() + defer pw.Close() + + scanner := git.NewFetchScanner(pr) + for scanner.Scan() { + refUpdatesFunc(scanner.StatusLine()) + } + + if err := scanner.Err(); err != nil { + logrus.Warnf("Scanner failed: %v", err) + } + }() + } if req.GetNoTags() { opts.Tags = git.FetchOptsTagsNone @@ -297,3 +373,39 @@ func (s *server) configureSSH(ctx context.Context, sshKey, knownHosts string) (s return "GIT_SSH_COMMAND=ssh " + strings.Join(conf, " "), cleanup, nil } + +type fetchRemoteWithStatusSender struct { + stream gitalypb.RepositoryService_FetchRemoteWithStatusServer + response *gitalypb.FetchRemoteWithStatusResponse +} + +func (s *fetchRemoteWithStatusSender) Reset() { s.response = &gitalypb.FetchRemoteWithStatusResponse{} } +func (s *fetchRemoteWithStatusSender) Send() error { return s.stream.Send(s.response) } +func (s *fetchRemoteWithStatusSender) Append(m proto.Message) { + s.response.RefUpdates = append(s.response.RefUpdates, m.(*gitalypb.FetchRemoteWithStatusResponse).RefUpdates...) +} + +func convertRefUpdateType(t git.RefUpdateType) (gitalypb.FetchRemoteWithStatusResponse_UpdateType, bool) { + var updateType gitalypb.FetchRemoteWithStatusResponse_UpdateType + + switch t { + case git.RefUpdateTypeFastForwardUpdate: + updateType = gitalypb.FetchRemoteWithStatusResponse_FAST_FORWARD_UPDATE + case git.RefUpdateTypeForcedUpdate: + updateType = gitalypb.FetchRemoteWithStatusResponse_FORCED_UPDATE + case git.RefUpdateTypePruned: + updateType = gitalypb.FetchRemoteWithStatusResponse_PRUNED + case git.RefUpdateTypeTagUpdate: + updateType = gitalypb.FetchRemoteWithStatusResponse_TAG_UPDATE + case git.RefUpdateTypeFetched: + updateType = gitalypb.FetchRemoteWithStatusResponse_FETCHED + case git.RefUpdateTypeUpdateFailed: + updateType = gitalypb.FetchRemoteWithStatusResponse_UPDATE_FAILED + case git.RefUpdateTypeUnchanged: + updateType = gitalypb.FetchRemoteWithStatusResponse_UNCHANGED + default: + return updateType, false + } + + return updateType, true +} diff --git a/internal/gitaly/service/repository/fetch_remote_test.go b/internal/gitaly/service/repository/fetch_remote_test.go index 586bd6e72c4..3d5f9f420d6 100644 --- a/internal/gitaly/service/repository/fetch_remote_test.go +++ b/internal/gitaly/service/repository/fetch_remote_test.go @@ -3,6 +3,7 @@ package repository import ( "context" "fmt" + "io" "io/ioutil" "net/http" "net/http/httptest" @@ -14,6 +15,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gitlab.com/gitlab-org/gitaly/internal/git" "gitlab.com/gitlab-org/gitaly/internal/gitaly/config" "gitlab.com/gitlab-org/gitaly/internal/helper/text" "gitlab.com/gitlab-org/gitaly/internal/metadata/featureflag" @@ -24,7 +26,7 @@ import ( "google.golang.org/grpc/metadata" ) -func copyRepoWithNewRemote(t *testing.T, repo *gitalypb.Repository, locator storage.Locator, remote string) *gitalypb.Repository { +func copyRepoWithNewRemote(t *testing.T, repo *gitalypb.Repository, locator storage.Locator, remote string) (*gitalypb.Repository, string) { repoPath, err := locator.GetRepoPath(repo) require.NoError(t, err) @@ -37,7 +39,7 @@ func copyRepoWithNewRemote(t *testing.T, repo *gitalypb.Repository, locator stor testhelper.MustRunCommand(t, nil, "git", "-C", clonePath, "remote", "add", remote, repoPath) - return cloneRepo + return cloneRepo, clonePath } func TestFetchRemoteSuccess(t *testing.T) { @@ -54,11 +56,9 @@ func TestFetchRemoteSuccess(t *testing.T) { testRepo, _, cleanupFn := testhelper.NewTestRepo(t) defer cleanupFn() - cloneRepo := copyRepoWithNewRemote(t, testRepo, locator, "my-remote") + cloneRepo, cloneRepoPath := copyRepoWithNewRemote(t, testRepo, locator, "my-remote") defer func() { - path, err := locator.GetRepoPath(cloneRepo) - require.NoError(t, err) - require.NoError(t, os.RemoveAll(path)) + require.NoError(t, os.RemoveAll(cloneRepoPath)) }() resp, err := client.FetchRemote(ctx, &gitalypb.FetchRemoteRequest{ @@ -71,6 +71,99 @@ func TestFetchRemoteSuccess(t *testing.T) { }) } +func TestFetchRemoteWithStatusSuccess(t *testing.T) { + locator := config.NewLocator(config.Config) + serverSocketPath, stop := runRepoServer(t, locator, testhelper.WithInternalSocket(config.Config)) + defer stop() + + client, conn := newRepositoryClient(t, serverSocketPath) + defer conn.Close() + + testRepo, testRepoPath, cleanupFn := testhelper.NewTestRepo(t) + defer cleanupFn() + + cloneRepo, cloneRepoPath := copyRepoWithNewRemote(t, testRepo, locator, "my-remote") + defer func() { + require.NoError(t, os.RemoveAll(cloneRepoPath)) + }() + + oldMasterSHA := "1e292f8" + + // Set up state for refs that will be overwritten + testhelper.CreateTag(t, cloneRepoPath, "modified-tag", "master", nil) + testhelper.CreateRemoteBranch(t, cloneRepoPath, "my-remote", "master", "master") + + // Make some updates to the source repo that we want to be pulled + newMasterSHA := testhelper.CreateCommit(t, testRepoPath, "master", nil) + newBranchSHA, newBranchName := testhelper.CreateCommitOnNewBranch(t, testRepoPath) + newTagSHA := testhelper.CreateTag(t, testRepoPath, "new-tag", newBranchSHA, nil) + modifiedTagSHA := testhelper.CreateTag(t, testRepoPath, "modified-tag", newBranchSHA, nil) + + stream, err := client.FetchRemoteWithStatus(context.Background(), &gitalypb.FetchRemoteRequest{ + Repository: cloneRepo, + Force: true, + Remote: "my-remote", + Timeout: 120, + }) + require.NoError(t, err) + + // Collect all status updates + var updates []*gitalypb.FetchRemoteWithStatusResponse_Update + for { + rsp, err := stream.Recv() + if rsp != nil { + updates = append(updates, rsp.GetRefUpdates()...) + } + + if err == io.EOF { + break + } + + require.NoError(t, err) + } + + gitCloneRepo := git.NewRepository(cloneRepo) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + newTagRef, err := gitCloneRepo.GetReference(ctx, "refs/tags/new-tag") + require.NoError(t, err, "New tag wasn't mirrored") + assert.Equal(t, newTagSHA, newTagRef.Target, "New tag has the wrong SHA") + assert.Contains(t, updates, refUpdateStruct('*', "[new tag]", "new-tag", "new-tag", "")) + + modifiedTagRef, err := gitCloneRepo.GetReference(ctx, "refs/tags/modified-tag") + require.NoError(t, err, "Modified tag wasn't mirrored") + assert.Equal(t, modifiedTagSHA, modifiedTagRef.Target, "Modified tag has the wrong SHA") + assert.Contains(t, updates, refUpdateStruct('t', "[tag update]", "modified-tag", "modified-tag", "")) + + masterRef, err := gitCloneRepo.GetReference(ctx, "refs/remotes/my-remote/master") + require.NoError(t, err, "Update to master wasn't mirrored") + assert.Equal(t, newMasterSHA, masterRef.Target) + assert.Contains(t, updates, refUpdateStruct('+', shortRevRange(oldMasterSHA, newMasterSHA), "master", "my-remote/master", "(forced update)")) + + newBranchRef, err := gitCloneRepo.GetReference(ctx, "refs/remotes/my-remote/"+newBranchName) + require.NoError(t, err, "New branch "+newBranchName+" wasn't mirrored") + assert.Equal(t, newBranchSHA, newBranchRef.Target) + assert.Contains(t, updates, refUpdateStruct('*', "[new branch]", newBranchName, "my-remote/"+newBranchName, "")) +} + +func refUpdateStruct(updateType byte, summary, from, to, reason string) *gitalypb.FetchRemoteWithStatusResponse_Update { + realUpdateType, _ := convertRefUpdateType(git.RefUpdateType(updateType)) + + return &gitalypb.FetchRemoteWithStatusResponse_Update{ + UpdateType: realUpdateType, + Summary: summary, + FromRef: from, + ToRef: to, + Reason: reason, + } +} + +func shortRevRange(from, to string) string { + return fmt.Sprintf("%s...%s", from[0:7], to[0:7]) +} + func TestFetchRemoteFailure(t *testing.T) { repo, _, cleanup := testhelper.NewTestRepo(t) defer cleanup() diff --git a/internal/praefect/coordinator.go b/internal/praefect/coordinator.go index ad549f75e38..3884b144dc2 100644 --- a/internal/praefect/coordinator.go +++ b/internal/praefect/coordinator.go @@ -68,6 +68,7 @@ var transactionRPCs = map[string]transactionsCondition{ "/gitaly.RepositoryService/CreateRepositoryFromSnapshot": transactionsFlag(featureflag.TxCreateRepositoryFromSnapshot), "/gitaly.RepositoryService/CreateRepositoryFromURL": transactionsFlag(featureflag.TxCreateRepositoryFromURL), "/gitaly.RepositoryService/FetchRemote": transactionsFlag(featureflag.TxFetchRemote), + "/gitaly.RepositoryService/FetchRemoteWithStatus": transactionsFlag(featureflag.TxFetchRemote), "/gitaly.RepositoryService/FetchSourceBranch": transactionsFlag(featureflag.TxFetchSourceBranch), "/gitaly.RepositoryService/ReplicateRepository": transactionsFlag(featureflag.TxReplicateRepository), "/gitaly.RepositoryService/WriteRef": transactionsFlag(featureflag.TxWriteRef), diff --git a/internal/praefect/protoregistry/protoregistry_test.go b/internal/praefect/protoregistry/protoregistry_test.go index 795ab3df97f..52e0e33cbb2 100644 --- a/internal/praefect/protoregistry/protoregistry_test.go +++ b/internal/praefect/protoregistry/protoregistry_test.go @@ -122,6 +122,7 @@ func TestNewProtoRegistry(t *testing.T) { "RepositorySize": protoregistry.OpAccessor, "ApplyGitattributes": protoregistry.OpMutator, "FetchRemote": protoregistry.OpMutator, + "FetchRemoteWithStatus": protoregistry.OpMutator, "CreateRepository": protoregistry.OpMutator, "GetArchive": protoregistry.OpAccessor, "HasLocalBranches": protoregistry.OpAccessor, -- GitLab