@aws-cdk/aws-ecs
Version:
The CDK Construct Library for AWS::ECS
521 lines • 88.1 kB
JavaScript
"use strict";
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Protocol = exports.ContainerDependencyCondition = exports.UlimitName = exports.ContainerDefinition = exports.Secret = void 0;
const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const cdk = require("@aws-cdk/core");
const task_definition_1 = require("./base/task-definition");
// keep this import separate from other imports to reduce chance for merge conflicts with v2-main
// eslint-disable-next-line no-duplicate-imports, import/order
const core_1 = require("@aws-cdk/core");
/**
* A secret environment variable.
*/
class Secret {
/**
* Creates an environment variable value from a parameter stored in AWS
* Systems Manager Parameter Store.
*/
static fromSsmParameter(parameter) {
return {
arn: parameter.parameterArn,
grantRead: grantee => parameter.grantRead(grantee),
};
}
/**
* Creates a environment variable value from a secret stored in AWS Secrets
* Manager.
*
* @param secret the secret stored in AWS Secrets Manager
* @param field the name of the field with the value that you want to set as
* the environment variable value. Only values in JSON format are supported.
* If you do not specify a JSON field, then the full content of the secret is
* used.
*/
static fromSecretsManager(secret, field) {
return {
arn: field ? `${secret.secretArn}:${field}::` : secret.secretArn,
hasField: !!field,
grantRead: grantee => secret.grantRead(grantee),
};
}
/**
* Creates a environment variable value from a secret stored in AWS Secrets
* Manager.
*
* @param secret the secret stored in AWS Secrets Manager
* @param versionInfo the version information to reference the secret
* @param field the name of the field with the value that you want to set as
* the environment variable value. Only values in JSON format are supported.
* If you do not specify a JSON field, then the full content of the secret is
* used.
*/
static fromSecretsManagerVersion(secret, versionInfo, field) {
var _c, _d;
jsiiDeprecationWarnings._aws_cdk_aws_ecs_SecretVersionInfo(versionInfo);
return {
arn: `${secret.secretArn}:${field !== null && field !== void 0 ? field : ''}:${(_c = versionInfo.versionStage) !== null && _c !== void 0 ? _c : ''}:${(_d = versionInfo.versionId) !== null && _d !== void 0 ? _d : ''}`,
hasField: !!field,
grantRead: grantee => secret.grantRead(grantee),
};
}
}
exports.Secret = Secret;
_a = JSII_RTTI_SYMBOL_1;
Secret[_a] = { fqn: "@aws-cdk/aws-ecs.Secret", version: "1.149.0" };
/**
* A container definition is used in a task definition to describe the containers that are launched as part of a task.
*/
class ContainerDefinition extends core_1.Construct {
/**
* Constructs a new instance of the ContainerDefinition class.
*/
constructor(scope, id, props) {
var _c, _d;
super(scope, id);
this.props = props;
/**
* The mount points for data volumes in your container.
*/
this.mountPoints = new Array();
/**
* The list of port mappings for the container. Port mappings allow containers to access ports
* on the host container instance to send or receive traffic.
*/
this.portMappings = new Array();
/**
* The data volumes to mount from another container in the same task definition.
*/
this.volumesFrom = new Array();
/**
* An array of ulimits to set in the container.
*/
this.ulimits = new Array();
/**
* An array dependencies defined for container startup and shutdown.
*/
this.containerDependencies = new Array();
/**
* The inference accelerators referenced by this container.
*/
this.inferenceAcceleratorResources = [];
/**
* The configured container links
*/
this.links = new Array();
jsiiDeprecationWarnings._aws_cdk_aws_ecs_ContainerDefinitionProps(props);
if (props.memoryLimitMiB !== undefined && props.memoryReservationMiB !== undefined) {
if (props.memoryLimitMiB < props.memoryReservationMiB) {
throw new Error('MemoryLimitMiB should not be less than MemoryReservationMiB.');
}
}
this.essential = (_c = props.essential) !== null && _c !== void 0 ? _c : true;
this.taskDefinition = props.taskDefinition;
this.memoryLimitSpecified = props.memoryLimitMiB !== undefined || props.memoryReservationMiB !== undefined;
this.linuxParameters = props.linuxParameters;
this.containerName = (_d = props.containerName) !== null && _d !== void 0 ? _d : this.node.id;
this.imageConfig = props.image.bind(this, this);
this.imageName = this.imageConfig.imageName;
if (props.logging) {
this.logDriverConfig = props.logging.bind(this, this);
}
if (props.secrets) {
this.secrets = [];
for (const [name, secret] of Object.entries(props.secrets)) {
if (secret.hasField) {
this.referencesSecretJsonField = true;
}
secret.grantRead(this.taskDefinition.obtainExecutionRole());
this.secrets.push({
name,
valueFrom: secret.arn,
});
}
}
if (props.environment) {
this.environment = { ...props.environment };
}
else {
this.environment = {};
}
if (props.environmentFiles) {
this.environmentFiles = [];
for (const environmentFile of props.environmentFiles) {
this.environmentFiles.push(environmentFile.bind(this));
}
}
props.taskDefinition._linkContainer(this);
if (props.portMappings) {
this.addPortMappings(...props.portMappings);
}
if (props.inferenceAcceleratorResources) {
this.addInferenceAcceleratorResource(...props.inferenceAcceleratorResources);
}
}
/**
* This method adds a link which allows containers to communicate with each other without the need for port mappings.
*
* This parameter is only supported if the task definition is using the bridge network mode.
* Warning: The --link flag is a legacy feature of Docker. It may eventually be removed.
*/
addLink(container, alias) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_ContainerDefinition(container);
if (this.taskDefinition.networkMode !== task_definition_1.NetworkMode.BRIDGE) {
throw new Error('You must use network mode Bridge to add container links.');
}
if (alias !== undefined) {
this.links.push(`${container.containerName}:${alias}`);
}
else {
this.links.push(`${container.containerName}`);
}
}
/**
* This method adds one or more mount points for data volumes to the container.
*/
addMountPoints(...mountPoints) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_MountPoint(mountPoints);
this.mountPoints.push(...mountPoints);
}
/**
* This method mounts temporary disk space to the container.
*
* This adds the correct container mountPoint and task definition volume.
*/
addScratch(scratch) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_ScratchSpace(scratch);
const mountPoint = {
containerPath: scratch.containerPath,
readOnly: scratch.readOnly,
sourceVolume: scratch.name,
};
const volume = {
host: {
sourcePath: scratch.sourcePath,
},
name: scratch.name,
};
this.taskDefinition.addVolume(volume);
this.addMountPoints(mountPoint);
}
/**
* This method adds one or more port mappings to the container.
*/
addPortMappings(...portMappings) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_PortMapping(portMappings);
this.portMappings.push(...portMappings.map(pm => {
if (this.taskDefinition.networkMode === task_definition_1.NetworkMode.AWS_VPC || this.taskDefinition.networkMode === task_definition_1.NetworkMode.HOST) {
if (pm.containerPort !== pm.hostPort && pm.hostPort !== undefined) {
throw new Error(`Host port (${pm.hostPort}) must be left out or equal to container port ${pm.containerPort} for network mode ${this.taskDefinition.networkMode}`);
}
}
if (this.taskDefinition.networkMode === task_definition_1.NetworkMode.BRIDGE) {
if (pm.hostPort === undefined) {
pm = {
...pm,
hostPort: 0,
};
}
}
return pm;
}));
}
/**
* This method adds an environment variable to the container.
*/
addEnvironment(name, value) {
this.environment[name] = value;
}
/**
* This method adds one or more resources to the container.
*/
addInferenceAcceleratorResource(...inferenceAcceleratorResources) {
this.inferenceAcceleratorResources.push(...inferenceAcceleratorResources.map(resource => {
for (const inferenceAccelerator of this.taskDefinition.inferenceAccelerators) {
if (resource === inferenceAccelerator.deviceName) {
return resource;
}
}
throw new Error(`Resource value ${resource} in container definition doesn't match any inference accelerator device name in the task definition.`);
}));
}
/**
* This method adds one or more ulimits to the container.
*/
addUlimits(...ulimits) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_Ulimit(ulimits);
this.ulimits.push(...ulimits);
}
/**
* This method adds one or more container dependencies to the container.
*/
addContainerDependencies(...containerDependencies) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_ContainerDependency(containerDependencies);
this.containerDependencies.push(...containerDependencies);
}
/**
* This method adds one or more volumes to the container.
*/
addVolumesFrom(...volumesFrom) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_VolumeFrom(volumesFrom);
this.volumesFrom.push(...volumesFrom);
}
/**
* This method adds the specified statement to the IAM task execution policy in the task definition.
*/
addToExecutionPolicy(statement) {
this.taskDefinition.addToExecutionRolePolicy(statement);
}
/**
* Returns the host port for the requested container port if it exists
*/
findPortMapping(containerPort, protocol) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_Protocol(protocol);
for (const portMapping of this.portMappings) {
const p = portMapping.protocol || Protocol.TCP;
const c = portMapping.containerPort;
if (c === containerPort && p === protocol) {
return portMapping;
}
}
return undefined;
}
/**
* The inbound rules associated with the security group the task or service will use.
*
* This property is only used for tasks that use the awsvpc network mode.
*/
get ingressPort() {
if (this.portMappings.length === 0) {
throw new Error(`Container ${this.containerName} hasn't defined any ports. Call addPortMappings().`);
}
const defaultPortMapping = this.portMappings[0];
if (defaultPortMapping.hostPort !== undefined && defaultPortMapping.hostPort !== 0) {
return defaultPortMapping.hostPort;
}
if (this.taskDefinition.networkMode === task_definition_1.NetworkMode.BRIDGE) {
return 0;
}
return defaultPortMapping.containerPort;
}
/**
* The port the container will listen on.
*/
get containerPort() {
if (this.portMappings.length === 0) {
throw new Error(`Container ${this.containerName} hasn't defined any ports. Call addPortMappings().`);
}
const defaultPortMapping = this.portMappings[0];
return defaultPortMapping.containerPort;
}
/**
* Render this container definition to a CloudFormation object
*
* @param _taskDefinition [disable-awslint:ref-via-interface] (unused but kept to avoid breaking change)
*/
renderContainerDefinition(_taskDefinition) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_TaskDefinition(_taskDefinition);
return {
command: this.props.command,
cpu: this.props.cpu,
disableNetworking: this.props.disableNetworking,
dependsOn: cdk.Lazy.any({ produce: () => this.containerDependencies.map(renderContainerDependency) }, { omitEmptyArray: true }),
dnsSearchDomains: this.props.dnsSearchDomains,
dnsServers: this.props.dnsServers,
dockerLabels: this.props.dockerLabels,
dockerSecurityOptions: this.props.dockerSecurityOptions,
entryPoint: this.props.entryPoint,
essential: this.essential,
hostname: this.props.hostname,
image: this.imageConfig.imageName,
memory: this.props.memoryLimitMiB,
memoryReservation: this.props.memoryReservationMiB,
mountPoints: cdk.Lazy.any({ produce: () => this.mountPoints.map(renderMountPoint) }, { omitEmptyArray: true }),
name: this.containerName,
portMappings: cdk.Lazy.any({ produce: () => this.portMappings.map(renderPortMapping) }, { omitEmptyArray: true }),
privileged: this.props.privileged,
readonlyRootFilesystem: this.props.readonlyRootFilesystem,
repositoryCredentials: this.imageConfig.repositoryCredentials,
startTimeout: this.props.startTimeout && this.props.startTimeout.toSeconds(),
stopTimeout: this.props.stopTimeout && this.props.stopTimeout.toSeconds(),
ulimits: cdk.Lazy.any({ produce: () => this.ulimits.map(renderUlimit) }, { omitEmptyArray: true }),
user: this.props.user,
volumesFrom: cdk.Lazy.any({ produce: () => this.volumesFrom.map(renderVolumeFrom) }, { omitEmptyArray: true }),
workingDirectory: this.props.workingDirectory,
logConfiguration: this.logDriverConfig,
environment: this.environment && Object.keys(this.environment).length ? renderKV(this.environment, 'name', 'value') : undefined,
environmentFiles: this.environmentFiles && renderEnvironmentFiles(cdk.Stack.of(this).partition, this.environmentFiles),
secrets: this.secrets,
extraHosts: this.props.extraHosts && renderKV(this.props.extraHosts, 'hostname', 'ipAddress'),
healthCheck: this.props.healthCheck && renderHealthCheck(this.props.healthCheck),
links: cdk.Lazy.list({ produce: () => this.links }, { omitEmpty: true }),
linuxParameters: this.linuxParameters && this.linuxParameters.renderLinuxParameters(),
resourceRequirements: (!this.props.gpuCount && this.inferenceAcceleratorResources.length == 0) ? undefined :
renderResourceRequirements(this.props.gpuCount, this.inferenceAcceleratorResources),
systemControls: this.props.systemControls && renderSystemControls(this.props.systemControls),
};
}
}
exports.ContainerDefinition = ContainerDefinition;
_b = JSII_RTTI_SYMBOL_1;
ContainerDefinition[_b] = { fqn: "@aws-cdk/aws-ecs.ContainerDefinition", version: "1.149.0" };
function renderKV(env, keyName, valueName) {
const ret = [];
for (const [key, value] of Object.entries(env)) {
ret.push({ [keyName]: key, [valueName]: value });
}
return ret;
}
function renderEnvironmentFiles(partition, environmentFiles) {
const ret = [];
for (const environmentFile of environmentFiles) {
const s3Location = environmentFile.s3Location;
if (!s3Location) {
throw Error('Environment file must specify an S3 location');
}
ret.push({
type: environmentFile.fileType,
value: `arn:${partition}:s3:::${s3Location.bucketName}/${s3Location.objectKey}`,
});
}
return ret;
}
function renderHealthCheck(hc) {
var _c, _d, _e, _f, _g, _h;
return {
command: getHealthCheckCommand(hc),
interval: (_d = (_c = hc.interval) === null || _c === void 0 ? void 0 : _c.toSeconds()) !== null && _d !== void 0 ? _d : 30,
retries: (_e = hc.retries) !== null && _e !== void 0 ? _e : 3,
startPeriod: (_f = hc.startPeriod) === null || _f === void 0 ? void 0 : _f.toSeconds(),
timeout: (_h = (_g = hc.timeout) === null || _g === void 0 ? void 0 : _g.toSeconds()) !== null && _h !== void 0 ? _h : 5,
};
}
function getHealthCheckCommand(hc) {
const cmd = hc.command;
const hcCommand = new Array();
if (cmd.length === 0) {
throw new Error('At least one argument must be supplied for health check command.');
}
if (cmd.length === 1) {
hcCommand.push('CMD-SHELL', cmd[0]);
return hcCommand;
}
if (cmd[0] !== 'CMD' && cmd[0] !== 'CMD-SHELL') {
hcCommand.push('CMD');
}
return hcCommand.concat(cmd);
}
function renderResourceRequirements(gpuCount = 0, inferenceAcceleratorResources = []) {
const ret = [];
for (const resource of inferenceAcceleratorResources) {
ret.push({
type: 'InferenceAccelerator',
value: resource,
});
}
if (gpuCount > 0) {
ret.push({
type: 'GPU',
value: gpuCount.toString(),
});
}
return ret;
}
/**
* Type of resource to set a limit on
*/
var UlimitName;
(function (UlimitName) {
UlimitName["CORE"] = "core";
UlimitName["CPU"] = "cpu";
UlimitName["DATA"] = "data";
UlimitName["FSIZE"] = "fsize";
UlimitName["LOCKS"] = "locks";
UlimitName["MEMLOCK"] = "memlock";
UlimitName["MSGQUEUE"] = "msgqueue";
UlimitName["NICE"] = "nice";
UlimitName["NOFILE"] = "nofile";
UlimitName["NPROC"] = "nproc";
UlimitName["RSS"] = "rss";
UlimitName["RTPRIO"] = "rtprio";
UlimitName["RTTIME"] = "rttime";
UlimitName["SIGPENDING"] = "sigpending";
UlimitName["STACK"] = "stack";
})(UlimitName = exports.UlimitName || (exports.UlimitName = {}));
function renderUlimit(ulimit) {
return {
name: ulimit.name,
softLimit: ulimit.softLimit,
hardLimit: ulimit.hardLimit,
};
}
var ContainerDependencyCondition;
(function (ContainerDependencyCondition) {
/**
* This condition emulates the behavior of links and volumes today.
* It validates that a dependent container is started before permitting other containers to start.
*/
ContainerDependencyCondition["START"] = "START";
/**
* This condition validates that a dependent container runs to completion (exits) before permitting other containers to start.
* This can be useful for nonessential containers that run a script and then exit.
*/
ContainerDependencyCondition["COMPLETE"] = "COMPLETE";
/**
* This condition is the same as COMPLETE, but it also requires that the container exits with a zero status.
*/
ContainerDependencyCondition["SUCCESS"] = "SUCCESS";
/**
* This condition validates that the dependent container passes its Docker health check before permitting other containers to start.
* This requires that the dependent container has health checks configured. This condition is confirmed only at task startup.
*/
ContainerDependencyCondition["HEALTHY"] = "HEALTHY";
})(ContainerDependencyCondition = exports.ContainerDependencyCondition || (exports.ContainerDependencyCondition = {}));
function renderContainerDependency(containerDependency) {
return {
containerName: containerDependency.container.containerName,
condition: containerDependency.condition || ContainerDependencyCondition.HEALTHY,
};
}
/**
* Network protocol
*/
var Protocol;
(function (Protocol) {
/**
* TCP
*/
Protocol["TCP"] = "tcp";
/**
* UDP
*/
Protocol["UDP"] = "udp";
})(Protocol = exports.Protocol || (exports.Protocol = {}));
function renderPortMapping(pm) {
return {
containerPort: pm.containerPort,
hostPort: pm.hostPort,
protocol: pm.protocol || Protocol.TCP,
};
}
function renderMountPoint(mp) {
return {
containerPath: mp.containerPath,
readOnly: mp.readOnly,
sourceVolume: mp.sourceVolume,
};
}
function renderVolumeFrom(vf) {
return {
sourceContainer: vf.sourceContainer,
readOnly: vf.readOnly,
};
}
function renderSystemControls(systemControls) {
return systemControls.map(sc => ({
namespace: sc.namespace,
value: sc.value,
}));
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29udGFpbmVyLWRlZmluaXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjb250YWluZXItZGVmaW5pdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFHQSxxQ0FBcUM7QUFFckMsNERBQXFFO0FBT3JFLGlHQUFpRztBQUNqRyw4REFBOEQ7QUFDOUQsd0NBQTJEO0FBb0IzRDs7R0FFRztBQUNILE1BQXNCLE1BQU07SUFDMUI7OztPQUdHO0lBQ0ksTUFBTSxDQUFDLGdCQUFnQixDQUFDLFNBQXlCO1FBQ3RELE9BQU87WUFDTCxHQUFHLEVBQUUsU0FBUyxDQUFDLFlBQVk7WUFDM0IsU0FBUyxFQUFFLE9BQU8sQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUM7U0FDbkQsQ0FBQztLQUNIO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ0ksTUFBTSxDQUFDLGtCQUFrQixDQUFDLE1BQThCLEVBQUUsS0FBYztRQUM3RSxPQUFPO1lBQ0wsR0FBRyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsU0FBUyxJQUFJLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsU0FBUztZQUNoRSxRQUFRLEVBQUUsQ0FBQyxDQUFDLEtBQUs7WUFDakIsU0FBUyxFQUFFLE9BQU8sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUM7U0FDaEQsQ0FBQztLQUNIO0lBRUQ7Ozs7Ozs7Ozs7T0FVRztJQUNJLE1BQU0sQ0FBQyx5QkFBeUIsQ0FBQyxNQUE4QixFQUFFLFdBQThCLEVBQUUsS0FBYzs7O1FBQ3BILE9BQU87WUFDTCxHQUFHLEVBQUUsR0FBRyxNQUFNLENBQUMsU0FBUyxJQUFJLEtBQUssYUFBTCxLQUFLLGNBQUwsS0FBSyxHQUFJLEVBQUUsSUFBSSxNQUFBLFdBQVcsQ0FBQyxZQUFZLG1DQUFJLEVBQUUsSUFBSSxNQUFBLFdBQVcsQ0FBQyxTQUFTLG1D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QUFDLGFBQWE7UUFDL0IsUUFBUSxFQUFFLEVBQUUsQ0FBQyxRQUFRO1FBQ3JCLFlBQVksRUFBRSxFQUFFLENBQUMsWUFBWTtLQUM5QixDQUFDO0FBQ0osQ0FBQztBQW9CRCxTQUFTLGdCQUFnQixDQUFDLEVBQWM7SUFDdEMsT0FBTztRQUNMLGVBQWUsRUFBRSxFQUFFLENBQUMsZUFBZTtRQUNuQyxRQUFRLEVBQUUsRUFBRSxDQUFDLFFBQVE7S0FDdEIsQ0FBQztBQUNKLENBQUM7QUFpQkQsU0FBUyxvQkFBb0IsQ0FBQyxjQUErQjtJQUMzRCxPQUFPLGNBQWMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQy9CLFNBQVMsRUFBRSxFQUFFLENBQUMsU0FBUztRQUN2QixLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUs7S0FDaEIsQ0FBQyxDQUFDLENBQUM7QUFDTixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgaWFtIGZyb20gJ0Bhd3MtY2RrL2F3cy1pYW0nO1xuaW1wb3J0ICogYXMgc2VjcmV0c21hbmFnZXIgZnJvbSAnQGF3cy1jZGsvYXdzLXNlY3JldHNtYW5hZ2VyJztcbmltcG9ydCAqIGFzIHNzbSBmcm9tICdAYXdzLWNkay9hd3Mtc3NtJztcbmltcG9ydCAqIGFzIGNkayBmcm9tICdAYXdzLWNkay9jb3JlJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgTmV0d29ya01vZGUsIFRhc2tEZWZpbml0aW9uIH0gZnJvbSAnLi9iYXNlL3Rhc2stZGVmaW5pdGlvbic7XG5pbXBvcnQgeyBDb250YWluZXJJbWFnZSwgQ29udGFpbmVySW1hZ2VDb25maWcgfSBmcm9tICcuL2NvbnRhaW5lci1pbWFnZSc7XG5pbXBvcnQgeyBDZm5UYXNrRGVmaW5pdGlvbiB9IGZyb20gJy4vZWNzLmdlbmVyYXRlZCc7XG5pbXBvcnQgeyBFbnZpcm9ubWVudEZpbGUsIEVudmlyb25tZW50RmlsZUNvbmZpZyB9IGZyb20gJy4vZW52aXJvbm1lbnQtZmlsZSc7XG5pbXBvcnQgeyBMaW51eFBhcmFtZXRlcnMgfSBmcm9tICcuL2xpbnV4LXBhcmFtZXRlcnMnO1xuaW1wb3J0IHsgTG9nRHJpdmVyLCBMb2dEcml2ZXJDb25maWcgfSBmcm9tICcuL2xvZy1kcml2ZXJzL2xvZy1kcml2ZXInO1xuXG4vLyBrZWVwIHRoaXMgaW1wb3J0IHNlcGFyYXRlIGZyb20gb3RoZXIgaW1wb3J0cyB0byByZWR1Y2UgY2hhbmNlIGZvciBtZXJnZSBjb25mbGljdHMgd2l0aCB2Mi1tYWluXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tZHVwbGljYXRlLWltcG9ydHMsIGltcG9ydC9vcmRlclxuaW1wb3J0IHsgQ29uc3RydWN0IGFzIENvcmVDb25zdHJ1Y3QgfSBmcm9tICdAYXdzLWNkay9jb3JlJztcblxuLyoqXG4gKiBTcGVjaWZ5IHRoZSBzZWNyZXQncyB2ZXJzaW9uIGlkIG9yIHZlcnNpb24gc3RhZ2VcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZWNyZXRWZXJzaW9uSW5mbyB7XG4gIC8qKlxuICAgKiB2ZXJzaW9uIGlkIG9mIHRoZSBzZWNyZXRcbiAgICpcbiAgICogQGRlZmF1bHQgLSB1c2UgZGVmYXVsdCB2ZXJzaW9uIGlkXG4gICAqL1xuICByZWFkb25seSB2ZXJzaW9uSWQ/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiB2ZXJzaW9uIHN0YWdlIG9mIHRoZSBzZWNyZXRcbiAgICpcbiAgICogQGRlZmF1bHQgLSB1c2UgZGVmYXVsdCB2ZXJzaW9uIHN0YWdlXG4gICAqL1xuICByZWFkb25seSB2ZXJzaW9uU3RhZ2U/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogQSBzZWNyZXQgZW52aXJvbm1lbnQgdmFyaWFibGUuXG4gKi9cbmV4cG9ydCBhYnN0cmFjdCBjbGFzcyBTZWNyZXQge1xuICAvKipcbiAgICogQ3JlYXRlcyBhbiBlbnZpcm9ubWVudCB2YXJpYWJsZSB2YWx1ZSBmcm9tIGEgcGFyYW1ldGVyIHN0b3JlZCBpbiBBV1NcbiAgICogU3lzdGVtcyBNYW5hZ2VyIFBhcmFtZXRlciBTdG9yZS5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZnJvbVNzbVBhcmFtZXRlcihwYXJhbWV0ZXI6IHNzbS5JUGFyYW1ldGVyKTogU2VjcmV0IHtcbiAgICByZXR1cm4ge1xuICAgICAgYXJuOiBwYXJhbWV0ZXIucGFyYW1ldGVyQXJuLFxuICAgICAgZ3JhbnRSZWFkOiBncmFudGVlID0+IHBhcmFtZXRlci5ncmFudFJlYWQoZ3JhbnRlZSksXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgZW52aXJvbm1lbnQgdmFyaWFibGUgdmFsdWUgZnJvbSBhIHNlY3JldCBzdG9yZWQgaW4gQVdTIFNlY3JldHNcbiAgICogTWFuYWdlci5cbiAgICpcbiAgICogQHBhcmFtIHNlY3JldCB0aGUgc2VjcmV0IHN0b3JlZCBpbiBBV1MgU2VjcmV0cyBNYW5hZ2VyXG4gICAqIEBwYXJhbSBmaWVsZCB0aGUgbmFtZSBvZiB0aGUgZmllbGQgd2l0aCB0aGUgdmFsdWUgdGhhdCB5b3Ugd2FudCB0byBzZXQgYXNcbiAgICogdGhlIGVudmlyb25tZW50IHZhcmlhYmxlIHZhbHVlLiBPbmx5IHZhbHVlcyBpbiBKU09OIGZvcm1hdCBhcmUgc3VwcG9ydGVkLlxuICAgKiBJZiB5b3UgZG8gbm90IHNwZWNpZnkgYSBKU09OIGZpZWxkLCB0aGVuIHRoZSBmdWxsIGNvbnRlbnQgb2YgdGhlIHNlY3JldCBpc1xuICAgKiB1c2VkLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBmcm9tU2VjcmV0c01hbmFnZXIoc2VjcmV0OiBzZWNyZXRzbWFuYWdlci5JU2VjcmV0LCBmaWVsZD86IHN0cmluZyk6IFNlY3JldCB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGFybjogZmllbGQgPyBgJHtzZWNyZXQuc2VjcmV0QXJufToke2ZpZWxkfTo6YCA6IHNlY3JldC5zZWNyZXRBcm4sXG4gICAgICBoYXNGaWVsZDogISFmaWVsZCxcbiAgICAgIGdyYW50UmVhZDogZ3JhbnRlZSA9PiBzZWNyZXQuZ3JhbnRSZWFkKGdyYW50ZWUpLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIGVudmlyb25tZW50IHZhcmlhYmxlIHZhbHVlIGZyb20gYSBzZWNyZXQgc3RvcmVkIGluIEFXUyBTZWNyZXRzXG4gICAqIE1hbmFnZXIuXG4gICAqXG4gICAqIEBwYXJhbSBzZWNyZXQgdGhlIHNlY3JldCBzdG9yZWQgaW4gQVdTIFNlY3JldHMgTWFuYWdlclxuICAgKiBAcGFyYW0gdmVyc2lvbkluZm8gdGhlIHZlcnNpb24gaW5mb3JtYXRpb24gdG8gcmVmZXJlbmNlIHRoZSBzZWNyZXRcbiAgICogQHBhcmFtIGZpZWxkIHRoZSBuYW1lIG9mIHRoZSBmaWVsZCB3aXRoIHRoZSB2YWx1ZSB0aGF0IHlvdSB3YW50IHRvIHNldCBhc1xuICAgKiB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGUgdmFsdWUuIE9ubHkgdmFsdWVzIGluIEpTT04gZm9ybWF0IGFyZSBzdXBwb3J0ZWQuXG4gICAqIElmIHlvdSBkbyBub3Qgc3BlY2lmeSBhIEpTT04gZmllbGQsIHRoZW4gdGhlIGZ1bGwgY29udGVudCBvZiB0aGUgc2VjcmV0IGlzXG4gICAqIHVzZWQuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGZyb21TZWNyZXRzTWFuYWdlclZlcnNpb24oc2VjcmV0OiBzZWNyZXRzbWFuYWdlci5JU2VjcmV0LCB2ZXJzaW9uSW5mbzogU2VjcmV0VmVyc2lvbkluZm8sIGZpZWxkPzogc3RyaW5nKTogU2VjcmV0IHtcbiAgICByZXR1cm4ge1xuICAgICAgYXJuOiBgJHtzZWNyZXQuc2VjcmV0QXJufToke2ZpZWxkID8/ICcnfToke3ZlcnNpb25JbmZvLnZlcnNpb25TdGFnZSA/PyAnJ306JHt2ZXJzaW9uSW5mby52ZXJzaW9uSWQgPz8gJyd9YCxcbiAgICAgIGhhc0ZpZWxkOiAhIWZpZWxkLFxuICAgICAgZ3JhbnRSZWFkOiBncmFudGVlID0+IHNlY3JldC5ncmFudFJlYWQoZ3JhbnRlZSksXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgQVJOIG9mIHRoZSBzZWNyZXRcbiAgICovXG4gIHB1YmxpYyBhYnN0cmFjdCByZWFkb25seSBhcm46IHN0cmluZztcblxuICAvKipcbiAgICogV2hldGhlciB0aGlzIHNlY3JldCB1c2VzIGEgc3BlY2lmaWMgSlNPTiBmaWVsZFxuICAgKi9cbiAgcHVibGljIGFic3RyYWN0IHJlYWRvbmx5IGhhc0ZpZWxkPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogR3JhbnRzIHJlYWRpbmcgdGhlIHNlY3JldCB0byBhIHByaW5jaXBhbFxuICAgKi9cbiAgcHVibGljIGFic3RyYWN0IGdyYW50UmVhZChncmFudGVlOiBpYW0uSUdyYW50YWJsZSk6IGlhbS5HcmFudDtcbn1cblxuLypcbiAqIFRoZSBvcHRpb25zIGZvciBjcmVhdGluZyBhIGNvbnRhaW5lciBkZWZpbml0aW9uLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIENvbnRhaW5lckRlZmluaXRpb25PcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBpbWFnZSB1c2VkIHRvIHN0YXJ0IGEgY29udGFpbmVyLlxuICAgKlxuICAgKiBUaGlzIHN0cmluZyBpcyBwYXNzZWQgZGlyZWN0bHkgdG8gdGhlIERvY2tlciBkYWVtb24uXG4gICAqIEltYWdlcyBpbiB0aGUgRG9ja2VyIEh1YiByZWdpc3RyeSBhcmUgYXZhaWxhYmxlIGJ5IGRlZmF1bHQuXG4gICAqIE90aGVyIHJlcG9zaXRvcmllcyBhcmUgc3BlY2lmaWVkIHdpdGggZWl0aGVyIHJlcG9zaXRvcnktdXJsL2ltYWdlOnRhZyBvciByZXBvc2l0b3J5LXVybC9pbWFnZUBkaWdlc3QuXG4gICAqIFRPRE86IFVwZGF0ZSB0aGVzZSB0byBzcGVjaWZ5IHVzaW5nIGNsYXNzZXMgb2YgSUNvbnRhaW5lckltYWdlXG4gICAqL1xuICByZWFkb25seSBpbWFnZTogQ29udGFpbmVySW1hZ2U7XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBjb250YWluZXIuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gaWQgb2Ygbm9kZSBhc3NvY2lhdGVkIHdpdGggQ29udGFpbmVyRGVmaW5pdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IGNvbnRhaW5lck5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBjb21tYW5kIHRoYXQgaXMgcGFzc2VkIHRvIHRoZSBjb250YWluZXIuXG4gICAqXG4gICAqIElmIHlvdSBwcm92aWRlIGEgc2hlbGwgY29tbWFuZCBhcyBhIHNpbmdsZSBzdHJpbmcsIHlvdSBoYXZlIHRvIHF1b3RlIGNvbW1hbmQtbGluZSBhcmd1bWVudHMuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gQ01EIHZhbHVlIGJ1aWx0IGludG8gY29udGFpbmVyIGltYWdlLlxuICAgKi9cbiAgcmVhZG9ubHkgY29tbWFuZD86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBUaGUgbWluaW11bSBudW1iZXIgb2YgQ1BVIHVuaXRzIHRvIHJlc2VydmUgZm9yIHRoZSBjb250YWluZXIuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gbWluaW11bSBDUFUgdW5pdHMgcmVzZXJ2ZWQuXG4gICAqL1xuICByZWFkb25seSBjcHU/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFNwZWNpZmllcyB3aGV0aGVyIG5ldHdvcmtpbmcgaXMgZGlzYWJsZWQgd2l0aGluIHRoZSBjb250YWluZXIuXG4gICAqXG4gICAqIFdoZW4gdGhpcyBwYXJhbWV0ZXIgaXMgdHJ1ZSwgbmV0d29ya2luZyBpcyBkaXNhYmxlZCB3aXRoaW4gdGhlIGNvbnRhaW5lci5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGRpc2FibGVOZXR3b3JraW5nPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogQSBsaXN0IG9mIEROUyBzZWFyY2ggZG9tYWlucyB0aGF0IGFyZSBwcmVzZW50ZWQgdG8gdGhlIGNvbnRhaW5lci5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBzZWFyY2ggZG9tYWlucy5cbiAgICovXG4gIHJlYWRvbmx5IGRuc1NlYXJjaERvbWFpbnM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQSBsaXN0IG9mIEROUyBzZXJ2ZXJzIHRoYXQgYXJlIHByZXNlbnRlZCB0byB0aGUgY29udGFpbmVyLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIERlZmF1bHQgRE5TIHNlcnZlcnMuXG4gICAqL1xuICByZWFkb25seSBkbnNTZXJ2ZXJzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIEEga2V5L3ZhbHVlIG1hcCBvZiBsYWJlbHMgdG8gYWRkIHRvIHRoZSBjb250YWluZXIuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gbGFiZWxzLlxuICAgKi9cbiAgcmVhZG9ubHkgZG9ja2VyTGFiZWxzPzogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfTtcblxuICAvKipcbiAgICogQSBsaXN0IG9mIHN0cmluZ3MgdG8gcHJvdmlkZSBjdXN0b20gbGFiZWxzIGZvciBTRUxpbnV4IGFuZCBBcHBBcm1vciBtdWx0aS1sZXZlbCBzZWN1cml0eSBzeXN0ZW1zLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIHNlY3VyaXR5IGxhYmVscy5cbiAgICovXG4gIHJlYWRvbmx5IGRvY2tlclNlY3VyaXR5T3B0aW9ucz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBUaGUgRU5UUllQT0lOVCB2YWx1ZSB0byBwYXNzIHRvIHRoZSBjb250YWluZXIuXG4gICAqXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmRvY2tlci5jb20vZW5naW5lL3JlZmVyZW5jZS9idWlsZGVyLyNlbnRyeXBvaW50XG4gICAqXG4gICAqIEBkZWZhdWx0IC0gRW50cnkgcG9pbnQgY29uZmlndXJlZCBpbiBjb250YWluZXIuXG4gICAqL1xuICByZWFkb25seSBlbnRyeVBvaW50Pzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdG8gcGFzcyB0byB0aGUgY29udGFpbmVyLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGVudmlyb25tZW50IHZhcmlhYmxlcy5cbiAgICovXG4gIHJlYWRvbmx5IGVudmlyb25tZW50PzogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfTtcblxuICAvKipcbiAgICogVGhlIGVudmlyb25tZW50IGZpbGVzIHRvIHBhc3MgdG8gdGhlIGNvbnRhaW5lci5cbiAgICpcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uRUNTL2xhdGVzdC9kZXZlbG9wZXJndWlkZS90YXNrZGVmLWVudmZpbGVzLmh0bWxcbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBlbnZpcm9ubWVudCBmaWxlcy5cbiAgICovXG4gIHJlYWRvbmx5IGVudmlyb25tZW50RmlsZXM/OiBFbnZpcm9ubWVudEZpbGVbXTtcblxuICAvKipcbiAgICogVGhlIHNlY3JldCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdG8gcGFzcyB0byB0aGUgY29udGFpbmVyLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIHNlY3JldCBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXG4gICAqL1xuICByZWFkb25seSBzZWNyZXRzPzogeyBba2V5OiBzdHJpbmddOiBTZWNyZXQgfTtcblxuICAvKipcbiAgICogVGltZSBkdXJhdGlvbiAoaW4gc2Vjb25kcykgdG8gd2FpdCBiZWZvcmUgZ2l2aW5nIHVwIG9uIHJlc29sdmluZyBkZXBlbmRlbmNpZXMgZm9yIGEgY29udGFpbmVyLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vbmVcbiAgICovXG4gIHJlYWRvbmx5IHN0YXJ0VGltZW91dD86IGNkay5EdXJhdGlvbjtcblxuICAvKipcbiAgICogVGltZSBkdXJhdGlvbiAoaW4gc2Vjb25kcykgdG8gd2FpdCBiZWZvcmUgdGhlIGNvbnRhaW5lciBpcyBmb3JjZWZ1bGx5IGtpbGxlZCBpZiBpdCBkb2Vzbid0IGV4aXQgbm9ybWFsbHkgb24gaXRzIG93bi5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBub25lXG4gICAqL1xuICByZWFkb25seSBzdG9wVGltZW91dD86IGNkay5EdXJhdGlvbjtcblxuICAvKipcbiAgICogU3BlY2lmaWVzIHdoZXRoZXIgdGhlIGNvbnRhaW5lciBpcyBtYXJrZWQgZXNzZW50aWFsLlxuICAgKlxuICAgKiBJZiB0aGUgZXNzZW50aWFsIHBhcmFtZXRlciBvZiBhIGNvbnRhaW5lciBpcyBtYXJrZWQgYXMgdHJ1ZSwgYW5kIHRoYXQgY29udGFpbmVyIGZhaWxzXG4gICAqIG9yIHN0b3BzIGZvciBhbnkgcmVhc29uLCBhbGwgb3RoZXIgY29udGFpbmVycyB0aGF0IGFyZSBwYXJ0IG9mIHRoZSB0YXNrIGFyZSBzdG9wcGVkLlxuICAgKiBJZiB0aGUgZXNzZW50aWFsIHBhcmFtZXRlciBvZiBhIGNvbnRhaW5lciBpcyBtYXJrZWQgYXMgZmFsc2UsIHRoZW4gaXRzIGZhaWx1cmUgZG9lcyBub3RcbiAgICogYWZmZWN0IHRoZSByZXN0IG9mIHRoZSBjb250YWluZXJzIGluIGEgdGFzay4gQWxsIHRhc2tzIG11c3QgaGF2ZSBhdCBsZWFzdCBvbmUgZXNzZW50aWFsIGNvbnRhaW5lci5cbiAgICpcbiAgICogSWYgdGhpcyBwYXJhbWV0ZXIgaXMgb21pdHRlZCwgYSBjb250YWluZXIgaXMgYXNzdW1lZCB0byBiZSBlc3NlbnRpYWwuXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IGVzc2VudGlhbD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEEgbGlzdCBvZiBob3N0bmFtZXMgYW5kIElQIGFkZHJlc3MgbWFwcGluZ3MgdG8gYXBwZW5kIHRvIHRoZSAvZXRjL2hvc3RzIGZpbGUgb24gdGhlIGNvbnRhaW5lci5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBleHRyYSBob3N0cy5cbiAgICovXG4gIHJlYWRvbmx5IGV4dHJhSG9zdHM/OiB7IFtuYW1lOiBzdHJpbmddOiBzdHJpbmcgfTtcblxuICAvKipcbiAgICogVGhlIGhlYWx0aCBjaGVjayBjb21tYW5kIGFuZCBhc3NvY2lhdGVkIGNvbmZpZ3VyYXRpb24gcGFyYW1ldGVycyBmb3IgdGhlIGNvbnRhaW5lci5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBIZWFsdGggY2hlY2sgY29uZmlndXJhdGlvbiBmcm9tIGNvbnRhaW5lci5cbiAgICovXG4gIHJlYWRvbmx5IGhlYWx0aENoZWNrPzogSGVhbHRoQ2hlY2s7XG5cbiAgLyoqXG4gICAqIFRoZSBob3N0bmFtZSB0byB1c2UgZm9yIHlvdXIgY29udGFpbmVyLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEF1dG9tYXRpYyBob3N0bmFtZS5cbiAgICovXG4gIHJlYWRvbmx5IGhvc3RuYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgYW1vdW50IChpbiBNaUIpIG9mIG1lbW9yeSB0byBwcmVzZW50IHRvIHRoZSBjb250YWluZXIuXG4gICAqXG4gICAqIElmIHlvdXIgY29udGFpbmVyIGF0dGVtcHRzIHRvIGV4Y2VlZCB0aGUgYWxsb2NhdGVkIG1lbW9yeSwgdGhlIGNvbnRhaW5lclxuICAgKiBpcyB0ZXJtaW5hdGVkLlxuICAgKlxuICAgKiBBdCBsZWFzdCBvbmUgb2YgbWVtb3J5TGltaXRNaUIgYW5kIG1lbW9yeVJlc2VydmF0aW9uTWlCIGlzIHJlcXVpcmVkIGZvciBub24tRmFyZ2F0ZSBzZXJ2aWNlcy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBtZW1vcnkgbGltaXQuXG4gICAqL1xuICByZWFkb25seSBtZW1vcnlMaW1pdE1p