From 253b99a1b578825e348baf678fa57c0c866b27de Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Fri, 15 Nov 2024 23:27:20 +0100 Subject: [PATCH 1/8] api: introduce `PromotionRetry` with `Attempts` cfg Signed-off-by: Hidde Beydals --- api/v1alpha1/generated.pb.go | 690 +++++++++++------- api/v1alpha1/generated.proto | 16 + api/v1alpha1/promotion_types.go | 23 + api/v1alpha1/promotion_types_test.go | 39 + api/v1alpha1/zz_generated.deepcopy.go | 20 + .../crds/kargo.akuity.io_promotions.yaml | 16 + .../crds/kargo.akuity.io_stages.yaml | 16 + .../promotions.kargo.akuity.io_v1alpha1.json | 13 + .../stages.kargo.akuity.io_v1alpha1.json | 13 + ui/src/gen/v1alpha1/generated_pb.ts | 56 ++ 10 files changed, 657 insertions(+), 245 deletions(-) create mode 100644 api/v1alpha1/promotion_types_test.go diff --git a/api/v1alpha1/generated.pb.go b/api/v1alpha1/generated.pb.go index aca238da8..d39689325 100644 --- a/api/v1alpha1/generated.pb.go +++ b/api/v1alpha1/generated.pb.go @@ -1094,10 +1094,38 @@ func (m *PromotionReference) XXX_DiscardUnknown() { var xxx_messageInfo_PromotionReference proto.InternalMessageInfo +func (m *PromotionRetry) Reset() { *m = PromotionRetry{} } +func (*PromotionRetry) ProtoMessage() {} +func (*PromotionRetry) Descriptor() ([]byte, []int) { + return fileDescriptor_e26b7f7bbc391025, []int{38} +} +func (m *PromotionRetry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PromotionRetry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *PromotionRetry) XXX_Merge(src proto.Message) { + xxx_messageInfo_PromotionRetry.Merge(m, src) +} +func (m *PromotionRetry) XXX_Size() int { + return m.Size() +} +func (m *PromotionRetry) XXX_DiscardUnknown() { + xxx_messageInfo_PromotionRetry.DiscardUnknown(m) +} + +var xxx_messageInfo_PromotionRetry proto.InternalMessageInfo + func (m *PromotionSpec) Reset() { *m = PromotionSpec{} } func (*PromotionSpec) ProtoMessage() {} func (*PromotionSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{38} + return fileDescriptor_e26b7f7bbc391025, []int{39} } func (m *PromotionSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1125,7 +1153,7 @@ var xxx_messageInfo_PromotionSpec proto.InternalMessageInfo func (m *PromotionStatus) Reset() { *m = PromotionStatus{} } func (*PromotionStatus) ProtoMessage() {} func (*PromotionStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{39} + return fileDescriptor_e26b7f7bbc391025, []int{40} } func (m *PromotionStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1153,7 +1181,7 @@ var xxx_messageInfo_PromotionStatus proto.InternalMessageInfo func (m *PromotionStep) Reset() { *m = PromotionStep{} } func (*PromotionStep) ProtoMessage() {} func (*PromotionStep) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{40} + return fileDescriptor_e26b7f7bbc391025, []int{41} } func (m *PromotionStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1181,7 +1209,7 @@ var xxx_messageInfo_PromotionStep proto.InternalMessageInfo func (m *PromotionTemplate) Reset() { *m = PromotionTemplate{} } func (*PromotionTemplate) ProtoMessage() {} func (*PromotionTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{41} + return fileDescriptor_e26b7f7bbc391025, []int{42} } func (m *PromotionTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1209,7 +1237,7 @@ var xxx_messageInfo_PromotionTemplate proto.InternalMessageInfo func (m *PromotionTemplateSpec) Reset() { *m = PromotionTemplateSpec{} } func (*PromotionTemplateSpec) ProtoMessage() {} func (*PromotionTemplateSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{42} + return fileDescriptor_e26b7f7bbc391025, []int{43} } func (m *PromotionTemplateSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1237,7 +1265,7 @@ var xxx_messageInfo_PromotionTemplateSpec proto.InternalMessageInfo func (m *PromotionVariable) Reset() { *m = PromotionVariable{} } func (*PromotionVariable) ProtoMessage() {} func (*PromotionVariable) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{43} + return fileDescriptor_e26b7f7bbc391025, []int{44} } func (m *PromotionVariable) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1265,7 +1293,7 @@ var xxx_messageInfo_PromotionVariable proto.InternalMessageInfo func (m *RepoSubscription) Reset() { *m = RepoSubscription{} } func (*RepoSubscription) ProtoMessage() {} func (*RepoSubscription) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{44} + return fileDescriptor_e26b7f7bbc391025, []int{45} } func (m *RepoSubscription) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1293,7 +1321,7 @@ var xxx_messageInfo_RepoSubscription proto.InternalMessageInfo func (m *Stage) Reset() { *m = Stage{} } func (*Stage) ProtoMessage() {} func (*Stage) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{45} + return fileDescriptor_e26b7f7bbc391025, []int{46} } func (m *Stage) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1321,7 +1349,7 @@ var xxx_messageInfo_Stage proto.InternalMessageInfo func (m *StageList) Reset() { *m = StageList{} } func (*StageList) ProtoMessage() {} func (*StageList) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{46} + return fileDescriptor_e26b7f7bbc391025, []int{47} } func (m *StageList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1349,7 +1377,7 @@ var xxx_messageInfo_StageList proto.InternalMessageInfo func (m *StageSpec) Reset() { *m = StageSpec{} } func (*StageSpec) ProtoMessage() {} func (*StageSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{47} + return fileDescriptor_e26b7f7bbc391025, []int{48} } func (m *StageSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1377,7 +1405,7 @@ var xxx_messageInfo_StageSpec proto.InternalMessageInfo func (m *StageStatus) Reset() { *m = StageStatus{} } func (*StageStatus) ProtoMessage() {} func (*StageStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{48} + return fileDescriptor_e26b7f7bbc391025, []int{49} } func (m *StageStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1405,7 +1433,7 @@ var xxx_messageInfo_StageStatus proto.InternalMessageInfo func (m *Verification) Reset() { *m = Verification{} } func (*Verification) ProtoMessage() {} func (*Verification) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{49} + return fileDescriptor_e26b7f7bbc391025, []int{50} } func (m *Verification) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1433,7 +1461,7 @@ var xxx_messageInfo_Verification proto.InternalMessageInfo func (m *VerificationInfo) Reset() { *m = VerificationInfo{} } func (*VerificationInfo) ProtoMessage() {} func (*VerificationInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{50} + return fileDescriptor_e26b7f7bbc391025, []int{51} } func (m *VerificationInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1461,7 +1489,7 @@ var xxx_messageInfo_VerificationInfo proto.InternalMessageInfo func (m *VerifiedStage) Reset() { *m = VerifiedStage{} } func (*VerifiedStage) ProtoMessage() {} func (*VerifiedStage) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{51} + return fileDescriptor_e26b7f7bbc391025, []int{52} } func (m *VerifiedStage) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1489,7 +1517,7 @@ var xxx_messageInfo_VerifiedStage proto.InternalMessageInfo func (m *Warehouse) Reset() { *m = Warehouse{} } func (*Warehouse) ProtoMessage() {} func (*Warehouse) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{52} + return fileDescriptor_e26b7f7bbc391025, []int{53} } func (m *Warehouse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1517,7 +1545,7 @@ var xxx_messageInfo_Warehouse proto.InternalMessageInfo func (m *WarehouseList) Reset() { *m = WarehouseList{} } func (*WarehouseList) ProtoMessage() {} func (*WarehouseList) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{53} + return fileDescriptor_e26b7f7bbc391025, []int{54} } func (m *WarehouseList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1545,7 +1573,7 @@ var xxx_messageInfo_WarehouseList proto.InternalMessageInfo func (m *WarehouseSpec) Reset() { *m = WarehouseSpec{} } func (*WarehouseSpec) ProtoMessage() {} func (*WarehouseSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{54} + return fileDescriptor_e26b7f7bbc391025, []int{55} } func (m *WarehouseSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1573,7 +1601,7 @@ var xxx_messageInfo_WarehouseSpec proto.InternalMessageInfo func (m *WarehouseStatus) Reset() { *m = WarehouseStatus{} } func (*WarehouseStatus) ProtoMessage() {} func (*WarehouseStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{55} + return fileDescriptor_e26b7f7bbc391025, []int{56} } func (m *WarehouseStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1642,6 +1670,7 @@ func init() { proto.RegisterType((*PromotionList)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionList") proto.RegisterType((*PromotionPolicy)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionPolicy") proto.RegisterType((*PromotionReference)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionReference") + proto.RegisterType((*PromotionRetry)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionRetry") proto.RegisterType((*PromotionSpec)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionSpec") proto.RegisterType((*PromotionStatus)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionStatus") proto.RegisterType((*PromotionStep)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionStep") @@ -1667,233 +1696,236 @@ func init() { } var fileDescriptor_e26b7f7bbc391025 = []byte{ - // 3604 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5b, 0x4b, 0x6c, 0x1b, 0xc7, - 0xdd, 0xf7, 0x92, 0x12, 0x25, 0xfe, 0xa9, 0xe7, 0x58, 0x4e, 0x14, 0xe5, 0x8b, 0xe4, 0x6f, 0x13, - 0x04, 0xc9, 0x97, 0x84, 0xfa, 0xfc, 0x8a, 0x1f, 0x69, 0x5d, 0x88, 0x94, 0x1f, 0x72, 0x95, 0x58, - 0x1d, 0x3a, 0x76, 0xea, 0xd8, 0x48, 0x47, 0xe4, 0x88, 0xdc, 0x8a, 0xdc, 0x65, 0x76, 0x96, 0x4a, - 0xd4, 0x16, 0x6d, 0xd2, 0x07, 0x10, 0xa0, 0x68, 0xd1, 0x43, 0xd0, 0xa4, 0x40, 0x0b, 0x14, 0xed, - 0xb9, 0x05, 0x7a, 0xee, 0x21, 0x87, 0x5e, 0x82, 0x22, 0x28, 0x82, 0xb6, 0x87, 0x1c, 0x02, 0xa1, - 0x51, 0x80, 0x1e, 0x73, 0xeb, 0xc5, 0x40, 0x81, 0x62, 0x1e, 0xbb, 0x3b, 0xbb, 0x5c, 0x5a, 0x5c, - 0x5a, 0x32, 0x8c, 0xde, 0xc8, 0xf9, 0xcf, 0xfc, 0xfe, 0xf3, 0xf8, 0xbf, 0x67, 0x16, 0x4e, 0xd6, - 0x2d, 0xaf, 0xd1, 0x59, 0x2f, 0x56, 0x9d, 0xd6, 0x22, 0xd9, 0xec, 0x58, 0xde, 0xf6, 0xe2, 0x26, - 0x71, 0xeb, 0xce, 0x22, 0x69, 0x5b, 0x8b, 0x5b, 0xc7, 0x48, 0xb3, 0xdd, 0x20, 0xc7, 0x16, 0xeb, - 0xd4, 0xa6, 0x2e, 0xf1, 0x68, 0xad, 0xd8, 0x76, 0x1d, 0xcf, 0x41, 0x4f, 0x84, 0xa3, 0x8a, 0x72, - 0x54, 0x51, 0x8c, 0x2a, 0x92, 0xb6, 0x55, 0xf4, 0x47, 0xcd, 0x3d, 0xa7, 0x61, 0xd7, 0x9d, 0xba, - 0xb3, 0x28, 0x06, 0xaf, 0x77, 0x36, 0xc4, 0x3f, 0xf1, 0x47, 0xfc, 0x92, 0xa0, 0x73, 0x97, 0x37, - 0xcf, 0xb0, 0xa2, 0x25, 0x38, 0xd3, 0x37, 0x3d, 0x6a, 0x33, 0xcb, 0xb1, 0xd9, 0x73, 0xa4, 0x6d, - 0x31, 0xea, 0x6e, 0x51, 0x77, 0xb1, 0xbd, 0x59, 0xe7, 0x34, 0x16, 0xed, 0xb0, 0xb8, 0xd5, 0x35, - 0xbd, 0xb9, 0x93, 0x21, 0x52, 0x8b, 0x54, 0x1b, 0x96, 0x4d, 0xdd, 0xed, 0x70, 0x78, 0x8b, 0x7a, - 0x24, 0x69, 0xd4, 0x62, 0xaf, 0x51, 0x6e, 0xc7, 0xf6, 0xac, 0x16, 0xed, 0x1a, 0xf0, 0xfc, 0x5e, - 0x03, 0x58, 0xb5, 0x41, 0x5b, 0x24, 0x3e, 0xce, 0xbc, 0x05, 0x87, 0x97, 0x6c, 0xd2, 0xdc, 0x66, - 0x16, 0xc3, 0x1d, 0x7b, 0xc9, 0xad, 0x77, 0x5a, 0xd4, 0xf6, 0xd0, 0x51, 0x18, 0xb2, 0x49, 0x8b, - 0xce, 0x1a, 0x47, 0x8d, 0xa7, 0xf2, 0xa5, 0xb1, 0x0f, 0x77, 0x16, 0x0e, 0xed, 0xee, 0x2c, 0x0c, - 0xbd, 0x44, 0x5a, 0x14, 0x0b, 0x0a, 0x7a, 0x1c, 0x86, 0xb7, 0x48, 0xb3, 0x43, 0x67, 0x33, 0xa2, - 0xcb, 0xb8, 0xea, 0x32, 0x7c, 0x9d, 0x37, 0x62, 0x49, 0x33, 0x7f, 0x90, 0x8d, 0xc0, 0xbf, 0x48, - 0x3d, 0x52, 0x23, 0x1e, 0x41, 0x2d, 0xc8, 0x35, 0xc9, 0x3a, 0x6d, 0xb2, 0x59, 0xe3, 0x68, 0xf6, - 0xa9, 0xc2, 0xf1, 0x0b, 0xc5, 0x7e, 0x0e, 0xb1, 0x98, 0x00, 0x55, 0x5c, 0x15, 0x38, 0x17, 0x6c, - 0xcf, 0xdd, 0x2e, 0x4d, 0xa8, 0x49, 0xe4, 0x64, 0x23, 0x56, 0x4c, 0xd0, 0xdb, 0x06, 0x14, 0x88, - 0x6d, 0x3b, 0x1e, 0xf1, 0xf8, 0x31, 0xcd, 0x66, 0x04, 0xd3, 0x2b, 0x83, 0x33, 0x5d, 0x0a, 0xc1, - 0x24, 0xe7, 0xc3, 0x8a, 0x73, 0x41, 0xa3, 0x60, 0x9d, 0xe7, 0xdc, 0x59, 0x28, 0x68, 0x53, 0x45, - 0x53, 0x90, 0xdd, 0xa4, 0xdb, 0x72, 0x7f, 0x31, 0xff, 0x89, 0x66, 0x22, 0x1b, 0xaa, 0x76, 0xf0, - 0x5c, 0xe6, 0x8c, 0x31, 0x77, 0x1e, 0xa6, 0xe2, 0x0c, 0xd3, 0x8c, 0x37, 0x7f, 0x6a, 0xc0, 0x8c, - 0xb6, 0x0a, 0x4c, 0x37, 0xa8, 0x4b, 0xed, 0x2a, 0x45, 0x8b, 0x90, 0xe7, 0x67, 0xc9, 0xda, 0xa4, - 0xea, 0x1f, 0xf5, 0xb4, 0x5a, 0x48, 0xfe, 0x25, 0x9f, 0x80, 0xc3, 0x3e, 0x81, 0x58, 0x64, 0xee, - 0x26, 0x16, 0xed, 0x06, 0x61, 0x74, 0x36, 0x1b, 0x15, 0x8b, 0x35, 0xde, 0x88, 0x25, 0xcd, 0xfc, - 0x32, 0x3c, 0xe2, 0xcf, 0xe7, 0x1a, 0x6d, 0xb5, 0x9b, 0xc4, 0xa3, 0xe1, 0xa4, 0xf6, 0x14, 0x3d, - 0x73, 0x12, 0xc6, 0x97, 0xda, 0x6d, 0xd7, 0xd9, 0xa2, 0xb5, 0x8a, 0x47, 0xea, 0xd4, 0xfc, 0xbe, - 0x01, 0x47, 0x96, 0xdc, 0xba, 0x53, 0x5e, 0x5e, 0x6a, 0xb7, 0x2f, 0x53, 0xd2, 0xf4, 0x1a, 0x15, - 0x8f, 0x78, 0x1d, 0x86, 0xce, 0x43, 0x8e, 0x89, 0x5f, 0x0a, 0xee, 0x49, 0x5f, 0x42, 0x24, 0xfd, - 0xce, 0xce, 0xc2, 0x4c, 0xc2, 0x40, 0x8a, 0xd5, 0x28, 0xf4, 0x34, 0x8c, 0xb4, 0x28, 0x63, 0xa4, - 0xee, 0xaf, 0x79, 0x52, 0x01, 0x8c, 0xbc, 0x28, 0x9b, 0xb1, 0x4f, 0x37, 0xff, 0x9c, 0x81, 0xc9, - 0x00, 0x4b, 0xb1, 0x3f, 0x80, 0x0d, 0xee, 0xc0, 0x58, 0x43, 0x5b, 0xa1, 0xd8, 0xe7, 0xc2, 0xf1, - 0x17, 0xfa, 0x94, 0xe5, 0xa4, 0x4d, 0x2a, 0xcd, 0x28, 0x36, 0x63, 0x7a, 0x2b, 0x8e, 0xb0, 0x41, - 0x2d, 0x00, 0xb6, 0x6d, 0x57, 0x15, 0xd3, 0x21, 0xc1, 0xf4, 0x6c, 0x4a, 0xa6, 0x95, 0x00, 0xa0, - 0x84, 0x14, 0x4b, 0x08, 0xdb, 0xb0, 0xc6, 0xc0, 0xfc, 0xbd, 0x01, 0x87, 0x13, 0xc6, 0xa1, 0x2f, - 0xc5, 0xce, 0xf3, 0x89, 0xae, 0xf3, 0x44, 0x5d, 0xc3, 0xc2, 0xd3, 0x7c, 0x16, 0x46, 0x5d, 0xba, - 0x65, 0x71, 0x5b, 0xad, 0x76, 0x78, 0x4a, 0x8d, 0x1f, 0xc5, 0xaa, 0x1d, 0x07, 0x3d, 0xd0, 0x33, - 0x90, 0xf7, 0x7f, 0xf3, 0x6d, 0xce, 0x72, 0x71, 0xe6, 0x07, 0xe7, 0x77, 0x65, 0x38, 0xa4, 0x9b, - 0xdf, 0x83, 0xe1, 0x72, 0x83, 0xb8, 0x1e, 0x97, 0x18, 0x97, 0xb6, 0x9d, 0x97, 0xf1, 0xaa, 0x9a, - 0x62, 0x20, 0x31, 0x58, 0x36, 0x63, 0x9f, 0xde, 0xc7, 0x61, 0x3f, 0x0d, 0x23, 0x5b, 0xd4, 0x15, - 0xf3, 0xcd, 0x46, 0xc1, 0xae, 0xcb, 0x66, 0xec, 0xd3, 0xcd, 0xbf, 0x19, 0x30, 0x23, 0x66, 0xb0, - 0x6c, 0xb1, 0xaa, 0xb3, 0x45, 0xdd, 0x6d, 0x4c, 0x59, 0xa7, 0xb9, 0xcf, 0x13, 0x5a, 0x86, 0x29, - 0x46, 0x5b, 0x5b, 0xd4, 0x2d, 0x3b, 0x36, 0xf3, 0x5c, 0x62, 0xd9, 0x9e, 0x9a, 0xd9, 0xac, 0xea, - 0x3d, 0x55, 0x89, 0xd1, 0x71, 0xd7, 0x08, 0xf4, 0x14, 0x8c, 0xaa, 0x69, 0x73, 0x51, 0xe2, 0x1b, - 0x3b, 0xc6, 0xcf, 0x40, 0xad, 0x89, 0xe1, 0x80, 0x6a, 0xfe, 0xd3, 0x80, 0x69, 0xb1, 0xaa, 0x4a, - 0x67, 0x9d, 0x55, 0x5d, 0xab, 0xcd, 0x4d, 0xe0, 0x83, 0xb8, 0xa4, 0xf3, 0x30, 0x51, 0xf3, 0x37, - 0x7e, 0xd5, 0x6a, 0x59, 0x9e, 0xd0, 0x91, 0xe1, 0xd2, 0x43, 0x0a, 0x63, 0x62, 0x39, 0x42, 0xc5, - 0xb1, 0xde, 0xe6, 0x2f, 0xb3, 0x70, 0xd8, 0xef, 0x42, 0x6b, 0x4b, 0xae, 0x67, 0x6d, 0x90, 0xaa, - 0xc7, 0x50, 0x0d, 0xc6, 0x6a, 0x61, 0xb3, 0xa7, 0x34, 0xef, 0xff, 0x8a, 0xd2, 0xdd, 0x17, 0x75, - 0x77, 0x5f, 0x6c, 0x6f, 0xd6, 0x79, 0x03, 0x2b, 0xf2, 0xa8, 0xa2, 0xb8, 0x75, 0xac, 0x78, 0xcd, - 0x6a, 0xd1, 0x50, 0xbb, 0x35, 0x78, 0x0f, 0x47, 0x50, 0xd1, 0x0d, 0xc8, 0xd6, 0x2d, 0x4f, 0x39, - 0xe3, 0x33, 0xfd, 0xa9, 0xf5, 0x25, 0x2b, 0x2e, 0x6a, 0xa5, 0x82, 0x62, 0x95, 0xbd, 0x64, 0x79, - 0x98, 0x23, 0xa2, 0x75, 0xc8, 0x59, 0x2d, 0x52, 0xa7, 0xbe, 0xcf, 0x3d, 0xd7, 0x1f, 0xf6, 0x0a, - 0x1f, 0x13, 0x47, 0x0f, 0xbc, 0xbb, 0xa0, 0x32, 0xac, 0x90, 0x39, 0x8f, 0x2a, 0x17, 0x11, 0xa9, - 0xa4, 0x7d, 0xf3, 0x48, 0x52, 0x96, 0x90, 0x87, 0xa0, 0x32, 0xac, 0x90, 0xcd, 0x4f, 0x32, 0x30, - 0x15, 0xee, 0x5f, 0xd9, 0x69, 0xb5, 0x2c, 0x0f, 0xcd, 0x41, 0xc6, 0xaa, 0x29, 0x09, 0x04, 0x35, - 0x30, 0xb3, 0xb2, 0x8c, 0x33, 0x56, 0x0d, 0x3d, 0x09, 0xb9, 0x75, 0x97, 0xd8, 0xd5, 0x86, 0x92, - 0xbc, 0x00, 0xb8, 0x24, 0x5a, 0xb1, 0xa2, 0xa2, 0xc7, 0x20, 0xeb, 0x91, 0xba, 0x12, 0xb8, 0x60, - 0xff, 0xae, 0x91, 0x3a, 0xe6, 0xed, 0x5c, 0xd2, 0x59, 0x67, 0xfd, 0x9b, 0xb4, 0x2a, 0x4f, 0x5e, - 0x93, 0xf4, 0x8a, 0x6c, 0xc6, 0x3e, 0x9d, 0x73, 0x24, 0x1d, 0xaf, 0xe1, 0xb8, 0xb3, 0xc3, 0x51, - 0x8e, 0x4b, 0xa2, 0x15, 0x2b, 0x2a, 0xf7, 0x49, 0x55, 0x31, 0x7f, 0x8f, 0xba, 0xb3, 0xb9, 0xa8, - 0x4f, 0x2a, 0xfb, 0x04, 0x1c, 0xf6, 0x41, 0xb7, 0xa1, 0x50, 0x75, 0x29, 0xf1, 0x1c, 0x77, 0x99, - 0x78, 0x74, 0x76, 0x24, 0xb5, 0x04, 0x4e, 0xf2, 0xc0, 0xa8, 0x1c, 0x42, 0x60, 0x1d, 0xcf, 0xfc, - 0xc2, 0x80, 0xd9, 0x70, 0x6b, 0xc5, 0xd9, 0x86, 0xc1, 0x80, 0xda, 0x1e, 0xa3, 0xc7, 0xf6, 0x3c, - 0x09, 0xb9, 0x9a, 0x55, 0xa7, 0xcc, 0x8b, 0xef, 0xf2, 0xb2, 0x68, 0xc5, 0x8a, 0x8a, 0x8e, 0x03, - 0xd4, 0x2d, 0x4f, 0x19, 0x07, 0xb5, 0xd9, 0x81, 0x0b, 0xba, 0x14, 0x50, 0xb0, 0xd6, 0x0b, 0xdd, - 0x80, 0xbc, 0x98, 0xe6, 0x80, 0x6a, 0x27, 0x5c, 0x45, 0xd9, 0x07, 0xc0, 0x21, 0x96, 0xf9, 0xf1, - 0x10, 0x8c, 0x5c, 0x74, 0xa9, 0x55, 0x6f, 0x78, 0xe8, 0x1b, 0x30, 0xda, 0x52, 0x41, 0xa5, 0x58, - 0x64, 0xe1, 0xf8, 0xff, 0xf7, 0xc7, 0xe3, 0xaa, 0x38, 0x74, 0x1e, 0x90, 0x86, 0x0b, 0x09, 0xdb, - 0x70, 0x80, 0xca, 0x03, 0x32, 0xd2, 0xb4, 0x08, 0x13, 0xe7, 0xa6, 0x05, 0x64, 0x4b, 0xbc, 0x11, - 0x4b, 0x1a, 0x7a, 0x15, 0x72, 0x8e, 0x6b, 0xd5, 0x2d, 0x7b, 0x36, 0x2f, 0x26, 0x71, 0xa2, 0x3f, - 0x15, 0x52, 0xab, 0xb8, 0x2a, 0x86, 0x86, 0x9b, 0x2f, 0xff, 0x63, 0x05, 0x89, 0x6e, 0xc2, 0x88, - 0x14, 0x26, 0x5f, 0x41, 0x17, 0xfb, 0x36, 0x30, 0x52, 0x1e, 0x43, 0xa1, 0x97, 0xff, 0x19, 0xf6, - 0x01, 0x51, 0x25, 0xb0, 0x2f, 0x43, 0x02, 0xfa, 0x99, 0x14, 0xf6, 0xa5, 0xa7, 0x41, 0xa9, 0x04, - 0x06, 0x65, 0x38, 0x0d, 0xa8, 0x30, 0x19, 0xbd, 0x2c, 0x08, 0xdf, 0x62, 0x15, 0xb9, 0xe4, 0x06, - 0xd8, 0x62, 0x15, 0x36, 0x4d, 0x44, 0xc3, 0x1d, 0x3f, 0xb0, 0x31, 0xdf, 0xcd, 0xc2, 0xb4, 0xea, - 0x59, 0x76, 0x9a, 0x4d, 0x5a, 0x15, 0x6e, 0x52, 0xda, 0xa7, 0x6c, 0xa2, 0x7d, 0xb2, 0x60, 0xd8, - 0xf2, 0x68, 0xcb, 0x4f, 0xc0, 0x4a, 0xa9, 0x66, 0x13, 0xf2, 0x28, 0xae, 0x70, 0x10, 0x99, 0x03, - 0x05, 0xa7, 0xa4, 0x7a, 0x61, 0xc9, 0x01, 0xfd, 0xc8, 0x80, 0xc3, 0x5b, 0xd4, 0xb5, 0x36, 0xac, - 0xaa, 0xc8, 0x60, 0x2e, 0x5b, 0xcc, 0x73, 0xdc, 0x6d, 0xe5, 0x11, 0x9e, 0xef, 0x8f, 0xf3, 0x75, - 0x0d, 0x60, 0xc5, 0xde, 0x70, 0x4a, 0x8f, 0x2a, 0x6e, 0x87, 0xaf, 0x77, 0x43, 0xe3, 0x24, 0x7e, - 0x73, 0x6d, 0x80, 0x70, 0xb6, 0x09, 0x09, 0xd4, 0xaa, 0x9e, 0x40, 0xf5, 0x3d, 0x31, 0x7f, 0xb1, - 0xbe, 0xc9, 0xd2, 0x13, 0xaf, 0x0f, 0x0c, 0x28, 0x28, 0xfa, 0xaa, 0xc5, 0x3c, 0x74, 0xab, 0x4b, - 0xdb, 0x8b, 0xfd, 0x69, 0x3b, 0x1f, 0x2d, 0x74, 0x3d, 0x88, 0x57, 0xfd, 0x16, 0x4d, 0xd3, 0xb1, - 0x7f, 0xa4, 0x72, 0x63, 0x9f, 0x4b, 0x35, 0xff, 0xd0, 0x30, 0x88, 0x3d, 0x52, 0x67, 0x67, 0xba, - 0x30, 0x1e, 0x51, 0x72, 0x74, 0x0a, 0x86, 0x36, 0x2d, 0xdb, 0xf7, 0x7a, 0xff, 0xeb, 0xc7, 0x53, - 0x5f, 0xb5, 0xec, 0xda, 0x9d, 0x9d, 0x85, 0xe9, 0x48, 0x67, 0xde, 0x88, 0x45, 0xf7, 0xbd, 0xc3, - 0xb0, 0x73, 0xa3, 0xef, 0xff, 0x7a, 0xe1, 0xd0, 0x5b, 0x9f, 0x1e, 0x3d, 0x64, 0xbe, 0x97, 0x85, - 0xa9, 0xf8, 0xae, 0xf6, 0x51, 0x90, 0x08, 0x6d, 0xd8, 0xe8, 0x81, 0xda, 0xb0, 0xcc, 0xc1, 0xd9, - 0xb0, 0xec, 0x41, 0xd8, 0xb0, 0xa1, 0x7d, 0xb3, 0x61, 0xe6, 0x5f, 0x0c, 0x98, 0x08, 0x4e, 0xe6, - 0xf5, 0x0e, 0xf7, 0xac, 0xe1, 0xae, 0x1b, 0xfb, 0xbf, 0xeb, 0xaf, 0xc1, 0x08, 0x73, 0x3a, 0x6e, - 0x55, 0x84, 0x8f, 0x1c, 0xfd, 0x64, 0x3a, 0xa3, 0x29, 0xc7, 0x6a, 0x31, 0x93, 0x6c, 0xc0, 0x3e, - 0xaa, 0x79, 0x2b, 0x58, 0x8f, 0x22, 0xc9, 0x88, 0xc2, 0xe5, 0xf1, 0x16, 0x5f, 0xcf, 0xa8, 0x1e, - 0x51, 0xf0, 0x56, 0xac, 0xa8, 0xc8, 0x14, 0xe6, 0xdc, 0x0f, 0x6c, 0xf3, 0x25, 0x50, 0x56, 0x59, - 0x9c, 0x81, 0xa4, 0x98, 0x5f, 0x64, 0x03, 0xed, 0x51, 0xe9, 0xeb, 0x1b, 0x00, 0xd2, 0x32, 0xd1, - 0xda, 0x8a, 0xad, 0x4c, 0x6f, 0x79, 0x00, 0x47, 0xa0, 0xcc, 0x21, 0x47, 0x91, 0xb6, 0x37, 0x88, - 0x01, 0x42, 0x02, 0xd6, 0x58, 0xa1, 0x6f, 0x43, 0x81, 0xa8, 0x92, 0xc9, 0x45, 0xc7, 0x55, 0x32, - 0xbc, 0x3c, 0x08, 0xe7, 0xa5, 0x10, 0x26, 0x5e, 0xfa, 0x0a, 0x29, 0x58, 0xe7, 0x36, 0xe7, 0xc2, - 0x64, 0x6c, 0xbe, 0x09, 0xd6, 0x77, 0x25, 0x6a, 0x7d, 0x4f, 0xa4, 0x71, 0x0b, 0xaa, 0x0e, 0xa4, - 0xd7, 0xcc, 0x18, 0x4c, 0xc5, 0x67, 0xba, 0x6f, 0x4c, 0x23, 0xc5, 0x27, 0xdd, 0xde, 0xff, 0x2a, - 0x03, 0xf9, 0x40, 0xe3, 0xd3, 0x64, 0xa9, 0xd2, 0x53, 0x67, 0xf6, 0xc8, 0x24, 0xb2, 0xfd, 0x64, - 0x12, 0x43, 0xbd, 0x33, 0x09, 0xbf, 0x92, 0x95, 0xbb, 0x7b, 0x25, 0x4b, 0xcb, 0x24, 0x46, 0xfa, - 0xcf, 0x24, 0x46, 0xf7, 0xce, 0x24, 0xcc, 0xdf, 0x18, 0x80, 0xba, 0xd3, 0xc6, 0x34, 0x1b, 0x45, - 0xe2, 0x76, 0xb8, 0x4f, 0x2f, 0x1d, 0xcf, 0xdd, 0x7a, 0x9b, 0x63, 0xf3, 0x83, 0x61, 0x98, 0xbc, - 0x64, 0x0d, 0x5c, 0x70, 0xf0, 0xe0, 0x61, 0x89, 0x54, 0xa1, 0x2a, 0x46, 0xaa, 0x78, 0x2e, 0xf1, - 0x68, 0x7d, 0x5b, 0x9d, 0xef, 0x39, 0x35, 0xf4, 0xe1, 0x72, 0x72, 0xb7, 0x3b, 0xbd, 0x49, 0xb8, - 0x17, 0x74, 0xdf, 0x42, 0xf2, 0x02, 0x8c, 0x33, 0xcf, 0xb5, 0xaa, 0x9e, 0x2c, 0x69, 0xb0, 0xd9, - 0x82, 0xb0, 0x72, 0x47, 0x54, 0xf7, 0xf1, 0x8a, 0x4e, 0xc4, 0xd1, 0xbe, 0x89, 0x95, 0x92, 0xa1, - 0xd4, 0x95, 0x92, 0x45, 0xc8, 0x93, 0x66, 0xd3, 0x79, 0xe3, 0x1a, 0xa9, 0x33, 0x95, 0xaa, 0x06, - 0x52, 0xb3, 0xe4, 0x13, 0x70, 0xd8, 0x07, 0x15, 0x01, 0xac, 0xba, 0xed, 0xb8, 0x54, 0x8c, 0xc8, - 0x09, 0x73, 0x3b, 0xc1, 0x6d, 0xdd, 0x4a, 0xd0, 0x8a, 0xb5, 0x1e, 0xa8, 0x02, 0x47, 0x2c, 0x9b, - 0xd1, 0x6a, 0xc7, 0xa5, 0x95, 0x4d, 0xab, 0x7d, 0x6d, 0xb5, 0x22, 0xac, 0xc4, 0xb6, 0x90, 0xe6, - 0xd1, 0xd2, 0x63, 0x8a, 0xd9, 0x91, 0x95, 0xa4, 0x4e, 0x38, 0x79, 0x2c, 0x3a, 0x09, 0x63, 0x96, - 0x5d, 0x6d, 0x76, 0x6a, 0x74, 0x8d, 0x78, 0x0d, 0x36, 0x3b, 0x2a, 0xa6, 0x31, 0xb5, 0xbb, 0xb3, - 0x30, 0xb6, 0xa2, 0xb5, 0xe3, 0x48, 0x2f, 0x3e, 0x8a, 0xbe, 0xa9, 0x8d, 0xca, 0x87, 0xa3, 0x2e, - 0xbc, 0xa9, 0x8f, 0xd2, 0x7b, 0x25, 0xd4, 0x92, 0x20, 0x55, 0x2d, 0xe9, 0xe7, 0x59, 0xc8, 0xc9, - 0x52, 0x2e, 0x3a, 0x15, 0xab, 0x97, 0x3e, 0xd6, 0x55, 0x2f, 0x2d, 0x24, 0x95, 0xbd, 0x4d, 0xc8, - 0x59, 0x8c, 0x75, 0xa2, 0xde, 0x6d, 0x45, 0xb4, 0x60, 0x45, 0x41, 0x16, 0x00, 0xf1, 0x4b, 0xad, - 0x7e, 0xe8, 0x72, 0x2a, 0x6d, 0x45, 0x38, 0x56, 0x0d, 0x0e, 0x08, 0x0c, 0x6b, 0xe0, 0xa2, 0xc2, - 0xe3, 0xd8, 0x1b, 0x56, 0x5d, 0xe5, 0xe1, 0xe7, 0xb5, 0xa8, 0x39, 0xbc, 0x7d, 0x7b, 0x2d, 0xb8, - 0x9e, 0x0b, 0x03, 0xe8, 0x48, 0x07, 0x1e, 0x49, 0x5f, 0xa9, 0x5c, 0x7d, 0x49, 0x2e, 0xa7, 0x2c, - 0x10, 0xb1, 0x42, 0xe6, 0x3c, 0x9c, 0x8e, 0xd7, 0xee, 0x78, 0x42, 0x26, 0xf7, 0x89, 0xc7, 0x55, - 0x81, 0x88, 0x15, 0xb2, 0xf9, 0x9e, 0x01, 0x93, 0x72, 0xbb, 0xcb, 0x0d, 0x5a, 0xdd, 0xac, 0x78, - 0xb4, 0xcd, 0x03, 0xdb, 0x0e, 0xa3, 0x2c, 0x1e, 0xd8, 0xbe, 0xcc, 0x28, 0xc3, 0x82, 0xa2, 0xad, - 0x3e, 0x73, 0x50, 0xab, 0x37, 0x7f, 0x67, 0xc0, 0xb0, 0x88, 0x20, 0xd3, 0x98, 0xba, 0x68, 0x55, - 0x25, 0xd3, 0x57, 0x55, 0x65, 0x8f, 0x7a, 0x57, 0x58, 0xd0, 0x19, 0xba, 0x5b, 0x41, 0xc7, 0xfc, - 0xdc, 0x80, 0x99, 0xa4, 0x22, 0x61, 0x9a, 0xe9, 0x3f, 0x0b, 0xa3, 0xed, 0x26, 0xf1, 0x36, 0x1c, - 0xb7, 0x15, 0xbf, 0x0d, 0x58, 0x53, 0xed, 0x38, 0xe8, 0x81, 0x5c, 0x00, 0xd7, 0xcf, 0x46, 0x7c, - 0x71, 0x3f, 0x9f, 0xd6, 0xf9, 0x44, 0xab, 0x5b, 0xe1, 0x66, 0x05, 0x4d, 0x0c, 0x6b, 0x5c, 0xcc, - 0x1f, 0x0f, 0xc3, 0xb4, 0x18, 0x32, 0xa8, 0x33, 0x1a, 0xe4, 0x84, 0xda, 0xf0, 0x90, 0xc8, 0x21, - 0xba, 0xfd, 0x97, 0x3c, 0xb4, 0x33, 0x6a, 0xfc, 0x43, 0x2b, 0x89, 0xbd, 0xee, 0xf4, 0xa4, 0xe0, - 0x1e, 0xb8, 0xdd, 0x4e, 0x09, 0xfe, 0xfb, 0x9c, 0x92, 0x2e, 0x6c, 0x23, 0x7b, 0x0a, 0x5b, 0x4f, - 0x17, 0x36, 0x7a, 0x0f, 0x2e, 0xac, 0xdb, 0xad, 0xe4, 0x53, 0xb9, 0x95, 0x5f, 0x64, 0x60, 0x64, - 0xcd, 0x75, 0x44, 0xb1, 0xf9, 0xe0, 0xeb, 0x96, 0x57, 0x61, 0x88, 0xb5, 0x69, 0x55, 0xd9, 0xbc, - 0x63, 0xfd, 0x69, 0x9a, 0x9a, 0x5e, 0xa5, 0x4d, 0xab, 0xa5, 0x51, 0x6e, 0x46, 0xf9, 0x2f, 0x2c, - 0x80, 0xb4, 0x02, 0x5c, 0x36, 0x4d, 0xb0, 0xef, 0x43, 0xde, 0xbd, 0x00, 0xf7, 0x81, 0x01, 0x05, - 0xd5, 0xf3, 0x81, 0xad, 0xf4, 0xa8, 0xf9, 0xf5, 0xa8, 0xf4, 0xfc, 0x24, 0x5c, 0x01, 0xdf, 0x34, - 0xf4, 0x5d, 0x98, 0x6e, 0xbb, 0x4e, 0xcb, 0xe1, 0x9a, 0xba, 0xe6, 0x34, 0xad, 0xaa, 0x45, 0xfd, - 0x62, 0xe1, 0xa9, 0xbe, 0xf9, 0x69, 0xc3, 0xb7, 0x4b, 0x8f, 0x28, 0xbe, 0xd3, 0x6b, 0x71, 0x5c, - 0xdc, 0xcd, 0xca, 0xfc, 0xbb, 0x01, 0xe3, 0x91, 0xbd, 0x47, 0x55, 0x80, 0xaa, 0x63, 0xd7, 0x2c, - 0x2f, 0xb8, 0x90, 0x2d, 0x1c, 0x5f, 0xec, 0x6f, 0x57, 0xcb, 0xfe, 0xb8, 0x50, 0xe8, 0x82, 0x26, - 0x86, 0x35, 0x58, 0x74, 0xc2, 0x7f, 0xbf, 0x10, 0x8d, 0x97, 0xe4, 0xfb, 0x85, 0x3b, 0x3b, 0x0b, - 0x63, 0x6a, 0x4e, 0xfa, 0x7b, 0x86, 0x34, 0xaf, 0x04, 0x7e, 0x9b, 0x81, 0x7c, 0xb0, 0xfe, 0xfb, - 0xa0, 0x46, 0x2f, 0x47, 0xd4, 0xe8, 0x44, 0xca, 0x93, 0x13, 0x8a, 0x14, 0xc4, 0x24, 0x9a, 0x32, - 0xdd, 0x8e, 0x29, 0x53, 0x5a, 0x91, 0xd8, 0x43, 0x9d, 0xfe, 0x24, 0x0f, 0x5f, 0xf6, 0xbd, 0x0f, - 0x0a, 0x75, 0x2d, 0xaa, 0x50, 0x8b, 0x29, 0x57, 0xd3, 0x43, 0xa5, 0xde, 0x31, 0x60, 0x32, 0xa6, - 0x04, 0xe8, 0x71, 0x18, 0x16, 0xd5, 0x21, 0x25, 0x5f, 0xc1, 0x40, 0x55, 0x4b, 0x10, 0x34, 0xb4, - 0x06, 0x33, 0xa4, 0xe3, 0x39, 0xc1, 0xd8, 0x0b, 0x36, 0x59, 0x6f, 0x52, 0x59, 0x20, 0x18, 0x2d, - 0xfd, 0x8f, 0x1a, 0x33, 0xb3, 0x94, 0xd0, 0x07, 0x27, 0x8e, 0x34, 0x3f, 0xca, 0x00, 0x0a, 0x1a, - 0xd3, 0x54, 0x55, 0x6f, 0xc3, 0xc8, 0x86, 0xac, 0xff, 0xdc, 0x5b, 0x59, 0xbc, 0x54, 0xd0, 0x6f, - 0x06, 0x7c, 0x4c, 0xf4, 0xf5, 0xfd, 0x91, 0x23, 0xe8, 0x96, 0x21, 0x74, 0x13, 0x60, 0xc3, 0xb2, - 0x2d, 0xd6, 0x18, 0xf0, 0x02, 0x4f, 0x78, 0xf3, 0x8b, 0x01, 0x02, 0xd6, 0xd0, 0xcc, 0x77, 0x33, - 0x9a, 0x7c, 0x0a, 0x73, 0xd9, 0xd7, 0xb9, 0x3e, 0x1d, 0xdd, 0xcc, 0x7c, 0xf7, 0x95, 0x89, 0xb6, - 0x31, 0x43, 0x5b, 0xc4, 0xf5, 0xab, 0xb7, 0xa7, 0x53, 0x6e, 0xcb, 0x75, 0xe2, 0x5a, 0xfc, 0xe0, - 0xc3, 0x23, 0xbd, 0x4e, 0x5c, 0x86, 0x05, 0x24, 0x7a, 0x85, 0x4f, 0x95, 0x06, 0x39, 0x5b, 0x6a, - 0x9b, 0xe0, 0xd1, 0xb6, 0xbe, 0x3e, 0xda, 0x66, 0x58, 0x02, 0x9a, 0x6f, 0xe7, 0x34, 0x81, 0x57, - 0x56, 0xfb, 0x0a, 0xa0, 0x26, 0x61, 0xde, 0x65, 0x62, 0xd7, 0xb8, 0x78, 0xd2, 0x0d, 0x97, 0xb2, - 0x86, 0x8a, 0xd0, 0xe6, 0x14, 0x0a, 0x5a, 0xed, 0xea, 0x81, 0x13, 0x46, 0xa1, 0x53, 0x51, 0xe3, - 0xbc, 0x10, 0x37, 0xce, 0x13, 0xa1, 0xb6, 0x0d, 0x66, 0x9e, 0x75, 0x71, 0x1f, 0x3e, 0x00, 0x71, - 0xff, 0x0e, 0x4c, 0x6f, 0xc4, 0xaf, 0xd0, 0xd4, 0x85, 0xfa, 0xe9, 0x01, 0x6f, 0xe0, 0x4a, 0x47, - 0x76, 0xc3, 0x7b, 0x97, 0xb0, 0x19, 0x77, 0x33, 0x42, 0x8e, 0xff, 0x74, 0x4c, 0x64, 0x9f, 0xb2, - 0x86, 0xd1, 0xb7, 0xca, 0xc5, 0xf2, 0xd6, 0xf8, 0xa3, 0x31, 0x09, 0x89, 0x23, 0x0c, 0x62, 0x2a, - 0x98, 0xdb, 0x4f, 0x15, 0x44, 0xa7, 0xa0, 0x50, 0xed, 0xb8, 0x2e, 0xb5, 0x3d, 0x3e, 0x1d, 0x11, - 0xca, 0x66, 0xc3, 0x5a, 0x74, 0x39, 0x24, 0x61, 0xbd, 0x1f, 0x7a, 0x4d, 0xe8, 0xa9, 0x47, 0x45, - 0x8e, 0x71, 0xef, 0xb9, 0x74, 0x5e, 0xe9, 0xb8, 0x27, 0x75, 0xdc, 0xa3, 0xe6, 0x1f, 0x74, 0xd7, - 0xd5, 0x67, 0x86, 0x3f, 0x07, 0x19, 0xc2, 0xe2, 0xe5, 0xdf, 0x25, 0x86, 0x33, 0x44, 0xcf, 0xfe, - 0xb3, 0x07, 0x96, 0xfd, 0xbb, 0x10, 0xc6, 0x64, 0xfe, 0x83, 0x4c, 0x74, 0x5b, 0x45, 0x0e, 0x46, - 0x9a, 0x07, 0x86, 0x5d, 0x30, 0xbd, 0x22, 0x08, 0xf3, 0x23, 0x03, 0x8e, 0x24, 0xf6, 0x0e, 0x4c, - 0x5f, 0xe6, 0x00, 0x4d, 0x9f, 0xb1, 0xdf, 0xa6, 0xef, 0xa6, 0xb6, 0x85, 0xfe, 0x14, 0xf6, 0xeb, - 0x15, 0xf5, 0xfb, 0x19, 0x98, 0xe2, 0xd9, 0x79, 0xa4, 0x0a, 0xb0, 0xe6, 0x3f, 0xd9, 0x4a, 0xe1, - 0x36, 0x63, 0x65, 0xed, 0xd2, 0x48, 0xe4, 0xad, 0xd6, 0x2b, 0x30, 0x2c, 0x12, 0x74, 0xe5, 0xe8, - 0x4f, 0xa7, 0xb8, 0x86, 0x8c, 0xa0, 0x0a, 0x9d, 0x90, 0x95, 0x0e, 0x09, 0xc8, 0x91, 0xc5, 0x0d, - 0xa2, 0x12, 0xe1, 0xd3, 0x29, 0xee, 0x22, 0xbb, 0x91, 0x45, 0x33, 0x96, 0x80, 0xe6, 0x7b, 0x19, - 0x90, 0x2e, 0xf6, 0x3e, 0x84, 0xd2, 0x5f, 0x8b, 0x84, 0xd2, 0x7d, 0xc6, 0x88, 0x62, 0x72, 0x3d, - 0xc3, 0xe8, 0x78, 0xf8, 0x73, 0x2c, 0x0d, 0xe8, 0xdd, 0x43, 0xe8, 0x3f, 0x1a, 0x90, 0x17, 0xfd, - 0xee, 0x43, 0xf8, 0xbc, 0x16, 0x0d, 0x9f, 0x9f, 0x49, 0xb1, 0x8a, 0x1e, 0xa1, 0xf3, 0xbb, 0x59, - 0x35, 0xfb, 0x20, 0xb8, 0x6a, 0x10, 0xb7, 0xa6, 0xc2, 0x86, 0x50, 0x03, 0x79, 0x23, 0x96, 0x34, - 0xf4, 0x2d, 0x98, 0x72, 0xe5, 0xa5, 0x34, 0xad, 0x5d, 0x0c, 0x7c, 0x78, 0x36, 0xf5, 0xad, 0xb1, - 0xba, 0xd9, 0x0e, 0xcb, 0x47, 0x38, 0x86, 0x8a, 0xbb, 0xf8, 0x70, 0xbf, 0xde, 0x8e, 0xdb, 0x32, - 0xe5, 0xef, 0x4e, 0x0f, 0x68, 0x38, 0xa5, 0x5f, 0xef, 0x6a, 0xc6, 0xdd, 0x8c, 0x50, 0x03, 0xc6, - 0xf4, 0xf7, 0x2e, 0x4a, 0x96, 0x8e, 0xa7, 0x7f, 0x58, 0x23, 0x6f, 0x26, 0xf4, 0x16, 0x1c, 0x41, - 0x36, 0x77, 0x72, 0x50, 0xd0, 0x84, 0x2f, 0x96, 0x92, 0x8f, 0x1f, 0x4c, 0x4a, 0x9e, 0x1c, 0x41, - 0x16, 0x06, 0x8a, 0x20, 0x8f, 0x45, 0x23, 0xc8, 0x47, 0xe3, 0x11, 0x24, 0x88, 0xd5, 0x45, 0xa2, - 0x47, 0x06, 0x13, 0x2a, 0x94, 0xf2, 0x1f, 0x2e, 0xa5, 0x8a, 0xc9, 0xbb, 0x03, 0x36, 0xb4, 0xbb, - 0xb3, 0xe0, 0x3f, 0x3b, 0xf0, 0x1f, 0x2c, 0xc5, 0x58, 0xa0, 0xf3, 0x01, 0xd3, 0x4a, 0xa7, 0xd5, - 0x22, 0xee, 0xf6, 0xec, 0x98, 0x98, 0x70, 0x50, 0xab, 0xbb, 0x18, 0xa1, 0xe2, 0x58, 0x6f, 0xb4, - 0x06, 0x39, 0x19, 0x89, 0xa9, 0xc7, 0x30, 0xcf, 0xa6, 0x09, 0xf2, 0x64, 0x8c, 0x20, 0x7f, 0x63, - 0x85, 0xa3, 0x07, 0xd1, 0xf9, 0x3d, 0x82, 0xe8, 0x2b, 0x80, 0x9c, 0x75, 0x11, 0x8d, 0xd4, 0x2e, - 0xc9, 0xcf, 0x8d, 0xb8, 0x54, 0xe6, 0x44, 0x84, 0x16, 0x1c, 0xd8, 0xd5, 0xae, 0x1e, 0x38, 0x61, - 0x14, 0xd7, 0x6a, 0x15, 0xbe, 0x05, 0xaa, 0xa0, 0x02, 0xe6, 0x33, 0x29, 0x15, 0x2b, 0x8c, 0xcd, - 0x67, 0xb8, 0x56, 0x97, 0x63, 0xa8, 0xb8, 0x8b, 0x0f, 0x7a, 0x1d, 0xc6, 0xb9, 0x08, 0x85, 0x8c, - 0xe1, 0x1e, 0x19, 0x4f, 0xef, 0xee, 0x2c, 0x8c, 0xaf, 0xea, 0x90, 0x38, 0xca, 0xc1, 0xfc, 0x77, - 0x06, 0x22, 0xfa, 0x87, 0xde, 0x31, 0x60, 0x9a, 0xc4, 0xbe, 0x95, 0xf1, 0xc3, 0x97, 0xaf, 0xa4, - 0xfb, 0x80, 0xa9, 0xeb, 0x53, 0x9b, 0xb0, 0x22, 0x17, 0xef, 0xc2, 0x70, 0x37, 0x53, 0xf4, 0x43, - 0x03, 0x0e, 0x93, 0xee, 0x8f, 0xa1, 0x94, 0x3f, 0x3c, 0x3b, 0xf0, 0xd7, 0x54, 0xa5, 0x87, 0x77, - 0x77, 0x16, 0x92, 0x3e, 0x13, 0xc3, 0x49, 0xec, 0xd0, 0xab, 0x30, 0x44, 0xdc, 0xba, 0x9f, 0xbd, - 0xa6, 0x67, 0xeb, 0x7f, 0xe3, 0x16, 0x3a, 0xe4, 0x25, 0xb7, 0xce, 0xb0, 0x00, 0x35, 0x3f, 0xcd, - 0xc2, 0x54, 0xfc, 0xa9, 0xa1, 0x7a, 0x9d, 0x31, 0x94, 0xf8, 0x3a, 0xe3, 0x71, 0x18, 0x26, 0x55, - 0x2f, 0x78, 0x2a, 0x11, 0x3e, 0xaf, 0xe5, 0x8d, 0x58, 0xd2, 0xd0, 0x0d, 0xc8, 0x33, 0x8f, 0xb8, - 0x1e, 0x4f, 0x6a, 0x54, 0x5e, 0x99, 0xfa, 0x29, 0x71, 0xc5, 0x07, 0xc0, 0x21, 0x16, 0x3a, 0x13, - 0x35, 0x67, 0x66, 0xdc, 0x9c, 0x4d, 0xeb, 0x6b, 0x19, 0x34, 0x27, 0x6e, 0x41, 0x41, 0x3b, 0x07, - 0xe5, 0x5d, 0xce, 0xa5, 0xde, 0xf7, 0x50, 0xec, 0x26, 0xe5, 0x87, 0x72, 0x21, 0x45, 0xc7, 0x0f, - 0x93, 0x46, 0xb1, 0x5b, 0xf7, 0x94, 0x34, 0x8a, 0xed, 0xd2, 0xd0, 0xcc, 0x49, 0x18, 0x8f, 0xbc, - 0x18, 0x12, 0xe5, 0xd8, 0x1b, 0xc4, 0xa5, 0x0d, 0xa7, 0xc3, 0xe8, 0x83, 0x5a, 0x8e, 0x0d, 0x26, - 0xb8, 0xdf, 0xe5, 0xd8, 0x10, 0x78, 0xef, 0x72, 0x6c, 0xd0, 0xf7, 0x81, 0x2d, 0xc7, 0x06, 0x33, - 0xec, 0x11, 0x53, 0xfe, 0x2b, 0xa3, 0xad, 0x22, 0x1a, 0x57, 0x66, 0xee, 0x12, 0x57, 0xde, 0x82, - 0x51, 0xcb, 0xf6, 0xa8, 0xbb, 0x45, 0x9a, 0xaa, 0x8a, 0xd8, 0xe7, 0x52, 0x97, 0x3b, 0xae, 0x8a, - 0xaa, 0xfc, 0xa5, 0xae, 0x28, 0x1c, 0x1c, 0x20, 0xa2, 0x26, 0x1c, 0xf1, 0x0b, 0x35, 0x2e, 0x25, - 0x61, 0xa1, 0x58, 0x5d, 0xb6, 0x3e, 0xef, 0xdf, 0xf4, 0x5d, 0x4c, 0xea, 0x74, 0xa7, 0x17, 0x01, - 0x27, 0x83, 0x22, 0x06, 0xe3, 0x4c, 0x4b, 0xa8, 0x7c, 0x47, 0xd2, 0x67, 0x91, 0x2b, 0x9e, 0x83, - 0x6a, 0x37, 0xb4, 0x3a, 0x28, 0x8e, 0xf2, 0x30, 0xff, 0x9a, 0x85, 0xc9, 0x98, 0xa4, 0xc5, 0x02, - 0xc7, 0xfc, 0xfd, 0x0c, 0x1c, 0x73, 0x03, 0x05, 0x8e, 0xc9, 0x31, 0xcd, 0xd0, 0x40, 0x31, 0xcd, - 0x0b, 0x32, 0xae, 0x50, 0x27, 0xb7, 0xb2, 0xac, 0xde, 0xce, 0x05, 0xbb, 0xb9, 0xaa, 0x13, 0x71, - 0xb4, 0xaf, 0xf0, 0xc2, 0xb5, 0xee, 0x0f, 0xc5, 0x54, 0x50, 0x74, 0x36, 0xed, 0x8b, 0x84, 0x00, - 0x40, 0x7a, 0xe1, 0x04, 0x02, 0x4e, 0x62, 0x57, 0xba, 0xf2, 0xe1, 0x67, 0xf3, 0x87, 0x3e, 0xfe, - 0x6c, 0xfe, 0xd0, 0x27, 0x9f, 0xcd, 0x1f, 0x7a, 0x6b, 0x77, 0xde, 0xf8, 0x70, 0x77, 0xde, 0xf8, - 0x78, 0x77, 0xde, 0xf8, 0x64, 0x77, 0xde, 0xf8, 0xc7, 0xee, 0xbc, 0xf1, 0xb3, 0xcf, 0xe7, 0x0f, - 0xdd, 0x7c, 0xa2, 0x9f, 0x2f, 0xfa, 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0xa6, 0x0e, 0x2f, 0xd4, - 0xf8, 0x3f, 0x00, 0x00, + // 3655 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5c, 0xdb, 0x6f, 0x24, 0x47, + 0x57, 0xdf, 0x9e, 0xb1, 0xc7, 0x9e, 0x33, 0xbe, 0xd6, 0x7a, 0x13, 0x7f, 0xfe, 0x88, 0xbd, 0x74, + 0xa2, 0x28, 0x21, 0xc9, 0x98, 0xbd, 0x65, 0x2f, 0x81, 0x45, 0x1e, 0x7b, 0x2f, 0x5e, 0xfc, 0x65, + 0x4d, 0xcd, 0x5e, 0x3e, 0x36, 0xbb, 0x0a, 0xe5, 0x99, 0xf2, 0x4c, 0xe3, 0x99, 0xee, 0x49, 0x57, + 0x8d, 0x13, 0x03, 0x82, 0x84, 0x8b, 0x14, 0x09, 0x81, 0x78, 0x88, 0x48, 0x90, 0x40, 0x42, 0xf0, + 0x0c, 0xff, 0x00, 0x0f, 0x79, 0xe0, 0x25, 0x42, 0x11, 0x8a, 0x80, 0x87, 0x3c, 0x44, 0x16, 0x71, + 0x24, 0x1e, 0xf3, 0xc6, 0xcb, 0x4a, 0x48, 0xa8, 0x2e, 0xdd, 0x5d, 0xdd, 0xd3, 0xb3, 0x9e, 0x9e, + 0xb5, 0x57, 0xab, 0xef, 0x6d, 0x5c, 0xa7, 0xea, 0x77, 0xea, 0x72, 0xce, 0xa9, 0x5f, 0x9d, 0xaa, + 0x36, 0x9c, 0x6f, 0x38, 0xbc, 0xd9, 0xdd, 0x2a, 0xd7, 0xbc, 0xf6, 0x32, 0xd9, 0xe9, 0x3a, 0x7c, + 0x6f, 0x79, 0x87, 0xf8, 0x0d, 0x6f, 0x99, 0x74, 0x9c, 0xe5, 0xdd, 0x33, 0xa4, 0xd5, 0x69, 0x92, + 0x33, 0xcb, 0x0d, 0xea, 0x52, 0x9f, 0x70, 0x5a, 0x2f, 0x77, 0x7c, 0x8f, 0x7b, 0xe8, 0x95, 0xa8, + 0x55, 0x59, 0xb5, 0x2a, 0xcb, 0x56, 0x65, 0xd2, 0x71, 0xca, 0x41, 0xab, 0x85, 0xb7, 0x0c, 0xec, + 0x86, 0xd7, 0xf0, 0x96, 0x65, 0xe3, 0xad, 0xee, 0xb6, 0xfc, 0x4b, 0xfe, 0x21, 0x7f, 0x29, 0xd0, + 0x85, 0x9b, 0x3b, 0x97, 0x58, 0xd9, 0x91, 0x9a, 0xe9, 0x47, 0x9c, 0xba, 0xcc, 0xf1, 0x5c, 0xf6, + 0x16, 0xe9, 0x38, 0x8c, 0xfa, 0xbb, 0xd4, 0x5f, 0xee, 0xec, 0x34, 0x84, 0x8c, 0xc5, 0x2b, 0x2c, + 0xef, 0xf6, 0x74, 0x6f, 0xe1, 0x7c, 0x84, 0xd4, 0x26, 0xb5, 0xa6, 0xe3, 0x52, 0x7f, 0x2f, 0x6a, + 0xde, 0xa6, 0x9c, 0xa4, 0xb5, 0x5a, 0xee, 0xd7, 0xca, 0xef, 0xba, 0xdc, 0x69, 0xd3, 0x9e, 0x06, + 0x6f, 0x1f, 0xd6, 0x80, 0xd5, 0x9a, 0xb4, 0x4d, 0x92, 0xed, 0xec, 0x87, 0x70, 0x72, 0xc5, 0x25, + 0xad, 0x3d, 0xe6, 0x30, 0xdc, 0x75, 0x57, 0xfc, 0x46, 0xb7, 0x4d, 0x5d, 0x8e, 0x4e, 0xc3, 0x88, + 0x4b, 0xda, 0x74, 0xde, 0x3a, 0x6d, 0xbd, 0x56, 0xac, 0x4c, 0x7c, 0xb5, 0xbf, 0x74, 0xe2, 0x60, + 0x7f, 0x69, 0xe4, 0x5d, 0xd2, 0xa6, 0x58, 0x4a, 0xd0, 0xcb, 0x30, 0xba, 0x4b, 0x5a, 0x5d, 0x3a, + 0x9f, 0x93, 0x55, 0x26, 0x75, 0x95, 0xd1, 0x7b, 0xa2, 0x10, 0x2b, 0x99, 0xfd, 0x27, 0xf9, 0x18, + 0xfc, 0xcf, 0x28, 0x27, 0x75, 0xc2, 0x09, 0x6a, 0x43, 0xa1, 0x45, 0xb6, 0x68, 0x8b, 0xcd, 0x5b, + 0xa7, 0xf3, 0xaf, 0x95, 0xce, 0x5e, 0x2b, 0x0f, 0xb2, 0x88, 0xe5, 0x14, 0xa8, 0xf2, 0x86, 0xc4, + 0xb9, 0xe6, 0x72, 0x7f, 0xaf, 0x32, 0xa5, 0x3b, 0x51, 0x50, 0x85, 0x58, 0x2b, 0x41, 0x9f, 0x58, + 0x50, 0x22, 0xae, 0xeb, 0x71, 0xc2, 0xc5, 0x32, 0xcd, 0xe7, 0xa4, 0xd2, 0x5b, 0xc3, 0x2b, 0x5d, + 0x89, 0xc0, 0x94, 0xe6, 0x93, 0x5a, 0x73, 0xc9, 0x90, 0x60, 0x53, 0xe7, 0xc2, 0x65, 0x28, 0x19, + 0x5d, 0x45, 0x33, 0x90, 0xdf, 0xa1, 0x7b, 0x6a, 0x7e, 0xb1, 0xf8, 0x89, 0xe6, 0x62, 0x13, 0xaa, + 0x67, 0xf0, 0x4a, 0xee, 0x92, 0xb5, 0x70, 0x15, 0x66, 0x92, 0x0a, 0xb3, 0xb4, 0xb7, 0xff, 0xd2, + 0x82, 0x39, 0x63, 0x14, 0x98, 0x6e, 0x53, 0x9f, 0xba, 0x35, 0x8a, 0x96, 0xa1, 0x28, 0xd6, 0x92, + 0x75, 0x48, 0x2d, 0x58, 0xea, 0x59, 0x3d, 0x90, 0xe2, 0xbb, 0x81, 0x00, 0x47, 0x75, 0x42, 0xb3, + 0xc8, 0x3d, 0xc9, 0x2c, 0x3a, 0x4d, 0xc2, 0xe8, 0x7c, 0x3e, 0x6e, 0x16, 0x9b, 0xa2, 0x10, 0x2b, + 0x99, 0xfd, 0xeb, 0xf0, 0x93, 0xa0, 0x3f, 0x77, 0x68, 0xbb, 0xd3, 0x22, 0x9c, 0x46, 0x9d, 0x3a, + 0xd4, 0xf4, 0xec, 0x69, 0x98, 0x5c, 0xe9, 0x74, 0x7c, 0x6f, 0x97, 0xd6, 0xab, 0x9c, 0x34, 0xa8, + 0xfd, 0xc7, 0x16, 0x9c, 0x5a, 0xf1, 0x1b, 0xde, 0xea, 0xda, 0x4a, 0xa7, 0x73, 0x93, 0x92, 0x16, + 0x6f, 0x56, 0x39, 0xe1, 0x5d, 0x86, 0xae, 0x42, 0x81, 0xc9, 0x5f, 0x1a, 0xee, 0xd5, 0xc0, 0x42, + 0x94, 0xfc, 0xf1, 0xfe, 0xd2, 0x5c, 0x4a, 0x43, 0x8a, 0x75, 0x2b, 0xf4, 0x3a, 0x8c, 0xb5, 0x29, + 0x63, 0xa4, 0x11, 0x8c, 0x79, 0x5a, 0x03, 0x8c, 0xfd, 0x4c, 0x15, 0xe3, 0x40, 0x6e, 0xff, 0x5b, + 0x0e, 0xa6, 0x43, 0x2c, 0xad, 0xfe, 0x18, 0x26, 0xb8, 0x0b, 0x13, 0x4d, 0x63, 0x84, 0x72, 0x9e, + 0x4b, 0x67, 0xdf, 0x19, 0xd0, 0x96, 0xd3, 0x26, 0xa9, 0x32, 0xa7, 0xd5, 0x4c, 0x98, 0xa5, 0x38, + 0xa6, 0x06, 0xb5, 0x01, 0xd8, 0x9e, 0x5b, 0xd3, 0x4a, 0x47, 0xa4, 0xd2, 0xcb, 0x19, 0x95, 0x56, + 0x43, 0x80, 0x0a, 0xd2, 0x2a, 0x21, 0x2a, 0xc3, 0x86, 0x02, 0xfb, 0x9f, 0x2d, 0x38, 0x99, 0xd2, + 0x0e, 0xfd, 0x5a, 0x62, 0x3d, 0x5f, 0xe9, 0x59, 0x4f, 0xd4, 0xd3, 0x2c, 0x5a, 0xcd, 0x37, 0x61, + 0xdc, 0xa7, 0xbb, 0x8e, 0x88, 0xd5, 0x7a, 0x86, 0x67, 0x74, 0xfb, 0x71, 0xac, 0xcb, 0x71, 0x58, + 0x03, 0xbd, 0x01, 0xc5, 0xe0, 0xb7, 0x98, 0xe6, 0xbc, 0x30, 0x67, 0xb1, 0x70, 0x41, 0x55, 0x86, + 0x23, 0xb9, 0xfd, 0x47, 0x30, 0xba, 0xda, 0x24, 0x3e, 0x17, 0x16, 0xe3, 0xd3, 0x8e, 0x77, 0x17, + 0x6f, 0xe8, 0x2e, 0x86, 0x16, 0x83, 0x55, 0x31, 0x0e, 0xe4, 0x03, 0x2c, 0xf6, 0xeb, 0x30, 0xb6, + 0x4b, 0x7d, 0xd9, 0xdf, 0x7c, 0x1c, 0xec, 0x9e, 0x2a, 0xc6, 0x81, 0xdc, 0xfe, 0x4f, 0x0b, 0xe6, + 0x64, 0x0f, 0xd6, 0x1c, 0x56, 0xf3, 0x76, 0xa9, 0xbf, 0x87, 0x29, 0xeb, 0xb6, 0x8e, 0xb8, 0x43, + 0x6b, 0x30, 0xc3, 0x68, 0x7b, 0x97, 0xfa, 0xab, 0x9e, 0xcb, 0xb8, 0x4f, 0x1c, 0x97, 0xeb, 0x9e, + 0xcd, 0xeb, 0xda, 0x33, 0xd5, 0x84, 0x1c, 0xf7, 0xb4, 0x40, 0xaf, 0xc1, 0xb8, 0xee, 0xb6, 0x30, + 0x25, 0x31, 0xb1, 0x13, 0x62, 0x0d, 0xf4, 0x98, 0x18, 0x0e, 0xa5, 0xf6, 0xff, 0x58, 0x30, 0x2b, + 0x47, 0x55, 0xed, 0x6e, 0xb1, 0x9a, 0xef, 0x74, 0x44, 0x08, 0x7c, 0x1e, 0x87, 0x74, 0x15, 0xa6, + 0xea, 0xc1, 0xc4, 0x6f, 0x38, 0x6d, 0x87, 0x4b, 0x1f, 0x19, 0xad, 0xbc, 0xa0, 0x31, 0xa6, 0xd6, + 0x62, 0x52, 0x9c, 0xa8, 0x6d, 0xff, 0x6d, 0x1e, 0x4e, 0x06, 0x55, 0x68, 0x7d, 0xc5, 0xe7, 0xce, + 0x36, 0xa9, 0x71, 0x86, 0xea, 0x30, 0x51, 0x8f, 0x8a, 0xb9, 0xf6, 0xbc, 0x5f, 0x29, 0xab, 0xed, + 0xbe, 0x6c, 0x6e, 0xf7, 0xe5, 0xce, 0x4e, 0x43, 0x14, 0xb0, 0xb2, 0x60, 0x15, 0xe5, 0xdd, 0x33, + 0xe5, 0x3b, 0x4e, 0x9b, 0x46, 0xde, 0x6d, 0xc0, 0x73, 0x1c, 0x43, 0x45, 0xf7, 0x21, 0xdf, 0x70, + 0xb8, 0xde, 0x8c, 0x2f, 0x0d, 0xe6, 0xd6, 0x37, 0x9c, 0xa4, 0xa9, 0x55, 0x4a, 0x5a, 0x55, 0xfe, + 0x86, 0xc3, 0xb1, 0x40, 0x44, 0x5b, 0x50, 0x70, 0xda, 0xa4, 0x41, 0x83, 0x3d, 0xf7, 0xca, 0x60, + 0xd8, 0xeb, 0xa2, 0x4d, 0x12, 0x3d, 0xdc, 0xdd, 0xa5, 0x94, 0x61, 0x8d, 0x2c, 0x74, 0xd4, 0x84, + 0x89, 0x28, 0x27, 0x1d, 0x58, 0x47, 0x9a, 0xb3, 0x44, 0x3a, 0xa4, 0x94, 0x61, 0x8d, 0x6c, 0x7f, + 0x9b, 0x83, 0x99, 0x68, 0xfe, 0x56, 0xbd, 0x76, 0xdb, 0xe1, 0x68, 0x01, 0x72, 0x4e, 0x5d, 0x5b, + 0x20, 0xe8, 0x86, 0xb9, 0xf5, 0x35, 0x9c, 0x73, 0xea, 0xe8, 0x55, 0x28, 0x6c, 0xf9, 0xc4, 0xad, + 0x35, 0xb5, 0xe5, 0x85, 0xc0, 0x15, 0x59, 0x8a, 0xb5, 0x14, 0xbd, 0x04, 0x79, 0x4e, 0x1a, 0xda, + 0xe0, 0xc2, 0xf9, 0xbb, 0x43, 0x1a, 0x58, 0x94, 0x0b, 0x4b, 0x67, 0xdd, 0xad, 0xdf, 0xa5, 0x35, + 0xb5, 0xf2, 0x86, 0xa5, 0x57, 0x55, 0x31, 0x0e, 0xe4, 0x42, 0x23, 0xe9, 0xf2, 0xa6, 0xe7, 0xcf, + 0x8f, 0xc6, 0x35, 0xae, 0xc8, 0x52, 0xac, 0xa5, 0x62, 0x4f, 0xaa, 0xc9, 0xfe, 0x73, 0xea, 0xcf, + 0x17, 0xe2, 0x7b, 0xd2, 0x6a, 0x20, 0xc0, 0x51, 0x1d, 0xf4, 0x08, 0x4a, 0x35, 0x9f, 0x12, 0xee, + 0xf9, 0x6b, 0x84, 0xd3, 0xf9, 0xb1, 0xcc, 0x16, 0x38, 0x2d, 0x88, 0xd1, 0x6a, 0x04, 0x81, 0x4d, + 0x3c, 0xfb, 0x47, 0x0b, 0xe6, 0xa3, 0xa9, 0x95, 0x6b, 0x1b, 0x91, 0x01, 0x3d, 0x3d, 0x56, 0x9f, + 0xe9, 0x79, 0x15, 0x0a, 0x75, 0xa7, 0x41, 0x19, 0x4f, 0xce, 0xf2, 0x9a, 0x2c, 0xc5, 0x5a, 0x8a, + 0xce, 0x02, 0x34, 0x1c, 0xae, 0x83, 0x83, 0x9e, 0xec, 0x70, 0x0b, 0xba, 0x11, 0x4a, 0xb0, 0x51, + 0x0b, 0xdd, 0x87, 0xa2, 0xec, 0xe6, 0x90, 0x6e, 0x27, 0xb7, 0x8a, 0xd5, 0x00, 0x00, 0x47, 0x58, + 0xf6, 0x37, 0x23, 0x30, 0x76, 0xdd, 0xa7, 0x4e, 0xa3, 0xc9, 0xd1, 0xef, 0xc0, 0x78, 0x5b, 0x93, + 0x4a, 0x39, 0xc8, 0xd2, 0xd9, 0x5f, 0x1d, 0x4c, 0xc7, 0x6d, 0xb9, 0xe8, 0x82, 0x90, 0x46, 0x03, + 0x89, 0xca, 0x70, 0x88, 0x2a, 0x08, 0x19, 0x69, 0x39, 0x84, 0xc9, 0x75, 0x33, 0x08, 0xd9, 0x8a, + 0x28, 0xc4, 0x4a, 0x86, 0xde, 0x83, 0x82, 0xe7, 0x3b, 0x0d, 0xc7, 0x9d, 0x2f, 0xca, 0x4e, 0x9c, + 0x1b, 0xcc, 0x85, 0xf4, 0x28, 0x6e, 0xcb, 0xa6, 0xd1, 0xe4, 0xab, 0xbf, 0xb1, 0x86, 0x44, 0x0f, + 0x60, 0x4c, 0x19, 0x53, 0xe0, 0xa0, 0xcb, 0x03, 0x07, 0x18, 0x65, 0x8f, 0x91, 0xd1, 0xab, 0xbf, + 0x19, 0x0e, 0x00, 0x51, 0x35, 0x8c, 0x2f, 0x23, 0x12, 0xfa, 0x8d, 0x0c, 0xf1, 0xa5, 0x6f, 0x40, + 0xa9, 0x86, 0x01, 0x65, 0x34, 0x0b, 0xa8, 0x0c, 0x19, 0xfd, 0x22, 0x88, 0x98, 0x62, 0xcd, 0x5c, + 0x0a, 0x43, 0x4c, 0xb1, 0xa6, 0x4d, 0x53, 0x71, 0xba, 0x13, 0x10, 0x1b, 0xfb, 0xb3, 0x3c, 0xcc, + 0xea, 0x9a, 0xab, 0x5e, 0xab, 0x45, 0x6b, 0x72, 0x9b, 0x54, 0xf1, 0x29, 0x9f, 0x1a, 0x9f, 0x1c, + 0x18, 0x75, 0x38, 0x6d, 0x07, 0x07, 0xb0, 0x4a, 0xa6, 0xde, 0x44, 0x3a, 0xca, 0xeb, 0x02, 0x44, + 0x9d, 0x81, 0xc2, 0x55, 0xd2, 0xb5, 0xb0, 0xd2, 0x80, 0xfe, 0xcc, 0x82, 0x93, 0xbb, 0xd4, 0x77, + 0xb6, 0x9d, 0x9a, 0x3c, 0xc1, 0xdc, 0x74, 0x18, 0xf7, 0xfc, 0x3d, 0xbd, 0x23, 0xbc, 0x3d, 0x98, + 0xe6, 0x7b, 0x06, 0xc0, 0xba, 0xbb, 0xed, 0x55, 0x7e, 0xaa, 0xb5, 0x9d, 0xbc, 0xd7, 0x0b, 0x8d, + 0xd3, 0xf4, 0x2d, 0x74, 0x00, 0xa2, 0xde, 0xa6, 0x1c, 0xa0, 0x36, 0xcc, 0x03, 0xd4, 0xc0, 0x1d, + 0x0b, 0x06, 0x1b, 0x84, 0x2c, 0xf3, 0xe0, 0xf5, 0xa5, 0x05, 0x25, 0x2d, 0xdf, 0x70, 0x18, 0x47, + 0x0f, 0x7b, 0xbc, 0xbd, 0x3c, 0x98, 0xb7, 0x8b, 0xd6, 0xd2, 0xd7, 0x43, 0xbe, 0x1a, 0x94, 0x18, + 0x9e, 0x8e, 0x83, 0x25, 0x55, 0x13, 0xfb, 0x56, 0xa6, 0xfe, 0x47, 0x81, 0x41, 0xce, 0x91, 0x5e, + 0x3b, 0xdb, 0x87, 0xc9, 0x98, 0x93, 0xa3, 0x0b, 0x30, 0xb2, 0xe3, 0xb8, 0xc1, 0xae, 0xf7, 0xcb, + 0x01, 0x9f, 0xfa, 0x4d, 0xc7, 0xad, 0x3f, 0xde, 0x5f, 0x9a, 0x8d, 0x55, 0x16, 0x85, 0x58, 0x56, + 0x3f, 0x9c, 0x86, 0x5d, 0x19, 0xff, 0xe2, 0xef, 0x97, 0x4e, 0x7c, 0xfc, 0xdd, 0xe9, 0x13, 0xf6, + 0xe7, 0x79, 0x98, 0x49, 0xce, 0xea, 0x00, 0x09, 0x89, 0x28, 0x86, 0x8d, 0x1f, 0x6b, 0x0c, 0xcb, + 0x1d, 0x5f, 0x0c, 0xcb, 0x1f, 0x47, 0x0c, 0x1b, 0x39, 0xb2, 0x18, 0x66, 0xff, 0xbb, 0x05, 0x53, + 0xe1, 0xca, 0x7c, 0xd0, 0x15, 0x3b, 0x6b, 0x34, 0xeb, 0xd6, 0xd1, 0xcf, 0xfa, 0xfb, 0x30, 0xc6, + 0xbc, 0xae, 0x5f, 0x93, 0xf4, 0x51, 0xa0, 0x9f, 0xcf, 0x16, 0x34, 0x55, 0x5b, 0x83, 0x33, 0xa9, + 0x02, 0x1c, 0xa0, 0xda, 0x0f, 0xc3, 0xf1, 0x68, 0x91, 0x62, 0x14, 0xbe, 0xe0, 0x5b, 0x62, 0x3c, + 0xe3, 0x26, 0xa3, 0x10, 0xa5, 0x58, 0x4b, 0x91, 0x2d, 0xc3, 0x79, 0x40, 0x6c, 0x8b, 0x15, 0xd0, + 0x51, 0x59, 0xae, 0x81, 0x92, 0xd8, 0x3f, 0xe6, 0x43, 0xef, 0xd1, 0xc7, 0xd7, 0x0f, 0x01, 0x54, + 0x64, 0xa2, 0xf5, 0x75, 0x57, 0x87, 0xde, 0xd5, 0x21, 0x36, 0x02, 0x1d, 0x0e, 0x05, 0x8a, 0x8a, + 0xbd, 0x21, 0x07, 0x88, 0x04, 0xd8, 0x50, 0x85, 0x7e, 0x1f, 0x4a, 0x44, 0xa7, 0x4c, 0xae, 0x7b, + 0xbe, 0xb6, 0xe1, 0xb5, 0x61, 0x34, 0xaf, 0x44, 0x30, 0xc9, 0xd4, 0x57, 0x24, 0xc1, 0xa6, 0xb6, + 0x05, 0x1f, 0xa6, 0x13, 0xfd, 0x4d, 0x89, 0xbe, 0xeb, 0xf1, 0xe8, 0x7b, 0x2e, 0xcb, 0xb6, 0xa0, + 0xf3, 0x40, 0x66, 0xce, 0x8c, 0xc1, 0x4c, 0xb2, 0xa7, 0x47, 0xa6, 0x34, 0x96, 0x7c, 0x32, 0xe3, + 0xfd, 0xdf, 0xe5, 0xa0, 0x18, 0x7a, 0x7c, 0x96, 0x53, 0xaa, 0xda, 0xa9, 0x73, 0x87, 0x9c, 0x24, + 0xf2, 0x83, 0x9c, 0x24, 0x46, 0xfa, 0x9f, 0x24, 0x82, 0x4c, 0x56, 0xe1, 0xc9, 0x99, 0x2c, 0xe3, + 0x24, 0x31, 0x36, 0xf8, 0x49, 0x62, 0xfc, 0xf0, 0x93, 0x84, 0xfd, 0x0f, 0x16, 0xa0, 0xde, 0x63, + 0x63, 0x96, 0x89, 0x22, 0xc9, 0x38, 0x3c, 0xe0, 0x2e, 0x9d, 0x3c, 0xbb, 0xf5, 0x0f, 0xc7, 0xf6, + 0x97, 0xa3, 0x30, 0x7d, 0xc3, 0x19, 0x3a, 0xe1, 0xc0, 0xe1, 0x45, 0x85, 0x54, 0xa5, 0x9a, 0x23, + 0x55, 0xb9, 0x4f, 0x38, 0x6d, 0xec, 0xe9, 0xf5, 0xbd, 0xa2, 0x9b, 0xbe, 0xb8, 0x9a, 0x5e, 0xed, + 0x71, 0x7f, 0x11, 0xee, 0x07, 0x3d, 0xb0, 0x91, 0xbc, 0x03, 0x93, 0x8c, 0xfb, 0x4e, 0x8d, 0xab, + 0x94, 0x06, 0x9b, 0x2f, 0xc9, 0x28, 0x77, 0x4a, 0x57, 0x9f, 0xac, 0x9a, 0x42, 0x1c, 0xaf, 0x9b, + 0x9a, 0x29, 0x19, 0xc9, 0x9c, 0x29, 0x59, 0x86, 0x22, 0x69, 0xb5, 0xbc, 0x0f, 0xef, 0x90, 0x06, + 0xd3, 0x47, 0xd5, 0xd0, 0x6a, 0x56, 0x02, 0x01, 0x8e, 0xea, 0xa0, 0x32, 0x80, 0xd3, 0x70, 0x3d, + 0x9f, 0xca, 0x16, 0x05, 0x19, 0x6e, 0xa7, 0x44, 0xac, 0x5b, 0x0f, 0x4b, 0xb1, 0x51, 0x03, 0x55, + 0xe1, 0x94, 0xe3, 0x32, 0x5a, 0xeb, 0xfa, 0xb4, 0xba, 0xe3, 0x74, 0xee, 0x6c, 0x54, 0x65, 0x94, + 0xd8, 0x93, 0xd6, 0x3c, 0x5e, 0x79, 0x49, 0x2b, 0x3b, 0xb5, 0x9e, 0x56, 0x09, 0xa7, 0xb7, 0x45, + 0xe7, 0x61, 0xc2, 0x71, 0x6b, 0xad, 0x6e, 0x9d, 0x6e, 0x12, 0xde, 0x64, 0xf3, 0xe3, 0xb2, 0x1b, + 0x33, 0x07, 0xfb, 0x4b, 0x13, 0xeb, 0x46, 0x39, 0x8e, 0xd5, 0x12, 0xad, 0xe8, 0x47, 0x46, 0xab, + 0x62, 0xd4, 0xea, 0xda, 0x47, 0x66, 0x2b, 0xb3, 0x56, 0x4a, 0x2e, 0x09, 0x32, 0xe5, 0x92, 0xfe, + 0x3a, 0x0f, 0x05, 0x95, 0xca, 0x45, 0x17, 0x12, 0xf9, 0xd2, 0x97, 0x7a, 0xf2, 0xa5, 0xa5, 0xb4, + 0xb4, 0xb7, 0x0d, 0x05, 0x87, 0xb1, 0x6e, 0x7c, 0x77, 0x5b, 0x97, 0x25, 0x58, 0x4b, 0x90, 0x03, + 0x40, 0x82, 0x54, 0x6b, 0x40, 0x5d, 0x2e, 0x64, 0xcd, 0x08, 0x27, 0xb2, 0xc1, 0xa1, 0x80, 0x61, + 0x03, 0x5c, 0x66, 0x78, 0x3c, 0x77, 0xdb, 0x69, 0xe8, 0x73, 0xf8, 0x55, 0x83, 0x35, 0x47, 0xb7, + 0x6f, 0xef, 0x87, 0xd7, 0x73, 0x11, 0x81, 0x8e, 0x55, 0x10, 0x4c, 0xfa, 0x56, 0xf5, 0xf6, 0xbb, + 0x6a, 0x38, 0xab, 0x12, 0x11, 0x6b, 0x64, 0xa1, 0xc3, 0xeb, 0xf2, 0x4e, 0x97, 0x4b, 0x9b, 0x3c, + 0x22, 0x1d, 0xb7, 0x25, 0x22, 0xd6, 0xc8, 0xf6, 0xe7, 0x16, 0x4c, 0xab, 0xe9, 0x5e, 0x6d, 0xd2, + 0xda, 0x4e, 0x95, 0xd3, 0x8e, 0x20, 0xb6, 0x5d, 0x46, 0x59, 0x92, 0xd8, 0xde, 0x65, 0x94, 0x61, + 0x29, 0x31, 0x46, 0x9f, 0x3b, 0xae, 0xd1, 0xdb, 0xff, 0x64, 0xc1, 0xa8, 0x64, 0x90, 0x59, 0x42, + 0x5d, 0x3c, 0xab, 0x92, 0x1b, 0x28, 0xab, 0x72, 0x48, 0xbe, 0x2b, 0x4a, 0xe8, 0x8c, 0x3c, 0x29, + 0xa1, 0x63, 0xff, 0x60, 0xc1, 0x5c, 0x5a, 0x92, 0x30, 0x4b, 0xf7, 0xdf, 0x84, 0xf1, 0x4e, 0x8b, + 0xf0, 0x6d, 0xcf, 0x6f, 0x27, 0x6f, 0x03, 0x36, 0x75, 0x39, 0x0e, 0x6b, 0x20, 0x1f, 0xc0, 0x0f, + 0x4e, 0x23, 0x81, 0xb9, 0x5f, 0xcd, 0xba, 0xf9, 0xc4, 0xb3, 0x5b, 0xd1, 0x64, 0x85, 0x45, 0x0c, + 0x1b, 0x5a, 0xec, 0x3f, 0x1f, 0x85, 0x59, 0xd9, 0x64, 0xd8, 0xcd, 0x68, 0x98, 0x15, 0xea, 0xc0, + 0x0b, 0xf2, 0x0c, 0xd1, 0xbb, 0x7f, 0xa9, 0x45, 0xbb, 0xa4, 0xdb, 0xbf, 0xb0, 0x9e, 0x5a, 0xeb, + 0x71, 0x5f, 0x09, 0xee, 0x83, 0xdb, 0xbb, 0x29, 0xc1, 0x2f, 0xde, 0xa6, 0x64, 0x1a, 0xdb, 0xd8, + 0xa1, 0xc6, 0xd6, 0x77, 0x0b, 0x1b, 0x7f, 0x8a, 0x2d, 0xac, 0x77, 0x5b, 0x29, 0x66, 0xda, 0x56, + 0xfe, 0x26, 0x07, 0x63, 0x9b, 0xbe, 0x27, 0x93, 0xcd, 0xc7, 0x9f, 0xb7, 0xbc, 0x0d, 0x23, 0xac, + 0x43, 0x6b, 0x3a, 0xe6, 0x9d, 0x19, 0xcc, 0xd3, 0x74, 0xf7, 0xaa, 0x1d, 0x5a, 0xab, 0x8c, 0x8b, + 0x30, 0x2a, 0x7e, 0x61, 0x09, 0x64, 0x24, 0xe0, 0xf2, 0x59, 0xc8, 0x7e, 0x00, 0xf9, 0xe4, 0x04, + 0xdc, 0x97, 0x16, 0x94, 0x74, 0xcd, 0xe7, 0x36, 0xd3, 0xa3, 0xfb, 0xd7, 0x27, 0xd3, 0xf3, 0x17, + 0xd1, 0x08, 0xc4, 0xa4, 0xa1, 0x3f, 0x84, 0xd9, 0x8e, 0xef, 0xb5, 0x3d, 0xe1, 0xa9, 0x9b, 0x5e, + 0xcb, 0xa9, 0x39, 0x34, 0x48, 0x16, 0x5e, 0x18, 0x58, 0x9f, 0xd1, 0x7c, 0xaf, 0xf2, 0x13, 0xad, + 0x77, 0x76, 0x33, 0x89, 0x8b, 0x7b, 0x55, 0xd9, 0xff, 0x65, 0xc1, 0x64, 0x6c, 0xee, 0x51, 0x0d, + 0xa0, 0xe6, 0xb9, 0x75, 0x87, 0x87, 0x17, 0xb2, 0xa5, 0xb3, 0xcb, 0x83, 0xcd, 0xea, 0x6a, 0xd0, + 0x2e, 0x32, 0xba, 0xb0, 0x88, 0x61, 0x03, 0x16, 0x9d, 0x0b, 0xde, 0x2f, 0xc4, 0xf9, 0x92, 0x7a, + 0xbf, 0xf0, 0x78, 0x7f, 0x69, 0x42, 0xf7, 0xc9, 0x7c, 0xcf, 0x90, 0xe5, 0x95, 0xc0, 0x3f, 0xe6, + 0xa0, 0x18, 0x8e, 0xff, 0x19, 0xb8, 0xd1, 0xdd, 0x98, 0x1b, 0x9d, 0xcb, 0xb8, 0x72, 0xd2, 0x91, + 0x42, 0x4e, 0x62, 0x38, 0xd3, 0xa3, 0x84, 0x33, 0x65, 0x35, 0x89, 0x43, 0xdc, 0xe9, 0x5f, 0xd5, + 0xe2, 0xab, 0xba, 0xcf, 0xc0, 0xa1, 0xee, 0xc4, 0x1d, 0x6a, 0x39, 0xe3, 0x68, 0xfa, 0xb8, 0xd4, + 0xa7, 0x16, 0x4c, 0x27, 0x9c, 0x00, 0xbd, 0x0c, 0xa3, 0x32, 0x3b, 0xa4, 0xed, 0x2b, 0x6c, 0xa8, + 0x73, 0x09, 0x52, 0x86, 0x36, 0x61, 0x8e, 0x74, 0xb9, 0x17, 0xb6, 0xbd, 0xe6, 0x92, 0xad, 0x16, + 0x55, 0x09, 0x82, 0xf1, 0xca, 0x2f, 0xe9, 0x36, 0x73, 0x2b, 0x29, 0x75, 0x70, 0x6a, 0x4b, 0xfb, + 0xeb, 0x1c, 0xa0, 0xb0, 0x30, 0x4b, 0x56, 0xf5, 0x11, 0x8c, 0x6d, 0xab, 0xfc, 0xcf, 0xd3, 0xa5, + 0xc5, 0x2b, 0x25, 0xf3, 0x66, 0x20, 0xc0, 0x44, 0xbf, 0x7d, 0x34, 0x76, 0x04, 0xbd, 0x36, 0x84, + 0x1e, 0x00, 0x6c, 0x3b, 0xae, 0xc3, 0x9a, 0x43, 0x5e, 0xe0, 0xc9, 0xdd, 0xfc, 0x7a, 0x88, 0x80, + 0x0d, 0x34, 0xfb, 0x2a, 0x4c, 0x19, 0xb3, 0xc9, 0xfd, 0x3d, 0xb1, 0xbf, 0x13, 0xce, 0x69, 0xbb, + 0xc3, 0x15, 0x95, 0xcf, 0x47, 0xf6, 0xb6, 0xa2, 0xcb, 0x71, 0x58, 0xc3, 0xfe, 0x2c, 0x67, 0xd8, + 0xb7, 0x0c, 0xb7, 0x03, 0xd9, 0xc5, 0xeb, 0xf1, 0xc5, 0x28, 0xf6, 0x5e, 0xb9, 0x18, 0x13, 0x3b, + 0xb2, 0x4b, 0xfc, 0x20, 0xfb, 0x7b, 0x31, 0xe3, 0xb4, 0xde, 0x23, 0xbe, 0x23, 0x0c, 0x27, 0x32, + 0x89, 0x7b, 0xc4, 0x67, 0x58, 0x42, 0xa2, 0x9f, 0x8b, 0xae, 0xd2, 0xf0, 0xcc, 0x97, 0x39, 0xa6, + 0x70, 0xda, 0x31, 0xc7, 0x47, 0x3b, 0x0c, 0x2b, 0x40, 0xfb, 0x93, 0x82, 0xe1, 0x30, 0x3a, 0xea, + 0xdf, 0x02, 0xd4, 0x22, 0x8c, 0xdf, 0x24, 0x6e, 0x5d, 0x98, 0x37, 0xdd, 0xf6, 0x29, 0x6b, 0x6a, + 0x86, 0xb7, 0xa0, 0x51, 0xd0, 0x46, 0x4f, 0x0d, 0x9c, 0xd2, 0x0a, 0x5d, 0x88, 0x07, 0xf7, 0xa5, + 0x64, 0x70, 0x8f, 0x16, 0x75, 0xc8, 0xf0, 0x6e, 0xba, 0xcb, 0xe8, 0x31, 0xb8, 0xcb, 0x1f, 0xc0, + 0xec, 0x76, 0xf2, 0x0a, 0x4e, 0x5f, 0xc8, 0x5f, 0x1c, 0xf2, 0x06, 0xaf, 0x72, 0xea, 0x20, 0xba, + 0xb7, 0x89, 0x8a, 0x71, 0xaf, 0x22, 0xe4, 0x05, 0x4f, 0xcf, 0xe4, 0xe9, 0x55, 0xe5, 0x40, 0x06, + 0x76, 0xd9, 0xc4, 0xb9, 0x37, 0xf9, 0xe8, 0x4c, 0x41, 0xe2, 0x98, 0x82, 0x84, 0x0b, 0x17, 0x8e, + 0xd2, 0x85, 0xd1, 0x05, 0x28, 0xd5, 0xba, 0xbe, 0x4f, 0x5d, 0x2e, 0xba, 0x23, 0xa9, 0x70, 0x3e, + 0xca, 0x65, 0xaf, 0x46, 0x22, 0x6c, 0xd6, 0x43, 0xef, 0x4b, 0x3f, 0xe5, 0x54, 0x9e, 0x51, 0x9e, + 0xfe, 0x2c, 0x5e, 0xd4, 0x3e, 0xce, 0x95, 0x8f, 0x73, 0x6a, 0x7f, 0x1a, 0x0b, 0x0d, 0x83, 0x65, + 0x08, 0x16, 0x20, 0x47, 0x58, 0x32, 0x7d, 0xbc, 0xc2, 0x70, 0x8e, 0x30, 0x74, 0x17, 0x46, 0x7d, + 0x11, 0xa1, 0x74, 0x04, 0x3c, 0x9f, 0xd1, 0x5b, 0x65, 0x74, 0x53, 0xdd, 0x94, 0x3f, 0xb1, 0x42, + 0x33, 0x92, 0x12, 0xf9, 0x63, 0x4b, 0x4a, 0xf8, 0x10, 0x51, 0xc5, 0xe0, 0x9d, 0x28, 0x7a, 0xa4, + 0x09, 0x8d, 0x95, 0xe5, 0xdd, 0x63, 0x0f, 0x4c, 0x3f, 0x62, 0x63, 0x7f, 0x6d, 0xc1, 0xa9, 0xd4, + 0xda, 0x61, 0x44, 0xcd, 0x1d, 0x63, 0x44, 0xb5, 0x8e, 0x3a, 0xa2, 0x3e, 0x30, 0xa6, 0x30, 0xe8, + 0xc2, 0x51, 0x3d, 0xee, 0xfe, 0x22, 0x07, 0x33, 0x98, 0x76, 0xbc, 0x58, 0x72, 0x62, 0x33, 0x78, + 0x49, 0x96, 0x61, 0x37, 0x4f, 0x64, 0xdb, 0x2b, 0x63, 0xb1, 0x27, 0x64, 0x3f, 0x87, 0x51, 0x99, + 0x37, 0xd0, 0xfc, 0xe3, 0x62, 0x86, 0xdb, 0xd1, 0x18, 0xaa, 0xb4, 0x61, 0x95, 0x80, 0x51, 0x80, + 0x02, 0x59, 0x5e, 0x6c, 0x6a, 0x13, 0xbe, 0x98, 0xe1, 0x8a, 0xb4, 0x17, 0x59, 0x16, 0x63, 0x05, + 0x68, 0x7f, 0x9e, 0x03, 0xb5, 0x73, 0x3f, 0x03, 0x86, 0xff, 0x5b, 0x31, 0x86, 0x3f, 0x20, 0x75, + 0x95, 0x9d, 0xeb, 0xcb, 0xee, 0x93, 0xac, 0xec, 0x4c, 0x16, 0xd0, 0x27, 0x33, 0xfb, 0x7f, 0xb1, + 0xa0, 0x28, 0xeb, 0x3d, 0x03, 0x56, 0xbf, 0x19, 0x67, 0xf5, 0x6f, 0x64, 0x18, 0x45, 0x1f, 0x46, + 0xff, 0x59, 0x5e, 0xf7, 0x3e, 0xe4, 0x6c, 0x4d, 0xe2, 0xd7, 0x35, 0x1b, 0x89, 0x3c, 0x50, 0x14, + 0x62, 0x25, 0x43, 0xbf, 0x07, 0x33, 0xbe, 0xba, 0x2b, 0xa7, 0xf5, 0xeb, 0x21, 0x35, 0xc8, 0x67, + 0xbe, 0xcc, 0xd6, 0x17, 0xee, 0x51, 0x56, 0x0b, 0x27, 0x50, 0x71, 0x8f, 0x1e, 0x41, 0x17, 0x3a, + 0xc9, 0x58, 0xa6, 0xb7, 0xd1, 0x8b, 0x43, 0x06, 0x4e, 0x45, 0x17, 0x7a, 0x8a, 0x71, 0xaf, 0x22, + 0xd4, 0x84, 0x09, 0xf3, 0x19, 0x8e, 0xb6, 0xa5, 0xb3, 0xd9, 0xdf, 0xfb, 0xa8, 0x0b, 0x13, 0xb3, + 0x04, 0xc7, 0x90, 0xed, 0xfd, 0x02, 0x94, 0x0c, 0xe3, 0x4b, 0x64, 0x0a, 0x26, 0x8f, 0x27, 0x53, + 0x90, 0x4e, 0x4c, 0x4b, 0x43, 0x11, 0xd3, 0x33, 0x71, 0x62, 0xfa, 0xd3, 0x24, 0x31, 0x05, 0x39, + 0xba, 0x18, 0x29, 0x65, 0x30, 0xa5, 0x19, 0x5a, 0xf0, 0x9e, 0x2a, 0x13, 0xd5, 0xef, 0xe5, 0x81, + 0xe8, 0x60, 0x7f, 0x29, 0x78, 0x0d, 0x11, 0xbc, 0xa3, 0x4a, 0xa8, 0x40, 0x57, 0x43, 0xa5, 0xd5, + 0x6e, 0xbb, 0x4d, 0xfc, 0xbd, 0xf9, 0x09, 0xd9, 0xe1, 0x30, 0x85, 0x78, 0x3d, 0x26, 0xc5, 0x89, + 0xda, 0x68, 0x13, 0x0a, 0x8a, 0xe0, 0xe9, 0x37, 0x3a, 0x6f, 0x66, 0xe1, 0x8e, 0x8a, 0x23, 0xa8, + 0xdf, 0x58, 0xe3, 0x98, 0xdc, 0xbc, 0x78, 0x08, 0x37, 0xbf, 0x05, 0xc8, 0xdb, 0x92, 0x6c, 0xa4, + 0x7e, 0x43, 0x7d, 0x05, 0x25, 0xac, 0xb2, 0x20, 0x89, 0x5f, 0xb8, 0x60, 0xb7, 0x7b, 0x6a, 0xe0, + 0x94, 0x56, 0xc2, 0xab, 0x35, 0x2b, 0x0c, 0x5d, 0x41, 0xf3, 0xf0, 0x4b, 0x99, 0x09, 0x56, 0x40, + 0xf9, 0xe7, 0x84, 0x57, 0xaf, 0x26, 0x50, 0x71, 0x8f, 0x1e, 0xf4, 0x01, 0x4c, 0x0a, 0x13, 0x8a, + 0x14, 0xc3, 0x53, 0x2a, 0x9e, 0x3d, 0xd8, 0x5f, 0x9a, 0xdc, 0x30, 0x21, 0x71, 0x5c, 0x83, 0xfd, + 0x7f, 0x39, 0x88, 0xf9, 0x1f, 0xfa, 0xd4, 0x82, 0x59, 0x92, 0xf8, 0x84, 0x27, 0xa0, 0x2f, 0xbf, + 0x91, 0xed, 0xbb, 0xaa, 0x9e, 0x2f, 0x80, 0xa2, 0x44, 0x61, 0xb2, 0x0a, 0xc3, 0xbd, 0x4a, 0xd1, + 0x9f, 0x5a, 0x70, 0x92, 0xf4, 0x7e, 0xa3, 0xa5, 0xf7, 0xc3, 0xcb, 0x43, 0x7f, 0xe4, 0x55, 0x79, + 0xf1, 0x60, 0x7f, 0x29, 0xed, 0xeb, 0x35, 0x9c, 0xa6, 0x0e, 0xbd, 0x07, 0x23, 0xc4, 0x6f, 0x04, + 0x87, 0xe2, 0xec, 0x6a, 0x83, 0x4f, 0xef, 0xa2, 0x0d, 0x79, 0xc5, 0x6f, 0x30, 0x2c, 0x41, 0xed, + 0xef, 0xf2, 0x30, 0x93, 0x7c, 0x01, 0xa9, 0x1f, 0x8d, 0x8c, 0xa4, 0x3e, 0x1a, 0x79, 0x19, 0x46, + 0x49, 0x8d, 0x87, 0x2f, 0x38, 0xa2, 0x57, 0xbf, 0xa2, 0x10, 0x2b, 0x19, 0xba, 0x0f, 0x45, 0xc6, + 0x89, 0xcf, 0xc5, 0x59, 0x49, 0x1f, 0x57, 0x33, 0xbf, 0x70, 0xae, 0x06, 0x00, 0x38, 0xc2, 0x42, + 0x97, 0xe2, 0xe1, 0xcc, 0x4e, 0x86, 0xb3, 0x59, 0x73, 0x2c, 0xc3, 0x1e, 0xb5, 0xdb, 0x50, 0x32, + 0xd6, 0x41, 0xef, 0x2e, 0x57, 0x32, 0xcf, 0x7b, 0x64, 0x76, 0xd3, 0xea, 0xfb, 0xbd, 0x48, 0x62, + 0xe2, 0x47, 0x67, 0x51, 0x39, 0x5b, 0x4f, 0x75, 0x16, 0x95, 0xd3, 0x65, 0xa0, 0xd9, 0xd3, 0x30, + 0x19, 0x7b, 0xc8, 0x24, 0xb3, 0xc4, 0xf7, 0x89, 0x4f, 0x9b, 0x5e, 0x97, 0xd1, 0xe7, 0x35, 0x4b, + 0x1c, 0x76, 0xf0, 0xa8, 0xb3, 0xc4, 0x11, 0xf0, 0xe1, 0x59, 0xe2, 0xb0, 0xee, 0x73, 0x9b, 0x25, + 0x0e, 0x7b, 0xd8, 0x87, 0x53, 0xfe, 0x6f, 0xce, 0x18, 0x45, 0x9c, 0x57, 0xe6, 0x9e, 0xc0, 0x2b, + 0x1f, 0xc2, 0xb8, 0xe3, 0x72, 0xea, 0xef, 0x92, 0x96, 0x3e, 0xda, 0x0f, 0x38, 0xd4, 0xb5, 0xae, + 0xaf, 0x59, 0x55, 0x30, 0xd4, 0x75, 0x8d, 0x83, 0x43, 0x44, 0xd4, 0x82, 0x53, 0x41, 0xfe, 0xc7, + 0xa7, 0x24, 0xca, 0x5f, 0xeb, 0x3b, 0xe0, 0xb7, 0x83, 0x0b, 0xc8, 0xeb, 0x69, 0x95, 0x1e, 0xf7, + 0x13, 0xe0, 0x74, 0x50, 0xc4, 0x60, 0x92, 0x19, 0x07, 0xaa, 0x60, 0x23, 0x19, 0x30, 0x77, 0x96, + 0x3c, 0x83, 0x1a, 0x17, 0xc7, 0x26, 0x28, 0x8e, 0xeb, 0xb0, 0xff, 0x23, 0x0f, 0xd3, 0x09, 0x4b, + 0x4b, 0x10, 0xc7, 0xe2, 0xb3, 0x24, 0x8e, 0x85, 0xa1, 0x88, 0x63, 0x3a, 0xa7, 0x19, 0x19, 0x8a, + 0xd3, 0xbc, 0xa3, 0x78, 0x85, 0x5e, 0xb9, 0xf5, 0x35, 0xfd, 0xa4, 0x2f, 0x9c, 0xcd, 0x0d, 0x53, + 0x88, 0xe3, 0x75, 0xe5, 0x2e, 0x5c, 0xef, 0xfd, 0x7e, 0x4d, 0x93, 0xa2, 0xcb, 0x59, 0x1f, 0x4a, + 0x84, 0x00, 0x6a, 0x17, 0x4e, 0x11, 0xe0, 0x34, 0x75, 0x95, 0x5b, 0x5f, 0x7d, 0xbf, 0x78, 0xe2, + 0x9b, 0xef, 0x17, 0x4f, 0x7c, 0xfb, 0xfd, 0xe2, 0x89, 0x8f, 0x0f, 0x16, 0xad, 0xaf, 0x0e, 0x16, + 0xad, 0x6f, 0x0e, 0x16, 0xad, 0x6f, 0x0f, 0x16, 0xad, 0xff, 0x3e, 0x58, 0xb4, 0xfe, 0xea, 0x87, + 0xc5, 0x13, 0x0f, 0x5e, 0x19, 0xe4, 0x1f, 0x0d, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8c, + 0xd4, 0xaa, 0xfb, 0x8f, 0x40, 0x00, 0x00, } func (m *AnalysisRunArgument) Marshal() (dAtA []byte, err error) { @@ -3894,6 +3926,32 @@ func (m *PromotionReference) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *PromotionRetry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PromotionRetry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PromotionRetry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i = encodeVarintGenerated(dAtA, i, uint64(m.Attempts)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil +} + func (m *PromotionSpec) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4078,6 +4136,18 @@ func (m *PromotionStep) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Retry != nil { + { + size, err := m.Retry.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } if m.Config != nil { { size, err := m.Config.MarshalToSizedBuffer(dAtA[:i]) @@ -5702,6 +5772,16 @@ func (m *PromotionReference) Size() (n int) { return n } +func (m *PromotionRetry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 1 + sovGenerated(uint64(m.Attempts)) + return n +} + func (m *PromotionSpec) Size() (n int) { if m == nil { return 0 @@ -5779,6 +5859,10 @@ func (m *PromotionStep) Size() (n int) { l = m.Config.Size() n += 1 + l + sovGenerated(uint64(l)) } + if m.Retry != nil { + l = m.Retry.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -6696,6 +6780,16 @@ func (this *PromotionReference) String() string { }, "") return s } +func (this *PromotionRetry) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PromotionRetry{`, + `Attempts:` + fmt.Sprintf("%v", this.Attempts) + `,`, + `}`, + }, "") + return s +} func (this *PromotionSpec) String() string { if this == nil { return "nil" @@ -6750,6 +6844,7 @@ func (this *PromotionStep) String() string { `Uses:` + fmt.Sprintf("%v", this.Uses) + `,`, `As:` + fmt.Sprintf("%v", this.As) + `,`, `Config:` + strings.Replace(fmt.Sprintf("%v", this.Config), "JSON", "v11.JSON", 1) + `,`, + `Retry:` + strings.Replace(this.Retry.String(), "PromotionRetry", "PromotionRetry", 1) + `,`, `}`, }, "") return s @@ -13586,6 +13681,75 @@ func (m *PromotionReference) Unmarshal(dAtA []byte) error { } return nil } +func (m *PromotionRetry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PromotionRetry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PromotionRetry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Attempts", wireType) + } + m.Attempts = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Attempts |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *PromotionSpec) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -14240,6 +14404,42 @@ func (m *PromotionStep) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Retry", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.Retry == nil { + m.Retry = &PromotionRetry{} + } + if err := m.Retry.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/api/v1alpha1/generated.proto b/api/v1alpha1/generated.proto index 02eaa3104..1250e062e 100644 --- a/api/v1alpha1/generated.proto +++ b/api/v1alpha1/generated.proto @@ -835,6 +835,19 @@ message PromotionReference { optional .k8s.io.apimachinery.pkg.apis.meta.v1.Time finishedAt = 4; } +// PromotionRetry describes the retry policy for a PromotionStep. +message PromotionRetry { + // Attempts is the number of times the step can be attempted before the + // PromotionStep is marked as failed. + // + // If this field is set to 1, the step will not be retried. If this + // field is set to -1, the step will be retried indefinitely. + // + // The default of this field depends on the step being executed. Refer to + // the documentation for the specific step for more information. + optional int64 attempts = 1; +} + // PromotionSpec describes the desired transition of a specific Stage into a // specific Freight. message PromotionSpec { @@ -915,6 +928,9 @@ message PromotionStep { // As is the alias this step can be referred to as. optional string as = 2; + // Retry is the retry policy for this step. + optional PromotionRetry retry = 4; + // Config is opaque configuration for the PromotionStep that is understood // only by each PromotionStep's implementation. It is legal to utilize // expressions in defining values at any level of this block. diff --git a/api/v1alpha1/promotion_types.go b/api/v1alpha1/promotion_types.go index a5b35d489..5fe50566c 100644 --- a/api/v1alpha1/promotion_types.go +++ b/api/v1alpha1/promotion_types.go @@ -109,6 +109,27 @@ type PromotionVariable struct { Value string `json:"value" protobuf:"bytes,2,opt,name=value"` } +// PromotionRetry describes the retry policy for a PromotionStep. +type PromotionRetry struct { + // Attempts is the number of times the step can be attempted before the + // PromotionStep is marked as failed. + // + // If this field is set to 1, the step will not be retried. If this + // field is set to -1, the step will be retried indefinitely. + // + // The default of this field depends on the step being executed. Refer to + // the documentation for the specific step for more information. + Attempts int64 `json:"attempts,omitempty" protobuf:"varint,1,opt,name=attempts"` +} + +// GetAttempts returns the Attempts field with the given fallback value. +func (r *PromotionRetry) GetAttempts(fallback int64) int64 { + if r == nil || r.Attempts == 0 { + return fallback + } + return r.Attempts +} + // PromotionStep describes a directive to be executed as part of a Promotion. type PromotionStep struct { // Uses identifies a runner that can execute this step. @@ -117,6 +138,8 @@ type PromotionStep struct { Uses string `json:"uses" protobuf:"bytes,1,opt,name=uses"` // As is the alias this step can be referred to as. As string `json:"as,omitempty" protobuf:"bytes,2,opt,name=as"` + // Retry is the retry policy for this step. + Retry *PromotionRetry `json:"retry,omitempty" protobuf:"bytes,4,opt,name=retry"` // Config is opaque configuration for the PromotionStep that is understood // only by each PromotionStep's implementation. It is legal to utilize // expressions in defining values at any level of this block. diff --git a/api/v1alpha1/promotion_types_test.go b/api/v1alpha1/promotion_types_test.go new file mode 100644 index 000000000..f608f7c7b --- /dev/null +++ b/api/v1alpha1/promotion_types_test.go @@ -0,0 +1,39 @@ +package v1alpha1 + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPromotionRetry_GetAttempts(t *testing.T) { + tests := []struct { + name string + retry *PromotionRetry + fallback int64 + want int64 + }{ + { + name: "retry is nil", + retry: nil, + fallback: 1, + want: 1, + }, + { + name: "attempts is not set", + retry: &PromotionRetry{}, + fallback: -1, + want: -1, + }, + { + name: "attempts is set", + retry: &PromotionRetry{ + Attempts: 3, + }, + want: 3, + }, + } + for _, tt := range tests { + require.Equal(t, tt.want, tt.retry.GetAttempts(tt.fallback)) + } +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index fb6807bea..23abc12ad 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -905,6 +905,21 @@ func (in *PromotionReference) DeepCopy() *PromotionReference { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PromotionRetry) DeepCopyInto(out *PromotionRetry) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromotionRetry. +func (in *PromotionRetry) DeepCopy() *PromotionRetry { + if in == nil { + return nil + } + out := new(PromotionRetry) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PromotionSpec) DeepCopyInto(out *PromotionSpec) { *out = *in @@ -976,6 +991,11 @@ func (in *PromotionStatus) DeepCopy() *PromotionStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PromotionStep) DeepCopyInto(out *PromotionStep) { *out = *in + if in.Retry != nil { + in, out := &in.Retry, &out.Retry + *out = new(PromotionRetry) + **out = **in + } if in.Config != nil { in, out := &in.Config, &out.Config *out = new(apiextensionsv1.JSON) diff --git a/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml b/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml index eb19c7814..97a67bcf9 100644 --- a/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml +++ b/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml @@ -95,6 +95,22 @@ spec: expressions in defining values at any level of this block. See https://docs.kargo.io/references/expression-language for details. x-kubernetes-preserve-unknown-fields: true + retry: + description: Retry is the retry policy for this step. + properties: + attempts: + description: |- + Attempts is the number of times the step can be attempted before the + PromotionStep is marked as failed. + + If this field is set to 1, the step will not be retried. If this + field is set to -1, the step will be retried indefinitely. + + The default of this field depends on the step being executed. Refer to + the documentation for the specific step for more information. + format: int64 + type: integer + type: object uses: description: Uses identifies a runner that can execute this step. diff --git a/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml b/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml index 890cfbc95..43da6c6f5 100644 --- a/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml +++ b/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml @@ -88,6 +88,22 @@ spec: expressions in defining values at any level of this block. See https://docs.kargo.io/references/expression-language for details. x-kubernetes-preserve-unknown-fields: true + retry: + description: Retry is the retry policy for this step. + properties: + attempts: + description: |- + Attempts is the number of times the step can be attempted before the + PromotionStep is marked as failed. + + If this field is set to 1, the step will not be retried. If this + field is set to -1, the step will be retried indefinitely. + + The default of this field depends on the step being executed. Refer to + the documentation for the specific step for more information. + format: int64 + type: integer + type: object uses: description: Uses identifies a runner that can execute this step. diff --git a/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json b/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json index 27c269f18..ccbc05e88 100644 --- a/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json +++ b/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json @@ -40,6 +40,19 @@ "description": "Config is opaque configuration for the PromotionStep that is understood\nonly by each PromotionStep's implementation. It is legal to utilize\nexpressions in defining values at any level of this block.\nSee https://docs.kargo.io/references/expression-language for details.", "x-kubernetes-preserve-unknown-fields": true }, + "retry": { + "description": "Retry is the retry policy for this step.", + "properties": { + "attempts": { + "description": "Attempts is the number of times the step can be attempted before the\nPromotionStep is marked as failed.\n\nIf this field is set to 1, the step will not be retried. If this\nfield is set to -1, the step will be retried indefinitely.\n\nThe default of this field depends on the step being executed. Refer to\nthe documentation for the specific step for more information.", + "format": "int64", + "maximum": 9223372036854776000, + "minimum": -9223372036854776000, + "type": "integer" + } + }, + "type": "object" + }, "uses": { "description": "Uses identifies a runner that can execute this step.", "minLength": 1, diff --git a/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json b/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json index c789dc920..a1b0c2611 100644 --- a/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json +++ b/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json @@ -35,6 +35,19 @@ "description": "Config is opaque configuration for the PromotionStep that is understood\nonly by each PromotionStep's implementation. It is legal to utilize\nexpressions in defining values at any level of this block.\nSee https://docs.kargo.io/references/expression-language for details.", "x-kubernetes-preserve-unknown-fields": true }, + "retry": { + "description": "Retry is the retry policy for this step.", + "properties": { + "attempts": { + "description": "Attempts is the number of times the step can be attempted before the\nPromotionStep is marked as failed.\n\nIf this field is set to 1, the step will not be retried. If this\nfield is set to -1, the step will be retried indefinitely.\n\nThe default of this field depends on the step being executed. Refer to\nthe documentation for the specific step for more information.", + "format": "int64", + "maximum": 9223372036854776000, + "minimum": -9223372036854776000, + "type": "integer" + } + }, + "type": "object" + }, "uses": { "description": "Uses identifies a runner that can execute this step.", "minLength": 1, diff --git a/ui/src/gen/v1alpha1/generated_pb.ts b/ui/src/gen/v1alpha1/generated_pb.ts index af35da164..99f9ff553 100644 --- a/ui/src/gen/v1alpha1/generated_pb.ts +++ b/ui/src/gen/v1alpha1/generated_pb.ts @@ -2616,6 +2616,54 @@ export class PromotionReference extends Message { } } +/** + * PromotionRetry describes the retry policy for a PromotionStep. + * + * @generated from message github.com.akuity.kargo.api.v1alpha1.PromotionRetry + */ +export class PromotionRetry extends Message { + /** + * Attempts is the number of times the step can be attempted before the + * PromotionStep is marked as failed. + * + * If this field is set to 1, the step will not be retried. If this + * field is set to -1, the step will be retried indefinitely. + * + * The default of this field depends on the step being executed. Refer to + * the documentation for the specific step for more information. + * + * @generated from field: optional int64 attempts = 1; + */ + attempts?: bigint; + + constructor(data?: PartialMessage) { + super(); + proto2.util.initPartial(data, this); + } + + static readonly runtime: typeof proto2 = proto2; + static readonly typeName = "github.com.akuity.kargo.api.v1alpha1.PromotionRetry"; + static readonly fields: FieldList = proto2.util.newFieldList(() => [ + { no: 1, name: "attempts", kind: "scalar", T: 3 /* ScalarType.INT64 */, opt: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): PromotionRetry { + return new PromotionRetry().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): PromotionRetry { + return new PromotionRetry().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): PromotionRetry { + return new PromotionRetry().fromJsonString(jsonString, options); + } + + static equals(a: PromotionRetry | PlainMessage | undefined, b: PromotionRetry | PlainMessage | undefined): boolean { + return proto2.util.equals(PromotionRetry, a, b); + } +} + /** * PromotionSpec describes the desired transition of a specific Stage into a * specific Freight. @@ -2833,6 +2881,13 @@ export class PromotionStep extends Message { */ as?: string; + /** + * Retry is the retry policy for this step. + * + * @generated from field: optional github.com.akuity.kargo.api.v1alpha1.PromotionRetry retry = 4; + */ + retry?: PromotionRetry; + /** * Config is opaque configuration for the PromotionStep that is understood * only by each PromotionStep's implementation. It is legal to utilize @@ -2853,6 +2908,7 @@ export class PromotionStep extends Message { static readonly fields: FieldList = proto2.util.newFieldList(() => [ { no: 1, name: "uses", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, { no: 2, name: "as", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, + { no: 4, name: "retry", kind: "message", T: PromotionRetry, opt: true }, { no: 3, name: "config", kind: "message", T: JSON, opt: true }, ]); From ce08ad06b201e0fe8e82e56bbaa7264787444fe9 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Mon, 18 Nov 2024 16:15:25 +0100 Subject: [PATCH 2/8] feat: add simple retry mechanism outline Signed-off-by: Hidde Beydals --- internal/directives/argocd_revisions.go | 2 +- internal/directives/git_commiter.go | 5 ++-- internal/directives/git_commiter_test.go | 2 +- internal/directives/git_pr_opener.go | 13 +++++----- internal/directives/git_pr_opener_test.go | 4 ++-- internal/directives/git_pr_waiter.go | 4 ++-- internal/directives/git_pusher.go | 8 ++++--- internal/directives/git_pusher_test.go | 4 ++-- internal/directives/promotions.go | 20 ++++++++++++++-- internal/directives/simple_engine.go | 29 +++++++++++++++++++++-- 10 files changed, 68 insertions(+), 23 deletions(-) diff --git a/internal/directives/argocd_revisions.go b/internal/directives/argocd_revisions.go index acaf966ce..13c2b26a0 100644 --- a/internal/directives/argocd_revisions.go +++ b/internal/directives/argocd_revisions.go @@ -177,7 +177,7 @@ func getCommitFromStep(sharedState State, stepAlias string) (string, error) { return "", fmt.Errorf("output from step with alias %q is not a map[string]any", stepAlias) } - commitAny, exists := stepOutputMap[commitKey] + commitAny, exists := stepOutputMap[stateKeyCommit] if !exists { return "", fmt.Errorf("no commit found in output from step with alias %q", stepAlias) diff --git a/internal/directives/git_commiter.go b/internal/directives/git_commiter.go index 9825dfc29..9dccb0674 100644 --- a/internal/directives/git_commiter.go +++ b/internal/directives/git_commiter.go @@ -11,7 +11,8 @@ import ( "github.com/akuity/kargo/internal/controller/git" ) -const commitKey = "commit" +// stateKeyCommit is the key used to store the commit ID in the shared State. +const stateKeyCommit = "commit" func init() { builtins.RegisterPromotionStepRunner(newGitCommitter(), nil) @@ -111,7 +112,7 @@ func (g *gitCommitter) runPromotionStep( } return PromotionStepResult{ Status: kargoapi.PromotionPhaseSucceeded, - Output: map[string]any{commitKey: commitID}, + Output: map[string]any{stateKeyCommit: commitID}, }, nil } diff --git a/internal/directives/git_commiter_test.go b/internal/directives/git_commiter_test.go index ae59b1639..7a62be37c 100644 --- a/internal/directives/git_commiter_test.go +++ b/internal/directives/git_commiter_test.go @@ -225,7 +225,7 @@ func Test_gitCommitter_runPromotionStep(t *testing.T) { require.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status) expectedCommit, err := workTree.LastCommitID() require.NoError(t, err) - actualCommit, ok := res.Output[commitKey] + actualCommit, ok := res.Output[stateKeyCommit] require.True(t, ok) require.Equal(t, expectedCommit, actualCommit) lastCommitMsg, err := workTree.CommitMessage("HEAD") diff --git a/internal/directives/git_pr_opener.go b/internal/directives/git_pr_opener.go index 0b979c434..5810ac163 100644 --- a/internal/directives/git_pr_opener.go +++ b/internal/directives/git_pr_opener.go @@ -18,7 +18,8 @@ import ( _ "github.com/akuity/kargo/internal/gitprovider/gitlab" // GitLab provider registration ) -const prNumberKey = "prNumber" +// stateKeyPRNumber is the key used to store the PR number in the shared State. +const stateKeyPRNumber = "prNumber" func init() { builtins.RegisterPromotionStepRunner( @@ -83,7 +84,7 @@ func (g *gitPROpener) runPromotionStep( return PromotionStepResult{ Status: kargoapi.PromotionPhaseSucceeded, Output: map[string]any{ - prNumberKey: prNumber, + stateKeyPRNumber: prNumber, }, }, nil } @@ -161,7 +162,7 @@ func (g *gitPROpener) runPromotionStep( return PromotionStepResult{ Status: kargoapi.PromotionPhaseSucceeded, Output: map[string]any{ - prNumberKey: pr.Number, + stateKeyPRNumber: pr.Number, }, }, nil } @@ -219,7 +220,7 @@ func (g *gitPROpener) runPromotionStep( return PromotionStepResult{ Status: kargoapi.PromotionPhaseSucceeded, Output: map[string]any{ - prNumberKey: pr.Number, + stateKeyPRNumber: pr.Number, }, }, nil } @@ -243,7 +244,7 @@ func (g *gitPROpener) getPRNumber( stepCtx.Alias, ) } - prNumberAny, exists := stepOutputMap[prNumberKey] + prNumberAny, exists := stepOutputMap[stateKeyPRNumber] if !exists { return -1, nil } @@ -283,7 +284,7 @@ func (g *gitPROpener) getSourceBranch( cfg.SourceBranchFromStep, ) } - sourceBranchAny, exists := stepOutputMap[branchKey] + sourceBranchAny, exists := stepOutputMap[stateKeyBranch] if !exists { return "", fmt.Errorf( "no branch found in output from step with alias %q", diff --git a/internal/directives/git_pr_opener_test.go b/internal/directives/git_pr_opener_test.go index 00d0e511e..bb4f9074f 100644 --- a/internal/directives/git_pr_opener_test.go +++ b/internal/directives/git_pr_opener_test.go @@ -202,7 +202,7 @@ func Test_gitPROpener_runPromotionStep(t *testing.T) { CredentialsDB: &credentials.FakeDB{}, SharedState: State{ "fake-step": map[string]any{ - branchKey: testSourceBranch, + stateKeyBranch: testSourceBranch, }, }, }, @@ -216,7 +216,7 @@ func Test_gitPROpener_runPromotionStep(t *testing.T) { }, ) require.NoError(t, err) - prNumber, ok := res.Output[prNumberKey] + prNumber, ok := res.Output[stateKeyPRNumber] require.True(t, ok) require.Equal(t, testPRNumber, prNumber) diff --git a/internal/directives/git_pr_waiter.go b/internal/directives/git_pr_waiter.go index 2d29b4ff9..748bdc581 100644 --- a/internal/directives/git_pr_waiter.go +++ b/internal/directives/git_pr_waiter.go @@ -121,7 +121,7 @@ func (g *gitPRWaiter) runPromotionStep( } return PromotionStepResult{ Status: kargoapi.PromotionPhaseSucceeded, - Output: map[string]any{commitKey: pr.MergeCommitSHA}, + Output: map[string]any{stateKeyCommit: pr.MergeCommitSHA}, }, nil } @@ -150,7 +150,7 @@ func (g *gitPRWaiter) getPRNumber( cfg.PRNumberFromStep, ) } - prNumberAny, exists := stepOutputMap[prNumberKey] + prNumberAny, exists := stepOutputMap[stateKeyPRNumber] if !exists { return 0, fmt.Errorf( "no PR number found in output from step with alias %q", diff --git a/internal/directives/git_pusher.go b/internal/directives/git_pusher.go index 8d37f78b5..9f835e72a 100644 --- a/internal/directives/git_pusher.go +++ b/internal/directives/git_pusher.go @@ -12,7 +12,9 @@ import ( "github.com/akuity/kargo/internal/credentials" ) -const branchKey = "branch" +// stateKeyBranch is the key used to store the branch that was pushed to in the +// shared State. +const stateKeyBranch = "branch" func init() { builtins.RegisterPromotionStepRunner( @@ -134,8 +136,8 @@ func (g *gitPushPusher) runPromotionStep( return PromotionStepResult{ Status: kargoapi.PromotionPhaseSucceeded, Output: map[string]any{ - branchKey: targetBranch, - commitKey: commitID, + stateKeyBranch: targetBranch, + stateKeyCommit: commitID, }, }, nil } diff --git a/internal/directives/git_pusher_test.go b/internal/directives/git_pusher_test.go index e900dcbba..7b5618c64 100644 --- a/internal/directives/git_pusher_test.go +++ b/internal/directives/git_pusher_test.go @@ -200,12 +200,12 @@ func Test_gitPusher_runPromotionStep(t *testing.T) { }, ) require.NoError(t, err) - branchName, ok := res.Output[branchKey] + branchName, ok := res.Output[stateKeyBranch] require.True(t, ok) require.Equal(t, "kargo/promotion/fake-promotion", branchName) expectedCommit, err := workTree.LastCommitID() require.NoError(t, err) - actualCommit, ok := res.Output[commitKey] + actualCommit, ok := res.Output[stateKeyCommit] require.True(t, ok) require.Equal(t, expectedCommit, actualCommit) } diff --git a/internal/directives/promotions.go b/internal/directives/promotions.go index 789d56b60..afafe7a01 100644 --- a/internal/directives/promotions.go +++ b/internal/directives/promotions.go @@ -27,6 +27,14 @@ type PromotionStepRunner interface { RunPromotionStep(context.Context, *PromotionStepContext) (PromotionStepResult, error) } +// RetryableStepRunner is an interface for PromotionStepRunners that can be +// retried in the event of a failure. +type RetryableStepRunner interface { + // DefaultAttempts returns the default number of attempts the step is + // allowed to make before failing. + DefaultAttempts() int64 +} + // PromotionContext is the context of a user-defined promotion process that is // executed by the Engine. type PromotionContext struct { @@ -50,10 +58,12 @@ type PromotionContext struct { // resolve. FreightRequests []kargoapi.FreightRequest // Freight is the collection of all Freight referenced by the Promotion. This - // collection contains both the Freight that is actively being promoted as - // well as any Freight that has been inherited from the target Stage's current + // collection contains both the Freight that is actively being promoted and + // any Freight that has been inherited from the target Stage's current // state. Freight kargoapi.FreightCollection + // Retry is the retry configuration for the Promotion. + Retry *kargoapi.PromotionRetry // SharedState is the index of the step from which the promotion should begin // execution. StartFromStep int64 @@ -145,6 +155,8 @@ func (s *PromotionStep) GetConfig( return config, nil } +// GetVars returns the variables defined in the PromotionStep. The variables are +// evaluated in the context of the provided PromotionContext. func (s *PromotionStep) GetVars(promoCtx PromotionContext) (map[string]any, error) { vars := make(map[string]any, len(promoCtx.Vars)) for _, v := range promoCtx.Vars { @@ -167,6 +179,10 @@ func (s *PromotionStep) GetVars(promoCtx PromotionContext) (map[string]any, erro return vars, nil } +// stateKeyAttempts is the key used to store the number of attempts that +// have been made to execute a step in the shared State. +const stateKeyAttempts = "attempts" + // PromotionResult is the result of a user-defined promotion process executed by // the Engine. It aggregates the status and output of the individual // PromotionStepResults returned by the PromotionStepRunner executing each diff --git a/internal/directives/simple_engine.go b/internal/directives/simple_engine.go index d504c91ea..369a8dacd 100644 --- a/internal/directives/simple_engine.go +++ b/internal/directives/simple_engine.go @@ -105,9 +105,10 @@ func (e *SimpleEngine) Promote( stateCopy := state.DeepCopy() step.Alias = strings.TrimSpace(step.Alias) - if step.Alias == "" { + switch { + case step.Alias == "": step.Alias = fmt.Sprintf("step-%d", i) - } else if ReservedStepAliasRegex.MatchString(step.Alias) { + case ReservedStepAliasRegex.MatchString(step.Alias): // A webhook enforces this regex as well, but we're checking here to // account for the possibility of EXISTING Stages with a promotionTemplate // containing a step with a now-reserved alias. @@ -150,7 +151,31 @@ func (e *SimpleEngine) Promote( stepCtx.ArgoCDClient = e.argoCDClient } + var maxAttempts int64 + if retryCfg, isRetryable := reg.Runner.(RetryableStepRunner); isRetryable { + maxAttempts = promoCtx.Retry.GetAttempts(retryCfg.DefaultAttempts()) + } + var attempts int64 + if stepState, ok := stateCopy[step.Alias].(State); ok { + if v, ok := stepState.Get(stateKeyAttempts); ok { + attempts, _ = v.(int64) + } + } + if maxAttempts > 0 && attempts >= maxAttempts { + return PromotionResult{ + Status: kargoapi.PromotionPhaseErrored, + CurrentStep: i, + State: state, + }, fmt.Errorf("step %q exceeded max attempts (%d/%d)", step.Alias, attempts, maxAttempts) + } + result, err := reg.Runner.RunPromotionStep(ctx, stepCtx) + + if result.Output == nil { + result.Output = make(State, 1) + } + result.Output[stateKeyAttempts] = attempts + 1 + state[step.Alias] = result.Output if err != nil { return PromotionResult{ From 5f9e05800759f5383c4c9209a4d99fe4e466d5ec Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Tue, 19 Nov 2024 18:03:04 +0100 Subject: [PATCH 3/8] refactor: split engine into smaller parts Signed-off-by: Hidde Beydals --- internal/controller/promotions/promotions.go | 1 + internal/directives/promotions.go | 56 +- internal/directives/promotions_test.go | 217 ++++++ internal/directives/simple_engine.go | 262 -------- internal/directives/simple_engine_health.go | 115 ++++ .../directives/simple_engine_health_test.go | 332 ++++++++++ internal/directives/simple_engine_promote.go | 248 +++++++ .../directives/simple_engine_promote_test.go | 615 ++++++++++++++++++ internal/directives/simple_engine_test.go | 316 --------- 9 files changed, 1580 insertions(+), 582 deletions(-) create mode 100644 internal/directives/simple_engine_health.go create mode 100644 internal/directives/simple_engine_health_test.go create mode 100644 internal/directives/simple_engine_promote.go create mode 100644 internal/directives/simple_engine_promote_test.go delete mode 100644 internal/directives/simple_engine_test.go diff --git a/internal/controller/promotions/promotions.go b/internal/controller/promotions/promotions.go index 35c2cc146..fab588b82 100644 --- a/internal/controller/promotions/promotions.go +++ b/internal/controller/promotions/promotions.go @@ -468,6 +468,7 @@ func (r *reconciler) promote( steps[i] = directives.PromotionStep{ Kind: step.Uses, Alias: step.As, + Retry: step.Retry, Config: step.Config.Raw, } } diff --git a/internal/directives/promotions.go b/internal/directives/promotions.go index afafe7a01..2b59d4ec8 100644 --- a/internal/directives/promotions.go +++ b/internal/directives/promotions.go @@ -35,6 +35,10 @@ type RetryableStepRunner interface { DefaultAttempts() int64 } +// stateKeyAttempts is the key used to store the number of attempts that +// have been made to execute a step in the shared State. +const stateKeyAttempts = "attempts" + // PromotionContext is the context of a user-defined promotion process that is // executed by the Engine. type PromotionContext struct { @@ -88,11 +92,59 @@ type PromotionStep struct { // step will be keyed to this alias by the Engine and made accessible to // subsequent steps. Alias string + // Retry is the retry configuration for the PromotionStep. + Retry *kargoapi.PromotionRetry // Config is an opaque JSON to be passed to the PromotionStepRunner executing // this step. Config []byte } +// GetAttempts returns the number of attempts that have been made to execute +// the step using the provided State. If no attempts have been made, 0 is +// returned. +func (s *PromotionStep) GetAttempts(state State) int64 { + if stepV, ok := state.Get(s.Alias); ok { + if stepState, ok := stepV.(map[string]any); ok { + if attemptsV, ok := stepState[stateKeyAttempts]; ok { + switch attempts := attemptsV.(type) { + case int64: + return attempts + case int: + return int64(attempts) + // If the State has been rehydrated from a JSON representation, + // the attempts value may be a float64. Convert it to an int64. + case float64: + return int64(attempts) + } + } + } + } + return 0 +} + +// GetMaxAttempts returns the maximum number of attempts that can be made to +// execute the step using the provided runner. If the runner is a +// RetryableStepRunner, the value of its retry configuration is used as the +// maximum default. Otherwise, the default is 1. +func (s *PromotionStep) GetMaxAttempts(runner any) int64 { + fallback := int64(1) + if retryCfg, isRetryable := runner.(RetryableStepRunner); isRetryable { + fallback = retryCfg.DefaultAttempts() + } + return s.Retry.GetAttempts(fallback) +} + +// RecordAttempt records an attempt to execute a step in the provided +// output. +func (s *PromotionStep) RecordAttempt(state State, output map[string]any) map[string]any { + attempts := s.GetAttempts(state) + if output == nil { + output = make(map[string]any, 1) + } + output[stateKeyAttempts] = attempts + 1 + return output +} + // GetConfig returns the Config unmarshalled into a map. Any expr-lang // expressions are evaluated in the context of the provided arguments // prior to unmarshaling. @@ -179,10 +231,6 @@ func (s *PromotionStep) GetVars(promoCtx PromotionContext) (map[string]any, erro return vars, nil } -// stateKeyAttempts is the key used to store the number of attempts that -// have been made to execute a step in the shared State. -const stateKeyAttempts = "attempts" - // PromotionResult is the result of a user-defined promotion process executed by // the Engine. It aggregates the status and output of the individual // PromotionStepResults returned by the PromotionStepRunner executing each diff --git a/internal/directives/promotions_test.go b/internal/directives/promotions_test.go index cd86d3a8c..06436be2e 100644 --- a/internal/directives/promotions_test.go +++ b/internal/directives/promotions_test.go @@ -4,11 +4,228 @@ import ( "context" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" kargoapi "github.com/akuity/kargo/api/v1alpha1" ) +type mockRetryableRunner struct { + defaultAttempts int64 +} + +func (m mockRetryableRunner) DefaultAttempts() int64 { + return m.defaultAttempts +} + +func TestPromotionStep_GetAttempts(t *testing.T) { + tests := []struct { + name string + step *PromotionStep + state State + assertions func(t *testing.T, result int64) + }{ + { + name: "returns 0 when state does not contain alias entry", + step: &PromotionStep{ + Alias: "step-1", + }, + state: State{}, + assertions: func(t *testing.T, result int64) { + assert.Equal(t, int64(0), result) + }, + }, + { + name: "returns 0 when state has alias entry but no attempts key", + step: &PromotionStep{ + Alias: "custom-alias", + }, + state: State{ + "custom-alias": map[string]any{ + "someOtherKey": "value", + }, + }, + assertions: func(t *testing.T, result int64) { + assert.Equal(t, int64(0), result) + }, + }, + { + name: "correctly converts float64 attempts", + step: &PromotionStep{ + Alias: "step-1", + }, + state: State{ + "step-1": map[string]any{ + stateKeyAttempts: float64(3), + }, + }, + assertions: func(t *testing.T, result int64) { + assert.Equal(t, int64(3), result) + }, + }, + { + name: "correctly handles int64 attempts", + step: &PromotionStep{ + Alias: "step-2", + }, + state: State{ + "step-2": map[string]any{ + stateKeyAttempts: int64(1), + }, + }, + assertions: func(t *testing.T, result int64) { + assert.Equal(t, int64(1), result) + }, + }, + { + name: "returns 0 when attempts value is not a number", + step: &PromotionStep{ + Alias: "invalid", + }, + state: State{ + "invalid": map[string]any{ + stateKeyAttempts: "not a number", + }, + }, + assertions: func(t *testing.T, result int64) { + assert.Equal(t, int64(0), result) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tt.step.GetAttempts(tt.state) + tt.assertions(t, result) + }) + } +} + +func TestPromotionStep_GetMaxAttempts(t *testing.T) { + tests := []struct { + name string + step *PromotionStep + runner any + assertions func(t *testing.T, result int64) + }{ + { + name: "returns 1 with no retry config", + step: &PromotionStep{ + Retry: nil, + }, + assertions: func(t *testing.T, result int64) { + assert.Equal(t, int64(1), result) + }, + }, + { + name: "returns configured attempts for non-retryable runner", + step: &PromotionStep{ + Retry: &kargoapi.PromotionRetry{ + Attempts: 5, + }, + }, + runner: nil, + assertions: func(t *testing.T, result int64) { + assert.Equal(t, int64(5), result) + }, + }, + { + name: "returns configured attempts for retryable runner", + step: &PromotionStep{ + Retry: &kargoapi.PromotionRetry{ + Attempts: 5, + }, + }, + runner: mockRetryableRunner{defaultAttempts: 3}, + assertions: func(t *testing.T, result int64) { + assert.Equal(t, int64(5), result) + }, + }, + { + name: "returns default attempts when retry config returns 0", + step: &PromotionStep{ + Retry: &kargoapi.PromotionRetry{ + Attempts: 0, + }, + }, + runner: mockRetryableRunner{defaultAttempts: 3}, + assertions: func(t *testing.T, result int64) { + assert.Equal(t, int64(3), result) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := tt.step.GetMaxAttempts(tt.runner) + tt.assertions(t, result) + }) + } +} + +func TestPromotionStep_RecordAttempt(t *testing.T) { + tests := []struct { + name string + step *PromotionStep + state State + output map[string]any + assertions func(*testing.T, map[string]any) + }{ + { + name: "increment attempt counter", + step: &PromotionStep{ + Alias: "foo", + }, + state: State{ + "foo": map[string]any{"attempts": 2}, + }, + assertions: func(t *testing.T, output map[string]any) { + assert.Equal(t, int64(3), output["attempts"]) + }, + }, + { + name: "initialize attempt counter", + step: &PromotionStep{ + Alias: "foo", + }, + assertions: func(t *testing.T, output map[string]any) { + assert.Equal(t, int64(1), output["attempts"]) + }, + }, + { + name: "preserve existing output", + step: &PromotionStep{ + Alias: "foo", + }, + output: map[string]any{"existing": "value"}, + assertions: func(t *testing.T, output map[string]any) { + assert.Equal(t, int64(1), output["attempts"]) + assert.Equal(t, "value", output["existing"]) + }, + }, + { + name: "overwrites attempts value modified by runner", + step: &PromotionStep{ + Alias: "foo", + }, + state: State{ + "foo": map[string]any{"attempts": 2}, + }, + output: map[string]any{"attempts": 5}, + assertions: func(t *testing.T, output map[string]any) { + assert.Equal(t, int64(3), output["attempts"]) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + output := tt.step.RecordAttempt(tt.state, tt.output) + tt.assertions(t, output) + }) + } +} + func TestPromotionStep_GetConfig(t *testing.T) { promoCtx := PromotionContext{ Project: "fake-project", diff --git a/internal/directives/simple_engine.go b/internal/directives/simple_engine.go index 369a8dacd..b56a0871f 100644 --- a/internal/directives/simple_engine.go +++ b/internal/directives/simple_engine.go @@ -1,18 +1,10 @@ package directives import ( - "context" - "encoding/json" - "fmt" - "os" "regexp" - "strings" - corev1 "k8s.io/api/core/v1" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "sigs.k8s.io/controller-runtime/pkg/client" - kargoapi "github.com/akuity/kargo/api/v1alpha1" "github.com/akuity/kargo/internal/credentials" ) @@ -43,257 +35,3 @@ func NewSimpleEngine( argoCDClient: argoCDClient, } } - -// Promote implements the Engine interface. -func (e *SimpleEngine) Promote( - ctx context.Context, - promoCtx PromotionContext, - steps []PromotionStep, -) (PromotionResult, error) { - workDir := promoCtx.WorkDir - if workDir == "" { - var err error - workDir, err = os.MkdirTemp("", "run-") - if err != nil { - return PromotionResult{ - Status: kargoapi.PromotionPhaseErrored, - CurrentStep: 0, - }, - fmt.Errorf("temporary working directory creation failed: %w", err) - } - defer os.RemoveAll(workDir) - } - - var err error - promoCtx.Secrets, err = e.getSecretsMap(ctx, promoCtx.Project) - if err != nil { - return PromotionResult{ - Status: kargoapi.PromotionPhaseErrored, - CurrentStep: 0, - }, - err - } - - // Initialize the shared state that will be passed to each step. - state := promoCtx.State.DeepCopy() - if state == nil { - state = make(State) - } - var healthCheckSteps []HealthCheckStep - - for i := promoCtx.StartFromStep; i < int64(len(steps)); i++ { - step := steps[i] - select { - case <-ctx.Done(): - return PromotionResult{ - Status: kargoapi.PromotionPhaseErrored, - CurrentStep: i, - State: state, - }, ctx.Err() - default: - } - reg, err := e.registry.GetPromotionStepRunnerRegistration(step.Kind) - if err != nil { - return PromotionResult{ - Status: kargoapi.PromotionPhaseErrored, - CurrentStep: i, - State: state, - }, - fmt.Errorf("no runner registered for step kind %q: %w", step.Kind, err) - } - - stateCopy := state.DeepCopy() - - step.Alias = strings.TrimSpace(step.Alias) - switch { - case step.Alias == "": - step.Alias = fmt.Sprintf("step-%d", i) - case ReservedStepAliasRegex.MatchString(step.Alias): - // A webhook enforces this regex as well, but we're checking here to - // account for the possibility of EXISTING Stages with a promotionTemplate - // containing a step with a now-reserved alias. - return PromotionResult{ - Status: kargoapi.PromotionPhaseErrored, - CurrentStep: i, - State: state, - }, fmt.Errorf("step alias %q is forbidden", step.Alias) - } - - stepCfg, err := step.GetConfig(ctx, e.kargoClient, promoCtx, stateCopy) - if err != nil { - return PromotionResult{ - Status: kargoapi.PromotionPhaseErrored, - CurrentStep: i, - State: state, - }, - fmt.Errorf("failed to get step config: %w", err) - } - stepCtx := &PromotionStepContext{ - UIBaseURL: promoCtx.UIBaseURL, - WorkDir: workDir, - SharedState: stateCopy, - Alias: step.Alias, - Config: stepCfg, - Project: promoCtx.Project, - Stage: promoCtx.Stage, - Promotion: promoCtx.Promotion, - FreightRequests: promoCtx.FreightRequests, - Freight: promoCtx.Freight, - } - // Selectively provide these capabilities via the PromotionStepContext. - if reg.Permissions.AllowCredentialsDB { - stepCtx.CredentialsDB = e.credentialsDB - } - if reg.Permissions.AllowKargoClient { - stepCtx.KargoClient = e.kargoClient - } - if reg.Permissions.AllowArgoCDClient { - stepCtx.ArgoCDClient = e.argoCDClient - } - - var maxAttempts int64 - if retryCfg, isRetryable := reg.Runner.(RetryableStepRunner); isRetryable { - maxAttempts = promoCtx.Retry.GetAttempts(retryCfg.DefaultAttempts()) - } - var attempts int64 - if stepState, ok := stateCopy[step.Alias].(State); ok { - if v, ok := stepState.Get(stateKeyAttempts); ok { - attempts, _ = v.(int64) - } - } - if maxAttempts > 0 && attempts >= maxAttempts { - return PromotionResult{ - Status: kargoapi.PromotionPhaseErrored, - CurrentStep: i, - State: state, - }, fmt.Errorf("step %q exceeded max attempts (%d/%d)", step.Alias, attempts, maxAttempts) - } - - result, err := reg.Runner.RunPromotionStep(ctx, stepCtx) - - if result.Output == nil { - result.Output = make(State, 1) - } - result.Output[stateKeyAttempts] = attempts + 1 - - state[step.Alias] = result.Output - if err != nil { - return PromotionResult{ - Status: kargoapi.PromotionPhaseErrored, - CurrentStep: i, - State: state, - }, - fmt.Errorf("failed to run step %q: %w", step.Kind, err) - } - - if result.Status != kargoapi.PromotionPhaseSucceeded { - return PromotionResult{ - Status: result.Status, - Message: result.Message, - CurrentStep: i, - State: state, - }, nil - } - - if result.HealthCheckStep != nil { - healthCheckSteps = append(healthCheckSteps, *result.HealthCheckStep) - } - } - return PromotionResult{ - Status: kargoapi.PromotionPhaseSucceeded, - HealthCheckSteps: healthCheckSteps, - CurrentStep: int64(len(steps)) - 1, - State: state, - }, nil -} - -// CheckHealth implements the Engine interface. -func (e *SimpleEngine) CheckHealth( - ctx context.Context, - healthCtx HealthCheckContext, - steps []HealthCheckStep, -) kargoapi.Health { - healthStatus := kargoapi.HealthStateHealthy - healthIssues := []string{} - healthOutput := make([]State, 0, len(steps)) -stepLoop: - for _, step := range steps { - select { - case <-ctx.Done(): - healthStatus = healthStatus.Merge(kargoapi.HealthStateUnknown) - healthIssues = append(healthIssues, ctx.Err().Error()) - break stepLoop - default: - } - reg, err := e.registry.GetHealthCheckStepRunnerRegistration(step.Kind) - if err != nil { - healthStatus = healthStatus.Merge(kargoapi.HealthStateUnknown) - healthIssues = append( - healthIssues, - fmt.Sprintf("no runner registered for step kind %q: %s", step.Kind, err.Error()), - ) - continue - } - stepCtx := &HealthCheckStepContext{ - Config: step.Config.DeepCopy(), - Project: healthCtx.Project, - Stage: healthCtx.Stage, - } - // Selectively provide these capabilities via the PromotionStepContext. - if reg.Permissions.AllowCredentialsDB { - stepCtx.CredentialsDB = e.credentialsDB - } - if reg.Permissions.AllowKargoClient { - stepCtx.KargoClient = e.kargoClient - } - if reg.Permissions.AllowArgoCDClient { - stepCtx.ArgoCDClient = e.argoCDClient - } - result := reg.Runner.RunHealthCheckStep(ctx, stepCtx) - healthStatus = healthStatus.Merge(result.Status) - healthIssues = append(healthIssues, result.Issues...) - healthOutput = append(healthOutput, result.Output) - } - if len(healthOutput) == 0 { - return kargoapi.Health{ - Status: healthStatus, - Issues: healthIssues, - } - } - bytes, err := json.Marshal(healthOutput) - if err != nil { - // Leave the status alone. Whatever it was determined to be was correct. - healthIssues = append( - healthIssues, - fmt.Sprintf("failed to marshal health output: %s", err.Error()), - ) - } - return kargoapi.Health{ - Status: healthStatus, - Issues: healthIssues, - Output: &apiextensionsv1.JSON{Raw: bytes}, - } -} - -func (e *SimpleEngine) getSecretsMap( - ctx context.Context, - project string, -) (map[string]map[string]string, error) { - secrets := corev1.SecretList{} - if err := e.kargoClient.List( - ctx, - &secrets, - client.InNamespace(project), - ); err != nil { - return nil, - fmt.Errorf("error listing Secrets for Project %q: %w", project, err) - } - secretsMap := make(map[string]map[string]string, len(secrets.Items)) - for _, secret := range secrets.Items { - secretsMap[secret.Name] = make(map[string]string, len(secret.Data)) - for key, value := range secret.Data { - secretsMap[secret.Name][key] = string(value) - } - } - return secretsMap, nil -} diff --git a/internal/directives/simple_engine_health.go b/internal/directives/simple_engine_health.go new file mode 100644 index 000000000..1c785ffe4 --- /dev/null +++ b/internal/directives/simple_engine_health.go @@ -0,0 +1,115 @@ +package directives + +import ( + "context" + "encoding/json" + "fmt" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" +) + +// CheckHealth implements the Engine interface. +func (e *SimpleEngine) CheckHealth( + ctx context.Context, + healthCtx HealthCheckContext, + steps []HealthCheckStep, +) kargoapi.Health { + status, issues, output := e.executeHealthChecks(ctx, healthCtx, steps) + if len(output) == 0 { + return kargoapi.Health{ + Status: status, + Issues: issues, + } + } + + b, err := json.Marshal(output) + if err != nil { + issues = append(issues, fmt.Sprintf("failed to marshal health output: %s", err.Error())) + } + + return kargoapi.Health{ + Status: status, + Issues: issues, + Output: &apiextensionsv1.JSON{Raw: b}, + } +} + +// executeHealthChecks executes a list of HealthCheckSteps in sequence. +func (e *SimpleEngine) executeHealthChecks( + ctx context.Context, + healthCtx HealthCheckContext, + steps []HealthCheckStep, +) (kargoapi.HealthState, []string, []State) { + var ( + aggregatedStatus = kargoapi.HealthStateHealthy + aggregatedIssues []string + aggregatedOutput = make([]State, 0, len(steps)) + ) + + for _, step := range steps { + select { + case <-ctx.Done(): + aggregatedStatus = aggregatedStatus.Merge(kargoapi.HealthStateUnknown) + aggregatedIssues = append(aggregatedIssues, ctx.Err().Error()) + return aggregatedStatus, aggregatedIssues, aggregatedOutput + default: + } + + result := e.executeHealthCheck(ctx, healthCtx, step) + aggregatedStatus = aggregatedStatus.Merge(result.Status) + aggregatedIssues = append(aggregatedIssues, result.Issues...) + + if result.Output != nil { + aggregatedOutput = append(aggregatedOutput, result.Output) + } + } + + return aggregatedStatus, aggregatedIssues, aggregatedOutput +} + +// executeHealthCheck executes a single HealthCheckStep. +func (e *SimpleEngine) executeHealthCheck( + ctx context.Context, + healthCtx HealthCheckContext, + step HealthCheckStep, +) HealthCheckStepResult { + reg, err := e.registry.GetHealthCheckStepRunnerRegistration(step.Kind) + if err != nil { + return HealthCheckStepResult{ + Status: kargoapi.HealthStateUnknown, + Issues: []string{ + fmt.Sprintf("no runner registered for step kind %q: %s", step.Kind, err.Error()), + }, + } + } + + stepCtx := e.prepareHealthCheckStepContext(healthCtx, step, reg) + return reg.Runner.RunHealthCheckStep(ctx, stepCtx) +} + +// prepareHealthCheckStepContext prepares a HealthCheckStepContext for a HealthCheckStep. +func (e *SimpleEngine) prepareHealthCheckStepContext( + healthCtx HealthCheckContext, + step HealthCheckStep, + reg HealthCheckStepRunnerRegistration, +) *HealthCheckStepContext { + stepCtx := &HealthCheckStepContext{ + Config: step.Config.DeepCopy(), + Project: healthCtx.Project, + Stage: healthCtx.Stage, + } + + if reg.Permissions.AllowCredentialsDB { + stepCtx.CredentialsDB = e.credentialsDB + } + if reg.Permissions.AllowKargoClient { + stepCtx.KargoClient = e.kargoClient + } + if reg.Permissions.AllowArgoCDClient { + stepCtx.ArgoCDClient = e.argoCDClient + } + + return stepCtx +} diff --git a/internal/directives/simple_engine_health_test.go b/internal/directives/simple_engine_health_test.go new file mode 100644 index 000000000..91a70de1c --- /dev/null +++ b/internal/directives/simple_engine_health_test.go @@ -0,0 +1,332 @@ +package directives + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" + "github.com/akuity/kargo/internal/credentials" +) + +func TestSimpleEngine_CheckHealth(t *testing.T) { + tests := []struct { + name string + healthCtx HealthCheckContext + steps []HealthCheckStep + assertions func(*testing.T, kargoapi.Health) + }{ + { + name: "successful health check", + steps: []HealthCheckStep{ + {Kind: "success-check"}, + }, + assertions: func(t *testing.T, health kargoapi.Health) { + assert.Equal(t, kargoapi.HealthStateHealthy, health.Status) + assert.Empty(t, health.Issues) + assert.NotNil(t, health.Output) + assert.JSONEq(t, `[{"test":"success"}]`, string(health.Output.Raw)) + }, + }, + { + name: "multiple successful health checks", + steps: []HealthCheckStep{ + {Kind: "success-check"}, + {Kind: "success-check"}, + }, + assertions: func(t *testing.T, health kargoapi.Health) { + assert.Equal(t, kargoapi.HealthStateHealthy, health.Status) + assert.Empty(t, health.Issues) + assert.NotNil(t, health.Output) + assert.JSONEq(t, `[{"test":"success"},{"test":"success"}]`, string(health.Output.Raw)) + }, + }, + { + name: "failed health check", + steps: []HealthCheckStep{ + {Kind: "error-check"}, + }, + assertions: func(t *testing.T, health kargoapi.Health) { + assert.Equal(t, kargoapi.HealthStateUnhealthy, health.Status) + assert.Contains(t, health.Issues, "health check failed") + assert.NotNil(t, health.Output) + }, + }, + { + name: "context cancellation", + steps: []HealthCheckStep{ + {Kind: "context-waiter"}, + }, + assertions: func(t *testing.T, health kargoapi.Health) { + assert.Equal(t, kargoapi.HealthStateUnknown, health.Status) + assert.Contains(t, health.Issues, context.Canceled.Error()) + assert.Nil(t, health.Output) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + testRegistry := NewStepRunnerRegistry() + testRegistry.RegisterHealthCheckStepRunner( + &mockHealthCheckStepRunner{ + name: "success-check", + runResult: HealthCheckStepResult{ + Status: kargoapi.HealthStateHealthy, + Output: State{"test": "success"}, + }, + }, + nil, + ) + testRegistry.RegisterHealthCheckStepRunner( + &mockHealthCheckStepRunner{ + name: "error-check", + runResult: HealthCheckStepResult{ + Status: kargoapi.HealthStateUnhealthy, + Issues: []string{"health check failed"}, + Output: State{"test": "error"}, + }, + }, + nil, + ) + testRegistry.RegisterHealthCheckStepRunner( + &mockHealthCheckStepRunner{ + name: "context-waiter", + runFunc: func(ctx context.Context, _ *HealthCheckStepContext) HealthCheckStepResult { + cancel() + <-ctx.Done() + return HealthCheckStepResult{ + Status: kargoapi.HealthStateUnknown, + Issues: []string{ctx.Err().Error()}, + } + }, + }, + nil, + ) + + engine := &SimpleEngine{ + registry: testRegistry, + } + + health := engine.CheckHealth(ctx, tt.healthCtx, tt.steps) + tt.assertions(t, health) + }) + } +} + +func TestSimpleEngine_executeHealthChecks(t *testing.T) { + tests := []struct { + name string + healthCtx HealthCheckContext + steps []HealthCheckStep + assertions func(*testing.T, kargoapi.HealthState, []string, []State) + }{ + { + name: "aggregate multiple healthy checks", + steps: []HealthCheckStep{ + {Kind: "success-check"}, + {Kind: "success-check"}, + }, + assertions: func(t *testing.T, status kargoapi.HealthState, issues []string, output []State) { + assert.Equal(t, kargoapi.HealthStateHealthy, status) + assert.Empty(t, issues) + assert.Len(t, output, 2) + for _, o := range output { + assert.Equal(t, "success", o["test"]) + } + }, + }, + { + name: "merge different health states", + steps: []HealthCheckStep{ + {Kind: "success-check"}, + {Kind: "error-check"}, + }, + assertions: func(t *testing.T, status kargoapi.HealthState, issues []string, output []State) { + assert.Equal(t, kargoapi.HealthStateUnhealthy, status) + assert.Contains(t, issues, "health check failed") + assert.Len(t, output, 2) + }, + }, + { + name: "context cancellation", + steps: []HealthCheckStep{ + {Kind: "context-waiter"}, + {Kind: "success-check"}, // Should not execute + }, + assertions: func(t *testing.T, status kargoapi.HealthState, issues []string, output []State) { + assert.Equal(t, kargoapi.HealthStateUnknown, status) + assert.Contains(t, issues, context.Canceled.Error()) + assert.Empty(t, output) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + testRegistry := NewStepRunnerRegistry() + testRegistry.RegisterHealthCheckStepRunner( + &mockHealthCheckStepRunner{ + name: "success-check", + runResult: HealthCheckStepResult{ + Status: kargoapi.HealthStateHealthy, + Output: State{"test": "success"}, + }, + }, + nil, + ) + testRegistry.RegisterHealthCheckStepRunner( + &mockHealthCheckStepRunner{ + name: "error-check", + runResult: HealthCheckStepResult{ + Status: kargoapi.HealthStateUnhealthy, + Issues: []string{"health check failed"}, + Output: State{"test": "error"}, + }, + }, + nil, + ) + testRegistry.RegisterHealthCheckStepRunner( + &mockHealthCheckStepRunner{ + name: "context-waiter", + runFunc: func(ctx context.Context, _ *HealthCheckStepContext) HealthCheckStepResult { + cancel() + <-ctx.Done() + return HealthCheckStepResult{ + Status: kargoapi.HealthStateUnknown, + Issues: []string{ctx.Err().Error()}, + } + }, + }, + nil, + ) + + engine := &SimpleEngine{ + registry: testRegistry, + } + + status, issues, output := engine.executeHealthChecks(ctx, tt.healthCtx, tt.steps) + tt.assertions(t, status, issues, output) + }) + } +} + +func TestSimpleEngine_executeHealthCheck(t *testing.T) { + tests := []struct { + name string + healthCtx HealthCheckContext + step HealthCheckStep + assertions func(*testing.T, HealthCheckStepResult) + }{ + { + name: "successful execution", + step: HealthCheckStep{Kind: "success-check"}, + assertions: func(t *testing.T, result HealthCheckStepResult) { + assert.Equal(t, kargoapi.HealthStateHealthy, result.Status) + assert.Empty(t, result.Issues) + }, + }, + { + name: "unregistered runner", + step: HealthCheckStep{Kind: "unknown"}, + assertions: func(t *testing.T, result HealthCheckStepResult) { + assert.Equal(t, kargoapi.HealthStateUnknown, result.Status) + assert.Contains(t, result.Issues[0], "no runner registered for step kind") + assert.Contains(t, result.Issues[0], "unknown") + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testRegistry := NewStepRunnerRegistry() + testRegistry.RegisterHealthCheckStepRunner( + &mockHealthCheckStepRunner{ + name: "success-check", + runResult: HealthCheckStepResult{ + Status: kargoapi.HealthStateHealthy, + }, + }, + nil, + ) + + engine := &SimpleEngine{ + registry: testRegistry, + } + + result := engine.executeHealthCheck(context.Background(), tt.healthCtx, tt.step) + tt.assertions(t, result) + }) + } +} + +func TestSimpleEngine_prepareHealthCheckStepContext(t *testing.T) { + tests := []struct { + name string + healthCtx HealthCheckContext + step HealthCheckStep + permissions StepRunnerPermissions + assertions func(*testing.T, *HealthCheckStepContext) + }{ + { + name: "context with all permissions", + healthCtx: HealthCheckContext{ + Project: "test-project", + Stage: "test-stage", + }, + step: HealthCheckStep{ + Config: map[string]any{ + "key": "value", + }, + }, + permissions: StepRunnerPermissions{ + AllowCredentialsDB: true, + AllowKargoClient: true, + AllowArgoCDClient: true, + }, + assertions: func(t *testing.T, ctx *HealthCheckStepContext) { + assert.Equal(t, "test-project", ctx.Project) + assert.Equal(t, "test-stage", ctx.Stage) + assert.NotNil(t, ctx.Config) + assert.NotNil(t, ctx.CredentialsDB) + assert.NotNil(t, ctx.KargoClient) + assert.NotNil(t, ctx.ArgoCDClient) + }, + }, + { + name: "context without permissions", + step: HealthCheckStep{}, + permissions: StepRunnerPermissions{}, + assertions: func(t *testing.T, ctx *HealthCheckStepContext) { + assert.Nil(t, ctx.CredentialsDB) + assert.Nil(t, ctx.KargoClient) + assert.Nil(t, ctx.ArgoCDClient) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + engine := &SimpleEngine{ + credentialsDB: &credentials.FakeDB{}, + kargoClient: fake.NewClientBuilder().Build(), + argoCDClient: fake.NewClientBuilder().Build(), + } + + reg := HealthCheckStepRunnerRegistration{ + Permissions: tt.permissions, + } + + ctx := engine.prepareHealthCheckStepContext(tt.healthCtx, tt.step, reg) + tt.assertions(t, ctx) + }) + } +} diff --git a/internal/directives/simple_engine_promote.go b/internal/directives/simple_engine_promote.go new file mode 100644 index 000000000..0066233cf --- /dev/null +++ b/internal/directives/simple_engine_promote.go @@ -0,0 +1,248 @@ +package directives + +import ( + "context" + "fmt" + "os" + "strings" + + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" +) + +// Promote implements the Engine interface. +func (e *SimpleEngine) Promote( + ctx context.Context, + promoCtx PromotionContext, + steps []PromotionStep, +) (PromotionResult, error) { + workDir, err := e.setupWorkDir(promoCtx.WorkDir) + if err != nil { + return PromotionResult{Status: kargoapi.PromotionPhaseErrored}, err + } + if workDir != promoCtx.WorkDir { + defer os.RemoveAll(workDir) + } + + if promoCtx.Secrets, err = e.getProjectSecrets(ctx, promoCtx.Project); err != nil { + return PromotionResult{Status: kargoapi.PromotionPhaseErrored}, err + } + + result, err := e.executeSteps(ctx, promoCtx, steps, workDir) + if err != nil { + return result, fmt.Errorf("step execution failed: %w", err) + } + + return result, nil +} + +// executeSteps executes a list of PromotionSteps in sequence. +func (e *SimpleEngine) executeSteps( + ctx context.Context, + promoCtx PromotionContext, + steps []PromotionStep, + workDir string, +) (PromotionResult, error) { + // Initialize the state which will be passed to each step. + // This is the state that will be updated by each step, + // and returned as the final state after all steps have + // run. + state := promoCtx.State.DeepCopy() + if state == nil { + state = make(State) + } + + var ( + healthChecks []HealthCheckStep + err error + ) + + // Execute each step in sequence, starting from the step index + // specified in the PromotionContext if provided. + for i := promoCtx.StartFromStep; i < int64(len(steps)); i++ { + select { + case <-ctx.Done(): + return PromotionResult{ + Status: kargoapi.PromotionPhaseErrored, + CurrentStep: i, + State: state, + }, ctx.Err() + default: + } + + // Prepare the step for execution by setting the alias. + step := steps[i] + if step.Alias, err = e.stepAlias(step.Alias, i); err != nil { + return PromotionResult{ + Status: kargoapi.PromotionPhaseErrored, + CurrentStep: i, + State: state, + }, err + } + + // Execute the step. + result, err := e.executeStep(ctx, promoCtx, step, workDir, state) + + // Update the state with the step output, regardless of the result. + state[step.Alias] = result.Output + + // If the step was not successful, return the result to wait for + // a next attempt or to fail the promotion. + if result.Status != kargoapi.PromotionPhaseSucceeded { + return PromotionResult{ + Status: result.Status, + Message: result.Message, + CurrentStep: i, + State: state, + }, err + } + + // If the step was successful, add its health check to the list. + if healthCheck := result.HealthCheckStep; healthCheck != nil { + healthChecks = append(healthChecks, *healthCheck) + } + } + + // All steps have succeeded, return the final state. + return PromotionResult{ + Status: kargoapi.PromotionPhaseSucceeded, + HealthCheckSteps: healthChecks, + CurrentStep: int64(len(steps)) - 1, + State: state, + }, nil +} + +// executeStep executes a single PromotionStep. +func (e *SimpleEngine) executeStep( + ctx context.Context, + promoCtx PromotionContext, + step PromotionStep, + workDir string, + state State, +) (PromotionStepResult, error) { + reg, err := e.registry.GetPromotionStepRunnerRegistration(step.Kind) + if err != nil { + return PromotionStepResult{ + Status: kargoapi.PromotionPhaseErrored, + }, err + } + + stepCtx, err := e.preparePromotionStepContext(ctx, promoCtx, step, workDir, state, reg) + if err != nil { + return PromotionStepResult{ + Status: kargoapi.PromotionPhaseErrored, + }, err + } + + // Check if the step has exceeded the maximum number of attempts. + if step.GetAttempts(promoCtx.State) >= step.GetMaxAttempts(reg.Runner) { + return PromotionStepResult{ + Status: kargoapi.PromotionPhaseErrored, + }, fmt.Errorf("step %q exceeded max attempts", step.Alias) + } + + // Run the step and record the attempt (regardless of the result). + result, err := reg.Runner.RunPromotionStep(ctx, stepCtx) + result.Output = step.RecordAttempt(state, result.Output) + + if err != nil { + err = fmt.Errorf("failed to run step %q: %w", step.Kind, err) + } + return result, err +} + +// preparePromotionStepContext prepares a PromotionStepContext for a PromotionStep. +func (e *SimpleEngine) preparePromotionStepContext( + ctx context.Context, + promoCtx PromotionContext, + step PromotionStep, + workDir string, + state State, + reg PromotionStepRunnerRegistration, +) (*PromotionStepContext, error) { + stateCopy := state.DeepCopy() + + stepCfg, err := step.GetConfig(ctx, e.kargoClient, promoCtx, stateCopy) + if err != nil { + return nil, fmt.Errorf("failed to get step config: %w", err) + } + + stepCtx := &PromotionStepContext{ + UIBaseURL: promoCtx.UIBaseURL, + WorkDir: workDir, + SharedState: stateCopy, + Alias: step.Alias, + Config: stepCfg, + Project: promoCtx.Project, + Stage: promoCtx.Stage, + Promotion: promoCtx.Promotion, + FreightRequests: promoCtx.FreightRequests, + Freight: promoCtx.Freight, + } + + if reg.Permissions.AllowCredentialsDB { + stepCtx.CredentialsDB = e.credentialsDB + } + if reg.Permissions.AllowKargoClient { + stepCtx.KargoClient = e.kargoClient + } + if reg.Permissions.AllowArgoCDClient { + stepCtx.ArgoCDClient = e.argoCDClient + } + + return stepCtx, nil +} + +// stepAlias returns the alias for a step. If the alias is empty, a default +// alias is returned based on the step index. +func (e *SimpleEngine) stepAlias(alias string, index int64) (string, error) { + if alias = strings.TrimSpace(alias); alias != "" { + // A webhook enforces this regex as well, but we're checking here to + // account for the possibility of EXISTING Stages with a promotionTemplate + // containing a step with a now-reserved alias. + if ReservedStepAliasRegex.MatchString(alias) { + return "", fmt.Errorf("step alias %q is forbidden", alias) + } + return alias, nil + } + return fmt.Sprintf("step-%d", index), nil +} + +// setupWorkDir creates a temporary working directory if one is not provided. +func (e *SimpleEngine) setupWorkDir(existingDir string) (string, error) { + if existingDir != "" { + return existingDir, nil + } + + workDir, err := os.MkdirTemp("", "run-") + if err != nil { + return "", fmt.Errorf("temporary working directory creation failed: %w", err) + } + return workDir, nil +} + +// getProjectSecrets returns a map of all Secrets in the Project. The returned +// map is keyed by Secret name and contains a map of Secret data. +func (e *SimpleEngine) getProjectSecrets( + ctx context.Context, + project string, +) (map[string]map[string]string, error) { + secrets := corev1.SecretList{} + if err := e.kargoClient.List( + ctx, + &secrets, + client.InNamespace(project), + ); err != nil { + return nil, fmt.Errorf("error listing Secrets for Project %q: %w", project, err) + } + secretsMap := make(map[string]map[string]string, len(secrets.Items)) + for _, secret := range secrets.Items { + secretsMap[secret.Name] = make(map[string]string, len(secret.Data)) + for key, value := range secret.Data { + secretsMap[secret.Name][key] = string(value) + } + } + return secretsMap, nil +} diff --git a/internal/directives/simple_engine_promote_test.go b/internal/directives/simple_engine_promote_test.go new file mode 100644 index 000000000..289b19a50 --- /dev/null +++ b/internal/directives/simple_engine_promote_test.go @@ -0,0 +1,615 @@ +package directives + +import ( + "context" + "errors" + "os" + "testing" + + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" + + kargoapi "github.com/akuity/kargo/api/v1alpha1" + "github.com/akuity/kargo/internal/credentials" +) + +func TestSimpleEngine_Promote(t *testing.T) { + tests := []struct { + name string + promoCtx PromotionContext + steps []PromotionStep + interceptor interceptor.Funcs + assertions func(*testing.T, PromotionResult, error) + }{ + { + name: "successful promotion", + promoCtx: PromotionContext{ + Project: "test-project", + State: State{"existing": "state"}, + }, + steps: []PromotionStep{ + {Kind: "success-step"}, + }, + assertions: func(t *testing.T, result PromotionResult, err error) { + assert.NoError(t, err) + assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status) + assert.NotNil(t, result.State) + assert.Equal(t, "state", result.State["existing"]) + assert.Equal(t, int64(0), result.CurrentStep) + }, + }, + { + name: "failed promotion", + promoCtx: PromotionContext{ + Project: "test-project", + }, + steps: []PromotionStep{ + {Kind: "error-step"}, + }, + assertions: func(t *testing.T, result PromotionResult, err error) { + assert.Error(t, err) + assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) + assert.ErrorContains(t, err, "step execution failed") + }, + }, + { + name: "context cancellation", + promoCtx: PromotionContext{ + Project: "test-project", + }, + steps: []PromotionStep{ + {Kind: "context-waiter"}, + }, + assertions: func(t *testing.T, result PromotionResult, err error) { + assert.Error(t, err) + assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) + assert.ErrorIs(t, err, context.Canceled) + }, + }, + { + name: "secrets retrieval failure", + promoCtx: PromotionContext{ + Project: "test-project", + }, + steps: []PromotionStep{ + {Kind: "success-step"}, + }, + interceptor: interceptor.Funcs{ + List: func(context.Context, client.WithWatch, client.ObjectList, ...client.ListOption) error { + return errors.New("something went wrong") + }, + }, + assertions: func(t *testing.T, result PromotionResult, err error) { + assert.ErrorContains(t, err, "error listing Secrets for Project") + assert.ErrorContains(t, err, "something went wrong") + assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + testRegistry := NewStepRunnerRegistry() + testRegistry.RegisterPromotionStepRunner( + &mockPromotionStepRunner{ + name: "success-step", + runResult: PromotionStepResult{Status: kargoapi.PromotionPhaseSucceeded}, + }, + &StepRunnerPermissions{}, + ) + testRegistry.RegisterPromotionStepRunner( + &mockPromotionStepRunner{ + name: "error-step", + runResult: PromotionStepResult{Status: kargoapi.PromotionPhaseErrored}, + runErr: errors.New("something went wrong"), + }, + &StepRunnerPermissions{}, + ) + testRegistry.RegisterPromotionStepRunner( + &mockPromotionStepRunner{ + name: "context-waiter", + runFunc: func(ctx context.Context, _ *PromotionStepContext) (PromotionStepResult, error) { + cancel() // Cancel context immediately + <-ctx.Done() + return PromotionStepResult{Status: kargoapi.PromotionPhaseErrored}, ctx.Err() + }, + }, + &StepRunnerPermissions{}, + ) + + engine := &SimpleEngine{ + registry: testRegistry, + kargoClient: fake.NewClientBuilder(). + WithInterceptorFuncs(tt.interceptor). + Build(), + } + + result, err := engine.Promote(ctx, tt.promoCtx, tt.steps) + tt.assertions(t, result, err) + }) + } +} + +func TestSimpleEngine_executeSteps(t *testing.T) { + tests := []struct { + name string + promoCtx PromotionContext + steps []PromotionStep + assertions func(*testing.T, PromotionResult, error) + }{ + { + name: "execute all steps successfully", + steps: []PromotionStep{ + {Kind: "success-step", Alias: "step1"}, + {Kind: "success-step", Alias: "step2"}, + }, + assertions: func(t *testing.T, result PromotionResult, err error) { + assert.NoError(t, err) + assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status) + assert.Equal(t, int64(1), result.CurrentStep) + + // Verify state contains outputs from both steps + assert.Equal(t, State{ + "step1": map[string]any{ + "attempts": int64(1), + "key": "value", + }, + "step2": map[string]any{ + "attempts": int64(1), + "key": "value", + }, + }, result.State) + }, + }, + { + name: "start from middle step", + promoCtx: PromotionContext{ + StartFromStep: 1, + }, + steps: []PromotionStep{ + {Kind: "error-step", Alias: "step1"}, // This step should be skipped + {Kind: "success-step", Alias: "step2"}, + }, + assertions: func(t *testing.T, result PromotionResult, err error) { + assert.NoError(t, err) + assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status) + assert.Equal(t, int64(1), result.CurrentStep) + + // Verify only second step output is in state + assert.Equal(t, State{ + "step2": map[string]any{ + "attempts": int64(1), + "key": "value", + }, + }, result.State) + }, + }, + { + name: "fail on step execution", + steps: []PromotionStep{ + {Kind: "success-step", Alias: "step1"}, + {Kind: "error-step", Alias: "step2"}, + }, + assertions: func(t *testing.T, result PromotionResult, err error) { + assert.ErrorContains(t, err, "something went wrong") + assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) + assert.Equal(t, int64(1), result.CurrentStep) + + // Verify first step output is preserved in state + assert.Equal(t, State{ + "step1": map[string]any{ + "attempts": int64(1), + "key": "value", + }, + "step2": map[string]any{ + "attempts": int64(1), + }, + }, result.State) + }, + }, + { + name: "fail on invalid step alias", + steps: []PromotionStep{ + {Kind: "success-step", Alias: "step-1"}, + }, + assertions: func(t *testing.T, result PromotionResult, err error) { + assert.ErrorContains(t, err, "is forbidden") + assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) + assert.Equal(t, int64(0), result.CurrentStep) + }, + }, + { + name: "context cancellation", + steps: []PromotionStep{ + {Kind: "context-waiter", Alias: "step1"}, + }, + assertions: func(t *testing.T, result PromotionResult, err error) { + assert.ErrorIs(t, err, context.Canceled) + assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) + assert.Equal(t, int64(0), result.CurrentStep) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + testRegistry := NewStepRunnerRegistry() + testRegistry.RegisterPromotionStepRunner( + &mockPromotionStepRunner{ + name: "success-step", + runResult: PromotionStepResult{ + Status: kargoapi.PromotionPhaseSucceeded, + Output: map[string]any{"key": "value"}, + }, + }, + &StepRunnerPermissions{}, + ) + testRegistry.RegisterPromotionStepRunner( + &mockPromotionStepRunner{ + name: "error-step", + runResult: PromotionStepResult{Status: kargoapi.PromotionPhaseErrored}, + runErr: errors.New("something went wrong"), + }, + &StepRunnerPermissions{}, + ) + testRegistry.RegisterPromotionStepRunner( + &mockPromotionStepRunner{ + name: "context-waiter", + runFunc: func(ctx context.Context, _ *PromotionStepContext) (PromotionStepResult, error) { + cancel() + <-ctx.Done() + return PromotionStepResult{Status: kargoapi.PromotionPhaseErrored}, ctx.Err() + }, + }, + &StepRunnerPermissions{}, + ) + + engine := &SimpleEngine{ + registry: testRegistry, + kargoClient: fake.NewClientBuilder().Build(), + } + + result, err := engine.executeSteps(ctx, tt.promoCtx, tt.steps, t.TempDir()) + tt.assertions(t, result, err) + }) + } +} + +func TestSimpleEngine_executeStep(t *testing.T) { + tests := []struct { + name string + promoCtx PromotionContext + step PromotionStep + assertions func(*testing.T, PromotionStepResult, error) + }{ + { + name: "successful step execution", + step: PromotionStep{Kind: "success-step"}, + assertions: func(t *testing.T, result PromotionStepResult, err error) { + assert.NoError(t, err) + assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status) + + // Verify attempts counter is added to output + assert.Equal(t, int64(1), result.Output["attempts"]) + assert.Equal(t, "test-value", result.Output["key"]) + }, + }, + { + name: "step execution with existing attempts", + promoCtx: PromotionContext{ + State: State{"test-step": map[string]any{"attempts": 0}}, + }, + step: PromotionStep{Kind: "success-step", Alias: "test-step"}, + assertions: func(t *testing.T, result PromotionStepResult, err error) { + assert.NoError(t, err) + assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status) + + // Verify attempts counter is incremented in output + assert.Equal(t, int64(1), result.Output["attempts"]) + assert.Equal(t, "test-value", result.Output["key"]) + }, + }, + { + name: "step execution failure", + step: PromotionStep{Kind: "error-step"}, + assertions: func(t *testing.T, result PromotionStepResult, err error) { + assert.ErrorContains(t, err, "failed to run step \"error-step\"") + assert.ErrorContains(t, err, "something went wrong") + assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) + + // Verify attempts counter is still added to output even on failure + assert.Equal(t, int64(1), result.Output["attempts"]) + }, + }, + { + name: "unregistered step kind", + step: PromotionStep{Kind: "unknown"}, + assertions: func(t *testing.T, result PromotionStepResult, err error) { + assert.Error(t, err) + assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) + }, + }, + { + name: "max attempts exceeded", + step: PromotionStep{Kind: "success-step", Alias: "test"}, + promoCtx: PromotionContext{ + State: State{"test": map[string]any{"attempts": 3}}, + }, + assertions: func(t *testing.T, result PromotionStepResult, err error) { + assert.ErrorContains(t, err, "exceeded max attempts") + assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testRegistry := NewStepRunnerRegistry() + testRegistry.RegisterPromotionStepRunner( + &mockPromotionStepRunner{ + name: "success-step", + runResult: PromotionStepResult{ + Status: kargoapi.PromotionPhaseSucceeded, + Output: map[string]any{"key": "test-value"}, + }, + }, + &StepRunnerPermissions{}, + ) + testRegistry.RegisterPromotionStepRunner( + &mockPromotionStepRunner{ + name: "error-step", + runResult: PromotionStepResult{Status: kargoapi.PromotionPhaseErrored}, + runErr: errors.New("something went wrong"), + }, + &StepRunnerPermissions{}, + ) + + engine := &SimpleEngine{ + registry: testRegistry, + kargoClient: fake.NewClientBuilder().Build(), + } + + result, err := engine.executeStep(context.Background(), tt.promoCtx, tt.step, t.TempDir(), make(State)) + tt.assertions(t, result, err) + }) + } +} + +func TestSimpleEngine_preparePromotionStepContext(t *testing.T) { + tests := []struct { + name string + promoCtx PromotionContext + step PromotionStep + permissions StepRunnerPermissions + assertions func(*testing.T, *PromotionStepContext, error) + }{ + { + name: "successful context preparation", + promoCtx: PromotionContext{ + Project: "test-project", + Stage: "test-stage", + UIBaseURL: "http://test", + }, + step: PromotionStep{Kind: "test-step"}, + permissions: StepRunnerPermissions{ + AllowCredentialsDB: true, + AllowKargoClient: true, + AllowArgoCDClient: true, + }, + assertions: func(t *testing.T, ctx *PromotionStepContext, err error) { + assert.NoError(t, err) + assert.Equal(t, "test-project", ctx.Project) + assert.Equal(t, "test-stage", ctx.Stage) + assert.Equal(t, "http://test", ctx.UIBaseURL) + assert.NotNil(t, ctx.CredentialsDB) + assert.NotNil(t, ctx.KargoClient) + assert.NotNil(t, ctx.ArgoCDClient) + }, + }, + { + name: "permissions control client access", + promoCtx: PromotionContext{}, + step: PromotionStep{Kind: "test-step"}, + permissions: StepRunnerPermissions{ + // Nothing allowed + }, + assertions: func(t *testing.T, ctx *PromotionStepContext, err error) { + assert.NoError(t, err) + assert.Nil(t, ctx.CredentialsDB) + assert.Nil(t, ctx.KargoClient) + assert.Nil(t, ctx.ArgoCDClient) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testRegistry := NewStepRunnerRegistry() + testRegistry.RegisterPromotionStepRunner( + &mockPromotionStepRunner{name: "test-step"}, + &tt.permissions, + ) + + engine := &SimpleEngine{ + registry: testRegistry, + kargoClient: fake.NewClientBuilder().Build(), + argoCDClient: fake.NewClientBuilder().Build(), + credentialsDB: &credentials.FakeDB{}, + } + + reg, _ := testRegistry.GetPromotionStepRunnerRegistration("test-step") + stepCtx, err := engine.preparePromotionStepContext( + context.Background(), + tt.promoCtx, + tt.step, + t.TempDir(), + make(State), + reg, + ) + tt.assertions(t, stepCtx, err) + }) + } +} + +func TestSimpleEngine_stepAlias(t *testing.T) { + tests := []struct { + name string + alias string + index int64 + assertions func(*testing.T, string, error) + }{ + { + name: "use provided alias", + alias: "custom-step", + assertions: func(t *testing.T, alias string, err error) { + assert.NoError(t, err) + assert.Equal(t, "custom-step", alias) + }, + }, + { + name: "generate default alias", + index: 42, + assertions: func(t *testing.T, alias string, err error) { + assert.NoError(t, err) + assert.Equal(t, "step-42", alias) + }, + }, + { + name: "reject reserved alias", + alias: "step-1", + assertions: func(t *testing.T, _ string, err error) { + assert.ErrorContains(t, err, "forbidden") + }, + }, + { + name: "trim whitespace", + alias: " step ", + assertions: func(t *testing.T, alias string, err error) { + assert.NoError(t, err) + assert.Equal(t, "step", alias) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + engine := &SimpleEngine{} + alias, err := engine.stepAlias(tt.alias, tt.index) + tt.assertions(t, alias, err) + }) + } +} + +func TestSimpleEngine_setupWorkDir(t *testing.T) { + tmpDir := t.TempDir() + + tests := []struct { + name string + existingDir string + assertions func(*testing.T, string, error) + }{ + { + name: "use existing directory", + existingDir: tmpDir, + assertions: func(t *testing.T, dir string, err error) { + assert.NoError(t, err) + assert.Equal(t, tmpDir, dir) + }, + }, + { + name: "create new directory", + assertions: func(t *testing.T, dir string, err error) { + assert.NoError(t, err) + assert.DirExists(t, dir) + t.Cleanup(func() { + _ = os.RemoveAll(dir) + }) + assert.Contains(t, dir, "run-") + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + engine := &SimpleEngine{} + dir, err := engine.setupWorkDir(tt.existingDir) + tt.assertions(t, dir, err) + }) + } +} + +func TestSimpleEngine_getProjectSecrets(t *testing.T) { + tests := []struct { + name string + project string + objects []client.Object + interceptor interceptor.Funcs + assertions func(*testing.T, map[string]map[string]string, error) + }{ + { + name: "successful retrieval", + project: "test-project", + objects: []client.Object{ + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-secret", + Namespace: "test-project", + }, + Data: map[string][]byte{ + "key1": []byte("value1"), + "key2": []byte("value2"), + }, + }, + }, + assertions: func(t *testing.T, secrets map[string]map[string]string, err error) { + assert.NoError(t, err) + assert.Equal(t, "value1", secrets["test-secret"]["key1"]) + assert.Equal(t, "value2", secrets["test-secret"]["key2"]) + }, + }, + { + name: "list error", + project: "test-project", + interceptor: interceptor.Funcs{ + List: func(context.Context, client.WithWatch, client.ObjectList, ...client.ListOption) error { + return errors.New("list error") + }, + }, + assertions: func(t *testing.T, _ map[string]map[string]string, err error) { + assert.ErrorContains(t, err, "error listing Secrets") + }, + }, + { + name: "no secrets", + project: "empty-project", + assertions: func(t *testing.T, secrets map[string]map[string]string, err error) { + assert.NoError(t, err) + assert.Empty(t, secrets) + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + engine := &SimpleEngine{ + kargoClient: fake.NewClientBuilder(). + WithObjects(tt.objects...). + WithInterceptorFuncs(tt.interceptor). + Build(), + } + + secrets, err := engine.getProjectSecrets(context.Background(), tt.project) + tt.assertions(t, secrets, err) + }) + } +} diff --git a/internal/directives/simple_engine_test.go b/internal/directives/simple_engine_test.go deleted file mode 100644 index 1d130a450..000000000 --- a/internal/directives/simple_engine_test.go +++ /dev/null @@ -1,316 +0,0 @@ -package directives - -import ( - "context" - "encoding/json" - "errors" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/client/fake" - "sigs.k8s.io/controller-runtime/pkg/client/interceptor" - - kargoapi "github.com/akuity/kargo/api/v1alpha1" -) - -func TestSimpleEngine_Promote(t *testing.T) { - testHealthCheckStep := HealthCheckStep{ - Kind: "fake", - Config: Config{ - "fake-key": "fake-value", - }, - } - - errorResult := PromotionStepResult{Status: kargoapi.PromotionPhaseErrored} - successResult := PromotionStepResult{ - Status: kargoapi.PromotionPhaseSucceeded, - HealthCheckStep: &testHealthCheckStep, - } - - const successStepName = "success" - const errorStepName = "failure" - const contextWaiterStep = "waiter" - testRegistry := NewStepRunnerRegistry() - testRegistry.RegisterPromotionStepRunner( - &mockPromotionStepRunner{ - name: successStepName, - runResult: successResult, - }, - nil, - ) - testRegistry.RegisterPromotionStepRunner( - &mockPromotionStepRunner{ - name: errorStepName, - runResult: errorResult, - runErr: errors.New("something went wrong"), - }, - nil, - ) - testRegistry.RegisterPromotionStepRunner( - &mockPromotionStepRunner{ - name: contextWaiterStep, - runFunc: func( - ctx context.Context, - _ *PromotionStepContext, - ) (PromotionStepResult, error) { - <-ctx.Done() // Wait for context to be canceled - return successResult, nil - }, - }, - nil, - ) - - tests := []struct { - name string - steps []PromotionStep - ctx context.Context - client client.Client - assertions func(*testing.T, PromotionResult, error) - }{ - { - name: "failure: error getting secrets", - ctx: context.Background(), - client: fake.NewClientBuilder().WithInterceptorFuncs( - interceptor.Funcs{ - List: func(context.Context, client.WithWatch, client.ObjectList, ...client.ListOption) error { - return errors.New("something went wrong") - }, - }, - ).Build(), - assertions: func(t *testing.T, res PromotionResult, err error) { - assert.Equal(t, kargoapi.PromotionPhaseErrored, res.Status) - assert.ErrorContains(t, err, "error listing Secrets for Project") - assert.ErrorContains(t, err, "something went wrong") - }, - }, - { - name: "success: single step", - steps: []PromotionStep{{Kind: successStepName}}, - ctx: context.Background(), - client: fake.NewClientBuilder().Build(), - assertions: func(t *testing.T, res PromotionResult, err error) { - assert.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status) - assert.Equal(t, []HealthCheckStep{testHealthCheckStep}, res.HealthCheckSteps) - assert.NoError(t, err) - }, - }, - { - name: "success: multiple steps", - steps: []PromotionStep{ - {Kind: successStepName}, - {Kind: successStepName}, - }, - ctx: context.Background(), - client: fake.NewClientBuilder().Build(), - assertions: func(t *testing.T, res PromotionResult, err error) { - assert.Equal(t, kargoapi.PromotionPhaseSucceeded, res.Status) - assert.Equal( - t, - []HealthCheckStep{testHealthCheckStep, testHealthCheckStep}, - res.HealthCheckSteps, - ) - assert.NoError(t, err) - }, - }, - { - name: "failure: runner not found", - steps: []PromotionStep{{Kind: "unknown"}}, - ctx: context.Background(), - client: fake.NewClientBuilder().Build(), - assertions: func(t *testing.T, res PromotionResult, err error) { - assert.Equal(t, kargoapi.PromotionPhaseErrored, res.Status) - assert.ErrorContains(t, err, "not found") - }, - }, - { - name: "failure: runner returns error", - steps: []PromotionStep{{Kind: errorStepName}}, - ctx: context.Background(), - client: fake.NewClientBuilder().Build(), - assertions: func(t *testing.T, res PromotionResult, err error) { - assert.Equal(t, kargoapi.PromotionPhaseErrored, res.Status) - assert.ErrorContains(t, err, "something went wrong") - }, - }, - { - name: "failure: context canceled", - steps: []PromotionStep{ - {Kind: contextWaiterStep}, - {Kind: contextWaiterStep}, // This runner should not be executed - }, - ctx: func() context.Context { - ctx, cancel := context.WithCancel(context.Background()) - go func() { - time.Sleep(10 * time.Millisecond) - cancel() - }() - return ctx - }(), - client: fake.NewClientBuilder().Build(), - assertions: func(t *testing.T, res PromotionResult, err error) { - assert.Equal(t, kargoapi.PromotionPhaseErrored, res.Status) - assert.ErrorIs(t, err, context.Canceled) - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - engine := NewSimpleEngine(nil, nil, nil) - engine.registry = testRegistry - engine.kargoClient = tt.client - res, err := engine.Promote(tt.ctx, PromotionContext{}, tt.steps) - tt.assertions(t, res, err) - }) - } -} - -func TestSimpleEngine_CheckHealth(t *testing.T) { - testOutput := map[string]any{ - "fake-key": "fake-value", - } - testOutputBytes, err := json.Marshal(testOutput) - require.NoError(t, err) - - const healthyStepName = "healthy" - const unhealthyStepName = "unhealthy" - const contextWaiterStep = "waiter" - testRegistry := NewStepRunnerRegistry() - testRegistry.RegisterHealthCheckStepRunner( - &mockHealthCheckStepRunner{ - name: healthyStepName, - runResult: HealthCheckStepResult{ - Status: kargoapi.HealthStateHealthy, - Output: testOutput, - }, - }, - nil, - ) - testRegistry.RegisterHealthCheckStepRunner( - &mockHealthCheckStepRunner{ - name: unhealthyStepName, - runResult: HealthCheckStepResult{ - Status: kargoapi.HealthStateUnhealthy, - Issues: []string{"something went wrong"}, - Output: testOutput, - }, - }, - nil, - ) - testRegistry.RegisterHealthCheckStepRunner( - &mockHealthCheckStepRunner{ - name: contextWaiterStep, - runFunc: func(ctx context.Context, _ *HealthCheckStepContext) HealthCheckStepResult { - <-ctx.Done() // Wait for context to be canceled - return HealthCheckStepResult{ - Status: kargoapi.HealthStateHealthy, - Output: testOutput, - } - }, - }, - nil, - ) - - tests := []struct { - name string - steps []HealthCheckStep - ctx context.Context - assertions func(*testing.T, kargoapi.Health) - }{ - { - name: "healthy: single step", - steps: []HealthCheckStep{{Kind: healthyStepName}}, - ctx: context.Background(), - assertions: func(t *testing.T, res kargoapi.Health) { - require.Equal(t, kargoapi.HealthStateHealthy, res.Status) - require.Empty(t, res.Issues) - require.NotNil(t, res.Output) - require.NotEmpty(t, res.Output.Raw) - require.Equal(t, 1, strings.Count(string(res.Output.Raw), string(testOutputBytes))) - }, - }, - { - name: "healthy: multiple steps", - steps: []HealthCheckStep{{Kind: healthyStepName}, {Kind: healthyStepName}}, - ctx: context.Background(), - assertions: func(t *testing.T, res kargoapi.Health) { - require.Equal(t, kargoapi.HealthStateHealthy, res.Status) - require.Empty(t, res.Issues) - require.NotNil(t, res.Output) - require.NotEmpty(t, res.Output.Raw) - require.Equal(t, 2, strings.Count(string(res.Output.Raw), string(testOutputBytes))) - }, - }, - { - name: "unknown: runner not found", - steps: []HealthCheckStep{{Kind: healthyStepName}, {Kind: "unknown"}}, - ctx: context.Background(), - assertions: func(t *testing.T, res kargoapi.Health) { - // First step healthy + second step not found == unknown - require.Equal(t, kargoapi.HealthStateUnknown, res.Status) - require.Len(t, res.Issues, 1) - require.Contains(t, res.Issues[0], "no runner registered for step kind") - require.NotNil(t, res.Output) - require.NotEmpty(t, res.Output.Raw) - // We should still get the output from the first step - require.Equal(t, 1, strings.Count(string(res.Output.Raw), string(testOutputBytes))) - }, - }, - { - name: "unhealthy: a step returns unhealthy", - steps: []HealthCheckStep{{Kind: unhealthyStepName}, {Kind: healthyStepName}}, - ctx: context.Background(), - assertions: func(t *testing.T, res kargoapi.Health) { - // First step unhealthy + second step unhealthy == unhealthy - require.Equal(t, kargoapi.HealthStateUnhealthy, res.Status) - require.Len(t, res.Issues, 1) - require.Equal(t, "something went wrong", res.Issues[0]) - require.NotNil(t, res.Output) - require.NotEmpty(t, res.Output.Raw) - // We should still get the output from both steps - require.Equal(t, 2, strings.Count(string(res.Output.Raw), string(testOutputBytes))) - }, - }, - { - name: "unknown: context canceled", - steps: []HealthCheckStep{ - {Kind: contextWaiterStep}, - {Kind: contextWaiterStep}, - }, - ctx: func() context.Context { - ctx, cancel := context.WithCancel(context.Background()) - go func() { - time.Sleep(10 * time.Millisecond) - cancel() - }() - return ctx - }(), - assertions: func(t *testing.T, res kargoapi.Health) { - // First step healthy + context canceled == unknown - require.Equal(t, kargoapi.HealthStateUnknown, res.Status) - require.Len(t, res.Issues, 1) - require.Equal(t, context.Canceled.Error(), res.Issues[0]) - require.NotNil(t, res.Output) - require.NotEmpty(t, res.Output.Raw) - // We should have output from one step - require.Equal(t, 1, strings.Count(string(res.Output.Raw), string(testOutputBytes))) - }, - }, - } - - engine := NewSimpleEngine(nil, nil, nil) - engine.registry = testRegistry - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - tt.assertions( - t, - engine.CheckHealth(tt.ctx, HealthCheckContext{}, tt.steps), - ) - }) - } -} From f65532e85a9aacb9f0f630a9026461c8cefb6556 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Wed, 20 Nov 2024 16:01:25 +0100 Subject: [PATCH 4/8] feat: mark step as `Running` during retries Signed-off-by: Hidde Beydals --- internal/directives/simple_engine_promote.go | 28 ++++++++++++- .../directives/simple_engine_promote_test.go | 40 +++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/internal/directives/simple_engine_promote.go b/internal/directives/simple_engine_promote.go index 0066233cf..a9aa48387 100644 --- a/internal/directives/simple_engine_promote.go +++ b/internal/directives/simple_engine_promote.go @@ -137,7 +137,9 @@ func (e *SimpleEngine) executeStep( } // Check if the step has exceeded the maximum number of attempts. - if step.GetAttempts(promoCtx.State) >= step.GetMaxAttempts(reg.Runner) { + attempts := step.GetAttempts(promoCtx.State) + maxAttempts := step.GetMaxAttempts(reg.Runner) + if maxAttempts > 0 && attempts >= maxAttempts { return PromotionStepResult{ Status: kargoapi.PromotionPhaseErrored, }, fmt.Errorf("step %q exceeded max attempts", step.Alias) @@ -150,6 +152,30 @@ func (e *SimpleEngine) executeStep( if err != nil { err = fmt.Errorf("failed to run step %q: %w", step.Kind, err) } + + // If the step failed, and the maximum number of attempts has not been + // reached, we are still "Running" the step and will retry it. + if err != nil || result.Status == kargoapi.PromotionPhaseErrored || result.Status == kargoapi.PromotionPhaseFailed { + if maxAttempts < 0 || attempts+1 < maxAttempts { + result.Status = kargoapi.PromotionPhaseRunning + + var message strings.Builder + _, _ = message.WriteString(fmt.Sprintf("step %q failed (attempt %d)", step.Alias, attempts+1)) + if result.Message != "" { + _, _ = message.WriteString(": ") + _, _ = message.WriteString(result.Message) + } + if err != nil { + _, _ = message.WriteString(": ") + _, _ = message.WriteString(err.Error()) + } + result.Message = message.String() + + // Swallow the error if the step is being retried. + return result, nil + } + } + return result, err } diff --git a/internal/directives/simple_engine_promote_test.go b/internal/directives/simple_engine_promote_test.go index 289b19a50..cb11053cb 100644 --- a/internal/directives/simple_engine_promote_test.go +++ b/internal/directives/simple_engine_promote_test.go @@ -350,6 +350,46 @@ func TestSimpleEngine_executeStep(t *testing.T) { assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) }, }, + { + name: "retry within max attempts", + promoCtx: PromotionContext{ + State: State{ + "step1": map[string]any{ + "attempts": int64(1), + }, + }, + }, + step: PromotionStep{ + Kind: "error-step", + Alias: "step1", + Retry: &kargoapi.PromotionRetry{Attempts: 3}, + }, + assertions: func(t *testing.T, result PromotionStepResult, err error) { + assert.NoError(t, err) + assert.Equal(t, kargoapi.PromotionPhaseRunning, result.Status) + assert.Contains(t, result.Message, "attempt 2") + }, + }, + { + name: "unlimited retries with negative max attempts", + step: PromotionStep{ + Kind: "error-step", + Alias: "unlimited", + Retry: &kargoapi.PromotionRetry{Attempts: -1}, + }, + promoCtx: PromotionContext{ + State: State{ + "unlimited": map[string]any{ + "attempts": int64(100), + }, + }, + }, + assertions: func(t *testing.T, result PromotionStepResult, err error) { + assert.NoError(t, err) + assert.Equal(t, kargoapi.PromotionPhaseRunning, result.Status) + assert.Contains(t, result.Message, "attempt 101") + }, + }, } for _, tt := range tests { From f07502ccb7abd93ef4c00866fba46a54244f4f67 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Wed, 20 Nov 2024 16:14:06 +0100 Subject: [PATCH 5/8] chore: try to match previous behavior Signed-off-by: Hidde Beydals --- internal/directives/argocd_updater.go | 5 +++++ internal/directives/git_pr_waiter.go | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/internal/directives/argocd_updater.go b/internal/directives/argocd_updater.go index 148fc2a30..e8c721847 100644 --- a/internal/directives/argocd_updater.go +++ b/internal/directives/argocd_updater.go @@ -127,6 +127,11 @@ func (a *argocdUpdater) Name() string { return "argocd-update" } +// DefaultAttempts implements the RetryableStepRunner interface. +func (a *argocdUpdater) DefaultAttempts() int64 { + return -1 +} + // RunPromotionStep implements the PromotionStepRunner interface. func (a *argocdUpdater) RunPromotionStep( ctx context.Context, diff --git a/internal/directives/git_pr_waiter.go b/internal/directives/git_pr_waiter.go index 748bdc581..531a13b4a 100644 --- a/internal/directives/git_pr_waiter.go +++ b/internal/directives/git_pr_waiter.go @@ -38,6 +38,11 @@ func (g *gitPRWaiter) Name() string { return "git-wait-for-pr" } +// DefaultAttempts implements the RetryableStepRunner interface. +func (g *gitPRWaiter) DefaultAttempts() int64 { + return -1 +} + // RunPromotionStep implements the PromotionStepRunner interface. func (g *gitPRWaiter) RunPromotionStep( ctx context.Context, From 3abbc8608d54b28d2e95f0ef51ea7b45a90d381f Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Thu, 21 Nov 2024 14:55:52 +0100 Subject: [PATCH 6/8] feat(api): add `CurrentStepAttempt` to `Promotion` status Signed-off-by: Hidde Beydals --- api/v1alpha1/generated.pb.go | 485 +++++++++--------- api/v1alpha1/generated.proto | 4 + api/v1alpha1/promotion_types.go | 3 + .../crds/kargo.akuity.io_promotions.yaml | 6 + .../crds/kargo.akuity.io_stages.yaml | 12 + .../promotions.kargo.akuity.io_v1alpha1.json | 7 + .../stages.kargo.akuity.io_v1alpha1.json | 14 + ui/src/gen/v1alpha1/generated_pb.ts | 9 + 8 files changed, 310 insertions(+), 230 deletions(-) diff --git a/api/v1alpha1/generated.pb.go b/api/v1alpha1/generated.pb.go index d39689325..5008856a7 100644 --- a/api/v1alpha1/generated.pb.go +++ b/api/v1alpha1/generated.pb.go @@ -1696,236 +1696,237 @@ func init() { } var fileDescriptor_e26b7f7bbc391025 = []byte{ - // 3655 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5c, 0xdb, 0x6f, 0x24, 0x47, - 0x57, 0xdf, 0x9e, 0xb1, 0xc7, 0x9e, 0x33, 0xbe, 0xd6, 0x7a, 0x13, 0x7f, 0xfe, 0x88, 0xbd, 0x74, - 0xa2, 0x28, 0x21, 0xc9, 0x98, 0xbd, 0x65, 0x2f, 0x81, 0x45, 0x1e, 0x7b, 0x2f, 0x5e, 0xfc, 0x65, - 0x4d, 0xcd, 0x5e, 0x3e, 0x36, 0xbb, 0x0a, 0xe5, 0x99, 0xf2, 0x4c, 0xe3, 0x99, 0xee, 0x49, 0x57, - 0x8d, 0x13, 0x03, 0x82, 0x84, 0x8b, 0x14, 0x09, 0x81, 0x78, 0x88, 0x48, 0x90, 0x40, 0x42, 0xf0, - 0x0c, 0xff, 0x00, 0x0f, 0x79, 0xe0, 0x25, 0x42, 0x11, 0x8a, 0x80, 0x87, 0x3c, 0x44, 0x16, 0x71, - 0x24, 0x1e, 0xf3, 0xc6, 0xcb, 0x4a, 0x48, 0xa8, 0x2e, 0xdd, 0x5d, 0xdd, 0xd3, 0xb3, 0x9e, 0x9e, - 0xb5, 0x57, 0xab, 0xef, 0x6d, 0x5c, 0xa7, 0xea, 0x77, 0xea, 0x72, 0xce, 0xa9, 0x5f, 0x9d, 0xaa, - 0x36, 0x9c, 0x6f, 0x38, 0xbc, 0xd9, 0xdd, 0x2a, 0xd7, 0xbc, 0xf6, 0x32, 0xd9, 0xe9, 0x3a, 0x7c, - 0x6f, 0x79, 0x87, 0xf8, 0x0d, 0x6f, 0x99, 0x74, 0x9c, 0xe5, 0xdd, 0x33, 0xa4, 0xd5, 0x69, 0x92, - 0x33, 0xcb, 0x0d, 0xea, 0x52, 0x9f, 0x70, 0x5a, 0x2f, 0x77, 0x7c, 0x8f, 0x7b, 0xe8, 0x95, 0xa8, - 0x55, 0x59, 0xb5, 0x2a, 0xcb, 0x56, 0x65, 0xd2, 0x71, 0xca, 0x41, 0xab, 0x85, 0xb7, 0x0c, 0xec, - 0x86, 0xd7, 0xf0, 0x96, 0x65, 0xe3, 0xad, 0xee, 0xb6, 0xfc, 0x4b, 0xfe, 0x21, 0x7f, 0x29, 0xd0, - 0x85, 0x9b, 0x3b, 0x97, 0x58, 0xd9, 0x91, 0x9a, 0xe9, 0x47, 0x9c, 0xba, 0xcc, 0xf1, 0x5c, 0xf6, - 0x16, 0xe9, 0x38, 0x8c, 0xfa, 0xbb, 0xd4, 0x5f, 0xee, 0xec, 0x34, 0x84, 0x8c, 0xc5, 0x2b, 0x2c, - 0xef, 0xf6, 0x74, 0x6f, 0xe1, 0x7c, 0x84, 0xd4, 0x26, 0xb5, 0xa6, 0xe3, 0x52, 0x7f, 0x2f, 0x6a, - 0xde, 0xa6, 0x9c, 0xa4, 0xb5, 0x5a, 0xee, 0xd7, 0xca, 0xef, 0xba, 0xdc, 0x69, 0xd3, 0x9e, 0x06, - 0x6f, 0x1f, 0xd6, 0x80, 0xd5, 0x9a, 0xb4, 0x4d, 0x92, 0xed, 0xec, 0x87, 0x70, 0x72, 0xc5, 0x25, - 0xad, 0x3d, 0xe6, 0x30, 0xdc, 0x75, 0x57, 0xfc, 0x46, 0xb7, 0x4d, 0x5d, 0x8e, 0x4e, 0xc3, 0x88, - 0x4b, 0xda, 0x74, 0xde, 0x3a, 0x6d, 0xbd, 0x56, 0xac, 0x4c, 0x7c, 0xb5, 0xbf, 0x74, 0xe2, 0x60, - 0x7f, 0x69, 0xe4, 0x5d, 0xd2, 0xa6, 0x58, 0x4a, 0xd0, 0xcb, 0x30, 0xba, 0x4b, 0x5a, 0x5d, 0x3a, - 0x9f, 0x93, 0x55, 0x26, 0x75, 0x95, 0xd1, 0x7b, 0xa2, 0x10, 0x2b, 0x99, 0xfd, 0x27, 0xf9, 0x18, - 0xfc, 0xcf, 0x28, 0x27, 0x75, 0xc2, 0x09, 0x6a, 0x43, 0xa1, 0x45, 0xb6, 0x68, 0x8b, 0xcd, 0x5b, - 0xa7, 0xf3, 0xaf, 0x95, 0xce, 0x5e, 0x2b, 0x0f, 0xb2, 0x88, 0xe5, 0x14, 0xa8, 0xf2, 0x86, 0xc4, - 0xb9, 0xe6, 0x72, 0x7f, 0xaf, 0x32, 0xa5, 0x3b, 0x51, 0x50, 0x85, 0x58, 0x2b, 0x41, 0x9f, 0x58, - 0x50, 0x22, 0xae, 0xeb, 0x71, 0xc2, 0xc5, 0x32, 0xcd, 0xe7, 0xa4, 0xd2, 0x5b, 0xc3, 0x2b, 0x5d, - 0x89, 0xc0, 0x94, 0xe6, 0x93, 0x5a, 0x73, 0xc9, 0x90, 0x60, 0x53, 0xe7, 0xc2, 0x65, 0x28, 0x19, - 0x5d, 0x45, 0x33, 0x90, 0xdf, 0xa1, 0x7b, 0x6a, 0x7e, 0xb1, 0xf8, 0x89, 0xe6, 0x62, 0x13, 0xaa, - 0x67, 0xf0, 0x4a, 0xee, 0x92, 0xb5, 0x70, 0x15, 0x66, 0x92, 0x0a, 0xb3, 0xb4, 0xb7, 0xff, 0xd2, - 0x82, 0x39, 0x63, 0x14, 0x98, 0x6e, 0x53, 0x9f, 0xba, 0x35, 0x8a, 0x96, 0xa1, 0x28, 0xd6, 0x92, - 0x75, 0x48, 0x2d, 0x58, 0xea, 0x59, 0x3d, 0x90, 0xe2, 0xbb, 0x81, 0x00, 0x47, 0x75, 0x42, 0xb3, - 0xc8, 0x3d, 0xc9, 0x2c, 0x3a, 0x4d, 0xc2, 0xe8, 0x7c, 0x3e, 0x6e, 0x16, 0x9b, 0xa2, 0x10, 0x2b, - 0x99, 0xfd, 0xeb, 0xf0, 0x93, 0xa0, 0x3f, 0x77, 0x68, 0xbb, 0xd3, 0x22, 0x9c, 0x46, 0x9d, 0x3a, - 0xd4, 0xf4, 0xec, 0x69, 0x98, 0x5c, 0xe9, 0x74, 0x7c, 0x6f, 0x97, 0xd6, 0xab, 0x9c, 0x34, 0xa8, - 0xfd, 0xc7, 0x16, 0x9c, 0x5a, 0xf1, 0x1b, 0xde, 0xea, 0xda, 0x4a, 0xa7, 0x73, 0x93, 0x92, 0x16, - 0x6f, 0x56, 0x39, 0xe1, 0x5d, 0x86, 0xae, 0x42, 0x81, 0xc9, 0x5f, 0x1a, 0xee, 0xd5, 0xc0, 0x42, - 0x94, 0xfc, 0xf1, 0xfe, 0xd2, 0x5c, 0x4a, 0x43, 0x8a, 0x75, 0x2b, 0xf4, 0x3a, 0x8c, 0xb5, 0x29, - 0x63, 0xa4, 0x11, 0x8c, 0x79, 0x5a, 0x03, 0x8c, 0xfd, 0x4c, 0x15, 0xe3, 0x40, 0x6e, 0xff, 0x5b, - 0x0e, 0xa6, 0x43, 0x2c, 0xad, 0xfe, 0x18, 0x26, 0xb8, 0x0b, 0x13, 0x4d, 0x63, 0x84, 0x72, 0x9e, - 0x4b, 0x67, 0xdf, 0x19, 0xd0, 0x96, 0xd3, 0x26, 0xa9, 0x32, 0xa7, 0xd5, 0x4c, 0x98, 0xa5, 0x38, - 0xa6, 0x06, 0xb5, 0x01, 0xd8, 0x9e, 0x5b, 0xd3, 0x4a, 0x47, 0xa4, 0xd2, 0xcb, 0x19, 0x95, 0x56, - 0x43, 0x80, 0x0a, 0xd2, 0x2a, 0x21, 0x2a, 0xc3, 0x86, 0x02, 0xfb, 0x9f, 0x2d, 0x38, 0x99, 0xd2, - 0x0e, 0xfd, 0x5a, 0x62, 0x3d, 0x5f, 0xe9, 0x59, 0x4f, 0xd4, 0xd3, 0x2c, 0x5a, 0xcd, 0x37, 0x61, - 0xdc, 0xa7, 0xbb, 0x8e, 0x88, 0xd5, 0x7a, 0x86, 0x67, 0x74, 0xfb, 0x71, 0xac, 0xcb, 0x71, 0x58, - 0x03, 0xbd, 0x01, 0xc5, 0xe0, 0xb7, 0x98, 0xe6, 0xbc, 0x30, 0x67, 0xb1, 0x70, 0x41, 0x55, 0x86, - 0x23, 0xb9, 0xfd, 0x47, 0x30, 0xba, 0xda, 0x24, 0x3e, 0x17, 0x16, 0xe3, 0xd3, 0x8e, 0x77, 0x17, - 0x6f, 0xe8, 0x2e, 0x86, 0x16, 0x83, 0x55, 0x31, 0x0e, 0xe4, 0x03, 0x2c, 0xf6, 0xeb, 0x30, 0xb6, - 0x4b, 0x7d, 0xd9, 0xdf, 0x7c, 0x1c, 0xec, 0x9e, 0x2a, 0xc6, 0x81, 0xdc, 0xfe, 0x4f, 0x0b, 0xe6, - 0x64, 0x0f, 0xd6, 0x1c, 0x56, 0xf3, 0x76, 0xa9, 0xbf, 0x87, 0x29, 0xeb, 0xb6, 0x8e, 0xb8, 0x43, - 0x6b, 0x30, 0xc3, 0x68, 0x7b, 0x97, 0xfa, 0xab, 0x9e, 0xcb, 0xb8, 0x4f, 0x1c, 0x97, 0xeb, 0x9e, - 0xcd, 0xeb, 0xda, 0x33, 0xd5, 0x84, 0x1c, 0xf7, 0xb4, 0x40, 0xaf, 0xc1, 0xb8, 0xee, 0xb6, 0x30, - 0x25, 0x31, 0xb1, 0x13, 0x62, 0x0d, 0xf4, 0x98, 0x18, 0x0e, 0xa5, 0xf6, 0xff, 0x58, 0x30, 0x2b, - 0x47, 0x55, 0xed, 0x6e, 0xb1, 0x9a, 0xef, 0x74, 0x44, 0x08, 0x7c, 0x1e, 0x87, 0x74, 0x15, 0xa6, - 0xea, 0xc1, 0xc4, 0x6f, 0x38, 0x6d, 0x87, 0x4b, 0x1f, 0x19, 0xad, 0xbc, 0xa0, 0x31, 0xa6, 0xd6, - 0x62, 0x52, 0x9c, 0xa8, 0x6d, 0xff, 0x6d, 0x1e, 0x4e, 0x06, 0x55, 0x68, 0x7d, 0xc5, 0xe7, 0xce, - 0x36, 0xa9, 0x71, 0x86, 0xea, 0x30, 0x51, 0x8f, 0x8a, 0xb9, 0xf6, 0xbc, 0x5f, 0x29, 0xab, 0xed, - 0xbe, 0x6c, 0x6e, 0xf7, 0xe5, 0xce, 0x4e, 0x43, 0x14, 0xb0, 0xb2, 0x60, 0x15, 0xe5, 0xdd, 0x33, - 0xe5, 0x3b, 0x4e, 0x9b, 0x46, 0xde, 0x6d, 0xc0, 0x73, 0x1c, 0x43, 0x45, 0xf7, 0x21, 0xdf, 0x70, - 0xb8, 0xde, 0x8c, 0x2f, 0x0d, 0xe6, 0xd6, 0x37, 0x9c, 0xa4, 0xa9, 0x55, 0x4a, 0x5a, 0x55, 0xfe, - 0x86, 0xc3, 0xb1, 0x40, 0x44, 0x5b, 0x50, 0x70, 0xda, 0xa4, 0x41, 0x83, 0x3d, 0xf7, 0xca, 0x60, - 0xd8, 0xeb, 0xa2, 0x4d, 0x12, 0x3d, 0xdc, 0xdd, 0xa5, 0x94, 0x61, 0x8d, 0x2c, 0x74, 0xd4, 0x84, - 0x89, 0x28, 0x27, 0x1d, 0x58, 0x47, 0x9a, 0xb3, 0x44, 0x3a, 0xa4, 0x94, 0x61, 0x8d, 0x6c, 0x7f, - 0x9b, 0x83, 0x99, 0x68, 0xfe, 0x56, 0xbd, 0x76, 0xdb, 0xe1, 0x68, 0x01, 0x72, 0x4e, 0x5d, 0x5b, - 0x20, 0xe8, 0x86, 0xb9, 0xf5, 0x35, 0x9c, 0x73, 0xea, 0xe8, 0x55, 0x28, 0x6c, 0xf9, 0xc4, 0xad, - 0x35, 0xb5, 0xe5, 0x85, 0xc0, 0x15, 0x59, 0x8a, 0xb5, 0x14, 0xbd, 0x04, 0x79, 0x4e, 0x1a, 0xda, - 0xe0, 0xc2, 0xf9, 0xbb, 0x43, 0x1a, 0x58, 0x94, 0x0b, 0x4b, 0x67, 0xdd, 0xad, 0xdf, 0xa5, 0x35, - 0xb5, 0xf2, 0x86, 0xa5, 0x57, 0x55, 0x31, 0x0e, 0xe4, 0x42, 0x23, 0xe9, 0xf2, 0xa6, 0xe7, 0xcf, - 0x8f, 0xc6, 0x35, 0xae, 0xc8, 0x52, 0xac, 0xa5, 0x62, 0x4f, 0xaa, 0xc9, 0xfe, 0x73, 0xea, 0xcf, - 0x17, 0xe2, 0x7b, 0xd2, 0x6a, 0x20, 0xc0, 0x51, 0x1d, 0xf4, 0x08, 0x4a, 0x35, 0x9f, 0x12, 0xee, - 0xf9, 0x6b, 0x84, 0xd3, 0xf9, 0xb1, 0xcc, 0x16, 0x38, 0x2d, 0x88, 0xd1, 0x6a, 0x04, 0x81, 0x4d, - 0x3c, 0xfb, 0x47, 0x0b, 0xe6, 0xa3, 0xa9, 0x95, 0x6b, 0x1b, 0x91, 0x01, 0x3d, 0x3d, 0x56, 0x9f, - 0xe9, 0x79, 0x15, 0x0a, 0x75, 0xa7, 0x41, 0x19, 0x4f, 0xce, 0xf2, 0x9a, 0x2c, 0xc5, 0x5a, 0x8a, - 0xce, 0x02, 0x34, 0x1c, 0xae, 0x83, 0x83, 0x9e, 0xec, 0x70, 0x0b, 0xba, 0x11, 0x4a, 0xb0, 0x51, - 0x0b, 0xdd, 0x87, 0xa2, 0xec, 0xe6, 0x90, 0x6e, 0x27, 0xb7, 0x8a, 0xd5, 0x00, 0x00, 0x47, 0x58, - 0xf6, 0x37, 0x23, 0x30, 0x76, 0xdd, 0xa7, 0x4e, 0xa3, 0xc9, 0xd1, 0xef, 0xc0, 0x78, 0x5b, 0x93, - 0x4a, 0x39, 0xc8, 0xd2, 0xd9, 0x5f, 0x1d, 0x4c, 0xc7, 0x6d, 0xb9, 0xe8, 0x82, 0x90, 0x46, 0x03, - 0x89, 0xca, 0x70, 0x88, 0x2a, 0x08, 0x19, 0x69, 0x39, 0x84, 0xc9, 0x75, 0x33, 0x08, 0xd9, 0x8a, - 0x28, 0xc4, 0x4a, 0x86, 0xde, 0x83, 0x82, 0xe7, 0x3b, 0x0d, 0xc7, 0x9d, 0x2f, 0xca, 0x4e, 0x9c, - 0x1b, 0xcc, 0x85, 0xf4, 0x28, 0x6e, 0xcb, 0xa6, 0xd1, 0xe4, 0xab, 0xbf, 0xb1, 0x86, 0x44, 0x0f, - 0x60, 0x4c, 0x19, 0x53, 0xe0, 0xa0, 0xcb, 0x03, 0x07, 0x18, 0x65, 0x8f, 0x91, 0xd1, 0xab, 0xbf, - 0x19, 0x0e, 0x00, 0x51, 0x35, 0x8c, 0x2f, 0x23, 0x12, 0xfa, 0x8d, 0x0c, 0xf1, 0xa5, 0x6f, 0x40, - 0xa9, 0x86, 0x01, 0x65, 0x34, 0x0b, 0xa8, 0x0c, 0x19, 0xfd, 0x22, 0x88, 0x98, 0x62, 0xcd, 0x5c, - 0x0a, 0x43, 0x4c, 0xb1, 0xa6, 0x4d, 0x53, 0x71, 0xba, 0x13, 0x10, 0x1b, 0xfb, 0xb3, 0x3c, 0xcc, - 0xea, 0x9a, 0xab, 0x5e, 0xab, 0x45, 0x6b, 0x72, 0x9b, 0x54, 0xf1, 0x29, 0x9f, 0x1a, 0x9f, 0x1c, - 0x18, 0x75, 0x38, 0x6d, 0x07, 0x07, 0xb0, 0x4a, 0xa6, 0xde, 0x44, 0x3a, 0xca, 0xeb, 0x02, 0x44, - 0x9d, 0x81, 0xc2, 0x55, 0xd2, 0xb5, 0xb0, 0xd2, 0x80, 0xfe, 0xcc, 0x82, 0x93, 0xbb, 0xd4, 0x77, - 0xb6, 0x9d, 0x9a, 0x3c, 0xc1, 0xdc, 0x74, 0x18, 0xf7, 0xfc, 0x3d, 0xbd, 0x23, 0xbc, 0x3d, 0x98, - 0xe6, 0x7b, 0x06, 0xc0, 0xba, 0xbb, 0xed, 0x55, 0x7e, 0xaa, 0xb5, 0x9d, 0xbc, 0xd7, 0x0b, 0x8d, - 0xd3, 0xf4, 0x2d, 0x74, 0x00, 0xa2, 0xde, 0xa6, 0x1c, 0xa0, 0x36, 0xcc, 0x03, 0xd4, 0xc0, 0x1d, - 0x0b, 0x06, 0x1b, 0x84, 0x2c, 0xf3, 0xe0, 0xf5, 0xa5, 0x05, 0x25, 0x2d, 0xdf, 0x70, 0x18, 0x47, - 0x0f, 0x7b, 0xbc, 0xbd, 0x3c, 0x98, 0xb7, 0x8b, 0xd6, 0xd2, 0xd7, 0x43, 0xbe, 0x1a, 0x94, 0x18, - 0x9e, 0x8e, 0x83, 0x25, 0x55, 0x13, 0xfb, 0x56, 0xa6, 0xfe, 0x47, 0x81, 0x41, 0xce, 0x91, 0x5e, - 0x3b, 0xdb, 0x87, 0xc9, 0x98, 0x93, 0xa3, 0x0b, 0x30, 0xb2, 0xe3, 0xb8, 0xc1, 0xae, 0xf7, 0xcb, - 0x01, 0x9f, 0xfa, 0x4d, 0xc7, 0xad, 0x3f, 0xde, 0x5f, 0x9a, 0x8d, 0x55, 0x16, 0x85, 0x58, 0x56, - 0x3f, 0x9c, 0x86, 0x5d, 0x19, 0xff, 0xe2, 0xef, 0x97, 0x4e, 0x7c, 0xfc, 0xdd, 0xe9, 0x13, 0xf6, - 0xe7, 0x79, 0x98, 0x49, 0xce, 0xea, 0x00, 0x09, 0x89, 0x28, 0x86, 0x8d, 0x1f, 0x6b, 0x0c, 0xcb, - 0x1d, 0x5f, 0x0c, 0xcb, 0x1f, 0x47, 0x0c, 0x1b, 0x39, 0xb2, 0x18, 0x66, 0xff, 0xbb, 0x05, 0x53, - 0xe1, 0xca, 0x7c, 0xd0, 0x15, 0x3b, 0x6b, 0x34, 0xeb, 0xd6, 0xd1, 0xcf, 0xfa, 0xfb, 0x30, 0xc6, - 0xbc, 0xae, 0x5f, 0x93, 0xf4, 0x51, 0xa0, 0x9f, 0xcf, 0x16, 0x34, 0x55, 0x5b, 0x83, 0x33, 0xa9, - 0x02, 0x1c, 0xa0, 0xda, 0x0f, 0xc3, 0xf1, 0x68, 0x91, 0x62, 0x14, 0xbe, 0xe0, 0x5b, 0x62, 0x3c, - 0xe3, 0x26, 0xa3, 0x10, 0xa5, 0x58, 0x4b, 0x91, 0x2d, 0xc3, 0x79, 0x40, 0x6c, 0x8b, 0x15, 0xd0, - 0x51, 0x59, 0xae, 0x81, 0x92, 0xd8, 0x3f, 0xe6, 0x43, 0xef, 0xd1, 0xc7, 0xd7, 0x0f, 0x01, 0x54, - 0x64, 0xa2, 0xf5, 0x75, 0x57, 0x87, 0xde, 0xd5, 0x21, 0x36, 0x02, 0x1d, 0x0e, 0x05, 0x8a, 0x8a, - 0xbd, 0x21, 0x07, 0x88, 0x04, 0xd8, 0x50, 0x85, 0x7e, 0x1f, 0x4a, 0x44, 0xa7, 0x4c, 0xae, 0x7b, - 0xbe, 0xb6, 0xe1, 0xb5, 0x61, 0x34, 0xaf, 0x44, 0x30, 0xc9, 0xd4, 0x57, 0x24, 0xc1, 0xa6, 0xb6, - 0x05, 0x1f, 0xa6, 0x13, 0xfd, 0x4d, 0x89, 0xbe, 0xeb, 0xf1, 0xe8, 0x7b, 0x2e, 0xcb, 0xb6, 0xa0, - 0xf3, 0x40, 0x66, 0xce, 0x8c, 0xc1, 0x4c, 0xb2, 0xa7, 0x47, 0xa6, 0x34, 0x96, 0x7c, 0x32, 0xe3, - 0xfd, 0xdf, 0xe5, 0xa0, 0x18, 0x7a, 0x7c, 0x96, 0x53, 0xaa, 0xda, 0xa9, 0x73, 0x87, 0x9c, 0x24, - 0xf2, 0x83, 0x9c, 0x24, 0x46, 0xfa, 0x9f, 0x24, 0x82, 0x4c, 0x56, 0xe1, 0xc9, 0x99, 0x2c, 0xe3, - 0x24, 0x31, 0x36, 0xf8, 0x49, 0x62, 0xfc, 0xf0, 0x93, 0x84, 0xfd, 0x0f, 0x16, 0xa0, 0xde, 0x63, - 0x63, 0x96, 0x89, 0x22, 0xc9, 0x38, 0x3c, 0xe0, 0x2e, 0x9d, 0x3c, 0xbb, 0xf5, 0x0f, 0xc7, 0xf6, - 0x97, 0xa3, 0x30, 0x7d, 0xc3, 0x19, 0x3a, 0xe1, 0xc0, 0xe1, 0x45, 0x85, 0x54, 0xa5, 0x9a, 0x23, - 0x55, 0xb9, 0x4f, 0x38, 0x6d, 0xec, 0xe9, 0xf5, 0xbd, 0xa2, 0x9b, 0xbe, 0xb8, 0x9a, 0x5e, 0xed, - 0x71, 0x7f, 0x11, 0xee, 0x07, 0x3d, 0xb0, 0x91, 0xbc, 0x03, 0x93, 0x8c, 0xfb, 0x4e, 0x8d, 0xab, - 0x94, 0x06, 0x9b, 0x2f, 0xc9, 0x28, 0x77, 0x4a, 0x57, 0x9f, 0xac, 0x9a, 0x42, 0x1c, 0xaf, 0x9b, - 0x9a, 0x29, 0x19, 0xc9, 0x9c, 0x29, 0x59, 0x86, 0x22, 0x69, 0xb5, 0xbc, 0x0f, 0xef, 0x90, 0x06, - 0xd3, 0x47, 0xd5, 0xd0, 0x6a, 0x56, 0x02, 0x01, 0x8e, 0xea, 0xa0, 0x32, 0x80, 0xd3, 0x70, 0x3d, - 0x9f, 0xca, 0x16, 0x05, 0x19, 0x6e, 0xa7, 0x44, 0xac, 0x5b, 0x0f, 0x4b, 0xb1, 0x51, 0x03, 0x55, - 0xe1, 0x94, 0xe3, 0x32, 0x5a, 0xeb, 0xfa, 0xb4, 0xba, 0xe3, 0x74, 0xee, 0x6c, 0x54, 0x65, 0x94, - 0xd8, 0x93, 0xd6, 0x3c, 0x5e, 0x79, 0x49, 0x2b, 0x3b, 0xb5, 0x9e, 0x56, 0x09, 0xa7, 0xb7, 0x45, - 0xe7, 0x61, 0xc2, 0x71, 0x6b, 0xad, 0x6e, 0x9d, 0x6e, 0x12, 0xde, 0x64, 0xf3, 0xe3, 0xb2, 0x1b, - 0x33, 0x07, 0xfb, 0x4b, 0x13, 0xeb, 0x46, 0x39, 0x8e, 0xd5, 0x12, 0xad, 0xe8, 0x47, 0x46, 0xab, - 0x62, 0xd4, 0xea, 0xda, 0x47, 0x66, 0x2b, 0xb3, 0x56, 0x4a, 0x2e, 0x09, 0x32, 0xe5, 0x92, 0xfe, - 0x3a, 0x0f, 0x05, 0x95, 0xca, 0x45, 0x17, 0x12, 0xf9, 0xd2, 0x97, 0x7a, 0xf2, 0xa5, 0xa5, 0xb4, - 0xb4, 0xb7, 0x0d, 0x05, 0x87, 0xb1, 0x6e, 0x7c, 0x77, 0x5b, 0x97, 0x25, 0x58, 0x4b, 0x90, 0x03, - 0x40, 0x82, 0x54, 0x6b, 0x40, 0x5d, 0x2e, 0x64, 0xcd, 0x08, 0x27, 0xb2, 0xc1, 0xa1, 0x80, 0x61, - 0x03, 0x5c, 0x66, 0x78, 0x3c, 0x77, 0xdb, 0x69, 0xe8, 0x73, 0xf8, 0x55, 0x83, 0x35, 0x47, 0xb7, - 0x6f, 0xef, 0x87, 0xd7, 0x73, 0x11, 0x81, 0x8e, 0x55, 0x10, 0x4c, 0xfa, 0x56, 0xf5, 0xf6, 0xbb, - 0x6a, 0x38, 0xab, 0x12, 0x11, 0x6b, 0x64, 0xa1, 0xc3, 0xeb, 0xf2, 0x4e, 0x97, 0x4b, 0x9b, 0x3c, - 0x22, 0x1d, 0xb7, 0x25, 0x22, 0xd6, 0xc8, 0xf6, 0xe7, 0x16, 0x4c, 0xab, 0xe9, 0x5e, 0x6d, 0xd2, - 0xda, 0x4e, 0x95, 0xd3, 0x8e, 0x20, 0xb6, 0x5d, 0x46, 0x59, 0x92, 0xd8, 0xde, 0x65, 0x94, 0x61, - 0x29, 0x31, 0x46, 0x9f, 0x3b, 0xae, 0xd1, 0xdb, 0xff, 0x64, 0xc1, 0xa8, 0x64, 0x90, 0x59, 0x42, - 0x5d, 0x3c, 0xab, 0x92, 0x1b, 0x28, 0xab, 0x72, 0x48, 0xbe, 0x2b, 0x4a, 0xe8, 0x8c, 0x3c, 0x29, - 0xa1, 0x63, 0xff, 0x60, 0xc1, 0x5c, 0x5a, 0x92, 0x30, 0x4b, 0xf7, 0xdf, 0x84, 0xf1, 0x4e, 0x8b, - 0xf0, 0x6d, 0xcf, 0x6f, 0x27, 0x6f, 0x03, 0x36, 0x75, 0x39, 0x0e, 0x6b, 0x20, 0x1f, 0xc0, 0x0f, - 0x4e, 0x23, 0x81, 0xb9, 0x5f, 0xcd, 0xba, 0xf9, 0xc4, 0xb3, 0x5b, 0xd1, 0x64, 0x85, 0x45, 0x0c, - 0x1b, 0x5a, 0xec, 0x3f, 0x1f, 0x85, 0x59, 0xd9, 0x64, 0xd8, 0xcd, 0x68, 0x98, 0x15, 0xea, 0xc0, - 0x0b, 0xf2, 0x0c, 0xd1, 0xbb, 0x7f, 0xa9, 0x45, 0xbb, 0xa4, 0xdb, 0xbf, 0xb0, 0x9e, 0x5a, 0xeb, - 0x71, 0x5f, 0x09, 0xee, 0x83, 0xdb, 0xbb, 0x29, 0xc1, 0x2f, 0xde, 0xa6, 0x64, 0x1a, 0xdb, 0xd8, - 0xa1, 0xc6, 0xd6, 0x77, 0x0b, 0x1b, 0x7f, 0x8a, 0x2d, 0xac, 0x77, 0x5b, 0x29, 0x66, 0xda, 0x56, - 0xfe, 0x26, 0x07, 0x63, 0x9b, 0xbe, 0x27, 0x93, 0xcd, 0xc7, 0x9f, 0xb7, 0xbc, 0x0d, 0x23, 0xac, - 0x43, 0x6b, 0x3a, 0xe6, 0x9d, 0x19, 0xcc, 0xd3, 0x74, 0xf7, 0xaa, 0x1d, 0x5a, 0xab, 0x8c, 0x8b, - 0x30, 0x2a, 0x7e, 0x61, 0x09, 0x64, 0x24, 0xe0, 0xf2, 0x59, 0xc8, 0x7e, 0x00, 0xf9, 0xe4, 0x04, - 0xdc, 0x97, 0x16, 0x94, 0x74, 0xcd, 0xe7, 0x36, 0xd3, 0xa3, 0xfb, 0xd7, 0x27, 0xd3, 0xf3, 0x17, - 0xd1, 0x08, 0xc4, 0xa4, 0xa1, 0x3f, 0x84, 0xd9, 0x8e, 0xef, 0xb5, 0x3d, 0xe1, 0xa9, 0x9b, 0x5e, - 0xcb, 0xa9, 0x39, 0x34, 0x48, 0x16, 0x5e, 0x18, 0x58, 0x9f, 0xd1, 0x7c, 0xaf, 0xf2, 0x13, 0xad, - 0x77, 0x76, 0x33, 0x89, 0x8b, 0x7b, 0x55, 0xd9, 0xff, 0x65, 0xc1, 0x64, 0x6c, 0xee, 0x51, 0x0d, - 0xa0, 0xe6, 0xb9, 0x75, 0x87, 0x87, 0x17, 0xb2, 0xa5, 0xb3, 0xcb, 0x83, 0xcd, 0xea, 0x6a, 0xd0, - 0x2e, 0x32, 0xba, 0xb0, 0x88, 0x61, 0x03, 0x16, 0x9d, 0x0b, 0xde, 0x2f, 0xc4, 0xf9, 0x92, 0x7a, - 0xbf, 0xf0, 0x78, 0x7f, 0x69, 0x42, 0xf7, 0xc9, 0x7c, 0xcf, 0x90, 0xe5, 0x95, 0xc0, 0x3f, 0xe6, - 0xa0, 0x18, 0x8e, 0xff, 0x19, 0xb8, 0xd1, 0xdd, 0x98, 0x1b, 0x9d, 0xcb, 0xb8, 0x72, 0xd2, 0x91, - 0x42, 0x4e, 0x62, 0x38, 0xd3, 0xa3, 0x84, 0x33, 0x65, 0x35, 0x89, 0x43, 0xdc, 0xe9, 0x5f, 0xd5, - 0xe2, 0xab, 0xba, 0xcf, 0xc0, 0xa1, 0xee, 0xc4, 0x1d, 0x6a, 0x39, 0xe3, 0x68, 0xfa, 0xb8, 0xd4, - 0xa7, 0x16, 0x4c, 0x27, 0x9c, 0x00, 0xbd, 0x0c, 0xa3, 0x32, 0x3b, 0xa4, 0xed, 0x2b, 0x6c, 0xa8, - 0x73, 0x09, 0x52, 0x86, 0x36, 0x61, 0x8e, 0x74, 0xb9, 0x17, 0xb6, 0xbd, 0xe6, 0x92, 0xad, 0x16, - 0x55, 0x09, 0x82, 0xf1, 0xca, 0x2f, 0xe9, 0x36, 0x73, 0x2b, 0x29, 0x75, 0x70, 0x6a, 0x4b, 0xfb, - 0xeb, 0x1c, 0xa0, 0xb0, 0x30, 0x4b, 0x56, 0xf5, 0x11, 0x8c, 0x6d, 0xab, 0xfc, 0xcf, 0xd3, 0xa5, - 0xc5, 0x2b, 0x25, 0xf3, 0x66, 0x20, 0xc0, 0x44, 0xbf, 0x7d, 0x34, 0x76, 0x04, 0xbd, 0x36, 0x84, - 0x1e, 0x00, 0x6c, 0x3b, 0xae, 0xc3, 0x9a, 0x43, 0x5e, 0xe0, 0xc9, 0xdd, 0xfc, 0x7a, 0x88, 0x80, - 0x0d, 0x34, 0xfb, 0x2a, 0x4c, 0x19, 0xb3, 0xc9, 0xfd, 0x3d, 0xb1, 0xbf, 0x13, 0xce, 0x69, 0xbb, - 0xc3, 0x15, 0x95, 0xcf, 0x47, 0xf6, 0xb6, 0xa2, 0xcb, 0x71, 0x58, 0xc3, 0xfe, 0x2c, 0x67, 0xd8, - 0xb7, 0x0c, 0xb7, 0x03, 0xd9, 0xc5, 0xeb, 0xf1, 0xc5, 0x28, 0xf6, 0x5e, 0xb9, 0x18, 0x13, 0x3b, - 0xb2, 0x4b, 0xfc, 0x20, 0xfb, 0x7b, 0x31, 0xe3, 0xb4, 0xde, 0x23, 0xbe, 0x23, 0x0c, 0x27, 0x32, - 0x89, 0x7b, 0xc4, 0x67, 0x58, 0x42, 0xa2, 0x9f, 0x8b, 0xae, 0xd2, 0xf0, 0xcc, 0x97, 0x39, 0xa6, - 0x70, 0xda, 0x31, 0xc7, 0x47, 0x3b, 0x0c, 0x2b, 0x40, 0xfb, 0x93, 0x82, 0xe1, 0x30, 0x3a, 0xea, - 0xdf, 0x02, 0xd4, 0x22, 0x8c, 0xdf, 0x24, 0x6e, 0x5d, 0x98, 0x37, 0xdd, 0xf6, 0x29, 0x6b, 0x6a, - 0x86, 0xb7, 0xa0, 0x51, 0xd0, 0x46, 0x4f, 0x0d, 0x9c, 0xd2, 0x0a, 0x5d, 0x88, 0x07, 0xf7, 0xa5, - 0x64, 0x70, 0x8f, 0x16, 0x75, 0xc8, 0xf0, 0x6e, 0xba, 0xcb, 0xe8, 0x31, 0xb8, 0xcb, 0x1f, 0xc0, - 0xec, 0x76, 0xf2, 0x0a, 0x4e, 0x5f, 0xc8, 0x5f, 0x1c, 0xf2, 0x06, 0xaf, 0x72, 0xea, 0x20, 0xba, - 0xb7, 0x89, 0x8a, 0x71, 0xaf, 0x22, 0xe4, 0x05, 0x4f, 0xcf, 0xe4, 0xe9, 0x55, 0xe5, 0x40, 0x06, - 0x76, 0xd9, 0xc4, 0xb9, 0x37, 0xf9, 0xe8, 0x4c, 0x41, 0xe2, 0x98, 0x82, 0x84, 0x0b, 0x17, 0x8e, - 0xd2, 0x85, 0xd1, 0x05, 0x28, 0xd5, 0xba, 0xbe, 0x4f, 0x5d, 0x2e, 0xba, 0x23, 0xa9, 0x70, 0x3e, - 0xca, 0x65, 0xaf, 0x46, 0x22, 0x6c, 0xd6, 0x43, 0xef, 0x4b, 0x3f, 0xe5, 0x54, 0x9e, 0x51, 0x9e, - 0xfe, 0x2c, 0x5e, 0xd4, 0x3e, 0xce, 0x95, 0x8f, 0x73, 0x6a, 0x7f, 0x1a, 0x0b, 0x0d, 0x83, 0x65, - 0x08, 0x16, 0x20, 0x47, 0x58, 0x32, 0x7d, 0xbc, 0xc2, 0x70, 0x8e, 0x30, 0x74, 0x17, 0x46, 0x7d, - 0x11, 0xa1, 0x74, 0x04, 0x3c, 0x9f, 0xd1, 0x5b, 0x65, 0x74, 0x53, 0xdd, 0x94, 0x3f, 0xb1, 0x42, - 0x33, 0x92, 0x12, 0xf9, 0x63, 0x4b, 0x4a, 0xf8, 0x10, 0x51, 0xc5, 0xe0, 0x9d, 0x28, 0x7a, 0xa4, - 0x09, 0x8d, 0x95, 0xe5, 0xdd, 0x63, 0x0f, 0x4c, 0x3f, 0x62, 0x63, 0x7f, 0x6d, 0xc1, 0xa9, 0xd4, - 0xda, 0x61, 0x44, 0xcd, 0x1d, 0x63, 0x44, 0xb5, 0x8e, 0x3a, 0xa2, 0x3e, 0x30, 0xa6, 0x30, 0xe8, - 0xc2, 0x51, 0x3d, 0xee, 0xfe, 0x22, 0x07, 0x33, 0x98, 0x76, 0xbc, 0x58, 0x72, 0x62, 0x33, 0x78, - 0x49, 0x96, 0x61, 0x37, 0x4f, 0x64, 0xdb, 0x2b, 0x63, 0xb1, 0x27, 0x64, 0x3f, 0x87, 0x51, 0x99, - 0x37, 0xd0, 0xfc, 0xe3, 0x62, 0x86, 0xdb, 0xd1, 0x18, 0xaa, 0xb4, 0x61, 0x95, 0x80, 0x51, 0x80, - 0x02, 0x59, 0x5e, 0x6c, 0x6a, 0x13, 0xbe, 0x98, 0xe1, 0x8a, 0xb4, 0x17, 0x59, 0x16, 0x63, 0x05, - 0x68, 0x7f, 0x9e, 0x03, 0xb5, 0x73, 0x3f, 0x03, 0x86, 0xff, 0x5b, 0x31, 0x86, 0x3f, 0x20, 0x75, - 0x95, 0x9d, 0xeb, 0xcb, 0xee, 0x93, 0xac, 0xec, 0x4c, 0x16, 0xd0, 0x27, 0x33, 0xfb, 0x7f, 0xb1, - 0xa0, 0x28, 0xeb, 0x3d, 0x03, 0x56, 0xbf, 0x19, 0x67, 0xf5, 0x6f, 0x64, 0x18, 0x45, 0x1f, 0x46, - 0xff, 0x59, 0x5e, 0xf7, 0x3e, 0xe4, 0x6c, 0x4d, 0xe2, 0xd7, 0x35, 0x1b, 0x89, 0x3c, 0x50, 0x14, - 0x62, 0x25, 0x43, 0xbf, 0x07, 0x33, 0xbe, 0xba, 0x2b, 0xa7, 0xf5, 0xeb, 0x21, 0x35, 0xc8, 0x67, - 0xbe, 0xcc, 0xd6, 0x17, 0xee, 0x51, 0x56, 0x0b, 0x27, 0x50, 0x71, 0x8f, 0x1e, 0x41, 0x17, 0x3a, - 0xc9, 0x58, 0xa6, 0xb7, 0xd1, 0x8b, 0x43, 0x06, 0x4e, 0x45, 0x17, 0x7a, 0x8a, 0x71, 0xaf, 0x22, - 0xd4, 0x84, 0x09, 0xf3, 0x19, 0x8e, 0xb6, 0xa5, 0xb3, 0xd9, 0xdf, 0xfb, 0xa8, 0x0b, 0x13, 0xb3, - 0x04, 0xc7, 0x90, 0xed, 0xfd, 0x02, 0x94, 0x0c, 0xe3, 0x4b, 0x64, 0x0a, 0x26, 0x8f, 0x27, 0x53, - 0x90, 0x4e, 0x4c, 0x4b, 0x43, 0x11, 0xd3, 0x33, 0x71, 0x62, 0xfa, 0xd3, 0x24, 0x31, 0x05, 0x39, - 0xba, 0x18, 0x29, 0x65, 0x30, 0xa5, 0x19, 0x5a, 0xf0, 0x9e, 0x2a, 0x13, 0xd5, 0xef, 0xe5, 0x81, - 0xe8, 0x60, 0x7f, 0x29, 0x78, 0x0d, 0x11, 0xbc, 0xa3, 0x4a, 0xa8, 0x40, 0x57, 0x43, 0xa5, 0xd5, - 0x6e, 0xbb, 0x4d, 0xfc, 0xbd, 0xf9, 0x09, 0xd9, 0xe1, 0x30, 0x85, 0x78, 0x3d, 0x26, 0xc5, 0x89, - 0xda, 0x68, 0x13, 0x0a, 0x8a, 0xe0, 0xe9, 0x37, 0x3a, 0x6f, 0x66, 0xe1, 0x8e, 0x8a, 0x23, 0xa8, - 0xdf, 0x58, 0xe3, 0x98, 0xdc, 0xbc, 0x78, 0x08, 0x37, 0xbf, 0x05, 0xc8, 0xdb, 0x92, 0x6c, 0xa4, - 0x7e, 0x43, 0x7d, 0x05, 0x25, 0xac, 0xb2, 0x20, 0x89, 0x5f, 0xb8, 0x60, 0xb7, 0x7b, 0x6a, 0xe0, - 0x94, 0x56, 0xc2, 0xab, 0x35, 0x2b, 0x0c, 0x5d, 0x41, 0xf3, 0xf0, 0x4b, 0x99, 0x09, 0x56, 0x40, - 0xf9, 0xe7, 0x84, 0x57, 0xaf, 0x26, 0x50, 0x71, 0x8f, 0x1e, 0xf4, 0x01, 0x4c, 0x0a, 0x13, 0x8a, - 0x14, 0xc3, 0x53, 0x2a, 0x9e, 0x3d, 0xd8, 0x5f, 0x9a, 0xdc, 0x30, 0x21, 0x71, 0x5c, 0x83, 0xfd, - 0x7f, 0x39, 0x88, 0xf9, 0x1f, 0xfa, 0xd4, 0x82, 0x59, 0x92, 0xf8, 0x84, 0x27, 0xa0, 0x2f, 0xbf, - 0x91, 0xed, 0xbb, 0xaa, 0x9e, 0x2f, 0x80, 0xa2, 0x44, 0x61, 0xb2, 0x0a, 0xc3, 0xbd, 0x4a, 0xd1, - 0x9f, 0x5a, 0x70, 0x92, 0xf4, 0x7e, 0xa3, 0xa5, 0xf7, 0xc3, 0xcb, 0x43, 0x7f, 0xe4, 0x55, 0x79, - 0xf1, 0x60, 0x7f, 0x29, 0xed, 0xeb, 0x35, 0x9c, 0xa6, 0x0e, 0xbd, 0x07, 0x23, 0xc4, 0x6f, 0x04, - 0x87, 0xe2, 0xec, 0x6a, 0x83, 0x4f, 0xef, 0xa2, 0x0d, 0x79, 0xc5, 0x6f, 0x30, 0x2c, 0x41, 0xed, - 0xef, 0xf2, 0x30, 0x93, 0x7c, 0x01, 0xa9, 0x1f, 0x8d, 0x8c, 0xa4, 0x3e, 0x1a, 0x79, 0x19, 0x46, - 0x49, 0x8d, 0x87, 0x2f, 0x38, 0xa2, 0x57, 0xbf, 0xa2, 0x10, 0x2b, 0x19, 0xba, 0x0f, 0x45, 0xc6, - 0x89, 0xcf, 0xc5, 0x59, 0x49, 0x1f, 0x57, 0x33, 0xbf, 0x70, 0xae, 0x06, 0x00, 0x38, 0xc2, 0x42, - 0x97, 0xe2, 0xe1, 0xcc, 0x4e, 0x86, 0xb3, 0x59, 0x73, 0x2c, 0xc3, 0x1e, 0xb5, 0xdb, 0x50, 0x32, - 0xd6, 0x41, 0xef, 0x2e, 0x57, 0x32, 0xcf, 0x7b, 0x64, 0x76, 0xd3, 0xea, 0xfb, 0xbd, 0x48, 0x62, - 0xe2, 0x47, 0x67, 0x51, 0x39, 0x5b, 0x4f, 0x75, 0x16, 0x95, 0xd3, 0x65, 0xa0, 0xd9, 0xd3, 0x30, - 0x19, 0x7b, 0xc8, 0x24, 0xb3, 0xc4, 0xf7, 0x89, 0x4f, 0x9b, 0x5e, 0x97, 0xd1, 0xe7, 0x35, 0x4b, - 0x1c, 0x76, 0xf0, 0xa8, 0xb3, 0xc4, 0x11, 0xf0, 0xe1, 0x59, 0xe2, 0xb0, 0xee, 0x73, 0x9b, 0x25, - 0x0e, 0x7b, 0xd8, 0x87, 0x53, 0xfe, 0x6f, 0xce, 0x18, 0x45, 0x9c, 0x57, 0xe6, 0x9e, 0xc0, 0x2b, - 0x1f, 0xc2, 0xb8, 0xe3, 0x72, 0xea, 0xef, 0x92, 0x96, 0x3e, 0xda, 0x0f, 0x38, 0xd4, 0xb5, 0xae, - 0xaf, 0x59, 0x55, 0x30, 0xd4, 0x75, 0x8d, 0x83, 0x43, 0x44, 0xd4, 0x82, 0x53, 0x41, 0xfe, 0xc7, - 0xa7, 0x24, 0xca, 0x5f, 0xeb, 0x3b, 0xe0, 0xb7, 0x83, 0x0b, 0xc8, 0xeb, 0x69, 0x95, 0x1e, 0xf7, - 0x13, 0xe0, 0x74, 0x50, 0xc4, 0x60, 0x92, 0x19, 0x07, 0xaa, 0x60, 0x23, 0x19, 0x30, 0x77, 0x96, - 0x3c, 0x83, 0x1a, 0x17, 0xc7, 0x26, 0x28, 0x8e, 0xeb, 0xb0, 0xff, 0x23, 0x0f, 0xd3, 0x09, 0x4b, - 0x4b, 0x10, 0xc7, 0xe2, 0xb3, 0x24, 0x8e, 0x85, 0xa1, 0x88, 0x63, 0x3a, 0xa7, 0x19, 0x19, 0x8a, - 0xd3, 0xbc, 0xa3, 0x78, 0x85, 0x5e, 0xb9, 0xf5, 0x35, 0xfd, 0xa4, 0x2f, 0x9c, 0xcd, 0x0d, 0x53, - 0x88, 0xe3, 0x75, 0xe5, 0x2e, 0x5c, 0xef, 0xfd, 0x7e, 0x4d, 0x93, 0xa2, 0xcb, 0x59, 0x1f, 0x4a, - 0x84, 0x00, 0x6a, 0x17, 0x4e, 0x11, 0xe0, 0x34, 0x75, 0x95, 0x5b, 0x5f, 0x7d, 0xbf, 0x78, 0xe2, - 0x9b, 0xef, 0x17, 0x4f, 0x7c, 0xfb, 0xfd, 0xe2, 0x89, 0x8f, 0x0f, 0x16, 0xad, 0xaf, 0x0e, 0x16, - 0xad, 0x6f, 0x0e, 0x16, 0xad, 0x6f, 0x0f, 0x16, 0xad, 0xff, 0x3e, 0x58, 0xb4, 0xfe, 0xea, 0x87, - 0xc5, 0x13, 0x0f, 0x5e, 0x19, 0xe4, 0x1f, 0x0d, 0xfc, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x8c, - 0xd4, 0xaa, 0xfb, 0x8f, 0x40, 0x00, 0x00, + // 3674 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5c, 0xcd, 0x6f, 0x23, 0x47, + 0x76, 0x9f, 0x26, 0x25, 0x4a, 0x7c, 0xd4, 0x67, 0x8d, 0xc6, 0xd6, 0x6a, 0x63, 0x69, 0xd2, 0x36, + 0x0c, 0x3b, 0xb6, 0xa9, 0xcc, 0x97, 0xe7, 0xc3, 0xc9, 0x04, 0x22, 0x35, 0x1f, 0x9a, 0x68, 0x3d, + 0x4a, 0x71, 0x3e, 0x36, 0xb3, 0x33, 0x70, 0x4a, 0x64, 0x89, 0xec, 0x88, 0xec, 0xe6, 0x76, 0x15, + 0xb5, 0x56, 0x12, 0x24, 0x9b, 0x2f, 0xc0, 0x40, 0x90, 0x20, 0x07, 0x23, 0xde, 0x00, 0x09, 0x10, + 0x24, 0xe7, 0xe4, 0x1f, 0xc8, 0xc1, 0x87, 0x5c, 0x8c, 0x60, 0x13, 0x18, 0x49, 0x0e, 0x3e, 0x2c, + 0x84, 0x58, 0x06, 0x72, 0xf4, 0x2d, 0x97, 0x01, 0x02, 0x04, 0xf5, 0xd1, 0xdd, 0xd5, 0xcd, 0xe6, + 0x88, 0xcd, 0x91, 0x06, 0x83, 0xbd, 0x51, 0xf5, 0xea, 0xfd, 0x5e, 0x7d, 0xbc, 0xf7, 0xea, 0xbd, + 0x57, 0xd5, 0x82, 0x8b, 0x4d, 0x87, 0xb7, 0x7a, 0xdb, 0xe5, 0xba, 0xd7, 0x59, 0x25, 0xbb, 0x3d, + 0x87, 0xef, 0xaf, 0xee, 0x12, 0xbf, 0xe9, 0xad, 0x92, 0xae, 0xb3, 0xba, 0x77, 0x8e, 0xb4, 0xbb, + 0x2d, 0x72, 0x6e, 0xb5, 0x49, 0x5d, 0xea, 0x13, 0x4e, 0x1b, 0xe5, 0xae, 0xef, 0x71, 0x0f, 0xbd, + 0x11, 0x71, 0x95, 0x15, 0x57, 0x59, 0x72, 0x95, 0x49, 0xd7, 0x29, 0x07, 0x5c, 0x4b, 0xef, 0x19, + 0xd8, 0x4d, 0xaf, 0xe9, 0xad, 0x4a, 0xe6, 0xed, 0xde, 0x8e, 0xfc, 0x4b, 0xfe, 0x21, 0x7f, 0x29, + 0xd0, 0xa5, 0xdb, 0xbb, 0x57, 0x58, 0xd9, 0x91, 0x92, 0xe9, 0xc7, 0x9c, 0xba, 0xcc, 0xf1, 0x5c, + 0xf6, 0x1e, 0xe9, 0x3a, 0x8c, 0xfa, 0x7b, 0xd4, 0x5f, 0xed, 0xee, 0x36, 0x05, 0x8d, 0xc5, 0x3b, + 0xac, 0xee, 0xf5, 0x0d, 0x6f, 0xe9, 0x62, 0x84, 0xd4, 0x21, 0xf5, 0x96, 0xe3, 0x52, 0x7f, 0x3f, + 0x62, 0xef, 0x50, 0x4e, 0xd2, 0xb8, 0x56, 0x07, 0x71, 0xf9, 0x3d, 0x97, 0x3b, 0x1d, 0xda, 0xc7, + 0xf0, 0xfe, 0x51, 0x0c, 0xac, 0xde, 0xa2, 0x1d, 0x92, 0xe4, 0xb3, 0x1f, 0xc3, 0xe9, 0x35, 0x97, + 0xb4, 0xf7, 0x99, 0xc3, 0x70, 0xcf, 0x5d, 0xf3, 0x9b, 0xbd, 0x0e, 0x75, 0x39, 0x3a, 0x0b, 0x63, + 0x2e, 0xe9, 0xd0, 0x45, 0xeb, 0xac, 0xf5, 0x56, 0xb1, 0x32, 0xf5, 0xc5, 0xc1, 0xca, 0xa9, 0xc3, + 0x83, 0x95, 0xb1, 0x0f, 0x49, 0x87, 0x62, 0x49, 0x41, 0xaf, 0xc3, 0xf8, 0x1e, 0x69, 0xf7, 0xe8, + 0x62, 0x4e, 0x76, 0x99, 0xd6, 0x5d, 0xc6, 0x1f, 0x88, 0x46, 0xac, 0x68, 0xf6, 0x1f, 0xe7, 0x63, + 0xf0, 0xdf, 0xa3, 0x9c, 0x34, 0x08, 0x27, 0xa8, 0x03, 0x85, 0x36, 0xd9, 0xa6, 0x6d, 0xb6, 0x68, + 0x9d, 0xcd, 0xbf, 0x55, 0x3a, 0x7f, 0xa3, 0x3c, 0xcc, 0x26, 0x96, 0x53, 0xa0, 0xca, 0x9b, 0x12, + 0xe7, 0x86, 0xcb, 0xfd, 0xfd, 0xca, 0x8c, 0x1e, 0x44, 0x41, 0x35, 0x62, 0x2d, 0x04, 0xfd, 0xa1, + 0x05, 0x25, 0xe2, 0xba, 0x1e, 0x27, 0x5c, 0x6c, 0xd3, 0x62, 0x4e, 0x0a, 0xbd, 0x33, 0xba, 0xd0, + 0xb5, 0x08, 0x4c, 0x49, 0x3e, 0xad, 0x25, 0x97, 0x0c, 0x0a, 0x36, 0x65, 0x2e, 0x5d, 0x85, 0x92, + 0x31, 0x54, 0x34, 0x07, 0xf9, 0x5d, 0xba, 0xaf, 0xd6, 0x17, 0x8b, 0x9f, 0x68, 0x21, 0xb6, 0xa0, + 0x7a, 0x05, 0xaf, 0xe5, 0xae, 0x58, 0x4b, 0xd7, 0x61, 0x2e, 0x29, 0x30, 0x0b, 0xbf, 0xfd, 0x17, + 0x16, 0x2c, 0x18, 0xb3, 0xc0, 0x74, 0x87, 0xfa, 0xd4, 0xad, 0x53, 0xb4, 0x0a, 0x45, 0xb1, 0x97, + 0xac, 0x4b, 0xea, 0xc1, 0x56, 0xcf, 0xeb, 0x89, 0x14, 0x3f, 0x0c, 0x08, 0x38, 0xea, 0x13, 0xaa, + 0x45, 0xee, 0x59, 0x6a, 0xd1, 0x6d, 0x11, 0x46, 0x17, 0xf3, 0x71, 0xb5, 0xd8, 0x12, 0x8d, 0x58, + 0xd1, 0xec, 0x5f, 0x85, 0xef, 0x04, 0xe3, 0xb9, 0x47, 0x3b, 0xdd, 0x36, 0xe1, 0x34, 0x1a, 0xd4, + 0x91, 0xaa, 0x67, 0xcf, 0xc2, 0xf4, 0x5a, 0xb7, 0xeb, 0x7b, 0x7b, 0xb4, 0x51, 0xe3, 0xa4, 0x49, + 0xed, 0x3f, 0xb2, 0xe0, 0xcc, 0x9a, 0xdf, 0xf4, 0xaa, 0xeb, 0x6b, 0xdd, 0xee, 0x6d, 0x4a, 0xda, + 0xbc, 0x55, 0xe3, 0x84, 0xf7, 0x18, 0xba, 0x0e, 0x05, 0x26, 0x7f, 0x69, 0xb8, 0x37, 0x03, 0x0d, + 0x51, 0xf4, 0xa7, 0x07, 0x2b, 0x0b, 0x29, 0x8c, 0x14, 0x6b, 0x2e, 0xf4, 0x36, 0x4c, 0x74, 0x28, + 0x63, 0xa4, 0x19, 0xcc, 0x79, 0x56, 0x03, 0x4c, 0x7c, 0x4f, 0x35, 0xe3, 0x80, 0x6e, 0xff, 0x6b, + 0x0e, 0x66, 0x43, 0x2c, 0x2d, 0xfe, 0x04, 0x16, 0xb8, 0x07, 0x53, 0x2d, 0x63, 0x86, 0x72, 0x9d, + 0x4b, 0xe7, 0x3f, 0x18, 0x52, 0x97, 0xd3, 0x16, 0xa9, 0xb2, 0xa0, 0xc5, 0x4c, 0x99, 0xad, 0x38, + 0x26, 0x06, 0x75, 0x00, 0xd8, 0xbe, 0x5b, 0xd7, 0x42, 0xc7, 0xa4, 0xd0, 0xab, 0x19, 0x85, 0xd6, + 0x42, 0x80, 0x0a, 0xd2, 0x22, 0x21, 0x6a, 0xc3, 0x86, 0x00, 0xfb, 0x9f, 0x2c, 0x38, 0x9d, 0xc2, + 0x87, 0x7e, 0x25, 0xb1, 0x9f, 0x6f, 0xf4, 0xed, 0x27, 0xea, 0x63, 0x8b, 0x76, 0xf3, 0x5d, 0x98, + 0xf4, 0xe9, 0x9e, 0x23, 0x7c, 0xb5, 0x5e, 0xe1, 0x39, 0xcd, 0x3f, 0x89, 0x75, 0x3b, 0x0e, 0x7b, + 0xa0, 0x77, 0xa0, 0x18, 0xfc, 0x16, 0xcb, 0x9c, 0x17, 0xea, 0x2c, 0x36, 0x2e, 0xe8, 0xca, 0x70, + 0x44, 0xb7, 0xff, 0x00, 0xc6, 0xab, 0x2d, 0xe2, 0x73, 0xa1, 0x31, 0x3e, 0xed, 0x7a, 0xf7, 0xf1, + 0xa6, 0x1e, 0x62, 0xa8, 0x31, 0x58, 0x35, 0xe3, 0x80, 0x3e, 0xc4, 0x66, 0xbf, 0x0d, 0x13, 0x7b, + 0xd4, 0x97, 0xe3, 0xcd, 0xc7, 0xc1, 0x1e, 0xa8, 0x66, 0x1c, 0xd0, 0xed, 0xff, 0xb4, 0x60, 0x41, + 0x8e, 0x60, 0xdd, 0x61, 0x75, 0x6f, 0x8f, 0xfa, 0xfb, 0x98, 0xb2, 0x5e, 0xfb, 0x98, 0x07, 0xb4, + 0x0e, 0x73, 0x8c, 0x76, 0xf6, 0xa8, 0x5f, 0xf5, 0x5c, 0xc6, 0x7d, 0xe2, 0xb8, 0x5c, 0x8f, 0x6c, + 0x51, 0xf7, 0x9e, 0xab, 0x25, 0xe8, 0xb8, 0x8f, 0x03, 0xbd, 0x05, 0x93, 0x7a, 0xd8, 0x42, 0x95, + 0xc4, 0xc2, 0x4e, 0x89, 0x3d, 0xd0, 0x73, 0x62, 0x38, 0xa4, 0xda, 0xff, 0x63, 0xc1, 0xbc, 0x9c, + 0x55, 0xad, 0xb7, 0xcd, 0xea, 0xbe, 0xd3, 0x15, 0x2e, 0xf0, 0x65, 0x9c, 0xd2, 0x75, 0x98, 0x69, + 0x04, 0x0b, 0xbf, 0xe9, 0x74, 0x1c, 0x2e, 0x6d, 0x64, 0xbc, 0xf2, 0x8a, 0xc6, 0x98, 0x59, 0x8f, + 0x51, 0x71, 0xa2, 0xb7, 0xfd, 0x37, 0x79, 0x38, 0x1d, 0x74, 0xa1, 0x8d, 0x35, 0x9f, 0x3b, 0x3b, + 0xa4, 0xce, 0x19, 0x6a, 0xc0, 0x54, 0x23, 0x6a, 0xe6, 0xda, 0xf2, 0x7e, 0xa9, 0xac, 0x8e, 0xfb, + 0xb2, 0x79, 0xdc, 0x97, 0xbb, 0xbb, 0x4d, 0xd1, 0xc0, 0xca, 0x22, 0xaa, 0x28, 0xef, 0x9d, 0x2b, + 0xdf, 0x73, 0x3a, 0x34, 0xb2, 0x6e, 0x03, 0x9e, 0xe3, 0x18, 0x2a, 0x7a, 0x08, 0xf9, 0xa6, 0xc3, + 0xf5, 0x61, 0x7c, 0x65, 0x38, 0xb3, 0xbe, 0xe5, 0x24, 0x55, 0xad, 0x52, 0xd2, 0xa2, 0xf2, 0xb7, + 0x1c, 0x8e, 0x05, 0x22, 0xda, 0x86, 0x82, 0xd3, 0x21, 0x4d, 0x1a, 0x9c, 0xb9, 0xd7, 0x86, 0xc3, + 0xde, 0x10, 0x3c, 0x49, 0xf4, 0xf0, 0x74, 0x97, 0x54, 0x86, 0x35, 0xb2, 0x90, 0x51, 0x17, 0x2a, + 0xa2, 0x8c, 0x74, 0x68, 0x19, 0x69, 0xc6, 0x12, 0xc9, 0x90, 0x54, 0x86, 0x35, 0xb2, 0xfd, 0x55, + 0x0e, 0xe6, 0xa2, 0xf5, 0xab, 0x7a, 0x9d, 0x8e, 0xc3, 0xd1, 0x12, 0xe4, 0x9c, 0x86, 0xd6, 0x40, + 0xd0, 0x8c, 0xb9, 0x8d, 0x75, 0x9c, 0x73, 0x1a, 0xe8, 0x4d, 0x28, 0x6c, 0xfb, 0xc4, 0xad, 0xb7, + 0xb4, 0xe6, 0x85, 0xc0, 0x15, 0xd9, 0x8a, 0x35, 0x15, 0xbd, 0x06, 0x79, 0x4e, 0x9a, 0x5a, 0xe1, + 0xc2, 0xf5, 0xbb, 0x47, 0x9a, 0x58, 0xb4, 0x0b, 0x4d, 0x67, 0xbd, 0xed, 0xdf, 0xa6, 0x75, 0xb5, + 0xf3, 0x86, 0xa6, 0xd7, 0x54, 0x33, 0x0e, 0xe8, 0x42, 0x22, 0xe9, 0xf1, 0x96, 0xe7, 0x2f, 0x8e, + 0xc7, 0x25, 0xae, 0xc9, 0x56, 0xac, 0xa9, 0xe2, 0x4c, 0xaa, 0xcb, 0xf1, 0x73, 0xea, 0x2f, 0x16, + 0xe2, 0x67, 0x52, 0x35, 0x20, 0xe0, 0xa8, 0x0f, 0x7a, 0x02, 0xa5, 0xba, 0x4f, 0x09, 0xf7, 0xfc, + 0x75, 0xc2, 0xe9, 0xe2, 0x44, 0x66, 0x0d, 0x9c, 0x15, 0x81, 0x51, 0x35, 0x82, 0xc0, 0x26, 0x9e, + 0xfd, 0xad, 0x05, 0x8b, 0xd1, 0xd2, 0xca, 0xbd, 0x8d, 0x82, 0x01, 0xbd, 0x3c, 0xd6, 0x80, 0xe5, + 0x79, 0x13, 0x0a, 0x0d, 0xa7, 0x49, 0x19, 0x4f, 0xae, 0xf2, 0xba, 0x6c, 0xc5, 0x9a, 0x8a, 0xce, + 0x03, 0x34, 0x1d, 0xae, 0x9d, 0x83, 0x5e, 0xec, 0xf0, 0x08, 0xba, 0x15, 0x52, 0xb0, 0xd1, 0x0b, + 0x3d, 0x84, 0xa2, 0x1c, 0xe6, 0x88, 0x66, 0x27, 0x8f, 0x8a, 0x6a, 0x00, 0x80, 0x23, 0x2c, 0xfb, + 0xcb, 0x31, 0x98, 0xb8, 0xe9, 0x53, 0xa7, 0xd9, 0xe2, 0xe8, 0xb7, 0x60, 0xb2, 0xa3, 0x83, 0x4a, + 0x39, 0xc9, 0xd2, 0xf9, 0x5f, 0x1e, 0x4e, 0xc6, 0x5d, 0xb9, 0xe9, 0x22, 0x20, 0x8d, 0x26, 0x12, + 0xb5, 0xe1, 0x10, 0x55, 0x04, 0x64, 0xa4, 0xed, 0x10, 0x26, 0xf7, 0xcd, 0x08, 0xc8, 0xd6, 0x44, + 0x23, 0x56, 0x34, 0xf4, 0x03, 0x28, 0x78, 0xbe, 0xd3, 0x74, 0xdc, 0xc5, 0xa2, 0x1c, 0xc4, 0x85, + 0xe1, 0x4c, 0x48, 0xcf, 0xe2, 0xae, 0x64, 0x8d, 0x16, 0x5f, 0xfd, 0x8d, 0x35, 0x24, 0x7a, 0x04, + 0x13, 0x4a, 0x99, 0x02, 0x03, 0x5d, 0x1d, 0xda, 0xc1, 0x28, 0x7d, 0x8c, 0x94, 0x5e, 0xfd, 0xcd, + 0x70, 0x00, 0x88, 0x6a, 0xa1, 0x7f, 0x19, 0x93, 0xd0, 0xef, 0x64, 0xf0, 0x2f, 0x03, 0x1d, 0x4a, + 0x2d, 0x74, 0x28, 0xe3, 0x59, 0x40, 0xa5, 0xcb, 0x18, 0xe4, 0x41, 0xc4, 0x12, 0xeb, 0xc8, 0xa5, + 0x30, 0xc2, 0x12, 0xeb, 0xb0, 0x69, 0x26, 0x1e, 0xee, 0x04, 0x81, 0x8d, 0xfd, 0x69, 0x1e, 0xe6, + 0x75, 0xcf, 0xaa, 0xd7, 0x6e, 0xd3, 0xba, 0x3c, 0x26, 0x95, 0x7f, 0xca, 0xa7, 0xfa, 0x27, 0x07, + 0xc6, 0x1d, 0x4e, 0x3b, 0x41, 0x02, 0x56, 0xc9, 0x34, 0x9a, 0x48, 0x46, 0x79, 0x43, 0x80, 0xa8, + 0x1c, 0x28, 0xdc, 0x25, 0xdd, 0x0b, 0x2b, 0x09, 0xe8, 0x4f, 0x2d, 0x38, 0xbd, 0x47, 0x7d, 0x67, + 0xc7, 0xa9, 0xcb, 0x0c, 0xe6, 0xb6, 0xc3, 0xb8, 0xe7, 0xef, 0xeb, 0x13, 0xe1, 0xfd, 0xe1, 0x24, + 0x3f, 0x30, 0x00, 0x36, 0xdc, 0x1d, 0xaf, 0xf2, 0x5d, 0x2d, 0xed, 0xf4, 0x83, 0x7e, 0x68, 0x9c, + 0x26, 0x6f, 0xa9, 0x0b, 0x10, 0x8d, 0x36, 0x25, 0x81, 0xda, 0x34, 0x13, 0xa8, 0xa1, 0x07, 0x16, + 0x4c, 0x36, 0x70, 0x59, 0x66, 0xe2, 0xf5, 0xb9, 0x05, 0x25, 0x4d, 0xdf, 0x74, 0x18, 0x47, 0x8f, + 0xfb, 0xac, 0xbd, 0x3c, 0x9c, 0xb5, 0x0b, 0x6e, 0x69, 0xeb, 0x61, 0xbc, 0x1a, 0xb4, 0x18, 0x96, + 0x8e, 0x83, 0x2d, 0x55, 0x0b, 0xfb, 0x5e, 0xa6, 0xf1, 0x47, 0x8e, 0x41, 0xae, 0x91, 0xde, 0x3b, + 0xdb, 0x87, 0xe9, 0x98, 0x91, 0xa3, 0x4b, 0x30, 0xb6, 0xeb, 0xb8, 0xc1, 0xa9, 0xf7, 0x8b, 0x41, + 0x3c, 0xf5, 0xeb, 0x8e, 0xdb, 0x78, 0x7a, 0xb0, 0x32, 0x1f, 0xeb, 0x2c, 0x1a, 0xb1, 0xec, 0x7e, + 0x74, 0x18, 0x76, 0x6d, 0xf2, 0x27, 0x7f, 0xb7, 0x72, 0xea, 0xc7, 0x3f, 0x3b, 0x7b, 0xca, 0xfe, + 0x2c, 0x0f, 0x73, 0xc9, 0x55, 0x1d, 0xa2, 0x20, 0x11, 0xf9, 0xb0, 0xc9, 0x13, 0xf5, 0x61, 0xb9, + 0x93, 0xf3, 0x61, 0xf9, 0x93, 0xf0, 0x61, 0x63, 0xc7, 0xe6, 0xc3, 0xec, 0x7f, 0xb7, 0x60, 0x26, + 0xdc, 0x99, 0x1f, 0xf6, 0xc4, 0xc9, 0x1a, 0xad, 0xba, 0x75, 0xfc, 0xab, 0xfe, 0x11, 0x4c, 0x30, + 0xaf, 0xe7, 0xd7, 0x65, 0xf8, 0x28, 0xd0, 0x2f, 0x66, 0x73, 0x9a, 0x8a, 0xd7, 0x88, 0x99, 0x54, + 0x03, 0x0e, 0x50, 0xed, 0xc7, 0xe1, 0x7c, 0x34, 0x49, 0x45, 0x14, 0xbe, 0x88, 0xb7, 0xc4, 0x7c, + 0x26, 0xcd, 0x88, 0x42, 0xb4, 0x62, 0x4d, 0x45, 0xb6, 0x74, 0xe7, 0x41, 0x60, 0x5b, 0xac, 0x80, + 0xf6, 0xca, 0x72, 0x0f, 0x14, 0xc5, 0xfe, 0x36, 0x1f, 0x5a, 0x8f, 0x4e, 0x5f, 0x7f, 0x04, 0xa0, + 0x3c, 0x13, 0x6d, 0x6c, 0xb8, 0xda, 0xf5, 0x56, 0x47, 0x38, 0x08, 0xb4, 0x3b, 0x14, 0x28, 0xca, + 0xf7, 0x86, 0x31, 0x40, 0x44, 0xc0, 0x86, 0x28, 0xf4, 0xbb, 0x50, 0x22, 0xba, 0x64, 0x72, 0xd3, + 0xf3, 0xb5, 0x0e, 0xaf, 0x8f, 0x22, 0x79, 0x2d, 0x82, 0x49, 0x96, 0xbe, 0x22, 0x0a, 0x36, 0xa5, + 0x2d, 0xf9, 0x30, 0x9b, 0x18, 0x6f, 0x8a, 0xf7, 0xdd, 0x88, 0x7b, 0xdf, 0x0b, 0x59, 0x8e, 0x05, + 0x5d, 0x07, 0x32, 0x6b, 0x66, 0x0c, 0xe6, 0x92, 0x23, 0x3d, 0x36, 0xa1, 0xb1, 0xe2, 0x93, 0xe9, + 0xef, 0xff, 0x36, 0x07, 0xc5, 0xd0, 0xe2, 0xb3, 0x64, 0xa9, 0xea, 0xa4, 0xce, 0x1d, 0x91, 0x49, + 0xe4, 0x87, 0xc9, 0x24, 0xc6, 0x06, 0x67, 0x12, 0x41, 0x25, 0xab, 0xf0, 0xec, 0x4a, 0x96, 0x91, + 0x49, 0x4c, 0x0c, 0x9f, 0x49, 0x4c, 0x1e, 0x9d, 0x49, 0xd8, 0x7f, 0x6f, 0x01, 0xea, 0x4f, 0x1b, + 0xb3, 0x2c, 0x14, 0x49, 0xfa, 0xe1, 0x21, 0x4f, 0xe9, 0x64, 0xee, 0x36, 0xd8, 0x1d, 0xdb, 0x9f, + 0x8f, 0xc3, 0xec, 0x2d, 0x67, 0xe4, 0x82, 0x03, 0x87, 0x57, 0x15, 0x52, 0x8d, 0xea, 0x18, 0xa9, + 0xc6, 0x7d, 0xc2, 0x69, 0x73, 0x5f, 0xef, 0xef, 0x35, 0xcd, 0xfa, 0x6a, 0x35, 0xbd, 0xdb, 0xd3, + 0xc1, 0x24, 0x3c, 0x08, 0x7a, 0x68, 0x25, 0xf9, 0x00, 0xa6, 0x19, 0xf7, 0x9d, 0x3a, 0x57, 0x25, + 0x0d, 0xb6, 0x58, 0x92, 0x5e, 0xee, 0x8c, 0xee, 0x3e, 0x5d, 0x33, 0x89, 0x38, 0xde, 0x37, 0xb5, + 0x52, 0x32, 0x96, 0xb9, 0x52, 0xb2, 0x0a, 0x45, 0xd2, 0x6e, 0x7b, 0x3f, 0xba, 0x47, 0x9a, 0x4c, + 0xa7, 0xaa, 0xa1, 0xd6, 0xac, 0x05, 0x04, 0x1c, 0xf5, 0x41, 0x65, 0x00, 0xa7, 0xe9, 0x7a, 0x3e, + 0x95, 0x1c, 0x05, 0xe9, 0x6e, 0x67, 0x84, 0xaf, 0xdb, 0x08, 0x5b, 0xb1, 0xd1, 0x03, 0xd5, 0xe0, + 0x8c, 0xe3, 0x32, 0x5a, 0xef, 0xf9, 0xb4, 0xb6, 0xeb, 0x74, 0xef, 0x6d, 0xd6, 0xa4, 0x97, 0xd8, + 0x97, 0xda, 0x3c, 0x59, 0x79, 0x4d, 0x0b, 0x3b, 0xb3, 0x91, 0xd6, 0x09, 0xa7, 0xf3, 0xa2, 0x8b, + 0x30, 0xe5, 0xb8, 0xf5, 0x76, 0xaf, 0x41, 0xb7, 0x08, 0x6f, 0xb1, 0xc5, 0x49, 0x39, 0x8c, 0xb9, + 0xc3, 0x83, 0x95, 0xa9, 0x0d, 0xa3, 0x1d, 0xc7, 0x7a, 0x09, 0x2e, 0xfa, 0xb1, 0xc1, 0x55, 0x8c, + 0xb8, 0x6e, 0x7c, 0x6c, 0x72, 0x99, 0xbd, 0x52, 0x6a, 0x49, 0x90, 0xa9, 0x96, 0xf4, 0x57, 0x79, + 0x28, 0xa8, 0x52, 0x2e, 0xba, 0x94, 0xa8, 0x97, 0xbe, 0xd6, 0x57, 0x2f, 0x2d, 0xa5, 0x95, 0xbd, + 0x6d, 0x28, 0x38, 0x8c, 0xf5, 0xe2, 0xa7, 0xdb, 0x86, 0x6c, 0xc1, 0x9a, 0x82, 0x1c, 0x00, 0x12, + 0x94, 0x5a, 0x83, 0xd0, 0xe5, 0x52, 0xd6, 0x8a, 0x70, 0xa2, 0x1a, 0x1c, 0x12, 0x18, 0x36, 0xc0, + 0x65, 0x85, 0xc7, 0x73, 0x77, 0x9c, 0xa6, 0xce, 0xc3, 0xaf, 0x1b, 0x51, 0x73, 0x74, 0xfb, 0xf6, + 0x51, 0x78, 0x3d, 0x17, 0x05, 0xd0, 0xb1, 0x0e, 0x22, 0x92, 0xbe, 0x53, 0xbb, 0xfb, 0xa1, 0x9a, + 0x4e, 0x55, 0x22, 0x62, 0x8d, 0x2c, 0x64, 0x78, 0x3d, 0xde, 0xed, 0x71, 0xa9, 0x93, 0xc7, 0x24, + 0xe3, 0xae, 0x44, 0xc4, 0x1a, 0xd9, 0xfe, 0xcc, 0x82, 0x59, 0xb5, 0xdc, 0xd5, 0x16, 0xad, 0xef, + 0xd6, 0x38, 0xed, 0x8a, 0xc0, 0xb6, 0xc7, 0x28, 0x4b, 0x06, 0xb6, 0xf7, 0x19, 0x65, 0x58, 0x52, + 0x8c, 0xd9, 0xe7, 0x4e, 0x6a, 0xf6, 0xf6, 0x3f, 0x5a, 0x30, 0x2e, 0x23, 0xc8, 0x2c, 0xae, 0x2e, + 0x5e, 0x55, 0xc9, 0x0d, 0x55, 0x55, 0x39, 0xa2, 0xde, 0x15, 0x15, 0x74, 0xc6, 0x9e, 0x55, 0xd0, + 0xb1, 0xbf, 0xb1, 0x60, 0x21, 0xad, 0x48, 0x98, 0x65, 0xf8, 0xef, 0xc2, 0x64, 0xb7, 0x4d, 0xf8, + 0x8e, 0xe7, 0x77, 0x92, 0xb7, 0x01, 0x5b, 0xba, 0x1d, 0x87, 0x3d, 0x90, 0x0f, 0xe0, 0x07, 0xd9, + 0x48, 0xa0, 0xee, 0xd7, 0xb3, 0x1e, 0x3e, 0xf1, 0xea, 0x56, 0xb4, 0x58, 0x61, 0x13, 0xc3, 0x86, + 0x14, 0xfb, 0xcf, 0xc6, 0x61, 0x5e, 0xb2, 0x8c, 0x7a, 0x18, 0x8d, 0xb2, 0x43, 0x5d, 0x78, 0x45, + 0xe6, 0x10, 0xfd, 0xe7, 0x97, 0xda, 0xb4, 0x2b, 0x9a, 0xff, 0x95, 0x8d, 0xd4, 0x5e, 0x4f, 0x07, + 0x52, 0xf0, 0x00, 0xdc, 0xfe, 0x43, 0x09, 0x7e, 0xfe, 0x0e, 0x25, 0x53, 0xd9, 0x26, 0x8e, 0x54, + 0xb6, 0x81, 0x47, 0xd8, 0xe4, 0x73, 0x1c, 0x61, 0xfd, 0xc7, 0x4a, 0x31, 0xd3, 0xb1, 0xf2, 0xd7, + 0x39, 0x98, 0xd8, 0xf2, 0x3d, 0x59, 0x6c, 0x3e, 0xf9, 0xba, 0xe5, 0x5d, 0x18, 0x63, 0x5d, 0x5a, + 0xd7, 0x3e, 0xef, 0xdc, 0x70, 0x96, 0xa6, 0x87, 0x57, 0xeb, 0xd2, 0x7a, 0x65, 0x52, 0xb8, 0x51, + 0xf1, 0x0b, 0x4b, 0x20, 0xa3, 0x00, 0x97, 0xcf, 0x12, 0xec, 0x07, 0x90, 0xcf, 0x2e, 0xc0, 0x7d, + 0x6e, 0x41, 0x49, 0xf7, 0x7c, 0x69, 0x2b, 0x3d, 0x7a, 0x7c, 0x03, 0x2a, 0x3d, 0x7f, 0x1e, 0xcd, + 0x40, 0x2c, 0x1a, 0xfa, 0x7d, 0x98, 0xef, 0xfa, 0x5e, 0xc7, 0x13, 0x96, 0xba, 0xe5, 0xb5, 0x9d, + 0xba, 0x43, 0x83, 0x62, 0xe1, 0xa5, 0xa1, 0xe5, 0x19, 0xec, 0xfb, 0x95, 0xef, 0x68, 0xb9, 0xf3, + 0x5b, 0x49, 0x5c, 0xdc, 0x2f, 0xca, 0xfe, 0x2f, 0x0b, 0xa6, 0x63, 0x6b, 0x8f, 0xea, 0x00, 0x75, + 0xcf, 0x6d, 0x38, 0x3c, 0xbc, 0x90, 0x2d, 0x9d, 0x5f, 0x1d, 0x6e, 0x55, 0xab, 0x01, 0x5f, 0xa4, + 0x74, 0x61, 0x13, 0xc3, 0x06, 0x2c, 0xba, 0x10, 0xbc, 0x5f, 0x88, 0xc7, 0x4b, 0xea, 0xfd, 0xc2, + 0xd3, 0x83, 0x95, 0x29, 0x3d, 0x26, 0xf3, 0x3d, 0x43, 0x96, 0x57, 0x02, 0xff, 0x90, 0x83, 0x62, + 0x38, 0xff, 0x17, 0x60, 0x46, 0xf7, 0x63, 0x66, 0x74, 0x21, 0xe3, 0xce, 0x49, 0x43, 0x0a, 0x63, + 0x12, 0xc3, 0x98, 0x9e, 0x24, 0x8c, 0x29, 0xab, 0x4a, 0x1c, 0x61, 0x4e, 0xff, 0xa2, 0x36, 0x5f, + 0xf5, 0x7d, 0x01, 0x06, 0x75, 0x2f, 0x6e, 0x50, 0xab, 0x19, 0x67, 0x33, 0xc0, 0xa4, 0x3e, 0xb1, + 0x60, 0x36, 0x61, 0x04, 0xe8, 0x75, 0x18, 0x97, 0xd5, 0x21, 0xad, 0x5f, 0x21, 0xa3, 0xae, 0x25, + 0x48, 0x1a, 0xda, 0x82, 0x05, 0xd2, 0xe3, 0x5e, 0xc8, 0x7b, 0xc3, 0x25, 0xdb, 0x6d, 0xaa, 0x0a, + 0x04, 0x93, 0x95, 0x5f, 0xd0, 0x3c, 0x0b, 0x6b, 0x29, 0x7d, 0x70, 0x2a, 0xa7, 0xfd, 0xd3, 0x1c, + 0xa0, 0xb0, 0x31, 0x4b, 0x55, 0xf5, 0x09, 0x4c, 0xec, 0xa8, 0xfa, 0xcf, 0xf3, 0x95, 0xc5, 0x2b, + 0x25, 0xf3, 0x66, 0x20, 0xc0, 0x44, 0xbf, 0x79, 0x3c, 0x7a, 0x04, 0xfd, 0x3a, 0x84, 0x1e, 0x01, + 0xec, 0x38, 0xae, 0xc3, 0x5a, 0x23, 0x5e, 0xe0, 0xc9, 0xd3, 0xfc, 0x66, 0x88, 0x80, 0x0d, 0x34, + 0xfb, 0x3a, 0xcc, 0x18, 0xab, 0xc9, 0xfd, 0x7d, 0x71, 0xbe, 0x13, 0xce, 0x69, 0xa7, 0xcb, 0x55, + 0x28, 0x9f, 0x8f, 0xf4, 0x6d, 0x4d, 0xb7, 0xe3, 0xb0, 0x87, 0xfd, 0x69, 0xce, 0xd0, 0x6f, 0xe9, + 0x6e, 0x87, 0xd2, 0x8b, 0xb7, 0xe3, 0x9b, 0x51, 0xec, 0xbf, 0x72, 0x31, 0x16, 0x76, 0x6c, 0x8f, + 0xf8, 0x41, 0xf5, 0xf7, 0x72, 0xc6, 0x65, 0x7d, 0x40, 0x7c, 0x47, 0x28, 0x4e, 0xa4, 0x12, 0x0f, + 0x88, 0xcf, 0xb0, 0x84, 0x44, 0xdf, 0x17, 0x43, 0xa5, 0x61, 0xce, 0x97, 0xd9, 0xa7, 0x70, 0xda, + 0x35, 0xe7, 0x47, 0xbb, 0x0c, 0x2b, 0x40, 0xfb, 0xdf, 0x0a, 0x86, 0xc1, 0x68, 0xaf, 0x7f, 0x07, + 0x50, 0x9b, 0x30, 0x7e, 0x9b, 0xb8, 0x0d, 0xa1, 0xde, 0x74, 0xc7, 0xa7, 0xac, 0xa5, 0x23, 0xbc, + 0x25, 0x8d, 0x82, 0x36, 0xfb, 0x7a, 0xe0, 0x14, 0x2e, 0x74, 0x29, 0xee, 0xdc, 0x57, 0x92, 0xce, + 0x3d, 0xda, 0xd4, 0x11, 0xdd, 0xbb, 0x69, 0x2e, 0xe3, 0x27, 0x60, 0x2e, 0xbf, 0x07, 0xf3, 0x3b, + 0xc9, 0x2b, 0x38, 0x7d, 0x21, 0x7f, 0x79, 0xc4, 0x1b, 0xbc, 0xca, 0x99, 0xc3, 0xe8, 0xde, 0x26, + 0x6a, 0xc6, 0xfd, 0x82, 0x90, 0x17, 0x3c, 0x3d, 0x93, 0xd9, 0xab, 0xaa, 0x81, 0x0c, 0x6d, 0xb2, + 0x89, 0xbc, 0x37, 0xf9, 0xe8, 0x4c, 0x41, 0xe2, 0x98, 0x80, 0x84, 0x09, 0x17, 0x8e, 0xd3, 0x84, + 0xd1, 0x25, 0x28, 0xd5, 0x7b, 0xbe, 0x4f, 0x5d, 0x2e, 0x86, 0x23, 0x43, 0xe1, 0x7c, 0x54, 0xcb, + 0xae, 0x46, 0x24, 0x6c, 0xf6, 0x13, 0xea, 0x68, 0xfc, 0xa9, 0x4d, 0x5b, 0x56, 0xd1, 0xf2, 0x91, + 0x3a, 0x56, 0xfb, 0x7a, 0xe0, 0x14, 0x2e, 0xf4, 0x91, 0xb4, 0x79, 0x4e, 0x65, 0xbe, 0xf3, 0xfc, + 0x79, 0x7d, 0x51, 0xfb, 0x0b, 0xae, 0xfc, 0x05, 0xa7, 0xf6, 0x27, 0x31, 0x37, 0x33, 0x5c, 0xb5, + 0x61, 0x09, 0x72, 0x84, 0x25, 0x4b, 0xd1, 0x6b, 0x0c, 0xe7, 0x08, 0x43, 0xf7, 0x61, 0xdc, 0x17, + 0xde, 0x4e, 0x7b, 0xd3, 0x8b, 0x19, 0x2d, 0x5f, 0x7a, 0x4a, 0x35, 0x4c, 0xf9, 0x13, 0x2b, 0x34, + 0xa3, 0xc0, 0x91, 0x3f, 0xb1, 0x02, 0x87, 0x0f, 0x51, 0xd8, 0x19, 0xbc, 0x39, 0x45, 0x4f, 0x74, + 0x70, 0x64, 0x65, 0x79, 0x43, 0xd9, 0x07, 0x33, 0x28, 0x48, 0xb2, 0x7f, 0x6a, 0xc1, 0x99, 0xd4, + 0xde, 0xa1, 0x77, 0xce, 0x9d, 0xa0, 0x77, 0xb6, 0x8e, 0xdb, 0x3b, 0x3f, 0x32, 0x96, 0x30, 0x18, + 0xc2, 0x71, 0x3d, 0x14, 0xff, 0x49, 0x0e, 0xe6, 0x30, 0xed, 0x7a, 0xb1, 0x42, 0xc7, 0x56, 0xf0, + 0x2a, 0x2d, 0x43, 0x64, 0x90, 0xa8, 0xdc, 0x57, 0x26, 0x62, 0xcf, 0xd1, 0xbe, 0x0f, 0xe3, 0xb2, + 0x06, 0xa1, 0x63, 0x99, 0xcb, 0x19, 0x6e, 0x5a, 0x63, 0xa8, 0x52, 0x87, 0x55, 0x31, 0x47, 0x01, + 0x0a, 0x64, 0x79, 0x49, 0xaa, 0x55, 0xf8, 0x72, 0x86, 0xeb, 0xd6, 0x7e, 0x64, 0xd9, 0x8c, 0x15, + 0xa0, 0xfd, 0x59, 0x0e, 0x54, 0x14, 0xf0, 0x02, 0xb2, 0x85, 0xdf, 0x88, 0x65, 0x0b, 0x43, 0x86, + 0xc1, 0x72, 0x70, 0x03, 0x33, 0x85, 0x64, 0x84, 0x77, 0x2e, 0x0b, 0xe8, 0xb3, 0xb3, 0x84, 0x7f, + 0xb6, 0xa0, 0x28, 0xfb, 0xbd, 0x80, 0x0c, 0x61, 0x2b, 0x9e, 0x21, 0xbc, 0x93, 0x61, 0x16, 0x03, + 0xb2, 0x83, 0x4f, 0xf3, 0x7a, 0xf4, 0x61, 0xfc, 0xd7, 0x22, 0x7e, 0x43, 0x47, 0x36, 0x91, 0x05, + 0x8a, 0x46, 0xac, 0x68, 0xe8, 0x77, 0x60, 0xce, 0x57, 0xf7, 0xee, 0xb4, 0x71, 0x33, 0x0c, 0x33, + 0xf2, 0x99, 0x2f, 0xc6, 0xf5, 0xe5, 0x7d, 0x54, 0x21, 0xc3, 0x09, 0x54, 0xdc, 0x27, 0x47, 0x84, + 0x1e, 0xdd, 0xa4, 0x2f, 0xd3, 0x47, 0xf2, 0xe5, 0x11, 0x1d, 0xa7, 0x0a, 0x3d, 0xfa, 0x9a, 0x71, + 0xbf, 0x20, 0xd4, 0x82, 0x29, 0xf3, 0x49, 0x8f, 0xd6, 0xa5, 0xf3, 0xd9, 0xdf, 0x0e, 0xa9, 0xcb, + 0x17, 0xb3, 0x05, 0xc7, 0x90, 0xed, 0x83, 0x02, 0x94, 0x0c, 0xe5, 0x4b, 0x54, 0x1d, 0xa6, 0x4f, + 0xa6, 0xea, 0x90, 0x1e, 0xe4, 0x96, 0x46, 0x0a, 0x72, 0xcf, 0xc5, 0x83, 0xdc, 0xef, 0x26, 0x83, + 0x5c, 0x90, 0xb3, 0x8b, 0x05, 0xb8, 0x0c, 0x66, 0x74, 0xb4, 0x17, 0xbc, 0xcd, 0xca, 0x94, 0x36, + 0xf4, 0xc7, 0x94, 0xe8, 0xf0, 0x60, 0x25, 0x78, 0x59, 0x11, 0xbc, 0xc9, 0x4a, 0x88, 0x40, 0xd7, + 0x43, 0xa1, 0xb5, 0x5e, 0xa7, 0x43, 0xfc, 0xfd, 0xc5, 0x29, 0x39, 0xe0, 0xb0, 0x1c, 0x79, 0x33, + 0x46, 0xc5, 0x89, 0xde, 0x68, 0x0b, 0x0a, 0x2a, 0x58, 0xd4, 0xef, 0x7d, 0xde, 0xcd, 0x12, 0x87, + 0xaa, 0x18, 0x41, 0xfd, 0xc6, 0x1a, 0xc7, 0x8c, 0xf3, 0x8b, 0x47, 0xc4, 0xf9, 0x77, 0x00, 0x79, + 0xdb, 0x32, 0x1a, 0x69, 0xdc, 0x52, 0x5f, 0x54, 0x09, 0xad, 0x2c, 0xc4, 0xc3, 0xc0, 0xbb, 0x7d, + 0x3d, 0x70, 0x0a, 0x97, 0xb0, 0x6a, 0x1d, 0x1c, 0x86, 0xa6, 0xa0, 0x63, 0xfa, 0x2b, 0x99, 0x03, + 0xac, 0x20, 0x7d, 0x58, 0x10, 0x56, 0x5d, 0x4d, 0xa0, 0xe2, 0x3e, 0x39, 0xe8, 0x87, 0x30, 0x2d, + 0x54, 0x28, 0x12, 0x0c, 0xcf, 0x29, 0x78, 0xfe, 0xf0, 0x60, 0x65, 0x7a, 0xd3, 0x84, 0xc4, 0x71, + 0x09, 0xf6, 0xff, 0xe5, 0x20, 0x66, 0x7f, 0xe8, 0x13, 0x0b, 0xe6, 0x49, 0xe2, 0x73, 0xa0, 0x20, + 0x7c, 0xf9, 0xb5, 0x6c, 0xdf, 0x68, 0xf5, 0x7d, 0x4d, 0x14, 0x15, 0x1d, 0x93, 0x5d, 0x18, 0xee, + 0x17, 0x8a, 0xfe, 0xc4, 0x82, 0xd3, 0xa4, 0xff, 0x7b, 0x2f, 0x7d, 0x1e, 0x5e, 0x1d, 0xf9, 0x83, + 0xb1, 0xca, 0xab, 0x87, 0x07, 0x2b, 0x69, 0x5f, 0xc2, 0xe1, 0x34, 0x71, 0xe8, 0x07, 0x30, 0x46, + 0xfc, 0x66, 0x90, 0x60, 0x67, 0x17, 0x1b, 0x7c, 0xc6, 0x17, 0x1d, 0xc8, 0x6b, 0x7e, 0x93, 0x61, + 0x09, 0x6a, 0xff, 0x2c, 0x0f, 0x73, 0xc9, 0xd7, 0x94, 0xfa, 0x01, 0xca, 0x58, 0xea, 0x03, 0x94, + 0xd7, 0x61, 0x9c, 0xd4, 0x79, 0xf8, 0x1a, 0x24, 0x7a, 0x41, 0x2c, 0x1a, 0xb1, 0xa2, 0xa1, 0x87, + 0x50, 0x64, 0x9c, 0xf8, 0x5c, 0xe4, 0x5d, 0x3a, 0xf5, 0xcd, 0xfc, 0x5a, 0xba, 0x16, 0x00, 0xe0, + 0x08, 0x0b, 0x5d, 0x89, 0xbb, 0x33, 0x3b, 0xe9, 0xce, 0xe6, 0xcd, 0xb9, 0x8c, 0x9a, 0xb6, 0x77, + 0xa0, 0x64, 0xec, 0x83, 0x3e, 0x5d, 0xae, 0x65, 0x5e, 0xf7, 0x48, 0xed, 0x66, 0xd5, 0xb7, 0x80, + 0x11, 0xc5, 0xc4, 0x8f, 0xf2, 0x5a, 0xb9, 0x5a, 0xcf, 0x95, 0xd7, 0xca, 0xe5, 0x32, 0xd0, 0xec, + 0x59, 0x98, 0x8e, 0x3d, 0x8a, 0x92, 0x15, 0xe7, 0x87, 0xc4, 0xa7, 0x2d, 0xaf, 0xc7, 0xe8, 0xcb, + 0x5a, 0x71, 0x0e, 0x07, 0x78, 0xdc, 0x15, 0xe7, 0x08, 0xf8, 0xe8, 0x8a, 0x73, 0xd8, 0xf7, 0xa5, + 0xad, 0x38, 0x87, 0x23, 0x1c, 0x10, 0x53, 0xfe, 0x6f, 0xce, 0x98, 0x45, 0x3c, 0xae, 0xcc, 0x3d, + 0x23, 0xae, 0x7c, 0x0c, 0x93, 0x8e, 0xcb, 0xa9, 0xbf, 0x47, 0xda, 0x3a, 0xb5, 0x1f, 0x72, 0xaa, + 0xeb, 0x3d, 0x5f, 0x47, 0x55, 0xc1, 0x54, 0x37, 0x34, 0x0e, 0x0e, 0x11, 0x51, 0x1b, 0xce, 0x04, + 0xb5, 0x24, 0x9f, 0x92, 0xa8, 0x16, 0xae, 0xef, 0x93, 0xdf, 0x0f, 0x2e, 0x33, 0x6f, 0xa6, 0x75, + 0x7a, 0x3a, 0x88, 0x80, 0xd3, 0x41, 0x11, 0x83, 0x69, 0x66, 0x24, 0x54, 0xc1, 0x41, 0x32, 0x64, + 0x1d, 0x2e, 0x99, 0x83, 0x1a, 0x97, 0xd0, 0x26, 0x28, 0x8e, 0xcb, 0xb0, 0xff, 0x23, 0x0f, 0xb3, + 0x09, 0x4d, 0x4b, 0x04, 0x8e, 0xc5, 0x17, 0x19, 0x38, 0x16, 0x46, 0x0a, 0x1c, 0xd3, 0x63, 0x9a, + 0xb1, 0x91, 0x62, 0x9a, 0x0f, 0x54, 0x5c, 0xa1, 0x77, 0x6e, 0x63, 0x5d, 0x3f, 0x0f, 0x0c, 0x57, + 0x73, 0xd3, 0x24, 0xe2, 0x78, 0x5f, 0x79, 0x0a, 0x37, 0xfa, 0xbf, 0x85, 0xd3, 0x41, 0xd1, 0xd5, + 0xac, 0x8f, 0x2e, 0x42, 0x00, 0x75, 0x0a, 0xa7, 0x10, 0x70, 0x9a, 0xb8, 0xca, 0x9d, 0x2f, 0xbe, + 0x5e, 0x3e, 0xf5, 0xe5, 0xd7, 0xcb, 0xa7, 0xbe, 0xfa, 0x7a, 0xf9, 0xd4, 0x8f, 0x0f, 0x97, 0xad, + 0x2f, 0x0e, 0x97, 0xad, 0x2f, 0x0f, 0x97, 0xad, 0xaf, 0x0e, 0x97, 0xad, 0xff, 0x3e, 0x5c, 0xb6, + 0xfe, 0xf2, 0x9b, 0xe5, 0x53, 0x8f, 0xde, 0x18, 0xe6, 0x9f, 0x16, 0xfc, 0x7f, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xc5, 0xa4, 0xb7, 0x24, 0xdb, 0x40, 0x00, 0x00, } func (m *AnalysisRunArgument) Marshal() (dAtA []byte, err error) { @@ -4033,6 +4034,9 @@ func (m *PromotionStatus) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + i = encodeVarintGenerated(dAtA, i, uint64(m.CurrentStepAttempt)) + i-- + dAtA[i] = 0x58 if m.State != nil { { size, err := m.State.MarshalToSizedBuffer(dAtA[:i]) @@ -5842,6 +5846,7 @@ func (m *PromotionStatus) Size() (n int) { l = m.State.Size() n += 1 + l + sovGenerated(uint64(l)) } + n += 1 + sovGenerated(uint64(m.CurrentStepAttempt)) return n } @@ -6832,6 +6837,7 @@ func (this *PromotionStatus) String() string { `HealthChecks:` + repeatedStringForHealthChecks + `,`, `CurrentStep:` + fmt.Sprintf("%v", this.CurrentStep) + `,`, `State:` + strings.Replace(fmt.Sprintf("%v", this.State), "JSON", "v11.JSON", 1) + `,`, + `CurrentStepAttempt:` + fmt.Sprintf("%v", this.CurrentStepAttempt) + `,`, `}`, }, "") return s @@ -14254,6 +14260,25 @@ func (m *PromotionStatus) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field CurrentStepAttempt", wireType) + } + m.CurrentStepAttempt = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.CurrentStepAttempt |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/api/v1alpha1/generated.proto b/api/v1alpha1/generated.proto index 1250e062e..711211022 100644 --- a/api/v1alpha1/generated.proto +++ b/api/v1alpha1/generated.proto @@ -913,6 +913,10 @@ message PromotionStatus { // subsequent reconciliations attempts. optional int64 currentStep = 9; + // CurrentStepAttempt is the number of times the current step has been + // attempted. + optional int64 currentStepAttempt = 11; + // State stores the state of the promotion process between reconciliation // attempts. optional .k8s.io.apiextensions_apiserver.pkg.apis.apiextensions.v1.JSON state = 10; diff --git a/api/v1alpha1/promotion_types.go b/api/v1alpha1/promotion_types.go index 5fe50566c..8debee21f 100644 --- a/api/v1alpha1/promotion_types.go +++ b/api/v1alpha1/promotion_types.go @@ -177,6 +177,9 @@ type PromotionStatus struct { // permits steps that have already run successfully to be skipped on // subsequent reconciliations attempts. CurrentStep int64 `json:"currentStep,omitempty" protobuf:"varint,9,opt,name=currentStep"` + // CurrentStepAttempt is the number of times the current step has been + // attempted. + CurrentStepAttempt int64 `json:"currentStepAttempt,omitempty" protobuf:"varint,11,opt,name=currentStepAttempt"` // State stores the state of the promotion process between reconciliation // attempts. State *apiextensionsv1.JSON `json:"state,omitempty" protobuf:"bytes,10,opt,name=state"` diff --git a/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml b/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml index 97a67bcf9..124e00677 100644 --- a/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml +++ b/charts/kargo/resources/crds/kargo.akuity.io_promotions.yaml @@ -161,6 +161,12 @@ spec: subsequent reconciliations attempts. format: int64 type: integer + currentStepAttempt: + description: |- + CurrentStepAttempt is the number of times the current step has been + attempted. + format: int64 + type: integer finishedAt: description: FinishedAt is the time when the promotion was completed. format: date-time diff --git a/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml b/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml index 43da6c6f5..c2d17a876 100644 --- a/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml +++ b/charts/kargo/resources/crds/kargo.akuity.io_stages.yaml @@ -485,6 +485,12 @@ spec: subsequent reconciliations attempts. format: int64 type: integer + currentStepAttempt: + description: |- + CurrentStepAttempt is the number of times the current step has been + attempted. + format: int64 + type: integer finishedAt: description: FinishedAt is the time when the promotion was completed. @@ -1306,6 +1312,12 @@ spec: subsequent reconciliations attempts. format: int64 type: integer + currentStepAttempt: + description: |- + CurrentStepAttempt is the number of times the current step has been + attempted. + format: int64 + type: integer finishedAt: description: FinishedAt is the time when the promotion was completed. diff --git a/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json b/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json index ccbc05e88..afd56da14 100644 --- a/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json +++ b/ui/src/gen/schema/promotions.kargo.akuity.io_v1alpha1.json @@ -107,6 +107,13 @@ "minimum": -9223372036854776000, "type": "integer" }, + "currentStepAttempt": { + "description": "CurrentStepAttempt is the number of times the current step has been\nattempted.", + "format": "int64", + "maximum": 9223372036854776000, + "minimum": -9223372036854776000, + "type": "integer" + }, "finishedAt": { "description": "FinishedAt is the time when the promotion was completed.", "format": "date-time", diff --git a/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json b/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json index a1b0c2611..40a55c066 100644 --- a/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json +++ b/ui/src/gen/schema/stages.kargo.akuity.io_v1alpha1.json @@ -425,6 +425,13 @@ "minimum": -9223372036854776000, "type": "integer" }, + "currentStepAttempt": { + "description": "CurrentStepAttempt is the number of times the current step has been\nattempted.", + "format": "int64", + "maximum": 9223372036854776000, + "minimum": -9223372036854776000, + "type": "integer" + }, "finishedAt": { "description": "FinishedAt is the time when the promotion was completed.", "format": "date-time", @@ -1214,6 +1221,13 @@ "minimum": -9223372036854776000, "type": "integer" }, + "currentStepAttempt": { + "description": "CurrentStepAttempt is the number of times the current step has been\nattempted.", + "format": "int64", + "maximum": 9223372036854776000, + "minimum": -9223372036854776000, + "type": "integer" + }, "finishedAt": { "description": "FinishedAt is the time when the promotion was completed.", "format": "date-time", diff --git a/ui/src/gen/v1alpha1/generated_pb.ts b/ui/src/gen/v1alpha1/generated_pb.ts index 99f9ff553..ad35db92b 100644 --- a/ui/src/gen/v1alpha1/generated_pb.ts +++ b/ui/src/gen/v1alpha1/generated_pb.ts @@ -2815,6 +2815,14 @@ export class PromotionStatus extends Message { */ currentStep?: bigint; + /** + * CurrentStepAttempt is the number of times the current step has been + * attempted. + * + * @generated from field: optional int64 currentStepAttempt = 11; + */ + currentStepAttempt?: bigint; + /** * State stores the state of the promotion process between reconciliation * attempts. @@ -2839,6 +2847,7 @@ export class PromotionStatus extends Message { { no: 8, name: "healthChecks", kind: "message", T: HealthCheckStep, repeated: true }, { no: 6, name: "finishedAt", kind: "message", T: Time, opt: true }, { no: 9, name: "currentStep", kind: "scalar", T: 3 /* ScalarType.INT64 */, opt: true }, + { no: 11, name: "currentStepAttempt", kind: "scalar", T: 3 /* ScalarType.INT64 */, opt: true }, { no: 10, name: "state", kind: "message", T: JSON, opt: true }, ]); From f8c4a5b993b77aa5d9e1cdecaa3bfd69c0a7a535 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Thu, 21 Nov 2024 14:56:45 +0100 Subject: [PATCH 7/8] refactor: move attempts tracking out of state Signed-off-by: Hidde Beydals --- internal/controller/promotions/promotions.go | 3 + internal/directives/promotions.go | 51 +---- internal/directives/promotions_test.go | 146 ------------- internal/directives/simple_engine_promote.go | 112 +++++----- .../directives/simple_engine_promote_test.go | 195 +++++++----------- 5 files changed, 142 insertions(+), 365 deletions(-) diff --git a/internal/controller/promotions/promotions.go b/internal/controller/promotions/promotions.go index fab588b82..4b89815c0 100644 --- a/internal/controller/promotions/promotions.go +++ b/internal/controller/promotions/promotions.go @@ -482,6 +482,7 @@ func (r *reconciler) promote( FreightRequests: stage.Spec.RequestedFreight, Freight: *workingPromo.Status.FreightCollection.DeepCopy(), StartFromStep: promo.Status.CurrentStep, + Attempts: promo.Status.CurrentStepAttempt, State: directives.State(workingPromo.Status.GetState()), Vars: workingPromo.Spec.Vars, } @@ -491,6 +492,7 @@ func (r *reconciler) promote( // allows individual steps to self-discover that they've run before and // examine the results of their own previous execution. promoCtx.StartFromStep = 0 + promoCtx.Attempts = 0 } else if !os.IsExist(err) { return nil, fmt.Errorf("error creating working directory: %w", err) } @@ -506,6 +508,7 @@ func (r *reconciler) promote( workingPromo.Status.Phase = res.Status workingPromo.Status.Message = res.Message workingPromo.Status.CurrentStep = res.CurrentStep + workingPromo.Status.CurrentStepAttempt = res.Attempt workingPromo.Status.State = &apiextensionsv1.JSON{Raw: res.State.ToJSON()} if res.Status == kargoapi.PromotionPhaseSucceeded { var healthChecks []kargoapi.HealthCheckStep diff --git a/internal/directives/promotions.go b/internal/directives/promotions.go index 2b59d4ec8..bf25c84a7 100644 --- a/internal/directives/promotions.go +++ b/internal/directives/promotions.go @@ -35,10 +35,6 @@ type RetryableStepRunner interface { DefaultAttempts() int64 } -// stateKeyAttempts is the key used to store the number of attempts that -// have been made to execute a step in the shared State. -const stateKeyAttempts = "attempts" - // PromotionContext is the context of a user-defined promotion process that is // executed by the Engine. type PromotionContext struct { @@ -66,11 +62,12 @@ type PromotionContext struct { // any Freight that has been inherited from the target Stage's current // state. Freight kargoapi.FreightCollection - // Retry is the retry configuration for the Promotion. - Retry *kargoapi.PromotionRetry - // SharedState is the index of the step from which the promotion should begin - // execution. + // StartFromStep is the index of the step from which the promotion should + // begin execution. StartFromStep int64 + // Attempts is the number of attempts that have been made to execute + // the current step. + Attempts int64 // State is the current state of the promotion process. State State // Vars is a list of variables definitions that can be used by the @@ -99,29 +96,6 @@ type PromotionStep struct { Config []byte } -// GetAttempts returns the number of attempts that have been made to execute -// the step using the provided State. If no attempts have been made, 0 is -// returned. -func (s *PromotionStep) GetAttempts(state State) int64 { - if stepV, ok := state.Get(s.Alias); ok { - if stepState, ok := stepV.(map[string]any); ok { - if attemptsV, ok := stepState[stateKeyAttempts]; ok { - switch attempts := attemptsV.(type) { - case int64: - return attempts - case int: - return int64(attempts) - // If the State has been rehydrated from a JSON representation, - // the attempts value may be a float64. Convert it to an int64. - case float64: - return int64(attempts) - } - } - } - } - return 0 -} - // GetMaxAttempts returns the maximum number of attempts that can be made to // execute the step using the provided runner. If the runner is a // RetryableStepRunner, the value of its retry configuration is used as the @@ -134,17 +108,6 @@ func (s *PromotionStep) GetMaxAttempts(runner any) int64 { return s.Retry.GetAttempts(fallback) } -// RecordAttempt records an attempt to execute a step in the provided -// output. -func (s *PromotionStep) RecordAttempt(state State, output map[string]any) map[string]any { - attempts := s.GetAttempts(state) - if output == nil { - output = make(map[string]any, 1) - } - output[stateKeyAttempts] = attempts + 1 - return output -} - // GetConfig returns the Config unmarshalled into a map. Any expr-lang // expressions are evaluated in the context of the provided arguments // prior to unmarshaling. @@ -248,9 +211,11 @@ type PromotionResult struct { // health check processes. HealthCheckSteps []HealthCheckStep // If the promotion process remains in-progress, perhaps waiting for a change - // in some external state, the value of this field will indicated where to + // in some external state, the value of this field will indicate where to // resume the process in the next reconciliation. CurrentStep int64 + // Attempt tracks the current execution attempt of the current step. + Attempt int64 // State is the current state of the promotion process. State State } diff --git a/internal/directives/promotions_test.go b/internal/directives/promotions_test.go index 06436be2e..a97c305c8 100644 --- a/internal/directives/promotions_test.go +++ b/internal/directives/promotions_test.go @@ -18,89 +18,6 @@ func (m mockRetryableRunner) DefaultAttempts() int64 { return m.defaultAttempts } -func TestPromotionStep_GetAttempts(t *testing.T) { - tests := []struct { - name string - step *PromotionStep - state State - assertions func(t *testing.T, result int64) - }{ - { - name: "returns 0 when state does not contain alias entry", - step: &PromotionStep{ - Alias: "step-1", - }, - state: State{}, - assertions: func(t *testing.T, result int64) { - assert.Equal(t, int64(0), result) - }, - }, - { - name: "returns 0 when state has alias entry but no attempts key", - step: &PromotionStep{ - Alias: "custom-alias", - }, - state: State{ - "custom-alias": map[string]any{ - "someOtherKey": "value", - }, - }, - assertions: func(t *testing.T, result int64) { - assert.Equal(t, int64(0), result) - }, - }, - { - name: "correctly converts float64 attempts", - step: &PromotionStep{ - Alias: "step-1", - }, - state: State{ - "step-1": map[string]any{ - stateKeyAttempts: float64(3), - }, - }, - assertions: func(t *testing.T, result int64) { - assert.Equal(t, int64(3), result) - }, - }, - { - name: "correctly handles int64 attempts", - step: &PromotionStep{ - Alias: "step-2", - }, - state: State{ - "step-2": map[string]any{ - stateKeyAttempts: int64(1), - }, - }, - assertions: func(t *testing.T, result int64) { - assert.Equal(t, int64(1), result) - }, - }, - { - name: "returns 0 when attempts value is not a number", - step: &PromotionStep{ - Alias: "invalid", - }, - state: State{ - "invalid": map[string]any{ - stateKeyAttempts: "not a number", - }, - }, - assertions: func(t *testing.T, result int64) { - assert.Equal(t, int64(0), result) - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - result := tt.step.GetAttempts(tt.state) - tt.assertions(t, result) - }) - } -} - func TestPromotionStep_GetMaxAttempts(t *testing.T) { tests := []struct { name string @@ -163,69 +80,6 @@ func TestPromotionStep_GetMaxAttempts(t *testing.T) { } } -func TestPromotionStep_RecordAttempt(t *testing.T) { - tests := []struct { - name string - step *PromotionStep - state State - output map[string]any - assertions func(*testing.T, map[string]any) - }{ - { - name: "increment attempt counter", - step: &PromotionStep{ - Alias: "foo", - }, - state: State{ - "foo": map[string]any{"attempts": 2}, - }, - assertions: func(t *testing.T, output map[string]any) { - assert.Equal(t, int64(3), output["attempts"]) - }, - }, - { - name: "initialize attempt counter", - step: &PromotionStep{ - Alias: "foo", - }, - assertions: func(t *testing.T, output map[string]any) { - assert.Equal(t, int64(1), output["attempts"]) - }, - }, - { - name: "preserve existing output", - step: &PromotionStep{ - Alias: "foo", - }, - output: map[string]any{"existing": "value"}, - assertions: func(t *testing.T, output map[string]any) { - assert.Equal(t, int64(1), output["attempts"]) - assert.Equal(t, "value", output["existing"]) - }, - }, - { - name: "overwrites attempts value modified by runner", - step: &PromotionStep{ - Alias: "foo", - }, - state: State{ - "foo": map[string]any{"attempts": 2}, - }, - output: map[string]any{"attempts": 5}, - assertions: func(t *testing.T, output map[string]any) { - assert.Equal(t, int64(3), output["attempts"]) - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - output := tt.step.RecordAttempt(tt.state, tt.output) - tt.assertions(t, output) - }) - } -} - func TestPromotionStep_GetConfig(t *testing.T) { promoCtx := PromotionContext{ Project: "fake-project", diff --git a/internal/directives/simple_engine_promote.go b/internal/directives/simple_engine_promote.go index a9aa48387..b62593653 100644 --- a/internal/directives/simple_engine_promote.go +++ b/internal/directives/simple_engine_promote.go @@ -57,6 +57,7 @@ func (e *SimpleEngine) executeSteps( var ( healthChecks []HealthCheckStep err error + attempt = promoCtx.Attempts ) // Execute each step in sequence, starting from the step index @@ -82,8 +83,57 @@ func (e *SimpleEngine) executeSteps( }, err } + // Get the PromotionStepRunner for the step. + reg, err := e.registry.GetPromotionStepRunnerRegistration(step.Kind) + if err != nil { + return PromotionResult{ + Status: kargoapi.PromotionPhaseErrored, + CurrentStep: i, + State: state, + }, err + } + + // Check if the step has exceeded the maximum number of attempts. + maxAttempts := step.GetMaxAttempts(reg.Runner) + if maxAttempts > 0 && attempt >= maxAttempts { + return PromotionResult{ + Status: kargoapi.PromotionPhaseErrored, + CurrentStep: i, + State: state, + Attempt: attempt, + }, fmt.Errorf("step %q exceeded max attempts", step.Alias) + } + + // Count the attempt we are about to make. + attempt++ + // Execute the step. - result, err := e.executeStep(ctx, promoCtx, step, workDir, state) + result, err := e.executeStep(ctx, promoCtx, step, reg, workDir, state) + + // If the step failed, and the maximum number of attempts has not been + // reached, we are still "Running" the step and will retry it. + if err != nil || result.Status == kargoapi.PromotionPhaseErrored || result.Status == kargoapi.PromotionPhaseFailed { + if maxAttempts < 0 || attempt < maxAttempts { + var message strings.Builder + _, _ = message.WriteString(fmt.Sprintf("step %q failed (attempt %d)", step.Alias, attempt)) + if result.Message != "" { + _, _ = message.WriteString(": ") + _, _ = message.WriteString(result.Message) + } + if err != nil { + _, _ = message.WriteString(": ") + _, _ = message.WriteString(err.Error()) + } + + // Update the result to indicate that the step is still running. + result.Status = kargoapi.PromotionPhaseRunning + result.Message = message.String() + + // Swallow the error if the step failed, as we are still + // retrying it. + err = nil + } + } // Update the state with the step output, regardless of the result. state[step.Alias] = result.Output @@ -95,11 +145,14 @@ func (e *SimpleEngine) executeSteps( Status: result.Status, Message: result.Message, CurrentStep: i, + Attempt: attempt, State: state, }, err } - // If the step was successful, add its health check to the list. + // If the step was successful, reset the attempts counter and add its + // health check to the list. + attempt = 0 if healthCheck := result.HealthCheckStep; healthCheck != nil { healthChecks = append(healthChecks, *healthCheck) } @@ -110,6 +163,7 @@ func (e *SimpleEngine) executeSteps( Status: kargoapi.PromotionPhaseSucceeded, HealthCheckSteps: healthChecks, CurrentStep: int64(len(steps)) - 1, + Attempt: 0, State: state, }, nil } @@ -119,63 +173,21 @@ func (e *SimpleEngine) executeStep( ctx context.Context, promoCtx PromotionContext, step PromotionStep, + reg PromotionStepRunnerRegistration, workDir string, state State, ) (PromotionStepResult, error) { - reg, err := e.registry.GetPromotionStepRunnerRegistration(step.Kind) - if err != nil { - return PromotionStepResult{ - Status: kargoapi.PromotionPhaseErrored, - }, err - } - - stepCtx, err := e.preparePromotionStepContext(ctx, promoCtx, step, workDir, state, reg) + stepCtx, err := e.preparePromotionStepContext(ctx, promoCtx, step, reg.Permissions, workDir, state) if err != nil { return PromotionStepResult{ Status: kargoapi.PromotionPhaseErrored, }, err } - // Check if the step has exceeded the maximum number of attempts. - attempts := step.GetAttempts(promoCtx.State) - maxAttempts := step.GetMaxAttempts(reg.Runner) - if maxAttempts > 0 && attempts >= maxAttempts { - return PromotionStepResult{ - Status: kargoapi.PromotionPhaseErrored, - }, fmt.Errorf("step %q exceeded max attempts", step.Alias) - } - - // Run the step and record the attempt (regardless of the result). result, err := reg.Runner.RunPromotionStep(ctx, stepCtx) - result.Output = step.RecordAttempt(state, result.Output) - if err != nil { err = fmt.Errorf("failed to run step %q: %w", step.Kind, err) } - - // If the step failed, and the maximum number of attempts has not been - // reached, we are still "Running" the step and will retry it. - if err != nil || result.Status == kargoapi.PromotionPhaseErrored || result.Status == kargoapi.PromotionPhaseFailed { - if maxAttempts < 0 || attempts+1 < maxAttempts { - result.Status = kargoapi.PromotionPhaseRunning - - var message strings.Builder - _, _ = message.WriteString(fmt.Sprintf("step %q failed (attempt %d)", step.Alias, attempts+1)) - if result.Message != "" { - _, _ = message.WriteString(": ") - _, _ = message.WriteString(result.Message) - } - if err != nil { - _, _ = message.WriteString(": ") - _, _ = message.WriteString(err.Error()) - } - result.Message = message.String() - - // Swallow the error if the step is being retried. - return result, nil - } - } - return result, err } @@ -184,9 +196,9 @@ func (e *SimpleEngine) preparePromotionStepContext( ctx context.Context, promoCtx PromotionContext, step PromotionStep, + permissions StepRunnerPermissions, workDir string, state State, - reg PromotionStepRunnerRegistration, ) (*PromotionStepContext, error) { stateCopy := state.DeepCopy() @@ -208,13 +220,13 @@ func (e *SimpleEngine) preparePromotionStepContext( Freight: promoCtx.Freight, } - if reg.Permissions.AllowCredentialsDB { + if permissions.AllowCredentialsDB { stepCtx.CredentialsDB = e.credentialsDB } - if reg.Permissions.AllowKargoClient { + if permissions.AllowKargoClient { stepCtx.KargoClient = e.kargoClient } - if reg.Permissions.AllowArgoCDClient { + if permissions.AllowArgoCDClient { stepCtx.ArgoCDClient = e.argoCDClient } diff --git a/internal/directives/simple_engine_promote_test.go b/internal/directives/simple_engine_promote_test.go index cb11053cb..d17275b6f 100644 --- a/internal/directives/simple_engine_promote_test.go +++ b/internal/directives/simple_engine_promote_test.go @@ -154,16 +154,15 @@ func TestSimpleEngine_executeSteps(t *testing.T) { assert.NoError(t, err) assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status) assert.Equal(t, int64(1), result.CurrentStep) + assert.Equal(t, int64(0), result.Attempt) // Verify state contains outputs from both steps assert.Equal(t, State{ "step1": map[string]any{ - "attempts": int64(1), - "key": "value", + "key": "value", }, "step2": map[string]any{ - "attempts": int64(1), - "key": "value", + "key": "value", }, }, result.State) }, @@ -181,12 +180,12 @@ func TestSimpleEngine_executeSteps(t *testing.T) { assert.NoError(t, err) assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status) assert.Equal(t, int64(1), result.CurrentStep) + assert.Equal(t, int64(0), result.Attempt) // Verify only second step output is in state assert.Equal(t, State{ "step2": map[string]any{ - "attempts": int64(1), - "key": "value", + "key": "value", }, }, result.State) }, @@ -201,16 +200,14 @@ func TestSimpleEngine_executeSteps(t *testing.T) { assert.ErrorContains(t, err, "something went wrong") assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) assert.Equal(t, int64(1), result.CurrentStep) + assert.Equal(t, int64(1), result.Attempt) // Verify first step output is preserved in state assert.Equal(t, State{ "step1": map[string]any{ - "attempts": int64(1), - "key": "value", - }, - "step2": map[string]any{ - "attempts": int64(1), + "key": "value", }, + "step2": map[string]any(nil), }, result.State) }, }, @@ -236,6 +233,46 @@ func TestSimpleEngine_executeSteps(t *testing.T) { assert.Equal(t, int64(0), result.CurrentStep) }, }, + { + name: "retry failed step within max attempts", + promoCtx: PromotionContext{ + Attempts: 1, + }, + steps: []PromotionStep{ + { + Kind: "error-step", + Alias: "step1", + Retry: &kargoapi.PromotionRetry{Attempts: 3}, + }, + }, + assertions: func(t *testing.T, result PromotionResult, err error) { + assert.NoError(t, err) + assert.Equal(t, kargoapi.PromotionPhaseRunning, result.Status) + assert.Equal(t, int64(0), result.CurrentStep) + assert.Equal(t, int64(2), result.Attempt) + assert.Contains(t, result.Message, "attempt 2") + }, + }, + { + name: "max attempts exceeded", + promoCtx: PromotionContext{ + Attempts: 3, + }, + steps: []PromotionStep{ + { + Kind: "error-step", + Alias: "step1", + Retry: &kargoapi.PromotionRetry{Attempts: 3}, + }, + }, + assertions: func(t *testing.T, result PromotionResult, err error) { + assert.Error(t, err) + assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) + assert.Equal(t, int64(0), result.CurrentStep) + assert.Equal(t, int64(3), result.Attempt) + assert.Contains(t, err.Error(), "exceeded max attempts") + }, + }, } for _, tt := range tests { @@ -290,136 +327,51 @@ func TestSimpleEngine_executeStep(t *testing.T) { name string promoCtx PromotionContext step PromotionStep + reg PromotionStepRunnerRegistration assertions func(*testing.T, PromotionStepResult, error) }{ { name: "successful step execution", - step: PromotionStep{Kind: "success-step"}, - assertions: func(t *testing.T, result PromotionStepResult, err error) { - assert.NoError(t, err) - assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status) - - // Verify attempts counter is added to output - assert.Equal(t, int64(1), result.Output["attempts"]) - assert.Equal(t, "test-value", result.Output["key"]) - }, - }, - { - name: "step execution with existing attempts", - promoCtx: PromotionContext{ - State: State{"test-step": map[string]any{"attempts": 0}}, + reg: PromotionStepRunnerRegistration{ + Runner: &mockPromotionStepRunner{ + name: "success-step", + runResult: PromotionStepResult{ + Status: kargoapi.PromotionPhaseSucceeded, + }, + }, }, - step: PromotionStep{Kind: "success-step", Alias: "test-step"}, assertions: func(t *testing.T, result PromotionStepResult, err error) { assert.NoError(t, err) assert.Equal(t, kargoapi.PromotionPhaseSucceeded, result.Status) - - // Verify attempts counter is incremented in output - assert.Equal(t, int64(1), result.Output["attempts"]) - assert.Equal(t, "test-value", result.Output["key"]) }, }, { name: "step execution failure", step: PromotionStep{Kind: "error-step"}, - assertions: func(t *testing.T, result PromotionStepResult, err error) { - assert.ErrorContains(t, err, "failed to run step \"error-step\"") - assert.ErrorContains(t, err, "something went wrong") - assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) - - // Verify attempts counter is still added to output even on failure - assert.Equal(t, int64(1), result.Output["attempts"]) - }, - }, - { - name: "unregistered step kind", - step: PromotionStep{Kind: "unknown"}, - assertions: func(t *testing.T, result PromotionStepResult, err error) { - assert.Error(t, err) - assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) - }, - }, - { - name: "max attempts exceeded", - step: PromotionStep{Kind: "success-step", Alias: "test"}, - promoCtx: PromotionContext{ - State: State{"test": map[string]any{"attempts": 3}}, - }, - assertions: func(t *testing.T, result PromotionStepResult, err error) { - assert.ErrorContains(t, err, "exceeded max attempts") - assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) - }, - }, - { - name: "retry within max attempts", - promoCtx: PromotionContext{ - State: State{ - "step1": map[string]any{ - "attempts": int64(1), - }, - }, - }, - step: PromotionStep{ - Kind: "error-step", - Alias: "step1", - Retry: &kargoapi.PromotionRetry{Attempts: 3}, - }, - assertions: func(t *testing.T, result PromotionStepResult, err error) { - assert.NoError(t, err) - assert.Equal(t, kargoapi.PromotionPhaseRunning, result.Status) - assert.Contains(t, result.Message, "attempt 2") - }, - }, - { - name: "unlimited retries with negative max attempts", - step: PromotionStep{ - Kind: "error-step", - Alias: "unlimited", - Retry: &kargoapi.PromotionRetry{Attempts: -1}, - }, - promoCtx: PromotionContext{ - State: State{ - "unlimited": map[string]any{ - "attempts": int64(100), + reg: PromotionStepRunnerRegistration{ + Runner: &mockPromotionStepRunner{ + name: "error-step", + runResult: PromotionStepResult{ + Status: kargoapi.PromotionPhaseErrored, }, + runErr: errors.New("something went wrong"), }, }, assertions: func(t *testing.T, result PromotionStepResult, err error) { - assert.NoError(t, err) - assert.Equal(t, kargoapi.PromotionPhaseRunning, result.Status) - assert.Contains(t, result.Message, "attempt 101") + assert.ErrorContains(t, err, "failed to run step \"error-step\"") + assert.ErrorContains(t, err, "something went wrong") + assert.Equal(t, kargoapi.PromotionPhaseErrored, result.Status) }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - testRegistry := NewStepRunnerRegistry() - testRegistry.RegisterPromotionStepRunner( - &mockPromotionStepRunner{ - name: "success-step", - runResult: PromotionStepResult{ - Status: kargoapi.PromotionPhaseSucceeded, - Output: map[string]any{"key": "test-value"}, - }, - }, - &StepRunnerPermissions{}, - ) - testRegistry.RegisterPromotionStepRunner( - &mockPromotionStepRunner{ - name: "error-step", - runResult: PromotionStepResult{Status: kargoapi.PromotionPhaseErrored}, - runErr: errors.New("something went wrong"), - }, - &StepRunnerPermissions{}, - ) - engine := &SimpleEngine{ - registry: testRegistry, kargoClient: fake.NewClientBuilder().Build(), } - result, err := engine.executeStep(context.Background(), tt.promoCtx, tt.step, t.TempDir(), make(State)) + result, err := engine.executeStep(context.Background(), tt.promoCtx, tt.step, tt.reg, t.TempDir(), make(State)) tt.assertions(t, result, err) }) } @@ -460,9 +412,7 @@ func TestSimpleEngine_preparePromotionStepContext(t *testing.T) { name: "permissions control client access", promoCtx: PromotionContext{}, step: PromotionStep{Kind: "test-step"}, - permissions: StepRunnerPermissions{ - // Nothing allowed - }, + permissions: StepRunnerPermissions{}, assertions: func(t *testing.T, ctx *PromotionStepContext, err error) { assert.NoError(t, err) assert.Nil(t, ctx.CredentialsDB) @@ -474,27 +424,20 @@ func TestSimpleEngine_preparePromotionStepContext(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - testRegistry := NewStepRunnerRegistry() - testRegistry.RegisterPromotionStepRunner( - &mockPromotionStepRunner{name: "test-step"}, - &tt.permissions, - ) - engine := &SimpleEngine{ - registry: testRegistry, + registry: NewStepRunnerRegistry(), kargoClient: fake.NewClientBuilder().Build(), argoCDClient: fake.NewClientBuilder().Build(), credentialsDB: &credentials.FakeDB{}, } - reg, _ := testRegistry.GetPromotionStepRunnerRegistration("test-step") stepCtx, err := engine.preparePromotionStepContext( context.Background(), tt.promoCtx, tt.step, + tt.permissions, t.TempDir(), make(State), - reg, ) tt.assertions(t, stepCtx, err) }) From 029aff5397b3e4d7a5badf69bc9e97042ec6e79f Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Thu, 21 Nov 2024 21:03:14 +0100 Subject: [PATCH 8/8] chore(api): rename `PromotionRetry` -> `PromotionStepRetry` Signed-off-by: Hidde Beydals --- api/v1alpha1/generated.pb.go | 760 +++++++++--------- api/v1alpha1/generated.proto | 28 +- api/v1alpha1/promotion_types.go | 8 +- api/v1alpha1/promotion_types_test.go | 6 +- api/v1alpha1/zz_generated.deepcopy.go | 32 +- internal/directives/promotions.go | 2 +- internal/directives/promotions_test.go | 6 +- .../directives/simple_engine_promote_test.go | 4 +- ui/src/gen/v1alpha1/generated_pb.ts | 102 +-- 9 files changed, 474 insertions(+), 474 deletions(-) diff --git a/api/v1alpha1/generated.pb.go b/api/v1alpha1/generated.pb.go index 5008856a7..a3c7fd4a0 100644 --- a/api/v1alpha1/generated.pb.go +++ b/api/v1alpha1/generated.pb.go @@ -1094,38 +1094,10 @@ func (m *PromotionReference) XXX_DiscardUnknown() { var xxx_messageInfo_PromotionReference proto.InternalMessageInfo -func (m *PromotionRetry) Reset() { *m = PromotionRetry{} } -func (*PromotionRetry) ProtoMessage() {} -func (*PromotionRetry) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{38} -} -func (m *PromotionRetry) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *PromotionRetry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil -} -func (m *PromotionRetry) XXX_Merge(src proto.Message) { - xxx_messageInfo_PromotionRetry.Merge(m, src) -} -func (m *PromotionRetry) XXX_Size() int { - return m.Size() -} -func (m *PromotionRetry) XXX_DiscardUnknown() { - xxx_messageInfo_PromotionRetry.DiscardUnknown(m) -} - -var xxx_messageInfo_PromotionRetry proto.InternalMessageInfo - func (m *PromotionSpec) Reset() { *m = PromotionSpec{} } func (*PromotionSpec) ProtoMessage() {} func (*PromotionSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{39} + return fileDescriptor_e26b7f7bbc391025, []int{38} } func (m *PromotionSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1153,7 +1125,7 @@ var xxx_messageInfo_PromotionSpec proto.InternalMessageInfo func (m *PromotionStatus) Reset() { *m = PromotionStatus{} } func (*PromotionStatus) ProtoMessage() {} func (*PromotionStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{40} + return fileDescriptor_e26b7f7bbc391025, []int{39} } func (m *PromotionStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1181,7 +1153,7 @@ var xxx_messageInfo_PromotionStatus proto.InternalMessageInfo func (m *PromotionStep) Reset() { *m = PromotionStep{} } func (*PromotionStep) ProtoMessage() {} func (*PromotionStep) Descriptor() ([]byte, []int) { - return fileDescriptor_e26b7f7bbc391025, []int{41} + return fileDescriptor_e26b7f7bbc391025, []int{40} } func (m *PromotionStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1206,6 +1178,34 @@ func (m *PromotionStep) XXX_DiscardUnknown() { var xxx_messageInfo_PromotionStep proto.InternalMessageInfo +func (m *PromotionStepRetry) Reset() { *m = PromotionStepRetry{} } +func (*PromotionStepRetry) ProtoMessage() {} +func (*PromotionStepRetry) Descriptor() ([]byte, []int) { + return fileDescriptor_e26b7f7bbc391025, []int{41} +} +func (m *PromotionStepRetry) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PromotionStepRetry) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *PromotionStepRetry) XXX_Merge(src proto.Message) { + xxx_messageInfo_PromotionStepRetry.Merge(m, src) +} +func (m *PromotionStepRetry) XXX_Size() int { + return m.Size() +} +func (m *PromotionStepRetry) XXX_DiscardUnknown() { + xxx_messageInfo_PromotionStepRetry.DiscardUnknown(m) +} + +var xxx_messageInfo_PromotionStepRetry proto.InternalMessageInfo + func (m *PromotionTemplate) Reset() { *m = PromotionTemplate{} } func (*PromotionTemplate) ProtoMessage() {} func (*PromotionTemplate) Descriptor() ([]byte, []int) { @@ -1670,10 +1670,10 @@ func init() { proto.RegisterType((*PromotionList)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionList") proto.RegisterType((*PromotionPolicy)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionPolicy") proto.RegisterType((*PromotionReference)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionReference") - proto.RegisterType((*PromotionRetry)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionRetry") proto.RegisterType((*PromotionSpec)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionSpec") proto.RegisterType((*PromotionStatus)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionStatus") proto.RegisterType((*PromotionStep)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionStep") + proto.RegisterType((*PromotionStepRetry)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionStepRetry") proto.RegisterType((*PromotionTemplate)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionTemplate") proto.RegisterType((*PromotionTemplateSpec)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionTemplateSpec") proto.RegisterType((*PromotionVariable)(nil), "github.com.akuity.kargo.api.v1alpha1.PromotionVariable") @@ -1696,237 +1696,237 @@ func init() { } var fileDescriptor_e26b7f7bbc391025 = []byte{ - // 3674 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x5c, 0xcd, 0x6f, 0x23, 0x47, - 0x76, 0x9f, 0x26, 0x25, 0x4a, 0x7c, 0xd4, 0x67, 0x8d, 0xc6, 0xd6, 0x6a, 0x63, 0x69, 0xd2, 0x36, - 0x0c, 0x3b, 0xb6, 0xa9, 0xcc, 0x97, 0xe7, 0xc3, 0xc9, 0x04, 0x22, 0x35, 0x1f, 0x9a, 0x68, 0x3d, - 0x4a, 0x71, 0x3e, 0x36, 0xb3, 0x33, 0x70, 0x4a, 0x64, 0x89, 0xec, 0x88, 0xec, 0xe6, 0x76, 0x15, - 0xb5, 0x56, 0x12, 0x24, 0x9b, 0x2f, 0xc0, 0x40, 0x90, 0x20, 0x07, 0x23, 0xde, 0x00, 0x09, 0x10, - 0x24, 0xe7, 0xe4, 0x1f, 0xc8, 0xc1, 0x87, 0x5c, 0x8c, 0x60, 0x13, 0x18, 0x49, 0x0e, 0x3e, 0x2c, - 0x84, 0x58, 0x06, 0x72, 0xf4, 0x2d, 0x97, 0x01, 0x02, 0x04, 0xf5, 0xd1, 0xdd, 0xd5, 0xcd, 0xe6, - 0x88, 0xcd, 0x91, 0x06, 0x83, 0xbd, 0x51, 0xf5, 0xea, 0xfd, 0x5e, 0x7d, 0xbc, 0xf7, 0xea, 0xbd, - 0x57, 0xd5, 0x82, 0x8b, 0x4d, 0x87, 0xb7, 0x7a, 0xdb, 0xe5, 0xba, 0xd7, 0x59, 0x25, 0xbb, 0x3d, - 0x87, 0xef, 0xaf, 0xee, 0x12, 0xbf, 0xe9, 0xad, 0x92, 0xae, 0xb3, 0xba, 0x77, 0x8e, 0xb4, 0xbb, - 0x2d, 0x72, 0x6e, 0xb5, 0x49, 0x5d, 0xea, 0x13, 0x4e, 0x1b, 0xe5, 0xae, 0xef, 0x71, 0x0f, 0xbd, - 0x11, 0x71, 0x95, 0x15, 0x57, 0x59, 0x72, 0x95, 0x49, 0xd7, 0x29, 0x07, 0x5c, 0x4b, 0xef, 0x19, - 0xd8, 0x4d, 0xaf, 0xe9, 0xad, 0x4a, 0xe6, 0xed, 0xde, 0x8e, 0xfc, 0x4b, 0xfe, 0x21, 0x7f, 0x29, - 0xd0, 0xa5, 0xdb, 0xbb, 0x57, 0x58, 0xd9, 0x91, 0x92, 0xe9, 0xc7, 0x9c, 0xba, 0xcc, 0xf1, 0x5c, - 0xf6, 0x1e, 0xe9, 0x3a, 0x8c, 0xfa, 0x7b, 0xd4, 0x5f, 0xed, 0xee, 0x36, 0x05, 0x8d, 0xc5, 0x3b, - 0xac, 0xee, 0xf5, 0x0d, 0x6f, 0xe9, 0x62, 0x84, 0xd4, 0x21, 0xf5, 0x96, 0xe3, 0x52, 0x7f, 0x3f, - 0x62, 0xef, 0x50, 0x4e, 0xd2, 0xb8, 0x56, 0x07, 0x71, 0xf9, 0x3d, 0x97, 0x3b, 0x1d, 0xda, 0xc7, - 0xf0, 0xfe, 0x51, 0x0c, 0xac, 0xde, 0xa2, 0x1d, 0x92, 0xe4, 0xb3, 0x1f, 0xc3, 0xe9, 0x35, 0x97, - 0xb4, 0xf7, 0x99, 0xc3, 0x70, 0xcf, 0x5d, 0xf3, 0x9b, 0xbd, 0x0e, 0x75, 0x39, 0x3a, 0x0b, 0x63, - 0x2e, 0xe9, 0xd0, 0x45, 0xeb, 0xac, 0xf5, 0x56, 0xb1, 0x32, 0xf5, 0xc5, 0xc1, 0xca, 0xa9, 0xc3, - 0x83, 0x95, 0xb1, 0x0f, 0x49, 0x87, 0x62, 0x49, 0x41, 0xaf, 0xc3, 0xf8, 0x1e, 0x69, 0xf7, 0xe8, - 0x62, 0x4e, 0x76, 0x99, 0xd6, 0x5d, 0xc6, 0x1f, 0x88, 0x46, 0xac, 0x68, 0xf6, 0x1f, 0xe7, 0x63, - 0xf0, 0xdf, 0xa3, 0x9c, 0x34, 0x08, 0x27, 0xa8, 0x03, 0x85, 0x36, 0xd9, 0xa6, 0x6d, 0xb6, 0x68, - 0x9d, 0xcd, 0xbf, 0x55, 0x3a, 0x7f, 0xa3, 0x3c, 0xcc, 0x26, 0x96, 0x53, 0xa0, 0xca, 0x9b, 0x12, - 0xe7, 0x86, 0xcb, 0xfd, 0xfd, 0xca, 0x8c, 0x1e, 0x44, 0x41, 0x35, 0x62, 0x2d, 0x04, 0xfd, 0xa1, - 0x05, 0x25, 0xe2, 0xba, 0x1e, 0x27, 0x5c, 0x6c, 0xd3, 0x62, 0x4e, 0x0a, 0xbd, 0x33, 0xba, 0xd0, - 0xb5, 0x08, 0x4c, 0x49, 0x3e, 0xad, 0x25, 0x97, 0x0c, 0x0a, 0x36, 0x65, 0x2e, 0x5d, 0x85, 0x92, - 0x31, 0x54, 0x34, 0x07, 0xf9, 0x5d, 0xba, 0xaf, 0xd6, 0x17, 0x8b, 0x9f, 0x68, 0x21, 0xb6, 0xa0, - 0x7a, 0x05, 0xaf, 0xe5, 0xae, 0x58, 0x4b, 0xd7, 0x61, 0x2e, 0x29, 0x30, 0x0b, 0xbf, 0xfd, 0x17, - 0x16, 0x2c, 0x18, 0xb3, 0xc0, 0x74, 0x87, 0xfa, 0xd4, 0xad, 0x53, 0xb4, 0x0a, 0x45, 0xb1, 0x97, - 0xac, 0x4b, 0xea, 0xc1, 0x56, 0xcf, 0xeb, 0x89, 0x14, 0x3f, 0x0c, 0x08, 0x38, 0xea, 0x13, 0xaa, - 0x45, 0xee, 0x59, 0x6a, 0xd1, 0x6d, 0x11, 0x46, 0x17, 0xf3, 0x71, 0xb5, 0xd8, 0x12, 0x8d, 0x58, - 0xd1, 0xec, 0x5f, 0x85, 0xef, 0x04, 0xe3, 0xb9, 0x47, 0x3b, 0xdd, 0x36, 0xe1, 0x34, 0x1a, 0xd4, - 0x91, 0xaa, 0x67, 0xcf, 0xc2, 0xf4, 0x5a, 0xb7, 0xeb, 0x7b, 0x7b, 0xb4, 0x51, 0xe3, 0xa4, 0x49, - 0xed, 0x3f, 0xb2, 0xe0, 0xcc, 0x9a, 0xdf, 0xf4, 0xaa, 0xeb, 0x6b, 0xdd, 0xee, 0x6d, 0x4a, 0xda, - 0xbc, 0x55, 0xe3, 0x84, 0xf7, 0x18, 0xba, 0x0e, 0x05, 0x26, 0x7f, 0x69, 0xb8, 0x37, 0x03, 0x0d, - 0x51, 0xf4, 0xa7, 0x07, 0x2b, 0x0b, 0x29, 0x8c, 0x14, 0x6b, 0x2e, 0xf4, 0x36, 0x4c, 0x74, 0x28, - 0x63, 0xa4, 0x19, 0xcc, 0x79, 0x56, 0x03, 0x4c, 0x7c, 0x4f, 0x35, 0xe3, 0x80, 0x6e, 0xff, 0x6b, - 0x0e, 0x66, 0x43, 0x2c, 0x2d, 0xfe, 0x04, 0x16, 0xb8, 0x07, 0x53, 0x2d, 0x63, 0x86, 0x72, 0x9d, - 0x4b, 0xe7, 0x3f, 0x18, 0x52, 0x97, 0xd3, 0x16, 0xa9, 0xb2, 0xa0, 0xc5, 0x4c, 0x99, 0xad, 0x38, - 0x26, 0x06, 0x75, 0x00, 0xd8, 0xbe, 0x5b, 0xd7, 0x42, 0xc7, 0xa4, 0xd0, 0xab, 0x19, 0x85, 0xd6, - 0x42, 0x80, 0x0a, 0xd2, 0x22, 0x21, 0x6a, 0xc3, 0x86, 0x00, 0xfb, 0x9f, 0x2c, 0x38, 0x9d, 0xc2, - 0x87, 0x7e, 0x25, 0xb1, 0x9f, 0x6f, 0xf4, 0xed, 0x27, 0xea, 0x63, 0x8b, 0x76, 0xf3, 0x5d, 0x98, - 0xf4, 0xe9, 0x9e, 0x23, 0x7c, 0xb5, 0x5e, 0xe1, 0x39, 0xcd, 0x3f, 0x89, 0x75, 0x3b, 0x0e, 0x7b, - 0xa0, 0x77, 0xa0, 0x18, 0xfc, 0x16, 0xcb, 0x9c, 0x17, 0xea, 0x2c, 0x36, 0x2e, 0xe8, 0xca, 0x70, - 0x44, 0xb7, 0xff, 0x00, 0xc6, 0xab, 0x2d, 0xe2, 0x73, 0xa1, 0x31, 0x3e, 0xed, 0x7a, 0xf7, 0xf1, - 0xa6, 0x1e, 0x62, 0xa8, 0x31, 0x58, 0x35, 0xe3, 0x80, 0x3e, 0xc4, 0x66, 0xbf, 0x0d, 0x13, 0x7b, - 0xd4, 0x97, 0xe3, 0xcd, 0xc7, 0xc1, 0x1e, 0xa8, 0x66, 0x1c, 0xd0, 0xed, 0xff, 0xb4, 0x60, 0x41, - 0x8e, 0x60, 0xdd, 0x61, 0x75, 0x6f, 0x8f, 0xfa, 0xfb, 0x98, 0xb2, 0x5e, 0xfb, 0x98, 0x07, 0xb4, - 0x0e, 0x73, 0x8c, 0x76, 0xf6, 0xa8, 0x5f, 0xf5, 0x5c, 0xc6, 0x7d, 0xe2, 0xb8, 0x5c, 0x8f, 0x6c, - 0x51, 0xf7, 0x9e, 0xab, 0x25, 0xe8, 0xb8, 0x8f, 0x03, 0xbd, 0x05, 0x93, 0x7a, 0xd8, 0x42, 0x95, - 0xc4, 0xc2, 0x4e, 0x89, 0x3d, 0xd0, 0x73, 0x62, 0x38, 0xa4, 0xda, 0xff, 0x63, 0xc1, 0xbc, 0x9c, - 0x55, 0xad, 0xb7, 0xcd, 0xea, 0xbe, 0xd3, 0x15, 0x2e, 0xf0, 0x65, 0x9c, 0xd2, 0x75, 0x98, 0x69, - 0x04, 0x0b, 0xbf, 0xe9, 0x74, 0x1c, 0x2e, 0x6d, 0x64, 0xbc, 0xf2, 0x8a, 0xc6, 0x98, 0x59, 0x8f, - 0x51, 0x71, 0xa2, 0xb7, 0xfd, 0x37, 0x79, 0x38, 0x1d, 0x74, 0xa1, 0x8d, 0x35, 0x9f, 0x3b, 0x3b, - 0xa4, 0xce, 0x19, 0x6a, 0xc0, 0x54, 0x23, 0x6a, 0xe6, 0xda, 0xf2, 0x7e, 0xa9, 0xac, 0x8e, 0xfb, - 0xb2, 0x79, 0xdc, 0x97, 0xbb, 0xbb, 0x4d, 0xd1, 0xc0, 0xca, 0x22, 0xaa, 0x28, 0xef, 0x9d, 0x2b, - 0xdf, 0x73, 0x3a, 0x34, 0xb2, 0x6e, 0x03, 0x9e, 0xe3, 0x18, 0x2a, 0x7a, 0x08, 0xf9, 0xa6, 0xc3, - 0xf5, 0x61, 0x7c, 0x65, 0x38, 0xb3, 0xbe, 0xe5, 0x24, 0x55, 0xad, 0x52, 0xd2, 0xa2, 0xf2, 0xb7, - 0x1c, 0x8e, 0x05, 0x22, 0xda, 0x86, 0x82, 0xd3, 0x21, 0x4d, 0x1a, 0x9c, 0xb9, 0xd7, 0x86, 0xc3, - 0xde, 0x10, 0x3c, 0x49, 0xf4, 0xf0, 0x74, 0x97, 0x54, 0x86, 0x35, 0xb2, 0x90, 0x51, 0x17, 0x2a, - 0xa2, 0x8c, 0x74, 0x68, 0x19, 0x69, 0xc6, 0x12, 0xc9, 0x90, 0x54, 0x86, 0x35, 0xb2, 0xfd, 0x55, - 0x0e, 0xe6, 0xa2, 0xf5, 0xab, 0x7a, 0x9d, 0x8e, 0xc3, 0xd1, 0x12, 0xe4, 0x9c, 0x86, 0xd6, 0x40, - 0xd0, 0x8c, 0xb9, 0x8d, 0x75, 0x9c, 0x73, 0x1a, 0xe8, 0x4d, 0x28, 0x6c, 0xfb, 0xc4, 0xad, 0xb7, - 0xb4, 0xe6, 0x85, 0xc0, 0x15, 0xd9, 0x8a, 0x35, 0x15, 0xbd, 0x06, 0x79, 0x4e, 0x9a, 0x5a, 0xe1, - 0xc2, 0xf5, 0xbb, 0x47, 0x9a, 0x58, 0xb4, 0x0b, 0x4d, 0x67, 0xbd, 0xed, 0xdf, 0xa6, 0x75, 0xb5, - 0xf3, 0x86, 0xa6, 0xd7, 0x54, 0x33, 0x0e, 0xe8, 0x42, 0x22, 0xe9, 0xf1, 0x96, 0xe7, 0x2f, 0x8e, - 0xc7, 0x25, 0xae, 0xc9, 0x56, 0xac, 0xa9, 0xe2, 0x4c, 0xaa, 0xcb, 0xf1, 0x73, 0xea, 0x2f, 0x16, - 0xe2, 0x67, 0x52, 0x35, 0x20, 0xe0, 0xa8, 0x0f, 0x7a, 0x02, 0xa5, 0xba, 0x4f, 0x09, 0xf7, 0xfc, - 0x75, 0xc2, 0xe9, 0xe2, 0x44, 0x66, 0x0d, 0x9c, 0x15, 0x81, 0x51, 0x35, 0x82, 0xc0, 0x26, 0x9e, - 0xfd, 0xad, 0x05, 0x8b, 0xd1, 0xd2, 0xca, 0xbd, 0x8d, 0x82, 0x01, 0xbd, 0x3c, 0xd6, 0x80, 0xe5, - 0x79, 0x13, 0x0a, 0x0d, 0xa7, 0x49, 0x19, 0x4f, 0xae, 0xf2, 0xba, 0x6c, 0xc5, 0x9a, 0x8a, 0xce, - 0x03, 0x34, 0x1d, 0xae, 0x9d, 0x83, 0x5e, 0xec, 0xf0, 0x08, 0xba, 0x15, 0x52, 0xb0, 0xd1, 0x0b, - 0x3d, 0x84, 0xa2, 0x1c, 0xe6, 0x88, 0x66, 0x27, 0x8f, 0x8a, 0x6a, 0x00, 0x80, 0x23, 0x2c, 0xfb, - 0xcb, 0x31, 0x98, 0xb8, 0xe9, 0x53, 0xa7, 0xd9, 0xe2, 0xe8, 0xb7, 0x60, 0xb2, 0xa3, 0x83, 0x4a, - 0x39, 0xc9, 0xd2, 0xf9, 0x5f, 0x1e, 0x4e, 0xc6, 0x5d, 0xb9, 0xe9, 0x22, 0x20, 0x8d, 0x26, 0x12, - 0xb5, 0xe1, 0x10, 0x55, 0x04, 0x64, 0xa4, 0xed, 0x10, 0x26, 0xf7, 0xcd, 0x08, 0xc8, 0xd6, 0x44, - 0x23, 0x56, 0x34, 0xf4, 0x03, 0x28, 0x78, 0xbe, 0xd3, 0x74, 0xdc, 0xc5, 0xa2, 0x1c, 0xc4, 0x85, - 0xe1, 0x4c, 0x48, 0xcf, 0xe2, 0xae, 0x64, 0x8d, 0x16, 0x5f, 0xfd, 0x8d, 0x35, 0x24, 0x7a, 0x04, - 0x13, 0x4a, 0x99, 0x02, 0x03, 0x5d, 0x1d, 0xda, 0xc1, 0x28, 0x7d, 0x8c, 0x94, 0x5e, 0xfd, 0xcd, - 0x70, 0x00, 0x88, 0x6a, 0xa1, 0x7f, 0x19, 0x93, 0xd0, 0xef, 0x64, 0xf0, 0x2f, 0x03, 0x1d, 0x4a, - 0x2d, 0x74, 0x28, 0xe3, 0x59, 0x40, 0xa5, 0xcb, 0x18, 0xe4, 0x41, 0xc4, 0x12, 0xeb, 0xc8, 0xa5, - 0x30, 0xc2, 0x12, 0xeb, 0xb0, 0x69, 0x26, 0x1e, 0xee, 0x04, 0x81, 0x8d, 0xfd, 0x69, 0x1e, 0xe6, - 0x75, 0xcf, 0xaa, 0xd7, 0x6e, 0xd3, 0xba, 0x3c, 0x26, 0x95, 0x7f, 0xca, 0xa7, 0xfa, 0x27, 0x07, - 0xc6, 0x1d, 0x4e, 0x3b, 0x41, 0x02, 0x56, 0xc9, 0x34, 0x9a, 0x48, 0x46, 0x79, 0x43, 0x80, 0xa8, - 0x1c, 0x28, 0xdc, 0x25, 0xdd, 0x0b, 0x2b, 0x09, 0xe8, 0x4f, 0x2d, 0x38, 0xbd, 0x47, 0x7d, 0x67, - 0xc7, 0xa9, 0xcb, 0x0c, 0xe6, 0xb6, 0xc3, 0xb8, 0xe7, 0xef, 0xeb, 0x13, 0xe1, 0xfd, 0xe1, 0x24, - 0x3f, 0x30, 0x00, 0x36, 0xdc, 0x1d, 0xaf, 0xf2, 0x5d, 0x2d, 0xed, 0xf4, 0x83, 0x7e, 0x68, 0x9c, - 0x26, 0x6f, 0xa9, 0x0b, 0x10, 0x8d, 0x36, 0x25, 0x81, 0xda, 0x34, 0x13, 0xa8, 0xa1, 0x07, 0x16, - 0x4c, 0x36, 0x70, 0x59, 0x66, 0xe2, 0xf5, 0xb9, 0x05, 0x25, 0x4d, 0xdf, 0x74, 0x18, 0x47, 0x8f, - 0xfb, 0xac, 0xbd, 0x3c, 0x9c, 0xb5, 0x0b, 0x6e, 0x69, 0xeb, 0x61, 0xbc, 0x1a, 0xb4, 0x18, 0x96, - 0x8e, 0x83, 0x2d, 0x55, 0x0b, 0xfb, 0x5e, 0xa6, 0xf1, 0x47, 0x8e, 0x41, 0xae, 0x91, 0xde, 0x3b, - 0xdb, 0x87, 0xe9, 0x98, 0x91, 0xa3, 0x4b, 0x30, 0xb6, 0xeb, 0xb8, 0xc1, 0xa9, 0xf7, 0x8b, 0x41, - 0x3c, 0xf5, 0xeb, 0x8e, 0xdb, 0x78, 0x7a, 0xb0, 0x32, 0x1f, 0xeb, 0x2c, 0x1a, 0xb1, 0xec, 0x7e, - 0x74, 0x18, 0x76, 0x6d, 0xf2, 0x27, 0x7f, 0xb7, 0x72, 0xea, 0xc7, 0x3f, 0x3b, 0x7b, 0xca, 0xfe, - 0x2c, 0x0f, 0x73, 0xc9, 0x55, 0x1d, 0xa2, 0x20, 0x11, 0xf9, 0xb0, 0xc9, 0x13, 0xf5, 0x61, 0xb9, - 0x93, 0xf3, 0x61, 0xf9, 0x93, 0xf0, 0x61, 0x63, 0xc7, 0xe6, 0xc3, 0xec, 0x7f, 0xb7, 0x60, 0x26, - 0xdc, 0x99, 0x1f, 0xf6, 0xc4, 0xc9, 0x1a, 0xad, 0xba, 0x75, 0xfc, 0xab, 0xfe, 0x11, 0x4c, 0x30, - 0xaf, 0xe7, 0xd7, 0x65, 0xf8, 0x28, 0xd0, 0x2f, 0x66, 0x73, 0x9a, 0x8a, 0xd7, 0x88, 0x99, 0x54, - 0x03, 0x0e, 0x50, 0xed, 0xc7, 0xe1, 0x7c, 0x34, 0x49, 0x45, 0x14, 0xbe, 0x88, 0xb7, 0xc4, 0x7c, - 0x26, 0xcd, 0x88, 0x42, 0xb4, 0x62, 0x4d, 0x45, 0xb6, 0x74, 0xe7, 0x41, 0x60, 0x5b, 0xac, 0x80, - 0xf6, 0xca, 0x72, 0x0f, 0x14, 0xc5, 0xfe, 0x36, 0x1f, 0x5a, 0x8f, 0x4e, 0x5f, 0x7f, 0x04, 0xa0, - 0x3c, 0x13, 0x6d, 0x6c, 0xb8, 0xda, 0xf5, 0x56, 0x47, 0x38, 0x08, 0xb4, 0x3b, 0x14, 0x28, 0xca, - 0xf7, 0x86, 0x31, 0x40, 0x44, 0xc0, 0x86, 0x28, 0xf4, 0xbb, 0x50, 0x22, 0xba, 0x64, 0x72, 0xd3, - 0xf3, 0xb5, 0x0e, 0xaf, 0x8f, 0x22, 0x79, 0x2d, 0x82, 0x49, 0x96, 0xbe, 0x22, 0x0a, 0x36, 0xa5, - 0x2d, 0xf9, 0x30, 0x9b, 0x18, 0x6f, 0x8a, 0xf7, 0xdd, 0x88, 0x7b, 0xdf, 0x0b, 0x59, 0x8e, 0x05, - 0x5d, 0x07, 0x32, 0x6b, 0x66, 0x0c, 0xe6, 0x92, 0x23, 0x3d, 0x36, 0xa1, 0xb1, 0xe2, 0x93, 0xe9, - 0xef, 0xff, 0x36, 0x07, 0xc5, 0xd0, 0xe2, 0xb3, 0x64, 0xa9, 0xea, 0xa4, 0xce, 0x1d, 0x91, 0x49, - 0xe4, 0x87, 0xc9, 0x24, 0xc6, 0x06, 0x67, 0x12, 0x41, 0x25, 0xab, 0xf0, 0xec, 0x4a, 0x96, 0x91, - 0x49, 0x4c, 0x0c, 0x9f, 0x49, 0x4c, 0x1e, 0x9d, 0x49, 0xd8, 0x7f, 0x6f, 0x01, 0xea, 0x4f, 0x1b, - 0xb3, 0x2c, 0x14, 0x49, 0xfa, 0xe1, 0x21, 0x4f, 0xe9, 0x64, 0xee, 0x36, 0xd8, 0x1d, 0xdb, 0x9f, - 0x8f, 0xc3, 0xec, 0x2d, 0x67, 0xe4, 0x82, 0x03, 0x87, 0x57, 0x15, 0x52, 0x8d, 0xea, 0x18, 0xa9, - 0xc6, 0x7d, 0xc2, 0x69, 0x73, 0x5f, 0xef, 0xef, 0x35, 0xcd, 0xfa, 0x6a, 0x35, 0xbd, 0xdb, 0xd3, - 0xc1, 0x24, 0x3c, 0x08, 0x7a, 0x68, 0x25, 0xf9, 0x00, 0xa6, 0x19, 0xf7, 0x9d, 0x3a, 0x57, 0x25, - 0x0d, 0xb6, 0x58, 0x92, 0x5e, 0xee, 0x8c, 0xee, 0x3e, 0x5d, 0x33, 0x89, 0x38, 0xde, 0x37, 0xb5, - 0x52, 0x32, 0x96, 0xb9, 0x52, 0xb2, 0x0a, 0x45, 0xd2, 0x6e, 0x7b, 0x3f, 0xba, 0x47, 0x9a, 0x4c, - 0xa7, 0xaa, 0xa1, 0xd6, 0xac, 0x05, 0x04, 0x1c, 0xf5, 0x41, 0x65, 0x00, 0xa7, 0xe9, 0x7a, 0x3e, - 0x95, 0x1c, 0x05, 0xe9, 0x6e, 0x67, 0x84, 0xaf, 0xdb, 0x08, 0x5b, 0xb1, 0xd1, 0x03, 0xd5, 0xe0, - 0x8c, 0xe3, 0x32, 0x5a, 0xef, 0xf9, 0xb4, 0xb6, 0xeb, 0x74, 0xef, 0x6d, 0xd6, 0xa4, 0x97, 0xd8, - 0x97, 0xda, 0x3c, 0x59, 0x79, 0x4d, 0x0b, 0x3b, 0xb3, 0x91, 0xd6, 0x09, 0xa7, 0xf3, 0xa2, 0x8b, - 0x30, 0xe5, 0xb8, 0xf5, 0x76, 0xaf, 0x41, 0xb7, 0x08, 0x6f, 0xb1, 0xc5, 0x49, 0x39, 0x8c, 0xb9, - 0xc3, 0x83, 0x95, 0xa9, 0x0d, 0xa3, 0x1d, 0xc7, 0x7a, 0x09, 0x2e, 0xfa, 0xb1, 0xc1, 0x55, 0x8c, - 0xb8, 0x6e, 0x7c, 0x6c, 0x72, 0x99, 0xbd, 0x52, 0x6a, 0x49, 0x90, 0xa9, 0x96, 0xf4, 0x57, 0x79, - 0x28, 0xa8, 0x52, 0x2e, 0xba, 0x94, 0xa8, 0x97, 0xbe, 0xd6, 0x57, 0x2f, 0x2d, 0xa5, 0x95, 0xbd, - 0x6d, 0x28, 0x38, 0x8c, 0xf5, 0xe2, 0xa7, 0xdb, 0x86, 0x6c, 0xc1, 0x9a, 0x82, 0x1c, 0x00, 0x12, - 0x94, 0x5a, 0x83, 0xd0, 0xe5, 0x52, 0xd6, 0x8a, 0x70, 0xa2, 0x1a, 0x1c, 0x12, 0x18, 0x36, 0xc0, - 0x65, 0x85, 0xc7, 0x73, 0x77, 0x9c, 0xa6, 0xce, 0xc3, 0xaf, 0x1b, 0x51, 0x73, 0x74, 0xfb, 0xf6, - 0x51, 0x78, 0x3d, 0x17, 0x05, 0xd0, 0xb1, 0x0e, 0x22, 0x92, 0xbe, 0x53, 0xbb, 0xfb, 0xa1, 0x9a, - 0x4e, 0x55, 0x22, 0x62, 0x8d, 0x2c, 0x64, 0x78, 0x3d, 0xde, 0xed, 0x71, 0xa9, 0x93, 0xc7, 0x24, - 0xe3, 0xae, 0x44, 0xc4, 0x1a, 0xd9, 0xfe, 0xcc, 0x82, 0x59, 0xb5, 0xdc, 0xd5, 0x16, 0xad, 0xef, - 0xd6, 0x38, 0xed, 0x8a, 0xc0, 0xb6, 0xc7, 0x28, 0x4b, 0x06, 0xb6, 0xf7, 0x19, 0x65, 0x58, 0x52, - 0x8c, 0xd9, 0xe7, 0x4e, 0x6a, 0xf6, 0xf6, 0x3f, 0x5a, 0x30, 0x2e, 0x23, 0xc8, 0x2c, 0xae, 0x2e, - 0x5e, 0x55, 0xc9, 0x0d, 0x55, 0x55, 0x39, 0xa2, 0xde, 0x15, 0x15, 0x74, 0xc6, 0x9e, 0x55, 0xd0, - 0xb1, 0xbf, 0xb1, 0x60, 0x21, 0xad, 0x48, 0x98, 0x65, 0xf8, 0xef, 0xc2, 0x64, 0xb7, 0x4d, 0xf8, - 0x8e, 0xe7, 0x77, 0x92, 0xb7, 0x01, 0x5b, 0xba, 0x1d, 0x87, 0x3d, 0x90, 0x0f, 0xe0, 0x07, 0xd9, - 0x48, 0xa0, 0xee, 0xd7, 0xb3, 0x1e, 0x3e, 0xf1, 0xea, 0x56, 0xb4, 0x58, 0x61, 0x13, 0xc3, 0x86, - 0x14, 0xfb, 0xcf, 0xc6, 0x61, 0x5e, 0xb2, 0x8c, 0x7a, 0x18, 0x8d, 0xb2, 0x43, 0x5d, 0x78, 0x45, - 0xe6, 0x10, 0xfd, 0xe7, 0x97, 0xda, 0xb4, 0x2b, 0x9a, 0xff, 0x95, 0x8d, 0xd4, 0x5e, 0x4f, 0x07, - 0x52, 0xf0, 0x00, 0xdc, 0xfe, 0x43, 0x09, 0x7e, 0xfe, 0x0e, 0x25, 0x53, 0xd9, 0x26, 0x8e, 0x54, - 0xb6, 0x81, 0x47, 0xd8, 0xe4, 0x73, 0x1c, 0x61, 0xfd, 0xc7, 0x4a, 0x31, 0xd3, 0xb1, 0xf2, 0xd7, - 0x39, 0x98, 0xd8, 0xf2, 0x3d, 0x59, 0x6c, 0x3e, 0xf9, 0xba, 0xe5, 0x5d, 0x18, 0x63, 0x5d, 0x5a, - 0xd7, 0x3e, 0xef, 0xdc, 0x70, 0x96, 0xa6, 0x87, 0x57, 0xeb, 0xd2, 0x7a, 0x65, 0x52, 0xb8, 0x51, - 0xf1, 0x0b, 0x4b, 0x20, 0xa3, 0x00, 0x97, 0xcf, 0x12, 0xec, 0x07, 0x90, 0xcf, 0x2e, 0xc0, 0x7d, - 0x6e, 0x41, 0x49, 0xf7, 0x7c, 0x69, 0x2b, 0x3d, 0x7a, 0x7c, 0x03, 0x2a, 0x3d, 0x7f, 0x1e, 0xcd, - 0x40, 0x2c, 0x1a, 0xfa, 0x7d, 0x98, 0xef, 0xfa, 0x5e, 0xc7, 0x13, 0x96, 0xba, 0xe5, 0xb5, 0x9d, - 0xba, 0x43, 0x83, 0x62, 0xe1, 0xa5, 0xa1, 0xe5, 0x19, 0xec, 0xfb, 0x95, 0xef, 0x68, 0xb9, 0xf3, - 0x5b, 0x49, 0x5c, 0xdc, 0x2f, 0xca, 0xfe, 0x2f, 0x0b, 0xa6, 0x63, 0x6b, 0x8f, 0xea, 0x00, 0x75, - 0xcf, 0x6d, 0x38, 0x3c, 0xbc, 0x90, 0x2d, 0x9d, 0x5f, 0x1d, 0x6e, 0x55, 0xab, 0x01, 0x5f, 0xa4, - 0x74, 0x61, 0x13, 0xc3, 0x06, 0x2c, 0xba, 0x10, 0xbc, 0x5f, 0x88, 0xc7, 0x4b, 0xea, 0xfd, 0xc2, - 0xd3, 0x83, 0x95, 0x29, 0x3d, 0x26, 0xf3, 0x3d, 0x43, 0x96, 0x57, 0x02, 0xff, 0x90, 0x83, 0x62, - 0x38, 0xff, 0x17, 0x60, 0x46, 0xf7, 0x63, 0x66, 0x74, 0x21, 0xe3, 0xce, 0x49, 0x43, 0x0a, 0x63, - 0x12, 0xc3, 0x98, 0x9e, 0x24, 0x8c, 0x29, 0xab, 0x4a, 0x1c, 0x61, 0x4e, 0xff, 0xa2, 0x36, 0x5f, - 0xf5, 0x7d, 0x01, 0x06, 0x75, 0x2f, 0x6e, 0x50, 0xab, 0x19, 0x67, 0x33, 0xc0, 0xa4, 0x3e, 0xb1, - 0x60, 0x36, 0x61, 0x04, 0xe8, 0x75, 0x18, 0x97, 0xd5, 0x21, 0xad, 0x5f, 0x21, 0xa3, 0xae, 0x25, - 0x48, 0x1a, 0xda, 0x82, 0x05, 0xd2, 0xe3, 0x5e, 0xc8, 0x7b, 0xc3, 0x25, 0xdb, 0x6d, 0xaa, 0x0a, - 0x04, 0x93, 0x95, 0x5f, 0xd0, 0x3c, 0x0b, 0x6b, 0x29, 0x7d, 0x70, 0x2a, 0xa7, 0xfd, 0xd3, 0x1c, - 0xa0, 0xb0, 0x31, 0x4b, 0x55, 0xf5, 0x09, 0x4c, 0xec, 0xa8, 0xfa, 0xcf, 0xf3, 0x95, 0xc5, 0x2b, - 0x25, 0xf3, 0x66, 0x20, 0xc0, 0x44, 0xbf, 0x79, 0x3c, 0x7a, 0x04, 0xfd, 0x3a, 0x84, 0x1e, 0x01, - 0xec, 0x38, 0xae, 0xc3, 0x5a, 0x23, 0x5e, 0xe0, 0xc9, 0xd3, 0xfc, 0x66, 0x88, 0x80, 0x0d, 0x34, - 0xfb, 0x3a, 0xcc, 0x18, 0xab, 0xc9, 0xfd, 0x7d, 0x71, 0xbe, 0x13, 0xce, 0x69, 0xa7, 0xcb, 0x55, - 0x28, 0x9f, 0x8f, 0xf4, 0x6d, 0x4d, 0xb7, 0xe3, 0xb0, 0x87, 0xfd, 0x69, 0xce, 0xd0, 0x6f, 0xe9, - 0x6e, 0x87, 0xd2, 0x8b, 0xb7, 0xe3, 0x9b, 0x51, 0xec, 0xbf, 0x72, 0x31, 0x16, 0x76, 0x6c, 0x8f, - 0xf8, 0x41, 0xf5, 0xf7, 0x72, 0xc6, 0x65, 0x7d, 0x40, 0x7c, 0x47, 0x28, 0x4e, 0xa4, 0x12, 0x0f, - 0x88, 0xcf, 0xb0, 0x84, 0x44, 0xdf, 0x17, 0x43, 0xa5, 0x61, 0xce, 0x97, 0xd9, 0xa7, 0x70, 0xda, - 0x35, 0xe7, 0x47, 0xbb, 0x0c, 0x2b, 0x40, 0xfb, 0xdf, 0x0a, 0x86, 0xc1, 0x68, 0xaf, 0x7f, 0x07, - 0x50, 0x9b, 0x30, 0x7e, 0x9b, 0xb8, 0x0d, 0xa1, 0xde, 0x74, 0xc7, 0xa7, 0xac, 0xa5, 0x23, 0xbc, - 0x25, 0x8d, 0x82, 0x36, 0xfb, 0x7a, 0xe0, 0x14, 0x2e, 0x74, 0x29, 0xee, 0xdc, 0x57, 0x92, 0xce, - 0x3d, 0xda, 0xd4, 0x11, 0xdd, 0xbb, 0x69, 0x2e, 0xe3, 0x27, 0x60, 0x2e, 0xbf, 0x07, 0xf3, 0x3b, - 0xc9, 0x2b, 0x38, 0x7d, 0x21, 0x7f, 0x79, 0xc4, 0x1b, 0xbc, 0xca, 0x99, 0xc3, 0xe8, 0xde, 0x26, - 0x6a, 0xc6, 0xfd, 0x82, 0x90, 0x17, 0x3c, 0x3d, 0x93, 0xd9, 0xab, 0xaa, 0x81, 0x0c, 0x6d, 0xb2, - 0x89, 0xbc, 0x37, 0xf9, 0xe8, 0x4c, 0x41, 0xe2, 0x98, 0x80, 0x84, 0x09, 0x17, 0x8e, 0xd3, 0x84, - 0xd1, 0x25, 0x28, 0xd5, 0x7b, 0xbe, 0x4f, 0x5d, 0x2e, 0x86, 0x23, 0x43, 0xe1, 0x7c, 0x54, 0xcb, - 0xae, 0x46, 0x24, 0x6c, 0xf6, 0x13, 0xea, 0x68, 0xfc, 0xa9, 0x4d, 0x5b, 0x56, 0xd1, 0xf2, 0x91, - 0x3a, 0x56, 0xfb, 0x7a, 0xe0, 0x14, 0x2e, 0xf4, 0x91, 0xb4, 0x79, 0x4e, 0x65, 0xbe, 0xf3, 0xfc, - 0x79, 0x7d, 0x51, 0xfb, 0x0b, 0xae, 0xfc, 0x05, 0xa7, 0xf6, 0x27, 0x31, 0x37, 0x33, 0x5c, 0xb5, - 0x61, 0x09, 0x72, 0x84, 0x25, 0x4b, 0xd1, 0x6b, 0x0c, 0xe7, 0x08, 0x43, 0xf7, 0x61, 0xdc, 0x17, - 0xde, 0x4e, 0x7b, 0xd3, 0x8b, 0x19, 0x2d, 0x5f, 0x7a, 0x4a, 0x35, 0x4c, 0xf9, 0x13, 0x2b, 0x34, - 0xa3, 0xc0, 0x91, 0x3f, 0xb1, 0x02, 0x87, 0x0f, 0x51, 0xd8, 0x19, 0xbc, 0x39, 0x45, 0x4f, 0x74, - 0x70, 0x64, 0x65, 0x79, 0x43, 0xd9, 0x07, 0x33, 0x28, 0x48, 0xb2, 0x7f, 0x6a, 0xc1, 0x99, 0xd4, - 0xde, 0xa1, 0x77, 0xce, 0x9d, 0xa0, 0x77, 0xb6, 0x8e, 0xdb, 0x3b, 0x3f, 0x32, 0x96, 0x30, 0x18, - 0xc2, 0x71, 0x3d, 0x14, 0xff, 0x49, 0x0e, 0xe6, 0x30, 0xed, 0x7a, 0xb1, 0x42, 0xc7, 0x56, 0xf0, - 0x2a, 0x2d, 0x43, 0x64, 0x90, 0xa8, 0xdc, 0x57, 0x26, 0x62, 0xcf, 0xd1, 0xbe, 0x0f, 0xe3, 0xb2, - 0x06, 0xa1, 0x63, 0x99, 0xcb, 0x19, 0x6e, 0x5a, 0x63, 0xa8, 0x52, 0x87, 0x55, 0x31, 0x47, 0x01, - 0x0a, 0x64, 0x79, 0x49, 0xaa, 0x55, 0xf8, 0x72, 0x86, 0xeb, 0xd6, 0x7e, 0x64, 0xd9, 0x8c, 0x15, - 0xa0, 0xfd, 0x59, 0x0e, 0x54, 0x14, 0xf0, 0x02, 0xb2, 0x85, 0xdf, 0x88, 0x65, 0x0b, 0x43, 0x86, - 0xc1, 0x72, 0x70, 0x03, 0x33, 0x85, 0x64, 0x84, 0x77, 0x2e, 0x0b, 0xe8, 0xb3, 0xb3, 0x84, 0x7f, - 0xb6, 0xa0, 0x28, 0xfb, 0xbd, 0x80, 0x0c, 0x61, 0x2b, 0x9e, 0x21, 0xbc, 0x93, 0x61, 0x16, 0x03, - 0xb2, 0x83, 0x4f, 0xf3, 0x7a, 0xf4, 0x61, 0xfc, 0xd7, 0x22, 0x7e, 0x43, 0x47, 0x36, 0x91, 0x05, - 0x8a, 0x46, 0xac, 0x68, 0xe8, 0x77, 0x60, 0xce, 0x57, 0xf7, 0xee, 0xb4, 0x71, 0x33, 0x0c, 0x33, - 0xf2, 0x99, 0x2f, 0xc6, 0xf5, 0xe5, 0x7d, 0x54, 0x21, 0xc3, 0x09, 0x54, 0xdc, 0x27, 0x47, 0x84, - 0x1e, 0xdd, 0xa4, 0x2f, 0xd3, 0x47, 0xf2, 0xe5, 0x11, 0x1d, 0xa7, 0x0a, 0x3d, 0xfa, 0x9a, 0x71, - 0xbf, 0x20, 0xd4, 0x82, 0x29, 0xf3, 0x49, 0x8f, 0xd6, 0xa5, 0xf3, 0xd9, 0xdf, 0x0e, 0xa9, 0xcb, - 0x17, 0xb3, 0x05, 0xc7, 0x90, 0xed, 0x83, 0x02, 0x94, 0x0c, 0xe5, 0x4b, 0x54, 0x1d, 0xa6, 0x4f, - 0xa6, 0xea, 0x90, 0x1e, 0xe4, 0x96, 0x46, 0x0a, 0x72, 0xcf, 0xc5, 0x83, 0xdc, 0xef, 0x26, 0x83, - 0x5c, 0x90, 0xb3, 0x8b, 0x05, 0xb8, 0x0c, 0x66, 0x74, 0xb4, 0x17, 0xbc, 0xcd, 0xca, 0x94, 0x36, - 0xf4, 0xc7, 0x94, 0xe8, 0xf0, 0x60, 0x25, 0x78, 0x59, 0x11, 0xbc, 0xc9, 0x4a, 0x88, 0x40, 0xd7, - 0x43, 0xa1, 0xb5, 0x5e, 0xa7, 0x43, 0xfc, 0xfd, 0xc5, 0x29, 0x39, 0xe0, 0xb0, 0x1c, 0x79, 0x33, - 0x46, 0xc5, 0x89, 0xde, 0x68, 0x0b, 0x0a, 0x2a, 0x58, 0xd4, 0xef, 0x7d, 0xde, 0xcd, 0x12, 0x87, - 0xaa, 0x18, 0x41, 0xfd, 0xc6, 0x1a, 0xc7, 0x8c, 0xf3, 0x8b, 0x47, 0xc4, 0xf9, 0x77, 0x00, 0x79, - 0xdb, 0x32, 0x1a, 0x69, 0xdc, 0x52, 0x5f, 0x54, 0x09, 0xad, 0x2c, 0xc4, 0xc3, 0xc0, 0xbb, 0x7d, - 0x3d, 0x70, 0x0a, 0x97, 0xb0, 0x6a, 0x1d, 0x1c, 0x86, 0xa6, 0xa0, 0x63, 0xfa, 0x2b, 0x99, 0x03, - 0xac, 0x20, 0x7d, 0x58, 0x10, 0x56, 0x5d, 0x4d, 0xa0, 0xe2, 0x3e, 0x39, 0xe8, 0x87, 0x30, 0x2d, - 0x54, 0x28, 0x12, 0x0c, 0xcf, 0x29, 0x78, 0xfe, 0xf0, 0x60, 0x65, 0x7a, 0xd3, 0x84, 0xc4, 0x71, - 0x09, 0xf6, 0xff, 0xe5, 0x20, 0x66, 0x7f, 0xe8, 0x13, 0x0b, 0xe6, 0x49, 0xe2, 0x73, 0xa0, 0x20, - 0x7c, 0xf9, 0xb5, 0x6c, 0xdf, 0x68, 0xf5, 0x7d, 0x4d, 0x14, 0x15, 0x1d, 0x93, 0x5d, 0x18, 0xee, - 0x17, 0x8a, 0xfe, 0xc4, 0x82, 0xd3, 0xa4, 0xff, 0x7b, 0x2f, 0x7d, 0x1e, 0x5e, 0x1d, 0xf9, 0x83, - 0xb1, 0xca, 0xab, 0x87, 0x07, 0x2b, 0x69, 0x5f, 0xc2, 0xe1, 0x34, 0x71, 0xe8, 0x07, 0x30, 0x46, - 0xfc, 0x66, 0x90, 0x60, 0x67, 0x17, 0x1b, 0x7c, 0xc6, 0x17, 0x1d, 0xc8, 0x6b, 0x7e, 0x93, 0x61, - 0x09, 0x6a, 0xff, 0x2c, 0x0f, 0x73, 0xc9, 0xd7, 0x94, 0xfa, 0x01, 0xca, 0x58, 0xea, 0x03, 0x94, - 0xd7, 0x61, 0x9c, 0xd4, 0x79, 0xf8, 0x1a, 0x24, 0x7a, 0x41, 0x2c, 0x1a, 0xb1, 0xa2, 0xa1, 0x87, - 0x50, 0x64, 0x9c, 0xf8, 0x5c, 0xe4, 0x5d, 0x3a, 0xf5, 0xcd, 0xfc, 0x5a, 0xba, 0x16, 0x00, 0xe0, - 0x08, 0x0b, 0x5d, 0x89, 0xbb, 0x33, 0x3b, 0xe9, 0xce, 0xe6, 0xcd, 0xb9, 0x8c, 0x9a, 0xb6, 0x77, - 0xa0, 0x64, 0xec, 0x83, 0x3e, 0x5d, 0xae, 0x65, 0x5e, 0xf7, 0x48, 0xed, 0x66, 0xd5, 0xb7, 0x80, - 0x11, 0xc5, 0xc4, 0x8f, 0xf2, 0x5a, 0xb9, 0x5a, 0xcf, 0x95, 0xd7, 0xca, 0xe5, 0x32, 0xd0, 0xec, - 0x59, 0x98, 0x8e, 0x3d, 0x8a, 0x92, 0x15, 0xe7, 0x87, 0xc4, 0xa7, 0x2d, 0xaf, 0xc7, 0xe8, 0xcb, - 0x5a, 0x71, 0x0e, 0x07, 0x78, 0xdc, 0x15, 0xe7, 0x08, 0xf8, 0xe8, 0x8a, 0x73, 0xd8, 0xf7, 0xa5, - 0xad, 0x38, 0x87, 0x23, 0x1c, 0x10, 0x53, 0xfe, 0x6f, 0xce, 0x98, 0x45, 0x3c, 0xae, 0xcc, 0x3d, - 0x23, 0xae, 0x7c, 0x0c, 0x93, 0x8e, 0xcb, 0xa9, 0xbf, 0x47, 0xda, 0x3a, 0xb5, 0x1f, 0x72, 0xaa, - 0xeb, 0x3d, 0x5f, 0x47, 0x55, 0xc1, 0x54, 0x37, 0x34, 0x0e, 0x0e, 0x11, 0x51, 0x1b, 0xce, 0x04, - 0xb5, 0x24, 0x9f, 0x92, 0xa8, 0x16, 0xae, 0xef, 0x93, 0xdf, 0x0f, 0x2e, 0x33, 0x6f, 0xa6, 0x75, - 0x7a, 0x3a, 0x88, 0x80, 0xd3, 0x41, 0x11, 0x83, 0x69, 0x66, 0x24, 0x54, 0xc1, 0x41, 0x32, 0x64, - 0x1d, 0x2e, 0x99, 0x83, 0x1a, 0x97, 0xd0, 0x26, 0x28, 0x8e, 0xcb, 0xb0, 0xff, 0x23, 0x0f, 0xb3, - 0x09, 0x4d, 0x4b, 0x04, 0x8e, 0xc5, 0x17, 0x19, 0x38, 0x16, 0x46, 0x0a, 0x1c, 0xd3, 0x63, 0x9a, - 0xb1, 0x91, 0x62, 0x9a, 0x0f, 0x54, 0x5c, 0xa1, 0x77, 0x6e, 0x63, 0x5d, 0x3f, 0x0f, 0x0c, 0x57, - 0x73, 0xd3, 0x24, 0xe2, 0x78, 0x5f, 0x79, 0x0a, 0x37, 0xfa, 0xbf, 0x85, 0xd3, 0x41, 0xd1, 0xd5, - 0xac, 0x8f, 0x2e, 0x42, 0x00, 0x75, 0x0a, 0xa7, 0x10, 0x70, 0x9a, 0xb8, 0xca, 0x9d, 0x2f, 0xbe, - 0x5e, 0x3e, 0xf5, 0xe5, 0xd7, 0xcb, 0xa7, 0xbe, 0xfa, 0x7a, 0xf9, 0xd4, 0x8f, 0x0f, 0x97, 0xad, - 0x2f, 0x0e, 0x97, 0xad, 0x2f, 0x0f, 0x97, 0xad, 0xaf, 0x0e, 0x97, 0xad, 0xff, 0x3e, 0x5c, 0xb6, - 0xfe, 0xf2, 0x9b, 0xe5, 0x53, 0x8f, 0xde, 0x18, 0xe6, 0x9f, 0x16, 0xfc, 0x7f, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xc5, 0xa4, 0xb7, 0x24, 0xdb, 0x40, 0x00, 0x00, + // 3673 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x3c, 0x4d, 0x6f, 0x23, 0x47, + 0x76, 0xd3, 0xa4, 0x44, 0x89, 0x8f, 0xfa, 0xac, 0xd1, 0xd8, 0x5a, 0x6d, 0x2c, 0x4d, 0xda, 0x86, + 0x61, 0xc7, 0x36, 0x95, 0xf9, 0xf2, 0x7c, 0x38, 0x99, 0x40, 0xa4, 0xe6, 0x43, 0x13, 0xad, 0x47, + 0x29, 0x8e, 0x67, 0x76, 0x67, 0x67, 0xe0, 0x94, 0xc8, 0x12, 0xd9, 0x11, 0xd9, 0xcd, 0xed, 0x2a, + 0x6a, 0xad, 0x24, 0x48, 0x36, 0x5f, 0xc0, 0x02, 0xf9, 0x40, 0x0e, 0x46, 0xbc, 0x01, 0x12, 0x20, + 0x48, 0xce, 0xc9, 0x1f, 0xc8, 0xc1, 0x87, 0x5c, 0x8c, 0xc0, 0x09, 0x8c, 0x24, 0x07, 0x1f, 0x0c, + 0x21, 0x96, 0x81, 0x1c, 0x7d, 0xcb, 0x65, 0x80, 0x00, 0x41, 0x7d, 0x74, 0x77, 0x75, 0xb3, 0x39, + 0x62, 0x73, 0xa4, 0xc1, 0x60, 0x6f, 0x54, 0xbd, 0xaf, 0xaa, 0x57, 0xef, 0xbd, 0x7a, 0xef, 0x55, + 0xb5, 0xe0, 0x62, 0xd3, 0xe1, 0xad, 0xde, 0x76, 0xb9, 0xee, 0x75, 0x56, 0xc9, 0x6e, 0xcf, 0xe1, + 0xfb, 0xab, 0xbb, 0xc4, 0x6f, 0x7a, 0xab, 0xa4, 0xeb, 0xac, 0xee, 0x9d, 0x23, 0xed, 0x6e, 0x8b, + 0x9c, 0x5b, 0x6d, 0x52, 0x97, 0xfa, 0x84, 0xd3, 0x46, 0xb9, 0xeb, 0x7b, 0xdc, 0x43, 0xaf, 0x45, + 0x54, 0x65, 0x45, 0x55, 0x96, 0x54, 0x65, 0xd2, 0x75, 0xca, 0x01, 0xd5, 0xd2, 0x3b, 0x06, 0xef, + 0xa6, 0xd7, 0xf4, 0x56, 0x25, 0xf1, 0x76, 0x6f, 0x47, 0xfe, 0x25, 0xff, 0x90, 0xbf, 0x14, 0xd3, + 0xa5, 0xdb, 0xbb, 0x57, 0x58, 0xd9, 0x91, 0x92, 0xe9, 0x47, 0x9c, 0xba, 0xcc, 0xf1, 0x5c, 0xf6, + 0x0e, 0xe9, 0x3a, 0x8c, 0xfa, 0x7b, 0xd4, 0x5f, 0xed, 0xee, 0x36, 0x05, 0x8c, 0xc5, 0x11, 0x56, + 0xf7, 0xfa, 0xa6, 0xb7, 0x74, 0x31, 0xe2, 0xd4, 0x21, 0xf5, 0x96, 0xe3, 0x52, 0x7f, 0x3f, 0x22, + 0xef, 0x50, 0x4e, 0xd2, 0xa8, 0x56, 0x07, 0x51, 0xf9, 0x3d, 0x97, 0x3b, 0x1d, 0xda, 0x47, 0xf0, + 0xee, 0x51, 0x04, 0xac, 0xde, 0xa2, 0x1d, 0x92, 0xa4, 0xb3, 0x1f, 0xc1, 0xe9, 0x35, 0x97, 0xb4, + 0xf7, 0x99, 0xc3, 0x70, 0xcf, 0x5d, 0xf3, 0x9b, 0xbd, 0x0e, 0x75, 0x39, 0x3a, 0x0b, 0x63, 0x2e, + 0xe9, 0xd0, 0x45, 0xeb, 0xac, 0xf5, 0x46, 0xb1, 0x32, 0xf5, 0xd9, 0xc1, 0xca, 0xa9, 0xc3, 0x83, + 0x95, 0xb1, 0xf7, 0x49, 0x87, 0x62, 0x09, 0x41, 0xaf, 0xc2, 0xf8, 0x1e, 0x69, 0xf7, 0xe8, 0x62, + 0x4e, 0xa2, 0x4c, 0x6b, 0x94, 0xf1, 0xfb, 0x62, 0x10, 0x2b, 0x98, 0xfd, 0x47, 0xf9, 0x18, 0xfb, + 0xef, 0x51, 0x4e, 0x1a, 0x84, 0x13, 0xd4, 0x81, 0x42, 0x9b, 0x6c, 0xd3, 0x36, 0x5b, 0xb4, 0xce, + 0xe6, 0xdf, 0x28, 0x9d, 0xbf, 0x51, 0x1e, 0x66, 0x13, 0xcb, 0x29, 0xac, 0xca, 0x9b, 0x92, 0xcf, + 0x0d, 0x97, 0xfb, 0xfb, 0x95, 0x19, 0x3d, 0x89, 0x82, 0x1a, 0xc4, 0x5a, 0x08, 0xfa, 0x03, 0x0b, + 0x4a, 0xc4, 0x75, 0x3d, 0x4e, 0xb8, 0xd8, 0xa6, 0xc5, 0x9c, 0x14, 0x7a, 0x67, 0x74, 0xa1, 0x6b, + 0x11, 0x33, 0x25, 0xf9, 0xb4, 0x96, 0x5c, 0x32, 0x20, 0xd8, 0x94, 0xb9, 0x74, 0x15, 0x4a, 0xc6, + 0x54, 0xd1, 0x1c, 0xe4, 0x77, 0xe9, 0xbe, 0xd2, 0x2f, 0x16, 0x3f, 0xd1, 0x42, 0x4c, 0xa1, 0x5a, + 0x83, 0xd7, 0x72, 0x57, 0xac, 0xa5, 0xeb, 0x30, 0x97, 0x14, 0x98, 0x85, 0xde, 0xfe, 0x0b, 0x0b, + 0x16, 0x8c, 0x55, 0x60, 0xba, 0x43, 0x7d, 0xea, 0xd6, 0x29, 0x5a, 0x85, 0xa2, 0xd8, 0x4b, 0xd6, + 0x25, 0xf5, 0x60, 0xab, 0xe7, 0xf5, 0x42, 0x8a, 0xef, 0x07, 0x00, 0x1c, 0xe1, 0x84, 0x66, 0x91, + 0x7b, 0x9a, 0x59, 0x74, 0x5b, 0x84, 0xd1, 0xc5, 0x7c, 0xdc, 0x2c, 0xb6, 0xc4, 0x20, 0x56, 0x30, + 0xfb, 0x57, 0xe1, 0x3b, 0xc1, 0x7c, 0xee, 0xd1, 0x4e, 0xb7, 0x4d, 0x38, 0x8d, 0x26, 0x75, 0xa4, + 0xe9, 0xd9, 0xb3, 0x30, 0xbd, 0xd6, 0xed, 0xfa, 0xde, 0x1e, 0x6d, 0xd4, 0x38, 0x69, 0x52, 0xfb, + 0x0f, 0x2d, 0x38, 0xb3, 0xe6, 0x37, 0xbd, 0xea, 0xfa, 0x5a, 0xb7, 0x7b, 0x9b, 0x92, 0x36, 0x6f, + 0xd5, 0x38, 0xe1, 0x3d, 0x86, 0xae, 0x43, 0x81, 0xc9, 0x5f, 0x9a, 0xdd, 0xeb, 0x81, 0x85, 0x28, + 0xf8, 0x93, 0x83, 0x95, 0x85, 0x14, 0x42, 0x8a, 0x35, 0x15, 0x7a, 0x13, 0x26, 0x3a, 0x94, 0x31, + 0xd2, 0x0c, 0xd6, 0x3c, 0xab, 0x19, 0x4c, 0x7c, 0x4f, 0x0d, 0xe3, 0x00, 0x6e, 0xff, 0x6b, 0x0e, + 0x66, 0x43, 0x5e, 0x5a, 0xfc, 0x09, 0x28, 0xb8, 0x07, 0x53, 0x2d, 0x63, 0x85, 0x52, 0xcf, 0xa5, + 0xf3, 0xef, 0x0d, 0x69, 0xcb, 0x69, 0x4a, 0xaa, 0x2c, 0x68, 0x31, 0x53, 0xe6, 0x28, 0x8e, 0x89, + 0x41, 0x1d, 0x00, 0xb6, 0xef, 0xd6, 0xb5, 0xd0, 0x31, 0x29, 0xf4, 0x6a, 0x46, 0xa1, 0xb5, 0x90, + 0x41, 0x05, 0x69, 0x91, 0x10, 0x8d, 0x61, 0x43, 0x80, 0xfd, 0x4f, 0x16, 0x9c, 0x4e, 0xa1, 0x43, + 0xbf, 0x92, 0xd8, 0xcf, 0xd7, 0xfa, 0xf6, 0x13, 0xf5, 0x91, 0x45, 0xbb, 0xf9, 0x36, 0x4c, 0xfa, + 0x74, 0xcf, 0x11, 0xb1, 0x5a, 0x6b, 0x78, 0x4e, 0xd3, 0x4f, 0x62, 0x3d, 0x8e, 0x43, 0x0c, 0xf4, + 0x16, 0x14, 0x83, 0xdf, 0x42, 0xcd, 0x79, 0x61, 0xce, 0x62, 0xe3, 0x02, 0x54, 0x86, 0x23, 0xb8, + 0xfd, 0xfb, 0x30, 0x5e, 0x6d, 0x11, 0x9f, 0x0b, 0x8b, 0xf1, 0x69, 0xd7, 0xfb, 0x00, 0x6f, 0xea, + 0x29, 0x86, 0x16, 0x83, 0xd5, 0x30, 0x0e, 0xe0, 0x43, 0x6c, 0xf6, 0x9b, 0x30, 0xb1, 0x47, 0x7d, + 0x39, 0xdf, 0x7c, 0x9c, 0xd9, 0x7d, 0x35, 0x8c, 0x03, 0xb8, 0xfd, 0x9f, 0x16, 0x2c, 0xc8, 0x19, + 0xac, 0x3b, 0xac, 0xee, 0xed, 0x51, 0x7f, 0x1f, 0x53, 0xd6, 0x6b, 0x1f, 0xf3, 0x84, 0xd6, 0x61, + 0x8e, 0xd1, 0xce, 0x1e, 0xf5, 0xab, 0x9e, 0xcb, 0xb8, 0x4f, 0x1c, 0x97, 0xeb, 0x99, 0x2d, 0x6a, + 0xec, 0xb9, 0x5a, 0x02, 0x8e, 0xfb, 0x28, 0xd0, 0x1b, 0x30, 0xa9, 0xa7, 0x2d, 0x4c, 0x49, 0x28, + 0x76, 0x4a, 0xec, 0x81, 0x5e, 0x13, 0xc3, 0x21, 0xd4, 0xfe, 0x1f, 0x0b, 0xe6, 0xe5, 0xaa, 0x6a, + 0xbd, 0x6d, 0x56, 0xf7, 0x9d, 0xae, 0x08, 0x81, 0x2f, 0xe2, 0x92, 0xae, 0xc3, 0x4c, 0x23, 0x50, + 0xfc, 0xa6, 0xd3, 0x71, 0xb8, 0xf4, 0x91, 0xf1, 0xca, 0x4b, 0x9a, 0xc7, 0xcc, 0x7a, 0x0c, 0x8a, + 0x13, 0xd8, 0xf6, 0xdf, 0xe4, 0xe1, 0x74, 0x80, 0x42, 0x1b, 0x6b, 0x3e, 0x77, 0x76, 0x48, 0x9d, + 0x33, 0xd4, 0x80, 0xa9, 0x46, 0x34, 0xcc, 0xb5, 0xe7, 0xfd, 0x52, 0x59, 0x1d, 0xf7, 0x65, 0xf3, + 0xb8, 0x2f, 0x77, 0x77, 0x9b, 0x62, 0x80, 0x95, 0x45, 0x56, 0x51, 0xde, 0x3b, 0x57, 0xbe, 0xe7, + 0x74, 0x68, 0xe4, 0xdd, 0x06, 0x7b, 0x8e, 0x63, 0x5c, 0xd1, 0x03, 0xc8, 0x37, 0x1d, 0xae, 0x0f, + 0xe3, 0x2b, 0xc3, 0xb9, 0xf5, 0x2d, 0x27, 0x69, 0x6a, 0x95, 0x92, 0x16, 0x95, 0xbf, 0xe5, 0x70, + 0x2c, 0x38, 0xa2, 0x6d, 0x28, 0x38, 0x1d, 0xd2, 0xa4, 0xc1, 0x99, 0x7b, 0x6d, 0x38, 0xde, 0x1b, + 0x82, 0x26, 0xc9, 0x3d, 0x3c, 0xdd, 0x25, 0x94, 0x61, 0xcd, 0x59, 0xc8, 0xa8, 0x0b, 0x13, 0x51, + 0x4e, 0x3a, 0xb4, 0x8c, 0x34, 0x67, 0x89, 0x64, 0x48, 0x28, 0xc3, 0x9a, 0xb3, 0xfd, 0x65, 0x0e, + 0xe6, 0x22, 0xfd, 0x55, 0xbd, 0x4e, 0xc7, 0xe1, 0x68, 0x09, 0x72, 0x4e, 0x43, 0x5b, 0x20, 0x68, + 0xc2, 0xdc, 0xc6, 0x3a, 0xce, 0x39, 0x0d, 0xf4, 0x3a, 0x14, 0xb6, 0x7d, 0xe2, 0xd6, 0x5b, 0xda, + 0xf2, 0x42, 0xc6, 0x15, 0x39, 0x8a, 0x35, 0x14, 0xbd, 0x02, 0x79, 0x4e, 0x9a, 0xda, 0xe0, 0x42, + 0xfd, 0xdd, 0x23, 0x4d, 0x2c, 0xc6, 0x85, 0xa5, 0xb3, 0xde, 0xf6, 0x6f, 0xd1, 0xba, 0xda, 0x79, + 0xc3, 0xd2, 0x6b, 0x6a, 0x18, 0x07, 0x70, 0x21, 0x91, 0xf4, 0x78, 0xcb, 0xf3, 0x17, 0xc7, 0xe3, + 0x12, 0xd7, 0xe4, 0x28, 0xd6, 0x50, 0x71, 0x26, 0xd5, 0xe5, 0xfc, 0x39, 0xf5, 0x17, 0x0b, 0xf1, + 0x33, 0xa9, 0x1a, 0x00, 0x70, 0x84, 0x83, 0x1e, 0x43, 0xa9, 0xee, 0x53, 0xc2, 0x3d, 0x7f, 0x9d, + 0x70, 0xba, 0x38, 0x91, 0xd9, 0x02, 0x67, 0x45, 0x62, 0x54, 0x8d, 0x58, 0x60, 0x93, 0x9f, 0xfd, + 0xad, 0x05, 0x8b, 0x91, 0x6a, 0xe5, 0xde, 0x46, 0xc9, 0x80, 0x56, 0x8f, 0x35, 0x40, 0x3d, 0xaf, + 0x43, 0xa1, 0xe1, 0x34, 0x29, 0xe3, 0x49, 0x2d, 0xaf, 0xcb, 0x51, 0xac, 0xa1, 0xe8, 0x3c, 0x40, + 0xd3, 0xe1, 0x3a, 0x38, 0x68, 0x65, 0x87, 0x47, 0xd0, 0xad, 0x10, 0x82, 0x0d, 0x2c, 0xf4, 0x00, + 0x8a, 0x72, 0x9a, 0x23, 0xba, 0x9d, 0x3c, 0x2a, 0xaa, 0x01, 0x03, 0x1c, 0xf1, 0xb2, 0xbf, 0x18, + 0x83, 0x89, 0x9b, 0x3e, 0x75, 0x9a, 0x2d, 0x8e, 0x7e, 0x13, 0x26, 0x3b, 0x3a, 0xa9, 0x94, 0x8b, + 0x2c, 0x9d, 0xff, 0xe5, 0xe1, 0x64, 0xdc, 0x95, 0x9b, 0x2e, 0x12, 0xd2, 0x68, 0x21, 0xd1, 0x18, + 0x0e, 0xb9, 0x8a, 0x84, 0x8c, 0xb4, 0x1d, 0xc2, 0xe4, 0xbe, 0x19, 0x09, 0xd9, 0x9a, 0x18, 0xc4, + 0x0a, 0x86, 0x7e, 0x08, 0x05, 0xcf, 0x77, 0x9a, 0x8e, 0xbb, 0x58, 0x94, 0x93, 0xb8, 0x30, 0x9c, + 0x0b, 0xe9, 0x55, 0xdc, 0x95, 0xa4, 0x91, 0xf2, 0xd5, 0xdf, 0x58, 0xb3, 0x44, 0x0f, 0x61, 0x42, + 0x19, 0x53, 0xe0, 0xa0, 0xab, 0x43, 0x07, 0x18, 0x65, 0x8f, 0x91, 0xd1, 0xab, 0xbf, 0x19, 0x0e, + 0x18, 0xa2, 0x5a, 0x18, 0x5f, 0xc6, 0x24, 0xeb, 0xb7, 0x32, 0xc4, 0x97, 0x81, 0x01, 0xa5, 0x16, + 0x06, 0x94, 0xf1, 0x2c, 0x4c, 0x65, 0xc8, 0x18, 0x14, 0x41, 0x84, 0x8a, 0x75, 0xe6, 0x52, 0x18, + 0x41, 0xc5, 0x3a, 0x6d, 0x9a, 0x89, 0xa7, 0x3b, 0x41, 0x62, 0x63, 0x7f, 0x9c, 0x87, 0x79, 0x8d, + 0x59, 0xf5, 0xda, 0x6d, 0x5a, 0x97, 0xc7, 0xa4, 0x8a, 0x4f, 0xf9, 0xd4, 0xf8, 0xe4, 0xc0, 0xb8, + 0xc3, 0x69, 0x27, 0x28, 0xc0, 0x2a, 0x99, 0x66, 0x13, 0xc9, 0x28, 0x6f, 0x08, 0x26, 0xaa, 0x06, + 0x0a, 0x77, 0x49, 0x63, 0x61, 0x25, 0x01, 0xfd, 0x89, 0x05, 0xa7, 0xf7, 0xa8, 0xef, 0xec, 0x38, + 0x75, 0x59, 0xc1, 0xdc, 0x76, 0x18, 0xf7, 0xfc, 0x7d, 0x7d, 0x22, 0xbc, 0x3b, 0x9c, 0xe4, 0xfb, + 0x06, 0x83, 0x0d, 0x77, 0xc7, 0xab, 0x7c, 0x57, 0x4b, 0x3b, 0x7d, 0xbf, 0x9f, 0x35, 0x4e, 0x93, + 0xb7, 0xd4, 0x05, 0x88, 0x66, 0x9b, 0x52, 0x40, 0x6d, 0x9a, 0x05, 0xd4, 0xd0, 0x13, 0x0b, 0x16, + 0x1b, 0x84, 0x2c, 0xb3, 0xf0, 0xfa, 0xd4, 0x82, 0x92, 0x86, 0x6f, 0x3a, 0x8c, 0xa3, 0x47, 0x7d, + 0xde, 0x5e, 0x1e, 0xce, 0xdb, 0x05, 0xb5, 0xf4, 0xf5, 0x30, 0x5f, 0x0d, 0x46, 0x0c, 0x4f, 0xc7, + 0xc1, 0x96, 0x2a, 0xc5, 0xbe, 0x93, 0x69, 0xfe, 0x51, 0x60, 0x90, 0x3a, 0xd2, 0x7b, 0x67, 0xfb, + 0x30, 0x1d, 0x73, 0x72, 0x74, 0x09, 0xc6, 0x76, 0x1d, 0x37, 0x38, 0xf5, 0x7e, 0x31, 0xc8, 0xa7, + 0x7e, 0xdd, 0x71, 0x1b, 0x4f, 0x0e, 0x56, 0xe6, 0x63, 0xc8, 0x62, 0x10, 0x4b, 0xf4, 0xa3, 0xd3, + 0xb0, 0x6b, 0x93, 0x3f, 0xfb, 0xbb, 0x95, 0x53, 0x3f, 0xf9, 0xea, 0xec, 0x29, 0xfb, 0x93, 0x3c, + 0xcc, 0x25, 0xb5, 0x3a, 0x44, 0x43, 0x22, 0x8a, 0x61, 0x93, 0x27, 0x1a, 0xc3, 0x72, 0x27, 0x17, + 0xc3, 0xf2, 0x27, 0x11, 0xc3, 0xc6, 0x8e, 0x2d, 0x86, 0xd9, 0xff, 0x6e, 0xc1, 0x4c, 0xb8, 0x33, + 0x3f, 0xea, 0x89, 0x93, 0x35, 0xd2, 0xba, 0x75, 0xfc, 0x5a, 0xff, 0x10, 0x26, 0x98, 0xd7, 0xf3, + 0xeb, 0x32, 0x7d, 0x14, 0xdc, 0x2f, 0x66, 0x0b, 0x9a, 0x8a, 0xd6, 0xc8, 0x99, 0xd4, 0x00, 0x0e, + 0xb8, 0xda, 0x8f, 0xc2, 0xf5, 0x68, 0x90, 0xca, 0x28, 0x7c, 0x91, 0x6f, 0x89, 0xf5, 0x4c, 0x9a, + 0x19, 0x85, 0x18, 0xc5, 0x1a, 0x8a, 0x6c, 0x19, 0xce, 0x83, 0xc4, 0xb6, 0x58, 0x01, 0x1d, 0x95, + 0xe5, 0x1e, 0x28, 0x88, 0xfd, 0x6d, 0x3e, 0xf4, 0x1e, 0x5d, 0xbe, 0xfe, 0x18, 0x40, 0x45, 0x26, + 0xda, 0xd8, 0x70, 0x75, 0xe8, 0xad, 0x8e, 0x70, 0x10, 0xe8, 0x70, 0x28, 0xb8, 0xa8, 0xd8, 0x1b, + 0xe6, 0x00, 0x11, 0x00, 0x1b, 0xa2, 0xd0, 0xef, 0x40, 0x89, 0xe8, 0x96, 0xc9, 0x4d, 0xcf, 0xd7, + 0x36, 0xbc, 0x3e, 0x8a, 0xe4, 0xb5, 0x88, 0x4d, 0xb2, 0xf5, 0x15, 0x41, 0xb0, 0x29, 0x6d, 0xc9, + 0x87, 0xd9, 0xc4, 0x7c, 0x53, 0xa2, 0xef, 0x46, 0x3c, 0xfa, 0x5e, 0xc8, 0x72, 0x2c, 0xe8, 0x3e, + 0x90, 0xd9, 0x33, 0x63, 0x30, 0x97, 0x9c, 0xe9, 0xb1, 0x09, 0x8d, 0x35, 0x9f, 0xcc, 0x78, 0xff, + 0xb7, 0x39, 0x28, 0x86, 0x1e, 0x9f, 0xa5, 0x4a, 0x55, 0x27, 0x75, 0xee, 0x88, 0x4a, 0x22, 0x3f, + 0x4c, 0x25, 0x31, 0x36, 0xb8, 0x92, 0x08, 0x3a, 0x59, 0x85, 0xa7, 0x77, 0xb2, 0x8c, 0x4a, 0x62, + 0x62, 0xf8, 0x4a, 0x62, 0xf2, 0xe8, 0x4a, 0xc2, 0xfe, 0x7b, 0x0b, 0x50, 0x7f, 0xd9, 0x98, 0x45, + 0x51, 0x24, 0x19, 0x87, 0x87, 0x3c, 0xa5, 0x93, 0xb5, 0xdb, 0xe0, 0x70, 0x6c, 0x7f, 0x3a, 0x0e, + 0xb3, 0xb7, 0x9c, 0x91, 0x1b, 0x0e, 0x1c, 0x5e, 0x56, 0x9c, 0x6a, 0x54, 0xe7, 0x48, 0x35, 0xee, + 0x13, 0x4e, 0x9b, 0xfb, 0x7a, 0x7f, 0xaf, 0x69, 0xd2, 0x97, 0xab, 0xe9, 0x68, 0x4f, 0x06, 0x83, + 0xf0, 0x20, 0xd6, 0x43, 0x1b, 0xc9, 0x7b, 0x30, 0xcd, 0xb8, 0xef, 0xd4, 0xb9, 0x6a, 0x69, 0xb0, + 0xc5, 0x92, 0x8c, 0x72, 0x67, 0x34, 0xfa, 0x74, 0xcd, 0x04, 0xe2, 0x38, 0x6e, 0x6a, 0xa7, 0x64, + 0x2c, 0x73, 0xa7, 0x64, 0x15, 0x8a, 0xa4, 0xdd, 0xf6, 0x7e, 0x7c, 0x8f, 0x34, 0x99, 0x2e, 0x55, + 0x43, 0xab, 0x59, 0x0b, 0x00, 0x38, 0xc2, 0x41, 0x65, 0x00, 0xa7, 0xe9, 0x7a, 0x3e, 0x95, 0x14, + 0x05, 0x19, 0x6e, 0x67, 0x44, 0xac, 0xdb, 0x08, 0x47, 0xb1, 0x81, 0x81, 0x6a, 0x70, 0xc6, 0x71, + 0x19, 0xad, 0xf7, 0x7c, 0x5a, 0xdb, 0x75, 0xba, 0xf7, 0x36, 0x6b, 0x32, 0x4a, 0xec, 0x4b, 0x6b, + 0x9e, 0xac, 0xbc, 0xa2, 0x85, 0x9d, 0xd9, 0x48, 0x43, 0xc2, 0xe9, 0xb4, 0xe8, 0x22, 0x4c, 0x39, + 0x6e, 0xbd, 0xdd, 0x6b, 0xd0, 0x2d, 0xc2, 0x5b, 0x6c, 0x71, 0x52, 0x4e, 0x63, 0xee, 0xf0, 0x60, + 0x65, 0x6a, 0xc3, 0x18, 0xc7, 0x31, 0x2c, 0x41, 0x45, 0x3f, 0x32, 0xa8, 0x8a, 0x11, 0xd5, 0x8d, + 0x8f, 0x4c, 0x2a, 0x13, 0x2b, 0xa5, 0x97, 0x04, 0x99, 0x7a, 0x49, 0x7f, 0x95, 0x87, 0x82, 0x6a, + 0xe5, 0xa2, 0x4b, 0x89, 0x7e, 0xe9, 0x2b, 0x7d, 0xfd, 0xd2, 0x52, 0x5a, 0xdb, 0xdb, 0x86, 0x82, + 0xc3, 0x58, 0x2f, 0x7e, 0xba, 0x6d, 0xc8, 0x11, 0xac, 0x21, 0xc8, 0x01, 0x20, 0x41, 0xab, 0x35, + 0x48, 0x5d, 0x2e, 0x65, 0xed, 0x08, 0x27, 0xba, 0xc1, 0x21, 0x80, 0x61, 0x83, 0xb9, 0xec, 0xf0, + 0x78, 0xee, 0x8e, 0xd3, 0xd4, 0x75, 0xf8, 0x75, 0x23, 0x6b, 0x8e, 0x6e, 0xdf, 0x3e, 0x0c, 0xaf, + 0xe7, 0xa2, 0x04, 0x3a, 0x86, 0x20, 0x32, 0xe9, 0x3b, 0xb5, 0xbb, 0xef, 0xab, 0xe5, 0x54, 0x25, + 0x47, 0xac, 0x39, 0x0b, 0x19, 0x5e, 0x8f, 0x77, 0x7b, 0x5c, 0xda, 0xe4, 0x31, 0xc9, 0xb8, 0x2b, + 0x39, 0x62, 0xcd, 0xd9, 0xfe, 0xc4, 0x82, 0x59, 0xa5, 0xee, 0x6a, 0x8b, 0xd6, 0x77, 0x6b, 0x9c, + 0x76, 0x45, 0x62, 0xdb, 0x63, 0x94, 0x25, 0x13, 0xdb, 0x0f, 0x18, 0x65, 0x58, 0x42, 0x8c, 0xd5, + 0xe7, 0x4e, 0x6a, 0xf5, 0xf6, 0x3f, 0x5a, 0x30, 0x2e, 0x33, 0xc8, 0x2c, 0xa1, 0x2e, 0xde, 0x55, + 0xc9, 0x0d, 0xd5, 0x55, 0x39, 0xa2, 0xdf, 0x15, 0x35, 0x74, 0xc6, 0x9e, 0xd6, 0xd0, 0xb1, 0xbf, + 0xb1, 0x60, 0x21, 0xad, 0x49, 0x98, 0x65, 0xfa, 0x6f, 0xc3, 0x64, 0xb7, 0x4d, 0xf8, 0x8e, 0xe7, + 0x77, 0x92, 0xb7, 0x01, 0x5b, 0x7a, 0x1c, 0x87, 0x18, 0xc8, 0x07, 0xf0, 0x83, 0x6a, 0x24, 0x30, + 0xf7, 0xeb, 0x59, 0x0f, 0x9f, 0x78, 0x77, 0x2b, 0x52, 0x56, 0x38, 0xc4, 0xb0, 0x21, 0xc5, 0xfe, + 0xd3, 0x71, 0x98, 0x97, 0x24, 0xa3, 0x1e, 0x46, 0xa3, 0xec, 0x50, 0x17, 0x5e, 0x92, 0x35, 0x44, + 0xff, 0xf9, 0xa5, 0x36, 0xed, 0x8a, 0xa6, 0x7f, 0x69, 0x23, 0x15, 0xeb, 0xc9, 0x40, 0x08, 0x1e, + 0xc0, 0xb7, 0xff, 0x50, 0x82, 0x9f, 0xbf, 0x43, 0xc9, 0x34, 0xb6, 0x89, 0x23, 0x8d, 0x6d, 0xe0, + 0x11, 0x36, 0xf9, 0x0c, 0x47, 0x58, 0xff, 0xb1, 0x52, 0xcc, 0x74, 0xac, 0xfc, 0x75, 0x0e, 0x26, + 0xb6, 0x7c, 0x4f, 0x36, 0x9b, 0x4f, 0xbe, 0x6f, 0x79, 0x17, 0xc6, 0x58, 0x97, 0xd6, 0x75, 0xcc, + 0x3b, 0x37, 0x9c, 0xa7, 0xe9, 0xe9, 0xd5, 0xba, 0xb4, 0x5e, 0x99, 0x14, 0x61, 0x54, 0xfc, 0xc2, + 0x92, 0x91, 0xd1, 0x80, 0xcb, 0x67, 0x49, 0xf6, 0x03, 0x96, 0x4f, 0x6f, 0xc0, 0x7d, 0x6a, 0x41, + 0x49, 0x63, 0xbe, 0xb0, 0x9d, 0x1e, 0x3d, 0xbf, 0x01, 0x9d, 0x9e, 0x3f, 0x8f, 0x56, 0x20, 0x94, + 0x86, 0x7e, 0x0f, 0xe6, 0xbb, 0xbe, 0xd7, 0xf1, 0x84, 0xa7, 0x6e, 0x79, 0x6d, 0xa7, 0xee, 0xd0, + 0xa0, 0x59, 0x78, 0x69, 0x68, 0x79, 0x06, 0xf9, 0x7e, 0xe5, 0x3b, 0x5a, 0xee, 0xfc, 0x56, 0x92, + 0x2f, 0xee, 0x17, 0x65, 0xff, 0x97, 0x05, 0xd3, 0x31, 0xdd, 0xa3, 0x3a, 0x40, 0xdd, 0x73, 0x1b, + 0x0e, 0x0f, 0x2f, 0x64, 0x4b, 0xe7, 0x57, 0x87, 0xd3, 0x6a, 0x35, 0xa0, 0x8b, 0x8c, 0x2e, 0x1c, + 0x62, 0xd8, 0x60, 0x8b, 0x2e, 0x04, 0xef, 0x17, 0xe2, 0xf9, 0x92, 0x7a, 0xbf, 0xf0, 0xe4, 0x60, + 0x65, 0x4a, 0xcf, 0xc9, 0x7c, 0xcf, 0x90, 0xe5, 0x95, 0xc0, 0x3f, 0xe4, 0xa0, 0x18, 0xae, 0xff, + 0x39, 0xb8, 0xd1, 0x07, 0x31, 0x37, 0xba, 0x90, 0x71, 0xe7, 0xa4, 0x23, 0x85, 0x39, 0x89, 0xe1, + 0x4c, 0x8f, 0x13, 0xce, 0x94, 0xd5, 0x24, 0x8e, 0x70, 0xa7, 0x7f, 0x51, 0x9b, 0xaf, 0x70, 0x9f, + 0x83, 0x43, 0xdd, 0x8b, 0x3b, 0xd4, 0x6a, 0xc6, 0xd5, 0x0c, 0x70, 0xa9, 0x9f, 0x5a, 0x30, 0x9b, + 0x70, 0x02, 0xf4, 0x2a, 0x8c, 0xcb, 0xee, 0x90, 0xb6, 0xaf, 0x90, 0x50, 0xf7, 0x12, 0x24, 0x0c, + 0x6d, 0xc1, 0x02, 0xe9, 0x71, 0x2f, 0xa4, 0xbd, 0xe1, 0x92, 0xed, 0x36, 0x55, 0x0d, 0x82, 0xc9, + 0xca, 0x2f, 0x68, 0x9a, 0x85, 0xb5, 0x14, 0x1c, 0x9c, 0x4a, 0x69, 0x7f, 0x9e, 0x03, 0x14, 0x0e, + 0x66, 0xe9, 0xaa, 0x3e, 0x86, 0x89, 0x1d, 0xd5, 0xff, 0x79, 0xb6, 0xb6, 0x78, 0xa5, 0x64, 0xde, + 0x0c, 0x04, 0x3c, 0xd1, 0x0f, 0x8e, 0xc7, 0x8e, 0xa0, 0xdf, 0x86, 0xd0, 0x43, 0x80, 0x1d, 0xc7, + 0x75, 0x58, 0x6b, 0xc4, 0x0b, 0x3c, 0x79, 0x9a, 0xdf, 0x0c, 0x39, 0x60, 0x83, 0x9b, 0xfd, 0x71, + 0xce, 0xb0, 0x4f, 0x19, 0x2e, 0x87, 0xda, 0xd7, 0x37, 0xe3, 0xca, 0x2c, 0xf6, 0x5f, 0x99, 0x18, + 0x8a, 0x19, 0xdb, 0x23, 0x7e, 0xd0, 0xbd, 0xbd, 0x9c, 0x51, 0x2d, 0xf7, 0x89, 0xef, 0x88, 0x8d, + 0x8f, 0xb6, 0xf4, 0x3e, 0xf1, 0x19, 0x96, 0x2c, 0xd1, 0xf7, 0xc5, 0x54, 0x69, 0x58, 0xb3, 0x65, + 0x8e, 0x09, 0x9c, 0x76, 0xcd, 0xf5, 0xd1, 0x2e, 0xc3, 0x8a, 0xa1, 0xfd, 0x6f, 0x05, 0xc3, 0xe0, + 0x75, 0xd4, 0xbe, 0x03, 0xa8, 0x4d, 0x18, 0xbf, 0x4d, 0xdc, 0x86, 0x30, 0x4f, 0xba, 0xe3, 0x53, + 0xd6, 0xd2, 0x19, 0xda, 0x92, 0xe6, 0x82, 0x36, 0xfb, 0x30, 0x70, 0x0a, 0x15, 0xba, 0x14, 0x0f, + 0xce, 0x2b, 0xc9, 0xe0, 0x3c, 0x13, 0x79, 0xdb, 0x68, 0xe1, 0xd9, 0x34, 0xf7, 0xf1, 0x13, 0x30, + 0xf7, 0xdf, 0x85, 0xf9, 0x9d, 0xe4, 0x15, 0x9a, 0xbe, 0x50, 0xbf, 0x3c, 0xe2, 0x0d, 0x5c, 0xe5, + 0xcc, 0x61, 0x74, 0xef, 0x12, 0x0d, 0xe3, 0x7e, 0x41, 0xc8, 0x0b, 0x9e, 0x8e, 0xc9, 0xea, 0x53, + 0xf5, 0x30, 0x86, 0x76, 0xb9, 0x44, 0xdd, 0x9a, 0x7c, 0x34, 0xa6, 0x58, 0xe2, 0x98, 0x80, 0x84, + 0x0b, 0x16, 0x8e, 0xd3, 0x05, 0xd1, 0x25, 0x28, 0xd5, 0x7b, 0xbe, 0x4f, 0x5d, 0x2e, 0xa6, 0x23, + 0x53, 0xd9, 0x7c, 0xd4, 0x8b, 0xae, 0x46, 0x20, 0x6c, 0xe2, 0x09, 0x73, 0x34, 0xfe, 0x5c, 0xe3, + 0x9c, 0x76, 0xba, 0x5c, 0x76, 0xc1, 0xf2, 0x91, 0x39, 0x56, 0xfb, 0x30, 0x70, 0x0a, 0x15, 0xfa, + 0x50, 0xfa, 0x3c, 0xa7, 0xb2, 0x5e, 0x79, 0xf6, 0xba, 0xbc, 0xa8, 0xe3, 0x05, 0x57, 0xf1, 0x82, + 0x53, 0xfb, 0xcf, 0x62, 0x61, 0x66, 0xb8, 0x6e, 0xc1, 0x12, 0xe4, 0x08, 0x4b, 0xb6, 0x92, 0xd7, + 0x18, 0xce, 0x11, 0x86, 0x7e, 0x00, 0xe3, 0x3e, 0xe5, 0xfe, 0xbe, 0x8e, 0x86, 0x57, 0x46, 0xf0, + 0x7c, 0x2c, 0xe8, 0xd5, 0x54, 0xe5, 0x4f, 0xac, 0x38, 0x1a, 0x4d, 0x8a, 0xfc, 0x89, 0x35, 0x29, + 0x2a, 0xc6, 0x19, 0x16, 0xce, 0x45, 0x54, 0x56, 0x44, 0x6d, 0x88, 0x52, 0x4b, 0x3e, 0x3a, 0xe9, + 0xf5, 0x46, 0x31, 0x1c, 0x62, 0xd8, 0x3e, 0x44, 0xe9, 0x67, 0xf0, 0xf6, 0x14, 0x3d, 0xd6, 0x49, + 0x92, 0x95, 0xe5, 0x2d, 0x65, 0x1f, 0x9b, 0x41, 0xc9, 0x92, 0xfd, 0xb9, 0x05, 0x67, 0x52, 0xb1, + 0xc3, 0x28, 0x9f, 0x3b, 0xc1, 0x28, 0x6f, 0x1d, 0x77, 0x94, 0x7f, 0x68, 0xa8, 0x30, 0x98, 0xc2, + 0x71, 0x3d, 0x18, 0xff, 0x59, 0x0e, 0xe6, 0x30, 0xed, 0x7a, 0xb1, 0x86, 0xc7, 0x56, 0xf0, 0x3a, + 0x2d, 0x43, 0x86, 0x90, 0xe8, 0xe0, 0x57, 0x26, 0x62, 0xcf, 0xd2, 0xbe, 0x0f, 0xe3, 0xb2, 0x17, + 0xa1, 0x73, 0x9a, 0xcb, 0x19, 0x6e, 0x5c, 0x63, 0x5c, 0xa5, 0x1f, 0xa8, 0xa6, 0x8e, 0x62, 0x28, + 0x38, 0xcb, 0xcb, 0x52, 0xed, 0x06, 0x97, 0x33, 0x5c, 0xbb, 0xf6, 0x73, 0x96, 0xc3, 0x58, 0x31, + 0xb4, 0x3f, 0xc9, 0x81, 0xca, 0x26, 0x9e, 0x43, 0xd5, 0xf0, 0x1b, 0xb1, 0xaa, 0x61, 0xc8, 0x74, + 0x58, 0x4e, 0x6e, 0x60, 0xc5, 0x90, 0xcc, 0xf4, 0xce, 0x65, 0x61, 0xfa, 0xf4, 0x6a, 0xe1, 0x9f, + 0x2d, 0x28, 0x4a, 0xbc, 0xe7, 0x50, 0x29, 0x6c, 0xc5, 0x2b, 0x85, 0xb7, 0x32, 0xac, 0x62, 0x40, + 0x95, 0xf0, 0x71, 0x5e, 0xcf, 0x3e, 0xcc, 0x23, 0x5b, 0xc4, 0x6f, 0xe8, 0x0c, 0x29, 0xf2, 0x40, + 0x31, 0x88, 0x15, 0x0c, 0xfd, 0x36, 0xcc, 0xf9, 0xea, 0xfe, 0x9d, 0x36, 0x6e, 0x86, 0xe9, 0x4a, + 0x3e, 0xf3, 0x05, 0xb9, 0xbe, 0xc4, 0x8f, 0x3a, 0x65, 0x38, 0xc1, 0x15, 0xf7, 0xc9, 0x11, 0x29, + 0x4c, 0x37, 0x19, 0xcb, 0xf4, 0xd1, 0x7e, 0x79, 0xc4, 0xc0, 0xa9, 0x52, 0x98, 0xbe, 0x61, 0xdc, + 0x2f, 0x08, 0xb5, 0x60, 0xca, 0x7c, 0xda, 0xa3, 0x6d, 0xe9, 0x7c, 0xf6, 0x37, 0x44, 0xea, 0x12, + 0xc6, 0x1c, 0xc1, 0x31, 0xce, 0xf6, 0x41, 0x01, 0x4a, 0x86, 0xf1, 0x25, 0xba, 0x0f, 0xd3, 0x27, + 0xd3, 0x7d, 0x48, 0x4f, 0x96, 0x4b, 0x23, 0x25, 0xcb, 0xe7, 0xe2, 0xc9, 0xf2, 0x77, 0x93, 0xc9, + 0x32, 0xc8, 0xd5, 0xc5, 0x12, 0x65, 0x06, 0x33, 0x3a, 0x6b, 0x0c, 0xde, 0x68, 0x65, 0x2a, 0x3f, + 0xfa, 0x73, 0x53, 0x74, 0x78, 0xb0, 0x12, 0xbc, 0xb0, 0x08, 0xde, 0x66, 0x25, 0x44, 0xa0, 0xeb, + 0xa1, 0xd0, 0x5a, 0xaf, 0xd3, 0x21, 0xfe, 0xfe, 0xe2, 0x94, 0x9c, 0x70, 0xd8, 0x96, 0xbc, 0x19, + 0x83, 0xe2, 0x04, 0x36, 0xda, 0x82, 0x82, 0x4a, 0x3a, 0xf5, 0xbb, 0x9f, 0xb7, 0xb3, 0xe4, 0xb3, + 0x2a, 0xcf, 0x50, 0xbf, 0xb1, 0xe6, 0x63, 0xd6, 0x0b, 0xc5, 0x23, 0xea, 0x85, 0x3b, 0x80, 0xbc, + 0x6d, 0x99, 0xd1, 0x34, 0x6e, 0xa9, 0x2f, 0xab, 0x84, 0x55, 0x16, 0xe2, 0xe9, 0xe4, 0xdd, 0x3e, + 0x0c, 0x9c, 0x42, 0x25, 0xbc, 0x5a, 0x27, 0x99, 0xa1, 0x2b, 0xe8, 0xda, 0x20, 0x6b, 0xa2, 0x16, + 0x95, 0x21, 0x0b, 0xc2, 0xab, 0xab, 0x09, 0xae, 0xb8, 0x4f, 0x0e, 0xfa, 0x11, 0x4c, 0x0b, 0x13, + 0x8a, 0x04, 0xc3, 0x33, 0x0a, 0x9e, 0x3f, 0x3c, 0x58, 0x99, 0xde, 0x34, 0x59, 0xe2, 0xb8, 0x04, + 0xfb, 0xff, 0x72, 0x10, 0xf3, 0x3f, 0xf4, 0x53, 0x0b, 0xe6, 0x49, 0xe2, 0xb3, 0xa0, 0x20, 0x7d, + 0xf9, 0xb5, 0x6c, 0xdf, 0x6a, 0xf5, 0x7d, 0x55, 0x14, 0x35, 0x1f, 0x93, 0x28, 0x0c, 0xf7, 0x0b, + 0x45, 0x7f, 0x6c, 0xc1, 0x69, 0xd2, 0xff, 0xdd, 0x97, 0x3e, 0x0f, 0xaf, 0x8e, 0xfc, 0xe1, 0x58, + 0xe5, 0xe5, 0xc3, 0x83, 0x95, 0xb4, 0x2f, 0xe2, 0x70, 0x9a, 0x38, 0xf4, 0x43, 0x18, 0x23, 0x7e, + 0x33, 0x28, 0xd4, 0xb3, 0x8b, 0x0d, 0x3e, 0xe7, 0x8b, 0x0e, 0xe4, 0x35, 0xbf, 0xc9, 0xb0, 0x64, + 0x6a, 0x7f, 0x95, 0x87, 0xb9, 0xe4, 0xab, 0x4a, 0xfd, 0x10, 0x65, 0x2c, 0xf5, 0x21, 0xca, 0xab, + 0x30, 0x4e, 0xea, 0x3c, 0x7c, 0x15, 0x12, 0xbd, 0x24, 0x16, 0x83, 0x58, 0xc1, 0xd0, 0x03, 0x28, + 0x32, 0x4e, 0x7c, 0x2e, 0xea, 0x37, 0x5d, 0x42, 0x67, 0x7e, 0x35, 0x5d, 0x0b, 0x18, 0xe0, 0x88, + 0x17, 0xba, 0x12, 0x0f, 0x67, 0x76, 0x32, 0x9c, 0xcd, 0x9b, 0x6b, 0x19, 0xb5, 0xfc, 0xef, 0x40, + 0xc9, 0xd8, 0x07, 0x7d, 0xba, 0x5c, 0xcb, 0xac, 0xf7, 0xc8, 0xec, 0x66, 0xd5, 0x37, 0x81, 0x11, + 0xc4, 0xe4, 0x1f, 0xd5, 0xc7, 0x52, 0x5b, 0xcf, 0x54, 0x1f, 0x4b, 0x75, 0x19, 0xdc, 0xec, 0x59, + 0x98, 0x8e, 0x3d, 0x8e, 0x92, 0x9d, 0xe7, 0x07, 0xc4, 0xa7, 0x2d, 0xaf, 0xc7, 0xe8, 0x8b, 0xda, + 0x79, 0x0e, 0x27, 0x78, 0xdc, 0x9d, 0xe7, 0x88, 0xf1, 0xd1, 0x9d, 0xe7, 0x10, 0xf7, 0x85, 0xed, + 0x3c, 0x87, 0x33, 0x1c, 0x90, 0x53, 0xfe, 0x6f, 0xce, 0x58, 0x45, 0x3c, 0xaf, 0xcc, 0x3d, 0x25, + 0xaf, 0x7c, 0x04, 0x93, 0x8e, 0xcb, 0xa9, 0xbf, 0x47, 0xda, 0xba, 0x45, 0x30, 0xe4, 0x52, 0xd7, + 0x7b, 0xbe, 0xce, 0xaa, 0x82, 0xa5, 0x6e, 0x68, 0x3e, 0x38, 0xe4, 0x88, 0xda, 0x70, 0x26, 0xe8, + 0x49, 0xf9, 0x94, 0x44, 0x3d, 0x71, 0x7d, 0xaf, 0xfc, 0x6e, 0x70, 0xa9, 0x79, 0x33, 0x0d, 0xe9, + 0xc9, 0x20, 0x00, 0x4e, 0x67, 0x8a, 0x18, 0x4c, 0x33, 0xa3, 0xa0, 0x0a, 0x0e, 0x92, 0x21, 0xfb, + 0x79, 0xc9, 0x1a, 0xd4, 0xb8, 0x8c, 0x36, 0x99, 0xe2, 0xb8, 0x0c, 0xfb, 0x3f, 0xf2, 0x30, 0x9b, + 0xb0, 0xb4, 0x44, 0xe2, 0x58, 0x7c, 0x9e, 0x89, 0x63, 0x61, 0xa4, 0xc4, 0x31, 0x3d, 0xa7, 0x19, + 0x1b, 0x29, 0xa7, 0x79, 0x4f, 0xe5, 0x15, 0x7a, 0xe7, 0x36, 0xd6, 0xf5, 0x33, 0xc1, 0x50, 0x9b, + 0x9b, 0x26, 0x10, 0xc7, 0x71, 0xe5, 0x29, 0xdc, 0xe8, 0xff, 0x26, 0x4e, 0x27, 0x45, 0x57, 0xb3, + 0x3e, 0xbe, 0x08, 0x19, 0xa8, 0x53, 0x38, 0x05, 0x80, 0xd3, 0xc4, 0x55, 0xee, 0x7c, 0xf6, 0xf5, + 0xf2, 0xa9, 0x2f, 0xbe, 0x5e, 0x3e, 0xf5, 0xe5, 0xd7, 0xcb, 0xa7, 0x7e, 0x72, 0xb8, 0x6c, 0x7d, + 0x76, 0xb8, 0x6c, 0x7d, 0x71, 0xb8, 0x6c, 0x7d, 0x79, 0xb8, 0x6c, 0xfd, 0xf7, 0xe1, 0xb2, 0xf5, + 0x97, 0xdf, 0x2c, 0x9f, 0x7a, 0xf8, 0xda, 0x30, 0xff, 0xbc, 0xe0, 0xff, 0x03, 0x00, 0x00, 0xff, + 0xff, 0x90, 0x47, 0xd6, 0xce, 0xe3, 0x40, 0x00, 0x00, } func (m *AnalysisRunArgument) Marshal() (dAtA []byte, err error) { @@ -3927,32 +3927,6 @@ func (m *PromotionReference) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *PromotionRetry) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *PromotionRetry) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *PromotionRetry) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - i = encodeVarintGenerated(dAtA, i, uint64(m.Attempts)) - i-- - dAtA[i] = 0x8 - return len(dAtA) - i, nil -} - func (m *PromotionSpec) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4177,6 +4151,32 @@ func (m *PromotionStep) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *PromotionStepRetry) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PromotionStepRetry) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PromotionStepRetry) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + i = encodeVarintGenerated(dAtA, i, uint64(m.Attempts)) + i-- + dAtA[i] = 0x8 + return len(dAtA) - i, nil +} + func (m *PromotionTemplate) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -5776,16 +5776,6 @@ func (m *PromotionReference) Size() (n int) { return n } -func (m *PromotionRetry) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - n += 1 + sovGenerated(uint64(m.Attempts)) - return n -} - func (m *PromotionSpec) Size() (n int) { if m == nil { return 0 @@ -5871,6 +5861,16 @@ func (m *PromotionStep) Size() (n int) { return n } +func (m *PromotionStepRetry) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + n += 1 + sovGenerated(uint64(m.Attempts)) + return n +} + func (m *PromotionTemplate) Size() (n int) { if m == nil { return 0 @@ -6785,16 +6785,6 @@ func (this *PromotionReference) String() string { }, "") return s } -func (this *PromotionRetry) String() string { - if this == nil { - return "nil" - } - s := strings.Join([]string{`&PromotionRetry{`, - `Attempts:` + fmt.Sprintf("%v", this.Attempts) + `,`, - `}`, - }, "") - return s -} func (this *PromotionSpec) String() string { if this == nil { return "nil" @@ -6850,7 +6840,17 @@ func (this *PromotionStep) String() string { `Uses:` + fmt.Sprintf("%v", this.Uses) + `,`, `As:` + fmt.Sprintf("%v", this.As) + `,`, `Config:` + strings.Replace(fmt.Sprintf("%v", this.Config), "JSON", "v11.JSON", 1) + `,`, - `Retry:` + strings.Replace(this.Retry.String(), "PromotionRetry", "PromotionRetry", 1) + `,`, + `Retry:` + strings.Replace(this.Retry.String(), "PromotionStepRetry", "PromotionStepRetry", 1) + `,`, + `}`, + }, "") + return s +} +func (this *PromotionStepRetry) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&PromotionStepRetry{`, + `Attempts:` + fmt.Sprintf("%v", this.Attempts) + `,`, `}`, }, "") return s @@ -13687,75 +13687,6 @@ func (m *PromotionReference) Unmarshal(dAtA []byte) error { } return nil } -func (m *PromotionRetry) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: PromotionRetry: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: PromotionRetry: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Attempts", wireType) - } - m.Attempts = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenerated - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Attempts |= int64(b&0x7F) << shift - if b < 0x80 { - break - } - } - default: - iNdEx = preIndex - skippy, err := skipGenerated(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenerated - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *PromotionSpec) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -14459,7 +14390,7 @@ func (m *PromotionStep) Unmarshal(dAtA []byte) error { return io.ErrUnexpectedEOF } if m.Retry == nil { - m.Retry = &PromotionRetry{} + m.Retry = &PromotionStepRetry{} } if err := m.Retry.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { return err @@ -14486,6 +14417,75 @@ func (m *PromotionStep) Unmarshal(dAtA []byte) error { } return nil } +func (m *PromotionStepRetry) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PromotionStepRetry: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PromotionStepRetry: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Attempts", wireType) + } + m.Attempts = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Attempts |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *PromotionTemplate) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/api/v1alpha1/generated.proto b/api/v1alpha1/generated.proto index 711211022..08f411a1c 100644 --- a/api/v1alpha1/generated.proto +++ b/api/v1alpha1/generated.proto @@ -835,19 +835,6 @@ message PromotionReference { optional .k8s.io.apimachinery.pkg.apis.meta.v1.Time finishedAt = 4; } -// PromotionRetry describes the retry policy for a PromotionStep. -message PromotionRetry { - // Attempts is the number of times the step can be attempted before the - // PromotionStep is marked as failed. - // - // If this field is set to 1, the step will not be retried. If this - // field is set to -1, the step will be retried indefinitely. - // - // The default of this field depends on the step being executed. Refer to - // the documentation for the specific step for more information. - optional int64 attempts = 1; -} - // PromotionSpec describes the desired transition of a specific Stage into a // specific Freight. message PromotionSpec { @@ -933,7 +920,7 @@ message PromotionStep { optional string as = 2; // Retry is the retry policy for this step. - optional PromotionRetry retry = 4; + optional PromotionStepRetry retry = 4; // Config is opaque configuration for the PromotionStep that is understood // only by each PromotionStep's implementation. It is legal to utilize @@ -942,6 +929,19 @@ message PromotionStep { optional .k8s.io.apiextensions_apiserver.pkg.apis.apiextensions.v1.JSON config = 3; } +// PromotionStepRetry describes the retry policy for a PromotionStep. +message PromotionStepRetry { + // Attempts is the number of times the step can be attempted before the + // PromotionStep is marked as failed. + // + // If this field is set to 1, the step will not be retried. If this + // field is set to -1, the step will be retried indefinitely. + // + // The default of this field depends on the step being executed. Refer to + // the documentation for the specific step for more information. + optional int64 attempts = 1; +} + // PromotionTemplate defines a template for a Promotion that can be used to // incorporate Freight into a Stage. message PromotionTemplate { diff --git a/api/v1alpha1/promotion_types.go b/api/v1alpha1/promotion_types.go index 8debee21f..7ae3a3651 100644 --- a/api/v1alpha1/promotion_types.go +++ b/api/v1alpha1/promotion_types.go @@ -109,8 +109,8 @@ type PromotionVariable struct { Value string `json:"value" protobuf:"bytes,2,opt,name=value"` } -// PromotionRetry describes the retry policy for a PromotionStep. -type PromotionRetry struct { +// PromotionStepRetry describes the retry policy for a PromotionStep. +type PromotionStepRetry struct { // Attempts is the number of times the step can be attempted before the // PromotionStep is marked as failed. // @@ -123,7 +123,7 @@ type PromotionRetry struct { } // GetAttempts returns the Attempts field with the given fallback value. -func (r *PromotionRetry) GetAttempts(fallback int64) int64 { +func (r *PromotionStepRetry) GetAttempts(fallback int64) int64 { if r == nil || r.Attempts == 0 { return fallback } @@ -139,7 +139,7 @@ type PromotionStep struct { // As is the alias this step can be referred to as. As string `json:"as,omitempty" protobuf:"bytes,2,opt,name=as"` // Retry is the retry policy for this step. - Retry *PromotionRetry `json:"retry,omitempty" protobuf:"bytes,4,opt,name=retry"` + Retry *PromotionStepRetry `json:"retry,omitempty" protobuf:"bytes,4,opt,name=retry"` // Config is opaque configuration for the PromotionStep that is understood // only by each PromotionStep's implementation. It is legal to utilize // expressions in defining values at any level of this block. diff --git a/api/v1alpha1/promotion_types_test.go b/api/v1alpha1/promotion_types_test.go index f608f7c7b..980662786 100644 --- a/api/v1alpha1/promotion_types_test.go +++ b/api/v1alpha1/promotion_types_test.go @@ -9,7 +9,7 @@ import ( func TestPromotionRetry_GetAttempts(t *testing.T) { tests := []struct { name string - retry *PromotionRetry + retry *PromotionStepRetry fallback int64 want int64 }{ @@ -21,13 +21,13 @@ func TestPromotionRetry_GetAttempts(t *testing.T) { }, { name: "attempts is not set", - retry: &PromotionRetry{}, + retry: &PromotionStepRetry{}, fallback: -1, want: -1, }, { name: "attempts is set", - retry: &PromotionRetry{ + retry: &PromotionStepRetry{ Attempts: 3, }, want: 3, diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 23abc12ad..efe94eef0 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -905,21 +905,6 @@ func (in *PromotionReference) DeepCopy() *PromotionReference { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PromotionRetry) DeepCopyInto(out *PromotionRetry) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromotionRetry. -func (in *PromotionRetry) DeepCopy() *PromotionRetry { - if in == nil { - return nil - } - out := new(PromotionRetry) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PromotionSpec) DeepCopyInto(out *PromotionSpec) { *out = *in @@ -993,7 +978,7 @@ func (in *PromotionStep) DeepCopyInto(out *PromotionStep) { *out = *in if in.Retry != nil { in, out := &in.Retry, &out.Retry - *out = new(PromotionRetry) + *out = new(PromotionStepRetry) **out = **in } if in.Config != nil { @@ -1013,6 +998,21 @@ func (in *PromotionStep) DeepCopy() *PromotionStep { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PromotionStepRetry) DeepCopyInto(out *PromotionStepRetry) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PromotionStepRetry. +func (in *PromotionStepRetry) DeepCopy() *PromotionStepRetry { + if in == nil { + return nil + } + out := new(PromotionStepRetry) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PromotionTemplate) DeepCopyInto(out *PromotionTemplate) { *out = *in diff --git a/internal/directives/promotions.go b/internal/directives/promotions.go index bf25c84a7..7c965d793 100644 --- a/internal/directives/promotions.go +++ b/internal/directives/promotions.go @@ -90,7 +90,7 @@ type PromotionStep struct { // subsequent steps. Alias string // Retry is the retry configuration for the PromotionStep. - Retry *kargoapi.PromotionRetry + Retry *kargoapi.PromotionStepRetry // Config is an opaque JSON to be passed to the PromotionStepRunner executing // this step. Config []byte diff --git a/internal/directives/promotions_test.go b/internal/directives/promotions_test.go index a97c305c8..217440ab2 100644 --- a/internal/directives/promotions_test.go +++ b/internal/directives/promotions_test.go @@ -37,7 +37,7 @@ func TestPromotionStep_GetMaxAttempts(t *testing.T) { { name: "returns configured attempts for non-retryable runner", step: &PromotionStep{ - Retry: &kargoapi.PromotionRetry{ + Retry: &kargoapi.PromotionStepRetry{ Attempts: 5, }, }, @@ -49,7 +49,7 @@ func TestPromotionStep_GetMaxAttempts(t *testing.T) { { name: "returns configured attempts for retryable runner", step: &PromotionStep{ - Retry: &kargoapi.PromotionRetry{ + Retry: &kargoapi.PromotionStepRetry{ Attempts: 5, }, }, @@ -61,7 +61,7 @@ func TestPromotionStep_GetMaxAttempts(t *testing.T) { { name: "returns default attempts when retry config returns 0", step: &PromotionStep{ - Retry: &kargoapi.PromotionRetry{ + Retry: &kargoapi.PromotionStepRetry{ Attempts: 0, }, }, diff --git a/internal/directives/simple_engine_promote_test.go b/internal/directives/simple_engine_promote_test.go index d17275b6f..ed1a5cc4c 100644 --- a/internal/directives/simple_engine_promote_test.go +++ b/internal/directives/simple_engine_promote_test.go @@ -242,7 +242,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) { { Kind: "error-step", Alias: "step1", - Retry: &kargoapi.PromotionRetry{Attempts: 3}, + Retry: &kargoapi.PromotionStepRetry{Attempts: 3}, }, }, assertions: func(t *testing.T, result PromotionResult, err error) { @@ -262,7 +262,7 @@ func TestSimpleEngine_executeSteps(t *testing.T) { { Kind: "error-step", Alias: "step1", - Retry: &kargoapi.PromotionRetry{Attempts: 3}, + Retry: &kargoapi.PromotionStepRetry{Attempts: 3}, }, }, assertions: func(t *testing.T, result PromotionResult, err error) { diff --git a/ui/src/gen/v1alpha1/generated_pb.ts b/ui/src/gen/v1alpha1/generated_pb.ts index ad35db92b..c4ee4ec77 100644 --- a/ui/src/gen/v1alpha1/generated_pb.ts +++ b/ui/src/gen/v1alpha1/generated_pb.ts @@ -2616,54 +2616,6 @@ export class PromotionReference extends Message { } } -/** - * PromotionRetry describes the retry policy for a PromotionStep. - * - * @generated from message github.com.akuity.kargo.api.v1alpha1.PromotionRetry - */ -export class PromotionRetry extends Message { - /** - * Attempts is the number of times the step can be attempted before the - * PromotionStep is marked as failed. - * - * If this field is set to 1, the step will not be retried. If this - * field is set to -1, the step will be retried indefinitely. - * - * The default of this field depends on the step being executed. Refer to - * the documentation for the specific step for more information. - * - * @generated from field: optional int64 attempts = 1; - */ - attempts?: bigint; - - constructor(data?: PartialMessage) { - super(); - proto2.util.initPartial(data, this); - } - - static readonly runtime: typeof proto2 = proto2; - static readonly typeName = "github.com.akuity.kargo.api.v1alpha1.PromotionRetry"; - static readonly fields: FieldList = proto2.util.newFieldList(() => [ - { no: 1, name: "attempts", kind: "scalar", T: 3 /* ScalarType.INT64 */, opt: true }, - ]); - - static fromBinary(bytes: Uint8Array, options?: Partial): PromotionRetry { - return new PromotionRetry().fromBinary(bytes, options); - } - - static fromJson(jsonValue: JsonValue, options?: Partial): PromotionRetry { - return new PromotionRetry().fromJson(jsonValue, options); - } - - static fromJsonString(jsonString: string, options?: Partial): PromotionRetry { - return new PromotionRetry().fromJsonString(jsonString, options); - } - - static equals(a: PromotionRetry | PlainMessage | undefined, b: PromotionRetry | PlainMessage | undefined): boolean { - return proto2.util.equals(PromotionRetry, a, b); - } -} - /** * PromotionSpec describes the desired transition of a specific Stage into a * specific Freight. @@ -2893,9 +2845,9 @@ export class PromotionStep extends Message { /** * Retry is the retry policy for this step. * - * @generated from field: optional github.com.akuity.kargo.api.v1alpha1.PromotionRetry retry = 4; + * @generated from field: optional github.com.akuity.kargo.api.v1alpha1.PromotionStepRetry retry = 4; */ - retry?: PromotionRetry; + retry?: PromotionStepRetry; /** * Config is opaque configuration for the PromotionStep that is understood @@ -2917,7 +2869,7 @@ export class PromotionStep extends Message { static readonly fields: FieldList = proto2.util.newFieldList(() => [ { no: 1, name: "uses", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, { no: 2, name: "as", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, - { no: 4, name: "retry", kind: "message", T: PromotionRetry, opt: true }, + { no: 4, name: "retry", kind: "message", T: PromotionStepRetry, opt: true }, { no: 3, name: "config", kind: "message", T: JSON, opt: true }, ]); @@ -2938,6 +2890,54 @@ export class PromotionStep extends Message { } } +/** + * PromotionStepRetry describes the retry policy for a PromotionStep. + * + * @generated from message github.com.akuity.kargo.api.v1alpha1.PromotionStepRetry + */ +export class PromotionStepRetry extends Message { + /** + * Attempts is the number of times the step can be attempted before the + * PromotionStep is marked as failed. + * + * If this field is set to 1, the step will not be retried. If this + * field is set to -1, the step will be retried indefinitely. + * + * The default of this field depends on the step being executed. Refer to + * the documentation for the specific step for more information. + * + * @generated from field: optional int64 attempts = 1; + */ + attempts?: bigint; + + constructor(data?: PartialMessage) { + super(); + proto2.util.initPartial(data, this); + } + + static readonly runtime: typeof proto2 = proto2; + static readonly typeName = "github.com.akuity.kargo.api.v1alpha1.PromotionStepRetry"; + static readonly fields: FieldList = proto2.util.newFieldList(() => [ + { no: 1, name: "attempts", kind: "scalar", T: 3 /* ScalarType.INT64 */, opt: true }, + ]); + + static fromBinary(bytes: Uint8Array, options?: Partial): PromotionStepRetry { + return new PromotionStepRetry().fromBinary(bytes, options); + } + + static fromJson(jsonValue: JsonValue, options?: Partial): PromotionStepRetry { + return new PromotionStepRetry().fromJson(jsonValue, options); + } + + static fromJsonString(jsonString: string, options?: Partial): PromotionStepRetry { + return new PromotionStepRetry().fromJsonString(jsonString, options); + } + + static equals(a: PromotionStepRetry | PlainMessage | undefined, b: PromotionStepRetry | PlainMessage | undefined): boolean { + return proto2.util.equals(PromotionStepRetry, a, b); + } +} + /** * PromotionTemplate defines a template for a Promotion that can be used to * incorporate Freight into a Stage.