mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-15 23:03:40 +00:00
dra api: implement semver attribute value type
This adds support for semantic version comparison to the CEL support in the "named resources" structured parameter model. For example, it can be used to check that an instance supports a certain API level. To minimize the risk, the new "semver" type is only defined in the CEL environment for DRA expressions, not in the base library. See https://github.com/kubernetes/kubernetes/pull/123664 for a PR which adds it to the base library. Validation of semver strings is done with the regular expression from semver.org. The actual evaluation at runtime then uses semver/v4.
This commit is contained in:
parent
234dc1f63d
commit
42ee56f093
@ -57,6 +57,7 @@ API rule violation: names_match,k8s.io/api/resource/v1alpha2,NamedResourcesAttri
|
||||
API rule violation: names_match,k8s.io/api/resource/v1alpha2,NamedResourcesAttributeValue,QuantityValue
|
||||
API rule violation: names_match,k8s.io/api/resource/v1alpha2,NamedResourcesAttributeValue,StringSliceValue
|
||||
API rule violation: names_match,k8s.io/api/resource/v1alpha2,NamedResourcesAttributeValue,StringValue
|
||||
API rule violation: names_match,k8s.io/api/resource/v1alpha2,NamedResourcesAttributeValue,VersionValue
|
||||
API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaProps,Ref
|
||||
API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaProps,Schema
|
||||
API rule violation: names_match,k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1,JSONSchemaProps,XEmbeddedResource
|
||||
|
4
api/openapi-spec/swagger.json
generated
4
api/openapi-spec/swagger.json
generated
@ -14900,6 +14900,10 @@
|
||||
"stringSlice": {
|
||||
"$ref": "#/definitions/io.k8s.api.resource.v1alpha2.NamedResourcesStringSlice",
|
||||
"description": "StringSliceValue is an array of strings."
|
||||
},
|
||||
"version": {
|
||||
"description": "VersionValue is a semantic version according to semver.org spec 2.0.0.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
@ -228,6 +228,10 @@
|
||||
}
|
||||
],
|
||||
"description": "StringSliceValue is an array of strings."
|
||||
},
|
||||
"version": {
|
||||
"description": "VersionValue is a semantic version according to semver.org spec 2.0.0.",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
@ -59,7 +59,8 @@ type NamedResourcesAttributeValue struct {
|
||||
StringValue *string
|
||||
// StringSliceValue is an array of strings.
|
||||
StringSliceValue *NamedResourcesStringSlice
|
||||
// TODO: VersionValue *SemVersion
|
||||
// VersionValue is a semantic version according to semver.org spec 2.0.0.
|
||||
VersionValue *string
|
||||
}
|
||||
|
||||
// NamedResourcesIntSlice contains a slice of 64-bit integers.
|
||||
@ -74,17 +75,6 @@ type NamedResourcesStringSlice struct {
|
||||
Strings []string
|
||||
}
|
||||
|
||||
// TODO
|
||||
//
|
||||
// A wrapper around https://pkg.go.dev/github.com/blang/semver/v4#Version which
|
||||
// is encoded as a string. During decoding, it validates that the string
|
||||
// can be parsed using tolerant parsing (currently trims spaces, removes a "v" prefix,
|
||||
// adds a 0 patch number to versions with only major and minor components specified,
|
||||
// and removes leading 0s).
|
||||
// type SemVersion struct {
|
||||
// semver.Version
|
||||
//}
|
||||
|
||||
// NamedResourcesRequest is used in ResourceRequestModel.
|
||||
type NamedResourcesRequest struct {
|
||||
// Selector is a CEL expression which must evaluate to true if a
|
||||
|
@ -18,6 +18,7 @@ package validation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
@ -63,6 +64,27 @@ func validateInstances(instances []resource.NamedResourcesInstance, fldPath *fie
|
||||
return allErrs
|
||||
}
|
||||
|
||||
var (
|
||||
numericIdentifier = `(0|[1-9]\d*)`
|
||||
|
||||
preReleaseIdentifier = `(0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)`
|
||||
|
||||
buildIdentifier = `[0-9a-zA-Z-]+`
|
||||
|
||||
semverRe = regexp.MustCompile(`^` +
|
||||
|
||||
// dot-separated version segments (e.g. 1.2.3)
|
||||
numericIdentifier + `\.` + numericIdentifier + `\.` + numericIdentifier +
|
||||
|
||||
// optional dot-separated prerelease segments (e.g. -alpha.PRERELEASE.1)
|
||||
`(-` + preReleaseIdentifier + `(\.` + preReleaseIdentifier + `)*)?` +
|
||||
|
||||
// optional dot-separated build identifier segments (e.g. +build.id.20240305)
|
||||
`(\+` + buildIdentifier + `(\.` + buildIdentifier + `)*)?` +
|
||||
|
||||
`$`)
|
||||
)
|
||||
|
||||
func validateAttributes(attributes []resource.NamedResourcesAttribute, fldPath *field.Path) field.ErrorList {
|
||||
var allErrs field.ErrorList
|
||||
attributeNames := sets.New[string]()
|
||||
@ -95,7 +117,12 @@ func validateAttributes(attributes []resource.NamedResourcesAttribute, fldPath *
|
||||
if attribute.StringSliceValue != nil {
|
||||
entries.Insert("stringSlice")
|
||||
}
|
||||
// TODO: VersionValue
|
||||
if attribute.VersionValue != nil {
|
||||
entries.Insert("version")
|
||||
if !semverRe.MatchString(*attribute.VersionValue) {
|
||||
allErrs = append(allErrs, field.Invalid(idxPath.Child("version"), *attribute.VersionValue, "must be a string compatible with semver.org spec 2.0.0"))
|
||||
}
|
||||
}
|
||||
|
||||
switch len(entries) {
|
||||
case 0:
|
||||
|
@ -75,7 +75,44 @@ func TestValidateResources(t *testing.T) {
|
||||
"string-slice": {
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{StringSliceValue: &resourceapi.NamedResourcesStringSlice{Strings: []string{"hello"}}}}}}}),
|
||||
},
|
||||
// TODO: semver
|
||||
"version-okay": {
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{VersionValue: ptr.To("1.0.0")}}}}}),
|
||||
},
|
||||
"version-beta": {
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{VersionValue: ptr.To("1.0.0-beta")}}}}}),
|
||||
},
|
||||
"version-beta-1": {
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{VersionValue: ptr.To("1.0.0-beta.1")}}}}}),
|
||||
},
|
||||
"version-build": {
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{VersionValue: ptr.To("1.0.0+build")}}}}}),
|
||||
},
|
||||
"version-build-1": {
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{VersionValue: ptr.To("1.0.0+build.1")}}}}}),
|
||||
},
|
||||
"version-beta-1-build-1": {
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{VersionValue: ptr.To("1.0.0-beta.1+build.1")}}}}}),
|
||||
},
|
||||
"version-bad": {
|
||||
wantFailures: field.ErrorList{field.Invalid(field.NewPath("instances").Index(0).Child("attributes").Index(0).Child("version"), "1.0", "must be a string compatible with semver.org spec 2.0.0")},
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{VersionValue: ptr.To("1.0")}}}}}),
|
||||
},
|
||||
"version-bad-leading-zeros": {
|
||||
wantFailures: field.ErrorList{field.Invalid(field.NewPath("instances").Index(0).Child("attributes").Index(0).Child("version"), "01.0.0", "must be a string compatible with semver.org spec 2.0.0")},
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{VersionValue: ptr.To("01.0.0")}}}}}),
|
||||
},
|
||||
"version-bad-leading-zeros-middle": {
|
||||
wantFailures: field.ErrorList{field.Invalid(field.NewPath("instances").Index(0).Child("attributes").Index(0).Child("version"), "1.00.0", "must be a string compatible with semver.org spec 2.0.0")},
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{VersionValue: ptr.To("1.00.0")}}}}}),
|
||||
},
|
||||
"version-bad-leading-zeros-end": {
|
||||
wantFailures: field.ErrorList{field.Invalid(field.NewPath("instances").Index(0).Child("attributes").Index(0).Child("version"), "1.0.00", "must be a string compatible with semver.org spec 2.0.0")},
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{VersionValue: ptr.To("1.0.00")}}}}}),
|
||||
},
|
||||
"version-bad-spaces": {
|
||||
wantFailures: field.ErrorList{field.Invalid(field.NewPath("instances").Index(0).Child("attributes").Index(0).Child("version"), " 1.0.0 ", "must be a string compatible with semver.org spec 2.0.0")},
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName, NamedResourcesAttributeValue: resourceapi.NamedResourcesAttributeValue{VersionValue: ptr.To(" 1.0.0 ")}}}}}),
|
||||
},
|
||||
"empty-attribute": {
|
||||
wantFailures: field.ErrorList{field.Required(field.NewPath("instances").Index(0).Child("attributes").Index(0), "exactly one value must be set")},
|
||||
resources: testResources([]resourceapi.NamedResourcesInstance{{Name: goodName, Attributes: []resourceapi.NamedResourcesAttribute{{Name: goodName}}}}),
|
||||
@ -132,7 +169,9 @@ func TestValidateSelector(t *testing.T) {
|
||||
"stringslice": {
|
||||
selector: `attributes.stringslice["name"].isSorted()`,
|
||||
},
|
||||
// TODO: semver
|
||||
"version": {
|
||||
selector: `attributes.version["name"].isGreaterThan(semver("1.0.0"))`,
|
||||
},
|
||||
}
|
||||
|
||||
for name, scenario := range scenarios {
|
||||
|
@ -679,6 +679,7 @@ func autoConvert_v1alpha2_NamedResourcesAttributeValue_To_resource_NamedResource
|
||||
out.IntSliceValue = (*resource.NamedResourcesIntSlice)(unsafe.Pointer(in.IntSliceValue))
|
||||
out.StringValue = (*string)(unsafe.Pointer(in.StringValue))
|
||||
out.StringSliceValue = (*resource.NamedResourcesStringSlice)(unsafe.Pointer(in.StringSliceValue))
|
||||
out.VersionValue = (*string)(unsafe.Pointer(in.VersionValue))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -694,6 +695,7 @@ func autoConvert_resource_NamedResourcesAttributeValue_To_v1alpha2_NamedResource
|
||||
out.IntSliceValue = (*v1alpha2.NamedResourcesIntSlice)(unsafe.Pointer(in.IntSliceValue))
|
||||
out.StringValue = (*string)(unsafe.Pointer(in.StringValue))
|
||||
out.StringSliceValue = (*v1alpha2.NamedResourcesStringSlice)(unsafe.Pointer(in.StringSliceValue))
|
||||
out.VersionValue = (*string)(unsafe.Pointer(in.VersionValue))
|
||||
return nil
|
||||
}
|
||||
|
||||
|
5
pkg/apis/resource/zz_generated.deepcopy.go
generated
5
pkg/apis/resource/zz_generated.deepcopy.go
generated
@ -187,6 +187,11 @@ func (in *NamedResourcesAttributeValue) DeepCopyInto(out *NamedResourcesAttribut
|
||||
*out = new(NamedResourcesStringSlice)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.VersionValue != nil {
|
||||
in, out := &in.VersionValue, &out.VersionValue
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
14
pkg/generated/openapi/zz_generated.openapi.go
generated
14
pkg/generated/openapi/zz_generated.openapi.go
generated
@ -44907,6 +44907,13 @@ func schema_k8sio_api_resource_v1alpha2_NamedResourcesAttribute(ref common.Refer
|
||||
Ref: ref("k8s.io/api/resource/v1alpha2.NamedResourcesStringSlice"),
|
||||
},
|
||||
},
|
||||
"version": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "VersionValue is a semantic version according to semver.org spec 2.0.0.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
Required: []string{"name"},
|
||||
},
|
||||
@ -44962,6 +44969,13 @@ func schema_k8sio_api_resource_v1alpha2_NamedResourcesAttributeValue(ref common.
|
||||
Ref: ref("k8s.io/api/resource/v1alpha2.NamedResourcesStringSlice"),
|
||||
},
|
||||
},
|
||||
"version": {
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Description: "VersionValue is a semantic version according to semver.org spec 2.0.0.",
|
||||
Type: []string{"string"},
|
||||
Format: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
329
staging/src/k8s.io/api/resource/v1alpha2/generated.pb.go
generated
329
staging/src/k8s.io/api/resource/v1alpha2/generated.pb.go
generated
@ -1331,147 +1331,149 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_4312f5b44a31ec02 = []byte{
|
||||
// 2231 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x1a, 0x4b, 0x6f, 0x1b, 0xc7,
|
||||
0xd9, 0x4b, 0xd2, 0x16, 0xf5, 0xc9, 0xa2, 0xa4, 0xb5, 0x64, 0xd1, 0x8e, 0x42, 0x2a, 0x8b, 0x16,
|
||||
0x15, 0x50, 0x9b, 0x8c, 0xe5, 0xc4, 0x31, 0xd2, 0xb4, 0x80, 0xd7, 0x8a, 0x5d, 0xa1, 0x89, 0xa3,
|
||||
0x0c, 0x63, 0x27, 0x4e, 0x5f, 0x59, 0x71, 0xc7, 0xd2, 0xd6, 0xe4, 0x2e, 0xbd, 0x33, 0x54, 0x6c,
|
||||
0xf4, 0x62, 0x14, 0x7d, 0x5d, 0x0a, 0xa4, 0x68, 0x51, 0xb4, 0xa7, 0x9e, 0x8a, 0xa2, 0x97, 0x5e,
|
||||
0xda, 0x7b, 0x0f, 0x41, 0x1b, 0x03, 0xbd, 0x38, 0x68, 0x81, 0x06, 0x3d, 0x10, 0x35, 0xfb, 0x13,
|
||||
0x7a, 0xcb, 0xa9, 0x98, 0xc7, 0x3e, 0x66, 0xb9, 0x4b, 0x71, 0xd9, 0x46, 0x48, 0x4e, 0xd2, 0xce,
|
||||
0x7c, 0xef, 0xef, 0x9b, 0xef, 0x31, 0x43, 0x38, 0x77, 0xf7, 0x32, 0x69, 0x38, 0x5e, 0xd3, 0xea,
|
||||
0x39, 0x4d, 0x1f, 0x13, 0xaf, 0xef, 0xb7, 0x71, 0xf3, 0xe0, 0x82, 0xd5, 0xe9, 0xed, 0x5b, 0x9b,
|
||||
0xcd, 0x3d, 0xec, 0x62, 0xdf, 0xa2, 0xd8, 0x6e, 0xf4, 0x7c, 0x8f, 0x7a, 0xfa, 0x9a, 0x80, 0x6e,
|
||||
0x58, 0x3d, 0xa7, 0x11, 0x40, 0x37, 0x02, 0xe8, 0xb3, 0xe7, 0xf7, 0x1c, 0xba, 0xdf, 0xdf, 0x6d,
|
||||
0xb4, 0xbd, 0x6e, 0x73, 0xcf, 0xdb, 0xf3, 0x9a, 0x1c, 0x69, 0xb7, 0x7f, 0x87, 0x7f, 0xf1, 0x0f,
|
||||
0xfe, 0x9f, 0x20, 0x76, 0xd6, 0x88, 0xb1, 0x6e, 0x7b, 0x3e, 0x63, 0x9b, 0x64, 0x78, 0xf6, 0xb9,
|
||||
0x08, 0xa6, 0x6b, 0xb5, 0xf7, 0x1d, 0x17, 0xfb, 0x0f, 0x9a, 0xbd, 0xbb, 0x7b, 0xaa, 0xbc, 0x79,
|
||||
0xb0, 0x48, 0xb3, 0x8b, 0xa9, 0x95, 0xc6, 0xab, 0x99, 0x85, 0xe5, 0xf7, 0x5d, 0xea, 0x74, 0x47,
|
||||
0xd9, 0x5c, 0x3a, 0x0c, 0x81, 0xb4, 0xf7, 0x71, 0xd7, 0x4a, 0xe2, 0x19, 0xbf, 0x2c, 0xc0, 0xe2,
|
||||
0x95, 0x4e, 0xc7, 0x6b, 0x5b, 0xd4, 0xf1, 0x5c, 0x84, 0x49, 0xbf, 0x43, 0x75, 0x0f, 0x16, 0x02,
|
||||
0x7d, 0xbe, 0x6a, 0xb9, 0x76, 0x07, 0x93, 0xaa, 0xb6, 0x5e, 0xdc, 0x98, 0xdb, 0x3c, 0xd7, 0x18,
|
||||
0x67, 0xf4, 0x06, 0x52, 0x90, 0xcc, 0xd5, 0x47, 0x83, 0xfa, 0xb1, 0xe1, 0xa0, 0xbe, 0xa0, 0xae,
|
||||
0x13, 0x94, 0xa4, 0xae, 0xef, 0xc2, 0xa2, 0x75, 0x60, 0x39, 0x1d, 0x6b, 0xb7, 0x83, 0x5f, 0x73,
|
||||
0x6f, 0x78, 0x36, 0x26, 0xd5, 0xc2, 0xba, 0xb6, 0x31, 0xb7, 0xb9, 0x1e, 0xe7, 0xc8, 0x3c, 0xd3,
|
||||
0x38, 0xb8, 0xd0, 0x60, 0x00, 0x2d, 0xdc, 0xc1, 0x6d, 0xea, 0xf9, 0xe6, 0xf2, 0x70, 0x50, 0x5f,
|
||||
0xbc, 0x92, 0xc0, 0x46, 0x23, 0xf4, 0xf4, 0x26, 0xcc, 0x92, 0x7d, 0xcb, 0xc7, 0x6c, 0xad, 0x5a,
|
||||
0x5c, 0xd7, 0x36, 0xca, 0xe6, 0x92, 0x14, 0x70, 0xb6, 0x15, 0x6c, 0xa0, 0x08, 0xc6, 0xf8, 0xa9,
|
||||
0x06, 0x2b, 0x49, 0xd3, 0xbc, 0xea, 0xd9, 0xb8, 0xa3, 0xdf, 0x87, 0x8a, 0x6b, 0x75, 0xb1, 0x1d,
|
||||
0xe8, 0xc5, 0xcc, 0xc3, 0x84, 0x7d, 0x69, 0xbc, 0x79, 0x6e, 0x28, 0x38, 0x49, 0xd2, 0xa6, 0x3e,
|
||||
0x1c, 0xd4, 0x2b, 0x2a, 0x0c, 0x4a, 0xf0, 0x31, 0x7e, 0x5f, 0x80, 0xd3, 0x5b, 0xbe, 0x73, 0x80,
|
||||
0xfd, 0x11, 0xa7, 0xfd, 0x58, 0x83, 0xd5, 0x03, 0xec, 0xda, 0x9e, 0x8f, 0xf0, 0xbd, 0x3e, 0x26,
|
||||
0x74, 0xc7, 0xf2, 0xad, 0x2e, 0xa6, 0xd8, 0x0f, 0xc4, 0x3b, 0x1f, 0x13, 0x2f, 0x0c, 0x92, 0x46,
|
||||
0xef, 0xee, 0x5e, 0x43, 0x06, 0x49, 0x03, 0x59, 0xef, 0xbe, 0x7c, 0x9f, 0x62, 0x97, 0x38, 0x9e,
|
||||
0x6b, 0xd6, 0xa5, 0x75, 0x56, 0x6f, 0xa5, 0x53, 0x45, 0x59, 0xec, 0x98, 0x28, 0x2b, 0x56, 0x9a,
|
||||
0xe5, 0xa4, 0x53, 0x2f, 0x8e, 0xb7, 0x53, 0xaa, 0xd1, 0xcd, 0xa7, 0xa5, 0x38, 0xe9, 0x3e, 0x41,
|
||||
0xe9, 0x0c, 0x8d, 0x5f, 0x14, 0xa0, 0x22, 0x0c, 0x26, 0xc5, 0x24, 0xfa, 0x26, 0x80, 0xcd, 0x57,
|
||||
0x98, 0xad, 0xb9, 0x69, 0x66, 0x4d, 0x5d, 0x12, 0x87, 0xad, 0x70, 0x07, 0xc5, 0xa0, 0x74, 0x02,
|
||||
0x8b, 0x42, 0xd9, 0x98, 0x51, 0x0b, 0xd3, 0x18, 0xb5, 0x2a, 0x19, 0x2d, 0xde, 0x4a, 0x90, 0x43,
|
||||
0x23, 0x0c, 0xf4, 0xaf, 0x43, 0xd9, 0x97, 0x42, 0x57, 0x8b, 0xfc, 0xfc, 0x9d, 0x9f, 0xec, 0xfc,
|
||||
0x49, 0x55, 0xcd, 0x45, 0xc9, 0xac, 0x1c, 0xe8, 0x8e, 0x42, 0x82, 0x86, 0x09, 0xb5, 0xf1, 0xf1,
|
||||
0xa8, 0xaf, 0x43, 0xc9, 0x8d, 0x2c, 0x74, 0x52, 0xd2, 0x2a, 0x71, 0xdb, 0xf0, 0x1d, 0xe3, 0x2f,
|
||||
0x1a, 0xac, 0x26, 0x88, 0x50, 0xea, 0x3b, 0xbb, 0x7d, 0x8a, 0x0f, 0xc7, 0x66, 0x51, 0x52, 0xb1,
|
||||
0x02, 0xf8, 0x5b, 0x56, 0xa7, 0x8f, 0xa5, 0x49, 0x5f, 0xcc, 0x75, 0x8c, 0x14, 0x0a, 0xe6, 0xe7,
|
||||
0x24, 0xa3, 0xb5, 0x71, 0x50, 0x28, 0xc1, 0xd7, 0xf8, 0x53, 0x11, 0xc6, 0x22, 0xe8, 0xdf, 0x84,
|
||||
0xf2, 0xbd, 0xbe, 0xe5, 0x52, 0x87, 0x3e, 0xa8, 0x9e, 0xe0, 0x42, 0x36, 0x32, 0xfd, 0xae, 0x48,
|
||||
0xfd, 0xba, 0xc4, 0x32, 0x97, 0x86, 0x83, 0xfa, 0x7c, 0xf0, 0x25, 0xa4, 0x08, 0x49, 0xea, 0xcf,
|
||||
0x40, 0x69, 0xd7, 0xf3, 0xc4, 0xf1, 0x28, 0x9b, 0xf3, 0x2c, 0x25, 0x99, 0x9e, 0xd7, 0x11, 0x60,
|
||||
0x7c, 0x4b, 0xaf, 0x41, 0xd1, 0x71, 0x69, 0x75, 0x66, 0x5d, 0xdb, 0x28, 0x9a, 0x27, 0x99, 0x53,
|
||||
0xb7, 0x5d, 0x2a, 0x00, 0xd8, 0x86, 0xde, 0x86, 0xb2, 0xe3, 0xd2, 0x56, 0xc7, 0x69, 0xe3, 0x6a,
|
||||
0x99, 0x4b, 0xf8, 0x5c, 0x1e, 0x33, 0x6e, 0x4b, 0x5c, 0x21, 0x67, 0xf0, 0x25, 0xe5, 0x0c, 0x08,
|
||||
0xeb, 0x5f, 0x80, 0x13, 0x84, 0xfa, 0x8e, 0xbb, 0x57, 0x3d, 0xce, 0xdd, 0xba, 0x30, 0x1c, 0xd4,
|
||||
0xe7, 0x5a, 0x7c, 0x45, 0x80, 0xca, 0x6d, 0xdd, 0x83, 0x39, 0xf1, 0x9f, 0x10, 0x68, 0x96, 0x0b,
|
||||
0xf4, 0x42, 0x1e, 0x81, 0x5a, 0x11, 0xba, 0x48, 0xf1, 0xb1, 0x05, 0xc1, 0x2b, 0xce, 0xc1, 0xd8,
|
||||
0x82, 0x65, 0x15, 0xff, 0x9a, 0xd3, 0xa1, 0xd8, 0xd7, 0xcf, 0x41, 0x99, 0xc8, 0x4a, 0x21, 0x43,
|
||||
0x31, 0x3c, 0x14, 0x41, 0x05, 0x41, 0x21, 0x84, 0xf1, 0x1b, 0x0d, 0x4e, 0x27, 0xed, 0x42, 0xa8,
|
||||
0xe5, 0xb6, 0x27, 0x89, 0x67, 0x07, 0x20, 0x0c, 0x2b, 0x96, 0x1d, 0xd8, 0x81, 0x7d, 0x7e, 0xaa,
|
||||
0x50, 0x8e, 0xd2, 0x51, 0xb8, 0x44, 0x50, 0x8c, 0xb8, 0x71, 0x69, 0x54, 0x4c, 0xe9, 0xa1, 0x35,
|
||||
0x28, 0x39, 0x2e, 0x15, 0xf5, 0xba, 0x68, 0x96, 0x99, 0x88, 0xdb, 0x2e, 0x25, 0x88, 0xaf, 0x1a,
|
||||
0x2f, 0xc3, 0x4a, 0xa2, 0xc0, 0x88, 0x74, 0x90, 0xd3, 0x4c, 0x0f, 0x47, 0xce, 0x7d, 0xf8, 0x8f,
|
||||
0x8e, 0x61, 0xd6, 0x91, 0x36, 0x0b, 0xba, 0x86, 0x9c, 0x81, 0x28, 0x90, 0xa3, 0xe2, 0x1c, 0xac,
|
||||
0x10, 0x14, 0x51, 0x36, 0x4c, 0x38, 0x93, 0x19, 0x2f, 0xfa, 0xe7, 0x61, 0x46, 0xc4, 0x86, 0x90,
|
||||
0x60, 0xd6, 0x9c, 0x1b, 0x0e, 0xea, 0x33, 0x02, 0x82, 0xa0, 0x60, 0xcf, 0xf8, 0xa1, 0x06, 0x4b,
|
||||
0xac, 0x37, 0x08, 0x68, 0x88, 0xe2, 0x7e, 0x2f, 0xa3, 0xb8, 0xe7, 0x72, 0x65, 0xf8, 0xcf, 0x44,
|
||||
0x55, 0xfd, 0xc3, 0x82, 0x2a, 0x88, 0xd0, 0xe2, 0x1d, 0x28, 0xb3, 0xf6, 0xd0, 0xb6, 0xa8, 0x25,
|
||||
0x45, 0x78, 0x76, 0x5c, 0xce, 0x21, 0x0d, 0x06, 0xcd, 0xda, 0xa3, 0xd7, 0x76, 0xbf, 0x83, 0xdb,
|
||||
0xf4, 0x55, 0x4c, 0xad, 0x28, 0x90, 0xa2, 0x35, 0x14, 0x52, 0x65, 0x5e, 0x77, 0x3d, 0x1b, 0xf3,
|
||||
0x3a, 0x58, 0x50, 0xbd, 0x7e, 0x43, 0xae, 0xa3, 0x10, 0x22, 0x51, 0x37, 0x8b, 0x13, 0xd5, 0xcd,
|
||||
0xfb, 0xb0, 0xe4, 0x26, 0x2d, 0x5c, 0x2d, 0x71, 0x65, 0x9a, 0x87, 0xd8, 0x33, 0x89, 0x66, 0x9e,
|
||||
0x91, 0xbc, 0x46, 0x7d, 0x86, 0x46, 0x99, 0x18, 0x7f, 0xd5, 0x60, 0x65, 0xc4, 0xa6, 0xaf, 0x38,
|
||||
0x84, 0xea, 0xdf, 0x18, 0xb1, 0x6b, 0x63, 0x32, 0xbb, 0x32, 0x6c, 0x6e, 0xd5, 0xd0, 0x4a, 0xc1,
|
||||
0x4a, 0xcc, 0xa6, 0x6f, 0xc0, 0x71, 0x87, 0xe2, 0x6e, 0x90, 0x00, 0x72, 0x68, 0x29, 0x72, 0xdd,
|
||||
0xbc, 0xa4, 0x7d, 0x7c, 0x9b, 0x51, 0x41, 0x82, 0x98, 0xf1, 0xc7, 0x02, 0x2c, 0xef, 0x78, 0x76,
|
||||
0xab, 0xbd, 0x8f, 0xed, 0x7e, 0xc7, 0x71, 0xf7, 0xae, 0x7a, 0x2e, 0xc5, 0xf7, 0xe9, 0x11, 0x04,
|
||||
0xc9, 0x5b, 0x50, 0x22, 0x3d, 0xdc, 0x96, 0xb5, 0xf9, 0xd2, 0x78, 0x7d, 0xd2, 0x64, 0x6c, 0xf5,
|
||||
0x70, 0x3b, 0x4a, 0x98, 0xec, 0x0b, 0x71, 0x8a, 0xfa, 0x3b, 0xac, 0x9a, 0x58, 0xb4, 0x4f, 0x78,
|
||||
0x30, 0xcd, 0x6d, 0x5e, 0x9e, 0x82, 0x36, 0xc7, 0x37, 0x2b, 0x92, 0xfa, 0x09, 0xf1, 0x8d, 0x24,
|
||||
0x5d, 0xe3, 0x43, 0x0d, 0xaa, 0x69, 0x68, 0x47, 0x10, 0x07, 0x6f, 0xaa, 0x71, 0xb0, 0x99, 0x5f,
|
||||
0xb7, 0x8c, 0x50, 0x78, 0x2f, 0x43, 0x27, 0x66, 0x58, 0xfd, 0x32, 0x9c, 0x14, 0x59, 0x1a, 0xdb,
|
||||
0x2c, 0xb4, 0x64, 0x2e, 0x5f, 0x96, 0x84, 0x4e, 0xb6, 0x62, 0x7b, 0x48, 0x81, 0xd4, 0x5f, 0x84,
|
||||
0x4a, 0xcf, 0xa3, 0xd8, 0xa5, 0x8e, 0xd5, 0x09, 0x06, 0x30, 0x96, 0x3a, 0x79, 0xfe, 0xda, 0x51,
|
||||
0x76, 0x50, 0x02, 0xd2, 0xf8, 0x95, 0x06, 0x67, 0xb3, 0xbd, 0xa3, 0x7f, 0x17, 0x2a, 0x81, 0xc6,
|
||||
0x57, 0x3b, 0x96, 0xd3, 0x0d, 0xea, 0xc2, 0x97, 0x26, 0xeb, 0x66, 0x39, 0x4e, 0x44, 0x5b, 0xba,
|
||||
0xfc, 0xb4, 0xd4, 0xa9, 0xa2, 0x80, 0x11, 0x94, 0x60, 0x65, 0xfc, 0xba, 0x00, 0xf3, 0x0a, 0xc8,
|
||||
0x11, 0x1c, 0x99, 0xd7, 0x95, 0x23, 0xd3, 0xcc, 0xa3, 0x66, 0xd6, 0x59, 0xb9, 0x9d, 0x38, 0x2b,
|
||||
0x17, 0xf2, 0x10, 0x1d, 0x7f, 0x48, 0x86, 0x1a, 0xd4, 0x14, 0xf8, 0xab, 0x9e, 0x4b, 0xfa, 0x5d,
|
||||
0x36, 0x31, 0xdd, 0xc1, 0x3e, 0x66, 0xcd, 0xcf, 0x39, 0x28, 0x5b, 0x3d, 0xe7, 0xba, 0xef, 0xf5,
|
||||
0x7b, 0xc9, 0xf6, 0xe0, 0xca, 0xce, 0x36, 0x5f, 0x47, 0x21, 0x04, 0x83, 0x0e, 0x24, 0x92, 0x65,
|
||||
0x22, 0x36, 0x88, 0xc8, 0x09, 0x25, 0x84, 0x08, 0x1b, 0xab, 0x52, 0x66, 0x63, 0x65, 0x42, 0xb1,
|
||||
0xef, 0xd8, 0xb2, 0xe5, 0x7c, 0x56, 0x02, 0x14, 0x6f, 0x6e, 0x6f, 0x7d, 0x3c, 0xa8, 0x3f, 0x93,
|
||||
0x75, 0xef, 0x41, 0x1f, 0xf4, 0x30, 0x69, 0xdc, 0xdc, 0xde, 0x42, 0x0c, 0xd9, 0x78, 0x5f, 0x83,
|
||||
0x25, 0x45, 0xc9, 0x23, 0x48, 0x01, 0x3b, 0x6a, 0x0a, 0xf8, 0x62, 0x0e, 0x97, 0x65, 0x9c, 0xfd,
|
||||
0x9f, 0x15, 0x61, 0x55, 0x81, 0x8b, 0x4d, 0x8b, 0x9f, 0x7c, 0x58, 0xbf, 0x0b, 0xf3, 0xe1, 0xf5,
|
||||
0xd1, 0x35, 0xdf, 0xeb, 0xca, 0xf8, 0xfe, 0x4a, 0x0e, 0xbd, 0x62, 0xf3, 0x6e, 0x10, 0x5c, 0x62,
|
||||
0xe2, 0xb8, 0x1e, 0x27, 0x8c, 0x54, 0x3e, 0xb9, 0xaf, 0x6e, 0xf4, 0x0e, 0x54, 0x6c, 0x65, 0xe8,
|
||||
0xaf, 0x96, 0x26, 0xb9, 0xbf, 0x52, 0x2f, 0x0a, 0xa2, 0x14, 0xa3, 0xae, 0xa3, 0x04, 0x6d, 0xe3,
|
||||
0x1f, 0x1a, 0x3c, 0x95, 0xa1, 0xe5, 0x11, 0x44, 0xd9, 0xdb, 0x6a, 0x94, 0x3d, 0x3f, 0x95, 0x37,
|
||||
0x32, 0xe2, 0xed, 0xe7, 0x1a, 0xac, 0x1f, 0xe6, 0xbf, 0x9c, 0xc9, 0x61, 0x1d, 0x4a, 0x77, 0x1d,
|
||||
0xd7, 0x96, 0xfd, 0x66, 0x78, 0xdc, 0xbf, 0xe6, 0xb8, 0x36, 0xe2, 0x3b, 0x61, 0x42, 0x28, 0x66,
|
||||
0xde, 0x3b, 0x3c, 0xd4, 0xe0, 0xe9, 0xb1, 0xd5, 0x61, 0x82, 0x69, 0xed, 0xcb, 0xb0, 0xd0, 0x77,
|
||||
0x49, 0xdf, 0xa1, 0x2c, 0x60, 0xe2, 0x05, 0xef, 0xd4, 0x70, 0x50, 0x5f, 0xb8, 0xa9, 0x6e, 0xa1,
|
||||
0x24, 0xac, 0xf1, 0xdb, 0x42, 0x22, 0x9f, 0xf0, 0xf2, 0x7b, 0x1d, 0x96, 0x62, 0xe5, 0x87, 0x90,
|
||||
0xd8, 0x0d, 0x53, 0xd8, 0xbd, 0xa2, 0x24, 0x00, 0x1a, 0xc5, 0x61, 0x47, 0xad, 0x17, 0x37, 0xf5,
|
||||
0xff, 0xf3, 0xa8, 0x29, 0x1b, 0x48, 0xe5, 0xa3, 0xef, 0x40, 0x25, 0xba, 0x48, 0x63, 0x9d, 0xb4,
|
||||
0x74, 0xc3, 0x46, 0x70, 0x16, 0xae, 0x28, 0xbb, 0x1f, 0x8f, 0xac, 0xa0, 0x04, 0xbe, 0xf1, 0x9f,
|
||||
0x02, 0x9c, 0x4a, 0x29, 0x47, 0x53, 0x5d, 0xc3, 0x7d, 0x0b, 0x20, 0xa2, 0x2e, 0x6d, 0xd2, 0xc8,
|
||||
0x77, 0x99, 0x68, 0x56, 0xf8, 0x5c, 0x1d, 0xad, 0xc6, 0x28, 0xea, 0x04, 0xe6, 0x7c, 0x4c, 0xb0,
|
||||
0x7f, 0x80, 0xed, 0x6b, 0x9e, 0x2f, 0x2f, 0xdd, 0x5e, 0xca, 0x61, 0xf4, 0x91, 0xd2, 0x69, 0x9e,
|
||||
0x92, 0x2a, 0xcd, 0xa1, 0x88, 0x30, 0x8a, 0x73, 0xd1, 0x5b, 0xb0, 0x62, 0xe3, 0xf8, 0xed, 0x25,
|
||||
0x4f, 0x2b, 0xd8, 0xe6, 0x15, 0xb1, 0x1c, 0xdd, 0x7b, 0x6e, 0xa5, 0x01, 0xa1, 0x74, 0x5c, 0xe3,
|
||||
0xef, 0x1a, 0xac, 0x28, 0x92, 0xbd, 0x81, 0xbb, 0xbd, 0x8e, 0x45, 0x8f, 0x62, 0xac, 0xbc, 0xad,
|
||||
0xb4, 0x3f, 0x2f, 0xe4, 0x30, 0x5f, 0x20, 0x64, 0x56, 0x1b, 0x64, 0xfc, 0x4d, 0x83, 0x33, 0xa9,
|
||||
0x18, 0x47, 0x90, 0x68, 0xdf, 0x52, 0x13, 0xed, 0xc5, 0x29, 0xf4, 0xca, 0x48, 0xb3, 0x8f, 0xb3,
|
||||
0xb4, 0x6a, 0x89, 0x31, 0xe9, 0xb3, 0xd7, 0xaf, 0x1a, 0x1f, 0x14, 0x95, 0xb6, 0x9b, 0x1c, 0x45,
|
||||
0x7f, 0xa2, 0x66, 0x94, 0xc2, 0x44, 0x19, 0x65, 0x24, 0xd1, 0x16, 0x73, 0x26, 0x5a, 0x42, 0xa6,
|
||||
0x4b, 0xb4, 0xb7, 0x61, 0x5e, 0xad, 0x3e, 0xa5, 0x09, 0xdf, 0xbb, 0x38, 0xe9, 0x96, 0x52, 0x9d,
|
||||
0x54, 0x4a, 0xfa, 0x2b, 0xb0, 0x4c, 0xa8, 0xdf, 0x6f, 0xd3, 0xbe, 0x8f, 0xed, 0xd8, 0x83, 0xc5,
|
||||
0x71, 0x9e, 0x4f, 0xaa, 0xc3, 0x41, 0x7d, 0xb9, 0x95, 0xb2, 0x8f, 0x52, 0xb1, 0x92, 0x9d, 0x33,
|
||||
0x21, 0x9f, 0xe6, 0xce, 0x99, 0x64, 0x75, 0x32, 0xef, 0xab, 0x9d, 0x73, 0xdc, 0x6b, 0x9f, 0x85,
|
||||
0xce, 0x79, 0x4c, 0x94, 0x8d, 0xed, 0x9c, 0x69, 0xca, 0xbb, 0x95, 0xa8, 0x6a, 0x87, 0x94, 0xcd,
|
||||
0xe4, 0xf3, 0x54, 0xae, 0x87, 0xab, 0x37, 0x61, 0xe6, 0x0e, 0xbf, 0x7e, 0x9f, 0xb0, 0xef, 0x0e,
|
||||
0x14, 0x15, 0x77, 0xf6, 0xe6, 0x82, 0x64, 0x35, 0x23, 0xbe, 0x09, 0x0a, 0xa8, 0x25, 0x3b, 0xed,
|
||||
0xb8, 0x55, 0x3e, 0xcd, 0x9d, 0x76, 0x5c, 0xce, 0x8c, 0xf8, 0xfc, 0xb3, 0xda, 0x69, 0xa7, 0xfa,
|
||||
0xfb, 0xe8, 0x3b, 0x6d, 0x36, 0x79, 0xb1, 0xbf, 0xa4, 0x67, 0xb5, 0x83, 0x09, 0x3d, 0x9c, 0xbc,
|
||||
0x6e, 0x04, 0x1b, 0x28, 0x82, 0x31, 0x3e, 0xd0, 0xa0, 0xa2, 0xba, 0x73, 0xaa, 0x46, 0xef, 0xa1,
|
||||
0x06, 0xa7, 0x7c, 0x85, 0x4c, 0xfc, 0xfd, 0xf8, 0x42, 0x9e, 0x70, 0x12, 0x97, 0xc7, 0x4f, 0x49,
|
||||
0x86, 0xa7, 0x52, 0x36, 0x51, 0x1a, 0x2b, 0xe3, 0x07, 0x1a, 0xa4, 0x01, 0xeb, 0x6e, 0xc6, 0xfb,
|
||||
0xc0, 0x66, 0x9e, 0xf7, 0x01, 0x19, 0xe9, 0x93, 0x3c, 0x0e, 0xfc, 0x33, 0x66, 0x51, 0xf1, 0x7b,
|
||||
0x89, 0xa9, 0x2c, 0xba, 0x0e, 0x25, 0x7e, 0x2c, 0x12, 0xd1, 0xb0, 0x65, 0x51, 0x0b, 0xf1, 0x1d,
|
||||
0xdd, 0x87, 0x4a, 0x54, 0x00, 0xd8, 0x3a, 0x2f, 0x18, 0x87, 0x5e, 0xf9, 0x46, 0xa5, 0x24, 0xf1,
|
||||
0xf3, 0x0f, 0xae, 0x5c, 0x4b, 0xa1, 0x88, 0x12, 0x1c, 0x8c, 0x9f, 0x14, 0x60, 0x21, 0xf1, 0x6a,
|
||||
0x9d, 0xfa, 0xd6, 0xae, 0x7d, 0xd2, 0x6f, 0xed, 0xdf, 0xd7, 0x60, 0xd9, 0x57, 0x05, 0x89, 0x47,
|
||||
0xdc, 0x66, 0xae, 0x87, 0x77, 0x11, 0x72, 0x6b, 0x92, 0xfd, 0x72, 0xda, 0x2e, 0x4a, 0xe5, 0x66,
|
||||
0xfc, 0x48, 0x83, 0x54, 0x70, 0xdd, 0xcb, 0x88, 0xba, 0x8b, 0xf9, 0x5e, 0xa5, 0xc4, 0xef, 0x02,
|
||||
0x26, 0x09, 0xbb, 0x3f, 0x14, 0xa1, 0x9a, 0xe5, 0x5a, 0xfd, 0x7b, 0x1a, 0xac, 0x08, 0x13, 0x26,
|
||||
0x72, 0xd5, 0x74, 0x8e, 0x0a, 0x47, 0x9c, 0x5b, 0x69, 0x34, 0x51, 0x3a, 0x2b, 0x55, 0x88, 0xf8,
|
||||
0xbc, 0x3b, 0xdd, 0x2f, 0x33, 0x46, 0x85, 0x50, 0x66, 0xe8, 0x74, 0x56, 0xca, 0x13, 0x5a, 0xe9,
|
||||
0xd0, 0x27, 0xb4, 0x6f, 0xc3, 0x8c, 0xcf, 0xa7, 0x50, 0xd6, 0x8c, 0x4d, 0xf0, 0x34, 0x9a, 0xfe,
|
||||
0x53, 0x9f, 0xa8, 0x40, 0x8a, 0x6f, 0x82, 0x02, 0xaa, 0xc6, 0xef, 0x34, 0x18, 0x89, 0xf6, 0xa9,
|
||||
0xd2, 0x85, 0x05, 0xd0, 0xfb, 0x1f, 0x0d, 0x1a, 0xb2, 0x88, 0x59, 0x31, 0x46, 0xd4, 0x34, 0x1f,
|
||||
0x3d, 0xa9, 0x1d, 0x7b, 0xfc, 0xa4, 0x76, 0xec, 0xa3, 0x27, 0xb5, 0x63, 0x0f, 0x87, 0x35, 0xed,
|
||||
0xd1, 0xb0, 0xa6, 0x3d, 0x1e, 0xd6, 0xb4, 0x8f, 0x86, 0x35, 0xed, 0x5f, 0xc3, 0x9a, 0xf6, 0xde,
|
||||
0xbf, 0x6b, 0xc7, 0xde, 0x5e, 0x1b, 0xf7, 0xa3, 0xc0, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x15,
|
||||
0x38, 0x05, 0x05, 0x33, 0x28, 0x00, 0x00,
|
||||
// 2257 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x3a, 0xcd, 0x6f, 0x1b, 0xc7,
|
||||
0xf5, 0x5e, 0x92, 0xb6, 0xa8, 0x27, 0x8b, 0x92, 0xd6, 0x92, 0x4d, 0x3b, 0x0a, 0xa9, 0x2c, 0x7e,
|
||||
0x3f, 0x54, 0x68, 0x6d, 0x32, 0x96, 0x13, 0xc7, 0x48, 0xd3, 0x02, 0x5e, 0x2b, 0x76, 0x85, 0x26,
|
||||
0x8e, 0x32, 0x8c, 0x95, 0x38, 0xfd, 0xca, 0x8a, 0x3b, 0x96, 0xb6, 0x26, 0x77, 0xe9, 0x9d, 0xa1,
|
||||
0x62, 0xa3, 0x17, 0xa3, 0xe8, 0xd7, 0xa5, 0x40, 0x8a, 0x16, 0x45, 0x7b, 0xea, 0xa9, 0x28, 0x7a,
|
||||
0xe9, 0xa5, 0xfd, 0x0f, 0x82, 0x36, 0x06, 0x7a, 0x71, 0xd0, 0x02, 0x0d, 0x7a, 0x20, 0x6a, 0xf6,
|
||||
0xd8, 0x63, 0x6f, 0x39, 0x15, 0xf3, 0xb1, 0x1f, 0xb3, 0xdc, 0xa5, 0xb8, 0x6c, 0x23, 0x24, 0x27,
|
||||
0x72, 0x66, 0xde, 0xf7, 0x7b, 0xf3, 0xde, 0x9b, 0x99, 0x85, 0xf3, 0x77, 0xaf, 0x90, 0x86, 0xe3,
|
||||
0x35, 0xad, 0x9e, 0xd3, 0xf4, 0x31, 0xf1, 0xfa, 0x7e, 0x1b, 0x37, 0x0f, 0x2e, 0x5a, 0x9d, 0xde,
|
||||
0xbe, 0xb5, 0xd1, 0xdc, 0xc3, 0x2e, 0xf6, 0x2d, 0x8a, 0xed, 0x46, 0xcf, 0xf7, 0xa8, 0xa7, 0xaf,
|
||||
0x0a, 0xe8, 0x86, 0xd5, 0x73, 0x1a, 0x01, 0x74, 0x23, 0x80, 0x3e, 0x77, 0x61, 0xcf, 0xa1, 0xfb,
|
||||
0xfd, 0xdd, 0x46, 0xdb, 0xeb, 0x36, 0xf7, 0xbc, 0x3d, 0xaf, 0xc9, 0x91, 0x76, 0xfb, 0x77, 0xf8,
|
||||
0x88, 0x0f, 0xf8, 0x3f, 0x41, 0xec, 0x9c, 0x11, 0x63, 0xdd, 0xf6, 0x7c, 0xc6, 0x36, 0xc9, 0xf0,
|
||||
0xdc, 0x73, 0x11, 0x4c, 0xd7, 0x6a, 0xef, 0x3b, 0x2e, 0xf6, 0x1f, 0x34, 0x7b, 0x77, 0xf7, 0x54,
|
||||
0x79, 0xf3, 0x60, 0x91, 0x66, 0x17, 0x53, 0x2b, 0x8d, 0x57, 0x33, 0x0b, 0xcb, 0xef, 0xbb, 0xd4,
|
||||
0xe9, 0x8e, 0xb2, 0xb9, 0x7c, 0x18, 0x02, 0x69, 0xef, 0xe3, 0xae, 0x95, 0xc4, 0x33, 0x7e, 0x51,
|
||||
0x80, 0xc5, 0xab, 0x9d, 0x8e, 0xd7, 0xb6, 0xa8, 0xe3, 0xb9, 0x08, 0x93, 0x7e, 0x87, 0xea, 0x1e,
|
||||
0x2c, 0x04, 0xfa, 0x7c, 0xc5, 0x72, 0xed, 0x0e, 0x26, 0x55, 0x6d, 0xad, 0xb8, 0x3e, 0xb7, 0x71,
|
||||
0xbe, 0x31, 0xce, 0xe8, 0x0d, 0xa4, 0x20, 0x99, 0x67, 0x1e, 0x0d, 0xea, 0xc7, 0x86, 0x83, 0xfa,
|
||||
0x82, 0x3a, 0x4f, 0x50, 0x92, 0xba, 0xbe, 0x0b, 0x8b, 0xd6, 0x81, 0xe5, 0x74, 0xac, 0xdd, 0x0e,
|
||||
0x7e, 0xcd, 0xbd, 0xe9, 0xd9, 0x98, 0x54, 0x0b, 0x6b, 0xda, 0xfa, 0xdc, 0xc6, 0x5a, 0x9c, 0x23,
|
||||
0xf3, 0x4c, 0xe3, 0xe0, 0x62, 0x83, 0x01, 0xb4, 0x70, 0x07, 0xb7, 0xa9, 0xe7, 0x9b, 0xcb, 0xc3,
|
||||
0x41, 0x7d, 0xf1, 0x6a, 0x02, 0x1b, 0x8d, 0xd0, 0xd3, 0x9b, 0x30, 0x4b, 0xf6, 0x2d, 0x1f, 0xb3,
|
||||
0xb9, 0x6a, 0x71, 0x4d, 0x5b, 0x2f, 0x9b, 0x4b, 0x52, 0xc0, 0xd9, 0x56, 0xb0, 0x80, 0x22, 0x18,
|
||||
0xe3, 0x27, 0x1a, 0xac, 0x24, 0x4d, 0xf3, 0xaa, 0x67, 0xe3, 0x8e, 0x7e, 0x1f, 0x2a, 0xae, 0xd5,
|
||||
0xc5, 0x76, 0xa0, 0x17, 0x33, 0x0f, 0x13, 0xf6, 0xa5, 0xf1, 0xe6, 0xb9, 0xa9, 0xe0, 0x24, 0x49,
|
||||
0x9b, 0xfa, 0x70, 0x50, 0xaf, 0xa8, 0x30, 0x28, 0xc1, 0xc7, 0xf8, 0x5d, 0x01, 0x4e, 0x6f, 0xfa,
|
||||
0xce, 0x01, 0xf6, 0x47, 0x9c, 0xf6, 0x23, 0x0d, 0xce, 0x1c, 0x60, 0xd7, 0xf6, 0x7c, 0x84, 0xef,
|
||||
0xf5, 0x31, 0xa1, 0xdb, 0x96, 0x6f, 0x75, 0x31, 0xc5, 0x7e, 0x20, 0xde, 0x85, 0x98, 0x78, 0x61,
|
||||
0x90, 0x34, 0x7a, 0x77, 0xf7, 0x1a, 0x32, 0x48, 0x1a, 0xc8, 0x7a, 0xf7, 0xe5, 0xfb, 0x14, 0xbb,
|
||||
0xc4, 0xf1, 0x5c, 0xb3, 0x2e, 0xad, 0x73, 0x66, 0x27, 0x9d, 0x2a, 0xca, 0x62, 0xc7, 0x44, 0x59,
|
||||
0xb1, 0xd2, 0x2c, 0x27, 0x9d, 0x7a, 0x69, 0xbc, 0x9d, 0x52, 0x8d, 0x6e, 0x3e, 0x2d, 0xc5, 0x49,
|
||||
0xf7, 0x09, 0x4a, 0x67, 0x68, 0xfc, 0xbc, 0x00, 0x15, 0x61, 0x30, 0x29, 0x26, 0xd1, 0x37, 0x00,
|
||||
0x6c, 0x3e, 0xc3, 0x6c, 0xcd, 0x4d, 0x33, 0x6b, 0xea, 0x92, 0x38, 0x6c, 0x86, 0x2b, 0x28, 0x06,
|
||||
0xa5, 0x13, 0x58, 0x14, 0xca, 0xc6, 0x8c, 0x5a, 0x98, 0xc6, 0xa8, 0x55, 0xc9, 0x68, 0x71, 0x27,
|
||||
0x41, 0x0e, 0x8d, 0x30, 0xd0, 0xbf, 0x06, 0x65, 0x5f, 0x0a, 0x5d, 0x2d, 0xf2, 0xfd, 0x77, 0x61,
|
||||
0xb2, 0xfd, 0x27, 0x55, 0x35, 0x17, 0x25, 0xb3, 0x72, 0xa0, 0x3b, 0x0a, 0x09, 0x1a, 0x26, 0xd4,
|
||||
0xc6, 0xc7, 0xa3, 0xbe, 0x06, 0x25, 0x37, 0xb2, 0xd0, 0x49, 0x49, 0xab, 0xc4, 0x6d, 0xc3, 0x57,
|
||||
0x8c, 0x3f, 0x69, 0x70, 0x26, 0x41, 0x84, 0x52, 0xdf, 0xd9, 0xed, 0x53, 0x7c, 0x38, 0x36, 0x8b,
|
||||
0x92, 0x8a, 0x15, 0xc0, 0xef, 0x58, 0x9d, 0x3e, 0x96, 0x26, 0x7d, 0x31, 0xd7, 0x36, 0x52, 0x28,
|
||||
0x98, 0xff, 0x27, 0x19, 0xad, 0x8e, 0x83, 0x42, 0x09, 0xbe, 0xc6, 0xbf, 0x8a, 0x30, 0x16, 0x41,
|
||||
0xff, 0x06, 0x94, 0xef, 0xf5, 0x2d, 0x97, 0x3a, 0xf4, 0x41, 0xf5, 0x04, 0x17, 0xb2, 0x91, 0xe9,
|
||||
0x77, 0x45, 0xea, 0xd7, 0x25, 0x96, 0xb9, 0x34, 0x1c, 0xd4, 0xe7, 0x83, 0x91, 0x90, 0x22, 0x24,
|
||||
0xa9, 0x3f, 0x03, 0xa5, 0x5d, 0xcf, 0x13, 0xdb, 0xa3, 0x6c, 0xce, 0xb3, 0x94, 0x64, 0x7a, 0x5e,
|
||||
0x47, 0x80, 0xf1, 0x25, 0xbd, 0x06, 0x45, 0xc7, 0xa5, 0xd5, 0x99, 0x35, 0x6d, 0xbd, 0x68, 0x9e,
|
||||
0x64, 0x4e, 0xdd, 0x72, 0xa9, 0x00, 0x60, 0x0b, 0x7a, 0x1b, 0xca, 0x8e, 0x4b, 0x5b, 0x1d, 0xa7,
|
||||
0x8d, 0xab, 0x65, 0x2e, 0xe1, 0x73, 0x79, 0xcc, 0xb8, 0x25, 0x71, 0x85, 0x9c, 0xc1, 0x48, 0xca,
|
||||
0x19, 0x10, 0xd6, 0x3f, 0x07, 0x27, 0x08, 0xf5, 0x1d, 0x77, 0xaf, 0x7a, 0x9c, 0xbb, 0x75, 0x61,
|
||||
0x38, 0xa8, 0xcf, 0xb5, 0xf8, 0x8c, 0x00, 0x95, 0xcb, 0xba, 0x07, 0x73, 0xe2, 0x9f, 0x10, 0x68,
|
||||
0x96, 0x0b, 0xf4, 0x42, 0x1e, 0x81, 0x5a, 0x11, 0xba, 0x48, 0xf1, 0xb1, 0x09, 0xc1, 0x2b, 0xce,
|
||||
0x41, 0xff, 0x3c, 0xcc, 0x1c, 0x60, 0x9f, 0x6d, 0xb1, 0x2a, 0x70, 0xd1, 0x16, 0x87, 0x83, 0xfa,
|
||||
0xc9, 0x1d, 0x31, 0x25, 0xe0, 0x03, 0x00, 0x63, 0x13, 0x96, 0x55, 0x5e, 0xd7, 0x9d, 0x0e, 0xc5,
|
||||
0xbe, 0x7e, 0x1e, 0xca, 0x44, 0x56, 0x15, 0x19, 0xb6, 0xe1, 0x06, 0x0a, 0xaa, 0x0d, 0x0a, 0x21,
|
||||
0x8c, 0x5f, 0x6b, 0x70, 0x3a, 0x69, 0x43, 0x42, 0x2d, 0xb7, 0x3d, 0x49, 0xec, 0x3b, 0x00, 0x61,
|
||||
0x08, 0xb2, 0x4c, 0xc2, 0x36, 0xf7, 0xf3, 0x53, 0x85, 0x7d, 0x94, 0xba, 0xc2, 0x29, 0x82, 0x62,
|
||||
0xc4, 0x8d, 0xcb, 0xa3, 0x62, 0x4a, 0x6f, 0xae, 0x42, 0xc9, 0x71, 0xa9, 0xa8, 0xed, 0x45, 0xb3,
|
||||
0xcc, 0x44, 0xdc, 0x72, 0x29, 0x41, 0x7c, 0xd6, 0x78, 0x19, 0x56, 0x12, 0xc5, 0x48, 0xa4, 0x8e,
|
||||
0x9c, 0x66, 0x7a, 0x38, 0x92, 0x23, 0xc2, 0x3f, 0x3a, 0x86, 0x59, 0x47, 0xda, 0x2c, 0xe8, 0x30,
|
||||
0x72, 0x06, 0xad, 0x40, 0x8e, 0x0a, 0x79, 0x30, 0x43, 0x50, 0x44, 0xd9, 0x30, 0xe1, 0x6c, 0x66,
|
||||
0x6c, 0xe9, 0xff, 0x0f, 0x33, 0x22, 0x8e, 0x84, 0x04, 0xb3, 0xe6, 0xdc, 0x70, 0x50, 0x9f, 0x11,
|
||||
0x10, 0x04, 0x05, 0x6b, 0xc6, 0x0f, 0x34, 0x58, 0x62, 0x7d, 0x44, 0x40, 0x43, 0x34, 0x02, 0xf7,
|
||||
0x32, 0x1a, 0x81, 0x5c, 0xae, 0x0c, 0xff, 0x4c, 0xd4, 0x01, 0x7c, 0x58, 0x50, 0x05, 0x11, 0x5a,
|
||||
0xbc, 0x03, 0x65, 0xd6, 0x4a, 0xda, 0x16, 0xb5, 0xa4, 0x08, 0xcf, 0x8e, 0xcb, 0x4f, 0xa4, 0xc1,
|
||||
0xa0, 0x59, 0x2b, 0xf5, 0xda, 0xee, 0xb7, 0x71, 0x9b, 0xbe, 0x8a, 0xa9, 0x15, 0x05, 0x52, 0x34,
|
||||
0x87, 0x42, 0xaa, 0xcc, 0xeb, 0xae, 0x67, 0x63, 0x5e, 0x33, 0x0b, 0xaa, 0xd7, 0x6f, 0xca, 0x79,
|
||||
0x14, 0x42, 0x24, 0x6a, 0x6c, 0x71, 0xa2, 0x1a, 0x7b, 0x1f, 0x96, 0xdc, 0xa4, 0x85, 0xab, 0x25,
|
||||
0xae, 0x4c, 0xf3, 0x10, 0x7b, 0x26, 0xd1, 0xcc, 0xb3, 0x92, 0xd7, 0xa8, 0xcf, 0xd0, 0x28, 0x13,
|
||||
0xe3, 0xcf, 0x1a, 0xac, 0x8c, 0xd8, 0xf4, 0x15, 0x87, 0x50, 0xfd, 0xeb, 0x23, 0x76, 0x6d, 0x4c,
|
||||
0x66, 0x57, 0x86, 0xcd, 0xad, 0x1a, 0x5a, 0x29, 0x98, 0x89, 0xd9, 0xf4, 0x0d, 0x38, 0xee, 0x50,
|
||||
0xdc, 0x0d, 0x12, 0x40, 0x0e, 0x2d, 0x45, 0x5e, 0x9c, 0x97, 0xb4, 0x8f, 0x6f, 0x31, 0x2a, 0x48,
|
||||
0x10, 0x33, 0xfe, 0x50, 0x80, 0xe5, 0x6d, 0xcf, 0x6e, 0xb5, 0xf7, 0xb1, 0xdd, 0xef, 0x38, 0xee,
|
||||
0xde, 0x35, 0xcf, 0xa5, 0xf8, 0x3e, 0x3d, 0x82, 0x20, 0x79, 0x0b, 0x4a, 0xa4, 0x87, 0xdb, 0xb2,
|
||||
0x8e, 0x5f, 0x1e, 0xaf, 0x4f, 0x9a, 0x8c, 0xad, 0x1e, 0x6e, 0x47, 0x09, 0x93, 0x8d, 0x10, 0xa7,
|
||||
0xa8, 0xbf, 0xc3, 0x2a, 0x8f, 0x45, 0xfb, 0x84, 0x07, 0xd3, 0xdc, 0xc6, 0x95, 0x29, 0x68, 0x73,
|
||||
0x7c, 0xb3, 0x22, 0xa9, 0x9f, 0x10, 0x63, 0x24, 0xe9, 0x1a, 0x1f, 0x6a, 0x50, 0x4d, 0x43, 0x3b,
|
||||
0x82, 0x38, 0x78, 0x53, 0x8d, 0x83, 0x8d, 0xfc, 0xba, 0x65, 0x84, 0xc2, 0x7b, 0x19, 0x3a, 0x31,
|
||||
0xc3, 0xea, 0x57, 0xe0, 0xa4, 0xc8, 0xd2, 0xd8, 0x66, 0xa1, 0x25, 0x73, 0xf9, 0xb2, 0x24, 0x74,
|
||||
0xb2, 0x15, 0x5b, 0x43, 0x0a, 0xa4, 0xfe, 0x22, 0x54, 0x7a, 0x1e, 0xc5, 0x2e, 0x75, 0xac, 0x4e,
|
||||
0x70, 0x58, 0x63, 0xa9, 0x93, 0xe7, 0xaf, 0x6d, 0x65, 0x05, 0x25, 0x20, 0x8d, 0x5f, 0x6a, 0x70,
|
||||
0x2e, 0xdb, 0x3b, 0xfa, 0x77, 0xa0, 0x12, 0x68, 0x7c, 0xad, 0x63, 0x39, 0xdd, 0xa0, 0x2e, 0x7c,
|
||||
0x71, 0xb2, 0xce, 0x97, 0xe3, 0x44, 0xb4, 0xa5, 0xcb, 0x4f, 0x4b, 0x9d, 0x2a, 0x0a, 0x18, 0x41,
|
||||
0x09, 0x56, 0xc6, 0xaf, 0x0a, 0x30, 0xaf, 0x80, 0x1c, 0xc1, 0x96, 0x79, 0x5d, 0xd9, 0x32, 0xcd,
|
||||
0x3c, 0x6a, 0x66, 0xed, 0x95, 0xdb, 0x89, 0xbd, 0x72, 0x31, 0x0f, 0xd1, 0xf1, 0x9b, 0x64, 0xa8,
|
||||
0x41, 0x4d, 0x81, 0xbf, 0xe6, 0xb9, 0xa4, 0xdf, 0x65, 0xa7, 0xab, 0x3b, 0xd8, 0xc7, 0xac, 0xf9,
|
||||
0x39, 0x0f, 0x65, 0xab, 0xe7, 0xdc, 0xf0, 0xbd, 0x7e, 0x2f, 0xd9, 0x1e, 0x5c, 0xdd, 0xde, 0xe2,
|
||||
0xf3, 0x28, 0x84, 0x60, 0xd0, 0x81, 0x44, 0xb2, 0x4c, 0xc4, 0x0e, 0x2d, 0xf2, 0x34, 0x13, 0x42,
|
||||
0x84, 0x8d, 0x55, 0x29, 0xb3, 0xb1, 0x32, 0xa1, 0xd8, 0x77, 0x6c, 0xd9, 0x9e, 0x3e, 0x2b, 0x01,
|
||||
0x8a, 0xb7, 0xb6, 0x36, 0x3f, 0x1e, 0xd4, 0x9f, 0xc9, 0xba, 0x23, 0xa1, 0x0f, 0x7a, 0x98, 0x34,
|
||||
0x6e, 0x6d, 0x6d, 0x22, 0x86, 0x6c, 0xbc, 0xaf, 0xc1, 0x92, 0xa2, 0xe4, 0x11, 0xa4, 0x80, 0x6d,
|
||||
0x35, 0x05, 0x7c, 0x21, 0x87, 0xcb, 0x32, 0xf6, 0xfe, 0x4f, 0x8b, 0x70, 0x46, 0x81, 0x8b, 0x9d,
|
||||
0x2c, 0x3f, 0xf9, 0xb0, 0x7e, 0x17, 0xe6, 0xc3, 0xab, 0xa6, 0xeb, 0xbe, 0xd7, 0x95, 0xf1, 0xfd,
|
||||
0xe5, 0x1c, 0x7a, 0xc5, 0xce, 0xc6, 0x41, 0x70, 0x89, 0xd3, 0xc9, 0x8d, 0x38, 0x61, 0xa4, 0xf2,
|
||||
0xc9, 0x7d, 0xcd, 0xa3, 0x77, 0xa0, 0x62, 0x2b, 0x17, 0x04, 0xd5, 0xd2, 0x24, 0x77, 0x5d, 0xea,
|
||||
0xa5, 0x42, 0x94, 0x62, 0xd4, 0x79, 0x94, 0xa0, 0x6d, 0xfc, 0x4d, 0x83, 0xa7, 0x32, 0xb4, 0x3c,
|
||||
0x82, 0x28, 0x7b, 0x5b, 0x8d, 0xb2, 0xe7, 0xa7, 0xf2, 0x46, 0x46, 0xbc, 0xfd, 0x4c, 0x83, 0xb5,
|
||||
0xc3, 0xfc, 0x97, 0x33, 0x39, 0xac, 0x41, 0xe9, 0xae, 0xe3, 0xda, 0xb2, 0xdf, 0x0c, 0xb7, 0xfb,
|
||||
0x57, 0x1d, 0xd7, 0x46, 0x7c, 0x25, 0x4c, 0x08, 0xc5, 0xcc, 0x3b, 0x8a, 0x87, 0x1a, 0x3c, 0x3d,
|
||||
0xb6, 0x3a, 0x4c, 0x70, 0x5a, 0xfb, 0x12, 0x2c, 0xf4, 0x5d, 0xd2, 0x77, 0x28, 0x0b, 0x98, 0x78,
|
||||
0xc1, 0x3b, 0x35, 0x1c, 0xd4, 0x17, 0x6e, 0xa9, 0x4b, 0x28, 0x09, 0x6b, 0xfc, 0xa6, 0x90, 0xc8,
|
||||
0x27, 0xbc, 0xfc, 0xde, 0x80, 0xa5, 0x58, 0xf9, 0x21, 0x24, 0x76, 0x1b, 0x15, 0x76, 0xaf, 0x28,
|
||||
0x09, 0x80, 0x46, 0x71, 0xd8, 0x56, 0xeb, 0xc5, 0x4d, 0xfd, 0xbf, 0xdc, 0x6a, 0xca, 0x02, 0x52,
|
||||
0xf9, 0xe8, 0xdb, 0x50, 0x89, 0x2e, 0xdd, 0x58, 0x27, 0x2d, 0xdd, 0xb0, 0x1e, 0xec, 0x85, 0xab,
|
||||
0xca, 0xea, 0xc7, 0x23, 0x33, 0x28, 0x81, 0x6f, 0xfc, 0xbb, 0x00, 0xa7, 0x52, 0xca, 0xd1, 0x54,
|
||||
0x57, 0x76, 0xdf, 0x04, 0x88, 0xa8, 0x4b, 0x9b, 0x34, 0xf2, 0x5d, 0x3c, 0x9a, 0x15, 0x7e, 0xae,
|
||||
0x8e, 0x66, 0x63, 0x14, 0x75, 0x02, 0x73, 0x3e, 0x26, 0xd8, 0x3f, 0xc0, 0xf6, 0x75, 0xcf, 0x97,
|
||||
0x17, 0x74, 0x2f, 0xe5, 0x30, 0xfa, 0x48, 0xe9, 0x34, 0x4f, 0x49, 0x95, 0xe6, 0x50, 0x44, 0x18,
|
||||
0xc5, 0xb9, 0xe8, 0x2d, 0x58, 0xb1, 0x71, 0xfc, 0xa6, 0x93, 0xa7, 0x15, 0x6c, 0xf3, 0x8a, 0x58,
|
||||
0x8e, 0xee, 0x48, 0x37, 0xd3, 0x80, 0x50, 0x3a, 0xae, 0xf1, 0x57, 0x0d, 0x56, 0x14, 0xc9, 0xde,
|
||||
0xc0, 0xdd, 0x5e, 0xc7, 0xa2, 0x47, 0x71, 0xac, 0xbc, 0xad, 0xb4, 0x3f, 0x2f, 0xe4, 0x30, 0x5f,
|
||||
0x20, 0x64, 0x56, 0x1b, 0x64, 0xfc, 0x45, 0x83, 0xb3, 0xa9, 0x18, 0x47, 0x90, 0x68, 0xdf, 0x52,
|
||||
0x13, 0xed, 0xa5, 0x29, 0xf4, 0xca, 0x48, 0xb3, 0x8f, 0xb3, 0xb4, 0x6a, 0x89, 0x63, 0xd2, 0x67,
|
||||
0xaf, 0x5f, 0x35, 0x3e, 0x28, 0x2a, 0x6d, 0x37, 0x39, 0x8a, 0xfe, 0x44, 0xcd, 0x28, 0x85, 0x89,
|
||||
0x32, 0xca, 0x48, 0xa2, 0x2d, 0xe6, 0x4c, 0xb4, 0x84, 0x4c, 0x97, 0x68, 0x6f, 0xc3, 0xbc, 0x5a,
|
||||
0x7d, 0x4a, 0x13, 0xbe, 0x8d, 0x71, 0xd2, 0x2d, 0xa5, 0x3a, 0xa9, 0x94, 0xf4, 0x57, 0x60, 0x99,
|
||||
0x50, 0xbf, 0xdf, 0xa6, 0x7d, 0x1f, 0xdb, 0xb1, 0xc7, 0x8d, 0xe3, 0x3c, 0x9f, 0x54, 0x87, 0x83,
|
||||
0xfa, 0x72, 0x2b, 0x65, 0x1d, 0xa5, 0x62, 0x25, 0x3b, 0x67, 0x42, 0x3e, 0xcd, 0x9d, 0x33, 0xc9,
|
||||
0xea, 0x64, 0xde, 0x57, 0x3b, 0xe7, 0xb8, 0xd7, 0x3e, 0x0b, 0x9d, 0xf3, 0x98, 0x28, 0x1b, 0xdb,
|
||||
0x39, 0xd3, 0x94, 0x37, 0x2e, 0x51, 0xd5, 0x0e, 0x29, 0x9b, 0xc9, 0xa7, 0xac, 0x5c, 0x8f, 0x5c,
|
||||
0x6f, 0xc2, 0xcc, 0x1d, 0x7e, 0xfd, 0x3e, 0x61, 0xdf, 0x1d, 0x28, 0x2a, 0xee, 0xec, 0xcd, 0x05,
|
||||
0xc9, 0x6a, 0x46, 0x8c, 0x09, 0x0a, 0xa8, 0x25, 0x3b, 0xed, 0xb8, 0x55, 0x3e, 0xcd, 0x9d, 0x76,
|
||||
0x5c, 0xce, 0x8c, 0xf8, 0xfc, 0xa3, 0xda, 0x69, 0xa7, 0xfa, 0xfb, 0xe8, 0x3b, 0x6d, 0x76, 0xf2,
|
||||
0x62, 0xbf, 0xa4, 0x67, 0xb5, 0x83, 0x13, 0x7a, 0x78, 0xf2, 0xba, 0x19, 0x2c, 0xa0, 0x08, 0xc6,
|
||||
0xf8, 0x40, 0x83, 0x8a, 0xea, 0xce, 0xa9, 0x1a, 0xbd, 0x87, 0x1a, 0x9c, 0xf2, 0x15, 0x32, 0xf1,
|
||||
0xb7, 0xe6, 0x8b, 0x79, 0xc2, 0x49, 0x5c, 0x1e, 0x3f, 0x25, 0x19, 0x9e, 0x4a, 0x59, 0x44, 0x69,
|
||||
0xac, 0x8c, 0xef, 0x6b, 0x90, 0x06, 0xac, 0xbb, 0x19, 0xef, 0x03, 0x1b, 0x79, 0xde, 0x07, 0x64,
|
||||
0xa4, 0x4f, 0xf2, 0x38, 0xf0, 0xf7, 0x98, 0x45, 0xc5, 0xb7, 0x15, 0x53, 0x59, 0x74, 0x0d, 0x4a,
|
||||
0x7c, 0x5b, 0x24, 0xa2, 0x61, 0xd3, 0xa2, 0x16, 0xe2, 0x2b, 0xba, 0x0f, 0x95, 0xa8, 0x00, 0xb0,
|
||||
0x79, 0x5e, 0x30, 0x0e, 0xbd, 0xf2, 0x8d, 0x4a, 0x49, 0xe2, 0x53, 0x11, 0xae, 0x5c, 0x4b, 0xa1,
|
||||
0x88, 0x12, 0x1c, 0x8c, 0x1f, 0x17, 0x60, 0x21, 0xf1, 0xc2, 0x9d, 0xfa, 0x2e, 0xaf, 0x7d, 0xd2,
|
||||
0xef, 0xf2, 0xdf, 0xd3, 0x60, 0xd9, 0x57, 0x05, 0x89, 0x47, 0xdc, 0x46, 0xae, 0x47, 0x7a, 0x11,
|
||||
0x72, 0xab, 0x92, 0xfd, 0x72, 0xda, 0x2a, 0x4a, 0xe5, 0x66, 0xfc, 0x50, 0x83, 0x54, 0x70, 0xdd,
|
||||
0xcb, 0x88, 0xba, 0x4b, 0xf9, 0x5e, 0xa5, 0xc4, 0x37, 0x04, 0x93, 0x84, 0xdd, 0xef, 0x8b, 0x50,
|
||||
0xcd, 0x72, 0xad, 0xfe, 0x5d, 0x0d, 0x56, 0x84, 0x09, 0x13, 0xb9, 0x6a, 0x3a, 0x47, 0x85, 0x47,
|
||||
0x9c, 0x9d, 0x34, 0x9a, 0x28, 0x9d, 0x95, 0x2a, 0x44, 0xfc, 0xbc, 0x3b, 0xdd, 0x57, 0x1c, 0xa3,
|
||||
0x42, 0x28, 0x67, 0xe8, 0x74, 0x56, 0xca, 0x13, 0x5a, 0xe9, 0xd0, 0x27, 0xb4, 0x6f, 0xc1, 0x8c,
|
||||
0xcf, 0x4f, 0xa1, 0xac, 0x19, 0x9b, 0xe0, 0x69, 0x34, 0xfd, 0xb3, 0xa0, 0xa8, 0x40, 0x8a, 0x31,
|
||||
0x41, 0x01, 0x55, 0xe3, 0xb7, 0x1a, 0x8c, 0x44, 0xfb, 0x54, 0xe9, 0xc2, 0x02, 0xe8, 0xfd, 0x97,
|
||||
0x06, 0x0d, 0x59, 0xc4, 0xac, 0x18, 0x23, 0x6a, 0x9a, 0x8f, 0x9e, 0xd4, 0x8e, 0x3d, 0x7e, 0x52,
|
||||
0x3b, 0xf6, 0xd1, 0x93, 0xda, 0xb1, 0x87, 0xc3, 0x9a, 0xf6, 0x68, 0x58, 0xd3, 0x1e, 0x0f, 0x6b,
|
||||
0xda, 0x47, 0xc3, 0x9a, 0xf6, 0x8f, 0x61, 0x4d, 0x7b, 0xef, 0x9f, 0xb5, 0x63, 0x6f, 0xaf, 0x8e,
|
||||
0xfb, 0x80, 0xf0, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x03, 0x20, 0x09, 0x51, 0x5f, 0x28, 0x00,
|
||||
0x00,
|
||||
}
|
||||
|
||||
func (m *AllocationResult) Marshal() (dAtA []byte, err error) {
|
||||
@ -1747,6 +1749,13 @@ func (m *NamedResourcesAttributeValue) MarshalToSizedBuffer(dAtA []byte) (int, e
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if m.VersionValue != nil {
|
||||
i -= len(*m.VersionValue)
|
||||
copy(dAtA[i:], *m.VersionValue)
|
||||
i = encodeVarintGenerated(dAtA, i, uint64(len(*m.VersionValue)))
|
||||
i--
|
||||
dAtA[i] = 0x52
|
||||
}
|
||||
if m.StringSliceValue != nil {
|
||||
{
|
||||
size, err := m.StringSliceValue.MarshalToSizedBuffer(dAtA[:i])
|
||||
@ -3592,6 +3601,10 @@ func (m *NamedResourcesAttributeValue) Size() (n int) {
|
||||
l = m.StringSliceValue.Size()
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
if m.VersionValue != nil {
|
||||
l = len(*m.VersionValue)
|
||||
n += 1 + l + sovGenerated(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
@ -4289,6 +4302,7 @@ func (this *NamedResourcesAttributeValue) String() string {
|
||||
`IntValue:` + valueToStringGenerated(this.IntValue) + `,`,
|
||||
`IntSliceValue:` + strings.Replace(this.IntSliceValue.String(), "NamedResourcesIntSlice", "NamedResourcesIntSlice", 1) + `,`,
|
||||
`StringSliceValue:` + strings.Replace(this.StringSliceValue.String(), "NamedResourcesStringSlice", "NamedResourcesStringSlice", 1) + `,`,
|
||||
`VersionValue:` + valueToStringGenerated(this.VersionValue) + `,`,
|
||||
`}`,
|
||||
}, "")
|
||||
return s
|
||||
@ -5695,6 +5709,39 @@ func (m *NamedResourcesAttributeValue) Unmarshal(dAtA []byte) error {
|
||||
return err
|
||||
}
|
||||
iNdEx = postIndex
|
||||
case 10:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field VersionValue", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowGenerated
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthGenerated
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
s := string(dAtA[iNdEx:postIndex])
|
||||
m.VersionValue = &s
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipGenerated(dAtA[iNdEx:])
|
||||
|
@ -134,6 +134,9 @@ message NamedResourcesAttributeValue {
|
||||
|
||||
// StringSliceValue is an array of strings.
|
||||
optional NamedResourcesStringSlice stringSlice = 9;
|
||||
|
||||
// VersionValue is a semantic version according to semver.org spec 2.0.0.
|
||||
optional string version = 10;
|
||||
}
|
||||
|
||||
// NamedResourcesFilter is used in ResourceFilterModel.
|
||||
|
@ -70,7 +70,8 @@ type NamedResourcesAttributeValue struct {
|
||||
StringValue *string `json:"string,omitempty" protobuf:"bytes,5,opt,name=string"`
|
||||
// StringSliceValue is an array of strings.
|
||||
StringSliceValue *NamedResourcesStringSlice `json:"stringSlice,omitempty" protobuf:"bytes,9,rep,name=stringSlice"`
|
||||
// TODO: VersionValue *SemVersion `json:"version,omitempty" protobuf:"bytes,7,opt,name=version"`
|
||||
// VersionValue is a semantic version according to semver.org spec 2.0.0.
|
||||
VersionValue *string `json:"version,omitempty" protobuf:"bytes,10,opt,name=version"`
|
||||
}
|
||||
|
||||
// NamedResourcesIntSlice contains a slice of 64-bit integers.
|
||||
@ -89,17 +90,6 @@ type NamedResourcesStringSlice struct {
|
||||
Strings []string `json:"strings" protobuf:"bytes,1,opt,name=strings"`
|
||||
}
|
||||
|
||||
// TODO
|
||||
//
|
||||
// A wrapper around https://pkg.go.dev/github.com/blang/semver/v4#Version which
|
||||
// is encoded as a string. During decoding, it validates that the string
|
||||
// can be parsed using tolerant parsing (currently trims spaces, removes a "v" prefix,
|
||||
// adds a 0 patch number to versions with only major and minor components specified,
|
||||
// and removes leading 0s).
|
||||
// type NamedResourcesSemVersion struct {
|
||||
// semver.Version
|
||||
//}
|
||||
|
||||
// NamedResourcesRequest is used in ResourceRequestModel.
|
||||
type NamedResourcesRequest struct {
|
||||
// Selector is a CEL expression which must evaluate to true if a
|
||||
|
@ -183,6 +183,11 @@ func (in *NamedResourcesAttributeValue) DeepCopyInto(out *NamedResourcesAttribut
|
||||
*out = new(NamedResourcesStringSlice)
|
||||
(*in).DeepCopyInto(*out)
|
||||
}
|
||||
if in.VersionValue != nil {
|
||||
in, out := &in.VersionValue, &out.VersionValue
|
||||
*out = new(string)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,8 @@
|
||||
"strings": [
|
||||
"stringsValue"
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": "versionValue"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Binary file not shown.
@ -47,5 +47,6 @@ namedResources:
|
||||
stringSlice:
|
||||
strings:
|
||||
- stringsValue
|
||||
version: versionValue
|
||||
name: nameValue
|
||||
nodeName: nodeNameValue
|
||||
|
@ -12001,6 +12001,9 @@ var schemaYAML = typed.YAMLObject(`types:
|
||||
- name: stringSlice
|
||||
type:
|
||||
namedType: io.k8s.api.resource.v1alpha2.NamedResourcesStringSlice
|
||||
- name: version
|
||||
type:
|
||||
scalar: string
|
||||
- name: io.k8s.api.resource.v1alpha2.NamedResourcesFilter
|
||||
map:
|
||||
fields:
|
||||
|
@ -90,3 +90,11 @@ func (b *NamedResourcesAttributeApplyConfiguration) WithStringSliceValue(value *
|
||||
b.StringSliceValue = value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithVersionValue sets the VersionValue field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the VersionValue field is set to the value of the last call.
|
||||
func (b *NamedResourcesAttributeApplyConfiguration) WithVersionValue(value string) *NamedResourcesAttributeApplyConfiguration {
|
||||
b.VersionValue = &value
|
||||
return b
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ type NamedResourcesAttributeValueApplyConfiguration struct {
|
||||
IntSliceValue *NamedResourcesIntSliceApplyConfiguration `json:"intSlice,omitempty"`
|
||||
StringValue *string `json:"string,omitempty"`
|
||||
StringSliceValue *NamedResourcesStringSliceApplyConfiguration `json:"stringSlice,omitempty"`
|
||||
VersionValue *string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// NamedResourcesAttributeValueApplyConfiguration constructs an declarative configuration of the NamedResourcesAttributeValue type for use with
|
||||
@ -86,3 +87,11 @@ func (b *NamedResourcesAttributeValueApplyConfiguration) WithStringSliceValue(va
|
||||
b.StringSliceValue = value
|
||||
return b
|
||||
}
|
||||
|
||||
// WithVersionValue sets the VersionValue field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the VersionValue field is set to the value of the last call.
|
||||
func (b *NamedResourcesAttributeValueApplyConfiguration) WithVersionValue(value string) *NamedResourcesAttributeValueApplyConfiguration {
|
||||
b.VersionValue = &value
|
||||
return b
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ module k8s.io/dynamic-resource-allocation
|
||||
go 1.22.0
|
||||
|
||||
require (
|
||||
github.com/blang/semver/v4 v4.0.0
|
||||
github.com/go-logr/logr v1.4.1
|
||||
github.com/google/cel-go v0.17.8
|
||||
github.com/google/go-cmp v0.6.0
|
||||
|
@ -6,6 +6,7 @@ github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/g
|
||||
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
|
||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/blang/semver/v4"
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/traits"
|
||||
@ -105,43 +106,54 @@ var valueTypes = map[string]struct {
|
||||
celType *cel.Type
|
||||
// get returns nil if the attribute doesn't have the type, otherwise
|
||||
// the value of that type.
|
||||
get func(attr resourceapi.NamedResourcesAttribute) any
|
||||
get func(attr resourceapi.NamedResourcesAttribute) (any, error)
|
||||
}{
|
||||
"quantity": {apiservercel.QuantityType, func(attr resourceapi.NamedResourcesAttribute) any {
|
||||
"quantity": {apiservercel.QuantityType, func(attr resourceapi.NamedResourcesAttribute) (any, error) {
|
||||
if attr.QuantityValue == nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
return apiservercel.Quantity{Quantity: attr.QuantityValue}
|
||||
return apiservercel.Quantity{Quantity: attr.QuantityValue}, nil
|
||||
}},
|
||||
"bool": {cel.BoolType, func(attr resourceapi.NamedResourcesAttribute) any {
|
||||
"bool": {cel.BoolType, func(attr resourceapi.NamedResourcesAttribute) (any, error) {
|
||||
if attr.BoolValue == nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
return *attr.BoolValue
|
||||
return *attr.BoolValue, nil
|
||||
}},
|
||||
"int": {cel.IntType, func(attr resourceapi.NamedResourcesAttribute) any {
|
||||
"int": {cel.IntType, func(attr resourceapi.NamedResourcesAttribute) (any, error) {
|
||||
if attr.IntValue == nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
return *attr.IntValue
|
||||
return *attr.IntValue, nil
|
||||
}},
|
||||
"intslice": {types.NewListType(cel.IntType), func(attr resourceapi.NamedResourcesAttribute) any {
|
||||
"intslice": {types.NewListType(cel.IntType), func(attr resourceapi.NamedResourcesAttribute) (any, error) {
|
||||
if attr.IntSliceValue == nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
return attr.IntSliceValue.Ints
|
||||
return attr.IntSliceValue.Ints, nil
|
||||
}},
|
||||
"string": {cel.StringType, func(attr resourceapi.NamedResourcesAttribute) any {
|
||||
"string": {cel.StringType, func(attr resourceapi.NamedResourcesAttribute) (any, error) {
|
||||
if attr.StringValue == nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
return *attr.StringValue
|
||||
return *attr.StringValue, nil
|
||||
}},
|
||||
"stringslice": {types.NewListType(cel.StringType), func(attr resourceapi.NamedResourcesAttribute) any {
|
||||
"stringslice": {types.NewListType(cel.StringType), func(attr resourceapi.NamedResourcesAttribute) (any, error) {
|
||||
if attr.StringSliceValue == nil {
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
return attr.StringSliceValue.Strings
|
||||
return attr.StringSliceValue.Strings, nil
|
||||
}},
|
||||
"version": {SemverType, func(attr resourceapi.NamedResourcesAttribute) (any, error) {
|
||||
if attr.VersionValue == nil {
|
||||
return nil, nil
|
||||
}
|
||||
v, err := semver.Parse(*attr.VersionValue)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse semantic version: %v", err)
|
||||
}
|
||||
|
||||
return Semver{Version: v}, nil
|
||||
}},
|
||||
}
|
||||
|
||||
@ -150,7 +162,11 @@ var boolType = reflect.TypeOf(true)
|
||||
func (c CompilationResult) Evaluate(ctx context.Context, attributes []resourceapi.NamedResourcesAttribute) (bool, error) {
|
||||
variables := make(map[string]any, len(valueTypes))
|
||||
for name, valueType := range valueTypes {
|
||||
variables[attributesVarPrefix+name] = buildValueMapper(c.Environment.CELTypeAdapter(), attributes, valueType.get)
|
||||
m, err := buildValueMapper(c.Environment.CELTypeAdapter(), attributes, valueType.get)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("extract attributes with type %s: %v", name, err)
|
||||
}
|
||||
variables[attributesVarPrefix+name] = m
|
||||
}
|
||||
result, _, err := c.Program.ContextEval(ctx, variables)
|
||||
if err != nil {
|
||||
@ -172,7 +188,9 @@ func mustBuildEnv() *environment.EnvSet {
|
||||
versioned := []environment.VersionedOptions{
|
||||
{
|
||||
IntroducedVersion: version.MajorMinor(1, 30),
|
||||
EnvOptions: buildVersionedAttributes(),
|
||||
EnvOptions: append(buildVersionedAttributes(),
|
||||
SemverLib(),
|
||||
),
|
||||
},
|
||||
}
|
||||
envset, err := envset.Extend(versioned...)
|
||||
@ -190,17 +208,21 @@ func buildVersionedAttributes() []cel.EnvOption {
|
||||
return options
|
||||
}
|
||||
|
||||
func buildValueMapper(adapter types.Adapter, attributes []resourceapi.NamedResourcesAttribute, get func(resourceapi.NamedResourcesAttribute) any) traits.Mapper {
|
||||
func buildValueMapper(adapter types.Adapter, attributes []resourceapi.NamedResourcesAttribute, get func(resourceapi.NamedResourcesAttribute) (any, error)) (traits.Mapper, error) {
|
||||
// This implementation constructs a map and then let's cel handle the
|
||||
// lookup and iteration. This is done for the sake of simplicity.
|
||||
// Whether it's faster than writing a custom mapper depends on
|
||||
// real-world attribute sets and CEL expressions and would have to be
|
||||
// benchmarked.
|
||||
valueMap := make(map[string]any)
|
||||
for _, attribute := range attributes {
|
||||
if value := get(attribute); value != nil {
|
||||
for name, attribute := range attributes {
|
||||
value, err := get(attribute)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("attribute %q: %v", name, err)
|
||||
}
|
||||
if value != nil {
|
||||
valueMap[attribute.Name] = value
|
||||
}
|
||||
}
|
||||
return types.NewStringInterfaceMap(adapter, valueMap)
|
||||
return types.NewStringInterfaceMap(adapter, valueMap), nil
|
||||
}
|
||||
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
Copyright 2024 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/blang/semver/v4"
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
var (
|
||||
SemverType = cel.ObjectType("kubernetes.Semver")
|
||||
)
|
||||
|
||||
// Semver provdes a CEL representation of a [semver.Version].
|
||||
type Semver struct {
|
||||
semver.Version
|
||||
}
|
||||
|
||||
func (v Semver) ConvertToNative(typeDesc reflect.Type) (interface{}, error) {
|
||||
if reflect.TypeOf(v.Version).AssignableTo(typeDesc) {
|
||||
return v.Version, nil
|
||||
}
|
||||
if reflect.TypeOf("").AssignableTo(typeDesc) {
|
||||
return v.Version.String(), nil
|
||||
}
|
||||
return nil, fmt.Errorf("type conversion error from 'Semver' to '%v'", typeDesc)
|
||||
}
|
||||
|
||||
func (v Semver) ConvertToType(typeVal ref.Type) ref.Val {
|
||||
switch typeVal {
|
||||
case SemverType:
|
||||
return v
|
||||
case types.TypeType:
|
||||
return SemverType
|
||||
default:
|
||||
return types.NewErr("type conversion error from '%s' to '%s'", SemverType, typeVal)
|
||||
}
|
||||
}
|
||||
|
||||
func (v Semver) Equal(other ref.Val) ref.Val {
|
||||
otherDur, ok := other.(Semver)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(other)
|
||||
}
|
||||
return types.Bool(v.Version.EQ(otherDur.Version))
|
||||
}
|
||||
|
||||
func (v Semver) Type() ref.Type {
|
||||
return SemverType
|
||||
}
|
||||
|
||||
func (v Semver) Value() interface{} {
|
||||
return v.Version
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
/*
|
||||
Copyright 2023 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cel_test
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/blang/semver/v4"
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
library "k8s.io/dynamic-resource-allocation/structured/namedresources/cel"
|
||||
)
|
||||
|
||||
func testSemver(t *testing.T, expr string, expectResult ref.Val, expectRuntimeErrPattern string, expectCompileErrs []string) {
|
||||
env, err := cel.NewEnv(
|
||||
library.SemverLib(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
compiled, issues := env.Compile(expr)
|
||||
|
||||
if len(expectCompileErrs) > 0 {
|
||||
missingCompileErrs := []string{}
|
||||
matchedCompileErrs := sets.New[int]()
|
||||
for _, expectedCompileErr := range expectCompileErrs {
|
||||
compiledPattern, err := regexp.Compile(expectedCompileErr)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to compile expected err regex: %v", err)
|
||||
}
|
||||
|
||||
didMatch := false
|
||||
|
||||
for i, compileError := range issues.Errors() {
|
||||
if compiledPattern.Match([]byte(compileError.Message)) {
|
||||
didMatch = true
|
||||
matchedCompileErrs.Insert(i)
|
||||
}
|
||||
}
|
||||
|
||||
if !didMatch {
|
||||
missingCompileErrs = append(missingCompileErrs, expectedCompileErr)
|
||||
} else if len(matchedCompileErrs) != len(issues.Errors()) {
|
||||
unmatchedErrs := []cel.Error{}
|
||||
for i, issue := range issues.Errors() {
|
||||
if !matchedCompileErrs.Has(i) {
|
||||
unmatchedErrs = append(unmatchedErrs, *issue)
|
||||
}
|
||||
}
|
||||
require.Empty(t, unmatchedErrs, "unexpected compilation errors")
|
||||
}
|
||||
}
|
||||
|
||||
require.Empty(t, missingCompileErrs, "expected compilation errors")
|
||||
return
|
||||
} else if len(issues.Errors()) > 0 {
|
||||
for _, err := range issues.Errors() {
|
||||
t.Errorf("unexpected compile error: %v", err)
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
prog, err := env.Program(compiled)
|
||||
if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
}
|
||||
res, _, err := prog.Eval(map[string]interface{}{})
|
||||
if len(expectRuntimeErrPattern) > 0 {
|
||||
if err == nil {
|
||||
t.Fatalf("no runtime error thrown. Expected: %v", expectRuntimeErrPattern)
|
||||
} else if matched, regexErr := regexp.MatchString(expectRuntimeErrPattern, err.Error()); regexErr != nil {
|
||||
t.Fatalf("failed to compile expected err regex: %v", regexErr)
|
||||
} else if !matched {
|
||||
t.Fatalf("unexpected err: %v", err)
|
||||
}
|
||||
} else if err != nil {
|
||||
t.Fatalf("%v", err)
|
||||
} else if expectResult != nil {
|
||||
converted := res.Equal(expectResult).Value().(bool)
|
||||
require.True(t, converted, "expectation not equal to output")
|
||||
} else {
|
||||
t.Fatal("expected result must not be nil")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSemver(t *testing.T) {
|
||||
trueVal := types.Bool(true)
|
||||
falseVal := types.Bool(false)
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
expr string
|
||||
expectValue ref.Val
|
||||
expectedCompileErr []string
|
||||
expectedRuntimeErr string
|
||||
}{
|
||||
{
|
||||
name: "parse",
|
||||
expr: `semver("1.2.3")`,
|
||||
expectValue: library.Semver{Version: semver.MustParse("1.2.3")},
|
||||
},
|
||||
{
|
||||
name: "parseInvalidVersion",
|
||||
expr: `semver("v1.0")`,
|
||||
expectedRuntimeErr: "No Major.Minor.Patch elements found",
|
||||
},
|
||||
{
|
||||
name: "isSemver",
|
||||
expr: `isSemver("1.2.3-beta.1+build.1")`,
|
||||
expectValue: trueVal,
|
||||
},
|
||||
{
|
||||
name: "isSemver_false",
|
||||
expr: `isSemver("v1.0")`,
|
||||
expectValue: falseVal,
|
||||
},
|
||||
{
|
||||
name: "isSemver_noOverload",
|
||||
expr: `isSemver([1, 2, 3])`,
|
||||
expectedCompileErr: []string{"found no matching overload for 'isSemver' applied to.*"},
|
||||
},
|
||||
{
|
||||
name: "equality_reflexivity",
|
||||
expr: `semver("1.2.3") == semver("1.2.3")`,
|
||||
expectValue: trueVal,
|
||||
},
|
||||
{
|
||||
name: "inequality",
|
||||
expr: `semver("1.2.3") == semver("1.0.0")`,
|
||||
expectValue: falseVal,
|
||||
},
|
||||
{
|
||||
name: "semver_less",
|
||||
expr: `semver("1.0.0").isLessThan(semver("1.2.3"))`,
|
||||
expectValue: trueVal,
|
||||
},
|
||||
{
|
||||
name: "semver_less_false",
|
||||
expr: `semver("1.0.0").isLessThan(semver("1.0.0"))`,
|
||||
expectValue: falseVal,
|
||||
},
|
||||
{
|
||||
name: "semver_greater",
|
||||
expr: `semver("1.2.3").isGreaterThan(semver("1.0.0"))`,
|
||||
expectValue: trueVal,
|
||||
},
|
||||
{
|
||||
name: "semver_greater_false",
|
||||
expr: `semver("1.0.0").isGreaterThan(semver("1.0.0"))`,
|
||||
expectValue: falseVal,
|
||||
},
|
||||
{
|
||||
name: "compare_equal",
|
||||
expr: `semver("1.2.3").compareTo(semver("1.2.3"))`,
|
||||
expectValue: types.Int(0),
|
||||
},
|
||||
{
|
||||
name: "compare_less",
|
||||
expr: `semver("1.0.0").compareTo(semver("1.2.3"))`,
|
||||
expectValue: types.Int(-1),
|
||||
},
|
||||
{
|
||||
name: "compare_greater",
|
||||
expr: `semver("1.2.3").compareTo(semver("1.0.0"))`,
|
||||
expectValue: types.Int(1),
|
||||
},
|
||||
{
|
||||
name: "major",
|
||||
expr: `semver("1.2.3").major()`,
|
||||
expectValue: types.Int(1),
|
||||
},
|
||||
{
|
||||
name: "minor",
|
||||
expr: `semver("1.2.3").minor()`,
|
||||
expectValue: types.Int(2),
|
||||
},
|
||||
{
|
||||
name: "patch",
|
||||
expr: `semver("1.2.3").patch()`,
|
||||
expectValue: types.Int(3),
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
testSemver(t, c.expr, c.expectValue, c.expectedRuntimeErr, c.expectedCompileErr)
|
||||
})
|
||||
}
|
||||
}
|
@ -0,0 +1,238 @@
|
||||
/*
|
||||
Copyright 2024 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package cel
|
||||
|
||||
import (
|
||||
"github.com/blang/semver/v4"
|
||||
"github.com/google/cel-go/cel"
|
||||
"github.com/google/cel-go/common/types"
|
||||
"github.com/google/cel-go/common/types/ref"
|
||||
)
|
||||
|
||||
// Semver provides a CEL function library extension for [semver.Version].
|
||||
//
|
||||
// semver
|
||||
//
|
||||
// Converts a string to a semantic version or results in an error if the string is not a valid semantic version. Refer
|
||||
// to semver.org documentation for information on accepted patterns.
|
||||
//
|
||||
// semver(<string>) <Semver>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// semver('1.0.0') // returns a Semver
|
||||
// semver('0.1.0-alpha.1') // returns a Semver
|
||||
// semver('200K') // error
|
||||
// semver('Three') // error
|
||||
// semver('Mi') // error
|
||||
//
|
||||
// isSemver
|
||||
//
|
||||
// Returns true if a string is a valid Semver. isSemver returns true if and
|
||||
// only if semver does not result in error.
|
||||
//
|
||||
// isSemver( <string>) <bool>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// isSemver('1.0.0') // returns true
|
||||
// isSemver('v1.0') // returns true (tolerant parsing)
|
||||
// isSemver('hello') // returns false
|
||||
//
|
||||
// Conversion to Scalars:
|
||||
//
|
||||
// - major/minor/patch: return the major version number as int64.
|
||||
//
|
||||
// <Semver>.major() <int>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// semver("1.2.3").major() // returns 1
|
||||
//
|
||||
// Comparisons
|
||||
//
|
||||
// - isGreaterThan: Returns true if and only if the receiver is greater than the operand
|
||||
//
|
||||
// - isLessThan: Returns true if and only if the receiver is less than the operand
|
||||
//
|
||||
// - compareTo: Compares receiver to operand and returns 0 if they are equal, 1 if the receiver is greater, or -1 if the receiver is less than the operand
|
||||
//
|
||||
//
|
||||
// <Semver>.isLessThan(<semver>) <bool>
|
||||
// <Semver>.isGreaterThan(<semver>) <bool>
|
||||
// <Semver>.compareTo(<semver>) <int>
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// semver("1.2.3").compareTo(semver("1.2.3")) // returns 0
|
||||
// semver("1.2.3").compareTo(semver("2.0.0")) // returns -1
|
||||
// semver("1.2.3").compareTo(semver("0.1.2")) // returns 1
|
||||
|
||||
func SemverLib() cel.EnvOption {
|
||||
return cel.Lib(semverLib)
|
||||
}
|
||||
|
||||
var semverLib = &semverLibType{}
|
||||
|
||||
type semverLibType struct{}
|
||||
|
||||
func (*semverLibType) LibraryName() string {
|
||||
return "k8s.semver"
|
||||
}
|
||||
|
||||
func (*semverLibType) CompileOptions() []cel.EnvOption {
|
||||
// Defined in this function to avoid an initialization order problem.
|
||||
semverLibraryDecls := map[string][]cel.FunctionOpt{
|
||||
"semver": {
|
||||
cel.Overload("string_to_semver", []*cel.Type{cel.StringType}, SemverType, cel.UnaryBinding((stringToSemver))),
|
||||
},
|
||||
"isSemver": {
|
||||
cel.Overload("is_semver_string", []*cel.Type{cel.StringType}, cel.BoolType, cel.UnaryBinding(isSemver)),
|
||||
},
|
||||
"isGreaterThan": {
|
||||
cel.MemberOverload("semver_is_greater_than", []*cel.Type{SemverType, SemverType}, cel.BoolType, cel.BinaryBinding(semverIsGreaterThan)),
|
||||
},
|
||||
"isLessThan": {
|
||||
cel.MemberOverload("semver_is_less_than", []*cel.Type{SemverType, SemverType}, cel.BoolType, cel.BinaryBinding(semverIsLessThan)),
|
||||
},
|
||||
"compareTo": {
|
||||
cel.MemberOverload("semver_compare_to", []*cel.Type{SemverType, SemverType}, cel.IntType, cel.BinaryBinding(semverCompareTo)),
|
||||
},
|
||||
"major": {
|
||||
cel.MemberOverload("semver_major", []*cel.Type{SemverType}, cel.IntType, cel.UnaryBinding(semverMajor)),
|
||||
},
|
||||
"minor": {
|
||||
cel.MemberOverload("semver_minor", []*cel.Type{SemverType}, cel.IntType, cel.UnaryBinding(semverMinor)),
|
||||
},
|
||||
"patch": {
|
||||
cel.MemberOverload("semver_patch", []*cel.Type{SemverType}, cel.IntType, cel.UnaryBinding(semverPatch)),
|
||||
},
|
||||
}
|
||||
|
||||
options := make([]cel.EnvOption, 0, len(semverLibraryDecls))
|
||||
for name, overloads := range semverLibraryDecls {
|
||||
options = append(options, cel.Function(name, overloads...))
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func (*semverLibType) ProgramOptions() []cel.ProgramOption {
|
||||
return []cel.ProgramOption{}
|
||||
}
|
||||
|
||||
func isSemver(arg ref.Val) ref.Val {
|
||||
str, ok := arg.Value().(string)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
|
||||
// Using semver/v4 here is okay because this function isn't
|
||||
// used to validate the Kubernetes API. In the CEL base library
|
||||
// we would have to use the regular expression from
|
||||
// pkg/apis/resource/structured/namedresources/validation/validation.go.
|
||||
_, err := semver.Parse(str)
|
||||
if err != nil {
|
||||
return types.Bool(false)
|
||||
}
|
||||
|
||||
return types.Bool(true)
|
||||
}
|
||||
|
||||
func stringToSemver(arg ref.Val) ref.Val {
|
||||
str, ok := arg.Value().(string)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
|
||||
// Using semver/v4 here is okay because this function isn't
|
||||
// used to validate the Kubernetes API. In the CEL base library
|
||||
// we would have to use the regular expression from
|
||||
// pkg/apis/resource/structured/namedresources/validation/validation.go
|
||||
// first before parsing.
|
||||
v, err := semver.Parse(str)
|
||||
if err != nil {
|
||||
return types.WrapErr(err)
|
||||
}
|
||||
|
||||
return Semver{Version: v}
|
||||
}
|
||||
|
||||
func semverMajor(arg ref.Val) ref.Val {
|
||||
v, ok := arg.Value().(semver.Version)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
return types.Int(v.Major)
|
||||
}
|
||||
|
||||
func semverMinor(arg ref.Val) ref.Val {
|
||||
v, ok := arg.Value().(semver.Version)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
return types.Int(v.Minor)
|
||||
}
|
||||
|
||||
func semverPatch(arg ref.Val) ref.Val {
|
||||
v, ok := arg.Value().(semver.Version)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
return types.Int(v.Patch)
|
||||
}
|
||||
|
||||
func semverIsGreaterThan(arg ref.Val, other ref.Val) ref.Val {
|
||||
v, ok := arg.Value().(semver.Version)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
|
||||
v2, ok := other.Value().(semver.Version)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
|
||||
return types.Bool(v.Compare(v2) == 1)
|
||||
}
|
||||
|
||||
func semverIsLessThan(arg ref.Val, other ref.Val) ref.Val {
|
||||
v, ok := arg.Value().(semver.Version)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
|
||||
v2, ok := other.Value().(semver.Version)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
|
||||
return types.Bool(v.Compare(v2) == -1)
|
||||
}
|
||||
|
||||
func semverCompareTo(arg ref.Val, other ref.Val) ref.Val {
|
||||
v, ok := arg.Value().(semver.Version)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
|
||||
v2, ok := other.Value().(semver.Version)
|
||||
if !ok {
|
||||
return types.MaybeNoSuchOverloadErr(arg)
|
||||
}
|
||||
|
||||
return types.Int(v.Compare(v2))
|
||||
}
|
Loading…
Reference in New Issue
Block a user