diff --git a/api/protobuf-spec/github_com_openshift_origin_pkg_build_api_v1.proto b/api/protobuf-spec/github_com_openshift_origin_pkg_build_api_v1.proto index 89ba9f75d39c..d86c2cf44798 100644 --- a/api/protobuf-spec/github_com_openshift_origin_pkg_build_api_v1.proto +++ b/api/protobuf-spec/github_com_openshift_origin_pkg_build_api_v1.proto @@ -111,6 +111,14 @@ message BuildConfigSpec { // CommonSpec is the desired build specification optional CommonSpec commonSpec = 3; + + // successfulBuildsHistoryLimit is the number of old successful builds to retain. + // If not specified, all successful builds are retained. + optional int32 successfulBuildsHistoryLimit = 4; + + // failedBuildsHistoryLimit is the number of old failed builds to retain. + // If not specified, all failed builds are retained. + optional int32 failedBuildsHistoryLimit = 5; } // BuildConfigStatus contains current state of the build config object. diff --git a/api/swagger-spec/oapi-v1.json b/api/swagger-spec/oapi-v1.json index bf73ca6d64fe..2f80904923f3 100644 --- a/api/swagger-spec/oapi-v1.json +++ b/api/swagger-spec/oapi-v1.json @@ -23359,6 +23359,16 @@ "nodeSelector": { "type": "object", "description": "nodeSelector is a selector which must be true for the build pod to fit on a node If nil, it can be overridden by default build nodeselector values for the cluster. If set to an empty map or a map with any values, default build nodeselector values are ignored." + }, + "successfulBuildsHistoryLimit": { + "type": "integer", + "format": "int32", + "description": "successfulBuildsHistoryLimit is the number of old successful builds to retain. If not specified, all successful builds are retained." + }, + "failedBuildsHistoryLimit": { + "type": "integer", + "format": "int32", + "description": "failedBuildsHistoryLimit is the number of old failed builds to retain. If not specified, all failed builds are retained." } } }, diff --git a/api/swagger-spec/openshift-openapi-spec.json b/api/swagger-spec/openshift-openapi-spec.json index 5c282d2a2da1..ba24e0035d68 100644 --- a/api/swagger-spec/openshift-openapi-spec.json +++ b/api/swagger-spec/openshift-openapi-spec.json @@ -72737,6 +72737,11 @@ "type": "integer", "format": "int64" }, + "failedBuildsHistoryLimit": { + "description": "failedBuildsHistoryLimit is the number of old failed builds to retain. If not specified, all failed builds are retained.", + "type": "integer", + "format": "int32" + }, "nodeSelector": { "description": "nodeSelector is a selector which must be true for the build pod to fit on a node If nil, it can be overridden by default build nodeselector values for the cluster. If set to an empty map or a map with any values, default build nodeselector values are ignored.", "type": "object", @@ -72776,6 +72781,11 @@ "description": "strategy defines how to perform a build.", "$ref": "#/definitions/v1.BuildStrategy" }, + "successfulBuildsHistoryLimit": { + "description": "successfulBuildsHistoryLimit is the number of old successful builds to retain. If not specified, all successful builds are retained.", + "type": "integer", + "format": "int32" + }, "triggers": { "description": "triggers determine how new Builds can be launched from a BuildConfig. If no triggers are defined, a new build can only occur as a result of an explicit client build creation.", "type": "array", diff --git a/pkg/build/api/types.go b/pkg/build/api/types.go index d3354d7e27df..f77e17e4c64b 100644 --- a/pkg/build/api/types.go +++ b/pkg/build/api/types.go @@ -991,6 +991,14 @@ type BuildConfigSpec struct { // CommonSpec is the desired build specification CommonSpec + + // SuccessfulBuildsHistoryLimit is the number of old successful builds to retain. + // This field is a pointer to allow for differentiation between an explicit zero and not specified. + SuccessfulBuildsHistoryLimit *int32 + + // FailedBuildsHistoryLimit is the number of old failed builds to retain. + // This field is a pointer to allow for differentiation between an explicit zero and not specified. + FailedBuildsHistoryLimit *int32 } // BuildRunPolicy defines the behaviour of how the new builds are executed diff --git a/pkg/build/api/v1/generated.pb.go b/pkg/build/api/v1/generated.pb.go index 2ce528c805ea..0000c49e6f70 100644 --- a/pkg/build/api/v1/generated.pb.go +++ b/pkg/build/api/v1/generated.pb.go @@ -605,6 +605,16 @@ func (m *BuildConfigSpec) MarshalTo(data []byte) (int, error) { return 0, err } i += n10 + if m.SuccessfulBuildsHistoryLimit != nil { + data[i] = 0x20 + i++ + i = encodeVarintGenerated(data, i, uint64(*m.SuccessfulBuildsHistoryLimit)) + } + if m.FailedBuildsHistoryLimit != nil { + data[i] = 0x28 + i++ + i = encodeVarintGenerated(data, i, uint64(*m.FailedBuildsHistoryLimit)) + } return i, nil } @@ -2729,6 +2739,12 @@ func (m *BuildConfigSpec) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) l = m.CommonSpec.Size() n += 1 + l + sovGenerated(uint64(l)) + if m.SuccessfulBuildsHistoryLimit != nil { + n += 1 + sovGenerated(uint64(*m.SuccessfulBuildsHistoryLimit)) + } + if m.FailedBuildsHistoryLimit != nil { + n += 1 + sovGenerated(uint64(*m.FailedBuildsHistoryLimit)) + } return n } @@ -3577,6 +3593,8 @@ func (this *BuildConfigSpec) String() string { `Triggers:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.Triggers), "BuildTriggerPolicy", "BuildTriggerPolicy", 1), `&`, ``, 1) + `,`, `RunPolicy:` + fmt.Sprintf("%v", this.RunPolicy) + `,`, `CommonSpec:` + strings.Replace(strings.Replace(this.CommonSpec.String(), "CommonSpec", "CommonSpec", 1), `&`, ``, 1) + `,`, + `SuccessfulBuildsHistoryLimit:` + valueToStringGenerated(this.SuccessfulBuildsHistoryLimit) + `,`, + `FailedBuildsHistoryLimit:` + valueToStringGenerated(this.FailedBuildsHistoryLimit) + `,`, `}`, }, "") return s @@ -5074,6 +5092,46 @@ func (m *BuildConfigSpec) Unmarshal(data []byte) error { return err } iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SuccessfulBuildsHistoryLimit", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + v |= (int32(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.SuccessfulBuildsHistoryLimit = &v + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field FailedBuildsHistoryLimit", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := data[iNdEx] + iNdEx++ + v |= (int32(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + m.FailedBuildsHistoryLimit = &v default: iNdEx = preIndex skippy, err := skipGenerated(data[iNdEx:]) @@ -12001,240 +12059,244 @@ var ( ) var fileDescriptorGenerated = []byte{ - // 3751 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe4, 0x5b, 0x4d, 0x6c, 0x1c, 0x47, - 0x76, 0x56, 0xcf, 0x0c, 0xe7, 0xe7, 0x0d, 0xc5, 0x9f, 0xa2, 0xb4, 0xa2, 0xb4, 0x5e, 0x8e, 0xb6, - 0x77, 0xbd, 0x58, 0x67, 0xe5, 0x61, 0x24, 0x5b, 0x8a, 0xf6, 0xc7, 0x5e, 0x73, 0x86, 0x94, 0x4c, - 0x2d, 0x25, 0x31, 0x35, 0xb4, 0x95, 0x95, 0x83, 0x6c, 0x9a, 0xcd, 0x9a, 0x61, 0x9b, 0x3d, 0xdd, - 0xb3, 0x5d, 0x35, 0xb4, 0x18, 0xec, 0x02, 0xc6, 0x06, 0x46, 0x92, 0x5b, 0xe2, 0x24, 0x80, 0x2f, - 0x01, 0x62, 0x20, 0x3f, 0x08, 0x72, 0x08, 0x90, 0xe4, 0x92, 0x4b, 0xe0, 0x20, 0x40, 0xe0, 0x53, - 0xe2, 0x63, 0x0e, 0xc9, 0x20, 0x66, 0x0e, 0x3e, 0x26, 0x41, 0x2e, 0x81, 0x4e, 0x41, 0xfd, 0x74, - 0x77, 0x75, 0x4f, 0x93, 0xd2, 0x34, 0x25, 0xd9, 0x41, 0x6e, 0x9c, 0xf7, 0x5e, 0x7d, 0xaf, 0xea, - 0xf5, 0xab, 0x7a, 0x3f, 0x55, 0x84, 0xef, 0xf5, 0x1c, 0xb6, 0x3b, 0xdc, 0x6e, 0xda, 0x7e, 0x7f, - 0xd9, 0x1f, 0x10, 0x8f, 0xee, 0x3a, 0x5d, 0xb6, 0xec, 0x07, 0x4e, 0xcf, 0xf1, 0x96, 0x07, 0x7b, - 0xbd, 0xe5, 0xed, 0xa1, 0xe3, 0xee, 0x2c, 0x5b, 0x03, 0x67, 0x79, 0xff, 0xf2, 0x72, 0x8f, 0x78, - 0x24, 0xb0, 0x18, 0xd9, 0x69, 0x0e, 0x02, 0x9f, 0xf9, 0xe8, 0x52, 0x3c, 0xba, 0x19, 0x8d, 0x6e, - 0xca, 0xd1, 0xcd, 0xc1, 0x5e, 0xaf, 0x29, 0x46, 0x37, 0xad, 0x81, 0xd3, 0xdc, 0xbf, 0x7c, 0xe1, - 0x45, 0x4d, 0x57, 0xcf, 0xef, 0xf9, 0xcb, 0x02, 0x64, 0x7b, 0xd8, 0x15, 0xbf, 0xc4, 0x0f, 0xf1, - 0x97, 0x04, 0xbf, 0xf0, 0xf2, 0xde, 0x75, 0xda, 0x74, 0x7c, 0xae, 0xbb, 0x6f, 0xd9, 0xbb, 0x8e, - 0x47, 0x82, 0x03, 0x31, 0x25, 0x6b, 0xe0, 0xd0, 0xe5, 0x3e, 0x61, 0x56, 0xc6, 0x94, 0x2e, 0x2c, - 0x1f, 0x35, 0x2a, 0x18, 0x7a, 0xcc, 0xe9, 0x93, 0xb1, 0x01, 0xd7, 0x1e, 0x35, 0x80, 0xda, 0xbb, - 0xa4, 0x6f, 0x8d, 0x8d, 0x7b, 0xe9, 0xa8, 0x71, 0x43, 0xe6, 0xb8, 0xcb, 0x8e, 0xc7, 0x28, 0x0b, - 0xc6, 0x06, 0x69, 0x6b, 0xa2, 0x24, 0xd8, 0x27, 0x41, 0xbc, 0x20, 0xf2, 0xc0, 0xea, 0x0f, 0x5c, - 0x92, 0xb5, 0xa6, 0x4b, 0x6a, 0xd4, 0xde, 0x70, 0x9b, 0x04, 0x1e, 0x61, 0x84, 0x86, 0xc3, 0x32, - 0xa4, 0xcd, 0x8f, 0x4a, 0x70, 0xbe, 0xe5, 0x78, 0x56, 0x70, 0xd0, 0xe2, 0xd6, 0xc7, 0xe4, 0xc7, - 0x43, 0x42, 0xd9, 0xdd, 0x01, 0x73, 0x7c, 0x8f, 0xa2, 0x5f, 0x85, 0x2a, 0x37, 0xdd, 0x8e, 0xc5, - 0xac, 0x45, 0xe3, 0xa2, 0xf1, 0xcd, 0xfa, 0x95, 0x9f, 0x6f, 0x4a, 0xf8, 0xa6, 0xbe, 0x12, 0xf1, - 0xf5, 0xf8, 0xbc, 0x9a, 0x5c, 0xba, 0xb9, 0x7f, 0xb9, 0x79, 0x77, 0xfb, 0x6d, 0x62, 0xb3, 0xdb, - 0x84, 0x59, 0x2d, 0xf4, 0xf1, 0xa8, 0x71, 0xea, 0x70, 0xd4, 0x80, 0x98, 0x86, 0x23, 0x54, 0xf4, - 0x0d, 0x28, 0x5b, 0xf4, 0x86, 0xe3, 0x92, 0xc5, 0xc2, 0x45, 0xe3, 0x9b, 0xb5, 0xd6, 0x8c, 0x92, - 0x2e, 0xaf, 0x08, 0x2a, 0x56, 0x5c, 0x74, 0x0d, 0x66, 0x02, 0xb2, 0xef, 0x50, 0xc7, 0xf7, 0xda, - 0x7e, 0xbf, 0xef, 0xb0, 0xc5, 0x62, 0x52, 0x5e, 0x52, 0x71, 0x4a, 0x0a, 0x7d, 0x1b, 0x66, 0x43, - 0xca, 0x6d, 0x42, 0xa9, 0xd5, 0x23, 0x8b, 0x25, 0x31, 0x70, 0x56, 0x0d, 0xac, 0x28, 0x32, 0x4e, - 0xcb, 0xa1, 0x16, 0xa0, 0x90, 0xb4, 0x32, 0x64, 0xbb, 0x7e, 0x70, 0xc7, 0xea, 0x93, 0xc5, 0x29, - 0x31, 0x3a, 0x5a, 0x54, 0xcc, 0xc1, 0x19, 0xd2, 0x68, 0x0d, 0x16, 0x92, 0xd4, 0xb5, 0xbe, 0xe5, - 0xb8, 0x8b, 0x65, 0x01, 0xb2, 0xa0, 0x40, 0xea, 0x1a, 0x0b, 0x67, 0xc9, 0xa3, 0x1f, 0xc0, 0xd9, - 0xe4, 0xba, 0x18, 0x91, 0xb3, 0xa9, 0x08, 0xa0, 0xb3, 0x0a, 0xe8, 0x74, 0x82, 0x89, 0xb3, 0xc7, - 0xa0, 0x3b, 0xf0, 0xa5, 0x31, 0x86, 0x9c, 0x56, 0x55, 0xa0, 0x7d, 0x49, 0xa1, 0xcd, 0x24, 0xb9, - 0xf8, 0x88, 0x51, 0xe6, 0x77, 0x61, 0x5e, 0xf3, 0xa0, 0x8e, 0x3f, 0x0c, 0x6c, 0xa2, 0x7d, 0x57, - 0xe3, 0xb8, 0xef, 0x6a, 0xfe, 0xbe, 0x01, 0x67, 0x5b, 0x0e, 0xdb, 0x1e, 0xda, 0x7b, 0x84, 0xdd, - 0x23, 0xdb, 0xaf, 0xfb, 0xfe, 0x5e, 0xdb, 0x1a, 0x52, 0x82, 0x7e, 0x02, 0x60, 0xfb, 0xfd, 0xbe, - 0xef, 0x75, 0x06, 0xc4, 0x56, 0xde, 0xf7, 0x5a, 0x73, 0x92, 0x33, 0xa4, 0xd9, 0x16, 0xe3, 0x75, - 0xd4, 0xd6, 0x05, 0x35, 0x0f, 0x34, 0xce, 0xc3, 0x9a, 0x3e, 0xf3, 0x4f, 0x0b, 0x30, 0x25, 0xd6, - 0xf3, 0x0c, 0xf6, 0xc0, 0x0f, 0xa1, 0x44, 0xf9, 0x1a, 0x0b, 0x02, 0xfd, 0x17, 0x26, 0x5b, 0xa3, - 0x34, 0xfa, 0x80, 0xd8, 0xad, 0x69, 0xa5, 0xa4, 0xc4, 0x7f, 0x61, 0x01, 0x89, 0x2c, 0x28, 0x53, - 0x66, 0xb1, 0x21, 0x15, 0xdb, 0xa5, 0x7e, 0xe5, 0xdb, 0x79, 0xc0, 0x05, 0x40, 0xfc, 0x05, 0xe5, - 0x6f, 0xac, 0x80, 0xcd, 0xbf, 0x29, 0x40, 0x5d, 0xc8, 0xb5, 0x7d, 0xaf, 0xeb, 0xf4, 0x9e, 0x81, - 0xbd, 0x7e, 0x94, 0xb0, 0xd7, 0x2b, 0x39, 0x96, 0x24, 0xa7, 0x7a, 0xa4, 0xd5, 0x7a, 0x29, 0xab, - 0x7d, 0x3f, 0xbf, 0x8a, 0xe3, 0x6d, 0xf7, 0x4f, 0x06, 0xcc, 0x6a, 0xd2, 0x1b, 0x0e, 0x65, 0xe8, - 0x97, 0xc7, 0xec, 0xd7, 0x7c, 0x3c, 0xfb, 0xf1, 0xd1, 0xc2, 0x7a, 0x73, 0x4a, 0x5b, 0x35, 0xa4, - 0x68, 0xb6, 0xfb, 0x15, 0x98, 0x72, 0x18, 0xe9, 0xd3, 0xc5, 0xc2, 0xc5, 0x62, 0x4e, 0x7f, 0x90, - 0x73, 0x6d, 0x9d, 0x56, 0x5a, 0xa6, 0xd6, 0x39, 0x1e, 0x96, 0xb0, 0xe6, 0x5f, 0x16, 0x12, 0x2b, - 0xe2, 0x46, 0x45, 0x1e, 0x54, 0x59, 0xe0, 0xf4, 0x7a, 0x24, 0xa0, 0x8b, 0x86, 0x50, 0xfb, 0x5a, - 0x0e, 0xb5, 0x5b, 0x12, 0x62, 0xd3, 0x77, 0x1d, 0xfb, 0x20, 0x5e, 0xa3, 0x22, 0x53, 0x1c, 0xe9, - 0x40, 0x2b, 0x50, 0x0b, 0x86, 0x9e, 0x14, 0x54, 0x61, 0xe5, 0x6b, 0x4a, 0xbc, 0x86, 0x43, 0xc6, - 0xc3, 0x51, 0x63, 0x46, 0x86, 0xbc, 0x90, 0x82, 0xe3, 0x51, 0xc8, 0x4d, 0x1c, 0x3e, 0xd2, 0x0b, - 0xae, 0xe7, 0x39, 0x7c, 0x84, 0x8f, 0x45, 0xee, 0x1c, 0xd3, 0x12, 0x87, 0xcd, 0x2d, 0x98, 0x1f, - 0xf3, 0x19, 0x74, 0x15, 0xea, 0xae, 0x45, 0xd9, 0x9b, 0x24, 0xe0, 0x67, 0xae, 0x70, 0x85, 0x62, - 0x1c, 0x32, 0x36, 0x62, 0x16, 0xd6, 0xe5, 0xcc, 0xbf, 0x37, 0xa0, 0x26, 0xc0, 0x9e, 0x81, 0x33, - 0xfd, 0x52, 0xd2, 0x99, 0x5e, 0xca, 0xf1, 0x55, 0x8f, 0x70, 0x23, 0x80, 0xaa, 0x5c, 0x84, 0xdf, - 0x33, 0x7f, 0xa3, 0xa4, 0x5c, 0x6a, 0xc3, 0xef, 0x85, 0x89, 0xc9, 0x32, 0xd4, 0x6c, 0xdf, 0x63, - 0x16, 0x9f, 0xbd, 0x8a, 0x30, 0xf3, 0xe1, 0x27, 0x6e, 0x87, 0x0c, 0x1c, 0xcb, 0xf0, 0x78, 0xd4, - 0xf5, 0x5d, 0xd7, 0x7f, 0x47, 0x38, 0x44, 0x35, 0xde, 0x91, 0x37, 0x04, 0x15, 0x2b, 0x2e, 0xba, - 0x04, 0xd5, 0x01, 0x8f, 0x73, 0xbe, 0xda, 0xfc, 0xd5, 0xd8, 0x00, 0x9b, 0x8a, 0x8e, 0x23, 0x09, - 0xf4, 0x32, 0x4c, 0x53, 0xc7, 0xb3, 0x49, 0x87, 0xd8, 0xbe, 0xb7, 0x43, 0x45, 0x6a, 0x51, 0x6c, - 0xcd, 0x1d, 0x8e, 0x1a, 0xd3, 0x1d, 0x8d, 0x8e, 0x13, 0x52, 0xe8, 0x1e, 0xd4, 0xc4, 0xef, 0x2d, - 0x47, 0xe5, 0x13, 0xf5, 0x2b, 0x3f, 0xf7, 0x78, 0x5f, 0x85, 0x8f, 0x68, 0x9d, 0xe6, 0x8b, 0xec, - 0x84, 0x00, 0x38, 0xc6, 0x42, 0x57, 0x00, 0x78, 0x12, 0x4a, 0x99, 0xd5, 0x1f, 0x50, 0x91, 0x64, - 0x54, 0x63, 0xdf, 0xdb, 0x8a, 0x38, 0x58, 0x93, 0x42, 0xdf, 0x82, 0x1a, 0xb3, 0x1c, 0x77, 0xc3, - 0xf1, 0x08, 0x15, 0xe9, 0x44, 0x51, 0x2a, 0xd8, 0x0a, 0x89, 0x38, 0xe6, 0xa3, 0x26, 0x80, 0xeb, - 0xf4, 0x1d, 0xd6, 0x3a, 0x60, 0x84, 0x8a, 0x74, 0xa1, 0xd8, 0x9a, 0xe1, 0xe0, 0x1b, 0x11, 0x15, - 0x6b, 0x12, 0xdc, 0xea, 0x9e, 0xff, 0x8e, 0xe5, 0xb0, 0xc5, 0x5a, 0xd2, 0xea, 0x77, 0xfc, 0x7b, - 0x96, 0xc3, 0xb0, 0xe2, 0xa2, 0xe7, 0xa1, 0xb2, 0xaf, 0xfc, 0x1c, 0x04, 0x68, 0x9d, 0x67, 0x66, - 0xa1, 0x7f, 0x87, 0x3c, 0xf3, 0xcf, 0xc2, 0x50, 0x73, 0x77, 0xc8, 0x06, 0x43, 0x86, 0xd6, 0xa0, - 0xc0, 0x7c, 0xe5, 0xd7, 0x2f, 0x86, 0x16, 0x8c, 0xf3, 0xde, 0xd0, 0x7e, 0x71, 0x70, 0xc1, 0xa4, - 0x4b, 0x02, 0xe2, 0xd9, 0xa4, 0x55, 0x3e, 0x1c, 0x35, 0x0a, 0x5b, 0x3e, 0x2e, 0x30, 0x1f, 0x6d, - 0x03, 0x0c, 0x86, 0x74, 0xb7, 0x43, 0xec, 0x80, 0x30, 0x15, 0x55, 0xae, 0x1c, 0x0f, 0xb7, 0xe1, - 0xdb, 0x96, 0x9b, 0xc6, 0x14, 0x96, 0xd8, 0x8c, 0x90, 0xb0, 0x86, 0x8a, 0x7c, 0xa8, 0x3b, 0x7d, - 0xab, 0x47, 0x36, 0xac, 0x6d, 0xe2, 0x72, 0xd7, 0x2a, 0x4e, 0x7e, 0xa2, 0xac, 0x47, 0x00, 0xf1, - 0x39, 0x10, 0xd3, 0x28, 0xd6, 0x35, 0x98, 0x3f, 0x33, 0x60, 0x41, 0xd8, 0x6a, 0xd3, 0xa7, 0x4c, - 0x66, 0x6c, 0xe2, 0x30, 0x7e, 0x1e, 0x2a, 0xfc, 0xe4, 0xb1, 0xbc, 0x1d, 0x71, 0x16, 0xd7, 0xa4, - 0xa9, 0xdb, 0x92, 0x84, 0x43, 0x1e, 0x7a, 0x0e, 0x4a, 0x56, 0xd0, 0x93, 0x3b, 0xbb, 0xd6, 0xaa, - 0xf2, 0x00, 0xb9, 0x12, 0xf4, 0x28, 0x16, 0x54, 0xfe, 0x5d, 0xa9, 0x1d, 0x38, 0x83, 0xb1, 0x2c, - 0xbc, 0x23, 0xa8, 0x58, 0x71, 0xcd, 0x9f, 0x55, 0x60, 0x5a, 0xaf, 0x2b, 0x9e, 0x41, 0x72, 0xd0, - 0x85, 0x6a, 0x98, 0xa7, 0xaa, 0x4f, 0xf9, 0xbd, 0xc9, 0xac, 0x2c, 0x13, 0x58, 0xac, 0x30, 0x5a, - 0xd3, 0x7c, 0xeb, 0x87, 0xbf, 0x70, 0x84, 0x8d, 0x7c, 0x98, 0x53, 0x01, 0x87, 0xec, 0xb4, 0x0e, - 0xc4, 0x67, 0x50, 0x71, 0x62, 0x42, 0x4f, 0x3c, 0x73, 0x38, 0x6a, 0xcc, 0x6d, 0xa5, 0xa0, 0xf0, - 0x18, 0x38, 0xfa, 0x01, 0x94, 0xba, 0x81, 0xdf, 0x17, 0x67, 0xcc, 0xc4, 0x4a, 0xc4, 0x07, 0xbc, - 0x11, 0xf8, 0x7d, 0x2c, 0x40, 0x90, 0x0d, 0xe5, 0x6d, 0x91, 0xb3, 0xab, 0xf3, 0x67, 0xd2, 0x0c, - 0x27, 0x9d, 0xef, 0xb7, 0x80, 0x7f, 0x7d, 0x49, 0xc6, 0x0a, 0x1a, 0x5d, 0x4e, 0x46, 0xb0, 0xb2, - 0xd8, 0xd9, 0xb3, 0xc7, 0x45, 0x2f, 0xd4, 0x86, 0x22, 0xf1, 0xf6, 0x17, 0x2b, 0x62, 0x7b, 0x7c, - 0xfd, 0xf8, 0x35, 0xae, 0x79, 0xfb, 0x6f, 0x5a, 0x41, 0xab, 0xae, 0xdc, 0xa1, 0xb8, 0xe6, 0xed, - 0x63, 0x3e, 0x1a, 0xed, 0x43, 0x5d, 0xb3, 0xde, 0x62, 0x55, 0x80, 0x7d, 0x3f, 0x7f, 0xca, 0x21, - 0x2b, 0x87, 0x68, 0xcb, 0x69, 0xdf, 0x0a, 0xeb, 0x8a, 0xd0, 0xef, 0x19, 0x70, 0x76, 0xc7, 0xb7, - 0xf7, 0x48, 0xd0, 0x61, 0xbc, 0xc6, 0xee, 0x1d, 0xa8, 0x70, 0x25, 0x4e, 0xbf, 0xfa, 0x95, 0xf6, - 0x64, 0x53, 0x58, 0xcd, 0x82, 0x6a, 0x9d, 0x3f, 0x1c, 0x35, 0xce, 0x66, 0xb2, 0x70, 0xb6, 0x72, - 0xf3, 0x0f, 0xa6, 0xd4, 0xa9, 0xa9, 0x4a, 0xb3, 0x97, 0xa0, 0xc4, 0x0e, 0x06, 0x61, 0x61, 0xd6, - 0x08, 0xf3, 0xdf, 0xad, 0x83, 0x01, 0x79, 0x38, 0x6a, 0xcc, 0x6a, 0xa2, 0x9c, 0x84, 0x85, 0xb0, - 0xe6, 0x30, 0x85, 0xa7, 0xe7, 0x30, 0x4d, 0x00, 0xb9, 0x84, 0x2e, 0x2f, 0x1c, 0xd5, 0xd1, 0xc2, - 0x77, 0xfa, 0x6a, 0x44, 0xc5, 0x9a, 0x04, 0xba, 0x07, 0xc5, 0x9e, 0xc3, 0xd4, 0x8e, 0x98, 0x70, - 0x9b, 0xdf, 0x74, 0x98, 0x3e, 0x9d, 0x0a, 0xf7, 0xa0, 0x9b, 0x0e, 0xc3, 0x1c, 0x91, 0x97, 0x4d, - 0xe2, 0x2c, 0xa5, 0x8b, 0x53, 0x79, 0xd2, 0x64, 0xb1, 0x61, 0x15, 0x70, 0x74, 0x34, 0x0a, 0x22, - 0xc5, 0x0a, 0x98, 0xc7, 0x6a, 0x9e, 0x9d, 0x90, 0x07, 0x6c, 0xd5, 0x09, 0x54, 0x43, 0x40, 0xcb, - 0x13, 0x43, 0x0e, 0xd6, 0xa4, 0xd0, 0x2e, 0x4c, 0x53, 0x81, 0xaa, 0x42, 0x55, 0x25, 0x77, 0xa8, - 0x92, 0x29, 0x8a, 0x86, 0x85, 0x13, 0xc8, 0xe8, 0x6d, 0xa8, 0x50, 0xf1, 0x17, 0xcd, 0xb7, 0x7d, - 0x24, 0x8c, 0x6e, 0xe0, 0xa8, 0xdf, 0x22, 0x59, 0x14, 0x87, 0x0a, 0xcc, 0xff, 0x0a, 0x33, 0x56, - 0x11, 0x9f, 0xdc, 0x8c, 0xb2, 0xff, 0xa9, 0x65, 0xde, 0xe9, 0xa3, 0xa2, 0xf0, 0x8c, 0x8e, 0x0a, - 0xf3, 0xbf, 0xcb, 0xe1, 0x9e, 0x94, 0xc9, 0xfe, 0x65, 0x98, 0x1a, 0xec, 0x5a, 0x34, 0xdc, 0x94, - 0x5f, 0x0e, 0x93, 0xe2, 0x4d, 0x4e, 0x7c, 0x38, 0x6a, 0x80, 0x0c, 0xe5, 0xfc, 0x17, 0x96, 0x92, - 0x22, 0x05, 0xb6, 0x3c, 0x9b, 0xb8, 0x2e, 0xd9, 0x51, 0x49, 0x6d, 0x9c, 0x02, 0x87, 0x0c, 0x1c, - 0xcb, 0xa0, 0x6b, 0x50, 0x0e, 0x88, 0x45, 0x7d, 0x4f, 0xed, 0xac, 0xa5, 0xd0, 0x33, 0xb1, 0xa0, - 0x3e, 0xe4, 0x1e, 0x21, 0xcb, 0x53, 0xf1, 0x1b, 0x2b, 0x69, 0xf4, 0x02, 0x54, 0xfa, 0xc7, 0xb7, - 0xce, 0x42, 0x3e, 0xea, 0xc2, 0x0c, 0x65, 0x56, 0xc0, 0xa2, 0x5c, 0x33, 0x47, 0x7a, 0x8b, 0x0e, - 0x47, 0x8d, 0x99, 0x4e, 0x02, 0x05, 0xa7, 0x50, 0xd1, 0x10, 0x16, 0x6c, 0xbf, 0x3f, 0x70, 0x09, - 0x3f, 0xe1, 0x62, 0x65, 0xe5, 0x89, 0x95, 0x9d, 0x3b, 0x1c, 0x35, 0x16, 0xda, 0xe3, 0x50, 0x38, - 0x0b, 0x1f, 0xbd, 0x02, 0xd5, 0x9d, 0x61, 0x60, 0x71, 0xa2, 0x4a, 0x95, 0xbf, 0x1a, 0x16, 0x07, - 0xab, 0x8a, 0xfe, 0x70, 0xd4, 0x38, 0xcd, 0xb3, 0xeb, 0x66, 0x48, 0xc0, 0xd1, 0x10, 0xb4, 0x0d, - 0x17, 0x7c, 0x91, 0xb8, 0xca, 0xe3, 0x4c, 0x06, 0xfa, 0x70, 0x4b, 0xaa, 0xe6, 0x9b, 0xa9, 0x00, - 0x2f, 0xdc, 0x3d, 0x52, 0x12, 0x1f, 0x83, 0x82, 0x7e, 0x11, 0xca, 0xb6, 0xa8, 0x22, 0x55, 0xcc, - 0x99, 0x30, 0x4f, 0x00, 0xd9, 0x4a, 0xe5, 0x00, 0x58, 0x01, 0xa1, 0x1e, 0x94, 0xa5, 0x42, 0x91, - 0x9b, 0xe7, 0xdb, 0x1e, 0xd2, 0xb1, 0xe4, 0x9a, 0xe2, 0x23, 0x51, 0xfe, 0xc6, 0x0a, 0x1e, 0xfd, - 0x48, 0xb4, 0x5d, 0xf8, 0xa9, 0x5b, 0x17, 0xfb, 0x70, 0xc2, 0x4e, 0x58, 0x87, 0x8f, 0x5d, 0xf7, - 0xba, 0x7e, 0xa2, 0xdd, 0x22, 0xce, 0x5c, 0x09, 0x6b, 0x7a, 0xaa, 0xce, 0xd6, 0x67, 0x83, 0x7e, - 0xa8, 0x15, 0x11, 0x2b, 0x27, 0x5c, 0xda, 0x96, 0xaf, 0x17, 0x16, 0xe6, 0x86, 0x4a, 0xc1, 0x93, - 0x22, 0xbc, 0xb2, 0x17, 0x41, 0x60, 0xd5, 0xe9, 0x11, 0xca, 0xd4, 0x96, 0x4f, 0x66, 0xf4, 0x92, - 0x85, 0x75, 0x39, 0xf3, 0xb3, 0x12, 0x9c, 0x56, 0x70, 0x32, 0xc0, 0xa3, 0xab, 0x89, 0x48, 0xfe, - 0xd5, 0x54, 0x24, 0x9f, 0x4f, 0x08, 0x6b, 0xb1, 0xfc, 0xa7, 0x30, 0x93, 0xcc, 0x14, 0x54, 0x4c, - 0x5f, 0xc9, 0x93, 0x9f, 0x24, 0x94, 0xc8, 0xcd, 0x9b, 0xcc, 0x4e, 0x70, 0x4a, 0x19, 0x57, 0xaf, - 0x62, 0x4d, 0xa8, 0xbe, 0x98, 0x47, 0xbd, 0x8a, 0x2b, 0xe3, 0xea, 0x3b, 0x09, 0x70, 0x9c, 0x52, - 0xc6, 0xd5, 0xdb, 0x43, 0xca, 0xfc, 0x7e, 0xa4, 0xbe, 0x94, 0x47, 0x7d, 0x5b, 0x60, 0x64, 0xa8, - 0x6f, 0x27, 0xc0, 0x71, 0x4a, 0x19, 0xfa, 0xd0, 0x80, 0x73, 0x6f, 0x13, 0x6f, 0xcf, 0xf1, 0xe8, - 0xa6, 0x33, 0x20, 0xae, 0xe3, 0xc5, 0x76, 0x90, 0x87, 0xe5, 0xad, 0xc9, 0x26, 0x72, 0x2b, 0x09, - 0x96, 0x9c, 0xd1, 0x97, 0x0f, 0x47, 0x8d, 0x73, 0xb7, 0xb2, 0xd5, 0xe1, 0xa3, 0xe6, 0x61, 0xfe, - 0xed, 0x94, 0xda, 0x28, 0x7a, 0x54, 0xd3, 0xe3, 0x80, 0xf1, 0x88, 0x38, 0xf0, 0x53, 0x98, 0x11, - 0x17, 0x4d, 0x8e, 0xad, 0x1a, 0xec, 0xf9, 0x3c, 0xec, 0x66, 0x02, 0x43, 0xc6, 0x56, 0x61, 0xe3, - 0x24, 0x03, 0xa7, 0x94, 0xa1, 0x03, 0x38, 0x2d, 0xf5, 0x84, 0xda, 0x8b, 0x79, 0x6e, 0x0f, 0x6e, - 0x3a, 0xec, 0xf5, 0x08, 0x42, 0x2a, 0x9f, 0x3f, 0x1c, 0x35, 0x4e, 0x27, 0xe8, 0x38, 0xa9, 0x09, - 0xbd, 0x6b, 0xc0, 0x9c, 0xd8, 0xb4, 0xed, 0x5d, 0xcb, 0xeb, 0xc9, 0xaf, 0xa1, 0x1c, 0xec, 0xd5, - 0x1c, 0x49, 0xa4, 0x44, 0x91, 0xca, 0x45, 0xa1, 0xb8, 0x9e, 0xc2, 0xc6, 0x63, 0xda, 0xd4, 0xea, - 0x5d, 0x2b, 0x5a, 0xfd, 0x54, 0xce, 0xd5, 0x6f, 0x58, 0xd9, 0xab, 0x8f, 0xe9, 0x38, 0xa9, 0x09, - 0xbd, 0x67, 0xc0, 0xdc, 0x76, 0xea, 0x36, 0x47, 0x45, 0xe5, 0xf6, 0xa4, 0x05, 0x43, 0xc6, 0x9d, - 0x90, 0x34, 0x41, 0x9a, 0x85, 0xc7, 0x54, 0x9a, 0xff, 0x51, 0x02, 0x34, 0xde, 0x34, 0x46, 0x2f, - 0x27, 0xce, 0xcb, 0x8b, 0xa9, 0xf3, 0x72, 0x4e, 0x1f, 0xa1, 0x1d, 0x97, 0x3d, 0x28, 0xcb, 0xa9, - 0xe7, 0xeb, 0x27, 0xa8, 0x39, 0x29, 0xdc, 0x2c, 0x17, 0x52, 0xf0, 0x3c, 0xe9, 0x56, 0x8e, 0xac, - 0x1c, 0xf6, 0x64, 0x9a, 0xb2, 0x76, 0x4a, 0xa8, 0x00, 0x51, 0x15, 0x83, 0xa4, 0xe3, 0x28, 0x0f, - 0x7d, 0x2d, 0xb7, 0x87, 0x86, 0x3a, 0x67, 0xa3, 0x08, 0x26, 0xe9, 0x58, 0xd7, 0xa2, 0x2c, 0xe9, - 0x5a, 0xdb, 0xca, 0x25, 0x9f, 0x8c, 0x25, 0x35, 0x77, 0x54, 0xf0, 0x68, 0x00, 0xb5, 0xc8, 0x27, - 0x94, 0xff, 0x9d, 0x4c, 0x57, 0xb6, 0xe3, 0xc5, 0x4a, 0xcc, 0x0f, 0x2a, 0xa0, 0xd5, 0x18, 0xe8, - 0x55, 0x98, 0xa1, 0x24, 0xd8, 0x77, 0x6c, 0xb2, 0x62, 0xdb, 0xfe, 0xd0, 0x0b, 0xa3, 0x7c, 0x74, - 0xb7, 0xda, 0x49, 0x70, 0x71, 0x4a, 0x5a, 0xdc, 0xdb, 0x89, 0xb0, 0xa5, 0x7c, 0x2e, 0xd7, 0xbd, - 0x5d, 0xaa, 0x00, 0x55, 0x8d, 0x2d, 0x05, 0x9c, 0x68, 0x94, 0x15, 0x9f, 0x62, 0xa3, 0xcc, 0x81, - 0x2a, 0x4d, 0x46, 0xda, 0xef, 0xe6, 0xca, 0xb2, 0x54, 0x44, 0x8b, 0xda, 0xf1, 0x51, 0x18, 0x8b, - 0xe0, 0xb9, 0xd5, 0x54, 0xa6, 0x3a, 0x95, 0xdb, 0x6a, 0x8f, 0xc8, 0x51, 0x6d, 0xa8, 0x05, 0x44, - 0x5a, 0x90, 0x2a, 0xcf, 0x7a, 0x44, 0xfd, 0x8d, 0x95, 0x38, 0x26, 0x3f, 0x1e, 0x3a, 0x01, 0xe9, - 0x13, 0x8f, 0xd1, 0xb8, 0x52, 0x0b, 0xb9, 0x14, 0xc7, 0xb8, 0x68, 0x08, 0x30, 0x88, 0xba, 0xb6, - 0xaa, 0xca, 0xcf, 0x93, 0x9a, 0x26, 0x5b, 0xbf, 0x71, 0x31, 0x1c, 0xd3, 0xb1, 0xa6, 0x08, 0xbd, - 0x05, 0xe7, 0xe3, 0xaa, 0x67, 0x95, 0x58, 0x3b, 0x22, 0x29, 0x50, 0x57, 0x1b, 0xb2, 0xd9, 0xff, - 0x95, 0xc3, 0x51, 0xe3, 0x7c, 0xfb, 0x28, 0x21, 0x7c, 0xf4, 0x78, 0xf4, 0x00, 0xa6, 0x3d, 0x7f, - 0x87, 0x74, 0x88, 0x4b, 0x6c, 0xe6, 0x07, 0xaa, 0x3c, 0x69, 0x4d, 0xb6, 0x2a, 0xd9, 0xd2, 0xb2, - 0xdc, 0x3b, 0x1a, 0x92, 0xec, 0x65, 0xe8, 0x14, 0x9c, 0xd0, 0x64, 0xfe, 0x91, 0x01, 0x19, 0xb7, - 0xfd, 0x09, 0xff, 0x37, 0x9e, 0xa2, 0xff, 0x7f, 0x03, 0xca, 0x34, 0xbe, 0x59, 0xd0, 0x7b, 0xe5, - 0xb2, 0xf1, 0xa2, 0xb8, 0xe6, 0x5f, 0x97, 0x60, 0x21, 0x23, 0xa9, 0x44, 0x77, 0x55, 0xdf, 0x37, - 0xd7, 0x35, 0x47, 0x74, 0xbb, 0xad, 0xf5, 0x7e, 0xc5, 0x75, 0x87, 0xeb, 0x3e, 0xa9, 0xeb, 0x8e, - 0x10, 0x09, 0x6b, 0xa8, 0x61, 0x1f, 0xb7, 0x78, 0xa2, 0x3e, 0xee, 0x2d, 0x40, 0xe4, 0xc1, 0xc0, - 0xa7, 0x44, 0x15, 0x14, 0xbe, 0x38, 0xce, 0x4b, 0xa2, 0xd5, 0x11, 0xbd, 0xe3, 0x58, 0x1b, 0x93, - 0xc0, 0x19, 0xa3, 0xd0, 0x32, 0xd4, 0xba, 0x7e, 0x60, 0x13, 0x3e, 0x5f, 0x71, 0x3a, 0x68, 0xdd, - 0x92, 0x1b, 0x21, 0x03, 0xc7, 0x32, 0xc8, 0x8e, 0x3b, 0x60, 0xe5, 0x3c, 0x97, 0x35, 0xd2, 0x10, - 0x62, 0xdf, 0x1d, 0xd9, 0xfa, 0x42, 0x2b, 0x30, 0x2b, 0x06, 0xad, 0x6c, 0xae, 0x87, 0x5d, 0x72, - 0xf9, 0xa2, 0xe7, 0x9c, 0x1a, 0x22, 0xbb, 0xb1, 0x31, 0x1b, 0xa7, 0xe5, 0xcd, 0xff, 0x2c, 0xc1, - 0x42, 0x46, 0x25, 0x16, 0x5d, 0x17, 0x18, 0x4f, 0xe2, 0xba, 0xe0, 0x59, 0xb8, 0xcc, 0x0b, 0x50, - 0xf1, 0xfc, 0xb6, 0x65, 0xef, 0x12, 0x75, 0xf1, 0x1a, 0x99, 0xed, 0x8e, 0x24, 0xe3, 0x90, 0x1f, - 0x7a, 0x57, 0xe9, 0x44, 0xde, 0x35, 0xb1, 0x47, 0xbc, 0x1a, 0x96, 0xcd, 0x5d, 0xc7, 0x25, 0x9b, - 0x16, 0xdb, 0x55, 0x5d, 0xdb, 0x28, 0xa6, 0xaf, 0x26, 0xb8, 0x38, 0x25, 0x8d, 0xde, 0x80, 0x9a, - 0xfc, 0x78, 0x41, 0x8f, 0x4e, 0x74, 0xc3, 0x11, 0x4d, 0xab, 0x15, 0x0e, 0xc7, 0x31, 0x12, 0x1a, - 0xc0, 0x39, 0x91, 0x63, 0xf1, 0xb3, 0xb1, 0xef, 0xfc, 0x9a, 0x68, 0x35, 0xa9, 0xb7, 0x0f, 0xb2, - 0xa5, 0x74, 0x8d, 0xd7, 0x80, 0xeb, 0xd9, 0x22, 0x0f, 0x8f, 0x66, 0xe1, 0xa3, 0x60, 0x4d, 0x0f, - 0xb2, 0x2f, 0x20, 0x92, 0x2b, 0x34, 0x9e, 0xd4, 0x0a, 0xcd, 0x3f, 0x36, 0x60, 0x21, 0xa3, 0x14, - 0xfc, 0xc2, 0x9d, 0xe0, 0xff, 0x53, 0x48, 0xcf, 0x73, 0x6d, 0x9f, 0x78, 0x2c, 0xdf, 0x85, 0xcb, - 0xa6, 0xbc, 0xdb, 0x90, 0x7b, 0xed, 0xea, 0xc4, 0xb5, 0x9b, 0xe8, 0x83, 0x25, 0x2f, 0x35, 0x9e, - 0xc8, 0x99, 0x7c, 0xf4, 0x1d, 0x57, 0xe9, 0xf3, 0xbc, 0xe3, 0xfa, 0xc8, 0x80, 0x99, 0xe4, 0x8d, - 0x0e, 0xfa, 0x0a, 0x14, 0x87, 0x81, 0xa3, 0x8c, 0x1e, 0x2d, 0xe4, 0x0d, 0xbc, 0x8e, 0x39, 0x9d, - 0xb3, 0x03, 0xd2, 0x55, 0x5f, 0x34, 0x62, 0x63, 0xd2, 0xc5, 0x9c, 0x8e, 0x06, 0x50, 0x1f, 0x04, - 0xfe, 0x83, 0x03, 0xd9, 0x0b, 0xcd, 0xf7, 0x7a, 0x6e, 0x33, 0x06, 0x88, 0xdb, 0x7b, 0x1a, 0x11, - 0xeb, 0x2a, 0x44, 0x9a, 0x32, 0xde, 0x72, 0xf8, 0xc2, 0x39, 0xf9, 0xfb, 0x05, 0xa8, 0x28, 0xff, - 0x42, 0x3f, 0x81, 0x99, 0x5e, 0xc2, 0xe8, 0xf9, 0x66, 0x98, 0xba, 0x8a, 0x8b, 0xce, 0xd3, 0x24, - 0x1d, 0xa7, 0x74, 0xa1, 0xdf, 0x34, 0x60, 0xbe, 0xe7, 0xb0, 0xe4, 0xfa, 0xf2, 0x5d, 0x4f, 0xde, - 0x4c, 0xc3, 0xb4, 0xce, 0xab, 0x49, 0xcc, 0x8f, 0xb1, 0xf0, 0xb8, 0x52, 0xf3, 0x7d, 0xf9, 0xed, - 0x52, 0x0d, 0x93, 0xcf, 0xf9, 0x09, 0xeb, 0xdf, 0x15, 0x60, 0x7c, 0xf6, 0xfc, 0x3b, 0xdb, 0xb2, - 0xae, 0x30, 0x32, 0x1f, 0x50, 0x2b, 0x2e, 0xaf, 0xd5, 0x2d, 0xf1, 0x02, 0x39, 0x9f, 0x45, 0xa5, - 0xd6, 0xb6, 0xef, 0xb1, 0xc0, 0x77, 0xdf, 0xa0, 0x24, 0xd0, 0x5e, 0x00, 0x0b, 0x58, 0xac, 0xe0, - 0x79, 0xad, 0x6e, 0x87, 0x0f, 0x8a, 0xf3, 0xbd, 0xb7, 0x1c, 0xd7, 0xa5, 0xbd, 0x05, 0x53, 0xc8, - 0x38, 0x56, 0x32, 0xc1, 0x85, 0x96, 0xf9, 0xbb, 0x06, 0xcc, 0xa5, 0x1b, 0x71, 0x7c, 0xbc, 0x08, - 0x8d, 0xeb, 0xab, 0xe9, 0x46, 0xe8, 0xba, 0x24, 0xe3, 0x90, 0x8f, 0xb6, 0xa0, 0xc2, 0x13, 0x28, - 0xac, 0x4e, 0x9a, 0x89, 0x13, 0x31, 0xf1, 0x38, 0xe7, 0x86, 0x44, 0xc0, 0x21, 0x94, 0xf9, 0x57, - 0x06, 0xa0, 0xf1, 0xe6, 0x0b, 0xda, 0x84, 0x33, 0xae, 0x45, 0x59, 0x74, 0xe9, 0xb8, 0x9e, 0x98, - 0xe4, 0x73, 0x6a, 0x92, 0x67, 0x36, 0x32, 0x64, 0x70, 0xe6, 0xc8, 0x28, 0x89, 0x2c, 0x3c, 0x81, - 0x24, 0xd2, 0xec, 0x00, 0xc4, 0xaf, 0x95, 0xd0, 0x45, 0x28, 0x79, 0x56, 0x3f, 0x0c, 0x8a, 0x51, - 0x9d, 0x22, 0x1e, 0xae, 0x0b, 0x0e, 0xfa, 0x1a, 0x4c, 0xed, 0x5b, 0xee, 0x30, 0xfc, 0xcf, 0x80, - 0xe8, 0xa1, 0xe0, 0x9b, 0x9c, 0x88, 0x25, 0xcf, 0xfc, 0x93, 0x02, 0xd4, 0xb5, 0xeb, 0xf6, 0xa7, - 0x51, 0x2d, 0x4d, 0x0d, 0x2c, 0xb6, 0x1b, 0xbe, 0x71, 0x7c, 0x25, 0xf7, 0x4b, 0x00, 0x9e, 0x03, - 0xc6, 0x8b, 0xe0, 0xbf, 0x28, 0x96, 0xd0, 0xa9, 0xf4, 0xba, 0xf8, 0x34, 0xd2, 0x6b, 0xf3, 0x3d, - 0x03, 0x66, 0x53, 0xb3, 0x41, 0x57, 0x00, 0x68, 0xf4, 0x4b, 0x7d, 0x89, 0xa8, 0x49, 0x10, 0xcb, - 0x61, 0x4d, 0x4a, 0x64, 0xc1, 0x84, 0x32, 0xc7, 0x13, 0x19, 0xe1, 0xaa, 0x13, 0xa8, 0xcf, 0x13, - 0x67, 0xc1, 0x09, 0x2e, 0x4e, 0x49, 0x9b, 0xff, 0x6a, 0xc0, 0x73, 0xc7, 0x5d, 0x59, 0xf0, 0x9a, - 0x48, 0xdd, 0x4b, 0x44, 0x79, 0xb6, 0x91, 0xac, 0x89, 0x6e, 0x25, 0xd9, 0x38, 0x2d, 0x8f, 0xae, - 0x42, 0x5d, 0x23, 0xa9, 0x09, 0x46, 0x11, 0x58, 0x1b, 0x8e, 0x75, 0xb9, 0x27, 0x92, 0x20, 0x99, - 0xff, 0x68, 0xc0, 0x99, 0xac, 0x36, 0x05, 0x0a, 0xc2, 0xc7, 0xb2, 0x32, 0x31, 0xbe, 0x7d, 0xf2, - 0xce, 0x47, 0x53, 0x3c, 0x99, 0x5d, 0xf3, 0x58, 0x70, 0x90, 0xfd, 0x8c, 0xf6, 0xc2, 0x75, 0x80, - 0x58, 0x06, 0xcd, 0x41, 0x71, 0x8f, 0x1c, 0x48, 0x6b, 0x62, 0xfe, 0x27, 0x3a, 0x93, 0xd8, 0x62, - 0x6a, 0x4f, 0x7d, 0xa7, 0x70, 0xdd, 0xf8, 0x4e, 0xf5, 0x83, 0x3f, 0x6c, 0x9c, 0x7a, 0xf7, 0x5f, - 0x2e, 0x9e, 0x32, 0x7f, 0xc7, 0x00, 0x3d, 0x69, 0x41, 0xdf, 0x82, 0xda, 0x2e, 0x63, 0x03, 0x41, - 0x52, 0x2f, 0x09, 0xc4, 0x83, 0xd1, 0xd7, 0xb7, 0xb6, 0x36, 0x05, 0x11, 0xc7, 0x7c, 0xd4, 0x04, - 0xe0, 0x3f, 0xa8, 0x94, 0x2e, 0xc5, 0x2f, 0x7a, 0xb8, 0x74, 0x47, 0x8a, 0x6b, 0x12, 0xe8, 0x79, - 0x5e, 0x04, 0x4a, 0x61, 0xf9, 0x8f, 0x36, 0x75, 0x59, 0x00, 0x4a, 0xc9, 0x90, 0x67, 0xfe, 0x85, - 0x01, 0xf3, 0x63, 0x4f, 0x4c, 0xd0, 0xfd, 0x28, 0x85, 0x31, 0xf2, 0x6f, 0xa1, 0xec, 0xb4, 0xe7, - 0xc4, 0x6e, 0xff, 0xe7, 0x06, 0x40, 0xdc, 0x12, 0x40, 0x2e, 0x4c, 0x4b, 0xe0, 0x44, 0xde, 0x94, - 0x67, 0xc2, 0x67, 0xd4, 0x04, 0xa6, 0x3b, 0x1a, 0x1e, 0x4e, 0xa0, 0xf3, 0x52, 0xb7, 0xef, 0x0f, - 0x3d, 0x26, 0x36, 0x53, 0x21, 0xf9, 0x5a, 0xfa, 0x76, 0xc8, 0xc0, 0xb1, 0x8c, 0xf9, 0x5b, 0x53, - 0xb0, 0x90, 0x71, 0xbf, 0xfa, 0xff, 0xb8, 0x17, 0xf5, 0x02, 0x54, 0xe4, 0x9b, 0x56, 0x9a, 0xce, - 0x19, 0xe4, 0x93, 0x57, 0x8a, 0x43, 0x3e, 0xba, 0x0c, 0x75, 0xc7, 0xb3, 0x65, 0xa7, 0xd7, 0x0a, - 0x5b, 0x0b, 0xf2, 0x62, 0x24, 0x26, 0x63, 0x5d, 0x26, 0xd9, 0x8b, 0x28, 0x3f, 0x56, 0x77, 0x6a, - 0x5a, 0xfd, 0xc7, 0xa1, 0x7c, 0x79, 0x5a, 0xc9, 0xf3, 0x41, 0x44, 0xe3, 0x14, 0x6b, 0x30, 0x38, - 0x01, 0x8a, 0x7e, 0xdd, 0x80, 0x39, 0x45, 0x58, 0x09, 0x98, 0xd3, 0xb5, 0xec, 0xe8, 0x39, 0xd8, - 0x09, 0xc3, 0xe0, 0xa2, 0x5a, 0xdc, 0x1c, 0x4e, 0xc1, 0xe3, 0x31, 0x85, 0xe6, 0x7d, 0x98, 0x1f, - 0x4b, 0xf0, 0x1e, 0x2f, 0x7b, 0x20, 0xe2, 0x9f, 0xda, 0x52, 0xd9, 0x83, 0xfc, 0x5f, 0x36, 0xc9, - 0x33, 0x3f, 0x34, 0x60, 0x26, 0x95, 0x1f, 0xe7, 0x2a, 0xd6, 0xef, 0xeb, 0xc5, 0xfa, 0x89, 0x6b, - 0x8f, 0x44, 0xd9, 0x6e, 0xfe, 0x43, 0x01, 0x6a, 0xd1, 0xd3, 0x16, 0xf4, 0x62, 0x62, 0xe1, 0xe7, - 0xf5, 0x85, 0x3f, 0x1c, 0x35, 0xa4, 0xa0, 0x66, 0x85, 0xb7, 0xa0, 0x16, 0x3d, 0x9d, 0x52, 0xd3, - 0x9b, 0xe4, 0x79, 0x54, 0xe4, 0x84, 0xd1, 0x7b, 0x2c, 0x1c, 0xe3, 0xf1, 0x7c, 0x33, 0x7c, 0xdb, - 0x74, 0xdb, 0x71, 0x5d, 0x87, 0xaa, 0xab, 0x82, 0xa2, 0xb8, 0x2a, 0x88, 0xf2, 0xcd, 0xd5, 0x0c, - 0x19, 0x9c, 0x39, 0x12, 0xbd, 0x05, 0x53, 0x94, 0x91, 0x01, 0x55, 0xad, 0xbd, 0x6b, 0x93, 0x3e, - 0x00, 0x22, 0x03, 0xd1, 0xf7, 0x88, 0x3e, 0x36, 0xa7, 0x50, 0x2c, 0x31, 0xcd, 0xcf, 0x0c, 0xa8, - 0x86, 0x22, 0xe8, 0x52, 0xc2, 0x8e, 0x8b, 0x29, 0x3b, 0x0a, 0xb9, 0xff, 0xb3, 0x66, 0x34, 0xbb, - 0x30, 0x93, 0xbc, 0xbf, 0xd4, 0xaa, 0x7b, 0xe3, 0xb8, 0xea, 0x1e, 0x5d, 0x82, 0xaa, 0xe5, 0xba, - 0xfe, 0x3b, 0x6b, 0xde, 0xbe, 0x7a, 0x53, 0x18, 0xdd, 0xb7, 0xad, 0x28, 0x3a, 0x8e, 0x24, 0x5a, - 0x5f, 0xff, 0xf8, 0xd3, 0xa5, 0x53, 0x9f, 0x7c, 0xba, 0x74, 0xea, 0x9f, 0x3f, 0x5d, 0x3a, 0xf5, - 0xee, 0xe1, 0x92, 0xf1, 0xf1, 0xe1, 0x92, 0xf1, 0xc9, 0xe1, 0x92, 0xf1, 0x6f, 0x87, 0x4b, 0xc6, - 0x6f, 0xff, 0xfb, 0xd2, 0xa9, 0xfb, 0x85, 0xfd, 0xcb, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, 0x99, - 0x5c, 0x26, 0xda, 0x36, 0x3e, 0x00, 0x00, + // 3813 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe4, 0x5b, 0x4d, 0x6c, 0x1c, 0xc9, + 0x75, 0x56, 0xcf, 0x0c, 0xe7, 0xe7, 0x0d, 0xc5, 0x9f, 0xa2, 0x64, 0x8d, 0x64, 0x99, 0x23, 0xb7, + 0xbd, 0x86, 0x37, 0xd6, 0x0e, 0x23, 0xed, 0xae, 0xb2, 0xfe, 0xd9, 0xf5, 0x72, 0x86, 0x94, 0x96, + 0x32, 0x25, 0x31, 0x35, 0xdc, 0x5d, 0x7b, 0x37, 0x88, 0xd3, 0x6c, 0xd6, 0x0c, 0x7b, 0xd9, 0xd3, + 0x3d, 0xee, 0xaa, 0xe1, 0x8a, 0x81, 0x0d, 0x2c, 0x1c, 0x18, 0x49, 0x6e, 0x89, 0x93, 0x00, 0xbe, + 0x04, 0x88, 0x81, 0xfc, 0x20, 0xc8, 0x21, 0x87, 0xe4, 0x92, 0x4b, 0xe0, 0x20, 0x40, 0xb0, 0xa7, + 0xc4, 0xc7, 0x1c, 0x92, 0x41, 0x76, 0x72, 0xf0, 0x31, 0x7f, 0x97, 0x40, 0xa7, 0xa0, 0x7e, 0xba, + 0xbb, 0xba, 0xa7, 0xc9, 0xd5, 0x34, 0x25, 0xd9, 0x81, 0x6f, 0x9c, 0xf7, 0x5e, 0x7d, 0xaf, 0xea, + 0xf5, 0xab, 0x7a, 0x3f, 0x55, 0x84, 0xaf, 0xf4, 0x1d, 0x76, 0x30, 0xda, 0x6b, 0xd9, 0xfe, 0x60, + 0xcd, 0x1f, 0x12, 0x8f, 0x1e, 0x38, 0x3d, 0xb6, 0xe6, 0x07, 0x4e, 0xdf, 0xf1, 0xd6, 0x86, 0x87, + 0xfd, 0xb5, 0xbd, 0x91, 0xe3, 0xee, 0xaf, 0x59, 0x43, 0x67, 0xed, 0xe8, 0xc6, 0x5a, 0x9f, 0x78, + 0x24, 0xb0, 0x18, 0xd9, 0x6f, 0x0d, 0x03, 0x9f, 0xf9, 0xe8, 0x7a, 0x3c, 0xba, 0x15, 0x8d, 0x6e, + 0xc9, 0xd1, 0xad, 0xe1, 0x61, 0xbf, 0x25, 0x46, 0xb7, 0xac, 0xa1, 0xd3, 0x3a, 0xba, 0x71, 0xe5, + 0x05, 0x4d, 0x57, 0xdf, 0xef, 0xfb, 0x6b, 0x02, 0x64, 0x6f, 0xd4, 0x13, 0xbf, 0xc4, 0x0f, 0xf1, + 0x97, 0x04, 0xbf, 0xf2, 0xd2, 0xe1, 0x2b, 0xb4, 0xe5, 0xf8, 0x5c, 0xf7, 0xc0, 0xb2, 0x0f, 0x1c, + 0x8f, 0x04, 0xc7, 0x62, 0x4a, 0xd6, 0xd0, 0xa1, 0x6b, 0x03, 0xc2, 0xac, 0x8c, 0x29, 0x5d, 0x59, + 0x3b, 0x69, 0x54, 0x30, 0xf2, 0x98, 0x33, 0x20, 0x53, 0x03, 0x6e, 0x7d, 0xdc, 0x00, 0x6a, 0x1f, + 0x90, 0x81, 0x35, 0x35, 0xee, 0xc5, 0x93, 0xc6, 0x8d, 0x98, 0xe3, 0xae, 0x39, 0x1e, 0xa3, 0x2c, + 0x98, 0x1a, 0xa4, 0xad, 0x89, 0x92, 0xe0, 0x88, 0x04, 0xf1, 0x82, 0xc8, 0x43, 0x6b, 0x30, 0x74, + 0x49, 0xd6, 0x9a, 0xae, 0xab, 0x51, 0x87, 0xa3, 0x3d, 0x12, 0x78, 0x84, 0x11, 0x1a, 0x0e, 0xcb, + 0x90, 0x36, 0x7f, 0x54, 0x82, 0xcb, 0x6d, 0xc7, 0xb3, 0x82, 0xe3, 0x36, 0xb7, 0x3e, 0x26, 0xdf, + 0x1a, 0x11, 0xca, 0x1e, 0x0c, 0x99, 0xe3, 0x7b, 0x14, 0xfd, 0x1a, 0x54, 0xb9, 0xe9, 0xf6, 0x2d, + 0x66, 0x35, 0x8c, 0x6b, 0xc6, 0xe7, 0xeb, 0x37, 0x7f, 0xb1, 0x25, 0xe1, 0x5b, 0xfa, 0x4a, 0xc4, + 0xd7, 0xe3, 0xf3, 0x6a, 0x71, 0xe9, 0xd6, 0xd1, 0x8d, 0xd6, 0x83, 0xbd, 0xf7, 0x88, 0xcd, 0xee, + 0x11, 0x66, 0xb5, 0xd1, 0x87, 0xe3, 0xe6, 0xb9, 0xc9, 0xb8, 0x09, 0x31, 0x0d, 0x47, 0xa8, 0xe8, + 0x73, 0x50, 0xb6, 0xe8, 0x6d, 0xc7, 0x25, 0x8d, 0xc2, 0x35, 0xe3, 0xf3, 0xb5, 0xf6, 0x82, 0x92, + 0x2e, 0xaf, 0x0b, 0x2a, 0x56, 0x5c, 0x74, 0x0b, 0x16, 0x02, 0x72, 0xe4, 0x50, 0xc7, 0xf7, 0x3a, + 0xfe, 0x60, 0xe0, 0xb0, 0x46, 0x31, 0x29, 0x2f, 0xa9, 0x38, 0x25, 0x85, 0xbe, 0x08, 0x8b, 0x21, + 0xe5, 0x1e, 0xa1, 0xd4, 0xea, 0x93, 0x46, 0x49, 0x0c, 0x5c, 0x54, 0x03, 0x2b, 0x8a, 0x8c, 0xd3, + 0x72, 0xa8, 0x0d, 0x28, 0x24, 0xad, 0x8f, 0xd8, 0x81, 0x1f, 0xdc, 0xb7, 0x06, 0xa4, 0x31, 0x27, + 0x46, 0x47, 0x8b, 0x8a, 0x39, 0x38, 0x43, 0x1a, 0x6d, 0xc2, 0x4a, 0x92, 0xba, 0x39, 0xb0, 0x1c, + 0xb7, 0x51, 0x16, 0x20, 0x2b, 0x0a, 0xa4, 0xae, 0xb1, 0x70, 0x96, 0x3c, 0xfa, 0x1a, 0x5c, 0x4c, + 0xae, 0x8b, 0x11, 0x39, 0x9b, 0x8a, 0x00, 0xba, 0xa8, 0x80, 0xce, 0x27, 0x98, 0x38, 0x7b, 0x0c, + 0xba, 0x0f, 0x9f, 0x98, 0x62, 0xc8, 0x69, 0x55, 0x05, 0xda, 0x27, 0x14, 0xda, 0x42, 0x92, 0x8b, + 0x4f, 0x18, 0x65, 0x7e, 0x19, 0x96, 0x35, 0x0f, 0xea, 0xfa, 0xa3, 0xc0, 0x26, 0xda, 0x77, 0x35, + 0x4e, 0xfb, 0xae, 0xe6, 0x1f, 0x18, 0x70, 0xb1, 0xed, 0xb0, 0xbd, 0x91, 0x7d, 0x48, 0xd8, 0xdb, + 0x64, 0xef, 0x0d, 0xdf, 0x3f, 0xec, 0x58, 0x23, 0x4a, 0xd0, 0xb7, 0x01, 0x6c, 0x7f, 0x30, 0xf0, + 0xbd, 0xee, 0x90, 0xd8, 0xca, 0xfb, 0x5e, 0x6f, 0xcd, 0x72, 0x86, 0xb4, 0x3a, 0x62, 0xbc, 0x8e, + 0xda, 0xbe, 0xa2, 0xe6, 0x81, 0xa6, 0x79, 0x58, 0xd3, 0x67, 0xfe, 0x59, 0x01, 0xe6, 0xc4, 0x7a, + 0x9e, 0xc1, 0x1e, 0xf8, 0x06, 0x94, 0x28, 0x5f, 0x63, 0x41, 0xa0, 0xff, 0xd2, 0x6c, 0x6b, 0x94, + 0x46, 0x1f, 0x12, 0xbb, 0x3d, 0xaf, 0x94, 0x94, 0xf8, 0x2f, 0x2c, 0x20, 0x91, 0x05, 0x65, 0xca, + 0x2c, 0x36, 0xa2, 0x62, 0xbb, 0xd4, 0x6f, 0x7e, 0x31, 0x0f, 0xb8, 0x00, 0x88, 0xbf, 0xa0, 0xfc, + 0x8d, 0x15, 0xb0, 0xf9, 0x37, 0x05, 0xa8, 0x0b, 0xb9, 0x8e, 0xef, 0xf5, 0x9c, 0xfe, 0x33, 0xb0, + 0xd7, 0x37, 0x13, 0xf6, 0x7a, 0x35, 0xc7, 0x92, 0xe4, 0x54, 0x4f, 0xb4, 0x5a, 0x3f, 0x65, 0xb5, + 0xaf, 0xe6, 0x57, 0x71, 0xba, 0xed, 0xfe, 0xc9, 0x80, 0x45, 0x4d, 0x7a, 0xdb, 0xa1, 0x0c, 0xfd, + 0xca, 0x94, 0xfd, 0x5a, 0x8f, 0x67, 0x3f, 0x3e, 0x5a, 0x58, 0x6f, 0x49, 0x69, 0xab, 0x86, 0x14, + 0xcd, 0x76, 0xbf, 0x0a, 0x73, 0x0e, 0x23, 0x03, 0xda, 0x28, 0x5c, 0x2b, 0xe6, 0xf4, 0x07, 0x39, + 0xd7, 0xf6, 0x79, 0xa5, 0x65, 0x6e, 0x8b, 0xe3, 0x61, 0x09, 0x6b, 0xfe, 0x77, 0x31, 0xb1, 0x22, + 0x6e, 0x54, 0xe4, 0x41, 0x95, 0x05, 0x4e, 0xbf, 0x4f, 0x02, 0xda, 0x30, 0x84, 0xda, 0xd7, 0x73, + 0xa8, 0xdd, 0x95, 0x10, 0x3b, 0xbe, 0xeb, 0xd8, 0xc7, 0xf1, 0x1a, 0x15, 0x99, 0xe2, 0x48, 0x07, + 0x5a, 0x87, 0x5a, 0x30, 0xf2, 0xa4, 0xa0, 0x0a, 0x2b, 0x9f, 0x51, 0xe2, 0x35, 0x1c, 0x32, 0x1e, + 0x8d, 0x9b, 0x0b, 0x32, 0xe4, 0x85, 0x14, 0x1c, 0x8f, 0x42, 0x6e, 0xe2, 0xf0, 0x91, 0x5e, 0xf0, + 0x4a, 0x9e, 0xc3, 0x47, 0xf8, 0x58, 0xe4, 0xce, 0x31, 0x4d, 0x3f, 0x6c, 0xd0, 0x3e, 0x5c, 0xa5, + 0x23, 0xdb, 0x26, 0x94, 0xf6, 0x46, 0xae, 0x98, 0x14, 0x7d, 0xc3, 0xa1, 0xcc, 0x0f, 0x8e, 0xb7, + 0x1d, 0x1e, 0xea, 0x78, 0xc4, 0x9a, 0x6b, 0x5f, 0x9b, 0x8c, 0x9b, 0x57, 0xbb, 0xa7, 0xc8, 0xe1, + 0x53, 0x51, 0xd0, 0xd7, 0xa1, 0xd1, 0xb3, 0x1c, 0x97, 0xec, 0x67, 0x68, 0x98, 0x13, 0x1a, 0xae, + 0x4e, 0xc6, 0xcd, 0xc6, 0xed, 0x13, 0x64, 0xf0, 0x89, 0xa3, 0xcd, 0xbb, 0xb0, 0x3c, 0xe5, 0xf3, + 0xe8, 0x65, 0xa8, 0xbb, 0x16, 0x65, 0x6f, 0x91, 0x80, 0xc7, 0x0c, 0xe1, 0xca, 0xc5, 0x38, 0xe4, + 0x6d, 0xc7, 0x2c, 0xac, 0xcb, 0x99, 0x7f, 0x6f, 0x40, 0x4d, 0x80, 0x3d, 0x83, 0xcd, 0xf0, 0xf5, + 0xe4, 0x66, 0x78, 0x31, 0x87, 0x57, 0x9e, 0xb0, 0x0d, 0x00, 0xaa, 0x72, 0x11, 0x7e, 0xdf, 0xfc, + 0xcd, 0x92, 0xda, 0x12, 0xdb, 0x7e, 0x3f, 0x4c, 0xac, 0xd6, 0xa0, 0x66, 0xfb, 0x1e, 0xb3, 0xf8, + 0xec, 0x55, 0x84, 0x5c, 0x0e, 0x5d, 0xb4, 0x13, 0x32, 0x70, 0x2c, 0xc3, 0xe3, 0x69, 0xcf, 0x77, + 0x5d, 0xff, 0x7d, 0xe1, 0xd0, 0xd5, 0xf8, 0x44, 0xb9, 0x2d, 0xa8, 0x58, 0x71, 0xd1, 0x75, 0xa8, + 0x0e, 0x79, 0x9c, 0xf6, 0xd5, 0xe1, 0x55, 0x8d, 0x0d, 0xb0, 0xa3, 0xe8, 0x38, 0x92, 0x40, 0x2f, + 0xc1, 0x3c, 0x75, 0x3c, 0x9b, 0x74, 0x89, 0xed, 0x7b, 0xfb, 0x54, 0x38, 0x5a, 0xb1, 0xbd, 0x34, + 0x19, 0x37, 0xe7, 0xbb, 0x1a, 0x1d, 0x27, 0xa4, 0xd0, 0xdb, 0x50, 0x13, 0xbf, 0x77, 0x1d, 0x95, + 0x0f, 0xd5, 0x6f, 0xfe, 0xc2, 0xe3, 0x7d, 0x15, 0x3e, 0xa2, 0x7d, 0x9e, 0x2f, 0xb2, 0x1b, 0x02, + 0xe0, 0x18, 0x0b, 0xdd, 0x04, 0xe0, 0x49, 0x34, 0x65, 0xd6, 0x60, 0x48, 0x45, 0x92, 0x54, 0x8d, + 0xf7, 0xce, 0x6e, 0xc4, 0xc1, 0x9a, 0x14, 0xfa, 0x02, 0xd4, 0x98, 0xe5, 0xb8, 0xdb, 0x8e, 0x47, + 0xa8, 0x48, 0x87, 0x8a, 0x52, 0xc1, 0x6e, 0x48, 0xc4, 0x31, 0x1f, 0xb5, 0x00, 0x5c, 0xee, 0xb1, + 0xed, 0x63, 0x46, 0xa8, 0x48, 0x77, 0x8a, 0xed, 0x05, 0x0e, 0xbe, 0x1d, 0x51, 0xb1, 0x26, 0xc1, + 0xad, 0xee, 0xf9, 0xef, 0x5b, 0x0e, 0x6b, 0xd4, 0x92, 0x56, 0xbf, 0xef, 0xbf, 0x6d, 0x39, 0x0c, + 0x2b, 0x2e, 0x7a, 0x0e, 0x2a, 0x47, 0xca, 0xcf, 0x41, 0x80, 0xd6, 0x79, 0x66, 0x19, 0xfa, 0x77, + 0xc8, 0x33, 0xff, 0x3c, 0x0c, 0x95, 0x0f, 0x46, 0x6c, 0x38, 0x62, 0x68, 0x13, 0x0a, 0xcc, 0x57, + 0x7e, 0xfd, 0x42, 0x68, 0xc1, 0x38, 0x6f, 0x0f, 0xed, 0x17, 0x07, 0x47, 0x4c, 0x7a, 0x24, 0x20, + 0x9e, 0x4d, 0xda, 0xe5, 0xc9, 0xb8, 0x59, 0xd8, 0xf5, 0x71, 0x81, 0xf9, 0x68, 0x0f, 0x60, 0x38, + 0xa2, 0x07, 0x5d, 0x62, 0x07, 0x84, 0xa9, 0xa8, 0x78, 0xf3, 0x74, 0xb8, 0x6d, 0xdf, 0xb6, 0xdc, + 0x34, 0xa6, 0xb0, 0xc4, 0x4e, 0x84, 0x84, 0x35, 0x54, 0xe4, 0x43, 0xdd, 0x19, 0x58, 0x7d, 0xb2, + 0x6d, 0xed, 0x11, 0x97, 0xbb, 0x56, 0x71, 0xf6, 0x13, 0x71, 0x2b, 0x02, 0x88, 0xcf, 0x81, 0x98, + 0x46, 0xb1, 0xae, 0xc1, 0xfc, 0xae, 0x01, 0x2b, 0xc2, 0x56, 0x3b, 0x3e, 0x65, 0x32, 0xe3, 0x14, + 0x67, 0xe5, 0x73, 0x50, 0xe1, 0x27, 0xa7, 0xe5, 0xed, 0x8b, 0x58, 0x52, 0x93, 0xa6, 0xee, 0x48, + 0x12, 0x0e, 0x79, 0xe8, 0x2a, 0x94, 0xac, 0xa0, 0x2f, 0x77, 0x76, 0xad, 0x5d, 0xe5, 0x01, 0x7e, + 0x3d, 0xe8, 0x53, 0x2c, 0xa8, 0xfc, 0xbb, 0x52, 0x3b, 0x70, 0x86, 0x53, 0x55, 0x44, 0x57, 0x50, + 0xb1, 0xe2, 0x9a, 0xdf, 0xad, 0xc0, 0xbc, 0x5e, 0x17, 0x3d, 0x83, 0xe4, 0xa6, 0x07, 0xd5, 0x30, + 0xcf, 0x56, 0x9f, 0xf2, 0x2b, 0xb3, 0x59, 0x59, 0x26, 0xe0, 0x58, 0x61, 0xb4, 0xe7, 0xf9, 0xd6, + 0x0f, 0x7f, 0xe1, 0x08, 0x1b, 0xf9, 0xb0, 0xa4, 0x02, 0x26, 0xd9, 0x6f, 0x1f, 0x8b, 0xcf, 0xa0, + 0xe2, 0xdc, 0x8c, 0x9e, 0x78, 0x61, 0x32, 0x6e, 0x2e, 0xed, 0xa6, 0xa0, 0xf0, 0x14, 0x38, 0xfa, + 0x1a, 0x94, 0x7a, 0x81, 0x3f, 0x10, 0x67, 0xcc, 0xcc, 0x4a, 0xc4, 0x07, 0xbc, 0x1d, 0xf8, 0x03, + 0x2c, 0x40, 0x90, 0x0d, 0xe5, 0x3d, 0x51, 0x73, 0xa8, 0xf3, 0x67, 0xd6, 0x0c, 0x2d, 0x5d, 0xaf, + 0xb4, 0x81, 0x7f, 0x7d, 0x49, 0xc6, 0x0a, 0x1a, 0xdd, 0x48, 0x46, 0xb0, 0xb2, 0xd8, 0xd9, 0x8b, + 0xa7, 0x45, 0x2f, 0xd4, 0x81, 0x22, 0xf1, 0x8e, 0x1a, 0x15, 0xb1, 0x3d, 0x3e, 0x7b, 0xfa, 0x1a, + 0x37, 0xbd, 0xa3, 0xb7, 0xac, 0xa0, 0x5d, 0x57, 0xee, 0x50, 0xdc, 0xf4, 0x8e, 0x30, 0x1f, 0x8d, + 0x8e, 0xa0, 0xae, 0x59, 0xaf, 0x51, 0x15, 0x60, 0x5f, 0xcd, 0x9f, 0x32, 0xc9, 0xca, 0x27, 0xda, + 0x72, 0xda, 0xb7, 0xc2, 0xba, 0x22, 0xf4, 0xfb, 0x06, 0x5c, 0xdc, 0xf7, 0xed, 0x43, 0x12, 0x74, + 0x59, 0x60, 0x31, 0xd2, 0x3f, 0x56, 0xe1, 0x4a, 0x9c, 0x7e, 0xf5, 0x9b, 0x9d, 0xd9, 0xa6, 0xb0, + 0x91, 0x05, 0xd5, 0xbe, 0x3c, 0x19, 0x37, 0x2f, 0x66, 0xb2, 0x70, 0xb6, 0x72, 0xf3, 0x0f, 0xe7, + 0xd4, 0xa9, 0xa9, 0x4a, 0xcb, 0x17, 0xa1, 0xc4, 0x8e, 0x87, 0x61, 0x61, 0xd9, 0x0c, 0xf3, 0xf7, + 0xdd, 0xe3, 0x21, 0x79, 0x34, 0x6e, 0x2e, 0x6a, 0xa2, 0x9c, 0x84, 0x85, 0xb0, 0xe6, 0x30, 0x85, + 0xa7, 0xe7, 0x30, 0x2d, 0x00, 0xb9, 0x84, 0x1e, 0x2f, 0x7c, 0xd5, 0xd1, 0xc2, 0x77, 0xfa, 0x46, + 0x44, 0xc5, 0x9a, 0x04, 0x7a, 0x1b, 0x8a, 0x7d, 0x95, 0xde, 0xcd, 0xbc, 0xcd, 0xef, 0x38, 0x4c, + 0x9f, 0x4e, 0x85, 0x7b, 0xd0, 0x1d, 0x87, 0x61, 0x8e, 0xc8, 0xcb, 0x3e, 0x71, 0x96, 0xd2, 0xc6, + 0x5c, 0x9e, 0x34, 0x5f, 0x6c, 0x58, 0x05, 0x1c, 0x1d, 0x8d, 0x82, 0x48, 0xb1, 0x02, 0xe6, 0xb1, + 0x9a, 0x67, 0x27, 0xe4, 0x21, 0xdb, 0x70, 0x02, 0xd5, 0xd0, 0xd0, 0xf2, 0xdc, 0x90, 0x83, 0x35, + 0x29, 0x74, 0x00, 0xf3, 0x54, 0xa0, 0xaa, 0x50, 0x55, 0xc9, 0x1d, 0xaa, 0x64, 0x8a, 0xa2, 0x61, + 0xe1, 0x04, 0x32, 0x7a, 0x0f, 0x2a, 0x54, 0xfc, 0x45, 0xf3, 0x6d, 0x1f, 0x09, 0xa3, 0x1b, 0x38, + 0xea, 0x17, 0x49, 0x16, 0xc5, 0xa1, 0x02, 0xf3, 0xbf, 0xc2, 0x8c, 0x55, 0xc4, 0x27, 0x37, 0xa3, + 0x6d, 0xf1, 0xf4, 0x2a, 0x87, 0xd4, 0x51, 0x51, 0x78, 0x46, 0x47, 0x85, 0xf9, 0x3f, 0xe5, 0x70, + 0x4f, 0xca, 0x64, 0xff, 0x06, 0xcc, 0x0d, 0x0f, 0x2c, 0x1a, 0x6e, 0xca, 0x4f, 0x86, 0x49, 0xf1, + 0x0e, 0x27, 0x3e, 0x1a, 0x37, 0x41, 0x86, 0x72, 0xfe, 0x0b, 0x4b, 0x49, 0x91, 0x02, 0x5b, 0x9e, + 0x4d, 0x5c, 0x97, 0xec, 0xab, 0xa4, 0x36, 0x4e, 0x81, 0x43, 0x06, 0x8e, 0x65, 0xd0, 0x2d, 0x28, + 0x07, 0xc4, 0xa2, 0xbe, 0xa7, 0x76, 0xd6, 0x6a, 0xe8, 0x99, 0x58, 0x50, 0x1f, 0x71, 0x8f, 0x90, + 0xe5, 0xb5, 0xf8, 0x8d, 0x95, 0x34, 0x7a, 0x1e, 0x2a, 0x83, 0xd3, 0x5b, 0x7f, 0x21, 0x1f, 0xf5, + 0x60, 0x81, 0x32, 0x2b, 0x60, 0x51, 0xae, 0x99, 0x23, 0xbd, 0x45, 0x93, 0x71, 0x73, 0xa1, 0x9b, + 0x40, 0xc1, 0x29, 0x54, 0x34, 0x82, 0x15, 0xdb, 0x1f, 0x0c, 0x5d, 0xc2, 0x4f, 0xb8, 0x58, 0x59, + 0x79, 0x66, 0x65, 0x97, 0x26, 0xe3, 0xe6, 0x4a, 0x67, 0x1a, 0x0a, 0x67, 0xe1, 0xa3, 0x57, 0xa1, + 0xba, 0x3f, 0x0a, 0x2c, 0x4e, 0x54, 0xa9, 0xf2, 0xa7, 0xc3, 0xe2, 0x60, 0x43, 0xd1, 0x1f, 0x8d, + 0x9b, 0xe7, 0x79, 0x76, 0xdd, 0x0a, 0x09, 0x38, 0x1a, 0x82, 0xf6, 0xe0, 0x8a, 0x2f, 0x12, 0x57, + 0x79, 0x9c, 0xc9, 0x40, 0x1f, 0x6e, 0x49, 0xd5, 0x3c, 0x34, 0x15, 0xe0, 0x95, 0x07, 0x27, 0x4a, + 0xe2, 0x53, 0x50, 0xd0, 0x2f, 0x43, 0xd9, 0x16, 0x55, 0xa4, 0x8a, 0x39, 0x33, 0xe6, 0x09, 0x20, + 0x5b, 0xc1, 0x1c, 0x00, 0x2b, 0x20, 0xd4, 0x87, 0xb2, 0x54, 0x28, 0x72, 0xf3, 0x7c, 0xdb, 0x43, + 0x3a, 0x96, 0x5c, 0x53, 0x7c, 0x24, 0xca, 0xdf, 0x58, 0xc1, 0xa3, 0x6f, 0x8a, 0xb6, 0x11, 0x3f, + 0x75, 0xeb, 0x62, 0x1f, 0xce, 0xd8, 0xc9, 0xeb, 0xf2, 0xb1, 0x5b, 0x5e, 0xcf, 0x4f, 0xb4, 0x8b, + 0xc4, 0x99, 0x2b, 0x61, 0x4d, 0x4f, 0xd5, 0xd9, 0xfa, 0x6c, 0xd0, 0x37, 0xb4, 0x22, 0x62, 0xfd, + 0x8c, 0x4b, 0xdb, 0xf5, 0xf5, 0xc2, 0xc2, 0xdc, 0x56, 0x29, 0x78, 0x52, 0x84, 0x57, 0xf6, 0x22, + 0x08, 0x6c, 0x38, 0x7d, 0x42, 0x99, 0xda, 0xf2, 0xc9, 0x8c, 0x5e, 0xb2, 0xb0, 0x2e, 0x67, 0xfe, + 0xa4, 0x04, 0xe7, 0x15, 0x9c, 0x0c, 0xf0, 0xe8, 0xe5, 0x44, 0x24, 0xff, 0x74, 0x2a, 0x92, 0x2f, + 0x27, 0x84, 0xb5, 0x58, 0xfe, 0x1d, 0x58, 0x48, 0x66, 0x0a, 0x2a, 0xa6, 0xaf, 0xe7, 0xc9, 0x4f, + 0x12, 0x4a, 0xe4, 0xe6, 0x4d, 0x66, 0x27, 0x38, 0xa5, 0x8c, 0xab, 0x57, 0xb1, 0x26, 0x54, 0x5f, + 0xcc, 0xa3, 0x5e, 0xc5, 0x95, 0x69, 0xf5, 0xdd, 0x04, 0x38, 0x4e, 0x29, 0xe3, 0xea, 0xed, 0x11, + 0x65, 0xfe, 0x20, 0x52, 0x5f, 0xca, 0xa3, 0xbe, 0x23, 0x30, 0x32, 0xd4, 0x77, 0x12, 0xe0, 0x38, + 0xa5, 0x0c, 0xfd, 0xd0, 0x80, 0x4b, 0xef, 0x11, 0xef, 0xd0, 0xf1, 0xe8, 0x8e, 0x33, 0x24, 0xae, + 0xe3, 0xc5, 0x76, 0x90, 0x87, 0xe5, 0xdd, 0xd9, 0x26, 0x72, 0x37, 0x09, 0x96, 0x9c, 0xd1, 0x27, + 0x27, 0xe3, 0xe6, 0xa5, 0xbb, 0xd9, 0xea, 0xf0, 0x49, 0xf3, 0x30, 0xff, 0x76, 0x4e, 0x6d, 0x14, + 0x3d, 0xaa, 0xe9, 0x71, 0xc0, 0xf8, 0x98, 0x38, 0xf0, 0x1d, 0x58, 0x10, 0x17, 0x65, 0x8e, 0xad, + 0x2e, 0x08, 0xf2, 0x79, 0xd8, 0x9d, 0x04, 0x86, 0x8c, 0xad, 0xc2, 0xc6, 0x49, 0x06, 0x4e, 0x29, + 0x43, 0xc7, 0x70, 0x5e, 0xea, 0x09, 0xb5, 0x17, 0xf3, 0xdc, 0x7e, 0xdc, 0x71, 0xd8, 0x1b, 0x11, + 0x84, 0x54, 0xbe, 0x3c, 0x19, 0x37, 0xcf, 0x27, 0xe8, 0x38, 0xa9, 0x09, 0x7d, 0x60, 0xc0, 0x92, + 0xd8, 0xb4, 0x9d, 0x03, 0xcb, 0xeb, 0xcb, 0xaf, 0xa1, 0x1c, 0xec, 0xb5, 0x1c, 0x49, 0xa4, 0x44, + 0x91, 0xca, 0x45, 0xa1, 0xb8, 0x95, 0xc2, 0xc6, 0x53, 0xda, 0xd4, 0xea, 0x5d, 0x2b, 0x5a, 0xfd, + 0x5c, 0xce, 0xd5, 0x6f, 0x5b, 0xd9, 0xab, 0x8f, 0xe9, 0x38, 0xa9, 0x09, 0x7d, 0xcf, 0x80, 0xa5, + 0xbd, 0xd4, 0x6d, 0x94, 0x8a, 0xca, 0x9d, 0x59, 0x0b, 0x86, 0x8c, 0x3b, 0x2d, 0x69, 0x82, 0x34, + 0x0b, 0x4f, 0xa9, 0x34, 0xff, 0xa3, 0x04, 0x68, 0xba, 0xe9, 0x8d, 0x5e, 0x4a, 0x9c, 0x97, 0xd7, + 0x52, 0xe7, 0xe5, 0x92, 0x3e, 0x42, 0x3b, 0x2e, 0xfb, 0x50, 0x96, 0x53, 0xcf, 0xd7, 0x4f, 0x50, + 0x73, 0x52, 0xb8, 0x59, 0x2e, 0xa4, 0xe0, 0x79, 0xd2, 0xad, 0x1c, 0x59, 0x39, 0xec, 0xd9, 0x34, + 0x65, 0xed, 0x94, 0x50, 0x01, 0xa2, 0x2a, 0x06, 0x49, 0xc7, 0x51, 0x1e, 0xfa, 0x7a, 0x6e, 0x0f, + 0x0d, 0x75, 0x2e, 0x46, 0x11, 0x4c, 0xd2, 0xb1, 0xae, 0x45, 0x59, 0xd2, 0xb5, 0xf6, 0x94, 0x4b, + 0x3e, 0x19, 0x4b, 0x6a, 0xee, 0xa8, 0xe0, 0xd1, 0x10, 0x6a, 0x91, 0x4f, 0x28, 0xff, 0x3b, 0x9b, + 0xae, 0x6c, 0xc7, 0x8b, 0x95, 0x98, 0x3f, 0xa8, 0x80, 0x56, 0x63, 0xa0, 0xd7, 0x60, 0x81, 0x92, + 0xe0, 0xc8, 0xb1, 0xc9, 0xba, 0x6d, 0xfb, 0x23, 0x2f, 0x8c, 0xf2, 0xd1, 0xdd, 0x70, 0x37, 0xc1, + 0xc5, 0x29, 0x69, 0x71, 0xef, 0x28, 0xc2, 0x96, 0xf2, 0xb9, 0x5c, 0xf7, 0x8e, 0xa9, 0x02, 0x54, + 0x35, 0xb6, 0x14, 0x70, 0xa2, 0x51, 0x56, 0x7c, 0x8a, 0x8d, 0x32, 0x07, 0xaa, 0x34, 0x19, 0x69, + 0xbf, 0x9c, 0x2b, 0xcb, 0x52, 0x11, 0x2d, 0x6a, 0xc7, 0x47, 0x61, 0x2c, 0x82, 0xe7, 0x56, 0x53, + 0x99, 0xea, 0x5c, 0x6e, 0xab, 0x7d, 0x4c, 0x8e, 0x6a, 0x43, 0x2d, 0x20, 0xd2, 0x82, 0x54, 0x79, + 0xd6, 0xc7, 0xd4, 0xdf, 0x58, 0x89, 0x63, 0xf2, 0xad, 0x91, 0x13, 0x90, 0x01, 0xf1, 0x18, 0x8d, + 0x2b, 0xb5, 0x90, 0x4b, 0x71, 0x8c, 0x8b, 0x46, 0x00, 0xc3, 0xa8, 0x6b, 0xab, 0xaa, 0xfc, 0x3c, + 0xa9, 0x69, 0xb2, 0xf5, 0x1b, 0x17, 0xc3, 0x31, 0x1d, 0x6b, 0x8a, 0xd0, 0xbb, 0x70, 0x39, 0xae, + 0x7a, 0x36, 0x88, 0xb5, 0x2f, 0x92, 0x02, 0x75, 0xb5, 0x21, 0x9b, 0xfd, 0x9f, 0x9a, 0x8c, 0x9b, + 0x97, 0x3b, 0x27, 0x09, 0xe1, 0x93, 0xc7, 0xa3, 0x87, 0x30, 0xef, 0xf9, 0xfb, 0xa4, 0x4b, 0x5c, + 0x62, 0x33, 0x3f, 0x50, 0xe5, 0x49, 0x7b, 0xb6, 0x55, 0xc9, 0x96, 0x96, 0xe5, 0xde, 0xd7, 0x90, + 0x64, 0x2f, 0x43, 0xa7, 0xe0, 0x84, 0x26, 0xf3, 0x8f, 0x0d, 0xc8, 0x78, 0xad, 0x90, 0xf0, 0x7f, + 0xe3, 0x29, 0xfa, 0xff, 0xe7, 0xa0, 0x4c, 0xe3, 0x9b, 0x05, 0xbd, 0x57, 0x2e, 0x1b, 0x2f, 0x8a, + 0x6b, 0xfe, 0x75, 0x09, 0x56, 0x32, 0x92, 0x4a, 0xf4, 0x40, 0xf5, 0x7d, 0x73, 0x5d, 0x73, 0x44, + 0xb7, 0xf3, 0x5a, 0xef, 0x57, 0x5c, 0x77, 0xb8, 0xee, 0x93, 0xba, 0xee, 0x08, 0x91, 0xb0, 0x86, + 0x1a, 0xf6, 0x71, 0x8b, 0x67, 0xea, 0xe3, 0xde, 0x05, 0x44, 0x1e, 0x0e, 0x7d, 0x4a, 0x54, 0x41, + 0xe1, 0x8b, 0xe3, 0xbc, 0x24, 0x5a, 0x1d, 0xd1, 0x3b, 0x94, 0xcd, 0x29, 0x09, 0x9c, 0x31, 0x0a, + 0xad, 0x41, 0xad, 0xe7, 0x07, 0x36, 0xe1, 0xf3, 0x15, 0xa7, 0x83, 0xd6, 0x2d, 0xb9, 0x1d, 0x32, + 0x70, 0x2c, 0x83, 0xec, 0xb8, 0x03, 0x56, 0xce, 0x73, 0x59, 0x23, 0x0d, 0x21, 0xf6, 0xdd, 0x89, + 0xad, 0x2f, 0xb4, 0x0e, 0x8b, 0x62, 0xd0, 0xfa, 0xce, 0x56, 0xd8, 0x25, 0x97, 0x2f, 0x92, 0x2e, + 0xa9, 0x21, 0xb2, 0x1b, 0x1b, 0xb3, 0x71, 0x5a, 0xde, 0xfc, 0xcf, 0x12, 0xac, 0x64, 0x54, 0x62, + 0xd1, 0x75, 0x81, 0xf1, 0x24, 0xae, 0x0b, 0x9e, 0x85, 0xcb, 0x3c, 0x0f, 0x15, 0xcf, 0xef, 0x58, + 0xf6, 0x01, 0x51, 0x17, 0xaf, 0x91, 0xd9, 0xee, 0x4b, 0x32, 0x0e, 0xf9, 0xa1, 0x77, 0x95, 0xce, + 0xe4, 0x5d, 0x33, 0x7b, 0xc4, 0x6b, 0x61, 0xd9, 0xdc, 0x73, 0x5c, 0xb2, 0x63, 0xb1, 0x03, 0xd5, + 0xb5, 0x8d, 0x62, 0xfa, 0x46, 0x82, 0x8b, 0x53, 0xd2, 0xe8, 0x4d, 0xa8, 0xc9, 0x8f, 0x17, 0xf4, + 0xe9, 0x4c, 0x37, 0x1c, 0xd1, 0xb4, 0xda, 0xe1, 0x70, 0x1c, 0x23, 0xa1, 0x21, 0x5c, 0x12, 0x39, + 0x16, 0x3f, 0x1b, 0x07, 0xce, 0xaf, 0x8b, 0x56, 0x93, 0x7a, 0xbb, 0x21, 0x5b, 0x4a, 0xb7, 0x78, + 0x0d, 0xb8, 0x95, 0x2d, 0xf2, 0xe8, 0x64, 0x16, 0x3e, 0x09, 0xd6, 0xf4, 0x20, 0xfb, 0x02, 0x22, + 0xb9, 0x42, 0xe3, 0x49, 0xad, 0xd0, 0xfc, 0x13, 0x03, 0x56, 0x32, 0x4a, 0xc1, 0x9f, 0xb9, 0x13, + 0xfc, 0x7f, 0x0b, 0xe9, 0x79, 0x6e, 0x1e, 0x11, 0x8f, 0xe5, 0xbb, 0x70, 0xd9, 0x91, 0x77, 0x1b, + 0x72, 0xaf, 0xbd, 0x3c, 0x73, 0xed, 0x26, 0xfa, 0x60, 0xc9, 0x4b, 0x8d, 0x27, 0x72, 0x26, 0x9f, + 0x7c, 0xc7, 0x55, 0xfa, 0x69, 0xde, 0x71, 0xfd, 0xc8, 0x80, 0x85, 0xe4, 0x8d, 0x0e, 0xfa, 0x14, + 0x14, 0x47, 0x81, 0xa3, 0x8c, 0x1e, 0x2d, 0xe4, 0x4d, 0xbc, 0x85, 0x39, 0x9d, 0xb3, 0x03, 0xd2, + 0x53, 0x5f, 0x34, 0x62, 0x63, 0xd2, 0xc3, 0x9c, 0x8e, 0x86, 0x50, 0x1f, 0x06, 0xfe, 0xc3, 0x63, + 0xd9, 0x0b, 0xcd, 0xf7, 0xfa, 0x6f, 0x27, 0x06, 0x88, 0xdb, 0x7b, 0x1a, 0x11, 0xeb, 0x2a, 0x44, + 0x9a, 0x32, 0xdd, 0x72, 0xf8, 0x99, 0x73, 0xf2, 0xef, 0x17, 0xa0, 0xa2, 0xfc, 0x0b, 0x7d, 0x1b, + 0x16, 0xfa, 0x09, 0xa3, 0xe7, 0x9b, 0x61, 0xea, 0x2a, 0x2e, 0x3a, 0x4f, 0x93, 0x74, 0x9c, 0xd2, + 0x85, 0x7e, 0xcb, 0x80, 0xe5, 0xbe, 0xc3, 0x92, 0xeb, 0xcb, 0x77, 0x3d, 0x79, 0x27, 0x0d, 0xd3, + 0xbe, 0xac, 0x26, 0xb1, 0x3c, 0xc5, 0xc2, 0xd3, 0x4a, 0xcd, 0xef, 0xcb, 0x6f, 0x97, 0x6a, 0x98, + 0xfc, 0x94, 0x9f, 0xe0, 0xfe, 0x5d, 0x01, 0xa6, 0x67, 0xcf, 0xbf, 0xb3, 0x2d, 0xeb, 0x0a, 0x23, + 0xf3, 0x01, 0xb8, 0xe2, 0xf2, 0x5a, 0xdd, 0x12, 0x2f, 0xa8, 0xf3, 0x59, 0x54, 0x6a, 0xed, 0xf8, + 0x1e, 0x0b, 0x7c, 0xf7, 0x4d, 0x4a, 0x02, 0xed, 0x05, 0xb3, 0x80, 0xc5, 0x0a, 0x9e, 0xd7, 0xea, + 0x76, 0xf8, 0x20, 0x3a, 0xdf, 0x7b, 0xd1, 0x69, 0x5d, 0xda, 0x5b, 0x30, 0x85, 0x8c, 0x63, 0x25, + 0x33, 0x5c, 0x68, 0x99, 0xbf, 0x67, 0xc0, 0x52, 0xba, 0x11, 0xc7, 0xc7, 0x8b, 0xd0, 0xb8, 0xb5, + 0x91, 0x6e, 0x84, 0x6e, 0x49, 0x32, 0x0e, 0xf9, 0x68, 0x17, 0x2a, 0x3c, 0x81, 0xc2, 0xea, 0xa4, + 0x99, 0x39, 0x11, 0x13, 0x8f, 0x73, 0x6e, 0x4b, 0x04, 0x1c, 0x42, 0x99, 0x7f, 0x65, 0x00, 0x9a, + 0x6e, 0xbe, 0xa0, 0x1d, 0xb8, 0xe0, 0x5a, 0x94, 0x45, 0x97, 0x8e, 0x5b, 0x89, 0x49, 0x5e, 0x55, + 0x93, 0xbc, 0xb0, 0x9d, 0x21, 0x83, 0x33, 0x47, 0x46, 0x49, 0x64, 0xe1, 0x09, 0x24, 0x91, 0x66, + 0x17, 0x20, 0x7e, 0xad, 0x84, 0xae, 0x41, 0xc9, 0xb3, 0x06, 0x61, 0x50, 0x8c, 0xea, 0x14, 0xf1, + 0xf0, 0x5e, 0x70, 0xd0, 0x67, 0x60, 0xee, 0xc8, 0x72, 0x47, 0xe1, 0x7f, 0x36, 0x44, 0x0f, 0x05, + 0xdf, 0xe2, 0x44, 0x2c, 0x79, 0xe6, 0x9f, 0x16, 0xa0, 0xae, 0x5d, 0xb7, 0x3f, 0x8d, 0x6a, 0x69, + 0x6e, 0x68, 0xb1, 0x83, 0xf0, 0x8d, 0xe3, 0xab, 0xb9, 0x5f, 0x02, 0xf0, 0x1c, 0x30, 0x5e, 0x04, + 0xff, 0x45, 0xb1, 0x84, 0x4e, 0xa5, 0xd7, 0xc5, 0xa7, 0x91, 0x5e, 0x9b, 0xdf, 0x33, 0x60, 0x31, + 0x35, 0x1b, 0x74, 0x13, 0x80, 0x46, 0xbf, 0xd4, 0x97, 0x88, 0x9a, 0x04, 0xb1, 0x1c, 0xd6, 0xa4, + 0x44, 0x16, 0x4c, 0x28, 0x73, 0x3c, 0x91, 0x11, 0x6e, 0x38, 0x81, 0xfa, 0x3c, 0x71, 0x16, 0x9c, + 0xe0, 0xe2, 0x94, 0xb4, 0xf9, 0xaf, 0x06, 0x5c, 0x3d, 0xed, 0xca, 0x82, 0xd7, 0x44, 0xea, 0x5e, + 0x22, 0xca, 0xb3, 0x8d, 0x64, 0x4d, 0x74, 0x37, 0xc9, 0xc6, 0x69, 0x79, 0xf4, 0x32, 0xd4, 0x35, + 0x92, 0x9a, 0x60, 0x14, 0x81, 0xb5, 0xe1, 0x58, 0x97, 0x7b, 0x22, 0x09, 0x92, 0xf9, 0x8f, 0x06, + 0x5c, 0xc8, 0x6a, 0x53, 0xa0, 0x20, 0x7c, 0x2c, 0x2b, 0x13, 0xe3, 0x7b, 0x67, 0xef, 0x7c, 0xb4, + 0xc4, 0x93, 0xd9, 0x4d, 0x8f, 0x05, 0xc7, 0xd9, 0xcf, 0x68, 0xaf, 0xbc, 0x02, 0x10, 0xcb, 0xa0, + 0x25, 0x28, 0x1e, 0x92, 0x63, 0x69, 0x4d, 0xcc, 0xff, 0x44, 0x17, 0x12, 0x5b, 0x4c, 0xed, 0xa9, + 0x2f, 0x15, 0x5e, 0x31, 0xbe, 0x54, 0xfd, 0xc1, 0x1f, 0x35, 0xcf, 0x7d, 0xf0, 0x2f, 0xd7, 0xce, + 0x99, 0xbf, 0x6b, 0x80, 0x9e, 0xb4, 0xa0, 0x2f, 0x40, 0xed, 0x80, 0xb1, 0xa1, 0x20, 0xa9, 0x97, + 0x04, 0xe2, 0xc1, 0xe8, 0x1b, 0xbb, 0xbb, 0x3b, 0x82, 0x88, 0x63, 0x3e, 0x6a, 0x01, 0xf0, 0x1f, + 0x54, 0x4a, 0x97, 0xe2, 0x17, 0x3d, 0x5c, 0xba, 0x2b, 0xc5, 0x35, 0x09, 0xf4, 0x1c, 0x2f, 0x02, + 0xa5, 0xb0, 0xfc, 0x47, 0xa1, 0xba, 0x2c, 0x00, 0xa5, 0x64, 0xc8, 0x33, 0xff, 0xd2, 0x80, 0xe5, + 0xa9, 0x27, 0x26, 0xe8, 0x9d, 0x28, 0x85, 0x31, 0xf2, 0x6f, 0xa1, 0xec, 0xb4, 0xe7, 0xcc, 0x6e, + 0xff, 0x17, 0x06, 0x40, 0xdc, 0x12, 0x40, 0x2e, 0xcc, 0x4b, 0xe0, 0x44, 0xde, 0x94, 0x67, 0xc2, + 0x17, 0xd4, 0x04, 0xe6, 0xbb, 0x1a, 0x1e, 0x4e, 0xa0, 0xf3, 0x52, 0x77, 0xe0, 0x8f, 0x3c, 0x26, + 0x36, 0x53, 0x21, 0xf9, 0x5a, 0xfa, 0x5e, 0xc8, 0xc0, 0xb1, 0x8c, 0xf9, 0xdb, 0x73, 0xb0, 0x92, + 0x71, 0xbf, 0xfa, 0x73, 0xdc, 0x8b, 0x7a, 0x1e, 0x2a, 0xf2, 0x4d, 0x2b, 0x4d, 0xe7, 0x0c, 0xf2, + 0xc9, 0x2b, 0xc5, 0x21, 0x1f, 0xdd, 0x80, 0xba, 0xe3, 0xd9, 0xb2, 0xd3, 0x6b, 0x85, 0xad, 0x05, + 0x79, 0x31, 0x12, 0x93, 0xb1, 0x2e, 0x93, 0xec, 0x45, 0x94, 0x1f, 0xab, 0x3b, 0x35, 0xaf, 0xfe, + 0x63, 0x52, 0xbe, 0x3c, 0xad, 0xe4, 0xf9, 0x20, 0xa2, 0x71, 0x8a, 0x35, 0x18, 0x9c, 0x00, 0x45, + 0xbf, 0x61, 0xc0, 0x92, 0x22, 0xac, 0x07, 0xcc, 0xe9, 0x59, 0x76, 0xf4, 0x1c, 0xec, 0x8c, 0x61, + 0xb0, 0xa1, 0x16, 0xb7, 0x84, 0x53, 0xf0, 0x78, 0x4a, 0xa1, 0xf9, 0x0e, 0x2c, 0x4f, 0x25, 0x78, + 0x8f, 0x97, 0x3d, 0x10, 0xf1, 0x4f, 0x79, 0xa9, 0xec, 0x41, 0xfe, 0x2f, 0x9e, 0xe4, 0x99, 0x3f, + 0x34, 0x60, 0x21, 0x95, 0x1f, 0xe7, 0x2a, 0xd6, 0xdf, 0xd1, 0x8b, 0xf5, 0x33, 0xd7, 0x1e, 0x89, + 0xb2, 0xdd, 0xfc, 0x87, 0x02, 0xd4, 0xa2, 0xa7, 0x2d, 0xe8, 0x85, 0xc4, 0xc2, 0x2f, 0xeb, 0x0b, + 0x7f, 0x34, 0x6e, 0x4a, 0x41, 0xcd, 0x0a, 0xef, 0x42, 0x2d, 0x7a, 0x3a, 0xa5, 0xa6, 0x37, 0xcb, + 0xf3, 0xa8, 0xc8, 0x09, 0xa3, 0xf7, 0x58, 0x38, 0xc6, 0xe3, 0xf9, 0x66, 0xf8, 0xb6, 0xe9, 0x9e, + 0xe3, 0xba, 0x0e, 0x55, 0x57, 0x05, 0x45, 0x71, 0x55, 0x10, 0xe5, 0x9b, 0x1b, 0x19, 0x32, 0x38, + 0x73, 0x24, 0x7a, 0x17, 0xe6, 0x28, 0x23, 0x43, 0xaa, 0x5a, 0x7b, 0xb7, 0x66, 0x7d, 0x00, 0x44, + 0x86, 0xa2, 0xef, 0x11, 0x7d, 0x6c, 0x4e, 0xa1, 0x58, 0x62, 0x9a, 0x3f, 0x31, 0xa0, 0x1a, 0x8a, + 0xa0, 0xeb, 0x09, 0x3b, 0x36, 0x52, 0x76, 0x14, 0x72, 0xff, 0x6f, 0xcd, 0x68, 0xf6, 0x60, 0x21, + 0x79, 0x7f, 0xa9, 0x55, 0xf7, 0xc6, 0x69, 0xd5, 0x3d, 0xba, 0x0e, 0x55, 0xcb, 0x75, 0xfd, 0xf7, + 0x37, 0xbd, 0x23, 0xf5, 0xa6, 0x30, 0xba, 0x6f, 0x5b, 0x57, 0x74, 0x1c, 0x49, 0xb4, 0x3f, 0xfb, + 0xe1, 0x47, 0xab, 0xe7, 0x7e, 0xfc, 0xd1, 0xea, 0xb9, 0x7f, 0xfe, 0x68, 0xf5, 0xdc, 0x07, 0x93, + 0x55, 0xe3, 0xc3, 0xc9, 0xaa, 0xf1, 0xe3, 0xc9, 0xaa, 0xf1, 0x6f, 0x93, 0x55, 0xe3, 0x77, 0xfe, + 0x7d, 0xf5, 0xdc, 0x3b, 0x85, 0xa3, 0x1b, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0xd1, 0x91, 0xfd, + 0xfe, 0xf6, 0x3e, 0x00, 0x00, } diff --git a/pkg/build/api/v1/generated.proto b/pkg/build/api/v1/generated.proto index 89ba9f75d39c..d86c2cf44798 100644 --- a/pkg/build/api/v1/generated.proto +++ b/pkg/build/api/v1/generated.proto @@ -111,6 +111,14 @@ message BuildConfigSpec { // CommonSpec is the desired build specification optional CommonSpec commonSpec = 3; + + // successfulBuildsHistoryLimit is the number of old successful builds to retain. + // If not specified, all successful builds are retained. + optional int32 successfulBuildsHistoryLimit = 4; + + // failedBuildsHistoryLimit is the number of old failed builds to retain. + // If not specified, all failed builds are retained. + optional int32 failedBuildsHistoryLimit = 5; } // BuildConfigStatus contains current state of the build config object. diff --git a/pkg/build/api/v1/swagger_doc.go b/pkg/build/api/v1/swagger_doc.go index e8b473503992..b3f686ddcc7b 100644 --- a/pkg/build/api/v1/swagger_doc.go +++ b/pkg/build/api/v1/swagger_doc.go @@ -71,9 +71,11 @@ func (BuildConfigList) SwaggerDoc() map[string]string { } var map_BuildConfigSpec = map[string]string{ - "": "BuildConfigSpec describes when and how builds are created", - "triggers": "triggers determine how new Builds can be launched from a BuildConfig. If no triggers are defined, a new build can only occur as a result of an explicit client build creation.", - "runPolicy": "RunPolicy describes how the new build created from this build configuration will be scheduled for execution. This is optional, if not specified we default to \"Serial\".", + "": "BuildConfigSpec describes when and how builds are created", + "triggers": "triggers determine how new Builds can be launched from a BuildConfig. If no triggers are defined, a new build can only occur as a result of an explicit client build creation.", + "runPolicy": "RunPolicy describes how the new build created from this build configuration will be scheduled for execution. This is optional, if not specified we default to \"Serial\".", + "successfulBuildsHistoryLimit": "successfulBuildsHistoryLimit is the number of old successful builds to retain. If not specified, all successful builds are retained.", + "failedBuildsHistoryLimit": "failedBuildsHistoryLimit is the number of old failed builds to retain. If not specified, all failed builds are retained.", } func (BuildConfigSpec) SwaggerDoc() map[string]string { diff --git a/pkg/build/api/v1/types.go b/pkg/build/api/v1/types.go index d75a56b34166..a7137f4c5579 100644 --- a/pkg/build/api/v1/types.go +++ b/pkg/build/api/v1/types.go @@ -871,6 +871,14 @@ type BuildConfigSpec struct { // CommonSpec is the desired build specification CommonSpec `json:",inline" protobuf:"bytes,3,opt,name=commonSpec"` + + // successfulBuildsHistoryLimit is the number of old successful builds to retain. + // If not specified, all successful builds are retained. + SuccessfulBuildsHistoryLimit *int32 `json:"successfulBuildsHistoryLimit,omitempty" protobuf:"varint,4,opt,name=successfulBuildsHistoryLimit"` + + // failedBuildsHistoryLimit is the number of old failed builds to retain. + // If not specified, all failed builds are retained. + FailedBuildsHistoryLimit *int32 `json:"failedBuildsHistoryLimit,omitempty" protobuf:"varint,5,opt,name=failedBuildsHistoryLimit"` } // BuildRunPolicy defines the behaviour of how the new builds are executed diff --git a/pkg/build/api/v1/zz_generated.conversion.go b/pkg/build/api/v1/zz_generated.conversion.go index 3a7df5d1eb9e..68efd66e0122 100644 --- a/pkg/build/api/v1/zz_generated.conversion.go +++ b/pkg/build/api/v1/zz_generated.conversion.go @@ -308,6 +308,8 @@ func autoConvert_v1_BuildConfigSpec_To_api_BuildConfigSpec(in *BuildConfigSpec, if err := Convert_v1_CommonSpec_To_api_CommonSpec(&in.CommonSpec, &out.CommonSpec, s); err != nil { return err } + out.SuccessfulBuildsHistoryLimit = (*int32)(unsafe.Pointer(in.SuccessfulBuildsHistoryLimit)) + out.FailedBuildsHistoryLimit = (*int32)(unsafe.Pointer(in.FailedBuildsHistoryLimit)) return nil } @@ -331,6 +333,8 @@ func autoConvert_api_BuildConfigSpec_To_v1_BuildConfigSpec(in *api.BuildConfigSp if err := Convert_api_CommonSpec_To_v1_CommonSpec(&in.CommonSpec, &out.CommonSpec, s); err != nil { return err } + out.SuccessfulBuildsHistoryLimit = (*int32)(unsafe.Pointer(in.SuccessfulBuildsHistoryLimit)) + out.FailedBuildsHistoryLimit = (*int32)(unsafe.Pointer(in.FailedBuildsHistoryLimit)) return nil } diff --git a/pkg/build/api/v1/zz_generated.deepcopy.go b/pkg/build/api/v1/zz_generated.deepcopy.go index d4bfc9f03965..7061a5f1d154 100644 --- a/pkg/build/api/v1/zz_generated.deepcopy.go +++ b/pkg/build/api/v1/zz_generated.deepcopy.go @@ -179,6 +179,16 @@ func DeepCopy_v1_BuildConfigSpec(in interface{}, out interface{}, c *conversion. if err := DeepCopy_v1_CommonSpec(&in.CommonSpec, &out.CommonSpec, c); err != nil { return err } + if in.SuccessfulBuildsHistoryLimit != nil { + in, out := &in.SuccessfulBuildsHistoryLimit, &out.SuccessfulBuildsHistoryLimit + *out = new(int32) + **out = **in + } + if in.FailedBuildsHistoryLimit != nil { + in, out := &in.FailedBuildsHistoryLimit, &out.FailedBuildsHistoryLimit + *out = new(int32) + **out = **in + } return nil } } diff --git a/pkg/build/api/validation/validation.go b/pkg/build/api/validation/validation.go index 087136f1a111..828c32251532 100644 --- a/pkg/build/api/validation/validation.go +++ b/pkg/build/api/validation/validation.go @@ -148,6 +148,14 @@ func ValidateBuildConfig(config *buildapi.BuildConfig) field.ErrorList { "run policy must Parallel, Serial, or SerialLatestOnly")) } + if config.Spec.SuccessfulBuildsHistoryLimit != nil { + allErrs = append(allErrs, validation.ValidateNonnegativeField(int64(*config.Spec.SuccessfulBuildsHistoryLimit), specPath.Child("successfulBuildsHistoryLimit"))...) + } + + if config.Spec.FailedBuildsHistoryLimit != nil { + allErrs = append(allErrs, validation.ValidateNonnegativeField(int64(*config.Spec.FailedBuildsHistoryLimit), specPath.Child("failedBuildsHistoryLimit"))...) + } + allErrs = append(allErrs, validateCommonSpec(&config.Spec.CommonSpec, specPath)...) return allErrs diff --git a/pkg/build/api/zz_generated.deepcopy.go b/pkg/build/api/zz_generated.deepcopy.go index d205e6222183..af7ea6a18da5 100644 --- a/pkg/build/api/zz_generated.deepcopy.go +++ b/pkg/build/api/zz_generated.deepcopy.go @@ -180,6 +180,16 @@ func DeepCopy_api_BuildConfigSpec(in interface{}, out interface{}, c *conversion if err := DeepCopy_api_CommonSpec(&in.CommonSpec, &out.CommonSpec, c); err != nil { return err } + if in.SuccessfulBuildsHistoryLimit != nil { + in, out := &in.SuccessfulBuildsHistoryLimit, &out.SuccessfulBuildsHistoryLimit + *out = new(int32) + **out = **in + } + if in.FailedBuildsHistoryLimit != nil { + in, out := &in.FailedBuildsHistoryLimit, &out.FailedBuildsHistoryLimit + *out = new(int32) + **out = **in + } return nil } } diff --git a/pkg/build/client/clients.go b/pkg/build/client/clients.go index a6a939ec0211..0d48cbb140a5 100644 --- a/pkg/build/client/clients.go +++ b/pkg/build/client/clients.go @@ -8,7 +8,7 @@ import ( // BuildConfigGetter provides methods for getting BuildConfigs type BuildConfigGetter interface { - Get(namespace, name string) (*buildapi.BuildConfig, error) + Get(namespace, name string, options metav1.GetOptions) (*buildapi.BuildConfig, error) } // BuildConfigUpdater provides methods for updating BuildConfigs @@ -88,6 +88,29 @@ func (c OSClientBuildClonerClient) Clone(namespace string, request *buildapi.Bui return c.Client.Builds(namespace).Clone(request) } +// BuildDeleter knows how to delete builds from OpenShift. +type BuildDeleter interface { + // DeleteBuild removes the build from OpenShift's storage. + DeleteBuild(build *buildapi.Build) error +} + +// buildDeleter removes a build from OpenShift. +type buildDeleter struct { + builds osclient.BuildsNamespacer +} + +// NewBuildDeleter creates a new buildDeleter. +func NewBuildDeleter(builds osclient.BuildsNamespacer) BuildDeleter { + return &buildDeleter{ + builds: builds, + } +} + +// DeleteBuild deletes a build from OpenShift. +func (p *buildDeleter) DeleteBuild(build *buildapi.Build) error { + return p.builds.Builds(build.Namespace).Delete(build.Name) +} + // BuildConfigInstantiator provides methods for instantiating builds from build configs type BuildConfigInstantiator interface { Instantiate(namespace string, request *buildapi.BuildRequest) (*buildapi.Build, error) diff --git a/pkg/build/controller/build_controller.go b/pkg/build/controller/build_controller.go index f3b9f203e64a..8dd09ce012dd 100644 --- a/pkg/build/controller/build_controller.go +++ b/pkg/build/controller/build_controller.go @@ -26,6 +26,8 @@ import ( type BuildController struct { BuildUpdater buildclient.BuildUpdater BuildLister buildclient.BuildLister + BuildConfigGetter buildclient.BuildConfigGetter + BuildDeleter buildclient.BuildDeleter PodManager podManager BuildStrategy BuildStrategy ImageStreamClient imageStreamClient @@ -85,7 +87,7 @@ func (bc *BuildController) CancelBuild(build *buildapi.Build) error { glog.V(4).Infof("Build %s/%s was successfully cancelled.", build.Namespace, build.Name) - common.HandleBuildCompletion(build, bc.RunPolicies) + common.HandleBuildCompletion(build, bc.BuildLister, bc.BuildConfigGetter, bc.BuildDeleter, bc.RunPolicies) return nil } diff --git a/pkg/build/controller/build_controller_test.go b/pkg/build/controller/build_controller_test.go index c1b1eaf60318..854104334ac5 100644 --- a/pkg/build/controller/build_controller_test.go +++ b/pkg/build/controller/build_controller_test.go @@ -28,6 +28,24 @@ func (okc *okBuildLister) List(namespace string, opts metav1.ListOptions) (*buil return &buildapi.BuildList{Items: []buildapi.Build{}}, nil } +type okBuildDeleter struct{} + +func (okc *okBuildDeleter) DeleteBuild(*buildapi.Build) error { + return nil +} + +type okBuildConfigGetter struct { + BuildConfig *buildapi.BuildConfig +} + +func (okc *okBuildConfigGetter) Get(namespace, name string, options metav1.GetOptions) (*buildapi.BuildConfig, error) { + if okc.BuildConfig != nil { + return okc.BuildConfig, nil + } else { + return &buildapi.BuildConfig{}, nil + } +} + type errBuildUpdater struct{} func (ec *errBuildUpdater) Update(namespace string, build *buildapi.Build) error { @@ -153,6 +171,8 @@ func mockBuildController() *BuildController { return &BuildController{ BuildUpdater: &okBuildUpdater{}, BuildLister: &okBuildLister{}, + BuildDeleter: &okBuildDeleter{}, + BuildConfigGetter: &okBuildConfigGetter{}, PodManager: &okPodManager{}, BuildStrategy: &okStrategy{}, ImageStreamClient: &okImageStreamClient{}, diff --git a/pkg/build/controller/buildconfig_controller.go b/pkg/build/controller/buildconfig_controller.go index b89c4945d7e2..ea28c50b8ea5 100644 --- a/pkg/build/controller/buildconfig_controller.go +++ b/pkg/build/controller/buildconfig_controller.go @@ -12,6 +12,7 @@ import ( buildapi "github.com/openshift/origin/pkg/build/api" buildclient "github.com/openshift/origin/pkg/build/client" + buildutil "github.com/openshift/origin/pkg/build/controller/common" buildgenerator "github.com/openshift/origin/pkg/build/generator" ) @@ -35,7 +36,9 @@ func IsFatal(err error) bool { type BuildConfigController struct { BuildConfigInstantiator buildclient.BuildConfigInstantiator - + BuildConfigGetter buildclient.BuildConfigGetter + BuildLister buildclient.BuildLister + BuildDeleter buildclient.BuildDeleter // recorder is used to record events. Recorder record.EventRecorder } @@ -43,6 +46,10 @@ type BuildConfigController struct { func (c *BuildConfigController) HandleBuildConfig(bc *buildapi.BuildConfig) error { glog.V(4).Infof("Handling BuildConfig %s/%s", bc.Namespace, bc.Name) + if err := buildutil.HandleBuildPruning(bc.Name, bc.Namespace, c.BuildLister, c.BuildConfigGetter, c.BuildDeleter); err != nil { + utilruntime.HandleError(err) + } + hasChangeTrigger := buildapi.HasTriggerType(buildapi.ConfigChangeBuildTriggerType, bc) if !hasChangeTrigger { diff --git a/pkg/build/controller/buildconfig_controller_test.go b/pkg/build/controller/buildconfig_controller_test.go index c9c7606a07c5..6f78d8deb4d6 100644 --- a/pkg/build/controller/buildconfig_controller_test.go +++ b/pkg/build/controller/buildconfig_controller_test.go @@ -46,6 +46,9 @@ func TestHandleBuildConfig(t *testing.T) { } controller := &BuildConfigController{ BuildConfigInstantiator: instantiator, + BuildLister: &okBuildLister{}, + BuildDeleter: &okBuildDeleter{}, + BuildConfigGetter: &okBuildConfigGetter{BuildConfig: tc.bc}, Recorder: &record.FakeRecorder{}, } err := controller.HandleBuildConfig(tc.bc) diff --git a/pkg/build/controller/buildpod/buildpod_controller.go b/pkg/build/controller/buildpod/buildpod_controller.go index 82b20a20690e..7f279fa8a80e 100644 --- a/pkg/build/controller/buildpod/buildpod_controller.go +++ b/pkg/build/controller/buildpod/buildpod_controller.go @@ -47,8 +47,11 @@ type BuildPodController struct { queue workqueue.RateLimitingInterface - buildStore oscache.StoreToBuildLister - podInformer kcoreinformers.PodInformer + buildStore oscache.StoreToBuildLister + buildLister buildclient.BuildLister + buildConfigGetter buildclient.BuildConfigGetter + buildDeleter buildclient.BuildDeleter + podInformer kcoreinformers.PodInformer buildStoreSynced func() bool podStoreSynced func() bool @@ -64,13 +67,19 @@ func NewBuildPodController(buildInformer cache.SharedIndexInformer, podInformer eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: v1core.New(extkc.Core().RESTClient()).Events("")}) buildListerUpdater := buildclient.NewOSClientBuildClient(oc) + buildConfigGetter := buildclient.NewOSClientBuildConfigClient(oc) + buildDeleter := buildclient.NewBuildDeleter(oc) + c := &BuildPodController{ - buildUpdater: buildListerUpdater, - secretClient: intkc.Core(), // TODO: Replace with cache client - podClient: intkc.Core(), - podInformer: podInformer, - queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), - recorder: eventBroadcaster.NewRecorder(kapi.Scheme, clientv1.EventSource{Component: "build-pod-controller"}), + buildUpdater: buildListerUpdater, + buildLister: buildListerUpdater, + buildConfigGetter: buildConfigGetter, + buildDeleter: buildDeleter, + secretClient: intkc.Core(), // TODO: Replace with cache client + podClient: intkc.Core(), + podInformer: podInformer, + queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), + recorder: eventBroadcaster.NewRecorder(kapi.Scheme, clientv1.EventSource{Component: "build-pod-controller"}), } c.runPolicies = policy.GetAllRunPolicies(buildListerUpdater, buildListerUpdater) @@ -235,7 +244,7 @@ func (bc *BuildPodController) HandlePod(pod *kapi.Pod) error { case buildapi.BuildPhaseError, buildapi.BuildPhaseFailed: bc.recorder.Eventf(build, kapi.EventTypeNormal, buildapi.BuildFailedEventReason, fmt.Sprintf(buildapi.BuildFailedEventMessage, build.Namespace, build.Name)) } - common.HandleBuildCompletion(build, bc.runPolicies) + common.HandleBuildCompletion(build, bc.buildLister, bc.buildConfigGetter, bc.buildDeleter, bc.runPolicies) } return nil @@ -281,7 +290,7 @@ func (bc *BuildPodController) HandleBuildPodDeletion(pod *kapi.Pod) error { if err := bc.buildUpdater.Update(build.Namespace, build); err != nil { return fmt.Errorf("Failed to update build %s/%s: %v", build.Namespace, build.Name, err) } - common.HandleBuildCompletion(build, bc.runPolicies) + common.HandleBuildCompletion(build, bc.buildLister, bc.buildConfigGetter, bc.buildDeleter, bc.runPolicies) } return nil } diff --git a/pkg/build/controller/common/util.go b/pkg/build/controller/common/util.go index f5071e7c746c..afac3145ea21 100644 --- a/pkg/build/controller/common/util.go +++ b/pkg/build/controller/common/util.go @@ -2,13 +2,18 @@ package common import ( "fmt" + "sort" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kerrors "k8s.io/apimachinery/pkg/util/errors" utilruntime "k8s.io/apimachinery/pkg/util/runtime" buildapi "github.com/openshift/origin/pkg/build/api" + buildclient "github.com/openshift/origin/pkg/build/client" "github.com/openshift/origin/pkg/build/controller/policy" buildutil "github.com/openshift/origin/pkg/build/util" + + "github.com/golang/glog" ) // SetBuildCompletionTimeAndDuration will set the build completion timestamp @@ -32,7 +37,7 @@ func SetBuildCompletionTimeAndDuration(build *buildapi.Build, startTime *metav1. return true } -func HandleBuildCompletion(build *buildapi.Build, runPolicies []policy.RunPolicy) { +func HandleBuildCompletion(build *buildapi.Build, buildLister buildclient.BuildLister, buildConfigGetter buildclient.BuildConfigGetter, buildDeleter buildclient.BuildDeleter, runPolicies []policy.RunPolicy) { if !buildutil.IsBuildComplete(build) { return } @@ -44,6 +49,75 @@ func HandleBuildCompletion(build *buildapi.Build, runPolicies []policy.RunPolicy if err := runPolicy.OnComplete(build); err != nil { utilruntime.HandleError(fmt.Errorf("failed to run policy on completed build %s/%s: %v", build.Namespace, build.Name, err)) } + if err := HandleBuildPruning(buildutil.ConfigNameForBuild(build), build.Namespace, buildLister, buildConfigGetter, buildDeleter); err != nil { + utilruntime.HandleError(fmt.Errorf("failed to prune old builds %s/%s: %v", build.Namespace, build.Name, err)) + } +} + +type ByCreationTimestamp []buildapi.Build + +func (b ByCreationTimestamp) Len() int { + return len(b) +} + +func (b ByCreationTimestamp) Swap(i, j int) { + b[i], b[j] = b[j], b[i] +} + +func (b ByCreationTimestamp) Less(i, j int) bool { + return !b[j].CreationTimestamp.Time.After(b[i].CreationTimestamp.Time) +} + +// HandleBuildPruning handles the deletion of old successful and failed builds +// based on settings in the BuildConfig. +func HandleBuildPruning(buildConfigName string, namespace string, buildLister buildclient.BuildLister, buildConfigGetter buildclient.BuildConfigGetter, buildDeleter buildclient.BuildDeleter) error { + buildConfig, err := buildConfigGetter.Get(namespace, buildConfigName, metav1.GetOptions{}) + if err != nil { + return err + } + + var buildsToDelete []buildapi.Build + var errList []error + + if buildConfig.Spec.SuccessfulBuildsHistoryLimit != nil { + successfulBuilds, err := buildutil.BuildConfigBuilds(buildLister, namespace, buildConfigName, func(build buildapi.Build) bool { return build.Status.Phase == buildapi.BuildPhaseComplete }) + if err != nil { + return err + } + sort.Sort(ByCreationTimestamp(successfulBuilds.Items)) + + successfulBuildsHistoryLimit := int(*buildConfig.Spec.SuccessfulBuildsHistoryLimit) + if len(successfulBuilds.Items) > successfulBuildsHistoryLimit { + glog.V(4).Infof("Preparing to prune %v of %v old successful builds, successfulBuildsHistoryLimit set to %v", (len(successfulBuilds.Items) - successfulBuildsHistoryLimit), len(successfulBuilds.Items), successfulBuildsHistoryLimit) + buildsToDelete = append(buildsToDelete, successfulBuilds.Items[successfulBuildsHistoryLimit:]...) + } + } + + if buildConfig.Spec.FailedBuildsHistoryLimit != nil { + failedBuilds, err := buildutil.BuildConfigBuilds(buildLister, namespace, buildConfigName, func(build buildapi.Build) bool { return build.Status.Phase == buildapi.BuildPhaseFailed }) + if err != nil { + return err + } + sort.Sort(ByCreationTimestamp(failedBuilds.Items)) + + failedBuildsHistoryLimit := int(*buildConfig.Spec.FailedBuildsHistoryLimit) + if len(failedBuilds.Items) > failedBuildsHistoryLimit { + glog.V(4).Infof("Preparing to prune %v of %v old failed builds, failedBuildsHistoryLimit set to %v", (len(failedBuilds.Items) - failedBuildsHistoryLimit), len(failedBuilds.Items), failedBuildsHistoryLimit) + buildsToDelete = append(buildsToDelete, failedBuilds.Items[failedBuildsHistoryLimit:]...) + } + } + + for i, b := range buildsToDelete { + glog.V(4).Infof("Pruning old build: %s/%s", b.Namespace, b.Name) + if err := buildDeleter.DeleteBuild(&buildsToDelete[i]); err != nil { + errList = append(errList, err) + } + } + if errList != nil { + return kerrors.NewAggregate(errList) + } + + return nil } func SetBuildPodNameAnnotation(build *buildapi.Build, podName string) { diff --git a/pkg/build/controller/common/util_test.go b/pkg/build/controller/common/util_test.go new file mode 100644 index 000000000000..340059764fbf --- /dev/null +++ b/pkg/build/controller/common/util_test.go @@ -0,0 +1,159 @@ +package common + +import ( + "fmt" + "reflect" + "sort" + "strings" + "testing" + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + kapi "k8s.io/kubernetes/pkg/api" + + buildapi "github.com/openshift/origin/pkg/build/api" + buildclient "github.com/openshift/origin/pkg/build/client" + buildutil "github.com/openshift/origin/pkg/build/util" + "github.com/openshift/origin/pkg/client/testclient" +) + +func mockBuildConfig(name string) buildapi.BuildConfig { + appName := strings.Split(name, "-") + successfulBuildsToKeep := int32(2) + failedBuildsToKeep := int32(3) + return buildapi.BuildConfig{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-build", appName[0]), + Namespace: "namespace", + Labels: map[string]string{ + "app": appName[0], + }, + }, + Spec: buildapi.BuildConfigSpec{ + SuccessfulBuildsHistoryLimit: &successfulBuildsToKeep, + FailedBuildsHistoryLimit: &failedBuildsToKeep, + }, + } +} + +func mockBuild(name string, phase buildapi.BuildPhase, stamp *metav1.Time) buildapi.Build { + appName := strings.Split(name, "-") + return buildapi.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + UID: types.UID(fmt.Sprintf("uid%v", appName[1])), + Namespace: "namespace", + CreationTimestamp: *stamp, + Labels: map[string]string{ + "app": appName[0], + buildapi.BuildConfigLabel: fmt.Sprintf("%v-build", appName[0]), + "buildconfig": fmt.Sprintf("%v-build", appName[0]), + }, + Annotations: map[string]string{ + buildapi.BuildConfigLabel: fmt.Sprintf("%v-build", appName[0]), + }, + }, + Status: buildapi.BuildStatus{ + Phase: phase, + StartTimestamp: stamp, + Config: &kapi.ObjectReference{ + Name: fmt.Sprintf("%v-build", appName[0]), + Namespace: "namespace", + }, + }, + } +} + +func mockBuildsList(length int) (buildapi.BuildConfig, []buildapi.Build) { + var builds []buildapi.Build + buildPhaseList := []buildapi.BuildPhase{buildapi.BuildPhaseComplete, buildapi.BuildPhaseFailed} + addOrSubtract := []string{"+", "-"} + + for i := 0; i < length; i++ { + duration, _ := time.ParseDuration(fmt.Sprintf("%v%vh", addOrSubtract[i%2], i)) + startTime := metav1.NewTime(time.Now().Add(duration)) + build := mockBuild(fmt.Sprintf("myapp-%v", i), buildPhaseList[i%2], &startTime) + builds = append(builds, build) + } + + return mockBuildConfig("myapp"), builds +} + +func TestSetBuildCompletionTimeAndDuration(t *testing.T) { + build := &buildapi.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: "myapp-1", + Namespace: "namespace", + }, + } + + now := metav1.Now() + SetBuildCompletionTimeAndDuration(build, &now) + + if build.Status.StartTimestamp == nil { + t.Errorf("should have set the StartTimestamp, but instead it was nil") + } + if build.Status.CompletionTimestamp == nil { + t.Errorf("should have set the CompletionTimestamp, but instead it was nil") + } + if build.Status.Duration > 0 { + t.Errorf("should have set the Duration to 0s, but instead it was %v", build.Status.Duration) + } +} + +func TestHandleBuildPruning(t *testing.T) { + var objects []runtime.Object + buildconfig, builds := mockBuildsList(10) + + objects = append(objects, &buildconfig) + for index := range builds { + objects = append(objects, &builds[index]) + } + + osclient := testclient.NewSimpleFake(objects...) + + build, err := osclient.Builds("namespace").Get("myapp-0", metav1.GetOptions{}) + if err != nil { + t.Errorf("%v", err) + } + + buildLister := buildclient.NewOSClientBuildClient(osclient) + buildConfigGetter := buildclient.NewOSClientBuildConfigClient(osclient) + buildDeleter := buildclient.NewBuildDeleter(osclient) + + bcName := buildutil.ConfigNameForBuild(build) + successfulStartingBuilds, err := buildutil.BuildConfigBuilds(buildLister, build.Namespace, bcName, func(build buildapi.Build) bool { return build.Status.Phase == buildapi.BuildPhaseComplete }) + sort.Sort(ByCreationTimestamp(successfulStartingBuilds.Items)) + + failedStartingBuilds, err := buildutil.BuildConfigBuilds(buildLister, build.Namespace, bcName, func(build buildapi.Build) bool { return build.Status.Phase == buildapi.BuildPhaseFailed }) + sort.Sort(ByCreationTimestamp(failedStartingBuilds.Items)) + + if len(successfulStartingBuilds.Items)+len(failedStartingBuilds.Items) != 10 { + t.Errorf("should start with 10 builds, but started with %v instead", len(successfulStartingBuilds.Items)+len(failedStartingBuilds.Items)) + } + + if err := HandleBuildPruning(bcName, build.Namespace, buildLister, buildConfigGetter, buildDeleter); err != nil { + t.Errorf("error pruning builds: %v", err) + } + + successfulRemainingBuilds, err := buildutil.BuildConfigBuilds(buildLister, build.Namespace, bcName, func(build buildapi.Build) bool { return build.Status.Phase == buildapi.BuildPhaseComplete }) + sort.Sort(ByCreationTimestamp(successfulRemainingBuilds.Items)) + + failedRemainingBuilds, err := buildutil.BuildConfigBuilds(buildLister, build.Namespace, bcName, func(build buildapi.Build) bool { return build.Status.Phase == buildapi.BuildPhaseFailed }) + sort.Sort(ByCreationTimestamp(failedRemainingBuilds.Items)) + + if len(successfulRemainingBuilds.Items)+len(failedRemainingBuilds.Items) != 5 { + t.Errorf("there should only be 5 builds left, but instead there are %v", len(successfulRemainingBuilds.Items)+len(failedRemainingBuilds.Items)) + } + + if !reflect.DeepEqual(successfulStartingBuilds.Items[:2], successfulRemainingBuilds.Items) { + t.Errorf("expected the two most recent successful builds should be left, but instead there were %v: %v", len(successfulRemainingBuilds.Items), successfulRemainingBuilds.Items) + } + + if !reflect.DeepEqual(failedStartingBuilds.Items[:3], failedRemainingBuilds.Items) { + t.Errorf("expected the three most recent failed builds to be left, but instead there were %v: %v", len(failedRemainingBuilds.Items), failedRemainingBuilds.Items) + } + +} diff --git a/pkg/build/controller/factory/factory.go b/pkg/build/controller/factory/factory.go index bce256dd571f..1270c01972d5 100644 --- a/pkg/build/controller/factory/factory.go +++ b/pkg/build/controller/factory/factory.go @@ -75,6 +75,8 @@ type BuildControllerFactory struct { ExternalKubeClient kclientsetexternal.Interface BuildUpdater buildclient.BuildUpdater BuildLister buildclient.BuildLister + BuildConfigGetter buildclient.BuildConfigGetter + BuildDeleter buildclient.BuildDeleter DockerBuildStrategy *strategy.DockerBuildStrategy SourceBuildStrategy *strategy.SourceBuildStrategy CustomBuildStrategy *strategy.CustomBuildStrategy @@ -97,6 +99,8 @@ func (factory *BuildControllerFactory) Create() controller.RunnableController { buildController := &buildcontroller.BuildController{ BuildUpdater: factory.BuildUpdater, BuildLister: factory.BuildLister, + BuildConfigGetter: factory.BuildConfigGetter, + BuildDeleter: factory.BuildDeleter, ImageStreamClient: client, PodManager: client, RunPolicies: policy.GetAllRunPolicies(factory.BuildLister, factory.BuildUpdater), @@ -218,6 +222,9 @@ type BuildConfigControllerFactory struct { KubeClient kclientset.Interface ExternalKubeClient kclientsetexternal.Interface BuildConfigInstantiator buildclient.BuildConfigInstantiator + BuildConfigGetter buildclient.BuildConfigGetter + BuildLister buildclient.BuildLister + BuildDeleter buildclient.BuildDeleter // Stop may be set to allow controllers created by this factory to be terminated. Stop <-chan struct{} } @@ -232,6 +239,9 @@ func (factory *BuildConfigControllerFactory) Create() controller.RunnableControl bcController := &buildcontroller.BuildConfigController{ BuildConfigInstantiator: factory.BuildConfigInstantiator, + BuildConfigGetter: factory.BuildConfigGetter, + BuildLister: factory.BuildLister, + BuildDeleter: factory.BuildDeleter, Recorder: eventBroadcaster.NewRecorder(kapi.Scheme, kclientv1.EventSource{Component: "build-config-controller"}), } diff --git a/pkg/build/prune/prune.go b/pkg/build/prune/prune.go index 778b75397275..7d52a9f7552f 100644 --- a/pkg/build/prune/prune.go +++ b/pkg/build/prune/prune.go @@ -6,19 +6,13 @@ import ( "github.com/golang/glog" buildapi "github.com/openshift/origin/pkg/build/api" - "github.com/openshift/origin/pkg/client" + buildclient "github.com/openshift/origin/pkg/build/client" ) type Pruner interface { // Prune is responsible for actual removal of builds identified as candidates // for pruning based on pruning algorithm. - Prune(deleter BuildDeleter) error -} - -// BuildDeleter knows how to delete builds from OpenShift. -type BuildDeleter interface { - // DeleteBuild removes the build from OpenShift's storage. - DeleteBuild(build *buildapi.Build) error + Prune(deleter buildclient.BuildDeleter) error } // pruner is an object that knows how to prune a data set @@ -74,7 +68,7 @@ func NewPruner(options PrunerOptions) Pruner { } // Prune will visit each item in the prunable set and invoke the associated BuildDeleter. -func (p *pruner) Prune(deleter BuildDeleter) error { +func (p *pruner) Prune(deleter buildclient.BuildDeleter) error { builds, err := p.resolver.Resolve() if err != nil { return err @@ -86,22 +80,3 @@ func (p *pruner) Prune(deleter BuildDeleter) error { } return nil } - -// buildDeleter removes a build from OpenShift. -type buildDeleter struct { - builds client.BuildsNamespacer -} - -var _ BuildDeleter = &buildDeleter{} - -// NewBuildDeleter creates a new buildDeleter. -func NewBuildDeleter(builds client.BuildsNamespacer) BuildDeleter { - return &buildDeleter{ - builds: builds, - } -} - -func (p *buildDeleter) DeleteBuild(build *buildapi.Build) error { - glog.V(4).Infof("Deleting build %q", build.Name) - return p.builds.Builds(build.Namespace).Delete(build.Name) -} diff --git a/pkg/build/prune/prune_test.go b/pkg/build/prune/prune_test.go index ce8b689fc4ce..b23b93aef579 100644 --- a/pkg/build/prune/prune_test.go +++ b/pkg/build/prune/prune_test.go @@ -9,6 +9,7 @@ import ( "k8s.io/apimachinery/pkg/util/sets" buildapi "github.com/openshift/origin/pkg/build/api" + buildclient "github.com/openshift/origin/pkg/build/client" ) type mockDeleteRecorder struct { @@ -16,7 +17,7 @@ type mockDeleteRecorder struct { err error } -var _ BuildDeleter = &mockDeleteRecorder{} +var _ buildclient.BuildDeleter = &mockDeleteRecorder{} func (m *mockDeleteRecorder) DeleteBuild(build *buildapi.Build) error { m.set.Insert(build.Name) diff --git a/pkg/cmd/admin/prune/builds.go b/pkg/cmd/admin/prune/builds.go index 161fec2497c0..e41a0c7c0cc8 100644 --- a/pkg/cmd/admin/prune/builds.go +++ b/pkg/cmd/admin/prune/builds.go @@ -13,6 +13,7 @@ import ( kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" buildapi "github.com/openshift/origin/pkg/build/api" + buildclient "github.com/openshift/origin/pkg/build/client" "github.com/openshift/origin/pkg/build/prune" "github.com/openshift/origin/pkg/client" "github.com/openshift/origin/pkg/cmd/templates" @@ -156,7 +157,7 @@ func (o PruneBuildsOptions) Run() error { buildDeleter := &describingBuildDeleter{w: w} if o.Confirm { - buildDeleter.delegate = prune.NewBuildDeleter(o.OSClient) + buildDeleter.delegate = buildclient.NewBuildDeleter(o.OSClient) } else { fmt.Fprintln(os.Stderr, "Dry run enabled - no modifications will be made. Add --confirm to remove builds") } @@ -168,11 +169,11 @@ func (o PruneBuildsOptions) Run() error { // If a delegate exists, its DeleteBuild function is invoked prior to returning. type describingBuildDeleter struct { w io.Writer - delegate prune.BuildDeleter + delegate buildclient.BuildDeleter headerPrinted bool } -var _ prune.BuildDeleter = &describingBuildDeleter{} +var _ buildclient.BuildDeleter = &describingBuildDeleter{} func (p *describingBuildDeleter) DeleteBuild(build *buildapi.Build) error { if !p.headerPrinted { diff --git a/pkg/cmd/server/origin/run_components.go b/pkg/cmd/server/origin/run_components.go index bf1191e38156..ed5c8af8287f 100644 --- a/pkg/cmd/server/origin/run_components.go +++ b/pkg/cmd/server/origin/run_components.go @@ -289,6 +289,9 @@ func (c *MasterConfig) RunBuildController(informers shared.InformerFactory) erro OSClient: osclient, BuildUpdater: buildclient.NewOSClientBuildClient(osclient), BuildLister: buildclient.NewOSClientBuildClient(osclient), + BuildConfigGetter: buildclient.NewOSClientBuildConfigClient(osclient), + BuildDeleter: buildclient.NewBuildDeleter(osclient), + DockerBuildStrategy: &buildstrategy.DockerBuildStrategy{ Image: dockerImage, // TODO: this will be set to --storage-version (the internal schema we use) @@ -334,6 +337,9 @@ func (c *MasterConfig) RunBuildConfigChangeController() { KubeClient: internalKubeClientset, ExternalKubeClient: externalKubeClientset, BuildConfigInstantiator: bcInstantiator, + BuildLister: buildclient.NewOSClientBuildClient(bcClient), + BuildConfigGetter: buildclient.NewOSClientBuildConfigClient(bcClient), + BuildDeleter: buildclient.NewBuildDeleter(bcClient), } factory.Create().Run() } diff --git a/pkg/openapi/zz_generated.openapi.go b/pkg/openapi/zz_generated.openapi.go index 6aec52bd5333..7fb396af7f16 100644 --- a/pkg/openapi/zz_generated.openapi.go +++ b/pkg/openapi/zz_generated.openapi.go @@ -2456,6 +2456,20 @@ func GetOpenAPIDefinitions(ref openapi.ReferenceCallback) map[string]openapi.Ope }, }, }, + "successfulBuildsHistoryLimit": { + SchemaProps: spec.SchemaProps{ + Description: "successfulBuildsHistoryLimit is the number of old successful builds to retain. If not specified, all successful builds are retained.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + "failedBuildsHistoryLimit": { + SchemaProps: spec.SchemaProps{ + Description: "failedBuildsHistoryLimit is the number of old failed builds to retain. If not specified, all failed builds are retained.", + Type: []string{"integer"}, + Format: "int32", + }, + }, }, Required: []string{"triggers", "strategy", "nodeSelector"}, }, diff --git a/test/extended/builds/build_pruning.go b/test/extended/builds/build_pruning.go new file mode 100644 index 000000000000..65a427fa39e9 --- /dev/null +++ b/test/extended/builds/build_pruning.go @@ -0,0 +1,96 @@ +package builds + +import ( + "fmt" + "path/filepath" + + g "github.com/onsi/ginkgo" + o "github.com/onsi/gomega" + + exutil "github.com/openshift/origin/test/extended/util" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = g.Describe("[builds][pruning] prune builds based on settings in the buildconfig", func() { + var ( + buildPruningBaseDir = exutil.FixturePath("testdata", "build-pruning") + isFixture = filepath.Join(buildPruningBaseDir, "imagestream.yaml") + successfulBuildConfig = filepath.Join(buildPruningBaseDir, "successful-build-config.yaml") + failedBuildConfig = filepath.Join(buildPruningBaseDir, "failed-build-config.yaml") + oc = exutil.NewCLI("build-pruning", exutil.KubeConfigPath()) + ) + + g.JustBeforeEach(func() { + g.By("waiting for builder service account") + err := exutil.WaitForBuilderAccount(oc.KubeClient().Core().ServiceAccounts(oc.Namespace())) + o.Expect(err).NotTo(o.HaveOccurred()) + g.By("waiting for openshift namespace imagestreams") + err = exutil.WaitForOpenShiftNamespaceImageStreams(oc) + o.Expect(err).NotTo(o.HaveOccurred()) + }) + + g.It("should prune completed builds based on the successfulBuildsHistoryLimit setting", func() { + + g.By("creating test image stream") + err := oc.Run("create").Args("-f", isFixture).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + g.By("creating test successful build config") + err = oc.Run("create").Args("-f", successfulBuildConfig).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + g.By("starting three test builds") + br, _ := exutil.StartBuildAndWait(oc, "myphp") + br.AssertSuccess() + br, _ = exutil.StartBuildAndWait(oc, "myphp") + br.AssertSuccess() + br, _ = exutil.StartBuildAndWait(oc, "myphp") + br.AssertSuccess() + + buildConfig, err := oc.Client().BuildConfigs(oc.Namespace()).Get("myphp", metav1.GetOptions{}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + } + + builds, err := oc.Client().Builds(oc.Namespace()).List(metav1.ListOptions{}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + } + + o.Expect(int32(len(builds.Items))).To(o.Equal(*buildConfig.Spec.SuccessfulBuildsHistoryLimit), "there should be %v completed builds left after pruning, but instead there were %v", *buildConfig.Spec.SuccessfulBuildsHistoryLimit, len(builds.Items)) + + }) + + g.It("should prune failed builds based on the failedBuildsHistoryLimit setting", func() { + + g.By("creating test image stream") + err := oc.Run("create").Args("-f", isFixture).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + g.By("creating test successful build config") + err = oc.Run("create").Args("-f", failedBuildConfig).Execute() + o.Expect(err).NotTo(o.HaveOccurred()) + + g.By("starting three test builds") + br, _ := exutil.StartBuildAndWait(oc, "myphp") + br.AssertFailure() + br, _ = exutil.StartBuildAndWait(oc, "myphp") + br.AssertFailure() + br, _ = exutil.StartBuildAndWait(oc, "myphp") + br.AssertFailure() + + buildConfig, err := oc.Client().BuildConfigs(oc.Namespace()).Get("myphp", metav1.GetOptions{}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + } + + builds, err := oc.Client().Builds(oc.Namespace()).List(metav1.ListOptions{}) + if err != nil { + fmt.Fprintf(g.GinkgoWriter, "%v", err) + } + + o.Expect(int32(len(builds.Items))).To(o.Equal(*buildConfig.Spec.FailedBuildsHistoryLimit), "there should be %v failed builds left after pruning, but instead there were %v", *buildConfig.Spec.FailedBuildsHistoryLimit, len(builds.Items)) + + }) +}) diff --git a/test/extended/testdata/bindata.go b/test/extended/testdata/bindata.go index 995b9b126872..88bf50bb36ea 100644 --- a/test/extended/testdata/bindata.go +++ b/test/extended/testdata/bindata.go @@ -5,6 +5,9 @@ // test/extended/testdata/build-extended/bc-scripts-in-the-image.yaml // test/extended/testdata/build-extended/jvm-runner-with-scripts.yaml // test/extended/testdata/build-extended/jvm-runner.yaml +// test/extended/testdata/build-pruning/failed-build-config.yaml +// test/extended/testdata/build-pruning/imagestream.yaml +// test/extended/testdata/build-pruning/successful-build-config.yaml // test/extended/testdata/build-quota/.s2i/bin/assemble // test/extended/testdata/build-quota/Dockerfile // test/extended/testdata/build-secrets/Dockerfile @@ -452,6 +455,125 @@ func testExtendedTestdataBuildExtendedJvmRunnerYaml() (*asset, error) { return a, nil } +var _testExtendedTestdataBuildPruningFailedBuildConfigYaml = []byte(`apiVersion: v1 +kind: BuildConfig +metadata: + name: myphp + labels: + app: myphp + annotations: + openshift.io/generated-by: OpenShiftWebConsole +spec: + failedBuildsHistoryLimit: 2 + triggers: {} + runPolicy: Serial + source: + type: Git + git: + uri: 'https://github.com/openshift/non-working-example.git' + ref: master + strategy: + type: Source + sourceStrategy: + from: + kind: ImageStreamTag + namespace: openshift + name: 'php:7.0' + output: + to: + kind: ImageStreamTag + name: 'myphp:latest' + resources: {} + postCommit: {} + nodeSelector: null +status: +`) + +func testExtendedTestdataBuildPruningFailedBuildConfigYamlBytes() ([]byte, error) { + return _testExtendedTestdataBuildPruningFailedBuildConfigYaml, nil +} + +func testExtendedTestdataBuildPruningFailedBuildConfigYaml() (*asset, error) { + bytes, err := testExtendedTestdataBuildPruningFailedBuildConfigYamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/build-pruning/failed-build-config.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testExtendedTestdataBuildPruningImagestreamYaml = []byte(`apiVersion: v1 +kind: ImageStream +metadata: + name: myphp +`) + +func testExtendedTestdataBuildPruningImagestreamYamlBytes() ([]byte, error) { + return _testExtendedTestdataBuildPruningImagestreamYaml, nil +} + +func testExtendedTestdataBuildPruningImagestreamYaml() (*asset, error) { + bytes, err := testExtendedTestdataBuildPruningImagestreamYamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/build-pruning/imagestream.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testExtendedTestdataBuildPruningSuccessfulBuildConfigYaml = []byte(`apiVersion: v1 +kind: BuildConfig +metadata: + name: myphp + labels: + app: myphp + annotations: + openshift.io/generated-by: OpenShiftWebConsole +spec: + successfulBuildsHistoryLimit: 2 + triggers: {} + runPolicy: Serial + source: + type: Git + git: + uri: 'https://github.com/openshift/cakephp-ex.git' + ref: master + strategy: + type: Source + sourceStrategy: + from: + kind: ImageStreamTag + namespace: openshift + name: 'php:7.0' + output: + to: + kind: ImageStreamTag + name: 'myphp:latest' + resources: {} + postCommit: {} + nodeSelector: null +status: +`) + +func testExtendedTestdataBuildPruningSuccessfulBuildConfigYamlBytes() ([]byte, error) { + return _testExtendedTestdataBuildPruningSuccessfulBuildConfigYaml, nil +} + +func testExtendedTestdataBuildPruningSuccessfulBuildConfigYaml() (*asset, error) { + bytes, err := testExtendedTestdataBuildPruningSuccessfulBuildConfigYamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/extended/testdata/build-pruning/successful-build-config.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + var _testExtendedTestdataBuildQuotaS2iBinAssemble = []byte(`#!/bin/sh @@ -19194,6 +19316,9 @@ var _bindata = map[string]func() (*asset, error){ "test/extended/testdata/build-extended/bc-scripts-in-the-image.yaml": testExtendedTestdataBuildExtendedBcScriptsInTheImageYaml, "test/extended/testdata/build-extended/jvm-runner-with-scripts.yaml": testExtendedTestdataBuildExtendedJvmRunnerWithScriptsYaml, "test/extended/testdata/build-extended/jvm-runner.yaml": testExtendedTestdataBuildExtendedJvmRunnerYaml, + "test/extended/testdata/build-pruning/failed-build-config.yaml": testExtendedTestdataBuildPruningFailedBuildConfigYaml, + "test/extended/testdata/build-pruning/imagestream.yaml": testExtendedTestdataBuildPruningImagestreamYaml, + "test/extended/testdata/build-pruning/successful-build-config.yaml": testExtendedTestdataBuildPruningSuccessfulBuildConfigYaml, "test/extended/testdata/build-quota/.s2i/bin/assemble": testExtendedTestdataBuildQuotaS2iBinAssemble, "test/extended/testdata/build-quota/Dockerfile": testExtendedTestdataBuildQuotaDockerfile, "test/extended/testdata/build-secrets/Dockerfile": testExtendedTestdataBuildSecretsDockerfile, @@ -19486,6 +19611,11 @@ var _bintree = &bintree{nil, map[string]*bintree{ "jvm-runner-with-scripts.yaml": &bintree{testExtendedTestdataBuildExtendedJvmRunnerWithScriptsYaml, map[string]*bintree{}}, "jvm-runner.yaml": &bintree{testExtendedTestdataBuildExtendedJvmRunnerYaml, map[string]*bintree{}}, }}, + "build-pruning": &bintree{nil, map[string]*bintree{ + "failed-build-config.yaml": &bintree{testExtendedTestdataBuildPruningFailedBuildConfigYaml, map[string]*bintree{}}, + "imagestream.yaml": &bintree{testExtendedTestdataBuildPruningImagestreamYaml, map[string]*bintree{}}, + "successful-build-config.yaml": &bintree{testExtendedTestdataBuildPruningSuccessfulBuildConfigYaml, map[string]*bintree{}}, + }}, "build-quota": &bintree{nil, map[string]*bintree{ ".s2i": &bintree{nil, map[string]*bintree{ "bin": &bintree{nil, map[string]*bintree{ diff --git a/test/extended/testdata/build-pruning/failed-build-config.yaml b/test/extended/testdata/build-pruning/failed-build-config.yaml new file mode 100644 index 000000000000..ece44b8da6af --- /dev/null +++ b/test/extended/testdata/build-pruning/failed-build-config.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: BuildConfig +metadata: + name: myphp + labels: + app: myphp + annotations: + openshift.io/generated-by: OpenShiftWebConsole +spec: + failedBuildsHistoryLimit: 2 + triggers: {} + runPolicy: Serial + source: + type: Git + git: + uri: 'https://github.com/openshift/non-working-example.git' + ref: master + strategy: + type: Source + sourceStrategy: + from: + kind: ImageStreamTag + namespace: openshift + name: 'php:7.0' + output: + to: + kind: ImageStreamTag + name: 'myphp:latest' + resources: {} + postCommit: {} + nodeSelector: null +status: diff --git a/test/extended/testdata/build-pruning/imagestream.yaml b/test/extended/testdata/build-pruning/imagestream.yaml new file mode 100644 index 000000000000..6378d9d80039 --- /dev/null +++ b/test/extended/testdata/build-pruning/imagestream.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: ImageStream +metadata: + name: myphp diff --git a/test/extended/testdata/build-pruning/successful-build-config.yaml b/test/extended/testdata/build-pruning/successful-build-config.yaml new file mode 100644 index 000000000000..14419bd62d50 --- /dev/null +++ b/test/extended/testdata/build-pruning/successful-build-config.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: BuildConfig +metadata: + name: myphp + labels: + app: myphp + annotations: + openshift.io/generated-by: OpenShiftWebConsole +spec: + successfulBuildsHistoryLimit: 2 + triggers: {} + runPolicy: Serial + source: + type: Git + git: + uri: 'https://github.com/openshift/cakephp-ex.git' + ref: master + strategy: + type: Source + sourceStrategy: + from: + kind: ImageStreamTag + namespace: openshift + name: 'php:7.0' + output: + to: + kind: ImageStreamTag + name: 'myphp:latest' + resources: {} + postCommit: {} + nodeSelector: null +status: