Browse code

Extend Builds with list of labels applied to image

Martin Milata authored on 2016/10/04 23:13:32
Showing 32 changed files
... ...
@@ -184,6 +184,10 @@ message BuildOutput {
184 184
   // up the authentication for executing the Docker push to authentication
185 185
   // enabled Docker Registry (or Docker Hub).
186 186
   optional k8s.io.kubernetes.pkg.api.v1.LocalObjectReference pushSecret = 2;
187
+
188
+  // imageLabels define a list of labels that are applied to the resulting image. If there
189
+  // are multiple labels with the same name then the last one in the list is used.
190
+  repeated ImageLabel imageLabels = 3;
187 191
 }
188 192
 
189 193
 // A BuildPostCommitSpec holds a build post commit hook specification. The hook
... ...
@@ -641,6 +645,15 @@ message ImageChangeTrigger {
641 641
   optional k8s.io.kubernetes.pkg.api.v1.ObjectReference from = 2;
642 642
 }
643 643
 
644
+// ImageLabel represents a label applied to the resulting image.
645
+message ImageLabel {
646
+  // name defines the name of the label. It must have non-zero length.
647
+  optional string name = 1;
648
+
649
+  // value defines the literal value of the label.
650
+  optional string value = 2;
651
+}
652
+
644 653
 // ImageSource is used to describe build source that will be extracted from an image. A reference of
645 654
 // type ImageStreamTag, ImageStreamImage or DockerImage may be used. A pull secret can be specified
646 655
 // to pull the image from an external registry or override the default service account secret if pulling
... ...
@@ -22071,6 +22071,30 @@
22071 22071
      "pushSecret": {
22072 22072
       "$ref": "v1.LocalObjectReference",
22073 22073
       "description": "PushSecret is the name of a Secret that would be used for setting up the authentication for executing the Docker push to authentication enabled Docker Registry (or Docker Hub)."
22074
+     },
22075
+     "imageLabels": {
22076
+      "type": "array",
22077
+      "items": {
22078
+       "$ref": "v1.ImageLabel"
22079
+      },
22080
+      "description": "imageLabels define a list of labels that are applied to the resulting image. If there are multiple labels with the same name then the last one in the list is used."
22081
+     }
22082
+    }
22083
+   },
22084
+   "v1.ImageLabel": {
22085
+    "id": "v1.ImageLabel",
22086
+    "description": "ImageLabel represents a label applied to the resulting image.",
22087
+    "required": [
22088
+     "name"
22089
+    ],
22090
+    "properties": {
22091
+     "name": {
22092
+      "type": "string",
22093
+      "description": "name defines the name of the label. It must have non-zero length."
22094
+     },
22095
+     "value": {
22096
+      "type": "string",
22097
+      "description": "value defines the literal value of the label."
22074 22098
      }
22075 22099
     }
22076 22100
    },
... ...
@@ -44770,6 +44770,13 @@
44770 44770
    "v1.BuildOutput": {
44771 44771
     "description": "BuildOutput is input to a build strategy and describes the Docker image that the strategy should produce.",
44772 44772
     "properties": {
44773
+     "imageLabels": {
44774
+      "description": "imageLabels define a list of labels that are applied to the resulting image. If there are multiple labels with the same name then the last one in the list is used.",
44775
+      "type": "array",
44776
+      "items": {
44777
+       "$ref": "#/definitions/v1.ImageLabel"
44778
+      }
44779
+     },
44773 44780
      "pushSecret": {
44774 44781
       "$ref": "#/definitions/v1.LocalObjectReference"
44775 44782
      },
... ...
@@ -47742,6 +47749,22 @@
47742 47742
      }
47743 47743
     }
47744 47744
    },
47745
+   "v1.ImageLabel": {
47746
+    "description": "ImageLabel represents a label applied to the resulting image.",
47747
+    "required": [
47748
+     "name"
47749
+    ],
47750
+    "properties": {
47751
+     "name": {
47752
+      "description": "name defines the name of the label. It must have non-zero length.",
47753
+      "type": "string"
47754
+     },
47755
+     "value": {
47756
+      "description": "value defines the literal value of the label.",
47757
+      "type": "string"
47758
+     }
47759
+    }
47760
+   },
47745 47761
    "v1.ImageLayer": {
47746 47762
     "description": "ImageLayer represents a single layer of the image. Some images may have multiple layers. Some may have none.",
47747 47763
     "required": [
... ...
@@ -88,6 +88,12 @@ func (a *buildDefaults) applyBuildDefaults(build *buildapi.Build) {
88 88
 		addDefaultEnvVar(envVar, buildEnv)
89 89
 	}
90 90
 
91
+	// Apply default labels
92
+	for _, lbl := range a.defaultsConfig.ImageLabels {
93
+		glog.V(5).Infof("Adding default image label %s=%s to build %s/%s", lbl.Name, lbl.Value, build.Namespace, build.Name)
94
+		addDefaultLabel(lbl, &build.Spec.Output.ImageLabels)
95
+	}
96
+
91 97
 	sourceDefaults := a.defaultsConfig.SourceStrategyDefaults
92 98
 	sourceStrategy := build.Spec.Strategy.SourceStrategy
93 99
 	if sourceDefaults != nil && sourceDefaults.Incremental != nil && *sourceDefaults.Incremental &&
... ...
@@ -153,3 +159,15 @@ func addDefaultEnvVar(v kapi.EnvVar, envVars *[]kapi.EnvVar) {
153 153
 		*envVars = append(*envVars, v)
154 154
 	}
155 155
 }
156
+
157
+func addDefaultLabel(defaultLabel buildapi.ImageLabel, buildLabels *[]buildapi.ImageLabel) {
158
+	found := false
159
+	for _, lbl := range *buildLabels {
160
+		if lbl.Name == defaultLabel.Name {
161
+			found = true
162
+		}
163
+	}
164
+	if !found {
165
+		*buildLabels = append(*buildLabels, defaultLabel)
166
+	}
167
+}
... ...
@@ -1,6 +1,7 @@
1 1
 package defaults
2 2
 
3 3
 import (
4
+	"reflect"
4 5
 	"testing"
5 6
 
6 7
 	kapi "k8s.io/kubernetes/pkg/api"
... ...
@@ -8,6 +9,7 @@ import (
8 8
 	buildadmission "github.com/openshift/origin/pkg/build/admission"
9 9
 	defaultsapi "github.com/openshift/origin/pkg/build/admission/defaults/api"
10 10
 	u "github.com/openshift/origin/pkg/build/admission/testutil"
11
+	buildapi "github.com/openshift/origin/pkg/build/api"
11 12
 
12 13
 	_ "github.com/openshift/origin/pkg/api/install"
13 14
 )
... ...
@@ -130,3 +132,137 @@ func TestIncrementalDefaults(t *testing.T) {
130 130
 	}
131 131
 
132 132
 }
133
+
134
+func TestLabelDefaults(t *testing.T) {
135
+	tests := []struct {
136
+		buildLabels   []buildapi.ImageLabel
137
+		defaultLabels []buildapi.ImageLabel
138
+		expected      []buildapi.ImageLabel
139
+	}{
140
+		{
141
+			buildLabels:   nil,
142
+			defaultLabels: nil,
143
+			expected:      nil,
144
+		},
145
+		{
146
+			buildLabels: nil,
147
+			defaultLabels: []buildapi.ImageLabel{
148
+				{
149
+					Name:  "distribution-scope",
150
+					Value: "private",
151
+				},
152
+				{
153
+					Name:  "changelog-url",
154
+					Value: "file:///dev/null",
155
+				},
156
+			},
157
+			expected: []buildapi.ImageLabel{
158
+				{
159
+					Name:  "distribution-scope",
160
+					Value: "private",
161
+				},
162
+				{
163
+					Name:  "changelog-url",
164
+					Value: "file:///dev/null",
165
+				},
166
+			},
167
+		},
168
+		{
169
+			buildLabels: []buildapi.ImageLabel{
170
+				{
171
+					Name:  "distribution-scope",
172
+					Value: "private",
173
+				},
174
+				{
175
+					Name:  "changelog-url",
176
+					Value: "file:///dev/null",
177
+				},
178
+			},
179
+			defaultLabels: nil,
180
+			expected: []buildapi.ImageLabel{
181
+				{
182
+					Name:  "distribution-scope",
183
+					Value: "private",
184
+				},
185
+				{
186
+					Name:  "changelog-url",
187
+					Value: "file:///dev/null",
188
+				},
189
+			},
190
+		},
191
+		{
192
+			buildLabels: []buildapi.ImageLabel{
193
+				{
194
+					Name:  "distribution-scope",
195
+					Value: "private",
196
+				},
197
+			},
198
+			defaultLabels: []buildapi.ImageLabel{
199
+				{
200
+					Name:  "distribution-scope",
201
+					Value: "public",
202
+				},
203
+				{
204
+					Name:  "changelog-url",
205
+					Value: "file:///dev/null",
206
+				},
207
+			},
208
+			expected: []buildapi.ImageLabel{
209
+				{
210
+					Name:  "distribution-scope",
211
+					Value: "private",
212
+				},
213
+				{
214
+					Name:  "changelog-url",
215
+					Value: "file:///dev/null",
216
+				},
217
+			},
218
+		},
219
+		{
220
+			buildLabels: []buildapi.ImageLabel{
221
+				{
222
+					Name:  "distribution-scope",
223
+					Value: "private",
224
+				},
225
+			},
226
+			defaultLabels: []buildapi.ImageLabel{
227
+				{
228
+					Name:  "changelog-url",
229
+					Value: "file:///dev/null",
230
+				},
231
+			},
232
+			expected: []buildapi.ImageLabel{
233
+				{
234
+					Name:  "distribution-scope",
235
+					Value: "private",
236
+				},
237
+				{
238
+					Name:  "changelog-url",
239
+					Value: "file:///dev/null",
240
+				},
241
+			},
242
+		},
243
+	}
244
+
245
+	for i, test := range tests {
246
+		defaultsConfig := &defaultsapi.BuildDefaultsConfig{
247
+			ImageLabels: test.defaultLabels,
248
+		}
249
+
250
+		admitter := NewBuildDefaults(defaultsConfig)
251
+		pod := u.Pod().WithBuild(t, u.Build().WithImageLabels(test.buildLabels).AsBuild(), "v1")
252
+		err := admitter.Admit(pod.ToAttributes())
253
+		if err != nil {
254
+			t.Fatalf("unexpected error: %v", err)
255
+		}
256
+		build := pod.GetBuild(t)
257
+		if err != nil {
258
+			t.Fatalf("unexpected error: %v", err)
259
+		}
260
+
261
+		result := build.Spec.Output.ImageLabels
262
+		if !reflect.DeepEqual(result, test.expected) {
263
+			t.Errorf("expected[%d]: %v, got: %v", i, test.expected, result)
264
+		}
265
+	}
266
+}
... ...
@@ -3,6 +3,8 @@ package api
3 3
 import (
4 4
 	kapi "k8s.io/kubernetes/pkg/api"
5 5
 	"k8s.io/kubernetes/pkg/api/unversioned"
6
+
7
+	buildapi "github.com/openshift/origin/pkg/build/api"
6 8
 )
7 9
 
8 10
 // BuildDefaultsConfig controls the default information for Builds
... ...
@@ -25,6 +27,11 @@ type BuildDefaultsConfig struct {
25 25
 	// SourceStrategyDefaults are default values that apply to builds using the
26 26
 	// source strategy.
27 27
 	SourceStrategyDefaults *SourceStrategyDefaultsConfig
28
+
29
+	// ImageLabels is a list of docker labels that are applied to the resulting image.
30
+	// User can override a default label by providing a label with the same name in their
31
+	// Build/BuildConfig.
32
+	ImageLabels []buildapi.ImageLabel
28 33
 }
29 34
 
30 35
 // SourceStrategyDefaultsConfig contains values that apply to builds using the
... ...
@@ -12,6 +12,7 @@ var map_BuildDefaultsConfig = map[string]string{
12 12
 	"gitNoProxy":    "GitNoProxy is the list of domains for which the proxy should not be used",
13 13
 	"env":           "Env is a set of default environment variables that will be applied to the build if the specified variables do not exist on the build",
14 14
 	"sourceStrategyDefaults": "SourceStrategyDefaults are default values that apply to builds using the source strategy.",
15
+	"imageLabels":            "ImageLabels is a list of docker labels that are applied to the resulting image. User can override a default label by providing a label with the same name in their Build/BuildConfig.",
15 16
 }
16 17
 
17 18
 func (BuildDefaultsConfig) SwaggerDoc() map[string]string {
... ...
@@ -3,6 +3,8 @@ package v1
3 3
 import (
4 4
 	kapi "k8s.io/kubernetes/pkg/api"
5 5
 	"k8s.io/kubernetes/pkg/api/unversioned"
6
+
7
+	buildapi "github.com/openshift/origin/pkg/build/api/v1"
6 8
 )
7 9
 
8 10
 // BuildDefaultsConfig controls the default information for Builds
... ...
@@ -25,6 +27,11 @@ type BuildDefaultsConfig struct {
25 25
 	// SourceStrategyDefaults are default values that apply to builds using the
26 26
 	// source strategy.
27 27
 	SourceStrategyDefaults *SourceStrategyDefaultsConfig `json:"sourceStrategyDefaults,omitempty"`
28
+
29
+	// ImageLabels is a list of docker labels that are applied to the resulting image.
30
+	// User can override a default label by providing a label with the same name in their
31
+	// Build/BuildConfig.
32
+	ImageLabels []buildapi.ImageLabel `json:"imageLabels,omitempty"`
28 33
 }
29 34
 
30 35
 // SourceStrategyDefaultsConfig contains values that apply to builds using the
... ...
@@ -7,12 +7,12 @@ import (
7 7
 	buildvalidation "github.com/openshift/origin/pkg/build/api/validation"
8 8
 )
9 9
 
10
-// ValidateBuild tests required fields for a Build.
11 10
 func ValidateBuildDefaultsConfig(config *api.BuildDefaultsConfig) field.ErrorList {
12 11
 	allErrs := field.ErrorList{}
13 12
 	allErrs = append(allErrs, validateURL(config.GitHTTPProxy, field.NewPath("gitHTTPProxy"))...)
14 13
 	allErrs = append(allErrs, validateURL(config.GitHTTPSProxy, field.NewPath("gitHTTPSProxy"))...)
15 14
 	allErrs = append(allErrs, buildvalidation.ValidateStrategyEnv(config.Env, field.NewPath("env"))...)
15
+	allErrs = append(allErrs, buildvalidation.ValidateImageLabels(config.ImageLabels, field.NewPath("imageLabels"))...)
16 16
 	return allErrs
17 17
 }
18 18
 
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"k8s.io/kubernetes/pkg/util/validation/field"
8 8
 
9 9
 	defaultsapi "github.com/openshift/origin/pkg/build/admission/defaults/api"
10
+	buildapi "github.com/openshift/origin/pkg/build/api"
10 11
 )
11 12
 
12 13
 func TestValidateBuildDefaultsConfig(t *testing.T) {
... ...
@@ -97,6 +98,52 @@ func TestValidateBuildDefaultsConfig(t *testing.T) {
97 97
 			errField:    "env[0].valueFrom",
98 98
 			errType:     field.ErrorTypeInvalid,
99 99
 		},
100
+		// 6: label: empty name
101
+		{
102
+			config: &defaultsapi.BuildDefaultsConfig{
103
+				ImageLabels: []buildapi.ImageLabel{
104
+					{
105
+						Name:  "",
106
+						Value: "empty",
107
+					},
108
+				},
109
+			},
110
+			errExpected: true,
111
+			errField:    "imageLabels[0].name",
112
+			errType:     field.ErrorTypeRequired,
113
+		},
114
+		// 7: label: bad name
115
+		{
116
+			config: &defaultsapi.BuildDefaultsConfig{
117
+				ImageLabels: []buildapi.ImageLabel{
118
+					{
119
+						Name:  "\tč;",
120
+						Value: "????",
121
+					},
122
+				},
123
+			},
124
+			errExpected: true,
125
+			errField:    "imageLabels[0].name",
126
+			errType:     field.ErrorTypeInvalid,
127
+		},
128
+		// 8: duplicate label
129
+		{
130
+			config: &defaultsapi.BuildDefaultsConfig{
131
+				ImageLabels: []buildapi.ImageLabel{
132
+					{
133
+						Name:  "name",
134
+						Value: "Jan",
135
+					},
136
+					{
137
+						Name:  "name",
138
+						Value: "Elvis",
139
+					},
140
+				},
141
+			},
142
+			errExpected: true,
143
+			errField:    "imageLabels[1].name",
144
+			errType:     field.ErrorTypeInvalid,
145
+		},
100 146
 	}
101 147
 
102 148
 	for i, tc := range tests {
... ...
@@ -10,6 +10,8 @@ import (
10 10
 
11 11
 	buildadmission "github.com/openshift/origin/pkg/build/admission"
12 12
 	overridesapi "github.com/openshift/origin/pkg/build/admission/overrides/api"
13
+	"github.com/openshift/origin/pkg/build/admission/overrides/api/validation"
14
+	buildapi "github.com/openshift/origin/pkg/build/api"
13 15
 )
14 16
 
15 17
 func init() {
... ...
@@ -30,6 +32,10 @@ func getConfig(in io.Reader) (*overridesapi.BuildOverridesConfig, error) {
30 30
 	if err != nil {
31 31
 		return nil, err
32 32
 	}
33
+	errs := validation.ValidateBuildOverridesConfig(overridesConfig)
34
+	if len(errs) > 0 {
35
+		return nil, errs.ToAggregate()
36
+	}
33 37
 	return overridesConfig, nil
34 38
 }
35 39
 
... ...
@@ -59,14 +65,28 @@ func (a *buildOverrides) Admit(attributes admission.Attributes) error {
59 59
 }
60 60
 
61 61
 func (a *buildOverrides) applyOverrides(attributes admission.Attributes) error {
62
-	if !a.overridesConfig.ForcePull {
63
-		return nil
64
-	}
65 62
 	build, version, err := buildadmission.GetBuild(attributes)
66 63
 	if err != nil {
67 64
 		return err
68 65
 	}
69 66
 	glog.V(4).Infof("Handling build %s/%s", build.Namespace, build.Name)
67
+
68
+	if a.overridesConfig.ForcePull {
69
+		if err := applyForcePullToBuild(build, attributes); err != nil {
70
+			return err
71
+		}
72
+	}
73
+
74
+	// Apply label overrides
75
+	for _, lbl := range a.overridesConfig.ImageLabels {
76
+		glog.V(5).Infof("Overriding image label %s=%s in build %s/%s", lbl.Name, lbl.Value, build.Namespace, build.Name)
77
+		overrideLabel(lbl, &build.Spec.Output.ImageLabels)
78
+	}
79
+
80
+	return buildadmission.SetBuild(attributes, build, version)
81
+}
82
+
83
+func applyForcePullToBuild(build *buildapi.Build, attributes admission.Attributes) error {
70 84
 	if build.Spec.Strategy.DockerStrategy != nil {
71 85
 		glog.V(5).Infof("Setting docker strategy ForcePull to true in build %s/%s", build.Namespace, build.Name)
72 86
 		build.Spec.Strategy.DockerStrategy.ForcePull = true
... ...
@@ -83,7 +103,7 @@ func (a *buildOverrides) applyOverrides(attributes admission.Attributes) error {
83 83
 		glog.V(5).Infof("Setting custom strategy ForcePull to true in build %s/%s", build.Namespace, build.Name)
84 84
 		build.Spec.Strategy.CustomStrategy.ForcePull = true
85 85
 	}
86
-	return buildadmission.SetBuild(attributes, build, version)
86
+	return nil
87 87
 }
88 88
 
89 89
 func applyForcePullToPod(attributes admission.Attributes) error {
... ...
@@ -101,3 +121,17 @@ func applyForcePullToPod(attributes admission.Attributes) error {
101 101
 	}
102 102
 	return nil
103 103
 }
104
+
105
+func overrideLabel(overridingLabel buildapi.ImageLabel, buildLabels *[]buildapi.ImageLabel) {
106
+	found := false
107
+	for i, lbl := range *buildLabels {
108
+		if lbl.Name == overridingLabel.Name {
109
+			glog.V(5).Infof("Replacing label %s (original value %q) with new value %q", lbl.Name, lbl.Value, overridingLabel.Value)
110
+			(*buildLabels)[i] = overridingLabel
111
+			found = true
112
+		}
113
+	}
114
+	if !found {
115
+		*buildLabels = append(*buildLabels, overridingLabel)
116
+	}
117
+}
... ...
@@ -1,6 +1,7 @@
1 1
 package overrides
2 2
 
3 3
 import (
4
+	"reflect"
4 5
 	"testing"
5 6
 
6 7
 	"k8s.io/kubernetes/pkg/admission"
... ...
@@ -66,3 +67,134 @@ func TestBuildOverrideForcePull(t *testing.T) {
66 66
 		}
67 67
 	}
68 68
 }
69
+
70
+func TestLabelOverrides(t *testing.T) {
71
+	tests := []struct {
72
+		buildLabels    []buildapi.ImageLabel
73
+		overrideLabels []buildapi.ImageLabel
74
+		expected       []buildapi.ImageLabel
75
+	}{
76
+		{
77
+			buildLabels:    nil,
78
+			overrideLabels: nil,
79
+			expected:       nil,
80
+		},
81
+		{
82
+			buildLabels: nil,
83
+			overrideLabels: []buildapi.ImageLabel{
84
+				{
85
+					Name:  "distribution-scope",
86
+					Value: "private",
87
+				},
88
+				{
89
+					Name:  "changelog-url",
90
+					Value: "file:///dev/null",
91
+				},
92
+			},
93
+			expected: []buildapi.ImageLabel{
94
+				{
95
+					Name:  "distribution-scope",
96
+					Value: "private",
97
+				},
98
+				{
99
+					Name:  "changelog-url",
100
+					Value: "file:///dev/null",
101
+				},
102
+			},
103
+		},
104
+		{
105
+			buildLabels: []buildapi.ImageLabel{
106
+				{
107
+					Name:  "distribution-scope",
108
+					Value: "private",
109
+				},
110
+				{
111
+					Name:  "changelog-url",
112
+					Value: "file:///dev/null",
113
+				},
114
+			},
115
+			overrideLabels: nil,
116
+			expected: []buildapi.ImageLabel{
117
+				{
118
+					Name:  "distribution-scope",
119
+					Value: "private",
120
+				},
121
+				{
122
+					Name:  "changelog-url",
123
+					Value: "file:///dev/null",
124
+				},
125
+			},
126
+		},
127
+		{
128
+			buildLabels: []buildapi.ImageLabel{
129
+				{
130
+					Name:  "distribution-scope",
131
+					Value: "public",
132
+				},
133
+			},
134
+			overrideLabels: []buildapi.ImageLabel{
135
+				{
136
+					Name:  "distribution-scope",
137
+					Value: "private",
138
+				},
139
+				{
140
+					Name:  "changelog-url",
141
+					Value: "file:///dev/null",
142
+				},
143
+			},
144
+			expected: []buildapi.ImageLabel{
145
+				{
146
+					Name:  "distribution-scope",
147
+					Value: "private",
148
+				},
149
+				{
150
+					Name:  "changelog-url",
151
+					Value: "file:///dev/null",
152
+				},
153
+			},
154
+		},
155
+		{
156
+			buildLabels: []buildapi.ImageLabel{
157
+				{
158
+					Name:  "distribution-scope",
159
+					Value: "private",
160
+				},
161
+			},
162
+			overrideLabels: []buildapi.ImageLabel{
163
+				{
164
+					Name:  "changelog-url",
165
+					Value: "file:///dev/null",
166
+				},
167
+			},
168
+			expected: []buildapi.ImageLabel{
169
+				{
170
+					Name:  "distribution-scope",
171
+					Value: "private",
172
+				},
173
+				{
174
+					Name:  "changelog-url",
175
+					Value: "file:///dev/null",
176
+				},
177
+			},
178
+		},
179
+	}
180
+
181
+	for i, test := range tests {
182
+		overridesConfig := &overridesapi.BuildOverridesConfig{
183
+			ImageLabels: test.overrideLabels,
184
+		}
185
+
186
+		admitter := NewBuildOverrides(overridesConfig)
187
+		pod := u.Pod().WithBuild(t, u.Build().WithImageLabels(test.buildLabels).AsBuild(), "v1")
188
+		err := admitter.Admit(pod.ToAttributes())
189
+		if err != nil {
190
+			t.Fatalf("unexpected error: %v", err)
191
+		}
192
+		build := pod.GetBuild(t)
193
+
194
+		result := build.Spec.Output.ImageLabels
195
+		if !reflect.DeepEqual(result, test.expected) {
196
+			t.Errorf("expected[%d]: %v, got: %v", i, test.expected, result)
197
+		}
198
+	}
199
+}
... ...
@@ -2,6 +2,8 @@ package api
2 2
 
3 3
 import (
4 4
 	"k8s.io/kubernetes/pkg/api/unversioned"
5
+
6
+	buildapi "github.com/openshift/origin/pkg/build/api"
5 7
 )
6 8
 
7 9
 // BuildOverridesConfig controls override settings for builds
... ...
@@ -10,4 +12,9 @@ type BuildOverridesConfig struct {
10 10
 
11 11
 	// ForcePull indicates whether the build strategy should always be set to ForcePull=true
12 12
 	ForcePull bool
13
+
14
+	// ImageLabels is a list of docker labels that are applied to the resulting image.
15
+	// If user provided a label in their Build/BuildConfig with the same name as one in this
16
+	// list, the user's label will be overwritten.
17
+	ImageLabels []buildapi.ImageLabel
13 18
 }
... ...
@@ -6,8 +6,9 @@ package v1
6 6
 // ==== DO NOT EDIT THIS FILE MANUALLY ====
7 7
 
8 8
 var map_BuildOverridesConfig = map[string]string{
9
-	"":          "BuildOverridesConfig controls override settings for builds",
10
-	"forcePull": "ForcePull indicates whether the build strategy should always be set to ForcePull=true",
9
+	"":            "BuildOverridesConfig controls override settings for builds",
10
+	"forcePull":   "ForcePull indicates whether the build strategy should always be set to ForcePull=true",
11
+	"imageLabels": "ImageLabels is a list of docker labels that are applied to the resulting image. If user provided a label in their Build/BuildConfig with the same name as one in this list, the user's label will be overwritten.",
11 12
 }
12 13
 
13 14
 func (BuildOverridesConfig) SwaggerDoc() map[string]string {
... ...
@@ -2,6 +2,8 @@ package v1
2 2
 
3 3
 import (
4 4
 	"k8s.io/kubernetes/pkg/api/unversioned"
5
+
6
+	buildapi "github.com/openshift/origin/pkg/build/api/v1"
5 7
 )
6 8
 
7 9
 // BuildOverridesConfig controls override settings for builds
... ...
@@ -10,4 +12,9 @@ type BuildOverridesConfig struct {
10 10
 
11 11
 	// ForcePull indicates whether the build strategy should always be set to ForcePull=true
12 12
 	ForcePull bool `json:"forcePull"`
13
+
14
+	// ImageLabels is a list of docker labels that are applied to the resulting image.
15
+	// If user provided a label in their Build/BuildConfig with the same name as one in this
16
+	// list, the user's label will be overwritten.
17
+	ImageLabels []buildapi.ImageLabel `json:"imageLabels,omitempty"`
13 18
 }
14 19
new file mode 100644
... ...
@@ -0,0 +1,14 @@
0
+package validation
1
+
2
+import (
3
+	"k8s.io/kubernetes/pkg/util/validation/field"
4
+
5
+	"github.com/openshift/origin/pkg/build/admission/overrides/api"
6
+	buildvalidation "github.com/openshift/origin/pkg/build/api/validation"
7
+)
8
+
9
+func ValidateBuildOverridesConfig(config *api.BuildOverridesConfig) field.ErrorList {
10
+	allErrs := field.ErrorList{}
11
+	allErrs = append(allErrs, buildvalidation.ValidateImageLabels(config.ImageLabels, field.NewPath("imageLabels"))...)
12
+	return allErrs
13
+}
... ...
@@ -49,6 +49,11 @@ func (b *TestBuild) WithCustomStrategy() *TestBuild {
49 49
 	return b
50 50
 }
51 51
 
52
+func (b *TestBuild) WithImageLabels(labels []buildapi.ImageLabel) *TestBuild {
53
+	b.Spec.Output.ImageLabels = labels
54
+	return b
55
+}
56
+
52 57
 func (b *TestBuild) AsBuild() *buildapi.Build {
53 58
 	return (*buildapi.Build)(b)
54 59
 }
... ...
@@ -661,6 +661,19 @@ type BuildOutput struct {
661 661
 	// up the authentication for executing the Docker push to authentication
662 662
 	// enabled Docker Registry (or Docker Hub).
663 663
 	PushSecret *kapi.LocalObjectReference
664
+
665
+	// ImageLabels define a list of labels that are applied to the resulting image. If there
666
+	// are multiple labels with the same name then the last one in the list is used.
667
+	ImageLabels []ImageLabel
668
+}
669
+
670
+// ImageLabel represents a label applied to the resulting image.
671
+type ImageLabel struct {
672
+	// Name defines the name of the label. It must have non-zero length.
673
+	Name string
674
+
675
+	// Value defines the literal value of the label.
676
+	Value string
664 677
 }
665 678
 
666 679
 // BuildConfig is a template which can be used to create new builds.
... ...
@@ -39,6 +39,7 @@
39 39
 		GitSourceRevision
40 40
 		ImageChangeCause
41 41
 		ImageChangeTrigger
42
+		ImageLabel
42 43
 		ImageSource
43 44
 		ImageSourcePath
44 45
 		JenkinsPipelineBuildStrategy
... ...
@@ -197,47 +198,51 @@ func (m *ImageChangeTrigger) Reset()                    { *m = ImageChangeTrigge
197 197
 func (*ImageChangeTrigger) ProtoMessage()               {}
198 198
 func (*ImageChangeTrigger) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{29} }
199 199
 
200
+func (m *ImageLabel) Reset()                    { *m = ImageLabel{} }
201
+func (*ImageLabel) ProtoMessage()               {}
202
+func (*ImageLabel) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{30} }
203
+
200 204
 func (m *ImageSource) Reset()                    { *m = ImageSource{} }
201 205
 func (*ImageSource) ProtoMessage()               {}
202
-func (*ImageSource) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{30} }
206
+func (*ImageSource) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{31} }
203 207
 
204 208
 func (m *ImageSourcePath) Reset()                    { *m = ImageSourcePath{} }
205 209
 func (*ImageSourcePath) ProtoMessage()               {}
206
-func (*ImageSourcePath) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{31} }
210
+func (*ImageSourcePath) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{32} }
207 211
 
208 212
 func (m *JenkinsPipelineBuildStrategy) Reset()      { *m = JenkinsPipelineBuildStrategy{} }
209 213
 func (*JenkinsPipelineBuildStrategy) ProtoMessage() {}
210 214
 func (*JenkinsPipelineBuildStrategy) Descriptor() ([]byte, []int) {
211
-	return fileDescriptorGenerated, []int{32}
215
+	return fileDescriptorGenerated, []int{33}
212 216
 }
213 217
 
214 218
 func (m *ProxyConfig) Reset()                    { *m = ProxyConfig{} }
215 219
 func (*ProxyConfig) ProtoMessage()               {}
216
-func (*ProxyConfig) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{33} }
220
+func (*ProxyConfig) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{34} }
217 221
 
218 222
 func (m *SecretBuildSource) Reset()                    { *m = SecretBuildSource{} }
219 223
 func (*SecretBuildSource) ProtoMessage()               {}
220
-func (*SecretBuildSource) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{34} }
224
+func (*SecretBuildSource) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{35} }
221 225
 
222 226
 func (m *SecretSpec) Reset()                    { *m = SecretSpec{} }
223 227
 func (*SecretSpec) ProtoMessage()               {}
224
-func (*SecretSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{35} }
228
+func (*SecretSpec) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{36} }
225 229
 
226 230
 func (m *SourceBuildStrategy) Reset()                    { *m = SourceBuildStrategy{} }
227 231
 func (*SourceBuildStrategy) ProtoMessage()               {}
228
-func (*SourceBuildStrategy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{36} }
232
+func (*SourceBuildStrategy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{37} }
229 233
 
230 234
 func (m *SourceControlUser) Reset()                    { *m = SourceControlUser{} }
231 235
 func (*SourceControlUser) ProtoMessage()               {}
232
-func (*SourceControlUser) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{37} }
236
+func (*SourceControlUser) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{38} }
233 237
 
234 238
 func (m *SourceRevision) Reset()                    { *m = SourceRevision{} }
235 239
 func (*SourceRevision) ProtoMessage()               {}
236
-func (*SourceRevision) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{38} }
240
+func (*SourceRevision) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{39} }
237 241
 
238 242
 func (m *WebHookTrigger) Reset()                    { *m = WebHookTrigger{} }
239 243
 func (*WebHookTrigger) ProtoMessage()               {}
240
-func (*WebHookTrigger) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{39} }
244
+func (*WebHookTrigger) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{40} }
241 245
 
242 246
 func init() {
243 247
 	proto.RegisterType((*BinaryBuildRequestOptions)(nil), "github.com.openshift.origin.pkg.build.api.v1.BinaryBuildRequestOptions")
... ...
@@ -270,6 +275,7 @@ func init() {
270 270
 	proto.RegisterType((*GitSourceRevision)(nil), "github.com.openshift.origin.pkg.build.api.v1.GitSourceRevision")
271 271
 	proto.RegisterType((*ImageChangeCause)(nil), "github.com.openshift.origin.pkg.build.api.v1.ImageChangeCause")
272 272
 	proto.RegisterType((*ImageChangeTrigger)(nil), "github.com.openshift.origin.pkg.build.api.v1.ImageChangeTrigger")
273
+	proto.RegisterType((*ImageLabel)(nil), "github.com.openshift.origin.pkg.build.api.v1.ImageLabel")
273 274
 	proto.RegisterType((*ImageSource)(nil), "github.com.openshift.origin.pkg.build.api.v1.ImageSource")
274 275
 	proto.RegisterType((*ImageSourcePath)(nil), "github.com.openshift.origin.pkg.build.api.v1.ImageSourcePath")
275 276
 	proto.RegisterType((*JenkinsPipelineBuildStrategy)(nil), "github.com.openshift.origin.pkg.build.api.v1.JenkinsPipelineBuildStrategy")
... ...
@@ -717,6 +723,18 @@ func (m *BuildOutput) MarshalTo(data []byte) (int, error) {
717 717
 		}
718 718
 		i += n13
719 719
 	}
720
+	if len(m.ImageLabels) > 0 {
721
+		for _, msg := range m.ImageLabels {
722
+			data[i] = 0x1a
723
+			i++
724
+			i = encodeVarintGenerated(data, i, uint64(msg.Size()))
725
+			n, err := msg.MarshalTo(data[i:])
726
+			if err != nil {
727
+				return 0, err
728
+			}
729
+			i += n
730
+		}
731
+	}
720 732
 	return i, nil
721 733
 }
722 734
 
... ...
@@ -1741,6 +1759,32 @@ func (m *ImageChangeTrigger) MarshalTo(data []byte) (int, error) {
1741 1741
 	return i, nil
1742 1742
 }
1743 1743
 
1744
+func (m *ImageLabel) Marshal() (data []byte, err error) {
1745
+	size := m.Size()
1746
+	data = make([]byte, size)
1747
+	n, err := m.MarshalTo(data)
1748
+	if err != nil {
1749
+		return nil, err
1750
+	}
1751
+	return data[:n], nil
1752
+}
1753
+
1754
+func (m *ImageLabel) MarshalTo(data []byte) (int, error) {
1755
+	var i int
1756
+	_ = i
1757
+	var l int
1758
+	_ = l
1759
+	data[i] = 0xa
1760
+	i++
1761
+	i = encodeVarintGenerated(data, i, uint64(len(m.Name)))
1762
+	i += copy(data[i:], m.Name)
1763
+	data[i] = 0x12
1764
+	i++
1765
+	i = encodeVarintGenerated(data, i, uint64(len(m.Value)))
1766
+	i += copy(data[i:], m.Value)
1767
+	return i, nil
1768
+}
1769
+
1744 1770
 func (m *ImageSource) Marshal() (data []byte, err error) {
1745 1771
 	size := m.Size()
1746 1772
 	data = make([]byte, size)
... ...
@@ -2294,6 +2338,12 @@ func (m *BuildOutput) Size() (n int) {
2294 2294
 		l = m.PushSecret.Size()
2295 2295
 		n += 1 + l + sovGenerated(uint64(l))
2296 2296
 	}
2297
+	if len(m.ImageLabels) > 0 {
2298
+		for _, e := range m.ImageLabels {
2299
+			l = e.Size()
2300
+			n += 1 + l + sovGenerated(uint64(l))
2301
+		}
2302
+	}
2297 2303
 	return n
2298 2304
 }
2299 2305
 
... ...
@@ -2679,6 +2729,16 @@ func (m *ImageChangeTrigger) Size() (n int) {
2679 2679
 	return n
2680 2680
 }
2681 2681
 
2682
+func (m *ImageLabel) Size() (n int) {
2683
+	var l int
2684
+	_ = l
2685
+	l = len(m.Name)
2686
+	n += 1 + l + sovGenerated(uint64(l))
2687
+	l = len(m.Value)
2688
+	n += 1 + l + sovGenerated(uint64(l))
2689
+	return n
2690
+}
2691
+
2682 2692
 func (m *ImageSource) Size() (n int) {
2683 2693
 	var l int
2684 2694
 	_ = l
... ...
@@ -2963,6 +3023,7 @@ func (this *BuildOutput) String() string {
2963 2963
 	s := strings.Join([]string{`&BuildOutput{`,
2964 2964
 		`To:` + strings.Replace(fmt.Sprintf("%v", this.To), "ObjectReference", "k8s_io_kubernetes_pkg_api_v1.ObjectReference", 1) + `,`,
2965 2965
 		`PushSecret:` + strings.Replace(fmt.Sprintf("%v", this.PushSecret), "LocalObjectReference", "k8s_io_kubernetes_pkg_api_v1.LocalObjectReference", 1) + `,`,
2966
+		`ImageLabels:` + strings.Replace(strings.Replace(fmt.Sprintf("%v", this.ImageLabels), "ImageLabel", "ImageLabel", 1), `&`, ``, 1) + `,`,
2966 2967
 		`}`,
2967 2968
 	}, "")
2968 2969
 	return s
... ...
@@ -3222,6 +3283,17 @@ func (this *ImageChangeTrigger) String() string {
3222 3222
 	}, "")
3223 3223
 	return s
3224 3224
 }
3225
+func (this *ImageLabel) String() string {
3226
+	if this == nil {
3227
+		return "nil"
3228
+	}
3229
+	s := strings.Join([]string{`&ImageLabel{`,
3230
+		`Name:` + fmt.Sprintf("%v", this.Name) + `,`,
3231
+		`Value:` + fmt.Sprintf("%v", this.Value) + `,`,
3232
+		`}`,
3233
+	}, "")
3234
+	return s
3235
+}
3225 3236
 func (this *ImageSource) String() string {
3226 3237
 	if this == nil {
3227 3238
 		return "nil"
... ...
@@ -4838,6 +4910,37 @@ func (m *BuildOutput) Unmarshal(data []byte) error {
4838 4838
 				return err
4839 4839
 			}
4840 4840
 			iNdEx = postIndex
4841
+		case 3:
4842
+			if wireType != 2 {
4843
+				return fmt.Errorf("proto: wrong wireType = %d for field ImageLabels", wireType)
4844
+			}
4845
+			var msglen int
4846
+			for shift := uint(0); ; shift += 7 {
4847
+				if shift >= 64 {
4848
+					return ErrIntOverflowGenerated
4849
+				}
4850
+				if iNdEx >= l {
4851
+					return io.ErrUnexpectedEOF
4852
+				}
4853
+				b := data[iNdEx]
4854
+				iNdEx++
4855
+				msglen |= (int(b) & 0x7F) << shift
4856
+				if b < 0x80 {
4857
+					break
4858
+				}
4859
+			}
4860
+			if msglen < 0 {
4861
+				return ErrInvalidLengthGenerated
4862
+			}
4863
+			postIndex := iNdEx + msglen
4864
+			if postIndex > l {
4865
+				return io.ErrUnexpectedEOF
4866
+			}
4867
+			m.ImageLabels = append(m.ImageLabels, ImageLabel{})
4868
+			if err := m.ImageLabels[len(m.ImageLabels)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
4869
+				return err
4870
+			}
4871
+			iNdEx = postIndex
4841 4872
 		default:
4842 4873
 			iNdEx = preIndex
4843 4874
 			skippy, err := skipGenerated(data[iNdEx:])
... ...
@@ -8320,6 +8423,114 @@ func (m *ImageChangeTrigger) Unmarshal(data []byte) error {
8320 8320
 	}
8321 8321
 	return nil
8322 8322
 }
8323
+func (m *ImageLabel) Unmarshal(data []byte) error {
8324
+	l := len(data)
8325
+	iNdEx := 0
8326
+	for iNdEx < l {
8327
+		preIndex := iNdEx
8328
+		var wire uint64
8329
+		for shift := uint(0); ; shift += 7 {
8330
+			if shift >= 64 {
8331
+				return ErrIntOverflowGenerated
8332
+			}
8333
+			if iNdEx >= l {
8334
+				return io.ErrUnexpectedEOF
8335
+			}
8336
+			b := data[iNdEx]
8337
+			iNdEx++
8338
+			wire |= (uint64(b) & 0x7F) << shift
8339
+			if b < 0x80 {
8340
+				break
8341
+			}
8342
+		}
8343
+		fieldNum := int32(wire >> 3)
8344
+		wireType := int(wire & 0x7)
8345
+		if wireType == 4 {
8346
+			return fmt.Errorf("proto: ImageLabel: wiretype end group for non-group")
8347
+		}
8348
+		if fieldNum <= 0 {
8349
+			return fmt.Errorf("proto: ImageLabel: illegal tag %d (wire type %d)", fieldNum, wire)
8350
+		}
8351
+		switch fieldNum {
8352
+		case 1:
8353
+			if wireType != 2 {
8354
+				return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
8355
+			}
8356
+			var stringLen uint64
8357
+			for shift := uint(0); ; shift += 7 {
8358
+				if shift >= 64 {
8359
+					return ErrIntOverflowGenerated
8360
+				}
8361
+				if iNdEx >= l {
8362
+					return io.ErrUnexpectedEOF
8363
+				}
8364
+				b := data[iNdEx]
8365
+				iNdEx++
8366
+				stringLen |= (uint64(b) & 0x7F) << shift
8367
+				if b < 0x80 {
8368
+					break
8369
+				}
8370
+			}
8371
+			intStringLen := int(stringLen)
8372
+			if intStringLen < 0 {
8373
+				return ErrInvalidLengthGenerated
8374
+			}
8375
+			postIndex := iNdEx + intStringLen
8376
+			if postIndex > l {
8377
+				return io.ErrUnexpectedEOF
8378
+			}
8379
+			m.Name = string(data[iNdEx:postIndex])
8380
+			iNdEx = postIndex
8381
+		case 2:
8382
+			if wireType != 2 {
8383
+				return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType)
8384
+			}
8385
+			var stringLen uint64
8386
+			for shift := uint(0); ; shift += 7 {
8387
+				if shift >= 64 {
8388
+					return ErrIntOverflowGenerated
8389
+				}
8390
+				if iNdEx >= l {
8391
+					return io.ErrUnexpectedEOF
8392
+				}
8393
+				b := data[iNdEx]
8394
+				iNdEx++
8395
+				stringLen |= (uint64(b) & 0x7F) << shift
8396
+				if b < 0x80 {
8397
+					break
8398
+				}
8399
+			}
8400
+			intStringLen := int(stringLen)
8401
+			if intStringLen < 0 {
8402
+				return ErrInvalidLengthGenerated
8403
+			}
8404
+			postIndex := iNdEx + intStringLen
8405
+			if postIndex > l {
8406
+				return io.ErrUnexpectedEOF
8407
+			}
8408
+			m.Value = string(data[iNdEx:postIndex])
8409
+			iNdEx = postIndex
8410
+		default:
8411
+			iNdEx = preIndex
8412
+			skippy, err := skipGenerated(data[iNdEx:])
8413
+			if err != nil {
8414
+				return err
8415
+			}
8416
+			if skippy < 0 {
8417
+				return ErrInvalidLengthGenerated
8418
+			}
8419
+			if (iNdEx + skippy) > l {
8420
+				return io.ErrUnexpectedEOF
8421
+			}
8422
+			iNdEx += skippy
8423
+		}
8424
+	}
8425
+
8426
+	if iNdEx > l {
8427
+		return io.ErrUnexpectedEOF
8428
+	}
8429
+	return nil
8430
+}
8323 8431
 func (m *ImageSource) Unmarshal(data []byte) error {
8324 8432
 	l := len(data)
8325 8433
 	iNdEx := 0
... ...
@@ -9741,199 +9952,202 @@ var (
9741 9741
 )
9742 9742
 
9743 9743
 var fileDescriptorGenerated = []byte{
9744
-	// 3094 bytes of a gzipped FileDescriptorProto
9745
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe4, 0x1a, 0x4b, 0x6c, 0x24, 0xc5,
9746
-	0x95, 0x9e, 0x19, 0x8f, 0x67, 0x6a, 0xbc, 0xb6, 0xb7, 0xbc, 0xb0, 0x5e, 0x03, 0x0b, 0x34, 0x24,
9747
-	0x22, 0x02, 0x66, 0x64, 0xf3, 0x09, 0x88, 0x4f, 0xf0, 0x8c, 0x77, 0xc1, 0x8e, 0xd9, 0x75, 0x9e,
9748
-	0xcd, 0x27, 0x1b, 0x25, 0x51, 0x7b, 0x5c, 0x33, 0x6e, 0x3c, 0xd3, 0x3d, 0xe9, 0xee, 0x31, 0x58,
9749
-	0x4a, 0x24, 0x94, 0x28, 0x12, 0xb9, 0xe5, 0x77, 0xc8, 0x25, 0x89, 0x90, 0xf2, 0x39, 0x70, 0x88,
9750
-	0xf2, 0x39, 0x20, 0xe5, 0x92, 0x48, 0x39, 0x70, 0xe4, 0x98, 0x13, 0x0a, 0x70, 0xc8, 0x39, 0x57,
9751
-	0x4e, 0xa9, 0xcf, 0xab, 0xee, 0xea, 0x9e, 0xb1, 0x61, 0xda, 0xeb, 0x55, 0xa4, 0x1c, 0xc6, 0x72,
9752
-	0xbf, 0xf7, 0xea, 0xbd, 0xaa, 0x57, 0xaf, 0xde, 0xaf, 0x8a, 0x3c, 0xd3, 0x75, 0xa3, 0xfd, 0xe1,
9753
-	0x6e, 0xbd, 0xed, 0xf7, 0x1b, 0xfe, 0x80, 0x79, 0xe1, 0xbe, 0xdb, 0x89, 0x1a, 0x7e, 0xe0, 0x76,
9754
-	0x5d, 0xaf, 0x31, 0x38, 0xe8, 0x36, 0x76, 0x87, 0x6e, 0x6f, 0xaf, 0xe1, 0x0c, 0xdc, 0xc6, 0xe1,
9755
-	0x72, 0xa3, 0xcb, 0x3c, 0x16, 0x38, 0x11, 0xdb, 0xab, 0x0f, 0x02, 0x3f, 0xf2, 0xe9, 0xc3, 0xc9,
9756
-	0xe8, 0x7a, 0x3c, 0xba, 0xae, 0x46, 0xd7, 0xf9, 0xe8, 0xba, 0x1c, 0x5d, 0xe7, 0xa3, 0xeb, 0x87,
9757
-	0xcb, 0x4b, 0x8f, 0x18, 0xb2, 0xba, 0x7e, 0xd7, 0x6f, 0x48, 0x26, 0xbb, 0xc3, 0x8e, 0xfc, 0x92,
9758
-	0x1f, 0xf2, 0x3f, 0xc5, 0x7c, 0xe9, 0xf1, 0x83, 0x27, 0xc3, 0xba, 0xeb, 0x37, 0x0e, 0x86, 0xbb,
9759
-	0x2c, 0xf0, 0x58, 0xc4, 0x42, 0x39, 0x21, 0x31, 0x95, 0xa1, 0x77, 0xc8, 0x82, 0xd0, 0xf5, 0x3d,
9760
-	0xb6, 0x97, 0x9d, 0xd3, 0xd2, 0xc3, 0xc7, 0x0f, 0x1b, 0x5d, 0xc1, 0xd2, 0x23, 0xe3, 0xa9, 0x83,
9761
-	0xa1, 0x17, 0xb9, 0x7d, 0x36, 0x42, 0xbe, 0x3c, 0x9e, 0x7c, 0x18, 0xb9, 0xbd, 0x86, 0xeb, 0x45,
9762
-	0x61, 0x14, 0x64, 0x87, 0xd8, 0xef, 0x95, 0xc8, 0xa5, 0xa6, 0xeb, 0x39, 0xc1, 0x51, 0x53, 0x28,
9763
-	0x03, 0xd8, 0x77, 0x86, 0x2c, 0x8c, 0xae, 0x0f, 0x22, 0x3e, 0xfd, 0x90, 0xbe, 0x46, 0x2a, 0x7d,
9764
-	0x16, 0x39, 0x7b, 0x4e, 0xe4, 0x2c, 0x5a, 0xf7, 0x5a, 0x0f, 0xd6, 0x56, 0x1e, 0xac, 0x2b, 0x19,
9765
-	0xf5, 0x44, 0x86, 0x54, 0xa5, 0x52, 0x62, 0xfd, 0xfa, 0xee, 0xeb, 0xac, 0x1d, 0xbd, 0xc4, 0xc7,
9766
-	0x34, 0xe9, 0xfb, 0x1f, 0xde, 0x73, 0xdb, 0xc7, 0x1f, 0xde, 0x43, 0x12, 0x18, 0xc4, 0xdc, 0xe8,
9767
-	0x17, 0x49, 0xd9, 0x09, 0xaf, 0xba, 0x3d, 0xb6, 0x58, 0xe0, 0x7c, 0xab, 0xcd, 0x59, 0xa4, 0x2e,
9768
-	0xaf, 0x4a, 0x28, 0x20, 0x96, 0x3e, 0x41, 0x66, 0x03, 0x76, 0xe8, 0x0a, 0x6d, 0xb6, 0xfc, 0x7e,
9769
-	0xdf, 0x8d, 0x16, 0x8b, 0x69, 0x7a, 0x05, 0x85, 0x0c, 0x15, 0x7d, 0x8a, 0xcc, 0x69, 0xc8, 0x4b,
9770
-	0x2c, 0x0c, 0x9d, 0x2e, 0x5b, 0x2c, 0xc9, 0x81, 0x73, 0x38, 0x70, 0x1a, 0xc1, 0x90, 0xa5, 0xa3,
9771
-	0x4d, 0x42, 0x35, 0x68, 0x75, 0x18, 0xed, 0xfb, 0xc1, 0x35, 0xa7, 0xcf, 0x16, 0xa7, 0xe4, 0xe8,
9772
-	0x78, 0x51, 0x09, 0x06, 0xc6, 0x50, 0xd3, 0x2b, 0x64, 0x21, 0x0d, 0xbd, 0xd2, 0x77, 0xdc, 0xde,
9773
-	0x62, 0x59, 0x32, 0x59, 0x40, 0x26, 0x35, 0x03, 0x05, 0xe3, 0xe8, 0xe9, 0x57, 0xc9, 0xed, 0xe9,
9774
-	0x75, 0x45, 0x4c, 0xcd, 0x66, 0x5a, 0x32, 0xba, 0x1d, 0x19, 0x9d, 0x4b, 0x21, 0x61, 0xfc, 0x18,
9775
-	0x7a, 0x8d, 0xdc, 0x31, 0x82, 0x50, 0xd3, 0xaa, 0x48, 0x6e, 0x77, 0x20, 0xb7, 0xd9, 0x34, 0x16,
9776
-	0x8e, 0x19, 0x65, 0x3f, 0x4d, 0xce, 0x1b, 0x96, 0xb3, 0xed, 0x0f, 0x83, 0x36, 0x33, 0xf6, 0xd5,
9777
-	0x3a, 0x69, 0x5f, 0xed, 0x5f, 0x17, 0xc8, 0x94, 0x1c, 0x77, 0x86, 0x36, 0xf6, 0x75, 0x52, 0x0a,
9778
-	0x07, 0xac, 0x2d, 0x2d, 0xac, 0xb6, 0xf2, 0xe5, 0xfa, 0x24, 0xee, 0xa0, 0xae, 0x16, 0xc5, 0x87,
9779
-	0x37, 0x67, 0x50, 0x48, 0x49, 0x7c, 0x81, 0x64, 0x49, 0x1d, 0x52, 0x0e, 0x23, 0x27, 0x1a, 0x86,
9780
-	0xd2, 0x1c, 0x6b, 0x2b, 0x4f, 0xe5, 0x61, 0x2e, 0x19, 0x24, 0x1a, 0x52, 0xdf, 0x80, 0x8c, 0xed,
9781
-	0x3f, 0x16, 0x48, 0x4d, 0xd2, 0xb5, 0x7c, 0xaf, 0xe3, 0x76, 0xcf, 0x50, 0x4f, 0xdf, 0x4e, 0xe9,
9782
-	0xe9, 0xd9, 0x1c, 0x4b, 0x51, 0x53, 0x3c, 0x56, 0x5b, 0xdd, 0x8c, 0xb6, 0xbe, 0x92, 0x5f, 0xc4,
9783
-	0xc9, 0x3a, 0xfb, 0xc0, 0x22, 0x73, 0x06, 0xf5, 0xa6, 0x1b, 0x46, 0xf4, 0x9b, 0x23, 0x7a, 0x6b,
9784
-	0x9c, 0xa0, 0x37, 0xc3, 0x77, 0xd7, 0xc5, 0x70, 0xa9, 0xbe, 0x79, 0x14, 0x57, 0xd1, 0x10, 0x43,
9785
-	0x79, 0xdf, 0x22, 0x53, 0x6e, 0xc4, 0xfa, 0x21, 0xd7, 0x5e, 0x31, 0xa7, 0x21, 0xa8, 0xc9, 0x36,
9786
-	0xcf, 0xa1, 0x94, 0xa9, 0x75, 0xc1, 0x0f, 0x14, 0x5b, 0xfb, 0x4f, 0x85, 0xd4, 0x92, 0x84, 0x56,
9787
-	0xa9, 0x47, 0x2a, 0x11, 0x67, 0xd8, 0xe5, 0x33, 0xe5, 0x4b, 0x12, 0x62, 0x9f, 0xcf, 0x21, 0x76,
9788
-	0x47, 0xb1, 0xd8, 0xf2, 0x7b, 0x6e, 0xfb, 0x28, 0x59, 0x23, 0x82, 0x43, 0x88, 0x65, 0xd0, 0x55,
9789
-	0x52, 0xe5, 0x21, 0x47, 0x11, 0xa2, 0xbf, 0xbe, 0x1f, 0xc9, 0xab, 0xa0, 0x11, 0x9f, 0x72, 0xcf,
9790
-	0xa1, 0x62, 0x88, 0x86, 0x40, 0x32, 0x8a, 0xf6, 0x08, 0xe1, 0x53, 0xeb, 0xfb, 0x9e, 0x58, 0x00,
9791
-	0x9a, 0xc1, 0x93, 0x93, 0x4d, 0xba, 0x15, 0x8f, 0x4f, 0xec, 0x39, 0x81, 0x81, 0xc1, 0xdf, 0xde,
9792
-	0xe0, 0xae, 0x29, 0x6b, 0x34, 0xf4, 0x71, 0x52, 0xeb, 0x39, 0x61, 0xf4, 0x8a, 0xda, 0x5f, 0x69,
9793
-	0x0b, 0xc5, 0xc4, 0x17, 0x6f, 0x26, 0x28, 0x30, 0xe9, 0xec, 0x7f, 0x58, 0xa4, 0x2a, 0x99, 0xdd,
9794
-	0x0a, 0x6b, 0x7a, 0x2d, 0x6d, 0x4d, 0x8f, 0xe6, 0xd8, 0xd6, 0x63, 0xec, 0x88, 0x90, 0x8a, 0x5a,
9795
-	0x85, 0xdf, 0xb5, 0xdf, 0x2e, 0xa1, 0x4d, 0xf1, 0x0f, 0x1d, 0xea, 0x1b, 0xa4, 0xda, 0xf6, 0xbd,
9796
-	0xc8, 0x71, 0x79, 0x7e, 0x80, 0xbe, 0xfb, 0xbc, 0xde, 0xe3, 0x96, 0x46, 0x40, 0x42, 0x23, 0x3c,
9797
-	0x7d, 0xc7, 0xef, 0xf5, 0xfc, 0x37, 0xa4, 0x45, 0x54, 0x92, 0x33, 0x79, 0x55, 0x42, 0x01, 0xb1,
9798
-	0xf4, 0x61, 0x52, 0x19, 0x88, 0x08, 0xe2, 0xe3, 0xf1, 0xaf, 0x24, 0x0a, 0xd8, 0x42, 0x38, 0xc4,
9799
-	0x14, 0xf4, 0x31, 0x32, 0x13, 0xba, 0x5e, 0x9b, 0x6d, 0x33, 0x2e, 0x69, 0x2f, 0x94, 0x41, 0xbb,
9800
-	0xd8, 0x9c, 0xe7, 0xd4, 0x33, 0xdb, 0x06, 0x1c, 0x52, 0x54, 0x5c, 0x6d, 0x55, 0xf9, 0xbd, 0xe3,
9801
-	0x62, 0xa4, 0xae, 0xad, 0x3c, 0xf4, 0x39, 0xb7, 0x45, 0x0c, 0x69, 0x9e, 0x13, 0xab, 0xdc, 0xd6,
9802
-	0x1c, 0x20, 0x61, 0x46, 0x57, 0x08, 0x11, 0xa9, 0x16, 0xf7, 0x2f, 0xfd, 0x41, 0x28, 0xe3, 0x77,
9803
-	0x25, 0xb1, 0xbe, 0x9d, 0x18, 0x03, 0x06, 0x15, 0x7d, 0x88, 0x54, 0xb9, 0x8e, 0x7a, 0x9b, 0x5c,
9804
-	0x4d, 0xa1, 0x8c, 0xd4, 0x45, 0x25, 0x60, 0x47, 0x03, 0x21, 0xc1, 0xd3, 0x3a, 0x21, 0x3d, 0x97,
9805
-	0x87, 0xd5, 0xe6, 0x11, 0x9f, 0xa1, 0x8c, 0xc4, 0xc5, 0xe6, 0xac, 0x60, 0xbe, 0x19, 0x43, 0xc1,
9806
-	0xa0, 0x10, 0x6a, 0xf7, 0xfc, 0x37, 0x1c, 0x9e, 0x08, 0x55, 0xd3, 0x6a, 0xbf, 0xe6, 0xbf, 0xca,
9807
-	0xa1, 0x80, 0x58, 0xfa, 0x05, 0x32, 0x8d, 0x8b, 0x5c, 0x24, 0x92, 0x69, 0x4d, 0x24, 0x3d, 0xda,
9808
-	0xc2, 0x35, 0xce, 0x7e, 0xcf, 0xc2, 0x28, 0x73, 0x7d, 0x18, 0x0d, 0x86, 0x11, 0x4f, 0x5c, 0x0a,
9809
-	0x91, 0x8f, 0x96, 0xfd, 0xc8, 0xe7, 0x89, 0x2f, 0xc0, 0x3a, 0x2c, 0x60, 0x5c, 0x5d, 0xcd, 0x32,
9810
-	0x17, 0x50, 0xd8, 0xf1, 0x81, 0x33, 0xa0, 0xbb, 0x84, 0x0c, 0x86, 0xe1, 0x3e, 0xdf, 0x9f, 0x80,
9811
-	0x45, 0x18, 0x58, 0x56, 0x4e, 0x66, 0xb7, 0xe9, 0xb7, 0x9d, 0x5e, 0x96, 0xa7, 0xd4, 0xc4, 0x56,
9812
-	0xcc, 0x09, 0x0c, 0xae, 0xf6, 0xf7, 0x2d, 0xb2, 0x20, 0xa7, 0xbe, 0xe5, 0x87, 0x91, 0xca, 0x4d,
9813
-	0xa4, 0x77, 0xe4, 0x2b, 0x17, 0xae, 0xc0, 0xf1, 0xf6, 0xa4, 0x73, 0xac, 0xaa, 0x95, 0xb7, 0x14,
9814
-	0x08, 0x34, 0x8e, 0xde, 0x45, 0x4a, 0x4e, 0xd0, 0x55, 0x27, 0xad, 0xda, 0xac, 0x88, 0x90, 0xb5,
9815
-	0xca, 0xbf, 0x41, 0x42, 0x85, 0x9a, 0xc3, 0x76, 0xe0, 0x0e, 0x46, 0xf2, 0xcd, 0x6d, 0x09, 0x05,
9816
-	0xc4, 0xda, 0x9f, 0x4c, 0x91, 0x19, 0x33, 0x73, 0x3e, 0xc3, 0x30, 0xdd, 0x21, 0x15, 0x9d, 0x89,
9817
-	0xa1, 0x46, 0x9f, 0x99, 0xcc, 0x3d, 0xa8, 0x14, 0x0d, 0x90, 0x47, 0x73, 0x46, 0x1c, 0x41, 0xfd,
9818
-	0x05, 0x31, 0x6f, 0xea, 0x93, 0x79, 0xf4, 0xfc, 0x6c, 0xaf, 0x79, 0xb4, 0xde, 0x17, 0xb9, 0x73,
9819
-	0x31, 0x8f, 0x41, 0x5c, 0xe0, 0x02, 0xe6, 0x77, 0x32, 0xac, 0x60, 0x84, 0x39, 0xcf, 0x72, 0x4b,
9820
-	0x9d, 0xc0, 0xef, 0xcb, 0xb3, 0x3e, 0xb1, 0x10, 0xb9, 0x71, 0x57, 0xf9, 0x70, 0x90, 0x4c, 0x68,
9821
-	0x9b, 0x94, 0x77, 0x65, 0x56, 0x8a, 0x7e, 0x60, 0xd2, 0x5c, 0x23, 0x9b, 0xd1, 0x36, 0x89, 0xd8,
9822
-	0x75, 0x05, 0x06, 0x64, 0x4d, 0x97, 0xd3, 0xa1, 0xa4, 0x2c, 0x0f, 0xd8, 0xdc, 0x49, 0x61, 0x84,
9823
-	0xb6, 0x48, 0x91, 0x79, 0x87, 0xdc, 0x1d, 0x08, 0xbf, 0xfe, 0xc0, 0xc9, 0x6b, 0xbc, 0xe2, 0x1d,
9824
-	0xbe, 0xe2, 0x04, 0xcd, 0x1a, 0x9a, 0x43, 0x91, 0x7f, 0x83, 0x18, 0x4d, 0x0f, 0x49, 0xcd, 0xd0,
9825
-	0x1e, 0xf7, 0x16, 0xc5, 0x9c, 0xd9, 0x14, 0xee, 0x4a, 0xcb, 0x19, 0x86, 0x2c, 0x89, 0x81, 0xc6,
9826
-	0x5e, 0x81, 0x29, 0xc8, 0xfe, 0xe5, 0x14, 0x7a, 0x09, 0xcc, 0xf2, 0x1f, 0x25, 0xa5, 0xe8, 0x68,
9827
-	0xa0, 0x73, 0xfc, 0x7b, 0x74, 0xca, 0xb7, 0xc3, 0x61, 0x3c, 0x0d, 0x98, 0x33, 0x48, 0x05, 0x08,
9828
-	0x24, 0xb1, 0xb1, 0x33, 0x85, 0xb3, 0xdb, 0x19, 0xee, 0x4e, 0xf7, 0xfc, 0xf6, 0x01, 0x0b, 0x3a,
9829
-	0xa2, 0x06, 0xc1, 0xb3, 0x2b, 0x8e, 0xd4, 0x5a, 0x0c, 0x05, 0x83, 0x82, 0xbe, 0x4a, 0x8a, 0x7c,
9830
-	0x16, 0x68, 0x7a, 0x13, 0x9e, 0xa7, 0x17, 0xb8, 0x4f, 0x36, 0xa6, 0x33, 0x2d, 0xb6, 0x8a, 0xc3,
9831
-	0x40, 0x70, 0x14, 0x15, 0x82, 0x2b, 0xac, 0x3b, 0xe4, 0x76, 0x98, 0x23, 0x31, 0x94, 0x27, 0x03,
9832
-	0x19, 0xc7, 0xbe, 0x47, 0x02, 0x79, 0xb6, 0xab, 0x18, 0x8b, 0xd8, 0x24, 0xc2, 0x31, 0x7b, 0x33,
9833
-	0x5a, 0x73, 0x03, 0xac, 0x2d, 0x8d, 0xcc, 0x48, 0x63, 0xc0, 0xa0, 0xa2, 0xfb, 0x3c, 0xbe, 0x4a,
9834
-	0xae, 0xe8, 0x9a, 0xa7, 0x73, 0xbb, 0x66, 0x15, 0x93, 0x0d, 0x5e, 0x90, 0xe2, 0x4c, 0x5f, 0x27,
9835
-	0xd3, 0xa1, 0xfc, 0x2f, 0xcc, 0x67, 0xa7, 0x8a, 0x8d, 0xa9, 0xe0, 0xb8, 0x74, 0x57, 0xa8, 0x10,
9836
-	0xb4, 0x00, 0xfb, 0x3f, 0x3a, 0x47, 0x93, 0x01, 0x20, 0x9d, 0x6b, 0x5a, 0x67, 0x9b, 0x6b, 0x66,
9837
-	0xcf, 0x64, 0xe1, 0x56, 0x9d, 0xc9, 0x77, 0xe3, 0x33, 0xa9, 0xd2, 0xdb, 0x65, 0x32, 0x35, 0xd8,
9838
-	0x77, 0x42, 0x7d, 0x28, 0xef, 0xd4, 0x59, 0xe0, 0x96, 0x00, 0xf2, 0x53, 0x49, 0x54, 0xac, 0x14,
9839
-	0x5f, 0xa0, 0x28, 0x65, 0xce, 0xe7, 0xf0, 0xbd, 0xec, 0xf5, 0xd8, 0x1e, 0x66, 0x71, 0x49, 0xce,
9840
-	0xa7, 0x11, 0x90, 0xd0, 0xd0, 0x27, 0x48, 0x39, 0x60, 0x4e, 0xc8, 0x5d, 0x9e, 0x3a, 0x59, 0x97,
9841
-	0xb5, 0x65, 0x82, 0x84, 0x7e, 0x2a, 0x2c, 0x42, 0x55, 0x64, 0xf2, 0x1b, 0x90, 0x9a, 0x7e, 0x89,
9842
-	0x4c, 0xf7, 0x4f, 0xee, 0xc2, 0x68, 0x3c, 0xaf, 0x15, 0x67, 0x79, 0x1a, 0x15, 0x44, 0x71, 0x6e,
9843
-	0x95, 0x27, 0x9f, 0xa3, 0xa2, 0x8d, 0xb1, 0x9d, 0x62, 0x03, 0x19, 0xb6, 0x7c, 0xdf, 0x16, 0xf8,
9844
-	0xe6, 0x0c, 0x7a, 0x4c, 0xe4, 0xbf, 0x89, 0xb4, 0xf2, 0xe4, 0xd2, 0x2e, 0x72, 0x69, 0x0b, 0xad,
9845
-	0x51, 0x5e, 0x30, 0x4e, 0x00, 0x7d, 0x96, 0x54, 0xf6, 0x86, 0x81, 0x23, 0x80, 0x98, 0x1c, 0xde,
9846
-	0xa7, 0xf3, 0xe1, 0x35, 0x84, 0x73, 0x3d, 0x9e, 0x13, 0xf9, 0x64, 0x5d, 0x03, 0x20, 0x1e, 0xc2,
9847
-	0x33, 0xab, 0x25, 0x5f, 0xa6, 0x6a, 0xca, 0xa1, 0xa9, 0x98, 0xaa, 0x0f, 0x25, 0x76, 0x72, 0x6c,
9848
-	0x64, 0xb8, 0x74, 0xfd, 0x58, 0x4a, 0x38, 0x81, 0x0b, 0xfd, 0x1a, 0x29, 0xb7, 0x65, 0xe5, 0x24,
9849
-	0x73, 0xcc, 0x89, 0x43, 0x32, 0x51, 0x7d, 0x39, 0xc1, 0x00, 0x90, 0x91, 0xfd, 0xef, 0x12, 0x39,
9850
-	0x87, 0xd6, 0x2a, 0xda, 0x8f, 0xdd, 0x23, 0x5e, 0x8e, 0x99, 0x31, 0xe4, 0xbe, 0x4c, 0x0c, 0x39,
9851
-	0x9f, 0x22, 0x36, 0xa2, 0xc8, 0xf7, 0xc8, 0xac, 0x72, 0xdf, 0x1a, 0x87, 0xd1, 0x64, 0x75, 0xb2,
9852
-	0x13, 0xa7, 0xd6, 0x9d, 0x12, 0xa2, 0xac, 0x66, 0x2d, 0xc5, 0x1c, 0x32, 0xc2, 0x84, 0x78, 0xf4,
9853
-	0x72, 0x5a, 0x7c, 0x31, 0x8f, 0x78, 0xf4, 0x68, 0xa3, 0xe2, 0xb7, 0x53, 0xcc, 0x21, 0x23, 0x4c,
9854
-	0x88, 0x6f, 0x0f, 0xc3, 0xc8, 0xef, 0xc7, 0xe2, 0x4b, 0x79, 0xc4, 0xb7, 0x24, 0x8f, 0x31, 0xe2,
9855
-	0x5b, 0x29, 0xe6, 0x90, 0x11, 0x46, 0xdf, 0xb1, 0xc8, 0xc5, 0xd7, 0x99, 0x77, 0xe0, 0x7a, 0xe1,
9856
-	0x96, 0x3b, 0x60, 0x3d, 0x5e, 0xc1, 0xc4, 0x13, 0x51, 0xc7, 0x74, 0x63, 0xb2, 0x89, 0x6c, 0xa4,
9857
-	0x99, 0xa5, 0x67, 0x74, 0x27, 0x9f, 0xd1, 0xc5, 0x8d, 0xf1, 0xe2, 0xe0, 0xb8, 0x79, 0xd8, 0x7f,
9858
-	0x2d, 0x62, 0xf1, 0x6f, 0xfa, 0x53, 0xd3, 0x03, 0x59, 0x9f, 0xe1, 0x81, 0xb8, 0x8e, 0x65, 0x97,
9859
-	0xdc, 0x6d, 0xbf, 0xca, 0x76, 0x5f, 0xf4, 0xfd, 0x83, 0x7c, 0x16, 0xf6, 0x42, 0x8a, 0x87, 0xf2,
9860
-	0xea, 0x52, 0xc7, 0x69, 0x04, 0x64, 0x84, 0xd1, 0x23, 0x72, 0x4e, 0xc9, 0xd1, 0xd2, 0x95, 0x81,
9861
-	0x3d, 0x3f, 0x71, 0x6e, 0xf2, 0x62, 0xcc, 0x42, 0x09, 0x3f, 0x2f, 0x3a, 0xc5, 0x29, 0x38, 0xa4,
9862
-	0x25, 0xd1, 0xb7, 0x2c, 0x32, 0x2f, 0x73, 0x8b, 0xd6, 0xbe, 0xe3, 0x75, 0xd5, 0x6e, 0xa0, 0x81,
9863
-	0x3d, 0x97, 0x23, 0x7d, 0x51, 0x5c, 0x94, 0x70, 0x59, 0x0b, 0xac, 0x67, 0x78, 0xc3, 0x88, 0x34,
9864
-	0xfb, 0xe7, 0x45, 0x42, 0x47, 0xbb, 0x53, 0xf4, 0xb1, 0x94, 0xb3, 0xb8, 0x37, 0xe3, 0x2c, 0xe6,
9865
-	0xcd, 0x11, 0x86, 0xaf, 0xe8, 0x92, 0xb2, 0x9a, 0x75, 0xbe, 0x7a, 0x09, 0xd5, 0x82, 0x7c, 0xc7,
9866
-	0xe9, 0x0f, 0xd9, 0x8b, 0x5c, 0x07, 0x77, 0x11, 0x77, 0xeb, 0x74, 0x92, 0xc6, 0x99, 0x89, 0x16,
9867
-	0x40, 0x43, 0x52, 0x33, 0xb4, 0x86, 0xdb, 0xf3, 0x7c, 0xee, 0xed, 0xd1, 0x32, 0x65, 0xf5, 0x62,
9868
-	0xc0, 0xc1, 0x94, 0x62, 0xff, 0xaa, 0x4c, 0x8c, 0xfc, 0x87, 0x3e, 0xc7, 0xbd, 0x20, 0x0b, 0x0e,
9869
-	0xdd, 0x36, 0x5b, 0x6d, 0xb7, 0xfd, 0xa1, 0x17, 0xe1, 0xc6, 0xc4, 0x57, 0x08, 0xdb, 0x29, 0x2c,
9870
-	0x64, 0xa8, 0x65, 0xfb, 0x5c, 0x3a, 0x36, 0xdc, 0x98, 0x5c, 0xed, 0xf3, 0x4c, 0x72, 0x8c, 0xd5,
9871
-	0x2d, 0x32, 0x4e, 0x55, 0xcb, 0xc5, 0x33, 0xac, 0x96, 0x5d, 0x52, 0x09, 0xd3, 0xbe, 0xf8, 0xe9,
9872
-	0x5c, 0x77, 0x01, 0xe8, 0xf3, 0xe2, 0xde, 0x58, 0xec, 0xe8, 0x62, 0xf6, 0x42, 0x6b, 0x2a, 0x68,
9873
-	0xa3, 0xaf, 0xcd, 0xa3, 0x35, 0x95, 0x11, 0x24, 0x5a, 0x53, 0xdf, 0x80, 0x8c, 0x79, 0x8d, 0x56,
9874
-	0x0d, 0x98, 0xd2, 0x60, 0x88, 0xa9, 0xd0, 0x67, 0xd4, 0x06, 0x80, 0xe4, 0xa2, 0xff, 0xe1, 0x06,
9875
-	0xac, 0xcf, 0xbc, 0x28, 0x4c, 0xb2, 0x48, 0x8d, 0x0d, 0x21, 0xe1, 0x4b, 0x87, 0x84, 0x0c, 0xe2,
9876
-	0x96, 0x0d, 0x56, 0x20, 0xab, 0x39, 0xd6, 0x92, 0xee, 0xfb, 0x24, 0x89, 0x7a, 0x02, 0x07, 0x43,
9877
-	0x10, 0xfd, 0x06, 0xb9, 0x94, 0xe4, 0x63, 0x6b, 0xcc, 0xd9, 0x93, 0x61, 0x03, 0xfb, 0x8c, 0xaa,
9878
-	0xf1, 0x76, 0x37, 0x1f, 0x7e, 0xa9, 0x75, 0x1c, 0x11, 0x1c, 0x3f, 0xde, 0xfe, 0x4b, 0x89, 0x2c,
9879
-	0x8c, 0x89, 0xaa, 0xf4, 0x3a, 0xf6, 0x36, 0x72, 0x75, 0xd4, 0xe2, 0xbb, 0x14, 0xa3, 0xbf, 0x21,
9880
-	0x3b, 0x6b, 0xbd, 0xde, 0xcd, 0xea, 0xac, 0x69, 0x4e, 0x60, 0x70, 0xd5, 0xbd, 0x8a, 0xe2, 0xa9,
9881
-	0x7a, 0x15, 0x1b, 0x84, 0xb2, 0x37, 0xb9, 0xfa, 0x19, 0x66, 0x54, 0xe2, 0xaf, 0x2a, 0xb4, 0x2b,
9882
-	0xcd, 0x25, 0xa4, 0xa6, 0x57, 0x46, 0x28, 0x60, 0xcc, 0x28, 0x51, 0xa8, 0x74, 0x7c, 0x6e, 0x3b,
9883
-	0x62, 0xbe, 0xd2, 0xf8, 0x8d, 0x42, 0xe5, 0xaa, 0x46, 0x40, 0x42, 0xc3, 0xed, 0x38, 0x2e, 0x3e,
9884
-	0xcb, 0x72, 0x15, 0x4f, 0xe6, 0x29, 0x3e, 0xa5, 0x59, 0x1d, 0x5b, 0x75, 0xd2, 0x55, 0x32, 0x27,
9885
-	0x07, 0xad, 0x6e, 0xad, 0xeb, 0x4e, 0x90, 0xba, 0x97, 0xbd, 0x88, 0x43, 0x54, 0x23, 0x24, 0x41,
9886
-	0x43, 0x96, 0xde, 0xfe, 0x7d, 0x91, 0x2c, 0x8c, 0x49, 0x45, 0xe3, 0x96, 0x98, 0x75, 0x33, 0x5a,
9887
-	0x62, 0xb7, 0xc2, 0x64, 0x78, 0x7e, 0xe5, 0xf9, 0x2d, 0xa7, 0xbd, 0xcf, 0xb0, 0xc9, 0x1f, 0xab,
9888
-	0xed, 0x9a, 0x02, 0x83, 0xc6, 0x6b, 0xeb, 0x2a, 0x9d, 0xca, 0xba, 0x26, 0xb6, 0x88, 0xe7, 0x74,
9889
-	0xdd, 0x20, 0xda, 0x3e, 0x5b, 0x4e, 0xb4, 0x8f, 0x0d, 0x93, 0x38, 0x64, 0xad, 0xa5, 0xb0, 0x90,
9890
-	0xa1, 0xb6, 0x7f, 0x6b, 0x91, 0x85, 0x31, 0x29, 0x5d, 0x2a, 0xce, 0x58, 0x67, 0x18, 0x67, 0x44,
9891
-	0x43, 0x3a, 0xd9, 0x40, 0xb3, 0x21, 0xad, 0x36, 0x03, 0xb1, 0xf6, 0x47, 0x23, 0xf3, 0xbc, 0x72,
9892
-	0xc8, 0x7d, 0x72, 0xbe, 0x96, 0xdd, 0x96, 0xea, 0x8e, 0x29, 0x93, 0x79, 0x7c, 0xe2, 0x0c, 0x74,
9893
-	0xdd, 0xeb, 0xf8, 0x99, 0xb6, 0xd8, 0xcd, 0x70, 0x2d, 0xf6, 0xdf, 0x2c, 0x32, 0x9b, 0x6e, 0xbe,
9894
-	0xd1, 0xbb, 0x49, 0x71, 0x18, 0xb8, 0xb8, 0xba, 0x78, 0xc4, 0xcb, 0xb0, 0x0e, 0x02, 0x2e, 0xd0,
9895
-	0x01, 0xeb, 0xa0, 0xea, 0x62, 0x34, 0x37, 0x6d, 0x10, 0x70, 0x3a, 0x20, 0xb5, 0x41, 0xe0, 0xbf,
9896
-	0x79, 0xa4, 0x8a, 0xd6, 0x7c, 0x77, 0xfa, 0x5b, 0x09, 0x83, 0xa4, 0x7b, 0x63, 0x00, 0xc1, 0x14,
9897
-	0x61, 0xff, 0xc6, 0x22, 0x74, 0x34, 0x47, 0xff, 0x9f, 0xb3, 0xa6, 0x9f, 0x16, 0xc8, 0x34, 0x6e,
9898
-	0x24, 0xfd, 0x2e, 0xaf, 0x8b, 0x52, 0x4a, 0xcf, 0x37, 0xc3, 0x4c, 0xd7, 0x34, 0x3e, 0x7f, 0x69,
9899
-	0x38, 0x64, 0x64, 0xd1, 0xb7, 0x2d, 0x72, 0x9e, 0x83, 0xd2, 0xeb, 0xcb, 0xd7, 0x49, 0x7e, 0x21,
9900
-	0xcb, 0xa6, 0x79, 0x09, 0x27, 0x71, 0x7e, 0x04, 0x05, 0xa3, 0x42, 0xed, 0xbf, 0x17, 0xc8, 0x28,
9901
-	0xa1, 0x50, 0x69, 0x5b, 0x65, 0x34, 0xd6, 0xd8, 0x17, 0x4a, 0x88, 0x15, 0x45, 0x89, 0x23, 0x9f,
9902
-	0xf8, 0xe4, 0x9b, 0xbc, 0x92, 0x2a, 0xba, 0xbb, 0x81, 0xdf, 0x7b, 0x99, 0xe7, 0xd5, 0xc6, 0x13,
9903
-	0x1b, 0xc9, 0x16, 0x90, 0x3d, 0x37, 0xea, 0x6a, 0x5b, 0xbf, 0xd8, 0xc9, 0xf7, 0xf0, 0x62, 0x54,
9904
-	0x96, 0x71, 0x25, 0x8c, 0x9c, 0x21, 0x11, 0x32, 0x41, 0x9b, 0xcf, 0xfe, 0x19, 0x2f, 0x35, 0xb3,
9905
-	0x45, 0xa2, 0x18, 0x2f, 0x8b, 0x8e, 0xf5, 0xb5, 0x6c, 0x91, 0xbe, 0xae, 0xc0, 0xa0, 0xf1, 0x74,
9906
-	0x87, 0x4c, 0x8b, 0xd8, 0x06, 0x78, 0xa8, 0x27, 0x8e, 0x91, 0xf2, 0x4e, 0xf0, 0xaa, 0xe2, 0x00,
9907
-	0x9a, 0x95, 0xfd, 0x67, 0x7e, 0x2a, 0x47, 0x6b, 0x23, 0xee, 0x06, 0x2f, 0x88, 0xab, 0x9c, 0xb8,
9908
-	0x15, 0xbb, 0x9e, 0x9a, 0xe4, 0x5d, 0x38, 0xc9, 0x0b, 0x9b, 0x63, 0x68, 0x60, 0xec, 0xc8, 0x38,
9909
-	0xbe, 0x17, 0x6e, 0x42, 0x7c, 0xb7, 0x7f, 0x57, 0x20, 0x35, 0xe3, 0xbe, 0xe0, 0x2c, 0x72, 0xce,
9910
-	0xa9, 0x01, 0x8f, 0x81, 0xfa, 0x55, 0xc2, 0xb3, 0xb9, 0xaf, 0x32, 0x44, 0x24, 0x4d, 0xde, 0x27,
9911
-	0x88, 0xaf, 0x10, 0x14, 0xeb, 0x4c, 0x92, 0x52, 0x3c, 0x8b, 0x24, 0xc5, 0xfe, 0xa1, 0x45, 0xe6,
9912
-	0x32, 0xb3, 0x11, 0x97, 0x28, 0x61, 0xfc, 0x85, 0x3b, 0x1a, 0x57, 0x12, 0x09, 0x1d, 0x18, 0x54,
9913
-	0x32, 0x97, 0x60, 0x61, 0xe4, 0x7a, 0xb2, 0x25, 0x2b, 0x2e, 0x5f, 0x0a, 0x99, 0x5c, 0x22, 0x85,
9914
-	0x85, 0x0c, 0xb5, 0xfd, 0x0b, 0x8b, 0xdc, 0x75, 0x52, 0xe7, 0x4b, 0x64, 0x96, 0xd8, 0xde, 0x8a,
9915
-	0xb3, 0x15, 0x2b, 0x9d, 0x59, 0x6e, 0xa4, 0xd1, 0x90, 0xa5, 0x17, 0xaf, 0x5d, 0x0c, 0x10, 0x4e,
9916
-	0x30, 0x8e, 0x4b, 0xc6, 0x70, 0x30, 0xe9, 0xec, 0x9f, 0x58, 0xc4, 0x0c, 0x5a, 0xe2, 0x2d, 0xc3,
9917
-	0x7e, 0x14, 0x0d, 0x24, 0x08, 0x9b, 0xfe, 0xf2, 0x2d, 0xc3, 0x8b, 0x3b, 0x3b, 0x5b, 0x12, 0x08,
9918
-	0x09, 0x5e, 0x5c, 0xbe, 0x89, 0x8f, 0x50, 0x51, 0x97, 0x92, 0xcb, 0x37, 0x41, 0xbd, 0xad, 0xc8,
9919
-	0x0d, 0x0a, 0x71, 0x53, 0xef, 0xf9, 0x8a, 0x58, 0x3d, 0xaf, 0xac, 0xa9, 0x84, 0x51, 0x51, 0x6a,
9920
-	0x9c, 0xfd, 0x07, 0xee, 0xfa, 0x47, 0x6e, 0x83, 0xe8, 0x8d, 0x38, 0x84, 0x59, 0xf9, 0x8d, 0x65,
9921
-	0x7c, 0xd8, 0x3b, 0xf5, 0x06, 0xbf, 0x6b, 0x11, 0x92, 0x94, 0x10, 0xb4, 0x47, 0x66, 0x14, 0xe3,
9922
-	0x54, 0xdc, 0xcc, 0x33, 0xe1, 0x0b, 0x38, 0x81, 0x99, 0x6d, 0x83, 0x1f, 0xa4, 0xb8, 0x8b, 0xd4,
9923
-	0xb8, 0x2f, 0xba, 0x2c, 0xd2, 0x6c, 0x0a, 0xe9, 0x97, 0x3c, 0x2f, 0x69, 0x04, 0x24, 0x34, 0xf6,
9924
-	0x8f, 0xa6, 0xc8, 0xc2, 0x98, 0x86, 0xf4, 0xff, 0x71, 0xed, 0xca, 0x03, 0x91, 0x7a, 0xdf, 0x11,
9925
-	0x66, 0x03, 0x99, 0x7a, 0xfe, 0x21, 0x8a, 0x40, 0xf5, 0x8f, 0x78, 0x0a, 0xe0, 0x7a, 0x6d, 0xd5,
9926
-	0xf8, 0x70, 0x74, 0x29, 0xa2, 0x9a, 0x69, 0x09, 0x18, 0x4c, 0x9a, 0x74, 0xed, 0x52, 0xfe, 0x5c,
9927
-	0xd5, 0xec, 0x0c, 0x3e, 0xf9, 0x56, 0xaf, 0x31, 0xa6, 0xf3, 0x6c, 0x88, 0xbc, 0xaf, 0x05, 0x83,
9928
-	0x0d, 0xa4, 0x98, 0xd2, 0x1f, 0xf0, 0x88, 0x8c, 0x80, 0xd5, 0x20, 0x72, 0x3b, 0x4e, 0x3b, 0xbe,
9929
-	0xb9, 0x3d, 0xa5, 0xc3, 0x5f, 0xc4, 0xc5, 0xcd, 0x43, 0x86, 0x3d, 0x8c, 0x08, 0xb4, 0x6f, 0xf0,
9930
-	0xa3, 0x9e, 0xcd, 0x3a, 0xe8, 0xbd, 0xa4, 0xe4, 0x89, 0x57, 0xcf, 0xca, 0x07, 0xc6, 0x96, 0x25,
9931
-	0x1f, 0x3b, 0x4b, 0x0c, 0xbd, 0x9f, 0x4c, 0x31, 0xf9, 0x94, 0x59, 0xd9, 0x7b, 0x1c, 0x62, 0xd4,
9932
-	0x0b, 0x66, 0x85, 0xb3, 0xdf, 0xe1, 0x65, 0x43, 0x26, 0x69, 0xcb, 0x55, 0x15, 0xdd, 0x30, 0xab,
9933
-	0xa2, 0x53, 0xe7, 0x9e, 0xa9, 0xfa, 0xc8, 0xee, 0x90, 0xd9, 0x74, 0x33, 0xd8, 0x48, 0xd5, 0xad,
9934
-	0x93, 0x52, 0x75, 0xf1, 0xce, 0xce, 0x11, 0x0f, 0xee, 0xb8, 0x11, 0xe3, 0x5d, 0x6e, 0xdc, 0x4b,
9935
-	0x5c, 0x45, 0x38, 0xc4, 0x14, 0xcd, 0x07, 0xde, 0xff, 0xe8, 0xf2, 0x6d, 0x1f, 0xf0, 0xdf, 0x3f,
9936
-	0xf9, 0xef, 0xad, 0x8f, 0x2f, 0x5b, 0xef, 0xf3, 0xdf, 0x07, 0xfc, 0xf7, 0x2f, 0xfe, 0xfb, 0xf1,
9937
-	0x27, 0x97, 0x6f, 0xbb, 0x51, 0x38, 0x5c, 0xfe, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfb, 0xcd,
9938
-	0xf3, 0xee, 0x80, 0x31, 0x00, 0x00,
9744
+	// 3141 bytes of a gzipped FileDescriptorProto
9745
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe4, 0x1a, 0x4b, 0x6c, 0x24, 0x47,
9746
+	0x35, 0x3d, 0x33, 0x1e, 0xcf, 0xd4, 0x78, 0x6d, 0x6f, 0x79, 0x93, 0xf5, 0x3a, 0xc9, 0x26, 0xe9,
9747
+	0x04, 0x14, 0x94, 0x64, 0x46, 0x76, 0x3e, 0x24, 0xca, 0x87, 0x78, 0xc6, 0xbb, 0x89, 0x8d, 0xb3,
9748
+	0x6b, 0x9e, 0x9d, 0x0f, 0x8b, 0x00, 0xb5, 0xc7, 0x35, 0xe3, 0x8e, 0x67, 0xba, 0x87, 0xee, 0x1e,
9749
+	0x27, 0x96, 0x40, 0x8a, 0x40, 0x48, 0xe1, 0xc6, 0xef, 0xc0, 0x05, 0x50, 0x24, 0x3e, 0x42, 0x39,
9750
+	0x20, 0x3e, 0x07, 0x24, 0x2e, 0x20, 0x71, 0xc8, 0x31, 0x47, 0x4e, 0x11, 0x49, 0x0e, 0x9c, 0xb9,
9751
+	0xe6, 0x44, 0x7d, 0x5e, 0x75, 0x57, 0xf7, 0x8c, 0x9d, 0x9d, 0xf6, 0x3a, 0x42, 0xe2, 0x30, 0x96,
9752
+	0xfb, 0xbd, 0x57, 0xef, 0x55, 0xbd, 0x7a, 0xf5, 0x7e, 0x55, 0xe4, 0x99, 0xae, 0x1b, 0xed, 0x0f,
9753
+	0x77, 0xeb, 0x6d, 0xbf, 0xdf, 0xf0, 0x07, 0xcc, 0x0b, 0xf7, 0xdd, 0x4e, 0xd4, 0xf0, 0x03, 0xb7,
9754
+	0xeb, 0x7a, 0x8d, 0xc1, 0x41, 0xb7, 0xb1, 0x3b, 0x74, 0x7b, 0x7b, 0x0d, 0x67, 0xe0, 0x36, 0x0e,
9755
+	0x97, 0x1b, 0x5d, 0xe6, 0xb1, 0xc0, 0x89, 0xd8, 0x5e, 0x7d, 0x10, 0xf8, 0x91, 0x4f, 0x1f, 0x4e,
9756
+	0x46, 0xd7, 0xe3, 0xd1, 0x75, 0x35, 0xba, 0xce, 0x47, 0xd7, 0xe5, 0xe8, 0x3a, 0x1f, 0x5d, 0x3f,
9757
+	0x5c, 0x5e, 0x7a, 0xc4, 0x90, 0xd5, 0xf5, 0xbb, 0x7e, 0x43, 0x32, 0xd9, 0x1d, 0x76, 0xe4, 0x97,
9758
+	0xfc, 0x90, 0xff, 0x29, 0xe6, 0x4b, 0x8f, 0x1f, 0x3c, 0x19, 0xd6, 0x5d, 0xbf, 0x71, 0x30, 0xdc,
9759
+	0x65, 0x81, 0xc7, 0x22, 0x16, 0xca, 0x09, 0x89, 0xa9, 0x0c, 0xbd, 0x43, 0x16, 0x84, 0xae, 0xef,
9760
+	0xb1, 0xbd, 0xec, 0x9c, 0x96, 0x1e, 0x3e, 0x7e, 0xd8, 0xe8, 0x0a, 0x96, 0x1e, 0x19, 0x4f, 0x1d,
9761
+	0x0c, 0xbd, 0xc8, 0xed, 0xb3, 0x11, 0xf2, 0xe5, 0xf1, 0xe4, 0xc3, 0xc8, 0xed, 0x35, 0x5c, 0x2f,
9762
+	0x0a, 0xa3, 0x20, 0x3b, 0xc4, 0xfe, 0x4b, 0x89, 0x5c, 0x6a, 0xba, 0x9e, 0x13, 0x1c, 0x35, 0x85,
9763
+	0x32, 0x80, 0x7d, 0x6b, 0xc8, 0xc2, 0xe8, 0xfa, 0x20, 0xe2, 0xd3, 0x0f, 0xe9, 0x6b, 0xa4, 0xd2,
9764
+	0x67, 0x91, 0xb3, 0xe7, 0x44, 0xce, 0xa2, 0x75, 0xaf, 0xf5, 0x60, 0x6d, 0xe5, 0xc1, 0xba, 0x92,
9765
+	0x51, 0x4f, 0x64, 0x48, 0x55, 0x2a, 0x25, 0xd6, 0xaf, 0xef, 0xbe, 0xce, 0xda, 0xd1, 0x4b, 0x7c,
9766
+	0x4c, 0x93, 0xbe, 0xf7, 0xc1, 0x3d, 0xb7, 0x7d, 0xf4, 0xc1, 0x3d, 0x24, 0x81, 0x41, 0xcc, 0x8d,
9767
+	0x7e, 0x9e, 0x94, 0x9d, 0xf0, 0xaa, 0xdb, 0x63, 0x8b, 0x05, 0xce, 0xb7, 0xda, 0x9c, 0x45, 0xea,
9768
+	0xf2, 0xaa, 0x84, 0x02, 0x62, 0xe9, 0x13, 0x64, 0x36, 0x60, 0x87, 0xae, 0xd0, 0x66, 0xcb, 0xef,
9769
+	0xf7, 0xdd, 0x68, 0xb1, 0x98, 0xa6, 0x57, 0x50, 0xc8, 0x50, 0xd1, 0xa7, 0xc8, 0x9c, 0x86, 0xbc,
9770
+	0xc4, 0xc2, 0xd0, 0xe9, 0xb2, 0xc5, 0x92, 0x1c, 0x38, 0x87, 0x03, 0xa7, 0x11, 0x0c, 0x59, 0x3a,
9771
+	0xda, 0x24, 0x54, 0x83, 0x56, 0x87, 0xd1, 0xbe, 0x1f, 0x5c, 0x73, 0xfa, 0x6c, 0x71, 0x4a, 0x8e,
9772
+	0x8e, 0x17, 0x95, 0x60, 0x60, 0x0c, 0x35, 0xbd, 0x42, 0x16, 0xd2, 0xd0, 0x2b, 0x7d, 0xc7, 0xed,
9773
+	0x2d, 0x96, 0x25, 0x93, 0x05, 0x64, 0x52, 0x33, 0x50, 0x30, 0x8e, 0x9e, 0x7e, 0x99, 0xdc, 0x9e,
9774
+	0x5e, 0x57, 0xc4, 0xd4, 0x6c, 0xa6, 0x25, 0xa3, 0xdb, 0x91, 0xd1, 0xb9, 0x14, 0x12, 0xc6, 0x8f,
9775
+	0xa1, 0xd7, 0xc8, 0x1d, 0x23, 0x08, 0x35, 0xad, 0x8a, 0xe4, 0x76, 0x07, 0x72, 0x9b, 0x4d, 0x63,
9776
+	0xe1, 0x98, 0x51, 0xf6, 0xd3, 0xe4, 0xbc, 0x61, 0x39, 0xdb, 0xfe, 0x30, 0x68, 0x33, 0x63, 0x5f,
9777
+	0xad, 0x93, 0xf6, 0xd5, 0xfe, 0x65, 0x81, 0x4c, 0xc9, 0x71, 0x67, 0x68, 0x63, 0x5f, 0x25, 0xa5,
9778
+	0x70, 0xc0, 0xda, 0xd2, 0xc2, 0x6a, 0x2b, 0x5f, 0xac, 0x4f, 0xe2, 0x0e, 0xea, 0x6a, 0x51, 0x7c,
9779
+	0x78, 0x73, 0x06, 0x85, 0x94, 0xc4, 0x17, 0x48, 0x96, 0xd4, 0x21, 0xe5, 0x30, 0x72, 0xa2, 0x61,
9780
+	0x28, 0xcd, 0xb1, 0xb6, 0xf2, 0x54, 0x1e, 0xe6, 0x92, 0x41, 0xa2, 0x21, 0xf5, 0x0d, 0xc8, 0xd8,
9781
+	0xfe, 0x43, 0x81, 0xd4, 0x24, 0x5d, 0xcb, 0xf7, 0x3a, 0x6e, 0xf7, 0x0c, 0xf5, 0xf4, 0xcd, 0x94,
9782
+	0x9e, 0x9e, 0xcd, 0xb1, 0x14, 0x35, 0xc5, 0x63, 0xb5, 0xd5, 0xcd, 0x68, 0xeb, 0x4b, 0xf9, 0x45,
9783
+	0x9c, 0xac, 0xb3, 0xf7, 0x2d, 0x32, 0x67, 0x50, 0x6f, 0xba, 0x61, 0x44, 0xbf, 0x3e, 0xa2, 0xb7,
9784
+	0xc6, 0x09, 0x7a, 0x33, 0x7c, 0x77, 0x5d, 0x0c, 0x97, 0xea, 0x9b, 0x47, 0x71, 0x15, 0x0d, 0x31,
9785
+	0x94, 0xf7, 0x0d, 0x32, 0xe5, 0x46, 0xac, 0x1f, 0x72, 0xed, 0x15, 0x73, 0x1a, 0x82, 0x9a, 0x6c,
9786
+	0xf3, 0x1c, 0x4a, 0x99, 0x5a, 0x17, 0xfc, 0x40, 0xb1, 0xb5, 0xff, 0x58, 0x48, 0x2d, 0x49, 0x68,
9787
+	0x95, 0x7a, 0xa4, 0x12, 0x71, 0x86, 0x5d, 0x3e, 0x53, 0xbe, 0x24, 0x21, 0xf6, 0xf9, 0x1c, 0x62,
9788
+	0x77, 0x14, 0x8b, 0x2d, 0xbf, 0xe7, 0xb6, 0x8f, 0x92, 0x35, 0x22, 0x38, 0x84, 0x58, 0x06, 0x5d,
9789
+	0x25, 0x55, 0x1e, 0x72, 0x14, 0x21, 0xfa, 0xeb, 0xfb, 0x91, 0xbc, 0x0a, 0x1a, 0xf1, 0x09, 0xf7,
9790
+	0x1c, 0x2a, 0x86, 0x68, 0x08, 0x24, 0xa3, 0x68, 0x8f, 0x10, 0x3e, 0xb5, 0xbe, 0xef, 0x89, 0x05,
9791
+	0xa0, 0x19, 0x3c, 0x39, 0xd9, 0xa4, 0x5b, 0xf1, 0xf8, 0xc4, 0x9e, 0x13, 0x18, 0x18, 0xfc, 0xed,
9792
+	0x0d, 0xee, 0x9a, 0xb2, 0x46, 0x43, 0x1f, 0x27, 0xb5, 0x9e, 0x13, 0x46, 0xaf, 0xa8, 0xfd, 0x95,
9793
+	0xb6, 0x50, 0x4c, 0x7c, 0xf1, 0x66, 0x82, 0x02, 0x93, 0xce, 0xfe, 0x87, 0x45, 0xaa, 0x92, 0xd9,
9794
+	0x67, 0x61, 0x4d, 0xaf, 0xa5, 0xad, 0xe9, 0xd1, 0x1c, 0xdb, 0x7a, 0x8c, 0x1d, 0x11, 0x52, 0x51,
9795
+	0xab, 0xf0, 0xbb, 0xf6, 0xdb, 0x25, 0xb4, 0x29, 0xfe, 0xa1, 0x43, 0x7d, 0x83, 0x54, 0xdb, 0xbe,
9796
+	0x17, 0x39, 0x2e, 0xcf, 0x0f, 0xd0, 0x77, 0x9f, 0xd7, 0x7b, 0xdc, 0xd2, 0x08, 0x48, 0x68, 0x84,
9797
+	0xa7, 0xef, 0xf8, 0xbd, 0x9e, 0xff, 0x86, 0xb4, 0x88, 0x4a, 0x72, 0x26, 0xaf, 0x4a, 0x28, 0x20,
9798
+	0x96, 0x3e, 0x4c, 0x2a, 0x03, 0x11, 0x41, 0x7c, 0x3c, 0xfe, 0x95, 0x44, 0x01, 0x5b, 0x08, 0x87,
9799
+	0x98, 0x82, 0x3e, 0x46, 0x66, 0x42, 0xd7, 0x6b, 0xb3, 0x6d, 0xc6, 0x25, 0xed, 0x85, 0x32, 0x68,
9800
+	0x17, 0x9b, 0xf3, 0x9c, 0x7a, 0x66, 0xdb, 0x80, 0x43, 0x8a, 0x8a, 0xab, 0xad, 0x2a, 0xbf, 0x77,
9801
+	0x5c, 0x8c, 0xd4, 0xb5, 0x95, 0x87, 0x6e, 0x72, 0x5b, 0xc4, 0x90, 0xe6, 0x39, 0xb1, 0xca, 0x6d,
9802
+	0xcd, 0x01, 0x12, 0x66, 0x74, 0x85, 0x10, 0x91, 0x6a, 0x71, 0xff, 0xd2, 0x1f, 0x84, 0x32, 0x7e,
9803
+	0x57, 0x12, 0xeb, 0xdb, 0x89, 0x31, 0x60, 0x50, 0xd1, 0x87, 0x48, 0x95, 0xeb, 0xa8, 0xb7, 0xc9,
9804
+	0xd5, 0x14, 0xca, 0x48, 0x5d, 0x54, 0x02, 0x76, 0x34, 0x10, 0x12, 0x3c, 0xad, 0x13, 0xd2, 0x73,
9805
+	0x79, 0x58, 0x6d, 0x1e, 0xf1, 0x19, 0xca, 0x48, 0x5c, 0x6c, 0xce, 0x0a, 0xe6, 0x9b, 0x31, 0x14,
9806
+	0x0c, 0x0a, 0xa1, 0x76, 0xcf, 0x7f, 0xc3, 0xe1, 0x89, 0x50, 0x35, 0xad, 0xf6, 0x6b, 0xfe, 0xab,
9807
+	0x1c, 0x0a, 0x88, 0xa5, 0x9f, 0x23, 0xd3, 0xb8, 0xc8, 0x45, 0x22, 0x99, 0xd6, 0x44, 0xd2, 0xa3,
9808
+	0x2d, 0x5c, 0xe3, 0xec, 0xdf, 0xe9, 0x28, 0x73, 0x7d, 0x18, 0x0d, 0x86, 0x11, 0x4f, 0x5c, 0x0a,
9809
+	0x91, 0x8f, 0x96, 0xfd, 0xc8, 0xcd, 0xc4, 0x17, 0x60, 0x1d, 0x16, 0x30, 0xae, 0xae, 0x66, 0x99,
9810
+	0x0b, 0x28, 0xec, 0xf8, 0xc0, 0x19, 0xd0, 0x5d, 0x42, 0x06, 0xc3, 0x70, 0x9f, 0xef, 0x4f, 0xc0,
9811
+	0x22, 0x0c, 0x2c, 0x2b, 0x27, 0xb3, 0xdb, 0xf4, 0xdb, 0x4e, 0x2f, 0xcb, 0x53, 0x6a, 0x62, 0x2b,
9812
+	0xe6, 0x04, 0x06, 0x57, 0xea, 0x93, 0x9a, 0xdb, 0xe7, 0x09, 0xdb, 0xa6, 0xb3, 0xcb, 0x7a, 0xc2,
9813
+	0xb6, 0x8a, 0x93, 0xfb, 0x94, 0xf5, 0x98, 0x41, 0xe2, 0x09, 0x12, 0x58, 0x08, 0xa6, 0x04, 0xfb,
9814
+	0xbb, 0x16, 0x59, 0x90, 0xba, 0xda, 0xf2, 0xc3, 0x48, 0x25, 0x43, 0xd2, 0x1d, 0x73, 0x55, 0x0b,
9815
+	0xdf, 0xe3, 0x78, 0x7b, 0xd2, 0x1b, 0x57, 0x95, 0xaa, 0x5b, 0x0a, 0x04, 0x1a, 0x47, 0xef, 0x22,
9816
+	0x25, 0x27, 0xe8, 0xaa, 0xa3, 0x5d, 0x6d, 0x56, 0x44, 0x8c, 0x5c, 0xe5, 0xdf, 0x20, 0xa1, 0x62,
9817
+	0x5f, 0xc3, 0x76, 0xe0, 0x0e, 0x46, 0x12, 0xdc, 0x6d, 0x09, 0x05, 0xc4, 0xda, 0x1f, 0x4f, 0x91,
9818
+	0x19, 0x33, 0x55, 0x3f, 0xc3, 0xbc, 0xa0, 0x43, 0x2a, 0x3a, 0xf5, 0xc3, 0x2d, 0x7c, 0x66, 0x32,
9819
+	0xed, 0xaa, 0x9c, 0x10, 0x90, 0x47, 0x73, 0x46, 0x9c, 0x79, 0xfd, 0x05, 0x31, 0x6f, 0xbe, 0x91,
9820
+	0xf3, 0x18, 0x6a, 0xd8, 0x5e, 0xf3, 0x48, 0xaa, 0x1f, 0x23, 0xc4, 0x84, 0x16, 0x78, 0x81, 0x0b,
9821
+	0x98, 0xdf, 0xc9, 0xb0, 0x82, 0x11, 0xe6, 0x3c, 0xad, 0x2e, 0x75, 0x02, 0xbf, 0x2f, 0x9d, 0xcb,
9822
+	0xc4, 0x42, 0xe4, 0xc6, 0x5d, 0xe5, 0xc3, 0x41, 0x32, 0xa1, 0x6d, 0x52, 0xde, 0x95, 0x69, 0x30,
9823
+	0x3a, 0x9e, 0x49, 0x93, 0x9b, 0x6c, 0x0a, 0xdd, 0x24, 0x62, 0xd7, 0x15, 0x18, 0x90, 0x35, 0x5d,
9824
+	0x4e, 0xc7, 0xae, 0xb2, 0x3c, 0xd1, 0x73, 0x27, 0xc5, 0x2d, 0xda, 0x22, 0x45, 0xe6, 0x1d, 0x72,
9825
+	0xff, 0x23, 0x8e, 0xc5, 0x03, 0x27, 0xaf, 0xf1, 0x8a, 0x77, 0xf8, 0x8a, 0x13, 0x34, 0x6b, 0x68,
9826
+	0x0e, 0x45, 0xfe, 0x0d, 0x62, 0x34, 0x3d, 0x24, 0x35, 0x43, 0x7b, 0xdc, 0x3d, 0x15, 0x73, 0xa6,
9827
+	0x6f, 0xb8, 0x2b, 0x2d, 0x67, 0x18, 0xb2, 0xe4, 0xa8, 0x19, 0x7b, 0x05, 0xa6, 0x20, 0xfb, 0xe7,
9828
+	0x53, 0xe8, 0x96, 0xb0, 0xac, 0x78, 0x94, 0x94, 0xa2, 0xa3, 0x81, 0x2e, 0x2a, 0xee, 0xd1, 0x39,
9829
+	0xe6, 0x0e, 0x87, 0xf1, 0xbc, 0x63, 0xce, 0x20, 0x15, 0x20, 0x90, 0xc4, 0xc6, 0xce, 0x14, 0xce,
9830
+	0x6e, 0x67, 0xb8, 0xff, 0xde, 0xf3, 0xdb, 0x07, 0x2c, 0xe8, 0x88, 0xa2, 0x07, 0xcf, 0xae, 0x38,
9831
+	0x52, 0x6b, 0x31, 0x14, 0x0c, 0x0a, 0xfa, 0x2a, 0x29, 0xf2, 0x59, 0xa0, 0xe9, 0x4d, 0x78, 0x9e,
9832
+	0x5e, 0xe0, 0x41, 0xc0, 0x98, 0xce, 0xb4, 0xd8, 0x2a, 0x0e, 0x03, 0xc1, 0x51, 0x94, 0x24, 0xd2,
9833
+	0x59, 0x85, 0xdc, 0x0e, 0x73, 0x64, 0xa2, 0xf2, 0x64, 0x20, 0xe3, 0xd8, 0xf7, 0x48, 0x20, 0x4f,
9834
+	0xaf, 0x15, 0x63, 0x11, 0x0c, 0x45, 0xfc, 0x67, 0x6f, 0x46, 0x6b, 0x6e, 0x80, 0xc5, 0xac, 0x91,
9835
+	0x8a, 0x69, 0x0c, 0x18, 0x54, 0x74, 0x9f, 0x07, 0x74, 0xc9, 0x15, 0x63, 0xc1, 0x74, 0xee, 0x58,
9836
+	0xa0, 0x92, 0x00, 0x83, 0x17, 0xa4, 0x38, 0xd3, 0xd7, 0xc9, 0x74, 0x28, 0xff, 0x0b, 0xf3, 0xd9,
9837
+	0xa9, 0x62, 0x63, 0x2a, 0x38, 0xee, 0x15, 0x28, 0x54, 0x08, 0x5a, 0x80, 0xfd, 0x1f, 0x9d, 0x14,
9838
+	0xca, 0x00, 0x90, 0x4e, 0x6e, 0xad, 0xb3, 0x4d, 0x6e, 0xb3, 0x67, 0xb2, 0xf0, 0x59, 0x9d, 0xc9,
9839
+	0x77, 0xe3, 0x33, 0xa9, 0xf2, 0xe9, 0x65, 0x32, 0x35, 0xd8, 0x77, 0x42, 0x7d, 0x28, 0xef, 0xd4,
9840
+	0x69, 0xe7, 0x96, 0x00, 0xf2, 0x53, 0x49, 0x54, 0xac, 0x14, 0x5f, 0xa0, 0x28, 0x65, 0x92, 0xe9,
9841
+	0xf0, 0xbd, 0xec, 0xf5, 0xd8, 0x1e, 0xa6, 0x8d, 0x49, 0x92, 0xa9, 0x11, 0x90, 0xd0, 0xd0, 0x27,
9842
+	0x48, 0x39, 0x60, 0x4e, 0xc8, 0x5d, 0x9e, 0x3a, 0x59, 0x97, 0xb5, 0x65, 0x82, 0x84, 0x7e, 0x22,
9843
+	0x2c, 0x42, 0x95, 0x80, 0xf2, 0x1b, 0x90, 0x9a, 0x7e, 0x81, 0x4c, 0xf7, 0x4f, 0x6e, 0xfb, 0x68,
9844
+	0x3c, 0x2f, 0x4e, 0x67, 0x79, 0xde, 0x16, 0x44, 0x71, 0x32, 0x97, 0x27, 0x81, 0xa4, 0xa2, 0x6f,
9845
+	0xb2, 0x9d, 0x62, 0x03, 0x19, 0xb6, 0x7c, 0xdf, 0x16, 0xf8, 0xe6, 0x0c, 0x7a, 0x4c, 0x24, 0xdc,
9846
+	0x89, 0xb4, 0xf2, 0xe4, 0xd2, 0x2e, 0x72, 0x69, 0x0b, 0xad, 0x51, 0x5e, 0x30, 0x4e, 0x00, 0x7d,
9847
+	0x96, 0x54, 0xf6, 0x86, 0x81, 0x23, 0x80, 0x98, 0x8d, 0xde, 0xa7, 0x13, 0xf0, 0x35, 0x84, 0x73,
9848
+	0x3d, 0x9e, 0x13, 0x09, 0x6c, 0x5d, 0x03, 0x20, 0x1e, 0xc2, 0x53, 0xb9, 0x25, 0x5f, 0xe6, 0x86,
9849
+	0xca, 0xa1, 0xa9, 0x98, 0xaa, 0x0f, 0x25, 0xb6, 0x8e, 0x6c, 0x64, 0xb8, 0x74, 0xfd, 0x58, 0x4a,
9850
+	0x38, 0x81, 0x0b, 0xfd, 0x0a, 0x29, 0xb7, 0x65, 0xa9, 0x26, 0x93, 0xda, 0x89, 0x43, 0x32, 0x51,
9851
+	0x8d, 0x40, 0xc1, 0x00, 0x90, 0x91, 0xfd, 0xef, 0x12, 0x39, 0x87, 0xd6, 0x2a, 0xfa, 0x9d, 0xdd,
9852
+	0x23, 0x5e, 0xff, 0x99, 0x31, 0xe4, 0xbe, 0x4c, 0x0c, 0x39, 0x9f, 0x22, 0x36, 0xa2, 0xc8, 0x77,
9853
+	0xc8, 0xac, 0x72, 0xdf, 0x1a, 0x87, 0xd1, 0x64, 0x75, 0xb2, 0x13, 0xa7, 0xd6, 0x9d, 0x12, 0xa2,
9854
+	0xac, 0x66, 0x2d, 0xc5, 0x1c, 0x32, 0xc2, 0x84, 0x78, 0xf4, 0x72, 0x5a, 0x7c, 0x31, 0x8f, 0x78,
9855
+	0xf4, 0x68, 0xa3, 0xe2, 0xb7, 0x53, 0xcc, 0x21, 0x23, 0x4c, 0x88, 0x6f, 0x0f, 0xc3, 0xc8, 0xef,
9856
+	0xc7, 0xe2, 0x4b, 0x79, 0xc4, 0xb7, 0x24, 0x8f, 0x31, 0xe2, 0x5b, 0x29, 0xe6, 0x90, 0x11, 0x46,
9857
+	0xdf, 0xb1, 0xc8, 0xc5, 0xd7, 0x99, 0x77, 0xe0, 0x7a, 0xe1, 0x96, 0x3b, 0x60, 0x3d, 0x5e, 0x32,
9858
+	0xc5, 0x13, 0x51, 0xc7, 0x74, 0x63, 0xb2, 0x89, 0x6c, 0xa4, 0x99, 0xa5, 0x67, 0x74, 0x27, 0x9f,
9859
+	0xd1, 0xc5, 0x8d, 0xf1, 0xe2, 0xe0, 0xb8, 0x79, 0xd8, 0x7f, 0x2d, 0x62, 0xb7, 0xc1, 0xf4, 0xa7,
9860
+	0xa6, 0x07, 0xb2, 0x3e, 0xc5, 0x03, 0x71, 0x1d, 0xcb, 0xb6, 0xbc, 0xdb, 0x7e, 0x95, 0xed, 0xbe,
9861
+	0xe8, 0xfb, 0x07, 0xf9, 0x2c, 0xec, 0x85, 0x14, 0x0f, 0xe5, 0xd5, 0xa5, 0x8e, 0xd3, 0x08, 0xc8,
9862
+	0x08, 0xa3, 0x47, 0xe4, 0x9c, 0x92, 0xa3, 0xa5, 0x2b, 0x03, 0x7b, 0x7e, 0xe2, 0xdc, 0xe4, 0xc5,
9863
+	0x98, 0x85, 0x12, 0x7e, 0x5e, 0xb4, 0xa6, 0x53, 0x70, 0x48, 0x4b, 0xa2, 0x6f, 0x59, 0x64, 0x5e,
9864
+	0xe6, 0x16, 0xad, 0x7d, 0xc7, 0xeb, 0xaa, 0xdd, 0x40, 0x03, 0x7b, 0x2e, 0x47, 0xfa, 0xa2, 0xb8,
9865
+	0x28, 0xe1, 0xb2, 0x16, 0x58, 0xcf, 0xf0, 0x86, 0x11, 0x69, 0xf6, 0x4f, 0x8b, 0x84, 0x8e, 0xb6,
9866
+	0xc3, 0xe8, 0x63, 0x29, 0x67, 0x71, 0x6f, 0xc6, 0x59, 0xcc, 0x9b, 0x23, 0x0c, 0x5f, 0xd1, 0x25,
9867
+	0x65, 0x35, 0xeb, 0x7c, 0xf5, 0x12, 0xaa, 0x05, 0xf9, 0x8e, 0xd3, 0x1f, 0xb2, 0x17, 0xb9, 0x0e,
9868
+	0xee, 0x22, 0xee, 0xd6, 0xe9, 0x24, 0x8d, 0x33, 0x13, 0x2d, 0x80, 0x86, 0x58, 0x67, 0x2b, 0xad,
9869
+	0xe1, 0xf6, 0x3c, 0x9f, 0x7b, 0x7b, 0xb4, 0xcc, 0xb9, 0xb8, 0xd6, 0x56, 0x70, 0x30, 0xa5, 0xd8,
9870
+	0xbf, 0x28, 0x13, 0x23, 0xff, 0xa1, 0xcf, 0x71, 0x2f, 0xc8, 0x82, 0x43, 0xb7, 0xcd, 0x56, 0xdb,
9871
+	0x6d, 0x7f, 0xe8, 0x45, 0xb8, 0x31, 0xf1, 0x9d, 0xc5, 0x76, 0x0a, 0x0b, 0x19, 0x6a, 0xd9, 0xaf,
9872
+	0x97, 0x8e, 0x0d, 0x37, 0x26, 0x57, 0xbf, 0x3e, 0x93, 0x1c, 0x63, 0x75, 0x8b, 0x8c, 0x53, 0xd5,
9873
+	0x72, 0xf1, 0x0c, 0xab, 0x65, 0x97, 0x54, 0xc2, 0xb4, 0x2f, 0x7e, 0x3a, 0xd7, 0xe5, 0x03, 0xfa,
9874
+	0xbc, 0xb8, 0x19, 0x17, 0x3b, 0xba, 0x98, 0xbd, 0xd0, 0x9a, 0x0a, 0xda, 0xe8, 0x6b, 0xf3, 0x68,
9875
+	0x4d, 0x65, 0x04, 0x89, 0xd6, 0xd4, 0x37, 0x20, 0x63, 0x5e, 0xa3, 0x55, 0x03, 0xa6, 0x34, 0x18,
9876
+	0x62, 0x2a, 0xf4, 0x29, 0xb5, 0x01, 0x20, 0xb9, 0xe8, 0x7f, 0xb8, 0x01, 0xeb, 0x33, 0x2f, 0x0a,
9877
+	0x93, 0x2c, 0x52, 0x63, 0x43, 0x48, 0xf8, 0xd2, 0x21, 0x21, 0x83, 0xb8, 0x65, 0x83, 0x15, 0xc8,
9878
+	0x6a, 0x8e, 0xb5, 0xa4, 0xfb, 0x3e, 0x49, 0xa2, 0x9e, 0xc0, 0xc1, 0x10, 0x44, 0xbf, 0x46, 0x2e,
9879
+	0x25, 0xf9, 0xd8, 0x1a, 0x73, 0xf6, 0x64, 0xd8, 0xc0, 0xc6, 0xa6, 0xea, 0xf4, 0xdd, 0xcd, 0x87,
9880
+	0x5f, 0x6a, 0x1d, 0x47, 0x04, 0xc7, 0x8f, 0xb7, 0xff, 0x5c, 0x22, 0x0b, 0x63, 0xa2, 0x2a, 0xbd,
9881
+	0x8e, 0xbd, 0x8d, 0x5c, 0x2d, 0xbc, 0xf8, 0xf2, 0xc6, 0xe8, 0x6f, 0xc8, 0x56, 0x5e, 0xaf, 0x77,
9882
+	0xab, 0x5a, 0x79, 0x9a, 0x13, 0x18, 0x5c, 0x75, 0xaf, 0xa2, 0x78, 0xaa, 0x5e, 0xc5, 0x06, 0xa1,
9883
+	0xec, 0x4d, 0xae, 0x7e, 0x86, 0x19, 0x95, 0xf8, 0xab, 0x0a, 0xed, 0x4a, 0x73, 0x09, 0xa9, 0xe9,
9884
+	0x95, 0x11, 0x0a, 0x18, 0x33, 0x4a, 0x14, 0x2a, 0x1d, 0x9f, 0xdb, 0x8e, 0x98, 0xaf, 0x34, 0x7e,
9885
+	0xa3, 0x50, 0xb9, 0xaa, 0x11, 0x90, 0xd0, 0x70, 0x3b, 0x8e, 0x8b, 0xcf, 0x72, 0x9e, 0x46, 0xa4,
9886
+	0x52, 0x84, 0x34, 0xab, 0x63, 0xab, 0x4e, 0xba, 0x4a, 0xe6, 0xe4, 0xa0, 0xd5, 0xad, 0x75, 0xdd,
9887
+	0x09, 0x52, 0x17, 0xc1, 0x17, 0x71, 0x88, 0x6a, 0x84, 0x24, 0x68, 0xc8, 0xd2, 0xdb, 0xbf, 0x2d,
9888
+	0x92, 0x85, 0x31, 0xa9, 0x68, 0xdc, 0x12, 0xb3, 0x6e, 0x45, 0x4b, 0xec, 0xb3, 0x30, 0x19, 0x9e,
9889
+	0x5f, 0x79, 0x7e, 0xcb, 0x69, 0xef, 0x33, 0xbc, 0x55, 0x88, 0xd5, 0x76, 0x4d, 0x81, 0x41, 0xe3,
9890
+	0xb5, 0x75, 0x95, 0x4e, 0x65, 0x5d, 0x13, 0x5b, 0xc4, 0x73, 0xba, 0x6e, 0x10, 0x6d, 0x9f, 0x2d,
9891
+	0x27, 0xda, 0xc7, 0x86, 0x49, 0x1c, 0xb2, 0xd6, 0x52, 0x58, 0xc8, 0x50, 0xdb, 0xbf, 0xb6, 0xc8,
9892
+	0xc2, 0x98, 0x94, 0x2e, 0x15, 0x67, 0xac, 0x33, 0x8c, 0x33, 0xa2, 0x21, 0x9d, 0x6c, 0xa0, 0xd9,
9893
+	0x90, 0x56, 0x9b, 0x81, 0x58, 0xfb, 0xc3, 0x91, 0x79, 0x5e, 0x39, 0xe4, 0x3e, 0x39, 0x5f, 0xcb,
9894
+	0x6e, 0x4b, 0x75, 0xc7, 0x94, 0xc9, 0x3c, 0x3e, 0x71, 0x06, 0xba, 0xee, 0x75, 0xfc, 0x4c, 0x5b,
9895
+	0xec, 0x56, 0xb8, 0x16, 0xfb, 0x6f, 0x16, 0x99, 0x4d, 0x37, 0xdf, 0xe8, 0xdd, 0xa4, 0x38, 0x0c,
9896
+	0x5c, 0x5c, 0x5d, 0x3c, 0xe2, 0x65, 0x58, 0x07, 0x01, 0x17, 0xe8, 0x80, 0x75, 0x50, 0x75, 0x31,
9897
+	0x9a, 0x9b, 0x36, 0x08, 0x38, 0x1d, 0x90, 0xda, 0x20, 0xf0, 0xdf, 0x3c, 0x52, 0x45, 0x6b, 0xbe,
9898
+	0x47, 0x04, 0x5b, 0x09, 0x83, 0xa4, 0x7b, 0x63, 0x00, 0xc1, 0x14, 0x61, 0xff, 0xca, 0x22, 0x74,
9899
+	0x34, 0x47, 0xff, 0x9f, 0xb3, 0xa6, 0x1f, 0x17, 0xc8, 0x34, 0x6e, 0x24, 0xfd, 0x36, 0xaf, 0x8b,
9900
+	0x52, 0x4a, 0xcf, 0x37, 0xc3, 0x4c, 0xd7, 0x34, 0x3e, 0x7f, 0x69, 0x38, 0x64, 0x64, 0xd1, 0xb7,
9901
+	0x2d, 0x72, 0x9e, 0x83, 0xd2, 0xeb, 0xcb, 0xd7, 0x49, 0x7e, 0x21, 0xcb, 0xa6, 0x79, 0x09, 0x27,
9902
+	0x71, 0x7e, 0x04, 0x05, 0xa3, 0x42, 0xed, 0xbf, 0x17, 0xc8, 0x28, 0xa1, 0x50, 0x69, 0x5b, 0x65,
9903
+	0x34, 0xd6, 0xd8, 0x27, 0x51, 0x88, 0x15, 0x45, 0x89, 0x23, 0xdf, 0x14, 0xe5, 0x9b, 0xbc, 0x92,
9904
+	0x2a, 0xba, 0xbb, 0x81, 0xdf, 0x7b, 0x99, 0xe7, 0xd5, 0xc6, 0x9b, 0x1e, 0xc9, 0x16, 0x90, 0x3d,
9905
+	0x37, 0xea, 0x6a, 0x5b, 0x3f, 0x11, 0xca, 0xf7, 0xd2, 0x63, 0x54, 0x96, 0x71, 0x07, 0x8d, 0x9c,
9906
+	0x21, 0x11, 0x32, 0x41, 0x9b, 0xcf, 0xfe, 0x09, 0x2f, 0x35, 0xb3, 0x45, 0xa2, 0x18, 0x2f, 0x8b,
9907
+	0x8e, 0xf5, 0xb5, 0x6c, 0x91, 0xbe, 0xae, 0xc0, 0xa0, 0xf1, 0x74, 0x87, 0x4c, 0x8b, 0xd8, 0x06,
9908
+	0x78, 0xa8, 0x27, 0x8e, 0x91, 0xf2, 0x4e, 0xf0, 0xaa, 0xe2, 0x00, 0x9a, 0x95, 0xfd, 0x27, 0x7e,
9909
+	0x2a, 0x47, 0x6b, 0x23, 0xee, 0x06, 0x2f, 0x88, 0xab, 0x9c, 0xb8, 0x15, 0xbb, 0x9e, 0x9a, 0xe4,
9910
+	0x5d, 0x38, 0xc9, 0x0b, 0x9b, 0x63, 0x68, 0x60, 0xec, 0xc8, 0x38, 0xbe, 0x17, 0x6e, 0x41, 0x7c,
9911
+	0xb7, 0xb7, 0x09, 0x49, 0x2e, 0x49, 0xe9, 0xbd, 0xa4, 0xe4, 0x89, 0x37, 0x69, 0x6a, 0x72, 0x71,
9912
+	0x0a, 0x29, 0x9f, 0xa2, 0x49, 0x0c, 0xbd, 0x9f, 0x4c, 0x1d, 0x3a, 0xbd, 0xa1, 0x7e, 0xeb, 0x17,
9913
+	0x3f, 0x50, 0x78, 0x45, 0x00, 0x41, 0xe1, 0xec, 0xdf, 0x14, 0x48, 0xcd, 0xb8, 0x84, 0x38, 0x8b,
9914
+	0x44, 0x76, 0x6a, 0xc0, 0x03, 0xab, 0x7e, 0x5b, 0xf1, 0x6c, 0xee, 0xfb, 0x11, 0x11, 0x9e, 0x93,
9915
+	0x45, 0x88, 0xaf, 0x10, 0x14, 0xeb, 0x4c, 0xe6, 0x53, 0x3c, 0x8b, 0xcc, 0xc7, 0xfe, 0xbe, 0x45,
9916
+	0xe6, 0x32, 0xb3, 0x11, 0x37, 0x33, 0x61, 0xfc, 0x85, 0x3b, 0x11, 0x97, 0x27, 0x09, 0x1d, 0x18,
9917
+	0x54, 0x32, 0x41, 0x61, 0x61, 0xe4, 0x7a, 0xb2, 0xcf, 0x2b, 0x6e, 0x74, 0x0a, 0x99, 0x04, 0x25,
9918
+	0x85, 0x85, 0x0c, 0xb5, 0xfd, 0x33, 0x8b, 0xdc, 0x75, 0x52, 0x3b, 0x4d, 0xa4, 0xab, 0xd8, 0x33,
9919
+	0x8b, 0x53, 0x20, 0x2b, 0x9d, 0xae, 0x6e, 0xa4, 0xd1, 0x90, 0xa5, 0x17, 0x6f, 0x76, 0x0c, 0x10,
9920
+	0x4e, 0x30, 0x0e, 0x76, 0xc6, 0x70, 0x30, 0xe9, 0xec, 0x1f, 0x59, 0xc4, 0x8c, 0x84, 0xe2, 0x45,
9921
+	0xc6, 0x7e, 0x14, 0x0d, 0x24, 0x08, 0x6f, 0x12, 0xe4, 0x8b, 0x8c, 0x17, 0x77, 0x76, 0xb6, 0x24,
9922
+	0x10, 0x12, 0xbc, 0xb8, 0xd1, 0x13, 0x1f, 0xa1, 0xa2, 0x2e, 0x25, 0x37, 0x7a, 0x82, 0x7a, 0x5b,
9923
+	0x91, 0x1b, 0x14, 0xe2, 0xfa, 0xdf, 0xf3, 0x15, 0xb1, 0x7a, 0x24, 0x5a, 0x53, 0x59, 0xa8, 0xa2,
9924
+	0xd4, 0x38, 0xfb, 0xf7, 0x3c, 0x9e, 0x8c, 0x5c, 0x31, 0xd1, 0x1b, 0x71, 0x5c, 0xb4, 0xf2, 0x1b,
9925
+	0xcb, 0xf8, 0x58, 0x7a, 0xea, 0x0d, 0x7e, 0xd7, 0x22, 0x24, 0xa9, 0x4b, 0x68, 0x8f, 0xcc, 0x28,
9926
+	0xc6, 0xa9, 0x60, 0x9c, 0x67, 0xc2, 0x17, 0x70, 0x02, 0x33, 0xdb, 0x06, 0x3f, 0x48, 0x71, 0x17,
9927
+	0xf9, 0x76, 0x5f, 0xb4, 0x6e, 0xa4, 0xd9, 0x14, 0xd2, 0xef, 0x91, 0x5e, 0xd2, 0x08, 0x48, 0x68,
9928
+	0xec, 0x1f, 0x4c, 0x91, 0x85, 0x31, 0x5d, 0xee, 0xff, 0xe3, 0x82, 0x98, 0x47, 0x37, 0xf5, 0x68,
9929
+	0x24, 0xcc, 0x46, 0x47, 0xf5, 0xa6, 0x44, 0x54, 0x96, 0xea, 0x1f, 0xf1, 0xbe, 0xc0, 0xf5, 0xda,
9930
+	0xaa, 0x9b, 0xe2, 0xe8, 0xfa, 0x46, 0x75, 0xe8, 0x12, 0x30, 0x98, 0x34, 0xe9, 0x82, 0xa8, 0x7c,
9931
+	0x53, 0x25, 0xf2, 0x0c, 0x3e, 0x5c, 0x57, 0x4f, 0x3c, 0xa6, 0xf3, 0x6c, 0x88, 0xbc, 0x04, 0x06,
9932
+	0x83, 0x0d, 0xa4, 0x98, 0xd2, 0xef, 0xf1, 0x30, 0x8f, 0x80, 0xd5, 0x20, 0x72, 0x3b, 0x4e, 0x3b,
9933
+	0xbe, 0x0e, 0x3e, 0xa5, 0xc3, 0x5f, 0xc4, 0xc5, 0xcd, 0x43, 0x86, 0x3d, 0x8c, 0x08, 0xb4, 0x6f,
9934
+	0xf0, 0xa3, 0x9e, 0x4d, 0x65, 0x6e, 0x2e, 0x4e, 0x32, 0xf9, 0x20, 0x3b, 0x13, 0x27, 0xd5, 0x3b,
9935
+	0x6c, 0x85, 0xb3, 0xdf, 0xe1, 0xb5, 0x48, 0x26, 0x13, 0xcc, 0x55, 0x6a, 0xdd, 0x30, 0x4b, 0xad,
9936
+	0x53, 0x27, 0xb4, 0xa9, 0xa2, 0xcb, 0xee, 0x90, 0xd9, 0x74, 0x87, 0xd9, 0xc8, 0xff, 0xad, 0x93,
9937
+	0xf2, 0x7f, 0xf1, 0x5a, 0xd0, 0x11, 0xcf, 0x06, 0xb9, 0x11, 0xe3, 0x05, 0x71, 0xdc, 0xa0, 0x5c,
9938
+	0x45, 0x38, 0xc4, 0x14, 0xcd, 0x07, 0xde, 0xfb, 0xf0, 0xf2, 0x6d, 0xef, 0xf3, 0xdf, 0x3f, 0xf9,
9939
+	0xef, 0xad, 0x8f, 0x2e, 0x5b, 0xef, 0xf1, 0xdf, 0xfb, 0xfc, 0xf7, 0x2f, 0xfe, 0xfb, 0xe1, 0xc7,
9940
+	0x97, 0x6f, 0xbb, 0x51, 0x38, 0x5c, 0xfe, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x37, 0xef, 0xc2,
9941
+	0xa1, 0x46, 0x32, 0x00, 0x00,
9939 9942
 }
... ...
@@ -184,6 +184,10 @@ message BuildOutput {
184 184
   // up the authentication for executing the Docker push to authentication
185 185
   // enabled Docker Registry (or Docker Hub).
186 186
   optional k8s.io.kubernetes.pkg.api.v1.LocalObjectReference pushSecret = 2;
187
+
188
+  // imageLabels define a list of labels that are applied to the resulting image. If there
189
+  // are multiple labels with the same name then the last one in the list is used.
190
+  repeated ImageLabel imageLabels = 3;
187 191
 }
188 192
 
189 193
 // A BuildPostCommitSpec holds a build post commit hook specification. The hook
... ...
@@ -641,6 +645,15 @@ message ImageChangeTrigger {
641 641
   optional k8s.io.kubernetes.pkg.api.v1.ObjectReference from = 2;
642 642
 }
643 643
 
644
+// ImageLabel represents a label applied to the resulting image.
645
+message ImageLabel {
646
+  // name defines the name of the label. It must have non-zero length.
647
+  optional string name = 1;
648
+
649
+  // value defines the literal value of the label.
650
+  optional string value = 2;
651
+}
652
+
644 653
 // ImageSource is used to describe build source that will be extracted from an image. A reference of
645 654
 // type ImageStreamTag, ImageStreamImage or DockerImage may be used. A pull secret can be specified
646 655
 // to pull the image from an external registry or override the default service account secret if pulling
... ...
@@ -118,9 +118,10 @@ func (BuildLogOptions) SwaggerDoc() map[string]string {
118 118
 }
119 119
 
120 120
 var map_BuildOutput = map[string]string{
121
-	"":           "BuildOutput is input to a build strategy and describes the Docker image that the strategy should produce.",
122
-	"to":         "to defines an optional location to push the output of this build to. Kind must be one of 'ImageStreamTag' or 'DockerImage'. This value will be used to look up a Docker image repository to push to. In the case of an ImageStreamTag, the ImageStreamTag will be looked for in the namespace of the build unless Namespace is specified.",
123
-	"pushSecret": "PushSecret is the name of a Secret that would be used for setting up the authentication for executing the Docker push to authentication enabled Docker Registry (or Docker Hub).",
121
+	"":            "BuildOutput is input to a build strategy and describes the Docker image that the strategy should produce.",
122
+	"to":          "to defines an optional location to push the output of this build to. Kind must be one of 'ImageStreamTag' or 'DockerImage'. This value will be used to look up a Docker image repository to push to. In the case of an ImageStreamTag, the ImageStreamTag will be looked for in the namespace of the build unless Namespace is specified.",
123
+	"pushSecret":  "PushSecret is the name of a Secret that would be used for setting up the authentication for executing the Docker push to authentication enabled Docker Registry (or Docker Hub).",
124
+	"imageLabels": "imageLabels define a list of labels that are applied to the resulting image. If there are multiple labels with the same name then the last one in the list is used.",
124 125
 }
125 126
 
126 127
 func (BuildOutput) SwaggerDoc() map[string]string {
... ...
@@ -359,6 +360,16 @@ func (ImageChangeTrigger) SwaggerDoc() map[string]string {
359 359
 	return map_ImageChangeTrigger
360 360
 }
361 361
 
362
+var map_ImageLabel = map[string]string{
363
+	"":      "ImageLabel represents a label applied to the resulting image.",
364
+	"name":  "name defines the name of the label. It must have non-zero length.",
365
+	"value": "value defines the literal value of the label.",
366
+}
367
+
368
+func (ImageLabel) SwaggerDoc() map[string]string {
369
+	return map_ImageLabel
370
+}
371
+
362 372
 var map_ImageSource = map[string]string{
363 373
 	"":           "ImageSource is used to describe build source that will be extracted from an image. A reference of type ImageStreamTag, ImageStreamImage or DockerImage may be used. A pull secret can be specified to pull the image from an external registry or override the default service account secret if pulling from the internal registry. A list of paths to copy from the image and their respective destination within the build directory must be specified in the paths array.",
364 374
 	"from":       "from is a reference to an ImageStreamTag, ImageStreamImage, or DockerImage to copy source from.",
... ...
@@ -622,6 +622,19 @@ type BuildOutput struct {
622 622
 	// up the authentication for executing the Docker push to authentication
623 623
 	// enabled Docker Registry (or Docker Hub).
624 624
 	PushSecret *kapi.LocalObjectReference `json:"pushSecret,omitempty" protobuf:"bytes,2,opt,name=pushSecret"`
625
+
626
+	// imageLabels define a list of labels that are applied to the resulting image. If there
627
+	// are multiple labels with the same name then the last one in the list is used.
628
+	ImageLabels []ImageLabel `json:"imageLabels,omitempty" protobuf:"bytes,3,rep,name=imageLabels"`
629
+}
630
+
631
+// ImageLabel represents a label applied to the resulting image.
632
+type ImageLabel struct {
633
+	// name defines the name of the label. It must have non-zero length.
634
+	Name string `json:"name" protobuf:"bytes,1,opt,name=name"`
635
+
636
+	// value defines the literal value of the label.
637
+	Value string `json:"value,omitempty" protobuf:"bytes,2,opt,name=value"`
625 638
 }
626 639
 
627 640
 // Build configurations define a build process for new Docker images. There are three types of builds possible - a Docker build using a Dockerfile, a Source-to-Image build that uses a specially prepared base image that accepts source code that it can make runnable, and a custom build that can run // arbitrary Docker images as a base and accept the build parameters. Builds run on the cluster and on completion are pushed to the Docker registry specified in the "output" section. A build can be triggered via a webhook, when the base image changes, or when a user manually requests a new build be // created.
... ...
@@ -81,6 +81,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
81 81
 		Convert_api_ImageChangeCause_To_v1_ImageChangeCause,
82 82
 		Convert_v1_ImageChangeTrigger_To_api_ImageChangeTrigger,
83 83
 		Convert_api_ImageChangeTrigger_To_v1_ImageChangeTrigger,
84
+		Convert_v1_ImageLabel_To_api_ImageLabel,
85
+		Convert_api_ImageLabel_To_v1_ImageLabel,
84 86
 		Convert_v1_ImageSource_To_api_ImageSource,
85 87
 		Convert_api_ImageSource_To_v1_ImageSource,
86 88
 		Convert_v1_ImageSourcePath_To_api_ImageSourcePath,
... ...
@@ -488,6 +490,17 @@ func autoConvert_v1_BuildOutput_To_api_BuildOutput(in *BuildOutput, out *api.Bui
488 488
 	} else {
489 489
 		out.PushSecret = nil
490 490
 	}
491
+	if in.ImageLabels != nil {
492
+		in, out := &in.ImageLabels, &out.ImageLabels
493
+		*out = make([]api.ImageLabel, len(*in))
494
+		for i := range *in {
495
+			if err := Convert_v1_ImageLabel_To_api_ImageLabel(&(*in)[i], &(*out)[i], s); err != nil {
496
+				return err
497
+			}
498
+		}
499
+	} else {
500
+		out.ImageLabels = nil
501
+	}
491 502
 	return nil
492 503
 }
493 504
 
... ...
@@ -510,6 +523,17 @@ func autoConvert_api_BuildOutput_To_v1_BuildOutput(in *api.BuildOutput, out *Bui
510 510
 	} else {
511 511
 		out.PushSecret = nil
512 512
 	}
513
+	if in.ImageLabels != nil {
514
+		in, out := &in.ImageLabels, &out.ImageLabels
515
+		*out = make([]ImageLabel, len(*in))
516
+		for i := range *in {
517
+			if err := Convert_api_ImageLabel_To_v1_ImageLabel(&(*in)[i], &(*out)[i], s); err != nil {
518
+				return err
519
+			}
520
+		}
521
+	} else {
522
+		out.ImageLabels = nil
523
+	}
513 524
 	return nil
514 525
 }
515 526
 
... ...
@@ -1638,6 +1662,26 @@ func Convert_api_ImageChangeTrigger_To_v1_ImageChangeTrigger(in *api.ImageChange
1638 1638
 	return autoConvert_api_ImageChangeTrigger_To_v1_ImageChangeTrigger(in, out, s)
1639 1639
 }
1640 1640
 
1641
+func autoConvert_v1_ImageLabel_To_api_ImageLabel(in *ImageLabel, out *api.ImageLabel, s conversion.Scope) error {
1642
+	out.Name = in.Name
1643
+	out.Value = in.Value
1644
+	return nil
1645
+}
1646
+
1647
+func Convert_v1_ImageLabel_To_api_ImageLabel(in *ImageLabel, out *api.ImageLabel, s conversion.Scope) error {
1648
+	return autoConvert_v1_ImageLabel_To_api_ImageLabel(in, out, s)
1649
+}
1650
+
1651
+func autoConvert_api_ImageLabel_To_v1_ImageLabel(in *api.ImageLabel, out *ImageLabel, s conversion.Scope) error {
1652
+	out.Name = in.Name
1653
+	out.Value = in.Value
1654
+	return nil
1655
+}
1656
+
1657
+func Convert_api_ImageLabel_To_v1_ImageLabel(in *api.ImageLabel, out *ImageLabel, s conversion.Scope) error {
1658
+	return autoConvert_api_ImageLabel_To_v1_ImageLabel(in, out, s)
1659
+}
1660
+
1641 1661
 func autoConvert_v1_ImageSource_To_api_ImageSource(in *ImageSource, out *api.ImageSource, s conversion.Scope) error {
1642 1662
 	if err := api_v1.Convert_v1_ObjectReference_To_api_ObjectReference(&in.From, &out.From, s); err != nil {
1643 1663
 		return err
... ...
@@ -50,6 +50,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
50 50
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_GitSourceRevision, InType: reflect.TypeOf(&GitSourceRevision{})},
51 51
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ImageChangeCause, InType: reflect.TypeOf(&ImageChangeCause{})},
52 52
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ImageChangeTrigger, InType: reflect.TypeOf(&ImageChangeTrigger{})},
53
+		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ImageLabel, InType: reflect.TypeOf(&ImageLabel{})},
53 54
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ImageSource, InType: reflect.TypeOf(&ImageSource{})},
54 55
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ImageSourcePath, InType: reflect.TypeOf(&ImageSourcePath{})},
55 56
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_JenkinsPipelineBuildStrategy, InType: reflect.TypeOf(&JenkinsPipelineBuildStrategy{})},
... ...
@@ -275,6 +276,15 @@ func DeepCopy_v1_BuildOutput(in interface{}, out interface{}, c *conversion.Clon
275 275
 		} else {
276 276
 			out.PushSecret = nil
277 277
 		}
278
+		if in.ImageLabels != nil {
279
+			in, out := &in.ImageLabels, &out.ImageLabels
280
+			*out = make([]ImageLabel, len(*in))
281
+			for i := range *in {
282
+				(*out)[i] = (*in)[i]
283
+			}
284
+		} else {
285
+			out.ImageLabels = nil
286
+		}
278 287
 		return nil
279 288
 	}
280 289
 }
... ...
@@ -850,6 +860,16 @@ func DeepCopy_v1_ImageChangeTrigger(in interface{}, out interface{}, c *conversi
850 850
 	}
851 851
 }
852 852
 
853
+func DeepCopy_v1_ImageLabel(in interface{}, out interface{}, c *conversion.Cloner) error {
854
+	{
855
+		in := in.(*ImageLabel)
856
+		out := out.(*ImageLabel)
857
+		out.Name = in.Name
858
+		out.Value = in.Value
859
+		return nil
860
+	}
861
+}
862
+
853 863
 func DeepCopy_v1_ImageSource(in interface{}, out interface{}, c *conversion.Cloner) error {
854 864
 	{
855 865
 		in := in.(*ImageSource)
... ...
@@ -422,6 +422,7 @@ func validateOutput(output *buildapi.BuildOutput, fldPath *field.Path) field.Err
422 422
 	}
423 423
 
424 424
 	allErrs = append(allErrs, validateSecretRef(output.PushSecret, fldPath.Child("pushSecret"))...)
425
+	allErrs = append(allErrs, ValidateImageLabels(output.ImageLabels, fldPath.Child("imageLabels"))...)
425 426
 
426 427
 	return allErrs
427 428
 }
... ...
@@ -670,3 +671,29 @@ func validateRuntimeImage(sourceStrategy *buildapi.SourceBuildStrategy, fldPath
670 670
 	}
671 671
 	return
672 672
 }
673
+
674
+func ValidateImageLabels(labels []buildapi.ImageLabel, fldPath *field.Path) (allErrs field.ErrorList) {
675
+	for i, lbl := range labels {
676
+		idxPath := fldPath.Index(i)
677
+		if len(lbl.Name) == 0 {
678
+			allErrs = append(allErrs, field.Required(idxPath.Child("name"), ""))
679
+			continue
680
+		}
681
+		for _, msg := range kvalidation.IsConfigMapKey(lbl.Name) {
682
+			allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), lbl.Name, msg))
683
+		}
684
+	}
685
+
686
+	// find duplicates
687
+	seen := make(map[string]bool)
688
+	for i, lbl := range labels {
689
+		idxPath := fldPath.Index(i)
690
+		if seen[lbl.Name] {
691
+			allErrs = append(allErrs, field.Invalid(idxPath.Child("name"), lbl.Name, "duplicate name"))
692
+			continue
693
+		}
694
+		seen[lbl.Name] = true
695
+	}
696
+
697
+	return
698
+}
... ...
@@ -1895,6 +1895,116 @@ func TestValidateCommonSpec(t *testing.T) {
1895 1895
 				},
1896 1896
 			},
1897 1897
 		},
1898
+		// 32
1899
+		{
1900
+			string(field.ErrorTypeRequired) + "output.imageLabels[0].name",
1901
+			buildapi.CommonSpec{
1902
+				Source: buildapi.BuildSource{
1903
+					Git: &buildapi.GitBuildSource{
1904
+						URI: "http://github.com/my/repository",
1905
+					},
1906
+				},
1907
+				Strategy: buildapi.BuildStrategy{
1908
+					DockerStrategy: &buildapi.DockerBuildStrategy{},
1909
+				},
1910
+				Output: buildapi.BuildOutput{
1911
+					ImageLabels: []buildapi.ImageLabel{
1912
+						{
1913
+							Name:  "",
1914
+							Value: "",
1915
+						},
1916
+					},
1917
+				},
1918
+			},
1919
+		},
1920
+		// 33
1921
+		{
1922
+			string(field.ErrorTypeInvalid) + "output.imageLabels[0].name",
1923
+			buildapi.CommonSpec{
1924
+				Source: buildapi.BuildSource{
1925
+					Git: &buildapi.GitBuildSource{
1926
+						URI: "http://github.com/my/repository",
1927
+					},
1928
+				},
1929
+				Strategy: buildapi.BuildStrategy{
1930
+					DockerStrategy: &buildapi.DockerBuildStrategy{},
1931
+				},
1932
+				Output: buildapi.BuildOutput{
1933
+					ImageLabels: []buildapi.ImageLabel{
1934
+						{
1935
+							Name:  "%$#@!",
1936
+							Value: "",
1937
+						},
1938
+					},
1939
+				},
1940
+			},
1941
+		},
1942
+		// 34
1943
+		// duplicate labels
1944
+		{
1945
+			string(field.ErrorTypeInvalid) + "output.imageLabels[1].name",
1946
+			buildapi.CommonSpec{
1947
+				Source: buildapi.BuildSource{
1948
+					Git: &buildapi.GitBuildSource{
1949
+						URI: "http://github.com/my/repository",
1950
+					},
1951
+				},
1952
+				Strategy: buildapi.BuildStrategy{
1953
+					DockerStrategy: &buildapi.DockerBuildStrategy{},
1954
+				},
1955
+				Output: buildapi.BuildOutput{
1956
+					ImageLabels: []buildapi.ImageLabel{
1957
+						{
1958
+							Name:  "really",
1959
+							Value: "yes",
1960
+						},
1961
+						{
1962
+							Name:  "really",
1963
+							Value: "no",
1964
+						},
1965
+					},
1966
+				},
1967
+			},
1968
+		},
1969
+		// 35
1970
+		// nonconsecutive duplicate labels
1971
+		{
1972
+			string(field.ErrorTypeInvalid) + "output.imageLabels[3].name",
1973
+			buildapi.CommonSpec{
1974
+				Source: buildapi.BuildSource{
1975
+					Git: &buildapi.GitBuildSource{
1976
+						URI: "http://github.com/my/repository",
1977
+					},
1978
+				},
1979
+				Strategy: buildapi.BuildStrategy{
1980
+					DockerStrategy: &buildapi.DockerBuildStrategy{},
1981
+				},
1982
+				Output: buildapi.BuildOutput{
1983
+					ImageLabels: []buildapi.ImageLabel{
1984
+						{
1985
+							Name:  "a",
1986
+							Value: "1",
1987
+						},
1988
+						{
1989
+							Name:  "really",
1990
+							Value: "yes",
1991
+						},
1992
+						{
1993
+							Name:  "b",
1994
+							Value: "2",
1995
+						},
1996
+						{
1997
+							Name:  "really",
1998
+							Value: "no",
1999
+						},
2000
+						{
2001
+							Name:  "c",
2002
+							Value: "3",
2003
+						},
2004
+					},
2005
+				},
2006
+			},
2007
+		},
1898 2008
 	}
