diff --git a/USERS.md b/USERS.md index 08176d9d80138..fa34d7e6726e3 100644 --- a/USERS.md +++ b/USERS.md @@ -94,6 +94,7 @@ Currently, the following organizations are **officially** using Argo CD: 1. [Daydream](https://daydream.ing) 1. [Deloitte](https://www.deloitte.com/) 1. [Deutsche Telekom AG](https://telekom.com) +1. [Deutsche Bank AG](https://www.deutsche-bank.de/) 1. [Devopsi - Poland Software/DevOps Consulting](https://devopsi.pl/) 1. [Devtron Labs](https://github.com/devtron-labs/devtron) 1. [DigitalEd](https://www.digitaled.com) diff --git a/assets/swagger.json b/assets/swagger.json index ce1d12d9be5e8..95779c28b5670 100644 --- a/assets/swagger.json +++ b/assets/swagger.json @@ -1490,43 +1490,8 @@ "in": "body", "required": true, "schema": { - "type": "string" + "$ref": "#/definitions/applicationResourceActionRunRequest" } - }, - { - "type": "string", - "name": "namespace", - "in": "query" - }, - { - "type": "string", - "name": "resourceName", - "in": "query" - }, - { - "type": "string", - "name": "version", - "in": "query" - }, - { - "type": "string", - "name": "group", - "in": "query" - }, - { - "type": "string", - "name": "kind", - "in": "query" - }, - { - "type": "string", - "name": "appNamespace", - "in": "query" - }, - { - "type": "string", - "name": "project", - "in": "query" } ], "responses": { @@ -5032,6 +4997,55 @@ "applicationOperationTerminateResponse": { "type": "object" }, + "applicationResourceActionParameters": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "applicationResourceActionRunRequest": { + "type": "object", + "properties": { + "action": { + "type": "string" + }, + "appNamespace": { + "type": "string" + }, + "group": { + "type": "string" + }, + "kind": { + "type": "string" + }, + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "project": { + "type": "string" + }, + "resourceActionParameters": { + "type": "array", + "items": { + "$ref": "#/definitions/applicationResourceActionParameters" + } + }, + "resourceName": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, "applicationResourceActionsListResponse": { "type": "object", "properties": { diff --git a/cmd/argocd/commands/admin/settings.go b/cmd/argocd/commands/admin/settings.go index e3d0b74d48726..a239de54b0a7f 100644 --- a/cmd/argocd/commands/admin/settings.go +++ b/cmd/argocd/commands/admin/settings.go @@ -24,6 +24,7 @@ import ( "sigs.k8s.io/yaml" "github.com/argoproj/argo-cd/v3/common" + applicationpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/application" "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v3/util/argo/normalizers" "github.com/argoproj/argo-cd/v3/util/cli" @@ -563,6 +564,8 @@ argocd admin settings resource-overrides action list /tmp/deploy.yaml --argocd-c } func NewResourceActionRunCommand(cmdCtx commandContext) *cobra.Command { + var resourceActionParameters []string + command := &cobra.Command{ Use: "run-action RESOURCE_YAML_PATH ACTION", Aliases: []string{"action"}, @@ -579,6 +582,23 @@ argocd admin settings resource-overrides action /tmp/deploy.yaml restart --argoc } action := args[1] + // Parse resource action parameters + parsedParams := make([]*applicationpkg.ResourceActionParameters, 0) + if len(resourceActionParameters) > 0 { + for _, param := range resourceActionParameters { + parts := strings.SplitN(param, "=", 2) + if len(parts) != 2 { + log.Fatalf("Invalid parameter format: %s", param) + } + name := parts[0] + value := parts[1] + parsedParams = append(parsedParams, &applicationpkg.ResourceActionParameters{ + Name: &name, + Value: &value, + }) + } + } + executeResourceOverrideCommand(ctx, cmdCtx, args, func(res unstructured.Unstructured, override v1alpha1.ResourceOverride, overrides map[string]v1alpha1.ResourceOverride) { gvk := res.GroupVersionKind() if override.Actions == "" { @@ -590,7 +610,7 @@ argocd admin settings resource-overrides action /tmp/deploy.yaml restart --argoc action, err := luaVM.GetResourceAction(&res, action) errors.CheckError(err) - modifiedRes, err := luaVM.ExecuteResourceAction(&res, action.ActionLua) + modifiedRes, err := luaVM.ExecuteResourceAction(&res, action.ActionLua, parsedParams) errors.CheckError(err) for _, impactedResource := range modifiedRes { @@ -615,5 +635,7 @@ argocd admin settings resource-overrides action /tmp/deploy.yaml restart --argoc }) }, } + + command.Flags().StringArrayVar(&resourceActionParameters, "param", []string{}, "Action parameters (e.g. --param key1=value1)") return command } diff --git a/docs/assets/scale_resources_1.png b/docs/assets/scale_resources_1.png new file mode 100644 index 0000000000000..73b7fb45a8fb3 Binary files /dev/null and b/docs/assets/scale_resources_1.png differ diff --git a/docs/assets/scale_resources_2.png b/docs/assets/scale_resources_2.png new file mode 100644 index 0000000000000..e88d3aee6fab4 Binary files /dev/null and b/docs/assets/scale_resources_2.png differ diff --git a/docs/assets/scale_resources_3.png b/docs/assets/scale_resources_3.png new file mode 100644 index 0000000000000..04f62e4a24fbb Binary files /dev/null and b/docs/assets/scale_resources_3.png differ diff --git a/docs/operator-manual/resource_actions_builtin.md b/docs/operator-manual/resource_actions_builtin.md index 51735e4ad5c30..20681af407bfa 100644 --- a/docs/operator-manual/resource_actions_builtin.md +++ b/docs/operator-manual/resource_actions_builtin.md @@ -2,7 +2,9 @@ - [apps/Deployment/pause](https://github.com/argoproj/argo-cd/blob/master/resource_customizations/apps/Deployment/actions/pause/action.lua) - [apps/Deployment/restart](https://github.com/argoproj/argo-cd/blob/master/resource_customizations/apps/Deployment/actions/restart/action.lua) - [apps/Deployment/resume](https://github.com/argoproj/argo-cd/blob/master/resource_customizations/apps/Deployment/actions/resume/action.lua) +- [apps/Deployment/scale](https://github.com/argoproj/argo-cd/blob/master/resource_customizations/apps/Deployment/actions/scale/action.lua) - [apps/StatefulSet/restart](https://github.com/argoproj/argo-cd/blob/master/resource_customizations/apps/StatefulSet/actions/restart/action.lua) +- [apps/StatefulSet/scale](https://github.com/argoproj/argo-cd/blob/master/resource_customizations/apps/StatefulSet/actions/scale/action.lua) - [argoproj.io/AnalysisRun/terminate](https://github.com/argoproj/argo-cd/blob/master/resource_customizations/argoproj.io/AnalysisRun/actions/terminate/action.lua) - [argoproj.io/CronWorkflow/create-workflow](https://github.com/argoproj/argo-cd/blob/master/resource_customizations/argoproj.io/CronWorkflow/actions/create-workflow/action.lua) - [argoproj.io/Rollout/abort](https://github.com/argoproj/argo-cd/blob/master/resource_customizations/argoproj.io/Rollout/actions/abort/action.lua) diff --git a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_run-action.md b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_run-action.md index 41d9213db7636..e10d6ece07bdf 100644 --- a/docs/user-guide/commands/argocd_admin_settings_resource-overrides_run-action.md +++ b/docs/user-guide/commands/argocd_admin_settings_resource-overrides_run-action.md @@ -22,7 +22,8 @@ argocd admin settings resource-overrides action /tmp/deploy.yaml restart --argoc ### Options ``` - -h, --help help for run-action + -h, --help help for run-action + --param stringArray Action parameters (e.g. --param key1=value1) ``` ### Options inherited from parent commands diff --git a/docs/user-guide/scale_application_resources.md b/docs/user-guide/scale_application_resources.md new file mode 100644 index 0000000000000..53858983a6284 --- /dev/null +++ b/docs/user-guide/scale_application_resources.md @@ -0,0 +1,22 @@ +# Scale Resources in ArgoCD UI + +This enables users to scale resources directly from the ArgoCD UI. Users will be able to increase or decrease the number of replicas (Pods) for Deployments and StatefulSets by using an input field. The feature aims to enhance user experience, especially for non-technical users, by eliminating the need to modify configuration files or use kubectl commands for scaling. + + +## Example Usage +1. User navigates to a Deployment or StatefulSet in any ArgoCD application. +2. User clicks on the Actions dropdown and selects "Scale". + ![action button for scaling](../assets/scale_resources_1.png) +3. A modal pops up showing an input field `Enter input parameters for action: scale` with the current number of Pods. +4. User adjusts the number of Pods by entering a number. + ![input field for scaling](../assets/scale_resources_2.png) +5. User presses OK, and the resource is scaled accordingly. + ![result for scaling](../assets/scale_resources_3.png) + + +!!! note + This feature will only apply to `Deployments`, and `StatefulSets`. + +!!! note + If you use HPA (Horizontal Pod Autoscaling) or enabled ArgoCD auto-sync, changing the replica count in scale actions would be overwritten. + Ensure that invalid values (e.g., `non-numeric` characters, `negative` numbers, or values beyond the `max integer limit`) cannot be entered. diff --git a/pkg/apiclient/application/application.pb.go b/pkg/apiclient/application/application.pb.go index ad02b2b6b9b2a..8b72807e852a3 100644 --- a/pkg/apiclient/application/application.pb.go +++ b/pkg/apiclient/application/application.pb.go @@ -1717,26 +1717,82 @@ func (m *ApplicationResourceDeleteRequest) GetProject() string { return "" } -type ResourceActionRunRequest struct { +type ResourceActionParameters struct { Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` - Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"` - ResourceName *string `protobuf:"bytes,3,req,name=resourceName" json:"resourceName,omitempty"` - Version *string `protobuf:"bytes,4,req,name=version" json:"version,omitempty"` - Group *string `protobuf:"bytes,5,opt,name=group" json:"group,omitempty"` - Kind *string `protobuf:"bytes,6,req,name=kind" json:"kind,omitempty"` - Action *string `protobuf:"bytes,7,req,name=action" json:"action,omitempty"` - AppNamespace *string `protobuf:"bytes,8,opt,name=appNamespace" json:"appNamespace,omitempty"` - Project *string `protobuf:"bytes,9,opt,name=project" json:"project,omitempty"` + Value *string `protobuf:"bytes,2,req,name=value" json:"value,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` } +func (m *ResourceActionParameters) Reset() { *m = ResourceActionParameters{} } +func (m *ResourceActionParameters) String() string { return proto.CompactTextString(m) } +func (*ResourceActionParameters) ProtoMessage() {} +func (*ResourceActionParameters) Descriptor() ([]byte, []int) { + return fileDescriptor_df6e82b174b5eaec, []int{20} +} +func (m *ResourceActionParameters) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ResourceActionParameters) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ResourceActionParameters.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ResourceActionParameters) XXX_Merge(src proto.Message) { + xxx_messageInfo_ResourceActionParameters.Merge(m, src) +} +func (m *ResourceActionParameters) XXX_Size() int { + return m.Size() +} +func (m *ResourceActionParameters) XXX_DiscardUnknown() { + xxx_messageInfo_ResourceActionParameters.DiscardUnknown(m) +} + +var xxx_messageInfo_ResourceActionParameters proto.InternalMessageInfo + +func (m *ResourceActionParameters) GetName() string { + if m != nil && m.Name != nil { + return *m.Name + } + return "" +} + +func (m *ResourceActionParameters) GetValue() string { + if m != nil && m.Value != nil { + return *m.Value + } + return "" +} + +type ResourceActionRunRequest struct { + Name *string `protobuf:"bytes,1,req,name=name" json:"name,omitempty"` + Namespace *string `protobuf:"bytes,2,opt,name=namespace" json:"namespace,omitempty"` + ResourceName *string `protobuf:"bytes,3,req,name=resourceName" json:"resourceName,omitempty"` + Version *string `protobuf:"bytes,4,req,name=version" json:"version,omitempty"` + Group *string `protobuf:"bytes,5,opt,name=group" json:"group,omitempty"` + Kind *string `protobuf:"bytes,6,req,name=kind" json:"kind,omitempty"` + Action *string `protobuf:"bytes,7,req,name=action" json:"action,omitempty"` + AppNamespace *string `protobuf:"bytes,8,opt,name=appNamespace" json:"appNamespace,omitempty"` + Project *string `protobuf:"bytes,9,opt,name=project" json:"project,omitempty"` + ResourceActionParameters []*ResourceActionParameters `protobuf:"bytes,10,rep,name=resourceActionParameters" json:"resourceActionParameters,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + func (m *ResourceActionRunRequest) Reset() { *m = ResourceActionRunRequest{} } func (m *ResourceActionRunRequest) String() string { return proto.CompactTextString(m) } func (*ResourceActionRunRequest) ProtoMessage() {} func (*ResourceActionRunRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{20} + return fileDescriptor_df6e82b174b5eaec, []int{21} } func (m *ResourceActionRunRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1828,6 +1884,13 @@ func (m *ResourceActionRunRequest) GetProject() string { return "" } +func (m *ResourceActionRunRequest) GetResourceActionParameters() []*ResourceActionParameters { + if m != nil { + return m.ResourceActionParameters + } + return nil +} + type ResourceActionsListResponse struct { Actions []*v1alpha1.ResourceAction `protobuf:"bytes,1,rep,name=actions" json:"actions,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -1839,7 +1902,7 @@ func (m *ResourceActionsListResponse) Reset() { *m = ResourceActionsList func (m *ResourceActionsListResponse) String() string { return proto.CompactTextString(m) } func (*ResourceActionsListResponse) ProtoMessage() {} func (*ResourceActionsListResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{21} + return fileDescriptor_df6e82b174b5eaec, []int{22} } func (m *ResourceActionsListResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1886,7 +1949,7 @@ func (m *ApplicationResourceResponse) Reset() { *m = ApplicationResource func (m *ApplicationResourceResponse) String() string { return proto.CompactTextString(m) } func (*ApplicationResourceResponse) ProtoMessage() {} func (*ApplicationResourceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{22} + return fileDescriptor_df6e82b174b5eaec, []int{23} } func (m *ApplicationResourceResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1949,7 +2012,7 @@ func (m *ApplicationPodLogsQuery) Reset() { *m = ApplicationPodLogsQuery func (m *ApplicationPodLogsQuery) String() string { return proto.CompactTextString(m) } func (*ApplicationPodLogsQuery) ProtoMessage() {} func (*ApplicationPodLogsQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{23} + return fileDescriptor_df6e82b174b5eaec, []int{24} } func (m *ApplicationPodLogsQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2113,7 +2176,7 @@ func (m *LogEntry) Reset() { *m = LogEntry{} } func (m *LogEntry) String() string { return proto.CompactTextString(m) } func (*LogEntry) ProtoMessage() {} func (*LogEntry) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{24} + return fileDescriptor_df6e82b174b5eaec, []int{25} } func (m *LogEntry) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2190,7 +2253,7 @@ func (m *OperationTerminateRequest) Reset() { *m = OperationTerminateReq func (m *OperationTerminateRequest) String() string { return proto.CompactTextString(m) } func (*OperationTerminateRequest) ProtoMessage() {} func (*OperationTerminateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{25} + return fileDescriptor_df6e82b174b5eaec, []int{26} } func (m *OperationTerminateRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2253,7 +2316,7 @@ func (m *ApplicationSyncWindowsQuery) Reset() { *m = ApplicationSyncWind func (m *ApplicationSyncWindowsQuery) String() string { return proto.CompactTextString(m) } func (*ApplicationSyncWindowsQuery) ProtoMessage() {} func (*ApplicationSyncWindowsQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{26} + return fileDescriptor_df6e82b174b5eaec, []int{27} } func (m *ApplicationSyncWindowsQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2316,7 +2379,7 @@ func (m *ApplicationSyncWindowsResponse) Reset() { *m = ApplicationSyncW func (m *ApplicationSyncWindowsResponse) String() string { return proto.CompactTextString(m) } func (*ApplicationSyncWindowsResponse) ProtoMessage() {} func (*ApplicationSyncWindowsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{27} + return fileDescriptor_df6e82b174b5eaec, []int{28} } func (m *ApplicationSyncWindowsResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2380,7 +2443,7 @@ func (m *ApplicationSyncWindow) Reset() { *m = ApplicationSyncWindow{} } func (m *ApplicationSyncWindow) String() string { return proto.CompactTextString(m) } func (*ApplicationSyncWindow) ProtoMessage() {} func (*ApplicationSyncWindow) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{28} + return fileDescriptor_df6e82b174b5eaec, []int{29} } func (m *ApplicationSyncWindow) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2447,7 +2510,7 @@ func (m *OperationTerminateResponse) Reset() { *m = OperationTerminateRe func (m *OperationTerminateResponse) String() string { return proto.CompactTextString(m) } func (*OperationTerminateResponse) ProtoMessage() {} func (*OperationTerminateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{29} + return fileDescriptor_df6e82b174b5eaec, []int{30} } func (m *OperationTerminateResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2494,7 +2557,7 @@ func (m *ResourcesQuery) Reset() { *m = ResourcesQuery{} } func (m *ResourcesQuery) String() string { return proto.CompactTextString(m) } func (*ResourcesQuery) ProtoMessage() {} func (*ResourcesQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{30} + return fileDescriptor_df6e82b174b5eaec, []int{31} } func (m *ResourcesQuery) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2590,7 +2653,7 @@ func (m *ManagedResourcesResponse) Reset() { *m = ManagedResourcesRespon func (m *ManagedResourcesResponse) String() string { return proto.CompactTextString(m) } func (*ManagedResourcesResponse) ProtoMessage() {} func (*ManagedResourcesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{31} + return fileDescriptor_df6e82b174b5eaec, []int{32} } func (m *ManagedResourcesResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2640,7 +2703,7 @@ func (m *LinkInfo) Reset() { *m = LinkInfo{} } func (m *LinkInfo) String() string { return proto.CompactTextString(m) } func (*LinkInfo) ProtoMessage() {} func (*LinkInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{32} + return fileDescriptor_df6e82b174b5eaec, []int{33} } func (m *LinkInfo) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2708,7 +2771,7 @@ func (m *LinksResponse) Reset() { *m = LinksResponse{} } func (m *LinksResponse) String() string { return proto.CompactTextString(m) } func (*LinksResponse) ProtoMessage() {} func (*LinksResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{33} + return fileDescriptor_df6e82b174b5eaec, []int{34} } func (m *LinksResponse) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2757,7 +2820,7 @@ func (m *ListAppLinksRequest) Reset() { *m = ListAppLinksRequest{} } func (m *ListAppLinksRequest) String() string { return proto.CompactTextString(m) } func (*ListAppLinksRequest) ProtoMessage() {} func (*ListAppLinksRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_df6e82b174b5eaec, []int{34} + return fileDescriptor_df6e82b174b5eaec, []int{35} } func (m *ListAppLinksRequest) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -2828,6 +2891,7 @@ func init() { proto.RegisterType((*ApplicationResourceRequest)(nil), "application.ApplicationResourceRequest") proto.RegisterType((*ApplicationResourcePatchRequest)(nil), "application.ApplicationResourcePatchRequest") proto.RegisterType((*ApplicationResourceDeleteRequest)(nil), "application.ApplicationResourceDeleteRequest") + proto.RegisterType((*ResourceActionParameters)(nil), "application.ResourceActionParameters") proto.RegisterType((*ResourceActionRunRequest)(nil), "application.ResourceActionRunRequest") proto.RegisterType((*ResourceActionsListResponse)(nil), "application.ResourceActionsListResponse") proto.RegisterType((*ApplicationResourceResponse)(nil), "application.ApplicationResourceResponse") @@ -2850,180 +2914,183 @@ func init() { } var fileDescriptor_df6e82b174b5eaec = []byte{ - // 2759 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0x4d, 0x8c, 0x1b, 0x49, - 0xf5, 0xff, 0x97, 0x3d, 0x9e, 0xf1, 0x3c, 0xcf, 0x64, 0x92, 0xda, 0x64, 0xfe, 0xbd, 0xce, 0x6c, - 0xf0, 0x76, 0x92, 0x8d, 0x77, 0x92, 0xb1, 0x93, 0x49, 0x40, 0xd9, 0xd9, 0x5d, 0x41, 0x32, 0xf9, - 0x84, 0x49, 0x36, 0xf4, 0x24, 0x04, 0x2d, 0x07, 0xa8, 0xed, 0xae, 0xb1, 0x9b, 0xb1, 0xbb, 0x3b, - 0xdd, 0x6d, 0x87, 0x51, 0xc8, 0x65, 0x11, 0x17, 0xb4, 0x02, 0x01, 0x7b, 0x40, 0x08, 0x01, 0xda, - 0xd5, 0x4a, 0x08, 0x81, 0xb8, 0x20, 0x84, 0x84, 0x90, 0xe0, 0x00, 0x82, 0x03, 0xd2, 0x0a, 0x8e, - 0x5c, 0x50, 0x84, 0x38, 0xc2, 0x65, 0xcf, 0x08, 0x55, 0x75, 0x55, 0x77, 0xb5, 0x3f, 0xda, 0x1e, - 0x6c, 0xb4, 0xb9, 0xf5, 0x2b, 0x57, 0xbd, 0xf7, 0x7b, 0xaf, 0x5e, 0xbd, 0xf7, 0xea, 0x95, 0xe1, - 0x44, 0x40, 0xfd, 0x2e, 0xf5, 0xeb, 0xc4, 0xf3, 0x5a, 0xb6, 0x49, 0x42, 0xdb, 0x75, 0xd4, 0xef, - 0x9a, 0xe7, 0xbb, 0xa1, 0x8b, 0x4b, 0xca, 0x50, 0x79, 0xa5, 0xe1, 0xba, 0x8d, 0x16, 0xad, 0x13, - 0xcf, 0xae, 0x13, 0xc7, 0x71, 0x43, 0x3e, 0x1c, 0x44, 0x53, 0xcb, 0xfa, 0xee, 0xc5, 0xa0, 0x66, - 0xbb, 0xfc, 0x57, 0xd3, 0xf5, 0x69, 0xbd, 0x7b, 0xae, 0xde, 0xa0, 0x0e, 0xf5, 0x49, 0x48, 0x2d, - 0x31, 0xe7, 0x42, 0x32, 0xa7, 0x4d, 0xcc, 0xa6, 0xed, 0x50, 0x7f, 0xaf, 0xee, 0xed, 0x36, 0xd8, - 0x40, 0x50, 0x6f, 0xd3, 0x90, 0x0c, 0x5a, 0xb5, 0xd5, 0xb0, 0xc3, 0x66, 0xe7, 0x8d, 0x9a, 0xe9, - 0xb6, 0xeb, 0xc4, 0x6f, 0xb8, 0x9e, 0xef, 0x7e, 0x91, 0x7f, 0xac, 0x99, 0x56, 0xbd, 0x7b, 0x3e, - 0x61, 0xa0, 0xea, 0xd2, 0x3d, 0x47, 0x5a, 0x5e, 0x93, 0xf4, 0x73, 0xbb, 0x3a, 0x82, 0x9b, 0x4f, - 0x3d, 0x57, 0xd8, 0x86, 0x7f, 0xda, 0xa1, 0xeb, 0xef, 0x29, 0x9f, 0x11, 0x1b, 0xfd, 0x03, 0x04, - 0x07, 0x2f, 0x25, 0xf2, 0x3e, 0xdd, 0xa1, 0xfe, 0x1e, 0xc6, 0x30, 0xe3, 0x90, 0x36, 0xd5, 0x50, - 0x05, 0x55, 0xe7, 0x0d, 0xfe, 0x8d, 0x35, 0x98, 0xf3, 0xe9, 0x8e, 0x4f, 0x83, 0xa6, 0x96, 0xe3, - 0xc3, 0x92, 0xc4, 0x65, 0x28, 0x32, 0xe1, 0xd4, 0x0c, 0x03, 0x2d, 0x5f, 0xc9, 0x57, 0xe7, 0x8d, - 0x98, 0xc6, 0x55, 0x58, 0xf2, 0x69, 0xe0, 0x76, 0x7c, 0x93, 0x7e, 0x86, 0xfa, 0x81, 0xed, 0x3a, - 0xda, 0x0c, 0x5f, 0xdd, 0x3b, 0xcc, 0xb8, 0x04, 0xb4, 0x45, 0xcd, 0xd0, 0xf5, 0xb5, 0x02, 0x9f, - 0x12, 0xd3, 0x0c, 0x0f, 0x03, 0xae, 0xcd, 0x46, 0x78, 0xd8, 0x37, 0xd6, 0x61, 0x81, 0x78, 0xde, - 0x6d, 0xd2, 0xa6, 0x81, 0x47, 0x4c, 0xaa, 0xcd, 0xf1, 0xdf, 0x52, 0x63, 0x0c, 0xb3, 0x40, 0xa2, - 0x15, 0x39, 0x30, 0x49, 0xea, 0x9b, 0x30, 0x7f, 0xdb, 0xb5, 0xe8, 0x70, 0x75, 0x7b, 0xd9, 0xe7, - 0xfa, 0xd9, 0xeb, 0xbf, 0x43, 0x70, 0xc4, 0xa0, 0x5d, 0x9b, 0xe1, 0xbf, 0x45, 0x43, 0x62, 0x91, - 0x90, 0xf4, 0x72, 0xcc, 0xc5, 0x1c, 0xcb, 0x50, 0xf4, 0xc5, 0x64, 0x2d, 0xc7, 0xc7, 0x63, 0xba, - 0x4f, 0x5a, 0x3e, 0x5b, 0x99, 0xc8, 0x84, 0x92, 0xc4, 0x15, 0x28, 0x45, 0xb6, 0xbc, 0xe9, 0x58, - 0xf4, 0x4b, 0xdc, 0x7a, 0x05, 0x43, 0x1d, 0xc2, 0x2b, 0x30, 0xdf, 0x8d, 0xec, 0x7c, 0xd3, 0xe2, - 0x56, 0x2c, 0x18, 0xc9, 0x80, 0xfe, 0x0f, 0x04, 0xc7, 0x14, 0x1f, 0x30, 0xc4, 0xce, 0x5c, 0xed, - 0x52, 0x27, 0x0c, 0x86, 0x2b, 0x74, 0x06, 0x0e, 0xc9, 0x4d, 0xec, 0xb5, 0x53, 0xff, 0x0f, 0x4c, - 0x45, 0x75, 0x50, 0xaa, 0xa8, 0x8e, 0x31, 0x45, 0x24, 0x7d, 0xef, 0xe6, 0x15, 0xa1, 0xa6, 0x3a, - 0xd4, 0x67, 0xa8, 0x42, 0xb6, 0xa1, 0x66, 0x53, 0x86, 0xd2, 0xdf, 0x47, 0xa0, 0x29, 0x8a, 0xde, - 0x22, 0x8e, 0xbd, 0x43, 0x83, 0x70, 0xdc, 0x3d, 0x43, 0x53, 0xdc, 0xb3, 0x2a, 0x2c, 0x45, 0x5a, - 0xdd, 0x61, 0xe7, 0x91, 0xc5, 0x1f, 0xad, 0x50, 0xc9, 0x57, 0xf3, 0x46, 0xef, 0x30, 0xdb, 0x3b, - 0x29, 0x33, 0xd0, 0x66, 0xb9, 0x1b, 0x27, 0x03, 0xfa, 0xf3, 0x30, 0x7f, 0xcd, 0x6e, 0xd1, 0xcd, - 0x66, 0xc7, 0xd9, 0xc5, 0x87, 0xa1, 0x60, 0xb2, 0x0f, 0xae, 0xc3, 0x82, 0x11, 0x11, 0xfa, 0x37, - 0x11, 0x3c, 0x3f, 0x4c, 0xeb, 0xfb, 0x76, 0xd8, 0x64, 0xeb, 0x83, 0x61, 0xea, 0x9b, 0x4d, 0x6a, - 0xee, 0x06, 0x9d, 0xb6, 0x74, 0x59, 0x49, 0x4f, 0xa6, 0xbe, 0xfe, 0x63, 0x04, 0xd5, 0x91, 0x98, - 0xee, 0xfb, 0xc4, 0xf3, 0xa8, 0x8f, 0xaf, 0x41, 0xe1, 0x01, 0xfb, 0x81, 0x1f, 0xd0, 0xd2, 0x7a, - 0xad, 0xa6, 0x06, 0xf8, 0x91, 0x5c, 0x6e, 0xfc, 0x9f, 0x11, 0x2d, 0xc7, 0x35, 0x69, 0x9e, 0x1c, - 0xe7, 0xb3, 0x9c, 0xe2, 0x13, 0x5b, 0x91, 0xcd, 0xe7, 0xd3, 0x2e, 0xcf, 0xc2, 0x8c, 0x47, 0xfc, - 0x50, 0x3f, 0x02, 0xcf, 0xa4, 0x8f, 0x87, 0xe7, 0x3a, 0x01, 0xd5, 0x7f, 0x95, 0xf6, 0xa6, 0x4d, - 0x9f, 0x92, 0x90, 0x1a, 0xf4, 0x41, 0x87, 0x06, 0x21, 0xde, 0x05, 0x35, 0xe7, 0x70, 0xab, 0x96, - 0xd6, 0x6f, 0xd6, 0x92, 0xa0, 0x5d, 0x93, 0x41, 0x9b, 0x7f, 0x7c, 0xde, 0xb4, 0x6a, 0xdd, 0xf3, - 0x35, 0x6f, 0xb7, 0x51, 0x63, 0x29, 0x20, 0x85, 0x4c, 0xa6, 0x00, 0x55, 0x55, 0x43, 0xe5, 0x8e, - 0x97, 0x61, 0xb6, 0xe3, 0x05, 0xd4, 0x0f, 0xb9, 0x66, 0x45, 0x43, 0x50, 0x6c, 0xff, 0xba, 0xa4, - 0x65, 0x5b, 0x24, 0x8c, 0xf6, 0xa7, 0x68, 0xc4, 0xb4, 0xfe, 0xeb, 0x34, 0xfa, 0x7b, 0x9e, 0xf5, - 0x61, 0xa1, 0x57, 0x51, 0xe6, 0xd2, 0x28, 0x55, 0x0f, 0xca, 0xa7, 0x3d, 0xe8, 0xe7, 0x69, 0xfc, - 0x57, 0x68, 0x8b, 0x26, 0xf8, 0x07, 0x39, 0xb3, 0x06, 0x73, 0x26, 0x09, 0x4c, 0x62, 0x49, 0x29, - 0x92, 0x64, 0x81, 0xcc, 0xf3, 0x5d, 0x8f, 0x34, 0x38, 0xa7, 0x3b, 0x6e, 0xcb, 0x36, 0xf7, 0x84, - 0xb8, 0xfe, 0x1f, 0xfa, 0x1c, 0x7f, 0x26, 0xdb, 0xf1, 0x0b, 0x69, 0xd8, 0xc7, 0xa1, 0xb4, 0xbd, - 0xe7, 0x98, 0xaf, 0x79, 0xd1, 0xe1, 0x3e, 0x0c, 0x05, 0x3b, 0xa4, 0xed, 0x40, 0x43, 0xfc, 0x60, - 0x47, 0x84, 0xfe, 0xef, 0x02, 0x2c, 0x2b, 0xba, 0xb1, 0x05, 0x59, 0x9a, 0x65, 0x45, 0xa9, 0x65, - 0x98, 0xb5, 0xfc, 0x3d, 0xa3, 0xe3, 0x08, 0x07, 0x10, 0x14, 0x13, 0xec, 0xf9, 0x1d, 0x27, 0x82, - 0x5f, 0x34, 0x22, 0x02, 0xef, 0x40, 0x31, 0x08, 0x59, 0x95, 0xd1, 0xd8, 0xe3, 0xc0, 0x4b, 0xeb, - 0x9f, 0x9c, 0x6c, 0xd3, 0x19, 0xf4, 0x6d, 0xc1, 0xd1, 0x88, 0x79, 0xe3, 0x07, 0x2c, 0xa6, 0x45, - 0x81, 0x2e, 0xd0, 0xe6, 0x2a, 0xf9, 0x6a, 0x69, 0x7d, 0x7b, 0x72, 0x41, 0xaf, 0x79, 0xac, 0x42, - 0x52, 0x32, 0x98, 0x91, 0x48, 0x61, 0x61, 0xb4, 0x2d, 0xe2, 0x43, 0x20, 0xaa, 0x81, 0x64, 0x00, - 0x7f, 0x16, 0x0a, 0xb6, 0xb3, 0xe3, 0x06, 0xda, 0x3c, 0x07, 0x73, 0x79, 0x32, 0x30, 0x37, 0x9d, - 0x1d, 0xd7, 0x88, 0x18, 0xe2, 0x07, 0xb0, 0xe8, 0xd3, 0xd0, 0xdf, 0x93, 0x56, 0xd0, 0x80, 0xdb, - 0xf5, 0x53, 0x93, 0x49, 0x30, 0x54, 0x96, 0x46, 0x5a, 0x02, 0xde, 0x80, 0x52, 0x90, 0xf8, 0x98, - 0x56, 0xe2, 0x02, 0xb5, 0x14, 0x23, 0xc5, 0x07, 0x0d, 0x75, 0x72, 0x9f, 0x77, 0x2f, 0x64, 0x7b, - 0xf7, 0xe2, 0xc8, 0xac, 0x76, 0x60, 0x8c, 0xac, 0xb6, 0xd4, 0x9b, 0xd5, 0xfe, 0x85, 0x60, 0xa5, - 0x2f, 0x38, 0x6d, 0x7b, 0x34, 0xf3, 0x18, 0x10, 0x98, 0x09, 0x3c, 0x6a, 0xf2, 0x4c, 0x55, 0x5a, - 0xbf, 0x35, 0xb5, 0x68, 0xc5, 0xe5, 0x72, 0xd6, 0x59, 0x01, 0x75, 0xc2, 0xb8, 0xf0, 0x03, 0x04, - 0xff, 0xaf, 0xc8, 0xbc, 0x43, 0x42, 0xb3, 0x99, 0xa5, 0x2c, 0x3b, 0xbf, 0x6c, 0x8e, 0xc8, 0xcb, - 0x11, 0xc1, 0xac, 0xca, 0x3f, 0xee, 0xee, 0x79, 0x0c, 0x20, 0xfb, 0x25, 0x19, 0x98, 0xb0, 0x78, - 0xfa, 0x09, 0x82, 0xb2, 0x1a, 0xc3, 0xdd, 0x56, 0xeb, 0x0d, 0x62, 0xee, 0x66, 0x81, 0x3c, 0x00, - 0x39, 0xdb, 0xe2, 0x08, 0xf3, 0x46, 0xce, 0xb6, 0xf6, 0x19, 0x8c, 0x7a, 0xe1, 0xce, 0x66, 0xc3, - 0x9d, 0x4b, 0xc3, 0xfd, 0xa0, 0x07, 0xae, 0x0c, 0x09, 0x19, 0x70, 0x57, 0x60, 0xde, 0xe9, 0x29, - 0x64, 0x93, 0x81, 0x01, 0x05, 0x6c, 0xae, 0xaf, 0x80, 0xd5, 0x60, 0xae, 0x1b, 0x5f, 0x73, 0xd8, - 0xcf, 0x92, 0x64, 0x2a, 0x36, 0x7c, 0xb7, 0xe3, 0x09, 0xa3, 0x47, 0x04, 0x43, 0xb1, 0x6b, 0x3b, - 0xac, 0x24, 0xe7, 0x28, 0xd8, 0xf7, 0xfe, 0x2f, 0x36, 0x29, 0xb5, 0x7f, 0x9a, 0x83, 0x8f, 0x0c, - 0x50, 0x7b, 0xa4, 0x3f, 0x3d, 0x1d, 0xba, 0xc7, 0x5e, 0x3d, 0x37, 0xd4, 0xab, 0x8b, 0xa3, 0xbc, - 0x7a, 0x3e, 0xdb, 0x5e, 0x90, 0xb6, 0xd7, 0x8f, 0x72, 0x50, 0x19, 0x60, 0xaf, 0xd1, 0xe5, 0xc4, - 0x53, 0x63, 0xb0, 0x1d, 0xd7, 0x17, 0x5e, 0x52, 0x34, 0x22, 0x82, 0x9d, 0x33, 0xd7, 0xf7, 0x9a, - 0xc4, 0xe1, 0xde, 0x51, 0x34, 0x04, 0x35, 0xa1, 0xa9, 0xbe, 0x96, 0x03, 0x4d, 0xda, 0xe7, 0x92, - 0xc9, 0xad, 0xd5, 0x71, 0x9e, 0x7e, 0x13, 0x2d, 0xc3, 0x2c, 0xe1, 0x68, 0x85, 0x53, 0x09, 0xaa, - 0xcf, 0x18, 0xc5, 0x6c, 0x63, 0xcc, 0xa7, 0x8d, 0xf1, 0x55, 0x04, 0x47, 0xd3, 0xc6, 0x08, 0xb6, - 0xec, 0x20, 0x94, 0x97, 0x03, 0xbc, 0x03, 0x73, 0x91, 0x9c, 0xa8, 0xb4, 0x2b, 0xad, 0x6f, 0x4d, - 0x9a, 0xf0, 0x53, 0x86, 0x97, 0xcc, 0xf5, 0x97, 0xe0, 0xe8, 0xc0, 0x28, 0x27, 0x60, 0x94, 0xa1, - 0x28, 0x8b, 0x1c, 0xb1, 0x35, 0x31, 0xad, 0xbf, 0x3b, 0x93, 0x4e, 0x39, 0xae, 0xb5, 0xe5, 0x36, - 0x32, 0xee, 0xfb, 0xd9, 0xdb, 0xc9, 0x4c, 0xe5, 0x5a, 0xca, 0xd5, 0x5e, 0x92, 0x6c, 0x9d, 0xe9, - 0x3a, 0x21, 0xb1, 0x1d, 0xea, 0x8b, 0xac, 0x98, 0x0c, 0xb0, 0x6d, 0x08, 0x6c, 0xc7, 0xa4, 0xdb, - 0xd4, 0x74, 0x1d, 0x2b, 0xe0, 0xfb, 0x99, 0x37, 0x52, 0x63, 0xf8, 0x06, 0xcc, 0x73, 0xfa, 0xae, - 0xdd, 0x8e, 0xd2, 0x40, 0x69, 0x7d, 0xb5, 0x16, 0xf5, 0xe0, 0x6a, 0x6a, 0x0f, 0x2e, 0xb1, 0x61, - 0x9b, 0x86, 0xa4, 0xd6, 0x3d, 0x57, 0x63, 0x2b, 0x8c, 0x64, 0x31, 0xc3, 0x12, 0x12, 0xbb, 0xb5, - 0x65, 0x3b, 0xbc, 0xf0, 0x64, 0xa2, 0x92, 0x01, 0xe6, 0x2a, 0x3b, 0x6e, 0xab, 0xe5, 0x3e, 0x94, - 0xe7, 0x26, 0xa2, 0xd8, 0xaa, 0x8e, 0x13, 0xda, 0x2d, 0x2e, 0x3f, 0x72, 0x84, 0x64, 0x80, 0xaf, - 0xb2, 0x5b, 0x21, 0xf5, 0xc5, 0x81, 0x11, 0x54, 0xec, 0x8c, 0xa5, 0xa8, 0xad, 0x24, 0xcf, 0x6b, - 0xe4, 0xb6, 0x0b, 0xaa, 0xdb, 0xf6, 0x1e, 0x85, 0xc5, 0x01, 0xbd, 0x11, 0xde, 0x65, 0xa3, 0x5d, - 0xdb, 0xed, 0xb0, 0x9a, 0x8a, 0x97, 0x1e, 0x92, 0xee, 0x73, 0xe5, 0xa5, 0x6c, 0x57, 0x3e, 0x98, - 0x2e, 0xda, 0x78, 0x65, 0x1c, 0x9a, 0xcd, 0x4d, 0x12, 0x50, 0xed, 0x10, 0x67, 0x9d, 0x0c, 0xe8, - 0xbf, 0x41, 0x50, 0xdc, 0x72, 0x1b, 0x57, 0x9d, 0xd0, 0xdf, 0xe3, 0x77, 0x28, 0xd7, 0x09, 0xa9, - 0x23, 0xbd, 0x49, 0x92, 0x6c, 0x8b, 0x42, 0xbb, 0x4d, 0xb7, 0x43, 0xd2, 0xf6, 0x44, 0x05, 0xb6, - 0xaf, 0x2d, 0x8a, 0x17, 0x33, 0xb3, 0xb5, 0x48, 0x10, 0xf2, 0x78, 0x50, 0x34, 0xf8, 0x37, 0x53, - 0x30, 0x9e, 0xb0, 0x1d, 0xfa, 0x22, 0x18, 0xa4, 0xc6, 0x54, 0x07, 0x2c, 0x44, 0xd8, 0x04, 0xa9, - 0xb7, 0xe1, 0xd9, 0xf8, 0x6a, 0x70, 0x97, 0xfa, 0x6d, 0xdb, 0x21, 0xd9, 0xb1, 0x7d, 0x8c, 0xe6, - 0x5f, 0xc6, 0xcd, 0xd4, 0x4d, 0x1d, 0x49, 0x56, 0x69, 0xdf, 0xb7, 0x1d, 0xcb, 0x7d, 0x98, 0x71, - 0xb4, 0x26, 0x13, 0xf8, 0xe7, 0x74, 0xff, 0x4e, 0x91, 0x18, 0xc7, 0x81, 0x1b, 0xb0, 0xc8, 0x22, - 0x46, 0x97, 0x8a, 0x1f, 0x44, 0x50, 0xd2, 0x87, 0xb5, 0x52, 0x12, 0x1e, 0x46, 0x7a, 0x21, 0xde, - 0x82, 0x25, 0x12, 0x04, 0x76, 0xc3, 0xa1, 0x96, 0xe4, 0x95, 0x1b, 0x9b, 0x57, 0xef, 0xd2, 0xe8, - 0x52, 0xce, 0x67, 0x88, 0xfd, 0x96, 0xa4, 0xfe, 0x15, 0x04, 0x47, 0x06, 0x32, 0x89, 0xcf, 0x15, - 0x52, 0x82, 0x7c, 0x19, 0x8a, 0x81, 0xd9, 0xa4, 0x56, 0xa7, 0x45, 0x65, 0xa7, 0x4a, 0xd2, 0xec, - 0x37, 0xab, 0x13, 0xed, 0xbe, 0x48, 0x32, 0x31, 0x8d, 0x8f, 0x01, 0xb4, 0x89, 0xd3, 0x21, 0x2d, - 0x0e, 0x61, 0x86, 0x43, 0x50, 0x46, 0xf4, 0x15, 0x28, 0x0f, 0x72, 0x1d, 0xd1, 0x01, 0xfa, 0x27, - 0x82, 0x03, 0x32, 0xe4, 0x8a, 0xdd, 0xad, 0xc2, 0x92, 0x62, 0x86, 0xdb, 0xc9, 0x46, 0xf7, 0x0e, - 0x8f, 0x08, 0xa7, 0xd2, 0x4b, 0xf2, 0xe9, 0x16, 0x7c, 0x37, 0xd5, 0x44, 0x1f, 0x3b, 0x1b, 0xa2, - 0x29, 0x55, 0x97, 0x5f, 0x06, 0xed, 0x16, 0x71, 0x48, 0x83, 0x5a, 0xb1, 0xda, 0xb1, 0x8b, 0x7d, - 0x41, 0x6d, 0x65, 0x4c, 0xdc, 0x38, 0x88, 0x0b, 0x31, 0x7b, 0x67, 0x47, 0xb6, 0x45, 0x7c, 0x28, - 0x6e, 0xd9, 0xce, 0x2e, 0xbb, 0x5d, 0x33, 0x8d, 0x43, 0x3b, 0x6c, 0x49, 0xeb, 0x46, 0x04, 0x3e, - 0x08, 0xf9, 0x8e, 0xdf, 0x12, 0x1e, 0xc0, 0x3e, 0x71, 0x05, 0x4a, 0x16, 0x0d, 0x4c, 0xdf, 0xf6, - 0xc4, 0xfe, 0xf3, 0x96, 0xb2, 0x32, 0xc4, 0xf6, 0xc1, 0x36, 0x5d, 0x67, 0xb3, 0x45, 0x82, 0x40, - 0xa6, 0xa7, 0x78, 0x40, 0x7f, 0x05, 0x16, 0x99, 0xcc, 0x44, 0xcd, 0xd3, 0x69, 0x35, 0x8f, 0xa4, - 0xe0, 0x4b, 0x78, 0x12, 0x31, 0x81, 0x67, 0x58, 0x55, 0x70, 0xc9, 0xf3, 0x04, 0x93, 0x31, 0x8b, - 0xa5, 0xfc, 0xa0, 0xec, 0x3a, 0xb0, 0x93, 0xba, 0xfe, 0xd7, 0xe3, 0x80, 0xd5, 0x73, 0x42, 0xfd, - 0xae, 0x6d, 0x52, 0xfc, 0x2d, 0x04, 0x33, 0x4c, 0x34, 0x7e, 0x6e, 0xd8, 0xb1, 0xe4, 0xfe, 0x5a, - 0x9e, 0xde, 0x35, 0x99, 0x49, 0xd3, 0x57, 0xde, 0xfc, 0xcb, 0xdf, 0xbf, 0x9d, 0x5b, 0xc6, 0x87, - 0xf9, 0xfb, 0x59, 0xf7, 0x9c, 0xfa, 0x96, 0x15, 0xe0, 0xb7, 0x10, 0x60, 0x51, 0x25, 0x29, 0x2f, - 0x0c, 0xf8, 0xf4, 0x30, 0x88, 0x03, 0x5e, 0x22, 0xca, 0xcf, 0x29, 0x59, 0xa5, 0x66, 0xba, 0x3e, - 0x65, 0x39, 0x84, 0x4f, 0xe0, 0x00, 0x56, 0x39, 0x80, 0x13, 0x58, 0x1f, 0x04, 0xa0, 0xfe, 0x88, - 0x59, 0xf4, 0x71, 0x9d, 0x46, 0x72, 0xdf, 0x41, 0x50, 0xb8, 0xcf, 0x6f, 0x18, 0x23, 0x8c, 0xb4, - 0x3d, 0x35, 0x23, 0x71, 0x71, 0x1c, 0xad, 0x7e, 0x9c, 0x23, 0x7d, 0x0e, 0x1f, 0x95, 0x48, 0x83, - 0xd0, 0xa7, 0xa4, 0x9d, 0x02, 0x7c, 0x16, 0xe1, 0xf7, 0x10, 0xcc, 0x46, 0xad, 0x65, 0x7c, 0x72, - 0x18, 0xca, 0x54, 0xeb, 0xb9, 0x3c, 0xbd, 0x3e, 0xad, 0xfe, 0x22, 0xc7, 0x78, 0x5c, 0x1f, 0xb8, - 0x9d, 0x1b, 0xa9, 0x2e, 0xee, 0xdb, 0x08, 0xf2, 0xd7, 0xe9, 0x48, 0x7f, 0x9b, 0x22, 0xb8, 0x3e, - 0x03, 0x0e, 0xd8, 0x6a, 0xfc, 0x2e, 0x82, 0x67, 0xaf, 0xd3, 0x70, 0x70, 0x7a, 0xc4, 0xd5, 0xd1, - 0x39, 0x4b, 0xb8, 0xdd, 0xe9, 0x31, 0x66, 0xc6, 0x79, 0xa1, 0xce, 0x91, 0xbd, 0x88, 0x4f, 0x65, - 0x39, 0x61, 0xb0, 0xe7, 0x98, 0x0f, 0x05, 0x8e, 0x3f, 0x22, 0x38, 0xd8, 0xfb, 0x92, 0x88, 0xd3, - 0x09, 0x75, 0xe0, 0x43, 0x63, 0xf9, 0xf6, 0xa4, 0x51, 0x36, 0xcd, 0x54, 0xbf, 0xc4, 0x91, 0xbf, - 0x8c, 0x5f, 0xca, 0x42, 0x1e, 0xf7, 0xe9, 0xea, 0x8f, 0xe4, 0xe7, 0x63, 0xfe, 0xea, 0xcd, 0x61, - 0xff, 0x09, 0xc1, 0x61, 0xc9, 0x77, 0xb3, 0x49, 0xfc, 0xf0, 0x0a, 0x65, 0x15, 0x76, 0x30, 0x96, - 0x3e, 0x13, 0x66, 0x0d, 0x55, 0x9e, 0x7e, 0x95, 0xeb, 0xf2, 0x71, 0xfc, 0xea, 0xbe, 0x75, 0x31, - 0x19, 0x1b, 0x4b, 0xc0, 0x7e, 0x13, 0xc1, 0xc2, 0x75, 0x1a, 0xde, 0x8a, 0x7b, 0xc5, 0x27, 0xc7, - 0x7a, 0x7f, 0x2a, 0xaf, 0xd4, 0x94, 0xc7, 0x76, 0xf9, 0x53, 0xec, 0x22, 0x6b, 0x1c, 0xdc, 0x29, - 0x7c, 0x32, 0x0b, 0x5c, 0xd2, 0x9f, 0x7e, 0x07, 0xc1, 0x11, 0x15, 0x44, 0xf2, 0x6e, 0xf7, 0xd1, - 0xfd, 0xbd, 0x86, 0x89, 0x37, 0xb5, 0x11, 0xe8, 0xd6, 0x39, 0xba, 0x33, 0xfa, 0x60, 0x07, 0x6e, - 0xf7, 0xa1, 0xd8, 0x40, 0xab, 0x55, 0x84, 0x7f, 0x8b, 0x60, 0x36, 0x6a, 0xd5, 0x0e, 0xb7, 0x51, - 0xea, 0x9d, 0x69, 0x9a, 0xd1, 0x40, 0xec, 0x76, 0xf9, 0xec, 0x60, 0x83, 0xaa, 0xeb, 0xa5, 0xab, - 0xd6, 0xb8, 0x95, 0xd3, 0x61, 0xec, 0x17, 0x08, 0x20, 0x69, 0x37, 0xe3, 0x17, 0xb3, 0xf5, 0x50, - 0x5a, 0xd2, 0xe5, 0xe9, 0x36, 0x9c, 0xf5, 0x1a, 0xd7, 0xa7, 0x5a, 0xae, 0x64, 0xc6, 0x10, 0x8f, - 0x9a, 0x1b, 0x51, 0x6b, 0xfa, 0x87, 0x08, 0x0a, 0xbc, 0xcb, 0x87, 0x4f, 0x0c, 0xc3, 0xac, 0x36, - 0x01, 0xa7, 0x69, 0xfa, 0x17, 0x38, 0xd4, 0xca, 0x7a, 0x56, 0x20, 0xde, 0x40, 0xab, 0xb8, 0x0b, - 0xb3, 0x51, 0x5f, 0x6d, 0xb8, 0x7b, 0xa4, 0xfa, 0x6e, 0xe5, 0x4a, 0x46, 0x61, 0x10, 0x39, 0xaa, - 0xc8, 0x01, 0xab, 0xa3, 0x72, 0xc0, 0x0c, 0x0b, 0xd3, 0xf8, 0x78, 0x56, 0x10, 0xff, 0x1f, 0x18, - 0xe6, 0x34, 0x47, 0x77, 0x52, 0xaf, 0x8c, 0xca, 0x03, 0xcc, 0x3a, 0xdf, 0x41, 0x70, 0xb0, 0xb7, - 0xb8, 0xc6, 0x47, 0x7b, 0x62, 0xa6, 0x7a, 0xd7, 0x28, 0xa7, 0xad, 0x38, 0xac, 0x30, 0xd7, 0x3f, - 0xc1, 0x51, 0x6c, 0xe0, 0x8b, 0x23, 0x4f, 0xc6, 0x6d, 0x19, 0x75, 0x18, 0xa3, 0xb5, 0xe4, 0xed, - 0xec, 0x97, 0x08, 0x16, 0x24, 0xdf, 0xbb, 0x3e, 0xa5, 0xd9, 0xb0, 0xa6, 0x77, 0x10, 0x98, 0x2c, - 0xfd, 0x15, 0x0e, 0xff, 0x63, 0xf8, 0xc2, 0x98, 0xf0, 0x25, 0xec, 0xb5, 0x90, 0x21, 0xfd, 0x3d, - 0x82, 0x43, 0xf7, 0x23, 0xbf, 0xff, 0x90, 0xf0, 0x6f, 0x72, 0xfc, 0xaf, 0xe2, 0x97, 0x33, 0xea, - 0xbc, 0x51, 0x6a, 0x9c, 0x45, 0xf8, 0x67, 0x08, 0x8a, 0xf2, 0xcd, 0x05, 0x9f, 0x1a, 0x7a, 0x30, - 0xd2, 0xaf, 0x32, 0xd3, 0x74, 0x66, 0x51, 0xd4, 0xe8, 0x27, 0x32, 0xd3, 0xa9, 0x90, 0xcf, 0x1c, - 0xfa, 0x6d, 0x04, 0x38, 0xbe, 0x33, 0xc7, 0xb7, 0x68, 0xfc, 0x42, 0x4a, 0xd4, 0xd0, 0xc6, 0x4c, - 0xf9, 0xd4, 0xc8, 0x79, 0xe9, 0x54, 0xba, 0x9a, 0x99, 0x4a, 0xdd, 0x58, 0xfe, 0xd7, 0x11, 0x94, - 0xae, 0xd3, 0xf8, 0x0e, 0x92, 0x61, 0xcb, 0xf4, 0x93, 0x51, 0xb9, 0x3a, 0x7a, 0xa2, 0x40, 0x74, - 0x86, 0x23, 0x7a, 0x01, 0x67, 0x9b, 0x4a, 0x02, 0xf8, 0x1e, 0x82, 0xc5, 0x3b, 0xaa, 0x8b, 0xe2, - 0x33, 0xa3, 0x24, 0xa5, 0x22, 0xf9, 0xf8, 0xb8, 0xce, 0x73, 0x5c, 0x6b, 0xfa, 0x58, 0xb8, 0x36, - 0xc4, 0xeb, 0xcb, 0xf7, 0x51, 0x74, 0x89, 0xed, 0xe9, 0x76, 0xff, 0xb7, 0x76, 0xcb, 0x68, 0x9a, - 0xeb, 0x17, 0x38, 0xbe, 0x1a, 0x3e, 0x33, 0x0e, 0xbe, 0xba, 0x68, 0x81, 0xe3, 0xef, 0x22, 0x38, - 0xc4, 0x5f, 0x22, 0x54, 0xc6, 0x3d, 0x29, 0x66, 0xd8, 0xbb, 0xc5, 0x18, 0x29, 0x46, 0xc4, 0x1f, - 0x7d, 0x5f, 0xa0, 0x36, 0xe4, 0x2b, 0xc3, 0x37, 0x10, 0x1c, 0x90, 0x49, 0x4d, 0xec, 0xee, 0xda, - 0x28, 0xc3, 0xed, 0x37, 0x09, 0x0a, 0x77, 0x5b, 0x1d, 0xcf, 0xdd, 0xde, 0x43, 0x30, 0x27, 0x7a, - 0xfd, 0x19, 0xa5, 0x82, 0xf2, 0x18, 0x50, 0xee, 0xe9, 0x71, 0x88, 0x66, 0xb0, 0xfe, 0x39, 0x2e, - 0xf6, 0x1e, 0xae, 0x67, 0x89, 0xf5, 0x5c, 0x2b, 0xa8, 0x3f, 0x12, 0x9d, 0xd8, 0xc7, 0xf5, 0x96, - 0xdb, 0x08, 0x5e, 0xd7, 0x71, 0x66, 0x42, 0x64, 0x73, 0xce, 0x22, 0x1c, 0xc2, 0x3c, 0x73, 0x0e, - 0xde, 0x38, 0xc1, 0x95, 0x9e, 0x36, 0x4b, 0x5f, 0x4f, 0xa5, 0x5c, 0xee, 0x6b, 0xc4, 0x24, 0x19, - 0x50, 0x5c, 0x63, 0xf1, 0xf3, 0x99, 0x62, 0xb9, 0xa0, 0xb7, 0x10, 0x1c, 0x52, 0xbd, 0x3d, 0x12, - 0x3f, 0xb6, 0xaf, 0x67, 0xa1, 0x10, 0x45, 0x35, 0x5e, 0x1d, 0xcb, 0x91, 0x38, 0x9c, 0xcb, 0xd7, - 0xfe, 0xf0, 0xe4, 0x18, 0x7a, 0xff, 0xc9, 0x31, 0xf4, 0xb7, 0x27, 0xc7, 0xd0, 0xeb, 0x17, 0xc7, - 0xfb, 0x07, 0xb1, 0xd9, 0xb2, 0xa9, 0x13, 0xaa, 0xec, 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0x88, - 0xb6, 0x78, 0x6a, 0x27, 0x2d, 0x00, 0x00, + // 2801 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0x4d, 0x8c, 0x1c, 0x47, + 0x15, 0xa6, 0x66, 0x76, 0x76, 0x67, 0xdf, 0xec, 0x7a, 0xed, 0x8a, 0xbd, 0x74, 0xc6, 0x1b, 0x33, + 0x69, 0xdb, 0xf1, 0x64, 0xed, 0x9d, 0xb1, 0x37, 0x01, 0x92, 0x4d, 0x22, 0x70, 0xd6, 0x8e, 0xb3, + 0xb0, 0x76, 0x4c, 0xaf, 0x83, 0x51, 0x38, 0x40, 0xa5, 0xbb, 0x76, 0xa6, 0xd9, 0x9e, 0xee, 0x76, + 0x77, 0xcf, 0x84, 0x55, 0xc8, 0x25, 0x88, 0x5b, 0x04, 0x02, 0x82, 0xc4, 0x01, 0x01, 0x4a, 0x14, + 0x09, 0x21, 0x10, 0x17, 0x84, 0x90, 0x10, 0x12, 0x1c, 0x40, 0x70, 0x40, 0x8a, 0x40, 0xe2, 0x8c, + 0x22, 0xc4, 0x0d, 0xb8, 0xe4, 0x8c, 0x50, 0x55, 0x57, 0x75, 0x57, 0xcf, 0x4f, 0xcf, 0x2c, 0x33, + 0x28, 0xbe, 0xf5, 0xab, 0xa9, 0x7a, 0xef, 0x7b, 0xaf, 0x5e, 0xbd, 0xf7, 0xea, 0xd5, 0xc0, 0xb9, + 0x90, 0x06, 0x3d, 0x1a, 0x34, 0x89, 0xef, 0x3b, 0xb6, 0x49, 0x22, 0xdb, 0x73, 0xd5, 0xef, 0x86, + 0x1f, 0x78, 0x91, 0x87, 0x2b, 0xca, 0x50, 0x75, 0xad, 0xe5, 0x79, 0x2d, 0x87, 0x36, 0x89, 0x6f, + 0x37, 0x89, 0xeb, 0x7a, 0x11, 0x1f, 0x0e, 0xe3, 0xa9, 0x55, 0xfd, 0xe0, 0x89, 0xb0, 0x61, 0x7b, + 0xfc, 0x57, 0xd3, 0x0b, 0x68, 0xb3, 0x77, 0xa5, 0xd9, 0xa2, 0x2e, 0x0d, 0x48, 0x44, 0x2d, 0x31, + 0xe7, 0xf1, 0x74, 0x4e, 0x87, 0x98, 0x6d, 0xdb, 0xa5, 0xc1, 0x61, 0xd3, 0x3f, 0x68, 0xb1, 0x81, + 0xb0, 0xd9, 0xa1, 0x11, 0x19, 0xb6, 0x6a, 0xb7, 0x65, 0x47, 0xed, 0xee, 0xcb, 0x0d, 0xd3, 0xeb, + 0x34, 0x49, 0xd0, 0xf2, 0xfc, 0xc0, 0xfb, 0x12, 0xff, 0xd8, 0x30, 0xad, 0x66, 0xef, 0xb1, 0x94, + 0x81, 0xaa, 0x4b, 0xef, 0x0a, 0x71, 0xfc, 0x36, 0x19, 0xe4, 0x76, 0x7d, 0x0c, 0xb7, 0x80, 0xfa, + 0x9e, 0xb0, 0x0d, 0xff, 0xb4, 0x23, 0x2f, 0x38, 0x54, 0x3e, 0x63, 0x36, 0xfa, 0xfb, 0x08, 0x8e, + 0x5f, 0x4d, 0xe5, 0x7d, 0xa6, 0x4b, 0x83, 0x43, 0x8c, 0x61, 0xce, 0x25, 0x1d, 0xaa, 0xa1, 0x1a, + 0xaa, 0x2f, 0x1a, 0xfc, 0x1b, 0x6b, 0xb0, 0x10, 0xd0, 0xfd, 0x80, 0x86, 0x6d, 0xad, 0xc0, 0x87, + 0x25, 0x89, 0xab, 0x50, 0x66, 0xc2, 0xa9, 0x19, 0x85, 0x5a, 0xb1, 0x56, 0xac, 0x2f, 0x1a, 0x09, + 0x8d, 0xeb, 0xb0, 0x12, 0xd0, 0xd0, 0xeb, 0x06, 0x26, 0xfd, 0x2c, 0x0d, 0x42, 0xdb, 0x73, 0xb5, + 0x39, 0xbe, 0xba, 0x7f, 0x98, 0x71, 0x09, 0xa9, 0x43, 0xcd, 0xc8, 0x0b, 0xb4, 0x12, 0x9f, 0x92, + 0xd0, 0x0c, 0x0f, 0x03, 0xae, 0xcd, 0xc7, 0x78, 0xd8, 0x37, 0xd6, 0x61, 0x89, 0xf8, 0xfe, 0x2d, + 0xd2, 0xa1, 0xa1, 0x4f, 0x4c, 0xaa, 0x2d, 0xf0, 0xdf, 0x32, 0x63, 0x0c, 0xb3, 0x40, 0xa2, 0x95, + 0x39, 0x30, 0x49, 0xea, 0xdb, 0xb0, 0x78, 0xcb, 0xb3, 0xe8, 0x68, 0x75, 0xfb, 0xd9, 0x17, 0x06, + 0xd9, 0xeb, 0xbf, 0x43, 0x70, 0xca, 0xa0, 0x3d, 0x9b, 0xe1, 0xbf, 0x49, 0x23, 0x62, 0x91, 0x88, + 0xf4, 0x73, 0x2c, 0x24, 0x1c, 0xab, 0x50, 0x0e, 0xc4, 0x64, 0xad, 0xc0, 0xc7, 0x13, 0x7a, 0x40, + 0x5a, 0x31, 0x5f, 0x99, 0xd8, 0x84, 0x92, 0xc4, 0x35, 0xa8, 0xc4, 0xb6, 0xdc, 0x71, 0x2d, 0xfa, + 0x65, 0x6e, 0xbd, 0x92, 0xa1, 0x0e, 0xe1, 0x35, 0x58, 0xec, 0xc5, 0x76, 0xde, 0xb1, 0xb8, 0x15, + 0x4b, 0x46, 0x3a, 0xa0, 0xff, 0x03, 0xc1, 0x19, 0xc5, 0x07, 0x0c, 0xb1, 0x33, 0xd7, 0x7b, 0xd4, + 0x8d, 0xc2, 0xd1, 0x0a, 0x5d, 0x82, 0x13, 0x72, 0x13, 0xfb, 0xed, 0x34, 0xf8, 0x03, 0x53, 0x51, + 0x1d, 0x94, 0x2a, 0xaa, 0x63, 0x4c, 0x11, 0x49, 0xbf, 0xb8, 0x73, 0x4d, 0xa8, 0xa9, 0x0e, 0x0d, + 0x18, 0xaa, 0x94, 0x6f, 0xa8, 0xf9, 0x8c, 0xa1, 0xf4, 0x77, 0x11, 0x68, 0x8a, 0xa2, 0x37, 0x89, + 0x6b, 0xef, 0xd3, 0x30, 0x9a, 0x74, 0xcf, 0xd0, 0x0c, 0xf7, 0xac, 0x0e, 0x2b, 0xb1, 0x56, 0xb7, + 0xd9, 0x79, 0x64, 0xf1, 0x47, 0x2b, 0xd5, 0x8a, 0xf5, 0xa2, 0xd1, 0x3f, 0xcc, 0xf6, 0x4e, 0xca, + 0x0c, 0xb5, 0x79, 0xee, 0xc6, 0xe9, 0x80, 0xfe, 0x30, 0x2c, 0x3e, 0x67, 0x3b, 0x74, 0xbb, 0xdd, + 0x75, 0x0f, 0xf0, 0x49, 0x28, 0x99, 0xec, 0x83, 0xeb, 0xb0, 0x64, 0xc4, 0x84, 0xfe, 0x4d, 0x04, + 0x0f, 0x8f, 0xd2, 0xfa, 0xae, 0x1d, 0xb5, 0xd9, 0xfa, 0x70, 0x94, 0xfa, 0x66, 0x9b, 0x9a, 0x07, + 0x61, 0xb7, 0x23, 0x5d, 0x56, 0xd2, 0xd3, 0xa9, 0xaf, 0xff, 0x18, 0x41, 0x7d, 0x2c, 0xa6, 0xbb, + 0x01, 0xf1, 0x7d, 0x1a, 0xe0, 0xe7, 0xa0, 0x74, 0x8f, 0xfd, 0xc0, 0x0f, 0x68, 0x65, 0xb3, 0xd1, + 0x50, 0x03, 0xfc, 0x58, 0x2e, 0xcf, 0x7f, 0xc8, 0x88, 0x97, 0xe3, 0x86, 0x34, 0x4f, 0x81, 0xf3, + 0x59, 0xcd, 0xf0, 0x49, 0xac, 0xc8, 0xe6, 0xf3, 0x69, 0xcf, 0xce, 0xc3, 0x9c, 0x4f, 0x82, 0x48, + 0x3f, 0x05, 0x0f, 0x64, 0x8f, 0x87, 0xef, 0xb9, 0x21, 0xd5, 0x7f, 0x95, 0xf5, 0xa6, 0xed, 0x80, + 0x92, 0x88, 0x1a, 0xf4, 0x5e, 0x97, 0x86, 0x11, 0x3e, 0x00, 0x35, 0xe7, 0x70, 0xab, 0x56, 0x36, + 0x77, 0x1a, 0x69, 0xd0, 0x6e, 0xc8, 0xa0, 0xcd, 0x3f, 0xbe, 0x60, 0x5a, 0x8d, 0xde, 0x63, 0x0d, + 0xff, 0xa0, 0xd5, 0x60, 0x29, 0x20, 0x83, 0x4c, 0xa6, 0x00, 0x55, 0x55, 0x43, 0xe5, 0x8e, 0x57, + 0x61, 0xbe, 0xeb, 0x87, 0x34, 0x88, 0xb8, 0x66, 0x65, 0x43, 0x50, 0x6c, 0xff, 0x7a, 0xc4, 0xb1, + 0x2d, 0x12, 0xc5, 0xfb, 0x53, 0x36, 0x12, 0x5a, 0xff, 0x75, 0x16, 0xfd, 0x8b, 0xbe, 0xf5, 0x41, + 0xa1, 0x57, 0x51, 0x16, 0xb2, 0x28, 0x55, 0x0f, 0x2a, 0x66, 0x3d, 0xe8, 0xe7, 0x59, 0xfc, 0xd7, + 0xa8, 0x43, 0x53, 0xfc, 0xc3, 0x9c, 0x59, 0x83, 0x05, 0x93, 0x84, 0x26, 0xb1, 0xa4, 0x14, 0x49, + 0xb2, 0x40, 0xe6, 0x07, 0x9e, 0x4f, 0x5a, 0x9c, 0xd3, 0x6d, 0xcf, 0xb1, 0xcd, 0x43, 0x21, 0x6e, + 0xf0, 0x87, 0x01, 0xc7, 0x9f, 0xcb, 0x77, 0xfc, 0x52, 0x16, 0xf6, 0x59, 0xa8, 0xec, 0x1d, 0xba, + 0xe6, 0x0b, 0x7e, 0x7c, 0xb8, 0x4f, 0x42, 0xc9, 0x8e, 0x68, 0x27, 0xd4, 0x10, 0x3f, 0xd8, 0x31, + 0xa1, 0xff, 0xa7, 0x04, 0xab, 0x8a, 0x6e, 0x6c, 0x41, 0x9e, 0x66, 0x79, 0x51, 0x6a, 0x15, 0xe6, + 0xad, 0xe0, 0xd0, 0xe8, 0xba, 0xc2, 0x01, 0x04, 0xc5, 0x04, 0xfb, 0x41, 0xd7, 0x8d, 0xe1, 0x97, + 0x8d, 0x98, 0xc0, 0xfb, 0x50, 0x0e, 0x23, 0x56, 0x65, 0xb4, 0x0e, 0x39, 0xf0, 0xca, 0xe6, 0xa7, + 0xa6, 0xdb, 0x74, 0x06, 0x7d, 0x4f, 0x70, 0x34, 0x12, 0xde, 0xf8, 0x1e, 0x8b, 0x69, 0x71, 0xa0, + 0x0b, 0xb5, 0x85, 0x5a, 0xb1, 0x5e, 0xd9, 0xdc, 0x9b, 0x5e, 0xd0, 0x0b, 0x3e, 0xab, 0x90, 0x94, + 0x0c, 0x66, 0xa4, 0x52, 0x58, 0x18, 0xed, 0x88, 0xf8, 0x10, 0x8a, 0x6a, 0x20, 0x1d, 0xc0, 0x9f, + 0x83, 0x92, 0xed, 0xee, 0x7b, 0xa1, 0xb6, 0xc8, 0xc1, 0x3c, 0x3b, 0x1d, 0x98, 0x1d, 0x77, 0xdf, + 0x33, 0x62, 0x86, 0xf8, 0x1e, 0x2c, 0x07, 0x34, 0x0a, 0x0e, 0xa5, 0x15, 0x34, 0xe0, 0x76, 0xfd, + 0xf4, 0x74, 0x12, 0x0c, 0x95, 0xa5, 0x91, 0x95, 0x80, 0xb7, 0xa0, 0x12, 0xa6, 0x3e, 0xa6, 0x55, + 0xb8, 0x40, 0x2d, 0xc3, 0x48, 0xf1, 0x41, 0x43, 0x9d, 0x3c, 0xe0, 0xdd, 0x4b, 0xf9, 0xde, 0xbd, + 0x3c, 0x36, 0xab, 0x1d, 0x9b, 0x20, 0xab, 0xad, 0xf4, 0x67, 0xb5, 0x7f, 0x23, 0x58, 0x1b, 0x08, + 0x4e, 0x7b, 0x3e, 0xcd, 0x3d, 0x06, 0x04, 0xe6, 0x42, 0x9f, 0x9a, 0x3c, 0x53, 0x55, 0x36, 0x6f, + 0xce, 0x2c, 0x5a, 0x71, 0xb9, 0x9c, 0x75, 0x5e, 0x40, 0x9d, 0x32, 0x2e, 0xfc, 0x00, 0xc1, 0x87, + 0x15, 0x99, 0xb7, 0x49, 0x64, 0xb6, 0xf3, 0x94, 0x65, 0xe7, 0x97, 0xcd, 0x11, 0x79, 0x39, 0x26, + 0x98, 0x55, 0xf9, 0xc7, 0x9d, 0x43, 0x9f, 0x01, 0x64, 0xbf, 0xa4, 0x03, 0x53, 0x16, 0x4f, 0x3f, + 0x41, 0x50, 0x55, 0x63, 0xb8, 0xe7, 0x38, 0x2f, 0x13, 0xf3, 0x20, 0x0f, 0xe4, 0x31, 0x28, 0xd8, + 0x16, 0x47, 0x58, 0x34, 0x0a, 0xb6, 0x75, 0xc4, 0x60, 0xd4, 0x0f, 0x77, 0x3e, 0x1f, 0xee, 0x42, + 0x16, 0xee, 0xfb, 0x7d, 0x70, 0x65, 0x48, 0xc8, 0x81, 0xbb, 0x06, 0x8b, 0x6e, 0x5f, 0x21, 0x9b, + 0x0e, 0x0c, 0x29, 0x60, 0x0b, 0x03, 0x05, 0xac, 0x06, 0x0b, 0xbd, 0xe4, 0x9a, 0xc3, 0x7e, 0x96, + 0x24, 0x53, 0xb1, 0x15, 0x78, 0x5d, 0x5f, 0x18, 0x3d, 0x26, 0x18, 0x8a, 0x03, 0xdb, 0x65, 0x25, + 0x39, 0x47, 0xc1, 0xbe, 0x8f, 0x7e, 0xb1, 0xc9, 0xa8, 0xfd, 0xd3, 0x02, 0x7c, 0x64, 0x88, 0xda, + 0x63, 0xfd, 0xe9, 0xfe, 0xd0, 0x3d, 0xf1, 0xea, 0x85, 0x91, 0x5e, 0x5d, 0x1e, 0xe7, 0xd5, 0x8b, + 0xf9, 0xf6, 0x82, 0xac, 0xbd, 0x7e, 0x54, 0x80, 0xda, 0x10, 0x7b, 0x8d, 0x2f, 0x27, 0xee, 0x1b, + 0x83, 0xed, 0x7b, 0x81, 0xf0, 0x92, 0xb2, 0x11, 0x13, 0xec, 0x9c, 0x79, 0x81, 0xdf, 0x26, 0x2e, + 0xf7, 0x8e, 0xb2, 0x21, 0xa8, 0x29, 0x4d, 0x75, 0x0d, 0x34, 0x69, 0x9e, 0xab, 0x66, 0x1c, 0xa4, + 0x02, 0xd2, 0xa1, 0x11, 0x0d, 0xc2, 0x51, 0x21, 0xaa, 0x47, 0x9c, 0x2e, 0x95, 0x21, 0x8a, 0x13, + 0xfa, 0x3f, 0x0b, 0xfd, 0x6c, 0x8c, 0xae, 0x7b, 0xff, 0x1b, 0x7a, 0x15, 0xe6, 0x09, 0x47, 0x2b, + 0x5c, 0x53, 0x50, 0x03, 0x26, 0x2d, 0xe7, 0x9b, 0x74, 0x31, 0x9b, 0x2f, 0x09, 0x68, 0xc1, 0x08, + 0x93, 0x6a, 0xc0, 0x2b, 0x91, 0xf3, 0x99, 0xf4, 0x34, 0xca, 0xfe, 0xc6, 0x48, 0x36, 0xfa, 0xd7, + 0x10, 0x9c, 0xce, 0x2e, 0x0b, 0x77, 0xed, 0x30, 0x92, 0xb7, 0x18, 0xbc, 0x0f, 0x0b, 0xb1, 0x2a, + 0x71, 0x0d, 0x5a, 0xd9, 0xdc, 0x9d, 0xb6, 0x32, 0xc9, 0xec, 0xad, 0x64, 0xae, 0x3f, 0x09, 0xa7, + 0x87, 0x86, 0x63, 0x01, 0xa3, 0x0a, 0x65, 0x59, 0x8d, 0x89, 0xdd, 0x4f, 0x68, 0xfd, 0xed, 0xb9, + 0x6c, 0x6e, 0xf4, 0xac, 0x5d, 0xaf, 0x95, 0xd3, 0x98, 0xc8, 0xf7, 0x18, 0xb6, 0x1b, 0x9e, 0xa5, + 0xf4, 0x20, 0x24, 0xc9, 0xd6, 0x99, 0x9e, 0x1b, 0x11, 0xdb, 0xa5, 0x81, 0x48, 0xdf, 0xe9, 0x00, + 0xdb, 0xe9, 0xd0, 0x76, 0x4d, 0xba, 0x47, 0x4d, 0xcf, 0xb5, 0x42, 0xee, 0x32, 0x45, 0x23, 0x33, + 0x86, 0x9f, 0x87, 0x45, 0x4e, 0xdf, 0xb1, 0x3b, 0x71, 0xbe, 0xaa, 0x6c, 0xae, 0x37, 0xe2, 0x66, + 0x61, 0x43, 0x6d, 0x16, 0xa6, 0x36, 0xec, 0xd0, 0x88, 0x34, 0x7a, 0x57, 0x1a, 0x6c, 0x85, 0x91, + 0x2e, 0x66, 0x58, 0x22, 0x62, 0x3b, 0xbb, 0xb6, 0xcb, 0x2b, 0x64, 0x26, 0x2a, 0x1d, 0x60, 0xde, + 0xb8, 0xef, 0x39, 0x8e, 0xf7, 0x8a, 0x3c, 0xe0, 0x31, 0xc5, 0x56, 0x75, 0xdd, 0xc8, 0x76, 0xb8, + 0xfc, 0xd8, 0xd7, 0xd2, 0x01, 0xbe, 0xca, 0x76, 0x22, 0x1a, 0x88, 0x93, 0x2d, 0xa8, 0xc4, 0xdf, + 0x2b, 0x71, 0xff, 0x4b, 0x06, 0x96, 0xf8, 0x64, 0x2c, 0xa9, 0x27, 0xa3, 0xff, 0xb4, 0x2d, 0x0f, + 0x69, 0xe2, 0xf0, 0x76, 0x20, 0xed, 0xd9, 0x5e, 0x97, 0x15, 0x7f, 0xbc, 0x46, 0x92, 0xf4, 0xc0, + 0x69, 0x59, 0xc9, 0x3f, 0x2d, 0xc7, 0xb3, 0xa7, 0x85, 0x97, 0xf0, 0x91, 0xd9, 0xde, 0x26, 0x21, + 0xd5, 0x4e, 0x70, 0xd6, 0xe9, 0x80, 0xfe, 0x1b, 0x04, 0xe5, 0x5d, 0xaf, 0x75, 0xdd, 0x8d, 0x82, + 0x43, 0x7e, 0xd9, 0xf3, 0xdc, 0x88, 0xba, 0xd2, 0x9b, 0x24, 0xc9, 0xb6, 0x28, 0xb2, 0x3b, 0x74, + 0x2f, 0x22, 0x1d, 0x5f, 0x94, 0x8a, 0x47, 0xda, 0xa2, 0x64, 0x31, 0x33, 0x9b, 0x43, 0xc2, 0x88, + 0x87, 0x9c, 0xb2, 0xc1, 0xbf, 0x99, 0x82, 0xc9, 0x84, 0xbd, 0x28, 0x10, 0xf1, 0x26, 0x33, 0xa6, + 0x3a, 0x60, 0x29, 0xc6, 0x26, 0x48, 0xbd, 0x03, 0x0f, 0x26, 0x77, 0x98, 0x3b, 0x34, 0xe8, 0xd8, + 0x2e, 0xc9, 0x4f, 0x42, 0x13, 0x74, 0x29, 0x73, 0xae, 0xd0, 0x5e, 0xe6, 0x48, 0xb2, 0x2b, 0xc1, + 0x5d, 0xdb, 0xb5, 0xbc, 0x57, 0x72, 0x8e, 0xd6, 0x74, 0x02, 0xff, 0x9c, 0x6d, 0x34, 0x2a, 0x12, + 0x93, 0x38, 0xf0, 0x3c, 0x2c, 0xb3, 0x88, 0xd1, 0xa3, 0xe2, 0x07, 0x11, 0x94, 0xf4, 0x51, 0x3d, + 0x9f, 0x94, 0x87, 0x91, 0x5d, 0x88, 0x77, 0x61, 0x85, 0x84, 0xa1, 0xdd, 0x72, 0xa9, 0x25, 0x79, + 0x15, 0x26, 0xe6, 0xd5, 0xbf, 0x34, 0xee, 0x1e, 0xf0, 0x19, 0x62, 0xbf, 0x25, 0xa9, 0x7f, 0x15, + 0xc1, 0xa9, 0xa1, 0x4c, 0x92, 0x73, 0x85, 0x94, 0x3c, 0x52, 0x85, 0x72, 0x68, 0xb6, 0xa9, 0xd5, + 0x75, 0x64, 0x5e, 0x4c, 0x68, 0xf6, 0x9b, 0xd5, 0x8d, 0x77, 0x5f, 0xe4, 0xb1, 0x84, 0xc6, 0x67, + 0x00, 0x3a, 0xc4, 0xed, 0x12, 0x87, 0x43, 0x98, 0xe3, 0x10, 0x94, 0x11, 0x7d, 0x0d, 0xaa, 0xc3, + 0x5c, 0x47, 0xb4, 0xaa, 0xfe, 0x85, 0xe0, 0x98, 0x0c, 0xb9, 0x62, 0x77, 0xeb, 0xb0, 0xa2, 0x98, + 0xe1, 0x56, 0xba, 0xd1, 0xfd, 0xc3, 0x63, 0xc2, 0xa9, 0xf4, 0x92, 0x62, 0xf6, 0xad, 0xa0, 0x97, + 0xe9, 0xf6, 0x4f, 0x9c, 0x70, 0xd1, 0x8c, 0xca, 0xe0, 0xaf, 0x80, 0x76, 0x93, 0xb8, 0xa4, 0x45, + 0xad, 0x44, 0xed, 0xc4, 0xc5, 0xbe, 0xa8, 0xf6, 0x5c, 0xa6, 0xee, 0x70, 0x24, 0x15, 0xa3, 0xbd, + 0xbf, 0x2f, 0xfb, 0x37, 0x01, 0x94, 0x77, 0x6d, 0xf7, 0x60, 0xc7, 0xdd, 0xf7, 0x98, 0xc6, 0x91, + 0x1d, 0x39, 0xd2, 0xba, 0x31, 0x81, 0x8f, 0x43, 0xb1, 0x1b, 0x38, 0xc2, 0x03, 0xd8, 0x27, 0xae, + 0x41, 0xc5, 0xa2, 0xa1, 0x19, 0xd8, 0xbe, 0xd8, 0x7f, 0xde, 0xfb, 0x56, 0x86, 0xd8, 0x3e, 0xd8, + 0xa6, 0xe7, 0x6e, 0x3b, 0x24, 0x0c, 0x65, 0x7a, 0x4a, 0x06, 0xf4, 0xa7, 0x61, 0x99, 0xc9, 0x4c, + 0xd5, 0xbc, 0x98, 0x55, 0xf3, 0x54, 0x06, 0xbe, 0x84, 0x27, 0x11, 0x13, 0x78, 0x80, 0x55, 0x05, + 0x57, 0x7d, 0x5f, 0x30, 0x99, 0xb0, 0x1e, 0x2b, 0x0e, 0xcb, 0xae, 0x43, 0x5b, 0xbe, 0x9b, 0x7f, + 0x3d, 0x0b, 0x58, 0x3d, 0x27, 0x34, 0xe8, 0xd9, 0x26, 0xc5, 0xdf, 0x42, 0x30, 0xc7, 0x44, 0xe3, + 0x87, 0x46, 0x1d, 0x4b, 0xee, 0xaf, 0xd5, 0xd9, 0xdd, 0xe7, 0x99, 0x34, 0x7d, 0xed, 0xf5, 0xbf, + 0xfc, 0xfd, 0xdb, 0x85, 0x55, 0x7c, 0x92, 0x3f, 0xf4, 0xf5, 0xae, 0xa8, 0x8f, 0x6e, 0x21, 0x7e, + 0x03, 0x01, 0x16, 0x55, 0x92, 0xf2, 0x14, 0x82, 0x2f, 0x8e, 0x82, 0x38, 0xe4, 0xc9, 0xa4, 0xfa, + 0x90, 0x92, 0x55, 0x1a, 0xa6, 0x17, 0x50, 0x96, 0x43, 0xf8, 0x04, 0x0e, 0x60, 0x9d, 0x03, 0x38, + 0x87, 0xf5, 0x61, 0x00, 0x9a, 0xaf, 0x32, 0x8b, 0xbe, 0xd6, 0xa4, 0xb1, 0xdc, 0xb7, 0x10, 0x94, + 0xee, 0xf2, 0xab, 0xd0, 0x18, 0x23, 0xed, 0xcd, 0xcc, 0x48, 0x5c, 0x1c, 0x47, 0xab, 0x9f, 0xe5, + 0x48, 0x1f, 0xc2, 0xa7, 0x25, 0xd2, 0x30, 0x0a, 0x28, 0xe9, 0x64, 0x00, 0x5f, 0x46, 0xf8, 0x1d, + 0x04, 0xf3, 0x71, 0x0f, 0x1c, 0x9f, 0x1f, 0x85, 0x32, 0xd3, 0x23, 0xaf, 0xce, 0xae, 0xa1, 0xac, + 0x3f, 0xca, 0x31, 0x9e, 0xd5, 0x87, 0x6e, 0xe7, 0x56, 0xa6, 0xdd, 0xfc, 0x26, 0x82, 0xe2, 0x0d, + 0x3a, 0xd6, 0xdf, 0x66, 0x08, 0x6e, 0xc0, 0x80, 0x43, 0xb6, 0x1a, 0xbf, 0x8d, 0xe0, 0xc1, 0x1b, + 0x34, 0x1a, 0x9e, 0x1e, 0x71, 0x7d, 0x7c, 0xce, 0x12, 0x6e, 0x77, 0x71, 0x82, 0x99, 0x49, 0x5e, + 0x68, 0x72, 0x64, 0x8f, 0xe2, 0x0b, 0x79, 0x4e, 0x18, 0x1e, 0xba, 0xe6, 0x2b, 0x02, 0xc7, 0x1f, + 0x11, 0x1c, 0xef, 0x7f, 0xf2, 0xc4, 0x7a, 0xdf, 0x1d, 0x65, 0xc8, 0x8b, 0x68, 0xf5, 0xd6, 0xb4, + 0x51, 0x36, 0xcb, 0x54, 0xbf, 0xca, 0x91, 0x3f, 0x85, 0x9f, 0xcc, 0x43, 0x9e, 0x34, 0x14, 0x9b, + 0xaf, 0xca, 0xcf, 0xd7, 0xf8, 0xf3, 0x3c, 0x87, 0xfd, 0x27, 0x04, 0x27, 0x25, 0xdf, 0xed, 0x36, + 0x09, 0xa2, 0x6b, 0x94, 0x55, 0xd8, 0xe1, 0x44, 0xfa, 0x4c, 0x99, 0x35, 0x54, 0x79, 0xfa, 0x75, + 0xae, 0xcb, 0x27, 0xf0, 0x33, 0x47, 0xd6, 0xc5, 0x64, 0x6c, 0x2c, 0x01, 0xfb, 0x75, 0x04, 0x4b, + 0x37, 0x68, 0x74, 0x33, 0x69, 0x6a, 0x9f, 0x9f, 0xe8, 0xa1, 0xac, 0xba, 0xd6, 0x50, 0xfe, 0x15, + 0x20, 0x7f, 0x4a, 0x5c, 0x64, 0x83, 0x83, 0xbb, 0x80, 0xcf, 0xe7, 0x81, 0x4b, 0x1b, 0xe9, 0x6f, + 0x21, 0x38, 0xa5, 0x82, 0x48, 0x1f, 0x18, 0x3f, 0x7a, 0xb4, 0x67, 0x3b, 0xf1, 0xf8, 0x37, 0x06, + 0xdd, 0x26, 0x47, 0x77, 0x49, 0x1f, 0xee, 0xc0, 0x9d, 0x01, 0x14, 0x5b, 0x68, 0xbd, 0x8e, 0xf0, + 0x6f, 0x11, 0xcc, 0xc7, 0x3d, 0xe5, 0xd1, 0x36, 0xca, 0x3c, 0x88, 0xcd, 0x32, 0x1a, 0x88, 0xdd, + 0xae, 0x5e, 0x1e, 0x6e, 0x50, 0x75, 0xbd, 0x74, 0xd5, 0x06, 0xb7, 0x72, 0x36, 0x8c, 0xfd, 0x02, + 0x01, 0xa4, 0x7d, 0x71, 0xfc, 0x68, 0xbe, 0x1e, 0x4a, 0xef, 0xbc, 0x3a, 0xdb, 0xce, 0xb8, 0xde, + 0xe0, 0xfa, 0xd4, 0xab, 0xb5, 0xdc, 0x18, 0xe2, 0x53, 0x73, 0x2b, 0xee, 0xa1, 0xff, 0x10, 0x41, + 0x89, 0xb7, 0x23, 0xf1, 0xb9, 0x51, 0x98, 0xd5, 0x6e, 0xe5, 0x2c, 0x4d, 0xff, 0x08, 0x87, 0x5a, + 0xdb, 0xcc, 0x0b, 0xc4, 0x5b, 0x68, 0x1d, 0xf7, 0x60, 0x3e, 0x6e, 0x00, 0x8e, 0x76, 0x8f, 0x4c, + 0x83, 0xb0, 0x5a, 0xcb, 0x29, 0x0c, 0x62, 0x47, 0x15, 0x39, 0x60, 0x7d, 0x5c, 0x0e, 0x98, 0x63, + 0x61, 0x1a, 0x9f, 0xcd, 0x0b, 0xe2, 0xff, 0x07, 0xc3, 0x5c, 0xe4, 0xe8, 0xce, 0xeb, 0xb5, 0x71, + 0x79, 0x80, 0x59, 0xe7, 0xbb, 0x08, 0x8e, 0xf7, 0x17, 0xd7, 0xf8, 0xf4, 0xd0, 0x3e, 0x95, 0xc8, + 0x49, 0x59, 0x2b, 0x8e, 0x2a, 0xcc, 0xf5, 0x4f, 0x72, 0x14, 0x5b, 0xf8, 0x89, 0xb1, 0x27, 0xe3, + 0x96, 0x8c, 0x3a, 0x8c, 0xd1, 0x46, 0xfa, 0xc8, 0xf7, 0x4b, 0x04, 0x4b, 0x92, 0xef, 0x9d, 0x80, + 0xd2, 0x7c, 0x58, 0xb3, 0x3b, 0x08, 0x4c, 0x96, 0xfe, 0x34, 0x87, 0xff, 0x31, 0xfc, 0xf8, 0x84, + 0xf0, 0x25, 0xec, 0x8d, 0x88, 0x21, 0xfd, 0x3d, 0x82, 0x13, 0x77, 0x63, 0xbf, 0xff, 0x80, 0xf0, + 0x6f, 0x73, 0xfc, 0xcf, 0xe0, 0xa7, 0x72, 0xea, 0xbc, 0x71, 0x6a, 0x5c, 0x46, 0xf8, 0x67, 0x08, + 0xca, 0xf2, 0x71, 0x08, 0x5f, 0x18, 0x79, 0x30, 0xb2, 0xcf, 0x47, 0xb3, 0x74, 0x66, 0x51, 0xd4, + 0xe8, 0xe7, 0x72, 0xd3, 0xa9, 0x90, 0xcf, 0x1c, 0xfa, 0x4d, 0x04, 0x38, 0xb9, 0x33, 0x27, 0xb7, + 0x68, 0xfc, 0x48, 0x46, 0xd4, 0xc8, 0xc6, 0x4c, 0xf5, 0xc2, 0xd8, 0x79, 0xd9, 0x54, 0xba, 0x9e, + 0x9b, 0x4a, 0xbd, 0x44, 0xfe, 0xd7, 0x11, 0x54, 0x6e, 0xd0, 0xe4, 0x0e, 0x92, 0x63, 0xcb, 0xec, + 0xdb, 0x56, 0xb5, 0x3e, 0x7e, 0xa2, 0x40, 0x74, 0x89, 0x23, 0x7a, 0x04, 0xe7, 0x9b, 0x4a, 0x02, + 0xf8, 0x1e, 0x82, 0xe5, 0xdb, 0xaa, 0x8b, 0xe2, 0x4b, 0xe3, 0x24, 0x65, 0x22, 0xf9, 0xe4, 0xb8, + 0x1e, 0xe3, 0xb8, 0x36, 0xf4, 0x89, 0x70, 0x6d, 0x89, 0x67, 0xa2, 0xef, 0xa3, 0xf8, 0x12, 0xdb, + 0xd7, 0xed, 0xfe, 0x5f, 0xed, 0x96, 0xd3, 0x34, 0xd7, 0x1f, 0xe7, 0xf8, 0x1a, 0xf8, 0xd2, 0x24, + 0xf8, 0x9a, 0xa2, 0x05, 0x8e, 0xbf, 0x83, 0xe0, 0x04, 0x7f, 0xec, 0x50, 0x19, 0xe3, 0xbc, 0x0e, + 0x7f, 0xfa, 0x34, 0x32, 0x41, 0x8a, 0xf9, 0x38, 0x07, 0x75, 0x45, 0x3f, 0x12, 0x28, 0xe6, 0xff, + 0xdf, 0x40, 0x70, 0x4c, 0xe6, 0x33, 0xb1, 0xb1, 0x1b, 0xe3, 0x6c, 0x76, 0xd4, 0xfc, 0x27, 0x3c, + 0x6d, 0x7d, 0x32, 0x4f, 0x7b, 0x07, 0xc1, 0x82, 0x68, 0xf3, 0xe7, 0x54, 0x09, 0xca, 0x3b, 0x40, + 0xb5, 0xaf, 0xbd, 0x21, 0xfa, 0xc0, 0xfa, 0xe7, 0xb9, 0xd8, 0x17, 0x71, 0x33, 0x4f, 0xac, 0xef, + 0x59, 0x61, 0xf3, 0x55, 0xd1, 0x84, 0x7d, 0xad, 0xe9, 0x78, 0xad, 0xf0, 0x25, 0x1d, 0xe7, 0xe6, + 0x42, 0x36, 0xe7, 0x32, 0xc2, 0x11, 0x2c, 0x32, 0xbf, 0xe0, 0x3d, 0x13, 0x5c, 0xeb, 0xeb, 0xb0, + 0x0c, 0xb4, 0x53, 0xaa, 0xd5, 0x81, 0x1e, 0x4c, 0x9a, 0xfc, 0xc4, 0x0d, 0x16, 0x3f, 0x9c, 0x2b, + 0x96, 0x0b, 0x7a, 0x03, 0xc1, 0x09, 0xd5, 0xd1, 0x63, 0xf1, 0x13, 0xbb, 0x79, 0x1e, 0x0a, 0x51, + 0x4f, 0xe3, 0xf5, 0x89, 0x7c, 0x88, 0xc3, 0x79, 0xf6, 0xb9, 0x3f, 0xbc, 0x77, 0x06, 0xbd, 0xfb, + 0xde, 0x19, 0xf4, 0xb7, 0xf7, 0xce, 0xa0, 0x97, 0x9e, 0x98, 0xec, 0x5f, 0xce, 0xa6, 0x63, 0x53, + 0x37, 0x52, 0xd9, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, 0x20, 0x14, 0xaf, 0x73, 0xcb, 0x2d, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -5709,6 +5776,51 @@ func (m *ApplicationResourceDeleteRequest) MarshalToSizedBuffer(dAtA []byte) (in return len(dAtA) - i, nil } +func (m *ResourceActionParameters) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ResourceActionParameters) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ResourceActionParameters) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if m.Value == nil { + return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("value") + } else { + i -= len(*m.Value) + copy(dAtA[i:], *m.Value) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Value))) + i-- + dAtA[i] = 0x12 + } + if m.Name == nil { + return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("name") + } else { + i -= len(*m.Name) + copy(dAtA[i:], *m.Name) + i = encodeVarintApplication(dAtA, i, uint64(len(*m.Name))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func (m *ResourceActionRunRequest) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -5733,6 +5845,20 @@ func (m *ResourceActionRunRequest) MarshalToSizedBuffer(dAtA []byte) (int, error i -= len(m.XXX_unrecognized) copy(dAtA[i:], m.XXX_unrecognized) } + if len(m.ResourceActionParameters) > 0 { + for iNdEx := len(m.ResourceActionParameters) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ResourceActionParameters[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintApplication(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + } if m.Project != nil { i -= len(*m.Project) copy(dAtA[i:], *m.Project) @@ -7358,6 +7484,26 @@ func (m *ApplicationResourceDeleteRequest) Size() (n int) { return n } +func (m *ResourceActionParameters) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.Name != nil { + l = len(*m.Name) + n += 1 + l + sovApplication(uint64(l)) + } + if m.Value != nil { + l = len(*m.Value) + n += 1 + l + sovApplication(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func (m *ResourceActionRunRequest) Size() (n int) { if m == nil { return 0 @@ -7400,6 +7546,12 @@ func (m *ResourceActionRunRequest) Size() (n int) { l = len(*m.Project) n += 1 + l + sovApplication(uint64(l)) } + if len(m.ResourceActionParameters) > 0 { + for _, e := range m.ResourceActionParameters { + l = e.Size() + n += 1 + l + sovApplication(uint64(l)) + } + } if m.XXX_unrecognized != nil { n += len(m.XXX_unrecognized) } @@ -12360,6 +12512,132 @@ func (m *ApplicationResourceDeleteRequest) Unmarshal(dAtA []byte) error { } return nil } +func (m *ResourceActionParameters) Unmarshal(dAtA []byte) error { + var hasFields [1]uint64 + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ResourceActionParameters: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ResourceActionParameters: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Name = &s + iNdEx = postIndex + hasFields[0] |= uint64(0x00000001) + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthApplication + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + s := string(dAtA[iNdEx:postIndex]) + m.Value = &s + iNdEx = postIndex + hasFields[0] |= uint64(0x00000002) + default: + iNdEx = preIndex + skippy, err := skipApplication(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthApplication + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + if hasFields[0]&uint64(0x00000001) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("name") + } + if hasFields[0]&uint64(0x00000002) == 0 { + return github_com_gogo_protobuf_proto.NewRequiredNotSetError("value") + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *ResourceActionRunRequest) Unmarshal(dAtA []byte) error { var hasFields [1]uint64 l := len(dAtA) @@ -12692,6 +12970,40 @@ func (m *ResourceActionRunRequest) Unmarshal(dAtA []byte) error { s := string(dAtA[iNdEx:postIndex]) m.Project = &s iNdEx = postIndex + case 10: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ResourceActionParameters", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowApplication + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthApplication + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthApplication + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ResourceActionParameters = append(m.ResourceActionParameters, &ResourceActionParameters{}) + if err := m.ResourceActionParameters[len(m.ResourceActionParameters)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipApplication(dAtA[iNdEx:]) diff --git a/pkg/apiclient/application/application.pb.gw.go b/pkg/apiclient/application/application.pb.gw.go index ed6064cadb9a2..1085fe040c916 100644 --- a/pkg/apiclient/application/application.pb.gw.go +++ b/pkg/apiclient/application/application.pb.gw.go @@ -1621,10 +1621,6 @@ func local_request_ApplicationService_ListResourceActions_0(ctx context.Context, } -var ( - filter_ApplicationService_RunResourceAction_0 = &utilities.DoubleArray{Encoding: map[string]int{"action": 0, "name": 1}, Base: []int{1, 1, 2, 0, 0}, Check: []int{0, 1, 1, 2, 3}} -) - func request_ApplicationService_RunResourceAction_0(ctx context.Context, marshaler runtime.Marshaler, client ApplicationServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq ResourceActionRunRequest var metadata runtime.ServerMetadata @@ -1633,7 +1629,7 @@ func request_ApplicationService_RunResourceAction_0(ctx context.Context, marshal if berr != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Action); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -1655,13 +1651,6 @@ func request_ApplicationService_RunResourceAction_0(ctx context.Context, marshal return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_RunResourceAction_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := client.RunResourceAction(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -1675,7 +1664,7 @@ func local_request_ApplicationService_RunResourceAction_0(ctx context.Context, m if berr != nil { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Action); err != nil && err != io.EOF { + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } @@ -1697,13 +1686,6 @@ func local_request_ApplicationService_RunResourceAction_0(ctx context.Context, m return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "name", err) } - if err := req.ParseForm(); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ApplicationService_RunResourceAction_0); err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - msg, err := server.RunResourceAction(ctx, &protoReq) return msg, metadata, err diff --git a/pkg/apis/application/v1alpha1/openapi_generated.go b/pkg/apis/application/v1alpha1/openapi_generated.go index ac8014f7b61fd..b4f026b8d2cba 100644 --- a/pkg/apis/application/v1alpha1/openapi_generated.go +++ b/pkg/apis/application/v1alpha1/openapi_generated.go @@ -6270,6 +6270,30 @@ func schema_pkg_apis_application_v1alpha1_ResourceAction(ref common.ReferenceCal Format: "", }, }, + "defaultValue": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "hasParameters": { + SchemaProps: spec.SchemaProps{ + Type: []string{"boolean"}, + Format: "", + }, + }, + "regexp": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "errorMessage": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, diff --git a/resource_customizations/apps/Deployment/actions/action_test.yaml b/resource_customizations/apps/Deployment/actions/action_test.yaml index 14538c8d0b63f..67ac923fae995 100644 --- a/resource_customizations/apps/Deployment/actions/action_test.yaml +++ b/resource_customizations/apps/Deployment/actions/action_test.yaml @@ -1,10 +1,20 @@ actionTests: -- action: restart - inputPath: testdata/deployment.yaml - expectedOutputPath: testdata/deployment-restarted.yaml -- action: pause - inputPath: testdata/deployment.yaml - expectedOutputPath: testdata/deployment-pause.yaml -- action: resume - inputPath: testdata/deployment-pause.yaml - expectedOutputPath: testdata/deployment-resume.yaml \ No newline at end of file + - action: restart + inputPath: testdata/deployment.yaml + expectedOutputPath: testdata/deployment-restarted.yaml + - action: pause + inputPath: testdata/deployment.yaml + expectedOutputPath: testdata/deployment-pause.yaml + - action: resume + inputPath: testdata/deployment-pause.yaml + expectedOutputPath: testdata/deployment-resume.yaml + - action: scale + inputPath: testdata/deployment.yaml + expectedOutputPath: testdata/deployment-scaled.yaml + parameters: + replicas: '6' + - action: scale + inputPath: testdata/deployment.yaml + expectedErrorMessage: 'invalid number: not_a_number' + parameters: + replicas: 'not_a_number' diff --git a/resource_customizations/apps/Deployment/actions/discovery.lua b/resource_customizations/apps/Deployment/actions/discovery.lua index d090d587769c7..f939d920f842b 100644 --- a/resource_customizations/apps/Deployment/actions/discovery.lua +++ b/resource_customizations/apps/Deployment/actions/discovery.lua @@ -7,4 +7,13 @@ if obj.spec.paused ~= nil then actions["pause"] = {paused} end actions["resume"] = {["disabled"] = not(paused)} + +actions["scale"] = { + ["params"] = { + { + ["name"] = "replicas", + ["default"] = tostring(obj.spec.replicas) + } + }, +} return actions diff --git a/resource_customizations/apps/Deployment/actions/scale/action.lua b/resource_customizations/apps/Deployment/actions/scale/action.lua new file mode 100644 index 0000000000000..bc27eaf345a27 --- /dev/null +++ b/resource_customizations/apps/Deployment/actions/scale/action.lua @@ -0,0 +1,9 @@ +local os = require("os") + +local replicas = tonumber(actionParams["replicas"]) +if not replicas then + error("invalid number: " .. actionParams["replicas"], 0) +end + +obj.spec.replicas = replicas +return obj diff --git a/resource_customizations/apps/Deployment/actions/testdata/deployment-scaled.yaml b/resource_customizations/apps/Deployment/actions/testdata/deployment-scaled.yaml new file mode 100644 index 0000000000000..ed71333a04ad3 --- /dev/null +++ b/resource_customizations/apps/Deployment/actions/testdata/deployment-scaled.yaml @@ -0,0 +1,61 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + deployment.kubernetes.io/revision: "1" + creationTimestamp: "2019-09-12T01:33:53Z" + generation: 1 + name: nginx-deploy + namespace: default + resourceVersion: "6897444" + selfLink: /apis/apps/v1/namespaces/default/deployments/nginx-deploy + uid: 61689d6d-d4fd-11e9-9e69-42010aa8005f +spec: + progressDeadlineSeconds: 600 + replicas: 6 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: nginx + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + labels: + app: nginx + spec: + containers: + - image: nginx:latest + imagePullPolicy: Always + name: nginx + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 +status: + availableReplicas: 2 + conditions: + - lastTransitionTime: "2019-09-12T01:33:53Z" + lastUpdateTime: "2019-09-12T01:33:53Z" + message: Deployment does not have minimum availability. + reason: MinimumReplicasUnavailable + status: "False" + type: Available + - lastTransitionTime: "2019-09-12T01:33:53Z" + lastUpdateTime: "2019-09-12T01:34:05Z" + message: ReplicaSet "nginx-deploy-9cb4784bd" is progressing. + reason: ReplicaSetUpdated + status: "True" + type: Progressing + observedGeneration: 1 + readyReplicas: 2 + replicas: 3 + unavailableReplicas: 1 + updatedReplicas: 3 diff --git a/resource_customizations/apps/StatefulSet/actions/action_test.yaml b/resource_customizations/apps/StatefulSet/actions/action_test.yaml index bab15aacbd94f..e8388a7a0eb66 100644 --- a/resource_customizations/apps/StatefulSet/actions/action_test.yaml +++ b/resource_customizations/apps/StatefulSet/actions/action_test.yaml @@ -1,4 +1,14 @@ actionTests: -- action: restart - inputPath: testdata/statefulset.yaml - expectedOutputPath: testdata/statefulset-restarted.yaml + - action: restart + inputPath: testdata/statefulset.yaml + expectedOutputPath: testdata/statefulset-restarted.yaml + - action: scale + inputPath: testdata/statefulset.yaml + expectedOutputPath: testdata/statefulset-scaled.yaml + parameters: + replicas: '6' + - action: scale + inputPath: testdata/statefulset.yaml + expectedErrorMessage: 'invalid number: not_a_number' + parameters: + replicas: 'not_a_number' diff --git a/resource_customizations/apps/StatefulSet/actions/discovery.lua b/resource_customizations/apps/StatefulSet/actions/discovery.lua index dc7f10431bc70..83a37a874e4b4 100644 --- a/resource_customizations/apps/StatefulSet/actions/discovery.lua +++ b/resource_customizations/apps/StatefulSet/actions/discovery.lua @@ -1,3 +1,12 @@ local actions = {} actions["restart"] = {} + +actions["scale"] = { + ["params"] = { + { + ["name"] = "replicas", + ["default"] = tostring(obj.spec.replicas) + } + }, +} return actions diff --git a/resource_customizations/apps/StatefulSet/actions/scale/action.lua b/resource_customizations/apps/StatefulSet/actions/scale/action.lua new file mode 100644 index 0000000000000..bc27eaf345a27 --- /dev/null +++ b/resource_customizations/apps/StatefulSet/actions/scale/action.lua @@ -0,0 +1,9 @@ +local os = require("os") + +local replicas = tonumber(actionParams["replicas"]) +if not replicas then + error("invalid number: " .. actionParams["replicas"], 0) +end + +obj.spec.replicas = replicas +return obj diff --git a/resource_customizations/apps/StatefulSet/actions/testdata/statefulset-scaled.yaml b/resource_customizations/apps/StatefulSet/actions/testdata/statefulset-scaled.yaml new file mode 100644 index 0000000000000..57b7c0e86eeac --- /dev/null +++ b/resource_customizations/apps/StatefulSet/actions/testdata/statefulset-scaled.yaml @@ -0,0 +1,50 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + creationTimestamp: "2019-09-13T08:52:54Z" + generation: 2 + labels: + app.kubernetes.io/instance: extensions + name: statefulset + namespace: statefulset + resourceVersion: "7471813" + selfLink: /apis/apps/v1/namespaces/statefulset/statefulsets/statefulset + uid: dfe8fadf-d603-11e9-9e69-42010aa8005f +spec: + podManagementPolicy: OrderedReady + replicas: 6 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: statefulset + serviceName: statefulset + template: + metadata: + labels: + app: statefulset + spec: + containers: + - image: registry.k8s.io/nginx-slim:0.8 + imagePullPolicy: IfNotPresent + name: nginx + resources: {} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 + updateStrategy: + rollingUpdate: + partition: 0 + type: RollingUpdate +status: + collisionCount: 0 + currentReplicas: 3 + currentRevision: statefulset-85b7f767c6 + observedGeneration: 2 + readyReplicas: 3 + replicas: 3 + updateRevision: statefulset-85b7f767c6 + updatedReplicas: 3 diff --git a/server/application/application.go b/server/application/application.go index 3b027a196af96..ce5e53466509d 100644 --- a/server/application/application.go +++ b/server/application/application.go @@ -2455,7 +2455,7 @@ func (s *Server) RunResourceAction(ctx context.Context, q *application.ResourceA return nil, fmt.Errorf("error getting Lua resource action: %w", err) } - newObjects, err := luaVM.ExecuteResourceAction(liveObj, action.ActionLua) + newObjects, err := luaVM.ExecuteResourceAction(liveObj, action.ActionLua, q.GetResourceActionParameters()) if err != nil { return nil, fmt.Errorf("error executing Lua resource action: %w", err) } diff --git a/server/application/application.proto b/server/application/application.proto index 4c3b11df8e4f2..d1221f2b30e30 100644 --- a/server/application/application.proto +++ b/server/application/application.proto @@ -203,6 +203,11 @@ message ApplicationResourceDeleteRequest { optional string project = 10; } +message ResourceActionParameters { + required string name = 1; + required string value = 2; +} + message ResourceActionRunRequest { required string name = 1; optional string namespace = 2; @@ -213,6 +218,7 @@ message ResourceActionRunRequest { required string action = 7; optional string appNamespace = 8; optional string project = 9; + repeated ResourceActionParameters resourceActionParameters = 10; } message ResourceActionsListResponse { @@ -463,7 +469,7 @@ service ApplicationService { rpc RunResourceAction(ResourceActionRunRequest) returns (ApplicationResponse) { option (google.api.http) = { post: "/api/v1/applications/{name}/resource/actions" - body: "action" + body: "*" }; } diff --git a/ui/src/app/applications/components/utils.tsx b/ui/src/app/applications/components/utils.tsx index c7d054a2032af..91a46e85f73d9 100644 --- a/ui/src/app/applications/components/utils.tsx +++ b/ui/src/app/applications/components/utils.tsx @@ -521,22 +521,45 @@ export const deletePopup = async ( ); }; -export function getResourceActionsMenuItems(resource: ResourceTreeNode, metadata: models.ObjectMeta, apis: ContextApis): Promise { - return services.applications - .getResourceActions(metadata.name, metadata.namespace, resource) - .then(actions => { - return actions.map( - action => - ({ - title: action.displayName ?? action.name, - disabled: !!action.disabled, - iconClassName: action.iconClass, - action: async () => { +export async function getResourceActionsMenuItems(resource: ResourceTreeNode, metadata: models.ObjectMeta, apis: ContextApis): Promise { + return services.applications.getResourceActions(metadata.name, metadata.namespace, resource).then(actions => { + return actions.map(action => ({ + title: action.displayName ?? action.name, + disabled: !!action.disabled, + iconClassName: action.iconClass, + action: async () => { + const confirmed = false; + const title = action.params ? `Enter input parameters for action: ${action.name}` : `Perform ${action.name} action?`; + await apis.popup.prompt( + title, + api => ( +
+ {!action.params && ( +
+
Are you sure you want to perform {action.name} action?
+
+ )} + {action.params && + action.params.map((param, index) => ( +
+ +
+ ))} +
+ ), + { + submit: async (vals, _, close) => { try { - const confirmed = await apis.popup.confirm(`Execute '${action.name}' action?`, `Are you sure you want to execute '${action.name}' action?`); - if (confirmed) { - await services.applications.runResourceAction(metadata.name, metadata.namespace, resource, action.name); - } + const resourceActionParameters = action.params + ? action.params.map(param => ({ + name: param.name, + value: vals[param.name] || param.default, + type: param.type, + default: param.default + })) + : []; + await services.applications.runResourceAction(metadata.name, metadata.namespace, resource, action.name, resourceActionParameters); + close(); } catch (e) { apis.notifications.show({ content: , @@ -544,10 +567,20 @@ export function getResourceActionsMenuItems(resource: ResourceTreeNode, metadata }); } } - }) as MenuItem - ); - }) - .catch(() => [] as MenuItem[]); + }, + null, + null, + action.params + ? action.params.reduce((acc, res) => { + acc[res.name] = res.default; + return acc; + }, {} as any) + : {} + ); + return confirmed; + } + })); + }); } function getActionItems( diff --git a/ui/src/app/shared/services/applications-service.ts b/ui/src/app/shared/services/applications-service.ts index d62b81e00dc2a..8c0f693de9637 100644 --- a/ui/src/app/shared/services/applications-service.ts +++ b/ui/src/app/shared/services/applications-service.ts @@ -326,18 +326,27 @@ export class ApplicationsService { }); } - public runResourceAction(name: string, appNamespace: string, resource: models.ResourceNode, action: string): Promise { + public runResourceAction( + name: string, + appNamespace: string, + resource: models.ResourceNode, + action: string, + resourceActionParameters: models.ResourceActionParam[] + ): Promise { return requests .post(`/applications/${name}/resource/actions`) - .query({ - appNamespace, - namespace: resource.namespace, - resourceName: resource.name, - version: resource.version, - kind: resource.kind, - group: resource.group - }) - .send(JSON.stringify(action)) + .send( + JSON.stringify({ + appNamespace, + namespace: resource.namespace, + resourceName: resource.name, + version: resource.version, + kind: resource.kind, + group: resource.group, + resourceActionParameters: resourceActionParameters, + action + }) + ) .then(res => (res.body.actions as models.ResourceAction[]) || []); } diff --git a/util/lua/custom_actions_test.go b/util/lua/custom_actions_test.go index e5b0642dc5862..1e525906628e7 100644 --- a/util/lua/custom_actions_test.go +++ b/util/lua/custom_actions_test.go @@ -15,6 +15,7 @@ import ( "github.com/argoproj/gitops-engine/pkg/diff" + applicationpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/application" appsv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v3/util/cli" ) @@ -95,10 +96,12 @@ type IndividualDiscoveryTest struct { } type IndividualActionTest struct { - Action string `yaml:"action"` - InputPath string `yaml:"inputPath"` - ExpectedOutputPath string `yaml:"expectedOutputPath"` - InputStr string `yaml:"input"` + Action string `yaml:"action"` + InputPath string `yaml:"inputPath"` + ExpectedOutputPath string `yaml:"expectedOutputPath"` + ExpectedErrorMessage string `yaml:"expectedErrorMessage"` + InputStr string `yaml:"input"` + Parameters map[string]string `yaml:"parameters"` } func TestLuaResourceActionsScript(t *testing.T) { @@ -146,8 +149,34 @@ func TestLuaResourceActionsScript(t *testing.T) { require.NoError(t, err) + // Log the action Lua script + t.Logf("Action Lua script: %s", action.ActionLua) + + // Parse action parameters + var params []*applicationpkg.ResourceActionParameters + if test.Parameters != nil { + for k, v := range test.Parameters { + params = append(params, &applicationpkg.ResourceActionParameters{ + Name: &k, + Value: &v, + }) + } + } + + if len(params) > 0 { + // Log the parameters + t.Logf("Parameters: %+v", params) + } + require.NoError(t, err) - impactedResources, err := vm.ExecuteResourceAction(sourceObj, action.ActionLua) + impactedResources, err := vm.ExecuteResourceAction(sourceObj, action.ActionLua, params) + + // Handle expected errors + if test.ExpectedErrorMessage != "" { + assert.EqualError(t, err, test.ExpectedErrorMessage) + return + } + require.NoError(t, err) // Treat the Lua expected output as a list @@ -185,6 +214,7 @@ func TestLuaResourceActionsScript(t *testing.T) { result.SetName(expectedObj.GetName()) } } + // Ideally, we would use a assert.Equal to detect the difference, but the Lua VM returns a object with float64 instead of the original int32. As a result, the assert.Equal is never true despite that the change has been applied. diffResult, err := diff.Diff(expectedObj, result, diff.WithNormalizer(testNormalizer{})) require.NoError(t, err) diff --git a/util/lua/lua.go b/util/lua/lua.go index b5bdada688fb2..df47709b7c5d2 100644 --- a/util/lua/lua.go +++ b/util/lua/lua.go @@ -17,6 +17,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" luajson "layeh.com/gopher-json" + applicationpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/application" appv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v3/resource_customizations" "github.com/argoproj/argo-cd/v3/util/glob" @@ -70,6 +71,10 @@ type VM struct { } func (vm VM) runLua(obj *unstructured.Unstructured, script string) (*lua.LState, error) { + return vm.runLuaWithResourceActionParameters(obj, script, nil) +} + +func (vm VM) runLuaWithResourceActionParameters(obj *unstructured.Unstructured, script string, resourceActionParameters []*applicationpkg.ResourceActionParameters) (*lua.LState, error) { l := lua.NewState(lua.Options{ SkipOpenLibs: !vm.UseOpenLibs, }) @@ -99,9 +104,29 @@ func (vm VM) runLua(obj *unstructured.Unstructured, script string) (*lua.LState, ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() l.SetContext(ctx) + + // Inject action parameters as a hash table global variable + actionParams := l.CreateTable(0, len(resourceActionParameters)) + for _, resourceActionParameter := range resourceActionParameters { + value := decodeValue(l, resourceActionParameter.GetValue()) + actionParams.RawSetH(lua.LString(resourceActionParameter.GetName()), value) + } + l.SetGlobal("actionParams", actionParams) // Set the actionParams table as a global variable + objectValue := decodeValue(l, obj.Object) l.SetGlobal("obj", objectValue) err := l.DoString(script) + + // Remove the default lua stack trace from execution errors since these + // errors will make it back to the user + var apiErr *lua.ApiError + if errors.As(err, &apiErr) { + if apiErr.Type == lua.ApiErrorRun { + apiErr.StackTrace = "" + err = apiErr + } + } + return l, err } @@ -173,8 +198,8 @@ func (vm VM) GetHealthScript(obj *unstructured.Unstructured) (script string, use return builtInScript, true, err } -func (vm VM) ExecuteResourceAction(obj *unstructured.Unstructured, script string) ([]ImpactedResource, error) { - l, err := vm.runLua(obj, script) +func (vm VM) ExecuteResourceAction(obj *unstructured.Unstructured, script string, resourceActionParameters []*applicationpkg.ResourceActionParameters) ([]ImpactedResource, error) { + l, err := vm.runLuaWithResourceActionParameters(obj, script, resourceActionParameters) if err != nil { return nil, err } diff --git a/util/lua/lua_test.go b/util/lua/lua_test.go index 79a2de9042966..aa78424108e91 100644 --- a/util/lua/lua_test.go +++ b/util/lua/lua_test.go @@ -12,6 +12,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "sigs.k8s.io/yaml" + applicationpkg "github.com/argoproj/argo-cd/v3/pkg/apiclient/application" appv1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1" "github.com/argoproj/argo-cd/v3/util/grpc" ) @@ -477,7 +478,7 @@ func TestExecuteOldStyleResourceAction(t *testing.T) { testObj := StrToUnstructured(objJSON) expectedLuaUpdatedObj := StrToUnstructured(expectedLuaUpdatedResult) vm := VM{} - newObjects, err := vm.ExecuteResourceAction(testObj, validActionLua) + newObjects, err := vm.ExecuteResourceAction(testObj, validActionLua, nil) require.NoError(t, err) assert.Len(t, newObjects, 1) assert.Equal(t, newObjects[0].K8SOperation, K8SOperation("patch")) @@ -516,7 +517,7 @@ const expectedCreatedMultipleJobsObjList = ` kind: Job metadata: name: hello-2 - namespace: test-ns + namespace: test-ns ` const expectedActionMixedOperationObjList = ` @@ -533,9 +534,9 @@ const expectedActionMixedOperationObjList = ` kind: CronJob metadata: name: hello - namespace: test-ns + namespace: test-ns labels: - test: test + test: test ` const createJobActionLua = ` @@ -650,7 +651,7 @@ func TestExecuteNewStyleCreateActionSingleResource(t *testing.T) { expectedObjects, err := UnmarshalToImpactedResources(bytes.NewBuffer(jsonBytes).String()) require.NoError(t, err) vm := VM{} - newObjects, err := vm.ExecuteResourceAction(testObj, createJobActionLua) + newObjects, err := vm.ExecuteResourceAction(testObj, createJobActionLua, nil) require.NoError(t, err) assert.Equal(t, expectedObjects, newObjects) } @@ -663,7 +664,7 @@ func TestExecuteNewStyleCreateActionMultipleResources(t *testing.T) { expectedObjects, err := UnmarshalToImpactedResources(bytes.NewBuffer(jsonBytes).String()) require.NoError(t, err) vm := VM{} - newObjects, err := vm.ExecuteResourceAction(testObj, createMultipleJobsActionLua) + newObjects, err := vm.ExecuteResourceAction(testObj, createMultipleJobsActionLua, nil) require.NoError(t, err) assert.Equal(t, expectedObjects, newObjects) } @@ -676,7 +677,7 @@ func TestExecuteNewStyleActionMixedOperationsOk(t *testing.T) { expectedObjects, err := UnmarshalToImpactedResources(bytes.NewBuffer(jsonBytes).String()) require.NoError(t, err) vm := VM{} - newObjects, err := vm.ExecuteResourceAction(testObj, mixedOperationActionLuaOk) + newObjects, err := vm.ExecuteResourceAction(testObj, mixedOperationActionLuaOk, nil) require.NoError(t, err) assert.Equal(t, expectedObjects, newObjects) } @@ -684,14 +685,14 @@ func TestExecuteNewStyleActionMixedOperationsOk(t *testing.T) { func TestExecuteNewStyleActionMixedOperationsFailure(t *testing.T) { testObj := StrToUnstructured(cronJobObjYaml) vm := VM{} - _, err := vm.ExecuteResourceAction(testObj, createMixedOperationActionLuaFailing) + _, err := vm.ExecuteResourceAction(testObj, createMixedOperationActionLuaFailing, nil) assert.ErrorContains(t, err, "unsupported operation") } func TestExecuteResourceActionNonTableReturn(t *testing.T) { testObj := StrToUnstructured(objJSON) vm := VM{} - _, err := vm.ExecuteResourceAction(testObj, returnInt) + _, err := vm.ExecuteResourceAction(testObj, returnInt, nil) assert.Errorf(t, err, incorrectReturnType, "table", "number") } @@ -703,7 +704,7 @@ return newObj func TestExecuteResourceActionInvalidUnstructured(t *testing.T) { testObj := StrToUnstructured(objJSON) vm := VM{} - _, err := vm.ExecuteResourceAction(testObj, invalidTableReturn) + _, err := vm.ExecuteResourceAction(testObj, invalidTableReturn, nil) require.Error(t, err) } @@ -758,7 +759,7 @@ func TestCleanPatch(t *testing.T) { testObj := StrToUnstructured(objWithEmptyStruct) expectedObj := StrToUnstructured(expectedUpdatedObjWithEmptyStruct) vm := VM{} - newObjects, err := vm.ExecuteResourceAction(testObj, pausedToFalseLua) + newObjects, err := vm.ExecuteResourceAction(testObj, pausedToFalseLua, nil) require.NoError(t, err) assert.Len(t, newObjects, 1) assert.Equal(t, newObjects[0].K8SOperation, K8SOperation("patch")) @@ -841,7 +842,7 @@ return hs` overrides := getHealthOverride(false) status, err := overrides.GetResourceHealth(testObj) assert.IsType(t, &lua.ApiError{}, err) - expectedErr := ":4: attempt to index a non-table object(nil) with key 'find'\nstack traceback:\n\t:4: in main chunk\n\t[G]: ?" + expectedErr := ":4: attempt to index a non-table object(nil) with key 'find'" require.EqualError(t, err, expectedErr) assert.Nil(t, status) }) @@ -882,3 +883,74 @@ return hs` assert.Nil(t, status) }) } + +func TestExecuteResourceActionWithParams(t *testing.T) { + deploymentObj := createMockResource("Deployment", "test-deployment", 1) + statefulSetObj := createMockResource("StatefulSet", "test-statefulset", 1) + + actionLua := ` + obj.spec.replicas = tonumber(actionParams["replicas"]) + return obj + ` + + params := []*applicationpkg.ResourceActionParameters{ + { + Name: func() *string { s := "replicas"; return &s }(), + Value: func() *string { s := "3"; return &s }(), + }, + } + + vm := VM{} + + // Test with Deployment + t.Run("Test with Deployment", func(t *testing.T) { + impactedResources, err := vm.ExecuteResourceAction(deploymentObj, actionLua, params) + require.NoError(t, err) + + for _, impactedResource := range impactedResources { + modifiedObj := impactedResource.UnstructuredObj + + // Check the replicas in the modified object + actualReplicas, found, err := unstructured.NestedInt64(modifiedObj.Object, "spec", "replicas") + require.NoError(t, err) + assert.True(t, found, "spec.replicas should be found in the modified object") + assert.Equal(t, int64(3), actualReplicas, "replicas should be updated to 3") + } + }) + + // Test with StatefulSet + t.Run("Test with StatefulSet", func(t *testing.T) { + impactedResources, err := vm.ExecuteResourceAction(statefulSetObj, actionLua, params) + require.NoError(t, err) + + for _, impactedResource := range impactedResources { + modifiedObj := impactedResource.UnstructuredObj + + // Check the replicas in the modified object + actualReplicas, found, err := unstructured.NestedInt64(modifiedObj.Object, "spec", "replicas") + require.NoError(t, err) + assert.True(t, found, "spec.replicas should be found in the modified object") + assert.Equal(t, int64(3), actualReplicas, "replicas should be updated to 3") + } + }) +} + +func createMockResource(kind string, name string, replicas int) *unstructured.Unstructured { + return StrToUnstructured(fmt.Sprintf(` + apiVersion: apps/v1 + kind: %s + metadata: + name: %s + namespace: default + spec: + replicas: %d + template: + metadata: + labels: + app: test + spec: + containers: + - name: test-container + image: nginx + `, kind, name, replicas)) +}