diff --git a/Makefile b/Makefile index 13f39574c577e..f1a56f2da2d74 100644 --- a/Makefile +++ b/Makefile @@ -79,6 +79,7 @@ define run-in-test-server -e ARGOCD_TLS_DATA_PATH=${ARGOCD_TLS_DATA_PATH:-/tmp/argocd-local/tls} \ -e ARGOCD_SSH_DATA_PATH=${ARGOCD_SSH_DATA_PATH:-/tmp/argocd-local/ssh} \ -e ARGOCD_GPG_DATA_PATH=${ARGOCD_GPG_DATA_PATH:-/tmp/argocd-local/gpg/source} \ + -e ARGOCD_E2E_RECORD=${ARGOCD_E2E_RECORD} \ -v ${DOCKER_SRC_MOUNT} \ -v ${GOPATH}/pkg/mod:/go/pkg/mod${VOLUME_MOUNT} \ -v ${GOCACHE}:/tmp/go-build-cache${VOLUME_MOUNT} \ @@ -100,6 +101,7 @@ define run-in-test-client -e HOME=/home/user \ -e GOPATH=/go \ -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) \ + -e ARGOCD_E2E_RECORD=$(ARGOCD_E2E_RECORD) \ -e GOCACHE=/tmp/go-build-cache \ -e ARGOCD_LINT_GOGC=$(ARGOCD_LINT_GOGC) \ -v ${DOCKER_SRC_MOUNT} \ @@ -112,9 +114,13 @@ define run-in-test-client bash -c "$(1)" endef -# define exec-in-test-server - docker exec -it -u $(shell id -u):$(shell id -g) -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) argocd-test-server $(1) + docker exec -it -u $(shell id -u):$(shell id -g) \ + -e ARGOCD_E2E_K3S=$(ARGOCD_E2E_K3S) \ + -e ARGOCD_E2E_RECORD=$(ARGOCD_E2E_RECORD) \ + -e ARGOCD_E2E_APP_NAMESPACE=$(ARGOCD_E2E_APP_NAMESPACE) \ + -e ARGOCD_E2E_TEST_TIMEOUT=$(ARGOCD_E2E_TEST_TIMEOUT) \ + argocd-test-server $(1) endef PATH:=$(PATH):$(PWD)/hack diff --git a/assets/swagger.json b/assets/swagger.json index cd28c12b13875..adb0042d2b786 100644 --- a/assets/swagger.json +++ b/assets/swagger.json @@ -4637,6 +4637,13 @@ "$ref": "#/definitions/v1alpha1SignatureKey" } }, + "sourceNamespaces": { + "type": "array", + "title": "SourceNamespaces contains list of allowed Application namespaces", + "items": { + "type": "string" + } + }, "sourceRepos": { "type": "array", "title": "SourceRepos contains list of repository URLs which can be used for deployment", diff --git a/cmd/argocd-server/commands/argocd_server.go b/cmd/argocd-server/commands/argocd_server.go index f627788fa72de..16f606d57468e 100644 --- a/cmd/argocd-server/commands/argocd_server.go +++ b/cmd/argocd-server/commands/argocd_server.go @@ -141,6 +141,7 @@ func NewCommand() *cobra.Command { Cache: cache, XFrameOptions: frameOptions, RedisClient: redisClient, + WatchAllNamespaces: true, } stats.RegisterStackDumper() diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index 6d0a33189c5f5..2beab18d857e2 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -351,7 +351,7 @@ func NewApplicationLogsCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co } func printAppSummaryTable(app *argoappv1.Application, appURL string, windows *argoappv1.SyncWindows) { - fmt.Printf(printOpFmtStr, "Name:", app.Name) + fmt.Printf(printOpFmtStr, "Name:", app.QualifiedName()) fmt.Printf(printOpFmtStr, "Project:", app.Spec.GetProject()) fmt.Printf(printOpFmtStr, "Server:", app.Spec.Destination.Server) fmt.Printf(printOpFmtStr, "Namespace:", app.Spec.Destination.Namespace) @@ -537,7 +537,7 @@ func NewApplicationSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Com } setParameterOverrides(app, appOpts.Parameters) _, err = appIf.UpdateSpec(ctx, &applicationpkg.ApplicationUpdateSpecRequest{ - Name: &app.Name, + Name: &appName, Spec: app.Spec, Validate: &appOpts.Validate, }) @@ -685,7 +685,7 @@ func NewApplicationUnsetCommand(clientOpts *argocdclient.ClientOptions) *cobra.C cmdutil.SetAppSpecOptions(c.Flags(), &app.Spec, &appOpts) _, err = appIf.UpdateSpec(context.Background(), &applicationpkg.ApplicationUpdateSpecRequest{ - Name: &app.Name, + Name: pointer.StringPtr(app.QualifiedName()), Spec: app.Spec, Validate: &appOpts.Validate, }) @@ -748,7 +748,7 @@ func getLocalObjectsString(app *argoappv1.Application, local, localRepoRoot, app res, err := repository.GenerateManifests(local, localRepoRoot, app.Spec.Source.TargetRevision, &repoapiclient.ManifestRequest{ Repo: &argoappv1.Repository{Repo: app.Spec.Source.RepoURL}, AppLabelKey: appLabelKey, - AppName: app.Name, + AppName: app.InstanceName(), Namespace: app.Spec.Destination.Namespace, ApplicationSource: &app.Spec.Source, KustomizeOptions: kustomizeOptions, @@ -840,7 +840,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co cluster, err := clusterIf.Get(context.Background(), &clusterpkg.ClusterQuery{Name: app.Spec.Destination.Name, Server: app.Spec.Destination.Server}) errors.CheckError(err) localObjs := groupObjsByKey(getLocalObjects(app, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins), liveObjs, app.Spec.Destination.Namespace) - items = groupObjsForDiff(resources, localObjs, items, argoSettings, appName) + items = groupObjsForDiff(resources, localObjs, items, argoSettings, app.InstanceName()) } else if revision != "" { var unstructureds []*unstructured.Unstructured q := applicationpkg.ApplicationManifestQuery{ @@ -855,7 +855,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co unstructureds = append(unstructureds, obj) } groupedObjs := groupObjsByKey(unstructureds, liveObjs, app.Spec.Destination.Namespace) - items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, appName) + items = groupObjsForDiff(resources, groupedObjs, items, argoSettings, app.InstanceName()) } else { for i := range resources.Items { res := resources.Items[i] @@ -1029,7 +1029,7 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. // Print simple list of application names func printApplicationNames(apps []argoappv1.Application) { for _, app := range apps { - fmt.Println(app.Name) + fmt.Println(app.QualifiedName()) } } @@ -1047,7 +1047,7 @@ func printApplicationTable(apps []argoappv1.Application, output *string) { _, _ = fmt.Fprintf(w, fmtStr, headers...) for _, app := range apps { vals := []interface{}{ - app.Name, + app.QualifiedName(), app.Spec.Destination.Server, app.Spec.Destination.Namespace, app.Spec.GetProject(), @@ -1067,10 +1067,11 @@ func printApplicationTable(apps []argoappv1.Application, output *string) { // NewApplicationListCommand returns a new instance of an `argocd app list` command func NewApplicationListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var ( - output string - selector string - projects []string - repo string + output string + selector string + projects []string + repo string + namespace string ) var command = &cobra.Command{ Use: "list", @@ -1109,6 +1110,7 @@ func NewApplicationListCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co command.Flags().StringVarP(&selector, "selector", "l", "", "List apps by label") command.Flags().StringArrayVarP(&projects, "project", "p", []string{}, "Filter by project name") command.Flags().StringVarP(&repo, "repo", "r", "", "List apps by source repo URL") + command.Flags().StringVarP(&namespace, "namespace", "n", "", "List only apps in given namespace") return command } @@ -1228,7 +1230,7 @@ func NewApplicationWaitCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co list, err := appIf.List(context.Background(), &applicationpkg.ApplicationQuery{Selector: selector}) errors.CheckError(err) for _, i := range list.Items { - appNames = append(appNames, i.Name) + appNames = append(appNames, i.Namespace+"/"+i.Name) } } for _, appName := range appNames { @@ -1315,7 +1317,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co log.Fatalf("no apps match selector %v", selector) } for _, i := range list.Items { - appNames = append(appNames, i.Name) + appNames = append(appNames, i.QualifiedName()) } } @@ -1413,7 +1415,6 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co if !async { app, err := waitOnApplicationStatus(acdClient, appName, timeout, false, false, true, false, selectedResources) errors.CheckError(err) - if !dryRun { if !app.Status.OperationState.Phase.Successful() { log.Fatalf("Operation has completed with phase: %s", app.Status.OperationState.Phase) @@ -1662,12 +1663,10 @@ func waitOnApplicationStatus(acdClient apiclient.Client, appName string, timeout // Wait on the application as a whole selectedResourcesAreReady = checkResourceStatus(watchSync, watchHealth, watchOperation, watchSuspended, string(app.Status.Health.Status), string(app.Status.Sync.Status), appEvent.Application.Operation) } - if selectedResourcesAreReady && (!operationInProgress || !watchOperation) { app = printFinalStatus(app) return app, nil } - newStates := groupResourceStates(app, selectedResources) for _, newState := range newStates { var doPrint bool diff --git a/cmd/util/app.go b/cmd/util/app.go index 505cf2176f72e..8a462e727b3b2 100644 --- a/cmd/util/app.go +++ b/cmd/util/app.go @@ -48,6 +48,7 @@ type AppOptions struct { allowEmpty bool namePrefix string nameSuffix string + namespace string directoryRecurse bool configManagementPlugin string jsonnetTlaStr []string @@ -118,6 +119,7 @@ func AddAppFlags(command *cobra.Command, opts *AppOptions) { command.Flags().DurationVar(&opts.retryBackoffDuration, "sync-retry-backoff-duration", argoappv1.DefaultSyncRetryDuration, "Sync retry backoff base duration. Input needs to be a duration (e.g. 2m, 1h)") command.Flags().DurationVar(&opts.retryBackoffMaxDuration, "sync-retry-backoff-max-duration", argoappv1.DefaultSyncRetryMaxDuration, "Max sync retry backoff duration. Input needs to be a duration (e.g. 2m, 1h)") command.Flags().Int64Var(&opts.retryBackoffFactor, "sync-retry-backoff-factor", argoappv1.DefaultSyncRetryFactor, "Factor multiplies the base duration after each failed sync retry") + command.Flags().StringVar(&opts.namespace, "app-namespace", "", "create application in given namespace instead of the default one") } func SetAppSpecOptions(flags *pflag.FlagSet, spec *argoappv1.ApplicationSpec, appOpts *AppOptions) int { @@ -584,6 +586,9 @@ func ConstructApp(fileURL, appName string, labels, args []string, appOpts AppOpt SetParameterOverrides(&app, appOpts.Parameters) mergeLabels(&app, labels) } + if appOpts.namespace != "" { + app.Namespace = appOpts.namespace + } return &app, nil } diff --git a/controller/appcontroller.go b/controller/appcontroller.go index 952d8a4053452..274c3400584e8 100644 --- a/controller/appcontroller.go +++ b/controller/appcontroller.go @@ -112,6 +112,7 @@ type ApplicationController struct { metricsServer *metrics.MetricsServer kubectlSemaphore *semaphore.Weighted clusterFilter func(cluster *appv1.Cluster) bool + watchAllNamespaces bool } // NewApplicationController creates new instance of ApplicationController. @@ -151,6 +152,7 @@ func NewApplicationController( settingsMgr: settingsMgr, selfHealTimeout: selfHealTimeout, clusterFilter: clusterFilter, + watchAllNamespaces: true, } if kubectlParallelismLimit > 0 { ctrl.kubectlSemaphore = semaphore.NewWeighted(kubectlParallelismLimit) @@ -231,7 +233,7 @@ func isSelfReferencedApp(app *appv1.Application, ref v1.ObjectReference) bool { } func (ctrl *ApplicationController) getAppProj(app *appv1.Application) (*appv1.AppProject, error) { - return argo.GetAppProject(&app.Spec, applisters.NewAppProjectLister(ctrl.projInformer.GetIndexer()), ctrl.namespace, ctrl.settingsMgr) + return argo.GetAppProject(app, applisters.NewAppProjectLister(ctrl.projInformer.GetIndexer()), ctrl.namespace, ctrl.settingsMgr) } func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]bool, ref v1.ObjectReference) { @@ -248,15 +250,22 @@ func (ctrl *ApplicationController) handleObjectUpdated(managedByApp map[string]b if proj, err := ctrl.getAppProj(app); err == nil && proj.IsGroupKindPermitted(ref.GroupVersionKind().GroupKind(), true) && !isKnownOrphanedResourceExclusion(kube.NewResourceKey(ref.GroupVersionKind().Group, ref.GroupVersionKind().Kind, ref.Namespace, ref.Name), proj) { - managedByApp[app.Name] = false + managedByApp[app.InstanceName()] = false } } } } for appName, isManagedResource := range managedByApp { - obj, exists, err := ctrl.appInformer.GetIndexer().GetByKey(ctrl.namespace + "/" + appName) - if app, ok := obj.(*appv1.Application); exists && err == nil && ok && isSelfReferencedApp(app, ref) { - // Don't force refresh app if related resource is application itself. This prevents infinite reconciliation loop. + obj, exists, err := ctrl.appInformer.GetIndexer().GetByKey(strings.ReplaceAll(appName, "_", "/")) + app, ok := obj.(*appv1.Application) + // Don't force refresh app if related resource is application itself. This prevents infinite reconciliation loop. + if exists && err == nil && ok && isSelfReferencedApp(app, ref) { + continue + } + + // Process only objects managed by an application that is allowed to + if proj, err := ctrl.getAppProj(app); err != nil || !proj.IsAppNamespacePermitted(app, ctrl.namespace) { + log.Errorf("application '%s' is not permitted in namespace '%s' by project '%s'", app.Name, app.Namespace, proj.Name) continue } @@ -282,11 +291,11 @@ func (ctrl *ApplicationController) setAppManagedResources(a *appv1.Application, if err != nil { return nil, err } - err = ctrl.cache.SetAppResourcesTree(a.Name, tree) + err = ctrl.cache.SetAppResourcesTree(a.InstanceName(), tree) if err != nil { return nil, err } - return tree, ctrl.cache.SetAppManagedResources(a.Name, managedResources) + return tree, ctrl.cache.SetAppManagedResources(a.InstanceName(), managedResources) } // returns true of given resources exist in the namespace by default and not managed by the user @@ -316,7 +325,7 @@ func isKnownOrphanedResourceExclusion(key kube.ResourceKey, proj *appv1.AppProje func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managedResources []*appv1.ResourceDiff) (*appv1.ApplicationTree, error) { nodes := make([]appv1.ResourceNode, 0) - proj, err := argo.GetAppProject(&a.Spec, applisters.NewAppProjectLister(ctrl.projInformer.GetIndexer()), ctrl.namespace, ctrl.settingsMgr) + proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(ctrl.projInformer.GetIndexer()), ctrl.namespace, ctrl.settingsMgr) if err != nil { return nil, err } @@ -369,7 +378,7 @@ func (ctrl *ApplicationController) getResourceTree(a *appv1.Application, managed err := ctrl.stateCache.IterateHierarchy(a.Spec.Destination.Server, k, func(child appv1.ResourceNode, appName string) { belongToAnotherApp := false if appName != "" { - if _, exists, err := ctrl.appInformer.GetIndexer().GetByKey(ctrl.namespace + "/" + appName); exists && err == nil { + if _, exists, err := ctrl.appInformer.GetIndexer().GetByKey(strings.ReplaceAll(appName, "_", "/")); exists && err == nil { belongToAnotherApp = true } } @@ -605,14 +614,15 @@ func (ctrl *ApplicationController) Run(ctx context.Context, statusProcessors int } func (ctrl *ApplicationController) requestAppRefresh(appName string, compareWith *CompareWith, after *time.Duration) { - key := fmt.Sprintf("%s/%s", ctrl.namespace, appName) + app, ns := argo.ParseAppNamespacedName(strings.ReplaceAll(appName, "_", "/"), ctrl.namespace) + key := fmt.Sprintf("%s/%s", ns, app) if compareWith != nil && after != nil { ctrl.appComparisonTypeRefreshQueue.AddAfter(fmt.Sprintf("%s/%d", key, compareWith), *after) } else { if compareWith != nil { ctrl.refreshRequestedAppsMutex.Lock() - ctrl.refreshRequestedApps[appName] = compareWith.Max(ctrl.refreshRequestedApps[appName]) + ctrl.refreshRequestedApps[key] = compareWith.Max(ctrl.refreshRequestedApps[key]) ctrl.refreshRequestedAppsMutex.Unlock() } if after != nil { @@ -626,11 +636,13 @@ func (ctrl *ApplicationController) requestAppRefresh(appName string, compareWith } func (ctrl *ApplicationController) isRefreshRequested(appName string) (bool, CompareWith) { + app, ns := argo.ParseAppNamespacedName(strings.ReplaceAll(appName, "_", "/"), ctrl.namespace) + key := fmt.Sprintf("%s/%s", ns, app) ctrl.refreshRequestedAppsMutex.Lock() defer ctrl.refreshRequestedAppsMutex.Unlock() - level, ok := ctrl.refreshRequestedApps[appName] + level, ok := ctrl.refreshRequestedApps[key] if ok { - delete(ctrl.refreshRequestedApps, appName) + delete(ctrl.refreshRequestedApps, key) } return ok, level } @@ -703,7 +715,8 @@ func (ctrl *ApplicationController) processAppComparisonTypeQueueItem() (processN log.Warnf("Unable to parse comparison type: %v", err) return } else { - ctrl.requestAppRefresh(parts[1], CompareWith(compareWith).Pointer(), nil) + // TODO: provide a method to construct instance key from namespace + name + ctrl.requestAppRefresh(parts[0]+"_"+parts[1], CompareWith(compareWith).Pointer(), nil) } } return @@ -797,7 +810,7 @@ func (ctrl *ApplicationController) getPermittedAppLiveObjects(app *appv1.Applica } func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Application) ([]*unstructured.Unstructured, error) { - logCtx := log.WithField("application", app.Name) + logCtx := log.WithField("application", app.QualifiedName()) logCtx.Infof("Deleting resources") // Get refreshed application info, since informer app copy might be stale app, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Get(context.Background(), app.Name, metav1.GetOptions{}) @@ -870,11 +883,11 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic logCtx.Infof("%d objects remaining for deletion", len(objsMap)) return objs, nil } - err = ctrl.cache.SetAppManagedResources(app.Name, nil) + err = ctrl.cache.SetAppManagedResources(app.InstanceName(), nil) if err != nil { return objs, err } - err = ctrl.cache.SetAppResourcesTree(app.Name, nil) + err = ctrl.cache.SetAppResourcesTree(app.InstanceName(), nil) if err != nil { return objs, err } @@ -885,7 +898,7 @@ func (ctrl *ApplicationController) finalizeApplicationDeletion(app *appv1.Applic } logCtx.Infof("Successfully deleted %d resources", len(objs)) - ctrl.projectRefreshQueue.Add(fmt.Sprintf("%s/%s", app.Namespace, app.Spec.GetProject())) + ctrl.projectRefreshQueue.Add(fmt.Sprintf("%s/%s", ctrl.namespace, app.Spec.GetProject())) return objs, nil } @@ -927,7 +940,7 @@ func (ctrl *ApplicationController) setAppCondition(app *appv1.Application, condi } func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Application) { - logCtx := log.WithField("application", app.Name) + logCtx := log.WithField("application", app.QualifiedName()) var state *appv1.OperationState // Recover from any unexpected panics and automatically set the status to be failed defer func() { @@ -958,7 +971,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli retryAfter := time.Until(retryAt) if retryAfter > 0 { logCtx.Infof("Skipping retrying in-progress operation. Attempting again at: %s", retryAt.Format(time.RFC3339)) - ctrl.requestAppRefresh(app.Name, CompareWithLatest.Pointer(), &retryAfter) + ctrl.requestAppRefresh(app.InstanceName(), CompareWithLatest.Pointer(), &retryAfter) return } else { // retrying operation. remove previous failure time in app since it is used as a trigger @@ -987,7 +1000,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli if state.Phase == synccommon.OperationRunning { // It's possible for an app to be terminated while we were operating on it. We do not want // to clobber the Terminated state with Running. Get the latest app state to check for this. - freshApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).Get(context.Background(), app.ObjectMeta.Name, metav1.GetOptions{}) + freshApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace).Get(context.Background(), app.ObjectMeta.Name, metav1.GetOptions{}) if err == nil { if freshApp.Status.OperationState != nil && freshApp.Status.OperationState.Phase == synccommon.OperationTerminating { state.Phase = synccommon.OperationTerminating @@ -1021,7 +1034,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli // sync/health information if _, err := cache.MetaNamespaceKeyFunc(app); err == nil { // force app refresh with using CompareWithLatest comparison type and trigger app reconciliation loop - ctrl.requestAppRefresh(app.Name, CompareWithLatest.Pointer(), nil) + ctrl.requestAppRefresh(app.InstanceName(), CompareWithLatest.Pointer(), nil) } else { logCtx.Warnf("Fails to requeue application: %v", err) } @@ -1049,7 +1062,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta patch["operation"] = nil } if reflect.DeepEqual(app.Status.OperationState, state) { - log.Infof("No operation updates necessary to '%s'. Skipping patch", app.Name) + log.Infof("No operation updates necessary to '%s'. Skipping patch", app.QualifiedName()) return nil } patchJSON, err := json.Marshal(patch) @@ -1063,7 +1076,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta } } - appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace) + appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(app.Namespace) patchedApp, err := appClient.Patch(context.Background(), app.Name, types.MergePatchType, patchJSON, metav1.PatchOptions{}) if err != nil { // Stop retrying updating deleted application @@ -1072,7 +1085,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta } return err } - log.Infof("updated '%s' operation (phase: %s)", app.Name, state.Phase) + log.Infof("updated '%s' operation (phase: %s)", app.QualifiedName(), state.Phase) if state.Phase.Completed() { eventInfo := argo.EventInfo{Reason: argo.EventReasonOperationCompleted} var messages []string @@ -1108,6 +1121,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo processNext = false return } + processNext = true defer func() { if r := recover(); r != nil { @@ -1138,7 +1152,7 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo } app := origApp.DeepCopy() - logCtx := log.WithFields(log.Fields{"application": app.Name}) + logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()}) startTime := time.Now() defer func() { reconcileDuration := time.Since(startTime) @@ -1154,13 +1168,13 @@ func (ctrl *ApplicationController) processAppRefreshQueueItem() (processNext boo if comparisonLevel == ComparisonWithNothing { managedResources := make([]*appv1.ResourceDiff, 0) - if err := ctrl.cache.GetAppManagedResources(app.Name, &managedResources); err != nil { + if err := ctrl.cache.GetAppManagedResources(app.InstanceName(), &managedResources); err != nil { logCtx.Warnf("Failed to get cached managed resources for tree reconciliation, fallback to full reconciliation") } else { var tree *appv1.ApplicationTree if tree, err = ctrl.getResourceTree(app, managedResources); err == nil { app.Status.Summary = tree.GetSummary() - if err := ctrl.cache.SetAppResourcesTree(app.Name, tree); err != nil { + if err := ctrl.cache.SetAppResourcesTree(app.InstanceName(), tree); err != nil { logCtx.Errorf("Failed to cache resources tree: %v", err) return } @@ -1246,7 +1260,7 @@ func resourceStatusKey(res appv1.ResourceStatus) string { // Additionally returns whether full refresh was requested or not. // If full refresh is requested then target and live state should be reconciled, else only live state tree should be updated. func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application, statusRefreshTimeout time.Duration) (bool, appv1.RefreshType, CompareWith) { - logCtx := log.WithFields(log.Fields{"application": app.Name}) + logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()}) var reason string compareWith := CompareWithLatest refreshType := appv1.RefreshTypeNormal @@ -1271,7 +1285,7 @@ func (ctrl *ApplicationController) needRefreshAppStatus(app *appv1.Application, reason = fmt.Sprintf("comparison expired. reconciledAt: %v, expiry: %v", reconciledAtStr, statusRefreshTimeout) } else if !app.Spec.Destination.Equals(app.Status.Sync.ComparedTo.Destination) { reason = "spec.destination differs" - } else if requested, level := ctrl.isRefreshRequested(app.Name); requested { + } else if requested, level := ctrl.isRefreshRequested(app.QualifiedName()); requested { compareWith = level reason = "controller refresh requested" } @@ -1318,7 +1332,7 @@ func (ctrl *ApplicationController) refreshAppConditions(app *appv1.Application) // normalizeApplication normalizes an application.spec and additionally persists updates if it changed func (ctrl *ApplicationController) normalizeApplication(orig, app *appv1.Application) { - logCtx := log.WithFields(log.Fields{"application": app.Name}) + logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()}) app.Spec = *argo.NormalizeApplicationSpec(&app.Spec) patch, modified, err := diff.CreateTwoWayMergePatch(orig, app, appv1.Application{}) if err != nil { @@ -1336,7 +1350,7 @@ func (ctrl *ApplicationController) normalizeApplication(orig, app *appv1.Applica // persistAppStatus persists updates to application status. If no changes were made, it is a no-op func (ctrl *ApplicationController) persistAppStatus(orig *appv1.Application, newStatus *appv1.ApplicationStatus) { - logCtx := log.WithFields(log.Fields{"application": orig.Name}) + logCtx := log.WithFields(log.Fields{"application": orig.QualifiedName()}) if orig.Status.Sync.Status != newStatus.Sync.Status { message := fmt.Sprintf("Updated sync status: %s -> %s", orig.Status.Sync.Status, newStatus.Sync.Status) ctrl.auditLogger.LogAppEvent(orig, argo.EventInfo{Reason: argo.EventReasonResourceUpdated, Type: v1.EventTypeNormal}, message) @@ -1379,7 +1393,7 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus * if app.Spec.SyncPolicy == nil || app.Spec.SyncPolicy.Automated == nil { return nil } - logCtx := log.WithFields(log.Fields{"application": app.Name}) + logCtx := log.WithFields(log.Fields{"application": app.QualifiedName()}) if app.Operation != nil { logCtx.Infof("Skipping auto-sync: another operation is in progress") return nil @@ -1450,7 +1464,7 @@ func (ctrl *ApplicationController) autoSync(app *appv1.Application, syncStatus * } } else { logCtx.Infof("Skipping auto-sync: already attempted sync to %s with timeout %v (retrying in %v)", desiredCommitSHA, ctrl.selfHealTimeout, retryAfter) - ctrl.requestAppRefresh(app.Name, CompareWithLatest.Pointer(), &retryAfter) + ctrl.requestAppRefresh(app.InstanceName(), CompareWithLatest.Pointer(), &retryAfter) return nil } @@ -1531,13 +1545,17 @@ func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool { } func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.SharedIndexInformer, applisters.ApplicationLister) { + watchNamespace := ctrl.namespace + if ctrl.watchAllNamespaces { + watchNamespace = "" + } informer := cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options metav1.ListOptions) (apiruntime.Object, error) { - return ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).List(context.TODO(), options) + return ctrl.applicationClientset.ArgoprojV1alpha1().Applications(watchNamespace).List(context.TODO(), options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { - return ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).Watch(context.TODO(), options) + return ctrl.applicationClientset.ArgoprojV1alpha1().Applications(watchNamespace).Watch(context.TODO(), options) }, }, &appv1.Application{}, @@ -1596,10 +1614,10 @@ func (ctrl *ApplicationController) newApplicationInformerAndLister() (cache.Shar oldApp, oldOK := old.(*appv1.Application) newApp, newOK := new.(*appv1.Application) if oldOK && newOK && automatedSyncEnabled(oldApp, newApp) { - log.WithField("application", newApp.Name).Info("Enabled automated sync") + log.WithField("application", newApp.QualifiedName()).Info("Enabled automated sync") compareWith = CompareWithLatest.Pointer() } - ctrl.requestAppRefresh(newApp.Name, compareWith, nil) + ctrl.requestAppRefresh(newApp.QualifiedName(), compareWith, nil) ctrl.appOperationQueue.Add(key) }, DeleteFunc: func(obj interface{}) { diff --git a/controller/appcontroller_test.go b/controller/appcontroller_test.go index c7abb22c3d289..530856496b503 100644 --- a/controller/appcontroller_test.go +++ b/controller/appcontroller_test.go @@ -250,7 +250,7 @@ metadata: name: test-cm namespace: invalid labels: - app.kubernetes.io/instance: my-app + app.kubernetes.io/instance: ` + test.FakeArgoCDNamespace + `_my-app data: ` @@ -731,18 +731,34 @@ func TestNormalizeApplication(t *testing.T) { } func TestHandleAppUpdated(t *testing.T) { + defaultProj := argoappv1.AppProject{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + Namespace: test.FakeArgoCDNamespace, + }, + Spec: argoappv1.AppProjectSpec{ + SourceRepos: []string{"*"}, + Destinations: []argoappv1.ApplicationDestination{ + { + Server: "*", + Namespace: "*", + }, + }, + }, + } + app := newFakeApp() app.Spec.Destination.Namespace = test.FakeArgoCDNamespace app.Spec.Destination.Server = argoappv1.KubernetesInternalAPIServerAddr - ctrl := newFakeController(&fakeData{apps: []runtime.Object{app}}) + ctrl := newFakeController(&fakeData{apps: []runtime.Object{app, &defaultProj}}) - ctrl.handleObjectUpdated(map[string]bool{app.Name: true}, kube.GetObjectRef(kube.MustToUnstructured(app))) - isRequested, level := ctrl.isRefreshRequested(app.Name) + ctrl.handleObjectUpdated(map[string]bool{app.InstanceName(): true}, kube.GetObjectRef(kube.MustToUnstructured(app))) + isRequested, level := ctrl.isRefreshRequested(app.QualifiedName()) assert.False(t, isRequested) assert.Equal(t, ComparisonWithNothing, level) - ctrl.handleObjectUpdated(map[string]bool{app.Name: true}, corev1.ObjectReference{UID: "test", Kind: kube.DeploymentKind, Name: "test", Namespace: "default"}) - isRequested, level = ctrl.isRefreshRequested(app.Name) + ctrl.handleObjectUpdated(map[string]bool{app.InstanceName(): true}, corev1.ObjectReference{UID: "test", Kind: kube.DeploymentKind, Name: "test", Namespace: "default"}) + isRequested, level = ctrl.isRefreshRequested(app.QualifiedName()) assert.True(t, isRequested) assert.Equal(t, CompareWithRecent, level) } diff --git a/controller/cache/cache.go b/controller/cache/cache.go index 1650d163fb8fd..a54bb1e34ffed 100644 --- a/controller/cache/cache.go +++ b/controller/cache/cache.go @@ -414,7 +414,7 @@ func (c *liveStateCache) GetManagedLiveObjs(a *appv1.Application, targetObjs []* return nil, err } return clusterInfo.GetManagedLiveObjs(targetObjs, func(r *clustercache.Resource) bool { - return resInfo(r).AppName == a.Name + return resInfo(r).AppName == a.InstanceName() }) } diff --git a/controller/state.go b/controller/state.go index a6819a88afb55..a8c9d62ab15e9 100644 --- a/controller/state.go +++ b/controller/state.go @@ -165,7 +165,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1 NoCache: noCache, NoRevisionCache: noRevisionCache, AppLabelKey: appLabelKey, - AppName: app.Name, + AppName: app.InstanceName(), Namespace: app.Spec.Destination.Namespace, ApplicationSource: &source, Plugins: tools, @@ -185,7 +185,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1 } ts.AddCheckpoint("unmarshal_ms") - logCtx := log.WithField("application", app.Name) + logCtx := log.WithField("application", app.QualifiedName()) for k, v := range ts.Timings() { logCtx = logCtx.WithField(k, v.Milliseconds()) } @@ -387,7 +387,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap failedToLoadObjs := false conditions := make([]v1alpha1.ApplicationCondition, 0) - logCtx := log.WithField("application", app.Name) + logCtx := log.WithField("application", app.QualifiedName()) logCtx.Infof("Comparing app state (cluster: %s, namespace: %s)", app.Spec.Destination.Server, app.Spec.Destination.Namespace) var targetObjs []*unstructured.Unstructured @@ -463,10 +463,10 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap for _, liveObj := range liveObjByKey { if liveObj != nil { appInstanceName := kubeutil.GetAppInstanceLabel(liveObj, appLabelKey) - if appInstanceName != "" && appInstanceName != app.Name { + if appInstanceName != "" && appInstanceName != app.InstanceName() { conditions = append(conditions, v1alpha1.ApplicationCondition{ Type: v1alpha1.ApplicationConditionSharedResourceWarning, - Message: fmt.Sprintf("%s/%s is part of applications %s and %s", liveObj.GetKind(), liveObj.GetName(), app.Name, appInstanceName), + Message: fmt.Sprintf("%s/%s is part of applications %s and %s", liveObj.GetKind(), liveObj.GetName(), app.InstanceName(), appInstanceName), LastTransitionTime: &now, }) } @@ -497,7 +497,7 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap _, refreshRequested := app.IsRefreshRequested() noCache = noCache || refreshRequested || app.Status.Expired(m.statusRefreshTimeout) - if noCache || specChanged || revisionChanged || m.cache.GetAppManagedResources(app.Name, &cachedDiff) != nil { + if noCache || specChanged || revisionChanged || m.cache.GetAppManagedResources(app.InstanceName(), &cachedDiff) != nil { // (rare) cache miss diffResults, err = diff.DiffArray(reconciliation.Target, reconciliation.Live, diffOpts...) } else { @@ -664,7 +664,7 @@ func (m *appStateManager) persistRevisionHistory(app *v1alpha1.Application, revi if err != nil { return err } - _, err = m.appclientset.ArgoprojV1alpha1().Applications(m.namespace).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{}) + _, err = m.appclientset.ArgoprojV1alpha1().Applications(app.Namespace).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{}) return err } diff --git a/controller/state_test.go b/controller/state_test.go index 9074cebf08be8..e7bcd3ee1e592 100644 --- a/controller/state_test.go +++ b/controller/state_test.go @@ -365,7 +365,7 @@ func TestSetManagedResourcesWithResourcesOfAnotherApp(t *testing.T) { ResourceNode: argoappv1.ResourceNode{ ResourceRef: argoappv1.ResourceRef{Kind: kube.DeploymentKind, Name: "guestbook", Namespace: app2.Namespace}, }, - AppName: "app2", + AppName: test.FakeArgoCDNamespace + "_app2", }, }, }) @@ -398,6 +398,7 @@ func TestReturnUnknownComparisonStateOnSettingLoadError(t *testing.T) { func TestSetManagedResourcesKnownOrphanedResourceExceptions(t *testing.T) { proj := defaultProj.DeepCopy() proj.Spec.OrphanedResources = &argoappv1.OrphanedResourcesMonitorSettings{} + proj.Spec.SourceNamespaces = []string{"default"} app := newFakeApp() app.Namespace = "default" diff --git a/controller/sync.go b/controller/sync.go index 1d839d094384c..34d57428c04a6 100644 --- a/controller/sync.go +++ b/controller/sync.go @@ -87,7 +87,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha revision = syncOp.Revision } - proj, err := argo.GetAppProject(&app.Spec, listersv1alpha1.NewAppProjectLister(m.projInformer.GetIndexer()), m.namespace, m.settingsMgr) + proj, err := argo.GetAppProject(app, listersv1alpha1.NewAppProjectLister(m.projInformer.GetIndexer()), m.namespace, m.settingsMgr) if err != nil { state.Phase = common.OperationError state.Message = fmt.Sprintf("Failed to load application project: %v", err) @@ -129,7 +129,7 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha atomic.AddUint64(&syncIdPrefix, 1) syncId := fmt.Sprintf("%05d-%s", syncIdPrefix, rand.RandString(5)) - logEntry := log.WithFields(log.Fields{"application": app.Name, "syncId": syncId}) + logEntry := log.WithFields(log.Fields{"application": app.QualifiedName(), "syncId": syncId}) initialResourcesRes := make([]common.ResourceSyncResult, 0) for i, res := range syncRes.Resources { key := kube.ResourceKey{Group: res.Group, Kind: res.Kind, Namespace: res.Namespace, Name: res.Name} diff --git a/docs/operator-manual/server-commands/argocd-util_app_generate-spec.md b/docs/operator-manual/server-commands/argocd-util_app_generate-spec.md index 762b61af92e6a..15ba35a124172 100644 --- a/docs/operator-manual/server-commands/argocd-util_app_generate-spec.md +++ b/docs/operator-manual/server-commands/argocd-util_app_generate-spec.md @@ -34,6 +34,7 @@ argocd-util app generate-spec APPNAME [flags] ``` --allow-empty Set allow zero live resources when sync is automated + --app-namespace string create application in given namespace instead of the default one --auto-prune Set automatic pruning when sync is automated --config-management-plugin string Config management plugin name --dest-name string K8s cluster Name (e.g. minikube) diff --git a/docs/user-guide/commands/argocd_app_create.md b/docs/user-guide/commands/argocd_app_create.md index 6039c991e516f..60f29095508bd 100644 --- a/docs/user-guide/commands/argocd_app_create.md +++ b/docs/user-guide/commands/argocd_app_create.md @@ -34,6 +34,7 @@ argocd app create APPNAME [flags] ``` --allow-empty Set allow zero live resources when sync is automated + --app-namespace string create application in given namespace instead of the default one --auto-prune Set automatic pruning when sync is automated --config-management-plugin string Config management plugin name --dest-name string K8s cluster Name (e.g. minikube) diff --git a/docs/user-guide/commands/argocd_app_list.md b/docs/user-guide/commands/argocd_app_list.md index 4559d073a9d1c..6fb7f22b60b1a 100644 --- a/docs/user-guide/commands/argocd_app_list.md +++ b/docs/user-guide/commands/argocd_app_list.md @@ -20,6 +20,7 @@ argocd app list [flags] ``` -h, --help help for list + -n, --namespace string List only apps in given namespace -o, --output string Output format. One of: wide|name|json|yaml (default "wide") -p, --project stringArray Filter by project name -r, --repo string List apps by source repo URL diff --git a/docs/user-guide/commands/argocd_app_set.md b/docs/user-guide/commands/argocd_app_set.md index 2d36deb6036a3..9965eb6c8fc51 100644 --- a/docs/user-guide/commands/argocd_app_set.md +++ b/docs/user-guide/commands/argocd_app_set.md @@ -10,6 +10,7 @@ argocd app set APPNAME [flags] ``` --allow-empty Set allow zero live resources when sync is automated + --app-namespace string create application in given namespace instead of the default one --auto-prune Set automatic pruning when sync is automated --config-management-plugin string Config management plugin name --dest-name string K8s cluster Name (e.g. minikube) diff --git a/manifests/crds/appproject-crd.yaml b/manifests/crds/appproject-crd.yaml index a048c656238d6..29c8ad918b057 100644 --- a/manifests/crds/appproject-crd.yaml +++ b/manifests/crds/appproject-crd.yaml @@ -221,6 +221,12 @@ spec: - keyID type: object type: array + sourceNamespaces: + description: SourceNamespaces contains list of allowed Application + namespaces + items: + type: string + type: array sourceRepos: description: SourceRepos contains list of repository URLs which can be used for deployment diff --git a/manifests/ha/install.yaml b/manifests/ha/install.yaml index 94312e7007ea5..0e8af1c059ace 100644 --- a/manifests/ha/install.yaml +++ b/manifests/ha/install.yaml @@ -2441,6 +2441,12 @@ spec: - keyID type: object type: array + sourceNamespaces: + description: SourceNamespaces contains list of allowed Application + namespaces + items: + type: string + type: array sourceRepos: description: SourceRepos contains list of repository URLs which can be used for deployment diff --git a/manifests/install.yaml b/manifests/install.yaml index 986246fbee0ec..7d9ba06e4f21c 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -2441,6 +2441,12 @@ spec: - keyID type: object type: array + sourceNamespaces: + description: SourceNamespaces contains list of allowed Application + namespaces + items: + type: string + type: array sourceRepos: description: SourceRepos contains list of repository URLs which can be used for deployment diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index 8a1f20c3e477e..ca388f526928c 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -5,6 +5,7 @@ API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/ap API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,AppProjectSpec,NamespaceResourceWhitelist API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,AppProjectSpec,Roles API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,AppProjectSpec,SignatureKeys +API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,AppProjectSpec,SourceNamespaces API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,AppProjectSpec,SourceRepos API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSourceHelm,FileParameters API rule violation: list_type_missing,github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1,ApplicationSourceHelm,Parameters diff --git a/pkg/apis/application/v1alpha1/app_project_types.go b/pkg/apis/application/v1alpha1/app_project_types.go index 3eefef42cf4ff..e7067ece0bd8a 100644 --- a/pkg/apis/application/v1alpha1/app_project_types.go +++ b/pkg/apis/application/v1alpha1/app_project_types.go @@ -361,6 +361,24 @@ func (proj AppProject) IsDestinationPermitted(dst ApplicationDestination) bool { return false } +// IsAppNamespacePermitted checks whether an application that associates with +// this AppProject is allowed by comparing the Application's namespace with +// the list of allowed namespaces in the AppProject. +func (proj AppProject) IsAppNamespacePermitted(app *Application, controllerNs string) bool { + // Applications in the installation namespace are always permitted + // At Application creation time, its namespace may yet be empty to indicate + // that is will be created in the controller's namespace. + if app.Namespace == "" || app.Namespace == controllerNs { + return true + } + for _, ns := range proj.Spec.SourceNamespaces { + if ns == app.Namespace { + return true + } + } + return false +} + // TODO: document this method func (proj *AppProject) NormalizeJWTTokens() bool { needNormalize := false diff --git a/pkg/apis/application/v1alpha1/generated.pb.go b/pkg/apis/application/v1alpha1/generated.pb.go index 5000c20a1a256..80ab9244ee812 100644 --- a/pkg/apis/application/v1alpha1/generated.pb.go +++ b/pkg/apis/application/v1alpha1/generated.pb.go @@ -2631,421 +2631,423 @@ func init() { } var fileDescriptor_030104ce3b95bcac = []byte{ - // 6622 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3d, 0x5b, 0x6c, 0x24, 0xd9, - 0x55, 0x5b, 0xdd, 0x7e, 0x74, 0x1f, 0x3f, 0x66, 0x7c, 0xe7, 0xb1, 0xce, 0xb0, 0x19, 0x8f, 0x6a, - 0x95, 0x64, 0x21, 0x89, 0xcd, 0x0e, 0x4b, 0x58, 0xb2, 0x21, 0xc1, 0x6d, 0xcf, 0xc3, 0x33, 0x9e, - 0x19, 0xef, 0xb1, 0x67, 0x86, 0x3c, 0x08, 0x5b, 0xae, 0xbe, 0xdd, 0xae, 0x71, 0x77, 0x55, 0x6f, - 0x55, 0xb5, 0xc7, 0x9d, 0x90, 0x17, 0x0a, 0x64, 0x45, 0x1e, 0x1b, 0x25, 0xf9, 0x48, 0x24, 0x04, - 0xe1, 0x21, 0x24, 0x3e, 0x22, 0xe0, 0x0b, 0x10, 0xf0, 0x93, 0xaf, 0x00, 0x12, 0x44, 0x02, 0x25, - 0x81, 0x08, 0x93, 0x0c, 0x41, 0x3c, 0x24, 0x40, 0x40, 0x7e, 0x98, 0x2f, 0x74, 0xdf, 0xb7, 0xaa, - 0xbb, 0xc7, 0xf6, 0xb8, 0x66, 0x12, 0x45, 0xfc, 0x75, 0x9d, 0x73, 0xee, 0x39, 0xe7, 0xbe, 0xce, - 0x3d, 0xf7, 0xdc, 0x73, 0x6f, 0xc3, 0x6a, 0x33, 0x48, 0xb7, 0xba, 0x9b, 0xf3, 0x7e, 0xd4, 0x5e, - 0xf0, 0xe2, 0x66, 0xd4, 0x89, 0xa3, 0x3b, 0xfc, 0xc7, 0x9b, 0xfd, 0xfa, 0xc2, 0xce, 0xf9, 0x85, - 0xce, 0x76, 0x73, 0xc1, 0xeb, 0x04, 0xc9, 0x82, 0xd7, 0xe9, 0xb4, 0x02, 0xdf, 0x4b, 0x83, 0x28, - 0x5c, 0xd8, 0x79, 0xd6, 0x6b, 0x75, 0xb6, 0xbc, 0x67, 0x17, 0x9a, 0x34, 0xa4, 0xb1, 0x97, 0xd2, - 0xfa, 0x7c, 0x27, 0x8e, 0xd2, 0x88, 0xbc, 0xcd, 0x70, 0x9b, 0x57, 0xdc, 0xf8, 0x8f, 0x9f, 0xf3, - 0xeb, 0xf3, 0x3b, 0xe7, 0xe7, 0x3b, 0xdb, 0xcd, 0x79, 0xc6, 0x6d, 0xde, 0xe2, 0x36, 0xaf, 0xb8, - 0x9d, 0x79, 0xb3, 0xa5, 0x4b, 0x33, 0x6a, 0x46, 0x0b, 0x9c, 0xe9, 0x66, 0xb7, 0xc1, 0xbf, 0xf8, - 0x07, 0xff, 0x25, 0x84, 0x9d, 0x71, 0xb7, 0x9f, 0x4f, 0xe6, 0x83, 0x88, 0xa9, 0xb7, 0xe0, 0x47, - 0x31, 0x5d, 0xd8, 0xe9, 0x53, 0xe8, 0xcc, 0x73, 0x86, 0xa6, 0xed, 0xf9, 0x5b, 0x41, 0x48, 0xe3, - 0x9e, 0xa9, 0x53, 0x9b, 0xa6, 0xde, 0xa0, 0x52, 0x0b, 0xc3, 0x4a, 0xc5, 0xdd, 0x30, 0x0d, 0xda, - 0xb4, 0xaf, 0xc0, 0x5b, 0xf6, 0x2b, 0x90, 0xf8, 0x5b, 0xb4, 0xed, 0xe5, 0xcb, 0xb9, 0x2f, 0xc3, - 0xd4, 0xe2, 0xed, 0xf5, 0xc5, 0x6e, 0xba, 0xb5, 0x14, 0x85, 0x8d, 0xa0, 0x49, 0x7e, 0x1c, 0x26, - 0xfc, 0x56, 0x37, 0x49, 0x69, 0x7c, 0xdd, 0x6b, 0xd3, 0x59, 0xe7, 0x9c, 0xf3, 0x4c, 0xb5, 0x76, - 0xe2, 0x2b, 0x7b, 0x73, 0x4f, 0xdc, 0xdb, 0x9b, 0x9b, 0x58, 0x32, 0x28, 0xb4, 0xe9, 0xc8, 0x0f, - 0xc3, 0x78, 0x1c, 0xb5, 0xe8, 0x22, 0x5e, 0x9f, 0x2d, 0xf1, 0x22, 0xc7, 0x64, 0x91, 0x71, 0x14, - 0x60, 0x54, 0x78, 0xf7, 0x6b, 0x25, 0x80, 0xc5, 0x4e, 0x67, 0x2d, 0x8e, 0xee, 0x50, 0x3f, 0x25, - 0x2f, 0x41, 0x85, 0xb5, 0x42, 0xdd, 0x4b, 0x3d, 0x2e, 0x6d, 0xe2, 0xfc, 0x8f, 0xce, 0x8b, 0xca, - 0xcc, 0xdb, 0x95, 0x31, 0x3d, 0xc7, 0xa8, 0xe7, 0x77, 0x9e, 0x9d, 0xbf, 0xb1, 0xc9, 0xca, 0x5f, - 0xa3, 0xa9, 0x57, 0x23, 0x52, 0x18, 0x18, 0x18, 0x6a, 0xae, 0x24, 0x84, 0x91, 0xa4, 0x43, 0x7d, - 0xae, 0xd8, 0xc4, 0xf9, 0xd5, 0xf9, 0xa3, 0x0c, 0x91, 0x79, 0xa3, 0xf9, 0x7a, 0x87, 0xfa, 0xb5, - 0x49, 0x29, 0x79, 0x84, 0x7d, 0x21, 0x97, 0x43, 0x76, 0x60, 0x2c, 0x49, 0xbd, 0xb4, 0x9b, 0xcc, - 0x96, 0xb9, 0xc4, 0xeb, 0x85, 0x49, 0xe4, 0x5c, 0x6b, 0xd3, 0x52, 0xe6, 0x98, 0xf8, 0x46, 0x29, - 0xcd, 0xfd, 0x7b, 0x07, 0xa6, 0x0d, 0xf1, 0x6a, 0x90, 0xa4, 0xe4, 0x3d, 0x7d, 0x8d, 0x3b, 0x7f, - 0xb0, 0xc6, 0x65, 0xa5, 0x79, 0xd3, 0x1e, 0x97, 0xc2, 0x2a, 0x0a, 0x62, 0x35, 0x6c, 0x1b, 0x46, - 0x83, 0x94, 0xb6, 0x93, 0xd9, 0xd2, 0xb9, 0xf2, 0x33, 0x13, 0xe7, 0x2f, 0x17, 0x55, 0xcf, 0xda, - 0x94, 0x14, 0x3a, 0xba, 0xc2, 0xd8, 0xa3, 0x90, 0xe2, 0x7e, 0x17, 0xec, 0xfa, 0xb1, 0x06, 0x27, - 0xcf, 0xc2, 0x44, 0x12, 0x75, 0x63, 0x9f, 0x22, 0xed, 0x44, 0xc9, 0xac, 0x73, 0xae, 0xcc, 0x86, - 0x1e, 0x1b, 0xa9, 0xeb, 0x06, 0x8c, 0x36, 0x0d, 0xf9, 0x94, 0x03, 0x93, 0x75, 0x9a, 0xa4, 0x41, - 0xc8, 0xe5, 0x2b, 0xe5, 0x37, 0x8e, 0xac, 0xbc, 0x02, 0x2e, 0x1b, 0xe6, 0xb5, 0x93, 0xb2, 0x22, - 0x93, 0x16, 0x30, 0xc1, 0x8c, 0x7c, 0x36, 0xe3, 0xea, 0x34, 0xf1, 0xe3, 0xa0, 0xc3, 0xbe, 0xf9, - 0x98, 0xb1, 0x66, 0xdc, 0xb2, 0x41, 0xa1, 0x4d, 0x47, 0x42, 0x18, 0x65, 0x33, 0x2a, 0x99, 0x1d, - 0xe1, 0xfa, 0xaf, 0x1c, 0x4d, 0x7f, 0xd9, 0xa8, 0x6c, 0xb2, 0x9a, 0xd6, 0x67, 0x5f, 0x09, 0x0a, - 0x31, 0xe4, 0x93, 0x0e, 0xcc, 0xca, 0x19, 0x8f, 0x54, 0x34, 0xe8, 0xed, 0xad, 0x20, 0xa5, 0xad, - 0x20, 0x49, 0x67, 0x47, 0xb9, 0x0e, 0x0b, 0x07, 0x1b, 0x5b, 0x97, 0xe2, 0xa8, 0xdb, 0xb9, 0x1a, - 0x84, 0xf5, 0xda, 0x39, 0x29, 0x69, 0x76, 0x69, 0x08, 0x63, 0x1c, 0x2a, 0x92, 0x7c, 0xd6, 0x81, - 0x33, 0xa1, 0xd7, 0xa6, 0x49, 0xc7, 0x63, 0x5d, 0x2b, 0xd0, 0xb5, 0x96, 0xe7, 0x6f, 0x73, 0x8d, - 0xc6, 0x1e, 0x4e, 0x23, 0x57, 0x6a, 0x74, 0xe6, 0xfa, 0x50, 0xd6, 0xf8, 0x00, 0xb1, 0xe4, 0x37, - 0x1d, 0x98, 0x89, 0xe2, 0xce, 0x96, 0x17, 0xd2, 0xba, 0xc2, 0x26, 0xb3, 0xe3, 0x7c, 0xea, 0xbd, - 0xf7, 0x68, 0x5d, 0x74, 0x23, 0xcf, 0xf6, 0x5a, 0x14, 0x06, 0x69, 0x14, 0xaf, 0xd3, 0x34, 0x0d, - 0xc2, 0x66, 0x52, 0x3b, 0x75, 0x6f, 0x6f, 0x6e, 0xa6, 0x8f, 0x0a, 0xfb, 0xf5, 0x21, 0xef, 0x87, - 0x89, 0xa4, 0x17, 0xfa, 0xb7, 0x83, 0xb0, 0x1e, 0xdd, 0x4d, 0x66, 0x2b, 0x45, 0x4c, 0xdf, 0x75, - 0xcd, 0x50, 0x4e, 0x40, 0x23, 0x00, 0x6d, 0x69, 0x83, 0x3b, 0xce, 0x0c, 0xa5, 0x6a, 0xd1, 0x1d, - 0x67, 0x06, 0xd3, 0x03, 0xc4, 0x92, 0x8f, 0x39, 0x30, 0x95, 0x04, 0xcd, 0xd0, 0x4b, 0xbb, 0x31, - 0xbd, 0x4a, 0x7b, 0xc9, 0x2c, 0x70, 0x45, 0xae, 0x1c, 0xb1, 0x55, 0x2c, 0x96, 0xb5, 0x53, 0x52, - 0xc7, 0x29, 0x1b, 0x9a, 0x60, 0x56, 0xee, 0xa0, 0x89, 0x66, 0x86, 0xf5, 0x44, 0xb1, 0x13, 0xcd, - 0x0c, 0xea, 0xa1, 0x22, 0xdd, 0x3f, 0x2b, 0xc1, 0xf1, 0xfc, 0x1a, 0x44, 0x7e, 0xdb, 0x81, 0x63, - 0x77, 0xee, 0xa6, 0x1b, 0xd1, 0x36, 0x0d, 0x93, 0x5a, 0x8f, 0x59, 0x0a, 0x6e, 0x7d, 0x27, 0xce, - 0xfb, 0xc5, 0xae, 0x76, 0xf3, 0x57, 0xb2, 0x52, 0x2e, 0x84, 0x69, 0xdc, 0xab, 0x3d, 0x29, 0xeb, - 0x73, 0xec, 0xca, 0xed, 0x0d, 0x1b, 0x8b, 0x79, 0xa5, 0xce, 0x7c, 0xdc, 0x81, 0x93, 0x83, 0x58, - 0x90, 0xe3, 0x50, 0xde, 0xa6, 0x3d, 0xe1, 0xe0, 0x20, 0xfb, 0x49, 0x7e, 0x16, 0x46, 0x77, 0xbc, - 0x56, 0x97, 0x4a, 0x47, 0xe1, 0xd2, 0xd1, 0x2a, 0xa2, 0x35, 0x43, 0xc1, 0xf5, 0xad, 0xa5, 0xe7, - 0x1d, 0xf7, 0xaf, 0xca, 0x30, 0x61, 0x2d, 0x15, 0x8f, 0xc1, 0xf9, 0x89, 0x32, 0xce, 0xcf, 0xb5, - 0xc2, 0x56, 0xb9, 0xa1, 0xde, 0xcf, 0xdd, 0x9c, 0xf7, 0x73, 0xa3, 0x38, 0x91, 0x0f, 0x74, 0x7f, - 0x48, 0x0a, 0xd5, 0xa8, 0xc3, 0x9c, 0x5b, 0xb6, 0x8a, 0x8e, 0x14, 0xd1, 0x85, 0x37, 0x14, 0xbb, - 0xda, 0xd4, 0xbd, 0xbd, 0xb9, 0xaa, 0xfe, 0x44, 0x23, 0xc8, 0xfd, 0xba, 0x03, 0x27, 0x2d, 0x1d, - 0x97, 0xa2, 0xb0, 0x1e, 0xf0, 0xae, 0x3d, 0x07, 0x23, 0x69, 0xaf, 0xa3, 0x3c, 0x68, 0xdd, 0x52, - 0x1b, 0xbd, 0x0e, 0x45, 0x8e, 0x61, 0x3e, 0x73, 0x9b, 0x26, 0x89, 0xd7, 0xa4, 0x79, 0x9f, 0xf9, - 0x9a, 0x00, 0xa3, 0xc2, 0x93, 0x18, 0x48, 0xcb, 0x4b, 0xd2, 0x8d, 0xd8, 0x0b, 0x13, 0xce, 0x7e, - 0x23, 0x68, 0x53, 0xd9, 0xc0, 0x3f, 0x72, 0xb0, 0x11, 0xc3, 0x4a, 0xd4, 0x4e, 0xdf, 0xdb, 0x9b, - 0x23, 0xab, 0x7d, 0x9c, 0x70, 0x00, 0x77, 0xf7, 0xb3, 0x0e, 0x9c, 0x1e, 0xec, 0xd6, 0x90, 0xd7, - 0xc3, 0x58, 0x42, 0xe3, 0x1d, 0x1a, 0xcb, 0xda, 0x99, 0x2e, 0xe1, 0x50, 0x94, 0x58, 0xb2, 0x00, - 0x55, 0x6d, 0x72, 0x65, 0x1d, 0x67, 0x24, 0x69, 0xd5, 0xd8, 0x69, 0x43, 0xc3, 0x1a, 0x8d, 0x7d, - 0x48, 0x27, 0x48, 0x37, 0x1a, 0xdf, 0x6f, 0x70, 0x8c, 0xfb, 0x0f, 0x0e, 0x1c, 0xb3, 0xb4, 0x7a, - 0x0c, 0x5e, 0x6e, 0x98, 0xf5, 0x72, 0x57, 0x0a, 0x1b, 0xcf, 0x43, 0xdc, 0xdc, 0x2f, 0x8f, 0xc1, - 0x8c, 0x3d, 0xea, 0xb9, 0x39, 0xe6, 0x1b, 0x2c, 0xda, 0x89, 0x6e, 0xe2, 0xaa, 0x6c, 0x73, 0xb3, - 0xc1, 0x12, 0x60, 0x54, 0x78, 0xd6, 0x88, 0x1d, 0x2f, 0xdd, 0x92, 0x0d, 0xae, 0x1b, 0x71, 0xcd, - 0x4b, 0xb7, 0x90, 0x63, 0xc8, 0xdb, 0x61, 0x3a, 0xf5, 0xe2, 0x26, 0x4d, 0x91, 0xee, 0x04, 0x89, - 0x9a, 0x2f, 0xd5, 0xda, 0x69, 0x49, 0x3b, 0xbd, 0x91, 0xc1, 0x62, 0x8e, 0x9a, 0xbc, 0x0c, 0x23, - 0x5b, 0xb4, 0xd5, 0x96, 0x7e, 0xcd, 0x7a, 0x71, 0x33, 0x9c, 0xd7, 0xf5, 0x32, 0x6d, 0xb5, 0x6b, - 0x15, 0xa6, 0x32, 0xfb, 0x85, 0x5c, 0x14, 0xf9, 0x45, 0x07, 0xaa, 0xdb, 0xdd, 0x24, 0x8d, 0xda, - 0xc1, 0xfb, 0xe8, 0x6c, 0x85, 0x0b, 0xfe, 0x99, 0x82, 0x05, 0x5f, 0x55, 0xfc, 0xc5, 0x7c, 0xd7, - 0x9f, 0x68, 0x24, 0x93, 0x0f, 0xc0, 0xf8, 0x76, 0x12, 0x85, 0x21, 0x65, 0x9e, 0x0a, 0x53, 0xe2, - 0x56, 0xd1, 0x4a, 0x08, 0xee, 0xb5, 0x09, 0xd6, 0xb7, 0xf2, 0x03, 0x95, 0x4c, 0xde, 0x0c, 0xf5, - 0x20, 0xa6, 0x7e, 0x1a, 0xc5, 0xbd, 0x59, 0x78, 0x24, 0xcd, 0xb0, 0xac, 0xf8, 0x8b, 0x66, 0xd0, - 0x9f, 0x68, 0x24, 0x93, 0x1e, 0x8c, 0x75, 0x5a, 0xdd, 0x66, 0x10, 0xce, 0x4e, 0x70, 0x1d, 0x6e, - 0x16, 0xac, 0xc3, 0x1a, 0x67, 0x5e, 0x03, 0x66, 0x54, 0xc4, 0x6f, 0x94, 0x02, 0xc9, 0xd3, 0x30, - 0xea, 0x6f, 0x79, 0x71, 0x3a, 0x3b, 0xc9, 0xc7, 0xac, 0x9e, 0x44, 0x4b, 0x0c, 0x88, 0x02, 0xe7, - 0xfe, 0x7a, 0x09, 0xce, 0x0c, 0xaf, 0x98, 0x98, 0x4d, 0x7e, 0x37, 0x4e, 0x84, 0x7d, 0xae, 0xd8, - 0xb3, 0x89, 0x83, 0x51, 0xe1, 0xc9, 0x47, 0x1c, 0x18, 0xbf, 0x23, 0x7b, 0xbc, 0xf4, 0x48, 0x7a, - 0xfc, 0x8a, 0xec, 0x71, 0xad, 0xc3, 0x15, 0xd5, 0xeb, 0x52, 0x2e, 0x53, 0x97, 0xee, 0xfa, 0xad, - 0x6e, 0x5d, 0x59, 0x46, 0x4d, 0x7a, 0x41, 0x80, 0x51, 0xe1, 0x19, 0x69, 0x10, 0x0a, 0xd2, 0x91, - 0x2c, 0xe9, 0x4a, 0x28, 0x49, 0x25, 0xde, 0xfd, 0x4e, 0x19, 0x4e, 0x0d, 0x9c, 0x7c, 0x64, 0x1e, - 0x80, 0xfb, 0x2c, 0x17, 0x03, 0xb6, 0xc1, 0x14, 0xbb, 0xea, 0x69, 0xe6, 0x62, 0xdc, 0xd2, 0x50, - 0xb4, 0x28, 0xc8, 0x87, 0x00, 0x3a, 0x5e, 0xec, 0xb5, 0x69, 0x4a, 0x63, 0x65, 0x27, 0xaf, 0x1e, - 0xad, 0x95, 0x98, 0x1e, 0x6b, 0x8a, 0xa7, 0xf1, 0x71, 0x34, 0x28, 0x41, 0x4b, 0x24, 0xdb, 0x43, - 0xc7, 0xb4, 0x45, 0xbd, 0x84, 0x5e, 0x37, 0xcb, 0x87, 0xde, 0x43, 0xa3, 0x41, 0xa1, 0x4d, 0xc7, - 0xd6, 0x31, 0x5e, 0x8b, 0x44, 0xb6, 0x95, 0x5e, 0xc7, 0x78, 0x3d, 0x13, 0x94, 0x58, 0xf2, 0xaa, - 0x03, 0xd3, 0x8d, 0xa0, 0x45, 0x8d, 0x74, 0xb9, 0xe3, 0xbd, 0x71, 0xf4, 0x4a, 0x5e, 0xb4, 0xf9, - 0x1a, 0x0b, 0x9c, 0x01, 0x27, 0x98, 0x13, 0xcf, 0xba, 0x79, 0x87, 0xc6, 0xdc, 0x74, 0x8f, 0x65, - 0xbb, 0xf9, 0x96, 0x00, 0xa3, 0xc2, 0xbb, 0x5f, 0x28, 0xc1, 0xec, 0xb0, 0x31, 0x47, 0x12, 0x36, - 0xb2, 0xd2, 0x5b, 0x5e, 0x9c, 0x48, 0xf7, 0xfd, 0x88, 0xbb, 0x40, 0xc9, 0xf7, 0x96, 0x17, 0xdb, - 0x63, 0x94, 0x0b, 0x40, 0x25, 0x89, 0xdc, 0x81, 0x91, 0xb4, 0xe5, 0x15, 0x14, 0x36, 0xb2, 0x24, - 0x1a, 0x27, 0x6b, 0x75, 0x31, 0x41, 0x2e, 0x83, 0x3c, 0x05, 0x23, 0xad, 0x60, 0x93, 0x39, 0xa3, - 0x6c, 0x10, 0xf3, 0x55, 0x65, 0x35, 0xd8, 0x4c, 0x90, 0x43, 0xdd, 0xaf, 0x39, 0x03, 0xda, 0x46, - 0x1a, 0x5d, 0x36, 0xa8, 0x68, 0xb8, 0x13, 0xc4, 0x51, 0xd8, 0xa6, 0x61, 0x9a, 0x0f, 0x85, 0x5e, - 0x30, 0x28, 0xb4, 0xe9, 0xc8, 0x2f, 0x38, 0x03, 0x66, 0xc3, 0x11, 0x63, 0x80, 0x52, 0xa5, 0x03, - 0x4f, 0x08, 0xf7, 0x3f, 0xc7, 0x06, 0xd8, 0x3f, 0xbd, 0xa0, 0x91, 0xf3, 0x00, 0xcc, 0x9b, 0x5a, - 0x8b, 0x69, 0x23, 0xd8, 0x95, 0x35, 0xd3, 0x2c, 0xaf, 0x6b, 0x0c, 0x5a, 0x54, 0xaa, 0xcc, 0x7a, - 0xb7, 0xc1, 0xca, 0x94, 0xfa, 0xcb, 0x08, 0x0c, 0x5a, 0x54, 0xe4, 0x39, 0x18, 0x0b, 0xda, 0x5e, - 0x93, 0xaa, 0xf6, 0x7f, 0x8a, 0x4d, 0xae, 0x15, 0x0e, 0xb9, 0xbf, 0x37, 0x37, 0xad, 0x15, 0xe2, - 0x20, 0x94, 0xb4, 0xe4, 0xb7, 0x1c, 0x98, 0xf4, 0xa3, 0x76, 0x3b, 0x0a, 0x57, 0xbd, 0x4d, 0xda, - 0x52, 0x21, 0xae, 0x3b, 0x8f, 0x6a, 0xb9, 0x9f, 0x5f, 0xb2, 0x84, 0x89, 0x0d, 0xa6, 0x0e, 0xdc, - 0xd9, 0x28, 0xcc, 0x68, 0x65, 0xcf, 0xc1, 0xd1, 0x07, 0xcf, 0x41, 0xf2, 0x87, 0x0e, 0xcc, 0x88, - 0xb2, 0x8b, 0x61, 0x18, 0xa5, 0x32, 0xf2, 0x28, 0x62, 0x54, 0xd1, 0x23, 0xae, 0x96, 0x25, 0x51, - 0xd4, 0xed, 0x35, 0x52, 0xcd, 0x99, 0x3e, 0x3c, 0xf6, 0x2b, 0x49, 0x2e, 0xc1, 0x4c, 0x23, 0x8a, - 0x7d, 0x6a, 0x37, 0x04, 0x77, 0xfc, 0x2a, 0x86, 0xd1, 0xc5, 0x3c, 0x01, 0xf6, 0x97, 0x21, 0xb7, - 0xe0, 0xb4, 0x05, 0xb4, 0xdb, 0xa1, 0xc2, 0xb9, 0x9d, 0x95, 0xdc, 0x4e, 0x5f, 0x1c, 0x48, 0x85, - 0x43, 0x4a, 0x9f, 0x79, 0x07, 0xcc, 0xf4, 0xf5, 0xdf, 0x80, 0xdd, 0xfd, 0x49, 0x7b, 0x77, 0x5f, - 0xb5, 0x36, 0xe5, 0x67, 0x96, 0xe1, 0xf4, 0xe0, 0x96, 0x3a, 0x0c, 0x17, 0xf7, 0x57, 0x1d, 0x78, - 0x72, 0x88, 0x1b, 0xa3, 0xb7, 0x35, 0xce, 0xb0, 0x6d, 0x0d, 0xf1, 0xa0, 0x4c, 0xc3, 0x1d, 0x69, - 0x2c, 0x2e, 0x1e, 0x6d, 0x44, 0x5c, 0x08, 0x77, 0x44, 0x47, 0x8f, 0xdf, 0xdb, 0x9b, 0x2b, 0x5f, - 0x08, 0x77, 0x90, 0xf1, 0x76, 0x3f, 0x37, 0x96, 0xd9, 0x39, 0xad, 0xab, 0xcd, 0x3a, 0x57, 0x54, - 0xee, 0x9b, 0x6e, 0x14, 0x3c, 0x16, 0xad, 0x9d, 0xa1, 0x08, 0xc1, 0x4b, 0x71, 0xe4, 0xe3, 0x0e, - 0x8f, 0x7a, 0xab, 0x1d, 0xa5, 0xf4, 0xac, 0x1e, 0x4d, 0x10, 0xde, 0x8e, 0xa5, 0x2b, 0x20, 0xda, - 0xd2, 0xd9, 0x4c, 0xee, 0x88, 0xa0, 0x53, 0xde, 0xbf, 0x52, 0x71, 0x71, 0x85, 0x27, 0xbb, 0x00, - 0x49, 0x2f, 0xf4, 0xd7, 0xa2, 0x56, 0xe0, 0xf7, 0x64, 0x98, 0xa1, 0x80, 0xc8, 0xa9, 0xe0, 0x27, - 0x9c, 0x2c, 0xf3, 0x8d, 0x96, 0x2c, 0xf2, 0x45, 0x07, 0x66, 0x82, 0x66, 0x18, 0xc5, 0x74, 0x39, - 0x68, 0x34, 0x68, 0x4c, 0x43, 0x9f, 0x2a, 0x3f, 0xe4, 0xf6, 0xd1, 0x34, 0x50, 0x41, 0xbf, 0x95, - 0x3c, 0x7b, 0x33, 0xc5, 0xfb, 0x50, 0xd8, 0xaf, 0x0c, 0xa9, 0xc3, 0x48, 0x10, 0x36, 0x22, 0x69, - 0xd8, 0x6a, 0x47, 0x53, 0x6a, 0x25, 0x6c, 0x44, 0x66, 0xae, 0xb0, 0x2f, 0xe4, 0xdc, 0xc9, 0x2a, - 0x9c, 0x8c, 0xe5, 0x4e, 0xf4, 0x72, 0x90, 0x30, 0x7f, 0x7e, 0x35, 0x68, 0x07, 0x29, 0x37, 0x4a, - 0xe5, 0xda, 0xec, 0xbd, 0xbd, 0xb9, 0x93, 0x38, 0x00, 0x8f, 0x03, 0x4b, 0xb9, 0xaf, 0x54, 0xb3, - 0xdb, 0x6d, 0x11, 0x4c, 0xfa, 0x00, 0x54, 0x63, 0x1d, 0xbe, 0x17, 0x9e, 0xd1, 0x6a, 0x31, 0x6d, - 0x2c, 0xa3, 0x58, 0x3a, 0x0e, 0x62, 0x02, 0xf5, 0x46, 0x22, 0xf3, 0x90, 0x58, 0xcf, 0xcb, 0x69, - 0x51, 0xc0, 0xf8, 0x92, 0x52, 0x4d, 0xc0, 0xae, 0x17, 0xfa, 0xc8, 0x65, 0x90, 0x18, 0xc6, 0xb6, - 0xa8, 0xd7, 0x4a, 0xb7, 0x64, 0x3c, 0xe9, 0xca, 0x51, 0x7d, 0x5a, 0xc6, 0x2b, 0x1f, 0xab, 0x13, - 0x50, 0x94, 0x92, 0xc8, 0x2e, 0x8c, 0x6f, 0x89, 0x4e, 0x90, 0x6b, 0xfb, 0xb5, 0xa3, 0x36, 0x6e, - 0xa6, 0x67, 0xcd, 0xfc, 0x95, 0x00, 0x54, 0xe2, 0xc8, 0x2f, 0x39, 0x00, 0xbe, 0x0a, 0xd2, 0xa9, - 0xe9, 0x83, 0x85, 0xd9, 0x1d, 0x1d, 0xff, 0x33, 0xae, 0x91, 0x06, 0x25, 0x68, 0x49, 0x26, 0x2f, - 0xc1, 0x64, 0x4c, 0xfd, 0x28, 0xf4, 0x83, 0x16, 0xad, 0x2f, 0xa6, 0xdc, 0x8d, 0x3f, 0x5c, 0x30, - 0xef, 0x38, 0xf3, 0x4f, 0xd0, 0xe2, 0x81, 0x19, 0x8e, 0xe4, 0x15, 0x07, 0xa6, 0x75, 0xa0, 0x92, - 0x75, 0x08, 0x95, 0x01, 0x9b, 0xd5, 0x82, 0xc2, 0xa2, 0x9c, 0x67, 0x8d, 0xb0, 0xed, 0x4a, 0x16, - 0x86, 0x39, 0xb9, 0xe4, 0x5d, 0x00, 0xd1, 0x26, 0x0f, 0x0a, 0xb2, 0xaa, 0x56, 0x0e, 0x5d, 0xd5, - 0x69, 0x11, 0xdf, 0x56, 0x1c, 0xd0, 0xe2, 0x46, 0xae, 0x02, 0x88, 0x69, 0xb3, 0xd1, 0xeb, 0x50, - 0x1e, 0x94, 0xa9, 0xd6, 0xde, 0xa8, 0x1a, 0x7f, 0x5d, 0x63, 0xee, 0xef, 0xcd, 0xf5, 0xef, 0x76, - 0x79, 0x34, 0xd6, 0x2a, 0x4e, 0xde, 0x0f, 0xe3, 0x49, 0xb7, 0xdd, 0xf6, 0x74, 0x70, 0x65, 0xad, - 0xb8, 0x15, 0x51, 0xf0, 0x35, 0x63, 0x53, 0x02, 0x50, 0x49, 0x74, 0x43, 0x20, 0xfd, 0xf4, 0xe4, - 0x39, 0x98, 0xa4, 0xbb, 0x29, 0x8d, 0x43, 0xaf, 0x75, 0x13, 0x57, 0xd5, 0x76, 0x9c, 0x77, 0xfe, - 0x05, 0x0b, 0x8e, 0x19, 0x2a, 0xe2, 0x6a, 0xcf, 0xbb, 0xc4, 0xe9, 0xc1, 0x78, 0xde, 0xca, 0xcf, - 0x76, 0xff, 0xb7, 0x94, 0xf1, 0x08, 0x36, 0x62, 0x4a, 0x49, 0x04, 0xa3, 0x61, 0x54, 0xd7, 0x46, - 0xef, 0x4a, 0x31, 0x46, 0xef, 0x7a, 0x54, 0xb7, 0xce, 0x95, 0xd9, 0x57, 0x82, 0x42, 0x0e, 0x3f, - 0x78, 0x53, 0x27, 0x94, 0x1c, 0x21, 0x9d, 0xa0, 0x22, 0x25, 0xeb, 0x83, 0xb7, 0x1b, 0xb6, 0x20, - 0xcc, 0xca, 0x25, 0xdb, 0x30, 0xba, 0x15, 0x25, 0xa9, 0xd8, 0xab, 0x1c, 0xd9, 0x0b, 0xbb, 0x1c, - 0x25, 0x29, 0x5f, 0xc2, 0x74, 0xb5, 0x19, 0x24, 0x41, 0x21, 0xc3, 0xfd, 0x67, 0x27, 0x13, 0x7c, - 0xb9, 0xed, 0xa5, 0xfe, 0xd6, 0x85, 0x1d, 0xb6, 0x7f, 0xbc, 0x9a, 0x39, 0x38, 0xf8, 0x09, 0xfb, - 0xe0, 0xe0, 0xfe, 0xde, 0xdc, 0x1b, 0x86, 0x25, 0xfa, 0xdc, 0x65, 0x1c, 0xe6, 0x39, 0x0b, 0xeb, - 0x8c, 0xe1, 0xc3, 0x0e, 0x4c, 0x58, 0xea, 0xc9, 0x05, 0xa5, 0xc0, 0x18, 0xb6, 0x76, 0xae, 0x2c, - 0x20, 0xda, 0x22, 0xdd, 0xcf, 0x38, 0x30, 0x5e, 0xf3, 0xfc, 0xed, 0xa8, 0xd1, 0x20, 0x6f, 0x82, - 0x4a, 0xbd, 0x2b, 0x8f, 0x68, 0x44, 0xfd, 0x74, 0xe4, 0x7d, 0x59, 0xc2, 0x51, 0x53, 0xb0, 0x31, - 0xdc, 0xf0, 0xfc, 0x34, 0x8a, 0xb9, 0xda, 0x65, 0x31, 0x86, 0x2f, 0x72, 0x08, 0x4a, 0x0c, 0xdb, - 0xa4, 0xb7, 0xbd, 0x5d, 0x55, 0x38, 0x1f, 0xf9, 0xb9, 0x66, 0x50, 0x68, 0xd3, 0xb9, 0x7f, 0x3e, - 0x0a, 0xe3, 0xf2, 0x2c, 0xf4, 0xc0, 0xa7, 0x19, 0xca, 0x8b, 0x2f, 0x0d, 0xf5, 0xe2, 0x13, 0x18, - 0xf3, 0x79, 0x1a, 0x95, 0x5c, 0x4a, 0x8f, 0x18, 0x03, 0x93, 0x0a, 0x8a, 0xcc, 0x2c, 0xa3, 0x96, - 0xf8, 0x46, 0x29, 0x8a, 0x7c, 0xda, 0x81, 0x63, 0x7e, 0x14, 0x86, 0xd4, 0x37, 0x76, 0x7e, 0xa4, - 0x88, 0xd3, 0xbe, 0xa5, 0x2c, 0x53, 0x73, 0xe8, 0x9a, 0x43, 0x60, 0x5e, 0x3c, 0x79, 0x01, 0xa6, - 0x44, 0x9b, 0xdd, 0xca, 0xec, 0x8f, 0xcd, 0xf9, 0xb7, 0x8d, 0xc4, 0x2c, 0x2d, 0x99, 0x17, 0x71, - 0x06, 0x7e, 0x20, 0x24, 0xf6, 0xc8, 0x32, 0xf8, 0xa8, 0x4f, 0x8c, 0x12, 0xb4, 0x28, 0x48, 0x0c, - 0x24, 0xa6, 0x8d, 0x98, 0x26, 0x5b, 0x48, 0x5f, 0xee, 0xd2, 0x24, 0xe5, 0x6b, 0xcc, 0xf8, 0xc3, - 0x9d, 0x8d, 0x61, 0x1f, 0x27, 0x1c, 0xc0, 0x9d, 0x6c, 0x4b, 0x47, 0xb7, 0x52, 0xc4, 0x74, 0x92, - 0xdd, 0x3c, 0xd4, 0xdf, 0x9d, 0x83, 0xd1, 0x64, 0xcb, 0x8b, 0xeb, 0x7c, 0x6d, 0x2b, 0xd7, 0xaa, - 0xcc, 0x96, 0xac, 0x33, 0x00, 0x0a, 0xb8, 0xfb, 0x5d, 0x07, 0x8e, 0xab, 0xb1, 0xe2, 0xf9, 0x5b, - 0x94, 0x95, 0x25, 0x6f, 0x87, 0x69, 0xed, 0x4f, 0x2e, 0x45, 0x5d, 0x19, 0xc0, 0x2a, 0x9b, 0x08, - 0x23, 0x66, 0xb0, 0x98, 0xa3, 0x26, 0x0b, 0x50, 0x65, 0x2a, 0x8b, 0xa2, 0x62, 0xfe, 0x69, 0x9f, - 0x75, 0x71, 0x6d, 0x45, 0x96, 0x32, 0x34, 0x24, 0x82, 0x99, 0x96, 0x97, 0xa4, 0x5c, 0x03, 0xe6, - 0x5e, 0x3e, 0xe4, 0x11, 0x25, 0xcf, 0x62, 0x59, 0xcd, 0x33, 0xc2, 0x7e, 0xde, 0xee, 0xd7, 0x47, - 0x60, 0x2a, 0x33, 0x45, 0x98, 0x79, 0xe9, 0x26, 0x6c, 0x0d, 0xd4, 0x7b, 0x6d, 0x6d, 0x5e, 0x6e, - 0x4a, 0x38, 0x6a, 0x0a, 0x46, 0xdd, 0xf1, 0x92, 0xe4, 0x6e, 0x14, 0xd7, 0xe5, 0x9c, 0xd6, 0xd4, - 0x6b, 0x12, 0x8e, 0x9a, 0x82, 0x19, 0x9a, 0x4d, 0xea, 0xc5, 0x34, 0xe6, 0xa7, 0xfa, 0x79, 0x43, - 0x53, 0x33, 0x28, 0xb4, 0xe9, 0xf8, 0xec, 0x4c, 0x5b, 0xc9, 0x52, 0x2b, 0xa0, 0x61, 0x2a, 0xd4, - 0x2c, 0x66, 0x76, 0x6e, 0xac, 0xae, 0xdb, 0x4c, 0xcd, 0xec, 0xcc, 0x21, 0x30, 0x2f, 0x9e, 0x7c, - 0xd4, 0x81, 0x29, 0xef, 0x6e, 0x62, 0x92, 0x3e, 0xf9, 0xf4, 0x3c, 0xb2, 0xb5, 0xca, 0xe4, 0x91, - 0xd6, 0x66, 0xd8, 0x3c, 0xcf, 0x80, 0x30, 0x2b, 0x94, 0x7c, 0xde, 0x01, 0x42, 0x77, 0xa9, 0xbf, - 0x16, 0x47, 0x3b, 0x41, 0x5d, 0xf5, 0xa1, 0xf4, 0x83, 0x8f, 0xe8, 0x76, 0x5d, 0xe8, 0xe3, 0x2b, - 0xa6, 0x77, 0x3f, 0x1c, 0x07, 0xe8, 0xe0, 0xfe, 0x5d, 0x19, 0x26, 0xac, 0x59, 0x39, 0xd0, 0xc4, - 0x3a, 0xdf, 0x67, 0x26, 0xb6, 0x74, 0x08, 0x13, 0xfb, 0x21, 0xa8, 0xfa, 0xca, 0x50, 0x14, 0x93, - 0xa4, 0x9a, 0x37, 0x3f, 0xc6, 0x56, 0x68, 0x10, 0x1a, 0x99, 0xe4, 0x12, 0xcc, 0x58, 0x6c, 0xa4, - 0x91, 0x19, 0xe1, 0x46, 0x46, 0x47, 0x1c, 0x16, 0xf3, 0x04, 0xd8, 0x5f, 0x86, 0x3c, 0xcb, 0xdc, - 0x9b, 0x40, 0xd6, 0x4b, 0x6c, 0xe7, 0x64, 0x02, 0xe8, 0xe2, 0xda, 0x8a, 0x02, 0xa3, 0x4d, 0xe3, - 0x7e, 0xdd, 0xd1, 0x9d, 0xfb, 0x18, 0xb2, 0x07, 0xee, 0x64, 0xb3, 0x07, 0x2e, 0x14, 0xd2, 0xcc, - 0x43, 0x32, 0x07, 0xae, 0xc3, 0xf8, 0x52, 0xd4, 0x6e, 0x7b, 0x61, 0x9d, 0xbc, 0x0e, 0xc6, 0x7d, - 0xf1, 0x53, 0xee, 0x17, 0xf8, 0x71, 0xb2, 0xc4, 0xa2, 0xc2, 0x91, 0xa7, 0x60, 0xc4, 0x8b, 0x9b, - 0x6a, 0x8f, 0xc0, 0x4f, 0x47, 0x16, 0xe3, 0x66, 0x82, 0x1c, 0xea, 0x7e, 0xb6, 0x04, 0xb0, 0x14, - 0xb5, 0x3b, 0x5e, 0x4c, 0xeb, 0x1b, 0xd1, 0xff, 0x07, 0x0b, 0x85, 0xeb, 0xf8, 0x09, 0x07, 0x08, - 0x6b, 0x95, 0x28, 0xa4, 0xa1, 0x39, 0x91, 0x61, 0xeb, 0xa5, 0xaf, 0xa0, 0x72, 0xf1, 0x31, 0x73, - 0x40, 0x21, 0xd0, 0xd0, 0x1c, 0xc0, 0x9d, 0x7c, 0x5a, 0x05, 0x9b, 0xcb, 0xd9, 0x93, 0x6e, 0x7e, - 0x3a, 0x29, 0x63, 0xcf, 0xee, 0xe7, 0x4a, 0x70, 0x5a, 0x98, 0xad, 0x6b, 0x5e, 0xe8, 0x35, 0x69, - 0x9b, 0x69, 0x75, 0xd0, 0xb0, 0xb3, 0xcf, 0xfc, 0x98, 0x40, 0x1d, 0x6c, 0x1f, 0x75, 0x70, 0x8a, - 0x41, 0x25, 0x86, 0xd1, 0x4a, 0x18, 0xa4, 0xc8, 0x99, 0x93, 0x04, 0x2a, 0xea, 0xda, 0x81, 0x34, - 0x36, 0x05, 0x09, 0xd2, 0xf3, 0xee, 0x92, 0x64, 0x8f, 0x5a, 0x90, 0xfb, 0x65, 0x07, 0xf2, 0x46, - 0x94, 0x3b, 0xfa, 0x22, 0x35, 0x2d, 0xef, 0xe8, 0x67, 0x33, 0xc9, 0x0e, 0x91, 0x98, 0xf5, 0x1e, - 0x98, 0xf0, 0xd2, 0x94, 0xb6, 0x3b, 0xc2, 0xeb, 0x2c, 0x3f, 0x5c, 0x64, 0xe3, 0x5a, 0x54, 0x0f, - 0x1a, 0x01, 0xf7, 0x36, 0x6d, 0x76, 0xee, 0x8b, 0x50, 0x51, 0xc1, 0xfc, 0x03, 0x74, 0xe6, 0xd3, - 0x99, 0xb3, 0x89, 0x21, 0xc3, 0xe5, 0x7e, 0x09, 0x06, 0xac, 0x82, 0xac, 0xca, 0xc6, 0x5e, 0x64, - 0xaa, 0x7c, 0x38, 0x9b, 0x41, 0x76, 0xc5, 0x41, 0x86, 0xd8, 0x42, 0xbf, 0xb3, 0xe8, 0x55, 0xdc, - 0x9c, 0x6d, 0x4c, 0x48, 0xfd, 0xf4, 0xf9, 0x06, 0x39, 0x0f, 0x60, 0xcc, 0xbc, 0x3c, 0xd0, 0xd7, - 0x41, 0x38, 0xb3, 0x1a, 0xa0, 0x45, 0xc5, 0x9c, 0xba, 0x20, 0x4c, 0x52, 0xaf, 0xd5, 0xba, 0x1c, - 0x84, 0xa9, 0xdc, 0xa6, 0x68, 0x13, 0xb0, 0x62, 0x50, 0x68, 0xd3, 0x9d, 0x79, 0x8b, 0xd5, 0x2f, - 0x87, 0x39, 0x23, 0xfa, 0x44, 0x09, 0xa6, 0x2f, 0x85, 0xdd, 0xb5, 0x4b, 0x6b, 0xdd, 0xcd, 0x56, - 0xe0, 0x5f, 0xa5, 0x3d, 0xd6, 0x69, 0xdb, 0xb4, 0xb7, 0xb2, 0x2c, 0x9b, 0x5d, 0x77, 0xda, 0x55, - 0x06, 0x44, 0x81, 0x63, 0x6a, 0x36, 0x82, 0xb0, 0x49, 0xe3, 0x4e, 0x1c, 0x48, 0x6f, 0xdc, 0x52, - 0xf3, 0xa2, 0x41, 0xa1, 0x4d, 0xc7, 0x78, 0x47, 0x77, 0x43, 0x1a, 0xe7, 0xed, 0xc7, 0x0d, 0x06, - 0x44, 0x81, 0x63, 0x44, 0x69, 0xdc, 0x4d, 0x52, 0xd9, 0x62, 0x9a, 0x68, 0x83, 0x01, 0x51, 0xe0, - 0xd8, 0xf0, 0x48, 0xba, 0x9b, 0x3c, 0xc0, 0x96, 0x3b, 0xea, 0x5c, 0x17, 0x60, 0x54, 0x78, 0x46, - 0xba, 0x4d, 0x7b, 0xcb, 0x6c, 0x35, 0xcd, 0x65, 0x26, 0x5c, 0x15, 0x60, 0x54, 0x78, 0xf7, 0x9f, - 0x1c, 0x20, 0xd9, 0xe6, 0x78, 0x0c, 0x0b, 0xf2, 0xcb, 0xd9, 0x05, 0xf9, 0x88, 0xb1, 0xd0, 0xac, - 0xfa, 0x43, 0xd6, 0xe5, 0xdf, 0x70, 0x60, 0xd2, 0x0e, 0x8b, 0x93, 0x66, 0xce, 0x10, 0xdd, 0xc8, - 0x1a, 0xa2, 0xfb, 0x7b, 0x73, 0x3f, 0x35, 0xe8, 0x56, 0x5c, 0x33, 0x48, 0xa3, 0x4e, 0xf2, 0x66, - 0x1a, 0x36, 0x83, 0x90, 0xf2, 0xa0, 0x8f, 0x08, 0xa7, 0x67, 0x62, 0xee, 0x4b, 0x51, 0x9d, 0x3e, - 0x84, 0x25, 0x73, 0x6f, 0xc3, 0x4c, 0x5f, 0x3a, 0xca, 0x01, 0x8c, 0xce, 0xbe, 0xc9, 0x86, 0xee, - 0x27, 0x1d, 0x98, 0xca, 0x64, 0xf3, 0x14, 0x64, 0xca, 0xf8, 0xac, 0x88, 0xf8, 0x89, 0x4a, 0x1c, - 0x84, 0x22, 0xe4, 0x52, 0xb1, 0x66, 0x85, 0x41, 0xa1, 0x4d, 0xe7, 0x7e, 0xa6, 0x04, 0x15, 0x15, - 0x9c, 0x3b, 0x80, 0x2a, 0x1f, 0x77, 0x60, 0x4a, 0x6f, 0x8d, 0xb9, 0xc3, 0x5c, 0x48, 0x46, 0x07, - 0xd3, 0x40, 0x1f, 0xbb, 0x31, 0x87, 0x59, 0x7b, 0xee, 0x68, 0x0b, 0xc3, 0xac, 0x6c, 0x72, 0x0b, - 0x20, 0xe9, 0x25, 0x29, 0x6d, 0x5b, 0xae, 0xbb, 0x6b, 0xcd, 0x8e, 0x79, 0x3f, 0x8a, 0x29, 0x9b, - 0x0b, 0xd7, 0xa3, 0x3a, 0x5d, 0xd7, 0x94, 0xc6, 0x10, 0x1a, 0x18, 0x5a, 0x9c, 0xdc, 0xdf, 0x2d, - 0xc1, 0xf1, 0xbc, 0x4a, 0xe4, 0xdd, 0x30, 0xa9, 0xa4, 0x5b, 0x97, 0x01, 0x55, 0x44, 0x72, 0x12, - 0x2d, 0xdc, 0xfd, 0xbd, 0xb9, 0xb9, 0xfe, 0xdb, 0x90, 0xf3, 0x36, 0x09, 0x66, 0x98, 0x89, 0xf8, - 0x84, 0x8c, 0xa8, 0xd4, 0x7a, 0x8b, 0x9d, 0x8e, 0x0c, 0x32, 0x58, 0xf1, 0x09, 0x1b, 0x8b, 0x39, - 0x6a, 0xb2, 0x06, 0x27, 0x2d, 0xc8, 0x75, 0x1a, 0x34, 0xb7, 0x36, 0xa3, 0x58, 0x64, 0x9d, 0x97, - 0x6b, 0x4f, 0x49, 0x2e, 0x27, 0x71, 0x00, 0x0d, 0x0e, 0x2c, 0x49, 0xde, 0x04, 0x15, 0xdf, 0xeb, - 0x78, 0x7e, 0x90, 0xf6, 0xe4, 0x5e, 0x44, 0xdb, 0x91, 0x25, 0x09, 0x47, 0x4d, 0xe1, 0x5e, 0x83, - 0x91, 0x03, 0x8e, 0xa0, 0x03, 0xad, 0xcb, 0x2f, 0x42, 0x85, 0xb1, 0x63, 0x76, 0xa3, 0x28, 0x96, - 0x11, 0x54, 0xd4, 0x25, 0x04, 0xe2, 0x42, 0x39, 0xf0, 0x54, 0x08, 0x48, 0x57, 0x6b, 0x25, 0x49, - 0xba, 0xdc, 0xeb, 0x60, 0x48, 0xf2, 0x34, 0x94, 0xe9, 0x6e, 0x27, 0x1f, 0xeb, 0xb9, 0xb0, 0xdb, - 0x09, 0x62, 0x9a, 0x30, 0x22, 0xba, 0xdb, 0x21, 0x67, 0xa0, 0x14, 0xd4, 0xe5, 0x82, 0x02, 0x92, - 0xa6, 0xb4, 0xb2, 0x8c, 0xa5, 0xa0, 0xee, 0xee, 0x42, 0x55, 0xdf, 0x7a, 0x20, 0xdb, 0xca, 0xce, - 0x3a, 0x45, 0x44, 0xd3, 0x15, 0xdf, 0x21, 0x16, 0xb6, 0x0b, 0x60, 0xf2, 0xc0, 0x8a, 0xb2, 0x2f, - 0xe7, 0x60, 0xc4, 0x8f, 0x64, 0xca, 0x65, 0xc5, 0xb0, 0xe1, 0x06, 0x96, 0x63, 0xdc, 0xdb, 0x30, - 0x7d, 0x35, 0x8c, 0xee, 0x86, 0x6c, 0xe1, 0xbb, 0x18, 0xd0, 0x56, 0x9d, 0x31, 0x6e, 0xb0, 0x1f, - 0xf9, 0xe5, 0x9c, 0x63, 0x51, 0xe0, 0xf4, 0xd5, 0x80, 0xd2, 0xb0, 0xab, 0x01, 0xee, 0x2f, 0x3b, - 0x70, 0x3c, 0x9f, 0xf3, 0xf5, 0x3d, 0xdb, 0x61, 0x7c, 0x98, 0x29, 0xa3, 0x92, 0x8a, 0x6e, 0x74, - 0xc4, 0xf1, 0xe5, 0xf3, 0x30, 0xb9, 0xd9, 0x0d, 0x5a, 0x75, 0xf9, 0x2d, 0xf5, 0xd1, 0x69, 0x53, - 0x35, 0x0b, 0x87, 0x19, 0x4a, 0xe6, 0xa7, 0x6d, 0x06, 0xa1, 0x17, 0xf7, 0xd6, 0xcc, 0xba, 0xa1, - 0xcd, 0x53, 0x4d, 0x63, 0xd0, 0xa2, 0x72, 0xff, 0xa6, 0x0c, 0xe6, 0xfa, 0x05, 0x09, 0xe4, 0xe9, - 0xb8, 0x53, 0x44, 0xd8, 0x6a, 0xbd, 0x17, 0xfa, 0xe6, 0xa2, 0x47, 0x25, 0x77, 0x38, 0xfe, 0x31, - 0x87, 0x79, 0x88, 0x41, 0x1a, 0x78, 0xdc, 0x58, 0xc8, 0x8d, 0xd2, 0x5a, 0x41, 0x07, 0xa8, 0x2b, - 0x82, 0x73, 0x14, 0xdb, 0x3e, 0xa7, 0x16, 0x86, 0xb6, 0x64, 0xf2, 0x92, 0x0c, 0x39, 0x97, 0x0b, - 0xcb, 0xad, 0xa8, 0xe4, 0xe2, 0xcc, 0x1d, 0x18, 0x8d, 0x69, 0x1a, 0xab, 0xac, 0x96, 0xab, 0x47, - 0x3d, 0x80, 0x4b, 0xe3, 0xde, 0x7a, 0xca, 0x36, 0x63, 0x4d, 0xcb, 0x31, 0xe2, 0x60, 0x14, 0x82, - 0xdc, 0x04, 0x48, 0x7f, 0x5b, 0x1c, 0x32, 0x8a, 0xbb, 0x00, 0x55, 0xaf, 0x9b, 0x46, 0x6d, 0xd6, - 0x4c, 0xbc, 0x7b, 0x2a, 0x56, 0x9c, 0x5a, 0x21, 0xd0, 0xd0, 0xb8, 0xaf, 0x8e, 0x42, 0xee, 0xb8, - 0x9a, 0xec, 0xda, 0x57, 0x87, 0x9c, 0x62, 0xaf, 0x0e, 0x69, 0x65, 0x06, 0x5d, 0x1f, 0x22, 0x4d, - 0x18, 0xed, 0x6c, 0x79, 0x89, 0x9a, 0xa3, 0x2f, 0xaa, 0x66, 0x5a, 0x63, 0xc0, 0xfb, 0x7b, 0x73, - 0x3f, 0x7d, 0x30, 0x3f, 0x90, 0x8d, 0xd5, 0x05, 0x91, 0xbb, 0x67, 0x44, 0x73, 0x1e, 0x28, 0xf8, - 0xdb, 0x9e, 0x60, 0x79, 0x9f, 0x3d, 0xed, 0x47, 0x1c, 0x91, 0xe3, 0x84, 0x34, 0xe9, 0xb6, 0x52, - 0x39, 0x1a, 0x5e, 0x2c, 0x70, 0x96, 0x09, 0xc6, 0x26, 0xd9, 0x49, 0x7c, 0xa3, 0x25, 0x94, 0xbc, - 0x1b, 0xaa, 0x49, 0xea, 0xc5, 0xe9, 0x43, 0xa6, 0x46, 0xe8, 0x46, 0x5f, 0x57, 0x4c, 0xd0, 0xf0, - 0x23, 0xef, 0x02, 0x68, 0x04, 0x61, 0x90, 0x6c, 0x3d, 0xe4, 0x49, 0x11, 0x57, 0xfc, 0xa2, 0xe6, - 0x80, 0x16, 0x37, 0x66, 0xdd, 0xf8, 0xd8, 0x16, 0x21, 0xcd, 0x0a, 0x5f, 0x4b, 0xb5, 0x75, 0x43, - 0x8d, 0x41, 0x8b, 0xca, 0xfd, 0x20, 0x9c, 0xc8, 0x5f, 0xdb, 0x95, 0x5b, 0xc3, 0x66, 0x1c, 0x75, - 0x3b, 0xf9, 0xb5, 0x84, 0x5f, 0xeb, 0x44, 0x81, 0x63, 0x36, 0x7e, 0x3b, 0x08, 0xeb, 0x79, 0x1b, - 0x7f, 0x35, 0x08, 0xeb, 0xc8, 0x31, 0x07, 0xb8, 0x53, 0xf5, 0xc7, 0x0e, 0x9c, 0xdb, 0xef, 0x76, - 0x31, 0xdb, 0xf6, 0xdf, 0xf5, 0xe2, 0x50, 0xde, 0x97, 0xe0, 0xb6, 0xe3, 0xb6, 0x17, 0x87, 0xc8, - 0xa1, 0xa4, 0x07, 0x63, 0x22, 0x1d, 0x4c, 0x7a, 0xc7, 0x2f, 0x16, 0x7b, 0xd7, 0x99, 0xed, 0xad, - 0x74, 0xb4, 0x46, 0xa4, 0xa2, 0xa1, 0x14, 0xe8, 0xbe, 0xea, 0x00, 0xb9, 0xb1, 0x43, 0xe3, 0x38, - 0xa8, 0x5b, 0x09, 0x6c, 0xe4, 0x39, 0x98, 0xbc, 0xb3, 0x7e, 0xe3, 0xfa, 0x5a, 0x14, 0x84, 0x3c, - 0x0f, 0xdb, 0x4a, 0x9b, 0xb8, 0x62, 0xc1, 0x31, 0x43, 0x45, 0x96, 0x60, 0xe6, 0xce, 0xcb, 0x6c, - 0xc9, 0xb9, 0xb0, 0xdb, 0x89, 0x69, 0x92, 0xe8, 0x17, 0x02, 0xaa, 0xe2, 0x60, 0xea, 0xca, 0x8b, - 0x39, 0x24, 0xf6, 0xd3, 0xbb, 0x5f, 0x2a, 0xc1, 0x84, 0x75, 0xa1, 0xfe, 0x00, 0xfe, 0x48, 0xee, - 0x0d, 0x80, 0xd2, 0x01, 0xdf, 0x00, 0x78, 0x06, 0x2a, 0x9d, 0xa8, 0x15, 0xf8, 0x81, 0x4e, 0xb0, - 0x9e, 0xe4, 0xa7, 0x57, 0x12, 0x86, 0x1a, 0x4b, 0xee, 0x42, 0x55, 0xdf, 0x8c, 0x95, 0x29, 0x57, - 0x45, 0x79, 0x64, 0x7a, 0xae, 0x99, 0x1b, 0xaf, 0x46, 0x16, 0x71, 0x61, 0x8c, 0x0f, 0x54, 0x15, - 0x9b, 0xe7, 0x67, 0xf8, 0x7c, 0x04, 0x27, 0x28, 0x31, 0xee, 0xbf, 0x8d, 0x42, 0x15, 0x69, 0x27, - 0x5a, 0x8a, 0x69, 0x3d, 0x21, 0xaf, 0x85, 0x72, 0x37, 0x6e, 0xc9, 0xc6, 0xd2, 0x61, 0x9e, 0x9b, - 0xb8, 0x8a, 0x0c, 0x9e, 0x59, 0x1d, 0x4a, 0x87, 0x3a, 0xe3, 0x2b, 0xef, 0x7b, 0xc6, 0xf7, 0x02, - 0x4c, 0x25, 0xc9, 0xd6, 0x5a, 0x1c, 0xec, 0x78, 0x29, 0x1b, 0x73, 0x32, 0x26, 0x62, 0x0e, 0x55, - 0xd6, 0x2f, 0x1b, 0x24, 0x66, 0x69, 0xc9, 0x25, 0x98, 0x31, 0x27, 0x6d, 0x34, 0x4e, 0x79, 0x08, - 0x44, 0x44, 0x4b, 0xf4, 0x99, 0x86, 0x39, 0x9b, 0x93, 0x04, 0xd8, 0x5f, 0x86, 0x2c, 0xc3, 0xf1, - 0x0c, 0x90, 0x29, 0x22, 0x42, 0x29, 0xb3, 0x92, 0xcf, 0xf1, 0x0c, 0x1f, 0xa6, 0x4b, 0x5f, 0x09, - 0x72, 0x0d, 0x4e, 0x88, 0xfe, 0xe5, 0x37, 0xaa, 0x75, 0x8d, 0xc6, 0x39, 0xa3, 0x1f, 0x92, 0x8c, - 0x4e, 0x5c, 0xea, 0x27, 0xc1, 0x41, 0xe5, 0xd8, 0x08, 0xd5, 0xe0, 0x95, 0x65, 0x69, 0xd8, 0xf4, - 0x08, 0xd5, 0x6c, 0x56, 0xea, 0x68, 0xd3, 0x91, 0x77, 0xc2, 0x93, 0xe6, 0x53, 0x44, 0xd0, 0xc4, - 0x6a, 0xbf, 0x2c, 0x4f, 0xb3, 0xe7, 0x24, 0x8b, 0x27, 0x2f, 0x0d, 0x24, 0xab, 0xe3, 0xb0, 0xf2, - 0x64, 0x13, 0xce, 0x68, 0xd4, 0x05, 0x36, 0x7b, 0x3b, 0x71, 0x90, 0xd0, 0x9a, 0x97, 0xd0, 0x9b, - 0x71, 0x8b, 0x67, 0x6f, 0x55, 0xcd, 0xab, 0x00, 0x97, 0x82, 0xf4, 0xf2, 0x20, 0x4a, 0x5c, 0xc5, - 0x07, 0x70, 0x61, 0xce, 0x05, 0x0d, 0xbd, 0xcd, 0x16, 0xbd, 0xb1, 0xb4, 0xc2, 0x6f, 0xba, 0x59, - 0xce, 0xc5, 0x05, 0x85, 0x40, 0x43, 0xa3, 0x5d, 0xfb, 0xc9, 0xa1, 0xae, 0xfd, 0x37, 0x1d, 0x98, - 0xd2, 0x83, 0xfd, 0x31, 0xc4, 0xbb, 0x5a, 0xd9, 0x78, 0xd7, 0xa5, 0xa3, 0x7a, 0x75, 0x52, 0xf3, - 0x21, 0x1b, 0xb1, 0x3f, 0xa9, 0x02, 0xf0, 0x77, 0x56, 0x02, 0x9e, 0x6d, 0x79, 0x0e, 0x46, 0x62, - 0xda, 0x89, 0xf2, 0x96, 0x8f, 0x51, 0x20, 0xc7, 0x7c, 0xff, 0x4e, 0xe7, 0x41, 0x67, 0xbe, 0xa3, - 0xdf, 0xdb, 0x33, 0xdf, 0x75, 0x38, 0x15, 0x84, 0x09, 0xf5, 0xbb, 0xb1, 0x5c, 0xe8, 0x2e, 0x47, - 0x89, 0xb6, 0x0e, 0x95, 0xda, 0x6b, 0x25, 0xa3, 0x53, 0x2b, 0x83, 0x88, 0x70, 0x70, 0x59, 0xd6, - 0xa4, 0x0a, 0x21, 0xaf, 0x75, 0x98, 0xf0, 0x80, 0x84, 0xa3, 0xa6, 0x30, 0x13, 0x62, 0xb5, 0xa1, - 0xee, 0x6d, 0xe4, 0x26, 0xc4, 0xea, 0xc5, 0x75, 0x34, 0x34, 0x83, 0xad, 0x62, 0xb5, 0x20, 0xab, - 0x08, 0x87, 0xb6, 0x8a, 0x6a, 0x7e, 0x4e, 0x0c, 0xbd, 0x95, 0xaf, 0x16, 0xeb, 0xc9, 0xa1, 0x8b, - 0xf5, 0xdb, 0x61, 0x3a, 0x08, 0xb7, 0x68, 0x1c, 0xa4, 0xb4, 0xce, 0xe7, 0xc2, 0xec, 0x14, 0x6f, - 0x08, 0x1d, 0xb9, 0x5a, 0xc9, 0x60, 0x31, 0x47, 0x9d, 0x35, 0x2a, 0xd3, 0x07, 0x30, 0x2a, 0x43, - 0x4c, 0xf9, 0xb1, 0x62, 0x4c, 0xf9, 0xf1, 0xa3, 0x9b, 0xf2, 0x99, 0x47, 0x6a, 0xca, 0x49, 0x21, - 0xa6, 0xfc, 0x69, 0x18, 0xed, 0xc4, 0xd1, 0x6e, 0x6f, 0xf6, 0x44, 0xd6, 0x9b, 0x5e, 0x63, 0x40, - 0x14, 0x38, 0xf7, 0x95, 0x12, 0x9c, 0x32, 0xe6, 0x8b, 0x0d, 0x9a, 0xa0, 0xc1, 0x26, 0x30, 0xbf, - 0x31, 0x27, 0x72, 0x28, 0xac, 0x48, 0xa8, 0x09, 0xaa, 0x6a, 0x0c, 0x5a, 0x54, 0x3c, 0xa0, 0x48, - 0x63, 0x9e, 0x8e, 0x99, 0xb7, 0x6d, 0x4b, 0x12, 0x8e, 0x9a, 0x82, 0xbf, 0xbc, 0x46, 0xe3, 0x54, - 0x1e, 0xa8, 0xe4, 0x13, 0x8c, 0x96, 0x0c, 0x0a, 0x6d, 0x3a, 0xe6, 0x03, 0xfa, 0x6a, 0x5e, 0x31, - 0xfb, 0x36, 0x29, 0x7c, 0x40, 0x3d, 0x95, 0x34, 0x56, 0xa9, 0xc3, 0x23, 0xc7, 0xa3, 0xfd, 0xea, - 0xf0, 0x48, 0x80, 0xa6, 0x70, 0xff, 0xc7, 0x81, 0xd7, 0x0c, 0x6c, 0x8a, 0xc7, 0xb0, 0x66, 0xed, - 0x66, 0xd7, 0xac, 0xf5, 0xa3, 0xaf, 0x59, 0x7d, 0xb5, 0x18, 0xb2, 0x7e, 0xfd, 0xad, 0x03, 0xd3, - 0x86, 0xfe, 0x31, 0x54, 0x35, 0x28, 0xf4, 0x0d, 0x35, 0xa3, 0xba, 0x48, 0x13, 0xcc, 0xd4, 0xed, - 0x9b, 0xbc, 0x6e, 0x62, 0x43, 0xb5, 0xe8, 0xab, 0x47, 0x4a, 0xf6, 0xd9, 0x99, 0xf4, 0x60, 0x8c, - 0x5f, 0x2b, 0x4d, 0x8a, 0xd9, 0xd8, 0x65, 0xe5, 0xf3, 0xd8, 0xa6, 0xd9, 0xd8, 0xf1, 0xcf, 0x04, - 0xa5, 0x40, 0x9e, 0x2c, 0x1c, 0x24, 0xcc, 0x08, 0xd6, 0x65, 0x0c, 0xd6, 0x24, 0x0b, 0x4b, 0x38, - 0x6a, 0x0a, 0xb7, 0x0d, 0xb3, 0x59, 0xe6, 0xcb, 0xb4, 0xc1, 0xe3, 0x67, 0x07, 0xaa, 0xe6, 0x02, - 0x54, 0x3d, 0x5e, 0x6a, 0xb5, 0xeb, 0xe5, 0x5f, 0x2a, 0x59, 0x54, 0x08, 0x34, 0x34, 0xee, 0xef, - 0x38, 0x70, 0x62, 0x40, 0x65, 0x0a, 0x8c, 0x3d, 0xa7, 0xc6, 0x0a, 0x0c, 0x79, 0x3d, 0xa6, 0x4e, - 0x1b, 0x9e, 0x8a, 0xd0, 0x58, 0x01, 0x9d, 0x65, 0x01, 0x46, 0x85, 0x77, 0xff, 0xdd, 0x81, 0x63, - 0x59, 0x5d, 0x13, 0x72, 0x05, 0x88, 0xa8, 0xcc, 0x72, 0x90, 0xf8, 0xd1, 0x0e, 0x8d, 0x7b, 0xac, - 0xe6, 0x42, 0xeb, 0x33, 0x92, 0x13, 0x59, 0xec, 0xa3, 0xc0, 0x01, 0xa5, 0xc8, 0x27, 0x79, 0x7e, - 0x8e, 0x6a, 0x6d, 0x35, 0x52, 0x6e, 0x15, 0x39, 0x52, 0x4c, 0x67, 0xda, 0xdb, 0x62, 0x2d, 0x12, - 0x6d, 0xf9, 0xee, 0xb7, 0x46, 0x40, 0x1f, 0x4e, 0xf1, 0x58, 0x40, 0x41, 0x91, 0x94, 0xcc, 0x73, - 0x36, 0xe5, 0x43, 0x3c, 0x67, 0x33, 0xf2, 0xa0, 0x8d, 0xbf, 0x78, 0x5b, 0xc5, 0x38, 0x98, 0x96, - 0xd1, 0xdf, 0x30, 0x28, 0xb4, 0xe9, 0x98, 0x26, 0xad, 0x60, 0x87, 0x8a, 0x42, 0x63, 0x59, 0x4d, - 0x56, 0x15, 0x02, 0x0d, 0x0d, 0xd3, 0xa4, 0x1e, 0x34, 0x1a, 0x72, 0xfb, 0xa7, 0x35, 0x61, 0xad, - 0x83, 0x1c, 0xc3, 0x28, 0xb6, 0xa2, 0x68, 0x5b, 0x3a, 0x75, 0x9a, 0xe2, 0x72, 0x14, 0x6d, 0x23, - 0xc7, 0x30, 0x37, 0x24, 0x8c, 0xe2, 0xb6, 0xd7, 0x0a, 0xde, 0x47, 0xeb, 0x5a, 0x8a, 0x74, 0xe6, - 0xb4, 0x1b, 0x72, 0xbd, 0x9f, 0x04, 0x07, 0x95, 0x63, 0x23, 0xb0, 0x13, 0xd3, 0x7a, 0xe0, 0xa7, - 0x36, 0x37, 0xc8, 0x8e, 0xc0, 0xb5, 0x3e, 0x0a, 0x1c, 0x50, 0x8a, 0x2c, 0xc2, 0x31, 0x75, 0xb8, - 0xa8, 0x12, 0x40, 0x84, 0x87, 0xa7, 0x9d, 0x6b, 0xcc, 0xa2, 0x31, 0x4f, 0xcf, 0xac, 0x4d, 0x5b, - 0xa6, 0xe1, 0x70, 0xdf, 0xcf, 0xb2, 0x36, 0x2a, 0x3d, 0x07, 0x35, 0x85, 0xfb, 0x7b, 0x25, 0xb6, - 0x3a, 0x0e, 0xb9, 0x35, 0xf9, 0xd8, 0x22, 0x77, 0xd9, 0x11, 0x39, 0x72, 0x80, 0x11, 0xf9, 0x1c, - 0x4c, 0xde, 0x49, 0xa2, 0x50, 0x47, 0xc5, 0x46, 0x87, 0x46, 0xc5, 0x2c, 0xaa, 0xc1, 0x51, 0xb1, - 0xb1, 0x43, 0x46, 0xc5, 0xfe, 0x62, 0x14, 0x4e, 0xeb, 0xf3, 0x60, 0x9a, 0xde, 0x8d, 0xe2, 0xed, - 0x20, 0x6c, 0xf2, 0x33, 0xd4, 0x2f, 0x3a, 0x30, 0x29, 0x86, 0xb7, 0xbc, 0x5f, 0x2e, 0xce, 0x0c, - 0x1b, 0x05, 0x5d, 0x01, 0xca, 0x08, 0x9b, 0xdf, 0xb0, 0x04, 0xe5, 0x2e, 0xfb, 0xdb, 0x28, 0xcc, - 0x68, 0x44, 0x3e, 0x00, 0xa0, 0x1e, 0x41, 0x6a, 0x14, 0xf4, 0x14, 0x94, 0xd2, 0x0f, 0x69, 0xc3, - 0xb8, 0x92, 0x1b, 0x5a, 0x08, 0x5a, 0x02, 0xc9, 0x2b, 0x0e, 0x8c, 0xb5, 0x44, 0xdb, 0x88, 0x03, - 0xa0, 0x97, 0x1e, 0x49, 0xdb, 0xd8, 0xad, 0xa2, 0x97, 0x65, 0xd9, 0x1e, 0x52, 0x3e, 0x41, 0x18, - 0x0f, 0xc2, 0x26, 0xeb, 0x56, 0x19, 0x48, 0x7c, 0xc3, 0xa0, 0xfc, 0x83, 0xd5, 0xc8, 0xab, 0xd7, - 0xbc, 0x96, 0x17, 0xfa, 0x34, 0x5e, 0x11, 0xe4, 0xf6, 0x53, 0x34, 0x1c, 0x80, 0x8a, 0x51, 0xdf, - 0x1d, 0xb7, 0xd1, 0x83, 0xdc, 0x71, 0x3b, 0xf3, 0x0e, 0x98, 0xe9, 0xeb, 0xcc, 0x43, 0xdd, 0xfc, - 0xff, 0x49, 0x98, 0x78, 0xc8, 0xa2, 0xee, 0x9f, 0x8e, 0x99, 0x35, 0xe6, 0x7a, 0x54, 0x17, 0x37, - 0xad, 0x62, 0xd3, 0xa3, 0xd2, 0x55, 0x2c, 0x70, 0x88, 0x58, 0xcf, 0xd9, 0x68, 0x20, 0xda, 0x22, - 0xd9, 0x18, 0xed, 0x78, 0x31, 0x0d, 0x1f, 0xf5, 0x18, 0x5d, 0xd3, 0x42, 0xd0, 0x12, 0x48, 0xb6, - 0x32, 0x27, 0x94, 0x17, 0x8f, 0x7e, 0x42, 0xc9, 0xbc, 0xd7, 0x81, 0x37, 0x62, 0x3e, 0xed, 0xc0, - 0x74, 0x98, 0x19, 0xb9, 0xf2, 0x94, 0x6a, 0xe3, 0x51, 0xcc, 0x0a, 0x71, 0xc3, 0x35, 0x0b, 0xc3, - 0x9c, 0xfc, 0x41, 0x2b, 0xd0, 0xe8, 0x21, 0x57, 0x20, 0x73, 0x65, 0x73, 0x6c, 0xd8, 0x95, 0x4d, - 0x12, 0xea, 0xcb, 0xda, 0xe3, 0x85, 0x5f, 0xd6, 0x86, 0x01, 0x17, 0xb5, 0x6f, 0x43, 0xd5, 0x8f, - 0xa9, 0x97, 0x3e, 0xe4, 0xbd, 0x5d, 0xfe, 0x80, 0xd8, 0x92, 0x62, 0x80, 0x86, 0x97, 0xfb, 0xd7, - 0x65, 0x38, 0xae, 0x5a, 0x44, 0x9d, 0xde, 0xb0, 0xe5, 0x4c, 0xc8, 0x35, 0xbe, 0xa8, 0x5e, 0xce, - 0x2e, 0x2b, 0x04, 0x1a, 0x1a, 0xe6, 0x3e, 0x75, 0x13, 0x7a, 0xa3, 0x43, 0xc3, 0xd5, 0x60, 0x33, - 0xe1, 0x2d, 0x6e, 0xa5, 0x80, 0xdd, 0x34, 0x28, 0xb4, 0xe9, 0x98, 0xef, 0x2c, 0xdc, 0xd8, 0x24, - 0x7f, 0x18, 0x2a, 0xdd, 0x63, 0x54, 0x78, 0xf2, 0x85, 0x81, 0xaf, 0x2e, 0x14, 0x93, 0x06, 0xd0, - 0x77, 0x68, 0x75, 0xc8, 0xe7, 0x16, 0x5e, 0x75, 0xe0, 0xd8, 0x76, 0x26, 0xff, 0x44, 0x99, 0xe4, - 0x23, 0x66, 0x35, 0x66, 0x93, 0x5a, 0xcc, 0x10, 0xce, 0xc2, 0x13, 0xcc, 0x4b, 0x77, 0xff, 0xcb, - 0x01, 0xdb, 0x3c, 0x1d, 0xcc, 0x11, 0xb2, 0xde, 0xd1, 0x29, 0xed, 0xf3, 0x8e, 0x8e, 0xf2, 0x99, - 0xca, 0x07, 0xf3, 0xd1, 0x47, 0x0e, 0xe1, 0xa3, 0x8f, 0x0e, 0x75, 0xb2, 0x5e, 0x0b, 0xe5, 0x6e, - 0x50, 0x97, 0x6e, 0xb6, 0x39, 0x90, 0x5a, 0x59, 0x46, 0x06, 0x77, 0xff, 0x68, 0xd4, 0x6c, 0xab, - 0xe5, 0xe9, 0xf5, 0x0f, 0x44, 0xb5, 0x1b, 0x3a, 0x49, 0x55, 0xd4, 0xfc, 0x7a, 0x5f, 0x92, 0xea, - 0xdb, 0x0e, 0x9f, 0x9c, 0x20, 0x1a, 0x68, 0x58, 0x8e, 0xea, 0xf8, 0x3e, 0x99, 0x09, 0x77, 0xa0, - 0xc2, 0x76, 0x22, 0x3c, 0x3e, 0x56, 0xc9, 0x28, 0x55, 0xb9, 0x2c, 0xe1, 0xf7, 0xf7, 0xe6, 0xde, - 0x7a, 0x78, 0xb5, 0x54, 0x69, 0xd4, 0xfc, 0x49, 0x02, 0x55, 0xf6, 0x9b, 0x27, 0x51, 0xc8, 0x3d, - 0xce, 0x4d, 0x6d, 0x8b, 0x14, 0xa2, 0x90, 0x0c, 0x0d, 0x23, 0x87, 0x84, 0x50, 0xe5, 0x2f, 0xbe, - 0x70, 0xa1, 0x62, 0x2b, 0xb4, 0xa6, 0x53, 0x19, 0x14, 0xe2, 0xfe, 0xde, 0xdc, 0x0b, 0x87, 0x17, - 0xaa, 0x8b, 0xa3, 0x11, 0xe1, 0x7e, 0xa7, 0x6c, 0xc6, 0xae, 0xcc, 0x4d, 0xfe, 0x81, 0x18, 0xbb, - 0xcf, 0xe7, 0xc6, 0xee, 0xb9, 0xbe, 0xb1, 0x3b, 0x6d, 0x5e, 0x45, 0xc9, 0x8c, 0xc6, 0xc7, 0xbd, - 0xc0, 0xee, 0xbf, 0xed, 0xe6, 0x9e, 0xc5, 0xcb, 0xdd, 0x20, 0xa6, 0xc9, 0x5a, 0xdc, 0x0d, 0x83, - 0xb0, 0xc9, 0x87, 0x63, 0xc5, 0xf6, 0x2c, 0x32, 0x68, 0xcc, 0xd3, 0xbb, 0x5f, 0xe2, 0x67, 0x8e, - 0x56, 0x3e, 0x16, 0xeb, 0xe5, 0x16, 0x7f, 0x34, 0x47, 0x64, 0x84, 0xea, 0x5e, 0x16, 0x2f, 0xe5, - 0x08, 0x1c, 0xb9, 0x0b, 0xe3, 0x9b, 0xe2, 0xe2, 0x7e, 0x31, 0x17, 0x84, 0xe4, 0x2b, 0x00, 0xfc, - 0x2a, 0xa6, 0x7a, 0x12, 0xe0, 0xbe, 0xf9, 0x89, 0x4a, 0x9a, 0xfb, 0x6b, 0x65, 0x38, 0x96, 0x7b, - 0xd2, 0x85, 0xed, 0xcf, 0xd5, 0xfb, 0x3d, 0xf9, 0x60, 0xba, 0x7e, 0xa7, 0x56, 0x53, 0x90, 0xf7, - 0x02, 0xd4, 0x69, 0xa7, 0x15, 0xf5, 0xb8, 0xe3, 0x32, 0x72, 0x68, 0xc7, 0x45, 0xfb, 0xba, 0xcb, - 0x9a, 0x0b, 0x5a, 0x1c, 0x65, 0x1a, 0xec, 0xa8, 0x78, 0x96, 0x20, 0x9b, 0x06, 0x6b, 0xdd, 0x93, - 0x1b, 0x7b, 0xbc, 0xf7, 0xe4, 0x02, 0x38, 0x26, 0x54, 0xd4, 0x59, 0x4f, 0x0f, 0x91, 0xdc, 0x74, - 0x82, 0x8d, 0xa8, 0xe5, 0x2c, 0x1b, 0xcc, 0xf3, 0x75, 0x3f, 0x55, 0x62, 0xee, 0x9b, 0x68, 0xec, - 0x6b, 0x2a, 0x96, 0xfd, 0x7a, 0x18, 0xf3, 0xba, 0xe9, 0x56, 0xd4, 0xf7, 0x90, 0xc2, 0x22, 0x87, - 0xa2, 0xc4, 0x92, 0x55, 0x18, 0xa9, 0x7b, 0xa9, 0x7a, 0x67, 0xfd, 0x30, 0xca, 0x99, 0xc0, 0x95, - 0x97, 0x52, 0xe4, 0x5c, 0xc8, 0x53, 0x30, 0x92, 0x7a, 0xcd, 0xcc, 0x0b, 0x8f, 0x1b, 0x5e, 0x33, - 0x41, 0x0e, 0xb5, 0x57, 0x97, 0x91, 0x7d, 0x56, 0x97, 0x17, 0xac, 0x7f, 0x00, 0xb0, 0x0e, 0x49, - 0xfa, 0x5f, 0xed, 0x17, 0x89, 0xf9, 0x19, 0x5a, 0xf7, 0xc7, 0x60, 0xd2, 0x7e, 0xd5, 0xff, 0x40, - 0xf7, 0x7a, 0xdc, 0x7f, 0x1d, 0x81, 0xa9, 0x4c, 0x66, 0x5c, 0x66, 0x94, 0x3b, 0xfb, 0x8e, 0x72, - 0x7e, 0xa6, 0xd5, 0x0d, 0xa9, 0xcc, 0x7b, 0xb4, 0xce, 0xb4, 0xba, 0x21, 0x45, 0x81, 0x63, 0xbd, - 0x52, 0x8f, 0x7b, 0xd8, 0x0d, 0x65, 0x10, 0x5d, 0xf7, 0xca, 0x32, 0x87, 0xa2, 0xc4, 0xb2, 0x0d, - 0xec, 0x64, 0xc2, 0x8d, 0xa2, 0xb0, 0x11, 0x72, 0xd6, 0x5c, 0x29, 0xe2, 0xf1, 0x29, 0x99, 0x05, - 0xca, 0x37, 0xf4, 0x36, 0x04, 0x33, 0x12, 0xc9, 0x47, 0x1d, 0xfb, 0xd9, 0xad, 0xb1, 0x22, 0x0e, - 0x7f, 0xf2, 0x89, 0x87, 0x62, 0x06, 0x3d, 0xf8, 0xf5, 0xad, 0x44, 0x4f, 0xe0, 0xf1, 0x47, 0x33, - 0x81, 0x61, 0xc0, 0xe4, 0x7d, 0x23, 0x54, 0xdb, 0x5e, 0x18, 0x34, 0x68, 0x92, 0x8a, 0x7f, 0xe4, - 0xa8, 0x8a, 0xdd, 0xd3, 0x35, 0x05, 0x44, 0x83, 0xe7, 0xff, 0x7b, 0xc3, 0x2b, 0x26, 0x36, 0x31, - 0x55, 0xeb, 0x7f, 0x6f, 0x0c, 0x18, 0x6d, 0x1a, 0xf7, 0xf7, 0x1d, 0x38, 0x35, 0xb0, 0x31, 0xbe, - 0x7f, 0xa3, 0x95, 0xee, 0x1f, 0x94, 0xe0, 0xc4, 0x80, 0xcc, 0x51, 0xd2, 0x7b, 0x64, 0xaf, 0xb3, - 0xc9, 0xd4, 0xd4, 0xa9, 0xa1, 0x63, 0xe3, 0x70, 0xcb, 0x90, 0x59, 0x0a, 0xca, 0x8f, 0x75, 0x29, - 0x70, 0xbf, 0x54, 0x02, 0xeb, 0x1d, 0x41, 0xf2, 0x41, 0x3b, 0x49, 0xda, 0x29, 0x2a, 0xa1, 0x57, - 0x30, 0xd7, 0x49, 0xd6, 0xa2, 0xd5, 0x06, 0xe5, 0x5c, 0xe7, 0xc7, 0x6b, 0x69, 0xff, 0xf1, 0x4a, - 0x5a, 0x2a, 0x1b, 0xbd, 0x5c, 0x7c, 0x36, 0x7a, 0xb5, 0x2f, 0x13, 0xfd, 0x57, 0x1c, 0x31, 0xd2, - 0x72, 0x55, 0x32, 0x16, 0xd6, 0x79, 0x80, 0x85, 0x7d, 0x13, 0x54, 0x12, 0xda, 0x6a, 0x30, 0xcf, - 0x4e, 0x5a, 0x62, 0x3d, 0x26, 0xd6, 0x25, 0x1c, 0x35, 0x05, 0xbf, 0xa7, 0xda, 0x6a, 0x45, 0x77, - 0x2f, 0xb4, 0x3b, 0x69, 0x4f, 0xda, 0x64, 0x73, 0x4f, 0x55, 0x63, 0xd0, 0xa2, 0x72, 0xff, 0xdb, - 0x11, 0xdd, 0x29, 0x7d, 0xf4, 0xe7, 0x73, 0xf7, 0x07, 0x0f, 0xee, 0xde, 0xfe, 0x3c, 0x80, 0xaf, - 0x6f, 0xf4, 0x17, 0xf3, 0xbc, 0xa0, 0x79, 0x21, 0xc0, 0x7e, 0xf3, 0x4e, 0xc1, 0xd0, 0x92, 0x97, - 0x99, 0x3c, 0xe5, 0xfd, 0x26, 0x8f, 0xfb, 0x1f, 0x0e, 0x64, 0x16, 0x0b, 0xd2, 0x81, 0x51, 0xa6, - 0x41, 0xaf, 0x98, 0xf7, 0x07, 0x6c, 0xd6, 0x6c, 0x62, 0xc9, 0x61, 0xc1, 0x7f, 0xa2, 0x10, 0x44, - 0x5a, 0xd2, 0x3b, 0x2f, 0x15, 0xf1, 0x46, 0x86, 0x2d, 0x90, 0xf9, 0xf7, 0xf2, 0x3f, 0x0e, 0xb4, - 0xa7, 0xef, 0x3e, 0x0f, 0x33, 0x7d, 0x4a, 0xf1, 0x1b, 0x45, 0x91, 0x7a, 0x74, 0xc1, 0x1a, 0x81, - 0xfc, 0x7e, 0x23, 0x0a, 0x1c, 0x73, 0xf0, 0x8f, 0xe7, 0xd9, 0x93, 0xcf, 0x3b, 0x30, 0x93, 0xe4, - 0xf9, 0x3d, 0xaa, 0xb6, 0xd3, 0x91, 0xab, 0x3e, 0x14, 0xf6, 0x2b, 0xe1, 0xfe, 0xa5, 0x34, 0x4f, - 0xe2, 0x3f, 0xa1, 0xf4, 0xe2, 0xe2, 0x0c, 0x5d, 0x5c, 0xd8, 0x14, 0xf3, 0xb7, 0x68, 0xbd, 0xdb, - 0xea, 0x4b, 0xa5, 0x59, 0x97, 0x70, 0xd4, 0x14, 0x99, 0x67, 0xc6, 0xca, 0xfb, 0x3e, 0x33, 0xf6, - 0x1c, 0x4c, 0xda, 0x0f, 0x8b, 0xf0, 0x10, 0x9a, 0x3c, 0x7c, 0xb0, 0xdf, 0x20, 0xc1, 0x0c, 0x55, - 0xee, 0x99, 0xaa, 0xd1, 0x7d, 0x9f, 0xa9, 0x7a, 0x06, 0x2a, 0xf2, 0x2f, 0x96, 0x54, 0x7c, 0x57, - 0xe4, 0xe9, 0x48, 0x18, 0x6a, 0x2c, 0x33, 0x10, 0x6d, 0x2f, 0xec, 0x7a, 0x2d, 0xd6, 0x42, 0x32, - 0x27, 0x4f, 0xcf, 0xac, 0x6b, 0x1a, 0x83, 0x16, 0x95, 0xfb, 0x2f, 0x0e, 0xe4, 0x1f, 0xfe, 0xc9, - 0x64, 0xf6, 0x39, 0xfb, 0x66, 0xf6, 0x65, 0x13, 0x9c, 0x4a, 0x07, 0x4a, 0x70, 0xb2, 0x73, 0x8f, - 0xca, 0x0f, 0xcc, 0x3d, 0x7a, 0x9d, 0xb9, 0x15, 0x2e, 0x92, 0x94, 0x26, 0x06, 0xdd, 0x08, 0x27, - 0x2e, 0x8c, 0xf9, 0x9e, 0x4e, 0x9c, 0x9e, 0x14, 0x8e, 0xd2, 0xd2, 0x22, 0x27, 0x92, 0x98, 0xda, - 0xfc, 0x57, 0xbe, 0x7d, 0xf6, 0x89, 0xaf, 0x7e, 0xfb, 0xec, 0x13, 0xdf, 0xf8, 0xf6, 0xd9, 0x27, - 0x3e, 0x7c, 0xef, 0xac, 0xf3, 0x95, 0x7b, 0x67, 0x9d, 0xaf, 0xde, 0x3b, 0xeb, 0x7c, 0xe3, 0xde, - 0x59, 0xe7, 0x5b, 0xf7, 0xce, 0x3a, 0x9f, 0xfe, 0xc7, 0xb3, 0x4f, 0xbc, 0xab, 0xa2, 0xc6, 0xea, - 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0xf7, 0x6e, 0xec, 0x2c, 0x61, 0x74, 0x00, 0x00, + // 6645 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7d, 0x6b, 0x6c, 0x24, 0xd9, + 0x55, 0xf0, 0x56, 0xb7, 0x1f, 0xdd, 0xc7, 0x8f, 0x19, 0xdf, 0x79, 0xac, 0x33, 0xdf, 0x66, 0x3c, + 0xaa, 0x55, 0x92, 0xfd, 0x48, 0x62, 0xb3, 0xc3, 0x12, 0x96, 0x6c, 0x48, 0xe2, 0xb6, 0xe7, 0xe1, + 0x19, 0xcf, 0x8c, 0xf7, 0xd8, 0x33, 0x43, 0x1e, 0x84, 0x2d, 0x57, 0xdf, 0x6e, 0xd7, 0xb8, 0xbb, + 0xaa, 0xb7, 0xaa, 0xda, 0xe3, 0x4e, 0xc8, 0x0b, 0x05, 0xb2, 0x22, 0x8f, 0x8d, 0x92, 0xfc, 0x48, + 0x24, 0x04, 0xe1, 0x21, 0x24, 0x7e, 0x44, 0xc0, 0x1f, 0x1e, 0x02, 0xfe, 0xe4, 0x57, 0x00, 0x09, + 0x22, 0x81, 0x92, 0x40, 0x84, 0x49, 0x86, 0x20, 0x1e, 0x12, 0x20, 0x1e, 0x7f, 0x98, 0x5f, 0xe8, + 0xbe, 0x6f, 0x55, 0x77, 0x8f, 0xed, 0x71, 0xcd, 0x24, 0x8a, 0xf8, 0xd7, 0x75, 0xce, 0xb9, 0xe7, + 0x9c, 0xfb, 0x3a, 0xf7, 0xdc, 0x73, 0xcf, 0xbd, 0x0d, 0xab, 0xcd, 0x20, 0xdd, 0xea, 0x6e, 0xce, + 0xfb, 0x51, 0x7b, 0xc1, 0x8b, 0x9b, 0x51, 0x27, 0x8e, 0xee, 0xf0, 0x1f, 0x6f, 0xf6, 0xeb, 0x0b, + 0x3b, 0xe7, 0x17, 0x3a, 0xdb, 0xcd, 0x05, 0xaf, 0x13, 0x24, 0x0b, 0x5e, 0xa7, 0xd3, 0x0a, 0x7c, + 0x2f, 0x0d, 0xa2, 0x70, 0x61, 0xe7, 0x59, 0xaf, 0xd5, 0xd9, 0xf2, 0x9e, 0x5d, 0x68, 0xd2, 0x90, + 0xc6, 0x5e, 0x4a, 0xeb, 0xf3, 0x9d, 0x38, 0x4a, 0x23, 0xf2, 0x36, 0xc3, 0x6d, 0x5e, 0x71, 0xe3, + 0x3f, 0x7e, 0xda, 0xaf, 0xcf, 0xef, 0x9c, 0x9f, 0xef, 0x6c, 0x37, 0xe7, 0x19, 0xb7, 0x79, 0x8b, + 0xdb, 0xbc, 0xe2, 0x76, 0xe6, 0xcd, 0x96, 0x2e, 0xcd, 0xa8, 0x19, 0x2d, 0x70, 0xa6, 0x9b, 0xdd, + 0x06, 0xff, 0xe2, 0x1f, 0xfc, 0x97, 0x10, 0x76, 0xc6, 0xdd, 0x7e, 0x3e, 0x99, 0x0f, 0x22, 0xa6, + 0xde, 0x82, 0x1f, 0xc5, 0x74, 0x61, 0xa7, 0x4f, 0xa1, 0x33, 0xcf, 0x19, 0x9a, 0xb6, 0xe7, 0x6f, + 0x05, 0x21, 0x8d, 0x7b, 0xa6, 0x4e, 0x6d, 0x9a, 0x7a, 0x83, 0x4a, 0x2d, 0x0c, 0x2b, 0x15, 0x77, + 0xc3, 0x34, 0x68, 0xd3, 0xbe, 0x02, 0x6f, 0xd9, 0xaf, 0x40, 0xe2, 0x6f, 0xd1, 0xb6, 0x97, 0x2f, + 0xe7, 0xbe, 0x0c, 0x53, 0x8b, 0xb7, 0xd7, 0x17, 0xbb, 0xe9, 0xd6, 0x52, 0x14, 0x36, 0x82, 0x26, + 0xf9, 0x51, 0x98, 0xf0, 0x5b, 0xdd, 0x24, 0xa5, 0xf1, 0x75, 0xaf, 0x4d, 0x67, 0x9d, 0x73, 0xce, + 0x33, 0xd5, 0xda, 0x89, 0xaf, 0xee, 0xcd, 0x3d, 0x71, 0x6f, 0x6f, 0x6e, 0x62, 0xc9, 0xa0, 0xd0, + 0xa6, 0x23, 0xff, 0x1f, 0xc6, 0xe3, 0xa8, 0x45, 0x17, 0xf1, 0xfa, 0x6c, 0x89, 0x17, 0x39, 0x26, + 0x8b, 0x8c, 0xa3, 0x00, 0xa3, 0xc2, 0xbb, 0x5f, 0x2f, 0x01, 0x2c, 0x76, 0x3a, 0x6b, 0x71, 0x74, + 0x87, 0xfa, 0x29, 0x79, 0x09, 0x2a, 0xac, 0x15, 0xea, 0x5e, 0xea, 0x71, 0x69, 0x13, 0xe7, 0x7f, + 0x78, 0x5e, 0x54, 0x66, 0xde, 0xae, 0x8c, 0xe9, 0x39, 0x46, 0x3d, 0xbf, 0xf3, 0xec, 0xfc, 0x8d, + 0x4d, 0x56, 0xfe, 0x1a, 0x4d, 0xbd, 0x1a, 0x91, 0xc2, 0xc0, 0xc0, 0x50, 0x73, 0x25, 0x21, 0x8c, + 0x24, 0x1d, 0xea, 0x73, 0xc5, 0x26, 0xce, 0xaf, 0xce, 0x1f, 0x65, 0x88, 0xcc, 0x1b, 0xcd, 0xd7, + 0x3b, 0xd4, 0xaf, 0x4d, 0x4a, 0xc9, 0x23, 0xec, 0x0b, 0xb9, 0x1c, 0xb2, 0x03, 0x63, 0x49, 0xea, + 0xa5, 0xdd, 0x64, 0xb6, 0xcc, 0x25, 0x5e, 0x2f, 0x4c, 0x22, 0xe7, 0x5a, 0x9b, 0x96, 0x32, 0xc7, + 0xc4, 0x37, 0x4a, 0x69, 0xee, 0xdf, 0x3a, 0x30, 0x6d, 0x88, 0x57, 0x83, 0x24, 0x25, 0xef, 0xed, + 0x6b, 0xdc, 0xf9, 0x83, 0x35, 0x2e, 0x2b, 0xcd, 0x9b, 0xf6, 0xb8, 0x14, 0x56, 0x51, 0x10, 0xab, + 0x61, 0xdb, 0x30, 0x1a, 0xa4, 0xb4, 0x9d, 0xcc, 0x96, 0xce, 0x95, 0x9f, 0x99, 0x38, 0x7f, 0xb9, + 0xa8, 0x7a, 0xd6, 0xa6, 0xa4, 0xd0, 0xd1, 0x15, 0xc6, 0x1e, 0x85, 0x14, 0xf7, 0x77, 0x27, 0xec, + 0xfa, 0xb1, 0x06, 0x27, 0xcf, 0xc2, 0x44, 0x12, 0x75, 0x63, 0x9f, 0x22, 0xed, 0x44, 0xc9, 0xac, + 0x73, 0xae, 0xcc, 0x86, 0x1e, 0x1b, 0xa9, 0xeb, 0x06, 0x8c, 0x36, 0x0d, 0xf9, 0xb4, 0x03, 0x93, + 0x75, 0x9a, 0xa4, 0x41, 0xc8, 0xe5, 0x2b, 0xe5, 0x37, 0x8e, 0xac, 0xbc, 0x02, 0x2e, 0x1b, 0xe6, + 0xb5, 0x93, 0xb2, 0x22, 0x93, 0x16, 0x30, 0xc1, 0x8c, 0x7c, 0x36, 0xe3, 0xea, 0x34, 0xf1, 0xe3, + 0xa0, 0xc3, 0xbe, 0xf9, 0x98, 0xb1, 0x66, 0xdc, 0xb2, 0x41, 0xa1, 0x4d, 0x47, 0x42, 0x18, 0x65, + 0x33, 0x2a, 0x99, 0x1d, 0xe1, 0xfa, 0xaf, 0x1c, 0x4d, 0x7f, 0xd9, 0xa8, 0x6c, 0xb2, 0x9a, 0xd6, + 0x67, 0x5f, 0x09, 0x0a, 0x31, 0xe4, 0x53, 0x0e, 0xcc, 0xca, 0x19, 0x8f, 0x54, 0x34, 0xe8, 0xed, + 0xad, 0x20, 0xa5, 0xad, 0x20, 0x49, 0x67, 0x47, 0xb9, 0x0e, 0x0b, 0x07, 0x1b, 0x5b, 0x97, 0xe2, + 0xa8, 0xdb, 0xb9, 0x1a, 0x84, 0xf5, 0xda, 0x39, 0x29, 0x69, 0x76, 0x69, 0x08, 0x63, 0x1c, 0x2a, + 0x92, 0x7c, 0xce, 0x81, 0x33, 0xa1, 0xd7, 0xa6, 0x49, 0xc7, 0x63, 0x5d, 0x2b, 0xd0, 0xb5, 0x96, + 0xe7, 0x6f, 0x73, 0x8d, 0xc6, 0x1e, 0x4e, 0x23, 0x57, 0x6a, 0x74, 0xe6, 0xfa, 0x50, 0xd6, 0xf8, + 0x00, 0xb1, 0xe4, 0xd7, 0x1c, 0x98, 0x89, 0xe2, 0xce, 0x96, 0x17, 0xd2, 0xba, 0xc2, 0x26, 0xb3, + 0xe3, 0x7c, 0xea, 0xbd, 0xef, 0x68, 0x5d, 0x74, 0x23, 0xcf, 0xf6, 0x5a, 0x14, 0x06, 0x69, 0x14, + 0xaf, 0xd3, 0x34, 0x0d, 0xc2, 0x66, 0x52, 0x3b, 0x75, 0x6f, 0x6f, 0x6e, 0xa6, 0x8f, 0x0a, 0xfb, + 0xf5, 0x21, 0x1f, 0x80, 0x89, 0xa4, 0x17, 0xfa, 0xb7, 0x83, 0xb0, 0x1e, 0xdd, 0x4d, 0x66, 0x2b, + 0x45, 0x4c, 0xdf, 0x75, 0xcd, 0x50, 0x4e, 0x40, 0x23, 0x00, 0x6d, 0x69, 0x83, 0x3b, 0xce, 0x0c, + 0xa5, 0x6a, 0xd1, 0x1d, 0x67, 0x06, 0xd3, 0x03, 0xc4, 0x92, 0x8f, 0x3b, 0x30, 0x95, 0x04, 0xcd, + 0xd0, 0x4b, 0xbb, 0x31, 0xbd, 0x4a, 0x7b, 0xc9, 0x2c, 0x70, 0x45, 0xae, 0x1c, 0xb1, 0x55, 0x2c, + 0x96, 0xb5, 0x53, 0x52, 0xc7, 0x29, 0x1b, 0x9a, 0x60, 0x56, 0xee, 0xa0, 0x89, 0x66, 0x86, 0xf5, + 0x44, 0xb1, 0x13, 0xcd, 0x0c, 0xea, 0xa1, 0x22, 0xc9, 0x3b, 0xe1, 0xb8, 0x00, 0xe9, 0x96, 0x4d, + 0x66, 0x27, 0xb9, 0xa1, 0x3d, 0x79, 0x6f, 0x6f, 0xee, 0xf8, 0x7a, 0x0e, 0x87, 0x7d, 0xd4, 0xee, + 0x9f, 0x94, 0xe0, 0x78, 0x7e, 0x15, 0x23, 0xbf, 0xe1, 0xc0, 0xb1, 0x3b, 0x77, 0xd3, 0x8d, 0x68, + 0x9b, 0x86, 0x49, 0xad, 0xc7, 0x6c, 0x0d, 0xb7, 0xdf, 0x13, 0xe7, 0xfd, 0x62, 0xd7, 0xcb, 0xf9, + 0x2b, 0x59, 0x29, 0x17, 0xc2, 0x34, 0xee, 0xd5, 0x9e, 0x94, 0x2d, 0x72, 0xec, 0xca, 0xed, 0x0d, + 0x1b, 0x8b, 0x79, 0xa5, 0xce, 0x7c, 0xc2, 0x81, 0x93, 0x83, 0x58, 0x90, 0xe3, 0x50, 0xde, 0xa6, + 0x3d, 0xe1, 0x22, 0x21, 0xfb, 0x49, 0x7e, 0x0a, 0x46, 0x77, 0xbc, 0x56, 0x97, 0x4a, 0x57, 0xe3, + 0xd2, 0xd1, 0x2a, 0xa2, 0x35, 0x43, 0xc1, 0xf5, 0xad, 0xa5, 0xe7, 0x1d, 0xf7, 0x2f, 0xca, 0x30, + 0x61, 0x2d, 0x36, 0x8f, 0xc1, 0x7d, 0x8a, 0x32, 0xee, 0xd3, 0xb5, 0xc2, 0xd6, 0xc9, 0xa1, 0xfe, + 0xd3, 0xdd, 0x9c, 0xff, 0x74, 0xa3, 0x38, 0x91, 0x0f, 0x74, 0xa0, 0x48, 0x0a, 0xd5, 0xa8, 0xc3, + 0xdc, 0x63, 0xb6, 0x0e, 0x8f, 0x14, 0xd1, 0x85, 0x37, 0x14, 0xbb, 0xda, 0xd4, 0xbd, 0xbd, 0xb9, + 0xaa, 0xfe, 0x44, 0x23, 0xc8, 0xfd, 0x86, 0x03, 0x27, 0x2d, 0x1d, 0x97, 0xa2, 0xb0, 0x1e, 0xf0, + 0xae, 0x3d, 0x07, 0x23, 0x69, 0xaf, 0xa3, 0x7c, 0x70, 0xdd, 0x52, 0x1b, 0xbd, 0x0e, 0x45, 0x8e, + 0x61, 0x5e, 0x77, 0x9b, 0x26, 0x89, 0xd7, 0xa4, 0x79, 0xaf, 0xfb, 0x9a, 0x00, 0xa3, 0xc2, 0x93, + 0x18, 0x48, 0xcb, 0x4b, 0xd2, 0x8d, 0xd8, 0x0b, 0x13, 0xce, 0x7e, 0x23, 0x68, 0x53, 0xd9, 0xc0, + 0x3f, 0x74, 0xb0, 0x11, 0xc3, 0x4a, 0xd4, 0x4e, 0xdf, 0xdb, 0x9b, 0x23, 0xab, 0x7d, 0x9c, 0x70, + 0x00, 0x77, 0xf7, 0x73, 0x0e, 0x9c, 0x1e, 0xec, 0x18, 0x91, 0xd7, 0xc3, 0x58, 0x42, 0xe3, 0x1d, + 0x1a, 0xcb, 0xda, 0x99, 0x2e, 0xe1, 0x50, 0x94, 0x58, 0xb2, 0x00, 0x55, 0x6d, 0xb4, 0x65, 0x1d, + 0x67, 0x24, 0x69, 0xd5, 0x58, 0x7a, 0x43, 0xc3, 0x1a, 0x8d, 0x7d, 0x48, 0x37, 0x4a, 0x37, 0x1a, + 0xdf, 0xb1, 0x70, 0x8c, 0xfb, 0x77, 0x0e, 0x1c, 0xb3, 0xb4, 0x7a, 0x0c, 0x7e, 0x72, 0x98, 0xf5, + 0x93, 0x57, 0x0a, 0x1b, 0xcf, 0x43, 0x1c, 0xe5, 0xaf, 0x8c, 0xc1, 0x8c, 0x3d, 0xea, 0xb9, 0x3d, + 0xe6, 0x5b, 0x34, 0xda, 0x89, 0x6e, 0xe2, 0xaa, 0x6c, 0x73, 0xb3, 0x45, 0x13, 0x60, 0x54, 0x78, + 0xd6, 0x88, 0x1d, 0x2f, 0xdd, 0x92, 0x0d, 0xae, 0x1b, 0x71, 0xcd, 0x4b, 0xb7, 0x90, 0x63, 0xc8, + 0xdb, 0x61, 0x3a, 0xf5, 0xe2, 0x26, 0x4d, 0x91, 0xee, 0x04, 0x89, 0x9a, 0x2f, 0xd5, 0xda, 0x69, + 0x49, 0x3b, 0xbd, 0x91, 0xc1, 0x62, 0x8e, 0x9a, 0xbc, 0x0c, 0x23, 0x5b, 0xb4, 0xd5, 0x96, 0x9e, + 0xd1, 0x7a, 0x71, 0x33, 0x9c, 0xd7, 0xf5, 0x32, 0x6d, 0xb5, 0x6b, 0x15, 0xa6, 0x32, 0xfb, 0x85, + 0x5c, 0x14, 0xf9, 0x39, 0x07, 0xaa, 0xdb, 0xdd, 0x24, 0x8d, 0xda, 0xc1, 0xfb, 0xe9, 0x6c, 0x85, + 0x0b, 0xfe, 0xc9, 0x82, 0x05, 0x5f, 0x55, 0xfc, 0xc5, 0x7c, 0xd7, 0x9f, 0x68, 0x24, 0x93, 0x0f, + 0xc2, 0xf8, 0x76, 0x12, 0x85, 0x21, 0x65, 0xbe, 0x0e, 0x53, 0xe2, 0x56, 0xd1, 0x4a, 0x08, 0xee, + 0xb5, 0x09, 0xd6, 0xb7, 0xf2, 0x03, 0x95, 0x4c, 0xde, 0x0c, 0xf5, 0x20, 0xa6, 0x7e, 0x1a, 0xc5, + 0xbd, 0x59, 0x78, 0x24, 0xcd, 0xb0, 0xac, 0xf8, 0x8b, 0x66, 0xd0, 0x9f, 0x68, 0x24, 0x93, 0x1e, + 0x8c, 0x75, 0x5a, 0xdd, 0x66, 0x10, 0xce, 0x4e, 0x70, 0x1d, 0x6e, 0x16, 0xac, 0xc3, 0x1a, 0x67, + 0x5e, 0x03, 0x66, 0x54, 0xc4, 0x6f, 0x94, 0x02, 0xc9, 0xd3, 0x30, 0xea, 0x6f, 0x79, 0x71, 0x3a, + 0x3b, 0xc9, 0xc7, 0xac, 0x9e, 0x44, 0x4b, 0x0c, 0x88, 0x02, 0xe7, 0xfe, 0x4a, 0x09, 0xce, 0x0c, + 0xaf, 0x98, 0x98, 0x4d, 0x7e, 0x37, 0x4e, 0x84, 0x7d, 0xae, 0xd8, 0xb3, 0x89, 0x83, 0x51, 0xe1, + 0xc9, 0x47, 0x1d, 0x18, 0xbf, 0x23, 0x7b, 0xbc, 0xf4, 0x48, 0x7a, 0xfc, 0x8a, 0xec, 0x71, 0xad, + 0xc3, 0x15, 0xd5, 0xeb, 0x52, 0x2e, 0x53, 0x97, 0xee, 0xfa, 0xad, 0x6e, 0x5d, 0x59, 0x46, 0x4d, + 0x7a, 0x41, 0x80, 0x51, 0xe1, 0x19, 0x69, 0x10, 0x0a, 0xd2, 0x91, 0x2c, 0xe9, 0x4a, 0x28, 0x49, + 0x25, 0xde, 0xfd, 0x6e, 0x19, 0x4e, 0x0d, 0x9c, 0x7c, 0x64, 0x1e, 0x80, 0xfb, 0x2c, 0x17, 0x03, + 0xb6, 0x45, 0x15, 0xfb, 0xf2, 0x69, 0xe6, 0x62, 0xdc, 0xd2, 0x50, 0xb4, 0x28, 0xc8, 0x87, 0x01, + 0x3a, 0x5e, 0xec, 0xb5, 0x69, 0x4a, 0x63, 0x65, 0x27, 0xaf, 0x1e, 0xad, 0x95, 0x98, 0x1e, 0x6b, + 0x8a, 0xa7, 0xf1, 0x71, 0x34, 0x28, 0x41, 0x4b, 0x24, 0xdb, 0x85, 0xc7, 0xb4, 0x45, 0xbd, 0x84, + 0x3b, 0xae, 0xf9, 0x5d, 0x38, 0x1a, 0x14, 0xda, 0x74, 0x6c, 0x1d, 0xe3, 0xb5, 0x48, 0x64, 0x5b, + 0xe9, 0x75, 0x8c, 0xd7, 0x33, 0x41, 0x89, 0x25, 0xaf, 0x3a, 0x30, 0xdd, 0x08, 0x5a, 0xd4, 0x48, + 0x97, 0x7b, 0xe6, 0x1b, 0x47, 0xaf, 0xe4, 0x45, 0x9b, 0xaf, 0xb1, 0xc0, 0x19, 0x70, 0x82, 0x39, + 0xf1, 0xac, 0x9b, 0x77, 0x68, 0xcc, 0x4d, 0xf7, 0x58, 0xb6, 0x9b, 0x6f, 0x09, 0x30, 0x2a, 0xbc, + 0xfb, 0xc5, 0x12, 0xcc, 0x0e, 0x1b, 0x73, 0x24, 0x61, 0x23, 0x2b, 0xbd, 0xe5, 0xc5, 0x89, 0x74, + 0xdf, 0x8f, 0xb8, 0x8f, 0x94, 0x7c, 0x6f, 0x79, 0xb1, 0x3d, 0x46, 0xb9, 0x00, 0x54, 0x92, 0xc8, + 0x1d, 0x18, 0x49, 0x5b, 0x5e, 0x41, 0x81, 0x27, 0x4b, 0xa2, 0x71, 0xb2, 0x56, 0x17, 0x13, 0xe4, + 0x32, 0xc8, 0x53, 0x30, 0xd2, 0x0a, 0x36, 0x99, 0x33, 0xca, 0x06, 0x31, 0x5f, 0x55, 0x56, 0x83, + 0xcd, 0x04, 0x39, 0xd4, 0xfd, 0xba, 0x33, 0xa0, 0x6d, 0xa4, 0xd1, 0x65, 0x83, 0x8a, 0x86, 0x3b, + 0x41, 0x1c, 0x85, 0x6d, 0x1a, 0xa6, 0xf9, 0x60, 0xea, 0x05, 0x83, 0x42, 0x9b, 0x8e, 0xfc, 0xac, + 0x33, 0x60, 0x36, 0x1c, 0x31, 0x8a, 0x28, 0x55, 0x3a, 0xf0, 0x84, 0x70, 0xff, 0x7d, 0x6c, 0x80, + 0xfd, 0xd3, 0x0b, 0x1a, 0x39, 0x0f, 0xc0, 0xbc, 0xa9, 0xb5, 0x98, 0x36, 0x82, 0x5d, 0x59, 0x33, + 0xcd, 0xf2, 0xba, 0xc6, 0xa0, 0x45, 0xa5, 0xca, 0xac, 0x77, 0x1b, 0xac, 0x4c, 0xa9, 0xbf, 0x8c, + 0xc0, 0xa0, 0x45, 0x45, 0x9e, 0x83, 0xb1, 0xa0, 0xed, 0x35, 0xa9, 0x6a, 0xff, 0xa7, 0xd8, 0xe4, + 0x5a, 0xe1, 0x90, 0xfb, 0x7b, 0x73, 0xd3, 0x5a, 0x21, 0x0e, 0x42, 0x49, 0x4b, 0x7e, 0xdd, 0x81, + 0x49, 0x3f, 0x6a, 0xb7, 0xa3, 0x70, 0xd5, 0xdb, 0xa4, 0x2d, 0x15, 0x24, 0xbb, 0xf3, 0xa8, 0x96, + 0xfb, 0xf9, 0x25, 0x4b, 0x98, 0xd8, 0x60, 0xea, 0xd0, 0x9f, 0x8d, 0xc2, 0x8c, 0x56, 0xf6, 0x1c, + 0x1c, 0x7d, 0xf0, 0x1c, 0x24, 0xbf, 0xef, 0xc0, 0x8c, 0x28, 0xbb, 0x18, 0x86, 0x51, 0x2a, 0x63, + 0x97, 0x22, 0xca, 0x15, 0x3d, 0xe2, 0x6a, 0x59, 0x12, 0x45, 0xdd, 0x5e, 0x23, 0xd5, 0x9c, 0xe9, + 0xc3, 0x63, 0xbf, 0x92, 0xe4, 0x12, 0xcc, 0x34, 0xa2, 0xd8, 0xa7, 0x76, 0x43, 0x70, 0xc7, 0xaf, + 0x62, 0x18, 0x5d, 0xcc, 0x13, 0x60, 0x7f, 0x19, 0x72, 0x0b, 0x4e, 0x5b, 0x40, 0xbb, 0x1d, 0x2a, + 0x9c, 0xdb, 0x59, 0xc9, 0xed, 0xf4, 0xc5, 0x81, 0x54, 0x38, 0xa4, 0xf4, 0x99, 0x77, 0xc0, 0x4c, + 0x5f, 0xff, 0x0d, 0xd8, 0xdd, 0x9f, 0xb4, 0x77, 0xf7, 0x55, 0x6b, 0x53, 0x7e, 0x66, 0x19, 0x4e, + 0x0f, 0x6e, 0xa9, 0xc3, 0x70, 0x71, 0x7f, 0xc9, 0x81, 0x27, 0x87, 0xb8, 0x31, 0x7a, 0x5b, 0xe3, + 0x0c, 0xdb, 0xd6, 0x10, 0x0f, 0xca, 0x34, 0xdc, 0x91, 0xc6, 0xe2, 0xe2, 0xd1, 0x46, 0xc4, 0x85, + 0x70, 0x47, 0x74, 0xf4, 0xf8, 0xbd, 0xbd, 0xb9, 0xf2, 0x85, 0x70, 0x07, 0x19, 0x6f, 0xf7, 0xf3, + 0x63, 0x99, 0x9d, 0xd3, 0xba, 0xda, 0xac, 0x73, 0x45, 0xe5, 0xbe, 0xe9, 0x46, 0xc1, 0x63, 0xd1, + 0xda, 0x19, 0x8a, 0x20, 0xbe, 0x14, 0x47, 0x3e, 0xe1, 0xf0, 0xb8, 0xb9, 0xda, 0x51, 0x4a, 0xcf, + 0xea, 0xd1, 0x84, 0xf1, 0xed, 0x68, 0xbc, 0x02, 0xa2, 0x2d, 0x9d, 0xcd, 0xe4, 0x8e, 0x08, 0x3a, + 0xe5, 0xfd, 0x2b, 0x15, 0x59, 0x57, 0x78, 0xb2, 0x0b, 0x90, 0xf4, 0x42, 0x7f, 0x2d, 0x6a, 0x05, + 0x7e, 0x4f, 0x86, 0x19, 0x0a, 0x88, 0xbd, 0x0a, 0x7e, 0xc2, 0xc9, 0x32, 0xdf, 0x68, 0xc9, 0x22, + 0x5f, 0x72, 0x60, 0x26, 0x68, 0x86, 0x51, 0x4c, 0x97, 0x83, 0x46, 0x83, 0xc6, 0x34, 0xf4, 0xa9, + 0xf2, 0x43, 0x6e, 0x1f, 0x4d, 0x03, 0x15, 0x36, 0x5c, 0xc9, 0xb3, 0x37, 0x53, 0xbc, 0x0f, 0x85, + 0xfd, 0xca, 0x90, 0x3a, 0x8c, 0x04, 0x61, 0x23, 0x92, 0x86, 0xad, 0x76, 0x34, 0xa5, 0x56, 0xc2, + 0x46, 0x64, 0xe6, 0x0a, 0xfb, 0x42, 0xce, 0x9d, 0xac, 0xc2, 0xc9, 0x58, 0xee, 0x44, 0x2f, 0x07, + 0x09, 0xf3, 0xe7, 0x57, 0x83, 0x76, 0x90, 0x72, 0xa3, 0x54, 0xae, 0xcd, 0xde, 0xdb, 0x9b, 0x3b, + 0x89, 0x03, 0xf0, 0x38, 0xb0, 0x94, 0xfb, 0x4a, 0x35, 0xbb, 0xdd, 0x16, 0xc1, 0xa4, 0x0f, 0x42, + 0x35, 0xd6, 0x07, 0x00, 0xc2, 0x33, 0x5a, 0x2d, 0xa6, 0x8d, 0x65, 0x14, 0x4b, 0xc7, 0x41, 0x4c, + 0xa8, 0xdf, 0x48, 0x64, 0x1e, 0x12, 0xeb, 0x79, 0x39, 0x2d, 0x0a, 0x18, 0x5f, 0x52, 0xaa, 0x09, + 0xd8, 0xf5, 0x42, 0x1f, 0xb9, 0x0c, 0x12, 0xc3, 0xd8, 0x16, 0xf5, 0x5a, 0xe9, 0x96, 0x8c, 0x27, + 0x5d, 0x39, 0xaa, 0x4f, 0xcb, 0x78, 0xe5, 0x63, 0x75, 0x02, 0x8a, 0x52, 0x12, 0xd9, 0x85, 0xf1, + 0x2d, 0xd1, 0x09, 0x72, 0x6d, 0xbf, 0x76, 0xd4, 0xc6, 0xcd, 0xf4, 0xac, 0x99, 0xbf, 0x12, 0x80, + 0x4a, 0x1c, 0xf9, 0x79, 0x07, 0xc0, 0x57, 0x41, 0x3a, 0x35, 0x7d, 0xb0, 0x30, 0xbb, 0xa3, 0xe3, + 0x7f, 0xc6, 0x35, 0xd2, 0xa0, 0x04, 0x2d, 0xc9, 0xe4, 0x25, 0x98, 0x8c, 0xa9, 0x1f, 0x85, 0x7e, + 0xd0, 0xa2, 0xf5, 0xc5, 0x94, 0xbb, 0xf1, 0x87, 0x0b, 0xe6, 0x1d, 0x67, 0xfe, 0x09, 0x5a, 0x3c, + 0x30, 0xc3, 0x91, 0xbc, 0xe2, 0xc0, 0xb4, 0x0e, 0x54, 0xb2, 0x0e, 0xa1, 0x32, 0x60, 0xb3, 0x5a, + 0x50, 0x58, 0x94, 0xf3, 0xac, 0x11, 0xb6, 0x5d, 0xc9, 0xc2, 0x30, 0x27, 0x97, 0xbc, 0x1b, 0x20, + 0xda, 0xe4, 0x41, 0x41, 0x56, 0xd5, 0xca, 0xa1, 0xab, 0x3a, 0x2d, 0xe2, 0xdb, 0x8a, 0x03, 0x5a, + 0xdc, 0xc8, 0x55, 0x00, 0x31, 0x6d, 0x36, 0x7a, 0x1d, 0xca, 0x83, 0x32, 0xd5, 0xda, 0x1b, 0x55, + 0xe3, 0xaf, 0x6b, 0xcc, 0xfd, 0xbd, 0xb9, 0xfe, 0xdd, 0x2e, 0x8f, 0xc6, 0x5a, 0xc5, 0xc9, 0x07, + 0x60, 0x3c, 0xe9, 0xb6, 0xdb, 0x9e, 0x0e, 0xae, 0xac, 0x15, 0xb7, 0x22, 0x0a, 0xbe, 0x66, 0x6c, + 0x4a, 0x00, 0x2a, 0x89, 0x6e, 0x08, 0xa4, 0x9f, 0x9e, 0x3c, 0x07, 0x93, 0x74, 0x37, 0xa5, 0x71, + 0xe8, 0xb5, 0x6e, 0xe2, 0xaa, 0xda, 0x8e, 0xf3, 0xce, 0xbf, 0x60, 0xc1, 0x31, 0x43, 0x45, 0x5c, + 0xed, 0x79, 0x97, 0x38, 0x3d, 0x18, 0xcf, 0x5b, 0xf9, 0xd9, 0xee, 0xff, 0x94, 0x32, 0x1e, 0xc1, + 0x46, 0x4c, 0x29, 0x89, 0x60, 0x34, 0x8c, 0xea, 0xda, 0xe8, 0x5d, 0x29, 0xc6, 0xe8, 0x5d, 0x8f, + 0xea, 0xd6, 0xc9, 0x34, 0xfb, 0x4a, 0x50, 0xc8, 0xe1, 0x47, 0x77, 0xea, 0x8c, 0x93, 0x23, 0xa4, + 0x13, 0x54, 0xa4, 0x64, 0x7d, 0x74, 0x77, 0xc3, 0x16, 0x84, 0x59, 0xb9, 0x64, 0x1b, 0x46, 0xb7, + 0xa2, 0x24, 0x15, 0x7b, 0x95, 0x23, 0x7b, 0x61, 0x97, 0xa3, 0x24, 0xe5, 0x4b, 0x98, 0xae, 0x36, + 0x83, 0x24, 0x28, 0x64, 0xb8, 0xff, 0xe8, 0x64, 0x82, 0x2f, 0xb7, 0xbd, 0xd4, 0xdf, 0xba, 0xb0, + 0xc3, 0xf6, 0x8f, 0x57, 0x33, 0x07, 0x07, 0x3f, 0x66, 0x1f, 0x1c, 0xdc, 0xdf, 0x9b, 0x7b, 0xc3, + 0xb0, 0x54, 0xa1, 0xbb, 0x8c, 0xc3, 0x3c, 0x67, 0x61, 0x9d, 0x31, 0x7c, 0xc4, 0x81, 0x09, 0x4b, + 0x3d, 0xb9, 0xa0, 0x14, 0x18, 0xc3, 0xd6, 0xce, 0x95, 0x05, 0x44, 0x5b, 0xa4, 0xfb, 0x59, 0x07, + 0xc6, 0x6b, 0x9e, 0xbf, 0x1d, 0x35, 0x1a, 0xe4, 0x4d, 0x50, 0xa9, 0x77, 0xe5, 0x11, 0x8d, 0xa8, + 0x9f, 0x8e, 0xbc, 0x2f, 0x4b, 0x38, 0x6a, 0x0a, 0x36, 0x86, 0x1b, 0x9e, 0x9f, 0x46, 0x31, 0x57, + 0xbb, 0x2c, 0xc6, 0xf0, 0x45, 0x0e, 0x41, 0x89, 0x61, 0x9b, 0xf4, 0xb6, 0xb7, 0xab, 0x0a, 0xe7, + 0x23, 0x3f, 0xd7, 0x0c, 0x0a, 0x6d, 0x3a, 0xf7, 0x4f, 0x47, 0x61, 0x5c, 0x9e, 0xa6, 0x1e, 0xf8, + 0x34, 0x43, 0x79, 0xf1, 0xa5, 0xa1, 0x5e, 0x7c, 0x02, 0x63, 0x3e, 0x4f, 0xc4, 0x92, 0x4b, 0xe9, + 0x11, 0x63, 0x60, 0x52, 0x41, 0x91, 0xdb, 0x65, 0xd4, 0x12, 0xdf, 0x28, 0x45, 0x91, 0xcf, 0x38, + 0x70, 0xcc, 0x8f, 0xc2, 0x90, 0xfa, 0xc6, 0xce, 0x8f, 0x14, 0x71, 0xda, 0xb7, 0x94, 0x65, 0x6a, + 0x0e, 0x5d, 0x73, 0x08, 0xcc, 0x8b, 0x27, 0x2f, 0xc0, 0x94, 0x68, 0xb3, 0x5b, 0x99, 0xfd, 0xb1, + 0x39, 0x41, 0xb7, 0x91, 0x98, 0xa5, 0x25, 0xf3, 0x22, 0xce, 0x20, 0xcf, 0xaa, 0xc7, 0x4c, 0xf0, + 0xd1, 0x3a, 0xa5, 0xb6, 0x28, 0x48, 0x0c, 0x24, 0xa6, 0x8d, 0x98, 0x26, 0x5b, 0x48, 0x5f, 0xee, + 0xd2, 0x24, 0xe5, 0x6b, 0xcc, 0xf8, 0xc3, 0x9d, 0x8d, 0x61, 0x1f, 0x27, 0x1c, 0xc0, 0x9d, 0x6c, + 0x4b, 0x47, 0xb7, 0x52, 0xc4, 0x74, 0x92, 0xdd, 0x3c, 0xd4, 0xdf, 0x9d, 0x83, 0xd1, 0x64, 0xcb, + 0x8b, 0xeb, 0x7c, 0x6d, 0x2b, 0xd7, 0xaa, 0xcc, 0x96, 0xac, 0x33, 0x00, 0x0a, 0xb8, 0xfb, 0xdf, + 0x0e, 0x1c, 0x57, 0x63, 0xc5, 0xf3, 0xb7, 0x28, 0x2b, 0x4b, 0xde, 0x0e, 0xd3, 0xda, 0x9f, 0x5c, + 0x8a, 0xba, 0x32, 0x80, 0x55, 0x36, 0x11, 0x46, 0xcc, 0x60, 0x31, 0x47, 0x4d, 0x16, 0xa0, 0xca, + 0x54, 0x16, 0x45, 0xc5, 0xfc, 0xd3, 0x3e, 0xeb, 0xe2, 0xda, 0x8a, 0x2c, 0x65, 0x68, 0x48, 0x04, + 0x33, 0x2d, 0x2f, 0x49, 0xb9, 0x06, 0xcc, 0xbd, 0x7c, 0xc8, 0x23, 0x4a, 0x9e, 0x07, 0xb3, 0x9a, + 0x67, 0x84, 0xfd, 0xbc, 0xdd, 0x6f, 0x8c, 0xc0, 0x54, 0x66, 0x8a, 0x30, 0xf3, 0xd2, 0x4d, 0xd8, + 0x1a, 0xa8, 0xf7, 0xda, 0xda, 0xbc, 0xdc, 0x94, 0x70, 0xd4, 0x14, 0x8c, 0xba, 0xe3, 0x25, 0xc9, + 0xdd, 0x28, 0xae, 0xcb, 0x39, 0xad, 0xa9, 0xd7, 0x24, 0x1c, 0x35, 0x05, 0x33, 0x34, 0x9b, 0xd4, + 0x8b, 0x69, 0xcc, 0x4f, 0xf5, 0xf3, 0x86, 0xa6, 0x66, 0x50, 0x68, 0xd3, 0xf1, 0xd9, 0x99, 0xb6, + 0x92, 0xa5, 0x56, 0x40, 0xc3, 0x54, 0xa8, 0x59, 0xcc, 0xec, 0xdc, 0x58, 0x5d, 0xb7, 0x99, 0x9a, + 0xd9, 0x99, 0x43, 0x60, 0x5e, 0x3c, 0xf9, 0x98, 0x03, 0x53, 0xde, 0xdd, 0xc4, 0xa4, 0x8d, 0xf2, + 0xe9, 0x79, 0x64, 0x6b, 0x95, 0xc9, 0x44, 0xad, 0xcd, 0xb0, 0x79, 0x9e, 0x01, 0x61, 0x56, 0x28, + 0xf9, 0x82, 0x03, 0x84, 0xee, 0x52, 0x7f, 0x2d, 0x8e, 0x76, 0x82, 0xba, 0xea, 0x43, 0xe9, 0x07, + 0x1f, 0xd1, 0xed, 0xba, 0xd0, 0xc7, 0x57, 0x4c, 0xef, 0x7e, 0x38, 0x0e, 0xd0, 0xc1, 0xfd, 0x9b, + 0x32, 0x4c, 0x58, 0xb3, 0x72, 0xa0, 0x89, 0x75, 0xbe, 0xcf, 0x4c, 0x6c, 0xe9, 0x10, 0x26, 0xf6, + 0xc3, 0x50, 0xf5, 0x95, 0xa1, 0x28, 0x26, 0xcd, 0x35, 0x6f, 0x7e, 0x8c, 0xad, 0xd0, 0x20, 0x34, + 0x32, 0xc9, 0x25, 0x98, 0xb1, 0xd8, 0x48, 0x23, 0x33, 0xc2, 0x8d, 0x8c, 0x8e, 0x38, 0x2c, 0xe6, + 0x09, 0xb0, 0xbf, 0x0c, 0x79, 0x96, 0xb9, 0x37, 0x81, 0xac, 0x97, 0xd8, 0xce, 0xc9, 0x14, 0xd2, + 0xc5, 0xb5, 0x15, 0x05, 0x46, 0x9b, 0xc6, 0xfd, 0x86, 0xa3, 0x3b, 0xf7, 0x31, 0x64, 0x0f, 0xdc, + 0xc9, 0x66, 0x0f, 0x5c, 0x28, 0xa4, 0x99, 0x87, 0x64, 0x0e, 0x5c, 0x87, 0xf1, 0xa5, 0xa8, 0xdd, + 0xf6, 0xc2, 0x3a, 0x79, 0x1d, 0x8c, 0xfb, 0xe2, 0xa7, 0xdc, 0x2f, 0xf0, 0xe3, 0x64, 0x89, 0x45, + 0x85, 0x23, 0x4f, 0xc1, 0x88, 0x17, 0x37, 0xd5, 0x1e, 0x81, 0x9f, 0x8e, 0x2c, 0xc6, 0xcd, 0x04, + 0x39, 0xd4, 0xfd, 0x5c, 0x09, 0x60, 0x29, 0x6a, 0x77, 0xbc, 0x98, 0xd6, 0x37, 0xa2, 0xff, 0x0b, + 0x16, 0x0a, 0xd7, 0xf1, 0x93, 0x0e, 0x10, 0xd6, 0x2a, 0x51, 0x48, 0x43, 0x73, 0x22, 0xc3, 0xd6, + 0x4b, 0x5f, 0x41, 0xe5, 0xe2, 0x63, 0xe6, 0x80, 0x42, 0xa0, 0xa1, 0x39, 0x80, 0x3b, 0xf9, 0xb4, + 0x0a, 0x36, 0x97, 0xb3, 0x27, 0xdd, 0xfc, 0x74, 0x52, 0xc6, 0x9e, 0xdd, 0xcf, 0x97, 0xe0, 0xb4, + 0x30, 0x5b, 0xd7, 0xbc, 0xd0, 0x6b, 0xd2, 0x36, 0xd3, 0xea, 0xa0, 0x61, 0x67, 0x9f, 0xf9, 0x31, + 0x81, 0x3a, 0xd8, 0x3e, 0xea, 0xe0, 0x14, 0x83, 0x4a, 0x0c, 0xa3, 0x95, 0x30, 0x48, 0x91, 0x33, + 0x27, 0x09, 0x54, 0xd4, 0xc5, 0x05, 0x69, 0x6c, 0x0a, 0x12, 0xa4, 0xe7, 0xdd, 0x25, 0xc9, 0x1e, + 0xb5, 0x20, 0xf7, 0x2b, 0x0e, 0xe4, 0x8d, 0x28, 0x77, 0xf4, 0x45, 0x6a, 0x5a, 0xde, 0xd1, 0xcf, + 0x66, 0x92, 0x1d, 0x22, 0x31, 0xeb, 0xbd, 0x30, 0xe1, 0xa5, 0x29, 0x6d, 0x77, 0x84, 0xd7, 0x59, + 0x7e, 0xb8, 0xc8, 0xc6, 0xb5, 0xa8, 0x1e, 0x34, 0x02, 0xee, 0x6d, 0xda, 0xec, 0xdc, 0x17, 0xa1, + 0xa2, 0x82, 0xf9, 0x07, 0xe8, 0xcc, 0xa7, 0x33, 0x67, 0x13, 0x43, 0x86, 0xcb, 0xfd, 0x12, 0x0c, + 0x58, 0x05, 0x59, 0x95, 0x8d, 0xbd, 0xc8, 0x54, 0xf9, 0x70, 0x36, 0x83, 0xec, 0x8a, 0x83, 0x0c, + 0xb1, 0x85, 0x7e, 0x57, 0xd1, 0xab, 0xb8, 0x39, 0xdb, 0x98, 0x90, 0xfa, 0xe9, 0xf3, 0x0d, 0x72, + 0x1e, 0xc0, 0x98, 0x79, 0x79, 0xa0, 0xaf, 0x83, 0x70, 0x66, 0x35, 0x40, 0x8b, 0x8a, 0x39, 0x75, + 0x41, 0x98, 0xa4, 0x5e, 0xab, 0x75, 0x39, 0x08, 0x53, 0xb9, 0x4d, 0xd1, 0x26, 0x60, 0xc5, 0xa0, + 0xd0, 0xa6, 0x3b, 0xf3, 0x16, 0xab, 0x5f, 0x0e, 0x73, 0x46, 0xf4, 0xc9, 0x12, 0x4c, 0x5f, 0x0a, + 0xbb, 0x6b, 0x97, 0xd6, 0xba, 0x9b, 0xad, 0xc0, 0xbf, 0x4a, 0x7b, 0xac, 0xd3, 0xb6, 0x69, 0x6f, + 0x65, 0x59, 0x36, 0xbb, 0xee, 0xb4, 0xab, 0x0c, 0x88, 0x02, 0xc7, 0xd4, 0x6c, 0x04, 0x61, 0x93, + 0xc6, 0x9d, 0x38, 0x90, 0xde, 0xb8, 0xa5, 0xe6, 0x45, 0x83, 0x42, 0x9b, 0x8e, 0xf1, 0x8e, 0xee, + 0x86, 0x34, 0xce, 0xdb, 0x8f, 0x1b, 0x0c, 0x88, 0x02, 0xc7, 0x88, 0xd2, 0xb8, 0x9b, 0xa4, 0xb2, + 0xc5, 0x34, 0xd1, 0x06, 0x03, 0xa2, 0xc0, 0xb1, 0xe1, 0x91, 0x74, 0x37, 0x79, 0x80, 0x2d, 0x77, + 0xd4, 0xb9, 0x2e, 0xc0, 0xa8, 0xf0, 0x8c, 0x74, 0x9b, 0xf6, 0x96, 0xd9, 0x6a, 0x9a, 0xcb, 0x4c, + 0xb8, 0x2a, 0xc0, 0xa8, 0xf0, 0xee, 0x3f, 0x38, 0x40, 0xb2, 0xcd, 0xf1, 0x18, 0x16, 0xe4, 0x97, + 0xb3, 0x0b, 0xf2, 0x11, 0x63, 0xa1, 0x59, 0xf5, 0x87, 0xac, 0xcb, 0xbf, 0xea, 0xc0, 0xa4, 0x1d, + 0x16, 0x27, 0xcd, 0x9c, 0x21, 0xba, 0x91, 0x35, 0x44, 0xf7, 0xf7, 0xe6, 0x7e, 0x62, 0xd0, 0xbd, + 0xba, 0x66, 0x90, 0x46, 0x9d, 0xe4, 0xcd, 0x34, 0x6c, 0x06, 0x21, 0xe5, 0x41, 0x1f, 0x11, 0x4e, + 0xcf, 0xc4, 0xdc, 0x97, 0xa2, 0x3a, 0x7d, 0x08, 0x4b, 0xe6, 0xde, 0x86, 0x99, 0xbe, 0x74, 0x94, + 0x03, 0x18, 0x9d, 0x7d, 0x93, 0x0d, 0xdd, 0x4f, 0x39, 0x30, 0x95, 0xc9, 0xe6, 0x29, 0xc8, 0x94, + 0xf1, 0x59, 0x11, 0xf1, 0x13, 0x95, 0x38, 0x08, 0x45, 0xc8, 0xa5, 0x62, 0xcd, 0x0a, 0x83, 0x42, + 0x9b, 0xce, 0xfd, 0x6c, 0x09, 0x2a, 0x2a, 0x38, 0x77, 0x00, 0x55, 0x3e, 0xe1, 0xc0, 0x94, 0xde, + 0x1a, 0x73, 0x87, 0xb9, 0x90, 0x8c, 0x0e, 0xa6, 0x81, 0x3e, 0x76, 0x63, 0x0e, 0xb3, 0xf6, 0xdc, + 0xd1, 0x16, 0x86, 0x59, 0xd9, 0xe4, 0x16, 0x40, 0xd2, 0x4b, 0x52, 0xda, 0xb6, 0x5c, 0x77, 0xd7, + 0x9a, 0x1d, 0xf3, 0x7e, 0x14, 0x53, 0x36, 0x17, 0xae, 0x47, 0x75, 0xba, 0xae, 0x29, 0x8d, 0x21, + 0x34, 0x30, 0xb4, 0x38, 0xb9, 0xbf, 0x55, 0x82, 0xe3, 0x79, 0x95, 0xc8, 0x7b, 0x60, 0x52, 0x49, + 0xb7, 0xae, 0x13, 0xaa, 0x88, 0xe4, 0x24, 0x5a, 0xb8, 0xfb, 0x7b, 0x73, 0x73, 0xfd, 0xf7, 0x29, + 0xe7, 0x6d, 0x12, 0xcc, 0x30, 0x13, 0xf1, 0x09, 0x19, 0x51, 0xa9, 0xf5, 0x16, 0x3b, 0x1d, 0x19, + 0x64, 0xb0, 0xe2, 0x13, 0x36, 0x16, 0x73, 0xd4, 0x64, 0x0d, 0x4e, 0x5a, 0x90, 0xeb, 0x34, 0x68, + 0x6e, 0x6d, 0x46, 0xb1, 0xc8, 0x3a, 0x2f, 0xd7, 0x9e, 0x92, 0x5c, 0x4e, 0xe2, 0x00, 0x1a, 0x1c, + 0x58, 0x92, 0xbc, 0x09, 0x2a, 0xbe, 0xd7, 0xf1, 0xfc, 0x20, 0xed, 0xc9, 0xbd, 0x88, 0xb6, 0x23, + 0x4b, 0x12, 0x8e, 0x9a, 0xc2, 0xbd, 0x06, 0x23, 0x07, 0x1c, 0x41, 0x07, 0x5a, 0x97, 0x5f, 0x84, + 0x0a, 0x63, 0xc7, 0xec, 0x46, 0x51, 0x2c, 0x23, 0xa8, 0xa8, 0x4b, 0x08, 0xc4, 0x85, 0x72, 0xe0, + 0xa9, 0x10, 0x90, 0xae, 0xd6, 0x4a, 0x92, 0x74, 0xb9, 0xd7, 0xc1, 0x90, 0xe4, 0x69, 0x28, 0xd3, + 0xdd, 0x4e, 0x3e, 0xd6, 0x73, 0x61, 0xb7, 0x13, 0xc4, 0x34, 0x61, 0x44, 0x74, 0xb7, 0x43, 0xce, + 0x40, 0x29, 0xa8, 0xcb, 0x05, 0x05, 0x24, 0x4d, 0x69, 0x65, 0x19, 0x4b, 0x41, 0xdd, 0xdd, 0x85, + 0xaa, 0xbe, 0xf5, 0x40, 0xb6, 0x95, 0x9d, 0x75, 0x8a, 0x88, 0xa6, 0x2b, 0xbe, 0x43, 0x2c, 0x6c, + 0x17, 0xc0, 0xe4, 0x81, 0x15, 0x65, 0x5f, 0xce, 0xc1, 0x88, 0x1f, 0xc9, 0x94, 0xcb, 0x8a, 0x61, + 0xc3, 0x0d, 0x2c, 0xc7, 0xb8, 0xb7, 0x61, 0xfa, 0x6a, 0x18, 0xdd, 0x0d, 0xd9, 0xc2, 0x77, 0x31, + 0xa0, 0xad, 0x3a, 0x63, 0xdc, 0x60, 0x3f, 0xf2, 0xcb, 0x39, 0xc7, 0xa2, 0xc0, 0xe9, 0xab, 0x01, + 0xa5, 0x61, 0x57, 0x03, 0xdc, 0x5f, 0x70, 0xe0, 0x78, 0x3e, 0xe7, 0xeb, 0x7b, 0xb6, 0xc3, 0xf8, + 0x08, 0x53, 0x46, 0x25, 0x15, 0xdd, 0xe8, 0x88, 0xe3, 0xcb, 0xe7, 0x61, 0x72, 0xb3, 0x1b, 0xb4, + 0xea, 0xf2, 0x5b, 0xea, 0xa3, 0xd3, 0xa6, 0x6a, 0x16, 0x0e, 0x33, 0x94, 0xcc, 0x4f, 0xdb, 0x0c, + 0x42, 0x2f, 0xee, 0xad, 0x99, 0x75, 0x43, 0x9b, 0xa7, 0x9a, 0xc6, 0xa0, 0x45, 0xe5, 0xfe, 0x55, + 0x19, 0xcc, 0xf5, 0x0b, 0x12, 0xc8, 0xd3, 0x71, 0xa7, 0x88, 0xb0, 0xd5, 0x7a, 0x2f, 0xf4, 0xcd, + 0x45, 0x8f, 0x4a, 0xee, 0x70, 0xfc, 0xe3, 0x0e, 0xf3, 0x10, 0x83, 0x34, 0xf0, 0xb8, 0xb1, 0x90, + 0x1b, 0xa5, 0xb5, 0x82, 0x0e, 0x50, 0x57, 0x04, 0xe7, 0x28, 0xb6, 0x7d, 0x4e, 0x2d, 0x0c, 0x6d, + 0xc9, 0xe4, 0x25, 0x19, 0x72, 0x2e, 0x17, 0x96, 0x5b, 0x51, 0xc9, 0xc5, 0x99, 0x3b, 0x30, 0x1a, + 0xd3, 0x34, 0x56, 0x59, 0x2d, 0x57, 0x8f, 0x7a, 0x00, 0x97, 0xc6, 0xbd, 0xf5, 0x94, 0x6d, 0xc6, + 0x9a, 0x96, 0x63, 0xc4, 0xc1, 0x28, 0x04, 0xb9, 0x09, 0x90, 0xfe, 0xb6, 0x38, 0x64, 0x14, 0x77, + 0x01, 0xaa, 0x5e, 0x37, 0x8d, 0xda, 0xac, 0x99, 0x78, 0xf7, 0x54, 0xac, 0x38, 0xb5, 0x42, 0xa0, + 0xa1, 0x71, 0x5f, 0x1d, 0x85, 0xdc, 0x71, 0x35, 0xd9, 0xb5, 0xaf, 0x0e, 0x39, 0xc5, 0x5e, 0x1d, + 0xd2, 0xca, 0x0c, 0xba, 0x3e, 0x44, 0x9a, 0x30, 0xda, 0xd9, 0xf2, 0x12, 0x35, 0x47, 0x5f, 0x54, + 0xcd, 0xb4, 0xc6, 0x80, 0xf7, 0xf7, 0xe6, 0xde, 0x79, 0x30, 0x3f, 0x90, 0x8d, 0xd5, 0x05, 0x91, + 0xbb, 0x67, 0x44, 0x73, 0x1e, 0x28, 0xf8, 0xdb, 0x9e, 0x60, 0x79, 0x9f, 0x3d, 0xed, 0x47, 0x1d, + 0x91, 0xe3, 0x84, 0x34, 0xe9, 0xb6, 0x52, 0x39, 0x1a, 0x5e, 0x2c, 0x70, 0x96, 0x09, 0xc6, 0x26, + 0xd9, 0x49, 0x7c, 0xa3, 0x25, 0x94, 0xbc, 0x07, 0xaa, 0x49, 0xea, 0xc5, 0xe9, 0x43, 0xa6, 0x46, + 0xe8, 0x46, 0x5f, 0x57, 0x4c, 0xd0, 0xf0, 0x23, 0xef, 0x06, 0x68, 0x04, 0x61, 0x90, 0x6c, 0x3d, + 0xe4, 0x49, 0x11, 0x57, 0xfc, 0xa2, 0xe6, 0x80, 0x16, 0x37, 0x66, 0xdd, 0xf8, 0xd8, 0x16, 0x21, + 0xcd, 0x0a, 0x5f, 0x4b, 0xb5, 0x75, 0x43, 0x8d, 0x41, 0x8b, 0xca, 0xfd, 0x10, 0x9c, 0xc8, 0x5f, + 0xfc, 0x95, 0x5b, 0xc3, 0x66, 0x1c, 0x75, 0x3b, 0xf9, 0xb5, 0x84, 0x5f, 0x0c, 0x45, 0x81, 0x63, + 0x36, 0x7e, 0x3b, 0x08, 0xeb, 0x79, 0x1b, 0x7f, 0x35, 0x08, 0xeb, 0xc8, 0x31, 0x07, 0xb8, 0x53, + 0xf5, 0x87, 0x0e, 0x9c, 0xdb, 0xef, 0x7e, 0x32, 0xdb, 0xf6, 0xdf, 0xf5, 0xe2, 0x50, 0xde, 0x97, + 0xe0, 0xb6, 0xe3, 0xb6, 0x17, 0x87, 0xc8, 0xa1, 0xa4, 0x07, 0x63, 0x22, 0x1d, 0x4c, 0x7a, 0xc7, + 0x2f, 0x16, 0x7b, 0x5b, 0x9a, 0xed, 0xad, 0x74, 0xb4, 0x46, 0xa4, 0xa2, 0xa1, 0x14, 0xe8, 0xbe, + 0xea, 0x00, 0xb9, 0xb1, 0x43, 0xe3, 0x38, 0xa8, 0x5b, 0x09, 0x6c, 0xe4, 0x39, 0x98, 0xbc, 0xb3, + 0x7e, 0xe3, 0xfa, 0x5a, 0x14, 0x84, 0x3c, 0x0f, 0xdb, 0x4a, 0x9b, 0xb8, 0x62, 0xc1, 0x31, 0x43, + 0x45, 0x96, 0x60, 0xe6, 0xce, 0xcb, 0x6c, 0xc9, 0xb9, 0xb0, 0xdb, 0x89, 0x69, 0x92, 0xe8, 0x37, + 0x06, 0xaa, 0xe2, 0x60, 0xea, 0xca, 0x8b, 0x39, 0x24, 0xf6, 0xd3, 0xbb, 0x5f, 0x2e, 0xc1, 0x84, + 0x75, 0x25, 0xff, 0x00, 0xfe, 0x48, 0xee, 0x15, 0x81, 0xd2, 0x01, 0x5f, 0x11, 0x78, 0x06, 0x2a, + 0x9d, 0xa8, 0x15, 0xf8, 0x81, 0x4e, 0xb0, 0x9e, 0xe4, 0xa7, 0x57, 0x12, 0x86, 0x1a, 0x4b, 0xee, + 0x42, 0x55, 0xdf, 0x8c, 0x95, 0x29, 0x57, 0x45, 0x79, 0x64, 0x7a, 0xae, 0x99, 0x1b, 0xaf, 0x46, + 0x16, 0x71, 0x61, 0x8c, 0x0f, 0x54, 0x15, 0x9b, 0xe7, 0x67, 0xf8, 0x7c, 0x04, 0x27, 0x28, 0x31, + 0xee, 0xbf, 0x8c, 0x42, 0x15, 0x69, 0x27, 0x5a, 0x8a, 0x69, 0x3d, 0x21, 0xaf, 0x85, 0x72, 0x37, + 0x6e, 0xc9, 0xc6, 0xd2, 0x61, 0x9e, 0x9b, 0xb8, 0x8a, 0x0c, 0x9e, 0x59, 0x1d, 0x4a, 0x87, 0x3a, + 0xe3, 0x2b, 0xef, 0x7b, 0xc6, 0xf7, 0x02, 0x4c, 0x25, 0xc9, 0xd6, 0x5a, 0x1c, 0xec, 0x78, 0x29, + 0x1b, 0x73, 0x32, 0x26, 0x62, 0x0e, 0x55, 0xd6, 0x2f, 0x1b, 0x24, 0x66, 0x69, 0xc9, 0x25, 0x98, + 0x31, 0x27, 0x6d, 0x34, 0x4e, 0x79, 0x08, 0x44, 0x44, 0x4b, 0xf4, 0x99, 0x86, 0x39, 0x9b, 0x93, + 0x04, 0xd8, 0x5f, 0x86, 0x2c, 0xc3, 0xf1, 0x0c, 0x90, 0x29, 0x22, 0x42, 0x29, 0xb3, 0x92, 0xcf, + 0xf1, 0x0c, 0x1f, 0xa6, 0x4b, 0x5f, 0x09, 0x72, 0x0d, 0x4e, 0x88, 0xfe, 0xe5, 0x37, 0xaa, 0x75, + 0x8d, 0xc6, 0x39, 0xa3, 0xff, 0x27, 0x19, 0x9d, 0xb8, 0xd4, 0x4f, 0x82, 0x83, 0xca, 0xb1, 0x11, + 0xaa, 0xc1, 0x2b, 0xcb, 0xd2, 0xb0, 0xe9, 0x11, 0xaa, 0xd9, 0xac, 0xd4, 0xd1, 0xa6, 0x23, 0xef, + 0x82, 0x27, 0xcd, 0xa7, 0x88, 0xa0, 0x89, 0xd5, 0x7e, 0x59, 0x9e, 0x66, 0xcf, 0x49, 0x16, 0x4f, + 0x5e, 0x1a, 0x48, 0x56, 0xc7, 0x61, 0xe5, 0xc9, 0x26, 0x9c, 0xd1, 0xa8, 0x0b, 0x6c, 0xf6, 0x76, + 0xe2, 0x20, 0xa1, 0x35, 0x2f, 0xa1, 0x37, 0xe3, 0x16, 0xcf, 0xde, 0xaa, 0x9a, 0x77, 0x05, 0x2e, + 0x05, 0xe9, 0xe5, 0x41, 0x94, 0xb8, 0x8a, 0x0f, 0xe0, 0xc2, 0x9c, 0x0b, 0x1a, 0x7a, 0x9b, 0x2d, + 0x7a, 0x63, 0x69, 0x85, 0xdf, 0x74, 0xb3, 0x9c, 0x8b, 0x0b, 0x0a, 0x81, 0x86, 0x46, 0xbb, 0xf6, + 0x93, 0x43, 0x5d, 0xfb, 0x6f, 0x39, 0x30, 0xa5, 0x07, 0xfb, 0x63, 0x88, 0x77, 0xb5, 0xb2, 0xf1, + 0xae, 0x4b, 0x47, 0xf5, 0xea, 0xa4, 0xe6, 0x43, 0x36, 0x62, 0x7f, 0x54, 0x05, 0xe0, 0x2f, 0xb5, + 0x04, 0x3c, 0xdb, 0xf2, 0x1c, 0x8c, 0xc4, 0xb4, 0x13, 0xe5, 0x2d, 0x1f, 0xa3, 0x40, 0x8e, 0xf9, + 0xfe, 0x9d, 0xce, 0x83, 0xce, 0x7c, 0x47, 0xbf, 0xb7, 0x67, 0xbe, 0xeb, 0x70, 0x2a, 0x08, 0x13, + 0xea, 0x77, 0x63, 0xb9, 0xd0, 0x5d, 0x8e, 0x12, 0x6d, 0x1d, 0x2a, 0xb5, 0xd7, 0x4a, 0x46, 0xa7, + 0x56, 0x06, 0x11, 0xe1, 0xe0, 0xb2, 0xac, 0x49, 0x15, 0x42, 0x5e, 0xeb, 0x30, 0xe1, 0x01, 0x09, + 0x47, 0x4d, 0x61, 0x26, 0xc4, 0x6a, 0x43, 0xdd, 0xdb, 0xc8, 0x4d, 0x88, 0xd5, 0x8b, 0xeb, 0x68, + 0x68, 0x06, 0x5b, 0xc5, 0x6a, 0x41, 0x56, 0x11, 0x0e, 0x6d, 0x15, 0xd5, 0xfc, 0x9c, 0x18, 0x7a, + 0x2b, 0x5f, 0x2d, 0xd6, 0x93, 0x43, 0x17, 0xeb, 0xb7, 0xc3, 0x74, 0x10, 0x6e, 0xd1, 0x38, 0x48, + 0x69, 0x9d, 0xcf, 0x85, 0xd9, 0x29, 0xde, 0x10, 0x3a, 0x72, 0xb5, 0x92, 0xc1, 0x62, 0x8e, 0x3a, + 0x6b, 0x54, 0xa6, 0x0f, 0x60, 0x54, 0x86, 0x98, 0xf2, 0x63, 0xc5, 0x98, 0xf2, 0xe3, 0x47, 0x37, + 0xe5, 0x33, 0x8f, 0xd4, 0x94, 0x93, 0x42, 0x4c, 0xf9, 0xd3, 0x30, 0xda, 0x89, 0xa3, 0xdd, 0xde, + 0xec, 0x89, 0xac, 0x37, 0xbd, 0xc6, 0x80, 0x28, 0x70, 0xee, 0x2b, 0x25, 0x38, 0x65, 0xcc, 0x17, + 0x1b, 0x34, 0x41, 0x83, 0x4d, 0x60, 0x7e, 0x63, 0x4e, 0xe4, 0x50, 0x58, 0x91, 0x50, 0x13, 0x54, + 0xd5, 0x18, 0xb4, 0xa8, 0x78, 0x40, 0x91, 0xc6, 0x3c, 0x1d, 0x33, 0x6f, 0xdb, 0x96, 0x24, 0x1c, + 0x35, 0x05, 0x7f, 0xbb, 0x8d, 0xc6, 0xa9, 0x3c, 0x50, 0xc9, 0x27, 0x18, 0x2d, 0x19, 0x14, 0xda, + 0x74, 0xcc, 0x07, 0xf4, 0xd5, 0xbc, 0x62, 0xf6, 0x6d, 0x52, 0xf8, 0x80, 0x7a, 0x2a, 0x69, 0xac, + 0x52, 0x87, 0x47, 0x8e, 0x47, 0xfb, 0xd5, 0xe1, 0x91, 0x00, 0x4d, 0xe1, 0xfe, 0x97, 0x03, 0xaf, + 0x19, 0xd8, 0x14, 0x8f, 0x61, 0xcd, 0xda, 0xcd, 0xae, 0x59, 0xeb, 0x47, 0x5f, 0xb3, 0xfa, 0x6a, + 0x31, 0x64, 0xfd, 0xfa, 0x6b, 0x07, 0xa6, 0x0d, 0xfd, 0x63, 0xa8, 0x6a, 0x50, 0xe8, 0x2b, 0x6c, + 0x46, 0x75, 0x91, 0x26, 0x98, 0xa9, 0xdb, 0xb7, 0x78, 0xdd, 0xc4, 0x86, 0x6a, 0xd1, 0x57, 0x8f, + 0x94, 0xec, 0xb3, 0x33, 0xe9, 0xc1, 0x18, 0xbf, 0x56, 0x9a, 0x14, 0xb3, 0xb1, 0xcb, 0xca, 0xe7, + 0xb1, 0x4d, 0xb3, 0xb1, 0xe3, 0x9f, 0x09, 0x4a, 0x81, 0x3c, 0x59, 0x38, 0x48, 0x98, 0x11, 0xac, + 0xcb, 0x18, 0xac, 0x49, 0x16, 0x96, 0x70, 0xd4, 0x14, 0x6e, 0x1b, 0x66, 0xb3, 0xcc, 0x97, 0x69, + 0x83, 0xc7, 0xcf, 0x0e, 0x54, 0xcd, 0x05, 0xa8, 0x7a, 0xbc, 0xd4, 0x6a, 0xd7, 0xcb, 0xbf, 0x54, + 0xb2, 0xa8, 0x10, 0x68, 0x68, 0xdc, 0xdf, 0x74, 0xe0, 0xc4, 0x80, 0xca, 0x14, 0x18, 0x7b, 0x4e, + 0x8d, 0x15, 0x18, 0xf2, 0x7a, 0x4c, 0x9d, 0x36, 0x3c, 0x15, 0xa1, 0xb1, 0x02, 0x3a, 0xcb, 0x02, + 0x8c, 0x0a, 0xef, 0xfe, 0xab, 0x03, 0xc7, 0xb2, 0xba, 0x26, 0xe4, 0x0a, 0x10, 0x51, 0x99, 0xe5, + 0x20, 0xf1, 0xa3, 0x1d, 0x1a, 0xf7, 0x58, 0xcd, 0x85, 0xd6, 0x67, 0x24, 0x27, 0xb2, 0xd8, 0x47, + 0x81, 0x03, 0x4a, 0x91, 0x4f, 0xf1, 0xfc, 0x1c, 0xd5, 0xda, 0x6a, 0xa4, 0xdc, 0x2a, 0x72, 0xa4, + 0x98, 0xce, 0xb4, 0xb7, 0xc5, 0x5a, 0x24, 0xda, 0xf2, 0xdd, 0x6f, 0x8f, 0x80, 0x3e, 0x9c, 0xe2, + 0xb1, 0x80, 0x82, 0x22, 0x29, 0x99, 0xe7, 0x6c, 0xca, 0x87, 0x78, 0xce, 0x66, 0xe4, 0x41, 0x1b, + 0x7f, 0xf1, 0xb6, 0x8a, 0x71, 0x30, 0x2d, 0xa3, 0xbf, 0x61, 0x50, 0x68, 0xd3, 0x31, 0x4d, 0x5a, + 0xc1, 0x0e, 0x15, 0x85, 0xc6, 0xb2, 0x9a, 0xac, 0x2a, 0x04, 0x1a, 0x1a, 0xa6, 0x49, 0x3d, 0x68, + 0x34, 0xe4, 0xf6, 0x4f, 0x6b, 0xc2, 0x5a, 0x07, 0x39, 0x86, 0x51, 0x6c, 0x45, 0xd1, 0xb6, 0x74, + 0xea, 0x34, 0xc5, 0xe5, 0x28, 0xda, 0x46, 0x8e, 0x61, 0x6e, 0x48, 0x18, 0xc5, 0x6d, 0xaf, 0x15, + 0xbc, 0x9f, 0xd6, 0xb5, 0x14, 0xe9, 0xcc, 0x69, 0x37, 0xe4, 0x7a, 0x3f, 0x09, 0x0e, 0x2a, 0xc7, + 0x46, 0x60, 0x27, 0xa6, 0xf5, 0xc0, 0x4f, 0x6d, 0x6e, 0x90, 0x1d, 0x81, 0x6b, 0x7d, 0x14, 0x38, + 0xa0, 0x14, 0x59, 0x84, 0x63, 0xea, 0x70, 0x51, 0x25, 0x80, 0x08, 0x0f, 0x4f, 0x3b, 0xd7, 0x98, + 0x45, 0x63, 0x9e, 0x9e, 0x59, 0x9b, 0xb6, 0x4c, 0xc3, 0xe1, 0xbe, 0x9f, 0x65, 0x6d, 0x54, 0x7a, + 0x0e, 0x6a, 0x0a, 0xf7, 0xb7, 0x4b, 0x6c, 0x75, 0x1c, 0x72, 0x6b, 0xf2, 0xb1, 0x45, 0xee, 0xb2, + 0x23, 0x72, 0xe4, 0x00, 0x23, 0xf2, 0x39, 0x98, 0xbc, 0x93, 0x44, 0xa1, 0x8e, 0x8a, 0x8d, 0x0e, + 0x8d, 0x8a, 0x59, 0x54, 0x83, 0xa3, 0x62, 0x63, 0x87, 0x8c, 0x8a, 0xfd, 0xd9, 0x28, 0x9c, 0xd6, + 0xe7, 0xc1, 0x34, 0xbd, 0x1b, 0xc5, 0xdb, 0x41, 0xd8, 0xe4, 0x67, 0xa8, 0x5f, 0x72, 0x60, 0x52, + 0x0c, 0x6f, 0x79, 0xbf, 0x5c, 0x9c, 0x19, 0x36, 0x0a, 0xba, 0x02, 0x94, 0x11, 0x36, 0xbf, 0x61, + 0x09, 0xca, 0x5d, 0xf6, 0xb7, 0x51, 0x98, 0xd1, 0x88, 0x7c, 0x10, 0x40, 0x3d, 0x82, 0xd4, 0x28, + 0xe8, 0x29, 0x28, 0xa5, 0x1f, 0xd2, 0x86, 0x71, 0x25, 0x37, 0xb4, 0x10, 0xb4, 0x04, 0x92, 0x57, + 0x1c, 0x18, 0x6b, 0x89, 0xb6, 0x11, 0x07, 0x40, 0x2f, 0x3d, 0x92, 0xb6, 0xb1, 0x5b, 0x45, 0x2f, + 0xcb, 0xb2, 0x3d, 0xa4, 0x7c, 0x82, 0x30, 0x1e, 0x84, 0x4d, 0xd6, 0xad, 0x32, 0x90, 0xf8, 0x86, + 0x41, 0xf9, 0x07, 0xab, 0x91, 0x57, 0xaf, 0x79, 0x2d, 0x2f, 0xf4, 0x69, 0xbc, 0x22, 0xc8, 0xed, + 0xa7, 0x68, 0x38, 0x00, 0x15, 0xa3, 0xbe, 0x3b, 0x6e, 0xa3, 0x07, 0xb9, 0xe3, 0x76, 0xe6, 0x1d, + 0x30, 0xd3, 0xd7, 0x99, 0x87, 0xba, 0xf9, 0xff, 0xe3, 0x30, 0xf1, 0x90, 0x45, 0xdd, 0x3f, 0x1e, + 0x33, 0x6b, 0xcc, 0xf5, 0xa8, 0x2e, 0x6e, 0x5a, 0xc5, 0xa6, 0x47, 0xa5, 0xab, 0x58, 0xe0, 0x10, + 0xb1, 0x9e, 0xb3, 0xd1, 0x40, 0xb4, 0x45, 0xb2, 0x31, 0xda, 0xf1, 0x62, 0x1a, 0x3e, 0xea, 0x31, + 0xba, 0xa6, 0x85, 0xa0, 0x25, 0x90, 0x6c, 0x65, 0x4e, 0x28, 0x2f, 0x1e, 0xfd, 0x84, 0x92, 0x79, + 0xaf, 0x03, 0x6f, 0xc4, 0x7c, 0xc6, 0x81, 0xe9, 0x30, 0x33, 0x72, 0xe5, 0x29, 0xd5, 0xc6, 0xa3, + 0x98, 0x15, 0xe2, 0x86, 0x6b, 0x16, 0x86, 0x39, 0xf9, 0x83, 0x56, 0xa0, 0xd1, 0x43, 0xae, 0x40, + 0xe6, 0xca, 0xe6, 0xd8, 0xb0, 0x2b, 0x9b, 0x24, 0xd4, 0x97, 0xb5, 0xc7, 0x0b, 0xbf, 0xac, 0x0d, + 0x03, 0x2e, 0x6a, 0xdf, 0x86, 0xaa, 0x1f, 0x53, 0x2f, 0x7d, 0xc8, 0x7b, 0xbb, 0xfc, 0x01, 0xb1, + 0x25, 0xc5, 0x00, 0x0d, 0x2f, 0xf7, 0x2f, 0xcb, 0x70, 0x5c, 0xb5, 0x88, 0x3a, 0xbd, 0x61, 0xcb, + 0x99, 0x90, 0x6b, 0x7c, 0x51, 0xbd, 0x9c, 0x5d, 0x56, 0x08, 0x34, 0x34, 0xcc, 0x7d, 0xea, 0x26, + 0xf4, 0x46, 0x87, 0x86, 0xab, 0xc1, 0x66, 0xc2, 0x5b, 0xdc, 0x4a, 0x01, 0xbb, 0x69, 0x50, 0x68, + 0xd3, 0x31, 0xdf, 0x59, 0xb8, 0xb1, 0x49, 0xfe, 0x30, 0x54, 0xba, 0xc7, 0xa8, 0xf0, 0xe4, 0x8b, + 0x03, 0x5f, 0x5d, 0x28, 0x26, 0x0d, 0xa0, 0xef, 0xd0, 0xea, 0x90, 0xcf, 0x2d, 0xbc, 0xea, 0xc0, + 0xb1, 0xed, 0x4c, 0xfe, 0x89, 0x32, 0xc9, 0x47, 0xcc, 0x6a, 0xcc, 0x26, 0xb5, 0x98, 0x21, 0x9c, + 0x85, 0x27, 0x98, 0x97, 0xee, 0xfe, 0x87, 0x03, 0xb6, 0x79, 0x3a, 0x98, 0x23, 0x64, 0xbd, 0xa3, + 0x53, 0xda, 0xe7, 0x1d, 0x1d, 0xe5, 0x33, 0x95, 0x0f, 0xe6, 0xa3, 0x8f, 0x1c, 0xc2, 0x47, 0x1f, + 0x1d, 0xea, 0x64, 0xbd, 0x16, 0xca, 0xdd, 0xa0, 0x2e, 0xdd, 0x6c, 0x73, 0x20, 0xb5, 0xb2, 0x8c, + 0x0c, 0xee, 0xfe, 0xc1, 0xa8, 0xd9, 0x56, 0xcb, 0xd3, 0xeb, 0x1f, 0x88, 0x6a, 0x37, 0x74, 0x92, + 0xaa, 0xa8, 0xf9, 0xf5, 0xbe, 0x24, 0xd5, 0xb7, 0x1d, 0x3e, 0x39, 0x41, 0x34, 0xd0, 0xb0, 0x1c, + 0xd5, 0xf1, 0x7d, 0x32, 0x13, 0xee, 0x40, 0x85, 0xed, 0x44, 0x78, 0x7c, 0xac, 0x92, 0x51, 0xaa, + 0x72, 0x59, 0xc2, 0xef, 0xef, 0xcd, 0xbd, 0xf5, 0xf0, 0x6a, 0xa9, 0xd2, 0xa8, 0xf9, 0x93, 0x04, + 0xaa, 0xec, 0x37, 0x4f, 0xa2, 0x90, 0x7b, 0x9c, 0x9b, 0xda, 0x16, 0x29, 0x44, 0x21, 0x19, 0x1a, + 0x46, 0x0e, 0x09, 0xa1, 0xca, 0x5f, 0x7c, 0xe1, 0x42, 0xc5, 0x56, 0x68, 0x4d, 0xa7, 0x32, 0x28, + 0xc4, 0xfd, 0xbd, 0xb9, 0x17, 0x0e, 0x2f, 0x54, 0x17, 0x47, 0x23, 0xc2, 0xfd, 0x6e, 0xd9, 0x8c, + 0x5d, 0x99, 0x9b, 0xfc, 0x03, 0x31, 0x76, 0x9f, 0xcf, 0x8d, 0xdd, 0x73, 0x7d, 0x63, 0x77, 0xda, + 0xbc, 0x8a, 0x92, 0x19, 0x8d, 0x8f, 0x7b, 0x81, 0xdd, 0x7f, 0xdb, 0xcd, 0x3d, 0x8b, 0x97, 0xbb, + 0x41, 0x4c, 0x93, 0xb5, 0xb8, 0x1b, 0x06, 0x61, 0x93, 0x0f, 0xc7, 0x8a, 0xed, 0x59, 0x64, 0xd0, + 0x98, 0xa7, 0x77, 0xbf, 0xcc, 0xcf, 0x1c, 0xad, 0x7c, 0x2c, 0xd6, 0xcb, 0x2d, 0xfe, 0x68, 0x8e, + 0xc8, 0x08, 0xd5, 0xbd, 0x2c, 0x5e, 0xca, 0x11, 0x38, 0x72, 0x17, 0xc6, 0x37, 0xc5, 0xc5, 0xfd, + 0x62, 0x2e, 0x08, 0xc9, 0x57, 0x00, 0xf8, 0x55, 0x4c, 0xf5, 0x24, 0xc0, 0x7d, 0xf3, 0x13, 0x95, + 0x34, 0xf7, 0x97, 0xcb, 0x70, 0x2c, 0xf7, 0xa4, 0x0b, 0xdb, 0x9f, 0xab, 0xf7, 0x7b, 0xf2, 0xc1, + 0x74, 0xfd, 0x4e, 0xad, 0xa6, 0x20, 0xef, 0x03, 0xa8, 0xd3, 0x4e, 0x2b, 0xea, 0x71, 0xc7, 0x65, + 0xe4, 0xd0, 0x8e, 0x8b, 0xf6, 0x75, 0x97, 0x35, 0x17, 0xb4, 0x38, 0xca, 0x34, 0xd8, 0x51, 0xf1, + 0x2c, 0x41, 0x36, 0x0d, 0xd6, 0xba, 0x27, 0x37, 0xf6, 0x78, 0xef, 0xc9, 0x05, 0x70, 0x4c, 0xa8, + 0xa8, 0xb3, 0x9e, 0x1e, 0x22, 0xb9, 0xe9, 0x04, 0x1b, 0x51, 0xcb, 0x59, 0x36, 0x98, 0xe7, 0xeb, + 0x7e, 0xba, 0xc4, 0xdc, 0x37, 0xd1, 0xd8, 0xd7, 0x54, 0x2c, 0xfb, 0xf5, 0x30, 0xe6, 0x75, 0xd3, + 0xad, 0xa8, 0xef, 0x21, 0x85, 0x45, 0x0e, 0x45, 0x89, 0x25, 0xab, 0x30, 0x52, 0xf7, 0x52, 0xf5, + 0xce, 0xfa, 0x61, 0x94, 0x33, 0x81, 0x2b, 0x2f, 0xa5, 0xc8, 0xb9, 0x90, 0xa7, 0x60, 0x24, 0xf5, + 0x9a, 0x99, 0x17, 0x1e, 0x37, 0xbc, 0x66, 0x82, 0x1c, 0x6a, 0xaf, 0x2e, 0x23, 0xfb, 0xac, 0x2e, + 0x2f, 0x58, 0xff, 0x21, 0x60, 0x1d, 0x92, 0xf4, 0xbf, 0xfb, 0x2f, 0x12, 0xf3, 0x33, 0xb4, 0xee, + 0x8f, 0xc0, 0xa4, 0xfd, 0xbf, 0x00, 0x07, 0xba, 0xd7, 0xe3, 0xfe, 0xf3, 0x08, 0x4c, 0x65, 0x32, + 0xe3, 0x32, 0xa3, 0xdc, 0xd9, 0x77, 0x94, 0xf3, 0x33, 0xad, 0x6e, 0x48, 0x65, 0xde, 0xa3, 0x75, + 0xa6, 0xd5, 0x0d, 0x29, 0x0a, 0x1c, 0xeb, 0x95, 0x7a, 0xdc, 0xc3, 0x6e, 0x28, 0x83, 0xe8, 0xba, + 0x57, 0x96, 0x39, 0x14, 0x25, 0x96, 0x6d, 0x60, 0x27, 0x13, 0x6e, 0x14, 0x85, 0x8d, 0x90, 0xb3, + 0xe6, 0x4a, 0x11, 0x8f, 0x4f, 0xc9, 0x2c, 0x50, 0xbe, 0xa1, 0xb7, 0x21, 0x98, 0x91, 0x48, 0x3e, + 0xe6, 0xd8, 0xcf, 0x6e, 0x8d, 0x15, 0x71, 0xf8, 0x93, 0x4f, 0x3c, 0x14, 0x33, 0xe8, 0xc1, 0xaf, + 0x6f, 0x25, 0x7a, 0x02, 0x8f, 0x3f, 0x9a, 0x09, 0x0c, 0x03, 0x26, 0xef, 0x1b, 0xa1, 0xda, 0xf6, + 0xc2, 0xa0, 0x41, 0x93, 0x54, 0xfc, 0xa7, 0x47, 0x55, 0xec, 0x9e, 0xae, 0x29, 0x20, 0x1a, 0x3c, + 0xff, 0xe7, 0x1c, 0x5e, 0x31, 0xb1, 0x89, 0xa9, 0x5a, 0xff, 0x9c, 0x63, 0xc0, 0x68, 0xd3, 0xb8, + 0xbf, 0xe3, 0xc0, 0xa9, 0x81, 0x8d, 0xf1, 0xfd, 0x1b, 0xad, 0x74, 0x7f, 0xaf, 0x04, 0x27, 0x06, + 0x64, 0x8e, 0x92, 0xde, 0x23, 0x7b, 0x9d, 0x4d, 0xa6, 0xa6, 0x4e, 0x0d, 0x1d, 0x1b, 0x87, 0x5b, + 0x86, 0xcc, 0x52, 0x50, 0x7e, 0xac, 0x4b, 0x81, 0xfb, 0xe5, 0x12, 0x58, 0xef, 0x08, 0x92, 0x0f, + 0xd9, 0x49, 0xd2, 0x4e, 0x51, 0x09, 0xbd, 0x82, 0xb9, 0x4e, 0xb2, 0x16, 0xad, 0x36, 0x28, 0xe7, + 0x3a, 0x3f, 0x5e, 0x4b, 0xfb, 0x8f, 0x57, 0xd2, 0x52, 0xd9, 0xe8, 0xe5, 0xe2, 0xb3, 0xd1, 0xab, + 0x7d, 0x99, 0xe8, 0xbf, 0xe8, 0x88, 0x91, 0x96, 0xab, 0x92, 0xb1, 0xb0, 0xce, 0x03, 0x2c, 0xec, + 0x9b, 0xa0, 0x92, 0xd0, 0x56, 0x83, 0x79, 0x76, 0xd2, 0x12, 0xeb, 0x31, 0xb1, 0x2e, 0xe1, 0xa8, + 0x29, 0xf8, 0x3d, 0xd5, 0x56, 0x2b, 0xba, 0x7b, 0xa1, 0xdd, 0x49, 0x7b, 0xd2, 0x26, 0x9b, 0x7b, + 0xaa, 0x1a, 0x83, 0x16, 0x95, 0xfb, 0x9f, 0x8e, 0xe8, 0x4e, 0xe9, 0xa3, 0x3f, 0x9f, 0xbb, 0x3f, + 0x78, 0x70, 0xf7, 0xf6, 0x67, 0x00, 0x7c, 0x7d, 0xa3, 0xbf, 0x98, 0xe7, 0x05, 0xcd, 0x0b, 0x01, + 0xf6, 0x9b, 0x77, 0x0a, 0x86, 0x96, 0xbc, 0xcc, 0xe4, 0x29, 0xef, 0x37, 0x79, 0xdc, 0x7f, 0x73, + 0x20, 0xb3, 0x58, 0x90, 0x0e, 0x8c, 0x32, 0x0d, 0x7a, 0xc5, 0xbc, 0x3f, 0x60, 0xb3, 0x66, 0x13, + 0x4b, 0x0e, 0x0b, 0xfe, 0x13, 0x85, 0x20, 0xd2, 0x92, 0xde, 0x79, 0xa9, 0x88, 0x37, 0x32, 0x6c, + 0x81, 0xcc, 0xbf, 0x97, 0xff, 0x71, 0xa0, 0x3d, 0x7d, 0xf7, 0x79, 0x98, 0xe9, 0x53, 0x8a, 0xdf, + 0x28, 0x8a, 0xd4, 0xa3, 0x0b, 0xd6, 0x08, 0xe4, 0xf7, 0x1b, 0x51, 0xe0, 0x98, 0x83, 0x7f, 0x3c, + 0xcf, 0x9e, 0x7c, 0xc1, 0x81, 0x99, 0x24, 0xcf, 0xef, 0x51, 0xb5, 0x9d, 0x8e, 0x5c, 0xf5, 0xa1, + 0xb0, 0x5f, 0x09, 0xf7, 0xcf, 0xa5, 0x79, 0x12, 0xff, 0x2a, 0xa5, 0x17, 0x17, 0x67, 0xe8, 0xe2, + 0xc2, 0xa6, 0x98, 0xbf, 0x45, 0xeb, 0xdd, 0x56, 0x5f, 0x2a, 0xcd, 0xba, 0x84, 0xa3, 0xa6, 0xc8, + 0x3c, 0x33, 0x56, 0xde, 0xf7, 0x99, 0xb1, 0xe7, 0x60, 0xd2, 0x7e, 0x58, 0x84, 0x87, 0xd0, 0xe4, + 0xe1, 0x83, 0xfd, 0x06, 0x09, 0x66, 0xa8, 0x72, 0xcf, 0x54, 0x8d, 0xee, 0xfb, 0x4c, 0xd5, 0x33, + 0x50, 0x91, 0x7f, 0xd2, 0xa4, 0xe2, 0xbb, 0x22, 0x4f, 0x47, 0xc2, 0x50, 0x63, 0x99, 0x81, 0x68, + 0x7b, 0x61, 0xd7, 0x6b, 0xb1, 0x16, 0x92, 0x39, 0x79, 0x7a, 0x66, 0x5d, 0xd3, 0x18, 0xb4, 0xa8, + 0xdc, 0x7f, 0x72, 0x20, 0xff, 0xf0, 0x4f, 0x26, 0xb3, 0xcf, 0xd9, 0x37, 0xb3, 0x2f, 0x9b, 0xe0, + 0x54, 0x3a, 0x50, 0x82, 0x93, 0x9d, 0x7b, 0x54, 0x7e, 0x60, 0xee, 0xd1, 0xeb, 0xcc, 0xad, 0x70, + 0x91, 0xa4, 0x34, 0x31, 0xe8, 0x46, 0x38, 0x71, 0x61, 0xcc, 0xf7, 0x74, 0xe2, 0xf4, 0xa4, 0x70, + 0x94, 0x96, 0x16, 0x39, 0x91, 0xc4, 0xd4, 0xe6, 0xbf, 0xfa, 0x9d, 0xb3, 0x4f, 0x7c, 0xed, 0x3b, + 0x67, 0x9f, 0xf8, 0xe6, 0x77, 0xce, 0x3e, 0xf1, 0x91, 0x7b, 0x67, 0x9d, 0xaf, 0xde, 0x3b, 0xeb, + 0x7c, 0xed, 0xde, 0x59, 0xe7, 0x9b, 0xf7, 0xce, 0x3a, 0xdf, 0xbe, 0x77, 0xd6, 0xf9, 0xcc, 0xdf, + 0x9f, 0x7d, 0xe2, 0xdd, 0x15, 0x35, 0x56, 0xff, 0x37, 0x00, 0x00, 0xff, 0xff, 0xa4, 0x8a, 0x2c, + 0xc1, 0xa3, 0x74, 0x00, 0x00, } func (m *AWSAuthConfig) Marshal() (dAtA []byte, err error) { @@ -3201,6 +3203,15 @@ func (m *AppProjectSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.SourceNamespaces) > 0 { + for iNdEx := len(m.SourceNamespaces) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.SourceNamespaces[iNdEx]) + copy(dAtA[i:], m.SourceNamespaces[iNdEx]) + i = encodeVarintGenerated(dAtA, i, uint64(len(m.SourceNamespaces[iNdEx]))) + i-- + dAtA[i] = 0x62 + } + } if len(m.ClusterResourceBlacklist) > 0 { for iNdEx := len(m.ClusterResourceBlacklist) - 1; iNdEx >= 0; iNdEx-- { { @@ -8187,6 +8198,12 @@ func (m *AppProjectSpec) Size() (n int) { n += 1 + l + sovGenerated(uint64(l)) } } + if len(m.SourceNamespaces) > 0 { + for _, s := range m.SourceNamespaces { + l = len(s) + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -10066,6 +10083,7 @@ func (this *AppProjectSpec) String() string { `NamespaceResourceWhitelist:` + repeatedStringForNamespaceResourceWhitelist + `,`, `SignatureKeys:` + repeatedStringForSignatureKeys + `,`, `ClusterResourceBlacklist:` + repeatedStringForClusterResourceBlacklist + `,`, + `SourceNamespaces:` + fmt.Sprintf("%v", this.SourceNamespaces) + `,`, `}`, }, "") return s @@ -12205,6 +12223,38 @@ func (m *AppProjectSpec) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 12: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field SourceNamespaces", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.SourceNamespaces = append(m.SourceNamespaces, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/pkg/apis/application/v1alpha1/generated.proto b/pkg/apis/application/v1alpha1/generated.proto index ebcd2a405ea02..91bea67bebeb2 100644 --- a/pkg/apis/application/v1alpha1/generated.proto +++ b/pkg/apis/application/v1alpha1/generated.proto @@ -82,6 +82,9 @@ message AppProjectSpec { // ClusterResourceBlacklist contains list of blacklisted cluster level resources repeated k8s.io.apimachinery.pkg.apis.meta.v1.GroupKind clusterResourceBlacklist = 11; + + // SourceNamespaces contains list of allowed Application namespaces + repeated string sourceNamespaces = 12; } // AppProjectStatus contains status information for AppProject CRs diff --git a/pkg/apis/application/v1alpha1/openapi_generated.go b/pkg/apis/application/v1alpha1/openapi_generated.go index 3c011f91f6f57..7799b9a60f6e5 100644 --- a/pkg/apis/application/v1alpha1/openapi_generated.go +++ b/pkg/apis/application/v1alpha1/openapi_generated.go @@ -377,6 +377,21 @@ func schema_pkg_apis_application_v1alpha1_AppProjectSpec(ref common.ReferenceCal }, }, }, + "sourceNamespaces": { + SchemaProps: spec.SchemaProps{ + Description: "SourceNamespaces contains list of allowed Application namespaces", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, }, }, }, diff --git a/pkg/apis/application/v1alpha1/types.go b/pkg/apis/application/v1alpha1/types.go index 7280274ec165a..28752b3efd11c 100644 --- a/pkg/apis/application/v1alpha1/types.go +++ b/pkg/apis/application/v1alpha1/types.go @@ -1634,6 +1634,8 @@ type AppProjectSpec struct { SignatureKeys []SignatureKey `json:"signatureKeys,omitempty" protobuf:"bytes,10,opt,name=signatureKeys"` // ClusterResourceBlacklist contains list of blacklisted cluster level resources ClusterResourceBlacklist []metav1.GroupKind `json:"clusterResourceBlacklist,omitempty" protobuf:"bytes,11,opt,name=clusterResourceBlacklist"` + // SourceNamespaces contains list of allowed Application namespaces + SourceNamespaces []string `json:"sourceNamespaces,omitempty" protobuf:"bytes,12,name=sourceNamespaces"` } // SyncWindows is a collection of sync windows in this project @@ -2417,3 +2419,13 @@ func (d *ApplicationDestination) MarshalJSON() ([]byte, error) { } return json.Marshal(&struct{ *Alias }{Alias: (*Alias)(dest)}) } + +// InstanceName returns the string that is as the instance label name for an application +func (app *Application) InstanceName() string { + return app.Namespace + "_" + app.Name +} + +// QualifiedName returns the qualified name of the application in the format namespace/name +func (app *Application) QualifiedName() string { + return app.Namespace + "/" + app.Name +} diff --git a/pkg/apis/application/v1alpha1/types_test.go b/pkg/apis/application/v1alpha1/types_test.go index cd18fe8cc749d..42ced8fe92278 100644 --- a/pkg/apis/application/v1alpha1/types_test.go +++ b/pkg/apis/application/v1alpha1/types_test.go @@ -2228,3 +2228,72 @@ func TestRemoveEnvEntry(t *testing.T) { assert.EqualError(t, err, `unable to find env variable with key "key" for plugin "test"`) }) } + +func TestAppProjectIsSourceNamespacePermitted(t *testing.T) { + app1 := &Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app1", + Namespace: "argocd", + }, + Spec: ApplicationSpec{}, + } + app2 := &Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app2", + Namespace: "some-ns", + }, + Spec: ApplicationSpec{}, + } + app3 := &Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app2", + Namespace: "", + }, + Spec: ApplicationSpec{}, + } + t.Run("App in same namespace as controller", func(t *testing.T) { + proj := &AppProject{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + Namespace: "argocd", + }, + Spec: AppProjectSpec{ + SourceNamespaces: []string{}, + }, + } + // app1 is installed to argocd namespace, controller as well + assert.True(t, proj.IsAppNamespacePermitted(app1, "argocd")) + // app2 is installed to some-ns namespace, controller as well + assert.True(t, proj.IsAppNamespacePermitted(app2, "some-ns")) + // app3 has no namespace set, so will be implicitly created in controller's namespace + assert.True(t, proj.IsAppNamespacePermitted(app3, "argocd")) + }) + t.Run("App not permitted when sourceNamespaces is empty", func(t *testing.T) { + proj := &AppProject{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + Namespace: "argocd", + }, + Spec: AppProjectSpec{ + SourceNamespaces: []string{}, + }, + } + // app2 is installed to some-ns, controller running in argocd + assert.False(t, proj.IsAppNamespacePermitted(app2, "argocd")) + }) + + t.Run("App permitted when sourceNamespaces has app namespace", func(t *testing.T) { + proj := &AppProject{ + ObjectMeta: metav1.ObjectMeta{ + Name: "default", + Namespace: "argocd", + }, + Spec: AppProjectSpec{ + SourceNamespaces: []string{"some-ns"}, + }, + } + // app2 is installed to some-ns, controller running in argocd + assert.True(t, proj.IsAppNamespacePermitted(app2, "argocd")) + }) + +} diff --git a/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go index 85ece26b4d483..f12eaedd4addb 100644 --- a/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go @@ -148,6 +148,11 @@ func (in *AppProjectSpec) DeepCopyInto(out *AppProjectSpec) { *out = make([]v1.GroupKind, len(*in)) copy(*out, *in) } + if in.SourceNamespaces != nil { + in, out := &in.SourceNamespaces, &out.SourceNamespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } return } diff --git a/pkg/client/listers/application/v1alpha1/application_expansion.go b/pkg/client/listers/application/v1alpha1/application_expansion.go new file mode 100644 index 0000000000000..994b36fe9a6be --- /dev/null +++ b/pkg/client/listers/application/v1alpha1/application_expansion.go @@ -0,0 +1,30 @@ +package v1alpha1 + +import ( + v1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" +) + +// ApplicationListerExpansion allows custom methods to be added to +// ApplicationLister. +type ApplicationListerExpansion interface{} + +// ApplicationNamespaceListerExpansion allows custom methods to be added to +// ApplicationNamespaceLister. +type ApplicationNamespaceListerExpansion interface { + NamespacedGet(appName string) (*v1alpha1.Application, error) +} + +// NamespacedGet retrieves the Application from the indexer for a given namespace and name. +// Name must be specified as "namespace/name". +// It will use the namespace specified in name, instead the one specified in the lister. +func (s applicationNamespaceLister) NamespacedGet(name string) (*v1alpha1.Application, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("application"), name) + } + return obj.(*v1alpha1.Application), nil +} diff --git a/pkg/client/listers/application/v1alpha1/expansion_generated.go b/pkg/client/listers/application/v1alpha1/expansion_generated.go index 6a821fce850fc..a3a41b1832658 100644 --- a/pkg/client/listers/application/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/application/v1alpha1/expansion_generated.go @@ -9,11 +9,3 @@ type AppProjectListerExpansion interface{} // AppProjectNamespaceListerExpansion allows custom methods to be added to // AppProjectNamespaceLister. type AppProjectNamespaceListerExpansion interface{} - -// ApplicationListerExpansion allows custom methods to be added to -// ApplicationLister. -type ApplicationListerExpansion interface{} - -// ApplicationNamespaceListerExpansion allows custom methods to be added to -// ApplicationNamespaceLister. -type ApplicationNamespaceListerExpansion interface{} diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index 549961afa1304..1c77f06cd896a 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -543,6 +543,15 @@ func runHelmBuild(appPath string, h helm.Helm) error { return ioutil.WriteFile(markerFile, []byte("marker"), 0644) } +func appNameWithoutPrefix(appName string) string { + t := strings.SplitN(appName, "_", 2) + if len(t) == 2 { + return t[1] + } else { + return appName + } +} + func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclient.ManifestRequest, isLocal bool) ([]*unstructured.Unstructured, error) { concurrencyAllowed := isConcurrencyAllowed(appPath) if !concurrencyAllowed { @@ -551,7 +560,7 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie } templateOpts := &helm.TemplateOpts{ - Name: q.AppName, + Name: appNameWithoutPrefix(q.AppName), Namespace: q.Namespace, KubeVersion: text.SemVer(q.KubeVersion), APIVersions: q.ApiVersions, @@ -796,7 +805,7 @@ func GenerateManifests(appPath, repoRoot, revision string, q *apiclient.Manifest func newEnv(q *apiclient.ManifestRequest, revision string) *v1alpha1.Env { return &v1alpha1.Env{ - &v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: q.AppName}, + &v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: appNameWithoutPrefix(q.AppName)}, &v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAMESPACE", Value: q.Namespace}, &v1alpha1.EnvEntry{Name: "ARGOCD_APP_REVISION", Value: revision}, &v1alpha1.EnvEntry{Name: "ARGOCD_APP_SOURCE_REPO_URL", Value: q.Repo.Repo}, diff --git a/server/application/application.go b/server/application/application.go index 80a7f15816fc3..49da92a4fc166 100644 --- a/server/application/application.go +++ b/server/application/application.go @@ -173,6 +173,10 @@ func (s *Server) List(ctx context.Context, q *application.ApplicationQuery) (*ap // Create creates an application func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateRequest) (*appv1.Application, error) { + // Assume control plane's namespace if no namespace is explictly set + if q.Application.Namespace == "" { + q.Application.Namespace = s.ns + } if err := s.enf.EnforceErr(ctx.Value("claims"), rbacpolicy.ResourceApplications, rbacpolicy.ActionCreate, appRBACName(q.Application)); err != nil { return nil, err } @@ -189,7 +193,7 @@ func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateReq if err != nil { return nil, err } - created, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Create(ctx, &a, metav1.CreateOptions{}) + created, err := s.appclientset.ArgoprojV1alpha1().Applications(a.Namespace).Create(ctx, &a, metav1.CreateOptions{}) if err == nil { s.logAppEvent(created, ctx, argo.EventReasonResourceCreated, "created application") s.waitSync(created) @@ -199,7 +203,7 @@ func (s *Server) Create(ctx context.Context, q *application.ApplicationCreateReq return nil, err } // act idempotent if existing spec matches new spec - existing, err := s.appLister.Get(a.Name) + existing, err := s.appLister.NamespacedGet(a.QualifiedName()) if err != nil { return nil, status.Errorf(codes.Internal, "unable to check existing application details: %v", err) } @@ -249,7 +253,7 @@ func (s *Server) queryRepoServer(ctx context.Context, a *v1alpha1.Application, a if err != nil { return err } - proj, err := argo.GetAppProject(&a.Spec, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr) + proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr) if err != nil { if apierr.IsNotFound(err) { return status.Errorf(codes.InvalidArgument, "application references project %s which does not exist", a.Spec.Project) @@ -279,7 +283,8 @@ func (s *Server) queryRepoServer(ctx context.Context, a *v1alpha1.Application, a // GetManifests returns application manifests func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationManifestQuery) (*apiclient.ManifestResponse, error) { - a, err := s.appLister.Get(*q.Name) + appName, ns := argo.ParseAppNamespacedName(*q.Name, s.ns) + a, err := s.appLister.NamespacedGet(ns + "/" + appName) if err != nil { return nil, err } @@ -322,7 +327,7 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan Repo: repo, Revision: revision, AppLabelKey: appInstanceLabelKey, - AppName: a.Name, + AppName: a.InstanceName(), Namespace: a.Spec.Destination.Namespace, ApplicationSource: &a.Spec.Source, Repos: helmRepos, @@ -363,10 +368,12 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan // Get returns an application by name func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*appv1.Application, error) { + appName, ns := argo.ParseAppNamespacedName(q.GetName(), s.ns) + // We must use a client Get instead of an informer Get, because it's common to call Get immediately // following a Watch (which is not yet powered by an informer), and the Get must reflect what was // previously seen by the client. - a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, q.GetName(), metav1.GetOptions{ + a, err := s.appclientset.ArgoprojV1alpha1().Applications(ns).Get(ctx, appName, metav1.GetOptions{ ResourceVersion: q.ResourceVersion, }) @@ -384,16 +391,16 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app if *q.Refresh == string(appv1.RefreshTypeHard) { refreshType = appv1.RefreshTypeHard } - appIf := s.appclientset.ArgoprojV1alpha1().Applications(s.ns) + appIf := s.appclientset.ArgoprojV1alpha1().Applications(ns) // subscribe early with buffered channel to ensure we don't miss events events := make(chan *appv1.ApplicationWatchEvent, watchAPIBufferSize) unsubscribe := s.appBroadcaster.Subscribe(events, func(event *appv1.ApplicationWatchEvent) bool { - return event.Application.Name == q.GetName() + return event.Application.Name == appName //&& event.Application.Namespace == ns }) defer unsubscribe() - app, err := argoutil.RefreshApp(appIf, *q.Name, refreshType) + app, err := argoutil.RefreshApp(appIf, appName, refreshType) if err != nil { return nil, err } @@ -425,7 +432,6 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app if minVersion, err = strconv.Atoi(app.ResourceVersion); err != nil { minVersion = 0 } - for { select { case <-ctx.Done(): @@ -446,7 +452,8 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*app // ListResourceEvents returns a list of event resources func (s *Server) ListResourceEvents(ctx context.Context, q *application.ApplicationResourceEventsQuery) (*v1.EventList, error) { - a, err := s.appLister.Get(*q.Name) + appName, ns := argo.ParseAppNamespacedName(*q.Name, s.ns) + a, err := s.appLister.NamespacedGet(ns + "/" + appName) if err != nil { return nil, err } @@ -495,8 +502,7 @@ func (s *Server) ListResourceEvents(ctx context.Context, q *application.Applicat func (s *Server) validateAndUpdateApp(ctx context.Context, newApp *appv1.Application, merge bool, validate bool) (*appv1.Application, error) { s.projectLock.RLock(newApp.Spec.GetProject()) defer s.projectLock.RUnlock(newApp.Spec.GetProject()) - - app, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, newApp.Name, metav1.GetOptions{}) + app, err := s.appclientset.ArgoprojV1alpha1().Applications(newApp.Namespace).Get(ctx, newApp.Name, metav1.GetOptions{}) if err != nil { return nil, err } @@ -541,7 +547,7 @@ func (s *Server) waitSync(app *appv1.Application) { return } for { - if currApp, err := s.appLister.Get(app.Name); err == nil { + if currApp, err := s.appLister.NamespacedGet(app.QualifiedName()); err == nil { currVersion, err := strconv.Atoi(currApp.ResourceVersion) if err == nil && currVersion >= minVersion { return @@ -568,7 +574,7 @@ func (s *Server) updateApp(app *appv1.Application, newApp *appv1.Application, ct app.Finalizers = newApp.Finalizers - res, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Update(ctx, app, metav1.UpdateOptions{}) + res, err := s.appclientset.ArgoprojV1alpha1().Applications(app.Namespace).Update(ctx, app, metav1.UpdateOptions{}) if err == nil { s.logAppEvent(app, ctx, argo.EventReasonResourceUpdated, "updated application spec") s.waitSync(res) @@ -578,7 +584,7 @@ func (s *Server) updateApp(app *appv1.Application, newApp *appv1.Application, ct return nil, err } - app, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, newApp.Name, metav1.GetOptions{}) + app, err = s.appclientset.ArgoprojV1alpha1().Applications(newApp.Namespace).Get(ctx, newApp.Name, metav1.GetOptions{}) if err != nil { return nil, err } @@ -601,7 +607,8 @@ func (s *Server) Update(ctx context.Context, q *application.ApplicationUpdateReq // UpdateSpec updates an application spec and filters out any invalid parameter overrides func (s *Server) UpdateSpec(ctx context.Context, q *application.ApplicationUpdateSpecRequest) (*appv1.ApplicationSpec, error) { - a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, *q.Name, metav1.GetOptions{}) + appName, ns := argo.ParseAppNamespacedName(*q.Name, s.ns) + a, err := s.appclientset.ArgoprojV1alpha1().Applications(ns).Get(ctx, appName, metav1.GetOptions{}) if err != nil { return nil, err } @@ -622,8 +629,8 @@ func (s *Server) UpdateSpec(ctx context.Context, q *application.ApplicationUpdat // Patch patches an application func (s *Server) Patch(ctx context.Context, q *application.ApplicationPatchRequest) (*appv1.Application, error) { - - app, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, *q.Name, metav1.GetOptions{}) + appName, ns := argo.ParseAppNamespacedName(*q.Name, s.ns) + app, err := s.appclientset.ArgoprojV1alpha1().Applications(ns).Get(ctx, appName, metav1.GetOptions{}) if err != nil { return nil, err } @@ -668,7 +675,8 @@ func (s *Server) Patch(ctx context.Context, q *application.ApplicationPatchReque // Delete removes an application and all associated resources func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteRequest) (*application.ApplicationResponse, error) { - a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, *q.Name, metav1.GetOptions{}) + appName, ns := argo.ParseAppNamespacedName(*q.Name, s.ns) + a, err := s.appclientset.ArgoprojV1alpha1().Applications(ns).Get(ctx, appName, metav1.GetOptions{}) if err != nil { return nil, err } @@ -720,7 +728,7 @@ func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteReq } } - err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Delete(ctx, *q.Name, metav1.DeleteOptions{}) + err = s.appclientset.ArgoprojV1alpha1().Applications(ns).Delete(ctx, appName, metav1.DeleteOptions{}) if err != nil { return nil, err } @@ -729,6 +737,7 @@ func (s *Server) Delete(ctx context.Context, q *application.ApplicationDeleteReq } func (s *Server) Watch(q *application.ApplicationQuery, ws application.ApplicationService_WatchServer) error { + appName, ns := argo.ParseAppNamespacedName(*q.Name, s.ns) logCtx := log.NewEntry(log.New()) if q.Name != nil { logCtx = logCtx.WithField("application", *q.Name) @@ -751,7 +760,7 @@ func (s *Server) Watch(q *application.ApplicationQuery, ws application.Applicati if appVersion, err := strconv.Atoi(a.ResourceVersion); err == nil && appVersion < minVersion { return } - matchedEvent := q.GetName() == "" || a.Name == q.GetName() && selector.Matches(labels.Set(a.Labels)) + matchedEvent := appName == "" || a.Name == appName && a.Namespace == ns && selector.Matches(labels.Set(a.Labels)) if !matchedEvent { return } @@ -800,14 +809,14 @@ func (s *Server) Watch(q *application.ApplicationQuery, ws application.Applicati } func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Application, validate bool) error { - proj, err := argo.GetAppProject(&app.Spec, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr) + proj, err := argo.GetAppProject(app, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr) if err != nil { if apierr.IsNotFound(err) { return status.Errorf(codes.InvalidArgument, "application references project %s which does not exist", app.Spec.Project) } return err } - currApp, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, app.Name, metav1.GetOptions{}) + currApp, err := s.appclientset.ArgoprojV1alpha1().Applications(app.Namespace).Get(ctx, app.Name, metav1.GetOptions{}) if err != nil { if !apierr.IsNotFound(err) { return err @@ -866,6 +875,11 @@ func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Applica } app.Spec = *argo.NormalizeApplicationSpec(&app.Spec) + + if !proj.IsAppNamespacePermitted(app, s.ns) { + return fmt.Errorf("application '%s' in namespace '%s' is not permitted to associate with project '%s'", app.Name, app.Namespace, proj.GetName()) + } + return nil } @@ -893,7 +907,7 @@ func (s *Server) getCachedAppState(ctx context.Context, a *appv1.Application, ge return errors.New(argoutil.FormatAppConditions(conditions)) } _, err = s.Get(ctx, &application.ApplicationQuery{ - Name: pointer.StringPtr(a.Name), + Name: pointer.StringPtr(a.QualifiedName()), Refresh: pointer.StringPtr(string(appv1.RefreshTypeNormal)), }) if err != nil { @@ -907,13 +921,14 @@ func (s *Server) getCachedAppState(ctx context.Context, a *appv1.Application, ge func (s *Server) getAppResources(ctx context.Context, a *appv1.Application) (*appv1.ApplicationTree, error) { var tree appv1.ApplicationTree err := s.getCachedAppState(ctx, a, func() error { - return s.cache.GetAppResourcesTree(a.Name, &tree) + return s.cache.GetAppResourcesTree(a.InstanceName(), &tree) }) return &tree, err } func (s *Server) getAppResource(ctx context.Context, action string, q *application.ApplicationResourceRequest) (*appv1.ResourceNode, *rest.Config, *appv1.Application, error) { - a, err := s.appLister.Get(*q.Name) + appName, ns := argo.ParseAppNamespacedName(*q.Name, s.ns) + a, err := s.appLister.NamespacedGet(ns + "/" + appName) if err != nil { return nil, nil, nil, err } @@ -1051,7 +1066,8 @@ func (s *Server) DeleteResource(ctx context.Context, q *application.ApplicationR } func (s *Server) ResourceTree(ctx context.Context, q *application.ResourcesQuery) (*appv1.ApplicationTree, error) { - a, err := s.appLister.Get(q.GetApplicationName()) + appName, ns := argo.ParseAppNamespacedName(q.GetApplicationName(), s.ns) + a, err := s.appLister.NamespacedGet(ns + "/" + appName) if err != nil { return nil, err } @@ -1062,7 +1078,8 @@ func (s *Server) ResourceTree(ctx context.Context, q *application.ResourcesQuery } func (s *Server) WatchResourceTree(q *application.ResourcesQuery, ws application.ApplicationService_WatchResourceTreeServer) error { - a, err := s.appLister.Get(q.GetApplicationName()) + appName, ns := argo.ParseAppNamespacedName(q.GetApplicationName(), s.ns) + a, err := s.appLister.NamespacedGet(ns + "/" + appName) if err != nil { return err } @@ -1071,9 +1088,9 @@ func (s *Server) WatchResourceTree(q *application.ResourcesQuery, ws application return err } - return s.cache.OnAppResourcesTreeChanged(ws.Context(), q.GetApplicationName(), func() error { + return s.cache.OnAppResourcesTreeChanged(ws.Context(), ns+"/"+appName, func() error { var tree appv1.ApplicationTree - err := s.cache.GetAppResourcesTree(q.GetApplicationName(), &tree) + err := s.cache.GetAppResourcesTree(ns+"/"+appName, &tree) if err != nil { return err } @@ -1082,7 +1099,8 @@ func (s *Server) WatchResourceTree(q *application.ResourcesQuery, ws application } func (s *Server) RevisionMetadata(ctx context.Context, q *application.RevisionMetadataQuery) (*v1alpha1.RevisionMetadata, error) { - a, err := s.appLister.Get(q.GetName()) + appName, ns := argo.ParseAppNamespacedName(q.GetName(), s.ns) + a, err := s.appLister.NamespacedGet(ns + "/" + appName) if err != nil { return nil, err } @@ -1095,7 +1113,7 @@ func (s *Server) RevisionMetadata(ctx context.Context, q *application.RevisionMe } // We need to get some information with the project associated to the app, // so we'll know whether GPG signatures are enforced. - proj, err := argo.GetAppProject(&a.Spec, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), a.Namespace, s.settingsMgr) + proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), a.Namespace, s.settingsMgr) if err != nil { return nil, err } @@ -1119,7 +1137,8 @@ func isMatchingResource(q *application.ResourcesQuery, key kube.ResourceKey) boo } func (s *Server) ManagedResources(ctx context.Context, q *application.ResourcesQuery) (*application.ManagedResourcesResponse, error) { - a, err := s.appLister.Get(*q.ApplicationName) + appName, ns := argo.ParseAppNamespacedName(*q.ApplicationName, s.ns) + a, err := s.appLister.NamespacedGet(ns + "/" + appName) if err != nil { return nil, err } @@ -1128,7 +1147,7 @@ func (s *Server) ManagedResources(ctx context.Context, q *application.ResourcesQ } items := make([]*appv1.ResourceDiff, 0) err = s.getCachedAppState(ctx, a, func() error { - return s.cache.GetAppManagedResources(a.Name, &items) + return s.cache.GetAppManagedResources(a.InstanceName(), &items) }) if err != nil { return nil, err @@ -1178,7 +1197,8 @@ func (s *Server) PodLogs(q *application.ApplicationPodLogsQuery, ws application. } } - a, err := s.appLister.Get(q.GetName()) + appName, ns := argo.ParseAppNamespacedName(q.GetName(), s.ns) + a, err := s.appLister.NamespacedGet(ns + "/" + appName) if err != nil { return err } @@ -1344,13 +1364,13 @@ func isTheSelectedOne(currentNode *appv1.ResourceNode, q *application.Applicatio // Sync syncs an application to its target state func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncRequest) (*appv1.Application, error) { - appIf := s.appclientset.ArgoprojV1alpha1().Applications(s.ns) - a, err := appIf.Get(ctx, *syncReq.Name, metav1.GetOptions{}) + appName, ns := argo.ParseAppNamespacedName(*syncReq.Name, s.ns) + appIf := s.appclientset.ArgoprojV1alpha1().Applications(ns) + a, err := appIf.Get(ctx, appName, metav1.GetOptions{}) if err != nil { return nil, err } - - proj, err := argo.GetAppProject(&a.Spec, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), a.Namespace, s.settingsMgr) + proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), s.ns, s.settingsMgr) if err != nil { if apierr.IsNotFound(err) { return a, status.Errorf(codes.InvalidArgument, "application references project %s which does not exist", a.Spec.Project) @@ -1420,8 +1440,7 @@ func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncR if retry != nil { op.Retry = *retry } - - a, err = argo.SetAppOperation(appIf, *syncReq.Name, &op) + a, err = argo.SetAppOperation(appIf, appName, &op) if err == nil { partial := "" if len(syncReq.Resources) > 0 { @@ -1437,8 +1456,9 @@ func (s *Server) Sync(ctx context.Context, syncReq *application.ApplicationSyncR } func (s *Server) Rollback(ctx context.Context, rollbackReq *application.ApplicationRollbackRequest) (*appv1.Application, error) { - appIf := s.appclientset.ArgoprojV1alpha1().Applications(s.ns) - a, err := appIf.Get(ctx, *rollbackReq.Name, metav1.GetOptions{}) + appName, ns := argo.ParseAppNamespacedName(*rollbackReq.Name, s.ns) + appIf := s.appclientset.ArgoprojV1alpha1().Applications(ns) + a, err := appIf.Get(ctx, appName, metav1.GetOptions{}) if err != nil { return nil, err } @@ -1484,7 +1504,7 @@ func (s *Server) Rollback(ctx context.Context, rollbackReq *application.Applicat Source: &deploymentInfo.Source, }, } - a, err = argo.SetAppOperation(appIf, *rollbackReq.Name, &op) + a, err = argo.SetAppOperation(appIf, appName, &op) if err == nil { s.logAppEvent(a, ctx, argo.EventReasonOperationStarted, fmt.Sprintf("initiated rollback to %d", rollbackReq.ID)) } @@ -1550,7 +1570,8 @@ func (s *Server) resolveRevision(ctx context.Context, app *appv1.Application, sy } func (s *Server) TerminateOperation(ctx context.Context, termOpReq *application.OperationTerminateRequest) (*application.OperationTerminateResponse, error) { - a, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, *termOpReq.Name, metav1.GetOptions{}) + appName, ns := argo.ParseAppNamespacedName(*termOpReq.Name, s.ns) + a, err := s.appclientset.ArgoprojV1alpha1().Applications(ns).Get(ctx, appName, metav1.GetOptions{}) if err != nil { return nil, err } @@ -1563,7 +1584,7 @@ func (s *Server) TerminateOperation(ctx context.Context, termOpReq *application. return nil, status.Errorf(codes.InvalidArgument, "Unable to terminate operation. No operation is in progress") } a.Status.OperationState.Phase = common.OperationTerminating - updated, err := s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Update(ctx, a, metav1.UpdateOptions{}) + updated, err := s.appclientset.ArgoprojV1alpha1().Applications(ns).Update(ctx, a, metav1.UpdateOptions{}) if err == nil { s.waitSync(updated) s.logAppEvent(a, ctx, argo.EventReasonResourceUpdated, "terminated running operation") @@ -1574,7 +1595,7 @@ func (s *Server) TerminateOperation(ctx context.Context, termOpReq *application. } log.Warnf("Failed to set operation for app '%s' due to update conflict. Retrying again...", *termOpReq.Name) time.Sleep(100 * time.Millisecond) - a, err = s.appclientset.ArgoprojV1alpha1().Applications(s.ns).Get(ctx, *termOpReq.Name, metav1.GetOptions{}) + a, err = s.appclientset.ArgoprojV1alpha1().Applications(ns).Get(ctx, appName, metav1.GetOptions{}) if err != nil { return nil, err } @@ -1793,7 +1814,7 @@ func (s *Server) GetApplicationSyncWindows(ctx context.Context, q *application.A return nil, err } - proj, err := argo.GetAppProject(&a.Spec, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), a.Namespace, s.settingsMgr) + proj, err := argo.GetAppProject(a, applisters.NewAppProjectLister(s.projInformer.GetIndexer()), a.Namespace, s.settingsMgr) if err != nil { return nil, err } diff --git a/server/server.go b/server/server.go index 9b27dcf7fa014..1ff6b76f066cd 100644 --- a/server/server.go +++ b/server/server.go @@ -181,6 +181,7 @@ type ArgoCDServerOpts struct { RedisClient *redis.Client TLSConfigCustomizer tlsutil.ConfigCustomizer XFrameOptions string + WatchAllNamespaces bool } // initializeDefaultProject creates the default project if it does not already exist @@ -212,12 +213,17 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts) *ArgoCDServer { err = initializeDefaultProject(opts) errors.CheckError(err) - factory := appinformer.NewFilteredSharedInformerFactory(opts.AppClientset, 0, opts.Namespace, func(options *metav1.ListOptions) {}) + watchNamespace := opts.Namespace + if opts.WatchAllNamespaces { + log.Warnf("Watching all namespaces for applications") + watchNamespace = "" + } + factory := appinformer.NewFilteredSharedInformerFactory(opts.AppClientset, 0, watchNamespace, func(options *metav1.ListOptions) {}) projInformer := factory.Argoproj().V1alpha1().AppProjects().Informer() projLister := factory.Argoproj().V1alpha1().AppProjects().Lister().AppProjects(opts.Namespace) appInformer := factory.Argoproj().V1alpha1().Applications().Informer() - appLister := factory.Argoproj().V1alpha1().Applications().Lister().Applications(opts.Namespace) + appLister := factory.Argoproj().V1alpha1().Applications().Lister().Applications(watchNamespace) userStateStorage := util_session.NewUserStateStorage(opts.RedisClient) sessionMgr := util_session.NewSessionManager(settingsMgr, projLister, opts.DexServerAddr, userStateStorage) diff --git a/test/e2e/app_management_test.go b/test/e2e/app_management_test.go index ad06558c5bec4..449640419ba4e 100644 --- a/test/e2e/app_management_test.go +++ b/test/e2e/app_management_test.go @@ -33,6 +33,7 @@ import ( applicationpkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/application" repositorypkg "github.com/argoproj/argo-cd/v2/pkg/apiclient/repository" . "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + "github.com/argoproj/argo-cd/v2/test/e2e/fixture" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture" . "github.com/argoproj/argo-cd/v2/test/e2e/fixture/app" . "github.com/argoproj/argo-cd/v2/util/argo" @@ -129,7 +130,7 @@ func TestAppCreation(t *testing.T) { When(). // ensure that update replaces spec and merge labels and annotations And(func() { - FailOnErr(AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Patch(context.Background(), + FailOnErr(AppClientset.ArgoprojV1alpha1().Applications(fixture.AppNamespace()).Patch(context.Background(), ctx.GetName(), types.MergePatchType, []byte(`{"metadata": {"labels": { "test": "label" }, "annotations": { "test": "annotation" }}}`), metav1.PatchOptions{})) }). Create("--upsert"). @@ -289,11 +290,11 @@ func TestAppRollbackSuccessful(t *testing.T) { patch, _, err := diff.CreateTwoWayMergePatch(app, appWithHistory, &Application{}) assert.NoError(t, err) - app, err = AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{}) + app, err = AppClientset.ArgoprojV1alpha1().Applications(fixture.AppNamespace()).Patch(context.Background(), app.Name, types.MergePatchType, patch, metav1.PatchOptions{}) assert.NoError(t, err) // sync app and make sure it reaches InSync state - _, err = RunCli("app", "rollback", app.Name, "1") + _, err = RunCli("app", "rollback", app.QualifiedName(), "1") assert.NoError(t, err) }). @@ -339,7 +340,7 @@ func TestManipulateApplicationResources(t *testing.T) { Then(). Expect(SyncStatusIs(SyncStatusCodeSynced)). And(func(app *Application) { - manifests, err := RunCli("app", "manifests", app.Name, "--source", "live") + manifests, err := RunCli("app", "manifests", app.QualifiedName(), "--source", "live") assert.NoError(t, err) resources, err := kube.SplitYAML([]byte(manifests)) assert.NoError(t, err) @@ -360,7 +361,7 @@ func TestManipulateApplicationResources(t *testing.T) { defer io.Close(closer) _, err = client.DeleteResource(context.Background(), &applicationpkg.ApplicationResourceDeleteRequest{ - Name: &app.Name, + Name: pointer.StringPtr(app.QualifiedName()), Group: deployment.GroupVersionKind().Group, Kind: deployment.GroupVersionKind().Kind, Version: deployment.GroupVersionKind().Version, @@ -413,24 +414,24 @@ func TestAppWithSecrets(t *testing.T) { Namespace: app.Spec.Destination.Namespace, Kind: kube.SecretKind, Group: "", - Name: &app.Name, + Name: pointer.StringPtr(app.QualifiedName()), Version: "v1", ResourceName: "test-secret", })).(*applicationpkg.ApplicationResourceResponse) assetSecretDataHidden(t, res.Manifest) - manifests, err := client.GetManifests(context.Background(), &applicationpkg.ApplicationManifestQuery{Name: &app.Name}) + manifests, err := client.GetManifests(context.Background(), &applicationpkg.ApplicationManifestQuery{Name: pointer.StringPtr(app.QualifiedName())}) errors.CheckError(err) for _, manifest := range manifests.Manifests { assetSecretDataHidden(t, manifest) } - diffOutput := FailOnErr(RunCli("app", "diff", app.Name)).(string) + diffOutput := FailOnErr(RunCli("app", "diff", app.QualifiedName())).(string) assert.Empty(t, diffOutput) // make sure resource update error does not print secret details - _, err = RunCli("app", "patch-resource", "test-app-with-secrets", "--resource-name", "test-secret", + _, err = RunCli("app", "patch-resource", app.QualifiedName(), "--resource-name", "test-secret", "--kind", "Secret", "--patch", `{"op": "add", "path": "/data", "value": "hello"}'`, "--patch-type", "application/json-patch+json") require.Error(t, err) @@ -450,20 +451,20 @@ func TestAppWithSecrets(t *testing.T) { Then(). Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). And(func(app *Application) { - diffOutput, err := RunCli("app", "diff", app.Name) + diffOutput, err := RunCli("app", "diff", app.QualifiedName()) assert.Error(t, err) assert.Contains(t, diffOutput, "username: ++++++++") assert.Contains(t, diffOutput, "password: ++++++++++++") // local diff should ignore secrets - diffOutput = FailOnErr(RunCli("app", "diff", app.Name, "--local", "testdata/secrets")).(string) + diffOutput = FailOnErr(RunCli("app", "diff", app.QualifiedName(), "--local", "testdata/secrets")).(string) assert.Empty(t, diffOutput) // ignore missing field and make sure diff shows no difference app.Spec.IgnoreDifferences = []ResourceIgnoreDifferences{{ Kind: kube.SecretKind, JSONPointers: []string{"/data"}, }} - FailOnErr(client.UpdateSpec(context.Background(), &applicationpkg.ApplicationUpdateSpecRequest{Name: &app.Name, Spec: app.Spec})) + FailOnErr(client.UpdateSpec(context.Background(), &applicationpkg.ApplicationUpdateSpecRequest{Name: pointer.StringPtr(app.QualifiedName()), Spec: app.Spec})) }). When(). Refresh(RefreshTypeNormal). @@ -471,7 +472,7 @@ func TestAppWithSecrets(t *testing.T) { Expect(OperationPhaseIs(OperationSucceeded)). Expect(SyncStatusIs(SyncStatusCodeSynced)). And(func(app *Application) { - diffOutput := FailOnErr(RunCli("app", "diff", app.Name)).(string) + diffOutput := FailOnErr(RunCli("app", "diff", app.QualifiedName())).(string) assert.Empty(t, diffOutput) }). // verify not committed secret also ignore during diffing @@ -485,7 +486,7 @@ stringData: username: test-username`). Then(). And(func(app *Application) { - diffOutput := FailOnErr(RunCli("app", "diff", app.Name, "--local", "testdata/secrets")).(string) + diffOutput := FailOnErr(RunCli("app", "diff", app.QualifiedName(), "--local", "testdata/secrets")).(string) assert.Empty(t, diffOutput) }) } @@ -509,7 +510,7 @@ func TestResourceDiffing(t *testing.T) { Then(). Expect(SyncStatusIs(SyncStatusCodeOutOfSync)). And(func(app *Application) { - diffOutput, err := RunCli("app", "diff", app.Name, "--local", "testdata/guestbook") + diffOutput, err := RunCli("app", "diff", app.QualifiedName(), "--local", "testdata/guestbook") assert.Error(t, err) assert.Contains(t, diffOutput, fmt.Sprintf("===== apps/Deployment %s/guestbook-ui ======", DeploymentNamespace())) }). @@ -522,7 +523,7 @@ func TestResourceDiffing(t *testing.T) { Then(). Expect(SyncStatusIs(SyncStatusCodeSynced)). And(func(app *Application) { - diffOutput, err := RunCli("app", "diff", app.Name, "--local", "testdata/guestbook") + diffOutput, err := RunCli("app", "diff", app.QualifiedName(), "--local", "testdata/guestbook") assert.NoError(t, err) assert.Empty(t, diffOutput) }) @@ -597,7 +598,7 @@ func testEdgeCasesApplicationResources(t *testing.T, appPath string, statusCode expect. Expect(HealthIs(statusCode)). And(func(app *Application) { - diffOutput, err := RunCli("app", "diff", app.Name, "--local", path.Join("testdata", appPath)) + diffOutput, err := RunCli("app", "diff", app.QualifiedName(), "--local", path.Join("testdata", appPath)) assert.Empty(t, diffOutput) assert.NoError(t, err) }) @@ -657,7 +658,7 @@ func TestResourceAction(t *testing.T) { defer io.Close(closer) actions, err := client.ListResourceActions(context.Background(), &applicationpkg.ApplicationResourceRequest{ - Name: &app.Name, + Name: pointer.StringPtr(app.QualifiedName()), Group: "apps", Kind: "Deployment", Version: "v1", @@ -667,7 +668,7 @@ func TestResourceAction(t *testing.T) { assert.NoError(t, err) assert.Equal(t, []ResourceAction{{Name: "sample", Disabled: false}}, actions.Actions) - _, err = client.RunResourceAction(context.Background(), &applicationpkg.ResourceActionRunRequest{Name: &app.Name, + _, err = client.RunResourceAction(context.Background(), &applicationpkg.ResourceActionRunRequest{Name: pointer.StringPtr(app.QualifiedName()), Group: "apps", Kind: "Deployment", Version: "v1", @@ -692,11 +693,11 @@ func TestSyncResourceByLabel(t *testing.T) { Sync(). Then(). And(func(app *Application) { - _, _ = RunCli("app", "sync", app.Name, "--label", fmt.Sprintf("app.kubernetes.io/instance=%s", app.Name)) + _, _ = RunCli("app", "sync", app.QualifiedName(), "--label", fmt.Sprintf("app.kubernetes.io/instance=%s", app.InstanceName())) }). Expect(SyncStatusIs(SyncStatusCodeSynced)). And(func(app *Application) { - _, err := RunCli("app", "sync", app.Name, "--label", "this-label=does-not-exist") + _, err := RunCli("app", "sync", app.QualifiedName(), "--label", "this-label=does-not-exist") assert.Error(t, err) assert.Contains(t, err.Error(), "level=fatal") }) @@ -710,7 +711,7 @@ func TestLocalManifestSync(t *testing.T) { Sync(). Then(). And(func(app *Application) { - res, _ := RunCli("app", "manifests", app.Name) + res, _ := RunCli("app", "manifests", app.QualifiedName()) assert.Contains(t, res, "containerPort: 80") assert.Contains(t, res, "image: gcr.io/heptio-images/ks-guestbook-demo:0.2") }). @@ -721,7 +722,7 @@ func TestLocalManifestSync(t *testing.T) { Then(). Expect(SyncStatusIs(SyncStatusCodeSynced)). And(func(app *Application) { - res, _ := RunCli("app", "manifests", app.Name) + res, _ := RunCli("app", "manifests", app.QualifiedName()) assert.Contains(t, res, "containerPort: 81") assert.Contains(t, res, "image: gcr.io/heptio-images/ks-guestbook-demo:0.3") }). @@ -732,7 +733,7 @@ func TestLocalManifestSync(t *testing.T) { Then(). Expect(SyncStatusIs(SyncStatusCodeSynced)). And(func(app *Application) { - res, _ := RunCli("app", "manifests", app.Name) + res, _ := RunCli("app", "manifests", app.QualifiedName()) assert.Contains(t, res, "containerPort: 80") assert.Contains(t, res, "image: gcr.io/heptio-images/ks-guestbook-demo:0.2") }) @@ -746,7 +747,7 @@ func TestLocalSync(t *testing.T) { Create(). Then(). And(func(app *Application) { - FailOnErr(RunCli("app", "sync", app.Name, "--local", "testdata/helm")) + FailOnErr(RunCli("app", "sync", app.QualifiedName(), "--local", "testdata/helm")) }) } @@ -758,10 +759,10 @@ func TestNoLocalSyncWithAutosyncEnabled(t *testing.T) { Sync(). Then(). And(func(app *Application) { - _, err := RunCli("app", "set", app.Name, "--sync-policy", "automated") + _, err := RunCli("app", "set", app.QualifiedName(), "--sync-policy", "automated") assert.NoError(t, err) - _, err = RunCli("app", "sync", app.Name, "--local", guestbookPathLocal) + _, err = RunCli("app", "sync", app.QualifiedName(), "--local", guestbookPathLocal) assert.Error(t, err) }) } @@ -774,11 +775,11 @@ func TestLocalSyncDryRunWithAutosyncEnabled(t *testing.T) { Sync(). Then(). And(func(app *Application) { - _, err := RunCli("app", "set", app.Name, "--sync-policy", "automated") + _, err := RunCli("app", "set", app.QualifiedName(), "--sync-policy", "automated") assert.NoError(t, err) appBefore := app.DeepCopy() - _, err = RunCli("app", "sync", app.Name, "--dry-run", "--local", guestbookPathLocal) + _, err = RunCli("app", "sync", app.QualifiedName(), "--dry-run", "--local", guestbookPathLocal) assert.NoError(t, err) appAfter := app.DeepCopy() @@ -959,7 +960,7 @@ func TestSelfManagedApps(t *testing.T) { reconciledCount := 0 var lastReconciledAt *metav1.Time - for event := range ArgoCDClientset.WatchApplicationWithRetry(ctx, a.Name, a.ResourceVersion) { + for event := range ArgoCDClientset.WatchApplicationWithRetry(ctx, a.QualifiedName(), a.ResourceVersion) { reconciledAt := event.Application.Status.ReconciledAt if reconciledAt == nil { reconciledAt = &metav1.Time{} @@ -1019,6 +1020,7 @@ func TestOrphanedResource(t *testing.T) { SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true)}, + SourceNamespaces: []string{fixture.AppNamespace()}, }). Path(guestbookPath). When(). @@ -1039,7 +1041,7 @@ func TestOrphanedResource(t *testing.T) { Then(). Expect(Condition(ApplicationConditionOrphanedResourceWarning, "Application has 1 orphaned resources")). And(func(app *Application) { - output, err := RunCli("app", "resources", app.Name) + output, err := RunCli("app", "resources", app.QualifiedName()) assert.NoError(t, err) assert.Contains(t, output, "orphaned-configmap") }). @@ -1054,7 +1056,7 @@ func TestOrphanedResource(t *testing.T) { Then(). Expect(Condition(ApplicationConditionOrphanedResourceWarning, "Application has 1 orphaned resources")). And(func(app *Application) { - output, err := RunCli("app", "resources", app.Name) + output, err := RunCli("app", "resources", app.QualifiedName()) assert.NoError(t, err) assert.Contains(t, output, "orphaned-configmap") }). @@ -1063,6 +1065,7 @@ func TestOrphanedResource(t *testing.T) { SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true), Ignore: []OrphanedResourceKey{{Kind: "ConfigMap"}}}, + SourceNamespaces: []string{fixture.AppNamespace()}, }). When(). Refresh(RefreshTypeNormal). @@ -1070,7 +1073,7 @@ func TestOrphanedResource(t *testing.T) { Expect(SyncStatusIs(SyncStatusCodeSynced)). Expect(NoConditions()). And(func(app *Application) { - output, err := RunCli("app", "resources", app.Name) + output, err := RunCli("app", "resources", app.QualifiedName()) assert.NoError(t, err) assert.NotContains(t, output, "orphaned-configmap") }). @@ -1079,6 +1082,7 @@ func TestOrphanedResource(t *testing.T) { SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true), Ignore: []OrphanedResourceKey{{Kind: "ConfigMap", Name: "orphaned-configmap"}}}, + SourceNamespaces: []string{fixture.AppNamespace()}, }). When(). Refresh(RefreshTypeNormal). @@ -1086,7 +1090,7 @@ func TestOrphanedResource(t *testing.T) { Expect(SyncStatusIs(SyncStatusCodeSynced)). Expect(NoConditions()). And(func(app *Application) { - output, err := RunCli("app", "resources", app.Name) + output, err := RunCli("app", "resources", app.QualifiedName()) assert.NoError(t, err) assert.NotContains(t, output, "orphaned-configmap") }). @@ -1095,6 +1099,7 @@ func TestOrphanedResource(t *testing.T) { SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, OrphanedResources: nil, + SourceNamespaces: []string{fixture.AppNamespace()}, }). When(). Refresh(RefreshTypeNormal). @@ -1110,7 +1115,7 @@ func TestNotPermittedResources(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "sample-ingress", Labels: map[string]string{ - common.LabelKeyAppInstance: ctx.GetName(), + common.LabelKeyAppInstance: ctx.GetInstanceName(), }, }, Spec: networkingv1beta.IngressSpec{ @@ -1157,7 +1162,9 @@ func TestNotPermittedResources(t *testing.T) { Destinations: []ApplicationDestination{{Namespace: DeploymentNamespace(), Server: "*"}}, NamespaceResourceBlacklist: []metav1.GroupKind{ {Group: "", Kind: "Service"}, - }}). + }, + SourceNamespaces: []string{fixture.AppNamespace()}, + }). And(func() { FailOnErr(KubeClientset.NetworkingV1beta1().Ingresses(ArgoCDNamespace).Create(context.Background(), ingress, metav1.CreateOptions{})) FailOnErr(KubeClientset.CoreV1().Services(DeploymentNamespace()).Create(context.Background(), svc, metav1.CreateOptions{})) @@ -1200,7 +1207,7 @@ func TestSyncWithInfos(t *testing.T) { Create(). Then(). And(func(app *Application) { - _, err := RunCli("app", "sync", app.Name, + _, err := RunCli("app", "sync", app.QualifiedName(), "--info", fmt.Sprintf("%s=%s", expectedInfo[0].Name, expectedInfo[0].Value), "--info", fmt.Sprintf("%s=%s", expectedInfo[1].Name, expectedInfo[1].Value)) assert.NoError(t, err) @@ -1222,7 +1229,7 @@ func TestCreateAppWithNoNameSpaceForGlobalResource(t *testing.T) { Then(). And(func(app *Application) { time.Sleep(500 * time.Millisecond) - app, err := AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Get(context.Background(), app.Name, metav1.GetOptions{}) + app, err := AppClientset.ArgoprojV1alpha1().Applications(fixture.AppNamespace()).Get(context.Background(), app.Name, metav1.GetOptions{}) assert.NoError(t, err) assert.Len(t, app.Status.Conditions, 0) }) @@ -1240,7 +1247,7 @@ func TestCreateAppWithNoNameSpaceWhenRequired(t *testing.T) { Refresh(RefreshTypeNormal). Then(). And(func(app *Application) { - updatedApp, err := AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Get(context.Background(), app.Name, metav1.GetOptions{}) + updatedApp, err := AppClientset.ArgoprojV1alpha1().Applications(fixture.AppNamespace()).Get(context.Background(), app.Name, metav1.GetOptions{}) require.NoError(t, err) assert.Len(t, updatedApp.Status.Conditions, 2) @@ -1262,7 +1269,7 @@ func TestCreateAppWithNoNameSpaceWhenRequired2(t *testing.T) { Refresh(RefreshTypeNormal). Then(). And(func(app *Application) { - updatedApp, err := AppClientset.ArgoprojV1alpha1().Applications(ArgoCDNamespace).Get(context.Background(), app.Name, metav1.GetOptions{}) + updatedApp, err := AppClientset.ArgoprojV1alpha1().Applications(fixture.AppNamespace()).Get(context.Background(), app.Name, metav1.GetOptions{}) require.NoError(t, err) assert.Len(t, updatedApp.Status.Conditions, 2) @@ -1278,6 +1285,7 @@ func TestListResource(t *testing.T) { SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, OrphanedResources: &OrphanedResourcesMonitorSettings{Warn: pointer.BoolPtr(true)}, + SourceNamespaces: []string{fixture.AppNamespace()}, }). Path(guestbookPath). When(). @@ -1298,19 +1306,19 @@ func TestListResource(t *testing.T) { Then(). Expect(Condition(ApplicationConditionOrphanedResourceWarning, "Application has 1 orphaned resources")). And(func(app *Application) { - output, err := RunCli("app", "resources", app.Name) + output, err := RunCli("app", "resources", app.QualifiedName()) assert.NoError(t, err) assert.Contains(t, output, "orphaned-configmap") assert.Contains(t, output, "guestbook-ui") }). And(func(app *Application) { - output, err := RunCli("app", "resources", app.Name, "--orphaned=true") + output, err := RunCli("app", "resources", app.QualifiedName(), "--orphaned=true") assert.NoError(t, err) assert.Contains(t, output, "orphaned-configmap") assert.NotContains(t, output, "guestbook-ui") }). And(func(app *Application) { - output, err := RunCli("app", "resources", app.Name, "--orphaned=false") + output, err := RunCli("app", "resources", app.QualifiedName(), "--orphaned=false") assert.NoError(t, err) assert.NotContains(t, output, "orphaned-configmap") assert.Contains(t, output, "guestbook-ui") @@ -1320,6 +1328,7 @@ func TestListResource(t *testing.T) { SourceRepos: []string{"*"}, Destinations: []ApplicationDestination{{Namespace: "*", Server: "*"}}, OrphanedResources: nil, + SourceNamespaces: []string{fixture.AppNamespace()}, }). When(). Refresh(RefreshTypeNormal). @@ -1398,7 +1407,8 @@ func TestCreateDisableValidation(t *testing.T) { Then(). And(func(app *Application) { _, err := RunCli("app", "create", app.Name, "--upsert", "--validate=false", "--repo", RepoURL(RepoURLTypeFile), - "--path", "baddir2", "--project", app.Spec.Project, "--dest-server", KubernetesInternalAPIServerAddr, "--dest-namespace", DeploymentNamespace()) + "--path", "baddir2", "--project", app.Spec.Project, "--dest-server", KubernetesInternalAPIServerAddr, "--dest-namespace", DeploymentNamespace(), + "--app-namespace", fixture.AppNamespace()) assert.NoError(t, err) }). When(). @@ -1487,38 +1497,38 @@ definitions: Then(). // tests resource actions on a CRD using status subresource And(func(app *Application) { - _, err := RunCli("app", "actions", "run", app.Name, "--kind", "StatusSubResource", "update-both") + _, err := RunCli("app", "actions", "run", app.QualifiedName(), "--kind", "StatusSubResource", "update-both") assert.NoError(t, err) text := FailOnErr(Run(".", "kubectl", "-n", app.Spec.Destination.Namespace, "get", "statussubresources", "status-subresource", "-o", "jsonpath={.spec.foo}")).(string) assert.Equal(t, "update-both", text) text = FailOnErr(Run(".", "kubectl", "-n", app.Spec.Destination.Namespace, "get", "statussubresources", "status-subresource", "-o", "jsonpath={.status.bar}")).(string) assert.Equal(t, "update-both", text) - _, err = RunCli("app", "actions", "run", app.Name, "--kind", "StatusSubResource", "update-spec") + _, err = RunCli("app", "actions", "run", app.QualifiedName(), "--kind", "StatusSubResource", "update-spec") assert.NoError(t, err) text = FailOnErr(Run(".", "kubectl", "-n", app.Spec.Destination.Namespace, "get", "statussubresources", "status-subresource", "-o", "jsonpath={.spec.foo}")).(string) assert.Equal(t, "update-spec", text) - _, err = RunCli("app", "actions", "run", app.Name, "--kind", "StatusSubResource", "update-status") + _, err = RunCli("app", "actions", "run", app.QualifiedName(), "--kind", "StatusSubResource", "update-status") assert.NoError(t, err) text = FailOnErr(Run(".", "kubectl", "-n", app.Spec.Destination.Namespace, "get", "statussubresources", "status-subresource", "-o", "jsonpath={.status.bar}")).(string) assert.Equal(t, "update-status", text) }). // tests resource actions on a CRD *not* using status subresource And(func(app *Application) { - _, err := RunCli("app", "actions", "run", app.Name, "--kind", "NonStatusSubResource", "update-both") + _, err := RunCli("app", "actions", "run", app.QualifiedName(), "--kind", "NonStatusSubResource", "update-both") assert.NoError(t, err) text := FailOnErr(Run(".", "kubectl", "-n", app.Spec.Destination.Namespace, "get", "nonstatussubresources", "non-status-subresource", "-o", "jsonpath={.spec.foo}")).(string) assert.Equal(t, "update-both", text) text = FailOnErr(Run(".", "kubectl", "-n", app.Spec.Destination.Namespace, "get", "nonstatussubresources", "non-status-subresource", "-o", "jsonpath={.status.bar}")).(string) assert.Equal(t, "update-both", text) - _, err = RunCli("app", "actions", "run", app.Name, "--kind", "NonStatusSubResource", "update-spec") + _, err = RunCli("app", "actions", "run", app.QualifiedName(), "--kind", "NonStatusSubResource", "update-spec") assert.NoError(t, err) text = FailOnErr(Run(".", "kubectl", "-n", app.Spec.Destination.Namespace, "get", "nonstatussubresources", "non-status-subresource", "-o", "jsonpath={.spec.foo}")).(string) assert.Equal(t, "update-spec", text) - _, err = RunCli("app", "actions", "run", app.Name, "--kind", "NonStatusSubResource", "update-status") + _, err = RunCli("app", "actions", "run", app.QualifiedName(), "--kind", "NonStatusSubResource", "update-status") assert.NoError(t, err) text = FailOnErr(Run(".", "kubectl", "-n", app.Spec.Destination.Namespace, "get", "nonstatussubresources", "non-status-subresource", "-o", "jsonpath={.status.bar}")).(string) assert.Equal(t, "update-status", text) @@ -1535,17 +1545,17 @@ func TestAppLogs(t *testing.T) { Then(). Expect(HealthIs(health.HealthStatusHealthy)). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") + out, err := RunCli("app", "logs", app.QualifiedName(), "--kind", "Deployment", "--group", "", "--name", "guestbook-ui") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Pod") + out, err := RunCli("app", "logs", app.QualifiedName(), "--kind", "Pod") assert.NoError(t, err) assert.Contains(t, out, "Hi") }). And(func(app *Application) { - out, err := RunCli("app", "logs", app.Name, "--kind", "Service") + out, err := RunCli("app", "logs", app.QualifiedName(), "--kind", "Service") assert.NoError(t, err) assert.NotContains(t, out, "Hi") }) @@ -1571,9 +1581,8 @@ func TestAppWaitOperationInProgress(t *testing.T) { Then(). // stuck in running state Expect(OperationPhaseIs(OperationRunning)). - When(). - And(func() { - _, err := RunCli("app", "wait", Name(), "--suspended") + And(func(app *Application) { + _, err := RunCli("app", "wait", app.QualifiedName(), "--suspended") errors.CheckError(err) }) } diff --git a/test/e2e/cli_test.go b/test/e2e/cli_test.go index 16e119c51a711..c9b59a5a14c32 100644 --- a/test/e2e/cli_test.go +++ b/test/e2e/cli_test.go @@ -18,7 +18,7 @@ func TestCliAppCommand(t *testing.T) { When(). Create(). And(func() { - output, err := RunCli("app", "sync", Name(), "--timeout", "90") + output, err := RunCli("app", "sync", QualifiedName(), "--timeout", "90") assert.NoError(t, err) vars := map[string]interface{}{"Name": Name(), "Namespace": DeploymentNamespace()} assert.Contains(t, NormalizeOutput(output), Tmpl(`Pod {{.Namespace}} pod Synced Progressing pod/pod created`, vars)) diff --git a/test/e2e/cluster_test.go b/test/e2e/cluster_test.go index d67b642827ca5..0398cd35b1aaa 100644 --- a/test/e2e/cluster_test.go +++ b/test/e2e/cluster_test.go @@ -11,12 +11,15 @@ import ( ) func TestClusterList(t *testing.T) { + SkipIfAlreadyRun(t) output := FailOnErr(RunCli("cluster", "list")).(string) assert.Equal(t, fmt.Sprintf(`SERVER NAME VERSION STATUS MESSAGE https://kubernetes.default.svc in-cluster %v Successful `, GetVersions().ServerVersion), output) + RecordTestRun(t) } func TestClusterGet(t *testing.T) { + SkipIfAlreadyRun(t) output := FailOnErr(RunCli("cluster", "get", "https://kubernetes.default.svc")).(string) assert.Contains(t, output, fmt.Sprintf(` @@ -29,4 +32,5 @@ serverVersion: "%v"`, GetVersions().ServerVersion)) insecure: false`) assert.Contains(t, output, `status: Successful`) + RecordTestRun(t) } diff --git a/test/e2e/custom_tool_test.go b/test/e2e/custom_tool_test.go index 04fb24678862b..f1d530c5e3a4c 100644 --- a/test/e2e/custom_tool_test.go +++ b/test/e2e/custom_tool_test.go @@ -188,9 +188,9 @@ func TestCustomToolSyncAndDiffLocal(t *testing.T) { time.Sleep(1 * time.Second) }). And(func(app *Application) { - FailOnErr(RunCli("app", "sync", app.Name, "--local", "testdata/guestbook")) + FailOnErr(RunCli("app", "sync", app.QualifiedName(), "--local", "testdata/guestbook")) }). And(func(app *Application) { - FailOnErr(RunCli("app", "diff", app.Name, "--local", "testdata/guestbook")) + FailOnErr(RunCli("app", "diff", app.QualifiedName(), "--local", "testdata/guestbook")) }) } diff --git a/test/e2e/fixture/app/actions.go b/test/e2e/fixture/app/actions.go index dbc001e4321da..19386657b0dc1 100644 --- a/test/e2e/fixture/app/actions.go +++ b/test/e2e/fixture/app/actions.go @@ -3,6 +3,7 @@ package app import ( "fmt" "io/ioutil" + "os" log "github.com/sirupsen/logrus" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -71,14 +72,18 @@ func (a *Actions) CreateFromPartialFile(data string, flags ...string) *Actions { _, err = tmpFile.Write([]byte(data)) errors.CheckError(err) - args := append([]string{ + args := []string{ "app", "create", "-f", tmpFile.Name(), "--name", a.context.name, "--repo", fixture.RepoURL(a.context.repoURLType), "--dest-server", a.context.destServer, "--dest-namespace", fixture.DeploymentNamespace(), - }, flags...) + } + if os.Getenv("ARGOCD_E2E_APP_NAMESPACE") != "" { + args = append(args, "--app-namespace", os.Getenv("ARGOCD_E2E_APP_NAMESPACE")) + } + args = append(args, flags...) defer tmpFile.Close() a.runCli(args...) return a @@ -87,7 +92,8 @@ func (a *Actions) CreateFromFile(handler func(app *Application), flags ...string a.context.t.Helper() app := &Application{ ObjectMeta: v1.ObjectMeta{ - Name: a.context.name, + Name: a.context.name, + Namespace: fixture.AppNamespace(), }, Spec: ApplicationSpec{ Project: a.context.project, @@ -200,6 +206,9 @@ func (a *Actions) prepareCreateArgs(args []string) []string { if a.context.revision != "" { args = append(args, "--revision", a.context.revision) } + if ns := os.Getenv("ARGOCD_E2E_APP_NAMESPACE"); ns != "" { + args = append(args, "--app-namespace", ns) + } return args } @@ -211,7 +220,7 @@ func (a *Actions) Declarative(filename string) *Actions { func (a *Actions) DeclarativeWithCustomRepo(filename string, repoURL string) *Actions { a.context.t.Helper() values := map[string]interface{}{ - "ArgoCDNamespace": fixture.ArgoCDNamespace, + "ArgoCDNamespace": fixture.AppNamespace(), "DeploymentNamespace": fixture.DeploymentNamespace(), "Name": a.context.name, "Path": a.context.path, @@ -225,13 +234,13 @@ func (a *Actions) DeclarativeWithCustomRepo(filename string, repoURL string) *Ac func (a *Actions) PatchApp(patch string) *Actions { a.context.t.Helper() - a.runCli("app", "patch", a.context.name, "--patch", patch) + a.runCli("app", "patch", a.context.AppName(), "--patch", patch) return a } func (a *Actions) AppSet(flags ...string) *Actions { a.context.t.Helper() - args := []string{"app", "set", a.context.name} + args := []string{"app", "set", a.context.AppName()} args = append(args, flags...) a.runCli(args...) return a @@ -239,7 +248,7 @@ func (a *Actions) AppSet(flags ...string) *Actions { func (a *Actions) AppUnSet(flags ...string) *Actions { a.context.t.Helper() - args := []string{"app", "unset", a.context.name} + args := []string{"app", "unset", a.context.AppName()} args = append(args, flags...) a.runCli(args...) return a @@ -249,7 +258,7 @@ func (a *Actions) Sync(args ...string) *Actions { a.context.t.Helper() args = append([]string{"app", "sync"}, args...) if a.context.name != "" { - args = append(args, a.context.name) + args = append(args, a.context.AppName()) } args = append(args, "--timeout", fmt.Sprintf("%v", a.context.timeout)) @@ -282,7 +291,7 @@ func (a *Actions) Sync(args ...string) *Actions { func (a *Actions) TerminateOp() *Actions { a.context.t.Helper() - a.runCli("app", "terminate-op", a.context.name) + a.runCli("app", "terminate-op", a.context.AppName()) return a } @@ -293,14 +302,14 @@ func (a *Actions) Refresh(refreshType RefreshType) *Actions { RefreshTypeHard: "--hard-refresh", }[refreshType] - a.runCli("app", "get", a.context.name, flag) + a.runCli("app", "get", a.context.AppName(), flag) return a } func (a *Actions) Delete(cascade bool) *Actions { a.context.t.Helper() - a.runCli("app", "delete", a.context.name, fmt.Sprintf("--cascade=%v", cascade), "--yes") + a.runCli("app", "delete", a.context.AppName(), fmt.Sprintf("--cascade=%v", cascade), "--yes") return a } diff --git a/test/e2e/fixture/app/consequences.go b/test/e2e/fixture/app/consequences.go index 5530666a5ce0b..6f43d14641daa 100644 --- a/test/e2e/fixture/app/consequences.go +++ b/test/e2e/fixture/app/consequences.go @@ -62,7 +62,7 @@ func (c *Consequences) app() *Application { } func (c *Consequences) get() (*Application, error) { - return fixture.AppClientset.ArgoprojV1alpha1().Applications(fixture.ArgoCDNamespace).Get(context.Background(), c.context.name, v1.GetOptions{}) + return fixture.AppClientset.ArgoprojV1alpha1().Applications(fixture.AppNamespace()).Get(context.Background(), c.context.name, v1.GetOptions{}) } func (c *Consequences) resource(kind, name, namespace string) ResourceStatus { diff --git a/test/e2e/fixture/app/context.go b/test/e2e/fixture/app/context.go index c2db065f3d9e1..31a0c39856149 100644 --- a/test/e2e/fixture/app/context.go +++ b/test/e2e/fixture/app/context.go @@ -1,6 +1,7 @@ package app import ( + "os" "testing" "time" @@ -38,6 +39,15 @@ type Context struct { directoryRecurse bool } +// AppName gets the full qualified name to refer to an application. +func (c *Context) AppName() string { + ns := os.Getenv("ARGOCD_E2E_APP_NAMESPACE") + if ns != "" { + return ns + "/" + c.name + } + return c.name +} + func Given(t *testing.T) *Context { fixture.EnsureCleanState(t) // ARGOCE_E2E_DEFAULT_TIMEOUT can be used to override the default timeout @@ -157,6 +167,10 @@ func (c *Context) GetName() string { return c.name } +func (c *Context) GetInstanceName() string { + return fixture.AppNamespace() + "_" + c.name +} + func (c *Context) Name(name string) *Context { c.name = name return c diff --git a/test/e2e/fixture/app/expectation.go b/test/e2e/fixture/app/expectation.go index 3c92aca31846d..e63d8a91c0b74 100644 --- a/test/e2e/fixture/app/expectation.go +++ b/test/e2e/fixture/app/expectation.go @@ -219,10 +219,10 @@ func pods() (*v1.PodList, error) { func Event(reason string, message string) Expectation { return func(c *Consequences) (state, string) { - list, err := fixture.KubeClientset.CoreV1().Events(fixture.ArgoCDNamespace).List(context.Background(), metav1.ListOptions{ + list, err := fixture.KubeClientset.CoreV1().Events(fixture.AppNamespace()).List(context.Background(), metav1.ListOptions{ FieldSelector: fields.SelectorFromSet(map[string]string{ "involvedObject.name": c.context.name, - "involvedObject.namespace": fixture.ArgoCDNamespace, + "involvedObject.namespace": fixture.AppNamespace(), }).String(), }) if err != nil { diff --git a/test/e2e/fixture/fixture.go b/test/e2e/fixture/fixture.go index e5921f1afc9cd..7d301cd0c3d22 100644 --- a/test/e2e/fixture/fixture.go +++ b/test/e2e/fixture/fixture.go @@ -424,6 +424,9 @@ func EnsureCleanState(t *testing.T) { // delete resources // kubectl delete apps --all CheckError(AppClientset.ArgoprojV1alpha1().Applications(TestNamespace()).DeleteCollection(context.Background(), v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{})) + if ns := os.Getenv("ARGOCD_E2E_APP_NAMESPACE"); ns != "" { + CheckError(AppClientset.ArgoprojV1alpha1().Applications(ns).DeleteCollection(context.Background(), v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{})) + } // kubectl delete appprojects --field-selector metadata.name!=default CheckError(AppClientset.ArgoprojV1alpha1().AppProjects(TestNamespace()).DeleteCollection(context.Background(), v1.DeleteOptions{PropagationPolicy: &policy}, v1.ListOptions{FieldSelector: "metadata.name!=default"})) @@ -451,6 +454,7 @@ func EnsureCleanState(t *testing.T) { SourceRepos: []string{"*"}, Destinations: []v1alpha1.ApplicationDestination{{Namespace: "*", Server: "*"}}, ClusterResourceWhitelist: []v1.GroupKind{{Group: "*", Kind: "*"}}, + SourceNamespaces: []string{AppNamespace()}, }) // Create separate project for testing gpg signature verification @@ -461,6 +465,7 @@ func EnsureCleanState(t *testing.T) { Destinations: []v1alpha1.ApplicationDestination{{Namespace: "*", Server: "*"}}, ClusterResourceWhitelist: []v1.GroupKind{{Group: "*", Kind: "*"}}, SignatureKeys: []v1alpha1.SignatureKey{{KeyID: GpgGoodKeyID}}, + SourceNamespaces: []string{AppNamespace()}, }) // Recreate temp dir @@ -623,7 +628,7 @@ func Declarative(filename string, values interface{}) (string, error) { _, err = tmpFile.WriteString(Tmpl(string(bytes), values)) CheckError(err) defer tmpFile.Close() - return Run("", "kubectl", "-n", TestNamespace(), "apply", "-f", tmpFile.Name()) + return Run("", "kubectl", "-n", AppNamespace(), "apply", "-f", tmpFile.Name()) } func CreateSubmoduleRepos(repoType string) { @@ -740,3 +745,11 @@ func RecordTestRun(t *testing.T) { t.Fatalf("could not write to %s: %v", rf, err) } } + +func AppNamespace() string { + return GetEnvWithDefault("ARGOCD_E2E_APP_NAMESPACE", TestNamespace()) +} + +func QualifiedName() string { + return AppNamespace() + "/" + Name() +} diff --git a/test/e2e/helm_test.go b/test/e2e/helm_test.go index 910e32ccfe2f7..b492ce1ceaa1d 100644 --- a/test/e2e/helm_test.go +++ b/test/e2e/helm_test.go @@ -442,7 +442,7 @@ func TestHelmRepoDiffLocal(t *testing.T) { "--key-file", "../fixture/certs/argocd-test-client.key", "--ca-file", "../fixture/certs/argocd-test-ca.crt", )) - diffOutput := FailOnErr(RunCli("app", "diff", app.Name, "--local", "testdata/helm")).(string) + diffOutput := FailOnErr(RunCli("app", "diff", app.QualifiedName(), "--local", "testdata/helm")).(string) assert.Empty(t, diffOutput) }) } diff --git a/test/e2e/hook_test.go b/test/e2e/hook_test.go index d318721c781b5..c40ee6a7a6027 100644 --- a/test/e2e/hook_test.go +++ b/test/e2e/hook_test.go @@ -55,8 +55,8 @@ func TestHookDiff(t *testing.T) { When(). Create(). Then(). - And(func(_ *Application) { - output, err := RunCli("app", "diff", Name()) + And(func(app *Application) { + output, err := RunCli("app", "diff", app.QualifiedName()) assert.Error(t, err) assert.Contains(t, output, "name: pod") assert.NotContains(t, output, "name: hook") @@ -185,7 +185,7 @@ spec: Expect(OperationPhaseIs(OperationFailed)) } -func TestSyncFailHookPodFailureSyncFailFailure(t *testing.T) { +func TestSyncFailHookPodFailureSyncFail(t *testing.T) { // Tests that a failing SyncFail hook will successfully be marked as failed Given(t). Path("hook"). @@ -234,7 +234,7 @@ spec: } // make sure that we delete the hook on success -func TestHookDeletePolicyHookSucceededHookExit0(t *testing.T) { +func TestHookDeletePolicyHookSucceededExit0(t *testing.T) { Given(t). Path("hook"). When(). @@ -247,7 +247,7 @@ func TestHookDeletePolicyHookSucceededHookExit0(t *testing.T) { } // make sure that we delete the hook on failure, if policy is set -func TestHookDeletePolicyHookSucceededHookExit1(t *testing.T) { +func TestHookDeletePolicyHookSucceededExit1(t *testing.T) { Given(t). Path("hook"). When(). @@ -263,7 +263,7 @@ func TestHookDeletePolicyHookSucceededHookExit1(t *testing.T) { } // make sure that we do NOT delete the hook on success if failure policy is set -func TestHookDeletePolicyHookFailedHookExit0(t *testing.T) { +func TestHookDeletePolicyHookFailedExit0(t *testing.T) { Given(t). Path("hook"). When(). @@ -277,7 +277,7 @@ func TestHookDeletePolicyHookFailedHookExit0(t *testing.T) { } // make sure that we do delete the hook on failure if failure policy is set -func TestHookDeletePolicyHookFailedHookExit1(t *testing.T) { +func TestHookDeletePolicyHookFailedExit1(t *testing.T) { Given(t). Path("hook"). When(). diff --git a/test/e2e/jsonnet_test.go b/test/e2e/jsonnet_test.go index 507caf341f38b..cdd9294d49afa 100644 --- a/test/e2e/jsonnet_test.go +++ b/test/e2e/jsonnet_test.go @@ -22,7 +22,7 @@ func TestJsonnetAppliedCorrectly(t *testing.T) { Then(). Expect(SyncStatusIs(SyncStatusCodeSynced)). And(func(app *Application) { - manifests, err := RunCli("app", "manifests", app.Name, "--source", "live") + manifests, err := RunCli("app", "manifests", app.QualifiedName(), "--source", "live") assert.NoError(t, err) resources, err := kube.SplitYAML([]byte(manifests)) assert.NoError(t, err) @@ -52,7 +52,7 @@ func TestJsonnetTlaParameterAppliedCorrectly(t *testing.T) { Then(). Expect(SyncStatusIs(SyncStatusCodeSynced)). And(func(app *Application) { - manifests, err := RunCli("app", "manifests", app.Name, "--source", "live") + manifests, err := RunCli("app", "manifests", app.QualifiedName(), "--source", "live") assert.NoError(t, err) resources, err := kube.SplitYAML([]byte(manifests)) assert.NoError(t, err) diff --git a/test/e2e/sync_waves_test.go b/test/e2e/sync_waves_test.go index 48073b3d91044..606b2a8d61db1 100644 --- a/test/e2e/sync_waves_test.go +++ b/test/e2e/sync_waves_test.go @@ -54,7 +54,7 @@ func TestFixingDegradedApp(t *testing.T) { Expect(ResourceHealthIs("ConfigMap", "cm-2", health.HealthStatusHealthy)) } -func TestOneProgressingDeploymentIsSucceededAndSynced(t *testing.T) { +func TestProgressingDeplIsSucceededAndSynced(t *testing.T) { Given(t). Path("one-deployment"). When(). @@ -75,7 +75,7 @@ func TestOneProgressingDeploymentIsSucceededAndSynced(t *testing.T) { Expect(ResourceResultNumbering(1)) } -func TestDegradedDeploymentIsSucceededAndSynced(t *testing.T) { +func TestDegDeploymentIsSucceededAndSynced(t *testing.T) { Given(t). Path("one-deployment"). When(). diff --git a/test/e2e/testdata/self-managed-app/resources.yaml b/test/e2e/testdata/self-managed-app/resources.yaml index 86048b6848351..baaf0d6887b3b 100644 --- a/test/e2e/testdata/self-managed-app/resources.yaml +++ b/test/e2e/testdata/self-managed-app/resources.yaml @@ -2,7 +2,6 @@ apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: test-self-managed-apps - namespace: argocd-e2e spec: project: default diff --git a/test/fixture/testrepos/start-helm-registry.sh b/test/fixture/testrepos/start-helm-registry.sh index d803b1349481e..0c0987f9d6c42 100755 --- a/test/fixture/testrepos/start-helm-registry.sh +++ b/test/fixture/testrepos/start-helm-registry.sh @@ -1,3 +1,3 @@ #!/usr/bin/env bash export HELM_EXPERIMENTAL_OCI=1 -docker run -p 5000:5000 --restart=always --name registry registry +docker run --rm -p 5000:5000 --name registry registry diff --git a/util/argo/argo.go b/util/argo/argo.go index 6e4b5a23235cd..183434cc6d070 100644 --- a/util/argo/argo.go +++ b/util/argo/argo.go @@ -374,11 +374,14 @@ func APIGroupsToVersions(apiGroups []metav1.APIGroup) []string { } // GetAppProject returns a project from an application -func GetAppProject(spec *argoappv1.ApplicationSpec, projLister applicationsv1.AppProjectLister, ns string, settingsManager *settings.SettingsManager) (*argoappv1.AppProject, error) { - projOrig, err := projLister.AppProjects(ns).Get(spec.GetProject()) +func GetAppProject(app *argoappv1.Application, projLister applicationsv1.AppProjectLister, ns string, settingsManager *settings.SettingsManager) (*argoappv1.AppProject, error) { + projOrig, err := projLister.AppProjects(ns).Get(app.Spec.GetProject()) if err != nil { return nil, err } + if !projOrig.IsAppNamespacePermitted(app, ns) { + return nil, fmt.Errorf("application %s in namespace %s is not allowed to associate to project %s", app.Name, app.Namespace, projOrig.Name) + } return GetAppVirtualProject(projOrig, projLister, settingsManager) } @@ -440,6 +443,7 @@ func verifyGenerateManifests( // SetAppOperation updates an application with the specified operation, retrying conflict errors func SetAppOperation(appIf v1alpha1.ApplicationInterface, appName string, op *argoappv1.Operation) (*argoappv1.Application, error) { + log.Warnf("In set AppOperation") for { a, err := appIf.Get(context.Background(), appName, metav1.GetOptions{}) if err != nil { @@ -621,3 +625,21 @@ func mergeVirtualProject(proj *argoappv1.AppProject, globalProj *argoappv1.AppPr return proj } + +// ParseAppNamespacedName parses a namespaced name in the format namespace/name +// and returns the components. If name wasn't namespaced, defaultNs will be +// returned as namespace component. +func ParseAppNamespacedName(name string, defaultNs string) (string, string) { + var ns string + var appName string + t := strings.SplitN(name, "/", 2) + if len(t) == 2 { + ns = t[0] + appName = t[1] + } else { + ns = defaultNs + appName = t[0] + } + + return appName, ns +} diff --git a/util/argo/argo_test.go b/util/argo/argo_test.go index beea8c489805a..5a3a43fd148da 100644 --- a/util/argo/argo_test.go +++ b/util/argo/argo_test.go @@ -73,7 +73,7 @@ func TestGetAppProjectWithNoProjDefined(t *testing.T) { kubeClient := fake.NewSimpleClientset(&cm) settingsMgr := settings.NewSettingsManager(context.Background(), kubeClient, test.FakeArgoCDNamespace) - proj, err := GetAppProject(&testApp.Spec, applisters.NewAppProjectLister(informer.GetIndexer()), namespace, settingsMgr) + proj, err := GetAppProject(&testApp, applisters.NewAppProjectLister(informer.GetIndexer()), namespace, settingsMgr) assert.Nil(t, err) assert.Equal(t, proj.Name, projName) }