1899 2009
 
1900 2010
 	for count, config := range errorCases {
... ...
@@ -2105,6 +2215,79 @@ func TestValidateCommonSpecSuccess(t *testing.T) {
2105 2105
 				},
2106 2106
 			},
2107 2107
 		},
2108
+		// 6
2109
+		{
2110
+			CommonSpec: buildapi.CommonSpec{
2111
+				Source: buildapi.BuildSource{
2112
+					Git: &buildapi.GitBuildSource{
2113
+						URI: "http://github.com/my/repository",
2114
+					},
2115
+				},
2116
+				Strategy: buildapi.BuildStrategy{
2117
+					DockerStrategy: &buildapi.DockerBuildStrategy{},
2118
+				},
2119
+				Output: buildapi.BuildOutput{
2120
+					ImageLabels: nil,
2121
+				},
2122
+			},
2123
+		},
2124
+		// 7
2125
+		{
2126
+			CommonSpec: buildapi.CommonSpec{
2127
+				Source: buildapi.BuildSource{
2128
+					Git: &buildapi.GitBuildSource{
2129
+						URI: "http://github.com/my/repository",
2130
+					},
2131
+				},
2132
+				Strategy: buildapi.BuildStrategy{
2133
+					DockerStrategy: &buildapi.DockerBuildStrategy{},
2134
+				},
2135
+				Output: buildapi.BuildOutput{
2136
+					ImageLabels: []buildapi.ImageLabel{},
2137
+				},
2138
+			},
2139
+		},
2140
+		// 8
2141
+		{
2142
+			CommonSpec: buildapi.CommonSpec{
2143
+				Source: buildapi.BuildSource{
2144
+					Git: &buildapi.GitBuildSource{
2145
+						URI: "http://github.com/my/repository",
2146
+					},
2147
+				},
2148
+				Strategy: buildapi.BuildStrategy{
2149
+					DockerStrategy: &buildapi.DockerBuildStrategy{},
2150
+				},
2151
+				Output: buildapi.BuildOutput{
2152
+					ImageLabels: []buildapi.ImageLabel{
2153
+						{
2154
+							Name: "key",
2155
+						},
2156
+					},
2157
+				},
2158
+			},
2159
+		},
2160
+		// 9
2161
+		{
2162
+			CommonSpec: buildapi.CommonSpec{
2163
+				Source: buildapi.BuildSource{
2164
+					Git: &buildapi.GitBuildSource{
2165
+						URI: "http://github.com/my/repository",
2166
+					},
2167
+				},
2168
+				Strategy: buildapi.BuildStrategy{
2169
+					DockerStrategy: &buildapi.DockerBuildStrategy{},
2170
+				},
2171
+				Output: buildapi.BuildOutput{
2172
+					ImageLabels: []buildapi.ImageLabel{
2173
+						{
2174
+							Name:  "key",
2175
+							Value: "value )(*&",
2176
+						},
2177
+					},
2178
+				},
2179
+			},
2180
+		},
2108 2181
 	}
