aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
480 lines • 86.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.destroyStack = exports.makeBodyParameterAndUpload = exports.deployStack = void 0;
const cxapi = require("@aws-cdk/cx-api");
const chalk = require("chalk");
const fs = require("fs-extra");
const uuid = require("uuid");
const evaluate_cloudformation_template_1 = require("./evaluate-cloudformation-template");
const common_1 = require("./hotswap/common");
const hotswap_deployments_1 = require("./hotswap-deployments");
const cloudformation_1 = require("./util/cloudformation");
const stack_activity_monitor_1 = require("./util/cloudformation/stack-activity-monitor");
const assets_1 = require("../assets");
const logging_1 = require("../logging");
const serialize_1 = require("../serialize");
const asset_manifest_builder_1 = require("../util/asset-manifest-builder");
const asset_publishing_1 = require("../util/asset-publishing");
const content_hash_1 = require("../util/content-hash");
const LARGE_TEMPLATE_SIZE_KB = 50;
async function deployStack(options) {
const stackArtifact = options.stack;
const stackEnv = options.resolvedEnvironment;
options.sdk.appendCustomUserAgent(options.extraUserAgent);
const cfn = options.sdk.cloudFormation();
const deployName = options.deployName || stackArtifact.stackName;
let cloudFormationStack = await cloudformation_1.CloudFormationStack.lookup(cfn, deployName);
if (cloudFormationStack.stackStatus.isCreationFailure) {
(0, logging_1.debug)(`Found existing stack ${deployName} that had previously failed creation. Deleting it before attempting to re-create it.`);
await cfn.deleteStack({ StackName: deployName }).promise();
const deletedStack = await (0, cloudformation_1.waitForStackDelete)(cfn, deployName);
if (deletedStack && deletedStack.stackStatus.name !== 'DELETE_COMPLETE') {
throw new Error(`Failed deleting stack ${deployName} that had previously failed creation (current state: ${deletedStack.stackStatus})`);
}
// Update variable to mark that the stack does not exist anymore, but avoid
// doing an actual lookup in CloudFormation (which would be silly to do if
// we just deleted it).
cloudFormationStack = cloudformation_1.CloudFormationStack.doesNotExist(cfn, deployName);
}
// Detect "legacy" assets (which remain in the metadata) and publish them via
// an ad-hoc asset manifest, while passing their locations via template
// parameters.
const legacyAssets = new asset_manifest_builder_1.AssetManifestBuilder();
const assetParams = await (0, assets_1.addMetadataAssetsToManifest)(stackArtifact, legacyAssets, options.envResources, options.reuseAssets);
const finalParameterValues = { ...options.parameters, ...assetParams };
const templateParams = cloudformation_1.TemplateParameters.fromTemplate(stackArtifact.template);
const stackParams = options.usePreviousParameters
? templateParams.updateExisting(finalParameterValues, cloudFormationStack.parameters)
: templateParams.supplyAll(finalParameterValues);
if (await canSkipDeploy(options, cloudFormationStack, stackParams.hasChanges(cloudFormationStack.parameters))) {
(0, logging_1.debug)(`${deployName}: skipping deployment (use --force to override)`);
// if we can skip deployment and we are performing a hotswap, let the user know
// that no hotswap deployment happened
if (options.hotswap !== common_1.HotswapMode.FULL_DEPLOYMENT) {
(0, logging_1.print)(`\n ${common_1.ICON} %s\n`, chalk.bold('hotswap deployment skipped - no changes were detected (use --force to override)'));
}
return {
noOp: true,
outputs: cloudFormationStack.outputs,
stackArn: cloudFormationStack.stackId,
};
}
else {
(0, logging_1.debug)(`${deployName}: deploying...`);
}
const bodyParameter = await makeBodyParameter(stackArtifact, options.resolvedEnvironment, legacyAssets, options.envResources, options.sdk, options.overrideTemplate);
await (0, asset_publishing_1.publishAssets)(legacyAssets.toManifest(stackArtifact.assembly.directory), options.sdkProvider, stackEnv, {
parallel: options.assetParallelism,
});
const hotswapMode = options.hotswap;
if (hotswapMode && hotswapMode !== common_1.HotswapMode.FULL_DEPLOYMENT) {
// attempt to short-circuit the deployment if possible
try {
const hotswapDeploymentResult = await (0, hotswap_deployments_1.tryHotswapDeployment)(options.sdkProvider, stackParams.values, cloudFormationStack, stackArtifact, hotswapMode);
if (hotswapDeploymentResult) {
return hotswapDeploymentResult;
}
(0, logging_1.print)('Could not perform a hotswap deployment, as the stack %s contains non-Asset changes', stackArtifact.displayName);
}
catch (e) {
if (!(e instanceof evaluate_cloudformation_template_1.CfnEvaluationException)) {
throw e;
}
(0, logging_1.print)('Could not perform a hotswap deployment, because the CloudFormation template could not be resolved: %s', e.message);
}
if (hotswapMode === common_1.HotswapMode.FALL_BACK) {
(0, logging_1.print)('Falling back to doing a full deployment');
options.sdk.appendCustomUserAgent('cdk-hotswap/fallback');
}
else {
return { noOp: true, stackArn: cloudFormationStack.stackId, outputs: cloudFormationStack.outputs };
}
}
// could not short-circuit the deployment, perform a full CFN deploy instead
const fullDeployment = new FullCloudFormationDeployment(options, cloudFormationStack, stackArtifact, stackParams, bodyParameter);
return fullDeployment.performDeployment();
}
exports.deployStack = deployStack;
/**
* This class shares state and functionality between the different full deployment modes
*/
class FullCloudFormationDeployment {
constructor(options, cloudFormationStack, stackArtifact, stackParams, bodyParameter) {
this.options = options;
this.cloudFormationStack = cloudFormationStack;
this.stackArtifact = stackArtifact;
this.stackParams = stackParams;
this.bodyParameter = bodyParameter;
this.cfn = options.sdk.cloudFormation();
this.stackName = options.deployName ?? stackArtifact.stackName;
this.update = cloudFormationStack.exists && cloudFormationStack.stackStatus.name !== 'REVIEW_IN_PROGRESS';
this.verb = this.update ? 'update' : 'create';
this.uuid = uuid.v4();
}
async performDeployment() {
const deploymentMethod = this.options.deploymentMethod ?? { method: 'change-set' };
if (deploymentMethod.method === 'direct' && this.options.resourcesToImport) {
throw new Error('Importing resources requires a changeset deployment');
}
switch (deploymentMethod.method) {
case 'change-set':
return this.changeSetDeployment(deploymentMethod);
case 'direct':
return this.directDeployment();
}
}
async changeSetDeployment(deploymentMethod) {
const changeSetName = deploymentMethod.changeSetName ?? 'cdk-deploy-change-set';
const execute = deploymentMethod.execute ?? true;
const changeSetDescription = await this.createChangeSet(changeSetName, execute);
await this.updateTerminationProtection();
if ((0, cloudformation_1.changeSetHasNoChanges)(changeSetDescription)) {
(0, logging_1.debug)('No changes are to be performed on %s.', this.stackName);
if (execute) {
(0, logging_1.debug)('Deleting empty change set %s', changeSetDescription.ChangeSetId);
await this.cfn.deleteChangeSet({ StackName: this.stackName, ChangeSetName: changeSetName }).promise();
}
return { noOp: true, outputs: this.cloudFormationStack.outputs, stackArn: changeSetDescription.StackId };
}
if (!execute) {
(0, logging_1.print)('Changeset %s created and waiting in review for manual execution (--no-execute)', changeSetDescription.ChangeSetId);
return { noOp: false, outputs: this.cloudFormationStack.outputs, stackArn: changeSetDescription.StackId };
}
return this.executeChangeSet(changeSetDescription);
}
async createChangeSet(changeSetName, willExecute) {
await this.cleanupOldChangeset(changeSetName);
(0, logging_1.debug)(`Attempting to create ChangeSet with name ${changeSetName} to ${this.verb} stack ${this.stackName}`);
(0, logging_1.print)('%s: creating CloudFormation changeset...', chalk.bold(this.stackName));
const changeSet = await this.cfn.createChangeSet({
StackName: this.stackName,
ChangeSetName: changeSetName,
ChangeSetType: this.options.resourcesToImport ? 'IMPORT' : this.update ? 'UPDATE' : 'CREATE',
ResourcesToImport: this.options.resourcesToImport,
Description: `CDK Changeset for execution ${this.uuid}`,
ClientToken: `create${this.uuid}`,
...this.commonPrepareOptions(),
}).promise();
(0, logging_1.debug)('Initiated creation of changeset: %s; waiting for it to finish creating...', changeSet.Id);
// Fetching all pages if we'll execute, so we can have the correct change count when monitoring.
return (0, cloudformation_1.waitForChangeSet)(this.cfn, this.stackName, changeSetName, { fetchAll: willExecute });
}
async executeChangeSet(changeSet) {
(0, logging_1.debug)('Initiating execution of changeset %s on stack %s', changeSet.ChangeSetId, this.stackName);
await this.cfn.executeChangeSet({
StackName: this.stackName,
ChangeSetName: changeSet.ChangeSetName,
ClientRequestToken: `exec${this.uuid}`,
...this.commonExecuteOptions(),
}).promise();
(0, logging_1.debug)('Execution of changeset %s on stack %s has started; waiting for the update to complete...', changeSet.ChangeSetId, this.stackName);
// +1 for the extra event emitted from updates.
const changeSetLength = (changeSet.Changes ?? []).length + (this.update ? 1 : 0);
return this.monitorDeployment(changeSet.CreationTime, changeSetLength);
}
async cleanupOldChangeset(changeSetName) {
if (this.cloudFormationStack.exists) {
// Delete any existing change sets generated by CDK since change set names must be unique.
// The delete request is successful as long as the stack exists (even if the change set does not exist).
(0, logging_1.debug)(`Removing existing change set with name ${changeSetName} if it exists`);
await this.cfn.deleteChangeSet({ StackName: this.stackName, ChangeSetName: changeSetName }).promise();
}
}
async updateTerminationProtection() {
// Update termination protection only if it has changed.
const terminationProtection = this.stackArtifact.terminationProtection ?? false;
if (!!this.cloudFormationStack.terminationProtection !== terminationProtection) {
(0, logging_1.debug)('Updating termination protection from %s to %s for stack %s', this.cloudFormationStack.terminationProtection, terminationProtection, this.stackName);
await this.cfn.updateTerminationProtection({
StackName: this.stackName,
EnableTerminationProtection: terminationProtection,
}).promise();
(0, logging_1.debug)('Termination protection updated to %s for stack %s', terminationProtection, this.stackName);
}
}
async directDeployment() {
(0, logging_1.print)('%s: %s stack...', chalk.bold(this.stackName), this.update ? 'updating' : 'creating');
const startTime = new Date();
if (this.update) {
await this.cfn.updateStack({
StackName: this.stackName,
ClientRequestToken: `update${this.uuid}`,
...this.commonPrepareOptions(),
...this.commonExecuteOptions(),
}).promise();
const ret = await this.monitorDeployment(startTime, undefined);
await this.updateTerminationProtection();
return ret;
}
else {
// Take advantage of the fact that we can set termination protection during create
const terminationProtection = this.stackArtifact.terminationProtection ?? false;
await this.cfn.createStack({
StackName: this.stackName,
ClientRequestToken: `create${this.uuid}`,
...terminationProtection ? { EnableTerminationProtection: true } : undefined,
...this.commonPrepareOptions(),
...this.commonExecuteOptions(),
}).promise();
return this.monitorDeployment(startTime, undefined);
}
}
async monitorDeployment(startTime, expectedChanges) {
const monitor = this.options.quiet ? undefined : stack_activity_monitor_1.StackActivityMonitor.withDefaultPrinter(this.cfn, this.stackName, this.stackArtifact, {
resourcesTotal: expectedChanges,
progress: this.options.progress,
changeSetCreationTime: startTime,
ci: this.options.ci,
}).start();
let finalState = this.cloudFormationStack;
try {
const successStack = await (0, cloudformation_1.waitForStackDeploy)(this.cfn, this.stackName);
// This shouldn't really happen, but catch it anyway. You never know.
if (!successStack) {
throw new Error('Stack deploy failed (the stack disappeared while we were deploying it)');
}
finalState = successStack;
}
catch (e) {
throw new Error(suffixWithErrors(e.message, monitor?.errors));
}
finally {
await monitor?.stop();
}
(0, logging_1.debug)('Stack %s has completed updating', this.stackName);
return { noOp: false, outputs: finalState.outputs, stackArn: finalState.stackId };
}
/**
* Return the options that are shared between CreateStack, UpdateStack and CreateChangeSet
*/
commonPrepareOptions() {
return {
Capabilities: ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'],
NotificationARNs: this.options.notificationArns,
Parameters: this.stackParams.apiParameters,
RoleARN: this.options.roleArn,
TemplateBody: this.bodyParameter.TemplateBody,
TemplateURL: this.bodyParameter.TemplateURL,
Tags: this.options.tags,
};
}
/**
* Return the options that are shared between UpdateStack and CreateChangeSet
*
* Be careful not to add in keys for options that aren't used, as the features may not have been
* deployed everywhere yet.
*/
commonExecuteOptions() {
const shouldDisableRollback = this.options.rollback === false;
return {
StackName: this.stackName,
...shouldDisableRollback ? { DisableRollback: true } : undefined,
};
}
}
/**
* Prepares the body parameter for +CreateChangeSet+.
*
* If the template is small enough to be inlined into the API call, just return
* it immediately.
*
* Otherwise, add it to the asset manifest to get uploaded to the staging
* bucket and return its coordinates. If there is no staging bucket, an error
* is thrown.
*
* @param stack the synthesized stack that provides the CloudFormation template
* @param toolkitInfo information about the toolkit stack
*/
async function makeBodyParameter(stack, resolvedEnvironment, assetManifest, resources, sdk, overrideTemplate) {
// If the template has already been uploaded to S3, just use it from there.
if (stack.stackTemplateAssetObjectUrl && !overrideTemplate) {
return { TemplateURL: restUrlFromManifest(stack.stackTemplateAssetObjectUrl, resolvedEnvironment, sdk) };
}
// Otherwise, pass via API call (if small) or upload here (if large)
const templateJson = (0, serialize_1.toYAML)(overrideTemplate ?? stack.template);
if (templateJson.length <= LARGE_TEMPLATE_SIZE_KB * 1024) {
return { TemplateBody: templateJson };
}
const toolkitInfo = await resources.lookupToolkit();
if (!toolkitInfo.found) {
(0, logging_1.error)(`The template for stack "${stack.displayName}" is ${Math.round(templateJson.length / 1024)}KiB. ` +
`Templates larger than ${LARGE_TEMPLATE_SIZE_KB}KiB must be uploaded to S3.\n` +
'Run the following command in order to setup an S3 bucket in this environment, and then re-deploy:\n\n', chalk.blue(`\t$ cdk bootstrap ${resolvedEnvironment.name}\n`));
throw new Error('Template too large to deploy ("cdk bootstrap" is required)');
}
const templateHash = (0, content_hash_1.contentHash)(templateJson);
const key = `cdk/${stack.id}/${templateHash}.yml`;
let templateFile = stack.templateFile;
if (overrideTemplate) {
// Add a variant of this template
templateFile = `${stack.templateFile}-${templateHash}.yaml`;
await fs.writeFile(templateFile, templateJson, { encoding: 'utf-8' });
}
assetManifest.addFileAsset(templateHash, {
path: templateFile,
}, {
bucketName: toolkitInfo.bucketName,
objectKey: key,
});
const templateURL = `${toolkitInfo.bucketUrl}/${key}`;
(0, logging_1.debug)('Storing template in S3 at:', templateURL);
return { TemplateURL: templateURL };
}
/**
* Prepare a body parameter for CFN, performing the upload
*
* Return it as-is if it is small enough to pass in the API call,
* upload to S3 and return the coordinates if it is not.
*/
async function makeBodyParameterAndUpload(stack, resolvedEnvironment, resources, sdkProvider, sdk, overrideTemplate) {
// We don't have access to the actual asset manifest here, so pretend that the
// stack doesn't have a pre-published URL.
const forceUploadStack = Object.create(stack, {
stackTemplateAssetObjectUrl: { value: undefined },
});
const builder = new asset_manifest_builder_1.AssetManifestBuilder();
const bodyparam = await makeBodyParameter(forceUploadStack, resolvedEnvironment, builder, resources, sdk, overrideTemplate);
const manifest = builder.toManifest(stack.assembly.directory);
await (0, asset_publishing_1.publishAssets)(manifest, sdkProvider, resolvedEnvironment, { quiet: true });
return bodyparam;
}
exports.makeBodyParameterAndUpload = makeBodyParameterAndUpload;
async function destroyStack(options) {
const deployName = options.deployName || options.stack.stackName;
const cfn = options.sdk.cloudFormation();
const currentStack = await cloudformation_1.CloudFormationStack.lookup(cfn, deployName);
if (!currentStack.exists) {
return;
}
const monitor = options.quiet ? undefined : stack_activity_monitor_1.StackActivityMonitor.withDefaultPrinter(cfn, deployName, options.stack, {
ci: options.ci,
}).start();
try {
await cfn.deleteStack({ StackName: deployName, RoleARN: options.roleArn }).promise();
const destroyedStack = await (0, cloudformation_1.waitForStackDelete)(cfn, deployName);
if (destroyedStack && destroyedStack.stackStatus.name !== 'DELETE_COMPLETE') {
throw new Error(`Failed to destroy ${deployName}: ${destroyedStack.stackStatus}`);
}
}
catch (e) {
throw new Error(suffixWithErrors(e.message, monitor?.errors));
}
finally {
if (monitor) {
await monitor.stop();
}
}
}
exports.destroyStack = destroyStack;
/**
* Checks whether we can skip deployment
*
* We do this in a complicated way by preprocessing (instead of just
* looking at the changeset), because if there are nested stacks involved
* the changeset will always show the nested stacks as needing to be
* updated, and the deployment will take a long time to in effect not
* do anything.
*/
async function canSkipDeploy(deployStackOptions, cloudFormationStack, parameterChanges) {
const deployName = deployStackOptions.deployName || deployStackOptions.stack.stackName;
(0, logging_1.debug)(`${deployName}: checking if we can skip deploy`);
// Forced deploy
if (deployStackOptions.force) {
(0, logging_1.debug)(`${deployName}: forced deployment`);
return false;
}
// Creating changeset only (default true), never skip
if (deployStackOptions.deploymentMethod?.method === 'change-set' && deployStackOptions.deploymentMethod.execute === false) {
(0, logging_1.debug)(`${deployName}: --no-execute, always creating change set`);
return false;
}
// No existing stack
if (!cloudFormationStack.exists) {
(0, logging_1.debug)(`${deployName}: no existing stack`);
return false;
}
// Template has changed (assets taken into account here)
if (JSON.stringify(deployStackOptions.stack.template) !== JSON.stringify(await cloudFormationStack.template())) {
(0, logging_1.debug)(`${deployName}: template has changed`);
return false;
}
// Tags have changed
if (!compareTags(cloudFormationStack.tags, deployStackOptions.tags ?? [])) {
(0, logging_1.debug)(`${deployName}: tags have changed`);
return false;
}
// Termination protection has been updated
if (!!deployStackOptions.stack.terminationProtection !== !!cloudFormationStack.terminationProtection) {
(0, logging_1.debug)(`${deployName}: termination protection has been updated`);
return false;
}
// Parameters have changed
if (parameterChanges) {
if (parameterChanges === 'ssm') {
(0, logging_1.debug)(`${deployName}: some parameters come from SSM so we have to assume they may have changed`);
}
else {
(0, logging_1.debug)(`${deployName}: parameters have changed`);
}
return false;
}
// Existing stack is in a failed state
if (cloudFormationStack.stackStatus.isFailure) {
(0, logging_1.debug)(`${deployName}: stack is in a failure state`);
return false;
}
// We can skip deploy
return true;
}
/**
* Compares two list of tags, returns true if identical.
*/
function compareTags(a, b) {
if (a.length !== b.length) {
return false;
}
for (const aTag of a) {
const bTag = b.find(tag => tag.Key === aTag.Key);
if (!bTag || bTag.Value !== aTag.Value) {
return false;
}
}
return true;
}
/**
* Format an S3 URL in the manifest for use with CloudFormation
*
* Replaces environment placeholders (which this field may contain),
* and reformats s3://.../... urls into S3 REST URLs (which CloudFormation
* expects)
*/
function restUrlFromManifest(url, environment, sdk) {
const doNotUseMarker = '**DONOTUSE**';
// This URL may contain placeholders, so still substitute those.
url = cxapi.EnvironmentPlaceholders.replace(url, {
accountId: environment.account,
region: environment.region,
partition: doNotUseMarker,
});
// Yes, this is extremely crude, but we don't actually need this so I'm not inclined to spend
// a lot of effort trying to thread the right value to this location.
if (url.indexOf(doNotUseMarker) > -1) {
throw new Error('Cannot use \'${AWS::Partition}\' in the \'stackTemplateAssetObjectUrl\' field');
}
const s3Url = url.match(/s3:\/\/([^/]+)\/(.*)$/);
if (!s3Url) {
return url;
}
// We need to pass an 'https://s3.REGION.amazonaws.com[.cn]/bucket/object' URL to CloudFormation, but we
// got an 's3://bucket/object' URL instead. Construct the rest API URL here.
const bucketName = s3Url[1];
const objectKey = s3Url[2];
const urlSuffix = sdk.getEndpointSuffix(environment.region);
return `https://s3.${environment.region}.${urlSuffix}/${bucketName}/${objectKey}`;
}
function suffixWithErrors(msg, errors) {
return errors && errors.length > 0
? `${msg}: ${errors.join(', ')}`
: msg;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwbG95LXN0YWNrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGVwbG95LXN0YWNrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHlDQUF5QztBQUV6QywrQkFBK0I7QUFDL0IsK0JBQStCO0FBQy9CLDZCQUE2QjtBQUc3Qix5RkFBNEU7QUFDNUUsNkNBQXFEO0FBQ3JELCtEQUE2RDtBQUM3RCwwREFHK0I7QUFDL0IseUZBQTJHO0FBQzNHLHNDQUF3RDtBQUV4RCx3Q0FBaUQ7QUFDakQsNENBQXNDO0FBQ3RDLDJFQUFzRTtBQUN0RSwrREFBeUQ7QUFDekQsdURBQW1EO0FBc05uRCxNQUFNLHNCQUFzQixHQUFHLEVBQUUsQ0FBQztBQUUzQixLQUFLLFVBQVUsV0FBVyxDQUFDLE9BQTJCO0lBQzNELE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxLQUFLLENBQUM7SUFFcEMsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixDQUFDO0lBRTdDLE9BQU8sQ0FBQyxHQUFHLENBQUMscUJBQXFCLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQzFELE1BQU0sR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxFQUFFLENBQUM7SUFDekMsTUFBTSxVQUFVLEdBQUcsT0FBTyxDQUFDLFVBQVUsSUFBSSxhQUFhLENBQUMsU0FBUyxDQUFDO0lBQ2pFLElBQUksbUJBQW1CLEdBQUcsTUFBTSxvQ0FBbUIsQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBRTVFLElBQUksbUJBQW1CLENBQUMsV0FBVyxDQUFDLGlCQUFpQixFQUFFO1FBQ3JELElBQUEsZUFBSyxFQUFDLHdCQUF3QixVQUFVLHNGQUFzRixDQUFDLENBQUM7UUFDaEksTUFBTSxHQUFHLENBQUMsV0FBVyxDQUFDLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDM0QsTUFBTSxZQUFZ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QyxJQUFJLENBQUMsRUFBRTtRQUNoQyxDQUFDLENBQUMsR0FBRyxDQUFDO0FBQ1YsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGN4YXBpIGZyb20gJ0Bhd3MtY2RrL2N4LWFwaSc7XG5pbXBvcnQgdHlwZSB7IENsb3VkRm9ybWF0aW9uIH0gZnJvbSAnYXdzLXNkayc7XG5pbXBvcnQgKiBhcyBjaGFsayBmcm9tICdjaGFsayc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy1leHRyYSc7XG5pbXBvcnQgKiBhcyB1dWlkIGZyb20gJ3V1aWQnO1xuaW1wb3J0IHsgSVNESywgU2RrUHJvdmlkZXIgfSBmcm9tICcuL2F3cy1hdXRoJztcbmltcG9ydCB7IEVudmlyb25tZW50UmVzb3VyY2VzIH0gZnJvbSAnLi9lbnZpcm9ubWVudC1yZXNvdXJjZXMnO1xuaW1wb3J0IHsgQ2ZuRXZhbHVhdGlvbkV4Y2VwdGlvbiB9IGZyb20gJy4vZXZhbHVhdGUtY2xvdWRmb3JtYXRpb24tdGVtcGxhdGUnO1xuaW1wb3J0IHsgSG90c3dhcE1vZGUsIElDT04gfSBmcm9tICcuL2hvdHN3YXAvY29tbW9uJztcbmltcG9ydCB7IHRyeUhvdHN3YXBEZXBsb3ltZW50IH0gZnJvbSAnLi9ob3Rzd2FwLWRlcGxveW1lbnRzJztcbmltcG9ydCB7XG4gIGNoYW5nZVNldEhhc05vQ2hhbmdlcywgQ2xvdWRGb3JtYXRpb25TdGFjaywgVGVtcGxhdGVQYXJhbWV0ZXJzLCB3YWl0Rm9yQ2hhbmdlU2V0LFxuICB3YWl0Rm9yU3RhY2tEZXBsb3ksIHdhaXRGb3JTdGFja0RlbGV0ZSwgUGFyYW1ldGVyVmFsdWVzLCBQYXJhbWV0ZXJDaGFuZ2VzLCBSZXNvdXJjZXNUb0ltcG9ydCxcbn0gZnJvbSAnLi91dGlsL2Nsb3VkZm9ybWF0aW9uJztcbmltcG9ydCB7IFN0YWNrQWN0aXZpdHlNb25pdG9yLCBTdGFja0FjdGl2aXR5UHJvZ3Jlc3MgfSBmcm9tICcuL3V0aWwvY2xvdWRmb3JtYXRpb24vc3RhY2stYWN0aXZpdHktbW9uaXRvcic7XG5pbXBvcnQgeyBhZGRNZXRhZGF0YUFzc2V0c1RvTWFuaWZlc3QgfSBmcm9tICcuLi9hc3NldHMnO1xuaW1wb3J0IHsgVGFnIH0gZnJvbSAnLi4vY2RrLXRvb2xraXQnO1xuaW1wb3J0IHsgZGVidWcsIGVycm9yLCBwcmludCB9IGZyb20gJy4uL2xvZ2dpbmcnO1xuaW1wb3J0IHsgdG9ZQU1MIH0gZnJvbSAnLi4vc2VyaWFsaXplJztcbmltcG9ydCB7IEFzc2V0TWFuaWZlc3RCdWlsZGVyIH0gZnJvbSAnLi4vdXRpbC9hc3NldC1tYW5pZmVzdC1idWlsZGVyJztcbmltcG9ydCB7IHB1Ymxpc2hBc3NldHMgfSBmcm9tICcuLi91dGlsL2Fzc2V0LXB1Ymxpc2hpbmcnO1xuaW1wb3J0IHsgY29udGVudEhhc2ggfSBmcm9tICcuLi91dGlsL2NvbnRlbnQtaGFzaCc7XG5cbnR5cGUgVGVtcGxhdGVCb2R5UGFyYW1ldGVyID0ge1xuICBUZW1wbGF0ZUJvZHk/OiBzdHJpbmdcbiAgVGVtcGxhdGVVUkw/OiBzdHJpbmdcbn07XG5cbmV4cG9ydCBpbnRlcmZhY2UgRGVwbG95U3RhY2tSZXN1bHQge1xuICByZWFkb25seSBub09wOiBib29sZWFuO1xuICByZWFkb25seSBvdXRwdXRzOiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfTtcbiAgcmVhZG9ubHkgc3RhY2tBcm46IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBEZXBsb3lTdGFja09wdGlvbnMge1xuICAvKipcbiAgICogVGhlIHN0YWNrIHRvIGJlIGRlcGxveWVkXG4gICAqL1xuICByZWFkb25seSBzdGFjazogY3hhcGkuQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0O1xuXG4gIC8qKlxuICAgKiBUaGUgZW52aXJvbm1lbnQgdG8gZGVwbG95IHRoaXMgc3RhY2sgaW5cbiAgICpcbiAgICogVGhlIGVudmlyb25tZW50IG9uIHRoZSBzdGFjayBhcnRpZmFjdCBtYXkgYmUgdW5yZXNvbHZlZCwgdGhpcyBvbmVcbiAgICogbXVzdCBiZSByZXNvbHZlZC5cbiAgICovXG4gIHJlYWRvbmx5IHJlc29sdmVkRW52aXJvbm1lbnQ6IGN4YXBpLkVudmlyb25tZW50O1xuXG4gIC8qKlxuICAgKiBUaGUgU0RLIHRvIHVzZSBmb3IgZGVwbG95aW5nIHRoZSBzdGFja1xuICAgKlxuICAgKiBTaG91bGQgaGF2ZSBiZWVuIGluaXRpYWxpemVkIHdpdGggdGhlIGNvcnJlY3Qgcm9sZSB3aXRoIHdoaWNoXG4gICAqIHN0YWNrIG9wZXJhdGlvbnMgc2hvdWxkIGJlIHBlcmZvcm1lZC5cbiAgICovXG4gIHJlYWRvbmx5IHNkazogSVNESztcblxuICAvKipcbiAgICogU0RLIHByb3ZpZGVyIChzZWVkZWQgd2l0aCBkZWZhdWx0IGNyZWRlbnRpYWxzKVxuICAgKlxuICAgKiBXaWxsIGV4Y2x1c2l2ZWx5IGJlIHVzZWQgdG8gYXNzdW1lIHB1Ymxpc2hpbmcgY3JlZGVudGlhbHMgKHdoaWNoIG11c3RcbiAgICogc3RhcnQgb3V0IGZyb20gY3VycmVudCBjcmVkZW50aWFscyByZWdhcmRsZXNzIG9mIHdoZXRoZXIgd2UndmUgYXNzdW1lZCBhblxuICAgKiBhY3Rpb24gcm9sZSB0byB0b3VjaCB0aGUgc3RhY2sgb3Igbm90KS5cbiAgICpcbiAgICogVXNlZCBmb3IgdGhlIGZvbGxvd2luZyBwdXJwb3NlczpcbiAgICpcbiAgICogLSBQdWJsaXNoIGxlZ2FjeSBhc3NldHMuXG4gICAqIC0gVXBsb2FkIGxhcmdlIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlcyB0byB0aGUgc3RhZ2luZyBidWNrZXQuXG4gICAqL1xuICByZWFkb25seSBzZGtQcm92aWRlcjogU2RrUHJvdmlkZXI7XG5cbiAgLyoqXG4gICAqIEluZm9ybWF0aW9uIGFib3V0IHRoZSBib290c3RyYXAgc3RhY2sgZm91bmQgaW4gdGhlIHRhcmdldCBlbnZpcm9ubWVudFxuICAgKi9cbiAgcmVhZG9ubHkgZW52UmVzb3VyY2VzOiBFbnZpcm9ubWVudFJlc291cmNlcztcblxuICAvKipcbiAgICogUm9sZSB0byBwYXNzIHRvIENsb3VkRm9ybWF0aW9uIHRvIGV4ZWN1dGUgdGhlIGNoYW5nZSBzZXRcbiAgICpcbiAgICogQGRlZmF1bHQgLSBSb2xlIHNwZWNpZmllZCBvbiBzdGFjaywgb3RoZXJ3aXNlIGN1cnJlbnRcbiAgICovXG4gIHJlYWRvbmx5IHJvbGVBcm4/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE5vdGlmaWNhdGlvbiBBUk5zIHRvIHBhc3MgdG8gQ2xvdWRGb3JtYXRpb2