2109 2182
 	for count, config := range testCases {
2110 2183
 		errors := validateCommonSpec(&config.CommonSpec, nil)
... ...
@@ -51,6 +51,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
51 51
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_GitSourceRevision, InType: reflect.TypeOf(&GitSourceRevision{})},
52 52
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ImageChangeCause, InType: reflect.TypeOf(&ImageChangeCause{})},
53 53
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ImageChangeTrigger, InType: reflect.TypeOf(&ImageChangeTrigger{})},
54
+		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ImageLabel, InType: reflect.TypeOf(&ImageLabel{})},
54 55
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ImageSource, InType: reflect.TypeOf(&ImageSource{})},
55 56
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ImageSourcePath, InType: reflect.TypeOf(&ImageSourcePath{})},
56 57
 		conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_JenkinsPipelineBuildStrategy, InType: reflect.TypeOf(&JenkinsPipelineBuildStrategy{})},
... ...
@@ -276,6 +277,15 @@ func DeepCopy_api_BuildOutput(in interface{}, out interface{}, c *conversion.Clo
276 276
 		} else {
277 277
 			out.PushSecret = nil
278 278
 		}
279
+		if in.ImageLabels != nil {
280
+			in, out := &in.ImageLabels, &out.ImageLabels
281
+			*out = make([]ImageLabel, len(*in))
282
+			for i := range *in {
283
+				(*out)[i] = (*in)[i]
284
+			}
285
+		} else {
286
+			out.ImageLabels = nil
287
+		}
279 288
 		return nil
280 289
 	}
281 290
 }
... ...
@@ -871,6 +881,16 @@ func DeepCopy_api_ImageChangeTrigger(in interface{}, out interface{}, c *convers
871 871
 	}
872 872
 }
873 873
 
874
+func DeepCopy_api_ImageLabel(in interface{}, out interface{}, c *conversion.Cloner) error {
875
+	{
876
+		in := in.(*ImageLabel)
877
+		out := out.(*ImageLabel)
878
+		out.Name = in.Name
879
+		out.Value = in.Value
880
+		return nil
881
+	}
882
+}
883
+
874 884
 func DeepCopy_api_ImageSource(in interface{}, out interface{}, c *conversion.Cloner) error {
875 885
 	{
876 886
 		in := in.(*ImageSource)
... ...
@@ -254,10 +254,14 @@ func (d *DockerBuilder) buildLabels(dir string) []dockerfile.KeyValue {
254 254
 		sourceInfo.ContextDir = d.build.Spec.Source.ContextDir
255 255
 	}
256 256
 	labels = util.GenerateLabelsFromSourceInfo(labels, &sourceInfo.SourceInfo, api.DefaultDockerLabelNamespace)
257
-	kv := make([]dockerfile.KeyValue, 0, len(labels))
257
+	kv := make([]dockerfile.KeyValue, 0, len(labels)+len(d.build.Spec.Output.ImageLabels))
258 258
 	for k, v := range labels {
259 259
 		kv = append(kv, dockerfile.KeyValue{Key: k, Value: v})
260 260
 	}
261
+	// override autogenerated labels
262
+	for _, lbl := range d.build.Spec.Output.ImageLabels {
263
+		kv = append(kv, dockerfile.KeyValue{Key: lbl.Name, Value: lbl.Value})
264
+	}
261 265
 	return kv
262 266
 }
263 267
 
... ...
@@ -183,6 +183,7 @@ func (s *S2IBuilder) Build() error {
183 183
 		IncrementalFromTag: pushTag,
184 184
 
185 185
 		Environment:       buildEnvVars(s.build),
186
+		Labels:            buildLabels(s.build),
186 187
 		DockerNetworkMode: getDockerNetworkMode(),
187 188
 
188 189
 		Source:                    sourceURI.String(),
... ...
@@ -352,6 +353,14 @@ func buildEnvVars(build *api.Build) s2iapi.EnvironmentList {
352 352
 	return *envVars
353 353
 }
354 354
 
355
+func buildLabels(build *api.Build) map[string]string {
356
+	labels := make(map[string]string)
357
+	for _, lbl := range build.Spec.Output.ImageLabels {
358
+		labels[lbl.Name] = lbl.Value
359
+	}
360
+	return labels
361
+}
362
+
355 363
 // scriptProxyConfig determines a proxy configuration for downloading
356 364
 // scripts from a URL. For now, it uses environment variables passed in
357 365
 // the strategy's environment. There is no preference given to either lowercase
... ...
@@ -84,7 +84,7 @@ var _ = g.Describe("[builds][Slow] result image should have proper labels set",
84 84
 	})
85 85
 })
86 86
 
87
-// ExpectOpenShiftLabels tests if builded Docker image contains appropriate
87
+// ExpectOpenShiftLabels tests if built Docker image contains appropriate
88 88
 // labels.
89 89
 func ExpectOpenShiftLabels(labels map[string]string) error {
90 90
 	ExpectedLabels := []string{
... ...
@@ -95,11 +95,12 @@ func ExpectOpenShiftLabels(labels map[string]string) error {
95 95
 		"io.openshift.build.commit.message",
96 96
 		"io.openshift.build.source-location",
97 97
 		"io.openshift.build.source-context-dir",
98
+		"user-specified-label",
98 99
 	}
99 100
 
100 101
 	for _, label := range ExpectedLabels {
101 102
 		if labels[label] == "" {
102
-			return fmt.Errorf("Builded image doesn't contain proper Docker image labels. Missing %q label", label)
103
+			return fmt.Errorf("Built image doesn't contain proper Docker image labels. Missing %q label", label)
103 104
 		}
104 105
 	}
105 106
 
... ...
@@ -29,7 +29,13 @@
29 29
       "to":{
30 30
         "kind":"ImageStreamTag",
31 31
         "name":"test:latest"
32
-      }
32
+      },
33
+      "imageLabels": [
34
+        {
35
+          "name": "user-specified-label",
36
+          "value": "arbitrary-value"
37
+        }
38
+      ]
33 39
     }
34 40
   }
35 41
 }
... ...
@@ -35,7 +35,13 @@
35 35
       "to": {
36 36
         "kind": "ImageStreamTag",
37 37
         "name": "test:latest"
38
-      }
38
+      },
39
+      "imageLabels": [
40
+        {
41
+          "name": "user-specified-label",
42
+          "value": "arbitrary-value"
43
+        }
44
+      ]
39 45
     }
40 46
   }
41
-}
42 47
\ No newline at end of file
48
+}